@duke333/builder-ui 0.2.3 → 0.2.5
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/README.md +18 -0
- package/dist/{BuilderAdminPages-DrOrFyIX.d.ts → BuilderAdminPages-bV-lwDOp.d.ts} +15 -0
- package/dist/{RuntimeEntryDialog-Bw741XbS.d.ts → RuntimeEntryDialog-B4TbF8os.d.ts} +1 -1
- package/dist/admin/index.d.ts +2 -2
- package/dist/admin/index.js +55 -4
- package/dist/admin/index.js.map +1 -1
- package/dist/api/index.d.ts +14 -0
- package/dist/api/index.js +19 -2
- package/dist/api/index.js.map +1 -1
- package/dist/components/index.d.ts +4 -3
- package/dist/components/index.js +31 -12
- package/dist/components/index.js.map +1 -1
- package/dist/hooks/index.js +30 -3
- package/dist/hooks/index.js.map +1 -1
- package/dist/index.d.ts +157 -22
- package/dist/index.js +1054 -536
- package/dist/index.js.map +1 -1
- package/dist/integration/index.d.ts +1 -1
- package/dist/integration/index.js +104 -9
- package/dist/integration/index.js.map +1 -1
- package/dist/runtime/index.d.ts +16 -26
- package/dist/runtime/index.js +41 -1
- package/dist/runtime/index.js.map +1 -1
- package/dist/runtimeUtils-CCtLyIf1.d.ts +33 -0
- package/dist/styles.css +198 -0
- package/dist/styles.css.map +1 -1
- package/package.json +5 -2
package/README.md
CHANGED
|
@@ -53,6 +53,24 @@ loading, empty, errors, focus restoration, and row action isolation. Runtime for
|
|
|
53
53
|
|
|
54
54
|
The existing `createDynamic*Component` factories remain available as the advanced headless API.
|
|
55
55
|
|
|
56
|
+
## Form Layout Presentation
|
|
57
|
+
|
|
58
|
+
Form layout groups stay backward-compatible and render as stacked sections by default. Set the
|
|
59
|
+
layout presentation to `tabs` when each group should be shown as a tab:
|
|
60
|
+
|
|
61
|
+
```ts
|
|
62
|
+
layout: {
|
|
63
|
+
presentation: "tabs",
|
|
64
|
+
groups: [
|
|
65
|
+
{ id: "general", title: "General", columns: 12, fields: [] },
|
|
66
|
+
{ id: "content", title: "Content", columns: 12, fields: [] },
|
|
67
|
+
],
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
The ready runtime keeps inactive tab fields mounted so their form state and validation remain
|
|
72
|
+
intact. Headless consumers should preserve the same behavior in their form adapter.
|
|
73
|
+
|
|
56
74
|
## Validation
|
|
57
75
|
|
|
58
76
|
```bash
|
|
@@ -46,6 +46,10 @@ type BuilderEditorField<TFieldType extends string> = {
|
|
|
46
46
|
required: boolean;
|
|
47
47
|
hidden?: boolean;
|
|
48
48
|
disabled?: boolean;
|
|
49
|
+
storage?: "s3" | "server";
|
|
50
|
+
contentKind?: "image" | "file";
|
|
51
|
+
multiple?: boolean;
|
|
52
|
+
maxBytes?: number;
|
|
49
53
|
placeholder?: string;
|
|
50
54
|
description?: string;
|
|
51
55
|
options?: BuilderEditorSelectOption[];
|
|
@@ -83,6 +87,7 @@ type BuilderEditorFormLayoutGroup = {
|
|
|
83
87
|
fields?: BuilderEditorFormLayoutField[];
|
|
84
88
|
};
|
|
85
89
|
type BuilderEditorFormLayout = {
|
|
90
|
+
presentation?: "stacked" | "tabs";
|
|
86
91
|
groups?: BuilderEditorFormLayoutGroup[];
|
|
87
92
|
};
|
|
88
93
|
type BuilderEditorColumn = {
|
|
@@ -123,6 +128,10 @@ type BuilderFormEditorFieldValues<TFieldType extends string = string> = {
|
|
|
123
128
|
required: boolean;
|
|
124
129
|
hidden: boolean;
|
|
125
130
|
disabled: boolean;
|
|
131
|
+
storage?: "s3" | "server";
|
|
132
|
+
contentKind?: "image" | "file";
|
|
133
|
+
multiple?: boolean;
|
|
134
|
+
maxMegabytes?: number;
|
|
126
135
|
placeholder?: string;
|
|
127
136
|
optionsText?: string;
|
|
128
137
|
optionsMode: "static" | "table";
|
|
@@ -181,6 +190,7 @@ type BuilderFormEditorValues<TFieldType extends string = string, TTriggerEvent e
|
|
|
181
190
|
sourceTable: string;
|
|
182
191
|
apiBasePath?: string;
|
|
183
192
|
fields: BuilderFormEditorFieldValues<TFieldType>[];
|
|
193
|
+
layoutPresentation: "stacked" | "tabs";
|
|
184
194
|
layoutGroups: BuilderFormEditorLayoutGroupValues[];
|
|
185
195
|
subforms?: BuilderFormEditorSubformValues[];
|
|
186
196
|
triggers: BuilderEditorTriggerValues<TTriggerEvent>[];
|
|
@@ -261,6 +271,10 @@ declare function builderFormEditorInputFromValues<TFieldType extends string, TTr
|
|
|
261
271
|
required: boolean;
|
|
262
272
|
hidden: boolean;
|
|
263
273
|
disabled: boolean;
|
|
274
|
+
storage: "s3" | "server" | undefined;
|
|
275
|
+
contentKind: "file" | "image" | undefined;
|
|
276
|
+
multiple: boolean | undefined;
|
|
277
|
+
maxBytes: number | undefined;
|
|
264
278
|
placeholder: string;
|
|
265
279
|
options: BuilderEditorSelectOption[] | undefined;
|
|
266
280
|
optionsSource: {
|
|
@@ -283,6 +297,7 @@ declare function builderFormEditorInputFromValues<TFieldType extends string, TTr
|
|
|
283
297
|
}[];
|
|
284
298
|
}[];
|
|
285
299
|
layout: {
|
|
300
|
+
presentation: "stacked" | "tabs";
|
|
286
301
|
groups: BuilderFormEditorLayoutGroupValues[];
|
|
287
302
|
};
|
|
288
303
|
subforms: {
|
|
@@ -2,7 +2,7 @@ import * as react from 'react';
|
|
|
2
2
|
import { ComponentType, ReactNode } from 'react';
|
|
3
3
|
import { BuilderApiContracts } from './api/index.js';
|
|
4
4
|
import { BuilderHooks } from './hooks/index.js';
|
|
5
|
-
import { BuilderRuntimeFormSchemaLike, BuilderRuntimeFormValues, BuilderRuntimeEntryLike, BuilderRuntimeViewLike, BuilderRuntimePresentation, BuilderRuntimeEntryValues } from './
|
|
5
|
+
import { a as BuilderRuntimeFormSchemaLike, d as BuilderRuntimeFormValues, b as BuilderRuntimeEntryLike, e as BuilderRuntimeViewLike, B as BuilderRuntimePresentation, c as BuilderRuntimeEntryValues } from './runtimeUtils-CCtLyIf1.js';
|
|
6
6
|
|
|
7
7
|
type DynamicFormContracts = BuilderApiContracts & {
|
|
8
8
|
BuilderForm: {
|
package/dist/admin/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { C as BuilderViewEditorEntity, D as BuilderViewEditorValues, X as BuilderFormEditorLayoutGroupValues, u as BuilderFormEditorValues, s as BuilderFormEditorFieldValues, Y as BuilderFormEditorSubformValues } from '../BuilderAdminPages-
|
|
2
|
-
export { B as BUILDER_EDITOR_NONE_VALUE, a as BuilderAdminPageContracts, b as BuilderAdminPagesOptions, c as BuilderAdminPagesRoutes, d as BuilderDefaultEntity, e as BuilderDefaultEntityListResult, f as BuilderDefaultEntityManagerDependencies, g as BuilderDefaultEntityManagerLabels, h as BuilderDefaultEntityManagerState, i as BuilderDefaultEntityMutation, j as BuilderDefaultEntityQueryResult, k as BuilderDefaultFormEditorBodyOptions, l as BuilderDefaultListEditorBodyOptions, m as BuilderDefaultOption, n as BuilderEditorDbTable, o as BuilderEditorSelectOption, p as BuilderEditorTriggerValues, q as BuilderFormEditorBodyProps, r as BuilderFormEditorEntity, t as BuilderFormEditorPageDependencies, v as BuilderListEditorBodyProps, w as BuilderListEditorColumnValues, x as BuilderListEditorEntity, y as BuilderListEditorOrderByValues, z as BuilderListEditorPageDependencies, A as BuilderListEditorValues, E as builderEditorOptionsToText, F as builderEditorSearchFieldsToText, G as builderEditorTextToOptions, H as builderEditorTextToSearchFields, Z as builderFormEditorDefaultLayoutGroups, _ as builderFormEditorDefaultSpan, I as builderFormEditorFieldsFromTable, J as builderFormEditorInputFromValues, K as builderFormEditorValuesFromEntity, L as builderListEditorColumnsFromTable, M as builderListEditorInputFromValues, N as builderListEditorValuesFromEntity, O as builderViewEditorInputFromValues, P as builderViewEditorValuesFromEntity, Q as createBuilderAdminPages, R as createBuilderDefaultEntityManagerComponent, S as createBuilderDefaultFormEditorBody, T as createBuilderDefaultListEditorBody, U as createBuilderFormEditorPageComponent, V as createBuilderListEditorPageComponent, W as getBuilderEditorTriggerRoute } from '../BuilderAdminPages-
|
|
1
|
+
import { C as BuilderViewEditorEntity, D as BuilderViewEditorValues, X as BuilderFormEditorLayoutGroupValues, u as BuilderFormEditorValues, s as BuilderFormEditorFieldValues, Y as BuilderFormEditorSubformValues } from '../BuilderAdminPages-bV-lwDOp.js';
|
|
2
|
+
export { B as BUILDER_EDITOR_NONE_VALUE, a as BuilderAdminPageContracts, b as BuilderAdminPagesOptions, c as BuilderAdminPagesRoutes, d as BuilderDefaultEntity, e as BuilderDefaultEntityListResult, f as BuilderDefaultEntityManagerDependencies, g as BuilderDefaultEntityManagerLabels, h as BuilderDefaultEntityManagerState, i as BuilderDefaultEntityMutation, j as BuilderDefaultEntityQueryResult, k as BuilderDefaultFormEditorBodyOptions, l as BuilderDefaultListEditorBodyOptions, m as BuilderDefaultOption, n as BuilderEditorDbTable, o as BuilderEditorSelectOption, p as BuilderEditorTriggerValues, q as BuilderFormEditorBodyProps, r as BuilderFormEditorEntity, t as BuilderFormEditorPageDependencies, v as BuilderListEditorBodyProps, w as BuilderListEditorColumnValues, x as BuilderListEditorEntity, y as BuilderListEditorOrderByValues, z as BuilderListEditorPageDependencies, A as BuilderListEditorValues, E as builderEditorOptionsToText, F as builderEditorSearchFieldsToText, G as builderEditorTextToOptions, H as builderEditorTextToSearchFields, Z as builderFormEditorDefaultLayoutGroups, _ as builderFormEditorDefaultSpan, I as builderFormEditorFieldsFromTable, J as builderFormEditorInputFromValues, K as builderFormEditorValuesFromEntity, L as builderListEditorColumnsFromTable, M as builderListEditorInputFromValues, N as builderListEditorValuesFromEntity, O as builderViewEditorInputFromValues, P as builderViewEditorValuesFromEntity, Q as createBuilderAdminPages, R as createBuilderDefaultEntityManagerComponent, S as createBuilderDefaultFormEditorBody, T as createBuilderDefaultListEditorBody, U as createBuilderFormEditorPageComponent, V as createBuilderListEditorPageComponent, W as getBuilderEditorTriggerRoute } from '../BuilderAdminPages-bV-lwDOp.js';
|
|
3
3
|
import * as react from 'react';
|
|
4
4
|
import { ComponentType, ReactNode } from 'react';
|
|
5
5
|
import { BuilderApiContracts } from '../api/index.js';
|
package/dist/admin/index.js
CHANGED
|
@@ -45,7 +45,7 @@ function clampLayoutSpan(span, columns) {
|
|
|
45
45
|
return Math.max(1, Math.min(columns, Math.trunc(span)));
|
|
46
46
|
}
|
|
47
47
|
function builderFormEditorDefaultSpan(field) {
|
|
48
|
-
if (field.type === "textarea" || field.type === "checkbox") return 12;
|
|
48
|
+
if (field.type === "textarea" || field.type === "richtext" || field.type === "checkbox") return 12;
|
|
49
49
|
return 6;
|
|
50
50
|
}
|
|
51
51
|
function builderFormEditorDefaultLayoutGroups(fields, subforms = []) {
|
|
@@ -112,6 +112,10 @@ function builderFormEditorValuesFromEntity(form, emptyValues) {
|
|
|
112
112
|
required: field.required,
|
|
113
113
|
hidden: field.hidden ?? false,
|
|
114
114
|
disabled: field.disabled ?? false,
|
|
115
|
+
storage: field.storage ?? "s3",
|
|
116
|
+
contentKind: field.contentKind ?? "image",
|
|
117
|
+
multiple: field.multiple ?? false,
|
|
118
|
+
maxMegabytes: field.maxBytes ? field.maxBytes / (1024 * 1024) : 10,
|
|
115
119
|
placeholder: field.placeholder ?? "",
|
|
116
120
|
optionsText: builderEditorOptionsToText(field.options),
|
|
117
121
|
optionsMode: field.optionsSource?.type === "dbTable" ? "table" : "static",
|
|
@@ -141,6 +145,7 @@ function builderFormEditorValuesFromEntity(form, emptyValues) {
|
|
|
141
145
|
sourceTable: source?.type === "dbTable" ? source.tableName : BUILDER_EDITOR_NONE_VALUE,
|
|
142
146
|
apiBasePath: source?.type === "apiEndpoint" ? source.basePath : "",
|
|
143
147
|
fields,
|
|
148
|
+
layoutPresentation: form.schema.layout?.presentation ?? "stacked",
|
|
144
149
|
layoutGroups: normalizeBuilderFormEditorLayoutGroups(
|
|
145
150
|
form.schema.layout?.groups,
|
|
146
151
|
fields,
|
|
@@ -194,6 +199,10 @@ function builderFormEditorFieldsFromTable(table) {
|
|
|
194
199
|
required: !column.nullable,
|
|
195
200
|
hidden: false,
|
|
196
201
|
disabled: false,
|
|
202
|
+
storage: "s3",
|
|
203
|
+
contentKind: "image",
|
|
204
|
+
multiple: false,
|
|
205
|
+
maxMegabytes: 10,
|
|
197
206
|
placeholder: column.label,
|
|
198
207
|
optionsText: "",
|
|
199
208
|
optionsMode: "static",
|
|
@@ -230,6 +239,10 @@ function builderFormEditorInputFromValues(values) {
|
|
|
230
239
|
required: field.required,
|
|
231
240
|
hidden: field.hidden,
|
|
232
241
|
disabled: field.disabled,
|
|
242
|
+
storage: field.type === "file" ? field.storage : void 0,
|
|
243
|
+
contentKind: field.type === "file" ? field.contentKind : void 0,
|
|
244
|
+
multiple: field.type === "file" ? field.multiple : void 0,
|
|
245
|
+
maxBytes: field.type === "file" && typeof field.maxMegabytes === "number" && field.maxMegabytes > 0 ? Math.round(field.maxMegabytes * 1024 * 1024) : void 0,
|
|
233
246
|
placeholder: field.placeholder?.trim() || field.label,
|
|
234
247
|
options: field.type === "select" && field.optionsMode === "static" ? builderEditorTextToOptions(field.optionsText) : void 0,
|
|
235
248
|
optionsSource: field.type === "select" && field.optionsMode === "table" && field.optionsTable !== BUILDER_EDITOR_NONE_VALUE && field.optionsValueField !== BUILDER_EDITOR_NONE_VALUE && field.optionsLabelField !== BUILDER_EDITOR_NONE_VALUE ? {
|
|
@@ -252,6 +265,7 @@ function builderFormEditorInputFromValues(values) {
|
|
|
252
265
|
}))
|
|
253
266
|
})),
|
|
254
267
|
layout: {
|
|
268
|
+
presentation: values.layoutPresentation,
|
|
255
269
|
groups: normalizeBuilderFormEditorLayoutGroups(
|
|
256
270
|
values.layoutGroups,
|
|
257
271
|
values.fields,
|
|
@@ -320,7 +334,7 @@ function builderViewEditorInputFromValues(values, parseTriggers) {
|
|
|
320
334
|
}
|
|
321
335
|
|
|
322
336
|
// src/admin/BuilderDefaultEditorBodies.tsx
|
|
323
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
337
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
324
338
|
var styles = {
|
|
325
339
|
page: {
|
|
326
340
|
display: "grid",
|
|
@@ -583,6 +597,30 @@ function createBuilderDefaultFormEditorBody(options) {
|
|
|
583
597
|
/* @__PURE__ */ jsx("input", { type: "checkbox", ...form.register(`fields.${index}.disabled`) }),
|
|
584
598
|
"Disabled"
|
|
585
599
|
] }),
|
|
600
|
+
fields[index]?.type === "file" ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
601
|
+
/* @__PURE__ */ jsxs("label", { style: styles.field, children: [
|
|
602
|
+
/* @__PURE__ */ jsx("span", { style: styles.label, children: "Storage" }),
|
|
603
|
+
/* @__PURE__ */ jsxs("select", { style: styles.input, ...form.register(`fields.${index}.storage`), children: [
|
|
604
|
+
/* @__PURE__ */ jsx("option", { value: "s3", children: "S3" }),
|
|
605
|
+
/* @__PURE__ */ jsx("option", { value: "server", children: "Server" })
|
|
606
|
+
] })
|
|
607
|
+
] }),
|
|
608
|
+
/* @__PURE__ */ jsxs("label", { style: styles.field, children: [
|
|
609
|
+
/* @__PURE__ */ jsx("span", { style: styles.label, children: "Content type" }),
|
|
610
|
+
/* @__PURE__ */ jsxs("select", { style: styles.input, ...form.register(`fields.${index}.contentKind`), children: [
|
|
611
|
+
/* @__PURE__ */ jsx("option", { value: "image", children: "Image" }),
|
|
612
|
+
/* @__PURE__ */ jsx("option", { value: "file", children: "File" })
|
|
613
|
+
] })
|
|
614
|
+
] }),
|
|
615
|
+
/* @__PURE__ */ jsxs("label", { style: styles.checkboxField, children: [
|
|
616
|
+
/* @__PURE__ */ jsx("input", { type: "checkbox", ...form.register(`fields.${index}.multiple`) }),
|
|
617
|
+
"Multiple"
|
|
618
|
+
] }),
|
|
619
|
+
/* @__PURE__ */ jsxs("label", { style: styles.field, children: [
|
|
620
|
+
/* @__PURE__ */ jsx("span", { style: styles.label, children: "Max size (MB)" }),
|
|
621
|
+
/* @__PURE__ */ jsx("input", { type: "number", min: "1", max: "100", style: styles.input, ...form.register(`fields.${index}.maxMegabytes`, { valueAsNumber: true }) })
|
|
622
|
+
] })
|
|
623
|
+
] }) : null,
|
|
586
624
|
/* @__PURE__ */ jsxs("label", { style: styles.field, children: [
|
|
587
625
|
/* @__PURE__ */ jsx("span", { style: styles.label, children: "Placeholder" }),
|
|
588
626
|
/* @__PURE__ */ jsx("input", { style: styles.input, ...form.register(`fields.${index}.placeholder`) })
|
|
@@ -621,6 +659,13 @@ function createBuilderDefaultFormEditorBody(options) {
|
|
|
621
659
|
}
|
|
622
660
|
)
|
|
623
661
|
] }),
|
|
662
|
+
/* @__PURE__ */ jsx("div", { style: styles.grid, children: /* @__PURE__ */ jsxs("label", { style: styles.field, children: [
|
|
663
|
+
/* @__PURE__ */ jsx("span", { style: styles.label, children: "Group presentation" }),
|
|
664
|
+
/* @__PURE__ */ jsxs("select", { style: styles.input, ...form.register("layoutPresentation"), children: [
|
|
665
|
+
/* @__PURE__ */ jsx("option", { value: "stacked", children: "Stacked sections" }),
|
|
666
|
+
/* @__PURE__ */ jsx("option", { value: "tabs", children: "Tabs" })
|
|
667
|
+
] })
|
|
668
|
+
] }) }),
|
|
624
669
|
form.watch("layoutGroups").map((group, groupIndex) => /* @__PURE__ */ jsxs("div", { style: styles.row, children: [
|
|
625
670
|
/* @__PURE__ */ jsxs("label", { style: styles.field, children: [
|
|
626
671
|
/* @__PURE__ */ jsx("span", { style: styles.label, children: "Group title" }),
|
|
@@ -1193,7 +1238,7 @@ function createBuilderDefaultEntityManagerComponent(deps) {
|
|
|
1193
1238
|
// src/admin/BuilderDefaultViewEditorPage.tsx
|
|
1194
1239
|
import { useEffect } from "react";
|
|
1195
1240
|
import { useForm } from "react-hook-form";
|
|
1196
|
-
import { Fragment, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
1241
|
+
import { Fragment as Fragment2, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
1197
1242
|
var styles3 = {
|
|
1198
1243
|
page: {
|
|
1199
1244
|
display: "grid",
|
|
@@ -1380,7 +1425,7 @@ function createBuilderDefaultViewEditorPage(options) {
|
|
|
1380
1425
|
(lists.data ?? []).map((item) => /* @__PURE__ */ jsx3("option", { value: item.id, children: item.title }, item.id))
|
|
1381
1426
|
] })
|
|
1382
1427
|
] }),
|
|
1383
|
-
showPermissions ? /* @__PURE__ */ jsxs3(
|
|
1428
|
+
showPermissions ? /* @__PURE__ */ jsxs3(Fragment2, { children: [
|
|
1384
1429
|
/* @__PURE__ */ jsxs3("label", { style: styles3.field, children: [
|
|
1385
1430
|
/* @__PURE__ */ jsx3("span", { style: styles3.label, children: "Read permission" }),
|
|
1386
1431
|
/* @__PURE__ */ jsxs3("select", { style: styles3.input, ...form.register("permissionRead"), children: [
|
|
@@ -1544,6 +1589,7 @@ import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
|
1544
1589
|
var defaultFieldTypeOptions = [
|
|
1545
1590
|
{ value: "text", label: "Text" },
|
|
1546
1591
|
{ value: "textarea", label: "Textarea" },
|
|
1592
|
+
{ value: "richtext", label: "Rich text" },
|
|
1547
1593
|
{ value: "number", label: "Number" },
|
|
1548
1594
|
{ value: "money", label: "Money" },
|
|
1549
1595
|
{ value: "select", label: "Select" },
|
|
@@ -1654,6 +1700,10 @@ function createBuilderAdminPages({
|
|
|
1654
1700
|
required: true,
|
|
1655
1701
|
hidden: false,
|
|
1656
1702
|
disabled: false,
|
|
1703
|
+
storage: "s3",
|
|
1704
|
+
contentKind: "image",
|
|
1705
|
+
multiple: false,
|
|
1706
|
+
maxMegabytes: 10,
|
|
1657
1707
|
placeholder: "",
|
|
1658
1708
|
optionsText: "",
|
|
1659
1709
|
optionsMode: "static",
|
|
@@ -1673,6 +1723,7 @@ function createBuilderAdminPages({
|
|
|
1673
1723
|
sourceTable: BUILDER_EDITOR_NONE_VALUE,
|
|
1674
1724
|
apiBasePath: "",
|
|
1675
1725
|
fields: [emptyField],
|
|
1726
|
+
layoutPresentation: "stacked",
|
|
1676
1727
|
layoutGroups: builderFormEditorDefaultLayoutGroups([emptyField]),
|
|
1677
1728
|
subforms: [],
|
|
1678
1729
|
triggers: [],
|