@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
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
import { evaluate, max, min, round } from "@floating-ui/utils";
|
|
2
|
+
import { DEV } from "esm-env";
|
|
3
|
+
import { detectOverflow, offset, } from "@floating-ui/dom";
|
|
4
|
+
import { tick, untrack } from "svelte";
|
|
5
|
+
let devMessageSet;
|
|
6
|
+
if (DEV) {
|
|
7
|
+
devMessageSet = new Set();
|
|
8
|
+
}
|
|
9
|
+
export function warn(...messages) {
|
|
10
|
+
const message = `Floating UI: ${messages.join(" ")}`;
|
|
11
|
+
if (!devMessageSet?.has(message)) {
|
|
12
|
+
devMessageSet?.add(message);
|
|
13
|
+
console.warn(message);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
export function error(...messages) {
|
|
17
|
+
const message = `Floating UI: ${messages.join(" ")}`;
|
|
18
|
+
if (!devMessageSet?.has(message)) {
|
|
19
|
+
devMessageSet?.add(message);
|
|
20
|
+
console.error(message);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
export function getUserAgent() {
|
|
24
|
+
const uaData = navigator.userAgentData;
|
|
25
|
+
if (uaData && Array.isArray(uaData.brands)) {
|
|
26
|
+
return uaData.brands.map(({ brand, version }) => `${brand}/${version}`).join(" ");
|
|
27
|
+
}
|
|
28
|
+
return navigator.userAgent;
|
|
29
|
+
}
|
|
30
|
+
// ------
|
|
31
|
+
function getArgsWithCustomFloatingHeight(state, height) {
|
|
32
|
+
return {
|
|
33
|
+
...state,
|
|
34
|
+
rects: {
|
|
35
|
+
...state.rects,
|
|
36
|
+
floating: {
|
|
37
|
+
...state.rects.floating,
|
|
38
|
+
height,
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Positions the floating element such that an inner element inside of it is
|
|
45
|
+
* anchored to the reference element.
|
|
46
|
+
* @see https://floating-ui.com/docs/inner
|
|
47
|
+
*/
|
|
48
|
+
export const inner = (props) => ({
|
|
49
|
+
name: "inner",
|
|
50
|
+
options: props,
|
|
51
|
+
async fn(state) {
|
|
52
|
+
const { listRef, overflowRef, onFallbackChange, offset: innerOffset = 0, index = 0, minItemsVisible = 4, referenceOverflowThreshold = 0, scrollRef, ...detectOverflowOptions } = evaluate(props, state);
|
|
53
|
+
const { rects, elements: { floating }, } = state;
|
|
54
|
+
const item = listRef.current[index];
|
|
55
|
+
const scrollEl = scrollRef?.current || floating;
|
|
56
|
+
// Valid combinations:
|
|
57
|
+
// 1. Floating element is the scrollRef and has a border (default)
|
|
58
|
+
// 2. Floating element is not the scrollRef, floating element has a border
|
|
59
|
+
// 3. Floating element is not the scrollRef, scrollRef has a border
|
|
60
|
+
// Floating > {...getFloatingProps()} wrapper > scrollRef > items is not
|
|
61
|
+
// allowed as VoiceOver doesn't work.
|
|
62
|
+
const clientTop = floating.clientTop || scrollEl.clientTop;
|
|
63
|
+
const floatingIsBordered = floating.clientTop !== 0;
|
|
64
|
+
const scrollElIsBordered = scrollEl.clientTop !== 0;
|
|
65
|
+
const floatingIsScrollEl = floating === scrollEl;
|
|
66
|
+
if (DEV) {
|
|
67
|
+
if (!state.placement.startsWith("bottom")) {
|
|
68
|
+
warn('`placement` side must be "bottom" when using the `inner`', "middleware.");
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
if (!item) {
|
|
72
|
+
return {};
|
|
73
|
+
}
|
|
74
|
+
const nextArgs = {
|
|
75
|
+
...state,
|
|
76
|
+
...(await offset(-item.offsetTop - floating.clientTop - rects.reference.height / 2 - item.offsetHeight / 2 - innerOffset).fn(state)),
|
|
77
|
+
};
|
|
78
|
+
const overflow = await detectOverflow(getArgsWithCustomFloatingHeight(nextArgs, scrollEl.scrollHeight + clientTop + floating.clientTop), detectOverflowOptions);
|
|
79
|
+
const refOverflow = await detectOverflow(nextArgs, {
|
|
80
|
+
...detectOverflowOptions,
|
|
81
|
+
elementContext: "reference",
|
|
82
|
+
});
|
|
83
|
+
const diffY = max(0, overflow.top);
|
|
84
|
+
const nextY = nextArgs.y + diffY;
|
|
85
|
+
const maxHeight = round(max(0, scrollEl.scrollHeight +
|
|
86
|
+
((floatingIsBordered && floatingIsScrollEl) || scrollElIsBordered ? clientTop * 2 : 0) -
|
|
87
|
+
diffY -
|
|
88
|
+
max(0, overflow.bottom)));
|
|
89
|
+
scrollEl.style.maxHeight = `${maxHeight}px`;
|
|
90
|
+
scrollEl.scrollTop = diffY;
|
|
91
|
+
// There is not enough space, fallback to standard anchored positioning
|
|
92
|
+
if (onFallbackChange) {
|
|
93
|
+
const shouldFallback = (scrollEl.scrollHeight > scrollEl.offsetHeight &&
|
|
94
|
+
scrollEl.offsetHeight < item.offsetHeight * minItemsVisible - 1) ||
|
|
95
|
+
refOverflow.top >= -referenceOverflowThreshold ||
|
|
96
|
+
refOverflow.bottom >= -referenceOverflowThreshold;
|
|
97
|
+
onFallbackChange(shouldFallback);
|
|
98
|
+
await tick();
|
|
99
|
+
}
|
|
100
|
+
if (overflowRef) {
|
|
101
|
+
overflowRef.current = await detectOverflow(getArgsWithCustomFloatingHeight({ ...nextArgs, y: nextY }, scrollEl.offsetHeight + clientTop + floating.clientTop), detectOverflowOptions);
|
|
102
|
+
}
|
|
103
|
+
return {
|
|
104
|
+
y: nextY,
|
|
105
|
+
};
|
|
106
|
+
},
|
|
107
|
+
});
|
|
108
|
+
/**
|
|
109
|
+
* Changes the `inner` middleware's `offset` upon a `wheel` event to
|
|
110
|
+
* expand the floating element's height, revealing more list items.
|
|
111
|
+
* @see https://floating-ui.com/docs/inner
|
|
112
|
+
*/
|
|
113
|
+
export function useInnerOffset(options) {
|
|
114
|
+
const { context, props } = $derived(options);
|
|
115
|
+
const { open, elements } = $derived(context);
|
|
116
|
+
const { enabled = true, overflowRef, scrollRef, onChange: unstable_onChange } = $derived(props);
|
|
117
|
+
const onChange = unstable_onChange;
|
|
118
|
+
let controlledScrollingRef = $state(false);
|
|
119
|
+
let prevScrollTopRef = $state(null);
|
|
120
|
+
let initialOverflowRef = $state(null);
|
|
121
|
+
$effect(() => {
|
|
122
|
+
if (!enabled)
|
|
123
|
+
return;
|
|
124
|
+
[open, elements.floating, overflowRef, scrollRef, onChange];
|
|
125
|
+
untrack(() => {
|
|
126
|
+
function onWheel(e) {
|
|
127
|
+
if (e.ctrlKey || !el || overflowRef.current == null) {
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
const dY = e.deltaY;
|
|
131
|
+
const isAtTop = overflowRef.current.top >= -0.5;
|
|
132
|
+
const isAtBottom = overflowRef.current.bottom >= -0.5;
|
|
133
|
+
const remainingScroll = el.scrollHeight - el.clientHeight;
|
|
134
|
+
const sign = dY < 0 ? -1 : 1;
|
|
135
|
+
const method = dY < 0 ? "max" : "min";
|
|
136
|
+
if (el.scrollHeight <= el.clientHeight) {
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
if ((!isAtTop && dY > 0) || (!isAtBottom && dY < 0)) {
|
|
140
|
+
e.preventDefault();
|
|
141
|
+
onChange((d) => d + Math[method](dY, remainingScroll * sign));
|
|
142
|
+
tick();
|
|
143
|
+
}
|
|
144
|
+
else if (/firefox/i.test(getUserAgent())) {
|
|
145
|
+
// Needed to propagate scrolling during momentum scrolling phase once
|
|
146
|
+
// it gets limited by the boundary. UX improvement, not critical.
|
|
147
|
+
el.scrollTop += dY;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
const el = scrollRef?.current || elements.floating;
|
|
151
|
+
if (open && el) {
|
|
152
|
+
el.addEventListener("wheel", onWheel);
|
|
153
|
+
// Wait for the position to be ready.
|
|
154
|
+
requestAnimationFrame(() => {
|
|
155
|
+
prevScrollTopRef = el.scrollTop;
|
|
156
|
+
if (overflowRef.current != null) {
|
|
157
|
+
initialOverflowRef = { ...overflowRef.current };
|
|
158
|
+
}
|
|
159
|
+
});
|
|
160
|
+
return () => {
|
|
161
|
+
prevScrollTopRef = null;
|
|
162
|
+
initialOverflowRef = null;
|
|
163
|
+
el.removeEventListener("wheel", onWheel);
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
});
|
|
168
|
+
const floating = $derived({
|
|
169
|
+
onKeyDown() {
|
|
170
|
+
controlledScrollingRef = true;
|
|
171
|
+
},
|
|
172
|
+
onWheel() {
|
|
173
|
+
controlledScrollingRef = false;
|
|
174
|
+
},
|
|
175
|
+
onPointerMove() {
|
|
176
|
+
controlledScrollingRef = false;
|
|
177
|
+
},
|
|
178
|
+
async onScroll() {
|
|
179
|
+
const el = scrollRef?.current || elements.floating;
|
|
180
|
+
if (!overflowRef.current || !el || !controlledScrollingRef) {
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
if (prevScrollTopRef !== null) {
|
|
184
|
+
const scrollDiff = el.scrollTop - prevScrollTopRef;
|
|
185
|
+
if ((overflowRef.current.bottom < -0.5 && scrollDiff < -1) ||
|
|
186
|
+
(overflowRef.current.top < -0.5 && scrollDiff > 1)) {
|
|
187
|
+
onChange((d) => d + scrollDiff);
|
|
188
|
+
await tick();
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
// [Firefox] Wait for the height change to have been applied.
|
|
192
|
+
requestAnimationFrame(() => {
|
|
193
|
+
prevScrollTopRef = el.scrollTop;
|
|
194
|
+
});
|
|
195
|
+
},
|
|
196
|
+
});
|
|
197
|
+
return {
|
|
198
|
+
get floating() {
|
|
199
|
+
return enabled ? floating : undefined;
|
|
200
|
+
},
|
|
201
|
+
};
|
|
202
|
+
}
|
|
@@ -4,38 +4,20 @@ import { useDisabled } from "../hooks/use-disabled.js";
|
|
|
4
4
|
import { calculateActiveIndex, Focus } from "../utils/calculate-active-index.js";
|
|
5
5
|
import { FocusableMode, isFocusableElement, sortByDomNode } from "../utils/focus-management.js";
|
|
6
6
|
import { match } from "../utils/match.js";
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import { ActivationTrigger, ListboxStates, ValueMode } from "./ListboxStates.js";
|
|
7
|
+
import { setContext } from "svelte";
|
|
8
|
+
import { ActivationTrigger, ListboxStates, ValueMode } from "./context.svelte.js";
|
|
10
9
|
let DEFAULT_LISTBOX_TAG = "svelte:fragment";
|
|
11
|
-
export * from "./
|
|
12
|
-
export function useActions(component) {
|
|
13
|
-
const context = getContext("ListboxActionsContext");
|
|
14
|
-
if (!context) {
|
|
15
|
-
let err = new Error(`<${component} /> is missing a parent <Listbox /> component.`);
|
|
16
|
-
if (Error.captureStackTrace) Error.captureStackTrace(err, useActions);
|
|
17
|
-
throw err;
|
|
18
|
-
}
|
|
19
|
-
return context;
|
|
20
|
-
}
|
|
21
|
-
export function useData(component) {
|
|
22
|
-
const context = getContext("ListboxData");
|
|
23
|
-
if (context === null) {
|
|
24
|
-
let err = new Error(`<${component} /> is missing a parent <Listbox /> component.`);
|
|
25
|
-
if (Error.captureStackTrace) Error.captureStackTrace(err, useData);
|
|
26
|
-
throw err;
|
|
27
|
-
}
|
|
28
|
-
return context;
|
|
29
|
-
}
|
|
10
|
+
export * from "./context.svelte.js";
|
|
30
11
|
</script>
|
|
31
12
|
|
|
32
13
|
<script lang="ts" generics="TType, TActualType, TTag extends ElementType = typeof DEFAULT_LISTBOX_TAG">import { disposables } from "../utils/disposables.js";
|
|
33
14
|
import FormFields from "../internal/FormFields.svelte";
|
|
34
|
-
import {
|
|
15
|
+
import { useFloatingProvider } from "../internal/floating.svelte.js";
|
|
35
16
|
import { createOpenClosedContext, State } from "../internal/open-closed.js";
|
|
36
17
|
import { useLabels } from "../label/context.svelte.js";
|
|
37
18
|
import { useOutsideClick } from "../hooks/use-outside-click.svelte.js";
|
|
38
19
|
import ElementOrComponent from "../utils/ElementOrComponent.svelte";
|
|
20
|
+
import { SvelteMap } from "svelte/reactivity";
|
|
39
21
|
function adjustOrderedState(state, adjustment = (i) => i) {
|
|
40
22
|
let currentActiveOption = state.activeOptionIndex !== null ? state.options[state.activeOptionIndex] : null;
|
|
41
23
|
let sortedOptions = sortByDomNode(
|
|
@@ -189,11 +171,11 @@ const stateReducer = (initialState) => {
|
|
|
189
171
|
_state2.searchQuery = "";
|
|
190
172
|
return _state2;
|
|
191
173
|
},
|
|
192
|
-
registerOption(
|
|
193
|
-
let option = { id
|
|
174
|
+
registerOption(id, dataRef) {
|
|
175
|
+
let option = { id, dataRef };
|
|
194
176
|
let adjustedState = adjustOrderedState(_state2, (options) => [...options, option]);
|
|
195
177
|
if (_state2.activeOptionIndex === null) {
|
|
196
|
-
if (isSelected(
|
|
178
|
+
if (isSelected(dataRef.current.value)) {
|
|
197
179
|
adjustedState.activeOptionIndex = adjustedState.options.indexOf(option);
|
|
198
180
|
}
|
|
199
181
|
}
|
|
@@ -201,9 +183,9 @@ const stateReducer = (initialState) => {
|
|
|
201
183
|
_state2.activeOptionIndex = adjustedState.activeOptionIndex;
|
|
202
184
|
return _state2;
|
|
203
185
|
},
|
|
204
|
-
unregisterOption(
|
|
186
|
+
unregisterOption(id) {
|
|
205
187
|
let adjustedState = adjustOrderedState(_state2, (options) => {
|
|
206
|
-
let idx = options.findIndex((a) => a.id ===
|
|
188
|
+
let idx = options.findIndex((a) => a.id === id);
|
|
207
189
|
if (idx !== -1) options.splice(idx, 1);
|
|
208
190
|
return options;
|
|
209
191
|
});
|
|
@@ -214,10 +196,6 @@ const stateReducer = (initialState) => {
|
|
|
214
196
|
}
|
|
215
197
|
};
|
|
216
198
|
};
|
|
217
|
-
const listboxActionsContext = null;
|
|
218
|
-
setContext("ListboxActionsContext", listboxActionsContext);
|
|
219
|
-
const listboxDataContext = null;
|
|
220
|
-
setContext("ListboxDataContext", listboxDataContext);
|
|
221
199
|
let {
|
|
222
200
|
ref = $bindable(),
|
|
223
201
|
value: controlledValue,
|
|
@@ -255,10 +233,10 @@ const _state = stateReducer({
|
|
|
255
233
|
optionsVisible: false,
|
|
256
234
|
__demoMode
|
|
257
235
|
});
|
|
258
|
-
const
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
const
|
|
236
|
+
const optionsProps = $state({ static: false, hold: false });
|
|
237
|
+
let buttonElement = $state(null);
|
|
238
|
+
let optionsElement = $state(null);
|
|
239
|
+
const listElements = new SvelteMap();
|
|
262
240
|
const compare = useByComparator(by);
|
|
263
241
|
const isSelected = (compareValue) => match(data.mode, {
|
|
264
242
|
[ValueMode.Multi]: () => {
|
|
@@ -304,34 +282,39 @@ const data = {
|
|
|
304
282
|
},
|
|
305
283
|
compare,
|
|
306
284
|
isSelected,
|
|
307
|
-
get
|
|
308
|
-
return
|
|
285
|
+
get optionsProps() {
|
|
286
|
+
return optionsProps;
|
|
287
|
+
},
|
|
288
|
+
get buttonElement() {
|
|
289
|
+
return buttonElement;
|
|
290
|
+
},
|
|
291
|
+
set buttonElement(value2) {
|
|
292
|
+
buttonElement = value2;
|
|
309
293
|
},
|
|
310
|
-
get
|
|
311
|
-
return
|
|
294
|
+
get optionsElement() {
|
|
295
|
+
return optionsElement;
|
|
312
296
|
},
|
|
313
|
-
|
|
314
|
-
|
|
297
|
+
set optionsElement(value2) {
|
|
298
|
+
optionsElement = value2;
|
|
315
299
|
},
|
|
316
|
-
get
|
|
317
|
-
return
|
|
300
|
+
get listElements() {
|
|
301
|
+
return listElements;
|
|
318
302
|
}
|
|
319
303
|
};
|
|
320
304
|
setContext("ListboxDataContext", data);
|
|
321
|
-
setContext("ListboxData", data);
|
|
322
305
|
const outsideClickEnabled = $derived(data.listboxState === ListboxStates.Open);
|
|
323
306
|
useOutsideClick({
|
|
324
307
|
get enabled() {
|
|
325
308
|
return outsideClickEnabled;
|
|
326
309
|
},
|
|
327
310
|
get containers() {
|
|
328
|
-
return [data.
|
|
311
|
+
return [data.buttonElement, data.optionsElement];
|
|
329
312
|
},
|
|
330
313
|
cb: (event, target) => {
|
|
331
314
|
_state.closeListbox();
|
|
332
315
|
if (!isFocusableElement(target, FocusableMode.Loose)) {
|
|
333
316
|
event.preventDefault();
|
|
334
|
-
data.
|
|
317
|
+
data.buttonElement?.focus();
|
|
335
318
|
}
|
|
336
319
|
}
|
|
337
320
|
});
|
|
@@ -363,8 +346,8 @@ const goToOption = (focus, id, trigger) => {
|
|
|
363
346
|
});
|
|
364
347
|
};
|
|
365
348
|
const registerOption = (id, dataRef) => {
|
|
366
|
-
_state.registerOption(
|
|
367
|
-
return () => _state.unregisterOption(
|
|
349
|
+
_state.registerOption(id, dataRef);
|
|
350
|
+
return () => _state.unregisterOption(id);
|
|
368
351
|
};
|
|
369
352
|
const onChange = (value2) => {
|
|
370
353
|
return match(data.mode, {
|
|
@@ -394,7 +377,7 @@ setContext("ListboxActionsContext", {
|
|
|
394
377
|
search: _state.search,
|
|
395
378
|
clearSearch: _state.clearSearch
|
|
396
379
|
});
|
|
397
|
-
|
|
380
|
+
useFloatingProvider();
|
|
398
381
|
const openClosed = $derived(
|
|
399
382
|
match(data.listboxState, {
|
|
400
383
|
[ListboxStates.Open]: State.Open,
|
|
@@ -410,7 +393,7 @@ useLabels({
|
|
|
410
393
|
inherit: true,
|
|
411
394
|
props: {
|
|
412
395
|
get htmlFor() {
|
|
413
|
-
return data.
|
|
396
|
+
return data.buttonElement?.id;
|
|
414
397
|
}
|
|
415
398
|
},
|
|
416
399
|
slot: {
|
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
import { type ByComparator } from "../hooks/use-by-comparator.js";
|
|
2
|
-
import { Focus } from "../utils/calculate-active-index.js";
|
|
3
|
-
import { type MutableRefObject } from "../utils/ref.svelte.js";
|
|
4
2
|
import type { ElementType, Props } from "../utils/types.js";
|
|
5
3
|
import { type Snippet } from "svelte";
|
|
6
|
-
import { ActivationTrigger, ListboxStates, ValueMode } from "./ListboxStates.js";
|
|
7
4
|
declare let DEFAULT_LISTBOX_TAG: string;
|
|
8
5
|
type ListboxRenderPropArg<T> = {
|
|
9
6
|
open: boolean;
|
|
@@ -25,59 +22,11 @@ export type ListboxProps<TTag extends ElementType = typeof DEFAULT_LISTBOX_TAG,
|
|
|
25
22
|
__demoMode?: boolean;
|
|
26
23
|
}>;
|
|
27
24
|
export type ListboxChildren<T> = Snippet<[ListboxRenderPropArg<T>]>;
|
|
28
|
-
export * from "./
|
|
29
|
-
export type ListboxOptionDataRef<T> = MutableRefObject<{
|
|
30
|
-
textValue?: string;
|
|
31
|
-
disabled: boolean;
|
|
32
|
-
value: T;
|
|
33
|
-
domRef: MutableRefObject<HTMLElement | null>;
|
|
34
|
-
}>;
|
|
35
|
-
interface StateDefinition<T> {
|
|
36
|
-
listboxState: ListboxStates;
|
|
37
|
-
options: {
|
|
38
|
-
id: string;
|
|
39
|
-
dataRef: ListboxOptionDataRef<T>;
|
|
40
|
-
}[];
|
|
41
|
-
searchQuery: string;
|
|
42
|
-
activeOptionIndex: number | null;
|
|
43
|
-
activationTrigger: ActivationTrigger;
|
|
44
|
-
__demoMode: boolean;
|
|
45
|
-
}
|
|
46
|
-
type ListboxActionsContext = {
|
|
47
|
-
openListbox(): void;
|
|
48
|
-
closeListbox(): void;
|
|
49
|
-
registerOption(id: string, dataRef: ListboxOptionDataRef<unknown>): () => void;
|
|
50
|
-
goToOption(focus: Focus.Specific, id: string, trigger?: ActivationTrigger): void;
|
|
51
|
-
goToOption(focus: Focus, id?: string, trigger?: ActivationTrigger): void;
|
|
52
|
-
selectOption(id: string): void;
|
|
53
|
-
selectActiveOption(): void;
|
|
54
|
-
onChange(value: unknown): void;
|
|
55
|
-
search(query: string): void;
|
|
56
|
-
clearSearch(): void;
|
|
57
|
-
};
|
|
58
|
-
export declare function useActions(component: string): ListboxActionsContext;
|
|
59
|
-
export type ListboxDataContext = {
|
|
60
|
-
value: unknown;
|
|
61
|
-
disabled: boolean;
|
|
62
|
-
invalid: boolean;
|
|
63
|
-
mode: ValueMode;
|
|
64
|
-
orientation: "horizontal" | "vertical";
|
|
65
|
-
activeOptionIndex: number | null;
|
|
66
|
-
compare(a: unknown, z: unknown): boolean;
|
|
67
|
-
isSelected(value: unknown): boolean;
|
|
68
|
-
optionsPropsRef: MutableRefObject<{
|
|
69
|
-
static: boolean;
|
|
70
|
-
hold: boolean;
|
|
71
|
-
}>;
|
|
72
|
-
listRef: MutableRefObject<Map<string, HTMLElement | null>>;
|
|
73
|
-
buttonRef: MutableRefObject<HTMLElement | null>;
|
|
74
|
-
optionsRef: MutableRefObject<HTMLElement | null>;
|
|
75
|
-
} & Omit<StateDefinition<unknown>, "dataRef">;
|
|
76
|
-
export declare function useData(component: string): ListboxDataContext;
|
|
25
|
+
export * from "./context.svelte.js";
|
|
77
26
|
declare class __sveltets_Render<TType, TActualType, TTag extends ElementType = typeof DEFAULT_LISTBOX_TAG> {
|
|
78
27
|
props(): {
|
|
79
28
|
as?: TTag | undefined;
|
|
80
|
-
} & (Exclude<keyof import("../utils/types.js").PropsOf<TTag>, "form" | ("as" | "children" | "refName" | "class") | "invalid" | "disabled" | "name" | "value" | "onchange" | "multiple" | "__demoMode" | "
|
|
29
|
+
} & (Exclude<keyof import("../utils/types.js").PropsOf<TTag>, "form" | ("as" | "children" | "refName" | "class") | "invalid" | "disabled" | "name" | "value" | "onchange" | "multiple" | "__demoMode" | "horizontal" | "defaultValue" | "by"> extends infer T extends keyof import("../utils/types.js").PropsOf<TTag> ? { [P in T]: import("../utils/types.js").PropsOf<TTag>[P]; } : never) & {
|
|
81
30
|
children?: import("../utils/types.js").Children<ListboxRenderPropArg<TType>> | undefined;
|
|
82
31
|
ref?: HTMLElement;
|
|
83
32
|
} & (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) ? {
|
|
@@ -6,7 +6,7 @@ import { Focus } from "../utils/calculate-active-index.js";
|
|
|
6
6
|
import { useFocusRing } from "../hooks/use-focus-ring.svelte.js";
|
|
7
7
|
import { useActivePress } from "../hooks/use-active-press.svelte.js";
|
|
8
8
|
import { useResolveButtonType } from "../hooks/use-resolve-button-type.svelte.js";
|
|
9
|
-
import {
|
|
9
|
+
import { useFloatingReference, useFloatingReferenceProps } from "../internal/floating.svelte.js";
|
|
10
10
|
import { stateFromSlot } from "../utils/state.js";
|
|
11
11
|
import { useLabelledBy } from "../label/context.svelte.js";
|
|
12
12
|
import { useDescribedBy } from "../description/context.svelte.js";
|
|
@@ -27,9 +27,10 @@ let {
|
|
|
27
27
|
autofocus = false,
|
|
28
28
|
...theirProps
|
|
29
29
|
} = $props();
|
|
30
|
-
const { setReference
|
|
30
|
+
const { setReference } = useFloatingReference();
|
|
31
|
+
const { getReferenceProps: getFloatingReferenceProps } = useFloatingReferenceProps();
|
|
31
32
|
$effect(() => {
|
|
32
|
-
data.
|
|
33
|
+
data.buttonElement = ref || null;
|
|
33
34
|
setReference(ref);
|
|
34
35
|
});
|
|
35
36
|
const disabled = $derived(data.disabled || ownDisabled);
|
|
@@ -61,7 +62,7 @@ const handleKeyUp = (event) => {
|
|
|
61
62
|
const handleClick = (event) => {
|
|
62
63
|
if (data.listboxState === ListboxStates.Open) {
|
|
63
64
|
actions.closeListbox();
|
|
64
|
-
data.
|
|
65
|
+
data.buttonElement?.focus({ preventScroll: true });
|
|
65
66
|
} else {
|
|
66
67
|
event.preventDefault();
|
|
67
68
|
actions.openListbox();
|
|
@@ -106,7 +107,7 @@ const buttonType = useResolveButtonType({
|
|
|
106
107
|
return { type: theirProps.type, as: theirProps.as };
|
|
107
108
|
},
|
|
108
109
|
get ref() {
|
|
109
|
-
return data.
|
|
110
|
+
return { current: data.buttonElement };
|
|
110
111
|
}
|
|
111
112
|
});
|
|
112
113
|
const ourProps = $derived(
|
|
@@ -116,7 +117,7 @@ const ourProps = $derived(
|
|
|
116
117
|
id,
|
|
117
118
|
type: buttonType.type,
|
|
118
119
|
"aria-haspopup": "listbox",
|
|
119
|
-
"aria-controls": data.
|
|
120
|
+
"aria-controls": data.optionsElement?.id,
|
|
120
121
|
"aria-expanded": data.listboxState === ListboxStates.Open,
|
|
121
122
|
"aria-labelledby": labelledBy.value,
|
|
122
123
|
"aria-describedby": describedBy.value,
|
|
@@ -44,10 +44,13 @@ const bag = $derived({
|
|
|
44
44
|
});
|
|
45
45
|
$effect(() => {
|
|
46
46
|
if (!ref) {
|
|
47
|
-
data.
|
|
47
|
+
data.listElements.delete(id);
|
|
48
48
|
} else {
|
|
49
|
-
data.
|
|
49
|
+
data.listElements.set(id, ref);
|
|
50
50
|
}
|
|
51
|
+
return () => {
|
|
52
|
+
if (ref) data.listElements.delete(id);
|
|
53
|
+
};
|
|
51
54
|
});
|
|
52
55
|
$effect(() => {
|
|
53
56
|
if (data.__demoMode) return;
|
|
@@ -72,7 +75,7 @@ const handleClick = (event) => {
|
|
|
72
75
|
actions.onChange(value);
|
|
73
76
|
if (data.mode === ValueMode.Single) {
|
|
74
77
|
actions.closeListbox();
|
|
75
|
-
data.
|
|
78
|
+
data.buttonElement?.focus({ preventScroll: true });
|
|
76
79
|
}
|
|
77
80
|
};
|
|
78
81
|
const handleFocus = () => {
|