@flowdrop/flowdrop 1.0.1 → 1.2.0

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 (385) hide show
  1. package/README.md +50 -50
  2. package/dist/adapters/WorkflowAdapter.d.ts +1 -1
  3. package/dist/adapters/WorkflowAdapter.js +25 -25
  4. package/dist/adapters/agentspec/AgentSpecAdapter.d.ts +2 -2
  5. package/dist/adapters/agentspec/AgentSpecAdapter.js +133 -122
  6. package/dist/adapters/agentspec/agentAdapter.d.ts +2 -2
  7. package/dist/adapters/agentspec/agentAdapter.js +10 -10
  8. package/dist/adapters/agentspec/autoLayout.d.ts +1 -1
  9. package/dist/adapters/agentspec/autoLayout.js +2 -2
  10. package/dist/adapters/agentspec/componentTypeDefaults.d.ts +1 -1
  11. package/dist/adapters/agentspec/componentTypeDefaults.js +120 -120
  12. package/dist/adapters/agentspec/defaultNodeTypes.d.ts +2 -2
  13. package/dist/adapters/agentspec/defaultNodeTypes.js +307 -307
  14. package/dist/adapters/agentspec/index.d.ts +10 -10
  15. package/dist/adapters/agentspec/index.js +6 -6
  16. package/dist/adapters/agentspec/validator.d.ts +2 -2
  17. package/dist/adapters/agentspec/validator.js +22 -20
  18. package/dist/api/enhanced-client.d.ts +3 -3
  19. package/dist/api/enhanced-client.js +73 -72
  20. package/dist/components/App.svelte +1090 -961
  21. package/dist/components/App.svelte.d.ts +9 -6
  22. package/dist/components/CanvasBanner.stories.svelte +23 -20
  23. package/dist/components/CanvasBanner.stories.svelte.d.ts +1 -1
  24. package/dist/components/CanvasBanner.svelte +52 -46
  25. package/dist/components/ConfigForm.svelte +1164 -1065
  26. package/dist/components/ConfigForm.svelte.d.ts +2 -2
  27. package/dist/components/ConfigModal.svelte +180 -180
  28. package/dist/components/ConfigModal.svelte.d.ts +1 -1
  29. package/dist/components/ConfigPanel.stories.svelte +35 -35
  30. package/dist/components/ConfigPanel.stories.svelte.d.ts +1 -1
  31. package/dist/components/ConfigPanel.svelte +178 -167
  32. package/dist/components/ConfigPanel.svelte.d.ts +1 -1
  33. package/dist/components/ConnectionLine.svelte +25 -25
  34. package/dist/components/EdgeRefresher.svelte +26 -26
  35. package/dist/components/FlowDropEdge.stories.svelte +179 -143
  36. package/dist/components/FlowDropEdge.svelte +147 -147
  37. package/dist/components/FlowDropEdge.svelte.d.ts +1 -1
  38. package/dist/components/FlowDropZone.svelte +63 -60
  39. package/dist/components/FlowDropZone.svelte.d.ts +1 -1
  40. package/dist/components/LoadingSpinner.stories.svelte +19 -19
  41. package/dist/components/LoadingSpinner.stories.svelte.d.ts +1 -1
  42. package/dist/components/LoadingSpinner.svelte +21 -21
  43. package/dist/components/LoadingSpinner.svelte.d.ts +1 -1
  44. package/dist/components/Logo.stories.svelte +13 -13
  45. package/dist/components/Logo.stories.svelte.d.ts +1 -1
  46. package/dist/components/Logo.svelte +101 -95
  47. package/dist/components/LogsSidebar.svelte +553 -546
  48. package/dist/components/LogsSidebar.svelte.d.ts +1 -1
  49. package/dist/components/MarkdownDisplay.stories.svelte +29 -23
  50. package/dist/components/MarkdownDisplay.stories.svelte.d.ts +1 -1
  51. package/dist/components/MarkdownDisplay.svelte +16 -14
  52. package/dist/components/Navbar.stories.svelte +43 -38
  53. package/dist/components/Navbar.stories.svelte.d.ts +1 -1
  54. package/dist/components/Navbar.svelte +760 -706
  55. package/dist/components/Navbar.svelte.d.ts +1 -1
  56. package/dist/components/NodeSidebar.svelte +905 -746
  57. package/dist/components/NodeSidebar.svelte.d.ts +5 -1
  58. package/dist/components/NodeStatusOverlay.stories.svelte +82 -70
  59. package/dist/components/NodeStatusOverlay.stories.svelte.d.ts +1 -1
  60. package/dist/components/NodeStatusOverlay.svelte +295 -280
  61. package/dist/components/NodeStatusOverlay.svelte.d.ts +3 -3
  62. package/dist/components/PipelineStatus.svelte +326 -300
  63. package/dist/components/PipelineStatus.svelte.d.ts +4 -4
  64. package/dist/components/PortCoordinateTracker.svelte +49 -47
  65. package/dist/components/PortCoordinateTracker.svelte.d.ts +1 -1
  66. package/dist/components/ReadOnlyDetails.svelte +156 -156
  67. package/dist/components/SchemaForm.stories.svelte +106 -98
  68. package/dist/components/SchemaForm.stories.svelte.d.ts +1 -1
  69. package/dist/components/SchemaForm.svelte +490 -463
  70. package/dist/components/SchemaForm.svelte.d.ts +2 -2
  71. package/dist/components/SettingsModal.svelte +226 -223
  72. package/dist/components/SettingsModal.svelte.d.ts +1 -1
  73. package/dist/components/SettingsPanel.svelte +637 -601
  74. package/dist/components/SettingsPanel.svelte.d.ts +1 -1
  75. package/dist/components/StatusIcon.stories.svelte +62 -49
  76. package/dist/components/StatusIcon.stories.svelte.d.ts +1 -1
  77. package/dist/components/StatusIcon.svelte +87 -87
  78. package/dist/components/StatusIcon.svelte.d.ts +2 -2
  79. package/dist/components/StatusLabel.stories.svelte +12 -12
  80. package/dist/components/StatusLabel.stories.svelte.d.ts +1 -1
  81. package/dist/components/StatusLabel.svelte +19 -19
  82. package/dist/components/ThemeToggle.stories.svelte +16 -16
  83. package/dist/components/ThemeToggle.stories.svelte.d.ts +1 -1
  84. package/dist/components/ThemeToggle.svelte +180 -169
  85. package/dist/components/ThemeToggle.svelte.d.ts +1 -1
  86. package/dist/components/UniversalNode.svelte +150 -138
  87. package/dist/components/UniversalNode.svelte.d.ts +3 -3
  88. package/dist/components/WorkflowEditor.svelte +1069 -1014
  89. package/dist/components/WorkflowEditor.svelte.d.ts +4 -4
  90. package/dist/components/form/FormArray.svelte +1034 -973
  91. package/dist/components/form/FormArray.svelte.d.ts +1 -1
  92. package/dist/components/form/FormAutocomplete.svelte +1021 -978
  93. package/dist/components/form/FormAutocomplete.svelte.d.ts +1 -1
  94. package/dist/components/form/FormCheckboxGroup.stories.svelte +23 -20
  95. package/dist/components/form/FormCheckboxGroup.stories.svelte.d.ts +1 -1
  96. package/dist/components/form/FormCheckboxGroup.svelte +136 -136
  97. package/dist/components/form/FormCodeEditor.svelte +452 -434
  98. package/dist/components/form/FormField.svelte +366 -355
  99. package/dist/components/form/FormField.svelte.d.ts +2 -2
  100. package/dist/components/form/FormFieldLight.svelte +400 -384
  101. package/dist/components/form/FormFieldLight.svelte.d.ts +1 -1
  102. package/dist/components/form/FormFieldWrapper.stories.svelte +42 -42
  103. package/dist/components/form/FormFieldWrapper.stories.svelte.d.ts +1 -1
  104. package/dist/components/form/FormFieldWrapper.svelte +100 -93
  105. package/dist/components/form/FormFieldWrapper.svelte.d.ts +1 -1
  106. package/dist/components/form/FormFieldset.svelte +108 -108
  107. package/dist/components/form/FormFieldset.svelte.d.ts +2 -2
  108. package/dist/components/form/FormMarkdownEditor.svelte +758 -725
  109. package/dist/components/form/FormNumberField.stories.svelte +25 -25
  110. package/dist/components/form/FormNumberField.stories.svelte.d.ts +1 -1
  111. package/dist/components/form/FormNumberField.svelte +88 -88
  112. package/dist/components/form/FormRangeField.stories.svelte +20 -20
  113. package/dist/components/form/FormRangeField.stories.svelte.d.ts +1 -1
  114. package/dist/components/form/FormRangeField.svelte +234 -226
  115. package/dist/components/form/FormSelect.stories.svelte +38 -38
  116. package/dist/components/form/FormSelect.stories.svelte.d.ts +1 -1
  117. package/dist/components/form/FormSelect.svelte +101 -101
  118. package/dist/components/form/FormSelect.svelte.d.ts +1 -1
  119. package/dist/components/form/FormTemplateEditor.svelte +847 -798
  120. package/dist/components/form/FormTemplateEditor.svelte.d.ts +1 -1
  121. package/dist/components/form/FormTextField.stories.svelte +29 -23
  122. package/dist/components/form/FormTextField.stories.svelte.d.ts +1 -1
  123. package/dist/components/form/FormTextField.svelte +68 -68
  124. package/dist/components/form/FormTextarea.stories.svelte +28 -25
  125. package/dist/components/form/FormTextarea.stories.svelte.d.ts +1 -1
  126. package/dist/components/form/FormTextarea.svelte +74 -74
  127. package/dist/components/form/FormToggle.stories.svelte +23 -20
  128. package/dist/components/form/FormToggle.stories.svelte.d.ts +1 -1
  129. package/dist/components/form/FormToggle.svelte +98 -98
  130. package/dist/components/form/FormUISchemaRenderer.svelte +120 -113
  131. package/dist/components/form/FormUISchemaRenderer.svelte.d.ts +3 -3
  132. package/dist/components/form/index.d.ts +19 -19
  133. package/dist/components/form/index.js +18 -18
  134. package/dist/components/form/templateAutocomplete.d.ts +2 -2
  135. package/dist/components/form/templateAutocomplete.js +64 -55
  136. package/dist/components/form/types.d.ts +6 -6
  137. package/dist/components/form/types.js +9 -4
  138. package/dist/components/icons/AlertCircleIcon.svelte +11 -0
  139. package/dist/components/icons/AlertCircleIcon.svelte.d.ts +26 -0
  140. package/dist/components/icons/CogIcon.svelte +11 -0
  141. package/dist/components/icons/CogIcon.svelte.d.ts +26 -0
  142. package/dist/components/interrupt/ChoicePrompt.stories.svelte +54 -38
  143. package/dist/components/interrupt/ChoicePrompt.stories.svelte.d.ts +1 -1
  144. package/dist/components/interrupt/ChoicePrompt.svelte +407 -383
  145. package/dist/components/interrupt/ChoicePrompt.svelte.d.ts +1 -1
  146. package/dist/components/interrupt/ConfirmationPrompt.stories.svelte +48 -48
  147. package/dist/components/interrupt/ConfirmationPrompt.stories.svelte.d.ts +1 -1
  148. package/dist/components/interrupt/ConfirmationPrompt.svelte +280 -274
  149. package/dist/components/interrupt/ConfirmationPrompt.svelte.d.ts +1 -1
  150. package/dist/components/interrupt/FormPrompt.svelte +223 -218
  151. package/dist/components/interrupt/FormPrompt.svelte.d.ts +1 -1
  152. package/dist/components/interrupt/InterruptBubble.svelte +617 -583
  153. package/dist/components/interrupt/InterruptBubble.svelte.d.ts +2 -2
  154. package/dist/components/interrupt/ReviewPrompt.stories.svelte +66 -56
  155. package/dist/components/interrupt/ReviewPrompt.stories.svelte.d.ts +1 -1
  156. package/dist/components/interrupt/ReviewPrompt.svelte +861 -841
  157. package/dist/components/interrupt/ReviewPrompt.svelte.d.ts +1 -1
  158. package/dist/components/interrupt/TextInputPrompt.stories.svelte +38 -33
  159. package/dist/components/interrupt/TextInputPrompt.stories.svelte.d.ts +1 -1
  160. package/dist/components/interrupt/TextInputPrompt.svelte +333 -328
  161. package/dist/components/interrupt/TextInputPrompt.svelte.d.ts +1 -1
  162. package/dist/components/interrupt/index.d.ts +5 -5
  163. package/dist/components/interrupt/index.js +5 -5
  164. package/dist/components/layouts/MainLayout.svelte +724 -691
  165. package/dist/components/layouts/MainLayout.svelte.d.ts +6 -6
  166. package/dist/components/nodes/GatewayNode.stories.svelte +100 -99
  167. package/dist/components/nodes/GatewayNode.svelte +605 -571
  168. package/dist/components/nodes/GatewayNode.svelte.d.ts +3 -3
  169. package/dist/components/nodes/IdeaNode.stories.svelte +44 -43
  170. package/dist/components/nodes/IdeaNode.svelte +451 -437
  171. package/dist/components/nodes/IdeaNode.svelte.d.ts +1 -1
  172. package/dist/components/nodes/NotesNode.stories.svelte +65 -64
  173. package/dist/components/nodes/NotesNode.svelte +380 -369
  174. package/dist/components/nodes/NotesNode.svelte.d.ts +1 -1
  175. package/dist/components/nodes/SimpleNode.stories.svelte +145 -144
  176. package/dist/components/nodes/SimpleNode.svelte +486 -424
  177. package/dist/components/nodes/SimpleNode.svelte.d.ts +1 -1
  178. package/dist/components/nodes/SquareNode.stories.svelte +73 -73
  179. package/dist/components/nodes/SquareNode.svelte +439 -380
  180. package/dist/components/nodes/SquareNode.svelte.d.ts +1 -1
  181. package/dist/components/nodes/TerminalNode.stories.svelte +13 -13
  182. package/dist/components/nodes/TerminalNode.svelte +709 -670
  183. package/dist/components/nodes/TerminalNode.svelte.d.ts +1 -1
  184. package/dist/components/nodes/ToolNode.stories.svelte +181 -180
  185. package/dist/components/nodes/ToolNode.svelte +505 -447
  186. package/dist/components/nodes/ToolNode.svelte.d.ts +1 -1
  187. package/dist/components/nodes/WorkflowNode.stories.svelte +70 -46
  188. package/dist/components/nodes/WorkflowNode.svelte +621 -551
  189. package/dist/components/nodes/WorkflowNode.svelte.d.ts +3 -3
  190. package/dist/components/playground/ChatPanel.svelte +945 -889
  191. package/dist/components/playground/ExecutionLogs.svelte +495 -472
  192. package/dist/components/playground/InputCollector.svelte +449 -428
  193. package/dist/components/playground/MessageBubble.stories.svelte +47 -47
  194. package/dist/components/playground/MessageBubble.stories.svelte.d.ts +1 -1
  195. package/dist/components/playground/MessageBubble.svelte +626 -610
  196. package/dist/components/playground/MessageBubble.svelte.d.ts +1 -1
  197. package/dist/components/playground/Playground.svelte +1088 -1057
  198. package/dist/components/playground/Playground.svelte.d.ts +3 -3
  199. package/dist/components/playground/PlaygroundModal.svelte +208 -204
  200. package/dist/components/playground/PlaygroundModal.svelte.d.ts +3 -3
  201. package/dist/components/playground/SessionManager.svelte +527 -521
  202. package/dist/components/playground/SessionManager.svelte.d.ts +1 -1
  203. package/dist/config/agentSpecEndpoints.d.ts +1 -1
  204. package/dist/config/agentSpecEndpoints.js +20 -20
  205. package/dist/config/constants.js +2 -2
  206. package/dist/config/defaultCategories.d.ts +1 -1
  207. package/dist/config/defaultCategories.js +86 -86
  208. package/dist/config/defaultPortConfig.d.ts +1 -1
  209. package/dist/config/defaultPortConfig.js +144 -144
  210. package/dist/config/endpoints.d.ts +4 -4
  211. package/dist/config/endpoints.js +65 -65
  212. package/dist/config/runtimeConfig.d.ts +2 -2
  213. package/dist/config/runtimeConfig.js +8 -8
  214. package/dist/core/index.d.ts +63 -59
  215. package/dist/core/index.js +35 -33
  216. package/dist/display/index.d.ts +2 -2
  217. package/dist/display/index.js +2 -2
  218. package/dist/editor/index.d.ts +62 -62
  219. package/dist/editor/index.js +53 -53
  220. package/dist/form/code.d.ts +5 -5
  221. package/dist/form/code.js +14 -14
  222. package/dist/form/fieldRegistry.d.ts +3 -3
  223. package/dist/form/fieldRegistry.js +11 -9
  224. package/dist/form/full.d.ts +8 -8
  225. package/dist/form/full.js +9 -9
  226. package/dist/form/index.d.ts +18 -18
  227. package/dist/form/index.js +16 -16
  228. package/dist/form/markdown.d.ts +4 -4
  229. package/dist/form/markdown.js +8 -8
  230. package/dist/helpers/proximityConnect.d.ts +3 -3
  231. package/dist/helpers/proximityConnect.js +34 -32
  232. package/dist/helpers/workflowEditorHelper.d.ts +5 -5
  233. package/dist/helpers/workflowEditorHelper.js +108 -96
  234. package/dist/index.d.ts +6 -6
  235. package/dist/index.js +6 -6
  236. package/dist/mocks/app-environment.js +2 -2
  237. package/dist/mocks/app-forms.js +9 -9
  238. package/dist/mocks/app-navigation.js +11 -11
  239. package/dist/mocks/app-stores.js +8 -8
  240. package/dist/playground/index.d.ts +19 -19
  241. package/dist/playground/index.js +16 -16
  242. package/dist/playground/mount.d.ts +3 -3
  243. package/dist/playground/mount.js +24 -24
  244. package/dist/registry/builtinFormats.js +13 -13
  245. package/dist/registry/builtinNodes.d.ts +2 -2
  246. package/dist/registry/builtinNodes.js +77 -77
  247. package/dist/registry/index.d.ts +4 -4
  248. package/dist/registry/index.js +4 -4
  249. package/dist/registry/nodeComponentRegistry.d.ts +8 -8
  250. package/dist/registry/nodeComponentRegistry.js +11 -9
  251. package/dist/registry/plugin.d.ts +2 -2
  252. package/dist/registry/plugin.js +11 -11
  253. package/dist/registry/workflowFormatRegistry.d.ts +3 -3
  254. package/dist/registry/workflowFormatRegistry.js +2 -2
  255. package/dist/schema/index.d.ts +1 -1
  256. package/dist/schema/index.js +2 -2
  257. package/dist/services/agentSpecExecutionService.d.ts +3 -3
  258. package/dist/services/agentSpecExecutionService.js +59 -55
  259. package/dist/services/api.d.ts +2 -2
  260. package/dist/services/api.js +37 -37
  261. package/dist/services/apiVariableService.d.ts +1 -1
  262. package/dist/services/apiVariableService.js +41 -34
  263. package/dist/services/autoSaveService.js +8 -8
  264. package/dist/services/categoriesApi.d.ts +2 -2
  265. package/dist/services/categoriesApi.js +8 -8
  266. package/dist/services/draftStorage.d.ts +1 -1
  267. package/dist/services/draftStorage.js +11 -11
  268. package/dist/services/dynamicSchemaService.d.ts +1 -1
  269. package/dist/services/dynamicSchemaService.js +41 -39
  270. package/dist/services/globalSave.d.ts +2 -2
  271. package/dist/services/globalSave.js +41 -38
  272. package/dist/services/historyService.d.ts +1 -1
  273. package/dist/services/historyService.js +8 -8
  274. package/dist/services/interruptService.d.ts +1 -1
  275. package/dist/services/interruptService.js +35 -29
  276. package/dist/services/nodeExecutionService.d.ts +1 -1
  277. package/dist/services/nodeExecutionService.js +45 -44
  278. package/dist/services/playgroundService.d.ts +1 -1
  279. package/dist/services/playgroundService.js +29 -29
  280. package/dist/services/portConfigApi.d.ts +2 -2
  281. package/dist/services/portConfigApi.js +8 -8
  282. package/dist/services/settingsService.d.ts +2 -2
  283. package/dist/services/settingsService.js +25 -19
  284. package/dist/services/toastService.d.ts +4 -4
  285. package/dist/services/toastService.js +33 -33
  286. package/dist/services/variableService.d.ts +1 -1
  287. package/dist/services/variableService.js +36 -36
  288. package/dist/services/workflowStorage.d.ts +2 -2
  289. package/dist/services/workflowStorage.js +13 -13
  290. package/dist/settings/index.d.ts +7 -7
  291. package/dist/settings/index.js +6 -6
  292. package/dist/skins/default.d.ts +2 -0
  293. package/dist/skins/default.js +1 -0
  294. package/dist/skins/index.d.ts +13 -0
  295. package/dist/skins/index.js +30 -0
  296. package/dist/skins/slate.d.ts +2 -0
  297. package/dist/skins/slate.js +78 -0
  298. package/dist/stores/categoriesStore.svelte.d.ts +1 -1
  299. package/dist/stores/categoriesStore.svelte.js +5 -5
  300. package/dist/stores/editorStateMachine.svelte.d.ts +2 -2
  301. package/dist/stores/editorStateMachine.svelte.js +65 -33
  302. package/dist/stores/historyStore.svelte.d.ts +4 -4
  303. package/dist/stores/historyStore.svelte.js +4 -4
  304. package/dist/stores/interruptStore.svelte.d.ts +3 -3
  305. package/dist/stores/interruptStore.svelte.js +21 -21
  306. package/dist/stores/playgroundStore.svelte.d.ts +2 -2
  307. package/dist/stores/playgroundStore.svelte.js +25 -18
  308. package/dist/stores/portCoordinateStore.svelte.d.ts +2 -2
  309. package/dist/stores/portCoordinateStore.svelte.js +15 -8
  310. package/dist/stores/settingsStore.svelte.d.ts +2 -2
  311. package/dist/stores/settingsStore.svelte.js +62 -57
  312. package/dist/stores/workflowStore.svelte.d.ts +3 -3
  313. package/dist/stores/workflowStore.svelte.js +50 -47
  314. package/dist/stories/CanvasDecorator.svelte +35 -32
  315. package/dist/stories/CanvasDecorator.svelte.d.ts +2 -2
  316. package/dist/stories/EdgeDecorator.svelte +102 -99
  317. package/dist/stories/EdgeDecorator.svelte.d.ts +1 -1
  318. package/dist/stories/NodeDecorator.svelte +59 -53
  319. package/dist/stories/NodeDecorator.svelte.d.ts +1 -1
  320. package/dist/stories/utils.d.ts +2 -2
  321. package/dist/stories/utils.js +105 -67
  322. package/dist/styles/base.css +599 -595
  323. package/dist/styles/toast.css +14 -14
  324. package/dist/styles/tokens.css +409 -378
  325. package/dist/svelte-app.d.ts +12 -9
  326. package/dist/svelte-app.js +40 -39
  327. package/dist/themes/default.d.ts +2 -0
  328. package/dist/themes/default.js +9 -0
  329. package/dist/themes/index.d.ts +13 -0
  330. package/dist/themes/index.js +44 -0
  331. package/dist/themes/minimal.d.ts +2 -0
  332. package/dist/themes/minimal.js +11 -0
  333. package/dist/types/agentspec.d.ts +18 -18
  334. package/dist/types/agentspec.js +2 -2
  335. package/dist/types/auth.d.ts +1 -1
  336. package/dist/types/auth.js +6 -6
  337. package/dist/types/config.d.ts +6 -6
  338. package/dist/types/events.d.ts +2 -2
  339. package/dist/types/events.js +2 -2
  340. package/dist/types/index.d.ts +32 -32
  341. package/dist/types/index.js +6 -6
  342. package/dist/types/interrupt.d.ts +6 -6
  343. package/dist/types/interrupt.js +21 -21
  344. package/dist/types/interruptState.d.ts +12 -12
  345. package/dist/types/interruptState.js +66 -66
  346. package/dist/types/playground.d.ts +7 -7
  347. package/dist/types/playground.js +14 -14
  348. package/dist/types/settings.d.ts +5 -3
  349. package/dist/types/settings.js +25 -18
  350. package/dist/types/skin.d.ts +31 -0
  351. package/dist/types/skin.js +1 -0
  352. package/dist/types/theme.d.ts +35 -0
  353. package/dist/types/theme.js +1 -0
  354. package/dist/types/uischema.d.ts +4 -4
  355. package/dist/types/uischema.js +3 -3
  356. package/dist/utils/colors.d.ts +1 -1
  357. package/dist/utils/colors.js +97 -95
  358. package/dist/utils/config.d.ts +2 -2
  359. package/dist/utils/config.js +48 -48
  360. package/dist/utils/connections.d.ts +2 -2
  361. package/dist/utils/connections.js +15 -15
  362. package/dist/utils/errors.js +3 -3
  363. package/dist/utils/fetchWithAuth.d.ts +1 -1
  364. package/dist/utils/fetchWithAuth.js +2 -2
  365. package/dist/utils/handleIds.d.ts +2 -2
  366. package/dist/utils/handleIds.js +8 -8
  367. package/dist/utils/handlePositioning.d.ts +1 -1
  368. package/dist/utils/handlePositioning.js +2 -2
  369. package/dist/utils/icons.d.ts +1 -1
  370. package/dist/utils/icons.js +74 -74
  371. package/dist/utils/logger.d.ts +1 -1
  372. package/dist/utils/logger.js +7 -7
  373. package/dist/utils/nodeStatus.d.ts +1 -1
  374. package/dist/utils/nodeStatus.js +48 -48
  375. package/dist/utils/nodeTypes.d.ts +1 -1
  376. package/dist/utils/nodeTypes.js +21 -20
  377. package/dist/utils/nodeWrapper.d.ts +7 -7
  378. package/dist/utils/nodeWrapper.js +21 -19
  379. package/dist/utils/performanceUtils.d.ts +1 -1
  380. package/dist/utils/performanceUtils.js +2 -1
  381. package/dist/utils/sanitize.js +1 -1
  382. package/dist/utils/uischema.d.ts +2 -2
  383. package/dist/utils/uischema.js +8 -8
  384. package/dist/utils/validation.js +20 -8
  385. package/package.json +1 -1
