@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,382 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ // EmbeddedListInput — row/totals table for a createEmbeddedListField
3
+ // (invoice-positions-style) field. Controlled: rows, derived values, and
4
+ // issue groups are computed by the caller; this component only renders
5
+ // and reports interaction (cell edits, row add/remove/duplicate/move,
6
+ // paste).
7
+ //
8
+ // Only one of the two layouts (table for md+, cards below md) is mounted
9
+ // at a time, picked via useIsNarrowViewport — mounting both and toggling
10
+ // with `hidden`/`md:hidden` left two live inputs per cell sharing one DOM
11
+ // id (#1854). The `hidden md:block` / `md:hidden` classes stay on the
12
+ // wrapper divs as a defensive fallback (e.g. SSR/no-JS, where
13
+ // getServerSnapshot forces the desktop layout) even though
14
+ // useIsNarrowViewport — unlike the vendored useIsMobile it replaced —
15
+ // already reports the correct value on the very first client render.
16
+ //
17
+ // ponytail: crossing the mobile/desktop breakpoint unmounts the active
18
+ // layout and mounts the other, so an in-progress cell draft (uncommitted
19
+ // MoneyInput text, IME composition) and focus are lost — accepted trade-off
20
+ // for the single-mount-per-side fix above. Upgrade: lift per-cell draft
21
+ // state into a `draftsByCellId` map here that survives the layout swap.
22
+ import { ArrowDown, ArrowUp, Copy, Plus, Trash2 } from "lucide-react";
23
+ import { Fragment, useEffect, useRef, useState, } from "react";
24
+ import { applyFormatSpec } from "../../headless/index.js";
25
+ import { useLocale, useTranslation } from "../../index.js";
26
+ import { cn } from "../lib/cn.js";
27
+ import { Button as UiButton } from "../ui/button.js";
28
+ import { Checkbox } from "../ui/checkbox.js";
29
+ import { Input as UiInput } from "../ui/input.js";
30
+ import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "../ui/table.js";
31
+ import { ComboboxInput } from "./combobox.js";
32
+ import { DateInput } from "./date-input.js";
33
+ import { formatMoney, MoneyInput } from "./money-input.js";
34
+ import { SegmentedControl } from "./segmented-select.js";
35
+ import { TimestampInput } from "./timestamp-input.js";
36
+ import { useIsNarrowViewport } from "./use-narrow-viewport.js";
37
+ // `input[type=hidden]` excluded — ComboboxInput renders one as a plain
38
+ // name-carrier before its focusable trigger button.
39
+ const FOCUSABLE_SELECTOR = "input:not([type=hidden]), button, [tabindex]";
40
+ // Widths in rem include the cell's padding. Short-value columns are fixed so
41
+ // the table's free width goes to the text/reference columns, which only
42
+ // declare a floor (about 16 characters plus padding or a chevron).
43
+ const FLEXIBLE_COLUMN_MIN_REM = 12;
44
+ // Four size-7 icon buttons (duplicate, up, down, remove) plus the cell's px-1 and border.
45
+ const ACTIONS_COLUMN_REM = 8.5;
46
+ function fixedColumnRem(type) {
47
+ switch (type) {
48
+ case "number":
49
+ case "decimal":
50
+ return 7.5;
51
+ case "money":
52
+ return 10;
53
+ case "date":
54
+ return 10;
55
+ case "timestamp":
56
+ return 16;
57
+ case "boolean":
58
+ return 4;
59
+ case "select":
60
+ return 12;
61
+ case "text":
62
+ case "reference":
63
+ return undefined;
64
+ default: {
65
+ const exhaustiveCheck = type;
66
+ return exhaustiveCheck;
67
+ }
68
+ }
69
+ }
70
+ // Widths sit on <col>: in a table-fixed table they are the column widths, and the
71
+ // columns without one (text/reference) are the ones that absorb the free width.
72
+ function columnWidthStyle(type) {
73
+ const rem = fixedColumnRem(type);
74
+ return rem === undefined ? undefined : { width: `${rem}rem` };
75
+ }
76
+ // A table-fixed table distributes only the width beyond this sum; below it the
77
+ // scroll container scrolls instead of squeezing columns.
78
+ function tableMinWidthRem(columns, hasActions) {
79
+ const columnsRem = columns.reduce((sum, column) => sum + (fixedColumnRem(column.type) ?? FLEXIBLE_COLUMN_MIN_REM), 0);
80
+ return columnsRem + (hasActions ? ACTIONS_COLUMN_REM : 0);
81
+ }
82
+ function columnAlignClass(type) {
83
+ switch (type) {
84
+ case "money":
85
+ case "number":
86
+ case "decimal":
87
+ return "text-right";
88
+ case "boolean":
89
+ return "text-center";
90
+ case "date":
91
+ case "timestamp":
92
+ case "text":
93
+ case "select":
94
+ case "reference":
95
+ return "text-left";
96
+ default: {
97
+ const exhaustiveCheck = type;
98
+ return exhaustiveCheck;
99
+ }
100
+ }
101
+ }
102
+ // Exported (unlike columnWidthClass/columnAlignClass above) because
103
+ // happy-dom performs no layout — scrollWidth/clientWidth/getBoundingClientRect
104
+ // always read 0 in tests, so the only way to cover this decision at all is
105
+ // as a pure function of the three scroll metrics, tested directly.
106
+ // The 1px slack absorbs sub-pixel rounding from browser zoom/fractional
107
+ // scaling, which would otherwise report a spurious sliver of "still
108
+ // scrollable" at a fully-scrolled edge.
109
+ export function computeScrollAffordance(scrollLeft, scrollWidth, clientWidth) {
110
+ return {
111
+ canScrollLeft: scrollLeft > 1,
112
+ canScrollRight: scrollLeft + clientWidth < scrollWidth - 1,
113
+ };
114
+ }
115
+ function formatTotalValue(total, columns, currency, locale) {
116
+ const column = columns.find((c) => c.field === total.field);
117
+ if (column?.type === "money")
118
+ return formatMoney(total.value, currency, locale);
119
+ return total.value.toLocaleString(locale);
120
+ }
121
+ // Tab/newline-delimited clipboard text → 2D string grid. Not a regex
122
+ // parse — split on the literal delimiters, trim a trailing `\r` per line
123
+ // (Windows clipboard line endings).
124
+ function parsePasteGrid(text) {
125
+ return text.split("\n").map((line) => {
126
+ const withoutCr = line.endsWith("\r") ? line.slice(0, -1) : line;
127
+ return withoutCr.split("\t");
128
+ });
129
+ }
130
+ function IssueMessages({ issues, testId, constrainWidth, }) {
131
+ const t = useTranslation();
132
+ if (issues === undefined || issues.length === 0)
133
+ return null;
134
+ return (_jsx("div", { role: "alert", "data-testid": testId, className: cn("text-xs text-destructive", constrainWidth === true && "max-w-[16rem] whitespace-normal break-words"), children: issues.map((issue) => (_jsx("div", { children: t(issue.i18nKey, issue.params) }, `${issue.path}:${issue.code}`))) }));
135
+ }
136
+ function readOnlyCellText(column, value, currency, locale) {
137
+ if (value === null || value === undefined || value === "")
138
+ return "";
139
+ switch (column.type) {
140
+ case "boolean":
141
+ return value === true ? "✓" : "";
142
+ case "date":
143
+ case "timestamp":
144
+ return applyFormatSpec({ format: column.type, locale }, value);
145
+ case "number":
146
+ case "decimal":
147
+ return typeof value === "number"
148
+ ? applyFormatSpec({ format: column.type, locale }, value)
149
+ : String(value);
150
+ case "money":
151
+ return typeof value === "number" ? formatMoney(value, currency, locale) : String(value);
152
+ case "select":
153
+ return typeof value === "string" ? (column.optionLabels?.[value] ?? value) : String(value);
154
+ case "reference":
155
+ return typeof value === "string"
156
+ ? (column.referenceOptions?.find((o) => o.value === value)?.label ?? value)
157
+ : String(value);
158
+ case "text":
159
+ return String(value);
160
+ default: {
161
+ const exhaustiveCheck = column.type;
162
+ return exhaustiveCheck;
163
+ }
164
+ }
165
+ }
166
+ function renderCellControl({ cellId, column, label, value, disabled, onChange, currency, locale, }) {
167
+ if (column.readOnly === true && !column.derived) {
168
+ return (_jsx("div", { "data-cell-id": cellId, "data-readonly-cell": "", className: cn("min-w-0 whitespace-normal break-words py-1.5 text-sm", columnAlignClass(column.type)), children: readOnlyCellText(column, value, currency, locale) }));
169
+ }
170
+ const isDisabled = disabled || column.derived;
171
+ switch (column.type) {
172
+ case "text":
173
+ return (_jsx(UiInput, { "data-cell-id": cellId, type: "text", "aria-label": label, className: "min-w-0", disabled: isDisabled, value: typeof value === "string" ? value : "", onChange: (e) => onChange(e.target.value) }));
174
+ case "number":
175
+ case "decimal":
176
+ return (_jsx(UiInput, { "data-cell-id": cellId, type: "number", "aria-label": label, disabled: isDisabled, className: "min-w-0 text-right tabular-nums", value: typeof value === "number" ? value : "", onChange: (e) => {
177
+ const raw = e.target.value;
178
+ onChange(raw === "" ? undefined : Number(raw));
179
+ } }));
180
+ case "boolean":
181
+ return (_jsx("div", { className: "flex justify-center", children: _jsx(Checkbox, { "data-cell-id": cellId, "aria-label": label, disabled: isDisabled, checked: value === true, onCheckedChange: (checked) => onChange(checked === true) }) }));
182
+ case "date":
183
+ return (_jsx("div", { "data-cell-id": cellId, className: "w-full min-w-0", children: _jsx(DateInput, { id: cellId, name: cellId, ariaLabel: label, value: typeof value === "string" ? value : "", onChange: (v) => onChange(v), disabled: isDisabled }) }));
184
+ case "timestamp":
185
+ return (_jsx("div", { "data-cell-id": cellId, className: "w-full min-w-0", children: _jsx(TimestampInput, { id: cellId, name: cellId, ariaLabel: label, value: typeof value === "string" ? value : "", onChange: (v) => onChange(v), disabled: isDisabled }) }));
186
+ case "money":
187
+ return (_jsx("div", { "data-cell-id": cellId, className: "w-full min-w-0", children: _jsx(MoneyInput, { id: cellId, name: cellId, ariaLabel: label, value: typeof value === "number" ? value : "", onChange: (v) => onChange(v), currency: currency, disabled: isDisabled }) }));
188
+ case "select": {
189
+ const options = (column.options ?? []).map((opt) => ({
190
+ value: opt,
191
+ label: column.optionLabels?.[opt] ?? opt,
192
+ }));
193
+ if (column.display === "radio" && options.length > 0) {
194
+ return (_jsx("div", { "data-cell-id": cellId, className: "w-full min-w-0", children: _jsx(SegmentedControl, { id: cellId, name: cellId, labelProps: { "aria-label": label }, value: typeof value === "string" ? value : "", onChange: (v) => onChange(v), options: options, disabled: isDisabled }) }));
195
+ }
196
+ return (_jsx("div", { "data-cell-id": cellId, className: "w-full min-w-0", children: _jsx(ComboboxInput, { id: cellId, name: cellId, ariaLabel: label, value: typeof value === "string" ? value : "", onChange: (v) => onChange(v), options: options, disabled: isDisabled }) }));
197
+ }
198
+ case "reference":
199
+ return (_jsx("div", { "data-cell-id": cellId, className: "w-full min-w-0", children: _jsx(ComboboxInput, { id: cellId, name: cellId, ariaLabel: label, value: typeof value === "string" ? value : "", onChange: (v) => onChange(v), options: column.referenceOptions ?? [], disabled: isDisabled, loading: column.referenceLoading }) }));
200
+ default: {
201
+ const exhaustiveCheck = column.type;
202
+ return exhaustiveCheck;
203
+ }
204
+ }
205
+ }
206
+ function RowActions({ rowIndex, rowsLength, minItems, maxItems, onDuplicateRow, onMoveRow, onRemoveRow, duplicateLabel, moveUpLabel, moveDownLabel, removeLabel, testIdPrefix, buttonSizeClass = "size-7", }) {
207
+ const duplicateDisabled = maxItems !== undefined && rowsLength >= maxItems;
208
+ const removeDisabled = rowsLength <= (minItems ?? 0);
209
+ return (_jsxs("div", { className: "inline-flex items-center", children: [_jsx(UiButton, { type: "button", variant: "ghost", size: "icon", className: buttonSizeClass, "aria-label": duplicateLabel, disabled: duplicateDisabled, onClick: () => onDuplicateRow(rowIndex), "data-testid": testIdPrefix !== undefined ? `${testIdPrefix}-duplicate` : undefined, children: _jsx(Copy, { className: "size-4", "aria-hidden": "true" }) }), _jsx(UiButton, { type: "button", variant: "ghost", size: "icon", className: buttonSizeClass, "aria-label": moveUpLabel, disabled: rowIndex === 0, onClick: () => onMoveRow(rowIndex, rowIndex - 1), "data-testid": testIdPrefix !== undefined ? `${testIdPrefix}-move-up` : undefined, children: _jsx(ArrowUp, { className: "size-4", "aria-hidden": "true" }) }), _jsx(UiButton, { type: "button", variant: "ghost", size: "icon", className: buttonSizeClass, "aria-label": moveDownLabel, disabled: rowIndex === rowsLength - 1, onClick: () => onMoveRow(rowIndex, rowIndex + 1), "data-testid": testIdPrefix !== undefined ? `${testIdPrefix}-move-down` : undefined, children: _jsx(ArrowDown, { className: "size-4", "aria-hidden": "true" }) }), _jsx(UiButton, { type: "button", variant: "ghost", size: "icon", className: buttonSizeClass, "aria-label": removeLabel, disabled: removeDisabled, onClick: () => onRemoveRow(rowIndex), "data-testid": testIdPrefix !== undefined ? `${testIdPrefix}-remove` : undefined, children: _jsx(Trash2, { className: "size-4", "aria-hidden": "true" }) })] }));
210
+ }
211
+ export function EmbeddedListInput({ id, columns, rows, totals, currency, disabled, fixedRows, minItems, maxItems, listIssues, rowIssues, cellIssues, onCellChange, onAddRow, onRemoveRow, onDuplicateRow, onMoveRow, onPasteCells, addLabel, actionsLabel, removeLabel, duplicateLabel, moveUpLabel, moveDownLabel, emptyLabel, emptyCtaLabel, testId, }) {
212
+ // Callers that don't wire up the field-currency plumbing (or direct
213
+ // callers/tests that predate #1839) keep getting the same "EUR" this
214
+ // component always hardcoded.
215
+ const effectiveCurrency = currency ?? "EUR";
216
+ const t = useTranslation();
217
+ const cellLabel = (column, rowIndex) => t("kumiko.field.embedded-list.cell-label", { column: column.label, row: rowIndex + 1 });
218
+ const resolvedLocale = useLocale().locale();
219
+ const isMobile = useIsNarrowViewport();
220
+ const containerRef = useRef(null);
221
+ const [pendingFocusCellId, setPendingFocusCellId] = useState(undefined);
222
+ const [scrollAffordance, setScrollAffordance] = useState({
223
+ canScrollLeft: false,
224
+ canScrollRight: false,
225
+ });
226
+ // A callback ref (not useRef) so the setup effect below re-runs exactly
227
+ // when the scroll container itself is attached/detached — isMobile flips
228
+ // the whole subtree between mobile cards and this table (see the
229
+ // ponytail note at the top of the file), so a plain useRef wouldn't
230
+ // notice the desktop table remounting with a fresh DOM node.
231
+ const [scrollContainerEl, setScrollContainerEl] = useState(null);
232
+ // Resetting scrollLeft here is what guarantees the table always opens
233
+ // scrolled fully left (fw#2159): browsers still auto-scroll a focused
234
+ // descendant into view even inside an overflow-x-auto container, but
235
+ // that's now a real, user-drivable scroll instead of an invisible one.
236
+ useEffect(() => {
237
+ if (scrollContainerEl === null)
238
+ return;
239
+ const el = scrollContainerEl;
240
+ el.scrollLeft = 0;
241
+ const updateAffordance = () => {
242
+ setScrollAffordance(computeScrollAffordance(el.scrollLeft, el.scrollWidth, el.clientWidth));
243
+ };
244
+ updateAffordance();
245
+ el.addEventListener("scroll", updateAffordance);
246
+ const resizeObserver = new ResizeObserver(updateAffordance);
247
+ resizeObserver.observe(el);
248
+ return () => {
249
+ el.removeEventListener("scroll", updateAffordance);
250
+ resizeObserver.disconnect();
251
+ };
252
+ }, [scrollContainerEl]);
253
+ // React 19 batches the setPendingFocusCellId + onAddRow calls from the
254
+ // same keydown handler into one commit, so the new row already exists
255
+ // by the time this effect runs — no need to depend on rows.length too.
256
+ useEffect(() => {
257
+ if (pendingFocusCellId === undefined)
258
+ return;
259
+ // ponytail: capability-scoped DOM query, not a global — degrades to
260
+ // "no auto-focus" on a hypothetical native impl instead of crashing.
261
+ // `data-cell-id` sits on the focusable control itself for text/boolean
262
+ // cells, but on a non-focusable wrapper `<div>` for date/money/select/
263
+ // reference/timestamp cells (see renderCellControl) — walk into the
264
+ // wrapper for its focusable descendant instead of calling .focus() on
265
+ // a div. `input[type=hidden]` excluded: ComboboxInput (select/reference)
266
+ // renders a hidden name-carrier input before its trigger button — it
267
+ // would otherwise win the "first match in document order" query
268
+ // without ever actually receiving focus.
269
+ const matched = containerRef.current?.querySelector(`[data-cell-id="${pendingFocusCellId}"]`);
270
+ const target = matched?.matches(FOCUSABLE_SELECTOR)
271
+ ? matched
272
+ : (matched?.querySelector(FOCUSABLE_SELECTOR) ?? matched);
273
+ target?.focus();
274
+ setPendingFocusCellId(undefined);
275
+ }, [pendingFocusCellId]);
276
+ const cellId = (rowIndex, field) => `${id}-${rowIndex}-${field}`;
277
+ // handleLastCellKeyDown must attach to the last EDITABLE column, not
278
+ // columns.length - 1 — a derived column there is rendered disabled
279
+ // (renderCellControl) and never receives focus/keydown, which would
280
+ // silently kill Tab/Enter-appends-a-row whenever the table ends in a
281
+ // derived column (e.g. a trailing "amount" total).
282
+ const lastEditableIndex = columns.findLastIndex((column) => !column.derived && column.readOnly !== true);
283
+ // Fixed rows drop every row-mutation affordance but leave cells editable.
284
+ const showControls = disabled !== true && fixedRows !== true;
285
+ // The pinned actions column marks its edge with an inset shadow: in a
286
+ // border-collapse table a border-l is painted at the cell's unscrolled
287
+ // position and vanishes while content scrolls underneath.
288
+ const isHorizontallyScrollable = scrollAffordance.canScrollLeft || scrollAffordance.canScrollRight;
289
+ const addDisabled = maxItems !== undefined && rows.length >= maxItems;
290
+ const handlePaste = (rowIndex, columnIndex) => {
291
+ return (event) => {
292
+ if (onPasteCells === undefined)
293
+ return;
294
+ if (disabled === true)
295
+ return;
296
+ const text = event.clipboardData?.getData("text") ?? "";
297
+ const grid = parsePasteGrid(text);
298
+ const isMultiCell = grid.length > 1 || (grid[0]?.length ?? 0) > 1;
299
+ if (!isMultiCell)
300
+ return;
301
+ event.preventDefault();
302
+ onPasteCells(rowIndex, columnIndex, grid);
303
+ };
304
+ };
305
+ const handleLastCellKeyDown = (event) => {
306
+ if (disabled === true || fixedRows === true)
307
+ return;
308
+ const isTabForward = event.key === "Tab" && !event.shiftKey;
309
+ const isEnter = event.key === "Enter";
310
+ if (!isTabForward && !isEnter)
311
+ return;
312
+ // A select/reference last column renders its picker trigger as a
313
+ // <button> (or an open cmdk popover's own input) in the cell — Enter
314
+ // there is the browser's native button-activation, not "append a row".
315
+ // Returning before preventDefault() lets that activation proceed;
316
+ // Tab still falls through to the append-row behavior below.
317
+ if (isEnter &&
318
+ event.target instanceof HTMLElement &&
319
+ event.target.closest('button, [role="combobox"], [cmdk-input]') !== null) {
320
+ return;
321
+ }
322
+ if (maxItems !== undefined && rows.length >= maxItems)
323
+ return;
324
+ // Enter bubbles up from the cell control through this TableCell — an
325
+ // ancestor of any <form> the caller wraps the whole field in.
326
+ // preventDefault() during the bubble phase still stops that form's
327
+ // default submit, same as it stops Tab's default focus-move below.
328
+ event.preventDefault();
329
+ // readOnly cells render a non-focusable div, so focusing columns[0] would drop focus.
330
+ const firstColumn = columns.find((c) => c.derived !== true && c.readOnly !== true);
331
+ if (firstColumn !== undefined) {
332
+ setPendingFocusCellId(cellId(rows.length, firstColumn.field));
333
+ }
334
+ onAddRow();
335
+ };
336
+ const testIdFor = (suffix) => testId !== undefined ? `${testId}-${suffix}` : undefined;
337
+ if (rows.length === 0) {
338
+ return (_jsxs("div", { ref: containerRef, "data-testid": testId !== undefined ? `${testId}-empty` : "embedded-list-empty", className: "flex flex-col items-center justify-center gap-3 rounded-lg border border-dashed p-10 text-center text-sm text-muted-foreground", children: [_jsx("span", { children: emptyLabel }), showControls && (_jsxs(UiButton, { type: "button", variant: "outline", size: "sm", onClick: onAddRow, "data-testid": testId !== undefined ? `${testId}-empty-add` : "embedded-list-empty-add", children: [_jsx(Plus, { className: "size-4", "aria-hidden": "true" }), emptyCtaLabel] }))] }));
339
+ }
340
+ const hasTotals = totals !== undefined && totals.length > 0;
341
+ return (_jsxs("div", { ref: containerRef, "data-testid": testId, className: "min-w-0", children: [!isMobile && (_jsxs("div", { "data-testid": testIdFor("desktop"), className: "hidden min-w-0 md:block", children: [_jsxs("div", { className: "min-w-0 overflow-hidden rounded-lg border bg-card", children: [_jsxs("div", { className: "relative min-w-0", children: [_jsx("div", { ref: setScrollContainerEl, "data-testid": testIdFor("desktop-scroll"), className: "overflow-x-auto [&_[data-slot=table-container]]:overflow-x-visible", children: _jsxs(Table, { className: "w-full table-fixed", style: { minWidth: `${tableMinWidthRem(columns, showControls)}rem` }, children: [_jsxs("colgroup", { children: [columns.map((column) => (_jsx("col", { style: columnWidthStyle(column.type) }, column.field))), showControls && _jsx("col", { style: { width: `${ACTIONS_COLUMN_REM}rem` } })] }), _jsx(TableHeader, { className: "bg-muted", children: _jsxs(TableRow, { className: "hover:bg-transparent", children: [columns.map((column) => (_jsx(TableHead, { title: column.label, className: cn("truncate", columnAlignClass(column.type)), children: column.label }, column.field))), showControls && (_jsx(TableHead, { className: cn("sticky right-0 z-10 whitespace-nowrap bg-muted px-1 text-right", isHorizontallyScrollable &&
342
+ "shadow-[inset_1px_0_0_var(--color-border)]"), "aria-label": actionsLabel }))] }) }), _jsx(TableBody, { children: rows.map((row, rowIndex) => {
343
+ const isLastRow = rowIndex === rows.length - 1;
344
+ const rowIssuesForRow = rowIssues?.[rowIndex];
345
+ return (_jsxs(Fragment
346
+ // biome-ignore lint/suspicious/noArrayIndexKey: rows have no caller-guaranteed stable id; every cell is fully controlled (value+onChange), so reordering doesn't rely on DOM node identity surviving between renders.
347
+ , { children: [_jsxs(TableRow, { className: "group", "data-testid": testIdFor(`row-${rowIndex}`), children: [columns.map((column, columnIndex) => {
348
+ const isLastCell = isLastRow && columnIndex === lastEditableIndex;
349
+ const issues = cellIssues?.[`${rowIndex}.${column.field}`];
350
+ return (_jsxs(TableCell, { "data-testid": testIdFor(`cell-${rowIndex}-${column.field}`), onPaste: onPasteCells !== undefined
351
+ ? handlePaste(rowIndex, columnIndex)
352
+ : undefined, onKeyDown: isLastCell ? handleLastCellKeyDown : undefined, children: [renderCellControl({
353
+ cellId: cellId(rowIndex, column.field),
354
+ label: cellLabel(column, rowIndex),
355
+ column,
356
+ value: row[column.field],
357
+ disabled: disabled === true,
358
+ onChange: (value) => onCellChange(rowIndex, column.field, value),
359
+ currency: effectiveCurrency,
360
+ locale: resolvedLocale,
361
+ }), _jsx(IssueMessages, { issues: issues, testId: testIdFor(`cell-${rowIndex}-${column.field}-errors`), constrainWidth: true })] }, column.field));
362
+ }), showControls && (_jsx(TableCell, { className: cn("sticky right-0 z-10 whitespace-nowrap bg-card px-1 text-right group-hover:bg-muted", isHorizontallyScrollable &&
363
+ "shadow-[inset_1px_0_0_var(--color-border)]"), children: _jsx(RowActions, { rowIndex: rowIndex, rowsLength: rows.length, minItems: minItems, maxItems: maxItems, onDuplicateRow: onDuplicateRow, onMoveRow: onMoveRow, onRemoveRow: onRemoveRow, duplicateLabel: duplicateLabel, moveUpLabel: moveUpLabel, moveDownLabel: moveDownLabel, removeLabel: removeLabel, testIdPrefix: testIdFor(`row-${rowIndex}`) }) }))] }), rowIssuesForRow !== undefined && rowIssuesForRow.length > 0 && (_jsx(TableRow, { children: _jsx(TableCell, { colSpan: columns.length + (showControls ? 1 : 0), children: _jsx(IssueMessages, { issues: rowIssuesForRow, testId: testIdFor(`row-${rowIndex}-issues`) }) }) }))] }, rowIndex));
364
+ }) })] }) }), scrollAffordance.canScrollLeft && (_jsx("div", { "aria-hidden": "true", className: "pointer-events-none absolute inset-y-0 left-0 w-6 bg-gradient-to-r from-card to-transparent" })), scrollAffordance.canScrollRight && !showControls && (_jsx("div", { "aria-hidden": "true", className: "pointer-events-none absolute inset-y-0 right-0 w-6 bg-gradient-to-l from-card to-transparent" }))] }), showControls && (_jsx("div", { className: "border-t p-2", children: _jsxs(UiButton, { type: "button", variant: "ghost", size: "sm", onClick: onAddRow, disabled: addDisabled, "data-testid": testIdFor("add"), children: [_jsx(Plus, { className: "size-4", "aria-hidden": "true" }), addLabel] }) })), hasTotals && (_jsx("div", { "data-testid": testIdFor("totals"), className: "flex flex-wrap items-center justify-end gap-6 border-t bg-muted/30 px-4 py-3 text-sm", children: totals.map((total) => (_jsxs("div", { className: "flex items-baseline gap-2", children: [_jsx("span", { className: "text-muted-foreground", children: total.label }), _jsx("span", { className: "font-medium tabular-nums", children: formatTotalValue(total, columns, effectiveCurrency, resolvedLocale) })] }, total.field))) }))] }), _jsx(IssueMessages, { issues: listIssues, testId: testIdFor("list-issues") })] })), isMobile && (_jsxs("div", { "data-testid": testIdFor("mobile"), className: "md:hidden flex flex-col gap-3", children: [rows.map((row, rowIndex) => {
365
+ const isLastRow = rowIndex === rows.length - 1;
366
+ const rowIssuesForRow = rowIssues?.[rowIndex];
367
+ return (_jsxs("div", { "data-testid": testIdFor(`row-${rowIndex}`), className: "flex flex-col gap-3 rounded-lg border bg-card p-4", children: [columns.map((column, columnIndex) => {
368
+ const isLastCell = isLastRow && columnIndex === lastEditableIndex;
369
+ const issues = cellIssues?.[`${rowIndex}.${column.field}`];
370
+ return (_jsxs("div", { className: "flex flex-col gap-1", onPaste: onPasteCells !== undefined ? handlePaste(rowIndex, columnIndex) : undefined, onKeyDown: isLastCell ? handleLastCellKeyDown : undefined, children: [_jsx("span", { className: "text-xs font-medium text-muted-foreground", children: column.label }), renderCellControl({
371
+ cellId: cellId(rowIndex, column.field),
372
+ label: cellLabel(column, rowIndex),
373
+ column,
374
+ value: row[column.field],
375
+ disabled: disabled === true,
376
+ onChange: (value) => onCellChange(rowIndex, column.field, value),
377
+ currency: effectiveCurrency,
378
+ locale: resolvedLocale,
379
+ }), _jsx(IssueMessages, { issues: issues, testId: testIdFor(`cell-${rowIndex}-${column.field}-errors`) })] }, column.field));
380
+ }), rowIssuesForRow !== undefined && rowIssuesForRow.length > 0 && (_jsx(IssueMessages, { issues: rowIssuesForRow, testId: testIdFor(`row-${rowIndex}-issues`) })), showControls && (_jsx("div", { className: "flex items-center justify-end gap-1 border-t pt-3", children: _jsx(RowActions, { rowIndex: rowIndex, rowsLength: rows.length, minItems: minItems, maxItems: maxItems, onDuplicateRow: onDuplicateRow, onMoveRow: onMoveRow, onRemoveRow: onRemoveRow, duplicateLabel: duplicateLabel, moveUpLabel: moveUpLabel, moveDownLabel: moveDownLabel, removeLabel: removeLabel, testIdPrefix: testIdFor(`row-${rowIndex}`), buttonSizeClass: "size-10" }) }))] }, rowIndex));
381
+ }), showControls && (_jsxs(UiButton, { type: "button", variant: "outline", onClick: onAddRow, disabled: addDisabled, "data-testid": testIdFor("add"), children: [_jsx(Plus, { className: "size-4", "aria-hidden": "true" }), addLabel] })), hasTotals && (_jsx("div", { "data-testid": testIdFor("totals"), className: "flex flex-col gap-2 rounded-lg border bg-muted/30 p-4 text-sm", children: totals.map((total) => (_jsxs("div", { className: "flex items-center justify-between", children: [_jsx("span", { className: "text-muted-foreground", children: total.label }), _jsx("span", { className: "font-medium tabular-nums", children: formatTotalValue(total, columns, effectiveCurrency, resolvedLocale) })] }, total.field))) })), _jsx(IssueMessages, { issues: listIssues, testId: testIdFor("list-issues") })] }))] }));
382
+ }
@@ -0,0 +1,25 @@
1
+ import { type ReactNode } from "react";
2
+ import type { ListColumnFileDisplay } from "../../headless/index.ts";
3
+ export declare function fileOriginalUrl(fileId: string): string;
4
+ export declare function fileVariantUrl(fileId: string, variant: string): string;
5
+ export declare function FileThumbnail({ fileId, variant, className, testId, }: {
6
+ readonly fileId: string;
7
+ readonly variant?: string;
8
+ readonly className?: string;
9
+ readonly testId?: string;
10
+ }): ReactNode;
11
+ export declare function FileNameLink({ fileId, fallbackLabel, className, }: {
12
+ readonly fileId: string;
13
+ readonly fallbackLabel: string;
14
+ readonly className?: string;
15
+ }): ReactNode;
16
+ export declare function CardLeadingImage({ value, display, }: {
17
+ readonly value: unknown;
18
+ readonly display: ListColumnFileDisplay;
19
+ }): ReactNode;
20
+ export declare function FileDisplayCell({ value, display, fallbackLabel, compact, }: {
21
+ readonly value: unknown;
22
+ readonly display: ListColumnFileDisplay;
23
+ readonly fallbackLabel: string;
24
+ readonly compact?: boolean;
25
+ }): ReactNode;
@@ -0,0 +1,90 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { isUuid } from "@cosmicdrift/kumiko-types/identifiers";
3
+ import { ImageIcon } from "lucide-react";
4
+ import { useEffect, useState } from "react";
5
+ import { cn } from "../lib/cn.js";
6
+ // Stored values are untrusted: only UUIDs reach a request, and path segments are
7
+ // encoded so an id like "../x" or "a?b" cannot redirect the request.
8
+ export function fileOriginalUrl(fileId) {
9
+ return `/api/files/${encodeURIComponent(fileId)}`;
10
+ }
11
+ export function fileVariantUrl(fileId, variant) {
12
+ return `${fileOriginalUrl(fileId)}/variant/${encodeURIComponent(variant)}`;
13
+ }
14
+ function thumbnailSources(fileId, variant) {
15
+ if (!isUuid(fileId))
16
+ return [];
17
+ return variant === undefined
18
+ ? [fileOriginalUrl(fileId)]
19
+ : [fileVariantUrl(fileId, variant), fileOriginalUrl(fileId)];
20
+ }
21
+ // A declared variant can 404 when the upload carried no entityType/fieldName
22
+ // (the variant is resolved per field), while the original always serves. So the
23
+ // chain is variant -> original -> placeholder instead of a broken-image icon.
24
+ function ThumbnailChain({ fileId, variant, className, testId, }) {
25
+ const sources = thumbnailSources(fileId, variant);
26
+ const [failedCount, setFailedCount] = useState(0);
27
+ const src = sources[failedCount];
28
+ if (src === undefined) {
29
+ return (_jsx("div", { "data-testid": testId, className: cn("bg-muted text-muted-foreground flex items-center justify-center rounded-md border", className), children: _jsx(ImageIcon, { className: "size-1/3" }) }));
30
+ }
31
+ return (_jsx("img", { src: src, alt: "", "data-testid": testId, onError: () => setFailedCount((n) => n + 1), className: cn("bg-muted rounded-md border object-contain", className) }));
32
+ }
33
+ export function FileThumbnail({ fileId, variant, className = "h-24 w-32", testId, }) {
34
+ return (_jsx(ThumbnailChain, { fileId: fileId, variant: variant, className: className, testId: testId }, `${fileId}:${variant ?? ""}`));
35
+ }
36
+ function isFileMeta(value) {
37
+ return (typeof value === "object" &&
38
+ value !== null &&
39
+ "fileName" in value &&
40
+ typeof value.fileName === "string");
41
+ }
42
+ export function FileNameLink({ fileId, fallbackLabel, className, }) {
43
+ const [fileName, setFileName] = useState(null);
44
+ const validId = isUuid(fileId);
45
+ useEffect(() => {
46
+ let cancelled = false;
47
+ setFileName(null);
48
+ if (!validId)
49
+ return;
50
+ fetch(`${fileOriginalUrl(fileId)}/meta`)
51
+ .then((res) => (res.ok ? res.json() : null))
52
+ .then((meta) => {
53
+ if (!cancelled && isFileMeta(meta))
54
+ setFileName(meta.fileName);
55
+ })
56
+ .catch(() => { });
57
+ return () => {
58
+ cancelled = true;
59
+ };
60
+ }, [fileId, validId]);
61
+ if (!validId)
62
+ return _jsx("span", { className: cn("text-sm", className), children: fallbackLabel });
63
+ return (_jsx("a", { href: fileOriginalUrl(fileId), target: "_blank", rel: "noreferrer", className: cn("text-sm underline underline-offset-2", className), children: fileName ?? fallbackLabel }));
64
+ }
65
+ function fileIdsOf(value) {
66
+ if (typeof value === "string")
67
+ return value === "" ? [] : [value];
68
+ if (!Array.isArray(value))
69
+ return [];
70
+ return value.filter((entry) => typeof entry === "string" && entry !== "");
71
+ }
72
+ // Height-bound, width follows the aspect ratio within a clamp, so a portrait and
73
+ // a landscape photo both read as a preview without stretching the column.
74
+ const TABLE_THUMBNAIL_CLASS = "h-16 min-w-16 max-w-24 object-cover";
75
+ // A card's meta line is one text line (h-5) tall.
76
+ const CARD_THUMBNAIL_CLASS = "size-5 rounded-sm object-cover";
77
+ const CARD_LEADING_CLASS = "size-14 shrink-0 rounded-md object-cover";
78
+ // Leading preview of a narrow list card: the card's own image, not a meta chip.
79
+ export function CardLeadingImage({ value, display, }) {
80
+ const [first] = fileIdsOf(value);
81
+ if (first === undefined || display.kind !== "image")
82
+ return null;
83
+ return (_jsx(FileThumbnail, { fileId: first, className: CARD_LEADING_CLASS, ...(display.variant !== undefined && { variant: display.variant }) }));
84
+ }
85
+ export function FileDisplayCell({ value, display, fallbackLabel, compact = false, }) {
86
+ const [first, ...rest] = fileIdsOf(value);
87
+ if (first === undefined)
88
+ return null;
89
+ return (_jsxs("span", { className: "inline-flex items-center gap-2", children: [display.kind === "image" ? (_jsx(FileThumbnail, { fileId: first, className: compact ? CARD_THUMBNAIL_CLASS : TABLE_THUMBNAIL_CLASS, ...(display.variant !== undefined && { variant: display.variant }) })) : (_jsx(FileNameLink, { fileId: first, fallbackLabel: fallbackLabel })), rest.length > 0 && _jsxs("span", { className: "text-muted-foreground text-xs", children: ["+", rest.length] })] }));
90
+ }
@@ -0,0 +1,21 @@
1
+ import { type ReactNode } from "react";
2
+ export type FileUploadInputProps = {
3
+ readonly kind: "file" | "image";
4
+ readonly id: string;
5
+ readonly value: string | null;
6
+ readonly onChange: (fileId: string | null) => void;
7
+ readonly accept?: readonly string[];
8
+ readonly disabled?: boolean;
9
+ readonly entityType?: string;
10
+ readonly entityId?: string;
11
+ readonly fieldName?: string;
12
+ readonly imageVariant?: string;
13
+ readonly capture?: "environment" | "user";
14
+ /** Folder picker (web-only, `webkitdirectory`): hands the picked files with
15
+ * `webkitRelativePath` to `onFilesPicked` and uploads nothing. */
16
+ readonly directory?: boolean;
17
+ readonly onFilesPicked?: (files: readonly File[]) => void;
18
+ readonly pickLabel?: string;
19
+ readonly testId?: string;
20
+ };
21
+ export declare function FileUploadInput({ kind, id, value, onChange, accept, disabled, entityType, entityId, fieldName, imageVariant, capture, directory, onFilesPicked, pickLabel, testId, }: FileUploadInputProps): ReactNode;
@@ -0,0 +1,56 @@
1
+ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ // File/image upload widget for the auto-edit form. Uploads via multipart POST
3
+ // to /api/files (mounted by the stack when a storageProvider is set), gets the
4
+ // FileRef UUID back and lifts it up as the field value. Image → uncropped
5
+ // rectangular preview (GET /api/files/:id, or the declared variant), file →
6
+ // file name link. A disabled input shows the value only, without controls.
7
+ import { ImageIcon, Loader2, Upload } from "lucide-react";
8
+ import { useRef, useState } from "react";
9
+ import { useTranslation } from "../../index.js";
10
+ import { toAcceptAttr } from "../lib/accept-attr.js";
11
+ import { resizeImageBeforeUpload } from "../lib/resize-image.js";
12
+ import { FileUploadFailedError, uploadFileRef } from "../lib/upload-file-ref.js";
13
+ import { Button as UiButton } from "../ui/button.js";
14
+ import { FileNameLink, FileThumbnail } from "./file-thumbnail.js";
15
+ // React's input typings have no `webkitdirectory`; spreading keeps it typed-cast-free.
16
+ const DIRECTORY_INPUT_ATTRS = { webkitdirectory: "", multiple: true };
17
+ export function FileUploadInput({ kind, id, value, onChange, accept, disabled, entityType, entityId, fieldName, imageVariant, capture, directory, onFilesPicked, pickLabel, testId, }) {
18
+ const t = useTranslation();
19
+ const inputRef = useRef(null);
20
+ const [uploading, setUploading] = useState(false);
21
+ const [error, setError] = useState(null);
22
+ async function onPick(e) {
23
+ if (directory === true) {
24
+ onFilesPicked?.(Array.from(e.target.files ?? []));
25
+ if (inputRef.current)
26
+ inputRef.current.value = "";
27
+ return;
28
+ }
29
+ const file = e.target.files?.[0];
30
+ if (file === undefined)
31
+ return;
32
+ setUploading(true);
33
+ setError(null);
34
+ try {
35
+ const uploadFile = await resizeImageBeforeUpload(file);
36
+ onChange(await uploadFileRef(uploadFile, { entityType, entityId, fieldName }));
37
+ }
38
+ catch (error) {
39
+ setError(error instanceof FileUploadFailedError && error.fromServer
40
+ ? error.message
41
+ : t("kumiko.field.file-upload.failed"));
42
+ }
43
+ finally {
44
+ setUploading(false);
45
+ // Clear the input so re-picking the SAME file still fires change — the
46
+ // browser suppresses the event otherwise (no-op in jsdom, real-browser).
47
+ if (inputRef.current)
48
+ inputRef.current.value = "";
49
+ }
50
+ }
51
+ const acceptAttr = toAcceptAttr(accept);
52
+ return (_jsxs("div", { className: "flex items-center gap-4", children: [kind === "image" && value !== null && (_jsx(FileThumbnail, { fileId: value, ...(imageVariant !== undefined && { variant: imageVariant }) })), kind === "image" && value === null && (_jsx("div", { className: "bg-muted text-muted-foreground flex h-24 w-32 items-center justify-center rounded-md border", children: _jsx(ImageIcon, { className: "size-6" }) })), kind === "file" && value !== null && (_jsx(FileNameLink, { fileId: value, fallbackLabel: t("kumiko.field.file-upload.attached") })), _jsx("input", { ref: inputRef, id: id, ...(testId !== undefined && { "data-testid": `${testId}-input` }), type: "file", className: "hidden", ...(acceptAttr !== undefined && { accept: acceptAttr }), ...(capture !== undefined && { capture }), ...(directory === true && DIRECTORY_INPUT_ATTRS), onChange: (e) => void onPick(e), disabled: disabled }), disabled !== true && (_jsxs(_Fragment, { children: [_jsxs(UiButton, { type: "button", variant: "outline", size: "sm", disabled: uploading, onClick: () => inputRef.current?.click(), ...(testId !== undefined && { "data-testid": `${testId}-pick` }), children: [uploading ? (_jsx(Loader2, { className: "size-4 animate-spin" })) : (_jsx(Upload, { className: "size-4" })), pickLabel ??
53
+ (value !== null
54
+ ? t("kumiko.field.file-upload.change")
55
+ : t("kumiko.field.file-upload.upload"))] }), value !== null && (_jsx(UiButton, { type: "button", variant: "ghost", size: "sm", onClick: () => onChange(null), children: t("kumiko.field.file-upload.remove") }))] })), error !== null && _jsx("span", { className: "text-destructive text-xs", children: error })] }));
56
+ }
@@ -0,0 +1,34 @@
1
+ import { type ReactNode } from "react";
2
+ import { applyFormatSpec } from "../../headless/index.ts";
3
+ import { type CardProps, type CorePrimitives, type FormWidth } from "../../index.ts";
4
+ import "../react-css-custom-properties.ts";
5
+ export declare const END_LABEL_MIN_ROWS = 50;
6
+ export declare function isComponentRendererRef(renderer: unknown): {
7
+ readonly name: string;
8
+ } | undefined;
9
+ export { applyFormatSpec };
10
+ export declare function defaultCellRender(value: unknown, type: string, optionLabels?: Readonly<Record<string, string>>, locale?: string, columnKey?: string, grouping?: boolean): string;
11
+ export declare function EmbeddedFormProvider({ children }: {
12
+ children: ReactNode;
13
+ }): ReactNode;
14
+ export declare function BareFormProvider({ children }: {
15
+ children: ReactNode;
16
+ }): ReactNode;
17
+ export declare function ScreenWidthProvider({ width, children, }: {
18
+ readonly width: FormWidth | undefined;
19
+ readonly children: ReactNode;
20
+ }): ReactNode;
21
+ export type FormScreenShellWidth = FormWidth;
22
+ export declare function FormScreenShell({ children, className, testId, maxWidth, fillHeight, }: {
23
+ readonly children: ReactNode;
24
+ readonly className?: string;
25
+ readonly testId?: string;
26
+ readonly maxWidth?: FormScreenShellWidth;
27
+ /** Stacks children in a `h-full` flex column instead of normal document
28
+ * flow, so a `flex-1 min-h-0` child can claim the remaining height below
29
+ * the others (fw#2722 — DefaultForm's tabs+relatedList case). Default
30
+ * false: unchanged, content-sized height. */
31
+ readonly fillHeight?: boolean;
32
+ }): ReactNode;
33
+ export declare function DefaultCard({ slots, options, className, testId, dataAttributes, children, }: CardProps): ReactNode;
34
+ export declare const defaultPrimitives: CorePrimitives;