@hanzo/ui 8.0.23 → 8.0.25

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 (60) hide show
  1. package/README.md +59 -0
  2. package/dist/chunk-3NG33DV2.cjs +607 -0
  3. package/dist/chunk-3NG33DV2.cjs.map +1 -0
  4. package/dist/chunk-5CZOYONP.js +343 -0
  5. package/dist/chunk-5CZOYONP.js.map +1 -0
  6. package/dist/{chunk-P2P6ST6J.js → chunk-7ZNK6JSS.js} +9 -394
  7. package/dist/chunk-7ZNK6JSS.js.map +1 -0
  8. package/dist/chunk-GVCOAJLO.js +397 -0
  9. package/dist/chunk-GVCOAJLO.js.map +1 -0
  10. package/dist/chunk-GWNNLYX4.cjs +353 -0
  11. package/dist/chunk-GWNNLYX4.cjs.map +1 -0
  12. package/dist/{chunk-NBZDIMP3.cjs → chunk-ONVERVFG.cjs} +33 -438
  13. package/dist/chunk-ONVERVFG.cjs.map +1 -0
  14. package/dist/chunk-P2QU5MN5.js +555 -0
  15. package/dist/chunk-P2QU5MN5.js.map +1 -0
  16. package/dist/chunk-WHJR5S4L.cjs +418 -0
  17. package/dist/chunk-WHJR5S4L.cjs.map +1 -0
  18. package/dist/framework/CollectionBuilder.d.ts +12 -0
  19. package/dist/framework/CollectionsBrowser.d.ts +26 -19
  20. package/dist/framework/DocTypeRecords.d.ts +31 -11
  21. package/dist/framework/MediaGrid.d.ts +42 -0
  22. package/dist/framework/RecordCards.d.ts +35 -0
  23. package/dist/framework/builder-logic.d.ts +76 -0
  24. package/dist/framework/client.d.ts +31 -44
  25. package/dist/framework/core.cjs +213 -0
  26. package/dist/framework/core.cjs.map +1 -0
  27. package/dist/framework/core.d.ts +6 -0
  28. package/dist/framework/core.js +4 -0
  29. package/dist/framework/core.js.map +1 -0
  30. package/dist/framework/data.d.ts +2 -2
  31. package/dist/framework/fields.d.ts +47 -4
  32. package/dist/framework/index.cjs +1340 -0
  33. package/dist/framework/index.cjs.map +1 -0
  34. package/dist/framework/index.d.ts +9 -23
  35. package/dist/framework/index.js +1119 -0
  36. package/dist/framework/index.js.map +1 -0
  37. package/dist/framework/media.d.ts +53 -0
  38. package/dist/framework/parts.d.ts +74 -0
  39. package/dist/framework/responsive.d.ts +41 -0
  40. package/dist/framework/types.d.ts +13 -7
  41. package/dist/product/SelectMenu.d.ts +13 -1
  42. package/dist/product/index.cjs +2061 -336
  43. package/dist/product/index.cjs.map +1 -1
  44. package/dist/product/index.js +1909 -3
  45. package/dist/product/index.js.map +1 -1
  46. package/dist/product/social/index.cjs +17 -16
  47. package/dist/product/social/index.js +3 -2
  48. package/package.json +11 -5
  49. package/dist/chunk-2BM42AZR.cjs +0 -2301
  50. package/dist/chunk-2BM42AZR.cjs.map +0 -1
  51. package/dist/chunk-7P7R7FC5.js +0 -2231
  52. package/dist/chunk-7P7R7FC5.js.map +0 -1
  53. package/dist/chunk-NBZDIMP3.cjs.map +0 -1
  54. package/dist/chunk-P2P6ST6J.js.map +0 -1
  55. package/dist/framework/Loader.d.ts +0 -4
  56. package/dist/framework.cjs +0 -757
  57. package/dist/framework.cjs.map +0 -1
  58. package/dist/framework.d.ts +0 -1
  59. package/dist/framework.js +0 -727
  60. package/dist/framework.js.map +0 -1
