@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,35 @@
1
+ import { type ReactNode } from "react";
2
+ /** Wizard step overview — numbered chips with a connector line between
3
+ * them. With `onStepSelect`, done chips render as buttons for jumping back
4
+ * (every non-current chip with `selectableSteps="all"`); the current chip
5
+ * never does. `doneSteps` overrides the position-based done state. With
6
+ * `onStepSelect` and `selectableSteps="all"` the narrow-viewport label becomes
7
+ * a dropdown listing every step (same rows as the rail), so phones can jump
8
+ * too. Three visual states, none conveyed by color alone:
9
+ * done (checkmark replaces the number, `aria-current` absent, a sr-only
10
+ * label says so since the number itself is gone), current (`aria-current
11
+ * ="step"`, own background), upcoming (dimmed, number visible). Below
12
+ * `sm` the chip row hides in favor of `compactLabel` (seven step names
13
+ * don't fit on a phone) — both live in the DOM, Tailwind's
14
+ * `hidden`/`sm:hidden` pair picks the visible one per viewport (same
15
+ * pattern as embedded-list-input.tsx's desktop/mobile split). */
16
+ export declare function StepBar({ steps, currentIndex, compactLabel, onStepSelect, doneSteps, selectableSteps, narrowLayout, orientation, heading, description, subtitles, upNext, testId, compactTestId, }: {
17
+ readonly steps: readonly string[];
18
+ readonly currentIndex: number;
19
+ readonly compactLabel: string;
20
+ readonly onStepSelect?: (index: number) => void;
21
+ readonly doneSteps?: readonly boolean[];
22
+ readonly selectableSteps?: "done" | "all";
23
+ readonly narrowLayout?: "label" | "steps";
24
+ readonly orientation?: "horizontal" | "vertical";
25
+ readonly heading?: string;
26
+ readonly description?: string;
27
+ readonly subtitles?: readonly (string | undefined)[];
28
+ readonly upNext?: {
29
+ readonly heading: string;
30
+ readonly title: string;
31
+ readonly subtitle?: string;
32
+ };
33
+ readonly testId?: string;
34
+ readonly compactTestId?: string;
35
+ }): ReactNode;
@@ -0,0 +1,60 @@
1
+ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Check, ChevronDown } from "lucide-react";
3
+ import { useId, useRef, useState } from "react";
4
+ import { useTranslation } from "../../index.js";
5
+ import { cn } from "../lib/cn.js";
6
+ const CHIP_CLASS = "flex items-center gap-1.5 rounded-full px-3 py-1 text-sm transition-colors";
7
+ function chipTestId(testId, index) {
8
+ return testId !== undefined ? `${testId}-step-${index}` : undefined;
9
+ }
10
+ function StepRailRow({ index, label, subtitle, subtitleTestId, rowTestId, state: { isCurrent, isDone, isSelectable }, onSelect, doneLabel, minHeightClass = "min-h-9", }) {
11
+ const rowClass = cn("flex w-full items-center gap-2.5 rounded-md px-2 py-1 text-left text-sm", minHeightClass, isCurrent && "bg-primary/10 font-semibold text-primary", isDone && "text-foreground", !isCurrent && !isDone && "text-foreground-secondary");
12
+ const content = (_jsxs(_Fragment, { children: [_jsx("span", { "aria-hidden": "true", className: cn("flex size-[22px] shrink-0 items-center justify-center rounded-full border text-xs font-semibold", isCurrent && "border-primary bg-primary text-primary-foreground", isDone && "border-status-ok-surface bg-status-ok-surface text-status-ok", !isCurrent && !isDone && "border-input bg-card text-foreground-secondary"), children: isDone ? _jsx(Check, { className: "size-3" }) : index + 1 }), isDone && _jsx("span", { className: "sr-only", children: doneLabel }), _jsxs("span", { className: "flex min-w-0 flex-col", children: [_jsx("span", { className: "truncate", children: label }), subtitle !== undefined && (_jsx("span", { "data-testid": subtitleTestId, className: "truncate text-xs font-normal text-foreground-secondary", children: subtitle }))] })] }));
13
+ return isSelectable ? (_jsx("button", { type: "button", onClick: () => onSelect?.(index), "data-testid": rowTestId, className: cn(rowClass, "hover:bg-muted-foreground/10"), children: content })) : (_jsx("span", { "aria-current": isCurrent ? "step" : undefined, "data-testid": rowTestId, className: rowClass, children: content }));
14
+ }
15
+ function CompactStepPicker({ steps, compactLabel, subtitles, stepState, onStepSelect, compactTestId, doneLabel, }) {
16
+ const [open, setOpen] = useState(false);
17
+ const listId = useId();
18
+ const toggleRef = useRef(null);
19
+ return (_jsxs("div", { onKeyDown: (event) => {
20
+ if (event.key === "Escape" && open) {
21
+ setOpen(false);
22
+ toggleRef.current?.focus();
23
+ }
24
+ }, children: [_jsxs("button", { ref: toggleRef, type: "button", "aria-expanded": open, "aria-controls": open ? listId : undefined, "data-testid": compactTestId, onClick: () => setOpen((wasOpen) => !wasOpen), className: "flex min-h-11 w-full items-center justify-between gap-2 rounded-md border border-border bg-card px-3 text-left text-sm font-medium text-foreground hover:bg-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", children: [compactLabel, _jsx(ChevronDown, { "aria-hidden": "true", className: cn("size-4 shrink-0 transition-transform", open && "rotate-180") })] }), open && (_jsx("ol", { id: listId, className: "m-0 mt-1 flex list-none flex-col gap-0.5 rounded-md border border-border bg-card p-1", children: steps.map((label, i) => (_jsx("li", { children: _jsx(StepRailRow, { index: i, label: label, subtitle: subtitles?.[i], subtitleTestId: undefined, rowTestId: chipTestId(compactTestId, i), state: stepState(i), onSelect: (index) => {
25
+ setOpen(false);
26
+ onStepSelect(index);
27
+ }, doneLabel: doneLabel, minHeightClass: "min-h-11" }) }, `${i}-${label}`))) }))] }));
28
+ }
29
+ /** Wizard step overview — numbered chips with a connector line between
30
+ * them. With `onStepSelect`, done chips render as buttons for jumping back
31
+ * (every non-current chip with `selectableSteps="all"`); the current chip
32
+ * never does. `doneSteps` overrides the position-based done state. With
33
+ * `onStepSelect` and `selectableSteps="all"` the narrow-viewport label becomes
34
+ * a dropdown listing every step (same rows as the rail), so phones can jump
35
+ * too. Three visual states, none conveyed by color alone:
36
+ * done (checkmark replaces the number, `aria-current` absent, a sr-only
37
+ * label says so since the number itself is gone), current (`aria-current
38
+ * ="step"`, own background), upcoming (dimmed, number visible). Below
39
+ * `sm` the chip row hides in favor of `compactLabel` (seven step names
40
+ * don't fit on a phone) — both live in the DOM, Tailwind's
41
+ * `hidden`/`sm:hidden` pair picks the visible one per viewport (same
42
+ * pattern as embedded-list-input.tsx's desktop/mobile split). */
43
+ export function StepBar({ steps, currentIndex, compactLabel, onStepSelect, doneSteps, selectableSteps = "done", narrowLayout = "label", orientation = "horizontal", heading, description, subtitles, upNext, testId, compactTestId, }) {
44
+ const t = useTranslation();
45
+ const stepState = (i) => {
46
+ const isCurrent = i === currentIndex;
47
+ const isDone = !isCurrent && (doneSteps !== undefined ? doneSteps[i] === true : i < currentIndex);
48
+ const isSelectable = onStepSelect !== undefined && !isCurrent && (selectableSteps === "all" || isDone);
49
+ return { isCurrent, isDone, isSelectable };
50
+ };
51
+ const compactPicker = onStepSelect !== undefined && selectableSteps === "all";
52
+ const pickerElement = compactPicker ? (_jsx(CompactStepPicker, { steps: steps, compactLabel: compactLabel, subtitles: subtitles, stepState: stepState, onStepSelect: onStepSelect, compactTestId: compactTestId, doneLabel: t("kumiko.widget.step-bar.done") })) : null;
53
+ if (orientation === "vertical") {
54
+ return (_jsxs(_Fragment, { children: [_jsxs("nav", { className: "hidden w-[280px] shrink-0 flex-col gap-4 overflow-y-auto border-r border-border bg-muted px-6 py-7 lg:flex", children: [heading !== undefined && (_jsxs("div", { className: "flex flex-col gap-1", children: [_jsx("span", { className: "text-sm font-semibold text-foreground", children: heading }), description !== undefined && (_jsx("span", { className: "text-[13px] text-foreground-secondary", children: description }))] })), _jsx("ol", { "data-testid": testId, className: "m-0 flex list-none flex-col gap-0.5 p-0", children: steps.map((label, i) => (_jsx("li", { children: _jsx(StepRailRow, { index: i, label: label, subtitle: subtitles?.[i], subtitleTestId: testId !== undefined ? `${testId}-subtitle-${i}` : undefined, rowTestId: chipTestId(testId, i), state: stepState(i), onSelect: onStepSelect, doneLabel: t("kumiko.widget.step-bar.done") }) }, `${i}-${label}`))) }), upNext !== undefined && (_jsxs("div", { "data-testid": testId !== undefined ? `${testId}-up-next` : undefined, className: "mt-2 flex flex-col gap-1 rounded-md border border-border bg-card px-3 py-2.5", children: [_jsx("span", { className: "text-xs font-semibold uppercase tracking-wider text-muted-foreground", children: upNext.heading }), _jsx("span", { className: "text-sm font-medium text-foreground", children: upNext.title }), upNext.subtitle !== undefined && (_jsx("span", { className: "text-xs text-foreground-secondary", children: upNext.subtitle }))] }))] }), compactPicker ? (_jsx("div", { className: "px-4 pt-3 lg:hidden", children: pickerElement })) : (_jsx("p", { "data-testid": compactTestId, className: "px-4 pt-3 text-sm text-muted-foreground lg:hidden", children: compactLabel }))] }));
55
+ }
56
+ return (_jsxs(_Fragment, { children: [_jsx("ol", { "data-testid": testId, className: cn("items-center gap-2", narrowLayout === "steps" ? "flex flex-wrap" : "hidden sm:flex sm:flex-wrap"), children: steps.map((label, i) => {
57
+ const { isCurrent, isDone, isSelectable } = stepState(i);
58
+ return (_jsxs("li", { className: "flex items-center gap-2", children: [i > 0 && _jsx("span", { "aria-hidden": "true", className: "h-px w-4 bg-border" }), isSelectable ? (_jsxs("button", { type: "button", onClick: () => onStepSelect?.(i), "data-testid": chipTestId(testId, i), className: cn(CHIP_CLASS, isDone ? "text-primary" : "text-muted-foreground", "max-sm:min-h-11 hover:bg-primary/10 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"), children: [isDone ? (_jsxs(_Fragment, { children: [_jsx(Check, { "aria-hidden": "true", className: "size-3.5" }), _jsx("span", { className: "sr-only", children: t("kumiko.widget.step-bar.done") })] })) : (_jsx("span", { className: "text-xs font-semibold", children: i + 1 })), label] })) : (_jsxs("span", { "aria-current": isCurrent ? "step" : undefined, "data-testid": chipTestId(testId, i), className: cn(CHIP_CLASS, isCurrent && "bg-primary font-semibold text-primary-foreground", isDone && "text-primary", !isCurrent && !isDone && "text-muted-foreground"), children: [isDone ? (_jsxs(_Fragment, { children: [_jsx(Check, { "aria-hidden": "true", className: "size-3.5" }), _jsx("span", { className: "sr-only", children: t("kumiko.widget.step-bar.done") })] })) : (_jsx("span", { className: "text-xs font-semibold", children: i + 1 })), label] }))] }, `${i}-${label}`));
59
+ }) }), compactPicker ? (_jsx("div", { className: narrowLayout === "steps" ? "hidden" : "sm:hidden", children: pickerElement })) : (_jsx("p", { "data-testid": compactTestId, className: cn("text-sm text-muted-foreground", narrowLayout === "steps" ? "hidden" : "sm:hidden"), children: compactLabel }))] }));
60
+ }
@@ -0,0 +1,24 @@
1
+ import { type ReactNode } from "react";
2
+ export type UploadZoneProps = {
3
+ /** Uploads a single file (POST + optional follow-up mutation). Throws on
4
+ * failure — the message ends up in the row's error line. Runs in
5
+ * parallel per file within a batch (no sequential waiting). */
6
+ readonly onUpload: (file: File) => Promise<void>;
7
+ readonly title: ReactNode;
8
+ readonly hint?: ReactNode;
9
+ readonly accept?: readonly string[];
10
+ /** Allow multiple files per pick/drop. Defaults to true. */
11
+ readonly multiple?: boolean;
12
+ /** Forwarded to the file input: a phone opens that camera directly instead
13
+ * of offering camera, gallery and files. Leave unset to keep the choice. */
14
+ readonly capture?: "environment" | "user";
15
+ readonly disabled?: boolean;
16
+ readonly testId?: string;
17
+ };
18
+ export declare function matchesAccept(file: File, accept?: readonly string[]): boolean;
19
+ /** Drop zone + multi-file picker with a per-file status row (uploading/done/
20
+ * error). For screens that accept several files and upload them
21
+ * independently — unlike `FileField` (single file, FileRef value inside a
22
+ * form field). `onUpload` decides what "upload" means (storage POST, ingest
23
+ * mutation, or both); the zone only tracks uploading/done/error. */
24
+ export declare function UploadZone({ onUpload, title, hint, accept, multiple, capture, disabled, testId, }: UploadZoneProps): ReactNode;
@@ -0,0 +1,108 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { CheckCircle2, FileUp, Loader2, TriangleAlert, Upload } from "lucide-react";
3
+ import { useId, useRef, useState } from "react";
4
+ import { useTranslation } from "../../index.js";
5
+ import { toAcceptAttr } from "../lib/accept-attr.js";
6
+ import { cn } from "../lib/cn.js";
7
+ import { resizeImageBeforeUpload } from "../lib/resize-image.js";
8
+ const STATUS_ICON = {
9
+ uploading: _jsx(Loader2, { className: "size-3.5 animate-spin text-muted-foreground", "aria-hidden": "true" }),
10
+ done: _jsx(CheckCircle2, { className: "size-3.5 text-primary", "aria-hidden": "true" }),
11
+ error: _jsx(TriangleAlert, { className: "size-3.5 text-destructive", "aria-hidden": "true" }),
12
+ };
13
+ const STATUS_LABEL_KEY = {
14
+ uploading: "kumiko.widget.upload.uploading",
15
+ done: "kumiko.widget.upload.done",
16
+ error: "kumiko.widget.upload.error",
17
+ };
18
+ // `accept` on the native <input> only filters the file-picker dialog — a
19
+ // drag&drop drop is never routed through it, so any file type lands in
20
+ // `onUpload` regardless of what `accept` promises. Same matching rules as
21
+ // the native attribute: MIME type (with an optional "type/*" wildcard) or
22
+ // file extension.
23
+ export function matchesAccept(file, accept) {
24
+ if (accept === undefined || accept.length === 0)
25
+ return true;
26
+ const name = file.name.toLowerCase();
27
+ const type = file.type.toLowerCase();
28
+ return accept.some((raw) => {
29
+ const a = raw.toLowerCase();
30
+ if (a.includes("/"))
31
+ return a.endsWith("/*") ? type.startsWith(a.slice(0, -1)) : type === a;
32
+ return name.endsWith(a.startsWith(".") ? a : `.${a}`);
33
+ });
34
+ }
35
+ function partitionByAccept(files, accept) {
36
+ const accepted = [];
37
+ const rejected = [];
38
+ for (const file of files)
39
+ (matchesAccept(file, accept) ? accepted : rejected).push(file);
40
+ return [accepted, rejected];
41
+ }
42
+ /** Drop zone + multi-file picker with a per-file status row (uploading/done/
43
+ * error). For screens that accept several files and upload them
44
+ * independently — unlike `FileField` (single file, FileRef value inside a
45
+ * form field). `onUpload` decides what "upload" means (storage POST, ingest
46
+ * mutation, or both); the zone only tracks uploading/done/error. */
47
+ export function UploadZone({ onUpload, title, hint, accept, multiple = true, capture, disabled, testId, }) {
48
+ const t = useTranslation();
49
+ const inputId = useId();
50
+ const inputRef = useRef(null);
51
+ const [rows, setRows] = useState([]);
52
+ const [dragOver, setDragOver] = useState(false);
53
+ // `crypto.randomUUID` only exists in a secure context — a plain-HTTP LAN
54
+ // preview leaves it undefined. These ids are React keys/row ids, not
55
+ // globally unique identifiers, so a per-instance counter is enough.
56
+ const nextRowId = useRef(0);
57
+ async function uploadOne(file) {
58
+ const rowId = String(nextRowId.current++);
59
+ const uploadFile = await resizeImageBeforeUpload(file);
60
+ setRows((prev) => [...prev, { id: rowId, fileName: uploadFile.name, status: "uploading" }]);
61
+ try {
62
+ await onUpload(uploadFile);
63
+ setRows((prev) => prev.map((row) => (row.id === rowId ? { ...row, status: "done" } : row)));
64
+ }
65
+ catch (cause) {
66
+ const message = cause instanceof Error ? cause.message : t("kumiko.widget.upload.error");
67
+ setRows((prev) => prev.map((row) => (row.id === rowId ? { ...row, status: "error", error: message } : row)));
68
+ }
69
+ }
70
+ async function uploadFiles(files) {
71
+ if (files === null || files.length === 0)
72
+ return;
73
+ const picked = multiple ? Array.from(files) : files[0] !== undefined ? [files[0]] : [];
74
+ // Reset before awaits so re-picking the same file during a slow upload still fires change.
75
+ if (inputRef.current)
76
+ inputRef.current.value = "";
77
+ const [accepted, rejected] = partitionByAccept(picked, accept);
78
+ for (const file of rejected) {
79
+ setRows((prev) => [
80
+ ...prev,
81
+ {
82
+ id: String(nextRowId.current++),
83
+ fileName: file.name,
84
+ status: "error",
85
+ error: t("kumiko.widget.upload.rejected-type"),
86
+ },
87
+ ]);
88
+ }
89
+ await Promise.all(accepted.map((file) => uploadOne(file)));
90
+ }
91
+ function handleDrop(e) {
92
+ e.preventDefault();
93
+ setDragOver(false);
94
+ if (disabled === true)
95
+ return;
96
+ void uploadFiles(e.dataTransfer.files);
97
+ }
98
+ const acceptAttr = toAcceptAttr(accept);
99
+ return (_jsxs("div", { "data-testid": testId, className: "flex flex-col gap-4", children: [_jsxs("label", { htmlFor: inputId, onDragOver: (e) => {
100
+ e.preventDefault();
101
+ if (disabled !== true)
102
+ setDragOver(true);
103
+ }, onDragLeave: (e) => {
104
+ if (!(e.relatedTarget instanceof Node) || !e.currentTarget.contains(e.relatedTarget)) {
105
+ setDragOver(false);
106
+ }
107
+ }, onDrop: handleDrop, "data-testid": testId !== undefined ? `${testId}-dropzone` : undefined, className: cn("flex w-full cursor-pointer flex-col items-center gap-3 rounded-lg border-2 border-dashed p-10 text-center transition-colors has-[:focus-visible]:ring-2 has-[:focus-visible]:ring-ring has-[:focus-visible]:ring-offset-2", dragOver ? "border-primary bg-muted/40" : "border-border", disabled === true && "cursor-not-allowed opacity-50"), children: [_jsx(Upload, { className: "size-8 text-muted-foreground", "aria-hidden": "true" }), _jsx("span", { className: "text-sm", children: title }), hint !== undefined && _jsx("span", { className: "text-sm text-muted-foreground", children: hint }), _jsx("input", { ref: inputRef, id: inputId, type: "file", multiple: multiple, className: "sr-only", "data-testid": testId !== undefined ? `${testId}-input` : undefined, disabled: disabled, ...(acceptAttr !== undefined && { accept: acceptAttr }), ...(capture !== undefined && { capture }), onChange: (e) => void uploadFiles(e.target.files) })] }), rows.length > 0 && (_jsx("ul", { className: "flex flex-col gap-2", children: rows.map((row) => (_jsxs("li", { "data-testid": testId !== undefined ? `${testId}-row` : undefined, className: "flex items-center justify-between gap-3 rounded-md border border-border px-4 py-2", children: [_jsxs("div", { className: "flex min-w-0 items-center gap-2", children: [_jsx(FileUp, { className: "size-4 shrink-0 text-muted-foreground", "aria-hidden": "true" }), _jsx("span", { className: "truncate text-sm", children: row.fileName })] }), _jsxs("output", { className: "flex shrink-0 items-center gap-1.5 text-xs text-muted-foreground", children: [STATUS_ICON[row.status], _jsx("span", { className: "sr-only", children: t(STATUS_LABEL_KEY[row.status]) }), row.status === "error" && row.error !== undefined && _jsx("span", { children: row.error })] })] }, row.id))) }))] }));
108
+ }
@@ -0,0 +1,20 @@
1
+ /** Formular-State für Rechner-Screens: ein Draft-Objekt + `patch` für
2
+ * Teil-Updates + `field(name)` das die `{ id, name, value, onChange }`-Props
3
+ * fertig für die Feld-Widgets (NumberField/MoneyField/PercentField) liefert.
4
+ * Ersetzt das pro Screen wiederholte Draft-Interface + patch-Helper.
5
+ * `idPrefix` verhindert doppelte DOM-`id`s, wenn mehrere `useDraft`-Formulare
6
+ * mit gleichnamigen Feldern auf derselben Seite gemountet werden — `name`
7
+ * bleibt der reine Key fürs Form-Payload. */
8
+ export declare function useDraft<T extends object>(defaults: T, options?: {
9
+ readonly idPrefix?: string;
10
+ }): {
11
+ readonly draft: T;
12
+ readonly patch: (changes: Partial<T>) => void;
13
+ readonly reset: () => void;
14
+ readonly field: <K extends keyof T>(name: K) => {
15
+ readonly id: string;
16
+ readonly name: string;
17
+ readonly value: T[K];
18
+ readonly onChange: (v: T[K]) => void;
19
+ };
20
+ };
@@ -0,0 +1,21 @@
1
+ import { useCallback, useState } from "react";
2
+ /** Formular-State für Rechner-Screens: ein Draft-Objekt + `patch` für
3
+ * Teil-Updates + `field(name)` das die `{ id, name, value, onChange }`-Props
4
+ * fertig für die Feld-Widgets (NumberField/MoneyField/PercentField) liefert.
5
+ * Ersetzt das pro Screen wiederholte Draft-Interface + patch-Helper.
6
+ * `idPrefix` verhindert doppelte DOM-`id`s, wenn mehrere `useDraft`-Formulare
7
+ * mit gleichnamigen Feldern auf derselben Seite gemountet werden — `name`
8
+ * bleibt der reine Key fürs Form-Payload. */
9
+ export function useDraft(defaults, options) {
10
+ const idPrefix = options?.idPrefix;
11
+ const [draft, setDraft] = useState(defaults);
12
+ const patch = useCallback((changes) => setDraft((d) => ({ ...d, ...changes })), []);
13
+ const reset = useCallback(() => setDraft(defaults), [defaults]);
14
+ const field = useCallback((name) => ({
15
+ id: idPrefix !== undefined ? `${idPrefix}-${String(name)}` : String(name),
16
+ name: String(name),
17
+ value: draft[name],
18
+ onChange: (v) => setDraft((d) => ({ ...d, [name]: v })),
19
+ }), [draft, idPrefix]);
20
+ return { draft, patch, reset, field };
21
+ }
@@ -0,0 +1,21 @@
1
+ import { type KeyboardEvent, type PointerEvent } from "react";
2
+ export type DragDelta = {
3
+ readonly dx: number;
4
+ readonly dy: number;
5
+ };
6
+ type PointerDragOptions<TStart> = {
7
+ readonly onStart: (event: PointerEvent<HTMLElement>) => TStart;
8
+ readonly onMove: (start: TStart, delta: DragDelta) => void;
9
+ readonly onEnd?: () => void;
10
+ };
11
+ type PointerDragHandlers = {
12
+ readonly onPointerDown: (event: PointerEvent<HTMLElement>) => void;
13
+ readonly onPointerMove: (event: PointerEvent<HTMLElement>) => void;
14
+ readonly onPointerUp: (event: PointerEvent<HTMLElement>) => void;
15
+ readonly onPointerCancel: (event: PointerEvent<HTMLElement>) => void;
16
+ readonly onLostPointerCapture: (event: PointerEvent<HTMLElement>) => void;
17
+ };
18
+ export declare function usePointerDrag<TStart>({ onStart, onMove, onEnd, }: PointerDragOptions<TStart>): PointerDragHandlers;
19
+ /** Arrow keys as a pixel delta (Shift = larger step); undefined for any other key. */
20
+ export declare function arrowKeyDelta(event: KeyboardEvent<HTMLElement>): DragDelta | undefined;
21
+ export {};
@@ -0,0 +1,53 @@
1
+ import { useRef } from "react";
2
+ export function usePointerDrag({ onStart, onMove, onEnd, }) {
3
+ const dragRef = useRef(null);
4
+ const onPointerDown = (event) => {
5
+ event.preventDefault();
6
+ event.currentTarget.setPointerCapture(event.pointerId);
7
+ dragRef.current = { startX: event.clientX, startY: event.clientY, start: onStart(event) };
8
+ // Without the lock a fast drag selects the text underneath instead of just dragging.
9
+ document.body.style.setProperty("user-select", "none");
10
+ };
11
+ const onPointerMove = (event) => {
12
+ const drag = dragRef.current;
13
+ if (drag !== null) {
14
+ onMove(drag.start, { dx: event.clientX - drag.startX, dy: event.clientY - drag.startY });
15
+ }
16
+ };
17
+ const endDrag = (event) => {
18
+ if (event.currentTarget.hasPointerCapture(event.pointerId)) {
19
+ event.currentTarget.releasePointerCapture(event.pointerId);
20
+ }
21
+ const wasDragging = dragRef.current !== null;
22
+ dragRef.current = null;
23
+ document.body.style.removeProperty("user-select");
24
+ // pointerup and the lostpointercapture it triggers both land here; only the first ends a drag.
25
+ if (wasDragging)
26
+ onEnd?.();
27
+ };
28
+ return {
29
+ onPointerDown,
30
+ onPointerMove,
31
+ onPointerUp: endDrag,
32
+ onPointerCancel: endDrag,
33
+ onLostPointerCapture: endDrag,
34
+ };
35
+ }
36
+ const KEY_STEP_PX = 16;
37
+ const KEY_STEP_SHIFT_PX = 40;
38
+ /** Arrow keys as a pixel delta (Shift = larger step); undefined for any other key. */
39
+ export function arrowKeyDelta(event) {
40
+ const step = event.shiftKey ? KEY_STEP_SHIFT_PX : KEY_STEP_PX;
41
+ switch (event.key) {
42
+ case "ArrowLeft":
43
+ return { dx: -step, dy: 0 };
44
+ case "ArrowRight":
45
+ return { dx: step, dy: 0 };
46
+ case "ArrowUp":
47
+ return { dx: 0, dy: -step };
48
+ case "ArrowDown":
49
+ return { dx: 0, dy: step };
50
+ default:
51
+ return undefined;
52
+ }
53
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@cosmicdrift/kumiko-renderer",
3
- "version": "0.373.0",
4
- "description": "Platform-agnostic React renderer for Kumiko screens. Contains the shared logic — primitives-contract, hooks, KumikoScreen, navigation & SSE abstractions — that any platform-specific renderer (web, native) composes. No DOM, no EventSource, no react-dom.",
3
+ "version": "0.377.0",
4
+ "description": "React renderer for Kumiko screens. The root export holds the platform-agnostic logic (primitives contract, hooks, KumikoScreen, navigation and SSE abstractions); ./headless the DOM-free UI logic, ./live the HTTP dispatcher, ./web the browser bindings (HTML primitives, history navigation, EventSource live events, createKumikoApp).",
5
5
  "license": "BUSL-1.1",
6
6
  "author": "Marc Frost <marc@cosmicdriftgamestudio.com>",
7
7
  "type": "module",
@@ -12,23 +12,90 @@
12
12
  ".": {
13
13
  "types": "./dist/index.d.ts",
14
14
  "default": "./dist/index.js"
15
+ },
16
+ "./headless": {
17
+ "types": "./dist/headless/index.d.ts",
18
+ "default": "./dist/headless/index.js"
19
+ },
20
+ "./headless/apex": {
21
+ "types": "./dist/headless/apex/index.d.ts",
22
+ "default": "./dist/headless/apex/index.js"
23
+ },
24
+ "./headless/dispatcher": {
25
+ "types": "./dist/headless/dispatcher/index.d.ts",
26
+ "default": "./dist/headless/dispatcher/index.js"
27
+ },
28
+ "./headless/locale-routing": {
29
+ "types": "./dist/headless/locale-routing/index.d.ts",
30
+ "default": "./dist/headless/locale-routing/index.js"
31
+ },
32
+ "./live": {
33
+ "types": "./dist/live/index.d.ts",
34
+ "default": "./dist/live/index.js"
35
+ },
36
+ "./web": {
37
+ "types": "./dist/web/index.d.ts",
38
+ "default": "./dist/web/index.js"
39
+ },
40
+ "./web/styles.css": "./src/web/styles.css",
41
+ "./web/theme-plugin": {
42
+ "types": "./dist/web/theme-plugin.d.ts",
43
+ "default": "./dist/web/theme-plugin.js"
15
44
  }
16
45
  },
