bank20baht-ui 0.8.2 → 0.10.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.
@@ -167,7 +167,7 @@ let p = class extends E {
167
167
  return o`<div class="baht-bar-chart-row">
168
168
  <span class="baht-bar-chart-label" title=${y}>${y}</span>
169
169
  <div
170
- class="baht-bar-chart-track${this.stacked ? " baht-bar-chart-track--stacked" : ""}"
170
+ class="baht-bar-chart-track${this.stacked ? " baht-bar-chart-track--stacked" : ""}${this.categoryMarkers(y).length > 0 ? " baht-bar-chart-track--marked" : ""}"
171
171
  tabindex="0"
172
172
  role="button"
173
173
  aria-label=${u}
@@ -25,6 +25,18 @@ export declare class BahtLineChart extends BahtChartBase {
25
25
  labelValues: 'ends' | 'none';
26
26
  /** Accessible summary; falls back to a generated sentence. */
27
27
  label: string;
28
+ /**
29
+ * Drawing width in SVG units. It follows the host up to `W`, so on a phone
30
+ * one unit is one CSS pixel and tick text keeps its real size instead of
31
+ * shrinking with a 640-wide drawing scaled into a 360px card.
32
+ */
33
+ private width;
34
+ private resizeObserver;
35
+ connectedCallback(): void;
36
+ disconnectedCallback(): void;
37
+ protected firstUpdated(): void;
38
+ /** Host width → drawing width. Never runs on the server (`hasDom` guard). */
39
+ private measure;
28
40
  private get plot();
29
41
  protected render(): TemplateResult;
30
42
  private crosshairAt;
@@ -1,151 +1,176 @@
1
- import { html as k, nothing as y, svg as l } from "lit";
2
- import { property as d, customElement as E } from "lit/decorators.js";
3
- import { arr as A } from "../base.js";
4
- import { BahtChartBase as N, niceTicks as V, linearScale as T, chartColor as g, renderTableTwin as q } from "./charts.js";
5
- var U = Object.defineProperty, R = Object.getOwnPropertyDescriptor, m = (b, a, n, o) => {
6
- for (var c = o > 1 ? void 0 : o ? R(a, n) : a, f = b.length - 1, u; f >= 0; f--)
7
- (u = b[f]) && (c = (o ? u(a, n, c) : u(c)) || c);
8
- return o && c && U(a, n, c), c;
1
+ import { html as _, nothing as y, svg as l } from "lit";
2
+ import { property as x, state as H, customElement as N } from "lit/decorators.js";
3
+ import { hasDom as k, arr as L } from "../base.js";
4
+ import { BahtChartBase as W, niceTicks as q, linearScale as O, chartColor as g, renderTableTwin as R } from "./charts.js";
5
+ var U = Object.defineProperty, V = Object.getOwnPropertyDescriptor, c = (o, s, $, r) => {
6
+ for (var d = r > 1 ? void 0 : r ? V(s, $) : s, f = o.length - 1, b; f >= 0; f--)
7
+ (b = o[f]) && (d = (r ? b(s, $, d) : b(d)) || d);
8
+ return r && d && U(s, $, d), d;
9
9
  };
10
- const C = 640, L = 260, s = { top: 14, right: 72, bottom: 30, left: 60 };
11
- let h = class extends N {
10
+ const T = 640, X = 280, A = 260, I = 56, a = { top: 14, right: 72, bottom: 30, left: 60 };
11
+ let h = class extends W {
12
12
  constructor() {
13
- super(...arguments), this.series = [], this.categories = [], this.area = !1, this.markers = [], this.forecast = 0, this.baseline = null, this.labelValues = "ends", this.label = "", this.crosshairAt = null;
13
+ super(...arguments), this.series = [], this.categories = [], this.area = !1, this.markers = [], this.forecast = 0, this.baseline = null, this.labelValues = "ends", this.label = "", this.width = T, this.crosshairAt = null;
14
+ }
15
+ connectedCallback() {
16
+ super.connectedCallback(), !(!k() || typeof ResizeObserver > "u") && (this.resizeObserver = new ResizeObserver(() => {
17
+ this.measure();
18
+ }), this.resizeObserver.observe(this));
19
+ }
20
+ disconnectedCallback() {
21
+ var o;
22
+ (o = this.resizeObserver) == null || o.disconnect(), this.resizeObserver = void 0, super.disconnectedCallback();
23
+ }
24
+ firstUpdated() {
25
+ k() && queueMicrotask(() => {
26
+ this.measure();
27
+ });
28
+ }
29
+ /** Host width → drawing width. Never runs on the server (`hasDom` guard). */
30
+ measure() {
31
+ if (!k() || !this.isConnected) return;
32
+ const o = this.clientWidth;
33
+ if (o <= 0) return;
34
+ const s = Math.min(T, Math.max(X, Math.round(o)));
35
+ s !== this.width && (this.width = s);
14
36
  }
15
37
  get plot() {
16
- return { w: C - s.left - s.right, h: L - s.top - s.bottom };
38
+ return { w: this.width - a.left - a.right, h: A - a.top - a.bottom };
17
39
  }
18
40
  render() {
19
- const b = this.hold({
20
- series: A(this.series).filter((t) => t.values.length > 0),
21
- categories: A(this.categories)
22
- }), { series: a, categories: n } = b;
23
- if (a.length === 0)
24
- return k`<div class=${this.rootClass("baht-line-chart")}>${this.renderEmpty()}</div>`;
25
- const o = Math.max(...a.map((t) => t.values.length)), c = a.flatMap((t) => t.values).filter((t) => Number.isFinite(t)), f = Math.max(0, ...c, ...this.markers.map((t) => t.value)), u = V(f, 4), j = u[u.length - 1] ?? 1, { w: v, h: F } = this.plot, $ = T([0, Math.max(1, o - 1)], [s.left, s.left + v]), r = T([0, j], [s.top + F, s.top]), M = Math.max(0, o - 1 - Math.max(0, this.forecast)), P = (t, e, i) => t.slice(e, i + 1).map((p, x) => `${x === 0 ? "M" : "L"}${$(e + x).toFixed(2)},${r(p).toFixed(2)}`).join(" "), w = a.map((t, e) => ({
41
+ const o = this.hold({
42
+ series: L(this.series).filter((t) => t.values.length > 0),
43
+ categories: L(this.categories)
44
+ }), { series: s, categories: $ } = o;
45
+ if (s.length === 0)
46
+ return _`<div class=${this.rootClass("baht-line-chart")}>${this.renderEmpty()}</div>`;
47
+ const r = Math.max(...s.map((t) => t.values.length)), d = s.flatMap((t) => t.values).filter((t) => Number.isFinite(t)), f = Math.max(0, ...d, ...this.markers.map((t) => t.value)), b = q(f, 4), z = b[b.length - 1] ?? 1, { w: v, h: F } = this.plot, p = O([0, Math.max(1, r - 1)], [a.left, a.left + v]), i = O([0, z], [a.top + F, a.top]), M = Math.max(0, r - 1 - Math.max(0, this.forecast)), w = (t, e, n) => t.slice(e, n + 1).map((u, m) => `${m === 0 ? "M" : "L"}${p(e + m).toFixed(2)},${i(u).toFixed(2)}`).join(" "), P = s.map((t, e) => ({
26
48
  i: e,
27
49
  name: t.name,
28
50
  value: t.values[t.values.length - 1] ?? 0,
29
- yPos: r(t.values[t.values.length - 1] ?? 0),
51
+ yPos: i(t.values[t.values.length - 1] ?? 0),
30
52
  color: g(e, t.color)
31
- })), _ = [...w].sort((t, e) => t.yPos - e.yPos), B = _.some((t, e) => e > 0 && t.yPos - _[e - 1].yPos < 15), H = this.labelValues === "ends" && !B, O = Math.max(1, Math.ceil(o / 8)), D = this.label || `Line chart, ${a.length} series over ${o} points. ${a.map((t, e) => `${t.name}: ${this.fmt(w[e].value)} at the end`).join(". ")}`;
32
- return k`<div class=${this.rootClass("baht-line-chart")}>
53
+ })), C = [...P].sort((t, e) => t.yPos - e.yPos), B = C.some((t, e) => e > 0 && t.yPos - C[e - 1].yPos < 15), j = this.labelValues === "ends" && !B, D = Math.max(1, Math.ceil(r / Math.max(2, Math.min(8, Math.floor(v / I))))), E = this.label || `Line chart, ${s.length} series over ${r} points. ${s.map((t, e) => `${t.name}: ${this.fmt(P[e].value)} at the end`).join(". ")}`;
54
+ return _`<div class=${this.rootClass("baht-line-chart")}>
33
55
  <svg
34
56
  class="baht-chart-svg"
35
- viewBox="0 0 ${C} ${L}"
57
+ viewBox="0 0 ${this.width} ${A}"
36
58
  preserveAspectRatio="xMidYMid meet"
37
59
  role="img"
38
- aria-label=${D}
60
+ aria-label=${E}
39
61
  >
40
- ${u.map(
62
+ ${b.map(
41
63
  (t) => l`
