@pzerelles/headlessui-svelte 2.1.2-next.7 → 2.1.2-next.8
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 -174
- package/dist/close-button/CloseButton.svelte +6 -12
- package/dist/combobox/Combobox.svelte +3 -50
- package/dist/data-interactive/DataInteractive.svelte +29 -57
- package/dist/description/Description.svelte +21 -32
- package/dist/dialog/Dialog.svelte +34 -69
- package/dist/dialog/DialogBackdrop.svelte +12 -29
- package/dist/dialog/DialogPanel.svelte +26 -49
- package/dist/dialog/DialogTitle.svelte +23 -38
- package/dist/dialog/InternalDialog.svelte +202 -263
- package/dist/field/Field.svelte +26 -49
- 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/FocusSentinel.svelte +8 -16
- package/dist/internal/ForcePortalRoot.svelte +3 -7
- package/dist/internal/FormFields.svelte +20 -31
- package/dist/internal/FormResolver.svelte +15 -20
- package/dist/internal/Hidden.svelte +23 -44
- package/dist/internal/HoistFormFields.svelte +4 -7
- package/dist/internal/MainTreeProvider.svelte +36 -89
- package/dist/internal/Portal.svelte +14 -18
- package/dist/label/Label.svelte +57 -91
- package/dist/legend/Legend.svelte +3 -18
- package/dist/listbox/Listbox.svelte +396 -588
- package/dist/listbox/ListboxButton.svelte +127 -176
- package/dist/listbox/ListboxOption.svelte +125 -166
- package/dist/listbox/ListboxOptions.svelte +244 -340
- package/dist/listbox/ListboxSelectedOption.svelte +15 -38
- package/dist/menu/Menu.svelte +218 -307
- package/dist/menu/MenuButton.svelte +115 -157
- package/dist/menu/MenuHeading.svelte +14 -34
- package/dist/menu/MenuItem.svelte +107 -145
- package/dist/menu/MenuItems.svelte +224 -298
- package/dist/menu/MenuSection.svelte +9 -26
- package/dist/menu/MenuSeparator.svelte +4 -20
- package/dist/portal/InternalPortal.svelte +85 -141
- package/dist/portal/Portal.svelte +2 -5
- package/dist/portal/PortalGroup.svelte +9 -30
- package/dist/switch/Switch.svelte +132 -179
- package/dist/switch/SwitchGroup.svelte +31 -44
- package/dist/tabs/Tab.svelte +143 -195
- package/dist/tabs/TabGroup.svelte +205 -292
- package/dist/tabs/TabList.svelte +11 -31
- package/dist/tabs/TabPanel.svelte +43 -68
- 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/ElementOrComponent.svelte +23 -44
- package/dist/utils/Generic.svelte +17 -29
- package/dist/utils/StableCollection.svelte +36 -54
- package/package.json +1 -1
|
@@ -1,624 +1,432 @@
|
|
|
1
|
-
<script lang="ts" module>
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
value: T
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export type ListboxProps<
|
|
22
|
-
TTag extends ElementType = typeof DEFAULT_LISTBOX_TAG,
|
|
23
|
-
TType = string,
|
|
24
|
-
TActualType = TType extends (infer U)[] ? U : TType,
|
|
25
|
-
> = Props<
|
|
26
|
-
TTag,
|
|
27
|
-
ListboxRenderPropArg<TType>,
|
|
28
|
-
"value" | "defaultValue" | "onchange" | "by" | "disabled" | "horizontal" | "name" | "multiple",
|
|
29
|
-
{
|
|
30
|
-
value?: TType
|
|
31
|
-
defaultValue?: TType
|
|
32
|
-
onchange?: (value: TType) => void
|
|
33
|
-
by?: ByComparator<TActualType>
|
|
34
|
-
disabled?: boolean
|
|
35
|
-
invalid?: boolean
|
|
36
|
-
horizontal?: boolean
|
|
37
|
-
form?: string
|
|
38
|
-
name?: string
|
|
39
|
-
multiple?: boolean
|
|
40
|
-
|
|
41
|
-
__demoMode?: boolean
|
|
42
|
-
}
|
|
43
|
-
>
|
|
44
|
-
|
|
45
|
-
export type ListboxChildren<T> = Snippet<[ListboxRenderPropArg<T>]>
|
|
46
|
-
|
|
47
|
-
export * from "./ListboxStates.js"
|
|
48
|
-
|
|
49
|
-
export type ListboxOptionDataRef<T> = MutableRefObject<{
|
|
50
|
-
textValue?: string
|
|
51
|
-
disabled: boolean
|
|
52
|
-
value: T
|
|
53
|
-
domRef: MutableRefObject<HTMLElement | null>
|
|
54
|
-
}>
|
|
55
|
-
|
|
56
|
-
interface StateDefinition<T> {
|
|
57
|
-
listboxState: ListboxStates
|
|
58
|
-
|
|
59
|
-
options: { id: string; dataRef: ListboxOptionDataRef<T> }[]
|
|
60
|
-
searchQuery: string
|
|
61
|
-
activeOptionIndex: number | null
|
|
62
|
-
activationTrigger: ActivationTrigger
|
|
63
|
-
|
|
64
|
-
__demoMode: boolean
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
type ListboxActionsContext = {
|
|
68
|
-
openListbox(): void
|
|
69
|
-
closeListbox(): void
|
|
70
|
-
registerOption(id: string, dataRef: ListboxOptionDataRef<unknown>): () => void
|
|
71
|
-
goToOption(focus: Focus.Specific, id: string, trigger?: ActivationTrigger): void
|
|
72
|
-
goToOption(focus: Focus, id?: string, trigger?: ActivationTrigger): void
|
|
73
|
-
selectOption(id: string): void
|
|
74
|
-
selectActiveOption(): void
|
|
75
|
-
onChange(value: unknown): void
|
|
76
|
-
search(query: string): void
|
|
77
|
-
clearSearch(): void
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
export function useActions(component: string) {
|
|
81
|
-
const context = getContext<ListboxActionsContext>("ListboxActionsContext")
|
|
82
|
-
if (!context) {
|
|
83
|
-
let err = new Error(`<${component} /> is missing a parent <Listbox /> component.`)
|
|
84
|
-
if (Error.captureStackTrace) Error.captureStackTrace(err, useActions)
|
|
85
|
-
throw err
|
|
86
|
-
}
|
|
87
|
-
return context
|
|
1
|
+
<script lang="ts" module>import { useByComparator } from "../hooks/use-by-comparator.js";
|
|
2
|
+
import { useControllable } from "../hooks/use-controllable.svelte.js";
|
|
3
|
+
import { useDisabled } from "../hooks/use-disabled.js";
|
|
4
|
+
import { calculateActiveIndex, Focus } from "../utils/calculate-active-index.js";
|
|
5
|
+
import { FocusableMode, isFocusableElement, sortByDomNode } from "../utils/focus-management.js";
|
|
6
|
+
import { match } from "../utils/match.js";
|
|
7
|
+
import { useRef } from "../utils/ref.svelte.js";
|
|
8
|
+
import { getContext, setContext } from "svelte";
|
|
9
|
+
import { ActivationTrigger, ListboxStates, ValueMode } from "./ListboxStates.js";
|
|
10
|
+
let DEFAULT_LISTBOX_TAG = "svelte:fragment";
|
|
11
|
+
export * from "./ListboxStates.js";
|
|
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;
|
|
88
18
|
}
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
compare(a: unknown, z: unknown): boolean
|
|
98
|
-
isSelected(value: unknown): boolean
|
|
99
|
-
|
|
100
|
-
optionsPropsRef: MutableRefObject<{
|
|
101
|
-
static: boolean
|
|
102
|
-
hold: boolean
|
|
103
|
-
}>
|
|
104
|
-
|
|
105
|
-
listRef: MutableRefObject<Map<string, HTMLElement | null>>
|
|
106
|
-
|
|
107
|
-
buttonRef: MutableRefObject<HTMLElement | null>
|
|
108
|
-
optionsRef: MutableRefObject<HTMLElement | null>
|
|
109
|
-
} & Omit<StateDefinition<unknown>, "dataRef">
|
|
110
|
-
|
|
111
|
-
export function useData(component: string) {
|
|
112
|
-
const context = getContext<ListboxDataContext>("ListboxData")
|
|
113
|
-
if (context === null) {
|
|
114
|
-
let err = new Error(`<${component} /> is missing a parent <Listbox /> component.`)
|
|
115
|
-
if (Error.captureStackTrace) Error.captureStackTrace(err, useData)
|
|
116
|
-
throw err
|
|
117
|
-
}
|
|
118
|
-
return context
|
|
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;
|
|
119
27
|
}
|
|
28
|
+
return context;
|
|
29
|
+
}
|
|
120
30
|
</script>
|
|
121
31
|
|
|
122
|
-
<script lang="ts" generics="TType, TActualType, TTag extends ElementType = typeof DEFAULT_LISTBOX_TAG">
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
state
|
|
133
|
-
|
|
134
|
-
)
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
adjustment(state.options.slice()),
|
|
139
|
-
(option) => option.dataRef.current.domRef.current
|
|
140
|
-
)
|
|
141
|
-
|
|
142
|
-
// If we inserted an option before the current active option then the active option index
|
|
143
|
-
// would be wrong. To fix this, we will re-lookup the correct index.
|
|
144
|
-
let adjustedActiveOptionIndex = currentActiveOption ? sortedOptions.indexOf(currentActiveOption) : null
|
|
145
|
-
|
|
146
|
-
// Reset to `null` in case the currentActiveOption was removed.
|
|
147
|
-
if (adjustedActiveOptionIndex === -1) {
|
|
148
|
-
adjustedActiveOptionIndex = null
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
return {
|
|
152
|
-
options: sortedOptions,
|
|
153
|
-
activeOptionIndex: adjustedActiveOptionIndex,
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
const stateReducer = (initialState: StateDefinition<TActualType>) => {
|
|
158
|
-
let _state = $state(initialState)
|
|
159
|
-
return {
|
|
160
|
-
get listboxState() {
|
|
161
|
-
return _state.listboxState
|
|
162
|
-
},
|
|
163
|
-
get options() {
|
|
164
|
-
return _state.options
|
|
165
|
-
},
|
|
166
|
-
get searchQuery() {
|
|
167
|
-
return _state.searchQuery
|
|
168
|
-
},
|
|
169
|
-
get activeOptionIndex() {
|
|
170
|
-
return _state.activeOptionIndex
|
|
171
|
-
},
|
|
172
|
-
get activationTrigger() {
|
|
173
|
-
return _state.activationTrigger
|
|
174
|
-
},
|
|
175
|
-
get __demoMode() {
|
|
176
|
-
return _state.__demoMode
|
|
177
|
-
},
|
|
178
|
-
closeListbox() {
|
|
179
|
-
if (disabled) return _state
|
|
180
|
-
if (_state.listboxState === ListboxStates.Closed) return _state
|
|
181
|
-
_state.activeOptionIndex = null
|
|
182
|
-
_state.listboxState = ListboxStates.Closed
|
|
183
|
-
_state.__demoMode = false
|
|
184
|
-
return _state
|
|
185
|
-
},
|
|
186
|
-
openListbox() {
|
|
187
|
-
if (disabled) return _state
|
|
188
|
-
if (_state.listboxState === ListboxStates.Open) return _state
|
|
189
|
-
|
|
190
|
-
// Check if we have a selected value that we can make active
|
|
191
|
-
let activeOptionIndex = _state.activeOptionIndex
|
|
192
|
-
let optionIdx = _state.options.findIndex((option) => isSelected(option.dataRef.current.value))
|
|
193
|
-
|
|
194
|
-
if (optionIdx !== -1) {
|
|
195
|
-
activeOptionIndex = optionIdx
|
|
196
|
-
}
|
|
197
|
-
_state.listboxState = ListboxStates.Open
|
|
198
|
-
_state.activeOptionIndex = activeOptionIndex
|
|
199
|
-
_state.__demoMode = false
|
|
200
|
-
return _state
|
|
201
|
-
},
|
|
202
|
-
goToOption(
|
|
203
|
-
action:
|
|
204
|
-
| { focus: Focus.Specific; id: string; trigger?: ActivationTrigger }
|
|
205
|
-
| { focus: Exclude<Focus, Focus.Specific>; trigger?: ActivationTrigger }
|
|
206
|
-
) {
|
|
207
|
-
if (disabled) return _state
|
|
208
|
-
if (_state.listboxState === ListboxStates.Closed) return _state
|
|
209
|
-
|
|
210
|
-
_state.searchQuery = ""
|
|
211
|
-
_state.activationTrigger = action.trigger ?? ActivationTrigger.Other
|
|
212
|
-
_state.__demoMode = false
|
|
213
|
-
|
|
214
|
-
// Optimization:
|
|
215
|
-
//
|
|
216
|
-
// There is no need to sort the DOM nodes if we know that we don't want to focus anything
|
|
217
|
-
if (action.focus === Focus.Nothing) {
|
|
218
|
-
_state.activeOptionIndex = null
|
|
219
|
-
return _state
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
// Optimization:
|
|
223
|
-
//
|
|
224
|
-
// There is no need to sort the DOM nodes if we know exactly where to go
|
|
225
|
-
if (action.focus === Focus.Specific) {
|
|
226
|
-
_state.activeOptionIndex = _state.options.findIndex((o) => o.id === action.id)
|
|
227
|
-
return _state
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
// Optimization:
|
|
231
|
-
//
|
|
232
|
-
// If the current DOM node and the previous DOM node are next to each other,
|
|
233
|
-
// or if the previous DOM node is already the first DOM node, then we don't
|
|
234
|
-
// have to sort all the DOM nodes.
|
|
235
|
-
else if (action.focus === Focus.Previous) {
|
|
236
|
-
let activeOptionIdx = _state.activeOptionIndex
|
|
237
|
-
if (activeOptionIdx !== null) {
|
|
238
|
-
let currentDom = _state.options[activeOptionIdx].dataRef.current.domRef
|
|
239
|
-
let previousOptionIndex = calculateActiveIndex(action, {
|
|
240
|
-
resolveItems: () => _state.options,
|
|
241
|
-
resolveActiveIndex: () => _state.activeOptionIndex,
|
|
242
|
-
resolveId: (option) => option.id,
|
|
243
|
-
resolveDisabled: (option) => option.dataRef.current.disabled ?? false,
|
|
244
|
-
})
|
|
245
|
-
if (previousOptionIndex !== null) {
|
|
246
|
-
let previousDom = _state.options[previousOptionIndex].dataRef.current.domRef
|
|
247
|
-
if (
|
|
248
|
-
// Next to each other
|
|
249
|
-
currentDom.current?.previousElementSibling === previousDom?.current ||
|
|
250
|
-
// Or already the first element
|
|
251
|
-
previousDom.current?.previousElementSibling === null
|
|
252
|
-
) {
|
|
253
|
-
_state.activeOptionIndex = previousOptionIndex
|
|
254
|
-
return _state
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
// Optimization:
|
|
261
|
-
//
|
|
262
|
-
// If the current DOM node and the next DOM node are next to each other, or
|
|
263
|
-
// if the next DOM node is already the last DOM node, then we don't have to
|
|
264
|
-
// sort all the DOM nodes.
|
|
265
|
-
else if (action.focus === Focus.Next) {
|
|
266
|
-
let activeOptionIdx = _state.activeOptionIndex
|
|
267
|
-
if (activeOptionIdx !== null) {
|
|
268
|
-
let currentDom = _state.options[activeOptionIdx].dataRef.current.domRef
|
|
269
|
-
let nextOptionIndex = calculateActiveIndex(action, {
|
|
270
|
-
resolveItems: () => _state.options,
|
|
271
|
-
resolveActiveIndex: () => _state.activeOptionIndex,
|
|
272
|
-
resolveId: (option) => option.id,
|
|
273
|
-
resolveDisabled: (option) => option.dataRef.current.disabled ?? false,
|
|
274
|
-
})
|
|
275
|
-
if (nextOptionIndex !== null) {
|
|
276
|
-
let nextDom = _state.options[nextOptionIndex].dataRef.current.domRef
|
|
277
|
-
if (
|
|
278
|
-
// Next to each other
|
|
279
|
-
currentDom.current?.nextElementSibling === nextDom.current ||
|
|
280
|
-
// Or already the last element
|
|
281
|
-
nextDom.current?.nextElementSibling === null
|
|
282
|
-
) {
|
|
283
|
-
_state.activeOptionIndex = nextOptionIndex
|
|
284
|
-
return _state
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
// Slow path:
|
|
291
|
-
//
|
|
292
|
-
// Ensure all the options are correctly sorted according to DOM position
|
|
293
|
-
let adjustedState = adjustOrderedState(_state)
|
|
294
|
-
let activeOptionIndex = calculateActiveIndex(action, {
|
|
295
|
-
resolveItems: () => adjustedState.options,
|
|
296
|
-
resolveActiveIndex: () => adjustedState.activeOptionIndex,
|
|
297
|
-
resolveId: (option) => option.id,
|
|
298
|
-
resolveDisabled: (option) => option.dataRef.current.disabled ?? false,
|
|
299
|
-
})
|
|
300
|
-
|
|
301
|
-
_state.options = adjustedState.options
|
|
302
|
-
_state.activeOptionIndex = activeOptionIndex
|
|
303
|
-
return _state
|
|
304
|
-
},
|
|
305
|
-
search(value: string) {
|
|
306
|
-
if (disabled) return _state
|
|
307
|
-
if (_state.listboxState === ListboxStates.Closed) return _state
|
|
308
|
-
|
|
309
|
-
let wasAlreadySearching = _state.searchQuery !== ""
|
|
310
|
-
let offset = wasAlreadySearching ? 0 : 1
|
|
311
|
-
|
|
312
|
-
let searchQuery = _state.searchQuery + value.toLowerCase()
|
|
313
|
-
|
|
314
|
-
let reOrderedOptions =
|
|
315
|
-
_state.activeOptionIndex !== null
|
|
316
|
-
? _state.options
|
|
317
|
-
.slice(_state.activeOptionIndex + offset)
|
|
318
|
-
.concat(_state.options.slice(0, _state.activeOptionIndex + offset))
|
|
319
|
-
: _state.options
|
|
320
|
-
|
|
321
|
-
let matchingOption = reOrderedOptions.find(
|
|
322
|
-
(option) => !option.dataRef.current.disabled && option.dataRef.current.textValue?.startsWith(searchQuery)
|
|
323
|
-
)
|
|
324
|
-
|
|
325
|
-
let matchIdx = matchingOption ? _state.options.indexOf(matchingOption) : -1
|
|
326
|
-
|
|
327
|
-
if (matchIdx === -1 || matchIdx === _state.activeOptionIndex) {
|
|
328
|
-
_state.searchQuery = searchQuery
|
|
329
|
-
} else {
|
|
330
|
-
_state.searchQuery = searchQuery
|
|
331
|
-
_state.activeOptionIndex = matchIdx
|
|
332
|
-
_state.activationTrigger = ActivationTrigger.Other
|
|
333
|
-
}
|
|
334
|
-
return _state
|
|
335
|
-
},
|
|
336
|
-
clearSearch() {
|
|
337
|
-
if (disabled) return _state
|
|
338
|
-
if (_state.listboxState === ListboxStates.Closed) return _state
|
|
339
|
-
if (_state.searchQuery === "") return _state
|
|
340
|
-
_state.searchQuery = ""
|
|
341
|
-
return _state
|
|
342
|
-
},
|
|
343
|
-
registerOption(action: { id: string; dataRef: ListboxOptionDataRef<TActualType> }) {
|
|
344
|
-
let option = { id: action.id, dataRef: action.dataRef }
|
|
345
|
-
let adjustedState = adjustOrderedState(_state, (options) => [...options, option])
|
|
346
|
-
|
|
347
|
-
// Check if we need to make the newly registered option active.
|
|
348
|
-
if (_state.activeOptionIndex === null) {
|
|
349
|
-
if (isSelected(action.dataRef.current.value as any)) {
|
|
350
|
-
adjustedState.activeOptionIndex = adjustedState.options.indexOf(option)
|
|
351
|
-
}
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
_state.options = adjustedState.options
|
|
355
|
-
_state.activeOptionIndex = adjustedState.activeOptionIndex
|
|
356
|
-
return _state
|
|
357
|
-
},
|
|
358
|
-
unregisterOption(action: { id: string }) {
|
|
359
|
-
let adjustedState = adjustOrderedState(_state, (options) => {
|
|
360
|
-
let idx = options.findIndex((a) => a.id === action.id)
|
|
361
|
-
if (idx !== -1) options.splice(idx, 1)
|
|
362
|
-
return options
|
|
363
|
-
})
|
|
364
|
-
|
|
365
|
-
_state.options = adjustedState.options
|
|
366
|
-
_state.activeOptionIndex = adjustedState.activeOptionIndex
|
|
367
|
-
_state.activationTrigger = ActivationTrigger.Other
|
|
368
|
-
return _state
|
|
369
|
-
},
|
|
370
|
-
}
|
|
32
|
+
<script lang="ts" generics="TType, TActualType, TTag extends ElementType = typeof DEFAULT_LISTBOX_TAG">import { disposables } from "../utils/disposables.js";
|
|
33
|
+
import FormFields from "../internal/FormFields.svelte";
|
|
34
|
+
import { createFloatingContext } from "../internal/floating.svelte.js";
|
|
35
|
+
import { createOpenClosedContext, State } from "../internal/open-closed.js";
|
|
36
|
+
import { useLabels } from "../label/context.svelte.js";
|
|
37
|
+
import { useOutsideClick } from "../hooks/use-outside-click.svelte.js";
|
|
38
|
+
import ElementOrComponent from "../utils/ElementOrComponent.svelte";
|
|
39
|
+
function adjustOrderedState(state, adjustment = (i) => i) {
|
|
40
|
+
let currentActiveOption = state.activeOptionIndex !== null ? state.options[state.activeOptionIndex] : null;
|
|
41
|
+
let sortedOptions = sortByDomNode(
|
|
42
|
+
adjustment(state.options.slice()),
|
|
43
|
+
(option) => option.dataRef.current.domRef.current
|
|
44
|
+
);
|
|
45
|
+
let adjustedActiveOptionIndex = currentActiveOption ? sortedOptions.indexOf(currentActiveOption) : null;
|
|
46
|
+
if (adjustedActiveOptionIndex === -1) {
|
|
47
|
+
adjustedActiveOptionIndex = null;
|
|
371
48
|
}
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
ref = $bindable(),
|
|
381
|
-
as,
|
|
382
|
-
value: controlledValue,
|
|
383
|
-
defaultValue,
|
|
384
|
-
form,
|
|
385
|
-
name,
|
|
386
|
-
onchange: controlledOnChange,
|
|
387
|
-
by,
|
|
388
|
-
invalid = false,
|
|
389
|
-
disabled: ownDisabled = false,
|
|
390
|
-
horizontal = false,
|
|
391
|
-
multiple = false,
|
|
392
|
-
__demoMode = false,
|
|
393
|
-
...theirProps
|
|
394
|
-
}: { as?: TTag } & ListboxProps<TTag, TType, TActualType> = $props()
|
|
395
|
-
|
|
396
|
-
const providedDisabled = useDisabled()
|
|
397
|
-
const disabled = $derived(providedDisabled.value || ownDisabled)
|
|
398
|
-
|
|
399
|
-
const orientation = horizontal ? "horizontal" : "vertical"
|
|
400
|
-
const controllable = useControllable<any>(
|
|
401
|
-
{
|
|
402
|
-
get controlledValue() {
|
|
403
|
-
return controlledValue
|
|
404
|
-
},
|
|
405
|
-
},
|
|
406
|
-
controlledOnChange,
|
|
407
|
-
defaultValue
|
|
408
|
-
)
|
|
409
|
-
const { value = multiple ? [] : undefined, onchange: theirOnChange } = $derived(controllable)
|
|
410
|
-
|
|
411
|
-
const _state = stateReducer({
|
|
412
|
-
listboxState: __demoMode ? ListboxStates.Open : ListboxStates.Closed,
|
|
413
|
-
options: [],
|
|
414
|
-
searchQuery: "",
|
|
415
|
-
activeOptionIndex: null,
|
|
416
|
-
activationTrigger: ActivationTrigger.Other,
|
|
417
|
-
optionsVisible: false,
|
|
418
|
-
__demoMode,
|
|
419
|
-
} as StateDefinition<TActualType>)
|
|
420
|
-
|
|
421
|
-
type _Data = ListboxDataContext
|
|
422
|
-
|
|
423
|
-
const optionsPropsRef = useRef<_Data["optionsPropsRef"]["current"]>({ static: false, hold: false })
|
|
424
|
-
|
|
425
|
-
const buttonRef = useRef<_Data["buttonRef"]["current"]>(null)
|
|
426
|
-
const optionsRef = useRef<_Data["optionsRef"]["current"]>(null)
|
|
427
|
-
const listRef = useRef<_Data["listRef"]["current"]>(new Map())
|
|
428
|
-
|
|
429
|
-
const compare = useByComparator(by)
|
|
430
|
-
|
|
431
|
-
const isSelected = (compareValue: TActualType): boolean =>
|
|
432
|
-
match(data.mode, {
|
|
433
|
-
[ValueMode.Multi]: () => {
|
|
434
|
-
return (value as EnsureArray<TType>).some((option) => compare(option, compareValue))
|
|
435
|
-
},
|
|
436
|
-
[ValueMode.Single]: () => {
|
|
437
|
-
return compare(value as TActualType, compareValue)
|
|
438
|
-
},
|
|
439
|
-
})
|
|
440
|
-
|
|
441
|
-
const data = {
|
|
49
|
+
return {
|
|
50
|
+
options: sortedOptions,
|
|
51
|
+
activeOptionIndex: adjustedActiveOptionIndex
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
const stateReducer = (initialState) => {
|
|
55
|
+
let _state2 = $state(initialState);
|
|
56
|
+
return {
|
|
442
57
|
get listboxState() {
|
|
443
|
-
return
|
|
58
|
+
return _state2.listboxState;
|
|
444
59
|
},
|
|
445
60
|
get options() {
|
|
446
|
-
return
|
|
61
|
+
return _state2.options;
|
|
447
62
|
},
|
|
448
63
|
get searchQuery() {
|
|
449
|
-
return
|
|
64
|
+
return _state2.searchQuery;
|
|
450
65
|
},
|
|
451
66
|
get activeOptionIndex() {
|
|
452
|
-
return
|
|
67
|
+
return _state2.activeOptionIndex;
|
|
453
68
|
},
|
|
454
69
|
get activationTrigger() {
|
|
455
|
-
return
|
|
70
|
+
return _state2.activationTrigger;
|
|
456
71
|
},
|
|
457
72
|
get __demoMode() {
|
|
458
|
-
return
|
|
459
|
-
},
|
|
460
|
-
get value() {
|
|
461
|
-
return value
|
|
462
|
-
},
|
|
463
|
-
get disabled() {
|
|
464
|
-
return disabled
|
|
465
|
-
},
|
|
466
|
-
get invalid() {
|
|
467
|
-
return invalid
|
|
468
|
-
},
|
|
469
|
-
get mode() {
|
|
470
|
-
return multiple ? ValueMode.Multi : ValueMode.Single
|
|
73
|
+
return _state2.__demoMode;
|
|
471
74
|
},
|
|
472
|
-
|
|
473
|
-
return
|
|
75
|
+
closeListbox() {
|
|
76
|
+
if (disabled) return _state2;
|
|
77
|
+
if (_state2.listboxState === ListboxStates.Closed) return _state2;
|
|
78
|
+
_state2.activeOptionIndex = null;
|
|
79
|
+
_state2.listboxState = ListboxStates.Closed;
|
|
80
|
+
_state2.__demoMode = false;
|
|
81
|
+
return _state2;
|
|
474
82
|
},
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
83
|
+
openListbox() {
|
|
84
|
+
if (disabled) return _state2;
|
|
85
|
+
if (_state2.listboxState === ListboxStates.Open) return _state2;
|
|
86
|
+
let activeOptionIndex = _state2.activeOptionIndex;
|
|
87
|
+
let optionIdx = _state2.options.findIndex((option) => isSelected(option.dataRef.current.value));
|
|
88
|
+
if (optionIdx !== -1) {
|
|
89
|
+
activeOptionIndex = optionIdx;
|
|
90
|
+
}
|
|
91
|
+
_state2.listboxState = ListboxStates.Open;
|
|
92
|
+
_state2.activeOptionIndex = activeOptionIndex;
|
|
93
|
+
_state2.__demoMode = false;
|
|
94
|
+
return _state2;
|
|
485
95
|
},
|
|
486
|
-
|
|
487
|
-
return
|
|
96
|
+
goToOption(action) {
|
|
97
|
+
if (disabled) return _state2;
|
|
98
|
+
if (_state2.listboxState === ListboxStates.Closed) return _state2;
|
|
99
|
+
_state2.searchQuery = "";
|
|
100
|
+
_state2.activationTrigger = action.trigger ?? ActivationTrigger.Other;
|
|
101
|
+
_state2.__demoMode = false;
|
|
102
|
+
if (action.focus === Focus.Nothing) {
|
|
103
|
+
_state2.activeOptionIndex = null;
|
|
104
|
+
return _state2;
|
|
105
|
+
}
|
|
106
|
+
if (action.focus === Focus.Specific) {
|
|
107
|
+
_state2.activeOptionIndex = _state2.options.findIndex((o) => o.id === action.id);
|
|
108
|
+
return _state2;
|
|
109
|
+
} else if (action.focus === Focus.Previous) {
|
|
110
|
+
let activeOptionIdx = _state2.activeOptionIndex;
|
|
111
|
+
if (activeOptionIdx !== null) {
|
|
112
|
+
let currentDom = _state2.options[activeOptionIdx].dataRef.current.domRef;
|
|
113
|
+
let previousOptionIndex = calculateActiveIndex(action, {
|
|
114
|
+
resolveItems: () => _state2.options,
|
|
115
|
+
resolveActiveIndex: () => _state2.activeOptionIndex,
|
|
116
|
+
resolveId: (option) => option.id,
|
|
117
|
+
resolveDisabled: (option) => option.dataRef.current.disabled ?? false
|
|
118
|
+
});
|
|
119
|
+
if (previousOptionIndex !== null) {
|
|
120
|
+
let previousDom = _state2.options[previousOptionIndex].dataRef.current.domRef;
|
|
121
|
+
if (
|
|
122
|
+
// Next to each other
|
|
123
|
+
currentDom.current?.previousElementSibling === previousDom?.current || // Or already the first element
|
|
124
|
+
previousDom.current?.previousElementSibling === null
|
|
125
|
+
) {
|
|
126
|
+
_state2.activeOptionIndex = previousOptionIndex;
|
|
127
|
+
return _state2;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
} else if (action.focus === Focus.Next) {
|
|
132
|
+
let activeOptionIdx = _state2.activeOptionIndex;
|
|
133
|
+
if (activeOptionIdx !== null) {
|
|
134
|
+
let currentDom = _state2.options[activeOptionIdx].dataRef.current.domRef;
|
|
135
|
+
let nextOptionIndex = calculateActiveIndex(action, {
|
|
136
|
+
resolveItems: () => _state2.options,
|
|
137
|
+
resolveActiveIndex: () => _state2.activeOptionIndex,
|
|
138
|
+
resolveId: (option) => option.id,
|
|
139
|
+
resolveDisabled: (option) => option.dataRef.current.disabled ?? false
|
|
140
|
+
});
|
|
141
|
+
if (nextOptionIndex !== null) {
|
|
142
|
+
let nextDom = _state2.options[nextOptionIndex].dataRef.current.domRef;
|
|
143
|
+
if (
|
|
144
|
+
// Next to each other
|
|
145
|
+
currentDom.current?.nextElementSibling === nextDom.current || // Or already the last element
|
|
146
|
+
nextDom.current?.nextElementSibling === null
|
|
147
|
+
) {
|
|
148
|
+
_state2.activeOptionIndex = nextOptionIndex;
|
|
149
|
+
return _state2;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
let adjustedState = adjustOrderedState(_state2);
|
|
155
|
+
let activeOptionIndex = calculateActiveIndex(action, {
|
|
156
|
+
resolveItems: () => adjustedState.options,
|
|
157
|
+
resolveActiveIndex: () => adjustedState.activeOptionIndex,
|
|
158
|
+
resolveId: (option) => option.id,
|
|
159
|
+
resolveDisabled: (option) => option.dataRef.current.disabled ?? false
|
|
160
|
+
});
|
|
161
|
+
_state2.options = adjustedState.options;
|
|
162
|
+
_state2.activeOptionIndex = activeOptionIndex;
|
|
163
|
+
return _state2;
|
|
488
164
|
},
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
165
|
+
search(value2) {
|
|
166
|
+
if (disabled) return _state2;
|
|
167
|
+
if (_state2.listboxState === ListboxStates.Closed) return _state2;
|
|
168
|
+
let wasAlreadySearching = _state2.searchQuery !== "";
|
|
169
|
+
let offset = wasAlreadySearching ? 0 : 1;
|
|
170
|
+
let searchQuery = _state2.searchQuery + value2.toLowerCase();
|
|
171
|
+
let reOrderedOptions = _state2.activeOptionIndex !== null ? _state2.options.slice(_state2.activeOptionIndex + offset).concat(_state2.options.slice(0, _state2.activeOptionIndex + offset)) : _state2.options;
|
|
172
|
+
let matchingOption = reOrderedOptions.find(
|
|
173
|
+
(option) => !option.dataRef.current.disabled && option.dataRef.current.textValue?.startsWith(searchQuery)
|
|
174
|
+
);
|
|
175
|
+
let matchIdx = matchingOption ? _state2.options.indexOf(matchingOption) : -1;
|
|
176
|
+
if (matchIdx === -1 || matchIdx === _state2.activeOptionIndex) {
|
|
177
|
+
_state2.searchQuery = searchQuery;
|
|
178
|
+
} else {
|
|
179
|
+
_state2.searchQuery = searchQuery;
|
|
180
|
+
_state2.activeOptionIndex = matchIdx;
|
|
181
|
+
_state2.activationTrigger = ActivationTrigger.Other;
|
|
182
|
+
}
|
|
183
|
+
return _state2;
|
|
498
184
|
},
|
|
499
|
-
|
|
500
|
-
return
|
|
185
|
+
clearSearch() {
|
|
186
|
+
if (disabled) return _state2;
|
|
187
|
+
if (_state2.listboxState === ListboxStates.Closed) return _state2;
|
|
188
|
+
if (_state2.searchQuery === "") return _state2;
|
|
189
|
+
_state2.searchQuery = "";
|
|
190
|
+
return _state2;
|
|
501
191
|
},
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
if (
|
|
506
|
-
|
|
507
|
-
|
|
192
|
+
registerOption(action) {
|
|
193
|
+
let option = { id: action.id, dataRef: action.dataRef };
|
|
194
|
+
let adjustedState = adjustOrderedState(_state2, (options) => [...options, option]);
|
|
195
|
+
if (_state2.activeOptionIndex === null) {
|
|
196
|
+
if (isSelected(action.dataRef.current.value)) {
|
|
197
|
+
adjustedState.activeOptionIndex = adjustedState.options.indexOf(option);
|
|
198
|
+
}
|
|
508
199
|
}
|
|
200
|
+
_state2.options = adjustedState.options;
|
|
201
|
+
_state2.activeOptionIndex = adjustedState.activeOptionIndex;
|
|
202
|
+
return _state2;
|
|
509
203
|
},
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
204
|
+
unregisterOption(action) {
|
|
205
|
+
let adjustedState = adjustOrderedState(_state2, (options) => {
|
|
206
|
+
let idx = options.findIndex((a) => a.id === action.id);
|
|
207
|
+
if (idx !== -1) options.splice(idx, 1);
|
|
208
|
+
return options;
|
|
209
|
+
});
|
|
210
|
+
_state2.options = adjustedState.options;
|
|
211
|
+
_state2.activeOptionIndex = adjustedState.activeOptionIndex;
|
|
212
|
+
_state2.activationTrigger = ActivationTrigger.Other;
|
|
213
|
+
return _state2;
|
|
214
|
+
}
|
|
215
|
+
};
|
|
216
|
+
};
|
|
217
|
+
const listboxActionsContext = null;
|
|
218
|
+
setContext("ListboxActionsContext", listboxActionsContext);
|
|
219
|
+
const listboxDataContext = null;
|
|
220
|
+
setContext("ListboxDataContext", listboxDataContext);
|
|
221
|
+
let {
|
|
222
|
+
ref = $bindable(),
|
|
223
|
+
as,
|
|
224
|
+
value: controlledValue,
|
|
225
|
+
defaultValue,
|
|
226
|
+
form,
|
|
227
|
+
name,
|
|
228
|
+
onchange: controlledOnChange,
|
|
229
|
+
by,
|
|
230
|
+
invalid = false,
|
|
231
|
+
disabled: ownDisabled = false,
|
|
232
|
+
horizontal = false,
|
|
233
|
+
multiple = false,
|
|
234
|
+
__demoMode = false,
|
|
235
|
+
...theirProps
|
|
236
|
+
} = $props();
|
|
237
|
+
const providedDisabled = useDisabled();
|
|
238
|
+
const disabled = $derived(providedDisabled.value || ownDisabled);
|
|
239
|
+
const orientation = horizontal ? "horizontal" : "vertical";
|
|
240
|
+
const controllable = useControllable(
|
|
241
|
+
{
|
|
242
|
+
get controlledValue() {
|
|
243
|
+
return controlledValue;
|
|
534
244
|
}
|
|
535
|
-
|
|
245
|
+
},
|
|
246
|
+
controlledOnChange,
|
|
247
|
+
defaultValue
|
|
248
|
+
);
|
|
249
|
+
const { value = multiple ? [] : void 0, onchange: theirOnChange } = $derived(controllable);
|
|
250
|
+
const _state = stateReducer({
|
|
251
|
+
listboxState: __demoMode ? ListboxStates.Open : ListboxStates.Closed,
|
|
252
|
+
options: [],
|
|
253
|
+
searchQuery: "",
|
|
254
|
+
activeOptionIndex: null,
|
|
255
|
+
activationTrigger: ActivationTrigger.Other,
|
|
256
|
+
optionsVisible: false,
|
|
257
|
+
__demoMode
|
|
258
|
+
});
|
|
259
|
+
const optionsPropsRef = useRef({ static: false, hold: false });
|
|
260
|
+
const buttonRef = useRef(null);
|
|
261
|
+
const optionsRef = useRef(null);
|
|
262
|
+
const listRef = useRef(/* @__PURE__ */ new Map());
|
|
263
|
+
const compare = useByComparator(by);
|
|
264
|
+
const isSelected = (compareValue) => match(data.mode, {
|
|
265
|
+
[ValueMode.Multi]: () => {
|
|
266
|
+
return value.some((option) => compare(option, compareValue));
|
|
267
|
+
},
|
|
268
|
+
[ValueMode.Single]: () => {
|
|
269
|
+
return compare(value, compareValue);
|
|
536
270
|
}
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
271
|
+
});
|
|
272
|
+
const data = {
|
|
273
|
+
get listboxState() {
|
|
274
|
+
return _state.listboxState;
|
|
275
|
+
},
|
|
276
|
+
get options() {
|
|
277
|
+
return _state.options;
|
|
278
|
+
},
|
|
279
|
+
get searchQuery() {
|
|
280
|
+
return _state.searchQuery;
|
|
281
|
+
},
|
|
282
|
+
get activeOptionIndex() {
|
|
283
|
+
return _state.activeOptionIndex;
|
|
284
|
+
},
|
|
285
|
+
get activationTrigger() {
|
|
286
|
+
return _state.activationTrigger;
|
|
287
|
+
},
|
|
288
|
+
get __demoMode() {
|
|
289
|
+
return _state.__demoMode;
|
|
290
|
+
},
|
|
291
|
+
get value() {
|
|
292
|
+
return value;
|
|
293
|
+
},
|
|
294
|
+
get disabled() {
|
|
295
|
+
return disabled;
|
|
296
|
+
},
|
|
297
|
+
get invalid() {
|
|
298
|
+
return invalid;
|
|
299
|
+
},
|
|
300
|
+
get mode() {
|
|
301
|
+
return multiple ? ValueMode.Multi : ValueMode.Single;
|
|
302
|
+
},
|
|
303
|
+
get orientation() {
|
|
304
|
+
return orientation;
|
|
305
|
+
},
|
|
306
|
+
compare,
|
|
307
|
+
isSelected,
|
|
308
|
+
get optionsPropsRef() {
|
|
309
|
+
return optionsPropsRef;
|
|
310
|
+
},
|
|
311
|
+
get buttonRef() {
|
|
312
|
+
return buttonRef;
|
|
313
|
+
},
|
|
314
|
+
get optionsRef() {
|
|
315
|
+
return optionsRef;
|
|
316
|
+
},
|
|
317
|
+
get listRef() {
|
|
318
|
+
return listRef;
|
|
548
319
|
}
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
320
|
+
};
|
|
321
|
+
setContext("ListboxDataContext", data);
|
|
322
|
+
setContext("ListboxData", data);
|
|
323
|
+
const outsideClickEnabled = $derived(data.listboxState === ListboxStates.Open);
|
|
324
|
+
useOutsideClick({
|
|
325
|
+
get enabled() {
|
|
326
|
+
return outsideClickEnabled;
|
|
327
|
+
},
|
|
328
|
+
get containers() {
|
|
329
|
+
return [data.buttonRef, data.optionsRef];
|
|
330
|
+
},
|
|
331
|
+
cb: (event, target) => {
|
|
332
|
+
_state.closeListbox();
|
|
333
|
+
if (!isFocusableElement(target, FocusableMode.Loose)) {
|
|
334
|
+
event.preventDefault();
|
|
335
|
+
data.buttonRef.current?.focus();
|
|
336
|
+
}
|
|
553
337
|
}
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
return theirOnChange?.(copy as unknown as TType[])
|
|
571
|
-
},
|
|
572
|
-
})
|
|
338
|
+
});
|
|
339
|
+
const slot = $derived({
|
|
340
|
+
open: _state.listboxState === ListboxStates.Open,
|
|
341
|
+
disabled,
|
|
342
|
+
invalid,
|
|
343
|
+
value
|
|
344
|
+
});
|
|
345
|
+
const selectOption = (id) => {
|
|
346
|
+
let option = _state.options.find((item) => item.id === id);
|
|
347
|
+
if (!option) return;
|
|
348
|
+
};
|
|
349
|
+
const selectActiveOption = () => {
|
|
350
|
+
if (_state.activeOptionIndex !== null) {
|
|
351
|
+
let { dataRef, id } = _state.options[_state.activeOptionIndex];
|
|
352
|
+
_state.goToOption({ focus: Focus.Specific, id });
|
|
573
353
|
}
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
)
|
|
595
|
-
createOpenClosedContext({
|
|
596
|
-
get value() {
|
|
597
|
-
return openClosed
|
|
354
|
+
7;
|
|
355
|
+
};
|
|
356
|
+
const d = disposables();
|
|
357
|
+
const goToOption = (focus, id, trigger) => {
|
|
358
|
+
d.dispose();
|
|
359
|
+
d.microTask(() => {
|
|
360
|
+
if (focus === Focus.Specific) {
|
|
361
|
+
return _state.goToOption({ focus: Focus.Specific, id, trigger });
|
|
362
|
+
}
|
|
363
|
+
return _state.goToOption({ focus, trigger });
|
|
364
|
+
});
|
|
365
|
+
};
|
|
366
|
+
const registerOption = (id, dataRef) => {
|
|
367
|
+
_state.registerOption({ id, dataRef });
|
|
368
|
+
return () => _state.unregisterOption({ id });
|
|
369
|
+
};
|
|
370
|
+
const onChange = (value2) => {
|
|
371
|
+
return match(data.mode, {
|
|
372
|
+
[ValueMode.Single]() {
|
|
373
|
+
return theirOnChange?.(value2);
|
|
598
374
|
},
|
|
375
|
+
[ValueMode.Multi]() {
|
|
376
|
+
let copy = data.value.slice();
|
|
377
|
+
let idx = copy.findIndex((item) => compare(item, value2));
|
|
378
|
+
if (idx === -1) {
|
|
379
|
+
copy.push(value2);
|
|
380
|
+
} else {
|
|
381
|
+
copy.splice(idx, 1);
|
|
382
|
+
}
|
|
383
|
+
return theirOnChange?.(copy);
|
|
384
|
+
}
|
|
385
|
+
});
|
|
386
|
+
};
|
|
387
|
+
setContext("ListboxActionsContext", {
|
|
388
|
+
onChange,
|
|
389
|
+
registerOption,
|
|
390
|
+
goToOption,
|
|
391
|
+
closeListbox: _state.closeListbox,
|
|
392
|
+
openListbox: _state.openListbox,
|
|
393
|
+
selectActiveOption,
|
|
394
|
+
selectOption,
|
|
395
|
+
search: _state.search,
|
|
396
|
+
clearSearch: _state.clearSearch
|
|
397
|
+
});
|
|
398
|
+
createFloatingContext();
|
|
399
|
+
const openClosed = $derived(
|
|
400
|
+
match(data.listboxState, {
|
|
401
|
+
[ListboxStates.Open]: State.Open,
|
|
402
|
+
[ListboxStates.Closed]: State.Closed
|
|
599
403
|
})
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
404
|
+
);
|
|
405
|
+
createOpenClosedContext({
|
|
406
|
+
get value() {
|
|
407
|
+
return openClosed;
|
|
408
|
+
}
|
|
409
|
+
});
|
|
410
|
+
useLabels({
|
|
411
|
+
inherit: true,
|
|
412
|
+
props: {
|
|
413
|
+
get htmlFor() {
|
|
414
|
+
return data.buttonRef.current?.id;
|
|
415
|
+
}
|
|
416
|
+
},
|
|
417
|
+
slot: {
|
|
418
|
+
get open() {
|
|
419
|
+
return data.listboxState === ListboxStates.Open;
|
|
615
420
|
},
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
if (defaultValue === undefined) return
|
|
620
|
-
return theirOnChange?.(defaultValue)
|
|
421
|
+
get disabled() {
|
|
422
|
+
return disabled;
|
|
423
|
+
}
|
|
621
424
|
}
|
|
425
|
+
});
|
|
426
|
+
const reset = () => {
|
|
427
|
+
if (defaultValue === void 0) return;
|
|
428
|
+
return theirOnChange?.(defaultValue);
|
|
429
|
+
};
|
|
622
430
|
</script>
|
|
623
431
|
|
|
624
432
|
{#if name && value}
|