Skip to main content

Overriding the Sidebar component

To override the default Sidebar component, input DrawingsSidebarComponent or DrawingsSidebarFooter to the uiOverrides.DrawingsSidebar property on ChartReactApp (or on createWidget in the vanilla widget).

To remove specific drawing tools or change their order without a full sidebar rewrite, use drawingsList in chart config — see Drawings configuration. Deeper custom hierarchy beyond drawingsList groups requires a full sidebar uiOverrides implementation.

The Sidebar component has the following properties:

interface DrawingSidebarProps {
readonly drawingGroups: DrawingGroup[];
readonly onSidebarToggle: (isExpanded: boolean) => void;
readonly onButtonClick: (type: SidebarFooterButtonType) => void;
readonly onDrawingClick: (type: DrawingType) => void;
readonly buttonsState: ButtonsState;
readonly isSidebarExpanded: boolean;
readonly drawingsDisabled: boolean;
readonly onFavorite: (name: DrawingType) => void;
readonly onUnFavorite: (name: DrawingType) => void;
readonly favoriteDrawings: Array<DrawingType>;
readonly activeDrawingType: DrawingType | string;
readonly icons: IconsPool;
readonly startNewIconDrawing: (iconType: IconsPoolNames) => void;
}

The Sidebar Footer component has the following properties:

interface DrawingsSidebarFooterProps {
readonly buttonsState: ButtonsState;
readonly expanded: boolean;
readonly disabled?: boolean;
readonly onButtonClick: (type: SidebarFooterButtonType) => void;
}

Example

The below example shows how to make a customized Sidebar with custom scrollable list of drawings and the Sidebar Footer with Hide and Sync buttons removed.

Source code

