diff --git a/libs/designer-ui/src/lib/html/plugins/toolbar/DropdownColorPicker.tsx b/libs/designer-ui/src/lib/html/plugins/toolbar/DropdownColorPicker.tsx index f3969125abd..5c29be8149e 100644 --- a/libs/designer-ui/src/lib/html/plugins/toolbar/DropdownColorPicker.tsx +++ b/libs/designer-ui/src/lib/html/plugins/toolbar/DropdownColorPicker.tsx @@ -9,6 +9,7 @@ import { transformColor } from '@microsoft/logic-apps-shared'; import type { LexicalEditor } from 'lexical'; import { useEffect, useMemo, useRef, useState } from 'react'; import constants from '../../../constants'; +import { useDebouncedState } from '@react-hookz/web'; interface DropdownColorPickerProps { disabled?: boolean; @@ -17,7 +18,7 @@ interface DropdownColorPickerProps { buttonIconSrc?: string; buttonLabel?: string; color: string; - onChange?: (color: string) => void; + onChange: (color: string) => void; title?: string; editor: LexicalEditor; } @@ -34,6 +35,7 @@ export const DropdownColorPicker = ({ const { isInverted } = useTheme(); const [selfColor, setSelfColor] = useState(transformColor('hex', color)); const [inputColor, setInputColor] = useState(color); + const [exposedColor, setExposedColor] = useDebouncedState(selfColor, 300); const innerDivRef = useRef(null); const arrowNavigationAttributes = useArrowNavigationGroup({ axis: 'horizontal', circular: true }); @@ -81,11 +83,17 @@ export const DropdownColorPicker = ({ useEffect(() => { // Check if the dropdown is actually active - if (innerDivRef.current !== null && onChange) { - onChange(selfColor.hex); + if (innerDivRef.current !== null) { + if (exposedColor.hex !== selfColor.hex) { + setExposedColor(selfColor); + } setInputColor(selfColor.hex); } - }, [selfColor, onChange]); + }, [exposedColor, selfColor, setExposedColor]); + + useEffect(() => { + onChange(exposedColor.hex); + }, [exposedColor, onChange]); useEffect(() => { if (color === undefined) { @@ -120,6 +128,7 @@ export const DropdownColorPicker = ({ className="color-picker-saturation" style={{ backgroundColor: `hsl(${selfColor.hsv.hue}, 100%, 50%)` }} onChange={onMoveSaturation} + value={saturationPosition} >
- +
void; - children: JSX.Element; + style?: React.CSSProperties; + value: Position; } -export const MoveWrapper = ({ className, style, onChange, children }: MoveWrapperProps) => { +const keyMoveMap: Record = { + ArrowLeft: { x: -1, y: 0 }, + ArrowRight: { x: 1, y: 0 }, + ArrowUp: { x: 0, y: -1 }, + ArrowDown: { x: 0, y: 1 }, +}; + +export const MoveWrapper = ({ children, className, onChange, style, value }: MoveWrapperProps) => { const divRef = useRef(null); + const getBoundingClientRect = (): DOMRect | undefined => { + return divRef.current?.getBoundingClientRect(); + } + const move = (e: React.MouseEvent | MouseEvent): void => { - if (divRef.current) { - const { current: div } = divRef; - const { width, height, left, top, right } = div.getBoundingClientRect(); + const rect = getBoundingClientRect(); + if (rect) { + const { width, height, left, top, right } = rect; if (e.clientX <= right && e.clientX >= left) { const x = clamp(e.clientX - left, width, 0); @@ -47,8 +59,26 @@ export const MoveWrapper = ({ className, style, onChange, children }: MoveWrappe document.addEventListener('mouseup', onMouseUp, false); }; + const onKeyDown = (e: React.KeyboardEvent): void => { + const { key } = e; + const rect = getBoundingClientRect(); + + if (rect && key in keyMoveMap) { + const { width, height } = rect; + const multiplier = e.shiftKey ? 10 : 1; + const offset = keyMoveMap[key]; + + onChange({ + x: clamp(value.x + (multiplier * offset.x), width, 0), + y: clamp(value.y + (multiplier * offset.y), height, 0), + }); + + e.preventDefault(); + } + } + return ( -
+
{children}
);