@kne/form-creator 0.1.3 → 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.
@@ -4,16 +4,17 @@ import { useState, useMemo, useEffect, createElement, Fragment } from 'react';
4
4
  import { Space, Tag, Button, Typography, Flex, Dropdown, Empty, message, Checkbox as Checkbox$1, Input as Input$1, InputNumber as InputNumber$1, Card, Tooltip } from 'antd';
5
5
  import { createWithIntlProvider, useIntl } from '@kne/react-intl';
6
6
  import { useIsMobile, RESPONSIVE_BOUNDARY_CLASS } from '@kne/responsive-utils';
7
- import { ArrowUpOutlined, ArrowDownOutlined, EditOutlined, DeleteOutlined, PlusOutlined, SettingOutlined, FormOutlined, UnorderedListOutlined, TableOutlined, AppstoreOutlined, OrderedListOutlined, ApartmentOutlined, QuestionCircleOutlined } from '@ant-design/icons';
8
- import { hooks, Input, TextArea, InputNumber, Select, RadioGroup, CheckboxGroup, Switch, Checkbox, DatePicker, useFormContext, Slider, SubmitButton, ResetButton, CancelButton } from '@kne/react-form-antd';
7
+ import { ArrowUpOutlined, ArrowDownOutlined, EditOutlined, DeleteOutlined, PlusOutlined, SettingOutlined, FormOutlined, UnorderedListOutlined, TableOutlined, ClusterOutlined, PartitionOutlined, AppstoreOutlined, OrderedListOutlined, SelectOutlined, ApartmentOutlined, ArrowLeftOutlined, ArrowRightOutlined, QuestionCircleOutlined } from '@ant-design/icons';
8
+ import { hooks, Input, TextArea, InputNumber, Select, RadioGroup, CheckboxGroup, Switch, Checkbox, DatePicker, useFormContext, Slider, SubmitButton, ResetButton, CancelButton, RULES, preset as preset$1 } from '@kne/react-form-antd';
9
9
  import SelectList, { SelectTableList, SelectTree, SelectCascader } from '@kne/super-select';
10
10
  import { SelectFunction, SelectIndustry, SelectAddress } from '@kne/super-select-plus';
11
11
  import '@kne/super-select/dist/index.css';
12
12
  import '@kne/super-select-plus/dist/index.css';
13
13
  import { jsxs, jsx } from 'react/jsx-runtime';
14
14
  import FormInfo, { FormModal, Form, Steps, MultiField, TableList, List } from '@kne/form-info';
15
+ import InfoPage from '@kne/info-page';
15
16
 
16
- 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"};
17
+ 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"};
17
18
 
