@k2b/ui 0.35.0 → 0.37.0
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/browser/actions/Dropdown.js +132 -116
- package/dist/browser/actions/Dropdown.js.map +1 -1
- package/dist/browser/actions/Tabs.js +18 -15
- package/dist/browser/actions/Tabs.js.map +1 -1
- package/dist/browser/chat/ChatComposer.js +58 -25
- package/dist/browser/chat/ChatComposer.js.map +1 -1
- package/dist/browser/content/MapView.js +128 -13
- package/dist/browser/content/MapView.js.map +1 -1
- package/dist/browser/content/MapViewFrame.js +1 -1
- package/dist/browser/content/MapViewFrame.js.map +1 -1
- package/dist/browser/content/MessageRow.js +164 -152
- package/dist/browser/content/MessageRow.js.map +1 -1
- package/dist/browser/content/index.js +1 -0
- package/dist/browser/content/index.js.map +1 -1
- package/dist/browser/content/map-view-glyphs.js +23 -0
- package/dist/browser/content/map-view-glyphs.js.map +1 -0
- package/dist/browser/content/map-view-live.js +45 -22
- package/dist/browser/content/map-view-live.js.map +1 -1
- package/dist/browser/content/map-view-snapshot.js +191 -0
- package/dist/browser/content/map-view-snapshot.js.map +1 -0
- package/dist/browser/content/map-view-types.js.map +1 -1
- package/dist/browser/feedback/prompts.js +23 -9
- package/dist/browser/feedback/prompts.js.map +1 -1
- package/dist/browser/inputs/Combobox.js +164 -82
- package/dist/browser/inputs/Combobox.js.map +1 -1
- package/dist/browser/inputs/RichSelect.js +86 -67
- package/dist/browser/inputs/RichSelect.js.map +1 -1
- package/dist/browser/inputs/TextInput.js +1 -1
- package/dist/browser/inputs/TextInput.js.map +1 -1
- package/dist/browser/internal/keyed-for.js +47 -0
- package/dist/browser/internal/keyed-for.js.map +1 -0
- package/dist/browser/layout/AppWorkspace.js +73 -70
- package/dist/browser/layout/AppWorkspace.js.map +1 -1
- package/dist/browser/layout/ScrollArea.js +4 -1
- package/dist/browser/layout/ScrollArea.js.map +1 -1
- package/dist/browser/text-editor/engine.js +13 -10
- package/dist/browser/text-editor/engine.js.map +1 -1
- package/dist/ssr/actions/Dropdown.js +101 -85
- package/dist/ssr/actions/Dropdown.js.map +1 -1
- package/dist/ssr/actions/Tabs.js +12 -9
- package/dist/ssr/actions/Tabs.js.map +1 -1
- package/dist/ssr/chat/ChatComposer.js +41 -15
- package/dist/ssr/chat/ChatComposer.js.map +1 -1
- package/dist/ssr/content/MapView.js +128 -13
- package/dist/ssr/content/MapView.js.map +1 -1
- package/dist/ssr/content/MapViewFrame.js +1 -1
- package/dist/ssr/content/MapViewFrame.js.map +1 -1
- package/dist/ssr/content/MessageRow.js +9 -2
- package/dist/ssr/content/MessageRow.js.map +1 -1
- package/dist/ssr/content/index.js +1 -0
- package/dist/ssr/content/index.js.map +1 -1
- package/dist/ssr/content/map-view-glyphs.js +23 -0
- package/dist/ssr/content/map-view-glyphs.js.map +1 -0
- package/dist/ssr/content/map-view-snapshot.js +191 -0
- package/dist/ssr/content/map-view-snapshot.js.map +1 -0
- package/dist/ssr/content/map-view-types.js.map +1 -1
- package/dist/ssr/feedback/prompts.js +22 -8
- package/dist/ssr/feedback/prompts.js.map +1 -1
- package/dist/ssr/inputs/Combobox.js +79 -28
- package/dist/ssr/inputs/Combobox.js.map +1 -1
- package/dist/ssr/inputs/RichSelect.js +47 -28
- package/dist/ssr/inputs/RichSelect.js.map +1 -1
- package/dist/ssr/inputs/TextInput.js.map +1 -1
- package/dist/ssr/internal/keyed-for.js +47 -0
- package/dist/ssr/internal/keyed-for.js.map +1 -0
- package/dist/ssr/layout/AppWorkspace.js +1 -1
- package/dist/ssr/layout/AppWorkspace.js.map +1 -1
- package/dist/ssr/layout/ScrollArea.js +4 -1
- package/dist/ssr/layout/ScrollArea.js.map +1 -1
- package/dist/ssr/text-editor/engine.js +13 -10
- package/dist/ssr/text-editor/engine.js.map +1 -1
- package/dist/styles.css +1 -1
- package/dist/types/content/MapViewFrame.d.ts +1 -1
- package/dist/types/content/MessageRow.d.ts +1 -1
- package/dist/types/content/index.d.ts +2 -1
- package/dist/types/content/map-view-glyphs.d.ts +5 -0
- package/dist/types/content/map-view-live.d.ts +1 -1
- package/dist/types/content/map-view-snapshot.d.ts +13 -0
- package/dist/types/content/map-view-types.d.ts +15 -0
- package/dist/types/feedback/prompts.d.ts +5 -0
- package/dist/types/inputs/Combobox.d.ts +12 -0
- package/dist/types/inputs/TextInput.d.ts +2 -1
- package/dist/types/internal/keyed-for.d.ts +13 -0
- package/dist/types/layout/AppWorkspace.d.ts +4 -1
- package/dist/types/layout/ScrollArea.d.ts +2 -0
- package/dist/types/text-editor/engine.d.ts +1 -1
- package/package.json +4 -2
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { template as _$template } from "solid-js/web";
|
|
2
2
|
import { delegateEvents as _$delegateEvents } from "solid-js/web";
|
|
3
3
|
import { className as _$className } from "solid-js/web";
|
|
4
|
+
import { setStyleProperty as _$setStyleProperty } from "solid-js/web";
|
|
4
5
|
import { addEventListener as _$addEventListener } from "solid-js/web";
|
|
5
6
|
import { effect as _$effect } from "solid-js/web";
|
|
6
7
|
import { runHydrationEvents as _$runHydrationEvents } from "solid-js/web";
|
|
@@ -14,14 +15,17 @@ import { mergeProps as _$mergeProps } from "solid-js/web";
|
|
|
14
15
|
import { memo as _$memo } from "solid-js/web";
|
|
15
16
|
import { use as _$use } from "solid-js/web";
|
|
16
17
|
var _tmpl$ = /*#__PURE__*/_$template(`<i class="ti ti-loader-2 k2b-spin"aria-hidden=true>`),
|
|
17
|
-
_tmpl$2 = /*#__PURE__*/_$template(`<div class=k2b-combobox><div class=k2b-combobox__input><i class="ti ti-search"aria-hidden=true></i><input type=text role=combobox aria-autocomplete=list><!$><!/></div><div popover=manual class=k2b-choice-popover><div class=k2b-choice-options role=listbox
|
|
18
|
+
_tmpl$2 = /*#__PURE__*/_$template(`<div class=k2b-combobox><div class=k2b-combobox__input><i class="ti ti-search"aria-hidden=true></i><input type=text role=combobox autocomplete=off aria-autocomplete=list><!$><!/></div><div popover=manual class=k2b-choice-popover><div class=k2b-choice-options role=listbox><!$><!/><!$><!/><!$><!/></div><!$><!/>`),
|
|
18
19
|
_tmpl$3 = /*#__PURE__*/_$template(`<i class="ti ti-chevron-down"aria-hidden=true>`),
|
|
19
|
-
_tmpl$4 = /*#__PURE__*/_$template(`<div class=k2b-choice-status
|
|
20
|
-
_tmpl$5 = /*#__PURE__*/_$template(`<div class=k2b-choice-status>`),
|
|
21
|
-
_tmpl$6 = /*#__PURE__*/_$template(`<
|
|
22
|
-
_tmpl$7 = /*#__PURE__*/_$template(`<
|
|
23
|
-
_tmpl$8 = /*#__PURE__*/_$template(`<
|
|
24
|
-
|
|
20
|
+
_tmpl$4 = /*#__PURE__*/_$template(`<div class=k2b-choice-status>`),
|
|
21
|
+
_tmpl$5 = /*#__PURE__*/_$template(`<div class=k2b-choice-status data-tone=danger><span></span><button type=button>`),
|
|
22
|
+
_tmpl$6 = /*#__PURE__*/_$template(`<div class=k2b-choice-loading role=status><span class=k2b-sr-only></span><!$><!/>`),
|
|
23
|
+
_tmpl$7 = /*#__PURE__*/_$template(`<div class=k2b-choice-loading__row aria-hidden=true><span class=k2b-skeleton></span><span class=k2b-skeleton>`),
|
|
24
|
+
_tmpl$8 = /*#__PURE__*/_$template(`<button type=button class=k2b-choice-option role=option><!$><!/><span><strong></strong><!$><!/>`),
|
|
25
|
+
_tmpl$9 = /*#__PURE__*/_$template(`<i aria-hidden=true>`),
|
|
26
|
+
_tmpl$0 = /*#__PURE__*/_$template(`<small>`),
|
|
27
|
+
_tmpl$1 = /*#__PURE__*/_$template(`<div class=k2b-choice-footer>`);
|
|
28
|
+
import { createEffect, createMemo, createSignal, For, on, Show } from "solid-js";
|
|
25
29
|
import { createFieldMeta, Field, fieldControlAria } from "../internal/field";
|
|
26
30
|
import { useUiMessages } from "../intl/messages";
|
|
27
31
|
import { createChoiceLoader, createChoicePopover, nextEnabledChoiceIndex } from "./choice";
|
|
@@ -53,8 +57,11 @@ export function Combobox(props) {
|
|
|
53
57
|
// 150ms keeps typing responsive without hammering the loader.
|
|
54
58
|
() => props.debounceMs ?? 150);
|
|
55
59
|
const popover = createChoicePopover(() => Boolean(props.disabled || props.readOnly));
|
|
56
|
-
|
|
60
|
+
// A host notice or an error replaces the results; hidden results are never selectable.
|
|
61
|
+
const options = () => props.status || loader.error() ? [] : loader.options();
|
|
62
|
+
const optionsById = createMemo(() => new Map(options().map(option => [option.value, option])));
|
|
57
63
|
const focusedOption = () => options()[focusedIndex()];
|
|
64
|
+
const searchable = value => value.trim().length >= (props.minQueryLength ?? 0);
|
|
58
65
|
const focus = index => {
|
|
59
66
|
setFocusedIndex(index);
|
|
60
67
|
optionRefs[index]?.scrollIntoView({
|
|
@@ -64,9 +71,9 @@ export function Combobox(props) {
|
|
|
64
71
|
/** `eager` loads the currently controlled query on open; typing supplies its
|
|
65
72
|
* own query, so opening from `onInput` skips the duplicate request. */
|
|
66
73
|
const open = (eager = true) => {
|
|
67
|
-
if (props.disabled || props.readOnly || popover.open()) return;
|
|
74
|
+
if (props.disabled || props.readOnly || popover.open() || !searchable(query())) return;
|
|
68
75
|
popover.show();
|
|
69
|
-
if (eager) loader.load(query(), true);
|
|
76
|
+
if (eager && !props.status) loader.load(query(), true);
|
|
70
77
|
focus(-1);
|
|
71
78
|
};
|
|
72
79
|
const reset = () => {
|
|
@@ -76,8 +83,14 @@ export function Combobox(props) {
|
|
|
76
83
|
};
|
|
77
84
|
const close = () => {
|
|
78
85
|
popover.hide();
|
|
79
|
-
reset();
|
|
86
|
+
if (!props.freeText) return reset();
|
|
87
|
+
loader.cancel();
|
|
88
|
+
focus(-1);
|
|
80
89
|
};
|
|
90
|
+
createEffect(on(options, list => {
|
|
91
|
+
const index = props.autoHighlight;
|
|
92
|
+
if (index !== undefined && focusedIndex() < 0 && popover.open() && list.length > 0) setFocusedIndex(Math.min(index, list.length - 1));
|
|
93
|
+
}));
|
|
81
94
|
createEffect(() => {
|
|
82
95
|
if (props.readOnly) {
|
|
83
96
|
popover.hide();
|
|
@@ -94,7 +107,10 @@ export function Combobox(props) {
|
|
|
94
107
|
description: option.description,
|
|
95
108
|
icon: option.icon
|
|
96
109
|
});
|
|
97
|
-
|
|
110
|
+
if (props.freeText) {
|
|
111
|
+
loader.cancel();
|
|
112
|
+
focus(-1);
|
|
113
|
+
} else reset();
|
|
98
114
|
inputRef?.focus();
|
|
99
115
|
};
|
|
100
116
|
const onKeyDown = event => {
|
|
@@ -106,7 +122,7 @@ export function Combobox(props) {
|
|
|
106
122
|
// While the results are open, Enter belongs to them: it never submits an enclosing form, even with no option active.
|
|
107
123
|
event.preventDefault();
|
|
108
124
|
const option = options()[focusedIndex()];
|
|
109
|
-
if (option) select(option);
|
|
125
|
+
if (option) select(option);else if (props.freeText) close();
|
|
110
126
|
} else if ((event.key === "Escape" || event.key === "Tab") && popover.open()) {
|
|
111
127
|
// Escape is only ours while the list is open; otherwise it has to reach an
|
|
112
128
|
// enclosing dialog or drawer.
|
|
@@ -146,7 +162,11 @@ export function Combobox(props) {
|
|
|
146
162
|
_el$0 = _el$9.firstChild,
|
|
147
163
|
[_el$1, _co$2] = _$getNextMarker(_el$0.nextSibling),
|
|
148
164
|
_el$10 = _el$1.nextSibling,
|
|
149
|
-
[_el$11, _co$3] = _$getNextMarker(_el$10.nextSibling)
|
|
165
|
+
[_el$11, _co$3] = _$getNextMarker(_el$10.nextSibling),
|
|
166
|
+
_el$12 = _el$11.nextSibling,
|
|
167
|
+
[_el$13, _co$4] = _$getNextMarker(_el$12.nextSibling),
|
|
168
|
+
_el$14 = _el$9.nextSibling,
|
|
169
|
+
[_el$15, _co$5] = _$getNextMarker(_el$14.nextSibling);
|
|
150
170
|
var _ref$ = popover.setTrigger;
|
|
151
171
|
typeof _ref$ === "function" ? _$use(_ref$, _el$2) : popover.setTrigger = _el$2;
|
|
152
172
|
_$use(element => {
|
|
@@ -185,10 +205,16 @@ export function Combobox(props) {
|
|
|
185
205
|
event.currentTarget.value = query();
|
|
186
206
|
return;
|
|
187
207
|
}
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
loader.load(event.currentTarget.value);
|
|
208
|
+
const value = event.currentTarget.value;
|
|
209
|
+
setQuery(value);
|
|
191
210
|
focus(-1);
|
|
211
|
+
if (!searchable(value)) {
|
|
212
|
+
popover.hide();
|
|
213
|
+
loader.cancel();
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
open(false);
|
|
217
|
+
if (!props.status) loader.load(value);
|
|
192
218
|
},
|
|
193
219
|
"onKeyDown": onKeyDown
|
|
194
220
|
}), false, false);
|
|
@@ -208,83 +234,139 @@ export function Combobox(props) {
|
|
|
208
234
|
_$setAttribute(_el$9, "id", listboxId);
|
|
209
235
|
_$insert(_el$9, _$createComponent(Show, {
|
|
210
236
|
get when() {
|
|
211
|
-
return
|
|
237
|
+
return props.status;
|
|
238
|
+
},
|
|
239
|
+
children: status => (() => {
|
|
240
|
+
var _el$17 = _$getNextElement(_tmpl$4);
|
|
241
|
+
_$insert(_el$17, status);
|
|
242
|
+
return _el$17;
|
|
243
|
+
})()
|
|
244
|
+
}), _el$1, _co$2);
|
|
245
|
+
_$insert(_el$9, _$createComponent(Show, {
|
|
246
|
+
get when() {
|
|
247
|
+
return _$memo(() => !!!props.status)() && loader.error();
|
|
212
248
|
},
|
|
213
249
|
children: message => (() => {
|
|
214
|
-
var _el$
|
|
215
|
-
_el$
|
|
216
|
-
_el$
|
|
217
|
-
_$insert(_el$
|
|
218
|
-
_$addEventListener(_el$
|
|
219
|
-
_$insert(_el$
|
|
250
|
+
var _el$18 = _$getNextElement(_tmpl$5),
|
|
251
|
+
_el$19 = _el$18.firstChild,
|
|
252
|
+
_el$20 = _el$19.nextSibling;
|
|
253
|
+
_$insert(_el$19, message);
|
|
254
|
+
_$addEventListener(_el$20, "click", loader.retry, true);
|
|
255
|
+
_$insert(_el$20, () => messages().retry);
|
|
220
256
|
_$runHydrationEvents();
|
|
221
|
-
return _el$
|
|
257
|
+
return _el$18;
|
|
222
258
|
})()
|
|
223
|
-
}), _el$
|
|
259
|
+
}), _el$11, _co$3);
|
|
224
260
|
_$insert(_el$9, _$createComponent(For, {
|
|
225
261
|
get each() {
|
|
226
|
-
return
|
|
262
|
+
return options().map(option => option.value);
|
|
227
263
|
},
|
|
228
264
|
get fallback() {
|
|
229
|
-
return (
|
|
230
|
-
var _el$16 = _$getNextElement(_tmpl$5);
|
|
231
|
-
_$insert(_el$16, (() => {
|
|
232
|
-
var _c$ = _$memo(() => query().length >= 2);
|
|
233
|
-
return () => _c$() ? selectMessages().noResultsFound : selectMessages().typeToSearch;
|
|
234
|
-
})());
|
|
235
|
-
return _el$16;
|
|
236
|
-
})();
|
|
237
|
-
},
|
|
238
|
-
children: (option, index) => (() => {
|
|
239
|
-
var _el$17 = _$getNextElement(_tmpl$6),
|
|
240
|
-
_el$22 = _el$17.firstChild,
|
|
241
|
-
[_el$23, _co$5] = _$getNextMarker(_el$22.nextSibling),
|
|
242
|
-
_el$18 = _el$23.nextSibling,
|
|
243
|
-
_el$19 = _el$18.firstChild,
|
|
244
|
-
_el$20 = _el$19.nextSibling,
|
|
245
|
-
[_el$21, _co$4] = _$getNextMarker(_el$20.nextSibling);
|
|
246
|
-
_el$17.$$click = () => select(option);
|
|
247
|
-
_el$17.$$pointerdown = event => event.preventDefault();
|
|
248
|
-
_el$17.$$pointermove = () => focus(index());
|
|
249
|
-
_$use(element => optionRefs[index()] = element, _el$17);
|
|
250
|
-
_$insert(_el$17, _$createComponent(Show, {
|
|
265
|
+
return _$createComponent(Show, {
|
|
251
266
|
get when() {
|
|
252
|
-
return
|
|
267
|
+
return _$memo(() => !!!props.status)() && !loader.error();
|
|
253
268
|
},
|
|
254
|
-
children
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
269
|
+
get children() {
|
|
270
|
+
return _$createComponent(Show, {
|
|
271
|
+
get when() {
|
|
272
|
+
return loader.loading();
|
|
273
|
+
},
|
|
274
|
+
get fallback() {
|
|
275
|
+
return (() => {
|
|
276
|
+
var _el$25 = _$getNextElement(_tmpl$4);
|
|
277
|
+
_$insert(_el$25, (() => {
|
|
278
|
+
var _c$ = _$memo(() => query().length >= 2);
|
|
279
|
+
return () => _c$() ? props.empty ?? selectMessages().noResultsFound : selectMessages().typeToSearch;
|
|
280
|
+
})());
|
|
281
|
+
return _el$25;
|
|
282
|
+
})();
|
|
283
|
+
},
|
|
284
|
+
get children() {
|
|
285
|
+
var _el$21 = _$getNextElement(_tmpl$6),
|
|
286
|
+
_el$22 = _el$21.firstChild,
|
|
287
|
+
_el$23 = _el$22.nextSibling,
|
|
288
|
+
[_el$24, _co$6] = _$getNextMarker(_el$23.nextSibling);
|
|
289
|
+
_$insert(_el$22, () => messages().loading);
|
|
290
|
+
_$insert(_el$21, _$createComponent(For, {
|
|
291
|
+
each: [62, 48, 55],
|
|
292
|
+
children: width => (() => {
|
|
293
|
+
var _el$26 = _$getNextElement(_tmpl$7),
|
|
294
|
+
_el$27 = _el$26.firstChild,
|
|
295
|
+
_el$28 = _el$27.nextSibling;
|
|
296
|
+
_$setStyleProperty(_el$28, "width", `${width}%`);
|
|
297
|
+
return _el$26;
|
|
298
|
+
})()
|
|
299
|
+
}), _el$24, _co$6);
|
|
300
|
+
return _el$21;
|
|
301
|
+
}
|
|
302
|
+
});
|
|
303
|
+
}
|
|
283
304
|
});
|
|
284
|
-
|
|
285
|
-
|
|
305
|
+
},
|
|
306
|
+
children: (id, index) => {
|
|
307
|
+
const first = optionsById().get(id);
|
|
308
|
+
const option = () => optionsById().get(id) ?? first;
|
|
309
|
+
return (() => {
|
|
310
|
+
var _el$29 = _$getNextElement(_tmpl$8),
|
|
311
|
+
_el$34 = _el$29.firstChild,
|
|
312
|
+
[_el$35, _co$8] = _$getNextMarker(_el$34.nextSibling),
|
|
313
|
+
_el$30 = _el$35.nextSibling,
|
|
314
|
+
_el$31 = _el$30.firstChild,
|
|
315
|
+
_el$32 = _el$31.nextSibling,
|
|
316
|
+
[_el$33, _co$7] = _$getNextMarker(_el$32.nextSibling);
|
|
317
|
+
_el$29.$$click = () => select(option());
|
|
318
|
+
_el$29.$$pointerdown = event => event.preventDefault();
|
|
319
|
+
_el$29.$$pointermove = () => focus(index());
|
|
320
|
+
_$use(element => optionRefs[index()] = element, _el$29);
|
|
321
|
+
_$insert(_el$29, _$createComponent(Show, {
|
|
322
|
+
get when() {
|
|
323
|
+
return option().icon;
|
|
324
|
+
},
|
|
325
|
+
children: icon => (() => {
|
|
326
|
+
var _el$36 = _$getNextElement(_tmpl$9);
|
|
327
|
+
_$effect(() => _$className(_el$36, iconClass(icon())));
|
|
328
|
+
return _el$36;
|
|
329
|
+
})()
|
|
330
|
+
}), _el$35, _co$8);
|
|
331
|
+
_$insert(_el$31, () => option().label);
|
|
332
|
+
_$insert(_el$30, _$createComponent(Show, {
|
|
333
|
+
get when() {
|
|
334
|
+
return option().description;
|
|
335
|
+
},
|
|
336
|
+
children: description => (() => {
|
|
337
|
+
var _el$37 = _$getNextElement(_tmpl$0);
|
|
338
|
+
_$insert(_el$37, description);
|
|
339
|
+
return _el$37;
|
|
340
|
+
})()
|
|
341
|
+
}), _el$33, _co$7);
|
|
342
|
+
_$effect(_p$ => {
|
|
343
|
+
var _v$ = `${listboxId}-${index()}`,
|
|
344
|
+
_v$2 = index() === focusedIndex(),
|
|
345
|
+
_v$3 = index() === focusedIndex() ? "true" : undefined;
|
|
346
|
+
_v$ !== _p$.e && _$setAttribute(_el$29, "id", _p$.e = _v$);
|
|
347
|
+
_v$2 !== _p$.t && _$setAttribute(_el$29, "aria-selected", _p$.t = _v$2);
|
|
348
|
+
_v$3 !== _p$.a && _$setAttribute(_el$29, "data-focused", _p$.a = _v$3);
|
|
349
|
+
return _p$;
|
|
350
|
+
}, {
|
|
351
|
+
e: undefined,
|
|
352
|
+
t: undefined,
|
|
353
|
+
a: undefined
|
|
354
|
+
});
|
|
355
|
+
_$runHydrationEvents();
|
|
356
|
+
return _el$29;
|
|
357
|
+
})();
|
|
358
|
+
}
|
|
359
|
+
}), _el$13, _co$4);
|
|
360
|
+
_$insert(_el$8, _$createComponent(Show, {
|
|
361
|
+
get when() {
|
|
362
|
+
return props.footer;
|
|
363
|
+
},
|
|
364
|
+
children: footer => (() => {
|
|
365
|
+
var _el$38 = _$getNextElement(_tmpl$1);
|
|
366
|
+
_$insert(_el$38, footer);
|
|
367
|
+
return _el$38;
|
|
286
368
|
})()
|
|
287
|
-
}), _el$
|
|
369
|
+
}), _el$15, _co$5);
|
|
288
370
|
_$effect(() => _$setAttribute(_el$, "data-invalid", error() ? "true" : undefined));
|
|
289
371
|
_$runHydrationEvents();
|
|
290
372
|
return _el$;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":[],"sources":["inputs/Combobox.tsx"],"sourcesContent":["import { createEffect, createSignal, For, type JSX, Show } from \"solid-js\";\nimport { createFieldMeta, Field, fieldControlAria } from \"../internal/field\";\nimport { useUiMessages } from \"../intl/messages\";\nimport { type ChoiceOption, createChoiceLoader, createChoicePopover, nextEnabledChoiceIndex } from \"./choice\";\nimport type { FieldProps, MaybeAccessor } from \"./field-contract\";\nimport { resolveMaybeAccessor } from \"./field-contract\";\nimport { useSelectMessages } from \"./select-messages\";\n\nexport type ComboboxOption = { id: string; label: string; description?: string; icon?: string };\nexport type ComboboxProps = FieldProps & {\n readOnly?: boolean;\n query?: MaybeAccessor<string>;\n onQueryChange?: (query: string) => void;\n placeholder?: string;\n fetchData: (query: string, signal: AbortSignal) => Promise<ComboboxOption[]>;\n onSelect: (option: ComboboxOption) => void;\n debounceMs?: number;\n};\n\nconst iconClass = (icon: string) => (icon.split(/\\s+/).includes(\"ti\") ? icon : `ti ${icon}`);\n\nexport function Combobox(props: ComboboxProps): JSX.Element {\n const messages = useUiMessages();\n const selectMessages = useSelectMessages();\n const meta = createFieldMeta(props.id);\n const listboxId = `${meta.controlId}-listbox`;\n const [localQuery, setLocalQuery] = createSignal(\"\");\n const query = () => resolveMaybeAccessor(props.query) ?? localQuery();\n const setQuery = (value: string) => {\n setLocalQuery(value);\n props.onQueryChange?.(value);\n };\n const error = () => resolveMaybeAccessor(props.error);\n const [focusedIndex, setFocusedIndex] = createSignal(-1);\n let inputRef: HTMLInputElement | undefined;\n let optionRefs: HTMLButtonElement[] = [];\n const loader = createChoiceLoader(\n () => async (value, signal) => (await props.fetchData(value, signal)).map((option) => ({ ...option, value: option.id })),\n // Cloud debounces at 200ms and then pads the response with a 200ms minimum\n // load time to stop the spinner flickering. The spinner here sits in the\n // chevron slot and stale results stay visible, so there is nothing to pad —\n // 150ms keeps typing responsive without hammering the loader.\n () => props.debounceMs ?? 150,\n );\n const popover = createChoicePopover(() => Boolean(props.disabled || props.readOnly));\n const options = loader.options;\n const focusedOption = () => options()[focusedIndex()];\n const focus = (index: number) => {\n setFocusedIndex(index);\n optionRefs[index]?.scrollIntoView({ block: \"nearest\" });\n };\n /** `eager` loads the currently controlled query on open; typing supplies its\n * own query, so opening from `onInput` skips the duplicate request. */\n const open = (eager = true) => {\n if (props.disabled || props.readOnly || popover.open()) return;\n popover.show();\n if (eager) loader.load(query(), true);\n focus(-1);\n };\n const reset = () => {\n loader.cancel();\n setQuery(\"\");\n focus(-1);\n };\n const close = () => {\n popover.hide();\n reset();\n };\n createEffect(() => {\n if (props.readOnly) {\n popover.hide();\n loader.cancel();\n setFocusedIndex(-1);\n }\n });\n const select = (option: ChoiceOption<string>) => {\n if (props.disabled || props.readOnly) return;\n popover.hide();\n props.onSelect({ id: option.value, label: option.label, description: option.description, icon: option.icon });\n reset();\n inputRef?.focus();\n };\n const onKeyDown = (event: KeyboardEvent) => {\n if (props.disabled || props.readOnly) return;\n if (event.key === \"ArrowDown\" || event.key === \"ArrowUp\") {\n event.preventDefault();\n if (!popover.open()) open();\n else focus(nextEnabledChoiceIndex(options(), focusedIndex(), event.key === \"ArrowDown\" ? 1 : -1));\n } else if (event.key === \"Enter\" && popover.open()) {\n // While the results are open, Enter belongs to them: it never submits an enclosing form, even with no option active.\n event.preventDefault();\n const option = options()[focusedIndex()];\n if (option) select(option);\n } else if ((event.key === \"Escape\" || event.key === \"Tab\") && popover.open()) {\n // Escape is only ours while the list is open; otherwise it has to reach an\n // enclosing dialog or drawer.\n if (event.key === \"Escape\") event.preventDefault();\n close();\n }\n };\n\n return (\n <Field\n class={props.class}\n label={props.label}\n description={props.description}\n error={error()}\n meta={meta}\n required={props.required}\n disabled={props.disabled}\n >\n <div class=\"k2b-combobox\" data-invalid={error() ? \"true\" : undefined}>\n <div ref={popover.setTrigger} class=\"k2b-combobox__input\">\n <i class=\"ti ti-search\" aria-hidden=\"true\" />\n {/* A click, typing, or an arrow key opens the list. Focus alone (Tab, a dialog's initial focus) does not, so Escape still closes the enclosing dialog. */}\n <input\n ref={(element) => {\n inputRef = element;\n }}\n id={meta.controlId}\n type=\"text\"\n value={query()}\n placeholder={props.placeholder ?? messages().search}\n disabled={props.disabled}\n readOnly={props.readOnly}\n aria-readonly={props.readOnly ? \"true\" : undefined}\n role=\"combobox\"\n aria-autocomplete=\"list\"\n aria-expanded={popover.open()}\n aria-controls={listboxId}\n aria-activedescendant={focusedOption() ? `${listboxId}-${focusedIndex()}` : undefined}\n {...fieldControlAria(meta, props)}\n onClick={() => open()}\n onInput={(event) => {\n if (props.disabled || props.readOnly) {\n event.currentTarget.value = query();\n return;\n }\n setQuery(event.currentTarget.value);\n open(false);\n loader.load(event.currentTarget.value);\n focus(-1);\n }}\n onKeyDown={onKeyDown}\n />\n <Show when={loader.loading()} fallback={<i class=\"ti ti-chevron-down\" aria-hidden=\"true\" />}>\n <i class=\"ti ti-loader-2 k2b-spin\" aria-hidden=\"true\" />\n </Show>\n </div>\n <div ref={popover.setPopover} popover=\"manual\" class=\"k2b-choice-popover\">\n <div class=\"k2b-choice-options\" role=\"listbox\" id={listboxId}>\n <Show when={loader.error()}>\n {(message) => (\n <div class=\"k2b-choice-status\" data-tone=\"danger\">\n <span>{message()}</span>\n <button type=\"button\" onClick={loader.retry}>\n {messages().retry}\n </button>\n </div>\n )}\n </Show>\n <For\n each={loader.error() ? [] : options()}\n fallback={\n <div class=\"k2b-choice-status\">{query().length >= 2 ? selectMessages().noResultsFound : selectMessages().typeToSearch}</div>\n }\n >\n {(option, index) => (\n <button\n ref={(element) => (optionRefs[index()] = element)}\n type=\"button\"\n id={`${listboxId}-${index()}`}\n class=\"k2b-choice-option\"\n role=\"option\"\n aria-selected={index() === focusedIndex()}\n data-focused={index() === focusedIndex() ? \"true\" : undefined}\n onPointerMove={() => focus(index())}\n onPointerDown={(event) => event.preventDefault()}\n onClick={() => select(option)}\n >\n <Show when={option.icon}>{(icon) => <i class={iconClass(icon())} aria-hidden=\"true\" />}</Show>\n <span>\n <strong>{option.label}</strong>\n <Show when={option.description}>{(description) => <small>{description()}</small>}</Show>\n </span>\n </button>\n )}\n </For>\n </div>\n </div>\n </div>\n </Field>\n );\n}\n\nexport default Combobox;\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"names":[],"sources":["inputs/Combobox.tsx"],"sourcesContent":["import { createEffect, createMemo, createSignal, For, type JSX, on, Show } from \"solid-js\";\nimport { createFieldMeta, Field, fieldControlAria } from \"../internal/field\";\nimport { useUiMessages } from \"../intl/messages\";\nimport { type ChoiceOption, createChoiceLoader, createChoicePopover, nextEnabledChoiceIndex } from \"./choice\";\nimport type { FieldProps, MaybeAccessor } from \"./field-contract\";\nimport { resolveMaybeAccessor } from \"./field-contract\";\nimport { useSelectMessages } from \"./select-messages\";\n\nexport type ComboboxOption = { id: string; label: string; description?: string; icon?: string };\nexport type ComboboxProps = FieldProps & {\n readOnly?: boolean;\n query?: MaybeAccessor<string>;\n onQueryChange?: (query: string) => void;\n placeholder?: string;\n fetchData: (query: string, signal: AbortSignal) => Promise<ComboboxOption[]>;\n onSelect: (option: ComboboxOption) => void;\n debounceMs?: number;\n /** The query is the field's own value: picking or closing keeps the typed text, and Enter without an active option only closes the list. */\n freeText?: boolean;\n /** Below this many characters nothing loads and the list stays closed. */\n minQueryLength?: number;\n /** This result (by position) is active as soon as results arrive, so Enter takes it. */\n autoHighlight?: number;\n /** Replaces the results with a host-owned notice, such as an exhausted quota; nothing loads while it is set. */\n status?: JSX.Element;\n /** Shown instead of the default text when a search finds nothing. */\n empty?: JSX.Element;\n /** One line under the results, such as their source. */\n footer?: JSX.Element;\n};\n\nconst iconClass = (icon: string) => (icon.split(/\\s+/).includes(\"ti\") ? icon : `ti ${icon}`);\n\nexport function Combobox(props: ComboboxProps): JSX.Element {\n const messages = useUiMessages();\n const selectMessages = useSelectMessages();\n const meta = createFieldMeta(props.id);\n const listboxId = `${meta.controlId}-listbox`;\n const [localQuery, setLocalQuery] = createSignal(\"\");\n const query = () => resolveMaybeAccessor(props.query) ?? localQuery();\n const setQuery = (value: string) => {\n setLocalQuery(value);\n props.onQueryChange?.(value);\n };\n const error = () => resolveMaybeAccessor(props.error);\n const [focusedIndex, setFocusedIndex] = createSignal(-1);\n let inputRef: HTMLInputElement | undefined;\n let optionRefs: HTMLButtonElement[] = [];\n const loader = createChoiceLoader(\n () => async (value, signal) => (await props.fetchData(value, signal)).map((option) => ({ ...option, value: option.id })),\n // Cloud debounces at 200ms and then pads the response with a 200ms minimum\n // load time to stop the spinner flickering. The spinner here sits in the\n // chevron slot and stale results stay visible, so there is nothing to pad —\n // 150ms keeps typing responsive without hammering the loader.\n () => props.debounceMs ?? 150,\n );\n const popover = createChoicePopover(() => Boolean(props.disabled || props.readOnly));\n // A host notice or an error replaces the results; hidden results are never selectable.\n const options = () => (props.status || loader.error() ? [] : loader.options());\n const optionsById = createMemo(() => new Map(options().map((option) => [option.value, option])));\n const focusedOption = () => options()[focusedIndex()];\n const searchable = (value: string) => value.trim().length >= (props.minQueryLength ?? 0);\n const focus = (index: number) => {\n setFocusedIndex(index);\n optionRefs[index]?.scrollIntoView({ block: \"nearest\" });\n };\n /** `eager` loads the currently controlled query on open; typing supplies its\n * own query, so opening from `onInput` skips the duplicate request. */\n const open = (eager = true) => {\n if (props.disabled || props.readOnly || popover.open() || !searchable(query())) return;\n popover.show();\n if (eager && !props.status) loader.load(query(), true);\n focus(-1);\n };\n const reset = () => {\n loader.cancel();\n setQuery(\"\");\n focus(-1);\n };\n const close = () => {\n popover.hide();\n if (!props.freeText) return reset();\n loader.cancel();\n focus(-1);\n };\n createEffect(\n on(options, (list) => {\n const index = props.autoHighlight;\n if (index !== undefined && focusedIndex() < 0 && popover.open() && list.length > 0) setFocusedIndex(Math.min(index, list.length - 1));\n }),\n );\n createEffect(() => {\n if (props.readOnly) {\n popover.hide();\n loader.cancel();\n setFocusedIndex(-1);\n }\n });\n const select = (option: ChoiceOption<string>) => {\n if (props.disabled || props.readOnly) return;\n popover.hide();\n props.onSelect({ id: option.value, label: option.label, description: option.description, icon: option.icon });\n if (props.freeText) {\n loader.cancel();\n focus(-1);\n } else reset();\n inputRef?.focus();\n };\n const onKeyDown = (event: KeyboardEvent) => {\n if (props.disabled || props.readOnly) return;\n if (event.key === \"ArrowDown\" || event.key === \"ArrowUp\") {\n event.preventDefault();\n if (!popover.open()) open();\n else focus(nextEnabledChoiceIndex(options(), focusedIndex(), event.key === \"ArrowDown\" ? 1 : -1));\n } else if (event.key === \"Enter\" && popover.open()) {\n // While the results are open, Enter belongs to them: it never submits an enclosing form, even with no option active.\n event.preventDefault();\n const option = options()[focusedIndex()];\n if (option) select(option);\n else if (props.freeText) close();\n } else if ((event.key === \"Escape\" || event.key === \"Tab\") && popover.open()) {\n // Escape is only ours while the list is open; otherwise it has to reach an\n // enclosing dialog or drawer.\n if (event.key === \"Escape\") event.preventDefault();\n close();\n }\n };\n\n return (\n <Field\n class={props.class}\n label={props.label}\n description={props.description}\n error={error()}\n meta={meta}\n required={props.required}\n disabled={props.disabled}\n >\n <div class=\"k2b-combobox\" data-invalid={error() ? \"true\" : undefined}>\n <div ref={popover.setTrigger} class=\"k2b-combobox__input\">\n <i class=\"ti ti-search\" aria-hidden=\"true\" />\n {/* A click, typing, or an arrow key opens the list. Focus alone (Tab, a dialog's initial focus) does not, so Escape still closes the enclosing dialog. */}\n <input\n ref={(element) => {\n inputRef = element;\n }}\n id={meta.controlId}\n type=\"text\"\n value={query()}\n placeholder={props.placeholder ?? messages().search}\n disabled={props.disabled}\n readOnly={props.readOnly}\n aria-readonly={props.readOnly ? \"true\" : undefined}\n role=\"combobox\"\n autocomplete=\"off\"\n aria-autocomplete=\"list\"\n aria-expanded={popover.open()}\n aria-controls={listboxId}\n aria-activedescendant={focusedOption() ? `${listboxId}-${focusedIndex()}` : undefined}\n {...fieldControlAria(meta, props)}\n onClick={() => open()}\n onInput={(event) => {\n if (props.disabled || props.readOnly) {\n event.currentTarget.value = query();\n return;\n }\n const value = event.currentTarget.value;\n setQuery(value);\n focus(-1);\n if (!searchable(value)) {\n popover.hide();\n loader.cancel();\n return;\n }\n open(false);\n if (!props.status) loader.load(value);\n }}\n onKeyDown={onKeyDown}\n />\n <Show when={loader.loading()} fallback={<i class=\"ti ti-chevron-down\" aria-hidden=\"true\" />}>\n <i class=\"ti ti-loader-2 k2b-spin\" aria-hidden=\"true\" />\n </Show>\n </div>\n <div ref={popover.setPopover} popover=\"manual\" class=\"k2b-choice-popover\">\n <div class=\"k2b-choice-options\" role=\"listbox\" id={listboxId}>\n <Show when={props.status}>{(status) => <div class=\"k2b-choice-status\">{status()}</div>}</Show>\n <Show when={!props.status && loader.error()}>\n {(message) => (\n <div class=\"k2b-choice-status\" data-tone=\"danger\">\n <span>{message()}</span>\n <button type=\"button\" onClick={loader.retry}>\n {messages().retry}\n </button>\n </div>\n )}\n </Show>\n {/* Keyed by option ID, not object: each fetch returns new objects, and a row replaced between press and release\n would swallow the click. */}\n <For\n each={options().map((option) => option.value)}\n fallback={\n <Show when={!props.status && !loader.error()}>\n <Show\n when={loader.loading()}\n fallback={\n <div class=\"k2b-choice-status\">\n {query().length >= 2 ? (props.empty ?? selectMessages().noResultsFound) : selectMessages().typeToSearch}\n </div>\n }\n >\n {/* The first search has nothing to keep visible yet: rows of the final size wait in its place. */}\n <div class=\"k2b-choice-loading\" role=\"status\">\n <span class=\"k2b-sr-only\">{messages().loading}</span>\n <For each={[62, 48, 55]}>\n {(width) => (\n <div class=\"k2b-choice-loading__row\" aria-hidden=\"true\">\n <span class=\"k2b-skeleton\" />\n <span class=\"k2b-skeleton\" style={{ width: `${width}%` }} />\n </div>\n )}\n </For>\n </div>\n </Show>\n </Show>\n }\n >\n {(id, index) => {\n const first = optionsById().get(id)!;\n const option = () => optionsById().get(id) ?? first;\n return (\n <button\n ref={(element) => (optionRefs[index()] = element)}\n type=\"button\"\n id={`${listboxId}-${index()}`}\n class=\"k2b-choice-option\"\n role=\"option\"\n aria-selected={index() === focusedIndex()}\n data-focused={index() === focusedIndex() ? \"true\" : undefined}\n onPointerMove={() => focus(index())}\n onPointerDown={(event) => event.preventDefault()}\n onClick={() => select(option())}\n >\n <Show when={option().icon}>{(icon) => <i class={iconClass(icon())} aria-hidden=\"true\" />}</Show>\n <span>\n <strong>{option().label}</strong>\n <Show when={option().description}>{(description) => <small>{description()}</small>}</Show>\n </span>\n </button>\n );\n }}\n </For>\n </div>\n <Show when={props.footer}>{(footer) => <div class=\"k2b-choice-footer\">{footer()}</div>}</Show>\n </div>\n </div>\n </Field>\n );\n}\n\nexport default Combobox;\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -71,6 +71,7 @@ import { useRichSelectMessages } from "./rich-select-messages";
|
|
|
71
71
|
export const RICH_SELECT_SEARCH_FROM = 8;
|
|
72
72
|
const PHONE_QUERY = "(max-width: 47.999rem)";
|
|
73
73
|
const PLACEHOLDER_ROWS = 4;
|
|
74
|
+
const rowKey = row => row.kind === "heading" ? `heading:${row.id}` : `item:${row.item.value}`;
|
|
74
75
|
const isPhone = () => typeof matchMedia === "function" && matchMedia(PHONE_QUERY).matches;
|
|
75
76
|
function RichSelectVisual(props) {
|
|
76
77
|
return _$createComponent(Switch, {
|
|
@@ -445,6 +446,9 @@ export function RichSelect(props) {
|
|
|
445
446
|
});
|
|
446
447
|
return result;
|
|
447
448
|
});
|
|
449
|
+
// Rows are keyed by heading and value, not by object: a host that rebuilds equal items must not replace the option
|
|
450
|
+
// under a press, which would swallow its click.
|
|
451
|
+
const rowsByKey = createMemo(() => new Map(rows().map(row => [rowKey(row), row])));
|
|
448
452
|
const selected = createMemo(() => {
|
|
449
453
|
const current = value();
|
|
450
454
|
return current === null ? undefined : props.items.find(item => item.value === current);
|
|
@@ -879,7 +883,7 @@ export function RichSelect(props) {
|
|
|
879
883
|
get children() {
|
|
880
884
|
return _$createComponent(For, {
|
|
881
885
|
get each() {
|
|
882
|
-
return rows();
|
|
886
|
+
return rows().map(rowKey);
|
|
883
887
|
},
|
|
884
888
|
get fallback() {
|
|
885
889
|
return (() => {
|
|
@@ -888,80 +892,95 @@ export function RichSelect(props) {
|
|
|
888
892
|
return _el$77;
|
|
889
893
|
})();
|
|
890
894
|
},
|
|
891
|
-
children:
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
895
|
+
children: key => {
|
|
896
|
+
const first = rowsByKey().get(key);
|
|
897
|
+
if (first.kind === "heading") {
|
|
898
|
+
const label = () => {
|
|
899
|
+
const current = rowsByKey().get(key);
|
|
900
|
+
return current?.kind === "heading" ? current.label : first.label;
|
|
901
|
+
};
|
|
902
|
+
return (() => {
|
|
903
|
+
var _el$78 = _$getNextElement(_tmpl$26);
|
|
904
|
+
_$insert(_el$78, label);
|
|
905
|
+
return _el$78;
|
|
906
|
+
})();
|
|
907
|
+
}
|
|
908
|
+
const entry = () => {
|
|
909
|
+
const current = rowsByKey().get(key);
|
|
910
|
+
return current?.kind === "item" ? current : first;
|
|
906
911
|
};
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
912
|
+
return (// biome-ignore lint/a11y/useKeyWithClickEvents: the trigger or search field handles the keys through aria-activedescendant.
|
|
913
|
+
(() => {
|
|
914
|
+
var _el$79 = _$getNextElement(_tmpl$27),
|
|
915
|
+
_el$81 = _el$79.firstChild,
|
|
916
|
+
[_el$82, _co$13] = _$getNextMarker(_el$81.nextSibling),
|
|
917
|
+
_el$83 = _el$82.nextSibling,
|
|
918
|
+
[_el$84, _co$14] = _$getNextMarker(_el$83.nextSibling),
|
|
919
|
+
_el$80 = _el$84.nextSibling;
|
|
920
|
+
_el$79.$$click = () => choose(entry().item);
|
|
921
|
+
_el$79.$$pointermove = () => {
|
|
922
|
+
if (active() !== entry().index) setActive(entry().index);
|
|
923
|
+
};
|
|
924
|
+
_$insert(_el$79, _$createComponent(Show, {
|
|
913
925
|
get when() {
|
|
914
|
-
return
|
|
915
|
-
},
|
|
916
|
-
get fallback() {
|
|
917
|
-
return _$getNextElement(_tmpl$);
|
|
926
|
+
return anyVisual();
|
|
918
927
|
},
|
|
919
928
|
get children() {
|
|
920
|
-
return _$createComponent(
|
|
921
|
-
get
|
|
922
|
-
return
|
|
929
|
+
return _$createComponent(Show, {
|
|
930
|
+
get when() {
|
|
931
|
+
return hasVisual(entry().item);
|
|
932
|
+
},
|
|
933
|
+
get fallback() {
|
|
934
|
+
return _$getNextElement(_tmpl$);
|
|
935
|
+
},
|
|
936
|
+
get children() {
|
|
937
|
+
return _$createComponent(RichSelectVisual, {
|
|
938
|
+
get item() {
|
|
939
|
+
return entry().item;
|
|
940
|
+
}
|
|
941
|
+
});
|
|
923
942
|
}
|
|
924
943
|
});
|
|
925
944
|
}
|
|
945
|
+
}), _el$82, _co$13);
|
|
946
|
+
_$insert(_el$79, _$createComponent(RichSelectRowText, {
|
|
947
|
+
get item() {
|
|
948
|
+
return entry().item;
|
|
949
|
+
},
|
|
950
|
+
get labelId() {
|
|
951
|
+
return `${optionId(entry().index)}-label`;
|
|
952
|
+
},
|
|
953
|
+
get lineId() {
|
|
954
|
+
return `${optionId(entry().index)}-line`;
|
|
955
|
+
}
|
|
956
|
+
}), _el$84, _co$14);
|
|
957
|
+
_$effect(_p$ => {
|
|
958
|
+
var _v$25 = optionId(entry().index),
|
|
959
|
+
_v$26 = entry().item.value === value(),
|
|
960
|
+
_v$27 = entry().item.disabledReason ? "true" : undefined,
|
|
961
|
+
_v$28 = `${optionId(entry().index)}-label`,
|
|
962
|
+
_v$29 = [entry().item.disabledReason || entry().item.description ? `${optionId(entry().index)}-line` : "", withPreview() && entry().index === active() ? previewId : ""].filter(Boolean).join(" ") || undefined,
|
|
963
|
+
_v$30 = entry().index === active() ? "true" : undefined;
|
|
964
|
+
_v$25 !== _p$.e && _$setAttribute(_el$79, "id", _p$.e = _v$25);
|
|
965
|
+
_v$26 !== _p$.t && _$setAttribute(_el$79, "aria-selected", _p$.t = _v$26);
|
|
966
|
+
_v$27 !== _p$.a && _$setAttribute(_el$79, "aria-disabled", _p$.a = _v$27);
|
|
967
|
+
_v$28 !== _p$.o && _$setAttribute(_el$79, "aria-labelledby", _p$.o = _v$28);
|
|
968
|
+
_v$29 !== _p$.i && _$setAttribute(_el$79, "aria-describedby", _p$.i = _v$29);
|
|
969
|
+
_v$30 !== _p$.n && _$setAttribute(_el$79, "data-active", _p$.n = _v$30);
|
|
970
|
+
return _p$;
|
|
971
|
+
}, {
|
|
972
|
+
e: undefined,
|
|
973
|
+
t: undefined,
|
|
974
|
+
a: undefined,
|
|
975
|
+
o: undefined,
|
|
976
|
+
i: undefined,
|
|
977
|
+
n: undefined
|
|
926
978
|
});
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
},
|
|
933
|
-
get labelId() {
|
|
934
|
-
return `${optionId(row.index)}-label`;
|
|
935
|
-
},
|
|
936
|
-
get lineId() {
|
|
937
|
-
return `${optionId(row.index)}-line`;
|
|
938
|
-
}
|
|
939
|
-
}), _el$84, _co$14);
|
|
940
|
-
_$effect(_p$ => {
|
|
941
|
-
var _v$25 = optionId(row.index),
|
|
942
|
-
_v$26 = row.item.value === value(),
|
|
943
|
-
_v$27 = row.item.disabledReason ? "true" : undefined,
|
|
944
|
-
_v$28 = `${optionId(row.index)}-label`,
|
|
945
|
-
_v$29 = [row.item.disabledReason || row.item.description ? `${optionId(row.index)}-line` : "", withPreview() && row.index === active() ? previewId : ""].filter(Boolean).join(" ") || undefined,
|
|
946
|
-
_v$30 = row.index === active() ? "true" : undefined;
|
|
947
|
-
_v$25 !== _p$.e && _$setAttribute(_el$79, "id", _p$.e = _v$25);
|
|
948
|
-
_v$26 !== _p$.t && _$setAttribute(_el$79, "aria-selected", _p$.t = _v$26);
|
|
949
|
-
_v$27 !== _p$.a && _$setAttribute(_el$79, "aria-disabled", _p$.a = _v$27);
|
|
950
|
-
_v$28 !== _p$.o && _$setAttribute(_el$79, "aria-labelledby", _p$.o = _v$28);
|
|
951
|
-
_v$29 !== _p$.i && _$setAttribute(_el$79, "aria-describedby", _p$.i = _v$29);
|
|
952
|
-
_v$30 !== _p$.n && _$setAttribute(_el$79, "data-active", _p$.n = _v$30);
|
|
953
|
-
return _p$;
|
|
954
|
-
}, {
|
|
955
|
-
e: undefined,
|
|
956
|
-
t: undefined,
|
|
957
|
-
a: undefined,
|
|
958
|
-
o: undefined,
|
|
959
|
-
i: undefined,
|
|
960
|
-
n: undefined
|
|
961
|
-
});
|
|
962
|
-
_$runHydrationEvents();
|
|
963
|
-
return _el$79;
|
|
964
|
-
})()
|
|
979
|
+
_$runHydrationEvents();
|
|
980
|
+
return _el$79;
|
|
981
|
+
})()
|
|
982
|
+
);
|
|
983
|
+
}
|
|
965
984
|
});
|
|
966
985
|
}
|
|
967
986
|
}), _el$60, _co$8);
|