@cosmicdrift/kumiko-renderer 0.374.0 → 0.378.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 (477) hide show
  1. package/README.md +2 -2
  2. package/dist/app/action-form-support.d.ts +9 -2
  3. package/dist/app/action-form-support.js +24 -2
  4. package/dist/app/client-actions.d.ts +2 -2
  5. package/dist/app/column-renderers.js +1 -1
  6. package/dist/app/config-edit-shim.js +1 -1
  7. package/dist/app/content-preview.js +1 -6
  8. package/dist/app/custom-screens.js +1 -1
  9. package/dist/app/dashboard-body.d.ts +1 -1
  10. package/dist/app/entity-list-expanded-row.d.ts +1 -1
  11. package/dist/app/form-schema.d.ts +1 -1
  12. package/dist/app/form-schema.js +2 -2
  13. package/dist/app/kumiko-screen.d.ts +1 -1
  14. package/dist/app/kumiko-screen.js +10 -7
  15. package/dist/app/list-empty-content.d.ts +1 -1
  16. package/dist/app/list-facets.d.ts +1 -1
  17. package/dist/app/nav.js +2 -2
  18. package/dist/app/query-state-banners.d.ts +1 -1
  19. package/dist/app/reference-link.d.ts +1 -1
  20. package/dist/app/row-actions.d.ts +1 -1
  21. package/dist/app/secret-mint-body.d.ts +1 -1
  22. package/dist/app/secrets-edit-body.d.ts +1 -1
  23. package/dist/app/use-record-actions.d.ts +1 -1
  24. package/dist/app/write-failed-error.d.ts +1 -1
  25. package/dist/components/availability-options-select.d.ts +1 -1
  26. package/dist/components/embedded-list-field.d.ts +1 -1
  27. package/dist/components/embedded-list-field.js +1 -1
  28. package/dist/components/file-list-field.d.ts +1 -1
  29. package/dist/components/form-derivation-patch.d.ts +8 -0
  30. package/dist/components/form-derivation-patch.js +24 -0
  31. package/dist/components/form-screen-layout.d.ts +13 -0
  32. package/dist/components/form-screen-layout.js +13 -0
  33. package/dist/components/grid-cell-for-field.d.ts +1 -1
  34. package/dist/components/multi-select-checkboxes.d.ts +1 -1
  35. package/dist/components/multi-select-checkboxes.js +1 -1
  36. package/dist/components/query-options-select.d.ts +1 -1
  37. package/dist/components/related-list-section.d.ts +1 -1
  38. package/dist/components/render-edit-logic.d.ts +1 -1
  39. package/dist/components/render-edit-types.d.ts +6 -3
  40. package/dist/components/render-edit.d.ts +1 -1
  41. package/dist/components/render-edit.js +18 -3
  42. package/dist/components/render-field.d.ts +1 -1
  43. package/dist/components/render-field.js +12 -2
  44. package/dist/components/render-list.d.ts +1 -1
  45. package/dist/components/render-list.js +20 -4
  46. package/dist/components/write-form-section.d.ts +1 -1
  47. package/dist/components/write-form-section.js +1 -1
  48. package/dist/context/dispatcher-context.d.ts +1 -1
  49. package/dist/file-ids-of.d.ts +1 -0
  50. package/dist/file-ids-of.js +7 -0
  51. package/dist/flow-diagram/icons.d.ts +3 -0
  52. package/dist/flow-diagram/icons.js +14 -0
  53. package/dist/flow-diagram/index.d.ts +2 -0
  54. package/dist/flow-diagram/index.js +1 -0
  55. package/dist/flow-diagram/render.d.ts +3 -0
  56. package/dist/flow-diagram/render.js +234 -0
  57. package/dist/flow-diagram/types.d.ts +18 -0
  58. package/dist/flow-diagram/types.js +1 -0
  59. package/dist/format-when.js +1 -1
  60. package/dist/headless/apex/css.d.ts +3 -0
  61. package/dist/headless/apex/css.js +298 -0
  62. package/dist/headless/apex/index.d.ts +236 -0
  63. package/dist/headless/apex/index.js +377 -0
  64. package/dist/headless/apex/lightbox.d.ts +4 -0
  65. package/dist/headless/apex/lightbox.js +81 -0
  66. package/dist/headless/contracts/asset.d.ts +15 -0
  67. package/dist/headless/contracts/asset.js +17 -0
  68. package/dist/headless/contracts/index.d.ts +3 -0
  69. package/dist/headless/contracts/index.js +1 -0
  70. package/dist/headless/contracts/locale.d.ts +7 -0
  71. package/dist/headless/contracts/locale.js +11 -0
  72. package/dist/headless/contracts/primitives.d.ts +93 -0
  73. package/dist/headless/contracts/primitives.js +21 -0
  74. package/dist/headless/dispatcher/index.d.ts +2 -0
  75. package/dist/headless/dispatcher/index.js +1 -0
  76. package/dist/headless/dispatcher/types.d.ts +86 -0
  77. package/dist/headless/dispatcher/types.js +34 -0
  78. package/dist/headless/form/form-controller.d.ts +2 -0
  79. package/dist/headless/form/form-controller.js +409 -0
  80. package/dist/headless/form/index.d.ts +3 -0
  81. package/dist/headless/form/index.js +2 -0
  82. package/dist/headless/form/types.d.ts +76 -0
  83. package/dist/headless/form/types.js +1 -0
  84. package/dist/headless/form/zod-bridge.d.ts +10 -0
  85. package/dist/headless/form/zod-bridge.js +103 -0
  86. package/dist/headless/format/document-values.d.ts +12 -0
  87. package/dist/headless/format/document-values.js +70 -0
  88. package/dist/headless/format/escape.d.ts +5 -0
  89. package/dist/headless/format/escape.js +75 -0
  90. package/dist/headless/format/html-template.d.ts +9 -0
  91. package/dist/headless/format/html-template.js +39 -0
  92. package/dist/headless/format/index.d.ts +12 -0
  93. package/dist/headless/format/index.js +237 -0
  94. package/dist/headless/format/money.d.ts +3 -0
  95. package/dist/headless/format/money.js +39 -0
  96. package/dist/headless/index.d.ts +14 -0
  97. package/dist/headless/index.js +9 -0
  98. package/dist/headless/locale-routing/index.d.ts +41 -0
  99. package/dist/headless/locale-routing/index.js +145 -0
  100. package/dist/headless/nav/index.d.ts +2 -0
  101. package/dist/headless/nav/index.js +1 -0
  102. package/dist/headless/nav/resolve.d.ts +2 -0
  103. package/dist/headless/nav/resolve.js +71 -0
  104. package/dist/headless/nav/types.d.ts +26 -0
  105. package/dist/headless/nav/types.js +1 -0
  106. package/dist/headless/store/create-store.d.ts +2 -0
  107. package/dist/headless/store/create-store.js +43 -0
  108. package/dist/headless/store/equality.d.ts +1 -0
  109. package/dist/headless/store/equality.js +34 -0
  110. package/dist/headless/store/index.d.ts +3 -0
  111. package/dist/headless/store/index.js +2 -0
  112. package/dist/headless/store/types.d.ts +7 -0
  113. package/dist/headless/store/types.js +10 -0
  114. package/dist/headless/view-model/edit.d.ts +21 -0
  115. package/dist/headless/view-model/edit.js +512 -0
  116. package/dist/headless/view-model/embedded-list.d.ts +27 -0
  117. package/dist/headless/view-model/embedded-list.js +63 -0
  118. package/dist/headless/view-model/index.d.ts +7 -0
  119. package/dist/headless/view-model/index.js +3 -0
  120. package/dist/headless/view-model/list-file-display.d.ts +3 -0
  121. package/dist/headless/view-model/list-file-display.js +27 -0
  122. package/dist/headless/view-model/list.d.ts +16 -0
  123. package/dist/headless/view-model/list.js +229 -0
  124. package/dist/headless/view-model/types.d.ts +382 -0
  125. package/dist/headless/view-model/types.js +1 -0
  126. package/dist/hooks/use-ai-text.d.ts +1 -1
  127. package/dist/hooks/use-form.d.ts +1 -1
  128. package/dist/hooks/use-form.js +1 -1
  129. package/dist/hooks/use-mutation.d.ts +1 -1
  130. package/dist/hooks/use-query.d.ts +1 -1
  131. package/dist/hooks/use-store.d.ts +1 -1
  132. package/dist/hooks/use-store.js +7 -7
  133. package/dist/hooks/use-stream-handler.d.ts +1 -1
  134. package/dist/i18n-defaults.js +6 -0
  135. package/dist/i18n.d.ts +1 -1
  136. package/dist/i18n.js +1 -1
  137. package/dist/index.d.ts +3 -1
  138. package/dist/index.js +5 -4
  139. package/dist/live/csrf.d.ts +2 -0
  140. package/dist/live/csrf.js +60 -0
  141. package/dist/live/dispatcher-live.d.ts +7 -0
  142. package/dist/live/dispatcher-live.js +286 -0
  143. package/dist/live/envelopes.d.ts +101 -0
  144. package/dist/live/envelopes.js +35 -0
  145. package/dist/live/error-mapping.d.ts +16 -0
  146. package/dist/live/error-mapping.js +82 -0
  147. package/dist/live/index.d.ts +7 -0
  148. package/dist/live/index.js +5 -0
  149. package/dist/live/locale.d.ts +2 -0
  150. package/dist/live/locale.js +25 -0
  151. package/dist/live/sse-stream.d.ts +14 -0
  152. package/dist/live/sse-stream.js +128 -0
  153. package/dist/primitives.d.ts +45 -36
  154. package/dist/primitives.js +1 -1
  155. package/dist/session/session-ended.d.ts +1 -1
  156. package/dist/tokens.d.ts +3 -4
  157. package/dist/tokens.js +4 -5
  158. package/dist/web/app/app-schema-boot.d.ts +19 -0
  159. package/dist/web/app/app-schema-boot.js +124 -0
  160. package/dist/web/app/browser-locale.d.ts +22 -0
  161. package/dist/web/app/browser-locale.js +78 -0
  162. package/dist/web/app/client-plugin.d.ts +106 -0
  163. package/dist/web/app/client-plugin.js +12 -0
  164. package/dist/web/app/create-app.d.ts +104 -0
  165. package/dist/web/app/create-app.js +498 -0
  166. package/dist/web/app/create-public-surface.d.ts +36 -0
  167. package/dist/web/app/create-public-surface.js +40 -0
  168. package/dist/web/app/dashboard-body.d.ts +3 -0
  169. package/dist/web/app/dashboard-body.js +865 -0
  170. package/dist/web/app/dashboard-refresh.d.ts +6 -0
  171. package/dist/web/app/dashboard-refresh.js +15 -0
  172. package/dist/web/app/document-lang-sync.d.ts +4 -0
  173. package/dist/web/app/document-lang-sync.js +27 -0
  174. package/dist/web/app/draft-storage.d.ts +11 -0
  175. package/dist/web/app/draft-storage.js +53 -0
  176. package/dist/web/app/nav-providers-context.d.ts +13 -0
  177. package/dist/web/app/nav-providers-context.js +18 -0
  178. package/dist/web/app/nav.d.ts +40 -0
  179. package/dist/web/app/nav.js +231 -0
  180. package/dist/web/app/plain-content-editor.d.ts +3 -0
  181. package/dist/web/app/plain-content-editor.js +30 -0
  182. package/dist/web/app/relative-time.d.ts +10 -0
  183. package/dist/web/app/relative-time.js +56 -0
  184. package/dist/web/app/resolvers-context.d.ts +12 -0
  185. package/dist/web/app/resolvers-context.js +10 -0
  186. package/dist/web/app/rich-content-editor.d.ts +3 -0
  187. package/dist/web/app/rich-content-editor.js +15 -0
  188. package/dist/web/app/root-error-fallback.d.ts +2 -0
  189. package/dist/web/app/root-error-fallback.js +21 -0
  190. package/dist/web/app/screen-error-fallback.d.ts +6 -0
  191. package/dist/web/app/screen-error-fallback.js +17 -0
  192. package/dist/web/app/tiptap-editor.d.ts +3 -0
  193. package/dist/web/app/tiptap-editor.js +120 -0
  194. package/dist/web/app/toast-action-notifier.d.ts +5 -0
  195. package/dist/web/app/toast-action-notifier.js +17 -0
  196. package/dist/web/components/config-cascade.d.ts +13 -0
  197. package/dist/web/components/config-cascade.js +155 -0
  198. package/dist/web/components/config-source-badge.d.ts +6 -0
  199. package/dist/web/components/config-source-badge.js +55 -0
  200. package/dist/web/default-color-scheme.d.ts +2 -0
  201. package/dist/web/default-color-scheme.js +3 -0
  202. package/dist/web/icons.d.ts +94 -0
  203. package/dist/web/icons.js +100 -0
  204. package/dist/web/index.d.ts +78 -0
  205. package/dist/web/index.js +53 -0
  206. package/dist/web/layout/app-layout.d.ts +21 -0
  207. package/dist/web/layout/app-layout.js +8 -0
  208. package/dist/web/layout/avatar.d.ts +12 -0
  209. package/dist/web/layout/avatar.js +63 -0
  210. package/dist/web/layout/default-app-shell.d.ts +41 -0
  211. package/dist/web/layout/default-app-shell.js +16 -0
  212. package/dist/web/layout/editor-panel.d.ts +10 -0
  213. package/dist/web/layout/editor-panel.js +29 -0
  214. package/dist/web/layout/fill-classes.d.ts +9 -0
  215. package/dist/web/layout/fill-classes.js +15 -0
  216. package/dist/web/layout/filter-app-schema-navs.d.ts +7 -0
  217. package/dist/web/layout/filter-app-schema-navs.js +68 -0
  218. package/dist/web/layout/header-action-group.d.ts +6 -0
  219. package/dist/web/layout/header-action-group.js +8 -0
  220. package/dist/web/layout/header-overflow-menu.d.ts +4 -0
  221. package/dist/web/layout/header-overflow-menu.js +8 -0
  222. package/dist/web/layout/language-menu-items.d.ts +8 -0
  223. package/dist/web/layout/language-menu-items.js +16 -0
  224. package/dist/web/layout/language-switcher.d.ts +25 -0
  225. package/dist/web/layout/language-switcher.js +46 -0
  226. package/dist/web/layout/nav-tree.d.ts +19 -0
  227. package/dist/web/layout/nav-tree.js +536 -0
  228. package/dist/web/layout/page-header-slot.d.ts +25 -0
  229. package/dist/web/layout/page-header-slot.js +50 -0
  230. package/dist/web/layout/profile-menu.d.ts +13 -0
  231. package/dist/web/layout/profile-menu.js +6 -0
  232. package/dist/web/layout/shell-breadcrumb.d.ts +11 -0
  233. package/dist/web/layout/shell-breadcrumb.js +34 -0
  234. package/dist/web/layout/shell-header.d.ts +12 -0
  235. package/dist/web/layout/shell-header.js +159 -0
  236. package/dist/web/layout/sidebar-brand.d.ts +15 -0
  237. package/dist/web/layout/sidebar-brand.js +9 -0
  238. package/dist/web/layout/sidebar-panel.d.ts +41 -0
  239. package/dist/web/layout/sidebar-panel.js +107 -0
  240. package/dist/web/layout/sidebar-user.d.ts +8 -0
  241. package/dist/web/layout/sidebar-user.js +17 -0
  242. package/dist/web/layout/sidebar.d.ts +17 -0
  243. package/dist/web/layout/sidebar.js +11 -0
  244. package/dist/web/layout/target-resolver-stub.d.ts +13 -0
  245. package/dist/web/layout/target-resolver-stub.js +61 -0
  246. package/dist/web/layout/target-url.d.ts +12 -0
  247. package/dist/web/layout/target-url.js +77 -0
  248. package/dist/web/layout/theme-label.d.ts +15 -0
  249. package/dist/web/layout/theme-label.js +35 -0
  250. package/dist/web/layout/theme-menu-item.d.ts +12 -0
  251. package/dist/web/layout/theme-menu-item.js +16 -0
  252. package/dist/web/layout/theme-toggle.d.ts +17 -0
  253. package/dist/web/layout/theme-toggle.js +22 -0
  254. package/dist/web/layout/topbar.d.ts +8 -0
  255. package/dist/web/layout/topbar.js +4 -0
  256. package/dist/web/layout/workspace-shell.d.ts +63 -0
  257. package/dist/web/layout/workspace-shell.js +220 -0
  258. package/dist/web/layout/workspace-switcher.d.ts +15 -0
  259. package/dist/web/layout/workspace-switcher.js +36 -0
  260. package/dist/web/lib/accept-attr.d.ts +1 -0
  261. package/dist/web/lib/accept-attr.js +6 -0
  262. package/dist/web/lib/clamp.d.ts +1 -0
  263. package/dist/web/lib/clamp.js +3 -0
  264. package/dist/web/lib/cn.d.ts +6 -0
  265. package/dist/web/lib/cn.js +9 -0
  266. package/dist/web/lib/download.d.ts +2 -0
  267. package/dist/web/lib/download.js +24 -0
  268. package/dist/web/lib/file-ref-download.d.ts +15 -0
  269. package/dist/web/lib/file-ref-download.js +62 -0
  270. package/dist/web/lib/file-upload-form-data.d.ts +7 -0
  271. package/dist/web/lib/file-upload-form-data.js +11 -0
  272. package/dist/web/lib/resize-image.d.ts +1 -0
  273. package/dist/web/lib/resize-image.js +66 -0
  274. package/dist/web/lib/upload-file-ref.d.ts +9 -0
  275. package/dist/web/lib/upload-file-ref.js +29 -0
  276. package/dist/web/primitives/action-menu.d.ts +34 -0
  277. package/dist/web/primitives/action-menu.js +30 -0
  278. package/dist/web/primitives/calendar-popover.d.ts +13 -0
  279. package/dist/web/primitives/calendar-popover.js +76 -0
  280. package/dist/web/primitives/combobox.d.ts +56 -0
  281. package/dist/web/primitives/combobox.js +127 -0
  282. package/dist/web/primitives/date-field.d.ts +18 -0
  283. package/dist/web/primitives/date-field.js +74 -0
  284. package/dist/web/primitives/date-input.d.ts +1 -0
  285. package/dist/web/primitives/date-input.js +5 -0
  286. package/dist/web/primitives/date-parse.d.ts +11 -0
  287. package/dist/web/primitives/date-parse.js +159 -0
  288. package/dist/web/primitives/dialog.d.ts +3 -0
  289. package/dist/web/primitives/dialog.js +42 -0
  290. package/dist/web/primitives/drawer.d.ts +3 -0
  291. package/dist/web/primitives/drawer.js +17 -0
  292. package/dist/web/primitives/dropdown-menu.d.ts +15 -0
  293. package/dist/web/primitives/dropdown-menu.js +56 -0
  294. package/dist/web/primitives/embedded-list-input.d.ts +9 -0
  295. package/dist/web/primitives/embedded-list-input.js +382 -0
  296. package/dist/web/primitives/file-thumbnail.d.ts +31 -0
  297. package/dist/web/primitives/file-thumbnail.js +90 -0
  298. package/dist/web/primitives/file-upload.d.ts +21 -0
  299. package/dist/web/primitives/file-upload.js +56 -0
  300. package/dist/web/primitives/file-value-list.d.ts +3 -0
  301. package/dist/web/primitives/file-value-list.js +22 -0
  302. package/dist/web/primitives/index.d.ts +34 -0
  303. package/dist/web/primitives/index.js +2023 -0
  304. package/dist/web/primitives/json-view.d.ts +7 -0
  305. package/dist/web/primitives/json-view.js +84 -0
  306. package/dist/web/primitives/layout.d.ts +27 -0
  307. package/dist/web/primitives/layout.js +30 -0
  308. package/dist/web/primitives/lightbox.d.ts +3 -0
  309. package/dist/web/primitives/lightbox.js +36 -0
  310. package/dist/web/primitives/locale-number.d.ts +2 -0
  311. package/dist/web/primitives/locale-number.js +54 -0
  312. package/dist/web/primitives/located-timestamp-input.d.ts +22 -0
  313. package/dist/web/primitives/located-timestamp-input.js +22 -0
  314. package/dist/web/primitives/metric.d.ts +5 -0
  315. package/dist/web/primitives/metric.js +18 -0
  316. package/dist/web/primitives/modal-shell.d.ts +17 -0
  317. package/dist/web/primitives/modal-shell.js +9 -0
  318. package/dist/web/primitives/modal.d.ts +3 -0
  319. package/dist/web/primitives/modal.js +13 -0
  320. package/dist/web/primitives/money-input.d.ts +18 -0
  321. package/dist/web/primitives/money-input.js +122 -0
  322. package/dist/web/primitives/narrow-pinned-footer.d.ts +12 -0
  323. package/dist/web/primitives/narrow-pinned-footer.js +153 -0
  324. package/dist/web/primitives/number-input.d.ts +18 -0
  325. package/dist/web/primitives/number-input.js +53 -0
  326. package/dist/web/primitives/option-groups.d.ts +11 -0
  327. package/dist/web/primitives/option-groups.js +27 -0
  328. package/dist/web/primitives/page-header.d.ts +3 -0
  329. package/dist/web/primitives/page-header.js +52 -0
  330. package/dist/web/primitives/promo-panel.d.ts +3 -0
  331. package/dist/web/primitives/promo-panel.js +11 -0
  332. package/dist/web/primitives/segmented-select.d.ts +21 -0
  333. package/dist/web/primitives/segmented-select.js +62 -0
  334. package/dist/web/primitives/share-actions.d.ts +4 -0
  335. package/dist/web/primitives/share-actions.js +56 -0
  336. package/dist/web/primitives/status-badge.d.ts +3 -0
  337. package/dist/web/primitives/status-badge.js +5 -0
  338. package/dist/web/primitives/sticky-action-bar.d.ts +5 -0
  339. package/dist/web/primitives/sticky-action-bar.js +15 -0
  340. package/dist/web/primitives/tabs.d.ts +3 -0
  341. package/dist/web/primitives/tabs.js +107 -0
  342. package/dist/web/primitives/timestamp-input.d.ts +27 -0
  343. package/dist/web/primitives/timestamp-input.js +87 -0
  344. package/dist/web/primitives/toast.d.ts +19 -0
  345. package/dist/web/primitives/toast.js +63 -0
  346. package/dist/web/primitives/tz-input.d.ts +11 -0
  347. package/dist/web/primitives/tz-input.js +8 -0
  348. package/dist/web/primitives/tz-options.d.ts +4 -0
  349. package/dist/web/primitives/tz-options.js +17 -0
  350. package/dist/web/primitives/use-keyboard-inset.d.ts +1 -0
  351. package/dist/web/primitives/use-keyboard-inset.js +28 -0
  352. package/dist/web/primitives/use-narrow-viewport.d.ts +4 -0
  353. package/dist/web/primitives/use-narrow-viewport.js +46 -0
  354. package/dist/web/react-css-custom-properties.d.ts +6 -0
  355. package/dist/web/react-css-custom-properties.js +1 -0
  356. package/dist/web/sse/live-events.d.ts +15 -0
  357. package/dist/web/sse/live-events.js +148 -0
  358. package/dist/web/theme-plugin.d.ts +41 -0
  359. package/dist/web/theme-plugin.js +123 -0
  360. package/dist/web/tokens.d.ts +24 -0
  361. package/dist/web/tokens.js +203 -0
  362. package/dist/web/ui/avatar.d.ts +11 -0
  363. package/dist/web/ui/avatar.js +25 -0
  364. package/dist/web/ui/badge.d.ts +9 -0
  365. package/dist/web/ui/badge.js +26 -0
  366. package/dist/web/ui/breadcrumb.d.ts +11 -0
  367. package/dist/web/ui/breadcrumb.js +29 -0
  368. package/dist/web/ui/button.d.ts +10 -0
  369. package/dist/web/ui/button.js +37 -0
  370. package/dist/web/ui/checkbox.d.ts +4 -0
  371. package/dist/web/ui/checkbox.js +11 -0
  372. package/dist/web/ui/input.d.ts +3 -0
  373. package/dist/web/ui/input.js +8 -0
  374. package/dist/web/ui/label.d.ts +4 -0
  375. package/dist/web/ui/label.js +10 -0
  376. package/dist/web/ui/resizable.d.ts +7 -0
  377. package/dist/web/ui/resizable.js +16 -0
  378. package/dist/web/ui/separator.d.ts +4 -0
  379. package/dist/web/ui/separator.js +10 -0
  380. package/dist/web/ui/sheet.d.ts +14 -0
  381. package/dist/web/ui/sheet.js +42 -0
  382. package/dist/web/ui/sidebar.d.ts +73 -0
  383. package/dist/web/ui/sidebar.js +211 -0
  384. package/dist/web/ui/skeleton.d.ts +2 -0
  385. package/dist/web/ui/skeleton.js +7 -0
  386. package/dist/web/ui/switch.d.ts +6 -0
  387. package/dist/web/ui/switch.js +10 -0
  388. package/dist/web/ui/table.d.ts +10 -0
  389. package/dist/web/ui/table.js +30 -0
  390. package/dist/web/ui/tabs.d.ts +11 -0
  391. package/dist/web/ui/tabs.js +31 -0
  392. package/dist/web/ui/textarea.d.ts +3 -0
  393. package/dist/web/ui/textarea.js +8 -0
  394. package/dist/web/ui/tooltip.d.ts +7 -0
  395. package/dist/web/ui/tooltip.js +19 -0
  396. package/dist/web/ui/use-mobile.d.ts +1 -0
  397. package/dist/web/ui/use-mobile.js +16 -0
  398. package/dist/web/version/update-checker.d.ts +9 -0
  399. package/dist/web/version/update-checker.js +88 -0
  400. package/dist/web/widgets/ai-text-field.d.ts +36 -0
  401. package/dist/web/widgets/ai-text-field.js +137 -0
  402. package/dist/web/widgets/bounded-load-cache.d.ts +1 -0
  403. package/dist/web/widgets/bounded-load-cache.js +25 -0
  404. package/dist/web/widgets/chart-window.d.ts +58 -0
  405. package/dist/web/widgets/chart-window.js +190 -0
  406. package/dist/web/widgets/charts.d.ts +208 -0
  407. package/dist/web/widgets/charts.js +685 -0
  408. package/dist/web/widgets/collapsible-section.d.ts +10 -0
  409. package/dist/web/widgets/collapsible-section.js +17 -0
  410. package/dist/web/widgets/dashboard-list.d.ts +21 -0
  411. package/dist/web/widgets/dashboard-list.js +45 -0
  412. package/dist/web/widgets/detail-list.d.ts +15 -0
  413. package/dist/web/widgets/detail-list.js +8 -0
  414. package/dist/web/widgets/drawer.d.ts +65 -0
  415. package/dist/web/widgets/drawer.js +177 -0
  416. package/dist/web/widgets/feed-list.d.ts +13 -0
  417. package/dist/web/widgets/feed-list.js +9 -0
  418. package/dist/web/widgets/floating-panel.d.ts +30 -0
  419. package/dist/web/widgets/floating-panel.js +242 -0
  420. package/dist/web/widgets/form-fields.d.ts +93 -0
  421. package/dist/web/widgets/form-fields.js +50 -0
  422. package/dist/web/widgets/index.d.ts +28 -0
  423. package/dist/web/widgets/index.js +31 -0
  424. package/dist/web/widgets/infinity-list.d.ts +46 -0
  425. package/dist/web/widgets/infinity-list.js +211 -0
  426. package/dist/web/widgets/mode-switch.d.ts +21 -0
  427. package/dist/web/widgets/mode-switch.js +25 -0
  428. package/dist/web/widgets/pdf-preview.d.ts +10 -0
  429. package/dist/web/widgets/pdf-preview.js +140 -0
  430. package/dist/web/widgets/photo-slots.d.ts +29 -0
  431. package/dist/web/widgets/photo-slots.js +52 -0
  432. package/dist/web/widgets/plan-card.d.ts +36 -0
  433. package/dist/web/widgets/plan-card.js +13 -0
  434. package/dist/web/widgets/progress-bar.d.ts +19 -0
  435. package/dist/web/widgets/progress-bar.js +24 -0
  436. package/dist/web/widgets/progress-list.d.ts +19 -0
  437. package/dist/web/widgets/progress-list.js +11 -0
  438. package/dist/web/widgets/public-shell.d.ts +22 -0
  439. package/dist/web/widgets/public-shell.js +15 -0
  440. package/dist/web/widgets/query-table.d.ts +29 -0
  441. package/dist/web/widgets/query-table.js +30 -0
  442. package/dist/web/widgets/result-panel.d.ts +69 -0
  443. package/dist/web/widgets/result-panel.js +30 -0
  444. package/dist/web/widgets/section-card.d.ts +12 -0
  445. package/dist/web/widgets/section-card.js +9 -0
  446. package/dist/web/widgets/sheet-parts.d.ts +9 -0
  447. package/dist/web/widgets/sheet-parts.js +11 -0
  448. package/dist/web/widgets/side-by-side-table.d.ts +31 -0
  449. package/dist/web/widgets/side-by-side-table.js +11 -0
  450. package/dist/web/widgets/stat.d.ts +54 -0
  451. package/dist/web/widgets/stat.js +65 -0
  452. package/dist/web/widgets/states.d.ts +23 -0
  453. package/dist/web/widgets/states.js +20 -0
  454. package/dist/web/widgets/status-badge.d.ts +15 -0
  455. package/dist/web/widgets/status-badge.js +24 -0
  456. package/dist/web/widgets/step-bar.d.ts +35 -0
  457. package/dist/web/widgets/step-bar.js +60 -0
  458. package/dist/web/widgets/upload-zone.d.ts +24 -0
  459. package/dist/web/widgets/upload-zone.js +108 -0
  460. package/dist/web/widgets/use-draft.d.ts +20 -0
  461. package/dist/web/widgets/use-draft.js +21 -0
  462. package/dist/web/widgets/use-pointer-drag.d.ts +21 -0
  463. package/dist/web/widgets/use-pointer-drag.js +53 -0
  464. package/package.json +114 -7
  465. package/src/changes.json +92 -0
  466. package/src/web/fonts/OFL.txt +93 -0
  467. package/src/web/fonts/ibm-plex-mono-latin-400.woff2 +0 -0
  468. package/src/web/fonts/ibm-plex-mono-latin-500.woff2 +0 -0
  469. package/src/web/fonts/ibm-plex-mono-latin-ext-400.woff2 +0 -0
  470. package/src/web/fonts/ibm-plex-mono-latin-ext-500.woff2 +0 -0
  471. package/src/web/fonts/ibm-plex-sans-latin-400.woff2 +0 -0
  472. package/src/web/fonts/ibm-plex-sans-latin-500.woff2 +0 -0
  473. package/src/web/fonts/ibm-plex-sans-latin-600.woff2 +0 -0
  474. package/src/web/fonts/ibm-plex-sans-latin-ext-400.woff2 +0 -0
  475. package/src/web/fonts/ibm-plex-sans-latin-ext-500.woff2 +0 -0
  476. package/src/web/fonts/ibm-plex-sans-latin-ext-600.woff2 +0 -0
  477. package/src/web/styles.css +405 -0
