@rcarls/rc-select 0.2.0 → 0.3.1
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/README.md +4 -4
- package/dist/custom-elements.json +153 -75
- package/dist/{rc-select-BumY2uQl.js → rc-select-Bu4ukw92.js} +235 -122
- package/dist/rc-select-Bu4ukw92.js.map +1 -0
- package/dist/rc-select-define.js +1 -1
- package/dist/rc-select.js +1 -1
- package/dist/types/packages/rc-select/src/rc-select.d.ts +190 -37
- package/package.json +8 -11
- package/dist/demo.css +0 -85
- package/dist/demo.js +0 -40
- package/dist/rc-select-BumY2uQl.js.map +0 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { css as
|
|
2
|
-
import { property as n, query as
|
|
3
|
-
import { ActiveDescendantController as
|
|
4
|
-
const
|
|
1
|
+
import { css as f, LitElement as b, nothing as _, html as h } from "lit";
|
|
2
|
+
import { property as n, query as p, state as d } from "lit/decorators.js";
|
|
3
|
+
import { NativeChildController as g, ActiveDescendantController as m, AnchorController as y } from "@rcarls/rc-common";
|
|
4
|
+
const x = f`
|
|
5
5
|
:host {
|
|
6
6
|
display: inline-block;
|
|
7
7
|
}
|
|
@@ -19,12 +19,15 @@ const g = v`
|
|
|
19
19
|
flex-wrap: wrap;
|
|
20
20
|
gap: var(--rc-select-gap, var(--rc-control-gap, 0.25em));
|
|
21
21
|
min-block-size: var(--rc-select-control-block-size, var(--rc-control-block-size, auto));
|
|
22
|
-
padding: var(--rc-select-padding-block, var(--rc-control-padding-block,
|
|
23
|
-
var(--rc-select-padding-inline, var(--rc-control-padding-inline,
|
|
22
|
+
padding: var(--rc-select-padding-block, var(--rc-control-padding-block, 1px))
|
|
23
|
+
var(--rc-select-padding-inline, var(--rc-control-padding-inline, 4px));
|
|
24
24
|
min-width: 8em;
|
|
25
25
|
cursor: default;
|
|
26
26
|
user-select: none;
|
|
27
|
-
border: var(
|
|
27
|
+
border: var(
|
|
28
|
+
--rc-select-border,
|
|
29
|
+
var(--rc-border, 1px solid var(--rc-border-color, ButtonBorder))
|
|
30
|
+
);
|
|
28
31
|
border-radius: var(--rc-select-radius, var(--rc-control-radius, var(--rc-radius-sm, 0.125em)));
|
|
29
32
|
background: var(--rc-field, Field);
|
|
30
33
|
color: var(--rc-field-text, FieldText);
|
|
@@ -51,9 +54,12 @@ const g = v`
|
|
|
51
54
|
white-space: nowrap;
|
|
52
55
|
}
|
|
53
56
|
|
|
54
|
-
[part='toggle-
|
|
57
|
+
[part='toggle-indicator'] {
|
|
55
58
|
flex-shrink: 0;
|
|
56
|
-
|
|
59
|
+
display: inline-flex;
|
|
60
|
+
align-items: center;
|
|
61
|
+
justify-content: center;
|
|
62
|
+
inline-size: var(--rc-select-toggle-indicator-size, 1.1em);
|
|
57
63
|
}
|
|
58
64
|
|
|
59
65
|
/* Chips — the whole chip is the remove button for a larger touch target */
|
|
@@ -61,9 +67,11 @@ const g = v`
|
|
|
61
67
|
display: inline-flex;
|
|
62
68
|
align-items: center;
|
|
63
69
|
gap: var(--rc-select-chip-gap, calc(var(--rc-control-gap, 0.25em) * 0.8));
|
|
64
|
-
padding: var(--rc-select-chip-padding-block, 0.1em)
|
|
65
|
-
|
|
66
|
-
|
|
70
|
+
padding: var(--rc-select-chip-padding-block, 0.1em) var(--rc-select-chip-padding-inline, 0.3em);
|
|
71
|
+
border: var(
|
|
72
|
+
--rc-select-chip-border,
|
|
73
|
+
var(--rc-border, 1px solid var(--rc-border-color, ButtonBorder))
|
|
74
|
+
);
|
|
67
75
|
border-radius: var(--rc-select-chip-radius, var(--rc-radius-md, 0.25em));
|
|
68
76
|
background: var(--rc-button-bg, ButtonFace);
|
|
69
77
|
color: var(--rc-button-text, ButtonText);
|
|
@@ -92,8 +100,8 @@ const g = v`
|
|
|
92
100
|
pointer-events: none;
|
|
93
101
|
}
|
|
94
102
|
|
|
95
|
-
/*
|
|
96
|
-
slot[name
|
|
103
|
+
/* Hide the default slot — visually suppresses the slotted native <select> */
|
|
104
|
+
slot:not([name]) {
|
|
97
105
|
display: none;
|
|
98
106
|
}
|
|
99
107
|
|
|
@@ -102,44 +110,44 @@ const g = v`
|
|
|
102
110
|
max-height: var(--rc-select-max-height, 20em);
|
|
103
111
|
overflow-y: auto;
|
|
104
112
|
background: var(--rc-surface, Canvas);
|
|
105
|
-
border: var(
|
|
113
|
+
border: var(
|
|
114
|
+
--rc-select-listbox-border,
|
|
115
|
+
var(--rc-border, 1px solid var(--rc-border-color, ButtonBorder))
|
|
116
|
+
);
|
|
106
117
|
border-radius: var(--rc-select-listbox-radius, var(--rc-control-radius, 0));
|
|
107
|
-
box-shadow: var(
|
|
118
|
+
box-shadow: var(
|
|
119
|
+
--rc-select-shadow,
|
|
120
|
+
var(--rc-shadow, 0 2px 8px color-mix(in srgb, CanvasText 15%, transparent))
|
|
121
|
+
);
|
|
108
122
|
color: var(--rc-field-text, FieldText);
|
|
109
123
|
padding-block: var(--rc-select-listbox-padding-block, var(--rc-control-padding-block, 0.25em));
|
|
124
|
+
--rc-listbox-option-gap: var(--rc-item-gap, 0.4em);
|
|
125
|
+
--rc-listbox-option-padding-block: var(--rc-item-padding-block, 0.3em);
|
|
126
|
+
--rc-listbox-option-padding-inline: var(--rc-item-padding-inline, 0.75em);
|
|
127
|
+
--rc-listbox-hover-bg: var(--rc-highlight, Highlight);
|
|
128
|
+
--rc-listbox-hover-color: var(--rc-highlight-text, HighlightText);
|
|
129
|
+
--rc-listbox-active-bg: var(--rc-highlight, Highlight);
|
|
130
|
+
--rc-listbox-active-color: var(--rc-highlight-text, HighlightText);
|
|
131
|
+
--rc-listbox-selected-bg: var(--rc-highlight, Highlight);
|
|
132
|
+
--rc-listbox-selected-color: var(--rc-highlight-text, HighlightText);
|
|
133
|
+
--rc-listbox-disabled-opacity: var(--rc-disabled-opacity, 0.5);
|
|
110
134
|
|
|
111
135
|
&:not(:popover-open) {
|
|
112
136
|
display: none;
|
|
113
137
|
}
|
|
114
138
|
}
|
|
115
139
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
align-items: center;
|
|
120
|
-
gap: var(--rc-item-gap, 0.4em);
|
|
121
|
-
padding: var(--rc-item-padding-block, 0.3em) var(--rc-item-padding-inline, 0.75em);
|
|
122
|
-
cursor: default;
|
|
123
|
-
|
|
124
|
-
/* display: flex overrides [hidden]'s browser-default display:none — restore it explicitly */
|
|
125
|
-
&[hidden] { display: none; }
|
|
126
|
-
|
|
127
|
-
&:not([hidden]):not([aria-disabled='true']):hover {
|
|
128
|
-
background: var(--rc-highlight, Highlight);
|
|
129
|
-
color: var(--rc-highlight-text, HighlightText);
|
|
130
|
-
}
|
|
140
|
+
rc-listbox [part~='option'][hidden] {
|
|
141
|
+
display: none;
|
|
142
|
+
}
|
|
131
143
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
outline-offset: -2px;
|
|
137
|
-
}
|
|
144
|
+
rc-listbox [part~='option'][data-active]:not([aria-disabled='true']) {
|
|
145
|
+
outline: var(--rc-focus-ring, 2px solid var(--rc-accent, Highlight));
|
|
146
|
+
outline-offset: -2px;
|
|
147
|
+
}
|
|
138
148
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
cursor: not-allowed;
|
|
142
|
-
}
|
|
149
|
+
rc-listbox [part~='option'][aria-disabled='true'] {
|
|
150
|
+
cursor: not-allowed;
|
|
143
151
|
}
|
|
144
152
|
|
|
145
153
|
/* Selection checkmark — reserves space whether visible or not */
|
|
@@ -162,17 +170,23 @@ const g = v`
|
|
|
162
170
|
padding-top: 0.3em;
|
|
163
171
|
}
|
|
164
172
|
`;
|
|
165
|
-
var
|
|
166
|
-
for (var s = void 0, r =
|
|
167
|
-
(l =
|
|
168
|
-
return s &&
|
|
173
|
+
var k = Object.defineProperty, a = (v, e, t, i) => {
|
|
174
|
+
for (var s = void 0, r = v.length - 1, l; r >= 0; r--)
|
|
175
|
+
(l = v[r]) && (s = l(e, t, s) || s);
|
|
176
|
+
return s && k(e, t, s), s;
|
|
169
177
|
};
|
|
170
|
-
const
|
|
178
|
+
const u = class u extends b {
|
|
171
179
|
constructor() {
|
|
172
|
-
super(...arguments), this.open = !1, this.multiple = !1, this.disabled = !1, this.placeholder = "", this.display = "auto", this._selectedValues = /* @__PURE__ */ new Set(), this._chipNavIndex = -1, this._options = [], this._selectRef = null, this.
|
|
180
|
+
super(...arguments), this.open = !1, this.multiple = !1, this.disabled = !1, this.placeholder = "", this.display = "auto", this._selectedValues = /* @__PURE__ */ new Set(), this._chipNavIndex = -1, this._options = [], this._selectRef = null, this._selectController = new g(this, {
|
|
181
|
+
selector: ":scope > select",
|
|
182
|
+
observe: !0,
|
|
183
|
+
onChange: (e) => this._setupSelect(e),
|
|
184
|
+
onMissing: () => {
|
|
185
|
+
}
|
|
186
|
+
}), this._mutationObserver = null, this._selectionInitialized = !1, this._typeAheadBuffer = "", this._typeAheadTimer = 0, this._activeDescendantCtrl = new m(this, {
|
|
173
187
|
host: () => this._$trigger ?? null,
|
|
174
188
|
items: () => this._$listbox?.navigableItems ?? []
|
|
175
|
-
}), this._anchorCtrl = new
|
|
189
|
+
}), this._anchorCtrl = new y(this, {
|
|
176
190
|
anchor: () => this._$anchor ?? null,
|
|
177
191
|
floating: () => this._$listbox ?? null,
|
|
178
192
|
shadowHost: () => this,
|
|
@@ -192,16 +206,20 @@ const d = class d extends f {
|
|
|
192
206
|
capture: !0
|
|
193
207
|
}), this._mutationObserver?.disconnect();
|
|
194
208
|
}
|
|
195
|
-
|
|
209
|
+
updated(e) {
|
|
210
|
+
super.updated(e), this.toggleAttribute("has-value", this._selectedValues.size > 0);
|
|
211
|
+
}
|
|
212
|
+
/** Opens the popup listbox if not already open or disabled. */
|
|
196
213
|
openPopup() {
|
|
197
|
-
this.open || this.disabled || (this.open = !0, this._$listbox.showPopover(), this._anchorCtrl.update(), this.dispatchEvent(
|
|
198
|
-
new CustomEvent("rc-select-open", { bubbles: !0, composed: !0 })
|
|
199
|
-
), this.requestUpdate());
|
|
214
|
+
this.open || this.disabled || (this.open = !0, this._$listbox.showPopover(), this._anchorCtrl.update(), this.dispatchEvent(new CustomEvent("rc-select-open", { bubbles: !0, composed: !0 })), this.requestUpdate());
|
|
200
215
|
}
|
|
216
|
+
/**
|
|
217
|
+
* Closes the popup listbox.
|
|
218
|
+
*
|
|
219
|
+
* @param returnFocus - When `true` (default), returns focus to the trigger.
|
|
220
|
+
*/
|
|
201
221
|
closePopup(e = !0) {
|
|
202
|
-
this.open && (this.open = !1, this._$listbox.hidePopover(), this.
|
|
203
|
-
new CustomEvent("rc-select-close", { bubbles: !0, composed: !0 })
|
|
204
|
-
));
|
|
222
|
+
this.open && (this.open = !1, this._$listbox.hidePopover(), this._activeDescendantCtrl.clear(), e && this._$trigger?.focus(), this.dispatchEvent(new CustomEvent("rc-select-close", { bubbles: !0, composed: !0 })));
|
|
205
223
|
}
|
|
206
224
|
/**
|
|
207
225
|
* Current selection. Host writes update selection silently; user interaction
|
|
@@ -238,35 +256,49 @@ const d = class d extends f {
|
|
|
238
256
|
get selectedValues() {
|
|
239
257
|
return [...this._selectedValues];
|
|
240
258
|
}
|
|
259
|
+
/** `ListboxOption` objects for the current selection; falls back to label-only stubs for unknown values. */
|
|
241
260
|
get selectedOptions() {
|
|
242
261
|
return this._selectedOptionsFor(this.selectedValues);
|
|
243
262
|
}
|
|
263
|
+
/**
|
|
264
|
+
* Applies an already-normalized array of values as the current selection.
|
|
265
|
+
*
|
|
266
|
+
* In single-select mode only the first value is kept. Syncs `_$listbox` and the
|
|
267
|
+
* native `<select>` but does NOT dispatch `rc-select-change`.
|
|
268
|
+
*/
|
|
244
269
|
_applySelection(e) {
|
|
245
270
|
const t = this.multiple ? e : e.slice(0, 1);
|
|
246
271
|
this._selectedValues = new Set(t), this._$listbox?.setSelectedValues(t), this._syncNativeSelect(), this.requestUpdate();
|
|
247
272
|
}
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
this.
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
273
|
+
/**
|
|
274
|
+
* Resolves the slotted `<select>` on every `slotchange`, wires `_mutationObserver`,
|
|
275
|
+
* and seeds initial state via `queueMicrotask` to stay safe inside framework reactive passes.
|
|
276
|
+
*/
|
|
277
|
+
_handleSelectSlotChange() {
|
|
278
|
+
this._selectController.sync();
|
|
279
|
+
}
|
|
280
|
+
_setupSelect(e) {
|
|
281
|
+
this._mutationObserver?.disconnect(), this._mutationObserver = null, this._selectRef = e ? new WeakRef(e) : null, e && queueMicrotask(() => {
|
|
282
|
+
e.isConnected && (this.multiple = e.multiple, this.disabled = e.disabled, this._syncOptionsFromSelect(e), this._mutationObserver = new MutationObserver(() => {
|
|
283
|
+
const t = this._selectRef?.deref();
|
|
284
|
+
if (t) {
|
|
285
|
+
if (this.multiple = t.multiple, this.disabled = t.disabled, this._propertyOptions !== void 0) {
|
|
258
286
|
this._applySelectionFromCurrentSource();
|
|
259
287
|
return;
|
|
260
288
|
}
|
|
261
|
-
this._syncOptionsFromSelect(
|
|
289
|
+
this._syncOptionsFromSelect(t);
|
|
262
290
|
}
|
|
263
|
-
}), this._mutationObserver.observe(
|
|
291
|
+
}), this._mutationObserver.observe(e, {
|
|
264
292
|
childList: !0,
|
|
265
293
|
subtree: !0,
|
|
266
294
|
attributes: !0
|
|
267
|
-
}), this._syncAccessibleName(
|
|
295
|
+
}), this._syncAccessibleName(e));
|
|
268
296
|
});
|
|
269
297
|
}
|
|
298
|
+
/**
|
|
299
|
+
* Derives options from `$select` (or defers to `_propertyOptions` when set)
|
|
300
|
+
* and re-applies selection from the current authoritative source.
|
|
301
|
+
*/
|
|
270
302
|
_syncOptionsFromSelect(e) {
|
|
271
303
|
if (this._propertyOptions !== void 0) {
|
|
272
304
|
this._syncOptions(this._propertyOptions), this._mirrorOptionsToNativeSelect(), this._applySelectionFromCurrentSource();
|
|
@@ -275,6 +307,10 @@ const d = class d extends f {
|
|
|
275
307
|
const t = this._optionsFromSelect(e);
|
|
276
308
|
this._syncOptions(t), this._applySelectionFromCurrentSource(), this._syncAccessibleName(e);
|
|
277
309
|
}
|
|
310
|
+
/**
|
|
311
|
+
* Picks the correct selection source in priority order:
|
|
312
|
+
* controlled `_value` → `_defaultValue` → native `<select>` default/current state.
|
|
313
|
+
*/
|
|
278
314
|
_applySelectionFromCurrentSource() {
|
|
279
315
|
if (this._value !== void 0) {
|
|
280
316
|
this._applySelection(this._normalizeValue(this._value));
|
|
@@ -287,14 +323,22 @@ const d = class d extends f {
|
|
|
287
323
|
const e = this._selectionInitialized ? this._selectedValuesFromNativeSelect() : this._defaultSelectedValuesFromNativeSelect();
|
|
288
324
|
this._selectionInitialized = !0, this._applySelection(e);
|
|
289
325
|
}
|
|
326
|
+
/** Writes `_options` and pushes the list to `_$listbox` when it is mounted. */
|
|
290
327
|
_syncOptions(e) {
|
|
291
328
|
this._options = [...e], this._$listbox && (this._$listbox.options = this._options);
|
|
292
329
|
}
|
|
330
|
+
/** Returns `_propertyOptions` when set; otherwise reads live from the slotted `<select>`. */
|
|
293
331
|
_currentOptions() {
|
|
294
|
-
if (this._propertyOptions !== void 0)
|
|
332
|
+
if (this._propertyOptions !== void 0)
|
|
333
|
+
return this._propertyOptions;
|
|
295
334
|
const e = this._selectRef?.deref();
|
|
296
335
|
return e ? this._optionsFromSelect(e) : [];
|
|
297
336
|
}
|
|
337
|
+
/**
|
|
338
|
+
* Maps non-empty native `<option>` nodes to `ListboxOption` objects.
|
|
339
|
+
*
|
|
340
|
+
* Options with empty `value` are skipped (placeholder guard).
|
|
341
|
+
*/
|
|
298
342
|
_optionsFromSelect(e) {
|
|
299
343
|
const t = [];
|
|
300
344
|
for (const i of e.options)
|
|
@@ -305,14 +349,22 @@ const d = class d extends f {
|
|
|
305
349
|
});
|
|
306
350
|
return t;
|
|
307
351
|
}
|
|
352
|
+
/** Returns values of currently selected `<option>` nodes; falls back to `selectedValues` when no native select is present. */
|
|
308
353
|
_selectedValuesFromNativeSelect() {
|
|
309
354
|
const e = this._selectRef?.deref();
|
|
310
355
|
return e ? Array.from(e.selectedOptions).map((t) => t.value).filter(Boolean) : this.selectedValues;
|
|
311
356
|
}
|
|
357
|
+
/** Returns values of `defaultSelected` `<option>` nodes (author `selected` attribute); falls back to `selectedValues`. */
|
|
312
358
|
_defaultSelectedValuesFromNativeSelect() {
|
|
313
359
|
const e = this._selectRef?.deref();
|
|
314
360
|
return e ? Array.from(e.options).filter((t) => t.defaultSelected).map((t) => t.value).filter(Boolean) : this.selectedValues;
|
|
315
361
|
}
|
|
362
|
+
/**
|
|
363
|
+
* Rebuilds native `<select>` options from `_propertyOptions`.
|
|
364
|
+
*
|
|
365
|
+
* Only runs when `_propertyOptions` is set; pauses then resumes `_mutationObserver`
|
|
366
|
+
* while writing to avoid re-entrant sync.
|
|
367
|
+
*/
|
|
316
368
|
_mirrorOptionsToNativeSelect() {
|
|
317
369
|
const e = this._selectRef?.deref();
|
|
318
370
|
if (!(!e || this._propertyOptions === void 0)) {
|
|
@@ -328,44 +380,69 @@ const d = class d extends f {
|
|
|
328
380
|
});
|
|
329
381
|
}
|
|
330
382
|
}
|
|
383
|
+
/**
|
|
384
|
+
* Upserts a single option into `_options` (and `_propertyOptions` when set)
|
|
385
|
+
* and adds the corresponding `<option>` to the native `<select>` if absent.
|
|
386
|
+
*/
|
|
331
387
|
_addOption(e) {
|
|
332
388
|
const t = this._options.some((r) => r.value === e.value) ? this._options.map((r) => r.value === e.value ? e : r) : [...this._options, e];
|
|
333
389
|
this._propertyOptions !== void 0 && (this._propertyOptions = t), this._syncOptions(t);
|
|
334
390
|
const i = this._selectRef?.deref();
|
|
335
|
-
if (!i || Array.from(i.options).some((r) => r.value === e.value))
|
|
391
|
+
if (!i || Array.from(i.options).some((r) => r.value === e.value))
|
|
392
|
+
return;
|
|
336
393
|
const s = document.createElement("option");
|
|
337
394
|
s.value = e.value, s.text = e.label, s.disabled = e.disabled ?? !1, s.selected = this._selectedValues.has(e.value), i.add(s);
|
|
338
395
|
}
|
|
396
|
+
/** Coerces `RCSelectValue` (string or string[]) to `string[]`; returns `[]` for empty-string singles. */
|
|
339
397
|
_normalizeValue(e) {
|
|
340
398
|
return Array.isArray(e) ? e : e ? [e] : [];
|
|
341
399
|
}
|
|
400
|
+
/**
|
|
401
|
+
* Copies `aria-label` or first-label text from the native `<select>` to `_$trigger`.
|
|
402
|
+
*
|
|
403
|
+
* No-op when the trigger already has an explicit `aria-label`.
|
|
404
|
+
*/
|
|
342
405
|
_syncAccessibleName(e) {
|
|
343
|
-
if (!this._$trigger || this._$trigger.hasAttribute("aria-label"))
|
|
406
|
+
if (!this._$trigger || this._$trigger.hasAttribute("aria-label"))
|
|
407
|
+
return;
|
|
344
408
|
const t = e.getAttribute("aria-label") ?? e.labels?.[0]?.textContent?.trim() ?? null;
|
|
345
409
|
t ? this._$trigger.setAttribute("aria-label", t) : this._$trigger.removeAttribute("aria-label");
|
|
346
410
|
}
|
|
347
|
-
|
|
411
|
+
/**
|
|
412
|
+
* Handles `rc-listbox-change` from the popup.
|
|
413
|
+
*
|
|
414
|
+
* Stops propagation, mutates `_selectedValues`, syncs state, and fires
|
|
415
|
+
* `rc-select-change`.
|
|
416
|
+
*/
|
|
348
417
|
_handleListboxChange(e) {
|
|
349
|
-
const
|
|
350
|
-
if (
|
|
418
|
+
const t = e.detail;
|
|
419
|
+
if (t.reason === "action") {
|
|
420
|
+
e.stopPropagation();
|
|
421
|
+
return;
|
|
422
|
+
}
|
|
423
|
+
const { optionValue: i, value: s, selected: r } = t, l = i ?? (Array.isArray(s) ? s.at(-1) : s);
|
|
424
|
+
if (l) {
|
|
351
425
|
if (e.stopPropagation(), this.multiple) {
|
|
352
|
-
const
|
|
353
|
-
|
|
426
|
+
const c = new Set(this._selectedValues);
|
|
427
|
+
r ? c.add(l) : c.delete(l), this._selectedValues = c;
|
|
354
428
|
} else
|
|
355
|
-
this._selectedValues =
|
|
429
|
+
this._selectedValues = r ? /* @__PURE__ */ new Set([l]) : /* @__PURE__ */ new Set(), r && this.closePopup();
|
|
356
430
|
this._selectionInitialized = !0, this._syncNativeSelect(), this._$listbox.setSelectedValues(this.selectedValues), this._dispatchChange();
|
|
357
431
|
}
|
|
358
432
|
}
|
|
433
|
+
/** Removes a single value from `_selectedValues`, syncs the listbox and native select, and dispatches `rc-select-change`. */
|
|
359
434
|
_removeValue(e) {
|
|
360
435
|
const t = new Set(this._selectedValues);
|
|
361
436
|
t.delete(e), this._selectedValues = t, this._$listbox.setSelectedValues([...t]), this._selectionInitialized = !0, this._syncNativeSelect(), this._dispatchChange();
|
|
362
437
|
}
|
|
438
|
+
/** Flips `selected` on each `<option>` in the native `<select>` to match `_selectedValues`; no-op when no native select is present. */
|
|
363
439
|
_syncNativeSelect() {
|
|
364
440
|
const e = this._selectRef?.deref();
|
|
365
441
|
if (e)
|
|
366
442
|
for (const t of e.options)
|
|
367
443
|
t.selected = this._selectedValues.has(t.value);
|
|
368
444
|
}
|
|
445
|
+
/** Constructs and dispatches `rc-select-change` with current `value`, `selectedValues`, and `selectedOptions`. */
|
|
369
446
|
_dispatchChange() {
|
|
370
447
|
this.dispatchEvent(
|
|
371
448
|
new CustomEvent("rc-select-change", {
|
|
@@ -379,26 +456,33 @@ const d = class d extends f {
|
|
|
379
456
|
})
|
|
380
457
|
);
|
|
381
458
|
}
|
|
459
|
+
/** Maps value strings to `ListboxOption` objects from `_options`; creates label-only fallback stubs for unknown values. */
|
|
382
460
|
_selectedOptionsFor(e) {
|
|
383
|
-
return e.map((t) => this._options.find(
|
|
461
|
+
return e.map((t) => this._options.find(
|
|
462
|
+
(i) => i.kind !== "action" && i.value === t
|
|
463
|
+
) ?? {
|
|
384
464
|
value: t,
|
|
385
465
|
label: t
|
|
386
466
|
});
|
|
387
467
|
}
|
|
388
|
-
|
|
468
|
+
/** Resolved display mode after `auto` pointer-detection: `'chips'` on fine-pointer devices, `'compact'` on coarse. */
|
|
389
469
|
get _effectiveDisplay() {
|
|
390
470
|
return this.display === "chips" ? "chips" : this.display === "compact" || window.matchMedia("(pointer: coarse)").matches ? "compact" : "chips";
|
|
391
471
|
}
|
|
472
|
+
/** Looks up the display label for `value` from native `<select>` option text; returns `value` itself as a fallback. */
|
|
392
473
|
_labelFor(e) {
|
|
393
474
|
const t = this._selectRef?.deref();
|
|
394
475
|
if (t) {
|
|
395
476
|
for (const i of t.options)
|
|
396
|
-
if (i.value === e)
|
|
477
|
+
if (i.value === e)
|
|
478
|
+
return i.text;
|
|
397
479
|
}
|
|
398
480
|
return e;
|
|
399
481
|
}
|
|
482
|
+
/** Text shown in the trigger's value-display area; returns placeholder when chips are active or nothing is selected. */
|
|
400
483
|
get _displayLabel() {
|
|
401
|
-
if (this._selectedValues.size === 0)
|
|
484
|
+
if (this._selectedValues.size === 0)
|
|
485
|
+
return this.placeholder;
|
|
402
486
|
if (this._effectiveDisplay === "chips" && this.multiple)
|
|
403
487
|
return this.placeholder;
|
|
404
488
|
if (this._selectedValues.size === 1)
|
|
@@ -406,24 +490,29 @@ const d = class d extends f {
|
|
|
406
490
|
const e = [...this._selectedValues];
|
|
407
491
|
return `${this._labelFor(e[0])}, +${e.length - 1} more`;
|
|
408
492
|
}
|
|
409
|
-
|
|
493
|
+
/**
|
|
494
|
+
* APG Combobox keyboard handler on the trigger.
|
|
495
|
+
*
|
|
496
|
+
* Arrow keys navigate/open, Space/Enter activate, Tab closes without focus return,
|
|
497
|
+
* ArrowLeft enters chip navigation, and printable chars forward to type-ahead.
|
|
498
|
+
*/
|
|
410
499
|
_handleTriggerKeyDown(e) {
|
|
411
500
|
switch (e.key) {
|
|
412
501
|
case "ArrowDown":
|
|
413
|
-
e.preventDefault(), this.open ? this.
|
|
502
|
+
e.preventDefault(), this.open ? this._activeDescendantCtrl.navigate(1) : (this.openPopup(), this._activeDescendantCtrl.navigateToFirst());
|
|
414
503
|
break;
|
|
415
504
|
case "ArrowUp":
|
|
416
|
-
e.preventDefault(), this.open ? this.
|
|
505
|
+
e.preventDefault(), this.open ? this._activeDescendantCtrl.navigate(-1) : (this.openPopup(), this._activeDescendantCtrl.navigateToLast());
|
|
417
506
|
break;
|
|
418
507
|
case "Home":
|
|
419
|
-
this.open && (e.preventDefault(), this.
|
|
508
|
+
this.open && (e.preventDefault(), this._activeDescendantCtrl.navigateToFirst());
|
|
420
509
|
break;
|
|
421
510
|
case "End":
|
|
422
|
-
this.open && (e.preventDefault(), this.
|
|
511
|
+
this.open && (e.preventDefault(), this._activeDescendantCtrl.navigateToLast());
|
|
423
512
|
break;
|
|
424
513
|
case " ":
|
|
425
514
|
case "Enter":
|
|
426
|
-
e.preventDefault(), this.open ? this._activateActive() : (this.openPopup(), this.
|
|
515
|
+
e.preventDefault(), this.open ? this._activateActive() : (this.openPopup(), this._activeDescendantCtrl.navigateToFirst());
|
|
427
516
|
break;
|
|
428
517
|
case "Tab":
|
|
429
518
|
this.open && this.closePopup(!1);
|
|
@@ -435,13 +524,20 @@ const d = class d extends f {
|
|
|
435
524
|
e.key.length === 1 && !e.ctrlKey && !e.metaKey && !e.altKey && this._handleTypeAhead(e.key);
|
|
436
525
|
}
|
|
437
526
|
}
|
|
527
|
+
/**
|
|
528
|
+
* Dispatches a synthetic `pointerdown` on the active listbox item to activate it.
|
|
529
|
+
*
|
|
530
|
+
* Prefers `pointerdown` over a direct call so listbox item click logic
|
|
531
|
+
* (which is bound to `pointerdown`) fires through its normal path.
|
|
532
|
+
*/
|
|
438
533
|
_activateActive() {
|
|
439
|
-
const e = this.
|
|
440
|
-
e && e.dispatchEvent(
|
|
441
|
-
new PointerEvent("pointerdown", { bubbles: !0, cancelable: !0 })
|
|
442
|
-
);
|
|
534
|
+
const e = this._activeDescendantCtrl.activeItem;
|
|
535
|
+
e && e.dispatchEvent(new PointerEvent("pointerdown", { bubbles: !0, cancelable: !0 }));
|
|
443
536
|
}
|
|
444
|
-
|
|
537
|
+
/**
|
|
538
|
+
* Accumulates characters in `_typeAheadBuffer` and either immediately selects
|
|
539
|
+
* the first match (closed single-select) or moves the virtual cursor (open popup).
|
|
540
|
+
*/
|
|
445
541
|
_handleTypeAhead(e) {
|
|
446
542
|
clearTimeout(this._typeAheadTimer), this._typeAheadBuffer += e.toLowerCase(), this._typeAheadTimer = window.setTimeout(() => {
|
|
447
543
|
this._typeAheadBuffer = "";
|
|
@@ -453,26 +549,28 @@ const d = class d extends f {
|
|
|
453
549
|
if (!this.open)
|
|
454
550
|
this.multiple || (this._selectionInitialized = !0, this._applySelection([i.value]), this._dispatchChange());
|
|
455
551
|
else {
|
|
456
|
-
const r = this._$listbox.navigableItems.find(
|
|
457
|
-
|
|
458
|
-
);
|
|
459
|
-
r && this._adc.navigateToItem(r);
|
|
552
|
+
const r = this._$listbox.navigableItems.find((l) => l.getAttribute("data-value") === i.value);
|
|
553
|
+
r && this._activeDescendantCtrl.navigateToItem(r);
|
|
460
554
|
}
|
|
461
555
|
}
|
|
462
|
-
|
|
556
|
+
/** Focuses the last chip button and sets `_chipNavIndex` to begin roving-tabindex navigation within the chip group. */
|
|
463
557
|
_enterChipNav() {
|
|
464
|
-
const e = this.
|
|
558
|
+
const e = this._$chipButtons();
|
|
465
559
|
e.length !== 0 && (this._chipNavIndex = e.length - 1, e[this._chipNavIndex].focus());
|
|
466
560
|
}
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
'button[part~="chip"]'
|
|
471
|
-
)
|
|
472
|
-
);
|
|
561
|
+
/** Queries all `button[part~="chip"]` elements in `renderRoot`; order matches DOM order. */
|
|
562
|
+
_$chipButtons() {
|
|
563
|
+
return Array.from(this.renderRoot.querySelectorAll('button[part~="chip"]'));
|
|
473
564
|
}
|
|
565
|
+
/**
|
|
566
|
+
* Keyboard handler for chip buttons.
|
|
567
|
+
*
|
|
568
|
+
* ArrowLeft/Right rove chip focus, Escape returns to trigger,
|
|
569
|
+
* Delete/Backspace/Enter/Space remove the chip's value
|
|
570
|
+
* and return focus to the trigger.
|
|
571
|
+
*/
|
|
474
572
|
_handleChipKeyDown(e, t) {
|
|
475
|
-
const i = this.
|
|
573
|
+
const i = this._$chipButtons();
|
|
476
574
|
switch (e.key) {
|
|
477
575
|
case "ArrowLeft":
|
|
478
576
|
e.preventDefault(), this._chipNavIndex > 0 && (this._chipNavIndex--, i[this._chipNavIndex]?.focus());
|
|
@@ -491,14 +589,13 @@ const d = class d extends f {
|
|
|
491
589
|
break;
|
|
492
590
|
}
|
|
493
591
|
}
|
|
494
|
-
|
|
592
|
+
/** Toggles the popup open or closed on trigger click. */
|
|
495
593
|
_handleTriggerClick() {
|
|
496
594
|
this.open ? this.closePopup() : this.openPopup();
|
|
497
595
|
}
|
|
498
|
-
// ── Render ───────────────────────────────────────────────────────────────────
|
|
499
596
|
render() {
|
|
500
597
|
const e = this.multiple && this._effectiveDisplay === "chips" && this._selectedValues.size > 0;
|
|
501
|
-
return
|
|
598
|
+
return h`
|
|
502
599
|
<div id="anchor" part="anchor">
|
|
503
600
|
<div
|
|
504
601
|
id="trigger"
|
|
@@ -514,9 +611,24 @@ const d = class d extends f {
|
|
|
514
611
|
@keydown=${this._handleTriggerKeyDown}
|
|
515
612
|
>
|
|
516
613
|
${e ? this._renderChips() : _}
|
|
614
|
+
|
|
517
615
|
<span part="value-display">${this._displayLabel}</span>
|
|
518
|
-
|
|
519
|
-
|
|
616
|
+
|
|
617
|
+
<span part="toggle-indicator" aria-hidden="true">
|
|
618
|
+
<slot name="toggle-indicator">
|
|
619
|
+
<svg
|
|
620
|
+
width="10"
|
|
621
|
+
height="6"
|
|
622
|
+
viewBox="0 0 10 6"
|
|
623
|
+
fill="none"
|
|
624
|
+
stroke="currentColor"
|
|
625
|
+
stroke-width="1.5"
|
|
626
|
+
stroke-linecap="round"
|
|
627
|
+
stroke-linejoin="round"
|
|
628
|
+
>
|
|
629
|
+
<polyline points="1,1 5,5 9,1" />
|
|
630
|
+
</svg>
|
|
631
|
+
</slot>
|
|
520
632
|
</span>
|
|
521
633
|
</div>
|
|
522
634
|
</div>
|
|
@@ -530,15 +642,16 @@ const d = class d extends f {
|
|
|
530
642
|
@rc-listbox-change=${this._handleListboxChange}
|
|
531
643
|
></rc-listbox>
|
|
532
644
|
|
|
533
|
-
<slot
|
|
645
|
+
<slot @slotchange=${this._handleSelectSlotChange}></slot>
|
|
534
646
|
`;
|
|
535
647
|
}
|
|
648
|
+
/** Renders the chip group `<span>` with one `<button>` per selected value for multi-select chip display mode. */
|
|
536
649
|
_renderChips() {
|
|
537
|
-
return
|
|
650
|
+
return h`
|
|
538
651
|
<span part="chips" role="group" aria-label="Selected items">
|
|
539
652
|
${[...this._selectedValues].map((e) => {
|
|
540
653
|
const t = this._labelFor(e);
|
|
541
|
-
return
|
|
654
|
+
return h`
|
|
542
655
|
<button
|
|
543
656
|
type="button"
|
|
544
657
|
part="chip"
|
|
@@ -559,8 +672,8 @@ const d = class d extends f {
|
|
|
559
672
|
`;
|
|
560
673
|
}
|
|
561
674
|
};
|
|
562
|
-
|
|
563
|
-
let o =
|
|
675
|
+
u.styles = x;
|
|
676
|
+
let o = u;
|
|
564
677
|
a([
|
|
565
678
|
n({ type: Boolean, reflect: !0 })
|
|
566
679
|
], o.prototype, "open");
|
|
@@ -577,24 +690,24 @@ a([
|
|
|
577
690
|
n()
|
|
578
691
|
], o.prototype, "display");
|
|
579
692
|
a([
|
|
580
|
-
|
|
693
|
+
p("#anchor")
|
|
581
694
|
], o.prototype, "_$anchor");
|
|
582
695
|
a([
|
|
583
|
-
|
|
696
|
+
p("#trigger")
|
|
584
697
|
], o.prototype, "_$trigger");
|
|
585
698
|
a([
|
|
586
|
-
|
|
699
|
+
p("#listbox")
|
|
587
700
|
], o.prototype, "_$listbox");
|
|
588
701
|
a([
|
|
589
|
-
|
|
702
|
+
d()
|
|
590
703
|
], o.prototype, "_selectedValues");
|
|
591
704
|
a([
|
|
592
|
-
|
|
705
|
+
d()
|
|
593
706
|
], o.prototype, "_chipNavIndex");
|
|
594
707
|
a([
|
|
595
|
-
|
|
708
|
+
d()
|
|
596
709
|
], o.prototype, "_options");
|
|
597
710
|
export {
|
|
598
711
|
o as R
|
|
599
712
|
};
|
|
600
|
-
//# sourceMappingURL=rc-select-
|
|
713
|
+
//# sourceMappingURL=rc-select-Bu4ukw92.js.map
|