17
46
  "dependencies": {
18
- "@cosmicdrift/kumiko-framework": "0.373.0",
19
- "@cosmicdrift/kumiko-headless": "0.373.0",
20
- "@cosmicdrift/kumiko-types": "0.373.0",
47
+ "@cosmicdrift/kumiko-framework": "0.377.0",
48
+ "@cosmicdrift/kumiko-types": "0.377.0",
49
+ "@radix-ui/react-dialog": "^1.1.15",
50
+ "@radix-ui/react-dropdown-menu": "^2.1.16",
51
+ "@radix-ui/react-label": "^2.1.8",
52
+ "@radix-ui/react-popover": "^1.1.15",
53
+ "@radix-ui/react-select": "^2.2.6",
54
+ "@radix-ui/react-separator": "^1.1.7",
55
+ "@radix-ui/react-slot": "^1.2.4",
56
+ "@radix-ui/react-toast": "^1.2.15",
57
+ "@radix-ui/react-tooltip": "^1.2.8",
58
+ "@tiptap/core": "^3.30.5",
59
+ "@tiptap/pm": "^3.30.5",
60
+ "@tiptap/react": "^3.30.5",
61
+ "@tiptap/starter-kit": "^3.30.5",
62
+ "@types/qrcode": "^1.5.5",
63
+ "class-variance-authority": "^0.7.1",
64
+ "clsx": "^2.1.1",
65
+ "cmdk": "^1.1.1",
66
+ "lucide-react": "^1.14.0",
67
+ "qrcode": "^1.5.4",
68
+ "radix-ui": "^1.4.3",
21
69
  "react": "^19.2.6",
70
+ "react-day-picker": "^10.0.0",
71
+ "react-dom": "^19.2.6",
72
+ "react-resizable-panels": "^4.12.2",
73
+ "tailwind-merge": "^3.6.0",
22
74
  "temporal-polyfill": "^0.3.2",
23
75
  "zod": "^4.4.3"
24
76
  },
