diff --git a/invokeai/frontend/web/src/common/components/RgbColorPicker.tsx b/invokeai/frontend/web/src/common/components/ColorPicker/RgbColorPicker.tsx similarity index 66% rename from invokeai/frontend/web/src/common/components/RgbColorPicker.tsx rename to invokeai/frontend/web/src/common/components/ColorPicker/RgbColorPicker.tsx index ecb9405a3d..1361039b75 100644 --- a/invokeai/frontend/web/src/common/components/RgbColorPicker.tsx +++ b/invokeai/frontend/web/src/common/components/ColorPicker/RgbColorPicker.tsx @@ -1,15 +1,19 @@ import type { ChakraProps } from '@invoke-ai/ui-library'; -import { CompositeNumberInput, Flex, FormControl, FormLabel } from '@invoke-ai/ui-library'; +import { Box, CompositeNumberInput, Flex, FormControl, FormLabel } from '@invoke-ai/ui-library'; +import { RGB_COLOR_SWATCHES } from 'common/components/ColorPicker/swatches'; +import { rgbColorToString } from 'common/util/colorCodeTransformers'; import type { CSSProperties } from 'react'; import { memo, useCallback } from 'react'; import { RgbColorPicker as ColorfulRgbColorPicker } from 'react-colorful'; -import type { ColorPickerBaseProps, RgbColor } from 'react-colorful/dist/types'; +import type { RgbColor } from 'react-colorful/dist/types'; import { useTranslation } from 'react-i18next'; -type RgbColorPickerProps = ColorPickerBaseProps & { +type Props = { + color: RgbColor; + onChange: (color: RgbColor) => void; withNumberInput?: boolean; + withSwatches?: boolean; }; - const colorPickerPointerStyles: NonNullable = { width: 6, height: 6, @@ -20,7 +24,7 @@ const sx: ChakraProps['sx'] = { '.react-colorful__hue-pointer': colorPickerPointerStyles, '.react-colorful__saturation-pointer': colorPickerPointerStyles, '.react-colorful__alpha-pointer': colorPickerPointerStyles, - gap: 5, + gap: 4, flexDir: 'column', }; @@ -28,20 +32,21 @@ const colorPickerStyles: CSSProperties = { width: '100%' }; const numberInputWidth: ChakraProps['w'] = '3.5rem'; -const RgbColorPicker = (props: RgbColorPickerProps) => { - const { color, onChange, withNumberInput, ...rest } = props; +const RgbColorPicker = (props: Props) => { + const { color, onChange, withNumberInput = false, withSwatches = false } = props; const { t } = useTranslation(); const handleChangeR = useCallback((r: number) => onChange({ ...color, r }), [color, onChange]); const handleChangeG = useCallback((g: number) => onChange({ ...color, g }), [color, onChange]); const handleChangeB = useCallback((b: number) => onChange({ ...color, b }), [color, onChange]); return ( - + {withNumberInput && ( - + {t('common.red')[0]} { {t('common.green')[0]} { {t('common.blue')[0]} { )} + {withSwatches && ( + + {RGB_COLOR_SWATCHES.map((color, i) => ( + + ))} + + )} ); }; export default memo(RgbColorPicker); + +const ColorSwatch = ({ color, onChange }: { color: RgbColor; onChange: (color: RgbColor) => void }) => { + const onClick = useCallback(() => { + onChange(color); + }, [color, onChange]); + return ; +}; diff --git a/invokeai/frontend/web/src/common/components/IAIColorPicker.tsx b/invokeai/frontend/web/src/common/components/ColorPicker/RgbaColorPicker.tsx similarity index 67% rename from invokeai/frontend/web/src/common/components/IAIColorPicker.tsx rename to invokeai/frontend/web/src/common/components/ColorPicker/RgbaColorPicker.tsx index 25b129f678..fb3b1da2a0 100644 --- a/invokeai/frontend/web/src/common/components/IAIColorPicker.tsx +++ b/invokeai/frontend/web/src/common/components/ColorPicker/RgbaColorPicker.tsx @@ -1,13 +1,18 @@ import type { ChakraProps } from '@invoke-ai/ui-library'; -import { CompositeNumberInput, Flex, FormControl, FormLabel } from '@invoke-ai/ui-library'; +import { Box, CompositeNumberInput, Flex, FormControl, FormLabel } from '@invoke-ai/ui-library'; +import { RGBA_COLOR_SWATCHES } from 'common/components/ColorPicker/swatches'; +import { rgbaColorToString } from 'common/util/colorCodeTransformers'; import type { CSSProperties } from 'react'; import { memo, useCallback } from 'react'; -import { RgbaColorPicker } from 'react-colorful'; -import type { ColorPickerBaseProps, RgbaColor } from 'react-colorful/dist/types'; +import { RgbaColorPicker as ColorfulRgbaColorPicker } from 'react-colorful'; +import type { RgbaColor } from 'react-colorful/dist/types'; import { useTranslation } from 'react-i18next'; -type IAIColorPickerProps = ColorPickerBaseProps & { +type Props = { + color: RgbaColor; + onChange: (color: RgbaColor) => void; withNumberInput?: boolean; + withSwatches?: boolean; }; const colorPickerPointerStyles: NonNullable = { @@ -20,7 +25,7 @@ const sx: ChakraProps['sx'] = { '.react-colorful__hue-pointer': colorPickerPointerStyles, '.react-colorful__saturation-pointer': colorPickerPointerStyles, '.react-colorful__alpha-pointer': colorPickerPointerStyles, - gap: 5, + gap: 4, flexDir: 'column', }; @@ -28,8 +33,8 @@ const colorPickerStyles: CSSProperties = { width: '100%' }; const numberInputWidth: ChakraProps['w'] = '3.5rem'; -const IAIColorPicker = (props: IAIColorPickerProps) => { - const { color, onChange, withNumberInput, ...rest } = props; +const RgbaColorPicker = (props: Props) => { + const { color, onChange, withNumberInput = false, withSwatches = false } = props; const { t } = useTranslation(); const handleChangeR = useCallback((r: number) => onChange({ ...color, r }), [color, onChange]); const handleChangeG = useCallback((g: number) => onChange({ ...color, g }), [color, onChange]); @@ -37,9 +42,9 @@ const IAIColorPicker = (props: IAIColorPickerProps) => { const handleChangeA = useCallback((a: number) => onChange({ ...color, a }), [color, onChange]); return ( - + {withNumberInput && ( - + {t('common.red')[0]} { )} + {withSwatches && ( + + {RGBA_COLOR_SWATCHES.map((color, i) => ( + + ))} + + )} ); }; -export default memo(IAIColorPicker); +export default memo(RgbaColorPicker); + +const ColorSwatch = ({ color, onChange }: { color: RgbaColor; onChange: (color: RgbaColor) => void }) => { + const onClick = useCallback(() => { + onChange(color); + }, [color, onChange]); + return ; +}; diff --git a/invokeai/frontend/web/src/common/components/ColorPicker/swatches.ts b/invokeai/frontend/web/src/common/components/ColorPicker/swatches.ts new file mode 100644 index 0000000000..0bbbcfe3da --- /dev/null +++ b/invokeai/frontend/web/src/common/components/ColorPicker/swatches.ts @@ -0,0 +1,16 @@ +const SWATCHES = [ + { r: 0, g: 0, b: 0, a: 1 }, // black + { r: 255, g: 255, b: 255, a: 1 }, // white + { r: 255, g: 90, b: 94, a: 1 }, // red + { r: 255, g: 146, b: 75, a: 1 }, // orange + { r: 255, g: 202, b: 59, a: 1 }, // yellow + { r: 197, g: 202, b: 48, a: 1 }, // lime + { r: 138, g: 201, b: 38, a: 1 }, // green + { r: 83, g: 165, b: 117, a: 1 }, // teal + { r: 23, g: 130, b: 196, a: 1 }, // blue + { r: 66, g: 103, b: 172, a: 1 }, // indigo + { r: 107, g: 76, b: 147, a: 1 }, // purple +]; + +export const RGBA_COLOR_SWATCHES = SWATCHES; +export const RGB_COLOR_SWATCHES = SWATCHES.map(({ r, g, b }) => ({ r, g, b })); diff --git a/invokeai/frontend/web/src/features/controlLayers/components/CanvasEntityList/EntityListSelectedEntityActionBarFill.tsx b/invokeai/frontend/web/src/features/controlLayers/components/CanvasEntityList/EntityListSelectedEntityActionBarFill.tsx index aaac4d1b42..3004ddc0b8 100644 --- a/invokeai/frontend/web/src/features/controlLayers/components/CanvasEntityList/EntityListSelectedEntityActionBarFill.tsx +++ b/invokeai/frontend/web/src/features/controlLayers/components/CanvasEntityList/EntityListSelectedEntityActionBarFill.tsx @@ -1,6 +1,6 @@ import { Box, Flex, Popover, PopoverBody, PopoverContent, PopoverTrigger, Tooltip } from '@invoke-ai/ui-library'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; -import RgbColorPicker from 'common/components/RgbColorPicker'; +import RgbColorPicker from 'common/components/ColorPicker/RgbColorPicker'; import { rgbColorToString } from 'common/util/colorCodeTransformers'; import { MaskFillStyle } from 'features/controlLayers/components/common/MaskFillStyle'; import { entityFillColorChanged, entityFillStyleChanged } from 'features/controlLayers/store/canvasSlice'; @@ -65,7 +65,7 @@ export const EntityListSelectedEntityActionBarFill = memo(() => { - + diff --git a/invokeai/frontend/web/src/features/controlLayers/components/Tool/ToolFillColorPicker.tsx b/invokeai/frontend/web/src/features/controlLayers/components/Tool/ToolFillColorPicker.tsx index e9ca638b10..7d1b4bdd0e 100644 --- a/invokeai/frontend/web/src/features/controlLayers/components/Tool/ToolFillColorPicker.tsx +++ b/invokeai/frontend/web/src/features/controlLayers/components/Tool/ToolFillColorPicker.tsx @@ -1,7 +1,16 @@ -import { Box, Flex, Popover, PopoverBody, PopoverContent, PopoverTrigger, Tooltip } from '@invoke-ai/ui-library'; +import { + Box, + Flex, + Popover, + PopoverArrow, + PopoverBody, + PopoverContent, + PopoverTrigger, + Tooltip, +} from '@invoke-ai/ui-library'; import { createSelector } from '@reduxjs/toolkit'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; -import IAIColorPicker from 'common/components/IAIColorPicker'; +import RgbaColorPicker from 'common/components/ColorPicker/RgbaColorPicker'; import { rgbaColorToString } from 'common/util/colorCodeTransformers'; import { selectCanvasSettingsSlice, settingsColorChanged } from 'features/controlLayers/store/canvasSettingsSlice'; import type { RgbaColor } from 'features/controlLayers/store/types'; @@ -12,20 +21,6 @@ import { useTranslation } from 'react-i18next'; const selectColor = createSelector(selectCanvasSettingsSlice, (settings) => settings.color); -const SWATCHES = [ - { r: 0, g: 0, b: 0, a: 1 }, // black - { r: 255, g: 255, b: 255, a: 1 }, // white - { r: 255, g: 90, b: 94, a: 1 }, // red - { r: 255, g: 146, b: 75, a: 1 }, // orange - { r: 255, g: 202, b: 59, a: 1 }, // yellow - { r: 197, g: 202, b: 48, a: 1 }, // lime - { r: 138, g: 201, b: 38, a: 1 }, // green - { r: 83, g: 165, b: 117, a: 1 }, // teal - { r: 23, g: 130, b: 196, a: 1 }, // blue - { r: 66, g: 103, b: 172, a: 1 }, // indigo - { r: 107, g: 76, b: 147, a: 1 }, // purple -]; - export const ToolColorPicker = memo(() => { const { t } = useTranslation(); const fill = useAppSelector(selectColor); @@ -65,15 +60,9 @@ export const ToolColorPicker = memo(() => { + - - - - {SWATCHES.map((color, i) => ( - - ))} - - + @@ -81,22 +70,3 @@ export const ToolColorPicker = memo(() => { }); ToolColorPicker.displayName = 'ToolFillColorPicker'; - -const ColorSwatch = ({ color }: { color: RgbaColor }) => { - const dispatch = useAppDispatch(); - const onClick = useCallback(() => { - dispatch(settingsColorChanged(color)); - }, [color, dispatch]); - return ( - - ); -}; diff --git a/invokeai/frontend/web/src/features/parameters/components/Canvas/InfillAndScaling/ParamInfillColorOptions.tsx b/invokeai/frontend/web/src/features/parameters/components/Canvas/InfillAndScaling/ParamInfillColorOptions.tsx index 19aeb133a0..bea45ae282 100644 --- a/invokeai/frontend/web/src/features/parameters/components/Canvas/InfillAndScaling/ParamInfillColorOptions.tsx +++ b/invokeai/frontend/web/src/features/parameters/components/Canvas/InfillAndScaling/ParamInfillColorOptions.tsx @@ -1,6 +1,6 @@ import { Box, Flex, FormControl, FormLabel } from '@invoke-ai/ui-library'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; -import IAIColorPicker from 'common/components/IAIColorPicker'; +import RgbaColorPicker from 'common/components/ColorPicker/RgbaColorPicker'; import { selectInfillColorValue, selectInfillMethod, @@ -30,7 +30,7 @@ const ParamInfillColorOptions = () => { {t('parameters.infillColorValue')} - +