@proyecto-viviana/solidaria-components 0.3.1 → 0.4.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/dist/ActionBar.js +184 -0
- package/dist/ActionBar.js.map +1 -0
- package/dist/ActionBar.jsx +128 -0
- package/dist/ActionBar.jsx.map +1 -0
- package/dist/ActionGroup.js +179 -0
- package/dist/ActionGroup.js.map +1 -0
- package/dist/ActionGroup.jsx +129 -0
- package/dist/ActionGroup.jsx.map +1 -0
- package/dist/Alert.js +111 -0
- package/dist/Alert.js.map +1 -0
- package/dist/Alert.jsx +82 -0
- package/dist/Alert.jsx.map +1 -0
- package/dist/Autocomplete.js +130 -0
- package/dist/Autocomplete.js.map +1 -0
- package/dist/Autocomplete.jsx +116 -0
- package/dist/Autocomplete.jsx.map +1 -0
- package/dist/Breadcrumbs.d.ts.map +1 -1
- package/dist/Breadcrumbs.js +334 -0
- package/dist/Breadcrumbs.js.map +1 -0
- package/dist/Breadcrumbs.jsx +266 -0
- package/dist/Breadcrumbs.jsx.map +1 -0
- package/dist/Button.d.ts.map +1 -1
- package/dist/Button.js +348 -0
- package/dist/Button.js.map +1 -0
- package/dist/Button.jsx +314 -0
- package/dist/Button.jsx.map +1 -0
- package/dist/Calendar.d.ts +4 -4
- package/dist/Calendar.d.ts.map +1 -1
- package/dist/Calendar.js +538 -0
- package/dist/Calendar.js.map +1 -0
- package/dist/Calendar.jsx +333 -0
- package/dist/Calendar.jsx.map +1 -0
- package/dist/CalendarPicker.d.ts +33 -0
- package/dist/CalendarPicker.d.ts.map +1 -0
- package/dist/CalendarPicker.js +44 -0
- package/dist/CalendarPicker.js.map +1 -0
- package/dist/CalendarPicker.jsx +44 -0
- package/dist/CalendarPicker.jsx.map +1 -0
- package/dist/Checkbox.d.ts +83 -4
- package/dist/Checkbox.d.ts.map +1 -1
- package/dist/Checkbox.js +923 -0
- package/dist/Checkbox.js.map +1 -0
- package/dist/Checkbox.jsx +707 -0
- package/dist/Checkbox.jsx.map +1 -0
- package/dist/Collection.d.ts.map +1 -1
- package/dist/Collection.js +202 -0
- package/dist/Collection.js.map +1 -0
- package/dist/Collection.jsx +152 -0
- package/dist/Collection.jsx.map +1 -0
- package/dist/Color.d.ts.map +1 -1
- package/dist/Color.js +1720 -0
- package/dist/Color.js.map +1 -0
- package/dist/Color.jsx +1344 -0
- package/dist/Color.jsx.map +1 -0
- package/dist/ColorEditor.js +208 -0
- package/dist/ColorEditor.js.map +1 -0
- package/dist/ColorEditor.jsx +120 -0
- package/dist/ColorEditor.jsx.map +1 -0
- package/dist/ComboBox.d.ts +8 -5
- package/dist/ComboBox.d.ts.map +1 -1
- package/dist/ComboBox.js +992 -0
- package/dist/ComboBox.js.map +1 -0
- package/dist/ComboBox.jsx +714 -0
- package/dist/ComboBox.jsx.map +1 -0
- package/dist/ContextualHelpTrigger.js +146 -0
- package/dist/ContextualHelpTrigger.js.map +1 -0
- package/dist/ContextualHelpTrigger.jsx +109 -0
- package/dist/ContextualHelpTrigger.jsx.map +1 -0
- package/dist/DateField.d.ts +3 -3
- package/dist/DateField.d.ts.map +1 -1
- package/dist/DateField.js +4 -0
- package/dist/DateField.jsx +4 -0
- package/dist/DateField2.js +499 -0
- package/dist/DateField2.js.map +1 -0
- package/dist/DateField2.jsx +317 -0
- package/dist/DateField2.jsx.map +1 -0
- package/dist/DatePicker.d.ts +4 -4
- package/dist/DatePicker.d.ts.map +1 -1
- package/dist/DatePicker.js +991 -0
- package/dist/DatePicker.js.map +1 -0
- package/dist/DatePicker.jsx +682 -0
- package/dist/DatePicker.jsx.map +1 -0
- package/dist/Dialog.d.ts.map +1 -1
- package/dist/Dialog.js +337 -0
- package/dist/Dialog.js.map +1 -0
- package/dist/Dialog.jsx +192 -0
- package/dist/Dialog.jsx.map +1 -0
- package/dist/Disclosure.d.ts.map +1 -1
- package/dist/Disclosure.js +328 -0
- package/dist/Disclosure.js.map +1 -0
- package/dist/Disclosure.jsx +230 -0
- package/dist/Disclosure.jsx.map +1 -0
- package/dist/DragAndDrop.d.ts.map +1 -1
- package/dist/DragAndDrop.js +176 -0
- package/dist/DragAndDrop.js.map +1 -0
- package/dist/DragAndDrop.jsx +160 -0
- package/dist/DragAndDrop.jsx.map +1 -0
- package/dist/DropZone.d.ts.map +1 -1
- package/dist/DropZone.js +189 -0
- package/dist/DropZone.js.map +1 -0
- package/dist/DropZone.jsx +144 -0
- package/dist/DropZone.jsx.map +1 -0
- package/dist/FieldError.js +66 -0
- package/dist/FieldError.js.map +1 -0
- package/dist/FieldError.jsx +47 -0
- package/dist/FieldError.jsx.map +1 -0
- package/dist/FileTrigger.js +79 -0
- package/dist/FileTrigger.js.map +1 -0
- package/dist/FileTrigger.jsx +49 -0
- package/dist/FileTrigger.jsx.map +1 -0
- package/dist/Focusable.js +70 -0
- package/dist/Focusable.js.map +1 -0
- package/dist/Focusable.jsx +69 -0
- package/dist/Focusable.jsx.map +1 -0
- package/dist/Form.js +99 -0
- package/dist/Form.js.map +1 -0
- package/dist/Form.jsx +73 -0
- package/dist/Form.jsx.map +1 -0
- package/dist/GridList.d.ts +34 -2
- package/dist/GridList.d.ts.map +1 -1
- package/dist/GridList.js +723 -0
- package/dist/GridList.js.map +1 -0
- package/dist/GridList.jsx +552 -0
- package/dist/GridList.jsx.map +1 -0
- package/dist/HiddenTimeInput.js +104 -0
- package/dist/HiddenTimeInput.js.map +1 -0
- package/dist/HiddenTimeInput.jsx +69 -0
- package/dist/HiddenTimeInput.jsx.map +1 -0
- package/dist/Icon.d.ts.map +1 -1
- package/dist/Icon.js +127 -0
- package/dist/Icon.js.map +1 -0
- package/dist/Icon.jsx +72 -0
- package/dist/Icon.jsx.map +1 -0
- package/dist/Keyboard.js +30 -0
- package/dist/Keyboard.js.map +1 -0
- package/dist/Keyboard.jsx +24 -0
- package/dist/Keyboard.jsx.map +1 -0
- package/dist/Landmark.js +134 -0
- package/dist/Landmark.js.map +1 -0
- package/dist/Landmark.jsx +118 -0
- package/dist/Landmark.jsx.map +1 -0
- package/dist/Link.d.ts.map +1 -1
- package/dist/Link.js +219 -0
- package/dist/Link.js.map +1 -0
- package/dist/Link.jsx +189 -0
- package/dist/Link.jsx.map +1 -0
- package/dist/ListBox.d.ts.map +1 -1
- package/dist/ListBox.js +670 -0
- package/dist/ListBox.js.map +1 -0
- package/dist/ListBox.jsx +508 -0
- package/dist/ListBox.jsx.map +1 -0
- package/dist/Menu.d.ts +27 -9
- package/dist/Menu.d.ts.map +1 -1
- package/dist/Menu.js +1254 -0
- package/dist/Menu.js.map +1 -0
- package/dist/Menu.jsx +1042 -0
- package/dist/Menu.jsx.map +1 -0
- package/dist/Meter.d.ts.map +1 -1
- package/dist/Meter.js +123 -0
- package/dist/Meter.js.map +1 -0
- package/dist/Meter.jsx +107 -0
- package/dist/Meter.jsx.map +1 -0
- package/dist/Modal.d.ts.map +1 -1
- package/dist/Modal.js +380 -0
- package/dist/Modal.js.map +1 -0
- package/dist/Modal.jsx +314 -0
- package/dist/Modal.jsx.map +1 -0
- package/dist/NumberField.d.ts +3 -3
- package/dist/NumberField.d.ts.map +1 -1
- package/dist/NumberField.js +573 -0
- package/dist/NumberField.js.map +1 -0
- package/dist/NumberField.jsx +443 -0
- package/dist/NumberField.jsx.map +1 -0
- package/dist/Popover.d.ts +10 -2
- package/dist/Popover.d.ts.map +1 -1
- package/dist/Popover.js +464 -0
- package/dist/Popover.js.map +1 -0
- package/dist/Popover.jsx +333 -0
- package/dist/Popover.jsx.map +1 -0
- package/dist/Pressable.js +69 -0
- package/dist/Pressable.js.map +1 -0
- package/dist/Pressable.jsx +68 -0
- package/dist/Pressable.jsx.map +1 -0
- package/dist/ProgressBar.d.ts.map +1 -1
- package/dist/ProgressBar.js +130 -0
- package/dist/ProgressBar.js.map +1 -0
- package/dist/ProgressBar.jsx +114 -0
- package/dist/ProgressBar.jsx.map +1 -0
- package/dist/RadioGroup.d.ts +82 -4
- package/dist/RadioGroup.d.ts.map +1 -1
- package/dist/RadioGroup.js +931 -0
- package/dist/RadioGroup.js.map +1 -0
- package/dist/RadioGroup.jsx +681 -0
- package/dist/RadioGroup.jsx.map +1 -0
- package/dist/RangeCalendar.d.ts.map +1 -1
- package/dist/RangeCalendar.js +410 -0
- package/dist/RangeCalendar.js.map +1 -0
- package/dist/RangeCalendar.jsx +253 -0
- package/dist/RangeCalendar.jsx.map +1 -0
- package/dist/RouterProvider.js +118 -0
- package/dist/RouterProvider.js.map +1 -0
- package/dist/RouterProvider.jsx +112 -0
- package/dist/RouterProvider.jsx.map +1 -0
- package/dist/SearchField.d.ts +2 -2
- package/dist/SearchField.d.ts.map +1 -1
- package/dist/SearchField.js +643 -0
- package/dist/SearchField.js.map +1 -0
- package/dist/SearchField.jsx +526 -0
- package/dist/SearchField.jsx.map +1 -0
- package/dist/Select.d.ts.map +1 -1
- package/dist/Select.js +1031 -0
- package/dist/Select.js.map +1 -0
- package/dist/Select.jsx +744 -0
- package/dist/Select.jsx.map +1 -0
- package/dist/SelectionIndicator.d.ts.map +1 -1
- package/dist/SelectionIndicator.js +86 -0
- package/dist/SelectionIndicator.js.map +1 -0
- package/dist/SelectionIndicator.jsx +50 -0
- package/dist/SelectionIndicator.jsx.map +1 -0
- package/dist/Separator.js +97 -0
- package/dist/Separator.js.map +1 -0
- package/dist/Separator.jsx +85 -0
- package/dist/Separator.jsx.map +1 -0
- package/dist/SharedElementTransition.d.ts.map +1 -1
- package/dist/SharedElementTransition.js +165 -0
- package/dist/SharedElementTransition.js.map +1 -0
- package/dist/SharedElementTransition.jsx +138 -0
- package/dist/SharedElementTransition.jsx.map +1 -0
- package/dist/Slider.d.ts +33 -1
- package/dist/Slider.d.ts.map +1 -1
- package/dist/Slider.js +515 -0
- package/dist/Slider.js.map +1 -0
- package/dist/Slider.jsx +403 -0
- package/dist/Slider.jsx.map +1 -0
- package/dist/StepList.js +198 -0
- package/dist/StepList.js.map +1 -0
- package/dist/StepList.jsx +141 -0
- package/dist/StepList.jsx.map +1 -0
- package/dist/Switch.d.ts +65 -2
- package/dist/Switch.d.ts.map +1 -1
- package/dist/Switch.js +534 -0
- package/dist/Switch.js.map +1 -0
- package/dist/Switch.jsx +393 -0
- package/dist/Switch.jsx.map +1 -0
- package/dist/Table.d.ts +48 -0
- package/dist/Table.d.ts.map +1 -1
- package/dist/Table.js +1759 -0
- package/dist/Table.js.map +1 -0
- package/dist/Table.jsx +1348 -0
- package/dist/Table.jsx.map +1 -0
- package/dist/Tabs.d.ts +0 -4
- package/dist/Tabs.d.ts.map +1 -1
- package/dist/Tabs.js +595 -0
- package/dist/Tabs.js.map +1 -0
- package/dist/Tabs.jsx +367 -0
- package/dist/Tabs.jsx.map +1 -0
- package/dist/TagGroup.d.ts.map +1 -1
- package/dist/TagGroup.js +378 -0
- package/dist/TagGroup.js.map +1 -0
- package/dist/TagGroup.jsx +270 -0
- package/dist/TagGroup.jsx.map +1 -0
- package/dist/Text.d.ts +18 -6
- package/dist/Text.d.ts.map +1 -1
- package/dist/Text.js +42 -0
- package/dist/Text.js.map +1 -0
- package/dist/Text.jsx +35 -0
- package/dist/Text.jsx.map +1 -0
- package/dist/TextField.d.ts +7 -6
- package/dist/TextField.d.ts.map +1 -1
- package/dist/TextField.js +436 -0
- package/dist/TextField.js.map +1 -0
- package/dist/TextField.jsx +403 -0
- package/dist/TextField.jsx.map +1 -0
- package/dist/TimeField.d.ts +3 -3
- package/dist/TimeField.d.ts.map +1 -1
- package/dist/TimeField.js +372 -0
- package/dist/TimeField.js.map +1 -0
- package/dist/TimeField.jsx +224 -0
- package/dist/TimeField.jsx.map +1 -0
- package/dist/Toast.d.ts +14 -0
- package/dist/Toast.d.ts.map +1 -1
- package/dist/Toast.js +551 -0
- package/dist/Toast.js.map +1 -0
- package/dist/Toast.jsx +361 -0
- package/dist/Toast.jsx.map +1 -0
- package/dist/ToggleButton.d.ts.map +1 -1
- package/dist/ToggleButton.js +123 -0
- package/dist/ToggleButton.js.map +1 -0
- package/dist/ToggleButton.jsx +88 -0
- package/dist/ToggleButton.jsx.map +1 -0
- package/dist/ToggleButtonGroup.d.ts.map +1 -1
- package/dist/ToggleButtonGroup.js +114 -0
- package/dist/ToggleButtonGroup.js.map +1 -0
- package/dist/ToggleButtonGroup.jsx +85 -0
- package/dist/ToggleButtonGroup.jsx.map +1 -0
- package/dist/Toolbar.js +112 -0
- package/dist/Toolbar.js.map +1 -0
- package/dist/Toolbar.jsx +92 -0
- package/dist/Toolbar.jsx.map +1 -0
- package/dist/Tooltip.d.ts.map +1 -1
- package/dist/Tooltip.js +539 -0
- package/dist/Tooltip.js.map +1 -0
- package/dist/Tooltip.jsx +465 -0
- package/dist/Tooltip.jsx.map +1 -0
- package/dist/Tree.d.ts +14 -2
- package/dist/Tree.d.ts.map +1 -1
- package/dist/Tree.js +1424 -0
- package/dist/Tree.js.map +1 -0
- package/dist/Tree.jsx +1172 -0
- package/dist/Tree.jsx.map +1 -0
- package/dist/Virtualizer.d.ts +16 -2
- package/dist/Virtualizer.d.ts.map +1 -1
- package/dist/Virtualizer.js +2 -0
- package/dist/Virtualizer.jsx +2 -0
- package/dist/Virtualizer2.js +751 -0
- package/dist/Virtualizer2.js.map +1 -0
- package/dist/Virtualizer2.jsx +730 -0
- package/dist/Virtualizer2.jsx.map +1 -0
- package/dist/VirtualizerLayouts.d.ts +18 -0
- package/dist/VirtualizerLayouts.d.ts.map +1 -1
- package/dist/VisuallyHidden.js +42 -0
- package/dist/VisuallyHidden.js.map +1 -0
- package/dist/VisuallyHidden.jsx +35 -0
- package/dist/VisuallyHidden.jsx.map +1 -0
- package/dist/contexts.js +33 -0
- package/dist/contexts.js.map +1 -0
- package/dist/contexts.jsx +33 -0
- package/dist/contexts.jsx.map +1 -0
- package/dist/index.d.ts +7 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +70 -23711
- package/dist/index.jsx +70 -18116
- package/dist/useDragAndDrop.js +2 -0
- package/dist/useDragAndDrop.jsx +2 -0
- package/dist/useDragAndDrop2.js +395 -0
- package/dist/useDragAndDrop2.js.map +1 -0
- package/dist/useDragAndDrop2.jsx +395 -0
- package/dist/useDragAndDrop2.jsx.map +1 -0
- package/dist/utils.d.ts +83 -11
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +285 -0
- package/dist/utils.js.map +1 -0
- package/dist/utils.jsx +277 -0
- package/dist/utils.jsx.map +1 -0
- package/dist/virtualizer/Layout.js +144 -0
- package/dist/virtualizer/Layout.js.map +1 -0
- package/dist/virtualizer/Layout.jsx +144 -0
- package/dist/virtualizer/Layout.jsx.map +1 -0
- package/package.json +401 -4
- package/src/Breadcrumbs.tsx +3 -1
- package/src/Button.tsx +90 -23
- package/src/Calendar.tsx +27 -10
- package/src/CalendarPicker.tsx +73 -0
- package/src/Checkbox.tsx +539 -3
- package/src/Collection.tsx +9 -3
- package/src/Color.tsx +42 -14
- package/src/ComboBox.tsx +126 -14
- package/src/DateField.tsx +20 -2
- package/src/DatePicker.tsx +117 -10
- package/src/Dialog.tsx +13 -5
- package/src/Disclosure.tsx +3 -1
- package/src/DragAndDrop.tsx +3 -1
- package/src/DropZone.tsx +3 -1
- package/src/GridList.tsx +125 -24
- package/src/Icon.tsx +3 -1
- package/src/Link.tsx +3 -1
- package/src/ListBox.tsx +31 -4
- package/src/Menu.tsx +298 -131
- package/src/Meter.tsx +3 -1
- package/src/Modal.tsx +100 -52
- package/src/NumberField.tsx +73 -10
- package/src/Popover.tsx +49 -11
- package/src/ProgressBar.tsx +3 -1
- package/src/RadioGroup.tsx +468 -4
- package/src/RangeCalendar.tsx +3 -1
- package/src/SearchField.tsx +27 -3
- package/src/Select.tsx +22 -7
- package/src/SelectionIndicator.tsx +3 -1
- package/src/SharedElementTransition.tsx +3 -1
- package/src/Slider.tsx +159 -13
- package/src/Switch.tsx +395 -2
- package/src/Table.tsx +409 -95
- package/src/Tabs.tsx +16 -45
- package/src/TagGroup.tsx +4 -1
- package/src/Text.tsx +31 -10
- package/src/TextField.tsx +73 -10
- package/src/TimeField.tsx +20 -2
- package/src/Toast.tsx +79 -14
- package/src/ToggleButton.tsx +3 -1
- package/src/ToggleButtonGroup.tsx +3 -1
- package/src/Tooltip.tsx +55 -8
- package/src/Tree.tsx +77 -9
- package/src/Virtualizer.tsx +180 -31
- package/src/VirtualizerLayouts.ts +45 -10
- package/src/index.ts +50 -0
- package/src/utils.tsx +243 -27
- package/dist/index.js.map +0 -1
- package/dist/index.jsx.map +0 -1
package/src/Menu.tsx
CHANGED
|
@@ -26,6 +26,7 @@ import {
|
|
|
26
26
|
createHover,
|
|
27
27
|
createButton,
|
|
28
28
|
createInteractOutside,
|
|
29
|
+
createScrollIntoViewOnFocus,
|
|
29
30
|
mergeProps,
|
|
30
31
|
FocusScope,
|
|
31
32
|
type AriaMenuProps,
|
|
@@ -86,7 +87,7 @@ export interface MenuRenderProps {
|
|
|
86
87
|
|
|
87
88
|
export interface MenuProps<T>
|
|
88
89
|
extends
|
|
89
|
-
Omit<AriaMenuProps
|
|
90
|
+
Omit<AriaMenuProps<T>, "children">,
|
|
90
91
|
SlotProps,
|
|
91
92
|
Pick<
|
|
92
93
|
MenuStateProps<T>,
|
|
@@ -108,8 +109,10 @@ export interface MenuProps<T>
|
|
|
108
109
|
getDisabled?: (item: T) => boolean;
|
|
109
110
|
/** Keys of disabled items. */
|
|
110
111
|
disabledKeys?: Iterable<Key>;
|
|
111
|
-
/**
|
|
112
|
-
|
|
112
|
+
/** Whether disabled items can still receive focus. */
|
|
113
|
+
disabledBehavior?: "selection" | "all";
|
|
114
|
+
/** Handler called when an item is activated, with the activated item's value. */
|
|
115
|
+
onAction?: (key: Key, value: T) => void;
|
|
113
116
|
/** Handler called when the menu should close. */
|
|
114
117
|
onClose?: () => void;
|
|
115
118
|
/** The children of the component. A function may be provided to render each item. */
|
|
@@ -125,12 +128,9 @@ export interface MenuProps<T>
|
|
|
125
128
|
/** Whether the menu should close when an item is selected. */
|
|
126
129
|
shouldCloseOnSelect?: boolean;
|
|
127
130
|
/** Ref for the menu element. */
|
|
128
|
-
ref?: RefLike<
|
|
131
|
+
ref?: RefLike<HTMLDivElement>;
|
|
129
132
|
/** Custom renderer for the menu element. */
|
|
130
|
-
render?: (
|
|
131
|
-
props: JSX.HTMLAttributes<HTMLUListElement>,
|
|
132
|
-
renderProps: MenuRenderProps,
|
|
133
|
-
) => JSX.Element;
|
|
133
|
+
render?: (props: JSX.HTMLAttributes<HTMLDivElement>, renderProps: MenuRenderProps) => JSX.Element;
|
|
134
134
|
/** Drag and drop hooks from `useDragAndDrop`. */
|
|
135
135
|
dragAndDropHooks?: DragAndDropHooks<T>;
|
|
136
136
|
}
|
|
@@ -154,9 +154,22 @@ export interface MenuItemRenderProps {
|
|
|
154
154
|
hasSubmenu: boolean;
|
|
155
155
|
/** Whether the submenu is currently open. */
|
|
156
156
|
isOpen: boolean;
|
|
157
|
+
/**
|
|
158
|
+
* Internal: props (carrying the slot `id` the item's `aria-describedby`
|
|
159
|
+
* references) for the item's description text element. Threaded to the styled
|
|
160
|
+
* `Text slot="description"` so it receives the id — mirrors upstream's
|
|
161
|
+
* `TextContext` description-slot delegation.
|
|
162
|
+
*/
|
|
163
|
+
descriptionProps?: JSX.HTMLAttributes<HTMLElement>;
|
|
164
|
+
/**
|
|
165
|
+
* Internal: props (id + `aria-hidden`) for the item's keyboard-shortcut
|
|
166
|
+
* element, threaded to the styled `Keyboard`.
|
|
167
|
+
*/
|
|
168
|
+
keyboardShortcutProps?: JSX.HTMLAttributes<HTMLElement>;
|
|
157
169
|
}
|
|
158
170
|
|
|
159
|
-
export interface MenuItemProps<T>
|
|
171
|
+
export interface MenuItemProps<T>
|
|
172
|
+
extends Omit<AriaMenuItemProps, "children" | "key" | "id">, SlotProps {
|
|
160
173
|
/** The unique key for the item. */
|
|
161
174
|
id: Key;
|
|
162
175
|
/** The item value. */
|
|
@@ -185,11 +198,11 @@ export interface MenuItemProps<T> extends Omit<AriaMenuItemProps, "children" | "
|
|
|
185
198
|
onHoverEnd?: () => void;
|
|
186
199
|
/** Handler called when hover state changes. */
|
|
187
200
|
onHoverChange?: (isHovered: boolean) => void;
|
|
188
|
-
/** Ref for the menu item element. */
|
|
189
|
-
ref?: RefLike<
|
|
201
|
+
/** Ref for the menu item element (a `<div>`, or an `<a>` for link items). */
|
|
202
|
+
ref?: RefLike<HTMLElement>;
|
|
190
203
|
/** Custom renderer for the menu item element. */
|
|
191
204
|
render?: (
|
|
192
|
-
props: JSX.HTMLAttributes<
|
|
205
|
+
props: JSX.HTMLAttributes<HTMLElement>,
|
|
193
206
|
renderProps: MenuItemRenderProps,
|
|
194
207
|
) => JSX.Element;
|
|
195
208
|
}
|
|
@@ -249,13 +262,15 @@ interface MenuTriggerContextValue {
|
|
|
249
262
|
state: OverlayTriggerState;
|
|
250
263
|
triggerProps: JSX.HTMLAttributes<HTMLElement>;
|
|
251
264
|
menuProps: JSX.HTMLAttributes<HTMLElement>;
|
|
265
|
+
isPressed?: () => boolean;
|
|
266
|
+
onPressStart?: (e: { pointerType?: string }) => void;
|
|
252
267
|
}
|
|
253
268
|
|
|
254
269
|
interface MenuItemContextValue {
|
|
255
270
|
props?: () => JSX.HTMLAttributes<HTMLElement>;
|
|
256
271
|
closeOnSelect?: boolean;
|
|
257
272
|
onAction?: () => void;
|
|
258
|
-
setItemRef?: (el:
|
|
273
|
+
setItemRef?: (el: HTMLElement | null) => void;
|
|
259
274
|
}
|
|
260
275
|
|
|
261
276
|
interface StaticMenuCollectionItem {
|
|
@@ -283,6 +298,12 @@ interface MenuSectionSelectionRegistryContextValue {
|
|
|
283
298
|
selectItem(key: Key, event?: MenuSelectionEvent): boolean;
|
|
284
299
|
}
|
|
285
300
|
|
|
301
|
+
interface MenuItemCloseRegistryContextValue {
|
|
302
|
+
registerItem(key: Key, shouldCloseOnSelect: () => boolean | undefined): void;
|
|
303
|
+
unregisterItem(key: Key, shouldCloseOnSelect: () => boolean | undefined): void;
|
|
304
|
+
shouldCloseOnSelect(key: Key | null): boolean | undefined;
|
|
305
|
+
}
|
|
306
|
+
|
|
286
307
|
export const MenuContext = createContext<MenuContextValue<unknown> | null>(null);
|
|
287
308
|
export const MenuStateContext = createContext<MenuState<unknown> | null>(null);
|
|
288
309
|
export const MenuTriggerContext = createContext<MenuTriggerContextValue | null>(null);
|
|
@@ -292,6 +313,7 @@ const StaticMenuCollectionContext = createContext<StaticMenuCollectionContextVal
|
|
|
292
313
|
const MenuSectionSelectionContext = createContext<MenuSectionSelectionContextValue | null>(null);
|
|
293
314
|
const MenuSectionSelectionRegistryContext =
|
|
294
315
|
createContext<MenuSectionSelectionRegistryContextValue | null>(null);
|
|
316
|
+
const MenuItemCloseRegistryContext = createContext<MenuItemCloseRegistryContextValue | null>(null);
|
|
295
317
|
|
|
296
318
|
type RefLike<T> = ((el: T) => void) | { current?: T | null } | undefined;
|
|
297
319
|
|
|
@@ -323,6 +345,22 @@ export function MenuTrigger(props: MenuTriggerProps): JSX.Element {
|
|
|
323
345
|
},
|
|
324
346
|
});
|
|
325
347
|
|
|
348
|
+
const [isMousePressed, setMousePressed] = createSignal(false);
|
|
349
|
+
const onPressStart = (e: { pointerType?: string }) => {
|
|
350
|
+
if (e.pointerType !== "mouse" || typeof document === "undefined") {
|
|
351
|
+
return;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
setMousePressed(true);
|
|
355
|
+
document.addEventListener(
|
|
356
|
+
"pointerup",
|
|
357
|
+
() => {
|
|
358
|
+
setMousePressed(false);
|
|
359
|
+
},
|
|
360
|
+
{ once: true, capture: true },
|
|
361
|
+
);
|
|
362
|
+
};
|
|
363
|
+
|
|
326
364
|
const menuTrigger = createMenuTrigger(
|
|
327
365
|
{
|
|
328
366
|
get isDisabled() {
|
|
@@ -343,6 +381,8 @@ export function MenuTrigger(props: MenuTriggerProps): JSX.Element {
|
|
|
343
381
|
get menuProps() {
|
|
344
382
|
return menuTrigger.menuProps;
|
|
345
383
|
},
|
|
384
|
+
isPressed: isMousePressed,
|
|
385
|
+
onPressStart,
|
|
346
386
|
}}
|
|
347
387
|
>
|
|
348
388
|
{props.children}
|
|
@@ -369,10 +409,11 @@ export function SubmenuTrigger(props: SubmenuTriggerProps): JSX.Element {
|
|
|
369
409
|
},
|
|
370
410
|
});
|
|
371
411
|
|
|
372
|
-
let triggerRef:
|
|
412
|
+
let triggerRef: HTMLElement | null = null;
|
|
373
413
|
const triggerId = createUniqueId();
|
|
374
414
|
const menuId = createUniqueId();
|
|
375
415
|
let hoverTimeout: number | undefined;
|
|
416
|
+
let hasPointerHover = false;
|
|
376
417
|
const delay = () => props.delay ?? 200;
|
|
377
418
|
|
|
378
419
|
const clearHoverTimeout = () => {
|
|
@@ -387,6 +428,16 @@ export function SubmenuTrigger(props: SubmenuTriggerProps): JSX.Element {
|
|
|
387
428
|
state.open();
|
|
388
429
|
};
|
|
389
430
|
|
|
431
|
+
const queueOpenSubmenu = () => {
|
|
432
|
+
clearHoverTimeout();
|
|
433
|
+
const open = () => state.open();
|
|
434
|
+
if (typeof queueMicrotask === "function") {
|
|
435
|
+
queueMicrotask(open);
|
|
436
|
+
} else {
|
|
437
|
+
Promise.resolve().then(open);
|
|
438
|
+
}
|
|
439
|
+
};
|
|
440
|
+
|
|
390
441
|
const scheduleOpen = () => {
|
|
391
442
|
clearHoverTimeout();
|
|
392
443
|
hoverTimeout = window.setTimeout(() => {
|
|
@@ -395,6 +446,28 @@ export function SubmenuTrigger(props: SubmenuTriggerProps): JSX.Element {
|
|
|
395
446
|
}, delay());
|
|
396
447
|
};
|
|
397
448
|
|
|
449
|
+
const schedulePointerOpen = (event: PointerEvent) => {
|
|
450
|
+
hasPointerHover = true;
|
|
451
|
+
if (event.isTrusted === false) {
|
|
452
|
+
queueOpenSubmenu();
|
|
453
|
+
return;
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
scheduleOpen();
|
|
457
|
+
};
|
|
458
|
+
|
|
459
|
+
const openFromMouseHover = () => {
|
|
460
|
+
if (state.isOpen()) {
|
|
461
|
+
return;
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
if (hasPointerHover) {
|
|
465
|
+
scheduleOpen();
|
|
466
|
+
} else {
|
|
467
|
+
queueOpenSubmenu();
|
|
468
|
+
}
|
|
469
|
+
};
|
|
470
|
+
|
|
398
471
|
onCleanup(clearHoverTimeout);
|
|
399
472
|
|
|
400
473
|
const menuTriggerContext = createMemo<MenuTriggerContextValue>(() => ({
|
|
@@ -415,7 +488,7 @@ export function SubmenuTrigger(props: SubmenuTriggerProps): JSX.Element {
|
|
|
415
488
|
},
|
|
416
489
|
triggerRef: () => triggerRef,
|
|
417
490
|
setTriggerRef: (el: HTMLElement | null) => {
|
|
418
|
-
triggerRef = el
|
|
491
|
+
triggerRef = el;
|
|
419
492
|
},
|
|
420
493
|
triggerId,
|
|
421
494
|
trigger: "SubmenuTrigger",
|
|
@@ -430,17 +503,22 @@ export function SubmenuTrigger(props: SubmenuTriggerProps): JSX.Element {
|
|
|
430
503
|
props: () => ({
|
|
431
504
|
id: triggerId,
|
|
432
505
|
"aria-haspopup": "menu",
|
|
433
|
-
"aria-expanded"
|
|
434
|
-
|
|
506
|
+
get "aria-expanded"() {
|
|
507
|
+
return state.isOpen() || undefined;
|
|
508
|
+
},
|
|
509
|
+
get "aria-controls"() {
|
|
510
|
+
return state.isOpen() ? menuId : undefined;
|
|
511
|
+
},
|
|
435
512
|
onPointerEnter: (event: PointerEvent) => {
|
|
436
513
|
if (event.pointerType === "touch") return;
|
|
437
|
-
|
|
514
|
+
schedulePointerOpen(event);
|
|
438
515
|
},
|
|
439
516
|
onPointerOver: (event: PointerEvent) => {
|
|
440
517
|
if (event.pointerType === "touch") return;
|
|
441
|
-
|
|
518
|
+
schedulePointerOpen(event);
|
|
442
519
|
},
|
|
443
|
-
onMouseEnter:
|
|
520
|
+
onMouseEnter: openFromMouseHover,
|
|
521
|
+
onMouseOver: openFromMouseHover,
|
|
444
522
|
onKeyDown: (event: KeyboardEvent) => {
|
|
445
523
|
if (event.key === "ArrowRight" || event.key === "Enter" || event.key === " ") {
|
|
446
524
|
event.preventDefault();
|
|
@@ -512,6 +590,9 @@ export function MenuButton(props: MenuButtonProps): JSX.Element {
|
|
|
512
590
|
get isDisabled() {
|
|
513
591
|
return local.isDisabled;
|
|
514
592
|
},
|
|
593
|
+
onPressStart(e) {
|
|
594
|
+
context.onPressStart?.(e);
|
|
595
|
+
},
|
|
515
596
|
onPress() {
|
|
516
597
|
state.toggle();
|
|
517
598
|
},
|
|
@@ -529,14 +610,16 @@ export function MenuButton(props: MenuButtonProps): JSX.Element {
|
|
|
529
610
|
isOpen: state.isOpen(),
|
|
530
611
|
isFocused: isFocused(),
|
|
531
612
|
isFocusVisible: isFocusVisible(),
|
|
532
|
-
isPressed: buttonAria.isPressed(),
|
|
613
|
+
isPressed: context.isPressed?.() || buttonAria.isPressed(),
|
|
533
614
|
isHovered: isHovered(),
|
|
534
615
|
isDisabled: !!local.isDisabled,
|
|
535
616
|
}));
|
|
536
617
|
|
|
537
618
|
const renderProps = useRenderProps(
|
|
538
619
|
{
|
|
539
|
-
children
|
|
620
|
+
get children() {
|
|
621
|
+
return props.children;
|
|
622
|
+
},
|
|
540
623
|
class: local.class,
|
|
541
624
|
style: local.style,
|
|
542
625
|
defaultClassName: "solidaria-MenuButton",
|
|
@@ -586,7 +669,7 @@ export function MenuButton(props: MenuButtonProps): JSX.Element {
|
|
|
586
669
|
data-open={state.isOpen() || undefined}
|
|
587
670
|
data-focused={isFocused() || undefined}
|
|
588
671
|
data-focus-visible={isFocusVisible() || undefined}
|
|
589
|
-
data-pressed={buttonAria.isPressed() || undefined}
|
|
672
|
+
data-pressed={context.isPressed?.() || buttonAria.isPressed() || undefined}
|
|
590
673
|
data-hovered={isHovered() || undefined}
|
|
591
674
|
data-disabled={local.isDisabled || undefined}
|
|
592
675
|
>
|
|
@@ -601,23 +684,14 @@ export function MenuButton(props: MenuButtonProps): JSX.Element {
|
|
|
601
684
|
export function Menu<T>(props: MenuProps<T>): JSX.Element {
|
|
602
685
|
const [local, stateProps, ariaProps] = splitProps(
|
|
603
686
|
props,
|
|
604
|
-
[
|
|
605
|
-
"children",
|
|
606
|
-
"class",
|
|
607
|
-
"style",
|
|
608
|
-
"render",
|
|
609
|
-
"slot",
|
|
610
|
-
"renderEmptyState",
|
|
611
|
-
"shouldCloseOnSelect",
|
|
612
|
-
"ref",
|
|
613
|
-
"staticChildren",
|
|
614
|
-
],
|
|
687
|
+
["children", "class", "style", "render", "slot", "renderEmptyState", "ref", "staticChildren"],
|
|
615
688
|
[
|
|
616
689
|
"items",
|
|
617
690
|
"getKey",
|
|
618
691
|
"getTextValue",
|
|
619
692
|
"getDisabled",
|
|
620
693
|
"disabledKeys",
|
|
694
|
+
"disabledBehavior",
|
|
621
695
|
"selectionMode",
|
|
622
696
|
"selectionBehavior",
|
|
623
697
|
"disallowEmptySelection",
|
|
@@ -627,16 +701,18 @@ export function Menu<T>(props: MenuProps<T>): JSX.Element {
|
|
|
627
701
|
"allowDuplicateSelectionEvents",
|
|
628
702
|
"onAction",
|
|
629
703
|
"onClose",
|
|
704
|
+
"shouldCloseOnSelect",
|
|
630
705
|
"dragAndDropHooks",
|
|
631
706
|
],
|
|
632
707
|
);
|
|
633
708
|
|
|
634
709
|
const triggerContext = useContext(MenuTriggerContext);
|
|
635
710
|
|
|
636
|
-
const [menuRef, setMenuRef] = createSignal<
|
|
711
|
+
const [menuRef, setMenuRef] = createSignal<HTMLDivElement | null>(null);
|
|
637
712
|
const [staticItems, setStaticItems] = createSignal<StaticMenuCollectionItem[]>([]);
|
|
638
713
|
const staticItemMap = new Map<Key, StaticMenuCollectionItem>();
|
|
639
714
|
const sectionSelectionMap = new Map<Key, MenuSectionSelectionContextValue>();
|
|
715
|
+
const itemCloseMap = new Map<Key, () => boolean | undefined>();
|
|
640
716
|
const usesStaticChildren = () => local.staticChildren != null || stateProps.items == null;
|
|
641
717
|
|
|
642
718
|
const syncStaticItems = () => {
|
|
@@ -682,9 +758,27 @@ export function Menu<T>(props: MenuProps<T>): JSX.Element {
|
|
|
682
758
|
return true;
|
|
683
759
|
},
|
|
684
760
|
};
|
|
685
|
-
const
|
|
761
|
+
const itemCloseRegistry: MenuItemCloseRegistryContextValue = {
|
|
762
|
+
registerItem(key, shouldCloseOnSelect) {
|
|
763
|
+
itemCloseMap.set(key, shouldCloseOnSelect);
|
|
764
|
+
},
|
|
765
|
+
unregisterItem(key, shouldCloseOnSelect) {
|
|
766
|
+
if (itemCloseMap.get(key) === shouldCloseOnSelect) {
|
|
767
|
+
itemCloseMap.delete(key);
|
|
768
|
+
}
|
|
769
|
+
},
|
|
770
|
+
shouldCloseOnSelect(key) {
|
|
771
|
+
return key == null ? undefined : itemCloseMap.get(key)?.();
|
|
772
|
+
},
|
|
773
|
+
};
|
|
774
|
+
const handleAction = (key: Key, value?: T) => {
|
|
686
775
|
sectionSelectionRegistry.selectItem(key);
|
|
687
|
-
|
|
776
|
+
// Forward the activated item's value, which `createMenuState` sets from the
|
|
777
|
+
// collection node. For dynamic collections this is the user's data item.
|
|
778
|
+
// Static children are modeled with an internal item descriptor that upstream
|
|
779
|
+
// RAC does not expose as `value` (MenuItem only carries `value` for dynamic
|
|
780
|
+
// collections), so it is suppressed there to match.
|
|
781
|
+
stateProps.onAction?.(key, (usesStaticChildren() ? undefined : value) as T);
|
|
688
782
|
};
|
|
689
783
|
|
|
690
784
|
const flatItems = createMemo<T[]>(() => {
|
|
@@ -719,6 +813,9 @@ export function Menu<T>(props: MenuProps<T>): JSX.Element {
|
|
|
719
813
|
get disabledKeys() {
|
|
720
814
|
return stateProps.disabledKeys;
|
|
721
815
|
},
|
|
816
|
+
get disabledBehavior() {
|
|
817
|
+
return stateProps.disabledBehavior;
|
|
818
|
+
},
|
|
722
819
|
get selectionMode() {
|
|
723
820
|
return stateProps.selectionMode;
|
|
724
821
|
},
|
|
@@ -770,6 +867,12 @@ export function Menu<T>(props: MenuProps<T>): JSX.Element {
|
|
|
770
867
|
get onClose() {
|
|
771
868
|
return stateProps.onClose ?? (() => triggerContext?.state.close());
|
|
772
869
|
},
|
|
870
|
+
get shouldCloseOnSelect() {
|
|
871
|
+
return (
|
|
872
|
+
itemCloseRegistry.shouldCloseOnSelect(state.focusedKey()) ??
|
|
873
|
+
stateProps.shouldCloseOnSelect
|
|
874
|
+
);
|
|
875
|
+
},
|
|
773
876
|
get "aria-label"() {
|
|
774
877
|
return ariaProps["aria-label"];
|
|
775
878
|
},
|
|
@@ -783,6 +886,15 @@ export function Menu<T>(props: MenuProps<T>): JSX.Element {
|
|
|
783
886
|
state,
|
|
784
887
|
);
|
|
785
888
|
|
|
889
|
+
// Reveal the activedescendant-focused item on keyboard navigation. The menu
|
|
890
|
+
// keeps real DOM focus on itself, so the browser won't natively scroll an
|
|
891
|
+
// off-screen focused item into view the way roving tabindex would.
|
|
892
|
+
createScrollIntoViewOnFocus({
|
|
893
|
+
focusedKey: () => state.focusedKey(),
|
|
894
|
+
isActive: () => state.isFocused(),
|
|
895
|
+
ref: () => menuRef(),
|
|
896
|
+
});
|
|
897
|
+
|
|
786
898
|
const { isFocused, focusProps } = createFocusRing();
|
|
787
899
|
|
|
788
900
|
createInteractOutside({
|
|
@@ -832,7 +944,7 @@ export function Menu<T>(props: MenuProps<T>): JSX.Element {
|
|
|
832
944
|
const { ref: _ref4, ...rest } = labelProps as Record<string, unknown>;
|
|
833
945
|
return rest;
|
|
834
946
|
};
|
|
835
|
-
const setResolvedMenuRef = (el:
|
|
947
|
+
const setResolvedMenuRef = (el: HTMLDivElement): void => {
|
|
836
948
|
setMenuRef(el);
|
|
837
949
|
assignRef(local.ref, el);
|
|
838
950
|
};
|
|
@@ -1028,27 +1140,32 @@ export function Menu<T>(props: MenuProps<T>): JSX.Element {
|
|
|
1028
1140
|
dndDropIndicator(index, position) ??
|
|
1029
1141
|
parentCollectionRenderer?.renderDropIndicator?.(index, position),
|
|
1030
1142
|
}));
|
|
1143
|
+
const menuItemContextValue = createMemo<MenuItemContextValue>(() =>
|
|
1144
|
+
stateProps.shouldCloseOnSelect !== undefined
|
|
1145
|
+
? { closeOnSelect: stateProps.shouldCloseOnSelect }
|
|
1146
|
+
: {},
|
|
1147
|
+
);
|
|
1031
1148
|
const menuListChildren = () => (
|
|
1032
1149
|
<SharedElementTransition>
|
|
1033
1150
|
{state.collection().size === 0 && !usesStaticChildren() && local.renderEmptyState ? (
|
|
1034
|
-
<
|
|
1151
|
+
<div role="presentation" data-empty-state>
|
|
1035
1152
|
<div role="menuitem" style={{ display: "contents" }}>
|
|
1036
1153
|
{local.renderEmptyState()}
|
|
1037
1154
|
</div>
|
|
1038
|
-
</
|
|
1155
|
+
</div>
|
|
1039
1156
|
) : usesStaticChildren() ? (
|
|
1040
1157
|
renderStaticChildren()
|
|
1041
1158
|
) : hasSections() ? (
|
|
1042
1159
|
<For each={sectionedRenderEntries()}>
|
|
1043
1160
|
{(entry) =>
|
|
1044
1161
|
entry.type === "section" ? (
|
|
1045
|
-
<
|
|
1162
|
+
<div role="presentation" data-section-wrapper>
|
|
1046
1163
|
<Section class="solidaria-Menu-section">
|
|
1047
1164
|
{entry.section.title != null && (
|
|
1048
1165
|
<Header class="solidaria-Menu-sectionHeader">{entry.section.title}</Header>
|
|
1049
1166
|
)}
|
|
1050
1167
|
<Group class="solidaria-Menu-sectionGroup">
|
|
1051
|
-
<
|
|
1168
|
+
<div role="group" aria-label={entry.section["aria-label"]}>
|
|
1052
1169
|
<For each={entry.items}>
|
|
1053
1170
|
{(indexedItem) => (
|
|
1054
1171
|
<>
|
|
@@ -1062,10 +1179,10 @@ export function Menu<T>(props: MenuProps<T>): JSX.Element {
|
|
|
1062
1179
|
</>
|
|
1063
1180
|
)}
|
|
1064
1181
|
</For>
|
|
1065
|
-
</
|
|
1182
|
+
</div>
|
|
1066
1183
|
</Group>
|
|
1067
1184
|
</Section>
|
|
1068
|
-
</
|
|
1185
|
+
</div>
|
|
1069
1186
|
) : (
|
|
1070
1187
|
<>
|
|
1071
1188
|
{collectionRenderer().renderDropIndicator?.(entry.item.index, "before")}
|
|
@@ -1079,7 +1196,7 @@ export function Menu<T>(props: MenuProps<T>): JSX.Element {
|
|
|
1079
1196
|
) : (
|
|
1080
1197
|
<>
|
|
1081
1198
|
{virtualRange()?.offsetTop ? (
|
|
1082
|
-
<
|
|
1199
|
+
<div
|
|
1083
1200
|
role="presentation"
|
|
1084
1201
|
aria-hidden="true"
|
|
1085
1202
|
style={{ height: `${virtualRange()!.offsetTop}px` }}
|
|
@@ -1106,7 +1223,7 @@ export function Menu<T>(props: MenuProps<T>): JSX.Element {
|
|
|
1106
1223
|
}}
|
|
1107
1224
|
</For>
|
|
1108
1225
|
{virtualRange()?.offsetBottom ? (
|
|
1109
|
-
<
|
|
1226
|
+
<div
|
|
1110
1227
|
role="presentation"
|
|
1111
1228
|
aria-hidden="true"
|
|
1112
1229
|
style={{ height: `${virtualRange()!.offsetBottom}px` }}
|
|
@@ -1135,7 +1252,7 @@ export function Menu<T>(props: MenuProps<T>): JSX.Element {
|
|
|
1135
1252
|
"data-empty": state.collection().size === 0 || undefined,
|
|
1136
1253
|
"data-drop-target": isRootDropTarget() || undefined,
|
|
1137
1254
|
children: menuListChildren(),
|
|
1138
|
-
}) as JSX.HTMLAttributes<
|
|
1255
|
+
}) as JSX.HTMLAttributes<HTMLDivElement>;
|
|
1139
1256
|
|
|
1140
1257
|
// Only use FocusScope when inside a MenuTrigger (for popover behavior)
|
|
1141
1258
|
// Standalone menus don't need focus restoration
|
|
@@ -1153,44 +1270,46 @@ export function Menu<T>(props: MenuProps<T>): JSX.Element {
|
|
|
1153
1270
|
>
|
|
1154
1271
|
<MenuStateContext.Provider value={state}>
|
|
1155
1272
|
<MenuSectionSelectionRegistryContext.Provider value={sectionSelectionRegistry}>
|
|
1156
|
-
<
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
<
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
<
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
local.render
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1273
|
+
<MenuItemCloseRegistryContext.Provider value={itemCloseRegistry}>
|
|
1274
|
+
<StaticMenuCollectionContext.Provider
|
|
1275
|
+
value={usesStaticChildren() ? staticCollectionContext : null}
|
|
1276
|
+
>
|
|
1277
|
+
<MenuItemContext.Provider value={menuItemContextValue()}>
|
|
1278
|
+
<CollectionRendererContext.Provider value={collectionRenderer()}>
|
|
1279
|
+
<>
|
|
1280
|
+
<Show when={ariaProps.label}>
|
|
1281
|
+
<span {...cleanLabelProps()}>{ariaProps.label as JSX.Element}</span>
|
|
1282
|
+
</Show>
|
|
1283
|
+
{local.render ? (
|
|
1284
|
+
local.render(menuListProps(), renderValues())
|
|
1285
|
+
) : (
|
|
1286
|
+
<div
|
|
1287
|
+
ref={setResolvedMenuRef}
|
|
1288
|
+
{...mergeProps(
|
|
1289
|
+
domProps(),
|
|
1290
|
+
cleanMenuProps(),
|
|
1291
|
+
cleanTriggerMenuProps(),
|
|
1292
|
+
cleanFocusProps(),
|
|
1293
|
+
(droppableCollection()?.collectionProps as
|
|
1294
|
+
| Record<string, unknown>
|
|
1295
|
+
| undefined) ?? {},
|
|
1296
|
+
)}
|
|
1297
|
+
class={renderProps.class()}
|
|
1298
|
+
style={renderProps.style()}
|
|
1299
|
+
slot={local.slot}
|
|
1300
|
+
data-focused={state.isFocused() || undefined}
|
|
1301
|
+
data-disabled={resolveDisabled() || undefined}
|
|
1302
|
+
data-empty={state.collection().size === 0 || undefined}
|
|
1303
|
+
data-drop-target={isRootDropTarget() || undefined}
|
|
1304
|
+
>
|
|
1305
|
+
{menuListChildren()}
|
|
1306
|
+
</div>
|
|
1307
|
+
)}
|
|
1308
|
+
</>
|
|
1309
|
+
</CollectionRendererContext.Provider>
|
|
1310
|
+
</MenuItemContext.Provider>
|
|
1311
|
+
</StaticMenuCollectionContext.Provider>
|
|
1312
|
+
</MenuItemCloseRegistryContext.Provider>
|
|
1194
1313
|
</MenuSectionSelectionRegistryContext.Provider>
|
|
1195
1314
|
</MenuStateContext.Provider>
|
|
1196
1315
|
</MenuContext.Provider>
|
|
@@ -1240,17 +1359,26 @@ export function MenuItem<T>(props: MenuItemProps<T>): JSX.Element {
|
|
|
1240
1359
|
const staticCollection = useContext(StaticMenuCollectionContext);
|
|
1241
1360
|
const sectionSelection = useContext(MenuSectionSelectionContext);
|
|
1242
1361
|
const sectionSelectionRegistry = useContext(MenuSectionSelectionRegistryContext);
|
|
1243
|
-
const
|
|
1362
|
+
const itemCloseRegistry = useContext(MenuItemCloseRegistryContext);
|
|
1363
|
+
// Tracks the focusable menuitem element (the <div>, or the <a> for link
|
|
1364
|
+
// items) so roving focus can be moved onto it imperatively.
|
|
1365
|
+
const [ref, setRef] = createSignal<HTMLElement | null>(null);
|
|
1244
1366
|
const contextProps = () => itemContext?.props?.() ?? {};
|
|
1245
1367
|
const combinedOnAction = () => {
|
|
1246
1368
|
local.onAction?.();
|
|
1247
1369
|
itemContext?.onAction?.();
|
|
1248
1370
|
};
|
|
1371
|
+
const itemCloseOnSelect = () =>
|
|
1372
|
+
ariaProps.closeOnSelect ??
|
|
1373
|
+
sectionSelection?.shouldCloseOnSelect() ??
|
|
1374
|
+
itemContext?.closeOnSelect;
|
|
1249
1375
|
const activeSectionSelection = () =>
|
|
1250
1376
|
sectionSelection && sectionSelection.selectionMode() !== "none" ? sectionSelection : null;
|
|
1251
1377
|
let registeredStaticKey: Key | null = null;
|
|
1252
1378
|
let registeredSectionSelectionKey: Key | null = null;
|
|
1253
1379
|
let registeredSectionSelection: MenuSectionSelectionContextValue | null = null;
|
|
1380
|
+
let registeredCloseKey: Key | null = null;
|
|
1381
|
+
let registeredCloseAccessor: (() => boolean | undefined) | null = null;
|
|
1254
1382
|
|
|
1255
1383
|
const unregisterSectionSelection = () => {
|
|
1256
1384
|
if (registeredSectionSelectionKey != null && registeredSectionSelection) {
|
|
@@ -1304,9 +1432,38 @@ export function MenuItem<T>(props: MenuItemProps<T>): JSX.Element {
|
|
|
1304
1432
|
|
|
1305
1433
|
onCleanup(unregisterSectionSelection);
|
|
1306
1434
|
|
|
1435
|
+
const unregisterItemClose = () => {
|
|
1436
|
+
if (registeredCloseKey != null && registeredCloseAccessor) {
|
|
1437
|
+
itemCloseRegistry?.unregisterItem(registeredCloseKey, registeredCloseAccessor);
|
|
1438
|
+
registeredCloseKey = null;
|
|
1439
|
+
registeredCloseAccessor = null;
|
|
1440
|
+
}
|
|
1441
|
+
};
|
|
1442
|
+
|
|
1443
|
+
createEffect(() => {
|
|
1444
|
+
if (!itemCloseRegistry) {
|
|
1445
|
+
unregisterItemClose();
|
|
1446
|
+
return;
|
|
1447
|
+
}
|
|
1448
|
+
|
|
1449
|
+
if (registeredCloseKey === local.id && registeredCloseAccessor === itemCloseOnSelect) {
|
|
1450
|
+
return;
|
|
1451
|
+
}
|
|
1452
|
+
|
|
1453
|
+
unregisterItemClose();
|
|
1454
|
+
registeredCloseKey = local.id;
|
|
1455
|
+
registeredCloseAccessor = itemCloseOnSelect;
|
|
1456
|
+
itemCloseRegistry.registerItem(local.id, itemCloseOnSelect);
|
|
1457
|
+
});
|
|
1458
|
+
|
|
1459
|
+
onCleanup(unregisterItemClose);
|
|
1460
|
+
|
|
1307
1461
|
const itemAria = createMenuItem<T>(
|
|
1308
1462
|
{
|
|
1309
1463
|
key: local.id,
|
|
1464
|
+
get id() {
|
|
1465
|
+
return contextProps().id as string | undefined;
|
|
1466
|
+
},
|
|
1310
1467
|
get isDisabled() {
|
|
1311
1468
|
return Boolean(
|
|
1312
1469
|
ariaProps.isDisabled ||
|
|
@@ -1317,15 +1474,20 @@ export function MenuItem<T>(props: MenuItemProps<T>): JSX.Element {
|
|
|
1317
1474
|
get "aria-label"() {
|
|
1318
1475
|
return ariaProps["aria-label"] ?? local.textValue;
|
|
1319
1476
|
},
|
|
1477
|
+
get "aria-controls"() {
|
|
1478
|
+
return contextProps()["aria-controls"] as string | undefined;
|
|
1479
|
+
},
|
|
1480
|
+
get "aria-haspopup"() {
|
|
1481
|
+
return contextProps()["aria-haspopup"] as string | boolean | undefined;
|
|
1482
|
+
},
|
|
1483
|
+
get "aria-expanded"() {
|
|
1484
|
+
return contextProps()["aria-expanded"] as boolean | "true" | "false" | undefined;
|
|
1485
|
+
},
|
|
1320
1486
|
get onAction() {
|
|
1321
1487
|
return combinedOnAction;
|
|
1322
1488
|
},
|
|
1323
1489
|
get closeOnSelect() {
|
|
1324
|
-
return (
|
|
1325
|
-
ariaProps.closeOnSelect ??
|
|
1326
|
-
sectionSelection?.shouldCloseOnSelect() ??
|
|
1327
|
-
itemContext?.closeOnSelect
|
|
1328
|
-
);
|
|
1490
|
+
return itemCloseOnSelect();
|
|
1329
1491
|
},
|
|
1330
1492
|
get href() {
|
|
1331
1493
|
return local.href;
|
|
@@ -1341,6 +1503,7 @@ export function MenuItem<T>(props: MenuItemProps<T>): JSX.Element {
|
|
|
1341
1503
|
},
|
|
1342
1504
|
},
|
|
1343
1505
|
state,
|
|
1506
|
+
() => ref(),
|
|
1344
1507
|
);
|
|
1345
1508
|
|
|
1346
1509
|
const { isHovered, hoverProps } = createHover({
|
|
@@ -1364,12 +1527,16 @@ export function MenuItem<T>(props: MenuItemProps<T>): JSX.Element {
|
|
|
1364
1527
|
isDisabled: itemAria.isDisabled(),
|
|
1365
1528
|
hasSubmenu: Boolean(contextProps()["aria-haspopup"]),
|
|
1366
1529
|
isOpen: contextProps()["aria-expanded"] === true,
|
|
1530
|
+
descriptionProps: itemAria.descriptionProps,
|
|
1531
|
+
keyboardShortcutProps: itemAria.keyboardShortcutProps,
|
|
1367
1532
|
};
|
|
1368
1533
|
});
|
|
1369
1534
|
|
|
1370
1535
|
const renderProps = useRenderProps(
|
|
1371
1536
|
{
|
|
1372
|
-
children
|
|
1537
|
+
get children() {
|
|
1538
|
+
return props.children;
|
|
1539
|
+
},
|
|
1373
1540
|
class: local.class,
|
|
1374
1541
|
style: local.style,
|
|
1375
1542
|
defaultClassName: "solidaria-Menu-item",
|
|
@@ -1381,11 +1548,13 @@ export function MenuItem<T>(props: MenuItemProps<T>): JSX.Element {
|
|
|
1381
1548
|
};
|
|
1382
1549
|
|
|
1383
1550
|
const cleanItemProps = () => {
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1551
|
+
// Keep `aria-describedby`: the headless emits it (via `createSlotId`) only
|
|
1552
|
+
// when a description/keyboard element is actually rendered, so it points at
|
|
1553
|
+
// the styled `Text slot="description"` + `Keyboard` ids threaded through
|
|
1554
|
+
// `renderValues` below — restoring upstream's two-context description
|
|
1555
|
+
// delegation. `createSlotId` clears it to `undefined` on description-less
|
|
1556
|
+
// items, so nothing dangles.
|
|
1557
|
+
const { ref: _ref1, ...rest } = itemAria.menuItemProps as Record<string, unknown>;
|
|
1389
1558
|
if (!hasPrimitiveLabel() && rest["aria-label"] == null) {
|
|
1390
1559
|
delete rest["aria-labelledby"];
|
|
1391
1560
|
}
|
|
@@ -1476,7 +1645,7 @@ export function MenuItem<T>(props: MenuItemProps<T>): JSX.Element {
|
|
|
1476
1645
|
) : (
|
|
1477
1646
|
renderProps.renderChildren()
|
|
1478
1647
|
);
|
|
1479
|
-
const setResolvedItemRef = (el:
|
|
1648
|
+
const setResolvedItemRef = (el: HTMLElement | null) => {
|
|
1480
1649
|
setRef(el);
|
|
1481
1650
|
itemContext?.setItemRef?.(el);
|
|
1482
1651
|
if (el) assignRef(local.ref, el);
|
|
@@ -1496,7 +1665,7 @@ export function MenuItem<T>(props: MenuItemProps<T>): JSX.Element {
|
|
|
1496
1665
|
style: renderProps.style(),
|
|
1497
1666
|
...dataAttrs(),
|
|
1498
1667
|
children: childContent(),
|
|
1499
|
-
}) as JSX.HTMLAttributes<
|
|
1668
|
+
}) as JSX.HTMLAttributes<HTMLElement>;
|
|
1500
1669
|
const linkMenuItemProps = () =>
|
|
1501
1670
|
({
|
|
1502
1671
|
...mergeProps(
|
|
@@ -1512,7 +1681,7 @@ export function MenuItem<T>(props: MenuItemProps<T>): JSX.Element {
|
|
|
1512
1681
|
style: renderProps.style(),
|
|
1513
1682
|
...dataAttrs(),
|
|
1514
1683
|
children: childContent(),
|
|
1515
|
-
}) as JSX.HTMLAttributes<
|
|
1684
|
+
}) as JSX.HTMLAttributes<HTMLElement>;
|
|
1516
1685
|
|
|
1517
1686
|
if (local.render && !isLink()) {
|
|
1518
1687
|
return local.render(menuItemProps(), renderValues());
|
|
@@ -1522,7 +1691,7 @@ export function MenuItem<T>(props: MenuItemProps<T>): JSX.Element {
|
|
|
1522
1691
|
<Show
|
|
1523
1692
|
when={isLink()}
|
|
1524
1693
|
fallback={
|
|
1525
|
-
<
|
|
1694
|
+
<div
|
|
1526
1695
|
ref={(el) => {
|
|
1527
1696
|
setRef(el);
|
|
1528
1697
|
itemContext?.setItemRef?.(el);
|
|
@@ -1541,38 +1710,36 @@ export function MenuItem<T>(props: MenuItemProps<T>): JSX.Element {
|
|
|
1541
1710
|
{...dataAttrs()}
|
|
1542
1711
|
>
|
|
1543
1712
|
{childContent()}
|
|
1544
|
-
</
|
|
1713
|
+
</div>
|
|
1545
1714
|
}
|
|
1546
1715
|
>
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
)}
|
|
1575
|
-
</li>
|
|
1716
|
+
{local.render ? (
|
|
1717
|
+
local.render(linkMenuItemProps(), renderValues())
|
|
1718
|
+
) : (
|
|
1719
|
+
// Upstream renders the link menuitem as a bare <a role="menuitem"> (no
|
|
1720
|
+
// presentation wrapper); the <div> root makes the wrapper unnecessary.
|
|
1721
|
+
<a
|
|
1722
|
+
ref={(el) => {
|
|
1723
|
+
setRef(el);
|
|
1724
|
+
itemContext?.setItemRef?.(el);
|
|
1725
|
+
assignRef(local.ref, el);
|
|
1726
|
+
}}
|
|
1727
|
+
{...mergeProps(
|
|
1728
|
+
cleanItemPropsForLink(),
|
|
1729
|
+
contextProps() as Record<string, unknown>,
|
|
1730
|
+
domProps(),
|
|
1731
|
+
cleanHoverProps(),
|
|
1732
|
+
linkDomProps(),
|
|
1733
|
+
(draggableItem()?.dragProps as Record<string, unknown> | undefined) ?? {},
|
|
1734
|
+
(droppableItem()?.dropProps as Record<string, unknown> | undefined) ?? {},
|
|
1735
|
+
)}
|
|
1736
|
+
class={renderProps.class()}
|
|
1737
|
+
style={renderProps.style()}
|
|
1738
|
+
{...dataAttrs()}
|
|
1739
|
+
>
|
|
1740
|
+
{childContent()}
|
|
1741
|
+
</a>
|
|
1742
|
+
)}
|
|
1576
1743
|
</Show>
|
|
1577
1744
|
);
|
|
1578
1745
|
}
|