@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,498 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { isOpenToAllGranted } from "@cosmicdrift/kumiko-framework/ui-types";
3
+ import { createContext, useContext, useEffect, useMemo, useRef, useState, } from "react";
4
+ import { createRoot } from "react-dom/client";
5
+ import { AppFeaturesProvider, ClientActionsProvider, ColumnRenderersProvider, ContentEditorsProvider, CustomScreensProvider, createSessionEndedSignal, DashboardBodyProvider, DispatcherProvider, DraftStorageProvider, ErrorBoundary, ExtensionSectionsProvider, hasDetailScreen, KumikoScreen, kumikoDefaultTranslations, LiveEventsProvider, LocaleProvider, mergeTranslations, NavProvider, navigateWithReturnTo, PrimitivesProvider, qualifyScreenId, ScreenMissingState, SessionEndedSignalProvider, TokensProvider, toAppSchema, translationsByLocaleFromKeys, useNav, usePrimitives, useTranslation, withSessionEndedDetection, } from "../../index.js";
6
+ import { createLiveDispatcher } from "../../live/index.js";
7
+ import { lastSegment } from "../layout/nav-tree.js";
8
+ import { defaultPrimitives, ScreenWidthProvider } from "../primitives/index.js";
9
+ import { ToastProvider } from "../primitives/toast.js";
10
+ import { createEventSourceLiveEvents } from "../sse/live-events.js";
11
+ import { useBrowserTokensApi } from "../tokens.js";
12
+ import { UpdateChecker } from "../version/update-checker.js";
13
+ import { AppSchemaFetchBoot } from "./app-schema-boot.js";
14
+ import { createBrowserLocaleResolver } from "./browser-locale.js";
15
+ import { stackWrappers } from "./client-plugin.js";
16
+ import { WebDashboardBody } from "./dashboard-body.js";
17
+ import { DocumentLangSync } from "./document-lang-sync.js";
18
+ import { createBrowserDraftStorage } from "./draft-storage.js";
19
+ import { useBrowserNavApi } from "./nav.js";
20
+ import { NavProvidersProvider } from "./nav-providers-context.js";
21
+ import { ResolversProvider } from "./resolvers-context.js";
22
+ import { RootErrorFallback } from "./root-error-fallback.js";
23
+ import { ScreenErrorFallback } from "./screen-error-fallback.js";
24
+ import { ToastActionNotifier } from "./toast-action-notifier.js";
25
+ const EMPTY_FEATURES = [];
26
+ const EMPTY_COLLECTIONS = [];
27
+ // Qualifiziert den Key eines navProviders auf seine Nav-QN. Lokale ids
28
+ // (z.B. "content") werden wie in r.nav mit dem Feature-Namen qualifiziert;
29
+ // bereits qualifizierte QNs (App registriert die Nav für ein bundled-feature
30
+ // und gibt die QN als navId rein, z.B. "publicstatus:nav:content") gehen
31
+ // unverändert durch. MUSS konsistent zu qualifyNavId bleiben, sonst findet
32
+ // der NavTree-Knoten (Schema-Seite) seinen Provider nicht.
33
+ export function qualifyNavProviderKey(feature, id) {
34
+ return id.includes(":nav:") ? id : `${feature}:nav:${id}`;
35
+ }
36
+ // Nav-Provider-Map: ein navProvider hängt dynamische Children an einen
37
+ // konkreten r.nav({provider:true})-Knoten (per QN). Lokale nav-ids werden wie
38
+ // in r.nav mit dem Feature-Namen qualifiziert; bereits qualifizierte QNs
39
+ // (cross-feature, z.B. App registriert Nav für ein bundled-feature) gehen
40
+ // unverändert durch.
41
+ //
42
+ // Schema-derived providers (r.contentCollection) run first and hold the weaker
43
+ // claim on a QN — an explicitly registered navProvider overrides them without
44
+ // comment. Only two EXPLICIT registrations on the same QN are the conflict
45
+ // that deserves the warning.
46
+ export function buildNavProviderMaps(clientFeatures, collections) {
47
+ const navProviders = new Map();
48
+ const navEntities = new Map();
49
+ const derivedQns = new Set();
50
+ for (const f of clientFeatures) {
51
+ if (f.navProvidersFromCollections === undefined)
52
+ continue;
53
+ const derived = f.navProvidersFromCollections(collections);
54
+ for (const [qn, provider] of Object.entries(derived.providers)) {
55
+ navProviders.set(qn, provider);
56
+ derivedQns.add(qn);
57
+ }
58
+ for (const [qn, entities] of Object.entries(derived.entities ?? {})) {
59
+ if (entities.length > 0)
60
+ navEntities.set(qn, entities);
61
+ }
62
+ }
63
+ for (const f of clientFeatures) {
64
+ for (const [navId, provider] of Object.entries(f.navProviders ?? {})) {
65
+ const qn = qualifyNavProviderKey(f.name, navId);
66
+ if (navProviders.has(qn) && !derivedQns.delete(qn)) {
67
+ // biome-ignore lint/suspicious/noConsole: dev warning for schema conflicts
68
+ console.warn(`[kumiko] navProvider for "${qn}" defined by multiple clientFeatures — last wins.`);
69
+ }
70
+ navProviders.set(qn, provider);
71
+ }
72
+ for (const [navId, entities] of Object.entries(f.navEntities ?? {})) {
73
+ if (entities.length > 0)
74
+ navEntities.set(qualifyNavProviderKey(f.name, navId), entities);
75
+ }
76
+ }
77
+ return { navProviders, navEntities };
78
+ }
79
+ const BoundaryErrorHandlerContext = createContext(undefined);
80
+ // Reads a schema an app baked into the page itself (e.g. an e2e fixture) —
81
+ // nothing in this repo sets this global anymore now that HTML never carries
82
+ // an injected schema. Guarded for SSR/node even though this only runs in
83
+ // the browser today; harmless under jsdom either way.
84
+ function readInjectedSchema() {
85
+ if (typeof window === "undefined")
86
+ return undefined;
87
+ const w = window;
88
+ return w.__KUMIKO_SCHEMA__;
89
+ }
90
+ // Nav reachability is required, otherwise a dormant `type: "custom"`
91
+ // screen a feature only registers for manual app-side placement (e.g.
92
+ // auth-mfa's enable screen) can win by declaration order alone, landing
93
+ // every app without an explicit `screenQn` on a screen nobody wired a
94
+ // component for (#1258).
95
+ function firstNavReachableScreenQn(features, acceptsScreen) {
96
+ // NavDefinition.screen carries two shapes in practice: most bundled
97
+ // features author it pre-qualified ("tenant:screen:members"), but the
98
+ // config settings-hub generator emits the bare short id. Index both
99
+ // forms so nav-reachability doesn't depend on which convention a given
100
+ // feature happens to use.
101
+ const navScreenQns = new Set();
102
+ for (const f of features) {
103
+ for (const n of f.navs ?? []) {
104
+ if (n.screen === undefined)
105
+ continue;
106
+ navScreenQns.add(n.screen);
107
+ navScreenQns.add(qualifyScreenId(f.featureName, n.screen));
108
+ }
109
+ }
110
+ for (const feature of features) {
111
+ const screen = feature.screens.find((s) => acceptsScreen(s) && navScreenQns.has(qualifyScreenId(feature.featureName, s.id)));
112
+ if (screen !== undefined)
113
+ return qualifyScreenId(feature.featureName, screen.id);
114
+ }
115
+ return undefined;
116
+ }
117
+ // Only screens whose `access` excludes nobody: on an unprojected schema the
118
+ // landing is picked without knowing the user's roles, so a role-restricted
119
+ // screen would land every non-admin on access-denied (#1176).
120
+ export function firstOpenScreenQn(features) {
121
+ return firstNavReachableScreenQn(features, (s) => s.access === undefined || isOpenToAllGranted(s.access));
122
+ }
123
+ // Landing fallback for a schema that arrived already role-projected by the
124
+ // server (fetch mode, GET /api/schema strips screens the caller's roles
125
+ // can't see) — a pure SystemAdmin whose only screens are role-restricted
126
+ // must still get a landing instead of the "no-open-screen" banner.
127
+ // Regular users keep today's
128
+ // firstOpenScreenQn landing; only when that yields nothing do we fall back
129
+ // to any nav-reachable screen, since the projection already removed
130
+ // everything the caller's roles may not see.
131
+ export function firstLandingScreenQnForProjectedSchema(features) {
132
+ return firstOpenScreenQn(features) ?? firstNavReachableScreenQn(features, () => true);
133
+ }
134
+ // The server's role projection may strip an explicitly configured screenQn
135
+ // for this caller's roles; the root route then falls back to the first
136
+ // reachable landing instead of "Screen not found". An unprojected schema
137
+ // keeps the explicit screen as configured.
138
+ export function resolveRootScreenQn(features, explicitScreenQn, schemaIsRoleProjected) {
139
+ if (explicitScreenQn === undefined) {
140
+ return schemaIsRoleProjected
141
+ ? firstLandingScreenQnForProjectedSchema(features)
142
+ : firstOpenScreenQn(features);
143
+ }
144
+ if (!schemaIsRoleProjected)
145
+ return explicitScreenQn;
146
+ if (findOwnerFeature(features, explicitScreenQn) !== undefined)
147
+ return explicitScreenQn;
148
+ return firstLandingScreenQnForProjectedSchema(features);
149
+ }
150
+ // Last-wins merge for a clientFeature-contributed map (contentEditors,
151
+ // columnRenderers, extensionSectionComponents, ...): later features in
152
+ // `clientFeatures` override earlier ones on key collision, logging once
153
+ // per collision so an accidental override isn't silent.
154
+ function mergeByKey(clientFeatures, pick, label) {
155
+ const merged = {};
156
+ for (const f of clientFeatures) {
157
+ const entries = pick(f);
158
+ if (entries === undefined)
159
+ continue;
160
+ for (const [key, value] of Object.entries(entries)) {
161
+ if (merged[key] !== undefined) {
162
+ // biome-ignore lint/suspicious/noConsole: dev warning for schema conflicts
163
+ console.warn(`[kumiko] ${label} "${key}" defined by multiple clientFeatures — last definition (from "${f.name}") wins.`);
164
+ }
165
+ merged[key] = value;
166
+ }
167
+ }
168
+ return merged;
169
+ }
170
+ // Merges the content-editor map — same last-wins semantics as
171
+ // columnRenderers. No entry for a contentFormat → useContentEditor falls
172
+ // back to the textarea on its own, no warning needed.
173
+ export function mergeContentEditors(clientFeatures) {
174
+ return mergeByKey(clientFeatures, (f) => f.contentEditors, "contentEditor");
175
+ }
176
+ // Fail loud at boot instead of per-URL: a mounted server feature can
177
+ // declare a `type: "custom"` screen that's reachable directly by URL
178
+ // even without nav placement — without this check, a missing client
179
+ // plugin only surfaces as an error placeholder to whoever happens to
180
+ // open that URL (kumiko-framework#2025). Screens flagged `dormant`
181
+ // (e.g. user-data-rights privacy-center, auth-mfa's enable screen) are
182
+ // registered without a self-owned r.nav on purpose — an app opts in by
183
+ // navving them explicitly, so a consumer that hasn't done that yet isn't
184
+ // missing anything (kumiko-framework#2034). Still dev-only: several
185
+ // bundled screens that ARE self-navved (e.g. compliance-profiles'
186
+ // profile-picker) have real unmounted-client-plugin bugs in existing
187
+ // consumer apps today (kumiko-framework#2025) — running this in
188
+ // production before those are fixed (tracked via infra#503) would just
189
+ // spam every affected app's console.
190
+ function warnMissingCustomScreens(app, customScreens) {
191
+ if (typeof process === "undefined" || process.env.NODE_ENV === "production")
192
+ return;
193
+ const missingCustomScreens = app.features.flatMap((f) => f.screens
194
+ .filter((s) => s.type === "custom" && s.dormant !== true && customScreens[s.id] === undefined)
195
+ .map((s) => `${f.featureName}:${s.id}`));
196
+ if (missingCustomScreens.length > 0) {
197
+ // biome-ignore lint/suspicious/noConsole: dev-only diagnostic for missing client plugins
198
+ console.error(`[kumiko] ${missingCustomScreens.length} custom screen(s) have no registered component in clientFeatures.components — they render an error placeholder instead of the intended UI: ${missingCustomScreens.join(", ")}. Add the feature's web client plugin to clientFeatures.`);
199
+ }
200
+ }
201
+ // Everything schema-INdependent (dispatcher, providers, gates, merged
202
+ // component maps, ...) is built once in createKumikoApp and passed in as
203
+ // props; only the schema-dependent slice (fallbackBundles, nav-provider
204
+ // derivation, the actual screen tree) lives in this component's own state
205
+ // so a schema arriving later (the fetch path) doesn't need a second copy
206
+ // of the provider tree.
207
+ function KumikoAppRoot(props) {
208
+ const [app, setApp] = useState(props.initialApp);
209
+ // Precedence in fallbackBundles (array order = priority, highest first):
210
+ // 1. clientFeatures.translations — app overrides always win, even
211
+ // against the framework's own labels.
212
+ // 2. schemaTranslations — server-authored r.translations, projected
213
+ // verbatim by buildAppSchema (#1059). Without this bundle, nav/
214
+ // screen labels only resolve if an app ALSO duplicates them in its
215
+ // own web/i18n.ts — most bundled features never did, labels then
216
+ // render as raw i18n keys.
217
+ // 3. kumikoDefaultTranslations — framework defaults, the very last
218
+ // fallback.
219
+ // biome-ignore lint/correctness/useExhaustiveDependencies: props.clientFeatures is stable for the app instance's lifetime (built once in createKumikoApp)
220
+ const { fallbackBundles, navProviders, navEntities } = useMemo(() => {
221
+ const schemaTranslations = (app?.features ?? EMPTY_FEATURES).reduce((acc, f) => f.translations ? mergeTranslations(acc, translationsByLocaleFromKeys(f.translations)) : acc, {});
222
+ const bundles = [
223
+ ...props.clientFeatures.flatMap((f) => f.translations !== undefined ? [f.translations] : []),
224
+ schemaTranslations,
225
+ kumikoDefaultTranslations,
226
+ ];
227
+ const { navProviders: providersByQn, navEntities: entitiesByQn } = buildNavProviderMaps(props.clientFeatures, app?.features.flatMap((f) => f.contentCollections ?? []) ?? EMPTY_COLLECTIONS);
228
+ return { fallbackBundles: bundles, navProviders: providersByQn, navEntities: entitiesByQn };
229
+ }, [app]);
230
+ // Sync path (initialApp given at construction) never resets — that
231
+ // schema was handed in explicitly and stays valid for the app's
232
+ // lifetime. Fetch path resets to undefined on unmount so a future
233
+ // role-aware schema projection never lets a re-login reuse a
234
+ // previous user's cached app.
235
+ const isFetchMode = props.initialApp === undefined;
236
+ const screenNode = (_jsx(AppSchemaBoundary, { app: app, screenQn: props.screenQn, ...(props.schemaUrl !== undefined && { schemaUrl: props.schemaUrl }), navAdapter: props.navAdapter, onAppLoaded: (loaded) => {
237
+ warnMissingCustomScreens(loaded, props.customScreens);
238
+ setApp(loaded);
239
+ }, schemaIsRoleProjected: isFetchMode, ...(isFetchMode && { onUnmountResetSchema: () => setApp(undefined) }), ...(props.translate !== undefined && { translate: props.translate }), ...(props.onRowClick !== undefined && { onRowClick: props.onRowClick }), ...(props.shell !== undefined && { shell: props.shell }) }));
240
+ return (_jsx(TokensBoot, { children: _jsxs(LocaleProvider, { resolver: props.localeResolver, fallbackBundles: fallbackBundles, children: [_jsx(DocumentLangSync, { resolver: props.localeResolver }), _jsx(PrimitivesProvider, { value: props.primitives, children: _jsx(ScreenWidthProvider, { width: props.screenWidth, children: _jsx(AppFeaturesProvider, { features: app?.features ?? EMPTY_FEATURES, children: _jsx(DispatcherProvider, { dispatcher: props.dispatcher, children: _jsx(DraftStorageProvider, { value: props.draftStorage, children: _jsx(LiveEventsProvider, { value: props.liveEvents, children: _jsx(DashboardBodyProvider, { value: WebDashboardBody, children: _jsx(CustomScreensProvider, { value: props.customScreens, children: _jsx(ColumnRenderersProvider, { value: props.columnRenderers, children: _jsx(ContentEditorsProvider, { value: props.contentEditors, children: _jsx(ExtensionSectionsProvider, { value: props.extensionSectionComponents, children: _jsx(ClientActionsProvider, { value: props.clientActions, children: _jsx(NavProvidersProvider, { value: navProviders, entities: navEntities, children: _jsx(ResolversProvider, { resolvers: props.resolvers, children: _jsx(ToastProvider, { children: _jsxs(ToastActionNotifier, { children: [_jsx(UpdateChecker, {}), _jsx(SessionEndedSignalProvider, { signal: props.sessionEndedSignal, children: stackWrappers(props.providers, stackWrappers(props.gates, screenNode)) })] }) }) }) }) }) }) }) }) }) }) }) }) }) }) }) })] }) }));
241
+ }
242
+ // Sits INSIDE the clientFeature gates (e.g. an auth gate) — a gate that
243
+ // renders a login placeholder instead of children keeps this component
244
+ // (and its schema fetch) from ever mounting until the user is signed in.
245
+ function AppSchemaBoundary({ app, screenQn, schemaUrl, navAdapter, onAppLoaded, schemaIsRoleProjected, onUnmountResetSchema, translate, onRowClick, shell, }) {
246
+ // Called unconditionally regardless of which branch below actually
247
+ // renders — this component's identity persists across the "no app yet"
248
+ // → "app loaded" transition, so its hooks must run in the same order on
249
+ // every render (Rules of Hooks).
250
+ const t = useTranslation();
251
+ const { Banner } = usePrimitives();
252
+ // Ref, not an effect dependency: onUnmountResetSchema closes over
253
+ // KumikoAppRoot's setApp and would otherwise force this effect to
254
+ // re-run (and re-fire its cleanup) on every render.
255
+ const onUnmountResetSchemaRef = useRef(onUnmountResetSchema);
256
+ onUnmountResetSchemaRef.current = onUnmountResetSchema;
257
+ // A real unmount (the gate withdrawing children, e.g. on logout) resets
258
+ // the schema so the next mount re-fetches instead of reusing this
259
+ // session's — fetch-mode only, see isFetchMode in KumikoAppRoot.
260
+ useEffect(() => {
261
+ return () => onUnmountResetSchemaRef.current?.();
262
+ }, []);
263
+ if (app === undefined) {
264
+ return (_jsx(AppSchemaFetchBoot, { onLoaded: onAppLoaded, ...(schemaUrl !== undefined && { schemaUrl }) }));
265
+ }
266
+ const fallbackQn = resolveRootScreenQn(app.features, screenQn, schemaIsRoleProjected);
267
+ if (fallbackQn === undefined) {
268
+ return (_jsx(Banner, { variant: "error", padded: true, children: t("kumiko.app-boot.no-open-screen") }));
269
+ }
270
+ return (_jsx(BrowserNavBoot, { app: app, fallbackQn: fallbackQn, useNavApi: navAdapter, hasWorkspaces: (app.workspaces?.length ?? 0) > 0, ...(translate !== undefined && { translate }), ...(onRowClick !== undefined && { onRowClick }), ...(shell !== undefined && { shell }) }));
271
+ }
272
+ export function createKumikoApp(options = {}) {
273
+ const rootId = options.rootId ?? "root";
274
+ const container = document.getElementById(rootId);
275
+ if (!container) {
276
+ throw new Error(`createKumikoApp: DOM element #${rootId} not found. Make sure your HTML has a matching <div id="${rootId}"></div> before the bundle loads.`);
277
+ }
278
+ // toAppSchema normalizes the FeatureSchema/AppSchema union — from here on
279
+ // every layout only ever sees AppSchema. No schema resolved yet (neither
280
+ // options.schema nor window.__KUMIKO_SCHEMA__) is no longer an error here:
281
+ // KumikoAppRoot/AppSchemaBoundary fetch it from GET /api/schema instead.
282
+ const rawSchema = options.schema ?? readInjectedSchema();
283
+ let initialApp;
284
+ if (rawSchema !== undefined) {
285
+ initialApp = toAppSchema(rawSchema);
286
+ const fallbackQn = options.screenQn ?? firstOpenScreenQn(initialApp.features);
287
+ if (!fallbackQn) {
288
+ throw new Error("createKumikoApp: schema contains no screens accessible without a role restriction. Add at least one entry to `schema.screens` without `access.roles`, or pass `screenQn` explicitly.");
289
+ }
290
+ }
291
+ const sessionEndedSignal = createSessionEndedSignal();
292
+ const dispatcher = withSessionEndedDetection(options.dispatcher ?? createLiveDispatcher(), sessionEndedSignal);
293
+ const draftStorage = options.draftStorage ?? createBrowserDraftStorage();
294
+ const primitives = { ...defaultPrimitives, ...(options.primitives ?? {}) };
295
+ const liveEvents = createEventSourceLiveEvents({
296
+ onSessionEnded: () => sessionEndedSignal.notify(),
297
+ });
298
+ // Feature plugins: providers stack outermost (every gate + screen sees
299
+ // every provider), gates stack between the renderer providers and the
300
+ // shell/screen. Array order: first element = outermost wrapper.
301
+ const clientFeatures = options.clientFeatures ?? [];
302
+ const providers = clientFeatures.flatMap((f) => f.providers ?? []);
303
+ const gates = clientFeatures.flatMap((f) => f.gates ?? []);
304
+ // Custom-screen component map merge: later features override earlier ones
305
+ // on screenId collision (last-wins). Lets an app override a bundled
306
+ // feature's screen with a local component.
307
+ const customScreens = {};
308
+ for (const f of clientFeatures) {
309
+ if (f.components !== undefined)
310
+ Object.assign(customScreens, f.components);
311
+ }
312
+ if (initialApp !== undefined)
313
+ warnMissingCustomScreens(initialApp, customScreens);
314
+ // Column-renderer map, same last-wins semantics as customScreens —
315
+ // duplicate keys across features are rarely intentional, so a
316
+ // collision logs once instead of silently overriding a library's
317
+ // renderer.
318
+ const columnRenderers = mergeByKey(clientFeatures, (f) => f.columnRenderers, "columnRenderer");
319
+ // Extension-section components — same last-wins + warn semantics as
320
+ // columnRenderers. Mounted on ExtensionSectionsProvider; RenderEdit
321
+ // resolves the component from the section's `__component` marker.
322
+ const extensionSectionComponents = mergeByKey(clientFeatures, (f) => f.extensionSectionComponents, "extensionSectionComponent");
323
+ const clientActions = mergeByKey(clientFeatures, (f) => f.clientActions, "clientAction");
324
+ const contentEditors = mergeContentEditors(clientFeatures);
325
+ // Aggregate editor resolvers — keyed by "featureId:action". Same
326
+ // last-wins semantics as columnRenderers. Warns on collision.
327
+ const resolvers = new Map();
328
+ for (const f of clientFeatures) {
329
+ if (f.resolvers === undefined)
330
+ continue;
331
+ for (const [key, component] of Object.entries(f.resolvers)) {
332
+ if (resolvers.has(key)) {
333
+ // biome-ignore lint/suspicious/noConsole: client-bundle has no logger; collision is a dev-time warning that must surface in the browser DevTools.
334
+ console.warn(`[kumiko] resolver "${key}" defined by multiple clientFeatures — last definition (from "${f.name}") wins.`);
335
+ }
336
+ resolvers.set(key, component);
337
+ }
338
+ }
339
+ const localeResolver = options.locale ?? createBrowserLocaleResolver();
340
+ const navAdapter = options.navAdapter ?? useBrowserNavApi;
341
+ const root = createRoot(container);
342
+ root.render(_jsx(ErrorBoundary, { scope: "root", ...(options.onError !== undefined && { onError: options.onError }), fallback: () => _jsx(RootErrorFallback, {}), children: _jsx(BoundaryErrorHandlerContext.Provider, { value: options.onError, children: _jsx(KumikoAppRoot, { initialApp: initialApp, screenQn: options.screenQn, ...(options.schemaUrl !== undefined && { schemaUrl: options.schemaUrl }), clientFeatures: clientFeatures, providers: providers, gates: gates, customScreens: customScreens, columnRenderers: columnRenderers, extensionSectionComponents: extensionSectionComponents, clientActions: clientActions, contentEditors: contentEditors, resolvers: resolvers, dispatcher: dispatcher, sessionEndedSignal: sessionEndedSignal, draftStorage: draftStorage, primitives: primitives, liveEvents: liveEvents, localeResolver: localeResolver, navAdapter: navAdapter, screenWidth: options.screenWidth, ...(options.translate !== undefined && { translate: options.translate }), ...(options.onRowClick !== undefined && { onRowClick: options.onRowClick }), ...(options.shell !== undefined && { shell: options.shell }) }) }) }));
343
+ return { root };
344
+ }
345
+ // TokensBoot uses the browser-backed TokensApi hook (class-based
346
+ // dark-toggle) and passes the value through to the shared
347
+ // TokensProvider. No own state — the class on <html> is the
348
+ // SSoT, useSyncExternalStore in the hook syncs that into React.
349
+ function TokensBoot({ children }) {
350
+ const api = useBrowserTokensApi();
351
+ return _jsx(TokensProvider, { value: api, children: children });
352
+ }
353
+ function BrowserNavBoot({ app, fallbackQn, useNavApi, hasWorkspaces, translate, onRowClick, shell, }) {
354
+ const navApi = useNavApi({ hasWorkspaces, features: app.features });
355
+ const Shell = shell;
356
+ const screen = (_jsx(RoutedScreen, { app: app, fallbackQn: fallbackQn, ...(translate !== undefined && { translate }), ...(onRowClick !== undefined && { onRowClick }) }));
357
+ return (_jsx(NavProvider, { value: navApi, children: Shell !== undefined ? _jsx(Shell, { schema: app, children: screen }) : screen }));
358
+ }
359
+ // Finds the feature that owns a fully qualified ScreenQn.
360
+ // Returns undefined if the screen isn't declared in any feature schema —
361
+ // KumikoScreen then renders the "Screen not found" banner.
362
+ function findOwnerFeature(features, qn) {
363
+ for (const feature of features) {
364
+ for (const s of feature.screens) {
365
+ if (qualifyScreenId(feature.featureName, s.id) === qn)
366
+ return feature;
367
+ }
368
+ }
369
+ return undefined;
370
+ }
371
+ // Single source for "which entityEdit screen does a row click land on", shared
372
+ // by the click handler and hasRowClickTarget so a row never looks clickable
373
+ // without a target (or the reverse).
374
+ function findEditScreenForEntity(features, entityName) {
375
+ for (const feature of features) {
376
+ const editScreen = feature.screens.find((s) => s.type === "entityEdit" && s.entity === entityName);
377
+ if (editScreen)
378
+ return editScreen;
379
+ }
380
+ return undefined;
381
+ }
382
+ // fw#2640: a list screen with no reachable click target (no `detailFor`
383
+ // screen for its entity, no app-wide onRowClick, no entityEdit screen)
384
+ // must render without the row-click affordance instead of a silent no-op —
385
+ // mirrors the precedence effectiveOnRowClick itself resolves at click time.
386
+ // Only entityList/projectionList screens ever render RenderList; every other
387
+ // screen type never wires onRowClick at all, so it can never have a target.
388
+ function hasRowClickTarget(app, screen, onRowClick) {
389
+ if (screen === undefined)
390
+ return false;
391
+ if (screen.type !== "entityList" && screen.type !== "projectionList")
392
+ return false;
393
+ if (onRowClick !== undefined)
394
+ return true;
395
+ if (screen.type !== "entityList")
396
+ return false;
397
+ if (hasDetailScreen(app.features, screen.entity))
398
+ return true;
399
+ return findEditScreenForEntity(app.features, screen.entity) !== undefined;
400
+ }
401
+ function RoutedScreen({ app, fallbackQn, translate, onRowClick, }) {
402
+ const nav = useNav();
403
+ const onBoundaryError = useContext(BoundaryErrorHandlerContext);
404
+ // ScreenId from the route is NOT qualified — nav.route.screenId
405
+ // comes from the URL path and is the short form ("order-list"). We
406
+ // need to pin it to the right feature. Strategy: iterate through all
407
+ // features until the matching screen decl turns up. No match →
408
+ // fallback feature (the one from fallbackQn).
409
+ const { feature, qn, entityId, activeScreen } = useMemo(() => {
410
+ if (nav.route === undefined) {
411
+ const ownerFeature = findOwnerFeature(app.features, fallbackQn);
412
+ return {
413
+ feature: ownerFeature,
414
+ qn: fallbackQn,
415
+ entityId: undefined,
416
+ activeScreen: ownerFeature?.screens.find((s) => qualifyScreenId(ownerFeature.featureName, s.id) === fallbackQn),
417
+ };
418
+ }
419
+ const shortId = nav.route.screenId;
420
+ // Suche das Feature dessen Screens den short id enthalten.
421
+ let matchedFeature;
422
+ for (const f of app.features) {
423
+ if (f.screens.some((s) => s.id === shortId)) {
424
+ matchedFeature = f;
425
+ break;
426
+ }
427
+ }
428
+ const ownerFeature = matchedFeature ?? findOwnerFeature(app.features, fallbackQn);
429
+ const qualifiedQn = ownerFeature ? qualifyScreenId(ownerFeature.featureName, shortId) : shortId;
430
+ return {
431
+ feature: ownerFeature,
432
+ qn: qualifiedQn,
433
+ entityId: nav.route.entityId,
434
+ activeScreen: ownerFeature?.screens.find((s) => qualifyScreenId(ownerFeature.featureName, s.id) === qualifiedQn),
435
+ };
436
+ }, [nav.route, app, fallbackQn]);
437
+ const effectiveOnRowClick = useMemo(() => {
438
+ if (!hasRowClickTarget(app, activeScreen, onRowClick))
439
+ return undefined;
440
+ return (row, entityName) => {
441
+ // No ReturnHostProvider out here — derive the host from this memo's own qn/entityId.
442
+ const host = {
443
+ screenId: lastSegment(qn),
444
+ ...(entityId !== undefined && { entityId }),
445
+ };
446
+ // Precedence (fw#2164): detailFor screen, then onRowClick, then the
447
+ // entityEdit-search fallback below. An explicit rowActions
448
+ // rowClick:true already wins over all of this — kumiko-screen.tsx
449
+ // handles it before onRowClick is ever called.
450
+ if (hasDetailScreen(app.features, entityName)) {
451
+ navigateWithReturnTo(nav, { entity: entityName, id: row.id }, host);
452
+ return;
453
+ }
454
+ if (onRowClick !== undefined) {
455
+ onRowClick(row, entityName);
456
+ return;
457
+ }
458
+ // No declared detail screen and no app-wide onRowClick — search for
459
+ // the edit screen for the entity across all features — in a
460
+ // single-feature setup that's the same feature as the active one, in
461
+ // multi-feature the edit could theoretically live in a different
462
+ // feature (one that shares the entity).
463
+ const editScreen = findEditScreenForEntity(app.features, entityName);
464
+ if (editScreen) {
465
+ // editScreen.id is already short form; lastSegment is a no-op
466
+ // safety net here, kept for symmetry with the other call sites.
467
+ navigateWithReturnTo(nav, { screenId: lastSegment(editScreen.id), entityId: row.id }, host);
468
+ }
469
+ };
470
+ }, [app, activeScreen, onRowClick, nav, qn, entityId]);
471
+ // Copy-link action (Issue #912) for entityEdit update screens. Builds
472
+ // the absolute permalink URL from the current route + copies it —
473
+ // `navigator`/`window` are allowed here (renderer/web, not a
474
+ // platform-neutral package). No button without entityId (create-mode).
475
+ // Silent-catch on clipboard error (non-secure context) mirrors the
476
+ // existing pattern in pat-tokens-screen.tsx.
477
+ const effectiveOnCopyLink = useMemo(() => {
478
+ const route = nav.route;
479
+ if (route?.entityId === undefined)
480
+ return undefined;
481
+ return async () => {
482
+ const url = `${window.location.origin}${nav.hrefFor(route)}`;
483
+ try {
484
+ await navigator.clipboard.writeText(url);
485
+ }
486
+ catch {
487
+ // clipboard blocked (non-secure context) — no fallback UI needed here
488
+ }
489
+ };
490
+ }, [nav]);
491
+ if (feature === undefined || activeScreen === undefined) {
492
+ const landingExists = findOwnerFeature(app.features, fallbackQn) !== undefined;
493
+ return (_jsx(ScreenMissingState, { ...(landingExists && { homeScreenId: lastSegment(fallbackQn) }), screenQn: qn }));
494
+ }
495
+ // KumikoScreen takes a single-feature schema: the feature owning the active screen.
496
+ const schemaForScreen = feature;
497
+ return (_jsx(ErrorBoundary, { scope: "screen", ...(onBoundaryError !== undefined && { onError: onBoundaryError }), fallback: ({ error, reset }) => (_jsx(ScreenErrorFallback, { screen: qn, error: error, onReset: reset })), children: _jsx(KumikoScreen, { schema: schemaForScreen, qn: qn, ...(translate !== undefined && { translate }), ...(entityId !== undefined && { entityId }), onRowClick: effectiveOnRowClick, ...(effectiveOnCopyLink !== undefined && { onCopyLink: effectiveOnCopyLink }) }) }, `${qn}/${entityId ?? ""}`));
498
+ }
@@ -0,0 +1,36 @@
1
+ import type { ReactNode } from "react";
2
+ import { type Root } from "react-dom/client";
3
+ import type { Dispatcher, LocaleResolver } from "../../headless/index.ts";
4
+ import { type Formality, type PrimitivesRegistry } from "../../index.ts";
5
+ import { type ClientFeatureDefinition } from "./client-plugin.tsx";
6
+ export type PublicRoute = {
7
+ /** Exact window.location.pathname match (matched once on mount; every
8
+ * apex page is a full-page reload, no SPA router). */
9
+ readonly path: string;
10
+ readonly component: ReactNode;
11
+ };
12
+ export type CreatePublicSurfaceOptions = {
13
+ readonly routes: readonly PublicRoute[];
14
+ /** Rendered when no route.path matches the current path. */
15
+ readonly fallback?: ReactNode;
16
+ readonly rootId?: string;
17
+ readonly locale?: LocaleResolver;
18
+ readonly primitives?: Partial<PrimitivesRegistry>;
19
+ /** Dispatcher for handler calls (e.g. an anonymous deletion request).
20
+ * Auth screens don't need it (fetch via auth-client), but it's there for
21
+ * dispatching public flows. Default: createLiveDispatcher(). */
22
+ readonly dispatcher?: Dispatcher;
23
+ /** Feature client extensions — ONLY `providers` + `translations` are
24
+ * stacked. `gates` are deliberately ignored: an AuthGate would lock the
25
+ * public surface behind login. */
26
+ readonly clientFeatures?: readonly ClientFeatureDefinition[];
27
+ /** Page chrome around the matched content (apex/marketing layout). */
28
+ readonly shell?: (props: {
29
+ readonly children: ReactNode;
30
+ }) => ReactNode;
31
+ /** Wording for every page of this surface. Default: `"informal"`. */
32
+ readonly formality?: Formality;
33
+ };
34
+ export declare function createPublicSurface(options: CreatePublicSurfaceOptions): {
35
+ readonly root: Root;
36
+ };
@@ -0,0 +1,40 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { createRoot } from "react-dom/client";
3
+ import { DispatcherProvider, FormalityProvider, kumikoDefaultTranslations, LocaleProvider, PrimitivesProvider, } from "../../index.js";
4
+ import { createLiveDispatcher } from "../../live/index.js";
5
+ import { defaultPrimitives } from "../primitives/index.js";
6
+ import { ToastProvider } from "../primitives/toast.js";
7
+ import { createBrowserLocaleResolver } from "./browser-locale.js";
8
+ import { stackWrappers } from "./client-plugin.js";
9
+ import { DocumentLangSync } from "./document-lang-sync.js";
10
+ function matchRoute(options, pathname) {
11
+ for (const route of options.routes) {
12
+ if (route.path === pathname)
13
+ return route.component;
14
+ }
15
+ return options.fallback ?? null;
16
+ }
17
+ export function createPublicSurface(options) {
18
+ const rootId = options.rootId ?? "root";
19
+ const container = document.getElementById(rootId);
20
+ if (!container) {
21
+ throw new Error(`createPublicSurface: DOM element #${rootId} not found. Make sure your HTML has a matching <div id="${rootId}"></div> before the bundle loads.`);
22
+ }
23
+ const dispatcher = options.dispatcher ?? createLiveDispatcher();
24
+ const primitives = { ...defaultPrimitives, ...(options.primitives ?? {}) };
25
+ const localeResolver = options.locale ?? createBrowserLocaleResolver();
26
+ const clientFeatures = options.clientFeatures ?? [];
27
+ const providers = clientFeatures.flatMap((f) => f.providers ?? []);
28
+ const fallbackBundles = [
29
+ ...clientFeatures.flatMap((f) => (f.translations !== undefined ? [f.translations] : [])),
30
+ kumikoDefaultTranslations,
31
+ ];
32
+ const pathname = typeof window !== "undefined" ? window.location.pathname : "";
33
+ const matched = matchRoute(options, pathname);
34
+ const Shell = options.shell;
35
+ const content = Shell !== undefined ? _jsx(Shell, { children: matched }) : matched;
36
+ const tree = (_jsx(LocaleProvider, { resolver: localeResolver, fallbackBundles: fallbackBundles, children: _jsxs(FormalityProvider, { formality: options.formality ?? "informal", children: [_jsx(DocumentLangSync, { resolver: localeResolver }), _jsx(PrimitivesProvider, { value: primitives, children: _jsx(DispatcherProvider, { dispatcher: dispatcher, children: _jsx(ToastProvider, { children: stackWrappers(providers, content) }) }) })] }) }));
37
+ const root = createRoot(container);
38
+ root.render(tree);
39
+ return { root };
40
+ }
@@ -0,0 +1,3 @@
1
+ import { type ReactNode } from "react";
2
+ import { type DashboardBodyProps } from "../../index.ts";
3
+ export declare function WebDashboardBody({ featureName, screen, translate, }: DashboardBodyProps): ReactNode;