kanto-ds 1.4.0 → 1.5.2
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 +10 -10
- package/dist/chunks/{defaults-BwgjMcww.js → defaults-CFrjqae2.js} +22 -21
- package/dist/chunks/{defaults-BwgjMcww.js.map → defaults-CFrjqae2.js.map} +1 -1
- package/dist/chunks/events-r51msXNf.js +22 -0
- package/dist/chunks/{events-Bjl5Zmmq.js.map → events-r51msXNf.js.map} +1 -1
- package/dist/chunks/floating-B7_Dahpn.js +54 -0
- package/dist/chunks/floating-B7_Dahpn.js.map +1 -0
- package/dist/chunks/{form-control-CxjBTt1c.js → form-control-B74_EHtG.js} +7 -7
- package/dist/chunks/form-control-B74_EHtG.js.map +1 -0
- package/dist/chunks/{index-DSSLJirw.js → index-STEEvEP7.js} +24 -12
- package/dist/chunks/index-STEEvEP7.js.map +1 -0
- package/dist/chunks/kt-calendar-B_hFdD9V.js +640 -0
- package/dist/chunks/kt-calendar-B_hFdD9V.js.map +1 -0
- package/dist/chunks/{kt-element-E-tfJpGQ.js → kt-element-Djx2JcGl.js} +2 -2
- package/dist/chunks/{kt-element-E-tfJpGQ.js.map → kt-element-Djx2JcGl.js.map} +1 -1
- package/dist/chunks/{listbox-Sm3nvsC6.js → listbox-llcUu_V-.js} +18 -14
- package/dist/chunks/{listbox-Sm3nvsC6.js.map → listbox-llcUu_V-.js.map} +1 -1
- package/dist/chunks/locale-C5xLkGx5.js +14 -0
- package/dist/chunks/locale-C5xLkGx5.js.map +1 -0
- package/dist/chunks/position-Cx_ZH5zh.js +39 -0
- package/dist/chunks/position-Cx_ZH5zh.js.map +1 -0
- package/dist/components/core/kt-avatar/kt-avatar.js +2 -2
- package/dist/components/core/kt-badge/kt-badge.js +3 -3
- package/dist/components/core/kt-button/kt-button.js +1 -1
- package/dist/components/core/kt-card/kt-card.js +2 -2
- package/dist/components/core/kt-code/kt-code.js +3 -3
- package/dist/components/core/kt-icon/kt-icon.js +2 -2
- package/dist/components/core/kt-kbd/kt-kbd.js +1 -1
- package/dist/components/core/kt-split-button/kt-split-button.js +4 -4
- package/dist/components/data/kt-chart/kt-chart.js +3 -3
- package/dist/components/data/kt-meter/kt-meter.js +1 -1
- package/dist/components/data/kt-pagination/kt-pagination.js +3 -3
- package/dist/components/data/kt-stat/kt-stat.js +1 -1
- package/dist/components/data/kt-table/kt-table.d.ts +53 -3
- package/dist/components/data/kt-table/kt-table.js +286 -131
- package/dist/components/data/kt-table/kt-table.js.map +1 -1
- package/dist/components/data/kt-table/window.d.ts +19 -0
- package/dist/components/data/kt-timeline/kt-timeline.js +1 -1
- package/dist/components/feedback/kt-alert/kt-alert.js +3 -3
- package/dist/components/feedback/kt-empty-state/kt-empty-state.js +1 -1
- package/dist/components/feedback/kt-progress-bar/kt-progress-bar.js +10 -10
- package/dist/components/feedback/kt-progress-bar/kt-progress-bar.js.map +1 -1
- package/dist/components/feedback/kt-skeleton/kt-skeleton.js +1 -1
- package/dist/components/feedback/kt-toast/kt-toast.js +58 -42
- package/dist/components/feedback/kt-toast/kt-toast.js.map +1 -1
- package/dist/components/feedback/kt-toast-container/kt-toast-container.js +1 -1
- package/dist/components/feedback/kt-tooltip/kt-tooltip.d.ts +20 -0
- package/dist/components/feedback/kt-tooltip/kt-tooltip.js +95 -51
- package/dist/components/feedback/kt-tooltip/kt-tooltip.js.map +1 -1
- package/dist/components/forms/kt-calendar/kt-calendar.d.ts +96 -0
- package/dist/components/forms/kt-calendar/kt-calendar.js +13 -0
- package/dist/components/forms/kt-calendar/kt-calendar.js.map +1 -0
- package/dist/components/forms/kt-checkbox/kt-checkbox.d.ts +9 -0
- package/dist/components/forms/kt-checkbox/kt-checkbox.js +34 -20
- package/dist/components/forms/kt-checkbox/kt-checkbox.js.map +1 -1
- package/dist/components/forms/kt-date-picker/kt-date-picker.d.ts +105 -0
- package/dist/components/forms/kt-date-picker/kt-date-picker.js +382 -0
- package/dist/components/forms/kt-date-picker/kt-date-picker.js.map +1 -0
- package/dist/components/forms/kt-drag-drop/kt-drag-drop.d.ts +9 -0
- package/dist/components/forms/kt-drag-drop/kt-drag-drop.js +36 -22
- package/dist/components/forms/kt-drag-drop/kt-drag-drop.js.map +1 -1
- package/dist/components/forms/kt-form/kt-form.js +2 -2
- package/dist/components/forms/kt-input/kt-input.d.ts +37 -1
- package/dist/components/forms/kt-input/kt-input.js +380 -194
- package/dist/components/forms/kt-input/kt-input.js.map +1 -1
- package/dist/components/forms/kt-input-menu/kt-input-menu.d.ts +13 -0
- package/dist/components/forms/kt-input-menu/kt-input-menu.js +73 -42
- package/dist/components/forms/kt-input-menu/kt-input-menu.js.map +1 -1
- package/dist/components/forms/kt-label-input/kt-label-input.js +1 -1
- package/dist/components/forms/kt-radio-group/kt-radio-group.d.ts +9 -0
- package/dist/components/forms/kt-radio-group/kt-radio-group.js +67 -53
- package/dist/components/forms/kt-radio-group/kt-radio-group.js.map +1 -1
- package/dist/components/forms/kt-select/kt-select.d.ts +13 -0
- package/dist/components/forms/kt-select/kt-select.js +87 -56
- package/dist/components/forms/kt-select/kt-select.js.map +1 -1
- package/dist/components/forms/kt-textarea/kt-textarea.d.ts +9 -0
- package/dist/components/forms/kt-textarea/kt-textarea.js +28 -14
- package/dist/components/forms/kt-textarea/kt-textarea.js.map +1 -1
- package/dist/components/forms/kt-toggle/kt-toggle.d.ts +9 -0
- package/dist/components/forms/kt-toggle/kt-toggle.js +43 -29
- package/dist/components/forms/kt-toggle/kt-toggle.js.map +1 -1
- package/dist/components/navigation/kt-breadcrumb/kt-breadcrumb.js +3 -3
- package/dist/components/navigation/kt-header/kt-header.js +3 -3
- package/dist/components/navigation/kt-page-header/kt-page-header.js +1 -1
- package/dist/components/navigation/kt-segmented-control/kt-segmented-control.d.ts +9 -0
- package/dist/components/navigation/kt-segmented-control/kt-segmented-control.js +40 -22
- package/dist/components/navigation/kt-segmented-control/kt-segmented-control.js.map +1 -1
- package/dist/components/navigation/kt-sub-menu-navigation/kt-sub-menu-navigation.js +3 -3
- package/dist/components/navigation/kt-tabs/kt-tabs.js +2 -2
- package/dist/components/navigation/kt-toggle-button/kt-toggle-button.js +2 -2
- package/dist/components/navigation/kt-toggle-button-group/kt-toggle-button-group.js +3 -3
- package/dist/components/overlays/kt-collapsible/kt-collapsible.js +2 -2
- package/dist/components/overlays/kt-confirm-dialog/kt-confirm-dialog.js +3 -3
- package/dist/components/overlays/kt-dropdown/kt-dropdown.d.ts +7 -5
- package/dist/components/overlays/kt-dropdown/kt-dropdown.js +67 -57
- package/dist/components/overlays/kt-dropdown/kt-dropdown.js.map +1 -1
- package/dist/components/overlays/kt-modal/kt-modal.js +3 -3
- package/dist/components/overlays/kt-side-panel/kt-side-panel.js +3 -3
- package/dist/custom-elements.json +2110 -124
- package/dist/icons/defaults.d.ts +1 -0
- package/dist/icons/index.js +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.js +91 -87
- package/dist/index.js.map +1 -1
- package/dist/internal/countries.d.ts +24 -9
- package/dist/internal/date.d.ts +53 -0
- package/dist/internal/events.d.ts +5 -0
- package/dist/internal/floating.d.ts +48 -0
- package/dist/internal/form-control.d.ts +5 -1
- package/dist/internal/locale.d.ts +15 -0
- package/dist/internal/position.d.ts +27 -0
- package/dist/internal/strings.d.ts +15 -0
- package/dist/react/index.d.ts +12 -0
- package/dist/react/index.js +180 -166
- package/dist/react/index.js.map +1 -1
- package/dist/react/jsx.d.ts +11 -1
- package/dist/strings/index.js +1 -1
- package/dist/tokens/base.css +2 -0
- package/dist/tokens/responsive.css +1 -0
- package/dist/tokens/spacing.css +1 -0
- package/dist/vscode.css-custom-data.json +8 -0
- package/dist/vscode.html-custom-data.json +138 -11
- package/dist/vue/index.d.ts +4 -0
- package/dist/vue/index.js +9 -7
- package/dist/vue/index.js.map +1 -1
- package/dist/web-types.json +292 -14
- package/package.json +10 -1
- package/dist/chunks/events-Bjl5Zmmq.js +0 -18
- package/dist/chunks/form-control-CxjBTt1c.js.map +0 -1
- package/dist/chunks/index-DSSLJirw.js.map +0 -1
|
@@ -1,20 +1,28 @@
|
|
|
1
|
-
import { css as
|
|
2
|
-
import { state as
|
|
3
|
-
import { classMap as
|
|
4
|
-
import { K as v, d as
|
|
5
|
-
import { u as
|
|
6
|
-
import { a as
|
|
7
|
-
import { a as
|
|
8
|
-
import {
|
|
1
|
+
import { css as x, nothing as n, html as h } from "lit";
|
|
2
|
+
import { state as p, property as s } from "lit/decorators.js";
|
|
3
|
+
import { classMap as d } from "lit/directives/class-map.js";
|
|
4
|
+
import { K as v, d as w } from "../../../chunks/kt-element-Djx2JcGl.js";
|
|
5
|
+
import { u as k, t as g, e as m } from "../../../chunks/events-r51msXNf.js";
|
|
6
|
+
import { a as $, s as I, b as D } from "../../../chunks/form-control-B74_EHtG.js";
|
|
7
|
+
import { a as S, f as b, l as L, n as C, o as y } from "../../../chunks/listbox-llcUu_V-.js";
|
|
8
|
+
import { F as E, f as P } from "../../../chunks/floating-B7_Dahpn.js";
|
|
9
|
+
import { s as l } from "../../../chunks/index-STEEvEP7.js";
|
|
9
10
|
import "../../core/kt-icon/kt-icon.js";
|
|
10
|
-
var
|
|
11
|
-
for (var r = void 0,
|
|
12
|
-
(
|
|
13
|
-
return r &&
|
|
11
|
+
var q = Object.defineProperty, i = (c, e, o, a) => {
|
|
12
|
+
for (var r = void 0, u = c.length - 1, f; u >= 0; u--)
|
|
13
|
+
(f = c[u]) && (r = f(e, o, r) || r);
|
|
14
|
+
return r && q(e, o, r), r;
|
|
14
15
|
};
|
|
15
16
|
class t extends v {
|
|
16
17
|
constructor() {
|
|
17
|
-
super(...arguments), this.internals = null, this.defaultValue = null, this.listId =
|
|
18
|
+
super(...arguments), this.internals = null, this.defaultValue = null, this.listId = k("kt-select-list"), this.open = !1, this.placement = "bottom", this.floating = new E(this, {
|
|
19
|
+
panel: () => this.shadowRoot?.querySelector(".popup"),
|
|
20
|
+
anchor: () => this.shadowRoot?.querySelector(".trigger"),
|
|
21
|
+
matchWidth: !0,
|
|
22
|
+
onPlace: (e) => {
|
|
23
|
+
this.placement = e;
|
|
24
|
+
}
|
|
25
|
+
}), this.activeIndex = -1, this.options = [], this.value = null, this.placeholder = void 0, this.name = "", this.size = "medium", this.disabled = !1, this.formDisabled = !1, this.required = !1, this.error = "", this.clearable = !0, this.label = "", this.emptyText = void 0, this.onDocumentPointerDown = (e) => {
|
|
18
26
|
e.composedPath().includes(this) || (this.open = !1);
|
|
19
27
|
};
|
|
20
28
|
}
|
|
@@ -24,8 +32,9 @@ class t extends v {
|
|
|
24
32
|
static {
|
|
25
33
|
this.styles = [
|
|
26
34
|
v.styles,
|
|
27
|
-
|
|
28
|
-
|
|
35
|
+
P,
|
|
36
|
+
S,
|
|
37
|
+
x`
|
|
29
38
|
:host {
|
|
30
39
|
position: relative;
|
|
31
40
|
display: block;
|
|
@@ -89,10 +98,10 @@ class t extends v {
|
|
|
89
98
|
outline: var(--outline-width) solid var(--color-danger-base);
|
|
90
99
|
}
|
|
91
100
|
|
|
92
|
-
:host(
|
|
101
|
+
:host(:disabled) {
|
|
93
102
|
pointer-events: none;
|
|
94
103
|
}
|
|
95
|
-
:host(
|
|
104
|
+
:host(:disabled) .trigger {
|
|
96
105
|
color: var(--text-disabled);
|
|
97
106
|
background-color: var(--color-dark-14);
|
|
98
107
|
}
|
|
@@ -137,26 +146,41 @@ class t extends v {
|
|
|
137
146
|
`
|
|
138
147
|
];
|
|
139
148
|
}
|
|
149
|
+
/** Whether the control is off, by its own `disabled` or by its form. */
|
|
150
|
+
get inactive() {
|
|
151
|
+
return this.disabled || this.formDisabled;
|
|
152
|
+
}
|
|
140
153
|
connectedCallback() {
|
|
141
|
-
super.connectedCallback(), this.internals ??=
|
|
154
|
+
super.connectedCallback(), this.internals ??= $(this), this.defaultValue = this.value, g(this.open, document, "pointerdown", this.onDocumentPointerDown);
|
|
142
155
|
}
|
|
143
156
|
disconnectedCallback() {
|
|
144
157
|
super.disconnectedCallback(), document.removeEventListener("pointerdown", this.onDocumentPointerDown);
|
|
145
158
|
}
|
|
159
|
+
// Untyped: `open` is private, so not among the keys PropertyValues<this> knows.
|
|
160
|
+
updated(e) {
|
|
161
|
+
e.has("open") && g(this.open, document, "pointerdown", this.onDocumentPointerDown), this.floating.sync(this.open);
|
|
162
|
+
}
|
|
146
163
|
willUpdate(e) {
|
|
147
164
|
if (e.has("value") || e.has("required") || e.has("error") || this.stringsChanged(e)) {
|
|
148
|
-
|
|
149
|
-
const
|
|
150
|
-
|
|
165
|
+
I(this.internals, this.value === null ? null : String(this.value));
|
|
166
|
+
const o = this.required && this.value === null;
|
|
167
|
+
D(
|
|
151
168
|
this.internals,
|
|
152
|
-
{ valueMissing:
|
|
153
|
-
this.error || (
|
|
169
|
+
{ valueMissing: o, customError: !!this.error },
|
|
170
|
+
this.error || (o ? l().selectOption : "")
|
|
154
171
|
);
|
|
155
172
|
}
|
|
156
173
|
}
|
|
157
174
|
formResetCallback() {
|
|
158
175
|
this.value = this.defaultValue, this.open = !1;
|
|
159
176
|
}
|
|
177
|
+
/**
|
|
178
|
+
* Called by the platform when the control's disabled state changes — its
|
|
179
|
+
* own `disabled`, or an ancestor `<fieldset disabled>` it cannot see.
|
|
180
|
+
*/
|
|
181
|
+
formDisabledCallback(e) {
|
|
182
|
+
this.formDisabled = e;
|
|
183
|
+
}
|
|
160
184
|
formStateRestoreCallback(e) {
|
|
161
185
|
this.value = e;
|
|
162
186
|
}
|
|
@@ -168,9 +192,9 @@ class t extends v {
|
|
|
168
192
|
return this.options.find((e) => e.id === this.value);
|
|
169
193
|
}
|
|
170
194
|
openList() {
|
|
171
|
-
if (this.
|
|
195
|
+
if (this.inactive) return;
|
|
172
196
|
this.open = !0;
|
|
173
|
-
const e = this.options.findIndex((
|
|
197
|
+
const e = this.options.findIndex((o) => o.id === this.value);
|
|
174
198
|
this.activeIndex = e >= 0 ? e : b(this.options);
|
|
175
199
|
}
|
|
176
200
|
closeList() {
|
|
@@ -180,17 +204,17 @@ class t extends v {
|
|
|
180
204
|
this.open ? this.closeList() : this.openList();
|
|
181
205
|
}
|
|
182
206
|
choose(e) {
|
|
183
|
-
e.disabled || (this.value = e.id, this.closeList(), this.focus(),
|
|
207
|
+
e.disabled || (this.value = e.id, this.closeList(), this.focus(), m(this, "kt-change", { value: e.id, option: e }));
|
|
184
208
|
}
|
|
185
209
|
clear(e) {
|
|
186
|
-
e.stopPropagation(), this.value = null,
|
|
210
|
+
e.stopPropagation(), this.value = null, m(this, "kt-change", { value: null, option: null });
|
|
187
211
|
}
|
|
188
212
|
onKeyDown(e) {
|
|
189
213
|
switch (e.key) {
|
|
190
214
|
case "ArrowDown":
|
|
191
215
|
case "ArrowUp": {
|
|
192
216
|
if (e.preventDefault(), !this.open) return this.openList();
|
|
193
|
-
this.activeIndex =
|
|
217
|
+
this.activeIndex = C(
|
|
194
218
|
this.options,
|
|
195
219
|
this.activeIndex,
|
|
196
220
|
e.key === "ArrowDown" ? 1 : -1
|
|
@@ -208,8 +232,8 @@ class t extends v {
|
|
|
208
232
|
case "Enter":
|
|
209
233
|
case " ": {
|
|
210
234
|
if (e.preventDefault(), !this.open) return this.openList();
|
|
211
|
-
const
|
|
212
|
-
|
|
235
|
+
const o = this.options[this.activeIndex];
|
|
236
|
+
o && this.choose(o);
|
|
213
237
|
return;
|
|
214
238
|
}
|
|
215
239
|
case "Escape":
|
|
@@ -224,9 +248,9 @@ class t extends v {
|
|
|
224
248
|
return `${this.listId}-option-${e}`;
|
|
225
249
|
}
|
|
226
250
|
render() {
|
|
227
|
-
const e = this.selectedOption,
|
|
228
|
-
return
|
|
229
|
-
class=${
|
|
251
|
+
const e = this.selectedOption, o = this.clearable && e !== void 0 && !this.inactive;
|
|
252
|
+
return h`<div
|
|
253
|
+
class=${d({ open: this.open, error: !!this.error })}
|
|
230
254
|
@keydown=${this.onKeyDown}
|
|
231
255
|
>
|
|
232
256
|
<button
|
|
@@ -240,14 +264,14 @@ class t extends v {
|
|
|
240
264
|
aria-activedescendant=${this.open && this.activeIndex >= 0 ? this.optionId(this.activeIndex) : n}
|
|
241
265
|
aria-label=${this.label || n}
|
|
242
266
|
aria-invalid=${this.error ? "true" : n}
|
|
243
|
-
?disabled=${this.
|
|
267
|
+
?disabled=${this.inactive}
|
|
244
268
|
@click=${this.toggleList}
|
|
245
269
|
>
|
|
246
|
-
<span class=${
|
|
247
|
-
${e ?
|
|
270
|
+
<span class=${d({ value: !0, placeholder: !e })}>
|
|
271
|
+
${e ? y(e) : this.placeholder ?? l().select}
|
|
248
272
|
</span>
|
|
249
273
|
<span class="icons">
|
|
250
|
-
${
|
|
274
|
+
${o ? h`<span
|
|
251
275
|
class="clear"
|
|
252
276
|
role="button"
|
|
253
277
|
tabindex="-1"
|
|
@@ -263,15 +287,16 @@ class t extends v {
|
|
|
263
287
|
<ul
|
|
264
288
|
part="popup"
|
|
265
289
|
id=${this.listId}
|
|
266
|
-
|
|
290
|
+
popover="manual"
|
|
291
|
+
class=${d({ popup: !0, floating: !0, open: this.open, top: this.placement === "top" })}
|
|
267
292
|
role="listbox"
|
|
268
293
|
aria-label=${this.label || (this.placeholder ?? l().select)}
|
|
269
294
|
>
|
|
270
|
-
${this.options.length === 0 ?
|
|
271
|
-
(a, r) =>
|
|
295
|
+
${this.options.length === 0 ? h`<li class="empty">${this.emptyText ?? l().noOptions}</li>` : this.options.map(
|
|
296
|
+
(a, r) => h`<li
|
|
272
297
|
part="option"
|
|
273
298
|
id=${this.optionId(r)}
|
|
274
|
-
class=${
|
|
299
|
+
class=${d({
|
|
275
300
|
option: !0,
|
|
276
301
|
selected: a.id === this.value,
|
|
277
302
|
active: r === this.activeIndex,
|
|
@@ -282,7 +307,7 @@ class t extends v {
|
|
|
282
307
|
aria-disabled=${a.disabled ? "true" : n}
|
|
283
308
|
@click=${() => this.choose(a)}
|
|
284
309
|
>
|
|
285
|
-
${
|
|
310
|
+
${y(a)}
|
|
286
311
|
</li>`
|
|
287
312
|
)}
|
|
288
313
|
</ul>
|
|
@@ -290,45 +315,51 @@ class t extends v {
|
|
|
290
315
|
}
|
|
291
316
|
}
|
|
292
317
|
i([
|
|
293
|
-
|
|
318
|
+
p()
|
|
294
319
|
], t.prototype, "open");
|
|
295
320
|
i([
|
|
296
|
-
|
|
321
|
+
p()
|
|
322
|
+
], t.prototype, "placement");
|
|
323
|
+
i([
|
|
324
|
+
p()
|
|
297
325
|
], t.prototype, "activeIndex");
|
|
298
326
|
i([
|
|
299
|
-
|
|
327
|
+
s({ attribute: !1 })
|
|
300
328
|
], t.prototype, "options");
|
|
301
329
|
i([
|
|
302
|
-
|
|
330
|
+
s({ type: String })
|
|
303
331
|
], t.prototype, "value");
|
|
304
332
|
i([
|
|
305
|
-
|
|
333
|
+
s({ type: String })
|
|
306
334
|
], t.prototype, "placeholder");
|
|
307
335
|
i([
|
|
308
|
-
|
|
336
|
+
s({ type: String })
|
|
309
337
|
], t.prototype, "name");
|
|
310
338
|
i([
|
|
311
|
-
|
|
339
|
+
s({ type: String, reflect: !0 })
|
|
312
340
|
], t.prototype, "size");
|
|
313
341
|
i([
|
|
314
|
-
|
|
342
|
+
s({ type: Boolean, reflect: !0 })
|
|
315
343
|
], t.prototype, "disabled");
|
|
316
344
|
i([
|
|
317
|
-
|
|
345
|
+
p()
|
|
346
|
+
], t.prototype, "formDisabled");
|
|
347
|
+
i([
|
|
348
|
+
s({ type: Boolean, reflect: !0 })
|
|
318
349
|
], t.prototype, "required");
|
|
319
350
|
i([
|
|
320
|
-
|
|
351
|
+
s({ type: String, reflect: !0 })
|
|
321
352
|
], t.prototype, "error");
|
|
322
353
|
i([
|
|
323
|
-
|
|
354
|
+
s({ type: Boolean })
|
|
324
355
|
], t.prototype, "clearable");
|
|
325
356
|
i([
|
|
326
|
-
|
|
357
|
+
s({ type: String })
|
|
327
358
|
], t.prototype, "label");
|
|
328
359
|
i([
|
|
329
|
-
|
|
360
|
+
s({ type: String, attribute: "empty-text" })
|
|
330
361
|
], t.prototype, "emptyText");
|
|
331
|
-
|
|
362
|
+
w("kt-select", t);
|
|
332
363
|
export {
|
|
333
364
|
t as KtSelect
|
|
334
365
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"kt-select.js","sources":["../../../../src/components/forms/kt-select/kt-select.ts"],"sourcesContent":["import { css, html, nothing, type PropertyValues, type TemplateResult } from 'lit';\nimport { property, state } from 'lit/decorators.js';\nimport { classMap } from 'lit/directives/class-map.js';\nimport { KtElement, defineElement } from '#internal/kt-element';\nimport { emit, uniqueId } from '#internal/events';\nimport {\n attachFormInternals,\n setFormValue,\n setValidity,\n type UsableInternals,\n} from '#internal/form-control';\nimport {\n firstEnabledIndex,\n lastEnabledIndex,\n listboxStyles,\n nextEnabledIndex,\n optionLabel,\n type KtOption,\n} from '#internal/listbox';\nimport { strings } from '#internal/strings';\nimport '../../core/kt-icon/kt-icon.js';\n\nexport type KtSelectSize = 'small' | 'medium' | 'large';\nexport type { KtOption };\n\n/**\n * A single-choice dropdown.\n *\n * Unlike the trigger-plus-div it replaces, this is a real listbox: arrow keys\n * move an active descendant, Home and End jump to the ends, Enter commits,\n * Escape closes without changing anything, and disabled options are skipped\n * rather than merely unclickable.\n *\n * @element kt-select\n *\n * @csspart trigger - The button that opens the list.\n * @csspart popup - The option list.\n * @csspart option - An option row.\n *\n * @fires kt-change - An option was chosen or cleared.\n * `detail: { value, option }`.\n *\n * @example\n * ```html\n * <kt-select placeholder=\"Select a region\"></kt-select>\n * ```\n * ```js\n * select.options = [{ id: 'ne', label: 'North East' }, { id: 'sw', label: 'South West' }];\n * ```\n */\nexport class KtSelect extends KtElement {\n static readonly formAssociated = true;\n\n static override styles = [\n KtElement.styles,\n listboxStyles,\n css`\n :host {\n position: relative;\n display: block;\n --field-height: var(--button-height);\n }\n\n :host([size='small']) {\n --field-height: var(--button-height-small);\n }\n :host([size='large']) {\n --field-height: var(--button-height-large);\n }\n\n .trigger {\n display: grid;\n grid-template-columns: 1fr auto;\n align-items: center;\n gap: var(--gap-element);\n width: 100%;\n height: var(--field-height);\n padding: 0 var(--button-padding-x);\n color: var(--text-body);\n font: var(--font-input);\n text-align: left;\n background-color: var(--color-dark-20);\n border: none;\n border-radius: var(--radius-input);\n /* A resting hairline. A field is a fill on --surface-field, which is\n one ramp step from the page in dark and almost the same colour in\n light — so on a card or inside a modal it simply disappeared and\n read as a bare native control.\n\n A border rather than an outline, because the control inside fills\n the field exactly and a coincident outline is painted over by the\n native widget. A border insets the control by its own width, so it\n cannot be covered. box-sizing: border-box keeps the outer size.\n\n The hover and focus rings stay outlines on top of it, and the\n transparent resting outline is what they animate from: without it\n outline-color starts at the initial value, which resolves to the\n text colour, and hover flashed near-white before settling. */\n border: var(--border-width) solid var(--border-field);\n outline: var(--outline-width) solid transparent;\n cursor: pointer;\n transition:\n background-color var(--duration-instant),\n outline-color var(--duration-instant);\n }\n\n .trigger:hover {\n outline: var(--outline-width) solid var(--color-text-700);\n }\n .trigger:focus-visible,\n .open .trigger {\n background-color: var(--color-dark-12);\n outline: var(--outline-width) solid var(--color-primary-base);\n }\n\n .error .trigger,\n .error .trigger:hover {\n outline: var(--outline-width) solid var(--color-danger-base);\n }\n\n :host([disabled]) {\n pointer-events: none;\n }\n :host([disabled]) .trigger {\n color: var(--text-disabled);\n background-color: var(--color-dark-14);\n }\n\n .value {\n overflow: hidden;\n white-space: nowrap;\n text-overflow: ellipsis;\n }\n\n .placeholder {\n color: var(--text-muted);\n }\n\n .icons {\n display: inline-flex;\n align-items: center;\n gap: var(--gap-element);\n }\n\n .clear {\n display: inline-flex;\n padding: 0;\n color: inherit;\n background: none;\n border: none;\n cursor: pointer;\n transition: transform var(--duration-instant) ease-in-out;\n }\n .clear:hover {\n transform: rotate(90deg);\n }\n\n .chevron {\n display: inline-flex;\n align-items: center;\n transition: transform var(--duration-fast) ease-in-out;\n }\n .open .chevron {\n transform: scaleY(-1);\n }\n `,\n ];\n\n private internals: UsableInternals | null = null;\n private defaultValue: string | number | null = null;\n private readonly listId = uniqueId('kt-select-list');\n\n @state()\n private open = false;\n\n /** Index of the active descendant while the list is open; -1 for none. */\n @state()\n private activeIndex = -1;\n\n /** The options to choose from. A property: this is data, not an attribute. */\n @property({ attribute: false })\n options: readonly KtOption[] = [];\n\n /** The selected option's id, or `null`. */\n @property({ type: String })\n value: string | number | null = null;\n\n @property({ type: String })\n placeholder: string | undefined = undefined;\n\n @property({ type: String })\n name = '';\n\n @property({ type: String, reflect: true })\n size: KtSelectSize = 'medium';\n\n @property({ type: Boolean, reflect: true })\n disabled = false;\n\n @property({ type: Boolean, reflect: true })\n required = false;\n\n /** Error message. A non-empty value puts the control in its error state. */\n @property({ type: String, reflect: true })\n error = '';\n\n /** Shows the clear button once something is selected. */\n @property({ type: Boolean })\n clearable = true;\n\n /** Accessible name, when no `<kt-label-input>` wraps the control. */\n @property({ type: String })\n label = '';\n\n /** Shown when `options` is empty. */\n @property({ type: String, attribute: 'empty-text' })\n emptyText: string | undefined = undefined;\n\n override connectedCallback(): void {\n super.connectedCallback();\n this.internals ??= attachFormInternals(this);\n this.defaultValue = this.value;\n document.addEventListener('pointerdown', this.onDocumentPointerDown);\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n document.removeEventListener('pointerdown', this.onDocumentPointerDown);\n }\n\n override willUpdate(changed: PropertyValues<this>): void {\n if (\n changed.has('value') ||\n changed.has('required') ||\n changed.has('error') ||\n this.stringsChanged(changed)\n ) {\n setFormValue(this.internals, this.value === null ? null : String(this.value));\n\n const missing = this.required && this.value === null;\n setValidity(\n this.internals,\n { valueMissing: missing, customError: Boolean(this.error) },\n this.error || (missing ? strings().selectOption : ''),\n );\n }\n }\n\n formResetCallback(): void {\n this.value = this.defaultValue;\n this.open = false;\n }\n\n formStateRestoreCallback(state: string): void {\n this.value = state;\n }\n\n override focus(options?: FocusOptions): void {\n this.shadowRoot?.querySelector<HTMLButtonElement>('.trigger')?.focus(options);\n }\n\n /** The currently selected option, if the id still matches one. */\n get selectedOption(): KtOption | undefined {\n return this.options.find((option) => option.id === this.value);\n }\n\n private onDocumentPointerDown = (event: Event): void => {\n if (event.composedPath().includes(this)) return;\n this.open = false;\n };\n\n private openList(): void {\n if (this.disabled) return;\n this.open = true;\n const selected = this.options.findIndex((option) => option.id === this.value);\n this.activeIndex = selected >= 0 ? selected : firstEnabledIndex(this.options);\n }\n\n private closeList(): void {\n this.open = false;\n this.activeIndex = -1;\n }\n\n private toggleList(): void {\n if (this.open) this.closeList();\n else this.openList();\n }\n\n private choose(option: KtOption): void {\n if (option.disabled) return;\n this.value = option.id;\n this.closeList();\n this.focus();\n emit(this, 'kt-change', { value: option.id, option });\n }\n\n private clear(event: Event): void {\n event.stopPropagation();\n this.value = null;\n emit(this, 'kt-change', { value: null, option: null });\n }\n\n private onKeyDown(event: KeyboardEvent): void {\n switch (event.key) {\n case 'ArrowDown':\n case 'ArrowUp': {\n event.preventDefault();\n if (!this.open) return this.openList();\n this.activeIndex = nextEnabledIndex(\n this.options,\n this.activeIndex,\n event.key === 'ArrowDown' ? 1 : -1,\n );\n return;\n }\n case 'Home':\n if (!this.open) return;\n event.preventDefault();\n this.activeIndex = firstEnabledIndex(this.options);\n return;\n case 'End':\n if (!this.open) return;\n event.preventDefault();\n this.activeIndex = lastEnabledIndex(this.options);\n return;\n case 'Enter':\n case ' ': {\n event.preventDefault();\n if (!this.open) return this.openList();\n const option = this.options[this.activeIndex];\n if (option) this.choose(option);\n return;\n }\n case 'Escape':\n if (!this.open) return;\n event.stopPropagation();\n this.closeList();\n return;\n case 'Tab':\n this.closeList();\n }\n }\n\n private optionId(index: number): string {\n return `${this.listId}-option-${index}`;\n }\n\n override render(): TemplateResult {\n const selected = this.selectedOption;\n const showClear = this.clearable && selected !== undefined && !this.disabled;\n\n return html`<div\n class=${classMap({ open: this.open, error: Boolean(this.error) })}\n @keydown=${this.onKeyDown}\n >\n <button\n part=\"trigger\"\n type=\"button\"\n class=\"trigger\"\n role=\"combobox\"\n aria-haspopup=\"listbox\"\n aria-expanded=${this.open ? 'true' : 'false'}\n aria-controls=${this.listId}\n aria-activedescendant=${\n this.open && this.activeIndex >= 0 ? this.optionId(this.activeIndex) : nothing\n }\n aria-label=${this.label || nothing}\n aria-invalid=${this.error ? 'true' : nothing}\n ?disabled=${this.disabled}\n @click=${this.toggleList}\n >\n <span class=${classMap({ value: true, placeholder: !selected })}>\n ${selected ? optionLabel(selected) : (this.placeholder ?? strings().select)}\n </span>\n <span class=\"icons\">\n ${\n showClear\n ? html`<span\n class=\"clear\"\n role=\"button\"\n tabindex=\"-1\"\n aria-label=${strings().clear}\n @click=${this.clear}\n >\n <kt-icon name=\"x\" size=\"18\"></kt-icon>\n </span>`\n : nothing\n }\n <span class=\"chevron\"><kt-icon name=\"chevron-down\" size=\"18\"></kt-icon></span>\n </span>\n </button>\n\n <ul\n part=\"popup\"\n id=${this.listId}\n class=${classMap({ popup: true, open: this.open })}\n role=\"listbox\"\n aria-label=${this.label || (this.placeholder ?? strings().select)}\n >\n ${\n this.options.length === 0\n ? html`<li class=\"empty\">${this.emptyText ?? strings().noOptions}</li>`\n : this.options.map(\n (option, index) =>\n html`<li\n part=\"option\"\n id=${this.optionId(index)}\n class=${classMap({\n option: true,\n selected: option.id === this.value,\n active: index === this.activeIndex,\n disabled: Boolean(option.disabled),\n })}\n role=\"option\"\n aria-selected=${option.id === this.value ? 'true' : 'false'}\n aria-disabled=${option.disabled ? 'true' : nothing}\n @click=${() => this.choose(option)}\n >\n ${optionLabel(option)}\n </li>`,\n )\n }\n </ul>\n </div>`;\n }\n}\n\ndefineElement('kt-select', KtSelect);\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'kt-select': KtSelect;\n }\n}\n"],"names":["KtSelect","KtElement","uniqueId","event","listboxStyles","css","attachFormInternals","changed","setFormValue","missing","setValidity","strings","state","options","option","selected","firstEnabledIndex","emit","nextEnabledIndex","lastEnabledIndex","index","showClear","html","classMap","nothing","optionLabel","__decorateClass","property","defineElement"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"kt-select.js","sources":["../../../../src/components/forms/kt-select/kt-select.ts"],"sourcesContent":["import { css, html, nothing, type PropertyValues, type TemplateResult } from 'lit';\nimport { property, state } from 'lit/decorators.js';\nimport { classMap } from 'lit/directives/class-map.js';\nimport { KtElement, defineElement } from '#internal/kt-element';\nimport { emit, toggleListener, uniqueId } from '#internal/events';\nimport {\n attachFormInternals,\n setFormValue,\n setValidity,\n type UsableInternals,\n} from '#internal/form-control';\nimport {\n firstEnabledIndex,\n lastEnabledIndex,\n listboxStyles,\n nextEnabledIndex,\n optionLabel,\n type KtOption,\n} from '#internal/listbox';\nimport { FloatingController, floatingStyles } from '#internal/floating';\nimport type { Side } from '#internal/position';\nimport { strings } from '#internal/strings';\nimport '../../core/kt-icon/kt-icon.js';\n\nexport type KtSelectSize = 'small' | 'medium' | 'large';\nexport type { KtOption };\n\n/**\n * A single-choice dropdown.\n *\n * Unlike the trigger-plus-div it replaces, this is a real listbox: arrow keys\n * move an active descendant, Home and End jump to the ends, Enter commits,\n * Escape closes without changing anything, and disabled options are skipped\n * rather than merely unclickable.\n *\n * @element kt-select\n *\n * @csspart trigger - The button that opens the list.\n * @csspart popup - The option list.\n * @csspart option - An option row.\n *\n * @fires kt-change - An option was chosen or cleared.\n * `detail: { value, option }`.\n *\n * @example\n * ```html\n * <kt-select placeholder=\"Select a region\"></kt-select>\n * ```\n * ```js\n * select.options = [{ id: 'ne', label: 'North East' }, { id: 'sw', label: 'South West' }];\n * ```\n */\nexport class KtSelect extends KtElement {\n static readonly formAssociated = true;\n\n static override styles = [\n KtElement.styles,\n floatingStyles,\n listboxStyles,\n css`\n :host {\n position: relative;\n display: block;\n --field-height: var(--button-height);\n }\n\n :host([size='small']) {\n --field-height: var(--button-height-small);\n }\n :host([size='large']) {\n --field-height: var(--button-height-large);\n }\n\n .trigger {\n display: grid;\n grid-template-columns: 1fr auto;\n align-items: center;\n gap: var(--gap-element);\n width: 100%;\n height: var(--field-height);\n padding: 0 var(--button-padding-x);\n color: var(--text-body);\n font: var(--font-input);\n text-align: left;\n background-color: var(--color-dark-20);\n border: none;\n border-radius: var(--radius-input);\n /* A resting hairline. A field is a fill on --surface-field, which is\n one ramp step from the page in dark and almost the same colour in\n light — so on a card or inside a modal it simply disappeared and\n read as a bare native control.\n\n A border rather than an outline, because the control inside fills\n the field exactly and a coincident outline is painted over by the\n native widget. A border insets the control by its own width, so it\n cannot be covered. box-sizing: border-box keeps the outer size.\n\n The hover and focus rings stay outlines on top of it, and the\n transparent resting outline is what they animate from: without it\n outline-color starts at the initial value, which resolves to the\n text colour, and hover flashed near-white before settling. */\n border: var(--border-width) solid var(--border-field);\n outline: var(--outline-width) solid transparent;\n cursor: pointer;\n transition:\n background-color var(--duration-instant),\n outline-color var(--duration-instant);\n }\n\n .trigger:hover {\n outline: var(--outline-width) solid var(--color-text-700);\n }\n .trigger:focus-visible,\n .open .trigger {\n background-color: var(--color-dark-12);\n outline: var(--outline-width) solid var(--color-primary-base);\n }\n\n .error .trigger,\n .error .trigger:hover {\n outline: var(--outline-width) solid var(--color-danger-base);\n }\n\n :host(:disabled) {\n pointer-events: none;\n }\n :host(:disabled) .trigger {\n color: var(--text-disabled);\n background-color: var(--color-dark-14);\n }\n\n .value {\n overflow: hidden;\n white-space: nowrap;\n text-overflow: ellipsis;\n }\n\n .placeholder {\n color: var(--text-muted);\n }\n\n .icons {\n display: inline-flex;\n align-items: center;\n gap: var(--gap-element);\n }\n\n .clear {\n display: inline-flex;\n padding: 0;\n color: inherit;\n background: none;\n border: none;\n cursor: pointer;\n transition: transform var(--duration-instant) ease-in-out;\n }\n .clear:hover {\n transform: rotate(90deg);\n }\n\n .chevron {\n display: inline-flex;\n align-items: center;\n transition: transform var(--duration-fast) ease-in-out;\n }\n .open .chevron {\n transform: scaleY(-1);\n }\n `,\n ];\n\n private internals: UsableInternals | null = null;\n private defaultValue: string | number | null = null;\n private readonly listId = uniqueId('kt-select-list');\n\n @state()\n private open = false;\n\n /** The side the list opened on, for the direction of its entrance. */\n @state()\n private placement: Side = 'bottom';\n\n private floating = new FloatingController(this, {\n panel: () => this.shadowRoot?.querySelector<HTMLElement>('.popup'),\n anchor: () => this.shadowRoot?.querySelector('.trigger'),\n matchWidth: true,\n onPlace: (side) => {\n this.placement = side;\n },\n });\n\n /** Index of the active descendant while the list is open; -1 for none. */\n @state()\n private activeIndex = -1;\n\n /** The options to choose from. A property: this is data, not an attribute. */\n @property({ attribute: false })\n options: readonly KtOption[] = [];\n\n /** The selected option's id, or `null`. */\n @property({ type: String })\n value: string | number | null = null;\n\n @property({ type: String })\n placeholder: string | undefined = undefined;\n\n @property({ type: String })\n name = '';\n\n @property({ type: String, reflect: true })\n size: KtSelectSize = 'medium';\n\n @property({ type: Boolean, reflect: true })\n disabled = false;\n\n /** Disabled by an enclosing `<fieldset>`, which leaves `disabled` alone. */\n @state()\n private formDisabled = false;\n\n /** Whether the control is off, by its own `disabled` or by its form. */\n private get inactive(): boolean {\n return this.disabled || this.formDisabled;\n }\n\n @property({ type: Boolean, reflect: true })\n required = false;\n\n /** Error message. A non-empty value puts the control in its error state. */\n @property({ type: String, reflect: true })\n error = '';\n\n /** Shows the clear button once something is selected. */\n @property({ type: Boolean })\n clearable = true;\n\n /** Accessible name, when no `<kt-label-input>` wraps the control. */\n @property({ type: String })\n label = '';\n\n /** Shown when `options` is empty. */\n @property({ type: String, attribute: 'empty-text' })\n emptyText: string | undefined = undefined;\n\n override connectedCallback(): void {\n super.connectedCallback();\n this.internals ??= attachFormInternals(this);\n this.defaultValue = this.value;\n // Back on the document if it was reconnected while open.\n toggleListener(this.open, document, 'pointerdown', this.onDocumentPointerDown);\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n document.removeEventListener('pointerdown', this.onDocumentPointerDown);\n }\n\n // Untyped: `open` is private, so not among the keys PropertyValues<this> knows.\n override updated(changed: PropertyValues): void {\n // Only an open list closes on an outside click, so only an open one listens.\n if (changed.has('open')) {\n toggleListener(this.open, document, 'pointerdown', this.onDocumentPointerDown);\n }\n this.floating.sync(this.open);\n }\n\n override willUpdate(changed: PropertyValues<this>): void {\n if (\n changed.has('value') ||\n changed.has('required') ||\n changed.has('error') ||\n this.stringsChanged(changed)\n ) {\n setFormValue(this.internals, this.value === null ? null : String(this.value));\n\n const missing = this.required && this.value === null;\n setValidity(\n this.internals,\n { valueMissing: missing, customError: Boolean(this.error) },\n this.error || (missing ? strings().selectOption : ''),\n );\n }\n }\n\n formResetCallback(): void {\n this.value = this.defaultValue;\n this.open = false;\n }\n\n /**\n * Called by the platform when the control's disabled state changes — its\n * own `disabled`, or an ancestor `<fieldset disabled>` it cannot see.\n */\n formDisabledCallback(disabled: boolean): void {\n this.formDisabled = disabled;\n }\n\n formStateRestoreCallback(state: string): void {\n this.value = state;\n }\n\n override focus(options?: FocusOptions): void {\n this.shadowRoot?.querySelector<HTMLButtonElement>('.trigger')?.focus(options);\n }\n\n /** The currently selected option, if the id still matches one. */\n get selectedOption(): KtOption | undefined {\n return this.options.find((option) => option.id === this.value);\n }\n\n private onDocumentPointerDown = (event: Event): void => {\n if (event.composedPath().includes(this)) return;\n this.open = false;\n };\n\n private openList(): void {\n if (this.inactive) return;\n this.open = true;\n const selected = this.options.findIndex((option) => option.id === this.value);\n this.activeIndex = selected >= 0 ? selected : firstEnabledIndex(this.options);\n }\n\n private closeList(): void {\n this.open = false;\n this.activeIndex = -1;\n }\n\n private toggleList(): void {\n if (this.open) this.closeList();\n else this.openList();\n }\n\n private choose(option: KtOption): void {\n if (option.disabled) return;\n this.value = option.id;\n this.closeList();\n this.focus();\n emit(this, 'kt-change', { value: option.id, option });\n }\n\n private clear(event: Event): void {\n event.stopPropagation();\n this.value = null;\n emit(this, 'kt-change', { value: null, option: null });\n }\n\n private onKeyDown(event: KeyboardEvent): void {\n switch (event.key) {\n case 'ArrowDown':\n case 'ArrowUp': {\n event.preventDefault();\n if (!this.open) return this.openList();\n this.activeIndex = nextEnabledIndex(\n this.options,\n this.activeIndex,\n event.key === 'ArrowDown' ? 1 : -1,\n );\n return;\n }\n case 'Home':\n if (!this.open) return;\n event.preventDefault();\n this.activeIndex = firstEnabledIndex(this.options);\n return;\n case 'End':\n if (!this.open) return;\n event.preventDefault();\n this.activeIndex = lastEnabledIndex(this.options);\n return;\n case 'Enter':\n case ' ': {\n event.preventDefault();\n if (!this.open) return this.openList();\n const option = this.options[this.activeIndex];\n if (option) this.choose(option);\n return;\n }\n case 'Escape':\n if (!this.open) return;\n event.stopPropagation();\n this.closeList();\n return;\n case 'Tab':\n this.closeList();\n }\n }\n\n private optionId(index: number): string {\n return `${this.listId}-option-${index}`;\n }\n\n override render(): TemplateResult {\n const selected = this.selectedOption;\n const showClear = this.clearable && selected !== undefined && !this.inactive;\n\n return html`<div\n class=${classMap({ open: this.open, error: Boolean(this.error) })}\n @keydown=${this.onKeyDown}\n >\n <button\n part=\"trigger\"\n type=\"button\"\n class=\"trigger\"\n role=\"combobox\"\n aria-haspopup=\"listbox\"\n aria-expanded=${this.open ? 'true' : 'false'}\n aria-controls=${this.listId}\n aria-activedescendant=${\n this.open && this.activeIndex >= 0 ? this.optionId(this.activeIndex) : nothing\n }\n aria-label=${this.label || nothing}\n aria-invalid=${this.error ? 'true' : nothing}\n ?disabled=${this.inactive}\n @click=${this.toggleList}\n >\n <span class=${classMap({ value: true, placeholder: !selected })}>\n ${selected ? optionLabel(selected) : (this.placeholder ?? strings().select)}\n </span>\n <span class=\"icons\">\n ${\n showClear\n ? html`<span\n class=\"clear\"\n role=\"button\"\n tabindex=\"-1\"\n aria-label=${strings().clear}\n @click=${this.clear}\n >\n <kt-icon name=\"x\" size=\"18\"></kt-icon>\n </span>`\n : nothing\n }\n <span class=\"chevron\"><kt-icon name=\"chevron-down\" size=\"18\"></kt-icon></span>\n </span>\n </button>\n\n <ul\n part=\"popup\"\n id=${this.listId}\n popover=\"manual\"\n class=${classMap({ popup: true, floating: true, open: this.open, top: this.placement === 'top' })}\n role=\"listbox\"\n aria-label=${this.label || (this.placeholder ?? strings().select)}\n >\n ${\n this.options.length === 0\n ? html`<li class=\"empty\">${this.emptyText ?? strings().noOptions}</li>`\n : this.options.map(\n (option, index) =>\n html`<li\n part=\"option\"\n id=${this.optionId(index)}\n class=${classMap({\n option: true,\n selected: option.id === this.value,\n active: index === this.activeIndex,\n disabled: Boolean(option.disabled),\n })}\n role=\"option\"\n aria-selected=${option.id === this.value ? 'true' : 'false'}\n aria-disabled=${option.disabled ? 'true' : nothing}\n @click=${() => this.choose(option)}\n >\n ${optionLabel(option)}\n </li>`,\n )\n }\n </ul>\n </div>`;\n }\n}\n\ndefineElement('kt-select', KtSelect);\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'kt-select': KtSelect;\n }\n}\n"],"names":["KtSelect","KtElement","uniqueId","FloatingController","side","event","floatingStyles","listboxStyles","css","attachFormInternals","toggleListener","changed","setFormValue","missing","setValidity","strings","disabled","state","options","option","selected","firstEnabledIndex","emit","nextEnabledIndex","lastEnabledIndex","index","showClear","html","classMap","nothing","optionLabel","__decorateClass","property","defineElement"],"mappings":"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"}
|
|
@@ -30,6 +30,10 @@ export declare class KtTextarea extends KtElement {
|
|
|
30
30
|
rows: number;
|
|
31
31
|
maxlength?: number;
|
|
32
32
|
disabled: boolean;
|
|
33
|
+
/** Disabled by an enclosing `<fieldset>`, which leaves `disabled` alone. */
|
|
34
|
+
private formDisabled;
|
|
35
|
+
/** Whether the control is off, by its own `disabled` or by its form. */
|
|
36
|
+
private get inactive();
|
|
33
37
|
readonly: boolean;
|
|
34
38
|
required: boolean;
|
|
35
39
|
/** Error message. A non-empty value puts the field in its error state. */
|
|
@@ -48,6 +52,11 @@ export declare class KtTextarea extends KtElement {
|
|
|
48
52
|
connectedCallback(): void;
|
|
49
53
|
willUpdate(changed: PropertyValues<this>): void;
|
|
50
54
|
formResetCallback(): void;
|
|
55
|
+
/**
|
|
56
|
+
* Called by the platform when the control's disabled state changes — its
|
|
57
|
+
* own `disabled`, or an ancestor `<fieldset disabled>` it cannot see.
|
|
58
|
+
*/
|
|
59
|
+
formDisabledCallback(disabled: boolean): void;
|
|
51
60
|
formStateRestoreCallback(state: string): void;
|
|
52
61
|
focus(options?: FocusOptions): void;
|
|
53
62
|
blur(): void;
|
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
import { css as m, nothing as i, html as l } from "lit";
|
|
2
|
-
import { query as f, property as a } from "lit/decorators.js";
|
|
2
|
+
import { query as f, property as a, state as b } from "lit/decorators.js";
|
|
3
3
|
import { classMap as u } from "lit/directives/class-map.js";
|
|
4
4
|
import { live as g } from "lit/directives/live.js";
|
|
5
|
-
import { K as c, d as
|
|
6
|
-
import { e as p } from "../../../chunks/events-
|
|
7
|
-
import { a as
|
|
8
|
-
import { s as
|
|
5
|
+
import { K as c, d as y } from "../../../chunks/kt-element-Djx2JcGl.js";
|
|
6
|
+
import { e as p } from "../../../chunks/events-r51msXNf.js";
|
|
7
|
+
import { a as x, s as v, b as w } from "../../../chunks/form-control-B74_EHtG.js";
|
|
8
|
+
import { s as $ } from "../../../chunks/index-STEEvEP7.js";
|
|
9
9
|
import "../../core/kt-icon/kt-icon.js";
|
|
10
|
-
var
|
|
10
|
+
var k = Object.defineProperty, r = (n, e, o, C) => {
|
|
11
11
|
for (var s = void 0, h = n.length - 1, d; h >= 0; h--)
|
|
12
12
|
(d = n[h]) && (s = d(e, o, s) || s);
|
|
13
|
-
return s &&
|
|
13
|
+
return s && k(e, o, s), s;
|
|
14
14
|
};
|
|
15
15
|
class t extends c {
|
|
16
16
|
constructor() {
|
|
17
|
-
super(...arguments), this.internals = null, this.defaultValue = "", this.value = "", this.name = "", this.placeholder = "", this.rows = 3, this.disabled = !1, this.readonly = !1, this.required = !1, this.error = "", this.label = "", this.resize = "none";
|
|
17
|
+
super(...arguments), this.internals = null, this.defaultValue = "", this.value = "", this.name = "", this.placeholder = "", this.rows = 3, this.disabled = !1, this.formDisabled = !1, this.readonly = !1, this.required = !1, this.error = "", this.label = "", this.resize = "none";
|
|
18
18
|
}
|
|
19
19
|
static {
|
|
20
20
|
this.formAssociated = !0;
|
|
@@ -124,23 +124,34 @@ class t extends c {
|
|
|
124
124
|
`
|
|
125
125
|
];
|
|
126
126
|
}
|
|
127
|
+
/** Whether the control is off, by its own `disabled` or by its form. */
|
|
128
|
+
get inactive() {
|
|
129
|
+
return this.disabled || this.formDisabled;
|
|
130
|
+
}
|
|
127
131
|
connectedCallback() {
|
|
128
|
-
super.connectedCallback(), this.internals ??=
|
|
132
|
+
super.connectedCallback(), this.internals ??= x(this), this.defaultValue = this.value, v(this.internals, this.value);
|
|
129
133
|
}
|
|
130
134
|
willUpdate(e) {
|
|
131
135
|
if (e.has("value") || e.has("required") || e.has("error") || this.stringsChanged(e)) {
|
|
132
136
|
v(this.internals, this.value);
|
|
133
137
|
const o = this.required && this.value.length === 0;
|
|
134
|
-
|
|
138
|
+
w(
|
|
135
139
|
this.internals,
|
|
136
140
|
{ valueMissing: o, customError: !!this.error },
|
|
137
|
-
this.error || (o ?
|
|
141
|
+
this.error || (o ? $().required : "")
|
|
138
142
|
);
|
|
139
143
|
}
|
|
140
144
|
}
|
|
141
145
|
formResetCallback() {
|
|
142
146
|
this.value = this.defaultValue;
|
|
143
147
|
}
|
|
148
|
+
/**
|
|
149
|
+
* Called by the platform when the control's disabled state changes — its
|
|
150
|
+
* own `disabled`, or an ancestor `<fieldset disabled>` it cannot see.
|
|
151
|
+
*/
|
|
152
|
+
formDisabledCallback(e) {
|
|
153
|
+
this.formDisabled = e;
|
|
154
|
+
}
|
|
144
155
|
formStateRestoreCallback(e) {
|
|
145
156
|
this.value = e;
|
|
146
157
|
}
|
|
@@ -163,7 +174,7 @@ class t extends c {
|
|
|
163
174
|
class=${u({
|
|
164
175
|
field: !0,
|
|
165
176
|
error: !!this.error,
|
|
166
|
-
disabled: this.
|
|
177
|
+
disabled: this.inactive
|
|
167
178
|
})}
|
|
168
179
|
>
|
|
169
180
|
${this.error ? l`<span id="error-message" class="visually-hidden">${this.error}</span>` : i}
|
|
@@ -177,7 +188,7 @@ class t extends c {
|
|
|
177
188
|
aria-invalid=${this.error ? "true" : i}
|
|
178
189
|
aria-describedby=${this.error ? "error-message" : i}
|
|
179
190
|
.value=${g(this.value)}
|
|
180
|
-
?disabled=${this.
|
|
191
|
+
?disabled=${this.inactive}
|
|
181
192
|
?readonly=${this.readonly}
|
|
182
193
|
?required=${this.required}
|
|
183
194
|
@input=${this.onInput}
|
|
@@ -220,6 +231,9 @@ r([
|
|
|
220
231
|
r([
|
|
221
232
|
a({ type: Boolean, reflect: !0 })
|
|
222
233
|
], t.prototype, "disabled");
|
|
234
|
+
r([
|
|
235
|
+
b()
|
|
236
|
+
], t.prototype, "formDisabled");
|
|
223
237
|
r([
|
|
224
238
|
a({ type: Boolean, reflect: !0 })
|
|
225
239
|
], t.prototype, "readonly");
|
|
@@ -235,7 +249,7 @@ r([
|
|
|
235
249
|
r([
|
|
236
250
|
a({ type: String, reflect: !0 })
|
|
237
251
|
], t.prototype, "resize");
|
|
238
|
-
|
|
252
|
+
y("kt-textarea", t);
|
|
239
253
|
export {
|
|
240
254
|
t as KtTextarea
|
|
241
255
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"kt-textarea.js","sources":["../../../../src/components/forms/kt-textarea/kt-textarea.ts"],"sourcesContent":["import { css, html, nothing, type PropertyValues, type TemplateResult } from 'lit';\nimport { property, query } from 'lit/decorators.js';\nimport { classMap } from 'lit/directives/class-map.js';\nimport { live } from 'lit/directives/live.js';\nimport { KtElement, defineElement } from '#internal/kt-element';\nimport { emit } from '#internal/events';\nimport {\n attachFormInternals,\n setFormValue,\n setValidity,\n type UsableInternals,\n} from '#internal/form-control';\nimport { strings } from '#internal/strings';\nimport '../../core/kt-icon/kt-icon.js';\n\n/**\n * A multi-line text field, with the same borderless fill and outline states as\n * `<kt-input>`.\n *\n * A character counter appears whenever `maxlength` is set — the field tells\n * the user where the limit is before the browser silently stops accepting\n * keystrokes.\n *\n * @element kt-textarea\n *\n * @csspart base - The field container.\n * @csspart control - The native `<textarea>`.\n * @csspart counter - The character counter.\n *\n * @fires kt-input - On every keystroke. `detail: { value }`.\n * @fires kt-change - When the value is committed. `detail: { value }`.\n */\nexport class KtTextarea extends KtElement {\n static readonly formAssociated = true;\n\n static override styles = [\n KtElement.styles,\n css`\n :host {\n display: block;\n }\n\n .field {\n display: flex;\n align-items: flex-start;\n width: 100%;\n min-height: var(--button-height);\n background-color: var(--surface-field);\n border-radius: var(--radius-input);\n /* A resting hairline. A field is a fill on --surface-field, which is\n one ramp step from the page in dark and almost the same colour in\n light — so on a card or inside a modal it simply disappeared and\n read as a bare native control.\n\n A border rather than an outline, because the control inside fills\n the field exactly and a coincident outline is painted over by the\n native widget. A border insets the control by its own width, so it\n cannot be covered. box-sizing: border-box keeps the outer size.\n\n The hover and focus rings stay outlines on top of it, and the\n transparent resting outline is what they animate from: without it\n outline-color starts at the initial value, which resolves to the\n text colour, and hover flashed near-white before settling. */\n border: var(--border-width) solid var(--border-field);\n outline: var(--outline-width) solid transparent;\n transition: outline-color var(--duration-instant);\n }\n\n .field:hover {\n outline: var(--outline-width) solid var(--color-text-700);\n }\n .field:focus-within {\n outline: var(--outline-width) solid var(--color-primary-base);\n }\n\n .error,\n .error:hover,\n .error:focus-within {\n outline: var(--outline-width) solid var(--color-danger-base);\n }\n .error textarea {\n color: var(--color-danger-text);\n }\n\n .disabled {\n background-color: var(--color-dark-14);\n pointer-events: none;\n }\n .disabled textarea {\n color: var(--text-disabled);\n }\n\n textarea {\n width: 100%;\n min-height: calc(var(--button-height) - var(--gap-element) * 2);\n padding: var(--text-area-padding);\n color: var(--text-body);\n font: var(--font-input);\n background: transparent;\n border: none;\n outline: none;\n resize: none;\n }\n\n :host([resize='vertical']) textarea {\n resize: vertical;\n }\n\n textarea::placeholder {\n color: var(--text-muted);\n }\n\n .meta {\n display: flex;\n flex: none;\n flex-direction: column;\n align-items: center;\n gap: var(--gap-element);\n margin: 10px var(--button-padding-x) 0 0;\n }\n\n .counter {\n color: var(--color-text-700);\n font: var(--font-normal-small);\n font-variant-numeric: tabular-nums;\n white-space: nowrap;\n }\n\n .counter.at-limit {\n color: var(--color-danger-text);\n }\n\n .error-icon {\n display: flex;\n color: var(--color-danger-text);\n }\n `,\n ];\n\n @query('textarea')\n private control!: HTMLTextAreaElement;\n\n private internals: UsableInternals | null = null;\n private defaultValue = '';\n\n @property({ type: String })\n value = '';\n\n @property({ type: String })\n name = '';\n\n @property({ type: String })\n placeholder = '';\n\n @property({ type: Number })\n rows = 3;\n\n @property({ type: Number })\n maxlength?: number;\n\n @property({ type: Boolean, reflect: true })\n disabled = false;\n\n @property({ type: Boolean, reflect: true })\n readonly = false;\n\n @property({ type: Boolean, reflect: true })\n required = false;\n\n /** Error message. A non-empty value puts the field in its error state. */\n @property({ type: String, reflect: true })\n error = '';\n\n /** Accessible name, when no `<kt-label-input>` wraps the field. */\n @property({ type: String })\n label = '';\n\n /**\n * Whether the reader may drag the field taller.\n *\n * Off by default, as in the rest of Kanto: the grip is drawn by the operating\n * system, lands on the field's rounded corner and belongs to no design\n * system — and a field the layout sized is not usually the reader's to\n * resize. Turn it on where the content genuinely varies.\n */\n @property({ type: String, reflect: true })\n resize: 'vertical' | 'none' = 'none';\n\n override connectedCallback(): void {\n super.connectedCallback();\n this.internals ??= attachFormInternals(this);\n this.defaultValue = this.value;\n setFormValue(this.internals, this.value);\n }\n\n override willUpdate(changed: PropertyValues<this>): void {\n if (\n changed.has('value') ||\n changed.has('required') ||\n changed.has('error') ||\n this.stringsChanged(changed)\n ) {\n setFormValue(this.internals, this.value);\n\n const missing = this.required && this.value.length === 0;\n setValidity(\n this.internals,\n { valueMissing: missing, customError: Boolean(this.error) },\n this.error || (missing ? strings().required : ''),\n );\n }\n }\n\n formResetCallback(): void {\n this.value = this.defaultValue;\n }\n\n formStateRestoreCallback(state: string): void {\n this.value = state;\n }\n\n override focus(options?: FocusOptions): void {\n this.control?.focus(options);\n }\n\n override blur(): void {\n this.control?.blur();\n }\n\n private onInput(event: Event): void {\n this.value = (event.target as HTMLTextAreaElement).value;\n emit(this, 'kt-input', { value: this.value });\n }\n\n private onChange(event: Event): void {\n event.stopPropagation();\n emit(this, 'kt-change', { value: this.value });\n }\n\n override render(): TemplateResult {\n const showCounter = this.maxlength !== undefined;\n const atLimit = this.maxlength !== undefined && this.value.length >= this.maxlength;\n\n return html`<div\n part=\"base\"\n class=${classMap({\n field: true,\n error: Boolean(this.error),\n disabled: this.disabled,\n })}\n >\n ${\n this.error\n ? html`<span id=\"error-message\" class=\"visually-hidden\">${this.error}</span>`\n : nothing\n }\n <textarea\n part=\"control\"\n name=${this.name || nothing}\n rows=${this.rows}\n maxlength=${this.maxlength ?? nothing}\n placeholder=${this.placeholder || nothing}\n aria-label=${this.label || nothing}\n aria-invalid=${this.error ? 'true' : nothing}\n aria-describedby=${this.error ? 'error-message' : nothing}\n .value=${live(this.value)}\n ?disabled=${this.disabled}\n ?readonly=${this.readonly}\n ?required=${this.required}\n @input=${this.onInput}\n @change=${this.onChange}\n ></textarea>\n\n ${\n this.error || showCounter\n ? html`<div class=\"meta\">\n ${\n this.error\n ? html`<span class=\"error-icon\" title=${this.error}>\n <kt-icon name=\"circle-alert\" size=\"18\" label=${this.error}></kt-icon>\n </span>`\n : nothing\n }\n ${\n showCounter\n ? html`<span\n part=\"counter\"\n class=${classMap({ counter: true, 'at-limit': atLimit })}\n aria-live=\"polite\"\n >\n ${this.value.length} / ${this.maxlength}\n </span>`\n : nothing\n }\n </div>`\n : nothing\n }\n </div>`;\n }\n}\n\ndefineElement('kt-textarea', KtTextarea);\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'kt-textarea': KtTextarea;\n }\n}\n"],"names":["KtTextarea","KtElement","css","attachFormInternals","setFormValue","changed","missing","setValidity","strings","state","options","event","emit","showCounter","atLimit","html","classMap","nothing","live","__decorateClass","query","property","defineElement"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"kt-textarea.js","sources":["../../../../src/components/forms/kt-textarea/kt-textarea.ts"],"sourcesContent":["import { css, html, nothing, type PropertyValues, type TemplateResult } from 'lit';\nimport { property, query, state } from 'lit/decorators.js';\nimport { classMap } from 'lit/directives/class-map.js';\nimport { live } from 'lit/directives/live.js';\nimport { KtElement, defineElement } from '#internal/kt-element';\nimport { emit } from '#internal/events';\nimport {\n attachFormInternals,\n setFormValue,\n setValidity,\n type UsableInternals,\n} from '#internal/form-control';\nimport { strings } from '#internal/strings';\nimport '../../core/kt-icon/kt-icon.js';\n\n/**\n * A multi-line text field, with the same borderless fill and outline states as\n * `<kt-input>`.\n *\n * A character counter appears whenever `maxlength` is set — the field tells\n * the user where the limit is before the browser silently stops accepting\n * keystrokes.\n *\n * @element kt-textarea\n *\n * @csspart base - The field container.\n * @csspart control - The native `<textarea>`.\n * @csspart counter - The character counter.\n *\n * @fires kt-input - On every keystroke. `detail: { value }`.\n * @fires kt-change - When the value is committed. `detail: { value }`.\n */\nexport class KtTextarea extends KtElement {\n static readonly formAssociated = true;\n\n static override styles = [\n KtElement.styles,\n css`\n :host {\n display: block;\n }\n\n .field {\n display: flex;\n align-items: flex-start;\n width: 100%;\n min-height: var(--button-height);\n background-color: var(--surface-field);\n border-radius: var(--radius-input);\n /* A resting hairline. A field is a fill on --surface-field, which is\n one ramp step from the page in dark and almost the same colour in\n light — so on a card or inside a modal it simply disappeared and\n read as a bare native control.\n\n A border rather than an outline, because the control inside fills\n the field exactly and a coincident outline is painted over by the\n native widget. A border insets the control by its own width, so it\n cannot be covered. box-sizing: border-box keeps the outer size.\n\n The hover and focus rings stay outlines on top of it, and the\n transparent resting outline is what they animate from: without it\n outline-color starts at the initial value, which resolves to the\n text colour, and hover flashed near-white before settling. */\n border: var(--border-width) solid var(--border-field);\n outline: var(--outline-width) solid transparent;\n transition: outline-color var(--duration-instant);\n }\n\n .field:hover {\n outline: var(--outline-width) solid var(--color-text-700);\n }\n .field:focus-within {\n outline: var(--outline-width) solid var(--color-primary-base);\n }\n\n .error,\n .error:hover,\n .error:focus-within {\n outline: var(--outline-width) solid var(--color-danger-base);\n }\n .error textarea {\n color: var(--color-danger-text);\n }\n\n .disabled {\n background-color: var(--color-dark-14);\n pointer-events: none;\n }\n .disabled textarea {\n color: var(--text-disabled);\n }\n\n textarea {\n width: 100%;\n min-height: calc(var(--button-height) - var(--gap-element) * 2);\n padding: var(--text-area-padding);\n color: var(--text-body);\n font: var(--font-input);\n background: transparent;\n border: none;\n outline: none;\n resize: none;\n }\n\n :host([resize='vertical']) textarea {\n resize: vertical;\n }\n\n textarea::placeholder {\n color: var(--text-muted);\n }\n\n .meta {\n display: flex;\n flex: none;\n flex-direction: column;\n align-items: center;\n gap: var(--gap-element);\n margin: 10px var(--button-padding-x) 0 0;\n }\n\n .counter {\n color: var(--color-text-700);\n font: var(--font-normal-small);\n font-variant-numeric: tabular-nums;\n white-space: nowrap;\n }\n\n .counter.at-limit {\n color: var(--color-danger-text);\n }\n\n .error-icon {\n display: flex;\n color: var(--color-danger-text);\n }\n `,\n ];\n\n @query('textarea')\n private control!: HTMLTextAreaElement;\n\n private internals: UsableInternals | null = null;\n private defaultValue = '';\n\n @property({ type: String })\n value = '';\n\n @property({ type: String })\n name = '';\n\n @property({ type: String })\n placeholder = '';\n\n @property({ type: Number })\n rows = 3;\n\n @property({ type: Number })\n maxlength?: number;\n\n @property({ type: Boolean, reflect: true })\n disabled = false;\n\n /** Disabled by an enclosing `<fieldset>`, which leaves `disabled` alone. */\n @state()\n private formDisabled = false;\n\n /** Whether the control is off, by its own `disabled` or by its form. */\n private get inactive(): boolean {\n return this.disabled || this.formDisabled;\n }\n\n @property({ type: Boolean, reflect: true })\n readonly = false;\n\n @property({ type: Boolean, reflect: true })\n required = false;\n\n /** Error message. A non-empty value puts the field in its error state. */\n @property({ type: String, reflect: true })\n error = '';\n\n /** Accessible name, when no `<kt-label-input>` wraps the field. */\n @property({ type: String })\n label = '';\n\n /**\n * Whether the reader may drag the field taller.\n *\n * Off by default, as in the rest of Kanto: the grip is drawn by the operating\n * system, lands on the field's rounded corner and belongs to no design\n * system — and a field the layout sized is not usually the reader's to\n * resize. Turn it on where the content genuinely varies.\n */\n @property({ type: String, reflect: true })\n resize: 'vertical' | 'none' = 'none';\n\n override connectedCallback(): void {\n super.connectedCallback();\n this.internals ??= attachFormInternals(this);\n this.defaultValue = this.value;\n setFormValue(this.internals, this.value);\n }\n\n override willUpdate(changed: PropertyValues<this>): void {\n if (\n changed.has('value') ||\n changed.has('required') ||\n changed.has('error') ||\n this.stringsChanged(changed)\n ) {\n setFormValue(this.internals, this.value);\n\n const missing = this.required && this.value.length === 0;\n setValidity(\n this.internals,\n { valueMissing: missing, customError: Boolean(this.error) },\n this.error || (missing ? strings().required : ''),\n );\n }\n }\n\n formResetCallback(): void {\n this.value = this.defaultValue;\n }\n\n /**\n * Called by the platform when the control's disabled state changes — its\n * own `disabled`, or an ancestor `<fieldset disabled>` it cannot see.\n */\n formDisabledCallback(disabled: boolean): void {\n this.formDisabled = disabled;\n }\n\n formStateRestoreCallback(state: string): void {\n this.value = state;\n }\n\n override focus(options?: FocusOptions): void {\n this.control?.focus(options);\n }\n\n override blur(): void {\n this.control?.blur();\n }\n\n private onInput(event: Event): void {\n this.value = (event.target as HTMLTextAreaElement).value;\n emit(this, 'kt-input', { value: this.value });\n }\n\n private onChange(event: Event): void {\n event.stopPropagation();\n emit(this, 'kt-change', { value: this.value });\n }\n\n override render(): TemplateResult {\n const showCounter = this.maxlength !== undefined;\n const atLimit = this.maxlength !== undefined && this.value.length >= this.maxlength;\n\n return html`<div\n part=\"base\"\n class=${classMap({\n field: true,\n error: Boolean(this.error),\n disabled: this.inactive,\n })}\n >\n ${\n this.error\n ? html`<span id=\"error-message\" class=\"visually-hidden\">${this.error}</span>`\n : nothing\n }\n <textarea\n part=\"control\"\n name=${this.name || nothing}\n rows=${this.rows}\n maxlength=${this.maxlength ?? nothing}\n placeholder=${this.placeholder || nothing}\n aria-label=${this.label || nothing}\n aria-invalid=${this.error ? 'true' : nothing}\n aria-describedby=${this.error ? 'error-message' : nothing}\n .value=${live(this.value)}\n ?disabled=${this.inactive}\n ?readonly=${this.readonly}\n ?required=${this.required}\n @input=${this.onInput}\n @change=${this.onChange}\n ></textarea>\n\n ${\n this.error || showCounter\n ? html`<div class=\"meta\">\n ${\n this.error\n ? html`<span class=\"error-icon\" title=${this.error}>\n <kt-icon name=\"circle-alert\" size=\"18\" label=${this.error}></kt-icon>\n </span>`\n : nothing\n }\n ${\n showCounter\n ? html`<span\n part=\"counter\"\n class=${classMap({ counter: true, 'at-limit': atLimit })}\n aria-live=\"polite\"\n >\n ${this.value.length} / ${this.maxlength}\n </span>`\n : nothing\n }\n </div>`\n : nothing\n }\n </div>`;\n }\n}\n\ndefineElement('kt-textarea', KtTextarea);\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'kt-textarea': KtTextarea;\n }\n}\n"],"names":["KtTextarea","KtElement","css","attachFormInternals","setFormValue","changed","missing","setValidity","strings","disabled","state","options","event","emit","showCounter","atLimit","html","classMap","nothing","live","__decorateClass","query","property","defineElement"],"mappings":"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"}
|
|
@@ -31,6 +31,10 @@ export declare class KtToggle extends KtElement {
|
|
|
31
31
|
private defaultChecked;
|
|
32
32
|
checked: boolean;
|
|
33
33
|
disabled: boolean;
|
|
34
|
+
/** Disabled by an enclosing `<fieldset>`, which leaves `disabled` alone. */
|
|
35
|
+
private formDisabled;
|
|
36
|
+
/** Whether the control is off, by its own `disabled` or by its form. */
|
|
37
|
+
private get inactive();
|
|
34
38
|
size: KtToggleSize;
|
|
35
39
|
name: string;
|
|
36
40
|
/** Submitted when checked, as for a native checkbox. */
|
|
@@ -41,6 +45,11 @@ export declare class KtToggle extends KtElement {
|
|
|
41
45
|
willUpdate(changed: PropertyValues<this>): void;
|
|
42
46
|
private syncFormValue;
|
|
43
47
|
formResetCallback(): void;
|
|
48
|
+
/**
|
|
49
|
+
* Called by the platform when the control's disabled state changes — its
|
|
50
|
+
* own `disabled`, or an ancestor `<fieldset disabled>` it cannot see.
|
|
51
|
+
*/
|
|
52
|
+
formDisabledCallback(disabled: boolean): void;
|
|
44
53
|
formStateRestoreCallback(state: string): void;
|
|
45
54
|
focus(options?: FocusOptions): void;
|
|
46
55
|
private toggle;
|