@object-ui/app-shell 6.2.3 → 7.1.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 (486) hide show
  1. package/CHANGELOG.md +1229 -0
  2. package/README.md +292 -0
  3. package/dist/assistant/assistantBus.d.ts +72 -0
  4. package/dist/assistant/assistantBus.js +133 -0
  5. package/dist/chrome/CommandPalette.d.ts +1 -1
  6. package/dist/chrome/CommandPalette.js +26 -22
  7. package/dist/chrome/ConditionalAuthWrapper.d.ts +1 -1
  8. package/dist/chrome/ConsoleToaster.d.ts +1 -1
  9. package/dist/chrome/ConsoleToaster.js +3 -1
  10. package/dist/chrome/ErrorBoundary.d.ts +1 -1
  11. package/dist/chrome/KeyboardShortcutsDialog.d.ts +1 -1
  12. package/dist/chrome/KeyboardShortcutsDialog.js +16 -5
  13. package/dist/chrome/LoadingScreen.d.ts +1 -1
  14. package/dist/chrome/LoadingScreen.js +22 -26
  15. package/dist/chrome/RouteFader.d.ts +1 -1
  16. package/dist/chrome/ThemeProvider.d.ts +1 -1
  17. package/dist/components/ManagedByBadge.d.ts +1 -1
  18. package/dist/console/AppContent.d.ts +1 -1
  19. package/dist/console/AppContent.js +184 -39
  20. package/dist/console/ConsoleShell.d.ts +7 -7
  21. package/dist/console/ConsoleShell.js +32 -3
  22. package/dist/console/ai/AiChatPage.d.ts +88 -1
  23. package/dist/console/ai/AiChatPage.js +747 -66
  24. package/dist/console/ai/ConversationsSidebar.d.ts +26 -1
  25. package/dist/console/ai/ConversationsSidebar.js +149 -34
  26. package/dist/console/ai/LiveCanvas.d.ts +28 -0
  27. package/dist/console/ai/LiveCanvas.js +80 -0
  28. package/dist/console/ai/reconcileTurn.d.ts +8 -0
  29. package/dist/console/ai/reconcileTurn.js +20 -0
  30. package/dist/console/auth/AuthPageLayout.d.ts +1 -1
  31. package/dist/console/auth/ForgotPasswordPage.d.ts +1 -1
  32. package/dist/console/auth/LoginPage.d.ts +1 -1
  33. package/dist/console/auth/RegisterPage.d.ts +1 -1
  34. package/dist/console/auth/RegisterPage.js +23 -3
  35. package/dist/console/cloud-connection/CloudConnectionPanel.d.ts +1 -0
  36. package/dist/console/cloud-connection/CloudConnectionPanel.js +169 -0
  37. package/dist/console/home/AppCard.d.ts +1 -1
  38. package/dist/console/home/AppCard.js +6 -12
  39. package/dist/console/home/HomeAppsStrip.d.ts +8 -0
  40. package/dist/console/home/HomeAppsStrip.js +61 -0
  41. package/dist/console/home/HomeLayout.d.ts +1 -1
  42. package/dist/console/home/HomeLayout.js +3 -1
  43. package/dist/console/home/HomePage.d.ts +1 -2
  44. package/dist/console/home/HomePage.js +149 -21
  45. package/dist/console/home/HomeRail.d.ts +22 -0
  46. package/dist/console/home/HomeRail.js +62 -0
  47. package/dist/console/home/QuickActions.d.ts +1 -1
  48. package/dist/console/home/QuickActions.js +3 -11
  49. package/dist/console/home/RecentApps.d.ts +1 -1
  50. package/dist/console/home/RecentApps.js +2 -2
  51. package/dist/console/home/StarredApps.d.ts +1 -1
  52. package/dist/console/home/StarredApps.js +2 -2
  53. package/dist/console/marketplace/InstalledListWidget.d.ts +1 -0
  54. package/dist/console/marketplace/InstalledListWidget.js +93 -0
  55. package/dist/console/marketplace/MarkdownText.d.ts +1 -1
  56. package/dist/console/marketplace/MarketplaceAccessDenied.d.ts +1 -1
  57. package/dist/console/marketplace/MarketplaceInstalledPage.d.ts +8 -14
  58. package/dist/console/marketplace/MarketplaceInstalledPage.js +14 -66
  59. package/dist/console/marketplace/MarketplacePackagePage.d.ts +1 -1
  60. package/dist/console/marketplace/MarketplacePackagePage.js +249 -8
  61. package/dist/console/marketplace/MarketplacePage.d.ts +1 -1
  62. package/dist/console/marketplace/MarketplacePage.js +60 -3
  63. package/dist/console/marketplace/PackageIcon.d.ts +1 -1
  64. package/dist/console/marketplace/PluginDisclosure.d.ts +14 -0
  65. package/dist/console/marketplace/PluginDisclosure.js +38 -0
  66. package/dist/console/marketplace/marketplaceApi.d.ts +123 -0
  67. package/dist/console/marketplace/marketplaceApi.js +254 -1
  68. package/dist/console/organizations/CreateWorkspaceDialog.d.ts +1 -1
  69. package/dist/console/organizations/OrganizationsLayout.d.ts +1 -1
  70. package/dist/console/organizations/OrganizationsPage.d.ts +1 -1
  71. package/dist/console/organizations/manage/AcceptInvitationPage.d.ts +1 -1
  72. package/dist/console/organizations/manage/InvitationsPage.d.ts +1 -1
  73. package/dist/console/organizations/manage/InviteMemberDialog.d.ts +1 -1
  74. package/dist/console/organizations/manage/MembersPage.d.ts +1 -1
  75. package/dist/console/organizations/manage/OrganizationLayout.d.ts +1 -1
  76. package/dist/console/organizations/manage/SettingsPage.d.ts +1 -1
  77. package/dist/context/CommandPaletteProvider.d.ts +44 -0
  78. package/dist/context/CommandPaletteProvider.js +71 -0
  79. package/dist/context/FavoritesProvider.d.ts +1 -1
  80. package/dist/context/NavigationContext.d.ts +1 -1
  81. package/dist/context/RecentItemsProvider.d.ts +2 -2
  82. package/dist/context/UserStateAdapters.d.ts +1 -1
  83. package/dist/context/index.d.ts +2 -0
  84. package/dist/context/index.js +1 -0
  85. package/dist/hooks/index.d.ts +5 -2
  86. package/dist/hooks/index.js +4 -1
  87. package/dist/hooks/useActionModal.d.ts +53 -0
  88. package/dist/hooks/useActionModal.js +111 -0
  89. package/dist/hooks/useChatConversation.d.ts +137 -4
  90. package/dist/hooks/useChatConversation.js +316 -25
  91. package/dist/hooks/useConsoleActionRuntime.d.ts +70 -0
  92. package/dist/hooks/useConsoleActionRuntime.js +564 -0
  93. package/dist/hooks/useConversationList.js +61 -3
  94. package/dist/hooks/useHomeInbox.d.ts +13 -0
  95. package/dist/hooks/useHomeInbox.js +142 -0
  96. package/dist/hooks/useNavPins.js +17 -23
  97. package/dist/hooks/useNavigationSync.d.ts +33 -0
  98. package/dist/hooks/useNavigationSync.js +98 -12
  99. package/dist/hooks/useReconcileOnError.d.ts +40 -0
  100. package/dist/hooks/useReconcileOnError.js +37 -0
  101. package/dist/hooks/useRecordApprovals.d.ts +18 -19
  102. package/dist/hooks/useRecordApprovals.js +24 -40
  103. package/dist/hooks/useResponsiveSidebar.js +14 -5
  104. package/dist/hooks/useSettleSignal.d.ts +19 -0
  105. package/dist/hooks/useSettleSignal.js +20 -0
  106. package/dist/hooks/useTrackRouteAsRecent.js +35 -0
  107. package/dist/hooks/useUrlOverlay.d.ts +62 -0
  108. package/dist/hooks/useUrlOverlay.js +88 -0
  109. package/dist/index.d.ts +18 -8
  110. package/dist/index.js +17 -5
  111. package/dist/layout/ActivityFeed.d.ts +1 -1
  112. package/dist/layout/AppHeader.d.ts +3 -2
  113. package/dist/layout/AppHeader.js +237 -72
  114. package/dist/layout/AppSidebar.d.ts +2 -1
  115. package/dist/layout/AppSidebar.js +26 -46
  116. package/dist/layout/AppSwitcher.d.ts +2 -1
  117. package/dist/layout/AppSwitcher.js +9 -5
  118. package/dist/layout/AuthPageLayout.d.ts +1 -1
  119. package/dist/layout/ConnectionStatus.d.ts +1 -1
  120. package/dist/layout/ConnectionStatus.js +9 -6
  121. package/dist/layout/ConsoleChatbotFab.d.ts +19 -1
  122. package/dist/layout/ConsoleChatbotFab.js +16 -2
  123. package/dist/layout/ConsoleFloatingChatbot.d.ts +34 -2
  124. package/dist/layout/ConsoleFloatingChatbot.js +391 -41
  125. package/dist/layout/ConsoleLayout.d.ts +1 -1
  126. package/dist/layout/ConsoleLayout.js +27 -11
  127. package/dist/layout/ContextSelectors.d.ts +44 -0
  128. package/dist/layout/ContextSelectors.js +242 -0
  129. package/dist/layout/InboxPopover.d.ts +6 -1
  130. package/dist/layout/InboxPopover.js +25 -6
  131. package/dist/layout/LocaleSwitcher.d.ts +1 -1
  132. package/dist/layout/LocalizedSidebarTrigger.d.ts +2 -0
  133. package/dist/layout/LocalizedSidebarTrigger.js +15 -0
  134. package/dist/layout/MobileViewSwitcherContext.d.ts +1 -1
  135. package/dist/layout/ModeToggle.d.ts +1 -1
  136. package/dist/layout/PageHeader.d.ts +1 -1
  137. package/dist/layout/UnifiedSidebar.d.ts +2 -1
  138. package/dist/layout/UnifiedSidebar.js +116 -15
  139. package/dist/layout/agentPicker.d.ts +56 -0
  140. package/dist/layout/agentPicker.js +40 -0
  141. package/dist/observability/index.d.ts +1 -0
  142. package/dist/observability/index.js +1 -0
  143. package/dist/observability/settleSignal.d.ts +64 -0
  144. package/dist/observability/settleSignal.js +131 -0
  145. package/dist/preview/CommitTimeline.d.ts +15 -0
  146. package/dist/preview/CommitTimeline.js +82 -0
  147. package/dist/preview/DraftChangesPanel.d.ts +19 -0
  148. package/dist/preview/DraftChangesPanel.js +114 -0
  149. package/dist/preview/DraftPreviewBar.d.ts +8 -0
  150. package/dist/preview/DraftPreviewBar.js +86 -0
  151. package/dist/preview/PreviewDraftEmptyState.d.ts +16 -0
  152. package/dist/preview/PreviewDraftEmptyState.js +47 -0
  153. package/dist/preview/PreviewModeContext.d.ts +57 -0
  154. package/dist/preview/PreviewModeContext.js +99 -0
  155. package/dist/preview/UnpublishedAppBar.d.ts +8 -0
  156. package/dist/preview/UnpublishedAppBar.js +83 -0
  157. package/dist/preview/commitHistory.d.ts +28 -0
  158. package/dist/preview/commitHistory.js +48 -0
  159. package/dist/preview/draftStatus.d.ts +20 -0
  160. package/dist/preview/draftStatus.js +27 -0
  161. package/dist/preview/usePublishAllDrafts.d.ts +18 -0
  162. package/dist/preview/usePublishAllDrafts.js +106 -0
  163. package/dist/providers/AdapterProvider.d.ts +1 -1
  164. package/dist/providers/AdapterProvider.js +6 -1
  165. package/dist/providers/ExpressionProvider.d.ts +1 -1
  166. package/dist/providers/MetadataProvider.d.ts +17 -2
  167. package/dist/providers/MetadataProvider.js +192 -12
  168. package/dist/runtime-config.d.ts +46 -2
  169. package/dist/runtime-config.js +39 -2
  170. package/dist/services/builtinComponents.js +68 -59
  171. package/dist/skeletons/SkeletonDashboard.d.ts +1 -1
  172. package/dist/skeletons/SkeletonDetail.d.ts +1 -1
  173. package/dist/skeletons/SkeletonGrid.d.ts +1 -1
  174. package/dist/utils/appRoute.d.ts +21 -0
  175. package/dist/utils/appRoute.js +25 -0
  176. package/dist/utils/deriveRelatedLists.d.ts +54 -0
  177. package/dist/utils/deriveRelatedLists.js +91 -0
  178. package/dist/utils/index.d.ts +4 -0
  179. package/dist/utils/index.js +3 -0
  180. package/dist/utils/managedByEmptyState.d.ts +8 -1
  181. package/dist/utils/managedByEmptyState.js +13 -7
  182. package/dist/utils/preferLocal.d.ts +18 -0
  183. package/dist/utils/preferLocal.js +24 -0
  184. package/dist/views/ActionConfirmDialog.d.ts +1 -1
  185. package/dist/views/ActionConfirmDialog.js +3 -1
  186. package/dist/views/ActionParamDialog.d.ts +6 -1
  187. package/dist/views/ActionParamDialog.js +9 -3
  188. package/dist/views/ActionResultDialog.d.ts +13 -0
  189. package/dist/views/ActionResultDialog.js +134 -0
  190. package/dist/views/ComponentNavView.d.ts +14 -1
  191. package/dist/views/CreateViewDialog.d.ts +1 -1
  192. package/dist/views/DashboardConfigPanel.d.ts +28 -0
  193. package/dist/views/DashboardConfigPanel.js +81 -0
  194. package/dist/views/DashboardView.d.ts +4 -3
  195. package/dist/views/DashboardView.js +38 -239
  196. package/dist/views/FlowRunner.d.ts +31 -0
  197. package/dist/views/FlowRunner.js +121 -0
  198. package/dist/views/InterfaceListPage.d.ts +49 -0
  199. package/dist/views/InterfaceListPage.js +347 -0
  200. package/dist/views/MetadataInspector.d.ts +2 -2
  201. package/dist/views/ObjectView.d.ts +1 -1
  202. package/dist/views/ObjectView.js +209 -532
  203. package/dist/views/PageView.d.ts +8 -3
  204. package/dist/views/PageView.js +45 -32
  205. package/dist/views/RecordDetailView.d.ts +1 -1
  206. package/dist/views/RecordDetailView.js +363 -148
  207. package/dist/views/RecordFormPage.d.ts +1 -1
  208. package/dist/views/RecordFormPage.js +26 -1
  209. package/dist/views/ReportConfigPanel.d.ts +37 -0
  210. package/dist/views/ReportConfigPanel.js +85 -0
  211. package/dist/views/ReportView.d.ts +1 -1
  212. package/dist/views/ReportView.js +116 -7
  213. package/dist/views/RuntimeDraftBar.d.ts +30 -0
  214. package/dist/views/RuntimeDraftBar.js +112 -0
  215. package/dist/views/ScreenView.d.ts +70 -0
  216. package/dist/views/ScreenView.js +73 -0
  217. package/dist/views/SearchResultsPage.d.ts +1 -1
  218. package/dist/views/SearchResultsPage.js +8 -18
  219. package/dist/views/ViewConfigPanel.d.ts +24 -17
  220. package/dist/views/ViewConfigPanel.js +121 -77
  221. package/dist/views/index.d.ts +1 -1
  222. package/dist/views/index.js +1 -1
  223. package/dist/views/metadata-admin/AuditPanel.d.ts +28 -0
  224. package/dist/views/metadata-admin/AuditPanel.js +79 -0
  225. package/dist/views/metadata-admin/DiagnosticsPage.d.ts +20 -0
  226. package/dist/views/metadata-admin/DiagnosticsPage.js +69 -0
  227. package/dist/views/metadata-admin/DirectoryPage.d.ts +16 -1
  228. package/dist/views/metadata-admin/DirectoryPage.js +101 -24
  229. package/dist/views/metadata-admin/DraftReviewPanel.d.ts +33 -0
  230. package/dist/views/metadata-admin/DraftReviewPanel.js +77 -0
  231. package/dist/views/metadata-admin/EmbeddedItemEditor.d.ts +17 -1
  232. package/dist/views/metadata-admin/EmbeddedItemEditor.js +15 -8
  233. package/dist/views/metadata-admin/JsonSourceEditor.d.ts +39 -0
  234. package/dist/views/metadata-admin/JsonSourceEditor.js +196 -0
  235. package/dist/views/metadata-admin/LayeredDiff.d.ts +39 -1
  236. package/dist/views/metadata-admin/LayeredDiff.js +171 -5
  237. package/dist/views/metadata-admin/MetadataDetailDrawer.d.ts +15 -1
  238. package/dist/views/metadata-admin/MetadataTypeActions.d.ts +48 -0
  239. package/dist/views/metadata-admin/MetadataTypeActions.js +165 -0
  240. package/dist/views/metadata-admin/PackagesPage.d.ts +18 -0
  241. package/dist/views/metadata-admin/PackagesPage.js +403 -0
  242. package/dist/views/metadata-admin/PageShell.d.ts +1 -1
  243. package/dist/views/metadata-admin/PageShell.js +9 -4
  244. package/dist/views/metadata-admin/PermissionMatrixEditor.d.ts +35 -1
  245. package/dist/views/metadata-admin/QuickFind.d.ts +21 -1
  246. package/dist/views/metadata-admin/QuickFind.js +6 -3
  247. package/dist/views/metadata-admin/RelatedPanel.d.ts +24 -1
  248. package/dist/views/metadata-admin/RelatedPanel.js +20 -18
  249. package/dist/views/metadata-admin/ResourceEditPage.d.ts +40 -1
  250. package/dist/views/metadata-admin/ResourceEditPage.js +1250 -60
  251. package/dist/views/metadata-admin/ResourceHistoryPage.d.ts +39 -1
  252. package/dist/views/metadata-admin/ResourceHistoryPage.js +66 -16
  253. package/dist/views/metadata-admin/ResourceListPage.d.ts +13 -1
  254. package/dist/views/metadata-admin/ResourceListPage.js +258 -30
  255. package/dist/views/metadata-admin/ResourceRouter.d.ts +23 -1
  256. package/dist/views/metadata-admin/SchemaForm.d.ts +34 -1
  257. package/dist/views/metadata-admin/SchemaForm.js +559 -49
  258. package/dist/views/metadata-admin/StudioHomePage.d.ts +22 -0
  259. package/dist/views/metadata-admin/StudioHomePage.js +205 -0
  260. package/dist/views/metadata-admin/anchors.js +255 -24
  261. package/dist/views/metadata-admin/clientValidation.d.ts +50 -0
  262. package/dist/views/metadata-admin/clientValidation.js +169 -0
  263. package/dist/views/metadata-admin/color-variant-field.d.ts +30 -0
  264. package/dist/views/metadata-admin/color-variant-field.js +38 -0
  265. package/dist/views/metadata-admin/createDerive.d.ts +75 -0
  266. package/dist/views/metadata-admin/createDerive.js +179 -0
  267. package/dist/views/metadata-admin/dashboard-schema.d.ts +12 -0
  268. package/dist/views/metadata-admin/dashboard-schema.js +80 -0
  269. package/dist/views/metadata-admin/datasource/DatasourceResourcePage.d.ts +35 -0
  270. package/dist/views/metadata-admin/datasource/DatasourceResourcePage.js +327 -0
  271. package/dist/views/metadata-admin/datasource/register.d.ts +1 -0
  272. package/dist/views/metadata-admin/datasource/register.js +24 -0
  273. package/dist/views/metadata-admin/default-inspector-registry.d.ts +49 -0
  274. package/dist/views/metadata-admin/default-inspector-registry.js +8 -0
  275. package/dist/views/metadata-admin/default-schemas.js +115 -10
  276. package/dist/views/metadata-admin/external/ExternalDatasourcePanel.d.ts +27 -0
  277. package/dist/views/metadata-admin/external/ExternalDatasourcePanel.js +69 -0
  278. package/dist/views/metadata-admin/external/ImportObjectDialog.d.ts +27 -0
  279. package/dist/views/metadata-admin/external/ImportObjectDialog.js +77 -0
  280. package/dist/views/metadata-admin/external/SchemaBrowser.d.ts +16 -0
  281. package/dist/views/metadata-admin/external/SchemaBrowser.js +74 -0
  282. package/dist/views/metadata-admin/external/ValidationPanel.d.ts +16 -0
  283. package/dist/views/metadata-admin/external/ValidationPanel.js +68 -0
  284. package/dist/views/metadata-admin/external/api.d.ts +100 -0
  285. package/dist/views/metadata-admin/external/api.js +124 -0
  286. package/dist/views/metadata-admin/i18n.d.ts +1 -0
  287. package/dist/views/metadata-admin/i18n.js +1252 -2
  288. package/dist/views/metadata-admin/index.d.ts +8 -5
  289. package/dist/views/metadata-admin/index.js +12 -2
  290. package/dist/views/metadata-admin/inspector-registry.d.ts +51 -0
  291. package/dist/views/metadata-admin/inspector-registry.js +11 -0
  292. package/dist/views/metadata-admin/inspectors/ActionDefaultInspector.d.ts +30 -0
  293. package/dist/views/metadata-admin/inspectors/ActionDefaultInspector.js +180 -0
  294. package/dist/views/metadata-admin/inspectors/AppNavInspector.d.ts +16 -0
  295. package/dist/views/metadata-admin/inspectors/AppNavInspector.js +110 -0
  296. package/dist/views/metadata-admin/inspectors/ConditionBuilder.d.ts +29 -0
  297. package/dist/views/metadata-admin/inspectors/ConditionBuilder.js +154 -0
  298. package/dist/views/metadata-admin/inspectors/DashboardDefaultInspector.d.ts +28 -0
  299. package/dist/views/metadata-admin/inspectors/DashboardDefaultInspector.js +110 -0
  300. package/dist/views/metadata-admin/inspectors/DashboardWidgetInspector.d.ts +18 -0
  301. package/dist/views/metadata-admin/inspectors/DashboardWidgetInspector.js +139 -0
  302. package/dist/views/metadata-admin/inspectors/DatasetDefaultInspector.d.ts +21 -0
  303. package/dist/views/metadata-admin/inspectors/DatasetDefaultInspector.js +221 -0
  304. package/dist/views/metadata-admin/inspectors/FlowEdgeInspector.d.ts +16 -0
  305. package/dist/views/metadata-admin/inspectors/FlowEdgeInspector.js +126 -0
  306. package/dist/views/metadata-admin/inspectors/FlowInspector.d.ts +12 -0
  307. package/dist/views/metadata-admin/inspectors/FlowInspector.js +9 -0
  308. package/dist/views/metadata-admin/inspectors/FlowKeyValueField.d.ts +30 -0
  309. package/dist/views/metadata-admin/inspectors/FlowKeyValueField.js +125 -0
  310. package/dist/views/metadata-admin/inspectors/FlowNodeConfigField.d.ts +18 -0
  311. package/dist/views/metadata-admin/inspectors/FlowNodeConfigField.js +40 -0
  312. package/dist/views/metadata-admin/inspectors/FlowNodeInspector.d.ts +14 -0
  313. package/dist/views/metadata-admin/inspectors/FlowNodeInspector.js +205 -0
  314. package/dist/views/metadata-admin/inspectors/FlowObjectListField.d.ts +26 -0
  315. package/dist/views/metadata-admin/inspectors/FlowObjectListField.js +105 -0
  316. package/dist/views/metadata-admin/inspectors/FlowReferenceField.d.ts +83 -0
  317. package/dist/views/metadata-admin/inspectors/FlowReferenceField.js +181 -0
  318. package/dist/views/metadata-admin/inspectors/FlowStringListField.d.ts +21 -0
  319. package/dist/views/metadata-admin/inspectors/FlowStringListField.js +60 -0
  320. package/dist/views/metadata-admin/inspectors/InspectorComboField.d.ts +40 -0
  321. package/dist/views/metadata-admin/inspectors/InspectorComboField.js +61 -0
  322. package/dist/views/metadata-admin/inspectors/ObjectDefaultInspector.d.ts +21 -0
  323. package/dist/views/metadata-admin/inspectors/ObjectDefaultInspector.js +55 -0
  324. package/dist/views/metadata-admin/inspectors/ObjectFieldInspector.d.ts +23 -0
  325. package/dist/views/metadata-admin/inspectors/ObjectFieldInspector.js +365 -0
  326. package/dist/views/metadata-admin/inspectors/PageBlockInspector.d.ts +48 -0
  327. package/dist/views/metadata-admin/inspectors/PageBlockInspector.js +332 -0
  328. package/dist/views/metadata-admin/inspectors/ReportDefaultInspector.d.ts +58 -0
  329. package/dist/views/metadata-admin/inspectors/ReportDefaultInspector.js +218 -0
  330. package/dist/views/metadata-admin/inspectors/ViewColumnInspector.d.ts +19 -0
  331. package/dist/views/metadata-admin/inspectors/ViewColumnInspector.js +144 -0
  332. package/dist/views/metadata-admin/inspectors/ViewInspector.d.ts +19 -0
  333. package/dist/views/metadata-admin/inspectors/ViewInspector.js +21 -0
  334. package/dist/views/metadata-admin/inspectors/ViewVariantInspector.d.ts +54 -0
  335. package/dist/views/metadata-admin/inspectors/ViewVariantInspector.js +191 -0
  336. package/dist/views/metadata-admin/inspectors/_shared.d.ts +128 -0
  337. package/dist/views/metadata-admin/inspectors/_shared.js +113 -0
  338. package/dist/views/metadata-admin/inspectors/datasetFilterCondition.d.ts +24 -0
  339. package/dist/views/metadata-admin/inspectors/datasetFilterCondition.js +97 -0
  340. package/dist/views/metadata-admin/inspectors/expression-validate.d.ts +26 -0
  341. package/dist/views/metadata-admin/inspectors/expression-validate.js +66 -0
  342. package/dist/views/metadata-admin/inspectors/flow-node-config.d.ts +143 -0
  343. package/dist/views/metadata-admin/inspectors/flow-node-config.js +506 -0
  344. package/dist/views/metadata-admin/inspectors/index.d.ts +1 -0
  345. package/dist/views/metadata-admin/inspectors/index.js +45 -0
  346. package/dist/views/metadata-admin/inspectors/json-schema-to-fields.d.ts +40 -0
  347. package/dist/views/metadata-admin/inspectors/json-schema-to-fields.js +227 -0
  348. package/dist/views/metadata-admin/inspectors/useDatasetFields.d.ts +72 -0
  349. package/dist/views/metadata-admin/inspectors/useDatasetFields.js +0 -0
  350. package/dist/views/metadata-admin/issuePath.d.ts +22 -0
  351. package/dist/views/metadata-admin/issuePath.js +65 -0
  352. package/dist/views/metadata-admin/mergeServerFields.d.ts +65 -0
  353. package/dist/views/metadata-admin/mergeServerFields.js +56 -0
  354. package/dist/views/metadata-admin/package-scope.d.ts +26 -0
  355. package/dist/views/metadata-admin/package-scope.js +43 -0
  356. package/dist/views/metadata-admin/preview-registry.d.ts +55 -0
  357. package/dist/views/metadata-admin/previews/ActionPreview.d.ts +25 -0
  358. package/dist/views/metadata-admin/previews/ActionPreview.js +238 -0
  359. package/dist/views/metadata-admin/previews/AddWidgetPicker.d.ts +12 -0
  360. package/dist/views/metadata-admin/previews/AddWidgetPicker.js +56 -0
  361. package/dist/views/metadata-admin/previews/AgentPreview.d.ts +24 -0
  362. package/dist/views/metadata-admin/previews/AgentPreview.js +100 -0
  363. package/dist/views/metadata-admin/previews/AppNavCanvas.d.ts +31 -0
  364. package/dist/views/metadata-admin/previews/AppNavCanvas.js +260 -0
  365. package/dist/views/metadata-admin/previews/AppPreview.d.ts +16 -1
  366. package/dist/views/metadata-admin/previews/AppPreview.js +23 -14
  367. package/dist/views/metadata-admin/previews/BookPreview.d.ts +20 -0
  368. package/dist/views/metadata-admin/previews/BookPreview.js +132 -0
  369. package/dist/views/metadata-admin/previews/DashboardPreview.d.ts +16 -1
  370. package/dist/views/metadata-admin/previews/DashboardPreview.js +110 -8
  371. package/dist/views/metadata-admin/previews/DatasetPreview.d.ts +18 -0
  372. package/dist/views/metadata-admin/previews/DatasetPreview.js +105 -0
  373. package/dist/views/metadata-admin/previews/DatasourcePreview.d.ts +23 -0
  374. package/dist/views/metadata-admin/previews/DatasourcePreview.js +68 -0
  375. package/dist/views/metadata-admin/previews/EmailTemplatePreview.d.ts +14 -1
  376. package/dist/views/metadata-admin/previews/FieldStub.d.ts +30 -0
  377. package/dist/views/metadata-admin/previews/FieldStub.js +104 -0
  378. package/dist/views/metadata-admin/previews/FieldsListEditor.d.ts +50 -0
  379. package/dist/views/metadata-admin/previews/FieldsListEditor.js +97 -0
  380. package/dist/views/metadata-admin/previews/FlowCanvas.d.ts +49 -0
  381. package/dist/views/metadata-admin/previews/FlowCanvas.js +416 -0
  382. package/dist/views/metadata-admin/previews/FlowPreview.d.ts +20 -0
  383. package/dist/views/metadata-admin/previews/FlowPreview.js +120 -0
  384. package/dist/views/metadata-admin/previews/FlowRunsPanel.d.ts +46 -0
  385. package/dist/views/metadata-admin/previews/FlowRunsPanel.js +97 -0
  386. package/dist/views/metadata-admin/previews/FlowSimulatorPanel.d.ts +25 -0
  387. package/dist/views/metadata-admin/previews/FlowSimulatorPanel.js +204 -0
  388. package/dist/views/metadata-admin/previews/JobPreview.d.ts +28 -0
  389. package/dist/views/metadata-admin/previews/JobPreview.js +290 -0
  390. package/dist/views/metadata-admin/previews/ObjectFormCanvas.d.ts +30 -0
  391. package/dist/views/metadata-admin/previews/ObjectFormCanvas.js +547 -0
  392. package/dist/views/metadata-admin/previews/ObjectPreview.d.ts +14 -1
  393. package/dist/views/metadata-admin/previews/ObjectPreview.js +5 -30
  394. package/dist/views/metadata-admin/previews/OutlineStrip.d.ts +32 -0
  395. package/dist/views/metadata-admin/previews/OutlineStrip.js +8 -0
  396. package/dist/views/metadata-admin/previews/PageBlockCanvas.d.ts +49 -0
  397. package/dist/views/metadata-admin/previews/PageBlockCanvas.js +510 -0
  398. package/dist/views/metadata-admin/previews/PagePreview.d.ts +10 -1
  399. package/dist/views/metadata-admin/previews/PagePreview.js +200 -5
  400. package/dist/views/metadata-admin/previews/PermissionPreview.d.ts +27 -0
  401. package/dist/views/metadata-admin/previews/PermissionPreview.js +115 -0
  402. package/dist/views/metadata-admin/previews/PreviewShell.d.ts +29 -6
  403. package/dist/views/metadata-admin/previews/PreviewShell.js +16 -3
  404. package/dist/views/metadata-admin/previews/ReportPreview.d.ts +18 -1
  405. package/dist/views/metadata-admin/previews/ReportPreview.js +23 -15
  406. package/dist/views/metadata-admin/previews/RolePreview.d.ts +19 -0
  407. package/dist/views/metadata-admin/previews/RolePreview.js +14 -0
  408. package/dist/views/metadata-admin/previews/ScreenPreview.d.ts +38 -0
  409. package/dist/views/metadata-admin/previews/ScreenPreview.js +61 -0
  410. package/dist/views/metadata-admin/previews/SkillPreview.d.ts +22 -0
  411. package/dist/views/metadata-admin/previews/SkillPreview.js +34 -0
  412. package/dist/views/metadata-admin/previews/ToolPreview.d.ts +25 -0
  413. package/dist/views/metadata-admin/previews/ToolPreview.js +122 -0
  414. package/dist/views/metadata-admin/previews/TranslationPreview.d.ts +25 -0
  415. package/dist/views/metadata-admin/previews/TranslationPreview.js +52 -0
  416. package/dist/views/metadata-admin/previews/ValidationPreview.d.ts +27 -0
  417. package/dist/views/metadata-admin/previews/ValidationPreview.js +110 -0
  418. package/dist/views/metadata-admin/previews/ViewColumnPanes.d.ts +62 -0
  419. package/dist/views/metadata-admin/previews/ViewColumnPanes.js +140 -0
  420. package/dist/views/metadata-admin/previews/ViewPreview.d.ts +23 -1
  421. package/dist/views/metadata-admin/previews/ViewPreview.js +101 -73
  422. package/dist/views/metadata-admin/previews/block-config.d.ts +82 -0
  423. package/dist/views/metadata-admin/previews/block-config.js +324 -0
  424. package/dist/views/metadata-admin/previews/block-types.d.ts +40 -0
  425. package/dist/views/metadata-admin/previews/block-types.js +110 -0
  426. package/dist/views/metadata-admin/previews/field-types.d.ts +53 -0
  427. package/dist/views/metadata-admin/previews/field-types.js +97 -0
  428. package/dist/views/metadata-admin/previews/flow-canvas-layout.d.ts +102 -0
  429. package/dist/views/metadata-admin/previews/flow-canvas-layout.js +227 -0
  430. package/dist/views/metadata-admin/previews/flow-canvas-parts.d.ts +96 -0
  431. package/dist/views/metadata-admin/previews/flow-canvas-parts.js +373 -0
  432. package/dist/views/metadata-admin/previews/form-preview.d.ts +24 -0
  433. package/dist/views/metadata-admin/previews/form-preview.js +29 -0
  434. package/dist/views/metadata-admin/previews/index.js +43 -0
  435. package/dist/views/metadata-admin/previews/object-fields-bridge.d.ts +66 -0
  436. package/dist/views/metadata-admin/previews/object-fields-bridge.js +171 -0
  437. package/dist/views/metadata-admin/previews/object-fields-io.d.ts +130 -0
  438. package/dist/views/metadata-admin/previews/object-fields-io.js +243 -0
  439. package/dist/views/metadata-admin/previews/screen-spec.d.ts +43 -0
  440. package/dist/views/metadata-admin/previews/screen-spec.js +108 -0
  441. package/dist/views/metadata-admin/previews/simulator/flow-sim-types.d.ts +102 -0
  442. package/dist/views/metadata-admin/previews/simulator/flow-sim-types.js +2 -0
  443. package/dist/views/metadata-admin/previews/simulator/flow-sim-validate.d.ts +15 -0
  444. package/dist/views/metadata-admin/previews/simulator/flow-sim-validate.js +185 -0
  445. package/dist/views/metadata-admin/previews/simulator/flow-simulator.d.ts +73 -0
  446. package/dist/views/metadata-admin/previews/simulator/flow-simulator.js +426 -0
  447. package/dist/views/metadata-admin/previews/useDatasetCatalog.d.ts +47 -0
  448. package/dist/views/metadata-admin/previews/useDatasetCatalog.js +133 -0
  449. package/dist/views/metadata-admin/previews/useFlowNodePalette.d.ts +44 -0
  450. package/dist/views/metadata-admin/previews/useFlowNodePalette.js +124 -0
  451. package/dist/views/metadata-admin/previews/useMetaOptions.d.ts +8 -0
  452. package/dist/views/metadata-admin/previews/useMetaOptions.js +50 -0
  453. package/dist/views/metadata-admin/previews/useObjectFields.d.ts +23 -0
  454. package/dist/views/metadata-admin/previews/useObjectFields.js +79 -0
  455. package/dist/views/metadata-admin/previews/useObjectOptions.d.ts +8 -0
  456. package/dist/views/metadata-admin/previews/useObjectOptions.js +43 -0
  457. package/dist/views/metadata-admin/previews/view-column-io.d.ts +42 -0
  458. package/dist/views/metadata-admin/previews/view-column-io.js +73 -0
  459. package/dist/views/metadata-admin/previews/widget-types.d.ts +24 -0
  460. package/dist/views/metadata-admin/previews/widget-types.js +40 -0
  461. package/dist/views/metadata-admin/registry.d.ts +140 -19
  462. package/dist/views/metadata-admin/report-schema.d.ts +26 -0
  463. package/dist/views/metadata-admin/report-schema.js +121 -0
  464. package/dist/views/metadata-admin/useMetadata.d.ts +100 -2
  465. package/dist/views/metadata-admin/useMetadata.js +155 -4
  466. package/dist/views/metadata-admin/view-item-normalize.d.ts +20 -0
  467. package/dist/views/metadata-admin/view-item-normalize.js +68 -0
  468. package/dist/views/metadata-admin/view-schema.d.ts +16 -0
  469. package/dist/views/metadata-admin/view-schema.js +107 -0
  470. package/dist/views/metadata-admin/view-variant-model.d.ts +23 -0
  471. package/dist/views/metadata-admin/view-variant-model.js +64 -0
  472. package/dist/views/metadata-admin/widgets.d.ts +89 -1
  473. package/dist/views/metadata-admin/widgets.js +491 -17
  474. package/dist/views/runtime-metadata-persistence.d.ts +78 -0
  475. package/dist/views/runtime-metadata-persistence.js +89 -0
  476. package/dist/views/useOpenRecordList.d.ts +18 -0
  477. package/dist/views/useOpenRecordList.js +36 -0
  478. package/dist/views/userFilterUrlState.d.ts +15 -0
  479. package/dist/views/userFilterUrlState.js +53 -0
  480. package/dist/views/view-config-adapter.d.ts +38 -0
  481. package/dist/views/view-config-adapter.js +80 -0
  482. package/package.json +52 -34
  483. package/dist/views/DesignDrawer.d.ts +0 -28
  484. package/dist/views/DesignDrawer.js +0 -51
  485. package/dist/views/metadata-admin/DesignerEditorWrapper.d.ts +0 -68
  486. package/dist/views/metadata-admin/DesignerEditorWrapper.js +0 -158
