@fluixi-ui/listbox 0.2.0-alpha.18 → 0.2.0-alpha.20

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/index.js CHANGED
@@ -1,13 +1,5 @@
1
- import "@fluixi-ui/tokens/css/base.css";
2
- import "@fluixi-ui/tokens/css/parts/listbox.css";
3
1
  import { Listbox, ListboxGroup, ListboxGroupLabel, ListboxOption, ListboxSearch, useListboxContext } from "./listbox.js";
4
2
  import { VirtualListbox } from "./virtual-listbox.js";
5
- export {
6
- Listbox,
7
- ListboxGroup,
8
- ListboxGroupLabel,
9
- ListboxOption,
10
- ListboxSearch,
11
- VirtualListbox,
12
- useListboxContext
13
- };
3
+ import "@fluixi-ui/tokens/css/base.css";
4
+ import "@fluixi-ui/tokens/css/parts/listbox.css";
5
+ export { Listbox, ListboxGroup, ListboxGroupLabel, ListboxOption, ListboxSearch, VirtualListbox, useListboxContext };
package/dist/listbox.js CHANGED
@@ -1,281 +1,352 @@
1
- import { delegateEvents, splitProps, createComponent, createNativeElement, spread, mergeProps, handleRef, insert } from "@fluixi/dom";
2
- import { createSignal, createEffect, createMemo, createRenderEffect, onCleanup } from "@fluixi/reactive/signal";
3
- import { createSafeContext, createKeyOf, createValuesEqual, createId, composeEventHandlers, dataAttr, composeId } from "@fluixi-ui/kit";
1
+ import { createComponent, createNativeElement, delegateEvents, handleRef, insert, mergeProps, splitProps, spread } from "@fluixi/dom";
2
+ import { createEffect, createMemo, createRenderEffect, createSignal, onCleanup } from "@fluixi/reactive/signal";
3
+ import { composeEventHandlers, composeId, createId, createKeyOf, createSafeContext, createValuesEqual, dataAttr } from "@fluixi-ui/kit";
4
4
  import { createCollection, createSelectionManager, createTypeahead, getNextEnabledIndex } from "@fluixi-ui/primitives";
5
5
  import { fxProps } from "@fluixi-ui/fx";
6
- delegateEvents(["input", "click", "keydown", "focus"]);
7
- const [ListboxProvider, useListboxContext] = createSafeContext("Listbox");
6
+ //#region src/listbox.tsx
7
+ delegateEvents([
8
+ "input",
9
+ "click",
10
+ "keydown",
11
+ "focus"
12
+ ]);
13
+ var [ListboxProvider, useListboxContext] = createSafeContext("Listbox");
8
14
  function toArray(value) {
9
- if (value == null) return [];
10
- return Array.isArray(value) ? value : [value];
15
+ if (value == null) return [];
16
+ return Array.isArray(value) ? value : [value];
11
17
  }
