@kne/form-creator 0.1.4 → 0.1.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/dist/index.js CHANGED
@@ -12,13 +12,15 @@ require('@kne/super-select/dist/index.css');
12
12
  require('@kne/super-select-plus/dist/index.css');
13
13
  var jsxRuntime = require('react/jsx-runtime');
14
14
  var FormInfo = require('@kne/form-info');
15
+ var InfoPage = require('@kne/info-page');
15
16
 
16
17
  function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
17
18
 
18
19
  var SelectList__default = /*#__PURE__*/_interopDefaultLegacy(SelectList);
19
20
  var FormInfo__default = /*#__PURE__*/_interopDefaultLegacy(FormInfo);
21
+ var InfoPage__default = /*#__PURE__*/_interopDefaultLegacy(InfoPage);
20
22
 
21
- var style = {"kne-responsive-boundary":"kne-form-creator_gh14z","kne-responsive-scroll":"kne-form-creator_Kfn6L","form-creator":"kne-form-creator_Xrjrk","editor-pane":"kne-form-creator_Skfuv","preview-pane":"kne-form-creator_v4Lsp","editor-header":"kne-form-creator_WaSS-","block-list-panel":"kne-form-creator_lx8An","form-actions-setting-btn":"kne-form-creator_NekU2","panel-toolbar":"kne-form-creator_t0WxZ","add-block-btn":"kne-form-creator_16Zre","add-inline-btn":"kne-form-creator_iCYdB","ant-btn-disabled":"kne-form-creator_LdGtv","block-list":"kne-form-creator_wK5eK","block-section":"kne-form-creator_15IiK","block-kind-formInfo":"kne-form-creator_D0hoK","block-kind-list":"kne-form-creator_JdPhy","block-kind-tableList":"kne-form-creator_gzd64","block-kind-multiField":"kne-form-creator_t0iOJ","block-kind-steps":"kne-form-creator_QNF9W","step-section":"kne-form-creator_22ajp","block-section-header":"kne-form-creator_wS4rL","block-header-left":"kne-form-creator_t4awC","block-title":"kne-form-creator_wSVJf","block-summary":"kne-form-creator_GzeW8","block-header-actions":"kne-form-creator_Ue-nT","block-body":"kne-form-creator_je1H0","section-toolbar":"kne-form-creator_LUO8S","section-toolbar-label":"kne-form-creator_7KQ79","field-list":"kne-form-creator_-B7WZ","step-list":"kne-form-creator_kc1pH","step-section-header":"kne-form-creator_wkhEX","step-section-title":"kne-form-creator_NBinE","step-index":"kne-form-creator_CCKZZ","field-row":"kne-form-creator_XMkdt","field-row-index":"kne-form-creator_a-cDo","field-row-main":"kne-form-creator_ftlwp","inline-empty":"kne-form-creator_yP-RF","action-group":"kne-form-creator_773yo","hover-reveal":"kne-form-creator_S234h","action-btn":"kne-form-creator_mLgqh","add-block-dropdown":"kne-form-creator_vmS-e","add-block-option":"kne-form-creator_gjg2Y","add-block-option-icon":"kne-form-creator_qh1hh","add-block-option-text":"kne-form-creator_G8iJO","add-block-option-title":"kne-form-creator_ETSvm","add-block-option-desc":"kne-form-creator_O0C3l","field-empty":"kne-form-creator_Nmpfl","field-label-tips-icon":"kne-form-creator_0VVaO","preview-header":"kne-form-creator_c4BT0","preview-title":"kne-form-creator_fPkK4","preview-body":"kne-form-creator_6JntQ","schema-form":"kne-form-creator_MxCWP","schema-body":"kne-form-creator_q9ydz","schema-actions":"kne-form-creator_Y4eEH","schema-actions-inner":"kne-form-creator_FT9Zf","field-editor-form":"kne-form-creator_PGPHL","form-actions-editor":"kne-form-creator_fchMy","form-actions-switch-field":"kne-form-creator_6JE9x","form-actions-layout-panel":"kne-form-creator_rtm9D","form-actions-align-group":"kne-form-creator_51ZsV","form-actions-layout-title":"kne-form-creator_hFeiC","form-actions-gap-slider":"kne-form-creator_Gq0bk","editor-section":"kne-form-creator_jJy85","section-divider":"kne-form-creator_zA7L-","rule-editor":"kne-form-creator_bAlGU","options-editor":"kne-form-creator_AK4yO","super-select-props":"kne-form-creator_Iawhh","field-props-editor":"kne-form-creator_Gabf2","columns-editor":"kne-form-creator_DQW1N","prop-row":"kne-form-creator_7K54P","prop-label":"kne-form-creator_HAAyH","options-item":"kne-form-creator_dnOd2","table-row-card":"kne-form-creator_cwCYp","tree-options-editor":"kne-form-creator_s3nHO","tree-options-list":"kne-form-creator_Djs-E","tree-option-node":"kne-form-creator_XAcut","tree-option-row":"kne-form-creator_4K4Rj","tree-option-fields":"kne-form-creator_-4cjc","tree-option-actions":"kne-form-creator_IjCNI","tree-option-children":"kne-form-creator_pVPGJ","tree-add-sibling":"kne-form-creator_bl46P","rule-checkbox-group":"kne-form-creator_tDgVP","rule-len-row":"kne-form-creator_ATsae","rule-len-input":"kne-form-creator_jY4Ld","rule-len-sep":"kne-form-creator_jBDC8","options-list":"kne-form-creator_GUBNS","options-row":"kne-form-creator_uohD0","options-tip":"kne-form-creator_vrTmK","icon-square-btn":"kne-form-creator_DZjCf","icon-square-btn-sm":"kne-form-creator_GAh-t","is-mobile":"kne-form-creator_LtgJz"};
23
+ var style = {"kne-responsive-boundary":"kne-form-creator_gh14z","kne-responsive-scroll":"kne-form-creator_Kfn6L","form-creator":"kne-form-creator_Xrjrk","editor-pane":"kne-form-creator_Skfuv","preview-pane":"kne-form-creator_v4Lsp","editor-header":"kne-form-creator_WaSS-","block-list-panel":"kne-form-creator_lx8An","form-actions-setting-btn":"kne-form-creator_NekU2","panel-toolbar":"kne-form-creator_t0WxZ","add-block-btn":"kne-form-creator_16Zre","add-inline-btn":"kne-form-creator_iCYdB","ant-btn-disabled":"kne-form-creator_LdGtv","block-list":"kne-form-creator_wK5eK","block-section":"kne-form-creator_15IiK","block-kind-formInfo":"kne-form-creator_D0hoK","block-kind-list":"kne-form-creator_JdPhy","block-kind-tableList":"kne-form-creator_gzd64","block-kind-multiField":"kne-form-creator_t0iOJ","block-kind-steps":"kne-form-creator_QNF9W","step-section":"kne-form-creator_22ajp","block-section-header":"kne-form-creator_wS4rL","block-header-left":"kne-form-creator_t4awC","block-title":"kne-form-creator_wSVJf","block-summary":"kne-form-creator_GzeW8","block-header-actions":"kne-form-creator_Ue-nT","block-body":"kne-form-creator_je1H0","item-blocks-section":"kne-form-creator_wq4bT","nested-block-list":"kne-form-creator_4NWH4","block-section-nested":"kne-form-creator_mUKom","add-field-dropdown":"kne-form-creator_9JS0d","add-field-dropdown-item":"kne-form-creator_Ql1z3","add-field-dropdown-item-icon":"kne-form-creator_ZHB5O","add-field-dropdown-item-desc":"kne-form-creator_dcsOS","add-field-dropdown-divider":"kne-form-creator_CUK0H","add-field-dropdown-label":"kne-form-creator_bPJ-2","section-toolbar":"kne-form-creator_LUO8S","section-toolbar-label":"kne-form-creator_7KQ79","field-list":"kne-form-creator_-B7WZ","step-list":"kne-form-creator_kc1pH","step-section-header":"kne-form-creator_wkhEX","step-section-title":"kne-form-creator_NBinE","step-index":"kne-form-creator_CCKZZ","field-row":"kne-form-creator_XMkdt","field-row-index":"kne-form-creator_a-cDo","field-row-main":"kne-form-creator_ftlwp","inline-empty":"kne-form-creator_yP-RF","action-group":"kne-form-creator_773yo","hover-reveal":"kne-form-creator_S234h","hover-reveal-active":"kne-form-creator_AE-6r","action-btn":"kne-form-creator_mLgqh","add-block-dropdown":"kne-form-creator_vmS-e","add-block-option":"kne-form-creator_gjg2Y","add-block-option-icon":"kne-form-creator_qh1hh","add-block-option-text":"kne-form-creator_G8iJO","add-block-option-title":"kne-form-creator_ETSvm","add-block-option-desc":"kne-form-creator_O0C3l","field-empty":"kne-form-creator_Nmpfl","field-label-tips-icon":"kne-form-creator_0VVaO","preview-header":"kne-form-creator_c4BT0","preview-title":"kne-form-creator_fPkK4","preview-body":"kne-form-creator_6JntQ","schema-form":"kne-form-creator_MxCWP","schema-body":"kne-form-creator_q9ydz","schema-actions":"kne-form-creator_Y4eEH","schema-actions-inner":"kne-form-creator_FT9Zf","choice-block":"kne-form-creator_RllJe","choice-selector":"kne-form-creator_5A1eM","choice-panels":"kne-form-creator_IO0MY","choice-panels-empty":"kne-form-creator_T0nND","choice-option-panel":"kne-form-creator_FQixN","choice-option-panel-title":"kne-form-creator_ofRo2","choice-option-summary":"kne-form-creator_pksH8","field-editor-form":"kne-form-creator_PGPHL","form-actions-editor":"kne-form-creator_fchMy","form-actions-switch-field":"kne-form-creator_6JE9x","form-actions-layout-panel":"kne-form-creator_rtm9D","form-actions-align-group":"kne-form-creator_51ZsV","form-actions-layout-title":"kne-form-creator_hFeiC","form-actions-gap-slider":"kne-form-creator_Gq0bk","editor-section":"kne-form-creator_jJy85","section-divider":"kne-form-creator_zA7L-","rule-editor":"kne-form-creator_bAlGU","options-editor":"kne-form-creator_AK4yO","super-select-props":"kne-form-creator_Iawhh","field-props-editor":"kne-form-creator_Gabf2","columns-editor":"kne-form-creator_DQW1N","prop-row":"kne-form-creator_7K54P","prop-label":"kne-form-creator_HAAyH","options-item":"kne-form-creator_dnOd2","table-row-card":"kne-form-creator_cwCYp","tree-options-editor":"kne-form-creator_s3nHO","tree-options-list":"kne-form-creator_Djs-E","tree-option-node":"kne-form-creator_XAcut","tree-option-row":"kne-form-creator_4K4Rj","tree-option-fields":"kne-form-creator_-4cjc","tree-option-actions":"kne-form-creator_IjCNI","tree-option-children":"kne-form-creator_pVPGJ","tree-add-sibling":"kne-form-creator_bl46P","rule-checkbox-group":"kne-form-creator_tDgVP","rule-len-row":"kne-form-creator_ATsae","rule-len-input":"kne-form-creator_jY4Ld","rule-len-sep":"kne-form-creator_jBDC8","options-list":"kne-form-creator_GUBNS","options-row":"kne-form-creator_uohD0","options-tip":"kne-form-creator_vrTmK","icon-square-btn":"kne-form-creator_DZjCf","icon-square-btn-sm":"kne-form-creator_GAh-t","is-mobile":"kne-form-creator_LtgJz"};
22
24
 
