bank20baht-ui 0.6.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/base.d.ts +6 -0
- package/dist/components/base.js +103 -90
- package/dist/components/primitives/baht-currency.js +31 -28
- package/dist/components/primitives/baht-input.js +26 -23
- package/dist/components/primitives/baht-select.js +1 -0
- package/dist/components/primitives/baht-textarea.js +27 -24
- package/dist/core/types.d.ts +6 -0
- package/dist/css/components.css +51 -6
- package/dist/custom-elements.json +369 -0
- package/dist/tokens.css +51 -6
- package/dist/vscode.html-custom-data.json +12 -12
- package/dist/web-types.json +13 -13
- package/package.json +1 -1
|
@@ -92,6 +92,12 @@ export declare abstract class BahtFieldBase extends BahtElement {
|
|
|
92
92
|
/** Emit the user's edit upward (composed so it crosses any boundary). */
|
|
93
93
|
protected emitInput(value: unknown): void;
|
|
94
94
|
protected abstract renderControl(): TemplateResult;
|
|
95
|
+
/** True when `field.icon` names a real icon — gates both the icon markup
|
|
96
|
+
* and the control's icon-padding class, so a typo/removed name never
|
|
97
|
+
* leaves the control indented for a glyph that isn't there. */
|
|
98
|
+
protected get hasFieldIcon(): boolean;
|
|
99
|
+
/** Leading icon for text/currency/textarea/dropdown controls (spec: field.icon). */
|
|
100
|
+
protected renderFieldIcon(): TemplateResult | typeof nothing;
|
|
95
101
|
protected renderLabel(): TemplateResult | typeof nothing;
|
|
96
102
|
/** Required asterisk, or the "(optional)" marker when the form asks for it. */
|
|
97
103
|
protected renderLabelMark(): TemplateResult | typeof nothing;
|
package/dist/components/base.js
CHANGED
|
@@ -1,36 +1,37 @@
|
|
|
1
|
-
import { nothing as
|
|
2
|
-
import { property as
|
|
3
|
-
import { t as
|
|
4
|
-
|
|
1
|
+
import { nothing as o, html as a, LitElement as y, ReactiveElement as m } from "lit";
|
|
2
|
+
import { property as l } from "lit/decorators.js";
|
|
3
|
+
import { t as v } from "../core/i18n.js";
|
|
4
|
+
import { isIconName as c, renderIcon as C } from "./primitives/icons.js";
|
|
5
|
+
var I = Object.defineProperty, d = (i, e, t, s) => {
|
|
5
6
|
for (var r = void 0, u = i.length - 1, p; u >= 0; u--)
|
|
6
|
-
(p = i[u]) && (r = p(
|
|
7
|
-
return r &&
|
|
7
|
+
(p = i[u]) && (r = p(e, t, r) || r);
|
|
8
|
+
return r && I(e, t, r), r;
|
|
8
9
|
};
|
|
9
|
-
function
|
|
10
|
+
function f() {
|
|
10
11
|
return typeof document < "u" && typeof document.querySelector == "function";
|
|
11
12
|
}
|
|
12
|
-
const
|
|
13
|
-
function
|
|
14
|
-
if (i[
|
|
15
|
-
const
|
|
16
|
-
return (
|
|
13
|
+
const T = Symbol.for("bahtui.ssrStash");
|
|
14
|
+
function $(i) {
|
|
15
|
+
if (i[T]) return !0;
|
|
16
|
+
const e = i.firstChild;
|
|
17
|
+
return (e == null ? void 0 : e.nodeType) === 8 && e.data.startsWith("lit-part");
|
|
17
18
|
}
|
|
18
|
-
function
|
|
19
|
-
let
|
|
20
|
-
if (!
|
|
21
|
-
let
|
|
22
|
-
for (;
|
|
23
|
-
const s =
|
|
24
|
-
if (
|
|
25
|
-
const r =
|
|
26
|
-
r.startsWith("lit-part") ?
|
|
19
|
+
function g(i) {
|
|
20
|
+
let e = i.firstChild;
|
|
21
|
+
if (!e || e.nodeType !== 8 || !e.data.startsWith("lit-part")) return;
|
|
22
|
+
let t = 0;
|
|
23
|
+
for (; e; ) {
|
|
24
|
+
const s = e.nextSibling;
|
|
25
|
+
if (e.nodeType === 8) {
|
|
26
|
+
const r = e.data;
|
|
27
|
+
r.startsWith("lit-part") ? t += 1 : r.startsWith("/lit-part") && (t -= 1);
|
|
27
28
|
}
|
|
28
|
-
if (
|
|
29
|
-
|
|
29
|
+
if (e.remove(), t === 0) break;
|
|
30
|
+
e = s;
|
|
30
31
|
}
|
|
31
32
|
}
|
|
32
|
-
let
|
|
33
|
-
class
|
|
33
|
+
let b = 0;
|
|
34
|
+
class k extends y {
|
|
34
35
|
constructor() {
|
|
35
36
|
super(...arguments), this.uid = 0;
|
|
36
37
|
}
|
|
@@ -48,43 +49,43 @@ class $ extends b {
|
|
|
48
49
|
static get observedAttributes() {
|
|
49
50
|
return [...super.observedAttributes, "defer-hydration"];
|
|
50
51
|
}
|
|
51
|
-
attributeChangedCallback(
|
|
52
|
-
if (
|
|
52
|
+
attributeChangedCallback(e, t, s) {
|
|
53
|
+
if (e === "defer-hydration") {
|
|
53
54
|
s === null && this.isConnected && super.connectedCallback();
|
|
54
55
|
return;
|
|
55
56
|
}
|
|
56
|
-
super.attributeChangedCallback(
|
|
57
|
+
super.attributeChangedCallback(e, t, s);
|
|
57
58
|
}
|
|
58
59
|
connectedCallback() {
|
|
59
60
|
this.hasAttribute("defer-hydration") || super.connectedCallback();
|
|
60
61
|
}
|
|
61
|
-
update(
|
|
62
|
-
const
|
|
62
|
+
update(e) {
|
|
63
|
+
const t = !this.hasUpdated, s = globalThis.bahtHydrate, r = t && f() && $(this);
|
|
63
64
|
if (r)
|
|
64
65
|
if (s) {
|
|
65
66
|
const u = this.render();
|
|
66
|
-
this.renderOptions.isConnected = this.isConnected,
|
|
67
|
+
this.renderOptions.isConnected = this.isConnected, m.prototype.update.call(this, e), s(u, this, this.renderOptions);
|
|
67
68
|
} else
|
|
68
|
-
|
|
69
|
+
g(this), super.update(e);
|
|
69
70
|
else
|
|
70
|
-
|
|
71
|
-
r && this.uid === 0 && (this.uid = ++
|
|
71
|
+
t && f() && this.uid === 0 && (this.uid = ++b), super.update(e);
|
|
72
|
+
r && this.uid === 0 && (this.uid = ++b, this.requestUpdate());
|
|
72
73
|
}
|
|
73
74
|
/** Dispatch a bubbling, composed CustomEvent — crosses any light/shadow DOM boundary. */
|
|
74
|
-
emit(
|
|
75
|
-
this.dispatchEvent(new CustomEvent(
|
|
75
|
+
emit(e, t) {
|
|
76
|
+
this.dispatchEvent(new CustomEvent(e, { detail: t, bubbles: !0, composed: !0 }));
|
|
76
77
|
}
|
|
77
78
|
}
|
|
78
|
-
function
|
|
79
|
-
let
|
|
80
|
-
for (;
|
|
79
|
+
function E(i, e) {
|
|
80
|
+
let t = e;
|
|
81
|
+
for (; t.parentNode && t.parentNode !== i; ) t = t.parentNode;
|
|
81
82
|
const s = Array.from(i.childNodes).filter(
|
|
82
|
-
(r) => r !==
|
|
83
|
+
(r) => r !== t && r.nodeType !== Node.COMMENT_NODE
|
|
83
84
|
);
|
|
84
|
-
s.length > 0 &&
|
|
85
|
+
s.length > 0 && e.append(...s);
|
|
85
86
|
}
|
|
86
|
-
var
|
|
87
|
-
const n = (
|
|
87
|
+
var h;
|
|
88
|
+
const n = (h = class extends k {
|
|
88
89
|
constructor() {
|
|
89
90
|
super(...arguments), this.value = null, this.disabled = !1, this.readonly = !1, this.required = !1, this.showOptional = !1, this.error = null, this.typed = null, this.onFocusOut = () => this.flushTyped();
|
|
90
91
|
}
|
|
@@ -94,21 +95,21 @@ const n = (d = class extends $ {
|
|
|
94
95
|
disconnectedCallback() {
|
|
95
96
|
this.removeEventListener("focusout", this.onFocusOut), this.flushTyped(), super.disconnectedCallback();
|
|
96
97
|
}
|
|
97
|
-
willUpdate(
|
|
98
|
-
var
|
|
99
|
-
super.willUpdate(
|
|
98
|
+
willUpdate(e) {
|
|
99
|
+
var t;
|
|
100
|
+
super.willUpdate(e), e.has("value") && ((t = this.typed) != null && t.emitted) && (this.typed = null);
|
|
100
101
|
}
|
|
101
102
|
get effectiveDebounce() {
|
|
102
|
-
return this.debounce ??
|
|
103
|
+
return this.debounce ?? h.defaultDebounce;
|
|
103
104
|
}
|
|
104
105
|
/** A typed edit: emitted after `debounce` ms of quiet (or at once when 0). */
|
|
105
|
-
emitTyped(
|
|
106
|
-
const
|
|
107
|
-
if (clearTimeout(this.typedTimer),
|
|
108
|
-
this.typed = null, this.emitInput(
|
|
106
|
+
emitTyped(e) {
|
|
107
|
+
const t = this.effectiveDebounce;
|
|
108
|
+
if (clearTimeout(this.typedTimer), t <= 0) {
|
|
109
|
+
this.typed = null, this.emitInput(e);
|
|
109
110
|
return;
|
|
110
111
|
}
|
|
111
|
-
this.typed = { value:
|
|
112
|
+
this.typed = { value: e, emitted: !1 }, this.typedTimer = setTimeout(() => this.flushTyped(), t);
|
|
112
113
|
}
|
|
113
114
|
/** Hand a pending typed edit to the host now (blur, disconnect, host reads). Idempotent. */
|
|
114
115
|
flushTyped() {
|
|
@@ -119,21 +120,33 @@ const n = (d = class extends $ {
|
|
|
119
120
|
return this.typed ? this.typed.value : this.value;
|
|
120
121
|
}
|
|
121
122
|
/** Emit the user's edit upward (composed so it crosses any boundary). */
|
|
122
|
-
emitInput(
|
|
123
|
-
this.emit("baht-input", { key: this.field.key, value:
|
|
123
|
+
emitInput(e) {
|
|
124
|
+
this.emit("baht-input", { key: this.field.key, value: e });
|
|
125
|
+
}
|
|
126
|
+
/** True when `field.icon` names a real icon — gates both the icon markup
|
|
127
|
+
* and the control's icon-padding class, so a typo/removed name never
|
|
128
|
+
* leaves the control indented for a glyph that isn't there. */
|
|
129
|
+
get hasFieldIcon() {
|
|
130
|
+
const e = this.field.icon;
|
|
131
|
+
return e != null && c(e);
|
|
132
|
+
}
|
|
133
|
+
/** Leading icon for text/currency/textarea/dropdown controls (spec: field.icon). */
|
|
134
|
+
renderFieldIcon() {
|
|
135
|
+
const e = this.field.icon;
|
|
136
|
+
return e == null || !c(e) ? o : a`<span class="baht-field-icon" aria-hidden="true">${C(e)}</span>`;
|
|
124
137
|
}
|
|
125
138
|
renderLabel() {
|
|
126
|
-
return this.field.label ?
|
|
139
|
+
return this.field.label ? a`<label class="baht-label" id=${this.labelId} for=${this.controlId}>
|
|
127
140
|
${this.field.label}${this.renderLabelMark()}
|
|
128
|
-
</label>` :
|
|
141
|
+
</label>` : o;
|
|
129
142
|
}
|
|
130
143
|
/** Required asterisk, or the "(optional)" marker when the form asks for it. */
|
|
131
144
|
renderLabelMark() {
|
|
132
|
-
return this.required ?
|
|
145
|
+
return this.required ? a`<span class="baht-required-mark" aria-hidden="true">*</span>` : this.showOptional ? a`<span class="baht-optional">${v("optional")}</span>` : o;
|
|
133
146
|
}
|
|
134
147
|
get controlId() {
|
|
135
|
-
var
|
|
136
|
-
return `baht-${((
|
|
148
|
+
var e;
|
|
149
|
+
return `baht-${((e = this.field) == null ? void 0 : e.key) ?? ""}-${this.uid}`;
|
|
137
150
|
}
|
|
138
151
|
get labelId() {
|
|
139
152
|
return `${this.controlId}-label`;
|
|
@@ -146,54 +159,54 @@ const n = (d = class extends $ {
|
|
|
146
159
|
}
|
|
147
160
|
/** id list for the control's aria-describedby: error first, then help. */
|
|
148
161
|
get describedBy() {
|
|
149
|
-
const
|
|
162
|
+
const e = [this.error ? this.errorId : "", this.field.help ? this.helpId : ""].filter(
|
|
150
163
|
Boolean
|
|
151
164
|
);
|
|
152
|
-
return
|
|
165
|
+
return e.length > 0 ? e.join(" ") : o;
|
|
153
166
|
}
|
|
154
167
|
/** 'true' while the field is in error, else absent (styles hook on [aria-invalid]). */
|
|
155
168
|
get invalid() {
|
|
156
|
-
return this.error ? "true" :
|
|
169
|
+
return this.error ? "true" : o;
|
|
157
170
|
}
|
|
158
171
|
render() {
|
|
159
|
-
return this.field ?
|
|
172
|
+
return this.field ? a`
|
|
160
173
|
${this.renderLabel()}
|
|
161
174
|
${this.renderControl()}
|
|
162
|
-
${this.field.help ?
|
|
163
|
-
${this.error ?
|
|
164
|
-
` :
|
|
175
|
+
${this.field.help ? a`<div class="baht-help" id=${this.helpId}>${this.field.help}</div>` : o}
|
|
176
|
+
${this.error ? a`<div class="baht-error" id=${this.errorId} role="alert">${this.error}</div>` : o}
|
|
177
|
+
` : o;
|
|
165
178
|
}
|
|
166
|
-
},
|
|
167
|
-
|
|
168
|
-
|
|
179
|
+
}, h.defaultDebounce = 150, h);
|
|
180
|
+
d([
|
|
181
|
+
l({ attribute: !1 })
|
|
169
182
|
], n.prototype, "field");
|
|
170
|
-
|
|
171
|
-
|
|
183
|
+
d([
|
|
184
|
+
l({ attribute: !1 })
|
|
172
185
|
], n.prototype, "value");
|
|
173
|
-
|
|
174
|
-
|
|
186
|
+
d([
|
|
187
|
+
l({ type: Boolean })
|
|
175
188
|
], n.prototype, "disabled");
|
|
176
|
-
|
|
177
|
-
|
|
189
|
+
d([
|
|
190
|
+
l({ type: Boolean })
|
|
178
191
|
], n.prototype, "readonly");
|
|
179
|
-
|
|
180
|
-
|
|
192
|
+
d([
|
|
193
|
+
l({ type: Boolean })
|
|
181
194
|
], n.prototype, "required");
|
|
182
|
-
|
|
183
|
-
|
|
195
|
+
d([
|
|
196
|
+
l({ type: Boolean, attribute: "show-optional" })
|
|
184
197
|
], n.prototype, "showOptional");
|
|
185
|
-
|
|
186
|
-
|
|
198
|
+
d([
|
|
199
|
+
l({ attribute: !1 })
|
|
187
200
|
], n.prototype, "error");
|
|
188
|
-
|
|
189
|
-
|
|
201
|
+
d([
|
|
202
|
+
l({ type: Number })
|
|
190
203
|
], n.prototype, "debounce");
|
|
191
|
-
let
|
|
204
|
+
let N = n;
|
|
192
205
|
export {
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
206
|
+
k as BahtElement,
|
|
207
|
+
N as BahtFieldBase,
|
|
208
|
+
T as SSR_STASH,
|
|
209
|
+
E as adoptLightChildren,
|
|
210
|
+
f as hasDom,
|
|
211
|
+
$ as hasSsrMarkup
|
|
199
212
|
};
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import { html as
|
|
1
|
+
import { html as u } from "lit";
|
|
2
2
|
import { state as d, customElement as f } from "lit/decorators.js";
|
|
3
|
-
import { ifDefined as
|
|
4
|
-
import { live as
|
|
5
|
-
import { BahtFieldBase as
|
|
6
|
-
var
|
|
7
|
-
for (var t = n > 1 ? void 0 : n ?
|
|
3
|
+
import { ifDefined as h } from "lit/directives/if-defined.js";
|
|
4
|
+
import { live as p } from "lit/directives/live.js";
|
|
5
|
+
import { BahtFieldBase as m } from "../base.js";
|
|
6
|
+
var b = Object.defineProperty, y = Object.getOwnPropertyDescriptor, c = (r, e, i, n) => {
|
|
7
|
+
for (var t = n > 1 ? void 0 : n ? y(e, i) : e, o = r.length - 1, s; o >= 0; o--)
|
|
8
8
|
(s = r[o]) && (t = (n ? s(e, i, t) : s(t)) || t);
|
|
9
|
-
return n && t &&
|
|
9
|
+
return n && t && b(e, i, t), t;
|
|
10
10
|
};
|
|
11
|
-
function
|
|
11
|
+
function a(r) {
|
|
12
12
|
const e = r.replace(/,/g, "").trim();
|
|
13
13
|
if (e === "" || e === "-") return null;
|
|
14
14
|
const i = Number(e);
|
|
@@ -17,40 +17,43 @@ function u(r) {
|
|
|
17
17
|
function $(r) {
|
|
18
18
|
return r.toLocaleString("en-US", { maximumFractionDigits: 2 });
|
|
19
19
|
}
|
|
20
|
-
let l = class extends
|
|
20
|
+
let l = class extends m {
|
|
21
21
|
constructor() {
|
|
22
22
|
super(...arguments), this.focused = !1;
|
|
23
23
|
}
|
|
24
24
|
displayFor(r) {
|
|
25
25
|
if (r == null || r === "") return "";
|
|
26
|
-
const e = typeof r == "number" ? r :
|
|
26
|
+
const e = typeof r == "number" ? r : a(String(r));
|
|
27
27
|
return e == null ? String(r) : this.focused ? String(e) : $(e);
|
|
28
28
|
}
|
|
29
29
|
renderControl() {
|
|
30
|
-
return
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
30
|
+
return u`<span class="baht-field-icon-wrap">
|
|
31
|
+
${this.renderFieldIcon()}
|
|
32
|
+
<input
|
|
33
|
+
class="baht-control baht-control--currency${this.hasFieldIcon ? " baht-control--has-icon" : ""}"
|
|
34
|
+
id=${this.controlId}
|
|
35
|
+
type="text"
|
|
36
|
+
inputmode="decimal"
|
|
37
|
+
autocomplete="off"
|
|
38
|
+
.value=${p(this.displayFor(this.shownValue))}
|
|
39
|
+
placeholder=${h(this.field.placeholder)}
|
|
40
|
+
?disabled=${this.disabled}
|
|
41
|
+
?readonly=${this.readonly}
|
|
42
|
+
?required=${this.required}
|
|
43
|
+
aria-invalid=${this.invalid}
|
|
44
|
+
aria-describedby=${this.describedBy}
|
|
45
|
+
@focus=${() => {
|
|
44
46
|
this.focused = !0;
|
|
45
47
|
}}
|
|
46
|
-
|
|
48
|
+
@blur=${() => {
|
|
47
49
|
this.focused = !1;
|
|
48
50
|
}}
|
|
49
|
-
|
|
51
|
+
@input=${(r) => {
|
|
50
52
|
const e = r.target.value;
|
|
51
|
-
this.emitTyped(e === "" ? null :
|
|
53
|
+
this.emitTyped(e === "" ? null : a(e));
|
|
52
54
|
}}
|
|
53
|
-
|
|
55
|
+
/>
|
|
56
|
+
</span>`;
|
|
54
57
|
}
|
|
55
58
|
};
|
|
56
59
|
c([
|
|
@@ -1,34 +1,37 @@
|
|
|
1
|
-
import { html as
|
|
2
|
-
import { customElement as
|
|
1
|
+
import { html as d } from "lit";
|
|
2
|
+
import { customElement as h } from "lit/decorators.js";
|
|
3
3
|
import { ifDefined as r } from "lit/directives/if-defined.js";
|
|
4
4
|
import { live as p } from "lit/directives/live.js";
|
|
5
|
-
import { BahtFieldBase as
|
|
6
|
-
var
|
|
7
|
-
for (var t = a > 1 ? void 0 : a ?
|
|
5
|
+
import { BahtFieldBase as c } from "../base.js";
|
|
6
|
+
var m = Object.getOwnPropertyDescriptor, u = (e, l, n, a) => {
|
|
7
|
+
for (var t = a > 1 ? void 0 : a ? m(l, n) : l, i = e.length - 1, s; i >= 0; i--)
|
|
8
8
|
(s = e[i]) && (t = s(t) || t);
|
|
9
9
|
return t;
|
|
10
10
|
};
|
|
11
|
-
let o = class extends
|
|
11
|
+
let o = class extends c {
|
|
12
12
|
renderControl() {
|
|
13
|
-
return
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
13
|
+
return d`<span class="baht-field-icon-wrap">
|
|
14
|
+
${this.renderFieldIcon()}
|
|
15
|
+
<input
|
|
16
|
+
class="baht-control baht-control--text${this.hasFieldIcon ? " baht-control--has-icon" : ""}"
|
|
17
|
+
id=${this.controlId}
|
|
18
|
+
type=${this.field.type === "email" ? "email" : this.field.type === "password" ? "password" : "text"}
|
|
19
|
+
.value=${p(this.shownValue == null ? "" : String(this.shownValue))}
|
|
20
|
+
placeholder=${r(this.field.placeholder)}
|
|
21
|
+
maxlength=${r(this.field.max_length)}
|
|
22
|
+
autocomplete=${r(this.field.autocomplete)}
|
|
23
|
+
?disabled=${this.disabled}
|
|
24
|
+
?readonly=${this.readonly}
|
|
25
|
+
?required=${this.required}
|
|
26
|
+
aria-invalid=${this.invalid}
|
|
27
|
+
aria-describedby=${this.describedBy}
|
|
28
|
+
@input=${(e) => this.emitTyped(e.target.value)}
|
|
29
|
+
/>
|
|
30
|
+
</span>`;
|
|
28
31
|
}
|
|
29
32
|
};
|
|
30
|
-
o =
|
|
31
|
-
|
|
33
|
+
o = u([
|
|
34
|
+
h("baht-input")
|
|
32
35
|
], o);
|
|
33
36
|
export {
|
|
34
37
|
o as BahtInput
|
|
@@ -137,6 +137,7 @@ let n = class extends f {
|
|
|
137
137
|
@click=${() => this.toggle()}
|
|
138
138
|
@keydown=${(s) => this.onKeydown(s)}
|
|
139
139
|
>
|
|
140
|
+
${this.renderFieldIcon()}
|
|
140
141
|
<span class="baht-select-value">${t[e].label}</span>
|
|
141
142
|
<span class="baht-select-chevron" aria-hidden="true">${m("chevron-down")}</span>
|
|
142
143
|
</button>
|
|
@@ -1,34 +1,37 @@
|
|
|
1
|
-
import { html as
|
|
2
|
-
import { customElement as
|
|
1
|
+
import { html as n } from "lit";
|
|
2
|
+
import { customElement as d } from "lit/decorators.js";
|
|
3
3
|
import { ifDefined as a } from "lit/directives/if-defined.js";
|
|
4
|
-
import { live as
|
|
5
|
-
import { BahtFieldBase as
|
|
6
|
-
var
|
|
7
|
-
for (var t = l > 1 ? void 0 : l ?
|
|
4
|
+
import { live as c } from "lit/directives/live.js";
|
|
5
|
+
import { BahtFieldBase as m } from "../base.js";
|
|
6
|
+
var p = Object.getOwnPropertyDescriptor, f = (e, i, h, l) => {
|
|
7
|
+
for (var t = l > 1 ? void 0 : l ? p(i, h) : i, r = e.length - 1, o; r >= 0; r--)
|
|
8
8
|
(o = e[r]) && (t = o(t) || t);
|
|
9
9
|
return t;
|
|
10
10
|
};
|
|
11
|
-
let s = class extends
|
|
11
|
+
let s = class extends m {
|
|
12
12
|
renderControl() {
|
|
13
|
-
return
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
13
|
+
return n`<span class="baht-field-icon-wrap">
|
|
14
|
+
${this.renderFieldIcon()}
|
|
15
|
+
<textarea
|
|
16
|
+
class="baht-control baht-control--textarea${this.hasFieldIcon ? " baht-control--has-icon" : ""}"
|
|
17
|
+
id=${this.controlId}
|
|
18
|
+
.value=${c(this.shownValue == null ? "" : String(this.shownValue))}
|
|
19
|
+
placeholder=${a(this.field.placeholder)}
|
|
20
|
+
maxlength=${a(this.field.max_length)}
|
|
21
|
+
rows=${this.field.rows ?? 3}
|
|
22
|
+
autocomplete=${a(this.field.autocomplete)}
|
|
23
|
+
?disabled=${this.disabled}
|
|
24
|
+
?readonly=${this.readonly}
|
|
25
|
+
?required=${this.required}
|
|
26
|
+
aria-invalid=${this.invalid}
|
|
27
|
+
aria-describedby=${this.describedBy}
|
|
28
|
+
@input=${(e) => this.emitTyped(e.target.value)}
|
|
29
|
+
></textarea>
|
|
30
|
+
</span>`;
|
|
28
31
|
}
|
|
29
32
|
};
|
|
30
|
-
s =
|
|
31
|
-
|
|
33
|
+
s = f([
|
|
34
|
+
d("baht-textarea")
|
|
32
35
|
], s);
|
|
33
36
|
export {
|
|
34
37
|
s as BahtTextarea
|
package/dist/core/types.d.ts
CHANGED
|
@@ -34,6 +34,12 @@ export interface FieldDescriptor {
|
|
|
34
34
|
key: string;
|
|
35
35
|
label?: string;
|
|
36
36
|
placeholder?: string;
|
|
37
|
+
/**
|
|
38
|
+
* Leading icon inside the control (text/email/password/currency/textarea)
|
|
39
|
+
* or before the value (dropdown) — icon name from the curated set (see
|
|
40
|
+
* icons.ts). Unrecognized names render no icon (no layout shift).
|
|
41
|
+
*/
|
|
42
|
+
icon?: string;
|
|
37
43
|
help?: string;
|
|
38
44
|
autocomplete?: string;
|
|
39
45
|
width?: FieldWidth;
|
package/dist/css/components.css
CHANGED
|
@@ -154,6 +154,41 @@
|
|
|
154
154
|
font-variant-numeric: tabular-nums;
|
|
155
155
|
}
|
|
156
156
|
|
|
157
|
+
/* ---------- field.icon — leading glyph inside text/currency/textarea/
|
|
158
|
+
dropdown controls (spec: FieldDescriptor.icon). Bare `.baht-field-icon`
|
|
159
|
+
is a flex child (used as-is inside <baht-select>'s trigger row); wrapped
|
|
160
|
+
in `.baht-field-icon-wrap` it's absolutely positioned over the control,
|
|
161
|
+
which gets `.baht-control--has-icon` for the extra left padding. ---------- */
|
|
162
|
+
.baht-field-icon {
|
|
163
|
+
display: inline-flex;
|
|
164
|
+
flex: none;
|
|
165
|
+
color: var(--baht-color-text-muted);
|
|
166
|
+
}
|
|
167
|
+
.baht-field-icon .baht-icon {
|
|
168
|
+
height: 1rem;
|
|
169
|
+
}
|
|
170
|
+
.baht-field-icon-wrap {
|
|
171
|
+
position: relative;
|
|
172
|
+
display: block;
|
|
173
|
+
width: 100%;
|
|
174
|
+
}
|
|
175
|
+
.baht-field-icon-wrap .baht-field-icon {
|
|
176
|
+
position: absolute;
|
|
177
|
+
left: var(--baht-control-padding-x);
|
|
178
|
+
top: 50%;
|
|
179
|
+
transform: translateY(-50%);
|
|
180
|
+
pointer-events: none;
|
|
181
|
+
}
|
|
182
|
+
.baht-field-icon-wrap .baht-control--has-icon {
|
|
183
|
+
padding-left: calc(var(--baht-control-padding-x) * 2 + 1rem);
|
|
184
|
+
}
|
|
185
|
+
/* textarea is multi-line — pin the icon to the first line instead of
|
|
186
|
+
vertically centering it over the whole box. */
|
|
187
|
+
.baht-field-icon-wrap:has(.baht-control--textarea) .baht-field-icon {
|
|
188
|
+
top: 10px; /* matches .baht-control's own vertical padding */
|
|
189
|
+
transform: none;
|
|
190
|
+
}
|
|
191
|
+
|
|
157
192
|
/* ---------- <baht-datepicker> input — trailing calendar glyph ---------- */
|
|
158
193
|
.baht-datepicker-field {
|
|
159
194
|
display: block;
|
|
@@ -343,16 +378,28 @@
|
|
|
343
378
|
border-color: var(--baht-color-primary);
|
|
344
379
|
background: var(--baht-color-primary-wash);
|
|
345
380
|
}
|
|
381
|
+
.baht-option--card:has(input:focus-visible) {
|
|
382
|
+
outline: var(--baht-focus-ring);
|
|
383
|
+
outline-offset: 2px;
|
|
384
|
+
}
|
|
346
385
|
.baht-option-card-row {
|
|
347
386
|
display: flex;
|
|
348
387
|
align-items: center;
|
|
349
388
|
gap: var(--baht-space-2);
|
|
350
389
|
}
|
|
390
|
+
/* Selection reads from the card's own border/wash (above), not a radio
|
|
391
|
+
bullet — visually hidden rather than `display: none` so the input stays
|
|
392
|
+
in the tab order and keyboard-focusable (`:focus-visible` above). */
|
|
351
393
|
.baht-option--card input[type='radio'] {
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
394
|
+
position: absolute;
|
|
395
|
+
width: 1px;
|
|
396
|
+
height: 1px;
|
|
397
|
+
padding: 0;
|
|
398
|
+
margin: -1px;
|
|
399
|
+
overflow: hidden;
|
|
400
|
+
clip: rect(0, 0, 0, 0);
|
|
401
|
+
white-space: nowrap;
|
|
402
|
+
border: 0;
|
|
356
403
|
}
|
|
357
404
|
.baht-option-card-icon {
|
|
358
405
|
display: inline-flex;
|
|
@@ -371,8 +418,6 @@
|
|
|
371
418
|
color: var(--baht-color-text);
|
|
372
419
|
}
|
|
373
420
|
.baht-option-card-desc {
|
|
374
|
-
/* aligns under the title: radio width + row gap */
|
|
375
|
-
margin-left: calc(16px + var(--baht-space-2));
|
|
376
421
|
font-size: var(--baht-text-sm);
|
|
377
422
|
color: var(--baht-color-text-muted);
|
|
378
423
|
}
|