18
+ /**
19
+ * A selectable list of options using the active-descendant model (focus stays
20
+ * on the listbox; the active option is tracked via `aria-activedescendant`).
21
+ * Supports `single` or `multiple` selection, arrow-key navigation that skips
22
+ * disabled options, Home/End, and type-ahead.
23
+ *
24
+ * @example
25
+ * ```tsx
26
+ * import { Listbox, ListboxOption } from '@fluixi-ui/listbox';
27
+ *
28
+ * <Listbox selectionMode="single" defaultValue="apple" onChange={setFruit}>
29
+ * <ListboxOption value="apple">Apple</ListboxOption>
30
+ * <ListboxOption value="banana">Banana</ListboxOption>
31
+ * <ListboxOption value="cherry" disabled>Cherry</ListboxOption>
32
+ * </Listbox>
33
+ * ```
34
+ */
12
35
  function Listbox(props) {
13
- const [local, others] = splitProps(props, [
14
- "selectionMode",
15
- "value",
16
- "defaultValue",
17
- "onChange",
18
- "disabled",
19
- "disallowEmptySelection",
20
- "itemToKey",
21
- "compare",
22
- "ref",
23
- "children",
24
- "onKeyDown",
25
- "onFocus",
26
- "fx",
27
- "style"
28
- ]);
29
- const keyOf = createKeyOf(() => local.itemToKey);
30
- const valuesEqual = createValuesEqual(keyOf, () => local.compare);
31
- const valuesByKey = /* @__PURE__ */ new Map();
32
- const registerValue = (key, item) => {
33
- valuesByKey.set(key, item);
34
- return () => valuesByKey.delete(key);
35
- };
36
- const valueFor = (key) => valuesByKey.get(key) ?? key;
37
- const baseId = createId("listbox");
38
- const mode = () => local.selectionMode ?? "single";
39
- const isDisabled = () => local.disabled ?? false;
40
- const collection = createCollection();
41
- const selection = createSelectionManager({
42
- mode: local.selectionMode ?? "single",
43
- selectedKeys: local.value !== void 0 ? () => toArray(local.value).map(keyOf) : void 0,
44
- defaultSelectedKeys: toArray(local.defaultValue).map(keyOf),
45
- disallowEmptySelection: local.disallowEmptySelection,
46
- onSelectionChange: (keys) => local.onChange?.([...keys].map(valueFor))
47
- });
48
- const selectedValues = () => {
49
- if (local.value !== void 0 && local.value !== null) return toArray(local.value);
50
- return [...selection.selectedKeys()].map(valueFor);
51
- };
52
- const isValueSelected = (candidate) => {
53
- if (!local.compare) return selection.isSelected(keyOf(candidate));
54
- return selectedValues().some((selected) => valuesEqual(selected, candidate));
55
- };
56
- const [activeKey, setActiveKey] = createSignal(void 0);
57
- const [query, setQuery] = createSignal("");
58
- const optionId = (key) => composeId(baseId, `option-${key}`);
59
- const activeIndex = () => collection.items().findIndex((item) => item.value === activeKey());
60
- const move = (action) => {
61
- const items = collection.items();
62
- const next = getNextEnabledIndex(items, activeIndex(), action, true);
63
- if (next !== -1) setActiveKey(items[next].value);
64
- };
65
- const firstMeaningfulKey = () => {
66
- const selected = selection.firstSelectedKey();
67
- if (selected !== void 0) return selected;
68
- const first = collection.items().find((item) => !item.disabled);
69
- return first?.value;
70
- };
71
- const pressActive = () => {
72
- const key = activeKey();
73
- if (key !== void 0) selection.toggle(key);
74
- };
75
- const onOptionPress = (key) => {
76
- setActiveKey(key);
77
- selection.toggle(key);
78
- };
79
- const typeahead = createTypeahead({
80
- getItems: () => collection.items().map((item) => ({
81
- textValue: item.textValue ?? item.ref.textContent ?? "",
82
- disabled: item.disabled
83
- })),
84
- getActiveIndex: () => activeIndex(),
85
- onMatch: (index) => {
86
- const item = collection.items()[index];
87
- if (item) setActiveKey(item.value);
88
- }
89
- });
90
- const onKeyDown = (event) => {
91
- switch (event.key) {
92
- case "ArrowDown":
93
- event.preventDefault();
94
- move(activeKey() === void 0 ? "first" : "next");
95
- break;
96
- case "ArrowUp":
97
- event.preventDefault();
98
- move(activeKey() === void 0 ? "last" : "previous");
99
- break;
100
- case "Home":
101
- event.preventDefault();
102
- move("first");
103
- break;
104
- case "End":
105
- event.preventDefault();
106
- move("last");
107
- break;
108
- case "Enter":
109
- event.preventDefault();
110
- pressActive();
111
- break;
112
- case " ":
113
- if (typeahead.buffer() === "") {
114
- event.preventDefault();
115
- pressActive();
116
- } else {
117
- typeahead.onKeyDown(event);
118
- }
119
- break;
120
- default:
121
- typeahead.onKeyDown(event);
122
- }
123
- };
124
- const onFocus = () => {
125
- if (activeKey() === void 0) setActiveKey(firstMeaningfulKey());
126
- };
127
- createEffect(() => {
128
- const key = activeKey();
129
- if (key === void 0) return;
130
- const item = collection.items().find((entry) => entry.value === key);
131
- item?.ref.scrollIntoView?.({ block: "nearest" });
132
- });
133
- const context = {
134
- selection,
135
- keyOf,
136
- isValueSelected,
137
- registerValue,
138
- collection,
139
- activeKey,
140
- setActiveKey,
141
- optionId,
142
- isDisabled,
143
- onOptionPress,
144
- query,
145
- setQuery
146
- };
147
- createEffect(() => {
148
- query();
149
- const key = activeKey();
150
- if (key === void 0) return;
151
- const items = collection.items();
152
- if (!items.some((item) => item.value === key)) {
153
- setActiveKey(items.find((item) => !item.disabled)?.value);
154
- }
155
- });
156
- return createMemo(() => createComponent(ListboxProvider, { get value() {
157
- return context;
158
- }, get children() {
159
- return (() => {
160
- const _el$ = createNativeElement("div");
161
- spread({ element: _el$, props: mergeProps(fxProps(
162
- () => local.fx,
163
- () => local.style
164
- ), others, { ref: (node) => handleRef(local.ref, node), role: "listbox", id: baseId, tabindex: () => isDisabled() ? -1 : 0, "aria-multiselectable": () => mode() === "multiple" ? "true" : void 0, "aria-disabled": () => isDisabled() ? "true" : void 0, "aria-activedescendant": () => activeKey() !== void 0 ? optionId(activeKey()) : void 0, "data-disabled": () => dataAttr(isDisabled()), onKeyDown: composeEventHandlers([
165
- local.onKeyDown,
166
- (event) => {
167
- if (!isDisabled()) onKeyDown(event);
168
- }
169
- ]), onFocus: composeEventHandlers([
170
- local.onFocus,
171
- onFocus
172
- ]) }) });
173
- insert(_el$, local.children);
174
- return _el$;
175
- })();
176
- } }));
36
+ const [local, others] = splitProps(props, [
37
+ "selectionMode",
38
+ "value",
39
+ "defaultValue",
40
+ "onChange",
41
+ "disabled",
42
+ "disallowEmptySelection",
43
+ "itemToKey",
44
+ "compare",
45
+ "ref",
46
+ "children",
47
+ "onKeyDown",
48
+ "onFocus",
49
+ "fx",
50
+ "style"
51
+ ]);
52
+ const keyOf = createKeyOf(() => local.itemToKey);
53
+ const valuesEqual = createValuesEqual(keyOf, () => local.compare);
54
+ const valuesByKey = /* @__PURE__ */ new Map();
55
+ const registerValue = (key, item) => {
56
+ valuesByKey.set(key, item);
57
+ return () => valuesByKey.delete(key);
58
+ };
59
+ const valueFor = (key) => valuesByKey.get(key) ?? key;
60
+ const baseId = createId("listbox");
61
+ const mode = () => local.selectionMode ?? "single";
62
+ const isDisabled = () => local.disabled ?? false;
63
+ const collection = createCollection();
64
+ const selection = createSelectionManager({
65
+ mode: local.selectionMode ?? "single",
66
+ selectedKeys: local.value !== void 0 ? () => toArray(local.value).map(keyOf) : void 0,
67
+ defaultSelectedKeys: toArray(local.defaultValue).map(keyOf),
68
+ disallowEmptySelection: local.disallowEmptySelection,
69
+ onSelectionChange: (keys) => local.onChange?.([...keys].map(valueFor))
70
+ });
71
+ /** The selected values, from the controlled prop or resolved from the keys. */
72
+ const selectedValues = () => {
73
+ if (local.value !== void 0 && local.value !== null) return toArray(local.value);
74
+ return [...selection.selectedKeys()].map(valueFor);
75
+ };
76
+ const isValueSelected = (candidate) => {
77
+ if (!local.compare) return selection.isSelected(keyOf(candidate));
78
+ return selectedValues().some((selected) => valuesEqual(selected, candidate));
79
+ };
80
+ const [activeKey, setActiveKey] = createSignal(void 0);
81
+ const [query, setQuery] = createSignal("");
82
+ const optionId = (key) => composeId(baseId, `option-${key}`);
83
+ const activeIndex = () => collection.items().findIndex((item) => item.value === activeKey());
84
+ const move = (action) => {
85
+ const items = collection.items();
86
+ const next = getNextEnabledIndex(items, activeIndex(), action, true);
87
+ if (next !== -1) setActiveKey(items[next].value);
88
+ };
89
+ const firstMeaningfulKey = () => {
90
+ const selected = selection.firstSelectedKey();
91
+ if (selected !== void 0) return selected;
92
+ return collection.items().find((item) => !item.disabled)?.value;
93
+ };
94
+ const pressActive = () => {
95
+ const key = activeKey();
96
+ if (key !== void 0) selection.toggle(key);
97
+ };
98
+ const onOptionPress = (key) => {
99
+ setActiveKey(key);
100
+ selection.toggle(key);
101
+ };
102
+ const typeahead = createTypeahead({
103
+ getItems: () => collection.items().map((item) => ({
104
+ textValue: item.textValue ?? item.ref.textContent ?? "",
105
+ disabled: item.disabled
106
+ })),
107
+ getActiveIndex: () => activeIndex(),
108
+ onMatch: (index) => {
109
+ const item = collection.items()[index];
110
+ if (item) setActiveKey(item.value);
111
+ }
112
+ });
113
+ const onKeyDown = (event) => {
114
+ switch (event.key) {
115
+ case "ArrowDown":
116
+ event.preventDefault();
117
+ move(activeKey() === void 0 ? "first" : "next");
118
+ break;
119
+ case "ArrowUp":
120
+ event.preventDefault();
121
+ move(activeKey() === void 0 ? "last" : "previous");
122
+ break;
123
+ case "Home":
124
+ event.preventDefault();
125
+ move("first");
126
+ break;
127
+ case "End":
128
+ event.preventDefault();
129
+ move("last");
130
+ break;
131
+ case "Enter":
132
+ event.preventDefault();
133
+ pressActive();
134
+ break;
135
+ case " ":
136
+ if (typeahead.buffer() === "") {
137
+ event.preventDefault();
138
+ pressActive();
139
+ } else typeahead.onKeyDown(event);
140
+ break;
141
+ default: typeahead.onKeyDown(event);
142
+ }
143
+ };
144
+ const onFocus = () => {
145
+ if (activeKey() === void 0) setActiveKey(firstMeaningfulKey());
146
+ };
147
+ createEffect(() => {
148
+ const key = activeKey();
149
+ if (key === void 0) return;
150
+ collection.items().find((entry) => entry.value === key)?.ref.scrollIntoView?.({ block: "nearest" });
151
+ });
152
+ const context = {
153
+ selection,
154
+ keyOf,
155
+ isValueSelected,
156
+ registerValue,
157
+ collection,
158
+ activeKey,
159
+ setActiveKey,
160
+ optionId,
161
+ isDisabled,
162
+ onOptionPress,
163
+ query,
164
+ setQuery
165
+ };
166
+ createEffect(() => {
167
+ query();
168
+ const key = activeKey();
169
+ if (key === void 0) return;
170
+ const items = collection.items();
171
+ if (!items.some((item) => item.value === key)) setActiveKey(items.find((item) => !item.disabled)?.value);
172
+ });
173
+ return createMemo(() => createComponent(ListboxProvider, {
174
+ get value() {
175
+ return context;
176
+ },
177
+ get children() {
178
+ return (() => {
179
+ const _el$ = createNativeElement("div");
180
+ spread({
181
+ element: _el$,
182
+ props: mergeProps(fxProps(() => local.fx, () => local.style), others, {
183
+ ref: (node) => handleRef(local.ref, node),
184
+ role: "listbox",
185
+ id: baseId,
186
+ tabindex: () => isDisabled() ? -1 : 0,
187
+ "aria-multiselectable": () => mode() === "multiple" ? "true" : void 0,
188
+ "aria-disabled": () => isDisabled() ? "true" : void 0,
189
+ "aria-activedescendant": () => activeKey() !== void 0 ? optionId(activeKey()) : void 0,
190
+ "data-disabled": () => dataAttr(isDisabled()),
191
+ onKeyDown: composeEventHandlers([local.onKeyDown, (event) => {
192
+ if (!isDisabled()) onKeyDown(event);
193
+ }]),
194
+ onFocus: composeEventHandlers([local.onFocus, onFocus])
195
+ })
196
+ });
197
+ insert(_el$, local.children, null);
198
+ return _el$;
199
+ })();
200
+ }
201
+ }));
177
202
  }