77
+ "peerDependencies": {
78
+ "@tailwindcss/cli": "^4.3.0",
79
+ "tailwindcss": "^4.3.0"
80
+ },
81
+ "peerDependenciesMeta": {
82
+ "@tailwindcss/cli": {
83
+ "optional": false
84
+ },
85
+ "tailwindcss": {
86
+ "optional": false
87
+ }
88
+ },
25
89
  "devDependencies": {
90
+ "@cosmicdrift/kumiko-locale-de": "0.377.0",
91
+ "@cosmicdrift/kumiko-testing": "0.377.0",
92
+ "@tailwindcss/cli": "^4.3.0",
26
93
  "@testing-library/react": "^16.3.2",
94
+ "@testing-library/user-event": "^14.6.1",
27
95
  "@types/react": "^19.2.14",
28
96
  "@types/react-dom": "^19.2.3",
29
97
  "jsdom": "^29.1.1",
30
- "react-dom": "^19.2.6",
31
- "@cosmicdrift/kumiko-locale-de": "0.373.0"
98
+ "tailwindcss": "^4.3.0"
32
99
  },
33
100
  "repository": {
34
101
  "type": "git",
@@ -46,12 +113,43 @@
46
113
  ".": {
47
114
  "types": "./dist/index.d.ts",
48
115
  "default": "./dist/index.js"
116
+ },
117
+ "./headless": {
118
+ "types": "./dist/headless/index.d.ts",
119
+ "default": "./dist/headless/index.js"
120
+ },
121
+ "./headless/apex": {
122
+ "types": "./dist/headless/apex/index.d.ts",
123
+ "default": "./dist/headless/apex/index.js"
124
+ },
125
+ "./headless/dispatcher": {
126
+ "types": "./dist/headless/dispatcher/index.d.ts",
127
+ "default": "./dist/headless/dispatcher/index.js"
128
+ },
129
+ "./headless/locale-routing": {
130
+ "types": "./dist/headless/locale-routing/index.d.ts",
131
+ "default": "./dist/headless/locale-routing/index.js"
132
+ },
133
+ "./live": {
134
+ "types": "./dist/live/index.d.ts",
135
+ "default": "./dist/live/index.js"
136
+ },
137
+ "./web": {
138
+ "types": "./dist/web/index.d.ts",
139
+ "default": "./dist/web/index.js"
140
+ },
141
+ "./web/styles.css": "./src/web/styles.css",
142
+ "./web/theme-plugin": {
143
+ "types": "./dist/web/theme-plugin.d.ts",
144
+ "default": "./dist/web/theme-plugin.js"
49
145
  }
50
146
  }
