@pzerelles/headlessui-svelte 2.1.2-next.29 → 2.1.2-next.30
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/button/Button.svelte +54 -84
- package/dist/checkbox/Checkbox.svelte +120 -173
- package/dist/checkbox/Checkbox.svelte.d.ts +1 -1
- package/dist/close-button/CloseButton.svelte +6 -12
- package/dist/combobox/Combobox.svelte +3 -50
- package/dist/data-interactive/DataInteractive.svelte +29 -55
- package/dist/description/Description.svelte +21 -31
- package/dist/dialog/Dialog.svelte +228 -320
- package/dist/dialog/DialogBackdrop.svelte +12 -29
- package/dist/dialog/DialogPanel.svelte +25 -48
- package/dist/dialog/DialogTitle.svelte +23 -38
- package/dist/field/Field.svelte +25 -47
- package/dist/fieldset/Fieldset.svelte +29 -50
- package/dist/focus-trap/FocusTrap.svelte +283 -419
- package/dist/input/Input.svelte +53 -84
- package/dist/internal/FloatingProvider.svelte +9 -14
- package/dist/internal/FocusSentinel.svelte +8 -16
- package/dist/internal/ForcePortalRoot.svelte +3 -7
- package/dist/internal/FormFields.svelte +34 -47
- package/dist/internal/FormFieldsProvider.svelte +5 -9
- package/dist/internal/FormResolver.svelte +15 -20
- package/dist/internal/Hidden.svelte +29 -50
- package/dist/internal/MainTreeProvider.svelte +36 -89
- package/dist/internal/Portal.svelte +14 -18
- package/dist/label/Label.svelte +58 -93
- package/dist/legend/Legend.svelte +3 -12
- package/dist/listbox/Listbox.svelte +387 -525
- package/dist/listbox/Listbox.svelte.d.ts +1 -1
- package/dist/listbox/ListboxButton.svelte +127 -173
- package/dist/listbox/ListboxOption.svelte +129 -170
- package/dist/listbox/ListboxOptions.svelte +304 -400
- package/dist/listbox/ListboxSelectedOption.svelte +15 -38
- package/dist/menu/Menu.svelte +51 -78
- package/dist/menu/MenuButton.svelte +117 -157
- package/dist/menu/MenuHeading.svelte +14 -32
- package/dist/menu/MenuItem.svelte +107 -142
- package/dist/menu/MenuItems.svelte +229 -301
- package/dist/menu/MenuSection.svelte +9 -24
- package/dist/menu/MenuSeparator.svelte +4 -17
- package/dist/popover/Popover.svelte +150 -216
- package/dist/popover/PopoverBackdrop.svelte +41 -67
- package/dist/popover/PopoverButton.svelte +212 -292
- package/dist/popover/PopoverGroup.svelte +35 -62
- package/dist/popover/PopoverPanel.svelte +229 -311
- package/dist/portal/InternalPortal.svelte +85 -141
- package/dist/portal/Portal.svelte +2 -5
- package/dist/portal/PortalGroup.svelte +9 -30
- package/dist/select/Select.svelte +68 -98
- package/dist/switch/Switch.svelte +132 -179
- package/dist/switch/SwitchGroup.svelte +31 -44
- package/dist/tabs/Tab.svelte +142 -194
- package/dist/tabs/TabGroup.svelte +56 -86
- package/dist/tabs/TabGroup.svelte.d.ts +1 -1
- package/dist/tabs/TabList.svelte +11 -31
- package/dist/tabs/TabPanel.svelte +42 -67
- package/dist/tabs/TabPanels.svelte +7 -18
- package/dist/textarea/Textarea.svelte +53 -84
- package/dist/transition/InternalTransitionChild.svelte +170 -259
- package/dist/transition/Transition.svelte +66 -96
- package/dist/transition/TransitionChild.svelte +11 -31
- package/dist/utils/DisabledProvider.svelte +3 -7
- package/dist/utils/ElementOrComponent.svelte +23 -43
- package/dist/utils/Generic.svelte +16 -27
- package/dist/utils/StableCollection.svelte +36 -54
- package/dist/utils/floating-ui/svelte/components/FloatingNode.svelte +12 -27
- package/dist/utils/floating-ui/svelte/components/FloatingTree.svelte +44 -88
- package/package.json +4 -4
|
@@ -1,308 +1,228 @@
|
|
|
1
|
-
<script lang="ts" module>
|
|
2
|
-
import type { ElementType, Props, PropsOf } from "../utils/types.js"
|
|
3
|
-
|
|
4
|
-
const DEFAULT_BUTTON_TAG = "button" as const
|
|
5
|
-
export type PopoverButtonSlot = {
|
|
6
|
-
open: boolean
|
|
7
|
-
active: boolean
|
|
8
|
-
hover: boolean
|
|
9
|
-
focus: boolean
|
|
10
|
-
disabled: boolean
|
|
11
|
-
autofocus: boolean
|
|
12
|
-
}
|
|
13
|
-
export type PopoverButtonPropsWeControl = "aria-controls" | "aria-expanded"
|
|
14
|
-
|
|
15
|
-
export type PopoverButtonComponentProps = {
|
|
16
|
-
disabled?: boolean
|
|
17
|
-
autofocus?: boolean
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export type PopoverButtonProps<TTag extends ElementType = typeof DEFAULT_BUTTON_TAG> = Props<
|
|
21
|
-
TTag,
|
|
22
|
-
PopoverButtonSlot,
|
|
23
|
-
PopoverButtonPropsWeControl,
|
|
24
|
-
PopoverButtonComponentProps
|
|
25
|
-
>
|
|
1
|
+
<script lang="ts" module>const DEFAULT_BUTTON_TAG = "button";
|
|
26
2
|
</script>
|
|
27
3
|
|
|
28
|
-
<script lang="ts" generics="TTag extends ElementType = typeof DEFAULT_BUTTON_TAG">
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
context.setButtonId(id)
|
|
89
|
-
return () => {
|
|
90
|
-
context.setButtonId(undefined)
|
|
91
|
-
}
|
|
92
|
-
})
|
|
93
|
-
})
|
|
94
|
-
|
|
95
|
-
// This is a little bit different compared to the `id` we already have. The goal is to have a very
|
|
96
|
-
// unique identifier for this specific component. This can be achieved with the `id` from above.
|
|
97
|
-
//
|
|
98
|
-
// However, the difference is for React 17 and lower where the `useId` hook doesn't exist yet.
|
|
99
|
-
// There we will generate a unique ID based on a simple counter, but for SSR this will result in
|
|
100
|
-
// `undefined` first, later it is patched to be a unique ID. The problem is that this patching
|
|
101
|
-
// happens after the component is rendered and therefore there is a moment in time where multiple
|
|
102
|
-
// buttons have the exact same ID and the `state.buttons` would result in something like:
|
|
103
|
-
//
|
|
104
|
-
// ```js
|
|
105
|
-
// ['headlessui-popover-button-undefined', 'headlessui-popover-button-1']
|
|
106
|
-
// ```
|
|
107
|
-
//
|
|
108
|
-
// With this approach we guarantee that there is a unique value for each button.
|
|
109
|
-
const uniqueIdentifier = Symbol()
|
|
110
|
-
|
|
111
|
-
const floatingReference = useFloatingReference()
|
|
112
|
-
const { setReference } = $derived(floatingReference)
|
|
113
|
-
$effect(() => {
|
|
114
|
-
setReference(ref)
|
|
115
|
-
})
|
|
116
|
-
$effect(() => {
|
|
117
|
-
if (isWithinPanel) return
|
|
118
|
-
ref
|
|
119
|
-
untrack(() => {
|
|
120
|
-
if (ref) {
|
|
121
|
-
context.buttons.push(uniqueIdentifier)
|
|
122
|
-
} else {
|
|
123
|
-
let idx = context.buttons.indexOf(uniqueIdentifier)
|
|
124
|
-
if (idx !== -1) context.buttons.splice(idx, 1)
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
if (context.buttons.length > 1) {
|
|
128
|
-
console.warn("You are already using a <PopoverButton /> but only 1 <PopoverButton /> is supported.")
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
if (ref) context.setButton(ref)
|
|
132
|
-
})
|
|
133
|
-
})
|
|
134
|
-
const ownerDocument = $derived(getOwnerDocument(ref))
|
|
135
|
-
|
|
136
|
-
const handleKeyDown = (event: KeyboardEvent) => {
|
|
137
|
-
if (isWithinPanel) {
|
|
138
|
-
if (context.popoverState === PopoverStates.Closed) return
|
|
139
|
-
switch (event.key) {
|
|
140
|
-
case "Space":
|
|
141
|
-
case "Enter":
|
|
142
|
-
event.preventDefault() // Prevent triggering a *click* event
|
|
143
|
-
// @ts-expect-error
|
|
144
|
-
event.target.click?.()
|
|
145
|
-
context.closePopover()
|
|
146
|
-
context.button?.focus() // Re-focus the original opening Button
|
|
147
|
-
break
|
|
148
|
-
}
|
|
4
|
+
<script lang="ts" generics="TTag extends ElementType = typeof DEFAULT_BUTTON_TAG">import { useId } from "../hooks/use-id.js";
|
|
5
|
+
import {
|
|
6
|
+
PopoverStates,
|
|
7
|
+
usePopoverAPIContext,
|
|
8
|
+
usePopoverContext,
|
|
9
|
+
usePopoverGroupContext,
|
|
10
|
+
usePopoverPanelContext
|
|
11
|
+
} from "./context.svelte.js";
|
|
12
|
+
import { useFloatingReference } from "../internal/floating.svelte.js";
|
|
13
|
+
import { untrack } from "svelte";
|
|
14
|
+
import { getOwnerDocument } from "../utils/owner.js";
|
|
15
|
+
import { useFocusRing } from "../hooks/use-focus-ring.svelte.js";
|
|
16
|
+
import { useHover } from "../hooks/use-hover.svelte.js";
|
|
17
|
+
import { useActivePress } from "../hooks/use-active-press.svelte.js";
|
|
18
|
+
import { useResolveButtonType } from "../hooks/use-resolve-button-type.svelte.js";
|
|
19
|
+
import { mergeProps } from "../utils/render.js";
|
|
20
|
+
import { useTabDirection, Direction as TabDirection } from "../hooks/use-tab-direction.svelte.js";
|
|
21
|
+
import { match } from "../utils/match.js";
|
|
22
|
+
import { Focus, focusIn, FocusResult, getFocusableElements } from "../utils/focus-management.js";
|
|
23
|
+
import { microTask } from "../utils/microTask.js";
|
|
24
|
+
import Hidden, { HiddenFeatures } from "../internal/Hidden.svelte";
|
|
25
|
+
import ElementOrComponent from "../utils/ElementOrComponent.svelte";
|
|
26
|
+
const internalId = useId();
|
|
27
|
+
let {
|
|
28
|
+
ref = $bindable(),
|
|
29
|
+
id = `headlessui-popover-button-${internalId}`,
|
|
30
|
+
disabled = false,
|
|
31
|
+
autofocus = false,
|
|
32
|
+
...theirProps
|
|
33
|
+
} = $props();
|
|
34
|
+
const context = usePopoverContext("PopoverButton");
|
|
35
|
+
const api = usePopoverAPIContext("PopoverButton");
|
|
36
|
+
const { isPortalled } = $derived(api);
|
|
37
|
+
const sentinelId = `headlessui-focus-sentinel-${useId()}`;
|
|
38
|
+
const groupContext = usePopoverGroupContext();
|
|
39
|
+
const closeOthers = $derived(groupContext?.closeOthers);
|
|
40
|
+
const panelContext = usePopoverPanelContext();
|
|
41
|
+
const isWithinPanel = panelContext !== void 0;
|
|
42
|
+
$effect(() => {
|
|
43
|
+
if (isWithinPanel) return;
|
|
44
|
+
id;
|
|
45
|
+
return untrack(() => {
|
|
46
|
+
context.setButtonId(id);
|
|
47
|
+
return () => {
|
|
48
|
+
context.setButtonId(void 0);
|
|
49
|
+
};
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
const uniqueIdentifier = Symbol();
|
|
53
|
+
const floatingReference = useFloatingReference();
|
|
54
|
+
const { setReference } = $derived(floatingReference);
|
|
55
|
+
$effect(() => {
|
|
56
|
+
setReference(ref);
|
|
57
|
+
});
|
|
58
|
+
$effect(() => {
|
|
59
|
+
if (isWithinPanel) return;
|
|
60
|
+
ref;
|
|
61
|
+
untrack(() => {
|
|
62
|
+
if (ref) {
|
|
63
|
+
context.buttons.push(uniqueIdentifier);
|
|
149
64
|
} else {
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
case "Enter":
|
|
153
|
-
event.preventDefault() // Prevent triggering a *click* event
|
|
154
|
-
event.stopPropagation()
|
|
155
|
-
if (context.popoverState === PopoverStates.Closed) closeOthers?.(context.buttonId!)
|
|
156
|
-
context.togglePopover()
|
|
157
|
-
break
|
|
158
|
-
|
|
159
|
-
case "Escape":
|
|
160
|
-
if (context.popoverState !== PopoverStates.Open) return closeOthers?.(context.buttonId!)
|
|
161
|
-
if (!ref) return
|
|
162
|
-
if (ownerDocument?.activeElement && !ref.contains(ownerDocument.activeElement)) {
|
|
163
|
-
return
|
|
164
|
-
}
|
|
165
|
-
event.preventDefault()
|
|
166
|
-
event.stopPropagation()
|
|
167
|
-
context.closePopover()
|
|
168
|
-
break
|
|
169
|
-
}
|
|
65
|
+
let idx = context.buttons.indexOf(uniqueIdentifier);
|
|
66
|
+
if (idx !== -1) context.buttons.splice(idx, 1);
|
|
170
67
|
}
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
const handleKeyUp = (event: KeyboardEvent) => {
|
|
174
|
-
if (isWithinPanel) return
|
|
175
|
-
if (event.key === "Space") {
|
|
176
|
-
// Required for firefox, event.preventDefault() in handleKeyDown for
|
|
177
|
-
// the Space key doesn't cancel the handleKeyUp, which in turn
|
|
178
|
-
// triggers a *click*.
|
|
179
|
-
event.preventDefault()
|
|
68
|
+
if (context.buttons.length > 1) {
|
|
69
|
+
console.warn("You are already using a <PopoverButton /> but only 1 <PopoverButton /> is supported.");
|
|
180
70
|
}
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
71
|
+
if (ref) context.setButton(ref);
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
const ownerDocument = $derived(getOwnerDocument(ref));
|
|
75
|
+
const handleKeyDown = (event) => {
|
|
76
|
+
if (isWithinPanel) {
|
|
77
|
+
if (context.popoverState === PopoverStates.Closed) return;
|
|
78
|
+
switch (event.key) {
|
|
79
|
+
case "Space":
|
|
80
|
+
case "Enter":
|
|
81
|
+
event.preventDefault();
|
|
82
|
+
event.target.click?.();
|
|
83
|
+
context.closePopover();
|
|
84
|
+
context.button?.focus();
|
|
85
|
+
break;
|
|
86
|
+
}
|
|
87
|
+
} else {
|
|
88
|
+
switch (event.key) {
|
|
89
|
+
case "Space":
|
|
90
|
+
case "Enter":
|
|
91
|
+
event.preventDefault();
|
|
92
|
+
event.stopPropagation();
|
|
93
|
+
if (context.popoverState === PopoverStates.Closed) closeOthers?.(context.buttonId);
|
|
94
|
+
context.togglePopover();
|
|
95
|
+
break;
|
|
96
|
+
case "Escape":
|
|
97
|
+
if (context.popoverState !== PopoverStates.Open) return closeOthers?.(context.buttonId);
|
|
98
|
+
if (!ref) return;
|
|
99
|
+
if (ownerDocument?.activeElement && !ref.contains(ownerDocument.activeElement)) {
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
event.preventDefault();
|
|
103
|
+
event.stopPropagation();
|
|
104
|
+
context.closePopover();
|
|
105
|
+
break;
|
|
195
106
|
}
|
|
196
107
|
}
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
108
|
+
};
|
|
109
|
+
const handleKeyUp = (event) => {
|
|
110
|
+
if (isWithinPanel) return;
|
|
111
|
+
if (event.key === "Space") {
|
|
112
|
+
event.preventDefault();
|
|
201
113
|
}
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
disabled
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
get
|
|
237
|
-
return
|
|
114
|
+
};
|
|
115
|
+
const handleClick = (event) => {
|
|
116
|
+
if (disabled) return;
|
|
117
|
+
if (isWithinPanel) {
|
|
118
|
+
context.closePopover();
|
|
119
|
+
context.button?.focus();
|
|
120
|
+
} else {
|
|
121
|
+
event.preventDefault();
|
|
122
|
+
event.stopPropagation();
|
|
123
|
+
if (context.popoverState === PopoverStates.Closed) closeOthers?.(context.buttonId);
|
|
124
|
+
context.togglePopover();
|
|
125
|
+
context.button?.focus();
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
const handleMouseDown = (event) => {
|
|
129
|
+
event.preventDefault();
|
|
130
|
+
event.stopPropagation();
|
|
131
|
+
};
|
|
132
|
+
const { isFocusVisible: focus, focusProps } = $derived(
|
|
133
|
+
useFocusRing({
|
|
134
|
+
get autofocus() {
|
|
135
|
+
return autofocus;
|
|
136
|
+
}
|
|
137
|
+
})
|
|
138
|
+
);
|
|
139
|
+
const { isHovered: hover, hoverProps } = $derived(
|
|
140
|
+
useHover({
|
|
141
|
+
get disabled() {
|
|
142
|
+
return disabled;
|
|
143
|
+
}
|
|
144
|
+
})
|
|
145
|
+
);
|
|
146
|
+
const { pressed: active, pressProps } = $derived(
|
|
147
|
+
useActivePress({
|
|
148
|
+
get disabled() {
|
|
149
|
+
return disabled;
|
|
150
|
+
}
|
|
151
|
+
})
|
|
152
|
+
);
|
|
153
|
+
const visible = $derived(context.popoverState === PopoverStates.Open);
|
|
154
|
+
const slot = $derived({
|
|
155
|
+
open: visible,
|
|
156
|
+
active: active || visible,
|
|
157
|
+
disabled,
|
|
158
|
+
hover,
|
|
159
|
+
focus,
|
|
160
|
+
autofocus
|
|
161
|
+
});
|
|
162
|
+
const type = useResolveButtonType({
|
|
163
|
+
get props() {
|
|
164
|
+
return { type: theirProps.type, as: theirProps.as };
|
|
165
|
+
},
|
|
166
|
+
get ref() {
|
|
167
|
+
return { current: context.button };
|
|
168
|
+
}
|
|
169
|
+
});
|
|
170
|
+
const ourProps = $derived(
|
|
171
|
+
isWithinPanel ? mergeProps(
|
|
172
|
+
{
|
|
173
|
+
type,
|
|
174
|
+
onkeydown: handleKeyDown,
|
|
175
|
+
onclick: handleClick,
|
|
176
|
+
disabled: disabled || void 0,
|
|
177
|
+
autofocus
|
|
238
178
|
},
|
|
239
|
-
|
|
240
|
-
|
|
179
|
+
focusProps,
|
|
180
|
+
hoverProps,
|
|
181
|
+
pressProps
|
|
182
|
+
) : mergeProps(
|
|
183
|
+
{
|
|
184
|
+
id: context.buttonId,
|
|
185
|
+
type,
|
|
186
|
+
"aria-expanded": context.popoverState === PopoverStates.Open,
|
|
187
|
+
"aria-controls": context.panel ? context.panelId : void 0,
|
|
188
|
+
disabled: disabled || void 0,
|
|
189
|
+
autofocus,
|
|
190
|
+
onkeydown: handleKeyDown,
|
|
191
|
+
onkeyup: handleKeyUp,
|
|
192
|
+
onclick: handleClick,
|
|
193
|
+
onmousedown: handleMouseDown
|
|
241
194
|
},
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
? mergeProps(
|
|
246
|
-
{
|
|
247
|
-
type,
|
|
248
|
-
onkeydown: handleKeyDown,
|
|
249
|
-
onclick: handleClick,
|
|
250
|
-
disabled: disabled || undefined,
|
|
251
|
-
autofocus,
|
|
252
|
-
},
|
|
253
|
-
focusProps,
|
|
254
|
-
hoverProps,
|
|
255
|
-
pressProps
|
|
256
|
-
)
|
|
257
|
-
: mergeProps(
|
|
258
|
-
{
|
|
259
|
-
id: context.buttonId,
|
|
260
|
-
type,
|
|
261
|
-
"aria-expanded": context.popoverState === PopoverStates.Open,
|
|
262
|
-
"aria-controls": context.panel ? context.panelId : undefined,
|
|
263
|
-
disabled: disabled || undefined,
|
|
264
|
-
autofocus,
|
|
265
|
-
onkeydown: handleKeyDown,
|
|
266
|
-
onkeyup: handleKeyUp,
|
|
267
|
-
onclick: handleClick,
|
|
268
|
-
onmousedown: handleMouseDown,
|
|
269
|
-
},
|
|
270
|
-
focusProps,
|
|
271
|
-
hoverProps,
|
|
272
|
-
pressProps
|
|
273
|
-
)
|
|
195
|
+
focusProps,
|
|
196
|
+
hoverProps,
|
|
197
|
+
pressProps
|
|
274
198
|
)
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
{ relativeTo: context.button }
|
|
295
|
-
)
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
// TODO: Cleanup once we are using real browser tests
|
|
300
|
-
if (process.env.NODE_ENV === "test") {
|
|
301
|
-
microTask(run)
|
|
302
|
-
} else {
|
|
303
|
-
run()
|
|
199
|
+
);
|
|
200
|
+
const direction = useTabDirection();
|
|
201
|
+
const handleFocus = () => {
|
|
202
|
+
const el = context.panel;
|
|
203
|
+
if (!el) return;
|
|
204
|
+
function run() {
|
|
205
|
+
let result = match(direction.current, {
|
|
206
|
+
[TabDirection.Forwards]: () => focusIn(el, Focus.First),
|
|
207
|
+
[TabDirection.Backwards]: () => focusIn(el, Focus.Last)
|
|
208
|
+
});
|
|
209
|
+
if (result === FocusResult.Error) {
|
|
210
|
+
focusIn(
|
|
211
|
+
getFocusableElements().filter((el2) => el2.dataset.headlessuiFocusGuard !== "true"),
|
|
212
|
+
match(direction.current, {
|
|
213
|
+
[TabDirection.Forwards]: Focus.Next,
|
|
214
|
+
[TabDirection.Backwards]: Focus.Previous
|
|
215
|
+
}),
|
|
216
|
+
{ relativeTo: context.button }
|
|
217
|
+
);
|
|
304
218
|
}
|
|
305
219
|
}
|
|
220
|
+
if (process.env.NODE_ENV === "test") {
|
|
221
|
+
microTask(run);
|
|
222
|
+
} else {
|
|
223
|
+
run();
|
|
224
|
+
}
|
|
225
|
+
};
|
|
306
226
|
</script>
|
|
307
227
|
|
|
308
228
|
<ElementOrComponent
|
|
@@ -1,68 +1,41 @@
|
|
|
1
|
-
<script lang="ts" module>
|
|
2
|
-
|
|
3
|
-
import { setContext } from "svelte"
|
|
4
|
-
|
|
5
|
-
const DEFAULT_GROUP_TAG = "div" as const
|
|
6
|
-
type GroupRenderPropArg = {}
|
|
7
|
-
type GroupPropsWeControl = never
|
|
8
|
-
|
|
9
|
-
export type PopoverGroupProps<TTag extends ElementType = typeof DEFAULT_GROUP_TAG> = Props<
|
|
10
|
-
TTag,
|
|
11
|
-
GroupRenderPropArg,
|
|
12
|
-
GroupPropsWeControl
|
|
13
|
-
>
|
|
1
|
+
<script lang="ts" module>import { setContext } from "svelte";
|
|
2
|
+
const DEFAULT_GROUP_TAG = "div";
|
|
14
3
|
</script>
|
|
15
4
|
|
|
16
|
-
<script lang="ts" generics="TTag extends ElementType = typeof DEFAULT_GROUP_TAG">
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
5
|
+
<script lang="ts" generics="TTag extends ElementType = typeof DEFAULT_GROUP_TAG">import MainTreeProvider from "../internal/MainTreeProvider.svelte";
|
|
6
|
+
import ElementOrComponent from "../utils/ElementOrComponent.svelte";
|
|
7
|
+
import { getOwnerDocument } from "../utils/owner.js";
|
|
8
|
+
let { ref = $bindable(), ...theirProps } = $props();
|
|
9
|
+
const popovers = $state([]);
|
|
10
|
+
const unregisterPopover = (registerBag) => {
|
|
11
|
+
const idx = popovers.indexOf(registerBag);
|
|
12
|
+
if (idx !== -1) popovers.splice(idx, 1);
|
|
13
|
+
};
|
|
14
|
+
const registerPopover = (registerBag) => {
|
|
15
|
+
popovers.push(registerBag);
|
|
16
|
+
return () => unregisterPopover(registerBag);
|
|
17
|
+
};
|
|
18
|
+
const isFocusWithinPopoverGroup = () => {
|
|
19
|
+
const ownerDocument = getOwnerDocument(ref);
|
|
20
|
+
if (!ownerDocument) return false;
|
|
21
|
+
let element = ownerDocument.activeElement;
|
|
22
|
+
if (ref?.contains(element)) return true;
|
|
23
|
+
return popovers.some((bag) => {
|
|
24
|
+
return ownerDocument.getElementById(bag.buttonId)?.contains(element) || ownerDocument.getElementById(bag.panelId)?.contains(element);
|
|
25
|
+
});
|
|
26
|
+
};
|
|
27
|
+
const closeOthers = (buttonId) => {
|
|
28
|
+
for (const popover of popovers) {
|
|
29
|
+
if (popover.buttonId !== buttonId) popover.close();
|
|
34
30
|
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
// Check if the focus is in one of the button or panel elements. This is important in case you are rendering inside a Portal.
|
|
44
|
-
return popovers.some((bag) => {
|
|
45
|
-
return (
|
|
46
|
-
ownerDocument!.getElementById(bag.buttonId!)?.contains(element) ||
|
|
47
|
-
ownerDocument!.getElementById(bag.panelId!)?.contains(element)
|
|
48
|
-
)
|
|
49
|
-
})
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
const closeOthers = (buttonId: string) => {
|
|
53
|
-
for (const popover of popovers) {
|
|
54
|
-
if (popover.buttonId !== buttonId) popover.close()
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
setContext<PopoverGroupContext>("PopoverGroupContext", {
|
|
59
|
-
registerPopover,
|
|
60
|
-
unregisterPopover,
|
|
61
|
-
isFocusWithinPopoverGroup,
|
|
62
|
-
closeOthers,
|
|
63
|
-
})
|
|
64
|
-
|
|
65
|
-
const slot = {} satisfies GroupRenderPropArg
|
|
31
|
+
};
|
|
32
|
+
setContext("PopoverGroupContext", {
|
|
33
|
+
registerPopover,
|
|
34
|
+
unregisterPopover,
|
|
35
|
+
isFocusWithinPopoverGroup,
|
|
36
|
+
closeOthers
|
|
37
|
+
});
|
|
38
|
+
const slot = {};
|
|
66
39
|
</script>
|
|
67
40
|
|
|
68
41
|
<MainTreeProvider>
|