diff --git a/.storybook/main.js b/.storybook/main.js index 18be3bbfa97100ea219d993afa47f8a0a84b2559..2211f3f0f8745ae6448c3143f0f2d89077fae009 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 cfeedf632b470d9281d75858e2880735d9e42b8b..b25987b5af5528e7d5507335ac92dcd895dcc7b7 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 93fbc7a941fdbf9a21b570633980fecda095ddeb..1625992da87ddc9aef3b7bd779198c60fcc6f920 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 a79d8c98833a9578e0be37cd4ddec82d51e4251f..0000000000000000000000000000000000000000 --- 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 62edd0c91be6fd4d3c9197b26588546fcfd3e51b..594d453ec9028dcbe8b66670c01c3036a6bc1839 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 d63f7fd5ee2f0ff595cd736dd722f8f4da30ecc5..0000000000000000000000000000000000000000 --- 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 3721c495fd165490112053b5122c8020c741019b..f972aae67e67de287e577895c71f396c68f44939 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 18bf37631c723f85bd9ec06ec1bd2e6af94455f8..41c4c762f0e033b3b0402339371eec80a32bdbf5 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 f5e0cdaf37d366dffb69b12740c579ca6bda9865..93e7f50e778150b3895c0f66eecbd129428946a7 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 49fb2f751e5a82f5c11b6eb5fb0f681af8428c9d..8c03063d447bfd18a4974f349b5c52e6767e436d 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 f60d747fea34adcc06f45c583f7ca6d20d97dac6..9f9a0c6ec4857ce8fa10bae57e8f10bfe504ac1b 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 d540e9e43991e0d25f1d18bfc6711bb531edf48b..12dd371a15725ab8db43b24bfdc097abb32482a7 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 d1fe8b29d5686e05a9c89e5ed6fbe4686d1d7479..9ded9f55f0878d82ccda0a936f000bb814f646a0 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 e71db4ce7fc0c046f8f77f2e642a4e766b8600f1..7033efe4d50d6bc8708c9f2db94304f9ce659370 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 df81ef186936785a6072a8ea2094a833ef077c08..29c7931b6a6142d0483cbd5db38402720e971c3d 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 e9599ef179547b691d5068aabfc41799244afd30..f191ea8d838264f5ceb6f858be4879ad8826e1c4 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 657798b68b05b42fd1bdc8d0e0b782d8938387c5..c3594952a35e9bb1195a97c89c264986d11a3bc2 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 2b6610dee56836899f53efd54a23839b22002e68..64776f209732e051880662e844eef147d2515cc8 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 42da1d9e9ed6ca0dc638850bff6c18bcaf89ff71..0e5e977222268bf914718dd353b8d97c6a13ae74 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 345bf7464dc0195a31dd1405feebdf748f2e9785..1b781ab7f45fd220a8b395534e62fc00694530de 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 0000000000000000000000000000000000000000..e73d2b00bd97780ce68a5f4076f64f00619bd916 --- /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 38356ae06e946c2071c734c6e3f46814bc521209..ebf7c5b158ddf138cdb6c8d53ab8a95bad203689 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 0000000000000000000000000000000000000000..a3a202be0577d4054cf1c997d756acf7ab217654 --- /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 16674c49e1ebfc0028770c444d6ba70b185f35e0..f41a8b376c6c19d5c14874eda09fd50a0a8bf1e9 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 6d02d3346844028ed442dd968062a9823628be74..24c7383a6533d244c36e1adb441104573a6b9b25 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 29f51e8e09a565fa61382166a80574b2a9a0280e..3bc0702a5c16949e23c2adf6efdb8a094fcebfb1 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 e175bb4f8babc9a188bc4e5fec1320b84ec0ef50..3ebeeefb3822e1c731942464c2bb9a8726eb6eef 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 })}