23
25
  const locale$1 = {
24
26
  addField: '添加填写项',
@@ -39,18 +41,49 @@ const locale$1 = {
39
41
  expandBlock: '展开',
40
42
  collapseBlock: '收起',
41
43
  fieldCount: '{count} 个填写项',
44
+ fieldAndItemBlockCount: '{fields} 个填写项 · {nests} 个子模块',
45
+ addChildBlock: '添加子模块',
42
46
  stepCount: '{count} 个步骤',
43
47
  blockKind_formInfo: '基础表单',
44
48
  blockKind_list: '可增减列表',
45
49
  blockKind_tableList: '表格列表',
46
50
  blockKind_multiField: '同类多值',
51
+ blockKind_object: '分组信息',
52
+ blockKind_choice: '选项切换',
47
53
  blockKind_steps: '分步表单',
54
+ choiceMode: '可选几个',
55
+ choiceModeSingle: '只能选一个',
56
+ choiceModeMultiple: '可以选多个',
57
+ choiceMinSelect: '最少选择几个',
58
+ choiceMaxSelect: '最多选择几个',
59
+ choiceMinSelectError: '请至少选择 {count} 项',
60
+ choiceMaxSelectError: '最多只能选择 {count} 项',
61
+ choiceSelectorName: '所选结果的名称',
62
+ choiceSelectorNamePlaceholder: '可不填,系统会自动生成',
63
+ choiceSelectorInData: '提交时带上所选结果',
64
+ choiceTitlePlaceholder: '例如:客户类型',
65
+ choiceOptionListTitle: '选项列表',
66
+ addChoiceOption: '添加选项',
67
+ editChoiceOption: '编辑选项',
68
+ deleteChoiceOption: '删除选项',
69
+ choiceOptionTitle: '选项名称',
70
+ choiceOptionTitlePlaceholder: '例如:企业、个人',
71
+ emptyChoiceOptionList: '暂无选项,点击上方添加',
72
+ choiceOptionFallback: '选项{index}',
73
+ choiceOptionCount: '{count} 个选项',
74
+ choiceAreaTitle: '请选择',
75
+ choiceModeHintSingle: '请选择其中一项',
76
+ choiceModeHintMultiple: '可以选择多项',
77
+ choiceModeHintMultipleMin: '请至少选择 {count} 项',
78
+ choiceModeHintMultipleMax: '最多选择 {count} 项',
79
+ choiceModeHintMultipleRange: '请选择 {min}–{max} 项',
80
+ choiceSelectFirstHint: '请先在上方选择,再填写对应内容',
48
81
  blockTitle: '模块标题',
49
82
  blockTitlePlaceholder: '例如:基本信息',
50
83
  blockSubtitle: '模块副标题',
51
84
  blockSubtitlePlaceholder: '例如:请填写员工基本信息',
52
- blockName: '数据标识',
53
- blockNameRequired: '请填写数据标识',
85
+ blockName: '保存用的名称',
86
+ blockNameRequired: '请填写保存用的名称',
54
87
  blockGap: '间距',
55
88
  blockBordered: '显示边框',
56
89
  blockImportant: '突出显示',
@@ -74,7 +107,7 @@ const locale$1 = {
74
107
  stepNext: '下一步',
75
108
  stepComplete: '完成',
76
109
  fieldType: '填写项类型',
77
- fieldName: '数据标识',
110
+ fieldName: '保存用的名称',
78
111
  fieldNamePlaceholder: '已自动生成,可修改',
79
112
  fieldLabel: '显示名称',
80
113
  fieldLabelPlaceholder: '例如:姓名',
@@ -89,7 +122,7 @@ const locale$1 = {
89
122
  fieldHidden: '隐藏该项',
90
123
  fieldHiddenTag: '已隐藏',
91
124
  fieldBlockTag: '整行',
92
- fieldNameDuplicate: '该数据标识已被使用,请换一个',
125
+ fieldNameDuplicate: '该名称已被使用,请换一个',
93
126
  untitledField: '未命名填写项',
94
127
  previewTitle: '表单预览',
95
128
  previewHint: '左侧的配置变化会实时同步到这里',
@@ -128,9 +161,9 @@ const locale$1 = {
128
161
  columnNamePlaceholder: '已自动生成,可修改',
129
162
  columnWidthPlaceholder: '列宽(可选)',
130
163
  addColumn: '添加一列',
131
- columnsEditorHint: '列标题用于表头展示;数据名已自动生成,需要时可改',
164
+ columnsEditorHint: '列标题用于表头展示;保存用的名称已自动生成,需要时可改',
132
165
  fieldTableRows: '表格数据',
133
- tableRowsNeedColumnsHint: '请先在上方填写列的数据名,再来配置每一行数据',
166
+ tableRowsNeedColumnsHint: '请先在上方填写列的保存名称,再来配置每一行数据',
134
167
  tableRowTitle: '第 {index} 行',
135
168
  tableRowLabelPlaceholder: '选中后显示的文字',
136
169
  addTableRow: '添加一行数据',
@@ -204,18 +237,49 @@ const locale = {
204
237
  expandBlock: 'Expand',
205
238
  collapseBlock: 'Collapse',
206
239
  fieldCount: '{count} fields',
240
+ fieldAndItemBlockCount: '{fields} fields · {nests} child sections',
241
+ addChildBlock: 'Add child section',
207
242
  stepCount: '{count} steps',
208
243
  blockKind_formInfo: 'Basic Form',
209
244
  blockKind_list: 'Repeatable List',
210
245
  blockKind_tableList: 'Table List',
211
246
  blockKind_multiField: 'Multi-Value',
247
+ blockKind_object: 'Grouped Fields',
248
+ blockKind_choice: 'Options',
212
249
  blockKind_steps: 'Step-by-Step',
250
+ choiceMode: 'How many can be selected',
251
+ choiceModeSingle: 'One only',
252
+ choiceModeMultiple: 'More than one',
253
+ choiceMinSelect: 'Minimum selections',
254
+ choiceMaxSelect: 'Maximum selections',
255
+ choiceMinSelectError: 'Select at least {count}',
256
+ choiceMaxSelectError: 'Select at most {count}',
257
+ choiceSelectorName: 'Name for the selection',
258
+ choiceSelectorNamePlaceholder: 'Optional — generated automatically if empty',
259
+ choiceSelectorInData: 'Include the selection when submitting',
260
+ choiceTitlePlaceholder: 'e.g. Customer type',
261
+ choiceOptionListTitle: 'Options',
262
+ addChoiceOption: 'Add option',
263
+ editChoiceOption: 'Edit option',
264
+ deleteChoiceOption: 'Delete option',
265
+ choiceOptionTitle: 'Option name',
266
+ choiceOptionTitlePlaceholder: 'e.g. Company, Individual',
267
+ emptyChoiceOptionList: 'No options yet. Click above to add one.',
268
+ choiceOptionFallback: 'Option {index}',
269
+ choiceOptionCount: '{count} options',
270
+ choiceAreaTitle: 'Please select',
271
+ choiceModeHintSingle: 'Select one option',
272
+ choiceModeHintMultiple: 'You can select more than one',
273
+ choiceModeHintMultipleMin: 'Select at least {count}',
274
+ choiceModeHintMultipleMax: 'Select at most {count}',
275
+ choiceModeHintMultipleRange: 'Select {min}–{max} options',
276
+ choiceSelectFirstHint: 'Select an option above to continue',
213
277
  blockTitle: 'Section Title',
214
278
  blockTitlePlaceholder: 'e.g. Basic Info',
215
279
  blockSubtitle: 'Section Subtitle',
216
280
  blockSubtitlePlaceholder: 'e.g. Please fill in employee info',
217
- blockName: 'Data Key',
218
- blockNameRequired: 'Data key is required',
281
+ blockName: 'Save name',
282
+ blockNameRequired: 'Please enter a save name',
219
283
  blockGap: 'Spacing',
220
284
  blockBordered: 'Show Border',
221
285
  blockImportant: 'Highlight',
@@ -239,7 +303,7 @@ const locale = {
239
303
  stepNext: 'Next',
240
304
  stepComplete: 'Done',
241
305
  fieldType: 'Field Type',
242
- fieldName: 'Data Key',
306
+ fieldName: 'Save name',
243
307
  fieldNamePlaceholder: 'Auto-generated, editable',
244
308
  fieldLabel: 'Display Name',
245
309
  fieldLabelPlaceholder: 'e.g. Full Name',
@@ -254,7 +318,7 @@ const locale = {
254
318
  fieldHidden: 'Hidden',
255
319
  fieldHiddenTag: 'Hidden',
256
320
  fieldBlockTag: 'Full Width',
257
- fieldNameDuplicate: 'This data key is already in use, please choose another',
321
+ fieldNameDuplicate: 'This name is already in use, please choose another',
258
322
  untitledField: 'Untitled Field',
259
323
  previewTitle: 'Form Preview',
260
324
  previewHint: 'Changes on the left are reflected here in real time',
@@ -375,6 +439,7 @@ const isAutoDataKey = function (value, prefix) {
375
439
  }
376
440
  return new RegExp(`^${prefix}_[a-z0-9]+_[a-z0-9]+$`, 'i').test(String(value || '').trim());
377
441
  };
442
+ const MAX_BLOCK_DEPTH = 5;
378
443
  const createEmptyColumn = () => ({
379
444
  title: '',
380
445
  name: createDataKey('col'),
@@ -456,10 +521,23 @@ const createField$1 = function (overrides) {
456
521
  ...overrides
457
522
  };
458
523
  };
524
+ const createChoiceOption = function (overrides) {
525
+ if (overrides === void 0) {
526
+ overrides = {};
527
+ }
528
+ return {
529
+ id: createFieldId(),
530
+ title: '',
531
+ list: [],
532
+ blocks: [],
533
+ ...overrides
534
+ };
535
+ };
459
536
  const createBlock = function (kind, overrides) {
460
537
  if (overrides === void 0) {
461
538
  overrides = {};
462
539
  }
540
+ const needsName = ['list', 'tableList', 'multiField', 'object'].includes(kind);
463
541
  const base = {
464
542
  id: createFieldId(),
465
543
  kind,
@@ -469,20 +547,30 @@ const createBlock = function (kind, overrides) {
469
547
  gap: 24,
470
548
  bordered: false,
471
549
  important: false,
472
- name: ['list', 'tableList', 'multiField'].includes(kind) ? createDataKey('block') : '',
550
+ name: needsName ? createDataKey(kind === 'object' ? 'obj' : 'block') : '',
473
551
  label: '',
474
552
  addText: '',
475
553
  maxLength: undefined,
476
554
  minLength: undefined,
477
555
  fieldType: 'Input',
478
556
  autoStep: true,
557
+ mode: 'single',
558
+ selectorName: '',
559
+ selectorInData: true,
560
+ discriminator: undefined,
479
561
  list: [],
480
- items: []
562
+ items: [],
563
+ itemBlocks: [],
564
+ blocks: [],
565
+ options: []
481
566
  };
482
567
  if (kind === 'steps') {
483
568
  return {
484
569
  ...base,
485
570
  list: undefined,
571
+ itemBlocks: undefined,
572
+ blocks: undefined,
573
+ options: undefined,
486
574
  items: [createStep()],
487
575
  ...overrides
488
576
  };
@@ -491,11 +579,64 @@ const createBlock = function (kind, overrides) {
491
579
  return {
492
580
  ...base,
493
581
  list: undefined,
582
+ itemBlocks: undefined,
583
+ blocks: undefined,
584
+ options: undefined,
585
+ items: undefined,
586
+ ...overrides
587
+ };
588
+ }
589
+ if (kind === 'choice') {
590
+ const next = {
591
+ ...base,
592
+ list: undefined,
593
+ itemBlocks: undefined,
594
+ blocks: undefined,
595
+ items: undefined,
596
+ name: '',
597
+ options: [createChoiceOption({
598
+ title: '选项1'
599
+ })],
600
+ ...overrides,
601
+ kind: 'choice'
602
+ };
603
+ next.mode = next.mode === 'multiple' ? 'multiple' : 'single';
604
+ if (!Array.isArray(next.options)) {
605
+ next.options = [createChoiceOption({
606
+ title: '选项1'
607
+ })];
608
+ }
609
+ return next;
610
+ }
611
+ if (kind === 'object') {
612
+ return {
613
+ ...base,
614
+ items: undefined,
615
+ options: undefined,
616
+ itemBlocks: undefined,
494
617
  ...overrides
495
618
  };
496
619
  }
620
+ if (kind === 'list') {
621
+ return {
622
+ ...base,
623
+ blocks: undefined,
624
+ ...overrides
625
+ };
626
+ }
627
+ if (kind === 'tableList') {
628
+ return {
629
+ ...base,
630
+ blocks: undefined,
631
+ itemBlocks: undefined,
632
+ ...overrides
633
+ };
634
+ }
635
+
636
+ // formInfo:支持 blocks 子模块
497
637
  return {
498
638
  ...base,
639
+ itemBlocks: undefined,
499
640
  ...overrides
500
641
  };
501
642
  };
@@ -508,9 +649,27 @@ const createStep = function (overrides) {
508
649
  title: '',
509
650
  column: 2,
510
651
  list: [],
652
+ blocks: [],
511
653
  ...overrides
512
654
  };
513
655
  };
656
+ const normalizeSelectCount = function (value, minAllowed) {
657
+ if (minAllowed === void 0) {
658
+ minAllowed = 0;
659
+ }
660
+ if (value == null || value === '') {
661
+ return undefined;
662
+ }
663
+ const num = Number(value);
664
+ if (!Number.isFinite(num)) {
665
+ return undefined;
666
+ }
667
+ const int = Math.floor(num);
668
+ if (int < minAllowed) {
669
+ return undefined;
670
+ }
671
+ return int;
672
+ };
514
673
  const normalizeField = field => ({
515
674
  ...createField$1(),
516
675
  ...field,
@@ -518,29 +677,113 @@ const normalizeField = field => ({
518
677
  ...(field.props || {})
519
678
  }
520
679
  });
521
- const normalizeStep = step => ({
522
- ...createStep(),
523
- ...step,
524
- list: Array.isArray(step.list) ? step.list.map(normalizeField) : []
525
- });
526
- const normalizeBlock = block => {
680
+ const normalizeStep = function (step, depth) {
681
+ if (depth === void 0) {
682
+ depth = 0;
683
+ }
684
+ return {
685
+ ...createStep(),
686
+ ...step,
687
+ list: Array.isArray(step.list) ? step.list.map(normalizeField) : [],
688
+ blocks: Array.isArray(step.blocks) ? step.blocks.map(child => normalizeBlock(child, depth + 1)) : []
689
+ };
690
+ };
691
+ const normalizeChoiceOption = (option, depth) => {
692
+ let list = Array.isArray(option.list) ? option.list.map(normalizeField) : [];
693
+ let blocks = Array.isArray(option.blocks) ? option.blocks.map(block => normalizeBlock(block, depth + 1)) : [];
694
+
695
+ // 兼容仅写 blocks: [formInfo] 的写法:把首个 formInfo 的字段提升到 option.list,便于编辑器管理
696
+ if (!list.length && blocks[0]?.kind === 'formInfo' && (blocks[0].list || []).length) {
697
+ list = (blocks[0].list || []).map(normalizeField);
698
+ blocks = blocks.slice(1);
699
+ }
700
+ return {
701
+ ...createChoiceOption(),
702
+ ...option,
703
+ list,
704
+ blocks
705
+ };
706
+ };
707
+ const normalizeBlock = function (block, depth) {
708
+ if (depth === void 0) {
709
+ depth = 0;
710
+ }
527
711
  const kind = block.kind || 'formInfo';
712
+ if (depth > MAX_BLOCK_DEPTH) {
713
+ return {
714
+ ...createBlock(kind),
715
+ ...block,
716
+ list: Array.isArray(block.list) ? block.list.map(normalizeField) : [],
717
+ itemBlocks: [],
718
+ options: [],
719
+ items: kind === 'steps' ? [createStep()] : undefined
720
+ };
721
+ }
528
722
  const normalized = {
529
723
  ...createBlock(kind),
530
724
  ...block
531
725
  };
532
726
  if (kind === 'steps') {
533
- normalized.items = Array.isArray(block.items) ? block.items.map(normalizeStep) : [createStep()];
727
+ normalized.items = Array.isArray(block.items) ? block.items.map(step => normalizeStep(step, depth)) : [createStep()];
534
728
  delete normalized.list;
729
+ delete normalized.itemBlocks;
730
+ delete normalized.blocks;
731
+ delete normalized.options;
535
732
  return normalized;
536
733
  }
537
734
  if (kind === 'multiField') {
538
735
  normalized.list = undefined;
539
736
  normalized.items = undefined;
737
+ normalized.itemBlocks = undefined;
738
+ normalized.blocks = undefined;
739
+ normalized.options = undefined;
740
+ return normalized;
741
+ }
742
+ if (kind === 'choice') {
743
+ normalized.mode = block.mode === 'multiple' ? 'multiple' : 'single';
744
+ normalized.selectorName = block.selectorName != null ? String(block.selectorName) : '';
745
+ normalized.selectorInData = block.selectorInData !== false;
746
+ normalized.discriminator = block.discriminator && typeof block.discriminator === 'object' ? {
747
+ ...block.discriminator
748
+ } : undefined;
749
+ normalized.options = Array.isArray(block.options) ? block.options.map(option => normalizeChoiceOption(option, depth)) : [];
750
+ normalized.list = undefined;
751
+ normalized.items = undefined;
752
+ normalized.itemBlocks = undefined;
753
+ normalized.blocks = undefined;
754
+ if (normalized.mode === 'multiple') {
755
+ const minSelect = normalizeSelectCount(block.minLength, 0);
756
+ const maxSelect = normalizeSelectCount(block.maxLength, 1);
757
+ normalized.minLength = minSelect;
758
+ normalized.maxLength = maxSelect != null && minSelect != null && maxSelect < minSelect ? minSelect : maxSelect;
759
+ } else {
760
+ normalized.minLength = undefined;
761
+ normalized.maxLength = undefined;
762
+ }
763
+ return normalized;
764
+ }
765
+ if (kind === 'object') {
766
+ normalized.list = Array.isArray(block.list) ? block.list.map(normalizeField) : [];
767
+ normalized.items = undefined;
768
+ normalized.itemBlocks = undefined;
769
+ normalized.options = undefined;
770
+ normalized.blocks = Array.isArray(block.blocks) ? block.blocks.map(child => normalizeBlock(child, depth + 1)) : [];
540
771
  return normalized;
541
772
  }
542
773
  normalized.list = Array.isArray(block.list) ? block.list.map(normalizeField) : [];
543
774
  normalized.items = undefined;
775
+ normalized.options = undefined;
776
+ if (kind === 'list') {
777
+ normalized.itemBlocks = Array.isArray(block.itemBlocks) ? block.itemBlocks.map(child => normalizeBlock(child, depth + 1)) : [];
778
+ normalized.blocks = undefined;
779
+ } else if (kind === 'tableList') {
780
+ normalized.itemBlocks = undefined;
781
+ normalized.blocks = undefined;
782
+ } else {
783
+ // formInfo
784
+ normalized.itemBlocks = undefined;
785
+ normalized.blocks = Array.isArray(block.blocks) ? block.blocks.map(child => normalizeBlock(child, depth + 1)) : [];
786
+ }
544
787
  return normalized;
545
788
  };
546
789
  const normalizeSchema = function (schema) {
@@ -553,7 +796,7 @@ const normalizeSchema = function (schema) {
553
796
  ...base,
554
797
  ...schema,
555
798
  actions: normalizeFormActions(schema.actions),
556
- blocks: schema.blocks.map(normalizeBlock)
799
+ blocks: schema.blocks.map(block => normalizeBlock(block))
557
800
  };
558
801
  }
559
802
  if (Array.isArray(schema.list) && schema.list.length) {
@@ -598,54 +841,359 @@ const isFieldNameUnique = (fields, name, excludeId) => {
598
841
  }
599
842
  return !fields.some(item => item.name === name && item.id !== excludeId);
600
843
  };
601
- const collectSchemaFields = function (schema, _temp) {
602
- let {
603
- blockId,
604
- stepId
605
- } = _temp === void 0 ? {} : _temp;
606
- const blocks = schema.blocks || [];
607
- const fields = [];
844
+ const collectFieldsFromBlocks = function (blocks, acc) {
845
+ if (blocks === void 0) {
846
+ blocks = [];
847
+ }
848
+ if (acc === void 0) {
849
+ acc = [];
850
+ }
608
851
  blocks.forEach(block => {
609
- if (blockId && block.id !== blockId) {
852
+ if (!block) {
610
853
  return;
611
854
  }
612
855
  if (block.kind === 'steps') {
613
856
  (block.items || []).forEach(step => {
614
- if (stepId !== undefined && step.id !== stepId) {
615
- return;
616
- }
617
- fields.push(...(step.list || []));
857
+ acc.push(...(step.list || []));
858
+ collectFieldsFromBlocks(step.blocks || [], acc);
618
859
  });
619
860
  return;
620
861
  }
621
- if (block.kind !== 'multiField') {
622
- fields.push(...(block.list || []));
862
+ if (block.kind === 'choice') {
863
+ (block.options || []).forEach(option => {
864
+ acc.push(...(option.list || []));
865
+ collectFieldsFromBlocks(option.blocks || [], acc);
866
+ });
867
+ return;
868
+ }
869
+ if (block.kind !== 'multiField' && Array.isArray(block.list)) {
870
+ acc.push(...block.list);
871
+ }
872
+ if (Array.isArray(block.itemBlocks)) {
873
+ collectFieldsFromBlocks(block.itemBlocks, acc);
874
+ }
875
+ if (Array.isArray(block.blocks)) {
876
+ collectFieldsFromBlocks(block.blocks, acc);
623
877
  }
624
878
  });
879
+ return acc;
880
+ };
881
+ const collectSchemaFields = function (schema, _temp) {
882
+ let {
883
+ blockId,
884
+ stepId,
885
+ optionId
886
+ } = _temp === void 0 ? {} : _temp;
887
+ const blocks = schema.blocks || [];
888
+ if (!blockId) {
889
+ return collectFieldsFromBlocks(blocks);
890
+ }
891
+ const block = findBlockInTree(blocks, blockId);
892
+ if (!block) {
893
+ return [];
894
+ }
895
+ const fields = [];
896
+ if (block.kind === 'steps') {
897
+ (block.items || []).forEach(step => {
898
+ if (stepId !== undefined && step.id !== stepId) {
899
+ return;
900
+ }
901
+ fields.push(...(step.list || []));
902
+ });
903
+ return fields;
904
+ }
905
+ if (block.kind === 'choice') {
906
+ (block.options || []).forEach(option => {
907
+ if (optionId !== undefined && option.id !== optionId) {
908
+ return;
909
+ }
910
+ fields.push(...(option.list || []));
911
+ collectFieldsFromBlocks(option.blocks || [], fields);
912
+ });
913
+ return fields;
914
+ }
915
+ if (block.kind !== 'multiField') {
916
+ fields.push(...(block.list || []));
917
+ }
625
918
  return fields;
626
919
  };
920
+
921
+ /** 收集 blocks 树中所有字段 name(含 object 前缀后的完整名需在渲染层处理) */
922
+ const collectBlockFieldNames = function (blocks, _temp2) {
923
+ if (blocks === void 0) {
924
+ blocks = [];
925
+ }
926
+ let {
927
+ objectNamePrefix = ''
928
+ } = _temp2 === void 0 ? {} : _temp2;
929
+ const names = [];
930
+ const walk = (list, prefix) => {
931
+ (list || []).forEach(block => {
932
+ if (!block) {
933
+ return;
934
+ }
935
+ if (block.kind === 'object') {
936
+ const nextPrefix = [prefix, block.name].filter(Boolean).join('.');
937
+ (block.list || []).forEach(field => {
938
+ if (field?.name) {
939
+ names.push(nextPrefix ? `${nextPrefix}.${field.name}` : field.name);
940
+ }
941
+ });
942
+ walk(block.blocks || [], nextPrefix);
943
+ return;
944
+ }
945
+ if (block.kind === 'choice') {
946
+ (block.options || []).forEach(option => {
947
+ (option.list || []).forEach(field => {
948
+ if (field?.name) {
949
+ names.push(prefix ? `${prefix}.${field.name}` : field.name);
950
+ }
951
+ });
952
+ walk(option.blocks || [], prefix);
953
+ });
954
+ return;
955
+ }
956
+ if (block.kind === 'steps') {
957
+ (block.items || []).forEach(step => {
958
+ (step.list || []).forEach(field => {
959
+ if (field?.name) {
960
+ names.push(prefix ? `${prefix}.${field.name}` : field.name);
961
+ }
962
+ });
963
+ walk(step.blocks || [], prefix);
964
+ });
965
+ return;
966
+ }
967
+ if (block.kind !== 'multiField') {
968
+ (block.list || []).forEach(field => {
969
+ if (field?.name) {
970
+ names.push(prefix ? `${prefix}.${field.name}` : field.name);
971
+ }
972
+ });
973
+ }
974
+ if (block.kind === 'list') {
975
+ // 列表项内字段相对 GroupList,此处只收集定义名供 choice 清理参考
976
+ walk(block.itemBlocks || [], prefix);
977
+ }
978
+ if (Array.isArray(block.blocks)) {
979
+ walk(block.blocks, prefix);
980
+ }
981
+ });
982
+ };
983
+ walk(blocks, objectNamePrefix);
984
+ return names;
985
+ };
627
986
  const updateBlocks = (schema, updater) => ({
628
987
  ...schema,
629
988
  blocks: updater(schema.blocks || [])
630
989
  });
631
- const findBlock = (schema, blockId) => (schema.blocks || []).find(block => block.id === blockId);
632
- const mapBlocks = (schema, blockId, updater) => updateBlocks(schema, blocks => blocks.map(block => {
633
- if (block.id !== blockId) {
634
- return block;
990
+
991
+ /** blocks / itemBlocks / choice.options.blocks / steps.items.blocks 树中查找模块 */
992
+ const findBlockInTree = function (blocks, blockId) {
993
+ if (blocks === void 0) {
994
+ blocks = [];
635
995
  }
636
- return updater(block);
637
- }));
638
- const hasRenderableContent = schema => {
639
- const blocks = schema.blocks || [];
640
- return blocks.some(block => {
996
+ for (const block of blocks) {
997
+ if (!block) {
998
+ continue;
999
+ }
1000
+ if (block.id === blockId) {
1001
+ return block;
1002
+ }
1003
+ if (Array.isArray(block.itemBlocks)) {
1004
+ const found = findBlockInTree(block.itemBlocks, blockId);
1005
+ if (found) {
1006
+ return found;
1007
+ }
1008
+ }
1009
+ if (Array.isArray(block.blocks)) {
1010
+ const found = findBlockInTree(block.blocks, blockId);
1011
+ if (found) {
1012
+ return found;
1013
+ }
1014
+ }
1015
+ if (block.kind === 'choice') {
1016
+ for (const option of block.options || []) {
1017
+ const found = findBlockInTree(option.blocks || [], blockId);
1018
+ if (found) {
1019
+ return found;
1020
+ }
1021
+ }
1022
+ }
641
1023
  if (block.kind === 'steps') {
642
- return (block.items || []).some(step => (step.list || []).length > 0);
1024
+ for (const step of block.items || []) {
1025
+ const found = findBlockInTree(step.blocks || [], blockId);
1026
+ if (found) {
1027
+ return found;
1028
+ }
1029
+ }
643
1030
  }
644
- if (block.kind === 'multiField') {
645
- return !!block.name;
1031
+ }
1032
+ return null;
1033
+ };
1034
+ const findBlock = (schema, blockId) => findBlockInTree(schema.blocks || [], blockId);
1035
+
1036
+ /** 对模块上挂载的子模块列表(itemBlocks / blocks / option.blocks / step.blocks)应用同一变换 */
1037
+ const mapChildBlockLists = (block, mapList) => {
1038
+ let nextBlock = block;
1039
+ let changed = false;
1040
+ if (Array.isArray(block.itemBlocks)) {
1041
+ const itemBlocks = mapList(block.itemBlocks);
1042
+ if (itemBlocks !== block.itemBlocks) {
1043
+ nextBlock = {
1044
+ ...nextBlock,
1045
+ itemBlocks
1046
+ };
1047
+ changed = true;
646
1048
  }
647
- return (block.list || []).length > 0 || block.title;
1049
+ }
1050
+ if (Array.isArray(block.blocks)) {
1051
+ const childBlocks = mapList(block.blocks);
1052
+ if (childBlocks !== block.blocks) {
1053
+ nextBlock = {
1054
+ ...nextBlock,
1055
+ blocks: childBlocks
1056
+ };
1057
+ changed = true;
1058
+ }
1059
+ }
1060
+ if (block.kind === 'choice' && Array.isArray(block.options)) {
1061
+ let optionsChanged = false;
1062
+ const options = block.options.map(option => {
1063
+ if (!Array.isArray(option.blocks)) {
1064
+ return option;
1065
+ }
1066
+ const optionBlocks = mapList(option.blocks);
1067
+ if (optionBlocks !== option.blocks) {
1068
+ optionsChanged = true;
1069
+ return {
1070
+ ...option,
1071
+ blocks: optionBlocks
1072
+ };
1073
+ }
1074
+ return option;
1075
+ });
1076
+ if (optionsChanged) {
1077
+ nextBlock = {
1078
+ ...nextBlock,
1079
+ options
1080
+ };
1081
+ changed = true;
1082
+ }
1083
+ }
1084
+ if (block.kind === 'steps' && Array.isArray(block.items)) {
1085
+ let itemsChanged = false;
1086
+ const items = block.items.map(step => {
1087
+ if (!Array.isArray(step.blocks)) {
1088
+ return step;
1089
+ }
1090
+ const stepBlocks = mapList(step.blocks);
1091
+ if (stepBlocks !== step.blocks) {
1092
+ itemsChanged = true;
1093
+ return {
1094
+ ...step,
1095
+ blocks: stepBlocks
1096
+ };
1097
+ }
1098
+ return step;
1099
+ });
1100
+ if (itemsChanged) {
1101
+ nextBlock = {
1102
+ ...nextBlock,
1103
+ items
1104
+ };
1105
+ changed = true;
1106
+ }
1107
+ }
1108
+ return {
1109
+ nextBlock,
1110
+ changed
1111
+ };
1112
+ };
1113
+ const mapBlocksInTree = (blocks, blockId, updater) => {
1114
+ let changed = false;
1115
+ const next = (blocks || []).map(block => {
1116
+ if (!block) {
1117
+ return block;
1118
+ }
1119
+ if (block.id === blockId) {
1120
+ changed = true;
1121
+ return updater(block);
1122
+ }
1123
+ const {
1124
+ nextBlock,
1125
+ changed: childChanged
1126
+ } = mapChildBlockLists(block, list => mapBlocksInTree(list, blockId, updater));
1127
+ if (childChanged) {
1128
+ changed = true;
1129
+ }
1130
+ return nextBlock;
648
1131
  });
1132
+ return changed ? next : blocks;
1133
+ };
1134
+ const mapBlocks = (schema, blockId, updater) => updateBlocks(schema, blocks => mapBlocksInTree(blocks, blockId, updater));
1135
+ const removeBlockInTree = (blocks, blockId) => {
1136
+ let changed = false;
1137
+ const filtered = (blocks || []).filter(block => {
1138
+ if (block?.id === blockId) {
1139
+ changed = true;
1140
+ return false;
1141
+ }
1142
+ return true;
1143
+ });
1144
+ const next = filtered.map(block => {
1145
+ const {
1146
+ nextBlock,
1147
+ changed: childChanged
1148
+ } = mapChildBlockLists(block, list => removeBlockInTree(list, blockId));
1149
+ if (childChanged) {
1150
+ changed = true;
1151
+ }
1152
+ return nextBlock;
1153
+ });
1154
+ return changed ? next : blocks;
1155
+ };
1156
+ const moveBlockInTree = (blocks, blockId, direction) => {
1157
+ if ((blocks || []).some(block => block?.id === blockId)) {
1158
+ return moveItem(blocks, blockId, direction);
1159
+ }
1160
+ let changed = false;
1161
+ const next = (blocks || []).map(block => {
1162
+ const {
1163
+ nextBlock,
1164
+ changed: childChanged
1165
+ } = mapChildBlockLists(block, list => moveBlockInTree(list, blockId, direction));
1166
+ if (childChanged) {
1167
+ changed = true;
1168
+ }
1169
+ return nextBlock;
1170
+ });
1171
+ return changed ? next : blocks;
1172
+ };
1173
+ const blockHasContent = block => {
1174
+ if (!block) {
1175
+ return false;
1176
+ }
1177
+ if (block.kind === 'steps') {
1178
+ return (block.items || []).some(step => (step.list || []).length > 0 || (step.blocks || []).some(blockHasContent) || step.title);
1179
+ }
1180
+ if (block.kind === 'multiField') {
1181
+ return !!block.name;
1182
+ }
1183
+ if (block.kind === 'choice') {
1184
+ return (block.options || []).some(option => (option.list || []).length > 0 || (option.blocks || []).some(blockHasContent) || option.title);
1185
+ }
1186
+ if (block.kind === 'object') {
1187
+ return !!(block.name && ((block.list || []).length > 0 || (block.blocks || []).some(blockHasContent) || block.title));
1188
+ }
1189
+ if ((block.list || []).length > 0 || block.title || (block.blocks || []).some(blockHasContent)) {
1190
+ return true;
1191
+ }
1192
+ return (block.itemBlocks || []).some(blockHasContent);
1193
+ };
1194
+ const hasRenderableContent = schema => {
1195
+ const blocks = schema.blocks || [];
1196
+ return blocks.some(blockHasContent);
649
1197
  };
650
1198
 
651
1199
  const BLOCK_KINDS = {
@@ -675,6 +1223,19 @@ const BLOCK_KINDS = {
675
1223
  requiresName: true,
676
1224
  description: '同一种填写项可以输入多个值,例如多个手机号'
677
1225
  },
1226
+ object: {
1227
+ label: '分组信息',
1228
+ color: 'orange',
1229
+ hasFieldList: true,
1230
+ requiresName: true,
1231
+ description: '把相关的填写项放在一起,例如「在校时间」下的开始与结束'
1232
+ },
1233
+ choice: {
1234
+ label: '选项切换',
1235
+ color: 'magenta',
1236
+ hasChoiceOptions: true,
1237
+ description: '先选一类情况,再填写对应内容;可设为单选或多选'
1238
+ },
678
1239
  steps: {
679
1240
  label: '分步表单',
680
1241
  color: 'gold',
@@ -704,15 +1265,20 @@ const blockToFormValues = block => ({
704
1265
  maxLength: block.maxLength ?? null,
705
1266
  minLength: block.minLength ?? null,
706
1267
  fieldType: block.fieldType || 'Input',
707
- autoStep: block.autoStep !== false
1268
+ autoStep: block.autoStep !== false,
1269
+ mode: block.mode === 'multiple' ? 'multiple' : 'single',
1270
+ selectorName: block.selectorName || '',
1271
+ selectorInData: block.selectorInData !== false
708
1272
  });
709
1273
  const formValuesToBlock = function (values, existingBlock) {
710
1274
  if (existingBlock === void 0) {
711
1275
  existingBlock = {};
712
1276
  }
713
- return {
1277
+ const kind = values.kind || existingBlock.kind;
1278
+ const mode = values.mode === 'multiple' ? 'multiple' : 'single';
1279
+ const next = {
714
1280
  ...existingBlock,
715
- kind: values.kind || existingBlock.kind,
1281
+ kind,
716
1282
  title: values.title,
717
1283
  subtitle: values.subtitle,
718
1284
  column: values.column ?? 2,
@@ -725,8 +1291,16 @@ const formValuesToBlock = function (values, existingBlock) {
725
1291
  maxLength: values.maxLength ?? undefined,
726
1292
  minLength: values.minLength ?? undefined,
727
1293
  fieldType: values.fieldType || 'Input',
728
- autoStep: values.autoStep !== false
1294
+ autoStep: values.autoStep !== false,
1295
+ mode,
1296
+ selectorName: values.selectorName || '',
1297
+ selectorInData: values.selectorInData !== false
729
1298
  };
1299
+ if (kind === 'choice' && mode !== 'multiple') {
1300
+ next.minLength = undefined;
1301
+ next.maxLength = undefined;
1302
+ }
1303
+ return next;
730
1304
  };
731
1305
  const stepToFormValues = step => ({
732
1306
  title: step.title || '',
@@ -742,6 +1316,18 @@ const formValuesToStep = function (values, existingStep) {
742
1316
  column: values.column ?? 2
743
1317
  };
744
1318
  };
1319
+ const choiceOptionToFormValues = option => ({
1320
+ title: option.title || ''
1321
+ });
1322
+ const formValuesToChoiceOption = function (values, existingOption) {
1323
+ if (existingOption === void 0) {
1324
+ existingOption = {};
1325
+ }
1326
+ return {
1327
+ ...existingOption,
1328
+ title: values.title
1329
+ };
1330
+ };
745
1331
 
746
1332
  const mapOptionItem = item => {
747
1333
  if (!item || typeof item !== 'object') {
@@ -828,7 +1414,7 @@ const DEFAULT_RULE_CONFIG = () => ({
828
1414
  });
829
1415
  const RULE_LEN_PRESET = 'LEN';
830
1416
 
831
- /** 注册填写项校验规则 preset,会在规则勾选面板中展示 */
1417
+ /** 内部:注册填写项校验规则,会在规则勾选面板中展示(请通过 preset 注册) */
832
1418
  const registerRulePreset = item => {
833
1419
  if (!item?.value) {
834
1420
  return;
@@ -1099,7 +1685,7 @@ defineField('DatePicker', {
1099
1685
  * - min / max?: number(type=number)
1100
1686
  * - options?: { label, value }[](type=select)
1101
1687
  *
1102
- * registerField(type, definition) 还可传:
1688
+ * preset({ type, definition }) 的 fields 项还可传:
1103
1689
  * - groupName?: string 自定义类型下拉分组名;不传则归入「扩展字段」
1104
1690
  */
1105
1691
  const registerField = (type, definition) => {
@@ -1695,6 +2281,31 @@ const IconBtn = _ref2 => {
1695
2281
  ...props
1696
2282
  });
1697
2283
  };
2284
+ const ROOT_ADD_OPTIONS = [{
2285
+ key: 'formInfo',
2286
+ icon: /*#__PURE__*/jsxRuntime.jsx(icons.FormOutlined, {})
2287
+ }, {
2288
+ key: 'list',
2289
+ icon: /*#__PURE__*/jsxRuntime.jsx(icons.UnorderedListOutlined, {})
2290
+ }, {
2291
+ key: 'tableList',
2292
+ icon: /*#__PURE__*/jsxRuntime.jsx(icons.TableOutlined, {})
2293
+ }, {
2294
+ key: 'object',
2295
+ icon: /*#__PURE__*/jsxRuntime.jsx(icons.ClusterOutlined, {})
2296
+ }, {
2297
+ key: 'choice',
2298
+ icon: /*#__PURE__*/jsxRuntime.jsx(icons.PartitionOutlined, {})
2299
+ }, {
2300
+ key: 'multiField',
2301
+ icon: /*#__PURE__*/jsxRuntime.jsx(icons.AppstoreOutlined, {})
2302
+ }, {
2303
+ key: 'steps',
2304
+ icon: /*#__PURE__*/jsxRuntime.jsx(icons.OrderedListOutlined, {})
2305
+ }];
2306
+
2307
+ /** 可挂子模块的容器;表格列表 / 同类多值本身不支持子模块 */
2308
+ const NESTED_ADD_OPTIONS = ROOT_ADD_OPTIONS.filter(opt => opt.key !== 'steps');
1698
2309
  const BlockListPanel = _ref3 => {
1699
2310
  let {
1700
2311
  blocks,
@@ -1710,29 +2321,165 @@ const BlockListPanel = _ref3 => {
1710
2321
  onEditStep,
1711
2322
  onDeleteStep,
1712
2323
  onMoveStep,
2324
+ onAddChoiceOption,
2325
+ onEditChoiceOption,
2326
+ onDeleteChoiceOption,
2327
+ onMoveChoiceOption,
1713
2328
  onOpenFormActions
1714
2329
  } = _ref3;
1715
2330
  const {
1716
2331
  formatMessage
1717
2332
  } = reactIntl.useIntl();
1718
2333
  const [addMenuOpen, setAddMenuOpen] = react.useState(false);
1719
- const addBlockOptions = [{
1720
- key: 'formInfo',
1721
- icon: /*#__PURE__*/jsxRuntime.jsx(icons.FormOutlined, {})
1722
- }, {
1723
- key: 'list',
1724
- icon: /*#__PURE__*/jsxRuntime.jsx(icons.UnorderedListOutlined, {})
1725
- }, {
1726
- key: 'tableList',
1727
- icon: /*#__PURE__*/jsxRuntime.jsx(icons.TableOutlined, {})
1728
- }, {
1729
- key: 'multiField',
1730
- icon: /*#__PURE__*/jsxRuntime.jsx(icons.AppstoreOutlined, {})
1731
- }, {
1732
- key: 'steps',
1733
- icon: /*#__PURE__*/jsxRuntime.jsx(icons.OrderedListOutlined, {})
1734
- }];
1735
- const renderFieldList = (fields, blockId, stepId) => {
2334
+ const [addFieldMenuId, setAddFieldMenuId] = react.useState(null);
2335
+ const renderAddBlockMenu = function (options, _temp) {
2336
+ let {
2337
+ onSelect,
2338
+ className
2339
+ } = _temp === void 0 ? {} : _temp;
2340
+ return /*#__PURE__*/jsxRuntime.jsx("div", {
2341
+ className: className || style['add-block-dropdown'],
2342
+ children: options.map(opt => {
2343
+ const definition = getBlockDefinition(opt.key);
2344
+ return /*#__PURE__*/jsxRuntime.jsxs("div", {
2345
+ role: "button",
2346
+ tabIndex: 0,
2347
+ className: style['add-block-option'],
2348
+ onClick: () => onSelect(opt.key),
2349
+ onKeyDown: e => {
2350
+ if (e.key === 'Enter' || e.key === ' ') {
2351
+ onSelect(opt.key);
2352
+ }
2353
+ },
2354
+ children: [/*#__PURE__*/jsxRuntime.jsx("div", {
2355
+ className: style['add-block-option-icon'],
2356
+ children: opt.icon
2357
+ }), /*#__PURE__*/jsxRuntime.jsxs("div", {
2358
+ className: style['add-block-option-text'],
2359
+ children: [/*#__PURE__*/jsxRuntime.jsx("div", {
2360
+ className: style['add-block-option-title'],
2361
+ children: formatMessage({
2362
+ id: `blockKind_${opt.key}`
2363
+ })
2364
+ }), /*#__PURE__*/jsxRuntime.jsx("div", {
2365
+ className: style['add-block-option-desc'],
2366
+ children: definition?.description
2367
+ })]
2368
+ })]
2369
+ }, opt.key);
2370
+ })
2371
+ });
2372
+ };
2373
+ const renderAddFieldButton = _ref4 => {
2374
+ let {
2375
+ menuKey,
2376
+ depth,
2377
+ onAddFieldClick,
2378
+ onAddChildBlock
2379
+ } = _ref4;
2380
+ const canAddChild = typeof onAddChildBlock === 'function' && depth < MAX_BLOCK_DEPTH;
2381
+ const menuOpen = addFieldMenuId === menuKey;
2382
+ const btnClass = `${style['add-inline-btn']} ${style['hover-reveal']} ${menuOpen ? style['hover-reveal-active'] : ''}`.trim();
2383
+ if (!canAddChild) {
2384
+ return /*#__PURE__*/jsxRuntime.jsx(antd.Button, {
2385
+ type: "text",
2386
+ size: "small",
2387
+ icon: /*#__PURE__*/jsxRuntime.jsx(icons.PlusOutlined, {}),
2388
+ className: btnClass,
2389
+ onClick: onAddFieldClick,
2390
+ children: formatMessage({
2391
+ id: 'addField'
2392
+ })
2393
+ });
2394
+ }
2395
+ return /*#__PURE__*/jsxRuntime.jsx(antd.Dropdown, {
2396
+ open: menuOpen,
2397
+ onOpenChange: open => setAddFieldMenuId(open ? menuKey : null),
2398
+ trigger: ['hover'],
2399
+ mouseEnterDelay: 0.1,
2400
+ mouseLeaveDelay: 0.15,
2401
+ getPopupContainer: trigger => trigger.parentElement || document.body,
2402
+ dropdownRender: () => /*#__PURE__*/jsxRuntime.jsxs("div", {
2403
+ className: style['add-field-dropdown'],
2404
+ children: [/*#__PURE__*/jsxRuntime.jsxs("div", {
2405
+ role: "button",
2406
+ tabIndex: 0,
2407
+ className: style['add-field-dropdown-item'],
2408
+ onClick: () => {
2409
+ onAddFieldClick();
2410
+ setAddFieldMenuId(null);
2411
+ },
2412
+ onKeyDown: e => {
2413
+ if (e.key === 'Enter' || e.key === ' ') {
2414
+ onAddFieldClick();
2415
+ setAddFieldMenuId(null);
2416
+ }
2417
+ },
2418
+ children: [/*#__PURE__*/jsxRuntime.jsx("span", {
2419
+ className: style['add-field-dropdown-item-icon'],
2420
+ children: /*#__PURE__*/jsxRuntime.jsx(icons.SelectOutlined, {})
2421
+ }), /*#__PURE__*/jsxRuntime.jsx("span", {
2422
+ children: formatMessage({
2423
+ id: 'addField'
2424
+ })
2425
+ })]
2426
+ }), /*#__PURE__*/jsxRuntime.jsx("div", {
2427
+ className: style['add-field-dropdown-divider']
2428
+ }), /*#__PURE__*/jsxRuntime.jsx("div", {
2429
+ className: style['add-field-dropdown-label'],
2430
+ children: formatMessage({
2431
+ id: 'addChildBlock'
2432
+ })
2433
+ }), NESTED_ADD_OPTIONS.map(opt => {
2434
+ const definition = getBlockDefinition(opt.key);
2435
+ return /*#__PURE__*/jsxRuntime.jsxs("div", {
2436
+ role: "button",
2437
+ tabIndex: 0,
2438
+ className: style['add-field-dropdown-item'],
2439
+ onClick: () => {
2440
+ onAddChildBlock(opt.key);
2441
+ setAddFieldMenuId(null);
2442
+ },
2443
+ onKeyDown: e => {
2444
+ if (e.key === 'Enter' || e.key === ' ') {
2445
+ onAddChildBlock(opt.key);
2446
+ setAddFieldMenuId(null);
2447
+ }
2448
+ },
2449
+ children: [/*#__PURE__*/jsxRuntime.jsx("span", {
2450
+ className: style['add-field-dropdown-item-icon'],
2451
+ children: opt.icon
2452
+ }), /*#__PURE__*/jsxRuntime.jsx("span", {
2453
+ children: formatMessage({
2454
+ id: `blockKind_${opt.key}`
2455
+ })
2456
+ }), definition?.description ? /*#__PURE__*/jsxRuntime.jsx("span", {
2457
+ className: style['add-field-dropdown-item-desc'],
2458
+ children: definition.description
2459
+ }) : null]
2460
+ }, opt.key);
2461
+ })]
2462
+ }),
2463
+ children: /*#__PURE__*/jsxRuntime.jsx(antd.Button, {
2464
+ type: "text",
2465
+ size: "small",
2466
+ icon: /*#__PURE__*/jsxRuntime.jsx(icons.PlusOutlined, {}),
2467
+ className: btnClass,
2468
+ onClick: () => {
2469
+ onAddFieldClick();
2470
+ setAddFieldMenuId(null);
2471
+ },
2472
+ children: formatMessage({
2473
+ id: 'addField'
2474
+ })
2475
+ })
2476
+ });
2477
+ };
2478
+ const renderFieldList = function (fields, blockId, _temp2) {
2479
+ let {
2480
+ stepId,
2481
+ optionId
2482
+ } = _temp2 === void 0 ? {} : _temp2;
1736
2483
  if (!(fields || []).length) {
1737
2484
  return /*#__PURE__*/jsxRuntime.jsx(Text$3, {
1738
2485
  type: "secondary",
@@ -1748,13 +2495,35 @@ const BlockListPanel = _ref3 => {
1748
2495
  field: field,
1749
2496
  index: fieldIndex,
1750
2497
  total: fields.length,
1751
- onEdit: fieldItem => onEditField(blockId, fieldItem, stepId),
1752
- onDelete: fieldId => onDeleteField(blockId, fieldId, stepId),
1753
- onMove: (fieldId, direction) => onMoveField(blockId, fieldId, direction, stepId)
2498
+ onEdit: fieldItem => onEditField(blockId, fieldItem, {
2499
+ stepId,
2500
+ optionId
2501
+ }),
2502
+ onDelete: fieldId => onDeleteField(blockId, fieldId, {
2503
+ stepId,
2504
+ optionId
2505
+ }),
2506
+ onMove: (fieldId, direction) => onMoveField(blockId, fieldId, direction, {
2507
+ stepId,
2508
+ optionId
2509
+ })
1754
2510
  }, field.id))
1755
2511
  });
1756
2512
  };
1757
- const renderBlockChildren = block => {
2513
+ const renderNestedBlocks = (childBlocks, depth) => {
2514
+ if (!(childBlocks || []).length) {
2515
+ return null;
2516
+ }
2517
+ return /*#__PURE__*/jsxRuntime.jsx("div", {
2518
+ className: style['item-blocks-section'],
2519
+ children: /*#__PURE__*/jsxRuntime.jsx("div", {
2520
+ className: style['nested-block-list'],
2521
+ children: childBlocks.map((child, childIndex) => renderBlockSection(child, childIndex, childBlocks.length, depth + 1))
2522
+ })
2523
+ });
2524
+ };
2525
+ const renderItemBlocks = (parentBlock, depth) => renderNestedBlocks(parentBlock.itemBlocks, depth);
2526
+ const renderBlockChildren = (block, depth) => {
1758
2527
  if (block.kind === 'steps') {
1759
2528
  return /*#__PURE__*/jsxRuntime.jsxs("div", {
1760
2529
  className: style['block-body'],
@@ -1797,7 +2566,12 @@ const BlockListPanel = _ref3 => {
1797
2566
  })
1798
2567
  }), /*#__PURE__*/jsxRuntime.jsx(Text$3, {
1799
2568
  type: "secondary",
1800
- children: formatMessage({
2569
+ children: (step.blocks || []).length ? formatMessage({
2570
+ id: 'fieldAndItemBlockCount'
2571
+ }, {
2572
+ fields: step.list?.length || 0,
2573
+ nests: step.blocks.length
2574
+ }) : formatMessage({
1801
2575
  id: 'fieldCount'
1802
2576
  }, {
1803
2577
  count: step.list?.length || 0
@@ -1832,17 +2606,20 @@ const BlockListPanel = _ref3 => {
1832
2606
  icon: /*#__PURE__*/jsxRuntime.jsx(icons.DeleteOutlined, {}),
1833
2607
  onClick: () => onDeleteStep(block.id, step.id)
1834
2608
  })]
1835
- }), /*#__PURE__*/jsxRuntime.jsx(antd.Button, {
1836
- type: "text",
1837
- size: "small",
1838
- icon: /*#__PURE__*/jsxRuntime.jsx(icons.PlusOutlined, {}),
1839
- className: `${style['add-inline-btn']} ${style['hover-reveal']}`,
1840
- onClick: () => onAddField(block.id, step.id),
1841
- children: formatMessage({
1842
- id: 'addField'
2609
+ }), renderAddFieldButton({
2610
+ menuKey: `${block.id}:${step.id}`,
2611
+ depth,
2612
+ onAddFieldClick: () => onAddField(block.id, {
2613
+ stepId: step.id
2614
+ }),
2615
+ onAddChildBlock: kind => onAddBlock(kind, {
2616
+ parentBlockId: block.id,
2617
+ stepId: step.id
1843
2618
  })
1844
2619
  })]
1845
- }), renderFieldList(step.list, block.id, step.id)]
2620
+ }), renderFieldList(step.list, block.id, {
2621
+ stepId: step.id
2622
+ }), renderNestedBlocks(step.blocks, depth)]
1846
2623
  }, step.id))
1847
2624
  }) : /*#__PURE__*/jsxRuntime.jsx(Text$3, {
1848
2625
  type: "secondary",
@@ -1864,10 +2641,216 @@ const BlockListPanel = _ref3 => {
1864
2641
  })
1865
2642
  });
1866
2643
  }
1867
- return /*#__PURE__*/jsxRuntime.jsx("div", {
2644
+ if (block.kind === 'choice') {
2645
+ return /*#__PURE__*/jsxRuntime.jsxs("div", {
2646
+ className: style['block-body'],
2647
+ children: [/*#__PURE__*/jsxRuntime.jsxs("div", {
2648
+ className: style['section-toolbar'],
2649
+ children: [/*#__PURE__*/jsxRuntime.jsx(Text$3, {
2650
+ type: "secondary",
2651
+ className: style['section-toolbar-label'],
2652
+ children: formatMessage({
2653
+ id: 'choiceOptionListTitle'
2654
+ })
2655
+ }), /*#__PURE__*/jsxRuntime.jsx(antd.Button, {
2656
+ type: "text",
2657
+ size: "small",
2658
+ icon: /*#__PURE__*/jsxRuntime.jsx(icons.PlusOutlined, {}),
2659
+ className: `${style['add-inline-btn']} ${style['hover-reveal']}`,
2660
+ onClick: () => onAddChoiceOption(block.id),
2661
+ children: formatMessage({
2662
+ id: 'addChoiceOption'
2663
+ })
2664
+ })]
2665
+ }), (block.options || []).length ? /*#__PURE__*/jsxRuntime.jsx("div", {
2666
+ className: style['step-list'],
2667
+ children: (block.options || []).map((option, optionIndex) => /*#__PURE__*/jsxRuntime.jsxs("div", {
2668
+ className: style['step-section'],
2669
+ children: [/*#__PURE__*/jsxRuntime.jsxs("div", {
2670
+ className: style['step-section-header'],
2671
+ children: [/*#__PURE__*/jsxRuntime.jsxs(antd.Space, {
2672
+ size: 8,
2673
+ className: style['step-section-title'],
2674
+ children: [/*#__PURE__*/jsxRuntime.jsx("span", {
2675
+ className: style['step-index'],
2676
+ children: optionIndex + 1
2677
+ }), /*#__PURE__*/jsxRuntime.jsx(Text$3, {
2678
+ strong: true,
2679
+ children: option.title || formatMessage({
2680
+ id: 'choiceOptionFallback'
2681
+ }, {
2682
+ index: optionIndex + 1
2683
+ })
2684
+ }), /*#__PURE__*/jsxRuntime.jsx(Text$3, {
2685
+ type: "secondary",
2686
+ children: (option.blocks || []).length ? formatMessage({
2687
+ id: 'fieldAndItemBlockCount'
2688
+ }, {
2689
+ fields: option.list?.length || 0,
2690
+ nests: option.blocks.length
2691
+ }) : formatMessage({
2692
+ id: 'fieldCount'
2693
+ }, {
2694
+ count: option.list?.length || 0
2695
+ })
2696
+ })]
2697
+ }), /*#__PURE__*/jsxRuntime.jsxs(ActionGroup, {
2698
+ children: [/*#__PURE__*/jsxRuntime.jsx(IconBtn, {
2699
+ title: formatMessage({
2700
+ id: 'moveUp'
2701
+ }),
2702
+ icon: /*#__PURE__*/jsxRuntime.jsx(icons.ArrowUpOutlined, {}),
2703
+ disabled: optionIndex === 0,
2704
+ onClick: () => onMoveChoiceOption(block.id, option.id, 'up')
2705
+ }), /*#__PURE__*/jsxRuntime.jsx(IconBtn, {
2706
+ title: formatMessage({
2707
+ id: 'moveDown'
2708
+ }),
2709
+ icon: /*#__PURE__*/jsxRuntime.jsx(icons.ArrowDownOutlined, {}),
2710
+ disabled: optionIndex === (block.options?.length || 0) - 1,
2711
+ onClick: () => onMoveChoiceOption(block.id, option.id, 'down')
2712
+ }), /*#__PURE__*/jsxRuntime.jsx(IconBtn, {
2713
+ title: formatMessage({
2714
+ id: 'editChoiceOption'
2715
+ }),
2716
+ icon: /*#__PURE__*/jsxRuntime.jsx(icons.EditOutlined, {}),
2717
+ onClick: () => onEditChoiceOption(block.id, option)
2718
+ }), /*#__PURE__*/jsxRuntime.jsx(IconBtn, {
2719
+ title: formatMessage({
2720
+ id: 'deleteChoiceOption'
2721
+ }),
2722
+ danger: true,
2723
+ icon: /*#__PURE__*/jsxRuntime.jsx(icons.DeleteOutlined, {}),
2724
+ onClick: () => onDeleteChoiceOption(block.id, option.id)
2725
+ })]
2726
+ }), renderAddFieldButton({
2727
+ menuKey: `${block.id}:opt:${option.id}`,
2728
+ depth,
2729
+ onAddFieldClick: () => onAddField(block.id, {
2730
+ optionId: option.id
2731
+ }),
2732
+ onAddChildBlock: kind => onAddBlock(kind, {
2733
+ parentBlockId: block.id,
2734
+ optionId: option.id
2735
+ })
2736
+ })]
2737
+ }), renderFieldList(option.list, block.id, {
2738
+ optionId: option.id
2739
+ }), renderNestedBlocks(option.blocks, depth)]
2740
+ }, option.id))
2741
+ }) : /*#__PURE__*/jsxRuntime.jsx(Text$3, {
2742
+ type: "secondary",
2743
+ className: style['inline-empty'],
2744
+ children: formatMessage({
2745
+ id: 'emptyChoiceOptionList'
2746
+ })
2747
+ })]
2748
+ });
2749
+ }
2750
+ const supportsItemBlocks = block.kind === 'list';
2751
+ const supportsBlocks = block.kind === 'formInfo' || block.kind === 'object';
2752
+ return /*#__PURE__*/jsxRuntime.jsxs("div", {
1868
2753
  className: style['block-body'],
1869
- children: renderFieldList(block.list, block.id)
2754
+ children: [renderFieldList(block.list, block.id), supportsItemBlocks ? renderItemBlocks(block, depth) : null, supportsBlocks ? renderNestedBlocks(block.blocks, depth) : null]
2755
+ });
2756
+ };
2757
+ const renderBlockSection = function (block, blockIndex, total, depth) {
2758
+ if (depth === void 0) {
2759
+ depth = 0;
2760
+ }
2761
+ const definition = getBlockDefinition(block.kind);
2762
+ const canAddField = block.kind !== 'steps' && block.kind !== 'multiField' && block.kind !== 'choice';
2763
+ const supportsItemBlocks = block.kind === 'list';
2764
+ const supportsBlocks = block.kind === 'formInfo' || block.kind === 'object';
2765
+ const supportsChildModules = supportsItemBlocks || supportsBlocks;
2766
+ const nestCount = supportsItemBlocks ? block.itemBlocks?.length || 0 : block.blocks?.length || 0;
2767
+ const summary = block.kind === 'steps' ? formatMessage({
2768
+ id: 'stepCount'
2769
+ }, {
2770
+ count: block.items?.length || 0
2771
+ }) : block.kind === 'multiField' ? formatMessage({
2772
+ id: 'multiFieldSummary'
2773
+ }, {
2774
+ type: block.fieldType
2775
+ }) : block.kind === 'choice' ? formatMessage({
2776
+ id: 'choiceOptionCount'
2777
+ }, {
2778
+ count: block.options?.length || 0
2779
+ }) : supportsChildModules && nestCount > 0 ? formatMessage({
2780
+ id: 'fieldAndItemBlockCount'
2781
+ }, {
2782
+ fields: block.list?.length || 0,
2783
+ nests: nestCount
2784
+ }) : formatMessage({
2785
+ id: 'fieldCount'
2786
+ }, {
2787
+ count: block.list?.length || 0
1870
2788
  });
2789
+ return /*#__PURE__*/jsxRuntime.jsxs("section", {
2790
+ className: `${style['block-section']} ${style[`block-kind-${block.kind}`] || ''} ${depth > 0 ? style['block-section-nested'] : ''}`.trim(),
2791
+ children: [/*#__PURE__*/jsxRuntime.jsxs("header", {
2792
+ className: style['block-section-header'],
2793
+ children: [/*#__PURE__*/jsxRuntime.jsxs("div", {
2794
+ className: style['block-header-left'],
2795
+ children: [/*#__PURE__*/jsxRuntime.jsx(antd.Tag, {
2796
+ bordered: false,
2797
+ color: definition?.color || 'default',
2798
+ children: definition?.label || block.kind
2799
+ }), /*#__PURE__*/jsxRuntime.jsx(Text$3, {
2800
+ strong: true,
2801
+ ellipsis: true,
2802
+ className: style['block-title'],
2803
+ children: block.title || block.label || block.name || formatMessage({
2804
+ id: 'untitledBlock'
2805
+ })
2806
+ }), /*#__PURE__*/jsxRuntime.jsx("span", {
2807
+ className: style['block-summary'],
2808
+ children: summary
2809
+ })]
2810
+ }), /*#__PURE__*/jsxRuntime.jsxs(antd.Space, {
2811
+ size: 4,
2812
+ wrap: true,
2813
+ className: style['block-header-actions'],
2814
+ children: [/*#__PURE__*/jsxRuntime.jsxs(ActionGroup, {
2815
+ children: [/*#__PURE__*/jsxRuntime.jsx(IconBtn, {
2816
+ title: formatMessage({
2817
+ id: 'moveUp'
2818
+ }),
2819
+ icon: /*#__PURE__*/jsxRuntime.jsx(icons.ArrowUpOutlined, {}),
2820
+ disabled: blockIndex === 0,
2821
+ onClick: () => onMoveBlock(block.id, 'up')
2822
+ }), /*#__PURE__*/jsxRuntime.jsx(IconBtn, {
2823
+ title: formatMessage({
2824
+ id: 'moveDown'
2825
+ }),
2826
+ icon: /*#__PURE__*/jsxRuntime.jsx(icons.ArrowDownOutlined, {}),
2827
+ disabled: blockIndex === total - 1,
2828
+ onClick: () => onMoveBlock(block.id, 'down')
2829
+ }), /*#__PURE__*/jsxRuntime.jsx(IconBtn, {
2830
+ title: formatMessage({
2831
+ id: 'editBlock'
2832
+ }),
2833
+ icon: /*#__PURE__*/jsxRuntime.jsx(icons.SettingOutlined, {}),
2834
+ onClick: () => onEditBlock(block)
2835
+ }), /*#__PURE__*/jsxRuntime.jsx(IconBtn, {
2836
+ title: formatMessage({
2837
+ id: 'deleteBlock'
2838
+ }),
2839
+ danger: true,
2840
+ icon: /*#__PURE__*/jsxRuntime.jsx(icons.DeleteOutlined, {}),
2841
+ onClick: () => onDeleteBlock(block.id)
2842
+ })]
2843
+ }), canAddField ? renderAddFieldButton({
2844
+ menuKey: block.id,
2845
+ depth,
2846
+ onAddFieldClick: () => onAddField(block.id),
2847
+ onAddChildBlock: supportsChildModules ? kind => onAddBlock(kind, {
2848
+ parentBlockId: block.id
2849
+ }) : undefined
2850
+ }) : null]
2851
+ })]
2852
+ }), renderBlockChildren(block, depth)]
2853
+ }, block.id);
1871
2854
  };
1872
2855
  return /*#__PURE__*/jsxRuntime.jsxs("div", {
1873
2856
  className: style['block-list-panel'],
@@ -1880,41 +2863,11 @@ const BlockListPanel = _ref3 => {
1880
2863
  open: addMenuOpen,
1881
2864
  onOpenChange: setAddMenuOpen,
1882
2865
  trigger: ['click'],
1883
- dropdownRender: () => /*#__PURE__*/jsxRuntime.jsx("div", {
1884
- className: style['add-block-dropdown'],
1885
- children: addBlockOptions.map(opt => {
1886
- const definition = getBlockDefinition(opt.key);
1887
- return /*#__PURE__*/jsxRuntime.jsxs("div", {
1888
- role: "button",
1889
- tabIndex: 0,
1890
- className: style['add-block-option'],
1891
- onClick: () => {
1892
- onAddBlock(opt.key);
1893
- setAddMenuOpen(false);
1894
- },
1895
- onKeyDown: e => {
1896
- if (e.key === 'Enter' || e.key === ' ') {
1897
- onAddBlock(opt.key);
1898
- setAddMenuOpen(false);
1899
- }
1900
- },
1901
- children: [/*#__PURE__*/jsxRuntime.jsx("div", {
1902
- className: style['add-block-option-icon'],
1903
- children: opt.icon
1904
- }), /*#__PURE__*/jsxRuntime.jsxs("div", {
1905
- className: style['add-block-option-text'],
1906
- children: [/*#__PURE__*/jsxRuntime.jsx("div", {
1907
- className: style['add-block-option-title'],
1908
- children: formatMessage({
1909
- id: `blockKind_${opt.key}`
1910
- })
1911
- }), /*#__PURE__*/jsxRuntime.jsx("div", {
1912
- className: style['add-block-option-desc'],
1913
- children: definition?.description
1914
- })]
1915
- })]
1916
- }, opt.key);
1917
- })
2866
+ dropdownRender: () => renderAddBlockMenu(ROOT_ADD_OPTIONS, {
2867
+ onSelect: kind => {
2868
+ onAddBlock(kind);
2869
+ setAddMenuOpen(false);
2870
+ }
1918
2871
  }),
1919
2872
  children: /*#__PURE__*/jsxRuntime.jsx(antd.Button, {
1920
2873
  type: "primary",
@@ -1944,90 +2897,7 @@ const BlockListPanel = _ref3 => {
1944
2897
  })
1945
2898
  }) : /*#__PURE__*/jsxRuntime.jsx("div", {
1946
2899
  className: style['block-list'],
1947
- children: blocks.map((block, blockIndex) => {
1948
- const definition = getBlockDefinition(block.kind);
1949
- const canAddField = block.kind !== 'steps' && block.kind !== 'multiField';
1950
- const summary = block.kind === 'steps' ? formatMessage({
1951
- id: 'stepCount'
1952
- }, {
1953
- count: block.items?.length || 0
1954
- }) : block.kind === 'multiField' ? formatMessage({
1955
- id: 'multiFieldSummary'
1956
- }, {
1957
- type: block.fieldType
1958
- }) : formatMessage({
1959
- id: 'fieldCount'
1960
- }, {
1961
- count: block.list?.length || 0
1962
- });
1963
- return /*#__PURE__*/jsxRuntime.jsxs("section", {
1964
- className: `${style['block-section']} ${style[`block-kind-${block.kind}`] || ''}`.trim(),
1965
- children: [/*#__PURE__*/jsxRuntime.jsxs("header", {
1966
- className: style['block-section-header'],
1967
- children: [/*#__PURE__*/jsxRuntime.jsxs("div", {
1968
- className: style['block-header-left'],
1969
- children: [/*#__PURE__*/jsxRuntime.jsx(antd.Tag, {
1970
- bordered: false,
1971
- color: definition?.color || 'default',
1972
- children: definition?.label || block.kind
1973
- }), /*#__PURE__*/jsxRuntime.jsx(Text$3, {
1974
- strong: true,
1975
- ellipsis: true,
1976
- className: style['block-title'],
1977
- children: block.title || block.label || block.name || formatMessage({
1978
- id: 'untitledBlock'
1979
- })
1980
- }), /*#__PURE__*/jsxRuntime.jsx("span", {
1981
- className: style['block-summary'],
1982
- children: summary
1983
- })]
1984
- }), /*#__PURE__*/jsxRuntime.jsxs(antd.Space, {
1985
- size: 4,
1986
- wrap: true,
1987
- className: style['block-header-actions'],
1988
- children: [/*#__PURE__*/jsxRuntime.jsxs(ActionGroup, {
1989
- children: [/*#__PURE__*/jsxRuntime.jsx(IconBtn, {
1990
- title: formatMessage({
1991
- id: 'moveUp'
1992
- }),
1993
- icon: /*#__PURE__*/jsxRuntime.jsx(icons.ArrowUpOutlined, {}),
1994
- disabled: blockIndex === 0,
1995
- onClick: () => onMoveBlock(block.id, 'up')
1996
- }), /*#__PURE__*/jsxRuntime.jsx(IconBtn, {
1997
- title: formatMessage({
1998
- id: 'moveDown'
1999
- }),
2000
- icon: /*#__PURE__*/jsxRuntime.jsx(icons.ArrowDownOutlined, {}),
2001
- disabled: blockIndex === blocks.length - 1,
2002
- onClick: () => onMoveBlock(block.id, 'down')
2003
- }), /*#__PURE__*/jsxRuntime.jsx(IconBtn, {
2004
- title: formatMessage({
2005
- id: 'editBlock'
2006
- }),
2007
- icon: /*#__PURE__*/jsxRuntime.jsx(icons.SettingOutlined, {}),
2008
- onClick: () => onEditBlock(block)
2009
- }), /*#__PURE__*/jsxRuntime.jsx(IconBtn, {
2010
- title: formatMessage({
2011
- id: 'deleteBlock'
2012
- }),
2013
- danger: true,
2014
- icon: /*#__PURE__*/jsxRuntime.jsx(icons.DeleteOutlined, {}),
2015
- onClick: () => onDeleteBlock(block.id)
2016
- })]
2017
- }), canAddField ? /*#__PURE__*/jsxRuntime.jsx(antd.Button, {
2018
- type: "text",
2019
- size: "small",
2020
- icon: /*#__PURE__*/jsxRuntime.jsx(icons.PlusOutlined, {}),
2021
- className: `${style['add-inline-btn']} ${style['hover-reveal']}`,
2022
- onClick: () => onAddField(block.id),
2023
- children: formatMessage({
2024
- id: 'addField'
2025
- })
2026
- }) : null]
2027
- })]
2028
- }), renderBlockChildren(block)]
2029
- }, block.id);
2030
- })
2900
+ children: blocks.map((block, blockIndex) => renderBlockSection(block, blockIndex, blocks.length, 0))
2031
2901
  })]
2032
2902
  });
2033
2903
  };
@@ -2043,7 +2913,7 @@ const BlockConfigFields = _ref => {
2043
2913
  const definition = getBlockDefinition(kind);
2044
2914
  const fieldTypeOptions = react.useMemo(() => getFieldTypes(), []);
2045
2915
  const list = [];
2046
- if (kind === 'formInfo' || kind === 'list' || kind === 'tableList') {
2916
+ if (kind === 'formInfo' || kind === 'list' || kind === 'tableList' || kind === 'object') {
2047
2917
  list.push(/*#__PURE__*/jsxRuntime.jsx(reactFormAntd.Input, {
2048
2918
  name: "title",
2049
2919
  label: formatMessage({
@@ -2076,7 +2946,7 @@ const BlockConfigFields = _ref => {
2076
2946
  }),
2077
2947
  min: 1,
2078
2948
  max: 4
2079
- }, "column"), kind === 'formInfo' ? /*#__PURE__*/jsxRuntime.jsx(reactFormAntd.InputNumber, {
2949
+ }, "column"), kind === 'formInfo' || kind === 'object' ? /*#__PURE__*/jsxRuntime.jsx(reactFormAntd.InputNumber, {
2080
2950
  name: "gap",
2081
2951
  label: formatMessage({
2082
2952
  id: 'blockGap'
@@ -2093,7 +2963,7 @@ const BlockConfigFields = _ref => {
2093
2963
  children: formatMessage({
2094
2964
  id: 'blockImportant'
2095
2965
  })
2096
- }, "important") : null, kind !== 'formInfo' ? /*#__PURE__*/jsxRuntime.jsx(reactFormAntd.Input, {
2966
+ }, "important") : null, kind === 'list' || kind === 'tableList' ? /*#__PURE__*/jsxRuntime.jsx(reactFormAntd.Input, {
2097
2967
  name: "addText",
2098
2968
  label: formatMessage({
2099
2969
  id: 'blockAddText'
@@ -2101,13 +2971,13 @@ const BlockConfigFields = _ref => {
2101
2971
  placeholder: formatMessage({
2102
2972
  id: 'blockAddTextPlaceholder'
2103
2973
  })
2104
- }, "addText") : null, kind !== 'formInfo' ? /*#__PURE__*/jsxRuntime.jsx(reactFormAntd.InputNumber, {
2974
+ }, "addText") : null, kind === 'list' || kind === 'tableList' ? /*#__PURE__*/jsxRuntime.jsx(reactFormAntd.InputNumber, {
2105
2975
  name: "maxLength",
2106
2976
  label: formatMessage({
2107
2977
  id: 'blockMaxLength'
2108
2978
  }),
2109
2979
  min: 1
2110
- }, "maxLength") : null, kind !== 'formInfo' ? /*#__PURE__*/jsxRuntime.jsx(reactFormAntd.InputNumber, {
2980
+ }, "maxLength") : null, kind === 'list' || kind === 'tableList' ? /*#__PURE__*/jsxRuntime.jsx(reactFormAntd.InputNumber, {
2111
2981
  name: "minLength",
2112
2982
  label: formatMessage({
2113
2983
  id: 'blockMinLength'
@@ -2115,6 +2985,77 @@ const BlockConfigFields = _ref => {
2115
2985
  min: 0
2116
2986
  }, "minLength") : null);
2117
2987
  }
2988
+ if (kind === 'choice') {
2989
+ list.push(/*#__PURE__*/jsxRuntime.jsx(reactFormAntd.Input, {
2990
+ name: "title",
2991
+ label: formatMessage({
2992
+ id: 'blockTitle'
2993
+ }),
2994
+ placeholder: formatMessage({
2995
+ id: 'choiceTitlePlaceholder'
2996
+ })
2997
+ }, "title"), /*#__PURE__*/jsxRuntime.jsx(reactFormAntd.Select, {
2998
+ name: "mode",
2999
+ label: formatMessage({
3000
+ id: 'choiceMode'
3001
+ }),
3002
+ rule: "REQ",
3003
+ options: [{
3004
+ label: formatMessage({
3005
+ id: 'choiceModeSingle'
3006
+ }),
3007
+ value: 'single'
3008
+ }, {
3009
+ label: formatMessage({
3010
+ id: 'choiceModeMultiple'
3011
+ }),
3012
+ value: 'multiple'
3013
+ }]
3014
+ }, "mode"), /*#__PURE__*/jsxRuntime.jsx(reactFormAntd.InputNumber, {
3015
+ name: "minLength",
3016
+ label: formatMessage({
3017
+ id: 'choiceMinSelect'
3018
+ }),
3019
+ min: 0,
3020
+ placeholder: formatMessage({
3021
+ id: 'propOptionalNumber'
3022
+ }),
3023
+ display: _ref2 => {
3024
+ let {
3025
+ openApi
3026
+ } = _ref2;
3027
+ return openApi?.data?.mode === 'multiple';
3028
+ }
3029
+ }, "minLength"), /*#__PURE__*/jsxRuntime.jsx(reactFormAntd.InputNumber, {
3030
+ name: "maxLength",
3031
+ label: formatMessage({
3032
+ id: 'choiceMaxSelect'
3033
+ }),
3034
+ min: 1,
3035
+ placeholder: formatMessage({
3036
+ id: 'propOptionalNumber'
3037
+ }),
3038
+ display: _ref3 => {
3039
+ let {
3040
+ openApi
3041
+ } = _ref3;
3042
+ return openApi?.data?.mode === 'multiple';
3043
+ }
3044
+ }, "maxLength"), /*#__PURE__*/jsxRuntime.jsx(reactFormAntd.Input, {
3045
+ name: "selectorName",
3046
+ label: formatMessage({
3047
+ id: 'choiceSelectorName'
3048
+ }),
3049
+ placeholder: formatMessage({
3050
+ id: 'choiceSelectorNamePlaceholder'
3051
+ })
3052
+ }, "selectorName"), /*#__PURE__*/jsxRuntime.jsx(reactFormAntd.Checkbox, {
3053
+ name: "selectorInData",
3054
+ children: formatMessage({
3055
+ id: 'choiceSelectorInData'
3056
+ })
3057
+ }, "selectorInData"));
3058
+ }
2118
3059
  if (kind === 'multiField') {
2119
3060
  list.push(/*#__PURE__*/jsxRuntime.jsx(reactFormAntd.Input, {
2120
3061
  name: "name",
@@ -2190,14 +3131,14 @@ const BlockConfigFields = _ref => {
2190
3131
  })
2191
3132
  });
2192
3133
  };
2193
- const BlockEditorModal = _ref2 => {
3134
+ const BlockEditorModal = _ref4 => {
2194
3135
  let {
2195
3136
  open,
2196
3137
  block,
2197
3138
  onCancel,
2198
3139
  onSave,
2199
3140
  renderModal
2200
- } = _ref2;
3141
+ } = _ref4;
2201
3142
  const {
2202
3143
  formatMessage
2203
3144
  } = reactIntl.useIntl();
@@ -2206,7 +3147,7 @@ const BlockEditorModal = _ref2 => {
2206
3147
  const formData = react.useMemo(() => blockToFormValues(block || createBlock('formInfo')), [block, open]);
2207
3148
  const handleSubmit = function (values) {
2208
3149
  try {
2209
- if ((block?.kind === 'list' || block?.kind === 'tableList' || block?.kind === 'multiField') && !values.name) {
3150
+ if ((block?.kind === 'list' || block?.kind === 'tableList' || block?.kind === 'multiField' || block?.kind === 'object') && !values.name) {
2210
3151
  antd.message.error(formatMessage({
2211
3152
  id: 'blockNameRequired'
2212
3153
  }));
@@ -2243,14 +3184,75 @@ const BlockEditorModal = _ref2 => {
2243
3184
  children: /*#__PURE__*/jsxRuntime.jsx(BlockConfigFields, {
2244
3185
  kind: block?.kind || 'formInfo'
2245
3186
  })
2246
- }, open ? block?.id ? `edit-${block.id}` : `add-${block?.kind || 'formInfo'}-${formData.name || 'new'}` : 'closed');
3187
+ }, open ? block?.id ? `edit-${block.id}` : `add-${block?.kind || 'formInfo'}-${formData.name || 'new'}` : 'closed');
3188
+ };
3189
+ var BlockEditorModal$1 = BlockEditorModal;
3190
+
3191
+ const StepEditorModal = _ref => {
3192
+ let {
3193
+ open,
3194
+ step,
3195
+ onCancel,
3196
+ onSave,
3197
+ renderModal
3198
+ } = _ref;
3199
+ const {
3200
+ formatMessage
3201
+ } = reactIntl.useIntl();
3202
+ const isMobile = responsiveUtils.useIsMobile();
3203
+ const formData = react.useMemo(() => stepToFormValues(step || createStep()), [step, open]);
3204
+ return /*#__PURE__*/jsxRuntime.jsx(FormInfo.FormModal, {
3205
+ destroyOnHidden: true,
3206
+ destroyOnClose: true,
3207
+ title: formatMessage({
3208
+ id: step?.id ? 'editStep' : 'addStep'
3209
+ }),
3210
+ open: open,
3211
+ onCancel: onCancel,
3212
+ width: isMobile ? 'calc(100vw - 32px)' : 560,
3213
+ ...(renderModal ? {
3214
+ renderModal
3215
+ } : {}),
3216
+ formProps: {
3217
+ data: formData,
3218
+ onSubmit: values => {
3219
+ onSave(formValuesToStep(values, step || createStep()));
3220
+ }
3221
+ },
3222
+ okText: formatMessage({
3223
+ id: 'confirm'
3224
+ }),
3225
+ cancelText: formatMessage({
3226
+ id: 'cancel'
3227
+ }),
3228
+ children: /*#__PURE__*/jsxRuntime.jsx(FormInfo__default["default"], {
3229
+ column: 1,
3230
+ list: [/*#__PURE__*/jsxRuntime.jsx(reactFormAntd.Input, {
3231
+ name: "title",
3232
+ label: formatMessage({
3233
+ id: 'stepTitle'
3234
+ }),
3235
+ rule: "REQ",
3236
+ placeholder: formatMessage({
3237
+ id: 'stepTitlePlaceholder'
3238
+ })
3239
+ }, "title"), /*#__PURE__*/jsxRuntime.jsx(reactFormAntd.InputNumber, {
3240
+ name: "column",
3241
+ label: formatMessage({
3242
+ id: 'formColumnPlaceholder'
3243
+ }),
3244
+ min: 1,
3245
+ max: 4
3246
+ }, "column")]
3247
+ })
3248
+ }, open ? step?.id ? `edit-${step.id}` : `add-step-${formData.title || 'new'}` : 'closed');
2247
3249
  };
2248
- var BlockEditorModal$1 = BlockEditorModal;
3250
+ var StepEditorModal$1 = StepEditorModal;
2249
3251
 
2250
- const StepEditorModal = _ref => {
3252
+ const ChoiceOptionEditorModal = _ref => {
2251
3253
  let {
2252
3254
  open,
2253
- step,
3255
+ option,
2254
3256
  onCancel,
2255
3257
  onSave,
2256
3258
  renderModal
@@ -2259,12 +3261,12 @@ const StepEditorModal = _ref => {
2259
3261
  formatMessage
2260
3262
  } = reactIntl.useIntl();
2261
3263
  const isMobile = responsiveUtils.useIsMobile();
2262
- const formData = react.useMemo(() => stepToFormValues(step || createStep()), [step, open]);
3264
+ const formData = react.useMemo(() => choiceOptionToFormValues(option || createChoiceOption()), [option, open]);
2263
3265
  return /*#__PURE__*/jsxRuntime.jsx(FormInfo.FormModal, {
2264
3266
  destroyOnHidden: true,
2265
3267
  destroyOnClose: true,
2266
3268
  title: formatMessage({
2267
- id: step?.id ? 'editStep' : 'addStep'
3269
+ id: option?.id ? 'editChoiceOption' : 'addChoiceOption'
2268
3270
  }),
2269
3271
  open: open,
2270
3272
  onCancel: onCancel,
@@ -2275,7 +3277,7 @@ const StepEditorModal = _ref => {
2275
3277
  formProps: {
2276
3278
  data: formData,
2277
3279
  onSubmit: values => {
2278
- onSave(formValuesToStep(values, step || createStep()));
3280
+ onSave(formValuesToChoiceOption(values, option || createChoiceOption()));
2279
3281
  }
2280
3282
  },
2281
3283
  okText: formatMessage({
@@ -2289,24 +3291,17 @@ const StepEditorModal = _ref => {
2289
3291
  list: [/*#__PURE__*/jsxRuntime.jsx(reactFormAntd.Input, {
2290
3292
  name: "title",
2291
3293
  label: formatMessage({
2292
- id: 'stepTitle'
3294
+ id: 'choiceOptionTitle'
2293
3295
  }),
2294
3296
  rule: "REQ",
2295
3297
  placeholder: formatMessage({
2296
- id: 'stepTitlePlaceholder'
3298
+ id: 'choiceOptionTitlePlaceholder'
2297
3299
  })
2298
- }, "title"), /*#__PURE__*/jsxRuntime.jsx(reactFormAntd.InputNumber, {
2299
- name: "column",
2300
- label: formatMessage({
2301
- id: 'formColumnPlaceholder'
2302
- }),
2303
- min: 1,
2304
- max: 4
2305
- }, "column")]
3300
+ }, "title")]
2306
3301
  })
2307
- }, open ? step?.id ? `edit-${step.id}` : `add-step-${formData.title || 'new'}` : 'closed');
3302
+ }, open ? option?.id ? `edit-option-${option.id}` : `add-option-${formData.title || 'new'}` : 'closed');
2308
3303
  };
2309
- var StepEditorModal$1 = StepEditorModal;
3304
+ var ChoiceOptionEditorModal$1 = ChoiceOptionEditorModal;
2310
3305
 
2311
3306
  const {
2312
3307
  Text: Text$2
@@ -3734,6 +4729,272 @@ const FormActionsEditor = _ref => {
3734
4729
  };
3735
4730
  var FormActionsEditor$1 = FormActionsEditor;
3736
4731
 
4732
+ const getByPath = (obj, path) => {
4733
+ if (obj == null || path == null || path === '') {
4734
+ return undefined;
4735
+ }
4736
+ return String(path).split('.').reduce((current, key) => current == null ? undefined : current[key], obj);
4737
+ };
4738
+ const resolveSelectorName = block => {
4739
+ if (block.selectorName != null && String(block.selectorName).trim()) {
4740
+ return String(block.selectorName).trim();
4741
+ }
4742
+ if (block.discriminator?.propertyName) {
4743
+ return String(block.discriminator.propertyName).trim();
4744
+ }
4745
+ return `__choice_${block.id}`;
4746
+ };
4747
+ const resolveSelectedIds = (value, mode) => {
4748
+ if (mode === 'multiple') {
4749
+ if (Array.isArray(value)) {
4750
+ return value.map(String);
4751
+ }
4752
+ if (value == null || value === '') {
4753
+ return [];
4754
+ }
4755
+ return [String(value)];
4756
+ }
4757
+ if (value == null || value === '') {
4758
+ return [];
4759
+ }
4760
+ return [String(value)];
4761
+ };
4762
+ const clearUnselectedOptionFields = (openApi, keepIds, allOptions) => {
4763
+ if (!openApi?.setFields) {
4764
+ return;
4765
+ }
4766
+ const entries = [];
4767
+ allOptions.forEach(option => {
4768
+ if (keepIds.includes(String(option.id))) {
4769
+ return;
4770
+ }
4771
+ (option.list || []).forEach(field => {
4772
+ if (field?.name) {
4773
+ entries.push({
4774
+ name: field.name,
4775
+ value: undefined
4776
+ });
4777
+ }
4778
+ });
4779
+ collectBlockFieldNames(option.blocks || []).forEach(name => {
4780
+ entries.push({
4781
+ name,
4782
+ value: undefined
4783
+ });
4784
+ });
4785
+ });
4786
+ if (!entries.length) {
4787
+ return;
4788
+ }
4789
+ openApi.setFields(entries, {
4790
+ runValidate: false
4791
+ });
4792
+ };
4793
+ const resolveSelectLimits = block => {
4794
+ const minLength = Number.isFinite(Number(block.minLength)) ? Math.max(0, Math.floor(Number(block.minLength))) : undefined;
4795
+ let maxLength = Number.isFinite(Number(block.maxLength)) ? Math.max(1, Math.floor(Number(block.maxLength))) : undefined;
4796
+ if (minLength != null && maxLength != null && maxLength < minLength) {
4797
+ maxLength = minLength;
4798
+ }
4799
+ return {
4800
+ minLength,
4801
+ maxLength
4802
+ };
4803
+ };
4804
+ const buildMultipleHint = (formatMessage, minLength, maxLength) => {
4805
+ if (minLength != null && maxLength != null) {
4806
+ return formatMessage ? formatMessage({
4807
+ id: 'choiceModeHintMultipleRange'
4808
+ }, {
4809
+ min: minLength,
4810
+ max: maxLength
4811
+ }) : `请选择 ${minLength}–${maxLength} 项`;
4812
+ }
4813
+ if (minLength != null) {
4814
+ return formatMessage ? formatMessage({
4815
+ id: 'choiceModeHintMultipleMin'
4816
+ }, {
4817
+ count: minLength
4818
+ }) : `请至少选择 ${minLength} 项`;
4819
+ }
4820
+ if (maxLength != null) {
4821
+ return formatMessage ? formatMessage({
4822
+ id: 'choiceModeHintMultipleMax'
4823
+ }, {
4824
+ count: maxLength
4825
+ }) : `最多选择 ${maxLength} 项`;
4826
+ }
4827
+ return formatMessage ? formatMessage({
4828
+ id: 'choiceModeHintMultiple'
4829
+ }) : '可以选择多项';
4830
+ };
4831
+
4832
+ /**
4833
+ * choice:同一条选项 UI;mode=single 只挂载一支;mode=multiple 平铺所有选中支。
4834
+ * 外层用 InfoPage.Part 的 title 展示标题。
4835
+ */
4836
+ const ChoiceBlock = ({
4837
+ block,
4838
+ preview = false,
4839
+ isMobile = false,
4840
+ formatMessage,
4841
+ renderOptionContent
4842
+ }) => {
4843
+ const mode = block.mode === 'multiple' ? 'multiple' : 'single';
4844
+ const selectorName = resolveSelectorName(block);
4845
+ const options = react.useMemo(() => block.options || [], [block.options]);
4846
+ const {
4847
+ formData,
4848
+ openApi
4849
+ } = reactFormAntd.useFormContext() || {};
4850
+ const titleText = block.title != null ? String(block.title).trim() : '';
4851
+ const title = titleText || (formatMessage ? formatMessage({
4852
+ id: 'choiceAreaTitle'
4853
+ }) : '请选择');
4854
+ const bordered = isMobile ? false : block.bordered || undefined;
4855
+ const {
4856
+ minLength,
4857
+ maxLength
4858
+ } = mode === 'multiple' ? resolveSelectLimits(block) : {};
4859
+ const firstOptionId = options[0] != null ? String(options[0].id) : undefined;
4860
+
4861
+ // 单选且未选时,写入第一项,保证预览/提交与选项面板一致
4862
+ react.useEffect(() => {
4863
+ if (mode !== 'single' || !firstOptionId || !openApi?.setFields) {
4864
+ return;
4865
+ }
4866
+ const current = getByPath(formData || {}, selectorName);
4867
+ if (current != null && current !== '') {
4868
+ return;
4869
+ }
4870
+ openApi.setFields([{
4871
+ name: selectorName,
4872
+ value: firstOptionId
4873
+ }], {
4874
+ runValidate: false
4875
+ });
4876
+ }, [mode, firstOptionId, selectorName, openApi, formData]);
4877
+ const selectorOptions = react.useMemo(() => {
4878
+ const rawValue = getByPath(formData || {}, selectorName);
4879
+ const selectedIds = resolveSelectedIds(rawValue, mode);
4880
+ const atMax = mode === 'multiple' && maxLength != null && selectedIds.length >= maxLength;
4881
+ return options.map((option, index) => {
4882
+ const value = String(option.id);
4883
+ return {
4884
+ label: option.title || (formatMessage ? formatMessage({
4885
+ id: 'choiceOptionFallback'
4886
+ }, {
4887
+ index: index + 1
4888
+ }) : `选项${index + 1}`),
4889
+ value,
4890
+ disabled: atMax && !selectedIds.includes(value)
4891
+ };
4892
+ });
4893
+ }, [options, formatMessage, formData, selectorName, mode, maxLength]);
4894
+ const rawValue = getByPath(formData || {}, selectorName);
4895
+ let selectedIds = resolveSelectedIds(rawValue, mode);
4896
+ if (mode === 'single' && !selectedIds.length && firstOptionId) {
4897
+ selectedIds = [firstOptionId];
4898
+ }
4899
+ const activeOptions = options.filter(option => selectedIds.includes(String(option.id)));
4900
+ const handleChange = value => {
4901
+ let nextIds = resolveSelectedIds(value, mode);
4902
+ if (mode === 'multiple' && maxLength != null && nextIds.length > maxLength) {
4903
+ nextIds = nextIds.slice(0, maxLength);
4904
+ openApi?.setFields?.([{
4905
+ name: selectorName,
4906
+ value: nextIds
4907
+ }], {
4908
+ runValidate: false
4909
+ });
4910
+ }
4911
+ clearUnselectedOptionFields(openApi, nextIds, options);
4912
+ };
4913
+ const selectorRule = mode === 'multiple' && (minLength != null || maxLength != null) ? value => {
4914
+ const ids = resolveSelectedIds(value, 'multiple');
4915
+ if (minLength != null && ids.length < minLength) {
4916
+ return {
4917
+ result: false,
4918
+ errMsg: formatMessage ? formatMessage({
4919
+ id: 'choiceMinSelectError'
4920
+ }, {
4921
+ count: minLength
4922
+ }) : `请至少选择 ${minLength} 项`
4923
+ };
4924
+ }
4925
+ if (maxLength != null && ids.length > maxLength) {
4926
+ return {
4927
+ result: false,
4928
+ errMsg: formatMessage ? formatMessage({
4929
+ id: 'choiceMaxSelectError'
4930
+ }, {
4931
+ count: maxLength
4932
+ }) : `最多只能选择 ${maxLength} 项`
4933
+ };
4934
+ }
4935
+ return {
4936
+ result: true,
4937
+ errMsg: ''
4938
+ };
4939
+ } : undefined;
4940
+ const Selector = mode === 'multiple' ? reactFormAntd.CheckboxGroup : reactFormAntd.RadioGroup;
4941
+ const selectorProps = {
4942
+ key: 'choice-selector',
4943
+ name: selectorName,
4944
+ label: titleText || (formatMessage ? formatMessage({
4945
+ id: 'choiceAreaTitle'
4946
+ }) : '请选择'),
4947
+ labelHidden: true,
4948
+ options: selectorOptions,
4949
+ onChange: handleChange,
4950
+ ...(selectorRule ? {
4951
+ rule: selectorRule
4952
+ } : {}),
4953
+ ...(mode === 'single' ? {
4954
+ optionType: 'button',
4955
+ buttonStyle: 'solid',
4956
+ ...(firstOptionId ? {
4957
+ defaultValue: firstOptionId
4958
+ } : {})
4959
+ } : {})
4960
+ };
4961
+ const contentChildren = [];
4962
+ activeOptions.forEach(option => {
4963
+ const nodes = (typeof renderOptionContent === 'function' ? renderOptionContent(option, {
4964
+ preview,
4965
+ isMobile,
4966
+ formatMessage
4967
+ }) : []) || [];
4968
+ if (nodes.length) {
4969
+ contentChildren.push(/*#__PURE__*/react.createElement('div', {
4970
+ key: option.id,
4971
+ className: style['choice-option-panel']
4972
+ }, mode === 'multiple' && option.title ? /*#__PURE__*/react.createElement('div', {
4973
+ className: style['choice-option-panel-title']
4974
+ }, option.title) : null, ...nodes));
4975
+ }
4976
+ });
4977
+ const modeHint = mode === 'multiple' ? buildMultipleHint(formatMessage, minLength, maxLength) : formatMessage ? formatMessage({
4978
+ id: 'choiceModeHintSingle'
4979
+ }) : '请选择其中一项';
4980
+ return /*#__PURE__*/react.createElement(InfoPage__default["default"].Part, {
4981
+ title,
4982
+ subtitle: modeHint,
4983
+ bordered,
4984
+ className: style['choice-block'],
4985
+ 'data-choice-mode': mode
4986
+ }, /*#__PURE__*/react.createElement('div', {
4987
+ className: style['choice-selector']
4988
+ }, /*#__PURE__*/react.createElement(Selector, selectorProps)), contentChildren.length ? /*#__PURE__*/react.createElement('div', {
4989
+ className: style['choice-panels']
4990
+ }, ...contentChildren) : /*#__PURE__*/react.createElement('div', {
4991
+ className: style['choice-panels-empty']
4992
+ }, formatMessage ? formatMessage({
4993
+ id: 'choiceSelectFirstHint'
4994
+ }) : '请先在上方选择'));
4995
+ };
4996
+ var ChoiceBlock$1 = ChoiceBlock;
4997
+
3737
4998
  const buildLabelTips = tips => {
3738
4999
  if (tips == null || !String(tips).trim()) {
3739
5000
  return undefined;
@@ -3744,10 +5005,13 @@ const buildLabelTips = tips => {
3744
5005
  className: style['field-label-tips-icon']
3745
5006
  }));
3746
5007
  };
3747
- const renderFieldElements = function (fields, preview) {
5008
+ const renderFieldElements = function (fields, preview, _temp) {
3748
5009
  if (fields === void 0) {
3749
5010
  fields = [];
3750
5011
  }
5012
+ let {
5013
+ namePrefix
5014
+ } = _temp === void 0 ? {} : _temp;
3751
5015
  return fields.filter(field => !field.hidden).map(field => {
3752
5016
  const Component = getFieldComponent(field.type, field);
3753
5017
  if (!Component) {
@@ -3760,18 +5024,15 @@ const renderFieldElements = function (fields, preview) {
3760
5024
  if (definition?.optionsAllowDescription && props.options?.length && !props.api && !definition.optionsAllowChildren) {
3761
5025
  props.api = createApiFromOptions(props.options);
3762
5026
  }
3763
-
3764
- // 空字符串会盖掉 react-form-antd / SuperSelect 的默认「请输入/请选择」占位
3765
5027
  if (!Array.isArray(props.placeholder) && props.placeholder != null && !String(props.placeholder).trim()) {
3766
5028
  delete props.placeholder;
3767
5029
  }
3768
-
3769
- // schema 内部标记,不传给 antd
3770
5030
  delete props.range;
3771
5031
  const description = field.description != null && String(field.description).trim() ? field.description : undefined;
5032
+ const fieldName = namePrefix && field.name ? `${namePrefix}.${field.name}` : field.name;
3772
5033
  return /*#__PURE__*/react.createElement(Component, {
3773
5034
  key: field.id,
3774
- name: field.name,
5035
+ name: fieldName,
3775
5036
  label: field.label,
3776
5037
  rule: field.rule || undefined,
3777
5038
  block: field.block || undefined,
@@ -3781,62 +5042,144 @@ const renderFieldElements = function (fields, preview) {
3781
5042
  });
3782
5043
  }).filter(Boolean);
3783
5044
  };
3784
- const renderBlockElement = function (block, preview, _temp) {
3785
- let {
5045
+ const withBlockLayout = (element, forceBlock) => {
5046
+ if (!element || !forceBlock) {
5047
+ return element;
5048
+ }
5049
+ return /*#__PURE__*/react.createElement(element.type, {
5050
+ ...element.props,
5051
+ key: element.key,
5052
+ block: true
5053
+ });
5054
+ };
5055
+
5056
+ /** 列表子项内嵌的 FormInfo / List:表头圆角、去掉底边,压过 antd Card CSS-in-JS */
5057
+ const nestedListItemPartProps = {
5058
+ styles: {
5059
+ header: {
5060
+ borderBottom: 'none',
5061
+ borderRadius: 'var(--radius-default, 8px) var(--radius-default, 8px) 0 0'
5062
+ }
5063
+ },
5064
+ style: {
5065
+ borderRadius: 'var(--radius-default, 8px)',
5066
+ overflow: 'hidden'
5067
+ }
5068
+ };
5069
+ const renderBlockElement = function (block, preview, ctx) {
5070
+ if (preview === void 0) {
5071
+ preview = false;
5072
+ }
5073
+ if (ctx === void 0) {
5074
+ ctx = {};
5075
+ }
5076
+ const {
3786
5077
  isMobile = false,
3787
- formatMessage
3788
- } = _temp === void 0 ? {} : _temp;
3789
- const fields = renderFieldElements(block.list);
5078
+ formatMessage,
5079
+ depth = 0,
5080
+ asListItem = false
5081
+ } = ctx;
5082
+ if (!block || depth > MAX_BLOCK_DEPTH) {
5083
+ return null;
5084
+ }
5085
+ const nextCtx = {
5086
+ ...ctx,
5087
+ depth: depth + 1,
5088
+ asListItem: false
5089
+ };
3790
5090
  const bordered = isMobile ? false : block.bordered || undefined;
5091
+ const listItemPartProps = asListItem ? nestedListItemPartProps : null;
5092
+ const renderChildBlocks = function (blocks, childCtx) {
5093
+ if (blocks === void 0) {
5094
+ blocks = [];
5095
+ }
5096
+ if (childCtx === void 0) {
5097
+ childCtx = nextCtx;
5098
+ }
5099
+ return (blocks || []).map(child => renderBlockElement(child, preview, childCtx)).filter(Boolean);
5100
+ };
3791
5101
  switch (block.kind) {
3792
5102
  case 'formInfo':
3793
- return /*#__PURE__*/react.createElement(FormInfo__default["default"], {
3794
- key: block.id,
3795
- title: block.title || undefined,
3796
- subtitle: block.subtitle || undefined,
3797
- column: block.column,
3798
- gap: block.gap,
3799
- bordered,
3800
- list: fields
3801
- });
5103
+ {
5104
+ const fields = renderFieldElements(block.list);
5105
+ const nested = renderChildBlocks(block.blocks || [], nextCtx).map(node => withBlockLayout(node, true));
5106
+ return withBlockLayout(/*#__PURE__*/react.createElement(FormInfo__default["default"], {
5107
+ key: block.id,
5108
+ title: block.title || undefined,
5109
+ subtitle: block.subtitle || undefined,
5110
+ column: block.column,
5111
+ gap: block.gap,
5112
+ bordered,
5113
+ list: [...fields, ...nested],
5114
+ ...(listItemPartProps || {})
5115
+ }), asListItem);
5116
+ }
5117
+ case 'object':
5118
+ {
5119
+ const fields = renderFieldElements(block.list, preview, {
5120
+ namePrefix: block.name || ''
5121
+ });
5122
+ const nested = renderChildBlocks(block.blocks || [], nextCtx).map(node => withBlockLayout(node, true));
5123
+ return withBlockLayout(/*#__PURE__*/react.createElement(FormInfo__default["default"], {
5124
+ key: block.id,
5125
+ title: block.title || undefined,
5126
+ subtitle: block.subtitle || undefined,
5127
+ column: block.column,
5128
+ gap: block.gap,
5129
+ bordered,
5130
+ list: [...fields, ...nested],
5131
+ ...(listItemPartProps || {})
5132
+ }), asListItem);
5133
+ }
3802
5134
  case 'list':
3803
- return /*#__PURE__*/react.createElement(FormInfo.List, {
3804
- key: block.id,
3805
- name: block.name,
3806
- title: block.title || undefined,
3807
- important: block.important || undefined,
3808
- bordered,
3809
- maxLength: block.maxLength,
3810
- minLength: block.minLength,
3811
- // 不要传 addText: undefined,会盖掉 form-info 内部默认文案,变成畸形 icon-only 按钮
3812
- ...(block.addText ? {
3813
- addText: block.addText
3814
- } : {}),
3815
- ...(typeof block.itemTitle === 'function' || block.itemTitle ? {
3816
- itemTitle: block.itemTitle
3817
- } : {}),
3818
- list: fields
3819
- });
5135
+ {
5136
+ const fields = renderFieldElements(block.list);
5137
+ const nested = renderChildBlocks(block.itemBlocks || [], {
5138
+ ...nextCtx,
5139
+ asListItem: true
5140
+ }).map(node => withBlockLayout(node, true));
5141
+ return withBlockLayout(/*#__PURE__*/react.createElement(FormInfo.List, {
5142
+ key: block.id,
5143
+ name: block.name,
5144
+ title: block.title || undefined,
5145
+ important: block.important || undefined,
5146
+ bordered,
5147
+ maxLength: block.maxLength,
5148
+ minLength: block.minLength,
5149
+ ...(block.addText ? {
5150
+ addText: block.addText
5151
+ } : {}),
5152
+ ...(typeof block.itemTitle === 'function' || block.itemTitle ? {
5153
+ itemTitle: block.itemTitle
5154
+ } : {}),
5155
+ list: [...fields, ...nested],
5156
+ ...(listItemPartProps || {})
5157
+ }), asListItem);
5158
+ }
3820
5159
  case 'tableList':
3821
- return /*#__PURE__*/react.createElement(FormInfo.TableList, {
3822
- key: block.id,
3823
- name: block.name,
3824
- title: block.title || undefined,
3825
- bordered,
3826
- maxLength: block.maxLength,
3827
- minLength: block.minLength,
3828
- ...(block.addText ? {
3829
- addText: block.addText
3830
- } : {}),
3831
- list: fields
3832
- });
5160
+ {
5161
+ const fields = renderFieldElements(block.list);
5162
+ return withBlockLayout(/*#__PURE__*/react.createElement(FormInfo.TableList, {
5163
+ key: block.id,
5164
+ name: block.name,
5165
+ title: block.title || undefined,
5166
+ bordered,
5167
+ maxLength: block.maxLength,
5168
+ minLength: block.minLength,
5169
+ ...(block.addText ? {
5170
+ addText: block.addText
5171
+ } : {}),
5172
+ list: fields,
5173
+ ...(listItemPartProps || {})
5174
+ }), asListItem);
5175
+ }
3833
5176
  case 'multiField':
3834
5177
  {
3835
5178
  const FieldComponent = getFieldComponent(block.fieldType);
3836
5179
  if (!FieldComponent) {
3837
5180
  return null;
3838
5181
  }
3839
- return /*#__PURE__*/react.createElement(FormInfo.MultiField, {
5182
+ return withBlockLayout(/*#__PURE__*/react.createElement(FormInfo.MultiField, {
3840
5183
  key: block.id,
3841
5184
  name: block.name,
3842
5185
  label: block.label,
@@ -3845,26 +5188,70 @@ const renderBlockElement = function (block, preview, _temp) {
3845
5188
  ...(block.addText ? {
3846
5189
  addText: block.addText
3847
5190
  } : {})
3848
- });
5191
+ }), asListItem);
3849
5192
  }
3850
5193
  case 'steps':
3851
5194
  {
3852
- const bordered = isMobile ? false : block.bordered || undefined;
3853
- return /*#__PURE__*/react.createElement(FormInfo.Steps, {
5195
+ return withBlockLayout(/*#__PURE__*/react.createElement(FormInfo.Steps, {
3854
5196
  key: block.id,
3855
5197
  title: block.title || undefined,
3856
5198
  subtitle: block.subtitle || undefined,
3857
5199
  bordered,
3858
- items: (block.items || []).map(step => ({
3859
- key: step.id,
3860
- title: step.title,
3861
- column: step.column,
3862
- gap: block.gap,
3863
- list: renderFieldElements(step.list),
3864
- fieldNames: (step.list || []).filter(field => field && !field.hidden && field.name).map(field => field.name)
3865
- }))
3866
- });
5200
+ prevIcon: /*#__PURE__*/react.createElement(icons.ArrowLeftOutlined),
5201
+ nextIcon: /*#__PURE__*/react.createElement(icons.ArrowRightOutlined),
5202
+ items: (block.items || []).map(step => {
5203
+ const fields = renderFieldElements(step.list);
5204
+ const nested = renderChildBlocks(step.blocks || [], nextCtx);
5205
+ const fieldNames = [...(step.list || []).filter(field => field && !field.hidden && field.name).map(field => field.name), ...collectBlockFieldNames(step.blocks || [])];
5206
+ if (nested.length) {
5207
+ return {
5208
+ key: step.id,
5209
+ title: step.title,
5210
+ column: step.column,
5211
+ gap: block.gap,
5212
+ fieldNames,
5213
+ children: /*#__PURE__*/react.createElement(react.Fragment, {
5214
+ key: `${step.id}-body`
5215
+ }, fields.length ? /*#__PURE__*/react.createElement(FormInfo__default["default"], {
5216
+ key: `${step.id}-fields`,
5217
+ column: step.column,
5218
+ gap: block.gap,
5219
+ list: fields
5220
+ }) : null, ...nested)
5221
+ };
5222
+ }
5223
+ return {
5224
+ key: step.id,
5225
+ title: step.title,
5226
+ column: step.column,
5227
+ gap: block.gap,
5228
+ list: fields,
5229
+ fieldNames
5230
+ };
5231
+ })
5232
+ }), asListItem);
3867
5233
  }
5234
+ case 'choice':
5235
+ return withBlockLayout(/*#__PURE__*/react.createElement(ChoiceBlock$1, {
5236
+ key: block.id,
5237
+ block,
5238
+ preview,
5239
+ isMobile,
5240
+ formatMessage,
5241
+ renderOptionContent: option => {
5242
+ const nodes = [];
5243
+ if ((option.list || []).length) {
5244
+ nodes.push(/*#__PURE__*/react.createElement(FormInfo__default["default"], {
5245
+ key: `${option.id}-fields`,
5246
+ column: block.column || 2,
5247
+ gap: block.gap,
5248
+ list: renderFieldElements(option.list)
5249
+ }));
5250
+ }
5251
+ nodes.push(...renderChildBlocks(option.blocks || [], nextCtx));
5252
+ return nodes.filter(Boolean);
5253
+ }
5254
+ }), asListItem);
3868
5255
  default:
3869
5256
  return null;
3870
5257
  }
@@ -4120,8 +5507,13 @@ const FormCreator = withLocale$1(_ref => {
4120
5507
  const [innerSchema, setInnerSchema] = react.useState(() => normalizeSchema(defaultValue || defaultSchema()));
4121
5508
  const [blockEditorOpen, setBlockEditorOpen] = react.useState(false);
4122
5509
  const [editingBlock, setEditingBlock] = react.useState(null);
5510
+ const [blockParentId, setBlockParentId] = react.useState(null);
5511
+ const [blockParentStepId, setBlockParentStepId] = react.useState(null);
5512
+ const [blockParentOptionId, setBlockParentOptionId] = react.useState(null);
4123
5513
  const [stepEditorOpen, setStepEditorOpen] = react.useState(false);
4124
5514
  const [stepContext, setStepContext] = react.useState(null);
5515
+ const [choiceOptionEditorOpen, setChoiceOptionEditorOpen] = react.useState(false);
5516
+ const [choiceOptionContext, setChoiceOptionContext] = react.useState(null);
4125
5517
  const [fieldEditorOpen, setFieldEditorOpen] = react.useState(false);
4126
5518
  const [fieldContext, setFieldContext] = react.useState(null);
4127
5519
  const [editingField, setEditingField] = react.useState(null);
@@ -4134,34 +5526,78 @@ const FormCreator = withLocale$1(_ref => {
4134
5526
  }
4135
5527
  onChange?.(normalized);
4136
5528
  };
4137
- const handleAddBlock = kind => {
5529
+ const clearBlockEditor = () => {
5530
+ setBlockEditorOpen(false);
5531
+ setEditingBlock(null);
5532
+ setBlockParentId(null);
5533
+ setBlockParentStepId(null);
5534
+ setBlockParentOptionId(null);
5535
+ };
5536
+ const handleAddBlock = function (kind, _temp) {
5537
+ let {
5538
+ parentBlockId,
5539
+ stepId,
5540
+ optionId
5541
+ } = _temp === void 0 ? {} : _temp;
4138
5542
  setEditingBlock(createBlock(kind));
5543
+ setBlockParentId(parentBlockId || null);
5544
+ setBlockParentStepId(stepId || null);
5545
+ setBlockParentOptionId(optionId || null);
4139
5546
  setBlockEditorOpen(true);
4140
5547
  };
4141
5548
  const handleEditBlock = block => {
4142
5549
  setEditingBlock(block);
5550
+ setBlockParentId(null);
5551
+ setBlockParentStepId(null);
5552
+ setBlockParentOptionId(null);
4143
5553
  setBlockEditorOpen(true);
4144
5554
  };
4145
5555
  const handleSaveBlock = block => {
4146
- const exists = schema.blocks.some(item => item.id === block.id);
4147
- updateSchema({
4148
- ...schema,
4149
- blocks: exists ? schema.blocks.map(item => item.id === block.id ? block : item) : [...schema.blocks, block]
4150
- });
4151
- setBlockEditorOpen(false);
4152
- setEditingBlock(null);
5556
+ const exists = !!findBlock(schema, block.id);
5557
+ if (exists) {
5558
+ updateSchema(mapBlocks(schema, block.id, () => block));
5559
+ } else if (blockParentId && blockParentStepId) {
5560
+ updateSchema(mapBlocks(schema, blockParentId, parent => ({
5561
+ ...parent,
5562
+ items: (parent.items || []).map(step => step.id === blockParentStepId ? {
5563
+ ...step,
5564
+ blocks: [...(step.blocks || []), block]
5565
+ } : step)
5566
+ })));
5567
+ } else if (blockParentId && blockParentOptionId) {
5568
+ updateSchema(mapBlocks(schema, blockParentId, parent => ({
5569
+ ...parent,
5570
+ options: (parent.options || []).map(option => option.id === blockParentOptionId ? {
5571
+ ...option,
5572
+ blocks: [...(option.blocks || []), block]
5573
+ } : option)
5574
+ })));
5575
+ } else if (blockParentId) {
5576
+ updateSchema(mapBlocks(schema, blockParentId, parent => {
5577
+ if (parent.kind === 'list') {
5578
+ return {
5579
+ ...parent,
5580
+ itemBlocks: [...(parent.itemBlocks || []), block]
5581
+ };
5582
+ }
5583
+ return {
5584
+ ...parent,
5585
+ blocks: [...(parent.blocks || []), block]
5586
+ };
5587
+ }));
5588
+ } else {
5589
+ updateSchema({
5590
+ ...schema,
5591
+ blocks: [...schema.blocks, block]
5592
+ });
5593
+ }
5594
+ clearBlockEditor();
4153
5595
  };
4154
5596
  const handleDeleteBlock = blockId => {
4155
- updateSchema({
4156
- ...schema,
4157
- blocks: schema.blocks.filter(item => item.id !== blockId)
4158
- });
5597
+ updateSchema(updateBlocks(schema, blocks => removeBlockInTree(blocks, blockId)));
4159
5598
  };
4160
5599
  const handleMoveBlock = (blockId, direction) => {
4161
- updateSchema({
4162
- ...schema,
4163
- blocks: moveItem(schema.blocks, blockId, direction)
4164
- });
5600
+ updateSchema(updateBlocks(schema, blocks => moveBlockInTree(blocks, blockId, direction)));
4165
5601
  };
4166
5602
  const handleAddStep = blockId => {
4167
5603
  setStepContext({
@@ -4203,18 +5639,66 @@ const FormCreator = withLocale$1(_ref => {
4203
5639
  items: moveItem(block.items || [], stepId, direction)
4204
5640
  })));
4205
5641
  };
4206
- const handleAddField = (blockId, stepId) => {
5642
+ const handleAddChoiceOption = blockId => {
5643
+ setChoiceOptionContext({
5644
+ blockId,
5645
+ option: createChoiceOption()
5646
+ });
5647
+ setChoiceOptionEditorOpen(true);
5648
+ };
5649
+ const handleEditChoiceOption = (blockId, option) => {
5650
+ setChoiceOptionContext({
5651
+ blockId,
5652
+ option
5653
+ });
5654
+ setChoiceOptionEditorOpen(true);
5655
+ };
5656
+ const handleSaveChoiceOption = option => {
5657
+ const {
5658
+ blockId
5659
+ } = choiceOptionContext;
5660
+ updateSchema(mapBlocks(schema, blockId, block => {
5661
+ const exists = (block.options || []).some(item => item.id === option.id);
5662
+ return {
5663
+ ...block,
5664
+ options: exists ? block.options.map(item => item.id === option.id ? option : item) : [...(block.options || []), option]
5665
+ };
5666
+ }));
5667
+ setChoiceOptionEditorOpen(false);
5668
+ setChoiceOptionContext(null);
5669
+ };
5670
+ const handleDeleteChoiceOption = (blockId, optionId) => {
5671
+ updateSchema(mapBlocks(schema, blockId, block => ({
5672
+ ...block,
5673
+ options: (block.options || []).filter(item => item.id !== optionId)
5674
+ })));
5675
+ };
5676
+ const handleMoveChoiceOption = (blockId, optionId, direction) => {
5677
+ updateSchema(mapBlocks(schema, blockId, block => ({
5678
+ ...block,
5679
+ options: moveItem(block.options || [], optionId, direction)
5680
+ })));
5681
+ };
5682
+ const normalizeFieldScope = scope => {
5683
+ if (typeof scope === 'string' || scope == null) {
5684
+ return {
5685
+ stepId: scope
5686
+ };
5687
+ }
5688
+ return scope;
5689
+ };
5690
+ const handleAddField = (blockId, scope) => {
4207
5691
  setFieldContext({
4208
5692
  blockId,
4209
- stepId
5693
+ ...normalizeFieldScope(scope)
4210
5694
  });
4211
5695
  setEditingField(null);
4212
5696
  setFieldEditorOpen(true);
4213
5697
  };
4214
- const handleEditField = (blockId, field, stepId) => {
5698
+ const handleEditField = (blockId, field, scope) => {
4215
5699
  setFieldContext({
4216
5700
  blockId,
4217
- stepId
5701
+ ...normalizeFieldScope(scope)
4218
5702
  });
4219
5703
  setEditingField(field);
4220
5704
  setFieldEditorOpen(true);
@@ -4222,8 +5706,9 @@ const FormCreator = withLocale$1(_ref => {
4222
5706
  const handleSaveField = field => {
4223
5707
  const {
4224
5708
  blockId,
4225
- stepId
4226
- } = fieldContext;
5709
+ stepId,
5710
+ optionId
5711
+ } = fieldContext || {};
4227
5712
  updateSchema(mapBlocks(schema, blockId, block => {
4228
5713
  if (block.kind === 'steps') {
4229
5714
  return {
@@ -4240,6 +5725,21 @@ const FormCreator = withLocale$1(_ref => {
4240
5725
  })
4241
5726
  };
4242
5727
  }
5728
+ if (block.kind === 'choice') {
5729
+ return {
5730
+ ...block,
5731
+ options: (block.options || []).map(option => {
5732
+ if (option.id !== optionId) {
5733
+ return option;
5734
+ }
5735
+ const exists = (option.list || []).some(item => item.id === field.id);
5736
+ return {
5737
+ ...option,
5738
+ list: exists ? option.list.map(item => item.id === field.id ? field : item) : [...(option.list || []), field]
5739
+ };
5740
+ })
5741
+ };
5742
+ }
4243
5743
  const exists = (block.list || []).some(item => item.id === field.id);
4244
5744
  return {
4245
5745
  ...block,
@@ -4250,7 +5750,11 @@ const FormCreator = withLocale$1(_ref => {
4250
5750
  setFieldContext(null);
4251
5751
  setEditingField(null);
4252
5752
  };
4253
- const handleDeleteField = (blockId, fieldId, stepId) => {
5753
+ const handleDeleteField = (blockId, fieldId, scope) => {
5754
+ const {
5755
+ stepId,
5756
+ optionId
5757
+ } = normalizeFieldScope(scope);
4254
5758
  updateSchema(mapBlocks(schema, blockId, block => {
4255
5759
  if (block.kind === 'steps') {
4256
5760
  return {
@@ -4261,13 +5765,26 @@ const FormCreator = withLocale$1(_ref => {
4261
5765
  } : step)
4262
5766
  };
4263
5767
  }
5768
+ if (block.kind === 'choice') {
5769
+ return {
5770
+ ...block,
5771
+ options: (block.options || []).map(option => option.id === optionId ? {
5772
+ ...option,
5773
+ list: (option.list || []).filter(item => item.id !== fieldId)
5774
+ } : option)
5775
+ };
5776
+ }
4264
5777
  return {
4265
5778
  ...block,
4266
5779
  list: (block.list || []).filter(item => item.id !== fieldId)
4267
5780
  };
4268
5781
  }));
4269
5782
  };
4270
- const handleMoveField = (blockId, fieldId, direction, stepId) => {
5783
+ const handleMoveField = (blockId, fieldId, direction, scope) => {
5784
+ const {
5785
+ stepId,
5786
+ optionId
5787
+ } = normalizeFieldScope(scope);
4271
5788
  updateSchema(mapBlocks(schema, blockId, block => {
4272
5789
  if (block.kind === 'steps') {
4273
5790
  return {
@@ -4278,6 +5795,15 @@ const FormCreator = withLocale$1(_ref => {
4278
5795
  } : step)
4279
5796
  };
4280
5797
  }
5798
+ if (block.kind === 'choice') {
5799
+ return {
5800
+ ...block,
5801
+ options: (block.options || []).map(option => option.id === optionId ? {
5802
+ ...option,
5803
+ list: moveItem(option.list || [], fieldId, direction)
5804
+ } : option)
5805
+ };
5806
+ }
4281
5807
  return {
4282
5808
  ...block,
4283
5809
  list: moveItem(block.list || [], fieldId, direction)
@@ -4286,7 +5812,8 @@ const FormCreator = withLocale$1(_ref => {
4286
5812
  };
4287
5813
  const currentFieldScope = fieldContext ? collectSchemaFields(schema, {
4288
5814
  blockId: fieldContext.blockId,
4289
- stepId: fieldContext.stepId
5815
+ stepId: fieldContext.stepId,
5816
+ optionId: fieldContext.optionId
4290
5817
  }) : [];
4291
5818
  return /*#__PURE__*/jsxRuntime.jsxs("div", {
4292
5819
  className: [style['form-creator'], responsiveUtils.RESPONSIVE_BOUNDARY_CLASS, isMobile ? style['is-mobile'] : '', className].filter(Boolean).join(' '),
@@ -4306,6 +5833,10 @@ const FormCreator = withLocale$1(_ref => {
4306
5833
  onEditStep: handleEditStep,
4307
5834
  onDeleteStep: handleDeleteStep,
4308
5835
  onMoveStep: handleMoveStep,
5836
+ onAddChoiceOption: handleAddChoiceOption,
5837
+ onEditChoiceOption: handleEditChoiceOption,
5838
+ onDeleteChoiceOption: handleDeleteChoiceOption,
5839
+ onMoveChoiceOption: handleMoveChoiceOption,
4309
5840
  onOpenFormActions: () => setFormActionsOpen(true)
4310
5841
  })
4311
5842
  }), showPreview ? /*#__PURE__*/jsxRuntime.jsx("div", {
@@ -4327,10 +5858,7 @@ const FormCreator = withLocale$1(_ref => {
4327
5858
  open: blockEditorOpen,
4328
5859
  block: editingBlock,
4329
5860
  renderModal: renderModal,
4330
- onCancel: () => {
4331
- setBlockEditorOpen(false);
4332
- setEditingBlock(null);
4333
- },
5861
+ onCancel: clearBlockEditor,
4334
5862
  onSave: handleSaveBlock
4335
5863
  }), /*#__PURE__*/jsxRuntime.jsx(StepEditorModal$1, {
4336
5864
  open: stepEditorOpen,
@@ -4341,6 +5869,15 @@ const FormCreator = withLocale$1(_ref => {
4341
5869
  setStepContext(null);
4342
5870
  },
4343
5871
  onSave: handleSaveStep
5872
+ }), /*#__PURE__*/jsxRuntime.jsx(ChoiceOptionEditorModal$1, {
5873
+ open: choiceOptionEditorOpen,
5874
+ option: choiceOptionContext?.option,
5875
+ renderModal: renderModal,
5876
+ onCancel: () => {
5877
+ setChoiceOptionEditorOpen(false);
5878
+ setChoiceOptionContext(null);
5879
+ },
5880
+ onSave: handleSaveChoiceOption
4344
5881
  }), /*#__PURE__*/jsxRuntime.jsx(FieldEditorModal$1, {
4345
5882
  open: fieldEditorOpen,
4346
5883
  field: editingField,
@@ -4421,6 +5958,7 @@ const preset = function (_temp) {
4421
5958
  };
4422
5959
 
4423
5960
  exports.FormCreator = FormCreator$1;
5961
+ exports.MAX_BLOCK_DEPTH = MAX_BLOCK_DEPTH;
4424
5962
  exports.RULE_LEN_PRESET = RULE_LEN_PRESET;
4425
5963
  exports.RULE_PRESET_ITEMS = RULE_PRESET_ITEMS;
4426
5964
  exports.SchemaRenderer = SchemaRenderer$1;
@@ -4428,8 +5966,10 @@ exports.SchemaRendererInner = SchemaRendererInner;
4428
5966
  exports.applyFromPropsSchema = applyFromPropsSchema;
4429
5967
  exports.blockToFormValues = blockToFormValues;
4430
5968
  exports.buildRuleString = buildRuleString;
5969
+ exports.collectBlockFieldNames = collectBlockFieldNames;
4431
5970
  exports.collectSchemaFields = collectSchemaFields;
4432
5971
  exports.createBlock = createBlock;
5972
+ exports.createChoiceOption = createChoiceOption;
4433
5973
  exports.createField = createField$1;
4434
5974
  exports.createFieldId = createFieldId;
4435
5975
  exports.createStep = createStep;
@@ -4438,6 +5978,7 @@ exports.defaultFormActions = defaultFormActions;
4438
5978
  exports.defaultSchema = defaultSchema;
4439
5979
  exports.fieldToFormValues = fieldToFormValues;
4440
5980
  exports.findBlock = findBlock;
5981
+ exports.findBlockInTree = findBlockInTree;
4441
5982
  exports.formValuesToBlock = formValuesToBlock;
4442
5983
  exports.formValuesToField = formValuesToField;
4443
5984
  exports.getBlockDefinition = getBlockDefinition;
@@ -4449,6 +5990,7 @@ exports.getRulePresetItems = getRulePresetItems;
4449
5990
  exports.hasRenderableContent = hasRenderableContent;
4450
5991
  exports.isFieldNameUnique = isFieldNameUnique;
4451
5992
  exports.mapBlocks = mapBlocks;
5993
+ exports.moveBlockInTree = moveBlockInTree;
4452
5994
  exports.moveItem = moveItem;
4453
5995
  exports.normalizeBlock = normalizeBlock;
4454
5996
  exports.normalizeFormActions = normalizeFormActions;
@@ -4458,7 +6000,6 @@ exports.parseRuleString = parseRuleString;
4458
6000
  exports.pickFieldProps = pickFieldProps;
4459
6001
  exports.pickFromPropsSchema = pickFromPropsSchema;
4460
6002
  exports.preset = preset;
4461
- exports.registerField = registerField;
4462
- exports.registerRulePreset = registerRulePreset;
6003
+ exports.removeBlockInTree = removeBlockInTree;
4463
6004
  exports.updateBlocks = updateBlocks;
4464
6005
  //# sourceMappingURL=index.js.map