@webiny/app-admin 6.2.0 → 6.3.0-beta.1

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 (143) hide show
  1. package/base/Admin.js +2 -0
  2. package/base/Admin.js.map +1 -1
  3. package/base/Base/DefaultFieldRenderers.js +20 -4
  4. package/base/Base/DefaultFieldRenderers.js.map +1 -1
  5. package/base/Base/DefaultLayoutRenderers.d.ts +2 -0
  6. package/base/Base/DefaultLayoutRenderers.js +11 -0
  7. package/base/Base/DefaultLayoutRenderers.js.map +1 -0
  8. package/base/Base/FieldRenderers/InputRenderer.d.ts +15 -0
  9. package/base/Base/FieldRenderers/{TextRenderer.js → InputRenderer.js} +5 -3
  10. package/base/Base/FieldRenderers/InputRenderer.js.map +1 -0
  11. package/base/Base/FieldRenderers/ObjectRenderer/ObjectFieldComponents.d.ts +25 -0
  12. package/base/Base/FieldRenderers/ObjectRenderer/ObjectFieldComponents.js +89 -0
  13. package/base/Base/FieldRenderers/ObjectRenderer/ObjectFieldComponents.js.map +1 -0
  14. package/base/Base/FieldRenderers/ObjectRenderer/ObjectListFlatRenderer.d.ts +21 -0
  15. package/base/Base/FieldRenderers/ObjectRenderer/ObjectListFlatRenderer.js +28 -0
  16. package/base/Base/FieldRenderers/ObjectRenderer/ObjectListFlatRenderer.js.map +1 -0
  17. package/base/Base/FieldRenderers/ObjectRenderer/ObjectRenderer.d.ts +17 -0
  18. package/base/Base/FieldRenderers/ObjectRenderer/ObjectRenderer.js +63 -0
  19. package/base/Base/FieldRenderers/ObjectRenderer/ObjectRenderer.js.map +1 -0
  20. package/base/Base/FieldRenderers/ObjectRenderer/resolveItemTitle.d.ts +4 -0
  21. package/base/Base/FieldRenderers/ObjectRenderer/resolveItemTitle.js +22 -0
  22. package/base/Base/FieldRenderers/ObjectRenderer/resolveItemTitle.js.map +1 -0
  23. package/base/Base/FieldRenderers/PassthroughRenderer.d.ts +15 -0
  24. package/base/Base/FieldRenderers/PassthroughRenderer.js +29 -0
  25. package/base/Base/FieldRenderers/PassthroughRenderer.js.map +1 -0
  26. package/base/Base/FieldRenderers/SelectRenderer.d.ts +12 -2
  27. package/base/Base/FieldRenderers/SelectRenderer.js +4 -2
  28. package/base/Base/FieldRenderers/SelectRenderer.js.map +1 -1
  29. package/base/Base/FieldRenderers/TextareaRenderer.d.ts +17 -0
  30. package/base/Base/FieldRenderers/TextareaRenderer.js +25 -0
  31. package/base/Base/FieldRenderers/TextareaRenderer.js.map +1 -0
  32. package/base/Base/FieldRenderers/VerticalTabsRenderer.d.ts +5 -0
  33. package/base/Base/FieldRenderers/VerticalTabsRenderer.js +41 -0
  34. package/base/Base/FieldRenderers/VerticalTabsRenderer.js.map +1 -0
  35. package/base/Base.js +2 -1
  36. package/base/Base.js.map +1 -1
  37. package/base/createRootContainer.js +4 -0
  38. package/base/createRootContainer.js.map +1 -1
  39. package/base/providers/UiProviders.js +0 -1
  40. package/base/providers/UiProviders.js.map +1 -1
  41. package/components/Filters/Filters.js.map +1 -1
  42. package/components/IconPicker/components/IconPickerCell.d.ts +1 -1
  43. package/components/IconPicker/components/IconPickerTrigger.d.ts +1 -1
  44. package/components/IconPicker/components/IconPickerTrigger.js.map +1 -1
  45. package/components/LexicalEditor/LexicalEditor.js +7 -1
  46. package/components/LexicalEditor/LexicalEditor.js.map +1 -1
  47. package/components/LexicalEditor/lexicalValueFromHtml.d.ts +7 -0
  48. package/components/LexicalEditor/lexicalValueFromHtml.js +35 -0
  49. package/components/LexicalEditor/lexicalValueFromHtml.js.map +1 -0
  50. package/components/OverlayLayout/components/OverlayHeader.d.ts +1 -1
  51. package/components/OverlayLayout/components/OverlayHeader.js.map +1 -1
  52. package/components/SimpleForm/SimpleForm.d.ts +2 -2
  53. package/components/SimpleForm/SimpleForm.js.map +1 -1
  54. package/config/AdminConfig/Form.d.ts +1 -0
  55. package/config/AdminConfig/Form.js +3 -1
  56. package/config/AdminConfig/Form.js.map +1 -1
  57. package/config/AdminConfig/LayoutRenderer.d.ts +10 -0
  58. package/config/AdminConfig/LayoutRenderer.js +21 -0
  59. package/config/AdminConfig/LayoutRenderer.js.map +1 -0
  60. package/config/AdminConfig/Menu/MenuLink.d.ts +2 -2
  61. package/config/AdminConfig.d.ts +4 -0
  62. package/config/AdminConfig.js +2 -1
  63. package/config/AdminConfig.js.map +1 -1
  64. package/exports/admin.d.ts +2 -0
  65. package/exports/admin.js +2 -0
  66. package/exports/admin.js.map +1 -1
  67. package/features/formModel/Field.js +4 -0
  68. package/features/formModel/Field.js.map +1 -1
  69. package/features/formModel/FieldBuilder.d.ts +18 -2
  70. package/features/formModel/FieldBuilder.js +57 -3
  71. package/features/formModel/FieldBuilder.js.map +1 -1
  72. package/features/formModel/FormModel.d.ts +3 -3
  73. package/features/formModel/FormModel.js +48 -13
  74. package/features/formModel/FormModel.js.map +1 -1
  75. package/features/formModel/FormModel.test.js +383 -0
  76. package/features/formModel/FormModel.test.js.map +1 -1
  77. package/features/formModel/FormModelFactory.d.ts +2 -2
  78. package/features/formModel/FormModelFactory.js.map +1 -1
  79. package/features/formModel/FormView.d.ts +24 -4
  80. package/features/formModel/FormView.js +57 -27
  81. package/features/formModel/FormView.js.map +1 -1
  82. package/features/formModel/ObjectField.d.ts +46 -0
  83. package/features/formModel/ObjectField.js +346 -0
  84. package/features/formModel/ObjectField.js.map +1 -0
  85. package/features/formModel/abstractions.d.ts +88 -19
  86. package/features/formModel/abstractions.js +8 -0
  87. package/features/formModel/abstractions.js.map +1 -1
  88. package/features/formModel/index.d.ts +7 -4
  89. package/features/formModel/index.js +9 -2
  90. package/features/formModel/index.js.map +1 -1
  91. package/features/formModel/renderers.d.ts +6 -0
  92. package/features/formModel/renderers.js +10 -0
  93. package/features/formModel/renderers.js.map +1 -0
  94. package/features/formModel/useLayoutRenderers.d.ts +2 -0
  95. package/features/formModel/useLayoutRenderers.js +19 -0
  96. package/features/formModel/useLayoutRenderers.js.map +1 -0
  97. package/features/tools/ToolPipelineRunner.d.ts +10 -0
  98. package/features/tools/ToolPipelineRunner.js +33 -0
  99. package/features/tools/ToolPipelineRunner.js.map +1 -0
  100. package/features/tools/ToolRegistry.d.ts +12 -0
  101. package/features/tools/ToolRegistry.js +29 -0
  102. package/features/tools/ToolRegistry.js.map +1 -0
  103. package/features/tools/abstractions.d.ts +28 -0
  104. package/features/tools/abstractions.js +6 -0
  105. package/features/tools/abstractions.js.map +1 -0
  106. package/features/tools/feature.d.ts +4 -0
  107. package/features/tools/feature.js +19 -0
  108. package/features/tools/feature.js.map +1 -0
  109. package/features/tools/index.d.ts +2 -0
  110. package/features/tools/index.js +4 -0
  111. package/features/tools/index.js.map +1 -0
  112. package/features/wcp/ReactLicense.d.ts +3 -0
  113. package/features/wcp/ReactLicense.js +9 -0
  114. package/features/wcp/ReactLicense.js.map +1 -1
  115. package/features/wcp/WcpGateway.js +4 -0
  116. package/features/wcp/WcpGateway.js.map +1 -1
  117. package/features/webinySdk/WebinySdk.d.ts +11 -0
  118. package/features/webinySdk/WebinySdk.js +27 -0
  119. package/features/webinySdk/WebinySdk.js.map +1 -0
  120. package/features/webinySdk/abstractions.d.ts +6 -0
  121. package/features/webinySdk/abstractions.js +8 -0
  122. package/features/webinySdk/abstractions.js.map +1 -0
  123. package/features/webinySdk/feature.d.ts +3 -0
  124. package/features/webinySdk/feature.js +16 -0
  125. package/features/webinySdk/feature.js.map +1 -0
  126. package/features/webinySdk/index.d.ts +2 -0
  127. package/features/webinySdk/index.js +4 -0
  128. package/features/webinySdk/index.js.map +1 -0
  129. package/index.d.ts +8 -3
  130. package/index.js +5 -2
  131. package/index.js.map +1 -1
  132. package/package.json +24 -23
  133. package/presentation/textToLexicalTool/TextToLexicalTool.d.ts +27 -0
  134. package/presentation/textToLexicalTool/TextToLexicalTool.js +25 -0
  135. package/presentation/textToLexicalTool/TextToLexicalTool.js.map +1 -0
  136. package/presentation/textToLexicalTool/feature.d.ts +1 -0
  137. package/presentation/textToLexicalTool/feature.js +10 -0
  138. package/presentation/textToLexicalTool/feature.js.map +1 -0
  139. package/presentation/textToLexicalTool/textToLexicalState.d.ts +5 -0
  140. package/presentation/textToLexicalTool/textToLexicalState.js +19 -0
  141. package/presentation/textToLexicalTool/textToLexicalState.js.map +1 -0
  142. package/base/Base/FieldRenderers/TextRenderer.d.ts +0 -5
  143. package/base/Base/FieldRenderers/TextRenderer.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"names":["makeAutoObservable","computed","toJS","runInAction","observable","Field","createFieldBuilderRegistry","layoutAPI","row","fieldIds","type","separator","tabs","config","id","element","renderer","props","FormModel","_fields","Map","_layout","_baseline","_submitted","_validateOnChange","_isValid","_errors","_activeTabs","map","constructor","registry","builders","fields","name","builder","Object","entries","fieldConfig","build","field","setForm","set","layout","_warnOrphanFields","_generateDefaultLayout","validateOnSubmit","_snapshotBaseline","vm","autoBind","get","Error","factory","undefined","removeField","factoryOrNodeId","_accessLayoutNode","removals","modifierLayoutAPI","_createModifierLayoutAPI","target","_removeFromLayout","entry","_isPositionedNode","node","position","_insertIntoLayout","push","delete","getData","data","getValue","setData","value","setValueSilent","_resetAllValidation","reset","baselineValue","defaultValue","isDirty","baseline","current","is","isValid","errors","validate","valid","path","label","message","validation","length","submit","_resolveLayout","getField","getFields","_resolveLayoutNode","filter","Boolean","_resolveRowNode","_resolveSeparatorNode","_resolveTabsNode","_resolveElementNode","f","visible","tabKey","_tabsNodeKey","tab","description","icon","hasErrors","_tabHasErrors","child","storedActive","validActive","find","t","activeTabId","setActiveTab","_collectFieldIdsFromLayout","ids","join","layoutFieldIds","Set","has","console","warn","clear","resetValidation","_findLayoutIndex","findIndex","_nodeMatchesTarget","includes","filtered","targetIndex","result","splice","createLayoutNodeHandle","remove","nodeId","findTabsNode","found","as","tabsNode","definitionOrId","nodes","before","after","newTab","targetTabId","idx","handle","replace"],"sources":["FormModel.ts"],"sourcesContent":["import { makeAutoObservable, computed, toJS, runInAction, observable } from \"mobx\";\nimport { Field } from \"./Field.js\";\nimport { createFieldBuilderRegistry } from \"./FieldBuilder.js\";\nimport type {\n IFormModel,\n IField,\n IFieldBuilder,\n IFieldBuilderRegistry,\n IFormVM,\n IFormError,\n IFormModelConfig,\n ILayoutBuilder,\n ILayoutNodeHandle,\n ILayoutModifier,\n IPositionedLayoutNode,\n ILayoutNodeAccessHandle,\n ITabsHandle,\n ITabHandle,\n LayoutNode,\n LayoutPosition,\n LayoutNodeVM,\n IRowNode,\n IRowNodeVM,\n ISeparatorNode,\n ISeparatorNodeVM,\n ITabsNode,\n ITabsNodeVM,\n ITabDefinition,\n ITabDefinitionVM,\n IElementNode,\n IElementNodeVM\n} from \"./abstractions.js\";\n\nconst layoutAPI: ILayoutBuilder = {\n row(...fieldIds: string[]): IRowNode {\n return { type: \"row\", fieldIds };\n },\n separator(): ISeparatorNode {\n return { type: \"separator\" };\n },\n tabs(config: { id?: string; tabs: ITabDefinition[] }): ITabsNode {\n return { type: \"tabs\", id: config.id, tabs: config.tabs };\n },\n element(renderer: string, props?: Record<string, unknown>): IElementNode {\n return { type: \"element\", renderer, props };\n }\n};\n\nexport class FormModel implements IFormModel {\n private _fields = new Map<string, Field>();\n private _layout: LayoutNode[] = [];\n private _baseline = new Map<string, unknown>();\n private _submitted = false;\n private _validateOnChange = false;\n private _isValid: boolean | null = null;\n private _errors: IFormError[] = [];\n private _activeTabs = observable.map<string, string>();\n\n constructor(config: IFormModelConfig) {\n const registry = createFieldBuilderRegistry();\n const builders = config.fields(registry);\n\n // Build fields from builders\n for (const [name, builder] of Object.entries(builders)) {\n const fieldConfig = builder.build(name);\n const field = new Field(fieldConfig);\n field.setForm(this);\n this._fields.set(name, field);\n }\n\n // Build layout\n if (config.layout) {\n this._layout = config.layout(layoutAPI);\n this._warnOrphanFields();\n } else {\n this._layout = this._generateDefaultLayout();\n }\n\n // Validation strategy\n this._validateOnChange = config.validateOnSubmit === false;\n\n // Snapshot baseline from defaults\n this._snapshotBaseline();\n\n makeAutoObservable(\n this,\n {\n vm: computed\n },\n { autoBind: true }\n );\n }\n\n field(name: string): IField {\n // Try exact match first (supports dotted field names like \"properties.language\").\n const field = this._fields.get(name);\n\n if (!field) {\n throw new Error(`Field \"${name}\" not found.`);\n }\n\n return field;\n }\n\n fields(\n factory: (registry: IFieldBuilderRegistry) => Record<string, IFieldBuilder | undefined>\n ): void {\n const registry = createFieldBuilderRegistry();\n const builders = factory(registry);\n\n for (const [name, builder] of Object.entries(builders)) {\n if (builder === undefined) {\n // undefined = remove\n this.removeField(name);\n continue;\n }\n\n const fieldConfig = builder.build(name);\n const field = new Field(fieldConfig);\n field.setForm(this);\n\n // Replace or add — same operation on the map\n this._fields.set(name, field);\n }\n\n // Re-snapshot baseline to include new fields\n this._snapshotBaseline();\n }\n\n layout(factory: (layout: ILayoutModifier) => (LayoutNode | IPositionedLayoutNode)[]): void;\n layout(nodeId: string): ILayoutNodeAccessHandle;\n layout(\n factoryOrNodeId:\n | ((layout: ILayoutModifier) => (LayoutNode | IPositionedLayoutNode)[])\n | string\n ): void | ILayoutNodeAccessHandle {\n if (typeof factoryOrNodeId === \"string\") {\n return this._accessLayoutNode(factoryOrNodeId);\n }\n\n const factory = factoryOrNodeId;\n const removals: string[] = [];\n const modifierLayoutAPI = this._createModifierLayoutAPI(removals);\n\n const entries = factory(modifierLayoutAPI);\n\n // Process removals first\n for (const target of removals) {\n this._layout = this._removeFromLayout(this._layout, target);\n }\n\n // Process additions with positional modifiers\n for (const entry of entries) {\n if (this._isPositionedNode(entry)) {\n const { node, position } = entry;\n if (position) {\n this._layout = this._insertIntoLayout(this._layout, node, position);\n } else {\n this._layout.push(node);\n }\n } else {\n this._layout.push(entry);\n }\n }\n }\n\n removeField(name: string): void {\n this._fields.delete(name);\n this._baseline.delete(name);\n\n // Remove from layout\n this._layout = this._removeFromLayout(this._layout, name);\n }\n\n getData(): Record<string, unknown> {\n const data: Record<string, unknown> = {};\n for (const [name, field] of this._fields) {\n data[name] = toJS(field.getValue());\n }\n return data;\n }\n\n setData(data: Record<string, unknown>): void {\n for (const [name, value] of Object.entries(data)) {\n const field = this._fields.get(name);\n if (field) {\n field.setValueSilent(value);\n }\n }\n this._snapshotBaseline();\n this._resetAllValidation();\n this._submitted = false;\n this._isValid = null;\n this._errors = [];\n }\n\n reset(): void {\n for (const [name, field] of this._fields) {\n const baselineValue = this._baseline.get(name);\n field.setValueSilent(baselineValue ?? field.config.defaultValue ?? null);\n }\n this._resetAllValidation();\n this._submitted = false;\n this._isValid = null;\n this._errors = [];\n }\n\n get isDirty(): boolean {\n for (const [name, field] of this._fields) {\n const baseline = this._baseline.get(name);\n const current = field.getValue();\n if (!Object.is(toJS(current), toJS(baseline))) {\n return true;\n }\n }\n return false;\n }\n\n get isValid(): boolean | null {\n return this._isValid;\n }\n\n get errors(): IFormError[] {\n return this._errors;\n }\n\n async validate(): Promise<boolean> {\n const errors: IFormError[] = [];\n\n for (const [, field] of this._fields) {\n const valid = await field.validate();\n if (!valid) {\n errors.push({\n path: field.name,\n label: field.config.label,\n message: field.vm.validation.message || \"Invalid value.\"\n });\n }\n }\n\n const isValid = errors.length === 0;\n runInAction(() => {\n this._errors = errors;\n this._isValid = isValid;\n this._submitted = true;\n });\n return isValid;\n }\n\n async submit<T = Record<string, unknown>>(): Promise<T | false> {\n const valid = await this.validate();\n if (!valid) {\n return false;\n }\n return this.getData() as T;\n }\n\n get vm(): IFormVM {\n return {\n layout: this._resolveLayout(),\n errors: this._errors,\n isDirty: this.isDirty,\n isValid: this._isValid\n };\n }\n\n getField(name: string): Field | undefined {\n return this._fields.get(name);\n }\n\n getFields(): Map<string, Field> {\n return this._fields;\n }\n\n private _resolveLayout(): LayoutNodeVM[] {\n return this._layout\n .map(node => this._resolveLayoutNode(node))\n .filter(Boolean) as LayoutNodeVM[];\n }\n\n private _resolveLayoutNode(node: LayoutNode): LayoutNodeVM | null {\n switch (node.type) {\n case \"row\":\n return this._resolveRowNode(node);\n case \"separator\":\n return this._resolveSeparatorNode();\n case \"tabs\":\n return this._resolveTabsNode(node);\n case \"element\":\n return this._resolveElementNode(node);\n case \"object\":\n // ObjectNode rendering deferred to Phase 6\n return null;\n default:\n return null;\n }\n }\n\n private _resolveRowNode(node: IRowNode): IRowNodeVM | null {\n const fields = node.fieldIds\n .map(id => this._fields.get(id))\n .filter((f): f is Field => f !== undefined && f.visible)\n .map(f => f.vm);\n\n if (fields.length === 0) {\n return null;\n }\n\n return { type: \"row\", fields };\n }\n\n private _resolveSeparatorNode(): ISeparatorNodeVM {\n return { type: \"separator\" };\n }\n\n private _resolveTabsNode(node: ITabsNode): ITabsNodeVM | null {\n if (node.tabs.length === 0) {\n return null;\n }\n\n const tabKey = node.id || this._tabsNodeKey(node);\n\n const tabs: ITabDefinitionVM[] = node.tabs.map(tab => ({\n id: tab.id,\n label: tab.label,\n description: tab.description,\n icon: tab.icon,\n hasErrors: this._tabHasErrors(tab.layout),\n layout: tab.layout\n .map(child => this._resolveLayoutNode(child))\n .filter(Boolean) as LayoutNodeVM[]\n }));\n\n if (tabs.length === 0) {\n return null;\n }\n\n // Resolve active tab — fall back to first tab if stored value is invalid\n const storedActive = this._activeTabs.get(tabKey);\n const validActive = tabs.find(t => t.id === storedActive) ? storedActive! : tabs[0].id;\n\n return {\n type: \"tabs\",\n id: node.id,\n tabs,\n activeTabId: validActive,\n setActiveTab: (id: string) => {\n this._activeTabs.set(tabKey, id);\n }\n };\n }\n\n private _resolveElementNode(node: IElementNode): IElementNodeVM {\n return {\n type: \"element\",\n renderer: node.renderer,\n props: node.props\n };\n }\n\n private _tabHasErrors(layout: LayoutNode[]): boolean {\n const fieldIds = this._collectFieldIdsFromLayout(layout);\n for (const id of fieldIds) {\n const field = this._fields.get(id);\n if (field && field.vm.validation.isValid === false) {\n return true;\n }\n }\n return false;\n }\n\n private _collectFieldIdsFromLayout(layout: LayoutNode[]): string[] {\n const ids: string[] = [];\n for (const node of layout) {\n if (node.type === \"row\") {\n ids.push(...node.fieldIds);\n } else if (node.type === \"tabs\") {\n for (const tab of node.tabs) {\n ids.push(...this._collectFieldIdsFromLayout(tab.layout));\n }\n }\n }\n return ids;\n }\n\n private _tabsNodeKey(node: ITabsNode): string {\n return `__tabs_${node.tabs.map(t => t.id).join(\"_\")}`;\n }\n\n private _generateDefaultLayout(): LayoutNode[] {\n const layout: LayoutNode[] = [];\n for (const [name, field] of this._fields) {\n if (field.visible) {\n layout.push({ type: \"row\", fieldIds: [name] });\n }\n }\n return layout;\n }\n\n private _warnOrphanFields(): void {\n const layoutFieldIds = new Set(this._collectFieldIdsFromLayout(this._layout));\n\n for (const [name, field] of this._fields) {\n if (field.visible && !layoutFieldIds.has(name)) {\n console.warn(\n `[FormModel] Field \"${name}\" is not in the layout and not marked as .hidden(). ` +\n `Add it to the layout or mark it as .hidden() to suppress this warning.`\n );\n }\n }\n }\n\n private _snapshotBaseline(): void {\n this._baseline.clear();\n for (const [name, field] of this._fields) {\n this._baseline.set(name, toJS(field.getValue()));\n }\n }\n\n private _resetAllValidation(): void {\n for (const [, field] of this._fields) {\n field.resetValidation();\n }\n }\n\n /**\n * Find the index of a layout node that matches the given target.\n * Matches: row containing fieldId, tabs by id, element by id/renderer.\n * Returns -1 if not found.\n */\n private _findLayoutIndex(layout: LayoutNode[], target: string): number {\n return layout.findIndex(node => this._nodeMatchesTarget(node, target));\n }\n\n private _nodeMatchesTarget(node: LayoutNode, target: string): boolean {\n switch (node.type) {\n case \"row\":\n return node.fieldIds.includes(target);\n case \"tabs\":\n return node.id === target;\n case \"element\":\n return node.id === target || node.renderer === target;\n default:\n return false;\n }\n }\n\n /**\n * Remove a target from the layout tree. Handles field IDs in rows,\n * and node IDs for tabs/elements. Drops rows that become empty.\n */\n private _removeFromLayout(layout: LayoutNode[], target: string): LayoutNode[] {\n return layout\n .map(node => {\n if (node.type === \"row\") {\n const filtered = node.fieldIds.filter(id => id !== target);\n if (filtered.length === 0) {\n return null;\n }\n return { ...node, fieldIds: filtered };\n }\n // Remove tabs/elements by their ID\n if (\n (node.type === \"tabs\" && node.id === target) ||\n (node.type === \"element\" && (node.id === target || node.renderer === target))\n ) {\n return null;\n }\n return node;\n })\n .filter(Boolean) as LayoutNode[];\n }\n\n /**\n * Insert a layout node relative to a target field ID.\n */\n private _insertIntoLayout(\n layout: LayoutNode[],\n node: LayoutNode,\n position: LayoutPosition\n ): LayoutNode[] {\n const targetIndex = this._findLayoutIndex(layout, position.target);\n\n if (targetIndex === -1) {\n // Target not found — append\n return [...layout, node];\n }\n\n const result = [...layout];\n\n switch (position.type) {\n case \"before\":\n result.splice(targetIndex, 0, node);\n break;\n case \"after\":\n result.splice(targetIndex + 1, 0, node);\n break;\n case \"replace\":\n result.splice(targetIndex, 1, node);\n break;\n }\n\n return result;\n }\n\n private _createModifierLayoutAPI(removals: string[]): ILayoutModifier {\n return {\n row(...fieldIds: string[]): ILayoutNodeHandle {\n const node: IRowNode = { type: \"row\", fieldIds };\n return createLayoutNodeHandle(node);\n },\n separator(): ILayoutNodeHandle {\n const node: ISeparatorNode = { type: \"separator\" };\n return createLayoutNodeHandle(node);\n },\n tabs(config: { id?: string; tabs: ITabDefinition[] }): ILayoutNodeHandle {\n const node: ITabsNode = { type: \"tabs\", id: config.id, tabs: config.tabs };\n return createLayoutNodeHandle(node);\n },\n element(renderer: string, props?: Record<string, unknown>): ILayoutNodeHandle {\n const node: IElementNode = { type: \"element\", renderer, props };\n return createLayoutNodeHandle(node);\n },\n remove(target: string): void {\n removals.push(target);\n }\n };\n }\n\n private _accessLayoutNode(nodeId: string): ILayoutNodeAccessHandle {\n const findTabsNode = (layout: LayoutNode[]): ITabsNode | undefined => {\n for (const node of layout) {\n if (node.type === \"tabs\" && node.id === nodeId) {\n return node;\n }\n // Search inside nested tabs\n if (node.type === \"tabs\") {\n for (const tab of node.tabs) {\n const found = findTabsNode(tab.layout);\n if (found) {\n return found;\n }\n }\n }\n }\n return undefined;\n };\n\n return {\n as: (type: \"tabs\"): ITabsHandle => {\n const tabsNode = findTabsNode(this._layout);\n if (!tabsNode) {\n throw new Error(`Layout node \"${nodeId}\" not found.`);\n }\n if (tabsNode.type !== type) {\n throw new Error(\n `Layout node \"${nodeId}\" is type \"${tabsNode.type}\", not \"${type}\".`\n );\n }\n\n return {\n tab: (definitionOrId: ITabDefinition | string): ITabHandle => {\n if (typeof definitionOrId === \"string\") {\n // Access existing tab\n const tab = tabsNode.tabs.find(t => t.id === definitionOrId);\n if (!tab) {\n throw new Error(\n `Tab \"${definitionOrId}\" not found in tabs node \"${nodeId}\".`\n );\n }\n return {\n layout: (factory: (layout: ILayoutBuilder) => LayoutNode[]) => {\n const nodes = factory(layoutAPI);\n tab.layout.push(...nodes);\n },\n before: () => {\n /* no-op for existing tabs */\n },\n after: () => {\n /* no-op for existing tabs */\n }\n };\n } else {\n // Add new tab\n const newTab: ITabDefinition = { ...definitionOrId };\n // Resolve layout if it's a factory\n if (typeof (definitionOrId as any).layout === \"function\") {\n newTab.layout = (definitionOrId as any).layout(layoutAPI);\n }\n return {\n layout: (factory: (layout: ILayoutBuilder) => LayoutNode[]) => {\n newTab.layout = factory(layoutAPI);\n },\n before: (targetTabId: string) => {\n const idx = tabsNode.tabs.findIndex(t => t.id === targetTabId);\n if (idx !== -1) {\n tabsNode.tabs.splice(idx, 0, newTab);\n } else {\n tabsNode.tabs.push(newTab);\n }\n },\n after: (targetTabId: string) => {\n const idx = tabsNode.tabs.findIndex(t => t.id === targetTabId);\n if (idx !== -1) {\n tabsNode.tabs.splice(idx + 1, 0, newTab);\n } else {\n tabsNode.tabs.push(newTab);\n }\n }\n };\n }\n }\n };\n }\n };\n }\n\n private _isPositionedNode(\n entry: LayoutNode | IPositionedLayoutNode\n ): entry is IPositionedLayoutNode {\n return \"node\" in entry;\n }\n}\n\nfunction createLayoutNodeHandle(node: LayoutNode): ILayoutNodeHandle {\n const handle: ILayoutNodeHandle = {\n node,\n before(target: string): IPositionedLayoutNode {\n handle.position = { type: \"before\", target };\n return handle;\n },\n after(target: string): IPositionedLayoutNode {\n handle.position = { type: \"after\", target };\n return handle;\n },\n replace(target: string): IPositionedLayoutNode {\n handle.position = { type: \"replace\", target };\n return handle;\n }\n };\n return handle;\n}\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"names":["makeAutoObservable","computed","toJS","runInAction","observable","Field","ObjectField","isObjectField","createFieldBuilderRegistry","layoutAPI","row","fieldIds","type","separator","tabs","config","id","renderer","element","props","FormModel","_fields","Map","_layout","_baseline","_submitted","_validateOnChange","_isValid","_errors","_activeTabs","map","constructor","registry","builders","fields","name","builder","Object","entries","fieldConfig","build","field","_createField","setForm","set","layout","_warnOrphanFields","_generateDefaultLayout","validateOnSubmit","_snapshotBaseline","vm","autoBind","get","parts","split","length","current","i","getChild","undefined","Error","factory","removeField","factoryOrNodeId","_accessLayoutNode","removals","modifierLayoutAPI","_createModifierLayoutAPI","target","_removeFromLayout","entry","_isPositionedNode","node","position","_insertIntoLayout","push","delete","getData","data","getValue","setData","value","setValueSilent","_resetAllValidation","reset","baselineValue","defaultValue","isDirty","baseline","JSON","stringify","isValid","errors","validate","valid","path","label","message","validation","submit","_resolveLayout","getField","getFields","_resolveLayoutNode","filter","Boolean","_resolveRowNode","_resolveSeparatorNode","_resolveTabsNode","_resolveElementNode","f","visible","tabKey","_tabsNodeKey","tab","description","icon","hasErrors","_tabHasErrors","child","storedActive","validActive","find","t","activeTabId","setActiveTab","_collectFieldIdsFromLayout","ids","join","layoutFieldIds","Set","has","console","warn","clear","resetValidation","_findLayoutIndex","findIndex","_nodeMatchesTarget","includes","filtered","targetIndex","result","splice","createLayoutNodeHandle","remove","nodeId","findTabsNode","found","as","tabsNode","definitionOrId","nodes","before","after","newTab","targetTabId","idx","childBuilders","handle","replace"],"sources":["FormModel.ts"],"sourcesContent":["import { makeAutoObservable, computed, toJS, runInAction, observable } from \"mobx\";\nimport { Field } from \"./Field.js\";\nimport { ObjectField, isObjectField } from \"./ObjectField.js\";\nimport { createFieldBuilderRegistry } from \"./FieldBuilder.js\";\nimport type {\n IFormModel,\n IField,\n IFieldBuilder,\n IFieldBuilderRegistry,\n IObjectFieldConfig,\n IFormVM,\n IFormError,\n IFormModelConfig,\n ILayoutBuilder,\n ILayoutNodeHandle,\n ILayoutModifier,\n IPositionedLayoutNode,\n ILayoutNodeAccessHandle,\n ITabsHandle,\n ITabHandle,\n LayoutNode,\n LayoutPosition,\n LayoutNodeVM,\n IRowNode,\n IRowNodeVM,\n ISeparatorNode,\n ISeparatorNodeVM,\n ITabsNode,\n ITabsNodeVM,\n ITabDefinition,\n ITabDefinitionVM,\n IElementNode,\n IElementNodeVM\n} from \"./abstractions.js\";\n\nconst layoutAPI: ILayoutBuilder = {\n row(...fieldIds: string[]): IRowNode {\n return { type: \"row\", fieldIds };\n },\n separator(): ISeparatorNode {\n return { type: \"separator\" };\n },\n tabs(config: { id?: string; renderer?: string; tabs: ITabDefinition[] }): ITabsNode {\n return { type: \"tabs\", id: config.id, renderer: config.renderer, tabs: config.tabs };\n },\n element(renderer: string, props?: Record<string, unknown>): IElementNode {\n return { type: \"element\", renderer, props };\n }\n};\n\nexport class FormModel implements IFormModel {\n private _fields = new Map<string, IField>();\n private _layout: LayoutNode[] = [];\n private _baseline = new Map<string, unknown>();\n private _submitted = false;\n private _validateOnChange = false;\n private _isValid: boolean | null = null;\n private _errors: IFormError[] = [];\n private _activeTabs = observable.map<string, string>();\n\n constructor(config: IFormModelConfig) {\n const registry = createFieldBuilderRegistry();\n const builders = config.fields(registry);\n\n // Build fields from builders\n for (const [name, builder] of Object.entries(builders)) {\n const fieldConfig = builder.build(name);\n const field = this._createField(fieldConfig);\n field.setForm(this);\n this._fields.set(name, field);\n }\n\n // Build layout\n if (config.layout) {\n this._layout = config.layout(layoutAPI);\n this._warnOrphanFields();\n } else {\n this._layout = this._generateDefaultLayout();\n }\n\n // Validation strategy\n this._validateOnChange = config.validateOnSubmit === false;\n\n // Snapshot baseline from defaults\n this._snapshotBaseline();\n\n makeAutoObservable(\n this,\n {\n vm: computed\n },\n { autoBind: true }\n );\n }\n\n field(name: string): IField {\n // Try exact match first (supports dotted field names like \"properties.language\").\n const field = this._fields.get(name);\n if (field) {\n return field;\n }\n\n // Try dot-notation traversal through ObjectField children.\n const parts = name.split(\".\");\n if (parts.length > 1) {\n let current: IField | undefined = this._fields.get(parts[0]);\n for (let i = 1; i < parts.length && current; i++) {\n if (isObjectField(current)) {\n current = current.getChild(parts[i]);\n } else {\n current = undefined;\n }\n }\n if (current) {\n return current;\n }\n }\n\n throw new Error(`Field \"${name}\" not found.`);\n }\n\n fields(\n factory: (registry: IFieldBuilderRegistry) => Record<string, IFieldBuilder | undefined>\n ): void {\n const registry = createFieldBuilderRegistry();\n const builders = factory(registry);\n\n for (const [name, builder] of Object.entries(builders)) {\n if (builder === undefined) {\n // undefined = remove\n this.removeField(name);\n continue;\n }\n\n const fieldConfig = builder.build(name);\n const field = this._createField(fieldConfig);\n field.setForm(this);\n\n // Replace or add — same operation on the map\n this._fields.set(name, field);\n }\n\n // Re-snapshot baseline to include new fields\n this._snapshotBaseline();\n }\n\n layout(factory: (layout: ILayoutModifier) => (LayoutNode | IPositionedLayoutNode)[]): void;\n layout(nodeId: string): ILayoutNodeAccessHandle;\n layout(\n factoryOrNodeId:\n | ((layout: ILayoutModifier) => (LayoutNode | IPositionedLayoutNode)[])\n | string\n ): void | ILayoutNodeAccessHandle {\n if (typeof factoryOrNodeId === \"string\") {\n return this._accessLayoutNode(factoryOrNodeId);\n }\n\n const factory = factoryOrNodeId;\n const removals: string[] = [];\n const modifierLayoutAPI = this._createModifierLayoutAPI(removals);\n\n const entries = factory(modifierLayoutAPI);\n\n // Process removals first\n for (const target of removals) {\n this._layout = this._removeFromLayout(this._layout, target);\n }\n\n // Process additions with positional modifiers\n for (const entry of entries) {\n if (this._isPositionedNode(entry)) {\n const { node, position } = entry;\n if (position) {\n this._layout = this._insertIntoLayout(this._layout, node, position);\n } else {\n this._layout.push(node);\n }\n } else {\n this._layout.push(entry);\n }\n }\n }\n\n removeField(name: string): void {\n this._fields.delete(name);\n this._baseline.delete(name);\n\n // Remove from layout\n this._layout = this._removeFromLayout(this._layout, name);\n }\n\n getData(): Record<string, unknown> {\n const data: Record<string, unknown> = {};\n for (const [name, field] of this._fields) {\n if (isObjectField(field)) {\n data[name] = toJS(field.getData());\n } else {\n data[name] = toJS(field.getValue());\n }\n }\n return data;\n }\n\n setData(data: Record<string, unknown>): void {\n for (const [name, value] of Object.entries(data)) {\n const field = this._fields.get(name);\n if (field) {\n field.setValueSilent(value);\n }\n }\n this._snapshotBaseline();\n this._resetAllValidation();\n this._submitted = false;\n this._isValid = null;\n this._errors = [];\n }\n\n reset(): void {\n for (const [name, field] of this._fields) {\n const baselineValue = this._baseline.get(name);\n field.setValueSilent(baselineValue ?? field.config.defaultValue ?? null);\n }\n this._resetAllValidation();\n this._submitted = false;\n this._isValid = null;\n this._errors = [];\n }\n\n get isDirty(): boolean {\n for (const [name, field] of this._fields) {\n const baseline = this._baseline.get(name);\n const current = isObjectField(field) ? field.getData() : field.getValue();\n if (JSON.stringify(toJS(current)) !== JSON.stringify(toJS(baseline))) {\n return true;\n }\n }\n return false;\n }\n\n get isValid(): boolean | null {\n return this._isValid;\n }\n\n get errors(): IFormError[] {\n return this._errors;\n }\n\n async validate(): Promise<boolean> {\n const errors: IFormError[] = [];\n\n for (const [, field] of this._fields) {\n const valid = await field.validate();\n if (!valid) {\n errors.push({\n path: field.name,\n label: field.config.label,\n message: field.vm.validation.message || \"Invalid value.\"\n });\n }\n }\n\n const isValid = errors.length === 0;\n runInAction(() => {\n this._errors = errors;\n this._isValid = isValid;\n this._submitted = true;\n });\n return isValid;\n }\n\n async submit<T = Record<string, unknown>>(): Promise<T | false> {\n const valid = await this.validate();\n if (!valid) {\n return false;\n }\n return this.getData() as T;\n }\n\n get vm(): IFormVM {\n return {\n layout: this._resolveLayout(),\n errors: this._errors,\n isDirty: this.isDirty,\n isValid: this._isValid\n };\n }\n\n getField(name: string): IField | undefined {\n return this._fields.get(name);\n }\n\n getFields(): Map<string, IField> {\n return this._fields;\n }\n\n private _resolveLayout(): LayoutNodeVM[] {\n return this._layout\n .map(node => this._resolveLayoutNode(node))\n .filter(Boolean) as LayoutNodeVM[];\n }\n\n private _resolveLayoutNode(node: LayoutNode): LayoutNodeVM | null {\n switch (node.type) {\n case \"row\":\n return this._resolveRowNode(node);\n case \"separator\":\n return this._resolveSeparatorNode();\n case \"tabs\":\n return this._resolveTabsNode(node);\n case \"element\":\n return this._resolveElementNode(node);\n default:\n return null;\n }\n }\n\n private _resolveRowNode(node: IRowNode): IRowNodeVM | null {\n const fields = node.fieldIds\n .map(id => this._fields.get(id))\n .filter((f): f is IField => f !== undefined && f.visible)\n .map(f => f.vm);\n\n if (fields.length === 0) {\n return null;\n }\n\n return { type: \"row\", fields };\n }\n\n private _resolveSeparatorNode(): ISeparatorNodeVM {\n return { type: \"separator\" };\n }\n\n private _resolveTabsNode(node: ITabsNode): ITabsNodeVM | null {\n if (node.tabs.length === 0) {\n return null;\n }\n\n const tabKey = node.id || this._tabsNodeKey(node);\n\n const tabs: ITabDefinitionVM[] = node.tabs.map(tab => ({\n id: tab.id,\n label: tab.label,\n description: tab.description,\n icon: tab.icon,\n hasErrors: this._tabHasErrors(tab.layout),\n layout: tab.layout\n .map(child => this._resolveLayoutNode(child))\n .filter(Boolean) as LayoutNodeVM[]\n }));\n\n if (tabs.length === 0) {\n return null;\n }\n\n // Resolve active tab — fall back to first tab if stored value is invalid\n const storedActive = this._activeTabs.get(tabKey);\n const validActive = tabs.find(t => t.id === storedActive) ? storedActive! : tabs[0].id;\n\n return {\n type: \"tabs\",\n id: node.id,\n renderer: node.renderer,\n tabs,\n activeTabId: validActive,\n setActiveTab: (id: string) => {\n runInAction(() => {\n this._activeTabs.set(tabKey, id);\n });\n }\n };\n }\n\n private _resolveElementNode(node: IElementNode): IElementNodeVM {\n return {\n type: \"element\",\n renderer: node.renderer,\n props: node.props\n };\n }\n\n private _tabHasErrors(layout: LayoutNode[]): boolean {\n const fieldIds = this._collectFieldIdsFromLayout(layout);\n for (const id of fieldIds) {\n const field = this._fields.get(id);\n if (!field) {\n continue;\n }\n if (field.vm.validation.isValid === false) {\n return true;\n }\n if (isObjectField(field) && field.hasErrors) {\n return true;\n }\n }\n return false;\n }\n\n private _collectFieldIdsFromLayout(layout: LayoutNode[]): string[] {\n const ids: string[] = [];\n for (const node of layout) {\n if (node.type === \"row\") {\n ids.push(...node.fieldIds);\n } else if (node.type === \"tabs\") {\n for (const tab of node.tabs) {\n ids.push(...this._collectFieldIdsFromLayout(tab.layout));\n }\n }\n }\n return ids;\n }\n\n private _tabsNodeKey(node: ITabsNode): string {\n return `__tabs_${node.tabs.map(t => t.id).join(\"_\")}`;\n }\n\n private _generateDefaultLayout(): LayoutNode[] {\n const layout: LayoutNode[] = [];\n for (const [name, field] of this._fields) {\n if (field.visible) {\n layout.push({ type: \"row\", fieldIds: [name] });\n }\n }\n return layout;\n }\n\n private _warnOrphanFields(): void {\n const layoutFieldIds = new Set(this._collectFieldIdsFromLayout(this._layout));\n\n for (const [name, field] of this._fields) {\n if (field.visible && !layoutFieldIds.has(name)) {\n console.warn(\n `[FormModel] Field \"${name}\" is not in the layout and not marked as .hidden(). ` +\n `Add it to the layout or mark it as .hidden() to suppress this warning.`\n );\n }\n }\n }\n\n private _snapshotBaseline(): void {\n this._baseline.clear();\n for (const [name, field] of this._fields) {\n this._baseline.set(name, toJS(field.getValue()));\n }\n }\n\n private _resetAllValidation(): void {\n for (const [, field] of this._fields) {\n field.resetValidation();\n }\n }\n\n /**\n * Find the index of a layout node that matches the given target.\n * Matches: row containing fieldId, tabs by id, element by id/renderer.\n * Returns -1 if not found.\n */\n private _findLayoutIndex(layout: LayoutNode[], target: string): number {\n return layout.findIndex(node => this._nodeMatchesTarget(node, target));\n }\n\n private _nodeMatchesTarget(node: LayoutNode, target: string): boolean {\n switch (node.type) {\n case \"row\":\n return node.fieldIds.includes(target);\n case \"tabs\":\n return node.id === target;\n case \"element\":\n return node.id === target || node.renderer === target;\n default:\n return false;\n }\n }\n\n /**\n * Remove a target from the layout tree. Handles field IDs in rows,\n * and node IDs for tabs/elements. Drops rows that become empty.\n */\n private _removeFromLayout(layout: LayoutNode[], target: string): LayoutNode[] {\n return layout\n .map(node => {\n if (node.type === \"row\") {\n const filtered = node.fieldIds.filter(id => id !== target);\n if (filtered.length === 0) {\n return null;\n }\n return { ...node, fieldIds: filtered };\n }\n // Remove tabs/elements by their ID\n if (\n (node.type === \"tabs\" && node.id === target) ||\n (node.type === \"element\" && (node.id === target || node.renderer === target))\n ) {\n return null;\n }\n return node;\n })\n .filter(Boolean) as LayoutNode[];\n }\n\n /**\n * Insert a layout node relative to a target field ID.\n */\n private _insertIntoLayout(\n layout: LayoutNode[],\n node: LayoutNode,\n position: LayoutPosition\n ): LayoutNode[] {\n const targetIndex = this._findLayoutIndex(layout, position.target);\n\n if (targetIndex === -1) {\n // Target not found — append\n return [...layout, node];\n }\n\n const result = [...layout];\n\n switch (position.type) {\n case \"before\":\n result.splice(targetIndex, 0, node);\n break;\n case \"after\":\n result.splice(targetIndex + 1, 0, node);\n break;\n case \"replace\":\n result.splice(targetIndex, 1, node);\n break;\n }\n\n return result;\n }\n\n private _createModifierLayoutAPI(removals: string[]): ILayoutModifier {\n return {\n row(...fieldIds: string[]): ILayoutNodeHandle {\n const node: IRowNode = { type: \"row\", fieldIds };\n return createLayoutNodeHandle(node);\n },\n separator(): ILayoutNodeHandle {\n const node: ISeparatorNode = { type: \"separator\" };\n return createLayoutNodeHandle(node);\n },\n tabs(config: {\n id?: string;\n renderer?: string;\n tabs: ITabDefinition[];\n }): ILayoutNodeHandle {\n const node: ITabsNode = {\n type: \"tabs\",\n id: config.id,\n renderer: config.renderer,\n tabs: config.tabs\n };\n return createLayoutNodeHandle(node);\n },\n element(renderer: string, props?: Record<string, unknown>): ILayoutNodeHandle {\n const node: IElementNode = { type: \"element\", renderer, props };\n return createLayoutNodeHandle(node);\n },\n remove(target: string): void {\n removals.push(target);\n }\n };\n }\n\n private _accessLayoutNode(nodeId: string): ILayoutNodeAccessHandle {\n const findTabsNode = (layout: LayoutNode[]): ITabsNode | undefined => {\n for (const node of layout) {\n if (node.type === \"tabs\" && node.id === nodeId) {\n return node;\n }\n // Search inside nested tabs\n if (node.type === \"tabs\") {\n for (const tab of node.tabs) {\n const found = findTabsNode(tab.layout);\n if (found) {\n return found;\n }\n }\n }\n }\n return undefined;\n };\n\n return {\n as: (type: \"tabs\"): ITabsHandle => {\n const tabsNode = findTabsNode(this._layout);\n if (!tabsNode) {\n throw new Error(`Layout node \"${nodeId}\" not found.`);\n }\n if (tabsNode.type !== type) {\n throw new Error(\n `Layout node \"${nodeId}\" is type \"${tabsNode.type}\", not \"${type}\".`\n );\n }\n\n return {\n tab: (definitionOrId: ITabDefinition | string): ITabHandle => {\n if (typeof definitionOrId === \"string\") {\n // Access existing tab\n const tab = tabsNode.tabs.find(t => t.id === definitionOrId);\n if (!tab) {\n throw new Error(\n `Tab \"${definitionOrId}\" not found in tabs node \"${nodeId}\".`\n );\n }\n return {\n layout: (factory: (layout: ILayoutBuilder) => LayoutNode[]) => {\n const nodes = factory(layoutAPI);\n tab.layout.push(...nodes);\n },\n before: () => {\n /* no-op for existing tabs */\n },\n after: () => {\n /* no-op for existing tabs */\n }\n };\n } else {\n // Add new tab\n const newTab: ITabDefinition = { ...definitionOrId };\n // Resolve layout if it's a factory\n if (typeof (definitionOrId as any).layout === \"function\") {\n newTab.layout = (definitionOrId as any).layout(layoutAPI);\n }\n return {\n layout: (factory: (layout: ILayoutBuilder) => LayoutNode[]) => {\n newTab.layout = factory(layoutAPI);\n },\n before: (targetTabId: string) => {\n const idx = tabsNode.tabs.findIndex(t => t.id === targetTabId);\n if (idx !== -1) {\n tabsNode.tabs.splice(idx, 0, newTab);\n } else {\n tabsNode.tabs.push(newTab);\n }\n },\n after: (targetTabId: string) => {\n const idx = tabsNode.tabs.findIndex(t => t.id === targetTabId);\n if (idx !== -1) {\n tabsNode.tabs.splice(idx + 1, 0, newTab);\n } else {\n tabsNode.tabs.push(newTab);\n }\n }\n };\n }\n }\n };\n }\n };\n }\n\n private _createField(config: any): IField {\n if (config.childBuilders) {\n return new ObjectField(config as IObjectFieldConfig);\n }\n return new Field(config);\n }\n\n private _isPositionedNode(\n entry: LayoutNode | IPositionedLayoutNode\n ): entry is IPositionedLayoutNode {\n return \"node\" in entry;\n }\n}\n\nfunction createLayoutNodeHandle(node: LayoutNode): ILayoutNodeHandle {\n const handle: ILayoutNodeHandle = {\n node,\n before(target: string): IPositionedLayoutNode {\n handle.position = { type: \"before\", target };\n return handle;\n },\n after(target: string): IPositionedLayoutNode {\n handle.position = { type: \"after\", target };\n return handle;\n },\n replace(target: string): IPositionedLayoutNode {\n handle.position = { type: \"replace\", target };\n return handle;\n }\n };\n return handle;\n}\n"],"mappings":"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","ignoreList":[]}