@@ -0,0 +1,547 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ // Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
3
+ /**
4
+ * ObjectFormCanvas — form-designer-style preview for an Object
5
+ * metadata draft. Replaces the legacy CRUD grid in DesignerMode.
6
+ *
7
+ * Each field renders as the labeled input it will become at runtime
8
+ * (via {@link FieldStub}). Clicking a row selects it and the host
9
+ * swaps the inspector to {@link ObjectFieldInspector}. The trailing
10
+ * "+ Add field" button opens a categorized type picker — picking a
11
+ * type appends a fresh field and immediately selects it so authors
12
+ * can fill in name/label in the inspector.
13
+ *
14
+ * All edits go through the host's `onPatch` callback. Read-only
15
+ * surfaces (legacy tier objects, builtin objects) still render the
16
+ * preview but suppress selection chrome + the add button.
17
+ */
18
+ import * as React from 'react';
19
+ import { Badge, Button, cn, Popover, PopoverContent, PopoverTrigger, } from '@object-ui/components';
20
+ import { GripVertical, Plus, ChevronDown, ChevronRight, Trash2, ArrowUp, ArrowDown, FolderPlus, FolderInput, ChevronsDownUp, ChevronsUpDown, CheckSquare, GitCompareArrows, Sparkles, X, } from 'lucide-react';
21
+ import { requestAssistantOpen } from '../../../assistant/assistantBus';
22
+ import { readFields, writeFields, newField, toFieldName, groupEntries, readGroups, addGroup, renameGroup, removeGroup, moveGroup, clearFieldGroup, diffFields, } from './object-fields-io';
23
+ import { FIELD_TYPE_META, TYPES_BY_CATEGORY, CATEGORY_LABEL_EN, CATEGORY_LABEL_ZH, CATEGORY_TONE, } from './field-types';
24
+ import { FieldStub } from './FieldStub';
25
+ import { t, tFormat } from '../i18n';
26
+ /* ─── locale helpers ─── */
27
+ const isZh = (locale) => (locale ?? '').toLowerCase().startsWith('zh');
28
+ /** Field-type display label in the active locale (data carries both). */
29
+ const typeLabel = (meta, locale) => meta ? (isZh(locale) ? meta.labelZh : meta.label) : undefined;
30
+ const categoryLabel = (cat, locale) => (isZh(locale) ? CATEGORY_LABEL_ZH : CATEGORY_LABEL_EN)[cat];
31
+ export function ObjectFormCanvas({ objectName, draft, baseline, onPatch, selection, onSelectionChange, locale, }) {
32
+ const readOnly = !onPatch;
33
+ const view = React.useMemo(() => readFields(draft.fields), [draft]);
34
+ /* ─── Review/diff mode — draft vs last published ─── */
35
+ const diff = React.useMemo(() => (baseline ? diffFields(baseline.fields, draft.fields) : null), [baseline, draft]);
36
+ const changeCount = diff
37
+ ? diff.counts.added + diff.counts.changed + diff.counts.removed
38
+ : 0;
39
+ const [reviewMode, setReviewMode] = React.useState(false);
40
+ // Auto-exit review when nothing differs anymore (e.g. user reverted edits).
41
+ React.useEffect(() => {
42
+ if (reviewMode && changeCount === 0)
43
+ setReviewMode(false);
44
+ }, [reviewMode, changeCount]);
45
+ const reviewing = reviewMode && changeCount > 0;
46
+ const statusOf = (name) => reviewing ? diff?.byName[name]?.status : undefined;
47
+ const changedKeysOf = (name) => reviewing ? diff?.byName[name]?.changedKeys ?? [] : [];
48
+ const declaredGroups = React.useMemo(() => readGroups(draft.fieldGroups), [draft]);
49
+ const hasGroups = declaredGroups.length > 0;
50
+ // While editing, keep empty declared sections visible as drop targets.
51
+ const groups = React.useMemo(() => groupEntries(view, declaredGroups, { includeEmptyDeclared: !readOnly }), [view, declaredGroups, readOnly]);
52
+ // Collapse state is local UI — keyed by group key (null bucket → "").
53
+ const [collapsed, setCollapsed] = React.useState({});
54
+ const collapseKey = (key) => key ?? '__ungrouped__';
55
+ const toggleCollapse = React.useCallback((key) => {
56
+ const k = key ?? '__ungrouped__';
57
+ setCollapsed((prev) => ({ ...prev, [k]: !prev[k] }));
58
+ }, []);
59
+ const allCollapsed = groups.length > 0 && groups.every((g) => collapsed[collapseKey(g.key)]);
60
+ const setAllCollapsed = React.useCallback((value) => {
61
+ setCollapsed(() => {
62
+ const next = {};
63
+ for (const g of groups)
64
+ next[collapseKey(g.key)] = value;
65
+ return next;
66
+ });
67
+ }, [groups]);
68
+ const selectedName = selection?.kind === 'field' ? String(selection.id) : null;
69
+ const requiredCount = view.entries.filter((e) => !!e.def.required).length;
70
+ const selectField = React.useCallback((entry) => {
71
+ if (!onSelectionChange)
72
+ return;
73
+ onSelectionChange({
74
+ kind: 'field',
75
+ id: entry.name,
76
+ label: typeof entry.def.label === 'string' ? entry.def.label : entry.name,
77
+ });
78
+ }, [onSelectionChange]);
79
+ /* ─── Multi-select (bulk ops) — canvas-local; no host coupling ─── */
80
+ const [multiSel, setMultiSel] = React.useState(() => new Set());
81
+ const anchorRef = React.useRef(null);
82
+ // Flat rendered order, for Shift-range selection.
83
+ const flatNames = React.useMemo(() => groups.flatMap((g) => g.entries.map((e) => e.name)), [groups]);
84
+ // Drop names that no longer exist (e.g. after a bulk delete elsewhere).
85
+ React.useEffect(() => {
86
+ setMultiSel((prev) => {
87
+ if (prev.size === 0)
88
+ return prev;
89
+ const live = new Set([...prev].filter((n) => view.entries.some((e) => e.name === n)));
90
+ return live.size === prev.size ? prev : live;
91
+ });
92
+ }, [view]);
93
+ const handleRowClick = React.useCallback((entry, e) => {
94
+ const name = entry.name;
95
+ if (!readOnly && e && (e.metaKey || e.ctrlKey)) {
96
+ setMultiSel((prev) => {
97
+ const next = new Set(prev);
98
+ if (next.has(name))
99
+ next.delete(name);
100
+ else
101
+ next.add(name);
102
+ return next;
103
+ });
104
+ anchorRef.current = name;
105
+ return;
106
+ }
107
+ if (!readOnly && e && e.shiftKey && anchorRef.current && anchorRef.current !== name) {
108
+ const a = flatNames.indexOf(anchorRef.current);
109
+ const b = flatNames.indexOf(name);
110
+ if (a >= 0 && b >= 0) {
111
+ const [lo, hi] = a < b ? [a, b] : [b, a];
112
+ setMultiSel(new Set(flatNames.slice(lo, hi + 1)));
113
+ return;
114
+ }
115
+ }
116
+ // Plain click — clear multi-selection, single-select.
117
+ if (multiSel.size)
118
+ setMultiSel(new Set());
119
+ anchorRef.current = name;
120
+ selectField(entry);
121
+ }, [readOnly, flatNames, multiSel, selectField]);
122
+ const clearMulti = React.useCallback(() => setMultiSel(new Set()), []);
123
+ const bulkDelete = React.useCallback(() => {
124
+ if (!onPatch || multiSel.size === 0)
125
+ return;
126
+ const entries = view.entries.filter((e) => !multiSel.has(e.name));
127
+ onPatch({ fields: writeFields({ shape: view.shape, entries }) });
128
+ if (selectedName && multiSel.has(selectedName))
129
+ onSelectionChange?.(null);
130
+ setMultiSel(new Set());
131
+ }, [onPatch, multiSel, view, selectedName, onSelectionChange]);
132
+ const bulkSetGroup = React.useCallback((groupKey) => {
133
+ if (!onPatch || multiSel.size === 0)
134
+ return;
135
+ const entries = view.entries.map((e) => multiSel.has(e.name)
136
+ ? { name: e.name, def: { ...e.def, group: groupKey ?? undefined } }
137
+ : e);
138
+ onPatch({ fields: writeFields({ shape: view.shape, entries }) });
139
+ }, [onPatch, multiSel, view]);
140
+ const addField = React.useCallback((type, groupKey) => {
141
+ if (!onPatch)
142
+ return;
143
+ const existing = view.entries.map((e) => e.name);
144
+ const base = type === 'select' ? 'status' : type;
145
+ let i = 1;
146
+ let name = base;
147
+ while (existing.includes(name)) {
148
+ i += 1;
149
+ name = `${base}_${i}`;
150
+ }
151
+ const entry = newField(name, type);
152
+ if (groupKey)
153
+ entry.def = { ...entry.def, group: groupKey };
154
+ // Insert at the end of the target group's run so it lands in-section,
155
+ // otherwise append to the very end (ungrouped / no groups).
156
+ let insertAt = view.entries.length;
157
+ if (groupKey) {
158
+ for (let j = view.entries.length - 1; j >= 0; j -= 1) {
159
+ if (view.entries[j].def.group === groupKey) {
160
+ insertAt = j + 1;
161
+ break;
162
+ }
163
+ }
164
+ }
165
+ const entries = view.entries.slice();
166
+ entries.splice(insertAt, 0, entry);
167
+ onPatch({ fields: writeFields({ shape: view.shape, entries }) });
168
+ onSelectionChange?.({
169
+ kind: 'field',
170
+ id: name,
171
+ label: String(entry.def.label ?? name),
172
+ });
173
+ }, [onPatch, onSelectionChange, view]);
174
+ /* ─── Section (field group) operations ─── */
175
+ const addSection = React.useCallback(() => {
176
+ if (!onPatch)
177
+ return;
178
+ const label = tFormat('designer.canvas.sectionN', locale, {
179
+ n: declaredGroups.length + 1,
180
+ });
181
+ const next = addGroup(declaredGroups, label);
182
+ const created = next[next.length - 1];
183
+ onPatch({ fieldGroups: next });
184
+ // Reveal the new (empty) section if everything was collapsed.
185
+ setCollapsed((prev) => ({ ...prev, [created.key]: false }));
186
+ }, [onPatch, declaredGroups, locale]);
187
+ const renameSection = React.useCallback((key, label) => {
188
+ if (!onPatch)
189
+ return;
190
+ onPatch({ fieldGroups: renameGroup(declaredGroups, key, label) });
191
+ }, [onPatch, declaredGroups]);
192
+ const removeSection = React.useCallback((key) => {
193
+ if (!onPatch)
194
+ return;
195
+ // Drop the declaration AND clear `group` from its members so they
196
+ // fall back to the Ungrouped bucket rather than vanishing.
197
+ const clearedView = clearFieldGroup(view, key);
198
+ onPatch({
199
+ fieldGroups: removeGroup(declaredGroups, key),
200
+ fields: writeFields(clearedView),
201
+ });
202
+ }, [onPatch, declaredGroups, view]);
203
+ const moveSection = React.useCallback((key, dir) => {
204
+ if (!onPatch)
205
+ return;
206
+ onPatch({ fieldGroups: moveGroup(declaredGroups, key, dir) });
207
+ }, [onPatch, declaredGroups]);
208
+ // Reorder fields by moving `fromName` to the position of `toName`.
209
+ // Uses native HTML5 DnD — no library, no animations, just a working
210
+ // reorder for the most common designer interaction.
211
+ // If `toName`'s field is in a different group than the dragged field,
212
+ // adopt that group so cross-group drops are intuitive.
213
+ const reorderField = React.useCallback((fromName, toName, position) => {
214
+ if (!onPatch)
215
+ return;
216
+ if (fromName === toName)
217
+ return;
218
+ const entries = view.entries.slice();
219
+ const fromIdx = entries.findIndex((e) => e.name === fromName);
220
+ if (fromIdx < 0)
221
+ return;
222
+ const [moved] = entries.splice(fromIdx, 1);
223
+ const toIdx = entries.findIndex((e) => e.name === toName);
224
+ const targetEntry = toIdx >= 0 ? entries[toIdx] : undefined;
225
+ if (targetEntry) {
226
+ const targetGroup = typeof targetEntry.def.group === 'string' ? targetEntry.def.group : undefined;
227
+ const fromGroup = typeof moved.def.group === 'string' ? moved.def.group : undefined;
228
+ if (targetGroup !== fromGroup) {
229
+ moved.def = { ...moved.def, group: targetGroup };
230
+ }
231
+ }
232
+ if (toIdx < 0) {
233
+ entries.push(moved);
234
+ }
235
+ else {
236
+ entries.splice(position === 'before' ? toIdx : toIdx + 1, 0, moved);
237
+ }
238
+ onPatch({ fields: writeFields({ shape: view.shape, entries }) });
239
+ }, [onPatch, view]);
240
+ // Keyboard reorder (Alt+↑/↓): swap a field with its nearest neighbour
241
+ // in the SAME group so a focused row moves predictably within its
242
+ // section without ever changing groups.
243
+ const moveFieldByOffset = React.useCallback((name, dir) => {
244
+ if (!onPatch)
245
+ return;
246
+ const entries = view.entries.slice();
247
+ const idx = entries.findIndex((e) => e.name === name);
248
+ if (idx < 0)
249
+ return;
250
+ const grp = typeof entries[idx].def.group === 'string' ? entries[idx].def.group : null;
251
+ let j = idx + dir;
252
+ while (j >= 0 && j < entries.length) {
253
+ const g = typeof entries[j].def.group === 'string' ? entries[j].def.group : null;
254
+ if (g === grp)
255
+ break;
256
+ j += dir;
257
+ }
258
+ if (j < 0 || j >= entries.length)
259
+ return;
260
+ const tmp = entries[idx];
261
+ entries[idx] = entries[j];
262
+ entries[j] = tmp;
263
+ onPatch({ fields: writeFields({ shape: view.shape, entries }) });
264
+ }, [onPatch, view]);
265
+ // Drop a field into a group section's empty space (or onto its header).
266
+ // Reassigns Field.group and moves the entry to the end of that group's
267
+ // run in the source order so it visually lands where it was dropped.
268
+ const moveToGroup = React.useCallback((fromName, groupKey) => {
269
+ if (!onPatch)
270
+ return;
271
+ const entries = view.entries.slice();
272
+ const fromIdx = entries.findIndex((e) => e.name === fromName);
273
+ if (fromIdx < 0)
274
+ return;
275
+ const [moved] = entries.splice(fromIdx, 1);
276
+ const currentGroup = typeof moved.def.group === 'string' ? moved.def.group : null;
277
+ if (currentGroup === groupKey) {
278
+ // No group change — re-insert at original position (effectively no-op).
279
+ entries.splice(fromIdx, 0, moved);
280
+ return;
281
+ }
282
+ moved.def = { ...moved.def, group: groupKey ?? undefined };
283
+ // Find end of target group's run; if no members, append at end.
284
+ let insertAt = entries.length;
285
+ for (let i = entries.length - 1; i >= 0; i -= 1) {
286
+ const g = typeof entries[i].def.group === 'string' ? entries[i].def.group : null;
287
+ if (g === groupKey) {
288
+ insertAt = i + 1;
289
+ break;
290
+ }
291
+ }
292
+ entries.splice(insertAt, 0, moved);
293
+ onPatch({ fields: writeFields({ shape: view.shape, entries }) });
294
+ }, [onPatch, view]);
295
+ // Inline label rename — used by double-click on the field card label.
296
+ const renameLabel = React.useCallback((name, nextLabel) => {
297
+ if (!onPatch)
298
+ return;
299
+ const entries = view.entries.map((e) => e.name === name
300
+ ? { name, def: { ...e.def, label: nextLabel || undefined } }
301
+ : e);
302
+ onPatch({ fields: writeFields({ shape: view.shape, entries }) });
303
+ }, [onPatch, view]);
304
+ // Click anywhere on the empty canvas background to clear selection.
305
+ const handleBgClick = React.useCallback((e) => {
306
+ if (e.target === e.currentTarget && selectedName) {
307
+ onSelectionChange?.(null);
308
+ }
309
+ }, [onSelectionChange, selectedName]);
310
+ const emptyState = view.entries.length === 0;
311
+ // Section chrome (headers, collapse, drop-to-assign) only appears once
312
+ // groups exist — otherwise the canvas stays a flat field list.
313
+ const showSectionChrome = hasGroups || groups.length > 1;
314
+ return (_jsxs("div", { className: "h-full overflow-auto bg-muted/20", onClick: handleBgClick, "data-object-name": objectName, children: [!readOnly && multiSel.size > 0 && (_jsx(BulkActionBar, { count: multiSel.size, groups: declaredGroups, onMoveToGroup: bulkSetGroup, onDelete: bulkDelete, onClear: clearMulti, locale: locale })), _jsxs("div", { className: "mx-auto max-w-3xl px-6 py-6 space-y-4", onClick: handleBgClick, children: [!emptyState && (_jsx(CanvasToolbar, { fieldCount: view.entries.length, requiredCount: requiredCount, sectionCount: declaredGroups.length, allCollapsed: allCollapsed, onToggleAll: showSectionChrome ? () => setAllCollapsed(!allCollapsed) : undefined, reviewAvailable: changeCount > 0, reviewing: reviewing, diffCounts: diff?.counts, onToggleReview: () => setReviewMode((v) => !v), locale: locale })), emptyState ? (_jsx(EmptyCanvas, { onAdd: readOnly ? undefined : addField, locale: locale })) : (_jsx("div", { className: "space-y-5", children: groups.map((g) => {
315
+ const declaredIdx = g.key
316
+ ? declaredGroups.findIndex((d) => d.key === g.key)
317
+ : -1;
318
+ return (_jsxs(GroupSection, { groupKey: g.key, label: g.key === null ? t('designer.canvas.ungrouped', locale) : g.label, count: g.entries.length, showHeader: showSectionChrome, collapsed: !!collapsed[collapseKey(g.key)], onToggleCollapse: () => toggleCollapse(g.key), readOnly: readOnly, locale: locale, canMoveUp: declaredIdx > 0, canMoveDown: declaredIdx >= 0 && declaredIdx < declaredGroups.length - 1, onRename: g.key ? (label) => renameSection(g.key, label) : undefined, onRemove: g.key ? () => removeSection(g.key) : undefined, onMove: g.key ? (dir) => moveSection(g.key, dir) : undefined, onAddField: readOnly ? undefined : (type) => addField(type, g.key), onDropField: readOnly ? undefined : moveToGroup, children: [g.entries.map((entry) => (_jsx(FieldRow, { entry: entry, selected: entry.name === selectedName, multiSelected: multiSel.has(entry.name), diffStatus: statusOf(entry.name), changedKeys: changedKeysOf(entry.name), readOnly: readOnly, locale: locale, onClick: (e) => handleRowClick(entry, e), onReorder: readOnly ? undefined : reorderField, onRenameLabel: readOnly ? undefined : renameLabel, onMoveOffset: readOnly ? undefined : (dir) => moveFieldByOffset(entry.name, dir) }, entry.name))), g.entries.length === 0 && (_jsx("div", { className: "rounded-md border border-dashed bg-background/40 px-3 py-4 text-center text-[11px] text-muted-foreground", children: readOnly
319
+ ? t('designer.canvas.emptySection', locale)
320
+ : t('designer.canvas.dropHint', locale) }))] }, g.key ?? '__ungrouped__'));
321
+ }) })), reviewing && diff && diff.removed.length > 0 && (_jsxs("div", { className: "space-y-2.5", children: [_jsx("div", { className: "text-[11px] font-medium uppercase tracking-wider text-destructive/80 pl-1", children: t('designer.canvas.diffRemoved', locale) }), diff.removed.map((entry) => (_jsx(GhostFieldRow, { entry: entry, locale: locale }, entry.name)))] })), !emptyState && !readOnly && (_jsxs("div", { className: "flex items-center gap-2 pt-1", children: [_jsx(AddFieldButton, { onPick: (type) => addField(type), locale: locale }), _jsxs(Button, { variant: "ghost", size: "sm", className: "gap-1.5 text-muted-foreground hover:text-foreground", onClick: addSection, children: [_jsx(FolderPlus, { className: "h-3.5 w-3.5" }), t('designer.canvas.addSection', locale)] }), _jsxs(Button, { variant: "ghost", size: "sm", className: "gap-1.5 ml-auto text-primary/80 hover:text-primary", onClick: () => requestAssistantOpen(), children: [_jsx(Sparkles, { className: "h-3.5 w-3.5" }), t('designer.canvas.askAi', locale)] })] }))] })] }));
322
+ }
323
+ /* ─────────────── Review toolbar ─────────────── */
324
+ function CanvasToolbar({ fieldCount, requiredCount, sectionCount, allCollapsed, onToggleAll, reviewAvailable, reviewing, diffCounts, onToggleReview, locale, }) {
325
+ return (_jsxs("div", { className: "flex items-center justify-between gap-2 text-[11px] text-muted-foreground", children: [_jsx("div", { className: "flex items-center gap-1.5 flex-wrap", children: reviewing && diffCounts ? (_jsxs(_Fragment, { children: [_jsx("span", { className: "font-medium text-emerald-600 dark:text-emerald-400", children: diffCounts.added }), ' ', t('designer.canvas.diffAdded', locale), _jsx("span", { className: "text-muted-foreground/50", children: "\u00B7" }), _jsx("span", { className: "font-medium text-amber-600 dark:text-amber-400", children: diffCounts.changed }), ' ', t('designer.canvas.diffChanged', locale), _jsx("span", { className: "text-muted-foreground/50", children: "\u00B7" }), _jsx("span", { className: "font-medium text-destructive", children: diffCounts.removed }), ' ', t('designer.canvas.diffRemoved', locale), _jsx("span", { className: "text-muted-foreground/40 normal-case ml-1", children: t('designer.canvas.reviewVsPublished', locale) })] })) : (_jsxs(_Fragment, { children: [_jsx("span", { className: "font-medium text-foreground/80", children: fieldCount }), ' ', t('designer.canvas.fields', locale), _jsx("span", { className: "text-muted-foreground/50", children: "\u00B7" }), _jsx("span", { className: "font-medium text-foreground/80", children: requiredCount }), ' ', t('designer.canvas.required', locale), sectionCount > 0 && (_jsxs(_Fragment, { children: [_jsx("span", { className: "text-muted-foreground/50", children: "\u00B7" }), _jsx("span", { className: "font-medium text-foreground/80", children: sectionCount }), ' ', t('designer.canvas.sections', locale)] }))] })) }), _jsxs("div", { className: "flex items-center gap-1 shrink-0", children: [reviewAvailable && onToggleReview && (_jsxs("button", { type: "button", onClick: onToggleReview, className: cn('inline-flex items-center gap-1 rounded px-1.5 py-0.5 transition-colors', reviewing
326
+ ? 'bg-primary/10 text-primary hover:bg-primary/15'
327
+ : 'hover:bg-accent hover:text-foreground'), children: [_jsx(GitCompareArrows, { className: "h-3 w-3" }), reviewing
328
+ ? t('designer.canvas.reviewExit', locale)
329
+ : t('designer.canvas.reviewChanges', locale)] })), onToggleAll && (_jsxs("button", { type: "button", onClick: onToggleAll, className: "inline-flex items-center gap-1 rounded px-1.5 py-0.5 hover:bg-accent hover:text-foreground transition-colors", children: [allCollapsed ? (_jsx(ChevronsUpDown, { className: "h-3 w-3" })) : (_jsx(ChevronsDownUp, { className: "h-3 w-3" })), allCollapsed
330
+ ? t('designer.canvas.expandAll', locale)
331
+ : t('designer.canvas.collapseAll', locale)] }))] })] }));
332
+ }
333
+ /* ─────────────── Bulk-action bar ─────────────── */
334
+ function BulkActionBar({ count, groups, onMoveToGroup, onDelete, onClear, locale, }) {
335
+ const [open, setOpen] = React.useState(false);
336
+ return (_jsxs("div", { className: "sticky top-0 z-20 flex items-center gap-2 border-b border-primary/20 bg-primary/10 backdrop-blur px-6 py-2 text-sm", children: [_jsx("span", { className: "font-medium text-foreground", children: tFormat('designer.canvas.bulkSelected', locale, { n: count }) }), _jsx("span", { className: "text-muted-foreground text-[11px] hidden md:inline", children: t('designer.canvas.bulkHint', locale) }), _jsxs("div", { className: "ml-auto flex items-center gap-1.5", children: [groups.length > 0 && (_jsxs(Popover, { open: open, onOpenChange: setOpen, children: [_jsx(PopoverTrigger, { asChild: true, children: _jsxs(Button, { variant: "outline", size: "sm", className: "h-7 gap-1.5 bg-background/70", children: [_jsx(FolderInput, { className: "h-3.5 w-3.5" }), t('designer.canvas.bulkMoveTo', locale), _jsx(ChevronDown, { className: "h-3 w-3" })] }) }), _jsxs(PopoverContent, { align: "end", className: "w-52 p-1 max-h-[300px] overflow-auto", children: [_jsx("button", { type: "button", onClick: () => { onMoveToGroup(null); setOpen(false); }, className: "w-full text-left px-2 py-1.5 rounded text-sm hover:bg-accent", children: t('designer.canvas.ungrouped', locale) }), groups.map((g) => (_jsx("button", { type: "button", onClick: () => { onMoveToGroup(g.key); setOpen(false); }, className: "w-full text-left px-2 py-1.5 rounded text-sm hover:bg-accent truncate", children: g.label || g.key }, g.key)))] })] })), _jsxs(Button, { variant: "outline", size: "sm", className: "h-7 gap-1.5 bg-background/70 text-destructive hover:text-destructive", onClick: onDelete, children: [_jsx(Trash2, { className: "h-3.5 w-3.5" }), t('designer.canvas.bulkDelete', locale)] }), _jsxs(Button, { variant: "ghost", size: "sm", className: "h-7 gap-1.5", onClick: onClear, children: [_jsx(X, { className: "h-3.5 w-3.5" }), t('designer.canvas.bulkClear', locale)] })] })] }));
337
+ }
338
+ /* ─────────────── Building blocks ─────────────── */
339
+ function GroupSection({ groupKey, label, count, showHeader, collapsed, onToggleCollapse, readOnly, locale, canMoveUp, canMoveDown, onRename, onRemove, onMove, onAddField, onDropField, children, }) {
340
+ const [active, setActive] = React.useState(false);
341
+ const handleDragOver = (e) => {
342
+ if (!onDropField)
343
+ return;
344
+ const types = e.dataTransfer.types;
345
+ if (!types || !Array.from(types).includes('text/x-objectui-field'))
346
+ return;
347
+ e.preventDefault();
348
+ e.dataTransfer.dropEffect = 'move';
349
+ setActive(true);
350
+ };
351
+ const handleDragLeave = (e) => {
352
+ // Only deactivate when leaving the section container itself, not its children.
353
+ if (e.currentTarget === e.target)
354
+ setActive(false);
355
+ };
356
+ const handleDrop = (e) => {
357
+ if (!onDropField)
358
+ return;
359
+ // Let inner FieldRow drops win — only handle if no row already consumed it.
360
+ if (e.defaultPrevented) {
361
+ setActive(false);
362
+ return;
363
+ }
364
+ e.preventDefault();
365
+ const from = e.dataTransfer.getData('text/x-objectui-field');
366
+ setActive(false);
367
+ if (from)
368
+ onDropField(from, groupKey);
369
+ };
370
+ return (_jsxs("section", { className: cn('space-y-2.5 rounded-md transition-colors', active && 'bg-primary/5 ring-1 ring-primary/30 -mx-1 px-1 py-1'), onDragOver: handleDragOver, onDragLeave: handleDragLeave, onDrop: handleDrop, children: [showHeader && (_jsx(SectionHeader, { label: label, count: count, collapsed: collapsed, onToggleCollapse: onToggleCollapse, readOnly: readOnly, locale: locale, canMoveUp: canMoveUp, canMoveDown: canMoveDown, dropActive: active, onRename: onRename, onRemove: onRemove, onMove: onMove, onAddField: onAddField })), !collapsed && _jsx("div", { className: "space-y-2.5", children: children })] }));
371
+ }
372
+ function SectionHeader({ label, count, collapsed, onToggleCollapse, readOnly, locale, canMoveUp, canMoveDown, dropActive, onRename, onRemove, onMove, onAddField, }) {
373
+ const [editing, setEditing] = React.useState(false);
374
+ const [draft, setDraft] = React.useState(label);
375
+ React.useEffect(() => { setDraft(label); }, [label]);
376
+ const commit = () => {
377
+ if (!onRename) {
378
+ setEditing(false);
379
+ return;
380
+ }
381
+ const next = draft.trim();
382
+ if (next && next !== label)
383
+ onRename(next);
384
+ setEditing(false);
385
+ };
386
+ const Chevron = collapsed ? ChevronRight : ChevronDown;
387
+ return (_jsxs("div", { className: "group/sec flex items-center gap-1.5 pl-0.5 min-h-[24px]", children: [_jsx("button", { type: "button", onClick: onToggleCollapse, className: "flex items-center justify-center h-5 w-5 rounded text-muted-foreground hover:bg-accent hover:text-foreground transition-colors shrink-0", "aria-label": collapsed
388
+ ? t('designer.canvas.expandSection', locale)
389
+ : t('designer.canvas.collapseSection', locale), "aria-expanded": !collapsed, children: _jsx(Chevron, { className: "h-3.5 w-3.5" }) }), editing ? (_jsx("input", { autoFocus: true, value: draft, onChange: (e) => setDraft(e.target.value), onClick: (e) => e.stopPropagation(), onKeyDown: (e) => {
390
+ e.stopPropagation();
391
+ if (e.key === 'Enter') {
392
+ e.preventDefault();
393
+ commit();
394
+ }
395
+ else if (e.key === 'Escape') {
396
+ e.preventDefault();
397
+ setDraft(label);
398
+ setEditing(false);
399
+ }
400
+ }, onBlur: commit, className: "text-[11px] font-medium uppercase tracking-wider px-1 py-0.5 -my-0.5 rounded border border-primary bg-background outline-none min-w-0 flex-1 max-w-[220px]" })) : (_jsx("span", { className: cn('text-[11px] font-medium uppercase tracking-wider text-muted-foreground truncate', onRename && 'cursor-text hover:text-foreground'), onDoubleClick: onRename ? () => { setDraft(label); setEditing(true); } : undefined, title: onRename ? t('designer.canvas.renameHint', locale) : undefined, children: label })), _jsx("span", { className: "text-[10px] text-muted-foreground/60 tabular-nums shrink-0", children: count }), dropActive && (_jsx("span", { className: "text-primary normal-case text-[10px] font-normal", children: t('designer.canvas.dropToAssign', locale) })), !readOnly && (onMove || onRemove || onAddField) && (_jsxs("div", { className: "ml-auto flex items-center gap-0.5 opacity-0 group-hover/sec:opacity-100 focus-within:opacity-100 transition-opacity", children: [onAddField && (_jsx(AddFieldButton, { onPick: onAddField, compact: true, locale: locale })), onMove && (_jsxs(_Fragment, { children: [_jsx("button", { type: "button", onClick: () => onMove(-1), disabled: !canMoveUp, className: "h-5 w-5 flex items-center justify-center rounded text-muted-foreground hover:bg-accent hover:text-foreground disabled:opacity-30 disabled:pointer-events-none", "aria-label": t('designer.canvas.moveSectionUp', locale), children: _jsx(ArrowUp, { className: "h-3 w-3" }) }), _jsx("button", { type: "button", onClick: () => onMove(1), disabled: !canMoveDown, className: "h-5 w-5 flex items-center justify-center rounded text-muted-foreground hover:bg-accent hover:text-foreground disabled:opacity-30 disabled:pointer-events-none", "aria-label": t('designer.canvas.moveSectionDown', locale), children: _jsx(ArrowDown, { className: "h-3 w-3" }) })] })), onRemove && (_jsx("button", { type: "button", onClick: onRemove, className: "h-5 w-5 flex items-center justify-center rounded text-muted-foreground hover:bg-destructive/10 hover:text-destructive", "aria-label": t('designer.canvas.removeSection', locale), title: t('designer.canvas.removeSectionHint', locale), children: _jsx(Trash2, { className: "h-3 w-3" }) }))] }))] }));
401
+ }
402
+ /** Read-only ghost of a field that exists in the baseline but was removed. */
403
+ function GhostFieldRow({ entry, locale }) {
404
+ const def = entry.def;
405
+ const typeStr = typeof def.type === 'string' ? def.type : 'text';
406
+ const meta = FIELD_TYPE_META[typeStr];
407
+ const Icon = meta?.Icon;
408
+ const label = typeof def.label === 'string' ? def.label : entry.name;
409
+ return (_jsx("div", { className: "rounded-md border border-dashed border-destructive/30 bg-destructive/[0.03] px-3.5 py-2.5 opacity-80", children: _jsxs("div", { className: "flex items-center justify-between gap-2", children: [_jsxs("div", { className: "flex items-center gap-1.5 min-w-0", children: [Icon && _jsx(Icon, { className: "h-3.5 w-3.5 shrink-0 text-muted-foreground/50" }), _jsx("span", { className: "text-sm font-medium truncate line-through text-muted-foreground", children: label }), _jsx("code", { className: "text-[10px] text-muted-foreground/60 font-mono truncate line-through", children: entry.name })] }), _jsx(Badge, { className: "text-[10px] font-medium border-transparent bg-destructive/15 text-destructive shrink-0", children: t('designer.canvas.diffRemoved', locale) })] }) }));
410
+ }
411
+ function FieldRow({ entry, selected, multiSelected, diffStatus, changedKeys, readOnly, locale, onClick, onReorder, onRenameLabel, onMoveOffset, }) {
412
+ const def = entry.def;
413
+ const typeStr = typeof def.type === 'string' ? def.type : 'text';
414
+ const meta = FIELD_TYPE_META[typeStr];
415
+ const Icon = meta?.Icon;
416
+ const tone = CATEGORY_TONE[meta?.category ?? 'advanced'];
417
+ const label = typeof def.label === 'string' ? def.label : entry.name;
418
+ const required = !!def.required;
419
+ const description = typeof def.description === 'string' ? def.description : null;
420
+ const options = Array.isArray(def.options)
421
+ ? def.options.map((o) => ({
422
+ value: String(o.value ?? ''),
423
+ label: typeof o.label === 'string' ? o.label : undefined,
424
+ }))
425
+ : undefined;
426
+ const referenceTo = typeof def.reference === 'string' ? def.reference : undefined;
427
+ const formula = typeof def.formula === 'string' ? def.formula : undefined;
428
+ const placeholder = typeof def.placeholder === 'string' ? def.placeholder : undefined;
429
+ const [dropZone, setDropZone] = React.useState(null);
430
+ const draggable = !!onReorder;
431
+ const [editingLabel, setEditingLabel] = React.useState(false);
432
+ const [labelDraft, setLabelDraft] = React.useState(label);
433
+ React.useEffect(() => { setLabelDraft(label); }, [label]);
434
+ const beginEdit = (e) => {
435
+ if (!onRenameLabel)
436
+ return;
437
+ e.preventDefault();
438
+ e.stopPropagation();
439
+ setLabelDraft(label);
440
+ setEditingLabel(true);
441
+ };
442
+ const commitEdit = () => {
443
+ if (!onRenameLabel) {
444
+ setEditingLabel(false);
445
+ return;
446
+ }
447
+ const next = labelDraft.trim();
448
+ if (next && next !== label)
449
+ onRenameLabel(entry.name, next);
450
+ setEditingLabel(false);
451
+ };
452
+ const cancelEdit = () => {
453
+ setLabelDraft(label);
454
+ setEditingLabel(false);
455
+ };
456
+ const handleDragStart = (e) => {
457
+ e.dataTransfer.setData('text/x-objectui-field', entry.name);
458
+ e.dataTransfer.effectAllowed = 'move';
459
+ };
460
+ const handleDragOver = (e) => {
461
+ if (!draggable)
462
+ return;
463
+ const types = e.dataTransfer.types;
464
+ if (!types || !Array.from(types).includes('text/x-objectui-field'))
465
+ return;
466
+ e.preventDefault();
467
+ e.dataTransfer.dropEffect = 'move';
468
+ const rect = e.currentTarget.getBoundingClientRect();
469
+ const pos = e.clientY - rect.top < rect.height / 2 ? 'before' : 'after';
470
+ setDropZone(pos);
471
+ };
472
+ const handleDragLeave = () => setDropZone(null);
473
+ const handleDrop = (e) => {
474
+ if (!onReorder)
475
+ return;
476
+ e.preventDefault();
477
+ e.stopPropagation();
478
+ const from = e.dataTransfer.getData('text/x-objectui-field');
479
+ setDropZone(null);
480
+ if (from && from !== entry.name) {
481
+ onReorder(from, entry.name, dropZone ?? 'before');
482
+ }
483
+ };
484
+ return (_jsxs("div", { className: cn('relative', dropZone === 'before' && 'pt-1.5'), onDragOver: handleDragOver, onDragLeave: handleDragLeave, onDrop: handleDrop, children: [dropZone === 'before' && (_jsx("div", { className: "absolute left-0 right-0 -top-0.5 h-0.5 bg-primary rounded-full" })), _jsxs("div", { role: "button", tabIndex: readOnly ? -1 : 0, onClick: onClick, onKeyDown: (e) => {
485
+ if (e.target !== e.currentTarget)
486
+ return;
487
+ if (e.altKey && (e.key === 'ArrowUp' || e.key === 'ArrowDown')) {
488
+ if (onMoveOffset) {
489
+ e.preventDefault();
490
+ onMoveOffset(e.key === 'ArrowUp' ? -1 : 1);
491
+ }
492
+ return;
493
+ }
494
+ if (e.key === 'Enter' || e.key === ' ') {
495
+ e.preventDefault();
496
+ onClick?.();
497
+ }
498
+ }, draggable: draggable, onDragStart: handleDragStart, className: cn('group block w-full text-left rounded-md border bg-card px-3.5 py-2.5 transition-colors', 'hover:border-primary/40 hover:bg-card outline-none focus-visible:ring-2 focus-visible:ring-primary/40', selected ? 'border-primary ring-2 ring-primary/30 shadow-sm' : 'border-border', multiSelected && 'border-primary/60 ring-2 ring-primary/40 bg-primary/[0.04]', diffStatus === 'added' && 'border-l-[3px] border-l-emerald-500', diffStatus === 'changed' && 'border-l-[3px] border-l-amber-500', readOnly && 'cursor-default', draggable && 'cursor-grab active:cursor-grabbing'), "aria-pressed": selected || multiSelected, children: [_jsxs("div", { className: "flex items-center justify-between gap-2 mb-1.5", children: [_jsxs("div", { className: "flex items-center gap-1.5 min-w-0", children: [multiSelected && (_jsx(CheckSquare, { className: "h-3.5 w-3.5 text-primary shrink-0", "aria-hidden": "true" })), draggable && !multiSelected && (_jsx(GripVertical, { className: "h-3.5 w-3.5 text-muted-foreground/40 shrink-0 group-hover:text-muted-foreground/80", "aria-hidden": "true" })), Icon && _jsx(Icon, { className: cn('h-3.5 w-3.5 shrink-0', tone.icon) }), editingLabel ? (_jsx("input", { autoFocus: true, value: labelDraft, onChange: (e) => setLabelDraft(e.target.value), onClick: (e) => e.stopPropagation(), onKeyDown: (e) => {
499
+ e.stopPropagation();
500
+ if (e.key === 'Enter') {
501
+ e.preventDefault();
502
+ commitEdit();
503
+ }
504
+ else if (e.key === 'Escape') {
505
+ e.preventDefault();
506
+ cancelEdit();
507
+ }
508
+ }, onBlur: commitEdit, className: "text-sm font-medium px-1 py-0.5 -mx-1 -my-0.5 rounded border border-primary bg-background outline-none min-w-0 flex-1" })) : (_jsx("span", { className: cn('text-sm font-medium truncate', onRenameLabel && 'cursor-text'), onDoubleClick: beginEdit, title: onRenameLabel ? t('designer.canvas.renameHint', locale) : undefined, children: label })), required && _jsx("span", { className: "text-destructive text-sm", children: "*" }), _jsx("code", { className: "text-[10px] text-muted-foreground/70 font-mono truncate", children: entry.name })] }), _jsxs("div", { className: "flex items-center gap-1.5 shrink-0", children: [diffStatus === 'added' && (_jsx(Badge, { className: "text-[10px] font-medium border-transparent bg-emerald-500/15 text-emerald-700 dark:text-emerald-300", children: t('designer.canvas.diffAdded', locale) })), diffStatus === 'changed' && (_jsx(Badge, { className: "text-[10px] font-medium border-transparent bg-amber-500/15 text-amber-700 dark:text-amber-300", title: changedKeys && changedKeys.length
509
+ ? tFormat('designer.canvas.diffChangedKeys', locale, { keys: changedKeys.join(', ') })
510
+ : undefined, children: t('designer.canvas.diffChanged', locale) })), _jsx(Badge, { variant: "outline", className: cn('text-[10px] font-medium', tone.badge), children: typeLabel(meta, locale) ?? typeStr })] })] }), description && (_jsx("div", { className: "text-[11px] text-muted-foreground mb-1.5 line-clamp-1", children: description })), _jsx(FieldStub, { type: typeStr, label: label, placeholder: placeholder, options: options, referenceTo: referenceTo, formula: formula, locale: locale })] }), dropZone === 'after' && (_jsx("div", { className: "absolute left-0 right-0 -bottom-1 h-0.5 bg-primary rounded-full" }))] }));
511
+ }
512
+ function EmptyCanvas({ onAdd, locale }) {
513
+ return (_jsxs("div", { className: "rounded-lg border-2 border-dashed bg-background py-16 px-6 text-center space-y-3", children: [_jsx("div", { className: "text-sm font-medium", children: t('designer.canvas.noFields', locale) }), _jsx("div", { className: "text-xs text-muted-foreground", children: t('designer.canvas.noFieldsHint', locale) }), onAdd && (_jsxs("div", { className: "pt-2 flex items-center justify-center gap-2", children: [_jsx(AddFieldButton, { onPick: onAdd, locale: locale }), _jsxs(Button, { variant: "ghost", size: "sm", className: "gap-1.5 text-primary/80 hover:text-primary", onClick: () => requestAssistantOpen(), children: [_jsx(Sparkles, { className: "h-3.5 w-3.5" }), t('designer.canvas.askAiGenerate', locale)] })] }))] }));
514
+ }
515
+ function AddFieldButton({ onPick, compact, locale }) {
516
+ const [open, setOpen] = React.useState(false);
517
+ const [filter, setFilter] = React.useState('');
518
+ const q = filter.trim().toLowerCase();
519
+ const groups = React.useMemo(() => {
520
+ if (!q)
521
+ return TYPES_BY_CATEGORY;
522
+ return TYPES_BY_CATEGORY
523
+ .map((g) => ({
524
+ category: g.category,
525
+ types: g.types.filter((id) => {
526
+ const m = FIELD_TYPE_META[id];
527
+ return id.includes(q) || m.label.toLowerCase().includes(q) || m.labelZh.includes(filter.trim());
528
+ }),
529
+ }))
530
+ .filter((g) => g.types.length > 0);
531
+ }, [q, filter]);
532
+ return (_jsxs(Popover, { open: open, onOpenChange: (o) => {
533
+ setOpen(o);
534
+ if (!o)
535
+ setFilter('');
536
+ }, children: [_jsx(PopoverTrigger, { asChild: true, children: compact ? (_jsx("button", { type: "button", className: "h-5 w-5 flex items-center justify-center rounded text-muted-foreground hover:bg-accent hover:text-foreground", "aria-label": t('designer.canvas.addFieldToSection', locale), title: t('designer.canvas.addFieldToSection', locale), children: _jsx(Plus, { className: "h-3 w-3" }) })) : (_jsxs(Button, { variant: "outline", size: "sm", className: "gap-1.5 border-dashed", children: [_jsx(Plus, { className: "h-3.5 w-3.5" }), t('designer.canvas.addField', locale)] })) }), _jsxs(PopoverContent, { align: "start", className: "w-[320px] p-0 max-h-[480px] overflow-hidden flex flex-col", children: [_jsx("div", { className: "p-2 border-b", children: _jsx("input", { autoFocus: true, value: filter, onChange: (e) => setFilter(e.target.value), placeholder: t('designer.canvas.searchFieldType', locale), className: "h-7 w-full px-2 text-sm border rounded bg-background outline-none focus:ring-1 focus:ring-primary" }) }), _jsx("div", { className: "flex-1 overflow-auto p-1", children: groups.length === 0 ? (_jsx("div", { className: "text-xs text-muted-foreground p-4 text-center", children: t('designer.canvas.noMatchingTypes', locale) })) : (groups.map((g) => (_jsxs("div", { className: "mb-1", children: [_jsx("div", { className: "text-[10px] uppercase tracking-wider text-muted-foreground px-2 pt-2 pb-1", children: categoryLabel(g.category, locale) }), _jsx("div", { className: "grid grid-cols-2 gap-0.5", children: g.types.map((id) => {
537
+ const m = FIELD_TYPE_META[id];
538
+ const Icon = m.Icon;
539
+ return (_jsxs("button", { type: "button", onClick: () => {
540
+ onPick(id);
541
+ setOpen(false);
542
+ setFilter('');
543
+ }, className: "flex items-center gap-2 px-2 py-1.5 rounded text-left text-xs hover:bg-accent", children: [_jsx(Icon, { className: cn('h-3.5 w-3.5 shrink-0', CATEGORY_TONE[m.category].icon) }), _jsx("span", { className: "truncate", children: typeLabel(m, locale) })] }, id));
544
+ }) })] }, g.category)))) })] })] }));
545
+ }
546
+ // Internal helper for callers that want to normalize a name in their own UI.
547
+ export { toFieldName };
@@ -1,2 +1,15 @@
1
+ /**
2
+ * ObjectPreview — form-designer canvas for an Object metadata draft.
3
+ *
4
+ * Each field renders as the labeled input control it will become at
5
+ * runtime. Clicking a field selects it and the host swaps the right
6
+ * panel to {@link ObjectFieldInspector}. Trailing "+ Add field"
7
+ * button opens a categorized type picker.
8
+ *
9
+ * Read/write of `draft.fields` is non-destructive: the original shape
10
+ * (array vs record) and any unknown properties on each field are
11
+ * preserved via `object-fields-io`.
12
+ */
13
+ import * as React from 'react';
1
14
  import type { MetadataPreviewProps } from '../preview-registry';
