bank20baht-ui 0.12.0 → 0.12.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.
@@ -88,6 +88,8 @@ export declare class BahtForm extends BahtElement {
88
88
  private nextVisible;
89
89
  private revealClass;
90
90
  private stateFor;
91
+ /** The row sub-field states of one repeater: `fieldStates` keys starting `key[`. */
92
+ private rowStatesFor;
91
93
  private valueFor;
92
94
  /** Debounced keystrokes still in a control land in `edits` before anyone reads them. */
93
95
  private flushTyped;
@@ -1,16 +1,16 @@
1
1
  import { nothing as g, html as p } from "lit";
2
- import { property as d, state as m, customElement as x } from "lit/decorators.js";
3
- import { repeat as E } from "lit/directives/repeat.js";
2
+ import { property as d, state as m, customElement as E } from "lit/decorators.js";
3
+ import { repeat as P } from "lit/directives/repeat.js";
4
4
  import { html as $ } from "lit/static-html.js";
5
- import { BahtElement as P, hasDom as O } from "./base.js";
6
- import { TAG_FOR_TYPE as T, WIDTH_CLASS as B, staticTag as I } from "./primitives/tag-map.js";
5
+ import { BahtElement as T, hasDom as O } from "./base.js";
6
+ import { TAG_FOR_TYPE as B, WIDTH_CLASS as I, staticTag as j } from "./primitives/tag-map.js";
7
7
  import { defaultValue as C } from "../core/defaults.js";
8
8
  import { t as D } from "../core/i18n.js";
9
9
  import { validateField as _ } from "../core/validators.js";
10
10
  import { resolveViewFields as M } from "../core/views.js";
11
- import { applyFlags as j } from "../core/flags.js";
12
- import { hasScripts as w, runScripts as F, createScriptContext as L, MAX_SCRIPT_DEPTH as V } from "../core/engine/scripts.js";
13
- import { displayValue as A } from "../core/display.js";
11
+ import { applyFlags as L } from "../core/flags.js";
12
+ import { hasScripts as w, runScripts as F, createScriptContext as A, MAX_SCRIPT_DEPTH as x } from "../core/engine/scripts.js";
13
+ import { displayValue as R } from "../core/display.js";
14
14
  import "./primitives/baht-input.js";
15
15
  import "./primitives/baht-textarea.js";
16
16
  import "./primitives/baht-number.js";
@@ -26,12 +26,12 @@ import "./primitives/baht-file.js";
26
26
  import "./primitives/baht-text.js";
27
27
  import "./primitives/baht-section.js";
28
28
  import "./primitives/baht-repeater.js";
29
- var R = Object.defineProperty, U = Object.getOwnPropertyDescriptor, h = (t, s, e, i) => {
30
- for (var r = i > 1 ? void 0 : i ? U(s, e) : s, o = t.length - 1, a; o >= 0; o--)
29
+ var U = Object.defineProperty, W = Object.getOwnPropertyDescriptor, h = (t, s, e, i) => {
30
+ for (var r = i > 1 ? void 0 : i ? W(s, e) : s, o = t.length - 1, a; o >= 0; o--)
31
31
  (a = t[o]) && (r = (i ? a(s, e, r) : a(r)) || r);
32
- return i && r && R(s, e, r), r;
32
+ return i && r && U(s, e, r), r;
33
33
  };
34
- let n = class extends P {
34
+ let n = class extends T {
35
35
  constructor() {
36
36
  super(...arguments), this.value = {}, this.registry = {}, this.showOptional = !1, this.options = {}, this.fieldStates = {}, this.flags = {}, this.readonly = !1, this.edits = {}, this.errors = [], this.scriptStates = {}, this.fieldMessages = {}, this.formMessages = [], this.scriptContext = null, this.scriptContextForm = null, this.scriptDepth = 0, this.loadedForm = null, this.dynamicOptions = /* @__PURE__ */ new Map(), this.optionsSnapshots = /* @__PURE__ */ new Map(), this.optionsEpoch = /* @__PURE__ */ new Map(), this.warnedViews = /* @__PURE__ */ new Set(), this.flagCache = {}, this.lastVisible = {}, this.nextVisible = {};
37
37
  }
@@ -45,7 +45,7 @@ let n = class extends P {
45
45
  get effectiveForm() {
46
46
  const t = this.assignedForm;
47
47
  if (t)
48
- return (this.flagCache.form !== t || this.flagCache.flags !== this.flags) && (this.flagCache = { form: t, flags: this.flags, out: j(t, this.flags) }), this.flagCache.out;
48
+ return (this.flagCache.form !== t || this.flagCache.flags !== this.flags) && (this.flagCache = { form: t, flags: this.flags, out: L(t, this.flags) }), this.flagCache.out;
49
49
  }
50
50
  willUpdate(t) {
51
51
  t.has("value") && (this.edits = {}), (t.has("form") || t.has("flags")) && (this.dynamicOptions.clear(), this.optionsSnapshots.clear(), this.optionsEpoch.clear()), t.has("form") && (this.scriptStates = {}, this.fieldMessages = {}, this.formMessages = [], this.scriptContext = null), (t.has("form") || t.has("flags") || t.has("value") || t.has("registry")) && this.syncDynamicOptions();
@@ -111,6 +111,13 @@ let n = class extends P {
111
111
  }, e = this.scriptStates[t.key];
112
112
  return e ? { ...s, ...e } : s;
113
113
  }
114
+ /** The row sub-field states of one repeater: `fieldStates` keys starting `key[`. */
115
+ rowStatesFor(t) {
116
+ const s = `${t}[`, e = {};
117
+ for (const [i, r] of Object.entries(this.fieldStates))
118
+ i.startsWith(s) && (e[i] = r);
119
+ return e;
120
+ }
114
121
  valueFor(t) {
115
122
  return Object.hasOwn(this.edits, t.key) ? this.edits[t.key] : Object.hasOwn(this.value, t.key) ? this.value[t.key] : C(t);
116
123
  }
@@ -149,7 +156,9 @@ let n = class extends P {
149
156
  const i = this.stateFor(e);
150
157
  if (!i.visible) continue;
151
158
  const r = i.required === !!e.required ? e : { ...e, required: i.required };
152
- t.push(..._(r, this.valueFor(e), this.registry, s));
159
+ t.push(
160
+ ..._(r, this.valueFor(e), this.registry, s, this.fieldStates)
161
+ );
153
162
  }
154
163
  return t;
155
164
  }
@@ -183,7 +192,7 @@ let n = class extends P {
183
192
  // ---- client scripts (spec 01 §14) ----
184
193
  /** The `g` (g_form) for the current form — built lazily over this component's state. */
185
194
  g(t) {
186
- return this.scriptContext && this.scriptContextForm === t ? this.scriptContext : (this.scriptContextForm = t, this.scriptContext = L(t, {
195
+ return this.scriptContext && this.scriptContextForm === t ? this.scriptContext : (this.scriptContextForm = t, this.scriptContext = A(t, {
187
196
  getData: () => this.getData(),
188
197
  setValue: (s, e) => {
189
198
  this.applyScriptValue(s, e);
@@ -228,9 +237,9 @@ let n = class extends P {
228
237
  runChangeScripts(t, s, e, i) {
229
238
  const r = this.effectiveForm;
230
239
  if (!(!r || !w(r, "change", t))) {
231
- if (this.scriptDepth >= V) {
240
+ if (this.scriptDepth >= x) {
232
241
  console.warn(
233
- `[bahtui] script cascade on "${r.form_name}.${t}" exceeded ${V} levels — stopped (setValue ping-pong between change scripts?)`
242
+ `[bahtui] script cascade on "${r.form_name}.${t}" exceeded ${x} levels — stopped (setValue ping-pong between change scripts?)`
234
243
  );
235
244
  return;
236
245
  }
@@ -295,7 +304,7 @@ let n = class extends P {
295
304
  const s = this.stateFor(t);
296
305
  if (!s.visible) return [];
297
306
  const e = this.getData(), i = s.required === !!t.required ? t : { ...t, required: s.required };
298
- return _(i, this.valueFor(t), this.registry, e);
307
+ return _(i, this.valueFor(t), this.registry, e, this.fieldStates);
299
308
  }
300
309
  /** `validateOn: 'blur'` — validate just the field the user left, same as
301
310
  * how errors are shown elsewhere (merged into `this.errors`, painted by
@@ -307,18 +316,18 @@ let n = class extends P {
307
316
  }
308
317
  renderField(t) {
309
318
  var S;
310
- const s = T[t.type];
319
+ const s = B[t.type];
311
320
  if (!s)
312
321
  return console.warn(`[bahtui] unknown field type "${t.type}" — skipped`), g;
313
- const e = this.stateFor(t), i = B[t.width ?? "full"] ?? "baht-field--w-full", r = ((S = this.errors.find((u) => u.key === t.key)) == null ? void 0 : S.message) ?? null;
322
+ const e = this.stateFor(t), i = I[t.width ?? "full"] ?? "baht-field--w-full", r = ((S = this.errors.find((u) => u.key === t.key)) == null ? void 0 : S.message) ?? null;
314
323
  if (this.readonly && t.type !== "label" && t.type !== "section")
315
324
  return this.renderReadonlyField(t, i, e.visible);
316
325
  const o = t.options_from ? { ...t, options: this.dynamicOptions.get(t.key) ?? t.options ?? [] } : t, a = this.valueFor(t), l = !e.enabled, c = this.readonly || e.readonly, b = this.options.inputDebounce, v = (u) => {
317
326
  this.onControlInput(t.key, u);
318
- }, f = I(s);
327
+ }, f = j(s);
319
328
  let y;
320
329
  if (t.type === "repeater") {
321
- const u = this.errors.filter((q) => q.key.startsWith(`${t.key}[`));
330
+ const u = this.errors.filter((q) => q.key.startsWith(`${t.key}[`)), V = this.rowStatesFor(t.key);
322
331
  y = $`<${f}
323
332
  .field=${o}
324
333
  .value=${a}
@@ -329,6 +338,7 @@ let n = class extends P {
329
338
  .error=${r}
330
339
  .debounce=${b}
331
340
  .rowErrors=${u}
341
+ .rowStates=${V}
332
342
  @baht-input=${v}
333
343
  ></${f}>`;
334
344
  } else if (t.type === "file") {
@@ -395,7 +405,7 @@ let n = class extends P {
395
405
  e && this.onFieldInput(e, s);
396
406
  }
397
407
  renderReadonlyField(t, s, e) {
398
- const i = t.options_from ? this.dynamicOptions.get(t.key) ?? t.options ?? [] : t.options, r = A(t, this.valueFor(t), i), o = r.kind === "empty" ? p`<span class="baht-readonly-value baht-readonly-value--empty">${D("emptyValue")}</span>` : r.kind === "text" ? p`<span class="baht-readonly-value">${r.text}</span>` : r.kind === "chips" ? p`<span class="baht-readonly-value baht-readonly-chips"
408
+ const i = t.options_from ? this.dynamicOptions.get(t.key) ?? t.options ?? [] : t.options, r = R(t, this.valueFor(t), i), o = r.kind === "empty" ? p`<span class="baht-readonly-value baht-readonly-value--empty">${D("emptyValue")}</span>` : r.kind === "text" ? p`<span class="baht-readonly-value">${r.text}</span>` : r.kind === "chips" ? p`<span class="baht-readonly-value baht-readonly-chips"
399
409
  >${r.items.map((a) => p`<span class="baht-readonly-chip">${a}</span>`)}</span
400
410
  >` : p`<div class="baht-readonly-rows">
401
411
  ${r.rows.map(
@@ -431,7 +441,7 @@ let n = class extends P {
431
441
  </div>`
432
442
  )}
433
443
  </div>` : g}
434
- ${E(
444
+ ${P(
435
445
  this.sortedFields,
436
446
  (t) => t.key,
437
447
  (t) => this.renderField(t)
@@ -482,7 +492,7 @@ h([
482
492
  m()
483
493
  ], n.prototype, "formMessages", 2);
484
494
  n = h([
485
- x("baht-form")
495
+ E("baht-form")
486
496
  ], n);
487
497
  export {
488
498
  n as BahtForm
@@ -2,7 +2,7 @@ import { html as y } from "lit";
2
2
  import { customElement as g } from "lit/decorators.js";
3
3
  import { ifDefined as D } from "lit/directives/if-defined.js";
4
4
  import { BahtFieldBase as w } from "../field-base.js";
5
- import { formatIsoDateTime as u, formatIsoDate as c, dateModeOf as h, parseIsoDate as l, isoDaysOf as k, parseIsoDateTime as C, parseDisabledEntry as v } from "../../core/dates.js";
5
+ import { formatIsoDateTime as u, formatIsoDate as h, dateModeOf as c, parseIsoDate as l, isoDaysOf as k, parseIsoDateTime as v, parseDisabledEntry as C } from "../../core/dates.js";
6
6
  import { t as p } from "../../core/i18n.js";
7
7
  import { renderIcon as _ } from "./icons.js";
8
8
  var I = Object.getOwnPropertyDescriptor, B = (t, e, a, s) => {
@@ -12,7 +12,12 @@ var I = Object.getOwnPropertyDescriptor, B = (t, e, a, s) => {
12
12
  };
13
13
  let f, O;
14
14
  function x() {
15
- return O ?? (O = import("flatpickr").then((t) => f = t.default));
15
+ return O ?? (O = import("flatpickr").then(
16
+ (t) => f = t.default,
17
+ (t) => {
18
+ console.warn("[bahtui] <baht-datepicker> needs the `flatpickr` peer dependency", t);
19
+ }
20
+ ));
16
21
  }
17
22
  let m = class extends w {
18
23
  constructor() {
@@ -56,10 +61,8 @@ let m = class extends w {
56
61
  }
57
62
  if (((s = this.fp) == null ? void 0 : s.input) !== e || t.has("field") || t.has("disabled") || t.has("readonly")) {
58
63
  if (this.teardown(), !f) {
59
- this.pendingLoad ?? (this.pendingLoad = x().catch((i) => {
60
- console.warn("[bahtui] <baht-datepicker> needs the `flatpickr` peer dependency", i);
61
- }).then(() => {
62
- this.pendingLoad = void 0, this.isConnected && this.requestUpdate();
64
+ this.pendingLoad ?? (this.pendingLoad = x().then((i) => {
65
+ this.pendingLoad = void 0, i && this.isConnected && this.requestUpdate();
63
66
  }));
64
67
  return;
65
68
  }
@@ -81,11 +84,11 @@ let m = class extends w {
81
84
  /** Value-equality for the picker's own selection (minute-precise with `enable_time`). */
82
85
  sameInstants(t, e) {
83
86
  if (t.length !== e.length) return !1;
84
- const a = this.field.enable_time ? u : c;
87
+ const a = this.field.enable_time ? u : h;
85
88
  return t.every((s, i) => a(s) === a(e[i]));
86
89
  }
87
90
  options() {
88
- const t = this.field, e = h(t), a = l(t.min), s = l(t.max), i = b(t);
91
+ const t = this.field, e = c(t), a = l(t.min), s = l(t.max), i = b(t);
89
92
  return {
90
93
  static: !0,
91
94
  disableMobile: !0,
@@ -142,7 +145,7 @@ let m = class extends w {
142
145
  const t = this.fp;
143
146
  if (!t || !this.todayAllowed()) return;
144
147
  const e = this.field.enable_time ? E(/* @__PURE__ */ new Date()) : o(/* @__PURE__ */ new Date());
145
- switch (h(this.field)) {
148
+ switch (c(this.field)) {
146
149
  case "range":
147
150
  t.setDate([e, e], !0);
148
151
  break;
@@ -164,13 +167,13 @@ let m = class extends w {
164
167
  * a host may not always have a time to feed back (an edited record that
165
168
  * predates this field, for one). */
166
169
  datesOf(t) {
167
- const e = (a) => (this.field.enable_time ? C(a) : null) ?? l(a);
170
+ const e = (a) => (this.field.enable_time ? v(a) : null) ?? l(a);
168
171
  return k(t).map(e).filter((a) => a !== null);
169
172
  }
170
173
  /** flatpickr's selection -> the value shape of the field's mode. */
171
174
  toValue(t) {
172
- const e = this.field.enable_time ? u : c, a = t.map(e);
173
- switch (h(this.field)) {
175
+ const e = this.field.enable_time ? u : h, a = t.map(e);
176
+ switch (c(this.field)) {
174
177
  case "range":
175
178
  return a.length === 2 ? [a[0], a[1]] : null;
176
179
  case "multiple":
@@ -190,7 +193,7 @@ function E(t) {
190
193
  return new Date(t.getFullYear(), t.getMonth(), t.getDate(), t.getHours(), t.getMinutes());
191
194
  }
192
195
  function F(t, e) {
193
- return c(t) === c(e);
196
+ return h(t) === h(e);
194
197
  }
195
198
  function L(t, e) {
196
199
  if (t instanceof Date) return F(t, e);
@@ -204,7 +207,7 @@ function L(t, e) {
204
207
  function b(t) {
205
208
  const e = [];
206
209
  for (const s of t.disabled_dates ?? []) {
207
- const i = v(s);
210
+ const i = C(s);
208
211
  i && e.push(i[0].getTime() === i[1].getTime() ? i[0] : { from: i[0], to: i[1] });
209
212
  }
210
213
  const a = t.disabled_weekdays;
@@ -1,6 +1,6 @@
1
1
  import { nothing as r, html as h } from "lit";
2
2
  import { property as c, query as m, state as f, customElement as b } from "lit/decorators.js";
3
- import { boolOff as y, BahtElement as v, hasDom as p, adoptLightChildren as u } from "../base.js";
3
+ import { boolOff as v, BahtElement as y, 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";
@@ -13,10 +13,10 @@ const E = {
13
13
  fromAttribute: (t) => t !== null && t !== "false",
14
14
  toAttribute: (t) => t ? "" : null
15
15
  };
16
- let s = class extends v {
16
+ let s = class extends y {
17
17
  constructor() {
18
18
  super(...arguments), this.open = !1, this.heading = "", this.description = "", this.showClose = !0, this.placement = "center", this.closeOnScrim = !1, this.closing = !1, this.closeToken = 0, this.previousFocus = null, this.onKeydown = (t) => {
19
- !this.open || s.openStack.at(-1) !== this || (t.key === "Escape" ? this.requestClose("escape") : t.key === "Tab" && this.trapFocus(t));
19
+ !this.open || s.openStack.at(-1) !== this || (t.key === "Escape" ? t.defaultPrevented || this.requestClose("escape") : t.key === "Tab" && this.trapFocus(t));
20
20
  };
21
21
  }
22
22
  get titleId() {
@@ -126,7 +126,7 @@ l([
126
126
  c()
127
127
  ], s.prototype, "description", 2);
128
128
  l([
129
- c({ attribute: "show-close", converter: y })
129
+ c({ attribute: "show-close", converter: v })
130
130
  ], s.prototype, "showClose", 2);
131
131
  l([
132
132
  c()
@@ -1,6 +1,6 @@
1
1
  import { TemplateResult } from 'lit';
2
2
  import { BahtFieldBase } from '../field-base.js';
3
- import { ValidationError } from '../../core/types.js';
3
+ import { DerivedFieldState, ValidationError } from '../../core/types.js';
4
4
  /**
5
5
  * <baht-repeater> — array-of-rows control (spec 01 §10). `value` is an array
6
6
  * of row objects; every row renders the same `field.fields` sub-descriptors
@@ -10,6 +10,11 @@ import { ValidationError } from '../../core/types.js';
10
10
  export declare class BahtRepeater extends BahtFieldBase {
11
11
  /** Row-scoped errors from the host form, keyed `key[i].subKey`. */
12
12
  rowErrors: ValidationError[];
13
+ /**
14
+ * Rule-derived states of the row sub-fields, keyed `key[i].sub` (spec 02
15
+ * §2a). Absent = every sub-field visible with its descriptor defaults.
16
+ */
17
+ rowStates: Record<string, DerivedFieldState>;
13
18
  private get rows();
14
19
  private subFieldsSource;
15
20
  private subFieldsCache;
@@ -1,86 +1,90 @@
1
1
  import { nothing as d, html as l } from "lit";
2
- import { property as m, customElement as y } from "lit/decorators.js";
3
- import { repeat as u } from "lit/directives/repeat.js";
4
- import { html as $ } from "lit/static-html.js";
5
- import { hasDom as w } from "../base.js";
6
- import { BahtFieldBase as v } from "../field-base.js";
7
- import { TAG_FOR_TYPE as _, staticTag as F, WIDTH_CLASS as g } from "./tag-map.js";
8
- import { defaultValue as c } from "../../core/defaults.js";
2
+ import { property as b, customElement as w } from "lit/decorators.js";
3
+ import { repeat as c } from "lit/directives/repeat.js";
4
+ import { html as v } from "lit/static-html.js";
5
+ import { hasDom as _ } from "../base.js";
6
+ import { BahtFieldBase as F } from "../field-base.js";
7
+ import { TAG_FOR_TYPE as g, staticTag as R, WIDTH_CLASS as S } from "./tag-map.js";
8
+ import { defaultValue as f } from "../../core/defaults.js";
9
9
  import { t as h } from "../../core/i18n.js";
10
- var R = Object.defineProperty, T = Object.getOwnPropertyDescriptor, f = (t, e, r, o) => {
11
- for (var s = o > 1 ? void 0 : o ? T(e, r) : e, i = t.length - 1, a; i >= 0; i--)
12
- (a = t[i]) && (s = (o ? a(e, r, s) : a(s)) || s);
13
- return o && s && R(e, r, s), s;
10
+ var k = Object.defineProperty, T = Object.getOwnPropertyDescriptor, p = (r, e, t, o) => {
11
+ for (var s = o > 1 ? void 0 : o ? T(e, t) : e, a = r.length - 1, i; a >= 0; a--)
12
+ (i = r[a]) && (s = (o ? i(e, t, s) : i(s)) || s);
13
+ return o && s && k(e, t, s), s;
14
14
  };
15
- let n = class extends v {
15
+ let n = class extends F {
16
16
  constructor() {
17
- super(...arguments), this.rowErrors = [], this.subFieldsCache = [];
17
+ super(...arguments), this.rowErrors = [], this.rowStates = {}, this.subFieldsCache = [];
18
18
  }
19
19
  get rows() {
20
20
  return Array.isArray(this.value) ? this.value : [];
21
21
  }
22
22
  /** Ordered sub-descriptors, cached per identity (read per row per render). */
23
23
  get subFields() {
24
- const t = this.field.fields;
25
- return t !== this.subFieldsSource && (this.subFieldsSource = t, this.subFieldsCache = [...t ?? []].sort((e, r) => e.order - r.order).filter((e) => e.type !== "repeater")), this.subFieldsCache;
24
+ const r = this.field.fields;
25
+ return r !== this.subFieldsSource && (this.subFieldsSource = r, this.subFieldsCache = [...r ?? []].sort((e, t) => e.order - t.order).filter((e) => e.type !== "repeater")), this.subFieldsCache;
26
26
  }
27
- patchRow(t, e, r) {
27
+ patchRow(r, e, t) {
28
28
  const o = [...this.rows];
29
- o[t] = { ...o[t], [e]: r }, this.emitInput(o);
29
+ o[r] = { ...o[r], [e]: t }, this.emitInput(o);
30
30
  }
31
31
  addRow() {
32
- const t = {};
32
+ const r = {};
33
33
  for (const e of this.subFields)
34
- e.type === "label" || e.type === "section" || (t[e.key] = c(e));
35
- this.emitInput([...this.rows, t]);
34
+ e.type === "label" || e.type === "section" || (r[e.key] = f(e));
35
+ this.emitInput([...this.rows, r]);
36
36
  }
37
- removeRow(t) {
38
- this.emitInput(this.rows.filter((e, r) => r !== t));
37
+ removeRow(r) {
38
+ this.emitInput(this.rows.filter((e, t) => t !== r));
39
39
  }
40
40
  /** Pending keystrokes in any row land in the array before the host reads it. */
41
41
  flushTyped() {
42
- var t;
43
- if (!w()) {
42
+ var r;
43
+ if (!_()) {
44
44
  super.flushTyped();
45
45
  return;
46
46
  }
47
47
  for (const e of this.querySelectorAll(".baht-repeater-row > .baht-field > *"))
48
- (t = e.flushTyped) == null || t.call(e);
48
+ (r = e.flushTyped) == null || r.call(e);
49
49
  super.flushTyped();
50
50
  }
51
- errorFor(t, e) {
51
+ errorFor(r, e) {
52
52
  var o;
53
- const r = `${this.field.key}[${t}].${e}`;
54
- return ((o = this.rowErrors.find((s) => s.key === r)) == null ? void 0 : o.message) ?? null;
53
+ const t = `${this.field.key}[${r}].${e}`;
54
+ return ((o = this.rowErrors.find((s) => s.key === t)) == null ? void 0 : o.message) ?? null;
55
55
  }
56
56
  /**
57
57
  * Sub-controls render declaratively (one static-tag template per primitive, rows
58
58
  * keyed by index) so Lit reuses the same node across re-renders — typing keeps
59
59
  * focus, same as <baht-form> — and the whole thing renders on the server.
60
60
  */
61
- renderSub(t, e, r) {
62
- const o = _[r.type];
61
+ renderSub(r, e, t) {
62
+ const o = g[t.type];
63
63
  if (!o) return d;
64
- const s = F(o), i = g[r.width ?? "full"] ?? "baht-field--w-full", a = (p) => {
65
- p.stopPropagation();
66
- const { value: b } = p.detail;
67
- this.patchRow(e, r.key, b);
68
- };
69
- return l`<div class="baht-field ${i}" data-key=${r.key} data-type=${r.type}>
70
- ${$`<${s}
71
- .field=${r}
72
- .value=${Object.hasOwn(t, r.key) ? t[r.key] : c(r)}
73
- .disabled=${this.disabled}
74
- .readonly=${this.readonly}
75
- .required=${!!r.required}
76
- .error=${this.errorFor(e, r.key)}
64
+ const s = R(o), a = S[t.width ?? "full"] ?? "baht-field--w-full", i = this.rowStates[`${this.field.key}[${e}].${t.key}`], y = (u) => {
65
+ u.stopPropagation();
66
+ const { value: m } = u.detail;
67
+ this.patchRow(e, t.key, m);
68
+ }, $ = i !== void 0 && !i.visible;
69
+ return l`<div
70
+ class="baht-field ${a}${$ ? " baht-field--hidden" : ""}"
71
+ data-key=${t.key}
72
+ data-type=${t.type}
73
+ >
74
+ ${v`<${s}
75
+ .field=${t}
76
+ .value=${Object.hasOwn(r, t.key) ? r[t.key] : f(t)}
77
+ .disabled=${this.disabled || i !== void 0 && !i.enabled}
78
+ .readonly=${this.readonly || ((i == null ? void 0 : i.readonly) ?? !1)}
79
+ .required=${i ? i.required : !!t.required}
80
+ .error=${this.errorFor(e, t.key)}
77
81
  .debounce=${this.debounce}
78
- @baht-input=${a}
82
+ @baht-input=${y}
79
83
  ></${s}>`}
80
84
  </div>`;
81
85
  }
82
86
  renderControl() {
83
- const t = this.rows, e = !this.disabled && !this.readonly, r = this.field.max_rows !== void 0 && t.length >= this.field.max_rows;
87
+ const r = this.rows, e = !this.disabled && !this.readonly, t = this.field.max_rows !== void 0 && r.length >= this.field.max_rows;
84
88
  return l`<div
85
89
  class="baht-repeater"
86
90
  id=${this.controlId}
@@ -88,8 +92,8 @@ let n = class extends v {
88
92
  aria-labelledby=${this.field.label ? this.labelId : d}
89
93
  aria-describedby=${this.describedBy}
90
94
  >
91
- ${u(
92
- t,
95
+ ${c(
96
+ r,
93
97
  (o, s) => s,
94
98
  (o, s) => l`<div
95
99
  class="baht-repeater-row"
@@ -97,10 +101,10 @@ let n = class extends v {
97
101
  role="group"
98
102
  aria-label=${h("row", { n: s + 1 })}
99
103
  >
100
- ${u(
104
+ ${c(
101
105
  this.subFields,
102
- (i) => i.key,
103
- (i) => this.renderSub(o, s, i)
106
+ (a) => a.key,
107
+ (a) => this.renderSub(o, s, a)
104
108
  )}
105
109
  ${e ? l`<button
106
110
  type="button"
@@ -118,7 +122,7 @@ let n = class extends v {
118
122
  ${this.readonly ? d : l`<button
119
123
  type="button"
120
124
  class="baht-repeater-add"
121
- ?disabled=${this.disabled || r}
125
+ ?disabled=${this.disabled || t}
122
126
  @click=${() => {
123
127
  this.addRow();
124
128
  }}
@@ -128,11 +132,14 @@ let n = class extends v {
128
132
  </div>`;
129
133
  }
130
134
  };
131
- f([
132
- m({ attribute: !1 })
135
+ p([
136
+ b({ attribute: !1 })
133
137
  ], n.prototype, "rowErrors", 2);
134
- n = f([
135
- y("baht-repeater")
138
+ p([
139
+ b({ attribute: !1 })
140
+ ], n.prototype, "rowStates", 2);
141
+ n = p([
142
+ w("baht-repeater")
136
143
  ], n);
137
144
  export {
138
145
  n as BahtRepeater
@@ -31,7 +31,7 @@ let a = class extends g {
31
31
  return c() ? ((t = this.querySelector(".baht-swipe-row-actions")) == null ? void 0 : t.offsetWidth) ?? 0 : 0;
32
32
  }
33
33
  onPointerdown(t) {
34
- !this.hasActions || t.button !== 0 || (this.start = {
34
+ !this.hasActions || t.button !== 0 || (this.swallowClick = !1, this.start = {
35
35
  id: t.pointerId,
36
36
  x: t.clientX,
37
37
  y: t.clientY,
@@ -1,9 +1,27 @@
1
1
  import { Condition, NestedData } from '../types.js';
2
- /** Read a "formName.fieldKey" reference out of nested data. */
3
- export declare function readRef(data: NestedData, ref: string): unknown;
2
+ /** The repeater row a rule is being evaluated for (spec 02 §2a). */
3
+ export interface RowScope {
4
+ form: string;
5
+ repeater: string;
6
+ index: number;
7
+ }
8
+ export interface RowRef {
9
+ form: string;
10
+ repeater: string;
11
+ sub: string;
12
+ }
13
+ /** Split a row-scoped ref, or `null` when it is a plain `Form.key` reference. */
14
+ export declare function parseRowRef(ref: string): RowRef | null;
15
+ /**
16
+ * Read a "formName.fieldKey" reference out of nested data. With a `scope`, a
17
+ * row-scoped ref (`Form.repeater[].sub`) reads that sub-field of the scoped row.
18
+ */
19
+ export declare function readRef(data: NestedData, ref: string, scope?: RowScope): unknown;
4
20
  /**
5
21
  * Ordering used by rule conditions AND the `compare` validator: numeric when
6
22
  * both sides coerce, date-aware, else lexicographic. Null = not comparable.
7
23
  */
8
24
  export declare function compareValues(a: unknown, b: unknown): number | null;
9
- export declare function evalCondition(cond: Condition | undefined, data: NestedData): boolean;
25
+ export declare function evalCondition(cond: Condition | undefined, data: NestedData, scope?: RowScope): boolean;
26
+ /** Every row-scoped ref a condition mentions (`field` and `value_field`). */
27
+ export declare function conditionRowRefs(cond: Condition | undefined): RowRef[];