203
+ /** A selectable option within a {@link Listbox}, identified by `value`. */
178
204
  function ListboxOption(props) {
179
- const ctx = useListboxContext();
180
- const [local, others] = splitProps(props, [
181
- "value",
182
- "textValue",
183
- "disabled",
184
- "onClick",
185
- "ref",
186
- "children",
187
- "fx",
188
- "style"
189
- ]);
190
- const key = () => ctx.keyOf(local.value);
191
- const isDisabled = () => local.disabled ?? false;
192
- const isSelected = () => ctx.isValueSelected(local.value);
193
- const isActive = () => ctx.activeKey() === key();
194
- const [node, setNode] = createSignal(void 0);
195
- const label = () => local.textValue ?? (typeof local.children === "string" ? local.children : void 0) ?? node()?.textContent ?? // Falls back to the key, never the raw value: an object would stringify to
196
- // "[object Object]" and make typeahead match nothing.
197
- key();
198
- const isMatch = () => {
199
- const q = ctx.query().trim().toLowerCase();
200
- return q === "" || label().toLowerCase().includes(q);
201
- };
202
- const setRef = (element) => {
203
- setNode(element);
204
- handleRef(local.ref, element);
205
- };
206
- createRenderEffect(() => {
207
- const element = node();
208
- if (!element || !isMatch()) return;
209
- const remove = ctx.collection.register({
210
- ref: element,
211
- value: key(),
212
- textValue: local.textValue,
213
- disabled: local.disabled
214
- });
215
- onCleanup(remove);
216
- onCleanup(ctx.registerValue(key(), local.value));
217
- });
218
- return (() => {
219
- const _el$ = createNativeElement("div");
220
- spread({ element: _el$, props: mergeProps(fxProps(
221
- () => local.fx,
222
- () => local.style
223
- ), others, { ref: setRef, role: "option", id: () => ctx.optionId(key()), hidden: () => !isMatch(), "aria-selected": () => isSelected() ? "true" : "false", "aria-disabled": () => isDisabled() ? "true" : void 0, "data-selected": () => dataAttr(isSelected()), "data-active": () => dataAttr(isActive()), "data-disabled": () => dataAttr(isDisabled()), onClick: composeEventHandlers([
224
- local.onClick,
225
- () => {
226
- if (!isDisabled()) ctx.onOptionPress(key());
227
- }
228
- ]), onPointerMove: () => {
229
- if (!isDisabled()) ctx.setActiveKey(key());
230
- } }) });
231
- insert(_el$, local.children);
232
- return _el$;
233
- })();
205
+ const ctx = useListboxContext();
206
+ const [local, others] = splitProps(props, [
207
+ "value",
208
+ "textValue",
209
+ "disabled",
210
+ "onClick",
211
+ "ref",
212
+ "children",
213
+ "fx",
214
+ "style"
215
+ ]);
216
+ const key = () => ctx.keyOf(local.value);
217
+ const isDisabled = () => local.disabled ?? false;
218
+ const isSelected = () => ctx.isValueSelected(local.value);
219
+ const isActive = () => ctx.activeKey() === key();
220
+ const [node, setNode] = createSignal(void 0);
221
+ const label = () => local.textValue ?? (typeof local.children === "string" ? local.children : void 0) ?? node()?.textContent ?? key();
222
+ const isMatch = () => {
223
+ const q = ctx.query().trim().toLowerCase();
224
+ return q === "" || label().toLowerCase().includes(q);
225
+ };
226
+ const setRef = (element) => {
227
+ setNode(element);
228
+ handleRef(local.ref, element);
229
+ };
230
+ createRenderEffect(() => {
231
+ const element = node();
232
+ if (!element || !isMatch()) return;
233
+ const remove = ctx.collection.register({
234
+ ref: element,
235
+ value: key(),
236
+ textValue: local.textValue,
237
+ disabled: local.disabled
238
+ });
239
+ onCleanup(remove);
240
+ onCleanup(ctx.registerValue(key(), local.value));
241
+ });
242
+ return (() => {
243
+ const _el$ = createNativeElement("div");
244
+ spread({
245
+ element: _el$,
246
+ props: mergeProps(fxProps(() => local.fx, () => local.style), others, {
247
+ ref: setRef,
248
+ role: "option",
249
+ id: () => ctx.optionId(key()),
250
+ hidden: () => !isMatch(),
251
+ "aria-selected": () => isSelected() ? "true" : "false",
252
+ "aria-disabled": () => isDisabled() ? "true" : void 0,
253
+ "data-selected": () => dataAttr(isSelected()),
254
+ "data-active": () => dataAttr(isActive()),
255
+ "data-disabled": () => dataAttr(isDisabled()),
256
+ onClick: composeEventHandlers([local.onClick, () => {
257
+ if (!isDisabled()) ctx.onOptionPress(key());
258
+ }]),
259
+ onPointerMove: () => {
260
+ if (!isDisabled()) ctx.setActiveKey(key());
261
+ }
262
+ })
263
+ });
264
+ insert(_el$, local.children, null);
265
+ return _el$;
266
+ })();
234
267
  }
