@pzerelles/headlessui-svelte 2.1.2-next.10 → 2.1.2-next.11
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/hooks/use-did-element-move.svelte.js +5 -10
- package/dist/internal/FloatingProvider.svelte +12 -0
- package/dist/internal/FloatingProvider.svelte.d.ts +22 -0
- package/dist/internal/floating-provider.svelte.d.ts +3 -0
- package/dist/internal/floating-provider.svelte.js +206 -0
- package/dist/internal/floating.svelte.d.ts +48 -23
- package/dist/internal/floating.svelte.js +78 -260
- package/dist/internal/inner.svelte.d.ts +91 -0
- package/dist/internal/inner.svelte.js +202 -0
- package/dist/listbox/Listbox.svelte +34 -51
- package/dist/listbox/Listbox.svelte.d.ts +2 -53
- package/dist/listbox/ListboxButton.svelte +7 -6
- package/dist/listbox/ListboxOption.svelte +6 -3
- package/dist/listbox/ListboxOptions.svelte +51 -50
- package/dist/listbox/context.svelte.d.ts +75 -0
- package/dist/listbox/context.svelte.js +36 -0
- package/dist/menu/Menu.svelte +2 -2
- package/dist/menu/MenuButton.svelte +4 -2
- package/dist/menu/MenuItems.svelte +15 -11
- package/dist/tabs/TabGroup.svelte.d.ts +1 -1
- package/dist/utils/ElementOrComponent.svelte +1 -1
- package/dist/utils/floating-ui/svelte/components/FloatingNode.svelte +17 -0
- package/dist/utils/floating-ui/svelte/components/FloatingNode.svelte.d.ts +23 -0
- package/dist/utils/floating-ui/svelte/components/FloatingTree.svelte +50 -0
- package/dist/utils/floating-ui/svelte/components/FloatingTree.svelte.d.ts +41 -0
- package/dist/utils/floating-ui/svelte/hooks/useFloating.svelte.d.ts +6 -0
- package/dist/utils/floating-ui/svelte/hooks/useFloating.svelte.js +158 -0
- package/dist/utils/floating-ui/svelte/hooks/useFloatingRootContext.svelte.d.ts +11 -0
- package/dist/utils/floating-ui/svelte/hooks/useFloatingRootContext.svelte.js +53 -0
- package/dist/utils/floating-ui/svelte/hooks/useId.svelte.d.ts +9 -0
- package/dist/utils/floating-ui/svelte/hooks/useId.svelte.js +28 -0
- package/dist/utils/floating-ui/svelte/hooks/useInteractions.svelte.d.ts +23 -0
- package/dist/utils/floating-ui/svelte/hooks/useInteractions.svelte.js +72 -0
- package/dist/utils/floating-ui/svelte/index.d.ts +5 -0
- package/dist/utils/floating-ui/svelte/index.js +5 -0
- package/dist/utils/floating-ui/svelte/inner.svelte.d.ts +83 -0
- package/dist/utils/floating-ui/svelte/inner.svelte.js +178 -0
- package/dist/utils/floating-ui/svelte/types.d.ts +114 -0
- package/dist/utils/floating-ui/svelte/types.js +1 -0
- package/dist/utils/floating-ui/svelte/utils/createPubSub.d.ts +5 -0
- package/dist/utils/floating-ui/svelte/utils/createPubSub.js +14 -0
- package/dist/utils/floating-ui/svelte/utils/getFloatingFocusElement.d.ts +2 -0
- package/dist/utils/floating-ui/svelte/utils/getFloatingFocusElement.js +13 -0
- package/dist/utils/floating-ui/svelte/utils/log.d.ts +2 -0
- package/dist/utils/floating-ui/svelte/utils/log.js +19 -0
- package/dist/utils/floating-ui/svelte/utils.d.ts +19 -0
- package/dist/utils/floating-ui/svelte/utils.js +136 -0
- package/dist/utils/floating-ui/svelte-dom/arrow.d.ts +22 -0
- package/dist/utils/floating-ui/svelte-dom/arrow.js +29 -0
- package/dist/utils/floating-ui/svelte-dom/index.d.ts +2 -0
- package/dist/utils/floating-ui/svelte-dom/index.js +2 -0
- package/dist/utils/floating-ui/svelte-dom/types.d.ts +80 -0
- package/dist/utils/floating-ui/svelte-dom/types.js +3 -0
- package/dist/utils/floating-ui/svelte-dom/useFloating.svelte.d.ts +6 -0
- package/dist/utils/floating-ui/svelte-dom/useFloating.svelte.js +183 -0
- package/dist/utils/floating-ui/svelte-dom/utils/deepEqual.d.ts +1 -0
- package/dist/utils/floating-ui/svelte-dom/utils/deepEqual.js +50 -0
- package/dist/utils/floating-ui/svelte-dom/utils/getDPR.d.ts +1 -0
- package/dist/utils/floating-ui/svelte-dom/utils/getDPR.js +7 -0
- package/dist/utils/floating-ui/svelte-dom/utils/roundByDPR.d.ts +1 -0
- package/dist/utils/floating-ui/svelte-dom/utils/roundByDPR.js +5 -0
- package/dist/utils/floating-ui/svelte-dom/utils/useLatestRef.d.ts +4 -0
- package/dist/utils/floating-ui/svelte-dom/utils/useLatestRef.js +7 -0
- package/dist/utils/style.d.ts +2 -0
- package/dist/utils/style.js +6 -0
- package/package.json +3 -2
- package/dist/listbox/ListboxStates.d.ts +0 -12
- package/dist/listbox/ListboxStates.js +0 -15
|
@@ -24,9 +24,7 @@ import { Focus } from "../utils/calculate-active-index.js";
|
|
|
24
24
|
import { focusFrom, Focus as FocusManagementFocus } from "../utils/focus-management.js";
|
|
25
25
|
import { useElementSize } from "../hooks/use-element-size.svelte.js";
|
|
26
26
|
import { setContext } from "svelte";
|
|
27
|
-
import Hidden from "../internal/Hidden.svelte";
|
|
28
27
|
import Portal from "../portal/Portal.svelte";
|
|
29
|
-
import { stateFromSlot } from "../utils/state.js";
|
|
30
28
|
import ElementOrComponent from "../utils/ElementOrComponent.svelte";
|
|
31
29
|
const internalId = useId();
|
|
32
30
|
let {
|
|
@@ -36,11 +34,15 @@ let {
|
|
|
36
34
|
portal = false,
|
|
37
35
|
modal = true,
|
|
38
36
|
transition = false,
|
|
39
|
-
static: isStatic = false,
|
|
40
|
-
unmount = true,
|
|
41
37
|
...theirProps
|
|
42
38
|
} = $props();
|
|
43
|
-
const
|
|
39
|
+
const resolvedAnchor = useResolvedAnchor({
|
|
40
|
+
get anchor() {
|
|
41
|
+
return rawAnchor;
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
const { anchor } = $derived(resolvedAnchor);
|
|
45
|
+
let localOptionsElement = $state();
|
|
44
46
|
$effect(() => {
|
|
45
47
|
if (anchor) {
|
|
46
48
|
portal = true;
|
|
@@ -48,7 +50,7 @@ $effect(() => {
|
|
|
48
50
|
});
|
|
49
51
|
const data = useData("ListboxOptions");
|
|
50
52
|
const actions = useActions("ListboxOptions");
|
|
51
|
-
const ownerDocument = $derived(getOwnerDocument(data.
|
|
53
|
+
const ownerDocument = $derived(getOwnerDocument(data.optionsElement));
|
|
52
54
|
const usesOpenClosedState = useOpenClosed();
|
|
53
55
|
const show = $derived(
|
|
54
56
|
usesOpenClosedState !== null ? (usesOpenClosedState.value & State.Open) === State.Open : data.listboxState === ListboxStates.Open
|
|
@@ -58,7 +60,7 @@ const _transition = useTransition({
|
|
|
58
60
|
return transition;
|
|
59
61
|
},
|
|
60
62
|
get element() {
|
|
61
|
-
return
|
|
63
|
+
return localOptionsElement;
|
|
62
64
|
},
|
|
63
65
|
get show() {
|
|
64
66
|
return show;
|
|
@@ -70,7 +72,7 @@ useOnDisappear({
|
|
|
70
72
|
return visible;
|
|
71
73
|
},
|
|
72
74
|
get ref() {
|
|
73
|
-
return data.
|
|
75
|
+
return data.buttonElement;
|
|
74
76
|
},
|
|
75
77
|
get ondisappear() {
|
|
76
78
|
return actions.closeListbox;
|
|
@@ -92,7 +94,7 @@ useInertOthers({
|
|
|
92
94
|
},
|
|
93
95
|
elements: {
|
|
94
96
|
get allowed() {
|
|
95
|
-
return [data.
|
|
97
|
+
return [data.buttonElement, data.optionsElement];
|
|
96
98
|
}
|
|
97
99
|
}
|
|
98
100
|
});
|
|
@@ -102,7 +104,7 @@ const didButtonMove = useDidElementMove({
|
|
|
102
104
|
return didElementMoveEnabled;
|
|
103
105
|
},
|
|
104
106
|
get element() {
|
|
105
|
-
return data.
|
|
107
|
+
return data.buttonElement;
|
|
106
108
|
}
|
|
107
109
|
});
|
|
108
110
|
const panelEnabled = $derived(didButtonMove.value ? false : visible);
|
|
@@ -115,18 +117,18 @@ const frozenValue = useFrozenData({
|
|
|
115
117
|
return data.value;
|
|
116
118
|
}
|
|
117
119
|
});
|
|
118
|
-
const isSelected = (compareValue) => data.compare(frozenValue, compareValue);
|
|
119
|
-
const selectedOptionIndex = () => {
|
|
120
|
+
const isSelected = (compareValue) => data.compare(frozenValue.data, compareValue);
|
|
121
|
+
const selectedOptionIndex = $derived.by(() => {
|
|
120
122
|
if (anchor == null) return null;
|
|
121
123
|
if (!anchor?.to?.includes("selection")) return null;
|
|
122
124
|
let idx = data.options.findIndex((option) => isSelected(option.dataRef.current.value));
|
|
123
125
|
if (idx === -1) idx = 0;
|
|
124
126
|
return idx;
|
|
125
|
-
};
|
|
127
|
+
});
|
|
126
128
|
const anchorOptions = $derived.by(() => {
|
|
127
129
|
if (anchor == null) return void 0;
|
|
128
130
|
if (selectedOptionIndex === null) return { ...anchor, inner: void 0 };
|
|
129
|
-
let elements = Array.from(data.
|
|
131
|
+
let elements = Array.from(data.listElements.values());
|
|
130
132
|
return {
|
|
131
133
|
...anchor,
|
|
132
134
|
inner: {
|
|
@@ -140,20 +142,20 @@ const floatingPanel = useFloatingPanel({
|
|
|
140
142
|
return anchorOptions ?? null;
|
|
141
143
|
}
|
|
142
144
|
});
|
|
143
|
-
const { setFloating,
|
|
145
|
+
const { setFloating, styles } = $derived(floatingPanel);
|
|
144
146
|
const getFloatingPanelProps = useFloatingPanelProps();
|
|
145
147
|
$effect(() => {
|
|
146
|
-
|
|
147
|
-
|
|
148
|
+
localOptionsElement = ref;
|
|
149
|
+
data.optionsElement = ref ?? null;
|
|
150
|
+
if (anchor) setFloating(ref ?? null);
|
|
148
151
|
});
|
|
149
152
|
const searchDisposables = useDisposables();
|
|
150
|
-
const { listboxState,
|
|
153
|
+
const { listboxState, optionsElement } = $derived(data);
|
|
151
154
|
$effect(() => {
|
|
152
|
-
|
|
153
|
-
if (!container) return;
|
|
155
|
+
if (!optionsElement) return;
|
|
154
156
|
if (listboxState !== ListboxStates.Open) return;
|
|
155
|
-
if (
|
|
156
|
-
|
|
157
|
+
if (optionsElement === getOwnerDocument(optionsElement)?.activeElement) return;
|
|
158
|
+
optionsElement?.focus({ preventScroll: true });
|
|
157
159
|
});
|
|
158
160
|
const handleKeyDown = (event) => {
|
|
159
161
|
searchDisposables.dispose();
|
|
@@ -173,7 +175,7 @@ const handleKeyDown = (event) => {
|
|
|
173
175
|
}
|
|
174
176
|
if (data.mode === ValueMode.Single) {
|
|
175
177
|
actions.closeListbox();
|
|
176
|
-
data.
|
|
178
|
+
data.buttonElement?.focus({ preventScroll: true });
|
|
177
179
|
}
|
|
178
180
|
break;
|
|
179
181
|
case match(data.orientation, { vertical: "ArrowDown", horizontal: "ArrowRight" }):
|
|
@@ -198,13 +200,13 @@ const handleKeyDown = (event) => {
|
|
|
198
200
|
event.preventDefault();
|
|
199
201
|
event.stopPropagation();
|
|
200
202
|
actions.closeListbox();
|
|
201
|
-
data.
|
|
203
|
+
data.buttonElement?.focus({ preventScroll: true });
|
|
202
204
|
return;
|
|
203
205
|
case "Tab":
|
|
204
206
|
event.preventDefault();
|
|
205
207
|
event.stopPropagation();
|
|
206
208
|
actions.closeListbox();
|
|
207
|
-
focusFrom(data.
|
|
209
|
+
focusFrom(data.buttonElement, event.shiftKey ? FocusManagementFocus.Previous : FocusManagementFocus.Next);
|
|
208
210
|
break;
|
|
209
211
|
default:
|
|
210
212
|
if (event.key.length === 1) {
|
|
@@ -214,34 +216,35 @@ const handleKeyDown = (event) => {
|
|
|
214
216
|
break;
|
|
215
217
|
}
|
|
216
218
|
};
|
|
217
|
-
const labelledby = $derived(data.
|
|
219
|
+
const labelledby = $derived(data.buttonElement?.id);
|
|
218
220
|
const slot = $derived({
|
|
219
221
|
open: data.listboxState === ListboxStates.Open
|
|
220
222
|
});
|
|
221
223
|
const buttonSize = useElementSize({
|
|
222
224
|
get element() {
|
|
223
|
-
return data.
|
|
225
|
+
return data.buttonElement;
|
|
224
226
|
},
|
|
225
227
|
unit: true
|
|
226
228
|
});
|
|
227
|
-
|
|
228
|
-
|
|
229
|
+
$effect(() => {
|
|
230
|
+
transitionData;
|
|
231
|
+
});
|
|
232
|
+
const ourProps = $derived({
|
|
233
|
+
...mergeProps(anchor ? getFloatingPanelProps() : {}, {
|
|
229
234
|
id,
|
|
230
235
|
"aria-activedescendant": data.activeOptionIndex === null ? void 0 : data.options[data.activeOptionIndex]?.id,
|
|
231
236
|
"aria-multiselectable": data.mode === ValueMode.Multi ? true : void 0,
|
|
232
237
|
"aria-labelledby": labelledby,
|
|
233
238
|
"aria-orientation": data.orientation,
|
|
234
|
-
onkeydown: handleKeyDown,
|
|
235
239
|
role: "listbox",
|
|
236
240
|
// When the `Listbox` is closed, it should not be focusable. This allows us
|
|
237
241
|
// to skip focusing the `ListboxOptions` when pressing the tab key on an
|
|
238
242
|
// open `Listbox`, and go to the next focusable element.
|
|
239
|
-
|
|
240
|
-
style: [theirProps.style,
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
);
|
|
243
|
+
tabindex: data.listboxState === ListboxStates.Open ? 0 : void 0,
|
|
244
|
+
style: [theirProps.style, styles, `--button-width: ${buttonSize.width}`].filter(Boolean).join("; ")
|
|
245
|
+
}),
|
|
246
|
+
...transitionDataAttributes(transitionData)
|
|
247
|
+
});
|
|
245
248
|
const derivedData = {
|
|
246
249
|
...data,
|
|
247
250
|
get isSelected() {
|
|
@@ -249,20 +252,18 @@ const derivedData = {
|
|
|
249
252
|
}
|
|
250
253
|
};
|
|
251
254
|
setContext("ListboxDataContext", derivedData);
|
|
255
|
+
$inspect(styles);
|
|
252
256
|
</script>
|
|
253
257
|
|
|
254
|
-
<Portal enabled={portal ?
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
bind:ref
|
|
266
|
-
/>
|
|
267
|
-
{/if}
|
|
258
|
+
<Portal enabled={portal ? theirProps.static || visible : false}>
|
|
259
|
+
<ElementOrComponent
|
|
260
|
+
{ourProps}
|
|
261
|
+
{theirProps}
|
|
262
|
+
slots={slot}
|
|
263
|
+
defaultTag={DEFAULT_OPTIONS_TAG}
|
|
264
|
+
features={OptionsRenderFeatures}
|
|
265
|
+
visible={panelEnabled}
|
|
266
|
+
name="ListboxOptions"
|
|
267
|
+
bind:ref
|
|
268
|
+
/>
|
|
268
269
|
</Portal>
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import type { Focus } from "../utils/calculate-active-index.js";
|
|
2
|
+
import type { MutableRefObject } from "../utils/ref.svelte.js";
|
|
3
|
+
import type { SvelteMap } from "svelte/reactivity";
|
|
4
|
+
export declare enum ListboxStates {
|
|
5
|
+
Open = 0,
|
|
6
|
+
Closed = 1
|
|
7
|
+
}
|
|
8
|
+
export declare enum ValueMode {
|
|
9
|
+
Single = 0,
|
|
10
|
+
Multi = 1
|
|
11
|
+
}
|
|
12
|
+
export declare enum ActivationTrigger {
|
|
13
|
+
Pointer = 0,
|
|
14
|
+
Other = 1
|
|
15
|
+
}
|
|
16
|
+
export type ListboxOptionDataRef<T> = MutableRefObject<{
|
|
17
|
+
textValue?: string;
|
|
18
|
+
disabled: boolean;
|
|
19
|
+
value: T;
|
|
20
|
+
domRef: MutableRefObject<HTMLElement | null>;
|
|
21
|
+
}>;
|
|
22
|
+
export interface StateDefinition<T> {
|
|
23
|
+
listboxState: ListboxStates;
|
|
24
|
+
options: {
|
|
25
|
+
id: string;
|
|
26
|
+
dataRef: ListboxOptionDataRef<T>;
|
|
27
|
+
}[];
|
|
28
|
+
searchQuery: string;
|
|
29
|
+
activeOptionIndex: number | null;
|
|
30
|
+
activationTrigger: ActivationTrigger;
|
|
31
|
+
__demoMode: boolean;
|
|
32
|
+
}
|
|
33
|
+
export interface StateActions<T> {
|
|
34
|
+
openListbox(): void;
|
|
35
|
+
closeListbox(): void;
|
|
36
|
+
registerOption(id: string, dataRef: ListboxOptionDataRef<T>): void;
|
|
37
|
+
unregisterOption(id: string): void;
|
|
38
|
+
goToOption(action: {
|
|
39
|
+
focus: Focus.Specific;
|
|
40
|
+
id: string;
|
|
41
|
+
trigger?: ActivationTrigger;
|
|
42
|
+
} | {
|
|
43
|
+
focus: Exclude<Focus, Focus.Specific>;
|
|
44
|
+
trigger?: ActivationTrigger;
|
|
45
|
+
}): void;
|
|
46
|
+
search(query: string): void;
|
|
47
|
+
clearSearch(): void;
|
|
48
|
+
}
|
|
49
|
+
export type ListboxActionsContext<T = unknown> = {
|
|
50
|
+
registerOption(id: string, dataRef: ListboxOptionDataRef<T>): () => void;
|
|
51
|
+
goToOption(focus: Focus.Specific, id: string, trigger?: ActivationTrigger): void;
|
|
52
|
+
goToOption(focus: Focus, id?: string, trigger?: ActivationTrigger): void;
|
|
53
|
+
selectOption(id: string): void;
|
|
54
|
+
selectActiveOption(): void;
|
|
55
|
+
onChange(value: T): void;
|
|
56
|
+
} & Pick<StateActions<T>, "openListbox" | "closeListbox" | "search" | "clearSearch">;
|
|
57
|
+
export declare function useActions<T>(component: string): ListboxActionsContext<T>;
|
|
58
|
+
export type ListboxDataContext<T = unknown> = {
|
|
59
|
+
value: T;
|
|
60
|
+
disabled: boolean;
|
|
61
|
+
invalid: boolean;
|
|
62
|
+
mode: ValueMode;
|
|
63
|
+
orientation: "horizontal" | "vertical";
|
|
64
|
+
activeOptionIndex: number | null;
|
|
65
|
+
compare(a: T, z: T): boolean;
|
|
66
|
+
isSelected(value: T): boolean;
|
|
67
|
+
optionsProps: {
|
|
68
|
+
static: boolean;
|
|
69
|
+
hold: boolean;
|
|
70
|
+
};
|
|
71
|
+
listElements: SvelteMap<string, HTMLElement | null>;
|
|
72
|
+
buttonElement: HTMLElement | null;
|
|
73
|
+
optionsElement: HTMLElement | null;
|
|
74
|
+
} & StateDefinition<T>;
|
|
75
|
+
export declare function useData<T>(component: string): ListboxDataContext<T>;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { getContext } from "svelte";
|
|
2
|
+
export var ListboxStates;
|
|
3
|
+
(function (ListboxStates) {
|
|
4
|
+
ListboxStates[ListboxStates["Open"] = 0] = "Open";
|
|
5
|
+
ListboxStates[ListboxStates["Closed"] = 1] = "Closed";
|
|
6
|
+
})(ListboxStates || (ListboxStates = {}));
|
|
7
|
+
export var ValueMode;
|
|
8
|
+
(function (ValueMode) {
|
|
9
|
+
ValueMode[ValueMode["Single"] = 0] = "Single";
|
|
10
|
+
ValueMode[ValueMode["Multi"] = 1] = "Multi";
|
|
11
|
+
})(ValueMode || (ValueMode = {}));
|
|
12
|
+
export var ActivationTrigger;
|
|
13
|
+
(function (ActivationTrigger) {
|
|
14
|
+
ActivationTrigger[ActivationTrigger["Pointer"] = 0] = "Pointer";
|
|
15
|
+
ActivationTrigger[ActivationTrigger["Other"] = 1] = "Other";
|
|
16
|
+
})(ActivationTrigger || (ActivationTrigger = {}));
|
|
17
|
+
export function useActions(component) {
|
|
18
|
+
const context = getContext("ListboxActionsContext");
|
|
19
|
+
if (!context) {
|
|
20
|
+
let err = new Error(`<${component} /> is missing a parent <Listbox /> component.`);
|
|
21
|
+
if (Error.captureStackTrace)
|
|
22
|
+
Error.captureStackTrace(err, useActions);
|
|
23
|
+
throw err;
|
|
24
|
+
}
|
|
25
|
+
return context;
|
|
26
|
+
}
|
|
27
|
+
export function useData(component) {
|
|
28
|
+
const context = getContext("ListboxDataContext");
|
|
29
|
+
if (context === null) {
|
|
30
|
+
let err = new Error(`<${component} /> is missing a parent <Listbox /> component.`);
|
|
31
|
+
if (Error.captureStackTrace)
|
|
32
|
+
Error.captureStackTrace(err, useData);
|
|
33
|
+
throw err;
|
|
34
|
+
}
|
|
35
|
+
return context;
|
|
36
|
+
}
|
package/dist/menu/Menu.svelte
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script lang="ts" module>import { useOutsideClick } from "../hooks/use-outside-click.svelte.js";
|
|
2
|
-
import {
|
|
2
|
+
import { useFloatingProvider } from "../internal/floating.svelte.js";
|
|
3
3
|
import { createOpenClosedContext, State } from "../internal/open-closed.js";
|
|
4
4
|
import { calculateActiveIndex, Focus } from "../utils/calculate-active-index.js";
|
|
5
5
|
import ElementOrComponent from "../utils/ElementOrComponent.svelte";
|
|
@@ -218,7 +218,7 @@ const slot = $derived({
|
|
|
218
218
|
open: _state.menuState === MenuStates.Open,
|
|
219
219
|
close: _state.closeMenu
|
|
220
220
|
});
|
|
221
|
-
|
|
221
|
+
useFloatingProvider();
|
|
222
222
|
const openClosed = $derived(
|
|
223
223
|
match(menuState, {
|
|
224
224
|
[MenuStates.Open]: State.Open,
|
|
@@ -7,7 +7,7 @@ import { Focus } from "../utils/calculate-active-index.js";
|
|
|
7
7
|
import { useFocusRing } from "../hooks/use-focus-ring.svelte.js";
|
|
8
8
|
import { useActivePress } from "../hooks/use-active-press.svelte.js";
|
|
9
9
|
import { useResolveButtonType } from "../hooks/use-resolve-button-type.svelte.js";
|
|
10
|
-
import {
|
|
10
|
+
import { useFloatingReference, useFloatingReferenceProps } from "../internal/floating.svelte.js";
|
|
11
11
|
import { useHover } from "../hooks/use-hover.svelte.js";
|
|
12
12
|
import { mergeProps } from "../utils/render.js";
|
|
13
13
|
import { MenuStates, useMenuContext } from "./context.svelte.js";
|
|
@@ -22,7 +22,9 @@ let {
|
|
|
22
22
|
...theirProps
|
|
23
23
|
} = $props();
|
|
24
24
|
const _state = useMenuContext("MenuButton");
|
|
25
|
-
const
|
|
25
|
+
const floatingReference = useFloatingReference();
|
|
26
|
+
const { setReference } = $derived(floatingReference);
|
|
27
|
+
const { getReferenceProps: getFloatingReferenceProps } = useFloatingReferenceProps();
|
|
26
28
|
$effect(() => {
|
|
27
29
|
untrack(() => _state.setButtonElement(ref ? ref : null));
|
|
28
30
|
setReference(ref);
|
|
@@ -36,18 +36,23 @@ let {
|
|
|
36
36
|
transition = false,
|
|
37
37
|
...theirProps
|
|
38
38
|
} = $props();
|
|
39
|
-
const
|
|
39
|
+
const resolvedAnchor = useResolvedAnchor({
|
|
40
|
+
get anchor() {
|
|
41
|
+
return rawAnchor;
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
const { anchor } = $derived(resolvedAnchor);
|
|
40
45
|
const _state = useMenuContext("MenuOptions");
|
|
41
46
|
const floatingPanel = useFloatingPanel({
|
|
42
47
|
get placement() {
|
|
43
48
|
return anchor;
|
|
44
49
|
}
|
|
45
50
|
});
|
|
46
|
-
const { setFloating,
|
|
51
|
+
const { setFloating, styles } = $derived(floatingPanel);
|
|
47
52
|
const getFloatingPanelProps = useFloatingPanelProps();
|
|
48
53
|
$effect(() => {
|
|
49
|
-
untrack(() => _state.setItemsElement(ref
|
|
50
|
-
if (anchor) setFloating(ref);
|
|
54
|
+
untrack(() => _state.setItemsElement(ref ?? null));
|
|
55
|
+
if (anchor) setFloating(ref ?? null);
|
|
51
56
|
});
|
|
52
57
|
const ownerDocument = $derived(getOwnerDocument(_state.itemsElement));
|
|
53
58
|
$effect(() => {
|
|
@@ -211,8 +216,8 @@ const buttonSize = useElementSize({
|
|
|
211
216
|
},
|
|
212
217
|
unit: true
|
|
213
218
|
});
|
|
214
|
-
const ourProps = $derived(
|
|
215
|
-
mergeProps(anchor ? getFloatingPanelProps() : {}, {
|
|
219
|
+
const ourProps = $derived({
|
|
220
|
+
...mergeProps(anchor ? getFloatingPanelProps() : {}, {
|
|
216
221
|
"aria-activedescendant": _state.activeItemIndex === null ? void 0 : _state.items[_state.activeItemIndex]?.id,
|
|
217
222
|
"aria-labelledby": _state.buttonElement?.id,
|
|
218
223
|
id,
|
|
@@ -223,11 +228,10 @@ const ourProps = $derived(
|
|
|
223
228
|
// to skip focusing the `MenuItems` when pressing the tab key on an
|
|
224
229
|
// open `Menu`, and go to the next focusable element.
|
|
225
230
|
tabindex: _state.menuState === MenuStates.Open ? 0 : void 0,
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
);
|
|
231
|
+
style: [theirProps.style, styles, `--button-width: ${buttonSize.width}`].filter(Boolean).join("; ")
|
|
232
|
+
}),
|
|
233
|
+
...transitionDataAttributes(transitionData)
|
|
234
|
+
});
|
|
231
235
|
</script>
|
|
232
236
|
|
|
233
237
|
<Portal enabled={portal ? theirProps.static || visible : false}>
|
|
@@ -34,7 +34,7 @@ import type { MutableRefObject } from "../utils/ref.svelte.js";
|
|
|
34
34
|
declare class __sveltets_Render<TTag extends ElementType = typeof DEFAULT_TABS_TAG> {
|
|
35
35
|
props(): {
|
|
36
36
|
as?: TTag | undefined;
|
|
37
|
-
} & (Exclude<keyof import("../utils/types.js").PropsOf<TTag>, ("as" | "children" | "refName" | "class") | "onchange" | "vertical" | "
|
|
37
|
+
} & (Exclude<keyof import("../utils/types.js").PropsOf<TTag>, ("as" | "children" | "refName" | "class") | "onchange" | "vertical" | "manual" | "defaultIndex" | "selectedIndex"> extends infer T extends keyof import("../utils/types.js").PropsOf<TTag> ? { [P in T]: import("../utils/types.js").PropsOf<TTag>[P]; } : never) & {
|
|
38
38
|
children?: import("../utils/types.js").Children<TabsRenderPropArg> | undefined;
|
|
39
39
|
ref?: HTMLElement;
|
|
40
40
|
} & (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) ? {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<script lang="ts" generics="TFeature extends RenderFeatures, TTag extends ElementType, TSlot, TValue">import { mergePropsAdvanced, RenderFeatures
|
|
1
|
+
<script lang="ts" generics="TFeature extends RenderFeatures, TTag extends ElementType, TSlot, TValue">import { mergePropsAdvanced, RenderFeatures } from "./render.js";
|
|
2
2
|
import Generic from "./Generic.svelte";
|
|
3
3
|
let {
|
|
4
4
|
ourProps,
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
<script lang="ts" module></script>
|
|
2
|
+
|
|
3
|
+
<script lang="ts">import { setContext } from "svelte";
|
|
4
|
+
import { useFloatingParentNodeId } from "./FloatingTree.svelte";
|
|
5
|
+
const { children, id } = $props();
|
|
6
|
+
const parentId = useFloatingParentNodeId();
|
|
7
|
+
setContext("FloatingNodeContext", {
|
|
8
|
+
get id() {
|
|
9
|
+
return id;
|
|
10
|
+
},
|
|
11
|
+
get parentId() {
|
|
12
|
+
return parentId.value;
|
|
13
|
+
}
|
|
14
|
+
});
|
|
15
|
+
</script>
|
|
16
|
+
|
|
17
|
+
{#if children}{@render children()}{/if}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { Snippet } from "svelte";
|
|
2
|
+
export interface FloatingNodeProps {
|
|
3
|
+
children?: Snippet;
|
|
4
|
+
id: string;
|
|
5
|
+
}
|
|
6
|
+
interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
|
|
7
|
+
new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
|
|
8
|
+
$$bindings?: Bindings;
|
|
9
|
+
} & Exports;
|
|
10
|
+
(internal: unknown, props: Props & {
|
|
11
|
+
$$events?: Events;
|
|
12
|
+
$$slots?: Slots;
|
|
13
|
+
}): Exports & {
|
|
14
|
+
$set?: any;
|
|
15
|
+
$on?: any;
|
|
16
|
+
};
|
|
17
|
+
z_$$bindings?: Bindings;
|
|
18
|
+
}
|
|
19
|
+
declare const FloatingNode: $$__sveltets_2_IsomorphicComponent<FloatingNodeProps, {
|
|
20
|
+
[evt: string]: CustomEvent<any>;
|
|
21
|
+
}, {}, {}, "">;
|
|
22
|
+
type FloatingNode = InstanceType<typeof FloatingNode>;
|
|
23
|
+
export default FloatingNode;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
<script lang="ts" module>import { getContext } from "svelte";
|
|
2
|
+
import { useId } from "../hooks/useId.svelte.js";
|
|
3
|
+
import { createPubSub } from "../utils/createPubSub.js";
|
|
4
|
+
export const useFloatingParentNodeId = () => {
|
|
5
|
+
const context = getContext("FloatingNodeContext");
|
|
6
|
+
return {
|
|
7
|
+
get value() {
|
|
8
|
+
return context?.id ?? null;
|
|
9
|
+
}
|
|
10
|
+
};
|
|
11
|
+
};
|
|
12
|
+
export const useFloatingTree = () => getContext("FloatingTreeContext") ?? null;
|
|
13
|
+
export function useFloatingNodeId(options) {
|
|
14
|
+
const { customParentId } = $derived(options);
|
|
15
|
+
const id = useId();
|
|
16
|
+
const tree = useFloatingTree();
|
|
17
|
+
const reactParentId = useFloatingParentNodeId();
|
|
18
|
+
const parentId = $derived(customParentId || reactParentId.value);
|
|
19
|
+
$effect(() => {
|
|
20
|
+
const node = { id, parentId };
|
|
21
|
+
tree?.addNode(node);
|
|
22
|
+
return () => {
|
|
23
|
+
tree?.removeNode(node);
|
|
24
|
+
};
|
|
25
|
+
});
|
|
26
|
+
return id;
|
|
27
|
+
}
|
|
28
|
+
</script>
|
|
29
|
+
|
|
30
|
+
<script lang="ts">import { setContext } from "svelte";
|
|
31
|
+
const { children } = $props();
|
|
32
|
+
const nodesRef = $state({ current: [] });
|
|
33
|
+
const addNode = (node) => {
|
|
34
|
+
nodesRef.current = [...nodesRef.current, node];
|
|
35
|
+
};
|
|
36
|
+
const removeNode = (node) => {
|
|
37
|
+
nodesRef.current = nodesRef.current.filter((n) => n !== node);
|
|
38
|
+
};
|
|
39
|
+
const events = createPubSub();
|
|
40
|
+
setContext("FloatingTreeContext", {
|
|
41
|
+
get nodesRef() {
|
|
42
|
+
return nodesRef;
|
|
43
|
+
},
|
|
44
|
+
addNode,
|
|
45
|
+
removeNode,
|
|
46
|
+
events
|
|
47
|
+
});
|
|
48
|
+
</script>
|
|
49
|
+
|
|
50
|
+
{#if children}{@render children()}{/if}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { type Snippet } from "svelte";
|
|
2
|
+
import type { FloatingTreeType, ReferenceType } from "../types.js";
|
|
3
|
+
/**
|
|
4
|
+
* Returns the parent node id for nested floating elements, if available.
|
|
5
|
+
* Returns `null` for top-level floating elements.
|
|
6
|
+
*/
|
|
7
|
+
export declare const useFloatingParentNodeId: () => {
|
|
8
|
+
readonly value: string | null;
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* Returns the nearest floating tree context, if available.
|
|
12
|
+
*/
|
|
13
|
+
export declare const useFloatingTree: <RT extends ReferenceType = ReferenceType>() => FloatingTreeType<RT> | null;
|
|
14
|
+
/**
|
|
15
|
+
* Registers a node into the `FloatingTree`, returning its id.
|
|
16
|
+
* @see https://floating-ui.com/docs/FloatingTree
|
|
17
|
+
*/
|
|
18
|
+
export declare function useFloatingNodeId(options: {
|
|
19
|
+
customParentId?: string;
|
|
20
|
+
}): string;
|
|
21
|
+
export interface FloatingTreeProps {
|
|
22
|
+
children?: Snippet;
|
|
23
|
+
}
|
|
24
|
+
interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
|
|
25
|
+
new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
|
|
26
|
+
$$bindings?: Bindings;
|
|
27
|
+
} & Exports;
|
|
28
|
+
(internal: unknown, props: Props & {
|
|
29
|
+
$$events?: Events;
|
|
30
|
+
$$slots?: Slots;
|
|
31
|
+
}): Exports & {
|
|
32
|
+
$set?: any;
|
|
33
|
+
$on?: any;
|
|
34
|
+
};
|
|
35
|
+
z_$$bindings?: Bindings;
|
|
36
|
+
}
|
|
37
|
+
declare const FloatingTree: $$__sveltets_2_IsomorphicComponent<FloatingTreeProps, {
|
|
38
|
+
[evt: string]: CustomEvent<any>;
|
|
39
|
+
}, {}, {}, "">;
|
|
40
|
+
type FloatingTree = InstanceType<typeof FloatingTree>;
|
|
41
|
+
export default FloatingTree;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { ReferenceType, UseFloatingOptions, UseFloatingReturn } from "../types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Provides data to position a floating element and context to add interactions.
|
|
4
|
+
* @see https://floating-ui.com/docs/useFloating
|
|
5
|
+
*/
|
|
6
|
+
export declare function useFloating<RT extends ReferenceType = ReferenceType>(options?: UseFloatingOptions): UseFloatingReturn<RT>;
|