@pzerelles/headlessui-svelte 2.1.2-next.4 → 2.1.2-next.40

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 (252) hide show
  1. package/dist/button/Button.svelte +15 -18
  2. package/dist/button/Button.svelte.d.ts +8 -36
  3. package/dist/button/index.d.ts +1 -1
  4. package/dist/button/index.js +1 -1
  5. package/dist/checkbox/Checkbox.svelte +30 -26
  6. package/dist/checkbox/Checkbox.svelte.d.ts +17 -38
  7. package/dist/checkbox/index.d.ts +1 -1
  8. package/dist/checkbox/index.js +1 -1
  9. package/dist/close-button/CloseButton.svelte +4 -7
  10. package/dist/close-button/CloseButton.svelte.d.ts +3 -46
  11. package/dist/close-button/index.d.ts +1 -0
  12. package/dist/close-button/index.js +1 -0
  13. package/dist/data-interactive/DataInteractive.svelte +6 -22
  14. package/dist/data-interactive/DataInteractive.svelte.d.ts +9 -34
  15. package/dist/data-interactive/index.d.ts +1 -1
  16. package/dist/data-interactive/index.js +1 -1
  17. package/dist/description/Description.svelte +28 -23
  18. package/dist/description/Description.svelte.d.ts +9 -30
  19. package/dist/description/context.svelte.js +14 -16
  20. package/dist/description/index.d.ts +1 -1
  21. package/dist/dialog/Dialog.svelte +315 -31
  22. package/dist/dialog/Dialog.svelte.d.ts +7 -45
  23. package/dist/dialog/DialogBackdrop.svelte +11 -14
  24. package/dist/dialog/DialogBackdrop.svelte.d.ts +8 -33
  25. package/dist/dialog/DialogPanel.svelte +23 -19
  26. package/dist/dialog/DialogPanel.svelte.d.ts +8 -34
  27. package/dist/dialog/DialogTitle.svelte +17 -8
  28. package/dist/dialog/DialogTitle.svelte.d.ts +9 -30
  29. package/dist/dialog/context.svelte.js +2 -2
  30. package/dist/dialog/index.d.ts +4 -4
  31. package/dist/dialog/index.js +4 -4
  32. package/dist/field/Field.svelte +27 -26
  33. package/dist/field/Field.svelte.d.ts +7 -34
  34. package/dist/field/index.d.ts +1 -1
  35. package/dist/fieldset/Fieldset.svelte +14 -20
  36. package/dist/fieldset/Fieldset.svelte.d.ts +8 -35
  37. package/dist/fieldset/index.d.ts +1 -1
  38. package/dist/focus-trap/FocusTrap.svelte +30 -54
  39. package/dist/focus-trap/FocusTrap.svelte.d.ts +10 -52
  40. package/dist/focus-trap/FocusTrapFeatures.d.ts +14 -0
  41. package/dist/focus-trap/FocusTrapFeatures.js +15 -0
  42. package/dist/hooks/use-controllable.svelte.js +2 -1
  43. package/dist/hooks/use-did-element-move.svelte.js +5 -10
  44. package/dist/hooks/use-disabled.d.ts +6 -1
  45. package/dist/hooks/use-disabled.js +10 -5
  46. package/dist/hooks/use-event-listener.svelte.d.ts +1 -1
  47. package/dist/hooks/use-event-listener.svelte.js +3 -1
  48. package/dist/hooks/use-inert-others.svelte.js +10 -10
  49. package/dist/hooks/use-resolve-button-type.svelte.js +0 -1
  50. package/dist/hooks/use-root-containers.svelte.d.ts +2 -2
  51. package/dist/hooks/use-root-containers.svelte.js +5 -5
  52. package/dist/hooks/use-tab-direction.svelte.js +1 -1
  53. package/dist/index.d.ts +5 -2
  54. package/dist/index.js +5 -2
  55. package/dist/input/Input.svelte +28 -21
  56. package/dist/input/Input.svelte.d.ts +16 -33
  57. package/dist/input/index.d.ts +1 -1
  58. package/dist/input/index.js +1 -1
  59. package/dist/internal/FloatingProvider.svelte +17 -0
  60. package/dist/internal/FloatingProvider.svelte.d.ts +8 -0
  61. package/dist/internal/FocusSentinel.svelte +33 -32
  62. package/dist/internal/FocusSentinel.svelte.d.ts +4 -18
  63. package/dist/internal/ForcePortalRoot.svelte.d.ts +4 -18
  64. package/dist/internal/FormFields.svelte +18 -13
  65. package/dist/internal/FormFields.svelte.d.ts +4 -18
  66. package/dist/internal/FormFieldsProvider.svelte +17 -0
  67. package/dist/internal/FormFieldsProvider.svelte.d.ts +7 -0
  68. package/dist/internal/FormResolver.svelte +6 -2
  69. package/dist/internal/FormResolver.svelte.d.ts +4 -18
  70. package/dist/internal/Hidden.svelte +10 -10
  71. package/dist/internal/Hidden.svelte.d.ts +6 -33
  72. package/dist/internal/MainTreeProvider.svelte +1 -1
  73. package/dist/internal/MainTreeProvider.svelte.d.ts +4 -18
  74. package/dist/internal/Portal.svelte.d.ts +4 -18
  75. package/dist/internal/floating-provider.svelte.d.ts +3 -0
  76. package/dist/internal/floating-provider.svelte.js +206 -0
  77. package/dist/internal/floating.svelte.d.ts +46 -22
  78. package/dist/internal/floating.svelte.js +90 -272
  79. package/dist/internal/form-fields.svelte.d.ts +10 -0
  80. package/dist/internal/form-fields.svelte.js +23 -0
  81. package/dist/label/Label.svelte +17 -13
  82. package/dist/label/Label.svelte.d.ts +8 -33
  83. package/dist/label/context.svelte.js +1 -1
  84. package/dist/label/index.d.ts +1 -1
  85. package/dist/legend/Legend.svelte +21 -15
  86. package/dist/legend/Legend.svelte.d.ts +9 -34
  87. package/dist/listbox/Listbox.svelte +79 -163
  88. package/dist/listbox/Listbox.svelte.d.ts +16 -101
  89. package/dist/listbox/ListboxButton.svelte +24 -29
  90. package/dist/listbox/ListboxButton.svelte.d.ts +8 -38
  91. package/dist/listbox/ListboxOption.svelte +33 -27
  92. package/dist/listbox/ListboxOption.svelte.d.ts +16 -32
  93. package/dist/listbox/ListboxOptions.svelte +126 -73
  94. package/dist/listbox/ListboxOptions.svelte.d.ts +8 -43
  95. package/dist/listbox/ListboxSelectedOption.svelte +24 -26
  96. package/dist/listbox/ListboxSelectedOption.svelte.d.ts +14 -39
  97. package/dist/listbox/context.svelte.d.ts +76 -0
  98. package/dist/listbox/context.svelte.js +36 -0
  99. package/dist/listbox/index.d.ts +5 -5
  100. package/dist/listbox/index.js +4 -4
  101. package/dist/menu/Menu.svelte +22 -266
  102. package/dist/menu/Menu.svelte.d.ts +7 -37
  103. package/dist/menu/MenuButton.svelte +22 -24
  104. package/dist/menu/MenuButton.svelte.d.ts +8 -39
  105. package/dist/menu/MenuHeading.svelte +12 -16
  106. package/dist/menu/MenuHeading.svelte.d.ts +7 -36
  107. package/dist/menu/MenuItem.svelte +18 -23
  108. package/dist/menu/MenuItem.svelte.d.ts +9 -39
  109. package/dist/menu/MenuItems.svelte +33 -34
  110. package/dist/menu/MenuItems.svelte.d.ts +8 -43
  111. package/dist/menu/MenuSection.svelte +9 -12
  112. package/dist/menu/MenuSection.svelte.d.ts +7 -33
  113. package/dist/menu/MenuSeparator.svelte +9 -12
  114. package/dist/menu/MenuSeparator.svelte.d.ts +7 -33
  115. package/dist/menu/context.svelte.d.ts +2 -1
  116. package/dist/menu/context.svelte.js +212 -2
  117. package/dist/menu/index.d.ts +7 -7
  118. package/dist/menu/index.js +3 -3
  119. package/dist/popover/Popover.svelte +225 -0
  120. package/dist/popover/Popover.svelte.d.ts +15 -0
  121. package/dist/popover/PopoverBackdrop.svelte +83 -0
  122. package/dist/popover/PopoverBackdrop.svelte.d.ts +17 -0
  123. package/dist/popover/PopoverButton.svelte +324 -0
  124. package/dist/popover/PopoverButton.svelte.d.ts +21 -0
  125. package/dist/popover/PopoverGroup.svelte +66 -0
  126. package/dist/popover/PopoverGroup.svelte.d.ts +9 -0
  127. package/dist/popover/PopoverPanel.svelte +359 -0
  128. package/dist/popover/PopoverPanel.svelte.d.ts +22 -0
  129. package/dist/popover/context.svelte.d.ts +51 -0
  130. package/dist/popover/context.svelte.js +108 -0
  131. package/dist/popover/index.d.ts +5 -0
  132. package/dist/popover/index.js +5 -0
  133. package/dist/portal/InternalPortal.svelte +17 -17
  134. package/dist/portal/InternalPortal.svelte.d.ts +6 -33
  135. package/dist/portal/Portal.svelte +7 -6
  136. package/dist/portal/Portal.svelte.d.ts +3 -22
  137. package/dist/portal/PortalGroup.svelte +6 -14
  138. package/dist/portal/PortalGroup.svelte.d.ts +5 -34
  139. package/dist/radio-group/Radio.svelte +135 -0
  140. package/dist/radio-group/Radio.svelte.d.ts +35 -0
  141. package/dist/radio-group/RadioGroup.svelte +223 -0
  142. package/dist/radio-group/RadioGroup.svelte.d.ts +34 -0
  143. package/dist/radio-group/RadioOption.svelte +138 -0
  144. package/dist/radio-group/RadioOption.svelte.d.ts +37 -0
  145. package/dist/radio-group/contest.svelte.d.ts +30 -0
  146. package/dist/radio-group/contest.svelte.js +40 -0
  147. package/dist/radio-group/index.d.ts +3 -0
  148. package/dist/radio-group/index.js +3 -0
  149. package/dist/select/Select.svelte +103 -0
  150. package/dist/select/Select.svelte.d.ts +21 -0
  151. package/dist/select/index.d.ts +1 -0
  152. package/dist/select/index.js +1 -0
  153. package/dist/switch/Switch.svelte +27 -28
  154. package/dist/switch/Switch.svelte.d.ts +9 -42
  155. package/dist/switch/SwitchGroup.svelte +5 -5
  156. package/dist/switch/SwitchGroup.svelte.d.ts +8 -30
  157. package/dist/switch/index.d.ts +1 -1
  158. package/dist/switch/index.js +1 -1
  159. package/dist/tabs/Tab.svelte +26 -29
  160. package/dist/tabs/Tab.svelte.d.ts +8 -36
  161. package/dist/tabs/TabGroup.svelte +42 -264
  162. package/dist/tabs/TabGroup.svelte.d.ts +7 -57
  163. package/dist/tabs/TabList.svelte +13 -16
  164. package/dist/tabs/TabList.svelte.d.ts +8 -31
  165. package/dist/tabs/TabPanel.svelte +19 -19
  166. package/dist/tabs/TabPanel.svelte.d.ts +8 -38
  167. package/dist/tabs/TabPanels.svelte +11 -9
  168. package/dist/tabs/TabPanels.svelte.d.ts +8 -30
  169. package/dist/tabs/context.svelte.d.ts +31 -0
  170. package/dist/tabs/context.svelte.js +134 -0
  171. package/dist/tabs/index.d.ts +5 -5
  172. package/dist/tabs/index.js +4 -4
  173. package/dist/textarea/Textarea.svelte +23 -19
  174. package/dist/textarea/Textarea.svelte.d.ts +18 -30
  175. package/dist/textarea/index.d.ts +1 -1
  176. package/dist/textarea/index.js +1 -1
  177. package/dist/transition/InternalTransitionChild.svelte +19 -12
  178. package/dist/transition/InternalTransitionChild.svelte.d.ts +4 -35
  179. package/dist/transition/Transition.svelte +16 -17
  180. package/dist/transition/Transition.svelte.d.ts +8 -38
  181. package/dist/transition/TransitionChild.svelte +13 -12
  182. package/dist/transition/TransitionChild.svelte.d.ts +11 -38
  183. package/dist/transition/context.svelte.js +9 -9
  184. package/dist/transition/index.d.ts +2 -2
  185. package/dist/transition/index.js +2 -2
  186. package/dist/utils/DisabledProvider.svelte +10 -0
  187. package/dist/utils/DisabledProvider.svelte.d.ts +8 -0
  188. package/dist/utils/ElementOrComponent.svelte +57 -14
  189. package/dist/utils/ElementOrComponent.svelte.d.ts +19 -29
  190. package/dist/utils/StableCollection.svelte.d.ts +4 -18
  191. package/dist/utils/floating-ui/svelte/components/FloatingNode.svelte +32 -0
  192. package/dist/utils/floating-ui/svelte/components/FloatingNode.svelte.d.ts +8 -0
  193. package/dist/utils/floating-ui/svelte/components/FloatingTree.svelte +94 -0
  194. package/dist/utils/floating-ui/svelte/components/FloatingTree.svelte.d.ts +26 -0
  195. package/dist/utils/floating-ui/svelte/hooks/useFloating.svelte.d.ts +6 -0
  196. package/dist/utils/floating-ui/svelte/hooks/useFloating.svelte.js +158 -0
  197. package/dist/utils/floating-ui/svelte/hooks/useFloatingRootContext.svelte.d.ts +11 -0
  198. package/dist/utils/floating-ui/svelte/hooks/useFloatingRootContext.svelte.js +53 -0
  199. package/dist/utils/floating-ui/svelte/hooks/useId.svelte.d.ts +9 -0
  200. package/dist/utils/floating-ui/svelte/hooks/useId.svelte.js +28 -0
  201. package/dist/utils/floating-ui/svelte/hooks/useInteractions.svelte.d.ts +23 -0
  202. package/dist/utils/floating-ui/svelte/hooks/useInteractions.svelte.js +72 -0
  203. package/dist/utils/floating-ui/svelte/index.d.ts +5 -0
  204. package/dist/utils/floating-ui/svelte/index.js +5 -0
  205. package/dist/utils/floating-ui/svelte/inner.svelte.d.ts +83 -0
  206. package/dist/utils/floating-ui/svelte/inner.svelte.js +178 -0
  207. package/dist/utils/floating-ui/svelte/types.d.ts +114 -0
  208. package/dist/utils/floating-ui/svelte/utils/createPubSub.d.ts +5 -0
  209. package/dist/utils/floating-ui/svelte/utils/createPubSub.js +14 -0
  210. package/dist/utils/floating-ui/svelte/utils/getFloatingFocusElement.d.ts +2 -0
  211. package/dist/utils/floating-ui/svelte/utils/getFloatingFocusElement.js +13 -0
  212. package/dist/utils/floating-ui/svelte/utils/log.d.ts +2 -0
  213. package/dist/utils/floating-ui/svelte/utils/log.js +19 -0
  214. package/dist/utils/floating-ui/svelte/utils.d.ts +19 -0
  215. package/dist/utils/floating-ui/svelte/utils.js +136 -0
  216. package/dist/utils/floating-ui/svelte-dom/arrow.d.ts +22 -0
  217. package/dist/utils/floating-ui/svelte-dom/arrow.js +29 -0
  218. package/dist/utils/floating-ui/svelte-dom/index.d.ts +2 -0
  219. package/dist/utils/floating-ui/svelte-dom/index.js +2 -0
  220. package/dist/utils/floating-ui/svelte-dom/types.d.ts +80 -0
  221. package/dist/utils/floating-ui/svelte-dom/types.js +3 -0
  222. package/dist/utils/floating-ui/svelte-dom/useFloating.svelte.d.ts +6 -0
  223. package/dist/utils/floating-ui/svelte-dom/useFloating.svelte.js +182 -0
  224. package/dist/utils/floating-ui/svelte-dom/utils/deepEqual.d.ts +1 -0
  225. package/dist/utils/floating-ui/svelte-dom/utils/deepEqual.js +50 -0
  226. package/dist/utils/floating-ui/svelte-dom/utils/getDPR.d.ts +1 -0
  227. package/dist/utils/floating-ui/svelte-dom/utils/getDPR.js +7 -0
  228. package/dist/utils/floating-ui/svelte-dom/utils/roundByDPR.d.ts +1 -0
  229. package/dist/utils/floating-ui/svelte-dom/utils/roundByDPR.js +5 -0
  230. package/dist/utils/floating-ui/svelte-dom/utils/useLatestRef.d.ts +4 -0
  231. package/dist/utils/floating-ui/svelte-dom/utils/useLatestRef.js +7 -0
  232. package/dist/utils/id.d.ts +1 -1
  233. package/dist/utils/id.js +1 -1
  234. package/dist/utils/index.d.ts +3 -0
  235. package/dist/utils/index.js +3 -0
  236. package/dist/utils/state.js +4 -4
  237. package/dist/utils/style.d.ts +2 -0
  238. package/dist/utils/style.js +6 -0
  239. package/dist/utils/types.d.ts +12 -18
  240. package/package.json +33 -32
  241. package/dist/combobox/Combobox.svelte +0 -53
  242. package/dist/combobox/Combobox.svelte.d.ts +0 -50
  243. package/dist/dialog/InternalDialog.svelte +0 -294
  244. package/dist/dialog/InternalDialog.svelte.d.ts +0 -42
  245. package/dist/internal/HoistFormFields.svelte +0 -14
  246. package/dist/internal/HoistFormFields.svelte.d.ts +0 -21
  247. package/dist/internal/id.d.ts +0 -8
  248. package/dist/internal/id.js +0 -11
  249. package/dist/utils/Generic.svelte +0 -56
  250. package/dist/utils/Generic.svelte.d.ts +0 -35
  251. package/dist/utils/alternative-types.d.ts +0 -21
  252. /package/dist/utils/{alternative-types.js → floating-ui/svelte/types.js} +0 -0