268
+ /** Groups related options under a shared {@link ListboxGroupLabel}. */
235
269
  function ListboxGroup(props) {
236
- const [local, others] = splitProps(props, ["ref", "children", "fx", "style"]);
237
- const groupId = createId("listbox-group");
238
- return (() => {
239
- const _el$ = createNativeElement("div");
240
- spread({ element: _el$, props: mergeProps(fxProps(
241
- () => local.fx,
242
- () => local.style
243
- ), others, { ref: (node) => handleRef(local.ref, node), role: "group", "aria-labelledby": () => composeId(groupId, "label"), "data-listbox-group": "" }) });
244
- insert(_el$, createMemo(() => createComponent(ListboxGroupIdProvider, { get value() {
245
- return groupId;
246
- }, get children() {
247
- return local.children;
248
- } })), null);
249
- return _el$;
250
- })();
270
+ const [local, others] = splitProps(props, [
271
+ "ref",
272
+ "children",
273
+ "fx",
274
+ "style"
275
+ ]);
276
+ const groupId = createId("listbox-group");
277
+ return (() => {
278
+ const _el$ = createNativeElement("div");
279
+ spread({
280
+ element: _el$,
281
+ props: mergeProps(fxProps(() => local.fx, () => local.style), others, {
282
+ ref: (node) => handleRef(local.ref, node),
283
+ role: "group",
284
+ "aria-labelledby": () => composeId(groupId, "label"),
285
+ "data-listbox-group": ""
286
+ })
287
+ });
288
+ insert(_el$, createMemo(() => createComponent(ListboxGroupIdProvider, {
289
+ get value() {
290
+ return groupId;
291
+ },
292
+ get children() {
293
+ return local.children;
294
+ }
295
+ })), null);
296
+ return _el$;
297
+ })();
251
298
  }
