@pzerelles/headlessui-svelte 2.1.2-next.31 → 2.1.2-next.33

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (123) hide show
  1. package/dist/button/Button.svelte +84 -55
  2. package/dist/button/Button.svelte.d.ts +4 -32
  3. package/dist/checkbox/Checkbox.svelte +177 -121
  4. package/dist/checkbox/Checkbox.svelte.d.ts +14 -32
  5. package/dist/close-button/CloseButton.svelte +10 -7
  6. package/dist/close-button/CloseButton.svelte.d.ts +2 -44
  7. package/dist/data-interactive/DataInteractive.svelte +49 -37
  8. package/dist/data-interactive/DataInteractive.svelte.d.ts +7 -30
  9. package/dist/description/Description.svelte +35 -22
  10. package/dist/description/Description.svelte.d.ts +7 -28
  11. package/dist/dialog/Dialog.svelte +326 -232
  12. package/dist/dialog/Dialog.svelte.d.ts +4 -42
  13. package/dist/dialog/DialogBackdrop.svelte +33 -16
  14. package/dist/dialog/DialogBackdrop.svelte.d.ts +4 -29
  15. package/dist/dialog/DialogPanel.svelte +60 -29
  16. package/dist/dialog/DialogPanel.svelte.d.ts +4 -30
  17. package/dist/dialog/DialogTitle.svelte +51 -24
  18. package/dist/dialog/DialogTitle.svelte.d.ts +6 -27
  19. package/dist/field/Field.svelte +44 -28
  20. package/dist/field/Field.svelte.d.ts +4 -30
  21. package/dist/fieldset/Fieldset.svelte +48 -30
  22. package/dist/fieldset/Fieldset.svelte.d.ts +5 -31
  23. package/dist/focus-trap/FocusTrap.svelte +430 -298
  24. package/dist/focus-trap/FocusTrap.svelte.d.ts +5 -34
  25. package/dist/hooks/use-inert-others.svelte.js +10 -10
  26. package/dist/hooks/use-resolve-button-type.svelte.js +0 -1
  27. package/dist/input/Input.svelte +95 -54
  28. package/dist/input/Input.svelte.d.ts +13 -27
  29. package/dist/internal/FloatingProvider.svelte +14 -9
  30. package/dist/internal/FocusSentinel.svelte +49 -40
  31. package/dist/internal/ForcePortalRoot.svelte +7 -3
  32. package/dist/internal/FormFields.svelte +47 -34
  33. package/dist/internal/FormFieldsProvider.svelte +9 -5
  34. package/dist/internal/FormResolver.svelte +25 -16
  35. package/dist/internal/Hidden.svelte +45 -38
  36. package/dist/internal/Hidden.svelte.d.ts +4 -30
  37. package/dist/internal/MainTreeProvider.svelte +90 -37
  38. package/dist/internal/Portal.svelte +18 -14
  39. package/dist/label/Label.svelte +100 -59
  40. package/dist/label/Label.svelte.d.ts +7 -32
  41. package/dist/legend/Legend.svelte +27 -4
  42. package/dist/legend/Legend.svelte.d.ts +4 -3
  43. package/dist/listbox/Listbox.svelte +518 -391
  44. package/dist/listbox/Listbox.svelte.d.ts +11 -35
  45. package/dist/listbox/ListboxButton.svelte +175 -128
  46. package/dist/listbox/ListboxButton.svelte.d.ts +5 -32
  47. package/dist/listbox/ListboxOption.svelte +171 -130
  48. package/dist/listbox/ListboxOption.svelte.d.ts +12 -26
  49. package/dist/listbox/ListboxOptions.svelte +403 -305
  50. package/dist/listbox/ListboxOptions.svelte.d.ts +4 -38
  51. package/dist/listbox/ListboxSelectedOption.svelte +40 -19
  52. package/dist/listbox/ListboxSelectedOption.svelte.d.ts +8 -33
  53. package/dist/menu/Menu.svelte +76 -52
  54. package/dist/menu/Menu.svelte.d.ts +3 -31
  55. package/dist/menu/MenuButton.svelte +158 -118
  56. package/dist/menu/MenuButton.svelte.d.ts +4 -34
  57. package/dist/menu/MenuHeading.svelte +34 -15
  58. package/dist/menu/MenuHeading.svelte.d.ts +4 -31
  59. package/dist/menu/MenuItem.svelte +143 -108
  60. package/dist/menu/MenuItem.svelte.d.ts +5 -32
  61. package/dist/menu/MenuItems.svelte +301 -230
  62. package/dist/menu/MenuItems.svelte.d.ts +4 -38
  63. package/dist/menu/MenuSection.svelte +26 -10
  64. package/dist/menu/MenuSection.svelte.d.ts +5 -29
  65. package/dist/menu/MenuSeparator.svelte +20 -5
  66. package/dist/menu/MenuSeparator.svelte.d.ts +5 -28
  67. package/dist/popover/Popover.svelte +217 -151
  68. package/dist/popover/Popover.svelte.d.ts +4 -30
  69. package/dist/popover/PopoverBackdrop.svelte +71 -42
  70. package/dist/popover/PopoverBackdrop.svelte.d.ts +6 -34
  71. package/dist/popover/PopoverButton.svelte +302 -222
  72. package/dist/popover/PopoverButton.svelte.d.ts +6 -29
  73. package/dist/popover/PopoverGroup.svelte +64 -36
  74. package/dist/popover/PopoverGroup.svelte.d.ts +5 -28
  75. package/dist/popover/PopoverPanel.svelte +335 -248
  76. package/dist/popover/PopoverPanel.svelte.d.ts +5 -36
  77. package/dist/popover/index.d.ts +1 -1
  78. package/dist/portal/InternalPortal.svelte +143 -86
  79. package/dist/portal/InternalPortal.svelte.d.ts +4 -30
  80. package/dist/portal/Portal.svelte +8 -4
  81. package/dist/portal/Portal.svelte.d.ts +2 -18
  82. package/dist/portal/PortalGroup.svelte +23 -10
  83. package/dist/portal/PortalGroup.svelte.d.ts +3 -31
  84. package/dist/select/Select.svelte +100 -69
  85. package/dist/select/Select.svelte.d.ts +5 -32
  86. package/dist/switch/Switch.svelte +181 -133
  87. package/dist/switch/Switch.svelte.d.ts +5 -38
  88. package/dist/switch/SwitchGroup.svelte +45 -32
  89. package/dist/switch/SwitchGroup.svelte.d.ts +7 -28
  90. package/dist/tabs/Tab.svelte +195 -143
  91. package/dist/tabs/Tab.svelte.d.ts +4 -32
  92. package/dist/tabs/TabGroup.svelte +87 -57
  93. package/dist/tabs/TabGroup.svelte.d.ts +4 -34
  94. package/dist/tabs/TabList.svelte +31 -12
  95. package/dist/tabs/TabList.svelte.d.ts +5 -28
  96. package/dist/tabs/TabPanel.svelte +69 -44
  97. package/dist/tabs/TabPanel.svelte.d.ts +4 -34
  98. package/dist/tabs/TabPanels.svelte +19 -8
  99. package/dist/tabs/TabPanels.svelte.d.ts +5 -27
  100. package/dist/textarea/Textarea.svelte +87 -54
  101. package/dist/textarea/Textarea.svelte.d.ts +13 -27
  102. package/dist/transition/InternalTransitionChild.svelte +267 -171
  103. package/dist/transition/InternalTransitionChild.svelte.d.ts +3 -33
  104. package/dist/transition/Transition.svelte +88 -67
  105. package/dist/transition/Transition.svelte.d.ts +3 -36
  106. package/dist/transition/TransitionChild.svelte +31 -12
  107. package/dist/transition/TransitionChild.svelte.d.ts +8 -35
  108. package/dist/transition/context.svelte.js +7 -7
  109. package/dist/utils/DisabledProvider.svelte +7 -3
  110. package/dist/utils/ElementOrComponent.svelte +88 -24
  111. package/dist/utils/ElementOrComponent.svelte.d.ts +32 -27
  112. package/dist/utils/StableCollection.svelte +54 -36
  113. package/dist/utils/floating-ui/svelte/components/FloatingNode.svelte +27 -12
  114. package/dist/utils/floating-ui/svelte/components/FloatingTree.svelte +88 -44
  115. package/dist/utils/state.js +4 -4
  116. package/dist/utils/types.d.ts +14 -12
  117. package/package.json +12 -12
  118. package/dist/combobox/Combobox.svelte +0 -6
  119. package/dist/combobox/Combobox.svelte.d.ts +0 -50
  120. package/dist/utils/Generic.svelte +0 -46
  121. package/dist/utils/Generic.svelte.d.ts +0 -32
  122. package/dist/utils/alternative-types.d.ts +0 -20
  123. package/dist/utils/alternative-types.js +0 -1
