@pzerelles/headlessui-svelte 2.1.2-next.10 → 2.1.2-next.12
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-controllable.svelte.js +2 -1
- 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 +38 -52
- package/dist/listbox/Listbox.svelte.d.ts +3 -54
- package/dist/listbox/ListboxButton.svelte +7 -6
- package/dist/listbox/ListboxOption.svelte +7 -3
- package/dist/listbox/ListboxOptions.svelte +50 -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 +182 -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,13 +196,9 @@ 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
|
-
value: controlledValue,
|
|
201
|
+
value: controlledValue = $bindable(),
|
|
224
202
|
defaultValue,
|
|
225
203
|
form,
|
|
226
204
|
name,
|
|
@@ -240,6 +218,9 @@ const controllable = useControllable(
|
|
|
240
218
|
{
|
|
241
219
|
get controlledValue() {
|
|
242
220
|
return controlledValue;
|
|
221
|
+
},
|
|
222
|
+
set controlledValue(value2) {
|
|
223
|
+
controlledValue = value2;
|
|
243
224
|
}
|
|
244
225
|
},
|
|
245
226
|
controlledOnChange,
|
|
@@ -255,10 +236,10 @@ const _state = stateReducer({
|
|
|
255
236
|
optionsVisible: false,
|
|
256
237
|
__demoMode
|
|
257
238
|
});
|
|
258
|
-
const
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
const
|
|
239
|
+
const optionsProps = $state({ static: false, hold: false });
|
|
240
|
+
let buttonElement = $state(null);
|
|
241
|
+
let optionsElement = $state(null);
|
|
242
|
+
const listElements = new SvelteMap();
|
|
262
243
|
const compare = useByComparator(by);
|
|
263
244
|
const isSelected = (compareValue) => match(data.mode, {
|
|
264
245
|
[ValueMode.Multi]: () => {
|
|
@@ -304,34 +285,39 @@ const data = {
|
|
|
304
285
|
},
|
|
305
286
|
compare,
|
|
306
287
|
isSelected,
|
|
307
|
-
get
|
|
308
|
-
return
|
|
288
|
+
get optionsProps() {
|
|
289
|
+
return optionsProps;
|
|
290
|
+
},
|
|
291
|
+
get buttonElement() {
|
|
292
|
+
return buttonElement;
|
|
293
|
+
},
|
|
294
|
+
set buttonElement(value2) {
|
|
295
|
+
buttonElement = value2;
|
|
309
296
|
},
|
|
310
|
-
get
|
|
311
|
-
return
|
|
297
|
+
get optionsElement() {
|
|
298
|
+
return optionsElement;
|
|
312
299
|
},
|
|
313
|
-
|
|
314
|
-
|
|
300
|
+
set optionsElement(value2) {
|
|
301
|
+
optionsElement = value2;
|
|
315
302
|
},
|
|
316
|
-
get
|
|
317
|
-
return
|
|
303
|
+
get listElements() {
|
|
304
|
+
return listElements;
|
|
318
305
|
}
|
|
319
306
|
};
|
|
320
307
|
setContext("ListboxDataContext", data);
|
|
321
|
-
setContext("ListboxData", data);
|
|
322
308
|
const outsideClickEnabled = $derived(data.listboxState === ListboxStates.Open);
|
|
323
309
|
useOutsideClick({
|
|
324
310
|
get enabled() {
|
|
325
311
|
return outsideClickEnabled;
|
|
326
312
|
},
|
|
327
313
|
get containers() {
|
|
328
|
-
return [data.
|
|
314
|
+
return [data.buttonElement, data.optionsElement];
|
|
329
315
|
},
|
|
330
316
|
cb: (event, target) => {
|
|
331
317
|
_state.closeListbox();
|
|
332
318
|
if (!isFocusableElement(target, FocusableMode.Loose)) {
|
|
333
319
|
event.preventDefault();
|
|
334
|
-
data.
|
|
320
|
+
data.buttonElement?.focus();
|
|
335
321
|
}
|
|
336
322
|
}
|
|
337
323
|
});
|
|
@@ -363,8 +349,8 @@ const goToOption = (focus, id, trigger) => {
|
|
|
363
349
|
});
|
|
364
350
|
};
|
|
365
351
|
const registerOption = (id, dataRef) => {
|
|
366
|
-
_state.registerOption(
|
|
367
|
-
return () => _state.unregisterOption(
|
|
352
|
+
_state.registerOption(id, dataRef);
|
|
353
|
+
return () => _state.unregisterOption(id);
|
|
368
354
|
};
|
|
369
355
|
const onChange = (value2) => {
|
|
370
356
|
return match(data.mode, {
|
|
@@ -394,7 +380,7 @@ setContext("ListboxActionsContext", {
|
|
|
394
380
|
search: _state.search,
|
|
395
381
|
clearSearch: _state.clearSearch
|
|
396
382
|
});
|
|
397
|
-
|
|
383
|
+
useFloatingProvider();
|
|
398
384
|
const openClosed = $derived(
|
|
399
385
|
match(data.listboxState, {
|
|
400
386
|
[ListboxStates.Open]: State.Open,
|
|
@@ -410,7 +396,7 @@ useLabels({
|
|
|
410
396
|
inherit: true,
|
|
411
397
|
props: {
|
|
412
398
|
get htmlFor() {
|
|
413
|
-
return data.
|
|
399
|
+
return data.buttonElement?.id;
|
|
414
400
|
}
|
|
415
401
|
},
|
|
416
402
|
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) ? {
|
|
@@ -99,7 +48,7 @@ declare class __sveltets_Render<TType, TActualType, TTag extends ElementType = t
|
|
|
99
48
|
[evt: string]: CustomEvent<any>;
|
|
100
49
|
};
|
|
101
50
|
slots(): {};
|
|
102
|
-
bindings(): "ref";
|
|
51
|
+
bindings(): "ref" | "value";
|
|
103
52
|
exports(): {};
|
|
104
53
|
}
|
|
105
54
|
interface $$IsomorphicComponent {
|
|
@@ -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,
|
|
@@ -43,11 +43,15 @@ const bag = $derived({
|
|
|
43
43
|
}
|
|
44
44
|
});
|
|
45
45
|
$effect(() => {
|
|
46
|
+
if (usedInSelectedOption) return;
|
|
46
47
|
if (!ref) {
|
|
47
|
-
data.
|
|
48
|
+
data.listElements.delete(id);
|
|
48
49
|
} else {
|
|
49
|
-
data.
|
|
50
|
+
data.listElements.set(id, ref);
|
|
50
51
|
}
|
|
52
|
+
return () => {
|
|
53
|
+
if (ref) data.listElements.delete(id);
|
|
54
|
+
};
|
|
51
55
|
});
|
|
52
56
|
$effect(() => {
|
|
53
57
|
if (data.__demoMode) return;
|
|
@@ -72,7 +76,7 @@ const handleClick = (event) => {
|
|
|
72
76
|
actions.onChange(value);
|
|
73
77
|
if (data.mode === ValueMode.Single) {
|
|
74
78
|
actions.closeListbox();
|
|
75
|
-
data.
|
|
79
|
+
data.buttonElement?.focus({ preventScroll: true });
|
|
76
80
|
}
|
|
77
81
|
};
|
|
78
82
|
const handleFocus = () => {
|