@cosmicdrift/kumiko-renderer 0.374.0 → 0.378.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (477) hide show
  1. package/README.md +2 -2
  2. package/dist/app/action-form-support.d.ts +9 -2
  3. package/dist/app/action-form-support.js +24 -2
  4. package/dist/app/client-actions.d.ts +2 -2
  5. package/dist/app/column-renderers.js +1 -1
  6. package/dist/app/config-edit-shim.js +1 -1
  7. package/dist/app/content-preview.js +1 -6
  8. package/dist/app/custom-screens.js +1 -1
  9. package/dist/app/dashboard-body.d.ts +1 -1
  10. package/dist/app/entity-list-expanded-row.d.ts +1 -1
  11. package/dist/app/form-schema.d.ts +1 -1
  12. package/dist/app/form-schema.js +2 -2
  13. package/dist/app/kumiko-screen.d.ts +1 -1
  14. package/dist/app/kumiko-screen.js +10 -7
  15. package/dist/app/list-empty-content.d.ts +1 -1
  16. package/dist/app/list-facets.d.ts +1 -1
  17. package/dist/app/nav.js +2 -2
  18. package/dist/app/query-state-banners.d.ts +1 -1
  19. package/dist/app/reference-link.d.ts +1 -1
  20. package/dist/app/row-actions.d.ts +1 -1
  21. package/dist/app/secret-mint-body.d.ts +1 -1
  22. package/dist/app/secrets-edit-body.d.ts +1 -1
  23. package/dist/app/use-record-actions.d.ts +1 -1
  24. package/dist/app/write-failed-error.d.ts +1 -1
  25. package/dist/components/availability-options-select.d.ts +1 -1
  26. package/dist/components/embedded-list-field.d.ts +1 -1
  27. package/dist/components/embedded-list-field.js +1 -1
  28. package/dist/components/file-list-field.d.ts +1 -1
  29. package/dist/components/form-derivation-patch.d.ts +8 -0
  30. package/dist/components/form-derivation-patch.js +24 -0
  31. package/dist/components/form-screen-layout.d.ts +13 -0
  32. package/dist/components/form-screen-layout.js +13 -0
  33. package/dist/components/grid-cell-for-field.d.ts +1 -1
  34. package/dist/components/multi-select-checkboxes.d.ts +1 -1
  35. package/dist/components/multi-select-checkboxes.js +1 -1
  36. package/dist/components/query-options-select.d.ts +1 -1
  37. package/dist/components/related-list-section.d.ts +1 -1
  38. package/dist/components/render-edit-logic.d.ts +1 -1
  39. package/dist/components/render-edit-types.d.ts +6 -3
  40. package/dist/components/render-edit.d.ts +1 -1
  41. package/dist/components/render-edit.js +18 -3
  42. package/dist/components/render-field.d.ts +1 -1
  43. package/dist/components/render-field.js +12 -2
  44. package/dist/components/render-list.d.ts +1 -1
  45. package/dist/components/render-list.js +20 -4
  46. package/dist/components/write-form-section.d.ts +1 -1
  47. package/dist/components/write-form-section.js +1 -1
  48. package/dist/context/dispatcher-context.d.ts +1 -1
  49. package/dist/file-ids-of.d.ts +1 -0
  50. package/dist/file-ids-of.js +7 -0
  51. package/dist/flow-diagram/icons.d.ts +3 -0
  52. package/dist/flow-diagram/icons.js +14 -0
  53. package/dist/flow-diagram/index.d.ts +2 -0
  54. package/dist/flow-diagram/index.js +1 -0
  55. package/dist/flow-diagram/render.d.ts +3 -0
  56. package/dist/flow-diagram/render.js +234 -0
  57. package/dist/flow-diagram/types.d.ts +18 -0
  58. package/dist/flow-diagram/types.js +1 -0
  59. package/dist/format-when.js +1 -1
  60. package/dist/headless/apex/css.d.ts +3 -0
  61. package/dist/headless/apex/css.js +298 -0
  62. package/dist/headless/apex/index.d.ts +236 -0
  63. package/dist/headless/apex/index.js +377 -0
  64. package/dist/headless/apex/lightbox.d.ts +4 -0
  65. package/dist/headless/apex/lightbox.js +81 -0
  66. package/dist/headless/contracts/asset.d.ts +15 -0
  67. package/dist/headless/contracts/asset.js +17 -0
  68. package/dist/headless/contracts/index.d.ts +3 -0
  69. package/dist/headless/contracts/index.js +1 -0
  70. package/dist/headless/contracts/locale.d.ts +7 -0
  71. package/dist/headless/contracts/locale.js +11 -0
  72. package/dist/headless/contracts/primitives.d.ts +93 -0
  73. package/dist/headless/contracts/primitives.js +21 -0
  74. package/dist/headless/dispatcher/index.d.ts +2 -0
  75. package/dist/headless/dispatcher/index.js +1 -0
  76. package/dist/headless/dispatcher/types.d.ts +86 -0
  77. package/dist/headless/dispatcher/types.js +34 -0
  78. package/dist/headless/form/form-controller.d.ts +2 -0
  79. package/dist/headless/form/form-controller.js +409 -0
  80. package/dist/headless/form/index.d.ts +3 -0
  81. package/dist/headless/form/index.js +2 -0
  82. package/dist/headless/form/types.d.ts +76 -0
  83. package/dist/headless/form/types.js +1 -0
  84. package/dist/headless/form/zod-bridge.d.ts +10 -0
  85. package/dist/headless/form/zod-bridge.js +103 -0
  86. package/dist/headless/format/document-values.d.ts +12 -0
  87. package/dist/headless/format/document-values.js +70 -0
  88. package/dist/headless/format/escape.d.ts +5 -0
  89. package/dist/headless/format/escape.js +75 -0
  90. package/dist/headless/format/html-template.d.ts +9 -0
  91. package/dist/headless/format/html-template.js +39 -0
  92. package/dist/headless/format/index.d.ts +12 -0
  93. package/dist/headless/format/index.js +237 -0
  94. package/dist/headless/format/money.d.ts +3 -0
  95. package/dist/headless/format/money.js +39 -0
  96. package/dist/headless/index.d.ts +14 -0
  97. package/dist/headless/index.js +9 -0
  98. package/dist/headless/locale-routing/index.d.ts +41 -0
  99. package/dist/headless/locale-routing/index.js +145 -0
  100. package/dist/headless/nav/index.d.ts +2 -0
  101. package/dist/headless/nav/index.js +1 -0
  102. package/dist/headless/nav/resolve.d.ts +2 -0
  103. package/dist/headless/nav/resolve.js +71 -0
  104. package/dist/headless/nav/types.d.ts +26 -0
  105. package/dist/headless/nav/types.js +1 -0
  106. package/dist/headless/store/create-store.d.ts +2 -0
  107. package/dist/headless/store/create-store.js +43 -0
  108. package/dist/headless/store/equality.d.ts +1 -0
  109. package/dist/headless/store/equality.js +34 -0
  110. package/dist/headless/store/index.d.ts +3 -0
  111. package/dist/headless/store/index.js +2 -0
  112. package/dist/headless/store/types.d.ts +7 -0
  113. package/dist/headless/store/types.js +10 -0
  114. package/dist/headless/view-model/edit.d.ts +21 -0
  115. package/dist/headless/view-model/edit.js +512 -0
  116. package/dist/headless/view-model/embedded-list.d.ts +27 -0
  117. package/dist/headless/view-model/embedded-list.js +63 -0
  118. package/dist/headless/view-model/index.d.ts +7 -0
  119. package/dist/headless/view-model/index.js +3 -0
  120. package/dist/headless/view-model/list-file-display.d.ts +3 -0
  121. package/dist/headless/view-model/list-file-display.js +27 -0
  122. package/dist/headless/view-model/list.d.ts +16 -0
  123. package/dist/headless/view-model/list.js +229 -0
  124. package/dist/headless/view-model/types.d.ts +382 -0
  125. package/dist/headless/view-model/types.js +1 -0
  126. package/dist/hooks/use-ai-text.d.ts +1 -1
  127. package/dist/hooks/use-form.d.ts +1 -1
  128. package/dist/hooks/use-form.js +1 -1
  129. package/dist/hooks/use-mutation.d.ts +1 -1
  130. package/dist/hooks/use-query.d.ts +1 -1
  131. package/dist/hooks/use-store.d.ts +1 -1
  132. package/dist/hooks/use-store.js +7 -7
  133. package/dist/hooks/use-stream-handler.d.ts +1 -1
  134. package/dist/i18n-defaults.js +6 -0
  135. package/dist/i18n.d.ts +1 -1
  136. package/dist/i18n.js +1 -1
  137. package/dist/index.d.ts +3 -1
  138. package/dist/index.js +5 -4
  139. package/dist/live/csrf.d.ts +2 -0
  140. package/dist/live/csrf.js +60 -0
  141. package/dist/live/dispatcher-live.d.ts +7 -0
  142. package/dist/live/dispatcher-live.js +286 -0
  143. package/dist/live/envelopes.d.ts +101 -0
  144. package/dist/live/envelopes.js +35 -0
  145. package/dist/live/error-mapping.d.ts +16 -0
  146. package/dist/live/error-mapping.js +82 -0
  147. package/dist/live/index.d.ts +7 -0
  148. package/dist/live/index.js +5 -0
  149. package/dist/live/locale.d.ts +2 -0
  150. package/dist/live/locale.js +25 -0
  151. package/dist/live/sse-stream.d.ts +14 -0
  152. package/dist/live/sse-stream.js +128 -0
  153. package/dist/primitives.d.ts +45 -36
  154. package/dist/primitives.js +1 -1
  155. package/dist/session/session-ended.d.ts +1 -1
  156. package/dist/tokens.d.ts +3 -4
  157. package/dist/tokens.js +4 -5
  158. package/dist/web/app/app-schema-boot.d.ts +19 -0
  159. package/dist/web/app/app-schema-boot.js +124 -0
  160. package/dist/web/app/browser-locale.d.ts +22 -0
  161. package/dist/web/app/browser-locale.js +78 -0
  162. package/dist/web/app/client-plugin.d.ts +106 -0
  163. package/dist/web/app/client-plugin.js +12 -0
  164. package/dist/web/app/create-app.d.ts +104 -0
  165. package/dist/web/app/create-app.js +498 -0
  166. package/dist/web/app/create-public-surface.d.ts +36 -0
  167. package/dist/web/app/create-public-surface.js +40 -0
  168. package/dist/web/app/dashboard-body.d.ts +3 -0
  169. package/dist/web/app/dashboard-body.js +865 -0
  170. package/dist/web/app/dashboard-refresh.d.ts +6 -0
  171. package/dist/web/app/dashboard-refresh.js +15 -0
  172. package/dist/web/app/document-lang-sync.d.ts +4 -0
  173. package/dist/web/app/document-lang-sync.js +27 -0
  174. package/dist/web/app/draft-storage.d.ts +11 -0
  175. package/dist/web/app/draft-storage.js +53 -0
  176. package/dist/web/app/nav-providers-context.d.ts +13 -0
  177. package/dist/web/app/nav-providers-context.js +18 -0
  178. package/dist/web/app/nav.d.ts +40 -0
  179. package/dist/web/app/nav.js +231 -0
  180. package/dist/web/app/plain-content-editor.d.ts +3 -0
  181. package/dist/web/app/plain-content-editor.js +30 -0
  182. package/dist/web/app/relative-time.d.ts +10 -0
  183. package/dist/web/app/relative-time.js +56 -0
  184. package/dist/web/app/resolvers-context.d.ts +12 -0
  185. package/dist/web/app/resolvers-context.js +10 -0
  186. package/dist/web/app/rich-content-editor.d.ts +3 -0
  187. package/dist/web/app/rich-content-editor.js +15 -0
  188. package/dist/web/app/root-error-fallback.d.ts +2 -0
  189. package/dist/web/app/root-error-fallback.js +21 -0
  190. package/dist/web/app/screen-error-fallback.d.ts +6 -0
  191. package/dist/web/app/screen-error-fallback.js +17 -0
  192. package/dist/web/app/tiptap-editor.d.ts +3 -0
  193. package/dist/web/app/tiptap-editor.js +120 -0
  194. package/dist/web/app/toast-action-notifier.d.ts +5 -0
  195. package/dist/web/app/toast-action-notifier.js +17 -0
  196. package/dist/web/components/config-cascade.d.ts +13 -0
  197. package/dist/web/components/config-cascade.js +155 -0
  198. package/dist/web/components/config-source-badge.d.ts +6 -0
  199. package/dist/web/components/config-source-badge.js +55 -0
  200. package/dist/web/default-color-scheme.d.ts +2 -0
  201. package/dist/web/default-color-scheme.js +3 -0
  202. package/dist/web/icons.d.ts +94 -0
  203. package/dist/web/icons.js +100 -0
  204. package/dist/web/index.d.ts +78 -0
  205. package/dist/web/index.js +53 -0
  206. package/dist/web/layout/app-layout.d.ts +21 -0
  207. package/dist/web/layout/app-layout.js +8 -0
  208. package/dist/web/layout/avatar.d.ts +12 -0
  209. package/dist/web/layout/avatar.js +63 -0
  210. package/dist/web/layout/default-app-shell.d.ts +41 -0
  211. package/dist/web/layout/default-app-shell.js +16 -0
  212. package/dist/web/layout/editor-panel.d.ts +10 -0
  213. package/dist/web/layout/editor-panel.js +29 -0
  214. package/dist/web/layout/fill-classes.d.ts +9 -0
  215. package/dist/web/layout/fill-classes.js +15 -0
  216. package/dist/web/layout/filter-app-schema-navs.d.ts +7 -0
  217. package/dist/web/layout/filter-app-schema-navs.js +68 -0
  218. package/dist/web/layout/header-action-group.d.ts +6 -0
  219. package/dist/web/layout/header-action-group.js +8 -0
  220. package/dist/web/layout/header-overflow-menu.d.ts +4 -0
  221. package/dist/web/layout/header-overflow-menu.js +8 -0
  222. package/dist/web/layout/language-menu-items.d.ts +8 -0
  223. package/dist/web/layout/language-menu-items.js +16 -0
  224. package/dist/web/layout/language-switcher.d.ts +25 -0
  225. package/dist/web/layout/language-switcher.js +46 -0
  226. package/dist/web/layout/nav-tree.d.ts +19 -0
  227. package/dist/web/layout/nav-tree.js +536 -0
  228. package/dist/web/layout/page-header-slot.d.ts +25 -0
  229. package/dist/web/layout/page-header-slot.js +50 -0
  230. package/dist/web/layout/profile-menu.d.ts +13 -0
  231. package/dist/web/layout/profile-menu.js +6 -0
  232. package/dist/web/layout/shell-breadcrumb.d.ts +11 -0
  233. package/dist/web/layout/shell-breadcrumb.js +34 -0
  234. package/dist/web/layout/shell-header.d.ts +12 -0
  235. package/dist/web/layout/shell-header.js +159 -0
  236. package/dist/web/layout/sidebar-brand.d.ts +15 -0
  237. package/dist/web/layout/sidebar-brand.js +9 -0
  238. package/dist/web/layout/sidebar-panel.d.ts +41 -0
  239. package/dist/web/layout/sidebar-panel.js +107 -0
  240. package/dist/web/layout/sidebar-user.d.ts +8 -0
  241. package/dist/web/layout/sidebar-user.js +17 -0
  242. package/dist/web/layout/sidebar.d.ts +17 -0
  243. package/dist/web/layout/sidebar.js +11 -0
  244. package/dist/web/layout/target-resolver-stub.d.ts +13 -0
  245. package/dist/web/layout/target-resolver-stub.js +61 -0
  246. package/dist/web/layout/target-url.d.ts +12 -0
  247. package/dist/web/layout/target-url.js +77 -0
  248. package/dist/web/layout/theme-label.d.ts +15 -0
  249. package/dist/web/layout/theme-label.js +35 -0
  250. package/dist/web/layout/theme-menu-item.d.ts +12 -0
  251. package/dist/web/layout/theme-menu-item.js +16 -0
  252. package/dist/web/layout/theme-toggle.d.ts +17 -0
  253. package/dist/web/layout/theme-toggle.js +22 -0
  254. package/dist/web/layout/topbar.d.ts +8 -0
  255. package/dist/web/layout/topbar.js +4 -0
  256. package/dist/web/layout/workspace-shell.d.ts +63 -0
  257. package/dist/web/layout/workspace-shell.js +220 -0
  258. package/dist/web/layout/workspace-switcher.d.ts +15 -0
  259. package/dist/web/layout/workspace-switcher.js +36 -0
  260. package/dist/web/lib/accept-attr.d.ts +1 -0
  261. package/dist/web/lib/accept-attr.js +6 -0
  262. package/dist/web/lib/clamp.d.ts +1 -0
  263. package/dist/web/lib/clamp.js +3 -0
  264. package/dist/web/lib/cn.d.ts +6 -0
  265. package/dist/web/lib/cn.js +9 -0
  266. package/dist/web/lib/download.d.ts +2 -0
  267. package/dist/web/lib/download.js +24 -0
  268. package/dist/web/lib/file-ref-download.d.ts +15 -0
  269. package/dist/web/lib/file-ref-download.js +62 -0
  270. package/dist/web/lib/file-upload-form-data.d.ts +7 -0
  271. package/dist/web/lib/file-upload-form-data.js +11 -0
  272. package/dist/web/lib/resize-image.d.ts +1 -0
  273. package/dist/web/lib/resize-image.js +66 -0
  274. package/dist/web/lib/upload-file-ref.d.ts +9 -0
  275. package/dist/web/lib/upload-file-ref.js +29 -0
  276. package/dist/web/primitives/action-menu.d.ts +34 -0
  277. package/dist/web/primitives/action-menu.js +30 -0
  278. package/dist/web/primitives/calendar-popover.d.ts +13 -0
  279. package/dist/web/primitives/calendar-popover.js +76 -0
  280. package/dist/web/primitives/combobox.d.ts +56 -0
  281. package/dist/web/primitives/combobox.js +127 -0
  282. package/dist/web/primitives/date-field.d.ts +18 -0
  283. package/dist/web/primitives/date-field.js +74 -0
  284. package/dist/web/primitives/date-input.d.ts +1 -0
  285. package/dist/web/primitives/date-input.js +5 -0
  286. package/dist/web/primitives/date-parse.d.ts +11 -0
  287. package/dist/web/primitives/date-parse.js +159 -0
  288. package/dist/web/primitives/dialog.d.ts +3 -0
  289. package/dist/web/primitives/dialog.js +42 -0
  290. package/dist/web/primitives/drawer.d.ts +3 -0
  291. package/dist/web/primitives/drawer.js +17 -0
  292. package/dist/web/primitives/dropdown-menu.d.ts +15 -0
  293. package/dist/web/primitives/dropdown-menu.js +56 -0
  294. package/dist/web/primitives/embedded-list-input.d.ts +9 -0
  295. package/dist/web/primitives/embedded-list-input.js +382 -0
  296. package/dist/web/primitives/file-thumbnail.d.ts +31 -0
  297. package/dist/web/primitives/file-thumbnail.js +90 -0
  298. package/dist/web/primitives/file-upload.d.ts +21 -0
  299. package/dist/web/primitives/file-upload.js +56 -0
  300. package/dist/web/primitives/file-value-list.d.ts +3 -0
  301. package/dist/web/primitives/file-value-list.js +22 -0
  302. package/dist/web/primitives/index.d.ts +34 -0
  303. package/dist/web/primitives/index.js +2023 -0
  304. package/dist/web/primitives/json-view.d.ts +7 -0
  305. package/dist/web/primitives/json-view.js +84 -0
  306. package/dist/web/primitives/layout.d.ts +27 -0
  307. package/dist/web/primitives/layout.js +30 -0
  308. package/dist/web/primitives/lightbox.d.ts +3 -0
  309. package/dist/web/primitives/lightbox.js +36 -0
  310. package/dist/web/primitives/locale-number.d.ts +2 -0
  311. package/dist/web/primitives/locale-number.js +54 -0
  312. package/dist/web/primitives/located-timestamp-input.d.ts +22 -0
  313. package/dist/web/primitives/located-timestamp-input.js +22 -0
  314. package/dist/web/primitives/metric.d.ts +5 -0
  315. package/dist/web/primitives/metric.js +18 -0
  316. package/dist/web/primitives/modal-shell.d.ts +17 -0
  317. package/dist/web/primitives/modal-shell.js +9 -0
  318. package/dist/web/primitives/modal.d.ts +3 -0
  319. package/dist/web/primitives/modal.js +13 -0
  320. package/dist/web/primitives/money-input.d.ts +18 -0
  321. package/dist/web/primitives/money-input.js +122 -0
  322. package/dist/web/primitives/narrow-pinned-footer.d.ts +12 -0
  323. package/dist/web/primitives/narrow-pinned-footer.js +153 -0
  324. package/dist/web/primitives/number-input.d.ts +18 -0
  325. package/dist/web/primitives/number-input.js +53 -0
  326. package/dist/web/primitives/option-groups.d.ts +11 -0
  327. package/dist/web/primitives/option-groups.js +27 -0
  328. package/dist/web/primitives/page-header.d.ts +3 -0
  329. package/dist/web/primitives/page-header.js +52 -0
  330. package/dist/web/primitives/promo-panel.d.ts +3 -0
  331. package/dist/web/primitives/promo-panel.js +11 -0
  332. package/dist/web/primitives/segmented-select.d.ts +21 -0
  333. package/dist/web/primitives/segmented-select.js +62 -0
  334. package/dist/web/primitives/share-actions.d.ts +4 -0
  335. package/dist/web/primitives/share-actions.js +56 -0
  336. package/dist/web/primitives/status-badge.d.ts +3 -0
  337. package/dist/web/primitives/status-badge.js +5 -0
  338. package/dist/web/primitives/sticky-action-bar.d.ts +5 -0
  339. package/dist/web/primitives/sticky-action-bar.js +15 -0
  340. package/dist/web/primitives/tabs.d.ts +3 -0
  341. package/dist/web/primitives/tabs.js +107 -0
  342. package/dist/web/primitives/timestamp-input.d.ts +27 -0
  343. package/dist/web/primitives/timestamp-input.js +87 -0
  344. package/dist/web/primitives/toast.d.ts +19 -0
  345. package/dist/web/primitives/toast.js +63 -0
  346. package/dist/web/primitives/tz-input.d.ts +11 -0
  347. package/dist/web/primitives/tz-input.js +8 -0
  348. package/dist/web/primitives/tz-options.d.ts +4 -0
  349. package/dist/web/primitives/tz-options.js +17 -0
  350. package/dist/web/primitives/use-keyboard-inset.d.ts +1 -0
  351. package/dist/web/primitives/use-keyboard-inset.js +28 -0
  352. package/dist/web/primitives/use-narrow-viewport.d.ts +4 -0
  353. package/dist/web/primitives/use-narrow-viewport.js +46 -0
  354. package/dist/web/react-css-custom-properties.d.ts +6 -0
  355. package/dist/web/react-css-custom-properties.js +1 -0
  356. package/dist/web/sse/live-events.d.ts +15 -0
  357. package/dist/web/sse/live-events.js +148 -0
  358. package/dist/web/theme-plugin.d.ts +41 -0
  359. package/dist/web/theme-plugin.js +123 -0
  360. package/dist/web/tokens.d.ts +24 -0
  361. package/dist/web/tokens.js +203 -0
  362. package/dist/web/ui/avatar.d.ts +11 -0
  363. package/dist/web/ui/avatar.js +25 -0
  364. package/dist/web/ui/badge.d.ts +9 -0
  365. package/dist/web/ui/badge.js +26 -0
  366. package/dist/web/ui/breadcrumb.d.ts +11 -0
  367. package/dist/web/ui/breadcrumb.js +29 -0
  368. package/dist/web/ui/button.d.ts +10 -0
  369. package/dist/web/ui/button.js +37 -0
  370. package/dist/web/ui/checkbox.d.ts +4 -0
  371. package/dist/web/ui/checkbox.js +11 -0
  372. package/dist/web/ui/input.d.ts +3 -0
  373. package/dist/web/ui/input.js +8 -0
  374. package/dist/web/ui/label.d.ts +4 -0
  375. package/dist/web/ui/label.js +10 -0
  376. package/dist/web/ui/resizable.d.ts +7 -0
  377. package/dist/web/ui/resizable.js +16 -0
  378. package/dist/web/ui/separator.d.ts +4 -0
  379. package/dist/web/ui/separator.js +10 -0
  380. package/dist/web/ui/sheet.d.ts +14 -0
  381. package/dist/web/ui/sheet.js +42 -0
  382. package/dist/web/ui/sidebar.d.ts +73 -0
  383. package/dist/web/ui/sidebar.js +211 -0
  384. package/dist/web/ui/skeleton.d.ts +2 -0
  385. package/dist/web/ui/skeleton.js +7 -0
  386. package/dist/web/ui/switch.d.ts +6 -0
  387. package/dist/web/ui/switch.js +10 -0
  388. package/dist/web/ui/table.d.ts +10 -0
  389. package/dist/web/ui/table.js +30 -0
  390. package/dist/web/ui/tabs.d.ts +11 -0
  391. package/dist/web/ui/tabs.js +31 -0
  392. package/dist/web/ui/textarea.d.ts +3 -0
  393. package/dist/web/ui/textarea.js +8 -0
  394. package/dist/web/ui/tooltip.d.ts +7 -0
  395. package/dist/web/ui/tooltip.js +19 -0
  396. package/dist/web/ui/use-mobile.d.ts +1 -0
  397. package/dist/web/ui/use-mobile.js +16 -0
  398. package/dist/web/version/update-checker.d.ts +9 -0
  399. package/dist/web/version/update-checker.js +88 -0
  400. package/dist/web/widgets/ai-text-field.d.ts +36 -0
  401. package/dist/web/widgets/ai-text-field.js +137 -0
  402. package/dist/web/widgets/bounded-load-cache.d.ts +1 -0
  403. package/dist/web/widgets/bounded-load-cache.js +25 -0
  404. package/dist/web/widgets/chart-window.d.ts +58 -0
  405. package/dist/web/widgets/chart-window.js +190 -0
  406. package/dist/web/widgets/charts.d.ts +208 -0
  407. package/dist/web/widgets/charts.js +685 -0
  408. package/dist/web/widgets/collapsible-section.d.ts +10 -0
  409. package/dist/web/widgets/collapsible-section.js +17 -0
  410. package/dist/web/widgets/dashboard-list.d.ts +21 -0
  411. package/dist/web/widgets/dashboard-list.js +45 -0
  412. package/dist/web/widgets/detail-list.d.ts +15 -0
  413. package/dist/web/widgets/detail-list.js +8 -0
  414. package/dist/web/widgets/drawer.d.ts +65 -0
  415. package/dist/web/widgets/drawer.js +177 -0
  416. package/dist/web/widgets/feed-list.d.ts +13 -0
  417. package/dist/web/widgets/feed-list.js +9 -0
  418. package/dist/web/widgets/floating-panel.d.ts +30 -0
  419. package/dist/web/widgets/floating-panel.js +242 -0
  420. package/dist/web/widgets/form-fields.d.ts +93 -0
  421. package/dist/web/widgets/form-fields.js +50 -0
  422. package/dist/web/widgets/index.d.ts +28 -0
  423. package/dist/web/widgets/index.js +31 -0
  424. package/dist/web/widgets/infinity-list.d.ts +46 -0
  425. package/dist/web/widgets/infinity-list.js +211 -0
  426. package/dist/web/widgets/mode-switch.d.ts +21 -0
  427. package/dist/web/widgets/mode-switch.js +25 -0
  428. package/dist/web/widgets/pdf-preview.d.ts +10 -0
  429. package/dist/web/widgets/pdf-preview.js +140 -0
  430. package/dist/web/widgets/photo-slots.d.ts +29 -0
  431. package/dist/web/widgets/photo-slots.js +52 -0
  432. package/dist/web/widgets/plan-card.d.ts +36 -0
  433. package/dist/web/widgets/plan-card.js +13 -0
  434. package/dist/web/widgets/progress-bar.d.ts +19 -0
  435. package/dist/web/widgets/progress-bar.js +24 -0
  436. package/dist/web/widgets/progress-list.d.ts +19 -0
  437. package/dist/web/widgets/progress-list.js +11 -0
  438. package/dist/web/widgets/public-shell.d.ts +22 -0
  439. package/dist/web/widgets/public-shell.js +15 -0
  440. package/dist/web/widgets/query-table.d.ts +29 -0
  441. package/dist/web/widgets/query-table.js +30 -0
  442. package/dist/web/widgets/result-panel.d.ts +69 -0
  443. package/dist/web/widgets/result-panel.js +30 -0
  444. package/dist/web/widgets/section-card.d.ts +12 -0
  445. package/dist/web/widgets/section-card.js +9 -0
  446. package/dist/web/widgets/sheet-parts.d.ts +9 -0
  447. package/dist/web/widgets/sheet-parts.js +11 -0
  448. package/dist/web/widgets/side-by-side-table.d.ts +31 -0
  449. package/dist/web/widgets/side-by-side-table.js +11 -0
  450. package/dist/web/widgets/stat.d.ts +54 -0
  451. package/dist/web/widgets/stat.js +65 -0
  452. package/dist/web/widgets/states.d.ts +23 -0
  453. package/dist/web/widgets/states.js +20 -0
  454. package/dist/web/widgets/status-badge.d.ts +15 -0
  455. package/dist/web/widgets/status-badge.js +24 -0
  456. package/dist/web/widgets/step-bar.d.ts +35 -0
  457. package/dist/web/widgets/step-bar.js +60 -0
  458. package/dist/web/widgets/upload-zone.d.ts +24 -0
  459. package/dist/web/widgets/upload-zone.js +108 -0
  460. package/dist/web/widgets/use-draft.d.ts +20 -0
  461. package/dist/web/widgets/use-draft.js +21 -0
  462. package/dist/web/widgets/use-pointer-drag.d.ts +21 -0
  463. package/dist/web/widgets/use-pointer-drag.js +53 -0
  464. package/package.json +114 -7
  465. package/src/changes.json +92 -0
  466. package/src/web/fonts/OFL.txt +93 -0
  467. package/src/web/fonts/ibm-plex-mono-latin-400.woff2 +0 -0
  468. package/src/web/fonts/ibm-plex-mono-latin-500.woff2 +0 -0
  469. package/src/web/fonts/ibm-plex-mono-latin-ext-400.woff2 +0 -0
  470. package/src/web/fonts/ibm-plex-mono-latin-ext-500.woff2 +0 -0
  471. package/src/web/fonts/ibm-plex-sans-latin-400.woff2 +0 -0
  472. package/src/web/fonts/ibm-plex-sans-latin-500.woff2 +0 -0
  473. package/src/web/fonts/ibm-plex-sans-latin-600.woff2 +0 -0
  474. package/src/web/fonts/ibm-plex-sans-latin-ext-400.woff2 +0 -0
  475. package/src/web/fonts/ibm-plex-sans-latin-ext-500.woff2 +0 -0
  476. package/src/web/fonts/ibm-plex-sans-latin-ext-600.woff2 +0 -0
  477. package/src/web/styles.css +405 -0
