@cosmicdrift/kumiko-renderer 0.373.0 → 0.377.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 (466) hide show
  1. package/README.md +2 -2
  2. package/dist/app/action-form-support.d.ts +58 -0
  3. package/dist/app/action-form-support.js +96 -0
  4. package/dist/app/client-actions.d.ts +46 -0
  5. package/dist/app/client-actions.js +60 -0
  6. package/dist/app/column-renderers.js +1 -1
  7. package/dist/app/config-edit-shim.js +1 -1
  8. package/dist/app/content-preview.js +1 -6
  9. package/dist/app/custom-screens.js +1 -1
  10. package/dist/app/dashboard-body.d.ts +1 -1
  11. package/dist/app/entity-list-expanded-row.d.ts +1 -1
  12. package/dist/app/entity-list-expanded-row.js +4 -0
  13. package/dist/app/form-schema.d.ts +1 -1
  14. package/dist/app/form-schema.js +2 -2
  15. package/dist/app/header-actions-bar.d.ts +19 -0
  16. package/dist/app/header-actions-bar.js +30 -0
  17. package/dist/app/kumiko-screen.d.ts +1 -1
  18. package/dist/app/kumiko-screen.js +134 -66
  19. package/dist/app/list-empty-content.d.ts +2 -2
  20. package/dist/app/list-empty-content.js +3 -2
  21. package/dist/app/list-facets.d.ts +1 -1
  22. package/dist/app/nav.js +2 -2
  23. package/dist/app/query-state-banners.d.ts +1 -1
  24. package/dist/app/reference-link.d.ts +1 -1
  25. package/dist/app/row-actions.d.ts +10 -2
  26. package/dist/app/row-actions.js +85 -6
  27. package/dist/app/secret-mint-body.d.ts +1 -1
  28. package/dist/app/secrets-edit-body.d.ts +1 -1
  29. package/dist/app/use-record-actions.d.ts +12 -0
  30. package/dist/app/use-record-actions.js +30 -0
  31. package/dist/app/write-failed-error.d.ts +1 -1
  32. package/dist/components/availability-options-select.d.ts +1 -1
  33. package/dist/components/embedded-list-field.d.ts +1 -1
  34. package/dist/components/embedded-list-field.js +1 -1
  35. package/dist/components/file-list-field.d.ts +1 -1
  36. package/dist/components/grid-cell-for-field.d.ts +4 -2
  37. package/dist/components/grid-cell-for-field.js +2 -2
  38. package/dist/components/multi-select-checkboxes.d.ts +1 -1
  39. package/dist/components/multi-select-checkboxes.js +1 -1
  40. package/dist/components/query-options-select.d.ts +1 -1
  41. package/dist/components/related-list-section.d.ts +1 -1
  42. package/dist/components/related-list-section.js +16 -3
  43. package/dist/components/render-edit-logic.d.ts +1 -1
  44. package/dist/components/render-edit-types.d.ts +2 -2
  45. package/dist/components/render-edit.d.ts +1 -1
  46. package/dist/components/render-edit.js +5 -3
  47. package/dist/components/render-field.d.ts +5 -2
  48. package/dist/components/render-field.js +103 -9
  49. package/dist/components/render-list.d.ts +1 -1
  50. package/dist/components/render-list.js +20 -4
  51. package/dist/components/write-form-section.d.ts +1 -1
  52. package/dist/components/write-form-section.js +1 -1
  53. package/dist/context/dispatcher-context.d.ts +1 -1
  54. package/dist/format-when.js +1 -1
  55. package/dist/headless/apex/css.d.ts +3 -0
  56. package/dist/headless/apex/css.js +298 -0
  57. package/dist/headless/apex/index.d.ts +236 -0
  58. package/dist/headless/apex/index.js +377 -0
  59. package/dist/headless/apex/lightbox.d.ts +4 -0
  60. package/dist/headless/apex/lightbox.js +81 -0
  61. package/dist/headless/contracts/asset.d.ts +15 -0
  62. package/dist/headless/contracts/asset.js +17 -0
  63. package/dist/headless/contracts/index.d.ts +3 -0
  64. package/dist/headless/contracts/index.js +1 -0
  65. package/dist/headless/contracts/locale.d.ts +7 -0
  66. package/dist/headless/contracts/locale.js +11 -0
  67. package/dist/headless/contracts/primitives.d.ts +93 -0
  68. package/dist/headless/contracts/primitives.js +21 -0
  69. package/dist/headless/dispatcher/index.d.ts +2 -0
  70. package/dist/headless/dispatcher/index.js +1 -0
  71. package/dist/headless/dispatcher/types.d.ts +86 -0
  72. package/dist/headless/dispatcher/types.js +34 -0
  73. package/dist/headless/form/form-controller.d.ts +2 -0
  74. package/dist/headless/form/form-controller.js +409 -0
  75. package/dist/headless/form/index.d.ts +3 -0
  76. package/dist/headless/form/index.js +2 -0
  77. package/dist/headless/form/types.d.ts +76 -0
  78. package/dist/headless/form/types.js +1 -0
  79. package/dist/headless/form/zod-bridge.d.ts +10 -0
  80. package/dist/headless/form/zod-bridge.js +103 -0
  81. package/dist/headless/format/document-values.d.ts +12 -0
  82. package/dist/headless/format/document-values.js +70 -0
  83. package/dist/headless/format/escape.d.ts +5 -0
  84. package/dist/headless/format/escape.js +75 -0
  85. package/dist/headless/format/html-template.d.ts +9 -0
  86. package/dist/headless/format/html-template.js +39 -0
  87. package/dist/headless/format/index.d.ts +12 -0
  88. package/dist/headless/format/index.js +237 -0
  89. package/dist/headless/format/money.d.ts +3 -0
  90. package/dist/headless/format/money.js +39 -0
  91. package/dist/headless/index.d.ts +14 -0
  92. package/dist/headless/index.js +9 -0
  93. package/dist/headless/locale-routing/index.d.ts +41 -0
  94. package/dist/headless/locale-routing/index.js +145 -0
  95. package/dist/headless/nav/index.d.ts +2 -0
  96. package/dist/headless/nav/index.js +1 -0
  97. package/dist/headless/nav/resolve.d.ts +2 -0
  98. package/dist/headless/nav/resolve.js +71 -0
  99. package/dist/headless/nav/types.d.ts +26 -0
  100. package/dist/headless/nav/types.js +1 -0
  101. package/dist/headless/store/create-store.d.ts +2 -0
  102. package/dist/headless/store/create-store.js +43 -0
  103. package/dist/headless/store/equality.d.ts +1 -0
  104. package/dist/headless/store/equality.js +34 -0
  105. package/dist/headless/store/index.d.ts +3 -0
  106. package/dist/headless/store/index.js +2 -0
  107. package/dist/headless/store/types.d.ts +7 -0
  108. package/dist/headless/store/types.js +10 -0
  109. package/dist/headless/view-model/edit.d.ts +18 -0
  110. package/dist/headless/view-model/edit.js +501 -0
  111. package/dist/headless/view-model/embedded-list.d.ts +27 -0
  112. package/dist/headless/view-model/embedded-list.js +63 -0
  113. package/dist/headless/view-model/index.d.ts +7 -0
  114. package/dist/headless/view-model/index.js +3 -0
  115. package/dist/headless/view-model/list-file-display.d.ts +3 -0
  116. package/dist/headless/view-model/list-file-display.js +27 -0
  117. package/dist/headless/view-model/list.d.ts +16 -0
  118. package/dist/headless/view-model/list.js +229 -0
  119. package/dist/headless/view-model/types.d.ts +382 -0
  120. package/dist/headless/view-model/types.js +1 -0
  121. package/dist/hooks/use-ai-text.d.ts +1 -1
  122. package/dist/hooks/use-form.d.ts +1 -1
  123. package/dist/hooks/use-form.js +1 -1
  124. package/dist/hooks/use-mutation.d.ts +1 -1
  125. package/dist/hooks/use-query.d.ts +1 -1
  126. package/dist/hooks/use-store.d.ts +1 -1
  127. package/dist/hooks/use-store.js +7 -7
  128. package/dist/hooks/use-stream-handler.d.ts +1 -1
  129. package/dist/i18n-defaults.js +7 -0
  130. package/dist/i18n.d.ts +1 -1
  131. package/dist/i18n.js +1 -1
  132. package/dist/index.d.ts +5 -1
  133. package/dist/index.js +7 -4
  134. package/dist/live/csrf.d.ts +2 -0
  135. package/dist/live/csrf.js +60 -0
  136. package/dist/live/dispatcher-live.d.ts +7 -0
  137. package/dist/live/dispatcher-live.js +286 -0
  138. package/dist/live/envelopes.d.ts +101 -0
  139. package/dist/live/envelopes.js +35 -0
  140. package/dist/live/error-mapping.d.ts +16 -0
  141. package/dist/live/error-mapping.js +82 -0
  142. package/dist/live/index.d.ts +7 -0
  143. package/dist/live/index.js +5 -0
  144. package/dist/live/locale.d.ts +2 -0
  145. package/dist/live/locale.js +25 -0
  146. package/dist/live/sse-stream.d.ts +14 -0
  147. package/dist/live/sse-stream.js +128 -0
  148. package/dist/primitives.d.ts +53 -36
  149. package/dist/primitives.js +1 -1
  150. package/dist/session/session-ended.d.ts +1 -1
  151. package/dist/tokens.d.ts +3 -4
  152. package/dist/tokens.js +4 -5
  153. package/dist/web/app/app-schema-boot.d.ts +19 -0
  154. package/dist/web/app/app-schema-boot.js +124 -0
  155. package/dist/web/app/browser-locale.d.ts +22 -0
  156. package/dist/web/app/browser-locale.js +78 -0
  157. package/dist/web/app/client-plugin.d.ts +106 -0
  158. package/dist/web/app/client-plugin.js +12 -0
  159. package/dist/web/app/create-app.d.ts +104 -0
  160. package/dist/web/app/create-app.js +498 -0
  161. package/dist/web/app/create-public-surface.d.ts +36 -0
  162. package/dist/web/app/create-public-surface.js +40 -0
  163. package/dist/web/app/dashboard-body.d.ts +3 -0
  164. package/dist/web/app/dashboard-body.js +865 -0
  165. package/dist/web/app/dashboard-refresh.d.ts +6 -0
  166. package/dist/web/app/dashboard-refresh.js +15 -0
  167. package/dist/web/app/document-lang-sync.d.ts +4 -0
  168. package/dist/web/app/document-lang-sync.js +27 -0
  169. package/dist/web/app/draft-storage.d.ts +11 -0
  170. package/dist/web/app/draft-storage.js +53 -0
  171. package/dist/web/app/nav-providers-context.d.ts +13 -0
  172. package/dist/web/app/nav-providers-context.js +18 -0
  173. package/dist/web/app/nav.d.ts +40 -0
  174. package/dist/web/app/nav.js +231 -0
  175. package/dist/web/app/plain-content-editor.d.ts +3 -0
  176. package/dist/web/app/plain-content-editor.js +30 -0
  177. package/dist/web/app/relative-time.d.ts +10 -0
  178. package/dist/web/app/relative-time.js +56 -0
  179. package/dist/web/app/resolvers-context.d.ts +12 -0
  180. package/dist/web/app/resolvers-context.js +10 -0
  181. package/dist/web/app/rich-content-editor.d.ts +3 -0
  182. package/dist/web/app/rich-content-editor.js +15 -0
  183. package/dist/web/app/root-error-fallback.d.ts +2 -0
  184. package/dist/web/app/root-error-fallback.js +21 -0
  185. package/dist/web/app/screen-error-fallback.d.ts +6 -0
  186. package/dist/web/app/screen-error-fallback.js +17 -0
  187. package/dist/web/app/tiptap-editor.d.ts +3 -0
  188. package/dist/web/app/tiptap-editor.js +120 -0
  189. package/dist/web/app/toast-action-notifier.d.ts +5 -0
  190. package/dist/web/app/toast-action-notifier.js +17 -0
  191. package/dist/web/components/config-cascade.d.ts +13 -0
  192. package/dist/web/components/config-cascade.js +155 -0
  193. package/dist/web/components/config-source-badge.d.ts +6 -0
  194. package/dist/web/components/config-source-badge.js +55 -0
  195. package/dist/web/default-color-scheme.d.ts +2 -0
  196. package/dist/web/default-color-scheme.js +3 -0
  197. package/dist/web/icons.d.ts +94 -0
  198. package/dist/web/icons.js +100 -0
  199. package/dist/web/index.d.ts +78 -0
  200. package/dist/web/index.js +53 -0
  201. package/dist/web/layout/app-layout.d.ts +21 -0
  202. package/dist/web/layout/app-layout.js +8 -0
  203. package/dist/web/layout/avatar.d.ts +12 -0
  204. package/dist/web/layout/avatar.js +63 -0
  205. package/dist/web/layout/default-app-shell.d.ts +41 -0
  206. package/dist/web/layout/default-app-shell.js +16 -0
  207. package/dist/web/layout/editor-panel.d.ts +10 -0
  208. package/dist/web/layout/editor-panel.js +29 -0
  209. package/dist/web/layout/fill-classes.d.ts +9 -0
  210. package/dist/web/layout/fill-classes.js +15 -0
  211. package/dist/web/layout/filter-app-schema-navs.d.ts +7 -0
  212. package/dist/web/layout/filter-app-schema-navs.js +68 -0
  213. package/dist/web/layout/header-action-group.d.ts +6 -0
  214. package/dist/web/layout/header-action-group.js +8 -0
  215. package/dist/web/layout/header-overflow-menu.d.ts +4 -0
  216. package/dist/web/layout/header-overflow-menu.js +8 -0
  217. package/dist/web/layout/language-menu-items.d.ts +8 -0
  218. package/dist/web/layout/language-menu-items.js +16 -0
  219. package/dist/web/layout/language-switcher.d.ts +25 -0
  220. package/dist/web/layout/language-switcher.js +46 -0
  221. package/dist/web/layout/nav-tree.d.ts +19 -0
  222. package/dist/web/layout/nav-tree.js +536 -0
  223. package/dist/web/layout/page-header-slot.d.ts +25 -0
  224. package/dist/web/layout/page-header-slot.js +50 -0
  225. package/dist/web/layout/profile-menu.d.ts +13 -0
  226. package/dist/web/layout/profile-menu.js +6 -0
  227. package/dist/web/layout/shell-breadcrumb.d.ts +11 -0
  228. package/dist/web/layout/shell-breadcrumb.js +34 -0
  229. package/dist/web/layout/shell-header.d.ts +12 -0
  230. package/dist/web/layout/shell-header.js +159 -0
  231. package/dist/web/layout/sidebar-brand.d.ts +15 -0
  232. package/dist/web/layout/sidebar-brand.js +9 -0
  233. package/dist/web/layout/sidebar-panel.d.ts +41 -0
  234. package/dist/web/layout/sidebar-panel.js +107 -0
  235. package/dist/web/layout/sidebar-user.d.ts +8 -0
  236. package/dist/web/layout/sidebar-user.js +17 -0
  237. package/dist/web/layout/sidebar.d.ts +17 -0
  238. package/dist/web/layout/sidebar.js +11 -0
  239. package/dist/web/layout/target-resolver-stub.d.ts +13 -0
  240. package/dist/web/layout/target-resolver-stub.js +61 -0
  241. package/dist/web/layout/target-url.d.ts +12 -0
  242. package/dist/web/layout/target-url.js +77 -0
  243. package/dist/web/layout/theme-label.d.ts +15 -0
  244. package/dist/web/layout/theme-label.js +35 -0
  245. package/dist/web/layout/theme-menu-item.d.ts +12 -0
  246. package/dist/web/layout/theme-menu-item.js +16 -0
  247. package/dist/web/layout/theme-toggle.d.ts +17 -0
  248. package/dist/web/layout/theme-toggle.js +22 -0
  249. package/dist/web/layout/topbar.d.ts +8 -0
  250. package/dist/web/layout/topbar.js +4 -0
  251. package/dist/web/layout/workspace-shell.d.ts +63 -0
  252. package/dist/web/layout/workspace-shell.js +220 -0
  253. package/dist/web/layout/workspace-switcher.d.ts +15 -0
  254. package/dist/web/layout/workspace-switcher.js +36 -0
  255. package/dist/web/lib/accept-attr.d.ts +1 -0
  256. package/dist/web/lib/accept-attr.js +6 -0
  257. package/dist/web/lib/clamp.d.ts +1 -0
  258. package/dist/web/lib/clamp.js +3 -0
  259. package/dist/web/lib/cn.d.ts +6 -0
  260. package/dist/web/lib/cn.js +9 -0
  261. package/dist/web/lib/download.d.ts +2 -0
  262. package/dist/web/lib/download.js +24 -0
  263. package/dist/web/lib/file-ref-download.d.ts +15 -0
  264. package/dist/web/lib/file-ref-download.js +62 -0
  265. package/dist/web/lib/file-upload-form-data.d.ts +7 -0
  266. package/dist/web/lib/file-upload-form-data.js +11 -0
  267. package/dist/web/lib/resize-image.d.ts +1 -0
  268. package/dist/web/lib/resize-image.js +66 -0
  269. package/dist/web/lib/upload-file-ref.d.ts +9 -0
  270. package/dist/web/lib/upload-file-ref.js +29 -0
  271. package/dist/web/primitives/action-menu.d.ts +34 -0
  272. package/dist/web/primitives/action-menu.js +30 -0
  273. package/dist/web/primitives/calendar-popover.d.ts +13 -0
  274. package/dist/web/primitives/calendar-popover.js +76 -0
  275. package/dist/web/primitives/combobox.d.ts +56 -0
  276. package/dist/web/primitives/combobox.js +127 -0
  277. package/dist/web/primitives/date-field.d.ts +18 -0
  278. package/dist/web/primitives/date-field.js +74 -0
  279. package/dist/web/primitives/date-input.d.ts +1 -0
  280. package/dist/web/primitives/date-input.js +5 -0
  281. package/dist/web/primitives/date-parse.d.ts +11 -0
  282. package/dist/web/primitives/date-parse.js +159 -0
  283. package/dist/web/primitives/dialog.d.ts +3 -0
  284. package/dist/web/primitives/dialog.js +42 -0
  285. package/dist/web/primitives/drawer.d.ts +3 -0
  286. package/dist/web/primitives/drawer.js +17 -0
  287. package/dist/web/primitives/dropdown-menu.d.ts +15 -0
  288. package/dist/web/primitives/dropdown-menu.js +56 -0
  289. package/dist/web/primitives/embedded-list-input.d.ts +9 -0
  290. package/dist/web/primitives/embedded-list-input.js +382 -0
  291. package/dist/web/primitives/file-thumbnail.d.ts +25 -0
  292. package/dist/web/primitives/file-thumbnail.js +90 -0
  293. package/dist/web/primitives/file-upload.d.ts +21 -0
  294. package/dist/web/primitives/file-upload.js +56 -0
  295. package/dist/web/primitives/index.d.ts +34 -0
  296. package/dist/web/primitives/index.js +2021 -0
  297. package/dist/web/primitives/json-view.d.ts +7 -0
  298. package/dist/web/primitives/json-view.js +84 -0
  299. package/dist/web/primitives/layout.d.ts +27 -0
  300. package/dist/web/primitives/layout.js +30 -0
  301. package/dist/web/primitives/lightbox.d.ts +3 -0
  302. package/dist/web/primitives/lightbox.js +36 -0
  303. package/dist/web/primitives/locale-number.d.ts +2 -0
  304. package/dist/web/primitives/locale-number.js +54 -0
  305. package/dist/web/primitives/located-timestamp-input.d.ts +22 -0
  306. package/dist/web/primitives/located-timestamp-input.js +22 -0
  307. package/dist/web/primitives/metric.d.ts +5 -0
  308. package/dist/web/primitives/metric.js +18 -0
  309. package/dist/web/primitives/modal-shell.d.ts +17 -0
  310. package/dist/web/primitives/modal-shell.js +9 -0
  311. package/dist/web/primitives/modal.d.ts +3 -0
  312. package/dist/web/primitives/modal.js +13 -0
  313. package/dist/web/primitives/money-input.d.ts +18 -0
  314. package/dist/web/primitives/money-input.js +122 -0
  315. package/dist/web/primitives/narrow-pinned-footer.d.ts +12 -0
  316. package/dist/web/primitives/narrow-pinned-footer.js +153 -0
  317. package/dist/web/primitives/number-input.d.ts +18 -0
  318. package/dist/web/primitives/number-input.js +53 -0
  319. package/dist/web/primitives/option-groups.d.ts +11 -0
  320. package/dist/web/primitives/option-groups.js +27 -0
  321. package/dist/web/primitives/page-header.d.ts +3 -0
  322. package/dist/web/primitives/page-header.js +52 -0
  323. package/dist/web/primitives/promo-panel.d.ts +3 -0
  324. package/dist/web/primitives/promo-panel.js +11 -0
  325. package/dist/web/primitives/segmented-select.d.ts +21 -0
  326. package/dist/web/primitives/segmented-select.js +62 -0
  327. package/dist/web/primitives/share-actions.d.ts +4 -0
  328. package/dist/web/primitives/share-actions.js +56 -0
  329. package/dist/web/primitives/status-badge.d.ts +3 -0
  330. package/dist/web/primitives/status-badge.js +5 -0
  331. package/dist/web/primitives/sticky-action-bar.d.ts +5 -0
  332. package/dist/web/primitives/sticky-action-bar.js +15 -0
  333. package/dist/web/primitives/tabs.d.ts +3 -0
  334. package/dist/web/primitives/tabs.js +107 -0
  335. package/dist/web/primitives/timestamp-input.d.ts +27 -0
  336. package/dist/web/primitives/timestamp-input.js +87 -0
  337. package/dist/web/primitives/toast.d.ts +19 -0
  338. package/dist/web/primitives/toast.js +63 -0
  339. package/dist/web/primitives/tz-input.d.ts +11 -0
  340. package/dist/web/primitives/tz-input.js +8 -0
  341. package/dist/web/primitives/tz-options.d.ts +4 -0
  342. package/dist/web/primitives/tz-options.js +17 -0
  343. package/dist/web/primitives/use-keyboard-inset.d.ts +1 -0
  344. package/dist/web/primitives/use-keyboard-inset.js +28 -0
  345. package/dist/web/primitives/use-narrow-viewport.d.ts +4 -0
  346. package/dist/web/primitives/use-narrow-viewport.js +46 -0
  347. package/dist/web/react-css-custom-properties.d.ts +6 -0
  348. package/dist/web/react-css-custom-properties.js +1 -0
  349. package/dist/web/sse/live-events.d.ts +15 -0
  350. package/dist/web/sse/live-events.js +148 -0
  351. package/dist/web/theme-plugin.d.ts +41 -0
  352. package/dist/web/theme-plugin.js +123 -0
  353. package/dist/web/tokens.d.ts +24 -0
  354. package/dist/web/tokens.js +203 -0
  355. package/dist/web/ui/avatar.d.ts +11 -0
  356. package/dist/web/ui/avatar.js +25 -0
  357. package/dist/web/ui/badge.d.ts +9 -0
  358. package/dist/web/ui/badge.js +26 -0
  359. package/dist/web/ui/breadcrumb.d.ts +11 -0
  360. package/dist/web/ui/breadcrumb.js +29 -0
  361. package/dist/web/ui/button.d.ts +10 -0
  362. package/dist/web/ui/button.js +37 -0
  363. package/dist/web/ui/checkbox.d.ts +4 -0
  364. package/dist/web/ui/checkbox.js +11 -0
  365. package/dist/web/ui/input.d.ts +3 -0
  366. package/dist/web/ui/input.js +8 -0
  367. package/dist/web/ui/label.d.ts +4 -0
  368. package/dist/web/ui/label.js +10 -0
  369. package/dist/web/ui/resizable.d.ts +7 -0
  370. package/dist/web/ui/resizable.js +16 -0
  371. package/dist/web/ui/separator.d.ts +4 -0
  372. package/dist/web/ui/separator.js +10 -0
  373. package/dist/web/ui/sheet.d.ts +14 -0
  374. package/dist/web/ui/sheet.js +42 -0
  375. package/dist/web/ui/sidebar.d.ts +73 -0
  376. package/dist/web/ui/sidebar.js +211 -0
  377. package/dist/web/ui/skeleton.d.ts +2 -0
  378. package/dist/web/ui/skeleton.js +7 -0
  379. package/dist/web/ui/switch.d.ts +6 -0
  380. package/dist/web/ui/switch.js +10 -0
  381. package/dist/web/ui/table.d.ts +10 -0
  382. package/dist/web/ui/table.js +30 -0
  383. package/dist/web/ui/tabs.d.ts +11 -0
  384. package/dist/web/ui/tabs.js +31 -0
  385. package/dist/web/ui/textarea.d.ts +3 -0
  386. package/dist/web/ui/textarea.js +8 -0
  387. package/dist/web/ui/tooltip.d.ts +7 -0
  388. package/dist/web/ui/tooltip.js +19 -0
  389. package/dist/web/ui/use-mobile.d.ts +1 -0
  390. package/dist/web/ui/use-mobile.js +16 -0
  391. package/dist/web/version/update-checker.d.ts +9 -0
  392. package/dist/web/version/update-checker.js +88 -0
  393. package/dist/web/widgets/ai-text-field.d.ts +36 -0
  394. package/dist/web/widgets/ai-text-field.js +137 -0
  395. package/dist/web/widgets/chart-window.d.ts +58 -0
  396. package/dist/web/widgets/chart-window.js +190 -0
  397. package/dist/web/widgets/charts.d.ts +208 -0
  398. package/dist/web/widgets/charts.js +685 -0
  399. package/dist/web/widgets/collapsible-section.d.ts +10 -0
  400. package/dist/web/widgets/collapsible-section.js +17 -0
  401. package/dist/web/widgets/dashboard-list.d.ts +21 -0
  402. package/dist/web/widgets/dashboard-list.js +45 -0
  403. package/dist/web/widgets/detail-list.d.ts +15 -0
  404. package/dist/web/widgets/detail-list.js +8 -0
  405. package/dist/web/widgets/drawer.d.ts +65 -0
  406. package/dist/web/widgets/drawer.js +142 -0
  407. package/dist/web/widgets/feed-list.d.ts +13 -0
  408. package/dist/web/widgets/feed-list.js +9 -0
  409. package/dist/web/widgets/floating-panel.d.ts +30 -0
  410. package/dist/web/widgets/floating-panel.js +242 -0
  411. package/dist/web/widgets/form-fields.d.ts +93 -0
  412. package/dist/web/widgets/form-fields.js +50 -0
  413. package/dist/web/widgets/index.d.ts +27 -0
  414. package/dist/web/widgets/index.js +30 -0
  415. package/dist/web/widgets/infinity-list.d.ts +46 -0
  416. package/dist/web/widgets/infinity-list.js +211 -0
  417. package/dist/web/widgets/mode-switch.d.ts +21 -0
  418. package/dist/web/widgets/mode-switch.js +25 -0
  419. package/dist/web/widgets/photo-slots.d.ts +29 -0
  420. package/dist/web/widgets/photo-slots.js +52 -0
  421. package/dist/web/widgets/plan-card.d.ts +36 -0
  422. package/dist/web/widgets/plan-card.js +13 -0
  423. package/dist/web/widgets/progress-bar.d.ts +19 -0
  424. package/dist/web/widgets/progress-bar.js +24 -0
  425. package/dist/web/widgets/progress-list.d.ts +19 -0
  426. package/dist/web/widgets/progress-list.js +11 -0
  427. package/dist/web/widgets/public-shell.d.ts +22 -0
  428. package/dist/web/widgets/public-shell.js +15 -0
  429. package/dist/web/widgets/query-table.d.ts +29 -0
  430. package/dist/web/widgets/query-table.js +30 -0
  431. package/dist/web/widgets/result-panel.d.ts +69 -0
  432. package/dist/web/widgets/result-panel.js +30 -0
  433. package/dist/web/widgets/section-card.d.ts +12 -0
  434. package/dist/web/widgets/section-card.js +9 -0
  435. package/dist/web/widgets/sheet-parts.d.ts +9 -0
  436. package/dist/web/widgets/sheet-parts.js +11 -0
  437. package/dist/web/widgets/side-by-side-table.d.ts +31 -0
  438. package/dist/web/widgets/side-by-side-table.js +11 -0
  439. package/dist/web/widgets/stat.d.ts +54 -0
  440. package/dist/web/widgets/stat.js +65 -0
  441. package/dist/web/widgets/states.d.ts +23 -0
  442. package/dist/web/widgets/states.js +20 -0
  443. package/dist/web/widgets/status-badge.d.ts +15 -0
  444. package/dist/web/widgets/status-badge.js +24 -0
  445. package/dist/web/widgets/step-bar.d.ts +35 -0
  446. package/dist/web/widgets/step-bar.js +60 -0
  447. package/dist/web/widgets/upload-zone.d.ts +24 -0
  448. package/dist/web/widgets/upload-zone.js +108 -0
  449. package/dist/web/widgets/use-draft.d.ts +20 -0
  450. package/dist/web/widgets/use-draft.js +21 -0
  451. package/dist/web/widgets/use-pointer-drag.d.ts +21 -0
  452. package/dist/web/widgets/use-pointer-drag.js +53 -0
  453. package/package.json +105 -7
  454. package/src/changes.json +77 -0
  455. package/src/web/fonts/OFL.txt +93 -0
  456. package/src/web/fonts/ibm-plex-mono-latin-400.woff2 +0 -0
  457. package/src/web/fonts/ibm-plex-mono-latin-500.woff2 +0 -0
  458. package/src/web/fonts/ibm-plex-mono-latin-ext-400.woff2 +0 -0
  459. package/src/web/fonts/ibm-plex-mono-latin-ext-500.woff2 +0 -0
  460. package/src/web/fonts/ibm-plex-sans-latin-400.woff2 +0 -0
  461. package/src/web/fonts/ibm-plex-sans-latin-500.woff2 +0 -0
  462. package/src/web/fonts/ibm-plex-sans-latin-600.woff2 +0 -0
  463. package/src/web/fonts/ibm-plex-sans-latin-ext-400.woff2 +0 -0
  464. package/src/web/fonts/ibm-plex-sans-latin-ext-500.woff2 +0 -0
  465. package/src/web/fonts/ibm-plex-sans-latin-ext-600.woff2 +0 -0
  466. package/src/web/styles.css +401 -0
