|
@@ -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';
|
|
@@ -6,14 +7,29 @@ import { getColorFromHexRgbOrName } from '../../utils/namedColorsPalette';
|
|
|
import { SeriesColorPickerPopover } from './SeriesColorPickerPopover';
|
|
import { SeriesColorPickerPopover } from './SeriesColorPickerPopover';
|
|
|
|
|
|
|
|
import { withTheme } from '../../themes/ThemeContext';
|
|
import { withTheme } from '../../themes/ThemeContext';
|
|
|
|
|
+import { ColorPickerTrigger } from './ColorPickerTrigger';
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * If you need custom trigger for the color picker you can do that with a render prop pattern and supply a function
|
|
|
|
|
+ * as a child. You will get show/hide function which you can map to desired interaction (like onClick or onMouseLeave)
|
|
|
|
|
+ * and a ref which needs to be passed to an HTMLElement for correct positioning. If you want to use class or functional
|
|
|
|
|
+ * component as a custom trigger you will need to forward the reference to first HTMLElement child.
|
|
|
|
|
+ */
|
|
|
|
|
+type ColorPickerTriggerRenderer = (props: {
|
|
|
|
|
+ // This should be a React.RefObject<HTMLElement> but due to how object refs are defined you cannot downcast from that
|
|
|
|
|
+ // to a specific type like React.RefObject<HTMLDivElement> even though it would be fine in runtime.
|
|
|
|
|
+ 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;
|
|
@@ -23,11 +39,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}>
|
|
@@ -45,27 +61,21 @@ export const colorPickerFactory = <T extends ColorPickerProps>(
|
|
|
)}
|
|
)}
|
|
|
|
|
|
|
|
{children ? (
|
|
{children ? (
|
|
|
- React.cloneElement(children as JSX.Element, {
|
|
|
|
|
|
|
+ // Children have a bit weird type due to intersection used in the definition so we need to cast here,
|
|
|
|
|
+ // but the definition is correct and should not allow to pass a children that does not conform to
|
|
|
|
|
+ // ColorPickerTriggerRenderer type.
|
|
|
|
|
+ (children as ColorPickerTriggerRenderer)({
|
|
|
ref: this.pickerTriggerRef,
|
|
ref: this.pickerTriggerRef,
|
|
|
- onClick: showPopper,
|
|
|
|
|
- onMouseLeave: hidePopper,
|
|
|
|
|
|
|
+ showColorPicker: showPopper,
|
|
|
|
|
+ hideColorPicker: hidePopper,
|
|
|
})
|
|
})
|
|
|
) : (
|
|
) : (
|
|
|
- <div
|
|
|
|
|
|
|
+ <ColorPickerTrigger
|
|
|
ref={this.pickerTriggerRef}
|
|
ref={this.pickerTriggerRef}
|
|
|
onClick={showPopper}
|
|
onClick={showPopper}
|
|
|
onMouseLeave={hidePopper}
|
|
onMouseLeave={hidePopper}
|
|
|
- className="sp-replacer sp-light"
|
|
|
|
|
- >
|
|
|
|
|
- <div className="sp-preview">
|
|
|
|
|
- <div
|
|
|
|
|
- className="sp-preview-inner"
|
|
|
|
|
- style={{
|
|
|
|
|
- backgroundColor: getColorFromHexRgbOrName(this.props.color || '#000000', theme.type),
|
|
|
|
|
- }}
|
|
|
|
|
- />
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
|
|
+ color={getColorFromHexRgbOrName(this.props.color || '#000000', theme.type)}
|
|
|
|
|
+ />
|
|
|
)}
|
|
)}
|
|
|
</>
|
|
</>
|
|
|
);
|
|
);
|