@xbeeant/form-engine-designer 0.0.2 → 0.0.4

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.
Files changed (137) hide show
  1. package/dist/es/Canvas.js +42 -46
  2. package/dist/es/Canvas.js.map +1 -1
  3. package/dist/es/Designer.js +121 -98
  4. package/dist/es/Designer.js.map +1 -1
  5. package/dist/es/DesignerContext.js +86 -73
  6. package/dist/es/DesignerContext.js.map +1 -1
  7. package/dist/es/Palette.js +3 -3
  8. package/dist/es/Palette.js.map +1 -1
  9. package/dist/es/PropertyPanel.js +97 -97
  10. package/dist/es/PropertyPanel.js.map +1 -1
  11. package/dist/es/catalog.js +19 -11
  12. package/dist/es/catalog.js.map +1 -1
  13. package/dist/es/designer-context.js +110 -0
  14. package/dist/es/designer-context.js.map +1 -0
  15. package/dist/es/history.js +73 -0
  16. package/dist/es/history.js.map +1 -0
  17. package/dist/es/index.js +3 -3
  18. package/dist/es/property/basic-property.js +6 -0
  19. package/dist/es/property/basic-property.js.map +1 -1
  20. package/dist/es/property-panel.js +294 -0
  21. package/dist/es/property-panel.js.map +1 -0
  22. package/dist/es/resizable-panel.js +103 -0
  23. package/dist/es/resizable-panel.js.map +1 -0
  24. package/dist/es/schema-utils.js +286 -0
  25. package/dist/es/schema-utils.js.map +1 -0
  26. package/dist/es/widgets/BindEditor.js +60 -49
  27. package/dist/es/widgets/BindEditor.js.map +1 -1
  28. package/dist/es/widgets/CodeEditor.js +41 -49
  29. package/dist/es/widgets/CodeEditor.js.map +1 -1
  30. package/dist/es/widgets/DefaultEditor.js +25 -30
  31. package/dist/es/widgets/DefaultEditor.js.map +1 -1
  32. package/dist/es/widgets/DependenciesEditor.js +21 -21
  33. package/dist/es/widgets/DependenciesEditor.js.map +1 -1
  34. package/dist/es/widgets/EnumEditor.js +25 -31
  35. package/dist/es/widgets/EnumEditor.js.map +1 -1
  36. package/dist/es/widgets/ExpressionSwitch.js +32 -30
  37. package/dist/es/widgets/ExpressionSwitch.js.map +1 -1
  38. package/dist/es/widgets/ReactionsEditor.js +103 -103
  39. package/dist/es/widgets/ReactionsEditor.js.map +1 -1
  40. package/dist/es/widgets/RemoteDataEditor.js +63 -63
  41. package/dist/es/widgets/RemoteDataEditor.js.map +1 -1
  42. package/dist/es/widgets/ValidateEditor.js +49 -49
  43. package/dist/es/widgets/ValidateEditor.js.map +1 -1
  44. package/dist/es/widgets/bind-editor.js +78 -0
  45. package/dist/es/widgets/bind-editor.js.map +1 -0
  46. package/dist/es/widgets/code-editor.js +76 -0
  47. package/dist/es/widgets/code-editor.js.map +1 -0
  48. package/dist/es/widgets/default-editor.js +50 -0
  49. package/dist/es/widgets/default-editor.js.map +1 -0
  50. package/dist/es/widgets/dependencies-editor.js +36 -0
  51. package/dist/es/widgets/dependencies-editor.js.map +1 -0
  52. package/dist/es/widgets/enum-editor.js +43 -0
  53. package/dist/es/widgets/enum-editor.js.map +1 -0
  54. package/dist/es/widgets/expression-builder.js +367 -0
  55. package/dist/es/widgets/expression-builder.js.map +1 -0
  56. package/dist/es/widgets/expression-model.js +340 -0
  57. package/dist/es/widgets/expression-model.js.map +1 -0
  58. package/dist/es/widgets/expression-switch.js +49 -0
  59. package/dist/es/widgets/expression-switch.js.map +1 -0
  60. package/dist/es/widgets/index.js +13 -13
  61. package/dist/es/widgets/index.js.map +1 -1
  62. package/dist/es/widgets/options-editor.js +102 -0
  63. package/dist/es/widgets/options-editor.js.map +1 -0
  64. package/dist/es/widgets/reactions-editor.js +401 -0
  65. package/dist/es/widgets/reactions-editor.js.map +1 -0
  66. package/dist/es/widgets/reactions-model.js +107 -0
  67. package/dist/es/widgets/reactions-model.js.map +1 -0
  68. package/dist/es/widgets/remote-data-editor.js +314 -0
  69. package/dist/es/widgets/remote-data-editor.js.map +1 -0
  70. package/dist/es/widgets/use-form-data-fields.js +16 -0
  71. package/dist/es/widgets/use-form-data-fields.js.map +1 -0
  72. package/dist/es/widgets/validate-editor.js +118 -0
  73. package/dist/es/widgets/validate-editor.js.map +1 -0
  74. package/package.json +4 -5
  75. package/dist/es/react/src/components/FormController.js +0 -154
  76. package/dist/es/react/src/components/FormController.js.map +0 -1
  77. package/dist/es/react/src/components/NexusField.js +0 -99
  78. package/dist/es/react/src/components/NexusField.js.map +0 -1
  79. package/dist/es/react/src/components/NexusForm.js +0 -121
  80. package/dist/es/react/src/components/NexusForm.js.map +0 -1
  81. package/dist/es/react/src/components/NexusFormProvider.js +0 -19
  82. package/dist/es/react/src/components/NexusFormProvider.js.map +0 -1
  83. package/dist/es/react/src/components/NexusLayout.js +0 -49
  84. package/dist/es/react/src/components/NexusLayout.js.map +0 -1
  85. package/dist/es/react/src/components/NexusObject.js +0 -65
  86. package/dist/es/react/src/components/NexusObject.js.map +0 -1
  87. package/dist/es/react/src/contexts/FieldInheritContext.js +0 -6
  88. package/dist/es/react/src/contexts/FieldInheritContext.js.map +0 -1
  89. package/dist/es/react/src/contexts/GridContext.js +0 -6
  90. package/dist/es/react/src/contexts/GridContext.js.map +0 -1
  91. package/dist/es/react/src/contexts/LayoutConfigContext.js +0 -6
  92. package/dist/es/react/src/contexts/LayoutConfigContext.js.map +0 -1
  93. package/dist/es/react/src/contexts/NexusContext.js +0 -13
  94. package/dist/es/react/src/contexts/NexusContext.js.map +0 -1
  95. package/dist/es/react/src/hooks/useForm.js +0 -10
  96. package/dist/es/react/src/hooks/useForm.js.map +0 -1
  97. package/dist/es/react/src/utils/renderTreeNode.js +0 -18
  98. package/dist/es/react/src/utils/renderTreeNode.js.map +0 -1
  99. package/dist/es/react/src/utils/resolveColSpan.js +0 -10
  100. package/dist/es/react/src/utils/resolveColSpan.js.map +0 -1
  101. package/dist/es/schemaUtils.test.js +0 -188
  102. package/dist/es/schemaUtils.test.js.map +0 -1
  103. package/dist/es/vite-env.d.js +0 -2
  104. package/dist/es/vite-env.d.js.map +0 -1
  105. package/dist/es/widgets/expressionModel.test.js +0 -193
  106. package/dist/es/widgets/expressionModel.test.js.map +0 -1
  107. package/src/Canvas.tsx +0 -1111
  108. package/src/Designer.css +0 -206
  109. package/src/Designer.tsx +0 -254
  110. package/src/DesignerContext.tsx +0 -192
  111. package/src/Palette.tsx +0 -261
  112. package/src/PropertyPanel.tsx +0 -486
  113. package/src/ResizablePanel.tsx +0 -210
  114. package/src/catalog.ts +0 -526
  115. package/src/index.ts +0 -25
  116. package/src/property/basic-property.ts +0 -126
  117. package/src/schemaUtils.test.ts +0 -261
  118. package/src/schemaUtils.ts +0 -627
  119. package/src/types.ts +0 -38
  120. package/src/vite-env.d.ts +0 -1
  121. package/src/widgets/BindEditor.tsx +0 -105
  122. package/src/widgets/CodeEditor.tsx +0 -114
  123. package/src/widgets/DefaultEditor.tsx +0 -73
  124. package/src/widgets/DependenciesEditor.tsx +0 -56
  125. package/src/widgets/EnumEditor.tsx +0 -66
  126. package/src/widgets/ExpressionBuilder.tsx +0 -509
  127. package/src/widgets/ExpressionSwitch.tsx +0 -62
  128. package/src/widgets/OptionsEditor.tsx +0 -141
  129. package/src/widgets/ReactionsEditor.tsx +0 -532
  130. package/src/widgets/RemoteDataEditor.tsx +0 -382
  131. package/src/widgets/ValidateEditor.tsx +0 -162
  132. package/src/widgets/expressionModel.test.ts +0 -262
  133. package/src/widgets/expressionModel.ts +0 -573
  134. package/src/widgets/index.ts +0 -45
  135. package/src/widgets/reactionsModel.ts +0 -190
  136. package/src/widgets/useFormDataFields.ts +0 -21
  137. /package/dist/es/{form-engine-designer.css → index.css} +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"Palette.js","sources":["../../src/Palette.tsx"],"sourcesContent":["// ============================================================================\n// @xbeeant/form-engine-designer — 左侧组件目录面板\n// ============================================================================\n\nimport type { SchemaNode } from '@xbeeant/form-engine';\nimport { Collapse, Input } from 'antd';\nimport type { DragEvent } from 'react';\nimport { useCallback, useMemo, useState } from 'react';\nimport { useDesigner } from './DesignerContext';\nimport {\n generateKey,\n getNodeAtProperties,\n getPropertiesOf,\n} from './schemaUtils';\nimport type { CatalogItem, FieldDef } from './types';\n\n// 拖拽负载:palette 组件目录项 or 外部字段定义\nexport interface PaletteDragPayload {\n source: 'palette';\n catalogItem: CatalogItem;\n}\nexport interface FieldDefDragPayload {\n source: 'fieldDef';\n fieldDef: FieldDef;\n}\nexport type PaletteDragData = PaletteDragPayload | FieldDefDragPayload;\n\n// 面板类型 → 允许的唯一父容器类型(面板不能直接添加到根或普通容器)\nconst PANE_PARENT_TYPE: Record<string, string> = {\n tabPane: 'tabs',\n collapsePanel: 'collapse',\n step: 'steps',\n};\n\nconst isPaneItem = (item: CatalogItem): boolean =>\n item.category === 'layout' && !!PANE_PARENT_TYPE[item.layoutType ?? ''];\n\nfunction PaletteItem({\n item,\n onAdd,\n}: {\n item: CatalogItem;\n onAdd: (item: CatalogItem) => void;\n}) {\n const handleDragStart = (e: DragEvent<HTMLDivElement>) => {\n const payload: PaletteDragPayload = {\n source: 'palette',\n catalogItem: item,\n };\n e.dataTransfer.setData('application/json', JSON.stringify(payload));\n e.dataTransfer.effectAllowed = 'copy';\n };\n\n // 面板类组件只能放入对应容器,点击/拖拽提示差异化\n const paneParent = isPaneItem(item)\n ? PANE_PARENT_TYPE[item.layoutType ?? '']\n : undefined;\n const title = paneParent\n ? `拖拽「${item.label}」到「${paneParent}」容器中,或选中容器后点击`\n : `点击添加或拖拽「${item.label}」到画布`;\n\n return (\n <div\n className='group flex flex-col items-center gap-1 rounded-lg border border-[#f0f0f0] bg-white px-1 py-2 cursor-grab select-none transition-all hover:-translate-y-px hover:border-[#1677ff] hover:shadow-[0_2px_8px_rgba(22,119,255,0.12)] active:cursor-grabbing'\n draggable\n onDragStart={handleDragStart}\n onClick={() => onAdd(item)}\n title={title}\n >\n <span className='flex h-7 w-7 items-center justify-center rounded-md bg-[#f5f7fa] text-[15px] transition-colors group-hover:bg-[#e8f1ff]'>\n {item.icon}\n </span>\n <span className='w-full truncate text-center text-xs text-[#666] transition-colors group-hover:text-[#1677ff]'>\n {item.label}\n </span>\n </div>\n );\n}\n\nfunction FieldDefItem({ field }: { field: FieldDef }) {\n const handleDragStart = (e: DragEvent<HTMLDivElement>) => {\n const payload: FieldDefDragPayload = {\n source: 'fieldDef',\n fieldDef: field,\n };\n e.dataTransfer.setData('application/json', JSON.stringify(payload));\n e.dataTransfer.effectAllowed = 'copy';\n };\n\n return (\n <div\n className='flex items-center gap-2 rounded-lg border border-[#f0f0f0] bg-white px-2 py-1.5 cursor-grab select-none transition-all hover:-translate-y-px hover:border-[#1677ff] hover:shadow-[0_2px_8px_rgba(22,119,255,0.12)] active:cursor-grabbing'\n draggable\n onDragStart={handleDragStart}\n title={`id: ${field.id} · widget: ${field.widget}`}\n >\n <span className='flex h-6 w-6 flex-shrink-0 items-center justify-center rounded-md bg-[#f5f7fa] text-[13px]'>\n 🔧\n </span>\n <span className='truncate text-xs text-[#666]'>{field.name}</span>\n </div>\n );\n}\n\nexport function Palette() {\n const {\n schema,\n selectedPath,\n addNode,\n fields,\n widgetCatalog,\n layoutCatalog,\n } = useDesigner();\n const [keyword, setKeyword] = useState('');\n\n const handleAdd = useCallback(\n (item: CatalogItem) => {\n const base = item.widget || item.layoutType || 'field';\n // 面板类组件只能放入对应容器:点击时若已选中匹配容器则加入,否则忽略\n const paneParentType = isPaneItem(item)\n ? PANE_PARENT_TYPE[item.layoutType ?? '']\n : undefined;\n if (paneParentType) {\n if (!selectedPath || selectedPath.length === 0) {\n return;\n }\n const parent = getNodeAtProperties(schema.properties, selectedPath);\n if (!parent || parent.type !== paneParentType) {\n return;\n }\n const parentProps = getPropertiesOf(parent);\n if (!parentProps) {\n return;\n }\n const key = generateKey(parentProps, base);\n addNode(selectedPath, key, item.createNode() as unknown as SchemaNode);\n return;\n }\n const key = generateKey(schema.properties, base);\n const node = item.createNode() as unknown as SchemaNode;\n addNode([], key, node);\n },\n [schema, addNode, selectedPath],\n );\n\n const kw = keyword.trim().toLowerCase();\n\n const widgetItems = useMemo(\n () =>\n widgetCatalog\n .filter((item) => item.label.toLowerCase().includes(kw))\n .map((item) => (\n <PaletteItem key={item.widget} item={item} onAdd={handleAdd} />\n )),\n [widgetCatalog, kw, handleAdd],\n );\n\n const layoutItems = useMemo(\n () =>\n layoutCatalog\n .filter((item) => item.label.toLowerCase().includes(kw))\n .map((item) => (\n <PaletteItem key={item.layoutType} item={item} onAdd={handleAdd} />\n )),\n [layoutCatalog, kw, handleAdd],\n );\n\n const fieldItems = useMemo(\n () =>\n (fields ?? [])\n .filter((field) => field.name.toLowerCase().includes(kw))\n .map((field) => <FieldDefItem key={field.id} field={field} />),\n [fields, kw],\n );\n\n const sectionGrid = (items: React.ReactNode[], hasMore: boolean) =>\n items.length > 0 ? (\n <div className='grid grid-cols-2 gap-1.5 px-1 pb-2'>{items}</div>\n ) : (\n <div className='py-3 text-center text-xs text-[#c0c4cc]'>\n {hasMore ? '无匹配组件' : '暂无组件'}\n </div>\n );\n\n const collapseItems = [\n {\n key: 'widgets',\n label: (\n <span className='flex w-full items-center justify-between pr-1'>\n <span>表单组件</span>\n <span className='rounded-full bg-[#f0f0f0] px-1.5 py-px text-[11px] text-[#999]'>\n {widgetItems.length}\n </span>\n </span>\n ),\n children: sectionGrid(widgetItems, true),\n },\n {\n key: 'layouts',\n label: (\n <span className='flex w-full items-center justify-between pr-1'>\n <span>布局组件</span>\n <span className='rounded-full bg-[#f0f0f0] px-1.5 py-px text-[11px] text-[#999]'>\n {layoutItems.length}\n </span>\n </span>\n ),\n children: sectionGrid(layoutItems, true),\n },\n ];\n\n // 仅当传入 fields 时显示「字段列表」分组\n if (fields && fields.length > 0) {\n collapseItems.push({\n key: 'fieldList',\n label: (\n <span className='flex w-full items-center justify-between pr-1'>\n <span>字段列表</span>\n <span className='rounded-full bg-[#f0f0f0] px-1.5 py-px text-[11px] text-[#999]'>\n {fieldItems.length}\n </span>\n </span>\n ),\n children: (\n <div className='flex flex-col gap-1.5 px-1 pb-2'>\n {fieldItems.length > 0 ? (\n fieldItems\n ) : (\n <div className='py-3 text-center text-xs text-[#c0c4cc]'>\n 无匹配字段\n </div>\n )}\n </div>\n ),\n });\n }\n\n return (\n <div className='flex h-full flex-col border-r border-[#f0f0f0] bg-[#f7f8fa]'>\n <div className='px-3 pb-2 pt-3'>\n <Input\n size='small'\n allowClear\n prefix={<span className='text-xs text-[#bbb]'>🔍</span>}\n placeholder='搜索组件…'\n value={keyword}\n onChange={(e) => setKeyword(e.target.value)}\n className='nexus-palette-search'\n />\n </div>\n <div className='flex-1 overflow-y-auto px-2 pb-3'>\n <Collapse\n className='nexus-palette-collapse'\n expandIconPlacement='end'\n defaultActiveKey={['widgets', 'layouts']}\n items={collapseItems}\n />\n </div>\n </div>\n );\n}\n"],"names":["PANE_PARENT_TYPE","isPaneItem","item","PaletteItem","onAdd","handleDragStart","e","payload","paneParent","title","jsxs","jsx","FieldDefItem","field","Palette","schema","selectedPath","addNode","fields","widgetCatalog","layoutCatalog","useDesigner","keyword","setKeyword","useState","handleAdd","useCallback","paneParentType","parent","getNodeAtProperties","parentProps","getPropertiesOf","key","generateKey","node","kw","widgetItems","useMemo","layoutItems","fieldItems","sectionGrid","items","hasMore","collapseItems","Input","Collapse"],"mappings":"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"}
