bank20baht-ui 0.2.7 → 0.2.9

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 CHANGED
@@ -234,7 +234,9 @@ Geist / Geist Mono, borders-over-shadows, "paper" easing — plus a dark theme
234
234
  `items` is one page; `baht-page-change` asks your app to fetch the next one.
235
235
  - **Feedback** — `baht-modal` · `baht-toast` · `baht-alert` · `baht-tooltip` · `baht-progress` ·
236
236
  `baht-spinner` · `baht-skeleton`
237
- - **Inputs** — `baht-rating` · `baht-range` · `baht-otp` (+ the 11 form field primitives)
237
+ - **Inputs** — `baht-rating` · `baht-range` · `baht-otp` · `baht-typeahead` · `baht-reference-picker` ·
238
+ `baht-keyvalue-editor` (+ the 11 form field primitives). Typed fields debounce keystrokes (150 ms,
239
+ `debounce` / `options.inputDebounce`); `dropdown` renders its own listbox, never the OS picker.
238
240
  - **Structure & nav** — `baht-card` · `baht-fieldset` · `baht-timeline` · `baht-accordion` ·
239
241
  `baht-link` · `baht-breadcrumbs`
240
242
 
@@ -1,4 +1,4 @@
1
- function D(e) {
1
+ function $(e) {
2
2
  if (e.value !== void 0) return e.value;
3
3
  switch (e.type) {
4
4
  case "checkbox":
@@ -58,7 +58,17 @@ const Y = {
58
58
  no: "No",
59
59
  emptyValue: "Not provided",
60
60
  choose: "Select",
61
- rowCount: "{n} rows"
61
+ rowCount: "{n} rows",
62
+ close: "Close",
63
+ dismiss: "Dismiss",
64
+ opensInNewTab: "opens in new tab",
65
+ otpCharacter: "Character {i} of {n}",
66
+ row: "Row {n}",
67
+ removeRowN: "Remove row {n}",
68
+ stepDone: "completed",
69
+ stepCurrent: "current step",
70
+ today: "Today",
71
+ clear: "Clear"
62
72
  }, J = {
63
73
  required: "กรุณากรอกข้อมูลนี้",
64
74
  minLength: "ต้องมีอย่างน้อย {n} ตัวอักษร",
@@ -100,20 +110,30 @@ const Y = {
100
110
  no: "ไม่ใช่",
101
111
  emptyValue: "ไม่ได้ระบุ",
102
112
  choose: "เลือก",
103
- rowCount: "{n} แถว"
113
+ rowCount: "{n} แถว",
114
+ close: "ปิด",
115
+ dismiss: "ปิดข้อความ",
116
+ opensInNewTab: "เปิดในแท็บใหม่",
117
+ otpCharacter: "ตัวอักษรที่ {i} จาก {n}",
118
+ row: "แถวที่ {n}",
119
+ removeRowN: "ลบแถวที่ {n}",
120
+ stepDone: "เสร็จแล้ว",
121
+ stepCurrent: "ขั้นตอนปัจจุบัน",
122
+ today: "วันนี้",
123
+ clear: "ล้างค่า"
104
124
  }, K = { en: Y, th: J };
105
- let R = Y;
106
- function xe(e, t) {
107
- R = { ...K[e], ...t };
125
+ let D = Y;
126
+ function ve(e, t) {
127
+ D = { ...K[e], ...t };
108
128
  }
109
- function Ae() {
110
- return R;
129
+ function xe() {
130
+ return D;
111
131
  }
112
- function ve(e) {
113
- R = e;
132
+ function Ae(e) {
133
+ D = e;
114
134
  }
115
135
  function f(e, t) {
116
- let n = R[e];
136
+ let n = D[e];
117
137
  if (t)
118
138
  for (const [s, r] of Object.entries(t))
119
139
  n = n.replaceAll(`{${s}}`, () => String(r));
@@ -130,7 +150,7 @@ function q(e, t) {
130
150
  if (n !== -1)
131
151
  return (s = e[t.slice(0, n)]) == null ? void 0 : s[t.slice(n + 1)];
132
152
  }
133
- function j(e) {
153
+ function E(e) {
134
154
  return e == null ? !0 : typeof e == "string" ? e === "" : Array.isArray(e) ? e.length === 0 : !1;
135
155
  }
136
156
  function w(e, t) {
@@ -182,16 +202,16 @@ function X(e, t) {
182
202
  case "endsWith":
183
203
  return typeof n == "string" && n.endsWith(String(s));
184
204
  case "isEmpty":
185
- return j(n);
205
+ return E(n);
186
206
  case "isNotEmpty":
187
- return !j(n);
207
+ return !E(n);
188
208
  }
189
209
  }
190
- function x(e, t) {
191
- return e === void 0 ? !0 : "and" in e ? e.and.every((n) => x(n, t)) : "or" in e ? e.or.some((n) => x(n, t)) : "not" in e ? !x(e.not, t) : X(e, t);
210
+ function v(e, t) {
211
+ return e === void 0 ? !0 : "and" in e ? e.and.every((n) => v(n, t)) : "or" in e ? e.or.some((n) => v(n, t)) : "not" in e ? !v(e.not, t) : X(e, t);
192
212
  }
193
213
  const H = /^(\d{4})-(\d{2})-(\d{2})$/;
194
- function A(e) {
214
+ function x(e) {
195
215
  if (typeof e != "string") return null;
196
216
  const t = H.exec(e);
197
217
  if (!t) return null;
@@ -209,15 +229,15 @@ function ee(e) {
209
229
  function te(e) {
210
230
  const t = e.indexOf("/");
211
231
  if (t === -1) {
212
- const r = A(e);
232
+ const r = x(e);
213
233
  return r ? [r, r] : null;
214
234
  }
215
- const n = A(e.slice(0, t)), s = A(e.slice(t + 1));
235
+ const n = x(e.slice(0, t)), s = x(e.slice(t + 1));
216
236
  return !n || !s ? null : n <= s ? [n, s] : [s, n];
217
237
  }
218
238
  function ne(e, t) {
219
239
  var s;
220
- const n = A(t);
240
+ const n = x(t);
221
241
  if (!n) return !1;
222
242
  if ((s = e.disabledWeekdays) != null && s.includes(n.getDay())) return !0;
223
243
  for (const r of e.disabledDates ?? []) {
@@ -227,7 +247,7 @@ function ne(e, t) {
227
247
  return !1;
228
248
  }
229
249
  function re(e, t, n = 3660) {
230
- const s = A(e), r = A(t);
250
+ const s = x(e), r = x(t);
231
251
  if (!s || !r || s >= r) return [];
232
252
  const o = [], i = new Date(s);
233
253
  for (i.setDate(i.getDate() + 1); i < r && o.length < n; )
@@ -242,7 +262,7 @@ function oe(e) {
242
262
  const t = [...e.validators ?? []], n = (s) => t.some((r) => r.type === s);
243
263
  return e.required && !n("required") && t.push({ type: "required" }), e.maxLength !== void 0 && !n("maxLength") && t.push({ type: "maxLength", value: e.maxLength }), e.minLength !== void 0 && !n("minLength") && t.push({ type: "minLength", value: e.minLength }), e.min !== void 0 && !n("min") && t.push({ type: "min", value: e.min }), e.max !== void 0 && !n("max") && t.push({ type: "max", value: e.max }), e.type === "email" && !n("email") && t.push({ type: "email" }), t;
244
264
  }
245
- const M = (e) => Array.isArray(e) ? e : [e];
265
+ const j = (e) => Array.isArray(e) ? e : [e];
246
266
  function ie(e, t, n, s) {
247
267
  var r;
248
268
  switch (e.type) {
@@ -261,12 +281,12 @@ function ie(e, t, n, s) {
261
281
  ), null) : typeof t == "string" && t.length > o ? e.message ?? f("maxLength", { n: e.value }) : null;
262
282
  }
263
283
  case "min":
264
- return M(t).some((i) => {
284
+ return j(t).some((i) => {
265
285
  const a = w(i, e.value);
266
286
  return a !== null && a < 0;
267
287
  }) ? e.message ?? f("min", { n: e.value }) : null;
268
288
  case "max":
269
- return M(t).some((i) => {
289
+ return j(t).some((i) => {
270
290
  const a = w(i, e.value);
271
291
  return a !== null && a > 0;
272
292
  }) ? e.message ?? f("max", { n: e.value }) : null;
@@ -340,7 +360,7 @@ function me(e, t, n) {
340
360
  return s.forEach((i, a) => {
341
361
  const d = i !== null && typeof i == "object" && !Array.isArray(i) ? i : {}, p = {};
342
362
  for (const u of o)
343
- u.type === "label" || u.type === "section" || u.type === "repeater" || (p[u.key] = Object.hasOwn(d, u.key) ? d[u.key] : D(u));
363
+ u.type === "label" || u.type === "section" || u.type === "repeater" || (p[u.key] = Object.hasOwn(d, u.key) ? d[u.key] : $(u));
344
364
  for (const u of o)
345
365
  if (!(u.type === "label" || u.type === "section" || u.type === "repeater"))
346
366
  for (const y of ae(u, p[u.key], n, p))
@@ -361,11 +381,11 @@ function S(e, t) {
361
381
  function G(e, t) {
362
382
  return e.filter((n) => S(n.flag, t)).map((n) => n.fields ? { ...n, fields: G(n.fields, t) } : n);
363
383
  }
364
- function E(e) {
365
- return e.some((t) => t.flag !== void 0 || (t.fields ? E(t.fields) : !1));
384
+ function T(e) {
385
+ return e.some((t) => t.flag !== void 0 || (t.fields ? T(t.fields) : !1));
366
386
  }
367
- function T(e, t) {
368
- if (!E(e.field_data)) return e;
387
+ function M(e, t) {
388
+ if (!T(e.field_data)) return e;
369
389
  const n = G(e.field_data, t), s = new Set(n.map((r) => r.key));
370
390
  return {
371
391
  ...e,
@@ -373,34 +393,34 @@ function T(e, t) {
373
393
  ...e.views ? { views: e.views.map((r) => ({ ...r, fields: r.fields.filter((o) => s.has(o)) })) } : {}
374
394
  };
375
395
  }
376
- function Le(e, t = {}) {
396
+ function Re(e, t = {}) {
377
397
  if ("workflowId" in e) {
378
398
  const n = e;
379
- return n.forms.some((r) => r.flag !== void 0 || E(r.field_data)) || n.rules.some((r) => r.flag !== void 0) || (n.transitions ?? []).some((r) => r.flag !== void 0) ? {
399
+ return n.forms.some((r) => r.flag !== void 0 || T(r.field_data)) || n.rules.some((r) => r.flag !== void 0) || (n.transitions ?? []).some((r) => r.flag !== void 0) ? {
380
400
  ...n,
381
- forms: n.forms.filter((r) => S(r.flag, t)).map((r) => T(r, t)),
401
+ forms: n.forms.filter((r) => S(r.flag, t)).map((r) => M(r, t)),
382
402
  rules: n.rules.filter((r) => S(r.flag, t)),
383
403
  ...n.transitions ? { transitions: n.transitions.filter((r) => S(r.flag, t)) } : {}
384
404
  } : e;
385
405
  }
386
- return T(e, t);
406
+ return M(e, t);
387
407
  }
388
408
  function de(e) {
389
409
  if (e == null || e === "") return null;
390
410
  const t = Number(e);
391
411
  return Number.isNaN(t) ? null : t;
392
412
  }
393
- function L(e) {
413
+ function R(e) {
394
414
  return typeof e == "number" && Number.isNaN(e) ? null : e;
395
415
  }
396
- function $(e, t) {
416
+ function L(e, t) {
397
417
  if ("ref" in e) return q(t, e.ref);
398
418
  if ("const" in e) return e.const;
399
419
  if ("if" in e) {
400
420
  const [s, r, o] = e.if;
401
- return x(s, t) ? L($(r, t)) : L($(o, t));
421
+ return v(s, t) ? R(L(r, t)) : R(L(o, t));
402
422
  }
403
- const n = e.args.map((s) => L($(s, t)));
423
+ const n = e.args.map((s) => R(L(s, t)));
404
424
  switch (e.op) {
405
425
  case "concat":
406
426
  return n.map((s) => s == null ? "" : String(s)).join("");
@@ -428,10 +448,10 @@ function $(e, t) {
428
448
  }
429
449
  }
430
450
  function pe(e, t) {
431
- return L($(e, t));
451
+ return R(L(e, t));
432
452
  }
433
- const V = 20, _ = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
434
- function I(e, t) {
453
+ const C = 20, I = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
454
+ function V(e, t) {
435
455
  return e !== null && typeof e == "object" && Object.hasOwn(e, t) ? e[t] : void 0;
436
456
  }
437
457
  function O(e, t) {
@@ -454,15 +474,15 @@ function he(e, t) {
454
474
  const n = [], s = /* @__PURE__ */ new Map(), r = [];
455
475
  let o = {};
456
476
  for (const u of e.forms) {
457
- if (_.has(u.formName)) {
477
+ if (I.has(u.formName)) {
458
478
  n.push({ ref: u.formName, message: "unsafe form name", kind: "schema" });
459
479
  continue;
460
480
  }
461
481
  r.push(u.formName);
462
- const y = {}, N = I(t, u.formName);
482
+ const y = {}, N = V(t, u.formName);
463
483
  for (const m of [...u.field_data, ...B(u)]) {
464
484
  if (m.type === "label" || m.type === "section") continue;
465
- if (_.has(m.key)) {
485
+ if (I.has(m.key)) {
466
486
  n.push({
467
487
  ref: `${u.formName}.${m.key}`,
468
488
  message: "unsafe field key",
@@ -471,13 +491,13 @@ function he(e, t) {
471
491
  continue;
472
492
  }
473
493
  s.set(`${u.formName}.${m.key}`, m);
474
- const c = I(N, m.key);
475
- y[m.key] = c !== void 0 ? c : D(m);
494
+ const c = V(N, m.key);
495
+ y[m.key] = c !== void 0 ? c : $(m);
476
496
  }
477
497
  o[u.formName] = y;
478
498
  }
479
499
  let i = {}, a = {}, d = !1;
480
- for (let u = 0; u < V; u++) {
500
+ for (let u = 0; u < C; u++) {
481
501
  i = {}, a = {};
482
502
  for (const c of r) a[c] = { visible: !0 };
483
503
  for (const [c, h] of s)
@@ -490,12 +510,12 @@ function he(e, t) {
490
510
  };
491
511
  const y = /* @__PURE__ */ new Map();
492
512
  e.rules.forEach((c, h) => {
493
- const l = x(c.when, o) ? c.then : c.else;
513
+ const l = v(c.when, o) ? c.then : c.else;
494
514
  if (!l) return;
495
515
  const k = c.priority ?? 0;
496
516
  for (const g of l) {
497
- const b = ge(g), v = y.get(b) ?? [];
498
- v.push({ action: g, priority: k, index: h }), y.set(b, v);
517
+ const b = ge(g), A = y.get(b) ?? [];
518
+ A.push({ action: g, priority: k, index: h }), y.set(b, A);
499
519
  }
500
520
  });
501
521
  const N = [];
@@ -507,8 +527,8 @@ function he(e, t) {
507
527
  continue;
508
528
  }
509
529
  if (l.action === "showForm" || l.action === "hideForm" || l.action === "skipForm") {
510
- const v = a[l.target.form];
511
- if (!v) {
530
+ const A = a[l.target.form];
531
+ if (!A) {
512
532
  n.push({
513
533
  ref: l.target.form,
514
534
  message: `rule targets unknown form (${c})`,
@@ -516,7 +536,7 @@ function he(e, t) {
516
536
  });
517
537
  continue;
518
538
  }
519
- v.visible = l.action === "showForm";
539
+ A.visible = l.action === "showForm";
520
540
  continue;
521
541
  }
522
542
  const k = l.target, g = `${k.form}.${k.field}`, b = i[g];
@@ -551,11 +571,11 @@ function he(e, t) {
551
571
  const m = {};
552
572
  for (const c of r) m[c] = { ...o[c] };
553
573
  for (const [c, h] of s) {
554
- const [l, k] = C(c);
555
- (!a[l].visible || !i[c].visible) && (m[l][k] = D(h));
574
+ const [l, k] = _(c);
575
+ (!a[l].visible || !i[c].visible) && (m[l][k] = $(h));
556
576
  }
557
577
  for (const { ref: c, action: h } of N) {
558
- const [l, k] = C(c), g = i[c];
578
+ const [l, k] = _(c), g = i[c];
559
579
  if (!g) {
560
580
  n.push({ ref: c, message: "setValue targets unknown field", kind: "schema" });
561
581
  continue;
@@ -570,7 +590,7 @@ function he(e, t) {
570
590
  }
571
591
  d || n.push({
572
592
  ref: e.workflowId,
573
- message: `rules did not converge within ${V} passes (cycle?)`,
593
+ message: `rules did not converge within ${C} passes (cycle?)`,
574
594
  kind: "data"
575
595
  });
576
596
  const p = {};
@@ -587,7 +607,7 @@ function ge(e) {
587
607
  const t = e.action === "show" || e.action === "hide" ? "visible" : e.action === "enable" || e.action === "disable" ? "enabled" : e.action === "required" || e.action === "optional" ? "required" : e.action === "showForm" || e.action === "hideForm" || e.action === "skipForm" ? "formVisible" : e.action, n = "field" in e.target ? `${e.target.form}.${e.target.field}` : e.target.form;
588
608
  return `${t}:${n}`;
589
609
  }
590
- function C(e) {
610
+ function _(e) {
591
611
  const t = e.indexOf(".");
592
612
  return [e.slice(0, t), e.slice(t + 1)];
593
613
  }
@@ -602,7 +622,7 @@ function P(e, t) {
602
622
  }
603
623
  function W(e, t, n) {
604
624
  for (const o of e.transitions ?? [])
605
- if (o.from === t && x(o.when, n))
625
+ if (o.from === t && v(o.when, n))
606
626
  return o.to;
607
627
  const s = [...e.forms].sort((o, i) => o.order - i.order), r = s.findIndex((o) => o.formName === t);
608
628
  return r >= 0 && r + 1 < s.length ? s[r + 1].formName : "end";
@@ -616,7 +636,7 @@ function be(e, t, n, s) {
616
636
  }
617
637
  return i;
618
638
  }
619
- function $e(e, t) {
639
+ function Le(e, t) {
620
640
  var d;
621
641
  const n = P(e, t), r = (d = [...e.forms].sort((p, u) => p.order - u.order).find((p) => n.has(p.formName))) == null ? void 0 : d.formName;
622
642
  if (!r) return [];
@@ -669,8 +689,8 @@ function we(e, t, n = e.options) {
669
689
  }
670
690
  export {
671
691
  te as a,
672
- D as b,
673
- Le as c,
692
+ $ as b,
693
+ Re as c,
674
694
  Z as d,
675
695
  we as e,
676
696
  Q as f,
@@ -678,17 +698,17 @@ export {
678
698
  be as h,
679
699
  ee as i,
680
700
  B as j,
681
- x as k,
701
+ v as k,
682
702
  pe as l,
683
703
  S as m,
684
- Ae as n,
704
+ xe as n,
685
705
  ne as o,
686
- A as p,
706
+ x as p,
687
707
  q,
688
708
  Se as r,
689
- ve as s,
709
+ Ae as s,
690
710
  f as t,
691
- xe as u,
711
+ ve as u,
692
712
  ae as v,
693
- $e as w
713
+ Le as w
694
714
  };
@@ -0,0 +1,16 @@
1
+ function a(e, i) {
2
+ const n = typeof e.getAnimations == "function" ? e.getAnimations({ subtree: !0 }) : [];
3
+ if (n.length === 0) {
4
+ i();
5
+ return;
6
+ }
7
+ let s = !1;
8
+ const t = () => {
9
+ s || (s = !0, i());
10
+ };
11
+ Promise.all(n.map((o) => o.finished.catch(() => {
12
+ }))).then(t, t), setTimeout(t, 600);
13
+ }
14
+ export {
15
+ a
16
+ };
@@ -3,6 +3,8 @@ import { BahtElement } from './base.js';
3
3
  import { DerivedFieldState, FeatureFlags, FormDefinition, Registry, ValidationError } from '../core/types.js';
4
4
  export interface BahtFormOptions {
5
5
  validateOn?: 'change' | 'blur' | 'submit';
6
+ /** Debounce (ms) for typed fields; unset = BahtFieldBase.defaultDebounce (150). 0 = none. */
7
+ inputDebounce?: number;
6
8
  }
7
9
  /**
8
10
  * <baht-form> — dumb controlled form renderer (spec 01).
@@ -64,6 +66,8 @@ export declare class BahtForm extends BahtElement {
64
66
  private get sortedFields();
65
67
  private stateFor;
66
68
  private valueFor;
69
+ /** Debounced keystrokes still in a control land in `edits` before anyone reads them. */
70
+ private flushTyped;
67
71
  getData(): Record<string, unknown>;
68
72
  setValue(patch: Record<string, unknown>): void;
69
73
  validate(): {
@@ -1,4 +1,4 @@
1
- import { LitElement, nothing, TemplateResult } from 'lit';
1
+ import { LitElement, nothing, PropertyValues, TemplateResult } from 'lit';
2
2
  import { FieldDescriptor } from '../core/types.js';
3
3
  /** Light-DOM Lit base: consumer CSS reaches every internal node (spec 01 §6). */
4
4
  export declare class BahtElement extends LitElement {
@@ -22,12 +22,41 @@ export declare abstract class BahtFieldBase extends BahtElement {
22
22
  * collide — worst for radios, whose shared native `name` merges groups.
23
23
  */
24
24
  private readonly uid;
25
+ /**
26
+ * Default trailing debounce (ms) for TYPED edits — text, email, password,
27
+ * textarea, number. Every keystroke otherwise re-runs the host's rules,
28
+ * validation and dependent-option fetches. Per element: the `debounce`
29
+ * property/attribute; `<baht-form options.inputDebounce>` sets it for a whole
30
+ * form. 0 = emit on every keystroke. Selects, checkboxes, radios, toggles,
31
+ * dates and files are never debounced — a pick is one event.
32
+ */
33
+ static defaultDebounce: number;
25
34
  field: FieldDescriptor;
26
35
  value: unknown;
27
36
  disabled: boolean;
28
37
  readonly: boolean;
29
38
  required: boolean;
30
39
  error: string | null;
40
+ /** Debounce for typed edits (ms); unset = BahtFieldBase.defaultDebounce. */
41
+ debounce?: number;
42
+ /**
43
+ * The keystrokes not yet (or just) handed to the host. The control keeps
44
+ * rendering `typed.value` until the host's `value` moves, so a re-render
45
+ * mid-typing (a sibling field changing) can't snap the text back.
46
+ */
47
+ private typed;
48
+ private typedTimer;
49
+ private readonly onFocusOut;
50
+ connectedCallback(): void;
51
+ disconnectedCallback(): void;
52
+ protected willUpdate(changed: PropertyValues<this>): void;
53
+ protected get effectiveDebounce(): number;
54
+ /** A typed edit: emitted after `debounce` ms of quiet (or at once when 0). */
55
+ protected emitTyped(value: unknown): void;
56
+ /** Hand a pending typed edit to the host now (blur, disconnect, host reads). Idempotent. */
57
+ flushTyped(): void;
58
+ /** What a typed control shows: pending keystrokes win over a stale host value. */
59
+ protected get shownValue(): unknown;
31
60
  /** Emit the user's edit upward (composed so it crosses any boundary). */
32
61
  protected emitInput(value: unknown): void;
33
62
  protected abstract renderControl(): TemplateResult;
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Call `done` once the CSS animations currently running on `el` (or inside
3
+ * it) have finished — or right away when none play: `prefers-reduced-motion`
4
+ * (the stylesheet sets `animation: none`), a host without the tokens
5
+ * stylesheet, or a DOM without the Web Animations API (happy-dom). Add the
6
+ * `--leaving` class BEFORE calling this so the exit keyframes are the ones
7
+ * being waited on.
8
+ */
9
+ export declare function afterExit(el: Element, done: () => void): void;
@@ -12,6 +12,7 @@ export declare class BahtAlert extends BahtElement {
12
12
  message: string;
13
13
  dismissible: boolean;
14
14
  private dismissed;
15
+ private generation;
15
16
  protected willUpdate(changed: Map<PropertyKey, unknown>): void;
16
17
  private dismiss;
17
18
  protected render(): TemplateResult | typeof nothing;
@@ -13,6 +13,11 @@ import { BahtFieldBase } from '../base.js';
13
13
  * The calendar renders INSIDE the element (flatpickr `static`), so it lives in
14
14
  * light DOM like every other node and picks up a theme set on any ancestor.
15
15
  * Give a clipping ancestor (`overflow: hidden`) room, or it hides the popup.
16
+ *
17
+ * A footer under the grid carries **Today** (picks today — greyed out when
18
+ * min/max/disabled rules exclude it) and **Clear** (empties the value). Both
19
+ * go through flatpickr, so they emit exactly like a click on a day. `disableMobile`
20
+ * keeps this calendar on phones too — never the OS date wheel.
16
21
  */
17
22
  export declare class BahtDatepicker extends BahtFieldBase {
18
23
  private fp;
@@ -22,6 +27,8 @@ export declare class BahtDatepicker extends BahtFieldBase {
22
27
  * pick onChange already sent — compare against this until `value` catches up.
23
28
  */
24
29
  private lastEmitted;
30
+ private todayBtn;
31
+ private clearBtn;
25
32
  protected renderControl(): TemplateResult;
26
33
  connectedCallback(): void;
27
34
  disconnectedCallback(): void;
@@ -30,6 +37,13 @@ export declare class BahtDatepicker extends BahtFieldBase {
30
37
  /** Push the host-fed `value` into the calendar without echoing an event. */
31
38
  private syncValue;
32
39
  private options;
40
+ private mountFooter;
41
+ /** Today greys out when the rules exclude it; Clear when there is nothing to clear.
42
+ * `fp` is passed explicitly from onReady — it fires inside the flatpickr()
43
+ * call, before `this.fp` is assigned. */
44
+ private refreshFooter;
45
+ private todayAllowed;
46
+ private pickToday;
33
47
  private emitIfChanged;
34
48
  /** Host value (any mode) -> the Date list flatpickr works with. */
35
49
  private datesOf;
@@ -16,6 +16,10 @@ export declare class BahtModal extends BahtElement {
16
16
  showClose: boolean;
17
17
  closeOnScrim: boolean;
18
18
  private bodyEl;
19
+ private static instances;
20
+ private readonly titleId;
21
+ private closing;
22
+ private closeToken;
19
23
  private static openStack;
20
24
  private previousFocus;
21
25
  private onKeydown;
@@ -25,6 +29,7 @@ export declare class BahtModal extends BahtElement {
25
29
  connectedCallback(): void;
26
30
  disconnectedCallback(): void;
27
31
  protected firstUpdated(): void;
32
+ protected willUpdate(changed: Map<PropertyKey, unknown>): void;
28
33
  protected updated(changed: Map<PropertyKey, unknown>): void;
29
34
  /** Ask the host to close (the host owns `open`). */
30
35
  requestClose(reason?: 'escape' | 'scrim' | 'button'): void;
@@ -1,4 +1,4 @@
1
- import { TemplateResult } from 'lit';
1
+ import { PropertyValues, TemplateResult } from 'lit';
2
2
  import { BahtFieldBase } from '../base.js';
3
3
  import { ValidationError } from '../../core/types.js';
4
4
  /**
@@ -16,12 +16,14 @@ export declare class BahtRepeater extends BahtFieldBase {
16
16
  * when the descriptor changes or row indexes shift (remove).
17
17
  */
18
18
  private controls;
19
- protected willUpdate(changed: Map<PropertyKey, unknown>): void;
19
+ protected willUpdate(changed: PropertyValues<this>): void;
20
20
  private get rows();
21
21
  private get subFields();
22
22
  private patchRow;
23
23
  private addRow;
24
24
  private removeRow;
25
+ /** Pending keystrokes in any row land in the array before the host reads it. */
26
+ flushTyped(): void;
25
27
  private errorFor;
26
28
  private renderSub;
27
29
  protected renderControl(): TemplateResult;
@@ -1,5 +1,45 @@
1
- import { TemplateResult } from 'lit';
1
+ import { PropertyValues, TemplateResult } from 'lit';
2
2
  import { BahtFieldBase } from '../base.js';
3
+ /**
4
+ * Single-choice dropdown. Renders ITS OWN list (light DOM, positioned under
5
+ * the trigger) instead of the native `<select>` — so the picker looks the same
6
+ * on iOS/macOS as everywhere else (no UIKit wheel, no AppKit menu), and every
7
+ * option is styleable with the tokens.
8
+ *
9
+ * ARIA: APG "select-only combobox". The trigger is a `<button role="combobox">`
10
+ * (so `<label for>` still names it); `aria-activedescendant` tracks the
11
+ * highlighted option while focus stays on the trigger. Keys: Arrow Up/Down,
12
+ * Home/End, Enter/Space pick, Escape closes, Tab picks the highlighted option
13
+ * and moves on, typing jumps to the first option starting with those letters
14
+ * (while closed it picks it directly, like a native select).
15
+ *
16
+ * Value contract unchanged: option `key`, or `null` for the placeholder row.
17
+ */
3
18
  export declare class BahtSelect extends BahtFieldBase {
19
+ private open;
20
+ /** Index into `rows` (0 = the placeholder row) — the highlighted option. */
21
+ private active;
22
+ private typeBuffer;
23
+ private typeTimer;
24
+ private readonly onDocMousedown;
25
+ disconnectedCallback(): void;
26
+ private get listId();
27
+ private optionId;
28
+ /** Placeholder row first (picks `null`), then the field's options. */
29
+ private get rows();
30
+ private get currentKey();
31
+ private get selectedIndex();
32
+ private get interactive();
33
+ protected willUpdate(changed: PropertyValues<this>): void;
34
+ protected updated(): void;
35
+ private openList;
36
+ private close;
37
+ private toggle;
38
+ private commit;
39
+ private highlight;
40
+ private move;
41
+ /** Type-to-select: first option (after the highlighted one) starting with the buffer. */
42
+ private typeahead;
43
+ private onKeydown;
4
44
  protected renderControl(): TemplateResult;
5
45
  }
@@ -95,6 +95,8 @@ export declare class BahtTable extends BahtElement {
95
95
  hasNext: boolean;
96
96
  hasPrev: boolean;
97
97
  private pickerOpen;
98
+ private static instances;
99
+ private readonly pickerTitleId;
98
100
  /** User's picks once they've touched the picker; null = follow `visibleColumns`/all. */
99
101
  private pickedColumns;
100
102
  /** Working copy edited inside the modal; committed to `pickedColumns` on OK. */
@@ -104,7 +106,12 @@ export declare class BahtTable extends BahtElement {
104
106
  private pickSel;
105
107
  /** Reference columns unfolded in the Available tree (dot-walk). */
106
108
  private expanded;
109
+ /** Element focused before the picker opened — focus returns there on close. */
110
+ private pickerPreviousFocus;
107
111
  private readonly onPickerKeydown;
112
+ private pickerFocusables;
113
+ /** Keep Tab cycling inside the column-picker dialog (no escape to the page behind). */
114
+ private trapPickerFocus;
108
115
  disconnectedCallback(): void;
109
116
  protected willUpdate(changed: Map<PropertyKey, unknown>): void;
110
117
  /** The declared map, or one derived from the first row (nested objects become reference columns). */