51
147
  },
52
148
  "files": [
53
149
  "dist",
54
150
  "src/changes.json",
151
+ "src/web/styles.css",
152
+ "src/web/fonts",
55
153
  "README.md",
56
154
  "LICENSE"
57
155
  ]
package/src/changes.json CHANGED
@@ -1,4 +1,81 @@
1
1
  [
2
+ {
3
+ "version": "0.377.0",
4
+ "type": "improvement",
5
+ "title": "PlanCard ctaLink",
6
+ "detail": "PlanCard takes ctaLink ({ label, href, target? }) and renders it as a full-width link button in the footer instead of the cta button. The PlanCardLinkSlot type is exported from @cosmicdrift/kumiko-renderer/web next to PlanCardActionSlot."
7
+ },
8
+ {
9
+ "version": "0.377.0",
10
+ "type": "fix",
11
+ "title": "The entityEdit discard-confirm test waits for the form's mount effects before it types and clicks",
12
+ "detail": "The test rendered outside act and only waited for the input to appear. Under CPU load the form's mount effects (store subscription, dirty reporting) ran after the click, so the header action still had no discard confirm and the test failed. The render now runs inside act, so the detail query, the commit and the effects settle first. Test-only change, no runtime behavior changes."
13
+ },
14
+ {
15
+ "version": "0.377.0",
16
+ "type": "improvement",
17
+ "title": "headless and the live dispatcher moved into renderer",
18
+ "detail": "The headless UI logic is exported from @cosmicdrift/kumiko-renderer/headless (with /headless/apex, /headless/dispatcher and /headless/locale-routing), the HTTP dispatcher from @cosmicdrift/kumiko-renderer/live. @cosmicdrift/kumiko-headless and @cosmicdrift/kumiko-dispatcher-live now only re-export these subpaths and are removed after the consumer pass of wave 4.",
19
+ "migration": "Run bun kumiko-upgrade --apply, or bun kumiko codemod package-merge . --write. It rewrites imports of @cosmicdrift/kumiko-headless (and its subpaths) to @cosmicdrift/kumiko-renderer/headless and imports of @cosmicdrift/kumiko-dispatcher-live to @cosmicdrift/kumiko-renderer/live, and replaces both dependencies in package.json with kumiko-renderer.",
20
+ "codemod": "scripts/codemod/package-merge.ts"
21
+ },
22
+ {
23
+ "version": "0.377.0",
24
+ "type": "improvement",
25
+ "title": "renderer-web moved into renderer",
26
+ "detail": "The web bindings are exported from @cosmicdrift/kumiko-renderer/web, the stylesheet from @cosmicdrift/kumiko-renderer/web/styles.css and the Tailwind theme plugin from @cosmicdrift/kumiko-renderer/web/theme-plugin. @cosmicdrift/kumiko-renderer-web now only re-exports these and is removed after the consumer pass of wave 4.",
27
+ "migration": "Run bun kumiko-upgrade --apply, or bun kumiko codemod package-merge . --write. It rewrites imports and CSS @import lines of @cosmicdrift/kumiko-renderer-web (including /styles.css and /theme-plugin) to @cosmicdrift/kumiko-renderer/web and replaces the dependency in package.json with kumiko-renderer.",
28
+ "codemod": "scripts/codemod/package-merge.ts"
29
+ },
30
+ {
31
+ "version": "0.377.0",
32
+ "type": "improvement",
33
+ "title": "actionForm shows key figures from the handler's success payload",
34
+ "detail": "ActionFormScreenDefinition gets successFacts, a list of { field, label } entries read from the success payload and shown in the success box next to successLinks while the screen stays put. A number or string is one value, an array a comma-separated list of numbers, strings or { label } objects, a missing field is hidden. Mutually exclusive with redirect (boot validator). Default behaviour is unchanged."
35
+ },
36
+ {
37
+ "version": "0.377.0",
38
+ "type": "improvement",
39
+ "title": "A text field with format month renders a native month input",
40
+ "detail": "createTextField({ format: \"month\" }) renders <input type=\"month\"> and carries YYYY-MM. The schema builder validates the pattern server-side (an empty string is accepted for optional fields). New InputProps kind \"month\" for custom Input primitives.",
41
+ "migration": "Only custom CorePrimitives.Input implementations with an exhaustive switch over kind need a \"month\" branch; a text fallback is fine."
42
+ },
43
+ {
44
+ "version": "0.377.0",
45
+ "type": "improvement",
46
+ "title": "Array reference fields render as links in lists",
47
+ "detail": "A reference column over an array field renders one link per entry, labelled from the eagerloaded record or the label lookup, like single references. New CellLinkItem and RuntimeCellLinkItems exports from the headless view model; DataTableCell accepts linkItems."
48
+ },
49
+ {
50
+ "version": "0.377.0",
51
+ "type": "fix",
52
+ "title": "List empty state, sidebar rail cursor, toolbar description spacing and root form errors",
53
+ "detail": "The empty list no longer shows a second Create button when Create is already in the page header. The sidebar rail edge, which only toggles open and closed, shows a pointer cursor instead of a resize cursor. toolbarDescription always gets the standard bottom spacing, not only with fillsHeight. A server error without a field reference (path \"(root)\") shows once in the form banner instead of also at a field."
54
+ },
55
+ {
56
+ "version": "0.374.0",
57
+ "type": "improvement",
58
+ "title": "Success box with links, form reset and field placeholder",
59
+ "detail": "The actionForm success box shows the default text \"Done.\" (kumiko.actionForm.success) next to successMessage links, resetOnSuccess remounts the form with its initial values, and EditFieldSpec.placeholder reaches text, number and textarea inputs."
60
+ },
61
+ {
62
+ "version": "0.374.0",
63
+ "type": "improvement",
64
+ "title": "Client action registry for row actions",
65
+ "detail": "ClientActionsProvider, ActionNoticeProvider and runClientAction execute clientAction row actions on list, related list and record actions, with confirm, toast feedback and refetch."
66
+ },
67
+ {
68
+ "version": "0.374.0",
69
+ "type": "improvement",
70
+ "title": "actionForm load states and drawer row click",
71
+ "detail": "An actionForm with load queries by the route, drawer or URL id and shows loading, error, not-found and missing-id states; loaded values count as prefill for submitPrefilled. A row click fires a rowClick drawer action in entityList, projectionList and relatedList."
72
+ },
73
+ {
74
+ "version": "0.374.0",
75
+ "type": "improvement",
76
+ "title": "Input prefix, suffix and fill button",
77
+ "detail": "Text and number inputs show prefix and suffix text, and a fillAction renders a button that fetches a suggestion into the field, also for a readOnly field. The Input primitive takes prefix, suffix and fill; renderer-web draws them beside the input."
78
+ },
2
79
  {
3
80
  "version": "0.372.0",
4
81
  "type": "fix",