@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,93 @@
1
+ import type { ReactNode } from "react";
2
+ export interface NumberFieldProps {
3
+ readonly label: string;
4
+ readonly id: string;
5
+ readonly name: string;
6
+ readonly value: number | undefined;
7
+ readonly onChange: (v: number | undefined) => void;
8
+ readonly required?: boolean;
9
+ readonly disabled?: boolean;
10
+ readonly hideLabel?: boolean;
11
+ readonly testId?: string;
12
+ /** `false` renders without thousands separators (e.g. a year). Default `true`. */
13
+ readonly grouping?: boolean;
14
+ }
15
+ /** Zahlenfeld = Field + Input(kind:"number") in einem — nimmt der Screen die
16
+ * wiederholte id/name/value/onChange-Verdrahtung ab. `value` darf `undefined`
17
+ * sein (leeres Feld), intern auf den `""`-Empty-State des Inputs gemappt.
18
+ * Einheiten (€/%) gehören ins Label (`t("…Summe (€)")`), nicht als Badge. */
19
+ export declare function NumberField({ label, id, name, value, onChange, required, disabled, hideLabel, testId, grouping, }: NumberFieldProps): ReactNode;
20
+ export declare const MoneyField: typeof NumberField;
21
+ export declare const PercentField: typeof NumberField;
22
+ interface FieldBase {
23
+ readonly label: string;
24
+ readonly id: string;
25
+ readonly name: string;
26
+ readonly required?: boolean;
27
+ readonly disabled?: boolean;
28
+ readonly hideLabel?: boolean;
29
+ readonly testId?: string;
30
+ }
31
+ export interface TextFieldProps extends FieldBase {
32
+ readonly value: string;
33
+ readonly onChange: (v: string) => void;
34
+ readonly placeholder?: string;
35
+ readonly autoComplete?: string;
36
+ }
37
+ /** Textfeld = Field + Input(kind:"text"). */
38
+ export declare function TextField({ label, id, name, value, onChange, required, disabled, placeholder, autoComplete, hideLabel, testId, }: TextFieldProps): ReactNode;
39
+ export interface SelectFieldProps extends FieldBase {
40
+ readonly value: string;
41
+ readonly onChange: (v: string) => void;
42
+ readonly options: readonly string[] | readonly {
43
+ readonly value: string;
44
+ readonly label: string;
45
+ }[];
46
+ }
47
+ /** Auswahlfeld = Field + Input(kind:"select"). */
48
+ export declare function SelectField({ label, id, name, value, onChange, options, required, disabled, hideLabel, testId, }: SelectFieldProps): ReactNode;
49
+ export interface DateFieldProps extends FieldBase {
50
+ readonly value: string;
51
+ readonly onChange: (v: string) => void;
52
+ readonly min?: string;
53
+ readonly max?: string;
54
+ }
55
+ /** Datumsfeld = Field + Input(kind:"date"), ISO yyyy-mm-dd. */
56
+ export declare function DateField({ label, id, name, value, onChange, min, max, required, disabled, hideLabel, testId, }: DateFieldProps): ReactNode;
57
+ export interface BooleanFieldProps extends FieldBase {
58
+ readonly value: boolean;
59
+ readonly onChange: (v: boolean) => void;
60
+ }
61
+ /** Checkbox/Switch = Field(layout:"inline") + Input(kind:"boolean"). */
62
+ export declare function BooleanField({ label, id, name, value, onChange, required, disabled, hideLabel, testId, }: BooleanFieldProps): ReactNode;
63
+ export interface TextareaFieldProps extends FieldBase {
64
+ readonly value: string;
65
+ readonly onChange: (v: string) => void;
66
+ readonly rows?: number;
67
+ }
68
+ /** Mehrzeiliges Textfeld = Field + Input(kind:"textarea"). */
69
+ export declare function TextareaField({ label, id, name, value, onChange, rows, required, disabled, hideLabel, testId, }: TextareaFieldProps): ReactNode;
70
+ export interface RangeFieldProps extends FieldBase {
71
+ readonly value: number;
72
+ readonly onChange: (v: number) => void;
73
+ readonly min: number;
74
+ readonly max: number;
75
+ readonly step?: number;
76
+ }
77
+ /** Schieberegler = Field + Input(kind:"range"). */
78
+ export declare function RangeField({ label, id, name, value, onChange, min, max, step, required, disabled, hideLabel, testId, }: RangeFieldProps): ReactNode;
79
+ export interface FileFieldProps extends FieldBase {
80
+ /** FileRef-UUID der gespeicherten Datei, oder null. */
81
+ readonly value: string | null;
82
+ readonly onChange: (fileId: string | null) => void;
83
+ readonly accept?: readonly string[];
84
+ /** "image" zeigt eine Vorschau, "file" nur den Dateinamen. Default "file". */
85
+ readonly variant?: "file" | "image";
86
+ /** Bindet den Upload an ein konkretes Entity-Feld — der `/api/files`-Endpoint
87
+ * prüft `accept`/`maxSize` dann serverseitig gegen dessen Feld-Definition. */
88
+ readonly entityType?: string;
89
+ readonly fieldName?: string;
90
+ }
91
+ /** Datei-Upload = Field + Input(kind:"file"|"image") — FileRef-basiert. */
92
+ export declare function FileField({ label, id, name, value, onChange, accept, variant, entityType, fieldName, required, disabled, hideLabel, testId, }: FileFieldProps): ReactNode;
93
+ export {};
@@ -0,0 +1,50 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { usePrimitives } from "../../index.js";
3
+ /** Zahlenfeld = Field + Input(kind:"number") in einem — nimmt der Screen die
4
+ * wiederholte id/name/value/onChange-Verdrahtung ab. `value` darf `undefined`
5
+ * sein (leeres Feld), intern auf den `""`-Empty-State des Inputs gemappt.
6
+ * Einheiten (€/%) gehören ins Label (`t("…Summe (€)")`), nicht als Badge. */
7
+ export function NumberField({ label, id, name, value, onChange, required, disabled, hideLabel, testId, grouping, }) {
8
+ const { Field, Input } = usePrimitives();
9
+ return (_jsx(Field, { id: id, label: label, required: required, hideLabel: hideLabel, testId: testId, children: _jsx(Input, { kind: "number", id: id, name: name, value: value ?? "", onChange: onChange, required: required, disabled: disabled, ...(grouping !== undefined && { grouping }) }) }));
10
+ }
11
+ // Aliase markieren die Feld-Absicht am Call-Site (lesbarer als NumberField
12
+ // überall) ohne eigene Wrapper-Funktion vorzutäuschen — beide sind identisch
13
+ // zu NumberField, kein Ort für künftige geld-/prozent-spezifische Formatierung.
14
+ export const MoneyField = NumberField;
15
+ export const PercentField = NumberField;
16
+ /** Textfeld = Field + Input(kind:"text"). */
17
+ export function TextField({ label, id, name, value, onChange, required, disabled, placeholder, autoComplete, hideLabel, testId, }) {
18
+ const { Field, Input } = usePrimitives();
19
+ return (_jsx(Field, { id: id, label: label, required: required, hideLabel: hideLabel, testId: testId, children: _jsx(Input, { kind: "text", id: id, name: name, value: value, onChange: onChange, required: required, disabled: disabled, ...(placeholder !== undefined && { placeholder }), ...(autoComplete !== undefined && { autoComplete }) }) }));
20
+ }
21
+ /** Auswahlfeld = Field + Input(kind:"select"). */
22
+ export function SelectField({ label, id, name, value, onChange, options, required, disabled, hideLabel, testId, }) {
23
+ const { Field, Input } = usePrimitives();
24
+ return (_jsx(Field, { id: id, label: label, required: required, hideLabel: hideLabel, testId: testId, children: _jsx(Input, { kind: "select", id: id, name: name, value: value, onChange: onChange, options: options, required: required, disabled: disabled }) }));
25
+ }
26
+ /** Datumsfeld = Field + Input(kind:"date"), ISO yyyy-mm-dd. */
27
+ export function DateField({ label, id, name, value, onChange, min, max, required, disabled, hideLabel, testId, }) {
28
+ const { Field, Input } = usePrimitives();
29
+ return (_jsx(Field, { id: id, label: label, required: required, hideLabel: hideLabel, testId: testId, children: _jsx(Input, { kind: "date", id: id, name: name, value: value, onChange: (v) => onChange(v ?? ""), required: required, disabled: disabled, ...(min !== undefined && { min }), ...(max !== undefined && { max }) }) }));
30
+ }
31
+ /** Checkbox/Switch = Field(layout:"inline") + Input(kind:"boolean"). */
32
+ export function BooleanField({ label, id, name, value, onChange, required, disabled, hideLabel, testId, }) {
33
+ const { Field, Input } = usePrimitives();
34
+ return (_jsx(Field, { id: id, label: label, required: required, layout: "inline", hideLabel: hideLabel, testId: testId, children: _jsx(Input, { kind: "boolean", id: id, name: name, value: value, onChange: onChange, required: required, disabled: disabled }) }));
35
+ }
36
+ /** Mehrzeiliges Textfeld = Field + Input(kind:"textarea"). */
37
+ export function TextareaField({ label, id, name, value, onChange, rows, required, disabled, hideLabel, testId, }) {
38
+ const { Field, Input } = usePrimitives();
39
+ return (_jsx(Field, { id: id, label: label, required: required, hideLabel: hideLabel, testId: testId, children: _jsx(Input, { kind: "textarea", id: id, name: name, value: value, onChange: onChange, required: required, disabled: disabled, ...(rows !== undefined && { rows }) }) }));
40
+ }
41
+ /** Schieberegler = Field + Input(kind:"range"). */
42
+ export function RangeField({ label, id, name, value, onChange, min, max, step, required, disabled, hideLabel, testId, }) {
43
+ const { Field, Input } = usePrimitives();
44
+ return (_jsx(Field, { id: id, label: label, required: required, hideLabel: hideLabel, testId: testId, children: _jsx(Input, { kind: "range", id: id, name: name, value: value, onChange: onChange, min: min, max: max, required: required, disabled: disabled, ...(step !== undefined && { step }) }) }));
45
+ }
46
+ /** Datei-Upload = Field + Input(kind:"file"|"image") — FileRef-basiert. */
47
+ export function FileField({ label, id, name, value, onChange, accept, variant = "file", entityType, fieldName, required, disabled, hideLabel, testId, }) {
48
+ const { Field, Input } = usePrimitives();
49
+ return (_jsx(Field, { id: id, label: label, required: required, hideLabel: hideLabel, testId: testId, children: _jsx(Input, { kind: variant, id: id, name: name, value: value, onChange: onChange, required: required, disabled: disabled, ...(accept !== undefined && { accept }), ...(entityType !== undefined && { entityType }), ...(fieldName !== undefined && { fieldName }) }) }));
50
+ }
@@ -0,0 +1,27 @@
1
+ export { AiTextArea, type AiTextAreaProps, AiTextField, type AiTextFieldProps, } from "./ai-text-field.tsx";
2
+ export type { StackedAreaDateFormat, StackedAreaInitialWindow, StackedAreaRangeOption, StackedAreaRanges, StackedAreaWindowSelection, } from "./chart-window.ts";
3
+ export { type ChartMarker, type ChartSeries, type ChartTone, SegmentBarChart, type SegmentBarRow, StackedAreaChart, StackedBarChart, StatusBarChart, type StatusBarEntry, smoothPath, TimeseriesChart, type TimeseriesHeight, type TimeseriesPoint, type TimeseriesReferenceLine, type TimeseriesXAxis, type TimeseriesYAxis, } from "./charts.tsx";
4
+ export { CollapsibleSection } from "./collapsible-section.tsx";
5
+ export { type DashboardListColumn, DashboardListTable } from "./dashboard-list.tsx";
6
+ export { DetailList } from "./detail-list.tsx";
7
+ export { Drawer, type DrawerProps } from "./drawer.tsx";
8
+ export { FeedList, type FeedRow } from "./feed-list.tsx";
9
+ export { FloatingPanel, type FloatingPanelGeometry, type FloatingPanelProps, } from "./floating-panel.tsx";
10
+ export { BooleanField, type BooleanFieldProps, DateField, type DateFieldProps, FileField, type FileFieldProps, MoneyField, NumberField, type NumberFieldProps, PercentField, RangeField, type RangeFieldProps, SelectField, type SelectFieldProps, TextareaField, type TextareaFieldProps, TextField, type TextFieldProps, } from "./form-fields.tsx";
11
+ export { InfinityList, type InfinityListProps, type InfinityListSelection, } from "./infinity-list.tsx";
12
+ export { ModeSwitch, type ModeSwitchVariant } from "./mode-switch.tsx";
13
+ export { type PhotoSlotSpec, PhotoSlots, type PhotoSlotsProps } from "./photo-slots.tsx";
14
+ export { PlanCard, type PlanCardActionSlot, type PlanCardLinkSlot, type PlanCardPrice, type PlanCardProps, PlanGrid, type PlanGridProps, } from "./plan-card.tsx";
15
+ export { ProgressBar } from "./progress-bar.tsx";
16
+ export { ProgressList, type ProgressListRow } from "./progress-list.tsx";
17
+ export { PublicShell, type PublicShellProps, type PublicShellVariant } from "./public-shell.tsx";
18
+ export { QueryTable, type QueryTableColumn, type QueryTableProps } from "./query-table.tsx";
19
+ export { type ComparisonMetric, ComparisonTable, type ResultColumn, ResultPanel, ResultTable, } from "./result-panel.tsx";
20
+ export { SectionCard } from "./section-card.tsx";
21
+ export { SideBySideTable, type SideBySideTableCell, type SideBySideTableColumn, type SideBySideTableRow, } from "./side-by-side-table.tsx";
22
+ export { MiniStat, Sparkline, StatCard, type StatDelta, StatStripCell, type StatTone, } from "./stat.tsx";
23
+ export { EmptyState, ErrorState, LoadingState } from "./states.tsx";
24
+ export { STATUS_TONE_TEXT, StatusBadge, type StatusBadgeTone, type StatusTone, } from "./status-badge.tsx";
25
+ export { StepBar } from "./step-bar.tsx";
26
+ export { UploadZone, type UploadZoneProps } from "./upload-zone.tsx";
27
+ export { useDraft } from "./use-draft.ts";
@@ -0,0 +1,30 @@
1
+ // Mid-Level-Widgets — Kompositionen über den Primitives (Card, DataTable,
2
+ // Banner) + Theme-Tokens. Für Custom-Screens: erst hier schauen, dann bauen.
3
+ // Katalog: docs.kumiko.rocks → Guides → Widgets; visueller Überblick im
4
+ // styleguide-Sample.
5
+ export { AiTextArea, AiTextField, } from "./ai-text-field.js";
6
+ export { SegmentBarChart, StackedAreaChart, StackedBarChart, StatusBarChart, smoothPath, TimeseriesChart, } from "./charts.js";
7
+ export { CollapsibleSection } from "./collapsible-section.js";
8
+ export { DashboardListTable } from "./dashboard-list.js";
9
+ export { DetailList } from "./detail-list.js";
10
+ export { Drawer } from "./drawer.js";
11
+ export { FeedList } from "./feed-list.js";
12
+ export { FloatingPanel, } from "./floating-panel.js";
13
+ export { BooleanField, DateField, FileField, MoneyField, NumberField, PercentField, RangeField, SelectField, TextareaField, TextField, } from "./form-fields.js";
14
+ export { InfinityList, } from "./infinity-list.js";
15
+ export { ModeSwitch } from "./mode-switch.js";
16
+ export { PhotoSlots } from "./photo-slots.js";
17
+ export { PlanCard, PlanGrid, } from "./plan-card.js";
18
+ export { ProgressBar } from "./progress-bar.js";
19
+ export { ProgressList } from "./progress-list.js";
20
+ export { PublicShell } from "./public-shell.js";
21
+ export { QueryTable } from "./query-table.js";
22
+ export { ComparisonTable, ResultPanel, ResultTable, } from "./result-panel.js";
23
+ export { SectionCard } from "./section-card.js";
24
+ export { SideBySideTable, } from "./side-by-side-table.js";
25
+ export { MiniStat, Sparkline, StatCard, StatStripCell, } from "./stat.js";
26
+ export { EmptyState, ErrorState, LoadingState } from "./states.js";
27
+ export { STATUS_TONE_TEXT, StatusBadge, } from "./status-badge.js";
28
+ export { StepBar } from "./step-bar.js";
29
+ export { UploadZone } from "./upload-zone.js";
30
+ export { useDraft } from "./use-draft.js";
@@ -0,0 +1,46 @@
1
+ import { type ReactNode } from "react";
2
+ /** Position of the selected row among the rows loaded so far. `total`
3
+ * counts loaded rows only; `hasMore` says whether further pages exist. */
4
+ export type InfinityListSelection = {
5
+ readonly index: number;
6
+ readonly total: number;
7
+ readonly prevId: string | null;
8
+ readonly nextId: string | null;
9
+ readonly hasMore: boolean;
10
+ };
11
+ export type InfinityListProps<TData = unknown, TRow = Readonly<Record<string, unknown>>> = {
12
+ /** Dispatcher-Query-Type (`<feature>:query:<entity>:<verb>`). */
13
+ readonly query: string;
14
+ readonly payload?: Readonly<Record<string, unknown>>;
15
+ /** Rows per page — sent as `limit` in the query payload. Default 50. */
16
+ readonly pageSize?: number;
17
+ readonly rows: (data: TData) => readonly TRow[];
18
+ /** Pull the next-page cursor from the result; `null` means last page. */
19
+ readonly nextCursor: (data: TData) => string | null;
20
+ /** Must derive from row content (e.g. `row.id`), not from `index` — a
21
+ * live refresh reorders rows (new/changed rows move to the front). */
22
+ readonly rowId: (row: TRow, index: number) => string;
23
+ readonly renderRow: (row: TRow) => ReactNode;
24
+ readonly emptyState?: ReactNode;
25
+ readonly className?: string;
26
+ readonly testId?: string;
27
+ /** Subscribe to SSE events for the entity parsed from `query`
28
+ * (`<feature>:query:<entity>:<verb>`) and refetch the first page on
29
+ * any create/update/delete/restore event, merging it into the
30
+ * already-accumulated rows instead of collapsing them — see
31
+ * `useQuery`'s `live` option for the same convention. Default false. */
32
+ readonly live?: boolean;
33
+ /** Row id (as returned by `rowId`) whose position `onSelectionChange`
34
+ * reports. The list itself does not highlight it — `renderRow` does. */
35
+ readonly selectedId?: string | null;
36
+ /** Fires when the selected row's position or neighbours change, e.g. for
37
+ * a "message 4 of 6" header with previous/next buttons. Not called while
38
+ * nothing is selected or the selected row is not loaded. */
39
+ readonly onSelectionChange?: (selection: InfinityListSelection) => void;
40
+ };
41
+ /** Cursor-paginated scroll list (mail inbox, activity feeds) — loads the
42
+ * next page when the end sentinel becomes visible (IntersectionObserver),
43
+ * instead of a pager bar like QueryTable/entityList. The query handler
44
+ * receives `{ ...payload, limit, cursor? }` and returns rows plus the next
45
+ * cursor (same cursor convention as the audit-log screen). */
46
+ export declare function InfinityList<TData = unknown, TRow = Readonly<Record<string, unknown>>>({ query, payload, pageSize, rows, nextCursor, rowId, renderRow, emptyState, className, testId, live, selectedId, onSelectionChange, }: InfinityListProps<TData, TRow>): ReactNode;
@@ -0,0 +1,211 @@
1
+ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useCallback, useEffect, useRef, useState } from "react";
3
+ import { entityFromQueryType, useDispatcher, useLiveEvents, useTranslation } from "../../index.js";
4
+ import { EmptyState, ErrorState, LoadingState } from "./states.js";
5
+ /** Cursor-paginated scroll list (mail inbox, activity feeds) — loads the
6
+ * next page when the end sentinel becomes visible (IntersectionObserver),
7
+ * instead of a pager bar like QueryTable/entityList. The query handler
8
+ * receives `{ ...payload, limit, cursor? }` and returns rows plus the next
9
+ * cursor (same cursor convention as the audit-log screen). */
10
+ export function InfinityList({ query, payload, pageSize = 50, rows, nextCursor, rowId, renderRow, emptyState, className, testId, live = false, selectedId, onSelectionChange, }) {
11
+ const dispatcher = useDispatcher();
12
+ const t = useTranslation();
13
+ const subscribeLive = useLiveEvents();
14
+ const [state, setState] = useState({ kind: "loading" });
15
+ const sentinelRef = useRef(null);
16
+ const payloadKey = JSON.stringify(payload ?? {});
17
+ // rows/nextCursor/rowId are fresh closures on every caller render
18
+ // (inline arrow props). As useCallback deps that would recreate
19
+ // `load`/`refreshFirstPage` every render → the effects below would
20
+ // refetch in a loop. Refs keep them stable while always reading the
21
+ // current selector.
22
+ const rowsRef = useRef(rows);
23
+ rowsRef.current = rows;
24
+ const nextCursorRef = useRef(nextCursor);
25
+ nextCursorRef.current = nextCursor;
26
+ const rowIdRef = useRef(rowId);
27
+ rowIdRef.current = rowId;
28
+ // Discards a response whose request was superseded by a newer one before
29
+ // it resolved (e.g. two searches fired in quick succession) — without
30
+ // this, a slow earlier response can land after a faster later one and
31
+ // overwrite it, leaving stale rows on screen (fw#1705).
32
+ const requestSeq = useRef(0);
33
+ // IDs of the most recently loaded first page. refreshFirstPage() needs
34
+ // this to tell "row dropped from page 1 elsewhere" (must be pruned) apart
35
+ // from "row belongs to an already-accumulated later page" (must survive)
36
+ // — both are simply absent from the fresh page's id set.
37
+ const firstPageIdsRef = useRef(new Set());
38
+ // biome-ignore lint/correctness/useExhaustiveDependencies: payload goes through payloadKey
39
+ const load = useCallback(async (cursor) => {
40
+ const mySeq = ++requestSeq.current;
41
+ const res = await dispatcher.query(query, {
42
+ ...payload,
43
+ limit: pageSize,
44
+ ...(cursor !== null && { cursor }),
45
+ });
46
+ if (mySeq !== requestSeq.current)
47
+ return;
48
+ if (!res.isSuccess) {
49
+ setState({ kind: "error", error: res.error });
50
+ return;
51
+ }
52
+ const nextRows = rowsRef.current(res.data);
53
+ if (cursor === null) {
54
+ // Same identity as refreshFirstPage's freshIds/staleRows diff below
55
+ // — this ref is what that diff's previousFirstPageIds reads, so it
56
+ firstPageIdsRef.current = new Set(nextRows.map((row, index) => rowIdRef.current(row, index)));
57
+ }
58
+ setState((prev) => {
59
+ if (cursor === null || prev.kind !== "ready") {
60
+ return { kind: "ready", rows: nextRows, cursor: nextCursorRef.current(res.data) };
61
+ }
62
+ // The live-merge above can re-sort a row to the front of page 1; an
63
+ // offset-based cursor then re-serves that same row in a later page.
64
+ // Dedupe on append so it doesn't land twice under duplicate React
65
+ // keys.
66
+ const existingIds = new Set(prev.rows.map((row, index) => rowIdRef.current(row, index)));
67
+ const newRows = nextRows.filter((row, index) => !existingIds.has(rowIdRef.current(row, index)));
68
+ return {
69
+ kind: "ready",
70
+ rows: [...prev.rows, ...newRows],
71
+ cursor: nextCursorRef.current(res.data),
72
+ };
73
+ });
74
+ }, [dispatcher, query, pageSize, payloadKey]);
75
+ useEffect(() => {
76
+ setState({ kind: "loading" });
77
+ void load(null);
78
+ return () => {
79
+ requestSeq.current += 1;
80
+ };
81
+ }, [load]);
82
+ // Live-mode: on an SSE event for the query's entity, refetch only the
83
+ // first page and merge it in — rows the fresh page still contains move
84
+ // to the front (newest-first feeds), rows it dropped (edited/deleted
85
+ // elsewhere) are pruned, and everything beyond page 1 stays untouched.
86
+ // A full reload would collapse already-accumulated pages and jump the
87
+ // scroll position; see fw#1827.
88
+ // biome-ignore lint/correctness/useExhaustiveDependencies: payload goes through payloadKey
89
+ const refreshFirstPage = useCallback(async () => {
90
+ // Read, don't bump: a concurrent load() (e.g. the mount fetch still
91
+ // in flight) must still land. Bumping here would make load()'s own
92
+ // sequence check discard it, and the refresh below then bails on
93
+ // `prev.kind !== "ready"` — the list gets stuck in loading forever.
94
+ const seqAtStart = requestSeq.current;
95
+ const res = await dispatcher.query(query, { ...payload, limit: pageSize });
96
+ if (seqAtStart !== requestSeq.current)
97
+ return;
98
+ // skip: background live refresh failed, keep showing the current rows
99
+ if (!res.isSuccess)
100
+ return;
101
+ const freshRows = rowsRef.current(res.data);
102
+ const freshIds = new Set(freshRows.map((row, index) => rowIdRef.current(row, index)));
103
+ // A row absent from freshIds is stale for one of two reasons: it was
104
+ // dropped from page 1 (deleted, or filtered out elsewhere) and must be
105
+ // pruned, or it belongs to an already-accumulated later page and must
106
+ // survive. previousFirstPageIds — captured before it's overwritten below
107
+ // — is what tells those two cases apart.
108
+ const previousFirstPageIds = firstPageIdsRef.current;
109
+ firstPageIdsRef.current = freshIds;
110
+ setState((prev) => {
111
+ // skip: the initial load() is still in flight and owns the eventual
112
+ // state — a concurrent refresh landing here has nothing accumulated
113
+ // to merge into yet.
114
+ if (prev.kind === "loading")
115
+ return prev;
116
+ if (prev.kind !== "ready") {
117
+ // prev.kind === "error": this refresh succeeded — promote straight
118
+ // to "ready" instead of leaving the list stuck on the earlier
119
+ // failure forever (a live event should be able to recover it).
120
+ return { kind: "ready", rows: freshRows, cursor: nextCursorRef.current(res.data) };
121
+ }
122
+ const staleRows = prev.rows.filter((row, index) => {
123
+ const id = rowIdRef.current(row, index);
124
+ return !freshIds.has(id) && !previousFirstPageIds.has(id);
125
+ });
126
+ return { kind: "ready", rows: [...freshRows, ...staleRows], cursor: prev.cursor };
127
+ });
128
+ }, [dispatcher, query, pageSize, payloadKey]);
129
+ // Trailing debounce + in-flight coalesce: bulk SSE storms must not fan out
130
+ // into one query per event (fw#1829). A refresh already running schedules
131
+ // exactly one trailing pass after it settles.
132
+ const liveTimerRef = useRef(null);
133
+ const liveInFlightRef = useRef(false);
134
+ const liveTrailingRef = useRef(false);
135
+ useEffect(() => {
136
+ // skip: live mode off, no SSE subscription needed
137
+ if (!live)
138
+ return;
139
+ const entity = entityFromQueryType(query);
140
+ // skip: query type has no mapped entity, nothing to subscribe to
141
+ if (entity === undefined)
142
+ return;
143
+ const runRefresh = () => {
144
+ liveInFlightRef.current = true;
145
+ void refreshFirstPage().finally(() => {
146
+ liveInFlightRef.current = false;
147
+ if (liveTrailingRef.current) {
148
+ liveTrailingRef.current = false;
149
+ runRefresh();
150
+ }
151
+ });
152
+ };
153
+ const scheduleRefresh = () => {
154
+ if (liveTimerRef.current !== null)
155
+ clearTimeout(liveTimerRef.current);
156
+ liveTimerRef.current = setTimeout(() => {
157
+ liveTimerRef.current = null;
158
+ if (liveInFlightRef.current) {
159
+ liveTrailingRef.current = true;
160
+ return;
161
+ }
162
+ runRefresh();
163
+ }, 250);
164
+ };
165
+ const unsubscribe = subscribeLive(entity, scheduleRefresh);
166
+ return () => {
167
+ unsubscribe();
168
+ if (liveTimerRef.current !== null) {
169
+ clearTimeout(liveTimerRef.current);
170
+ liveTimerRef.current = null;
171
+ }
172
+ };
173
+ }, [live, query, refreshFirstPage, subscribeLive]);
174
+ useEffect(() => {
175
+ const sentinel = sentinelRef.current;
176
+ // skip: no further page or not ready yet — observer not needed
177
+ if (sentinel === null || state.kind !== "ready" || state.cursor === null)
178
+ return;
179
+ const cursor = state.cursor;
180
+ const observer = new IntersectionObserver((entries) => {
181
+ if (entries[0]?.isIntersecting === true)
182
+ void load(cursor);
183
+ });
184
+ observer.observe(sentinel);
185
+ return () => observer.disconnect();
186
+ }, [state, load]);
187
+ const onSelectionChangeRef = useRef(onSelectionChange);
188
+ onSelectionChangeRef.current = onSelectionChange;
189
+ useEffect(() => {
190
+ if (selectedId === undefined || selectedId === null || state.kind !== "ready")
191
+ return;
192
+ const ids = state.rows.map((row, index) => rowIdRef.current(row, index));
193
+ const index = ids.indexOf(selectedId);
194
+ if (index === -1)
195
+ return;
196
+ onSelectionChangeRef.current?.({
197
+ index,
198
+ total: ids.length,
199
+ prevId: ids[index - 1] ?? null,
200
+ nextId: ids[index + 1] ?? null,
201
+ hasMore: state.cursor !== null,
202
+ });
203
+ }, [state, selectedId]);
204
+ if (state.kind === "loading")
205
+ return _jsx(LoadingState, { rows: 4, testId: testId });
206
+ if (state.kind === "error")
207
+ return _jsx(ErrorState, { error: state.error, onRetry: () => void load(null), testId: testId });
208
+ if (state.rows.length === 0)
209
+ return _jsx(_Fragment, { children: emptyState ?? _jsx(EmptyState, { title: t("kumiko.list.no-entries"), testId: testId }) });
210
+ return (_jsxs("div", { "data-testid": testId, className: className ?? "flex flex-col overflow-y-auto", children: [state.rows.map((row, index) => (_jsx("div", { children: renderRow(row) }, rowId(row, index)))), _jsx("div", { ref: sentinelRef, className: "h-px" })] }));
211
+ }
@@ -0,0 +1,21 @@
1
+ import type { ReactNode } from "react";
2
+ export type ModeSwitchVariant = "outline" | "pill";
3
+ /** Segmented-Control für sich ausschließende Modi — die prominente
4
+ * Alternative zum vergrabenen <select>. */
5
+ export declare function ModeSwitch<T extends string>({ value, options, onChange, ariaLabel, variant, className, testId, }: {
6
+ /** `null`: no option active. */
7
+ readonly value: T | null;
8
+ readonly options: readonly {
9
+ readonly value: T;
10
+ readonly label: string;
11
+ /** Muted tabular counter after the label. */
12
+ readonly count?: number;
13
+ }[];
14
+ readonly onChange: (value: T) => void;
15
+ readonly ariaLabel?: string;
16
+ /** `outline` (default): bordered segments, active tinted. `pill`: grey
17
+ * track with a raised active segment. */
18
+ readonly variant?: ModeSwitchVariant;
19
+ readonly className?: string;
20
+ readonly testId?: string;
21
+ }): ReactNode;
@@ -0,0 +1,25 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { cn } from "../lib/cn.js";
3
+ /** Segmented-Control für sich ausschließende Modi — die prominente
4
+ * Alternative zum vergrabenen <select>. */
5
+ export function ModeSwitch({ value, options, onChange, ariaLabel, variant = "outline", className, testId, }) {
6
+ const pill = variant === "pill";
7
+ return (_jsx("div", { "data-testid": testId, role: "group", "aria-label": ariaLabel, className: cn("flex min-h-8", pill
8
+ ? "gap-0.5 rounded-lg bg-muted p-0.5"
9
+ : "overflow-hidden rounded-md border border-input bg-background", className), children: options.map((o) => {
10
+ const active = o.value === value;
11
+ return (_jsxs("button", { type: "button", "aria-pressed": active, onClick: () => onChange(o.value), className: cn("grow px-3 text-sm transition-colors", "focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring", pill
12
+ ? [
13
+ "rounded-md",
14
+ active
15
+ ? "bg-card font-semibold text-foreground shadow-sm dark:bg-foreground/10"
16
+ : "text-muted-foreground hover:text-foreground",
17
+ ]
18
+ : [
19
+ "border-l border-input first:border-l-0",
20
+ active
21
+ ? "bg-primary/10 font-semibold text-primary"
22
+ : "text-foreground hover:bg-muted",
23
+ ]), children: [o.label, o.count !== undefined && (_jsx("span", { "data-testid": testId !== undefined ? `${testId}-count-${o.value}` : undefined, className: cn("ml-1.5 font-normal tabular-nums", !active && "text-muted-foreground"), children: o.count }))] }, o.value));
24
+ }) }));
25
+ }
@@ -0,0 +1,29 @@
1
+ import { type ReactNode } from "react";
2
+ export type PhotoSlotSpec = {
3
+ readonly id: string;
4
+ /** The shot this slot asks for ("Front, angled") — the empty slot's
5
+ * caption and the filled thumbnail's alt text. */
6
+ readonly label: string;
7
+ /** Set once the app holds the photo; the slot then shows the thumbnail. */
8
+ readonly previewUrl?: string;
9
+ /** Corner tag on a filled slot, e.g. "Cover photo". */
10
+ readonly badge?: string;
11
+ };
12
+ export type PhotoSlotsProps = {
13
+ readonly slots: readonly PhotoSlotSpec[];
14
+ /** Stores the photo for `slotId`. Throws on failure — the message is shown
15
+ * under the slot. The app then passes the slot's `previewUrl`. */
16
+ readonly onUpload: (slotId: string, file: File) => Promise<void>;
17
+ /** Second line on an empty slot, e.g. "Camera or gallery". */
18
+ readonly pickHint?: ReactNode;
19
+ readonly accept?: readonly string[];
20
+ /** Opens that camera directly on phones; unset keeps camera and gallery. */
21
+ readonly capture?: "environment" | "user";
22
+ /** The first slot spans the full row (cover photo). Defaults to true. */
23
+ readonly featureFirst?: boolean;
24
+ readonly disabled?: boolean;
25
+ readonly testId?: string;
26
+ };
27
+ /** Guided photo capture: one tile per requested shot in a two-column grid,
28
+ * each its own camera/gallery picker, filled tiles show the thumbnail. */
29
+ export declare function PhotoSlots({ slots, onUpload, pickHint, accept, capture, featureFirst, disabled, testId, }: PhotoSlotsProps): ReactNode;
@@ -0,0 +1,52 @@
1
+ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Camera, Check, Loader2 } from "lucide-react";
3
+ import { 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
+ import { matchesAccept } from "./upload-zone.js";
9
+ const DEFAULT_ACCEPT = ["image/*"];
10
+ /** Guided photo capture: one tile per requested shot in a two-column grid,
11
+ * each its own camera/gallery picker, filled tiles show the thumbnail. */
12
+ export function PhotoSlots({ slots, onUpload, pickHint, accept = DEFAULT_ACCEPT, capture, featureFirst = true, disabled, testId, }) {
13
+ const t = useTranslation();
14
+ const [uploadStates, setUploadStates] = useState({});
15
+ function setSlotState(slotId, state) {
16
+ setUploadStates((prev) => {
17
+ const { [slotId]: _previous, ...rest } = prev;
18
+ return state === undefined ? rest : { ...rest, [slotId]: state };
19
+ });
20
+ }
21
+ async function uploadIntoSlot(slotId, file) {
22
+ if (!matchesAccept(file, accept)) {
23
+ setSlotState(slotId, { kind: "error", message: t("kumiko.widget.upload.rejected-type") });
24
+ return;
25
+ }
26
+ setSlotState(slotId, { kind: "uploading" });
27
+ try {
28
+ await onUpload(slotId, await resizeImageBeforeUpload(file));
29
+ setSlotState(slotId, undefined);
30
+ }
31
+ catch (cause) {
32
+ const message = cause instanceof Error ? cause.message : t("kumiko.widget.upload.error");
33
+ setSlotState(slotId, { kind: "error", message });
34
+ }
35
+ }
36
+ const acceptAttr = toAcceptAttr(accept);
37
+ return (_jsx("div", { "data-testid": testId, className: "grid grid-cols-2 gap-2.5", children: slots.map((slot, index) => {
38
+ const uploadState = uploadStates[slot.id];
39
+ const isUploading = uploadState?.kind === "uploading";
40
+ const isFeatured = featureFirst && index === 0;
41
+ const slotTestId = testId !== undefined ? `${testId}-slot-${slot.id}` : undefined;
42
+ return (_jsxs("div", { className: cn("flex flex-col gap-1", isFeatured && "col-span-2"), children: [_jsxs("label", { "data-testid": slotTestId, "data-filled": slot.previewUrl !== undefined ? "true" : undefined, className: cn("relative flex cursor-pointer flex-col items-center justify-center gap-1 overflow-hidden rounded-lg border-2 text-center text-sm transition-colors has-[:focus-visible]:ring-2 has-[:focus-visible]:ring-ring has-[:focus-visible]:ring-offset-2", isFeatured ? "h-52" : "h-32", slot.previewUrl !== undefined
43
+ ? "border-transparent"
44
+ : "border-dashed border-primary/60 bg-primary/5 text-primary", (disabled === true || isUploading) && "cursor-not-allowed opacity-60"), children: [slot.previewUrl !== undefined ? (_jsxs(_Fragment, { children: [_jsx("img", { src: slot.previewUrl, alt: slot.label, className: "absolute inset-0 size-full object-cover" }), slot.badge !== undefined && (_jsx("span", { className: "absolute bottom-2 left-2 rounded-full bg-background/90 px-2 py-0.5 text-xs font-semibold text-foreground", children: slot.badge })), _jsx("span", { className: "absolute top-2 right-2 flex size-6 items-center justify-center rounded-full bg-status-ok text-background", children: _jsx(Check, { "aria-hidden": "true", className: "size-3.5" }) })] })) : (_jsxs(_Fragment, { children: [isUploading ? (_jsx(Loader2, { "aria-hidden": "true", className: "size-6 animate-spin" })) : (_jsx(Camera, { "aria-hidden": "true", className: "size-6" })), _jsx("span", { className: "font-semibold", children: slot.label }), pickHint !== undefined && _jsx("span", { className: "text-xs", children: pickHint })] })), isUploading && (_jsx("span", { className: "sr-only", children: t("kumiko.widget.upload.uploading") })), _jsx("input", { type: "file", className: "sr-only", "data-testid": slotTestId !== undefined ? `${slotTestId}-input` : undefined, "aria-label": slot.label, disabled: disabled === true || isUploading, ...(acceptAttr !== undefined && { accept: acceptAttr }), ...(capture !== undefined && { capture }), onChange: (e) => {
45
+ const file = e.target.files?.[0];
46
+ // Reset so picking the same file again after an error still fires change.
47
+ e.target.value = "";
48
+ if (file !== undefined)
49
+ void uploadIntoSlot(slot.id, file);
50
+ } })] }), uploadState?.kind === "error" && (_jsx("p", { role: "alert", className: "text-xs text-destructive", children: uploadState.message }))] }, slot.id));
51
+ }) }));
52
+ }
@@ -0,0 +1,36 @@
1
+ import type { ReactNode } from "react";
2
+ export type PlanCardPrice = {
3
+ readonly amount: string;
4
+ readonly period?: string;
5
+ };
6
+ export type PlanCardActionSlot = {
7
+ readonly label: string;
8
+ readonly onClick: () => void;
9
+ readonly disabled?: boolean;
10
+ };
11
+ export type PlanCardLinkSlot = {
12
+ readonly label: string;
13
+ readonly href: string;
14
+ readonly target?: "_blank";
15
+ };
16
+ export type PlanCardProps = {
17
+ readonly title: string;
18
+ readonly description?: string;
19
+ /** null renders the price-unavailable state; undefined renders no price row. */
20
+ readonly price?: PlanCardPrice | null;
21
+ readonly features?: readonly ReactNode[];
22
+ readonly current?: boolean;
23
+ readonly cta?: PlanCardActionSlot;
24
+ /** Link-styled cta (e.g. contact sales); wins over `cta` when both are set. */
25
+ readonly ctaLink?: PlanCardLinkSlot;
26
+ readonly secondaryAction?: PlanCardActionSlot;
27
+ /** compact: one-off purchases (e.g. credit packs) — title+price in one row, no feature emphasis, smaller padding. */
28
+ readonly variant?: "default" | "compact";
29
+ readonly testId?: string;
30
+ };
31
+ export type PlanGridProps = {
32
+ readonly children: ReactNode;
33
+ readonly testId?: string;
34
+ };
35
+ export declare function PlanCard({ title, description, price, features, current, cta, ctaLink, secondaryAction, variant, testId, }: PlanCardProps): ReactNode;
36
+ export declare function PlanGrid({ children, testId }: PlanGridProps): ReactNode;