@@ -1135,6 +1135,389 @@ describe("FormModel", () => {
1135
1135
  });
1136
1136
  });
1137
1137
  });
1138
+ describe("object fields (Phase 6)", () => {
1139
+ describe("non-list object field", () => {
1140
+ function createFormWithObject() {
1141
+ return new FormModel({
1142
+ fields: fields => ({
1143
+ title: fields.text().label("Title"),
1144
+ address: fields.object().label("Address").fields(f => ({
1145
+ street: f.text().label("Street").required("Street is required"),
1146
+ city: f.text().label("City").required("City is required")
1147
+ }))
1148
+ }),
1149
+ layout: layout => [layout.row("title"), layout.row("address")]
1150
+ });
1151
+ }
1152
+ it("should create an object field with children", () => {
1153
+ const form = createFormWithObject();
1154
+ const field = form.field("address");
1155
+ expect(field).toBeDefined();
1156
+ expect(field.type).toBe("object");
1157
+ });
1158
+ it("should access child fields via dot-notation", () => {
1159
+ const form = createFormWithObject();
1160
+ const street = form.field("address.street");
1161
+ expect(street).toBeDefined();
1162
+ expect(street.type).toBe("text");
1163
+ });
1164
+ it("should throw on invalid dot-notation", () => {
1165
+ const form = createFormWithObject();
1166
+ expect(() => form.field("address.zipcode")).toThrow('Field "address.zipcode" not found.');
1167
+ });
1168
+ it("should return nested object from getData", () => {
1169
+ const form = createFormWithObject();
1170
+ form.field("address.street").setValue("123 Main St");
1171
+ form.field("address.city").setValue("Springfield");
1172
+ const data = form.getData();
1173
+ expect(data.address).toEqual({
1174
+ street: "123 Main St",
1175
+ city: "Springfield"
1176
+ });
1177
+ });
1178
+ it("should hydrate children from setData", () => {
1179
+ const form = createFormWithObject();
1180
+ form.setData({
1181
+ title: "Home",
1182
+ address: {
1183
+ street: "456 Oak Ave",
1184
+ city: "Portland"
1185
+ }
1186
+ });
1187
+ expect(form.field("address.street").getValue()).toBe("456 Oak Ave");
1188
+ expect(form.field("address.city").getValue()).toBe("Portland");
1189
+ });
1190
+ it("should not be dirty after setData", () => {
1191
+ const form = createFormWithObject();
1192
+ form.setData({
1193
+ title: "Home",
1194
+ address: {
1195
+ street: "456 Oak Ave",
1196
+ city: "Portland"
1197
+ }
1198
+ });
1199
+ expect(form.isDirty).toBe(false);
1200
+ });
1201
+ it("should be dirty after changing a child field", () => {
1202
+ const form = createFormWithObject();
1203
+ form.setData({
1204
+ title: "Home",
1205
+ address: {
1206
+ street: "456 Oak Ave",
1207
+ city: "Portland"
1208
+ }
1209
+ });
1210
+ form.field("address.street").setValue("789 Pine Rd");
1211
+ expect(form.isDirty).toBe(true);
1212
+ });
1213
+ it("should validate children recursively", async () => {
1214
+ const form = createFormWithObject();
1215
+ const valid = await form.validate();
1216
+ expect(valid).toBe(false);
1217
+ expect(form.errors.length).toBeGreaterThan(0);
1218
+ // The object field itself reports the error
1219
+ expect(form.errors.some(e => e.path === "address")).toBe(true);
1220
+ });
1221
+ it("should pass validation when children are valid", async () => {
1222
+ const form = createFormWithObject();
1223
+ form.field("title").setValue("Home");
1224
+ form.field("address.street").setValue("123 Main St");
1225
+ form.field("address.city").setValue("Springfield");
1226
+ const valid = await form.validate();
1227
+ expect(valid).toBe(true);
1228
+ });
1229
+ it("should expose IObjectFieldVM from field.vm", () => {
1230
+ const form = createFormWithObject();
1231
+ form.field("address.street").setValue("123 Main St");
1232
+ form.field("address.city").setValue("Springfield");
1233
+ const vm = form.field("address").vm;
1234
+ expect(vm.type).toBe("object");
1235
+ expect(vm.isList).toBe(false);
1236
+ expect(vm.fields).toHaveLength(2);
1237
+ expect(vm.fields[0].name).toBe("street");
1238
+ expect(vm.fields[0].value).toBe("123 Main St");
1239
+ expect(vm.fields[1].name).toBe("city");
1240
+ expect(vm.items).toHaveLength(0);
1241
+ });
1242
+ it("should render object field in a row via default layout", () => {
1243
+ const form = new FormModel({
1244
+ fields: fields => ({
1245
+ address: fields.object().label("Address").fields(f => ({
1246
+ street: f.text().label("Street"),
1247
+ city: f.text().label("City")
1248
+ }))
1249
+ })
1250
+ });
1251
+ const vm = form.vm;
1252
+ expect(vm.layout).toHaveLength(1);
1253
+ expect(vm.layout[0].type).toBe("row");
1254
+ const row = asRow(vm.layout[0]);
1255
+ expect(row.fields[0].type).toBe("object");
1256
+ expect(row.fields[0].name).toBe("address");
1257
+ });
1258
+ it("should reset to baseline values", () => {
1259
+ const form = createFormWithObject();
1260
+ form.setData({
1261
+ title: "Home",
1262
+ address: {
1263
+ street: "Original St",
1264
+ city: "Original City"
1265
+ }
1266
+ });
1267
+ form.field("address.street").setValue("Changed St");
1268
+ expect(form.isDirty).toBe(true);
1269
+ form.reset();
1270
+ expect(form.field("address.street").getValue()).toBe("Original St");
1271
+ expect(form.isDirty).toBe(false);
1272
+ });
1273
+ it("should submit nested data when valid", async () => {
1274
+ const form = createFormWithObject();
1275
+ form.field("title").setValue("Home");
1276
+ form.field("address.street").setValue("123 Main St");
1277
+ form.field("address.city").setValue("Springfield");
1278
+ const result = await form.submit();
1279
+ expect(result).toEqual({
1280
+ title: "Home",
1281
+ address: {
1282
+ street: "123 Main St",
1283
+ city: "Springfield"
1284
+ }
1285
+ });
1286
+ });
1287
+ });
1288
+ describe("list object field", () => {
1289
+ function createFormWithList() {
1290
+ return new FormModel({
1291
+ fields: fields => ({
1292
+ presets: fields.object().label("Presets").fields(f => ({
1293
+ name: f.text().label("Name").required("Name is required"),
1294
+ model: f.text().label("Model").required("Model is required")
1295
+ })).list()
1296
+ }),
1297
+ layout: layout => [layout.row("presets")]
1298
+ });
1299
+ }
1300
+ it("should create a list object field", () => {
1301
+ const form = createFormWithList();
1302
+ const field = form.field("presets");
1303
+ expect(field.type).toBe("object");
1304
+ });
1305
+ it("should return empty array from getData initially", () => {
1306
+ const form = createFormWithList();
1307
+ expect(form.getData().presets).toEqual([]);
1308
+ });
1309
+ it("should add items via the field VM", () => {
1310
+ const form = createFormWithList();
1311
+ const vm = form.field("presets").vm;
1312
+ expect(vm.isList).toBe(true);
1313
+ expect(vm.items).toHaveLength(0);
1314
+ vm.addItem();
1315
+ const updatedVm = form.field("presets").vm;
1316
+ expect(updatedVm.items).toHaveLength(1);
1317
+ expect(updatedVm.items[0].fields).toHaveLength(2);
1318
+ expect(updatedVm.items[0].fields[0].name).toBe("name");
1319
+ });
1320
+ it("should hydrate list from setData", () => {
1321
+ const form = createFormWithList();
1322
+ form.setData({
1323
+ presets: [{
1324
+ name: "Default",
1325
+ model: "claude-sonnet"
1326
+ }, {
1327
+ name: "Fast",
1328
+ model: "claude-haiku"
1329
+ }]
1330
+ });
1331
+ const data = form.getData();
1332
+ expect(data.presets).toEqual([{
1333
+ name: "Default",
1334
+ model: "claude-sonnet"
1335
+ }, {
1336
+ name: "Fast",
1337
+ model: "claude-haiku"
1338
+ }]);
1339
+ });
1340
+ it("should expose items via IObjectFieldVM", () => {
1341
+ const form = createFormWithList();
1342
+ form.setData({
1343
+ presets: [{
1344
+ name: "Default",
1345
+ model: "claude-sonnet"
1346
+ }, {
1347
+ name: "Fast",
1348
+ model: "claude-haiku"
1349
+ }]
1350
+ });
1351
+ const vm = form.field("presets").vm;
1352
+ expect(vm.items).toHaveLength(2);
1353
+ expect(vm.items[0].fields[0].value).toBe("Default");
1354
+ expect(vm.items[1].fields[1].value).toBe("claude-haiku");
1355
+ });
1356
+ it("should remove items via item.remove()", () => {
1357
+ const form = createFormWithList();
1358
+ form.setData({
1359
+ presets: [{
1360
+ name: "Default",
1361
+ model: "claude-sonnet"
1362
+ }, {
1363
+ name: "Fast",
1364
+ model: "claude-haiku"
1365
+ }]
1366
+ });
1367
+ const vm = form.field("presets").vm;
1368
+ vm.items[0].remove();
1369
+ expect(form.getData().presets).toEqual([{
1370
+ name: "Fast",
1371
+ model: "claude-haiku"
1372
+ }]);
1373
+ });
1374
+ it("should remove items via removeItem()", () => {
1375
+ const form = createFormWithList();
1376
+ form.setData({
1377
+ presets: [{
1378
+ name: "A",
1379
+ model: "a"
1380
+ }, {
1381
+ name: "B",
1382
+ model: "b"
1383
+ }, {
1384
+ name: "C",
1385
+ model: "c"
1386
+ }]
1387
+ });
1388
+ const vm = form.field("presets").vm;
1389
+ vm.removeItem(1);
1390
+ expect(form.getData().presets).toEqual([{
1391
+ name: "A",
1392
+ model: "a"
1393
+ }, {
1394
+ name: "C",
1395
+ model: "c"
1396
+ }]);
1397
+ });
1398
+ it("should validate all items", async () => {
1399
+ const form = createFormWithList();
1400
+ form.setData({
1401
+ presets: [{
1402
+ name: "Default",
1403
+ model: "claude-sonnet"
1404
+ }, {
1405
+ name: "",
1406
+ model: ""
1407
+ }]
1408
+ });
1409
+ const valid = await form.validate();
1410
+ expect(valid).toBe(false);
1411
+ });
1412
+ it("should pass validation when all items are valid", async () => {
1413
+ const form = createFormWithList();
1414
+ form.setData({
1415
+ presets: [{
1416
+ name: "Default",
1417
+ model: "claude-sonnet"
1418
+ }, {
1419
+ name: "Fast",
1420
+ model: "claude-haiku"
1421
+ }]
1422
+ });
1423
+ const valid = await form.validate();
1424
+ expect(valid).toBe(true);
1425
+ });
1426
+ it("should validate with listSchema", async () => {
1427
+ const form = new FormModel({
1428
+ fields: fields => ({
1429
+ presets: fields.object().label("Presets").fields(f => ({
1430
+ name: f.text().label("Name")
1431
+ })).list().listSchema(z.array(z.any()).min(2, "At least 2 presets are required"))
1432
+ })
1433
+ });
1434
+ form.setData({
1435
+ presets: [{
1436
+ name: "Only one"
1437
+ }]
1438
+ });
1439
+ const valid = await form.validate();
1440
+ expect(valid).toBe(false);
1441
+ expect(form.errors[0].message).toBe("At least 2 presets are required");
1442
+ });
1443
+ it("should be dirty after adding an item", () => {
1444
+ const form = createFormWithList();
1445
+ form.setData({
1446
+ presets: []
1447
+ });
1448
+ expect(form.isDirty).toBe(false);
1449
+ const vm = form.field("presets").vm;
1450
+ vm.addItem();
1451
+ expect(form.isDirty).toBe(true);
1452
+ });
1453
+ it("should have stable keys across re-renders", () => {
1454
+ const form = createFormWithList();
1455
+ form.setData({
1456
+ presets: [{
1457
+ name: "A",
1458
+ model: "a"
1459
+ }, {
1460
+ name: "B",
1461
+ model: "b"
1462
+ }]
1463
+ });
1464
+ const vm1 = form.field("presets").vm;
1465
+ const key0 = vm1.items[0].key;
1466
+ const key1 = vm1.items[1].key;
1467
+
1468
+ // Re-read VM — keys should be the same
1469
+ const vm2 = form.field("presets").vm;
1470
+ expect(vm2.items[0].key).toBe(key0);
1471
+ expect(vm2.items[1].key).toBe(key1);
1472
+ });
1473
+ it("should pass empty list validation when not required", async () => {
1474
+ const form = createFormWithList();
1475
+ const valid = await form.validate();
1476
+ expect(valid).toBe(true);
1477
+ });
1478
+ it("should modify item field values via VM onChange", () => {
1479
+ const form = createFormWithList();
1480
+ form.setData({
1481
+ presets: [{
1482
+ name: "Default",
1483
+ model: "claude-sonnet"
1484
+ }]
1485
+ });
1486
+ const vm = form.field("presets").vm;
1487
+ vm.items[0].fields[0].onChange("Updated");
1488
+ expect(form.getData().presets[0].name).toBe("Updated");
1489
+ });
1490
+ });
1491
+ describe("hasErrors rollup through tabs", () => {
1492
+ it("should report hasErrors in tabs containing object fields", async () => {
1493
+ const form = new FormModel({
1494
+ fields: fields => ({
1495
+ title: fields.text().label("Title"),
1496
+ address: fields.object().label("Address").fields(f => ({
1497
+ street: f.text().label("Street").required("Required")
1498
+ }))
1499
+ }),
1500
+ layout: layout => [layout.tabs({
1501
+ id: "settings",
1502
+ tabs: [{
1503
+ id: "general",
1504
+ label: "General",
1505
+ layout: [layout.row("title")]
1506
+ }, {
1507
+ id: "details",
1508
+ label: "Details",
1509
+ layout: [layout.row("address")]
1510
+ }]
1511
+ })]
1512
+ });
1513
+ form.field("title").setValue("Hello");
1514
+ await form.validate();
1515
+ const tabsNode = form.vm.layout[0];
1516
+ expect(tabsNode.tabs[0].hasErrors).toBe(false);
1517
+ expect(tabsNode.tabs[1].hasErrors).toBe(true);
1518
+ });
1519
+ });
1520
+ });
1138
1521
  });
1139
1522
 
1140
1523
  //# sourceMappingURL=FormModel.test.js.map