From 20b856fad2e6ba0e2e342d05a6b41b0283d04410 Mon Sep 17 00:00:00 2001 From: Alexander Polyankin <alexander.polyankin@metabase.com> Date: Mon, 30 May 2022 13:34:45 +0300 Subject: [PATCH] Use new ColorSelector for single color chart settings (#22974) --- .storybook/main.js | 4 +-- .../BrandColorSettings/BrandColorSettings.tsx | 21 ++++++--------- .../ChartColorSettings/ChartColorSettings.tsx | 21 ++++++--------- .../ColorSettings/ColorSettings.stories.tsx | 25 ----------------- .../settings/components/SettingsSetting.jsx | 2 -- .../components/widgets/SettingColor.jsx | 10 ------- .../ColorInput/ColorInput.stories.tsx | 8 +++--- .../core/components/ColorInput/ColorInput.tsx | 10 +++---- .../ColorPicker/ColorPicker.stories.tsx | 10 +++---- .../components/ColorPicker/ColorPicker.tsx | 24 +++++------------ .../ColorPicker/ColorPicker.unit.spec.tsx | 6 ++--- .../ColorPicker/ColorPickerContent.tsx | 10 +++---- .../ColorPicker/ColorPickerTrigger.tsx | 24 +++++------------ .../ColorPill/ColorPill.stories.tsx | 6 +++++ .../components/ColorPill/ColorPill.styled.tsx | 23 ++++++---------- .../core/components/ColorPill/ColorPill.tsx | 16 ++++------- .../ColorSelector/ColorSelector.stories.tsx | 10 +++---- .../ColorSelector/ColorSelector.tsx | 24 +++-------------- .../ColorSelector/ColorSelector.unit.spec.tsx | 2 +- .../ColorSelector/ColorSelectorContent.tsx | 9 +++---- .../src/metabase/hooks/use-current-ref.ts | 8 ++++++ frontend/src/metabase/lib/colors.ts | 11 ++++---- frontend/src/metabase/lib/colors/charts.ts | 13 +++++++++ .../settings/ChartNestedSettingSeries.jsx | 7 ++--- .../settings/ChartSettingColorPicker.jsx | 27 +++++++++++-------- .../settings/ChartSettingGaugeSegments.jsx | 18 ++++++------- .../settings/ChartSettingsTableFormatting.jsx | 9 ++++--- 27 files changed, 146 insertions(+), 212 deletions(-) delete mode 100644 enterprise/frontend/src/metabase-enterprise/whitelabel/components/ColorSettings/ColorSettings.stories.tsx delete mode 100644 frontend/src/metabase/admin/settings/components/widgets/SettingColor.jsx create mode 100644 frontend/src/metabase/hooks/use-current-ref.ts create mode 100644 frontend/src/metabase/lib/colors/charts.ts diff --git a/.storybook/main.js b/.storybook/main.js index 18be3bbfa97..2211f3f0f87 100644 --- a/.storybook/main.js +++ b/.storybook/main.js @@ -5,8 +5,8 @@ module.exports = { builder: "webpack5", }, stories: [ - "../(frontend|enterprise)/**/*.stories.mdx", - "../(frontend|enterprise)/**/*.stories.@(js|jsx|ts|tsx)", + "../frontend/**/*.stories.mdx", + "../frontend/**/*.stories.@(js|jsx|ts|tsx)", ], addons: ["@storybook/addon-essentials", "@storybook/addon-links"], webpackFinal: storybookConfig => ({ diff --git a/enterprise/frontend/src/metabase-enterprise/whitelabel/components/BrandColorSettings/BrandColorSettings.tsx b/enterprise/frontend/src/metabase-enterprise/whitelabel/components/BrandColorSettings/BrandColorSettings.tsx index cfeedf632b4..b25987b5af5 100644 --- a/enterprise/frontend/src/metabase-enterprise/whitelabel/components/BrandColorSettings/BrandColorSettings.tsx +++ b/enterprise/frontend/src/metabase-enterprise/whitelabel/components/BrandColorSettings/BrandColorSettings.tsx @@ -1,6 +1,7 @@ -import React, { memo, useCallback, useMemo, useRef } from "react"; +import React, { memo, useCallback, useMemo } from "react"; import { t } from "ttag"; -import { set, omit } from "lodash"; +import { omit, set } from "lodash"; +import { useCurrentRef } from "metabase/hooks/use-current-ref"; import ColorPicker from "metabase/core/components/ColorPicker"; import { getBrandColorOptions } from "./utils"; import { ColorOption } from "./types"; @@ -24,12 +25,8 @@ const BrandColorSettings = ({ originalColors, onChange, }: BrandColorSettingsProps): JSX.Element => { - const colorsRef = useRef(colors); - colorsRef.current = colors; - - const options = useMemo(() => { - return getBrandColorOptions(); - }, []); + const colorsRef = useCurrentRef(colors); + const options = useMemo(getBrandColorOptions, []); const handleChange = useCallback( (colorName: string, color?: string) => { @@ -39,7 +36,7 @@ const BrandColorSettings = ({ onChange?.(omit({ ...colorsRef.current }, colorName)); } }, - [onChange], + [colorsRef, onChange], ); return ( @@ -112,10 +109,8 @@ const BrandColorRow = memo(function BrandColorRow({ <TableBodyRow> <TableBodyCell> <ColorPicker - color={color ?? originalColor} - isBordered - isSelected - isDefault={color == null || color === originalColor} + value={color ?? originalColor} + isAuto={color == null || color === originalColor} onChange={handleChange} /> </TableBodyCell> diff --git a/enterprise/frontend/src/metabase-enterprise/whitelabel/components/ChartColorSettings/ChartColorSettings.tsx b/enterprise/frontend/src/metabase-enterprise/whitelabel/components/ChartColorSettings/ChartColorSettings.tsx index 93fbc7a941f..1625992da87 100644 --- a/enterprise/frontend/src/metabase-enterprise/whitelabel/components/ChartColorSettings/ChartColorSettings.tsx +++ b/enterprise/frontend/src/metabase-enterprise/whitelabel/components/ChartColorSettings/ChartColorSettings.tsx @@ -1,6 +1,7 @@ -import React, { memo, useCallback, useMemo, useRef } from "react"; +import React, { memo, useCallback, useMemo } from "react"; import { t } from "ttag"; import { flatten, omit, set } from "lodash"; +import { useCurrentRef } from "metabase/hooks/use-current-ref"; import ColorPicker from "metabase/core/components/ColorPicker"; import { getChartColorGroups } from "./utils"; import { @@ -23,12 +24,8 @@ const ChartColorSettings = ({ originalColors, onChange, }: ChartColorSettingsProps): JSX.Element => { - const colorsRef = useRef(colors); - colorsRef.current = colors; - - const colorGroups = useMemo(() => { - return getChartColorGroups(); - }, []); + const colorsRef = useCurrentRef(colors); + const colorGroups = useMemo(getChartColorGroups, []); const handleChange = useCallback( (colorName: string, color?: string) => { @@ -38,12 +35,12 @@ const ChartColorSettings = ({ onChange?.(omit({ ...colorsRef.current }, colorName)); } }, - [onChange], + [colorsRef, onChange], ); const handleReset = useCallback(() => { onChange?.(omit({ ...colorsRef.current }, flatten(colorGroups))); - }, [colorGroups, onChange]); + }, [colorsRef, colorGroups, onChange]); return ( <ChartColorTable @@ -119,10 +116,8 @@ const ChartColorCell = memo(function ChartColorCell({ return ( <TableBodyCell> <ColorPicker - color={color ?? originalColor} - isBordered - isSelected - isDefault={color == null || color === originalColor} + value={color ?? originalColor} + isAuto={color == null || color === originalColor} onChange={handleChange} /> </TableBodyCell> diff --git a/enterprise/frontend/src/metabase-enterprise/whitelabel/components/ColorSettings/ColorSettings.stories.tsx b/enterprise/frontend/src/metabase-enterprise/whitelabel/components/ColorSettings/ColorSettings.stories.tsx deleted file mode 100644 index a79d8c98833..00000000000 --- a/enterprise/frontend/src/metabase-enterprise/whitelabel/components/ColorSettings/ColorSettings.stories.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import React from "react"; -import { ComponentStory } from "@storybook/react"; -import { color } from "metabase/lib/colors"; -import ColorSettings from "./ColorSettings"; - -export default { - title: "Whitelabel/ColorSettings", - component: ColorSettings, -}; - -const Template: ComponentStory<typeof ColorSettings> = args => { - return <ColorSettings {...args} />; -}; - -export const Default = Template.bind({}); -Default.args = { - initialColors: { - brand: color("brand"), - }, - originalColors: { - brand: color("brand"), - accent1: color("accent1"), - accent7: color("accent7"), - }, -}; diff --git a/frontend/src/metabase/admin/settings/components/SettingsSetting.jsx b/frontend/src/metabase/admin/settings/components/SettingsSetting.jsx index 62edd0c91be..594d453ec90 100644 --- a/frontend/src/metabase/admin/settings/components/SettingsSetting.jsx +++ b/frontend/src/metabase/admin/settings/components/SettingsSetting.jsx @@ -13,7 +13,6 @@ import SettingRadio from "./widgets/SettingRadio"; import SettingToggle from "./widgets/SettingToggle"; import SettingSelect from "./widgets/SettingSelect"; import SettingText from "./widgets/SettingText"; -import SettingColor from "./widgets/SettingColor"; import { settingToFormFieldId } from "./../../settings/utils"; const SETTING_WIDGET_MAP = { @@ -24,7 +23,6 @@ const SETTING_WIDGET_MAP = { radio: SettingRadio, boolean: SettingToggle, text: SettingText, - color: SettingColor, }; const updatePlaceholderForEnvironmentVars = props => { diff --git a/frontend/src/metabase/admin/settings/components/widgets/SettingColor.jsx b/frontend/src/metabase/admin/settings/components/widgets/SettingColor.jsx deleted file mode 100644 index d63f7fd5ee2..00000000000 --- a/frontend/src/metabase/admin/settings/components/widgets/SettingColor.jsx +++ /dev/null @@ -1,10 +0,0 @@ -/* eslint-disable react/prop-types */ -import React from "react"; - -import ColorPicker from "metabase/components/ColorPicker"; - -const SettingColor = ({ setting, onChange }) => ( - <ColorPicker value={setting.value || setting.default} onChange={onChange} /> -); - -export default SettingColor; diff --git a/frontend/src/metabase/core/components/ColorInput/ColorInput.stories.tsx b/frontend/src/metabase/core/components/ColorInput/ColorInput.stories.tsx index 3721c495fd1..f972aae67e6 100644 --- a/frontend/src/metabase/core/components/ColorInput/ColorInput.stories.tsx +++ b/frontend/src/metabase/core/components/ColorInput/ColorInput.stories.tsx @@ -9,13 +9,13 @@ export default { }; const Template: ComponentStory<typeof ColorInput> = args => { - const [{ color }, updateArgs] = useArgs(); + const [{ value }, updateArgs] = useArgs(); - const handleChange = (color?: string) => { - updateArgs({ color }); + const handleChange = (value?: string) => { + updateArgs({ value }); }; - return <ColorInput {...args} color={color} onChange={handleChange} />; + return <ColorInput {...args} value={value} onChange={handleChange} />; }; export const Default = Template.bind({}); diff --git a/frontend/src/metabase/core/components/ColorInput/ColorInput.tsx b/frontend/src/metabase/core/components/ColorInput/ColorInput.tsx index 18bf37631c7..41c4c762f0e 100644 --- a/frontend/src/metabase/core/components/ColorInput/ColorInput.tsx +++ b/frontend/src/metabase/core/components/ColorInput/ColorInput.tsx @@ -17,16 +17,16 @@ export type ColorInputAttributes = Omit< >; export interface ColorInputProps extends ColorInputAttributes { - color?: string; + value?: string; fullWidth?: boolean; onChange?: (value?: string) => void; } const ColorInput = forwardRef(function ColorInput( - { color, onFocus, onBlur, onChange, ...props }: ColorInputProps, + { value, onFocus, onBlur, onChange, ...props }: ColorInputProps, ref: Ref<HTMLDivElement>, ) { - const colorText = useMemo(() => getColorHex(color) ?? "", [color]); + const colorText = useMemo(() => getColorHex(value) ?? "", [value]); const [inputText, setInputText] = useState(colorText); const [isFocused, setIsFocused] = useState(false); @@ -69,9 +69,9 @@ const ColorInput = forwardRef(function ColorInput( ); }); -const getColorHex = (color?: string) => { +const getColorHex = (value?: string) => { try { - return color ? Color(color).hex() : undefined; + return value ? Color(value).hex() : undefined; } catch (e) { return undefined; } diff --git a/frontend/src/metabase/core/components/ColorPicker/ColorPicker.stories.tsx b/frontend/src/metabase/core/components/ColorPicker/ColorPicker.stories.tsx index f5e0cdaf37d..93e7f50e778 100644 --- a/frontend/src/metabase/core/components/ColorPicker/ColorPicker.stories.tsx +++ b/frontend/src/metabase/core/components/ColorPicker/ColorPicker.stories.tsx @@ -10,17 +10,17 @@ export default { }; const Template: ComponentStory<typeof ColorPicker> = args => { - const [{ color }, updateArgs] = useArgs(); + const [{ value }, updateArgs] = useArgs(); - const handleChange = (color?: string) => { - updateArgs({ color }); + const handleChange = (value?: string) => { + updateArgs({ value }); }; - return <ColorPicker {...args} color={color} onChange={handleChange} />; + return <ColorPicker {...args} value={value} onChange={handleChange} />; }; export const Default = Template.bind({}); Default.args = { - color: color("brand"), + value: color("brand"), placeholder: color("brand"), }; diff --git a/frontend/src/metabase/core/components/ColorPicker/ColorPicker.tsx b/frontend/src/metabase/core/components/ColorPicker/ColorPicker.tsx index 49fb2f751e5..8c03063d447 100644 --- a/frontend/src/metabase/core/components/ColorPicker/ColorPicker.tsx +++ b/frontend/src/metabase/core/components/ColorPicker/ColorPicker.tsx @@ -9,24 +9,14 @@ export type ColorPickerAttributes = Omit< >; export interface ColorPickerProps extends ColorPickerAttributes { - color: string; + value: string; placeholder?: string; - isBordered?: boolean; - isSelected?: boolean; - isDefault?: boolean; + isAuto?: boolean; onChange?: (color?: string) => void; } const ColorPicker = forwardRef(function ColorPicker( - { - color, - placeholder, - isBordered, - isSelected, - isDefault, - onChange, - ...props - }: ColorPickerProps, + { value, placeholder, isAuto, onChange, ...props }: ColorPickerProps, ref: Ref<HTMLDivElement>, ) { return ( @@ -36,16 +26,14 @@ const ColorPicker = forwardRef(function ColorPicker( <ColorPickerTrigger {...props} ref={ref} - color={color} + value={value} placeholder={placeholder} - isBordered={isBordered} - isSelected={isSelected} - isDefault={isDefault} + isAuto={isAuto} onClick={onClick} onChange={onChange} /> )} - popoverContent={<ColorPickerContent color={color} onChange={onChange} />} + popoverContent={<ColorPickerContent value={value} onChange={onChange} />} /> ); }); diff --git a/frontend/src/metabase/core/components/ColorPicker/ColorPicker.unit.spec.tsx b/frontend/src/metabase/core/components/ColorPicker/ColorPicker.unit.spec.tsx index f60d747fea3..9f9a0c6ec48 100644 --- a/frontend/src/metabase/core/components/ColorPicker/ColorPicker.unit.spec.tsx +++ b/frontend/src/metabase/core/components/ColorPicker/ColorPicker.unit.spec.tsx @@ -5,10 +5,10 @@ import userEvent from "@testing-library/user-event"; import ColorPicker from "./ColorPicker"; const TestColorPicker = () => { - const [color, setColor] = useState("white"); - const handleChange = (color?: string) => setColor(color ?? "white"); + const [value, setValue] = useState("white"); + const handleChange = (value?: string) => setValue(value ?? "white"); - return <ColorPicker color={color} onChange={handleChange} />; + return <ColorPicker value={value} onChange={handleChange} />; }; describe("ColorPicker", () => { diff --git a/frontend/src/metabase/core/components/ColorPicker/ColorPickerContent.tsx b/frontend/src/metabase/core/components/ColorPicker/ColorPickerContent.tsx index d540e9e4399..12dd371a157 100644 --- a/frontend/src/metabase/core/components/ColorPicker/ColorPickerContent.tsx +++ b/frontend/src/metabase/core/components/ColorPicker/ColorPickerContent.tsx @@ -10,12 +10,12 @@ export type ColorPickerContentAttributes = Omit< >; export interface ColorPickerContentProps extends ColorPickerContentAttributes { - color?: string; - onChange?: (color?: string) => void; + value?: string; + onChange?: (value?: string) => void; } const ColorPickerContent = forwardRef(function ColorPickerContent( - { color, onChange, ...props }: ColorPickerContentProps, + { value, onChange, ...props }: ColorPickerContentProps, ref: Ref<HTMLDivElement>, ) { const handleChange = useCallback( @@ -25,8 +25,8 @@ const ColorPickerContent = forwardRef(function ColorPickerContent( return ( <ContentContainer {...props} ref={ref}> - <ColorPickerControls color={color} onChange={handleChange} /> - <ColorInput color={color} fullWidth onChange={onChange} /> + <ColorPickerControls color={value} onChange={handleChange} /> + <ColorInput value={value} fullWidth onChange={onChange} /> </ContentContainer> ); }); diff --git a/frontend/src/metabase/core/components/ColorPicker/ColorPickerTrigger.tsx b/frontend/src/metabase/core/components/ColorPicker/ColorPickerTrigger.tsx index d1fe8b29d56..9ded9f55f08 100644 --- a/frontend/src/metabase/core/components/ColorPicker/ColorPickerTrigger.tsx +++ b/frontend/src/metabase/core/components/ColorPicker/ColorPickerTrigger.tsx @@ -5,21 +5,17 @@ import { TriggerContainer } from "./ColorPicker.styled"; export interface ColorPickerTriggerProps extends Omit<HTMLAttributes<HTMLDivElement>, "onChange"> { - color: string; + value: string; placeholder?: string; - isBordered?: boolean; - isSelected?: boolean; - isDefault?: boolean; - onChange?: (color?: string) => void; + isAuto?: boolean; + onChange?: (value?: string) => void; } const ColorPickerTrigger = forwardRef(function ColorPickerTrigger( { - color, + value, placeholder, - isBordered, - isSelected, - isDefault, + isAuto, onClick, onChange, ...props @@ -28,15 +24,9 @@ const ColorPickerTrigger = forwardRef(function ColorPickerTrigger( ) { return ( <TriggerContainer {...props} ref={ref}> - <ColorPill - color={color} - isBordered={isBordered} - isSelected={isSelected} - isDefault={isDefault} - onClick={onClick} - /> + <ColorPill color={value} isAuto={isAuto} onClick={onClick} /> <ColorInput - color={color} + value={value} placeholder={placeholder} fullWidth onChange={onChange} diff --git a/frontend/src/metabase/core/components/ColorPill/ColorPill.stories.tsx b/frontend/src/metabase/core/components/ColorPill/ColorPill.stories.tsx index e71db4ce7fc..7033efe4d50 100644 --- a/frontend/src/metabase/core/components/ColorPill/ColorPill.stories.tsx +++ b/frontend/src/metabase/core/components/ColorPill/ColorPill.stories.tsx @@ -16,3 +16,9 @@ export const Default = Template.bind({}); Default.args = { color: color("brand"), }; + +export const Auto = Template.bind({}); +Auto.args = { + color: color("brand"), + isAuto: true, +}; diff --git a/frontend/src/metabase/core/components/ColorPill/ColorPill.styled.tsx b/frontend/src/metabase/core/components/ColorPill/ColorPill.styled.tsx index df81ef18693..29c7931b6a6 100644 --- a/frontend/src/metabase/core/components/ColorPill/ColorPill.styled.tsx +++ b/frontend/src/metabase/core/components/ColorPill/ColorPill.styled.tsx @@ -2,30 +2,23 @@ import styled from "@emotion/styled"; import { color } from "metabase/lib/colors"; export interface ColorPillRootProps { - isBordered?: boolean; - isSelected?: boolean; - isDefault?: boolean; + isAuto: boolean; + isSelected: boolean; } export const ColorPillRoot = styled.div<ColorPillRootProps>` display: inline-block; - width: 2rem; - height: 2rem; - padding: ${props => props.isBordered && "0.1875rem"}; - border-width: ${props => (props.isBordered ? "0.0625rem" : "0")}; + padding: 0.1875rem; + border-width: 0.0625rem; border-color: ${props => props.isSelected ? color("text-light") : "transparent"}; - border-style: ${props => (props.isDefault ? "dashed" : "solid")}; + border-style: ${props => (props.isAuto ? "dashed" : "solid")}; border-radius: 50%; cursor: pointer; `; -export interface ColorPillContentProps { - isBordered?: boolean; -} - -export const ColorPillContent = styled.div<ColorPillContentProps>` - width: ${props => (props.isBordered ? "1.5rem" : "2rem")}; - height: ${props => (props.isBordered ? "1.5rem" : "2rem")}; +export const ColorPillContent = styled.div` + width: 1.5rem; + height: 1.5rem; border-radius: 50%; `; diff --git a/frontend/src/metabase/core/components/ColorPill/ColorPill.tsx b/frontend/src/metabase/core/components/ColorPill/ColorPill.tsx index e9599ef1795..f191ea8d838 100644 --- a/frontend/src/metabase/core/components/ColorPill/ColorPill.tsx +++ b/frontend/src/metabase/core/components/ColorPill/ColorPill.tsx @@ -3,17 +3,15 @@ import { ColorPillContent, ColorPillRoot } from "./ColorPill.styled"; export interface ColorPillProps extends HTMLAttributes<HTMLDivElement> { color: string; - isBordered?: boolean; + isAuto?: boolean; isSelected?: boolean; - isDefault?: boolean; } const ColorPill = forwardRef(function ColorPill( { color, - isBordered, - isSelected, - isDefault, + isAuto = false, + isSelected = true, "aria-label": ariaLabel = color, ...props }: ColorPillProps, @@ -23,15 +21,11 @@ const ColorPill = forwardRef(function ColorPill( <ColorPillRoot {...props} ref={ref} - isBordered={isBordered} + isAuto={isAuto} isSelected={isSelected} - isDefault={isDefault} aria-label={ariaLabel} > - <ColorPillContent - isBordered={isBordered} - style={{ backgroundColor: color }} - /> + <ColorPillContent style={{ backgroundColor: color }} /> </ColorPillRoot> ); }); diff --git a/frontend/src/metabase/core/components/ColorSelector/ColorSelector.stories.tsx b/frontend/src/metabase/core/components/ColorSelector/ColorSelector.stories.tsx index 657798b68b0..c3594952a35 100644 --- a/frontend/src/metabase/core/components/ColorSelector/ColorSelector.stories.tsx +++ b/frontend/src/metabase/core/components/ColorSelector/ColorSelector.stories.tsx @@ -10,17 +10,17 @@ export default { }; const Template: ComponentStory<typeof ColorSelector> = args => { - const [{ color }, updateArgs] = useArgs(); + const [{ value }, updateArgs] = useArgs(); - const handleChange = (color: string) => { - updateArgs({ color }); + const handleChange = (value: string) => { + updateArgs({ value }); }; - return <ColorSelector {...args} color={color} onChange={handleChange} />; + return <ColorSelector {...args} value={value} onChange={handleChange} />; }; export const Default = Template.bind({}); Default.args = { - color: color("brand"), + value: color("brand"), colors: [color("brand"), color("summarize"), color("filter")], }; diff --git a/frontend/src/metabase/core/components/ColorSelector/ColorSelector.tsx b/frontend/src/metabase/core/components/ColorSelector/ColorSelector.tsx index 2b6610dee56..64776f20973 100644 --- a/frontend/src/metabase/core/components/ColorSelector/ColorSelector.tsx +++ b/frontend/src/metabase/core/components/ColorSelector/ColorSelector.tsx @@ -9,39 +9,23 @@ export type ColorSelectorAttributes = Omit< >; export interface ColorSelectorProps extends ColorSelectorAttributes { - color: string; + value: string; colors: string[]; - isBordered?: boolean; - isSelected?: boolean; onChange?: (color: string) => void; } const ColorSelector = forwardRef(function ColorSelector( - { - color, - colors, - isBordered, - isSelected, - onChange, - ...props - }: ColorSelectorProps, + { value, colors, onChange, ...props }: ColorSelectorProps, ref: Ref<HTMLDivElement>, ) { return ( <TippyPopoverWithTrigger renderTrigger={({ onClick }) => ( - <ColorPill - {...props} - ref={ref} - color={color} - isBordered={isBordered} - isSelected={isSelected} - onClick={onClick} - /> + <ColorPill {...props} ref={ref} color={value} onClick={onClick} /> )} popoverContent={ <ColorSelectorContent - color={color} + value={value} colors={colors} onChange={onChange} /> diff --git a/frontend/src/metabase/core/components/ColorSelector/ColorSelector.unit.spec.tsx b/frontend/src/metabase/core/components/ColorSelector/ColorSelector.unit.spec.tsx index 42da1d9e9ed..0e5e9772222 100644 --- a/frontend/src/metabase/core/components/ColorSelector/ColorSelector.unit.spec.tsx +++ b/frontend/src/metabase/core/components/ColorSelector/ColorSelector.unit.spec.tsx @@ -9,7 +9,7 @@ describe("ColorSelector", () => { render( <ColorSelector - color="white" + value="white" colors={["blue", "green"]} onChange={onChange} />, diff --git a/frontend/src/metabase/core/components/ColorSelector/ColorSelectorContent.tsx b/frontend/src/metabase/core/components/ColorSelector/ColorSelectorContent.tsx index 345bf7464dc..1b781ab7f45 100644 --- a/frontend/src/metabase/core/components/ColorSelector/ColorSelectorContent.tsx +++ b/frontend/src/metabase/core/components/ColorSelector/ColorSelectorContent.tsx @@ -4,13 +4,13 @@ import { ColorSelectorRoot } from "./ColorSelector.styled"; export interface ColorSelectorContentProps extends Omit<HTMLAttributes<HTMLDivElement>, "onChange"> { - color?: string; + value?: string; colors: string[]; - onChange?: (color: string) => void; + onChange?: (value: string) => void; } const ColorSelectorContent = forwardRef(function ColorSelector( - { color, colors, onChange, ...props }: ColorSelectorContentProps, + { value, colors, onChange, ...props }: ColorSelectorContentProps, ref: Ref<HTMLDivElement>, ) { return ( @@ -19,8 +19,7 @@ const ColorSelectorContent = forwardRef(function ColorSelector( <ColorPill key={index} color={option} - isBordered - isSelected={color === option} + isSelected={value === option} onClick={() => onChange?.(option)} /> ))} diff --git a/frontend/src/metabase/hooks/use-current-ref.ts b/frontend/src/metabase/hooks/use-current-ref.ts new file mode 100644 index 00000000000..e73d2b00bd9 --- /dev/null +++ b/frontend/src/metabase/hooks/use-current-ref.ts @@ -0,0 +1,8 @@ +import { useRef } from "react"; + +export const useCurrentRef = function<T>(value: T) { + const ref = useRef(value); + ref.current = value; + + return ref; +}; diff --git a/frontend/src/metabase/lib/colors.ts b/frontend/src/metabase/lib/colors.ts index 38356ae06e9..ebf7c5b158d 100644 --- a/frontend/src/metabase/lib/colors.ts +++ b/frontend/src/metabase/lib/colors.ts @@ -64,7 +64,6 @@ export const harmony: string[] = []; // DEPRECATED: we should remove these and use `colors` directly // compute satured/desaturated variants using "color" lib if absolutely required export const normal: Record<string, string> = {}; -export const saturated: Record<string, string> = {}; export const desaturated: Record<string, string> = {}; // make sure to do the initial "sync" syncColors(); @@ -109,11 +108,11 @@ function syncHarmony() { // syncs deprecated color families for legacy code function syncDeprecatedColorFamilies() { // normal + saturated + desaturated - normal.blue = saturated.blue = desaturated.blue = colors["brand"]; - normal.green = saturated.green = desaturated.green = colors["accent1"]; - normal.purple = saturated.purple = desaturated.purple = colors["accent2"]; - normal.red = saturated.red = desaturated.red = colors["accent3"]; - normal.yellow = saturated.yellow = desaturated.yellow = colors["accent4"]; + normal.blue = desaturated.blue = colors["brand"]; + normal.green = desaturated.green = colors["accent1"]; + normal.purple = desaturated.purple = colors["accent2"]; + normal.red = desaturated.red = colors["accent3"]; + normal.yellow = desaturated.yellow = colors["accent4"]; normal.orange = colors["accent5"]; normal.teal = colors["accent6"]; normal.indigo = colors["accent7"]; diff --git a/frontend/src/metabase/lib/colors/charts.ts b/frontend/src/metabase/lib/colors/charts.ts new file mode 100644 index 00000000000..a3a202be057 --- /dev/null +++ b/frontend/src/metabase/lib/colors/charts.ts @@ -0,0 +1,13 @@ +import { times } from "lodash"; +import { color } from "metabase/lib/colors"; + +export const getNormalColors = () => [ + color("brand"), + ...times(7, i => color(`accent${i + 1}`)), + color("text-dark"), +]; + +export const getDesaturatedColors = () => [ + color("brand"), + ...times(4, i => color(`accent${i + 1}`)), +]; diff --git a/frontend/src/metabase/visualizations/components/settings/ChartNestedSettingSeries.jsx b/frontend/src/metabase/visualizations/components/settings/ChartNestedSettingSeries.jsx index 16674c49e1e..f41a8b376c6 100644 --- a/frontend/src/metabase/visualizations/components/settings/ChartNestedSettingSeries.jsx +++ b/frontend/src/metabase/visualizations/components/settings/ChartNestedSettingSeries.jsx @@ -1,7 +1,8 @@ /* eslint-disable react/prop-types */ import React from "react"; -import ColorPicker from "metabase/components/ColorPicker"; +import { getNormalColors } from "metabase/lib/colors/charts"; +import ColorSelector from "metabase/core/components/ColorSelector"; import { SegmentedControl } from "metabase/components/SegmentedControl"; import Icon from "metabase/components/Icon"; import IconWrapper from "metabase/components/IconWrapper"; @@ -39,9 +40,9 @@ export default class ChartNestedSettingSeries extends React.Component { className="px4 pt2 mt2 border-top align-self-stretch" > <div className="flex align-center"> - <ColorPicker + <ColorSelector value={settings.color} - triggerSize={21} + colors={getNormalColors()} onChange={value => onChangeObjectSettings(single, { color: value }) } diff --git a/frontend/src/metabase/visualizations/components/settings/ChartSettingColorPicker.jsx b/frontend/src/metabase/visualizations/components/settings/ChartSettingColorPicker.jsx index 6d02d334684..24c7383a653 100644 --- a/frontend/src/metabase/visualizations/components/settings/ChartSettingColorPicker.jsx +++ b/frontend/src/metabase/visualizations/components/settings/ChartSettingColorPicker.jsx @@ -1,15 +1,20 @@ /* eslint-disable react/prop-types */ -import React, { Component } from "react"; +import React from "react"; -import ColorPicker from "metabase/components/ColorPicker"; +import { getNormalColors } from "metabase/lib/colors/charts"; +import ColorSelector from "metabase/core/components/ColorSelector"; -export default class ChartSettingColorPicker extends Component { - render() { - return ( - <div className="flex align-center mb1"> - <ColorPicker {...this.props} triggerSize={12} /> - {this.props.title && <h4 className="ml1">{this.props.title}</h4>} - </div> - ); - } +export default function ChartSettingColorPicker(props) { + const { value, onChange } = props; + + return ( + <div className="flex align-center mb1"> + <ColorSelector + value={value} + colors={getNormalColors()} + onChange={onChange} + /> + {props.title && <h4 className="ml1">{props.title}</h4>} + </div> + ); } diff --git a/frontend/src/metabase/visualizations/components/settings/ChartSettingGaugeSegments.jsx b/frontend/src/metabase/visualizations/components/settings/ChartSettingGaugeSegments.jsx index 29f51e8e09a..3bc0702a5c1 100644 --- a/frontend/src/metabase/visualizations/components/settings/ChartSettingGaugeSegments.jsx +++ b/frontend/src/metabase/visualizations/components/settings/ChartSettingGaugeSegments.jsx @@ -4,9 +4,10 @@ import React from "react"; import { t } from "ttag"; import _ from "underscore"; -import { color, normal } from "metabase/lib/colors"; +import { color } from "metabase/lib/colors"; +import { getNormalColors } from "metabase/lib/colors/charts"; -import ColorPicker from "metabase/components/ColorPicker"; +import ColorSelector from "metabase/core/components/ColorSelector"; import Button from "metabase/core/components/Button"; import Icon from "metabase/components/Icon"; import NumericInput from "metabase/components/NumericInput"; @@ -33,12 +34,11 @@ const ChartSettingGaugeSegments = ({ value: segments, onChange }) => { <React.Fragment key={segment.index}> <tr> <td> - <ColorPicker - value={segment.color} - onChange={color => onChangeProperty(index, "color", color)} - triggerSize={28} - padding={2} + <ColorSelector + className="mr1" + color={segment.color} colors={getColorPalette()} + onChange={color => onChangeProperty(index, "color", color)} /> </td> <td> @@ -101,10 +101,10 @@ const ChartSettingGaugeSegments = ({ value: segments, onChange }) => { function getColorPalette() { return [ + ...getNormalColors(), color("error"), color("warning"), color("success"), - ...Object.values(normal).slice(0, 9), color("bg-medium"), ]; } @@ -117,7 +117,7 @@ function newSegment(segments) { : -1; const nextColor = lastColorIndex >= 0 - ? palette[lastColorIndex + (1 % palette.length)] + ? palette[(lastColorIndex + 1) % palette.length] : palette[0]; return { diff --git a/frontend/src/metabase/visualizations/components/settings/ChartSettingsTableFormatting.jsx b/frontend/src/metabase/visualizations/components/settings/ChartSettingsTableFormatting.jsx index e175bb4f8ba..3ebeeefb382 100644 --- a/frontend/src/metabase/visualizations/components/settings/ChartSettingsTableFormatting.jsx +++ b/frontend/src/metabase/visualizations/components/settings/ChartSettingsTableFormatting.jsx @@ -9,7 +9,7 @@ import Icon from "metabase/components/Icon"; import Select, { Option } from "metabase/core/components/Select"; import Radio from "metabase/core/components/Radio"; import Toggle from "metabase/core/components/Toggle"; -import ColorPicker from "metabase/components/ColorPicker"; +import ColorSelector from "metabase/core/components/ColorSelector"; import ColorRangePicker, { ColorRangePreview, @@ -53,10 +53,11 @@ export const ALL_OPERATOR_NAMES = { ...STRING_OPERATOR_NAMES, }; -import { color, desaturated } from "metabase/lib/colors"; +import { color } from "metabase/lib/colors"; +import { getDesaturatedColors } from "metabase/lib/colors/charts"; // TODO -const COLORS = Object.values(desaturated); +const COLORS = getDesaturatedColors(); const COLOR_RANGES = [].concat( ...COLORS.map(color => [ ["white", color], @@ -390,7 +391,7 @@ const RuleEditor = ({ rule, cols, isNew, onChange, onDone, onRemove }) => { /> ) : null} <h3 className="mt3 mb1">{t`…turn its background this color:`}</h3> - <ColorPicker + <ColorSelector value={rule.color} colors={COLORS} onChange={color => onChange({ ...rule, color })} -- GitLab