@declarion/react 0.1.93 → 0.2.1

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.
Files changed (34) hide show
  1. package/dist-lib/DraggableChildrenTable-C5cpmctN.js +261 -0
  2. package/dist-lib/DraggableChildrenTable-C5cpmctN.js.map +1 -0
  3. package/dist-lib/components/detail-layout/AssociatedBlock.d.ts +1 -0
  4. package/dist-lib/components/detail-layout/ChildrenBlock.d.ts +2 -1
  5. package/dist-lib/components/detail-layout/DetailAuditStrip.d.ts +13 -0
  6. package/dist-lib/components/detail-layout/DetailHighlights.d.ts +15 -0
  7. package/dist-lib/components/detail-layout/ErrorSummary.d.ts +11 -0
  8. package/dist-lib/components/detail-layout/FieldRow.d.ts +21 -0
  9. package/dist-lib/components/detail-layout/LayoutRenderer.d.ts +2 -0
  10. package/dist-lib/components/detail-layout/blockMeta.d.ts +4 -0
  11. package/dist-lib/components/detail-layout/index.d.ts +4 -0
  12. package/dist-lib/components/fields/JsonField.d.ts +1 -0
  13. package/dist-lib/components/fields/cells/factories/emptyCell.d.ts +2 -0
  14. package/dist-lib/components/primitives/SectionCard.d.ts +6 -1
  15. package/dist-lib/components/primitives/dataTableStyles.d.ts +4 -0
  16. package/dist-lib/components/primitives/index.d.ts +1 -1
  17. package/dist-lib/components/shared/AuditMetaStrip.d.ts +11 -0
  18. package/dist-lib/components/shared/HighlightsStrip.d.ts +10 -0
  19. package/dist-lib/components/shared/RecordHeader.d.ts +15 -0
  20. package/dist-lib/components/shared/StatusStepper.d.ts +13 -0
  21. package/dist-lib/components/shared/toast/DeclarionToast.d.ts +31 -0
  22. package/dist-lib/{useUserLocale-GBIXbEE6.js → dataTableStyles-DiIApmjb.js} +1669 -1570
  23. package/dist-lib/dataTableStyles-DiIApmjb.js.map +1 -0
  24. package/dist-lib/declarion-react.css +1 -1
  25. package/dist-lib/index.js +6247 -5179
  26. package/dist-lib/index.js.map +1 -1
  27. package/dist-lib/lib/child-config.d.ts +1 -1
  28. package/dist-lib/lib/toast.d.ts +49 -16
  29. package/dist-lib/stores/appearance.d.ts +3 -0
  30. package/dist-lib/types/schema.d.ts +21 -3
  31. package/package.json +1 -1
  32. package/dist-lib/DraggableChildrenTable-IfspXSFA.js +0 -281
  33. package/dist-lib/DraggableChildrenTable-IfspXSFA.js.map +0 -1
  34. package/dist-lib/useUserLocale-GBIXbEE6.js.map +0 -1
@@ -13,7 +13,7 @@ export interface ResolvedChildConfig {
13
13
  quick_add?: ChildQuickAdd;
14
14
  editable: boolean;
15
15
  position_field?: string;
16
- interaction: "navigate" | "inline_edit" | "readonly";
16
+ interaction: "navigate" | "inline_edit" | "row_edit" | "readonly";
17
17
  }
18
18
  export declare function resolveChildConfig(relation: ChildRelation, childEntity: Entity, screenNode?: LayoutNode): ResolvedChildConfig;
19
19
  export declare function inferSort(entity: Entity): string;
