@mortenbrudvik/waveui 0.9.0 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +425 -104
- package/dist/components/input/Calendar.cjs +2 -0
- package/dist/components/input/Calendar.cjs.map +1 -0
- package/dist/components/input/Calendar.mjs +352 -0
- package/dist/components/input/Calendar.mjs.map +1 -0
- package/dist/components/input/Calendar.views.cjs +2 -0
- package/dist/components/input/Calendar.views.cjs.map +1 -0
- package/dist/components/input/Calendar.views.mjs +194 -0
- package/dist/components/input/Calendar.views.mjs.map +1 -0
- package/dist/components/input/ColorArea.cjs +1 -1
- package/dist/components/input/ColorArea.cjs.map +1 -1
- package/dist/components/input/ColorArea.mjs +18 -18
- package/dist/components/input/ColorArea.mjs.map +1 -1
- package/dist/components/input/Combobox.cjs +1 -1
- package/dist/components/input/Combobox.cjs.map +1 -1
- package/dist/components/input/Combobox.mjs +232 -156
- package/dist/components/input/Combobox.mjs.map +1 -1
- package/dist/components/input/Combobox.text.cjs +2 -0
- package/dist/components/input/Combobox.text.cjs.map +1 -0
- package/dist/components/input/Combobox.text.mjs +24 -0
- package/dist/components/input/Combobox.text.mjs.map +1 -0
- package/dist/components/input/DatePicker.cjs +1 -1
- package/dist/components/input/DatePicker.cjs.map +1 -1
- package/dist/components/input/DatePicker.mjs +203 -288
- package/dist/components/input/DatePicker.mjs.map +1 -1
- package/dist/components/input/Dropdown.cjs +1 -1
- package/dist/components/input/Dropdown.cjs.map +1 -1
- package/dist/components/input/Dropdown.mjs +135 -109
- package/dist/components/input/Dropdown.mjs.map +1 -1
- package/dist/components/input/Listbox.cjs +2 -0
- package/dist/components/input/Listbox.cjs.map +1 -0
- package/dist/components/input/Listbox.mjs +134 -0
- package/dist/components/input/Listbox.mjs.map +1 -0
- package/dist/components/input/Option.cjs +1 -1
- package/dist/components/input/Option.cjs.map +1 -1
- package/dist/components/input/Option.mjs +158 -97
- package/dist/components/input/Option.mjs.map +1 -1
- package/dist/components/input/SwatchPicker.cjs +1 -1
- package/dist/components/input/SwatchPicker.cjs.map +1 -1
- package/dist/components/input/SwatchPicker.context.cjs +2 -0
- package/dist/components/input/SwatchPicker.context.cjs.map +1 -0
- package/dist/components/input/SwatchPicker.context.mjs +35 -0
- package/dist/components/input/SwatchPicker.context.mjs.map +1 -0
- package/dist/components/input/SwatchPicker.mjs +131 -103
- package/dist/components/input/SwatchPicker.mjs.map +1 -1
- package/dist/components/input/SwatchPicker.swatches.cjs +2 -0
- package/dist/components/input/SwatchPicker.swatches.cjs.map +1 -0
- package/dist/components/input/SwatchPicker.swatches.mjs +207 -0
- package/dist/components/input/SwatchPicker.swatches.mjs.map +1 -0
- package/dist/components/input/TagPicker.cjs +1 -1
- package/dist/components/input/TagPicker.cjs.map +1 -1
- package/dist/components/input/TagPicker.mjs +144 -139
- package/dist/components/input/TagPicker.mjs.map +1 -1
- package/dist/components/input/TimePicker.cjs +1 -1
- package/dist/components/input/TimePicker.cjs.map +1 -1
- package/dist/components/input/TimePicker.mjs +77 -77
- package/dist/components/input/TimePicker.mjs.map +1 -1
- package/dist/components/input/dateUtils.cjs +1 -1
- package/dist/components/input/dateUtils.cjs.map +1 -1
- package/dist/components/input/dateUtils.mjs +114 -96
- package/dist/components/input/dateUtils.mjs.map +1 -1
- package/dist/components/input/pickerLabels.cjs +2 -0
- package/dist/components/input/pickerLabels.cjs.map +1 -0
- package/dist/components/input/pickerLabels.mjs +16 -0
- package/dist/components/input/pickerLabels.mjs.map +1 -0
- package/dist/components/input/pickerValues.cjs +2 -0
- package/dist/components/input/pickerValues.cjs.map +1 -0
- package/dist/components/input/pickerValues.mjs +24 -0
- package/dist/components/input/pickerValues.mjs.map +1 -0
- package/dist/components/table/useGridNavigation.cjs +1 -1
- package/dist/components/table/useGridNavigation.cjs.map +1 -1
- package/dist/components/table/useGridNavigation.mjs +67 -70
- package/dist/components/table/useGridNavigation.mjs.map +1 -1
- package/dist/hooks/useActiveDescendant.cjs +2 -0
- package/dist/hooks/useActiveDescendant.cjs.map +1 -0
- package/dist/hooks/useActiveDescendant.mjs +56 -0
- package/dist/hooks/useActiveDescendant.mjs.map +1 -0
- package/dist/hooks/useListbox.cjs +1 -1
- package/dist/hooks/useListbox.cjs.map +1 -1
- package/dist/hooks/useListbox.mjs +250 -210
- package/dist/hooks/useListbox.mjs.map +1 -1
- package/dist/hooks/useRovingGrid.cjs +2 -0
- package/dist/hooks/useRovingGrid.cjs.map +1 -0
- package/dist/hooks/useRovingGrid.mjs +69 -0
- package/dist/hooks/useRovingGrid.mjs.map +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +2147 -155
- package/dist/index.d.ts +2147 -155
- package/dist/index.mjs +107 -101
- package/dist/lib/classNames.cjs +1 -1
- package/dist/lib/classNames.cjs.map +1 -1
- package/dist/lib/classNames.mjs +84 -48
- package/dist/lib/classNames.mjs.map +1 -1
- package/dist/lib/date.cjs +2 -0
- package/dist/lib/date.cjs.map +1 -0
- package/dist/lib/date.mjs +44 -0
- package/dist/lib/date.mjs.map +1 -0
- package/dist/lib/focus.cjs +1 -1
- package/dist/lib/focus.cjs.map +1 -1
- package/dist/lib/focus.mjs +5 -2
- package/dist/lib/focus.mjs.map +1 -1
- package/dist/lib/layers.cjs.map +1 -1
- package/dist/lib/layers.mjs.map +1 -1
- package/dist/styles.css +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ColorArea.cjs","names":["useColorPartState","displayColor","toPercent","React","useMediaQuery","useMergedRefs","useFieldContext","useFieldControl","composeEventHandlers","isOwnEvent","getArrowIntent","getDirection","useEventCallback","colorAreaGradient","toPosition","hsvToHex","cn","colorAreaClassNames","COLOR_THUMB_CLASSES","areaValueText","HiddenInput","require_runtime","require_cn","require_composeEventHandlers","require_classNames","require_color","require_useEventCallback","require_direction","require_useMergedRefs","require_useFieldControl","require_useMediaQuery","require_useFormReset","require_HiddenInput","require_colorUtils","require_ColorPicker_parts","require_events","react","react_jsx_runtime","DEFAULT_LABELS","clampPercent","value","COARSE_POINTER","ColorArea","ariaLabel","ariaLabelledBy","ariaDescribedBy","ariaInvalid","ariaRequired","ariaErrorMessage","rest","part","strings","picker","labels","resolvedShape","shape","color","shown","saturation","brightness","activeAxis","setActiveAxis","coarsePointer","fieldRef","focusToken","setFocusToken","rootRef","saturationRef","brightnessRef","mergedRootRef","ref","mergedSaturationRef","controlRef","handledFocusTokenRef","field","invalid","_ariaRequired","_required","groupProps","errorMessageId","isRequired","required","form","applyAxis","percent","axis","handleKeyDown","onKeyDown","event","step","next","intent","token","handleInputChange","handleInputFocus","moveToPointer","fieldElement","rect","x","s","v","focusActiveAxis","handlePointerDown","onPointerDown","handlePointerMove","onPointerMove","textLabels","areaStyle","style","inputProps","tabIndex","className"],"sources":["../../../src/components/input/ColorArea.tsx"],"sourcesContent":["import * as React from 'react';\nimport { colorAreaClassNames } from '../../lib/classNames';\nimport { cn } from '../../lib/cn';\nimport { hsvToHex } from '../../lib/color';\nimport { composeEventHandlers } from '../../lib/composeEventHandlers';\nimport { getArrowIntent, getDirection } from '../../lib/direction';\nimport { isOwnEvent } from '../../lib/events';\nimport type { ColorPickerShape, HsvColor } from '../../lib/types';\nimport { useEventCallback } from '../../hooks/useEventCallback';\nimport { useFieldContext, useFieldControl } from '../../hooks/useFieldControl';\nimport { useFormReset } from '../../hooks/useFormReset';\nimport { useMediaQuery } from '../../hooks/useMediaQuery';\nimport { useMergedRefs } from '../../hooks/useMergedRefs';\nimport { HiddenInput } from '../internal/HiddenInput';\nimport { useColorPartState } from './ColorPicker.parts';\nimport {\n COLOR_THUMB_CLASSES,\n areaValueText,\n colorAreaGradient,\n displayColor,\n toPercent,\n toPosition,\n} from './colorUtils';\n\n/** Texts of a ColorArea, for localisation. Every key is optional. */\nexport interface ColorAreaLabels {\n /** Name of the horizontal slider.\n * @default 'Saturation'\n */\n saturation?: string;\n /** Name of the vertical slider (the `value` channel).\n * @default 'Brightness'\n */\n brightness?: string;\n /** Role description of both sliders.\n * @default '2D slider'\n */\n roleDescription?: string;\n /** Names the color at the end of each value text; return `''` to leave it out.\n * @default an English namer (\"dark blue\")\n */\n colorName?: (color: HsvColor) => string;\n /** Replaces a whole value text, for languages whose order differs. */\n valueText?: (color: HsvColor, channel: 'saturation' | 'value') => string;\n}\n\n/** Properties for the ColorArea component. */\nexport interface ColorAreaProps extends Omit<\n React.HTMLAttributes<HTMLDivElement>,\n 'defaultValue' | 'onChange'\n> {\n /**\n * The color (Fluent's `color`). Inside a ColorPicker, leave `value` and `defaultValue` out to\n * bind the area to the picker.\n */\n value?: HsvColor;\n /**\n * Initial color for uncontrolled usage (also what a form reset restores).\n * @default the brand blue, `{ h: 208, s: 0.92, v: 0.74 }` (`#0f6cbd`)\n */\n defaultValue?: HsvColor;\n /**\n * Called with the new color on every step (a key, a pointer move or assistive technology) that\n * changes it (Fluent's `onChange`). A bound area calls it too.\n */\n onValueChange?: (value: HsvColor) => void;\n /**\n * `'square'` removes the corner radius (the thumb stays round). Bound to a ColorPicker, the\n * picker's shape unless you pass one.\n * @default 'rounded'\n */\n shape?: ColorPickerShape;\n /** Texts of the area; bound to a ColorPicker, the picker's `labels` fill the keys you leave out. */\n labels?: ColorAreaLabels;\n /**\n * Unavailable: both inputs are natively disabled, pointer presses are ignored and the area is\n * dimmed. A bound area is also disabled while the picker's value is not a hex color.\n * @default false\n */\n disabled?: boolean;\n /** Form field name: the color is submitted as hex (`hsvToHex`). Ignored while bound to a ColorPicker. */\n name?: string;\n /** Id of the form the area belongs to, when it is rendered outside that form. */\n form?: string;\n /**\n * Marks the hidden form input required (a color is always set, so it never blocks). A consumer\n * `aria-required` does the same: a group supports neither, so neither is set on it.\n */\n required?: boolean;\n /** Ref to the saturation `<input type=\"range\">`. */\n controlRef?: React.Ref<HTMLInputElement>;\n /** Ref to the root `role=\"group\"` element. */\n ref?: React.Ref<HTMLDivElement>;\n}\n\n/** The two axes: saturation (x) and brightness (y, the `value` channel). */\ntype AreaAxis = 'saturation' | 'value';\n\nconst DEFAULT_LABELS = {\n saturation: 'Saturation',\n brightness: 'Brightness',\n roleDescription: '2D slider',\n} as const;\n\n/** A whole percentage clamped to 0–100. */\nfunction clampPercent(value: number): number {\n return Math.min(100, Math.max(0, value));\n}\n\n/** Touch-primary devices expose both inputs, so a touch screen reader can swipe each (D19). */\nconst COARSE_POINTER = '(pointer: coarse)';\n\n/**\n * A 2-D color field: saturation from left to right (mirrored in right-to-left layouts) and\n * brightness from bottom to top, at the value's hue. ArrowLeft and ArrowRight move saturation by\n * 1 %, ArrowUp and ArrowDown brightness; Shift with an arrow moves by 10, Page Up and Page Down\n * move brightness by 10, and Home and End set saturation to 0 and 100. A press or drag (mouse,\n * touch or pen) moves the thumb to the pointer. It is one Tab stop holding two sliders for\n * assistive technology, \"Saturation\" and \"Brightness\", whose value texts start with their own\n * channel and name the color; focus follows the axis a key moves, and unless the primary pointer\n * is coarse (touch), only the slider with the Tab stop is exposed. Inside a ColorPicker, leave\n * `value` and `defaultValue` out and it binds to the picker. Fluent's\n * `ColorArea`, with `value`/`onValueChange` for its `color`/`onChange`.\n *\n * @example\n * <ColorArea aria-label=\"Accent color\" value={color} onValueChange={setColor} />\n */\nexport const ColorArea = ({\n value,\n defaultValue,\n onValueChange,\n shape,\n labels,\n disabled = false,\n name,\n form,\n required,\n controlRef,\n className,\n style,\n id,\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledBy,\n 'aria-describedby': ariaDescribedBy,\n 'aria-invalid': ariaInvalid,\n 'aria-required': ariaRequired,\n 'aria-errormessage': ariaErrorMessage,\n autoFocus,\n tabIndex,\n onKeyDown,\n onPointerDown,\n onPointerMove,\n ref,\n ...rest\n}: ColorAreaProps) => {\n const part = useColorPartState({ value, defaultValue, onValueChange, disabled });\n const { picker } = part;\n const strings = {\n ...DEFAULT_LABELS,\n ...(picker && {\n saturation: picker.labels.saturation,\n brightness: picker.labels.brightness,\n roleDescription: picker.labels.roleDescription,\n colorName: picker.labels.colorName,\n valueText: picker.labels.valueText,\n }),\n ...labels,\n };\n const resolvedShape = shape ?? picker?.shape ?? 'rounded';\n const color = part.color;\n const shown = displayColor(color);\n const saturation = toPercent(shown.s);\n const brightness = toPercent(shown.v);\n\n const [activeAxis, setActiveAxis] = React.useState<AreaAxis>('saturation');\n const coarsePointer = useMediaQuery(COARSE_POINTER);\n const fieldRef = React.useRef<HTMLDivElement>(null);\n // Bumped on every handled key (not only an axis change), so the layout effect below moves focus\n // to the axis's input even when the key's axis is the one an earlier assistive-technology change\n // already made the Tab stop, without moving focus; focusing an input that already has focus does\n // nothing. Never bumped for an AT-driven change (`handleInputChange`) or a real focus event. A\n // plain counter, not a ref: react-hooks/refs only allows a ref's `current` to be touched from an\n // effect, a ref callback or a function assigned directly to a JSX handler prop, not one passed\n // through `composeEventHandlers`.\n const [focusToken, setFocusToken] = React.useState(0);\n const rootRef = React.useRef<HTMLDivElement>(null);\n const saturationRef = React.useRef<HTMLInputElement>(null);\n const brightnessRef = React.useRef<HTMLInputElement>(null);\n const mergedRootRef = useMergedRefs(ref, rootRef);\n const mergedSaturationRef = useMergedRefs(saturationRef, controlRef);\n /** The last `focusToken` this component already moved focus for (read/written in the effect only). */\n const handledFocusTokenRef = React.useRef(0);\n\n React.useLayoutEffect(() => {\n if (handledFocusTokenRef.current === focusToken) return;\n handledFocusTokenRef.current = focusToken;\n (activeAxis === 'saturation' ? saturationRef : brightnessRef).current?.focus({\n preventScroll: true,\n });\n }, [activeAxis, focusToken]);\n\n const field = useFieldContext();\n const fieldProps = useFieldControl(\n {\n id,\n 'aria-label':\n ariaLabel ?? (picker && ariaLabelledBy === undefined ? picker.labels.area : undefined),\n 'aria-labelledby': ariaLabelledBy,\n 'aria-describedby': ariaDescribedBy,\n 'aria-invalid': ariaInvalid,\n },\n { labelable: false },\n );\n // A group supports neither aria-invalid, aria-required nor `required` (ARIA 1.2): the invalid\n // state goes to both inputs and the required state to the hidden input.\n const {\n 'aria-invalid': invalid,\n 'aria-required': _ariaRequired,\n required: _required,\n ...groupProps\n } = fieldProps;\n const isInvalid = invalid !== undefined && invalid !== false && invalid !== 'false';\n const errorMessageId = (isInvalid && ariaErrorMessage) || undefined;\n const isRequired =\n required ?? (ariaRequired === true || ariaRequired === 'true' || (field?.required ?? false));\n\n useFormReset(rootRef, part.reset, form);\n\n /** Applies a whole percentage to one axis, keeping the other channels as given. */\n const applyAxis = (axis: AreaAxis, percent: number) => {\n if (percent === (axis === 'saturation' ? saturation : brightness)) return;\n part.setColor(\n axis === 'saturation' ? { ...color, s: percent / 100 } : { ...color, v: percent / 100 },\n );\n };\n\n const handleKeyDown = composeEventHandlers(\n onKeyDown,\n (event: React.KeyboardEvent<HTMLDivElement>) => {\n if (part.disabled || !isOwnEvent(event) || event.nativeEvent.isComposing) return;\n // A key with Alt, Ctrl or Meta belongs to the browser (Alt+Left is \"back\").\n if (event.altKey || event.ctrlKey || event.metaKey) return;\n const step = event.shiftKey ? 10 : 1;\n let axis: AreaAxis;\n let next: number;\n switch (event.key) {\n case 'ArrowLeft':\n case 'ArrowRight': {\n const intent = getArrowIntent(event.key, {\n orientation: 'horizontal',\n dir: getDirection(event.currentTarget),\n });\n axis = 'saturation';\n next = saturation + (intent === 'next' ? step : -step);\n break;\n }\n case 'ArrowUp':\n axis = 'value';\n next = brightness + step;\n break;\n case 'ArrowDown':\n axis = 'value';\n next = brightness - step;\n break;\n case 'PageUp':\n axis = 'value';\n next = brightness + 10;\n break;\n case 'PageDown':\n axis = 'value';\n next = brightness - 10;\n break;\n case 'Home':\n axis = 'saturation';\n next = 0;\n break;\n case 'End':\n axis = 'saturation';\n next = 100;\n break;\n default:\n return;\n }\n // Prevented, so the native range input never moves on its own.\n event.preventDefault();\n if (axis !== activeAxis) setActiveAxis(axis);\n // Every handled key moves focus to its axis's input, even when an earlier\n // assistive-technology change already made that axis the Tab stop.\n setFocusToken((token) => token + 1);\n applyAxis(axis, clampPercent(next));\n },\n );\n\n /** A change event from assistive technology (a swipe): that input becomes the Tab stop. */\n const handleInputChange = (axis: AreaAxis) => (event: React.ChangeEvent<HTMLInputElement>) => {\n if (part.disabled) return;\n if (axis !== activeAxis) setActiveAxis(axis);\n applyAxis(axis, clampPercent(Math.round(Number(event.currentTarget.value))));\n };\n\n const handleInputFocus = (axis: AreaAxis) => () => {\n if (axis !== activeAxis) setActiveAxis(axis);\n };\n\n // Both read a ref (`fieldRef`, or `saturationRef`/`brightnessRef`): `useEventCallback` (a custom\n // hook, opaque to react-hooks/refs) keeps that safe to call from the handler below, unlike a\n // plain function or `React.useCallback` passed into the generic `composeEventHandlers`.\n /** Moves the thumb to the pointer: saturation along x (mirrored in RTL), brightness along y. */\n const moveToPointer = useEventCallback((event: React.PointerEvent<HTMLDivElement>) => {\n const fieldElement = fieldRef.current;\n if (!fieldElement) return;\n const rect = fieldElement.getBoundingClientRect();\n if (rect.width <= 0 || rect.height <= 0) return;\n const x = Math.min(1, Math.max(0, (event.clientX - rect.left) / rect.width));\n const s = getDirection(event.currentTarget) === 'rtl' ? 1 - x : x;\n const v = Math.min(1, Math.max(0, 1 - (event.clientY - rect.top) / rect.height));\n if (s === shown.s && v === shown.v) return;\n part.setColor({ ...color, s, v });\n });\n /**\n * Focuses the input of the active axis (the press moves focus there instead of the point),\n * without the focus ring: Chromium treats this script focus as keyboard focus, where the\n * browser's own focus of a pressed control shows none. Browsers without the `focusVisible`\n * option ignore it.\n */\n const focusActiveAxis = useEventCallback(() => {\n const options: FocusOptions = { preventScroll: true, focusVisible: false };\n (activeAxis === 'saturation' ? saturationRef : brightnessRef).current?.focus(options);\n });\n\n const handlePointerDown = composeEventHandlers(\n onPointerDown,\n (event: React.PointerEvent<HTMLDivElement>) => {\n if (part.disabled || event.button !== 0 || !event.isPrimary || !isOwnEvent(event)) return;\n // No text selection and no focus move of the press: focus goes to the Tab stop instead.\n event.preventDefault();\n event.currentTarget.setPointerCapture(event.pointerId);\n moveToPointer(event);\n focusActiveAxis();\n },\n );\n\n // The drag lasts while the root holds the pointer; losing the capture (pointerup,\n // lostpointercapture) ends it.\n const handlePointerMove = composeEventHandlers(\n onPointerMove,\n (event: React.PointerEvent<HTMLDivElement>) => {\n if (part.disabled || !event.currentTarget.hasPointerCapture(event.pointerId)) return;\n moveToPointer(event);\n },\n );\n\n const textLabels = {\n saturation: strings.saturation,\n brightness: strings.brightness,\n colorName: strings.colorName,\n valueText: strings.valueText,\n };\n\n const areaStyle = {\n ...style,\n '--wave-color-area-gradient': colorAreaGradient(shown.h),\n '--wave-color-area-x': toPosition(shown.s),\n '--wave-color-area-y': toPosition(shown.v),\n '--wave-color-thumb': hsvToHex({ h: shown.h, s: shown.s, v: shown.v }),\n } as React.CSSProperties;\n\n const inputProps = (axis: AreaAxis) => ({\n type: 'range' as const,\n min: 0,\n max: 100,\n step: 1,\n disabled: part.disabled,\n 'aria-roledescription': strings.roleDescription,\n 'aria-invalid': invalid,\n 'aria-errormessage': errorMessageId,\n // One Tab stop: the input used last (C-ROUTING: a consumer tabIndex applies to it).\n tabIndex: axis === activeAxis ? (tabIndex ?? 0) : -1,\n // Where the primary pointer is not coarse, desktop screen readers meet one 2-D slider: the\n // input without the Tab stop is hidden (it stays focusable by script, never by Tab).\n 'aria-hidden': axis !== activeAxis && !coarsePointer ? true : undefined,\n onChange: handleInputChange(axis),\n onFocus: handleInputFocus(axis),\n className: 'sr-only',\n });\n\n return (\n <div\n role=\"group\"\n data-disabled={part.disabled ? '' : undefined}\n {...groupProps}\n className={cn(\n colorAreaClassNames.root,\n 'group/color-area relative h-40 w-full min-w-40 touch-none select-none data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50',\n resolvedShape === 'square' ? 'rounded-none' : 'rounded',\n className,\n )}\n style={areaStyle}\n {...rest}\n ref={mergedRootRef}\n onKeyDown={handleKeyDown}\n onPointerDown={handlePointerDown}\n onPointerMove={handlePointerMove}\n >\n <div\n ref={fieldRef}\n aria-hidden=\"true\"\n className={cn(\n colorAreaClassNames.field,\n 'absolute inset-0 rounded-[inherit] bg-(image:--wave-color-area-gradient) wave-rtl:-scale-x-100 forced-colors:forced-color-adjust-none',\n )}\n />\n <span\n aria-hidden=\"true\"\n className={cn(\n colorAreaClassNames.thumb,\n COLOR_THUMB_CLASSES,\n 'start-(--wave-color-area-x) bottom-(--wave-color-area-y) -translate-x-1/2 wave-rtl:translate-x-1/2 translate-y-1/2',\n 'group-has-[:focus-visible]/color-area:ring-2 group-has-[:focus-visible]/color-area:ring-background forced-colors:group-has-[:focus-visible]/color-area:ring-[Canvas] group-has-[:focus-visible]/color-area:outline-2 group-has-[:focus-visible]/color-area:outline-offset-2 group-has-[:focus-visible]/color-area:outline-ring forced-colors:group-has-[:focus-visible]/color-area:outline-[Highlight]',\n )}\n />\n <input\n {...inputProps('saturation')}\n ref={mergedSaturationRef}\n value={saturation}\n aria-label={strings.saturation}\n aria-valuetext={areaValueText(shown, 'saturation', textLabels)}\n autoFocus={autoFocus}\n />\n <input\n {...inputProps('value')}\n ref={brightnessRef}\n value={brightness}\n aria-label={strings.brightness}\n aria-orientation=\"vertical\"\n aria-valuetext={areaValueText(shown, 'value', textLabels)}\n />\n {!picker && (\n <HiddenInput\n type=\"text\"\n name={name}\n form={form}\n disabled={part.disabled}\n value={hsvToHex(color)}\n required={isRequired}\n onInvalid={() =>\n (activeAxis === 'saturation' ? saturationRef : brightnessRef).current?.focus()\n }\n />\n )}\n </div>\n );\n};\n\nColorArea.displayName = 'ColorArea';\n"],"mappings":"orBAkGA,IAAMsC,GAAiB,CACrB,WAAY,aACZ,WAAY,aACZ,gBAAiB,WACnB,EAGA,SAASC,EAAa,EAAuB,CAC3C,OAAO,KAAK,IAAI,IAAK,KAAK,IAAI,EAAGC,CAAK,CAAC,CACzC,CAGA,IAAMC,EAAiB,oBAiBVC,GAAa,CACxB,QACA,eACA,gBACA,QACA,SACA,WAAW,GACX,OACA,OACA,YACA,cACA,aACA,SACA,MACA,aAAcC,GACd,kBAAmBC,EACnB,mBAAoBC,GACpB,eAAgBC,GAChB,gBAAiBC,EACjB,oBAAqBC,GACrB,aACA,YACA,YACA,gBACA,gBACA,MACA,GAAGC,KACiB,CACpB,IAAMC,EAAOlD,EAAAA,kBAAkB,CAAE,QAAO,eAAc,gBAAe,UAAS,CAAC,EACzE,CAAE,UAAWkD,EACbC,EAAU,CACd,GAAGb,GACH,GAAIc,GAAU,CACZ,WAAYA,EAAO,OAAO,WAC1B,WAAYA,EAAO,OAAO,WAC1B,gBAAiBA,EAAO,OAAO,gBAC/B,UAAWA,EAAO,OAAO,UACzB,UAAWA,EAAO,OAAO,SAC3B,EACA,GAAGC,CACL,EACMC,EAAgBC,GAASH,GAAQ,OAAS,UAC1CI,EAAQN,EAAK,MACbO,EAAQxD,EAAAA,aAAauD,CAAK,EAC1BE,EAAaxD,EAAAA,UAAUuD,EAAM,CAAC,EAC9BE,EAAazD,EAAAA,UAAUuD,EAAM,CAAC,EAE9B,CAACG,EAAYC,GAAiB1D,EAAM,SAAmB,YAAY,EACnE2D,GAAgB1D,GAAAA,cAAcqC,CAAc,EAC5CsB,EAAW5D,EAAM,OAAuB,IAAI,EAQ5C,CAAC6D,EAAYC,IAAiB9D,EAAM,SAAS,CAAC,EAC9C+D,EAAU/D,EAAM,OAAuB,IAAI,EAC3CgE,EAAgBhE,EAAM,OAAyB,IAAI,EACnDiE,EAAgBjE,EAAM,OAAyB,IAAI,EACnDkE,GAAgBhE,EAAAA,cAAciE,EAAKJ,CAAO,EAC1CK,GAAsBlE,EAAAA,cAAc8D,EAAeK,EAAU,EAE7DC,EAAuBtE,EAAM,OAAO,CAAC,EAE3CiC,EAAM,oBAAsB,CACtBqC,EAAqB,UAAYT,IACrC,EAAqB,QAAUA,GAC9BJ,IAAe,aAAeO,EAAgBC,EAAA,CAAe,SAAS,MAAM,CAC3E,cAAe,EACjB,CAAC,EACH,EAAG,CAACR,EAAYI,CAAU,CAAC,EAE3B,IAAMU,GAAQpE,EAAAA,gBAAgB,EAcxB,CACJ,eAAgBqE,EAChB,gBAAiBC,GACjB,SAAUC,GACV,GAAGC,IAjBcvE,EAAAA,gBACjB,CACE,MACA,aACEoC,KAAcS,GAAUR,IAAmB,IAAA,GAAYQ,EAAO,OAAO,KAAO,IAAA,IAC9E,kBAAmBR,EACnB,mBAAoBC,GACpB,eAAgBC,EAClB,EACA,CAAE,UAAW,EAAM,CASjB,EAEEiC,GADYJ,IAAY,IAAA,IAAaA,IAAY,IAASA,IAAY,SACvC3B,IAAqB,IAAA,GACpDgC,GACJC,KAAalC,IAAiB,IAAQA,IAAiB,SAAW2B,IAAO,UAAY,KAEvF3C,EAAA,aAAamC,EAAShB,EAAK,MAAOgC,CAAI,EAGtC,IAAMC,GAAa,EAAgB,IAAoB,CACjDC,KAAaC,IAAS,aAAe3B,EAAaC,IACtDT,EAAK,SACHmC,IAAS,aAAe,CAAE,GAAG7B,EAAO,EAAG4B,EAAU,GAAI,EAAI,CAAE,GAAG5B,EAAO,EAAG4B,EAAU,GAAI,CACxF,CACF,EAEME,GAAgB9E,EAAAA,qBACpB+E,EACC,GAA+C,CAG9C,GAFIrC,EAAK,UAAY,CAACzC,EAAAA,WAAW+E,CAAK,GAAKA,EAAM,YAAY,aAEzDA,EAAM,QAAUA,EAAM,SAAWA,EAAM,QAAS,OACpD,IAAMC,EAAOD,EAAM,SAAW,GAAK,EAC/BH,EACAK,EACJ,OAAQF,EAAM,IAAd,CACE,IAAK,YACL,IAAK,aAAc,CACjB,IAAMG,EAASjF,EAAAA,eAAe8E,EAAM,IAAK,CACvC,YAAa,aACb,IAAK7E,EAAAA,aAAa6E,EAAM,aAAa,CACvC,CAAC,EACD,EAAO,aACP,EAAO9B,GAAciC,IAAW,OAASF,EAAO,CAACA,GACjD,KACF,CACA,IAAK,UACH,EAAO,QACP,EAAO9B,EAAa8B,EACpB,MACF,IAAK,YACH,EAAO,QACP,EAAO9B,EAAa8B,EACpB,MACF,IAAK,SACH,EAAO,QACP,EAAO9B,EAAa,GACpB,MACF,IAAK,WACH,EAAO,QACP,EAAOA,EAAa,GACpB,MACF,IAAK,OACH,EAAO,aACP,EAAO,EACP,MACF,IAAK,MACH,EAAO,aACP,EAAO,IACP,MACF,QACE,MACJ,CAEA6B,EAAM,eAAe,EACjBH,IAASzB,GAAYC,EAAcwB,CAAI,EAG3CpB,GAAe,GAAU2B,EAAQ,CAAC,EAClCT,EAAUE,EAAM9C,EAAamD,CAAI,CAAC,CACpC,CACF,EAGMG,EAAqB,GAAoB,GAA+C,CACxF3C,EAAK,WACLmC,IAASzB,GAAYC,EAAcwB,CAAI,EAC3CF,EAAUE,EAAM9C,EAAa,KAAK,MAAM,OAAOiD,EAAM,cAAc,KAAK,CAAC,CAAC,CAAC,EAC7E,EAEMM,GAAoB,OAAyB,CAC7CT,IAASzB,GAAYC,EAAcwB,CAAI,CAC7C,EAMMU,EAAgBnF,EAAAA,iBAAkB,GAA8C,CACpF,IAAMoF,EAAejC,EAAS,QAC9B,GAAI,CAACiC,EAAc,OACnB,IAAMC,EAAOD,EAAa,sBAAsB,EAChD,GAAIC,EAAK,OAAS,GAAKA,EAAK,QAAU,EAAG,OACzC,IAAMC,EAAI,KAAK,IAAI,EAAG,KAAK,IAAI,GAAIV,EAAM,QAAUS,EAAK,MAAQA,EAAK,KAAK,CAAC,EACrEE,EAAIxF,EAAAA,aAAa6E,EAAM,aAAa,IAAM,MAAQ,EAAIU,EAAIA,EAC1DE,EAAI,KAAK,IAAI,EAAG,KAAK,IAAI,EAAG,GAAKZ,EAAM,QAAUS,EAAK,KAAOA,EAAK,MAAM,CAAC,GAC3EE,IAAM1C,EAAM,GAAK2C,IAAM3C,EAAM,IACjCP,EAAK,SAAS,CAAE,GAAGM,EAAO,IAAG,GAAE,CAAC,CAClC,CAAC,EAOK6C,GAAkBzF,EAAAA,qBAAuB,EAE5CgD,IAAe,aAAeO,EAAgBC,EAAA,CAAe,SAAS,MAAM,CAD7C,cAAe,GAAM,aAAc,EACU,CAAO,CACtF,CAAC,EAEKkC,GAAoB9F,EAAAA,qBACxB+F,EACC,GAA8C,CACzC,GAAK,UAAYf,EAAM,SAAW,GAAMA,EAAM,WAAc/E,EAAAA,WAAW+E,CAAK,IAEhFA,EAAM,eAAe,EACrBA,EAAM,cAAc,kBAAkBA,EAAM,SAAS,EACrDO,EAAcP,CAAK,EACnBa,GAAgB,EAClB,CACF,EAIMG,GAAoBhG,EAAAA,qBACxBiG,EACC,GAA8C,CACzC,GAAK,UAAajB,EAAM,cAAc,kBAAkBA,EAAM,SAAS,GAC3EO,EAAcP,CAAK,CACrB,CACF,EAEMkB,EAAa,CACjB,WAAYvD,EAAQ,WACpB,WAAYA,EAAQ,WACpB,UAAWA,EAAQ,UACnB,UAAWA,EAAQ,SACrB,EAEMwD,GAAY,CAChB,GAAGC,GACH,6BAA8B/F,EAAAA,kBAAkB4C,EAAM,CAAC,EACvD,sBAAuB3C,EAAAA,WAAW2C,EAAM,CAAC,EACzC,sBAAuB3C,EAAAA,WAAW2C,EAAM,CAAC,EACzC,qBAAsB1C,EAAAA,SAAS,CAAE,EAAG0C,EAAM,EAAG,EAAGA,EAAM,EAAG,EAAGA,EAAM,CAAE,CAAC,CACvE,EAEMoD,EAAc,IAAoB,CACtC,KAAM,QACN,IAAK,EACL,IAAK,IACL,KAAM,EACN,SAAU3D,EAAK,SACf,uBAAwBC,EAAQ,gBAChC,eAAgBwB,EAChB,oBAAqBI,GAErB,SAAUM,IAASzB,EAAckD,IAAY,EAAK,GAGlD,cAAezB,IAASzB,GAAc,CAACE,IAAuB,IAAA,GAC9D,SAAU+B,EAAkBR,CAAI,EAChC,QAASS,GAAiBT,CAAI,EAC9B,UAAW,SACb,GAEA,OACE,EAAAhD,EAAA,KAAA,CAAC,MAAD,CACE,KAAK,QACL,gBAAea,EAAK,SAAW,GAAK,IAAA,GACpC,GAAI4B,GACJ,UAAW9D,EAAAA,GACTC,EAAAA,oBAAoB,KACpB,sIACAqC,IAAkB,SAAW,eAAiB,UAC9CyD,EACF,EACA,MAAOJ,GACP,GAAI1D,EACJ,IAAKoB,GACL,UAAWiB,GACX,cAAegB,GACf,cAAeE,GAfjB,SAAA,EAiBE,EAAAnE,EAAA,IAAA,CAAC,MAAD,CACE,IAAK0B,EACL,cAAY,OACZ,UAAW/C,EAAAA,GACTC,EAAAA,oBAAoB,MACpB,uIACF,CACD,CAAA,GACD,EAAAoB,EAAA,IAAA,CAAC,OAAD,CACE,cAAY,OACZ,UAAWrB,EAAAA,GACTC,EAAAA,oBAAoB,MACpBC,EAAAA,oBACA,qHACA,wYACF,CACD,CAAA,GACD,EAAAmB,EAAA,IAAA,CAAC,QAAD,CACE,GAAIwE,EAAW,YAAY,EAC3B,IAAKtC,GACL,MAAOb,EACP,aAAYP,EAAQ,WACpB,iBAAgBhC,EAAAA,cAAcsC,EAAO,aAAciD,CAAU,EAClD,YACZ,CAAA,GACD,EAAArE,EAAA,IAAA,CAAC,QAAD,CACE,GAAIwE,EAAW,OAAO,EACtB,IAAKzC,EACL,MAAOT,EACP,aAAYR,EAAQ,WACpB,mBAAiB,WACjB,iBAAgBhC,EAAAA,cAAcsC,EAAO,QAASiD,CAAU,CACzD,CAAA,EACA,CAACtD,IACA,EAAAf,EAAA,IAAA,CAACjB,EAAAA,YAAD,CACE,KAAK,OACC,OACA,OACN,SAAU8B,EAAK,SACf,MAAOnC,EAAAA,SAASyC,CAAK,EACrB,SAAUwB,GACV,eACGpB,IAAe,aAAeO,EAAgBC,EAAA,CAAe,SAAS,MAAM,CAEhF,CAAA,CAEA,GAET,EAEA,EAAU,YAAc"}
|
|
1
|
+
{"version":3,"file":"ColorArea.cjs","names":["useColorPartState","displayColor","toPercent","React","useMediaQuery","useMergedRefs","useFieldContext","useFieldControl","composeEventHandlers","isOwnEvent","getArrowIntent","getDirection","useEventCallback","colorAreaGradient","toPosition","hsvToHex","cn","colorAreaClassNames","COLOR_THUMB_CLASSES","areaValueText","HiddenInput","require_runtime","require_cn","require_composeEventHandlers","require_classNames","require_color","require_useEventCallback","require_direction","require_useMergedRefs","require_useFieldControl","require_useMediaQuery","require_useFormReset","require_HiddenInput","require_events","require_colorUtils","require_ColorPicker_parts","react","react_jsx_runtime","DEFAULT_LABELS","clampPercent","value","COARSE_POINTER","ColorArea","ariaLabel","ariaLabelledBy","ariaDescribedBy","ariaInvalid","ariaRequired","ariaErrorMessage","rest","part","strings","picker","labels","resolvedShape","shape","color","shown","saturation","brightness","activeAxis","setActiveAxis","coarsePointer","fieldRef","focusToken","setFocusToken","rootRef","saturationRef","brightnessRef","mergedRootRef","ref","mergedSaturationRef","controlRef","handledFocusTokenRef","field","invalid","_ariaRequired","_required","groupProps","errorMessageId","isRequired","required","form","applyAxis","percent","axis","handleKeyDown","onKeyDown","event","step","next","intent","token","handleInputChange","handleInputFocus","moveToPointer","fieldElement","rect","x","s","v","focusActiveAxis","handlePointerDown","onPointerDown","handlePointerMove","onPointerMove","textLabels","areaStyle","style","inputProps","tabIndex","className"],"sources":["../../../src/components/input/ColorArea.tsx"],"sourcesContent":["import * as React from 'react';\nimport { colorAreaClassNames } from '../../lib/classNames';\nimport { cn } from '../../lib/cn';\nimport { hsvToHex } from '../../lib/color';\nimport { composeEventHandlers } from '../../lib/composeEventHandlers';\nimport { getArrowIntent, getDirection } from '../../lib/direction';\nimport { isOwnEvent } from '../../lib/events';\nimport type { ColorPickerShape, HsvColor } from '../../lib/types';\nimport { useEventCallback } from '../../hooks/useEventCallback';\nimport { useFieldContext, useFieldControl } from '../../hooks/useFieldControl';\nimport { useFormReset } from '../../hooks/useFormReset';\nimport { useMediaQuery } from '../../hooks/useMediaQuery';\nimport { useMergedRefs } from '../../hooks/useMergedRefs';\nimport { HiddenInput } from '../internal/HiddenInput';\nimport { useColorPartState } from './ColorPicker.parts';\nimport {\n COLOR_THUMB_CLASSES,\n areaValueText,\n colorAreaGradient,\n displayColor,\n toPercent,\n toPosition,\n} from './colorUtils';\n\n/** Texts of a ColorArea, for localisation. Every key is optional. */\nexport interface ColorAreaLabels {\n /** Name of the horizontal slider.\n * @default 'Saturation'\n */\n saturation?: string;\n /** Name of the vertical slider (the `value` channel).\n * @default 'Brightness'\n */\n brightness?: string;\n /** Role description of both sliders.\n * @default '2D slider'\n */\n roleDescription?: string;\n /** Names the color at the end of each value text; return `''` to leave it out.\n * @default an English namer (\"dark blue\")\n */\n colorName?: (color: HsvColor) => string;\n /** Replaces a whole value text, for languages whose order differs. */\n valueText?: (color: HsvColor, channel: 'saturation' | 'value') => string;\n}\n\n/** Properties for the ColorArea component. */\nexport interface ColorAreaProps extends Omit<\n React.HTMLAttributes<HTMLDivElement>,\n 'defaultValue' | 'onChange'\n> {\n /**\n * The color (Fluent's `color`). Inside a ColorPicker, leave `value` and `defaultValue` out to\n * bind the area to the picker.\n */\n value?: HsvColor;\n /**\n * Initial color for uncontrolled usage (also what a form reset restores).\n * @default the brand blue, `{ h: 208, s: 0.92, v: 0.74 }` (`#0f6cbd`)\n */\n defaultValue?: HsvColor;\n /**\n * Called with the new color on every step (a key, a pointer move or assistive technology) that\n * changes it (Fluent's `onChange`). A bound area calls it too.\n */\n onValueChange?: (value: HsvColor) => void;\n /**\n * `'square'` removes the corner radius (the thumb stays round). Bound to a ColorPicker, the\n * picker's shape unless you pass one.\n * @default 'rounded'\n */\n shape?: ColorPickerShape;\n /** Texts of the area; bound to a ColorPicker, the picker's `labels` fill the keys you leave out. */\n labels?: ColorAreaLabels;\n /**\n * Unavailable: both inputs are natively disabled, pointer presses are ignored and the area is\n * dimmed. A bound area is also disabled while the picker's value is not a hex color.\n * @default false\n */\n disabled?: boolean;\n /** Form field name: the color is submitted as hex (`hsvToHex`). Ignored while bound to a ColorPicker. */\n name?: string;\n /** Id of the form the area belongs to, when it is rendered outside that form. */\n form?: string;\n /**\n * Marks the hidden form input required (a color is always set, so it never blocks). A consumer\n * `aria-required` does the same: a group supports neither, so neither is set on it.\n */\n required?: boolean;\n /** Ref to the saturation `<input type=\"range\">`. */\n controlRef?: React.Ref<HTMLInputElement>;\n /** Ref to the root `role=\"group\"` element. */\n ref?: React.Ref<HTMLDivElement>;\n}\n\n/** The two axes: saturation (x) and brightness (y, the `value` channel). */\ntype AreaAxis = 'saturation' | 'value';\n\nconst DEFAULT_LABELS = {\n saturation: 'Saturation',\n brightness: 'Brightness',\n roleDescription: '2D slider',\n} as const;\n\n/** A whole percentage clamped to 0–100. */\nfunction clampPercent(value: number): number {\n return Math.min(100, Math.max(0, value));\n}\n\n/** Touch-primary devices expose both inputs, so a touch screen reader can swipe each (D19). */\nconst COARSE_POINTER = '(pointer: coarse)';\n\n/**\n * A 2-D color field: saturation from left to right (mirrored in right-to-left layouts) and\n * brightness from bottom to top, at the value's hue. ArrowLeft and ArrowRight move saturation by\n * 1 %, ArrowUp and ArrowDown brightness; Shift with an arrow moves by 10, Page Up and Page Down\n * move brightness by 10, and Home and End set saturation to 0 and 100. A press or drag (mouse,\n * touch or pen) moves the thumb to the pointer. It is one Tab stop holding two sliders for\n * assistive technology, \"Saturation\" and \"Brightness\", whose value texts start with their own\n * channel and name the color; focus follows the axis a key moves, and unless the primary pointer\n * is coarse (touch), only the slider with the Tab stop is exposed. Inside a ColorPicker, leave\n * `value` and `defaultValue` out and it binds to the picker. Fluent's\n * `ColorArea`, with `value`/`onValueChange` for its `color`/`onChange`.\n *\n * @example\n * <ColorArea aria-label=\"Accent color\" value={color} onValueChange={setColor} />\n */\nexport const ColorArea = ({\n value,\n defaultValue,\n onValueChange,\n shape,\n labels,\n disabled = false,\n name,\n form,\n required,\n controlRef,\n className,\n style,\n id,\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledBy,\n 'aria-describedby': ariaDescribedBy,\n 'aria-invalid': ariaInvalid,\n 'aria-required': ariaRequired,\n 'aria-errormessage': ariaErrorMessage,\n autoFocus,\n tabIndex,\n onKeyDown,\n onPointerDown,\n onPointerMove,\n ref,\n ...rest\n}: ColorAreaProps) => {\n const part = useColorPartState({ value, defaultValue, onValueChange, disabled });\n const { picker } = part;\n const strings = {\n ...DEFAULT_LABELS,\n ...(picker && {\n saturation: picker.labels.saturation,\n brightness: picker.labels.brightness,\n roleDescription: picker.labels.roleDescription,\n colorName: picker.labels.colorName,\n valueText: picker.labels.valueText,\n }),\n ...labels,\n };\n const resolvedShape = shape ?? picker?.shape ?? 'rounded';\n const color = part.color;\n const shown = displayColor(color);\n const saturation = toPercent(shown.s);\n const brightness = toPercent(shown.v);\n\n const [activeAxis, setActiveAxis] = React.useState<AreaAxis>('saturation');\n const coarsePointer = useMediaQuery(COARSE_POINTER);\n const fieldRef = React.useRef<HTMLDivElement>(null);\n // Bumped on every handled key (not only an axis change), so the layout effect below moves focus\n // to the axis's input even when the key's axis is the one an earlier assistive-technology change\n // already made the Tab stop, without moving focus; focusing an input that already has focus does\n // nothing. Never bumped for an AT-driven change (`handleInputChange`) or a real focus event. A\n // plain counter, not a ref: react-hooks/refs only allows a ref's `current` to be touched from an\n // effect, a ref callback or a function assigned directly to a JSX handler prop, not one passed\n // through `composeEventHandlers`.\n const [focusToken, setFocusToken] = React.useState(0);\n const rootRef = React.useRef<HTMLDivElement>(null);\n const saturationRef = React.useRef<HTMLInputElement>(null);\n const brightnessRef = React.useRef<HTMLInputElement>(null);\n const mergedRootRef = useMergedRefs(ref, rootRef);\n const mergedSaturationRef = useMergedRefs(saturationRef, controlRef);\n /** The last `focusToken` this component already moved focus for (read/written in the effect only). */\n const handledFocusTokenRef = React.useRef(0);\n\n React.useLayoutEffect(() => {\n if (handledFocusTokenRef.current === focusToken) return;\n handledFocusTokenRef.current = focusToken;\n (activeAxis === 'saturation' ? saturationRef : brightnessRef).current?.focus({\n preventScroll: true,\n });\n }, [activeAxis, focusToken]);\n\n const field = useFieldContext();\n const fieldProps = useFieldControl(\n {\n id,\n 'aria-label':\n ariaLabel ?? (picker && ariaLabelledBy === undefined ? picker.labels.area : undefined),\n 'aria-labelledby': ariaLabelledBy,\n 'aria-describedby': ariaDescribedBy,\n 'aria-invalid': ariaInvalid,\n },\n { labelable: false },\n );\n // A group supports neither aria-invalid, aria-required nor `required` (ARIA 1.2): the invalid\n // state goes to both inputs and the required state to the hidden input.\n const {\n 'aria-invalid': invalid,\n 'aria-required': _ariaRequired,\n required: _required,\n ...groupProps\n } = fieldProps;\n const isInvalid = invalid !== undefined && invalid !== false && invalid !== 'false';\n const errorMessageId = (isInvalid && ariaErrorMessage) || undefined;\n const isRequired =\n required ?? (ariaRequired === true || ariaRequired === 'true' || (field?.required ?? false));\n\n useFormReset(rootRef, part.reset, form);\n\n /** Applies a whole percentage to one axis, keeping the other channels as given. */\n const applyAxis = (axis: AreaAxis, percent: number) => {\n if (percent === (axis === 'saturation' ? saturation : brightness)) return;\n part.setColor(\n axis === 'saturation' ? { ...color, s: percent / 100 } : { ...color, v: percent / 100 },\n );\n };\n\n const handleKeyDown = composeEventHandlers(\n onKeyDown,\n (event: React.KeyboardEvent<HTMLDivElement>) => {\n if (part.disabled || !isOwnEvent(event) || event.nativeEvent.isComposing) return;\n // A key with Alt, Ctrl or Meta belongs to the browser (Alt+Left is \"back\").\n if (event.altKey || event.ctrlKey || event.metaKey) return;\n const step = event.shiftKey ? 10 : 1;\n let axis: AreaAxis;\n let next: number;\n switch (event.key) {\n case 'ArrowLeft':\n case 'ArrowRight': {\n const intent = getArrowIntent(event.key, {\n orientation: 'horizontal',\n dir: getDirection(event.currentTarget),\n });\n axis = 'saturation';\n next = saturation + (intent === 'next' ? step : -step);\n break;\n }\n case 'ArrowUp':\n axis = 'value';\n next = brightness + step;\n break;\n case 'ArrowDown':\n axis = 'value';\n next = brightness - step;\n break;\n case 'PageUp':\n axis = 'value';\n next = brightness + 10;\n break;\n case 'PageDown':\n axis = 'value';\n next = brightness - 10;\n break;\n case 'Home':\n axis = 'saturation';\n next = 0;\n break;\n case 'End':\n axis = 'saturation';\n next = 100;\n break;\n default:\n return;\n }\n // Prevented, so the native range input never moves on its own.\n event.preventDefault();\n if (axis !== activeAxis) setActiveAxis(axis);\n // Every handled key moves focus to its axis's input, even when an earlier\n // assistive-technology change already made that axis the Tab stop.\n setFocusToken((token) => token + 1);\n applyAxis(axis, clampPercent(next));\n },\n );\n\n /** A change event from assistive technology (a swipe): that input becomes the Tab stop. */\n const handleInputChange = (axis: AreaAxis) => (event: React.ChangeEvent<HTMLInputElement>) => {\n if (part.disabled) return;\n if (axis !== activeAxis) setActiveAxis(axis);\n applyAxis(axis, clampPercent(Math.round(Number(event.currentTarget.value))));\n };\n\n const handleInputFocus = (axis: AreaAxis) => () => {\n if (axis !== activeAxis) setActiveAxis(axis);\n };\n\n // Both read a ref (`fieldRef`, or `saturationRef`/`brightnessRef`): `useEventCallback` (a custom\n // hook, opaque to react-hooks/refs) keeps that safe to call from the handler below, unlike a\n // plain function or `React.useCallback` passed into the generic `composeEventHandlers`.\n /** Moves the thumb to the pointer: saturation along x (mirrored in RTL), brightness along y. */\n const moveToPointer = useEventCallback((event: React.PointerEvent<HTMLDivElement>) => {\n const fieldElement = fieldRef.current;\n if (!fieldElement) return;\n const rect = fieldElement.getBoundingClientRect();\n if (rect.width <= 0 || rect.height <= 0) return;\n const x = Math.min(1, Math.max(0, (event.clientX - rect.left) / rect.width));\n const s = getDirection(event.currentTarget) === 'rtl' ? 1 - x : x;\n const v = Math.min(1, Math.max(0, 1 - (event.clientY - rect.top) / rect.height));\n if (s === shown.s && v === shown.v) return;\n part.setColor({ ...color, s, v });\n });\n /**\n * Focuses the input of the active axis (the press moves focus there instead of the point),\n * without the focus ring: Chromium treats this script focus as keyboard focus, where the\n * browser's own focus of a pressed control shows none. Browsers without the `focusVisible`\n * option ignore it.\n */\n const focusActiveAxis = useEventCallback(() => {\n const options: FocusOptions = { preventScroll: true, focusVisible: false };\n (activeAxis === 'saturation' ? saturationRef : brightnessRef).current?.focus(options);\n });\n\n const handlePointerDown = composeEventHandlers(\n onPointerDown,\n (event: React.PointerEvent<HTMLDivElement>) => {\n if (part.disabled || event.button !== 0 || !event.isPrimary || !isOwnEvent(event)) return;\n // No text selection and no focus move of the press: focus goes to the Tab stop instead.\n event.preventDefault();\n event.currentTarget.setPointerCapture(event.pointerId);\n moveToPointer(event);\n focusActiveAxis();\n },\n );\n\n // The drag lasts while the root holds the pointer; losing the capture (pointerup,\n // lostpointercapture) ends it.\n const handlePointerMove = composeEventHandlers(\n onPointerMove,\n (event: React.PointerEvent<HTMLDivElement>) => {\n if (part.disabled || !event.currentTarget.hasPointerCapture(event.pointerId)) return;\n moveToPointer(event);\n },\n );\n\n const textLabels = {\n saturation: strings.saturation,\n brightness: strings.brightness,\n colorName: strings.colorName,\n valueText: strings.valueText,\n };\n\n const areaStyle = {\n ...style,\n '--wave-color-area-gradient': colorAreaGradient(shown.h),\n '--wave-color-area-x': toPosition(shown.s),\n '--wave-color-area-y': toPosition(shown.v),\n '--wave-color-thumb': hsvToHex({ h: shown.h, s: shown.s, v: shown.v }),\n } as React.CSSProperties;\n\n const inputProps = (axis: AreaAxis) => ({\n type: 'range' as const,\n min: 0,\n max: 100,\n step: 1,\n disabled: part.disabled,\n 'aria-roledescription': strings.roleDescription,\n 'aria-invalid': invalid,\n 'aria-errormessage': errorMessageId,\n // One Tab stop: the input used last (C-ROUTING: a consumer tabIndex applies to it).\n tabIndex: axis === activeAxis ? (tabIndex ?? 0) : -1,\n // Where the primary pointer is not coarse, desktop screen readers meet one 2-D slider: the\n // input without the Tab stop is hidden (it stays focusable by script, never by Tab).\n 'aria-hidden': axis !== activeAxis && !coarsePointer ? true : undefined,\n onChange: handleInputChange(axis),\n onFocus: handleInputFocus(axis),\n className: 'sr-only',\n });\n\n return (\n <div\n role=\"group\"\n data-disabled={part.disabled ? '' : undefined}\n {...groupProps}\n className={cn(\n colorAreaClassNames.root,\n 'group/color-area relative h-40 w-full min-w-40 touch-none select-none data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50',\n resolvedShape === 'square' ? 'rounded-none' : 'rounded',\n className,\n )}\n style={areaStyle}\n {...rest}\n ref={mergedRootRef}\n onKeyDown={handleKeyDown}\n onPointerDown={handlePointerDown}\n onPointerMove={handlePointerMove}\n >\n <div\n ref={fieldRef}\n aria-hidden=\"true\"\n className={cn(\n colorAreaClassNames.field,\n 'absolute inset-0 rounded-[inherit] bg-(image:--wave-color-area-gradient) wave-rtl:-scale-x-100 forced-colors:forced-color-adjust-none',\n )}\n />\n <span\n aria-hidden=\"true\"\n className={cn(\n colorAreaClassNames.thumb,\n COLOR_THUMB_CLASSES,\n 'start-(--wave-color-area-x) bottom-(--wave-color-area-y) -translate-x-1/2 wave-rtl:translate-x-1/2 translate-y-1/2',\n 'group-has-[:focus-visible]/color-area:ring-2 group-has-[:focus-visible]/color-area:ring-background forced-colors:group-has-[:focus-visible]/color-area:ring-[Canvas] group-has-[:focus-visible]/color-area:outline-2 group-has-[:focus-visible]/color-area:outline-offset-2 group-has-[:focus-visible]/color-area:outline-ring forced-colors:group-has-[:focus-visible]/color-area:outline-[Highlight]',\n )}\n />\n <input\n {...inputProps('saturation')}\n ref={mergedSaturationRef}\n value={saturation}\n aria-label={strings.saturation}\n aria-valuetext={areaValueText(shown, 'saturation', textLabels)}\n autoFocus={autoFocus}\n />\n <input\n {...inputProps('value')}\n ref={brightnessRef}\n value={brightness}\n aria-label={strings.brightness}\n aria-orientation=\"vertical\"\n aria-valuetext={areaValueText(shown, 'value', textLabels)}\n />\n {!picker && (\n <HiddenInput\n type=\"text\"\n name={name}\n form={form}\n disabled={part.disabled}\n value={hsvToHex(color)}\n required={isRequired}\n onInvalid={() =>\n (activeAxis === 'saturation' ? saturationRef : brightnessRef).current?.focus()\n }\n />\n )}\n </div>\n );\n};\n\nColorArea.displayName = 'ColorArea';\n"],"mappings":"orBAkGA,IAAMsC,GAAiB,CACrB,WAAY,aACZ,WAAY,aACZ,gBAAiB,WACnB,EAGA,SAASC,EAAa,EAAuB,CAC3C,OAAO,KAAK,IAAI,IAAK,KAAK,IAAI,EAAGC,CAAK,CAAC,CACzC,CAGA,IAAMC,EAAiB,oBAiBVC,GAAa,CACxB,QACA,eACA,gBACA,QACA,SACA,WAAW,GACX,OACA,OACA,YACA,cACA,aACA,SACA,MACA,aAAcC,GACd,kBAAmBC,EACnB,mBAAoBC,GACpB,eAAgBC,GAChB,gBAAiBC,EACjB,oBAAqBC,GACrB,aACA,YACA,YACA,gBACA,gBACA,MACA,GAAGC,KACiB,CACpB,IAAMC,EAAOlD,EAAAA,kBAAkB,CAAE,QAAO,eAAc,gBAAe,UAAS,CAAC,EACzE,CAAE,UAAWkD,EACbC,EAAU,CACd,GAAGb,GACH,GAAIc,GAAU,CACZ,WAAYA,EAAO,OAAO,WAC1B,WAAYA,EAAO,OAAO,WAC1B,gBAAiBA,EAAO,OAAO,gBAC/B,UAAWA,EAAO,OAAO,UACzB,UAAWA,EAAO,OAAO,SAC3B,EACA,GAAGC,CACL,EACMC,EAAgBC,GAASH,GAAQ,OAAS,UAC1CI,EAAQN,EAAK,MACbO,EAAQxD,EAAAA,aAAauD,CAAK,EAC1BE,EAAaxD,EAAAA,UAAUuD,EAAM,CAAC,EAC9BE,EAAazD,EAAAA,UAAUuD,EAAM,CAAC,EAE9B,CAACG,EAAYC,GAAiB1D,EAAM,SAAmB,YAAY,EACnE2D,GAAgB1D,GAAAA,cAAcqC,CAAc,EAC5CsB,EAAW5D,EAAM,OAAuB,IAAI,EAQ5C,CAAC6D,EAAYC,IAAiB9D,EAAM,SAAS,CAAC,EAC9C+D,EAAU/D,EAAM,OAAuB,IAAI,EAC3CgE,EAAgBhE,EAAM,OAAyB,IAAI,EACnDiE,EAAgBjE,EAAM,OAAyB,IAAI,EACnDkE,GAAgBhE,EAAAA,cAAciE,EAAKJ,CAAO,EAC1CK,GAAsBlE,EAAAA,cAAc8D,EAAeK,EAAU,EAE7DC,EAAuBtE,EAAM,OAAO,CAAC,EAE3CiC,EAAM,oBAAsB,CACtBqC,EAAqB,UAAYT,IACrC,EAAqB,QAAUA,GAC9BJ,IAAe,aAAeO,EAAgBC,EAAA,CAAe,SAAS,MAAM,CAC3E,cAAe,EACjB,CAAC,EACH,EAAG,CAACR,EAAYI,CAAU,CAAC,EAE3B,IAAMU,GAAQpE,EAAAA,gBAAgB,EAcxB,CACJ,eAAgBqE,EAChB,gBAAiBC,GACjB,SAAUC,GACV,GAAGC,IAjBcvE,EAAAA,gBACjB,CACE,MACA,aACEoC,KAAcS,GAAUR,IAAmB,IAAA,GAAYQ,EAAO,OAAO,KAAO,IAAA,IAC9E,kBAAmBR,EACnB,mBAAoBC,GACpB,eAAgBC,EAClB,EACA,CAAE,UAAW,EAAM,CASjB,EAEEiC,GADYJ,IAAY,IAAA,IAAaA,IAAY,IAASA,IAAY,SACvC3B,IAAqB,IAAA,GACpDgC,GACJC,KAAalC,IAAiB,IAAQA,IAAiB,SAAW2B,IAAO,UAAY,KAEvF3C,EAAA,aAAamC,EAAShB,EAAK,MAAOgC,CAAI,EAGtC,IAAMC,GAAa,EAAgB,IAAoB,CACjDC,KAAaC,IAAS,aAAe3B,EAAaC,IACtDT,EAAK,SACHmC,IAAS,aAAe,CAAE,GAAG7B,EAAO,EAAG4B,EAAU,GAAI,EAAI,CAAE,GAAG5B,EAAO,EAAG4B,EAAU,GAAI,CACxF,CACF,EAEME,GAAgB9E,EAAAA,qBACpB+E,EACC,GAA+C,CAG9C,GAFIrC,EAAK,UAAY,CAACzC,EAAAA,WAAW+E,CAAK,GAAKA,EAAM,YAAY,aAEzDA,EAAM,QAAUA,EAAM,SAAWA,EAAM,QAAS,OACpD,IAAMC,EAAOD,EAAM,SAAW,GAAK,EAC/BH,EACAK,EACJ,OAAQF,EAAM,IAAd,CACE,IAAK,YACL,IAAK,aAAc,CACjB,IAAMG,EAASjF,EAAAA,eAAe8E,EAAM,IAAK,CACvC,YAAa,aACb,IAAK7E,EAAAA,aAAa6E,EAAM,aAAa,CACvC,CAAC,EACD,EAAO,aACP,EAAO9B,GAAciC,IAAW,OAASF,EAAO,CAACA,GACjD,KACF,CACA,IAAK,UACH,EAAO,QACP,EAAO9B,EAAa8B,EACpB,MACF,IAAK,YACH,EAAO,QACP,EAAO9B,EAAa8B,EACpB,MACF,IAAK,SACH,EAAO,QACP,EAAO9B,EAAa,GACpB,MACF,IAAK,WACH,EAAO,QACP,EAAOA,EAAa,GACpB,MACF,IAAK,OACH,EAAO,aACP,EAAO,EACP,MACF,IAAK,MACH,EAAO,aACP,EAAO,IACP,MACF,QACE,MACJ,CAEA6B,EAAM,eAAe,EACjBH,IAASzB,GAAYC,EAAcwB,CAAI,EAG3CpB,GAAe,GAAU2B,EAAQ,CAAC,EAClCT,EAAUE,EAAM9C,EAAamD,CAAI,CAAC,CACpC,CACF,EAGMG,EAAqB,GAAoB,GAA+C,CACxF3C,EAAK,WACLmC,IAASzB,GAAYC,EAAcwB,CAAI,EAC3CF,EAAUE,EAAM9C,EAAa,KAAK,MAAM,OAAOiD,EAAM,cAAc,KAAK,CAAC,CAAC,CAAC,EAC7E,EAEMM,GAAoB,OAAyB,CAC7CT,IAASzB,GAAYC,EAAcwB,CAAI,CAC7C,EAMMU,EAAgBnF,EAAAA,iBAAkB,GAA8C,CACpF,IAAMoF,EAAejC,EAAS,QAC9B,GAAI,CAACiC,EAAc,OACnB,IAAMC,EAAOD,EAAa,sBAAsB,EAChD,GAAIC,EAAK,OAAS,GAAKA,EAAK,QAAU,EAAG,OACzC,IAAMC,EAAI,KAAK,IAAI,EAAG,KAAK,IAAI,GAAIV,EAAM,QAAUS,EAAK,MAAQA,EAAK,KAAK,CAAC,EACrEE,EAAIxF,EAAAA,aAAa6E,EAAM,aAAa,IAAM,MAAQ,EAAIU,EAAIA,EAC1DE,EAAI,KAAK,IAAI,EAAG,KAAK,IAAI,EAAG,GAAKZ,EAAM,QAAUS,EAAK,KAAOA,EAAK,MAAM,CAAC,GAC3EE,IAAM1C,EAAM,GAAK2C,IAAM3C,EAAM,IACjCP,EAAK,SAAS,CAAE,GAAGM,EAAO,IAAG,GAAE,CAAC,CAClC,CAAC,EAOK6C,GAAkBzF,EAAAA,qBAAuB,EAE5CgD,IAAe,aAAeO,EAAgBC,EAAA,CAAe,SAAS,MAAM,CAD7C,cAAe,GAAM,aAAc,EACU,CAAO,CACtF,CAAC,EAEKkC,GAAoB9F,EAAAA,qBACxB+F,EACC,GAA8C,CACzC,GAAK,UAAYf,EAAM,SAAW,GAAMA,EAAM,WAAc/E,EAAAA,WAAW+E,CAAK,IAEhFA,EAAM,eAAe,EACrBA,EAAM,cAAc,kBAAkBA,EAAM,SAAS,EACrDO,EAAcP,CAAK,EACnBa,GAAgB,EAClB,CACF,EAIMG,GAAoBhG,EAAAA,qBACxBiG,EACC,GAA8C,CACzC,GAAK,UAAajB,EAAM,cAAc,kBAAkBA,EAAM,SAAS,GAC3EO,EAAcP,CAAK,CACrB,CACF,EAEMkB,EAAa,CACjB,WAAYvD,EAAQ,WACpB,WAAYA,EAAQ,WACpB,UAAWA,EAAQ,UACnB,UAAWA,EAAQ,SACrB,EAEMwD,GAAY,CAChB,GAAGC,GACH,6BAA8B/F,EAAAA,kBAAkB4C,EAAM,CAAC,EACvD,sBAAuB3C,EAAAA,WAAW2C,EAAM,CAAC,EACzC,sBAAuB3C,EAAAA,WAAW2C,EAAM,CAAC,EACzC,qBAAsB1C,EAAAA,SAAS,CAAE,EAAG0C,EAAM,EAAG,EAAGA,EAAM,EAAG,EAAGA,EAAM,CAAE,CAAC,CACvE,EAEMoD,EAAc,IAAoB,CACtC,KAAM,QACN,IAAK,EACL,IAAK,IACL,KAAM,EACN,SAAU3D,EAAK,SACf,uBAAwBC,EAAQ,gBAChC,eAAgBwB,EAChB,oBAAqBI,GAErB,SAAUM,IAASzB,EAAckD,IAAY,EAAK,GAGlD,cAAezB,IAASzB,GAAc,CAACE,IAAuB,IAAA,GAC9D,SAAU+B,EAAkBR,CAAI,EAChC,QAASS,GAAiBT,CAAI,EAC9B,UAAW,SACb,GAEA,OACE,EAAAhD,EAAA,KAAA,CAAC,MAAD,CACE,KAAK,QACL,gBAAea,EAAK,SAAW,GAAK,IAAA,GACpC,GAAI4B,GACJ,UAAW9D,EAAAA,GACTC,EAAAA,oBAAoB,KACpB,sIACAqC,IAAkB,SAAW,eAAiB,UAC9CyD,EACF,EACA,MAAOJ,GACP,GAAI1D,EACJ,IAAKoB,GACL,UAAWiB,GACX,cAAegB,GACf,cAAeE,GAfjB,SAAA,EAiBE,EAAAnE,EAAA,IAAA,CAAC,MAAD,CACE,IAAK0B,EACL,cAAY,OACZ,UAAW/C,EAAAA,GACTC,EAAAA,oBAAoB,MACpB,uIACF,CACD,CAAA,GACD,EAAAoB,EAAA,IAAA,CAAC,OAAD,CACE,cAAY,OACZ,UAAWrB,EAAAA,GACTC,EAAAA,oBAAoB,MACpBC,EAAAA,oBACA,qHACA,wYACF,CACD,CAAA,GACD,EAAAmB,EAAA,IAAA,CAAC,QAAD,CACE,GAAIwE,EAAW,YAAY,EAC3B,IAAKtC,GACL,MAAOb,EACP,aAAYP,EAAQ,WACpB,iBAAgBhC,EAAAA,cAAcsC,EAAO,aAAciD,CAAU,EAClD,YACZ,CAAA,GACD,EAAArE,EAAA,IAAA,CAAC,QAAD,CACE,GAAIwE,EAAW,OAAO,EACtB,IAAKzC,EACL,MAAOT,EACP,aAAYR,EAAQ,WACpB,mBAAiB,WACjB,iBAAgBhC,EAAAA,cAAcsC,EAAO,QAASiD,CAAU,CACzD,CAAA,EACA,CAACtD,IACA,EAAAf,EAAA,IAAA,CAACjB,EAAAA,YAAD,CACE,KAAK,OACC,OACA,OACN,SAAU8B,EAAK,SACf,MAAOnC,EAAAA,SAASyC,CAAK,EACrB,SAAUwB,GACV,eACGpB,IAAe,aAAeO,EAAgBC,EAAA,CAAe,SAAS,MAAM,CAEhF,CAAA,CAEA,GAET,EAEA,EAAU,YAAc"}
|
|
@@ -6,13 +6,13 @@ import { hsvToHex as r } from "../../lib/color.mjs";
|
|
|
6
6
|
import { useEventCallback as i } from "../../hooks/useEventCallback.mjs";
|
|
7
7
|
import { getArrowIntent as a, getDirection as o } from "../../lib/direction.mjs";
|
|
8
8
|
import { useMergedRefs as s } from "../../hooks/useMergedRefs.mjs";
|
|
9
|
-
import { useFieldContext as ee, useFieldControl as
|
|
10
|
-
import { useMediaQuery as
|
|
11
|
-
import { useFormReset as
|
|
12
|
-
import { HiddenInput as
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
9
|
+
import { useFieldContext as ee, useFieldControl as te } from "../../hooks/useFieldControl.mjs";
|
|
10
|
+
import { useMediaQuery as c } from "../../hooks/useMediaQuery.mjs";
|
|
11
|
+
import { useFormReset as l } from "../../hooks/useFormReset.mjs";
|
|
12
|
+
import { HiddenInput as ne } from "../internal/HiddenInput.mjs";
|
|
13
|
+
import { isOwnEvent as u } from "../../lib/events.mjs";
|
|
14
|
+
import { COLOR_THUMB_CLASSES as re, areaValueText as d, colorAreaGradient as ie, displayColor as f, toPercent as p, toPosition as m } from "./colorUtils.mjs";
|
|
15
|
+
import { useColorPartState as h } from "./ColorPicker.parts.mjs";
|
|
16
16
|
import * as g from "react";
|
|
17
17
|
import { jsx as _, jsxs as ae } from "react/jsx-runtime";
|
|
18
18
|
//#region src/components/input/ColorArea.tsx
|
|
@@ -25,7 +25,7 @@ function v(e) {
|
|
|
25
25
|
return Math.min(100, Math.max(0, e));
|
|
26
26
|
}
|
|
27
27
|
var se = "(pointer: coarse)", y = ({ value: y, defaultValue: ce, onValueChange: le, shape: ue, labels: de, disabled: fe = !1, name: pe, form: b, required: me, controlRef: he, className: ge, style: _e, id: ve, "aria-label": ye, "aria-labelledby": x, "aria-describedby": S, "aria-invalid": C, "aria-required": w, "aria-errormessage": T, autoFocus: E, tabIndex: D, onKeyDown: O, onPointerDown: k, onPointerMove: A, ref: j, ...M }) => {
|
|
28
|
-
let N =
|
|
28
|
+
let N = h({
|
|
29
29
|
value: y,
|
|
30
30
|
defaultValue: ce,
|
|
31
31
|
onValueChange: le,
|
|
@@ -40,18 +40,18 @@ var se = "(pointer: coarse)", y = ({ value: y, defaultValue: ce, onValueChange:
|
|
|
40
40
|
valueText: P.labels.valueText
|
|
41
41
|
},
|
|
42
42
|
...de
|
|
43
|
-
}, be = ue ?? P?.shape ?? "rounded", I = N.color, L =
|
|
43
|
+
}, be = ue ?? P?.shape ?? "rounded", I = N.color, L = f(I), R = p(L.s), z = p(L.v), [B, V] = g.useState("saturation"), xe = c(se), H = g.useRef(null), [U, Se] = g.useState(0), W = g.useRef(null), G = g.useRef(null), K = g.useRef(null), Ce = s(j, W), we = s(G, he), q = g.useRef(0);
|
|
44
44
|
g.useLayoutEffect(() => {
|
|
45
45
|
q.current !== U && (q.current = U, (B === "saturation" ? G : K).current?.focus({ preventScroll: !0 }));
|
|
46
46
|
}, [B, U]);
|
|
47
|
-
let Te = ee(), { "aria-invalid": J, "aria-required": Ee, required: De, ...Oe } =
|
|
47
|
+
let Te = ee(), { "aria-invalid": J, "aria-required": Ee, required: De, ...Oe } = te({
|
|
48
48
|
id: ve,
|
|
49
49
|
"aria-label": ye ?? (P && x === void 0 ? P.labels.area : void 0),
|
|
50
50
|
"aria-labelledby": x,
|
|
51
51
|
"aria-describedby": S,
|
|
52
52
|
"aria-invalid": C
|
|
53
53
|
}, { labelable: !1 }), ke = J !== void 0 && J !== !1 && J !== "false" && T || void 0, Ae = me ?? (w === !0 || w === "true" || (Te?.required ?? !1));
|
|
54
|
-
|
|
54
|
+
l(W, N.reset, b);
|
|
55
55
|
let Y = (e, t) => {
|
|
56
56
|
t !== (e === "saturation" ? R : z) && N.setColor(e === "saturation" ? {
|
|
57
57
|
...I,
|
|
@@ -61,7 +61,7 @@ var se = "(pointer: coarse)", y = ({ value: y, defaultValue: ce, onValueChange:
|
|
|
61
61
|
v: t / 100
|
|
62
62
|
});
|
|
63
63
|
}, X = t(O, (e) => {
|
|
64
|
-
if (N.disabled || !
|
|
64
|
+
if (N.disabled || !u(e) || e.nativeEvent.isComposing || e.altKey || e.ctrlKey || e.metaKey) return;
|
|
65
65
|
let t = e.shiftKey ? 10 : 1, n, r;
|
|
66
66
|
switch (e.key) {
|
|
67
67
|
case "ArrowLeft":
|
|
@@ -115,7 +115,7 @@ var se = "(pointer: coarse)", y = ({ value: y, defaultValue: ce, onValueChange:
|
|
|
115
115
|
focusVisible: !1
|
|
116
116
|
});
|
|
117
117
|
}), Pe = t(k, (e) => {
|
|
118
|
-
!N.disabled && e.button === 0 && e.isPrimary &&
|
|
118
|
+
!N.disabled && e.button === 0 && e.isPrimary && u(e) && (e.preventDefault(), e.currentTarget.setPointerCapture(e.pointerId), Z(e), Ne());
|
|
119
119
|
}), Fe = t(A, (e) => {
|
|
120
120
|
!N.disabled && e.currentTarget.hasPointerCapture(e.pointerId) && Z(e);
|
|
121
121
|
}), Q = {
|
|
@@ -125,9 +125,9 @@ var se = "(pointer: coarse)", y = ({ value: y, defaultValue: ce, onValueChange:
|
|
|
125
125
|
valueText: F.valueText
|
|
126
126
|
}, Ie = {
|
|
127
127
|
..._e,
|
|
128
|
-
"--wave-color-area-gradient":
|
|
129
|
-
"--wave-color-area-x":
|
|
130
|
-
"--wave-color-area-y":
|
|
128
|
+
"--wave-color-area-gradient": ie(L.h),
|
|
129
|
+
"--wave-color-area-x": m(L.s),
|
|
130
|
+
"--wave-color-area-y": m(L.v),
|
|
131
131
|
"--wave-color-thumb": r({
|
|
132
132
|
h: L.h,
|
|
133
133
|
s: L.s,
|
|
@@ -167,7 +167,7 @@ var se = "(pointer: coarse)", y = ({ value: y, defaultValue: ce, onValueChange:
|
|
|
167
167
|
}),
|
|
168
168
|
/* @__PURE__ */ _("span", {
|
|
169
169
|
"aria-hidden": "true",
|
|
170
|
-
className: e(n.thumb,
|
|
170
|
+
className: e(n.thumb, re, "start-(--wave-color-area-x) bottom-(--wave-color-area-y) -translate-x-1/2 wave-rtl:translate-x-1/2 translate-y-1/2", "group-has-[:focus-visible]/color-area:ring-2 group-has-[:focus-visible]/color-area:ring-background forced-colors:group-has-[:focus-visible]/color-area:ring-[Canvas] group-has-[:focus-visible]/color-area:outline-2 group-has-[:focus-visible]/color-area:outline-offset-2 group-has-[:focus-visible]/color-area:outline-ring forced-colors:group-has-[:focus-visible]/color-area:outline-[Highlight]")
|
|
171
171
|
}),
|
|
172
172
|
/* @__PURE__ */ _("input", {
|
|
173
173
|
...$("saturation"),
|
|
@@ -185,7 +185,7 @@ var se = "(pointer: coarse)", y = ({ value: y, defaultValue: ce, onValueChange:
|
|
|
185
185
|
"aria-orientation": "vertical",
|
|
186
186
|
"aria-valuetext": d(L, "value", Q)
|
|
187
187
|
}),
|
|
188
|
-
!P && /* @__PURE__ */ _(
|
|
188
|
+
!P && /* @__PURE__ */ _(ne, {
|
|
189
189
|
type: "text",
|
|
190
190
|
name: pe,
|
|
191
191
|
form: b,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ColorArea.mjs","names":["React","DEFAULT_LABELS","clampPercent","value","COARSE_POINTER","ColorArea","ariaLabel","ariaLabelledBy","ariaDescribedBy","ariaInvalid","ariaRequired","ariaErrorMessage","rest","part","useColorPartState","strings","picker","labels","resolvedShape","shape","color","shown","displayColor","saturation","toPercent","brightness","activeAxis","setActiveAxis","coarsePointer","useMediaQuery","fieldRef","focusToken","setFocusToken","rootRef","saturationRef","brightnessRef","mergedRootRef","useMergedRefs","ref","mergedSaturationRef","controlRef","handledFocusTokenRef","field","useFieldContext","invalid","_ariaRequired","_required","groupProps","useFieldControl","errorMessageId","isRequired","required","form","applyAxis","percent","axis","handleKeyDown","composeEventHandlers","onKeyDown","isOwnEvent","event","step","next","intent","getArrowIntent","getDirection","token","handleInputChange","handleInputFocus","moveToPointer","useEventCallback","fieldElement","rect","x","s","v","focusActiveAxis","handlePointerDown","onPointerDown","handlePointerMove","onPointerMove","textLabels","areaStyle","style","colorAreaGradient","toPosition","hsvToHex","inputProps","tabIndex","cn","colorAreaClassNames","className","COLOR_THUMB_CLASSES","areaValueText","HiddenInput"],"sources":["../../../src/components/input/ColorArea.tsx"],"sourcesContent":["import * as React from 'react';\nimport { colorAreaClassNames } from '../../lib/classNames';\nimport { cn } from '../../lib/cn';\nimport { hsvToHex } from '../../lib/color';\nimport { composeEventHandlers } from '../../lib/composeEventHandlers';\nimport { getArrowIntent, getDirection } from '../../lib/direction';\nimport { isOwnEvent } from '../../lib/events';\nimport type { ColorPickerShape, HsvColor } from '../../lib/types';\nimport { useEventCallback } from '../../hooks/useEventCallback';\nimport { useFieldContext, useFieldControl } from '../../hooks/useFieldControl';\nimport { useFormReset } from '../../hooks/useFormReset';\nimport { useMediaQuery } from '../../hooks/useMediaQuery';\nimport { useMergedRefs } from '../../hooks/useMergedRefs';\nimport { HiddenInput } from '../internal/HiddenInput';\nimport { useColorPartState } from './ColorPicker.parts';\nimport {\n COLOR_THUMB_CLASSES,\n areaValueText,\n colorAreaGradient,\n displayColor,\n toPercent,\n toPosition,\n} from './colorUtils';\n\n/** Texts of a ColorArea, for localisation. Every key is optional. */\nexport interface ColorAreaLabels {\n /** Name of the horizontal slider.\n * @default 'Saturation'\n */\n saturation?: string;\n /** Name of the vertical slider (the `value` channel).\n * @default 'Brightness'\n */\n brightness?: string;\n /** Role description of both sliders.\n * @default '2D slider'\n */\n roleDescription?: string;\n /** Names the color at the end of each value text; return `''` to leave it out.\n * @default an English namer (\"dark blue\")\n */\n colorName?: (color: HsvColor) => string;\n /** Replaces a whole value text, for languages whose order differs. */\n valueText?: (color: HsvColor, channel: 'saturation' | 'value') => string;\n}\n\n/** Properties for the ColorArea component. */\nexport interface ColorAreaProps extends Omit<\n React.HTMLAttributes<HTMLDivElement>,\n 'defaultValue' | 'onChange'\n> {\n /**\n * The color (Fluent's `color`). Inside a ColorPicker, leave `value` and `defaultValue` out to\n * bind the area to the picker.\n */\n value?: HsvColor;\n /**\n * Initial color for uncontrolled usage (also what a form reset restores).\n * @default the brand blue, `{ h: 208, s: 0.92, v: 0.74 }` (`#0f6cbd`)\n */\n defaultValue?: HsvColor;\n /**\n * Called with the new color on every step (a key, a pointer move or assistive technology) that\n * changes it (Fluent's `onChange`). A bound area calls it too.\n */\n onValueChange?: (value: HsvColor) => void;\n /**\n * `'square'` removes the corner radius (the thumb stays round). Bound to a ColorPicker, the\n * picker's shape unless you pass one.\n * @default 'rounded'\n */\n shape?: ColorPickerShape;\n /** Texts of the area; bound to a ColorPicker, the picker's `labels` fill the keys you leave out. */\n labels?: ColorAreaLabels;\n /**\n * Unavailable: both inputs are natively disabled, pointer presses are ignored and the area is\n * dimmed. A bound area is also disabled while the picker's value is not a hex color.\n * @default false\n */\n disabled?: boolean;\n /** Form field name: the color is submitted as hex (`hsvToHex`). Ignored while bound to a ColorPicker. */\n name?: string;\n /** Id of the form the area belongs to, when it is rendered outside that form. */\n form?: string;\n /**\n * Marks the hidden form input required (a color is always set, so it never blocks). A consumer\n * `aria-required` does the same: a group supports neither, so neither is set on it.\n */\n required?: boolean;\n /** Ref to the saturation `<input type=\"range\">`. */\n controlRef?: React.Ref<HTMLInputElement>;\n /** Ref to the root `role=\"group\"` element. */\n ref?: React.Ref<HTMLDivElement>;\n}\n\n/** The two axes: saturation (x) and brightness (y, the `value` channel). */\ntype AreaAxis = 'saturation' | 'value';\n\nconst DEFAULT_LABELS = {\n saturation: 'Saturation',\n brightness: 'Brightness',\n roleDescription: '2D slider',\n} as const;\n\n/** A whole percentage clamped to 0–100. */\nfunction clampPercent(value: number): number {\n return Math.min(100, Math.max(0, value));\n}\n\n/** Touch-primary devices expose both inputs, so a touch screen reader can swipe each (D19). */\nconst COARSE_POINTER = '(pointer: coarse)';\n\n/**\n * A 2-D color field: saturation from left to right (mirrored in right-to-left layouts) and\n * brightness from bottom to top, at the value's hue. ArrowLeft and ArrowRight move saturation by\n * 1 %, ArrowUp and ArrowDown brightness; Shift with an arrow moves by 10, Page Up and Page Down\n * move brightness by 10, and Home and End set saturation to 0 and 100. A press or drag (mouse,\n * touch or pen) moves the thumb to the pointer. It is one Tab stop holding two sliders for\n * assistive technology, \"Saturation\" and \"Brightness\", whose value texts start with their own\n * channel and name the color; focus follows the axis a key moves, and unless the primary pointer\n * is coarse (touch), only the slider with the Tab stop is exposed. Inside a ColorPicker, leave\n * `value` and `defaultValue` out and it binds to the picker. Fluent's\n * `ColorArea`, with `value`/`onValueChange` for its `color`/`onChange`.\n *\n * @example\n * <ColorArea aria-label=\"Accent color\" value={color} onValueChange={setColor} />\n */\nexport const ColorArea = ({\n value,\n defaultValue,\n onValueChange,\n shape,\n labels,\n disabled = false,\n name,\n form,\n required,\n controlRef,\n className,\n style,\n id,\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledBy,\n 'aria-describedby': ariaDescribedBy,\n 'aria-invalid': ariaInvalid,\n 'aria-required': ariaRequired,\n 'aria-errormessage': ariaErrorMessage,\n autoFocus,\n tabIndex,\n onKeyDown,\n onPointerDown,\n onPointerMove,\n ref,\n ...rest\n}: ColorAreaProps) => {\n const part = useColorPartState({ value, defaultValue, onValueChange, disabled });\n const { picker } = part;\n const strings = {\n ...DEFAULT_LABELS,\n ...(picker && {\n saturation: picker.labels.saturation,\n brightness: picker.labels.brightness,\n roleDescription: picker.labels.roleDescription,\n colorName: picker.labels.colorName,\n valueText: picker.labels.valueText,\n }),\n ...labels,\n };\n const resolvedShape = shape ?? picker?.shape ?? 'rounded';\n const color = part.color;\n const shown = displayColor(color);\n const saturation = toPercent(shown.s);\n const brightness = toPercent(shown.v);\n\n const [activeAxis, setActiveAxis] = React.useState<AreaAxis>('saturation');\n const coarsePointer = useMediaQuery(COARSE_POINTER);\n const fieldRef = React.useRef<HTMLDivElement>(null);\n // Bumped on every handled key (not only an axis change), so the layout effect below moves focus\n // to the axis's input even when the key's axis is the one an earlier assistive-technology change\n // already made the Tab stop, without moving focus; focusing an input that already has focus does\n // nothing. Never bumped for an AT-driven change (`handleInputChange`) or a real focus event. A\n // plain counter, not a ref: react-hooks/refs only allows a ref's `current` to be touched from an\n // effect, a ref callback or a function assigned directly to a JSX handler prop, not one passed\n // through `composeEventHandlers`.\n const [focusToken, setFocusToken] = React.useState(0);\n const rootRef = React.useRef<HTMLDivElement>(null);\n const saturationRef = React.useRef<HTMLInputElement>(null);\n const brightnessRef = React.useRef<HTMLInputElement>(null);\n const mergedRootRef = useMergedRefs(ref, rootRef);\n const mergedSaturationRef = useMergedRefs(saturationRef, controlRef);\n /** The last `focusToken` this component already moved focus for (read/written in the effect only). */\n const handledFocusTokenRef = React.useRef(0);\n\n React.useLayoutEffect(() => {\n if (handledFocusTokenRef.current === focusToken) return;\n handledFocusTokenRef.current = focusToken;\n (activeAxis === 'saturation' ? saturationRef : brightnessRef).current?.focus({\n preventScroll: true,\n });\n }, [activeAxis, focusToken]);\n\n const field = useFieldContext();\n const fieldProps = useFieldControl(\n {\n id,\n 'aria-label':\n ariaLabel ?? (picker && ariaLabelledBy === undefined ? picker.labels.area : undefined),\n 'aria-labelledby': ariaLabelledBy,\n 'aria-describedby': ariaDescribedBy,\n 'aria-invalid': ariaInvalid,\n },\n { labelable: false },\n );\n // A group supports neither aria-invalid, aria-required nor `required` (ARIA 1.2): the invalid\n // state goes to both inputs and the required state to the hidden input.\n const {\n 'aria-invalid': invalid,\n 'aria-required': _ariaRequired,\n required: _required,\n ...groupProps\n } = fieldProps;\n const isInvalid = invalid !== undefined && invalid !== false && invalid !== 'false';\n const errorMessageId = (isInvalid && ariaErrorMessage) || undefined;\n const isRequired =\n required ?? (ariaRequired === true || ariaRequired === 'true' || (field?.required ?? false));\n\n useFormReset(rootRef, part.reset, form);\n\n /** Applies a whole percentage to one axis, keeping the other channels as given. */\n const applyAxis = (axis: AreaAxis, percent: number) => {\n if (percent === (axis === 'saturation' ? saturation : brightness)) return;\n part.setColor(\n axis === 'saturation' ? { ...color, s: percent / 100 } : { ...color, v: percent / 100 },\n );\n };\n\n const handleKeyDown = composeEventHandlers(\n onKeyDown,\n (event: React.KeyboardEvent<HTMLDivElement>) => {\n if (part.disabled || !isOwnEvent(event) || event.nativeEvent.isComposing) return;\n // A key with Alt, Ctrl or Meta belongs to the browser (Alt+Left is \"back\").\n if (event.altKey || event.ctrlKey || event.metaKey) return;\n const step = event.shiftKey ? 10 : 1;\n let axis: AreaAxis;\n let next: number;\n switch (event.key) {\n case 'ArrowLeft':\n case 'ArrowRight': {\n const intent = getArrowIntent(event.key, {\n orientation: 'horizontal',\n dir: getDirection(event.currentTarget),\n });\n axis = 'saturation';\n next = saturation + (intent === 'next' ? step : -step);\n break;\n }\n case 'ArrowUp':\n axis = 'value';\n next = brightness + step;\n break;\n case 'ArrowDown':\n axis = 'value';\n next = brightness - step;\n break;\n case 'PageUp':\n axis = 'value';\n next = brightness + 10;\n break;\n case 'PageDown':\n axis = 'value';\n next = brightness - 10;\n break;\n case 'Home':\n axis = 'saturation';\n next = 0;\n break;\n case 'End':\n axis = 'saturation';\n next = 100;\n break;\n default:\n return;\n }\n // Prevented, so the native range input never moves on its own.\n event.preventDefault();\n if (axis !== activeAxis) setActiveAxis(axis);\n // Every handled key moves focus to its axis's input, even when an earlier\n // assistive-technology change already made that axis the Tab stop.\n setFocusToken((token) => token + 1);\n applyAxis(axis, clampPercent(next));\n },\n );\n\n /** A change event from assistive technology (a swipe): that input becomes the Tab stop. */\n const handleInputChange = (axis: AreaAxis) => (event: React.ChangeEvent<HTMLInputElement>) => {\n if (part.disabled) return;\n if (axis !== activeAxis) setActiveAxis(axis);\n applyAxis(axis, clampPercent(Math.round(Number(event.currentTarget.value))));\n };\n\n const handleInputFocus = (axis: AreaAxis) => () => {\n if (axis !== activeAxis) setActiveAxis(axis);\n };\n\n // Both read a ref (`fieldRef`, or `saturationRef`/`brightnessRef`): `useEventCallback` (a custom\n // hook, opaque to react-hooks/refs) keeps that safe to call from the handler below, unlike a\n // plain function or `React.useCallback` passed into the generic `composeEventHandlers`.\n /** Moves the thumb to the pointer: saturation along x (mirrored in RTL), brightness along y. */\n const moveToPointer = useEventCallback((event: React.PointerEvent<HTMLDivElement>) => {\n const fieldElement = fieldRef.current;\n if (!fieldElement) return;\n const rect = fieldElement.getBoundingClientRect();\n if (rect.width <= 0 || rect.height <= 0) return;\n const x = Math.min(1, Math.max(0, (event.clientX - rect.left) / rect.width));\n const s = getDirection(event.currentTarget) === 'rtl' ? 1 - x : x;\n const v = Math.min(1, Math.max(0, 1 - (event.clientY - rect.top) / rect.height));\n if (s === shown.s && v === shown.v) return;\n part.setColor({ ...color, s, v });\n });\n /**\n * Focuses the input of the active axis (the press moves focus there instead of the point),\n * without the focus ring: Chromium treats this script focus as keyboard focus, where the\n * browser's own focus of a pressed control shows none. Browsers without the `focusVisible`\n * option ignore it.\n */\n const focusActiveAxis = useEventCallback(() => {\n const options: FocusOptions = { preventScroll: true, focusVisible: false };\n (activeAxis === 'saturation' ? saturationRef : brightnessRef).current?.focus(options);\n });\n\n const handlePointerDown = composeEventHandlers(\n onPointerDown,\n (event: React.PointerEvent<HTMLDivElement>) => {\n if (part.disabled || event.button !== 0 || !event.isPrimary || !isOwnEvent(event)) return;\n // No text selection and no focus move of the press: focus goes to the Tab stop instead.\n event.preventDefault();\n event.currentTarget.setPointerCapture(event.pointerId);\n moveToPointer(event);\n focusActiveAxis();\n },\n );\n\n // The drag lasts while the root holds the pointer; losing the capture (pointerup,\n // lostpointercapture) ends it.\n const handlePointerMove = composeEventHandlers(\n onPointerMove,\n (event: React.PointerEvent<HTMLDivElement>) => {\n if (part.disabled || !event.currentTarget.hasPointerCapture(event.pointerId)) return;\n moveToPointer(event);\n },\n );\n\n const textLabels = {\n saturation: strings.saturation,\n brightness: strings.brightness,\n colorName: strings.colorName,\n valueText: strings.valueText,\n };\n\n const areaStyle = {\n ...style,\n '--wave-color-area-gradient': colorAreaGradient(shown.h),\n '--wave-color-area-x': toPosition(shown.s),\n '--wave-color-area-y': toPosition(shown.v),\n '--wave-color-thumb': hsvToHex({ h: shown.h, s: shown.s, v: shown.v }),\n } as React.CSSProperties;\n\n const inputProps = (axis: AreaAxis) => ({\n type: 'range' as const,\n min: 0,\n max: 100,\n step: 1,\n disabled: part.disabled,\n 'aria-roledescription': strings.roleDescription,\n 'aria-invalid': invalid,\n 'aria-errormessage': errorMessageId,\n // One Tab stop: the input used last (C-ROUTING: a consumer tabIndex applies to it).\n tabIndex: axis === activeAxis ? (tabIndex ?? 0) : -1,\n // Where the primary pointer is not coarse, desktop screen readers meet one 2-D slider: the\n // input without the Tab stop is hidden (it stays focusable by script, never by Tab).\n 'aria-hidden': axis !== activeAxis && !coarsePointer ? true : undefined,\n onChange: handleInputChange(axis),\n onFocus: handleInputFocus(axis),\n className: 'sr-only',\n });\n\n return (\n <div\n role=\"group\"\n data-disabled={part.disabled ? '' : undefined}\n {...groupProps}\n className={cn(\n colorAreaClassNames.root,\n 'group/color-area relative h-40 w-full min-w-40 touch-none select-none data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50',\n resolvedShape === 'square' ? 'rounded-none' : 'rounded',\n className,\n )}\n style={areaStyle}\n {...rest}\n ref={mergedRootRef}\n onKeyDown={handleKeyDown}\n onPointerDown={handlePointerDown}\n onPointerMove={handlePointerMove}\n >\n <div\n ref={fieldRef}\n aria-hidden=\"true\"\n className={cn(\n colorAreaClassNames.field,\n 'absolute inset-0 rounded-[inherit] bg-(image:--wave-color-area-gradient) wave-rtl:-scale-x-100 forced-colors:forced-color-adjust-none',\n )}\n />\n <span\n aria-hidden=\"true\"\n className={cn(\n colorAreaClassNames.thumb,\n COLOR_THUMB_CLASSES,\n 'start-(--wave-color-area-x) bottom-(--wave-color-area-y) -translate-x-1/2 wave-rtl:translate-x-1/2 translate-y-1/2',\n 'group-has-[:focus-visible]/color-area:ring-2 group-has-[:focus-visible]/color-area:ring-background forced-colors:group-has-[:focus-visible]/color-area:ring-[Canvas] group-has-[:focus-visible]/color-area:outline-2 group-has-[:focus-visible]/color-area:outline-offset-2 group-has-[:focus-visible]/color-area:outline-ring forced-colors:group-has-[:focus-visible]/color-area:outline-[Highlight]',\n )}\n />\n <input\n {...inputProps('saturation')}\n ref={mergedSaturationRef}\n value={saturation}\n aria-label={strings.saturation}\n aria-valuetext={areaValueText(shown, 'saturation', textLabels)}\n autoFocus={autoFocus}\n />\n <input\n {...inputProps('value')}\n ref={brightnessRef}\n value={brightness}\n aria-label={strings.brightness}\n aria-orientation=\"vertical\"\n aria-valuetext={areaValueText(shown, 'value', textLabels)}\n />\n {!picker && (\n <HiddenInput\n type=\"text\"\n name={name}\n form={form}\n disabled={part.disabled}\n value={hsvToHex(color)}\n required={isRequired}\n onInvalid={() =>\n (activeAxis === 'saturation' ? saturationRef : brightnessRef).current?.focus()\n }\n />\n )}\n </div>\n );\n};\n\nColorArea.displayName = 'ColorArea';\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ColorArea.mjs","names":["React","DEFAULT_LABELS","clampPercent","value","COARSE_POINTER","ColorArea","ariaLabel","ariaLabelledBy","ariaDescribedBy","ariaInvalid","ariaRequired","ariaErrorMessage","rest","part","useColorPartState","strings","picker","labels","resolvedShape","shape","color","shown","displayColor","saturation","toPercent","brightness","activeAxis","setActiveAxis","coarsePointer","useMediaQuery","fieldRef","focusToken","setFocusToken","rootRef","saturationRef","brightnessRef","mergedRootRef","useMergedRefs","ref","mergedSaturationRef","controlRef","handledFocusTokenRef","field","useFieldContext","invalid","_ariaRequired","_required","groupProps","useFieldControl","errorMessageId","isRequired","required","form","applyAxis","percent","axis","handleKeyDown","composeEventHandlers","onKeyDown","isOwnEvent","event","step","next","intent","getArrowIntent","getDirection","token","handleInputChange","handleInputFocus","moveToPointer","useEventCallback","fieldElement","rect","x","s","v","focusActiveAxis","handlePointerDown","onPointerDown","handlePointerMove","onPointerMove","textLabels","areaStyle","style","colorAreaGradient","toPosition","hsvToHex","inputProps","tabIndex","cn","colorAreaClassNames","className","COLOR_THUMB_CLASSES","areaValueText","HiddenInput"],"sources":["../../../src/components/input/ColorArea.tsx"],"sourcesContent":["import * as React from 'react';\nimport { colorAreaClassNames } from '../../lib/classNames';\nimport { cn } from '../../lib/cn';\nimport { hsvToHex } from '../../lib/color';\nimport { composeEventHandlers } from '../../lib/composeEventHandlers';\nimport { getArrowIntent, getDirection } from '../../lib/direction';\nimport { isOwnEvent } from '../../lib/events';\nimport type { ColorPickerShape, HsvColor } from '../../lib/types';\nimport { useEventCallback } from '../../hooks/useEventCallback';\nimport { useFieldContext, useFieldControl } from '../../hooks/useFieldControl';\nimport { useFormReset } from '../../hooks/useFormReset';\nimport { useMediaQuery } from '../../hooks/useMediaQuery';\nimport { useMergedRefs } from '../../hooks/useMergedRefs';\nimport { HiddenInput } from '../internal/HiddenInput';\nimport { useColorPartState } from './ColorPicker.parts';\nimport {\n COLOR_THUMB_CLASSES,\n areaValueText,\n colorAreaGradient,\n displayColor,\n toPercent,\n toPosition,\n} from './colorUtils';\n\n/** Texts of a ColorArea, for localisation. Every key is optional. */\nexport interface ColorAreaLabels {\n /** Name of the horizontal slider.\n * @default 'Saturation'\n */\n saturation?: string;\n /** Name of the vertical slider (the `value` channel).\n * @default 'Brightness'\n */\n brightness?: string;\n /** Role description of both sliders.\n * @default '2D slider'\n */\n roleDescription?: string;\n /** Names the color at the end of each value text; return `''` to leave it out.\n * @default an English namer (\"dark blue\")\n */\n colorName?: (color: HsvColor) => string;\n /** Replaces a whole value text, for languages whose order differs. */\n valueText?: (color: HsvColor, channel: 'saturation' | 'value') => string;\n}\n\n/** Properties for the ColorArea component. */\nexport interface ColorAreaProps extends Omit<\n React.HTMLAttributes<HTMLDivElement>,\n 'defaultValue' | 'onChange'\n> {\n /**\n * The color (Fluent's `color`). Inside a ColorPicker, leave `value` and `defaultValue` out to\n * bind the area to the picker.\n */\n value?: HsvColor;\n /**\n * Initial color for uncontrolled usage (also what a form reset restores).\n * @default the brand blue, `{ h: 208, s: 0.92, v: 0.74 }` (`#0f6cbd`)\n */\n defaultValue?: HsvColor;\n /**\n * Called with the new color on every step (a key, a pointer move or assistive technology) that\n * changes it (Fluent's `onChange`). A bound area calls it too.\n */\n onValueChange?: (value: HsvColor) => void;\n /**\n * `'square'` removes the corner radius (the thumb stays round). Bound to a ColorPicker, the\n * picker's shape unless you pass one.\n * @default 'rounded'\n */\n shape?: ColorPickerShape;\n /** Texts of the area; bound to a ColorPicker, the picker's `labels` fill the keys you leave out. */\n labels?: ColorAreaLabels;\n /**\n * Unavailable: both inputs are natively disabled, pointer presses are ignored and the area is\n * dimmed. A bound area is also disabled while the picker's value is not a hex color.\n * @default false\n */\n disabled?: boolean;\n /** Form field name: the color is submitted as hex (`hsvToHex`). Ignored while bound to a ColorPicker. */\n name?: string;\n /** Id of the form the area belongs to, when it is rendered outside that form. */\n form?: string;\n /**\n * Marks the hidden form input required (a color is always set, so it never blocks). A consumer\n * `aria-required` does the same: a group supports neither, so neither is set on it.\n */\n required?: boolean;\n /** Ref to the saturation `<input type=\"range\">`. */\n controlRef?: React.Ref<HTMLInputElement>;\n /** Ref to the root `role=\"group\"` element. */\n ref?: React.Ref<HTMLDivElement>;\n}\n\n/** The two axes: saturation (x) and brightness (y, the `value` channel). */\ntype AreaAxis = 'saturation' | 'value';\n\nconst DEFAULT_LABELS = {\n saturation: 'Saturation',\n brightness: 'Brightness',\n roleDescription: '2D slider',\n} as const;\n\n/** A whole percentage clamped to 0–100. */\nfunction clampPercent(value: number): number {\n return Math.min(100, Math.max(0, value));\n}\n\n/** Touch-primary devices expose both inputs, so a touch screen reader can swipe each (D19). */\nconst COARSE_POINTER = '(pointer: coarse)';\n\n/**\n * A 2-D color field: saturation from left to right (mirrored in right-to-left layouts) and\n * brightness from bottom to top, at the value's hue. ArrowLeft and ArrowRight move saturation by\n * 1 %, ArrowUp and ArrowDown brightness; Shift with an arrow moves by 10, Page Up and Page Down\n * move brightness by 10, and Home and End set saturation to 0 and 100. A press or drag (mouse,\n * touch or pen) moves the thumb to the pointer. It is one Tab stop holding two sliders for\n * assistive technology, \"Saturation\" and \"Brightness\", whose value texts start with their own\n * channel and name the color; focus follows the axis a key moves, and unless the primary pointer\n * is coarse (touch), only the slider with the Tab stop is exposed. Inside a ColorPicker, leave\n * `value` and `defaultValue` out and it binds to the picker. Fluent's\n * `ColorArea`, with `value`/`onValueChange` for its `color`/`onChange`.\n *\n * @example\n * <ColorArea aria-label=\"Accent color\" value={color} onValueChange={setColor} />\n */\nexport const ColorArea = ({\n value,\n defaultValue,\n onValueChange,\n shape,\n labels,\n disabled = false,\n name,\n form,\n required,\n controlRef,\n className,\n style,\n id,\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledBy,\n 'aria-describedby': ariaDescribedBy,\n 'aria-invalid': ariaInvalid,\n 'aria-required': ariaRequired,\n 'aria-errormessage': ariaErrorMessage,\n autoFocus,\n tabIndex,\n onKeyDown,\n onPointerDown,\n onPointerMove,\n ref,\n ...rest\n}: ColorAreaProps) => {\n const part = useColorPartState({ value, defaultValue, onValueChange, disabled });\n const { picker } = part;\n const strings = {\n ...DEFAULT_LABELS,\n ...(picker && {\n saturation: picker.labels.saturation,\n brightness: picker.labels.brightness,\n roleDescription: picker.labels.roleDescription,\n colorName: picker.labels.colorName,\n valueText: picker.labels.valueText,\n }),\n ...labels,\n };\n const resolvedShape = shape ?? picker?.shape ?? 'rounded';\n const color = part.color;\n const shown = displayColor(color);\n const saturation = toPercent(shown.s);\n const brightness = toPercent(shown.v);\n\n const [activeAxis, setActiveAxis] = React.useState<AreaAxis>('saturation');\n const coarsePointer = useMediaQuery(COARSE_POINTER);\n const fieldRef = React.useRef<HTMLDivElement>(null);\n // Bumped on every handled key (not only an axis change), so the layout effect below moves focus\n // to the axis's input even when the key's axis is the one an earlier assistive-technology change\n // already made the Tab stop, without moving focus; focusing an input that already has focus does\n // nothing. Never bumped for an AT-driven change (`handleInputChange`) or a real focus event. A\n // plain counter, not a ref: react-hooks/refs only allows a ref's `current` to be touched from an\n // effect, a ref callback or a function assigned directly to a JSX handler prop, not one passed\n // through `composeEventHandlers`.\n const [focusToken, setFocusToken] = React.useState(0);\n const rootRef = React.useRef<HTMLDivElement>(null);\n const saturationRef = React.useRef<HTMLInputElement>(null);\n const brightnessRef = React.useRef<HTMLInputElement>(null);\n const mergedRootRef = useMergedRefs(ref, rootRef);\n const mergedSaturationRef = useMergedRefs(saturationRef, controlRef);\n /** The last `focusToken` this component already moved focus for (read/written in the effect only). */\n const handledFocusTokenRef = React.useRef(0);\n\n React.useLayoutEffect(() => {\n if (handledFocusTokenRef.current === focusToken) return;\n handledFocusTokenRef.current = focusToken;\n (activeAxis === 'saturation' ? saturationRef : brightnessRef).current?.focus({\n preventScroll: true,\n });\n }, [activeAxis, focusToken]);\n\n const field = useFieldContext();\n const fieldProps = useFieldControl(\n {\n id,\n 'aria-label':\n ariaLabel ?? (picker && ariaLabelledBy === undefined ? picker.labels.area : undefined),\n 'aria-labelledby': ariaLabelledBy,\n 'aria-describedby': ariaDescribedBy,\n 'aria-invalid': ariaInvalid,\n },\n { labelable: false },\n );\n // A group supports neither aria-invalid, aria-required nor `required` (ARIA 1.2): the invalid\n // state goes to both inputs and the required state to the hidden input.\n const {\n 'aria-invalid': invalid,\n 'aria-required': _ariaRequired,\n required: _required,\n ...groupProps\n } = fieldProps;\n const isInvalid = invalid !== undefined && invalid !== false && invalid !== 'false';\n const errorMessageId = (isInvalid && ariaErrorMessage) || undefined;\n const isRequired =\n required ?? (ariaRequired === true || ariaRequired === 'true' || (field?.required ?? false));\n\n useFormReset(rootRef, part.reset, form);\n\n /** Applies a whole percentage to one axis, keeping the other channels as given. */\n const applyAxis = (axis: AreaAxis, percent: number) => {\n if (percent === (axis === 'saturation' ? saturation : brightness)) return;\n part.setColor(\n axis === 'saturation' ? { ...color, s: percent / 100 } : { ...color, v: percent / 100 },\n );\n };\n\n const handleKeyDown = composeEventHandlers(\n onKeyDown,\n (event: React.KeyboardEvent<HTMLDivElement>) => {\n if (part.disabled || !isOwnEvent(event) || event.nativeEvent.isComposing) return;\n // A key with Alt, Ctrl or Meta belongs to the browser (Alt+Left is \"back\").\n if (event.altKey || event.ctrlKey || event.metaKey) return;\n const step = event.shiftKey ? 10 : 1;\n let axis: AreaAxis;\n let next: number;\n switch (event.key) {\n case 'ArrowLeft':\n case 'ArrowRight': {\n const intent = getArrowIntent(event.key, {\n orientation: 'horizontal',\n dir: getDirection(event.currentTarget),\n });\n axis = 'saturation';\n next = saturation + (intent === 'next' ? step : -step);\n break;\n }\n case 'ArrowUp':\n axis = 'value';\n next = brightness + step;\n break;\n case 'ArrowDown':\n axis = 'value';\n next = brightness - step;\n break;\n case 'PageUp':\n axis = 'value';\n next = brightness + 10;\n break;\n case 'PageDown':\n axis = 'value';\n next = brightness - 10;\n break;\n case 'Home':\n axis = 'saturation';\n next = 0;\n break;\n case 'End':\n axis = 'saturation';\n next = 100;\n break;\n default:\n return;\n }\n // Prevented, so the native range input never moves on its own.\n event.preventDefault();\n if (axis !== activeAxis) setActiveAxis(axis);\n // Every handled key moves focus to its axis's input, even when an earlier\n // assistive-technology change already made that axis the Tab stop.\n setFocusToken((token) => token + 1);\n applyAxis(axis, clampPercent(next));\n },\n );\n\n /** A change event from assistive technology (a swipe): that input becomes the Tab stop. */\n const handleInputChange = (axis: AreaAxis) => (event: React.ChangeEvent<HTMLInputElement>) => {\n if (part.disabled) return;\n if (axis !== activeAxis) setActiveAxis(axis);\n applyAxis(axis, clampPercent(Math.round(Number(event.currentTarget.value))));\n };\n\n const handleInputFocus = (axis: AreaAxis) => () => {\n if (axis !== activeAxis) setActiveAxis(axis);\n };\n\n // Both read a ref (`fieldRef`, or `saturationRef`/`brightnessRef`): `useEventCallback` (a custom\n // hook, opaque to react-hooks/refs) keeps that safe to call from the handler below, unlike a\n // plain function or `React.useCallback` passed into the generic `composeEventHandlers`.\n /** Moves the thumb to the pointer: saturation along x (mirrored in RTL), brightness along y. */\n const moveToPointer = useEventCallback((event: React.PointerEvent<HTMLDivElement>) => {\n const fieldElement = fieldRef.current;\n if (!fieldElement) return;\n const rect = fieldElement.getBoundingClientRect();\n if (rect.width <= 0 || rect.height <= 0) return;\n const x = Math.min(1, Math.max(0, (event.clientX - rect.left) / rect.width));\n const s = getDirection(event.currentTarget) === 'rtl' ? 1 - x : x;\n const v = Math.min(1, Math.max(0, 1 - (event.clientY - rect.top) / rect.height));\n if (s === shown.s && v === shown.v) return;\n part.setColor({ ...color, s, v });\n });\n /**\n * Focuses the input of the active axis (the press moves focus there instead of the point),\n * without the focus ring: Chromium treats this script focus as keyboard focus, where the\n * browser's own focus of a pressed control shows none. Browsers without the `focusVisible`\n * option ignore it.\n */\n const focusActiveAxis = useEventCallback(() => {\n const options: FocusOptions = { preventScroll: true, focusVisible: false };\n (activeAxis === 'saturation' ? saturationRef : brightnessRef).current?.focus(options);\n });\n\n const handlePointerDown = composeEventHandlers(\n onPointerDown,\n (event: React.PointerEvent<HTMLDivElement>) => {\n if (part.disabled || event.button !== 0 || !event.isPrimary || !isOwnEvent(event)) return;\n // No text selection and no focus move of the press: focus goes to the Tab stop instead.\n event.preventDefault();\n event.currentTarget.setPointerCapture(event.pointerId);\n moveToPointer(event);\n focusActiveAxis();\n },\n );\n\n // The drag lasts while the root holds the pointer; losing the capture (pointerup,\n // lostpointercapture) ends it.\n const handlePointerMove = composeEventHandlers(\n onPointerMove,\n (event: React.PointerEvent<HTMLDivElement>) => {\n if (part.disabled || !event.currentTarget.hasPointerCapture(event.pointerId)) return;\n moveToPointer(event);\n },\n );\n\n const textLabels = {\n saturation: strings.saturation,\n brightness: strings.brightness,\n colorName: strings.colorName,\n valueText: strings.valueText,\n };\n\n const areaStyle = {\n ...style,\n '--wave-color-area-gradient': colorAreaGradient(shown.h),\n '--wave-color-area-x': toPosition(shown.s),\n '--wave-color-area-y': toPosition(shown.v),\n '--wave-color-thumb': hsvToHex({ h: shown.h, s: shown.s, v: shown.v }),\n } as React.CSSProperties;\n\n const inputProps = (axis: AreaAxis) => ({\n type: 'range' as const,\n min: 0,\n max: 100,\n step: 1,\n disabled: part.disabled,\n 'aria-roledescription': strings.roleDescription,\n 'aria-invalid': invalid,\n 'aria-errormessage': errorMessageId,\n // One Tab stop: the input used last (C-ROUTING: a consumer tabIndex applies to it).\n tabIndex: axis === activeAxis ? (tabIndex ?? 0) : -1,\n // Where the primary pointer is not coarse, desktop screen readers meet one 2-D slider: the\n // input without the Tab stop is hidden (it stays focusable by script, never by Tab).\n 'aria-hidden': axis !== activeAxis && !coarsePointer ? true : undefined,\n onChange: handleInputChange(axis),\n onFocus: handleInputFocus(axis),\n className: 'sr-only',\n });\n\n return (\n <div\n role=\"group\"\n data-disabled={part.disabled ? '' : undefined}\n {...groupProps}\n className={cn(\n colorAreaClassNames.root,\n 'group/color-area relative h-40 w-full min-w-40 touch-none select-none data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50',\n resolvedShape === 'square' ? 'rounded-none' : 'rounded',\n className,\n )}\n style={areaStyle}\n {...rest}\n ref={mergedRootRef}\n onKeyDown={handleKeyDown}\n onPointerDown={handlePointerDown}\n onPointerMove={handlePointerMove}\n >\n <div\n ref={fieldRef}\n aria-hidden=\"true\"\n className={cn(\n colorAreaClassNames.field,\n 'absolute inset-0 rounded-[inherit] bg-(image:--wave-color-area-gradient) wave-rtl:-scale-x-100 forced-colors:forced-color-adjust-none',\n )}\n />\n <span\n aria-hidden=\"true\"\n className={cn(\n colorAreaClassNames.thumb,\n COLOR_THUMB_CLASSES,\n 'start-(--wave-color-area-x) bottom-(--wave-color-area-y) -translate-x-1/2 wave-rtl:translate-x-1/2 translate-y-1/2',\n 'group-has-[:focus-visible]/color-area:ring-2 group-has-[:focus-visible]/color-area:ring-background forced-colors:group-has-[:focus-visible]/color-area:ring-[Canvas] group-has-[:focus-visible]/color-area:outline-2 group-has-[:focus-visible]/color-area:outline-offset-2 group-has-[:focus-visible]/color-area:outline-ring forced-colors:group-has-[:focus-visible]/color-area:outline-[Highlight]',\n )}\n />\n <input\n {...inputProps('saturation')}\n ref={mergedSaturationRef}\n value={saturation}\n aria-label={strings.saturation}\n aria-valuetext={areaValueText(shown, 'saturation', textLabels)}\n autoFocus={autoFocus}\n />\n <input\n {...inputProps('value')}\n ref={brightnessRef}\n value={brightness}\n aria-label={strings.brightness}\n aria-orientation=\"vertical\"\n aria-valuetext={areaValueText(shown, 'value', textLabels)}\n />\n {!picker && (\n <HiddenInput\n type=\"text\"\n name={name}\n form={form}\n disabled={part.disabled}\n value={hsvToHex(color)}\n required={isRequired}\n onInvalid={() =>\n (activeAxis === 'saturation' ? saturationRef : brightnessRef).current?.focus()\n }\n />\n )}\n </div>\n );\n};\n\nColorArea.displayName = 'ColorArea';\n"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use client";const e=require("../../_virtual/_rolldown/runtime.cjs"),t=require("../../lib/cn.cjs"),
|
|
1
|
+
"use client";const e=require("../../_virtual/_rolldown/runtime.cjs"),t=require("../../lib/cn.cjs"),n=require("../../lib/dev.cjs"),r=require("../../lib/composeEventHandlers.cjs"),i=require("../../lib/classNames.cjs"),ee=require("../../hooks/useEventCallback.cjs"),a=require("../../hooks/useControllable.cjs"),te=require("../../lib/focus.cjs"),ne=require("../../hooks/useMergedRefs.cjs"),re=require("../../hooks/useFieldControl.cjs"),ie=require("../../hooks/useListbox.cjs"),o=require("../../lib/styles.cjs"),ae=require("../../lib/icons.cjs"),oe=require("./inputLook.cjs"),se=require("./Input.cjs"),ce=require("../../hooks/useFormReset.cjs"),le=require("../internal/HiddenInput.cjs"),s=require("./pickerStyles.cjs"),ue=require("./Combobox.expand.cjs"),de=require("./Combobox.text.cjs"),c=require("./Option.cjs"),l=require("./pickerLabels.cjs"),u=require("./pickerValues.cjs");let d=require("react");d=e.__toESM(d,1);let f=require("react/jsx-runtime");var p=new Set([`historyUndo`,`historyRedo`]);function fe(e,t){return(e.textValue??e.label).toLowerCase().includes(t.toLowerCase())}var m=e=>{let{multiselect:m=!1,value:pe,defaultValue:h,onValueChange:me,onOptionSelect:g,open:he,defaultOpen:ge,onOpenChange:_e,placeholder:ve,disabled:_=!1,size:ye,appearance:be,freeform:xe=!1,filter:Se,query:Ce,defaultQuery:we,onQueryChange:Te,onActiveOptionChange:Ee,disabledOptionsFocusable:De=!1,name:Oe,form:ke,required:Ae,autoComplete:je=`off`,autoCapitalize:Me,autoCorrect:Ne,maxLength:Pe,readOnly:v,clearable:Fe=!1,expandIcon:Ie,labels:y,inputMode:Le,spellCheck:Re,enterKeyHint:ze,autoFocus:Be,tabIndex:Ve,id:He,"aria-label":Ue,"aria-labelledby":We,"aria-describedby":Ge,"aria-invalid":Ke,"aria-required":qe,"aria-errormessage":Je,"aria-details":Ye,onFocus:Xe,onBlur:Ze,onKeyDown:Qe,onKeyUp:$e,controlRef:et,className:tt,children:b,ref:nt,...rt}=e;g!==void 0&&n.warnDeprecated(`Combobox`,`onOptionSelect`,`onValueChange`);let x=xe&&!m,it=xe&&m;d.useEffect(()=>{it&&n.warnOnce(`Combobox:freeform-multiselect`,"Combobox: `freeform` is not available with `multiselect`: a multi-select Combobox selects options only.")},[it]);let at=x&&(Ce!==void 0||we!==void 0);d.useEffect(()=>{at&&n.warnOnce(`Combobox:query-freeform`,"Combobox: `query` and `defaultQuery` are not used with `freeform`: the typed text is the value (`value`, `onValueChange`).")},[at]);let ot=re.useFieldContext(),st=(Ae??ot?.required??!1)&&!v,S=re.useFieldControl({id:He,"aria-label":Ue,"aria-labelledby":We,"aria-describedby":Ge,"aria-invalid":Ke,"aria-required":qe??Ae}),ct=se.isInvalidLook(!1,S[`aria-invalid`]),{size:C,appearance:w}=oe.useInputLook(ye,be),[lt,T]=a.useControllable(pe,h??(m?u.EMPTY_VALUES:``),e=>{me?.(typeof e==`string`?e:[...e])}),E=u.toValues(lt),D=m?``:lt,O=!_&&!v,[ut,k]=a.useControllable(he,(ge??!1)&&O,_e),A=ut&&O,[dt,j]=a.useControllable(x?void 0:Ce,O?we??``:``,x?void 0:Te),[ft,M]=d.useState(!1),[N,P]=d.useState(null),F=x?N:O&&(ft||dt!==``)?dt:null,[I,pt]=d.useState(O?`unlocked`:`mounted-locked`);O&&I!==`unlocked`?pt(`unlocked`):!O&&I===`unlocked`&&(pt(`locked`),M(!1),P(null)),d.useEffect(()=>{I===`locked`&&j(``)},[I,j]);let mt=!O&&ut;d.useEffect(()=>{mt&&k(!1)},[mt,k]);let[ht,L]=d.useState(null),gt=d.useRef(null),R=d.useRef(null),_t=d.useMemo(()=>ie.collectOptionLabels(b),[b]),z=F??``,vt=d.useMemo(()=>z?e=>(Se??fe)(e,z):void 0,[z,Se]),B=e=>{x?P(e):(M(!0),j(e))},V=()=>{x?P(null):(M(!1),j(``))},yt=e=>{L(e),T(e),g?.(e)},H=()=>{k(!1),V()},U;x?U=()=>{P(null),yt(``)}:F&&(U=V);let W=ie.useListbox({open:A,onOpenChange:e=>{e?k(!0):H()},mode:`editable`,multiselect:m,disabledOptionsFocusable:De,selectedValues:E,onSelect:(e,t)=>{if(!m){T(e),g?.(e),V(),L(null);return}let{values:n,added:r}=u.toggleValue(E,e);T(n),g?.(e),l.announceToggle(y,t?.item.label??_t.get(e)??e,r,n.length),V()},filter:vt,autoHighlight:!x&&F?`first`:!1,onActiveValueChange:Ee,idPrefix:`combobox-listbox`,onClearDraft:U}),bt=e=>W.getItem(e)?.label??_t.get(e),G=``;if(m){let e=E.map(bt).filter(e=>e!==void 0);e.length>0&&(G=(y?.selection??l.defaultSelectionLabel)(e))}let K=m&&F===null&&G!==``,xt=D?bt(D):void 0,q;q=m?F??G:x?D===ht?D:xt??D:F??xt??``,x&&N!==null&&N!==q&&P(q);let J=A&&W.items.length>0,St=y?.noMatches??`No matches`,Y=A&&(J||!!F),Ct=Y&&!J,{layerId:wt,setReference:Tt,surfaceRef:Et,floatingProps:Dt}=c.useListboxPopup({open:A,surfaceOpen:Y,onDismiss:H,rootRef:gt,anchorRef:R}),Ot=ne.useMergedRefs(gt,nt),kt=ne.useMergedRefs(R,et,Tt);ce.useFormReset(R,()=>{T(m?e=>u.resetValues(e,h):h??``),V(),L(null)},ke);let X=d.useRef(!1),At=e=>{X.current=K&&!te.isFocused(e.currentTarget)},jt=e=>{K&&e.currentTarget.select()},Mt=e=>{X.current&&(X.current=!1,e.preventDefault())};d.useLayoutEffect(()=>{let e=R.current;K&&e&&te.isFocused(e)&&e.select()},[K,G]);let Z=d.useRef(null),Nt=d.useRef(null),Q=ee.useEventCallback(e=>{let t=e.currentTarget;K&&t.value===G&&(Z.current=null,!p.has(e.inputType??``)&&(Nt.current=e,B(G),A||k(!0)))});d.useEffect(()=>{let e=R.current;if(!m||!e)return;let t=t=>{let{inputType:n}=t,{selectionStart:r,selectionEnd:i}=e;Z.current={inputType:n,range:n===`insertFromDrop`||p.has(n)||r===null||i===null?null:[r,i]}};return e.addEventListener(`beforeinput`,t),e.addEventListener(`input`,Q),()=>{e.removeEventListener(`beforeinput`,t),e.removeEventListener(`input`,Q)}},[m,Q]);let Pt=e=>{if(e.key===`Escape`&&A&&!Y&&!e.nativeEvent.isComposing){H(),U&&e.currentTarget.value!==``&&(e.preventDefault(),U());return}W.onKeyDown(e)},Ft=e=>{if(e.nativeEvent===Nt.current)return;let t=e.target.value,n=Z.current;Z.current=null;let r=n&&n.inputType===e.nativeEvent.inputType?n:null;if(!m)B(t);else if(t===G&&(r===null||p.has(r.inputType)))V();else if(K){let e=r?.range;B((e&&de.replacedText(G,t,e[0],e[1]))??de.insertedText(G,t))}else B(t);A||k(!0),x&&yt(t)},It=()=>{O&&(A?H():k(!0),R.current?.focus())},Lt=()=>{T(m?u.EMPTY_VALUES:``),L(null),V(),k(!1),R.current?.focus()},$=ue.showsExpandButton(Ie),Rt=Fe&&(m?E.length>0:D!==``)&&!v,zt=S[`aria-label`]===void 0?S[`aria-labelledby`]??ot?.labelId:S[`aria-labelledby`];return(0,f.jsxs)(`div`,{"data-size":C,"data-appearance":w,...rt,ref:Ot,className:t.cn(i.comboboxClassNames.root,`relative inline-flex flex-col`,tt),children:[m&&(0,f.jsx)(l.PickerAnnouncer,{}),(0,f.jsxs)(`div`,{className:`relative flex items-center`,children:[(0,f.jsx)(`input`,{type:`text`,autoComplete:je,...S,...W.getComboboxProps(),"aria-expanded":J,"aria-errormessage":Je,"aria-details":Ye,ref:kt,disabled:_,readOnly:v,placeholder:m&&G!==``?void 0:ve,autoCapitalize:Me,autoCorrect:Ne,maxLength:K?void 0:Pe,inputMode:Le,spellCheck:Re,enterKeyHint:ze,autoFocus:Be,tabIndex:Ve,value:q,onChange:Ft,onClick:()=>{!A&&O&&k(!0)},onMouseDown:At,onMouseUp:Mt,onKeyDown:r.composeEventHandlers(Qe,v?void 0:Pt),onKeyUp:r.composeEventHandlers($e,W.onKeyUp),onFocus:r.composeEventHandlers(Xe,jt),onBlur:r.composeEventHandlers(Ze,V,{checkDefaultPrevented:!1}),className:t.cn(i.comboboxClassNames.input,o.inputHeightClasses[C],`w-full`,o.inputPaddingClasses[C],o.inputTextClasses[C],o.inputAppearanceClasses[w],`text-foreground placeholder:text-muted-foreground`,o.inputFocus,o.disabledStyles,ct&&`border-destructive`,s.pickerEndPadding(Number(Rt)+Number($),C))}),Rt&&(0,f.jsx)(`button`,{type:`button`,"aria-label":y?.clear??`Clear selection`,disabled:_,onMouseDown:e=>e.preventDefault(),onClick:Lt,className:t.cn(i.comboboxClassNames.clearButton,s.pickerIconButtonClasses(C,w),s.pickerButtonOffset(C,$?2:1),`focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring`,`disabled:cursor-not-allowed disabled:opacity-50 aria-disabled:cursor-not-allowed aria-disabled:opacity-50 aria-disabled:focus-visible:opacity-100`),children:(0,f.jsx)(ae.DismissIcon,{size:s.pickerGlyphSize(C,`icon`)})}),$&&(0,f.jsx)(ue.PickerExpandButton,{component:`Combobox`,expandIcon:Ie,label:y?.expand??`Show options`,expanded:J,listboxId:W.listboxId,disabled:_||!!v,onToggle:It,size:C,appearance:w,className:i.comboboxClassNames.expandButton,iconClassName:i.comboboxClassNames.expandIcon})]}),(0,f.jsx)(`span`,{role:`status`,className:`sr-only`,children:Ct&&St}),(0,f.jsx)(c.ListboxSurface,{listbox:W,layerId:wt,surfaceRef:Et,floatingProps:Dt,open:A,expanded:J,listClassName:i.comboboxClassNames.listbox,surfaceClassName:i.comboboxClassNames.surface,emptyContent:F?(0,f.jsx)(`div`,{"aria-hidden":`true`,className:t.cn(i.comboboxClassNames.emptyMessage,`px-3 py-1.5 text-body-1 text-muted-foreground`),children:St}):void 0,"aria-label":S[`aria-label`],"aria-labelledby":zt,children:b}),(0,f.jsx)(le.HiddenInput,{name:Oe,form:ke,disabled:_,value:m?E:D,type:`text`,required:st,onInvalid:()=>R.current?.focus()})]})};m.displayName=`Combobox`;var pe=c.Option,h=c.OptionGroup,me=Object.assign(m,{Option:c.Option,OptionGroup:c.OptionGroup});exports.Combobox=me,exports.ComboboxOption=pe,exports.ComboboxOptionGroup=h,exports.Option=c.Option,exports.OptionGroup=c.OptionGroup;
|
|
2
2
|
//# sourceMappingURL=Combobox.cjs.map
|