@@ -0,0 +1,10 @@
1
+ import { type ReactNode } from "react";
2
+ /** Aufklappbare Sektion (native <details>, aber React-kontrolliert: sonst
3
+ * springt das open-Attribut bei jedem Parent-Re-Render auf den Initialwert
4
+ * zurück). Eine Optik für alle „Erweitert"/„Mehr"-Abschnitte. */
5
+ export declare function CollapsibleSection({ title, defaultOpen, children, testId, }: {
6
+ readonly title: string;
7
+ readonly defaultOpen?: boolean;
8
+ readonly children: ReactNode;
9
+ readonly testId?: string;
10
+ }): ReactNode;
@@ -0,0 +1,17 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { ChevronRight } from "lucide-react";
3
+ import { useEffect, useState } from "react";
4
+ /** Aufklappbare Sektion (native <details>, aber React-kontrolliert: sonst
5
+ * springt das open-Attribut bei jedem Parent-Re-Render auf den Initialwert
6
+ * zurück). Eine Optik für alle „Erweitert"/„Mehr"-Abschnitte. */
7
+ export function CollapsibleSection({ title, defaultOpen = false, children, testId, }) {
8
+ const [open, setOpen] = useState(defaultOpen);
9
+ // useState(defaultOpen) liest nur den Mount-Wert — ein async hydrierter
10
+ // Draft flippt `defaultOpen` zu spät für den Lazy-Initializer. Open-only
11
+ // Effect: kämpft nie gegen ein manuelles Zuklappen des Users.
12
+ useEffect(() => {
13
+ if (defaultOpen)
14
+ setOpen(true);
15
+ }, [defaultOpen]);
16
+ return (_jsxs("details", { "data-testid": testId, className: "group rounded-lg border bg-card", open: open, onToggle: (e) => setOpen(e.currentTarget.open), children: [_jsxs("summary", { className: "flex cursor-pointer select-none items-center justify-between gap-2 rounded-lg px-4 py-2.5 text-sm font-medium hover:bg-muted/50 [&::-webkit-details-marker]:hidden", children: [_jsx("span", { children: title }), _jsx(ChevronRight, { "aria-hidden": "true", className: "size-4 text-muted-foreground transition-transform group-open:rotate-90" })] }), _jsx("div", { className: "border-t px-4 py-3", children: children })] }));
17
+ }
@@ -0,0 +1,21 @@
1
+ import type { ReactNode } from "react";
2
+ export type DashboardListColumn = {
3
+ readonly field: string;
4
+ /** Translated by the caller. */
5
+ readonly label: string;
6
+ readonly display?: "bar" | "badge" | "datetime";
7
+ readonly badgeToneField?: string;
8
+ };
9
+ type Row = Readonly<Record<string, unknown>>;
10
+ /** Compact 40px-row table for dashboard lists with optional bar/badge
11
+ * columns. */
12
+ export declare function DashboardListTable({ columns, rows, formatPercent, formatNumber, formatDateTime, translate, testId, }: {
13
+ readonly columns: readonly DashboardListColumn[];
14
+ readonly rows: readonly Row[];
15
+ readonly formatPercent: (fraction: number) => string;
16
+ readonly formatNumber: (value: number) => string;
17
+ readonly formatDateTime: (atMs: number) => string;
18
+ readonly translate: (key: string) => string;
19
+ readonly testId?: string;
20
+ }): ReactNode;
21
+ export {};
@@ -0,0 +1,45 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { EMPTY_VALUE_PLACEHOLDER } from "../../headless/index.js";
3
+ import { StatusBadge } from "./status-badge.js";
4
+ const BADGE_TONE = {
5
+ positive: "ok",
6
+ warn: "warn",
7
+ negative: "bad",
8
+ neutral: "muted",
9
+ };
10
+ function fractionOf(raw) {
11
+ return typeof raw === "number" && Number.isFinite(raw) ? Math.max(0, Math.min(1, raw)) : 0;
12
+ }
13
+ // Rows may carry i18n keys (quota labels, failure reasons); translate falls back to the key itself.
14
+ const I18N_KEY_SHAPE = /^[a-z][\w-]*(?:[:.][\w-]+)+$/i;
15
+ function Cell({ column, row, formatPercent, formatNumber, formatDateTime, translate, }) {
16
+ const raw = row[column.field];
17
+ if (column.display === "bar") {
18
+ const fraction = fractionOf(raw);
19
+ return (_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("div", { role: "progressbar", "aria-valuenow": Math.round(fraction * 100), "aria-valuemin": 0, "aria-valuemax": 100, "aria-label": column.label, className: "h-1 min-w-16 flex-1 overflow-hidden rounded-full bg-border", children: _jsx("div", { className: "h-full rounded-full bg-status-active", style: { width: `${fraction * 100}%` } }) }), _jsx("span", { className: "w-10 shrink-0 text-right tabular-nums text-muted-foreground", children: formatPercent(fraction) })] }));
20
+ }
21
+ if (column.display === "badge") {
22
+ if (raw === undefined || raw === null || raw === "")
23
+ return EMPTY_VALUE_PLACEHOLDER;
24
+ const toneKey = column.badgeToneField !== undefined ? row[column.badgeToneField] : undefined;
25
+ const tone = (typeof toneKey === "string" ? BADGE_TONE[toneKey] : undefined) ?? "muted";
26
+ return _jsx(StatusBadge, { tone: tone, children: String(raw) });
27
+ }
28
+ if (column.display === "datetime") {
29
+ const atMs = typeof raw === "number" ? raw : typeof raw === "string" ? Date.parse(raw) : Number.NaN;
30
+ if (!Number.isFinite(atMs))
31
+ return EMPTY_VALUE_PLACEHOLDER;
32
+ return _jsx("span", { className: "tabular-nums", children: formatDateTime(atMs) });
33
+ }
34
+ if (typeof raw === "number")
35
+ return _jsx("span", { className: "tabular-nums", children: formatNumber(raw) });
36
+ if (raw === undefined || raw === null || raw === "")
37
+ return EMPTY_VALUE_PLACEHOLDER;
38
+ const text = String(raw);
39
+ return I18N_KEY_SHAPE.test(text) ? translate(text) : text;
40
+ }
41
+ /** Compact 40px-row table for dashboard lists with optional bar/badge
42
+ * columns. */
43
+ export function DashboardListTable({ columns, rows, formatPercent, formatNumber, formatDateTime, translate, testId, }) {
44
+ return (_jsx("div", { className: "overflow-x-auto", children: _jsxs("table", { "data-testid": testId, className: "w-full text-sm", children: [_jsx("thead", { children: _jsx("tr", { className: "h-9 border-b border-border-row text-left text-xs text-muted-foreground", children: columns.map((column) => (_jsx("th", { scope: "col", className: "px-4 font-medium", children: column.label }, column.field))) }) }), _jsx("tbody", { children: rows.map((row, index) => (_jsx("tr", { className: "h-10 border-b border-border-row last:border-b-0", children: columns.map((column) => (_jsx("td", { className: "px-4", children: _jsx(Cell, { column: column, row: row, formatPercent: formatPercent, formatNumber: formatNumber, formatDateTime: formatDateTime, translate: translate }) }, column.field))) }, typeof row["id"] === "string" ? row["id"] : index))) })] }) }));
45
+ }
@@ -0,0 +1,15 @@
1
+ import type { ReactNode } from "react";
2
+ /** Read-only Schlüssel-Wert-Liste für Detail-Masken (Label links gedimmt,
3
+ * Wert rechts). Wert ist ReactNode → Badges/Chips möglich. `emphasize` hebt
4
+ * eine Zeile hervor (z.B. das Endergebnis in einem Rechner). */
5
+ export declare function DetailList({ rows, testId, }: {
6
+ readonly rows: readonly {
7
+ /** Optional stable key -- falls back to the label when omitted (fine as
8
+ * long as labels are unique; set id when they can repeat). */
9
+ readonly id?: string;
10
+ readonly label: string;
11
+ readonly value: ReactNode;
12
+ readonly emphasize?: boolean;
13
+ }[];
14
+ readonly testId?: string;
15
+ }): ReactNode;
@@ -0,0 +1,8 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { cn } from "../lib/cn.js";
3
+ /** Read-only Schlüssel-Wert-Liste für Detail-Masken (Label links gedimmt,
4
+ * Wert rechts). Wert ist ReactNode → Badges/Chips möglich. `emphasize` hebt
5
+ * eine Zeile hervor (z.B. das Endergebnis in einem Rechner). */
6
+ export function DetailList({ rows, testId, }) {
7
+ return (_jsx("dl", { "data-testid": testId, className: "@container flex flex-col divide-y", children: rows.map((row) => (_jsxs("div", { className: "grid grid-cols-1 gap-0.5 py-2.5 @md:grid-cols-[200px_1fr] @md:gap-4", children: [_jsx("dt", { className: cn("text-sm text-muted-foreground", row.emphasize === true && "font-semibold text-foreground"), children: row.label }), _jsx("dd", { className: cn("text-sm font-medium", row.emphasize === true && "font-semibold"), children: row.value })] }, row.id ?? row.label))) }));
8
+ }
@@ -0,0 +1,65 @@
1
+ import { type ReactNode } from "react";
2
+ export type DrawerProps = {
3
+ readonly open: boolean;
4
+ readonly onOpenChange: (open: boolean) => void;
5
+ readonly side?: "left" | "right" | "top" | "bottom";
6
+ readonly title?: ReactNode;
7
+ readonly description?: ReactNode;
8
+ readonly footer?: ReactNode;
9
+ readonly children: ReactNode;
10
+ readonly testId?: string;
11
+ /** Header close (X). Default `true`. Turn off when the caller's own
12
+ * footer already has a dedicated close/cancel action, so there is only
13
+ * one way to dismiss the drawer. */
14
+ readonly showCloseButton?: boolean;
15
+ /** Panel treatment. `"flush"` (default) docks the panel against the edge —
16
+ * full extent, no radius, and a border only on the edge facing the app
17
+ * content. `"floating"` gives the detached-panel look (margin to the
18
+ * viewport edge, full corner radius). Ignored in the narrow-viewport
19
+ * fullscreen layout. */
20
+ readonly variant?: "floating" | "flush";
21
+ /** `variant="flush"` only: dock the panel below the app's ShellHeader
22
+ * (offset top by `--shell-header-height`, height shrunk to match)
23
+ * instead of covering it. Default `false` is edge-to-edge. No ShellHeader
24
+ * mounted → the variable is `0`, so this is a no-op. Ignored in the
25
+ * narrow-viewport fullscreen layout, which already takes over the whole
26
+ * screen including the header. */
27
+ readonly belowHeader?: boolean;
28
+ /** Panel width for `side="left"|"right"` (ignored for top/bottom and in
29
+ * the narrow-viewport layout). A number is pixels, a string any CSS
30
+ * length. Superseded by `resize` when that's set. Default matches the
31
+ * panel's built-in `max(600px, 37.5vw)`. */
32
+ readonly width?: number | string;
33
+ /** Opt-in drag-to-resize + maximize toggle (left/right sides only). */
34
+ readonly resize?: {
35
+ readonly defaultWidthPx?: number;
36
+ readonly minWidthPx?: number;
37
+ readonly maxWidthPx?: number;
38
+ };
39
+ /** Backdrop behind the panel. A drawer exists so the content behind it
40
+ * stays readable, so the blur is off by default. Ignored when
41
+ * `modal={false}` — there is no overlay to style then. */
42
+ readonly backdrop?: {
43
+ readonly blurPx?: number;
44
+ readonly dimPercent?: number;
45
+ };
46
+ /** `false` runs the drawer as a panel beside the page instead of over it:
47
+ * no overlay, no focus trap, and the page behind stays interactive, so
48
+ * text there can be selected and copied. Escape closes in both modes, a
49
+ * click beside the panel only in the modal one — the non-modal case
50
+ * exists to be used next to the page content, where a stray click must
51
+ * not dismiss it. With `showCloseButton={false}` and no footer action
52
+ * that leaves Escape as the only way out, so keep one of the two.
53
+ * Default `true`. */
54
+ readonly modal?: boolean;
55
+ /** Extra classes for the panel, merged over the built-in ones. Not applied
56
+ * in the narrow-viewport fullscreen layout. */
57
+ readonly panelClassName?: string;
58
+ /** The body becomes a plain flex column with no padding or scrolling of its
59
+ * own, for children that bring their own scroll area and pinned footer. */
60
+ readonly fillBody?: boolean;
61
+ };
62
+ /** Slide-in panel beside a list (e.g. mail reader next to the inbox) —
63
+ * thin wrapper over the Sheet primitive with header/body/footer slots
64
+ * so screens skip per-route Radix boilerplate. */
65
+ export declare function Drawer({ open, onOpenChange, side, title, description, footer, children, testId, showCloseButton, variant, belowHeader, width, resize, backdrop, modal, panelClassName, fillBody, }: DrawerProps): ReactNode;
@@ -0,0 +1,177 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Maximize2Icon, Minimize2Icon } from "lucide-react";
3
+ import { useEffect, useState } from "react";
4
+ import { useTranslation } from "../../index.js";
5
+ import { clamp } from "../lib/clamp.js";
6
+ import { cn } from "../lib/cn.js";
7
+ import { useIsNarrowViewport } from "../primitives/use-narrow-viewport.js";
8
+ import { Sheet, SheetDescription, SheetFooter, SheetHeader, SheetTitle } from "../ui/sheet.js";
9
+ import { DrawerSheetContent } from "./sheet-parts.js";
10
+ import { arrowKeyDelta, usePointerDrag } from "./use-pointer-drag.js";
11
+ // Mirrors primitives/index.tsx's cardFooter + cardFooterBorder (row layout,
12
+ // end-justified actions, top border, panel surface instead of the card
13
+ // footer's bg-muted/30) — those two consts aren't exported, so the
14
+ // equivalent classes are inlined here rather than growing the vendored
15
+ // SheetFooter's own default className with panel-specific styling.
16
+ const DRAWER_FOOTER_CLASS = "flex-row flex-wrap items-center justify-end border-t bg-background px-[var(--card-padding)] py-4";
17
+ const MIN_WIDTH_PX = 320;
18
+ const MAX_WIDTH_PX = 1000;
19
+ // Must match the static `max(600px,37.5vw)` in floatingSideClass — Tailwind's
20
+ // JIT can't read these at runtime, so the two are kept in sync by hand.
21
+ // 600px (vs. the old 520px floor) gives a two-column field row (e.g.
22
+ // street/number, zip/city) room to breathe, while staying well under half
23
+ // of a 1280px viewport so a narrow window isn't dominated by the drawer.
24
+ // 37.5vw (vs. the old 25vw) keeps that same 600px on a 1280–1600px window
25
+ // (25vw was still under the floor there, making the ratio dead weight up
26
+ // to 2400px) but actually grows past the floor by ~1600px, so a 1920px
27
+ // window — where the two-column row is cramped just as often — lands
28
+ // around 720px instead of being stuck at 600px alongside a 1280px window.
29
+ const DEFAULT_WIDTH_MIN_PX = 600;
30
+ const DEFAULT_WIDTH_VIEWPORT_RATIO = 0.375;
31
+ const DEFAULT_BLUR_PX = 0;
32
+ const DEFAULT_DIM_PERCENT = 20;
33
+ function defaultWidthFromViewport() {
34
+ return typeof window === "undefined"
35
+ ? DEFAULT_WIDTH_MIN_PX
36
+ : Math.max(DEFAULT_WIDTH_MIN_PX, Math.round(window.innerWidth * DEFAULT_WIDTH_VIEWPORT_RATIO));
37
+ }
38
+ function normalizeWidth(width) {
39
+ return typeof width === "number" ? `${width}px` : width;
40
+ }
41
+ // Must match the static `max(600px,37.5vw)` in sidePanelClass — Tailwind's
42
+ // JIT can't read DEFAULT_WIDTH_MIN_PX/DEFAULT_WIDTH_VIEWPORT_RATIO at
43
+ // runtime, so the two are kept in sync by hand.
44
+ // Same cap as WIDTH_CLASS: an explicit `width` must not outgrow the viewport.
45
+ const MAX_VIEWPORT_WIDTH = "85vw";
46
+ const WIDTH_CLASS = "w-[max(600px,37.5vw)] max-w-[85vw] sm:max-w-[max(600px,37.5vw)]";
47
+ // "floating": 32px margin + 32px radius so the panel reads as detached from
48
+ // the viewport edge, unlike the sheet primitive's flush-edge default.
49
+ // "flush" docks it back to that flush-edge default instead, borrowing the
50
+ // vendored Sheet's per-side border (only the edge facing the app content).
51
+ // Below the narrow-viewport breakpoint neither treatment fits — the JS hook
52
+ // decides, not a `sm:` Tailwind prefix, since the resize width below already
53
+ // comes from JS and two decision sources is the bug this avoids.
54
+ function sidePanelClass(side, narrow, variant, belowHeader) {
55
+ if (narrow)
56
+ return "inset-0 h-full w-full max-w-none rounded-none border-0 overflow-hidden";
57
+ if (variant === "flush") {
58
+ switch (side) {
59
+ // h-full would pin height to 100vh despite the shifted top; h-auto lets inset-y-0 size it.
60
+ case "left":
61
+ return `inset-y-0 left-0 ${belowHeader ? "h-auto" : "h-full"} ${WIDTH_CLASS} border-r shadow-2xl overflow-hidden`;
62
+ case "top":
63
+ return `inset-x-0 ${belowHeader ? "top-(--shell-header-height)" : "top-0"} h-auto max-h-[80vh] border-b shadow-2xl overflow-hidden`;
64
+ case "bottom":
65
+ return "inset-x-0 bottom-0 h-auto max-h-[80vh] border-t shadow-2xl overflow-hidden";
66
+ default:
67
+ return `inset-y-0 right-0 ${belowHeader ? "h-auto" : "h-full"} ${WIDTH_CLASS} border-l shadow-2xl overflow-hidden`;
68
+ }
69
+ }
70
+ switch (side) {
71
+ case "left":
72
+ return `inset-y-8 left-8 h-auto ${WIDTH_CLASS} rounded-[2rem] border shadow-2xl overflow-hidden`;
73
+ case "top":
74
+ return "inset-x-8 top-8 h-auto max-h-[80vh] rounded-[2rem] border shadow-2xl overflow-hidden";
75
+ case "bottom":
76
+ return "inset-x-8 bottom-8 h-auto max-h-[80vh] rounded-[2rem] border shadow-2xl overflow-hidden";
77
+ default:
78
+ return `inset-y-8 right-8 h-auto ${WIDTH_CLASS} rounded-[2rem] border shadow-2xl overflow-hidden`;
79
+ }
80
+ }
81
+ const DRAWER_INSET_PROPERTY = {
82
+ left: "--kumiko-drawer-inset-left",
83
+ right: "--kumiko-drawer-inset-right",
84
+ };
85
+ // Publishes the width a non-modal side drawer occupies so the shell content (styles.css) can
86
+ // narrow instead of sitting underneath it. Read from the layout box (offsetLeft/offsetWidth), not
87
+ // getBoundingClientRect: the slide-in animation moves the painted rect, and the observer would
88
+ // not fire again once it settles.
89
+ // ponytail: one owner per side, so two non-modal drawers open on the same side overwrite each
90
+ // other's value; a registry that takes the max is needed once a screen stacks them.
91
+ function usePublishDrawerInset(sheet, side, active) {
92
+ useEffect(() => {
93
+ if (!active || sheet === null || (side !== "left" && side !== "right"))
94
+ return;
95
+ const property = DRAWER_INSET_PROPERTY[side];
96
+ const root = document.documentElement;
97
+ const publish = () => {
98
+ const inset = side === "right"
99
+ ? window.innerWidth - sheet.offsetLeft
100
+ : sheet.offsetLeft + sheet.offsetWidth;
101
+ root.style.setProperty(property, `${Math.max(0, Math.round(inset))}px`);
102
+ };
103
+ publish();
104
+ const observer = new ResizeObserver(publish);
105
+ observer.observe(sheet);
106
+ window.addEventListener("resize", publish);
107
+ return () => {
108
+ observer.disconnect();
109
+ window.removeEventListener("resize", publish);
110
+ root.style.removeProperty(property);
111
+ };
112
+ }, [sheet, side, active]);
113
+ }
114
+ /** Slide-in panel beside a list (e.g. mail reader next to the inbox) —
115
+ * thin wrapper over the Sheet primitive with header/body/footer slots
116
+ * so screens skip per-route Radix boilerplate. */
117
+ export function Drawer({ open, onOpenChange, side = "right", title, description, footer, children, testId, showCloseButton = true, variant = "flush", belowHeader = false, width, resize, backdrop, modal = true, panelClassName, fillBody = false, }) {
118
+ const t = useTranslation();
119
+ const narrow = useIsNarrowViewport();
120
+ const canResize = resize !== undefined && (side === "left" || side === "right");
121
+ const customWidthStyle = !canResize && !narrow && (side === "left" || side === "right") && width !== undefined
122
+ ? { width: normalizeWidth(width), maxWidth: MAX_VIEWPORT_WIDTH }
123
+ : undefined;
124
+ const minWidthPx = resize?.minWidthPx ?? MIN_WIDTH_PX;
125
+ const maxWidthPx = resize?.maxWidthPx ?? MAX_WIDTH_PX;
126
+ const effectiveMaxWidthPx = () => typeof window === "undefined"
127
+ ? maxWidthPx
128
+ : Math.min(maxWidthPx, Math.round(window.innerWidth * 0.9));
129
+ const [resizedWidthPx, setResizedWidthPx] = useState(() => clamp(resize?.defaultWidthPx ?? defaultWidthFromViewport(), minWidthPx, effectiveMaxWidthPx()));
130
+ const [maximized, setMaximized] = useState(false);
131
+ const [sheet, setSheet] = useState(null);
132
+ usePublishDrawerInset(sheet, side, open && !modal && !narrow);
133
+ const blurPx = backdrop?.blurPx ?? DEFAULT_BLUR_PX;
134
+ const dimPercent = backdrop?.dimPercent ?? DEFAULT_DIM_PERCENT;
135
+ const overlayStyle = {
136
+ backgroundColor: `rgb(0 0 0 / ${dimPercent}%)`,
137
+ ...(blurPx > 0 ? { backdropFilter: `blur(${blurPx}px)` } : {}),
138
+ };
139
+ const effectiveWidthPx = maximized ? effectiveMaxWidthPx() : resizedWidthPx;
140
+ // Inline style because tailwind-merge doesn't dedupe `top-*`/`bottom-*` against the base `inset-y-0`;
141
+ // style wins over class regardless of generated CSS order.
142
+ const verticalOffsetStyle = belowHeader && variant === "flush" && !narrow && (side === "left" || side === "right")
143
+ ? { top: "var(--shell-header-height)", bottom: 0 }
144
+ : undefined;
145
+ const widthStyle = canResize && !narrow ? { width: effectiveWidthPx, maxWidth: "none" } : customWidthStyle;
146
+ const sheetStyle = widthStyle === undefined && verticalOffsetStyle === undefined
147
+ ? undefined
148
+ : { ...widthStyle, ...verticalOffsetStyle };
149
+ const handleDrag = usePointerDrag({
150
+ onStart: () => {
151
+ setMaximized(false);
152
+ return { startWidth: effectiveWidthPx };
153
+ },
154
+ onMove: ({ startWidth }, { dx }) => {
155
+ const signedDelta = side === "right" ? -dx : dx;
156
+ setResizedWidthPx(clamp(startWidth + signedDelta, minWidthPx, effectiveMaxWidthPx()));
157
+ },
158
+ });
159
+ const onHandleKeyDown = (event) => {
160
+ const keyDelta = arrowKeyDelta(event);
161
+ if (keyDelta === undefined || keyDelta.dx === 0)
162
+ return;
163
+ event.preventDefault();
164
+ setMaximized(false);
165
+ const delta = side === "right" ? -keyDelta.dx : keyDelta.dx;
166
+ // Seed from the currently visible width, not the stale `resizedWidthPx`
167
+ // state — while maximized, it still holds the pre-maximize value, so a
168
+ // key press would otherwise jump the drawer back to that old size
169
+ // instead of resizing relative to what's on screen.
170
+ setResizedWidthPx((current) => clamp((maximized ? effectiveWidthPx : current) + delta, minWidthPx, effectiveMaxWidthPx()));
171
+ };
172
+ return (_jsx(Sheet, { open: open, onOpenChange: onOpenChange, modal: modal, children: _jsxs(DrawerSheetContent, { ref: setSheet, side: side, "data-testid": testId, overlayStyle: overlayStyle,
173
+ // Radix already drops the overlay and the focus trap for a
174
+ // non-modal Root; only the dismiss-on-outside-interaction is left
175
+ // to suppress, so a click into the page behind keeps the panel open.
176
+ onInteractOutside: modal ? undefined : (event) => event.preventDefault(), showCloseButton: showCloseButton, closeLabel: t("kumiko.dialog.close"), className: cn(sidePanelClass(side, narrow, variant, belowHeader), fillBody && "gap-0", !narrow && panelClassName), style: sheetStyle, children: [canResize && !narrow && (_jsx("button", { type: "button", onClick: () => setMaximized((m) => !m), "aria-pressed": maximized, "aria-label": maximized ? t("kumiko.widget.drawer.restore") : t("kumiko.widget.drawer.maximize"), className: "absolute top-4 right-14 z-10 rounded-xs p-1 text-muted-foreground opacity-70 transition-opacity hover:opacity-100 hover:bg-secondary focus-visible:ring-2 focus-visible:ring-ring focus-visible:outline-hidden", children: maximized ? (_jsx(Minimize2Icon, { className: "size-4" })) : (_jsx(Maximize2Icon, { className: "size-4" })) })), (title !== undefined || description !== undefined) && (_jsxs(SheetHeader, { children: [title !== undefined && _jsx(SheetTitle, { children: title }), description !== undefined && _jsx(SheetDescription, { children: description })] })), _jsx("div", { className: fillBody ? "flex min-h-0 flex-1 flex-col" : "flex-1 overflow-y-auto px-4", children: children }), footer !== undefined && (_jsx(SheetFooter, { className: DRAWER_FOOTER_CLASS, children: footer })), canResize && !narrow && (_jsx("div", { role: "separator", "aria-orientation": "vertical", "aria-label": t("kumiko.widget.drawer.resize"), "aria-valuenow": effectiveWidthPx, "aria-valuemin": minWidthPx, "aria-valuemax": effectiveMaxWidthPx(), tabIndex: 0, ...handleDrag, onKeyDown: onHandleKeyDown, className: cn("absolute inset-y-0 z-10 w-1 cursor-col-resize touch-none after:absolute after:inset-y-0 after:left-1/2 after:w-3 after:-translate-x-1/2 hover:bg-border", side === "right" ? "left-0 -translate-x-1/2" : "right-0 translate-x-1/2") }))] }) }));
177
+ }
@@ -0,0 +1,13 @@
1
+ import type { ReactNode } from "react";
2
+ export type FeedRow = {
3
+ readonly id: string;
4
+ readonly primary: string;
5
+ readonly trailing?: string;
6
+ };
7
+ /** Nicht-tabellarische Kurzliste (z.B. "nächste Termine") — Primary-Text +
8
+ * optionaler rechtsbündiger Trailing-Wert pro Zeile. */
9
+ export declare function FeedList({ rows, emptyContent, testId, }: {
10
+ readonly rows: readonly FeedRow[];
11
+ readonly emptyContent?: ReactNode;
12
+ readonly testId?: string;
13
+ }): ReactNode;
@@ -0,0 +1,9 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /** Nicht-tabellarische Kurzliste (z.B. "nächste Termine") — Primary-Text +
3
+ * optionaler rechtsbündiger Trailing-Wert pro Zeile. */
4
+ export function FeedList({ rows, emptyContent, testId, }) {
5
+ if (rows.length === 0) {
6
+ return _jsx("div", { "data-testid": testId, children: emptyContent });
7
+ }
8
+ return (_jsx("ul", { "data-testid": testId, className: "flex max-h-64 flex-col overflow-y-auto pr-1 text-sm", children: rows.map((row) => (_jsxs("li", { className: "flex justify-between gap-4 border-b py-1.5 last:border-b-0", children: [_jsx("span", { children: row.primary }), row.trailing !== undefined && (_jsx("span", { className: "tabular-nums text-muted-foreground", children: row.trailing }))] }, row.id))) }));
9
+ }
@@ -0,0 +1,30 @@
1
+ import { type ReactNode } from "react";
2
+ export type FloatingPanelGeometry = {
3
+ readonly x: number;
4
+ readonly y: number;
5
+ readonly width: number;
6
+ readonly height: number;
7
+ };
8
+ export type FloatingPanelProps = {
9
+ /** Header content; the header is the move handle. */
10
+ readonly title: ReactNode;
11
+ /** Header buttons (dock, minimize, close). Pointer-down on interactive
12
+ * elements does not start a drag. */
13
+ readonly headerActions?: ReactNode;
14
+ readonly children: ReactNode;
15
+ /** localStorage key; without it the geometry isn't persisted. */
16
+ readonly storageKey?: string;
17
+ /** Default 400x560, bottom-right with a 24px margin. */
18
+ readonly defaultGeometry?: Partial<FloatingPanelGeometry>;
19
+ readonly minWidthPx?: number;
20
+ readonly minHeightPx?: number;
21
+ /** Default: viewport width minus twice the margin. */
22
+ readonly maxWidthPx?: number;
23
+ /** Default: viewport height minus twice the margin. */
24
+ readonly maxHeightPx?: number;
25
+ readonly testId?: string;
26
+ };
27
+ /** Non-modal panel floating above the page: draggable by its header,
28
+ * resizable from all edges and corners, clamped to the viewport, geometry
29
+ * optionally remembered. On narrow viewports it becomes a full-screen sheet. */
30
+ export declare function FloatingPanel({ title, headerActions, children, storageKey, defaultGeometry, minWidthPx, minHeightPx, maxWidthPx, maxHeightPx, testId, }: FloatingPanelProps): ReactNode;