@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.
Files changed (105) hide show
  1. package/README.md +425 -104
  2. package/dist/components/input/Calendar.cjs +2 -0
  3. package/dist/components/input/Calendar.cjs.map +1 -0
  4. package/dist/components/input/Calendar.mjs +352 -0
  5. package/dist/components/input/Calendar.mjs.map +1 -0
  6. package/dist/components/input/Calendar.views.cjs +2 -0
  7. package/dist/components/input/Calendar.views.cjs.map +1 -0
  8. package/dist/components/input/Calendar.views.mjs +194 -0
  9. package/dist/components/input/Calendar.views.mjs.map +1 -0
  10. package/dist/components/input/ColorArea.cjs +1 -1
  11. package/dist/components/input/ColorArea.cjs.map +1 -1
  12. package/dist/components/input/ColorArea.mjs +18 -18
  13. package/dist/components/input/ColorArea.mjs.map +1 -1
  14. package/dist/components/input/Combobox.cjs +1 -1
  15. package/dist/components/input/Combobox.cjs.map +1 -1
  16. package/dist/components/input/Combobox.mjs +232 -156
  17. package/dist/components/input/Combobox.mjs.map +1 -1
  18. package/dist/components/input/Combobox.text.cjs +2 -0
  19. package/dist/components/input/Combobox.text.cjs.map +1 -0
  20. package/dist/components/input/Combobox.text.mjs +24 -0
  21. package/dist/components/input/Combobox.text.mjs.map +1 -0
  22. package/dist/components/input/DatePicker.cjs +1 -1
  23. package/dist/components/input/DatePicker.cjs.map +1 -1
  24. package/dist/components/input/DatePicker.mjs +203 -288
  25. package/dist/components/input/DatePicker.mjs.map +1 -1
  26. package/dist/components/input/Dropdown.cjs +1 -1
  27. package/dist/components/input/Dropdown.cjs.map +1 -1
  28. package/dist/components/input/Dropdown.mjs +135 -109
  29. package/dist/components/input/Dropdown.mjs.map +1 -1
  30. package/dist/components/input/Listbox.cjs +2 -0
  31. package/dist/components/input/Listbox.cjs.map +1 -0
  32. package/dist/components/input/Listbox.mjs +134 -0
  33. package/dist/components/input/Listbox.mjs.map +1 -0
  34. package/dist/components/input/Option.cjs +1 -1
  35. package/dist/components/input/Option.cjs.map +1 -1
  36. package/dist/components/input/Option.mjs +158 -97
  37. package/dist/components/input/Option.mjs.map +1 -1
  38. package/dist/components/input/SwatchPicker.cjs +1 -1
  39. package/dist/components/input/SwatchPicker.cjs.map +1 -1
  40. package/dist/components/input/SwatchPicker.context.cjs +2 -0
  41. package/dist/components/input/SwatchPicker.context.cjs.map +1 -0
  42. package/dist/components/input/SwatchPicker.context.mjs +35 -0
  43. package/dist/components/input/SwatchPicker.context.mjs.map +1 -0
  44. package/dist/components/input/SwatchPicker.mjs +131 -103
  45. package/dist/components/input/SwatchPicker.mjs.map +1 -1
  46. package/dist/components/input/SwatchPicker.swatches.cjs +2 -0
  47. package/dist/components/input/SwatchPicker.swatches.cjs.map +1 -0
  48. package/dist/components/input/SwatchPicker.swatches.mjs +207 -0
  49. package/dist/components/input/SwatchPicker.swatches.mjs.map +1 -0
  50. package/dist/components/input/TagPicker.cjs +1 -1
  51. package/dist/components/input/TagPicker.cjs.map +1 -1
  52. package/dist/components/input/TagPicker.mjs +144 -139
  53. package/dist/components/input/TagPicker.mjs.map +1 -1
  54. package/dist/components/input/TimePicker.cjs +1 -1
  55. package/dist/components/input/TimePicker.cjs.map +1 -1
  56. package/dist/components/input/TimePicker.mjs +77 -77
  57. package/dist/components/input/TimePicker.mjs.map +1 -1
  58. package/dist/components/input/dateUtils.cjs +1 -1
  59. package/dist/components/input/dateUtils.cjs.map +1 -1
  60. package/dist/components/input/dateUtils.mjs +114 -96
  61. package/dist/components/input/dateUtils.mjs.map +1 -1
  62. package/dist/components/input/pickerLabels.cjs +2 -0
  63. package/dist/components/input/pickerLabels.cjs.map +1 -0
  64. package/dist/components/input/pickerLabels.mjs +16 -0
  65. package/dist/components/input/pickerLabels.mjs.map +1 -0
  66. package/dist/components/input/pickerValues.cjs +2 -0
  67. package/dist/components/input/pickerValues.cjs.map +1 -0
  68. package/dist/components/input/pickerValues.mjs +24 -0
  69. package/dist/components/input/pickerValues.mjs.map +1 -0
  70. package/dist/components/table/useGridNavigation.cjs +1 -1
  71. package/dist/components/table/useGridNavigation.cjs.map +1 -1
  72. package/dist/components/table/useGridNavigation.mjs +67 -70
  73. package/dist/components/table/useGridNavigation.mjs.map +1 -1
  74. package/dist/hooks/useActiveDescendant.cjs +2 -0
  75. package/dist/hooks/useActiveDescendant.cjs.map +1 -0
  76. package/dist/hooks/useActiveDescendant.mjs +56 -0
  77. package/dist/hooks/useActiveDescendant.mjs.map +1 -0
  78. package/dist/hooks/useListbox.cjs +1 -1
  79. package/dist/hooks/useListbox.cjs.map +1 -1
  80. package/dist/hooks/useListbox.mjs +250 -210
  81. package/dist/hooks/useListbox.mjs.map +1 -1
  82. package/dist/hooks/useRovingGrid.cjs +2 -0
  83. package/dist/hooks/useRovingGrid.cjs.map +1 -0
  84. package/dist/hooks/useRovingGrid.mjs +69 -0
  85. package/dist/hooks/useRovingGrid.mjs.map +1 -0
  86. package/dist/index.cjs +1 -1
  87. package/dist/index.d.cts +2147 -155
  88. package/dist/index.d.ts +2147 -155
  89. package/dist/index.mjs +107 -101
  90. package/dist/lib/classNames.cjs +1 -1
  91. package/dist/lib/classNames.cjs.map +1 -1
  92. package/dist/lib/classNames.mjs +84 -48
  93. package/dist/lib/classNames.mjs.map +1 -1
  94. package/dist/lib/date.cjs +2 -0
  95. package/dist/lib/date.cjs.map +1 -0
  96. package/dist/lib/date.mjs +44 -0
  97. package/dist/lib/date.mjs.map +1 -0
  98. package/dist/lib/focus.cjs +1 -1
  99. package/dist/lib/focus.cjs.map +1 -1
  100. package/dist/lib/focus.mjs +5 -2
  101. package/dist/lib/focus.mjs.map +1 -1
  102. package/dist/lib/layers.cjs.map +1 -1
  103. package/dist/lib/layers.mjs.map +1 -1
  104. package/dist/styles.css +1 -1
  105. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"SwatchPicker.cjs","names":["getCheckColors","CheckIcon","useControllable","useRovingTabIndex","React","useMergedRefs","useFieldContext","useFieldControl","cn","swatchPickerClassNames","composeEventHandlers","motionSafeTransition","forcedColors","focusRing","HiddenInput","require_runtime","require_cn","require_dev","require_composeEventHandlers","require_classNames","require_useControllable","require_useRovingTabIndex","require_useMergedRefs","require_useFieldControl","require_styles","require_icons","require_useFormReset","require_HiddenInput","require_colorUtils","react","react_jsx_runtime","sizeMap","checkSizeMap","shapeMap","SwatchCheck","color","halo","glyph","SwatchPicker","valueProp","ariaLabel","ariaLabelledBy","ariaDescribedBy","ariaInvalid","ariaRequired","rest","onChange","initialValue","defaultValue","value","setValue","onValueChange","next","rootRef","mergedRef","ref","containerProps","field","fieldProps","required","isRequired","unnamed","unlabelledItem","items","item","form","focusTabStop","className","onKeyDown","onFocus","isSelected","getTabIndex","size","shape"],"sources":["../../../src/components/input/SwatchPicker.tsx"],"sourcesContent":["import * as React from 'react';\nimport { swatchPickerClassNames } from '../../lib/classNames';\nimport { cn } from '../../lib/cn';\nimport { composeEventHandlers } from '../../lib/composeEventHandlers';\nimport { warnDeprecated, warnOnce } from '../../lib/dev';\nimport { CheckIcon } from '../../lib/icons';\nimport { focusRing, forcedColors, motionSafeTransition } from '../../lib/styles';\nimport type { Shape, Size } from '../../lib/types';\nimport { useControllable } from '../../hooks/useControllable';\nimport { useFieldContext, useFieldControl } from '../../hooks/useFieldControl';\nimport { useFormReset } from '../../hooks/useFormReset';\nimport { useMergedRefs } from '../../hooks/useMergedRefs';\nimport { useRovingTabIndex } from '../../hooks/useRovingTabIndex';\nimport { HiddenInput } from '../internal/HiddenInput';\nimport { getCheckColors } from './colorUtils';\n\n/** Represents a single color swatch option. */\nexport interface SwatchItem {\n /** Unique identifier for the swatch (the value `onValueChange` reports and a form submits). */\n value: string;\n /** CSS color value (e.g., hex, rgb) used as the swatch background. */\n color: string;\n /**\n * Accessible name of the swatch, e.g. `'Cranberry'`. **Required for accessibility**: without it\n * the swatch is announced by its raw color value (`'#d13438'`) and a development warning is\n * logged.\n */\n label?: string;\n}\n\n/** Size of the swatches. */\nexport type SwatchPickerSize = Extract<Size, 'small' | 'medium' | 'large'>;\n\n/** Properties for the SwatchPicker component. */\nexport interface SwatchPickerProps extends Omit<\n React.HTMLAttributes<HTMLDivElement>,\n 'onChange' | 'defaultValue'\n> {\n /** The swatches to display, in order (a readonly array is accepted; it is never modified). */\n items: readonly SwatchItem[];\n /** Controlled selected swatch value (`''` = nothing selected). */\n value?: string;\n /** Initial selected value for uncontrolled usage (also what a form reset restores).\n * @default ''\n */\n defaultValue?: string;\n /** Called with the new value when the selection changes (not when the selected swatch is chosen again). */\n onValueChange?: (value: string) => void;\n /**\n * Called with the new value when the selection changes.\n * @deprecated Use `onValueChange`.\n */\n onChange?: (value: string) => void;\n /** Size of each swatch button (24, 32 or 40px).\n * @default 'medium'\n */\n size?: SwatchPickerSize;\n /** Shape of each swatch button.\n * @default 'circular'\n */\n shape?: Shape;\n /**\n * Form field name. With a name, the selected swatch's `value` is submitted with the form\n * (nothing while no swatch is selected).\n */\n name?: string;\n /** A swatch must be selected before the form can be submitted (native validation). */\n required?: boolean;\n /** Id of the form the picker belongs to, when it is rendered outside that form. */\n form?: string;\n /** Ref to the `role=\"radiogroup\"` element. */\n ref?: React.Ref<HTMLDivElement>;\n}\n\nconst sizeMap: Record<SwatchPickerSize, string> = {\n small: 'w-6 h-6',\n medium: 'w-8 h-8',\n large: 'w-10 h-10',\n};\n\nconst checkSizeMap: Record<SwatchPickerSize, number> = {\n small: 12,\n medium: 16,\n large: 20,\n};\n\nconst shapeMap: Record<Shape, string> = {\n circular: 'rounded-full',\n square: 'rounded-none',\n rounded: 'rounded',\n};\n\n/**\n * The check glyph of the selected swatch: black or white by the swatch's luminance, drawn over a\n * halo in the other color so it stays visible on any swatch (C-TOKENS exception for\n * user-supplied colors, `input-pickers#16`).\n */\nfunction SwatchCheck({ color, size }: { color: string; size: number }) {\n const { glyph, halo } = getCheckColors(color);\n return (\n <span aria-hidden=\"true\" className=\"pointer-events-none grid\">\n <CheckIcon\n size={size}\n strokeWidth={4}\n className=\"col-start-1 row-start-1\"\n style={{ color: halo }}\n />\n <CheckIcon\n size={size}\n strokeWidth={2}\n className=\"col-start-1 row-start-1\"\n style={{ color: glyph }}\n />\n </span>\n );\n}\n\n/**\n * A single-select grid of color swatches (`role=\"radiogroup\"` of `role=\"radio\"` buttons).\n *\n * - **Keyboard** (APG radio group): one tab stop — the selected swatch, else the first. All four\n * arrow keys move focus and select (Left/Right mirrored under `dir=\"rtl\"`), wrapping at the\n * ends; Home/End jump to the first/last swatch.\n * - **Selected indicator**: an offset ring in the foreground color (drawn on the page background,\n * not on the swatch) plus a check glyph whose color is picked by the swatch's luminance, so the\n * selection never relies on color alone.\n * - **Naming**: give the group a name with `aria-label`/`aria-labelledby` or render it inside a\n * `Field`, and give every item a `label`; both are reported in development when missing.\n * - **Forms**: with `name` (or `required`) it takes part in native forms; a form reset restores\n * `defaultValue`.\n *\n * @example\n * <SwatchPicker aria-label=\"Accent color\" items={[{ value: 'red', color: '#d13438', label: 'Red' }]} />\n */\nexport const SwatchPicker = ({\n items,\n value: valueProp,\n defaultValue,\n onValueChange,\n onChange,\n size = 'medium',\n shape = 'circular',\n name,\n required,\n form,\n className,\n id,\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledBy,\n 'aria-describedby': ariaDescribedBy,\n 'aria-invalid': ariaInvalid,\n 'aria-required': ariaRequired,\n onKeyDown,\n onFocus,\n ref,\n ...rest\n}: SwatchPickerProps) => {\n if (onChange !== undefined) warnDeprecated('SwatchPicker', 'onChange', 'onValueChange');\n const initialValue = defaultValue ?? '';\n const [value, setValue] = useControllable(valueProp, initialValue, (next: string) => {\n onValueChange?.(next);\n onChange?.(next);\n });\n\n const { containerProps, getTabIndex } = useRovingTabIndex({\n activeValue: value || null,\n orientation: 'both',\n // APG radio group: moving focus also selects.\n onFocusMove: (next) => setValue(next),\n });\n\n const rootRef = React.useRef<HTMLDivElement>(null);\n const mergedRef = useMergedRefs<HTMLDivElement>(ref, containerProps.ref, rootRef);\n\n const field = useFieldContext();\n const fieldProps = useFieldControl(\n {\n id,\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledBy,\n 'aria-describedby': ariaDescribedBy,\n 'aria-invalid': ariaInvalid,\n // An explicit `required={false}` wins over a required Field, so aria-required matches\n // `isRequired`.\n 'aria-required': ariaRequired ?? required,\n },\n { labelable: false },\n );\n const isRequired = required ?? field?.required ?? false;\n\n const unnamed =\n fieldProps['aria-label'] === undefined && fieldProps['aria-labelledby'] === undefined;\n const unlabelledItem = items.find((item) => !item.label)?.value;\n React.useEffect(() => {\n if (unnamed) {\n warnOnce(\n 'SwatchPicker:unnamed',\n 'SwatchPicker: the radiogroup has no accessible name. Pass `aria-label` or `aria-labelledby`, or render it inside a Field.',\n );\n }\n }, [unnamed]);\n React.useEffect(() => {\n if (unlabelledItem !== undefined) {\n warnOnce(\n 'SwatchPicker:item-label',\n `SwatchPicker: swatch \"${unlabelledItem}\" has no \\`label\\`, so it is announced by its color value. Give every item a \\`label\\`.`,\n );\n }\n }, [unlabelledItem]);\n\n useFormReset(rootRef, () => setValue(initialValue), form);\n\n const focusTabStop = () => {\n rootRef.current?.querySelector<HTMLElement>('[data-roving-value][tabindex=\"0\"]')?.focus();\n };\n\n return (\n <div\n role=\"radiogroup\"\n {...fieldProps}\n className={cn(swatchPickerClassNames.root, 'relative flex flex-wrap gap-2', className)}\n {...rest}\n ref={mergedRef}\n data-roving-container=\"\"\n onKeyDown={composeEventHandlers(onKeyDown, containerProps.onKeyDown)}\n onFocus={composeEventHandlers(onFocus, containerProps.onFocus, {\n checkDefaultPrevented: false,\n })}\n >\n {items.map((item) => {\n const isSelected = value === item.value;\n return (\n <button\n key={item.value}\n type=\"button\"\n role=\"radio\"\n aria-checked={isSelected}\n aria-label={item.label || item.color}\n data-roving-value={item.value}\n data-selected={isSelected ? '' : undefined}\n tabIndex={getTabIndex(item.value)}\n onClick={() => setValue(item.value)}\n className={cn(\n swatchPickerClassNames.swatch,\n sizeMap[size],\n shapeMap[shape],\n // The padding is set here (C-NATIVE); the swatch color is its background.\n 'relative flex shrink-0 items-center justify-center border-2 border-transparent p-0',\n motionSafeTransition,\n // User colors are the content: keep them (and the check glyph) in forced colors.\n 'forced-colors:forced-color-adjust-none',\n forcedColors.border,\n focusRing,\n // Outside the selection ring, so both stay visible together.\n 'focus-visible:outline-offset-4',\n isSelected\n ? 'ring-2 ring-foreground ring-offset-2 ring-offset-background'\n : 'hover:border-stroke-hover',\n )}\n style={{ backgroundColor: item.color }}\n >\n {isSelected && <SwatchCheck color={item.color} size={checkSizeMap[size]} />}\n </button>\n );\n })}\n <HiddenInput\n type=\"radio\"\n name={name}\n form={form}\n value={value}\n required={isRequired}\n onInvalid={focusTabStop}\n />\n </div>\n );\n};\n\nSwatchPicker.displayName = 'SwatchPicker';\n"],"mappings":"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"}