@@ -18,1032 +18,1093 @@
18
18
  -->
19
19
 
20
20
  <script lang="ts">
21
- import Icon from '@iconify/svelte';
22
- import type { FieldSchema } from './types.js';
23
-
24
- interface Props {
25
- /** Field identifier */
26
- id: string;
27
- /** Current array value */
28
- value: unknown[];
29
- /** Schema for array items */
30
- itemSchema: FieldSchema;
31
- /** Minimum number of items required */
32
- minItems?: number;
33
- /** Maximum number of items allowed */
34
- maxItems?: number;
35
- /** Label for add button */
36
- addLabel?: string;
37
- /** Whether the field is disabled */
38
- disabled?: boolean;
39
- /** Callback when value changes */
40
- onChange: (value: unknown[]) => void;
41
- }
42
-
43
- let {
44
- id,
45
- value = [],
46
- itemSchema,
47
- minItems = 0,
48
- maxItems,
49
- addLabel = 'Add Item',
50
- disabled = false,
51
- onChange
52
- }: Props = $props();
53
-
54
- /**
55
- * Ensure value is always an array
56
- */
57
- const items = $derived(Array.isArray(value) ? value : []);
58
-
59
- /**
60
- * Check if we can add more items
61
- */
62
- const canAddItem = $derived(maxItems === undefined || items.length < maxItems);
63
-
64
- /**
65
- * Check if we can remove items
66
- */
67
- const canRemoveItem = $derived(items.length > minItems);
68
-
69
- /**
70
- * Determine if items are simple (primitive) or complex (objects)
71
- */
72
- const isSimpleType = $derived(
73
- itemSchema.type === 'string' ||
74
- itemSchema.type === 'number' ||
75
- itemSchema.type === 'integer' ||
76
- itemSchema.type === 'boolean'
77
- );
78
-
79
- /**
80
- * Get the default value for a new item based on schema
81
- */
82
- function getDefaultValue(): unknown {
83
- if (itemSchema.default !== undefined) {
84
- return itemSchema.default;
85
- }
86
-
87
- switch (itemSchema.type) {
88
- case 'string':
89
- return '';
90
- case 'number':
91
- case 'integer':
92
- return 0;
93
- case 'boolean':
94
- return false;
95
- case 'object':
96
- // Create default object from properties
97
- if (itemSchema.properties) {
98
- const defaultObj: Record<string, unknown> = {};
99
- Object.entries(itemSchema.properties).forEach(([key, propSchema]) => {
100
- if (propSchema.default !== undefined) {
101
- defaultObj[key] = propSchema.default;
102
- } else {
103
- defaultObj[key] = getDefaultForType(propSchema.type);
104
- }
105
- });
106
- return defaultObj;
107
- }
108
- return {};
109
- case 'array':
110
- return [];
111
- default:
112
- return '';
113
- }
114
- }
115
-
116
- /**
117
- * Get default value for a specific type
118
- */
119
- function getDefaultForType(type: string | undefined): unknown {
120
- switch (type) {
121
- case 'string':
122
- return '';
123
- case 'number':
124
- case 'integer':
125
- return 0;
126
- case 'boolean':
127
- return false;
128
- case 'object':
129
- return {};
130
- case 'array':
131
- return [];
132
- default:
133
- return '';
134
- }
135
- }
136
-
137
- /**
138
- * Add a new item to the array
139
- */
140
- function addItem(): void {
141
- if (!canAddItem || disabled) return;
142
- const newValue = [...items, getDefaultValue()];
143
- onChange(newValue);
144
- }
145
-
146
- /**
147
- * Remove an item at the specified index
148
- */
149
- function removeItem(index: number): void {
150
- if (!canRemoveItem || disabled) return;
151
- const newValue = items.filter((_, i) => i !== index);
152
- onChange(newValue);
153
- }
154
-
155
- /**
156
- * Update an item at the specified index
157
- */
158
- function updateItem(index: number, newItemValue: unknown): void {
159
- const newValue = items.map((item, i) => (i === index ? newItemValue : item));
160
- onChange(newValue);
161
- }
162
-
163
- /**
164
- * Update a property of an object item
165
- */
166
- function updateObjectProperty(index: number, propertyKey: string, propertyValue: unknown): void {
167
- const currentItem = items[index] as Record<string, unknown>;
168
- const updatedItem = { ...currentItem, [propertyKey]: propertyValue };
169
- updateItem(index, updatedItem);
170
- }
171
-
172
- /**
173
- * Move an item up in the array
174
- */
175
- function moveItemUp(index: number): void {
176
- if (index === 0 || disabled) return;
177
- const newValue = [...items];
178
- [newValue[index - 1], newValue[index]] = [newValue[index], newValue[index - 1]];
179
- onChange(newValue);
180
- }
181
-
182
- /**
183
- * Move an item down in the array
184
- */
185
- function moveItemDown(index: number): void {
186
- if (index === items.length - 1 || disabled) return;
187
- const newValue = [...items];
188
- [newValue[index], newValue[index + 1]] = [newValue[index + 1], newValue[index]];
189
- onChange(newValue);
190
- }
191
-
192
- /**
193
- * Get item label for display
194
- */
195
- function getItemLabel(index: number, item: unknown): string {
196
- if (isSimpleType) {
197
- const itemStr = String(item);
198
- return itemStr.length > 30
199
- ? `${itemStr.substring(0, 30)}...`
200
- : itemStr || `Item ${index + 1}`;
201
- }
202
-
203
- // For objects, try to find a name/label/title property
204
- if (typeof item === 'object' && item !== null) {
205
- const obj = item as Record<string, unknown>;
206
- const labelKey = Object.keys(obj).find((k) =>
207
- ['name', 'label', 'title', 'id'].includes(k.toLowerCase())
208
- );
209
- if (labelKey && obj[labelKey]) {
210
- return String(obj[labelKey]);
211
- }
212
- }
213
-
214
- return `Item ${index + 1}`;
215
- }
216
-
217
- /**
218
- * Track collapsed state for complex items
219
- */
220
- let collapsedItems = $state<Set<number>>(new Set());
221
-
222
- /**
223
- * Toggle collapsed state for an item
224
- */
225
- function toggleCollapse(index: number): void {
226
- const newCollapsed = new Set(collapsedItems);
227
- if (newCollapsed.has(index)) {
228
- newCollapsed.delete(index);
229
- } else {
230
- newCollapsed.add(index);
231
- }
232
- collapsedItems = newCollapsed;
233
- }
234
-
235
- /**
236
- * Check if an item is collapsed
237
- */
238
- function isCollapsed(index: number): boolean {
239
- return collapsedItems.has(index);
240
- }
21
+ import Icon from "@iconify/svelte";
22
+ import type { FieldSchema } from "./types.js";
23
+
24
+ interface Props {
25
+ /** Field identifier */
26
+ id: string;
27
+ /** Current array value */
28
+ value: unknown[];
29
+ /** Schema for array items */
30
+ itemSchema: FieldSchema;
31
+ /** Minimum number of items required */
32
+ minItems?: number;
33
+ /** Maximum number of items allowed */
34
+ maxItems?: number;
35
+ /** Label for add button */
36
+ addLabel?: string;
37
+ /** Whether the field is disabled */
38
+ disabled?: boolean;
39
+ /** Callback when value changes */
40
+ onChange: (value: unknown[]) => void;
41
+ }
42
+
43
+ let {
44
+ id,
45
+ value = [],
46
+ itemSchema,
47
+ minItems = 0,
48
+ maxItems,
49
+ addLabel = "Add Item",
50
+ disabled = false,
51
+ onChange,
52
+ }: Props = $props();
53
+
54
+ /**
55
+ * Ensure value is always an array
56
+ */
57
+ const items = $derived(Array.isArray(value) ? value : []);
58
+
59
+ /**
60
+ * Check if we can add more items
61
+ */
62
+ const canAddItem = $derived(
63
+ maxItems === undefined || items.length < maxItems,
64
+ );
65
+
66
+ /**
67
+ * Check if we can remove items
68
+ */
69
+ const canRemoveItem = $derived(items.length > minItems);
70
+
71
+ /**
72
+ * Determine if items are simple (primitive) or complex (objects)
73
+ */
74
+ const isSimpleType = $derived(
75
+ itemSchema.type === "string" ||
76
+ itemSchema.type === "number" ||
77
+ itemSchema.type === "integer" ||
78
+ itemSchema.type === "boolean",
79
+ );
80
+
81
+ /**
82
+ * Get the default value for a new item based on schema
83
+ */
84
+ function getDefaultValue(): unknown {
85
+ if (itemSchema.default !== undefined) {
86
+ return itemSchema.default;
87
+ }
88
+
89
+ switch (itemSchema.type) {
90
+ case "string":
91
+ return "";
92
+ case "number":
93
+ case "integer":
94
+ return 0;
95
+ case "boolean":
96
+ return false;
97
+ case "object":
98
+ // Create default object from properties
99
+ if (itemSchema.properties) {
100
+ const defaultObj: Record<string, unknown> = {};
101
+ Object.entries(itemSchema.properties).forEach(([key, propSchema]) => {
102
+ if (propSchema.default !== undefined) {
103
+ defaultObj[key] = propSchema.default;
104
+ } else {
105
+ defaultObj[key] = getDefaultForType(propSchema.type);
106
+ }
107
+ });
108
+ return defaultObj;
109
+ }
110
+ return {};
111
+ case "array":
112
+ return [];
113
+ default:
114
+ return "";
115
+ }
116
+ }
117
+
118
+ /**
119
+ * Get default value for a specific type
120
+ */
121
+ function getDefaultForType(type: string | undefined): unknown {
122
+ switch (type) {
123
+ case "string":
124
+ return "";
125
+ case "number":
126
+ case "integer":
127
+ return 0;
128
+ case "boolean":
129
+ return false;
130
+ case "object":
131
+ return {};
132
+ case "array":
133
+ return [];
134
+ default:
135
+ return "";
136
+ }
137
+ }
138
+
139
+ /**
140
+ * Add a new item to the array
141
+ */
142
+ function addItem(): void {
143
+ if (!canAddItem || disabled) return;
144
+ const newValue = [...items, getDefaultValue()];
145
+ onChange(newValue);
146
+ }
147
+
148
+ /**
149
+ * Remove an item at the specified index
150
+ */
151
+ function removeItem(index: number): void {
152
+ if (!canRemoveItem || disabled) return;
153
+ const newValue = items.filter((_, i) => i !== index);
154
+ onChange(newValue);
155
+ }
156
+
157
+ /**
158
+ * Update an item at the specified index
159
+ */
160
+ function updateItem(index: number, newItemValue: unknown): void {
161
+ const newValue = items.map((item, i) =>
162
+ i === index ? newItemValue : item,
163
+ );
164
+ onChange(newValue);
165
+ }
166
+
167
+ /**
168
+ * Update a property of an object item
169
+ */
170
+ function updateObjectProperty(
171
+ index: number,
172
+ propertyKey: string,
173
+ propertyValue: unknown,
174
+ ): void {
175
+ const currentItem = items[index] as Record<string, unknown>;
176
+ const updatedItem = { ...currentItem, [propertyKey]: propertyValue };
177
+ updateItem(index, updatedItem);
178
+ }
179
+
180
+ /**
181
+ * Move an item up in the array
182
+ */
183
+ function moveItemUp(index: number): void {
184
+ if (index === 0 || disabled) return;
185
+ const newValue = [...items];
186
+ [newValue[index - 1], newValue[index]] = [
187
+ newValue[index],
188
+ newValue[index - 1],
189
+ ];
190
+ onChange(newValue);
191
+ }
192
+
193
+ /**
194
+ * Move an item down in the array
195
+ */
196
+ function moveItemDown(index: number): void {
197
+ if (index === items.length - 1 || disabled) return;
198
+ const newValue = [...items];
199
+ [newValue[index], newValue[index + 1]] = [
200
+ newValue[index + 1],
201
+ newValue[index],
202
+ ];
203
+ onChange(newValue);
204
+ }
205
+
206
+ /**
207
+ * Get item label for display
208
+ */
209
+ function getItemLabel(index: number, item: unknown): string {
210
+ if (isSimpleType) {
211
+ const itemStr = String(item);
212
+ return itemStr.length > 30
213
+ ? `${itemStr.substring(0, 30)}...`
214
+ : itemStr || `Item ${index + 1}`;
215
+ }
216
+
217
+ // For objects, try to find a name/label/title property
218
+ if (typeof item === "object" && item !== null) {
219
+ const obj = item as Record<string, unknown>;
220
+ const labelKey = Object.keys(obj).find((k) =>
221
+ ["name", "label", "title", "id"].includes(k.toLowerCase()),
222
+ );
223
+ if (labelKey && obj[labelKey]) {
224
+ return String(obj[labelKey]);
225
+ }
226
+ }
227
+
228
+ return `Item ${index + 1}`;
229
+ }
230
+
231
+ /**
232
+ * Track collapsed state for complex items
233
+ */
234
+ let collapsedItems = $state<Set<number>>(new Set());
235
+
236
+ /**
237
+ * Toggle collapsed state for an item
238
+ */
239
+ function toggleCollapse(index: number): void {
240
+ const newCollapsed = new Set(collapsedItems);
241
+ if (newCollapsed.has(index)) {
242
+ newCollapsed.delete(index);
243
+ } else {
244
+ newCollapsed.add(index);
245
+ }
246
+ collapsedItems = newCollapsed;
247
+ }
248
+
249
+ /**
250
+ * Check if an item is collapsed
251
+ */
252
+ function isCollapsed(index: number): boolean {
253
+ return collapsedItems.has(index);
254
+ }
241
255
  </script>