18
19
  function _extends() {
19
20
  return _extends = Object.assign ? Object.assign.bind() : function (n) {
@@ -53,18 +54,49 @@ const locale$1 = {
53
54
  expandBlock: '展开',
54
55
  collapseBlock: '收起',
55
56
  fieldCount: '{count} 个填写项',
57
+ fieldAndItemBlockCount: '{fields} 个填写项 · {nests} 个子模块',
58
+ addChildBlock: '添加子模块',
56
59
  stepCount: '{count} 个步骤',
57
60
  blockKind_formInfo: '基础表单',
58
61
  blockKind_list: '可增减列表',
59
62
  blockKind_tableList: '表格列表',
60
63
  blockKind_multiField: '同类多值',
64
+ blockKind_object: '分组信息',
65
+ blockKind_choice: '选项切换',
61
66
  blockKind_steps: '分步表单',
67
+ choiceMode: '可选几个',
68
+ choiceModeSingle: '只能选一个',
69
+ choiceModeMultiple: '可以选多个',
70
+ choiceMinSelect: '最少选择几个',
71
+ choiceMaxSelect: '最多选择几个',
72
+ choiceMinSelectError: '请至少选择 {count} 项',
73
+ choiceMaxSelectError: '最多只能选择 {count} 项',
74
+ choiceSelectorName: '所选结果的名称',
75
+ choiceSelectorNamePlaceholder: '可不填,系统会自动生成',
76
+ choiceSelectorInData: '提交时带上所选结果',
77
+ choiceTitlePlaceholder: '例如:客户类型',
78
+ choiceOptionListTitle: '选项列表',
79
+ addChoiceOption: '添加选项',
80
+ editChoiceOption: '编辑选项',
81
+ deleteChoiceOption: '删除选项',
82
+ choiceOptionTitle: '选项名称',
83
+ choiceOptionTitlePlaceholder: '例如:企业、个人',
84
+ emptyChoiceOptionList: '暂无选项,点击上方添加',
85
+ choiceOptionFallback: '选项{index}',
86
+ choiceOptionCount: '{count} 个选项',
87
+ choiceAreaTitle: '请选择',
88
+ choiceModeHintSingle: '请选择其中一项',
89
+ choiceModeHintMultiple: '可以选择多项',
90
+ choiceModeHintMultipleMin: '请至少选择 {count} 项',
91
+ choiceModeHintMultipleMax: '最多选择 {count} 项',
92
+ choiceModeHintMultipleRange: '请选择 {min}–{max} 项',
93
+ choiceSelectFirstHint: '请先在上方选择,再填写对应内容',
62
94
  blockTitle: '模块标题',
63
95
  blockTitlePlaceholder: '例如:基本信息',
64
96
  blockSubtitle: '模块副标题',
65
97
  blockSubtitlePlaceholder: '例如:请填写员工基本信息',
66
- blockName: '数据标识',
67
- blockNameRequired: '请填写数据标识',
98
+ blockName: '保存用的名称',
99
+ blockNameRequired: '请填写保存用的名称',
68
100
  blockGap: '间距',
69
101
  blockBordered: '显示边框',
70
102
  blockImportant: '突出显示',
@@ -88,7 +120,7 @@ const locale$1 = {
88
120
  stepNext: '下一步',
89
121
  stepComplete: '完成',
90
122
  fieldType: '填写项类型',
91
- fieldName: '数据标识',
123
+ fieldName: '保存用的名称',
92
124
  fieldNamePlaceholder: '已自动生成,可修改',
93
125
  fieldLabel: '显示名称',
94
126
  fieldLabelPlaceholder: '例如:姓名',
@@ -103,7 +135,7 @@ const locale$1 = {
103
135
  fieldHidden: '隐藏该项',
104
136
  fieldHiddenTag: '已隐藏',
105
137
  fieldBlockTag: '整行',
106
- fieldNameDuplicate: '该数据标识已被使用,请换一个',
138
+ fieldNameDuplicate: '该名称已被使用,请换一个',
107
139
  untitledField: '未命名填写项',
108
140
  previewTitle: '表单预览',
109
141
  previewHint: '左侧的配置变化会实时同步到这里',
@@ -142,9 +174,9 @@ const locale$1 = {
142
174
  columnNamePlaceholder: '已自动生成,可修改',
143
175
  columnWidthPlaceholder: '列宽(可选)',
144
176
  addColumn: '添加一列',
145
- columnsEditorHint: '列标题用于表头展示;数据名已自动生成,需要时可改',
177
+ columnsEditorHint: '列标题用于表头展示;保存用的名称已自动生成,需要时可改',
146
178
  fieldTableRows: '表格数据',
147
- tableRowsNeedColumnsHint: '请先在上方填写列的数据名,再来配置每一行数据',
179
+ tableRowsNeedColumnsHint: '请先在上方填写列的保存名称,再来配置每一行数据',
148
180
  tableRowTitle: '第 {index} 行',
149
181
  tableRowLabelPlaceholder: '选中后显示的文字',
150
182
  addTableRow: '添加一行数据',
@@ -218,18 +250,49 @@ const locale = {
218
250
  expandBlock: 'Expand',
219
251
  collapseBlock: 'Collapse',
220
252
  fieldCount: '{count} fields',
253
+ fieldAndItemBlockCount: '{fields} fields · {nests} child sections',
254
+ addChildBlock: 'Add child section',
221
255
  stepCount: '{count} steps',
222
256
  blockKind_formInfo: 'Basic Form',
223
257
  blockKind_list: 'Repeatable List',
224
258
  blockKind_tableList: 'Table List',
225
259
  blockKind_multiField: 'Multi-Value',
260
+ blockKind_object: 'Grouped Fields',
261
+ blockKind_choice: 'Options',
226
262
  blockKind_steps: 'Step-by-Step',
263
+ choiceMode: 'How many can be selected',
264
+ choiceModeSingle: 'One only',
265
+ choiceModeMultiple: 'More than one',
266
+ choiceMinSelect: 'Minimum selections',
267
+ choiceMaxSelect: 'Maximum selections',
268
+ choiceMinSelectError: 'Select at least {count}',
269
+ choiceMaxSelectError: 'Select at most {count}',
270
+ choiceSelectorName: 'Name for the selection',
271
+ choiceSelectorNamePlaceholder: 'Optional — generated automatically if empty',
272
+ choiceSelectorInData: 'Include the selection when submitting',
273
+ choiceTitlePlaceholder: 'e.g. Customer type',
274
+ choiceOptionListTitle: 'Options',
275
+ addChoiceOption: 'Add option',
276
+ editChoiceOption: 'Edit option',
277
+ deleteChoiceOption: 'Delete option',
278
+ choiceOptionTitle: 'Option name',
279
+ choiceOptionTitlePlaceholder: 'e.g. Company, Individual',
280
+ emptyChoiceOptionList: 'No options yet. Click above to add one.',
281
+ choiceOptionFallback: 'Option {index}',
282
+ choiceOptionCount: '{count} options',
283
+ choiceAreaTitle: 'Please select',
284
+ choiceModeHintSingle: 'Select one option',
285
+ choiceModeHintMultiple: 'You can select more than one',
286
+ choiceModeHintMultipleMin: 'Select at least {count}',
287
+ choiceModeHintMultipleMax: 'Select at most {count}',
288
+ choiceModeHintMultipleRange: 'Select {min}–{max} options',
289
+ choiceSelectFirstHint: 'Select an option above to continue',
227
290
  blockTitle: 'Section Title',
228
291
  blockTitlePlaceholder: 'e.g. Basic Info',
229
292
  blockSubtitle: 'Section Subtitle',
230
293
  blockSubtitlePlaceholder: 'e.g. Please fill in employee info',
231
- blockName: 'Data Key',
232
- blockNameRequired: 'Data key is required',
294
+ blockName: 'Save name',
295
+ blockNameRequired: 'Please enter a save name',
233
296
  blockGap: 'Spacing',
234
297
  blockBordered: 'Show Border',
235
298
  blockImportant: 'Highlight',
@@ -253,7 +316,7 @@ const locale = {
253
316
  stepNext: 'Next',
254
317
  stepComplete: 'Done',
255
318
  fieldType: 'Field Type',
256
- fieldName: 'Data Key',
319
+ fieldName: 'Save name',
257
320
  fieldNamePlaceholder: 'Auto-generated, editable',
258
321
  fieldLabel: 'Display Name',
259
322
  fieldLabelPlaceholder: 'e.g. Full Name',
@@ -268,7 +331,7 @@ const locale = {
268
331
  fieldHidden: 'Hidden',
269
332
  fieldHiddenTag: 'Hidden',
270
333
  fieldBlockTag: 'Full Width',
271
- fieldNameDuplicate: 'This data key is already in use, please choose another',
334
+ fieldNameDuplicate: 'This name is already in use, please choose another',
272
335
  untitledField: 'Untitled Field',
273
336
  previewTitle: 'Form Preview',
274
337
  previewHint: 'Changes on the left are reflected here in real time',
@@ -379,6 +442,7 @@ const createFieldId = () => `field_${Date.now()}_${Math.random().toString(36).sl
379
442
  /** 生成可编辑的默认数据标识,如 field_xxxx / col_xxxx */
380
443
  const createDataKey = (prefix = 'field') => `${prefix}_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 6)}`;
381
444
  const isAutoDataKey = (value, prefix = 'field') => new RegExp(`^${prefix}_[a-z0-9]+_[a-z0-9]+$`, 'i').test(String(value || '').trim());
445
+ const MAX_BLOCK_DEPTH = 5;
382
446
  const createEmptyColumn = () => ({
383
447
  title: '',
384
448
  name: createDataKey('col'),
@@ -442,7 +506,14 @@ const createField$1 = (overrides = {}) => _extends({
442
506
  hidden: false,
443
507
  props: {}
444
508
  }, overrides);
509
+ const createChoiceOption = (overrides = {}) => _extends({
510
+ id: createFieldId(),
511
+ title: '',
512
+ list: [],
513
+ blocks: []
514
+ }, overrides);
445
515
  const createBlock = (kind, overrides = {}) => {
516
+ const needsName = ['list', 'tableList', 'multiField', 'object'].includes(kind);
446
517
  const base = {
447
518
  id: createFieldId(),
448
519
  kind,
@@ -452,56 +523,199 @@ const createBlock = (kind, overrides = {}) => {
452
523
  gap: 24,
453
524
  bordered: false,
454
525
  important: false,
455
- name: ['list', 'tableList', 'multiField'].includes(kind) ? createDataKey('block') : '',
526
+ name: needsName ? createDataKey(kind === 'object' ? 'obj' : 'block') : '',
456
527
  label: '',
457
528
  addText: '',
458
529
  maxLength: undefined,
459
530
  minLength: undefined,
460
531
  fieldType: 'Input',
461
532
  autoStep: true,
533
+ mode: 'single',
534
+ selectorName: '',
535
+ selectorInData: true,
536
+ discriminator: undefined,
462
537
  list: [],
463
- items: []
538
+ items: [],
539
+ itemBlocks: [],
540
+ blocks: [],
541
+ options: []
464
542
  };
465
543
  if (kind === 'steps') {
466
544
  return _extends({}, base, {
467
545
  list: undefined,
546
+ itemBlocks: undefined,
547
+ blocks: undefined,
548
+ options: undefined,
468
549
  items: [createStep()]
469
550
  }, overrides);
470
551
  }
471
552
  if (kind === 'multiField') {
472
553
  return _extends({}, base, {
473
- list: undefined
554
+ list: undefined,
555
+ itemBlocks: undefined,
556
+ blocks: undefined,
557
+ options: undefined,
558
+ items: undefined
559
+ }, overrides);
560
+ }
561
+ if (kind === 'choice') {
562
+ const next = _extends({}, base, {
563
+ list: undefined,
564
+ itemBlocks: undefined,
565
+ blocks: undefined,
566
+ items: undefined,
567
+ name: '',
568
+ options: [createChoiceOption({
569
+ title: '选项1'
570
+ })]
571
+ }, overrides, {
572
+ kind: 'choice'
573
+ });
574
+ next.mode = next.mode === 'multiple' ? 'multiple' : 'single';
575
+ if (!Array.isArray(next.options)) {
576
+ next.options = [createChoiceOption({
577
+ title: '选项1'
578
+ })];
579
+ }
580
+ return next;
581
+ }
582
+ if (kind === 'object') {
583
+ return _extends({}, base, {
584
+ items: undefined,
585
+ options: undefined,
586
+ itemBlocks: undefined
474
587
  }, overrides);
475
588
  }
476
- return _extends({}, base, overrides);
589
+ if (kind === 'list') {
590
+ return _extends({}, base, {
591
+ blocks: undefined
592
+ }, overrides);
593
+ }
594
+ if (kind === 'tableList') {
595
+ return _extends({}, base, {
596
+ blocks: undefined,
597
+ itemBlocks: undefined
598
+ }, overrides);
599
+ }
600
+
601
+ // formInfo:支持 blocks 子模块
602
+ return _extends({}, base, {
603
+ itemBlocks: undefined
604
+ }, overrides);
477
605
  };
478
606
  const createStep = (overrides = {}) => _extends({
479
607
  id: createFieldId(),
480
608
  title: '',
481
609
  column: 2,
482
- list: []
610
+ list: [],
611
+ blocks: []
483
612
  }, overrides);
613
+ const normalizeSelectCount = (value, minAllowed = 0) => {
614
+ if (value == null || value === '') {
615
+ return undefined;
616
+ }
617
+ const num = Number(value);
618
+ if (!Number.isFinite(num)) {
619
+ return undefined;
620
+ }
621
+ const int = Math.floor(num);
622
+ if (int < minAllowed) {
623
+ return undefined;
624
+ }
625
+ return int;
626
+ };
484
627
  const normalizeField = field => _extends({}, createField$1(), field, {
485
628
  props: _extends({}, field.props || {})
486
629
  });
487
- const normalizeStep = step => _extends({}, createStep(), step, {
488
- list: Array.isArray(step.list) ? step.list.map(normalizeField) : []
630
+ const normalizeStep = (step, depth = 0) => _extends({}, createStep(), step, {
631
+ list: Array.isArray(step.list) ? step.list.map(normalizeField) : [],
632
+ blocks: Array.isArray(step.blocks) ? step.blocks.map(child => normalizeBlock(child, depth + 1)) : []
489
633
  });
490
- const normalizeBlock = block => {
634
+ const normalizeChoiceOption = (option, depth) => {
635
+ var _blocks$;
636
+ let list = Array.isArray(option.list) ? option.list.map(normalizeField) : [];
637
+ let blocks = Array.isArray(option.blocks) ? option.blocks.map(block => normalizeBlock(block, depth + 1)) : [];
638
+
639
+ // 兼容仅写 blocks: [formInfo] 的写法:把首个 formInfo 的字段提升到 option.list,便于编辑器管理
640
+ if (!list.length && ((_blocks$ = blocks[0]) == null ? void 0 : _blocks$.kind) === 'formInfo' && (blocks[0].list || []).length) {
641
+ list = (blocks[0].list || []).map(normalizeField);
642
+ blocks = blocks.slice(1);
643
+ }
644
+ return _extends({}, createChoiceOption(), option, {
645
+ list,
646
+ blocks
647
+ });
648
+ };
649
+ const normalizeBlock = (block, depth = 0) => {
491
650
  const kind = block.kind || 'formInfo';
651
+ if (depth > MAX_BLOCK_DEPTH) {
652
+ return _extends({}, createBlock(kind), block, {
653
+ list: Array.isArray(block.list) ? block.list.map(normalizeField) : [],
654
+ itemBlocks: [],
655
+ options: [],
656
+ items: kind === 'steps' ? [createStep()] : undefined
657
+ });
658
+ }
492
659
  const normalized = _extends({}, createBlock(kind), block);
493
660
  if (kind === 'steps') {
494
- normalized.items = Array.isArray(block.items) ? block.items.map(normalizeStep) : [createStep()];
661
+ normalized.items = Array.isArray(block.items) ? block.items.map(step => normalizeStep(step, depth)) : [createStep()];
495
662
  delete normalized.list;
663
+ delete normalized.itemBlocks;
664
+ delete normalized.blocks;
665
+ delete normalized.options;
496
666
  return normalized;
497
667
  }
498
668
  if (kind === 'multiField') {
499
669
  normalized.list = undefined;
500
670
  normalized.items = undefined;
671
+ normalized.itemBlocks = undefined;
672
+ normalized.blocks = undefined;
673
+ normalized.options = undefined;
674
+ return normalized;
675
+ }
676
+ if (kind === 'choice') {
677
+ normalized.mode = block.mode === 'multiple' ? 'multiple' : 'single';
678
+ normalized.selectorName = block.selectorName != null ? String(block.selectorName) : '';
679
+ normalized.selectorInData = block.selectorInData !== false;
680
+ normalized.discriminator = block.discriminator && typeof block.discriminator === 'object' ? _extends({}, block.discriminator) : undefined;
681
+ normalized.options = Array.isArray(block.options) ? block.options.map(option => normalizeChoiceOption(option, depth)) : [];
682
+ normalized.list = undefined;
683
+ normalized.items = undefined;
684
+ normalized.itemBlocks = undefined;
685
+ normalized.blocks = undefined;
686
+ if (normalized.mode === 'multiple') {
687
+ const minSelect = normalizeSelectCount(block.minLength, 0);
688
+ const maxSelect = normalizeSelectCount(block.maxLength, 1);
689
+ normalized.minLength = minSelect;
690
+ normalized.maxLength = maxSelect != null && minSelect != null && maxSelect < minSelect ? minSelect : maxSelect;
691
+ } else {
692
+ normalized.minLength = undefined;
693
+ normalized.maxLength = undefined;
694
+ }
695
+ return normalized;
696
+ }
697
+ if (kind === 'object') {
698
+ normalized.list = Array.isArray(block.list) ? block.list.map(normalizeField) : [];
699
+ normalized.items = undefined;
700
+ normalized.itemBlocks = undefined;
701
+ normalized.options = undefined;
702
+ normalized.blocks = Array.isArray(block.blocks) ? block.blocks.map(child => normalizeBlock(child, depth + 1)) : [];
501
703
  return normalized;
502
704
  }
503
705
  normalized.list = Array.isArray(block.list) ? block.list.map(normalizeField) : [];
504
706
  normalized.items = undefined;
707
+ normalized.options = undefined;
708
+ if (kind === 'list') {
709
+ normalized.itemBlocks = Array.isArray(block.itemBlocks) ? block.itemBlocks.map(child => normalizeBlock(child, depth + 1)) : [];
710
+ normalized.blocks = undefined;
711
+ } else if (kind === 'tableList') {
712
+ normalized.itemBlocks = undefined;
713
+ normalized.blocks = undefined;
714
+ } else {
715
+ // formInfo
716
+ normalized.itemBlocks = undefined;
717
+ normalized.blocks = Array.isArray(block.blocks) ? block.blocks.map(child => normalizeBlock(child, depth + 1)) : [];
718
+ }
505
719
  return normalized;
506
720
  };
507
721
  const normalizeSchema = (schema = {}) => {
@@ -509,7 +723,7 @@ const normalizeSchema = (schema = {}) => {
509
723
  if (Array.isArray(schema.blocks)) {
510
724
  return _extends({}, base, schema, {
511
725
  actions: normalizeFormActions(schema.actions),
512
- blocks: schema.blocks.map(normalizeBlock)
726
+ blocks: schema.blocks.map(block => normalizeBlock(block))
513
727
  });
514
728
  }
515
729
  if (Array.isArray(schema.list) && schema.list.length) {
@@ -550,52 +764,338 @@ const isFieldNameUnique = (fields, name, excludeId) => {
550
764
  }
551
765
  return !fields.some(item => item.name === name && item.id !== excludeId);
552
766
  };
553
- const collectSchemaFields = (schema, {
554
- blockId,
555
- stepId
556
- } = {}) => {
557
- const blocks = schema.blocks || [];
558
- const fields = [];
767
+ const collectFieldsFromBlocks = (blocks = [], acc = []) => {
559
768
  blocks.forEach(block => {
560
- if (blockId && block.id !== blockId) {
769
+ if (!block) {
561
770
  return;
562
771
  }
563
772
  if (block.kind === 'steps') {
564
773
  (block.items || []).forEach(step => {
565
- if (stepId !== undefined && step.id !== stepId) {
566
- return;
567
- }
568
- fields.push(...(step.list || []));
774
+ acc.push(...(step.list || []));
775
+ collectFieldsFromBlocks(step.blocks || [], acc);
776
+ });
777
+ return;
778
+ }
779
+ if (block.kind === 'choice') {
780
+ (block.options || []).forEach(option => {
781
+ acc.push(...(option.list || []));
782
+ collectFieldsFromBlocks(option.blocks || [], acc);
569
783
  });
570
784
  return;
571
785
  }
572
- if (block.kind !== 'multiField') {
573
- fields.push(...(block.list || []));
786
+ if (block.kind !== 'multiField' && Array.isArray(block.list)) {
787
+ acc.push(...block.list);
788
+ }
789
+ if (Array.isArray(block.itemBlocks)) {
790
+ collectFieldsFromBlocks(block.itemBlocks, acc);
791
+ }
792
+ if (Array.isArray(block.blocks)) {
793
+ collectFieldsFromBlocks(block.blocks, acc);
574
794
  }
575
795
  });
796
+ return acc;
797
+ };
798
+ const collectSchemaFields = (schema, {
799
+ blockId,
800
+ stepId,
801
+ optionId
802
+ } = {}) => {
803
+ const blocks = schema.blocks || [];
804
+ if (!blockId) {
805
+ return collectFieldsFromBlocks(blocks);
806
+ }
807
+ const block = findBlockInTree(blocks, blockId);
808
+ if (!block) {
809
+ return [];
810
+ }
811
+ const fields = [];
812
+ if (block.kind === 'steps') {
813
+ (block.items || []).forEach(step => {
814
+ if (stepId !== undefined && step.id !== stepId) {
815
+ return;
816
+ }
817
+ fields.push(...(step.list || []));
818
+ });
819
+ return fields;
820
+ }
821
+ if (block.kind === 'choice') {
822
+ (block.options || []).forEach(option => {
823
+ if (optionId !== undefined && option.id !== optionId) {
824
+ return;
825
+ }
826
+ fields.push(...(option.list || []));
827
+ collectFieldsFromBlocks(option.blocks || [], fields);
828
+ });
829
+ return fields;
830
+ }
831
+ if (block.kind !== 'multiField') {
832
+ fields.push(...(block.list || []));
833
+ }
576
834
  return fields;
577
835
  };
836
+
837
+ /** 收集 blocks 树中所有字段 name(含 object 前缀后的完整名需在渲染层处理) */
838
+ const collectBlockFieldNames = (blocks = [], {
839
+ objectNamePrefix: _objectNamePrefix = ''
840
+ } = {}) => {
841
+ const names = [];
842
+ const walk = (list, prefix) => {
843
+ (list || []).forEach(block => {
844
+ if (!block) {
845
+ return;
846
+ }
847
+ if (block.kind === 'object') {
848
+ const nextPrefix = [prefix, block.name].filter(Boolean).join('.');
849
+ (block.list || []).forEach(field => {
850
+ if (field != null && field.name) {
851
+ names.push(nextPrefix ? `${nextPrefix}.${field.name}` : field.name);
852
+ }
853
+ });
854
+ walk(block.blocks || [], nextPrefix);
855
+ return;
856
+ }
857
+ if (block.kind === 'choice') {
858
+ (block.options || []).forEach(option => {
859
+ (option.list || []).forEach(field => {
860
+ if (field != null && field.name) {
861
+ names.push(prefix ? `${prefix}.${field.name}` : field.name);
862
+ }
863
+ });
864
+ walk(option.blocks || [], prefix);
865
+ });
866
+ return;
867
+ }
868
+ if (block.kind === 'steps') {
869
+ (block.items || []).forEach(step => {
870
+ (step.list || []).forEach(field => {
871
+ if (field != null && field.name) {
872
+ names.push(prefix ? `${prefix}.${field.name}` : field.name);
873
+ }
874
+ });
875
+ walk(step.blocks || [], prefix);
876
+ });
877
+ return;
878
+ }
879
+ if (block.kind !== 'multiField') {
880
+ (block.list || []).forEach(field => {
881
+ if (field != null && field.name) {
882
+ names.push(prefix ? `${prefix}.${field.name}` : field.name);
883
+ }
884
+ });
885
+ }
886
+ if (block.kind === 'list') {
887
+ // 列表项内字段相对 GroupList,此处只收集定义名供 choice 清理参考
888
+ walk(block.itemBlocks || [], prefix);
889
+ }
890
+ if (Array.isArray(block.blocks)) {
891
+ walk(block.blocks, prefix);
892
+ }
893
+ });
894
+ };
895
+ walk(blocks, _objectNamePrefix);
896
+ return names;
897
+ };
578
898
  const updateBlocks = (schema, updater) => _extends({}, schema, {
579
899
  blocks: updater(schema.blocks || [])
580
900
  });
581
- const findBlock = (schema, blockId) => (schema.blocks || []).find(block => block.id === blockId);
582
- const mapBlocks = (schema, blockId, updater) => updateBlocks(schema, blocks => blocks.map(block => {
583
- if (block.id !== blockId) {
584
- return block;
585
- }
586
- return updater(block);
587
- }));
588
- const hasRenderableContent = schema => {
589
- const blocks = schema.blocks || [];
590
- return blocks.some(block => {
901
+
902
+ /** blocks / itemBlocks / choice.options.blocks / steps.items.blocks 树中查找模块 */
903
+ const findBlockInTree = (blocks = [], blockId) => {
904
+ for (const block of blocks) {
905
+ if (!block) {
906
+ continue;
907
+ }
908
+ if (block.id === blockId) {
909
+ return block;
910
+ }
911
+ if (Array.isArray(block.itemBlocks)) {
912
+ const found = findBlockInTree(block.itemBlocks, blockId);
913
+ if (found) {
914
+ return found;
915
+ }
916
+ }
917
+ if (Array.isArray(block.blocks)) {
918
+ const found = findBlockInTree(block.blocks, blockId);
919
+ if (found) {
920
+ return found;
921
+ }
922
+ }
923
+ if (block.kind === 'choice') {
924
+ for (const option of block.options || []) {
925
+ const found = findBlockInTree(option.blocks || [], blockId);
926
+ if (found) {
927
+ return found;
928
+ }
929
+ }
930
+ }
591
931
  if (block.kind === 'steps') {
592
- return (block.items || []).some(step => (step.list || []).length > 0);
932
+ for (const step of block.items || []) {
933
+ const found = findBlockInTree(step.blocks || [], blockId);
934
+ if (found) {
935
+ return found;
936
+ }
937
+ }
593
938
  }
594
- if (block.kind === 'multiField') {
595
- return !!block.name;
939
+ }
940
+ return null;
941
+ };
942
+ const findBlock = (schema, blockId) => findBlockInTree(schema.blocks || [], blockId);
943
+
944
+ /** 对模块上挂载的子模块列表(itemBlocks / blocks / option.blocks / step.blocks)应用同一变换 */
945
+ const mapChildBlockLists = (block, mapList) => {
946
+ let nextBlock = block;
947
+ let changed = false;
948
+ if (Array.isArray(block.itemBlocks)) {
949
+ const itemBlocks = mapList(block.itemBlocks);
950
+ if (itemBlocks !== block.itemBlocks) {
951
+ nextBlock = _extends({}, nextBlock, {
952
+ itemBlocks
953
+ });
954
+ changed = true;
955
+ }
956
+ }
957
+ if (Array.isArray(block.blocks)) {
958
+ const childBlocks = mapList(block.blocks);
959
+ if (childBlocks !== block.blocks) {
960
+ nextBlock = _extends({}, nextBlock, {
961
+ blocks: childBlocks
962
+ });
963
+ changed = true;
964
+ }
965
+ }
966
+ if (block.kind === 'choice' && Array.isArray(block.options)) {
967
+ let optionsChanged = false;
968
+ const options = block.options.map(option => {
969
+ if (!Array.isArray(option.blocks)) {
970
+ return option;
971
+ }
972
+ const optionBlocks = mapList(option.blocks);
973
+ if (optionBlocks !== option.blocks) {
974
+ optionsChanged = true;
975
+ return _extends({}, option, {
976
+ blocks: optionBlocks
977
+ });
978
+ }
979
+ return option;
980
+ });
981
+ if (optionsChanged) {
982
+ nextBlock = _extends({}, nextBlock, {
983
+ options
984
+ });
985
+ changed = true;
986
+ }
987
+ }
988
+ if (block.kind === 'steps' && Array.isArray(block.items)) {
989
+ let itemsChanged = false;
990
+ const items = block.items.map(step => {
991
+ if (!Array.isArray(step.blocks)) {
992
+ return step;
993
+ }
994
+ const stepBlocks = mapList(step.blocks);
995
+ if (stepBlocks !== step.blocks) {
996
+ itemsChanged = true;
997
+ return _extends({}, step, {
998
+ blocks: stepBlocks
999
+ });
1000
+ }
1001
+ return step;
1002
+ });
1003
+ if (itemsChanged) {
1004
+ nextBlock = _extends({}, nextBlock, {
1005
+ items
1006
+ });
1007
+ changed = true;
1008
+ }
1009
+ }
1010
+ return {
1011
+ nextBlock,
1012
+ changed
1013
+ };
1014
+ };
1015
+ const mapBlocksInTree = (blocks, blockId, updater) => {
1016
+ let changed = false;
1017
+ const next = (blocks || []).map(block => {
1018
+ if (!block) {
1019
+ return block;
1020
+ }
1021
+ if (block.id === blockId) {
1022
+ changed = true;
1023
+ return updater(block);
596
1024
  }
597
- return (block.list || []).length > 0 || block.title;
1025
+ const {
1026
+ nextBlock,
1027
+ changed: childChanged
1028
+ } = mapChildBlockLists(block, list => mapBlocksInTree(list, blockId, updater));
1029
+ if (childChanged) {
1030
+ changed = true;
1031
+ }
1032
+ return nextBlock;
1033
+ });
1034
+ return changed ? next : blocks;
1035
+ };
1036
+ const mapBlocks = (schema, blockId, updater) => updateBlocks(schema, blocks => mapBlocksInTree(blocks, blockId, updater));
1037
+ const removeBlockInTree = (blocks, blockId) => {
1038
+ let changed = false;
1039
+ const filtered = (blocks || []).filter(block => {
1040
+ if ((block == null ? void 0 : block.id) === blockId) {
1041
+ changed = true;
1042
+ return false;
1043
+ }
1044
+ return true;
598
1045
  });
1046
+ const next = filtered.map(block => {
1047
+ const {
1048
+ nextBlock,
1049
+ changed: childChanged
1050
+ } = mapChildBlockLists(block, list => removeBlockInTree(list, blockId));
1051
+ if (childChanged) {
1052
+ changed = true;
1053
+ }
1054
+ return nextBlock;
1055
+ });
1056
+ return changed ? next : blocks;
1057
+ };
1058
+ const moveBlockInTree = (blocks, blockId, direction) => {
1059
+ if ((blocks || []).some(block => (block == null ? void 0 : block.id) === blockId)) {
1060
+ return moveItem(blocks, blockId, direction);
1061
+ }
1062
+ let changed = false;
1063
+ const next = (blocks || []).map(block => {
1064
+ const {
1065
+ nextBlock,
1066
+ changed: childChanged
1067
+ } = mapChildBlockLists(block, list => moveBlockInTree(list, blockId, direction));
1068
+ if (childChanged) {
1069
+ changed = true;
1070
+ }
1071
+ return nextBlock;
1072
+ });
1073
+ return changed ? next : blocks;
1074
+ };
1075
+ const blockHasContent = block => {
1076
+ if (!block) {
1077
+ return false;
1078
+ }
1079
+ if (block.kind === 'steps') {
1080
+ return (block.items || []).some(step => (step.list || []).length > 0 || (step.blocks || []).some(blockHasContent) || step.title);
1081
+ }
1082
+ if (block.kind === 'multiField') {
1083
+ return !!block.name;
1084
+ }
1085
+ if (block.kind === 'choice') {
1086
+ return (block.options || []).some(option => (option.list || []).length > 0 || (option.blocks || []).some(blockHasContent) || option.title);
1087
+ }
1088
+ if (block.kind === 'object') {
1089
+ return !!(block.name && ((block.list || []).length > 0 || (block.blocks || []).some(blockHasContent) || block.title));
1090
+ }
1091
+ if ((block.list || []).length > 0 || block.title || (block.blocks || []).some(blockHasContent)) {
1092
+ return true;
1093
+ }
1094
+ return (block.itemBlocks || []).some(blockHasContent);
1095
+ };
1096
+ const hasRenderableContent = schema => {
1097
+ const blocks = schema.blocks || [];
1098
+ return blocks.some(blockHasContent);
599
1099
  };
600
1100
 
601
1101
  const BLOCK_KINDS = {
@@ -625,6 +1125,19 @@ const BLOCK_KINDS = {
625
1125
  requiresName: true,
626
1126
  description: '同一种填写项可以输入多个值,例如多个手机号'
627
1127
  },
1128
+ object: {
1129
+ label: '分组信息',
1130
+ color: 'orange',
1131
+ hasFieldList: true,
1132
+ requiresName: true,
1133
+ description: '把相关的填写项放在一起,例如「在校时间」下的开始与结束'
1134
+ },
1135
+ choice: {
1136
+ label: '选项切换',
1137
+ color: 'magenta',
1138
+ hasChoiceOptions: true,
1139
+ description: '先选一类情况,再填写对应内容;可设为单选或多选'
1140
+ },
628
1141
  steps: {
629
1142
  label: '分步表单',
630
1143
  color: 'gold',
@@ -653,13 +1166,18 @@ const blockToFormValues = block => {
653
1166
  maxLength: (_block$maxLength = block.maxLength) != null ? _block$maxLength : null,
654
1167
  minLength: (_block$minLength = block.minLength) != null ? _block$minLength : null,
655
1168
  fieldType: block.fieldType || 'Input',
656
- autoStep: block.autoStep !== false
1169
+ autoStep: block.autoStep !== false,
1170
+ mode: block.mode === 'multiple' ? 'multiple' : 'single',
1171
+ selectorName: block.selectorName || '',
1172
+ selectorInData: block.selectorInData !== false
657
1173
  };
658
1174
  };
659
1175
  const formValuesToBlock = (values, existingBlock = {}) => {
660
1176
  var _values$column, _values$gap, _values$maxLength, _values$minLength;
661
- return _extends({}, existingBlock, {
662
- kind: values.kind || existingBlock.kind,
1177
+ const kind = values.kind || existingBlock.kind;
1178
+ const mode = values.mode === 'multiple' ? 'multiple' : 'single';
1179
+ const next = _extends({}, existingBlock, {
1180
+ kind,
663
1181
  title: values.title,
664
1182
  subtitle: values.subtitle,
665
1183
  column: (_values$column = values.column) != null ? _values$column : 2,
@@ -672,8 +1190,16 @@ const formValuesToBlock = (values, existingBlock = {}) => {
672
1190
  maxLength: (_values$maxLength = values.maxLength) != null ? _values$maxLength : undefined,
673
1191
  minLength: (_values$minLength = values.minLength) != null ? _values$minLength : undefined,
674
1192
  fieldType: values.fieldType || 'Input',
675
- autoStep: values.autoStep !== false
1193
+ autoStep: values.autoStep !== false,
1194
+ mode,
1195
+ selectorName: values.selectorName || '',
1196
+ selectorInData: values.selectorInData !== false
676
1197
  });
1198
+ if (kind === 'choice' && mode !== 'multiple') {
1199
+ next.minLength = undefined;
1200
+ next.maxLength = undefined;
1201
+ }
1202
+ return next;
677
1203
  };
678
1204
  const stepToFormValues = step => {
679
1205
  var _step$column;
@@ -689,8 +1215,14 @@ const formValuesToStep = (values, existingStep = {}) => {
689
1215
  column: (_values$column2 = values.column) != null ? _values$column2 : 2
690
1216
  });
691
1217
  };
1218
+ const choiceOptionToFormValues = option => ({
1219
+ title: option.title || ''
1220
+ });
1221
+ const formValuesToChoiceOption = (values, existingOption = {}) => _extends({}, existingOption, {
1222
+ title: values.title
1223
+ });
692
1224
 
693
- const _excluded$3 = ["children"];
1225
+ const _excluded$4 = ["children"];
694
1226
  const mapOptionItem = item => {
695
1227
  if (!item || typeof item !== 'object') {
696
1228
  return item;
@@ -698,7 +1230,7 @@ const mapOptionItem = item => {
698
1230
  const {
699
1231
  children
700
1232
  } = item,
701
- rest = _objectWithoutPropertiesLoose(item, _excluded$3);
1233
+ rest = _objectWithoutPropertiesLoose(item, _excluded$4);
702
1234
  const next = _extends({}, rest);
703
1235
  if (Array.isArray(children) && children.length) {
704
1236
  next.children = children.map(mapOptionItem);
@@ -711,7 +1243,7 @@ const createApiFromOptions = (options = []) => ({
711
1243
  })
712
1244
  });
713
1245
 
714
- const _excluded$2 = ["options", "api", "placeholder"];
1246
+ const _excluded$3 = ["options", "api", "placeholder"];
715
1247
  const {
716
1248
  useOnChange: useOnChange$1
717
1249
  } = hooks;
@@ -726,7 +1258,7 @@ const createField = (Component, {
726
1258
  api,
727
1259
  placeholder
728
1260
  } = props,
729
- rest = _objectWithoutPropertiesLoose(props, _excluded$2);
1261
+ rest = _objectWithoutPropertiesLoose(props, _excluded$3);
730
1262
  const useOptionsDirectly = _preferOptions || hasNestedOptions(options);
731
1263
  const mergedApi = api || (!useOptionsDirectly && Array.isArray(options) && options.length ? createApiFromOptions(options) : undefined);
732
1264
  const resolvedPlaceholder = placeholder != null && String(placeholder).trim() ? placeholder : `${_placeholderPrefix}${props.label || ''}`;
@@ -774,7 +1306,7 @@ const DEFAULT_RULE_CONFIG = () => ({
774
1306
  });
775
1307
  const RULE_LEN_PRESET = 'LEN';
776
1308
 
777
- /** 注册填写项校验规则 preset,会在规则勾选面板中展示 */
1309
+ /** 内部:注册填写项校验规则,会在规则勾选面板中展示(请通过 preset 注册) */
778
1310
  const registerRulePreset = item => {
779
1311
  if (!(item != null && item.value)) {
780
1312
  return;
@@ -1043,7 +1575,7 @@ defineField('DatePicker', {
1043
1575
  * - min / max?: number(type=number)
1044
1576
  * - options?: { label, value }[](type=select)
1045
1577
  *
1046
- * registerField(type, definition) 还可传:
1578
+ * preset({ type, definition }) 的 fields 项还可传:
1047
1579
  * - groupName?: string 自定义类型下拉分组名;不传则归入「扩展字段」
1048
1580
  */
1049
1581
  const registerField = (type, definition) => {
@@ -1596,7 +2128,7 @@ const FieldRow = ({
1596
2128
  };
1597
2129
  var FieldRow$1 = FieldRow;
1598
2130
 
1599
- const _excluded$1 = ["title", "danger"];
2131
+ const _excluded$2 = ["title", "danger"];
1600
2132
  const {
1601
2133
  Text: Text$3
1602
2134
  } = Typography;
@@ -1611,7 +2143,7 @@ const IconBtn = _ref => {
1611
2143
  title,
1612
2144
  danger
1613
2145
  } = _ref,
1614
- props = _objectWithoutPropertiesLoose(_ref, _excluded$1);
2146
+ props = _objectWithoutPropertiesLoose(_ref, _excluded$2);
1615
2147
  return /*#__PURE__*/jsx(Button, _extends({
1616
2148
  type: "text",
1617
2149
  size: "small",
@@ -1620,6 +2152,31 @@ const IconBtn = _ref => {
1620
2152
  className: style['action-btn']
1621
2153
  }, props));
1622
2154
  };
2155
+ const ROOT_ADD_OPTIONS = [{
2156
+ key: 'formInfo',
2157
+ icon: /*#__PURE__*/jsx(FormOutlined, {})
2158
+ }, {
2159
+ key: 'list',
2160
+ icon: /*#__PURE__*/jsx(UnorderedListOutlined, {})
2161
+ }, {
2162
+ key: 'tableList',
2163
+ icon: /*#__PURE__*/jsx(TableOutlined, {})
2164
+ }, {
2165
+ key: 'object',
2166
+ icon: /*#__PURE__*/jsx(ClusterOutlined, {})
2167
+ }, {
2168
+ key: 'choice',
2169
+ icon: /*#__PURE__*/jsx(PartitionOutlined, {})
2170
+ }, {
2171
+ key: 'multiField',
2172
+ icon: /*#__PURE__*/jsx(AppstoreOutlined, {})
2173
+ }, {
2174
+ key: 'steps',
2175
+ icon: /*#__PURE__*/jsx(OrderedListOutlined, {})
2176
+ }];
2177
+
2178
+ /** 可挂子模块的容器;表格列表 / 同类多值本身不支持子模块 */
2179
+ const NESTED_ADD_OPTIONS = ROOT_ADD_OPTIONS.filter(opt => opt.key !== 'steps');
1623
2180
  const BlockListPanel = ({
1624
2181
  blocks,
1625
2182
  onAddBlock,
@@ -1634,29 +2191,160 @@ const BlockListPanel = ({
1634
2191
  onEditStep,
1635
2192
  onDeleteStep,
1636
2193
  onMoveStep,
2194
+ onAddChoiceOption,
2195
+ onEditChoiceOption,
2196
+ onDeleteChoiceOption,
2197
+ onMoveChoiceOption,
1637
2198
  onOpenFormActions
1638
2199
  }) => {
1639
2200
  const {
1640
2201
  formatMessage
1641
2202
  } = useIntl();
1642
2203
  const [addMenuOpen, setAddMenuOpen] = useState(false);
1643
- const addBlockOptions = [{
1644
- key: 'formInfo',
1645
- icon: /*#__PURE__*/jsx(FormOutlined, {})
1646
- }, {
1647
- key: 'list',
1648
- icon: /*#__PURE__*/jsx(UnorderedListOutlined, {})
1649
- }, {
1650
- key: 'tableList',
1651
- icon: /*#__PURE__*/jsx(TableOutlined, {})
1652
- }, {
1653
- key: 'multiField',
1654
- icon: /*#__PURE__*/jsx(AppstoreOutlined, {})
1655
- }, {
1656
- key: 'steps',
1657
- icon: /*#__PURE__*/jsx(OrderedListOutlined, {})
1658
- }];
1659
- const renderFieldList = (fields, blockId, stepId) => {
2204
+ const [addFieldMenuId, setAddFieldMenuId] = useState(null);
2205
+ const renderAddBlockMenu = (options, {
2206
+ onSelect,
2207
+ className
2208
+ } = {}) => /*#__PURE__*/jsx("div", {
2209
+ className: className || style['add-block-dropdown'],
2210
+ children: options.map(opt => {
2211
+ const definition = getBlockDefinition(opt.key);
2212
+ return /*#__PURE__*/jsxs("div", {
2213
+ role: "button",
2214
+ tabIndex: 0,
2215
+ className: style['add-block-option'],
2216
+ onClick: () => onSelect(opt.key),
2217
+ onKeyDown: e => {
2218
+ if (e.key === 'Enter' || e.key === ' ') {
2219
+ onSelect(opt.key);
2220
+ }
2221
+ },
2222
+ children: [/*#__PURE__*/jsx("div", {
2223
+ className: style['add-block-option-icon'],
2224
+ children: opt.icon
2225
+ }), /*#__PURE__*/jsxs("div", {
2226
+ className: style['add-block-option-text'],
2227
+ children: [/*#__PURE__*/jsx("div", {
2228
+ className: style['add-block-option-title'],
2229
+ children: formatMessage({
2230
+ id: `blockKind_${opt.key}`
2231
+ })
2232
+ }), /*#__PURE__*/jsx("div", {
2233
+ className: style['add-block-option-desc'],
2234
+ children: definition == null ? void 0 : definition.description
2235
+ })]
2236
+ })]
2237
+ }, opt.key);
2238
+ })
2239
+ });
2240
+ const renderAddFieldButton = ({
2241
+ menuKey,
2242
+ depth,
2243
+ onAddFieldClick,
2244
+ onAddChildBlock
2245
+ }) => {
2246
+ const canAddChild = typeof onAddChildBlock === 'function' && depth < MAX_BLOCK_DEPTH;
2247
+ const menuOpen = addFieldMenuId === menuKey;
2248
+ const btnClass = `${style['add-inline-btn']} ${style['hover-reveal']} ${menuOpen ? style['hover-reveal-active'] : ''}`.trim();
2249
+ if (!canAddChild) {
2250
+ return /*#__PURE__*/jsx(Button, {
2251
+ type: "text",
2252
+ size: "small",
2253
+ icon: /*#__PURE__*/jsx(PlusOutlined, {}),
2254
+ className: btnClass,
2255
+ onClick: onAddFieldClick,
2256
+ children: formatMessage({
2257
+ id: 'addField'
2258
+ })
2259
+ });
2260
+ }
2261
+ return /*#__PURE__*/jsx(Dropdown, {
2262
+ open: menuOpen,
2263
+ onOpenChange: open => setAddFieldMenuId(open ? menuKey : null),
2264
+ trigger: ['hover'],
2265
+ mouseEnterDelay: 0.1,
2266
+ mouseLeaveDelay: 0.15,
2267
+ getPopupContainer: trigger => trigger.parentElement || document.body,
2268
+ dropdownRender: () => /*#__PURE__*/jsxs("div", {
2269
+ className: style['add-field-dropdown'],
2270
+ children: [/*#__PURE__*/jsxs("div", {
2271
+ role: "button",
2272
+ tabIndex: 0,
2273
+ className: style['add-field-dropdown-item'],
2274
+ onClick: () => {
2275
+ onAddFieldClick();
2276
+ setAddFieldMenuId(null);
2277
+ },
2278
+ onKeyDown: e => {
2279
+ if (e.key === 'Enter' || e.key === ' ') {
2280
+ onAddFieldClick();
2281
+ setAddFieldMenuId(null);
2282
+ }
2283
+ },
2284
+ children: [/*#__PURE__*/jsx("span", {
2285
+ className: style['add-field-dropdown-item-icon'],
2286
+ children: /*#__PURE__*/jsx(SelectOutlined, {})
2287
+ }), /*#__PURE__*/jsx("span", {
2288
+ children: formatMessage({
2289
+ id: 'addField'
2290
+ })
2291
+ })]
2292
+ }), /*#__PURE__*/jsx("div", {
2293
+ className: style['add-field-dropdown-divider']
2294
+ }), /*#__PURE__*/jsx("div", {
2295
+ className: style['add-field-dropdown-label'],
2296
+ children: formatMessage({
2297
+ id: 'addChildBlock'
2298
+ })
2299
+ }), NESTED_ADD_OPTIONS.map(opt => {
2300
+ const definition = getBlockDefinition(opt.key);
2301
+ return /*#__PURE__*/jsxs("div", {
2302
+ role: "button",
2303
+ tabIndex: 0,
2304
+ className: style['add-field-dropdown-item'],
2305
+ onClick: () => {
2306
+ onAddChildBlock(opt.key);
2307
+ setAddFieldMenuId(null);
2308
+ },
2309
+ onKeyDown: e => {
2310
+ if (e.key === 'Enter' || e.key === ' ') {
2311
+ onAddChildBlock(opt.key);
2312
+ setAddFieldMenuId(null);
2313
+ }
2314
+ },
2315
+ children: [/*#__PURE__*/jsx("span", {
2316
+ className: style['add-field-dropdown-item-icon'],
2317
+ children: opt.icon
2318
+ }), /*#__PURE__*/jsx("span", {
2319
+ children: formatMessage({
2320
+ id: `blockKind_${opt.key}`
2321
+ })
2322
+ }), definition != null && definition.description ? /*#__PURE__*/jsx("span", {
2323
+ className: style['add-field-dropdown-item-desc'],
2324
+ children: definition.description
2325
+ }) : null]
2326
+ }, opt.key);
2327
+ })]
2328
+ }),
2329
+ children: /*#__PURE__*/jsx(Button, {
2330
+ type: "text",
2331
+ size: "small",
2332
+ icon: /*#__PURE__*/jsx(PlusOutlined, {}),
2333
+ className: btnClass,
2334
+ onClick: () => {
2335
+ onAddFieldClick();
2336
+ setAddFieldMenuId(null);
2337
+ },
2338
+ children: formatMessage({
2339
+ id: 'addField'
2340
+ })
2341
+ })
2342
+ });
2343
+ };
2344
+ const renderFieldList = (fields, blockId, {
2345
+ stepId,
2346
+ optionId
2347
+ } = {}) => {
1660
2348
  if (!(fields || []).length) {
1661
2349
  return /*#__PURE__*/jsx(Text$3, {
1662
2350
  type: "secondary",
@@ -1672,13 +2360,35 @@ const BlockListPanel = ({
1672
2360
  field: field,
1673
2361
  index: fieldIndex,
1674
2362
  total: fields.length,
1675
- onEdit: fieldItem => onEditField(blockId, fieldItem, stepId),
1676
- onDelete: fieldId => onDeleteField(blockId, fieldId, stepId),
1677
- onMove: (fieldId, direction) => onMoveField(blockId, fieldId, direction, stepId)
2363
+ onEdit: fieldItem => onEditField(blockId, fieldItem, {
2364
+ stepId,
2365
+ optionId
2366
+ }),
2367
+ onDelete: fieldId => onDeleteField(blockId, fieldId, {
2368
+ stepId,
2369
+ optionId
2370
+ }),
2371
+ onMove: (fieldId, direction) => onMoveField(blockId, fieldId, direction, {
2372
+ stepId,
2373
+ optionId
2374
+ })
1678
2375
  }, field.id))
1679
2376
  });
1680
2377
  };
1681
- const renderBlockChildren = block => {
2378
+ const renderNestedBlocks = (childBlocks, depth) => {
2379
+ if (!(childBlocks || []).length) {
2380
+ return null;
2381
+ }
2382
+ return /*#__PURE__*/jsx("div", {
2383
+ className: style['item-blocks-section'],
2384
+ children: /*#__PURE__*/jsx("div", {
2385
+ className: style['nested-block-list'],
2386
+ children: childBlocks.map((child, childIndex) => renderBlockSection(child, childIndex, childBlocks.length, depth + 1))
2387
+ })
2388
+ });
2389
+ };
2390
+ const renderItemBlocks = (parentBlock, depth) => renderNestedBlocks(parentBlock.itemBlocks, depth);
2391
+ const renderBlockChildren = (block, depth) => {
1682
2392
  if (block.kind === 'steps') {
1683
2393
  return /*#__PURE__*/jsxs("div", {
1684
2394
  className: style['block-body'],
@@ -1703,7 +2413,7 @@ const BlockListPanel = ({
1703
2413
  }), (block.items || []).length ? /*#__PURE__*/jsx("div", {
1704
2414
  className: style['step-list'],
1705
2415
  children: (block.items || []).map((step, stepIndex) => {
1706
- var _step$list, _block$items;
2416
+ var _step$list, _step$list2, _block$items;
1707
2417
  return /*#__PURE__*/jsxs("div", {
1708
2418
  className: style['step-section'],
1709
2419
  children: [/*#__PURE__*/jsxs("div", {
@@ -1723,10 +2433,15 @@ const BlockListPanel = ({
1723
2433
  })
1724
2434
  }), /*#__PURE__*/jsx(Text$3, {
1725
2435
  type: "secondary",
1726
- children: formatMessage({
2436
+ children: (step.blocks || []).length ? formatMessage({
2437
+ id: 'fieldAndItemBlockCount'
2438
+ }, {
2439
+ fields: ((_step$list = step.list) == null ? void 0 : _step$list.length) || 0,
2440
+ nests: step.blocks.length
2441
+ }) : formatMessage({
1727
2442
  id: 'fieldCount'
1728
2443
  }, {
1729
- count: ((_step$list = step.list) == null ? void 0 : _step$list.length) || 0
2444
+ count: ((_step$list2 = step.list) == null ? void 0 : _step$list2.length) || 0
1730
2445
  })
1731
2446
  })]
1732
2447
  }), /*#__PURE__*/jsxs(ActionGroup, {
@@ -1758,17 +2473,20 @@ const BlockListPanel = ({
1758
2473
  icon: /*#__PURE__*/jsx(DeleteOutlined, {}),
1759
2474
  onClick: () => onDeleteStep(block.id, step.id)
1760
2475
  })]
1761
- }), /*#__PURE__*/jsx(Button, {
1762
- type: "text",
1763
- size: "small",
1764
- icon: /*#__PURE__*/jsx(PlusOutlined, {}),
1765
- className: `${style['add-inline-btn']} ${style['hover-reveal']}`,
1766
- onClick: () => onAddField(block.id, step.id),
1767
- children: formatMessage({
1768
- id: 'addField'
2476
+ }), renderAddFieldButton({
2477
+ menuKey: `${block.id}:${step.id}`,
2478
+ depth,
2479
+ onAddFieldClick: () => onAddField(block.id, {
2480
+ stepId: step.id
2481
+ }),
2482
+ onAddChildBlock: kind => onAddBlock(kind, {
2483
+ parentBlockId: block.id,
2484
+ stepId: step.id
1769
2485
  })
1770
2486
  })]
1771
- }), renderFieldList(step.list, block.id, step.id)]
2487
+ }), renderFieldList(step.list, block.id, {
2488
+ stepId: step.id
2489
+ }), renderNestedBlocks(step.blocks, depth)]
1772
2490
  }, step.id);
1773
2491
  })
1774
2492
  }) : /*#__PURE__*/jsx(Text$3, {
@@ -1791,11 +2509,218 @@ const BlockListPanel = ({
1791
2509
  })
1792
2510
  });
1793
2511
  }
1794
- return /*#__PURE__*/jsx("div", {
2512
+ if (block.kind === 'choice') {
2513
+ return /*#__PURE__*/jsxs("div", {
2514
+ className: style['block-body'],
2515
+ children: [/*#__PURE__*/jsxs("div", {
2516
+ className: style['section-toolbar'],
2517
+ children: [/*#__PURE__*/jsx(Text$3, {
2518
+ type: "secondary",
2519
+ className: style['section-toolbar-label'],
2520
+ children: formatMessage({
2521
+ id: 'choiceOptionListTitle'
2522
+ })
2523
+ }), /*#__PURE__*/jsx(Button, {
2524
+ type: "text",
2525
+ size: "small",
2526
+ icon: /*#__PURE__*/jsx(PlusOutlined, {}),
2527
+ className: `${style['add-inline-btn']} ${style['hover-reveal']}`,
2528
+ onClick: () => onAddChoiceOption(block.id),
2529
+ children: formatMessage({
2530
+ id: 'addChoiceOption'
2531
+ })
2532
+ })]
2533
+ }), (block.options || []).length ? /*#__PURE__*/jsx("div", {
2534
+ className: style['step-list'],
2535
+ children: (block.options || []).map((option, optionIndex) => {
2536
+ var _option$list, _option$list2, _block$options;
2537
+ return /*#__PURE__*/jsxs("div", {
2538
+ className: style['step-section'],
2539
+ children: [/*#__PURE__*/jsxs("div", {
2540
+ className: style['step-section-header'],
2541
+ children: [/*#__PURE__*/jsxs(Space, {
2542
+ size: 8,
2543
+ className: style['step-section-title'],
2544
+ children: [/*#__PURE__*/jsx("span", {
2545
+ className: style['step-index'],
2546
+ children: optionIndex + 1
2547
+ }), /*#__PURE__*/jsx(Text$3, {
2548
+ strong: true,
2549
+ children: option.title || formatMessage({
2550
+ id: 'choiceOptionFallback'
2551
+ }, {
2552
+ index: optionIndex + 1
2553
+ })
2554
+ }), /*#__PURE__*/jsx(Text$3, {
2555
+ type: "secondary",
2556
+ children: (option.blocks || []).length ? formatMessage({
2557
+ id: 'fieldAndItemBlockCount'
2558
+ }, {
2559
+ fields: ((_option$list = option.list) == null ? void 0 : _option$list.length) || 0,
2560
+ nests: option.blocks.length
2561
+ }) : formatMessage({
2562
+ id: 'fieldCount'
2563
+ }, {
2564
+ count: ((_option$list2 = option.list) == null ? void 0 : _option$list2.length) || 0
2565
+ })
2566
+ })]
2567
+ }), /*#__PURE__*/jsxs(ActionGroup, {
2568
+ children: [/*#__PURE__*/jsx(IconBtn, {
2569
+ title: formatMessage({
2570
+ id: 'moveUp'
2571
+ }),
2572
+ icon: /*#__PURE__*/jsx(ArrowUpOutlined, {}),
2573
+ disabled: optionIndex === 0,
2574
+ onClick: () => onMoveChoiceOption(block.id, option.id, 'up')
2575
+ }), /*#__PURE__*/jsx(IconBtn, {
2576
+ title: formatMessage({
2577
+ id: 'moveDown'
2578
+ }),
2579
+ icon: /*#__PURE__*/jsx(ArrowDownOutlined, {}),
2580
+ disabled: optionIndex === (((_block$options = block.options) == null ? void 0 : _block$options.length) || 0) - 1,
2581
+ onClick: () => onMoveChoiceOption(block.id, option.id, 'down')
2582
+ }), /*#__PURE__*/jsx(IconBtn, {
2583
+ title: formatMessage({
2584
+ id: 'editChoiceOption'
2585
+ }),
2586
+ icon: /*#__PURE__*/jsx(EditOutlined, {}),
2587
+ onClick: () => onEditChoiceOption(block.id, option)
2588
+ }), /*#__PURE__*/jsx(IconBtn, {
2589
+ title: formatMessage({
2590
+ id: 'deleteChoiceOption'
2591
+ }),
2592
+ danger: true,
2593
+ icon: /*#__PURE__*/jsx(DeleteOutlined, {}),
2594
+ onClick: () => onDeleteChoiceOption(block.id, option.id)
2595
+ })]
2596
+ }), renderAddFieldButton({
2597
+ menuKey: `${block.id}:opt:${option.id}`,
2598
+ depth,
2599
+ onAddFieldClick: () => onAddField(block.id, {
2600
+ optionId: option.id
2601
+ }),
2602
+ onAddChildBlock: kind => onAddBlock(kind, {
2603
+ parentBlockId: block.id,
2604
+ optionId: option.id
2605
+ })
2606
+ })]
2607
+ }), renderFieldList(option.list, block.id, {
2608
+ optionId: option.id
2609
+ }), renderNestedBlocks(option.blocks, depth)]
2610
+ }, option.id);
2611
+ })
2612
+ }) : /*#__PURE__*/jsx(Text$3, {
2613
+ type: "secondary",
2614
+ className: style['inline-empty'],
2615
+ children: formatMessage({
2616
+ id: 'emptyChoiceOptionList'
2617
+ })
2618
+ })]
2619
+ });
2620
+ }
2621
+ const supportsItemBlocks = block.kind === 'list';
2622
+ const supportsBlocks = block.kind === 'formInfo' || block.kind === 'object';
2623
+ return /*#__PURE__*/jsxs("div", {
1795
2624
  className: style['block-body'],
1796
- children: renderFieldList(block.list, block.id)
2625
+ children: [renderFieldList(block.list, block.id), supportsItemBlocks ? renderItemBlocks(block, depth) : null, supportsBlocks ? renderNestedBlocks(block.blocks, depth) : null]
1797
2626
  });
1798
2627
  };
2628
+ const renderBlockSection = (block, blockIndex, total, depth = 0) => {
2629
+ var _block$itemBlocks, _block$blocks, _block$items2, _block$options2, _block$list, _block$list2;
2630
+ const definition = getBlockDefinition(block.kind);
2631
+ const canAddField = block.kind !== 'steps' && block.kind !== 'multiField' && block.kind !== 'choice';
2632
+ const supportsItemBlocks = block.kind === 'list';
2633
+ const supportsBlocks = block.kind === 'formInfo' || block.kind === 'object';
2634
+ const supportsChildModules = supportsItemBlocks || supportsBlocks;
2635
+ const nestCount = supportsItemBlocks ? ((_block$itemBlocks = block.itemBlocks) == null ? void 0 : _block$itemBlocks.length) || 0 : ((_block$blocks = block.blocks) == null ? void 0 : _block$blocks.length) || 0;
2636
+ const summary = block.kind === 'steps' ? formatMessage({
2637
+ id: 'stepCount'
2638
+ }, {
2639
+ count: ((_block$items2 = block.items) == null ? void 0 : _block$items2.length) || 0
2640
+ }) : block.kind === 'multiField' ? formatMessage({
2641
+ id: 'multiFieldSummary'
2642
+ }, {
2643
+ type: block.fieldType
2644
+ }) : block.kind === 'choice' ? formatMessage({
2645
+ id: 'choiceOptionCount'
2646
+ }, {
2647
+ count: ((_block$options2 = block.options) == null ? void 0 : _block$options2.length) || 0
2648
+ }) : supportsChildModules && nestCount > 0 ? formatMessage({
2649
+ id: 'fieldAndItemBlockCount'
2650
+ }, {
2651
+ fields: ((_block$list = block.list) == null ? void 0 : _block$list.length) || 0,
2652
+ nests: nestCount
2653
+ }) : formatMessage({
2654
+ id: 'fieldCount'
2655
+ }, {
2656
+ count: ((_block$list2 = block.list) == null ? void 0 : _block$list2.length) || 0
2657
+ });
2658
+ return /*#__PURE__*/jsxs("section", {
2659
+ className: `${style['block-section']} ${style[`block-kind-${block.kind}`] || ''} ${depth > 0 ? style['block-section-nested'] : ''}`.trim(),
2660
+ children: [/*#__PURE__*/jsxs("header", {
2661
+ className: style['block-section-header'],
2662
+ children: [/*#__PURE__*/jsxs("div", {
2663
+ className: style['block-header-left'],
2664
+ children: [/*#__PURE__*/jsx(Tag, {
2665
+ bordered: false,
2666
+ color: (definition == null ? void 0 : definition.color) || 'default',
2667
+ children: (definition == null ? void 0 : definition.label) || block.kind
2668
+ }), /*#__PURE__*/jsx(Text$3, {
2669
+ strong: true,
2670
+ ellipsis: true,
2671
+ className: style['block-title'],
2672
+ children: block.title || block.label || block.name || formatMessage({
2673
+ id: 'untitledBlock'
2674
+ })
2675
+ }), /*#__PURE__*/jsx("span", {
2676
+ className: style['block-summary'],
2677
+ children: summary
2678
+ })]
2679
+ }), /*#__PURE__*/jsxs(Space, {
2680
+ size: 4,
2681
+ wrap: true,
2682
+ className: style['block-header-actions'],
2683
+ children: [/*#__PURE__*/jsxs(ActionGroup, {
2684
+ children: [/*#__PURE__*/jsx(IconBtn, {
2685
+ title: formatMessage({
2686
+ id: 'moveUp'
2687
+ }),
2688
+ icon: /*#__PURE__*/jsx(ArrowUpOutlined, {}),
2689
+ disabled: blockIndex === 0,
2690
+ onClick: () => onMoveBlock(block.id, 'up')
2691
+ }), /*#__PURE__*/jsx(IconBtn, {
2692
+ title: formatMessage({
2693
+ id: 'moveDown'
2694
+ }),
2695
+ icon: /*#__PURE__*/jsx(ArrowDownOutlined, {}),
2696
+ disabled: blockIndex === total - 1,
2697
+ onClick: () => onMoveBlock(block.id, 'down')
2698
+ }), /*#__PURE__*/jsx(IconBtn, {
2699
+ title: formatMessage({
2700
+ id: 'editBlock'
2701
+ }),
2702
+ icon: /*#__PURE__*/jsx(SettingOutlined, {}),
2703
+ onClick: () => onEditBlock(block)
2704
+ }), /*#__PURE__*/jsx(IconBtn, {
2705
+ title: formatMessage({
2706
+ id: 'deleteBlock'
2707
+ }),
2708
+ danger: true,
2709
+ icon: /*#__PURE__*/jsx(DeleteOutlined, {}),
2710
+ onClick: () => onDeleteBlock(block.id)
2711
+ })]
2712
+ }), canAddField ? renderAddFieldButton({
2713
+ menuKey: block.id,
2714
+ depth,
2715
+ onAddFieldClick: () => onAddField(block.id),
2716
+ onAddChildBlock: supportsChildModules ? kind => onAddBlock(kind, {
2717
+ parentBlockId: block.id
2718
+ }) : undefined
2719
+ }) : null]
2720
+ })]
2721
+ }), renderBlockChildren(block, depth)]
2722
+ }, block.id);
2723
+ };
1799
2724
  return /*#__PURE__*/jsxs("div", {
1800
2725
  className: style['block-list-panel'],
1801
2726
  children: [/*#__PURE__*/jsxs(Flex, {
@@ -1807,41 +2732,11 @@ const BlockListPanel = ({
1807
2732
  open: addMenuOpen,
1808
2733
  onOpenChange: setAddMenuOpen,
1809
2734
  trigger: ['click'],
1810
- dropdownRender: () => /*#__PURE__*/jsx("div", {
1811
- className: style['add-block-dropdown'],
1812
- children: addBlockOptions.map(opt => {
1813
- const definition = getBlockDefinition(opt.key);
1814
- return /*#__PURE__*/jsxs("div", {
1815
- role: "button",
1816
- tabIndex: 0,
1817
- className: style['add-block-option'],
1818
- onClick: () => {
1819
- onAddBlock(opt.key);
1820
- setAddMenuOpen(false);
1821
- },
1822
- onKeyDown: e => {
1823
- if (e.key === 'Enter' || e.key === ' ') {
1824
- onAddBlock(opt.key);
1825
- setAddMenuOpen(false);
1826
- }
1827
- },
1828
- children: [/*#__PURE__*/jsx("div", {
1829
- className: style['add-block-option-icon'],
1830
- children: opt.icon
1831
- }), /*#__PURE__*/jsxs("div", {
1832
- className: style['add-block-option-text'],
1833
- children: [/*#__PURE__*/jsx("div", {
1834
- className: style['add-block-option-title'],
1835
- children: formatMessage({
1836
- id: `blockKind_${opt.key}`
1837
- })
1838
- }), /*#__PURE__*/jsx("div", {
1839
- className: style['add-block-option-desc'],
1840
- children: definition == null ? void 0 : definition.description
1841
- })]
1842
- })]
1843
- }, opt.key);
1844
- })
2735
+ dropdownRender: () => renderAddBlockMenu(ROOT_ADD_OPTIONS, {
2736
+ onSelect: kind => {
2737
+ onAddBlock(kind);
2738
+ setAddMenuOpen(false);
2739
+ }
1845
2740
  }),
1846
2741
  children: /*#__PURE__*/jsx(Button, {
1847
2742
  type: "primary",
@@ -1871,91 +2766,7 @@ const BlockListPanel = ({
1871
2766
  })
1872
2767
  }) : /*#__PURE__*/jsx("div", {
1873
2768
  className: style['block-list'],
1874
- children: blocks.map((block, blockIndex) => {
1875
- var _block$items2, _block$list;
1876
- const definition = getBlockDefinition(block.kind);
1877
- const canAddField = block.kind !== 'steps' && block.kind !== 'multiField';
1878
- const summary = block.kind === 'steps' ? formatMessage({
1879
- id: 'stepCount'
1880
- }, {
1881
- count: ((_block$items2 = block.items) == null ? void 0 : _block$items2.length) || 0
1882
- }) : block.kind === 'multiField' ? formatMessage({
1883
- id: 'multiFieldSummary'
1884
- }, {
1885
- type: block.fieldType
1886
- }) : formatMessage({
1887
- id: 'fieldCount'
1888
- }, {
1889
- count: ((_block$list = block.list) == null ? void 0 : _block$list.length) || 0
1890
- });
1891
- return /*#__PURE__*/jsxs("section", {
1892
- className: `${style['block-section']} ${style[`block-kind-${block.kind}`] || ''}`.trim(),
1893
- children: [/*#__PURE__*/jsxs("header", {
1894
- className: style['block-section-header'],
1895
- children: [/*#__PURE__*/jsxs("div", {
1896
- className: style['block-header-left'],
1897
- children: [/*#__PURE__*/jsx(Tag, {
1898
- bordered: false,
1899
- color: (definition == null ? void 0 : definition.color) || 'default',
1900
- children: (definition == null ? void 0 : definition.label) || block.kind
1901
- }), /*#__PURE__*/jsx(Text$3, {
1902
- strong: true,
1903
- ellipsis: true,
1904
- className: style['block-title'],
1905
- children: block.title || block.label || block.name || formatMessage({
1906
- id: 'untitledBlock'
1907
- })
1908
- }), /*#__PURE__*/jsx("span", {
1909
- className: style['block-summary'],
1910
- children: summary
1911
- })]
1912
- }), /*#__PURE__*/jsxs(Space, {
1913
- size: 4,
1914
- wrap: true,
1915
- className: style['block-header-actions'],
1916
- children: [/*#__PURE__*/jsxs(ActionGroup, {
1917
- children: [/*#__PURE__*/jsx(IconBtn, {
1918
- title: formatMessage({
1919
- id: 'moveUp'
1920
- }),
1921
- icon: /*#__PURE__*/jsx(ArrowUpOutlined, {}),
1922
- disabled: blockIndex === 0,
1923
- onClick: () => onMoveBlock(block.id, 'up')
1924
- }), /*#__PURE__*/jsx(IconBtn, {
1925
- title: formatMessage({
1926
- id: 'moveDown'
1927
- }),
1928
- icon: /*#__PURE__*/jsx(ArrowDownOutlined, {}),
1929
- disabled: blockIndex === blocks.length - 1,
1930
- onClick: () => onMoveBlock(block.id, 'down')
1931
- }), /*#__PURE__*/jsx(IconBtn, {
1932
- title: formatMessage({
1933
- id: 'editBlock'
1934
- }),
1935
- icon: /*#__PURE__*/jsx(SettingOutlined, {}),
1936
- onClick: () => onEditBlock(block)
1937
- }), /*#__PURE__*/jsx(IconBtn, {
1938
- title: formatMessage({
1939
- id: 'deleteBlock'
1940
- }),
1941
- danger: true,
1942
- icon: /*#__PURE__*/jsx(DeleteOutlined, {}),
1943
- onClick: () => onDeleteBlock(block.id)
1944
- })]
1945
- }), canAddField ? /*#__PURE__*/jsx(Button, {
1946
- type: "text",
1947
- size: "small",
1948
- icon: /*#__PURE__*/jsx(PlusOutlined, {}),
1949
- className: `${style['add-inline-btn']} ${style['hover-reveal']}`,
1950
- onClick: () => onAddField(block.id),
1951
- children: formatMessage({
1952
- id: 'addField'
1953
- })
1954
- }) : null]
1955
- })]
1956
- }), renderBlockChildren(block)]
1957
- }, block.id);
1958
- })
2769
+ children: blocks.map((block, blockIndex) => renderBlockSection(block, blockIndex, blocks.length, 0))
1959
2770
  })]
1960
2771
  });
1961
2772
  };
@@ -1970,7 +2781,7 @@ const BlockConfigFields = ({
1970
2781
  const definition = getBlockDefinition(kind);
1971
2782
  const fieldTypeOptions = useMemo(() => getFieldTypes(), []);
1972
2783
  const list = [];
1973
- if (kind === 'formInfo' || kind === 'list' || kind === 'tableList') {
2784
+ if (kind === 'formInfo' || kind === 'list' || kind === 'tableList' || kind === 'object') {
1974
2785
  list.push(/*#__PURE__*/jsx(Input, {
1975
2786
  name: "title",
1976
2787
  label: formatMessage({
@@ -2003,7 +2814,7 @@ const BlockConfigFields = ({
2003
2814
  }),
2004
2815
  min: 1,
2005
2816
  max: 4
2006
- }, "column"), kind === 'formInfo' ? /*#__PURE__*/jsx(InputNumber, {
2817
+ }, "column"), kind === 'formInfo' || kind === 'object' ? /*#__PURE__*/jsx(InputNumber, {
2007
2818
  name: "gap",
2008
2819
  label: formatMessage({
2009
2820
  id: 'blockGap'
@@ -2020,7 +2831,7 @@ const BlockConfigFields = ({
2020
2831
  children: formatMessage({
2021
2832
  id: 'blockImportant'
2022
2833
  })
2023
- }, "important") : null, kind !== 'formInfo' ? /*#__PURE__*/jsx(Input, {
2834
+ }, "important") : null, kind === 'list' || kind === 'tableList' ? /*#__PURE__*/jsx(Input, {
2024
2835
  name: "addText",
2025
2836
  label: formatMessage({
2026
2837
  id: 'blockAddText'
@@ -2028,13 +2839,13 @@ const BlockConfigFields = ({
2028
2839
  placeholder: formatMessage({
2029
2840
  id: 'blockAddTextPlaceholder'
2030
2841
  })
2031
- }, "addText") : null, kind !== 'formInfo' ? /*#__PURE__*/jsx(InputNumber, {
2842
+ }, "addText") : null, kind === 'list' || kind === 'tableList' ? /*#__PURE__*/jsx(InputNumber, {
2032
2843
  name: "maxLength",
2033
2844
  label: formatMessage({
2034
2845
  id: 'blockMaxLength'
2035
2846
  }),
2036
2847
  min: 1
2037
- }, "maxLength") : null, kind !== 'formInfo' ? /*#__PURE__*/jsx(InputNumber, {
2848
+ }, "maxLength") : null, kind === 'list' || kind === 'tableList' ? /*#__PURE__*/jsx(InputNumber, {
2038
2849
  name: "minLength",
2039
2850
  label: formatMessage({
2040
2851
  id: 'blockMinLength'
@@ -2042,6 +2853,77 @@ const BlockConfigFields = ({
2042
2853
  min: 0
2043
2854
  }, "minLength") : null);
2044
2855
  }
2856
+ if (kind === 'choice') {
2857
+ list.push(/*#__PURE__*/jsx(Input, {
2858
+ name: "title",
2859
+ label: formatMessage({
2860
+ id: 'blockTitle'
2861
+ }),
2862
+ placeholder: formatMessage({
2863
+ id: 'choiceTitlePlaceholder'
2864
+ })
2865
+ }, "title"), /*#__PURE__*/jsx(Select, {
2866
+ name: "mode",
2867
+ label: formatMessage({
2868
+ id: 'choiceMode'
2869
+ }),
2870
+ rule: "REQ",
2871
+ options: [{
2872
+ label: formatMessage({
2873
+ id: 'choiceModeSingle'
2874
+ }),
2875
+ value: 'single'
2876
+ }, {
2877
+ label: formatMessage({
2878
+ id: 'choiceModeMultiple'
2879
+ }),
2880
+ value: 'multiple'
2881
+ }]
2882
+ }, "mode"), /*#__PURE__*/jsx(InputNumber, {
2883
+ name: "minLength",
2884
+ label: formatMessage({
2885
+ id: 'choiceMinSelect'
2886
+ }),
2887
+ min: 0,
2888
+ placeholder: formatMessage({
2889
+ id: 'propOptionalNumber'
2890
+ }),
2891
+ display: ({
2892
+ openApi
2893
+ }) => {
2894
+ var _openApi$data;
2895
+ return (openApi == null || (_openApi$data = openApi.data) == null ? void 0 : _openApi$data.mode) === 'multiple';
2896
+ }
2897
+ }, "minLength"), /*#__PURE__*/jsx(InputNumber, {
2898
+ name: "maxLength",
2899
+ label: formatMessage({
2900
+ id: 'choiceMaxSelect'
2901
+ }),
2902
+ min: 1,
2903
+ placeholder: formatMessage({
2904
+ id: 'propOptionalNumber'
2905
+ }),
2906
+ display: ({
2907
+ openApi
2908
+ }) => {
2909
+ var _openApi$data2;
2910
+ return (openApi == null || (_openApi$data2 = openApi.data) == null ? void 0 : _openApi$data2.mode) === 'multiple';
2911
+ }
2912
+ }, "maxLength"), /*#__PURE__*/jsx(Input, {
2913
+ name: "selectorName",
2914
+ label: formatMessage({
2915
+ id: 'choiceSelectorName'
2916
+ }),
2917
+ placeholder: formatMessage({
2918
+ id: 'choiceSelectorNamePlaceholder'
2919
+ })
2920
+ }, "selectorName"), /*#__PURE__*/jsx(Checkbox, {
2921
+ name: "selectorInData",
2922
+ children: formatMessage({
2923
+ id: 'choiceSelectorInData'
2924
+ })
2925
+ }, "selectorInData"));
2926
+ }
2045
2927
  if (kind === 'multiField') {
2046
2928
  list.push(/*#__PURE__*/jsx(Input, {
2047
2929
  name: "name",
@@ -2131,7 +3013,7 @@ const BlockEditorModal = ({
2131
3013
  const isEdit = !!(block != null && block.id);
2132
3014
  const formData = useMemo(() => blockToFormValues(block || createBlock('formInfo')), [block, open]);
2133
3015
  const handleSubmit = async values => {
2134
- if (((block == null ? void 0 : block.kind) === 'list' || (block == null ? void 0 : block.kind) === 'tableList' || (block == null ? void 0 : block.kind) === 'multiField') && !values.name) {
3016
+ if (((block == null ? void 0 : block.kind) === 'list' || (block == null ? void 0 : block.kind) === 'tableList' || (block == null ? void 0 : block.kind) === 'multiField' || (block == null ? void 0 : block.kind) === 'object') && !values.name) {
2135
3017
  message.error(formatMessage({
2136
3018
  id: 'blockNameRequired'
2137
3019
  }));
@@ -2164,13 +3046,73 @@ const BlockEditorModal = ({
2164
3046
  children: /*#__PURE__*/jsx(BlockConfigFields, {
2165
3047
  kind: (block == null ? void 0 : block.kind) || 'formInfo'
2166
3048
  })
2167
- }), open ? block != null && block.id ? `edit-${block.id}` : `add-${(block == null ? void 0 : block.kind) || 'formInfo'}-${formData.name || 'new'}` : 'closed');
3049
+ }), open ? block != null && block.id ? `edit-${block.id}` : `add-${(block == null ? void 0 : block.kind) || 'formInfo'}-${formData.name || 'new'}` : 'closed');
3050
+ };
3051
+ var BlockEditorModal$1 = BlockEditorModal;
3052
+
3053
+ const StepEditorModal = ({
3054
+ open,
3055
+ step,
3056
+ onCancel,
3057
+ onSave,
3058
+ renderModal
3059
+ }) => {
3060
+ const {
3061
+ formatMessage
3062
+ } = useIntl();
3063
+ const isMobile = useIsMobile();
3064
+ const formData = useMemo(() => stepToFormValues(step || createStep()), [step, open]);
3065
+ return /*#__PURE__*/jsx(FormModal, _extends({
3066
+ destroyOnHidden: true,
3067
+ destroyOnClose: true,
3068
+ title: formatMessage({
3069
+ id: step != null && step.id ? 'editStep' : 'addStep'
3070
+ }),
3071
+ open: open,
3072
+ onCancel: onCancel,
3073
+ width: isMobile ? 'calc(100vw - 32px)' : 560
3074
+ }, renderModal ? {
3075
+ renderModal
3076
+ } : {}, {
3077
+ formProps: {
3078
+ data: formData,
3079
+ onSubmit: values => {
3080
+ onSave(formValuesToStep(values, step || createStep()));
3081
+ }
3082
+ },
3083
+ okText: formatMessage({
3084
+ id: 'confirm'
3085
+ }),
3086
+ cancelText: formatMessage({
3087
+ id: 'cancel'
3088
+ }),
3089
+ children: /*#__PURE__*/jsx(FormInfo, {
3090
+ column: 1,
3091
+ list: [/*#__PURE__*/jsx(Input, {
3092
+ name: "title",
3093
+ label: formatMessage({
3094
+ id: 'stepTitle'
3095
+ }),
3096
+ rule: "REQ",
3097
+ placeholder: formatMessage({
3098
+ id: 'stepTitlePlaceholder'
3099
+ })
3100
+ }, "title"), /*#__PURE__*/jsx(InputNumber, {
3101
+ name: "column",
3102
+ label: formatMessage({
3103
+ id: 'formColumnPlaceholder'
3104
+ }),
3105
+ min: 1,
3106
+ max: 4
3107
+ }, "column")]
3108
+ })
3109
+ }), open ? step != null && step.id ? `edit-${step.id}` : `add-step-${formData.title || 'new'}` : 'closed');
2168
3110
  };
2169
- var BlockEditorModal$1 = BlockEditorModal;
3111
+ var StepEditorModal$1 = StepEditorModal;
2170
3112
 
2171
- const StepEditorModal = ({
3113
+ const ChoiceOptionEditorModal = ({
2172
3114
  open,
2173
- step,
3115
+ option,
2174
3116
  onCancel,
2175
3117
  onSave,
2176
3118
  renderModal
@@ -2179,12 +3121,12 @@ const StepEditorModal = ({
2179
3121
  formatMessage
2180
3122
  } = useIntl();
2181
3123
  const isMobile = useIsMobile();
2182
- const formData = useMemo(() => stepToFormValues(step || createStep()), [step, open]);
3124
+ const formData = useMemo(() => choiceOptionToFormValues(option || createChoiceOption()), [option, open]);
2183
3125
  return /*#__PURE__*/jsx(FormModal, _extends({
2184
3126
  destroyOnHidden: true,
2185
3127
  destroyOnClose: true,
2186
3128
  title: formatMessage({
2187
- id: step != null && step.id ? 'editStep' : 'addStep'
3129
+ id: option != null && option.id ? 'editChoiceOption' : 'addChoiceOption'
2188
3130
  }),
2189
3131
  open: open,
2190
3132
  onCancel: onCancel,
@@ -2195,7 +3137,7 @@ const StepEditorModal = ({
2195
3137
  formProps: {
2196
3138
  data: formData,
2197
3139
  onSubmit: values => {
2198
- onSave(formValuesToStep(values, step || createStep()));
3140
+ onSave(formValuesToChoiceOption(values, option || createChoiceOption()));
2199
3141
  }
2200
3142
  },
2201
3143
  okText: formatMessage({
@@ -2209,24 +3151,17 @@ const StepEditorModal = ({
2209
3151
  list: [/*#__PURE__*/jsx(Input, {
2210
3152
  name: "title",
2211
3153
  label: formatMessage({
2212
- id: 'stepTitle'
3154
+ id: 'choiceOptionTitle'
2213
3155
  }),
2214
3156
  rule: "REQ",
2215
3157
  placeholder: formatMessage({
2216
- id: 'stepTitlePlaceholder'
3158
+ id: 'choiceOptionTitlePlaceholder'
2217
3159
  })
2218
- }, "title"), /*#__PURE__*/jsx(InputNumber, {
2219
- name: "column",
2220
- label: formatMessage({
2221
- id: 'formColumnPlaceholder'
2222
- }),
2223
- min: 1,
2224
- max: 4
2225
- }, "column")]
3160
+ }, "title")]
2226
3161
  })
2227
- }), open ? step != null && step.id ? `edit-${step.id}` : `add-step-${formData.title || 'new'}` : 'closed');
3162
+ }), open ? option != null && option.id ? `edit-option-${option.id}` : `add-option-${formData.title || 'new'}` : 'closed');
2228
3163
  };
2229
- var StepEditorModal$1 = StepEditorModal;
3164
+ var ChoiceOptionEditorModal$1 = ChoiceOptionEditorModal;
2230
3165
 
2231
3166
  const {
2232
3167
  Text: Text$2
@@ -3212,7 +4147,7 @@ const hasFieldPropsEditor = (type, definition) => {
3212
4147
  };
3213
4148
  var FieldPropsEditor$1 = FieldPropsEditor;
3214
4149
 
3215
- const _excluded = ["columns"];
4150
+ const _excluded$1 = ["columns"];
3216
4151
  const {
3217
4152
  Text
3218
4153
  } = Typography;
@@ -3228,7 +4163,7 @@ const getDefaultSelectProps = () => ({
3228
4163
  columns: [createEmptyColumn()]
3229
4164
  });
3230
4165
  const omitColumns = (_ref = {}) => {
3231
- let rest = _objectWithoutPropertiesLoose(_ref, _excluded);
4166
+ let rest = _objectWithoutPropertiesLoose(_ref, _excluded$1);
3232
4167
  return rest;
3233
4168
  };
3234
4169
  const FieldConfigFields = ({
@@ -3646,6 +4581,270 @@ const FormActionsEditor = ({
3646
4581
  };
3647
4582
  var FormActionsEditor$1 = FormActionsEditor;
3648
4583
 
4584
+ const getByPath = (obj, path) => {
4585
+ if (obj == null || path == null || path === '') {
4586
+ return undefined;
4587
+ }
4588
+ return String(path).split('.').reduce((current, key) => current == null ? undefined : current[key], obj);
4589
+ };
4590
+ const resolveSelectorName = block => {
4591
+ var _block$discriminator;
4592
+ if (block.selectorName != null && String(block.selectorName).trim()) {
4593
+ return String(block.selectorName).trim();
4594
+ }
4595
+ if ((_block$discriminator = block.discriminator) != null && _block$discriminator.propertyName) {
4596
+ return String(block.discriminator.propertyName).trim();
4597
+ }
4598
+ return `__choice_${block.id}`;
4599
+ };
4600
+ const resolveSelectedIds = (value, mode) => {
4601
+ if (mode === 'multiple') {
4602
+ if (Array.isArray(value)) {
4603
+ return value.map(String);
4604
+ }
4605
+ if (value == null || value === '') {
4606
+ return [];
4607
+ }
4608
+ return [String(value)];
4609
+ }
4610
+ if (value == null || value === '') {
4611
+ return [];
4612
+ }
4613
+ return [String(value)];
4614
+ };
4615
+ const clearUnselectedOptionFields = (openApi, keepIds, allOptions) => {
4616
+ if (!(openApi != null && openApi.setFields)) {
4617
+ return;
4618
+ }
4619
+ const entries = [];
4620
+ allOptions.forEach(option => {
4621
+ if (keepIds.includes(String(option.id))) {
4622
+ return;
4623
+ }
4624
+ (option.list || []).forEach(field => {
4625
+ if (field != null && field.name) {
4626
+ entries.push({
4627
+ name: field.name,
4628
+ value: undefined
4629
+ });
4630
+ }
4631
+ });
4632
+ collectBlockFieldNames(option.blocks || []).forEach(name => {
4633
+ entries.push({
4634
+ name,
4635
+ value: undefined
4636
+ });
4637
+ });
4638
+ });
4639
+ if (!entries.length) {
4640
+ return;
4641
+ }
4642
+ openApi.setFields(entries, {
4643
+ runValidate: false
4644
+ });
4645
+ };
4646
+ const resolveSelectLimits = block => {
4647
+ const minLength = Number.isFinite(Number(block.minLength)) ? Math.max(0, Math.floor(Number(block.minLength))) : undefined;
4648
+ let maxLength = Number.isFinite(Number(block.maxLength)) ? Math.max(1, Math.floor(Number(block.maxLength))) : undefined;
4649
+ if (minLength != null && maxLength != null && maxLength < minLength) {
4650
+ maxLength = minLength;
4651
+ }
4652
+ return {
4653
+ minLength,
4654
+ maxLength
4655
+ };
4656
+ };
4657
+ const buildMultipleHint = (formatMessage, minLength, maxLength) => {
4658
+ if (minLength != null && maxLength != null) {
4659
+ return formatMessage ? formatMessage({
4660
+ id: 'choiceModeHintMultipleRange'
4661
+ }, {
4662
+ min: minLength,
4663
+ max: maxLength
4664
+ }) : `请选择 ${minLength}–${maxLength} 项`;
4665
+ }
4666
+ if (minLength != null) {
4667
+ return formatMessage ? formatMessage({
4668
+ id: 'choiceModeHintMultipleMin'
4669
+ }, {
4670
+ count: minLength
4671
+ }) : `请至少选择 ${minLength} 项`;
4672
+ }
4673
+ if (maxLength != null) {
4674
+ return formatMessage ? formatMessage({
4675
+ id: 'choiceModeHintMultipleMax'
4676
+ }, {
4677
+ count: maxLength
4678
+ }) : `最多选择 ${maxLength} 项`;
4679
+ }
4680
+ return formatMessage ? formatMessage({
4681
+ id: 'choiceModeHintMultiple'
4682
+ }) : '可以选择多项';
4683
+ };
4684
+
4685
+ /**
4686
+ * choice:同一条选项 UI;mode=single 只挂载一支;mode=multiple 平铺所有选中支。
4687
+ * 外层用 InfoPage.Part 的 title 展示标题。
4688
+ */
4689
+ const ChoiceBlock = ({
4690
+ block,
4691
+ preview: _preview = false,
4692
+ isMobile: _isMobile = false,
4693
+ formatMessage,
4694
+ renderOptionContent
4695
+ }) => {
4696
+ const mode = block.mode === 'multiple' ? 'multiple' : 'single';
4697
+ const selectorName = resolveSelectorName(block);
4698
+ const options = useMemo(() => block.options || [], [block.options]);
4699
+ const {
4700
+ formData,
4701
+ openApi
4702
+ } = useFormContext() || {};
4703
+ const titleText = block.title != null ? String(block.title).trim() : '';
4704
+ const title = titleText || (formatMessage ? formatMessage({
4705
+ id: 'choiceAreaTitle'
4706
+ }) : '请选择');
4707
+ const bordered = _isMobile ? false : block.bordered || undefined;
4708
+ const {
4709
+ minLength,
4710
+ maxLength
4711
+ } = mode === 'multiple' ? resolveSelectLimits(block) : {};
4712
+ const firstOptionId = options[0] != null ? String(options[0].id) : undefined;
4713
+
4714
+ // 单选且未选时,写入第一项,保证预览/提交与选项面板一致
4715
+ useEffect(() => {
4716
+ if (mode !== 'single' || !firstOptionId || !(openApi != null && openApi.setFields)) {
4717
+ return;
4718
+ }
4719
+ const current = getByPath(formData || {}, selectorName);
4720
+ if (current != null && current !== '') {
4721
+ return;
4722
+ }
4723
+ openApi.setFields([{
4724
+ name: selectorName,
4725
+ value: firstOptionId
4726
+ }], {
4727
+ runValidate: false
4728
+ });
4729
+ }, [mode, firstOptionId, selectorName, openApi, formData]);
4730
+ const selectorOptions = useMemo(() => {
4731
+ const rawValue = getByPath(formData || {}, selectorName);
4732
+ const selectedIds = resolveSelectedIds(rawValue, mode);
4733
+ const atMax = mode === 'multiple' && maxLength != null && selectedIds.length >= maxLength;
4734
+ return options.map((option, index) => {
4735
+ const value = String(option.id);
4736
+ return {
4737
+ label: option.title || (formatMessage ? formatMessage({
4738
+ id: 'choiceOptionFallback'
4739
+ }, {
4740
+ index: index + 1
4741
+ }) : `选项${index + 1}`),
4742
+ value,
4743
+ disabled: atMax && !selectedIds.includes(value)
4744
+ };
4745
+ });
4746
+ }, [options, formatMessage, formData, selectorName, mode, maxLength]);
4747
+ const rawValue = getByPath(formData || {}, selectorName);
4748
+ let selectedIds = resolveSelectedIds(rawValue, mode);
4749
+ if (mode === 'single' && !selectedIds.length && firstOptionId) {
4750
+ selectedIds = [firstOptionId];
4751
+ }
4752
+ const activeOptions = options.filter(option => selectedIds.includes(String(option.id)));
4753
+ const handleChange = value => {
4754
+ let nextIds = resolveSelectedIds(value, mode);
4755
+ if (mode === 'multiple' && maxLength != null && nextIds.length > maxLength) {
4756
+ nextIds = nextIds.slice(0, maxLength);
4757
+ openApi == null || openApi.setFields == null || openApi.setFields([{
4758
+ name: selectorName,
4759
+ value: nextIds
4760
+ }], {
4761
+ runValidate: false
4762
+ });
4763
+ }
4764
+ clearUnselectedOptionFields(openApi, nextIds, options);
4765
+ };
4766
+ const selectorRule = mode === 'multiple' && (minLength != null || maxLength != null) ? value => {
4767
+ const ids = resolveSelectedIds(value, 'multiple');
4768
+ if (minLength != null && ids.length < minLength) {
4769
+ return {
4770
+ result: false,
4771
+ errMsg: formatMessage ? formatMessage({
4772
+ id: 'choiceMinSelectError'
4773
+ }, {
4774
+ count: minLength
4775
+ }) : `请至少选择 ${minLength} 项`
4776
+ };
4777
+ }
4778
+ if (maxLength != null && ids.length > maxLength) {
4779
+ return {
4780
+ result: false,
4781
+ errMsg: formatMessage ? formatMessage({
4782
+ id: 'choiceMaxSelectError'
4783
+ }, {
4784
+ count: maxLength
4785
+ }) : `最多只能选择 ${maxLength} 项`
4786
+ };
4787
+ }
4788
+ return {
4789
+ result: true,
4790
+ errMsg: ''
4791
+ };
4792
+ } : undefined;
4793
+ const Selector = mode === 'multiple' ? CheckboxGroup : RadioGroup;
4794
+ const selectorProps = _extends({
4795
+ key: 'choice-selector',
4796
+ name: selectorName,
4797
+ label: titleText || (formatMessage ? formatMessage({
4798
+ id: 'choiceAreaTitle'
4799
+ }) : '请选择'),
4800
+ labelHidden: true,
4801
+ options: selectorOptions,
4802
+ onChange: handleChange
4803
+ }, selectorRule ? {
4804
+ rule: selectorRule
4805
+ } : {}, mode === 'single' ? _extends({
4806
+ optionType: 'button',
4807
+ buttonStyle: 'solid'
4808
+ }, firstOptionId ? {
4809
+ defaultValue: firstOptionId
4810
+ } : {}) : {});
4811
+ const contentChildren = [];
4812
+ activeOptions.forEach(option => {
4813
+ const nodes = (typeof renderOptionContent === 'function' ? renderOptionContent(option, {
4814
+ preview: _preview,
4815
+ isMobile: _isMobile,
4816
+ formatMessage
4817
+ }) : []) || [];
4818
+ if (nodes.length) {
4819
+ contentChildren.push(/*#__PURE__*/createElement('div', {
4820
+ key: option.id,
4821
+ className: style['choice-option-panel']
4822
+ }, mode === 'multiple' && option.title ? /*#__PURE__*/createElement('div', {
4823
+ className: style['choice-option-panel-title']
4824
+ }, option.title) : null, ...nodes));
4825
+ }
4826
+ });
4827
+ const modeHint = mode === 'multiple' ? buildMultipleHint(formatMessage, minLength, maxLength) : formatMessage ? formatMessage({
4828
+ id: 'choiceModeHintSingle'
4829
+ }) : '请选择其中一项';
4830
+ return /*#__PURE__*/createElement(InfoPage.Part, {
4831
+ title,
4832
+ subtitle: modeHint,
4833
+ bordered,
4834
+ className: style['choice-block'],
4835
+ 'data-choice-mode': mode
4836
+ }, /*#__PURE__*/createElement('div', {
4837
+ className: style['choice-selector']
4838
+ }, /*#__PURE__*/createElement(Selector, selectorProps)), contentChildren.length ? /*#__PURE__*/createElement('div', {
4839
+ className: style['choice-panels']
4840
+ }, ...contentChildren) : /*#__PURE__*/createElement('div', {
4841
+ className: style['choice-panels-empty']
4842
+ }, formatMessage ? formatMessage({
4843
+ id: 'choiceSelectFirstHint'
4844
+ }) : '请先在上方选择'));
4845
+ };
4846
+ var ChoiceBlock$1 = ChoiceBlock;
4847
+
3649
4848
  const buildLabelTips = tips => {
3650
4849
  if (tips == null || !String(tips).trim()) {
3651
4850
  return undefined;
@@ -3656,7 +4855,9 @@ const buildLabelTips = tips => {
3656
4855
  className: style['field-label-tips-icon']
3657
4856
  }));
3658
4857
  };
3659
- const renderFieldElements = (fields = [], preview = false) => fields.filter(field => !field.hidden).map(field => {
4858
+ const renderFieldElements = (fields = [], preview = false, {
4859
+ namePrefix
4860
+ } = {}) => fields.filter(field => !field.hidden).map(field => {
3660
4861
  var _props$options;
3661
4862
  const Component = getFieldComponent(field.type, field);
3662
4863
  if (!Component) {
@@ -3667,18 +4868,15 @@ const renderFieldElements = (fields = [], preview = false) => fields.filter(fiel
3667
4868
  if (definition != null && definition.optionsAllowDescription && (_props$options = props.options) != null && _props$options.length && !props.api && !definition.optionsAllowChildren) {
3668
4869
  props.api = createApiFromOptions(props.options);
3669
4870
  }
3670
-
3671
- // 空字符串会盖掉 react-form-antd / SuperSelect 的默认「请输入/请选择」占位
3672
4871
  if (!Array.isArray(props.placeholder) && props.placeholder != null && !String(props.placeholder).trim()) {
3673
4872
  delete props.placeholder;
3674
4873
  }
3675
-
3676
- // schema 内部标记,不传给 antd
3677
4874
  delete props.range;
3678
4875
  const description = field.description != null && String(field.description).trim() ? field.description : undefined;
4876
+ const fieldName = namePrefix && field.name ? `${namePrefix}.${field.name}` : field.name;
3679
4877
  return /*#__PURE__*/createElement(Component, _extends({
3680
4878
  key: field.id,
3681
- name: field.name,
4879
+ name: fieldName,
3682
4880
  label: field.label,
3683
4881
  rule: field.rule || undefined,
3684
4882
  block: field.block || undefined
@@ -3687,59 +4885,122 @@ const renderFieldElements = (fields = [], preview = false) => fields.filter(fiel
3687
4885
  description
3688
4886
  }));
3689
4887
  }).filter(Boolean);
3690
- const renderBlockElement = (block, preview = false, {
3691
- isMobile: _isMobile = false,
3692
- formatMessage
3693
- } = {}) => {
3694
- const fields = renderFieldElements(block.list, preview);
3695
- const bordered = _isMobile ? false : block.bordered || undefined;
4888
+ const withBlockLayout = (element, forceBlock) => {
4889
+ if (!element || !forceBlock) {
4890
+ return element;
4891
+ }
4892
+ return /*#__PURE__*/createElement(element.type, _extends({}, element.props, {
4893
+ key: element.key,
4894
+ block: true
4895
+ }));
4896
+ };
4897
+
4898
+ /** 列表子项内嵌的 FormInfo / List:表头圆角、去掉底边,压过 antd Card CSS-in-JS */
4899
+ const nestedListItemPartProps = {
4900
+ styles: {
4901
+ header: {
4902
+ borderBottom: 'none',
4903
+ borderRadius: 'var(--radius-default, 8px) var(--radius-default, 8px) 0 0'
4904
+ }
4905
+ },
4906
+ style: {
4907
+ borderRadius: 'var(--radius-default, 8px)',
4908
+ overflow: 'hidden'
4909
+ }
4910
+ };
4911
+ const renderBlockElement = (block, preview = false, ctx = {}) => {
4912
+ const {
4913
+ isMobile = false,
4914
+ formatMessage,
4915
+ depth = 0,
4916
+ asListItem = false
4917
+ } = ctx;
4918
+ if (!block || depth > MAX_BLOCK_DEPTH) {
4919
+ return null;
4920
+ }
4921
+ const nextCtx = _extends({}, ctx, {
4922
+ depth: depth + 1,
4923
+ asListItem: false
4924
+ });
4925
+ const bordered = isMobile ? false : block.bordered || undefined;
4926
+ const listItemPartProps = asListItem ? nestedListItemPartProps : null;
4927
+ const renderChildBlocks = (blocks = [], childCtx = nextCtx) => (blocks || []).map(child => renderBlockElement(child, preview, childCtx)).filter(Boolean);
3696
4928
  switch (block.kind) {
3697
4929
  case 'formInfo':
3698
- return /*#__PURE__*/createElement(FormInfo, {
3699
- key: block.id,
3700
- title: block.title || undefined,
3701
- subtitle: block.subtitle || undefined,
3702
- column: block.column,
3703
- gap: block.gap,
3704
- bordered,
3705
- list: fields
3706
- });
4930
+ {
4931
+ const fields = renderFieldElements(block.list, preview);
4932
+ const nested = renderChildBlocks(block.blocks || [], nextCtx).map(node => withBlockLayout(node, true));
4933
+ return withBlockLayout(/*#__PURE__*/createElement(FormInfo, _extends({
4934
+ key: block.id,
4935
+ title: block.title || undefined,
4936
+ subtitle: block.subtitle || undefined,
4937
+ column: block.column,
4938
+ gap: block.gap,
4939
+ bordered,
4940
+ list: [...fields, ...nested]
4941
+ }, listItemPartProps || {})), asListItem);
4942
+ }
4943
+ case 'object':
4944
+ {
4945
+ const fields = renderFieldElements(block.list, preview, {
4946
+ namePrefix: block.name || ''
4947
+ });
4948
+ const nested = renderChildBlocks(block.blocks || [], nextCtx).map(node => withBlockLayout(node, true));
4949
+ return withBlockLayout(/*#__PURE__*/createElement(FormInfo, _extends({
4950
+ key: block.id,
4951
+ title: block.title || undefined,
4952
+ subtitle: block.subtitle || undefined,
4953
+ column: block.column,
4954
+ gap: block.gap,
4955
+ bordered,
4956
+ list: [...fields, ...nested]
4957
+ }, listItemPartProps || {})), asListItem);
4958
+ }
3707
4959
  case 'list':
3708
- return /*#__PURE__*/createElement(List, _extends({
3709
- key: block.id,
3710
- name: block.name,
3711
- title: block.title || undefined,
3712
- important: block.important || undefined,
3713
- bordered,
3714
- maxLength: block.maxLength,
3715
- minLength: block.minLength
3716
- }, block.addText ? {
3717
- addText: block.addText
3718
- } : {}, typeof block.itemTitle === 'function' || block.itemTitle ? {
3719
- itemTitle: block.itemTitle
3720
- } : {}, {
3721
- list: fields
3722
- }));
4960
+ {
4961
+ const fields = renderFieldElements(block.list, preview);
4962
+ const nested = renderChildBlocks(block.itemBlocks || [], _extends({}, nextCtx, {
4963
+ asListItem: true
4964
+ })).map(node => withBlockLayout(node, true));
4965
+ return withBlockLayout(/*#__PURE__*/createElement(List, _extends({
4966
+ key: block.id,
4967
+ name: block.name,
4968
+ title: block.title || undefined,
4969
+ important: block.important || undefined,
4970
+ bordered,
4971
+ maxLength: block.maxLength,
4972
+ minLength: block.minLength
4973
+ }, block.addText ? {
4974
+ addText: block.addText
4975
+ } : {}, typeof block.itemTitle === 'function' || block.itemTitle ? {
4976
+ itemTitle: block.itemTitle
4977
+ } : {}, {
4978
+ list: [...fields, ...nested]
4979
+ }, listItemPartProps || {})), asListItem);
4980
+ }
3723
4981
  case 'tableList':
3724
- return /*#__PURE__*/createElement(TableList, _extends({
3725
- key: block.id,
3726
- name: block.name,
3727
- title: block.title || undefined,
3728
- bordered,
3729
- maxLength: block.maxLength,
3730
- minLength: block.minLength
3731
- }, block.addText ? {
3732
- addText: block.addText
3733
- } : {}, {
3734
- list: fields
3735
- }));
4982
+ {
4983
+ const fields = renderFieldElements(block.list, preview);
4984
+ return withBlockLayout(/*#__PURE__*/createElement(TableList, _extends({
4985
+ key: block.id,
4986
+ name: block.name,
4987
+ title: block.title || undefined,
4988
+ bordered,
4989
+ maxLength: block.maxLength,
4990
+ minLength: block.minLength
4991
+ }, block.addText ? {
4992
+ addText: block.addText
4993
+ } : {}, {
4994
+ list: fields
4995
+ }, listItemPartProps || {})), asListItem);
4996
+ }
3736
4997
  case 'multiField':
3737
4998
  {
3738
4999
  const FieldComponent = getFieldComponent(block.fieldType);
3739
5000
  if (!FieldComponent) {
3740
5001
  return null;
3741
5002
  }
3742
- return /*#__PURE__*/createElement(MultiField, _extends({
5003
+ return withBlockLayout(/*#__PURE__*/createElement(MultiField, _extends({
3743
5004
  key: block.id,
3744
5005
  name: block.name,
3745
5006
  label: block.label,
@@ -3747,26 +5008,70 @@ const renderBlockElement = (block, preview = false, {
3747
5008
  block: block.block || undefined
3748
5009
  }, block.addText ? {
3749
5010
  addText: block.addText
3750
- } : {}));
5011
+ } : {})), asListItem);
3751
5012
  }
3752
5013
  case 'steps':
3753
5014
  {
3754
- const _bordered = _isMobile ? false : block.bordered || undefined;
3755
- return /*#__PURE__*/createElement(Steps, {
5015
+ return withBlockLayout(/*#__PURE__*/createElement(Steps, {
3756
5016
  key: block.id,
3757
5017
  title: block.title || undefined,
3758
5018
  subtitle: block.subtitle || undefined,
3759
- bordered: _bordered,
3760
- items: (block.items || []).map(step => ({
3761
- key: step.id,
3762
- title: step.title,
3763
- column: step.column,
3764
- gap: block.gap,
3765
- list: renderFieldElements(step.list, preview),
3766
- fieldNames: (step.list || []).filter(field => field && !field.hidden && field.name).map(field => field.name)
3767
- }))
3768
- });
5019
+ bordered,
5020
+ prevIcon: /*#__PURE__*/createElement(ArrowLeftOutlined),
5021
+ nextIcon: /*#__PURE__*/createElement(ArrowRightOutlined),
5022
+ items: (block.items || []).map(step => {
5023
+ const fields = renderFieldElements(step.list, preview);
5024
+ const nested = renderChildBlocks(step.blocks || [], nextCtx);
5025
+ const fieldNames = [...(step.list || []).filter(field => field && !field.hidden && field.name).map(field => field.name), ...collectBlockFieldNames(step.blocks || [])];
5026
+ if (nested.length) {
5027
+ return {
5028
+ key: step.id,
5029
+ title: step.title,
5030
+ column: step.column,
5031
+ gap: block.gap,
5032
+ fieldNames,
5033
+ children: /*#__PURE__*/createElement(Fragment, {
5034
+ key: `${step.id}-body`
5035
+ }, fields.length ? /*#__PURE__*/createElement(FormInfo, {
5036
+ key: `${step.id}-fields`,
5037
+ column: step.column,
5038
+ gap: block.gap,
5039
+ list: fields
5040
+ }) : null, ...nested)
5041
+ };
5042
+ }
5043
+ return {
5044
+ key: step.id,
5045
+ title: step.title,
5046
+ column: step.column,
5047
+ gap: block.gap,
5048
+ list: fields,
5049
+ fieldNames
5050
+ };
5051
+ })
5052
+ }), asListItem);
3769
5053
  }
5054
+ case 'choice':
5055
+ return withBlockLayout(/*#__PURE__*/createElement(ChoiceBlock$1, {
5056
+ key: block.id,
5057
+ block,
5058
+ preview,
5059
+ isMobile,
5060
+ formatMessage,
5061
+ renderOptionContent: option => {
5062
+ const nodes = [];
5063
+ if ((option.list || []).length) {
5064
+ nodes.push(/*#__PURE__*/createElement(FormInfo, {
5065
+ key: `${option.id}-fields`,
5066
+ column: block.column || 2,
5067
+ gap: block.gap,
5068
+ list: renderFieldElements(option.list, preview)
5069
+ }));
5070
+ }
5071
+ nodes.push(...renderChildBlocks(option.blocks || [], nextCtx));
5072
+ return nodes.filter(Boolean);
5073
+ }
5074
+ }), asListItem);
3770
5075
  default:
3771
5076
  return null;
3772
5077
  }
@@ -3774,7 +5079,7 @@ const renderBlockElement = (block, preview = false, {
3774
5079
  const renderSchemaInner = (schema, {
3775
5080
  preview: _preview = false,
3776
5081
  className,
3777
- isMobile: _isMobile2 = false,
5082
+ isMobile: _isMobile = false,
3778
5083
  formatMessage,
3779
5084
  children,
3780
5085
  actionNode
@@ -3782,7 +5087,7 @@ const renderSchemaInner = (schema, {
3782
5087
  const normalized = normalizeSchema(schema);
3783
5088
  const blocks = normalized.blocks || [];
3784
5089
  const contentChildren = blocks.map(block => renderBlockElement(block, _preview, {
3785
- isMobile: _isMobile2,
5090
+ isMobile: _isMobile,
3786
5091
  formatMessage
3787
5092
  })).filter(Boolean);
3788
5093
  if (!contentChildren.length && !children && !actionNode) {
@@ -3797,7 +5102,7 @@ const renderSchemaContent = (schema, {
3797
5102
  preview: _preview2 = false,
3798
5103
  formProps: _formProps = {},
3799
5104
  className,
3800
- isMobile: _isMobile3 = false,
5105
+ isMobile: _isMobile2 = false,
3801
5106
  formatMessage,
3802
5107
  children,
3803
5108
  actionNode
@@ -3805,7 +5110,7 @@ const renderSchemaContent = (schema, {
3805
5110
  const normalized = normalizeSchema(schema);
3806
5111
  const blocks = normalized.blocks || [];
3807
5112
  const contentChildren = blocks.map(block => renderBlockElement(block, _preview2, {
3808
- isMobile: _isMobile3,
5113
+ isMobile: _isMobile2,
3809
5114
  formatMessage
3810
5115
  })).filter(Boolean);
3811
5116
  if (!contentChildren.length && !children) {
@@ -4007,8 +5312,13 @@ const FormCreator = withLocale$1(({
4007
5312
  const [innerSchema, setInnerSchema] = useState(() => normalizeSchema(defaultValue || defaultSchema()));
4008
5313
  const [blockEditorOpen, setBlockEditorOpen] = useState(false);
4009
5314
  const [editingBlock, setEditingBlock] = useState(null);
5315
+ const [blockParentId, setBlockParentId] = useState(null);
5316
+ const [blockParentStepId, setBlockParentStepId] = useState(null);
5317
+ const [blockParentOptionId, setBlockParentOptionId] = useState(null);
4010
5318
  const [stepEditorOpen, setStepEditorOpen] = useState(false);
4011
5319
  const [stepContext, setStepContext] = useState(null);
5320
+ const [choiceOptionEditorOpen, setChoiceOptionEditorOpen] = useState(false);
5321
+ const [choiceOptionContext, setChoiceOptionContext] = useState(null);
4012
5322
  const [fieldEditorOpen, setFieldEditorOpen] = useState(false);
4013
5323
  const [fieldContext, setFieldContext] = useState(null);
4014
5324
  const [editingField, setEditingField] = useState(null);
@@ -4021,31 +5331,70 @@ const FormCreator = withLocale$1(({
4021
5331
  }
4022
5332
  onChange == null || onChange(normalized);
4023
5333
  };
4024
- const handleAddBlock = kind => {
5334
+ const clearBlockEditor = () => {
5335
+ setBlockEditorOpen(false);
5336
+ setEditingBlock(null);
5337
+ setBlockParentId(null);
5338
+ setBlockParentStepId(null);
5339
+ setBlockParentOptionId(null);
5340
+ };
5341
+ const handleAddBlock = (kind, {
5342
+ parentBlockId,
5343
+ stepId,
5344
+ optionId
5345
+ } = {}) => {
4025
5346
  setEditingBlock(createBlock(kind));
5347
+ setBlockParentId(parentBlockId || null);
5348
+ setBlockParentStepId(stepId || null);
5349
+ setBlockParentOptionId(optionId || null);
4026
5350
  setBlockEditorOpen(true);
4027
5351
  };
4028
5352
  const handleEditBlock = block => {
4029
5353
  setEditingBlock(block);
5354
+ setBlockParentId(null);
5355
+ setBlockParentStepId(null);
5356
+ setBlockParentOptionId(null);
4030
5357
  setBlockEditorOpen(true);
4031
5358
  };
4032
5359
  const handleSaveBlock = block => {
4033
- const exists = schema.blocks.some(item => item.id === block.id);
4034
- updateSchema(_extends({}, schema, {
4035
- blocks: exists ? schema.blocks.map(item => item.id === block.id ? block : item) : [...schema.blocks, block]
4036
- }));
4037
- setBlockEditorOpen(false);
4038
- setEditingBlock(null);
5360
+ const exists = !!findBlock(schema, block.id);
5361
+ if (exists) {
5362
+ updateSchema(mapBlocks(schema, block.id, () => block));
5363
+ } else if (blockParentId && blockParentStepId) {
5364
+ updateSchema(mapBlocks(schema, blockParentId, parent => _extends({}, parent, {
5365
+ items: (parent.items || []).map(step => step.id === blockParentStepId ? _extends({}, step, {
5366
+ blocks: [...(step.blocks || []), block]
5367
+ }) : step)
5368
+ })));
5369
+ } else if (blockParentId && blockParentOptionId) {
5370
+ updateSchema(mapBlocks(schema, blockParentId, parent => _extends({}, parent, {
5371
+ options: (parent.options || []).map(option => option.id === blockParentOptionId ? _extends({}, option, {
5372
+ blocks: [...(option.blocks || []), block]
5373
+ }) : option)
5374
+ })));
5375
+ } else if (blockParentId) {
5376
+ updateSchema(mapBlocks(schema, blockParentId, parent => {
5377
+ if (parent.kind === 'list') {
5378
+ return _extends({}, parent, {
5379
+ itemBlocks: [...(parent.itemBlocks || []), block]
5380
+ });
5381
+ }
5382
+ return _extends({}, parent, {
5383
+ blocks: [...(parent.blocks || []), block]
5384
+ });
5385
+ }));
5386
+ } else {
5387
+ updateSchema(_extends({}, schema, {
5388
+ blocks: [...schema.blocks, block]
5389
+ }));
5390
+ }
5391
+ clearBlockEditor();
4039
5392
  };
4040
5393
  const handleDeleteBlock = blockId => {
4041
- updateSchema(_extends({}, schema, {
4042
- blocks: schema.blocks.filter(item => item.id !== blockId)
4043
- }));
5394
+ updateSchema(updateBlocks(schema, blocks => removeBlockInTree(blocks, blockId)));
4044
5395
  };
4045
5396
  const handleMoveBlock = (blockId, direction) => {
4046
- updateSchema(_extends({}, schema, {
4047
- blocks: moveItem(schema.blocks, blockId, direction)
4048
- }));
5397
+ updateSchema(updateBlocks(schema, blocks => moveBlockInTree(blocks, blockId, direction)));
4049
5398
  };
4050
5399
  const handleAddStep = blockId => {
4051
5400
  setStepContext({
@@ -4084,27 +5433,71 @@ const FormCreator = withLocale$1(({
4084
5433
  items: moveItem(block.items || [], stepId, direction)
4085
5434
  })));
4086
5435
  };
4087
- const handleAddField = (blockId, stepId) => {
4088
- setFieldContext({
5436
+ const handleAddChoiceOption = blockId => {
5437
+ setChoiceOptionContext({
4089
5438
  blockId,
4090
- stepId
5439
+ option: createChoiceOption()
4091
5440
  });
4092
- setEditingField(null);
4093
- setFieldEditorOpen(true);
5441
+ setChoiceOptionEditorOpen(true);
4094
5442
  };
4095
- const handleEditField = (blockId, field, stepId) => {
4096
- setFieldContext({
5443
+ const handleEditChoiceOption = (blockId, option) => {
5444
+ setChoiceOptionContext({
4097
5445
  blockId,
4098
- stepId
5446
+ option
4099
5447
  });
5448
+ setChoiceOptionEditorOpen(true);
5449
+ };
5450
+ const handleSaveChoiceOption = option => {
5451
+ const {
5452
+ blockId
5453
+ } = choiceOptionContext;
5454
+ updateSchema(mapBlocks(schema, blockId, block => {
5455
+ const exists = (block.options || []).some(item => item.id === option.id);
5456
+ return _extends({}, block, {
5457
+ options: exists ? block.options.map(item => item.id === option.id ? option : item) : [...(block.options || []), option]
5458
+ });
5459
+ }));
5460
+ setChoiceOptionEditorOpen(false);
5461
+ setChoiceOptionContext(null);
5462
+ };
5463
+ const handleDeleteChoiceOption = (blockId, optionId) => {
5464
+ updateSchema(mapBlocks(schema, blockId, block => _extends({}, block, {
5465
+ options: (block.options || []).filter(item => item.id !== optionId)
5466
+ })));
5467
+ };
5468
+ const handleMoveChoiceOption = (blockId, optionId, direction) => {
5469
+ updateSchema(mapBlocks(schema, blockId, block => _extends({}, block, {
5470
+ options: moveItem(block.options || [], optionId, direction)
5471
+ })));
5472
+ };
5473
+ const normalizeFieldScope = scope => {
5474
+ if (typeof scope === 'string' || scope == null) {
5475
+ return {
5476
+ stepId: scope
5477
+ };
5478
+ }
5479
+ return scope;
5480
+ };
5481
+ const handleAddField = (blockId, scope) => {
5482
+ setFieldContext(_extends({
5483
+ blockId
5484
+ }, normalizeFieldScope(scope)));
5485
+ setEditingField(null);
5486
+ setFieldEditorOpen(true);
5487
+ };
5488
+ const handleEditField = (blockId, field, scope) => {
5489
+ setFieldContext(_extends({
5490
+ blockId
5491
+ }, normalizeFieldScope(scope)));
4100
5492
  setEditingField(field);
4101
5493
  setFieldEditorOpen(true);
4102
5494
  };
4103
5495
  const handleSaveField = field => {
4104
5496
  const {
4105
5497
  blockId,
4106
- stepId
4107
- } = fieldContext;
5498
+ stepId,
5499
+ optionId
5500
+ } = fieldContext || {};
4108
5501
  updateSchema(mapBlocks(schema, blockId, block => {
4109
5502
  if (block.kind === 'steps') {
4110
5503
  return _extends({}, block, {
@@ -4119,6 +5512,19 @@ const FormCreator = withLocale$1(({
4119
5512
  })
4120
5513
  });
4121
5514
  }
5515
+ if (block.kind === 'choice') {
5516
+ return _extends({}, block, {
5517
+ options: (block.options || []).map(option => {
5518
+ if (option.id !== optionId) {
5519
+ return option;
5520
+ }
5521
+ const exists = (option.list || []).some(item => item.id === field.id);
5522
+ return _extends({}, option, {
5523
+ list: exists ? option.list.map(item => item.id === field.id ? field : item) : [...(option.list || []), field]
5524
+ });
5525
+ })
5526
+ });
5527
+ }
4122
5528
  const exists = (block.list || []).some(item => item.id === field.id);
4123
5529
  return _extends({}, block, {
4124
5530
  list: exists ? block.list.map(item => item.id === field.id ? field : item) : [...(block.list || []), field]
@@ -4128,7 +5534,11 @@ const FormCreator = withLocale$1(({
4128
5534
  setFieldContext(null);
4129
5535
  setEditingField(null);
4130
5536
  };
4131
- const handleDeleteField = (blockId, fieldId, stepId) => {
5537
+ const handleDeleteField = (blockId, fieldId, scope) => {
5538
+ const {
5539
+ stepId,
5540
+ optionId
5541
+ } = normalizeFieldScope(scope);
4132
5542
  updateSchema(mapBlocks(schema, blockId, block => {
4133
5543
  if (block.kind === 'steps') {
4134
5544
  return _extends({}, block, {
@@ -4137,12 +5547,23 @@ const FormCreator = withLocale$1(({
4137
5547
  }) : step)
4138
5548
  });
4139
5549
  }
5550
+ if (block.kind === 'choice') {
5551
+ return _extends({}, block, {
5552
+ options: (block.options || []).map(option => option.id === optionId ? _extends({}, option, {
5553
+ list: (option.list || []).filter(item => item.id !== fieldId)
5554
+ }) : option)
5555
+ });
5556
+ }
4140
5557
  return _extends({}, block, {
4141
5558
  list: (block.list || []).filter(item => item.id !== fieldId)
4142
5559
  });
4143
5560
  }));
4144
5561
  };
4145
- const handleMoveField = (blockId, fieldId, direction, stepId) => {
5562
+ const handleMoveField = (blockId, fieldId, direction, scope) => {
5563
+ const {
5564
+ stepId,
5565
+ optionId
5566
+ } = normalizeFieldScope(scope);
4146
5567
  updateSchema(mapBlocks(schema, blockId, block => {
4147
5568
  if (block.kind === 'steps') {
4148
5569
  return _extends({}, block, {
@@ -4151,6 +5572,13 @@ const FormCreator = withLocale$1(({
4151
5572
  }) : step)
4152
5573
  });
4153
5574
  }
5575
+ if (block.kind === 'choice') {
5576
+ return _extends({}, block, {
5577
+ options: (block.options || []).map(option => option.id === optionId ? _extends({}, option, {
5578
+ list: moveItem(option.list || [], fieldId, direction)
5579
+ }) : option)
5580
+ });
5581
+ }
4154
5582
  return _extends({}, block, {
4155
5583
  list: moveItem(block.list || [], fieldId, direction)
4156
5584
  });
@@ -4158,7 +5586,8 @@ const FormCreator = withLocale$1(({
4158
5586
  };
4159
5587
  const currentFieldScope = fieldContext ? collectSchemaFields(schema, {
4160
5588
  blockId: fieldContext.blockId,
4161
- stepId: fieldContext.stepId
5589
+ stepId: fieldContext.stepId,
5590
+ optionId: fieldContext.optionId
4162
5591
  }) : [];
4163
5592
  return /*#__PURE__*/jsxs("div", {
4164
5593
  className: [style['form-creator'], RESPONSIVE_BOUNDARY_CLASS, isMobile ? style['is-mobile'] : '', className].filter(Boolean).join(' '),
@@ -4178,6 +5607,10 @@ const FormCreator = withLocale$1(({
4178
5607
  onEditStep: handleEditStep,
4179
5608
  onDeleteStep: handleDeleteStep,
4180
5609
  onMoveStep: handleMoveStep,
5610
+ onAddChoiceOption: handleAddChoiceOption,
5611
+ onEditChoiceOption: handleEditChoiceOption,
5612
+ onDeleteChoiceOption: handleDeleteChoiceOption,
5613
+ onMoveChoiceOption: handleMoveChoiceOption,
4181
5614
  onOpenFormActions: () => setFormActionsOpen(true)
4182
5615
  })
4183
5616
  }), _showPreview ? /*#__PURE__*/jsx("div", {
@@ -4199,10 +5632,7 @@ const FormCreator = withLocale$1(({
4199
5632
  open: blockEditorOpen,
4200
5633
  block: editingBlock,
4201
5634
  renderModal: renderModal,
4202
- onCancel: () => {
4203
- setBlockEditorOpen(false);
4204
- setEditingBlock(null);
4205
- },
5635
+ onCancel: clearBlockEditor,
4206
5636
  onSave: handleSaveBlock
4207
5637
  }), /*#__PURE__*/jsx(StepEditorModal$1, {
4208
5638
  open: stepEditorOpen,
@@ -4213,6 +5643,15 @@ const FormCreator = withLocale$1(({
4213
5643
  setStepContext(null);
4214
5644
  },
4215
5645
  onSave: handleSaveStep
5646
+ }), /*#__PURE__*/jsx(ChoiceOptionEditorModal$1, {
5647
+ open: choiceOptionEditorOpen,
5648
+ option: choiceOptionContext == null ? void 0 : choiceOptionContext.option,
5649
+ renderModal: renderModal,
5650
+ onCancel: () => {
5651
+ setChoiceOptionEditorOpen(false);
5652
+ setChoiceOptionContext(null);
5653
+ },
5654
+ onSave: handleSaveChoiceOption
4216
5655
  }), /*#__PURE__*/jsx(FieldEditorModal$1, {
4217
5656
  open: fieldEditorOpen,
4218
5657
  field: editingField,
@@ -4240,5 +5679,53 @@ const FormCreator = withLocale$1(({
4240
5679
  });
4241
5680
  var FormCreator$1 = FormCreator;
4242
5681
 
4243
- export { FormCreator$1 as FormCreator, RULE_LEN_PRESET, RULE_PRESET_ITEMS, SchemaRenderer$1 as SchemaRenderer, SchemaRendererInner, applyFromPropsSchema, blockToFormValues, buildRuleString, collectSchemaFields, createBlock, createField$1 as createField, createFieldId, createStep, FormCreator$1 as default, defaultFormActions, defaultSchema, fieldToFormValues, findBlock, formValuesToBlock, formValuesToField, getBlockDefinition, getBlockKindOptions, getFieldComponent, getFieldDefinition, getFieldTypes, getRulePresetItems, hasRenderableContent, isFieldNameUnique, mapBlocks, moveItem, normalizeBlock, normalizeFormActions, normalizeOptions, normalizeSchema, parseRuleString, pickFieldProps, pickFromPropsSchema, registerField, registerRulePreset, updateBlocks };
5682
+ const _excluded = ["label", "validator"];
5683
+
5684
+ /**
5685
+ * 统一注册扩展规则与填写项:运行时校验 + 编辑器规则面板 + 字段类型 registry。
5686
+ * 应用入口调用一次即可,FormCreator / SchemaRenderer 共用。
5687
+ */
5688
+ const preset = ({
5689
+ rules: _rules = {},
5690
+ fields: _fields = {}
5691
+ } = {}) => {
5692
+ const runtimeRules = _extends({}, RULES);
5693
+ Object.entries(_rules).forEach(([value, def]) => {
5694
+ if (def == null) {
5695
+ return;
5696
+ }
5697
+ if (typeof def === 'function') {
5698
+ registerRulePreset({
5699
+ value,
5700
+ label: value
5701
+ });
5702
+ runtimeRules[value] = def;
5703
+ return;
5704
+ }
5705
+ const {
5706
+ label,
5707
+ validator
5708
+ } = def,
5709
+ ruleBody = _objectWithoutPropertiesLoose(def, _excluded);
5710
+ if (label) {
5711
+ registerRulePreset({
5712
+ value,
5713
+ label
5714
+ });
5715
+ }
5716
+ if (typeof validator === 'function') {
5717
+ runtimeRules[value] = validator;
5718
+ } else if (Object.keys(ruleBody).length) {
5719
+ runtimeRules[value] = ruleBody;
5720
+ }
5721
+ });
5722
+ preset$1({
5723
+ rules: runtimeRules
5724
+ });
5725
+ Object.entries(_fields).forEach(([type, definition]) => {
5726
+ registerField(type, definition);
5727
+ });
5728
+ };
5729
+
5730
+ export { FormCreator$1 as FormCreator, MAX_BLOCK_DEPTH, RULE_LEN_PRESET, RULE_PRESET_ITEMS, SchemaRenderer$1 as SchemaRenderer, SchemaRendererInner, applyFromPropsSchema, blockToFormValues, buildRuleString, collectBlockFieldNames, collectSchemaFields, createBlock, createChoiceOption, createField$1 as createField, createFieldId, createStep, FormCreator$1 as default, defaultFormActions, defaultSchema, fieldToFormValues, findBlock, findBlockInTree, formValuesToBlock, formValuesToField, getBlockDefinition, getBlockKindOptions, getFieldComponent, getFieldDefinition, getFieldTypes, getRulePresetItems, hasRenderableContent, isFieldNameUnique, mapBlocks, moveBlockInTree, moveItem, normalizeBlock, normalizeFormActions, normalizeOptions, normalizeSchema, parseRuleString, pickFieldProps, pickFromPropsSchema, preset, removeBlockInTree, updateBlocks };
4244
5731
  //# sourceMappingURL=index.modern.js.map