@@ -0,0 +1,103 @@
1
+ // Translates a ZodError into the same FieldIssue shape the server emits via
2
+ // its own zod-bridge (packages/framework/src/errors/zod-bridge.ts). The two
3
+ // bridges stay in sync on purpose: a field failing zod on the client reads
4
+ // identically to the same field failing zod on the server, so the UI's
5
+ // error-display path doesn't branch on provenance.
6
+ //
7
+ // Duplicated here (not imported) so ui-core remains free of
8
+ // @cosmicdrift/kumiko-framework — this package has to bundle for browsers and Expo,
9
+ // where a server-oriented framework dep would balloon bundle size and drag
10
+ // in Node-only modules (postgres, drizzle, bullmq) even if only types are
11
+ // consumed.
12
+ //
13
+ // Keep this list in sync with the server-side mirror — Zod version bumps
14
+ // tend to introduce new param keys, and the server's classes.test.ts is
15
+ // what catches them. A value added there should be added here too.
16
+ const ISSUE_PARAM_KEYS = [
17
+ "minimum",
18
+ "maximum",
19
+ "expected",
20
+ "received",
21
+ "type",
22
+ "inclusive",
23
+ "exact",
24
+ "keys",
25
+ // Zod 4 additions
26
+ "format",
27
+ "divisor",
28
+ "values",
29
+ "pattern",
30
+ ];
31
+ // Flat FieldIssue list — same shape as server-side ValidationError.fields.
32
+ // The form-controller groups this by `path` for its snapshot's errors map.
33
+ export function zodErrorToFieldIssues(error) {
34
+ return error.issues.map((issue) => {
35
+ const params = extractIssueParams(issue);
36
+ return {
37
+ // Empty-path issues (top-level object/array failures) use "(root)" so
38
+ // the form-controller has a stable key to show "form itself is
39
+ // malformed" errors under — matches what the server does.
40
+ path: issue.path.map(String).join(".") || "(root)",
41
+ code: issue.code,
42
+ i18nKey: resolveI18nKey(issue),
43
+ ...(params && { params }),
44
+ };
45
+ });
46
+ }
47
+ // The issues that count for validity: hidden fields never block, and a
48
+ // scope narrows to the listed paths (an entry matches itself and everything
49
+ // below it, not siblings — #1898). `includeRoot` keeps "(root)" refine issues
50
+ // inside a scope (submit passes it, #1907). Shared by the controller's
51
+ // validate() and RenderEdit's `valid` dry-run so the two cannot drift.
52
+ export function relevantFieldIssues(issues, opts) {
53
+ const { hiddenFields, scope, includeRoot } = opts;
54
+ return issues.filter((issue) => {
55
+ const rootField = issue.path.split(".")[0] ?? "";
56
+ if (hiddenFields.has(rootField))
57
+ return false;
58
+ if (scope === undefined)
59
+ return true;
60
+ if (includeRoot === true && issue.path === "(root)")
61
+ return true;
62
+ return scope.some((entry) => issue.path === entry || issue.path.startsWith(`${entry}.`));
63
+ });
64
+ }
65
+ // Same magic key both sides of a superRefine can set to opt out of the
66
+ // generic `errors.validation.custom` message — see form-schema.ts.
67
+ export const I18N_KEY_PARAM = "i18nKey";
68
+ // `code: "custom"` is zod's catch-all for every superRefine/refine check;
69
+ // left mechanical it'd collapse onto one generic key, so a superRefine can
70
+ // set `params[I18N_KEY_PARAM]` to override it. Keep in sync with the server
71
+ // mirror (packages/framework/src/errors/zod-bridge.ts).
72
+ function resolveI18nKey(issue) {
73
+ if (issue.code === "custom") {
74
+ const override = issue.params?.[I18N_KEY_PARAM];
75
+ if (typeof override === "string")
76
+ return override;
77
+ }
78
+ return `errors.validation.${issue.code}`;
79
+ }
80
+ function extractIssueParams(issue) {
81
+ const out = {};
82
+ const bag = issue; // @cast-boundary zod-issue
83
+ for (const key of ISSUE_PARAM_KEYS) {
84
+ if (bag[key] !== undefined)
85
+ out[key] = bag[key];
86
+ }
87
+ return Object.keys(out).length > 0 ? out : undefined;
88
+ }
89
+ // Groups a flat FieldIssue list into the `errors` map carried by a
90
+ // FormSnapshot. A field with multiple issues (e.g. both "required" and
91
+ // "min") keeps both — UIs that only render the first can pick the first
92
+ // element, those that want a full list have it.
93
+ export function groupIssuesByPath(issues) {
94
+ const out = {};
95
+ for (const issue of issues) {
96
+ const bucket = out[issue.path];
97
+ if (bucket)
98
+ bucket.push(issue);
99
+ else
100
+ out[issue.path] = [issue];
101
+ }
102
+ return out;
103
+ }
@@ -0,0 +1,12 @@
1
+ export declare const DOCUMENT_FALLBACK_CURRENCY = "EUR";
2
+ export declare function formatDocumentMoney(value: unknown, tenantCurrency: string, locale: string): string;
3
+ export type DocumentDateOptions = {
4
+ /** Append the time of day. Only instants and offset date-times carry one; a
5
+ * date-only value prints just the date. */
6
+ readonly time?: boolean;
7
+ /** IANA zone an instant is shown in (default UTC). Offset date-times keep
8
+ * their own wall clock. */
9
+ readonly timeZone?: string;
10
+ };
11
+ export declare function formatDocumentDate(value: unknown, locale: string, options?: DocumentDateOptions): string;
12
+ export declare function formatDocumentPercent(value: unknown, locale: string): string;
@@ -0,0 +1,70 @@
1
+ import { Temporal } from "@cosmicdrift/kumiko-types/temporal";
2
+ import { formatMoney, resolveSafeMoneyLocale } from "./money.js";
3
+ // Used when the tenant has no currency setting.
4
+ export const DOCUMENT_FALLBACK_CURRENCY = "EUR";
5
+ const DATE_ONLY = /^\d{4}-\d{2}-\d{2}$/;
6
+ const DATE_TIME_WITH_OFFSET = /^\d{4}-\d{2}-\d{2}T.*[+-]\d{2}(:?\d{2})?$/;
7
+ function isPlainRecord(value) {
8
+ return typeof value === "object" && value !== null && !Array.isArray(value);
9
+ }
10
+ // A bare number is minor units in the tenant currency; a `{ amount, currency }`
11
+ // record brings its own currency.
12
+ export function formatDocumentMoney(value, tenantCurrency, locale) {
13
+ if (typeof value === "number" && Number.isFinite(value)) {
14
+ return formatMoney(value, tenantCurrency, locale);
15
+ }
16
+ if (isPlainRecord(value)) {
17
+ const { amount, currency } = value;
18
+ if (typeof amount === "number" && Number.isFinite(amount) && typeof currency === "string") {
19
+ return formatMoney(amount, currency, locale);
20
+ }
21
+ }
22
+ return value === undefined || value === null ? "" : String(value);
23
+ }
24
+ function formatOffsetDateTime(value, locale, withTime) {
25
+ const wallClock = Temporal.PlainDateTime.from(value);
26
+ return withTime
27
+ ? wallClock.toLocaleString(locale, { dateStyle: "long", timeStyle: "short" })
28
+ : wallClock.toPlainDate().toLocaleString(locale, { dateStyle: "long" });
29
+ }
30
+ function instantFormatOptions(options) {
31
+ if (options.time !== true)
32
+ return { dateStyle: "long", timeZone: "UTC" };
33
+ return { dateStyle: "long", timeStyle: "short", timeZone: options.timeZone ?? "UTC" };
34
+ }
35
+ // The long date a rendered mail or PDF prints for a `date` placeholder; the editor's
36
+ // sample values use it too, so both show the same text.
37
+ export function formatDocumentDate(value, locale, options = {}) {
38
+ if (typeof value !== "string" && typeof value !== "number") {
39
+ return value === undefined || value === null ? "" : String(value);
40
+ }
41
+ const safeLocale = resolveSafeMoneyLocale(locale);
42
+ try {
43
+ // A date-only string has no zone; going through an instant would show the
44
+ // previous day west of UTC.
45
+ if (typeof value === "string" && DATE_ONLY.test(value)) {
46
+ return Temporal.PlainDate.from(value).toLocaleString(safeLocale, { dateStyle: "long" });
47
+ }
48
+ // An explicit offset names the sender's zone: the calendar date is the wall-clock
49
+ // date of the string, not the date at UTC.
50
+ if (typeof value === "string" && DATE_TIME_WITH_OFFSET.test(value)) {
51
+ return formatOffsetDateTime(value, safeLocale, options.time === true);
52
+ }
53
+ const instant = typeof value === "number"
54
+ ? Temporal.Instant.fromEpochMilliseconds(value)
55
+ : Temporal.Instant.from(value);
56
+ return instant.toLocaleString(safeLocale, instantFormatOptions(options));
57
+ }
58
+ catch {
59
+ return String(value);
60
+ }
61
+ }
62
+ export function formatDocumentPercent(value, locale) {
63
+ if (typeof value === "number" && Number.isFinite(value)) {
64
+ return new Intl.NumberFormat(resolveSafeMoneyLocale(locale), {
65
+ style: "percent",
66
+ maximumFractionDigits: 2,
67
+ }).format(value / 100);
68
+ }
69
+ return value === undefined || value === null ? "" : String(value);
70
+ }
@@ -0,0 +1,5 @@
1
+ export declare function escapeHtml(s: string): string;
2
+ export declare function escapeHtmlAttr(s: string): string;
3
+ export declare function escapeXml(s: string): string;
4
+ export declare function stripControlChars(value: string): string;
5
+ export declare function isSafeHref(href: string): boolean;
@@ -0,0 +1,75 @@
1
+ export function escapeHtml(s) {
2
+ return s
3
+ .replace(/&/g, "&")
4
+ .replace(/</g, "&lt;")
5
+ .replace(/>/g, "&gt;")
6
+ .replace(/"/g, "&quot;");
7
+ }
8
+ // Superset of escapeHtml for attribute contexts: additionally escapes ' so
9
+ // single-quoted attributes cannot be broken out of.
10
+ export function escapeHtmlAttr(s) {
11
+ return escapeHtml(s).replace(/'/g, "&#39;");
12
+ }
13
+ // Shared API for app repos (publicstatus badge-SVG renders XML by hand) —
14
+ // no in-repo consumer yet, deliberately exported for cross-repo dedup.
15
+ export function escapeXml(s) {
16
+ return s
17
+ .replace(/&/g, "&amp;")
18
+ .replace(/</g, "&lt;")
19
+ .replace(/>/g, "&gt;")
20
+ .replace(/"/g, "&quot;")
21
+ .replace(/'/g, "&apos;");
22
+ }
23
+ // Strips ASCII control chars + space (codepoints 0x00-0x20 and 0x7f) — the
24
+ // same characters browsers strip before scheme detection. `.trim()` alone
25
+ // only removes leading/trailing whitespace, so a scheme like
26
+ // "java\tscript:" (tab embedded mid-scheme) survives to isSafeHref's regex
27
+ // check below, breaks its character class before the ":", falls through to
28
+ // `return true`, and the browser then normalizes it back to "javascript:"
29
+ // and executes it. Written as a char-code filter rather than a regex range
30
+ // to avoid embedding literal control characters in source.
31
+ export function stripControlChars(value) {
32
+ let result = "";
33
+ for (const ch of value) {
34
+ const code = ch.codePointAt(0) ?? 0;
35
+ if (code > 0x20 && code !== 0x7f)
36
+ result += ch;
37
+ }
38
+ return result;
39
+ }
40
+ // http(s)/mailto or scheme-less (relative/anchor) allowed; javascript:,
41
+ // data:, vbscript:, etc. rejected. Shared between renderer/web's Link
42
+ // primitive and page-render's server-side markdown renderer (both take
43
+ // untrusted tenant-authored hrefs) — no sanitizer dependency needed for a
44
+ // four-line regex check.
45
+ // Browsers decode HTML character references (&colon;, &#58;, &#x3a;, &Tab;,
46
+ // &#9;, ...) while parsing the href attribute, before the URL parser ever
47
+ // sees the value — so "javascript&colon;alert(1)" and "java&Tab;script:"
48
+ // both normalize to an executable javascript: URL at click time even though
49
+ // neither contains a literal ":" for the regex below to catch. Decode
50
+ // (not delete) so the scheme check sees what the browser will execute —
51
+ // deleting "&colon;" would leave no colon at all, which reads as a safe
52
+ // scheme-less href, exactly backwards.
53
+ const NAMED_HTML_ENTITY_CHARS = {
54
+ colon: ":",
55
+ tab: "\t",
56
+ newline: "\n",
57
+ semi: ";",
58
+ amp: "&",
59
+ };
60
+ function decodeHtmlEntities(value) {
61
+ return value.replace(/&(#x[0-9a-f]+|#[0-9]+|[a-z][a-z0-9]*);/gi, (match, entity) => {
62
+ if (entity[0] === "#") {
63
+ const isHex = entity[1]?.toLowerCase() === "x";
64
+ const code = Number.parseInt(isHex ? entity.slice(2) : entity.slice(1), isHex ? 16 : 10);
65
+ return Number.isFinite(code) ? String.fromCodePoint(code) : match;
66
+ }
67
+ return NAMED_HTML_ENTITY_CHARS[entity.toLowerCase()] ?? match;
68
+ });
69
+ }
70
+ export function isSafeHref(href) {
71
+ const trimmed = stripControlChars(decodeHtmlEntities(href)).toLowerCase();
72
+ if (!/^[a-z][a-z0-9+.-]*:/.test(trimmed))
73
+ return true;
74
+ return /^(?:https?|mailto):/.test(trimmed);
75
+ }
@@ -0,0 +1,9 @@
1
+ export declare class RawHtml {
2
+ readonly html: string;
3
+ constructor(html: string);
4
+ toString(): string;
5
+ }
6
+ /** Marks already escaped or trusted markup for html`...`. */
7
+ export declare function raw(html: string): RawHtml;
8
+ export type HtmlValue = string | number | boolean | null | undefined | RawHtml | ReadonlyArray<HtmlValue>;
9
+ export declare function html(strings: TemplateStringsArray, ...values: ReadonlyArray<HtmlValue>): RawHtml;
@@ -0,0 +1,39 @@
1
+ // html`...` — tagged template that HTML-escapes every interpolation automatically.
2
+ // Makes escaping structural instead of a per-call-site convention: forgetting
3
+ // it is impossible, deliberately raw HTML needs an explicit raw(). The
4
+ // HTML-escape guard (kumiko-guards) accepts html`...` as safe.
5
+ import { escapeHtml } from "./escape.js";
6
+ export class RawHtml {
7
+ html;
8
+ constructor(html) {
9
+ this.html = html;
10
+ }
11
+ toString() {
12
+ return this.html;
13
+ }
14
+ }
15
+ /** Marks already escaped or trusted markup for html`...`. */
16
+ export function raw(html) {
17
+ return new RawHtml(html);
18
+ }
19
+ function renderValue(value) {
20
+ if (value === null || value === undefined)
21
+ return "";
22
+ if (value instanceof RawHtml)
23
+ return value.html;
24
+ if (Array.isArray(value))
25
+ return value.map(renderValue).join("");
26
+ if (typeof value === "string")
27
+ return escapeHtml(value);
28
+ return String(value);
29
+ }
30
+ // Returns RawHtml so fragments can be nested without double escaping:
31
+ // `html`<div>${item}</div>`` inside an outer html`...` passes through
32
+ // unchanged. toString() yields the finished markup.
33
+ export function html(strings, ...values) {
34
+ let out = strings[0] ?? "";
35
+ values.forEach((value, i) => {
36
+ out += renderValue(value) + (strings[i + 1] ?? "");
37
+ });
38
+ return new RawHtml(out);
39
+ }
@@ -0,0 +1,12 @@
1
+ import { Temporal } from "@cosmicdrift/kumiko-types/temporal";
2
+ export declare const EMPTY_VALUE_PLACEHOLDER = "\u2014";
3
+ export declare function toInstant(raw: string): Temporal.Instant;
4
+ /** Exported for UnitKey parity tests against @cosmicdrift/kumiko-types/screen. */
5
+ export declare const UNIT_FORMAT_KEYS: readonly string[];
6
+ export { DOCUMENT_FALLBACK_CURRENCY, type DocumentDateOptions, formatDocumentDate, formatDocumentMoney, formatDocumentPercent, } from "./document-values.ts";
7
+ export { escapeHtml, escapeHtmlAttr, escapeXml, isSafeHref, stripControlChars } from "./escape.ts";
8
+ export { type HtmlValue, html, RawHtml, raw } from "./html-template.ts";
9
+ export { currencyDecimals, formatMoney, resolveSafeMoneyLocale } from "./money.ts";
10
+ export declare function applyFormatSpec(spec: {
11
+ format: string;
12
+ } & Record<string, unknown>, value: unknown, translate?: (key: string) => string): string;
@@ -0,0 +1,237 @@
1
+ // Pure format utilities — no web or platform dependencies.
2
+ // Shared between renderer/web, renderer-native, and server-side tests.
3
+ import { Temporal } from "@cosmicdrift/kumiko-types/temporal";
4
+ import { isOneOf } from "@cosmicdrift/kumiko-types/type-guards";
5
+ export const EMPTY_VALUE_PLACEHOLDER = "—";
6
+ function toPlainDate(raw) {
7
+ try {
8
+ return Temporal.PlainDate.from(raw);
9
+ }
10
+ catch {
11
+ // "date"-typed field stored as a full instant (day-boundary timestamp) —
12
+ // take the calendar date in the local zone rather than fail.
13
+ return toInstant(raw).toZonedDateTimeISO(Temporal.Now.timeZoneId()).toPlainDate();
14
+ }
15
+ }
16
+ // Temporal.Instant.from is stricter than the `new Date(raw)` this replaced:
17
+ // it requires a UTC designator/offset (Z/+hh:mm). Timestamps without one
18
+ // (e.g. "2026-07-18T12:00:00", still valid input to `new Date`) throw here
19
+ // instead of parsing — fall back to reading them as a local wall-clock time,
20
+ // same posture as toPlainDate's own fallback above.
21
+ export function toInstant(raw) {
22
+ try {
23
+ return Temporal.Instant.from(raw);
24
+ }
25
+ catch {
26
+ return Temporal.PlainDateTime.from(raw).toZonedDateTime(Temporal.Now.timeZoneId()).toInstant();
27
+ }
28
+ }
29
+ function formatDateCell(value, type, opts) {
30
+ try {
31
+ const raw = typeof value === "string" ? value : String(value);
32
+ const locale = opts?.locale;
33
+ if (opts?.dateStyle || opts?.timeStyle) {
34
+ if (type === "date") {
35
+ // ponytail: timeStyle is ignored here on purpose — a PlainDate has no
36
+ // time component to format, so a timeStyle-only "date" field falls
37
+ // back to PlainDate's default dateStyle instead of rendering a time.
38
+ return toPlainDate(raw).toLocaleString(locale, {
39
+ dateStyle: opts.dateStyle,
40
+ });
41
+ }
42
+ return toInstant(raw).toLocaleString(locale, {
43
+ dateStyle: opts.dateStyle,
44
+ timeStyle: opts.timeStyle,
45
+ timeZone: opts.timeZone,
46
+ });
47
+ }
48
+ if (type === "date") {
49
+ return toPlainDate(raw).toLocaleString(locale, {
50
+ year: "numeric",
51
+ month: "2-digit",
52
+ day: "2-digit",
53
+ });
54
+ }
55
+ return toInstant(raw).toLocaleString(locale, {
56
+ year: "numeric",
57
+ month: "short",
58
+ day: "numeric",
59
+ hour: "2-digit",
60
+ minute: "2-digit",
61
+ timeZone: opts?.timeZone,
62
+ });
63
+ }
64
+ catch {
65
+ return String(value);
66
+ }
67
+ }
68
+ // No `locale` fallback to a browser API here (headless has none) — passing
69
+ // `undefined` to Intl.NumberFormat resolves the runtime's default locale,
70
+ // the same value a browser's navigator.language-based guess would produce.
71
+ function formatNumberCell(value, locale, grouping = true) {
72
+ if (typeof value !== "number" || !Number.isFinite(value))
73
+ return String(value);
74
+ try {
75
+ return new Intl.NumberFormat(locale, { useGrouping: grouping }).format(value);
76
+ }
77
+ catch {
78
+ // Malformed BCP-47 locale tag — mirrors formatDateCell's fallback above.
79
+ return String(value);
80
+ }
81
+ }
82
+ // Two-tier unit table for `{ format: "unit" }`. Keys mirror
83
+ // @cosmicdrift/kumiko-types' UnitKey (kept as a local literal union instead
84
+ // of an import — headless has no build-time dependency on kumiko-types
85
+ // today, and applyFormatSpec's spec param is already an untyped
86
+ // Record<string, unknown>, cast per-case like every other format below).
87
+ const UNIT_INTL_IDS = {
88
+ km: "kilometer",
89
+ m: "meter",
90
+ kg: "kilogram",
91
+ percent: "percent",
92
+ mi: "mile",
93
+ };
94
+ // "m2" (square meter) has no ECMA-402 sanctioned unit — Intl.NumberFormat
95
+ // throws RangeError for "square-meter". Locale-format the number and append
96
+ // the literal suffix instead of going through `style: "unit"`.
97
+ const UNIT_SUFFIXES = { m2: "m²" };
98
+ function isIntlUnit(unit) {
99
+ return Object.hasOwn(UNIT_INTL_IDS, unit);
100
+ }
101
+ function isSuffixUnit(unit) {
102
+ return Object.hasOwn(UNIT_SUFFIXES, unit);
103
+ }
104
+ function formatUnitCell(value, unit, locale, unitDisplay) {
105
+ const n = typeof value === "number" ? value : Number(value);
106
+ if (unit === undefined || !Number.isFinite(n))
107
+ return String(value);
108
+ if (isIntlUnit(unit)) {
109
+ try {
110
+ return new Intl.NumberFormat(locale, {
111
+ style: "unit",
112
+ unit: UNIT_INTL_IDS[unit],
113
+ unitDisplay,
114
+ }).format(n);
115
+ }
116
+ catch {
117
+ // Malformed BCP-47 locale tag — mirrors formatNumberCell's fallback below.
118
+ return formatNumberCell(n, locale);
119
+ }
120
+ }
121
+ if (isSuffixUnit(unit)) {
122
+ return `${formatNumberCell(n, locale)} ${UNIT_SUFFIXES[unit]}`;
123
+ }
124
+ return String(value);
125
+ }
126
+ /** Exported for UnitKey parity tests against @cosmicdrift/kumiko-types/screen. */
127
+ export const UNIT_FORMAT_KEYS = [
128
+ ...Object.keys(UNIT_INTL_IDS),
129
+ ...Object.keys(UNIT_SUFFIXES),
130
+ ];
131
+ export { DOCUMENT_FALLBACK_CURRENCY, formatDocumentDate, formatDocumentMoney, formatDocumentPercent, } from "./document-values.js";
132
+ export { escapeHtml, escapeHtmlAttr, escapeXml, isSafeHref, stripControlChars } from "./escape.js";
133
+ export { html, RawHtml, raw } from "./html-template.js";
134
+ export { currencyDecimals, formatMoney, resolveSafeMoneyLocale } from "./money.js";
135
+ // JSON.stringify throws on BigInt and circular values; a cell must degrade to text instead of crashing the screen.
136
+ function stringifyJsonOrString(value, indent) {
137
+ try {
138
+ return JSON.stringify(value, null, indent) ?? String(value);
139
+ }
140
+ catch {
141
+ try {
142
+ return String(value);
143
+ }
144
+ catch {
145
+ return "[unserializable value]";
146
+ }
147
+ }
148
+ }
149
+ const INTL_DATE_STYLES = ["full", "long", "medium", "short"];
150
+ const INTL_UNIT_DISPLAYS = ["short", "long", "narrow"];
151
+ function stringSpec(spec, key) {
152
+ const v = spec[key];
153
+ return typeof v === "string" ? v : undefined;
154
+ }
155
+ function booleanSpec(spec, key) {
156
+ const v = spec[key];
157
+ return typeof v === "boolean" ? v : undefined;
158
+ }
159
+ function dateStyleSpec(spec, key) {
160
+ const v = spec[key];
161
+ return isOneOf(INTL_DATE_STYLES, v) ? v : undefined;
162
+ }
163
+ function unitDisplaySpec(spec) {
164
+ const v = spec["unitDisplay"];
165
+ return isOneOf(INTL_UNIT_DISPLAYS, v) ? v : "short";
166
+ }
167
+ export function applyFormatSpec(spec, value, translate) {
168
+ const isEmpty = value === null || value === undefined || value === "";
169
+ // priority renders its emptyLabel for empty values — every other format
170
+ // collapses empty to "".
171
+ if (isEmpty && spec.format !== "priority")
172
+ return "";
173
+ switch (spec.format) {
174
+ case "timestamp":
175
+ case "date":
176
+ return formatDateCell(value, spec.format, {
177
+ locale: stringSpec(spec, "locale"),
178
+ dateStyle: dateStyleSpec(spec, "dateStyle"),
179
+ timeStyle: spec.format === "timestamp" ? dateStyleSpec(spec, "timeStyle") : undefined,
180
+ timeZone: spec.format === "timestamp" ? stringSpec(spec, "timeZone") : undefined,
181
+ });
182
+ case "boolean": {
183
+ if (value === true) {
184
+ const trueLabel = stringSpec(spec, "trueLabel");
185
+ return trueLabel === undefined ? "✓" : (translate?.(trueLabel) ?? trueLabel);
186
+ }
187
+ if (value === false) {
188
+ const falseLabel = stringSpec(spec, "falseLabel");
189
+ return falseLabel === undefined ? "" : (translate?.(falseLabel) ?? falseLabel);
190
+ }
191
+ return "";
192
+ }
193
+ case "currency": {
194
+ const sym = stringSpec(spec, "symbol") ?? "";
195
+ return sym.length > 0 ? `${value} ${sym}` : String(value);
196
+ }
197
+ case "number":
198
+ case "decimal":
199
+ case "bigInt":
200
+ return formatNumberCell(value, stringSpec(spec, "locale"), booleanSpec(spec, "grouping") ?? true);
201
+ case "unit":
202
+ return formatUnitCell(value, stringSpec(spec, "unit"), stringSpec(spec, "locale"), unitDisplaySpec(spec));
203
+ case "priority": {
204
+ const emptyLabel = stringSpec(spec, "emptyLabel") ?? EMPTY_VALUE_PLACEHOLDER;
205
+ const prefix = stringSpec(spec, "prefix") ?? "";
206
+ if (isEmpty || value === 0)
207
+ return emptyLabel;
208
+ return `${prefix}${value}`;
209
+ }
210
+ case "enumOption": {
211
+ const keyPrefix = stringSpec(spec, "keyPrefix");
212
+ const labelFor = (item) => {
213
+ const raw = typeof item === "string" ? item : String(item);
214
+ if (keyPrefix === undefined || translate === undefined)
215
+ return raw;
216
+ const key = `${keyPrefix}${raw}`;
217
+ const translated = translate(key);
218
+ return translated === key ? raw : translated;
219
+ };
220
+ // multiSelect-style columns hold an array of option values
221
+ return Array.isArray(value) ? value.map(labelFor).join(", ") : labelFor(value);
222
+ }
223
+ // Thumbnails and file links are drawn by the web list cell; this is the
224
+ // text fallback for every other surface.
225
+ case "image":
226
+ case "file":
227
+ return Array.isArray(value) ? value.join(", ") : String(value);
228
+ case "json":
229
+ return stringifyJsonOrString(value, typeof spec["indent"] === "number" ? spec["indent"] : 2);
230
+ default:
231
+ if (typeof process !== "undefined" && process.env.NODE_ENV !== "production") {
232
+ // biome-ignore lint/suspicious/noConsole: dev-only warning
233
+ console.warn(`[kumiko] applyFormatSpec: unknown format key "${spec.format}" — registered via FieldFormatRegistry module augmentation?`);
234
+ }
235
+ return typeof value === "string" ? value : String(value);
236
+ }
237
+ }
@@ -0,0 +1,3 @@
1
+ export declare function currencyDecimals(code: string): number;
2
+ export declare function resolveSafeMoneyLocale(locale: string | undefined): string;
3
+ export declare function formatMoney(amountMinor: number, currency: string, locale?: string, fractionDigits?: number): string;
@@ -0,0 +1,39 @@
1
+ // Currency decimal places — covers the world's zero- and three-decimal
2
+ // outliers, defaults to 2 for everything else. Shared between renderer/web's
3
+ // MoneyInput (minor-unit display factor) and RenderField's minor/major-unit
4
+ // conversion (kumiko-framework#1923) — a single source keeps both sides
5
+ // scaling the same currency the same way.
6
+ export function currencyDecimals(code) {
7
+ if (code === "JPY" || code === "KRW" || code === "VND" || code === "ISK")
8
+ return 0;
9
+ if (code === "BHD" || code === "JOD" || code === "KWD" || code === "OMR" || code === "TND")
10
+ return 3;
11
+ return 2;
12
+ }
13
+ const FALLBACK_MONEY_LOCALE = "en-US";
14
+ // An invalid tag makes Intl constructors throw a RangeError; canonicalizing up
15
+ // front keeps server renders and client cells safe. No navigator lookup, so it
16
+ // behaves the same on the server.
17
+ export function resolveSafeMoneyLocale(locale) {
18
+ try {
19
+ return Intl.getCanonicalLocales(locale ?? FALLBACK_MONEY_LOCALE)[0] ?? FALLBACK_MONEY_LOCALE;
20
+ }
21
+ catch {
22
+ return FALLBACK_MONEY_LOCALE;
23
+ }
24
+ }
25
+ // currency is validated against the 3-letter-alpha shape Intl.NumberFormat
26
+ // requires: a non-conforming value (e.g. from a JSONB custom field) would throw
27
+ // a RangeError and take down the whole render instead of just this value.
28
+ export function formatMoney(amountMinor, currency, locale, fractionDigits) {
29
+ if (!/^[A-Za-z]{3}$/.test(currency))
30
+ return String(amountMinor);
31
+ const decimals = currencyDecimals(currency);
32
+ const displayDigits = fractionDigits ?? decimals;
33
+ return new Intl.NumberFormat(resolveSafeMoneyLocale(locale), {
34
+ style: "currency",
35
+ currency,
36
+ minimumFractionDigits: displayDigits,
37
+ maximumFractionDigits: displayDigits,
38
+ }).format(amountMinor / 10 ** decimals);
39
+ }
@@ -0,0 +1,14 @@
1
+ export type { ParsedRefTarget } from "@cosmicdrift/kumiko-framework/ui-types";
2
+ export { parseRefTarget } from "@cosmicdrift/kumiko-framework/ui-types";
3
+ export type { AssetResolution, AssetResolveContext, AssetResolver, BadgeProps, ButtonProps, CardProps, DatePickerProps, IconProps, LocaleResolver, ModalProps, NumberInputProps, PrimitiveCommonProps, PrimitivesContract, SelectOption, SelectProps, TextInputProps, ToastIntent, ToastProps, ToggleProps, } from "./contracts/index.ts";
4
+ export type { BatchResult, Command, Dispatcher, DispatcherError, DispatcherStatus, FieldIssue, PendingFile, PendingWrite, QueryOpts, QueryResult, StreamOpts, WriteOpts, WriteResult, } from "./dispatcher/index.ts";
5
+ export { StreamFrame, type StreamFrameEvent } from "./dispatcher/index.ts";
6
+ export type { FieldConditionPredicate, FieldConditions, FieldConditionValue, FieldState, FormController, FormControllerOptions, FormSnapshot, FormValues, SubmitConfig, SubmitPayloadMode, SubmitResult, } from "./form/index.ts";
7
+ export { createFormController, groupIssuesByPath, I18N_KEY_PARAM, relevantFieldIssues, zodErrorToFieldIssues, } from "./form/index.ts";
8
+ export { applyFormatSpec, currencyDecimals, DOCUMENT_FALLBACK_CURRENCY, EMPTY_VALUE_PLACEHOLDER, escapeHtml, escapeHtmlAttr, escapeXml, formatDocumentDate, formatDocumentMoney, formatDocumentPercent, formatMoney, type HtmlValue, html, isSafeHref, RawHtml, raw, resolveSafeMoneyLocale, stripControlChars, toInstant, } from "./format/index.ts";
9
+ export type { NavDefinition, NavNode, NavRegistrySlice, NavTree, ResolveNavigationOptions, } from "./nav/index.ts";
10
+ export { resolveNavigation } from "./nav/index.ts";
11
+ export type { Store, WritableStore } from "./store/index.ts";
12
+ export { createStore, shallowEqual } from "./store/index.ts";
13
+ export type { CellLink, CellLinkItem, ComputeEditViewModelInput, ComputeListViewModelInput, DerivedCellRoundingTarget, EditExtensionSectionViewModel, EditFieldSpec, EditFieldsSectionViewModel, EditFieldViewModel, EditFormMode, EditRelatedListSectionViewModel, EditSectionSpec, EditSectionViewModel, EditViewModel, EditWriteFormSectionViewModel, EmbeddedDerivedOp, EmbeddedListCellViewModel, EmbeddedListIssueGroups, FieldConditionCtx, FieldRenderer, ListColumnFileDisplay, ListColumnSpec, ListColumnViewModel, ListRowViewModel, ListViewModel, RuntimeCellLink, RuntimeCellLinkItems, RuntimeRenderer, ScreenSlots, Translate, } from "./view-model/index.ts";
14
+ export { buildOptionLabels, computeDerivedCellValue, computeEditViewModel, computeListViewModel, computeRelatedListSectionViewModel, embeddedCellLabelKey, embeddedCellOptionLabelKey, fieldLabelKey, fieldOptionLabelKey, fieldOptionLabelKeyPrefix, groupEmbeddedListIssues, roundDerivedCellValue, sumEmbeddedListColumn, } from "./view-model/index.ts";
@@ -0,0 +1,9 @@
1
+ // Re-Export aus framework/ui-types damit Renderer-Code denselben
2
+ // Parser nutzt wie der Server-Boot-Validator (Cross-Feature-Refs).
3
+ export { parseRefTarget } from "@cosmicdrift/kumiko-framework/ui-types";
4
+ export { StreamFrame } from "./dispatcher/index.js";
5
+ export { createFormController, groupIssuesByPath, I18N_KEY_PARAM, relevantFieldIssues, zodErrorToFieldIssues, } from "./form/index.js";
6
+ export { applyFormatSpec, currencyDecimals, DOCUMENT_FALLBACK_CURRENCY, EMPTY_VALUE_PLACEHOLDER, escapeHtml, escapeHtmlAttr, escapeXml, formatDocumentDate, formatDocumentMoney, formatDocumentPercent, formatMoney, html, isSafeHref, RawHtml, raw, resolveSafeMoneyLocale, stripControlChars, toInstant, } from "./format/index.js";
7
+ export { resolveNavigation } from "./nav/index.js";
8
+ export { createStore, shallowEqual } from "./store/index.js";
9
+ export { buildOptionLabels, computeDerivedCellValue, computeEditViewModel, computeListViewModel, computeRelatedListSectionViewModel, embeddedCellLabelKey, embeddedCellOptionLabelKey, fieldLabelKey, fieldOptionLabelKey, fieldOptionLabelKeyPrefix, groupEmbeddedListIssues, roundDerivedCellValue, sumEmbeddedListColumn, } from "./view-model/index.js";