42
- <line class="baht-chart-grid-line" x1=${s.left} x2=${s.left + v}
43
- y1=${r(t).toFixed(2)} y2=${r(t).toFixed(2)}/>
44
- <text class="baht-chart-tick" x=${s.left - 8} y=${(r(t) + 4).toFixed(2)}
64
+ <line class="baht-chart-grid-line" x1=${a.left} x2=${a.left + v}
65
+ y1=${i(t).toFixed(2)} y2=${i(t).toFixed(2)}/>
66
+ <text class="baht-chart-tick" x=${a.left - 8} y=${(i(t) + 4).toFixed(2)}
45
67
  text-anchor="end">${this.fmt(t)}</text>`
46
68
  )}
47
69
  ${this.baseline != null ? [
48
- l`<line class="baht-chart-baseline" x1=${s.left} x2=${s.left + v}
49
- y1=${r(this.baseline).toFixed(2)} y2=${r(this.baseline).toFixed(2)}/>`
70
+ l`<line class="baht-chart-baseline" x1=${a.left} x2=${a.left + v}
71
+ y1=${i(this.baseline).toFixed(2)} y2=${i(this.baseline).toFixed(2)}/>`
50
72
  ] : []}
51
- ${A(this.markers).map(
73
+ ${L(this.markers).map(
52
74
  (t) => l`
53
- <line class="baht-chart-marker-line" x1=${s.left} x2=${s.left + v}
54
- y1=${r(t.value).toFixed(2)} y2=${r(t.value).toFixed(2)}/>
55
- <text class="baht-chart-marker-label" x=${s.left + v} y=${(r(t.value) - 5).toFixed(2)}
75
+ <line class="baht-chart-marker-line" x1=${a.left} x2=${a.left + v}
76
+ y1=${i(t.value).toFixed(2)} y2=${i(t.value).toFixed(2)}/>
77
+ <text class="baht-chart-marker-label" x=${a.left + v} y=${(i(t.value) - 5).toFixed(2)}
56
78
  text-anchor="end">${t.label ?? this.fmt(t.value)}</text>`
57
79
  )}
58
- ${this.area && a.length === 1 ? l`<path class="baht-chart-area" fill=${g(0, a[0].color)}
59
- d=${`${P(a[0].values, 0, o - 1)} L${$(o - 1).toFixed(2)},${r(0).toFixed(2)} L${$(0).toFixed(2)},${r(0).toFixed(2)} Z`}/>` : y}
60
- ${a.map((t, e) => {
61
- const i = g(e, t.color), p = [
62
- l`<path class="baht-chart-line" d=${P(t.values, 0, M)} stroke=${i} fill="none"/>`
80
+ ${this.area && s.length === 1 ? l`<path class="baht-chart-area" fill=${g(0, s[0].color)}
81
+ d=${`${w(s[0].values, 0, r - 1)} L${p(r - 1).toFixed(2)},${i(0).toFixed(2)} L${p(0).toFixed(2)},${i(0).toFixed(2)} Z`}/>` : y}
82
+ ${s.map((t, e) => {
83
+ const n = g(e, t.color), u = [
84
+ l`<path class="baht-chart-line" d=${w(t.values, 0, M)} stroke=${n} fill="none"/>`
63
85
  ];
64
- return M < o - 1 && p.push(
65
- l`<path class="baht-chart-line baht-chart-line--forecast" d=${P(t.values, M, o - 1)}
66
- stroke=${i} fill="none"/>`
67
- ), p.push(
68
- l`<circle class="baht-chart-end-dot" cx=${$(o - 1).toFixed(2)}
69
- cy=${r(t.values[t.values.length - 1] ?? 0).toFixed(2)} r="4" fill=${i}/>`
70
- ), p;
86
+ return M < r - 1 && u.push(
87
+ l`<path class="baht-chart-line baht-chart-line--forecast" d=${w(t.values, M, r - 1)}
88
+ stroke=${n} fill="none"/>`
89
+ ), u.push(
90
+ l`<circle class="baht-chart-end-dot" cx=${p(r - 1).toFixed(2)}
91
+ cy=${i(t.values[t.values.length - 1] ?? 0).toFixed(2)} r="4" fill=${n}/>`
92
+ ), u;
71
93
  })}
72
- ${H ? w.map(
94
+ ${j ? P.map(
73
95
  (t) => l`