242
256
 
243
257
  <div class="form-array" class:form-array--disabled={disabled}>
244
- <!-- Array Items -->
245
- {#if items.length > 0}
246
- <div class="form-array__items">
247
- {#each items as item, index (index)}
248
- <div
249
- class="form-array__item"
250
- class:form-array__item--simple={isSimpleType}
251
- class:form-array__item--complex={!isSimpleType}
252
- style="animation-delay: {index * 50}ms"
253
- >
254
- <!-- Item Header -->
255
- <div class="form-array__item-header">
256
- <!-- Item index/label -->
257
- {#if !isSimpleType}
258
- <button
259
- type="button"
260
- class="form-array__item-toggle"
261
- onclick={() => toggleCollapse(index)}
262
- aria-expanded={!isCollapsed(index)}
263
- aria-label={isCollapsed(index) ? 'Expand item' : 'Collapse item'}
264
- >
265
- <Icon
266
- icon={isCollapsed(index) ? 'heroicons:chevron-right' : 'heroicons:chevron-down'}
267
- class="form-array__toggle-icon"
268
- />
269
- <span class="form-array__item-label">{getItemLabel(index, item)}</span>
270
- </button>
271
- {:else}
272
- <span class="form-array__item-number">#{index + 1}</span>
273
- {/if}
274
-
275
- <!-- Action buttons group -->
276
- <div class="form-array__actions">
277
- <!-- Move Up button -->
278
- <button
279
- type="button"
280
- class="form-array__action-btn form-array__action-btn--move"
281
- onclick={() => moveItemUp(index)}
282
- disabled={index === 0 || disabled}
283
- aria-label="Move item {index + 1} up"
284
- title="Move up"
285
- >
286
- <Icon icon="heroicons:arrow-up" />
287
- </button>
288
-
289
- <!-- Move Down button -->
290
- <button
291
- type="button"
292
- class="form-array__action-btn form-array__action-btn--move"
293
- onclick={() => moveItemDown(index)}
294
- disabled={index === items.length - 1 || disabled}
295
- aria-label="Move item {index + 1} down"
296
- title="Move down"
297
- >
298
- <Icon icon="heroicons:arrow-down" />
299
- </button>
300
-
301
- <!-- Delete button -->
302
- <button
303
- type="button"
304
- class="form-array__action-btn form-array__action-btn--delete"
305
- onclick={() => removeItem(index)}
306
- disabled={!canRemoveItem || disabled}
307
- aria-label="Delete item {index + 1}"
308
- title="Delete item"
309
- >
310
- <Icon icon="heroicons:trash" />
311
- </button>
312
- </div>
313
- </div>
314
-
315
- <!-- Item Content -->
316
- <div
317
- class="form-array__item-content"
318
- class:form-array__item-content--collapsed={!isSimpleType && isCollapsed(index)}
319
- >
320
- {#if isSimpleType}
321
- <!-- Simple type: render inline input -->
322
- {#if itemSchema.type === 'string'}
323
- {#if itemSchema.format === 'multiline'}
324
- <textarea
325
- class="form-array__input form-array__textarea"
326
- value={String(item ?? '')}
327
- placeholder={itemSchema.placeholder ?? ''}
328
- rows={3}
329
- oninput={(e) => updateItem(index, e.currentTarget.value)}
330
- {disabled}
331
- ></textarea>
332
- {:else}
333
- <input
334
- type="text"
335
- class="form-array__input"
336
- value={String(item ?? '')}
337
- placeholder={itemSchema.placeholder ?? ''}
338
- oninput={(e) => updateItem(index, e.currentTarget.value)}
339
- {disabled}
340
- />
341
- {/if}
342
- {:else if itemSchema.type === 'number' || itemSchema.type === 'integer'}
343
- <input
344
- type="number"
345
- class="form-array__input form-array__input--number"
346
- value={item as number}
347
- placeholder={itemSchema.placeholder ?? ''}
348
- min={itemSchema.minimum}
349
- max={itemSchema.maximum}
350
- oninput={(e) => {
351
- const val = e.currentTarget.value;
352
- updateItem(index, val === '' ? '' : Number(val));
353
- }}
354
- {disabled}
355
- />
356
- {:else if itemSchema.type === 'boolean'}
357
- <label class="form-array__toggle-wrapper">
358
- <input
359
- type="checkbox"
360
- class="form-array__checkbox-input"
361
- checked={Boolean(item)}
362
- onchange={(e) => updateItem(index, e.currentTarget.checked)}
363
- {disabled}
364
- />
365
- <span class="form-array__toggle-track">
366
- <span class="form-array__toggle-thumb"></span>
367
- </span>
368
- <span class="form-array__toggle-label">
369
- {item ? 'Yes' : 'No'}
370
- </span>
371
- </label>
372
- {:else if itemSchema.enum}
373
- <!-- Enum: render select -->
374
- <select
375
- class="form-array__select"
376
- value={String(item ?? '')}
377
- onchange={(e) => updateItem(index, e.currentTarget.value)}
378
- {disabled}
379
- >
380
- {#each itemSchema.enum as option}
381
- <option value={String(option)}>{String(option)}</option>
382
- {/each}
383
- </select>
384
- {:else}
385
- <!-- Fallback to text -->
386
- <input
387
- type="text"
388
- class="form-array__input"
389
- value={String(item ?? '')}
390
- placeholder={itemSchema.placeholder ?? ''}
391
- oninput={(e) => updateItem(index, e.currentTarget.value)}
392
- {disabled}
393
- />
394
- {/if}
395
- {:else if itemSchema.type === 'object' && itemSchema.properties}
396
- <!-- Complex type: render sub-form for object properties -->
397
- {#if !isCollapsed(index)}
398
- <div class="form-array__subform">
399
- {#each Object.entries(itemSchema.properties) as [propKey, propSchema], propIndex (propKey)}
400
- {@const propValue = (item as Record<string, unknown>)?.[propKey]}
401
- {@const isRequired = itemSchema.required?.includes(propKey) ?? false}
402
- {@const propFieldSchema = propSchema as FieldSchema}
403
-
404
- <div
405
- class="form-array__subform-field"
406
- style="animation-delay: {propIndex * 20}ms"
407
- >
408
- <label class="form-array__subform-label" for="{id}-{index}-{propKey}">
409
- <span class="form-array__subform-label-text">
410
- {propFieldSchema.title ?? propKey}
411
- </span>
412
- {#if isRequired}
413
- <span class="form-array__required">*</span>
414
- {/if}
415
- </label>
416
-
417
- <div class="form-array__subform-input">
418
- {#if propFieldSchema.enum}
419
- <select
420
- id="{id}-{index}-{propKey}"
421
- class="form-array__select"
422
- value={String(propValue ?? '')}
423
- onchange={(e) =>
424
- updateObjectProperty(index, propKey, e.currentTarget.value)}
425
- {disabled}
426
- >
427
- {#each propFieldSchema.enum as option}
428
- <option value={String(option)}>{String(option)}</option>
429
- {/each}
430
- </select>
431
- {:else if propFieldSchema.type === 'string' && propFieldSchema.format === 'multiline'}
432
- <textarea
433
- id="{id}-{index}-{propKey}"
434
- class="form-array__input form-array__textarea"
435
- value={String(propValue ?? '')}
436
- placeholder={propFieldSchema.placeholder ?? ''}
437
- rows={3}
438
- oninput={(e) =>
439
- updateObjectProperty(index, propKey, e.currentTarget.value)}
440
- {disabled}
441
- ></textarea>
442
- {:else if propFieldSchema.type === 'string'}
443
- <input
444
- id="{id}-{index}-{propKey}"
445
- type="text"
446
- class="form-array__input"
447
- value={String(propValue ?? '')}
448
- placeholder={propFieldSchema.placeholder ?? ''}
449
- oninput={(e) =>
450
- updateObjectProperty(index, propKey, e.currentTarget.value)}
451
- {disabled}
452
- />
453
- {:else if propFieldSchema.type === 'number' || propFieldSchema.type === 'integer'}
454
- <input
455
- id="{id}-{index}-{propKey}"
456
- type="number"
457
- class="form-array__input form-array__input--number"
458
- value={propValue as number}
459
- placeholder={propFieldSchema.placeholder ?? ''}
460
- min={propFieldSchema.minimum}
461
- max={propFieldSchema.maximum}
462
- oninput={(e) => {
463
- const val = e.currentTarget.value;
464
- updateObjectProperty(index, propKey, val === '' ? '' : Number(val));
465
- }}
466
- {disabled}
467
- />
468
- {:else if propFieldSchema.type === 'boolean'}
469
- <label class="form-array__toggle-wrapper">
470
- <input
471
- id="{id}-{index}-{propKey}"
472
- type="checkbox"
473
- class="form-array__checkbox-input"
474
- checked={Boolean(propValue)}
475
- onchange={(e) =>
476
- updateObjectProperty(index, propKey, e.currentTarget.checked)}
477
- {disabled}
478
- />
479
- <span class="form-array__toggle-track">
480
- <span class="form-array__toggle-thumb"></span>
481
- </span>
482
- <span class="form-array__toggle-label">
483
- {propValue ? 'Yes' : 'No'}
484
- </span>
485
- </label>
486
- {:else}
487
- <input
488
- id="{id}-{index}-{propKey}"
489
- type="text"
490
- class="form-array__input"
491
- value={String(propValue ?? '')}
492
- placeholder={propFieldSchema.placeholder ?? ''}
493
- oninput={(e) =>
494
- updateObjectProperty(index, propKey, e.currentTarget.value)}
495
- {disabled}
496
- />
497
- {/if}
498
- </div>
499
-
500
- {#if propFieldSchema.description && propFieldSchema.title}
501
- <p class="form-array__subform-description">{propFieldSchema.description}</p>
502
- {/if}
503
- </div>
504
- {/each}
505
- </div>
506
- {/if}
507
- {:else}
508
- <!-- Unknown complex type -->
509
- <div class="form-array__unsupported">
510
- <p>Complex item type "{itemSchema.type}" is not fully supported.</p>
511
- </div>
512
- {/if}
513
- </div>
514
- </div>
515
- {/each}
516
- </div>
517
- {:else}
518
- <!-- Empty State -->
519
- <div class="form-array__empty">
520
- <Icon icon="heroicons:squares-plus" class="form-array__empty-icon" />
521
- <p class="form-array__empty-text">No items yet</p>
522
- </div>
523
- {/if}
524
-
525
- <!-- Add Button -->
526
- <button
527
- type="button"
528
- class="form-array__add-btn"
529
- onclick={addItem}
530
- disabled={!canAddItem || disabled}
531
- aria-label={addLabel}
532
- >
533
- <Icon icon="heroicons:plus" />
534
- <span>{addLabel}</span>
535
- </button>
536
-
537
- <!-- Item count and limits -->
538
- {#if minItems > 0 || maxItems !== undefined}
539
- <div class="form-array__info">
540
- <span class="form-array__count">{items.length} item{items.length !== 1 ? 's' : ''}</span>
541
- {#if minItems > 0}
542
- <span class="form-array__limit">Min: {minItems}</span>
543
- {/if}
544
- {#if maxItems !== undefined}
545
- <span class="form-array__limit">Max: {maxItems}</span>
546
- {/if}
547
- </div>
548
- {/if}
258
+ <!-- Array Items -->
259
+ {#if items.length > 0}
260
+ <div class="form-array__items">
261
+ {#each items as item, index (index)}
262
+ <div
263
+ class="form-array__item"
264
+ class:form-array__item--simple={isSimpleType}
265
+ class:form-array__item--complex={!isSimpleType}
266
+ style="animation-delay: {index * 50}ms"
267
+ >
268
+ <!-- Item Header -->
269
+ <div class="form-array__item-header">
270
+ <!-- Item index/label -->
271
+ {#if !isSimpleType}
272
+ <button
273
+ type="button"
274
+ class="form-array__item-toggle"
275
+ onclick={() => toggleCollapse(index)}
276
+ aria-expanded={!isCollapsed(index)}
277
+ aria-label={isCollapsed(index)
278
+ ? "Expand item"
279
+ : "Collapse item"}
280
+ >
281
+ <Icon
282
+ icon={isCollapsed(index)
283
+ ? "heroicons:chevron-right"
284
+ : "heroicons:chevron-down"}
285
+ class="form-array__toggle-icon"
286
+ />
287
+ <span class="form-array__item-label"
288
+ >{getItemLabel(index, item)}</span
289
+ >
290
+ </button>
291
+ {:else}
292
+ <span class="form-array__item-number">#{index + 1}</span>
293
+ {/if}
294
+
295
+ <!-- Action buttons group -->
296
+ <div class="form-array__actions">
297
+ <!-- Move Up button -->
298
+ <button
299
+ type="button"
300
+ class="form-array__action-btn form-array__action-btn--move"
301
+ onclick={() => moveItemUp(index)}
302
+ disabled={index === 0 || disabled}
303
+ aria-label="Move item {index + 1} up"
304
+ title="Move up"
305
+ >
306
+ <Icon icon="heroicons:arrow-up" />
307
+ </button>
308
+
309
+ <!-- Move Down button -->
310
+ <button
311
+ type="button"
312
+ class="form-array__action-btn form-array__action-btn--move"
313
+ onclick={() => moveItemDown(index)}
314
+ disabled={index === items.length - 1 || disabled}
315
+ aria-label="Move item {index + 1} down"
316
+ title="Move down"
317
+ >
318
+ <Icon icon="heroicons:arrow-down" />
319
+ </button>
320
+
321
+ <!-- Delete button -->
322
+ <button
323
+ type="button"
324
+ class="form-array__action-btn form-array__action-btn--delete"
325
+ onclick={() => removeItem(index)}
326
+ disabled={!canRemoveItem || disabled}
327
+ aria-label="Delete item {index + 1}"
328
+ title="Delete item"
329
+ >
330
+ <Icon icon="heroicons:trash" />
331
+ </button>
332
+ </div>
333
+ </div>
334
+
335
+ <!-- Item Content -->
336
+ <div
337
+ class="form-array__item-content"
338
+ class:form-array__item-content--collapsed={!isSimpleType &&
339
+ isCollapsed(index)}
340
+ >
341
+ {#if isSimpleType}
342
+ <!-- Simple type: render inline input -->
343
+ {#if itemSchema.type === "string"}
344
+ {#if itemSchema.format === "multiline"}
345
+ <textarea
346
+ class="form-array__input form-array__textarea"
347
+ value={String(item ?? "")}
348
+ placeholder={itemSchema.placeholder ?? ""}
349
+ rows={3}
350
+ oninput={(e) => updateItem(index, e.currentTarget.value)}
351
+ {disabled}
352
+ ></textarea>
353
+ {:else}
354
+ <input
355
+ type="text"
356
+ class="form-array__input"
357
+ value={String(item ?? "")}
358
+ placeholder={itemSchema.placeholder ?? ""}
359
+ oninput={(e) => updateItem(index, e.currentTarget.value)}
360
+ {disabled}
361
+ />
362
+ {/if}
363
+ {:else if itemSchema.type === "number" || itemSchema.type === "integer"}
364
+ <input
365
+ type="number"
366
+ class="form-array__input form-array__input--number"
367
+ value={item as number}
368
+ placeholder={itemSchema.placeholder ?? ""}
369
+ min={itemSchema.minimum}
370
+ max={itemSchema.maximum}
371
+ oninput={(e) => {
372
+ const val = e.currentTarget.value;
373
+ updateItem(index, val === "" ? "" : Number(val));
374
+ }}
375
+ {disabled}
376
+ />
377
+ {:else if itemSchema.type === "boolean"}
378
+ <label class="form-array__toggle-wrapper">
379
+ <input
380
+ type="checkbox"
381
+ class="form-array__checkbox-input"
382
+ checked={Boolean(item)}
383
+ onchange={(e) => updateItem(index, e.currentTarget.checked)}
384
+ {disabled}
385
+ />
386
+ <span class="form-array__toggle-track">
387
+ <span class="form-array__toggle-thumb"></span>
388
+ </span>
389
+ <span class="form-array__toggle-label">
390
+ {item ? "Yes" : "No"}
391
+ </span>
392
+ </label>
393
+ {:else if itemSchema.enum}
394
+ <!-- Enum: render select -->
395
+ <select
396
+ class="form-array__select"
397
+ value={String(item ?? "")}
398
+ onchange={(e) => updateItem(index, e.currentTarget.value)}
399
+ {disabled}
400
+ >
401
+ {#each itemSchema.enum as option}
402
+ <option value={String(option)}>{String(option)}</option>
403
+ {/each}
404
+ </select>
405
+ {:else}
406
+ <!-- Fallback to text -->
407
+ <input
408
+ type="text"
409
+ class="form-array__input"
410
+ value={String(item ?? "")}
411
+ placeholder={itemSchema.placeholder ?? ""}
412
+ oninput={(e) => updateItem(index, e.currentTarget.value)}
413
+ {disabled}
414
+ />
415
+ {/if}
416
+ {:else if itemSchema.type === "object" && itemSchema.properties}
417
+ <!-- Complex type: render sub-form for object properties -->
418
+ {#if !isCollapsed(index)}
419
+ <div class="form-array__subform">
420
+ {#each Object.entries(itemSchema.properties) as [propKey, propSchema], propIndex (propKey)}
421
+ {@const propValue = (item as Record<string, unknown>)?.[
422
+ propKey
423
+ ]}
424
+ {@const isRequired =
425
+ itemSchema.required?.includes(propKey) ?? false}
426
+ {@const propFieldSchema = propSchema as FieldSchema}
427
+
428
+ <div
429
+ class="form-array__subform-field"
430
+ style="animation-delay: {propIndex * 20}ms"
431
+ >
432
+ <label
433
+ class="form-array__subform-label"
434
+ for="{id}-{index}-{propKey}"
435
+ >
436
+ <span class="form-array__subform-label-text">
437
+ {propFieldSchema.title ?? propKey}
438
+ </span>
439
+ {#if isRequired}
440
+ <span class="form-array__required">*</span>
441
+ {/if}
442
+ </label>
443
+
444
+ <div class="form-array__subform-input">
445
+ {#if propFieldSchema.enum}
446
+ <select
447
+ id="{id}-{index}-{propKey}"
448
+ class="form-array__select"
449
+ value={String(propValue ?? "")}
450
+ onchange={(e) =>
451
+ updateObjectProperty(
452
+ index,
453
+ propKey,
454
+ e.currentTarget.value,
455
+ )}
456
+ {disabled}
457
+ >
458
+ {#each propFieldSchema.enum as option}
459
+ <option value={String(option)}
460
+ >{String(option)}</option
461
+ >
462
+ {/each}
463
+ </select>
464
+ {:else if propFieldSchema.type === "string" && propFieldSchema.format === "multiline"}
465
+ <textarea
466
+ id="{id}-{index}-{propKey}"
467
+ class="form-array__input form-array__textarea"
468
+ value={String(propValue ?? "")}
469
+ placeholder={propFieldSchema.placeholder ?? ""}
470
+ rows={3}
471
+ oninput={(e) =>
472
+ updateObjectProperty(
473
+ index,
474
+ propKey,
475
+ e.currentTarget.value,
476
+ )}
477
+ {disabled}
478
+ ></textarea>
479
+ {:else if propFieldSchema.type === "string"}
480
+ <input
481
+ id="{id}-{index}-{propKey}"
482
+ type="text"
483
+ class="form-array__input"
484
+ value={String(propValue ?? "")}
485
+ placeholder={propFieldSchema.placeholder ?? ""}
486
+ oninput={(e) =>
487
+ updateObjectProperty(
488
+ index,
489
+ propKey,
490
+ e.currentTarget.value,
491
+ )}
492
+ {disabled}
493
+ />
494
+ {:else if propFieldSchema.type === "number" || propFieldSchema.type === "integer"}
495
+ <input
496
+ id="{id}-{index}-{propKey}"
497
+ type="number"
498
+ class="form-array__input form-array__input--number"
499
+ value={propValue as number}
500
+ placeholder={propFieldSchema.placeholder ?? ""}
501
+ min={propFieldSchema.minimum}
502
+ max={propFieldSchema.maximum}
503
+ oninput={(e) => {
504
+ const val = e.currentTarget.value;
505
+ updateObjectProperty(
506
+ index,
507
+ propKey,
508
+ val === "" ? "" : Number(val),
509
+ );
510
+ }}
511
+ {disabled}
512
+ />
513
+ {:else if propFieldSchema.type === "boolean"}
514
+ <label class="form-array__toggle-wrapper">
515
+ <input
516
+ id="{id}-{index}-{propKey}"
517
+ type="checkbox"
518
+ class="form-array__checkbox-input"
519
+ checked={Boolean(propValue)}
520
+ onchange={(e) =>
521
+ updateObjectProperty(
522
+ index,
523
+ propKey,
524
+ e.currentTarget.checked,
525
+ )}
526
+ {disabled}
527
+ />
528
+ <span class="form-array__toggle-track">
529
+ <span class="form-array__toggle-thumb"></span>
530
+ </span>
531
+ <span class="form-array__toggle-label">
532
+ {propValue ? "Yes" : "No"}
533
+ </span>
534
+ </label>
535
+ {:else}
536
+ <input
537
+ id="{id}-{index}-{propKey}"
538
+ type="text"
539
+ class="form-array__input"
540
+ value={String(propValue ?? "")}
541
+ placeholder={propFieldSchema.placeholder ?? ""}
542
+ oninput={(e) =>
543
+ updateObjectProperty(
544
+ index,
545
+ propKey,
546
+ e.currentTarget.value,
547
+ )}
548
+ {disabled}
549
+ />
550
+ {/if}
551
+ </div>
552
+
553
+ {#if propFieldSchema.description && propFieldSchema.title}
554
+ <p class="form-array__subform-description">
555
+ {propFieldSchema.description}
556
+ </p>
557
+ {/if}
558
+ </div>
559
+ {/each}
560
+ </div>
561
+ {/if}
562
+ {:else}
563
+ <!-- Unknown complex type -->
564
+ <div class="form-array__unsupported">
565
+ <p>
566
+ Complex item type "{itemSchema.type}" is not fully supported.
567
+ </p>
568
+ </div>
569
+ {/if}
570
+ </div>
571
+ </div>
572
+ {/each}
573
+ </div>
574
+ {:else}
575
+ <!-- Empty State -->
576
+ <div class="form-array__empty">
577
+ <Icon icon="heroicons:squares-plus" class="form-array__empty-icon" />
578
+ <p class="form-array__empty-text">No items yet</p>
579
+ </div>
580
+ {/if}
581
+
582
+ <!-- Add Button -->
583
+ <button
584
+ type="button"
585
+ class="form-array__add-btn"
586
+ onclick={addItem}
587
+ disabled={!canAddItem || disabled}
588
+ aria-label={addLabel}
589
+ >
590
+ <Icon icon="heroicons:plus" />
591
+ <span>{addLabel}</span>
592
+ </button>
593
+
594
+ <!-- Item count and limits -->
595
+ {#if minItems > 0 || maxItems !== undefined}
596
+ <div class="form-array__info">
597
+ <span class="form-array__count"
598
+ >{items.length} item{items.length !== 1 ? "s" : ""}</span
599
+ >
600
+ {#if minItems > 0}
601
+ <span class="form-array__limit">Min: {minItems}</span>
602
+ {/if}
603
+ {#if maxItems !== undefined}
604
+ <span class="form-array__limit">Max: {maxItems}</span>
605
+ {/if}
606
+ </div>
607
+ {/if}
549
608
  </div>
550
609
 
551
610
  <style>
552
- /* ============================================
611
+ /* ============================================
553
612
  FORM ARRAY CONTAINER
554
613
  ============================================ */
555
614
 
556
- .form-array {
557
- display: flex;
558
- flex-direction: column;
559
- gap: 0.75rem;
560
- }
615
+ .form-array {
616
+ display: flex;
617
+ flex-direction: column;
618
+ gap: 0.75rem;
619
+ }
561
620
 
562
- .form-array--disabled {
563
- opacity: 0.6;
564
- pointer-events: none;
565
- }
621
+ .form-array--disabled {
622
+ opacity: 0.6;
623
+ pointer-events: none;
624
+ }
566
625
 
567
- /* ============================================
626
+ /* ============================================
568
627
  ITEMS CONTAINER
569
628
  ============================================ */
570
629
 
571
- .form-array__items {
572
- display: flex;
573
- flex-direction: column;
574
- gap: 0.5rem;
575
- }
630
+ .form-array__items {
631
+ display: flex;
632
+ flex-direction: column;
633
+ gap: 0.5rem;
634
+ }
576
635
 
577
- /* ============================================
636
+ /* ============================================
578
637
  INDIVIDUAL ITEM
579
638
  ============================================ */
580
639
 
581
- .form-array__item {
582
- display: flex;
583
- flex-direction: column;
584
- background-color: var(--fd-muted);
585
- border: 1px solid var(--fd-border);
586
- border-radius: var(--fd-radius-lg);
587
- overflow: hidden;
588
- animation: itemFadeIn 0.25s ease-out forwards;
589
- opacity: 0;
590
- transform: translateY(-8px);
591
- }
592
-
593
- @keyframes itemFadeIn {
594
- to {
595
- opacity: 1;
596
- transform: translateY(0);
597
- }
598
- }
599
-
600
- .form-array__item--simple .form-array__item-content {
601
- padding: 0.5rem 0.75rem 0.75rem;
602
- }
603
-
604
- .form-array__item--complex .form-array__item-content {
605
- padding: 0;
606
- }
607
-
608
- /* ============================================
640
+ .form-array__item {
641
+ display: flex;
642
+ flex-direction: column;
643
+ background-color: var(--fd-muted);
644
+ border: 1px solid var(--fd-border);
645
+ border-radius: var(--fd-radius-lg);
646
+ overflow: hidden;
647
+ animation: itemFadeIn 0.25s ease-out forwards;
648
+ opacity: 0;
649
+ transform: translateY(-8px);
650
+ }
651
+
652
+ @keyframes itemFadeIn {
653
+ to {
654
+ opacity: 1;
655
+ transform: translateY(0);
656
+ }
657
+ }
658
+
659
+ .form-array__item--simple .form-array__item-content {
660
+ padding: 0.5rem 0.75rem 0.75rem;
661
+ }
662
+
663
+ .form-array__item--complex .form-array__item-content {
664
+ padding: 0;
665
+ }
666
+
667
+ /* ============================================
609
668
  ITEM HEADER
610
669
  ============================================ */
611
670
 
612
- .form-array__item-header {
613
- display: flex;
614
- align-items: center;
615
- gap: 0.625rem;
616
- padding: 0.625rem 0.75rem;
617
- background-color: var(--fd-subtle);
618
- border-bottom: 1px solid var(--fd-border);
619
- }
671
+ .form-array__item-header {
672
+ display: flex;
673
+ align-items: center;
674
+ gap: 0.625rem;
675
+ padding: 0.625rem 0.75rem;
676
+ background-color: var(--fd-subtle);
677
+ border-bottom: 1px solid var(--fd-border);
678
+ }
620
679
 
621
- .form-array__item--simple .form-array__item-header {
622
- padding: 0.5rem 0.625rem;
623
- }
680
+ .form-array__item--simple .form-array__item-header {
681
+ padding: 0.5rem 0.625rem;
682
+ }
624
683
 
625
- /* ============================================
684
+ /* ============================================
626
685
  ITEM NUMBER/LABEL
627
686
  ============================================ */
628
687
 
629
- .form-array__item-number {
630
- font-size: var(--fd-text-xs);
631
- font-weight: 600;
632
- color: var(--fd-muted-foreground);
633
- min-width: 1.75rem;
634
- padding: 0.125rem 0.375rem;
635
- background-color: var(--fd-border);
636
- border-radius: var(--fd-radius-sm);
637
- text-align: center;
638
- }
639
-
640
- .form-array__item-toggle {
641
- display: flex;
642
- align-items: center;
643
- gap: 0.5rem;
644
- flex: 1;
645
- padding: 0.375rem 0.5rem;
646
- margin: -0.25rem;
647
- border: 1px solid transparent;
648
- background: transparent;
649
- cursor: pointer;
650
- text-align: left;
651
- border-radius: var(--fd-radius-md);
652
- transition: all var(--fd-transition-fast);
653
- }
654
-
655
- .form-array__item-toggle:hover {
656
- background-color: var(--fd-border);
657
- }
658
-
659
- .form-array__item-toggle:focus-visible {
660
- outline: none;
661
- border-color: var(--fd-primary);
662
- box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.2);
663
- }
664
-
665
- .form-array__item-toggle :global(svg) {
666
- width: 1.125rem;
667
- height: 1.125rem;
668
- color: var(--fd-muted-foreground);
669
- transition: transform var(--fd-transition-normal);
670
- }
671
-
672
- .form-array__item-label {
673
- font-size: 0.8125rem;
674
- font-weight: 600;
675
- color: var(--fd-foreground);
676
- }
677
-
678
- /* ============================================
688
+ .form-array__item-number {
689
+ font-size: var(--fd-text-xs);
690
+ font-weight: 600;
691
+ color: var(--fd-muted-foreground);
692
+ min-width: 1.75rem;
693
+ padding: 0.125rem 0.375rem;
694
+ background-color: var(--fd-border);
695
+ border-radius: var(--fd-radius-sm);
696
+ text-align: center;
697
+ }
698
+
699
+ .form-array__item-toggle {
700
+ display: flex;
701
+ align-items: center;
702
+ gap: 0.5rem;
703
+ flex: 1;
704
+ padding: 0.375rem 0.5rem;
705
+ margin: -0.25rem;
706
+ border: 1px solid transparent;
707
+ background: transparent;
708
+ cursor: pointer;
709
+ text-align: left;
710
+ border-radius: var(--fd-radius-md);
711
+ transition: all var(--fd-transition-fast);
712
+ }
713
+
714
+ .form-array__item-toggle:hover {
715
+ background-color: var(--fd-border);
716
+ }
717
+
718
+ .form-array__item-toggle:focus-visible {
719
+ outline: none;
720
+ border-color: var(--fd-primary);
721
+ box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.2);
722
+ }
723
+
724
+ .form-array__item-toggle :global(svg) {
725
+ width: 1.125rem;
726
+ height: 1.125rem;
727
+ color: var(--fd-muted-foreground);
728
+ transition: transform var(--fd-transition-normal);
729
+ }
730
+
731
+ .form-array__item-label {
732
+ font-size: 0.8125rem;
733
+ font-weight: 600;
734
+ color: var(--fd-foreground);
735
+ }
736
+
737
+ /* ============================================
679
738
  ACTION BUTTONS GROUP
680
739
  ============================================ */
681
740
 
682
- .form-array__actions {
683
- display: flex;
684
- align-items: center;
685
- gap: 0.375rem;
686
- margin-left: auto;
687
- }
688
-
689
- .form-array__action-btn {
690
- display: flex;
691
- align-items: center;
692
- justify-content: center;
693
- width: 2rem;
694
- height: 2rem;
695
- padding: 0;
696
- border: 1px solid transparent;
697
- border-radius: 0.375rem;
698
- cursor: pointer;
699
- transition: all 0.15s;
700
- }
701
-
702
- .form-array__action-btn :global(svg) {
703
- width: 1rem;
704
- height: 1rem;
705
- }
706
-
707
- .form-array__action-btn:focus-visible {
708
- outline: none;
709
- box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.3);
710
- }
711
-
712
- .form-array__action-btn:disabled {
713
- opacity: 0.35;
714
- cursor: not-allowed;
715
- }
716
-
717
- /* Move Up/Down buttons - Blue semantic color */
718
- .form-array__action-btn--move {
719
- background-color: var(--fd-primary-muted);
720
- border-color: var(--fd-primary);
721
- color: var(--fd-primary-hover);
722
- }
723
-
724
- .form-array__action-btn--move:hover:not(:disabled) {
725
- background-color: var(--fd-primary-muted);
726
- border-color: var(--fd-primary-hover);
727
- color: var(--fd-primary-hover);
728
- }
729
-
730
- .form-array__action-btn--move:active:not(:disabled) {
731
- background-color: var(--fd-primary);
732
- }
733
-
734
- /* Delete button - Red/Warning semantic color */
735
- .form-array__action-btn--delete {
736
- background-color: var(--fd-error-muted);
737
- border-color: var(--fd-error);
738
- color: var(--fd-error);
739
- }
740
-
741
- .form-array__action-btn--delete:hover:not(:disabled) {
742
- background-color: var(--fd-error-muted);
743
- border-color: var(--fd-error-hover);
744
- color: var(--fd-error-hover);
745
- }
746
-
747
- .form-array__action-btn--delete:active:not(:disabled) {
748
- background-color: var(--fd-error);
749
- }
750
-
751
- /* ============================================
741
+ .form-array__actions {
742
+ display: flex;
743
+ align-items: center;
744
+ gap: 0.375rem;
745
+ margin-left: auto;
746
+ }
747
+
748
+ .form-array__action-btn {
749
+ display: flex;
750
+ align-items: center;
751
+ justify-content: center;
752
+ width: 2rem;
753
+ height: 2rem;
754
+ padding: 0;
755
+ border: 1px solid transparent;
756
+ border-radius: 0.375rem;
757
+ cursor: pointer;
758
+ transition: all 0.15s;
759
+ }
760
+
761
+ .form-array__action-btn :global(svg) {
762
+ width: 1rem;
763
+ height: 1rem;
764
+ }
765
+
766
+ .form-array__action-btn:focus-visible {
767
+ outline: none;
768
+ box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.3);
769
+ }
770
+
771
+ .form-array__action-btn:disabled {
772
+ opacity: 0.35;
773
+ cursor: not-allowed;
774
+ }
775
+
776
+ /* Move Up/Down buttons - Blue semantic color */
777
+ .form-array__action-btn--move {
778
+ background-color: var(--fd-primary-muted);
779
+ border-color: var(--fd-primary);
780
+ color: var(--fd-primary-hover);
781
+ }
782
+
783
+ .form-array__action-btn--move:hover:not(:disabled) {
784
+ background-color: var(--fd-primary-muted);
785
+ border-color: var(--fd-primary-hover);
786
+ color: var(--fd-primary-hover);
787
+ }
788
+
789
+ .form-array__action-btn--move:active:not(:disabled) {
790
+ background-color: var(--fd-primary);
791
+ }
792
+
793
+ /* Delete button - Red/Warning semantic color */
794
+ .form-array__action-btn--delete {
795
+ background-color: var(--fd-error-muted);
796
+ border-color: var(--fd-error);
797
+ color: var(--fd-error);
798
+ }
799
+
800
+ .form-array__action-btn--delete:hover:not(:disabled) {
801
+ background-color: var(--fd-error-muted);
802
+ border-color: var(--fd-error-hover);
803
+ color: var(--fd-error-hover);
804
+ }
805
+
806
+ .form-array__action-btn--delete:active:not(:disabled) {
807
+ background-color: var(--fd-error);
808
+ }
809
+
810
+ /* ============================================
752
811
  ITEM CONTENT
753
812
  ============================================ */
754
813
 
755
- .form-array__item-content {
756
- transition: all 0.2s ease-out;
757
- }
814
+ .form-array__item-content {
815
+ transition: all 0.2s ease-out;
816
+ }
758
817
 
759
- .form-array__item-content--collapsed {
760
- height: 0;
761
- overflow: hidden;
762
- padding: 0 !important;
763
- }
818
+ .form-array__item-content--collapsed {
819
+ height: 0;
820
+ overflow: hidden;
821
+ padding: 0 !important;
822
+ }
764
823
 
765
- /* ============================================
824
+ /* ============================================
766
825
  INPUTS (Simple Types)
767
826
  ============================================ */
768
827
 
769
- .form-array__input {
770
- width: 100%;
771
- padding: 0.5rem 0.75rem;
772
- border: 1px solid var(--fd-border);
773
- border-radius: var(--fd-radius-md);
774
- font-size: var(--fd-text-sm);
775
- font-family: inherit;
776
- color: var(--fd-foreground);
777
- background-color: var(--fd-background);
778
- transition: all var(--fd-transition-normal);
779
- }
780
-
781
- .form-array__input::placeholder {
782
- color: var(--fd-muted-foreground);
783
- }
784
-
785
- .form-array__input:hover {
786
- border-color: var(--fd-border-strong);
787
- }
788
-
789
- .form-array__input:focus {
790
- outline: none;
791
- border-color: var(--fd-primary);
792
- box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.1);
793
- }
794
-
795
- .form-array__input--number {
796
- font-variant-numeric: tabular-nums;
797
- }
798
-
799
- .form-array__textarea {
800
- resize: vertical;
801
- min-height: 4rem;
802
- line-height: 1.5;
803
- }
804
-
805
- .form-array__select {
806
- width: 100%;
807
- padding: 0.5rem 2rem 0.5rem 0.75rem;
808
- border: 1px solid var(--fd-border);
809
- border-radius: var(--fd-radius-md);
810
- font-size: var(--fd-text-sm);
811
- font-family: inherit;
812
- color: var(--fd-foreground);
813
- background-color: var(--fd-background);
814
- cursor: pointer;
815
- appearance: none;
816
- background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 24 24' stroke='%239ca3af'%3E%3Cpath stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M19 9l-7 7-7-7'%3E%3C/path%3E%3C/svg%3E");
817
- background-repeat: no-repeat;
818
- background-position: right 0.5rem center;
819
- background-size: 1rem;
820
- }
821
-
822
- .form-array__select:hover {
823
- border-color: var(--fd-border-strong);
824
- }
825
-
826
- .form-array__select:focus {
827
- outline: none;
828
- border-color: var(--fd-primary);
829
- box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.1);
830
- }
831
-
832
- /* ============================================
828
+ .form-array__input {
829
+ width: 100%;
830
+ padding: 0.5rem 0.75rem;
831
+ border: 1px solid var(--fd-border);
832
+ border-radius: var(--fd-radius-md);
833
+ font-size: var(--fd-text-sm);
834
+ font-family: inherit;
835
+ color: var(--fd-foreground);
836
+ background-color: var(--fd-background);
837
+ transition: all var(--fd-transition-normal);
838
+ }
839
+
840
+ .form-array__input::placeholder {
841
+ color: var(--fd-muted-foreground);
842
+ }
843
+
844
+ .form-array__input:hover {
845
+ border-color: var(--fd-border-strong);
846
+ }
847
+
848
+ .form-array__input:focus {
849
+ outline: none;
850
+ border-color: var(--fd-primary);
851
+ box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.1);
852
+ }
853
+
854
+ .form-array__input--number {
855
+ font-variant-numeric: tabular-nums;
856
+ }
857
+
858
+ .form-array__textarea {
859
+ resize: vertical;
860
+ min-height: 4rem;
861
+ line-height: 1.5;
862
+ }
863
+
864
+ .form-array__select {
865
+ width: 100%;
866
+ padding: 0.5rem 2rem 0.5rem 0.75rem;
867
+ border: 1px solid var(--fd-border);
868
+ border-radius: var(--fd-radius-md);
869
+ font-size: var(--fd-text-sm);
870
+ font-family: inherit;
871
+ color: var(--fd-foreground);
872
+ background-color: var(--fd-background);
873
+ cursor: pointer;
874
+ appearance: none;
875
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 24 24' stroke='%239ca3af'%3E%3Cpath stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M19 9l-7 7-7-7'%3E%3C/path%3E%3C/svg%3E");
876
+ background-repeat: no-repeat;
877
+ background-position: right 0.5rem center;
878
+ background-size: 1rem;
879
+ }
880
+
881
+ .form-array__select:hover {
882
+ border-color: var(--fd-border-strong);
883
+ }
884
+
885
+ .form-array__select:focus {
886
+ outline: none;
887
+ border-color: var(--fd-primary);
888
+ box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.1);
889
+ }
890
+
891
+ /* ============================================
833
892
  TOGGLE (Boolean in Array)
834
893
  ============================================ */
835
894
 
836
- .form-array__toggle-wrapper {
837
- display: flex;
838
- align-items: center;
839
- gap: 0.625rem;
840
- cursor: pointer;
841
- }
842
-
843
- .form-array__checkbox-input {
844
- position: absolute;
845
- opacity: 0;
846
- width: 0;
847
- height: 0;
848
- }
849
-
850
- .form-array__toggle-track {
851
- position: relative;
852
- width: 2.25rem;
853
- height: 1.25rem;
854
- background-color: var(--fd-border-strong);
855
- border-radius: 0.625rem;
856
- transition: background-color var(--fd-transition-normal);
857
- flex-shrink: 0;
858
- }
859
-
860
- .form-array__toggle-thumb {
861
- position: absolute;
862
- top: 0.125rem;
863
- left: 0.125rem;
864
- width: 1rem;
865
- height: 1rem;
866
- background-color: var(--fd-background);
867
- border-radius: 50%;
868
- box-shadow: var(--fd-shadow-sm);
869
- transition: transform var(--fd-transition-normal);
870
- }
871
-
872
- .form-array__checkbox-input:checked + .form-array__toggle-track {
873
- background-color: var(--fd-primary);
874
- }
875
-
876
- .form-array__checkbox-input:checked + .form-array__toggle-track .form-array__toggle-thumb {
877
- transform: translateX(1rem);
878
- }
879
-
880
- .form-array__toggle-label {
881
- font-size: 0.8125rem;
882
- color: var(--fd-muted-foreground);
883
- }
884
-
885
- /* ============================================
895
+ .form-array__toggle-wrapper {
896
+ display: flex;
897
+ align-items: center;
898
+ gap: 0.625rem;
899
+ cursor: pointer;
900
+ }
901
+
902
+ .form-array__checkbox-input {
903
+ position: absolute;
904
+ opacity: 0;
905
+ width: 0;
906
+ height: 0;
907
+ }
908
+
909
+ .form-array__toggle-track {
910
+ position: relative;
911
+ width: 2.25rem;
912
+ height: 1.25rem;
913
+ background-color: var(--fd-border-strong);
914
+ border-radius: 0.625rem;
915
+ transition: background-color var(--fd-transition-normal);
916
+ flex-shrink: 0;
917
+ }
918
+
919
+ .form-array__toggle-thumb {
920
+ position: absolute;
921
+ top: 0.125rem;
922
+ left: 0.125rem;
923
+ width: 1rem;
924
+ height: 1rem;
925
+ background-color: var(--fd-background);
926
+ border-radius: 50%;
927
+ box-shadow: var(--fd-shadow-sm);
928
+ transition: transform var(--fd-transition-normal);
929
+ }
930
+
931
+ .form-array__checkbox-input:checked + .form-array__toggle-track {
932
+ background-color: var(--fd-primary);
933
+ }
934
+
935
+ .form-array__checkbox-input:checked
936
+ + .form-array__toggle-track
937
+ .form-array__toggle-thumb {
938
+ transform: translateX(1rem);
939
+ }
940
+
941
+ .form-array__toggle-label {
942
+ font-size: 0.8125rem;
943
+ color: var(--fd-muted-foreground);
944
+ }
945
+
946
+ /* ============================================
886
947
  SUBFORM (Complex Types)
887
948
  ============================================ */
888
949
 
889
- .form-array__subform {
890
- display: flex;
891
- flex-direction: column;
892
- gap: 0.75rem;
893
- padding: 0.75rem;
894
- background-color: var(--fd-background);
895
- }
896
-
897
- .form-array__subform-field {
898
- display: flex;
899
- flex-direction: column;
900
- gap: 0.375rem;
901
- animation: subfieldFadeIn 0.2s ease-out forwards;
902
- opacity: 0;
903
- }
904
-
905
- @keyframes subfieldFadeIn {
906
- to {
907
- opacity: 1;
908
- }
909
- }
910
-
911
- .form-array__subform-label {
912
- display: flex;
913
- align-items: center;
914
- gap: 0.25rem;
915
- font-size: var(--fd-text-xs);
916
- font-weight: 600;
917
- color: var(--fd-muted-foreground);
918
- }
919
-
920
- .form-array__subform-label-text {
921
- line-height: 1.4;
922
- }
923
-
924
- .form-array__required {
925
- color: var(--fd-error);
926
- font-weight: 500;
927
- }
928
-
929
- .form-array__subform-description {
930
- margin: 0;
931
- font-size: 0.6875rem;
932
- color: var(--fd-muted-foreground);
933
- line-height: 1.4;
934
- }
935
-
936
- /* ============================================
950
+ .form-array__subform {
951
+ display: flex;
952
+ flex-direction: column;
953
+ gap: 0.75rem;
954
+ padding: 0.75rem;
955
+ background-color: var(--fd-background);
956
+ }
957
+
958
+ .form-array__subform-field {
959
+ display: flex;
960
+ flex-direction: column;
961
+ gap: 0.375rem;
962
+ animation: subfieldFadeIn 0.2s ease-out forwards;
963
+ opacity: 0;
964
+ }
965
+
966
+ @keyframes subfieldFadeIn {
967
+ to {
968
+ opacity: 1;
969
+ }
970
+ }
971
+
972
+ .form-array__subform-label {
973
+ display: flex;
974
+ align-items: center;
975
+ gap: 0.25rem;
976
+ font-size: var(--fd-text-xs);
977
+ font-weight: 600;
978
+ color: var(--fd-muted-foreground);
979
+ }
980
+
981
+ .form-array__subform-label-text {
982
+ line-height: 1.4;
983
+ }
984
+
985
+ .form-array__required {
986
+ color: var(--fd-error);
987
+ font-weight: 500;
988
+ }
989
+
990
+ .form-array__subform-description {
991
+ margin: 0;
992
+ font-size: 0.6875rem;
993
+ color: var(--fd-muted-foreground);
994
+ line-height: 1.4;
995
+ }
996
+
997
+ /* ============================================
937
998
  EMPTY STATE
938
999
  ============================================ */
939
1000
 
940
- .form-array__empty {
941
- display: flex;
942
- flex-direction: column;
943
- align-items: center;
944
- justify-content: center;
945
- padding: 2rem 1rem;
946
- background-color: var(--fd-muted);
947
- border: 2px dashed var(--fd-border-strong);
948
- border-radius: var(--fd-radius-lg);
949
- }
950
-
951
- .form-array__empty :global(svg) {
952
- width: 2.5rem;
953
- height: 2.5rem;
954
- color: var(--fd-muted-foreground);
955
- margin-bottom: 0.625rem;
956
- }
957
-
958
- .form-array__empty-text {
959
- margin: 0;
960
- font-size: var(--fd-text-sm);
961
- font-weight: 500;
962
- color: var(--fd-muted-foreground);
963
- }
964
-
965
- /* ============================================
1001
+ .form-array__empty {
1002
+ display: flex;
1003
+ flex-direction: column;
1004
+ align-items: center;
1005
+ justify-content: center;
1006
+ padding: 2rem 1rem;
1007
+ background-color: var(--fd-muted);
1008
+ border: 2px dashed var(--fd-border-strong);
1009
+ border-radius: var(--fd-radius-lg);
1010
+ }
1011
+
1012
+ .form-array__empty :global(svg) {
1013
+ width: 2.5rem;
1014
+ height: 2.5rem;
1015
+ color: var(--fd-muted-foreground);
1016
+ margin-bottom: 0.625rem;
1017
+ }
1018
+
1019
+ .form-array__empty-text {
1020
+ margin: 0;
1021
+ font-size: var(--fd-text-sm);
1022
+ font-weight: 500;
1023
+ color: var(--fd-muted-foreground);
1024
+ }
1025
+
1026
+ /* ============================================
966
1027
  ADD BUTTON
967
1028
  ============================================ */
968
1029
 
969
- .form-array__add-btn {
970
- display: inline-flex;
971
- align-items: center;
972
- justify-content: center;
973
- gap: 0.5rem;
974
- padding: 0.625rem 1rem;
975
- border: 1px solid var(--fd-success);
976
- border-radius: var(--fd-radius-lg);
977
- background-color: var(--fd-success-muted);
978
- color: var(--fd-success-hover);
979
- font-size: 0.8125rem;
980
- font-weight: 600;
981
- font-family: inherit;
982
- cursor: pointer;
983
- transition: all var(--fd-transition-fast);
984
- }
985
-
986
- .form-array__add-btn:hover:not(:disabled) {
987
- background-color: var(--fd-success-muted);
988
- border-color: var(--fd-success-hover);
989
- color: var(--fd-success-hover);
990
- }
991
-
992
- .form-array__add-btn:focus-visible {
993
- outline: none;
994
- box-shadow: 0 0 0 2px rgba(34, 197, 94, 0.3);
995
- }
996
-
997
- .form-array__add-btn:active:not(:disabled) {
998
- background-color: var(--fd-success);
999
- }
1000
-
1001
- .form-array__add-btn:disabled {
1002
- opacity: 0.5;
1003
- cursor: not-allowed;
1004
- }
1005
-
1006
- .form-array__add-btn :global(svg) {
1007
- width: 1.125rem;
1008
- height: 1.125rem;
1009
- }
1010
-
1011
- /* ============================================
1030
+ .form-array__add-btn {
1031
+ display: inline-flex;
1032
+ align-items: center;
1033
+ justify-content: center;
1034
+ gap: 0.5rem;
1035
+ padding: 0.625rem 1rem;
1036
+ border: 1px solid var(--fd-success);
1037
+ border-radius: var(--fd-radius-lg);
1038
+ background-color: var(--fd-success-muted);
1039
+ color: var(--fd-success-hover);
1040
+ font-size: 0.8125rem;
1041
+ font-weight: 600;
1042
+ font-family: inherit;
1043
+ cursor: pointer;
1044
+ transition: all var(--fd-transition-fast);
1045
+ }
1046
+
1047
+ .form-array__add-btn:hover:not(:disabled) {
1048
+ background-color: var(--fd-success-muted);
1049
+ border-color: var(--fd-success-hover);
1050
+ color: var(--fd-success-hover);
1051
+ }
1052
+
1053
+ .form-array__add-btn:focus-visible {
1054
+ outline: none;
1055
+ box-shadow: 0 0 0 2px rgba(34, 197, 94, 0.3);
1056
+ }
1057
+
1058
+ .form-array__add-btn:active:not(:disabled) {
1059
+ background-color: var(--fd-success);
1060
+ }
1061
+
1062
+ .form-array__add-btn:disabled {
1063
+ opacity: 0.5;
1064
+ cursor: not-allowed;
1065
+ }
1066
+
1067
+ .form-array__add-btn :global(svg) {
1068
+ width: 1.125rem;
1069
+ height: 1.125rem;
1070
+ }
1071
+
1072
+ /* ============================================
1012
1073
  INFO BAR
1013
1074
  ============================================ */
1014
1075
 
1015
- .form-array__info {
1016
- display: flex;
1017
- align-items: center;
1018
- gap: 0.75rem;
1019
- font-size: 0.6875rem;
1020
- color: var(--fd-muted-foreground);
1021
- }
1022
-
1023
- .form-array__count {
1024
- font-weight: 500;
1025
- }
1026
-
1027
- .form-array__limit {
1028
- padding: 0.125rem 0.375rem;
1029
- background-color: var(--fd-subtle);
1030
- border-radius: var(--fd-radius-sm);
1031
- }
1032
-
1033
- /* ============================================
1076
+ .form-array__info {
1077
+ display: flex;
1078
+ align-items: center;
1079
+ gap: 0.75rem;
1080
+ font-size: 0.6875rem;
1081
+ color: var(--fd-muted-foreground);
1082
+ }
1083
+
1084
+ .form-array__count {
1085
+ font-weight: 500;
1086
+ }
1087
+
1088
+ .form-array__limit {
1089
+ padding: 0.125rem 0.375rem;
1090
+ background-color: var(--fd-subtle);
1091
+ border-radius: var(--fd-radius-sm);
1092
+ }
1093
+
1094
+ /* ============================================
1034
1095
  UNSUPPORTED TYPE
1035
1096
  ============================================ */
1036
1097
 
1037
- .form-array__unsupported {
1038
- padding: 0.75rem;
1039
- background-color: var(--fd-warning-muted);
1040
- border: 1px solid var(--fd-warning);
1041
- border-radius: var(--fd-radius-md);
1042
- color: var(--fd-warning-hover);
1043
- font-size: var(--fd-text-xs);
1044
- }
1045
-
1046
- .form-array__unsupported p {
1047
- margin: 0;
1048
- }
1098
+ .form-array__unsupported {
1099
+ padding: 0.75rem;
1100
+ background-color: var(--fd-warning-muted);
1101
+ border: 1px solid var(--fd-warning);
1102
+ border-radius: var(--fd-radius-md);
1103
+ color: var(--fd-warning-hover);
1104
+ font-size: var(--fd-text-xs);
1105
+ }
1106
+
1107
+ .form-array__unsupported p {
1108
+ margin: 0;
1109
+ }
1049
1110
  </style>