@@ -0,0 +1,501 @@
1
+ import { availableSelectOptions, evalFieldCondition, isExtensionEditSection, isFieldsEditSection, isWriteFormEditSection, normalizeEditField, parseRefTarget, sectionFieldSpecs, WRITE_FORM_SECTION_ENTITY, } from "@cosmicdrift/kumiko-framework/ui-types";
2
+ import { buildOptionLabels, embeddedCellLabelKey, embeddedCellOptionLabelKey, fieldLabelKey, fieldOptionLabelKey, } from "./list.js";
3
+ // Resolves a writeForm section's own fieldDefs/fields through the same
4
+ // per-field pipeline as a plain fields section, by reusing the pipeline
5
+ // itself rather than duplicating it: wrap fieldDefs/fields as a throwaway
6
+ // entityEdit screen (same "synthesize a pseudo-entity" idiom as the shims in
7
+ // packages/renderer/src/app/*-shim.ts) and recurse into computeEditViewModel
8
+ // once. Split out of computeEditViewModel's section-map to keep that
9
+ // function's own complexity from absorbing this branch's decision points.
10
+ function computeWriteFormSectionViewModel(sectionSpec, screenId, values, translate, featureName) {
11
+ const innerEntity = { fields: sectionSpec.fieldDefs };
12
+ const innerScreen = {
13
+ id: `${screenId}:${sectionSpec.id ?? "write-form"}`,
14
+ type: "entityEdit",
15
+ entity: WRITE_FORM_SECTION_ENTITY,
16
+ layout: {
17
+ sections: [{ kind: "fields", fields: sectionSpec.fields, columns: sectionSpec.columns }],
18
+ },
19
+ };
20
+ const inner = computeEditViewModel({
21
+ screen: innerScreen,
22
+ entity: innerEntity,
23
+ values,
24
+ translate,
25
+ featureName,
26
+ });
27
+ const innerSection = inner.sections[0];
28
+ const fields = innerSection?.kind === "fields" ? innerSection.fields : [];
29
+ return {
30
+ kind: "writeForm",
31
+ ...(sectionSpec.title !== undefined && { title: translate(sectionSpec.title) }),
32
+ ...(sectionSpec.description !== undefined && {
33
+ description: translate(sectionSpec.description),
34
+ }),
35
+ columns: sectionSpec.columns ?? 1,
36
+ fields,
37
+ ...(sectionSpec.icon !== undefined && { icon: sectionSpec.icon }),
38
+ handler: sectionSpec.handler,
39
+ ...(sectionSpec.submitLabel !== undefined && {
40
+ submitLabel: translate(sectionSpec.submitLabel),
41
+ }),
42
+ ...(sectionSpec.actions !== undefined && { actions: sectionSpec.actions }),
43
+ };
44
+ }
45
+ function wasEmptiedByWriteExclusion(declaredFieldSpecs, remainingFields) {
46
+ return declaredFieldSpecs.length > 0 && remainingFields.length === 0;
47
+ }
48
+ // relatedList runs its own query — nothing here to resolve against
49
+ // entity/values, the spec passes through verbatim (fw#2166).
50
+ export function computeRelatedListSectionViewModel(sectionSpec, translate) {
51
+ return {
52
+ kind: "relatedList",
53
+ title: translate(sectionSpec.title),
54
+ query: sectionSpec.query,
55
+ ...(sectionSpec.parentParam !== undefined && { parentParam: sectionSpec.parentParam }),
56
+ ...(sectionSpec.parentFilter !== undefined && { parentFilter: sectionSpec.parentFilter }),
57
+ columns: sectionSpec.columns,
58
+ ...(sectionSpec.entity !== undefined && { entity: sectionSpec.entity }),
59
+ ...(sectionSpec.description !== undefined && {
60
+ description: translate(sectionSpec.description),
61
+ }),
62
+ ...(sectionSpec.itemNoun !== undefined && { itemNoun: sectionSpec.itemNoun }),
63
+ ...(sectionSpec.pageSize !== undefined && { pageSize: sectionSpec.pageSize }),
64
+ ...(sectionSpec.defaultSort !== undefined && { defaultSort: sectionSpec.defaultSort }),
65
+ ...(sectionSpec.searchable !== undefined && { searchable: sectionSpec.searchable }),
66
+ ...(sectionSpec.facets !== undefined && { facets: sectionSpec.facets }),
67
+ ...(sectionSpec.rowClick !== undefined && { rowClick: sectionSpec.rowClick }),
68
+ ...(sectionSpec.rowActions !== undefined && { rowActions: sectionSpec.rowActions }),
69
+ ...(sectionSpec.rowActionMode !== undefined && { rowActionMode: sectionSpec.rowActionMode }),
70
+ ...(sectionSpec.groupBy !== undefined && { groupBy: sectionSpec.groupBy }),
71
+ ...(sectionSpec.rowTone !== undefined && { rowTone: sectionSpec.rowTone }),
72
+ ...(sectionSpec.toolbarActions !== undefined && { toolbarActions: sectionSpec.toolbarActions }),
73
+ ...(sectionSpec.actions !== undefined && { actions: sectionSpec.actions }),
74
+ ...(sectionSpec.emptyState !== undefined && {
75
+ emptyState: {
76
+ title: translate(sectionSpec.emptyState.title),
77
+ ...(sectionSpec.emptyState.description !== undefined && {
78
+ description: translate(sectionSpec.emptyState.description),
79
+ }),
80
+ // Action stays untranslated, same convention as rowActions/
81
+ // toolbarActions above — the renderer's row-actions builder
82
+ // translates `action.label` at button-build time.
83
+ ...(sectionSpec.emptyState.action !== undefined && {
84
+ action: sectionSpec.emptyState.action,
85
+ }),
86
+ },
87
+ }),
88
+ };
89
+ }
90
+ function translateAffix(affix, translate) {
91
+ return typeof affix === "string" ? translate(affix) : affix;
92
+ }
93
+ function deriveFieldAffixHints(normalized, translate) {
94
+ return {
95
+ ...(normalized.placeholder !== undefined && { placeholder: translate(normalized.placeholder) }),
96
+ ...(normalized.prefix !== undefined && {
97
+ prefix: translateAffix(normalized.prefix, translate),
98
+ }),
99
+ ...(normalized.suffix !== undefined && {
100
+ suffix: translateAffix(normalized.suffix, translate),
101
+ }),
102
+ ...(normalized.fillAction !== undefined && {
103
+ fillAction: { ...normalized.fillAction, label: translate(normalized.fillAction.label) },
104
+ }),
105
+ };
106
+ }
107
+ function deriveSelectOptionsQuery(fieldDef) {
108
+ return fieldDef.type === "select" && fieldDef.optionsQuery !== undefined
109
+ ? {
110
+ selectOptionsQuery: {
111
+ query: fieldDef.optionsQuery,
112
+ payload: fieldDef.optionsQueryPayload ?? {},
113
+ },
114
+ }
115
+ : {};
116
+ }
117
+ function deriveSelectOptionsAvailabilityQuery(fieldDef) {
118
+ if (fieldDef.type === "multiSelect") {
119
+ return fieldDef.optionsAvailabilityQuery !== undefined
120
+ ? {
121
+ selectOptionsAvailabilityQuery: { query: fieldDef.optionsAvailabilityQuery, payload: {} },
122
+ }
123
+ : {};
124
+ }
125
+ return fieldDef.type === "select" && fieldDef.optionsAvailabilityQuery !== undefined
126
+ ? {
127
+ selectOptionsAvailabilityQuery: {
128
+ query: fieldDef.optionsAvailabilityQuery,
129
+ payload: fieldDef.optionsQueryPayload ?? {},
130
+ },
131
+ }
132
+ : {};
133
+ }
134
+ // A stored value that conditionalOptions no longer allows stays listed, so the
135
+ // form shows it (flagged on submit) instead of silently dropping it.
136
+ function selectableOptions(fieldDef, fieldName, values) {
137
+ if (fieldDef.type === "multiSelect")
138
+ return fieldDef.options;
139
+ if (fieldDef.type !== "select")
140
+ return undefined;
141
+ if (!fieldDef.conditionalOptions)
142
+ return fieldDef.options;
143
+ const available = availableSelectOptions(fieldDef, values);
144
+ const current = values[fieldName];
145
+ return fieldDef.options.filter((option) => available.includes(option) || option === current);
146
+ }
147
+ function deriveSelectFieldHints(fieldDef, translate, featureName, entityName, fieldName, values) {
148
+ const options = selectableOptions(fieldDef, fieldName, values);
149
+ const optionLabels = options !== undefined
150
+ ? buildOptionLabels(translate, (value) => fieldOptionLabelKey(featureName, entityName, fieldName, value), options)
151
+ : undefined;
152
+ const declaredDisplay = fieldDef.type === "multiSelect" || fieldDef.type === "select" ? fieldDef.display : undefined;
153
+ // The renderer's heuristic counts options, so a filtered list would switch widgets with the discriminator.
154
+ const display = declaredDisplay ??
155
+ (fieldDef.type === "select" && fieldDef.conditionalOptions ? "dropdown" : undefined);
156
+ const columns = fieldDef.type === "multiSelect" ? fieldDef.columns : undefined;
157
+ const maxRows = fieldDef.type === "multiSelect" ? fieldDef.maxRows : undefined;
158
+ return {
159
+ ...deriveSelectOptionsQuery(fieldDef),
160
+ ...deriveSelectOptionsAvailabilityQuery(fieldDef),
161
+ ...(options !== undefined && { options }),
162
+ ...(optionLabels !== undefined && { optionLabels }),
163
+ ...(display !== undefined && { display }),
164
+ ...(columns !== undefined && { columns }),
165
+ ...(maxRows !== undefined && { maxRows }),
166
+ };
167
+ }
168
+ function deriveTextFieldHints(fieldDef) {
169
+ const multiline = fieldDef.type === "text" || fieldDef.type === "longText" ? fieldDef.multiline : undefined;
170
+ const format = fieldDef.type === "text" ? fieldDef.format : undefined;
171
+ const writeOnly = fieldDef.type === "text" && fieldDef.writeOnly === true;
172
+ const autoComplete = fieldDef.type === "text" ? fieldDef.autoComplete : undefined;
173
+ return {
174
+ ...(multiline !== undefined && { multiline }),
175
+ ...(autoComplete !== undefined && { autoComplete }),
176
+ ...(format !== undefined && { format }),
177
+ ...(writeOnly && { writeOnly: true }),
178
+ ...("sensitive" in fieldDef && fieldDef.sensitive === true && { sensitive: true }),
179
+ };
180
+ }
181
+ function deriveDateFieldHints(fieldDef) {
182
+ const wallClock = fieldDef.type === "timestamp" &&
183
+ fieldDef.locatedBy !== undefined
184
+ ? true
185
+ : undefined;
186
+ const dateBounds = fieldDef.type === "date" ||
187
+ fieldDef.type === "timestamp" ||
188
+ fieldDef.type === "locatedTimestamp"
189
+ ? fieldDef
190
+ : undefined;
191
+ return {
192
+ ...(wallClock !== undefined && { wallClock }),
193
+ ...(dateBounds?.min !== undefined && { min: dateBounds.min }),
194
+ ...(dateBounds?.max !== undefined && { max: dateBounds.max }),
195
+ ...(dateBounds?.locale !== undefined && { dateLocale: dateBounds.locale }),
196
+ };
197
+ }
198
+ function deriveNumericFieldHints(fieldDef, resolvedCurrency) {
199
+ const grouping = fieldDef.type === "number" ? fieldDef.grouping : undefined;
200
+ return {
201
+ ...(grouping !== undefined && { grouping }),
202
+ ...(fieldDef.type === "money" && { currency: resolvedCurrency }),
203
+ ...(fieldDef.type === "number" && fieldDef.unit !== undefined && { unit: fieldDef.unit }),
204
+ };
205
+ }
206
+ // Declared reference metadata (EditFieldSpec.refEntity) takes priority over
207
+ // fieldDef.type — see computeEditViewModel's effectiveType, same reasoning.
208
+ function deriveReferenceFieldHints(fieldDef, normalized, declaredRefTarget, featureName) {
209
+ const refRaw = declaredRefTarget === undefined && fieldDef.type === "reference"
210
+ ? fieldDef.entity
211
+ : undefined;
212
+ const refTarget = declaredRefTarget ?? (refRaw !== undefined ? parseRefTarget(refRaw, featureName) : undefined);
213
+ const refLabelField = declaredRefTarget !== undefined
214
+ ? (normalized.refLabelField ?? "id")
215
+ : fieldDef.type === "reference"
216
+ ? (fieldDef.labelField ?? "id")
217
+ : undefined;
218
+ return {
219
+ ...(refTarget?.entityName !== undefined && { refEntity: refTarget.entityName }),
220
+ ...(refTarget?.featureName !== undefined && { refFeature: refTarget.featureName }),
221
+ ...(refLabelField !== undefined && { refLabelField }),
222
+ ...deriveReferenceMultiHints(fieldDef, declaredRefTarget),
223
+ };
224
+ }
225
+ // Declared reference metadata has no `multiple` or `optionsQuery` concept
226
+ // (it targets row-meta/derived fields, always single-valued and resolved
227
+ // through the target entity) — only a real ReferenceFieldDef carries them.
228
+ function deriveReferenceMultiHints(fieldDef, declaredRefTarget) {
229
+ const ownReferenceDef = declaredRefTarget === undefined && fieldDef.type === "reference"
230
+ ? fieldDef
231
+ : undefined;
232
+ const refMultiple = ownReferenceDef === undefined ? undefined : (ownReferenceDef.multiple ?? false);
233
+ return {
234
+ ...(ownReferenceDef?.optionsQuery !== undefined && {
235
+ refOptionsQuery: ownReferenceDef.optionsQuery,
236
+ }),
237
+ ...(refMultiple !== undefined && { refMultiple }),
238
+ };
239
+ }
240
+ // file/image: entityType/fieldName travel with the upload POST so the
241
+ // endpoint validates against the right field definition.
242
+ function isFileFieldType(fieldDef) {
243
+ return (fieldDef.type === "file" ||
244
+ fieldDef.type === "image" ||
245
+ fieldDef.type === "files" ||
246
+ fieldDef.type === "images");
247
+ }
248
+ function deriveImageHints(fieldDef) {
249
+ if (fieldDef.type !== "image" && fieldDef.type !== "images")
250
+ return {};
251
+ const imageVariant = Object.keys(fieldDef.variants ?? {})[0];
252
+ return {
253
+ ...(imageVariant !== undefined && { imageVariant }),
254
+ ...(fieldDef.capture !== undefined && { capture: fieldDef.capture }),
255
+ };
256
+ }
257
+ function deriveFileFieldHints(fieldDef, entityName, fieldName, entityId) {
258
+ if (!isFileFieldType(fieldDef))
259
+ return {};
260
+ const maxCount = fieldDef.type === "files" || fieldDef.type === "images" ? fieldDef.maxCount : undefined;
261
+ return {
262
+ ...(fieldDef.accept !== undefined && { accept: fieldDef.accept }),
263
+ ...(fieldDef.maxSize !== undefined && { maxSize: fieldDef.maxSize }),
264
+ ...(maxCount !== undefined && { maxCount }),
265
+ entityType: entityName,
266
+ fieldName,
267
+ ...(entityId !== undefined && { entityId }),
268
+ ...deriveImageHints(fieldDef),
269
+ };
270
+ }
271
+ function deriveEmbeddedCellSelectHints(subField, translate, featureName, entityName, fieldName, subFieldName) {
272
+ if (subField.type !== "select")
273
+ return {};
274
+ const options = subField.options ?? [];
275
+ return {
276
+ options,
277
+ optionLabels: buildOptionLabels(translate, (value) => embeddedCellOptionLabelKey(featureName, entityName, fieldName, subFieldName, value), options),
278
+ };
279
+ }
280
+ function deriveEmbeddedCellReferenceHints(subField, featureName) {
281
+ if (subField.type !== "reference")
282
+ return {};
283
+ const target = subField.entity !== undefined ? parseRefTarget(subField.entity, featureName) : undefined;
284
+ return {
285
+ ...(target !== undefined && { refEntity: target.entityName, refFeature: target.featureName }),
286
+ ...(subField.labelField !== undefined && { refLabelField: subField.labelField }),
287
+ ...(subField.optionsQuery !== undefined && { refOptionsQuery: subField.optionsQuery }),
288
+ };
289
+ }
290
+ function buildEmbeddedListCell(subFieldName, subField, translate, featureName, entityName, fieldName, listSpec) {
291
+ return {
292
+ field: subFieldName,
293
+ label: translate(embeddedCellLabelKey(featureName, entityName, fieldName, subFieldName)),
294
+ type: subField.type,
295
+ required: subField.required === true,
296
+ ...deriveEmbeddedCellSelectHints(subField, translate, featureName, entityName, fieldName, subFieldName),
297
+ ...deriveEmbeddedCellReferenceHints(subField, featureName),
298
+ ...(subField.type === "decimal" && subField.scale !== undefined && { scale: subField.scale }),
299
+ ...(subField.type === "select" &&
300
+ subField.display !== undefined && { display: subField.display }),
301
+ ...(listSpec?.readOnlyCells?.includes(subFieldName) === true && { readOnly: true }),
302
+ };
303
+ }
304
+ // Embedded-LIST field (`multiple: true`) — per-cell metadata for a renderer
305
+ // to draw one row per array item (invoice-positions-style table). A plain
306
+ // (non-list) embedded field emits none of this; the renderer tells the two
307
+ // apart by whether embeddedListCells is set, not by `type` (which stays
308
+ // "embedded" either way).
309
+ function deriveEmbeddedListHints(fieldDef, translate, featureName, entityName, fieldName, resolvedCurrency, listSpec) {
310
+ const isEmbeddedList = fieldDef.type === "embedded" &&
311
+ fieldDef.multiple === true;
312
+ const embeddedListDef = isEmbeddedList
313
+ ? fieldDef
314
+ : undefined;
315
+ const embeddedListCells = embeddedListDef !== undefined
316
+ ? Object.entries(embeddedListDef.schema).map(([subFieldName, subField]) => buildEmbeddedListCell(subFieldName, subField, translate, featureName, entityName, fieldName, listSpec))
317
+ : undefined;
318
+ return {
319
+ ...(embeddedListCells !== undefined && { embeddedListCells }),
320
+ ...(embeddedListDef?.minItems !== undefined && {
321
+ embeddedListMinItems: embeddedListDef.minItems,
322
+ }),
323
+ ...(embeddedListDef?.maxItems !== undefined && {
324
+ embeddedListMaxItems: embeddedListDef.maxItems,
325
+ }),
326
+ ...(embeddedListDef?.derived !== undefined && {
327
+ embeddedListDerived: embeddedListDef.derived,
328
+ }),
329
+ ...(embeddedListDef?.totals !== undefined && {
330
+ embeddedListTotals: embeddedListDef.totals,
331
+ }),
332
+ // Currency lives on the head aggregate (entity.defaultCurrency), not per
333
+ // row — one value for the whole embedded list.
334
+ ...(embeddedListDef !== undefined && { embeddedListCurrency: resolvedCurrency }),
335
+ ...(embeddedListDef !== undefined &&
336
+ listSpec?.fixedRows === true && { embeddedListFixedRows: true }),
337
+ };
338
+ }
339
+ function buildExtensionSectionViewModel(sectionSpec, translate) {
340
+ const entityNameOverride = sectionSpec.entityName?.trim();
341
+ return {
342
+ kind: "extension",
343
+ ...(sectionSpec.id !== undefined && { id: sectionSpec.id }),
344
+ title: translate(sectionSpec.title),
345
+ component: sectionSpec.component,
346
+ contributesToFormSubmit: sectionSpec.contributesToFormSubmit === true,
347
+ // Blank override must fall back to the host value: the renderer's `??`
348
+ // would otherwise pass "" through to the mounted extension.
349
+ ...(entityNameOverride !== undefined &&
350
+ entityNameOverride.length > 0 && { entityName: entityNameOverride }),
351
+ ...(sectionSpec.actions !== undefined && { actions: sectionSpec.actions }),
352
+ };
353
+ }
354
+ // Pure transform from screen-def + entity-def + row-values to the flat
355
+ // section/field tree the renderer draws. FieldConditions are evaluated here
356
+ // so the renderer never re-runs them during React render.
357
+ export function computeEditViewModel(input) {
358
+ const { screen, entity, values, translate, featureName, mode, entityId } = input;
359
+ const excludedFields = new Set(mode === undefined ? [] : screen.writeExcludedFields?.[mode]);
360
+ const isHiddenByExclusion = (fieldSpec) => mode === "create" && excludedFields.has(normalizeEditField(fieldSpec).field);
361
+ const sections = screen.layout.sections.map((sectionSpec) => {
362
+ if (isExtensionEditSection(sectionSpec)) {
363
+ return buildExtensionSectionViewModel(sectionSpec, translate);
364
+ }
365
+ if (isWriteFormEditSection(sectionSpec)) {
366
+ return computeWriteFormSectionViewModel(sectionSpec, screen.id, values, translate, featureName);
367
+ }
368
+ if (!isFieldsEditSection(sectionSpec)) {
369
+ return computeRelatedListSectionViewModel(sectionSpec, translate);
370
+ }
371
+ // `groups` flattens into the same per-field pipeline as plain `fields`;
372
+ // the group structure below just re-groups the computed views by name.
373
+ const declaredFieldSpecs = sectionFieldSpecs(sectionSpec);
374
+ const fields = declaredFieldSpecs
375
+ .filter((fieldSpec) => !isHiddenByExclusion(fieldSpec))
376
+ .map((fieldSpec) => {
377
+ const normalized = normalizeEditField(fieldSpec);
378
+ const fieldDef = entity.fields[normalized.field];
379
+ if (!fieldDef) {
380
+ throw new Error(`computeEditViewModel: screen "${screen.id}" references unknown field "${normalized.field}" on entity "${screen.entity}"`);
381
+ }
382
+ // Declared reference metadata (EditFieldSpec.refEntity) — for
383
+ // projectionDetail fields, which have no EntityDefinition field to
384
+ // carry a real "reference" type. Takes priority over fieldDef.type
385
+ // below so it also fires against the pseudo-entity that hardcodes
386
+ // every field as "text" (projection-detail-shim) — real entityEdit
387
+ // screens never set this, so their fieldDef.type === "reference"
388
+ // branch is unaffected.
389
+ // A real non-text field (e.g. a `reference` with `multiple`) keeps its own
390
+ // type and hints, as documented on EditFieldSpec.refEntity; the shim's
391
+ // pseudo-entity only ever declares "text".
392
+ const declaredRefTarget = normalized.refEntity !== undefined && fieldDef.type === "text"
393
+ ? parseRefTarget(normalized.refEntity, featureName)
394
+ : undefined;
395
+ const effectiveType = declaredRefTarget !== undefined ? "reference" : fieldDef.type;
396
+ const label = translate(screen.fieldLabels?.[normalized.field] ??
397
+ fieldLabelKey(featureName, screen.entity, normalized.field));
398
+ const visible = evalCondition(normalized.visible, true, values);
399
+ // `readOnly` (camelCase) is the name on both sides: EditFieldSpec
400
+ // in the engine, and the view-model emitted here. One convention
401
+ // through the stack beats translating at the boundary.
402
+ const readOnly = (mode === "update" && excludedFields.has(normalized.field)) ||
403
+ evalCondition(normalized.readOnly, false, values);
404
+ // `required` on the field-spec overrides the entity-default. A
405
+ // field that's required at the entity-level but marked required:
406
+ // false on the screen (e.g. a soft-onboarding wizard that
407
+ // collects less up-front) respects the screen override.
408
+ const entityRequired = fieldDef.required === true;
409
+ const required = evalCondition(normalized.required, entityRequired, values);
410
+ // ponytail: "EUR" mirrors DEFAULT_CURRENCIES[0] from
411
+ // framework/src/engine/field-helpers.ts — headless has no dependency
412
+ // on that module, so the literal is duplicated here instead of
413
+ // importing it just for one fallback string.
414
+ const resolvedCurrency = entity.defaultCurrency ?? "EUR";
415
+ const selectHints = deriveSelectFieldHints(fieldDef, translate, featureName, screen.entity, normalized.field, values);
416
+ const textHints = deriveTextFieldHints(fieldDef);
417
+ const dateHints = deriveDateFieldHints(fieldDef);
418
+ const numericHints = deriveNumericFieldHints(fieldDef, resolvedCurrency);
419
+ const referenceHints = deriveReferenceFieldHints(fieldDef, normalized, declaredRefTarget, featureName);
420
+ const fileHints = deriveFileFieldHints(fieldDef, screen.entity, normalized.field, entityId);
421
+ const embeddedListHints = deriveEmbeddedListHints(fieldDef, translate, featureName, screen.entity, normalized.field, resolvedCurrency, normalized.embeddedList);
422
+ const view = {
423
+ field: normalized.field,
424
+ label,
425
+ type: effectiveType,
426
+ value: values[normalized.field],
427
+ visible,
428
+ readOnly,
429
+ required,
430
+ ...(normalized.span !== undefined && { span: normalized.span }),
431
+ ...(normalized.renderer !== undefined && { renderer: normalized.renderer }),
432
+ ...selectHints,
433
+ ...textHints,
434
+ ...dateHints,
435
+ ...numericHints,
436
+ ...referenceHints,
437
+ ...fileHints,
438
+ ...(normalized.icon !== undefined && { icon: normalized.icon }),
439
+ ...deriveFieldAffixHints(normalized, translate),
440
+ ...embeddedListHints,
441
+ };
442
+ return view;
443
+ });
444
+ // The boot-validator rejects declared-empty sections (screens.ts), but a
445
+ // create-excluded field list can still empty one here: then `visible` is false.
446
+ const visible = fields.some((field) => field.visible);
447
+ // Tabs mode renders this section as its own panel, where two columns reads
448
+ // better than the single-column default a stacked form keeps. Applies to
449
+ // entityEdit tabs as well since fw#3134, not just projectionDetail.
450
+ const defaultColumns = screen.layout.mode === "tabs" ? 2 : 1;
451
+ const groups = sectionSpec.groups
452
+ ?.map((group) => ({ ...group, fields: group.fields.filter((f) => !isHiddenByExclusion(f)) }))
453
+ .filter((group) => group.fields.length > 0)
454
+ .map((group) => ({
455
+ title: translate(group.title),
456
+ columns: group.columns ?? 2,
457
+ fields: group.fields.map((fieldSpec) => {
458
+ const fieldName = normalizeEditField(fieldSpec).field;
459
+ const fieldView = fields.find((f) => f.field === fieldName);
460
+ if (fieldView === undefined) {
461
+ throw new Error(`computeEditViewModel: screen "${screen.id}" group "${group.title}" references field ` +
462
+ `"${fieldName}" that failed to resolve.`);
463
+ }
464
+ return fieldView;
465
+ }),
466
+ }));
467
+ return {
468
+ kind: "fields",
469
+ ...(sectionSpec.id !== undefined && { id: sectionSpec.id }),
470
+ visible,
471
+ emptiedByWriteExclusion: wasEmptiedByWriteExclusion(declaredFieldSpecs, fields),
472
+ // Untitled section (flat form) → no h3; translate only when set.
473
+ ...(sectionSpec.title !== undefined && { title: translate(sectionSpec.title) }),
474
+ ...(sectionSpec.description !== undefined && {
475
+ description: translate(sectionSpec.description),
476
+ }),
477
+ ...(sectionSpec.subtitle !== undefined && { subtitle: translate(sectionSpec.subtitle) }),
478
+ columns: sectionSpec.columns ?? defaultColumns,
479
+ fields,
480
+ ...(groups !== undefined && { groups }),
481
+ ...(sectionSpec.icon !== undefined && { icon: sectionSpec.icon }),
482
+ ...(sectionSpec.actions !== undefined && { actions: sectionSpec.actions }),
483
+ };
484
+ });
485
+ const idValue = values["id"];
486
+ const id = typeof idValue === "string" ? idValue : null;
487
+ return {
488
+ screenId: screen.id,
489
+ entityName: screen.entity,
490
+ id,
491
+ sections,
492
+ ...(screen.slots && { slots: screen.slots }),
493
+ };
494
+ }
495
+ // Resolves a FieldCondition against the current row values.
496
+ // `undefined` means "not declared" — caller substitutes the default.
497
+ function evalCondition(condition, fallback, values) {
498
+ if (condition === undefined)
499
+ return fallback;
500
+ return evalFieldCondition(condition, values);
501
+ }
@@ -0,0 +1,27 @@
1
+ import type { EmbeddedDerivedCellDef } from "@cosmicdrift/kumiko-framework/ui-types";
2
+ import type { FieldIssue } from "../dispatcher/index.ts";
3
+ export type EmbeddedDerivedOp = EmbeddedDerivedCellDef["op"];
4
+ export type { DerivedCellRoundingTarget } from "@cosmicdrift/kumiko-framework/ui-types";
5
+ export { computeDerivedCellValue, roundDerivedCellValue, } from "@cosmicdrift/kumiko-framework/ui-types";
6
+ /** Sums a numeric/money/decimal column across all rows. Non-numeric or
7
+ * missing values count as 0. Money columns are minor-unit integers —
8
+ * the sum stays in minor units, never rounds through a major-unit float. */
9
+ export declare function sumEmbeddedListColumn(rows: readonly Readonly<Record<string, unknown>>[], field: string): number;
10
+ export type EmbeddedListIssueGroups = {
11
+ /** Issues at exactly `listField` — e.g. min/max row-count violations. */
12
+ readonly listIssues: readonly FieldIssue[];
13
+ /** Issues at exactly `${listField}.${rowIndex}` — a row-level check
14
+ * (e.g. "row incomplete") that isn't attributable to one cell. */
15
+ readonly rowIssues: Readonly<Record<number, readonly FieldIssue[]>>;
16
+ /** Issues at exactly `${listField}.${rowIndex}.${cellField}`, keyed
17
+ * `${rowIndex}.${cellField}` (not the full path — the caller already
18
+ * knows listField). */
19
+ readonly cellIssues: Readonly<Record<string, readonly FieldIssue[]>>;
20
+ };
21
+ /** Buckets a flat issues-by-path map (FormSnapshot.errors shape — see
22
+ * packages/renderer/src/headless/form/zod-bridge.ts groupIssuesByPath) into the
23
+ * three levels an embedded-list widget renders. Only keys that are
24
+ * exactly `listField`, `listField.N`, or `listField.N.subfield` are
25
+ * claimed; unrelated keys (other top-level fields, or deeper nesting
26
+ * than this field ever produces) are ignored. */
27
+ export declare function groupEmbeddedListIssues(allIssues: Readonly<Record<string, readonly FieldIssue[]>>, listField: string): EmbeddedListIssueGroups;
@@ -0,0 +1,63 @@
1
+ // Canonical implementation moved to packages/framework/src/engine/embedded-derived.ts
2
+ // (the write-schema preprocess needs it server-side too).
3
+ export { computeDerivedCellValue, roundDerivedCellValue, } from "@cosmicdrift/kumiko-framework/ui-types";
4
+ /** Sums a numeric/money/decimal column across all rows. Non-numeric or
5
+ * missing values count as 0. Money columns are minor-unit integers —
6
+ * the sum stays in minor units, never rounds through a major-unit float. */
7
+ export function sumEmbeddedListColumn(rows, field) {
8
+ let sum = 0;
9
+ for (const row of rows) {
10
+ const value = row[field];
11
+ if (typeof value === "number" && Number.isFinite(value))
12
+ sum += value;
13
+ }
14
+ return sum;
15
+ }
16
+ /** Buckets a flat issues-by-path map (FormSnapshot.errors shape — see
17
+ * packages/renderer/src/headless/form/zod-bridge.ts groupIssuesByPath) into the
18
+ * three levels an embedded-list widget renders. Only keys that are
19
+ * exactly `listField`, `listField.N`, or `listField.N.subfield` are
20
+ * claimed; unrelated keys (other top-level fields, or deeper nesting
21
+ * than this field ever produces) are ignored. */
22
+ export function groupEmbeddedListIssues(allIssues, listField) {
23
+ const listIssues = [];
24
+ const rowIssues = {};
25
+ const cellIssues = {};
26
+ const prefix = `${listField}.`;
27
+ for (const [path, issues] of Object.entries(allIssues)) {
28
+ if (path === listField) {
29
+ listIssues.push(...issues);
30
+ continue;
31
+ }
32
+ if (!path.startsWith(prefix))
33
+ continue;
34
+ const rest = path.slice(prefix.length);
35
+ const segments = rest.split(".");
36
+ if (segments.length === 1) {
37
+ const rowIndex = parsePureRowIndex(segments[0]);
38
+ if (rowIndex === undefined)
39
+ continue;
40
+ rowIssues[rowIndex] = issues;
41
+ continue;
42
+ }
43
+ if (segments.length === 2) {
44
+ const rowIndex = parsePureRowIndex(segments[0]);
45
+ if (rowIndex === undefined)
46
+ continue;
47
+ const cellField = segments[1];
48
+ cellIssues[`${rowIndex}.${cellField}`] = issues;
49
+ }
50
+ // Deeper than `listField.N.subfield` — not a shape this field ever
51
+ // produces; ignore rather than misattribute to a cell.
52
+ }
53
+ return { listIssues, rowIssues, cellIssues };
54
+ }
55
+ function parsePureRowIndex(segment) {
56
+ if (segment === undefined || segment.length === 0)
57
+ return undefined;
58
+ for (const char of segment) {
59
+ if (char < "0" || char > "9")
60
+ return undefined;
61
+ }
62
+ return Number(segment);
63
+ }
@@ -0,0 +1,7 @@
1
+ export type { ComputeEditViewModelInput, EditFormMode } from "./edit.ts";
2
+ export { computeEditViewModel, computeRelatedListSectionViewModel } from "./edit.ts";
3
+ export type { DerivedCellRoundingTarget, EmbeddedDerivedOp, EmbeddedListIssueGroups, } from "./embedded-list.ts";
4
+ export { computeDerivedCellValue, groupEmbeddedListIssues, roundDerivedCellValue, sumEmbeddedListColumn, } from "./embedded-list.ts";
5
+ export type { ComputeListViewModelInput } from "./list.ts";
6
+ export { buildOptionLabels, computeListViewModel, embeddedCellLabelKey, embeddedCellOptionLabelKey, fieldLabelKey, fieldOptionLabelKey, fieldOptionLabelKeyPrefix, } from "./list.ts";
7
+ export type { CellLink, CellLinkItem, EditExtensionSectionViewModel, EditFieldSpec, EditFieldsSectionViewModel, EditFieldViewModel, EditRelatedListSectionViewModel, EditSectionSpec, EditSectionViewModel, EditViewModel, EditWriteFormSectionViewModel, EmbeddedListCellViewModel, FieldConditionCtx, FieldRenderer, ListColumnFileDisplay, ListColumnSpec, ListColumnViewModel, ListRowViewModel, ListViewModel, RuntimeCellLink, RuntimeCellLinkItems, RuntimeRenderer, ScreenSlots, Translate, } from "./types.ts";
@@ -0,0 +1,3 @@
1
+ export { computeEditViewModel, computeRelatedListSectionViewModel } from "./edit.js";
2
+ export { computeDerivedCellValue, groupEmbeddedListIssues, roundDerivedCellValue, sumEmbeddedListColumn, } from "./embedded-list.js";
3
+ export { buildOptionLabels, computeListViewModel, embeddedCellLabelKey, embeddedCellOptionLabelKey, fieldLabelKey, fieldOptionLabelKey, fieldOptionLabelKeyPrefix, } from "./list.js";
@@ -0,0 +1,3 @@
1
+ import type { FieldDefinition } from "@cosmicdrift/kumiko-framework/ui-types";
2
+ import type { ListColumnFileDisplay, ListColumnViewModel } from "./types.ts";
3
+ export declare function deriveListFileDisplay(fieldDef: FieldDefinition, renderer: ListColumnViewModel["renderer"]): ListColumnFileDisplay | undefined;
@@ -0,0 +1,27 @@
1
+ function firstVariantKey(fieldDef) {
2
+ return Object.keys(fieldDef.variants ?? {})[0];
3
+ }
4
+ function fromFormatSpec(renderer) {
5
+ if (typeof renderer !== "object" || renderer === null || !("format" in renderer)) {
6
+ return undefined;
7
+ }
8
+ if (renderer.format === "file")
9
+ return { kind: "file" };
10
+ if (renderer.format !== "image")
11
+ return undefined;
12
+ return renderer.variant === undefined
13
+ ? { kind: "image" }
14
+ : { kind: "image", variant: renderer.variant };
15
+ }
16
+ function fromFieldType(fieldDef) {
17
+ if (fieldDef.type === "file" || fieldDef.type === "files")
18
+ return { kind: "file" };
19
+ if (fieldDef.type !== "image" && fieldDef.type !== "images")
20
+ return undefined;
21
+ const variant = firstVariantKey(fieldDef);
22
+ return variant === undefined ? { kind: "image" } : { kind: "image", variant };
23
+ }
24
+ // An explicit `{ format: "image" | "file" }` renderer wins over the field type.
25
+ export function deriveListFileDisplay(fieldDef, renderer) {
26
+ return fromFormatSpec(renderer) ?? fromFieldType(fieldDef);
27
+ }
@@ -0,0 +1,16 @@
1
+ import type { EntityDefinition, EntityListScreenDefinition } from "@cosmicdrift/kumiko-framework/ui-types";
2
+ import type { ListViewModel, Translate } from "./types.ts";
3
+ export type ComputeListViewModelInput = {
4
+ readonly screen: EntityListScreenDefinition;
5
+ readonly entity: EntityDefinition;
6
+ readonly rows: readonly Readonly<Record<string, unknown>>[];
7
+ readonly translate: Translate;
8
+ readonly featureName: string;
9
+ };
10
+ export declare function computeListViewModel(input: ComputeListViewModelInput): ListViewModel;
11
+ export declare function fieldLabelKey(featureName: string, entityName: string, fieldName: string): string;
12
+ export declare function fieldOptionLabelKeyPrefix(featureName: string, entityName: string, fieldName: string): string;
13
+ export declare function fieldOptionLabelKey(featureName: string, entityName: string, fieldName: string, value: string): string;
14
+ export declare function embeddedCellLabelKey(featureName: string, entityName: string, fieldName: string, subFieldName: string): string;
15
+ export declare function embeddedCellOptionLabelKey(featureName: string, entityName: string, fieldName: string, subFieldName: string, value: string): string;
16
+ export declare function buildOptionLabels(translate: (key: string, params?: Readonly<Record<string, unknown>>) => string, keyFor: (value: string) => string, options: readonly string[]): Readonly<Record<string, string>>;