Use render props pattern in color picker

This commit is contained in:
Andrej Ocenas
2019-03-13 12:23:39 +01:00
parent 4a2905de97
commit 96285c4f56
5 changed files with 32 additions and 14 deletions
@@ -50,7 +50,16 @@ ColorPickerStories.add('Series color picker', () => {
color={selectedColor} color={selectedColor}
onChange={color => updateSelectedColor(color)} onChange={color => updateSelectedColor(color)}
> >
<div style={{ color: selectedColor, cursor: 'pointer' }}>Open color picker</div> {({ ref, showColorPicker, hideColorPicker }) => (
<div
ref={ref}
onMouseLeave={hideColorPicker}
onClick={showColorPicker}
style={{ color: selectedColor, cursor: 'pointer' }}
>
Open color picker
</div>
)}
</SeriesColorPicker> </SeriesColorPicker>
); );
}} }}
@@ -1,4 +1,5 @@
import React, { Component, createRef } from 'react'; import React, { Component, createRef } from 'react';
import { omit } from 'lodash';
import { PopperController } from '../Tooltip/PopperController'; import { PopperController } from '../Tooltip/PopperController';
import { Popper } from '../Tooltip/Popper'; import { Popper } from '../Tooltip/Popper';
import { ColorPickerPopover, ColorPickerProps, ColorPickerChangeHandler } from './ColorPickerPopover'; import { ColorPickerPopover, ColorPickerProps, ColorPickerChangeHandler } from './ColorPickerPopover';
@@ -8,13 +9,19 @@ import { SeriesColorPickerPopover } from './SeriesColorPickerPopover';
import { withTheme } from '../../themes/ThemeContext'; import { withTheme } from '../../themes/ThemeContext';
import { ColorPickerTrigger } from './ColorPickerTrigger'; import { ColorPickerTrigger } from './ColorPickerTrigger';
type ColorPickerTriggerRenderer = (props: {
ref: React.RefObject<any>;
showColorPicker: () => void;
hideColorPicker: () => void;
}) => React.ReactNode;
export const colorPickerFactory = <T extends ColorPickerProps>( export const colorPickerFactory = <T extends ColorPickerProps>(
popover: React.ComponentType<T>, popover: React.ComponentType<T>,
displayName = 'ColorPicker' displayName = 'ColorPicker'
) => { ) => {
return class ColorPicker extends Component<T, any> { return class ColorPicker extends Component<T & { children?: ColorPickerTriggerRenderer }, any> {
static displayName = displayName; static displayName = displayName;
pickerTriggerRef = createRef<HTMLDivElement>(); pickerTriggerRef = createRef<any>();
onColorChange = (color: string) => { onColorChange = (color: string) => {
const { onColorChange, onChange } = this.props; const { onColorChange, onChange } = this.props;
@@ -24,11 +31,11 @@ export const colorPickerFactory = <T extends ColorPickerProps>(
}; };
render() { render() {
const { theme, children } = this.props;
const popoverElement = React.createElement(popover, { const popoverElement = React.createElement(popover, {
...this.props, ...omit(this.props, 'children'),
onChange: this.onColorChange, onChange: this.onColorChange,
}); });
const { theme, children } = this.props;
return ( return (
<PopperController content={popoverElement} hideAfter={300}> <PopperController content={popoverElement} hideAfter={300}>
@@ -46,10 +53,10 @@ export const colorPickerFactory = <T extends ColorPickerProps>(
)} )}
{children ? ( {children ? (
React.cloneElement(children as JSX.Element, { (children as ColorPickerTriggerRenderer)({
ref: this.pickerTriggerRef, ref: this.pickerTriggerRef,
onClick: showPopper, showColorPicker: showPopper,
onMouseLeave: hidePopper, hideColorPicker: hidePopper,
}) })
) : ( ) : (
<ColorPickerTrigger <ColorPickerTrigger
@@ -17,8 +17,8 @@ export interface ColorPickerProps extends Themeable {
*/ */
onColorChange?: ColorPickerChangeHandler; onColorChange?: ColorPickerChangeHandler;
enableNamedColors?: boolean; enableNamedColors?: boolean;
children?: JSX.Element;
} }
export interface Props<T> extends ColorPickerProps, PopperContentProps { export interface Props<T> extends ColorPickerProps, PopperContentProps {
customPickers?: T; customPickers?: T;
} }
@@ -1,4 +1,4 @@
import React, { forwardRef, Ref } from 'react'; import React, { forwardRef } from 'react';
interface ColorPickerTriggerProps { interface ColorPickerTriggerProps {
onClick: () => void; onClick: () => void;
@@ -8,7 +8,7 @@ interface ColorPickerTriggerProps {
export const ColorPickerTrigger = forwardRef(function ColorPickerTrigger( export const ColorPickerTrigger = forwardRef(function ColorPickerTrigger(
props: ColorPickerTriggerProps, props: ColorPickerTriggerProps,
ref: Ref<HTMLDivElement> ref: React.Ref<HTMLDivElement>
) { ) {
return ( return (
<div <div
@@ -174,9 +174,11 @@ class LegendSeriesIcon extends PureComponent<LegendSeriesIconProps, LegendSeries
onToggleAxis={this.props.onToggleAxis} onToggleAxis={this.props.onToggleAxis}
enableNamedColors enableNamedColors
> >
<span className="graph-legend-icon"> {({ ref, showColorPicker, hideColorPicker }) => (
<SeriesIcon color={this.props.color} /> <span ref={ref} onClick={showColorPicker} onMouseLeave={hideColorPicker} className="graph-legend-icon">
</span> <SeriesIcon color={this.props.color} />
</span>
)}
</SeriesColorPicker> </SeriesColorPicker>
); );
} }