@sken-ds/primitives 0.3.0 → 0.3.4
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/decorate-D4FKzyDw.js +9 -0
- package/dist/directive-BcLtPdVO.js +263 -0
- package/dist/directive-BcLtPdVO.js.map +1 -0
- package/dist/index.js +14 -0
- package/dist/ix-bridge.css +608 -0
- package/dist/sken-button.js +125 -0
- package/dist/sken-button.js.map +1 -0
- package/dist/sken-checkbox.js +218 -0
- package/dist/sken-checkbox.js.map +1 -0
- package/dist/sken-combobox-group.js +20 -0
- package/dist/sken-combobox-group.js.map +1 -0
- package/dist/sken-combobox-item.js +20 -0
- package/dist/sken-combobox-item.js.map +1 -0
- package/dist/sken-combobox.js +590 -0
- package/dist/sken-combobox.js.map +1 -0
- package/dist/sken-datatable-BtR-NwRN.js +1563 -0
- package/dist/sken-datatable-BtR-NwRN.js.map +1 -0
- package/dist/sken-datatable.js +2 -0
- package/dist/sken-date-picker.js +42 -0
- package/dist/sken-date-picker.js.map +1 -0
- package/dist/sken-dialog-hRtML2jW.js +243 -0
- package/dist/sken-dialog-hRtML2jW.js.map +1 -0
- package/dist/sken-dialog.js +2 -0
- package/dist/sken-filter-chip.js +111 -0
- package/dist/sken-filter-chip.js.map +1 -0
- package/dist/sken-input.js +270 -0
- package/dist/sken-input.js.map +1 -0
- package/dist/sken-number-input.js +538 -0
- package/dist/sken-number-input.js.map +1 -0
- package/dist/sken-switch.js +196 -0
- package/dist/sken-switch.js.map +1 -0
- package/dist/sken-textarea.js +237 -0
- package/dist/sken-textarea.js.map +1 -0
- package/package.json +2 -2
|
@@ -0,0 +1,590 @@
|
|
|
1
|
+
import { t as e } from "./decorate-D4FKzyDw.js";
|
|
2
|
+
import "./sken-filter-chip.js";
|
|
3
|
+
import { LitElement as t, css as n, html as r } from "lit";
|
|
4
|
+
import { customElement as i, property as a, query as o, state as s } from "lit/decorators.js";
|
|
5
|
+
//#region src/components/sken-combobox.ts
|
|
6
|
+
var c = class extends t {
|
|
7
|
+
constructor(...e) {
|
|
8
|
+
super(...e), this.mode = "single", this.display = "count", this.chipOverflow = "wrap", this.value = null, this.filterable = !0, this.label = "", this.helperText = "", this.placeholder = "", this.disabled = !1, this.invalid = !1, this.required = !1, this.name = "", this.size = "md", this.describedById = "", this._items = [], this._query = "", this._open = !1, this._activeIndex = -1, this._visibleChipCount = -1, this._onKeydown = (e) => {
|
|
9
|
+
if (!this.disabled) switch (e.key) {
|
|
10
|
+
case "ArrowDown":
|
|
11
|
+
e.preventDefault(), this._open ? this._activeIndex = this._nextSelectableIndex(this._activeIndex, 1) : this._open_();
|
|
12
|
+
break;
|
|
13
|
+
case "ArrowUp":
|
|
14
|
+
e.preventDefault(), this._open ? this._activeIndex = this._nextSelectableIndex(this._activeIndex, -1) : this._open_();
|
|
15
|
+
break;
|
|
16
|
+
case "Home":
|
|
17
|
+
if (!this._open) return;
|
|
18
|
+
e.preventDefault(), this._activeIndex = this._firstSelectableIndex();
|
|
19
|
+
break;
|
|
20
|
+
case "End": {
|
|
21
|
+
if (!this._open) return;
|
|
22
|
+
e.preventDefault();
|
|
23
|
+
let t = this._visibleItems;
|
|
24
|
+
for (let e = t.length - 1; e >= 0; e--) if (!t[e].disabled) {
|
|
25
|
+
this._activeIndex = e;
|
|
26
|
+
break;
|
|
27
|
+
}
|
|
28
|
+
break;
|
|
29
|
+
}
|
|
30
|
+
case "Enter": {
|
|
31
|
+
if (!this._open) {
|
|
32
|
+
e.preventDefault(), this._open_();
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
let t = this._visibleItems[this._activeIndex];
|
|
36
|
+
t && !t.disabled && (e.preventDefault(), this._selectItem(t));
|
|
37
|
+
break;
|
|
38
|
+
}
|
|
39
|
+
case "Escape":
|
|
40
|
+
if (this._open) e.preventDefault(), this._close();
|
|
41
|
+
else if (this.value !== null && this.value !== void 0) {
|
|
42
|
+
e.preventDefault();
|
|
43
|
+
let t = this.mode === "multiple" ? [] : null;
|
|
44
|
+
this._setValue(t);
|
|
45
|
+
}
|
|
46
|
+
break;
|
|
47
|
+
case "Tab": this._close();
|
|
48
|
+
}
|
|
49
|
+
}, this._onInput = (e) => {
|
|
50
|
+
if (!this.filterable) return;
|
|
51
|
+
let t = e.target;
|
|
52
|
+
this._query = t.value, this._open || this._open_(), this._activeIndex = this._firstSelectableIndex();
|
|
53
|
+
}, this._onFocus = () => {
|
|
54
|
+
this.dispatchEvent(new FocusEvent("sken-focus", {
|
|
55
|
+
bubbles: !0,
|
|
56
|
+
composed: !0
|
|
57
|
+
}));
|
|
58
|
+
}, this._onBlur = () => {
|
|
59
|
+
setTimeout(() => {
|
|
60
|
+
this._close(), this.dispatchEvent(new FocusEvent("sken-blur", {
|
|
61
|
+
bubbles: !0,
|
|
62
|
+
composed: !0
|
|
63
|
+
}));
|
|
64
|
+
}, 100);
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
connectedCallback() {
|
|
68
|
+
super.connectedCallback(), this._observer = new MutationObserver(() => {
|
|
69
|
+
this._resolveItems(), this.requestUpdate();
|
|
70
|
+
}), this._observer.observe(this, {
|
|
71
|
+
childList: !0,
|
|
72
|
+
subtree: !0
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
disconnectedCallback() {
|
|
76
|
+
super.disconnectedCallback(), this._observer?.disconnect();
|
|
77
|
+
}
|
|
78
|
+
willUpdate(e) {
|
|
79
|
+
this._resolveItems();
|
|
80
|
+
}
|
|
81
|
+
firstUpdated(e) {
|
|
82
|
+
this._resolveItems(), queueMicrotask(() => {
|
|
83
|
+
this._items.length === 0 && this.children.length > 0 && (this._resolveItems(), this.requestUpdate());
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
updated(e) {
|
|
87
|
+
if (super.updated(e), this.mode !== "multiple" || this.display !== "chips" || this.chipOverflow !== "count") {
|
|
88
|
+
this._visibleChipCount !== -1 && (this._visibleChipCount = -1);
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
let t = this.renderRoot.querySelector(".chip-row");
|
|
92
|
+
if (!t) return;
|
|
93
|
+
let n = this.renderRoot.querySelector(".trigger");
|
|
94
|
+
if (!n) return;
|
|
95
|
+
let r = Array.from(t.querySelectorAll("sken-filter-chip:not(.overflow)"));
|
|
96
|
+
if (r.length === 0) {
|
|
97
|
+
this._visibleChipCount !== 0 && (this._visibleChipCount = 0);
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
let i = getComputedStyle(n), a = (parseFloat(i.paddingLeft) || 0) + (parseFloat(i.paddingRight) || 0), o = parseFloat(i.gap) || 0, s = n.clientWidth - a, c = 32 + o, l = 0, u = 0;
|
|
101
|
+
for (let e = 0; e < r.length; e++) {
|
|
102
|
+
let t = r[e].offsetWidth, n = l + t + (e > 0 ? o : 0);
|
|
103
|
+
if (n + (r.length - (e + 1) > 0 ? c : 0) > s) break;
|
|
104
|
+
l = n, u = e + 1;
|
|
105
|
+
}
|
|
106
|
+
this._visibleChipCount !== u && (this._visibleChipCount = u);
|
|
107
|
+
}
|
|
108
|
+
_resolveItems() {
|
|
109
|
+
let e = [];
|
|
110
|
+
for (let t of Array.from(this.children)) if (customElements.get("sken-combobox-group") && t instanceof customElements.get("sken-combobox-group")) {
|
|
111
|
+
let n = t, r = n.label || "", i = n.disabled;
|
|
112
|
+
for (let t of Array.from(n.children)) if (customElements.get("sken-combobox-item") && t instanceof customElements.get("sken-combobox-item")) {
|
|
113
|
+
let n = t;
|
|
114
|
+
e.push({
|
|
115
|
+
value: n.value,
|
|
116
|
+
label: n.label,
|
|
117
|
+
disabled: n.disabled || i,
|
|
118
|
+
groupLabel: r,
|
|
119
|
+
groupDisabled: i
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
} else if (customElements.get("sken-combobox-item") && t instanceof customElements.get("sken-combobox-item")) {
|
|
123
|
+
let n = t;
|
|
124
|
+
e.push({
|
|
125
|
+
value: n.value,
|
|
126
|
+
label: n.label,
|
|
127
|
+
disabled: n.disabled,
|
|
128
|
+
groupLabel: null,
|
|
129
|
+
groupDisabled: !1
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
this._items = e;
|
|
133
|
+
}
|
|
134
|
+
get _visibleItems() {
|
|
135
|
+
if (!this._query) return this._items;
|
|
136
|
+
let e = this._query.toLowerCase();
|
|
137
|
+
return this._items.filter((e) => !e.disabled || !0).filter((t) => t.label.toLowerCase().includes(e));
|
|
138
|
+
}
|
|
139
|
+
get _visibleGroups() {
|
|
140
|
+
let e = this._visibleItems, t = /* @__PURE__ */ new Map();
|
|
141
|
+
for (let n of e) {
|
|
142
|
+
let e = n.groupLabel || null;
|
|
143
|
+
t.has(e) || t.set(e, []), t.get(e).push(n);
|
|
144
|
+
}
|
|
145
|
+
let n = [];
|
|
146
|
+
for (let [e, r] of t) n.push({
|
|
147
|
+
label: e,
|
|
148
|
+
items: r
|
|
149
|
+
});
|
|
150
|
+
return n;
|
|
151
|
+
}
|
|
152
|
+
_setValue(e) {
|
|
153
|
+
e !== this.value && (this.value = e, this.dispatchEvent(new CustomEvent("sken-change", {
|
|
154
|
+
detail: { value: e },
|
|
155
|
+
bubbles: !0,
|
|
156
|
+
composed: !0
|
|
157
|
+
})));
|
|
158
|
+
}
|
|
159
|
+
_selectItem(e) {
|
|
160
|
+
if (!e.disabled) if (this.mode === "multiple") {
|
|
161
|
+
let t = Array.isArray(this.value) ? [...this.value] : [], n = t.indexOf(e.value);
|
|
162
|
+
n >= 0 ? t.splice(n, 1) : t.push(e.value), this._setValue(t), this._input.focus();
|
|
163
|
+
} else this._setValue(e.value), this._close();
|
|
164
|
+
}
|
|
165
|
+
_removeChip(e, t) {
|
|
166
|
+
if (t.stopPropagation(), this.mode !== "multiple") return;
|
|
167
|
+
let n = Array.isArray(this.value) ? [...this.value] : [], r = n.indexOf(e);
|
|
168
|
+
r < 0 || (n.splice(r, 1), this._setValue(n), this._input.focus());
|
|
169
|
+
}
|
|
170
|
+
_open_() {
|
|
171
|
+
this._open || this.disabled || (this._open = !0, this._activeIndex = this._firstSelectableIndex());
|
|
172
|
+
}
|
|
173
|
+
_close() {
|
|
174
|
+
this._open && (this._open = !1, this._activeIndex = -1);
|
|
175
|
+
}
|
|
176
|
+
_firstSelectableIndex() {
|
|
177
|
+
return this._visibleItems.findIndex((e) => !e.disabled);
|
|
178
|
+
}
|
|
179
|
+
_nextSelectableIndex(e, t) {
|
|
180
|
+
let n = this._visibleItems;
|
|
181
|
+
if (n.length === 0) return -1;
|
|
182
|
+
let r = e + t;
|
|
183
|
+
for (; r >= 0 && r < n.length;) {
|
|
184
|
+
if (!n[r].disabled) return r;
|
|
185
|
+
r += t;
|
|
186
|
+
}
|
|
187
|
+
return e;
|
|
188
|
+
}
|
|
189
|
+
get _displayValue() {
|
|
190
|
+
if (this._query) return this._query;
|
|
191
|
+
if (this.mode === "multiple") {
|
|
192
|
+
let e = Array.isArray(this.value) ? this.value : [];
|
|
193
|
+
return e.length === 0 || this.display === "chips" ? "" : `${e.length} selected`;
|
|
194
|
+
}
|
|
195
|
+
return this.value && typeof this.value == "string" ? this._items.find((e) => e.value === this.value)?.label ?? "" : "";
|
|
196
|
+
}
|
|
197
|
+
static {
|
|
198
|
+
this.styles = n`
|
|
199
|
+
:host {
|
|
200
|
+
display: inline-block;
|
|
201
|
+
position: relative;
|
|
202
|
+
font-family: var(--sken-family-sans, inherit);
|
|
203
|
+
color: var(--sken-foreground, #152b48);
|
|
204
|
+
inline-size: 100%;
|
|
205
|
+
}
|
|
206
|
+
.field {
|
|
207
|
+
display: grid;
|
|
208
|
+
gap: 0.375rem;
|
|
209
|
+
}
|
|
210
|
+
.label {
|
|
211
|
+
font-size: 0.8125rem;
|
|
212
|
+
font-weight: 500;
|
|
213
|
+
}
|
|
214
|
+
.trigger {
|
|
215
|
+
position: relative;
|
|
216
|
+
display: flex;
|
|
217
|
+
/* The trigger wraps its children: the chip row (if any)
|
|
218
|
+
* goes on its own line, then the input row. Without
|
|
219
|
+
* flex-wrap: wrap here, the chip row would push the input
|
|
220
|
+
* horizontally and the clear + chevron would float at
|
|
221
|
+
* the end of the first chip line. */
|
|
222
|
+
flex-wrap: wrap;
|
|
223
|
+
align-items: center;
|
|
224
|
+
gap: 0.25rem;
|
|
225
|
+
padding-inline: 0.75rem;
|
|
226
|
+
padding-block: var(--sken-2, 0.5rem);
|
|
227
|
+
min-block-size: 2.25rem;
|
|
228
|
+
box-sizing: border-box;
|
|
229
|
+
inline-size: 100%;
|
|
230
|
+
border: 1px solid var(--sken-border, #dfdfe3);
|
|
231
|
+
border-radius: var(--sken-md, 0.5rem);
|
|
232
|
+
background: var(--sken-input, #fff);
|
|
233
|
+
color: var(--sken-foreground, #152b48);
|
|
234
|
+
font-size: var(--sken-size-md, 0.875rem);
|
|
235
|
+
cursor: pointer;
|
|
236
|
+
transition: border-color 120ms ease, box-shadow 120ms ease;
|
|
237
|
+
}
|
|
238
|
+
.trigger:hover:not([data-disabled='true']) {
|
|
239
|
+
border-color: var(--sken-foreground, #152b48);
|
|
240
|
+
}
|
|
241
|
+
.trigger[data-focused='true'] {
|
|
242
|
+
border-color: var(--sken-primary, #2e6fc6);
|
|
243
|
+
box-shadow: 0 0 0 2px var(--sken-ring, #2e6fc640);
|
|
244
|
+
outline: none;
|
|
245
|
+
}
|
|
246
|
+
.trigger[data-disabled='true'] {
|
|
247
|
+
cursor: not-allowed;
|
|
248
|
+
opacity: var(--sken-disabled, 0.5);
|
|
249
|
+
}
|
|
250
|
+
:host([invalid]) .trigger {
|
|
251
|
+
border-color: var(--sken-destructive, #d4181d);
|
|
252
|
+
}
|
|
253
|
+
input {
|
|
254
|
+
flex: 1;
|
|
255
|
+
min-inline-size: 0;
|
|
256
|
+
border: none;
|
|
257
|
+
background: transparent;
|
|
258
|
+
color: inherit;
|
|
259
|
+
font: inherit;
|
|
260
|
+
outline: none;
|
|
261
|
+
}
|
|
262
|
+
input::placeholder {
|
|
263
|
+
color: var(--sken-muted-foreground, #4f6076);
|
|
264
|
+
}
|
|
265
|
+
.chevron,
|
|
266
|
+
.clear {
|
|
267
|
+
inline-size: 1rem;
|
|
268
|
+
block-size: 1rem;
|
|
269
|
+
flex-shrink: 0;
|
|
270
|
+
color: var(--sken-muted-foreground, #4f6076);
|
|
271
|
+
display: inline-flex;
|
|
272
|
+
align-items: center;
|
|
273
|
+
justify-content: center;
|
|
274
|
+
line-height: 1;
|
|
275
|
+
/* The trigger sets font-size: 0.875rem (--sken-size-md)
|
|
276
|
+
* and inherits Inter. Inter renders block glyphs like
|
|
277
|
+
* the down-chevron (▼, U+25BC) at near full em-box,
|
|
278
|
+
* which makes the chevron look huge next to the
|
|
279
|
+
* narrower clear (×, U+D7) which Arial renders as a
|
|
280
|
+
* thin cross. We pick a system sans explicitly so the
|
|
281
|
+
* two glyphs have similar visual weight, and drop to
|
|
282
|
+
* 0.75rem so the chevron's block shape does not eat
|
|
283
|
+
* the input's vertical padding. */
|
|
284
|
+
font-family: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
|
|
285
|
+
font-size: 0.75rem;
|
|
286
|
+
user-select: none;
|
|
287
|
+
}
|
|
288
|
+
.chevron {
|
|
289
|
+
display: inline-flex;
|
|
290
|
+
align-items: center;
|
|
291
|
+
justify-content: center;
|
|
292
|
+
inline-size: 1rem;
|
|
293
|
+
block-size: 1rem;
|
|
294
|
+
flex-shrink: 0;
|
|
295
|
+
color: var(--sken-muted-foreground, #4f6076);
|
|
296
|
+
transition: transform 120ms ease;
|
|
297
|
+
}
|
|
298
|
+
.chevron svg {
|
|
299
|
+
inline-size: 100%;
|
|
300
|
+
block-size: 100%;
|
|
301
|
+
/* Default stroke-width is fine for 16x16; if the consumer
|
|
302
|
+
* needs a different size, the consumer can set
|
|
303
|
+
* --sken-icon-stroke-width on the host. */
|
|
304
|
+
}
|
|
305
|
+
.chevron[data-open='true'] {
|
|
306
|
+
transform: rotate(180deg);
|
|
307
|
+
}
|
|
308
|
+
.clear {
|
|
309
|
+
cursor: pointer;
|
|
310
|
+
/* Outlined at rest: a 1px border on a transparent
|
|
311
|
+
* background, matching the Nord Design System's tag
|
|
312
|
+
* pattern (see nordhealth.design/components/tag).
|
|
313
|
+
* The outline signals affordance without filling
|
|
314
|
+
* the trigger with a gray pill, so the combobox
|
|
315
|
+
* stays visually calm when the clear is the only
|
|
316
|
+
* thing on the right edge. */
|
|
317
|
+
background: transparent;
|
|
318
|
+
border: 1px solid var(--sken-border, #dfdfe3);
|
|
319
|
+
padding: 0;
|
|
320
|
+
border-radius: 999px;
|
|
321
|
+
}
|
|
322
|
+
.clear:hover {
|
|
323
|
+
background: var(--sken-muted, #f4f4f5);
|
|
324
|
+
border-color: var(--sken-muted-foreground, #4f6076);
|
|
325
|
+
color: var(--sken-foreground, #152b48);
|
|
326
|
+
}
|
|
327
|
+
.listbox {
|
|
328
|
+
position: absolute;
|
|
329
|
+
inset-block-start: calc(100% + 0.25rem);
|
|
330
|
+
inset-inline: 0;
|
|
331
|
+
max-block-size: 16rem;
|
|
332
|
+
overflow-y: auto;
|
|
333
|
+
background: var(--sken-card, #fff);
|
|
334
|
+
border: 1px solid var(--sken-border, #dfdfe3);
|
|
335
|
+
border-radius: var(--sken-md, 0.5rem);
|
|
336
|
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
|
|
337
|
+
z-index: 10;
|
|
338
|
+
list-style: none;
|
|
339
|
+
margin: 0;
|
|
340
|
+
padding: 0.25rem 0;
|
|
341
|
+
/* Token-driven scrollbar so the panel matches the design
|
|
342
|
+
* language instead of inheriting the host OS default. The
|
|
343
|
+
* WebKit pseudo-elements cover Safari + older Chromium;
|
|
344
|
+
* scrollbar-width / scrollbar-color cover Firefox +
|
|
345
|
+
* modern Chromium. Both are needed because each engine
|
|
346
|
+
* ignores the other API. */
|
|
347
|
+
scrollbar-width: thin;
|
|
348
|
+
scrollbar-color: var(--sken-border, #dfdfe3) transparent;
|
|
349
|
+
}
|
|
350
|
+
.listbox::-webkit-scrollbar {
|
|
351
|
+
inline-size: 0.5rem;
|
|
352
|
+
block-size: 0.5rem;
|
|
353
|
+
}
|
|
354
|
+
.listbox::-webkit-scrollbar-track {
|
|
355
|
+
background: transparent;
|
|
356
|
+
}
|
|
357
|
+
.listbox::-webkit-scrollbar-thumb {
|
|
358
|
+
background: var(--sken-border, #dfdfe3);
|
|
359
|
+
border-radius: 999px;
|
|
360
|
+
border: 2px solid var(--sken-card, #fff);
|
|
361
|
+
background-clip: padding-box;
|
|
362
|
+
}
|
|
363
|
+
.listbox::-webkit-scrollbar-thumb:hover {
|
|
364
|
+
background: var(--sken-muted-foreground, #4f6076);
|
|
365
|
+
background-clip: padding-box;
|
|
366
|
+
}
|
|
367
|
+
.group-header {
|
|
368
|
+
padding: 0.5rem 0.75rem 0.25rem;
|
|
369
|
+
font-size: 0.75rem;
|
|
370
|
+
font-weight: 600;
|
|
371
|
+
text-transform: uppercase;
|
|
372
|
+
letter-spacing: 0.04em;
|
|
373
|
+
color: var(--sken-muted-foreground, #4f6076);
|
|
374
|
+
}
|
|
375
|
+
.option {
|
|
376
|
+
padding: 0.5rem 0.75rem;
|
|
377
|
+
cursor: pointer;
|
|
378
|
+
display: flex;
|
|
379
|
+
align-items: center;
|
|
380
|
+
gap: 0.5rem;
|
|
381
|
+
font-size: var(--sken-size-md, 0.875rem);
|
|
382
|
+
}
|
|
383
|
+
.option[data-active='true'] {
|
|
384
|
+
background: var(--sken-muted, #f4f4f5);
|
|
385
|
+
}
|
|
386
|
+
.option[data-selected='true'] {
|
|
387
|
+
font-weight: 500;
|
|
388
|
+
}
|
|
389
|
+
.option[data-disabled='true'] {
|
|
390
|
+
cursor: not-allowed;
|
|
391
|
+
opacity: var(--sken-disabled, 0.5);
|
|
392
|
+
}
|
|
393
|
+
.check {
|
|
394
|
+
inline-size: 1rem;
|
|
395
|
+
block-size: 1rem;
|
|
396
|
+
flex-shrink: 0;
|
|
397
|
+
color: var(--sken-primary, #2e6fc6);
|
|
398
|
+
opacity: 0;
|
|
399
|
+
}
|
|
400
|
+
.option[data-selected='true'] .check {
|
|
401
|
+
opacity: 1;
|
|
402
|
+
}
|
|
403
|
+
.helper {
|
|
404
|
+
font-size: 0.75rem;
|
|
405
|
+
color: var(--sken-muted-foreground, #4f6076);
|
|
406
|
+
}
|
|
407
|
+
.chip-row {
|
|
408
|
+
display: flex;
|
|
409
|
+
flex-wrap: wrap;
|
|
410
|
+
align-items: center;
|
|
411
|
+
gap: 0.25rem;
|
|
412
|
+
min-inline-size: 0;
|
|
413
|
+
/* The chip row wraps to multiple lines when the chips
|
|
414
|
+
* do not fit. The trigger's own height grows accordingly;
|
|
415
|
+
* for display:chips + chip-overflow:count, the row uses
|
|
416
|
+
* nowrap + overflow:hidden instead, so the trigger
|
|
417
|
+
* height stays constant. */
|
|
418
|
+
flex-basis: 100%;
|
|
419
|
+
row-gap: 0.25rem;
|
|
420
|
+
}
|
|
421
|
+
.chip-row[data-overflow='none'] {
|
|
422
|
+
flex-wrap: nowrap;
|
|
423
|
+
overflow-x: auto;
|
|
424
|
+
/* Hide the scrollbar visually; consumers who need to
|
|
425
|
+
* see overflow can override. Same scrollbar pattern as
|
|
426
|
+
* the listbox. */
|
|
427
|
+
scrollbar-width: none;
|
|
428
|
+
}
|
|
429
|
+
.chip-row[data-overflow='none']::-webkit-scrollbar {
|
|
430
|
+
display: none;
|
|
431
|
+
}
|
|
432
|
+
.chip-row[data-overflow='count'] {
|
|
433
|
+
flex-wrap: nowrap;
|
|
434
|
+
overflow-x: hidden;
|
|
435
|
+
}
|
|
436
|
+
.chip-row sken-filter-chip.overflow {
|
|
437
|
+
/* The overflow chip reuses the same visual treatment as
|
|
438
|
+
* a regular chip but with no close button (set via the
|
|
439
|
+
* hide-close-button attribute on the primitive). */
|
|
440
|
+
background: var(--sken-primary, #2e6fc6);
|
|
441
|
+
color: var(--sken-primary-foreground, #fff);
|
|
442
|
+
}
|
|
443
|
+
.chip-row sken-filter-chip.overflow:hover {
|
|
444
|
+
background: var(--sken-primary, #2e6fc6);
|
|
445
|
+
opacity: 0.92;
|
|
446
|
+
}
|
|
447
|
+
/* The input row (input + clear + chevron) sits on its own
|
|
448
|
+
* line below the chip row. Without this wrapper, the
|
|
449
|
+
* clear + chevron would float to the end of the first
|
|
450
|
+
* chip line in display:chips mode (visually wrong).
|
|
451
|
+
* The input row is always present, even when there are
|
|
452
|
+
* no chips — that way the layout is stable across the
|
|
453
|
+
* "empty" and "with chips" states. */
|
|
454
|
+
.input-row {
|
|
455
|
+
display: flex;
|
|
456
|
+
align-items: center;
|
|
457
|
+
/* Slightly wider gap than the trigger's general one, so
|
|
458
|
+
* the clear button and the chevron do not feel
|
|
459
|
+
* glued together at the right edge of the input. The
|
|
460
|
+
* extra 4px matches the visual weight of the icons
|
|
461
|
+
* (16x16 each) without making the layout feel sparse. */
|
|
462
|
+
gap: 0.5rem;
|
|
463
|
+
flex-basis: 100%;
|
|
464
|
+
min-inline-size: 0;
|
|
465
|
+
}
|
|
466
|
+
`;
|
|
467
|
+
}
|
|
468
|
+
render() {
|
|
469
|
+
let e = this._visibleItems, t = this._visibleGroups, n = this.mode === "multiple", i = n ? new Set(Array.isArray(this.value) ? this.value : []) : new Set(this.value ? [this.value] : []), a = `sken-combobox-listbox-${Math.random().toString(36).slice(2, 8)}`, o = n && this.display === "chips", s = o ? this._items.filter((e) => i.has(e.value)) : [], c = o && this._visibleChipCount >= 0 ? s.slice(0, this._visibleChipCount) : s, l = o && this._visibleChipCount >= 0 ? s.slice(this._visibleChipCount) : [];
|
|
470
|
+
return r`
|
|
471
|
+
<div class="field">
|
|
472
|
+
${this.label ? r`<label class="label" for="trigger">${this.label}</label>` : null}
|
|
473
|
+
<div
|
|
474
|
+
class="trigger"
|
|
475
|
+
data-focused=${this._open}
|
|
476
|
+
data-disabled=${this.disabled}
|
|
477
|
+
@click=${() => !this.disabled && (this._open ? this._close() : this._open_())}
|
|
478
|
+
>
|
|
479
|
+
${o && s.length > 0 ? r`<div
|
|
480
|
+
class="chip-row"
|
|
481
|
+
part="chip-row"
|
|
482
|
+
data-overflow=${this.chipOverflow}
|
|
483
|
+
>
|
|
484
|
+
${c.map((e) => r`
|
|
485
|
+
<sken-filter-chip
|
|
486
|
+
label=${e.label}
|
|
487
|
+
data-sken-combobox-chip-value=${e.value}
|
|
488
|
+
@sken-close=${(t) => this._removeChip(e.value, t)}
|
|
489
|
+
></sken-filter-chip>
|
|
490
|
+
`)}
|
|
491
|
+
${l.length > 0 && this.chipOverflow === "count" ? r`<sken-filter-chip
|
|
492
|
+
class="overflow"
|
|
493
|
+
label="+${l.length}"
|
|
494
|
+
data-sken-combobox-overflow=${l.length}
|
|
495
|
+
hide-close-button
|
|
496
|
+
@click=${(e) => {
|
|
497
|
+
e.stopPropagation(), this._open = !0;
|
|
498
|
+
}}
|
|
499
|
+
></sken-filter-chip>` : null}
|
|
500
|
+
</div>` : null}
|
|
501
|
+
<div class="input-row">
|
|
502
|
+
<input
|
|
503
|
+
id="trigger"
|
|
504
|
+
role="combobox"
|
|
505
|
+
aria-expanded=${this._open}
|
|
506
|
+
aria-controls=${a}
|
|
507
|
+
aria-activedescendant=${this._activeIndex >= 0 ? `${a}-opt-${this._activeIndex}` : ""}
|
|
508
|
+
aria-autocomplete=${this.filterable ? "list" : "none"}
|
|
509
|
+
aria-required=${this.required}
|
|
510
|
+
aria-invalid=${this.invalid}
|
|
511
|
+
aria-describedby=${this.describedById}
|
|
512
|
+
?disabled=${this.disabled}
|
|
513
|
+
.value=${this._displayValue}
|
|
514
|
+
placeholder=${this.placeholder}
|
|
515
|
+
@input=${this._onInput}
|
|
516
|
+
@keydown=${this._onKeydown}
|
|
517
|
+
@focus=${this._onFocus}
|
|
518
|
+
@blur=${this._onBlur}
|
|
519
|
+
/>
|
|
520
|
+
${!this.disabled && this.value !== null && (!n || i.size > 0) ? r`<button
|
|
521
|
+
type="button"
|
|
522
|
+
class="clear"
|
|
523
|
+
aria-label="Clear selection"
|
|
524
|
+
@click=${(e) => {
|
|
525
|
+
e.stopPropagation();
|
|
526
|
+
let t = n ? [] : null;
|
|
527
|
+
this._setValue(t), this._query = "", this._input.focus();
|
|
528
|
+
}}
|
|
529
|
+
>×</button>` : null}
|
|
530
|
+
<span class="chevron" data-open=${this._open} aria-hidden="true">
|
|
531
|
+
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
|
532
|
+
<path d="M3.5 6.5 L8 11 L12.5 6.5"></path>
|
|
533
|
+
</svg>
|
|
534
|
+
</span>
|
|
535
|
+
</div>
|
|
536
|
+
</div>
|
|
537
|
+
|
|
538
|
+
${this._open ? r`<ul
|
|
539
|
+
id=${a}
|
|
540
|
+
class="listbox"
|
|
541
|
+
role="listbox"
|
|
542
|
+
aria-multiselectable=${n}
|
|
543
|
+
>
|
|
544
|
+
${e.length === 0 ? r`<li class="option" data-disabled="true">No matches</li>` : t.map((t) => r`
|
|
545
|
+
${t.label ? r`<li
|
|
546
|
+
class="group-header"
|
|
547
|
+
role="presentation"
|
|
548
|
+
>${t.label}</li>` : null}
|
|
549
|
+
${t.items.map((t) => {
|
|
550
|
+
let o = e.indexOf(t), s = o === this._activeIndex, c = i.has(t.value);
|
|
551
|
+
return r`<li
|
|
552
|
+
id=${`${a}-opt-${o}`}
|
|
553
|
+
class="option"
|
|
554
|
+
role="option"
|
|
555
|
+
data-active=${s}
|
|
556
|
+
data-selected=${c}
|
|
557
|
+
data-disabled=${t.disabled}
|
|
558
|
+
aria-selected=${c}
|
|
559
|
+
aria-disabled=${t.disabled}
|
|
560
|
+
@mouseenter=${() => {
|
|
561
|
+
this._activeIndex = o;
|
|
562
|
+
}}
|
|
563
|
+
@click=${() => this._selectItem(t)}
|
|
564
|
+
>
|
|
565
|
+
${n ? r`<span class="check" aria-hidden="true">✓</span>` : null}
|
|
566
|
+
<span>${t.label}</span>
|
|
567
|
+
</li>`;
|
|
568
|
+
})}
|
|
569
|
+
`)}
|
|
570
|
+
</ul>` : null}
|
|
571
|
+
|
|
572
|
+
${this.helperText ? r`<div class="helper">${this.helperText}</div>` : null}
|
|
573
|
+
</div>
|
|
574
|
+
`;
|
|
575
|
+
}
|
|
576
|
+
};
|
|
577
|
+
e([a({ reflect: !0 })], c.prototype, "mode", void 0), e([a()], c.prototype, "display", void 0), e([a({ attribute: "chip-overflow" })], c.prototype, "chipOverflow", void 0), e([a({ attribute: !1 })], c.prototype, "value", void 0), e([a({ type: Boolean })], c.prototype, "filterable", void 0), e([a()], c.prototype, "label", void 0), e([a({ attribute: "helper-text" })], c.prototype, "helperText", void 0), e([a()], c.prototype, "placeholder", void 0), e([a({
|
|
578
|
+
type: Boolean,
|
|
579
|
+
reflect: !0
|
|
580
|
+
})], c.prototype, "disabled", void 0), e([a({
|
|
581
|
+
type: Boolean,
|
|
582
|
+
reflect: !0
|
|
583
|
+
})], c.prototype, "invalid", void 0), e([a({
|
|
584
|
+
type: Boolean,
|
|
585
|
+
reflect: !0
|
|
586
|
+
})], c.prototype, "required", void 0), e([a()], c.prototype, "name", void 0), e([a({ reflect: !0 })], c.prototype, "size", void 0), e([a({ attribute: "described-by-id" })], c.prototype, "describedById", void 0), e([s()], c.prototype, "_items", void 0), e([s()], c.prototype, "_query", void 0), e([s()], c.prototype, "_open", void 0), e([s()], c.prototype, "_activeIndex", void 0), e([s()], c.prototype, "_visibleChipCount", void 0), e([o("input")], c.prototype, "_input", void 0), c = e([i("sken-combobox")], c);
|
|
587
|
+
//#endregion
|
|
588
|
+
export { c as SkenCombobox };
|
|
589
|
+
|
|
590
|
+
//# sourceMappingURL=sken-combobox.js.map
|