@@ -0,0 +1,1340 @@
1
+ 'use client';
2
+ 'use strict';
3
+
4
+ var chunkGWNNLYX4_cjs = require('../chunk-GWNNLYX4.cjs');
5
+ var chunkWHJR5S4L_cjs = require('../chunk-WHJR5S4L.cjs');
6
+ require('../chunk-7XDEUEWI.cjs');
7
+ var chunk3NG33DV2_cjs = require('../chunk-3NG33DV2.cjs');
8
+ var react = require('react');
9
+ var gui = require('@hanzo/gui');
10
+ var lucideIcons2 = require('@hanzogui/lucide-icons-2');
11
+ var jsxRuntime = require('react/jsx-runtime');
12
+ var data = require('@hanzo/data');
13
+
14
+ var TABLE_MIN = 720;
15
+ var GRID_MIN = 560;
16
+ var TAP = 44;
17
+ function layoutFor(width, tableMin = TABLE_MIN) {
18
+ return width > 0 && width >= tableMin ? "desktop" : "phone";
19
+ }
20
+ function useContainerLayout(tableMin = TABLE_MIN) {
21
+ const [width, setWidth] = react.useState(0);
22
+ const onLayout = react.useCallback((e) => {
23
+ const w = Math.round(e?.nativeEvent?.layout?.width ?? 0);
24
+ setWidth((prev) => w > 0 && w !== prev ? w : prev);
25
+ }, []);
26
+ const layout = layoutFor(width, tableMin);
27
+ const phone = layout === "phone";
28
+ return {
29
+ layout,
30
+ phone,
31
+ wideEnoughForGrid: width >= GRID_MIN,
32
+ width,
33
+ onLayout
34
+ };
35
+ }
36
+ function Action({ children, icon, onPress, disabled, primary, danger, phone, label }) {
37
+ const Cmp = primary ? chunkWHJR5S4L_cjs.PrimaryButton : gui.Button;
38
+ return /* @__PURE__ */ jsxRuntime.jsx(
39
+ Cmp,
40
+ {
41
+ size: phone ? "$4" : "$2",
42
+ minH: phone ? TAP : void 0,
43
+ grow: phone ? 1 : 0,
44
+ flexBasis: phone ? 0 : "auto",
45
+ minW: phone ? 140 : void 0,
46
+ icon,
47
+ disabled,
48
+ onPress,
49
+ "aria-label": label,
50
+ ...danger ? { theme: "red" } : {},
51
+ children
52
+ }
53
+ );
54
+ }
55
+ function Actions({ children, phone }) {
56
+ return /* @__PURE__ */ jsxRuntime.jsx(gui.XStack, { gap: "$2", items: "center", flexWrap: "wrap", width: phone ? "100%" : void 0, children });
57
+ }
58
+ function ErrorBar({ message }) {
59
+ return /* @__PURE__ */ jsxRuntime.jsx(gui.Card, { borderWidth: 1, borderColor: "$red7", bg: "$red2", p: "$3", maxW: 620, children: /* @__PURE__ */ jsxRuntime.jsxs(gui.XStack, { gap: "$2", items: "flex-start", children: [
60
+ /* @__PURE__ */ jsxRuntime.jsx(lucideIcons2.TriangleAlert, { size: 15 }),
61
+ /* @__PURE__ */ jsxRuntime.jsx(gui.Text, { fontSize: "$3", color: "$red11", flex: 1, children: message })
62
+ ] }) });
63
+ }
64
+ function Loading({ label, size = "small" }) {
65
+ return /* @__PURE__ */ jsxRuntime.jsxs(gui.XStack, { items: "center", justify: "center", gap: "$3", py: "$8", children: [
66
+ /* @__PURE__ */ jsxRuntime.jsx(gui.Spinner, { size }),
67
+ label ? /* @__PURE__ */ jsxRuntime.jsx(gui.Text, { fontSize: "$3", color: "$color11", children: label }) : null
68
+ ] });
69
+ }
70
+ function Meta({ children }) {
71
+ return /* @__PURE__ */ jsxRuntime.jsx(gui.Text, { fontSize: "$2", color: "$color10", numberOfLines: 1, children });
72
+ }
73
+ var WRAP_ANYWHERE = { overflowWrap: "anywhere", wordBreak: "break-word" };
74
+ function Panel({ children, phone }) {
75
+ return /* @__PURE__ */ jsxRuntime.jsx(
76
+ gui.Card,
77
+ {
78
+ borderWidth: 1,
79
+ borderColor: "$borderColor",
80
+ p: phone ? "$3" : "$4",
81
+ maxW: 760,
82
+ width: "100%",
83
+ style: WRAP_ANYWHERE,
84
+ children: /* @__PURE__ */ jsxRuntime.jsx(gui.YStack, { gap: "$3", children })
85
+ }
86
+ );
87
+ }
88
+ var TYPE_OPTIONS = chunk3NG33DV2_cjs.BUILDER_FIELD_TYPES.map((t) => ({ key: t.type, label: t.label }));
89
+ function CollectionBuilder({ client, module, existing, onSaved, onCancel }) {
90
+ const editing = Boolean(existing);
91
+ const [name, setName] = react.useState(existing?.name ?? "");
92
+ const [fields, setFields] = react.useState(
93
+ () => existing ? chunk3NG33DV2_cjs.fieldsFromDocType(existing) : chunk3NG33DV2_cjs.starterFields()
94
+ );
95
+ const [busy, setBusy] = react.useState(false);
96
+ const [saveError, setSaveError] = react.useState(null);
97
+ const [showErrors, setShowErrors] = react.useState(false);
98
+ const { phone, onLayout } = useContainerLayout();
99
+ const validation = react.useMemo(() => chunk3NG33DV2_cjs.validateBuilder(name, fields), [name, fields]);
100
+ const patch = react.useCallback((key, next) => {
101
+ setFields((fs) => fs.map((f) => f.key === key ? { ...f, ...next } : f));
102
+ }, []);
103
+ const addField = react.useCallback(() => setFields((fs) => [...fs, chunk3NG33DV2_cjs.blankField()]), []);
104
+ const removeField = react.useCallback((key) => setFields((fs) => fs.filter((f) => f.key !== key)), []);
105
+ const move = react.useCallback((key, dir) => setFields((fs) => chunk3NG33DV2_cjs.moveField(fs, key, dir)), []);
106
+ const save = react.useCallback(async () => {
107
+ setShowErrors(true);
108
+ if (!validation.ok) return;
109
+ setBusy(true);
110
+ setSaveError(null);
111
+ try {
112
+ const dt = chunk3NG33DV2_cjs.toDocType(name, module, fields);
113
+ if (editing) await client.doctypes.update(name, dt);
114
+ else await client.doctypes.create(dt);
115
+ onSaved(name);
116
+ } catch (e) {
117
+ setSaveError(chunkWHJR5S4L_cjs.classifyBackend(e).message);
118
+ } finally {
119
+ setBusy(false);
120
+ }
121
+ }, [client, editing, fields, module, name, onSaved, validation.ok]);
122
+ const iconBtn = (icon, label, onPress, disabled, danger) => /* @__PURE__ */ jsxRuntime.jsx(
123
+ gui.Button,
124
+ {
125
+ size: phone ? "$3" : "$1",
126
+ circular: true,
127
+ minW: phone ? TAP : void 0,
128
+ minH: phone ? TAP : void 0,
129
+ "aria-label": label,
130
+ icon,
131
+ disabled,
132
+ onPress,
133
+ ...danger ? { theme: "red" } : {}
134
+ }
135
+ );
136
+ return /* @__PURE__ */ jsxRuntime.jsxs(gui.Card, { onLayout, borderWidth: 1, borderColor: "$borderColor", p: phone ? "$3" : "$4", gap: "$4", maxW: 820, width: "100%", children: [
137
+ /* @__PURE__ */ jsxRuntime.jsxs(gui.YStack, { gap: "$2", children: [
138
+ /* @__PURE__ */ jsxRuntime.jsx(gui.Text, { fontSize: "$5", fontWeight: "800", children: editing ? `Edit ${name}` : "New collection" }),
139
+ /* @__PURE__ */ jsxRuntime.jsx(gui.Text, { fontSize: "$2", color: "$color10", children: "A content type on the Hanzo Framework \u2014 name it and define its fields. Every field type is available; a rich-text field gives a full WYSIWYG body." })
140
+ ] }),
141
+ /* @__PURE__ */ jsxRuntime.jsxs(gui.YStack, { gap: "$1.5", width: "100%", children: [
142
+ /* @__PURE__ */ jsxRuntime.jsx(gui.Text, { fontSize: "$1", color: "$color11", textTransform: "uppercase", letterSpacing: 0.4, children: "Collection" }),
143
+ /* @__PURE__ */ jsxRuntime.jsx(
144
+ gui.Input,
145
+ {
146
+ width: "100%",
147
+ minH: phone ? TAP : void 0,
148
+ size: phone ? "$4" : "$3",
149
+ placeholder: "e.g. Recipe or LandingPage",
150
+ value: name,
151
+ onChangeText: setName,
152
+ disabled: busy || editing,
153
+ autoCapitalize: "none"
154
+ }
155
+ ),
156
+ editing ? /* @__PURE__ */ jsxRuntime.jsx(gui.Text, { fontSize: "$1", color: "$color9", children: "A collection\u2019s name is its identity and can\u2019t change." }) : null
157
+ ] }),
158
+ /* @__PURE__ */ jsxRuntime.jsxs(gui.YStack, { gap: "$2", width: "100%", children: [
159
+ /* @__PURE__ */ jsxRuntime.jsxs(gui.XStack, { items: "center", justify: "space-between", children: [
160
+ /* @__PURE__ */ jsxRuntime.jsx(gui.Text, { fontSize: "$3", fontWeight: "700", color: "$color11", children: "Fields" }),
161
+ /* @__PURE__ */ jsxRuntime.jsxs(gui.Text, { fontSize: "$1", color: "$color9", children: [
162
+ fields.length,
163
+ " field",
164
+ fields.length === 1 ? "" : "s"
165
+ ] })
166
+ ] }),
167
+ /* @__PURE__ */ jsxRuntime.jsx(gui.YStack, { gap: "$2", width: "100%", children: fields.map((f, i) => {
168
+ const err = showErrors ? validation.fieldErrors[f.key] : void 0;
169
+ const fname = f.label.trim() ? chunk3NG33DV2_cjs.fieldNameFromLabel(f.label) : "";
170
+ return /* @__PURE__ */ jsxRuntime.jsxs(
171
+ gui.YStack,
172
+ {
173
+ borderWidth: 1,
174
+ borderColor: err ? "$red7" : "$borderColor",
175
+ rounded: "$4",
176
+ p: "$3",
177
+ gap: "$2",
178
+ bg: "$color1",
179
+ width: "100%",
180
+ children: [
181
+ /* @__PURE__ */ jsxRuntime.jsxs(gui.XStack, { gap: "$2", items: "center", width: "100%", children: [
182
+ phone ? null : /* @__PURE__ */ jsxRuntime.jsx(lucideIcons2.GripVertical, { size: 15, opacity: 0.5 }),
183
+ /* @__PURE__ */ jsxRuntime.jsx(
184
+ gui.Input,
185
+ {
186
+ flex: 1,
187
+ minW: 0,
188
+ minH: phone ? TAP : void 0,
189
+ size: phone ? "$4" : "$3",
190
+ placeholder: "Field name (e.g. Title)",
191
+ value: f.label,
192
+ onChangeText: (v) => patch(f.key, { label: v }),
193
+ disabled: busy,
194
+ autoCapitalize: "none"
195
+ }
196
+ ),
197
+ phone ? null : /* @__PURE__ */ jsxRuntime.jsx(gui.YStack, { minW: 150, children: /* @__PURE__ */ jsxRuntime.jsx(
198
+ chunkGWNNLYX4_cjs.SelectMenu,
199
+ {
200
+ required: true,
201
+ ariaLabel: "Field type",
202
+ options: TYPE_OPTIONS,
203
+ value: f.type,
204
+ onChange: (v) => v && patch(f.key, { type: v }),
205
+ disabled: busy,
206
+ minWidth: 150
207
+ }
208
+ ) })
209
+ ] }),
210
+ phone ? /* @__PURE__ */ jsxRuntime.jsx(gui.YStack, { width: "100%", children: /* @__PURE__ */ jsxRuntime.jsx(
211
+ chunkGWNNLYX4_cjs.SelectMenu,
212
+ {
213
+ required: true,
214
+ ariaLabel: "Field type",
215
+ options: TYPE_OPTIONS,
216
+ value: f.type,
217
+ onChange: (v) => v && patch(f.key, { type: v }),
218
+ disabled: busy,
219
+ minWidth: 0,
220
+ minHeight: TAP
221
+ }
222
+ ) }) : null,
223
+ /* @__PURE__ */ jsxRuntime.jsxs(gui.XStack, { gap: "$4", items: "center", justify: "space-between", flexWrap: "wrap", width: "100%", children: [
224
+ /* @__PURE__ */ jsxRuntime.jsxs(gui.XStack, { gap: "$4", items: "center", children: [
225
+ /* @__PURE__ */ jsxRuntime.jsxs(gui.XStack, { gap: "$2", items: "center", minH: phone ? TAP : void 0, children: [
226
+ /* @__PURE__ */ jsxRuntime.jsx(chunkWHJR5S4L_cjs.FieldSwitch, { checked: f.required, onChange: (v) => patch(f.key, { required: v }), disabled: busy }),
227
+ /* @__PURE__ */ jsxRuntime.jsx(gui.Text, { fontSize: "$2", color: "$color10", children: "Required" })
228
+ ] }),
229
+ /* @__PURE__ */ jsxRuntime.jsxs(gui.XStack, { gap: "$2", items: "center", minH: phone ? TAP : void 0, children: [
230
+ /* @__PURE__ */ jsxRuntime.jsx(chunkWHJR5S4L_cjs.FieldSwitch, { checked: f.inListView, onChange: (v) => patch(f.key, { inListView: v }), disabled: busy }),
231
+ /* @__PURE__ */ jsxRuntime.jsx(gui.Text, { fontSize: "$2", color: "$color10", children: "In list" })
232
+ ] })
233
+ ] }),
234
+ /* @__PURE__ */ jsxRuntime.jsxs(gui.XStack, { gap: "$2", children: [
235
+ iconBtn(/* @__PURE__ */ jsxRuntime.jsx(lucideIcons2.ArrowUp, { size: 14 }), "Move field up", () => move(f.key, -1), busy || i === 0),
236
+ iconBtn(/* @__PURE__ */ jsxRuntime.jsx(lucideIcons2.ArrowDown, { size: 14 }), "Move field down", () => move(f.key, 1), busy || i === fields.length - 1),
237
+ iconBtn(/* @__PURE__ */ jsxRuntime.jsx(lucideIcons2.Trash2, { size: 14 }), "Remove field", () => removeField(f.key), busy, true)
238
+ ] })
239
+ ] }),
240
+ chunk3NG33DV2_cjs.fieldNeedsOptions(f.type) ? /* @__PURE__ */ jsxRuntime.jsxs(gui.YStack, { gap: "$1.5", width: "100%", children: [
241
+ /* @__PURE__ */ jsxRuntime.jsx(gui.Text, { fontSize: "$1", color: "$color10", textTransform: "uppercase", letterSpacing: 0.4, children: f.type === "Select" ? "Options" : f.type === "Link" ? "Relates to" : "Child type" }),
242
+ /* @__PURE__ */ jsxRuntime.jsx(
243
+ gui.Input,
244
+ {
245
+ width: "100%",
246
+ minH: phone ? TAP : void 0,
247
+ size: phone ? "$4" : "$2",
248
+ placeholder: f.type === "Select" ? "One per line \u2014 Draft / Published" : "Collection name (e.g. Author)",
249
+ value: f.options,
250
+ onChangeText: (v) => patch(f.key, { options: v }),
251
+ multiline: f.type === "Select",
252
+ numberOfLines: f.type === "Select" ? 3 : 1,
253
+ disabled: busy,
254
+ autoCapitalize: "none"
255
+ }
256
+ )
257
+ ] }) : null,
258
+ /* @__PURE__ */ jsxRuntime.jsxs(gui.XStack, { items: "center", justify: "space-between", gap: "$2", flexWrap: "wrap", children: [
259
+ fname ? /* @__PURE__ */ jsxRuntime.jsxs(gui.Text, { fontSize: "$1", color: "$color8", children: [
260
+ "field: ",
261
+ fname
262
+ ] }) : /* @__PURE__ */ jsxRuntime.jsx(gui.YStack, {}),
263
+ err ? /* @__PURE__ */ jsxRuntime.jsxs(gui.XStack, { gap: "$1", items: "center", children: [
264
+ /* @__PURE__ */ jsxRuntime.jsx(lucideIcons2.TriangleAlert, { size: 12 }),
265
+ /* @__PURE__ */ jsxRuntime.jsx(gui.Text, { fontSize: "$1", color: "$red11", children: err })
266
+ ] }) : null
267
+ ] })
268
+ ]
269
+ },
270
+ f.key
271
+ );
272
+ }) }),
273
+ /* @__PURE__ */ jsxRuntime.jsx(gui.XStack, { width: phone ? "100%" : void 0, children: /* @__PURE__ */ jsxRuntime.jsx(Action, { phone, icon: /* @__PURE__ */ jsxRuntime.jsx(lucideIcons2.Plus, { size: 14 }), onPress: addField, disabled: busy, children: "Add field" }) })
274
+ ] }),
275
+ showErrors && validation.formError ? /* @__PURE__ */ jsxRuntime.jsx(ErrorBar, { message: validation.formError }) : null,
276
+ saveError ? /* @__PURE__ */ jsxRuntime.jsx(ErrorBar, { message: saveError }) : null,
277
+ /* @__PURE__ */ jsxRuntime.jsxs(Actions, { phone, children: [
278
+ /* @__PURE__ */ jsxRuntime.jsx(Action, { phone, disabled: busy, onPress: onCancel, children: "Cancel" }),
279
+ /* @__PURE__ */ jsxRuntime.jsx(Action, { phone, primary: true, disabled: busy, onPress: save, children: busy ? "Saving\u2026" : editing ? "Save collection" : "Create collection" })
280
+ ] })
281
+ ] });
282
+ }
283
+ function CollectionsBrowser({
284
+ client,
285
+ module,
286
+ label,
287
+ subtitle,
288
+ onOpen,
289
+ setupDescription,
290
+ setupBullets,
291
+ renderBuilder,
292
+ icon = lucideIcons2.Boxes
293
+ }) {
294
+ const [state, setState] = react.useState({ phase: "loading" });
295
+ const [busy, setBusy] = react.useState(false);
296
+ const [creating, setCreating] = react.useState(false);
297
+ const [actionError, setActionError] = react.useState(null);
298
+ const { phone, onLayout } = useContainerLayout();
299
+ const load = react.useCallback(
300
+ async (signal) => {
301
+ setState({ phase: "loading" });
302
+ try {
303
+ const [dts, mod] = await Promise.all([
304
+ client.doctypes.list(),
305
+ client.modules.get(module).catch(() => null)
306
+ // lane may not be registered on an older engine
307
+ ]);
308
+ if (signal.cancelled) return;
309
+ setState({
310
+ phase: "ready",
311
+ collections: chunk3NG33DV2_cjs.moduleDoctypes(dts, module),
312
+ registered: Boolean(mod && mod.doctypes.length)
313
+ });
314
+ } catch (e) {
315
+ if (!signal.cancelled) setState({ phase: "error", error: chunkWHJR5S4L_cjs.classifyBackend(e) });
316
+ }
317
+ },
318
+ [client, module]
319
+ );
320
+ react.useEffect(() => {
321
+ const signal = { cancelled: false };
322
+ void load(signal);
323
+ return () => {
324
+ signal.cancelled = true;
325
+ };
326
+ }, [load]);
327
+ const reload = react.useCallback(() => void load({ cancelled: false }), [load]);
328
+ const install = react.useCallback(async () => {
329
+ setBusy(true);
330
+ setActionError(null);
331
+ try {
332
+ await client.modules.install(module);
333
+ reload();
334
+ } catch (e) {
335
+ setActionError(chunkWHJR5S4L_cjs.classifyBackend(e).message);
336
+ } finally {
337
+ setBusy(false);
338
+ }
339
+ }, [client, module, reload]);
340
+ if (state.phase === "loading") {
341
+ return /* @__PURE__ */ jsxRuntime.jsx(gui.YStack, { onLayout, width: "100%", children: /* @__PURE__ */ jsxRuntime.jsx(Loading, { label: `Loading ${label}\u2026` }) });
342
+ }
343
+ if (state.phase === "error") {
344
+ return /* @__PURE__ */ jsxRuntime.jsxs(gui.YStack, { onLayout, gap: "$3", width: "100%", children: [
345
+ /* @__PURE__ */ jsxRuntime.jsx(chunkWHJR5S4L_cjs.PageHeader, { title: label, subtitle }),
346
+ /* @__PURE__ */ jsxRuntime.jsx(chunkWHJR5S4L_cjs.BackendStateCard, { state: state.error, onRetry: reload, hint: "framework \xB7 GET /v1/framework/doctypes" })
347
+ ] });
348
+ }
349
+ const { collections } = state;
350
+ return /* @__PURE__ */ jsxRuntime.jsxs(gui.YStack, { onLayout, gap: "$3", width: "100%", children: [
351
+ /* @__PURE__ */ jsxRuntime.jsx(
352
+ chunkWHJR5S4L_cjs.PageHeader,
353
+ {
354
+ title: label,
355
+ subtitle,
356
+ actions: collections.length && !creating ? /* @__PURE__ */ jsxRuntime.jsx(
357
+ Action,
358
+ {
359
+ phone,
360
+ primary: true,
361
+ icon: /* @__PURE__ */ jsxRuntime.jsx(lucideIcons2.Plus, { size: 15 }),
362
+ onPress: () => {
363
+ setCreating(true);
364
+ setActionError(null);
365
+ },
366
+ children: "New collection"
367
+ }
368
+ ) : void 0
369
+ }
370
+ ),
371
+ actionError ? /* @__PURE__ */ jsxRuntime.jsx(ErrorBar, { message: actionError }) : null,
372
+ creating ? (renderBuilder ?? ((p) => /* @__PURE__ */ jsxRuntime.jsx(CollectionBuilder, { client, module, ...p })))({
373
+ onSaved: (name) => {
374
+ setCreating(false);
375
+ onOpen(name);
376
+ },
377
+ onCancel: () => setCreating(false)
378
+ }) : null,
379
+ collections.length === 0 && !creating ? /* @__PURE__ */ jsxRuntime.jsx(
380
+ chunkWHJR5S4L_cjs.EmptyState,
381
+ {
382
+ icon,
383
+ title: `Set up ${label}`,
384
+ description: setupDescription ?? `${label} is a set of collections on the Hanzo Framework \u2014 typed documents, per organization.`,
385
+ bullets: setupBullets ?? [
386
+ `Installs the default ${label} collections into your organization`,
387
+ "Every record is a document on the framework \u2014 versioned, permissioned, per-org",
388
+ "Add your own collections and fields any time"
389
+ ],
390
+ primary: state.registered ? { label: busy ? "Setting up\u2026" : `Set up ${label}`, onPress: install } : void 0,
391
+ secondary: { label: "New collection", onPress: () => setCreating(true) }
392
+ }
393
+ ) : !creating ? (
394
+ // A fixed 240px card is a 240px column on a 390px phone with dead space
395
+ // beside it. `flexBasis` + `flexGrow` makes each card fill the row on a
396
+ // phone and settle back to a 240px tile once the box can hold several.
397
+ /* @__PURE__ */ jsxRuntime.jsx(gui.XStack, { gap: "$3", flexWrap: "wrap", width: "100%", children: collections.map((dt) => /* @__PURE__ */ jsxRuntime.jsxs(
398
+ gui.YStack,
399
+ {
400
+ onPress: () => onOpen(dt.name),
401
+ hoverStyle: { borderColor: "$color8" },
402
+ pressStyle: { bg: "$color3" },
403
+ cursor: "pointer",
404
+ borderWidth: 1,
405
+ borderColor: "$borderColor",
406
+ rounded: "$4",
407
+ p: "$4",
408
+ gap: "$2",
409
+ minH: 88,
410
+ grow: phone ? 1 : 0,
411
+ flexBasis: phone ? "100%" : 240,
412
+ maxW: phone ? void 0 : 240,
413
+ children: [
414
+ /* @__PURE__ */ jsxRuntime.jsxs(gui.XStack, { gap: "$2", items: "center", children: [
415
+ /* @__PURE__ */ jsxRuntime.jsx(lucideIcons2.Boxes, { size: 16 }),
416
+ /* @__PURE__ */ jsxRuntime.jsx(gui.Text, { fontSize: "$4", fontWeight: "700", flex: 1, minW: 0, numberOfLines: 1, children: dt.name })
417
+ ] }),
418
+ /* @__PURE__ */ jsxRuntime.jsxs(Meta, { children: [
419
+ dt.fields?.length ?? 0,
420
+ " field",
421
+ (dt.fields?.length ?? 0) === 1 ? "" : "s",
422
+ dt.isSubmittable ? " \xB7 submittable" : ""
423
+ ] })
424
+ ]
425
+ },
426
+ dt.name
427
+ )) })
428
+ ) : null
429
+ ] });
430
+ }
431
+ function MediaGrid({
432
+ client,
433
+ dt,
434
+ docs,
435
+ media,
436
+ onOpen,
437
+ onChanged,
438
+ toolbarExtra,
439
+ accept = "image/*,application/pdf,video/*,audio/*"
440
+ }) {
441
+ const fileField = chunk3NG33DV2_cjs.mediaFileField(dt);
442
+ const inputRef = react.useRef(null);
443
+ const [busy, setBusy] = react.useState(false);
444
+ const [progress, setProgress] = react.useState(null);
445
+ const [error, setError] = react.useState(null);
446
+ const { phone, onLayout } = useContainerLayout();
447
+ const upload = react.useCallback(
448
+ async (files) => {
449
+ const list = Array.from(files);
450
+ if (list.length === 0) return;
451
+ setBusy(true);
452
+ setError(null);
453
+ setProgress({ done: 0, total: list.length });
454
+ try {
455
+ for (let i = 0; i < list.length; i += 1) {
456
+ const facts = await media.upload(list[i]);
457
+ await client.records.create(dt.name, chunk3NG33DV2_cjs.mediaDocPayload(dt, facts));
458
+ setProgress({ done: i + 1, total: list.length });
459
+ }
460
+ onChanged();
461
+ } catch (e) {
462
+ setError(chunkWHJR5S4L_cjs.classifyBackend(e).message);
463
+ } finally {
464
+ setBusy(false);
465
+ setProgress(null);
466
+ }
467
+ },
468
+ [client, dt, media, onChanged]
469
+ );
470
+ const pick = () => inputRef.current?.click();
471
+ const onInput = (e) => {
472
+ if (e.target.files) void upload(e.target.files);
473
+ e.target.value = "";
474
+ };
475
+ const HiddenInput = /* @__PURE__ */ jsxRuntime.jsx("input", { ref: inputRef, type: "file", multiple: true, accept, style: { display: "none" }, onChange: onInput });
476
+ const uploadLabel = busy ? progress ? `Uploading ${progress.done}/${progress.total}\u2026` : "Uploading\u2026" : "Upload";
477
+ if (docs.length === 0) {
478
+ return /* @__PURE__ */ jsxRuntime.jsxs(gui.YStack, { onLayout, gap: "$3", width: "100%", children: [
479
+ HiddenInput,
480
+ toolbarExtra ? /* @__PURE__ */ jsxRuntime.jsx(gui.XStack, { justify: phone ? "flex-start" : "flex-end", gap: "$2", width: "100%", children: toolbarExtra }) : null,
481
+ error ? /* @__PURE__ */ jsxRuntime.jsx(ErrorBar, { message: error }) : null,
482
+ /* @__PURE__ */ jsxRuntime.jsx(DropZone, { busy, onDrop: upload, children: /* @__PURE__ */ jsxRuntime.jsx(
483
+ chunkWHJR5S4L_cjs.EmptyState,
484
+ {
485
+ icon: lucideIcons2.Image,
486
+ title: "No media yet",
487
+ description: "Drag files here, or upload \u2014 images and files go to your organization's object storage and become reusable media you can attach to any record.",
488
+ primary: { label: uploadLabel, onPress: pick }
489
+ }
490
+ ) })
491
+ ] });
492
+ }
493
+ return /* @__PURE__ */ jsxRuntime.jsxs(gui.YStack, { onLayout, gap: "$3", width: "100%", children: [
494
+ HiddenInput,
495
+ /* @__PURE__ */ jsxRuntime.jsxs(gui.XStack, { gap: "$2", items: "center", flexWrap: "wrap", justify: phone ? "flex-start" : "flex-end", width: "100%", children: [
496
+ toolbarExtra,
497
+ /* @__PURE__ */ jsxRuntime.jsx(Action, { phone, primary: true, icon: /* @__PURE__ */ jsxRuntime.jsx(lucideIcons2.Upload, { size: 15 }), disabled: busy, onPress: pick, children: uploadLabel })
498
+ ] }),
499
+ error ? /* @__PURE__ */ jsxRuntime.jsx(ErrorBar, { message: error }) : null,
500
+ /* @__PURE__ */ jsxRuntime.jsx(DropZone, { busy, onDrop: upload, children: /* @__PURE__ */ jsxRuntime.jsx(gui.XStack, { gap: "$3", flexWrap: "wrap", width: "100%", children: docs.map((d) => /* @__PURE__ */ jsxRuntime.jsx(
501
+ MediaCard,
502
+ {
503
+ doc: d,
504
+ dt,
505
+ fileField,
506
+ media,
507
+ phone,
508
+ onOpen: () => onOpen(String(d.name)),
509
+ onDelete: async () => {
510
+ setBusy(true);
511
+ setError(null);
512
+ try {
513
+ await media.remove(d[fileField]);
514
+ await client.records.remove(dt.name, String(d.name));
515
+ onChanged();
516
+ } catch (e) {
517
+ setError(chunkWHJR5S4L_cjs.classifyBackend(e).message);
518
+ } finally {
519
+ setBusy(false);
520
+ }
521
+ },
522
+ disabled: busy
523
+ },
524
+ String(d.name)
525
+ )) }) })
526
+ ] });
527
+ }
528
+ function MediaCard({
529
+ doc,
530
+ dt,
531
+ fileField,
532
+ media,
533
+ phone,
534
+ onOpen,
535
+ onDelete,
536
+ disabled
537
+ }) {
538
+ const [url, setUrl] = react.useState("");
539
+ const [confirming, setConfirming] = react.useState(false);
540
+ const raw = String(doc[fileField] ?? "");
541
+ const title = chunk3NG33DV2_cjs.titleOf(doc, dt);
542
+ react.useEffect(() => {
543
+ let cancelled = false;
544
+ void media.resolveUrl(raw).then((u) => {
545
+ if (!cancelled) setUrl(u);
546
+ });
547
+ return () => {
548
+ cancelled = true;
549
+ };
550
+ }, [raw, media]);
551
+ return /* @__PURE__ */ jsxRuntime.jsxs(
552
+ gui.YStack,
553
+ {
554
+ borderWidth: 1,
555
+ borderColor: "$borderColor",
556
+ rounded: "$4",
557
+ grow: 0,
558
+ flexBasis: phone ? "47%" : 200,
559
+ maxW: phone ? void 0 : 200,
560
+ minW: 140,
561
+ overflow: "hidden",
562
+ hoverStyle: { borderColor: "$color8" },
563
+ children: [
564
+ /* @__PURE__ */ jsxRuntime.jsx(
565
+ gui.YStack,
566
+ {
567
+ height: phone ? 110 : 130,
568
+ bg: "$color3",
569
+ items: "center",
570
+ justify: "center",
571
+ overflow: "hidden",
572
+ cursor: "pointer",
573
+ pressStyle: { opacity: 0.8 },
574
+ onPress: onOpen,
575
+ children: url && (chunk3NG33DV2_cjs.looksLikeImage(raw) || chunk3NG33DV2_cjs.looksLikeImage(url)) ? (
576
+ // eslint-disable-next-line @next/next/no-img-element
577
+ /* @__PURE__ */ jsxRuntime.jsx("img", { src: url, alt: String(doc.alt ?? title), style: { width: "100%", height: "100%", objectFit: "cover" } })
578
+ ) : /* @__PURE__ */ jsxRuntime.jsx(lucideIcons2.Image, { size: 28 })
579
+ }
580
+ ),
581
+ /* @__PURE__ */ jsxRuntime.jsxs(gui.YStack, { p: "$3", gap: "$1", children: [
582
+ /* @__PURE__ */ jsxRuntime.jsx(gui.Text, { fontSize: "$3", fontWeight: "700", numberOfLines: 1, children: title }),
583
+ /* @__PURE__ */ jsxRuntime.jsxs(gui.XStack, { justify: "space-between", items: "center", gap: "$2", children: [
584
+ /* @__PURE__ */ jsxRuntime.jsx(Meta, { children: String(doc.mime ?? "file") }),
585
+ confirming ? /* @__PURE__ */ jsxRuntime.jsxs(gui.XStack, { gap: "$1", children: [
586
+ /* @__PURE__ */ jsxRuntime.jsx(
587
+ gui.Button,
588
+ {
589
+ size: phone ? "$3" : "$1",
590
+ minH: phone ? TAP : void 0,
591
+ theme: "red",
592
+ disabled,
593
+ onPress: () => {
594
+ setConfirming(false);
595
+ void onDelete();
596
+ },
597
+ children: "Delete"
598
+ }
599
+ ),
600
+ /* @__PURE__ */ jsxRuntime.jsx(gui.Button, { size: phone ? "$3" : "$1", minH: phone ? TAP : void 0, disabled, onPress: () => setConfirming(false), children: "No" })
601
+ ] }) : /* @__PURE__ */ jsxRuntime.jsx(
602
+ gui.Button,
603
+ {
604
+ size: phone ? "$3" : "$1",
605
+ circular: true,
606
+ chromeless: true,
607
+ minW: phone ? TAP : void 0,
608
+ minH: phone ? TAP : void 0,
609
+ "aria-label": `Delete ${title}`,
610
+ icon: /* @__PURE__ */ jsxRuntime.jsx(lucideIcons2.Trash2, { size: phone ? 16 : 13 }),
611
+ disabled,
612
+ onPress: () => setConfirming(true)
613
+ }
614
+ )
615
+ ] })
616
+ ] })
617
+ ]
618
+ }
619
+ );
620
+ }
621
+ function DropZone({
622
+ children,
623
+ busy,
624
+ onDrop
625
+ }) {
626
+ const [over, setOver] = react.useState(false);
627
+ return /* @__PURE__ */ jsxRuntime.jsx(
628
+ gui.YStack,
629
+ {
630
+ width: "100%",
631
+ onDragOver: (e) => {
632
+ e.preventDefault();
633
+ if (!busy) setOver(true);
634
+ },
635
+ onDragLeave: () => setOver(false),
636
+ onDrop: (e) => {
637
+ e.preventDefault();
638
+ setOver(false);
639
+ if (!busy && e.dataTransfer?.files?.length) void onDrop(e.dataTransfer.files);
640
+ },
641
+ rounded: "$4",
642
+ p: over ? "$3" : 0,
643
+ borderWidth: over ? 2 : 0,
644
+ borderColor: "$color8",
645
+ style: { borderStyle: "dashed" },
646
+ children
647
+ }
648
+ );
649
+ }
650
+ function headline(record, titleField) {
651
+ const t = titleField ? record[titleField] : void 0;
652
+ if (typeof t === "string" && t.trim()) return t;
653
+ if (typeof t === "number") return String(t);
654
+ const name = record.name ?? record.id;
655
+ return typeof name === "string" && name ? name : "Untitled";
656
+ }
657
+ function RecordCards({
658
+ titleField,
659
+ fields,
660
+ cardFields: cardFields2,
661
+ records,
662
+ loading,
663
+ empty,
664
+ onOpen,
665
+ onCreate,
666
+ createLabel = "New record",
667
+ toolbarExtra
668
+ }) {
669
+ const [query, setQuery] = react.useState("");
670
+ const visible = react.useMemo(() => data.searchRecords(records, query, fields), [records, query, fields]);
671
+ return /* @__PURE__ */ jsxRuntime.jsxs(gui.YStack, { testID: "doctype-cards", gap: "$3", width: "100%", children: [
672
+ /* @__PURE__ */ jsxRuntime.jsxs(gui.YStack, { gap: "$2", width: "100%", children: [
673
+ /* @__PURE__ */ jsxRuntime.jsxs(
674
+ gui.XStack,
675
+ {
676
+ items: "center",
677
+ gap: "$2",
678
+ px: "$3",
679
+ minH: 44,
680
+ rounded: "$3",
681
+ borderWidth: 1,
682
+ borderColor: "$borderColor",
683
+ width: "100%",
684
+ children: [
685
+ /* @__PURE__ */ jsxRuntime.jsx(lucideIcons2.Search, { size: 15, opacity: 0.6 }),
686
+ /* @__PURE__ */ jsxRuntime.jsx(
687
+ gui.Input,
688
+ {
689
+ unstyled: true,
690
+ flex: 1,
691
+ minW: 0,
692
+ height: 42,
693
+ fontSize: "$3",
694
+ color: "$color12",
695
+ placeholder: "Search",
696
+ value: query,
697
+ onChangeText: setQuery,
698
+ autoCapitalize: "none"
699
+ }
700
+ )
701
+ ]
702
+ }
703
+ ),
704
+ /* @__PURE__ */ jsxRuntime.jsxs(gui.XStack, { gap: "$2", items: "center", flexWrap: "wrap", width: "100%", children: [
705
+ onCreate ? /* @__PURE__ */ jsxRuntime.jsx(Action, { phone: true, primary: true, onPress: onCreate, children: createLabel }) : null,
706
+ toolbarExtra
707
+ ] })
708
+ ] }),
709
+ loading ? /* @__PURE__ */ jsxRuntime.jsx(Loading, { label: "Loading records\u2026" }) : null,
710
+ !loading && visible.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(gui.Card, { borderWidth: 1, borderColor: "$borderColor", p: "$4", width: "100%", children: /* @__PURE__ */ jsxRuntime.jsx(gui.Text, { fontSize: "$3", color: "$color10", children: query ? `No records match \u201C${query}\u201D.` : empty ?? "No records yet." }) }) : null,
711
+ /* @__PURE__ */ jsxRuntime.jsx(gui.YStack, { gap: "$2", width: "100%", children: visible.map((rec, i) => {
712
+ const key = String(rec.name ?? rec.id ?? i);
713
+ return /* @__PURE__ */ jsxRuntime.jsx(
714
+ gui.Card,
715
+ {
716
+ borderWidth: 1,
717
+ borderColor: "$borderColor",
718
+ rounded: "$3",
719
+ p: "$3",
720
+ width: "100%",
721
+ cursor: onOpen ? "pointer" : void 0,
722
+ pressStyle: onOpen ? { bg: "$color3" } : void 0,
723
+ hoverStyle: onOpen ? { borderColor: "$color8" } : void 0,
724
+ onPress: onOpen ? () => onOpen(rec) : void 0,
725
+ style: WRAP_ANYWHERE,
726
+ children: /* @__PURE__ */ jsxRuntime.jsxs(gui.YStack, { gap: "$2", width: "100%", children: [
727
+ /* @__PURE__ */ jsxRuntime.jsxs(gui.XStack, { items: "center", gap: "$2", width: "100%", children: [
728
+ /* @__PURE__ */ jsxRuntime.jsx(gui.Text, { fontSize: "$4", fontWeight: "700", flex: 1, minW: 0, numberOfLines: 2, children: headline(rec, titleField) }),
729
+ onOpen ? /* @__PURE__ */ jsxRuntime.jsx(lucideIcons2.ChevronRight, { size: 16, opacity: 0.5 }) : null
730
+ ] }),
731
+ cardFields2.map((f) => (
732
+ // Label above value: a two-column row forces the value into a
733
+ // sliver at 390px. Stacked, every field type gets the full width.
734
+ /* @__PURE__ */ jsxRuntime.jsxs(gui.YStack, { gap: "$0.5", width: "100%", children: [
735
+ /* @__PURE__ */ jsxRuntime.jsx(gui.Text, { fontSize: "$1", color: "$color10", textTransform: "uppercase", letterSpacing: 0.4, children: f.label }),
736
+ /* @__PURE__ */ jsxRuntime.jsx(gui.XStack, { width: "100%", flexWrap: "wrap", children: /* @__PURE__ */ jsxRuntime.jsx(data.FieldDisplay, { field: f, value: rec[f.name] }) })
737
+ ] }, f.name)
738
+ ))
739
+ ] })
740
+ },
741
+ key
742
+ );
743
+ }) }),
744
+ visible.length ? /* @__PURE__ */ jsxRuntime.jsxs(Meta, { children: [
745
+ visible.length,
746
+ " of ",
747
+ records.length,
748
+ " record",
749
+ records.length === 1 ? "" : "s"
750
+ ] }) : null
751
+ ] });
752
+ }
753
+ function DocTypeRecords({
754
+ client,
755
+ doctype,
756
+ onOpen,
757
+ onCreate,
758
+ project,
759
+ title,
760
+ media,
761
+ renderMedia,
762
+ limit = 200
763
+ }) {
764
+ const [state, setState] = react.useState({ phase: "loading" });
765
+ const [mutationError, setMutationError] = react.useState(null);
766
+ const { phone, onLayout } = useContainerLayout();
767
+ const load = react.useCallback(
768
+ async (signal) => {
769
+ setState({ phase: "loading" });
770
+ try {
771
+ const dt = await client.doctypes.get(doctype);
772
+ const linkOptions = await chunk3NG33DV2_cjs.loadLinkOptions(client, dt);
773
+ const filters = project && chunk3NG33DV2_cjs.hasProjectField(dt) ? { [chunk3NG33DV2_cjs.PROJECT_FIELD]: project } : void 0;
774
+ const docs = await client.records.list(doctype, { limit, ...filters ? { filters } : {} });
775
+ if (signal.cancelled) return;
776
+ const records = docs.map((d) => chunk3NG33DV2_cjs.enrichLinks(chunk3NG33DV2_cjs.toRecord(d, dt), dt, linkOptions));
777
+ setState({ phase: "ready", dt, fields: chunk3NG33DV2_cjs.docTypeToFields(dt), docs, records, linkOptions });
778
+ } catch (e) {
779
+ if (!signal.cancelled) setState({ phase: "error", error: chunkWHJR5S4L_cjs.classifyBackend(e) });
780
+ }
781
+ },
782
+ [client, doctype, project, limit]
783
+ );
784
+ react.useEffect(() => {
785
+ const signal = { cancelled: false };
786
+ void load(signal);
787
+ return () => {
788
+ signal.cancelled = true;
789
+ };
790
+ }, [load]);
791
+ const reload = react.useCallback(() => void load({ cancelled: false }), [load]);
792
+ const ready = state.phase === "ready" ? state : void 0;
793
+ const fieldOptions = react.useMemo(
794
+ () => ready ? chunk3NG33DV2_cjs.makeFieldOptions(ready.linkOptions) : void 0,
795
+ [ready]
796
+ );
797
+ const [view, setView] = react.useState(void 0);
798
+ const dtName = ready?.dt.name;
799
+ react.useEffect(() => {
800
+ if (!ready) return;
801
+ setView({
802
+ id: `doctype:${ready.dt.name}`,
803
+ name: ready.dt.name,
804
+ kind: "table",
805
+ filters: [],
806
+ sorts: [],
807
+ hiddenFields: chunk3NG33DV2_cjs.listHiddenFields(ready.dt)
808
+ });
809
+ }, [dtName]);
810
+ const cards = react.useMemo(
811
+ () => ready ? chunk3NG33DV2_cjs.cardFields(ready.dt, ready.fields) : [],
812
+ [ready]
813
+ );
814
+ const onEditCommit = react.useCallback(
815
+ async (record, field, value) => {
816
+ if (state.phase !== "ready") return;
817
+ const name = typeof record.name === "string" ? record.name : "";
818
+ if (!name) return;
819
+ setMutationError(null);
820
+ try {
821
+ const body = chunk3NG33DV2_cjs.savePayload({ ...record, [field.name]: value }, state.dt);
822
+ const saved = await client.records.update(doctype, name, body);
823
+ const next = chunk3NG33DV2_cjs.enrichLinks(chunk3NG33DV2_cjs.toRecord(saved, state.dt), state.dt, state.linkOptions);
824
+ setState((s) => s.phase === "ready" ? { ...s, records: s.records.map((r) => r.name === name ? next : r) } : s);
825
+ } catch (e) {
826
+ setMutationError(chunkWHJR5S4L_cjs.classifyBackend(e).message);
827
+ throw e;
828
+ }
829
+ },
830
+ [client, doctype, state]
831
+ );
832
+ if (state.phase === "error") {
833
+ return /* @__PURE__ */ jsxRuntime.jsx(gui.YStack, { onLayout, width: "100%", children: /* @__PURE__ */ jsxRuntime.jsx(chunkWHJR5S4L_cjs.BackendStateCard, { state: state.error, onRetry: reload, hint: `framework \xB7 GET /v1/framework/${doctype}` }) });
834
+ }
835
+ const refresh = phone ? /* @__PURE__ */ jsxRuntime.jsx(Action, { phone: true, icon: /* @__PURE__ */ jsxRuntime.jsx(lucideIcons2.RefreshCw, { size: 15 }), onPress: reload, children: "Refresh" }) : /* @__PURE__ */ jsxRuntime.jsx(gui.Button, { size: "$2", minH: TAP - 12, icon: /* @__PURE__ */ jsxRuntime.jsx(lucideIcons2.RefreshCw, { size: 15 }), onPress: reload, children: "Refresh" });
836
+ if (ready && (media || renderMedia) && chunk3NG33DV2_cjs.isMediaDoctype(ready.dt)) {
837
+ return /* @__PURE__ */ jsxRuntime.jsx(gui.YStack, { onLayout, width: "100%", children: renderMedia ? renderMedia({ dt: ready.dt, docs: ready.docs, onOpen, onChanged: reload, toolbarExtra: refresh }) : /* @__PURE__ */ jsxRuntime.jsx(
838
+ MediaGrid,
839
+ {
840
+ client,
841
+ dt: ready.dt,
842
+ docs: ready.docs,
843
+ media,
844
+ onOpen,
845
+ onChanged: reload,
846
+ toolbarExtra: refresh
847
+ }
848
+ ) });
849
+ }
850
+ const openByKey = (r) => onOpen(String(r.name ?? r.id ?? ""));
851
+ return /* @__PURE__ */ jsxRuntime.jsxs(gui.YStack, { onLayout, gap: "$3", width: "100%", children: [
852
+ mutationError ? /* @__PURE__ */ jsxRuntime.jsx(ErrorBar, { message: mutationError }) : null,
853
+ phone ? /* @__PURE__ */ jsxRuntime.jsx(
854
+ RecordCards,
855
+ {
856
+ titleField: ready?.dt.titleField,
857
+ fields: ready?.fields ?? [],
858
+ cardFields: cards,
859
+ records: ready?.records ?? [],
860
+ loading: state.phase === "loading",
861
+ empty: `No records in ${doctype} yet.`,
862
+ onOpen: openByKey,
863
+ onCreate,
864
+ toolbarExtra: refresh
865
+ }
866
+ ) : /* @__PURE__ */ jsxRuntime.jsx(gui.YStack, { testID: "doctype-table", width: "100%", children: /* @__PURE__ */ jsxRuntime.jsx(
867
+ data.RecordsView,
868
+ {
869
+ title,
870
+ fields: ready?.fields ?? [],
871
+ records: ready?.records ?? [],
872
+ loading: state.phase === "loading",
873
+ view,
874
+ onViewChange: setView,
875
+ onOpen: openByKey,
876
+ onCreate,
877
+ createLabel: "New record",
878
+ onEditCommit,
879
+ fieldOptions,
880
+ toolbarExtra: refresh,
881
+ titleField: ready?.dt.titleField,
882
+ empty: `No records in ${doctype} yet.`
883
+ }
884
+ ) })
885
+ ] });
886
+ }
887
+ function DocTypeDetail({ client, doctype, name, project, onBack, onView }) {
888
+ const isNew = name === "new";
889
+ const [state, setState] = react.useState({ phase: "loading" });
890
+ const [editing, setEditing] = react.useState(isNew);
891
+ const [draft, setDraft] = react.useState({});
892
+ const [busy, setBusy] = react.useState(false);
893
+ const [saveError, setSaveError] = react.useState(null);
894
+ const [confirmingDelete, setConfirmingDelete] = react.useState(false);
895
+ const { phone, onLayout } = useContainerLayout();
896
+ const load = react.useCallback(
897
+ async (signal) => {
898
+ setState({ phase: "loading" });
899
+ try {
900
+ const dt2 = await client.doctypes.get(doctype);
901
+ const linkOptions = await chunk3NG33DV2_cjs.loadLinkOptions(client, dt2);
902
+ const doc = isNew ? null : await client.records.get(doctype, name);
903
+ if (signal.cancelled) return;
904
+ const record2 = doc ? chunk3NG33DV2_cjs.enrichLinks(chunk3NG33DV2_cjs.toRecord(doc, dt2), dt2, linkOptions) : null;
905
+ setState({ phase: "ready", dt: dt2, record: record2, linkOptions });
906
+ const seed = chunk3NG33DV2_cjs.newDraft(dt2);
907
+ if (record2 == null && project && chunk3NG33DV2_cjs.hasProjectField(dt2)) seed[chunk3NG33DV2_cjs.PROJECT_FIELD] = project;
908
+ setDraft(record2 ? { ...record2 } : seed);
909
+ setEditing(isNew);
910
+ setSaveError(null);
911
+ setConfirmingDelete(false);
912
+ } catch (e) {
913
+ if (!signal.cancelled) setState({ phase: "error", error: chunkWHJR5S4L_cjs.classifyBackend(e) });
914
+ }
915
+ },
916
+ [client, doctype, name, isNew, project]
917
+ );
918
+ react.useEffect(() => {
919
+ const signal = { cancelled: false };
920
+ void load(signal);
921
+ return () => {
922
+ signal.cancelled = true;
923
+ };
924
+ }, [load]);
925
+ const reload = react.useCallback(() => void load({ cancelled: false }), [load]);
926
+ const ready = state.phase === "ready" ? state : void 0;
927
+ const dt = ready?.dt;
928
+ const record = ready?.record ?? null;
929
+ const fields = react.useMemo(() => dt ? chunk3NG33DV2_cjs.docTypeToFields(dt, { editing: !isNew }) : [], [dt, isNew]);
930
+ const fieldOptions = react.useMemo(() => ready ? chunk3NG33DV2_cjs.makeFieldOptions(ready.linkOptions) : void 0, [ready]);
931
+ const title = dt ? isNew ? `New ${doctype}` : chunk3NG33DV2_cjs.titleOf(record ?? {}, dt) : doctype;
932
+ const onChange = react.useCallback((field, value) => {
933
+ setDraft((d) => ({ ...d, [field]: value }));
934
+ }, []);
935
+ const reflect = react.useCallback(
936
+ (saved) => {
937
+ if (!dt || !ready) return;
938
+ const next = chunk3NG33DV2_cjs.enrichLinks(chunk3NG33DV2_cjs.toRecord(saved, dt), dt, ready.linkOptions);
939
+ setState({ phase: "ready", dt, record: next, linkOptions: ready.linkOptions });
940
+ setDraft({ ...next });
941
+ },
942
+ [dt, ready]
943
+ );
944
+ const save = react.useCallback(async () => {
945
+ if (!dt) return;
946
+ setBusy(true);
947
+ setSaveError(null);
948
+ try {
949
+ const body = chunk3NG33DV2_cjs.savePayload(draft, dt);
950
+ if (isNew) {
951
+ const created = await client.records.create(doctype, body);
952
+ if (created.name) onView(String(created.name));
953
+ else onBack();
954
+ return;
955
+ }
956
+ if (!record?.name) throw new Error("This record has no name to update.");
957
+ reflect(await client.records.update(doctype, String(record.name), body));
958
+ setEditing(false);
959
+ } catch (e) {
960
+ setSaveError(chunkWHJR5S4L_cjs.classifyBackend(e).message);
961
+ } finally {
962
+ setBusy(false);
963
+ }
964
+ }, [client, doctype, draft, dt, isNew, onBack, onView, record, reflect]);
965
+ const run = react.useCallback(
966
+ async (op) => {
967
+ setBusy(true);
968
+ setSaveError(null);
969
+ try {
970
+ const saved = await op();
971
+ if (saved) reflect(saved);
972
+ } catch (e) {
973
+ setSaveError(chunkWHJR5S4L_cjs.classifyBackend(e).message);
974
+ } finally {
975
+ setBusy(false);
976
+ }
977
+ },
978
+ [reflect]
979
+ );
980
+ const remove = react.useCallback(async () => {
981
+ if (!record?.name) return;
982
+ setBusy(true);
983
+ setSaveError(null);
984
+ try {
985
+ await client.records.remove(doctype, String(record.name));
986
+ onBack();
987
+ } catch (e) {
988
+ setSaveError(chunkWHJR5S4L_cjs.classifyBackend(e).message);
989
+ setBusy(false);
990
+ setConfirmingDelete(false);
991
+ }
992
+ }, [client, doctype, onBack, record]);
993
+ const backButton = /* @__PURE__ */ jsxRuntime.jsx(Action, { phone, icon: /* @__PURE__ */ jsxRuntime.jsx(lucideIcons2.ArrowLeft, { size: 15 }), onPress: onBack, children: "Back" });
994
+ if (state.phase === "loading") {
995
+ return /* @__PURE__ */ jsxRuntime.jsx(gui.YStack, { onLayout, width: "100%", children: /* @__PURE__ */ jsxRuntime.jsx(Loading, { label: `Loading ${doctype}\u2026` }) });
996
+ }
997
+ if (state.phase === "error") {
998
+ return /* @__PURE__ */ jsxRuntime.jsxs(gui.YStack, { onLayout, gap: "$3", width: "100%", children: [
999
+ /* @__PURE__ */ jsxRuntime.jsx(gui.XStack, { children: backButton }),
1000
+ /* @__PURE__ */ jsxRuntime.jsx(chunkWHJR5S4L_cjs.BackendStateCard, { state: state.error, onRetry: reload, hint: `framework \xB7 ${doctype}/${name}` })
1001
+ ] });
1002
+ }
1003
+ if (!dt) {
1004
+ return /* @__PURE__ */ jsxRuntime.jsx(gui.YStack, { onLayout, gap: "$3", width: "100%", children: /* @__PURE__ */ jsxRuntime.jsx(gui.XStack, { children: backButton }) });
1005
+ }
1006
+ const draftDoc = chunk3NG33DV2_cjs.isDraft(record);
1007
+ const statusF = chunk3NG33DV2_cjs.statusField(dt);
1008
+ const status = record ? String(record[statusF] ?? "") : "";
1009
+ const docstatus = record ? Number(record.docstatus ?? 0) : 0;
1010
+ const canEdit = !editing && !isNew && draftDoc;
1011
+ const canDelete = !editing && !isNew && draftDoc;
1012
+ const canPublish = canEdit && Boolean(statusF);
1013
+ const canSubmit = !editing && !isNew && Boolean(dt.isSubmittable) && draftDoc;
1014
+ const canCancel = !editing && !isNew && Boolean(dt.isSubmittable) && docstatus === chunk3NG33DV2_cjs.SUBMITTED;
1015
+ const lifecycle = docstatus === chunk3NG33DV2_cjs.SUBMITTED ? " \xB7 submitted" : docstatus === chunk3NG33DV2_cjs.CANCELLED ? " \xB7 cancelled" : "";
1016
+ return /* @__PURE__ */ jsxRuntime.jsxs(gui.YStack, { onLayout, gap: "$3", width: "100%", children: [
1017
+ /* @__PURE__ */ jsxRuntime.jsxs(gui.YStack, { gap: "$3", width: "100%", children: [
1018
+ /* @__PURE__ */ jsxRuntime.jsxs(gui.XStack, { items: "center", gap: "$3", width: "100%", flexWrap: "wrap", children: [
1019
+ phone ? null : backButton,
1020
+ /* @__PURE__ */ jsxRuntime.jsxs(gui.YStack, { flex: 1, minW: 200, children: [
1021
+ /* @__PURE__ */ jsxRuntime.jsx(gui.Text, { fontSize: "$6", fontWeight: "800", numberOfLines: 2, children: title }),
1022
+ /* @__PURE__ */ jsxRuntime.jsxs(gui.Text, { fontSize: "$2", color: "$color10", numberOfLines: 1, children: [
1023
+ doctype,
1024
+ status ? ` \xB7 ${status}` : "",
1025
+ lifecycle
1026
+ ] })
1027
+ ] })
1028
+ ] }),
1029
+ /* @__PURE__ */ jsxRuntime.jsxs(Actions, { phone, children: [
1030
+ phone ? backButton : null,
1031
+ editing ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1032
+ !isNew ? /* @__PURE__ */ jsxRuntime.jsx(
1033
+ Action,
1034
+ {
1035
+ phone,
1036
+ icon: /* @__PURE__ */ jsxRuntime.jsx(lucideIcons2.X, { size: 15 }),
1037
+ disabled: busy,
1038
+ onPress: () => {
1039
+ setDraft(record ? { ...record } : {});
1040
+ setEditing(false);
1041
+ setSaveError(null);
1042
+ },
1043
+ children: "Cancel"
1044
+ }
1045
+ ) : null,
1046
+ /* @__PURE__ */ jsxRuntime.jsx(Action, { phone, primary: true, icon: /* @__PURE__ */ jsxRuntime.jsx(lucideIcons2.Save, { size: 15 }), disabled: busy, onPress: save, children: busy ? "Saving\u2026" : isNew ? "Create" : "Save" })
1047
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1048
+ canDelete ? /* @__PURE__ */ jsxRuntime.jsx(Action, { phone, danger: true, icon: /* @__PURE__ */ jsxRuntime.jsx(lucideIcons2.Trash2, { size: 15 }), disabled: busy, onPress: () => setConfirmingDelete(true), children: "Delete" }) : null,
1049
+ canCancel ? /* @__PURE__ */ jsxRuntime.jsx(
1050
+ Action,
1051
+ {
1052
+ phone,
1053
+ icon: /* @__PURE__ */ jsxRuntime.jsx(lucideIcons2.Ban, { size: 15 }),
1054
+ disabled: busy,
1055
+ onPress: () => run(() => client.records.cancel(doctype, String(record.name))),
1056
+ children: "Cancel doc"
1057
+ }
1058
+ ) : null,
1059
+ canSubmit ? /* @__PURE__ */ jsxRuntime.jsx(
1060
+ Action,
1061
+ {
1062
+ phone,
1063
+ icon: /* @__PURE__ */ jsxRuntime.jsx(lucideIcons2.Send, { size: 15 }),
1064
+ disabled: busy,
1065
+ onPress: () => run(() => client.records.submit(doctype, String(record.name))),
1066
+ children: "Submit"
1067
+ }
1068
+ ) : null,
1069
+ canPublish ? status === "Published" ? /* @__PURE__ */ jsxRuntime.jsx(
1070
+ Action,
1071
+ {
1072
+ phone,
1073
+ icon: /* @__PURE__ */ jsxRuntime.jsx(lucideIcons2.PenOff, { size: 15 }),
1074
+ disabled: busy,
1075
+ onPress: () => run(
1076
+ async () => client.records.update(doctype, String(record.name), chunk3NG33DV2_cjs.savePayload({ ...record, [statusF]: "Draft" }, dt))
1077
+ ),
1078
+ children: "Unpublish"
1079
+ }
1080
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
1081
+ Action,
1082
+ {
1083
+ phone,
1084
+ primary: true,
1085
+ icon: /* @__PURE__ */ jsxRuntime.jsx(lucideIcons2.Globe, { size: 15 }),
1086
+ disabled: busy,
1087
+ onPress: () => run(
1088
+ async () => client.records.update(
1089
+ doctype,
1090
+ String(record.name),
1091
+ chunk3NG33DV2_cjs.savePayload({ ...record, [statusF]: "Published" }, dt)
1092
+ )
1093
+ ),
1094
+ children: "Publish"
1095
+ }
1096
+ ) : null,
1097
+ canEdit ? /* @__PURE__ */ jsxRuntime.jsx(Action, { phone, primary: true, icon: /* @__PURE__ */ jsxRuntime.jsx(lucideIcons2.Pencil, { size: 15 }), onPress: () => setEditing(true), children: "Edit" }) : null
1098
+ ] })
1099
+ ] })
1100
+ ] }),
1101
+ !editing && !isNew && !draftDoc ? /* @__PURE__ */ jsxRuntime.jsx(gui.Card, { borderWidth: 1, borderColor: "$borderColor", bg: "$color2", p: "$3", maxW: 620, children: /* @__PURE__ */ jsxRuntime.jsx(gui.Text, { fontSize: "$2", color: "$color11", children: docstatus === chunk3NG33DV2_cjs.SUBMITTED ? "This document is submitted. Cancel it to make further changes \u2014 the engine refuses edits and deletes on a submitted document." : "This document is cancelled. It is kept as a record and can no longer be edited or deleted." }) }) : null,
1102
+ confirmingDelete ? /* @__PURE__ */ jsxRuntime.jsxs(gui.Card, { borderWidth: 1, borderColor: "$red7", bg: "$red2", p: "$3", gap: "$3", maxW: 620, children: [
1103
+ /* @__PURE__ */ jsxRuntime.jsxs(gui.Text, { fontSize: "$3", fontWeight: "700", children: [
1104
+ "Delete \u201C",
1105
+ title,
1106
+ "\u201D? This cannot be undone."
1107
+ ] }),
1108
+ /* @__PURE__ */ jsxRuntime.jsxs(Actions, { phone, children: [
1109
+ /* @__PURE__ */ jsxRuntime.jsx(Action, { phone, danger: true, disabled: busy, onPress: remove, children: busy ? "Deleting\u2026" : "Confirm delete" }),
1110
+ /* @__PURE__ */ jsxRuntime.jsx(Action, { phone, disabled: busy, onPress: () => setConfirmingDelete(false), children: "Keep" })
1111
+ ] })
1112
+ ] }) : null,
1113
+ saveError ? /* @__PURE__ */ jsxRuntime.jsx(ErrorBar, { message: saveError }) : null,
1114
+ /* @__PURE__ */ jsxRuntime.jsx(Panel, { phone, children: editing ? /* @__PURE__ */ jsxRuntime.jsx(data.RecordForm, { fields, values: draft, onChange, fieldOptions }) : record ? /* @__PURE__ */ jsxRuntime.jsx(data.RecordDetail, { title, fields, record, fieldOptions }) : null })
1115
+ ] });
1116
+ }
1117
+
1118
+ Object.defineProperty(exports, "BUILDER_FIELD_TYPES", {
1119
+ enumerable: true,
1120
+ get: function () { return chunk3NG33DV2_cjs.BUILDER_FIELD_TYPES; }
1121
+ });
1122
+ Object.defineProperty(exports, "CANCELLED", {
1123
+ enumerable: true,
1124
+ get: function () { return chunk3NG33DV2_cjs.CANCELLED; }
1125
+ });
1126
+ Object.defineProperty(exports, "DRAFT", {
1127
+ enumerable: true,
1128
+ get: function () { return chunk3NG33DV2_cjs.DRAFT; }
1129
+ });
1130
+ Object.defineProperty(exports, "PROJECT_FIELD", {
1131
+ enumerable: true,
1132
+ get: function () { return chunk3NG33DV2_cjs.PROJECT_FIELD; }
1133
+ });
1134
+ Object.defineProperty(exports, "REDACTED_MARKER", {
1135
+ enumerable: true,
1136
+ get: function () { return chunk3NG33DV2_cjs.REDACTED_MARKER; }
1137
+ });
1138
+ Object.defineProperty(exports, "SUBMITTED", {
1139
+ enumerable: true,
1140
+ get: function () { return chunk3NG33DV2_cjs.SUBMITTED; }
1141
+ });
1142
+ Object.defineProperty(exports, "autonameSource", {
1143
+ enumerable: true,
1144
+ get: function () { return chunk3NG33DV2_cjs.autonameSource; }
1145
+ });
1146
+ Object.defineProperty(exports, "blankField", {
1147
+ enumerable: true,
1148
+ get: function () { return chunk3NG33DV2_cjs.blankField; }
1149
+ });
1150
+ Object.defineProperty(exports, "cardFields", {
1151
+ enumerable: true,
1152
+ get: function () { return chunk3NG33DV2_cjs.cardFields; }
1153
+ });
1154
+ Object.defineProperty(exports, "createFrameworkClient", {
1155
+ enumerable: true,
1156
+ get: function () { return chunk3NG33DV2_cjs.createFrameworkClient; }
1157
+ });
1158
+ Object.defineProperty(exports, "createMediaUploader", {
1159
+ enumerable: true,
1160
+ get: function () { return chunk3NG33DV2_cjs.createMediaUploader; }
1161
+ });
1162
+ Object.defineProperty(exports, "docTypeToFields", {
1163
+ enumerable: true,
1164
+ get: function () { return chunk3NG33DV2_cjs.docTypeToFields; }
1165
+ });
1166
+ Object.defineProperty(exports, "enrichLinks", {
1167
+ enumerable: true,
1168
+ get: function () { return chunk3NG33DV2_cjs.enrichLinks; }
1169
+ });
1170
+ Object.defineProperty(exports, "fieldNameFromLabel", {
1171
+ enumerable: true,
1172
+ get: function () { return chunk3NG33DV2_cjs.fieldNameFromLabel; }
1173
+ });
1174
+ Object.defineProperty(exports, "fieldNeedsOptions", {
1175
+ enumerable: true,
1176
+ get: function () { return chunk3NG33DV2_cjs.fieldNeedsOptions; }
1177
+ });
1178
+ Object.defineProperty(exports, "fieldTypeLabel", {
1179
+ enumerable: true,
1180
+ get: function () { return chunk3NG33DV2_cjs.fieldTypeLabel; }
1181
+ });
1182
+ Object.defineProperty(exports, "fieldsFromDocType", {
1183
+ enumerable: true,
1184
+ get: function () { return chunk3NG33DV2_cjs.fieldsFromDocType; }
1185
+ });
1186
+ Object.defineProperty(exports, "hasProjectField", {
1187
+ enumerable: true,
1188
+ get: function () { return chunk3NG33DV2_cjs.hasProjectField; }
1189
+ });
1190
+ Object.defineProperty(exports, "humanize", {
1191
+ enumerable: true,
1192
+ get: function () { return chunk3NG33DV2_cjs.humanize; }
1193
+ });
1194
+ Object.defineProperty(exports, "imageDimensions", {
1195
+ enumerable: true,
1196
+ get: function () { return chunk3NG33DV2_cjs.imageDimensions; }
1197
+ });
1198
+ Object.defineProperty(exports, "isDraft", {
1199
+ enumerable: true,
1200
+ get: function () { return chunk3NG33DV2_cjs.isDraft; }
1201
+ });
1202
+ Object.defineProperty(exports, "isMediaDoctype", {
1203
+ enumerable: true,
1204
+ get: function () { return chunk3NG33DV2_cjs.isMediaDoctype; }
1205
+ });
1206
+ Object.defineProperty(exports, "isRef", {
1207
+ enumerable: true,
1208
+ get: function () { return chunk3NG33DV2_cjs.isRef; }
1209
+ });
1210
+ Object.defineProperty(exports, "isValidDoctypeName", {
1211
+ enumerable: true,
1212
+ get: function () { return chunk3NG33DV2_cjs.isValidDoctypeName; }
1213
+ });
1214
+ Object.defineProperty(exports, "joinKey", {
1215
+ enumerable: true,
1216
+ get: function () { return chunk3NG33DV2_cjs.joinKey; }
1217
+ });
1218
+ Object.defineProperty(exports, "linkFields", {
1219
+ enumerable: true,
1220
+ get: function () { return chunk3NG33DV2_cjs.linkFields; }
1221
+ });
1222
+ Object.defineProperty(exports, "listHiddenFields", {
1223
+ enumerable: true,
1224
+ get: function () { return chunk3NG33DV2_cjs.listHiddenFields; }
1225
+ });
1226
+ Object.defineProperty(exports, "listQuery", {
1227
+ enumerable: true,
1228
+ get: function () { return chunk3NG33DV2_cjs.listQuery; }
1229
+ });
1230
+ Object.defineProperty(exports, "listedFieldNames", {
1231
+ enumerable: true,
1232
+ get: function () { return chunk3NG33DV2_cjs.listedFieldNames; }
1233
+ });
1234
+ Object.defineProperty(exports, "loadLinkOptions", {
1235
+ enumerable: true,
1236
+ get: function () { return chunk3NG33DV2_cjs.loadLinkOptions; }
1237
+ });
1238
+ Object.defineProperty(exports, "looksLikeImage", {
1239
+ enumerable: true,
1240
+ get: function () { return chunk3NG33DV2_cjs.looksLikeImage; }
1241
+ });
1242
+ Object.defineProperty(exports, "makeFieldOptions", {
1243
+ enumerable: true,
1244
+ get: function () { return chunk3NG33DV2_cjs.makeFieldOptions; }
1245
+ });
1246
+ Object.defineProperty(exports, "mediaDocPayload", {
1247
+ enumerable: true,
1248
+ get: function () { return chunk3NG33DV2_cjs.mediaDocPayload; }
1249
+ });
1250
+ Object.defineProperty(exports, "mediaFileField", {
1251
+ enumerable: true,
1252
+ get: function () { return chunk3NG33DV2_cjs.mediaFileField; }
1253
+ });
1254
+ Object.defineProperty(exports, "mediaKey", {
1255
+ enumerable: true,
1256
+ get: function () { return chunk3NG33DV2_cjs.mediaKey; }
1257
+ });
1258
+ Object.defineProperty(exports, "mediaRef", {
1259
+ enumerable: true,
1260
+ get: function () { return chunk3NG33DV2_cjs.mediaRef; }
1261
+ });
1262
+ Object.defineProperty(exports, "moduleDoctypes", {
1263
+ enumerable: true,
1264
+ get: function () { return chunk3NG33DV2_cjs.moduleDoctypes; }
1265
+ });
1266
+ Object.defineProperty(exports, "moveField", {
1267
+ enumerable: true,
1268
+ get: function () { return chunk3NG33DV2_cjs.moveField; }
1269
+ });
1270
+ Object.defineProperty(exports, "newDraft", {
1271
+ enumerable: true,
1272
+ get: function () { return chunk3NG33DV2_cjs.newDraft; }
1273
+ });
1274
+ Object.defineProperty(exports, "newKey", {
1275
+ enumerable: true,
1276
+ get: function () { return chunk3NG33DV2_cjs.newKey; }
1277
+ });
1278
+ Object.defineProperty(exports, "parseRef", {
1279
+ enumerable: true,
1280
+ get: function () { return chunk3NG33DV2_cjs.parseRef; }
1281
+ });
1282
+ Object.defineProperty(exports, "rows", {
1283
+ enumerable: true,
1284
+ get: function () { return chunk3NG33DV2_cjs.rows; }
1285
+ });
1286
+ Object.defineProperty(exports, "savePayload", {
1287
+ enumerable: true,
1288
+ get: function () { return chunk3NG33DV2_cjs.savePayload; }
1289
+ });
1290
+ Object.defineProperty(exports, "slugify", {
1291
+ enumerable: true,
1292
+ get: function () { return chunk3NG33DV2_cjs.slugify; }
1293
+ });
1294
+ Object.defineProperty(exports, "starterFields", {
1295
+ enumerable: true,
1296
+ get: function () { return chunk3NG33DV2_cjs.starterFields; }
1297
+ });
1298
+ Object.defineProperty(exports, "statusField", {
1299
+ enumerable: true,
1300
+ get: function () { return chunk3NG33DV2_cjs.statusField; }
1301
+ });
1302
+ Object.defineProperty(exports, "titleOf", {
1303
+ enumerable: true,
1304
+ get: function () { return chunk3NG33DV2_cjs.titleOf; }
1305
+ });
1306
+ Object.defineProperty(exports, "toDocField", {
1307
+ enumerable: true,
1308
+ get: function () { return chunk3NG33DV2_cjs.toDocField; }
1309
+ });
1310
+ Object.defineProperty(exports, "toDocType", {
1311
+ enumerable: true,
1312
+ get: function () { return chunk3NG33DV2_cjs.toDocType; }
1313
+ });
1314
+ Object.defineProperty(exports, "toRecord", {
1315
+ enumerable: true,
1316
+ get: function () { return chunk3NG33DV2_cjs.toRecord; }
1317
+ });
1318
+ Object.defineProperty(exports, "validateBuilder", {
1319
+ enumerable: true,
1320
+ get: function () { return chunk3NG33DV2_cjs.validateBuilder; }
1321
+ });
1322
+ exports.Action = Action;
1323
+ exports.Actions = Actions;
1324
+ exports.CollectionBuilder = CollectionBuilder;
1325
+ exports.CollectionsBrowser = CollectionsBrowser;
1326
+ exports.DocTypeDetail = DocTypeDetail;
1327
+ exports.DocTypeRecords = DocTypeRecords;
1328
+ exports.ErrorBar = ErrorBar;
1329
+ exports.GRID_MIN = GRID_MIN;
1330
+ exports.Loading = Loading;
1331
+ exports.MediaGrid = MediaGrid;
1332
+ exports.Meta = Meta;
1333
+ exports.Panel = Panel;
1334
+ exports.RecordCards = RecordCards;
1335
+ exports.TABLE_MIN = TABLE_MIN;
1336
+ exports.TAP = TAP;
1337
+ exports.layoutFor = layoutFor;
1338
+ exports.useContainerLayout = useContainerLayout;
1339
+ //# sourceMappingURL=index.cjs.map
1340
+ //# sourceMappingURL=index.cjs.map