@@ -0,0 +1,359 @@
1
+ <script lang="ts" module>
2
+ import type { Props } from "../utils/types.js"
3
+ import { RenderFeatures } from "../utils/render.js"
4
+
5
+ const DEFAULT_PANEL_TAG = "div" as const
6
+ export type PanelRenderPropArg = {
7
+ open: boolean
8
+ close: (focusableElement?: HTMLElement) => void
9
+ }
10
+
11
+ const PanelRenderFeatures = RenderFeatures.RenderStrategy | RenderFeatures.Static
12
+
13
+ type PanelPropsWeControl = "tabIndex"
14
+
15
+ export type PopoverPanelOwnProps = {
16
+ element?: HTMLElement
17
+ id?: string
18
+ focus?: boolean
19
+ anchor?: AnchorProps
20
+ portal?: boolean
21
+ modal?: boolean
22
+ transition?: boolean
23
+
24
+ // ItemsRenderFeatures
25
+ static?: boolean
26
+ unmount?: boolean
27
+ }
28
+
29
+ export type PopoverPanelProps = Props<typeof DEFAULT_PANEL_TAG, PanelRenderPropArg, PopoverPanelOwnProps>
30
+ </script>
31
+
32
+ <script lang="ts">
33
+ import { useId } from "../hooks/use-id.js"
34
+ import ElementOrComponent from "../utils/ElementOrComponent.svelte"
35
+ import { mergeProps } from "../utils/render.js"
36
+ import {
37
+ useFloatingPanel,
38
+ useFloatingPanelProps,
39
+ useResolvedAnchor,
40
+ type AnchorProps,
41
+ } from "../internal/floating.svelte.js"
42
+ import {
43
+ type PopoverAPIContext,
44
+ type PopoverPanelContext,
45
+ PopoverStates,
46
+ usePopoverAPIContext,
47
+ usePopoverContext,
48
+ } from "./context.svelte.js"
49
+ import { getOwnerDocument } from "../utils/owner.js"
50
+ import { clearOpenClosedContext, State, useOpenClosed } from "../internal/open-closed.js"
51
+ import { transitionDataAttributes, useTransition } from "../hooks/use-transition.svelte.js"
52
+ import { useOnDisappear } from "../hooks/use-on-disappear.svelte.js"
53
+ import { useScrollLock } from "../hooks/use-scroll-lock.svelte.js"
54
+ import { Focus, focusIn, FocusResult, getFocusableElements } from "../utils/focus-management.js"
55
+ import { useElementSize } from "../hooks/use-element-size.svelte.js"
56
+ import { useTabDirection, Direction as TabDirection } from "../hooks/use-tab-direction.svelte.js"
57
+ import { match } from "../utils/match.js"
58
+ import { microTask } from "../utils/microTask.js"
59
+ import { setContext, untrack } from "svelte"
60
+ import Portal from "../portal/Portal.svelte"
61
+ import Hidden, { HiddenFeatures } from "../internal/Hidden.svelte"
62
+
63
+ let internalId = useId()
64
+ let {
65
+ element = $bindable(),
66
+ id = `headlessui-popover-panel-${internalId}`,
67
+ focus = false,
68
+ anchor: rawAnchor,
69
+ portal: theirPortal = false,
70
+ modal = false,
71
+ transition = false,
72
+ ...theirProps
73
+ }: PopoverPanelProps = $props()
74
+
75
+ const context = usePopoverContext("PopoverPanel")
76
+ const api = usePopoverAPIContext("PopoverPanel")
77
+ const { close, isPortalled } = $derived(api)
78
+
79
+ const beforePanelSentinelId = `headlessui-focus-sentinel-before-${internalId}`
80
+ const afterPanelSentinelId = `headlessui-focus-sentinel-after-${internalId}`
81
+
82
+ const resolvedAnchor = useResolvedAnchor({
83
+ get anchor() {
84
+ return rawAnchor
85
+ },
86
+ })
87
+ const { anchor } = $derived(resolvedAnchor)
88
+ const floatingPanel = useFloatingPanel({
89
+ get placement() {
90
+ return anchor
91
+ },
92
+ })
93
+ const { setFloating, styles } = $derived(floatingPanel)
94
+ const getFloatingPanelProps = useFloatingPanelProps()
95
+
96
+ // Always enable `portal` functionality, when `anchor` is enabled
97
+ const portal = $derived(!!anchor || theirPortal)
98
+
99
+ $effect(() => {
100
+ if (anchor) setFloating(element ?? null)
101
+ untrack(() => context.setPanel(element))
102
+ })
103
+ const ownerDocument = $derived(getOwnerDocument(element))
104
+
105
+ $effect(() => {
106
+ id
107
+ return untrack(() => {
108
+ context.setPanelId(id)
109
+ return () => {
110
+ context.setPanelId(undefined)
111
+ }
112
+ })
113
+ })
114
+
115
+ const usesOpenClosedState = useOpenClosed()
116
+ const _transition = useTransition({
117
+ get enabled() {
118
+ return transition
119
+ },
120
+ get element() {
121
+ return element
122
+ },
123
+ get show() {
124
+ return usesOpenClosedState !== null
125
+ ? (usesOpenClosedState.value & State.Open) === State.Open
126
+ : context.popoverState === PopoverStates.Open
127
+ },
128
+ })
129
+ const { visible, data: transitionData } = $derived(_transition)
130
+
131
+ // Ensure we close the popover as soon as the button becomes hidden
132
+ useOnDisappear({
133
+ get enabled() {
134
+ return visible
135
+ },
136
+ get ref() {
137
+ return context.button
138
+ },
139
+ ondisappear: () => {
140
+ context.closePopover()
141
+ },
142
+ })
143
+
144
+ // Enable scroll locking when the popover is visible, and `modal` is enabled
145
+ const scrollLockEnabled = $derived(context.__demoMode ? false : modal && visible)
146
+ useScrollLock({
147
+ get enabled() {
148
+ return scrollLockEnabled
149
+ },
150
+ get ownerDocument() {
151
+ return ownerDocument
152
+ },
153
+ })
154
+
155
+ const handleKeyDown = (event: KeyboardEvent) => {
156
+ switch (event.key) {
157
+ case "Escape":
158
+ if (context.popoverState !== PopoverStates.Open) return
159
+ if (!element) return
160
+ if (ownerDocument?.activeElement && !element.contains(ownerDocument.activeElement)) {
161
+ return
162
+ }
163
+ event.preventDefault()
164
+ event.stopPropagation()
165
+ context.closePopover()
166
+ context.button?.focus()
167
+ break
168
+ }
169
+ }
170
+
171
+ // Unlink on "unmount" children
172
+ $effect(() => {
173
+ if (theirProps.static) return
174
+
175
+ if (context.popoverState === PopoverStates.Closed && (theirProps.unmount ?? true)) {
176
+ context.setPanel(undefined)
177
+ }
178
+ }) //, [state.popoverState, props.unmount, props.static, dispatch])
179
+
180
+ // Move focus within panel
181
+ $effect(() => {
182
+ if (context.__demoMode) return
183
+ if (!focus) return
184
+ if (context.popoverState !== PopoverStates.Open) return
185
+ if (!element) return
186
+
187
+ const activeElement = ownerDocument?.activeElement as HTMLElement
188
+ if (element.contains(activeElement)) return // Already focused within Dialog
189
+
190
+ focusIn(element, Focus.First)
191
+ }) //, [state.__demoMode, focus, internalPanelRef.current, state.popoverState])
192
+
193
+ const slot = $derived({
194
+ open: context.popoverState === PopoverStates.Open,
195
+ close,
196
+ } satisfies PanelRenderPropArg)
197
+
198
+ const buttonSize = useElementSize({
199
+ get element() {
200
+ return context.button ?? null
201
+ },
202
+ unit: true,
203
+ })
204
+ const ourProps: Record<string, any> = $derived(
205
+ mergeProps(anchor ? getFloatingPanelProps() : {}, {
206
+ id,
207
+ onkeydown: handleKeyDown,
208
+ onblur:
209
+ focus && context.popoverState === PopoverStates.Open
210
+ ? (event: FocusEvent) => {
211
+ let el = event.relatedTarget as HTMLElement
212
+ if (!el) return
213
+ if (!element) return
214
+ if (element.contains(el)) return
215
+
216
+ context.closePopover()
217
+
218
+ if (context.beforePanelSentinel?.contains?.(el) || context.afterPanelSentinel?.contains?.(el)) {
219
+ el.focus({ preventScroll: true })
220
+ }
221
+ }
222
+ : undefined,
223
+ tabIndex: -1,
224
+ style: [theirProps.style, styles, `--button-width: ${buttonSize.width}`].filter(Boolean).join("; "),
225
+ ...transitionDataAttributes(transitionData),
226
+ })
227
+ )
228
+
229
+ const direction = useTabDirection()
230
+ const handleBeforeFocus = () => {
231
+ let el = element as HTMLElement
232
+ if (!el) return
233
+
234
+ function run() {
235
+ match(direction.current, {
236
+ [TabDirection.Forwards]: () => {
237
+ // Try to focus the first thing in the panel. But if that fails (e.g.: there are no
238
+ // focusable elements, then we can move outside of the panel)
239
+ let result = focusIn(el, Focus.First)
240
+ if (result === FocusResult.Error) {
241
+ context.afterPanelSentinel?.focus()
242
+ }
243
+ },
244
+ [TabDirection.Backwards]: () => {
245
+ // Coming from the PopoverPanel (which is portalled to somewhere else). Let's redirect
246
+ // the focus to the PopoverButton again.
247
+ context.button?.focus({ preventScroll: true })
248
+ },
249
+ })
250
+ }
251
+
252
+ // TODO: Cleanup once we are using real browser tests
253
+ if (process.env.NODE_ENV === "test") {
254
+ microTask(run)
255
+ } else {
256
+ run()
257
+ }
258
+ }
259
+
260
+ const handleAfterFocus = () => {
261
+ let el = element as HTMLElement
262
+ if (!el) return
263
+
264
+ function run() {
265
+ match(direction.current, {
266
+ [TabDirection.Forwards]: () => {
267
+ if (!context.button) return
268
+
269
+ const elements = getFocusableElements()
270
+
271
+ const idx = elements.indexOf(context.button)
272
+ const before = elements.slice(0, idx + 1)
273
+ const after = elements.slice(idx + 1)
274
+
275
+ const combined = [...after, ...before]
276
+
277
+ // Ignore sentinel buttons and items inside the panel
278
+ for (const element of combined.slice()) {
279
+ if (element.dataset.headlessuiFocusGuard === "true" || element?.contains(element)) {
280
+ let idx = combined.indexOf(element)
281
+ if (idx !== -1) combined.splice(idx, 1)
282
+ }
283
+ }
284
+
285
+ focusIn(combined, Focus.First, { sorted: false })
286
+ },
287
+ [TabDirection.Backwards]: () => {
288
+ // Try to focus the first thing in the panel. But if that fails (e.g.: there are no
289
+ // focusable elements, then we can move outside of the panel)
290
+ let result = focusIn(el, Focus.Previous)
291
+ if (result === FocusResult.Error) {
292
+ context.button?.focus()
293
+ }
294
+ },
295
+ })
296
+ }
297
+
298
+ // TODO: Cleanup once we are using real browser tests
299
+ if (process.env.NODE_ENV === "test") {
300
+ microTask(run)
301
+ } else {
302
+ run()
303
+ }
304
+ }
305
+
306
+ clearOpenClosedContext()
307
+ setContext<PopoverPanelContext>("PopoverPanelContext", {
308
+ get value() {
309
+ return id
310
+ },
311
+ })
312
+ setContext<PopoverAPIContext>("PopoverAPIContext", {
313
+ get close() {
314
+ return close
315
+ },
316
+ get isPortalled() {
317
+ return isPortalled
318
+ },
319
+ })
320
+ </script>
321
+
322
+ <Portal enabled={portal ? theirProps.static || visible : false}>
323
+ {#if visible && isPortalled}
324
+ <Hidden asChild id={beforePanelSentinelId} features={HiddenFeatures.Focusable}>
325
+ {#snippet children({ props })}
326
+ <button
327
+ {...props}
328
+ type="button"
329
+ data-headlessui-focus-guard
330
+ onfocus={handleBeforeFocus}
331
+ bind:this={context.beforePanelSentinel}>&zwnj;</button
332
+ >
333
+ {/snippet}
334
+ </Hidden>
335
+ {/if}
336
+ <ElementOrComponent
337
+ {ourProps}
338
+ {theirProps}
339
+ slots={slot}
340
+ defaultTag={DEFAULT_PANEL_TAG}
341
+ features={PanelRenderFeatures}
342
+ {visible}
343
+ name="PopoverPanel"
344
+ bind:element
345
+ />
346
+ {#if visible && isPortalled}
347
+ <Hidden asChild id={afterPanelSentinelId} features={HiddenFeatures.Focusable}>
348
+ {#snippet children({ props })}
349
+ <button
350
+ {...props}
351
+ type="button"
352
+ data-headlessui-focus-guard
353
+ onfocus={handleAfterFocus}
354
+ bind:this={context.afterPanelSentinel}>&zwnj;</button
355
+ >
356
+ {/snippet}
357
+ </Hidden>
358
+ {/if}
359
+ </Portal>
@@ -0,0 +1,22 @@
1
+ import type { Props } from "../utils/types.js";
2
+ declare const DEFAULT_PANEL_TAG: "div";
3
+ export type PanelRenderPropArg = {
4
+ open: boolean;
5
+ close: (focusableElement?: HTMLElement) => void;
6
+ };
7
+ export type PopoverPanelOwnProps = {
8
+ element?: HTMLElement;
9
+ id?: string;
10
+ focus?: boolean;
11
+ anchor?: AnchorProps;
12
+ portal?: boolean;
13
+ modal?: boolean;
14
+ transition?: boolean;
15
+ static?: boolean;
16
+ unmount?: boolean;
17
+ };
18
+ export type PopoverPanelProps = Props<typeof DEFAULT_PANEL_TAG, PanelRenderPropArg, PopoverPanelOwnProps>;
19
+ import { type AnchorProps } from "../internal/floating.svelte.js";
20
+ declare const PopoverPanel: import("svelte").Component<PopoverPanelProps, {}, "element">;
21
+ type PopoverPanel = ReturnType<typeof PopoverPanel>;
22
+ export default PopoverPanel;
@@ -0,0 +1,51 @@
1
+ import type { MouseEventHandler } from "svelte/elements";
2
+ export type MouseEvent<T extends EventTarget> = Parameters<MouseEventHandler<T>>[0];
3
+ export declare enum PopoverStates {
4
+ Open = 0,
5
+ Closed = 1
6
+ }
7
+ export interface StateDefinition {
8
+ popoverState: PopoverStates;
9
+ buttons: symbol[];
10
+ button?: HTMLElement;
11
+ buttonId?: string;
12
+ panel?: HTMLElement;
13
+ panelId?: string;
14
+ beforePanelSentinel?: HTMLButtonElement;
15
+ afterPanelSentinel?: HTMLButtonElement;
16
+ afterButtonSentinel?: HTMLButtonElement;
17
+ __demoMode: boolean;
18
+ }
19
+ interface ActionDefinition {
20
+ togglePopover(): void;
21
+ closePopover(): void;
22
+ setButton(button: HTMLElement): void;
23
+ setButtonId(buttonId: string | undefined): void;
24
+ setPanel(panel?: HTMLElement): void;
25
+ setPanelId(panelId?: string): void;
26
+ }
27
+ export type PopoverContext = StateDefinition & ActionDefinition;
28
+ export declare const createPopoverContext: (initialState: StateDefinition) => PopoverContext;
29
+ export declare function usePopoverContext(component: string): PopoverContext;
30
+ export type PopoverAPIContext = {
31
+ close(focusableElement?: HTMLElement | MouseEvent<HTMLElement>): void;
32
+ isPortalled: boolean;
33
+ };
34
+ export declare function usePopoverAPIContext(component: string): PopoverAPIContext;
35
+ export type PopoverGroupContext = {
36
+ registerPopover(registerBag: PopoverRegisterBag): void;
37
+ unregisterPopover(registerBag: PopoverRegisterBag): void;
38
+ isFocusWithinPopoverGroup(): boolean;
39
+ closeOthers(buttonId: string): void;
40
+ };
41
+ export declare function usePopoverGroupContext(): PopoverGroupContext | undefined;
42
+ export type PopoverPanelContext = {
43
+ value: string;
44
+ };
45
+ export declare function usePopoverPanelContext(): PopoverPanelContext | undefined;
46
+ export interface PopoverRegisterBag {
47
+ buttonId?: string;
48
+ panelId?: string;
49
+ close(): void;
50
+ }
51
+ export {};
@@ -0,0 +1,108 @@
1
+ import { getContext, setContext } from "svelte";
2
+ export var PopoverStates;
3
+ (function (PopoverStates) {
4
+ PopoverStates[PopoverStates["Open"] = 0] = "Open";
5
+ PopoverStates[PopoverStates["Closed"] = 1] = "Closed";
6
+ })(PopoverStates || (PopoverStates = {}));
7
+ export const createPopoverContext = (initialState) => {
8
+ const _state = $state(initialState);
9
+ const context = {
10
+ get popoverState() {
11
+ return _state.popoverState;
12
+ },
13
+ get buttons() {
14
+ return _state.buttons;
15
+ },
16
+ get button() {
17
+ return _state.button;
18
+ },
19
+ get buttonId() {
20
+ return _state.buttonId;
21
+ },
22
+ get panel() {
23
+ return _state.panel;
24
+ },
25
+ get panelId() {
26
+ return _state.panelId;
27
+ },
28
+ get beforePanelSentinel() {
29
+ return _state.beforePanelSentinel;
30
+ },
31
+ set beforePanelSentinel(value) {
32
+ _state.beforePanelSentinel = value;
33
+ },
34
+ get afterPanelSentinel() {
35
+ return _state.afterPanelSentinel;
36
+ },
37
+ set afterPanelSentinel(value) {
38
+ _state.afterPanelSentinel = value;
39
+ },
40
+ get afterButtonSentinel() {
41
+ return _state.afterButtonSentinel;
42
+ },
43
+ set afterButtonSentinel(value) {
44
+ _state.afterButtonSentinel = value;
45
+ },
46
+ get __demoMode() {
47
+ return _state.__demoMode;
48
+ },
49
+ togglePopover() {
50
+ _state.__demoMode = false;
51
+ _state.popoverState = _state.popoverState === PopoverStates.Closed ? PopoverStates.Open : PopoverStates.Closed;
52
+ },
53
+ closePopover() {
54
+ if (_state.popoverState === PopoverStates.Closed)
55
+ return;
56
+ _state.__demoMode = false;
57
+ _state.popoverState = PopoverStates.Closed;
58
+ },
59
+ setButton(button) {
60
+ if (_state.button === button)
61
+ return;
62
+ _state.button = button;
63
+ },
64
+ setButtonId(buttonId) {
65
+ if (_state.buttonId === buttonId)
66
+ return;
67
+ _state.buttonId = buttonId;
68
+ },
69
+ setPanel(panel) {
70
+ if (_state.panel === panel)
71
+ return;
72
+ _state.panel = panel;
73
+ },
74
+ setPanelId(panelId) {
75
+ if (_state.panelId === panelId)
76
+ return;
77
+ _state.panelId = panelId;
78
+ },
79
+ };
80
+ setContext("PopoverContext", context);
81
+ return context;
82
+ };
83
+ export function usePopoverContext(component) {
84
+ const context = getContext("PopoverContext");
85
+ if (!context) {
86
+ const err = new Error(`<${component} /> is missing a parent <Popover /> component.`);
87
+ if (Error.captureStackTrace)
88
+ Error.captureStackTrace(err, usePopoverContext);
89
+ throw err;
90
+ }
91
+ return context;
92
+ }
93
+ export function usePopoverAPIContext(component) {
94
+ const context = getContext("PopoverAPIContext");
95
+ if (!context) {
96
+ const err = new Error(`<${component} /> is missing a parent <Popover /> component.`);
97
+ if (Error.captureStackTrace)
98
+ Error.captureStackTrace(err, usePopoverAPIContext);
99
+ throw err;
100
+ }
101
+ return context;
102
+ }
103
+ export function usePopoverGroupContext() {
104
+ return getContext("PopoverGroupContext");
105
+ }
106
+ export function usePopoverPanelContext() {
107
+ return getContext("PopoverPanelContext");
108
+ }
@@ -0,0 +1,5 @@
1
+ export { default as Popover, type PopoverProps, type PopoverRenderPropArg as PopoverSlot, type PopoverOwnProps, } from "./Popover.svelte";
2
+ export { default as PopoverBackdrop, type PopoverBackdropProps, type BackdropRenderPropArg as PopoverBackdropSlot, type PopoverBackdropOwnProps, } from "./PopoverBackdrop.svelte";
3
+ export { default as PopoverButton, type PopoverButtonProps, type PopoverButtonSlot, type PopoverButtonOwnProps, } from "./PopoverButton.svelte";
4
+ export { default as PopoverGroup, type PopoverGroupProps, type PopoverGroupOwnProps } from "./PopoverGroup.svelte";
5
+ export { default as PopoverPanel, type PopoverPanelProps, type PanelRenderPropArg as PopoverPanelSlot, type PopoverPanelOwnProps, } from "./PopoverPanel.svelte";
@@ -0,0 +1,5 @@
1
+ export { default as Popover, } from "./Popover.svelte";
2
+ export { default as PopoverBackdrop, } from "./PopoverBackdrop.svelte";
3
+ export { default as PopoverButton, } from "./PopoverButton.svelte";
4
+ export { default as PopoverGroup } from "./PopoverGroup.svelte";
5
+ export { default as PopoverPanel, } from "./PopoverPanel.svelte";
@@ -3,7 +3,7 @@
3
3
  import { getOwnerDocument } from "../utils/owner.js"
4
4
  import { getContext, onMount, setContext } from "svelte"
5
5
  import { env } from "../utils/env.js"
6
- import type { ElementType, Props } from "../utils/types.js"
6
+ import type { Props } from "../utils/types.js"
7
7
  import type { PortalGroupContext } from "./PortalGroup.svelte"
8
8
 
9
9
  function usePortalTarget(options: { element: HTMLElement | null }): { readonly target: HTMLElement | null } {
@@ -93,27 +93,27 @@
93
93
  // ---
94
94
 
95
95
  export const DEFAULT_PORTAL_TAG = "div"
96
- type PortalRenderPropArg = {}
96
+ export type PortalRenderPropArg = {}
97
97
  type PortalPropsWeControl = never
98
98
 
99
- export type PortalProps<TTag extends ElementType = typeof DEFAULT_PORTAL_TAG> = Props<
100
- TTag,
99
+ export type PortalProps = Props<
100
+ typeof DEFAULT_PORTAL_TAG,
101
101
  PortalRenderPropArg,
102
- PortalPropsWeControl,
103
102
  {
103
+ element?: HTMLElement
104
104
  enabled?: boolean
105
105
  }
106
106
  >
107
107
  </script>
108
108
 
109
- <script lang="ts" generics="TTag extends ElementType = typeof DEFAULT_PORTAL_TAG">
109
+ <script lang="ts">
110
110
  import ElementOrComponent from "../utils/ElementOrComponent.svelte"
111
111
 
112
- let { ref = $bindable(), ...theirProps }: { as?: TTag } & PortalProps<TTag> = $props()
112
+ let { element = $bindable(), ...theirProps }: PortalProps = $props()
113
113
 
114
114
  const portalTarget = usePortalTarget({
115
115
  get element() {
116
- return ref ?? null
116
+ return element ?? null
117
117
  },
118
118
  })
119
119
  const { target } = $derived(portalTarget)
@@ -121,24 +121,24 @@
121
121
  //const ready = useServerHandoffComplete()
122
122
 
123
123
  $effect(() => {
124
- if (!target || !ref) return
124
+ if (!target || !element) return
125
125
 
126
126
  // Element already exists in target, always calling target.appendChild(element) will cause a
127
127
  // brief unmount/remount.
128
- if (ref.parentNode !== target) {
129
- ref.setAttribute("data-headlessui-portal", "")
130
- target.appendChild(ref)
128
+ if (element.parentNode !== target) {
129
+ element.setAttribute("data-headlessui-portal", "")
130
+ target.appendChild(element)
131
131
  }
132
132
  })
133
133
 
134
134
  onMount(() => {
135
- if (parent) parent.register(ref!)
135
+ if (parent) parent.register(element!)
136
136
 
137
137
  return () => {
138
- if (!target || !ref) return
138
+ if (!target || !element) return
139
139
 
140
- if (ref instanceof Node && target.contains(ref)) {
141
- target.removeChild(ref)
140
+ if (element instanceof Node && target.contains(element)) {
141
+ target.removeChild(element)
142
142
  }
143
143
 
144
144
  if (target.childNodes.length <= 0) {
@@ -149,5 +149,5 @@
149
149
  </script>
150
150
 
151
151
  {#if target}
152
- <ElementOrComponent {theirProps} defaultTag={DEFAULT_PORTAL_TAG} name="InternalPortal" bind:ref />
152
+ <ElementOrComponent {theirProps} defaultTag={DEFAULT_PORTAL_TAG} name="InternalPortal" bind:element />
153
153
  {/if}
@@ -1,4 +1,4 @@
1
- import type { ElementType, Props } from "../utils/types.js";
1
+ import type { Props } from "../utils/types.js";
2
2
  type PortalParentContext = {
3
3
  register: (portal: HTMLElement) => () => void;
4
4
  unregister: (portal: HTMLElement) => void;
@@ -6,38 +6,11 @@ type PortalParentContext = {
6
6
  };
7
7
  export declare function useNestedPortals(): PortalParentContext;
8
8
  export declare const DEFAULT_PORTAL_TAG = "div";
9
- type PortalRenderPropArg = {};
10
- type PortalPropsWeControl = never;
11
- export type PortalProps<TTag extends ElementType = typeof DEFAULT_PORTAL_TAG> = Props<TTag, PortalRenderPropArg, PortalPropsWeControl, {
9
+ export type PortalRenderPropArg = {};
10
+ export type PortalProps = Props<typeof DEFAULT_PORTAL_TAG, PortalRenderPropArg, {
11
+ element?: HTMLElement;
12
12
  enabled?: boolean;
13
13
  }>;
14
- declare class __sveltets_Render<TTag extends ElementType = typeof DEFAULT_PORTAL_TAG> {
15
- props(): {
16
- as?: TTag | undefined;
17
- } & (Exclude<keyof import("../utils/types.js").PropsOf<TTag>, ("as" | "children" | "refName" | "class") | "enabled"> extends infer T extends keyof import("../utils/types.js").PropsOf<TTag> ? { [P in T]: import("../utils/types.js").PropsOf<TTag>[P]; } : never) & {
18
- children?: import("../utils/types.js").Children<PortalRenderPropArg> | undefined;
19
- ref?: HTMLElement;
20
- } & (true extends (import("../utils/types.js").PropsOf<TTag> extends infer T_1 ? T_1 extends import("../utils/types.js").PropsOf<TTag> ? T_1 extends never ? never : "class" extends infer T_2 ? T_2 extends "class" ? T_2 extends keyof T_1 ? true : never : never : never : never : never) ? {
21
- class?: import("../utils/types.js").PropsOf<TTag>["class"] | ((bag: PortalRenderPropArg) => string) | undefined;
22
- } : {}) & {
23
- enabled?: boolean;
24
- };
25
- events(): {} & {
26
- [evt: string]: CustomEvent<any>;
27
- };
28
- slots(): {};
29
- bindings(): "ref";
30
- exports(): {};
31
- }
32
- interface $$IsomorphicComponent {
33
- new <TTag extends ElementType = typeof DEFAULT_PORTAL_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']>> & {
34
- $$bindings?: ReturnType<__sveltets_Render<TTag>['bindings']>;
35
- } & ReturnType<__sveltets_Render<TTag>['exports']>;
36
- <TTag extends ElementType = typeof DEFAULT_PORTAL_TAG>(internal: unknown, props: ReturnType<__sveltets_Render<TTag>['props']> & {
37
- $$events?: ReturnType<__sveltets_Render<TTag>['events']>;
38
- }): ReturnType<__sveltets_Render<TTag>['exports']>;
39
- z_$$bindings?: ReturnType<__sveltets_Render<any>['bindings']>;
40
- }
41
- declare const InternalPortal: $$IsomorphicComponent;
42
- type InternalPortal<TTag extends ElementType = typeof DEFAULT_PORTAL_TAG> = InstanceType<typeof InternalPortal<TTag>>;
14
+ declare const InternalPortal: import("svelte").Component<PortalProps, {}, "element">;
15
+ type InternalPortal = ReturnType<typeof InternalPortal>;
43
16
  export default InternalPortal;