@mortenbrudvik/waveui 0.10.0 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +454 -74
- package/dist/components/button/Link.cjs +1 -1
- package/dist/components/button/Link.cjs.map +1 -1
- package/dist/components/button/Link.mjs +4 -4
- package/dist/components/button/Toolbar.cjs +1 -1
- package/dist/components/button/Toolbar.cjs.map +1 -1
- package/dist/components/button/Toolbar.mjs +25 -30
- package/dist/components/button/Toolbar.mjs.map +1 -1
- package/dist/components/button/Toolbar.navigation.cjs +2 -0
- package/dist/components/button/Toolbar.navigation.cjs.map +1 -0
- package/dist/components/button/Toolbar.navigation.mjs +17 -0
- package/dist/components/button/Toolbar.navigation.mjs.map +1 -0
- package/dist/components/data-display/Avatar.cjs +1 -1
- package/dist/components/data-display/Avatar.cjs.map +1 -1
- package/dist/components/data-display/Avatar.context.cjs +2 -0
- package/dist/components/data-display/Avatar.context.cjs.map +1 -0
- package/dist/components/data-display/Avatar.context.mjs +9 -0
- package/dist/components/data-display/Avatar.context.mjs.map +1 -0
- package/dist/components/data-display/Avatar.mjs +66 -61
- package/dist/components/data-display/Avatar.mjs.map +1 -1
- package/dist/components/data-display/AvatarGroup.cjs +1 -1
- package/dist/components/data-display/AvatarGroup.cjs.map +1 -1
- package/dist/components/data-display/AvatarGroup.mjs +10 -10
- package/dist/components/data-display/InfoButton.cjs +1 -1
- package/dist/components/data-display/InfoButton.cjs.map +1 -1
- package/dist/components/data-display/InfoButton.mjs +12 -12
- package/dist/components/data-display/InteractionTag.cjs +2 -0
- package/dist/components/data-display/InteractionTag.cjs.map +1 -0
- package/dist/components/data-display/InteractionTag.mjs +234 -0
- package/dist/components/data-display/InteractionTag.mjs.map +1 -0
- package/dist/components/data-display/Tag.cjs +1 -1
- package/dist/components/data-display/Tag.cjs.map +1 -1
- package/dist/components/data-display/Tag.mjs +222 -90
- package/dist/components/data-display/Tag.mjs.map +1 -1
- package/dist/components/data-display/TagGroup.cjs +2 -0
- package/dist/components/data-display/TagGroup.cjs.map +1 -0
- package/dist/components/data-display/TagGroup.context.cjs +2 -0
- package/dist/components/data-display/TagGroup.context.cjs.map +1 -0
- package/dist/components/data-display/TagGroup.context.mjs +113 -0
- package/dist/components/data-display/TagGroup.context.mjs.map +1 -0
- package/dist/components/data-display/TagGroup.mjs +149 -0
- package/dist/components/data-display/TagGroup.mjs.map +1 -0
- package/dist/components/data-display/tagStyles.cjs +2 -0
- package/dist/components/data-display/tagStyles.cjs.map +1 -0
- package/dist/components/data-display/tagStyles.mjs +108 -0
- package/dist/components/data-display/tagStyles.mjs.map +1 -0
- package/dist/components/feedback/Toaster.cjs +1 -1
- package/dist/components/feedback/Toaster.cjs.map +1 -1
- package/dist/components/feedback/Toaster.mjs +287 -255
- package/dist/components/feedback/Toaster.mjs.map +1 -1
- package/dist/components/input/Combobox.cjs +1 -1
- package/dist/components/input/Combobox.cjs.map +1 -1
- package/dist/components/input/Combobox.expand.cjs +1 -1
- package/dist/components/input/Combobox.expand.cjs.map +1 -1
- package/dist/components/input/Combobox.expand.mjs +7 -7
- package/dist/components/input/Combobox.expand.mjs.map +1 -1
- package/dist/components/input/Combobox.mjs +176 -175
- package/dist/components/input/Combobox.mjs.map +1 -1
- package/dist/components/input/DatePicker.cjs +1 -1
- package/dist/components/input/DatePicker.cjs.map +1 -1
- package/dist/components/input/DatePicker.mjs +188 -187
- package/dist/components/input/DatePicker.mjs.map +1 -1
- package/dist/components/input/Dropdown.cjs +1 -1
- package/dist/components/input/Dropdown.cjs.map +1 -1
- package/dist/components/input/Dropdown.mjs +41 -40
- package/dist/components/input/Dropdown.mjs.map +1 -1
- package/dist/components/input/Option.cjs +1 -1
- package/dist/components/input/Option.cjs.map +1 -1
- package/dist/components/input/Option.mjs +101 -94
- package/dist/components/input/Option.mjs.map +1 -1
- package/dist/components/input/SwatchPicker.cjs.map +1 -1
- package/dist/components/input/SwatchPicker.context.cjs.map +1 -1
- package/dist/components/input/SwatchPicker.context.mjs.map +1 -1
- package/dist/components/input/SwatchPicker.mjs.map +1 -1
- package/dist/components/input/TagPicker.cjs +1 -1
- package/dist/components/input/TagPicker.cjs.map +1 -1
- package/dist/components/input/TagPicker.context.cjs +2 -0
- package/dist/components/input/TagPicker.context.cjs.map +1 -0
- package/dist/components/input/TagPicker.context.mjs +20 -0
- package/dist/components/input/TagPicker.context.mjs.map +1 -0
- package/dist/components/input/TagPicker.create.cjs +2 -0
- package/dist/components/input/TagPicker.create.cjs.map +1 -0
- package/dist/components/input/TagPicker.create.mjs +24 -0
- package/dist/components/input/TagPicker.create.mjs.map +1 -0
- package/dist/components/input/TagPicker.mjs +13 -279
- package/dist/components/input/TagPicker.mjs.map +1 -1
- package/dist/components/input/TagPicker.option.cjs +2 -0
- package/dist/components/input/TagPicker.option.cjs.map +1 -0
- package/dist/components/input/TagPicker.option.mjs +45 -0
- package/dist/components/input/TagPicker.option.mjs.map +1 -0
- package/dist/components/input/TagPicker.overflow.cjs +2 -0
- package/dist/components/input/TagPicker.overflow.cjs.map +1 -0
- package/dist/components/input/TagPicker.overflow.mjs +153 -0
- package/dist/components/input/TagPicker.overflow.mjs.map +1 -0
- package/dist/components/input/TagPicker.parts.cjs +2 -0
- package/dist/components/input/TagPicker.parts.cjs.map +1 -0
- package/dist/components/input/TagPicker.parts.mjs +425 -0
- package/dist/components/input/TagPicker.parts.mjs.map +1 -0
- package/dist/components/input/TagPicker.root.cjs +2 -0
- package/dist/components/input/TagPicker.root.cjs.map +1 -0
- package/dist/components/input/TagPicker.root.mjs +417 -0
- package/dist/components/input/TagPicker.root.mjs.map +1 -0
- package/dist/components/input/TimePicker.cjs +1 -1
- package/dist/components/input/TimePicker.cjs.map +1 -1
- package/dist/components/input/TimePicker.mjs +156 -154
- package/dist/components/input/TimePicker.mjs.map +1 -1
- package/dist/components/layout/Accordion.cjs.map +1 -1
- package/dist/components/layout/Accordion.mjs.map +1 -1
- package/dist/components/navigation/Hamburger.cjs +2 -0
- package/dist/components/navigation/Hamburger.cjs.map +1 -0
- package/dist/components/navigation/Hamburger.mjs +54 -0
- package/dist/components/navigation/Hamburger.mjs.map +1 -0
- package/dist/components/navigation/Menu.popover.cjs +1 -1
- package/dist/components/navigation/Menu.popover.cjs.map +1 -1
- package/dist/components/navigation/Menu.popover.mjs +137 -127
- package/dist/components/navigation/Menu.popover.mjs.map +1 -1
- package/dist/components/navigation/Menu.root.cjs +1 -1
- package/dist/components/navigation/Menu.root.cjs.map +1 -1
- package/dist/components/navigation/Menu.root.mjs +4 -4
- package/dist/components/navigation/Nav.cjs +1 -1
- package/dist/components/navigation/Nav.cjs.map +1 -1
- package/dist/components/navigation/Nav.context.cjs +2 -0
- package/dist/components/navigation/Nav.context.cjs.map +1 -0
- package/dist/components/navigation/Nav.context.mjs +137 -0
- package/dist/components/navigation/Nav.context.mjs.map +1 -0
- package/dist/components/navigation/Nav.mjs +151 -258
- package/dist/components/navigation/Nav.mjs.map +1 -1
- package/dist/components/navigation/Nav.parts.cjs +2 -0
- package/dist/components/navigation/Nav.parts.cjs.map +1 -0
- package/dist/components/navigation/Nav.parts.mjs +77 -0
- package/dist/components/navigation/Nav.parts.mjs.map +1 -0
- package/dist/components/navigation/Nav.root.cjs +2 -0
- package/dist/components/navigation/Nav.root.cjs.map +1 -0
- package/dist/components/navigation/Nav.root.mjs +78 -0
- package/dist/components/navigation/Nav.root.mjs.map +1 -0
- package/dist/components/navigation/NavDrawer.cjs +2 -0
- package/dist/components/navigation/NavDrawer.cjs.map +1 -0
- package/dist/components/navigation/NavDrawer.context.cjs +2 -0
- package/dist/components/navigation/NavDrawer.context.cjs.map +1 -0
- package/dist/components/navigation/NavDrawer.context.mjs +11 -0
- package/dist/components/navigation/NavDrawer.context.mjs.map +1 -0
- package/dist/components/navigation/NavDrawer.mjs +179 -0
- package/dist/components/navigation/NavDrawer.mjs.map +1 -0
- package/dist/components/overlays/Dialog.cjs +1 -1
- package/dist/components/overlays/Dialog.cjs.map +1 -1
- package/dist/components/overlays/Dialog.mjs +188 -123
- package/dist/components/overlays/Dialog.mjs.map +1 -1
- package/dist/components/overlays/Dialog.shared.cjs +1 -1
- package/dist/components/overlays/Dialog.shared.cjs.map +1 -1
- package/dist/components/overlays/Dialog.shared.mjs +157 -81
- package/dist/components/overlays/Dialog.shared.mjs.map +1 -1
- package/dist/components/overlays/Dialog.slots.cjs +2 -0
- package/dist/components/overlays/Dialog.slots.cjs.map +1 -0
- package/dist/components/overlays/Dialog.slots.mjs +129 -0
- package/dist/components/overlays/Dialog.slots.mjs.map +1 -0
- package/dist/components/overlays/Drawer.cjs +1 -1
- package/dist/components/overlays/Drawer.cjs.map +1 -1
- package/dist/components/overlays/Drawer.context.cjs +2 -0
- package/dist/components/overlays/Drawer.context.cjs.map +1 -0
- package/dist/components/overlays/Drawer.context.mjs +29 -0
- package/dist/components/overlays/Drawer.context.mjs.map +1 -0
- package/dist/components/overlays/Drawer.mjs +12 -187
- package/dist/components/overlays/Drawer.mjs.map +1 -1
- package/dist/components/overlays/Drawer.panel.cjs +2 -0
- package/dist/components/overlays/Drawer.panel.cjs.map +1 -0
- package/dist/components/overlays/Drawer.panel.mjs +159 -0
- package/dist/components/overlays/Drawer.panel.mjs.map +1 -0
- package/dist/components/overlays/Drawer.parts.cjs +2 -0
- package/dist/components/overlays/Drawer.parts.cjs.map +1 -0
- package/dist/components/overlays/Drawer.parts.mjs +152 -0
- package/dist/components/overlays/Drawer.parts.mjs.map +1 -0
- package/dist/components/overlays/Drawer.root.cjs +2 -0
- package/dist/components/overlays/Drawer.root.cjs.map +1 -0
- package/dist/components/overlays/Drawer.root.mjs +207 -0
- package/dist/components/overlays/Drawer.root.mjs.map +1 -0
- package/dist/components/overlays/Drawer.scroll.cjs +2 -0
- package/dist/components/overlays/Drawer.scroll.cjs.map +1 -0
- package/dist/components/overlays/Drawer.scroll.mjs +42 -0
- package/dist/components/overlays/Drawer.scroll.mjs.map +1 -0
- package/dist/components/overlays/Popover.cjs +1 -1
- package/dist/components/overlays/Popover.cjs.map +1 -1
- package/dist/components/overlays/Popover.mjs +173 -162
- package/dist/components/overlays/Popover.mjs.map +1 -1
- package/dist/components/overlays/TeachingPopover.cjs +1 -1
- package/dist/components/overlays/TeachingPopover.cjs.map +1 -1
- package/dist/components/overlays/TeachingPopover.mjs +96 -91
- package/dist/components/overlays/TeachingPopover.mjs.map +1 -1
- package/dist/components/overlays/Tooltip.cjs +1 -1
- package/dist/components/overlays/Tooltip.cjs.map +1 -1
- package/dist/components/overlays/Tooltip.mjs +47 -47
- package/dist/components/overlays/Tooltip.mjs.map +1 -1
- package/dist/components/portal/Portal.cjs +1 -1
- package/dist/components/portal/Portal.cjs.map +1 -1
- package/dist/components/portal/Portal.mjs +5 -5
- package/dist/components/table/DataGrid.cjs +1 -1
- package/dist/components/table/DataGrid.cjs.map +1 -1
- package/dist/components/table/DataGrid.mjs +1 -1
- package/dist/hooks/useDismiss.cjs.map +1 -1
- package/dist/hooks/useDismiss.mjs.map +1 -1
- package/dist/hooks/useFocusTrap.cjs +1 -1
- package/dist/hooks/useFocusTrap.cjs.map +1 -1
- package/dist/hooks/useFocusTrap.mjs +115 -98
- package/dist/hooks/useFocusTrap.mjs.map +1 -1
- package/dist/hooks/useFocusVisible.cjs +2 -0
- package/dist/hooks/useFocusVisible.cjs.map +1 -0
- package/dist/hooks/useFocusVisible.mjs +49 -0
- package/dist/hooks/useFocusVisible.mjs.map +1 -0
- package/dist/hooks/useFocusableGroup.cjs +2 -0
- package/dist/hooks/useFocusableGroup.cjs.map +1 -0
- package/dist/hooks/useFocusableGroup.mjs +70 -0
- package/dist/hooks/useFocusableGroup.mjs.map +1 -0
- package/dist/hooks/useModalLayer.cjs +1 -1
- package/dist/hooks/useModalLayer.cjs.map +1 -1
- package/dist/hooks/useModalLayer.mjs +34 -21
- package/dist/hooks/useModalLayer.mjs.map +1 -1
- package/dist/hooks/useModalOpen.cjs +2 -0
- package/dist/hooks/useModalOpen.cjs.map +1 -0
- package/dist/hooks/useModalOpen.mjs +14 -0
- package/dist/hooks/useModalOpen.mjs.map +1 -0
- package/dist/hooks/usePopupPosition.cjs +1 -1
- package/dist/hooks/usePopupPosition.cjs.map +1 -1
- package/dist/hooks/usePopupPosition.mjs +82 -53
- package/dist/hooks/usePopupPosition.mjs.map +1 -1
- package/dist/hooks/useResolvedTarget.cjs +2 -0
- package/dist/hooks/useResolvedTarget.cjs.map +1 -0
- package/dist/hooks/useResolvedTarget.mjs +37 -0
- package/dist/hooks/useResolvedTarget.mjs.map +1 -0
- package/dist/hooks/useRestoreFocus.cjs +1 -1
- package/dist/hooks/useRestoreFocus.cjs.map +1 -1
- package/dist/hooks/useRestoreFocus.mjs +91 -78
- package/dist/hooks/useRestoreFocus.mjs.map +1 -1
- package/dist/hooks/useRovingGrid.cjs +1 -1
- package/dist/hooks/useRovingGrid.cjs.map +1 -1
- package/dist/hooks/useRovingGrid.mjs +8 -57
- package/dist/hooks/useRovingGrid.mjs.map +1 -1
- package/dist/hooks/useRovingTabIndex.cjs +1 -1
- package/dist/hooks/useRovingTabIndex.cjs.map +1 -1
- package/dist/hooks/useRovingTabIndex.mjs +180 -121
- package/dist/hooks/useRovingTabIndex.mjs.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +3070 -269
- package/dist/index.d.ts +3070 -269
- package/dist/index.mjs +127 -107
- package/dist/lib/classNames.cjs +1 -1
- package/dist/lib/classNames.cjs.map +1 -1
- package/dist/lib/classNames.mjs +137 -77
- package/dist/lib/classNames.mjs.map +1 -1
- package/dist/lib/icons.cjs +1 -1
- package/dist/lib/icons.cjs.map +1 -1
- package/dist/lib/icons.mjs +13 -6
- package/dist/lib/icons.mjs.map +1 -1
- package/dist/lib/layers.cjs +1 -1
- package/dist/lib/layers.cjs.map +1 -1
- package/dist/lib/layers.mjs +120 -111
- package/dist/lib/layers.mjs.map +1 -1
- package/dist/styles.css +1 -1
- package/package.json +1 -1
- package/src/styles/tokens.css +25 -0
|
@@ -1 +1 @@
|
|
|
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":"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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 { FocusMode, 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?: FocusMode;\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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"}
|
|
@@ -1 +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:
|
|
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 { FocusMode, 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: FocusMode;\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"}
|
|
@@ -1 +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:
|
|
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 { FocusMode, 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: FocusMode;\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 +1 @@
|
|
|
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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"}
|
|
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 { FocusMode, 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?: FocusMode;\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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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use client";const e=require("
|
|
1
|
+
"use client";const e=require("./TagPicker.option.cjs"),t=require("./TagPicker.parts.cjs"),n=require("./TagPicker.root.cjs");var r=Object.assign(n.TagPickerRoot,{Control:t.TagPickerControl,Group:t.TagPickerGroup,Input:t.TagPickerInput,Button:t.TagPickerButton,List:t.TagPickerList,Option:e.TagPickerOption,OptionGroup:t.TagPickerOptionGroup});exports.TagPicker=r,exports.TagPickerButton=t.TagPickerButton,exports.TagPickerControl=t.TagPickerControl,exports.TagPickerGroup=t.TagPickerGroup,exports.TagPickerInput=t.TagPickerInput,exports.TagPickerList=t.TagPickerList,exports.TagPickerOption=e.TagPickerOption,exports.TagPickerOptionGroup=t.TagPickerOptionGroup;
|
|
2
2
|
//# sourceMappingURL=TagPicker.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TagPicker.cjs","names":["React","cn","tagPickerClassNames","focusRing","DismissIcon","useFieldContext","useFieldControl","isInvalidLook","useInputLook","useControllable","EMPTY_VALUES","useIsClient","useId","useListbox","useListboxPopup","useMergedRefs","sameValues","getArrowIntent","getDirection","inputAppearanceClasses","inputFocusWithin","joinIds","composeEventHandlers","ListboxSurface","Option","HiddenInput","require_runtime","require_cn","require_dev","require_composeEventHandlers","require_classNames","require_useControllable","require_useId","require_direction","require_useMergedRefs","require_useIsClient","require_aria","require_useFieldControl","require_useAnnounce","require_useListbox","require_styles","require_icons","require_inputLook","require_Input","require_useFormReset","require_HiddenInput","require_Option","require_pickerLabels","require_pickerValues","require_usePreserveFocus","react","react_jsx_runtime","defaultRemoveLabel","label","defaultSummaryLabel","labels","matchesText","item","text","TAG_PICKER_SIZES","TAG_PICKER_SIZE","TagRemoveButton","ref","getFallback","TagPicker","valueProp","openProp","queryProp","sizeProp","appearanceProp","ariaLabel","ariaLabelledBy","ariaDescribedBy","ariaInvalid","ariaRequired","ariaErrorMessage","ariaDetails","rest","props","onChange","field","validates","required","readOnly","fieldProps","invalidLook","sizeClasses","size","selected","setSelected","defaultValue","list","next","onValueChange","interactive","disabled","openState","setOpen","defaultOpen","onOpenChange","isClient","open","queryState","setQuery","defaultQuery","onQueryChange","query","lock","setLock","lockedOpen","rootRef","inputRef","summaryId","labelByValue","map","option","options","labelOf","value","available","chosen","listFilter","filter","unknownValues","v","getInput","focusInput","addTag","removeTag","listbox","expanded","noMatchesText","surfaceOpen","noMatches","rootMergedRef","inputMergedRef","controlRef","initial","current","form","removeButtons","from","handleInputKeyDown","event","handleTagKeyDown","buttons","index","intent","listLabelledBy","appearance","className","setReference","placeholder","onKeyDown","onKeyUp"],"sources":["../../../src/components/input/TagPicker.tsx"],"sourcesContent":["import * as React from 'react';\nimport { cn } from '../../lib/cn';\nimport { joinIds } from '../../lib/aria';\nimport { tagPickerClassNames } from '../../lib/classNames';\nimport { composeEventHandlers } from '../../lib/composeEventHandlers';\nimport { warnDeprecated, warnOnce } from '../../lib/dev';\nimport { getArrowIntent, getDirection } from '../../lib/direction';\nimport { DismissIcon } from '../../lib/icons';\nimport {\n focusRing,\n inputAppearanceClasses,\n inputFocusWithin,\n inputInvalidWithin,\n} from '../../lib/styles';\nimport type { InputAppearance, Size } from '../../lib/types';\nimport { useAnnounce } from '../../hooks/useAnnounce';\nimport { useControllable } from '../../hooks/useControllable';\nimport { useFieldContext, useFieldControl } from '../../hooks/useFieldControl';\nimport { useFormReset } from '../../hooks/useFormReset';\nimport { useId } from '../../hooks/useId';\nimport { useIsClient } from '../../hooks/useIsClient';\nimport { useListbox, type ListboxItem } from '../../hooks/useListbox';\nimport { useMergedRefs } from '../../hooks/useMergedRefs';\nimport { usePreserveFocus } from '../../hooks/usePreserveFocus';\nimport { HiddenInput } from '../internal/HiddenInput';\nimport { useInputLook } from './inputLook';\nimport { isInvalidLook } from './Input';\nimport { ListboxSurface, Option, useListboxPopup } from './Option';\nimport { announceToggle } from './pickerLabels';\nimport { EMPTY_VALUES, sameValues } from './pickerValues';\nimport type { RoutedHandlers } from './routedHandlers';\n\n/** Represents a single selectable tag option. */\nexport interface TagPickerOption {\n /** Unique identifier for the option. */\n value: string;\n /** Display label for the option. */\n label: string;\n}\n\n/**\n * The TagPicker's built-in names, descriptions and announcements, for localization. Each member is\n * optional and falls back to its English default.\n */\nexport interface TagPickerLabels {\n /** Name of a tag's remove button.\n * @default (label) => `Remove ${label}`\n */\n remove?: (label: string) => string;\n /** Name of the list of selected tags.\n * @default 'Selected'\n */\n selected?: string;\n /** Description of the input that sums up the selected tags (their labels, in order).\n * @default (labels) => `Selected: ${labels.join(', ')}`\n */\n summary?: (labels: string[]) => string;\n /** Announcement when a tag is added; `count` is the number of tags after the change.\n * @default (label, count) => `${label} added, ${count} selected`\n */\n added?: (label: string, count: number) => string;\n /** Announcement when a tag is removed; `count` is the number of tags after the change.\n * @default (label, count) => `${label} removed, ${count} selected`\n */\n removed?: (label: string, count: number) => string;\n /** Status text (announced, and shown in the popup) when the typed text matches no option.\n * @default 'No matches'\n */\n noMatches?: string;\n}\n\nconst defaultRemoveLabel = (label: string) => `Remove ${label}`;\nconst defaultSummaryLabel = (labels: string[]) => `Selected: ${labels.join(', ')}`;\n\n/**\n * How the picker came to be locked (`disabled` or `readOnly`): not at all, by a change while\n * mounted, or since it mounted.\n */\ntype LockState = 'unlocked' | 'locked' | 'mounted-locked';\n\n/** The default `filter` (0.7's match): a case-insensitive substring of the option's label. */\nfunction matchesText(item: ListboxItem, text: string): boolean {\n return item.label.toLowerCase().includes(text.toLowerCase());\n}\n\n/** Properties for the TagPicker component. */\nexport interface TagPickerProps extends Omit<\n React.HTMLAttributes<HTMLDivElement>,\n 'onChange' | 'defaultValue' | RoutedHandlers\n> {\n /** Available options to choose from. */\n options: readonly TagPickerOption[];\n /** Controlled array of selected option values (`[]` for none). */\n value?: readonly string[];\n /**\n * Initial selected values for uncontrolled usage; a form reset restores them.\n * @default []\n */\n defaultValue?: readonly string[];\n /**\n * Called with the new selection when it changes: a tag is added or removed, or a form reset\n * restores different tags.\n */\n onValueChange?: (value: string[]) => void;\n /**\n * Called with the new selection when it changes: a tag is added or removed, or a form reset\n * restores different tags.\n * @deprecated Use `onValueChange`.\n */\n onChange?: (value: string[]) => void;\n /**\n * Controlled open state of the option list. The list renders only in the browser: an open\n * picker is closed in the server HTML and opens once it has hydrated.\n */\n open?: boolean;\n /**\n * Initial open state for uncontrolled usage. A picker that starts disabled or read-only starts\n * closed. The list renders only in the browser: it is closed in the server HTML and opens once\n * the picker has hydrated.\n * @default false\n */\n defaultOpen?: boolean;\n /** Called when the option list opens or closes. */\n onOpenChange?: (open: boolean) => void;\n /**\n * Placeholder text shown when no tags are selected.\n * @default 'Select...'\n */\n placeholder?: string;\n /**\n * Whether an option matches the typed text (the query). Called with every listed option (its\n * `value` and `label`; selected options are not listed) and the text whenever the text is not\n * empty; an option it returns `false` for is filtered out. It may keep options that do not\n * contain the text: `filter={() => true}` with `query` and `onQueryChange` leaves the matching\n * to you (a server-side search that replaces `options`), and a filter that always keeps an\n * option of your own gives a \"Create …\" entry. With a server-side search, keep the selected\n * options in `options` (they are never listed): a selected value without an option shows its raw\n * value as the tag label, with a development warning (the \"Async search\" story does this).\n * @default a case-insensitive substring match on the option's `label`\n */\n filter?: (option: ListboxItem, query: string) => boolean;\n /**\n * Controlled query: the text typed since the last tag was added, which filters the options and\n * shows in the input (hidden while `disabled` or `readOnly`).\n */\n query?: string;\n /**\n * Initial query for uncontrolled usage. A TagPicker that starts disabled or read-only starts\n * without it (as it starts closed).\n * @default ''\n */\n defaultQuery?: string;\n /**\n * Called with the new query when it changes: as the user types, and with `''` when it resets (a\n * tag added, Escape on the closed list, a form reset, or `disabled` or `readOnly` turned on\n * while text is typed). A blur or a close keeps the text. A TagPicker that mounts disabled or\n * read-only reports nothing: it keeps a controlled query, which shows once it unlocks.\n */\n onQueryChange?: (query: string) => void;\n /**\n * Whether the tag picker is disabled: nothing can be added or removed, and the remove buttons\n * leave the tab order.\n * @default false\n */\n disabled?: boolean;\n /**\n * Size of the tags and the field: `medium` (the 0.7 look), `large` or `extra-large` (Fluent's\n * union; TagPicker has no `small`). Default: the surrounding Field's `size`, else `WaveProvider\n * inputDefaults.size`, else `'medium'`; a Field or provider `small` gives `'medium'` too. The\n * option list keeps its size.\n */\n size?: TagPickerSize;\n /**\n * Look of the field: `outline` (a full border), `underline` (a bottom stroke only),\n * `filled-darker` or `filled-lighter` (a fill without a visible stroke: give the field a visible\n * label). Default: `WaveProvider inputDefaults.appearance`, else `'outline'`.\n */\n appearance?: InputAppearance;\n /** Name of the values in form submissions (one hidden input per value). */\n name?: string;\n /** Id of the form the values belong to, when the TagPicker is outside it. */\n form?: string;\n /**\n * At least one tag is required to submit the form (native constraint validation). Like a native\n * readonly input, a `readOnly` TagPicker does not block submission.\n */\n required?: boolean;\n /**\n * The `autocomplete` attribute of the `<input role=\"combobox\">`. Browser autofill is off unless\n * you set it (for example `'on'`).\n * @default 'off'\n */\n autoComplete?: string;\n /** The maximum length of the typed text (`maxlength` of the `<input role=\"combobox\">`). */\n maxLength?: number;\n /**\n * The selection cannot be changed: the input is read-only, the tags have no remove buttons, and\n * the option list neither opens (click, keyboard, a controlled `open`) nor adds tags; Escape is\n * left to the page. Turning it (or `disabled`) on while the list is open closes it\n * (`onOpenChange(false)`); a focused remove button hands focus to the input.\n */\n readOnly?: boolean;\n /**\n * Names of the remove buttons and the tag list, the summary that describes the input, the\n * announcements and the \"No matches\" text, for localization. Unset members keep their English\n * defaults.\n */\n labels?: TagPickerLabels;\n /** Called when the `<input role=\"combobox\">` receives focus (the root keeps other handlers). */\n onFocus?: React.FocusEventHandler<HTMLInputElement>;\n /** Called when the `<input role=\"combobox\">` loses focus. */\n onBlur?: React.FocusEventHandler<HTMLInputElement>;\n /**\n * Called on a key press in the `<input role=\"combobox\">`, before the built-in listbox and tag\n * keys; `event.preventDefault()` skips them.\n */\n onKeyDown?: React.KeyboardEventHandler<HTMLInputElement>;\n /** Called when a key is released in the `<input role=\"combobox\">`. */\n onKeyUp?: React.KeyboardEventHandler<HTMLInputElement>;\n /** Ref to the `<input role=\"combobox\">` (the focusable element). */\n controlRef?: React.Ref<HTMLInputElement>;\n /** Ref to the root `<div>`. */\n ref?: React.Ref<HTMLDivElement>;\n}\n\n/** Sizes of TagPicker (Fluent's): medium (the 0.7 look), large and extra-large. */\nexport type TagPickerSize = Extract<Size, 'medium' | 'large' | 'extra-large'>;\n\nconst TAG_PICKER_SIZES: readonly TagPickerSize[] = ['medium', 'large', 'extra-large'];\n\n/** Per-size classes of the control, the tags and the input (medium is the 0.7 look). */\nconst TAG_PICKER_SIZE: Readonly<\n Record<TagPickerSize, { control: string; tag: string; input: string }>\n> = {\n medium: {\n control: 'gap-1 px-2 py-1.5',\n tag: 'px-2 py-0.5 text-body-1',\n input: 'py-0.5 text-body-1',\n },\n large: {\n control: 'gap-1.5 px-2.5 py-2',\n tag: 'px-2 py-1 text-body-1',\n input: 'py-1 text-body-1',\n },\n 'extra-large': {\n control: 'gap-1.5 px-3 py-2.5',\n tag: 'px-2.5 py-1 text-body-2',\n input: 'py-1 text-body-2',\n },\n};\n\ninterface TagRemoveButtonProps {\n /** The accessible name of the button. */\n label: string;\n disabled: boolean;\n onClick: () => void;\n onKeyDown: React.KeyboardEventHandler<HTMLButtonElement>;\n /** The element that receives focus when this button unmounts while focused (the input). */\n getFallback: () => HTMLElement | null;\n}\n\n/**\n * A tag's remove button. When it unmounts while focused (`readOnly` turned on, or a controlled\n * value dropped its tag), focus moves to the input instead of falling to `<body>` (C-DISABLED).\n */\nfunction TagRemoveButton({\n label,\n disabled,\n onClick,\n onKeyDown,\n getFallback,\n}: TagRemoveButtonProps) {\n const ref = React.useRef<HTMLButtonElement | null>(null);\n usePreserveFocus(ref, getFallback);\n return (\n <button\n ref={ref}\n type=\"button\"\n data-wave-tagpicker-remove=\"\"\n disabled={disabled}\n aria-label={label}\n className={cn(\n tagPickerClassNames.removeButton,\n // Padding and background set here (C-NATIVE), not left to an app-wide rule.\n 'ms-0.5 inline-flex rounded-sm bg-transparent p-0 text-muted-foreground not-disabled:not-aria-disabled:hover:text-foreground disabled:cursor-not-allowed',\n focusRing,\n )}\n onClick={onClick}\n onKeyDown={onKeyDown}\n >\n <DismissIcon size={12} />\n </button>\n );\n}\n\n/**\n * A multi-select combobox that shows the selected values as removable tags. Typing filters the\n * options and makes the first match active; ArrowDown/ArrowUp move the highlight\n * (`aria-activedescendant`), Enter adds the highlighted option and keeps the list open (with\n * nothing highlighted — no typed text, or text that matches no option — Enter is left to the\n * surrounding form), Escape closes the list (and then clears the typed text). Backspace in the\n * empty input moves focus to the last tag; Backspace or Delete there removes it. Additions and\n * removals are announced (\"Cherry removed, 2 selected\"), and so is \"No matches\" for text that\n * matches no option. `filter` replaces the match (it may keep options that do not contain the\n * text, for a server-side search or a \"Create …\" entry), and `query`/`defaultQuery`/\n * `onQueryChange` control the typed text, which resets to `''` when a tag is added, on Escape and\n * on a form reset, and stays on a blur.\n *\n * The tags form a list named \"Selected\"; the input is described by a summary of the selected\n * labels (\"Selected: Apple, Banana\"). These built-in texts are English; `labels` localizes them.\n * The `<input>` receives `id`, `aria-label`, `aria-labelledby`, `aria-describedby`,\n * `aria-invalid`, `aria-required`, `aria-errormessage`, `aria-details`, `tabIndex`, `autoFocus`,\n * `onFocus`/`onBlur`/`onKeyDown`/`onKeyUp` and the text input attributes `autoComplete`,\n * `autoCapitalize`, `autoCorrect`, `maxLength`, `inputMode`, `spellCheck` and `enterKeyHint`.\n * `ref`, `className`, `style`, other `aria-*` attributes and the remaining props stay on the root\n * `<div>`. Inside a `Field` the input is labelled and described by it. The tag area shows the\n * error look whenever the input ends up `aria-invalid` (its own `aria-invalid` or a `Field`\n * error). With `name`/`required` the values take part in form submission, validation and reset.\n * Selected values without a matching option are shown with their raw value. The open list renders\n * only in the browser: an open list (`defaultOpen`, `open`) is closed in the server HTML and opens\n * once the picker has hydrated.\n *\n * **Size and appearance**: `size` resolves from its own prop, then the surrounding `Field`'s\n * `size`, then `WaveProvider inputDefaults.size`, else `'medium'` (a Field or provider `small`\n * gives `'medium'` too, since TagPicker has no `small`); `appearance` from its own prop, then\n * `WaveProvider inputDefaults.appearance`, else `'outline'`; both render as `data-size` and\n * `data-appearance` on the root `<div>`. The option list keeps its size.\n */\nexport const TagPicker = (props: TagPickerProps) => {\n const {\n options,\n value: valueProp,\n defaultValue,\n onValueChange,\n onChange,\n open: openProp,\n defaultOpen,\n onOpenChange,\n placeholder = 'Select...',\n filter,\n query: queryProp,\n defaultQuery,\n onQueryChange,\n disabled = false,\n size: sizeProp,\n appearance: appearanceProp,\n name,\n form,\n required,\n autoComplete = 'off',\n autoCapitalize,\n autoCorrect,\n maxLength,\n readOnly,\n labels,\n inputMode,\n spellCheck,\n enterKeyHint,\n autoFocus,\n tabIndex,\n id,\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledBy,\n 'aria-describedby': ariaDescribedBy,\n 'aria-invalid': ariaInvalid,\n 'aria-required': ariaRequired,\n 'aria-errormessage': ariaErrorMessage,\n 'aria-details': ariaDetails,\n onFocus,\n onBlur,\n onKeyDown,\n onKeyUp,\n controlRef,\n className,\n ref,\n ...rest\n } = props;\n\n if (onChange !== undefined) warnDeprecated('TagPicker', 'onChange', 'onValueChange');\n\n const field = useFieldContext();\n const isRequired = required ?? field?.required ?? false;\n // Like a native readonly input, a read-only TagPicker is barred from constraint validation (the\n // user could not fix it); its values are still submitted.\n const validates = isRequired && !readOnly;\n const fieldProps = useFieldControl({\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 // The error look follows the resolved state: the consumer's `aria-invalid` or the Field's.\n const invalidLook = isInvalidLook(false, fieldProps['aria-invalid']);\n const { size, appearance } = useInputLook(sizeProp, appearanceProp, {\n sizes: TAG_PICKER_SIZES,\n defaultSize: 'medium',\n });\n // A size outside TAG_PICKER_SIZES (from untyped code) is skipped by useInputLook, so `size` is\n // always one of them and the data attribute carries the resolved value.\n const sizeClasses = TAG_PICKER_SIZE[size];\n\n const [selected, setSelected] = useControllable<readonly string[]>(\n valueProp,\n defaultValue ?? EMPTY_VALUES,\n (next) => {\n // The props are read only; the callbacks receive an array of their own.\n const list = [...next];\n onValueChange?.(list);\n onChange?.(list);\n },\n );\n const interactive = !disabled && !readOnly;\n // A picker that starts disabled or read-only never shows its list, so it starts closed (no close\n // to report later).\n const [openState, setOpen] = useControllable(\n openProp,\n (defaultOpen ?? false) && interactive,\n onOpenChange,\n );\n // The open list lives in a portal, which renders only in the browser: until then (the server\n // HTML, hydration) the picker shows the closed inline list and reports it closed, so\n // aria-controls and aria-activedescendant never name a missing element.\n const isClient = useIsClient();\n const open = openState && interactive && isClient;\n // The query (D12): the text typed since the last tag was added, which filters the options. A\n // picker that starts locked starts without a query, as it starts closed.\n const [queryState, setQuery] = useControllable(\n queryProp,\n interactive ? (defaultQuery ?? '') : '',\n onQueryChange,\n );\n // Locking the control (readOnly/disabled) while typing drops the typed text: hidden during\n // render here, and the reset reported from an effect, since `onQueryChange` never runs during\n // render (D12). `lock` is how the picker came to be locked (previous-value pattern, C-HOOKS):\n // `'locked'` by a change while mounted, whose reset is reported once, or `'mounted-locked'`\n // since it mounted, which reports nothing and keeps a controlled query, hidden until the picker\n // unlocks (R20).\n const query = interactive ? queryState : '';\n const [lock, setLock] = React.useState<LockState>(interactive ? 'unlocked' : 'mounted-locked');\n if (interactive && lock !== 'unlocked') setLock('unlocked');\n else if (!interactive && lock === 'unlocked') setLock('locked');\n React.useEffect(() => {\n if (lock === 'locked') setQuery('');\n }, [lock, setQuery]);\n // Locking also closes the list itself, not only the derived `open`, so unlocking does not reopen\n // it without a user action. The close is reported through onOpenChange (a consumer callback from\n // an effect, C-HOOKS); a controlled `open` that stays true is still not shown while locked.\n const lockedOpen = !interactive && openState;\n React.useEffect(() => {\n if (lockedOpen) setOpen(false);\n }, [lockedOpen, setOpen]);\n // Keeps the shared live regions alive while mounted: every addition and removal is announced\n // (`announceToggle`).\n useAnnounce();\n\n const rootRef = React.useRef<HTMLDivElement | null>(null);\n const inputRef = React.useRef<HTMLInputElement | null>(null);\n const summaryId = useId('tagpicker-summary');\n\n const labelByValue = React.useMemo(() => {\n const map = new Map<string, string>();\n for (const option of options) if (!map.has(option.value)) map.set(option.value, option.label);\n return map;\n }, [options]);\n const labelOf = (value: string) => labelByValue.get(value) ?? value;\n\n const available = React.useMemo<ListboxItem[]>(() => {\n const chosen = new Set(selected);\n return options\n .filter((option) => !chosen.has(option.value))\n .map((option) => ({ value: option.value, label: option.label }));\n }, [options, selected]);\n // useListbox's navigability predicate: `filter` (else the 0.7 match) bound to the typed text,\n // while there is any (D13).\n const listFilter = React.useMemo(\n () => (query ? (item: ListboxItem) => (filter ?? matchesText)(item, query) : undefined),\n [query, filter],\n );\n\n // Unknown values render as tags labelled by the raw value (input-pickers#22).\n const unknownValues = selected.filter((value) => !labelByValue.has(value)).join('\\u0000');\n React.useEffect(() => {\n if (!unknownValues) return;\n warnOnce(\n 'TagPicker:unknown-value',\n `TagPicker: the selected value(s) ${unknownValues\n .split('\\u0000')\n .map((v) => `\"${v}\"`)\n .join(', ')} match no option; the raw value is shown as the tag label.`,\n );\n }, [unknownValues]);\n\n const getInput = () => inputRef.current;\n const focusInput = () => inputRef.current?.focus();\n\n const addTag = (value: string) => {\n if (!interactive || selected.includes(value)) return;\n const next = [...selected, value];\n setSelected(next);\n setQuery('');\n announceToggle(labels, labelOf(value), true, next.length);\n };\n\n const removeTag = (value: string) => {\n if (!interactive) return;\n const next = selected.filter((v) => v !== value);\n setSelected(next);\n announceToggle(labels, labelOf(value), false, next.length);\n focusInput();\n };\n\n const listbox = useListbox({\n open,\n onOpenChange: (next) => setOpen(next),\n mode: 'editable',\n multiselect: true,\n selectedValues: selected,\n onSelect: (value) => addTag(value),\n items: available,\n filter: listFilter,\n // Typing a filter makes its first match active (as in Combobox), so Enter adds what the list\n // shows instead of submitting the form. Nothing is active on open or with the text cleared.\n autoHighlight: query ? 'first' : false,\n idPrefix: 'tagpicker-listbox',\n onClearDraft: query ? () => setQuery('') : undefined,\n });\n\n // aria-expanded only while a listbox with options is shown (input-pickers#21).\n const expanded = open && listbox.items.length > 0;\n const noMatchesText = labels?.noMatches ?? 'No matches';\n // The popup shows the options, or \"No matches\" for a query.\n const surfaceOpen = open && (expanded || query !== '');\n const noMatches = surfaceOpen && !expanded;\n const { layerId, setReference, surfaceRef, floatingProps } = useListboxPopup({\n open,\n surfaceOpen,\n onDismiss: () => setOpen(false),\n rootRef,\n anchorRef: inputRef,\n });\n\n const rootMergedRef = useMergedRefs<HTMLDivElement>(rootRef, ref);\n const inputMergedRef = useMergedRefs<HTMLInputElement>(inputRef, controlRef);\n\n useFormReset(\n inputRef,\n () => {\n // Compared by content (C-FORMS): an inline default is a new array on every render, and a\n // reset that keeps the same tags reports nothing.\n const initial = defaultValue ?? EMPTY_VALUES;\n setSelected((current) => (sameValues(current, initial) ? current : [...initial]));\n setQuery('');\n },\n form,\n );\n\n /** The tags' remove buttons, found from an element inside the component (no ref read). */\n const removeButtons = (from: Element) =>\n Array.from(\n from\n .closest('[data-wave-tagpicker-control]')\n ?.querySelectorAll<HTMLButtonElement>('[data-wave-tagpicker-remove]') ?? [],\n );\n\n const handleInputKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => {\n // Read-only: no listbox keys at all (they would open the list, add or remove tags).\n if (!interactive) return;\n if (event.key === 'Escape' && open && !surfaceOpen && !event.nativeEvent.isComposing) {\n // Open with nothing shown (every option selected, no query): close, but leave Escape to an\n // enclosing layer (overlays#1) instead of consuming it for an invisible list.\n setOpen(false);\n return;\n }\n if (event.key === 'Backspace' && query === '' && selected.length > 0) {\n // First Backspace moves to the last tag; Backspace/Delete there removes it (input-pickers#14).\n event.preventDefault();\n removeButtons(event.currentTarget).at(-1)?.focus();\n return;\n }\n listbox.onKeyDown(event);\n };\n\n const handleTagKeyDown = (event: React.KeyboardEvent<HTMLButtonElement>, value: string) => {\n if (!interactive) return;\n const buttons = removeButtons(event.currentTarget);\n const index = buttons.indexOf(event.currentTarget);\n if (event.key === 'Backspace' || event.key === 'Delete') {\n event.preventDefault();\n removeTag(value);\n return;\n }\n if (event.key === 'Escape') {\n // Consumed here, so an enclosing layer ignores it (spec §5.4).\n event.preventDefault();\n focusInput();\n return;\n }\n const intent = getArrowIntent(event.key, {\n orientation: 'horizontal',\n dir: getDirection(event.currentTarget),\n });\n if (intent === 'prev' && index > 0) {\n event.preventDefault();\n buttons[index - 1].focus();\n } else if (intent === 'next') {\n event.preventDefault();\n if (index < buttons.length - 1) buttons[index + 1].focus();\n else focusInput();\n }\n };\n\n const listLabelledBy =\n fieldProps['aria-label'] === undefined\n ? (fieldProps['aria-labelledby'] ?? field?.labelId)\n : fieldProps['aria-labelledby'];\n\n return (\n <div\n data-size={size}\n data-appearance={appearance}\n {...rest}\n ref={rootMergedRef}\n className={cn(tagPickerClassNames.root, 'relative', className)}\n >\n <div\n ref={setReference}\n data-wave-tagpicker-control=\"\"\n role=\"group\"\n aria-disabled={disabled || undefined}\n className={cn(\n tagPickerClassNames.control,\n 'flex flex-wrap items-center',\n sizeClasses.control,\n inputAppearanceClasses[appearance],\n inputFocusWithin,\n invalidLook && inputInvalidWithin,\n disabled && 'cursor-not-allowed opacity-50',\n )}\n onClick={(event) => {\n if (disabled || (event.target as Element).closest('button')) return;\n focusInput();\n if (!open && interactive) setOpen(true);\n }}\n >\n {selected.length > 0 && (\n <div\n role=\"list\"\n aria-label={labels?.selected ?? 'Selected'}\n className={cn(tagPickerClassNames.group, 'flex flex-wrap items-center gap-1')}\n >\n {selected.map((value) => {\n const label = labelOf(value);\n return (\n <div\n key={value}\n role=\"listitem\"\n className={cn(\n tagPickerClassNames.tag,\n 'inline-flex items-center gap-1 rounded bg-muted text-foreground',\n sizeClasses.tag,\n )}\n >\n {label}\n {!readOnly && (\n <TagRemoveButton\n label={(labels?.remove ?? defaultRemoveLabel)(label)}\n disabled={disabled}\n onClick={() => removeTag(value)}\n onKeyDown={(event) => handleTagKeyDown(event, value)}\n getFallback={getInput}\n />\n )}\n </div>\n );\n })}\n </div>\n )}\n {selected.length > 0 && (\n // Describes the input. The list itself would read every \"Remove …\" button name too.\n <span id={summaryId} hidden>\n {(labels?.summary ?? defaultSummaryLabel)(selected.map(labelOf))}\n </span>\n )}\n <input\n type=\"text\"\n autoComplete={autoComplete}\n {...fieldProps}\n {...listbox.getComboboxProps()}\n aria-expanded={expanded}\n aria-describedby={joinIds(\n fieldProps['aria-describedby'],\n selected.length > 0 ? summaryId : undefined,\n )}\n aria-errormessage={ariaErrorMessage}\n aria-details={ariaDetails}\n ref={inputMergedRef}\n disabled={disabled}\n readOnly={readOnly}\n placeholder={selected.length === 0 ? placeholder : ''}\n autoCapitalize={autoCapitalize}\n autoCorrect={autoCorrect}\n maxLength={maxLength}\n inputMode={inputMode}\n spellCheck={spellCheck}\n enterKeyHint={enterKeyHint}\n autoFocus={autoFocus}\n tabIndex={tabIndex}\n value={query}\n onChange={(event) => {\n if (!interactive) return;\n setQuery(event.target.value);\n if (!open) setOpen(true);\n }}\n onKeyDown={composeEventHandlers(onKeyDown, handleInputKeyDown)}\n onKeyUp={composeEventHandlers(onKeyUp, listbox.onKeyUp)}\n onFocus={onFocus}\n onBlur={onBlur}\n className={cn(\n tagPickerClassNames.input,\n 'min-w-15 flex-1 bg-transparent text-foreground placeholder:text-muted-foreground focus:outline-hidden',\n sizeClasses.input,\n )}\n />\n </div>\n {/* Mounted before its text: a live region added together with its text is not announced by\n every screen reader. The row in the popup is the visible copy. */}\n <span role=\"status\" className=\"sr-only\">\n {noMatches && noMatchesText}\n </span>\n <ListboxSurface\n listbox={listbox}\n layerId={layerId}\n surfaceRef={surfaceRef}\n floatingProps={floatingProps}\n open={open}\n expanded={expanded}\n showCheck={false}\n listClassName={tagPickerClassNames.listbox}\n surfaceClassName={tagPickerClassNames.surface}\n emptyContent={\n query !== '' ? (\n <div\n aria-hidden=\"true\"\n className={cn(\n tagPickerClassNames.emptyMessage,\n 'px-3 py-1.5 text-body-1 text-muted-foreground',\n )}\n >\n {noMatchesText}\n </div>\n ) : undefined\n }\n aria-label={fieldProps['aria-label']}\n aria-labelledby={listLabelledBy}\n >\n {expanded &&\n listbox.items.map((item) => (\n <Option\n key={item.value}\n value={item.value}\n label={item.label}\n className={tagPickerClassNames.option}\n >\n {item.label}\n </Option>\n ))}\n </ListboxSurface>\n <HiddenInput\n name={name}\n form={form}\n disabled={disabled}\n value={selected}\n type=\"text\"\n required={validates}\n onInvalid={focusInput}\n />\n </div>\n );\n};\nTagPicker.displayName = 'TagPicker';\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"TagPicker.cjs","names":["TagPickerRoot","TagPickerControl","TagPickerGroup","TagPickerInput","TagPickerButton","TagPickerList","TagPickerOption","TagPickerOptionGroup","require_TagPicker_option","require_TagPicker_parts","require_TagPicker_root","TagPicker"],"sources":["../../../src/components/input/TagPicker.tsx"],"sourcesContent":["import { TagPickerRoot } from './TagPicker.root';\nimport {\n TagPickerButton,\n TagPickerControl,\n TagPickerGroup,\n TagPickerInput,\n TagPickerList,\n TagPickerOptionGroup,\n} from './TagPicker.parts';\nimport { TagPickerOption } from './TagPicker.option';\n\nexport type { TagPickerLabels, TagPickerProps, TagPickerSize } from './TagPicker.root';\nexport type {\n TagPickerButtonProps,\n TagPickerControlProps,\n TagPickerGroupProps,\n TagPickerInputProps,\n TagPickerListProps,\n} from './TagPicker.parts';\nexport type { TagPickerOptionProps } from './TagPicker.option';\n\n/**\n * A multi-select combobox that shows the selected values as removable tags.\n *\n * - **Two forms.** The array form, `<TagPicker options={…} />`, is the parts with their defaults:\n * `TagPicker.Control` (holding `TagPicker.Group` and `TagPicker.Input`) and `TagPicker.List`.\n * The parts form replaces only the part you need: your own Tags in `TagPicker.Group` (an\n * Avatar in each), rich `TagPicker.Option`s in `TagPicker.List`, or `TagPicker.Button`, a\n * select-only trigger, in place of the Input. Render `TagPicker.Control` and `TagPicker.List`\n * directly inside TagPicker (a Fragment is fine); without a List the default list is added.\n * `options` names the values in both forms (`media` and `secondaryContent` show in the default\n * options, `media` in the default tags too); with a List that has children, its options are\n * the options, and the options of selected values stay rendered (TagPicker hides them).\n * - **Keyboard.** Typing filters the options (`filter`, by default a case-insensitive match on\n * `textValue ?? label`); the option whose label equals the typed text becomes active, else the\n * first match. ArrowDown/ArrowUp move the highlight (`aria-activedescendant`), Enter adds the\n * active option and keeps the list open (with nothing active, Enter is left to the surrounding\n * form), Escape closes the list (and then clears the typed text). Backspace in the empty input,\n * and Left (Right in RTL) with the caret at its start, focus the last tag; Delete, Backspace,\n * Enter or Space on a remove button remove its tag and focus the next tag, else the input; a\n * click on one focuses the input. Additions and removals are announced (\"Cherry removed, 2\n * selected\"), and so is \"No matches\" for text that matches no option.\n * - **Free tagging.** With `allowCreate`, text that matches no option label, no selected value\n * (ignoring case) and no option value ends the list with a create option (`Create \"infra\"`);\n * Enter on it or a click adds the text as a tag after `onOptionCreate(text)` and clears the\n * text.\n * - **End buttons.** A chevron (`expandIcon`, `false` hides it) opens and closes the list without\n * taking focus; `clearable` adds a clear button, a Tab stop after the input, which removes every\n * tag. A press on the field's empty area toggles the list.\n * - **One line.** `overflow=\"count\"` keeps the tags on one line while focus is outside the picker\n * and its list is closed; the tags that do not fit give way to \"+N\".\n * - **Names.** The tags form a list named \"Selected\"; the trigger is described by a summary of the\n * selected labels (\"Selected: Apple, Banana\"). These built-in texts are English; `labels`\n * localizes them.\n * - **Routing.** The trigger (`TagPicker.Input` or `TagPicker.Button`) receives `id`,\n * `aria-label`, `aria-labelledby`, `aria-describedby`, `aria-invalid`, `aria-required`,\n * `aria-errormessage`, `aria-details`, `tabIndex` and `autoFocus`; the Input also\n * `onFocus`/`onBlur`/`onKeyDown`/`onKeyUp`, `controlRef` and the text input attributes\n * `autoComplete`, `autoCapitalize`, `autoCorrect`, `maxLength`, `inputMode`, `spellCheck` and\n * `enterKeyHint` (with the Button, pass handlers and `ref` on it). `ref`, `className`, `style`,\n * other `aria-*` attributes and the remaining props stay on the root `<div>`. Inside a `Field`\n * the trigger is labelled and described by it; the field shows the error look whenever the\n * trigger ends up `aria-invalid`. With `name`/`required` the values take part in form\n * submission, validation and reset. Selected values without a matching option show their raw\n * value.\n * - **Size and appearance**: `size` resolves from its own prop, then the surrounding `Field`'s\n * `size`, then `WaveProvider inputDefaults.size`, else `'medium'` (a Field or provider `small`\n * gives `'medium'` too, since TagPicker has no `small`); `appearance` from its own prop, then\n * `WaveProvider inputDefaults.appearance`, else `'outline'`; both render as `data-size` and\n * `data-appearance` on the root `<div>`, and the parts take neither. The tags are one Tag size\n * smaller. The option list keeps its size.\n * - **Server rendering.** The open list renders only in the browser: an open list (`defaultOpen`,\n * `open`) is closed in the server HTML and opens once the picker has hydrated; the tags of\n * registered options show their labels in the server HTML.\n *\n * Fluent's `selectedOptions` and `onOptionSelect` are `value` and `onValueChange` (plus\n * `onOptionCreate`). `TagPickerOption` is both the type of an `options` entry and the flat name of\n * `TagPicker.Option`.\n *\n * @example\n * <TagPicker aria-label=\"Fruits\" options={[{ value: 'apple', label: 'Apple' }]} clearable />\n *\n * @example\n * <TagPicker aria-label=\"People\" value={people} onValueChange={setPeople}>\n * <TagPicker.Control>\n * <TagPicker.Group>\n * {people.map((id) => (\n * <Tag key={id} value={id} media={<Avatar name={nameOf(id)} />} dismissLabel=\"Remove\">\n * {nameOf(id)}\n * </Tag>\n * ))}\n * </TagPicker.Group>\n * <TagPicker.Input />\n * </TagPicker.Control>\n * <TagPicker.List>\n * <TagPicker.Option value=\"katri\" label=\"Katri Athokas\" secondaryContent=\"Designer\">\n * Katri Athokas\n * </TagPicker.Option>\n * </TagPicker.List>\n * </TagPicker>\n */\nexport const TagPicker = /* @__PURE__ */ Object.assign(TagPickerRoot, {\n Control: TagPickerControl,\n Group: TagPickerGroup,\n Input: TagPickerInput,\n Button: TagPickerButton,\n List: TagPickerList,\n Option: TagPickerOption,\n OptionGroup: TagPickerOptionGroup,\n});\n\nexport {\n TagPickerControl,\n TagPickerGroup,\n TagPickerInput,\n TagPickerButton,\n TagPickerList,\n // The component (`TagPicker.Option`) and the interface of an `options` entry, one name (D64).\n TagPickerOption,\n TagPickerOptionGroup,\n};\n"],"mappings":"4HAqGA,IAAaW,EAA4B,OAAO,OAAOX,EAAAA,cAAe,CACpE,QAASC,EAAAA,iBACT,MAAOC,EAAAA,eACP,MAAOC,EAAAA,eACP,OAAQC,EAAAA,gBACR,KAAMC,EAAAA,cACN,OAAQC,EAAAA,gBACR,YAAaC,EAAAA,oBACf,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);r.displayName=`TagPickerContext`;var i=n.createContext(null);i.displayName=`TagPickerControlContext`;function a(e){let i=n.useContext(r);return i||t.reportMissingContext(e,`TagPicker`),i}function o(e,r){let a=n.useContext(i);return!a&&r&&t.reportMissingContext(e,`TagPicker.Control`),a}exports.TagPickerContext=r,exports.TagPickerControlContext=i,exports.useTagPickerContext=a,exports.useTagPickerControlContext=o;
|
|
2
|
+
//# sourceMappingURL=TagPicker.context.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TagPicker.context.cjs","names":["React","require_runtime","require_dev","react","TagPickerContext","TagPickerControlContext","useTagPickerContext","context","part","useTagPickerControlContext","inPicker"],"sources":["../../../src/components/input/TagPicker.context.ts"],"sourcesContent":["import * as React from 'react';\nimport { reportMissingContext } from '../../lib/dev';\nimport type { CoreSize, InputAppearance, TagAppearance, TagSize } from '../../lib/types';\nimport type { UseListboxPopupResult } from './Option';\nimport type { UseListboxResult } from '../../hooks/useListbox';\nimport type { Slot } from '../../lib/slot';\nimport type { TagPickerOption } from './TagPicker.option';\nimport type { TagPickerSize } from './TagPicker.root';\n\n/*\n * The contexts of TagPicker's parts: the root's state (TagPickerContext) and the field the\n * trigger draws in (TagPickerControlContext). Module-only (never exported from a barrel); it\n * imports no component.\n */\n\n/** Which part is the combobox: the text field (`TagPicker.Input`) or a button (`TagPicker.Button`). */\nexport type TagPickerTriggerKind = 'input' | 'button';\n\n/** The built-in texts, resolved (every member set). */\nexport interface ResolvedTagPickerLabels {\n remove: (label: string) => string;\n selected: string;\n create: (text: string) => string;\n clear: string;\n expand: string;\n overflowCount: (count: number) => string;\n noMatches: string;\n}\n\n/** The attributes the root routes to its trigger part, whichever it is (C-ROUTING). */\nexport interface TagPickerTriggerProps {\n id?: string;\n 'aria-label'?: string;\n 'aria-labelledby'?: string;\n /** The root's and the Field's description (the part joins its own first and the summary last). */\n 'aria-describedby'?: string;\n 'aria-invalid'?: React.AriaAttributes['aria-invalid'];\n 'aria-required'?: React.AriaAttributes['aria-required'];\n 'aria-errormessage'?: string;\n 'aria-details'?: string;\n tabIndex?: number;\n autoFocus?: boolean;\n}\n\n/** The root's props that reach `TagPicker.Input` only (its `<input>`). */\nexport interface TagPickerInputOnlyProps {\n autoComplete?: string;\n autoCapitalize?: string;\n autoCorrect?: string;\n maxLength?: number;\n inputMode?: React.HTMLAttributes<HTMLInputElement>['inputMode'];\n spellCheck?: React.HTMLAttributes<HTMLInputElement>['spellCheck'];\n enterKeyHint?: React.InputHTMLAttributes<HTMLInputElement>['enterKeyHint'];\n onFocus?: React.FocusEventHandler<HTMLInputElement>;\n onBlur?: React.FocusEventHandler<HTMLInputElement>;\n onKeyDown?: React.KeyboardEventHandler<HTMLInputElement>;\n onKeyUp?: React.KeyboardEventHandler<HTMLInputElement>;\n controlRef?: React.Ref<HTMLInputElement>;\n}\n\n/** What TagPicker gives its parts. */\nexport interface TagPickerContextValue {\n /** The resolved size and appearance (the root's `data-size` and `data-appearance`). */\n size: TagPickerSize;\n appearance: InputAppearance;\n /** The size of the end buttons' box and glyph: medium, else large. */\n coreSize: CoreSize;\n /** The tags' size and appearance for the picker's look (D54). */\n tagSize: TagSize;\n tagAppearance: TagAppearance;\n disabled: boolean;\n readOnly: boolean;\n /** Neither disabled nor read-only. */\n interactive: boolean;\n /** Whether the field shows the error look. */\n invalidLook: boolean;\n /** The selected values, in order. */\n selected: readonly string[];\n /** The label of a value: its option's, else the raw value. */\n labelOf: (value: string) => string;\n /** The `options` entry of a value (its label, `media` and `secondaryContent`). */\n entryOf: (value: string) => TagPickerOption | undefined;\n labels: ResolvedTagPickerLabels;\n placeholder: string;\n options: readonly TagPickerOption[];\n /** Whether the default tags warn for selected values without an option (D58's 0.10 configuration). */\n warnsUnknownValues: boolean;\n /** Whether the listbox is in data mode (no `TagPicker.List` children). */\n dataMode: boolean;\n listbox: UseListboxResult;\n /** The popup (open state, list shown with options or the create option). */\n open: boolean;\n expanded: boolean;\n /** The typed text (always `''` while locked). */\n query: string;\n /** The popup surface shows: the list, or \"No matches\" for typed text. */\n surfaceOpen: boolean;\n /** The create option: shown, its text, its reserved value and its name. */\n showCreate: boolean;\n createText: string;\n createValue: string;\n /** The \"No matches\" row of the popup, while the open list has text and nothing to show. */\n emptyContent: boolean;\n layerId: string;\n surfaceRef: UseListboxPopupResult['surfaceRef'];\n floatingProps: UseListboxPopupResult['floatingProps'];\n /** The listbox's name: TagPicker's (the List's own pair replaces it). */\n listLabel: { 'aria-label'?: string; 'aria-labelledby'?: string };\n triggerProps: TagPickerTriggerProps;\n inputProps: TagPickerInputOnlyProps;\n /** The summary's id while tags exist (it describes the trigger). */\n summaryId: string | undefined;\n /** The trigger element (the Input or the Button). */\n triggerRef: React.RefObject<HTMLElement | null>;\n /** Places the popup against the Control (as wide as the field): merged into its ref. */\n setReference: (element: HTMLElement | null) => void;\n /** The control element, the tag list and the \"+N\" chip (the single-line layout measures them). */\n controlRef: React.RefObject<HTMLDivElement | null>;\n groupRef: React.RefObject<HTMLDivElement | null>;\n chipRef: React.RefObject<HTMLSpanElement | null>;\n /** Registers a trigger part from its layout effect; returns the remover. */\n registerTrigger: (kind: TagPickerTriggerKind) => () => void;\n /** Registers a List part from its layout effect; returns the remover. */\n registerList: () => () => void;\n triggerKind: TagPickerTriggerKind;\n setOpen: (open: boolean) => void;\n /** Opens a closed list, closes an open one. */\n toggleOpen: () => void;\n focusTrigger: () => void;\n /** Removes a tag (a dismissal of the tag list, D56); announced. */\n removeTag: (value: string) => void;\n /** Removes every tag, clears the text, closes the list and focuses the trigger (D61). */\n clear: () => void;\n /** A user edit of the input's text: the query, the exact-match ranking and the open state. */\n editText: (text: string) => void;\n /** Focuses the last focusable control of the tag list; `false` when there is none. */\n focusLastTagControl: () => boolean;\n /** The root's `expandIcon` and `clearable`. */\n expandIcon: Slot<'span'> | undefined;\n clearable: boolean;\n /** The single-line layout: the mode, whether it is collapsed, the hidden values and the count. */\n overflow: 'wrap' | 'count';\n collapsed: boolean;\n hiddenValues: ReadonlySet<string> | undefined;\n}\n\n/** Internal: read with {@link useTagPickerContext}. `null` outside a TagPicker. */\nexport const TagPickerContext = React.createContext<TagPickerContextValue | null>(null);\nTagPickerContext.displayName = 'TagPickerContext';\n\n/** What `TagPicker.Control` gives its trigger part. */\nexport interface TagPickerControlContextValue {\n /** Registers the trigger with the root (the kind decides the listbox mode). */\n registerTrigger: (kind: TagPickerTriggerKind) => () => void;\n}\n\n/** Internal: read with {@link useTagPickerControlContext}. `null` outside a TagPicker.Control. */\nexport const TagPickerControlContext = React.createContext<TagPickerControlContextValue | null>(\n null,\n);\nTagPickerControlContext.displayName = 'TagPickerControlContext';\n\n/**\n * TagPicker's context for one of its parts. Outside a TagPicker it throws in development\n * (`[WaveUI] TagPicker.Control must be used within TagPicker`) and logs once in production,\n * returning `null`: the part then renders nothing.\n *\n * @param part The part's dotted name (`'TagPicker.Control'`).\n */\nexport function useTagPickerContext(part: string): TagPickerContextValue | null {\n const context = React.useContext(TagPickerContext);\n if (!context) reportMissingContext(part, 'TagPicker');\n return context;\n}\n\n/**\n * The context of the field a trigger part draws in, for a part inside a TagPicker (`inPicker`).\n * Outside a TagPicker.Control it throws in development\n * (`[WaveUI] TagPicker.Input must be used within TagPicker.Control`) and logs once in production,\n * returning `null`: the part then renders nothing. Outside a TagPicker the root's check has\n * reported already, so nothing more is reported.\n *\n * @param part The part's dotted name (`'TagPicker.Input'`).\n * @param inPicker Whether the part has TagPicker's context.\n */\nexport function useTagPickerControlContext(\n part: string,\n inPicker: boolean,\n): TagPickerControlContextValue | null {\n const context = React.useContext(TagPickerControlContext);\n if (!context && inPicker) reportMissingContext(part, 'TagPicker.Control');\n return context;\n}\n"],"mappings":"4IAmJA,IAAaI,EAAmBJ,EAAM,cAA4C,IAAI,EACtF,EAAiB,YAAc,mBAS/B,IAAaK,EAA0BL,EAAM,cAC3C,IACF,EACA,EAAwB,YAAc,0BAStC,SAAgBM,EAAoB,EAA4C,CAC9E,IAAMC,EAAUP,EAAM,WAAWI,CAAgB,EAEjD,OADKG,GAASL,EAAA,qBAAqBM,EAAM,WAAW,EAC7CD,CACT,CAYA,SAAgBE,EACd,EACA,EACqC,CACrC,IAAMF,EAAUP,EAAM,WAAWK,CAAuB,EAExD,MADI,CAACE,GAAWG,GAAUR,EAAA,qBAAqBM,EAAM,mBAAmB,EACjED,CACT"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { reportMissingContext as e } from "../../lib/dev.mjs";
|
|
3
|
+
import * as t from "react";
|
|
4
|
+
//#region src/components/input/TagPicker.context.ts
|
|
5
|
+
var n = t.createContext(null);
|
|
6
|
+
n.displayName = "TagPickerContext";
|
|
7
|
+
var r = t.createContext(null);
|
|
8
|
+
r.displayName = "TagPickerControlContext";
|
|
9
|
+
function i(r) {
|
|
10
|
+
let i = t.useContext(n);
|
|
11
|
+
return i || e(r, "TagPicker"), i;
|
|
12
|
+
}
|
|
13
|
+
function a(n, i) {
|
|
14
|
+
let a = t.useContext(r);
|
|
15
|
+
return !a && i && e(n, "TagPicker.Control"), a;
|
|
16
|
+
}
|
|
17
|
+
//#endregion
|
|
18
|
+
export { n as TagPickerContext, r as TagPickerControlContext, i as useTagPickerContext, a as useTagPickerControlContext };
|
|
19
|
+
|
|
20
|
+
//# sourceMappingURL=TagPicker.context.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TagPicker.context.mjs","names":["React","TagPickerContext","TagPickerControlContext","useTagPickerContext","context","reportMissingContext","part","useTagPickerControlContext","inPicker"],"sources":["../../../src/components/input/TagPicker.context.ts"],"sourcesContent":["import * as React from 'react';\nimport { reportMissingContext } from '../../lib/dev';\nimport type { CoreSize, InputAppearance, TagAppearance, TagSize } from '../../lib/types';\nimport type { UseListboxPopupResult } from './Option';\nimport type { UseListboxResult } from '../../hooks/useListbox';\nimport type { Slot } from '../../lib/slot';\nimport type { TagPickerOption } from './TagPicker.option';\nimport type { TagPickerSize } from './TagPicker.root';\n\n/*\n * The contexts of TagPicker's parts: the root's state (TagPickerContext) and the field the\n * trigger draws in (TagPickerControlContext). Module-only (never exported from a barrel); it\n * imports no component.\n */\n\n/** Which part is the combobox: the text field (`TagPicker.Input`) or a button (`TagPicker.Button`). */\nexport type TagPickerTriggerKind = 'input' | 'button';\n\n/** The built-in texts, resolved (every member set). */\nexport interface ResolvedTagPickerLabels {\n remove: (label: string) => string;\n selected: string;\n create: (text: string) => string;\n clear: string;\n expand: string;\n overflowCount: (count: number) => string;\n noMatches: string;\n}\n\n/** The attributes the root routes to its trigger part, whichever it is (C-ROUTING). */\nexport interface TagPickerTriggerProps {\n id?: string;\n 'aria-label'?: string;\n 'aria-labelledby'?: string;\n /** The root's and the Field's description (the part joins its own first and the summary last). */\n 'aria-describedby'?: string;\n 'aria-invalid'?: React.AriaAttributes['aria-invalid'];\n 'aria-required'?: React.AriaAttributes['aria-required'];\n 'aria-errormessage'?: string;\n 'aria-details'?: string;\n tabIndex?: number;\n autoFocus?: boolean;\n}\n\n/** The root's props that reach `TagPicker.Input` only (its `<input>`). */\nexport interface TagPickerInputOnlyProps {\n autoComplete?: string;\n autoCapitalize?: string;\n autoCorrect?: string;\n maxLength?: number;\n inputMode?: React.HTMLAttributes<HTMLInputElement>['inputMode'];\n spellCheck?: React.HTMLAttributes<HTMLInputElement>['spellCheck'];\n enterKeyHint?: React.InputHTMLAttributes<HTMLInputElement>['enterKeyHint'];\n onFocus?: React.FocusEventHandler<HTMLInputElement>;\n onBlur?: React.FocusEventHandler<HTMLInputElement>;\n onKeyDown?: React.KeyboardEventHandler<HTMLInputElement>;\n onKeyUp?: React.KeyboardEventHandler<HTMLInputElement>;\n controlRef?: React.Ref<HTMLInputElement>;\n}\n\n/** What TagPicker gives its parts. */\nexport interface TagPickerContextValue {\n /** The resolved size and appearance (the root's `data-size` and `data-appearance`). */\n size: TagPickerSize;\n appearance: InputAppearance;\n /** The size of the end buttons' box and glyph: medium, else large. */\n coreSize: CoreSize;\n /** The tags' size and appearance for the picker's look (D54). */\n tagSize: TagSize;\n tagAppearance: TagAppearance;\n disabled: boolean;\n readOnly: boolean;\n /** Neither disabled nor read-only. */\n interactive: boolean;\n /** Whether the field shows the error look. */\n invalidLook: boolean;\n /** The selected values, in order. */\n selected: readonly string[];\n /** The label of a value: its option's, else the raw value. */\n labelOf: (value: string) => string;\n /** The `options` entry of a value (its label, `media` and `secondaryContent`). */\n entryOf: (value: string) => TagPickerOption | undefined;\n labels: ResolvedTagPickerLabels;\n placeholder: string;\n options: readonly TagPickerOption[];\n /** Whether the default tags warn for selected values without an option (D58's 0.10 configuration). */\n warnsUnknownValues: boolean;\n /** Whether the listbox is in data mode (no `TagPicker.List` children). */\n dataMode: boolean;\n listbox: UseListboxResult;\n /** The popup (open state, list shown with options or the create option). */\n open: boolean;\n expanded: boolean;\n /** The typed text (always `''` while locked). */\n query: string;\n /** The popup surface shows: the list, or \"No matches\" for typed text. */\n surfaceOpen: boolean;\n /** The create option: shown, its text, its reserved value and its name. */\n showCreate: boolean;\n createText: string;\n createValue: string;\n /** The \"No matches\" row of the popup, while the open list has text and nothing to show. */\n emptyContent: boolean;\n layerId: string;\n surfaceRef: UseListboxPopupResult['surfaceRef'];\n floatingProps: UseListboxPopupResult['floatingProps'];\n /** The listbox's name: TagPicker's (the List's own pair replaces it). */\n listLabel: { 'aria-label'?: string; 'aria-labelledby'?: string };\n triggerProps: TagPickerTriggerProps;\n inputProps: TagPickerInputOnlyProps;\n /** The summary's id while tags exist (it describes the trigger). */\n summaryId: string | undefined;\n /** The trigger element (the Input or the Button). */\n triggerRef: React.RefObject<HTMLElement | null>;\n /** Places the popup against the Control (as wide as the field): merged into its ref. */\n setReference: (element: HTMLElement | null) => void;\n /** The control element, the tag list and the \"+N\" chip (the single-line layout measures them). */\n controlRef: React.RefObject<HTMLDivElement | null>;\n groupRef: React.RefObject<HTMLDivElement | null>;\n chipRef: React.RefObject<HTMLSpanElement | null>;\n /** Registers a trigger part from its layout effect; returns the remover. */\n registerTrigger: (kind: TagPickerTriggerKind) => () => void;\n /** Registers a List part from its layout effect; returns the remover. */\n registerList: () => () => void;\n triggerKind: TagPickerTriggerKind;\n setOpen: (open: boolean) => void;\n /** Opens a closed list, closes an open one. */\n toggleOpen: () => void;\n focusTrigger: () => void;\n /** Removes a tag (a dismissal of the tag list, D56); announced. */\n removeTag: (value: string) => void;\n /** Removes every tag, clears the text, closes the list and focuses the trigger (D61). */\n clear: () => void;\n /** A user edit of the input's text: the query, the exact-match ranking and the open state. */\n editText: (text: string) => void;\n /** Focuses the last focusable control of the tag list; `false` when there is none. */\n focusLastTagControl: () => boolean;\n /** The root's `expandIcon` and `clearable`. */\n expandIcon: Slot<'span'> | undefined;\n clearable: boolean;\n /** The single-line layout: the mode, whether it is collapsed, the hidden values and the count. */\n overflow: 'wrap' | 'count';\n collapsed: boolean;\n hiddenValues: ReadonlySet<string> | undefined;\n}\n\n/** Internal: read with {@link useTagPickerContext}. `null` outside a TagPicker. */\nexport const TagPickerContext = React.createContext<TagPickerContextValue | null>(null);\nTagPickerContext.displayName = 'TagPickerContext';\n\n/** What `TagPicker.Control` gives its trigger part. */\nexport interface TagPickerControlContextValue {\n /** Registers the trigger with the root (the kind decides the listbox mode). */\n registerTrigger: (kind: TagPickerTriggerKind) => () => void;\n}\n\n/** Internal: read with {@link useTagPickerControlContext}. `null` outside a TagPicker.Control. */\nexport const TagPickerControlContext = React.createContext<TagPickerControlContextValue | null>(\n null,\n);\nTagPickerControlContext.displayName = 'TagPickerControlContext';\n\n/**\n * TagPicker's context for one of its parts. Outside a TagPicker it throws in development\n * (`[WaveUI] TagPicker.Control must be used within TagPicker`) and logs once in production,\n * returning `null`: the part then renders nothing.\n *\n * @param part The part's dotted name (`'TagPicker.Control'`).\n */\nexport function useTagPickerContext(part: string): TagPickerContextValue | null {\n const context = React.useContext(TagPickerContext);\n if (!context) reportMissingContext(part, 'TagPicker');\n return context;\n}\n\n/**\n * The context of the field a trigger part draws in, for a part inside a TagPicker (`inPicker`).\n * Outside a TagPicker.Control it throws in development\n * (`[WaveUI] TagPicker.Input must be used within TagPicker.Control`) and logs once in production,\n * returning `null`: the part then renders nothing. Outside a TagPicker the root's check has\n * reported already, so nothing more is reported.\n *\n * @param part The part's dotted name (`'TagPicker.Input'`).\n * @param inPicker Whether the part has TagPicker's context.\n */\nexport function useTagPickerControlContext(\n part: string,\n inPicker: boolean,\n): TagPickerControlContextValue | null {\n const context = React.useContext(TagPickerControlContext);\n if (!context && inPicker) reportMissingContext(part, 'TagPicker.Control');\n return context;\n}\n"],"mappings":";;;;AAmJA,IAAaC,IAAmBD,EAAM,cAA4C,IAAI;AACtF,EAAiB,cAAc;AAS/B,IAAaE,IAA0BF,EAAM,cAC3C,IACF;AACA,EAAwB,cAAc;AAStC,SAAgBG,EAAoB,GAA4C;CAC9E,IAAMC,IAAUJ,EAAM,WAAWC,CAAgB;CAEjD,OADKG,KAASC,EAAqBC,GAAM,WAAW,GAC7CF;AACT;AAYA,SAAgBG,EACd,GACA,GACqC;CACrC,IAAMH,IAAUJ,EAAM,WAAWE,CAAuB;CAExD,OADI,CAACE,KAAWI,KAAUH,EAAqBC,GAAM,mBAAmB,GACjEF;AACT"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use client";function e(e,t){for(let n of e)if(n.toLowerCase()===t)return!0;return!1}function t(t,n){let r=t.trim();if(r===``)return null;let i=r.toLowerCase();if(e(n.labels,i)||e(n.selected,i))return null;for(let e of n.values)if(e===r)return null;return r}function n(e,t,n){let r=e.trim().toLowerCase();if(r===``)return null;for(let{value:e,label:i}of t)if(!n.has(e)&&i.toLowerCase()===r)return e;return null}exports.createOptionText=t,exports.findExactMatch=n;
|
|
2
|
+
//# sourceMappingURL=TagPicker.create.cjs.map
|