@declarion/react 0.1.79 → 0.1.80
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/dist-lib/DraggableChildrenTable-CcXR8Vm6.js +281 -0
- package/dist-lib/DraggableChildrenTable-CcXR8Vm6.js.map +1 -0
- package/dist-lib/Grid-CseTLMLv.js +405 -0
- package/dist-lib/Grid-CseTLMLv.js.map +1 -0
- package/dist-lib/{JsonEditor-CWueGEgA.js → JsonEditor-Tew1oNqZ.js} +1 -1
- package/dist-lib/{JsonEditor-CWueGEgA.js.map → JsonEditor-Tew1oNqZ.js.map} +1 -1
- package/dist-lib/MarkdownRenderer-Dl3GDuY9.js +72 -0
- package/dist-lib/MarkdownRenderer-Dl3GDuY9.js.map +1 -0
- package/dist-lib/components/detail-layout/index.d.ts +0 -1
- package/dist-lib/components/fields/cells/factories/markdownToPlainText.d.ts +7 -14
- package/dist-lib/components/file-widgets/GridLazy.d.ts +2 -0
- package/dist-lib/components/file-widgets/index.d.ts +1 -1
- package/dist-lib/components/shared/Markdown.d.ts +3 -0
- package/dist-lib/components/shared/MarkdownRenderer.d.ts +11 -0
- package/dist-lib/declarion-react.css +1 -1
- package/dist-lib/hooks/useAllEntityData.d.ts +16 -0
- package/dist-lib/index.d.ts +1 -0
- package/dist-lib/index.js +7557 -14512
- package/dist-lib/index.js.map +1 -1
- package/dist-lib/lib/capabilityPrefetch.d.ts +6 -0
- package/dist-lib/rich-text-CaQ6-8Gx.js +48 -0
- package/dist-lib/rich-text-CaQ6-8Gx.js.map +1 -0
- package/dist-lib/stores/tabs.d.ts +1 -0
- package/dist-lib/useUserLocale-D9wc5kzQ.js +5723 -0
- package/dist-lib/useUserLocale-D9wc5kzQ.js.map +1 -0
- package/dist-lib/value-FIp50R1-.js +571 -0
- package/dist-lib/value-FIp50R1-.js.map +1 -0
- package/package.json +3 -2
|
@@ -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-D9wc5kzQ.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-CcXR8Vm6.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DraggableChildrenTable-CcXR8Vm6.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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"}
|