1
+ {"version":3,"file":"SwatchPicker.cjs","names":["React","useSwatchPickerContext","cn","swatchPickerRowClassNames","flattenChildren","isElementOfType","useControllable","useRovingTabIndex","useRovingGrid","useMergedRefs","useFieldContext","useFieldControl","useId","useSwatchRegistry","ColorSwatch","joinIds","swatchPickerClassNames","composeEventHandlers","SwatchPickerContext","_Fragment","HiddenInput","require_runtime","require_cn","require_children","require_dev","require_composeEventHandlers","require_classNames","require_useControllable","require_useId","require_useRovingTabIndex","require_useMergedRefs","require_aria","require_useFieldControl","require_useFormReset","require_HiddenInput","require_useRovingGrid","require_SwatchPicker_context","require_SwatchPicker_swatches","react","react_jsx_runtime","swatchGap","spacing","tabStop","SwatchRowContext","SwatchPickerRow","rest","nested","isGridRow","layout","focusMode","className","gridRows","rows","pending","pendingKey","itemSwatches","flush","children","node","key","SwatchPickerRoot","valueProp","ariaLabel","ariaLabelledBy","ariaDescribedBy","ariaInvalid","ariaRequired","onChange","initialValue","defaultValue","value","setValue","onValueChange","next","isTab","isGrid","isArrowGrid","radio","grid","rovingTabIndex","getTabIndex","rootRef","mergedRef","ref","containerProps","field","fieldAriaRequired","fieldDescribedBy","fieldProps","required","isRequired","role","requiredHintId","showRequiredHint","unnamed","unlabelledItem","items","item","form","focusTabStop","register","contextValue","size","shape","onKeyDown","event","onFocus","labels","SwatchPicker"],"sources":["../../../src/components/input/SwatchPicker.tsx"],"sourcesContent":["import * as React from 'react';\nimport { swatchPickerClassNames, swatchPickerRowClassNames } from '../../lib/classNames';\nimport { cn } from '../../lib/cn';\nimport { composeEventHandlers } from '../../lib/composeEventHandlers';\nimport { joinIds } from '../../lib/aria';\nimport { flattenChildren, isElementOfType } from '../../lib/children';\nimport { warnDeprecated, warnOnce } from '../../lib/dev';\nimport type { Shape } from '../../lib/types';\nimport { useControllable } from '../../hooks/useControllable';\nimport { useFieldContext, useFieldControl } from '../../hooks/useFieldControl';\nimport { useFormReset } from '../../hooks/useFormReset';\nimport { useId } from '../../hooks/useId';\nimport { useMergedRefs } from '../../hooks/useMergedRefs';\nimport { useRovingGrid } from '../../hooks/useRovingGrid';\nimport { useRovingTabIndex } from '../../hooks/useRovingTabIndex';\nimport { HiddenInput } from '../internal/HiddenInput';\nimport {\n SwatchPickerContext,\n useSwatchPickerContext,\n useSwatchRegistry,\n type SwatchPickerContextValue,\n type SwatchPickerSize,\n} from './SwatchPicker.context';\nimport { ColorSwatch } from './SwatchPicker.swatches';\n\nexport type { SwatchPickerSize } from './SwatchPicker.context';\n\n/** Represents a single color swatch option. */\nexport interface SwatchItem {\n /** Unique identifier for the swatch (the value `onValueChange` reports and a form submits). */\n value: string;\n /** CSS color value (e.g., hex, rgb) used as the swatch background. */\n color: string;\n /**\n * Accessible name of the swatch, e.g. `'Cranberry'`. **Required for accessibility**: without it\n * the swatch is announced by its raw color value (`'#d13438'`) and a development warning is\n * logged.\n */\n label?: string;\n}\n\n/** Built-in strings of the SwatchPicker component (C-NAMING). */\nexport interface SwatchPickerLabels {\n /**\n * Said where the picker's role cannot carry `aria-required` (the grid layout, and the group of\n * `focusMode=\"tab\"`): a hidden text\n * joined into the picker's description while it is required.\n * @default 'Required'\n */\n required?: string;\n}\n\n/** Properties for the SwatchPicker component. */\nexport interface SwatchPickerProps extends Omit<\n React.HTMLAttributes<HTMLDivElement>,\n 'onChange' | 'defaultValue'\n> {\n /**\n * The swatches to display, in order (a readonly array is accepted; it is never modified):\n * rendered as `ColorSwatch` elements, before `children`.\n */\n items?: readonly SwatchItem[];\n /** Controlled selected swatch value (`''` = nothing selected). */\n value?: string;\n /** Initial selected value for uncontrolled usage (also what a form reset restores).\n * @default ''\n */\n defaultValue?: string;\n /** Called with the new value when the selection changes (not when the selected swatch is chosen again). */\n onValueChange?: (value: string) => void;\n /**\n * Called with the new value when the selection changes.\n * @deprecated Use `onValueChange`.\n */\n onChange?: (value: string) => void;\n // D18: an explicit C-ROUTING exception — a swatch's own ref/className/style/rest land on its\n // button, so a wrapping element's props reach the element that has focus.\n /**\n * Swatches rendered directly, in order, after `items` (e.g. `ColorSwatch`): read the picker's\n * context, so they may be wrapped in a `Tooltip` or another element that forwards its own props.\n * `SwatchPicker.Row` elements start rows; in the grid layout every run of other children (and\n * `items`, with the children that follow them) renders in a row of its own. A `SwatchPicker.Row`\n * must be a direct child or inside a Fragment: a wrapper component around a Row lands in an\n * implicit row, and nested rows are reported in development.\n */\n children?: React.ReactNode;\n /**\n * `'row'`: a radio group whose arrow keys select (and wrap). `'grid'`: rows of cells\n * (`SwatchPicker.Row`) whose arrow keys move focus in two dimensions without selecting; Space,\n * Enter and a click select. Changing it while mounted remounts the swatches, so focus falls\n * back to the page.\n * @default 'row'\n */\n layout?: 'row' | 'grid';\n /**\n * `'arrow'`: one tab stop and arrow keys, with the radio group (row layout) or grid (grid\n * layout) semantics. `'tab'`: every enabled swatch is its own tab stop and the arrow keys do\n * nothing, so the picker is a `role=\"group\"` of toggle buttons (`aria-pressed`, the selected\n * one pressed) in both layouts; rows have no role, and Space, Enter and a click select\n * (pressing the selected swatch again keeps it selected). The required hint (`labels.required`)\n * applies, as the group cannot carry `aria-required`.\n * @default 'arrow'\n */\n focusMode?: 'arrow' | 'tab';\n /** Built-in strings, for localization. */\n labels?: SwatchPickerLabels;\n /** Size of each swatch button (20, 24, 32 or 40px). A 20px swatch passes the target-size bar\n * through its spacing; a swatch's own `size` overrides this.\n * @default 'medium'\n */\n size?: SwatchPickerSize;\n /** Gap between swatches (and between rows): 4px or 8px. At `'small'` the focus outline's offset shrinks from 4px to\n * 2px, so it does not cover the neighbour.\n * @default 'medium'\n */\n spacing?: 'small' | 'medium';\n /** Shape of each swatch button (a swatch's own `shape` overrides this).\n * @default 'circular'\n */\n shape?: Shape;\n /**\n * Form field name. With a name, the selected swatch's `value` is submitted with the form\n * (nothing while no swatch is selected).\n */\n name?: string;\n /**\n * A swatch must be selected before the form can be submitted (native validation). The row\n * layout says so with `aria-required`; the grid layout and tab mode, whose roles do not allow\n * it, with the hidden `labels.required` text in the description (which a consumer\n * `aria-required` alone also shows).\n */\n required?: boolean;\n /** Id of the form the picker belongs to, when it is rendered outside that form. */\n form?: string;\n /**\n * Ref to the root element: `role=\"radiogroup\"`, `role=\"grid\"` in the grid layout, or\n * `role=\"group\"` in tab mode.\n */\n ref?: React.Ref<HTMLDivElement>;\n}\n\n/** Properties for the SwatchPicker.Row component. */\nexport interface SwatchPickerRowProps extends React.HTMLAttributes<HTMLDivElement> {\n /** Ref to the row element. */\n ref?: React.Ref<HTMLDivElement>;\n}\n\n/** The gap class the root and the rows share. */\nfunction swatchGap(spacing: 'small' | 'medium'): string {\n return spacing === 'small' ? 'gap-1' : 'gap-2';\n}\n\n/** Tab mode: every swatch is a tab stop. */\nconst tabStop = (): 0 => 0;\n\n/** True inside a `SwatchPicker.Row`: a second Row there is reported. */\nconst SwatchRowContext = React.createContext(false);\n\n/**\n * One row of swatches in a `SwatchPicker` (also exported as the flat `SwatchPickerRow`, for React\n * Server Components). In the grid layout it is a `role=\"row\"` element whose swatches are its\n * cells; Up and Down move between rows, and the row does not wrap (a wrapped swatch would sit\n * where Up and Down do not reach it): size it yourself. In the row layout and in tab mode\n * (`focusMode=\"tab\"`) it is a full-width line without a role, and its swatches stay radios of the\n * one group (row layout) or toggle buttons. Place it as a direct child of the `SwatchPicker` or\n * inside a Fragment: a wrapper component around a Row lands in an implicit row, and a Row inside\n * a Row is reported in development. Outside a `SwatchPicker` it throws in development.\n *\n * @example\n * <SwatchPicker layout=\"grid\" aria-label=\"Accent color\">\n * <SwatchPicker.Row>\n * <ColorSwatch value=\"red\" color=\"#d13438\" aria-label=\"Red\" />\n * <ColorSwatch value=\"blue\" color=\"#0f6cbd\" aria-label=\"Blue\" />\n * </SwatchPicker.Row>\n * </SwatchPicker>\n */\nexport const SwatchPickerRow = ({ className, ref, ...rest }: SwatchPickerRowProps) => {\n const { layout, focusMode, spacing } = useSwatchPickerContext('SwatchPicker.Row');\n const nested = React.useContext(SwatchRowContext);\n React.useEffect(() => {\n if (nested) {\n warnOnce(\n 'SwatchPicker.Row:nested',\n 'SwatchPicker.Row: a Row inside a Row nests rows. Rows must be direct children of the ' +\n 'SwatchPicker (or inside a Fragment); a wrapper component around a Row lands in an ' +\n 'implicit row.',\n );\n }\n }, [nested]);\n const isGridRow = layout === 'grid' && focusMode === 'arrow';\n return (\n <SwatchRowContext.Provider value>\n <div\n role={isGridRow ? 'row' : undefined}\n {...rest}\n ref={ref}\n className={cn(\n swatchPickerRowClassNames.root,\n // The grid's rows never wrap: Up and Down would not reach a wrapped swatch. Tab mode\n // has no arrow keys, so its rows wrap like the row layout's.\n isGridRow ? 'flex' : 'flex basis-full flex-wrap',\n swatchGap(spacing),\n className,\n )}\n />\n </SwatchRowContext.Provider>\n );\n};\nSwatchPickerRow.displayName = 'SwatchPickerRow';\n\n/**\n * The grid layout's rows: `SwatchPicker.Row` elements as they are, and `items` with every run of\n * other children (Fragments flattened) wrapped in an implicit row, so no cell sits outside a row.\n */\nfunction gridRows(\n itemSwatches: readonly React.ReactNode[] | undefined,\n children: React.ReactNode,\n): React.ReactNode[] {\n const rows: React.ReactNode[] = [];\n // Keys: an implicit row is keyed by its first node, so adding a row elsewhere keeps its\n // swatches mounted (and focused). Flattened keys start with a dot: no clash with `items`.\n let pending: React.ReactNode[] = [];\n let pendingKey = 'items';\n if (itemSwatches && itemSwatches.length > 0) {\n pending.push(<React.Fragment key=\"items\">{itemSwatches}</React.Fragment>);\n }\n const flush = () => {\n if (pending.length > 0) {\n rows.push(<SwatchPickerRow key={`implicit:${pendingKey}`}>{pending}</SwatchPickerRow>);\n }\n pending = [];\n };\n for (const { key, node } of flattenChildren(children)) {\n if (isElementOfType(node, SwatchPickerRow)) {\n flush();\n rows.push(<React.Fragment key={key}>{node}</React.Fragment>);\n } else {\n if (pending.length === 0) pendingKey = key;\n pending.push(<React.Fragment key={key}>{node}</React.Fragment>);\n }\n }\n flush();\n return rows;\n}\n\n// The root, documented on the exported `SwatchPicker` const.\nconst SwatchPickerRoot = ({\n items,\n value: valueProp,\n defaultValue,\n onValueChange,\n onChange,\n children,\n layout = 'row',\n focusMode = 'arrow',\n labels,\n size = 'medium',\n shape = 'circular',\n spacing = 'medium',\n name,\n required,\n form,\n className,\n id,\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledBy,\n 'aria-describedby': ariaDescribedBy,\n 'aria-invalid': ariaInvalid,\n 'aria-required': ariaRequired,\n onKeyDown,\n onFocus,\n ref,\n ...rest\n}: SwatchPickerProps) => {\n if (onChange !== undefined) warnDeprecated('SwatchPicker', 'onChange', 'onValueChange');\n const initialValue = defaultValue ?? '';\n const [value, setValue] = useControllable(valueProp, initialValue, (next: string) => {\n onValueChange?.(next);\n onChange?.(next);\n });\n const isTab = focusMode === 'tab';\n // The grid layout's rows are visual in tab mode: the grid keys and roles belong to arrow mode.\n const isGrid = layout === 'grid';\n const isArrowGrid = isGrid && !isTab;\n\n // Both hooks run on every render (hook order); only the layout's own one gets the container,\n // and tab mode none (every swatch is a tab stop, the arrow keys do nothing).\n const radio = useRovingTabIndex({\n activeValue: value || null,\n orientation: 'both',\n // APG radio group: moving focus also selects.\n onFocusMove: (next) => setValue(next),\n });\n // APG grid: the arrow keys move focus only; a swatch's own click (Space, Enter) selects.\n const grid = useRovingGrid({ activeValue: value || null });\n const { containerProps, getTabIndex: rovingTabIndex } = isArrowGrid ? grid : radio;\n const getTabIndex = isTab ? tabStop : rovingTabIndex;\n\n const rootRef = React.useRef<HTMLDivElement>(null);\n const mergedRef = useMergedRefs<HTMLDivElement>(ref, isTab ? null : containerProps.ref, rootRef);\n\n const field = useFieldContext();\n const {\n 'aria-required': fieldAriaRequired,\n 'aria-describedby': fieldDescribedBy,\n ...fieldProps\n } = useFieldControl(\n {\n id,\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledBy,\n 'aria-describedby': ariaDescribedBy,\n 'aria-invalid': ariaInvalid,\n // An explicit `required={false}` wins over a required Field, so aria-required matches\n // `isRequired`.\n 'aria-required': ariaRequired ?? required,\n },\n { labelable: false },\n );\n const isRequired = required ?? field?.required ?? false;\n const role = isTab ? 'group' : isGrid ? 'grid' : 'radiogroup';\n // Only `radiogroup` allows aria-required (a consumer's included): the description of a `grid`\n // or `group` says it instead.\n const requiredHintId = useId('wave-swatch-picker-required');\n const showRequiredHint =\n role !== 'radiogroup' &&\n fieldAriaRequired !== undefined &&\n String(fieldAriaRequired) !== 'false';\n\n const unnamed =\n fieldProps['aria-label'] === undefined && fieldProps['aria-labelledby'] === undefined;\n const unlabelledItem = items?.find((item) => !item.label)?.value;\n React.useEffect(() => {\n if (unnamed) {\n warnOnce(\n 'SwatchPicker:unnamed',\n `SwatchPicker: the ${role} has no accessible name. Pass \\`aria-label\\` or \\`aria-labelledby\\`, or render it inside a Field.`,\n );\n }\n }, [unnamed, role]);\n React.useEffect(() => {\n if (unlabelledItem !== undefined) {\n warnOnce(\n 'SwatchPicker:item-label',\n `SwatchPicker: swatch \"${unlabelledItem}\" has no \\`label\\`, so it is announced by its color value. Give every item a \\`label\\`.`,\n );\n }\n }, [unlabelledItem]);\n\n useFormReset(rootRef, () => setValue(initialValue), form);\n\n const focusTabStop = () => {\n rootRef.current?.querySelector<HTMLElement>('[data-roving-value][tabindex=\"0\"]')?.focus();\n };\n\n const register = useSwatchRegistry();\n const contextValue = React.useMemo<SwatchPickerContextValue>(\n () => ({\n value,\n select: setValue,\n size,\n shape,\n layout,\n focusMode,\n spacing,\n getTabIndex,\n register,\n }),\n [value, setValue, size, shape, layout, focusMode, spacing, getTabIndex, register],\n );\n\n const itemSwatches = items?.map((item) => (\n <ColorSwatch\n key={item.value}\n value={item.value}\n color={item.color}\n aria-label={item.label || item.color}\n />\n ));\n\n return (\n <div\n role={role}\n {...fieldProps}\n aria-required={role === 'radiogroup' ? fieldAriaRequired : undefined}\n aria-describedby={joinIds(fieldDescribedBy, showRequiredHint && requiredHintId)}\n data-layout={layout}\n data-focus-mode={focusMode}\n data-size={size}\n data-shape={shape}\n data-spacing={spacing}\n className={cn(\n swatchPickerClassNames.root,\n isGrid ? 'relative flex flex-col' : 'relative flex flex-wrap',\n swatchGap(spacing),\n className,\n )}\n {...rest}\n ref={mergedRef}\n data-roving-container={isTab ? undefined : ''}\n onKeyDown={composeEventHandlers(onKeyDown, (event: React.KeyboardEvent<HTMLDivElement>) => {\n // Tab mode has no arrow handling. An EmptySwatch is no radio: arrow keys pressed on it\n // would otherwise move to and select one. In the grid layout it is a cell like the others.\n if (isTab) return;\n if (!isGrid && (event.target as HTMLElement).hasAttribute?.('data-wave-empty-swatch')) {\n return;\n }\n containerProps.onKeyDown(event);\n })}\n onFocus={composeEventHandlers(onFocus, isTab ? undefined : containerProps.onFocus, {\n checkDefaultPrevented: false,\n })}\n >\n <SwatchPickerContext.Provider value={contextValue}>\n {isGrid ? (\n gridRows(itemSwatches, children)\n ) : (\n <>\n {itemSwatches}\n {children}\n </>\n )}\n </SwatchPickerContext.Provider>\n {showRequiredHint && (\n <span id={requiredHintId} hidden>\n {labels?.required ?? 'Required'}\n </span>\n )}\n <HiddenInput\n type=\"radio\"\n name={name}\n form={form}\n value={value}\n required={isRequired}\n onInvalid={focusTabStop}\n />\n </div>\n );\n};\nSwatchPickerRoot.displayName = 'SwatchPicker';\n\n/**\n * A single-select set of color swatches: a radio group (the default row layout) or a grid of rows\n * (`layout=\"grid\"`).\n *\n * - **Row layout** (APG radio group, `role=\"radiogroup\"` of `role=\"radio\"` buttons): one tab stop,\n * the selected swatch, else the first. All four arrow keys move focus and select (Left/Right\n * mirrored under `dir=\"rtl\"`), wrapping at the ends; Home/End jump to the first/last swatch.\n * - **Grid layout** (APG grid, `role=\"grid\"` of `SwatchPicker.Row` rows whose cells hold the\n * swatch buttons, the selected one `aria-selected` and pressed): the arrow keys move focus only.\n * Left/Right go through the cells in reading order across rows (mirrored under `dir=\"rtl\"`) and\n * stop at the grid's first and last cell; Up/Down go to the nearest enabled cell of the\n * previous/next row; Home/End to the first/last cell of the row, Ctrl+Home/End of the grid.\n * Space, Enter and a click select. One tab stop: the last focused cell, starting at the\n * selected swatch, else the first. `items`, and every run of children that are not rows, render\n * in a row of their own; rows do not wrap.\n * - **Selected indicator**: an offset ring in the foreground color (drawn on the page background,\n * not on the swatch) plus a check glyph whose color is picked by the swatch's luminance, so the\n * selection never relies on color alone.\n * - **Naming**: give the picker a name with `aria-label`/`aria-labelledby` or render it inside a\n * `Field`, and give every item a `label`; both are reported in development when missing.\n * - **Forms**: with `name` (or `required`) it takes part in native forms; a form reset restores\n * `defaultValue`. A required grid says so in its description (`labels.required`), since its\n * role does not allow `aria-required`.\n * - **Composition**: `items` render as `ColorSwatch` elements before `children`. A `ColorSwatch`,\n * `ImageSwatch` or `EmptySwatch` rendered directly as a child lets you wrap it, for example in\n * a `Tooltip` with `relationship=\"label\"` to name and describe it. A swatch rendered outside any\n * `SwatchPicker` throws in development. React Server Components use the flat `SwatchPickerRow`\n * name for `SwatchPicker.Row`.\n *\n * @example\n * <SwatchPicker aria-label=\"Accent color\" items={[{ value: 'red', color: '#d13438', label: 'Red' }]} />\n *\n * @example\n * <SwatchPicker layout=\"grid\" aria-label=\"Accent color\">\n * <SwatchPicker.Row>\n * <ColorSwatch value=\"red\" color=\"#d13438\" aria-label=\"Red\" />\n * <ColorSwatch value=\"blue\" color=\"#0f6cbd\" aria-label=\"Blue\" />\n * </SwatchPicker.Row>\n * <SwatchPicker.Row>\n * <ColorSwatch value=\"green\" color=\"#107c10\" aria-label=\"Green\" />\n * <EmptySwatch onClick={openColorDialog} />\n * </SwatchPicker.Row>\n * </SwatchPicker>\n */\nexport const SwatchPicker = /* @__PURE__ */ Object.assign(SwatchPickerRoot, {\n Row: SwatchPickerRow,\n});\n"],"mappings":"+wBAoJA,SAASwC,EAAU,EAAqC,CACtD,OAAOC,IAAY,QAAU,QAAU,OACzC,CAGA,IAAMC,OAAmB,EAGnBC,EAAmB3C,EAAM,cAAc,EAAK,EAoBrC4C,GAAmB,CAAE,YAAW,MAAK,GAAGC,KAAiC,CACpF,GAAM,CAAE,SAAQ,YAAW,WAAY5C,EAAAA,uBAAuB,kBAAkB,EAC1E6C,EAAS9C,EAAM,WAAW2C,CAAgB,EAChDL,EAAM,cAAgB,CAChBQ,GACFtB,EAAA,SACE,0BACA,sLAGF,CAEJ,EAAG,CAACsB,CAAM,CAAC,EACX,IAAMC,EAAYC,IAAW,QAAUC,IAAc,QACrD,OACE,EAAAV,EAAA,IAAA,CAACI,EAAiB,SAAlB,CAA2B,MAAA,GACzB,UAAA,EAAAJ,EAAA,IAAA,CAAC,MAAD,CACE,KAAMQ,EAAY,MAAQ,IAAA,GAC1B,GAAIF,EACC,MACL,UAAW3C,EAAAA,GACTC,EAAAA,0BAA0B,KAG1B4C,EAAY,OAAS,4BACrBP,EAAUC,CAAO,EACjBS,CACF,CACD,CAAA,CACwB,CAAA,CAE/B,EACA,EAAgB,YAAc,kBAM9B,SAASC,EACP,EACA,EACmB,CACnB,IAAMC,EAA0B,CAAC,EAG7BC,EAA6B,CAAC,EAC9BC,EAAa,QACbC,GAAgBA,EAAa,OAAS,GACxCF,EAAQ,MAAK,EAAAd,EAAA,IAAA,CAACvC,EAAM,SAAP,CAAA,SAA6BuD,CAA6B,EAAtC,OAAsC,CAAC,EAE1E,IAAMC,MAAc,CACdH,EAAQ,OAAS,GACnBD,EAAK,MAAK,EAAAb,EAAA,IAAA,CAACK,EAAD,CAAA,SAAiDS,CAAyB,EAApD,YAAYC,GAAwC,CAAC,EAEvF,EAAU,CAAC,CACb,EACA,IAAK,GAAM,CAAE,MAAK,UAAUlD,EAAAA,gBAAgBqD,CAAQ,EAC9CpD,EAAAA,gBAAgBqD,EAAMd,CAAe,GACvCY,EAAM,EACNJ,EAAK,MAAK,EAAAb,EAAA,IAAA,CAACvC,EAAM,SAAP,CAAA,SAA2B0D,CAAqB,EAA3BC,CAA2B,CAAC,IAEvDN,EAAQ,SAAW,IAAG,EAAaM,GACvCN,EAAQ,MAAK,EAAAd,EAAA,IAAA,CAACvC,EAAM,SAAP,CAAA,SAA2B0D,CAAqB,EAA3BC,CAA2B,CAAC,GAIlE,OADAH,EAAM,EACCJ,CACT,CAGA,IAAMQ,GAAoB,CACxB,QACA,MAAOC,EACP,eACA,gBACA,WACA,WACA,SAAS,MACT,YAAY,QACZ,UACA,OAAO,SACP,QAAQ,WACR,UAAU,SACV,OACA,WACA,OACA,YACA,KACA,aAAcC,GACd,kBAAmBC,GACnB,mBAAoBC,GACpB,eAAgBC,GAChB,gBAAiBC,GACjB,aACA,WACA,OACA,GAAGrB,KACoB,CACnBsB,IAAa,IAAA,IAAW3C,EAAA,eAAe,eAAgB,WAAY,eAAe,EACtF,IAAM4C,EAAeC,GAAgB,GAC/B,CAACC,EAAOC,GAAYjE,EAAAA,gBAAgBuD,EAAWO,EAAe,GAAiB,CACnFI,IAAgBC,CAAI,EACpBN,IAAWM,CAAI,CACjB,CAAC,EACKC,EAAQzB,IAAc,MAEtB0B,EAAS3B,IAAW,OACpB4B,EAAcD,GAAU,CAACD,EAIzBG,EAAQtE,EAAAA,kBAAkB,CAC9B,YAAa+D,GAAS,KACtB,YAAa,OAEb,YAAc,GAASC,EAASE,CAAI,CACtC,CAAC,EAEKK,EAAOtE,EAAAA,cAAc,CAAE,YAAa8D,GAAS,IAAK,CAAC,EACnD,CAAE,iBAAgB,YAAaS,IAAmBH,EAAcE,EAAOD,EACvEG,EAAcN,EAAQhC,GAAUqC,GAEhCE,EAAUjF,EAAM,OAAuB,IAAI,EAC3CkF,GAAYzE,EAAAA,cAA8B0E,GAAKT,EAAQ,KAAOU,EAAe,IAAKH,CAAO,EAEzFI,GAAQ3E,EAAAA,gBAAgB,EACxB,CACJ,gBAAiB4E,EACjB,mBAAoBC,GACpB,GAAGC,GACD7E,EAAAA,gBACF,CACE,KACA,aAAcmD,GACd,kBAAmBC,GACnB,mBAAoBC,GACpB,eAAgBC,GAGhB,gBAAiBC,IAAgBuB,CACnC,EACA,CAAE,UAAW,EAAM,CACrB,EACMC,GAAaD,GAAYJ,IAAO,UAAY,GAC5CM,EAAOjB,EAAQ,QAAUC,EAAS,OAAS,aAG3CiB,EAAiBhF,EAAAA,MAAM,6BAA6B,EACpDiF,EACJF,IAAS,cACTL,IAAsB,IAAA,IACtB,OAAOA,CAAiB,IAAM,QAE1BQ,EACJN,EAAW,gBAAkB,IAAA,IAAaA,EAAW,qBAAuB,IAAA,GACxEO,EAAiBC,GAAO,KAAM,GAAS,CAACC,EAAK,KAAK,CAAC,EAAE,MAC3D3D,EAAM,cAAgB,CAChBwD,GACFtE,EAAA,SACE,uBACA,qBAAqBmE,EAAK,kGAC5B,CAEJ,EAAG,CAACG,EAASH,CAAI,CAAC,EAClBrD,EAAM,cAAgB,CAChByD,IAAmB,IAAA,IACrBvE,EAAA,SACE,0BACA,yBAAyBuE,EAAe,wFAC1C,CAEJ,EAAG,CAACA,CAAc,CAAC,EAEnB9D,GAAA,aAAagD,MAAeV,EAASH,CAAY,EAAG8B,CAAI,EAExD,IAAMC,OAAqB,CACzBlB,EAAQ,SAAS,cAA2B,mCAAmC,CAAC,EAAE,MAAM,CAC1F,EAEMmB,EAAWvF,EAAAA,kBAAkB,EAC7BwF,GAAerG,EAAM,aAClB,CACL,QACA,OAAQuE,EACR,OACA,QACA,SACA,YACA,UACA,cACA,UACF,GACA,CAACD,EAAOC,EAAU+B,EAAMC,EAAOvD,EAAQC,EAAWR,EAASuC,EAAaoB,CAAQ,CAClF,EAEM7C,EAAeyC,GAAO,IAAK,IAC/B,EAAAzD,EAAA,IAAA,CAACzB,EAAAA,YAAD,CAEE,MAAOmF,EAAK,MACZ,MAAOA,EAAK,MACZ,aAAYA,EAAK,OAASA,EAAK,KAChC,EAJMA,EAAK,KAIX,CACF,EAED,OACE,EAAA1D,EAAA,KAAA,CAAC,MAAD,CACQ,OACN,GAAIiD,EACJ,gBAAeG,IAAS,aAAeL,EAAoB,IAAA,GAC3D,mBAAkBvE,EAAAA,QAAQwE,GAAkBM,GAAoBD,CAAc,EAC9E,cAAa5C,EACb,kBAAiBC,EACjB,YAAWqD,EACX,aAAYC,EACZ,eAAc9D,EACd,UAAWvC,EAAAA,GACTc,EAAAA,uBAAuB,KACvB2D,EAAS,yBAA2B,0BACpCnC,EAAUC,CAAO,EACjBS,CACF,EACA,GAAIL,EACJ,IAAKqC,GACL,wBAAuBR,EAAQ,IAAA,GAAY,GAC3C,UAAWzD,EAAAA,qBAAqBuF,GAAY,GAA+C,CAGrF9B,IACCC,GAAW,GAAM,OAAuB,eAAe,wBAAwB,IAGpFS,EAAe,UAAUqB,CAAK,CAChC,CAAC,EACD,QAASxF,EAAAA,qBAAqByF,GAAShC,EAAQ,IAAA,GAAYU,EAAe,QAAS,CACjF,sBAAuB,EACzB,CAAC,EA9BH,SAAA,EAgCE,EAAA7C,EAAA,IAAA,CAACrB,EAAAA,oBAAoB,SAArB,CAA8B,MAAOmF,GAClC,SAAA1B,EACCxB,EAASI,EAAcE,CAAQ,GAE/B,EAAAlB,EAAA,KAAA,CAAApB,EAAAA,SAAA,CAAA,SAAA,CACGoC,EACAE,CACD,CAAA,CAAA,CAEwB,CAAA,EAC7BoC,IACC,EAAAtD,EAAA,IAAA,CAAC,OAAD,CAAM,GAAIqD,EAAgB,OAAA,GACvB,SAAAe,IAAQ,UAAY,UACjB,CAAA,GAER,EAAApE,EAAA,IAAA,CAACnB,GAAAA,YAAD,CACE,KAAK,QACC,OACA,OACC,QACP,SAAUsE,GACV,UAAWS,EACZ,CAAA,CACE,GAET,EACA,EAAiB,YAAc,eA8C/B,IAAaS,EAA+B,OAAO,OAAOhD,EAAkB,CAC1E,IAAKhB,CACP,CAAC"}
@@ -0,0 +1,2 @@
1
+ "use client";const e=require("../../_virtual/_rolldown/runtime.cjs"),t=require("../../lib/dev.cjs");let n=require("react");n=e.__toESM(n,1);var r=n.createContext(null),i=()=>{},a={value:``,select:i,size:`medium`,shape:`circular`,layout:`row`,focusMode:`arrow`,spacing:`medium`,getTabIndex:()=>-1,register:()=>i};function o(e){return n.useContext(r)||(t.reportMissingContext(e,`SwatchPicker`),a)}function s(e){return`SwatchPicker: several swatches share the value "${e}". Swatch values must be unique; only the first one can be selected.`}function c(){let e=n.useRef(null);return e.current===null&&(e.current=new Map),n.useCallback(n=>{let r=e.current,i=(r.get(n)??0)+1;return r.set(n,i),i>1&&t.warnOnce(`SwatchPicker:duplicate-value:${n}`,s(n)),()=>{let e=(r.get(n)??1)-1;e>0?r.set(n,e):r.delete(n)}},[])}exports.SwatchPickerContext=r,exports.useSwatchPickerContext=o,exports.useSwatchRegistry=c;
2
+ //# sourceMappingURL=SwatchPicker.context.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SwatchPicker.context.cjs","names":["React","require_runtime","require_dev","react","SwatchPickerContext","noop","INERT_CONTEXT","useSwatchPickerContext","component","duplicateValueMessage","value","useSwatchRegistry","counts","map","count","remaining"],"sources":["../../../src/components/input/SwatchPicker.context.ts"],"sourcesContent":["import * as React from 'react';\nimport { reportMissingContext, warnOnce } from '../../lib/dev';\nimport type { Shape, Size } from '../../lib/types';\n\n/*\n * The context a `SwatchPicker` gives the swatches it renders (`ColorSwatch`, `ImageSwatch` and\n * `EmptySwatch`; the last reads only the appearance): the selected value, how to select, the picker's\n * appearance and focus behaviour, and the duplicate-value registry (D18). Internal; imports no\n * component.\n */\n\n/** Size of the swatches: 20, 24, 32 or 40px. */\nexport type SwatchPickerSize = Extract<Size, 'extra-small' | 'small' | 'medium' | 'large'>;\n\n/** The state and behaviour a `SwatchPicker` gives the swatches it renders (D18). */\nexport interface SwatchPickerContextValue {\n /** The selected value (`''` for none). */\n value: string;\n /** Selects `value` (through the picker's `useControllable` setter: fires only on change). */\n select: (value: string) => void;\n /** @default the picker's `size` prop */\n size: SwatchPickerSize;\n /** @default the picker's `shape` prop */\n shape: Shape;\n /** @default 'row' */\n layout: 'row' | 'grid';\n /** @default 'arrow' */\n focusMode: 'arrow' | 'tab';\n /** @default 'medium' */\n spacing: 'small' | 'medium';\n /** `0` for the swatch that holds the tab stop, `-1` for every other one. */\n getTabIndex: (value: string) => 0 | -1;\n /**\n * Counts a mounted swatch's `value` for the picker's lifetime; a second registration of the same\n * value warns once (C-DEV). Call it from the swatch's layout effect and call the returned\n * remover in that effect's cleanup.\n */\n register: (value: string) => () => void;\n}\n\n/** Internal: read with {@link useSwatchPickerContext}, never directly. */\nexport const SwatchPickerContext = React.createContext<SwatchPickerContextValue | null>(null);\n\nconst noop = () => {};\n\n/**\n * An inert picker: nothing is selected, nothing can be, and a swatch's own value is never\n * registered. Used outside a `SwatchPicker` in production, after {@link reportMissingContext} logs\n * once.\n */\nconst INERT_CONTEXT: SwatchPickerContextValue = {\n value: '',\n select: noop,\n size: 'medium',\n shape: 'circular',\n layout: 'row',\n focusMode: 'arrow',\n spacing: 'medium',\n getTabIndex: () => -1,\n register: () => noop,\n};\n\n/**\n * The context of the nearest `SwatchPicker` (C-CONTEXT). Throws in development when `component`\n * renders outside one; in production logs once (`reportMissingContext`) and returns the inert\n * value above.\n *\n * @param component The part reading the context, e.g. `'ColorSwatch'`.\n */\nexport function useSwatchPickerContext(component: string): SwatchPickerContextValue {\n const context = React.useContext(SwatchPickerContext);\n if (context) return context;\n reportMissingContext(component, 'SwatchPicker');\n return INERT_CONTEXT;\n}\n\n/** The warning for two swatches of one picker sharing a value. */\nfunction duplicateValueMessage(value: string): string {\n return (\n `SwatchPicker: several swatches share the value \"${value}\". Swatch values must be unique; ` +\n 'only the first one can be selected.'\n );\n}\n\n/**\n * The `register` function of one `SwatchPicker`: a count per swatch value (a `Map<string, number>`\n * kept in a ref, for the picker's lifetime). A second registration of the same value warns once\n * (`SwatchPicker:duplicate-value:<value>`, development only, through {@link warnOnce}).\n *\n * Internal (`SwatchPicker`'s root, which puts the result on its context value).\n */\nexport function useSwatchRegistry(): SwatchPickerContextValue['register'] {\n const counts = React.useRef<Map<string, number> | null>(null);\n if (counts.current === null) counts.current = new Map();\n\n return React.useCallback((value: string) => {\n const map = counts.current!;\n const count = (map.get(value) ?? 0) + 1;\n map.set(value, count);\n if (count > 1) {\n warnOnce(`SwatchPicker:duplicate-value:${value}`, duplicateValueMessage(value));\n }\n return () => {\n const remaining = (map.get(value) ?? 1) - 1;\n if (remaining > 0) map.set(value, remaining);\n else map.delete(value);\n };\n }, []);\n}\n"],"mappings":"4IAyCA,IAAaI,EAAsBJ,EAAM,cAA+C,IAAI,EAEtFK,MAAa,CAAC,EAOdC,EAA0C,CAC9C,MAAO,GACP,OAAQD,EACR,KAAM,SACN,MAAO,WACP,OAAQ,MACR,UAAW,QACX,QAAS,SACT,gBAAmB,GACnB,aAAgBA,CAClB,EASA,SAAgBE,EAAuB,EAA6C,CAIlF,OAHgBP,EAAM,WAAWI,CAC7B,IACJF,EAAA,qBAAqBM,EAAW,cAAc,EACvCF,EACT,CAGA,SAASG,EAAsB,EAAuB,CACpD,MACE,mDAAmDC,EAAM,qEAG7D,CASA,SAAgBC,GAA0D,CACxE,IAAMC,EAASZ,EAAM,OAAmC,IAAI,EAG5D,OAFIY,EAAO,UAAY,OAAM,EAAO,QAAU,IAAI,KAE3CZ,EAAM,YAAa,GAAkB,CAC1C,IAAMa,EAAMD,EAAO,QACbE,GAASD,EAAI,IAAIH,CAAK,GAAK,GAAK,EAKtC,OAJAG,EAAI,IAAIH,EAAOI,CAAK,EAChBA,EAAQ,GACVZ,EAAA,SAAS,gCAAgCQ,IAASD,EAAsBC,CAAK,CAAC,MAEnE,CACX,IAAMK,GAAaF,EAAI,IAAIH,CAAK,GAAK,GAAK,EACtCK,EAAY,EAAGF,EAAI,IAAIH,EAAOK,CAAS,EACtCF,EAAI,OAAOH,CAAK,CACvB,CACF,EAAG,CAAC,CAAC,CACP"}
@@ -0,0 +1,35 @@
1
+ "use client";
2
+ import { reportMissingContext as e, warnOnce as t } from "../../lib/dev.mjs";
3
+ import * as n from "react";
4
+ //#region src/components/input/SwatchPicker.context.ts
5
+ var r = n.createContext(null), i = () => {}, a = {
6
+ value: "",
7
+ select: i,
8
+ size: "medium",
9
+ shape: "circular",
10
+ layout: "row",
11
+ focusMode: "arrow",
12
+ spacing: "medium",
13
+ getTabIndex: () => -1,
14
+ register: () => i
15
+ };
16
+ function o(t) {
17
+ return n.useContext(r) || (e(t, "SwatchPicker"), a);
18
+ }
19
+ function s(e) {
20
+ return `SwatchPicker: several swatches share the value "${e}". Swatch values must be unique; only the first one can be selected.`;
21
+ }
22
+ function c() {
23
+ let e = n.useRef(null);
24
+ return e.current === null && (e.current = /* @__PURE__ */ new Map()), n.useCallback((n) => {
25
+ let r = e.current, i = (r.get(n) ?? 0) + 1;
26
+ return r.set(n, i), i > 1 && t(`SwatchPicker:duplicate-value:${n}`, s(n)), () => {
27
+ let e = (r.get(n) ?? 1) - 1;
28
+ e > 0 ? r.set(n, e) : r.delete(n);
29
+ };
30
+ }, []);
31
+ }
32
+ //#endregion
33
+ export { r as SwatchPickerContext, o as useSwatchPickerContext, c as useSwatchRegistry };
34
+
35
+ //# sourceMappingURL=SwatchPicker.context.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SwatchPicker.context.mjs","names":["React","SwatchPickerContext","noop","INERT_CONTEXT","useSwatchPickerContext","reportMissingContext","component","duplicateValueMessage","value","useSwatchRegistry","counts","map","count","warnOnce","remaining"],"sources":["../../../src/components/input/SwatchPicker.context.ts"],"sourcesContent":["import * as React from 'react';\nimport { reportMissingContext, warnOnce } from '../../lib/dev';\nimport type { Shape, Size } from '../../lib/types';\n\n/*\n * The context a `SwatchPicker` gives the swatches it renders (`ColorSwatch`, `ImageSwatch` and\n * `EmptySwatch`; the last reads only the appearance): the selected value, how to select, the picker's\n * appearance and focus behaviour, and the duplicate-value registry (D18). Internal; imports no\n * component.\n */\n\n/** Size of the swatches: 20, 24, 32 or 40px. */\nexport type SwatchPickerSize = Extract<Size, 'extra-small' | 'small' | 'medium' | 'large'>;\n\n/** The state and behaviour a `SwatchPicker` gives the swatches it renders (D18). */\nexport interface SwatchPickerContextValue {\n /** The selected value (`''` for none). */\n value: string;\n /** Selects `value` (through the picker's `useControllable` setter: fires only on change). */\n select: (value: string) => void;\n /** @default the picker's `size` prop */\n size: SwatchPickerSize;\n /** @default the picker's `shape` prop */\n shape: Shape;\n /** @default 'row' */\n layout: 'row' | 'grid';\n /** @default 'arrow' */\n focusMode: 'arrow' | 'tab';\n /** @default 'medium' */\n spacing: 'small' | 'medium';\n /** `0` for the swatch that holds the tab stop, `-1` for every other one. */\n getTabIndex: (value: string) => 0 | -1;\n /**\n * Counts a mounted swatch's `value` for the picker's lifetime; a second registration of the same\n * value warns once (C-DEV). Call it from the swatch's layout effect and call the returned\n * remover in that effect's cleanup.\n */\n register: (value: string) => () => void;\n}\n\n/** Internal: read with {@link useSwatchPickerContext}, never directly. */\nexport const SwatchPickerContext = React.createContext<SwatchPickerContextValue | null>(null);\n\nconst noop = () => {};\n\n/**\n * An inert picker: nothing is selected, nothing can be, and a swatch's own value is never\n * registered. Used outside a `SwatchPicker` in production, after {@link reportMissingContext} logs\n * once.\n */\nconst INERT_CONTEXT: SwatchPickerContextValue = {\n value: '',\n select: noop,\n size: 'medium',\n shape: 'circular',\n layout: 'row',\n focusMode: 'arrow',\n spacing: 'medium',\n getTabIndex: () => -1,\n register: () => noop,\n};\n\n/**\n * The context of the nearest `SwatchPicker` (C-CONTEXT). Throws in development when `component`\n * renders outside one; in production logs once (`reportMissingContext`) and returns the inert\n * value above.\n *\n * @param component The part reading the context, e.g. `'ColorSwatch'`.\n */\nexport function useSwatchPickerContext(component: string): SwatchPickerContextValue {\n const context = React.useContext(SwatchPickerContext);\n if (context) return context;\n reportMissingContext(component, 'SwatchPicker');\n return INERT_CONTEXT;\n}\n\n/** The warning for two swatches of one picker sharing a value. */\nfunction duplicateValueMessage(value: string): string {\n return (\n `SwatchPicker: several swatches share the value \"${value}\". Swatch values must be unique; ` +\n 'only the first one can be selected.'\n );\n}\n\n/**\n * The `register` function of one `SwatchPicker`: a count per swatch value (a `Map<string, number>`\n * kept in a ref, for the picker's lifetime). A second registration of the same value warns once\n * (`SwatchPicker:duplicate-value:<value>`, development only, through {@link warnOnce}).\n *\n * Internal (`SwatchPicker`'s root, which puts the result on its context value).\n */\nexport function useSwatchRegistry(): SwatchPickerContextValue['register'] {\n const counts = React.useRef<Map<string, number> | null>(null);\n if (counts.current === null) counts.current = new Map();\n\n return React.useCallback((value: string) => {\n const map = counts.current!;\n const count = (map.get(value) ?? 0) + 1;\n map.set(value, count);\n if (count > 1) {\n warnOnce(`SwatchPicker:duplicate-value:${value}`, duplicateValueMessage(value));\n }\n return () => {\n const remaining = (map.get(value) ?? 1) - 1;\n if (remaining > 0) map.set(value, remaining);\n else map.delete(value);\n };\n }, []);\n}\n"],"mappings":";;;;AAyCA,IAAaC,IAAsBD,EAAM,cAA+C,IAAI,GAEtFE,UAAa,CAAC,GAOdC,IAA0C;CAC9C,OAAO;CACP,QAAQD;CACR,MAAM;CACN,OAAO;CACP,QAAQ;CACR,WAAW;CACX,SAAS;CACT,mBAAmB;CACnB,gBAAgBA;AAClB;AASA,SAAgBE,EAAuB,GAA6C;CAIlF,OAHgBJ,EAAM,WAAWC,CAC7B,MACJI,EAAqBC,GAAW,cAAc,GACvCH;AACT;AAGA,SAASI,EAAsB,GAAuB;CACpD,OACE,mDAAmDC,EAAM;AAG7D;AASA,SAAgBC,IAA0D;CACxE,IAAMC,IAASV,EAAM,OAAmC,IAAI;CAG5D,OAFIU,EAAO,YAAY,SAAM,EAAO,0BAAU,IAAI,IAAI,IAE/CV,EAAM,aAAa,MAAkB;EAC1C,IAAMW,IAAMD,EAAO,SACbE,KAASD,EAAI,IAAIH,CAAK,KAAK,KAAK;EAKtC,OAJAG,EAAI,IAAIH,GAAOI,CAAK,GAChBA,IAAQ,KACVC,EAAS,gCAAgCL,KAASD,EAAsBC,CAAK,CAAC,SAEnE;GACX,IAAMM,KAAaH,EAAI,IAAIH,CAAK,KAAK,KAAK;GAC1C,AAAIM,IAAY,IAAGH,EAAI,IAAIH,GAAOM,CAAS,IACtCH,EAAI,OAAOH,CAAK;EACvB;CACF,GAAG,CAAC,CAAC;AACP"}
@@ -1,114 +1,142 @@
1
1
  "use client";