@@ -1,16 +1,49 @@
1
- /**
2
- * Shared toast configuration constants.
3
- *
4
- * The toaster is mounted once in `app.tsx` (sonner `<Toaster>` with
5
- * `closeButton` + `visibleToasts={5}`). Every toast emitter - the central
6
- * `ActionRunner` and the handful of direct `toast.error` callsites in
7
- * `useMutations`, `useVersionWatcher`, and form gates in `SmartDetailPage` -
8
- * MUST import this constant rather than hardcoding `Infinity` (which
9
- * piles toasts up indefinitely and overwhelms the surface).
10
- *
11
- * 60s is the chosen balance: well past human read time, short enough that
12
- * walking away does not produce a stale wall of red on return. `closeButton`
13
- * on the Toaster and the in-description Copy button cover the explicit
14
- * read-and-keep flow for users who need longer than 60s.
15
- */
16
- export declare const ERROR_TOAST_DURATION_MS = 60000;
1
+ import { type ToastType } from "../components/shared/toast/DeclarionToast";
2
+ export type { ToastType, ToastAction } from "../components/shared/toast/DeclarionToast";
3
+ /** Per-call toast options. Severity sets the defaults; these override them. */
4
+ export interface ToastOptions {
5
+ /** Auto-dismiss after this many ms. 0 = sticky. Defaults to the variant's. */
6
+ duration?: number;
7
+ /** Force sticky (never auto-dismiss) regardless of duration. */
8
+ sticky?: boolean;
9
+ /** Trailing action button - e.g. View / Retry / Undo / Reload. */
10
+ action?: {
11
+ label: string;
12
+ onClick: () => void;
13
+ };
14
+ /** Correlation id, shown top-right in mono, included when the user copies. */
15
+ requestId?: string;
16
+ /** Expandable detail block (stack trace, server payload). */
17
+ details?: string;
18
+ /** Repeats sharing a `group` roll up into one toast with a ×N badge. */
19
+ group?: string;
20
+ /** Explicit id - reuse to replace an existing toast in place (idempotent). */
21
+ id?: string;
22
+ }
23
+ /** Fields a loading toast can morph into when its async work resolves. */
24
+ export interface ToastUpdate {
25
+ type?: ToastType;
26
+ title?: string;
27
+ message?: string;
28
+ duration?: number;
29
+ sticky?: boolean;
30
+ action?: {
31
+ label: string;
32
+ onClick: () => void;
33
+ };
34
+ requestId?: string;
35
+ details?: string;
36
+ }
37
+ /** Morph an existing toast in place - the loading -> success/error path. */
38
+ declare function update(id: string, patch: ToastUpdate): void;
39
+ /** The app-wide toast API. Import this - not `sonner` - everywhere. */
40
+ export declare const toast: {
41
+ success: (title: string, message?: string, opts?: ToastOptions) => string;
42
+ info: (title: string, message?: string, opts?: ToastOptions) => string;
43
+ warning: (title: string, message?: string, opts?: ToastOptions) => string;
44
+ error: (title: string, message?: string, opts?: ToastOptions) => string;
45
+ loading: (title: string, message?: string, opts?: ToastOptions) => string;
46
+ update: typeof update;
47
+ dismiss: (id: string) => string | number;
48
+ dismissAll: () => string | number;
49
+ };
@@ -5,6 +5,7 @@ export type SidebarMode = "wide" | "collapsed";
5
5
  export type TabsPosition = "top" | "bottom";
6
6
  export type AiSurface = "command" | "panel" | "both" | "off";
7
7
  export type FaviconSource = "google" | "direct" | "none";