252
- const [ListboxGroupIdProvider, useListboxGroupId] = createSafeContext("ListboxGroup");
299
+ var [ListboxGroupIdProvider, useListboxGroupId] = createSafeContext("ListboxGroup");
300
+ /**
301
+ * A search box that filters the {@link Listbox}'s options by their text. Options
302
+ * that don't match are hidden and skipped by keyboard navigation. Place it above
303
+ * the options.
304
+ *
305
+ * @example
306
+ * ```tsx
307
+ * <Listbox>
308
+ * <ListboxSearch placeholder="Search…" />
309
+ * <ListboxOption value="apple">Apple</ListboxOption>
310
+ * </Listbox>
311
+ * ```
312
+ */
253
313
  function ListboxSearch(props) {
254
- const ctx = useListboxContext();
255
- return (() => {
256
- const _el$ = createNativeElement("input");
257
- spread({ element: _el$, props: mergeProps(props, { type: "text", "data-listbox-search": "", "aria-label": "Search options", value: () => ctx.query(), onInput: (event) => ctx.setQuery(event.target.value) }) });
258
- return _el$;
259
- })();
314
+ const ctx = useListboxContext();
315
+ return (() => {
316
+ const _el$ = createNativeElement("input");
317
+ spread({
318
+ element: _el$,
319
+ props: mergeProps(props, {
320
+ type: "text",
321
+ "data-listbox-search": "",
322
+ "aria-label": "Search options",
323
+ value: () => ctx.query(),
324
+ onInput: (event) => ctx.setQuery(event.target.value)
325
+ })
326
+ });
327
+ return _el$;
328
+ })();
260
329
  }
