@declarion/react 0.1.79 → 0.1.81

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 (64) hide show
  1. package/dist-lib/DraggableChildrenTable-XKJWMb1S.js +281 -0
  2. package/dist-lib/DraggableChildrenTable-XKJWMb1S.js.map +1 -0
  3. package/dist-lib/Grid-By_Ere-W.js +405 -0
  4. package/dist-lib/Grid-By_Ere-W.js.map +1 -0
  5. package/dist-lib/{JsonEditor-CWueGEgA.js → JsonEditor-CexL5HXN.js} +17 -15
  6. package/dist-lib/JsonEditor-CexL5HXN.js.map +1 -0
  7. package/dist-lib/MarkdownRenderer-Dl3GDuY9.js +72 -0
  8. package/dist-lib/MarkdownRenderer-Dl3GDuY9.js.map +1 -0
  9. package/dist-lib/api/events.d.ts +5 -0
  10. package/dist-lib/components/detail-layout/index.d.ts +0 -1
  11. package/dist-lib/components/fields/BoolField.d.ts +1 -1
  12. package/dist-lib/components/fields/EmailField.d.ts +1 -1
  13. package/dist-lib/components/fields/EnumField.d.ts +1 -1
  14. package/dist-lib/components/fields/IntArrayField.d.ts +1 -1
  15. package/dist-lib/components/fields/JsonEditor.d.ts +2 -1
  16. package/dist-lib/components/fields/JsonField.d.ts +1 -1
  17. package/dist-lib/components/fields/MultilangField.d.ts +1 -1
  18. package/dist-lib/components/fields/MultilangTextField.d.ts +1 -1
  19. package/dist-lib/components/fields/NumberField.d.ts +1 -1
  20. package/dist-lib/components/fields/PasswordField.d.ts +1 -1
  21. package/dist-lib/components/fields/PhoneField.d.ts +1 -1
  22. package/dist-lib/components/fields/RefField.d.ts +1 -1
  23. package/dist-lib/components/fields/SecretField.d.ts +1 -1
  24. package/dist-lib/components/fields/StringArrayField.d.ts +1 -1
  25. package/dist-lib/components/fields/StringField.d.ts +1 -1
  26. package/dist-lib/components/fields/TextField.d.ts +1 -1
  27. package/dist-lib/components/fields/TimestampField.d.ts +1 -1
  28. package/dist-lib/components/fields/UrlField.d.ts +1 -1
  29. package/dist-lib/components/fields/cells/factories/markdownToPlainText.d.ts +7 -14
  30. package/dist-lib/components/fields/index.d.ts +2 -0
  31. package/dist-lib/components/file-widgets/GridLazy.d.ts +2 -0
  32. package/dist-lib/components/file-widgets/host.d.ts +2 -0
  33. package/dist-lib/components/file-widgets/index.d.ts +1 -1
  34. package/dist-lib/components/file-widgets/types.d.ts +1 -0
  35. package/dist-lib/components/pages/list/DataCell.d.ts +7 -0
  36. package/dist-lib/components/pages/list/ListBulkBar.d.ts +27 -0
  37. package/dist-lib/components/pages/list/ListHeader.d.ts +23 -0
  38. package/dist-lib/components/pages/list/RowActionsCell.d.ts +38 -0
  39. package/dist-lib/components/pages/list/SaveViewDialog.d.ts +6 -0
  40. package/dist-lib/components/pages/list/columns.d.ts +42 -0
  41. package/dist-lib/components/pages/list/filter-meta.d.ts +9 -0
  42. package/dist-lib/components/primitives/BoolToggle.d.ts +3 -1
  43. package/dist-lib/components/primitives/Fields.d.ts +12 -3
  44. package/dist-lib/components/shared/Markdown.d.ts +3 -0
  45. package/dist-lib/components/shared/MarkdownRenderer.d.ts +11 -0
  46. package/dist-lib/declarion-react.css +1 -1
  47. package/dist-lib/hooks/useAllEntityData.d.ts +16 -0
  48. package/dist-lib/index.d.ts +1 -0
  49. package/dist-lib/index.js +12549 -19381
  50. package/dist-lib/index.js.map +1 -1
  51. package/dist-lib/lib/action-dispatch.d.ts +7 -0
  52. package/dist-lib/lib/capabilityPrefetch.d.ts +6 -0
  53. package/dist-lib/rich-text-CaQ6-8Gx.js +48 -0
  54. package/dist-lib/rich-text-CaQ6-8Gx.js.map +1 -0
  55. package/dist-lib/stores/realtime.d.ts +9 -0
  56. package/dist-lib/stores/tabs.d.ts +1 -0
  57. package/dist-lib/types/schema.d.ts +11 -1
  58. package/dist-lib/useUserLocale-CSS6fwi8.js +5830 -0
  59. package/dist-lib/useUserLocale-CSS6fwi8.js.map +1 -0
  60. package/dist-lib/value-DgzPSFZM.js +524 -0
  61. package/dist-lib/value-DgzPSFZM.js.map +1 -0
  62. package/package.json +3 -2
  63. package/dist-lib/JsonEditor-CWueGEgA.js.map +0 -1
  64. package/dist-lib/components/shared/RowActionItem.d.ts +0 -11
@@ -0,0 +1,281 @@
1
+ import { Gt as e, Ut as t, Wt as n, at as r, n as i, t as a } from "./useUserLocale-CSS6fwi8.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: i, 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 = i.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 = i.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
+ }, r = t.quick_add?.defaults ?? {};
32
+ for (let e of O) {
33
+ let t = i.fields.get(e);
34
+ t && (r[e] === void 0 ? t.default === void 0 ? t.type === "bool" && (n[e] = !1) : n[e] = t.default : n[e] = r[e]);
35
+ }
36
+ y([..._, n]);
37
+ }, [
38
+ _,
39
+ y,
40
+ O,
41
+ i,
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 = i.fields.get(e);
135
+ return /* @__PURE__ */ l("th", {
136
+ style: R,
137
+ children: t ? r(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: i,
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(n, {
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: r, 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
+ r.map((e) => {
222
+ let t = c.fields.get(e), r = 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 ? i({
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: r ? "1px solid var(--danger)" : "none",
241
+ outlineOffset: -1,
242
+ borderRadius: r ? 4 : 0
243
+ },
244
+ title: r ? `${e} is required` : void 0,
245
+ children: t ? i({
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-XKJWMb1S.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DraggableChildrenTable-XKJWMb1S.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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"}