8
+ export type ToastPosition = "top-left" | "top-center" | "top-right" | "bottom-left" | "bottom-center" | "bottom-right";
8
9
  export interface Appearance {
9
10
  theme: ThemeId;
10
11
  accent: AccentId;
@@ -19,6 +20,8 @@ export interface Appearance {
19
20
  aiSurface: AiSurface;
20
21
  /** Favicon source for unknown hosts in URL cells. See ui_favicon_source. */
21
22
  faviconSource: FaviconSource;
23
+ /** Where toasts appear. Read by <Toaster> in app.tsx. See ui_toast_position. */
24
+ toastPosition: ToastPosition;
22
25
  }
23
26
  export declare function applyAppearance(a: Appearance): void;
24
27
  interface AppearanceState extends Appearance {
@@ -142,10 +142,15 @@ export interface ChildDisplay {
142
142
  * - `navigate`: identity cell (first column) is a link to the child's
143
143
  * detail; other cells read-only. Default for associated entities
144
144
  * (child has its own detail screen).
145
- * - `inline_edit`: cells are inline-editable (aggregate children).
145
+ * - `inline_edit`: click a cell to edit it; typing auto-saves after a
146
+ * 500ms debounce. One active cell at a time.
147
+ * - `row_edit`: a per-row Edit button puts the whole row into edit mode
148
+ * (all editable cells become inputs); an explicit Confirm/Cancel pair
149
+ * commits or discards. Nothing persists until Confirm - same flow as
150
+ * the "Add row" draft.
146
151
  * - `readonly`: pure display.
147
152
  */
148
- interaction?: "navigate" | "inline_edit" | "readonly";
153
+ interaction?: "navigate" | "inline_edit" | "row_edit" | "readonly";
149
154
  }
150
155
  export interface ChildRelation {
151
156
  entity: string;
@@ -167,6 +172,7 @@ export interface StatusGroupDef {
167
172
  initial: string;
168
173
  statuses: StatusDef[];
169
174
  transitions?: Record<string, string[]>;
175
+ display_mode?: "pill" | "stepper";
170
176
  }
171
177
  export interface PropertyDef {
172
178
  name: LocalizedString;
@@ -333,6 +339,7 @@ export interface SectionNode {
333
339
  columns?: number;
334
340
  icon?: string;
335
341
  badge?: SectionBadgeConfig;
342
+ emphasis?: "primary" | "secondary";
336
343
  }
337
344
  export interface RowConfig {
338
345
  items: LayoutNode[];
@@ -382,7 +389,16 @@ export interface LayoutNode {
382
389
  searchable?: boolean;
383
390
  filters?: string[];
384
391
  position_field?: string;
385
- interaction?: "navigate" | "inline_edit" | "readonly";
392
+ interaction?: "navigate" | "inline_edit" | "row_edit" | "readonly";
393
+ }
394
+ export interface AuditLineDef {
395
+ label: LocalizedString;
396
+ at?: string;
397
+ by?: string;
398
+ }
399
+ export interface AuditConfig {
400
+ enabled?: boolean;
401
+ lines?: AuditLineDef[];
386
402
  }
387
403
  export interface Screen {
388
404
  type: "list" | "detail" | "custom" | "record_list";
@@ -404,6 +420,8 @@ export interface Screen {
404
420
  items?: LayoutNode[];
405
421
  sidebar?: LayoutNode[];
406
422
  sidebar_width?: string;
423
+ highlights?: string[];
424
+ audit?: AuditConfig;
407
425
  self?: boolean;
408
426
  list_width?: string;
409
427
  list_resizable?: boolean;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@declarion/react",
3
- "version": "0.1.93",
3
+ "version": "0.2.1",
4
4
  "private": false,
5
5
  "license": "MIT",
6
6
  "description": "React SDK for Declarion, the schema-driven business apps platform.",
@@ -1,281 +0,0 @@
1
- import { Jt as e, Kt as t, ct as n, n as r, qt as i, t as a } from "./useUserLocale-GBIXbEE6.js";
2
- import { useCallback as o, useMemo as s, useRef as c } from "react";
3
- import { jsx as l, jsxs as u } from "react/jsx-runtime";
4
- import { DndContext as d, PointerSensor as f, closestCenter as p, useSensor as m, useSensors as h } from "@dnd-kit/core";
5
- import { SortableContext as g, useSortable as _, verticalListSortingStrategy as v } from "@dnd-kit/sortable";
6
- import { CSS as y } from "@dnd-kit/utilities";
7
- //#region src/components/detail-layout/DraggableChildrenTable.tsx
8
- function b({ config: t, childEntity: r, schema: a, rows: _, onChange: y, validationErrors: b, refs: S }) {
9
- let C = c(null), w = t.position_field, T = t.columns, E = h(m(f, { activationConstraint: { distance: 5 } })), D = new Set(Array.isArray(t.foreign_key) ? t.foreign_key : [t.foreign_key]), O = T.filter((e) => {
10
- if (D.has(e) || e === w) return !1;
11
- let t = r.fields.get(e);
12
- return !(!t || t.auto || t.primary);
13
- }), k = new Set(T.filter((e) => {
14
- if (e === w) return !0;
15
- let t = r.fields.get(e);
16
- return t && (t.auto || t.primary);
17
- })), A = T.filter((e) => e !== w), j = s(() => _.filter((e) => !e._deleted).map((e) => e._key), [_]), M = o((e, t, n) => {
18
- y(_.map((r) => r._key === e ? {
19
- ...r,
20
- [t]: n,
21
- _dirty: !0
22
- } : r));
23
- }, [_, y]), N = o(() => {
24
- let e = _.filter((e) => !e._deleted).reduce((e, t) => {
25
- let n = typeof t[w] == "number" ? t[w] : -1;
26
- return Math.max(e, n);
27
- }, -1), n = {
28
- _key: crypto.randomUUID(),
29
- _dirty: !0,
30
- [w]: e + 1
31
- }, i = t.quick_add?.defaults ?? {};
32
- for (let e of O) {
33
- let t = r.fields.get(e);
34
- t && (i[e] === void 0 ? t.default === void 0 ? t.type === "bool" && (n[e] = !1) : n[e] = t.default : n[e] = i[e]);
35
- }
36
- y([..._, n]);
37
- }, [
38
- _,
39
- y,
40
- O,
41
- r,
42
- t.quick_add?.defaults,
43
- w
44
- ]), P = o((e) => {
45
- y(_.map((t) => t._key === e ? {
46
- ...t,
47
- _deleted: !0
48
- } : t));
49
- }, [_, y]), F = o((e) => {
50
- y(_.map((t) => t._key === e ? {
51
- ...t,
52
- _deleted: !1
53
- } : t));
54
- }, [_, y]), I = o((e) => {
55
- let { active: t, over: n } = e;
56
- if (!n || t.id === n.id) return;
57
- let r = _.filter((e) => !e._deleted), i = _.filter((e) => e._deleted), a = r.findIndex((e) => e._key === String(t.id)), o = r.findIndex((e) => e._key === String(n.id));
58
- if (a === -1 || o === -1) return;
59
- let s = [...r], [c] = s.splice(a, 1);
60
- s.splice(o, 0, c), y([...s.map((e, t) => ({
61
- ...e,
62
- [w]: t,
63
- _dirty: e[w] === t ? e._dirty : !0
64
- })), ...i]);
65
- }, [
66
- _,
67
- y,
68
- w
69
- ]), L = o((e) => {
70
- let t = e.target, n = t.closest("td");
71
- if (!n) return;
72
- let r = n.closest("tr");
73
- if (!r) return;
74
- let i = r.closest("tbody");
75
- if (!i) return;
76
- let a = Array.from(r.cells).indexOf(n), o = Array.from(i.rows).indexOf(r);
77
- if (e.key === "Tab") {
78
- let t = e.shiftKey ? -1 : 1, n = Array.from(i.rows), r = o, s = a + t;
79
- for (; r >= 0 && r < n.length;) if (s >= 0 && s < n[r].cells.length) {
80
- let i = n[r].cells[s].querySelector("input, select, textarea, [tabindex]");
81
- if (i) {
82
- e.preventDefault(), i.focus();
83
- return;
84
- }
85
- s += t;
86
- } else r += t, s = t > 0 ? 0 : (n[r]?.cells.length ?? 1) - 1;
87
- } else if (e.key === "Enter") {
88
- e.preventDefault();
89
- let t = Array.from(i.rows);
90
- if (o < t.length - 1) {
91
- let e = t[o + 1].cells[a]?.querySelector("input, select, textarea, [tabindex]");
92
- e && e.focus();
93
- } else N(), requestAnimationFrame(() => {
94
- let e = i.querySelectorAll("tr"), t = e[e.length - 1];
95
- if (t) {
96
- let e = t.querySelector("input, select, textarea, [tabindex]");
97
- e && e.focus();
98
- }
99
- });
100
- } else e.key === "Escape" && t.blur?.();
101
- }, [N]), R = {
102
- height: 30,
103
- padding: "0 12px",
104
- textAlign: "left",
105
- fontWeight: 600,
106
- fontSize: 11,
107
- letterSpacing: "0.04em",
108
- color: "var(--text-3)",
109
- textTransform: "uppercase",
110
- borderBottom: "1px solid var(--divider)"
111
- };
112
- return /* @__PURE__ */ u("div", { children: [/* @__PURE__ */ l("div", {
113
- style: { overflowX: "auto" },
114
- children: /* @__PURE__ */ l(d, {
115
- sensors: E,
116
- collisionDetection: p,
117
- onDragEnd: I,
118
- children: /* @__PURE__ */ u("table", {
119
- ref: C,
120
- style: {
121
- width: "100%",
122
- fontSize: 12.5,
123
- borderCollapse: "separate",
124
- borderSpacing: 0
125
- },
126
- onKeyDown: L,
127
- children: [/* @__PURE__ */ l("thead", { children: /* @__PURE__ */ u("tr", { children: [
128
- /* @__PURE__ */ l("th", { style: {
129
- ...R,
130
- width: 32,
131
- padding: "0 4px"
132
- } }),
133
- A.map((e) => {
134
- let t = r.fields.get(e);
135
- return /* @__PURE__ */ l("th", {
136
- style: R,
137
- children: t ? n(t, e, a.entities) : e
138
- }, e);
139
- }),
140
- /* @__PURE__ */ l("th", { style: {
141
- ...R,
142
- width: 40
143
- } })
144
- ] }) }), /* @__PURE__ */ l(g, {
145
- items: j,
146
- strategy: v,
147
- children: /* @__PURE__ */ l("tbody", { children: _.map((e) => /* @__PURE__ */ l(x, {
148
- row: e,
149
- columns: A,
150
- editableColumns: O,
151
- displayOnlyColumns: k,
152
- childEntity: r,
153
- validationErrors: b,
154
- refs: S,
155
- onCellChange: M,
156
- onDelete: P,
157
- onUndoDelete: F
158
- }, e._key)) })
159
- })]
160
- })
161
- })
162
- }), /* @__PURE__ */ l("div", {
163
- style: { marginTop: 8 },
164
- children: /* @__PURE__ */ l(i, {
165
- kind: "ghost",
166
- size: "xs",
167
- icon: /* @__PURE__ */ l(e.plus, { size: 12 }),
168
- onClick: N,
169
- children: "Add row"
170
- })
171
- })] });
172
- }
173
- function x({ row: n, columns: i, editableColumns: o, displayOnlyColumns: s, childEntity: c, validationErrors: d, refs: f, onCellChange: p, onDelete: m, onUndoDelete: h }) {
174
- let g = a(), v = !!n._deleted, b = d?.[n._key], { attributes: x, listeners: S, setNodeRef: C, transform: w, transition: T, isDragging: E } = _({
175
- id: n._key,
176
- disabled: v
177
- }), D = {
178
- transform: y.Translate.toString(w),
179
- transition: T,
180
- zIndex: E ? 10 : void 0,
181
- opacity: E ? .5 : void 0
182
- }, O = {
183
- padding: "6px 12px",
184
- borderBottom: "1px solid var(--divider)",
185
- verticalAlign: "middle",
186
- color: "var(--text-2)"
187
- }, k = {
188
- padding: "4px 4px",
189
- borderBottom: "1px solid var(--divider)",
190
- verticalAlign: "middle"
191
- };
192
- return /* @__PURE__ */ u("tr", {
193
- ref: C,
194
- style: {
195
- ...D,
196
- opacity: v ? .5 : D?.opacity ?? 1
197
- },
198
- children: [
199
- /* @__PURE__ */ l("td", {
200
- style: {
201
- padding: "4px 4px",
202
- borderBottom: "1px solid var(--divider)",
203
- width: 32,
204
- verticalAlign: "middle"
205
- },
206
- children: !v && /* @__PURE__ */ l("button", {
207
- type: "button",
208
- style: {
209
- cursor: "grab",
210
- padding: 4,
211
- color: "var(--text-3)",
212
- background: "transparent",
213
- border: 0,
214
- display: "inline-flex"
215
- },
216
- ...x,
217
- ...S,
218
- children: /* @__PURE__ */ l(e.grid, { size: 14 })
219
- })
220
- }),
221
- i.map((e) => {
222
- let t = c.fields.get(e), i = b?.includes(e), a = s.has(e), u = o.includes(e);
223
- return v || a || !u ? /* @__PURE__ */ l("td", {
224
- style: {
225
- ...O,
226
- textDecoration: v ? "line-through" : "none"
227
- },
228
- children: t ? r({
229
- field: t,
230
- fieldName: e,
231
- value: n[e],
232
- mode: "display",
233
- record: n,
234
- refs: f,
235
- locale: g
236
- }) : String(n[e] ?? "")
237
- }, e) : /* @__PURE__ */ l("td", {
238
- style: {
239
- ...k,
240
- outline: i ? "1px solid var(--danger)" : "none",
241
- outlineOffset: -1,
242
- borderRadius: i ? 4 : 0
243
- },
244
- title: i ? `${e} is required` : void 0,
245
- children: t ? r({
246
- field: t,
247
- fieldName: e,
248
- value: n[e],
249
- mode: "edit",
250
- onChange: (t) => p(n._key, e, t),
251
- record: n,
252
- refs: f,
253
- locale: g
254
- }) : String(n[e] ?? "")
255
- }, e);
256
- }),
257
- /* @__PURE__ */ l("td", {
258
- style: {
259
- padding: "4px 8px",
260
- borderBottom: "1px solid var(--divider)",
261
- verticalAlign: "middle"
262
- },
263
- children: v ? /* @__PURE__ */ l(t, {
264
- size: 24,
265
- icon: /* @__PURE__ */ l(e.refresh, { size: 12 }),
266
- onClick: () => h(n._key),
267
- title: "Undo delete"
268
- }) : /* @__PURE__ */ l(t, {
269
- size: 24,
270
- icon: /* @__PURE__ */ l(e.trash, { size: 12 }),
271
- onClick: () => m(n._key),
272
- title: "Delete row"
273
- })
274
- })
275
- ]
276
- });
277
- }
278
- //#endregion
279
- export { b as DraggableChildrenTable };
280
-
281
- //# sourceMappingURL=DraggableChildrenTable-IfspXSFA.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"DraggableChildrenTable-IfspXSFA.js","names":[],"sources":["../src/components/detail-layout/DraggableChildrenTable.tsx"],"sourcesContent":["import { useCallback, useMemo, useRef } from \"react\";\nimport {\n DndContext,\n closestCenter,\n PointerSensor,\n useSensor,\n useSensors,\n type DragEndEvent,\n} from \"@dnd-kit/core\";\nimport {\n SortableContext,\n verticalListSortingStrategy,\n useSortable,\n} from \"@dnd-kit/sortable\";\nimport { CSS } from \"@dnd-kit/utilities\";\nimport { Btn, Icon, IconBtn } from \"@/components/primitives\";\nimport { fieldDisplayName } from \"@/types/schema\";\nimport type { Entity, Schema } from \"@/types/schema\";\nimport { renderField } from \"@/components/fields\";\nimport type { RefsMap } from \"@/components/fields\";\nimport { useUserLocale } from \"@/hooks/useUserLocale\";\nimport type { PendingChildRow } from \"./LayoutRenderer\";\nimport type { ResolvedChildConfig } from \"@/lib/child-config\";\n\ninterface DraggableChildrenTableProps {\n config: ResolvedChildConfig;\n childEntity: Entity;\n schema: Schema;\n rows: PendingChildRow[];\n onChange: (rows: PendingChildRow[]) => void;\n validationErrors?: Record<string, string[]>;\n refs?: RefsMap;\n}\n\n// DraggableChildrenTable renders child rows with drag handles for reordering.\n// Used when position_field is configured on a child relation.\nexport function DraggableChildrenTable({\n config,\n childEntity,\n schema,\n rows,\n onChange,\n validationErrors,\n refs,\n}: DraggableChildrenTableProps) {\n const tableRef = useRef<HTMLTableElement>(null);\n const positionField = config.position_field!;\n const columns = config.columns;\n\n // distance: 5 separates click from drag.\n const sensors = useSensors(\n useSensor(PointerSensor, { activationConstraint: { distance: 5 } }),\n );\n\n // Editable columns: exclude FK, auto, primary, and position_field.\n const fkSet = new Set(Array.isArray(config.foreign_key) ? config.foreign_key : [config.foreign_key]);\n const editableColumns = columns.filter((col) => {\n if (fkSet.has(col)) return false;\n if (col === positionField) return false;\n const field = childEntity.fields.get(col);\n if (!field) return false;\n if (field.auto || field.primary) return false;\n return true;\n });\n\n // Display-only columns (auto/primary but visible in column list, or position_field).\n const displayOnlyColumns = new Set(\n columns.filter((col) => {\n if (col === positionField) return true;\n const field = childEntity.fields.get(col);\n return field && (field.auto || field.primary);\n }),\n );\n\n // Visible columns: exclude position_field from display since it's managed by drag.\n const visibleColumns = columns.filter((col) => col !== positionField);\n\n // Row IDs for SortableContext - only non-deleted rows participate in drag.\n const rowIds = useMemo(\n () => rows.filter((r) => !r._deleted).map((r) => r._key),\n [rows],\n );\n\n const handleCellChange = useCallback(\n (rowKey: string, fieldName: string, value: unknown) => {\n const updated = rows.map((row) =>\n row._key === rowKey\n ? { ...row, [fieldName]: value, _dirty: true }\n : row,\n );\n onChange(updated);\n },\n [rows, onChange],\n );\n\n const handleAddRow = useCallback(() => {\n const maxPosition = rows\n .filter((r) => !r._deleted)\n .reduce((max, r) => {\n const pos = typeof r[positionField] === \"number\" ? (r[positionField] as number) : -1;\n return Math.max(max, pos);\n }, -1);\n\n const newRow: PendingChildRow = {\n _key: crypto.randomUUID(),\n _dirty: true,\n [positionField]: maxPosition + 1,\n };\n // Pre-fill from quick_add.defaults first, then field-level defaults.\n const quickDefaults = config.quick_add?.defaults ?? {};\n for (const col of editableColumns) {\n const field = childEntity.fields.get(col);\n if (!field) continue;\n if (quickDefaults[col] !== undefined) {\n newRow[col] = quickDefaults[col];\n } else if (field.default !== undefined) {\n newRow[col] = field.default;\n } else if (field.type === \"bool\") {\n newRow[col] = false;\n }\n }\n onChange([...rows, newRow]);\n }, [rows, onChange, editableColumns, childEntity, config.quick_add?.defaults, positionField]);\n\n const handleDeleteRow = useCallback(\n (rowKey: string) => {\n const updated = rows.map((row) =>\n row._key === rowKey ? { ...row, _deleted: true } : row,\n );\n onChange(updated);\n },\n [rows, onChange],\n );\n\n const handleUndoDelete = useCallback(\n (rowKey: string) => {\n const updated = rows.map((row) =>\n row._key === rowKey ? { ...row, _deleted: false } : row,\n );\n onChange(updated);\n },\n [rows, onChange],\n );\n\n const handleDragEnd = useCallback(\n (event: DragEndEvent) => {\n const { active, over } = event;\n if (!over || active.id === over.id) return;\n\n // Reorder non-deleted rows.\n const nonDeleted = rows.filter((r) => !r._deleted);\n const deleted = rows.filter((r) => r._deleted);\n\n const oldIndex = nonDeleted.findIndex((r) => r._key === String(active.id));\n const newIndex = nonDeleted.findIndex((r) => r._key === String(over.id));\n if (oldIndex === -1 || newIndex === -1) return;\n\n // Move the row.\n const reordered = [...nonDeleted];\n const [moved] = reordered.splice(oldIndex, 1);\n reordered.splice(newIndex, 0, moved);\n\n // Re-assign sequential position values and mark dirty only if position changed.\n const withPositions = reordered.map((row, index) => ({\n ...row,\n [positionField]: index,\n _dirty: row[positionField] !== index ? true : row._dirty,\n }));\n\n // Append deleted rows at the end (they'll be excluded from payload).\n onChange([...withPositions, ...deleted]);\n },\n [rows, onChange, positionField],\n );\n\n const handleKeyDown = useCallback(\n (e: React.KeyboardEvent<HTMLTableElement>) => {\n const target = e.target as HTMLElement;\n const cell = target.closest(\"td\");\n if (!cell) return;\n const row = cell.closest(\"tr\");\n if (!row) return;\n const tbody = row.closest(\"tbody\");\n if (!tbody) return;\n\n const cellIndex = Array.from(row.cells).indexOf(cell as HTMLTableCellElement);\n const rowIndex = Array.from(tbody.rows).indexOf(row as HTMLTableRowElement);\n\n if (e.key === \"Tab\") {\n const direction = e.shiftKey ? -1 : 1;\n const allRows = Array.from(tbody.rows);\n let nextRow = rowIndex;\n let nextCell = cellIndex + direction;\n\n while (nextRow >= 0 && nextRow < allRows.length) {\n if (nextCell >= 0 && nextCell < allRows[nextRow].cells.length) {\n const nextTd = allRows[nextRow].cells[nextCell];\n const input = nextTd.querySelector(\"input, select, textarea, [tabindex]\") as HTMLElement | null;\n if (input) {\n e.preventDefault();\n input.focus();\n return;\n }\n nextCell += direction;\n } else {\n nextRow += direction;\n nextCell = direction > 0 ? 0 : (allRows[nextRow]?.cells.length ?? 1) - 1;\n }\n }\n } else if (e.key === \"Enter\") {\n e.preventDefault();\n const allRows = Array.from(tbody.rows);\n if (rowIndex < allRows.length - 1) {\n const nextTd = allRows[rowIndex + 1].cells[cellIndex];\n const input = nextTd?.querySelector(\"input, select, textarea, [tabindex]\") as HTMLElement | null;\n if (input) input.focus();\n } else {\n handleAddRow();\n requestAnimationFrame(() => {\n const newRows = tbody.querySelectorAll(\"tr\");\n const lastRow = newRows[newRows.length - 1];\n if (lastRow) {\n const firstInput = lastRow.querySelector(\"input, select, textarea, [tabindex]\") as HTMLElement | null;\n if (firstInput) firstInput.focus();\n }\n });\n }\n } else if (e.key === \"Escape\") {\n (target as HTMLElement).blur?.();\n }\n },\n [handleAddRow],\n );\n\n const thStyle: React.CSSProperties = {\n height: 30,\n padding: \"0 12px\",\n textAlign: \"left\",\n fontWeight: 600,\n fontSize: 11,\n letterSpacing: \"0.04em\",\n color: \"var(--text-3)\",\n textTransform: \"uppercase\",\n borderBottom: \"1px solid var(--divider)\",\n };\n\n return (\n <div>\n <div style={{ overflowX: \"auto\" }}>\n <DndContext sensors={sensors} collisionDetection={closestCenter} onDragEnd={handleDragEnd}>\n <table\n ref={tableRef}\n style={{ width: \"100%\", fontSize: 12.5, borderCollapse: \"separate\", borderSpacing: 0 }}\n onKeyDown={handleKeyDown}\n >\n <thead>\n <tr>\n <th style={{ ...thStyle, width: 32, padding: \"0 4px\" }} />\n {visibleColumns.map((col) => {\n const field = childEntity.fields.get(col);\n return (\n <th key={col} style={thStyle}>\n {field ? fieldDisplayName(field, col, schema.entities) : col}\n </th>\n );\n })}\n <th style={{ ...thStyle, width: 40 }} />\n </tr>\n </thead>\n <SortableContext items={rowIds} strategy={verticalListSortingStrategy}>\n <tbody>\n {rows.map((row) => (\n <SortableRow\n key={row._key}\n row={row}\n columns={visibleColumns}\n editableColumns={editableColumns}\n displayOnlyColumns={displayOnlyColumns}\n childEntity={childEntity}\n validationErrors={validationErrors}\n refs={refs}\n onCellChange={handleCellChange}\n onDelete={handleDeleteRow}\n onUndoDelete={handleUndoDelete}\n />\n ))}\n </tbody>\n </SortableContext>\n </table>\n </DndContext>\n </div>\n <div style={{ marginTop: 8 }}>\n <Btn kind=\"ghost\" size=\"xs\" icon={<Icon.plus size={12} />} onClick={handleAddRow}>\n Add row\n </Btn>\n </div>\n </div>\n );\n}\n\n// SortableRow wraps a table row with drag-and-drop support.\ninterface SortableRowProps {\n row: PendingChildRow;\n columns: string[];\n editableColumns: string[];\n displayOnlyColumns: Set<string>;\n childEntity: Entity;\n validationErrors?: Record<string, string[]>;\n refs?: RefsMap;\n onCellChange: (rowKey: string, fieldName: string, value: unknown) => void;\n onDelete: (rowKey: string) => void;\n onUndoDelete: (rowKey: string) => void;\n}\n\nfunction SortableRow({\n row,\n columns,\n editableColumns,\n displayOnlyColumns,\n childEntity,\n validationErrors,\n refs,\n onCellChange,\n onDelete,\n onUndoDelete,\n}: SortableRowProps) {\n const userLocale = useUserLocale();\n const isDeleted = !!row._deleted;\n const rowErrors = validationErrors?.[row._key];\n\n const {\n attributes,\n listeners,\n setNodeRef,\n transform,\n transition,\n isDragging,\n } = useSortable({ id: row._key, disabled: isDeleted });\n\n const style = {\n transform: CSS.Translate.toString(transform),\n transition,\n zIndex: isDragging ? 10 : undefined,\n opacity: isDragging ? 0.5 : undefined,\n };\n\n const cellStyle: React.CSSProperties = {\n padding: \"6px 12px\",\n borderBottom: \"1px solid var(--divider)\",\n verticalAlign: \"middle\",\n color: \"var(--text-2)\",\n };\n const editCellStyle: React.CSSProperties = {\n padding: \"4px 4px\",\n borderBottom: \"1px solid var(--divider)\",\n verticalAlign: \"middle\",\n };\n\n return (\n <tr ref={setNodeRef} style={{ ...style, opacity: isDeleted ? 0.5 : style?.opacity ?? 1 }}>\n <td style={{ padding: \"4px 4px\", borderBottom: \"1px solid var(--divider)\", width: 32, verticalAlign: \"middle\" }}>\n {!isDeleted && (\n <button\n type=\"button\"\n style={{\n cursor: \"grab\",\n padding: 4,\n color: \"var(--text-3)\",\n background: \"transparent\",\n border: 0,\n display: \"inline-flex\",\n }}\n {...attributes}\n {...listeners}\n >\n <Icon.grid size={14} />\n </button>\n )}\n </td>\n {columns.map((col) => {\n const field = childEntity.fields.get(col);\n const hasError = rowErrors?.includes(col);\n const isDisplayOnly = displayOnlyColumns.has(col);\n const isEditable = editableColumns.includes(col);\n\n if (isDeleted || isDisplayOnly || !isEditable) {\n return (\n <td\n key={col}\n style={{\n ...cellStyle,\n textDecoration: isDeleted ? \"line-through\" : \"none\",\n }}\n >\n {field\n ? renderField({\n field,\n fieldName: col,\n value: row[col],\n mode: \"display\",\n record: row as Record<string, unknown>,\n refs,\n locale: userLocale,\n })\n : String(row[col] ?? \"\")}\n </td>\n );\n }\n\n return (\n <td\n key={col}\n style={{\n ...editCellStyle,\n outline: hasError ? \"1px solid var(--danger)\" : \"none\",\n outlineOffset: -1,\n borderRadius: hasError ? 4 : 0,\n }}\n title={hasError ? `${col} is required` : undefined}\n >\n {field\n ? renderField({\n field,\n fieldName: col,\n value: row[col],\n mode: \"edit\",\n onChange: (val) => onCellChange(row._key, col, val),\n record: row as Record<string, unknown>,\n refs,\n locale: userLocale,\n })\n : String(row[col] ?? \"\")}\n </td>\n );\n })}\n <td style={{ padding: \"4px 8px\", borderBottom: \"1px solid var(--divider)\", verticalAlign: \"middle\" }}>\n {isDeleted ? (\n <IconBtn\n size={24}\n icon={<Icon.refresh size={12} />}\n onClick={() => onUndoDelete(row._key)}\n title=\"Undo delete\"\n />\n ) : (\n <IconBtn\n size={24}\n icon={<Icon.trash size={12} />}\n onClick={() => onDelete(row._key)}\n title=\"Delete row\"\n />\n )}\n </td>\n </tr>\n );\n}\n"],"mappings":"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"}