@duke333/builder-ui 0.1.0

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.
@@ -0,0 +1,581 @@
1
+ // src/components/DynamicForm.tsx
2
+ import { useMemo } from "react";
3
+ import { FormProvider, useForm } from "react-hook-form";
4
+
5
+ // src/runtime/runtimeUtils.ts
6
+ function emptyFieldValue(field) {
7
+ return field.type === "checkbox" ? false : "";
8
+ }
9
+ function createBuilderFormDefaultValues(schema) {
10
+ const values = {};
11
+ for (const field of schema?.fields ?? []) {
12
+ values[field.key] = emptyFieldValue(field);
13
+ }
14
+ return { values };
15
+ }
16
+ function createBuilderEntryDefaultValues(view, editing) {
17
+ const values = {};
18
+ for (const field of view.form?.schema.fields ?? []) {
19
+ const existing = editing?.values[field.key];
20
+ values[field.key] = existing === void 0 ? emptyFieldValue(field) : existing;
21
+ }
22
+ return { values, version: editing?.version ?? 0 };
23
+ }
24
+
25
+ // src/components/DynamicForm.tsx
26
+ import { jsx, jsxs } from "react/jsx-runtime";
27
+ function createDynamicFormComponent(deps) {
28
+ return function DynamicForm({ formId }) {
29
+ const query = deps.hooks.useRuntimeBuilderForm(formId);
30
+ const save = deps.hooks.useSaveRuntimeBuilderFormEntry(formId);
31
+ const formValues = useMemo(
32
+ () => query.data ? createBuilderFormDefaultValues(query.data.schema) : void 0,
33
+ [query.data]
34
+ );
35
+ const form = useForm({
36
+ defaultValues: createBuilderFormDefaultValues(query.data?.schema),
37
+ values: formValues
38
+ });
39
+ const onSubmit = form.handleSubmit(async (values) => {
40
+ try {
41
+ await save.mutateAsync(values);
42
+ form.reset(createBuilderFormDefaultValues(query.data?.schema));
43
+ deps.notifications.success("Form \u0445\u0430\u0434\u0433\u0430\u043B\u0430\u0433\u0434\u043B\u0430\u0430");
44
+ } catch (error) {
45
+ deps.notifications.error(deps.notifications.errorMessage(error, "\u0425\u0430\u0434\u0433\u0430\u043B\u0430\u0445\u0430\u0434 \u0430\u043B\u0434\u0430\u0430 \u0433\u0430\u0440\u043B\u0430\u0430"));
46
+ }
47
+ });
48
+ if (query.isError) {
49
+ return /* @__PURE__ */ jsx(
50
+ deps.ErrorState,
51
+ {
52
+ title: "Form \u043D\u044D\u044D\u0433\u0434\u0441\u044D\u043D\u0433\u04AF\u0439",
53
+ description: `\xAB${formId}\xBB id-\u0442\u0430\u0439 form \u043E\u043B\u0434\u0441\u043E\u043D\u0433\u04AF\u0439.`
54
+ }
55
+ );
56
+ }
57
+ if (!query.data) return null;
58
+ return /* @__PURE__ */ jsx(deps.FormShell, { title: query.data.title, children: /* @__PURE__ */ jsx(FormProvider, { ...form, children: /* @__PURE__ */ jsxs("form", { onSubmit, noValidate: true, className: "space-y-6", children: [
59
+ /* @__PURE__ */ jsx(deps.FormFields, { formId, schema: query.data.schema, namePrefix: "values" }),
60
+ /* @__PURE__ */ jsx(deps.SubmitButton, { isSaving: save.isPending })
61
+ ] }) }) });
62
+ };
63
+ }
64
+
65
+ // src/components/DynamicList.tsx
66
+ import { useMemo as useMemo2 } from "react";
67
+ import { jsx as jsx2 } from "react/jsx-runtime";
68
+ function createDynamicListComponent(deps) {
69
+ return function DynamicList({ listId }) {
70
+ const query = deps.hooks.useRuntimeBuilderList(listId);
71
+ const state = deps.useDataTableState({ pageSize: 20 });
72
+ const entriesQuery = deps.hooks.useRuntimeBuilderListEntries(listId, state.query);
73
+ const columns = useMemo2(() => query.data ? deps.buildColumns(query.data) : [], [query.data]);
74
+ const entries = entriesQuery.data?.items ?? [];
75
+ const controller = deps.useDataTable({
76
+ columns,
77
+ data: entries,
78
+ rowCount: entriesQuery.data?.total ?? 0,
79
+ state,
80
+ getRowId: (row) => row.id
81
+ });
82
+ if (query.isError) {
83
+ return /* @__PURE__ */ jsx2(
84
+ deps.ErrorState,
85
+ {
86
+ title: "List \u043D\u044D\u044D\u0433\u0434\u0441\u044D\u043D\u0433\u04AF\u0439",
87
+ description: `\xAB${listId}\xBB id-\u0442\u0430\u0439 list \u043E\u043B\u0434\u0441\u043E\u043D\u0433\u04AF\u0439.`
88
+ }
89
+ );
90
+ }
91
+ return /* @__PURE__ */ jsx2(
92
+ deps.DataGrid,
93
+ {
94
+ title: query.data?.title ?? "Dynamic List",
95
+ description: query.data?.description ?? `/winu/list?id=${listId}`,
96
+ controller,
97
+ isLoading: query.isPending || entriesQuery.isPending,
98
+ searchPlaceholder: "\u041C\u04E9\u0440 \u0445\u0430\u0439\u0445...",
99
+ emptyTitle: "\u041C\u04E9\u0440 \u0430\u043B\u0433\u0430",
100
+ emptyDescription: "\u042D\u043D\u044D list-\u0438\u0439\u043D datasource \u0434\u044D\u044D\u0440 \u043C\u04E9\u0440 \u0430\u043B\u0433\u0430."
101
+ }
102
+ );
103
+ };
104
+ }
105
+
106
+ // src/components/DynamicView.tsx
107
+ import { useMemo as useMemo3, useState } from "react";
108
+ import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
109
+ function createDynamicViewComponent(deps) {
110
+ return function DynamicView({ viewId }) {
111
+ const [editing, setEditing] = useState(null);
112
+ const [isDialogOpen, setDialogOpen] = useState(false);
113
+ const [pendingDelete, setPendingDelete] = useState(null);
114
+ const viewQuery = deps.hooks.useRuntimeBuilderView(viewId);
115
+ const state = deps.useDataTableState({ pageSize: 20 });
116
+ const entriesQuery = deps.hooks.useBuilderViewEntries(viewId, state.query);
117
+ const save = deps.hooks.useSaveBuilderViewEntry(viewId);
118
+ const remove = deps.hooks.useDeleteBuilderViewEntry(viewId);
119
+ const view = viewQuery.data;
120
+ const columns = useMemo3(
121
+ () => view ? deps.buildColumns(view, {
122
+ onEdit: (entry) => {
123
+ setEditing(entry);
124
+ setDialogOpen(true);
125
+ },
126
+ onDelete: setPendingDelete
127
+ }) : [],
128
+ [view]
129
+ );
130
+ const controller = deps.useDataTable({
131
+ columns,
132
+ data: entriesQuery.data?.items ?? [],
133
+ rowCount: entriesQuery.data?.total ?? 0,
134
+ state,
135
+ getRowId: (row) => row.id
136
+ });
137
+ if (viewQuery.isError) {
138
+ return /* @__PURE__ */ jsx3(
139
+ deps.ErrorState,
140
+ {
141
+ title: "View \u043D\u044D\u044D\u0433\u0434\u0441\u044D\u043D\u0433\u04AF\u0439",
142
+ description: `\xAB${viewId}\xBB id-\u0442\u0430\u0439 view \u043E\u043B\u0434\u0441\u043E\u043D\u0433\u04AF\u0439.`
143
+ }
144
+ );
145
+ }
146
+ return /* @__PURE__ */ jsxs2("div", { className: "space-y-6", children: [
147
+ /* @__PURE__ */ jsx3(
148
+ deps.DataGrid,
149
+ {
150
+ title: view?.title ?? "Dynamic View",
151
+ description: view?.description ?? `/winu/view?id=${viewId}`,
152
+ controller,
153
+ isLoading: viewQuery.isPending || entriesQuery.isPending,
154
+ searchPlaceholder: "\u041C\u04E9\u0440 \u0445\u0430\u0439\u0445...",
155
+ emptyTitle: "\u041C\u04E9\u0440 \u0430\u043B\u0433\u0430",
156
+ emptyDescription: "\u042D\u043D\u044D view \u0434\u044D\u044D\u0440 \u044D\u0445\u043D\u0438\u0439 \u043C\u04E9\u0440\u04E9\u04E9 \u043D\u044D\u043C\u044D\u044D\u0440\u044D\u0439.",
157
+ onRowClick: (entry) => {
158
+ setEditing(entry);
159
+ setDialogOpen(true);
160
+ },
161
+ toolbarExtra: /* @__PURE__ */ jsx3(
162
+ deps.AddButton,
163
+ {
164
+ disabled: !view?.form,
165
+ onAdd: () => {
166
+ setEditing(null);
167
+ setDialogOpen(true);
168
+ }
169
+ }
170
+ )
171
+ }
172
+ ),
173
+ view ? /* @__PURE__ */ jsx3(
174
+ deps.EntryDialog,
175
+ {
176
+ open: isDialogOpen,
177
+ view,
178
+ editing,
179
+ onClose: () => setDialogOpen(false),
180
+ onSave: save.mutateAsync,
181
+ isSaving: save.isPending
182
+ }
183
+ ) : null,
184
+ /* @__PURE__ */ jsx3(
185
+ deps.DeleteDialog,
186
+ {
187
+ entry: pendingDelete,
188
+ isDeleting: remove.isPending,
189
+ onClose: () => setPendingDelete(null),
190
+ onConfirm: async () => {
191
+ if (!pendingDelete) return;
192
+ await remove.mutateAsync(pendingDelete.id);
193
+ setPendingDelete(null);
194
+ }
195
+ }
196
+ )
197
+ ] });
198
+ };
199
+ }
200
+
201
+ // src/components/RuntimeEntryDialog.tsx
202
+ import { useEffect, useMemo as useMemo4, useState as useState2 } from "react";
203
+ import { FormProvider as FormProvider2, useForm as useForm2 } from "react-hook-form";
204
+ import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
205
+ function isDbTableSource(source) {
206
+ return source?.type === "dbTable" && "tableName" in source;
207
+ }
208
+ function runtimeViewTableName(view) {
209
+ const listSource = view.list?.source;
210
+ if (isDbTableSource(listSource)) return listSource.tableName;
211
+ const formSource = view.form?.source;
212
+ return isDbTableSource(formSource) ? formSource.tableName : void 0;
213
+ }
214
+ function cleanRowValues(values) {
215
+ return Object.fromEntries(
216
+ Object.entries(values).filter(([key]) => key === "_delete" || !key.startsWith("_"))
217
+ );
218
+ }
219
+ function childRowPayload(row, includeIdentity) {
220
+ const values = cleanRowValues(row.values);
221
+ if (!includeIdentity || row.values._draftNew === true) return values;
222
+ return {
223
+ id: row.id,
224
+ version: row.version,
225
+ ...values
226
+ };
227
+ }
228
+ function createRuntimeEntryDialogComponent(deps) {
229
+ return function RuntimeEntryDialog({
230
+ open,
231
+ view,
232
+ editing,
233
+ onClose,
234
+ onSave,
235
+ isSaving
236
+ }) {
237
+ const [draftSubforms, setDraftSubforms] = useState2({});
238
+ const compositeCreate = deps.useCreateCompositeEntry?.(view.id);
239
+ const compositeUpdate = deps.useUpdateCompositeEntry?.(view.id);
240
+ const form = useForm2({
241
+ defaultValues: createBuilderEntryDefaultValues(view, editing),
242
+ values: open ? createBuilderEntryDefaultValues(view, editing) : void 0
243
+ });
244
+ const mainTableName = runtimeViewTableName(view);
245
+ const hasDraftRows = useMemo4(
246
+ () => Object.values(draftSubforms).some((draft) => draft.rows.length > 0),
247
+ [draftSubforms]
248
+ );
249
+ useEffect(() => {
250
+ if (open) setDraftSubforms({});
251
+ }, [open]);
252
+ const onSubmit = form.handleSubmit(async (values) => {
253
+ try {
254
+ if (!editing && hasDraftRows) {
255
+ if (!mainTableName) throw new Error("Main form datasource table \u043E\u043B\u0434\u0441\u043E\u043D\u0433\u04AF\u0439");
256
+ if (!compositeCreate) throw new Error("Composite create handler \u0442\u043E\u0445\u0438\u0440\u0443\u0443\u043B\u0430\u0433\u0434\u0430\u0430\u0433\u04AF\u0439 \u0431\u0430\u0439\u043D\u0430");
257
+ await compositeCreate.mutateAsync({
258
+ data: {
259
+ [mainTableName]: values.values,
260
+ ...Object.fromEntries(
261
+ Object.values(draftSubforms).map((draft) => [
262
+ draft.dataKey,
263
+ draft.rows.filter((row) => row.values._delete !== true).map((row) => childRowPayload(row, false))
264
+ ])
265
+ )
266
+ }
267
+ });
268
+ } else if (editing && hasDraftRows) {
269
+ if (!mainTableName) throw new Error("Main form datasource table \u043E\u043B\u0434\u0441\u043E\u043D\u0433\u04AF\u0439");
270
+ if (!compositeUpdate) throw new Error("Composite update handler \u0442\u043E\u0445\u0438\u0440\u0443\u0443\u043B\u0430\u0433\u0434\u0430\u0430\u0433\u04AF\u0439 \u0431\u0430\u0439\u043D\u0430");
271
+ await compositeUpdate.mutateAsync({
272
+ id: editing.id,
273
+ input: {
274
+ data: {
275
+ [mainTableName]: {
276
+ id: editing.id,
277
+ version: values.version,
278
+ ...values.values
279
+ },
280
+ ...Object.fromEntries(
281
+ Object.values(draftSubforms).map((draft) => [
282
+ draft.dataKey,
283
+ draft.rows.map((row) => childRowPayload(row, true))
284
+ ])
285
+ )
286
+ }
287
+ }
288
+ });
289
+ } else {
290
+ await onSave({ id: editing?.id, input: values });
291
+ }
292
+ onClose();
293
+ deps.notifications.success(editing ? "\u041C\u04E9\u0440 \u0445\u0430\u0434\u0433\u0430\u043B\u0430\u0433\u0434\u043B\u0430\u0430" : "\u041C\u04E9\u0440 \u043D\u044D\u043C\u044D\u0433\u0434\u043B\u044D\u044D");
294
+ } catch (error) {
295
+ deps.notifications.error(deps.notifications.errorMessage(error, "\u0425\u0430\u0434\u0433\u0430\u043B\u0430\u0445\u0430\u0434 \u0430\u043B\u0434\u0430\u0430 \u0433\u0430\u0440\u043B\u0430\u0430"));
296
+ }
297
+ });
298
+ const saving = isSaving || Boolean(compositeCreate?.isPending || compositeUpdate?.isPending);
299
+ const extraItems = deps.SubformField && view.form?.schema.subforms?.length ? view.form.schema.subforms.map((subform) => ({
300
+ key: subform.key,
301
+ render: () => deps.SubformField ? /* @__PURE__ */ jsx4(
302
+ deps.SubformField,
303
+ {
304
+ subform,
305
+ parentEntry: editing,
306
+ draftRows: draftSubforms[subform.key]?.rows ?? [],
307
+ onDraftRowsChange: ({ subformKey, dataKey, rows }) => {
308
+ setDraftSubforms((current) => ({
309
+ ...current,
310
+ [subformKey]: { dataKey, rows }
311
+ }));
312
+ }
313
+ }
314
+ ) : null
315
+ })) : void 0;
316
+ return /* @__PURE__ */ jsx4(
317
+ deps.DialogShell,
318
+ {
319
+ open,
320
+ title: editing ? "\u041C\u04E9\u0440 \u0437\u0430\u0441\u0430\u0445" : "\u041C\u04E9\u0440 \u043D\u044D\u043C\u044D\u0445",
321
+ description: view.title,
322
+ onClose,
323
+ children: /* @__PURE__ */ jsx4(FormProvider2, { ...form, children: /* @__PURE__ */ jsxs3("form", { onSubmit, noValidate: true, className: deps.formClassName, children: [
324
+ view.form ? /* @__PURE__ */ jsx4(
325
+ deps.FormFields,
326
+ {
327
+ formId: view.form.id,
328
+ viewId: view.id,
329
+ entry: editing,
330
+ schema: view.form.schema,
331
+ namePrefix: "values",
332
+ extraItems
333
+ }
334
+ ) : null,
335
+ /* @__PURE__ */ jsx4(deps.Actions, { isSaving: saving, onClose })
336
+ ] }) })
337
+ }
338
+ );
339
+ };
340
+ }
341
+
342
+ // src/components/RuntimeSubformField.tsx
343
+ import { useEffect as useEffect2, useMemo as useMemo5, useRef, useState as useState3 } from "react";
344
+ import { FormProvider as FormProvider3, useForm as useForm3 } from "react-hook-form";
345
+ import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
346
+ function subformButtonLabel(subform) {
347
+ return subform.buttonLabel?.trim() || subform.label;
348
+ }
349
+ function parentValue(entry, field) {
350
+ if (!entry) return void 0;
351
+ const value = field === "id" ? entry.id : entry.values[field];
352
+ if (typeof value === "string") return value;
353
+ if (typeof value === "number" || typeof value === "boolean") return String(value);
354
+ return void 0;
355
+ }
356
+ function isDbTableSource2(source) {
357
+ return source?.type === "dbTable" && "tableName" in source;
358
+ }
359
+ function subformFallbackKey(view) {
360
+ return view.id;
361
+ }
362
+ function viewTableName(view) {
363
+ const source = view.list?.source;
364
+ return isDbTableSource2(source) ? source.tableName : subformFallbackKey(view);
365
+ }
366
+ function draftEntry(values, editing) {
367
+ const now = (/* @__PURE__ */ new Date()).toISOString();
368
+ return {
369
+ id: editing?.id ?? crypto.randomUUID(),
370
+ viewId: editing?.viewId ?? "",
371
+ values: editing ? values.values : { ...values.values, _draftNew: true },
372
+ version: editing?.version ?? 0,
373
+ createdAt: editing?.createdAt ?? now,
374
+ updatedAt: now
375
+ };
376
+ }
377
+ function RuntimeSubformEntryDialog({
378
+ open,
379
+ title,
380
+ view,
381
+ childField,
382
+ parentValue: linkedParentValue,
383
+ editing,
384
+ isSaving,
385
+ deps,
386
+ onClose,
387
+ onSave
388
+ }) {
389
+ const defaultValues = useMemo5(() => {
390
+ const values = createBuilderEntryDefaultValues(view, editing);
391
+ if (linkedParentValue) {
392
+ values.values[childField] = editing?.values[childField] ?? linkedParentValue;
393
+ }
394
+ return values;
395
+ }, [childField, editing, linkedParentValue, view]);
396
+ const form = useForm3({
397
+ defaultValues,
398
+ values: open ? defaultValues : void 0
399
+ });
400
+ const onSubmit = form.handleSubmit(async (values) => {
401
+ try {
402
+ await onSave({
403
+ id: editing?.id,
404
+ input: {
405
+ ...values,
406
+ values: {
407
+ ...values.values,
408
+ ...linkedParentValue ? { [childField]: linkedParentValue } : {}
409
+ }
410
+ }
411
+ });
412
+ onClose();
413
+ deps.notifications.success(editing ? "Section \u0445\u0430\u0434\u0433\u0430\u043B\u0430\u0433\u0434\u043B\u0430\u0430" : "Section \u043D\u044D\u043C\u044D\u0433\u0434\u043B\u044D\u044D");
414
+ } catch (error) {
415
+ deps.notifications.error(
416
+ deps.notifications.errorMessage(error, "Subform \u0445\u0430\u0434\u0433\u0430\u043B\u0430\u0445\u0430\u0434 \u0430\u043B\u0434\u0430\u0430 \u0433\u0430\u0440\u043B\u0430\u0430")
417
+ );
418
+ }
419
+ });
420
+ return /* @__PURE__ */ jsx5(deps.DialogShell, { open, title, description: view.title, onClose, children: /* @__PURE__ */ jsx5(FormProvider3, { ...form, children: /* @__PURE__ */ jsxs4(
421
+ "form",
422
+ {
423
+ className: deps.dialogFormClassName,
424
+ onSubmit: (event) => {
425
+ event.stopPropagation();
426
+ void onSubmit(event);
427
+ },
428
+ noValidate: true,
429
+ children: [
430
+ view.form ? /* @__PURE__ */ jsx5(
431
+ deps.DialogFields,
432
+ {
433
+ formId: view.form.id,
434
+ viewId: view.id,
435
+ schema: view.form.schema,
436
+ namePrefix: "values"
437
+ }
438
+ ) : null,
439
+ /* @__PURE__ */ jsx5(deps.DialogActions, { isSaving, onClose })
440
+ ]
441
+ }
442
+ ) }) });
443
+ }
444
+ function createRuntimeSubformFieldComponent(deps) {
445
+ return function RuntimeSubformField({
446
+ subform,
447
+ parentEntry,
448
+ draftRows = [],
449
+ onDraftRowsChange
450
+ }) {
451
+ const [isEntryDialogOpen, setEntryDialogOpen] = useState3(false);
452
+ const [editing, setEditing] = useState3(null);
453
+ const initializedDraft = useRef(false);
454
+ const linkedValue = parentValue(parentEntry, subform.parentField);
455
+ const isDraftMode = Boolean(onDraftRowsChange);
456
+ const canFetchBackendRows = Boolean(linkedValue);
457
+ const canUseBackendRows = canFetchBackendRows && !isDraftMode;
458
+ const isReady = Boolean(
459
+ subform.viewId && subform.childField && (linkedValue || onDraftRowsChange)
460
+ );
461
+ const tableState = deps.useDataTableState({ pageSize: 5 });
462
+ const query = useMemo5(
463
+ () => ({
464
+ ...tableState.query,
465
+ filterField: subform.childField,
466
+ filterValue: linkedValue ?? ""
467
+ }),
468
+ [linkedValue, subform.childField, tableState.query]
469
+ );
470
+ const viewQuery = deps.hooks.useRuntimeBuilderView(subform.viewId, Boolean(subform.viewId));
471
+ const entriesQuery = deps.hooks.useBuilderViewEntries(
472
+ subform.viewId,
473
+ query,
474
+ isReady && (canUseBackendRows || isDraftMode && canFetchBackendRows)
475
+ );
476
+ const save = deps.hooks.useSaveBuilderViewEntry(subform.viewId);
477
+ const view = viewQuery.data;
478
+ const columns = useMemo5(() => view ? deps.buildColumns(view) : [], [view]);
479
+ const rows = (canUseBackendRows ? entriesQuery.data?.items ?? [] : draftRows).filter(
480
+ (row) => row.values._delete !== true
481
+ );
482
+ const table = deps.useDataTable({
483
+ columns,
484
+ data: rows,
485
+ rowCount: canUseBackendRows ? entriesQuery.data?.total ?? 0 : rows.length,
486
+ state: tableState,
487
+ getRowId: (row) => row.id
488
+ });
489
+ const canOpen = isReady && Boolean(view?.form) && !viewQuery.isPending;
490
+ const selectedIds = new Set(table.selectedIds);
491
+ useEffect2(() => {
492
+ if (!isDraftMode || !view || initializedDraft.current || !entriesQuery.data) return;
493
+ initializedDraft.current = true;
494
+ onDraftRowsChange?.({
495
+ subformKey: subform.key,
496
+ dataKey: viewTableName(view),
497
+ rows: entriesQuery.data.items
498
+ });
499
+ }, [entriesQuery.data, isDraftMode, onDraftRowsChange, subform.key, view]);
500
+ return /* @__PURE__ */ jsxs4(
501
+ deps.Shell,
502
+ {
503
+ label: subform.label,
504
+ buttonLabel: subformButtonLabel(subform),
505
+ canOpen,
506
+ missingParentDescription: !linkedValue && !onDraftRowsChange ? `\u042D\u0445\u043B\u044D\u044D\u0434 parent \u043C\u04E9\u0440\u0438\u0439\u0433 \u0445\u0430\u0434\u0433\u0430\u043B\u043D\u0430, \u044D\u0441\u0432\u044D\u043B ${subform.parentField} \u0442\u0430\u043B\u0431\u0430\u0440\u044B\u043D \u0443\u0442\u0433\u044B\u0433 \u0431\u04E9\u0433\u043B\u04E9\u043D\u04E9.` : void 0,
507
+ onAdd: () => {
508
+ setEditing(null);
509
+ setEntryDialogOpen(true);
510
+ },
511
+ children: [
512
+ view?.list && (linkedValue || draftRows.length > 0) ? /* @__PURE__ */ jsx5(
513
+ deps.DataPanel,
514
+ {
515
+ controller: table,
516
+ isLoading: viewQuery.isPending || canUseBackendRows && entriesQuery.isPending,
517
+ showDraftDelete: isDraftMode && table.selectedIds.length > 0,
518
+ onRowClick: (entry) => {
519
+ setEditing(entry);
520
+ setEntryDialogOpen(true);
521
+ },
522
+ onDeleteSelected: () => {
523
+ if (!view) return;
524
+ onDraftRowsChange?.({
525
+ subformKey: subform.key,
526
+ dataKey: viewTableName(view),
527
+ rows: draftRows.filter((row) => !(selectedIds.has(row.id) && row.values._draftNew === true)).map(
528
+ (row) => selectedIds.has(row.id) ? { ...row, values: { ...row.values, _delete: true } } : row
529
+ )
530
+ });
531
+ table.clearSelection();
532
+ }
533
+ }
534
+ ) : null,
535
+ view ? /* @__PURE__ */ jsx5(
536
+ RuntimeSubformEntryDialog,
537
+ {
538
+ open: isEntryDialogOpen,
539
+ title: subform.label,
540
+ view,
541
+ childField: subform.childField,
542
+ parentValue: linkedValue,
543
+ editing,
544
+ isSaving: canUseBackendRows ? save.isPending : false,
545
+ deps,
546
+ onClose: () => {
547
+ setEntryDialogOpen(false);
548
+ setEditing(null);
549
+ },
550
+ onSave: async (args) => {
551
+ if (!isDraftMode && canUseBackendRows) {
552
+ await save.mutateAsync(args);
553
+ await entriesQuery.refetch();
554
+ return;
555
+ }
556
+ if (!onDraftRowsChange) return;
557
+ const nextEntry = {
558
+ ...draftEntry(args.input, editing),
559
+ viewId: view.id
560
+ };
561
+ onDraftRowsChange({
562
+ subformKey: subform.key,
563
+ dataKey: viewTableName(view),
564
+ rows: editing ? draftRows.map((row) => row.id === editing.id ? nextEntry : row) : [...draftRows, nextEntry]
565
+ });
566
+ }
567
+ }
568
+ ) : null
569
+ ]
570
+ }
571
+ );
572
+ };
573
+ }
574
+ export {
575
+ createDynamicFormComponent,
576
+ createDynamicListComponent,
577
+ createDynamicViewComponent,
578
+ createRuntimeEntryDialogComponent,
579
+ createRuntimeSubformFieldComponent
580
+ };
581
+ //# sourceMappingURL=index.js.map