From 5c7d9614fa66d97cee3585b238488d7ebfbf76f9 Mon Sep 17 00:00:00 2001 From: Valentyna Date: Mon, 9 Dec 2024 16:44:08 +0100 Subject: [PATCH 1/3] docs(react-color-picker): Added RGB fields to stories. --- .../ColorPickerDefault.stories.tsx | 85 ++++++++++++++++++- 1 file changed, 84 insertions(+), 1 deletion(-) diff --git a/packages/react-components/react-color-picker-preview/stories/src/ColorPicker/ColorPickerDefault.stories.tsx b/packages/react-components/react-color-picker-preview/stories/src/ColorPicker/ColorPickerDefault.stories.tsx index 4ba93f4bbf9392..4406c9c6835b02 100644 --- a/packages/react-components/react-color-picker-preview/stories/src/ColorPicker/ColorPickerDefault.stories.tsx +++ b/packages/react-components/react-color-picker-preview/stories/src/ColorPicker/ColorPickerDefault.stories.tsx @@ -1,6 +1,15 @@ import * as React from 'react'; import { tinycolor } from '@ctrl/tinycolor'; -import { makeStyles, useId, Input, type InputProps, Label } from '@fluentui/react-components'; +import { + makeStyles, + useId, + Input, + type InputProps, + Label, + SpinButton, + type SpinButtonProps, + type SpinButtonOnChangeData, +} from '@fluentui/react-components'; import { ColorPicker, ColorSlider, @@ -36,23 +45,51 @@ const useStyles = makeStyles({ input: { width: '80px', }, + spinButton: { + width: '50px', + }, }); const HEX_COLOR_REGEX = /^#?([0-9A-Fa-f]{0,6})$/; +const NUMBER_REGEX = /^\d+$/; const DEFAULT_COLOR_HSV = tinycolor('#2be700').toHsv(); +type RgbKey = 'r' | 'g' | 'b'; + export const Default = () => { const hexId = useId('hex-input'); const styles = useStyles(); const [color, setColor] = React.useState(DEFAULT_COLOR_HSV); const [hex, setHex] = React.useState(tinycolor(color).toHexString()); + const [rgb, setRgb] = React.useState(tinycolor(color).toRgb()); + const [red, setRed] = React.useState(rgb.r); + const [green, setGreen] = React.useState(rgb.g); + const [blue, setBlue] = React.useState(rgb.b); const handleChange: ColorPickerProps['onColorChange'] = (_, data) => { setColor({ ...data.color, a: data.color.a ?? 1 }); setHex(tinycolor(data.color).toHexString()); }; + const onRgbChange = ( + colorKey: RgbKey, + setColorFunction: React.Dispatch>, + data: SpinButtonOnChangeData, + ) => { + const value = data.displayValue ? parseInt(data.displayValue, 10) : data.value; + if (!value) { + return; + } + const newColor = tinycolor({ ...rgb, [colorKey]: value }); + if (newColor.isValid) { + setColor(newColor.toHsv()); + setHex(newColor.toHex()); + setRgb(newColor.toRgb()); + } + setColorFunction((oldValue: number) => (NUMBER_REGEX.test(value.toString()) ? value : oldValue)); + }; + return (
@@ -74,7 +111,11 @@ export const Default = () => { setHex(oldValue => (HEX_COLOR_REGEX.test(value) ? value : oldValue)); }} /> + onRgbChange('r', setRed, data)} /> + onRgbChange('g', setGreen, data)} /> + onRgbChange('b', setBlue, data)} />
+
); }; @@ -99,6 +140,34 @@ const InputHexField = ({ ); }; +const InputRgbField = ({ + value, + onChange, + label, +}: { + value: number; + label: string; + onChange?: SpinButtonProps['onChange']; +}) => { + const id = useId(`${label.toLowerCase()}-input`); + const styles = useStyles(); + + return ( +
+ + +
+ ); +}; + const handleOnBlur = (e: React.FocusEvent) => { const value = tinycolor(e.target.value); if (!value.isValid) { @@ -107,3 +176,17 @@ const handleOnBlur = (e: React.FocusEvent) => { e.target.removeAttribute('aria-invalid'); } }; + +const handleRgbKeyPress = (e: React.KeyboardEvent) => { + const allowedKeys = ['Backspace', 'Delete', 'ArrowLeft', 'ArrowRight', 'Tab', 'Enter', 'ArrowUp', 'ArrowDown']; + + const isCtrlCmd = e.ctrlKey || e.metaKey; + + if (isCtrlCmd && e.key) { + return; + } + + if (!allowedKeys.includes(e.key) && !NUMBER_REGEX.test((e.target as HTMLInputElement).value + e.key)) { + e.preventDefault(); + } +}; From b6bcee151d8112f38f4bf0b3c2547e1cda740531 Mon Sep 17 00:00:00 2001 From: Valentyna Date: Mon, 16 Dec 2024 15:51:33 +0100 Subject: [PATCH 2/3] PR fix --- .../ColorPickerDefault.stories.tsx | 25 ++++++++++--------- 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/packages/react-components/react-color-picker-preview/stories/src/ColorPicker/ColorPickerDefault.stories.tsx b/packages/react-components/react-color-picker-preview/stories/src/ColorPicker/ColorPickerDefault.stories.tsx index 4406c9c6835b02..a38eb8ac0d8eee 100644 --- a/packages/react-components/react-color-picker-preview/stories/src/ColorPicker/ColorPickerDefault.stories.tsx +++ b/packages/react-components/react-color-picker-preview/stories/src/ColorPicker/ColorPickerDefault.stories.tsx @@ -9,6 +9,7 @@ import { SpinButton, type SpinButtonProps, type SpinButtonOnChangeData, + type SpinButtonChangeEvent, } from '@fluentui/react-components'; import { ColorPicker, @@ -63,31 +64,28 @@ export const Default = () => { const [color, setColor] = React.useState(DEFAULT_COLOR_HSV); const [hex, setHex] = React.useState(tinycolor(color).toHexString()); const [rgb, setRgb] = React.useState(tinycolor(color).toRgb()); - const [red, setRed] = React.useState(rgb.r); - const [green, setGreen] = React.useState(rgb.g); - const [blue, setBlue] = React.useState(rgb.b); const handleChange: ColorPickerProps['onColorChange'] = (_, data) => { setColor({ ...data.color, a: data.color.a ?? 1 }); setHex(tinycolor(data.color).toHexString()); + setRgb(tinycolor(data.color).toRgb()); }; - const onRgbChange = ( - colorKey: RgbKey, - setColorFunction: React.Dispatch>, - data: SpinButtonOnChangeData, - ) => { + const onRgbChange = (event: SpinButtonChangeEvent, data: SpinButtonOnChangeData) => { const value = data.displayValue ? parseInt(data.displayValue, 10) : data.value; + if (!value) { return; } + + const colorKey = (event.target as HTMLInputElement).name as RgbKey; + const newColor = tinycolor({ ...rgb, [colorKey]: value }); if (newColor.isValid) { setColor(newColor.toHsv()); setHex(newColor.toHex()); setRgb(newColor.toRgb()); } - setColorFunction((oldValue: number) => (NUMBER_REGEX.test(value.toString()) ? value : oldValue)); }; return ( @@ -111,9 +109,9 @@ export const Default = () => { setHex(oldValue => (HEX_COLOR_REGEX.test(value) ? value : oldValue)); }} /> - onRgbChange('r', setRed, data)} /> - onRgbChange('g', setGreen, data)} /> - onRgbChange('b', setBlue, data)} /> + + +
@@ -144,9 +142,11 @@ const InputRgbField = ({ value, onChange, label, + name, }: { value: number; label: string; + name: RgbKey; onChange?: SpinButtonProps['onChange']; }) => { const id = useId(`${label.toLowerCase()}-input`); @@ -163,6 +163,7 @@ const InputRgbField = ({ value={value} id={id} onChange={onChange} + name={name} /> ); From 592d1827874a2364cc165c8412fc829eceaef993 Mon Sep 17 00:00:00 2001 From: Valentyna Date: Fri, 20 Dec 2024 16:47:50 +0100 Subject: [PATCH 3/3] removed handleRgbKeyPress --- .../ColorPickerDefault.stories.tsx | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) diff --git a/packages/react-components/react-color-picker-preview/stories/src/ColorPicker/ColorPickerDefault.stories.tsx b/packages/react-components/react-color-picker-preview/stories/src/ColorPicker/ColorPickerDefault.stories.tsx index a38eb8ac0d8eee..4902f0cf02eb84 100644 --- a/packages/react-components/react-color-picker-preview/stories/src/ColorPicker/ColorPickerDefault.stories.tsx +++ b/packages/react-components/react-color-picker-preview/stories/src/ColorPicker/ColorPickerDefault.stories.tsx @@ -72,9 +72,9 @@ export const Default = () => { }; const onRgbChange = (event: SpinButtonChangeEvent, data: SpinButtonOnChangeData) => { - const value = data.displayValue ? parseInt(data.displayValue, 10) : data.value; + const value = data.value ?? (data.displayValue !== undefined ? parseFloat(data.displayValue) : null); - if (!value) { + if (value === null || Number.isNaN(value) || !NUMBER_REGEX.test(value.toString())) { return; } @@ -156,7 +156,6 @@ const InputRgbField = ({
) => { e.target.removeAttribute('aria-invalid'); } }; - -const handleRgbKeyPress = (e: React.KeyboardEvent) => { - const allowedKeys = ['Backspace', 'Delete', 'ArrowLeft', 'ArrowRight', 'Tab', 'Enter', 'ArrowUp', 'ArrowDown']; - - const isCtrlCmd = e.ctrlKey || e.metaKey; - - if (isCtrlCmd && e.key) { - return; - } - - if (!allowedKeys.includes(e.key) && !NUMBER_REGEX.test((e.target as HTMLInputElement).value + e.key)) { - e.preventDefault(); - } -};