@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,323 +1,241 @@
|
|
|
1
|
-
<script lang="ts" module>
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
const DEFAULT_PANEL_TAG = "div" as const
|
|
6
|
-
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 PopoverPanelProps<TTag extends ElementType = typeof DEFAULT_PANEL_TAG> = Props<
|
|
16
|
-
TTag,
|
|
17
|
-
PanelRenderPropArg,
|
|
18
|
-
PanelPropsWeControl,
|
|
19
|
-
{
|
|
20
|
-
focus?: boolean
|
|
21
|
-
anchor?: AnchorProps
|
|
22
|
-
portal?: boolean
|
|
23
|
-
modal?: boolean
|
|
24
|
-
transition?: boolean
|
|
25
|
-
|
|
26
|
-
// ItemsRenderFeatures
|
|
27
|
-
static?: boolean
|
|
28
|
-
unmount?: boolean
|
|
29
|
-
}
|
|
30
|
-
>
|
|
1
|
+
<script lang="ts" module>import { RenderFeatures } from "../utils/render.js";
|
|
2
|
+
const DEFAULT_PANEL_TAG = "div";
|
|
3
|
+
const PanelRenderFeatures = RenderFeatures.RenderStrategy | RenderFeatures.Static;
|
|
31
4
|
</script>
|
|
32
5
|
|
|
33
|
-
<script lang="ts" generics="TTag extends ElementType = typeof DEFAULT_PANEL_TAG">
|
|
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
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
6
|
+
<script lang="ts" generics="TTag extends ElementType = typeof DEFAULT_PANEL_TAG">import { useId } from "../hooks/use-id.js";
|
|
7
|
+
import ElementOrComponent from "../utils/ElementOrComponent.svelte";
|
|
8
|
+
import { mergeProps } from "../utils/render.js";
|
|
9
|
+
import {
|
|
10
|
+
useFloatingPanel,
|
|
11
|
+
useFloatingPanelProps,
|
|
12
|
+
useResolvedAnchor
|
|
13
|
+
} from "../internal/floating.svelte.js";
|
|
14
|
+
import {
|
|
15
|
+
PopoverStates,
|
|
16
|
+
usePopoverAPIContext,
|
|
17
|
+
usePopoverContext
|
|
18
|
+
} from "./context.svelte.js";
|
|
19
|
+
import { getOwnerDocument } from "../utils/owner.js";
|
|
20
|
+
import { clearOpenClosedContext, State, useOpenClosed } from "../internal/open-closed.js";
|
|
21
|
+
import { transitionDataAttributes, useTransition } from "../hooks/use-transition.svelte.js";
|
|
22
|
+
import { useOnDisappear } from "../hooks/use-on-disappear.svelte.js";
|
|
23
|
+
import { useScrollLock } from "../hooks/use-scroll-lock.svelte.js";
|
|
24
|
+
import { Focus, focusIn, FocusResult, getFocusableElements } from "../utils/focus-management.js";
|
|
25
|
+
import { useElementSize } from "../hooks/use-element-size.svelte.js";
|
|
26
|
+
import { useTabDirection, Direction as TabDirection } from "../hooks/use-tab-direction.svelte.js";
|
|
27
|
+
import { match } from "../utils/match.js";
|
|
28
|
+
import { microTask } from "../utils/microTask.js";
|
|
29
|
+
import { setContext, untrack } from "svelte";
|
|
30
|
+
import Portal from "../portal/Portal.svelte";
|
|
31
|
+
import Hidden, { HiddenFeatures } from "../internal/Hidden.svelte";
|
|
32
|
+
let internalId = useId();
|
|
33
|
+
let {
|
|
34
|
+
ref = $bindable(),
|
|
35
|
+
id = `headlessui-popover-panel-${internalId}`,
|
|
36
|
+
focus = false,
|
|
37
|
+
anchor: rawAnchor,
|
|
38
|
+
portal: theirPortal = false,
|
|
39
|
+
modal = false,
|
|
40
|
+
transition = false,
|
|
41
|
+
...theirProps
|
|
42
|
+
} = $props();
|
|
43
|
+
const context = usePopoverContext("PopoverPanel");
|
|
44
|
+
const api = usePopoverAPIContext("PopoverPanel");
|
|
45
|
+
const { close, isPortalled } = $derived(api);
|
|
46
|
+
const beforePanelSentinelId = `headlessui-focus-sentinel-before-${internalId}`;
|
|
47
|
+
const afterPanelSentinelId = `headlessui-focus-sentinel-after-${internalId}`;
|
|
48
|
+
const resolvedAnchor = useResolvedAnchor({
|
|
49
|
+
get anchor() {
|
|
50
|
+
return rawAnchor;
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
const { anchor } = $derived(resolvedAnchor);
|
|
54
|
+
const floatingPanel = useFloatingPanel({
|
|
55
|
+
get placement() {
|
|
56
|
+
return anchor;
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
const { setFloating, styles } = $derived(floatingPanel);
|
|
60
|
+
const getFloatingPanelProps = useFloatingPanelProps();
|
|
61
|
+
const portal = $derived(!!anchor || theirPortal);
|
|
62
|
+
$effect(() => {
|
|
63
|
+
if (anchor) setFloating(ref ?? null);
|
|
64
|
+
untrack(() => context.setPanel(ref));
|
|
65
|
+
});
|
|
66
|
+
const ownerDocument = $derived(getOwnerDocument(ref));
|
|
67
|
+
$effect(() => {
|
|
68
|
+
id;
|
|
69
|
+
return untrack(() => {
|
|
70
|
+
context.setPanelId(id);
|
|
71
|
+
return () => {
|
|
72
|
+
context.setPanelId(void 0);
|
|
73
|
+
};
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
const usesOpenClosedState = useOpenClosed();
|
|
77
|
+
const _transition = useTransition({
|
|
78
|
+
get enabled() {
|
|
79
|
+
return transition;
|
|
80
|
+
},
|
|
81
|
+
get element() {
|
|
82
|
+
return ref;
|
|
83
|
+
},
|
|
84
|
+
get show() {
|
|
85
|
+
return usesOpenClosedState !== null ? (usesOpenClosedState.value & State.Open) === State.Open : context.popoverState === PopoverStates.Open;
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
const { visible, data: transitionData } = $derived(_transition);
|
|
89
|
+
useOnDisappear({
|
|
90
|
+
get enabled() {
|
|
91
|
+
return visible;
|
|
92
|
+
},
|
|
93
|
+
get ref() {
|
|
94
|
+
return context.button;
|
|
95
|
+
},
|
|
96
|
+
ondisappear: () => {
|
|
97
|
+
context.closePopover();
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
const scrollLockEnabled = $derived(context.__demoMode ? false : modal && visible);
|
|
101
|
+
useScrollLock({
|
|
102
|
+
get enabled() {
|
|
103
|
+
return scrollLockEnabled;
|
|
104
|
+
},
|
|
105
|
+
get ownerDocument() {
|
|
106
|
+
return ownerDocument;
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
const handleKeyDown = (event) => {
|
|
110
|
+
switch (event.key) {
|
|
111
|
+
case "Escape":
|
|
112
|
+
if (context.popoverState !== PopoverStates.Open) return;
|
|
113
|
+
if (!ref) return;
|
|
114
|
+
if (ownerDocument?.activeElement && !ref.contains(ownerDocument.activeElement)) {
|
|
115
|
+
return;
|
|
112
116
|
}
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
return
|
|
153
|
-
|
|
117
|
+
event.preventDefault();
|
|
118
|
+
event.stopPropagation();
|
|
119
|
+
context.closePopover();
|
|
120
|
+
context.button?.focus();
|
|
121
|
+
break;
|
|
122
|
+
}
|
|
123
|
+
};
|
|
124
|
+
$effect(() => {
|
|
125
|
+
if (theirProps.static) return;
|
|
126
|
+
if (context.popoverState === PopoverStates.Closed && (theirProps.unmount ?? true)) {
|
|
127
|
+
context.setPanel(void 0);
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
$effect(() => {
|
|
131
|
+
if (context.__demoMode) return;
|
|
132
|
+
if (!focus) return;
|
|
133
|
+
if (context.popoverState !== PopoverStates.Open) return;
|
|
134
|
+
if (!ref) return;
|
|
135
|
+
const activeElement = ownerDocument?.activeElement;
|
|
136
|
+
if (ref.contains(activeElement)) return;
|
|
137
|
+
focusIn(ref, Focus.First);
|
|
138
|
+
});
|
|
139
|
+
const slot = $derived({
|
|
140
|
+
open: context.popoverState === PopoverStates.Open,
|
|
141
|
+
close
|
|
142
|
+
});
|
|
143
|
+
const buttonSize = useElementSize({
|
|
144
|
+
get element() {
|
|
145
|
+
return context.button ?? null;
|
|
146
|
+
},
|
|
147
|
+
unit: true
|
|
148
|
+
});
|
|
149
|
+
const ourProps = $derived(
|
|
150
|
+
mergeProps(anchor ? getFloatingPanelProps() : {}, {
|
|
151
|
+
id,
|
|
152
|
+
onkeydown: handleKeyDown,
|
|
153
|
+
onblur: focus && context.popoverState === PopoverStates.Open ? (event) => {
|
|
154
|
+
let el = event.relatedTarget;
|
|
155
|
+
if (!el) return;
|
|
156
|
+
if (!ref) return;
|
|
157
|
+
if (ref.contains(el)) return;
|
|
158
|
+
context.closePopover();
|
|
159
|
+
if (context.beforePanelSentinel?.contains?.(el) || context.afterPanelSentinel?.contains?.(el)) {
|
|
160
|
+
el.focus({ preventScroll: true });
|
|
161
|
+
}
|
|
162
|
+
} : void 0,
|
|
163
|
+
tabIndex: -1,
|
|
164
|
+
style: [theirProps.style, styles, `--button-width: ${buttonSize.width}`].filter(Boolean).join("; "),
|
|
165
|
+
...transitionDataAttributes(transitionData)
|
|
154
166
|
})
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
167
|
+
);
|
|
168
|
+
const direction = useTabDirection();
|
|
169
|
+
const handleBeforeFocus = () => {
|
|
170
|
+
let el = ref;
|
|
171
|
+
if (!el) return;
|
|
172
|
+
function run() {
|
|
173
|
+
match(direction.current, {
|
|
174
|
+
[TabDirection.Forwards]: () => {
|
|
175
|
+
let result = focusIn(el, Focus.First);
|
|
176
|
+
if (result === FocusResult.Error) {
|
|
177
|
+
context.afterPanelSentinel?.focus();
|
|
163
178
|
}
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
context.
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
}
|
|
179
|
+
},
|
|
180
|
+
[TabDirection.Backwards]: () => {
|
|
181
|
+
context.button?.focus({ preventScroll: true });
|
|
182
|
+
}
|
|
183
|
+
});
|
|
170
184
|
}
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
if (context.popoverState === PopoverStates.Closed && (theirProps.unmount ?? true)) {
|
|
177
|
-
context.setPanel(undefined)
|
|
178
|
-
}
|
|
179
|
-
}) //, [state.popoverState, props.unmount, props.static, dispatch])
|
|
180
|
-
|
|
181
|
-
// Move focus within panel
|
|
182
|
-
$effect(() => {
|
|
183
|
-
if (context.__demoMode) return
|
|
184
|
-
if (!focus) return
|
|
185
|
-
if (context.popoverState !== PopoverStates.Open) return
|
|
186
|
-
if (!ref) return
|
|
187
|
-
|
|
188
|
-
const activeElement = ownerDocument?.activeElement as HTMLElement
|
|
189
|
-
if (ref.contains(activeElement)) return // Already focused within Dialog
|
|
190
|
-
|
|
191
|
-
focusIn(ref, Focus.First)
|
|
192
|
-
}) //, [state.__demoMode, focus, internalPanelRef.current, state.popoverState])
|
|
193
|
-
|
|
194
|
-
const slot = $derived({
|
|
195
|
-
open: context.popoverState === PopoverStates.Open,
|
|
196
|
-
close,
|
|
197
|
-
} satisfies PanelRenderPropArg)
|
|
198
|
-
|
|
199
|
-
const buttonSize = useElementSize({
|
|
200
|
-
get element() {
|
|
201
|
-
return context.button ?? null
|
|
202
|
-
},
|
|
203
|
-
unit: true,
|
|
204
|
-
})
|
|
205
|
-
const ourProps: Record<string, any> = $derived(
|
|
206
|
-
mergeProps(anchor ? getFloatingPanelProps() : {}, {
|
|
207
|
-
id,
|
|
208
|
-
onkeydown: handleKeyDown,
|
|
209
|
-
onblur:
|
|
210
|
-
focus && context.popoverState === PopoverStates.Open
|
|
211
|
-
? (event: FocusEvent) => {
|
|
212
|
-
let el = event.relatedTarget as HTMLElement
|
|
213
|
-
if (!el) return
|
|
214
|
-
if (!ref) return
|
|
215
|
-
if (ref.contains(el)) return
|
|
216
|
-
|
|
217
|
-
context.closePopover()
|
|
218
|
-
|
|
219
|
-
if (context.beforePanelSentinel?.contains?.(el) || context.afterPanelSentinel?.contains?.(el)) {
|
|
220
|
-
el.focus({ preventScroll: true })
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
: undefined,
|
|
224
|
-
tabIndex: -1,
|
|
225
|
-
style: [theirProps.style, styles, `--button-width: ${buttonSize.width}`].filter(Boolean).join("; "),
|
|
226
|
-
...transitionDataAttributes(transitionData),
|
|
227
|
-
})
|
|
228
|
-
)
|
|
229
|
-
|
|
230
|
-
const direction = useTabDirection()
|
|
231
|
-
const handleBeforeFocus = () => {
|
|
232
|
-
let el = ref as HTMLElement
|
|
233
|
-
if (!el) return
|
|
234
|
-
|
|
235
|
-
function run() {
|
|
236
|
-
match(direction.current, {
|
|
237
|
-
[TabDirection.Forwards]: () => {
|
|
238
|
-
// Try to focus the first thing in the panel. But if that fails (e.g.: there are no
|
|
239
|
-
// focusable elements, then we can move outside of the panel)
|
|
240
|
-
let result = focusIn(el, Focus.First)
|
|
241
|
-
if (result === FocusResult.Error) {
|
|
242
|
-
context.afterPanelSentinel?.focus()
|
|
243
|
-
}
|
|
244
|
-
},
|
|
245
|
-
[TabDirection.Backwards]: () => {
|
|
246
|
-
// Coming from the PopoverPanel (which is portalled to somewhere else). Let's redirect
|
|
247
|
-
// the focus to the PopoverButton again.
|
|
248
|
-
context.button?.focus({ preventScroll: true })
|
|
249
|
-
},
|
|
250
|
-
})
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
// TODO: Cleanup once we are using real browser tests
|
|
254
|
-
if (process.env.NODE_ENV === "test") {
|
|
255
|
-
microTask(run)
|
|
256
|
-
} else {
|
|
257
|
-
run()
|
|
258
|
-
}
|
|
185
|
+
if (process.env.NODE_ENV === "test") {
|
|
186
|
+
microTask(run);
|
|
187
|
+
} else {
|
|
188
|
+
run();
|
|
259
189
|
}
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
// Ignore sentinel buttons and items inside the panel
|
|
279
|
-
for (const element of combined.slice()) {
|
|
280
|
-
if (element.dataset.headlessuiFocusGuard === "true" || ref?.contains(element)) {
|
|
281
|
-
let idx = combined.indexOf(element)
|
|
282
|
-
if (idx !== -1) combined.splice(idx, 1)
|
|
283
|
-
}
|
|
190
|
+
};
|
|
191
|
+
const handleAfterFocus = () => {
|
|
192
|
+
let el = ref;
|
|
193
|
+
if (!el) return;
|
|
194
|
+
function run() {
|
|
195
|
+
match(direction.current, {
|
|
196
|
+
[TabDirection.Forwards]: () => {
|
|
197
|
+
if (!context.button) return;
|
|
198
|
+
const elements = getFocusableElements();
|
|
199
|
+
const idx = elements.indexOf(context.button);
|
|
200
|
+
const before = elements.slice(0, idx + 1);
|
|
201
|
+
const after = elements.slice(idx + 1);
|
|
202
|
+
const combined = [...after, ...before];
|
|
203
|
+
for (const element of combined.slice()) {
|
|
204
|
+
if (element.dataset.headlessuiFocusGuard === "true" || ref?.contains(element)) {
|
|
205
|
+
let idx2 = combined.indexOf(element);
|
|
206
|
+
if (idx2 !== -1) combined.splice(idx2, 1);
|
|
284
207
|
}
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
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()
|
|
304
|
-
}
|
|
208
|
+
}
|
|
209
|
+
focusIn(combined, Focus.First, { sorted: false });
|
|
210
|
+
},
|
|
211
|
+
[TabDirection.Backwards]: () => {
|
|
212
|
+
let result = focusIn(el, Focus.Previous);
|
|
213
|
+
if (result === FocusResult.Error) {
|
|
214
|
+
context.button?.focus();
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
});
|
|
305
218
|
}
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
219
|
+
if (process.env.NODE_ENV === "test") {
|
|
220
|
+
microTask(run);
|
|
221
|
+
} else {
|
|
222
|
+
run();
|
|
223
|
+
}
|
|
224
|
+
};
|
|
225
|
+
clearOpenClosedContext();
|
|
226
|
+
setContext("PopoverPanelContext", {
|
|
227
|
+
get value() {
|
|
228
|
+
return id;
|
|
229
|
+
}
|
|
230
|
+
});
|
|
231
|
+
setContext("PopoverAPIContext", {
|
|
232
|
+
get close() {
|
|
233
|
+
return close;
|
|
234
|
+
},
|
|
235
|
+
get isPortalled() {
|
|
236
|
+
return isPortalled;
|
|
237
|
+
}
|
|
238
|
+
});
|
|
321
239
|
</script>
|
|
322
240
|
|
|
323
241
|
<Portal enabled={portal ? theirProps.static || visible : false}>
|