74
- <text class="baht-chart-end-label" x=${$(o - 1) + 10} y=${(t.yPos + 4).toFixed(2)}
96
+ <text class="baht-chart-end-label" x=${p(r - 1) + 10} y=${(t.yPos + 4).toFixed(2)}
75
97
  text-anchor="start">${this.fmt(t.value)}</text>`
76
98
  ) : y}
77
- ${n.map(
78
- (t, e) => e % O === 0 ? l`<text class="baht-chart-tick" x=${$(e).toFixed(2)} y=${L - 10} text-anchor="middle">${t}</text>` : y
99
+ ${$.map(
100
+ (t, e) => e % D === 0 ? l`<text class="baht-chart-tick" x=${p(e).toFixed(2)} y=${A - 10} text-anchor="middle">${t}</text>` : y
79
101
  )}
80
- ${Array.from({ length: o }, (t, e) => {
81
- const i = v / Math.max(1, o - 1), p = `${n[e] ?? `Point ${e + 1}`}: ${a.map((x) => `${x.name} ${this.fmt(x.values[e] ?? 0)}`).join(", ")}`;
82
- return l`<rect class="baht-chart-hit" x=${($(e) - i / 2).toFixed(2)} y=${s.top}
83
- width=${Math.max(24, i).toFixed(2)} height=${F} tabindex="0" role="button"
84
- aria-label=${p}
85
- @pointermove=${(x) => {
86
- this.onHover(x, e, p);
102
+ ${Array.from({ length: r }, (t, e) => {
103
+ const n = v / Math.max(1, r - 1), u = `${$[e] ?? `Point ${e + 1}`}: ${s.map((m) => `${m.name} ${this.fmt(m.values[e] ?? 0)}`).join(", ")}`;
104
+ return l`<rect class="baht-chart-hit" x=${(p(e) - n / 2).toFixed(2)} y=${a.top}
105
+ width=${Math.max(24, n).toFixed(2)} height=${F} tabindex="0" role="button"
106
+ aria-label=${u}
107
+ @pointermove=${(m) => {
108
+ this.onHover(m, e, u);
87
109
  }}
88
110
  @pointerleave=${() => {
89
111
  this.onLeave();
90
112
  }}
91
- @focus=${(x) => {
92
- this.onHover(x, e, p);
113
+ @focus=${(m) => {
114
+ this.onHover(m, e, u);
93
115
  }}
94
116
  @blur=${() => {
95
117
  this.onLeave();
96
118
  }}/>`;
97
119
  })}
98
- ${this.crosshairAt != null ? l`<line class="baht-chart-crosshair" x1=${$(this.crosshairAt).toFixed(2)}
99
- x2=${$(this.crosshairAt).toFixed(2)} y1=${s.top} y2=${s.top + F}/>` : y}
120
+ ${this.crosshairAt != null ? l`<line class="baht-chart-crosshair" x1=${p(this.crosshairAt).toFixed(2)}
121
+ x2=${p(this.crosshairAt).toFixed(2)} y1=${a.top} y2=${a.top + F}/>` : y}
100
122
  </svg>
101
123
  ${this.renderTooltip()}
102
124
  ${this.renderLegend(
103
- a.map((t, e) => ({ label: t.name, color: g(e, t.color) })),
125
+ s.map((t, e) => ({ label: t.name, color: g(e, t.color) })),
104
126
  "line"
105
127
  )}
106
- ${this.showTable ? q(
128
+ ${this.showTable ? R(
107
129
  this.label || "Line chart data",
108
- ["Point", ...a.map((t) => t.name)],
109
- Array.from({ length: o }, (t, e) => [
110
- n[e] ?? `Point ${e + 1}`,
111
- ...a.map((i) => this.fmt(i.values[e] ?? 0))
130
+ ["Point", ...s.map((t) => t.name)],
131
+ Array.from({ length: r }, (t, e) => [
132
+ $[e] ?? `Point ${e + 1}`,
133
+ ...s.map((n) => this.fmt(n.values[e] ?? 0))
112
134
  ])
113
135
  ) : y}
114
136
  </div>`;
115
137
  }
116
- onHover(b, a, n) {
117
- this.crosshairAt = a, this.requestUpdate(), this.showTip(b, n);
138
+ onHover(o, s, $) {
139
+ this.crosshairAt = s, this.requestUpdate(), this.showTip(o, $);
118
140
  }
119
141
  onLeave() {
120
142
  this.crosshairAt = null, this.requestUpdate(), this.hideTip();
121
143
  }
122
144
  };
123
- m([
124
- d({ attribute: !1 })
145
+ c([
146
+ x({ attribute: !1 })
125
147
  ], h.prototype, "series", 2);
126
- m([
127
- d({ attribute: !1 })
148
+ c([
149
+ x({ attribute: !1 })
128
150
  ], h.prototype, "categories", 2);
129
- m([
130
- d({ type: Boolean })
151
+ c([
152
+ x({ type: Boolean })
131
153
  ], h.prototype, "area", 2);
132
- m([
133
- d({ attribute: !1 })
154
+ c([
155
+ x({ attribute: !1 })
134
156
  ], h.prototype, "markers", 2);
135
- m([
136
- d({ type: Number })
157
+ c([
158
+ x({ type: Number })
137
159
  ], h.prototype, "forecast", 2);
138
- m([
139
- d({ type: Number })
160
+ c([
161
+ x({ type: Number })
140
162
  ], h.prototype, "baseline", 2);
141
- m([
142
- d({ attribute: "label-values" })
163
+ c([
164
+ x({ attribute: "label-values" })
143
165
  ], h.prototype, "labelValues", 2);
144
- m([
145
- d()
166
+ c([
167
+ x()
146
168
  ], h.prototype, "label", 2);
147
- h = m([
148
- E("baht-line-chart")
169
+ c([
170
+ H()
171
+ ], h.prototype, "width", 2);
172
+ h = c([
173
+ N("baht-line-chart")
149
174
  ], h);
150
175
  export {
151
176
  h as BahtLineChart
@@ -16,6 +16,10 @@ export declare class BahtModal extends BahtElement {
16
16
  /** One muted line under the heading; also becomes the dialog's aria-describedby. */
17
17
  description: string;
18
18
  showClose: boolean;
19
+ /**
20
+ * Scrim click requests close. Off by default: a stray click outside the panel
21
+ * must not throw away what the user typed — close via ×, Escape or your buttons.
22
+ */
19
23
  closeOnScrim: boolean;
20
24
  private bodyEl;
21
25
  private get titleId();
@@ -1,17 +1,21 @@
1
1
  import { nothing as a, html as h } from "lit";
2
- import { property as c, query as f, state as b, customElement as y } from "lit/decorators.js";
3
- import { boolOff as m, BahtElement as v, hasDom as p, adoptLightChildren as u } from "../base.js";
2
+ import { property as c, query as f, state as m, customElement as b } from "lit/decorators.js";
3
+ import { boolOff as y, BahtElement as v, hasDom as p, adoptLightChildren as u } from "../base.js";
4
4
  import { afterExit as g } from "../motion.js";
5
5
  import { t as $ } from "../../core/i18n.js";
6
6
  import { renderIllustration as k } from "./illustrations.js";
7
- var C = Object.defineProperty, S = Object.getOwnPropertyDescriptor, l = (t, i, e, n) => {
8
- for (var o = n > 1 ? void 0 : n ? S(i, e) : i, r = t.length - 1, d; r >= 0; r--)
9
- (d = t[r]) && (o = (n ? d(i, e, o) : d(o)) || o);
7
+ var C = Object.defineProperty, S = Object.getOwnPropertyDescriptor, r = (t, i, e, n) => {
8
+ for (var o = n > 1 ? void 0 : n ? S(i, e) : i, l = t.length - 1, d; l >= 0; l--)
9
+ (d = t[l]) && (o = (n ? d(i, e, o) : d(o)) || o);
10
10
  return n && o && C(i, e, o), o;
11
11
  };
12
+ const E = {
13
+ fromAttribute: (t) => t !== null && t !== "false",
14
+ toAttribute: (t) => t ? "" : null
15
+ };
12
16
  let s = class extends v {
13
17
  constructor() {
14
- super(...arguments), this.open = !1, this.heading = "", this.description = "", this.showClose = !0, this.closeOnScrim = !0, this.closing = !1, this.closeToken = 0, this.previousFocus = null, this.onKeydown = (t) => {
18
+ super(...arguments), this.open = !1, this.heading = "", this.description = "", this.showClose = !0, this.closeOnScrim = !1, this.closing = !1, this.closeToken = 0, this.previousFocus = null, this.onKeydown = (t) => {
15
19
  !this.open || s.openStack.at(-1) !== this || (t.key === "Escape" ? this.requestClose("escape") : t.key === "Tab" && this.trapFocus(t));
16
20
  };
17
21
  }
@@ -36,12 +40,12 @@ let s = class extends v {
36
40
  e == null || e.focus(), t.preventDefault();
37
41
  return;
38
42
  }
39
- const n = i[0], o = i[i.length - 1], r = document.activeElement;
40
- if (!this.contains(r)) {
43
+ const n = i[0], o = i[i.length - 1], l = document.activeElement;
44
+ if (!this.contains(l)) {
41
45
  n.focus(), t.preventDefault();
42
46
  return;
43
47
  }
44
- t.shiftKey && (r === n || r === e) ? (o.focus(), t.preventDefault()) : !t.shiftKey && r === o && (n.focus(), t.preventDefault());
48
+ t.shiftKey && (l === n || l === e) ? (o.focus(), t.preventDefault()) : !t.shiftKey && l === o && (n.focus(), t.preventDefault());
45
49
  }
46
50
  connectedCallback() {
47
51
  super.connectedCallback(), p() && document.addEventListener("keydown", this.onKeydown);
@@ -110,29 +114,29 @@ let s = class extends v {
110
114
  }
111
115
  };
112
116
  s.openStack = [];
113
- l([
117
+ r([
114
118
  c({ type: Boolean, reflect: !0 })
115
119
  ], s.prototype, "open", 2);
116
- l([
120
+ r([
117
121
  c()
118
122
  ], s.prototype, "heading", 2);
119
- l([
123
+ r([
120
124
  c()
121
125
  ], s.prototype, "description", 2);
122
- l([
123
- c({ attribute: "show-close", converter: m })
126
+ r([
127
+ c({ attribute: "show-close", converter: y })
124
128
  ], s.prototype, "showClose", 2);
125
- l([
126
- c({ attribute: "close-on-scrim", converter: m })
129
+ r([
130
+ c({ attribute: "close-on-scrim", converter: E })
127
131
  ], s.prototype, "closeOnScrim", 2);
128
- l([
132
+ r([
129
133
  f(".baht-modal-body")
130
134
  ], s.prototype, "bodyEl", 2);
131
- l([
132
- b()
135
+ r([
136
+ m()
133
137
  ], s.prototype, "closing", 2);
134
- s = l([
135
- y("baht-modal")
138
+ s = r([
139
+ b("baht-modal")
136
140
  ], s);
137
141
  export {
138
142
  s as BahtModal
@@ -28,6 +28,10 @@ export interface MessageCatalog {
28
28
  removeRow: string;
29
29
  minRows: string;
30
30
  maxRows: string;
31
+ /** `min_rows: 1`, where "{n} rows" would read "1 rows". */
32
+ minRowsOne: string;
33
+ /** `max_rows: 1`. */
34
+ maxRowsOne: string;
31
35
  next: string;
32
36
  submit: string;
33
37
  back: string;
package/dist/core/i18n.js CHANGED
@@ -28,6 +28,8 @@ const n = {
28
28
  removeRow: "Remove row",
29
29
  minRows: "Add at least {n} rows",
30
30
  maxRows: "Add at most {n} rows",
31
+ minRowsOne: "Add at least one row",
32
+ maxRowsOne: "Add at most one row",
31
33
  next: "Next",
32
34
  submit: "Submit",
33
35
  back: "Back",
@@ -93,6 +95,8 @@ const n = {
93
95
  removeRow: "ลบแถว",
94
96
  minRows: "ต้องมีอย่างน้อย {n} แถว",
95
97
  maxRows: "ต้องไม่เกิน {n} แถว",
98
+ minRowsOne: "ต้องมีอย่างน้อย 1 แถว",
99
+ maxRowsOne: "ต้องไม่เกิน 1 แถว",
96
100
  next: "ถัดไป",
97
101
  submit: "ส่งข้อมูล",
98
102
  back: "ย้อนกลับ",
@@ -1,9 +1,9 @@
1
- import { defaultValue as b } from "./defaults.js";
1
+ import { defaultValue as w } from "./defaults.js";
2
2
  import { compareValues as k } from "./engine/conditions.js";
3
- import { isoDaysOf as x, dateModeOf as w, rangeInteriorDays as _, isDateDisabled as A } from "./dates.js";
4
- import { t as u } from "./i18n.js";
3
+ import { isoDaysOf as x, dateModeOf as _, rangeInteriorDays as b, isDateDisabled as A } from "./dates.js";
4
+ import { t as i } from "./i18n.js";
5
5
  const L = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
6
- function p(e) {
6
+ function l(e) {
7
7
  return e == null ? !0 : typeof e == "string" ? e === "" : Array.isArray(e) ? e.length === 0 : typeof e == "boolean" ? !e : !1;
8
8
  }
9
9
  function d(e) {
@@ -16,14 +16,14 @@ function h(e, t) {
16
16
  const r = Number(n.value);
17
17
  return Number.isNaN(r) ? (console.warn(
18
18
  `[bahtui] ${t} validator has non-numeric value ${JSON.stringify(n.value)} — skipped`
19
- ), null) : typeof s != "string" ? null : (e === "minLength" ? s.length < r : s.length > r) ? n.message ?? u(e, { n: n.value }) : null;
19
+ ), null) : typeof s != "string" ? null : (e === "minLength" ? s.length < r : s.length > r) ? n.message ?? i(e, { n: n.value }) : null;
20
20
  };
21
21
  }
22
22
  function f(e) {
23
23
  return (t, n) => E(n).some((r) => {
24
24
  const o = k(r, t.value);
25
25
  return o !== null && (e === "min" ? o < 0 : o > 0);
26
- }) ? t.message ?? u(e, { n: t.value }) : null;
26
+ }) ? t.message ?? i(e, { n: t.value }) : null;
27
27
  }
28
28
  const C = {
29
29
  eq: (e) => e === 0,
@@ -32,39 +32,39 @@ const C = {
32
32
  gte: (e) => e >= 0,
33
33
  lt: (e) => e < 0,
34
34
  lte: (e) => e <= 0
35
- }, $ = (e, t, n, s) => {
35
+ }, R = (e, t, n, s) => {
36
36
  const r = s == null ? void 0 : s[e.field ?? ""];
37
- if (r === void 0 || p(r)) return null;
37
+ if (r === void 0 || l(r)) return null;
38
38
  const o = k(t, r);
39
39
  if (o === null) return null;
40
40
  const a = e.op ?? "eq";
41
41
  if (C[a](o)) return null;
42
42
  const m = `compare${a[0].toUpperCase()}${a.slice(1)}`;
43
- return e.message ?? u(m, { other: e.field });
44
- }, q = (e, t) => {
43
+ return e.message ?? i(m, { other: e.field });
44
+ }, $ = (e, t) => {
45
45
  if (typeof t != "string") return null;
46
46
  const n = D(String(e.value));
47
- return n ? n.test(t) ? null : e.message ?? u("pattern") : null;
48
- }, N = (e, t, n) => {
47
+ return n ? n.test(t) ? null : e.message ?? i("pattern") : null;
48
+ }, O = (e, t, n) => {
49
49
  var o;
50
50
  const s = (o = n == null ? void 0 : n.validators) == null ? void 0 : o[e.fn ?? ""];
51
51
  if (!s)
52
52
  return console.warn(`[bahtui] unknown custom validator "${e.fn}" — skipped`), null;
53
53
  const r = s(t);
54
54
  return r === null ? null : e.message ?? r;
55
- }, R = {
56
- required: (e, t) => p(t) ? e.message ?? u("required") : null,
55
+ }, q = {
56
+ required: (e, t) => l(t) ? e.message ?? i("required") : null,
57
57
  minLength: h("minLength", "min_length"),
58
58
  maxLength: h("maxLength", "max_length"),
59
59
  min: f("min"),
60
60
  max: f("max"),
61
- pattern: q,
62
- email: (e, t) => typeof t == "string" && !L.test(t) ? e.message ?? u("email") : null,
63
- compare: $,
64
- custom: N
61
+ pattern: $,
62
+ email: (e, t) => typeof t == "string" && !L.test(t) ? e.message ?? i("email") : null,
63
+ compare: R,
64
+ custom: O
65
65
  };
66
- function O(e, t, n, s) {
67
- return R[e.type](e, t, n, s);
66
+ function N(e, t, n, s) {
67
+ return q[e.type](e, t, n, s);
68
68
  }
69
69
  const g = /* @__PURE__ */ new Map();
70
70
  function D(e) {
@@ -80,10 +80,10 @@ function D(e) {
80
80
  return t;
81
81
  }
82
82
  function S(e, t, n, s) {
83
- const r = [], o = d(e), a = p(t);
83
+ const r = [], o = d(e), a = l(t);
84
84
  for (const m of o) {
85
85
  if (m.type !== "required" && a) continue;
86
- const c = O(m, t, n, s);
86
+ const c = N(m, t, n, s);
87
87
  c !== null && r.push({ key: e.key, message: c });
88
88
  }
89
89
  return e.type === "repeater" && r.push(...V(e, t, n)), e.type === "file" && r.push(...T(e, t)), e.type === "date" && !a && r.push(...M(e, t)), r;
@@ -92,7 +92,7 @@ function M(e, t) {
92
92
  var s, r;
93
93
  if (!((s = e.disabled_dates) != null && s.length) && !((r = e.disabled_weekdays) != null && r.length)) return [];
94
94
  const n = x(t);
95
- return w(e) === "range" && n.length === 2 && n.push(..._(n[0], n[1])), n.some((o) => A(e, o)) ? [{ key: e.key, message: u("dateDisabled") }] : [];
95
+ return _(e) === "range" && n.length === 2 && n.push(...b(n[0], n[1])), n.some((o) => A(e, o)) ? [{ key: e.key, message: i("dateDisabled") }] : [];
96
96
  }
97
97
  function P(e) {
98
98
  return e !== null && typeof e == "object" && typeof e.url == "string" && typeof e.size == "number" && typeof e.name == "string";
@@ -106,22 +106,29 @@ function z(e, t, n) {
106
106
  function T(e, t) {
107
107
  const n = (Array.isArray(t) ? t : [t]).filter(P), s = [];
108
108
  for (const r of n)
109
- e.max_size !== void 0 && r.size > e.max_size && s.push({ key: e.key, message: u("fileTooLarge") }), e.accept && !z(e.accept, r.name, r.type ?? "") && s.push({ key: e.key, message: u("fileTypeNotAllowed") });
109
+ e.max_size !== void 0 && r.size > e.max_size && s.push({ key: e.key, message: i("fileTooLarge") }), e.accept && !z(e.accept, r.name, r.type ?? "") && s.push({ key: e.key, message: i("fileTypeNotAllowed") });
110
110
  return s;
111
111
  }
112
112
  function V(e, t, n) {
113
113
  if (t != null && !Array.isArray(t))
114
- return [{ key: e.key, message: u("pattern") }];
114
+ return [{ key: e.key, message: i("pattern") }];
115
115
  const s = Array.isArray(t) ? t : [], r = [];
116
- e.min_rows !== void 0 && s.length < e.min_rows && r.push({ key: e.key, message: u("minRows", { n: e.min_rows }) }), e.max_rows !== void 0 && s.length > e.max_rows && r.push({ key: e.key, message: u("maxRows", { n: e.max_rows }) });
116
+ if (e.min_rows !== void 0 && s.length < e.min_rows) {
117
+ const a = e.min_rows === 1 ? i("minRowsOne") : i("minRows", { n: e.min_rows });
118
+ r.push({ key: e.key, message: a });
119
+ }
120
+ if (e.max_rows !== void 0 && s.length > e.max_rows) {
121
+ const a = e.max_rows === 1 ? i("maxRowsOne") : i("maxRows", { n: e.max_rows });
122
+ r.push({ key: e.key, message: a });
123
+ }
117
124
  const o = [...e.fields ?? []].sort((a, m) => a.order - m.order);
118
125
  return s.forEach((a, m) => {
119
- const c = a !== null && typeof a == "object" && !Array.isArray(a) ? a : {}, l = {};
120
- for (const i of o)
121
- i.type === "label" || i.type === "section" || i.type === "repeater" || (l[i.key] = Object.hasOwn(c, i.key) ? c[i.key] : b(i));
122
- for (const i of o)
123
- if (!(i.type === "label" || i.type === "section" || i.type === "repeater"))
124
- for (const y of S(i, l[i.key], n, l))
126
+ const c = a !== null && typeof a == "object" && !Array.isArray(a) ? a : {}, p = {};
127
+ for (const u of o)
128
+ u.type === "label" || u.type === "section" || u.type === "repeater" || (p[u.key] = Object.hasOwn(c, u.key) ? c[u.key] : w(u));
129
+ for (const u of o)
130
+ if (!(u.type === "label" || u.type === "section" || u.type === "repeater"))
131
+ for (const y of S(u, p[u.key], n, p))
125
132
  r.push({ key: `${e.key}[${m}].${y.key}`, message: y.message });
126
133
  }), r;
127
134
  }
@@ -396,6 +396,10 @@
396
396
  display: flex;
397
397
  align-items: center;
398
398
  gap: var(--baht-space-2);
399
+ /* A narrow card (a 1/4 option width in a phone-width form) drops the label
400
+ under its icon instead of pushing it past the card edge into the next one. */
401
+ flex-wrap: wrap;
402
+ min-width: 0;
399
403
  }
400
404
  /* `option.width` — same fractions as `field.width`, against the card row's
401
405
  own gap (`--baht-space-3`) instead of the form grid's `--baht-field-gap`,
@@ -407,6 +411,7 @@
407
411
  .baht-option-card--w-1-4 {
408
412
  flex: 0 0 calc(25% - var(--baht-space-3) * 3 / 4);
409
413
  min-width: 0;
414
+ padding-inline: var(--baht-space-3);
410
415
  }
411
416
  .baht-option-card--w-1-2 {
412
417
  flex: 0 0 calc(50% - var(--baht-space-3) / 2);
@@ -449,6 +454,11 @@
449
454
  .baht-option-card-title {
450
455
  font-weight: 600;
451
456
  color: var(--baht-color-text);
457
+ /* Last resort when even its own line is too narrow: clip, never overflow. */
458
+ min-width: 0;
459
+ max-width: 100%;
460
+ overflow: hidden;
461
+ text-overflow: ellipsis;
452
462
  }
453
463
  .baht-option-card-desc {
454
464
  font-size: var(--baht-text-sm);
@@ -2546,16 +2556,17 @@ code.baht-code {
2546
2556
  vertical-align: middle;
2547
2557
  background: var(--baht-color-text-muted);
2548
2558
  }
2549
- /* A row's own marker, beside its line — on the surface so a bar behind it
2550
- never runs through the text. */
2559
+ /* A row with its own marker (a budget line) gets a caption lane above its
2560
+ bars: the label sits there beside its line and never covers a bar or the
2561
+ bar's value. */
2562
+ .baht-bar-chart-track--marked {
2563
+ padding-top: 1.1rem;
2564
+ }
2551
2565
  .baht-bar-chart-marker-label--row {
2552
- top: 50%;
2566
+ top: 0;
2553
2567
  bottom: auto;
2554
2568
  z-index: 2;
2555
- margin-top: -0.55rem;
2556
- background: var(--baht-chart-surface);
2557
- padding: 0 4px;
2558
- border-radius: var(--baht-radius-xs);
2569
+ padding: 0 2px;
2559
2570
  }
2560
2571
  .baht-bar-chart-marker-label--row::before {
2561
2572
  display: none; /* the line it names is right beside it */
@@ -10100,6 +10100,35 @@
10100
10100
  "description": "Accessible summary; falls back to a generated sentence.",
10101
10101
  "attribute": "label"
10102
10102
  },
10103
+ {
10104
+ "kind": "field",
10105
+ "name": "width",
10106
+ "privacy": "private",
10107
+ "default": "640",
10108
+ "description": "Drawing width in SVG units. It follows the host up to `W`, so on a phone\none unit is one CSS pixel and tick text keeps its real size instead of\nshrinking with a 640-wide drawing scaled into a 360px card.",
10109
+ "type": {
10110
+ "text": "number"
10111
+ }
10112
+ },
10113
+ {
10114
+ "kind": "field",
10115
+ "name": "resizeObserver",
10116
+ "type": {
10117
+ "text": "ResizeObserver | undefined"
10118
+ },
10119
+ "privacy": "private"
10120
+ },
10121
+ {
10122
+ "kind": "method",
10123
+ "name": "measure",
10124
+ "privacy": "private",
10125
+ "return": {
10126
+ "type": {
10127
+ "text": "void"
10128
+ }
10129
+ },
10130
+ "description": "Host width → drawing width. Never runs on the server (`hasDom` guard)."
10131
+ },
10103
10132
  {
10104
10133
  "kind": "field",
10105
10134
  "name": "plot",
@@ -11548,7 +11577,8 @@
11548
11577
  "type": {
11549
11578
  "text": "boolean"
11550
11579
  },
11551
- "default": "true",
11580
+ "default": "false",
11581
+ "description": "Scrim click requests close. Off by default: a stray click outside the panel\nmust not throw away what the user typed — close via ×, Escape or your buttons.",
11552
11582
  "attribute": "close-on-scrim"
11553
11583
  },
11554
11584
  {
@@ -11751,7 +11781,8 @@
11751
11781
  "type": {
11752
11782
  "text": "boolean"
11753
11783
  },
11754
- "default": "true",
11784
+ "default": "false",
11785
+ "description": "Scrim click requests close. Off by default: a stray click outside the panel\nmust not throw away what the user typed — close via ×, Escape or your buttons.",
11755
11786
  "fieldName": "closeOnScrim"
11756
11787
  },
11757
11788
  {
package/dist/overlay.d.ts CHANGED
@@ -8,7 +8,7 @@ export interface DialogOptions {
8
8
  cancelText?: string;
9
9
  /** Secondary monospace block under the message (error detail, payload, …). */
10
10
  detail?: string;
11
- /** Allow Escape / scrim-click to cancel. Default true. */
11
+ /** Allow Escape to cancel. Default true. A scrim click never cancels. */
12
12
  dismissible?: boolean;
13
13
  }
14
14
  export interface PromptOptions extends DialogOptions {
package/dist/overlay.js CHANGED
@@ -12,8 +12,8 @@ function p(e) {
12
12
  return I(() => L(e));
13
13
  }
14
14
  async function L(e) {
15
- const t = document.activeElement, s = e.dismissible !== !1, E = e.tone === "danger" ? "danger" : "primary", n = document.createElement("baht-modal");
16
- n.heading = e.title ?? "", n.showClose = !1, n.closeOnScrim = s;
15
+ const t = document.activeElement, r = e.dismissible !== !1, E = e.tone === "danger" ? "danger" : "primary", n = document.createElement("baht-modal");
16
+ n.heading = e.title ?? "", n.showClose = !1, n.closeOnScrim = !1;
17
17
  const c = document.createElement("div");
18
18
  c.className = `baht-dialog${e.tone ? ` baht-dialog--${e.tone}` : ""}`;
19
19
  const b = document.createElement("p");
@@ -25,8 +25,8 @@ async function L(e) {
25
25
  e.showInput && (a = document.createElement("input"), a.className = "baht-control baht-dialog-input", a.type = "text", a.value = e.value ?? "", e.placeholder && (a.placeholder = e.placeholder), c.appendChild(a));
26
26
  const u = document.createElement("div");
27
27
  u.className = "baht-dialog-actions";
28
- let l = null;
29
- e.showCancel && (l = document.createElement("baht-button"), l.className = "baht-dialog-cancel", l.variant = "secondary", l.label = e.cancelText ?? "Cancel", u.appendChild(l));
28
+ let o = null;
29
+ e.showCancel && (o = document.createElement("baht-button"), o.className = "baht-dialog-cancel", o.variant = "secondary", o.label = e.cancelText ?? "Cancel", u.appendChild(o));
30
30
  const i = document.createElement("baht-button");
31
31
  i.className = "baht-dialog-confirm", i.variant = E, i.label = e.confirmText ?? "OK", u.appendChild(i), c.appendChild(u), n.appendChild(c), document.body.appendChild(n), n.open = !0;
32
32
  let h;
@@ -36,24 +36,24 @@ async function L(e) {
36
36
  v.observe(document.documentElement, { childList: !0, subtree: !0 });
37
37
  const g = await new Promise((d) => {
38
38
  let C = !1;
39
- const m = (o) => {
40
- C || (C = !0, d(o));
39
+ const m = (s) => {
40
+ C || (C = !0, d(s));
41
41
  };
42
42
  h = () => {
43
43
  m({ confirmed: !1, reason: "detached" });
44
44
  }, i.addEventListener("click", () => {
45
45
  m({ confirmed: !0, reason: "confirm", ...a ? { value: a.value } : {} });
46
- }), l == null || l.addEventListener("click", () => {
46
+ }), o == null || o.addEventListener("click", () => {
47
47
  m({ confirmed: !1, reason: "cancel" });
48
- }), n.addEventListener("baht-close", (o) => {
49
- if (!s) return;
50
- const x = o.detail.reason;
48
+ }), n.addEventListener("baht-close", (s) => {
49
+ if (!r) return;
50
+ const x = s.detail.reason;
51
51
  m({ confirmed: !1, reason: x === "scrim" ? "scrim" : "escape" });
52
- }), a == null || a.addEventListener("keydown", (o) => {
53
- o.key === "Enter" && !o.isComposing && m({ confirmed: !0, reason: "confirm", value: o.target.value });
52
+ }), a == null || a.addEventListener("keydown", (s) => {
53
+ s.key === "Enter" && !s.isComposing && m({ confirmed: !0, reason: "confirm", value: s.target.value });
54
54
  }), n.updateComplete.then(() => {
55
- var o;
56
- return (o = a ?? i.querySelector("button")) == null ? void 0 : o.focus();
55
+ var s;
56
+ return (s = a ?? i.querySelector("button")) == null ? void 0 : s.focus();
57
57
  });
58
58
  });
59
59
  v.disconnect(), n.open = !1;
@@ -97,7 +97,7 @@ const P = {
97
97
  },
98
98
  /** Single text input. Resolves the value, or null on cancel/dismiss. */
99
99
  async prompt(e, t = {}) {
100
- const s = await p({
100
+ const r = await p({
101
101
  title: "Input needed",
102
102
  confirmText: "OK",
103
103
  ...t,
@@ -105,14 +105,14 @@ const P = {
105
105
  showCancel: !0,
106
106
  showInput: !0
107
107
  });
108
- return s.confirmed ? s.value ?? "" : null;
108
+ return r.confirmed ? r.value ?? "" : null;
109
109
  }
110
110
  };
111
- let r = null;
111
+ let l = null;
112
112
  function S() {
113
- return r != null && r.isConnected || (r = document.querySelector("baht-toast") ?? document.body.appendChild(document.createElement("baht-toast"))), r;
113
+ return l != null && l.isConnected || (l = document.querySelector("baht-toast") ?? document.body.appendChild(document.createElement("baht-toast"))), l;
114
114
  }
115
- const f = (e) => (t, s = {}) => T.show(t, { ...s, tone: e }), T = {
115
+ const f = (e) => (t, r = {}) => T.show(t, { ...r, tone: e }), T = {
116
116
  show(e, t = {}) {
117
117
  return S().show({ message: e, ...t });
118
118
  },
@@ -121,7 +121,7 @@ const f = (e) => (t, s = {}) => T.show(t, { ...s, tone: e }), T = {
121
121
  warning: f("warning"),
122
122
  danger: f("danger"),
123
123
  dismiss(e) {
124
- r == null || r.dismiss(e);
124
+ l == null || l.dismiss(e);
125
125
  }
126
126
  };
127
127
  export {
package/dist/tokens.css CHANGED
@@ -830,6 +830,10 @@
830
830
  display: flex;
831
831
  align-items: center;
832
832
  gap: var(--baht-space-2);
833
+ /* A narrow card (a 1/4 option width in a phone-width form) drops the label
834
+ under its icon instead of pushing it past the card edge into the next one. */
835
+ flex-wrap: wrap;
836
+ min-width: 0;
833
837
  }
834
838
  /* `option.width` — same fractions as `field.width`, against the card row's
835
839
  own gap (`--baht-space-3`) instead of the form grid's `--baht-field-gap`,
@@ -841,6 +845,7 @@
841
845
  .baht-option-card--w-1-4 {
842
846
  flex: 0 0 calc(25% - var(--baht-space-3) * 3 / 4);
843
847
  min-width: 0;
848
+ padding-inline: var(--baht-space-3);
844
849
  }
845
850
  .baht-option-card--w-1-2 {
846
851
  flex: 0 0 calc(50% - var(--baht-space-3) / 2);
@@ -883,6 +888,11 @@
883
888
  .baht-option-card-title {
884
889
  font-weight: 600;
885
890
  color: var(--baht-color-text);
891
+ /* Last resort when even its own line is too narrow: clip, never overflow. */
892
+ min-width: 0;
893
+ max-width: 100%;
894
+ overflow: hidden;
895
+ text-overflow: ellipsis;
886
896
  }
887
897
  .baht-option-card-desc {
888
898
  font-size: var(--baht-text-sm);
@@ -2980,16 +2990,17 @@ code.baht-code {
2980
2990
  vertical-align: middle;
2981
2991
  background: var(--baht-color-text-muted);
2982
2992
  }
2983
- /* A row's own marker, beside its line — on the surface so a bar behind it
2984
- never runs through the text. */
2993
+ /* A row with its own marker (a budget line) gets a caption lane above its
2994
+ bars: the label sits there beside its line and never covers a bar or the
2995
+ bar's value. */
2996
+ .baht-bar-chart-track--marked {
2997
+ padding-top: 1.1rem;
2998
+ }
2985
2999
  .baht-bar-chart-marker-label--row {
2986
- top: 50%;
3000
+ top: 0;
2987
3001
  bottom: auto;
2988
3002
  z-index: 2;
2989
- margin-top: -0.55rem;
2990
- background: var(--baht-chart-surface);
2991
- padding: 0 4px;
2992
- border-radius: var(--baht-radius-xs);
3003
+ padding: 0 2px;
2993
3004
  }
2994
3005
  .baht-bar-chart-marker-label--row::before {
2995
3006
  display: none; /* the line it names is right beside it */
@@ -710,7 +710,11 @@
710
710
  "values": []
711
711
  },
712
712
  { "name": "show-close", "values": [] },
713
- { "name": "close-on-scrim", "values": [] },
713
+ {
714
+ "name": "close-on-scrim",
715
+ "description": "Scrim click requests close. Off by default: a stray click outside the panel\nmust not throw away what the user typed — close via ×, Escape or your buttons.",
716
+ "values": []
717
+ },
714
718
  { "name": "defer-hydration", "values": [] }
715
719
  ],
716
720
  "references": []
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://raw.githubusercontent.com/JetBrains/web-types/master/schema/web-types.json",
3
3
  "name": "bank20baht-ui",
4
- "version": "0.8.2",
4
+ "version": "0.10.0",
5
5
  "description-markup": "markdown",
6
6
  "contributions": {
7
7
  "html": {
@@ -1645,7 +1645,8 @@
1645
1645
  },
1646
1646
  {
1647
1647
  "name": "close-on-scrim",
1648
- "value": { "type": "boolean", "default": "true" }
1648
+ "description": "Scrim click requests close. Off by default: a stray click outside the panel\nmust not throw away what the user typed — close via ×, Escape or your buttons.",
1649
+ "value": { "type": "boolean", "default": "false" }
1649
1650
  },
1650
1651
  { "name": "defer-hydration", "value": { "type": "string" } }
1651
1652
  ],
@@ -1660,7 +1661,11 @@
1660
1661
  "type": "string"
1661
1662
  },
1662
1663
  { "name": "showClose", "type": "boolean" },
1663
- { "name": "closeOnScrim", "type": "boolean" }
1664
+ {
1665
+ "name": "closeOnScrim",
1666
+ "description": "Scrim click requests close. Off by default: a stray click outside the panel\nmust not throw away what the user typed — close via ×, Escape or your buttons.",
1667
+ "type": "boolean"
1668
+ }
1664
1669
  ],
1665
1670
  "events": [{ "name": "name", "type": "CustomEvent" }]
1666
1671
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bank20baht-ui",
3
- "version": "0.8.2",
3
+ "version": "0.10.0",
4
4
  "type": "module",
5
5
  "description": "JSON-driven form + workflow engine. Send JSON in, get an interactive form out.",
6
6
  "license": "MIT",