Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
mbondyra committed May 20, 2024
1 parent 26737b8 commit f7ced69
Show file tree
Hide file tree
Showing 8 changed files with 136 additions and 224 deletions.
36 changes: 29 additions & 7 deletions packages/charts/src/components/legend/legend.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
*/

import classNames from 'classnames';
import React from 'react';
import React, { useCallback } from 'react';
import { connect } from 'react-redux';
import { Dispatch, bindActionCreators } from 'redux';

Expand All @@ -17,12 +17,14 @@ import { LegendTable } from './legend_table';
import { getLegendPositionConfig, legendPositionStyle } from './position_style';
import { getLegendStyle, getLegendListStyle } from './style_utils';
import { LegendItem, LegendItemExtraValues, LegendValue } from '../../common/legend';
import { SeriesIdentifier } from '../../common/series_id';
import { DEFAULT_LEGEND_CONFIG, LegendSpec } from '../../specs';
import { clearTemporaryColors, setTemporaryColor, setPersistedColor } from '../../state/actions/colors';
import {
onToggleDeselectSeriesAction,
onLegendItemOutAction,
onLegendItemOverAction,
LegendPath,
} from '../../state/actions/legend';
import { GlobalChartState } from '../../state/chart_state';
import { getChartThemeSelector } from '../../state/selectors/get_chart_theme';
Expand Down Expand Up @@ -73,6 +75,28 @@ function LegendComponent(props: LegendStateProps & LegendDispatchProps) {
config,
} = props;

const { onLegendItemOut, onLegendItemOver } = config;
const { onItemOutAction, onItemOverAction } = props;

const onLegendItemMouseOver = useCallback(
(seriesIdentifiers: SeriesIdentifier[], path: LegendPath) => {
// call the settings listener directly if available
if (onLegendItemOver) {
onLegendItemOver(seriesIdentifiers);
}
onItemOverAction(path);
},
[onItemOverAction, onLegendItemOver],
);

const onLegendItemMouseOut = useCallback(() => {
// call the settings listener directly if available
if (onLegendItemOut) {
onLegendItemOut();
}
onItemOutAction();
}, [onLegendItemOut, onItemOutAction]);

if (items.every(({ isItemHidden }) => isItemHidden)) {
return null;
}
Expand Down Expand Up @@ -100,14 +124,12 @@ function LegendComponent(props: LegendStateProps & LegendDispatchProps) {
hiddenItems: items.filter(({ isSeriesHidden }) => isSeriesHidden).length,
extraValues: props.extraValues,
legendValues: config.legendValues,
onMouseOut: config.onLegendItemOut,
onMouseOver: config.onLegendItemOver,
onLegendItemMouseOver,
onLegendItemMouseOut,
onClick: config.onLegendItemClick,
clearTemporaryColorsAction: props.clearTemporaryColors,
setPersistedColorAction: props.setPersistedColor,
setTemporaryColorAction: props.setTemporaryColor,
mouseOutAction: props.onItemOutAction,
mouseOverAction: props.onItemOverAction,
toggleDeselectSeriesAction: props.onToggleDeselectSeriesAction,
colorPicker: config.legendColorPicker,
action: config.legendAction,
Expand All @@ -129,8 +151,8 @@ function LegendComponent(props: LegendStateProps & LegendDispatchProps) {
seriesIdentifiers,
path,
extraValue: itemProps.extraValues.get(seriesIdentifiers[0]?.key ?? '')?.get(childId ?? ''),
onItemOutAction: itemProps.mouseOutAction,
onItemOverActon: () => itemProps.mouseOverAction(path),
onItemOutAction,
onItemOverActon: () => onItemOverAction(path),
onItemClickAction: (negate: boolean) => itemProps.toggleDeselectSeriesAction(seriesIdentifiers, negate),
}))}
/>
Expand Down
46 changes: 25 additions & 21 deletions packages/charts/src/components/legend/legend_color_picker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { LegendItemProps } from './legend_item';
import { Color } from '../../common/colors';