330
+ /** The heading for a {@link ListboxGroup}, linked via `aria-labelledby`. */
261
331
  function ListboxGroupLabel(props) {
262
- const groupId = useListboxGroupId();
263
- const [local, others] = splitProps(props, ["children", "fx", "style"]);
264
- return (() => {
265
- const _el$ = createNativeElement("div");
266
- spread({ element: _el$, props: mergeProps(fxProps(
267
- () => local.fx,
268
- () => local.style
269
- ), others, { id: () => composeId(groupId, "label"), "data-listbox-group-label": "" }) });
270
- insert(_el$, local.children);
271
- return _el$;
272
- })();
332
+ const groupId = useListboxGroupId();
333
+ const [local, others] = splitProps(props, [
334
+ "children",
335
+ "fx",
336
+ "style"
337
+ ]);
338
+ return (() => {
339
+ const _el$ = createNativeElement("div");
340
+ spread({
341
+ element: _el$,
342
+ props: mergeProps(fxProps(() => local.fx, () => local.style), others, {
343
+ id: () => composeId(groupId, "label"),
344
+ "data-listbox-group-label": ""
345
+ })
346
+ });
347
+ insert(_el$, local.children, null);
348
+ return _el$;
349
+ })();
273
350
  }
274
- export {
275
- Listbox,
276
- ListboxGroup,
277
- ListboxGroupLabel,
278
- ListboxOption,
279
- ListboxSearch,
280
- useListboxContext
281
- };
351
+ //#endregion
352
+ export { Listbox, ListboxGroup, ListboxGroupLabel, ListboxOption, ListboxSearch, useListboxContext };