2
2
  import { cn as e } from "../../lib/cn.mjs";
3
- import { warnDeprecated as t, warnOnce as n } from "../../lib/dev.mjs";
4
- import { composeEventHandlers as r } from "../../lib/composeEventHandlers.mjs";
5
- import { swatchPickerClassNames as i } from "../../lib/classNames.mjs";
6
- import { useControllable as a } from "../../hooks/useControllable.mjs";
7
- import { useRovingTabIndex as o } from "../../hooks/useRovingTabIndex.mjs";
8
- import { useMergedRefs as s } from "../../hooks/useMergedRefs.mjs";
9
- import { useFieldContext as c, useFieldControl as l } from "../../hooks/useFieldControl.mjs";
10
- import { focusRing as u, forcedColors as d, motionSafeTransition as f } from "../../lib/styles.mjs";
11
- import { CheckIcon as p } from "../../lib/icons.mjs";
12
- import { useFormReset as m } from "../../hooks/useFormReset.mjs";
13
- import { HiddenInput as h } from "../internal/HiddenInput.mjs";
14
- import { getCheckColors as g } from "./colorUtils.mjs";
15
- import * as _ from "react";
16
- import { jsx as v, jsxs as y } from "react/jsx-runtime";
3
+ import { flattenChildren as t, isElementOfType as n } from "../../lib/children.mjs";
4
+ import { warnDeprecated as r, warnOnce as i } from "../../lib/dev.mjs";
5
+ import { composeEventHandlers as a } from "../../lib/composeEventHandlers.mjs";
6
+ import { swatchPickerClassNames as o, swatchPickerRowClassNames as s } from "../../lib/classNames.mjs";
7
+ import { useControllable as c } from "../../hooks/useControllable.mjs";
8
+ import { useId as l } from "../../hooks/useId.mjs";
9
+ import { useRovingTabIndex as u } from "../../hooks/useRovingTabIndex.mjs";
10
+ import { useMergedRefs as d } from "../../hooks/useMergedRefs.mjs";
11
+ import { joinIds as ee } from "../../lib/aria.mjs";
12
+ import { useFieldContext as te, useFieldControl as ne } from "../../hooks/useFieldControl.mjs";
13
+ import { useFormReset as re } from "../../hooks/useFormReset.mjs";
14
+ import { HiddenInput as ie } from "../internal/HiddenInput.mjs";
15
+ import { useRovingGrid as ae } from "../../hooks/useRovingGrid.mjs";
16
+ import { SwatchPickerContext as oe, useSwatchPickerContext as f, useSwatchRegistry as p } from "./SwatchPicker.context.mjs";
17
+ import { ColorSwatch as m } from "./SwatchPicker.swatches.mjs";
18
+ import * as h from "react";
19
+ import { Fragment as se, jsx as g, jsxs as _ } from "react/jsx-runtime";
17
20
  //#region src/components/input/SwatchPicker.tsx