2
- export declare function ObjectPreview({ name, draft }: MetadataPreviewProps): import("react/jsx-runtime").JSX.Element;
15
+ export declare function ObjectPreview({ name, draft, baseline, onPatch, selection, onSelectionChange, locale, }: MetadataPreviewProps): React.JSX.Element;
@@ -1,36 +1,11 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
- // Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
3
- /**
4
- * ObjectPreview — render the object exactly the way the console does it:
5
- * via the same `object-view` SchemaRenderer the runtime route uses, with
6
- * the live adapter behind it. Authors see real records, real localized
7
- * column labels, real type-aware cell formatters (booleans → checkbox,
8
- * dates → locale string, refs → links), real search / filter chrome.
9
- *
10
- * This is a deliberate change from the earlier hand-rolled table: keeping
11
- * two implementations in sync was bound to drift, and the user explicitly
12
- * asked for preview parity with the console.
13
- */
14
- import * as React from 'react';
15
- import { SchemaRenderer } from '@object-ui/react';
16
2
  import { PreviewShell, PreviewMessage, PreviewErrorBoundary } from './PreviewShell';
17
- export function ObjectPreview({ name, draft }) {
3
+ import { ObjectFormCanvas } from './ObjectFormCanvas';
4
+ import { t } from '../i18n';
5
+ export function ObjectPreview({ name, draft, baseline, onPatch, selection, onSelectionChange, locale, }) {
18
6
  const objectName = String(draft.name ?? name ?? '');
19
7
  if (!objectName) {
20
- return (_jsx(PreviewShell, { hint: "object", children: _jsx(PreviewMessage, { children: "Give the object a name to enable preview." }) }));
8
+ return (_jsx(PreviewShell, { hint: "object", children: _jsx(PreviewMessage, { children: t('designer.canvas.nameToStart', locale) }) }));
21
9
  }
22
- // Reuse the exact same SDUI component the runtime route renders, so the
23
- // preview inherits localized headers, type-aware cell formatters, view
24
- // switcher, search, filter, sort and pagination chrome out of the box.
25
- const schema = React.useMemo(() => ({
26
- type: 'object-view',
27
- objectName,
28
- defaultViewType: 'grid',
29
- showSearch: true,
30
- showFilters: true,
31
- showCreate: false,
32
- showRefresh: true,
33
- showViewSwitcher: true,
34
- }), [objectName]);
35
- return (_jsx(PreviewShell, { hint: "object \u00B7 live data", children: _jsx(PreviewErrorBoundary, { fallbackHint: "The object metadata couldn't be rendered. Save the draft and reload to retry.", children: _jsx("div", { className: "max-h-[75vh] overflow-auto", children: _jsx(SchemaRenderer, { schema: schema }) }) }) }));
10
+ return (_jsx(PreviewShell, { hint: "object \u00B7 designer", children: _jsx(PreviewErrorBoundary, { fallbackHint: "The form designer couldn't be rendered. Check the Form tab.", children: _jsx(ObjectFormCanvas, { objectName: objectName, draft: draft, baseline: baseline, onPatch: onPatch, selection: selection, onSelectionChange: onSelectionChange, locale: locale }) }) }));
36
11
  }