diff --git a/apps/builder/app/builder/features/style-panel/shared/color-picker.tsx b/apps/builder/app/builder/features/style-panel/shared/color-picker.tsx index e2f78c1dfd..b5ce3a7ab0 100644 --- a/apps/builder/app/builder/features/style-panel/shared/color-picker.tsx +++ b/apps/builder/app/builder/features/style-panel/shared/color-picker.tsx @@ -218,7 +218,8 @@ export const ColorPicker = ({ > { - // Use Euclidian distance, if will not give good results use https://zschuessler.github.io/DeltaE/ + // Use Euclidian distance + // If results are not good, lets switch to https://zschuessler.github.io/DeltaE/ return Math.sqrt( Math.pow(a.r / 255 - b.r / 255, 2) + Math.pow(a.g / 255 - b.g / 255, 2) + @@ -17,6 +18,19 @@ const distance = (a: RgbaColor, b: RgbaColor) => { ); }; +// White color is invisible on white background, so we need to draw border +// the more color is white the more border is visible +const calcBorderColor = (color: RgbaColor) => { + const distanceToStartDrawBorder = 0.15; + const alpha = clamp( + (distanceToStartDrawBorder - distance(whiteColor, color)) / + distanceToStartDrawBorder, + 0, + 1 + ); + return colord(lerpColor(transparentColor, borderColorSwatch, alpha)); +}; + const lerp = (a: number, b: number, t: number) => { return a * (1 - t) + b * t; }; @@ -30,53 +44,37 @@ const lerpColor = (a: RgbaColor, b: RgbaColor, t: number) => { }; }; -const style = css({ +const thumbStyle = css({ width: theme.spacing[10], height: theme.spacing[10], backgroundBlendMode: "difference", - borderRadius: 2, + borderRadius: theme.borderRadius[2], borderWidth: 0, + borderStyle: "solid", }); export const ColorThumb = forwardRef< - ElementRef, - Omit, "color"> & { color: RgbaColor | undefined } ->(({ color, css, ...rest }, ref) => { - const colorString = colord(color || transparent).toRgbString(); - // @todo transparent icon can be better + ElementRef<"button">, + Omit, "color"> & { color?: RgbaColor; css?: CSS } +>(({ color = transparentColor, css, ...rest }, ref) => { const background = - color === null || (color && color.a < 1) - ? // chessboard 5x5 - `repeating-conic-gradient(rgba(0,0,0,0.22) 0% 25%, transparent 0% 50%) 0% 33.33% / 40% 40%, ${colorString}` - : colorString; - - const distanceToStartDrawBorder = 0.15; - - // White color is invisible on white background, so we need to draw border - // the more color is white the more border is visible - const borderColor = colord( - lerpColor( - transparent, - borderColorSwatch, - clamp( - (distanceToStartDrawBorder - - distance(whiteColor, color || transparent)) / - distanceToStartDrawBorder, - 0, - 1 - ) - ) - ).toRgbString(); + color === undefined || color.a < 1 + ? // Chessboard pattern 5x5 + `repeating-conic-gradient(rgba(0,0,0,0.22) 0% 25%, transparent 0% 50%) 0% 33.33% / 40% 40%, ${colord(color).toRgbString()}` + : colord(color).toRgbString(); + const borderColor = calcBorderColor(color); return ( - ); }); diff --git a/packages/design-system/src/components/input-field.tsx b/packages/design-system/src/components/input-field.tsx index 7f71249036..aa3206b2e3 100644 --- a/packages/design-system/src/components/input-field.tsx +++ b/packages/design-system/src/components/input-field.tsx @@ -280,6 +280,8 @@ export const InputField = forwardRef( // This way user can unfocus the input and then use any single-key shortcut. tabIndex={-1} ref={unfocusContainerRef} + // When managing focus with ArrowFocus, we don't want to focus this element. + data-no-arrow-focus /> diff --git a/packages/design-system/src/components/primitives/arrow-focus.tsx b/packages/design-system/src/components/primitives/arrow-focus.tsx index 7cb6da5404..e7f2b0c095 100644 --- a/packages/design-system/src/components/primitives/arrow-focus.tsx +++ b/packages/design-system/src/components/primitives/arrow-focus.tsx @@ -51,6 +51,12 @@ const willEventMoveCaret = (event: KeyboardEvent) => { return true; }; +const accept = (element: Element) => { + // In some cases we want to have an element that is tabbable, but it should not be ignored for arrow focus management. + // One use case is in input field, which is using ESC to focus an div to unfocus the input + return element.hasAttribute("data-no-arrow-focus") === false; +}; + // Need this wrapper becuase we can't call useFocusManager // in the same component that renders FocusScope const ContextHelper = ({ render }: { render: Render }) => { @@ -79,11 +85,15 @@ const ContextHelper = ({ render }: { render: Render }) => { } if (event.key === "ArrowRight" || event.key === "ArrowDown") { - focusManager.focusNext({ wrap: true, ...focusManagerOptions }); + focusManager.focusNext({ wrap: true, accept, ...focusManagerOptions }); event.preventDefault(); // Prevents the page from scrolling } if (event.key === "ArrowLeft" || event.key === "ArrowUp") { - focusManager.focusPrevious({ wrap: true, ...focusManagerOptions }); + focusManager.focusPrevious({ + wrap: true, + accept, + ...focusManagerOptions, + }); event.preventDefault(); // Prevents the page from scrolling } },