18
- var b = {
19
- small: "w-6 h-6",
20
- medium: "w-8 h-8",
21
- large: "w-10 h-10"
22
- }, x = {
23
- small: 12,
24
- medium: 16,
25
- large: 20
26
- }, S = {
27
- circular: "rounded-full",
28
- square: "rounded-none",
29
- rounded: "rounded"
30
- };
31
- function ee({ color: e, size: t }) {
32
- let { glyph: n, halo: r } = g(e);
33
- return /* @__PURE__ */ y("span", {
34
- "aria-hidden": "true",
35
- className: "pointer-events-none grid",
36
- children: [/* @__PURE__ */ v(p, {
37
- size: t,
38
- strokeWidth: 4,
39
- className: "col-start-1 row-start-1",
40
- style: { color: r }
41
- }), /* @__PURE__ */ v(p, {
42
- size: t,
43
- strokeWidth: 2,
44
- className: "col-start-1 row-start-1",
45
- style: { color: n }
46
- })]
21
+ function v(e) {
22
+ return e === "small" ? "gap-1" : "gap-2";
23
+ }
24
+ var ce = () => 0, y = h.createContext(!1), b = ({ className: t, ref: n, ...r }) => {
25
+ let { layout: a, focusMode: o, spacing: c } = f("SwatchPicker.Row"), l = h.useContext(y);
26
+ h.useEffect(() => {
27
+ l && i("SwatchPicker.Row:nested", "SwatchPicker.Row: a Row inside a Row nests rows. Rows must be direct children of the SwatchPicker (or inside a Fragment); a wrapper component around a Row lands in an implicit row.");
28
+ }, [l]);
29
+ let u = a === "grid" && o === "arrow";
30
+ return /* @__PURE__ */ g(y.Provider, {
31
+ value: !0,
32
+ children: /* @__PURE__ */ g("div", {
33
+ role: u ? "row" : void 0,
34
+ ...r,
35
+ ref: n,
36
+ className: e(s.root, u ? "flex" : "flex basis-full flex-wrap", v(c), t)
37
+ })
47
38
  });
39
+ };
40
+ b.displayName = "SwatchPickerRow";
41
+ function le(e, r) {
42
+ let i = [], a = [], o = "items";
43
+ e && e.length > 0 && a.push(/* @__PURE__ */ g(h.Fragment, { children: e }, "items"));
44
+ let s = () => {
45
+ a.length > 0 && i.push(/* @__PURE__ */ g(b, { children: a }, `implicit:${o}`)), a = [];
46
+ };
47
+ for (let { key: e, node: c } of t(r)) n(c, b) ? (s(), i.push(/* @__PURE__ */ g(h.Fragment, { children: c }, e))) : (a.length === 0 && (o = e), a.push(/* @__PURE__ */ g(h.Fragment, { children: c }, e)));
48
+ return s(), i;
48
49
  }
49
- var C = ({ items: p, value: g, defaultValue: C, onValueChange: w, onChange: T, size: E = "medium", shape: D = "circular", name: O, required: k, form: A, className: j, id: M, "aria-label": N, "aria-labelledby": P, "aria-describedby": F, "aria-invalid": I, "aria-required": L, onKeyDown: R, onFocus: z, ref: B, ...V }) => {
50
- T !== void 0 && t("SwatchPicker", "onChange", "onValueChange");
51
- let H = C ?? "", [U, W] = a(g, H, (e) => {
52
- w?.(e), T?.(e);
53
- }), { containerProps: G, getTabIndex: K } = o({
54
- activeValue: U || null,
50
+ var x = ({ items: t, value: n, defaultValue: s, onValueChange: f, onChange: y, children: b, layout: x = "row", focusMode: S = "arrow", labels: C, size: w = "medium", shape: T = "circular", spacing: E = "medium", name: ue, required: D, form: O, className: de, id: fe, "aria-label": pe, "aria-labelledby": me, "aria-describedby": k, "aria-invalid": A, "aria-required": j, onKeyDown: M, onFocus: N, ref: P, ...F }) => {
51
+ y !== void 0 && r("SwatchPicker", "onChange", "onValueChange");
52
+ let I = s ?? "", [L, R] = c(n, I, (e) => {
53
+ f?.(e), y?.(e);
54
+ }), z = S === "tab", B = x === "grid", he = B && !z, ge = u({
55
+ activeValue: L || null,
55
56
  orientation: "both",
56
- onFocusMove: (e) => W(e)
57
- }), q = _.useRef(null), J = s(B, G.ref, q), Y = c(), X = l({
58
- id: M,
59
- "aria-label": N,
60
- "aria-labelledby": P,
61
- "aria-describedby": F,
62
- "aria-invalid": I,
63
- "aria-required": L ?? k
64
- }, { labelable: !1 }), Z = k ?? Y?.required ?? !1, Q = X["aria-label"] === void 0 && X["aria-labelledby"] === void 0, $ = p.find((e) => !e.label)?.value;
65
- _.useEffect(() => {
66
- Q && n("SwatchPicker:unnamed", "SwatchPicker: the radiogroup has no accessible name. Pass `aria-label` or `aria-labelledby`, or render it inside a Field.");
67
- }, [Q]), _.useEffect(() => {
68
- $ !== void 0 && n("SwatchPicker:item-label", `SwatchPicker: swatch "${$}" has no \`label\`, so it is announced by its color value. Give every item a \`label\`.`);
69
- }, [$]), m(q, () => W(H), A);
70
- let te = () => {
71
- q.current?.querySelector("[data-roving-value][tabindex=\"0\"]")?.focus();
72
- };
73
- return /* @__PURE__ */ y("div", {
74
- role: "radiogroup",
75
- ...X,
76
- className: e(i.root, "relative flex flex-wrap gap-2", j),
77
- ...V,
78
- ref: J,
79
- "data-roving-container": "",
80
- onKeyDown: r(R, G.onKeyDown),
81
- onFocus: r(z, G.onFocus, { checkDefaultPrevented: !1 }),
82
- children: [p.map((t) => {
83
- let n = U === t.value;
84
- return /* @__PURE__ */ v("button", {
85
- type: "button",
86
- role: "radio",
87
- "aria-checked": n,
88
- "aria-label": t.label || t.color,
89
- "data-roving-value": t.value,
90
- "data-selected": n ? "" : void 0,
91
- tabIndex: K(t.value),
92
- onClick: () => W(t.value),
93
- className: e(i.swatch, b[E], S[D], "relative flex shrink-0 items-center justify-center border-2 border-transparent p-0", f, "forced-colors:forced-color-adjust-none", d.border, u, "focus-visible:outline-offset-4", n ? "ring-2 ring-foreground ring-offset-2 ring-offset-background" : "hover:border-stroke-hover"),
94
- style: { backgroundColor: t.color },
95
- children: n && /* @__PURE__ */ v(ee, {
96
- color: t.color,
97
- size: x[E]
98
- })
99
- }, t.value);
100
- }), /* @__PURE__ */ v(h, {
101
- type: "radio",
102
- name: O,
103
- form: A,
104
- value: U,
105
- required: Z,
106
- onInvalid: te
107
- })]
57
+ onFocusMove: (e) => R(e)
58
+ }), _e = ae({ activeValue: L || null }), { containerProps: V, getTabIndex: ve } = he ? _e : ge, H = z ? ce : ve, U = h.useRef(null), ye = d(P, z ? null : V.ref, U), be = te(), { "aria-required": W, "aria-describedby": G, ...K } = ne({
59
+ id: fe,
60
+ "aria-label": pe,
61
+ "aria-labelledby": me,
62
+ "aria-describedby": k,
63
+ "aria-invalid": A,
64
+ "aria-required": j ?? D
65
+ }, { labelable: !1 }), xe = D ?? be?.required ?? !1, q = z ? "group" : B ? "grid" : "radiogroup", J = l("wave-swatch-picker-required"), Y = q !== "radiogroup" && W !== void 0 && String(W) !== "false", X = K["aria-label"] === void 0 && K["aria-labelledby"] === void 0, Z = t?.find((e) => !e.label)?.value;
66
+ h.useEffect(() => {
67
+ X && i("SwatchPicker:unnamed", `SwatchPicker: the ${q} has no accessible name. Pass \`aria-label\` or \`aria-labelledby\`, or render it inside a Field.`);
68
+ }, [X, q]), h.useEffect(() => {
69
+ Z !== void 0 && i("SwatchPicker:item-label", `SwatchPicker: swatch "${Z}" has no \`label\`, so it is announced by its color value. Give every item a \`label\`.`);
70
+ }, [Z]), re(U, () => R(I), O);
71
+ let Se = () => {
72
+ U.current?.querySelector("[data-roving-value][tabindex=\"0\"]")?.focus();
73
+ }, Q = p(), Ce = h.useMemo(() => ({
74
+ value: L,
75
+ select: R,
76
+ size: w,
77
+ shape: T,
78
+ layout: x,
79
+ focusMode: S,
80
+ spacing: E,
81
+ getTabIndex: H,
82
+ register: Q
83
+ }), [
84
+ L,
85
+ R,
86
+ w,
87
+ T,
88
+ x,
89
+ S,
90
+ E,
91
+ H,
92
+ Q
93
+ ]), $ = t?.map((e) => /* @__PURE__ */ g(m, {
94
+ value: e.value,
95
+ color: e.color,
96
+ "aria-label": e.label || e.color
97
+ }, e.value));
98
+ return /* @__PURE__ */ _("div", {
99
+ role: q,
100
+ ...K,
101
+ "aria-required": q === "radiogroup" ? W : void 0,
102
+ "aria-describedby": ee(G, Y && J),
103
+ "data-layout": x,
104
+ "data-focus-mode": S,
105
+ "data-size": w,
106
+ "data-shape": T,
107
+ "data-spacing": E,
108
+ className: e(o.root, B ? "relative flex flex-col" : "relative flex flex-wrap", v(E), de),
109
+ ...F,
110
+ ref: ye,
111
+ "data-roving-container": z ? void 0 : "",
112
+ onKeyDown: a(M, (e) => {
113
+ z || (B || !e.target.hasAttribute?.("data-wave-empty-swatch")) && V.onKeyDown(e);
114
+ }),
115
+ onFocus: a(N, z ? void 0 : V.onFocus, { checkDefaultPrevented: !1 }),
116
+ children: [
117
+ /* @__PURE__ */ g(oe.Provider, {
118
+ value: Ce,
119
+ children: B ? le($, b) : /* @__PURE__ */ _(se, { children: [$, b] })
120
+ }),
121
+ Y && /* @__PURE__ */ g("span", {
122
+ id: J,
123
+ hidden: !0,
124
+ children: C?.required ?? "Required"
125
+ }),
126
+ /* @__PURE__ */ g(ie, {
127
+ type: "radio",
128
+ name: ue,
129
+ form: O,
130
+ value: L,
131
+ required: xe,
132
+ onInvalid: Se
133
+ })
134
+ ]
108
135
  });
109
136
  };
110
- C.displayName = "SwatchPicker";
137
+ x.displayName = "SwatchPicker";
138
+ var S = /* @__PURE__ */ Object.assign(x, { Row: b });
111
139
  //#endregion
112
- export { C as SwatchPicker };
140
+ export { S as SwatchPicker, b as SwatchPickerRow };
113
141
 
114
142
  //# sourceMappingURL=SwatchPicker.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"SwatchPicker.mjs","names":["React","sizeMap","checkSizeMap","shapeMap","SwatchCheck","getCheckColors","color","CheckIcon","halo","glyph","SwatchPicker","valueProp","ariaLabel","ariaLabelledBy","ariaDescribedBy","ariaInvalid","ariaRequired","rest","onChange","warnDeprecated","initialValue","defaultValue","value","setValue","useControllable","onValueChange","next","useRovingTabIndex","rootRef","mergedRef","useMergedRefs","ref","containerProps","field","useFieldContext","fieldProps","useFieldControl","required","isRequired","unnamed","unlabelledItem","items","item","warnOnce","useFormReset","form","focusTabStop","cn","swatchPickerClassNames","className","composeEventHandlers","onKeyDown","onFocus","isSelected","getTabIndex","size","shape","motionSafeTransition","forcedColors","focusRing","HiddenInput"],"sources":["../../../src/components/input/SwatchPicker.tsx"],"sourcesContent":["import * as React from 'react';\nimport { swatchPickerClassNames } from '../../lib/classNames';\nimport { cn } from '../../lib/cn';\nimport { composeEventHandlers } from '../../lib/composeEventHandlers';\nimport { warnDeprecated, warnOnce } from '../../lib/dev';\nimport { CheckIcon } from '../../lib/icons';\nimport { focusRing, forcedColors, motionSafeTransition } from '../../lib/styles';\nimport type { Shape, Size } from '../../lib/types';\nimport { useControllable } from '../../hooks/useControllable';\nimport { useFieldContext, useFieldControl } from '../../hooks/useFieldControl';\nimport { useFormReset } from '../../hooks/useFormReset';\nimport { useMergedRefs } from '../../hooks/useMergedRefs';\nimport { useRovingTabIndex } from '../../hooks/useRovingTabIndex';\nimport { HiddenInput } from '../internal/HiddenInput';\nimport { getCheckColors } from './colorUtils';\n\n/** Represents a single color swatch option. */\nexport interface SwatchItem {\n /** Unique identifier for the swatch (the value `onValueChange` reports and a form submits). */\n value: string;\n /** CSS color value (e.g., hex, rgb) used as the swatch background. */\n color: string;\n /**\n * Accessible name of the swatch, e.g. `'Cranberry'`. **Required for accessibility**: without it\n * the swatch is announced by its raw color value (`'#d13438'`) and a development warning is\n * logged.\n */\n label?: string;\n}\n\n/** Size of the swatches. */\nexport type SwatchPickerSize = Extract<Size, 'small' | 'medium' | 'large'>;\n\n/** Properties for the SwatchPicker component. */\nexport interface SwatchPickerProps extends Omit<\n React.HTMLAttributes<HTMLDivElement>,\n 'onChange' | 'defaultValue'\n> {\n /** The swatches to display, in order (a readonly array is accepted; it is never modified). */\n items: readonly SwatchItem[];\n /** Controlled selected swatch value (`''` = nothing selected). */\n value?: string;\n /** Initial selected value for uncontrolled usage (also what a form reset restores).\n * @default ''\n */\n defaultValue?: string;\n /** Called with the new value when the selection changes (not when the selected swatch is chosen again). */\n onValueChange?: (value: string) => void;\n /**\n * Called with the new value when the selection changes.\n * @deprecated Use `onValueChange`.\n */\n onChange?: (value: string) => void;\n /** Size of each swatch button (24, 32 or 40px).\n * @default 'medium'\n */\n size?: SwatchPickerSize;\n /** Shape of each swatch button.\n * @default 'circular'\n */\n shape?: Shape;\n /**\n * Form field name. With a name, the selected swatch's `value` is submitted with the form\n * (nothing while no swatch is selected).\n */\n name?: string;\n /** A swatch must be selected before the form can be submitted (native validation). */\n required?: boolean;\n /** Id of the form the picker belongs to, when it is rendered outside that form. */\n form?: string;\n /** Ref to the `role=\"radiogroup\"` element. */\n ref?: React.Ref<HTMLDivElement>;\n}\n\nconst sizeMap: Record<SwatchPickerSize, string> = {\n small: 'w-6 h-6',\n medium: 'w-8 h-8',\n large: 'w-10 h-10',\n};\n\nconst checkSizeMap: Record<SwatchPickerSize, number> = {\n small: 12,\n medium: 16,\n large: 20,\n};\n\nconst shapeMap: Record<Shape, string> = {\n circular: 'rounded-full',\n square: 'rounded-none',\n rounded: 'rounded',\n};\n\n/**\n * The check glyph of the selected swatch: black or white by the swatch's luminance, drawn over a\n * halo in the other color so it stays visible on any swatch (C-TOKENS exception for\n * user-supplied colors, `input-pickers#16`).\n */\nfunction SwatchCheck({ color, size }: { color: string; size: number }) {\n const { glyph, halo } = getCheckColors(color);\n return (\n <span aria-hidden=\"true\" className=\"pointer-events-none grid\">\n <CheckIcon\n size={size}\n strokeWidth={4}\n className=\"col-start-1 row-start-1\"\n style={{ color: halo }}\n />\n <CheckIcon\n size={size}\n strokeWidth={2}\n className=\"col-start-1 row-start-1\"\n style={{ color: glyph }}\n />\n </span>\n );\n}\n\n/**\n * A single-select grid of color swatches (`role=\"radiogroup\"` of `role=\"radio\"` buttons).\n *\n * - **Keyboard** (APG radio group): one tab stop — the selected swatch, else the first. All four\n * arrow keys move focus and select (Left/Right mirrored under `dir=\"rtl\"`), wrapping at the\n * ends; Home/End jump to the first/last swatch.\n * - **Selected indicator**: an offset ring in the foreground color (drawn on the page background,\n * not on the swatch) plus a check glyph whose color is picked by the swatch's luminance, so the\n * selection never relies on color alone.\n * - **Naming**: give the group a name with `aria-label`/`aria-labelledby` or render it inside a\n * `Field`, and give every item a `label`; both are reported in development when missing.\n * - **Forms**: with `name` (or `required`) it takes part in native forms; a form reset restores\n * `defaultValue`.\n *\n * @example\n * <SwatchPicker aria-label=\"Accent color\" items={[{ value: 'red', color: '#d13438', label: 'Red' }]} />\n */\nexport const SwatchPicker = ({\n items,\n value: valueProp,\n defaultValue,\n onValueChange,\n onChange,\n size = 'medium',\n shape = 'circular',\n name,\n required,\n form,\n className,\n id,\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledBy,\n 'aria-describedby': ariaDescribedBy,\n 'aria-invalid': ariaInvalid,\n 'aria-required': ariaRequired,\n onKeyDown,\n onFocus,\n ref,\n ...rest\n}: SwatchPickerProps) => {\n if (onChange !== undefined) warnDeprecated('SwatchPicker', 'onChange', 'onValueChange');\n const initialValue = defaultValue ?? '';\n const [value, setValue] = useControllable(valueProp, initialValue, (next: string) => {\n onValueChange?.(next);\n onChange?.(next);\n });\n\n const { containerProps, getTabIndex } = useRovingTabIndex({\n activeValue: value || null,\n orientation: 'both',\n // APG radio group: moving focus also selects.\n onFocusMove: (next) => setValue(next),\n });\n\n const rootRef = React.useRef<HTMLDivElement>(null);\n const mergedRef = useMergedRefs<HTMLDivElement>(ref, containerProps.ref, rootRef);\n\n const field = useFieldContext();\n const fieldProps = useFieldControl(\n {\n id,\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledBy,\n 'aria-describedby': ariaDescribedBy,\n 'aria-invalid': ariaInvalid,\n // An explicit `required={false}` wins over a required Field, so aria-required matches\n // `isRequired`.\n 'aria-required': ariaRequired ?? required,\n },\n { labelable: false },\n );\n const isRequired = required ?? field?.required ?? false;\n\n const unnamed =\n fieldProps['aria-label'] === undefined && fieldProps['aria-labelledby'] === undefined;\n const unlabelledItem = items.find((item) => !item.label)?.value;\n React.useEffect(() => {\n if (unnamed) {\n warnOnce(\n 'SwatchPicker:unnamed',\n 'SwatchPicker: the radiogroup has no accessible name. Pass `aria-label` or `aria-labelledby`, or render it inside a Field.',\n );\n }\n }, [unnamed]);\n React.useEffect(() => {\n if (unlabelledItem !== undefined) {\n warnOnce(\n 'SwatchPicker:item-label',\n `SwatchPicker: swatch \"${unlabelledItem}\" has no \\`label\\`, so it is announced by its color value. Give every item a \\`label\\`.`,\n );\n }\n }, [unlabelledItem]);\n\n useFormReset(rootRef, () => setValue(initialValue), form);\n\n const focusTabStop = () => {\n rootRef.current?.querySelector<HTMLElement>('[data-roving-value][tabindex=\"0\"]')?.focus();\n };\n\n return (\n <div\n role=\"radiogroup\"\n {...fieldProps}\n className={cn(swatchPickerClassNames.root, 'relative flex flex-wrap gap-2', className)}\n {...rest}\n ref={mergedRef}\n data-roving-container=\"\"\n onKeyDown={composeEventHandlers(onKeyDown, containerProps.onKeyDown)}\n onFocus={composeEventHandlers(onFocus, containerProps.onFocus, {\n checkDefaultPrevented: false,\n })}\n >\n {items.map((item) => {\n const isSelected = value === item.value;\n return (\n <button\n key={item.value}\n type=\"button\"\n role=\"radio\"\n aria-checked={isSelected}\n aria-label={item.label || item.color}\n data-roving-value={item.value}\n data-selected={isSelected ? '' : undefined}\n tabIndex={getTabIndex(item.value)}\n onClick={() => setValue(item.value)}\n className={cn(\n swatchPickerClassNames.swatch,\n sizeMap[size],\n shapeMap[shape],\n // The padding is set here (C-NATIVE); the swatch color is its background.\n 'relative flex shrink-0 items-center justify-center border-2 border-transparent p-0',\n motionSafeTransition,\n // User colors are the content: keep them (and the check glyph) in forced colors.\n 'forced-colors:forced-color-adjust-none',\n forcedColors.border,\n focusRing,\n // Outside the selection ring, so both stay visible together.\n 'focus-visible:outline-offset-4',\n isSelected\n ? 'ring-2 ring-foreground ring-offset-2 ring-offset-background'\n : 'hover:border-stroke-hover',\n )}\n style={{ backgroundColor: item.color }}\n >\n {isSelected && <SwatchCheck color={item.color} size={checkSizeMap[size]} />}\n </button>\n );\n })}\n <HiddenInput\n type=\"radio\"\n name={name}\n form={form}\n value={value}\n required={isRequired}\n onInvalid={focusTabStop}\n />\n </div>\n );\n};\n\nSwatchPicker.displayName = 'SwatchPicker';\n"],"mappings":";;;;;;;;;;;;;;;;;AA0EA,IAAMC,IAA4C;CAChD,OAAO;CACP,QAAQ;CACR,OAAO;AACT,GAEMC,IAAiD;CACrD,OAAO;CACP,QAAQ;CACR,OAAO;AACT,GAEMC,IAAkC;CACtC,UAAU;CACV,QAAQ;CACR,SAAS;AACX;AAOA,SAASC,GAAY,EAAE,UAAO,WAAyC;CACrE,IAAM,EAAE,UAAO,YAASC,EAAeC,CAAK;CAC5C,OACE,kBAAC,QAAD;EAAM,eAAY;EAAO,WAAU;EAAnC,UAAA,CACE,kBAACC,GAAD;GACQ;GACN,aAAa;GACb,WAAU;GACV,OAAO,EAAE,OAAOC,EAAK;EACtB,CAAA,GACD,kBAACD,GAAD;GACQ;GACN,aAAa;GACb,WAAU;GACV,OAAO,EAAE,OAAOE,EAAM;EACvB,CAAA,CACG;;AAEV;AAmBA,IAAaC,KAAgB,EAC3B,UACA,OAAOC,GACP,iBACA,kBACA,aACA,UAAO,UACP,WAAQ,YACR,SACA,aACA,SACA,cACA,OACA,cAAcC,GACd,mBAAmBC,GACnB,oBAAoBC,GACpB,gBAAgBC,GAChB,iBAAiBC,GACjB,cACA,YACA,QACA,GAAGC,QACoB;CACvB,AAAIC,MAAa,KAAA,KAAWC,EAAe,gBAAgB,YAAY,eAAe;CACtF,IAAMC,IAAeC,KAAgB,IAC/B,CAACC,GAAOC,KAAYC,EAAgBb,GAAWS,IAAe,MAAiB;EAEnF,AADAK,IAAgBC,CAAI,GACpBR,IAAWQ,CAAI;CACjB,CAAC,GAEK,EAAE,mBAAgB,mBAAgBC,EAAkB;EACxD,aAAaL,KAAS;EACtB,aAAa;EAEb,cAAc,MAASC,EAASG,CAAI;CACtC,CAAC,GAEKE,IAAU5B,EAAM,OAAuB,IAAI,GAC3C6B,IAAYC,EAA8BC,GAAKC,EAAe,KAAKJ,CAAO,GAE1EK,IAAQC,EAAgB,GACxBC,IAAaC,EACjB;EACE;EACA,cAAcxB;EACd,mBAAmBC;EACnB,oBAAoBC;EACpB,gBAAgBC;EAGhB,iBAAiBC,KAAgBqB;CACnC,GACA,EAAE,WAAW,GAAM,CACrB,GACMC,IAAaD,KAAYJ,GAAO,YAAY,IAE5CM,IACJJ,EAAW,kBAAkB,KAAA,KAAaA,EAAW,uBAAuB,KAAA,GACxEK,IAAiBC,EAAM,MAAM,MAAS,CAACC,EAAK,KAAK,CAAC,EAAE;CAkB1D,AAjBA1C,EAAM,gBAAgB;EACpB,AAAIuC,KACFI,EACE,wBACA,2HACF;CAEJ,GAAG,CAACJ,CAAO,CAAC,GACZvC,EAAM,gBAAgB;EACpB,AAAIwC,MAAmB,KAAA,KACrBG,EACE,2BACA,yBAAyBH,EAAe,wFAC1C;CAEJ,GAAG,CAACA,CAAc,CAAC,GAEnBI,EAAahB,SAAeL,EAASH,CAAY,GAAGyB,CAAI;CAExD,IAAMC,WAAqB;EACzB,EAAQ,SAAS,cAA2B,qCAAmC,CAAC,EAAE,MAAM;CAC1F;CAEA,OACE,kBAAC,OAAD;EACE,MAAK;EACL,GAAIX;EACJ,WAAWY,EAAGC,EAAuB,MAAM,iCAAiCC,CAAS;EACrF,GAAIhC;EACJ,KAAKY;EACL,yBAAsB;EACtB,WAAWqB,EAAqBC,GAAWnB,EAAe,SAAS;EACnE,SAASkB,EAAqBE,GAASpB,EAAe,SAAS,EAC7D,uBAAuB,GACzB,CAAC;EAVH,UAAA,CAYGS,EAAM,KAAK,MAAS;GACnB,IAAMY,IAAa/B,MAAUoB,EAAK;GAClC,OACE,kBAAC,UAAD;IAEE,MAAK;IACL,MAAK;IACL,gBAAcW;IACd,cAAYX,EAAK,SAASA,EAAK;IAC/B,qBAAmBA,EAAK;IACxB,iBAAeW,IAAa,KAAK,KAAA;IACjC,UAAUC,EAAYZ,EAAK,KAAK;IAChC,eAAenB,EAASmB,EAAK,KAAK;IAClC,WAAWK,EACTC,EAAuB,QACvB/C,EAAQsD,IACRpD,EAASqD,IAET,sFACAC,GAEA,0CACAC,EAAa,QACbC,GAEA,kCACAN,IACI,gEACA,2BACN;IACA,OAAO,EAAE,iBAAiBX,EAAK,MAAM;IAEpC,UAAAW,KAAc,kBAACjD,IAAD;KAAa,OAAOsC,EAAK;KAAO,MAAMxC,EAAaqD;IAAQ,CAAA;GACpE,GA7BDb,EAAK,KA6BJ;EAEZ,CAAC,GACD,kBAACkB,GAAD;GACE,MAAK;GACC;GACA;GACC;GACP,UAAUtB;GACV,WAAWQ;EACZ,CAAA,CACE;;AAET;AAEA,EAAa,cAAc"}
1
+ {"version":3,"file":"SwatchPicker.mjs","names":["useId","_Fragment","useId$1","React","swatchGap","spacing","tabStop","SwatchRowContext","SwatchPickerRow","rest","useSwatchPickerContext","nested","warnOnce","isGridRow","layout","focusMode","cn","swatchPickerRowClassNames","className","gridRows","rows","pending","pendingKey","itemSwatches","flush","flattenChildren","children","isElementOfType","node","key","SwatchPickerRoot","valueProp","ariaLabel","ariaLabelledBy","ariaDescribedBy","ariaInvalid","ariaRequired","onChange","warnDeprecated","initialValue","defaultValue","value","setValue","useControllable","onValueChange","next","isTab","isGrid","isArrowGrid","radio","useRovingTabIndex","grid","useRovingGrid","rovingTabIndex","getTabIndex","rootRef","mergedRef","useMergedRefs","ref","containerProps","field","useFieldContext","fieldAriaRequired","fieldDescribedBy","fieldProps","useFieldControl","required","isRequired","role","requiredHintId","showRequiredHint","unnamed","unlabelledItem","items","item","useFormReset","form","focusTabStop","register","useSwatchRegistry","contextValue","size","shape","ColorSwatch","joinIds","swatchPickerClassNames","composeEventHandlers","onKeyDown","event","onFocus","SwatchPickerContext","Fragment","labels","HiddenInput","SwatchPicker"],"sources":["../../../src/components/input/SwatchPicker.tsx"],"sourcesContent":["import * as React from 'react';\nimport { swatchPickerClassNames, swatchPickerRowClassNames } from '../../lib/classNames';\nimport { cn } from '../../lib/cn';\nimport { composeEventHandlers } from '../../lib/composeEventHandlers';\nimport { joinIds } from '../../lib/aria';\nimport { flattenChildren, isElementOfType } from '../../lib/children';\nimport { warnDeprecated, warnOnce } from '../../lib/dev';\nimport type { Shape } from '../../lib/types';\nimport { useControllable } from '../../hooks/useControllable';\nimport { useFieldContext, useFieldControl } from '../../hooks/useFieldControl';\nimport { useFormReset } from '../../hooks/useFormReset';\nimport { useId } from '../../hooks/useId';\nimport { useMergedRefs } from '../../hooks/useMergedRefs';\nimport { useRovingGrid } from '../../hooks/useRovingGrid';\nimport { useRovingTabIndex } from '../../hooks/useRovingTabIndex';\nimport { HiddenInput } from '../internal/HiddenInput';\nimport {\n SwatchPickerContext,\n useSwatchPickerContext,\n useSwatchRegistry,\n type SwatchPickerContextValue,\n type SwatchPickerSize,\n} from './SwatchPicker.context';\nimport { ColorSwatch } from './SwatchPicker.swatches';\n\nexport type { SwatchPickerSize } from './SwatchPicker.context';\n\n/** Represents a single color swatch option. */\nexport interface SwatchItem {\n /** Unique identifier for the swatch (the value `onValueChange` reports and a form submits). */\n value: string;\n /** CSS color value (e.g., hex, rgb) used as the swatch background. */\n color: string;\n /**\n * Accessible name of the swatch, e.g. `'Cranberry'`. **Required for accessibility**: without it\n * the swatch is announced by its raw color value (`'#d13438'`) and a development warning is\n * logged.\n */\n label?: string;\n}\n\n/** Built-in strings of the SwatchPicker component (C-NAMING). */\nexport interface SwatchPickerLabels {\n /**\n * Said where the picker's role cannot carry `aria-required` (the grid layout, and the group of\n * `focusMode=\"tab\"`): a hidden text\n * joined into the picker's description while it is required.\n * @default 'Required'\n */\n required?: string;\n}\n\n/** Properties for the SwatchPicker component. */\nexport interface SwatchPickerProps extends Omit<\n React.HTMLAttributes<HTMLDivElement>,\n 'onChange' | 'defaultValue'\n> {\n /**\n * The swatches to display, in order (a readonly array is accepted; it is never modified):\n * rendered as `ColorSwatch` elements, before `children`.\n */\n items?: readonly SwatchItem[];\n /** Controlled selected swatch value (`''` = nothing selected). */\n value?: string;\n /** Initial selected value for uncontrolled usage (also what a form reset restores).\n * @default ''\n */\n defaultValue?: string;\n /** Called with the new value when the selection changes (not when the selected swatch is chosen again). */\n onValueChange?: (value: string) => void;\n /**\n * Called with the new value when the selection changes.\n * @deprecated Use `onValueChange`.\n */\n onChange?: (value: string) => void;\n // D18: an explicit C-ROUTING exception — a swatch's own ref/className/style/rest land on its\n // button, so a wrapping element's props reach the element that has focus.\n /**\n * Swatches rendered directly, in order, after `items` (e.g. `ColorSwatch`): read the picker's\n * context, so they may be wrapped in a `Tooltip` or another element that forwards its own props.\n * `SwatchPicker.Row` elements start rows; in the grid layout every run of other children (and\n * `items`, with the children that follow them) renders in a row of its own. A `SwatchPicker.Row`\n * must be a direct child or inside a Fragment: a wrapper component around a Row lands in an\n * implicit row, and nested rows are reported in development.\n */\n children?: React.ReactNode;\n /**\n * `'row'`: a radio group whose arrow keys select (and wrap). `'grid'`: rows of cells\n * (`SwatchPicker.Row`) whose arrow keys move focus in two dimensions without selecting; Space,\n * Enter and a click select. Changing it while mounted remounts the swatches, so focus falls\n * back to the page.\n * @default 'row'\n */\n layout?: 'row' | 'grid';\n /**\n * `'arrow'`: one tab stop and arrow keys, with the radio group (row layout) or grid (grid\n * layout) semantics. `'tab'`: every enabled swatch is its own tab stop and the arrow keys do\n * nothing, so the picker is a `role=\"group\"` of toggle buttons (`aria-pressed`, the selected\n * one pressed) in both layouts; rows have no role, and Space, Enter and a click select\n * (pressing the selected swatch again keeps it selected). The required hint (`labels.required`)\n * applies, as the group cannot carry `aria-required`.\n * @default 'arrow'\n */\n focusMode?: 'arrow' | 'tab';\n /** Built-in strings, for localization. */\n labels?: SwatchPickerLabels;\n /** Size of each swatch button (20, 24, 32 or 40px). A 20px swatch passes the target-size bar\n * through its spacing; a swatch's own `size` overrides this.\n * @default 'medium'\n */\n size?: SwatchPickerSize;\n /** Gap between swatches (and between rows): 4px or 8px. At `'small'` the focus outline's offset shrinks from 4px to\n * 2px, so it does not cover the neighbour.\n * @default 'medium'\n */\n spacing?: 'small' | 'medium';\n /** Shape of each swatch button (a swatch's own `shape` overrides this).\n * @default 'circular'\n */\n shape?: Shape;\n /**\n * Form field name. With a name, the selected swatch's `value` is submitted with the form\n * (nothing while no swatch is selected).\n */\n name?: string;\n /**\n * A swatch must be selected before the form can be submitted (native validation). The row\n * layout says so with `aria-required`; the grid layout and tab mode, whose roles do not allow\n * it, with the hidden `labels.required` text in the description (which a consumer\n * `aria-required` alone also shows).\n */\n required?: boolean;\n /** Id of the form the picker belongs to, when it is rendered outside that form. */\n form?: string;\n /**\n * Ref to the root element: `role=\"radiogroup\"`, `role=\"grid\"` in the grid layout, or\n * `role=\"group\"` in tab mode.\n */\n ref?: React.Ref<HTMLDivElement>;\n}\n\n/** Properties for the SwatchPicker.Row component. */\nexport interface SwatchPickerRowProps extends React.HTMLAttributes<HTMLDivElement> {\n /** Ref to the row element. */\n ref?: React.Ref<HTMLDivElement>;\n}\n\n/** The gap class the root and the rows share. */\nfunction swatchGap(spacing: 'small' | 'medium'): string {\n return spacing === 'small' ? 'gap-1' : 'gap-2';\n}\n\n/** Tab mode: every swatch is a tab stop. */\nconst tabStop = (): 0 => 0;\n\n/** True inside a `SwatchPicker.Row`: a second Row there is reported. */\nconst SwatchRowContext = React.createContext(false);\n\n/**\n * One row of swatches in a `SwatchPicker` (also exported as the flat `SwatchPickerRow`, for React\n * Server Components). In the grid layout it is a `role=\"row\"` element whose swatches are its\n * cells; Up and Down move between rows, and the row does not wrap (a wrapped swatch would sit\n * where Up and Down do not reach it): size it yourself. In the row layout and in tab mode\n * (`focusMode=\"tab\"`) it is a full-width line without a role, and its swatches stay radios of the\n * one group (row layout) or toggle buttons. Place it as a direct child of the `SwatchPicker` or\n * inside a Fragment: a wrapper component around a Row lands in an implicit row, and a Row inside\n * a Row is reported in development. Outside a `SwatchPicker` it throws in development.\n *\n * @example\n * <SwatchPicker layout=\"grid\" aria-label=\"Accent color\">\n * <SwatchPicker.Row>\n * <ColorSwatch value=\"red\" color=\"#d13438\" aria-label=\"Red\" />\n * <ColorSwatch value=\"blue\" color=\"#0f6cbd\" aria-label=\"Blue\" />\n * </SwatchPicker.Row>\n * </SwatchPicker>\n */\nexport const SwatchPickerRow = ({ className, ref, ...rest }: SwatchPickerRowProps) => {\n const { layout, focusMode, spacing } = useSwatchPickerContext('SwatchPicker.Row');\n const nested = React.useContext(SwatchRowContext);\n React.useEffect(() => {\n if (nested) {\n warnOnce(\n 'SwatchPicker.Row:nested',\n 'SwatchPicker.Row: a Row inside a Row nests rows. Rows must be direct children of the ' +\n 'SwatchPicker (or inside a Fragment); a wrapper component around a Row lands in an ' +\n 'implicit row.',\n );\n }\n }, [nested]);\n const isGridRow = layout === 'grid' && focusMode === 'arrow';\n return (\n <SwatchRowContext.Provider value>\n <div\n role={isGridRow ? 'row' : undefined}\n {...rest}\n ref={ref}\n className={cn(\n swatchPickerRowClassNames.root,\n // The grid's rows never wrap: Up and Down would not reach a wrapped swatch. Tab mode\n // has no arrow keys, so its rows wrap like the row layout's.\n isGridRow ? 'flex' : 'flex basis-full flex-wrap',\n swatchGap(spacing),\n className,\n )}\n />\n </SwatchRowContext.Provider>\n );\n};\nSwatchPickerRow.displayName = 'SwatchPickerRow';\n\n/**\n * The grid layout's rows: `SwatchPicker.Row` elements as they are, and `items` with every run of\n * other children (Fragments flattened) wrapped in an implicit row, so no cell sits outside a row.\n */\nfunction gridRows(\n itemSwatches: readonly React.ReactNode[] | undefined,\n children: React.ReactNode,\n): React.ReactNode[] {\n const rows: React.ReactNode[] = [];\n // Keys: an implicit row is keyed by its first node, so adding a row elsewhere keeps its\n // swatches mounted (and focused). Flattened keys start with a dot: no clash with `items`.\n let pending: React.ReactNode[] = [];\n let pendingKey = 'items';\n if (itemSwatches && itemSwatches.length > 0) {\n pending.push(<React.Fragment key=\"items\">{itemSwatches}</React.Fragment>);\n }\n const flush = () => {\n if (pending.length > 0) {\n rows.push(<SwatchPickerRow key={`implicit:${pendingKey}`}>{pending}</SwatchPickerRow>);\n }\n pending = [];\n };\n for (const { key, node } of flattenChildren(children)) {\n if (isElementOfType(node, SwatchPickerRow)) {\n flush();\n rows.push(<React.Fragment key={key}>{node}</React.Fragment>);\n } else {\n if (pending.length === 0) pendingKey = key;\n pending.push(<React.Fragment key={key}>{node}</React.Fragment>);\n }\n }\n flush();\n return rows;\n}\n\n// The root, documented on the exported `SwatchPicker` const.\nconst SwatchPickerRoot = ({\n items,\n value: valueProp,\n defaultValue,\n onValueChange,\n onChange,\n children,\n layout = 'row',\n focusMode = 'arrow',\n labels,\n size = 'medium',\n shape = 'circular',\n spacing = 'medium',\n name,\n required,\n form,\n className,\n id,\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledBy,\n 'aria-describedby': ariaDescribedBy,\n 'aria-invalid': ariaInvalid,\n 'aria-required': ariaRequired,\n onKeyDown,\n onFocus,\n ref,\n ...rest\n}: SwatchPickerProps) => {\n if (onChange !== undefined) warnDeprecated('SwatchPicker', 'onChange', 'onValueChange');\n const initialValue = defaultValue ?? '';\n const [value, setValue] = useControllable(valueProp, initialValue, (next: string) => {\n onValueChange?.(next);\n onChange?.(next);\n });\n const isTab = focusMode === 'tab';\n // The grid layout's rows are visual in tab mode: the grid keys and roles belong to arrow mode.\n const isGrid = layout === 'grid';\n const isArrowGrid = isGrid && !isTab;\n\n // Both hooks run on every render (hook order); only the layout's own one gets the container,\n // and tab mode none (every swatch is a tab stop, the arrow keys do nothing).\n const radio = useRovingTabIndex({\n activeValue: value || null,\n orientation: 'both',\n // APG radio group: moving focus also selects.\n onFocusMove: (next) => setValue(next),\n });\n // APG grid: the arrow keys move focus only; a swatch's own click (Space, Enter) selects.\n const grid = useRovingGrid({ activeValue: value || null });\n const { containerProps, getTabIndex: rovingTabIndex } = isArrowGrid ? grid : radio;\n const getTabIndex = isTab ? tabStop : rovingTabIndex;\n\n const rootRef = React.useRef<HTMLDivElement>(null);\n const mergedRef = useMergedRefs<HTMLDivElement>(ref, isTab ? null : containerProps.ref, rootRef);\n\n const field = useFieldContext();\n const {\n 'aria-required': fieldAriaRequired,\n 'aria-describedby': fieldDescribedBy,\n ...fieldProps\n } = useFieldControl(\n {\n id,\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledBy,\n 'aria-describedby': ariaDescribedBy,\n 'aria-invalid': ariaInvalid,\n // An explicit `required={false}` wins over a required Field, so aria-required matches\n // `isRequired`.\n 'aria-required': ariaRequired ?? required,\n },\n { labelable: false },\n );\n const isRequired = required ?? field?.required ?? false;\n const role = isTab ? 'group' : isGrid ? 'grid' : 'radiogroup';\n // Only `radiogroup` allows aria-required (a consumer's included): the description of a `grid`\n // or `group` says it instead.\n const requiredHintId = useId('wave-swatch-picker-required');\n const showRequiredHint =\n role !== 'radiogroup' &&\n fieldAriaRequired !== undefined &&\n String(fieldAriaRequired) !== 'false';\n\n const unnamed =\n fieldProps['aria-label'] === undefined && fieldProps['aria-labelledby'] === undefined;\n const unlabelledItem = items?.find((item) => !item.label)?.value;\n React.useEffect(() => {\n if (unnamed) {\n warnOnce(\n 'SwatchPicker:unnamed',\n `SwatchPicker: the ${role} has no accessible name. Pass \\`aria-label\\` or \\`aria-labelledby\\`, or render it inside a Field.`,\n );\n }\n }, [unnamed, role]);\n React.useEffect(() => {\n if (unlabelledItem !== undefined) {\n warnOnce(\n 'SwatchPicker:item-label',\n `SwatchPicker: swatch \"${unlabelledItem}\" has no \\`label\\`, so it is announced by its color value. Give every item a \\`label\\`.`,\n );\n }\n }, [unlabelledItem]);\n\n useFormReset(rootRef, () => setValue(initialValue), form);\n\n const focusTabStop = () => {\n rootRef.current?.querySelector<HTMLElement>('[data-roving-value][tabindex=\"0\"]')?.focus();\n };\n\n const register = useSwatchRegistry();\n const contextValue = React.useMemo<SwatchPickerContextValue>(\n () => ({\n value,\n select: setValue,\n size,\n shape,\n layout,\n focusMode,\n spacing,\n getTabIndex,\n register,\n }),\n [value, setValue, size, shape, layout, focusMode, spacing, getTabIndex, register],\n );\n\n const itemSwatches = items?.map((item) => (\n <ColorSwatch\n key={item.value}\n value={item.value}\n color={item.color}\n aria-label={item.label || item.color}\n />\n ));\n\n return (\n <div\n role={role}\n {...fieldProps}\n aria-required={role === 'radiogroup' ? fieldAriaRequired : undefined}\n aria-describedby={joinIds(fieldDescribedBy, showRequiredHint && requiredHintId)}\n data-layout={layout}\n data-focus-mode={focusMode}\n data-size={size}\n data-shape={shape}\n data-spacing={spacing}\n className={cn(\n swatchPickerClassNames.root,\n isGrid ? 'relative flex flex-col' : 'relative flex flex-wrap',\n swatchGap(spacing),\n className,\n )}\n {...rest}\n ref={mergedRef}\n data-roving-container={isTab ? undefined : ''}\n onKeyDown={composeEventHandlers(onKeyDown, (event: React.KeyboardEvent<HTMLDivElement>) => {\n // Tab mode has no arrow handling. An EmptySwatch is no radio: arrow keys pressed on it\n // would otherwise move to and select one. In the grid layout it is a cell like the others.\n if (isTab) return;\n if (!isGrid && (event.target as HTMLElement).hasAttribute?.('data-wave-empty-swatch')) {\n return;\n }\n containerProps.onKeyDown(event);\n })}\n onFocus={composeEventHandlers(onFocus, isTab ? undefined : containerProps.onFocus, {\n checkDefaultPrevented: false,\n })}\n >\n <SwatchPickerContext.Provider value={contextValue}>\n {isGrid ? (\n gridRows(itemSwatches, children)\n ) : (\n <>\n {itemSwatches}\n {children}\n </>\n )}\n </SwatchPickerContext.Provider>\n {showRequiredHint && (\n <span id={requiredHintId} hidden>\n {labels?.required ?? 'Required'}\n </span>\n )}\n <HiddenInput\n type=\"radio\"\n name={name}\n form={form}\n value={value}\n required={isRequired}\n onInvalid={focusTabStop}\n />\n </div>\n );\n};\nSwatchPickerRoot.displayName = 'SwatchPicker';\n\n/**\n * A single-select set of color swatches: a radio group (the default row layout) or a grid of rows\n * (`layout=\"grid\"`).\n *\n * - **Row layout** (APG radio group, `role=\"radiogroup\"` of `role=\"radio\"` buttons): one tab stop,\n * the selected swatch, else the first. All four arrow keys move focus and select (Left/Right\n * mirrored under `dir=\"rtl\"`), wrapping at the ends; Home/End jump to the first/last swatch.\n * - **Grid layout** (APG grid, `role=\"grid\"` of `SwatchPicker.Row` rows whose cells hold the\n * swatch buttons, the selected one `aria-selected` and pressed): the arrow keys move focus only.\n * Left/Right go through the cells in reading order across rows (mirrored under `dir=\"rtl\"`) and\n * stop at the grid's first and last cell; Up/Down go to the nearest enabled cell of the\n * previous/next row; Home/End to the first/last cell of the row, Ctrl+Home/End of the grid.\n * Space, Enter and a click select. One tab stop: the last focused cell, starting at the\n * selected swatch, else the first. `items`, and every run of children that are not rows, render\n * in a row of their own; rows do not wrap.\n * - **Selected indicator**: an offset ring in the foreground color (drawn on the page background,\n * not on the swatch) plus a check glyph whose color is picked by the swatch's luminance, so the\n * selection never relies on color alone.\n * - **Naming**: give the picker a name with `aria-label`/`aria-labelledby` or render it inside a\n * `Field`, and give every item a `label`; both are reported in development when missing.\n * - **Forms**: with `name` (or `required`) it takes part in native forms; a form reset restores\n * `defaultValue`. A required grid says so in its description (`labels.required`), since its\n * role does not allow `aria-required`.\n * - **Composition**: `items` render as `ColorSwatch` elements before `children`. A `ColorSwatch`,\n * `ImageSwatch` or `EmptySwatch` rendered directly as a child lets you wrap it, for example in\n * a `Tooltip` with `relationship=\"label\"` to name and describe it. A swatch rendered outside any\n * `SwatchPicker` throws in development. React Server Components use the flat `SwatchPickerRow`\n * name for `SwatchPicker.Row`.\n *\n * @example\n * <SwatchPicker aria-label=\"Accent color\" items={[{ value: 'red', color: '#d13438', label: 'Red' }]} />\n *\n * @example\n * <SwatchPicker layout=\"grid\" aria-label=\"Accent color\">\n * <SwatchPicker.Row>\n * <ColorSwatch value=\"red\" color=\"#d13438\" aria-label=\"Red\" />\n * <ColorSwatch value=\"blue\" color=\"#0f6cbd\" aria-label=\"Blue\" />\n * </SwatchPicker.Row>\n * <SwatchPicker.Row>\n * <ColorSwatch value=\"green\" color=\"#107c10\" aria-label=\"Green\" />\n * <EmptySwatch onClick={openColorDialog} />\n * </SwatchPicker.Row>\n * </SwatchPicker>\n */\nexport const SwatchPicker = /* @__PURE__ */ Object.assign(SwatchPickerRoot, {\n Row: SwatchPickerRow,\n});\n"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ "use client";const e=require("../../_virtual/_rolldown/runtime.cjs"),t=require("../../lib/cn.cjs"),n=require("../../lib/dev.cjs"),r=require("../../lib/slot.cjs"),i=require("../../lib/composeEventHandlers.cjs"),a=require("../../lib/classNames.cjs"),o=require("../../hooks/useId.cjs"),s=require("../../lib/styles.cjs"),c=require("../button/Button.slots.cjs"),l=require("../../lib/icons.cjs"),u=require("./SwatchPicker.context.cjs"),d=require("./colorUtils.cjs");let f=require("react");f=e.__toESM(f,1);let p=require("react/jsx-runtime");var m={"extra-small":`w-5 h-5`,small:`w-6 h-6`,medium:`w-8 h-8`,large:`w-10 h-10`},h={"extra-small":10,small:12,medium:16,large:20},g={circular:`rounded-full`,square:`rounded-none`,rounded:`rounded`};function _({colors:e,size:n}){return(0,p.jsxs)(`span`,{"aria-hidden":`true`,className:`pointer-events-none grid`,children:[(0,p.jsx)(l.CheckIcon,{size:n,strokeWidth:4,className:t.cn(`col-start-1 row-start-1`,!e&&`text-background`),style:e?{color:e.halo}:void 0}),(0,p.jsx)(l.CheckIcon,{size:n,strokeWidth:2,className:t.cn(`col-start-1 row-start-1`,!e&&`text-foreground`),style:e?{color:e.glyph}:void 0})]})}function v({colors:e}){return(0,p.jsxs)(`svg`,{"data-wave-swatch-slash":``,"aria-hidden":`true`,viewBox:`0 0 24 24`,fill:`none`,className:`pointer-events-none absolute inset-0 h-full w-full`,children:[(0,p.jsx)(`line`,{x1:`5`,y1:`19`,x2:`19`,y2:`5`,stroke:`currentColor`,strokeLinecap:`round`,strokeWidth:4,className:e?void 0:`text-background`,style:e?{color:e.halo}:void 0}),(0,p.jsx)(`line`,{x1:`5`,y1:`19`,x2:`19`,y2:`5`,stroke:`currentColor`,strokeLinecap:`round`,strokeWidth:2,className:e?void 0:`text-foreground`,style:e?{color:e.glyph}:void 0})]})}function y(e,t,r){n.warnOnce(`${e}:unnamed`,`${e}: swatch "${t}" has no accessible name, so it is announced by its ${r}. Pass \`aria-label\`, or wrap it in a Tooltip with \`relationship="label"\`.`)}function b(e,t){let{glyph:n,button:r}=c.unwrapButtonGlyph(t);return x(e,r),n}function x(e,t){f.useEffect(()=>{t&&n.warnOnce(`${e}:icon-button`,`${e}: \`icon\` received ${t}; its children render as the glyph of the swatch and its props were dropped (buttons cannot be nested). Pass icon content instead, e.g. \`icon={<MyIcon />}\`.`)},[t,e])}function S(e,t,n){let r=u.useSwatchPickerContext(e);return{...r,size:t??r.size,shape:n??r.shape}}function C(e){return e===`small`?`focus-visible:outline-offset-2`:`focus-visible:outline-offset-4`}function w({selected:e,children:t}){return(0,p.jsx)(`div`,{role:`gridcell`,"aria-selected":e,className:`flex shrink-0`,children:t})}function T(e,n,r){return t.cn(m[e],g[n],`relative flex shrink-0 items-center justify-center border-2 p-0`,s.motionSafeTransition,s.focusRing,C(r),`disabled:cursor-not-allowed disabled:opacity-50`)}var E=({kind:e,rootClassName:n,iconClassName:o,value:c,fallbackKind:l,defaultName:u,checkColors:d,paint:m,paintClassName:g,keepsColors:x,icon:C,size:E,shape:D,className:O,style:k,onClick:A,disabled:j,"aria-label":M,"aria-labelledby":N,ref:P,...F})=>{let{value:I,select:L,size:R,shape:z,layout:B,focusMode:V,spacing:H,getTabIndex:U,register:W}=S(e,E,D),G=I===c,K=V===`tab`,q=B===`grid`&&!K,J=b(e,C);f.useLayoutEffect(()=>W(c),[W,c]);let Y=M!==void 0||N!==void 0;f.useEffect(()=>{Y||y(e,c,l)},[Y,e,c,l]);let X=(0,p.jsxs)(`button`,{type:`button`,role:q||K?void 0:`radio`,...F,ref:P,disabled:j,"aria-label":M??(N?void 0:u),"aria-labelledby":N,"aria-checked":q||K?void 0:G,"aria-pressed":K?G:q&&G||void 0,"data-roving-value":c,"data-selected":G?``:void 0,tabIndex:U(c),onClick:i.composeEventHandlers(A,()=>L(c)),className:t.cn(n,a.swatchPickerClassNames.swatch,T(R,z,H),`border-[color:var(--wave-swatch-border,transparent)]`,g,x&&`forced-colors:forced-color-adjust-none forced-colors:focus-visible:outline-[Highlight]`,s.forcedColors.border,G&&!x&&`forced-colors:border-[Highlight]`,G?t.cn(`ring-2 ring-foreground ring-offset-2 ring-offset-background`,x&&`forced-colors:ring-[Highlight]`):`not-disabled:not-aria-disabled:hover:border-stroke-hover`,O),style:{...k,...m},children:[G?(0,p.jsx)(_,{colors:d,size:h[R]}):J!=null&&r.slotRendersContent(J)&&r.renderSlot(J,`span`,t.cn(o,`pointer-events-none inline-flex`),{"aria-hidden":!0,style:d?{color:d.glyph}:void 0}),j&&(0,p.jsx)(v,{colors:d})]});return q?(0,p.jsx)(w,{selected:G,children:X}):X};E.displayName=`SwatchRadio`;var D=({color:e,borderColor:t,...n})=>(0,p.jsx)(E,{...n,kind:`ColorSwatch`,rootClassName:a.colorSwatchClassNames.root,iconClassName:a.colorSwatchClassNames.icon,fallbackKind:`color value`,defaultName:e,checkColors:d.getCheckColors(e),keepsColors:!0,paint:{backgroundColor:e,...t!==void 0&&{"--wave-swatch-border":t}}});D.displayName=`ColorSwatch`;var O=({src:e,...t})=>(0,p.jsx)(E,{...t,kind:`ImageSwatch`,rootClassName:a.imageSwatchClassNames.root,fallbackKind:`value`,defaultName:t.value,checkColors:null,keepsColors:!1,paintClassName:`bg-cover bg-center bg-no-repeat`,paint:{backgroundImage:`url(${JSON.stringify(e)})`}});O.displayName=`ImageSwatch`;var k=({icon:e,size:n,shape:i,className:u,"aria-label":d,"aria-labelledby":f,ref:m,...g})=>{let{size:_,shape:v,layout:y,focusMode:b,spacing:C,getTabIndex:E}=S(`EmptySwatch`,n,i),D=y===`grid`&&b!==`tab`,O=o.useId(`wave-empty-swatch`),{glyph:k,button:A}=c.unwrapButtonGlyph(e);x(`EmptySwatch`,A);let j=e==null||A!==null&&!r.slotRendersContent(k)?(0,p.jsx)(l.AddIcon,{size:h[_]}):k,M=(0,p.jsx)(`button`,{type:`button`,...g,ref:m,"aria-label":d??(f?void 0:`Add color`),"aria-labelledby":f,"data-wave-empty-swatch":``,...D&&{"data-roving-value":O,tabIndex:E(O)},className:t.cn(a.emptySwatchClassNames.root,a.swatchPickerClassNames.swatch,T(_,v,C),`border-dashed border-stroke-accessible bg-transparent text-foreground`,s.forcedColors.control,`not-disabled:not-aria-disabled:hover:bg-subtle-hover`,u),children:r.slotRendersContent(j)&&r.renderSlot(j,`span`,t.cn(a.emptySwatchClassNames.icon,`pointer-events-none inline-flex`),{"aria-hidden":!0})});return D?(0,p.jsx)(w,{children:M}):M};k.displayName=`EmptySwatch`,exports.ColorSwatch=D,exports.EmptySwatch=k,exports.ImageSwatch=O;
2
+ //# sourceMappingURL=SwatchPicker.swatches.cjs.map