import { ChartReactAppContainer, ChartReactAppWrapper } from '../../../../../src/components/ChartReactApp';
import { FlexContainer } from '../../../../../src/components/FlexContainer';
import React, { memo, useCallback, useContext, useRef } from 'react';
import { DrawingSidebarProps } from '@dx-private/dxchart5-react/dist/chart/components/chart-sidebar/chart-drawings-sidebar.component';
import { OverrideProps, useIcons } from '@dx-private/dxchart5-react/dist/chart/ui-overrides';
import { CREATE_MOCK_PROVIDERS } from '@dx-private/dxchart5-react-mock-providers';
import { ChartReactAPI } from '@dx-private/dxchart5-react/dist/chart/view-models/api/chart-react-api.view-model';
import {
DrawingsSidebarFooter as DefaultDrawingsSidebarFooter,
DrawingsSidebarFooterProps,
} from '@dx-private/dxchart5-react/dist/chart/components/chart-sidebar/chart-drawings-sidebar-footer.component';
import { DrawingsSidebarHeader } from '@dx-private/dxchart5-react/dist/chart/components/chart-sidebar/chart-drawings-sidebar-header.component';
import { DrawingType, isDrawingType } from '@dx-private/dxchart5-react/dist/chart/model/drawing.model';
import { DrawingsSidebarDrawingIcon } from '@dx-private/dxchart5-react/dist/chart/components/chart-sidebar/components/chart-drawings-sidebar-drawing-icon.component';
import { DrawingsSidebarDrawing } from '@dx-private/dxchart5-react/dist/chart/components/chart-sidebar/components/chart-drawings-sidebar-drawing.component';
import { SidebarSeparatorStyled } from '@dx-private/dxchart5-react/dist/chart/components/chart-sidebar/components/chart-drawings-sidebar-separator.styled';
import { MultiChartComponentContext } from '@dx-private/dxchart5-react/dist/chart/components/multi-chart/multi-chart-context';
import {
SidebarFooterButtonType,
SidebarFooterButtonTypes,
} from '@dx-private/dxchart5-react/dist/chart/components/chart-sidebar/chart-sidebar.model';
import { useA11yListboxArrowsFocusController } from '@dx-private/dxchart5-react/dist/chart-kit/accessibility/use-a11y-listbox-arrows-focus-controller';
import { DrawingsSidebarButtonWithTooltip } from '@dx-private/dxchart5-react/dist/chart/components/chart-sidebar/components/chart-drawings-sidebar-button-with-tooltip.component';
import {
getSidebarFooterButtonName,
getSidebarFooterIconByType,
} from '@dx-private/dxchart5-react/dist/chart/components/chart-sidebar/footer-functions';
import { DrawingsSidebarFooterStyled } from '@dx-private/dxchart5-react/dist/chart/components/chart-sidebar/chart-drawings-sidebar-footer.styled';
export const DrawingsSidebarComponent = ({
chartReactAPIProps: _chartApi,
originalProps: props,
}: OverrideProps<DrawingSidebarProps>) => {
const isActiveDrawing = useCallback(
(type: string | number) => (!isDrawingType(props.activeDrawingType) ? false : props.activeDrawingType === type),
[props.activeDrawingType],
);
return (
<div
style={{
display: 'flex',
flexFlow: 'column',
justifyContent: 'space-between',
backgroundColor: 'black',
alignItems: 'center',
}}>
<DrawingsSidebarHeader
disabled={props.drawingsDisabled}
expanded={props.isSidebarExpanded}
onToggleExpanded={props.onSidebarToggle}
/>
<div style={{ overflowY: 'scroll', scrollbarWidth: 'none' }}>
{props.drawingGroups.map((group, i) => {
return (
<React.Fragment key={group.groupName}>
{group.drawings.map((type: DrawingType) => {
const favorite = props.favoriteDrawings.includes(type);
return type === 'icon' ? (
<DrawingsSidebarDrawingIcon
disabled={props.drawingsDisabled}
key={type}
icons={props.icons}
active={isActiveDrawing(type)}
expanded={props.isSidebarExpanded}
onSelectIcon={() => void 0}
/>
) : (
<DrawingsSidebarDrawing
key={type}
type={type}
disabled={props.drawingsDisabled}
active={isActiveDrawing(type)}
expanded={props.isSidebarExpanded}
favorite={favorite}
onSelect={() => void 0}
onAddToFavorites={() => void 0}
onRemoveFromFavorites={() => void 0}
/>
);
})}
{i === props.drawingGroups.length - 1 ? null : (
<SidebarSeparatorStyled
role="separator"
styles={{ height: 1 }}
key={group.groupName}
scrollTop={1}
/>
)}
</React.Fragment>
);
})}
</div>
<DefaultDrawingsSidebarFooter
disabled={props.drawingsDisabled}
expanded={props.isSidebarExpanded}
buttonsState={props.buttonsState}
onButtonClick={props.onButtonClick}
/>
</div>
);
};
/* remove HIDE and SYNC buttons from sidebar footer */
const sidebarFooterButtonTypes = [
'MAGNET',
'DRAWING_MODE',
// 'SYNC_DRAWINGS',
// 'HIDE_DRAWINGS',
'DELETE_DRAWINGS',
] as const;
const DrawingsSidebarFooter = memo((overrideProps: OverrideProps<DrawingsSidebarFooterProps>) => {
const { chartReactAPIProps: _chartApi, originalProps: props } = overrideProps;
const { expanded, disabled = false, onButtonClick, buttonsState } = props;
const iconsConfig = useIcons();
const { localization } = useContext(MultiChartComponentContext);
const footerListRef = useRef<HTMLDivElement>(null);
const isActive = useCallback(
(type: SidebarFooterButtonType) => {
switch (type) {
case SidebarFooterButtonTypes.DRAWING_MODE:
return buttonsState.drawingModeOn;
case SidebarFooterButtonTypes.MAGNET:
return buttonsState.magnetOn;
case SidebarFooterButtonTypes.HIDE_DRAWINGS:
return !buttonsState.drawingsVisible;
case SidebarFooterButtonTypes.DELETE_DRAWINGS:
return false;
case SidebarFooterButtonTypes.SYNC_DRAWINGS:
return buttonsState.drawingSyncEnabled;
}
},
[buttonsState],
);
useA11yListboxArrowsFocusController({
wrapperRef: footerListRef,
childrenSelector: 'li',
direction: 'vertical',
role: 'listbox',
});
const renderSidebarFooterToolbarItem = (type: SidebarFooterButtonType, supressSelect: boolean = false) => {
return (
<DrawingsSidebarButtonWithTooltip
key={type}
icon={getSidebarFooterIconByType(type, iconsConfig, buttonsState)}
label={getSidebarFooterButtonName(type, localization.sidebar, buttonsState)}
expanded={expanded}
onClick={() => !supressSelect && onButtonClick(type)}
disableTooltip={expanded}
disabled={disabled}
isActive={isActive(type)}
/>
);
};
return (
<>
<SidebarSeparatorStyled role="separator" styles={{ height: 1 }} scrollTop={1} />
<DrawingsSidebarFooterStyled
aria-orientation="vertical"
aria-label={localization.sidebar.a11y_footerList}
ref={footerListRef}
expanded={expanded}>
{sidebarFooterButtonTypes.map(type => renderSidebarFooterToolbarItem(type))}
</DrawingsSidebarFooterStyled>
</>
);
});
export const OverridingSidebarComponent = () => {
const onApiCreated = (api: ChartReactAPI) => {
api.onChartCreated((_chartId, _chartInstance) => {});
};
const chartReactAppContainerProps = { width: 800, height: 50 };
return (
<>
<ChartReactAppContainer {...chartReactAppContainerProps}>
<div className={'chart-react-container'} />
</ChartReactAppContainer>
<FlexContainer $justifyContent={'flex-start'}>
<ChartReactAppWrapper
dependencies={{ ...CREATE_MOCK_PROVIDERS(), onApiCreated }}
uiOverrides={{
DrawingsSidebar: {
/* you can change both components at the same time, but you will have to add default footer component inside sidebar */
DrawingsSidebarComponent,
DrawingsSidebarFooter,
},
}}
/>
</FlexContainer>
</>
);
};