/** @internal */
export const LegendColorPicker = ({
export const useLegendColorPicker = ({
item: { color, isSeriesHidden, label, pointStyle, seriesIdentifiers },
colorPicker: ColorPickerRenderer,
clearTemporaryColorsAction,
Expand Down Expand Up @@ -51,26 +51,30 @@ export const LegendColorPicker = ({

const hasColorPicker = Boolean(ColorPickerRenderer);

return (
<>
<ItemColor
ref={colorRef}
const renderItemColor = () => (
<ItemColor
ref={colorRef}
color={color}
seriesName={label}
isSeriesHidden={isSeriesHidden}
hasColorPicker={hasColorPicker}
onClick={handleColorClick(hasColorPicker)}
pointStyle={pointStyle}
/>
);

const renderColorPickerPopup = () =>
ColorPickerRenderer &&
isOpen &&
colorRef.current && (
<ColorPickerRenderer
anchor={colorRef.current}
color={color}
seriesName={label}
isSeriesHidden={isSeriesHidden}
hasColorPicker={hasColorPicker}
onClick={handleColorClick(hasColorPicker)}
pointStyle={pointStyle}
onClose={handleColorPickerClose}
onChange={handleColorPickerChange}
seriesIdentifiers={seriesIdentifiers}
/>
{ColorPickerRenderer && isOpen && colorRef.current && (
<ColorPickerRenderer
anchor={colorRef.current}
color={color}
onClose={handleColorPickerClose}
onChange={handleColorPickerChange}
seriesIdentifiers={seriesIdentifiers}
/>
)}
</>
);
);

return { renderItemColor, renderColorPickerPopup };
};
116 changes: 19 additions & 97 deletions packages/charts/src/components/legend/legend_item.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,13 @@
*/

import classNames from 'classnames';
import React, { CSSProperties, useRef, useState, useCallback } from 'react';
import React, { CSSProperties, useCallback } from 'react';

import { Color as ItemColor } from './color';
import { Label as ItemLabel } from './label';
import { LegendActionComponent } from './legend_action';
import { useLegendColorPicker } from './legend_color_picker';
import { SharedLegendItemProps } from './types';
import { getExtra } from './utils';
import { Color } from '../../common/colors';
import { LegendItem, LegendItemExtraValues, LegendValue } from '../../common/legend';
import { SeriesIdentifier } from '../../common/series_id';
import { LayoutDirection } from '../../utils/common';
Expand All @@ -27,7 +26,8 @@ export interface LegendItemProps extends SharedLegendItemProps {
item: LegendItem;
}

const prepareLegendValue = (
/** @internal */
export const prepareLegendValues = (
item: LegendItem,
legendValues: LegendValue[],
totalItems: number,
Expand All @@ -36,18 +36,17 @@ const prepareLegendValue = (
if (legendValues.length === 0) {
return undefined;
}
if (legendValues[0] === LegendValue.CurrentAndLastValue) {
return getExtra(extraValues, item, totalItems);
if (legendValues.length === 1 && legendValues[0] === LegendValue.CurrentAndLastValue) {
return [getExtra(extraValues, item, totalItems)];
}
return item.values[0];
return item.values;
};
/** @internal */
export const LegendListItem: React.FC<LegendItemProps> = (props) => {
const {
extraValues,
item,
legendValues,
colorPicker,
totalItems,
action: Action,
positionConfig,
Expand All @@ -56,56 +55,25 @@ export const LegendListItem: React.FC<LegendItemProps> = (props) => {
flatLegend,
onClick,
toggleDeselectSeriesAction,
onMouseOver,
mouseOverAction,
onMouseOut,
mouseOutAction,
setPersistedColorAction,
clearTemporaryColorsAction,
setTemporaryColorAction,
colorPicker: ColorPicker,
hiddenItems,
onLegendItemMouseOver,
onLegendItemMouseOut,
} = props;
const { color, isSeriesHidden, isItemHidden, seriesIdentifiers, label, pointStyle, depth, path, isToggleable } = item;
const { color, isSeriesHidden, isItemHidden, seriesIdentifiers, label, depth, path, isToggleable } = item;

const itemClassNames = classNames('echLegendItem', {
'echLegendItem--hidden': isSeriesHidden,
'echLegendItem--vertical': positionConfig.direction === LayoutDirection.Vertical,
});

// only the first for now until https://github.com/elastic/elastic-charts/issues/2096
const legendValue = prepareLegendValue(item, legendValues, totalItems, extraValues);
const legendValueItems = prepareLegendValues(item, legendValues, totalItems, extraValues);

const style: CSSProperties = flatLegend
? {}
: {
[isMostlyRTL ? 'marginRight' : 'marginLeft']: LEGEND_HIERARCHY_MARGIN * (depth ?? 0),
};

const colorRef = useRef<HTMLButtonElement>(null);
const [isOpen, setIsOpen] = useState(false);
const shouldClearPersistedColor = useRef(false);

const toggleIsOpen = useCallback(() => {
setIsOpen((prevIsOpen) => !prevIsOpen);
}, []);

const onLegendItemMouseOver = useCallback(() => {
// call the settings listener directly if available
if (onMouseOver) {
onMouseOver(seriesIdentifiers);
}
mouseOverAction(path);
}, [mouseOverAction, onMouseOver, path, seriesIdentifiers]);

const onLegendItemMouseOut = useCallback(() => {
// call the settings listener directly if available
if (onMouseOut) {
onMouseOut();
}
mouseOutAction();
}, [onMouseOut, mouseOutAction]);

const onLabelToggle = useCallback(
(legendItemId: SeriesIdentifier[]) => (negate: boolean) => {
if (totalItems <= 1 || (!isToggleable && !onClick)) {
Expand All @@ -122,69 +90,22 @@ export const LegendListItem: React.FC<LegendItemProps> = (props) => {
},
[onClick, toggleDeselectSeriesAction, isToggleable, totalItems],
);

const renderColorPicker = useCallback(() => {
if (!ColorPicker || !isOpen || !colorRef.current) {
return null;
}

const seriesKeys = seriesIdentifiers.map(({ key }) => key);

return (
<ColorPicker
anchor={colorRef.current}
color={color}
onClose={() => {
setPersistedColorAction(seriesKeys, shouldClearPersistedColor.current ? null : color);
clearTemporaryColorsAction();
requestAnimationFrame(() => colorRef?.current?.focus());
toggleIsOpen();
}}
onChange={(c: Color | null) => {
shouldClearPersistedColor.current = c === null;
setTemporaryColorAction(seriesKeys, c);
}}
seriesIdentifiers={seriesIdentifiers}
/>
);
}, [
ColorPicker,
toggleIsOpen,
color,
seriesIdentifiers,
setPersistedColorAction,
clearTemporaryColorsAction,
setTemporaryColorAction,
isOpen,
]);
const { renderItemColor, renderColorPickerPopup } = useLegendColorPicker(props);

if (isItemHidden) return null;

return (
<>
<li
className={itemClassNames}
onMouseEnter={onLegendItemMouseOver}
onMouseEnter={() => onLegendItemMouseOver(seriesIdentifiers, path)}
onMouseLeave={onLegendItemMouseOut}
style={style}
dir={isMostlyRTL ? 'rtl' : 'ltr'}
data-ech-series-name={label}
>
<div className="background" />
<div className="echLegend__colorWrapper">
<ItemColor
ref={colorRef}
color={color}
seriesName={label}
isSeriesHidden={isSeriesHidden}
hasColorPicker={Boolean(colorPicker)}
onClick={(event: React.MouseEvent) => {
event.stopPropagation();
toggleIsOpen();
}}
pointStyle={pointStyle}
></ItemColor>
</div>
<div className="echLegend__colorWrapper">{renderItemColor()}</div>
<ItemLabel
label={label}
options={labelOptions}
Expand All @@ -194,14 +115,15 @@ export const LegendListItem: React.FC<LegendItemProps> = (props) => {
totalSeriesCount={totalItems}
hiddenSeriesCount={hiddenItems}
/>
{legendValue && legendValue.label !== '' && !isSeriesHidden && (
<div className="echLegendItem__legendValue" title={`${legendValue.label}`}>
{legendValue.label}
{/* // only the first for now until https://github.com/elastic/elastic-charts/issues/2096 */}
{legendValueItems?.[0] && legendValueItems[0].label !== '' && !isSeriesHidden && (
<div className="echLegendItem__legendValue" title={`${legendValueItems[0].label}`}>
{legendValueItems[0].label}
</div>
)}
{Action && <LegendActionComponent Action={Action} series={seriesIdentifiers} color={color} label={label} />}
</li>
{renderColorPicker()}
{renderColorPickerPopup()}
</>
);
};
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
@import '../variables';
@import '../../mixins';

.echLegendSingleItem {
.echLegendTable__item {
color: $euiTextColor;

&:last-child .echLegendTable__cell {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,10 @@

import React from 'react';

import { LayoutDirection } from '@elastic/charts';

import { LegendTableBody } from './legend_table_body';
import { LegendTableHeader } from './legend_table_header';
import { LegendItem } from '../../../common/legend';
import { LayoutDirection } from '../../../utils/common';
import { SharedLegendItemProps } from '../types';

/** @internal */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export const LegendTableHeader = ({

return (
<div role="rowgroup" className="echLegendTable__rowgroup echLegendTable__header">
<LegendTableRow className="echLegendSingleItem echLegendSingleItem--vertical" dir={isMostlyRTL ? 'rtl' : 'ltr'}>
<LegendTableRow className="echLegendTable__item echLegendTable__item--vertical" dir={isMostlyRTL ? 'rtl' : 'ltr'}>
<LegendTableCell className="echLegend__colorWrapper echLegendTable__colorCell"></LegendTableCell>
<LegendTableCell>{legendTitle}</LegendTableCell>
{legendValues.map((l) => (
Expand Down
Loading

0 comments on commit f7ced69

Please sign in to comment.