1
+ {"version":3,"file":"palette.js","sources":["../../src/palette.tsx"],"sourcesContent":["// ============================================================================\n// @xbeeant/form-engine-designer — 左侧组件目录面板\n// ============================================================================\n\nimport type { SchemaNode } from '@xbeeant/form-engine';\nimport { Collapse, Input } from 'antd';\nimport type { DragEvent } from 'react';\nimport { useCallback, useMemo, useState } from 'react';\nimport { useDesigner } from './designer-context';\nimport {\n generateKey,\n getNodeAtProperties,\n getPropertiesOf,\n} from './schema-utils';\nimport type { CatalogItem, FieldDef } from './types';\n\n// 拖拽负载:palette 组件目录项 or 外部字段定义\nexport interface PaletteDragPayload {\n source: 'palette';\n catalogItem: CatalogItem;\n}\nexport interface FieldDefDragPayload {\n source: 'fieldDef';\n fieldDef: FieldDef;\n}\nexport type PaletteDragData = PaletteDragPayload | FieldDefDragPayload;\n\n// 面板类型 → 允许的唯一父容器类型(面板不能直接添加到根或普通容器)\nconst PANE_PARENT_TYPE: Record<string, string> = {\n tabPane: 'tabs',\n collapsePanel: 'collapse',\n step: 'steps',\n};\n\nconst isPaneItem = (item: CatalogItem): boolean =>\n item.category === 'layout' && !!PANE_PARENT_TYPE[item.layoutType ?? ''];\n\nfunction PaletteItem({\n item,\n onAdd,\n}: {\n item: CatalogItem;\n onAdd: (item: CatalogItem) => void;\n}) {\n const handleDragStart = (e: DragEvent<HTMLDivElement>) => {\n const payload: PaletteDragPayload = {\n source: 'palette',\n catalogItem: item,\n };\n e.dataTransfer.setData('application/json', JSON.stringify(payload));\n e.dataTransfer.effectAllowed = 'copy';\n };\n\n // 面板类组件只能放入对应容器,点击/拖拽提示差异化\n const paneParent = isPaneItem(item)\n ? PANE_PARENT_TYPE[item.layoutType ?? '']\n : undefined;\n const title = paneParent\n ? `拖拽「${item.label}」到「${paneParent}」容器中,或选中容器后点击`\n : `点击添加或拖拽「${item.label}」到画布`;\n\n return (\n <div\n className='group flex flex-col items-center gap-1 rounded-lg border border-[#f0f0f0] bg-white px-1 py-2 cursor-grab select-none transition-all hover:-translate-y-px hover:border-[#1677ff] hover:shadow-[0_2px_8px_rgba(22,119,255,0.12)] active:cursor-grabbing'\n draggable\n onDragStart={handleDragStart}\n onClick={() => onAdd(item)}\n title={title}\n >\n <span className='flex h-7 w-7 items-center justify-center rounded-md bg-[#f5f7fa] text-[15px] transition-colors group-hover:bg-[#e8f1ff]'>\n {item.icon}\n </span>\n <span className='w-full truncate text-center text-xs text-[#666] transition-colors group-hover:text-[#1677ff]'>\n {item.label}\n </span>\n </div>\n );\n}\n\nfunction FieldDefItem({ field }: { field: FieldDef }) {\n const handleDragStart = (e: DragEvent<HTMLDivElement>) => {\n const payload: FieldDefDragPayload = {\n source: 'fieldDef',\n fieldDef: field,\n };\n e.dataTransfer.setData('application/json', JSON.stringify(payload));\n e.dataTransfer.effectAllowed = 'copy';\n };\n\n return (\n <div\n className='flex items-center gap-2 rounded-lg border border-[#f0f0f0] bg-white px-2 py-1.5 cursor-grab select-none transition-all hover:-translate-y-px hover:border-[#1677ff] hover:shadow-[0_2px_8px_rgba(22,119,255,0.12)] active:cursor-grabbing'\n draggable\n onDragStart={handleDragStart}\n title={`id: ${field.id} · widget: ${field.widget}`}\n >\n <span className='flex h-6 w-6 flex-shrink-0 items-center justify-center rounded-md bg-[#f5f7fa] text-[13px]'>\n 🔧\n </span>\n <span className='truncate text-xs text-[#666]'>{field.name}</span>\n </div>\n );\n}\n\nexport function Palette() {\n const {\n schema,\n selectedPath,\n addNode,\n fields,\n widgetCatalog,\n layoutCatalog,\n } = useDesigner();\n const [keyword, setKeyword] = useState('');\n\n const handleAdd = useCallback(\n (item: CatalogItem) => {\n const base = item.widget || item.layoutType || 'field';\n // 面板类组件只能放入对应容器:点击时若已选中匹配容器则加入,否则忽略\n const paneParentType = isPaneItem(item)\n ? PANE_PARENT_TYPE[item.layoutType ?? '']\n : undefined;\n if (paneParentType) {\n if (!selectedPath || selectedPath.length === 0) {\n return;\n }\n const parent = getNodeAtProperties(schema.properties, selectedPath);\n if (!parent || parent.type !== paneParentType) {\n return;\n }\n const parentProps = getPropertiesOf(parent);\n if (!parentProps) {\n return;\n }\n const key = generateKey(parentProps, base);\n addNode(selectedPath, key, item.createNode() as unknown as SchemaNode);\n return;\n }\n const key = generateKey(schema.properties, base);\n const node = item.createNode() as unknown as SchemaNode;\n addNode([], key, node);\n },\n [schema, addNode, selectedPath],\n );\n\n const kw = keyword.trim().toLowerCase();\n\n const widgetItems = useMemo(\n () =>\n widgetCatalog\n .filter((item) => item.label.toLowerCase().includes(kw))\n .map((item) => (\n <PaletteItem key={item.widget} item={item} onAdd={handleAdd} />\n )),\n [widgetCatalog, kw, handleAdd],\n );\n\n const layoutItems = useMemo(\n () =>\n layoutCatalog\n .filter((item) => item.label.toLowerCase().includes(kw))\n .map((item) => (\n <PaletteItem key={item.layoutType} item={item} onAdd={handleAdd} />\n )),\n [layoutCatalog, kw, handleAdd],\n );\n\n const fieldItems = useMemo(\n () =>\n (fields ?? [])\n .filter((field) => field.name.toLowerCase().includes(kw))\n .map((field) => <FieldDefItem key={field.id} field={field} />),\n [fields, kw],\n );\n\n const sectionGrid = (items: React.ReactNode[], hasMore: boolean) =>\n items.length > 0 ? (\n <div className='grid grid-cols-2 gap-1.5 px-1 pb-2'>{items}</div>\n ) : (\n <div className='py-3 text-center text-xs text-[#c0c4cc]'>\n {hasMore ? '无匹配组件' : '暂无组件'}\n </div>\n );\n\n const collapseItems = [\n {\n key: 'widgets',\n label: (\n <span className='flex w-full items-center justify-between pr-1'>\n <span>表单组件</span>\n <span className='rounded-full bg-[#f0f0f0] px-1.5 py-px text-[11px] text-[#999]'>\n {widgetItems.length}\n </span>\n </span>\n ),\n children: sectionGrid(widgetItems, true),\n },\n {\n key: 'layouts',\n label: (\n <span className='flex w-full items-center justify-between pr-1'>\n <span>布局组件</span>\n <span className='rounded-full bg-[#f0f0f0] px-1.5 py-px text-[11px] text-[#999]'>\n {layoutItems.length}\n </span>\n </span>\n ),\n children: sectionGrid(layoutItems, true),\n },\n ];\n\n // 仅当传入 fields 时显示「字段列表」分组\n if (fields && fields.length > 0) {\n collapseItems.push({\n key: 'fieldList',\n label: (\n <span className='flex w-full items-center justify-between pr-1'>\n <span>字段列表</span>\n <span className='rounded-full bg-[#f0f0f0] px-1.5 py-px text-[11px] text-[#999]'>\n {fieldItems.length}\n </span>\n </span>\n ),\n children: (\n <div className='flex flex-col gap-1.5 px-1 pb-2'>\n {fieldItems.length > 0 ? (\n fieldItems\n ) : (\n <div className='py-3 text-center text-xs text-[#c0c4cc]'>\n 无匹配字段\n </div>\n )}\n </div>\n ),\n });\n }\n\n return (\n <div className='flex h-full flex-col border-r border-[#f0f0f0] bg-[#f7f8fa]'>\n <div className='px-3 pb-2 pt-3'>\n <Input\n size='small'\n allowClear\n prefix={<span className='text-xs text-[#bbb]'>🔍</span>}\n placeholder='搜索组件…'\n value={keyword}\n onChange={(e) => setKeyword(e.target.value)}\n className='nexus-palette-search'\n />\n </div>\n <div className='flex-1 overflow-y-auto px-2 pb-3'>\n <Collapse\n className='nexus-palette-collapse'\n expandIconPlacement='end'\n defaultActiveKey={['widgets', 'layouts']}\n items={collapseItems}\n />\n </div>\n </div>\n );\n}\n"],"names":["PANE_PARENT_TYPE","isPaneItem","item","PaletteItem","onAdd","handleDragStart","e","payload","paneParent","title","jsxs","jsx","FieldDefItem","field","Palette","schema","selectedPath","addNode","fields","widgetCatalog","layoutCatalog","useDesigner","keyword","setKeyword","useState","handleAdd","useCallback","paneParentType","parent","getNodeAtProperties","parentProps","getPropertiesOf","key","generateKey","node","kw","widgetItems","useMemo","layoutItems","fieldItems","sectionGrid","items","hasMore","collapseItems","Input","Collapse"],"mappings":"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"}
@@ -1,42 +1,41 @@
1
- import { jsxs as a, jsx as o } from "react/jsx-runtime";
2
- import { NexusForm as S } from "./react/src/components/NexusForm.js";
3
- import { useForm as V } from "./react/src/hooks/useForm.js";
4
- import { registerAntdUI as W } from "@xbeeant/form-engine-ui";
5
- import { Input as T } from "antd";
6
- import { useMemo as P, useCallback as b, useState as A, useRef as D } from "react";
7
- import { useDesigner as E } from "./DesignerContext.js";
8
- import { dependencyPropertyFields as B, reactionPropertyFields as I, validationPropertyFields as M, commonPropertyFields as $ } from "./property/basic-property.js";
9
- import { getNodeAtProperties as z, extractFormLevelConfig as U, flattenNodeForPropertyEditor as F, diffPropertyPatch as q } from "./schemaUtils.js";
10
- import { propertyWidgets as G } from "./widgets/index.js";
11
- function H({
12
- schema: n,
1
+ import { jsxs as c, jsx as n } from "react/jsx-runtime";
2
+ import { useForm as W, NexusForm as E } from "@xbeeant/form-engine-react";
3
+ import { registerAntdUI as T } from "@xbeeant/form-engine-ui";
4
+ import { Input as A } from "antd";
5
+ import { useMemo as P, useCallback as b, useState as D, useRef as C, useEffect as K } from "react";
6
+ import { useDesigner as B } from "./DesignerContext.js";
7
+ import { dependencyPropertyFields as I, reactionPropertyFields as M, validationPropertyFields as $, commonPropertyFields as z } from "./property/basic-property.js";
8
+ import { getNodeAtProperties as U, extractFormLevelConfig as q, flattenNodeForPropertyEditor as j, diffPropertyPatch as G } from "./schemaUtils.js";
9
+ import { propertyWidgets as H } from "./widgets/index.js";
10
+ function J({
11
+ schema: o,
13
12
  initialValues: e,
14
13
  onValuesChange: r
15
14
  }) {
16
- const [i] = V(), d = i._getEngine();
17
- W(d);
18
- const s = D(/* @__PURE__ */ new Set()), l = b(
19
- (t, c, u) => {
20
- u && s.current.add(u), r(
15
+ const [s] = W(), a = s._getEngine();
16
+ T(a);
17
+ const i = C(/* @__PURE__ */ new Set()), d = b(
18
+ (t, l, u) => {
19
+ u && i.current.add(u), r(
21
20
  t,
22
- s.current
21
+ i.current
23
22
  );
24
23
  },
25
24
  [r]
26
25
  );
27
- return /* @__PURE__ */ o(
28
- S,
26
+ return /* @__PURE__ */ n(
27
+ E,
29
28
  {
30
29
  footer: !1,
31
- form: i,
32
- schema: n,
30
+ form: s,
31
+ schema: o,
33
32
  initialValues: e,
34
- watch: { "#": l },
35
- widgets: G
33
+ watch: { "#": d },
34
+ widgets: H
36
35
  }
37
36
  );
38
37
  }
39
- const j = {
38
+ const F = {
40
39
  displayType: {
41
40
  widget: "select",
42
41
  type: "string",
@@ -79,7 +78,7 @@ const j = {
79
78
  title: "每行显示列数(column)",
80
79
  default: 1
81
80
  }
82
- }, J = {
81
+ }, Q = {
83
82
  column: { widget: "number", type: "number", title: "列数(column)" },
84
83
  gap: { widget: "number", type: "number", title: "间距(gap)" },
85
84
  direction: {
@@ -94,63 +93,64 @@ const j = {
94
93
  }
95
94
  }
96
95
  };
97
- function m(n, e, r) {
96
+ function m(o, e, r) {
98
97
  return {
99
- [n]: {
98
+ [o]: {
100
99
  type: "collapsePanel",
101
100
  title: e,
102
101
  properties: r
103
102
  }
104
103
  };
105
104
  }
106
- function Q({ oldKey: n, locked: e, onRename: r }) {
107
- const [i, d] = A(n);
108
- if (e)
109
- return /* @__PURE__ */ a("div", { className: "mb-3 flex items-center justify-between gap-2 rounded-lg border border-[#f0f0f0] bg-[#fafafa] px-3 py-2", children: [
110
- /* @__PURE__ */ a("div", { className: "min-w-0", children: [
111
- /* @__PURE__ */ o("div", { className: "mb-0.5 text-[11px] text-[#999]", children: "字段标识(key)" }),
112
- /* @__PURE__ */ o("code", { className: "break-all font-mono text-[13px] text-[#333]", children: n })
105
+ function X({ oldKey: o, locked: e, onRename: r }) {
106
+ const [s, a] = D(o), i = C(o);
107
+ if (K(() => {
108
+ o !== i.current && (i.current = o, a(o));
109
+ }, [o]), e)
110
+ return /* @__PURE__ */ c("div", { className: "mb-3 flex items-center justify-between gap-2 rounded-lg border border-[#f0f0f0] bg-[#fafafa] px-3 py-2", children: [
111
+ /* @__PURE__ */ c("div", { className: "min-w-0", children: [
112
+ /* @__PURE__ */ n("div", { className: "mb-0.5 text-[11px] text-[#999]", children: "字段标识(key)" }),
113
+ /* @__PURE__ */ n("code", { className: "break-all font-mono text-[13px] text-[#333]", children: o })
113
114
  ] }),
114
- /* @__PURE__ */ o("span", { className: "shrink-0 rounded bg-[#f0f0f0] px-1.5 py-0.5 text-[11px] text-[#999]", children: "🔒 锁定" })
115
+ /* @__PURE__ */ n("span", { className: "shrink-0 rounded bg-[#f0f0f0] px-1.5 py-0.5 text-[11px] text-[#999]", children: "🔒 锁定" })
115
116
  ] });
116
- const s = (l) => {
117
- d(l), r(l);
117
+ const d = (t) => {
118
+ i.current = t, a(t), r(t);
118
119
  };
119
- return /* @__PURE__ */ a("div", { className: "mb-3", children: [
120
- /* @__PURE__ */ o("div", { className: "mb-1.5 text-[11px] text-[#999]", children: "字段标识(key)" }),
121
- /* @__PURE__ */ o(
122
- T,
120
+ return /* @__PURE__ */ c("div", { className: "mb-3", children: [
121
+ /* @__PURE__ */ n("div", { className: "mb-1.5 text-[11px] text-[#999]", children: "字段标识(key)" }),
122
+ /* @__PURE__ */ n(
123
+ A,
123
124
  {
124
125
  size: "small",
125
- value: i,
126
- onChange: (l) => {
127
- const t = (l.target.value || "").trim();
128
- s(t);
126
+ value: s,
127
+ onChange: (t) => {
128
+ const l = (t.target.value || "").trim();
129
+ d(l);
129
130
  },
130
- autoFocus: !0,
131
131
  className: "nexus-key-input"
132
132
  }
133
133
  ),
134
- /* @__PURE__ */ o("div", { className: "mt-1 text-[11px] text-[#c0c4cc]", children: "用于数据路径与联动引用,修改后自动迁移子节点" })
134
+ /* @__PURE__ */ n("div", { className: "mt-1 text-[11px] text-[#c0c4cc]", children: "用于数据路径与联动引用,修改后自动迁移子节点" })
135
135
  ] });
136
136
  }
137
137
  function ce() {
138
138
  const {
139
- schema: n,
139
+ schema: o,
140
140
  selectedPath: e,
141
141
  updateNode: r,
142
- renameNode: i,
143
- selectNode: d,
144
- setSchema: s,
145
- propertySchemaMap: l
146
- } = E(), t = e && e.length > 0 ? z(n.properties, e) : void 0, c = !e || e.length === 0, u = `node_${(e || []).join("_")}_${t?.type || "root"}`, g = e?.[e.length - 1] ?? "", C = t?._lockedKey === !0, x = t ? t.widget || t.type : null, L = P(() => {
147
- if (c)
142
+ renameNode: s,
143
+ selectNode: a,
144
+ setSchema: i,
145
+ propertySchemaMap: d
146
+ } = B(), t = e && e.length > 0 ? U(o.properties, e) : void 0, l = !e || e.length === 0, u = `node_${(e || []).join("_")}_${t?.type || "root"}`, g = e?.[e.length - 1] ?? "", L = t?._lockedKey === !0, x = t ? t.widget || t.type : null, R = P(() => {
147
+ if (l)
148
148
  return {
149
149
  type: "object",
150
- properties: j,
150
+ properties: F,
151
151
  displayType: "column"
152
152
  };
153
- const p = l[x] || J;
153
+ const p = d[x] || Q;
154
154
  return {
155
155
  type: "object",
156
156
  properties: {
@@ -170,7 +170,7 @@ function ce() {
170
170
  ...m(
171
171
  "sectionCommon",
172
172
  "通用属性",
173
- $
173
+ z
174
174
  ),
175
175
  ...m(
176
176
  "sectionFieldProps",
@@ -180,71 +180,71 @@ function ce() {
180
180
  ...m(
181
181
  "sectionValidation",
182
182
  "校验配置",
183
- M
183
+ $
184
184
  ),
185
185
  ...m(
186
186
  "sectionReaction",
187
187
  "联动配置",
188
- I
188
+ M
189
189
  ),
190
190
  ...m(
191
191
  "sectionDependency",
192
192
  "依赖配置",
193
- B
193
+ I
194
194
  )
195
195
  }
196
196
  }
197
197
  },
198
198
  displayType: "column"
199
199
  };
200
- }, [c, x, l]), f = P(
201
- () => U(
202
- n,
203
- Object.keys(j)
200
+ }, [l, x, d]), f = P(
201
+ () => q(
202
+ o,
203
+ Object.keys(F)
204
204
  ),
205
- [n]
206
- ), K = b(
207
- (p, O) => {
208
- const R = t ? F(
205
+ [o]
206
+ ), _ = b(
207
+ (p, S) => {
208
+ const V = t ? j(
209
209
  t
210
- ) : f, y = q(R, p, O);
210
+ ) : f, y = G(V, p, S);
211
211
  if (Object.keys(y).length === 0)
212
212
  return;
213
213
  if (!e || e.length === 0) {
214
- const h = { ...n };
214
+ const h = { ...o };
215
215
  for (const [k, N] of Object.entries(y))
216
216
  N === void 0 ? delete h[k] : h[k] = N;
217
- s(h);
217
+ i(h);
218
218
  return;
219
219
  }
220
- const { key: X, ...v } = y;
220
+ const { key: Y, ...v } = y;
221
221
  Object.keys(v).length > 0 && r(e, v);
222
222
  },
223
223
  [
224
224
  e,
225
225
  r,
226
- s,
227
- n,
226
+ i,
227
+ o,
228
228
  t,
229
229
  f
230
230
  ]
231
- ), _ = b(
231
+ ), O = b(
232
232
  (p) => {
233
- !e || e.length === 0 || i(e, p);
233
+ !e || e.length === 0 || s(e, p);
234
234
  },
235
- [e, i]
235
+ [e, s]
236
236
  ), w = t ? (t.widget || t.type || "").toLowerCase() : "";
237
- return /* @__PURE__ */ a("div", { className: "flex h-full flex-col border-l border-[#f0f0f0] bg-white", children: [
238
- /* @__PURE__ */ a("div", { className: "flex items-center justify-between border-b border-[#f0f0f0] px-4 py-2.5", children: [
239
- /* @__PURE__ */ a("div", { className: "pl-5 flex min-w-0 items-center gap-1 h-6", children: [
240
- !c && /* @__PURE__ */ o(
237
+ return /* @__PURE__ */ c("div", { className: "flex h-full flex-col border-l border-[#f0f0f0] bg-white", children: [
238
+ /* @__PURE__ */ c("div", { className: "flex items-center justify-between border-b border-[#f0f0f0] px-4 py-2.5", children: [
239
+ /* @__PURE__ */ c("div", { className: "pl-5 flex min-w-0 items-center gap-1 h-6", children: [
240
+ !l && /* @__PURE__ */ n(
241
241
  "button",
242
242
  {
243
243
  type: "button",
244
- onClick: () => d(null),
244
+ onClick: () => a(null),
245
245
  className: "-ml-1 mr-0.5 flex h-6 w-6 shrink-0 items-center justify-center rounded-md text-[#999] transition-colors hover:bg-[#f0f0f0] hover:text-[#333]",
246
246
  title: "返回表单属性",
247
- children: /* @__PURE__ */ o(
247
+ children: /* @__PURE__ */ n(
248
248
  "svg",
249
249
  {
250
250
  width: "12",
@@ -256,32 +256,32 @@ function ce() {
256
256
  strokeLinecap: "round",
257
257
  strokeLinejoin: "round",
258
258
  "aria-hidden": "true",
259
- children: /* @__PURE__ */ o("polyline", { points: "15 18 9 12 15 6" })
259
+ children: /* @__PURE__ */ n("polyline", { points: "15 18 9 12 15 6" })
260
260
  }
261
261
  )
262
262
  }
263
263
  ),
264
- /* @__PURE__ */ o("span", { className: "truncate text-[13px] font-semibold text-[#333]", children: c ? "表单属性" : "节点属性" })
264
+ /* @__PURE__ */ n("span", { className: "truncate text-[13px] font-semibold text-[#333]", children: l ? "表单属性" : "节点属性" })
265
265
  ] }),
266
- !c && w && /* @__PURE__ */ o("span", { className: "ml-2 shrink-0 rounded-md bg-[#e8f1ff] px-1.5 py-0.5 text-[11px] text-[#1677ff]", children: w })
266
+ !l && w && /* @__PURE__ */ n("span", { className: "ml-2 shrink-0 rounded-md bg-[#e8f1ff] px-1.5 py-0.5 text-[11px] text-[#1677ff]", children: w })
267
267
  ] }),
268
- /* @__PURE__ */ a("div", { className: "nexus-property-body flex-1 overflow-y-auto px-4 py-3", children: [
269
- !c && g && /* @__PURE__ */ o(
270
- Q,
268
+ /* @__PURE__ */ c("div", { className: "nexus-property-body flex-1 overflow-y-auto px-4 py-3", children: [
269
+ !l && g && /* @__PURE__ */ n(
270
+ X,
271
271
  {
272
272
  oldKey: g,
273
- locked: C,
274
- onRename: _
273
+ locked: L,
274
+ onRename: O
275
275
  }
276
276
  ),
277
- /* @__PURE__ */ o(
278
- H,
277
+ /* @__PURE__ */ n(
278
+ J,
279
279
  {
280
- schema: L,
281
- initialValues: t ? F(
280
+ schema: R,
281
+ initialValues: t ? j(
282
282
  t
283
283
  ) : f,
284
- onValuesChange: K
284
+ onValuesChange: _
285
285
  },
286
286
  u
287
287
  )
@@ -1 +1 @@
1
- {"version":3,"file":"PropertyPanel.js","sources":["../../src/PropertyPanel.tsx"],"sourcesContent":["// ============================================================================\n// @xbeeant/form-engine-designer — 右侧属性配置面板\n// 属性定义采用「描述符驱动」:\n// - 组件(widget)属性来自外部传入的 propertySchemaMap(key 为 widget 名,\n// 值为该组件的属性字段定义,示例见 @xbeeant/form-engine-ui/src/schema/*-schema.ts)\n// - 通用 / 校验 / 依赖分区在 ./property/basic-property.ts 中定义\n// - 布局节点与表单级属性在下方 formLevelProps / layoutBasicProps 内联定义\n//\n// 编辑流程(与 schemaUtils 的读/写通路对应):\n// flattenNodeForPropertyEditor → 节点 → 扁平 initialValues(读)\n// updateNodeWithNesting → 扁平 patch → 节点(写,split schema级/props级)\n// PropertyForm 通过 NexusForm 渲染 propertySchema 描述符驱动的表单\n// ============================================================================\n\nimport type { NexusSchema, SchemaNode } from '@xbeeant/form-engine';\nimport { NexusForm, useForm } from '@xbeeant/form-engine-react';\nimport { registerAntdUI } from '@xbeeant/form-engine-ui';\nimport { Input } from 'antd';\nimport { useCallback, useMemo, useRef, useState } from 'react';\nimport { useDesigner } from './DesignerContext';\nimport {\n commonPropertyFields,\n dependencyPropertyFields,\n reactionPropertyFields,\n validationPropertyFields,\n} from './property/basic-property.ts';\nimport {\n diffPropertyPatch,\n extractFormLevelConfig,\n flattenNodeForPropertyEditor,\n getNodeAtProperties,\n} from './schemaUtils';\nimport { propertyWidgets } from './widgets';\n\n// ────────────────────────────────────────────────────────────────────────────\n// PropertyForm — 属性表单容器\n// Designer 的自定义属性编辑器独立于 form-engine 的渲染系统\n// ────────────────────────────────────────────────────────────────────────────\n\ninterface PropertyFormProps {\n schema: NexusSchema;\n initialValues: Record<string, unknown>;\n onValuesChange: (\n allValues: Record<string, unknown>,\n changedFields: ReadonlySet<string>,\n ) => void;\n}\n\nfunction PropertyForm({\n schema,\n initialValues,\n onValuesChange,\n}: PropertyFormProps) {\n const [form] = useForm();\n const engine = form._getEngine();\n\n // 注册 antd 基础 widget(select/input/switch/number/textarea/collapse/collapsePanel)\n registerAntdUI(engine);\n // 记录本表单实例中用户实际改动过的字段(组件随 formKey 重建,节点切换时自动重置)。\n // 用于区分「未触碰的字符串默认值 ''」与「用户主动清空」——\n // 后者需要回写 schema(删除属性),前者写回会污染 schema(如 bind:'' 导致数据 key 丢失)。\n const changedFieldsRef = useRef<Set<string>>(new Set());\n // '#' 全局 watcher 由 FormController._onFieldValueChange 调用,\n // 前两个参数为 (globalData, globalData),第三参为本次实际变更的字段路径\n const handleWatch = useCallback(\n (value: unknown, _allValues: unknown, changedPath?: string) => {\n if (changedPath) {\n changedFieldsRef.current.add(changedPath);\n }\n onValuesChange(\n value as Record<string, unknown>,\n changedFieldsRef.current,\n );\n },\n [onValuesChange],\n );\n\n return (\n <NexusForm\n footer={false}\n form={form}\n schema={schema}\n initialValues={initialValues}\n watch={{ '#': handleWatch }}\n widgets={propertyWidgets}\n />\n );\n}\n\n// ────────────────────────────────────────────────────────────────────────────\n// 表单级属性(未选中节点时编辑 NexusSchema 顶层配置)\n// ────────────────────────────────────────────────────────────────────────────\n\nconst formLevelProps: Record<string, SchemaNode> = {\n displayType: {\n widget: 'select',\n type: 'string',\n title: '表单布局方向(displayType)',\n props: {\n options: [\n { label: '水平(row)', value: 'row' },\n { label: '垂直(column)', value: 'column' },\n { label: '行内(inline)', value: 'inline' },\n ],\n },\n },\n labelWidth: {\n widget: 'input',\n type: 'string',\n title: 'label 宽度(labelWidth)',\n placeholder: '如 120 或 20%',\n },\n colon: {\n widget: 'switch',\n type: 'boolean',\n title: '显示冒号(colon)',\n default: true,\n },\n label: {\n widget: 'switch',\n type: 'boolean',\n title: '显示 label(label)',\n default: true,\n },\n readOnly: {\n widget: 'switch',\n type: 'boolean',\n title: '整个表单只读(readOnly)',\n default: false,\n },\n column: {\n widget: 'number',\n type: 'number',\n title: '每行显示列数(column)',\n default: 1,\n },\n};\n\n// ────────────────────────────────────────────────────────────────────────────\n// 布局节点基础属性(layout nodes 不在 propertySchemaMap 中,单独定义)\n// ────────────────────────────────────────────────────────────────────────────\n\nconst layoutBasicProps: Record<string, SchemaNode> = {\n column: { widget: 'number', type: 'number', title: '列数(column)' },\n gap: { widget: 'number', type: 'number', title: '间距(gap)' },\n direction: {\n widget: 'select',\n type: 'string',\n title: '方向(direction)',\n props: {\n options: [\n { label: '水平', value: 'row' },\n { label: '垂直', value: 'column' },\n ],\n },\n },\n};\n\n// ────────────────────────────────────────────────────────────────────────────\n// collapseSection — 将一组扁平字段包裹成单个 collapse 分区\n// collapse / collapsePanel 均为布局节点,key 不进入数据路径,\n// 因此其内部字段(title / validate / bind 等)会被扁平地暴露给属性表单。\n// ────────────────────────────────────────────────────────────────────────────\n\nfunction collapseSection(\n key: string,\n title: string,\n fields: Record<string, SchemaNode>,\n): Record<string, SchemaNode> {\n // @ts-expect-error\n return {\n [key]: {\n type: 'collapsePanel',\n title,\n properties: fields,\n },\n } as unknown as SchemaNode;\n}\n\n// ────────────────────────────────────────────────────────────────────────────\n// KeyEditor — 单独处理 key 的编辑器\n// key 不是 SchemaNode 的属性,而是 properties 的索引键\n// 修改 key = schema 结构级操作:删除旧 key + 添加新 key + 更新选中路径\n// ────────────────────────────────────────────────────────────────────────────\n\ninterface KeyEditorProps {\n oldKey: string;\n locked?: boolean;\n onRename: (newKey: string) => void;\n}\n\nfunction KeyEditor({ oldKey, locked, onRename }: KeyEditorProps) {\n const [value, setValue] = useState(oldKey);\n\n if (locked) {\n return (\n <div className='mb-3 flex items-center justify-between gap-2 rounded-lg border border-[#f0f0f0] bg-[#fafafa] px-3 py-2'>\n <div className='min-w-0'>\n <div className='mb-0.5 text-[11px] text-[#999]'>字段标识(key)</div>\n <code className='break-all font-mono text-[13px] text-[#333]'>\n {oldKey}\n </code>\n </div>\n <span className='shrink-0 rounded bg-[#f0f0f0] px-1.5 py-0.5 text-[11px] text-[#999]'>\n 🔒 锁定\n </span>\n </div>\n );\n }\n\n const onChange = (v: string) => {\n setValue(v);\n onRename(v);\n };\n\n return (\n <div className='mb-3'>\n <div className='mb-1.5 text-[11px] text-[#999]'>字段标识(key)</div>\n <Input\n size='small'\n value={value}\n onChange={(e) => {\n const trimmed = (e.target.value || '').trim();\n onChange(trimmed);\n }}\n autoFocus\n className='nexus-key-input'\n />\n <div className='mt-1 text-[11px] text-[#c0c4cc]'>\n 用于数据路径与联动引用,修改后自动迁移子节点\n </div>\n </div>\n );\n}\n\n// ────────────────────────────────────────────────────────────────────────────\n// PropertyPanel — 主组件\n// ────────────────────────────────────────────────────────────────────────────\n\nexport function PropertyPanel() {\n const {\n schema,\n selectedPath,\n updateNode,\n renameNode,\n selectNode,\n setSchema,\n propertySchemaMap,\n } = useDesigner();\n\n const selectedNode =\n selectedPath && selectedPath.length > 0\n ? getNodeAtProperties(schema.properties, selectedPath)\n : undefined;\n\n const isFormLevel = !selectedPath || selectedPath.length === 0;\n\n // 选择变化时强制重建引擎(nodeVersion bump)\n const formKey = `node_${(selectedPath || []).join('_')}_${(selectedNode as { type?: string } | undefined)?.type || 'root'}`;\n\n // key 的特殊性:从 path 最后一段提取,不通过 NexusForm 管理\n const currentKey = selectedPath?.[selectedPath.length - 1] ?? '';\n const keyLocked =\n (selectedNode as unknown as Record<string, unknown> | undefined)\n ?._lockedKey === true;\n\n // 选中节点的 widget/type:决定属性面板使用哪组组件属性;\n // 仅在切换节点(widget/type 改变)时重新计算,避免每次输入都重建 schema\n // (selectedNode 的 object identity 会随每次 edit 变化,不能直接依赖)\n const selectedWidgetKey = selectedNode\n ? (selectedNode.widget as string | undefined) ||\n (selectedNode.type as string)\n : null;\n\n // 构建属性表单 schema:\n // - 未选中节点(form-level):formLevelProps(NexusSchema 顶层配置)\n // - 选中节点:4 个 collapse 分区(通用属性 / 组件属性 / 校验配置 / 依赖配置)\n // collapse 与 collapsePanel 均为布局节点,key 不进入数据路径,\n // 各分区内部字段会被扁平暴露给属性表单。\n // 注意:不依赖 selectedNode 对象本身(每次 edit 都是新引用),\n // 只依赖 isFormLevel 和 selectedWidgetKey,避免无谓 re-init。\n const formSchema = useMemo<NexusSchema>(() => {\n if (isFormLevel) {\n return {\n type: 'object',\n properties: formLevelProps,\n displayType: 'column',\n } as NexusSchema;\n }\n\n const widgetProps =\n propertySchemaMap[selectedWidgetKey as string] || layoutBasicProps;\n\n return {\n type: 'object',\n properties: {\n sectionProperty: {\n widget: 'collapse',\n props: {\n defaultActiveKey: [\n 'sectionCommon',\n 'sectionFieldProps',\n 'sectionValidation',\n 'sectionReaction',\n 'sectionDependency',\n ],\n },\n type: 'collapse',\n properties: {\n ...collapseSection(\n 'sectionCommon',\n '通用属性',\n commonPropertyFields,\n ),\n ...collapseSection(\n 'sectionFieldProps',\n '组件属性',\n widgetProps as Record<string, SchemaNode>,\n ),\n ...collapseSection(\n 'sectionValidation',\n '校验配置',\n validationPropertyFields,\n ),\n ...collapseSection(\n 'sectionReaction',\n '联动配置',\n reactionPropertyFields,\n ),\n ...collapseSection(\n 'sectionDependency',\n '依赖配置',\n dependencyPropertyFields,\n ),\n },\n },\n },\n displayType: 'column',\n } as NexusSchema;\n }, [isFormLevel, selectedWidgetKey, propertySchemaMap]);\n\n // 表单级属性面板的取值来源:只提取 NexusSchema 顶层的表单配置键,\n // 而非整个 schema 对象(schema 含 properties 与嵌套字段,不是表单级配置)\n const formLevelConfig = useMemo<Record<string, unknown>>(\n () =>\n extractFormLevelConfig(\n schema as unknown as Record<string, unknown>,\n Object.keys(formLevelProps),\n ),\n [schema],\n );\n\n const handleValuesChange = useCallback(\n (\n allValues: Record<string, unknown>,\n changedFields: ReadonlySet<string>,\n ) => {\n // 只写回「真正变化」的值:未触碰的空字符串(''/undefined/null)视为未赋值,\n // 不写回 Schema(否则 bind:'' / hidden:'' / required:'' 会导致 key 丢失 / 空联动);\n // 用户主动清空的字段(changedFields 命中)以 undefined 回写,由\n // updateNodeWithNesting 从节点删除对应属性(详见 diffPropertyPatch)\n const initial = selectedNode\n ? flattenNodeForPropertyEditor(\n selectedNode as unknown as Record<string, any>,\n )\n : formLevelConfig;\n\n const patch = diffPropertyPatch(initial, allValues, changedFields);\n if (Object.keys(patch).length === 0) {\n return;\n }\n\n if (!selectedPath || selectedPath.length === 0) {\n // form-level:修改 NexusSchema 顶层属性(undefined 表示清空,删除该键)\n const next = { ...(schema as unknown as Record<string, unknown>) };\n for (const [key, value] of Object.entries(patch)) {\n if (value === undefined) {\n delete next[key];\n } else {\n next[key] = value;\n }\n }\n setSchema(next as unknown as NexusSchema);\n return;\n }\n\n // 节点级:key 已由 KeyEditor 单独处理,此处跳过\n const { key: _key, ...rest } = patch;\n if (Object.keys(rest).length > 0) {\n updateNode(selectedPath, rest);\n }\n },\n [\n selectedPath,\n updateNode,\n setSchema,\n schema,\n selectedNode,\n formLevelConfig,\n ],\n );\n\n const handleRename = useCallback(\n (newKey: string) => {\n if (!selectedPath || selectedPath.length === 0) {\n return;\n }\n renameNode(selectedPath, newKey);\n },\n [selectedPath, renameNode],\n );\n\n // 节点类型徽标:字段取 widget,布局/对象取 type\n const nodeKind = selectedNode\n ? (\n (selectedNode.widget as string) ||\n (selectedNode.type as string) ||\n ''\n ).toLowerCase()\n : '';\n\n return (\n <div className='flex h-full flex-col border-l border-[#f0f0f0] bg-white'>\n {/* 导航头 */}\n <div className='flex items-center justify-between border-b border-[#f0f0f0] px-4 py-2.5'>\n <div className='pl-5 flex min-w-0 items-center gap-1 h-6'>\n {!isFormLevel && (\n <button\n type='button'\n onClick={() => selectNode(null)}\n className='-ml-1 mr-0.5 flex h-6 w-6 shrink-0 items-center justify-center rounded-md text-[#999] transition-colors hover:bg-[#f0f0f0] hover:text-[#333]'\n title='返回表单属性'\n >\n <svg\n width='12'\n height='12'\n viewBox='0 0 24 24'\n fill='none'\n stroke='currentColor'\n strokeWidth='2.5'\n strokeLinecap='round'\n strokeLinejoin='round'\n aria-hidden='true'\n >\n <polyline points='15 18 9 12 15 6' />\n </svg>\n </button>\n )}\n <span className='truncate text-[13px] font-semibold text-[#333]'>\n {isFormLevel ? '表单属性' : '节点属性'}\n </span>\n </div>\n {!isFormLevel && nodeKind && (\n <span className='ml-2 shrink-0 rounded-md bg-[#e8f1ff] px-1.5 py-0.5 text-[11px] text-[#1677ff]'>\n {nodeKind}\n </span>\n )}\n </div>\n\n <div className='nexus-property-body flex-1 overflow-y-auto px-4 py-3'>\n {/* key 特殊性处理:key 不是 SchemaNode 属性,而是 properties 索引键 */}\n {!isFormLevel && currentKey && (\n <KeyEditor\n oldKey={currentKey}\n locked={keyLocked}\n onRename={handleRename}\n />\n )}\n\n {/* 属性表单:完全基于 descriptor 驱动 */}\n <PropertyForm\n key={formKey}\n schema={formSchema}\n initialValues={\n selectedNode\n ? flattenNodeForPropertyEditor(\n selectedNode as unknown as Record<string, any>,\n )\n : formLevelConfig\n }\n onValuesChange={handleValuesChange}\n />\n </div>\n </div>\n );\n}\n"],"names":["PropertyForm","schema","initialValues","onValuesChange","form","useForm","engine","registerAntdUI","changedFieldsRef","useRef","handleWatch","useCallback","value","_allValues","changedPath","jsx","NexusForm","propertyWidgets","formLevelProps","layoutBasicProps","collapseSection","key","title","fields","KeyEditor","oldKey","locked","onRename","setValue","useState","jsxs","onChange","v","Input","e","trimmed","PropertyPanel","selectedPath","updateNode","renameNode","selectNode","setSchema","propertySchemaMap","useDesigner","selectedNode","getNodeAtProperties","isFormLevel","formKey","currentKey","keyLocked","selectedWidgetKey","formSchema","useMemo","widgetProps","commonPropertyFields","validationPropertyFields","reactionPropertyFields","dependencyPropertyFields","formLevelConfig","extractFormLevelConfig","handleValuesChange","allValues","changedFields","initial","flattenNodeForPropertyEditor","patch","diffPropertyPatch","next","_key","rest","handleRename","newKey","nodeKind"],"mappings":"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"}
1
+ {"version":3,"file":"PropertyPanel.js","sources":["../../src/PropertyPanel.tsx"],"sourcesContent":["// ============================================================================\n// @xbeeant/form-engine-designer — 右侧属性配置面板\n// 属性定义采用「描述符驱动」:\n// - 组件(widget)属性来自外部传入的 propertySchemaMap(key 为 widget 名,\n// 值为该组件的属性字段定义,示例见 @xbeeant/form-engine-ui/src/schema/*-schema.ts)\n// - 通用 / 校验 / 依赖分区在 ./property/basic-property.ts 中定义\n// - 布局节点与表单级属性在下方 formLevelProps / layoutBasicProps 内联定义\n//\n// 编辑流程(与 schemaUtils 的读/写通路对应):\n// flattenNodeForPropertyEditor → 节点 → 扁平 initialValues(读)\n// updateNodeWithNesting → 扁平 patch → 节点(写,split schema级/props级)\n// PropertyForm 通过 NexusForm 渲染 propertySchema 描述符驱动的表单\n// ============================================================================\n\nimport type { NexusSchema, SchemaNode } from '@xbeeant/form-engine';\nimport { NexusForm, useForm } from '@xbeeant/form-engine-react';\nimport { registerAntdUI } from '@xbeeant/form-engine-ui';\nimport { Input } from 'antd';\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport { useDesigner } from './DesignerContext';\nimport {\n commonPropertyFields,\n dependencyPropertyFields,\n reactionPropertyFields,\n validationPropertyFields,\n} from './property/basic-property.ts';\nimport {\n diffPropertyPatch,\n extractFormLevelConfig,\n flattenNodeForPropertyEditor,\n getNodeAtProperties,\n} from './schemaUtils';\nimport { propertyWidgets } from './widgets';\n\n// ────────────────────────────────────────────────────────────────────────────\n// PropertyForm — 属性表单容器\n// Designer 的自定义属性编辑器独立于 form-engine 的渲染系统\n// ────────────────────────────────────────────────────────────────────────────\n\ninterface PropertyFormProps {\n schema: NexusSchema;\n initialValues: Record<string, unknown>;\n onValuesChange: (\n allValues: Record<string, unknown>,\n changedFields: ReadonlySet<string>,\n ) => void;\n}\n\nfunction PropertyForm({\n schema,\n initialValues,\n onValuesChange,\n}: PropertyFormProps) {\n const [form] = useForm();\n const engine = form._getEngine();\n\n // 注册 antd 基础 widget(select/input/switch/number/textarea/collapse/collapsePanel)\n registerAntdUI(engine);\n // 记录本表单实例中用户实际改动过的字段(组件随 formKey 重建,节点切换时自动重置)。\n // 用于区分「未触碰的字符串默认值 ''」与「用户主动清空」——\n // 后者需要回写 schema(删除属性),前者写回会污染 schema(如 bind:'' 导致数据 key 丢失)。\n const changedFieldsRef = useRef<Set<string>>(new Set());\n // '#' 全局 watcher 由 FormController._onFieldValueChange 调用,\n // 前两个参数为 (globalData, globalData),第三参为本次实际变更的字段路径\n const handleWatch = useCallback(\n (value: unknown, _allValues: unknown, changedPath?: string) => {\n if (changedPath) {\n changedFieldsRef.current.add(changedPath);\n }\n onValuesChange(\n value as Record<string, unknown>,\n changedFieldsRef.current,\n );\n },\n [onValuesChange],\n );\n\n return (\n <NexusForm\n footer={false}\n form={form}\n schema={schema}\n initialValues={initialValues}\n watch={{ '#': handleWatch }}\n widgets={propertyWidgets}\n />\n );\n}\n\n// ────────────────────────────────────────────────────────────────────────────\n// 表单级属性(未选中节点时编辑 NexusSchema 顶层配置)\n// ────────────────────────────────────────────────────────────────────────────\n\nconst formLevelProps: Record<string, SchemaNode> = {\n displayType: {\n widget: 'select',\n type: 'string',\n title: '表单布局方向(displayType)',\n props: {\n options: [\n { label: '水平(row)', value: 'row' },\n { label: '垂直(column)', value: 'column' },\n { label: '行内(inline)', value: 'inline' },\n ],\n },\n },\n labelWidth: {\n widget: 'input',\n type: 'string',\n title: 'label 宽度(labelWidth)',\n placeholder: '如 120 或 20%',\n },\n colon: {\n widget: 'switch',\n type: 'boolean',\n title: '显示冒号(colon)',\n default: true,\n },\n label: {\n widget: 'switch',\n type: 'boolean',\n title: '显示 label(label)',\n default: true,\n },\n readOnly: {\n widget: 'switch',\n type: 'boolean',\n title: '整个表单只读(readOnly)',\n default: false,\n },\n column: {\n widget: 'number',\n type: 'number',\n title: '每行显示列数(column)',\n default: 1,\n },\n};\n\n// ────────────────────────────────────────────────────────────────────────────\n// 布局节点基础属性(layout nodes 不在 propertySchemaMap 中,单独定义)\n// ────────────────────────────────────────────────────────────────────────────\n\nconst layoutBasicProps: Record<string, SchemaNode> = {\n column: { widget: 'number', type: 'number', title: '列数(column)' },\n gap: { widget: 'number', type: 'number', title: '间距(gap)' },\n direction: {\n widget: 'select',\n type: 'string',\n title: '方向(direction)',\n props: {\n options: [\n { label: '水平', value: 'row' },\n { label: '垂直', value: 'column' },\n ],\n },\n },\n};\n\n// ────────────────────────────────────────────────────────────────────────────\n// collapseSection — 将一组扁平字段包裹成单个 collapse 分区\n// collapse / collapsePanel 均为布局节点,key 不进入数据路径,\n// 因此其内部字段(title / validate / bind 等)会被扁平地暴露给属性表单。\n// ────────────────────────────────────────────────────────────────────────────\n\nfunction collapseSection(\n key: string,\n title: string,\n fields: Record<string, SchemaNode>,\n): Record<string, SchemaNode> {\n // @ts-expect-error\n return {\n [key]: {\n type: 'collapsePanel',\n title,\n properties: fields,\n },\n } as unknown as SchemaNode;\n}\n\n// ────────────────────────────────────────────────────────────────────────────\n// KeyEditor — 单独处理 key 的编辑器\n// key 不是 SchemaNode 的属性,而是 properties 的索引键\n// 修改 key = schema 结构级操作:删除旧 key + 添加新 key + 更新选中路径\n// ────────────────────────────────────────────────────────────────────────────\n\ninterface KeyEditorProps {\n oldKey: string;\n locked?: boolean;\n onRename: (newKey: string) => void;\n}\n\nfunction KeyEditor({ oldKey, locked, onRename }: KeyEditorProps) {\n const [value, setValue] = useState(oldKey);\n // 记录已同步到本地 state 的外部 key:仅当外部 oldKey 发生「非本次编辑产生」的\n // 变化(如切换选中节点)时才重置输入框,避免用 key 重建组件导致失焦\n const syncedKeyRef = useRef(oldKey);\n\n useEffect(() => {\n if (oldKey !== syncedKeyRef.current) {\n syncedKeyRef.current = oldKey;\n setValue(oldKey);\n }\n }, [oldKey]);\n\n if (locked) {\n return (\n <div className='mb-3 flex items-center justify-between gap-2 rounded-lg border border-[#f0f0f0] bg-[#fafafa] px-3 py-2'>\n <div className='min-w-0'>\n <div className='mb-0.5 text-[11px] text-[#999]'>字段标识(key)</div>\n <code className='break-all font-mono text-[13px] text-[#333]'>\n {oldKey}\n </code>\n </div>\n <span className='shrink-0 rounded bg-[#f0f0f0] px-1.5 py-0.5 text-[11px] text-[#999]'>\n 🔒 锁定\n </span>\n </div>\n );\n }\n\n const onChange = (v: string) => {\n syncedKeyRef.current = v;\n setValue(v);\n onRename(v);\n };\n\n return (\n <div className='mb-3'>\n <div className='mb-1.5 text-[11px] text-[#999]'>字段标识(key)</div>\n <Input\n size='small'\n value={value}\n onChange={(e) => {\n const trimmed = (e.target.value || '').trim();\n onChange(trimmed);\n }}\n className='nexus-key-input'\n />\n <div className='mt-1 text-[11px] text-[#c0c4cc]'>\n 用于数据路径与联动引用,修改后自动迁移子节点\n </div>\n </div>\n );\n}\n\n// ────────────────────────────────────────────────────────────────────────────\n// PropertyPanel — 主组件\n// ────────────────────────────────────────────────────────────────────────────\n\nexport function PropertyPanel() {\n const {\n schema,\n selectedPath,\n updateNode,\n renameNode,\n selectNode,\n setSchema,\n propertySchemaMap,\n } = useDesigner();\n\n const selectedNode =\n selectedPath && selectedPath.length > 0\n ? getNodeAtProperties(schema.properties, selectedPath)\n : undefined;\n\n const isFormLevel = !selectedPath || selectedPath.length === 0;\n\n // 选择变化时强制重建引擎(nodeVersion bump)\n const formKey = `node_${(selectedPath || []).join('_')}_${(selectedNode as { type?: string } | undefined)?.type || 'root'}`;\n\n // key 的特殊性:从 path 最后一段提取,不通过 NexusForm 管理\n const currentKey = selectedPath?.[selectedPath.length - 1] ?? '';\n const keyLocked =\n (selectedNode as unknown as Record<string, unknown> | undefined)\n ?._lockedKey === true;\n\n // 选中节点的 widget/type:决定属性面板使用哪组组件属性;\n // 仅在切换节点(widget/type 改变)时重新计算,避免每次输入都重建 schema\n // (selectedNode 的 object identity 会随每次 edit 变化,不能直接依赖)\n const selectedWidgetKey = selectedNode\n ? (selectedNode.widget as string | undefined) ||\n (selectedNode.type as string)\n : null;\n\n // 构建属性表单 schema:\n // - 未选中节点(form-level):formLevelProps(NexusSchema 顶层配置)\n // - 选中节点:4 个 collapse 分区(通用属性 / 组件属性 / 校验配置 / 依赖配置)\n // collapse 与 collapsePanel 均为布局节点,key 不进入数据路径,\n // 各分区内部字段会被扁平暴露给属性表单。\n // 注意:不依赖 selectedNode 对象本身(每次 edit 都是新引用),\n // 只依赖 isFormLevel 和 selectedWidgetKey,避免无谓 re-init。\n const formSchema = useMemo<NexusSchema>(() => {\n if (isFormLevel) {\n return {\n type: 'object',\n properties: formLevelProps,\n displayType: 'column',\n } as NexusSchema;\n }\n\n const widgetProps =\n propertySchemaMap[selectedWidgetKey as string] || layoutBasicProps;\n\n return {\n type: 'object',\n properties: {\n sectionProperty: {\n widget: 'collapse',\n props: {\n defaultActiveKey: [\n 'sectionCommon',\n 'sectionFieldProps',\n 'sectionValidation',\n 'sectionReaction',\n 'sectionDependency',\n ],\n },\n type: 'collapse',\n properties: {\n ...collapseSection(\n 'sectionCommon',\n '通用属性',\n commonPropertyFields,\n ),\n ...collapseSection(\n 'sectionFieldProps',\n '组件属性',\n widgetProps as Record<string, SchemaNode>,\n ),\n ...collapseSection(\n 'sectionValidation',\n '校验配置',\n validationPropertyFields,\n ),\n ...collapseSection(\n 'sectionReaction',\n '联动配置',\n reactionPropertyFields,\n ),\n ...collapseSection(\n 'sectionDependency',\n '依赖配置',\n dependencyPropertyFields,\n ),\n },\n },\n },\n displayType: 'column',\n } as NexusSchema;\n }, [isFormLevel, selectedWidgetKey, propertySchemaMap]);\n\n // 表单级属性面板的取值来源:只提取 NexusSchema 顶层的表单配置键,\n // 而非整个 schema 对象(schema 含 properties 与嵌套字段,不是表单级配置)\n const formLevelConfig = useMemo<Record<string, unknown>>(\n () =>\n extractFormLevelConfig(\n schema as unknown as Record<string, unknown>,\n Object.keys(formLevelProps),\n ),\n [schema],\n );\n\n const handleValuesChange = useCallback(\n (\n allValues: Record<string, unknown>,\n changedFields: ReadonlySet<string>,\n ) => {\n // 只写回「真正变化」的值:未触碰的空字符串(''/undefined/null)视为未赋值,\n // 不写回 Schema(否则 bind:'' / hidden:'' / required:'' 会导致 key 丢失 / 空联动);\n // 用户主动清空的字段(changedFields 命中)以 undefined 回写,由\n // updateNodeWithNesting 从节点删除对应属性(详见 diffPropertyPatch)\n const initial = selectedNode\n ? flattenNodeForPropertyEditor(\n selectedNode as unknown as Record<string, any>,\n )\n : formLevelConfig;\n\n const patch = diffPropertyPatch(initial, allValues, changedFields);\n if (Object.keys(patch).length === 0) {\n return;\n }\n\n if (!selectedPath || selectedPath.length === 0) {\n // form-level:修改 NexusSchema 顶层属性(undefined 表示清空,删除该键)\n const next = { ...(schema as unknown as Record<string, unknown>) };\n for (const [key, value] of Object.entries(patch)) {\n if (value === undefined) {\n delete next[key];\n } else {\n next[key] = value;\n }\n }\n setSchema(next as unknown as NexusSchema);\n return;\n }\n\n // 节点级:key 已由 KeyEditor 单独处理,此处跳过\n const { key: _key, ...rest } = patch;\n if (Object.keys(rest).length > 0) {\n updateNode(selectedPath, rest);\n }\n },\n [\n selectedPath,\n updateNode,\n setSchema,\n schema,\n selectedNode,\n formLevelConfig,\n ],\n );\n\n const handleRename = useCallback(\n (newKey: string) => {\n if (!selectedPath || selectedPath.length === 0) {\n return;\n }\n renameNode(selectedPath, newKey);\n },\n [selectedPath, renameNode],\n );\n\n // 节点类型徽标:字段取 widget,布局/对象取 type\n const nodeKind = selectedNode\n ? (\n (selectedNode.widget as string) ||\n (selectedNode.type as string) ||\n ''\n ).toLowerCase()\n : '';\n\n return (\n <div className='flex h-full flex-col border-l border-[#f0f0f0] bg-white'>\n {/* 导航头 */}\n <div className='flex items-center justify-between border-b border-[#f0f0f0] px-4 py-2.5'>\n <div className='pl-5 flex min-w-0 items-center gap-1 h-6'>\n {!isFormLevel && (\n <button\n type='button'\n onClick={() => selectNode(null)}\n className='-ml-1 mr-0.5 flex h-6 w-6 shrink-0 items-center justify-center rounded-md text-[#999] transition-colors hover:bg-[#f0f0f0] hover:text-[#333]'\n title='返回表单属性'\n >\n <svg\n width='12'\n height='12'\n viewBox='0 0 24 24'\n fill='none'\n stroke='currentColor'\n strokeWidth='2.5'\n strokeLinecap='round'\n strokeLinejoin='round'\n aria-hidden='true'\n >\n <polyline points='15 18 9 12 15 6' />\n </svg>\n </button>\n )}\n <span className='truncate text-[13px] font-semibold text-[#333]'>\n {isFormLevel ? '表单属性' : '节点属性'}\n </span>\n </div>\n {!isFormLevel && nodeKind && (\n <span className='ml-2 shrink-0 rounded-md bg-[#e8f1ff] px-1.5 py-0.5 text-[11px] text-[#1677ff]'>\n {nodeKind}\n </span>\n )}\n </div>\n\n <div className='nexus-property-body flex-1 overflow-y-auto px-4 py-3'>\n {/* key 特殊性处理:key 不是 SchemaNode 属性,而是 properties 索引键 */}\n {!isFormLevel && currentKey && (\n <KeyEditor\n oldKey={currentKey}\n locked={keyLocked}\n onRename={handleRename}\n />\n )}\n\n {/* 属性表单:完全基于 descriptor 驱动 */}\n <PropertyForm\n key={formKey}\n schema={formSchema}\n initialValues={\n selectedNode\n ? flattenNodeForPropertyEditor(\n selectedNode as unknown as Record<string, any>,\n )\n : formLevelConfig\n }\n onValuesChange={handleValuesChange}\n />\n </div>\n </div>\n );\n}\n"],"names":["PropertyForm","schema","initialValues","onValuesChange","form","useForm","engine","registerAntdUI","changedFieldsRef","useRef","handleWatch","useCallback","value","_allValues","changedPath","jsx","NexusForm","propertyWidgets","formLevelProps","layoutBasicProps","collapseSection","key","title","fields","KeyEditor","oldKey","locked","onRename","setValue","useState","syncedKeyRef","useEffect","jsxs","onChange","v","Input","e","trimmed","PropertyPanel","selectedPath","updateNode","renameNode","selectNode","setSchema","propertySchemaMap","useDesigner","selectedNode","getNodeAtProperties","isFormLevel","formKey","currentKey","keyLocked","selectedWidgetKey","formSchema","useMemo","widgetProps","commonPropertyFields","validationPropertyFields","reactionPropertyFields","dependencyPropertyFields","formLevelConfig","extractFormLevelConfig","handleValuesChange","allValues","changedFields","initial","flattenNodeForPropertyEditor","patch","diffPropertyPatch","next","_key","rest","handleRename","newKey","nodeKind"],"mappings":"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"}
@@ -44,10 +44,10 @@ const e = [
44
44
  label: "下拉选择(远程)",
45
45
  icon: "📡",
46
46
  category: "widget",
47
- widget: "selectWithRemote",
47
+ widget: "remoteSelect",
48
48
  createNode: () => ({
49
49
  type: "string",
50
- widget: "selectWithRemote",
50
+ widget: "remoteSelect",
51
51
  title: "下拉选择(远程)",
52
52
  remoteData: {
53
53
  url: "/api/options",
@@ -111,10 +111,10 @@ const e = [
111
111
  label: "多选下拉(远程)",
112
112
  icon: "📡",
113
113
  category: "widget",
114
- widget: "multiSelectWithRemote",
114
+ widget: "remoteMultiSelect",
115
115
  createNode: () => ({
116
116
  type: "array",
117
- widget: "multiSelectWithRemote",
117
+ widget: "remoteMultiSelect",
118
118
  title: "多选下拉(远程)",
119
119
  remoteData: {
120
120
  url: "/api/multi-options",
@@ -214,7 +214,8 @@ const e = [
214
214
  createNode: () => ({
215
215
  type: "string",
216
216
  widget: "voidTitle",
217
- title: "标题文字"
217
+ title: "标题文字",
218
+ label: !1
218
219
  })
219
220
  },
220
221
  {
@@ -245,10 +246,10 @@ const e = [
245
246
  label: "自动完成(远程)",
246
247
  icon: "📡",
247
248
  category: "widget",
248
- widget: "autoCompleteWithRemote",
249
+ widget: "remoteAutoComplete",
249
250
  createNode: () => ({
250
251
  type: "string",
251
- widget: "autoCompleteWithRemote",
252
+ widget: "remoteAutoComplete",
252
253
  title: "自动完成(远程)",
253
254
  remoteData: {
254
255
  url: "/api/suggestions",
@@ -275,10 +276,10 @@ const e = [
275
276
  label: "级联选择(远程)",
276
277
  icon: "📡",
277
278
  category: "widget",
278
- widget: "cascaderWithRemote",
279
+ widget: "remoteCascader",
279
280
  createNode: () => ({
280
281
  type: "array",
281
- widget: "cascaderWithRemote",
282
+ widget: "remoteCascader",
282
283
  title: "级联选择(远程)",
283
284
  remoteData: {
284
285
  url: "/api/cascader/nodes",
@@ -310,10 +311,10 @@ const e = [
310
311
  label: "提及(远程)",
311
312
  icon: "📡",
312
313
  category: "widget",
313
- widget: "mentionsWithRemote",
314
+ widget: "remoteMentions",
314
315
  createNode: () => ({
315
316
  type: "string",
316
- widget: "mentionsWithRemote",
317
+ widget: "remoteMentions",
317
318
  title: "提及(远程)",
318
319
  remoteData: {
319
320
  url: "/api/users/suggestions",
@@ -505,6 +506,13 @@ const e = [
505
506
  category: "layout",
506
507
  layoutType: "space",
507
508
  createNode: () => ({ type: "space", properties: {} })
509
+ },
510
+ {
511
+ label: "透传容器",
512
+ icon: "📶",
513
+ category: "layout",
514
+ layoutType: "passThrough",
515
+ createNode: () => ({ type: "passThrough", properties: {} })
508
516
  }
509
517
  ];
510
518
  export {