@@ -1,237 +1,308 @@
1
- <script lang="ts" module>import { mergeProps, RenderFeatures } from "../utils/render.js";
2
- import {
3
- useFloatingPanel,
4
- useFloatingPanelProps,
5
- useResolvedAnchor
6
- } from "../internal/floating.svelte.js";
7
- const DEFAULT_ITEMS_TAG = "div";
8
- let ItemsRenderFeatures = RenderFeatures.RenderStrategy | RenderFeatures.Static;
9
- </script>
1
+ <script lang="ts" module>
2
+ import type { Props } from "../utils/types.js"
3
+ import { mergeProps, RenderFeatures, type PropsForFeatures } from "../utils/render.js"
4
+ import {
5
+ useFloatingPanel,
6
+ useFloatingPanelProps,
7
+ useResolvedAnchor,
8
+ type AnchorProps,
9
+ } from "../internal/floating.svelte.js"
10
10
 
11
- <script lang="ts" generics="TTag extends ElementType = typeof DEFAULT_ITEMS_TAG">import { useId } from "../hooks/use-id.js";
12
- import { getOwnerDocument } from "../utils/owner.js";
13
- import { State, useOpenClosed } from "../internal/open-closed.js";
14
- import { transitionDataAttributes, useTransition } from "../hooks/use-transition.svelte.js";
15
- import { useOnDisappear } from "../hooks/use-on-disappear.svelte.js";
16
- import { useScrollLock } from "../hooks/use-scroll-lock.svelte.js";
17
- import { useInertOthers } from "../hooks/use-inert-others.svelte.js";
18
- import { useDidElementMove } from "../hooks/use-did-element-move.svelte.js";
19
- import { useDisposables } from "../utils/disposables.js";
20
- import { Focus } from "../utils/calculate-active-index.js";
21
- import { focusFrom, Focus as FocusManagementFocus, restoreFocusIfNecessary } from "../utils/focus-management.js";
22
- import { useElementSize } from "../hooks/use-element-size.svelte.js";
23
- import { tick, untrack } from "svelte";
24
- import Portal from "../portal/Portal.svelte";
25
- import { MenuStates, useMenuContext } from "./context.svelte.js";
26
- import { useTreeWalker } from "../hooks/use-tree-walker.svelte.js";
27
- import ElementOrComponent from "../utils/ElementOrComponent.svelte";
28
- const internalId = useId();
29
- let {
30
- as = DEFAULT_ITEMS_TAG,
31
- ref = $bindable(),
32
- id = `headlessui-menu-items-${internalId}`,
33
- anchor: rawAnchor,
34
- portal = false,
35
- modal = true,
36
- transition = false,
37
- ...theirProps
38
- } = $props();
39
- const resolvedAnchor = useResolvedAnchor({
40
- get anchor() {
41
- return rawAnchor;
42
- }
43
- });
44
- const { anchor } = $derived(resolvedAnchor);
45
- const _state = useMenuContext("MenuOptions");
46
- const floatingPanel = useFloatingPanel({
47
- get placement() {
48
- return anchor;
49
- }
50
- });
51
- const { setFloating, styles } = $derived(floatingPanel);
52
- const getFloatingPanelProps = useFloatingPanelProps();
53
- $effect(() => {
54
- untrack(() => _state.setItemsElement(ref ?? null));
55
- if (anchor) setFloating(ref ?? null);
56
- });
57
- const ownerDocument = $derived(getOwnerDocument(_state.itemsElement));
58
- $effect(() => {
59
- if (anchor) {
60
- portal = true;
61
- }
62
- });
63
- const usesOpenClosedState = useOpenClosed();
64
- const show = $derived(
65
- usesOpenClosedState !== null ? (usesOpenClosedState.value & State.Open) === State.Open : _state.menuState === MenuStates.Open
66
- );
67
- const _transition = useTransition({
68
- get enabled() {
69
- return transition;
70
- },
71
- get element() {
72
- return ref;
73
- },
74
- get show() {
75
- return show;
76
- }
77
- });
78
- const { visible, data: transitionData } = $derived(_transition);
79
- useOnDisappear({
80
- get enabled() {
81
- return visible;
82
- },
83
- get ref() {
84
- return _state.buttonElement;
85
- },
86
- get ondisappear() {
87
- return _state.closeMenu;
88
- }
89
- });
90
- const scrollLockEnabled = $derived(_state.__demoMode ? false : modal && _state.menuState === MenuStates.Open);
91
- useScrollLock({
92
- get enabled() {
93
- return scrollLockEnabled;
94
- },
95
- get ownerDocument() {
96
- return ownerDocument;
11
+ const DEFAULT_ITEMS_TAG = "div" as const
12
+ type ItemsRenderPropArg = {
13
+ open: boolean
97
14
  }
98
- });
99
- const inertOthersEnabled = $derived(_state.__demoMode ? false : modal && _state.menuState === MenuStates.Open);
100
- useInertOthers({
101
- get enabled() {
102
- return inertOthersEnabled;
103
- },
104
- elements: {
105
- get allowed() {
106
- return [_state.buttonElement, _state.itemsElement].filter(Boolean);
15
+ type ItemsPropsWeControl = "aria-activedescendant" | "aria-labelledby" | "role" | "tabIndex"
16
+
17
+ let ItemsRenderFeatures = RenderFeatures.RenderStrategy | RenderFeatures.Static
18
+
19
+ export type MenuItemsProps = Props<
20
+ typeof DEFAULT_ITEMS_TAG,
21
+ ItemsRenderPropArg,
22
+ {
23
+ element?: HTMLElement
24
+ id?: string
25
+ anchor?: AnchorProps
26
+ portal?: boolean
27
+ modal?: boolean
28
+ transition?: boolean
29
+ } & PropsForFeatures<typeof ItemsRenderFeatures>
30
+ >
31
+ </script>
32
+
33
+ <script lang="ts">
34
+ import { useId } from "../hooks/use-id.js"
35
+ import { getOwnerDocument } from "../utils/owner.js"
36
+ import { State, useOpenClosed } from "../internal/open-closed.js"
37
+ import { transitionDataAttributes, useTransition } from "../hooks/use-transition.svelte.js"
38
+ import { useOnDisappear } from "../hooks/use-on-disappear.svelte.js"
39
+ import { useScrollLock } from "../hooks/use-scroll-lock.svelte.js"
40
+ import { useInertOthers } from "../hooks/use-inert-others.svelte.js"
41
+ import { useDidElementMove } from "../hooks/use-did-element-move.svelte.js"
42
+ import { useDisposables } from "../utils/disposables.js"
43
+ import { Focus } from "../utils/calculate-active-index.js"
44
+ import { focusFrom, Focus as FocusManagementFocus, restoreFocusIfNecessary } from "../utils/focus-management.js"
45
+ import { useElementSize } from "../hooks/use-element-size.svelte.js"
46
+ import { tick, untrack } from "svelte"
47
+ import Portal from "../portal/Portal.svelte"
48
+ import { MenuStates, useMenuContext } from "./context.svelte.js"
49
+ import { useTreeWalker } from "../hooks/use-tree-walker.svelte.js"
50
+ import ElementOrComponent from "../utils/ElementOrComponent.svelte"
51
+
52
+ const internalId = useId()
53
+ let {
54
+ element = $bindable(),
55
+ id = `headlessui-menu-items-${internalId}`,
56
+ anchor: rawAnchor,
57
+ portal = false,
58
+ modal = true,
59
+ transition = false,
60
+ ...theirProps
61
+ }: MenuItemsProps = $props()
62
+ const resolvedAnchor = useResolvedAnchor({
63
+ get anchor() {
64
+ return rawAnchor
65
+ },
66
+ })
67
+ const { anchor } = $derived(resolvedAnchor)
68
+ const _state = useMenuContext("MenuOptions")
69
+ const floatingPanel = useFloatingPanel({
70
+ get placement() {
71
+ return anchor
72
+ },
73
+ })
74
+ const { setFloating, styles } = $derived(floatingPanel)
75
+ const getFloatingPanelProps = useFloatingPanelProps()
76
+
77
+ $effect(() => {
78
+ untrack(() => _state.setItemsElement(element ?? null))
79
+ if (anchor) setFloating(element ?? null)
80
+ })
81
+ const ownerDocument = $derived(getOwnerDocument(_state.itemsElement))
82
+
83
+ // Always enable `portal` functionality, when `anchor` is enabled
84
+ $effect(() => {
85
+ if (anchor) {
86
+ portal = true
87
+ }
88
+ })
89
+
90
+ const usesOpenClosedState = useOpenClosed()
91
+ const show = $derived(
92
+ usesOpenClosedState !== null
93
+ ? (usesOpenClosedState.value & State.Open) === State.Open
94
+ : _state.menuState === MenuStates.Open
95
+ )
96
+ const _transition = useTransition({
97
+ get enabled() {
98
+ return transition
99
+ },
100
+ get element() {
101
+ return element
102
+ },
103
+ get show() {
104
+ return show
105
+ },
106
+ })
107
+ const { visible, data: transitionData } = $derived(_transition)
108
+
109
+ // Ensure we close the listbox as soon as the button becomes hidden
110
+ useOnDisappear({
111
+ get enabled() {
112
+ return visible
113
+ },
114
+ get ref() {
115
+ return _state.buttonElement
116
+ },
117
+ get ondisappear() {
118
+ return _state.closeMenu
119
+ },
120
+ })
121
+
122
+ // Enable scroll locking when the listbox is visible, and `modal` is enabled
123
+ const scrollLockEnabled = $derived(_state.__demoMode ? false : modal && _state.menuState === MenuStates.Open)
124
+ useScrollLock({
125
+ get enabled() {
126
+ return scrollLockEnabled
127
+ },
128
+ get ownerDocument() {
129
+ return ownerDocument
130
+ },
131
+ })
132
+
133
+ // Mark other elements as inert when the listbox is visible, and `modal` is enabled
134
+ const inertOthersEnabled = $derived(_state.__demoMode ? false : modal && _state.menuState === MenuStates.Open)
135
+ useInertOthers({
136
+ get enabled() {
137
+ return inertOthersEnabled
138
+ },
139
+ elements: {
140
+ get allowed() {
141
+ return [_state.buttonElement, _state.itemsElement].filter(Boolean)
142
+ },
143
+ },
144
+ })
145
+
146
+ // We keep track whether the button moved or not, we only check this when the menu state becomes
147
+ // closed. If the button moved, then we want to cancel pending transitions to prevent that the
148
+ // attached `MenuItems` is still transitioning while the button moved away.
149
+ //
150
+ // If we don't cancel these transitions then there will be a period where the `MenuItems` is
151
+ // visible and moving around because it is trying to re-position itself based on the new position.
152
+ //
153
+ // This can be solved by only transitioning the `opacity` instead of everything, but if you _do_
154
+ // want to transition the y-axis for example you will run into the same issue again.
155
+ const didElementMoveEnabled = $derived(_state.menuState !== MenuStates.Open)
156
+ const didButtonMove = useDidElementMove({
157
+ get enabled() {
158
+ return didElementMoveEnabled
159
+ },
160
+ get element() {
161
+ return _state.buttonElement
162
+ },
163
+ })
164
+
165
+ // Now that we know that the button did move or not, we can either disable the panel and all of
166
+ // its transitions, or rely on the `visible` state to hide the panel whenever necessary.
167
+ const panelEnabled = $derived(didButtonMove.value ? false : visible)
168
+
169
+ $effect(() => {
170
+ let container = _state.itemsElement
171
+ if (!container) return
172
+ if (_state.menuState !== MenuStates.Open) return
173
+ if (container === ownerDocument?.activeElement) return
174
+
175
+ container.focus({ preventScroll: true })
176
+ })
177
+
178
+ useTreeWalker({
179
+ get enabled() {
180
+ return _state.menuState === MenuStates.Open
181
+ },
182
+ get container() {
183
+ return _state.itemsElement
184
+ },
185
+ accept: (node) => {
186
+ if (node.getAttribute("role") === "menuitem") return NodeFilter.FILTER_REJECT
187
+ if (node.hasAttribute("role")) return NodeFilter.FILTER_SKIP
188
+ return NodeFilter.FILTER_ACCEPT
189
+ },
190
+ walk: (node) => {
191
+ node.setAttribute("role", "none")
192
+ },
193
+ })
194
+
195
+ const searchDisposables = useDisposables()
196
+
197
+ const handleKeyDown = async (event: KeyboardEvent) => {
198
+ searchDisposables.dispose()
199
+
200
+ switch (event.key) {
201
+ // Ref: https://www.w3.org/WAI/ARIA/apg/patterns/menu/#keyboard-interaction-12
202
+
203
+ case " ":
204
+ if (_state.searchQuery !== "") {
205
+ event.preventDefault()
206
+ event.stopPropagation()
207
+ return _state.search(event.key)
208
+ }
209
+ // When in type ahead mode, fallthrough
210
+ case "Enter":
211
+ event.preventDefault()
212
+ event.stopPropagation()
213
+ _state.closeMenu()
214
+ if (_state.activeItemIndex !== null) {
215
+ let { dataRef } = _state.items[_state.activeItemIndex]
216
+ dataRef.current?.domRef.current?.click()
217
+ }
218
+ restoreFocusIfNecessary(_state.buttonElement)
219
+ break
220
+
221
+ case "ArrowDown":
222
+ event.preventDefault()
223
+ event.stopPropagation()
224
+ return _state.goToItem({ focus: Focus.Next })
225
+
226
+ case "ArrowUp":
227
+ event.preventDefault()
228
+ event.stopPropagation()
229
+ return _state.goToItem({ focus: Focus.Previous })
230
+
231
+ case "Home":
232
+ case "PageUp":
233
+ event.preventDefault()
234
+ event.stopPropagation()
235
+ return _state.goToItem({ focus: Focus.First })
236
+
237
+ case "End":
238
+ case "PageDown":
239
+ event.preventDefault()
240
+ event.stopPropagation()
241
+ return _state.goToItem({ focus: Focus.Last })
242
+
243
+ case "Escape":
244
+ event.preventDefault()
245
+ event.stopPropagation()
246
+ _state.closeMenu()
247
+ await tick()
248
+ _state.buttonElement?.focus({ preventScroll: true })
249
+ break
250
+
251
+ case "Tab":
252
+ event.preventDefault()
253
+ event.stopPropagation()
254
+ _state.closeMenu()
255
+ await tick()
256
+ focusFrom(_state.buttonElement!, event.shiftKey ? FocusManagementFocus.Previous : FocusManagementFocus.Next)
257
+ break
258
+
259
+ default:
260
+ if (event.key.length === 1) {
261
+ _state.search(event.key)
262
+ searchDisposables.setTimeout(() => _state.clearSearch(), 350)
263
+ }
264
+ break
107
265
  }
108
266
  }
109
- });
110
- const didElementMoveEnabled = $derived(_state.menuState !== MenuStates.Open);
111
- const didButtonMove = useDidElementMove({
112
- get enabled() {
113
- return didElementMoveEnabled;
114
- },
115
- get element() {
116
- return _state.buttonElement;
117
- }
118
- });
119
- const panelEnabled = $derived(didButtonMove.value ? false : visible);
120
- $effect(() => {
121
- let container = _state.itemsElement;
122
- if (!container) return;
123
- if (_state.menuState !== MenuStates.Open) return;
124
- if (container === ownerDocument?.activeElement) return;
125
- container.focus({ preventScroll: true });
126
- });
127
- useTreeWalker({
128
- get enabled() {
129
- return _state.menuState === MenuStates.Open;
130
- },
131
- get container() {
132
- return _state.itemsElement;
133
- },
134
- accept: (node) => {
135
- if (node.getAttribute("role") === "menuitem") return NodeFilter.FILTER_REJECT;
136
- if (node.hasAttribute("role")) return NodeFilter.FILTER_SKIP;
137
- return NodeFilter.FILTER_ACCEPT;
138
- },
139
- walk: (node) => {
140
- node.setAttribute("role", "none");
141
- }
142
- });
143
- const searchDisposables = useDisposables();
144
- const handleKeyDown = async (event) => {
145
- searchDisposables.dispose();
146
- switch (event.key) {
147
- case " ":
148
- if (_state.searchQuery !== "") {
149
- event.preventDefault();
150
- event.stopPropagation();
151
- return _state.search(event.key);
152
- }
153
- case "Enter":
154
- event.preventDefault();
155
- event.stopPropagation();
156
- _state.closeMenu();
157
- if (_state.activeItemIndex !== null) {
158
- let { dataRef } = _state.items[_state.activeItemIndex];
159
- dataRef.current?.domRef.current?.click();
160
- }
161
- restoreFocusIfNecessary(_state.buttonElement);
162
- break;
163
- case "ArrowDown":
164
- event.preventDefault();
165
- event.stopPropagation();
166
- return _state.goToItem({ focus: Focus.Next });
167
- case "ArrowUp":
168
- event.preventDefault();
169
- event.stopPropagation();
170
- return _state.goToItem({ focus: Focus.Previous });
171
- case "Home":
172
- case "PageUp":
173
- event.preventDefault();
174
- event.stopPropagation();
175
- return _state.goToItem({ focus: Focus.First });
176
- case "End":
177
- case "PageDown":
178
- event.preventDefault();
179
- event.stopPropagation();
180
- return _state.goToItem({ focus: Focus.Last });
181
- case "Escape":
182
- event.preventDefault();
183
- event.stopPropagation();
184
- _state.closeMenu();
185
- await tick();
186
- _state.buttonElement?.focus({ preventScroll: true });
187
- break;
188
- case "Tab":
189
- event.preventDefault();
190
- event.stopPropagation();
191
- _state.closeMenu();
192
- await tick();
193
- focusFrom(_state.buttonElement, event.shiftKey ? FocusManagementFocus.Previous : FocusManagementFocus.Next);
194
- break;
195
- default:
196
- if (event.key.length === 1) {
197
- _state.search(event.key);
198
- searchDisposables.setTimeout(() => _state.clearSearch(), 350);
199
- }
200
- break;
201
- }
202
- };
203
- const handleKeyUp = (event) => {
204
- switch (event.key) {
205
- case " ":
206
- event.preventDefault();
207
- break;
267
+
268
+ const handleKeyUp = (event: KeyboardEvent) => {
269
+ switch (event.key) {
270
+ case " ":
271
+ // Required for firefox, event.preventDefault() in handleKeyDown for
272
+ // the Space key doesn't cancel the handleKeyUp, which in turn
273
+ // triggers a *click*.
274
+ event.preventDefault()
275
+ break
276
+ }
208
277
  }
209
- };
210
- const slot = $derived({
211
- open: _state.menuState === MenuStates.Open
212
- });
213
- const buttonSize = useElementSize({
214
- get element() {
215
- return _state.buttonElement;
216
- },
217
- unit: true
218
- });
219
- const ourProps = $derived({
220
- ...mergeProps(anchor ? getFloatingPanelProps() : {}, {
221
- "aria-activedescendant": _state.activeItemIndex === null ? void 0 : _state.items[_state.activeItemIndex]?.id,
222
- "aria-labelledby": _state.buttonElement?.id,
223
- id,
224
- onkeydown: handleKeyDown,
225
- onkeyup: handleKeyUp,
226
- role: "menu",
227
- // When the `Menu` is closed, it should not be focusable. This allows us
228
- // to skip focusing the `MenuItems` when pressing the tab key on an
229
- // open `Menu`, and go to the next focusable element.
230
- tabindex: _state.menuState === MenuStates.Open ? 0 : void 0,
231
- style: [theirProps.style, styles, `--button-width: ${buttonSize.width}`].filter(Boolean).join("; ")
232
- }),
233
- ...transitionDataAttributes(transitionData)
234
- });
278
+
279
+ const slot = $derived({
280
+ open: _state.menuState === MenuStates.Open,
281
+ } satisfies ItemsRenderPropArg)
282
+
283
+ const buttonSize = useElementSize({
284
+ get element() {
285
+ return _state.buttonElement
286
+ },
287
+ unit: true,
288
+ })
289
+
290
+ const ourProps = $derived({
291
+ ...mergeProps(anchor ? getFloatingPanelProps() : {}, {
292
+ "aria-activedescendant": _state.activeItemIndex === null ? undefined : _state.items[_state.activeItemIndex]?.id,
293
+ "aria-labelledby": _state.buttonElement?.id,
294
+ id,
295
+ onkeydown: handleKeyDown,
296
+ onkeyup: handleKeyUp,
297
+ role: "menu",
298
+ // When the `Menu` is closed, it should not be focusable. This allows us
299
+ // to skip focusing the `MenuItems` when pressing the tab key on an
300
+ // open `Menu`, and go to the next focusable element.
301
+ tabindex: _state.menuState === MenuStates.Open ? 0 : undefined,
302
+ style: [theirProps.style, styles, `--button-width: ${buttonSize.width}`].filter(Boolean).join("; "),
303
+ }),
304
+ ...transitionDataAttributes(transitionData),
305
+ })
235
306
  </script>
236
307
 
237
308
  <Portal enabled={portal ? theirProps.static || visible : false}>
@@ -243,6 +314,6 @@ const ourProps = $derived({
243
314
  features={ItemsRenderFeatures}
244
315
  visible={panelEnabled}
245
316
  name="MenuItems"
246
- bind:ref
317
+ bind:element
247
318
  />
248
319
  </Portal>
@@ -1,52 +1,18 @@
1
- import type { ElementType, Props } from "../utils/types.js";
1
+ import type { Props } from "../utils/types.js";
2
2
  import { type PropsForFeatures } from "../utils/render.js";
3
3
  import { type AnchorProps } from "../internal/floating.svelte.js";
4
4
  declare const DEFAULT_ITEMS_TAG: "div";
5
5
  type ItemsRenderPropArg = {
6
6
  open: boolean;
7
7
  };
8
- type ItemsPropsWeControl = "aria-activedescendant" | "aria-labelledby" | "role" | "tabIndex";
9
8
  declare let ItemsRenderFeatures: number;
10
- export type MenuItemsProps<TTag extends ElementType = typeof DEFAULT_ITEMS_TAG> = Props<TTag, ItemsRenderPropArg, ItemsPropsWeControl, {
9
+ export type MenuItemsProps = Props<typeof DEFAULT_ITEMS_TAG, ItemsRenderPropArg, {
10
+ element?: HTMLElement;
11
11
  id?: string;
12
12
  anchor?: AnchorProps;
13
13
  portal?: boolean;
14
14
  modal?: boolean;
15
15
  transition?: boolean;
16
16
  } & PropsForFeatures<typeof ItemsRenderFeatures>>;
17
- import { type Snippet } from "svelte";
18
- declare class __sveltets_Render<TTag extends ElementType = typeof DEFAULT_ITEMS_TAG> {
19
- props(): {
20
- as?: TTag | undefined;
21
- } & (Exclude<keyof import("../utils/types.js").PropsOf<TTag>, ("slot" | "as" | "children" | "class" | "ref") | "anchor" | "unmount" | "static" | "id" | "transition" | "portal" | "modal" | ItemsPropsWeControl> extends infer T extends keyof import("../utils/types.js").PropsOf<TTag> ? { [P in T]: import("../utils/types.js").PropsOf<TTag>[P]; } : never) & {
22
- children?: Snippet<[{
23
- slot: ItemsRenderPropArg;
24
- props: Record<string, any>;
25
- }]> | undefined;
26
- class?: string | ((bag: ItemsRenderPropArg) => string) | null | undefined;
27
- ref?: HTMLElement;
28
- } & {
29
- id?: string;
30
- anchor?: AnchorProps;
31
- portal?: boolean;
32
- modal?: boolean;
33
- transition?: boolean;
34
- } & {
35
- static?: boolean | undefined;
36
- unmount?: boolean | undefined;
37
- };
38
- events(): {};
39
- slots(): {};
40
- bindings(): "ref";
41
- exports(): {};
42
- }
43
- interface $$IsomorphicComponent {
44
- new <TTag extends ElementType = typeof DEFAULT_ITEMS_TAG>(options: import('svelte').ComponentConstructorOptions<ReturnType<__sveltets_Render<TTag>['props']>>): import('svelte').SvelteComponent<ReturnType<__sveltets_Render<TTag>['props']>, ReturnType<__sveltets_Render<TTag>['events']>, ReturnType<__sveltets_Render<TTag>['slots']>> & {
45
- $$bindings?: ReturnType<__sveltets_Render<TTag>['bindings']>;
46
- } & ReturnType<__sveltets_Render<TTag>['exports']>;
47
- <TTag extends ElementType = typeof DEFAULT_ITEMS_TAG>(internal: unknown, props: ReturnType<__sveltets_Render<TTag>['props']> & {}): ReturnType<__sveltets_Render<TTag>['exports']>;
48
- z_$$bindings?: ReturnType<__sveltets_Render<any>['bindings']>;
49
- }
50
- declare const MenuItems: $$IsomorphicComponent;
51
- type MenuItems<TTag extends ElementType = typeof DEFAULT_ITEMS_TAG> = InstanceType<typeof MenuItems<TTag>>;
17
+ declare const MenuItems: import("svelte").Component<MenuItemsProps, {}, "element">;
52
18
  export default MenuItems;
@@ -1,14 +1,30 @@
1
- <script lang="ts" module>const DEFAULT_SECTION_TAG = "div";
1
+ <script lang="ts" module>
2
+ import type { Props } from "../utils/types.js"
3
+
4
+ const DEFAULT_SECTION_TAG = "div" as const
5
+ type SectionRenderPropArg = {}
6
+ type SectionPropsWeControl = "role" | "aria-labelledby"
7
+
8
+ export type MenuSectionProps = Props<
9
+ typeof DEFAULT_SECTION_TAG,
10
+ SectionRenderPropArg,
11
+ {
12
+ element?: HTMLElement
13
+ }
14
+ >
2
15
  </script>
3
16
 
4
- <script lang="ts" generics="TTag extends ElementType = typeof DEFAULT_SECTION_TAG">import { useLabels } from "../label/context.svelte.js";
5
- import ElementOrComponent from "../utils/ElementOrComponent.svelte";
6
- const labelledby = useLabels();
7
- let { ref = $bindable(), ...theirProps } = $props();
8
- const ourProps = $derived({
9
- "aria-labelledby": labelledby,
10
- role: "group"
11
- });
17
+ <script lang="ts">
18
+ import { useLabels } from "../label/context.svelte.js"
19
+ import ElementOrComponent from "../utils/ElementOrComponent.svelte"
20
+
21
+ const labelledby = useLabels()
22
+
23
+ let { element = $bindable(), ...theirProps }: MenuSectionProps = $props()
24
+ const ourProps = $derived({
25
+ "aria-labelledby": labelledby,
26
+ role: "group",
27
+ })
12
28
  </script>
13
29
 
14
- <ElementOrComponent {ourProps} {theirProps} defaultTag={DEFAULT_SECTION_TAG} name="MenuSection" bind:ref />
30
+ <ElementOrComponent {ourProps} {theirProps} defaultTag={DEFAULT_SECTION_TAG} name="MenuSection" bind:element />
@@ -1,32 +1,8 @@
1
- import type { Snippet } from "svelte";
2
- import type { ElementType, Props } from "../utils/types.js";
1
+ import type { Props } from "../utils/types.js";
3
2
  declare const DEFAULT_SECTION_TAG: "div";
4
3
  type SectionRenderPropArg = {};
5
- type SectionPropsWeControl = "role" | "aria-labelledby";
6
- export type MenuSectionProps<TTag extends ElementType = typeof DEFAULT_SECTION_TAG> = Props<TTag, SectionRenderPropArg, SectionPropsWeControl>;
7
- declare class __sveltets_Render<TTag extends ElementType = typeof DEFAULT_SECTION_TAG> {
8
- props(): {
9
- as?: TTag | undefined;
10
- } & (Exclude<keyof import("../utils/types.js").PropsOf<TTag>, ("slot" | "as" | "children" | "class" | "ref") | SectionPropsWeControl> extends infer T extends keyof import("../utils/types.js").PropsOf<TTag> ? { [P in T]: import("../utils/types.js").PropsOf<TTag>[P]; } : never) & {
11
- children?: Snippet<[{
12
- slot: SectionRenderPropArg;
13
- props: Record<string, any>;
14
- }]> | undefined;
15
- class?: string | ((bag: SectionRenderPropArg) => string) | null | undefined;
16
- ref?: HTMLElement;
17
- };
18
- events(): {};
19
- slots(): {};
20
- bindings(): "ref";
21
- exports(): {};
22
- }
23
- interface $$IsomorphicComponent {
24
- new <TTag extends ElementType = typeof DEFAULT_SECTION_TAG>(options: import('svelte').ComponentConstructorOptions<ReturnType<__sveltets_Render<TTag>['props']>>): import('svelte').SvelteComponent<ReturnType<__sveltets_Render<TTag>['props']>, ReturnType<__sveltets_Render<TTag>['events']>, ReturnType<__sveltets_Render<TTag>['slots']>> & {
25
- $$bindings?: ReturnType<__sveltets_Render<TTag>['bindings']>;
26
- } & ReturnType<__sveltets_Render<TTag>['exports']>;
27
- <TTag extends ElementType = typeof DEFAULT_SECTION_TAG>(internal: unknown, props: ReturnType<__sveltets_Render<TTag>['props']> & {}): ReturnType<__sveltets_Render<TTag>['exports']>;
28
- z_$$bindings?: ReturnType<__sveltets_Render<any>['bindings']>;
29
- }
30
- declare const MenuSection: $$IsomorphicComponent;
31
- type MenuSection<TTag extends ElementType = typeof DEFAULT_SECTION_TAG> = InstanceType<typeof MenuSection<TTag>>;
4
+ export type MenuSectionProps = Props<typeof DEFAULT_SECTION_TAG, SectionRenderPropArg, {
5
+ element?: HTMLElement;
6
+ }>;
7
+ declare const MenuSection: import("svelte").Component<MenuSectionProps, {}, "element">;
32
8
  export default MenuSection;