@shwfed/nuxt 0.11.46 → 0.11.48

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.
@@ -7,12 +7,14 @@ import { computed, nextTick, ref, toRaw, watch } from "vue";
7
7
  import { useI18n } from "vue-i18n";
8
8
  import {
9
9
  CalendarFieldC,
10
+ ContainerFieldC,
10
11
  EmptyFieldC,
11
12
  FieldGroupC,
12
13
  FieldGroupStyleC,
13
14
  FieldsBodyC,
14
15
  FieldsConfigC,
15
16
  FieldsStyleC,
17
+ MarkdownBodyFieldC,
16
18
  MarkdownFieldC,
17
19
  NumberFieldC,
18
20
  RadioGroupFieldC,
@@ -45,6 +47,8 @@ import { NativeSelect, NativeSelectOption } from "../native-select";
45
47
  import { Switch } from "../switch";
46
48
  import { Textarea } from "../textarea";
47
49
  const ROOT_FIELD_GROUP_VALUE = "__root__";
50
+ const GROUP_OWNER_PREFIX = "group:";
51
+ const CONTAINER_OWNER_PREFIX = "container:";
48
52
  const props = defineProps({
49
53
  config: { type: null, required: true }
50
54
  });
@@ -72,10 +76,12 @@ const fieldTypeOptions = computed(() => [
72
76
  { type: "textarea", label: t("field-type-textarea") },
73
77
  { type: "number", label: t("field-type-number") },
74
78
  { type: "markdown", label: t("field-type-markdown") },
79
+ { type: "markdown-body", label: t("field-type-markdown-body") },
75
80
  { type: "select", label: t("field-type-select") },
76
81
  { type: "radio", label: t("field-type-radio") },
77
82
  { type: "calendar", label: t("field-type-calendar") },
78
83
  { type: "upload", label: t("field-type-upload") },
84
+ { type: "container", label: t("field-type-container") },
79
85
  { type: "empty", label: t("field-type-empty") },
80
86
  { type: "slot", label: t("field-type-slot") }
81
87
  ]);
@@ -84,28 +90,83 @@ const generalItem = computed(() => ({
84
90
  label: t("general")
85
91
  }));
86
92
  const normalizedSearch = computed(() => search.value.trim().toLocaleLowerCase());
93
+ function cloneValue(value) {
94
+ return JSON.parse(JSON.stringify(toRaw(value)));
95
+ }
96
+ function createContainerDraftField(field) {
97
+ const { fields, ...rest } = cloneValue(field);
98
+ return {
99
+ draftId: createDraftId(),
100
+ field: {
101
+ ...rest,
102
+ fields: []
103
+ },
104
+ children: cloneFields(fields)
105
+ };
106
+ }
107
+ function findDraftField(fields, draftId) {
108
+ for (const field of fields) {
109
+ if (field.draftId === draftId) {
110
+ return field;
111
+ }
112
+ const child = findDraftField(field.children, draftId);
113
+ if (child) {
114
+ return child;
115
+ }
116
+ }
117
+ return void 0;
118
+ }
119
+ function findFieldOwnerInFields(fields, draftId, owner) {
120
+ for (const field of fields) {
121
+ if (field.draftId === draftId) {
122
+ return owner;
123
+ }
124
+ if (field.field.type !== "container") {
125
+ continue;
126
+ }
127
+ const childOwner = findFieldOwnerInFields(field.children, draftId, {
128
+ kind: "container",
129
+ draftId: field.draftId
130
+ });
131
+ if (childOwner) {
132
+ return childOwner;
133
+ }
134
+ }
135
+ return void 0;
136
+ }
137
+ function findFieldOwnerByDraftId(draftId) {
138
+ const rootOwner = findFieldOwnerInFields(draftFields.value, draftId, {
139
+ kind: "root"
140
+ });
141
+ if (rootOwner) {
142
+ return rootOwner;
143
+ }
144
+ for (const group of draftGroups.value) {
145
+ const groupOwner = findFieldOwnerInFields(group.fields, draftId, {
146
+ kind: "group",
147
+ draftId: group.draftId
148
+ });
149
+ if (groupOwner) {
150
+ return groupOwner;
151
+ }
152
+ }
153
+ return void 0;
154
+ }
87
155
  const selectedGroup = computed(() => draftGroups.value.find((group) => group.draftId === selectedItemId.value));
88
156
  const selectedField = computed(() => {
89
- const rootField = draftFields.value.find((item) => item.draftId === selectedItemId.value);
157
+ const rootField = findDraftField(draftFields.value, selectedItemId.value);
90
158
  if (rootField) {
91
159
  return rootField;
92
160
  }
93
161
  for (const group of draftGroups.value) {
94
- const field = group.fields.find((item) => item.draftId === selectedItemId.value);
162
+ const field = findDraftField(group.fields, selectedItemId.value);
95
163
  if (field) {
96
164
  return field;
97
165
  }
98
166
  }
99
167
  return void 0;
100
168
  });
101
- const selectedFieldGroup = computed(() => {
102
- for (const group of draftGroups.value) {
103
- if (group.fields.some((item) => item.draftId === selectedItemId.value)) {
104
- return group;
105
- }
106
- }
107
- return void 0;
108
- });
169
+ const selectedFieldOwner = computed(() => findFieldOwnerByDraftId(selectedItemId.value));
109
170
  const usesContentsOrientation = computed(() => draftOrientation.value === "contents");
110
171
  const selectedFieldValidationRules = computed(() => {
111
172
  const field = selectedField.value?.field;
@@ -127,9 +188,13 @@ function createDefaultLocaleValue() {
127
188
  return [{ locale: "zh", message: "" }];
128
189
  }
129
190
  function createDraftField(field) {
191
+ if (field.type === "container") {
192
+ return createContainerDraftField(field);
193
+ }
130
194
  return {
131
195
  draftId: createDraftId(),
132
- field: JSON.parse(JSON.stringify(toRaw(field)))
196
+ field: cloneValue(field),
197
+ children: []
133
198
  };
134
199
  }
135
200
  function cloneFields(fields) {
@@ -138,11 +203,11 @@ function cloneFields(fields) {
138
203
  function createDraftGroup(group) {
139
204
  return {
140
205
  draftId: createDraftId(),
141
- group: JSON.parse(JSON.stringify(toRaw({
206
+ group: cloneValue({
142
207
  id: group.id,
143
208
  style: group.style,
144
209
  fields: []
145
- }))),
210
+ }),
146
211
  fields: cloneFields(group.fields)
147
212
  };
148
213
  }
@@ -162,33 +227,54 @@ function getFieldTypeLabel(type) {
162
227
  return t(`field-type-${type}`);
163
228
  }
164
229
  function isPassiveField(field) {
165
- return field.type === "slot" || field.type === "empty";
230
+ return field.type === "empty";
166
231
  }
167
232
  function isMarkdownField(field) {
168
233
  return field.type === "markdown";
169
234
  }
235
+ function isMarkdownBodyField(field) {
236
+ return field.type === "markdown-body";
237
+ }
238
+ function isMarkdownContentField(field) {
239
+ return isMarkdownField(field) || isMarkdownBodyField(field);
240
+ }
241
+ function hasFieldLabel(field) {
242
+ return field.type !== "empty" && !isMarkdownBodyField(field);
243
+ }
244
+ function supportsFieldCellStyles(field) {
245
+ return field.type !== "empty" && !isMarkdownBodyField(field);
246
+ }
170
247
  function isPathlessField(field) {
171
- return isPassiveField(field) || isMarkdownField(field);
248
+ return field.type === "slot" || field.type === "empty" || isMarkdownContentField(field) || field.type === "container";
172
249
  }
173
250
  function isInteractiveField(field) {
174
251
  return !isPathlessField(field);
175
252
  }
176
- function getSlotFieldLabel(_) {
177
- return getFieldTypeLabel("slot");
253
+ function getSlotFieldLabel(field) {
254
+ return getFieldChineseTitle(field) ?? getFieldTypeLabel("slot");
178
255
  }
179
256
  function getEmptyFieldLabel(_) {
180
257
  return getFieldTypeLabel("empty");
181
258
  }
259
+ function getContainerFieldLabel(field) {
260
+ return getFieldChineseTitle(field) ?? getUnnamedFieldLabel(field);
261
+ }
182
262
  function getUnnamedFieldLabel(field) {
183
263
  return t("unnamed-field", {
184
264
  type: getFieldTypeLabel(field.type)
185
265
  });
186
266
  }
267
+ function getFieldTitleValue(field) {
268
+ if (!hasFieldLabel(field)) {
269
+ return createDefaultLocaleValue();
270
+ }
271
+ return field.title ?? createDefaultLocaleValue();
272
+ }
187
273
  function getFieldChineseTitle(field) {
188
- if (isPassiveField(field)) {
274
+ if (!hasFieldLabel(field)) {
189
275
  return void 0;
190
276
  }
191
- const zhTitle = field.title.find((item) => item.locale === "zh");
277
+ const zhTitle = field.title?.find((item) => item.locale === "zh");
192
278
  if (!zhTitle) {
193
279
  return void 0;
194
280
  }
@@ -199,6 +285,9 @@ function getFieldListLabel(field) {
199
285
  if (field.type === "slot") {
200
286
  return getSlotFieldLabel(field);
201
287
  }
288
+ if (field.type === "container") {
289
+ return getContainerFieldLabel(field);
290
+ }
202
291
  if (field.type === "empty") {
203
292
  return getEmptyFieldLabel(field);
204
293
  }
@@ -209,32 +298,49 @@ function getGroupListLabel(index) {
209
298
  index: index + 1
210
299
  });
211
300
  }
212
- const rootFieldItems = computed(() => draftFields.value.map((item) => ({
213
- itemId: item.draftId,
214
- fieldId: item.field.id,
215
- label: getFieldListLabel(item.field),
216
- path: isPathlessField(item.field) ? void 0 : item.field.path,
217
- searchMeta: isPathlessField(item.field) ? item.field.id : [item.field.path, item.field.id].filter(Boolean).join(" "),
218
- type: item.field.type
219
- })));
301
+ function buildFieldSearchMeta(field) {
302
+ return isPathlessField(field) ? [field.id, getFieldChineseTitle(field)].filter(Boolean).join(" ") : [field.path, field.id, getFieldChineseTitle(field)].filter(Boolean).join(" ");
303
+ }
304
+ function flattenFieldItems(fields, depth, groupItemId) {
305
+ return fields.flatMap((item) => {
306
+ const currentItem = {
307
+ itemId: item.draftId,
308
+ groupItemId,
309
+ fieldId: item.field.id,
310
+ label: getFieldListLabel(item.field),
311
+ path: isPathlessField(item.field) ? void 0 : item.field.path,
312
+ searchMeta: buildFieldSearchMeta(item.field),
313
+ type: item.field.type,
314
+ depth
315
+ };
316
+ if (item.field.type !== "container") {
317
+ return [currentItem];
318
+ }
319
+ return [
320
+ currentItem,
321
+ ...flattenFieldItems(item.children, depth + 1, groupItemId)
322
+ ];
323
+ });
324
+ }
325
+ const rootFieldItems = computed(() => flattenFieldItems(draftFields.value, 0));
220
326
  const groupItems = computed(() => draftGroups.value.map((group, index) => {
221
- const fields = group.fields.map((item) => ({
222
- itemId: item.draftId,
223
- groupItemId: group.draftId,
224
- fieldId: item.field.id,
225
- label: getFieldListLabel(item.field),
226
- path: isPathlessField(item.field) ? void 0 : item.field.path,
227
- searchMeta: isPathlessField(item.field) ? item.field.id : [item.field.path, item.field.id].filter(Boolean).join(" "),
228
- type: item.field.type
229
- }));
230
327
  return {
231
328
  itemId: group.draftId,
232
329
  groupId: group.group.id,
233
330
  label: getGroupListLabel(index),
234
331
  searchMeta: group.group.id,
235
- fields
332
+ fields: flattenFieldItems(group.fields, 0, group.draftId)
236
333
  };
237
334
  }));
335
+ function getFieldOwnerValue(owner) {
336
+ if (owner.kind === "root") {
337
+ return ROOT_FIELD_GROUP_VALUE;
338
+ }
339
+ if (owner.kind === "group") {
340
+ return `${GROUP_OWNER_PREFIX}${owner.draftId}`;
341
+ }
342
+ return `${CONTAINER_OWNER_PREFIX}${owner.draftId}`;
343
+ }
238
344
  const filteredGroupItems = computed(() => {
239
345
  if (!normalizedSearch.value) {
240
346
  return groupItems.value;
@@ -265,6 +371,52 @@ const filteredRootFieldItems = computed(() => {
265
371
  });
266
372
  });
267
373
  const selectedItemLabel = computed(() => selectedField.value ? getFieldListLabel(selectedField.value.field) : selectedGroup.value ? getGroupListLabel(Math.max(draftGroups.value.findIndex((group) => group.draftId === selectedGroup.value?.draftId), 0)) : generalItem.value.label);
374
+ function collectDraftFieldIds(fields) {
375
+ return fields.flatMap((field) => [field.draftId, ...collectDraftFieldIds(field.children)]);
376
+ }
377
+ function buildFieldOwnerOptions(fields, depth, options, excludedDraftIds) {
378
+ for (const field of fields) {
379
+ if (field.field.type !== "container") {
380
+ continue;
381
+ }
382
+ if (!excludedDraftIds.has(field.draftId)) {
383
+ options.push({
384
+ value: getFieldOwnerValue({
385
+ kind: "container",
386
+ draftId: field.draftId
387
+ }),
388
+ label: `${" ".repeat(depth)}${getFieldListLabel(field.field)}`
389
+ });
390
+ }
391
+ buildFieldOwnerOptions(field.children, depth + 1, options, excludedDraftIds);
392
+ }
393
+ }
394
+ const selectedFieldOwnerOptions = computed(() => {
395
+ const options = [{
396
+ value: ROOT_FIELD_GROUP_VALUE,
397
+ label: t("field-group-none")
398
+ }];
399
+ const excludedDraftIds = new Set(
400
+ selectedField.value ? collectDraftFieldIds([selectedField.value]) : []
401
+ );
402
+ for (const group of groupItems.value) {
403
+ options.push({
404
+ value: `${GROUP_OWNER_PREFIX}${group.itemId}`,
405
+ label: group.label
406
+ });
407
+ }
408
+ buildFieldOwnerOptions(draftFields.value, 1, options, excludedDraftIds);
409
+ for (const group of draftGroups.value) {
410
+ buildFieldOwnerOptions(group.fields, 1, options, excludedDraftIds);
411
+ }
412
+ return options;
413
+ });
414
+ const selectedContainerChildItems = computed(() => {
415
+ if (selectedField.value?.field.type !== "container") {
416
+ return [];
417
+ }
418
+ return flattenFieldItems(selectedField.value.children, 1);
419
+ });
268
420
  function getFieldErrorKey(draftId, fieldKey) {
269
421
  return `${draftId}:${fieldKey}`;
270
422
  }
@@ -347,6 +499,13 @@ function normalizeField(field) {
347
499
  contentStyle: normalizeOptionalString(field.contentStyle ?? ""),
348
500
  hidden: normalizeOptionalString(field.hidden ?? "")
349
501
  };
502
+ case "markdown-body":
503
+ return {
504
+ ...field,
505
+ style: normalizeOptionalString(field.style ?? ""),
506
+ hidden: normalizeOptionalString(field.hidden ?? ""),
507
+ inline: field.inline ? true : void 0
508
+ };
350
509
  case "number":
351
510
  return {
352
511
  ...field,
@@ -426,8 +585,27 @@ function normalizeField(field) {
426
585
  case "slot":
427
586
  return {
428
587
  ...field,
588
+ title: field.title,
589
+ hideLabel: field.hideLabel ? true : void 0,
590
+ required: field.required ? true : void 0,
591
+ hidden: normalizeOptionalString(field.hidden ?? ""),
592
+ labelStyle: normalizeOptionalString(field.labelStyle ?? ""),
593
+ contentStyle: normalizeOptionalString(field.contentStyle ?? ""),
429
594
  style: normalizeOptionalString(field.style ?? "")
430
595
  };
596
+ case "container":
597
+ return {
598
+ ...field,
599
+ hideLabel: field.hideLabel ? true : void 0,
600
+ required: field.required ? true : void 0,
601
+ hidden: normalizeOptionalString(field.hidden ?? ""),
602
+ labelStyle: normalizeOptionalString(field.labelStyle ?? ""),
603
+ contentStyle: normalizeOptionalString(field.contentStyle ?? ""),
604
+ bodyOrientation: field.bodyOrientation ? normalizeOrientation(field.bodyOrientation) : void 0,
605
+ bodyBordered: field.bodyBordered ? true : void 0,
606
+ bodyStyle: normalizeOptionalString(field.bodyStyle ?? ""),
607
+ fields: []
608
+ };
431
609
  case "empty":
432
610
  return {
433
611
  ...field,
@@ -464,6 +642,12 @@ function createField(type) {
464
642
  title,
465
643
  locale: createDefaultLocaleValue()
466
644
  };
645
+ case "markdown-body":
646
+ return {
647
+ id,
648
+ type,
649
+ locale: createDefaultLocaleValue()
650
+ };
467
651
  case "select":
468
652
  case "radio":
469
653
  return {
@@ -495,6 +679,14 @@ function createField(type) {
495
679
  path: "",
496
680
  title
497
681
  };
682
+ case "container":
683
+ return {
684
+ id,
685
+ type,
686
+ hideLabel: void 0,
687
+ title,
688
+ fields: []
689
+ };
498
690
  case "empty":
499
691
  return {
500
692
  id,
@@ -542,6 +734,120 @@ function moveField(fields, oldIndex, newIndex) {
542
734
  nextFields.splice(newIndex, 0, movedField);
543
735
  return nextFields;
544
736
  }
737
+ function mapDraftFields(fields, updater) {
738
+ return fields.map((item) => {
739
+ const nextItem = updater(item);
740
+ if (nextItem.field.type !== "container") {
741
+ return nextItem;
742
+ }
743
+ return {
744
+ ...nextItem,
745
+ children: mapDraftFields(nextItem.children, updater)
746
+ };
747
+ });
748
+ }
749
+ function updateContainerFields(fields, containerDraftId, updater) {
750
+ return fields.map((item) => {
751
+ if (item.field.type !== "container") {
752
+ return item;
753
+ }
754
+ if (item.draftId === containerDraftId) {
755
+ return {
756
+ ...item,
757
+ children: updater(item.children)
758
+ };
759
+ }
760
+ return {
761
+ ...item,
762
+ children: updateContainerFields(item.children, containerDraftId, updater)
763
+ };
764
+ });
765
+ }
766
+ function findContainerChildren(fields, containerDraftId) {
767
+ for (const item of fields) {
768
+ if (item.field.type !== "container") {
769
+ continue;
770
+ }
771
+ if (item.draftId === containerDraftId) {
772
+ return item.children;
773
+ }
774
+ const children = findContainerChildren(item.children, containerDraftId);
775
+ if (children) {
776
+ return children;
777
+ }
778
+ }
779
+ return void 0;
780
+ }
781
+ function updateOwnerFields(owner, updater) {
782
+ if (owner.kind === "root") {
783
+ draftFields.value = updater(draftFields.value);
784
+ return;
785
+ }
786
+ if (owner.kind === "group") {
787
+ draftGroups.value = draftGroups.value.map((group) => group.draftId === owner.draftId ? {
788
+ ...group,
789
+ fields: updater(group.fields)
790
+ } : group);
791
+ return;
792
+ }
793
+ draftFields.value = updateContainerFields(draftFields.value, owner.draftId, updater);
794
+ draftGroups.value = draftGroups.value.map((group) => ({
795
+ ...group,
796
+ fields: updateContainerFields(group.fields, owner.draftId, updater)
797
+ }));
798
+ }
799
+ function getOwnerFields(owner) {
800
+ if (owner.kind === "root") {
801
+ return draftFields.value;
802
+ }
803
+ if (owner.kind === "group") {
804
+ return draftGroups.value.find((group) => group.draftId === owner.draftId)?.fields ?? [];
805
+ }
806
+ return findContainerChildren(draftFields.value, owner.draftId) ?? draftGroups.value.flatMap((group) => findContainerChildren(group.fields, owner.draftId) ?? []);
807
+ }
808
+ function removeFieldFromOwner(owner, fieldDraftId) {
809
+ let movedField;
810
+ updateOwnerFields(owner, (fields) => fields.filter((field) => {
811
+ if (field.draftId !== fieldDraftId) {
812
+ return true;
813
+ }
814
+ movedField = field;
815
+ return false;
816
+ }));
817
+ return movedField;
818
+ }
819
+ function insertFieldIntoOwner(owner, field, newIndex) {
820
+ updateOwnerFields(owner, (fields) => {
821
+ const nextFields = fields.slice();
822
+ const insertIndex = Math.min(Math.max(newIndex, 0), nextFields.length);
823
+ nextFields.splice(insertIndex, 0, field);
824
+ return nextFields;
825
+ });
826
+ }
827
+ function getOwnerItemCount(owner) {
828
+ return getOwnerFields(owner).length;
829
+ }
830
+ function getFieldOwnerFromValue(value) {
831
+ const ownerValue = String(value);
832
+ if (ownerValue === ROOT_FIELD_GROUP_VALUE) {
833
+ return {
834
+ kind: "root"
835
+ };
836
+ }
837
+ if (ownerValue.startsWith(GROUP_OWNER_PREFIX)) {
838
+ return {
839
+ kind: "group",
840
+ draftId: ownerValue.slice(GROUP_OWNER_PREFIX.length)
841
+ };
842
+ }
843
+ if (ownerValue.startsWith(CONTAINER_OWNER_PREFIX)) {
844
+ return {
845
+ kind: "container",
846
+ draftId: ownerValue.slice(CONTAINER_OWNER_PREFIX.length)
847
+ };
848
+ }
849
+ return void 0;
850
+ }
545
851
  function setSortableGroupListRef(groupDraftId, element) {
546
852
  sortableGroupListRefs.value[groupDraftId] = element instanceof HTMLElement ? element : null;
547
853
  }
@@ -577,84 +883,41 @@ function reorderRootFields(oldIndex, newIndex) {
577
883
  draftFields.value = moveField(draftFields.value, oldIndex, newIndex);
578
884
  }
579
885
  function moveFieldBetweenGroups(sourceGroupDraftId, targetGroupDraftId, fieldDraftId, newIndex) {
580
- let movedField;
581
- draftGroups.value = draftGroups.value.map((group) => {
582
- if (group.draftId === sourceGroupDraftId) {
583
- const nextFields = group.fields.filter((field) => {
584
- if (field.draftId !== fieldDraftId) {
585
- return true;
586
- }
587
- movedField = field;
588
- return false;
589
- });
590
- return {
591
- ...group,
592
- fields: nextFields
593
- };
594
- }
595
- return group;
596
- });
886
+ const movedField = removeFieldFromOwner({
887
+ kind: "group",
888
+ draftId: sourceGroupDraftId
889
+ }, fieldDraftId);
597
890
  if (!movedField) {
598
891
  return;
599
892
  }
600
- const nextMovedField = movedField;
601
- draftGroups.value = draftGroups.value.map((group) => {
602
- if (group.draftId !== targetGroupDraftId) {
603
- return group;
604
- }
605
- const nextFields = group.fields.slice();
606
- const insertIndex = Math.min(Math.max(newIndex, 0), nextFields.length);
607
- nextFields.splice(insertIndex, 0, nextMovedField);
608
- return {
609
- ...group,
610
- fields: nextFields
611
- };
612
- });
893
+ insertFieldIntoOwner({
894
+ kind: "group",
895
+ draftId: targetGroupDraftId
896
+ }, movedField, newIndex);
613
897
  }
614
898
  function moveFieldToRoot(sourceGroupDraftId, fieldDraftId, newIndex) {
615
- let movedField;
616
- draftGroups.value = draftGroups.value.map((group) => {
617
- if (group.draftId !== sourceGroupDraftId) {
618
- return group;
619
- }
620
- const nextFields2 = group.fields.filter((field) => {
621
- if (field.draftId !== fieldDraftId) {
622
- return true;
623
- }
624
- movedField = field;
625
- return false;
626
- });
627
- return {
628
- ...group,
629
- fields: nextFields2
630
- };
631
- });
899
+ const movedField = removeFieldFromOwner({
900
+ kind: "group",
901
+ draftId: sourceGroupDraftId
902
+ }, fieldDraftId);
632
903
  if (!movedField) {
633
904
  return;
634
905
  }
635
- const nextFields = draftFields.value.slice();
636
- const insertIndex = Math.min(Math.max(newIndex, 0), nextFields.length);
637
- nextFields.splice(insertIndex, 0, movedField);
638
- draftFields.value = nextFields;
906
+ insertFieldIntoOwner({
907
+ kind: "root"
908
+ }, movedField, newIndex);
639
909
  }
640
910
  function moveRootFieldToGroup(targetGroupDraftId, fieldDraftId, newIndex) {
641
- const movedField = draftFields.value.find((field) => field.draftId === fieldDraftId);
911
+ const movedField = removeFieldFromOwner({
912
+ kind: "root"
913
+ }, fieldDraftId);
642
914
  if (!movedField) {
643
915
  return;
644
916
  }
645
- draftFields.value = draftFields.value.filter((field) => field.draftId !== fieldDraftId);
646
- draftGroups.value = draftGroups.value.map((group) => {
647
- if (group.draftId !== targetGroupDraftId) {
648
- return group;
649
- }
650
- const nextFields = group.fields.slice();
651
- const insertIndex = Math.min(Math.max(newIndex, 0), nextFields.length);
652
- nextFields.splice(insertIndex, 0, movedField);
653
- return {
654
- ...group,
655
- fields: nextFields
656
- };
657
- });
917
+ insertFieldIntoOwner({
918
+ kind: "group",
919
+ draftId: targetGroupDraftId
920
+ }, movedField, newIndex);
658
921
  }
659
922
  async function refreshSortable() {
660
923
  for (const sortable of sortables.value) {
@@ -806,14 +1069,14 @@ function updateDraftStyle(value) {
806
1069
  draftStyle.value = normalizeOptionalString(String(value));
807
1070
  }
808
1071
  function updateDraftField(draftId, updater) {
809
- draftFields.value = draftFields.value.map((item) => item.draftId === draftId ? {
810
- draftId: item.draftId,
1072
+ draftFields.value = mapDraftFields(draftFields.value, (item) => item.draftId === draftId ? {
1073
+ ...item,
811
1074
  field: updater(item.field)
812
1075
  } : item);
813
1076
  draftGroups.value = draftGroups.value.map((group) => ({
814
1077
  ...group,
815
- fields: group.fields.map((item) => item.draftId === draftId ? {
816
- draftId: item.draftId,
1078
+ fields: mapDraftFields(group.fields, (item) => item.draftId === draftId ? {
1079
+ ...item,
817
1080
  field: updater(item.field)
818
1081
  } : item)
819
1082
  }));
@@ -834,38 +1097,39 @@ function updateSelectedGroupStyle(value) {
834
1097
  }
835
1098
  function updateSelectedFieldGroup(value) {
836
1099
  const selected = selectedField.value;
837
- const sourceGroup = selectedFieldGroup.value;
838
- if (!selected) {
1100
+ const sourceOwner = selectedFieldOwner.value;
1101
+ const targetOwner = getFieldOwnerFromValue(value);
1102
+ if (!selected || !sourceOwner || !targetOwner) {
839
1103
  return;
840
1104
  }
841
- const targetGroupDraftId = String(value);
842
- if (!targetGroupDraftId) {
1105
+ if (getFieldOwnerValue(sourceOwner) === getFieldOwnerValue(targetOwner)) {
843
1106
  return;
844
1107
  }
845
- if (targetGroupDraftId === ROOT_FIELD_GROUP_VALUE) {
846
- if (!sourceGroup) {
847
- return;
848
- }
849
- moveFieldToRoot(sourceGroup.draftId, selected.draftId, draftFields.value.length);
850
- return;
851
- }
852
- if (sourceGroup && targetGroupDraftId === sourceGroup.draftId) {
853
- return;
854
- }
855
- if (!sourceGroup) {
856
- moveRootFieldToGroup(targetGroupDraftId, selected.draftId, Number.MAX_SAFE_INTEGER);
1108
+ const movedField = removeFieldFromOwner(sourceOwner, selected.draftId);
1109
+ if (!movedField) {
857
1110
  return;
858
1111
  }
859
- moveFieldBetweenGroups(sourceGroup.draftId, targetGroupDraftId, selected.draftId, Number.MAX_SAFE_INTEGER);
1112
+ insertFieldIntoOwner(targetOwner, movedField, getOwnerItemCount(targetOwner));
860
1113
  }
861
- function getInsertionGroupDraftId() {
1114
+ function getInsertionOwner() {
1115
+ if (selectedField.value?.field.type === "container") {
1116
+ return {
1117
+ kind: "container",
1118
+ draftId: selectedField.value.draftId
1119
+ };
1120
+ }
862
1121
  if (selectedGroup.value) {
863
- return selectedGroup.value.draftId;
1122
+ return {
1123
+ kind: "group",
1124
+ draftId: selectedGroup.value.draftId
1125
+ };
864
1126
  }
865
- if (selectedFieldGroup.value) {
866
- return selectedFieldGroup.value.draftId;
1127
+ if (selectedFieldOwner.value) {
1128
+ return selectedFieldOwner.value;
867
1129
  }
868
- return void 0;
1130
+ return {
1131
+ kind: "root"
1132
+ };
869
1133
  }
870
1134
  function addGroup() {
871
1135
  const draftGroup = createDraftGroup(createGroup());
@@ -875,36 +1139,10 @@ function addGroup() {
875
1139
  }
876
1140
  function addField(type) {
877
1141
  const draftField = createDraftField(createField(type));
878
- const targetGroupDraftId = getInsertionGroupDraftId();
879
- if (targetGroupDraftId) {
880
- draftGroups.value = draftGroups.value.map((group) => {
881
- if (group.draftId !== targetGroupDraftId) {
882
- return group;
883
- }
884
- if (selectedFieldGroup.value?.draftId === targetGroupDraftId && selectedField.value) {
885
- const currentIndex = group.fields.findIndex((field) => field.draftId === selectedField.value?.draftId);
886
- if (currentIndex >= 0) {
887
- const nextFields = group.fields.slice();
888
- nextFields.splice(currentIndex + 1, 0, draftField);
889
- return {
890
- ...group,
891
- fields: nextFields
892
- };
893
- }
894
- }
895
- return {
896
- ...group,
897
- fields: [...group.fields, draftField]
898
- };
899
- });
900
- } else if (selectedField.value && !selectedFieldGroup.value) {
901
- const currentIndex = draftFields.value.findIndex((field) => field.draftId === selectedField.value?.draftId);
902
- const nextFields = draftFields.value.slice();
903
- nextFields.splice(currentIndex >= 0 ? currentIndex + 1 : nextFields.length, 0, draftField);
904
- draftFields.value = nextFields;
905
- } else {
906
- draftFields.value = [...draftFields.value, draftField];
907
- }
1142
+ const targetOwner = getInsertionOwner();
1143
+ const ownerFields = getOwnerFields(targetOwner);
1144
+ const currentIndex = selectedField.value && selectedFieldOwner.value && getFieldOwnerValue(selectedFieldOwner.value) === getFieldOwnerValue(targetOwner) && selectedField.value.field.type !== "container" ? ownerFields.findIndex((field) => field.draftId === selectedField.value?.draftId) : -1;
1145
+ insertFieldIntoOwner(targetOwner, draftField, currentIndex >= 0 ? currentIndex + 1 : ownerFields.length);
908
1146
  selectedItemId.value = draftField.draftId;
909
1147
  clearFieldErrors(draftField.draftId);
910
1148
  }
@@ -919,7 +1157,7 @@ function deleteGroup(itemId) {
919
1157
  if (deletedGroup) {
920
1158
  clearFieldErrors(deletedGroup.draftId);
921
1159
  for (const field of deletedGroup.fields) {
922
- clearFieldErrors(field.draftId);
1160
+ clearNestedFieldErrors(field);
923
1161
  }
924
1162
  }
925
1163
  if (selectedItemId.value !== itemId) {
@@ -929,30 +1167,33 @@ function deleteGroup(itemId) {
929
1167
  selectedItemId.value = nextGroup?.draftId ?? "general";
930
1168
  }
931
1169
  function deleteField(itemId) {
932
- let nextSelectedItemId;
933
- const rootDeleteIndex = draftFields.value.findIndex((field) => field.draftId === itemId);
934
- if (rootDeleteIndex >= 0) {
935
- const nextFields = draftFields.value.filter((field) => field.draftId !== itemId);
936
- const nextField = nextFields[rootDeleteIndex] ?? nextFields[rootDeleteIndex - 1];
937
- draftFields.value = nextFields;
938
- nextSelectedItemId = nextField?.draftId ?? "general";
939
- }
940
- draftGroups.value = draftGroups.value.map((group) => {
941
- const deleteIndex = group.fields.findIndex((field) => field.draftId === itemId);
942
- if (deleteIndex < 0) {
943
- return group;
944
- }
945
- const nextFields = group.fields.filter((field) => field.draftId !== itemId);
946
- const nextField = nextFields[deleteIndex] ?? nextFields[deleteIndex - 1];
947
- nextSelectedItemId = nextField?.draftId ?? group.draftId;
948
- return {
949
- ...group,
950
- fields: nextFields
951
- };
952
- });
1170
+ const owner = selectedItemId.value === itemId ? selectedFieldOwner.value : findFieldOwnerByDraftId(itemId);
1171
+ if (!owner) {
1172
+ return;
1173
+ }
1174
+ const currentFields = getOwnerFields(owner);
1175
+ const deleteIndex = currentFields.findIndex((field) => field.draftId === itemId);
1176
+ if (deleteIndex < 0) {
1177
+ return;
1178
+ }
1179
+ removeFieldFromOwner(owner, itemId);
1180
+ const nextFields = getOwnerFields(owner);
1181
+ const nextField = nextFields[deleteIndex] ?? nextFields[deleteIndex - 1];
953
1182
  clearFieldErrors(itemId);
954
1183
  if (selectedItemId.value === itemId) {
955
- selectedItemId.value = nextSelectedItemId ?? "general";
1184
+ if (nextField) {
1185
+ selectedItemId.value = nextField.draftId;
1186
+ return;
1187
+ }
1188
+ if (owner.kind === "group") {
1189
+ selectedItemId.value = owner.draftId;
1190
+ return;
1191
+ }
1192
+ if (owner.kind === "container") {
1193
+ selectedItemId.value = owner.draftId;
1194
+ return;
1195
+ }
1196
+ selectedItemId.value = "general";
956
1197
  }
957
1198
  }
958
1199
  function handleAddItem(type) {
@@ -963,7 +1204,10 @@ function handleAddItem(type) {
963
1204
  addField(type);
964
1205
  }
965
1206
  function isFieldLabelConfigurable(field) {
966
- return !isPassiveField(field);
1207
+ return hasFieldLabel(field);
1208
+ }
1209
+ function hasDirectFieldStyle(field) {
1210
+ return field.type !== "container";
967
1211
  }
968
1212
  function getFieldHideLabelValue(field) {
969
1213
  if (!isFieldLabelConfigurable(field)) {
@@ -973,14 +1217,14 @@ function getFieldHideLabelValue(field) {
973
1217
  }
974
1218
  function updateSelectedFieldTitle(value) {
975
1219
  const selected = selectedField.value;
976
- if (!selected) {
1220
+ if (!selected || !hasFieldLabel(selected.field)) {
977
1221
  return;
978
1222
  }
979
1223
  clearFieldError(selected.draftId, "title");
980
- updateDraftField(selected.draftId, (field) => ({
1224
+ updateDraftField(selected.draftId, (field) => hasFieldLabel(field) ? {
981
1225
  ...field,
982
1226
  title: value
983
- }));
1227
+ } : field);
984
1228
  }
985
1229
  function updateSelectedFieldHideLabel(value) {
986
1230
  const selected = selectedField.value;
@@ -999,15 +1243,25 @@ function updateSelectedFieldHideLabel(value) {
999
1243
  }
1000
1244
  function updateSelectedMarkdownLocale(value) {
1001
1245
  const selected = selectedField.value;
1002
- if (!selected || selected.field.type !== "markdown") {
1246
+ if (!selected || !isMarkdownContentField(selected.field)) {
1003
1247
  return;
1004
1248
  }
1005
1249
  clearFieldError(selected.draftId, "locale");
1006
- updateDraftField(selected.draftId, (field) => field.type === "markdown" ? {
1250
+ updateDraftField(selected.draftId, (field) => isMarkdownContentField(field) ? {
1007
1251
  ...field,
1008
1252
  locale: value
1009
1253
  } : field);
1010
1254
  }
1255
+ function updateSelectedMarkdownInline(value) {
1256
+ const selected = selectedField.value;
1257
+ if (!selected || !isMarkdownBodyField(selected.field)) {
1258
+ return;
1259
+ }
1260
+ updateDraftField(selected.draftId, (field) => isMarkdownBodyField(field) ? {
1261
+ ...field,
1262
+ inline: value ? true : void 0
1263
+ } : field);
1264
+ }
1011
1265
  function updateSelectedFieldId(value) {
1012
1266
  const selected = selectedField.value;
1013
1267
  if (!selected || selected.field.type !== "slot") {
@@ -1042,36 +1296,73 @@ function updateSelectedFieldPath(value) {
1042
1296
  }
1043
1297
  function updateSelectedFieldStyle(value) {
1044
1298
  const selected = selectedField.value;
1045
- if (!selected) {
1299
+ if (!selected || !hasDirectFieldStyle(selected.field)) {
1046
1300
  return;
1047
1301
  }
1048
1302
  clearFieldError(selected.draftId, "style");
1049
- updateDraftField(selected.draftId, (field) => ({
1303
+ updateDraftField(selected.draftId, (field) => {
1304
+ if (!hasDirectFieldStyle(field)) {
1305
+ return field;
1306
+ }
1307
+ return {
1308
+ ...field,
1309
+ style: normalizeOptionalString(String(value))
1310
+ };
1311
+ });
1312
+ }
1313
+ function updateSelectedContainerBodyOrientation(value) {
1314
+ const selected = selectedField.value;
1315
+ if (!selected || selected.field.type !== "container") {
1316
+ return;
1317
+ }
1318
+ const normalizedValue = normalizeOrientation(value);
1319
+ updateDraftField(selected.draftId, (field) => field.type === "container" ? {
1050
1320
  ...field,
1051
- style: normalizeOptionalString(String(value))
1052
- }));
1321
+ bodyOrientation: normalizedValue === "horizontal" ? void 0 : normalizedValue
1322
+ } : field);
1323
+ }
1324
+ function updateSelectedContainerBodyBordered(value) {
1325
+ const selected = selectedField.value;
1326
+ if (!selected || selected.field.type !== "container") {
1327
+ return;
1328
+ }
1329
+ updateDraftField(selected.draftId, (field) => field.type === "container" ? {
1330
+ ...field,
1331
+ bodyBordered: value ? true : void 0
1332
+ } : field);
1333
+ }
1334
+ function updateSelectedContainerBodyStyle(value) {
1335
+ const selected = selectedField.value;
1336
+ if (!selected || selected.field.type !== "container") {
1337
+ return;
1338
+ }
1339
+ clearFieldError(selected.draftId, "bodyStyle");
1340
+ updateDraftField(selected.draftId, (field) => field.type === "container" ? {
1341
+ ...field,
1342
+ bodyStyle: normalizeOptionalString(String(value))
1343
+ } : field);
1053
1344
  }
1054
1345
  function updateSelectedFieldLabelStyle(value) {
1055
1346
  const selected = selectedField.value;
1056
- if (!selected || isPassiveField(selected.field)) {
1347
+ if (!selected || !supportsFieldCellStyles(selected.field)) {
1057
1348
  return;
1058
1349
  }
1059
1350
  clearFieldError(selected.draftId, "labelStyle");
1060
- updateDraftField(selected.draftId, (field) => isPassiveField(field) ? field : {
1351
+ updateDraftField(selected.draftId, (field) => supportsFieldCellStyles(field) ? {
1061
1352
  ...field,
1062
1353
  labelStyle: normalizeOptionalString(String(value))
1063
- });
1354
+ } : field);
1064
1355
  }
1065
1356
  function updateSelectedFieldContentStyle(value) {
1066
1357
  const selected = selectedField.value;
1067
- if (!selected || isPassiveField(selected.field)) {
1358
+ if (!selected || !supportsFieldCellStyles(selected.field)) {
1068
1359
  return;
1069
1360
  }
1070
1361
  clearFieldError(selected.draftId, "contentStyle");
1071
- updateDraftField(selected.draftId, (field) => isPassiveField(field) ? field : {
1362
+ updateDraftField(selected.draftId, (field) => supportsFieldCellStyles(field) ? {
1072
1363
  ...field,
1073
1364
  contentStyle: normalizeOptionalString(String(value))
1074
- });
1365
+ } : field);
1075
1366
  }
1076
1367
  function updateSelectedFieldHidden(value) {
1077
1368
  const selected = selectedField.value;
@@ -1108,17 +1399,17 @@ function updateSelectedFieldInitialValue(value) {
1108
1399
  }
1109
1400
  function updateSelectedFieldRequired(value) {
1110
1401
  const selected = selectedField.value;
1111
- if (!selected || !isInteractiveField(selected.field)) {
1402
+ if (!selected || selected.field.type !== "slot" && selected.field.type !== "container" && !isInteractiveField(selected.field)) {
1112
1403
  return;
1113
1404
  }
1114
1405
  updateDraftField(selected.draftId, (field) => {
1115
- if (!isInteractiveField(field)) {
1116
- return field;
1406
+ if (field.type === "slot" || field.type === "container" || isInteractiveField(field)) {
1407
+ return {
1408
+ ...field,
1409
+ required: value ? true : void 0
1410
+ };
1117
1411
  }
1118
- return {
1119
- ...field,
1120
- required: value ? true : void 0
1121
- };
1412
+ return field;
1122
1413
  });
1123
1414
  }
1124
1415
  function updateSelectedStringDiscardEmpty(value) {
@@ -1566,6 +1857,10 @@ function getSchemaIssues(field) {
1566
1857
  const result = MarkdownFieldC.safeParse(field);
1567
1858
  return result.success ? [] : result.error.issues;
1568
1859
  }
1860
+ case "markdown-body": {
1861
+ const result = MarkdownBodyFieldC.safeParse(field);
1862
+ return result.success ? [] : result.error.issues;
1863
+ }
1569
1864
  case "select": {
1570
1865
  const result = SelectFieldC.safeParse(field);
1571
1866
  return result.success ? [] : result.error.issues;
@@ -1586,6 +1881,10 @@ function getSchemaIssues(field) {
1586
1881
  const result = SlotFieldC.safeParse(field);
1587
1882
  return result.success ? [] : result.error.issues;
1588
1883
  }
1884
+ case "container": {
1885
+ const result = ContainerFieldC.safeParse(field);
1886
+ return result.success ? [] : result.error.issues;
1887
+ }
1589
1888
  case "empty": {
1590
1889
  const result = EmptyFieldC.safeParse(field);
1591
1890
  return result.success ? [] : result.error.issues;
@@ -1621,9 +1920,32 @@ function normalizeGroup(group) {
1621
1920
  return {
1622
1921
  ...group,
1623
1922
  style: normalizeOptionalString(group.style ?? ""),
1624
- fields: group.fields.map((field) => normalizeField(field))
1923
+ fields: group.fields
1924
+ };
1925
+ }
1926
+ function normalizeDraftField(item) {
1927
+ const normalizedField = normalizeField(item.field);
1928
+ return {
1929
+ ...item,
1930
+ field: normalizedField,
1931
+ children: item.children.map((child) => normalizeDraftField(child))
1932
+ };
1933
+ }
1934
+ function buildFieldFromDraft(item) {
1935
+ if (item.field.type !== "container") {
1936
+ return item.field;
1937
+ }
1938
+ return {
1939
+ ...item.field,
1940
+ fields: item.children.map((child) => buildFieldFromDraft(child))
1625
1941
  };
1626
1942
  }
1943
+ function clearNestedFieldErrors(item) {
1944
+ clearFieldErrors(item.draftId);
1945
+ for (const child of item.children) {
1946
+ clearNestedFieldErrors(child);
1947
+ }
1948
+ }
1627
1949
  function validateDraftFields(fields, errors, idOwners, pathOwners) {
1628
1950
  let firstInvalidItemId;
1629
1951
  for (const item of fields) {
@@ -1661,25 +1983,21 @@ function validateDraftFields(fields, errors, idOwners, pathOwners) {
1661
1983
  setError(errors, issueKey, getSchemaIssueMessage(issue, issuePath));
1662
1984
  firstInvalidItemId = firstInvalidItemId ?? item.draftId;
1663
1985
  }
1986
+ const childInvalidItemId = validateDraftFields(item.children, errors, idOwners, pathOwners);
1987
+ firstInvalidItemId = firstInvalidItemId ?? childInvalidItemId;
1664
1988
  }
1665
1989
  return firstInvalidItemId;
1666
1990
  }
1667
1991
  function validateDraftState() {
1668
1992
  const errors = {};
1669
- const normalizedFields = draftFields.value.map((item) => ({
1670
- draftId: item.draftId,
1671
- field: normalizeField(item.field)
1672
- }));
1993
+ const normalizedFields = draftFields.value.map((item) => normalizeDraftField(item));
1673
1994
  const normalizedGroups = draftGroups.value.map((group) => ({
1674
1995
  draftId: group.draftId,
1675
1996
  group: normalizeGroup({
1676
1997
  ...group.group,
1677
- fields: group.fields.map((item) => item.field)
1998
+ fields: group.fields.map((item) => buildFieldFromDraft(normalizeDraftField(item)))
1678
1999
  }),
1679
- fields: group.fields.map((item) => ({
1680
- draftId: item.draftId,
1681
- field: normalizeField(item.field)
1682
- }))
2000
+ fields: group.fields.map((item) => normalizeDraftField(item))
1683
2001
  }));
1684
2002
  const groupIdOwners = {};
1685
2003
  const idOwners = {};
@@ -1741,10 +2059,10 @@ function buildDraftConfig() {
1741
2059
  return void 0;
1742
2060
  }
1743
2061
  const nextBody = {
1744
- fields: validatedDraftState.normalizedFields.map((item) => item.field),
2062
+ fields: validatedDraftState.normalizedFields.map((item) => buildFieldFromDraft(item)),
1745
2063
  groups: validatedDraftState.normalizedGroups.map((group) => ({
1746
2064
  ...group.group,
1747
- fields: group.fields.map((item) => item.field)
2065
+ fields: group.fields.map((item) => buildFieldFromDraft(item))
1748
2066
  }))
1749
2067
  };
1750
2068
  if (draftOrientation.value !== "horizontal") {
@@ -1825,13 +2143,16 @@ function buildDslGuideMarkdown() {
1825
2143
  "### 3. \u5B57\u6BB5\u7C7B\u578B\u7EA6\u675F",
1826
2144
  "- \u9876\u5C42\u914D\u7F6E\u53EF\u4EE5\u76F4\u63A5\u4F7F\u7528 `fields` \u653E\u6839\u7EA7\u5B57\u6BB5\uFF0C\u4E5F\u53EF\u4EE5\u4F7F\u7528 `groups` \u653E\u5206\u7EC4\u5B57\u6BB5\uFF0C\u4E24\u8005\u53EF\u4EE5\u540C\u65F6\u5B58\u5728\u3002",
1827
2145
  "- \u6BCF\u4E2A\u5B57\u6BB5\u7EC4\u90FD\u5FC5\u987B\u5305\u542B\u552F\u4E00\u4E14\u5408\u6CD5\u7684 UUID `id`\u3002",
1828
- "- \u5B57\u6BB5\u7EC4\u53EA\u8D1F\u8D23\u7ED3\u6784\u4E0E\u6837\u5F0F\uFF0C\u4E0D\u63D0\u4F9B\u6807\u9898\uFF1B\u5206\u7EC4\u8BF4\u660E\u8BF7\u4F7F\u7528 `markdown` \u5B57\u6BB5\u3002",
2146
+ "- \u5B57\u6BB5\u7EC4\u53EA\u8D1F\u8D23\u7ED3\u6784\u4E0E\u6837\u5F0F\uFF0C\u4E0D\u63D0\u4F9B\u6807\u9898\uFF1B\u5206\u7EC4\u8BF4\u660E\u4F18\u5148\u4F7F\u7528 `markdown-body` \u5B57\u6BB5\uFF0C\u82E5\u9700\u8981\u6807\u7B7E\u884C\u518D\u4F7F\u7528 `markdown` \u5B57\u6BB5\u3002",
1829
2147
  "- \u4EE3\u7801\u91CC\u5E94\u5148\u751F\u6210\u5E76\u4F7F\u7528 UUID\uFF0C\u518D\u628A\u540C\u4E00\u4E2A `id` \u7C98\u8D34\u56DE\u5B57\u6BB5\u914D\u7F6E\u3002",
1830
2148
  "- \u6240\u6709\u5B57\u6BB5\u90FD\u5FC5\u987B\u5305\u542B\u552F\u4E00\u4E14\u5408\u6CD5\u7684 UUID `id`\u3002",
1831
2149
  "- \u53EA\u6709\u53EF\u7ED1\u5B9A\u503C\u7684\u5B57\u6BB5\u53EF\u4EE5\u914D\u7F6E `path`\uFF0C\u5E76\u53C2\u4E0E\u8868\u5355\u503C\u8BFB\u5199\u3002",
1832
- "- `slot` \u548C `empty` \u5B57\u6BB5\u90FD\u4E0D\u4F1A\u7ED1\u5B9A\u6A21\u578B\u503C\uFF0C\u53EA\u5141\u8BB8 `id`\u3001`type` \u548C\u53EF\u9009\u7684 `style`\u3002",
2150
+ "- `slot` \u5B57\u6BB5\u4E0D\u4F1A\u7ED1\u5B9A\u6A21\u578B\u503C\uFF1B\u53EF\u9009 `title`\u3001`hideLabel`\u3001`required`\u3001`hidden`\u3001`labelStyle`\u3001`contentStyle` \u4E0E `style`\u3002",
2151
+ "- `container` \u5B57\u6BB5\u4E0D\u4F1A\u7ED1\u5B9A\u6A21\u578B\u503C\uFF1B\u4F7F\u7528 `fields` \u627F\u8F7D\u9012\u5F52\u5D4C\u5957\u5B57\u6BB5\uFF0C\u53EF\u9009 `bodyOrientation`\u3001`bodyBordered` \u4E0E `bodyStyle` \u63A7\u5236\u5185\u90E8\u5E03\u5C40\u3002",
2152
+ "- `empty` \u5B57\u6BB5\u4E0D\u4F1A\u7ED1\u5B9A\u6A21\u578B\u503C\uFF0C\u53EA\u5141\u8BB8 `id`\u3001`type` \u548C\u53EF\u9009\u7684 `style`\u3002",
1833
2153
  "- `markdown` \u5B57\u6BB5\u4F7F\u7528 `title` \u4E0E `locale` \u5C55\u793A\u5E26\u6807\u7B7E\u7684 Markdown \u5185\u5BB9\uFF0C\u4E0D\u7ED1\u5B9A `path`\u3002",
1834
- "- \u9664 `slot` \u4E0E `empty` \u5916\uFF0C\u5176\u5B83\u5E26\u6807\u7B7E\u5B57\u6BB5\u90FD\u53EF\u4EE5\u8BBE\u7F6E `hideLabel` \u9690\u85CF\u6807\u7B7E\u3002",
2154
+ "- `markdown-body` \u5B57\u6BB5\u4F7F\u7528 `locale` \u5C55\u793A\u65E0\u6807\u7B7E\u7684\u7EAF Markdown \u5185\u5BB9\uFF0C\u53EF\u9009 `inline` \u63A7\u5236\u5185\u8054\u6E32\u67D3\uFF0C\u4E0D\u7ED1\u5B9A `path`\u3002",
2155
+ "- \u9664 `empty` \u4E0E `markdown-body` \u5916\uFF0C\u5176\u5B83\u5E26\u6807\u7B7E\u5B57\u6BB5\u90FD\u53EF\u4EE5\u8BBE\u7F6E `hideLabel` \u9690\u85CF\u6807\u7B7E\u3002",
1835
2156
  "- \u666E\u901A\u5B57\u6BB5\u53EF\u989D\u5916\u4F7F\u7528 `labelStyle` \u4E0E `contentStyle`\uFF0C\u7528\u4E8E contents \u5E03\u5C40\u6A21\u5F0F\u4E0B\u5206\u522B\u63A7\u5236\u6807\u7B7E\u4E0E\u5185\u5BB9\u5355\u5143\u683C\u3002"
1836
2157
  ].join("\n");
1837
2158
  }
@@ -1842,10 +2163,13 @@ function buildMarkdownNotes() {
1842
2163
  "- \u5148\u5728\u4EE3\u7801\u91CC\u751F\u6210\u5E76\u4F7F\u7528 UUID\uFF0C\u518D\u628A\u540C\u4E00\u4E2A `id` \u7C98\u8D34\u5230\u5B57\u6BB5\u914D\u7F6E\u4E2D\u3002",
1843
2164
  "- \u6240\u6709\u5B57\u6BB5\u7EC4 `id` \u90FD\u5FC5\u987B\u552F\u4E00\u4E14\u7B26\u5408 UUID \u683C\u5F0F\u3002",
1844
2165
  "- \u6240\u6709\u5B57\u6BB5 `id` \u90FD\u5FC5\u987B\u552F\u4E00\u4E14\u7B26\u5408 UUID \u683C\u5F0F\u3002",
1845
- "- \u5B57\u6BB5\u7EC4\u6CA1\u6709\u6807\u9898\uFF1B\u5982\u679C\u9700\u8981\u5206\u6BB5\u6807\u9898\u6216\u8BF4\u660E\uFF0C\u8BF7\u63D2\u5165 `markdown` \u5B57\u6BB5\u3002",
1846
- "- `slot` \u4E0E `empty` \u5B57\u6BB5\u53EA\u80FD\u4F7F\u7528 `id`\u3001`type` \u548C\u53EF\u9009\u7684 `style`\u3002",
1847
- "- `markdown` \u5B57\u6BB5\u4E0D\u4F7F\u7528 `path`\uFF0C\u5185\u5BB9\u6765\u81EA `locale` \u672C\u5730\u5316 Markdown\u3002",
1848
- "- \u9664 `slot` \u4E0E `empty` \u5916\uFF0C\u5176\u5B83\u5E26\u6807\u7B7E\u5B57\u6BB5\u90FD\u53EF\u4EE5\u8BBE\u7F6E `hideLabel`\u3002",
2166
+ "- \u5B57\u6BB5\u7EC4\u6CA1\u6709\u6807\u9898\uFF1B\u5982\u679C\u9700\u8981\u5206\u6BB5\u6807\u9898\u6216\u8BF4\u660E\uFF0C\u4F18\u5148\u63D2\u5165 `markdown-body` \u5B57\u6BB5\uFF1B\u9700\u8981\u6807\u7B7E\u884C\u65F6\u518D\u4F7F\u7528 `markdown` \u5B57\u6BB5\u3002",
2167
+ "- `slot` \u5B57\u6BB5\u4E0D\u7ED1\u5B9A `path`\uFF0C\u53EF\u9009 `title`\u3001`hideLabel`\u3001`required`\u3001`hidden`\u3001`labelStyle`\u3001`contentStyle` \u4E0E `style`\u3002",
2168
+ "- `container` \u5B57\u6BB5\u4E0D\u7ED1\u5B9A `path`\uFF0C\u901A\u8FC7 `fields` \u9012\u5F52\u5D4C\u5957\u5B50\u5B57\u6BB5\uFF0C\u4E0D\u652F\u6301\u5D4C\u5957 `groups`\u3002",
2169
+ "- `empty` \u5B57\u6BB5\u53EA\u80FD\u4F7F\u7528 `id`\u3001`type` \u548C\u53EF\u9009\u7684 `style`\u3002",
2170
+ "- `markdown` \u5B57\u6BB5\u4E0D\u4F7F\u7528 `path`\uFF0C\u5185\u5BB9\u6765\u81EA `title` \u4E0E `locale` \u672C\u5730\u5316 Markdown\u3002",
2171
+ "- `markdown-body` \u5B57\u6BB5\u4E0D\u4F7F\u7528 `path`\uFF0C\u5185\u5BB9\u6765\u81EA `locale` \u672C\u5730\u5316 Markdown\uFF0C\u53EF\u9009 `inline` \u63A7\u5236\u6E32\u67D3\u65B9\u5F0F\u3002",
2172
+ "- \u9664 `empty` \u4E0E `markdown-body` \u5916\uFF0C\u5176\u5B83\u5E26\u6807\u7B7E\u5B57\u6BB5\u90FD\u53EF\u4EE5\u8BBE\u7F6E `hideLabel`\u3002",
1849
2173
  "- \u666E\u901A\u5B57\u6BB5\u5728 contents \u5E03\u5C40\u6A21\u5F0F\u4E0B\u53EF\u989D\u5916\u4F7F\u7528 `labelStyle` \u4E0E `contentStyle`\u3002",
1850
2174
  "- \u53EA\u6709\u5E26 `path` \u7684\u5B57\u6BB5\u624D\u8981\u6C42 `path` \u552F\u4E00\u4E14\u4E0D\u80FD\u4E3A\u7A7A\u3002",
1851
2175
  "- \u8868\u8FBE\u5F0F\u5B57\u6BB5\u5FC5\u987B\u4E25\u683C\u9075\u5B88 schema \u7EA6\u675F\uFF1B\u5982\u679C schema \u4E0D\u652F\u6301\uFF0C\u5C31\u76F4\u63A5\u8BF4\u660E\u9650\u5236\u3002"
@@ -2004,10 +2328,10 @@ function confirmChanges() {
2004
2328
  if (!result) {
2005
2329
  return;
2006
2330
  }
2007
- draftFields.value = result.normalizedFields.map((item) => createDraftField(item.field));
2331
+ draftFields.value = result.normalizedFields.map((item) => createDraftField(buildFieldFromDraft(item)));
2008
2332
  draftGroups.value = result.normalizedGroups.map((group) => createDraftGroup({
2009
2333
  ...group.group,
2010
- fields: group.fields.map((item) => item.field)
2334
+ fields: group.fields.map((item) => buildFieldFromDraft(item))
2011
2335
  }));
2012
2336
  emit("confirm", result.config);
2013
2337
  open.value = false;
@@ -2117,6 +2441,7 @@ function confirmChanges() {
2117
2441
  :data-field-id="item.fieldId"
2118
2442
  :data-field-path="item.path"
2119
2443
  :data-selected="selectedItemId === item.itemId ? 'true' : 'false'"
2444
+ :style="{ paddingLeft: `${item.depth * 12 + 4}px` }"
2120
2445
  :class="cn(
2121
2446
  'flex min-w-0 items-center gap-2 rounded-md border p-1 transition-colors',
2122
2447
  selectedItemId === item.itemId ? 'border-(--primary)/25 bg-[color-mix(in_srgb,var(--primary)_10%,white)]' : 'border-transparent hover:border-zinc-200 hover:bg-zinc-50'
@@ -2229,8 +2554,9 @@ function confirmChanges() {
2229
2554
  :data-field-id="item.fieldId"
2230
2555
  :data-field-path="item.path"
2231
2556
  :data-selected="selectedItemId === item.itemId ? 'true' : 'false'"
2557
+ :style="{ paddingLeft: `${item.depth * 12 + 16}px` }"
2232
2558
  :class="cn(
2233
- 'flex min-w-0 items-center gap-2 rounded-md border p-1 pl-4 transition-colors',
2559
+ 'flex min-w-0 items-center gap-2 rounded-md border p-1 transition-colors',
2234
2560
  selectedItemId === item.itemId ? 'border-(--primary)/25 bg-[color-mix(in_srgb,var(--primary)_10%,white)]' : 'border-transparent hover:border-zinc-200 hover:bg-zinc-50'
2235
2561
  )"
2236
2562
  >
@@ -2496,25 +2822,22 @@ function confirmChanges() {
2496
2822
  </span>
2497
2823
  <NativeSelect
2498
2824
  data-slot="fields-configurator-field-group-select"
2499
- :model-value="selectedFieldGroup?.draftId ?? ROOT_FIELD_GROUP_VALUE"
2825
+ :model-value="selectedFieldOwner ? getFieldOwnerValue(selectedFieldOwner) : ROOT_FIELD_GROUP_VALUE"
2500
2826
  @update:model-value="updateSelectedFieldGroup"
2501
2827
  >
2502
- <NativeSelectOption :value="ROOT_FIELD_GROUP_VALUE">
2503
- {{ t("field-group-none") }}
2504
- </NativeSelectOption>
2505
2828
  <NativeSelectOption
2506
- v-for="group in groupItems"
2507
- :key="group.itemId"
2508
- :value="group.itemId"
2829
+ v-for="option in selectedFieldOwnerOptions"
2830
+ :key="option.value"
2831
+ :value="option.value"
2509
2832
  >
2510
- {{ group.label }}
2833
+ {{ option.label }}
2511
2834
  </NativeSelectOption>
2512
2835
  </NativeSelect>
2513
2836
  </label>
2514
2837
  </section>
2515
2838
 
2516
2839
  <section
2517
- v-if="!isPassiveField(selectedField.field)"
2840
+ v-if="hasFieldLabel(selectedField.field)"
2518
2841
  data-slot="fields-configurator-field-label-section"
2519
2842
  class="flex flex-col gap-2"
2520
2843
  >
@@ -2524,7 +2847,7 @@ function confirmChanges() {
2524
2847
 
2525
2848
  <Locale
2526
2849
  data-slot="fields-configurator-field-title-locale"
2527
- :model-value="selectedField.field.title"
2850
+ :model-value="getFieldTitleValue(selectedField.field)"
2528
2851
  @update:model-value="updateSelectedFieldTitle"
2529
2852
  />
2530
2853
 
@@ -2538,7 +2861,7 @@ function confirmChanges() {
2538
2861
  </section>
2539
2862
 
2540
2863
  <section
2541
- v-if="selectedField.field.type === 'markdown'"
2864
+ v-if="isMarkdownContentField(selectedField.field)"
2542
2865
  data-slot="fields-configurator-field-markdown-section"
2543
2866
  class="flex flex-col gap-2"
2544
2867
  >
@@ -2565,6 +2888,21 @@ function confirmChanges() {
2565
2888
  >
2566
2889
  {{ validationErrors[getFieldErrorKey(selectedField.draftId, "locale")] }}
2567
2890
  </p>
2891
+
2892
+ <label
2893
+ v-if="isMarkdownBodyField(selectedField.field)"
2894
+ class="flex items-center justify-between gap-3 rounded-md border border-zinc-200 px-3 py-2"
2895
+ >
2896
+ <div class="flex flex-col gap-1">
2897
+ <span class="text-sm font-medium text-zinc-800">{{ t("field-markdown-inline") }}</span>
2898
+ <span class="text-xs text-zinc-500">{{ t("field-markdown-inline-description") }}</span>
2899
+ </div>
2900
+ <Switch
2901
+ data-slot="fields-configurator-field-markdown-inline-switch"
2902
+ :model-value="selectedField.field.inline ?? false"
2903
+ @update:model-value="updateSelectedMarkdownInline"
2904
+ />
2905
+ </label>
2568
2906
  </section>
2569
2907
 
2570
2908
  <section
@@ -2599,7 +2937,7 @@ function confirmChanges() {
2599
2937
  class="grid gap-4 md:grid-cols-2"
2600
2938
  >
2601
2939
  <label
2602
- v-if="isInteractiveField(selectedField.field)"
2940
+ v-if="isInteractiveField(selectedField.field) || selectedField.field.type === 'slot' || selectedField.field.type === 'container'"
2603
2941
  class="flex items-center justify-between gap-3 rounded-md border border-zinc-200 px-3 py-2 md:col-span-2"
2604
2942
  >
2605
2943
  <div class="flex flex-col gap-1">
@@ -2629,7 +2967,7 @@ function confirmChanges() {
2629
2967
  </label>
2630
2968
 
2631
2969
  <label
2632
- v-if="!usesContentsOrientation"
2970
+ v-if="hasDirectFieldStyle(selectedField.field) && (!usesContentsOrientation || isMarkdownBodyField(selectedField.field) || selectedField.field.type === 'slot')"
2633
2971
  class="flex flex-col gap-2"
2634
2972
  >
2635
2973
  <span class="text-xs font-medium text-zinc-500">
@@ -2637,7 +2975,7 @@ function confirmChanges() {
2637
2975
  </span>
2638
2976
  <Textarea
2639
2977
  data-slot="fields-configurator-field-style-input"
2640
- :model-value="selectedField.field.style ?? ''"
2978
+ :model-value="hasDirectFieldStyle(selectedField.field) ? selectedField.field.style ?? '' : ''"
2641
2979
  :aria-invalid="validationErrors[getFieldErrorKey(selectedField.draftId, 'style')] ? 'true' : void 0"
2642
2980
  :placeholder="t('field-style-placeholder')"
2643
2981
  class="min-h-20 font-mono text-sm"
@@ -2652,7 +2990,7 @@ function confirmChanges() {
2652
2990
  </label>
2653
2991
 
2654
2992
  <label
2655
- v-else
2993
+ v-else-if="supportsFieldCellStyles(selectedField.field)"
2656
2994
  class="flex flex-col gap-2"
2657
2995
  >
2658
2996
  <span class="text-xs font-medium text-zinc-500">
@@ -2675,7 +3013,7 @@ function confirmChanges() {
2675
3013
  </label>
2676
3014
 
2677
3015
  <label
2678
- v-if="usesContentsOrientation"
3016
+ v-if="usesContentsOrientation && supportsFieldCellStyles(selectedField.field)"
2679
3017
  class="flex flex-col gap-2"
2680
3018
  >
2681
3019
  <span class="text-xs font-medium text-zinc-500">
@@ -2764,6 +3102,99 @@ function confirmChanges() {
2764
3102
  </label>
2765
3103
  </section>
2766
3104
 
3105
+ <section
3106
+ v-if="selectedField.field.type === 'container'"
3107
+ data-slot="fields-configurator-container-options"
3108
+ class="grid gap-4 md:grid-cols-2"
3109
+ >
3110
+ <label class="flex flex-col gap-2">
3111
+ <span class="text-xs font-medium text-zinc-500">
3112
+ {{ t("container-body-orientation") }}
3113
+ </span>
3114
+ <NativeSelect
3115
+ data-slot="fields-configurator-container-body-orientation-select"
3116
+ :model-value="selectedField.field.bodyOrientation ?? 'horizontal'"
3117
+ @update:model-value="updateSelectedContainerBodyOrientation"
3118
+ >
3119
+ <NativeSelectOption value="horizontal">
3120
+ {{ t("fields-orientation-horizontal") }}
3121
+ </NativeSelectOption>
3122
+ <NativeSelectOption value="vertical">
3123
+ {{ t("fields-orientation-vertical") }}
3124
+ </NativeSelectOption>
3125
+ <NativeSelectOption value="floating">
3126
+ {{ t("fields-orientation-floating") }}
3127
+ </NativeSelectOption>
3128
+ <NativeSelectOption value="contents">
3129
+ {{ t("fields-orientation-contents") }}
3130
+ </NativeSelectOption>
3131
+ </NativeSelect>
3132
+ </label>
3133
+
3134
+ <label class="flex items-center justify-between gap-3 rounded-md border border-zinc-200 px-3 py-2">
3135
+ <div class="flex flex-col gap-1">
3136
+ <span class="text-sm font-medium text-zinc-800">{{ t("container-body-bordered") }}</span>
3137
+ <span class="text-xs text-zinc-500">{{ t("container-body-bordered-description") }}</span>
3138
+ </div>
3139
+ <Switch
3140
+ data-slot="fields-configurator-container-body-bordered-switch"
3141
+ :model-value="selectedField.field.bodyBordered ?? false"
3142
+ @update:model-value="updateSelectedContainerBodyBordered"
3143
+ />
3144
+ </label>
3145
+
3146
+ <label class="flex flex-col gap-2 md:col-span-2">
3147
+ <span class="text-xs font-medium text-zinc-500">
3148
+ {{ t("container-body-style") }}
3149
+ </span>
3150
+ <Textarea
3151
+ data-slot="fields-configurator-container-body-style-input"
3152
+ :model-value="selectedField.field.bodyStyle ?? ''"
3153
+ :aria-invalid="validationErrors[getFieldErrorKey(selectedField.draftId, 'bodyStyle')] ? 'true' : void 0"
3154
+ :placeholder="t('group-style-placeholder')"
3155
+ class="min-h-20 font-mono text-sm"
3156
+ @update:model-value="updateSelectedContainerBodyStyle"
3157
+ />
3158
+ <p
3159
+ v-if="validationErrors[getFieldErrorKey(selectedField.draftId, 'bodyStyle')]"
3160
+ class="text-xs text-red-500"
3161
+ >
3162
+ {{ validationErrors[getFieldErrorKey(selectedField.draftId, "bodyStyle")] }}
3163
+ </p>
3164
+ </label>
3165
+
3166
+ <div
3167
+ data-slot="fields-configurator-container-children"
3168
+ class="flex flex-col gap-2 md:col-span-2"
3169
+ >
3170
+ <p class="text-xs font-medium text-zinc-500">
3171
+ {{ t("field-children") }}
3172
+ </p>
3173
+ <div
3174
+ v-if="selectedContainerChildItems.length > 0"
3175
+ class="flex flex-col gap-1"
3176
+ >
3177
+ <button
3178
+ v-for="item in selectedContainerChildItems"
3179
+ :key="item.itemId"
3180
+ type="button"
3181
+ data-slot="fields-configurator-container-child"
3182
+ class="rounded-md border border-zinc-200 px-3 py-2 text-left text-sm text-zinc-700 transition-colors hover:border-zinc-300 hover:bg-zinc-50"
3183
+ :style="{ paddingLeft: `${item.depth * 12 + 12}px` }"
3184
+ @click="selectItem(item.itemId)"
3185
+ >
3186
+ {{ item.label }}
3187
+ </button>
3188
+ </div>
3189
+ <p
3190
+ v-else
3191
+ class="text-xs text-zinc-500"
3192
+ >
3193
+ {{ t("field-children-empty") }}
3194
+ </p>
3195
+ </div>
3196
+ </section>
3197
+
2767
3198
  <section
2768
3199
  v-if="selectedField.field.type === 'string' || selectedField.field.type === 'textarea'"
2769
3200
  data-slot="fields-configurator-string-options"
@@ -3358,10 +3789,12 @@ function confirmChanges() {
3358
3789
  "field-type-textarea": "多行文本",
3359
3790
  "field-type-number": "数字",
3360
3791
  "field-type-markdown": "Markdown",
3792
+ "field-type-markdown-body": "纯 Markdown",
3361
3793
  "field-type-select": "选择",
3362
3794
  "field-type-radio": "单选按钮组",
3363
3795
  "field-type-calendar": "日期",
3364
3796
  "field-type-upload": "上传",
3797
+ "field-type-container": "容器",
3365
3798
  "field-type-empty": "空白",
3366
3799
  "field-type-slot": "插槽",
3367
3800
  "field-id": "字段 ID",
@@ -3379,12 +3812,16 @@ function confirmChanges() {
3379
3812
  "copy-field-id-failed": "复制字段 ID 失败,请检查剪贴板权限。",
3380
3813
  "field-group": "所属分组",
3381
3814
  "field-group-none": "不分组",
3815
+ "field-children": "子字段",
3816
+ "field-children-empty": "这个容器还没有子字段。",
3382
3817
  "field-label": "字段标题",
3383
3818
  "group-style": "分组样式表达式",
3384
3819
  "group-style-placeholder": "例如返回一个 style map,例如 display: grid",
3385
3820
  "group-style-invalid": "分组样式表达式无效",
3386
3821
  "field-markdown-content": "Markdown 内容",
3387
3822
  "field-markdown-content-description": "支持 Markdown 编辑,并支持双花括号表达式求值。",
3823
+ "field-markdown-inline": "内联渲染",
3824
+ "field-markdown-inline-description": "开启后使用内联 Markdown 渲染;关闭时按块级 Markdown 渲染。",
3388
3825
  "field-required": "显示必填提示",
3389
3826
  "field-required-description": "开启后仅在标签后显示红色星号,不会自动添加校验规则。",
3390
3827
  "field-hide-label": "隐藏标签",
@@ -3394,6 +3831,10 @@ function confirmChanges() {
3394
3831
  "field-style": "样式表达式",
3395
3832
  "field-label-style": "标签样式表达式",
3396
3833
  "field-content-style": "内容样式表达式",
3834
+ "container-body-orientation": "容器内部布局",
3835
+ "container-body-bordered": "容器内部表格式边框",
3836
+ "container-body-bordered-description": "仅在 contents 布局下生效,用于容器内部字段网格。",
3837
+ "container-body-style": "容器内部样式表达式",
3397
3838
  "field-style-placeholder": "例如 width: 100%",
3398
3839
  "field-hidden": "隐藏条件",
3399
3840
  "field-hidden-placeholder": "返回 true 时隐藏字段",
@@ -3493,10 +3934,12 @@ function confirmChanges() {
3493
3934
  "field-type-textarea": "複数行テキスト",
3494
3935
  "field-type-number": "数値",
3495
3936
  "field-type-markdown": "Markdown",
3937
+ "field-type-markdown-body": "プレーン Markdown",
3496
3938
  "field-type-select": "選択",
3497
3939
  "field-type-radio": "ラジオグループ",
3498
3940
  "field-type-calendar": "日付",
3499
3941
  "field-type-upload": "アップロード",
3942
+ "field-type-container": "コンテナ",
3500
3943
  "field-type-empty": "空白",
3501
3944
  "field-type-slot": "スロット",
3502
3945
  "field-id": "フィールド ID",
@@ -3514,12 +3957,16 @@ function confirmChanges() {
3514
3957
  "copy-field-id-failed": "フィールド ID のコピーに失敗しました。クリップボード権限を確認してください。",
3515
3958
  "field-group": "所属グループ",
3516
3959
  "field-group-none": "グループなし",
3960
+ "field-children": "子フィールド",
3961
+ "field-children-empty": "このコンテナにはまだ子フィールドがありません。",
3517
3962
  "field-label": "フィールドラベル",
3518
3963
  "group-style": "グループスタイル式",
3519
3964
  "group-style-placeholder": "例: style map を返す式。例: display: grid",
3520
3965
  "group-style-invalid": "グループスタイル式が無効です",
3521
3966
  "field-markdown-content": "Markdown 内容",
3522
3967
  "field-markdown-content-description": "Markdown で編集でき、二重波括弧式も利用できます。",
3968
+ "field-markdown-inline": "インライン描画",
3969
+ "field-markdown-inline-description": "有効にするとインライン Markdown として描画し、無効ならブロック Markdown として描画します。",
3523
3970
  "field-required": "必須ヒントを表示",
3524
3971
  "field-required-description": "有効にするとラベルの後ろに赤い星印だけを表示し、検証ルールは自動追加しません。",
3525
3972
  "field-hide-label": "ラベルを非表示",
@@ -3529,6 +3976,10 @@ function confirmChanges() {
3529
3976
  "field-style": "スタイル式",
3530
3977
  "field-label-style": "ラベルスタイル式",
3531
3978
  "field-content-style": "コンテンツスタイル式",
3979
+ "container-body-orientation": "内部レイアウト",
3980
+ "container-body-bordered": "内部テーブル枠線",
3981
+ "container-body-bordered-description": "contents レイアウト時のみ有効で、内部フィールドグリッドに適用します。",
3982
+ "container-body-style": "内部スタイル式",
3532
3983
  "field-style-placeholder": "例: width: 100%",
3533
3984
  "field-hidden": "非表示条件",
3534
3985
  "field-hidden-placeholder": "true を返すと非表示になります",
@@ -3628,10 +4079,12 @@ function confirmChanges() {
3628
4079
  "field-type-textarea": "Textarea",
3629
4080
  "field-type-number": "Number",
3630
4081
  "field-type-markdown": "Markdown",
4082
+ "field-type-markdown-body": "Plain Markdown",
3631
4083
  "field-type-select": "Select",
3632
4084
  "field-type-radio": "Radio Group",
3633
4085
  "field-type-calendar": "Date",
3634
4086
  "field-type-upload": "Upload",
4087
+ "field-type-container": "Container",
3635
4088
  "field-type-empty": "Empty",
3636
4089
  "field-type-slot": "Slot",
3637
4090
  "field-id": "Field ID",
@@ -3649,12 +4102,16 @@ function confirmChanges() {
3649
4102
  "copy-field-id-failed": "Failed to copy the field ID. Check clipboard permissions.",
3650
4103
  "field-group": "Belong group",
3651
4104
  "field-group-none": "No group",
4105
+ "field-children": "Child fields",
4106
+ "field-children-empty": "This container does not have child fields yet.",
3652
4107
  "field-label": "Field label",
3653
4108
  "group-style": "Group style expression",
3654
4109
  "group-style-placeholder": "Return a style map, for example display: grid",
3655
4110
  "group-style-invalid": "The group style expression is invalid",
3656
4111
  "field-markdown-content": "Markdown content",
3657
4112
  "field-markdown-content-description": "Supports Markdown and can evaluate double-curly expressions.",
4113
+ "field-markdown-inline": "Inline rendering",
4114
+ "field-markdown-inline-description": "When enabled, render as inline Markdown. Otherwise render as block Markdown.",
3658
4115
  "field-required": "Show required hint",
3659
4116
  "field-required-description": "When enabled, only a red asterisk is shown after the label. No validation rule is added automatically.",
3660
4117
  "field-hide-label": "Hide label",
@@ -3664,6 +4121,10 @@ function confirmChanges() {
3664
4121
  "field-style": "Style expression",
3665
4122
  "field-label-style": "Label style expression",
3666
4123
  "field-content-style": "Content style expression",
4124
+ "container-body-orientation": "Nested layout",
4125
+ "container-body-bordered": "Nested table borders",
4126
+ "container-body-bordered-description": "Only applies in contents layout for the nested field grid.",
4127
+ "container-body-style": "Nested style expression",
3667
4128
  "field-style-placeholder": "For example width: 100%",
3668
4129
  "field-hidden": "Hidden expression",
3669
4130
  "field-hidden-placeholder": "Return true to hide the field",