@entifix/react-controls 0.18.2 → 0.20.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 (328) hide show
  1. package/README.md +13 -5
  2. package/dist/i18n/catalog/en.d.ts.map +1 -1
  3. package/dist/i18n/catalog/en.js +68 -10
  4. package/dist/i18n/catalog/en.js.map +1 -1
  5. package/dist/i18n/catalog/es.d.ts +76 -5
  6. package/dist/i18n/catalog/es.d.ts.map +1 -1
  7. package/dist/i18n/catalog/es.js +74 -10
  8. package/dist/i18n/catalog/es.js.map +1 -1
  9. package/dist/i18n/catalog/index.d.ts +126 -10
  10. package/dist/i18n/catalog/index.d.ts.map +1 -1
  11. package/dist/i18n/entity-labels.d.ts +14 -0
  12. package/dist/i18n/entity-labels.d.ts.map +1 -1
  13. package/dist/i18n/entity-labels.js +15 -0
  14. package/dist/i18n/entity-labels.js.map +1 -1
  15. package/dist/i18n/i18n-context.js +2 -2
  16. package/dist/i18n/i18n-context.js.map +1 -1
  17. package/dist/index.d.ts +13 -2
  18. package/dist/index.d.ts.map +1 -1
  19. package/dist/index.js +13 -2
  20. package/dist/index.js.map +1 -1
  21. package/dist/primitives.d.ts +7 -1
  22. package/dist/primitives.d.ts.map +1 -1
  23. package/dist/primitives.js +7 -1
  24. package/dist/primitives.js.map +1 -1
  25. package/dist/theme/index.d.ts +1 -0
  26. package/dist/theme/index.d.ts.map +1 -1
  27. package/dist/theme/index.js +1 -0
  28. package/dist/theme/index.js.map +1 -1
  29. package/dist/theme/theme-context.d.ts +35 -7
  30. package/dist/theme/theme-context.d.ts.map +1 -1
  31. package/dist/theme/theme-context.js +109 -21
  32. package/dist/theme/theme-context.js.map +1 -1
  33. package/dist/theme/theme-cookie.d.ts +9 -0
  34. package/dist/theme/theme-cookie.d.ts.map +1 -0
  35. package/dist/theme/theme-cookie.js +8 -0
  36. package/dist/theme/theme-cookie.js.map +1 -0
  37. package/dist/theme/theme-script.d.ts +8 -5
  38. package/dist/theme/theme-script.d.ts.map +1 -1
  39. package/dist/theme/theme-script.js +24 -10
  40. package/dist/theme/theme-script.js.map +1 -1
  41. package/dist/theme/types.d.ts +19 -3
  42. package/dist/theme/types.d.ts.map +1 -1
  43. package/dist/theme/types.js.map +1 -1
  44. package/dist/ui/actions/action-surfaces.d.ts +1 -1
  45. package/dist/ui/actions/action-surfaces.js +1 -1
  46. package/dist/ui/actions/action-surfaces.js.map +1 -1
  47. package/dist/ui/actions/error-actions.d.ts +32 -0
  48. package/dist/ui/actions/error-actions.d.ts.map +1 -0
  49. package/dist/ui/actions/error-actions.js +40 -0
  50. package/dist/ui/actions/error-actions.js.map +1 -0
  51. package/dist/ui/actions/index.d.ts +2 -0
  52. package/dist/ui/actions/index.d.ts.map +1 -1
  53. package/dist/ui/actions/index.js +2 -0
  54. package/dist/ui/actions/index.js.map +1 -1
  55. package/dist/ui/actions/shortcut.d.ts +13 -0
  56. package/dist/ui/actions/shortcut.d.ts.map +1 -0
  57. package/dist/ui/actions/shortcut.js +18 -0
  58. package/dist/ui/actions/shortcut.js.map +1 -0
  59. package/dist/ui/actions/use-verb-invoker.d.ts +50 -0
  60. package/dist/ui/actions/use-verb-invoker.d.ts.map +1 -0
  61. package/dist/ui/actions/use-verb-invoker.js +93 -0
  62. package/dist/ui/actions/use-verb-invoker.js.map +1 -0
  63. package/dist/ui/atoms/alert/alert-dismiss.d.ts +9 -0
  64. package/dist/ui/atoms/alert/alert-dismiss.d.ts.map +1 -0
  65. package/dist/ui/atoms/alert/alert-dismiss.js +28 -0
  66. package/dist/ui/atoms/alert/alert-dismiss.js.map +1 -0
  67. package/dist/ui/atoms/alert/alert.d.ts +24 -0
  68. package/dist/ui/atoms/alert/alert.d.ts.map +1 -0
  69. package/dist/ui/atoms/alert/alert.js +50 -0
  70. package/dist/ui/atoms/alert/alert.js.map +1 -0
  71. package/dist/ui/atoms/alert/index.d.ts +3 -0
  72. package/dist/ui/atoms/alert/index.d.ts.map +1 -0
  73. package/dist/ui/atoms/alert/index.js +4 -0
  74. package/dist/ui/atoms/alert/index.js.map +1 -0
  75. package/dist/ui/atoms/alert/tone.d.ts +8 -0
  76. package/dist/ui/atoms/alert/tone.d.ts.map +1 -0
  77. package/dist/ui/atoms/alert/tone.js +11 -0
  78. package/dist/ui/atoms/alert/tone.js.map +1 -0
  79. package/dist/ui/atoms/button/button-recipe.js +1 -1
  80. package/dist/ui/atoms/button/button-recipe.js.map +1 -1
  81. package/dist/ui/atoms/button/index.d.ts +1 -0
  82. package/dist/ui/atoms/button/index.d.ts.map +1 -1
  83. package/dist/ui/atoms/button/index.js +1 -0
  84. package/dist/ui/atoms/button/index.js.map +1 -1
  85. package/dist/ui/atoms/button/submit-button.d.ts +13 -0
  86. package/dist/ui/atoms/button/submit-button.d.ts.map +1 -0
  87. package/dist/ui/atoms/button/submit-button.js +29 -0
  88. package/dist/ui/atoms/button/submit-button.js.map +1 -0
  89. package/dist/ui/atoms/cell-value/cell-value.d.ts +6 -1
  90. package/dist/ui/atoms/cell-value/cell-value.d.ts.map +1 -1
  91. package/dist/ui/atoms/cell-value/cell-value.js +48 -16
  92. package/dist/ui/atoms/cell-value/cell-value.js.map +1 -1
  93. package/dist/ui/atoms/field/checkbox.d.ts.map +1 -1
  94. package/dist/ui/atoms/field/checkbox.js +21 -1
  95. package/dist/ui/atoms/field/checkbox.js.map +1 -1
  96. package/dist/ui/atoms/field/field.js +1 -1
  97. package/dist/ui/atoms/field/field.js.map +1 -1
  98. package/dist/ui/atoms/field-control/field-control.d.ts +7 -1
  99. package/dist/ui/atoms/field-control/field-control.d.ts.map +1 -1
  100. package/dist/ui/atoms/field-control/field-control.js +25 -3
  101. package/dist/ui/atoms/field-control/field-control.js.map +1 -1
  102. package/dist/ui/atoms/money/index.d.ts +4 -0
  103. package/dist/ui/atoms/money/index.d.ts.map +1 -0
  104. package/dist/ui/atoms/money/index.js +5 -0
  105. package/dist/ui/atoms/money/index.js.map +1 -0
  106. package/dist/ui/atoms/money/money-input.d.ts +19 -0
  107. package/dist/ui/atoms/money/money-input.d.ts.map +1 -0
  108. package/dist/ui/atoms/money/money-input.js +75 -0
  109. package/dist/ui/atoms/money/money-input.js.map +1 -0
  110. package/dist/ui/atoms/money/money-math.d.ts +21 -0
  111. package/dist/ui/atoms/money/money-math.d.ts.map +1 -0
  112. package/dist/ui/atoms/money/money-math.js +36 -0
  113. package/dist/ui/atoms/money/money-math.js.map +1 -0
  114. package/dist/ui/atoms/money/money.d.ts +19 -0
  115. package/dist/ui/atoms/money/money.d.ts.map +1 -0
  116. package/dist/ui/atoms/money/money.js +26 -0
  117. package/dist/ui/atoms/money/money.js.map +1 -0
  118. package/dist/ui/atoms/number-input/index.d.ts +3 -0
  119. package/dist/ui/atoms/number-input/index.d.ts.map +1 -0
  120. package/dist/ui/atoms/number-input/index.js +4 -0
  121. package/dist/ui/atoms/number-input/index.js.map +1 -0
  122. package/dist/ui/atoms/number-input/number-input.d.ts +10 -0
  123. package/dist/ui/atoms/number-input/number-input.d.ts.map +1 -0
  124. package/dist/ui/atoms/number-input/number-input.js +23 -0
  125. package/dist/ui/atoms/number-input/number-input.js.map +1 -0
  126. package/dist/ui/atoms/number-input/quantity-input.d.ts +29 -0
  127. package/dist/ui/atoms/number-input/quantity-input.d.ts.map +1 -0
  128. package/dist/ui/atoms/number-input/quantity-input.js +100 -0
  129. package/dist/ui/atoms/number-input/quantity-input.js.map +1 -0
  130. package/dist/ui/atoms/skeleton/skeleton.js +1 -1
  131. package/dist/ui/atoms/skeleton/skeleton.js.map +1 -1
  132. package/dist/ui/atoms/status-tag/index.d.ts +2 -0
  133. package/dist/ui/atoms/status-tag/index.d.ts.map +1 -0
  134. package/dist/ui/atoms/status-tag/index.js +3 -0
  135. package/dist/ui/atoms/status-tag/index.js.map +1 -0
  136. package/dist/ui/atoms/status-tag/status-tag.d.ts +17 -0
  137. package/dist/ui/atoms/status-tag/status-tag.d.ts.map +1 -0
  138. package/dist/ui/atoms/status-tag/status-tag.js +37 -0
  139. package/dist/ui/atoms/status-tag/status-tag.js.map +1 -0
  140. package/dist/ui/atoms/switch/switch.d.ts.map +1 -1
  141. package/dist/ui/atoms/switch/switch.js +6 -3
  142. package/dist/ui/atoms/switch/switch.js.map +1 -1
  143. package/dist/ui/atoms/table/table.d.ts +12 -3
  144. package/dist/ui/atoms/table/table.d.ts.map +1 -1
  145. package/dist/ui/atoms/table/table.js +59 -10
  146. package/dist/ui/atoms/table/table.js.map +1 -1
  147. package/dist/ui/atoms/text/text.d.ts +2 -2
  148. package/dist/ui/atoms/text/text.d.ts.map +1 -1
  149. package/dist/ui/atoms/text/text.js.map +1 -1
  150. package/dist/ui/molecules/action-bar/action-bar.d.ts +76 -0
  151. package/dist/ui/molecules/action-bar/action-bar.d.ts.map +1 -0
  152. package/dist/ui/molecules/action-bar/action-bar.js +218 -0
  153. package/dist/ui/molecules/action-bar/action-bar.js.map +1 -0
  154. package/dist/ui/molecules/action-bar/index.d.ts +2 -0
  155. package/dist/ui/molecules/action-bar/index.d.ts.map +1 -0
  156. package/dist/ui/molecules/action-bar/index.js +3 -0
  157. package/dist/ui/molecules/action-bar/index.js.map +1 -0
  158. package/dist/ui/molecules/breadcrumbs/breadcrumbs.d.ts +11 -2
  159. package/dist/ui/molecules/breadcrumbs/breadcrumbs.d.ts.map +1 -1
  160. package/dist/ui/molecules/breadcrumbs/breadcrumbs.js +9 -7
  161. package/dist/ui/molecules/breadcrumbs/breadcrumbs.js.map +1 -1
  162. package/dist/ui/molecules/bulk-action-bar/bulk-action-bar.d.ts.map +1 -1
  163. package/dist/ui/molecules/bulk-action-bar/bulk-action-bar.js +8 -10
  164. package/dist/ui/molecules/bulk-action-bar/bulk-action-bar.js.map +1 -1
  165. package/dist/ui/molecules/bulk-result/bulk-result.d.ts +3 -3
  166. package/dist/ui/molecules/bulk-result/bulk-result.js +4 -4
  167. package/dist/ui/molecules/bulk-result/bulk-result.js.map +1 -1
  168. package/dist/ui/molecules/column-settings/column-settings.js +1 -1
  169. package/dist/ui/molecules/column-settings/column-settings.js.map +1 -1
  170. package/dist/ui/molecules/confirm-dialog/confirm-dialog.d.ts +24 -9
  171. package/dist/ui/molecules/confirm-dialog/confirm-dialog.d.ts.map +1 -1
  172. package/dist/ui/molecules/confirm-dialog/confirm-dialog.js +38 -13
  173. package/dist/ui/molecules/confirm-dialog/confirm-dialog.js.map +1 -1
  174. package/dist/ui/molecules/description-list/description-list.d.ts +17 -0
  175. package/dist/ui/molecules/description-list/description-list.d.ts.map +1 -0
  176. package/dist/ui/molecules/description-list/description-list.js +36 -0
  177. package/dist/ui/molecules/description-list/description-list.js.map +1 -0
  178. package/dist/ui/molecules/description-list/index.d.ts +2 -0
  179. package/dist/ui/molecules/description-list/index.d.ts.map +1 -0
  180. package/dist/ui/molecules/description-list/index.js +3 -0
  181. package/dist/ui/molecules/description-list/index.js.map +1 -0
  182. package/dist/ui/molecules/drawer/drawer.js +3 -3
  183. package/dist/ui/molecules/drawer/drawer.js.map +1 -1
  184. package/dist/ui/molecules/empty-state/empty-state.d.ts +15 -0
  185. package/dist/ui/molecules/empty-state/empty-state.d.ts.map +1 -0
  186. package/dist/ui/molecules/empty-state/empty-state.js +29 -0
  187. package/dist/ui/molecules/empty-state/empty-state.js.map +1 -0
  188. package/dist/ui/molecules/empty-state/index.d.ts +2 -0
  189. package/dist/ui/molecules/empty-state/index.d.ts.map +1 -0
  190. package/dist/ui/molecules/empty-state/index.js +3 -0
  191. package/dist/ui/molecules/empty-state/index.js.map +1 -0
  192. package/dist/ui/molecules/entity-link-input/entity-link-input.d.ts.map +1 -1
  193. package/dist/ui/molecules/entity-link-input/entity-link-input.js +7 -4
  194. package/dist/ui/molecules/entity-link-input/entity-link-input.js.map +1 -1
  195. package/dist/ui/molecules/entity-link-picker/entity-link-picker.js +2 -2
  196. package/dist/ui/molecules/entity-link-picker/entity-link-picker.js.map +1 -1
  197. package/dist/ui/molecules/entity-record-card/entity-record-card.d.ts +33 -20
  198. package/dist/ui/molecules/entity-record-card/entity-record-card.d.ts.map +1 -1
  199. package/dist/ui/molecules/entity-record-card/entity-record-card.js +53 -20
  200. package/dist/ui/molecules/entity-record-card/entity-record-card.js.map +1 -1
  201. package/dist/ui/molecules/filter-builder/filter-builder.d.ts +8 -2
  202. package/dist/ui/molecules/filter-builder/filter-builder.d.ts.map +1 -1
  203. package/dist/ui/molecules/filter-builder/filter-builder.js +14 -5
  204. package/dist/ui/molecules/filter-builder/filter-builder.js.map +1 -1
  205. package/dist/ui/molecules/filter-chips/filter-chips.d.ts +16 -0
  206. package/dist/ui/molecules/filter-chips/filter-chips.d.ts.map +1 -0
  207. package/dist/ui/molecules/filter-chips/filter-chips.js +73 -0
  208. package/dist/ui/molecules/filter-chips/filter-chips.js.map +1 -0
  209. package/dist/ui/molecules/filter-chips/index.d.ts +2 -0
  210. package/dist/ui/molecules/filter-chips/index.d.ts.map +1 -0
  211. package/dist/ui/molecules/filter-chips/index.js +3 -0
  212. package/dist/ui/molecules/filter-chips/index.js.map +1 -0
  213. package/dist/ui/molecules/media-gallery/index.d.ts +2 -0
  214. package/dist/ui/molecules/media-gallery/index.d.ts.map +1 -0
  215. package/dist/ui/molecules/media-gallery/index.js +3 -0
  216. package/dist/ui/molecules/media-gallery/index.js.map +1 -0
  217. package/dist/ui/molecules/media-gallery/media-gallery.d.ts +31 -0
  218. package/dist/ui/molecules/media-gallery/media-gallery.d.ts.map +1 -0
  219. package/dist/ui/molecules/media-gallery/media-gallery.js +64 -0
  220. package/dist/ui/molecules/media-gallery/media-gallery.js.map +1 -0
  221. package/dist/ui/molecules/menu/menu.d.ts +11 -1
  222. package/dist/ui/molecules/menu/menu.d.ts.map +1 -1
  223. package/dist/ui/molecules/menu/menu.js +68 -6
  224. package/dist/ui/molecules/menu/menu.js.map +1 -1
  225. package/dist/ui/molecules/nav-menu/nav-menu.js +4 -4
  226. package/dist/ui/molecules/nav-menu/nav-menu.js.map +1 -1
  227. package/dist/ui/molecules/pagination/pagination.d.ts +5 -0
  228. package/dist/ui/molecules/pagination/pagination.d.ts.map +1 -1
  229. package/dist/ui/molecules/pagination/pagination.js +35 -18
  230. package/dist/ui/molecules/pagination/pagination.js.map +1 -1
  231. package/dist/ui/molecules/region-state/index.d.ts +2 -0
  232. package/dist/ui/molecules/region-state/index.d.ts.map +1 -0
  233. package/dist/ui/molecules/region-state/index.js +3 -0
  234. package/dist/ui/molecules/region-state/index.js.map +1 -0
  235. package/dist/ui/molecules/region-state/region-state.d.ts +42 -0
  236. package/dist/ui/molecules/region-state/region-state.d.ts.map +1 -0
  237. package/dist/ui/molecules/region-state/region-state.js +83 -0
  238. package/dist/ui/molecules/region-state/region-state.js.map +1 -0
  239. package/dist/ui/molecules/segmented-nav/segment-classes.d.ts +3 -3
  240. package/dist/ui/molecules/segmented-nav/segment-classes.d.ts.map +1 -1
  241. package/dist/ui/molecules/segmented-nav/segment-classes.js +2 -2
  242. package/dist/ui/molecules/segmented-nav/segment-classes.js.map +1 -1
  243. package/dist/ui/molecules/segmented-nav/segmented-nav.d.ts +14 -4
  244. package/dist/ui/molecules/segmented-nav/segmented-nav.d.ts.map +1 -1
  245. package/dist/ui/molecules/segmented-nav/segmented-nav.js +6 -5
  246. package/dist/ui/molecules/segmented-nav/segmented-nav.js.map +1 -1
  247. package/dist/ui/molecules/split-view/split-view.js +3 -3
  248. package/dist/ui/molecules/split-view/split-view.js.map +1 -1
  249. package/dist/ui/molecules/tab-strip/tab-strip.d.ts +51 -12
  250. package/dist/ui/molecules/tab-strip/tab-strip.d.ts.map +1 -1
  251. package/dist/ui/molecules/tab-strip/tab-strip.js +125 -34
  252. package/dist/ui/molecules/tab-strip/tab-strip.js.map +1 -1
  253. package/dist/ui/molecules/table-toolbar/table-toolbar.d.ts +3 -1
  254. package/dist/ui/molecules/table-toolbar/table-toolbar.d.ts.map +1 -1
  255. package/dist/ui/molecules/table-toolbar/table-toolbar.js +3 -2
  256. package/dist/ui/molecules/table-toolbar/table-toolbar.js.map +1 -1
  257. package/dist/ui/molecules/toast-region/toast-region.d.ts +63 -19
  258. package/dist/ui/molecules/toast-region/toast-region.d.ts.map +1 -1
  259. package/dist/ui/molecules/toast-region/toast-region.js +129 -42
  260. package/dist/ui/molecules/toast-region/toast-region.js.map +1 -1
  261. package/dist/ui/organisms/command-palette/command-palette.d.ts.map +1 -1
  262. package/dist/ui/organisms/command-palette/command-palette.js +25 -18
  263. package/dist/ui/organisms/command-palette/command-palette.js.map +1 -1
  264. package/dist/ui/organisms/entity-detail-grid/entity-detail-grid.d.ts.map +1 -1
  265. package/dist/ui/organisms/entity-detail-grid/entity-detail-grid.js +8 -3
  266. package/dist/ui/organisms/entity-detail-grid/entity-detail-grid.js.map +1 -1
  267. package/dist/ui/organisms/entity-form/entity-form.d.ts +1 -1
  268. package/dist/ui/organisms/entity-form/entity-form.d.ts.map +1 -1
  269. package/dist/ui/organisms/entity-form/entity-form.js +325 -215
  270. package/dist/ui/organisms/entity-form/entity-form.js.map +1 -1
  271. package/dist/ui/organisms/entity-form/entity-form.types.d.ts +8 -0
  272. package/dist/ui/organisms/entity-form/entity-form.types.d.ts.map +1 -1
  273. package/dist/ui/organisms/entity-form/entity-form.types.js.map +1 -1
  274. package/dist/ui/organisms/entity-table/entity-table.d.ts +1 -1
  275. package/dist/ui/organisms/entity-table/entity-table.d.ts.map +1 -1
  276. package/dist/ui/organisms/entity-table/entity-table.js +334 -198
  277. package/dist/ui/organisms/entity-table/entity-table.js.map +1 -1
  278. package/dist/ui/organisms/entity-table/entity-table.types.d.ts +19 -4
  279. package/dist/ui/organisms/entity-table/entity-table.types.d.ts.map +1 -1
  280. package/dist/ui/organisms/entity-table/entity-table.types.js.map +1 -1
  281. package/dist/ui/organisms/entity-table/header-sort.d.ts +18 -0
  282. package/dist/ui/organisms/entity-table/header-sort.d.ts.map +1 -0
  283. package/dist/ui/organisms/entity-table/header-sort.js +54 -0
  284. package/dist/ui/organisms/entity-table/header-sort.js.map +1 -0
  285. package/dist/ui/organisms/entity-table/pivot.d.ts +25 -0
  286. package/dist/ui/organisms/entity-table/pivot.d.ts.map +1 -0
  287. package/dist/ui/organisms/entity-table/pivot.js +106 -0
  288. package/dist/ui/organisms/entity-table/pivot.js.map +1 -0
  289. package/dist/ui/organisms/entity-table/use-result-announcement.d.ts +13 -0
  290. package/dist/ui/organisms/entity-table/use-result-announcement.d.ts.map +1 -0
  291. package/dist/ui/organisms/entity-table/use-result-announcement.js +31 -0
  292. package/dist/ui/organisms/entity-table/use-result-announcement.js.map +1 -0
  293. package/dist/ui/organisms/top-bar/live-indicator.d.ts +11 -0
  294. package/dist/ui/organisms/top-bar/live-indicator.d.ts.map +1 -0
  295. package/dist/ui/organisms/top-bar/live-indicator.js +46 -0
  296. package/dist/ui/organisms/top-bar/live-indicator.js.map +1 -0
  297. package/dist/ui/organisms/top-bar/top-bar.d.ts +11 -2
  298. package/dist/ui/organisms/top-bar/top-bar.d.ts.map +1 -1
  299. package/dist/ui/organisms/top-bar/top-bar.js +14 -5
  300. package/dist/ui/organisms/top-bar/top-bar.js.map +1 -1
  301. package/dist/ui/organisms/wizard/wizard.d.ts +1 -1
  302. package/dist/ui/organisms/wizard/wizard.d.ts.map +1 -1
  303. package/dist/ui/organisms/wizard/wizard.js +7 -1
  304. package/dist/ui/organisms/wizard/wizard.js.map +1 -1
  305. package/dist/ui/organisms/wizard/wizard.types.d.ts +8 -0
  306. package/dist/ui/organisms/wizard/wizard.types.d.ts.map +1 -1
  307. package/dist/ui/organisms/wizard/wizard.types.js.map +1 -1
  308. package/dist/ui/utils/live-updates.d.ts +24 -0
  309. package/dist/ui/utils/live-updates.d.ts.map +1 -0
  310. package/dist/ui/utils/live-updates.js +20 -0
  311. package/dist/ui/utils/live-updates.js.map +1 -0
  312. package/dist/ui/utils/use-focus-on-arrival.d.ts +14 -0
  313. package/dist/ui/utils/use-focus-on-arrival.d.ts.map +1 -0
  314. package/dist/ui/utils/use-focus-on-arrival.js +42 -0
  315. package/dist/ui/utils/use-focus-on-arrival.js.map +1 -0
  316. package/dist/ui/utils/use-hotkey.d.ts +44 -25
  317. package/dist/ui/utils/use-hotkey.d.ts.map +1 -1
  318. package/dist/ui/utils/use-hotkey.js +80 -48
  319. package/dist/ui/utils/use-hotkey.js.map +1 -1
  320. package/package.json +5 -5
  321. package/dist/ui/molecules/split-button/index.d.ts +0 -2
  322. package/dist/ui/molecules/split-button/index.d.ts.map +0 -1
  323. package/dist/ui/molecules/split-button/index.js +0 -3
  324. package/dist/ui/molecules/split-button/index.js.map +0 -1
  325. package/dist/ui/molecules/split-button/split-button.d.ts +0 -21
  326. package/dist/ui/molecules/split-button/split-button.d.ts.map +0 -1
  327. package/dist/ui/molecules/split-button/split-button.js +0 -35
  328. package/dist/ui/molecules/split-button/split-button.js.map +0 -1
@@ -0,0 +1,15 @@
1
+ import type { ComponentPropsWithoutRef, ReactNode } from 'react';
2
+ export interface EmptyStateProps extends Omit<ComponentPropsWithoutRef<'div'>, 'children'> {
3
+ /** One sentence: what is not here, and why when it is not obvious. */
4
+ children: ReactNode;
5
+ /** The one thing to do about it — create the first record, clear a filter. */
6
+ action?: ReactNode;
7
+ }
8
+ /**
9
+ * What a region shows when it holds nothing: one sentence, and at most one way
10
+ * forward. Not a failure — a region that could not load says so with an
11
+ * `Alert` instead, because an empty result and a dead backend must never look
12
+ * alike. Server-safe.
13
+ */
14
+ export declare function EmptyState({ action, className, children, ...props }: EmptyStateProps): import("react").JSX.Element;
15
+ //# sourceMappingURL=empty-state.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"empty-state.d.ts","sourceRoot":"","sources":["../../../../src/ui/molecules/empty-state/empty-state.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,wBAAwB,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAIjE,MAAM,WAAW,eAAgB,SAAQ,IAAI,CAC3C,wBAAwB,CAAC,KAAK,CAAC,EAC/B,UAAU,CACX;IACC,sEAAsE;IACtE,QAAQ,EAAE,SAAS,CAAC;IACpB,8EAA8E;IAC9E,MAAM,CAAC,EAAE,SAAS,CAAC;CACpB;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,EACzB,MAAM,EACN,SAAS,EACT,QAAQ,EACR,GAAG,KAAK,EACT,EAAE,eAAe,+BAejB"}
@@ -0,0 +1,29 @@
1
+ import { _ as _extends } from "@swc/helpers/_/_extends";
2
+ import { _ as _object_without_properties_loose } from "@swc/helpers/_/_object_without_properties_loose";
3
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
4
+ import { cn } from '../../utils/cn.js';
5
+ /**
6
+ * What a region shows when it holds nothing: one sentence, and at most one way
7
+ * forward. Not a failure — a region that could not load says so with an
8
+ * `Alert` instead, because an empty result and a dead backend must never look
9
+ * alike. Server-safe.
10
+ */ export function EmptyState(_0) {
11
+ let { action, className, children } = _0, props = _object_without_properties_loose(_0, [
12
+ "action",
13
+ "className",
14
+ "children"
15
+ ]);
16
+ return /*#__PURE__*/ _jsxs("div", _extends({
17
+ className: cn('flex flex-col items-center gap-s rounded-lg border border-dashed border-border px-m py-l text-center', className)
18
+ }, props, {
19
+ children: [
20
+ /*#__PURE__*/ _jsx("p", {
21
+ className: "m-0 max-w-(--measure) text-step-sm text-content-muted",
22
+ children: children
23
+ }),
24
+ action
25
+ ]
26
+ }));
27
+ }
28
+
29
+ //# sourceMappingURL=empty-state.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/ui/molecules/empty-state/empty-state.tsx"],"sourcesContent":["import type { ComponentPropsWithoutRef, ReactNode } from 'react';\n\nimport { cn } from '../../utils/cn.js';\n\nexport interface EmptyStateProps extends Omit<\n ComponentPropsWithoutRef<'div'>,\n 'children'\n> {\n /** One sentence: what is not here, and why when it is not obvious. */\n children: ReactNode;\n /** The one thing to do about it — create the first record, clear a filter. */\n action?: ReactNode;\n}\n\n/**\n * What a region shows when it holds nothing: one sentence, and at most one way\n * forward. Not a failure — a region that could not load says so with an\n * `Alert` instead, because an empty result and a dead backend must never look\n * alike. Server-safe.\n */\nexport function EmptyState({\n action,\n className,\n children,\n ...props\n}: EmptyStateProps) {\n return (\n <div\n className={cn(\n 'flex flex-col items-center gap-s rounded-lg border border-dashed border-border px-m py-l text-center',\n className,\n )}\n {...props}\n >\n <p className=\"m-0 max-w-(--measure) text-step-sm text-content-muted\">\n {children}\n </p>\n {action}\n </div>\n );\n}\n"],"names":["cn","EmptyState","action","className","children","props","div","p"],"mappings":";;;AAEA,SAASA,EAAE,QAAQ,oBAAoB;AAYvC;;;;;CAKC,GACD,OAAO,SAASC,WAAW,EAKT;QALS,EACzBC,MAAM,EACNC,SAAS,EACTC,QAAQ,EAEQ,OADbC;;;;;IAEH,qBACE,MAACC;QACCH,WAAWH,GACT,wGACAG;OAEEE;;0BAEJ,KAACE;gBAAEJ,WAAU;0BACVC;;YAEFF;;;AAGP"}
@@ -0,0 +1,2 @@
1
+ export * from './empty-state.js';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/ui/molecules/empty-state/index.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAC"}
@@ -0,0 +1,3 @@
1
+ export * from './empty-state.js';
2
+
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/ui/molecules/empty-state/index.ts"],"sourcesContent":["export * from './empty-state.js';\n"],"names":[],"mappings":"AAAA,cAAc,mBAAmB"}
@@ -1 +1 @@
1
- {"version":3,"file":"entity-link-input.d.ts","sourceRoot":"","sources":["../../../../src/ui/molecules/entity-link-input/entity-link-input.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,MAAM,EACN,qBAAqB,EACrB,gBAAgB,EACjB,MAAM,eAAe,CAAC;AAcvB,MAAM,WAAW,oBAAoB,CAAC,OAAO,SAAS,MAAM;IAC1D,+DAA+D;IAC/D,UAAU,EAAE,qBAAqB,CAAC;IAClC,4EAA4E;IAC5E,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,gBAAgB,CAAC,OAAO,CAAC,CAAC;IAClC,4CAA4C;IAC5C,QAAQ,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;IACpC,gCAAgC;IAChC,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,0CAA0C;IAC1C,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAsBD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,eAAe,CAAC,OAAO,SAAS,MAAM,EAAE,EACtD,UAAU,EACV,KAAK,EACL,MAAM,EACN,QAAQ,EACR,OAAO,EACP,EAAE,EACF,QAAgB,GACjB,EAAE,oBAAoB,CAAC,OAAO,CAAC,+BAiJ/B"}
1
+ {"version":3,"file":"entity-link-input.d.ts","sourceRoot":"","sources":["../../../../src/ui/molecules/entity-link-input/entity-link-input.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,MAAM,EACN,qBAAqB,EACrB,gBAAgB,EACjB,MAAM,eAAe,CAAC;AAcvB,MAAM,WAAW,oBAAoB,CAAC,OAAO,SAAS,MAAM;IAC1D,+DAA+D;IAC/D,UAAU,EAAE,qBAAqB,CAAC;IAClC,4EAA4E;IAC5E,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,gBAAgB,CAAC,OAAO,CAAC,CAAC;IAClC,4CAA4C;IAC5C,QAAQ,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;IACpC,gCAAgC;IAChC,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,0CAA0C;IAC1C,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAsBD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,eAAe,CAAC,OAAO,SAAS,MAAM,EAAE,EACtD,UAAU,EACV,KAAK,EACL,MAAM,EACN,QAAQ,EACR,OAAO,EACP,EAAE,EACF,QAAgB,GACjB,EAAE,oBAAoB,CAAC,OAAO,CAAC,+BAoJ/B"}
@@ -97,7 +97,7 @@ import { LoadingBoundary } from '../loading-boundary/index.js';
97
97
  disabled: disabled,
98
98
  onChange: (event)=>source.quick.setTerm(event.currentTarget.value),
99
99
  className: [
100
- 'w-full rounded-lg border border-border bg-surface-elevated px-2xs py-3xs',
100
+ 'min-h-(--target-min) w-full rounded-lg border border-border-control bg-surface-elevated px-2xs py-3xs',
101
101
  'text-step-sm text-content',
102
102
  'focus-ring',
103
103
  'disabled:cursor-not-allowed disabled:opacity-50'
@@ -112,7 +112,7 @@ import { LoadingBoundary } from '../loading-boundary/index.js';
112
112
  }),
113
113
  /*#__PURE__*/ _jsxs(ComboboxOptions, {
114
114
  className: [
115
- 'max-h-64 absolute z-50 mt-3xs w-full overflow-auto',
115
+ 'max-h-64 absolute z-(--z-dropdown) mt-3xs w-full overflow-auto',
116
116
  'rounded-lg border border-border bg-surface-elevated p-3xs shadow-overlay',
117
117
  // The panel itself is a focus-managed CONTAINER, not a target: the ring
118
118
  // belongs on the item inside it. Stripping the outline here is
@@ -134,8 +134,11 @@ import { LoadingBoundary } from '../loading-boundary/index.js';
134
134
  source.quick.options.map((option)=>/*#__PURE__*/ _jsx(ComboboxOption, {
135
135
  value: option,
136
136
  className: [
137
- 'cursor-pointer rounded-md px-2xs py-3xs text-step-sm text-content',
138
- 'data-focus:bg-surface'
137
+ 'flex min-h-(--target-min) cursor-pointer items-center rounded-md border-l-2 border-transparent px-2xs py-3xs text-step-sm text-content',
138
+ // Active: the focus ring. Chosen but not under the
139
+ // keyboard: a `selected` edge, 3:1 on the panel.
140
+ 'focus-ring data-focus:bg-surface data-focus:-outline-offset-2',
141
+ 'data-selected:border-selected'
139
142
  ].join(' '),
140
143
  children: source.labelOf(option)
141
144
  }, String(option.id)))
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/ui/molecules/entity-link-input/entity-link-input.tsx"],"sourcesContent":["'use client';\n\nimport type {\n Entity,\n EntityFieldDescriptor,\n EntityLinkSource,\n} from '@entifix/core';\nimport {\n Combobox,\n ComboboxButton,\n ComboboxInput,\n ComboboxOption,\n ComboboxOptions,\n} from '@headlessui/react';\n\nimport { useErrorMessage, useT } from '../../../i18n/index.js';\nimport { Button } from '../../atoms/button/index.js';\nimport { EntityLinkPicker } from '../entity-link-picker/index.js';\nimport { LoadingBoundary } from '../loading-boundary/index.js';\n\nexport interface EntityLinkInputProps<TTarget extends Entity> {\n /** The relation being edited. Its label names the controls. */\n descriptor: EntityFieldDescriptor;\n /** The held foreign key, as the draft carries it. `''` means unassigned. */\n value: string;\n source: EntityLinkSource<TTarget>;\n /** A target was chosen — in either mode. */\n onSelect: (entity: TTarget) => void;\n /** The relation was emptied. */\n onClear: () => void;\n /** The id the field's label points at. */\n id?: string;\n disabled?: boolean;\n}\n\n/** Chevron — the quick search. Inline so the package ships no icon dependency. */\nfunction ChevronIcon() {\n return (\n <svg aria-hidden viewBox=\"0 0 20 20\" className=\"size-4 fill-current\">\n <path d=\"M5.5 7.5 10 12l4.5-4.5z\" />\n </svg>\n );\n}\n\n/** Ellipsis — the browse dialog, the same affordance a desktop app uses. */\nfunction EllipsisIcon() {\n return (\n <svg aria-hidden viewBox=\"0 0 20 20\" className=\"size-4 fill-current\">\n <circle cx=\"4\" cy=\"10\" r=\"1.5\" />\n <circle cx=\"10\" cy=\"10\" r=\"1.5\" />\n <circle cx=\"16\" cy=\"10\" r=\"1.5\" />\n </svg>\n );\n}\n\n/**\n * The editor for a to-one relation: what the value *is*, plus the two ways to\n * change it.\n *\n * - the chevron opens a type-ahead over the target entity — \"I know roughly what\n * it is called\";\n * - the ellipsis opens the target's full table in a dialog — \"I need to filter\n * the catalog to find it\".\n *\n * It is presentational. Every option, loading flag and error arrives through\n * {@link EntityLinkSource}, which the integration layer produces; this component\n * cannot fetch, and never decides how the relation is written back — it reports\n * the chosen instance and the form's reconstruction step applies the entity's own\n * `linkSerialization` policy.\n *\n * The displayed text is the target's label when one is known and the bare foreign\n * key when it is not, so a draft restored before its label resolves still shows\n * *something* true rather than an empty box.\n */\nexport function EntityLinkInput<TTarget extends Entity>({\n descriptor,\n value,\n source,\n onSelect,\n onClear,\n id,\n disabled = false,\n}: EntityLinkInputProps<TTarget>) {\n const t = useT();\n const errorMessage = useErrorMessage();\n\n const assigned = value !== '';\n const label = source.selected.label ?? (assigned ? value : '');\n const display = source.selected.isLoading\n ? t('link.loading')\n : label === ''\n ? t('link.empty')\n : label;\n\n /**\n * Headless UI reports `null` when the search is abandoned (escape, blur). That\n * is not a request to empty the relation — clearing is the explicit action\n * beside the input — so it leaves the held value alone.\n */\n const handleSelect = (entity: TTarget | null) => {\n if (entity === null) return;\n onSelect(entity);\n source.quick.setTerm('');\n };\n\n return (\n <div className=\"flex flex-col gap-3xs\">\n <div className=\"flex items-stretch gap-3xs\">\n <div className=\"relative flex-1\">\n <Combobox<TTarget | null>\n value={null}\n onChange={handleSelect}\n disabled={disabled}\n immediate\n >\n {/*\n The input edits the *search term*, never the value: the value is a\n foreign key, which is not something a user types. So it displays the\n resolved label while idle and the term while searching.\n */}\n <ComboboxInput\n id={id}\n aria-label={t('link.search', { field: descriptor.label })}\n placeholder={display}\n value={source.quick.term}\n disabled={disabled}\n onChange={event =>\n source.quick.setTerm(event.currentTarget.value)\n }\n className={[\n 'w-full rounded-lg border border-border bg-surface-elevated px-2xs py-3xs',\n 'text-step-sm text-content',\n 'focus-ring',\n 'disabled:cursor-not-allowed disabled:opacity-50',\n ].join(' ')}\n />\n <ComboboxButton\n aria-label={t('link.suggestAria', { field: descriptor.label })}\n className=\"inset-y-0 right-0 absolute flex items-center px-2xs text-content-muted\"\n >\n <ChevronIcon />\n </ComboboxButton>\n <ComboboxOptions\n className={[\n 'max-h-64 absolute z-50 mt-3xs w-full overflow-auto',\n 'rounded-lg border border-border bg-surface-elevated p-3xs shadow-overlay',\n // The panel itself is a focus-managed CONTAINER, not a target: the ring\n // belongs on the item inside it. Stripping the outline here is\n // correct, and is not a missing `focus-ring`.\n 'focus:outline-none',\n ].join(' ')}\n >\n {source.quick.isLoading && (\n <LoadingBoundary\n isLoading\n lines={2}\n label={t('link.loading')}\n className=\"px-2xs py-3xs\"\n >\n {null}\n </LoadingBoundary>\n )}\n {!source.quick.isLoading && source.quick.options.length === 0 && (\n <div className=\"px-2xs py-3xs text-step-sm text-content-muted\">\n {t('link.noResults')}\n </div>\n )}\n {source.quick.options.map(option => (\n <ComboboxOption\n key={String(option.id)}\n value={option}\n className={[\n 'cursor-pointer rounded-md px-2xs py-3xs text-step-sm text-content',\n 'data-focus:bg-surface',\n ].join(' ')}\n >\n {source.labelOf(option)}\n </ComboboxOption>\n ))}\n </ComboboxOptions>\n </Combobox>\n </div>\n\n <Button\n type=\"button\"\n variant=\"secondary\"\n size=\"sm\"\n disabled={disabled}\n aria-label={t('link.browseAria', { field: descriptor.label })}\n onClick={source.browse.open}\n >\n <EllipsisIcon />\n </Button>\n {/* Clearing is only offered when there is something to clear — and a\n required relation still offers it, because `required` is the form's\n rule to report, not the input's to enforce. */}\n {assigned && !disabled && (\n <Button type=\"button\" variant=\"ghost\" size=\"sm\" onClick={onClear}>\n {t('link.clear', { field: descriptor.label })}\n </Button>\n )}\n </div>\n\n {/* The held value, always readable — the combobox input shows the term. */}\n <span\n data-testid={`entity-link-value-${descriptor.name}`}\n className=\"text-step-sm text-content\"\n >\n {display}\n </span>\n\n {source.quick.error && (\n <span role=\"alert\" className=\"text-step-sm text-danger\">\n {errorMessage(source.quick.error)}\n </span>\n )}\n\n <EntityLinkPicker<TTarget>\n descriptor={descriptor}\n source={source}\n onSelect={entity => {\n onSelect(entity);\n source.browse.close();\n }}\n />\n </div>\n );\n}\n"],"names":["Combobox","ComboboxButton","ComboboxInput","ComboboxOption","ComboboxOptions","useErrorMessage","useT","Button","EntityLinkPicker","LoadingBoundary","ChevronIcon","svg","aria-hidden","viewBox","className","path","d","EllipsisIcon","circle","cx","cy","r","EntityLinkInput","descriptor","value","source","onSelect","onClear","id","disabled","t","errorMessage","assigned","label","selected","display","isLoading","handleSelect","entity","quick","setTerm","div","onChange","immediate","aria-label","field","placeholder","term","event","currentTarget","join","lines","options","length","map","option","labelOf","String","type","variant","size","onClick","browse","open","span","data-testid","name","error","role","close"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../src/ui/molecules/entity-link-input/entity-link-input.tsx"],"sourcesContent":["'use client';\n\nimport type {\n Entity,\n EntityFieldDescriptor,\n EntityLinkSource,\n} from '@entifix/core';\nimport {\n Combobox,\n ComboboxButton,\n ComboboxInput,\n ComboboxOption,\n ComboboxOptions,\n} from '@headlessui/react';\n\nimport { useErrorMessage, useT } from '../../../i18n/index.js';\nimport { Button } from '../../atoms/button/index.js';\nimport { EntityLinkPicker } from '../entity-link-picker/index.js';\nimport { LoadingBoundary } from '../loading-boundary/index.js';\n\nexport interface EntityLinkInputProps<TTarget extends Entity> {\n /** The relation being edited. Its label names the controls. */\n descriptor: EntityFieldDescriptor;\n /** The held foreign key, as the draft carries it. `''` means unassigned. */\n value: string;\n source: EntityLinkSource<TTarget>;\n /** A target was chosen — in either mode. */\n onSelect: (entity: TTarget) => void;\n /** The relation was emptied. */\n onClear: () => void;\n /** The id the field's label points at. */\n id?: string;\n disabled?: boolean;\n}\n\n/** Chevron — the quick search. Inline so the package ships no icon dependency. */\nfunction ChevronIcon() {\n return (\n <svg aria-hidden viewBox=\"0 0 20 20\" className=\"size-4 fill-current\">\n <path d=\"M5.5 7.5 10 12l4.5-4.5z\" />\n </svg>\n );\n}\n\n/** Ellipsis — the browse dialog, the same affordance a desktop app uses. */\nfunction EllipsisIcon() {\n return (\n <svg aria-hidden viewBox=\"0 0 20 20\" className=\"size-4 fill-current\">\n <circle cx=\"4\" cy=\"10\" r=\"1.5\" />\n <circle cx=\"10\" cy=\"10\" r=\"1.5\" />\n <circle cx=\"16\" cy=\"10\" r=\"1.5\" />\n </svg>\n );\n}\n\n/**\n * The editor for a to-one relation: what the value *is*, plus the two ways to\n * change it.\n *\n * - the chevron opens a type-ahead over the target entity — \"I know roughly what\n * it is called\";\n * - the ellipsis opens the target's full table in a dialog — \"I need to filter\n * the catalog to find it\".\n *\n * It is presentational. Every option, loading flag and error arrives through\n * {@link EntityLinkSource}, which the integration layer produces; this component\n * cannot fetch, and never decides how the relation is written back — it reports\n * the chosen instance and the form's reconstruction step applies the entity's own\n * `linkSerialization` policy.\n *\n * The displayed text is the target's label when one is known and the bare foreign\n * key when it is not, so a draft restored before its label resolves still shows\n * *something* true rather than an empty box.\n */\nexport function EntityLinkInput<TTarget extends Entity>({\n descriptor,\n value,\n source,\n onSelect,\n onClear,\n id,\n disabled = false,\n}: EntityLinkInputProps<TTarget>) {\n const t = useT();\n const errorMessage = useErrorMessage();\n\n const assigned = value !== '';\n const label = source.selected.label ?? (assigned ? value : '');\n const display = source.selected.isLoading\n ? t('link.loading')\n : label === ''\n ? t('link.empty')\n : label;\n\n /**\n * Headless UI reports `null` when the search is abandoned (escape, blur). That\n * is not a request to empty the relation — clearing is the explicit action\n * beside the input — so it leaves the held value alone.\n */\n const handleSelect = (entity: TTarget | null) => {\n if (entity === null) return;\n onSelect(entity);\n source.quick.setTerm('');\n };\n\n return (\n <div className=\"flex flex-col gap-3xs\">\n <div className=\"flex items-stretch gap-3xs\">\n <div className=\"relative flex-1\">\n <Combobox<TTarget | null>\n value={null}\n onChange={handleSelect}\n disabled={disabled}\n immediate\n >\n {/*\n The input edits the *search term*, never the value: the value is a\n foreign key, which is not something a user types. So it displays the\n resolved label while idle and the term while searching.\n */}\n <ComboboxInput\n id={id}\n aria-label={t('link.search', { field: descriptor.label })}\n placeholder={display}\n value={source.quick.term}\n disabled={disabled}\n onChange={event =>\n source.quick.setTerm(event.currentTarget.value)\n }\n className={[\n 'min-h-(--target-min) w-full rounded-lg border border-border-control bg-surface-elevated px-2xs py-3xs',\n 'text-step-sm text-content',\n 'focus-ring',\n 'disabled:cursor-not-allowed disabled:opacity-50',\n ].join(' ')}\n />\n <ComboboxButton\n aria-label={t('link.suggestAria', { field: descriptor.label })}\n className=\"inset-y-0 right-0 absolute flex items-center px-2xs text-content-muted\"\n >\n <ChevronIcon />\n </ComboboxButton>\n <ComboboxOptions\n className={[\n 'max-h-64 absolute z-(--z-dropdown) mt-3xs w-full overflow-auto',\n 'rounded-lg border border-border bg-surface-elevated p-3xs shadow-overlay',\n // The panel itself is a focus-managed CONTAINER, not a target: the ring\n // belongs on the item inside it. Stripping the outline here is\n // correct, and is not a missing `focus-ring`.\n 'focus:outline-none',\n ].join(' ')}\n >\n {source.quick.isLoading && (\n <LoadingBoundary\n isLoading\n lines={2}\n label={t('link.loading')}\n className=\"px-2xs py-3xs\"\n >\n {null}\n </LoadingBoundary>\n )}\n {!source.quick.isLoading && source.quick.options.length === 0 && (\n <div className=\"px-2xs py-3xs text-step-sm text-content-muted\">\n {t('link.noResults')}\n </div>\n )}\n {source.quick.options.map(option => (\n <ComboboxOption\n key={String(option.id)}\n value={option}\n className={[\n 'flex min-h-(--target-min) cursor-pointer items-center rounded-md border-l-2 border-transparent px-2xs py-3xs text-step-sm text-content',\n // Active: the focus ring. Chosen but not under the\n // keyboard: a `selected` edge, 3:1 on the panel.\n 'focus-ring data-focus:bg-surface data-focus:-outline-offset-2',\n 'data-selected:border-selected',\n ].join(' ')}\n >\n {source.labelOf(option)}\n </ComboboxOption>\n ))}\n </ComboboxOptions>\n </Combobox>\n </div>\n\n <Button\n type=\"button\"\n variant=\"secondary\"\n size=\"sm\"\n disabled={disabled}\n aria-label={t('link.browseAria', { field: descriptor.label })}\n onClick={source.browse.open}\n >\n <EllipsisIcon />\n </Button>\n {/* Clearing is only offered when there is something to clear — and a\n required relation still offers it, because `required` is the form's\n rule to report, not the input's to enforce. */}\n {assigned && !disabled && (\n <Button type=\"button\" variant=\"ghost\" size=\"sm\" onClick={onClear}>\n {t('link.clear', { field: descriptor.label })}\n </Button>\n )}\n </div>\n\n {/* The held value, always readable — the combobox input shows the term. */}\n <span\n data-testid={`entity-link-value-${descriptor.name}`}\n className=\"text-step-sm text-content\"\n >\n {display}\n </span>\n\n {source.quick.error && (\n <span role=\"alert\" className=\"text-step-sm text-danger\">\n {errorMessage(source.quick.error)}\n </span>\n )}\n\n <EntityLinkPicker<TTarget>\n descriptor={descriptor}\n source={source}\n onSelect={entity => {\n onSelect(entity);\n source.browse.close();\n }}\n />\n </div>\n );\n}\n"],"names":["Combobox","ComboboxButton","ComboboxInput","ComboboxOption","ComboboxOptions","useErrorMessage","useT","Button","EntityLinkPicker","LoadingBoundary","ChevronIcon","svg","aria-hidden","viewBox","className","path","d","EllipsisIcon","circle","cx","cy","r","EntityLinkInput","descriptor","value","source","onSelect","onClear","id","disabled","t","errorMessage","assigned","label","selected","display","isLoading","handleSelect","entity","quick","setTerm","div","onChange","immediate","aria-label","field","placeholder","term","event","currentTarget","join","lines","options","length","map","option","labelOf","String","type","variant","size","onClick","browse","open","span","data-testid","name","error","role","close"],"mappings":"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"}
@@ -23,11 +23,11 @@ import { EntityTable } from '../../organisms/entity-table/index.js';
23
23
  /*#__PURE__*/ _jsxs(Dialog, {
24
24
  open: browse.isOpen,
25
25
  onClose: browse.close,
26
- className: "inset-0 fixed z-50 flex items-start justify-center overflow-y-auto p-s",
26
+ className: "inset-0 fixed z-(--z-overlay) flex items-start justify-center overflow-y-auto p-s",
27
27
  children: [
28
28
  /*#__PURE__*/ _jsx("div", {
29
29
  "aria-hidden": true,
30
- className: "inset-0 bg-black/40 fixed"
30
+ className: "inset-0 fixed bg-scrim"
31
31
  }),
32
32
  /*#__PURE__*/ _jsxs(DialogPanel, {
33
33
  className: "max-w-4xl relative w-full rounded-lg border border-border bg-surface p-s shadow-overlay",
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/ui/molecules/entity-link-picker/entity-link-picker.tsx"],"sourcesContent":["'use client';\n\nimport type {\n Entity,\n EntityFieldDescriptor,\n EntityLinkSource,\n} from '@entifix/core';\nimport { Dialog, DialogPanel, DialogTitle } from '@headlessui/react';\n\nimport { useT } from '../../../i18n/index.js';\nimport { Button } from '../../atoms/button/index.js';\nimport { EntityTable } from '../../organisms/entity-table/index.js';\n\nexport interface EntityLinkPickerProps<TTarget extends Entity> {\n /** The relation being set — its label names the dialog. */\n descriptor: EntityFieldDescriptor;\n source: EntityLinkSource<TTarget>;\n onSelect: (entity: TTarget) => void;\n}\n\n/**\n * The thorough half of setting a relation: the target entity's own table, with\n * its filters, sorting and paging, inside a dialog.\n *\n * It adds nothing to the table — that is the point. A picker that re-implemented\n * filtering would drift from the listing the user already knows, so this mounts\n * the same `EntityTable` and swaps navigation for selection through `onSelect`.\n * Everything it renders comes from `source.browse`, so it holds no fetch of its\n * own.\n */\nexport function EntityLinkPicker<TTarget extends Entity>({\n descriptor,\n source,\n onSelect,\n}: EntityLinkPickerProps<TTarget>) {\n const t = useT();\n const { browse } = source;\n\n return (\n // The dialog element itself fills the viewport rather than wrapping a\n // `fixed` child in a `relative` box: a zero-sized dialog is invisible to\n // anything measuring it — assistive tech and Playwright alike — even with a\n // painted panel inside it.\n <Dialog\n open={browse.isOpen}\n onClose={browse.close}\n className=\"inset-0 fixed z-50 flex items-start justify-center overflow-y-auto p-s\"\n >\n {/* Backdrop and panel are separate so a click outside closes the dialog\n without the table's own clicks bubbling into it. */}\n <div aria-hidden className=\"inset-0 bg-black/40 fixed\" />\n <DialogPanel className=\"max-w-4xl relative w-full rounded-lg border border-border bg-surface p-s shadow-overlay\">\n <div className=\"flex items-center justify-between gap-s\">\n <DialogTitle className=\"text-step-1 font-semibold text-content\">\n {t('link.browseTitle', { field: descriptor.label })}\n </DialogTitle>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n onClick={browse.close}\n >\n {t('link.close')}\n </Button>\n </div>\n\n <EntityTable<TTarget>\n entityConstructor={source.entityConstructor}\n isLoading={browse.isLoading}\n error={browse.error}\n items={browse.items}\n totalItems={browse.totalItems}\n currentPage={browse.currentPage}\n pageSize={browse.pageSize}\n onPageChange={browse.onPageChange}\n onPageSizeChange={browse.onPageSizeChange}\n filtering={browse.filtering}\n sorting={browse.sorting}\n onFilteringChange={browse.onFilteringChange}\n onSortingChange={browse.onSortingChange}\n onSelect={onSelect}\n // Scoped so a picker's column personalization does not overwrite the\n // one the user set on the full listing of the same entity.\n preferencesKey={`link-picker:${descriptor.name}`}\n />\n </DialogPanel>\n </Dialog>\n );\n}\n"],"names":["Dialog","DialogPanel","DialogTitle","useT","Button","EntityTable","EntityLinkPicker","descriptor","source","onSelect","t","browse","open","isOpen","onClose","close","className","div","aria-hidden","field","label","type","variant","size","onClick","entityConstructor","isLoading","error","items","totalItems","currentPage","pageSize","onPageChange","onPageSizeChange","filtering","sorting","onFilteringChange","onSortingChange","preferencesKey","name"],"mappings":"AAAA;;AAOA,SAASA,MAAM,EAAEC,WAAW,EAAEC,WAAW,QAAQ,oBAAoB;AAErE,SAASC,IAAI,QAAQ,yBAAyB;AAC9C,SAASC,MAAM,QAAQ,8BAA8B;AACrD,SAASC,WAAW,QAAQ,wCAAwC;AASpE;;;;;;;;;CASC,GACD,OAAO,SAASC,iBAAyC,EACvDC,UAAU,EACVC,MAAM,EACNC,QAAQ,EACuB;IAC/B,MAAMC,IAAIP;IACV,MAAM,EAAEQ,MAAM,EAAE,GAAGH;IAEnB,OACE,sEAAsE;IACtE,yEAAyE;IACzE,4EAA4E;IAC5E,2BAA2B;kBAC3B,MAACR;QACCY,MAAMD,OAAOE,MAAM;QACnBC,SAASH,OAAOI,KAAK;QACrBC,WAAU;;0BAIV,KAACC;gBAAIC,aAAW;gBAACF,WAAU;;0BAC3B,MAACf;gBAAYe,WAAU;;kCACrB,MAACC;wBAAID,WAAU;;0CACb,KAACd;gCAAYc,WAAU;0CACpBN,EAAE,oBAAoB;oCAAES,OAAOZ,WAAWa,KAAK;gCAAC;;0CAEnD,KAAChB;gCACCiB,MAAK;gCACLC,SAAQ;gCACRC,MAAK;gCACLC,SAASb,OAAOI,KAAK;0CAEpBL,EAAE;;;;kCAIP,KAACL;wBACCoB,mBAAmBjB,OAAOiB,iBAAiB;wBAC3CC,WAAWf,OAAOe,SAAS;wBAC3BC,OAAOhB,OAAOgB,KAAK;wBACnBC,OAAOjB,OAAOiB,KAAK;wBACnBC,YAAYlB,OAAOkB,UAAU;wBAC7BC,aAAanB,OAAOmB,WAAW;wBAC/BC,UAAUpB,OAAOoB,QAAQ;wBACzBC,cAAcrB,OAAOqB,YAAY;wBACjCC,kBAAkBtB,OAAOsB,gBAAgB;wBACzCC,WAAWvB,OAAOuB,SAAS;wBAC3BC,SAASxB,OAAOwB,OAAO;wBACvBC,mBAAmBzB,OAAOyB,iBAAiB;wBAC3CC,iBAAiB1B,OAAO0B,eAAe;wBACvC5B,UAAUA;wBACV,qEAAqE;wBACrE,2DAA2D;wBAC3D6B,gBAAgB,CAAC,YAAY,EAAE/B,WAAWgC,IAAI,EAAE;;;;;;AAK1D"}
1
+ {"version":3,"sources":["../../../../src/ui/molecules/entity-link-picker/entity-link-picker.tsx"],"sourcesContent":["'use client';\n\nimport type {\n Entity,\n EntityFieldDescriptor,\n EntityLinkSource,\n} from '@entifix/core';\nimport { Dialog, DialogPanel, DialogTitle } from '@headlessui/react';\n\nimport { useT } from '../../../i18n/index.js';\nimport { Button } from '../../atoms/button/index.js';\nimport { EntityTable } from '../../organisms/entity-table/index.js';\n\nexport interface EntityLinkPickerProps<TTarget extends Entity> {\n /** The relation being set — its label names the dialog. */\n descriptor: EntityFieldDescriptor;\n source: EntityLinkSource<TTarget>;\n onSelect: (entity: TTarget) => void;\n}\n\n/**\n * The thorough half of setting a relation: the target entity's own table, with\n * its filters, sorting and paging, inside a dialog.\n *\n * It adds nothing to the table — that is the point. A picker that re-implemented\n * filtering would drift from the listing the user already knows, so this mounts\n * the same `EntityTable` and swaps navigation for selection through `onSelect`.\n * Everything it renders comes from `source.browse`, so it holds no fetch of its\n * own.\n */\nexport function EntityLinkPicker<TTarget extends Entity>({\n descriptor,\n source,\n onSelect,\n}: EntityLinkPickerProps<TTarget>) {\n const t = useT();\n const { browse } = source;\n\n return (\n // The dialog element itself fills the viewport rather than wrapping a\n // `fixed` child in a `relative` box: a zero-sized dialog is invisible to\n // anything measuring it — assistive tech and Playwright alike — even with a\n // painted panel inside it.\n <Dialog\n open={browse.isOpen}\n onClose={browse.close}\n className=\"inset-0 fixed z-(--z-overlay) flex items-start justify-center overflow-y-auto p-s\"\n >\n {/* Backdrop and panel are separate so a click outside closes the dialog\n without the table's own clicks bubbling into it. */}\n <div aria-hidden className=\"inset-0 fixed bg-scrim\" />\n <DialogPanel className=\"max-w-4xl relative w-full rounded-lg border border-border bg-surface p-s shadow-overlay\">\n <div className=\"flex items-center justify-between gap-s\">\n <DialogTitle className=\"text-step-1 font-semibold text-content\">\n {t('link.browseTitle', { field: descriptor.label })}\n </DialogTitle>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n onClick={browse.close}\n >\n {t('link.close')}\n </Button>\n </div>\n\n <EntityTable<TTarget>\n entityConstructor={source.entityConstructor}\n isLoading={browse.isLoading}\n error={browse.error}\n items={browse.items}\n totalItems={browse.totalItems}\n currentPage={browse.currentPage}\n pageSize={browse.pageSize}\n onPageChange={browse.onPageChange}\n onPageSizeChange={browse.onPageSizeChange}\n filtering={browse.filtering}\n sorting={browse.sorting}\n onFilteringChange={browse.onFilteringChange}\n onSortingChange={browse.onSortingChange}\n onSelect={onSelect}\n // Scoped so a picker's column personalization does not overwrite the\n // one the user set on the full listing of the same entity.\n preferencesKey={`link-picker:${descriptor.name}`}\n />\n </DialogPanel>\n </Dialog>\n );\n}\n"],"names":["Dialog","DialogPanel","DialogTitle","useT","Button","EntityTable","EntityLinkPicker","descriptor","source","onSelect","t","browse","open","isOpen","onClose","close","className","div","aria-hidden","field","label","type","variant","size","onClick","entityConstructor","isLoading","error","items","totalItems","currentPage","pageSize","onPageChange","onPageSizeChange","filtering","sorting","onFilteringChange","onSortingChange","preferencesKey","name"],"mappings":"AAAA;;AAOA,SAASA,MAAM,EAAEC,WAAW,EAAEC,WAAW,QAAQ,oBAAoB;AAErE,SAASC,IAAI,QAAQ,yBAAyB;AAC9C,SAASC,MAAM,QAAQ,8BAA8B;AACrD,SAASC,WAAW,QAAQ,wCAAwC;AASpE;;;;;;;;;CASC,GACD,OAAO,SAASC,iBAAyC,EACvDC,UAAU,EACVC,MAAM,EACNC,QAAQ,EACuB;IAC/B,MAAMC,IAAIP;IACV,MAAM,EAAEQ,MAAM,EAAE,GAAGH;IAEnB,OACE,sEAAsE;IACtE,yEAAyE;IACzE,4EAA4E;IAC5E,2BAA2B;kBAC3B,MAACR;QACCY,MAAMD,OAAOE,MAAM;QACnBC,SAASH,OAAOI,KAAK;QACrBC,WAAU;;0BAIV,KAACC;gBAAIC,aAAW;gBAACF,WAAU;;0BAC3B,MAACf;gBAAYe,WAAU;;kCACrB,MAACC;wBAAID,WAAU;;0CACb,KAACd;gCAAYc,WAAU;0CACpBN,EAAE,oBAAoB;oCAAES,OAAOZ,WAAWa,KAAK;gCAAC;;0CAEnD,KAAChB;gCACCiB,MAAK;gCACLC,SAAQ;gCACRC,MAAK;gCACLC,SAASb,OAAOI,KAAK;0CAEpBL,EAAE;;;;kCAIP,KAACL;wBACCoB,mBAAmBjB,OAAOiB,iBAAiB;wBAC3CC,WAAWf,OAAOe,SAAS;wBAC3BC,OAAOhB,OAAOgB,KAAK;wBACnBC,OAAOjB,OAAOiB,KAAK;wBACnBC,YAAYlB,OAAOkB,UAAU;wBAC7BC,aAAanB,OAAOmB,WAAW;wBAC/BC,UAAUpB,OAAOoB,QAAQ;wBACzBC,cAAcrB,OAAOqB,YAAY;wBACjCC,kBAAkBtB,OAAOsB,gBAAgB;wBACzCC,WAAWvB,OAAOuB,SAAS;wBAC3BC,SAASxB,OAAOwB,OAAO;wBACvBC,mBAAmBzB,OAAOyB,iBAAiB;wBAC3CC,iBAAiB1B,OAAO0B,eAAe;wBACvC5B,UAAUA;wBACV,qEAAqE;wBACrE,2DAA2D;wBAC3D6B,gBAAgB,CAAC,YAAY,EAAE/B,WAAWgC,IAAI,EAAE;;;;;;AAK1D"}
@@ -1,30 +1,43 @@
1
- import type { ReactNode } from 'react';
2
- export interface EntityRecordCardColumn {
3
- name: string;
4
- label: string;
1
+ import { type ReactNode } from 'react';
2
+ /** One line of a card: a member's label and its value. */
3
+ export interface EntityRecordCardMeta {
4
+ key: string;
5
+ label: ReactNode;
6
+ value: ReactNode;
5
7
  }
6
8
  export interface EntityRecordCardProps {
7
- columns: readonly EntityRecordCardColumn[];
8
- /** Renders one column's cell. Supplied by the caller so a card and a table
9
- * row stay in agreement about custom renderers. */
10
- renderCell: (column: EntityRecordCardColumn) => ReactNode;
11
- /** Optional trailing actions (a link to the record, …). */
12
- actions?: ReactNode;
13
9
  /**
14
- * Rendered above the fields — the card's equivalent of a leading column.
15
- *
16
- * A selection box goes here rather than beside the actions because it is not
17
- * an action on the record: it decides whether the record is *in the set* the
18
- * actions will run over, and putting the two in one row reads as a third
19
- * button.
10
+ * The record's heading — what it is read as, usually a link to it. A link
11
+ * here is stretched over the whole card, so the card is one target.
12
+ */
13
+ title: ReactNode;
14
+ /** A line under the heading. */
15
+ subtitle?: ReactNode;
16
+ /** Short values beside the heading — a status. */
17
+ badges?: readonly {
18
+ key: string;
19
+ value: ReactNode;
20
+ }[];
21
+ /** The record's other members, as a description list. */
22
+ meta: readonly EntityRecordCardMeta[];
23
+ /**
24
+ * Above the heading: a selection box. It is not an action on the record —
25
+ * it decides whether the record is *in the set* the actions run over — so it
26
+ * does not sit with them.
20
27
  */
21
28
  leading?: ReactNode;
29
+ /** Above the heading, at the end: the record's menu. */
30
+ actions?: ReactNode;
22
31
  className?: string;
23
32
  }
24
33
  /**
25
- * A record pivoted from a row into a label/value stack. This is the narrow
26
- * viewport form of a table row: at phone widths a horizontal scroll hides most
27
- * columns, whereas stacking keeps every visible column readable.
34
+ * A record pivoted from a row into a card: the narrow form of a table row,
35
+ * where a horizontal scroll would hide most columns.
36
+ *
37
+ * An `article` named by its `h3`, so a reader can move card by card with the
38
+ * heading keys and hears what each record is. The title's link is stretched
39
+ * over the card; the selection box and the menu sit above it, so they stay
40
+ * their own targets.
28
41
  */
29
- export declare function EntityRecordCard({ columns, renderCell, actions, leading, className, }: EntityRecordCardProps): import("react").JSX.Element;
42
+ export declare function EntityRecordCard({ title, subtitle, badges, meta, leading, actions, className, }: EntityRecordCardProps): import("react").JSX.Element;
30
43
  //# sourceMappingURL=entity-record-card.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"entity-record-card.d.ts","sourceRoot":"","sources":["../../../../src/ui/molecules/entity-record-card/entity-record-card.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAIvC,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,SAAS,sBAAsB,EAAE,CAAC;IAC3C;wDACoD;IACpD,UAAU,EAAE,CAAC,MAAM,EAAE,sBAAsB,KAAK,SAAS,CAAC;IAC1D,2DAA2D;IAC3D,OAAO,CAAC,EAAE,SAAS,CAAC;IACpB;;;;;;;OAOG;IACH,OAAO,CAAC,EAAE,SAAS,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,EAC/B,OAAO,EACP,UAAU,EACV,OAAO,EACP,OAAO,EACP,SAAS,GACV,EAAE,qBAAqB,+BAyBvB"}
1
+ {"version":3,"file":"entity-record-card.d.ts","sourceRoot":"","sources":["../../../../src/ui/molecules/entity-record-card/entity-record-card.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAS,MAAM,OAAO,CAAC;AAI9C,0DAA0D;AAC1D,MAAM,WAAW,oBAAoB;IACnC,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,SAAS,CAAC;IACjB,KAAK,EAAE,SAAS,CAAC;CAClB;AAED,MAAM,WAAW,qBAAqB;IACpC;;;OAGG;IACH,KAAK,EAAE,SAAS,CAAC;IACjB,gCAAgC;IAChC,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,kDAAkD;IAClD,MAAM,CAAC,EAAE,SAAS;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,SAAS,CAAA;KAAE,EAAE,CAAC;IACtD,yDAAyD;IACzD,IAAI,EAAE,SAAS,oBAAoB,EAAE,CAAC;IACtC;;;;OAIG;IACH,OAAO,CAAC,EAAE,SAAS,CAAC;IACpB,wDAAwD;IACxD,OAAO,CAAC,EAAE,SAAS,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAAC,EAC/B,KAAK,EACL,QAAQ,EACR,MAAW,EACX,IAAI,EACJ,OAAO,EACP,OAAO,EACP,SAAS,GACV,EAAE,qBAAqB,+BAyDvB"}
@@ -1,36 +1,69 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useId } from 'react';
2
3
  import { cn } from '../../utils/cn.js';
3
4
  /**
4
- * A record pivoted from a row into a label/value stack. This is the narrow
5
- * viewport form of a table row: at phone widths a horizontal scroll hides most
6
- * columns, whereas stacking keeps every visible column readable.
7
- */ export function EntityRecordCard({ columns, renderCell, actions, leading, className }) {
8
- return /*#__PURE__*/ _jsxs("div", {
9
- className: cn('rounded-xl border border-border bg-surface-elevated p-s text-content shadow-edge', className),
5
+ * A record pivoted from a row into a card: the narrow form of a table row,
6
+ * where a horizontal scroll would hide most columns.
7
+ *
8
+ * An `article` named by its `h3`, so a reader can move card by card with the
9
+ * heading keys and hears what each record is. The title's link is stretched
10
+ * over the card; the selection box and the menu sit above it, so they stay
11
+ * their own targets.
12
+ */ export function EntityRecordCard({ title, subtitle, badges = [], meta, leading, actions, className }) {
13
+ const titleId = useId();
14
+ return /*#__PURE__*/ _jsxs("article", {
15
+ "aria-labelledby": titleId,
16
+ className: cn('relative rounded-xl border border-border bg-surface-elevated p-s text-content shadow-edge focus-within:border-primary', className),
10
17
  children: [
11
- leading && /*#__PURE__*/ _jsx("div", {
12
- className: "mb-2xs flex",
13
- children: leading
18
+ (leading !== undefined || actions !== undefined) && /*#__PURE__*/ _jsxs("div", {
19
+ className: "relative z-1 mb-2xs flex items-center justify-between gap-2xs",
20
+ children: [
21
+ /*#__PURE__*/ _jsx("div", {
22
+ className: "flex",
23
+ children: leading
24
+ }),
25
+ /*#__PURE__*/ _jsx("div", {
26
+ className: "flex",
27
+ children: actions
28
+ })
29
+ ]
14
30
  }),
15
- /*#__PURE__*/ _jsx("dl", {
16
- className: "flex flex-col gap-2xs",
17
- children: columns.map((column)=>/*#__PURE__*/ _jsxs("div", {
31
+ /*#__PURE__*/ _jsxs("div", {
32
+ className: "flex flex-wrap items-baseline justify-between gap-2xs",
33
+ children: [
34
+ /*#__PURE__*/ _jsx("h3", {
35
+ id: titleId,
36
+ className: "m-0 [&_a]:after:inset-0 text-step-0 font-semibold [&_a]:after:absolute [&_a]:after:content-['']",
37
+ children: title
38
+ }),
39
+ badges.length > 0 && /*#__PURE__*/ _jsx("div", {
40
+ className: "flex flex-wrap gap-3xs",
41
+ children: badges.map((badge)=>/*#__PURE__*/ _jsx("span", {
42
+ className: "rounded-full border border-border px-2xs text-step-sm",
43
+ children: badge.value
44
+ }, badge.key))
45
+ })
46
+ ]
47
+ }),
48
+ subtitle !== undefined && /*#__PURE__*/ _jsx("p", {
49
+ className: "m-0 text-step-sm text-content-muted",
50
+ children: subtitle
51
+ }),
52
+ meta.length > 0 && /*#__PURE__*/ _jsx("dl", {
53
+ className: "mt-2xs flex flex-col gap-2xs",
54
+ children: meta.map((line)=>/*#__PURE__*/ _jsxs("div", {
18
55
  className: "flex items-baseline justify-between gap-2xs",
19
56
  children: [
20
57
  /*#__PURE__*/ _jsx("dt", {
21
58
  className: "tracking-wide text-step-xs text-content-muted uppercase",
22
- children: column.label
59
+ children: line.label
23
60
  }),
24
61
  /*#__PURE__*/ _jsx("dd", {
25
- className: "text-right text-step-sm",
26
- children: renderCell(column)
62
+ className: "m-0 text-right text-step-sm",
63
+ children: line.value
27
64
  })
28
65
  ]
29
- }, column.name))
30
- }),
31
- actions && /*#__PURE__*/ _jsx("div", {
32
- className: "mt-2xs flex justify-end",
33
- children: actions
66
+ }, line.key))
34
67
  })
35
68
  ]
36
69
  });
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/ui/molecules/entity-record-card/entity-record-card.tsx"],"sourcesContent":["import type { ReactNode } from 'react';\n\nimport { cn } from '../../utils/cn.js';\n\nexport interface EntityRecordCardColumn {\n name: string;\n label: string;\n}\n\nexport interface EntityRecordCardProps {\n columns: readonly EntityRecordCardColumn[];\n /** Renders one column's cell. Supplied by the caller so a card and a table\n * row stay in agreement about custom renderers. */\n renderCell: (column: EntityRecordCardColumn) => ReactNode;\n /** Optional trailing actions (a link to the record, …). */\n actions?: ReactNode;\n /**\n * Rendered above the fields — the card's equivalent of a leading column.\n *\n * A selection box goes here rather than beside the actions because it is not\n * an action on the record: it decides whether the record is *in the set* the\n * actions will run over, and putting the two in one row reads as a third\n * button.\n */\n leading?: ReactNode;\n className?: string;\n}\n\n/**\n * A record pivoted from a row into a label/value stack. This is the narrow\n * viewport form of a table row: at phone widths a horizontal scroll hides most\n * columns, whereas stacking keeps every visible column readable.\n */\nexport function EntityRecordCard({\n columns,\n renderCell,\n actions,\n leading,\n className,\n}: EntityRecordCardProps) {\n return (\n <div\n className={cn(\n 'rounded-xl border border-border bg-surface-elevated p-s text-content shadow-edge',\n className,\n )}\n >\n {leading && <div className=\"mb-2xs flex\">{leading}</div>}\n <dl className=\"flex flex-col gap-2xs\">\n {columns.map(column => (\n <div\n key={column.name}\n className=\"flex items-baseline justify-between gap-2xs\"\n >\n <dt className=\"tracking-wide text-step-xs text-content-muted uppercase\">\n {column.label}\n </dt>\n <dd className=\"text-right text-step-sm\">{renderCell(column)}</dd>\n </div>\n ))}\n </dl>\n {actions && <div className=\"mt-2xs flex justify-end\">{actions}</div>}\n </div>\n );\n}\n"],"names":["cn","EntityRecordCard","columns","renderCell","actions","leading","className","div","dl","map","column","dt","label","dd","name"],"mappings":";AAEA,SAASA,EAAE,QAAQ,oBAAoB;AA0BvC;;;;CAIC,GACD,OAAO,SAASC,iBAAiB,EAC/BC,OAAO,EACPC,UAAU,EACVC,OAAO,EACPC,OAAO,EACPC,SAAS,EACa;IACtB,qBACE,MAACC;QACCD,WAAWN,GACT,oFACAM;;YAGDD,yBAAW,KAACE;gBAAID,WAAU;0BAAeD;;0BAC1C,KAACG;gBAAGF,WAAU;0BACXJ,QAAQO,GAAG,CAACC,CAAAA,uBACX,MAACH;wBAECD,WAAU;;0CAEV,KAACK;gCAAGL,WAAU;0CACXI,OAAOE,KAAK;;0CAEf,KAACC;gCAAGP,WAAU;0CAA2BH,WAAWO;;;uBAN/CA,OAAOI,IAAI;;YAUrBV,yBAAW,KAACG;gBAAID,WAAU;0BAA2BF;;;;AAG5D"}
1
+ {"version":3,"sources":["../../../../src/ui/molecules/entity-record-card/entity-record-card.tsx"],"sourcesContent":["import { type ReactNode, useId } from 'react';\n\nimport { cn } from '../../utils/cn.js';\n\n/** One line of a card: a member's label and its value. */\nexport interface EntityRecordCardMeta {\n key: string;\n label: ReactNode;\n value: ReactNode;\n}\n\nexport interface EntityRecordCardProps {\n /**\n * The record's heading — what it is read as, usually a link to it. A link\n * here is stretched over the whole card, so the card is one target.\n */\n title: ReactNode;\n /** A line under the heading. */\n subtitle?: ReactNode;\n /** Short values beside the heading — a status. */\n badges?: readonly { key: string; value: ReactNode }[];\n /** The record's other members, as a description list. */\n meta: readonly EntityRecordCardMeta[];\n /**\n * Above the heading: a selection box. It is not an action on the record —\n * it decides whether the record is *in the set* the actions run over — so it\n * does not sit with them.\n */\n leading?: ReactNode;\n /** Above the heading, at the end: the record's menu. */\n actions?: ReactNode;\n className?: string;\n}\n\n/**\n * A record pivoted from a row into a card: the narrow form of a table row,\n * where a horizontal scroll would hide most columns.\n *\n * An `article` named by its `h3`, so a reader can move card by card with the\n * heading keys and hears what each record is. The title's link is stretched\n * over the card; the selection box and the menu sit above it, so they stay\n * their own targets.\n */\nexport function EntityRecordCard({\n title,\n subtitle,\n badges = [],\n meta,\n leading,\n actions,\n className,\n}: EntityRecordCardProps) {\n const titleId = useId();\n\n return (\n <article\n aria-labelledby={titleId}\n className={cn(\n 'relative rounded-xl border border-border bg-surface-elevated p-s text-content shadow-edge focus-within:border-primary',\n className,\n )}\n >\n {(leading !== undefined || actions !== undefined) && (\n <div className=\"relative z-1 mb-2xs flex items-center justify-between gap-2xs\">\n <div className=\"flex\">{leading}</div>\n <div className=\"flex\">{actions}</div>\n </div>\n )}\n <div className=\"flex flex-wrap items-baseline justify-between gap-2xs\">\n <h3\n id={titleId}\n className=\"m-0 [&_a]:after:inset-0 text-step-0 font-semibold [&_a]:after:absolute [&_a]:after:content-['']\"\n >\n {title}\n </h3>\n {badges.length > 0 && (\n <div className=\"flex flex-wrap gap-3xs\">\n {badges.map(badge => (\n <span\n key={badge.key}\n className=\"rounded-full border border-border px-2xs text-step-sm\"\n >\n {badge.value}\n </span>\n ))}\n </div>\n )}\n </div>\n {subtitle !== undefined && (\n <p className=\"m-0 text-step-sm text-content-muted\">{subtitle}</p>\n )}\n {meta.length > 0 && (\n <dl className=\"mt-2xs flex flex-col gap-2xs\">\n {meta.map(line => (\n <div\n key={line.key}\n className=\"flex items-baseline justify-between gap-2xs\"\n >\n <dt className=\"tracking-wide text-step-xs text-content-muted uppercase\">\n {line.label}\n </dt>\n <dd className=\"m-0 text-right text-step-sm\">{line.value}</dd>\n </div>\n ))}\n </dl>\n )}\n </article>\n );\n}\n"],"names":["useId","cn","EntityRecordCard","title","subtitle","badges","meta","leading","actions","className","titleId","article","aria-labelledby","undefined","div","h3","id","length","map","badge","span","value","key","p","dl","line","dt","label","dd"],"mappings":";AAAA,SAAyBA,KAAK,QAAQ,QAAQ;AAE9C,SAASC,EAAE,QAAQ,oBAAoB;AAgCvC;;;;;;;;CAQC,GACD,OAAO,SAASC,iBAAiB,EAC/BC,KAAK,EACLC,QAAQ,EACRC,SAAS,EAAE,EACXC,IAAI,EACJC,OAAO,EACPC,OAAO,EACPC,SAAS,EACa;IACtB,MAAMC,UAAUV;IAEhB,qBACE,MAACW;QACCC,mBAAiBF;QACjBD,WAAWR,GACT,yHACAQ;;YAGAF,CAAAA,YAAYM,aAAaL,YAAYK,SAAQ,mBAC7C,MAACC;gBAAIL,WAAU;;kCACb,KAACK;wBAAIL,WAAU;kCAAQF;;kCACvB,KAACO;wBAAIL,WAAU;kCAAQD;;;;0BAG3B,MAACM;gBAAIL,WAAU;;kCACb,KAACM;wBACCC,IAAIN;wBACJD,WAAU;kCAETN;;oBAEFE,OAAOY,MAAM,GAAG,mBACf,KAACH;wBAAIL,WAAU;kCACZJ,OAAOa,GAAG,CAACC,CAAAA,sBACV,KAACC;gCAECX,WAAU;0CAETU,MAAME,KAAK;+BAHPF,MAAMG,GAAG;;;;YASvBlB,aAAaS,2BACZ,KAACU;gBAAEd,WAAU;0BAAuCL;;YAErDE,KAAKW,MAAM,GAAG,mBACb,KAACO;gBAAGf,WAAU;0BACXH,KAAKY,GAAG,CAACO,CAAAA,qBACR,MAACX;wBAECL,WAAU;;0CAEV,KAACiB;gCAAGjB,WAAU;0CACXgB,KAAKE,KAAK;;0CAEb,KAACC;gCAAGnB,WAAU;0CAA+BgB,KAAKJ,KAAK;;;uBANlDI,KAAKH,GAAG;;;;AAa3B"}
@@ -1,10 +1,16 @@
1
- import { type Entity, type EntityFieldDescriptor, type FilterGroup } from '@entifix/core';
1
+ import { type Entity, type EntityFacetCounts, type EntityFieldDescriptor, type FilterGroup } from '@entifix/core';
2
2
  export interface FilterBuilderProps<TEntity extends Entity> {
3
3
  /** Filterable members, already resolved from the entity metadata. */
4
4
  descriptors: readonly EntityFieldDescriptor[];
5
5
  /** The filtering currently applied, used to seed the rows. */
6
6
  value?: FilterGroup<TEntity>;
7
7
  onChange: (filtering: FilterGroup<TEntity>) => void;
8
+ /**
9
+ * How many records hold each value, by member — shown beside an enum's or a
10
+ * boolean's choices, so a reader sees what a choice would keep before
11
+ * applying it ([ADR 0012](../../../../../../../docs/adr/0012-facet-counts-are-a-port-of-their-own.md)).
12
+ */
13
+ facets?: EntityFacetCounts;
8
14
  }
9
15
  /**
10
16
  * Builds an `EntityFiltering` value from entity metadata: the member list, the
@@ -15,5 +21,5 @@ export interface FilterBuilderProps<TEntity extends Entity> {
15
21
  * feeds a load request: emitting per keystroke would put one HTTP request on
16
22
  * the wire per character typed.
17
23
  */
18
- export declare function FilterBuilder<TEntity extends Entity>({ descriptors, value: applied, onChange, }: FilterBuilderProps<TEntity>): import("react").JSX.Element;
24
+ export declare function FilterBuilder<TEntity extends Entity>({ descriptors, value: applied, onChange, facets, }: FilterBuilderProps<TEntity>): import("react").JSX.Element;
19
25
  //# sourceMappingURL=filter-builder.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"filter-builder.d.ts","sourceRoot":"","sources":["../../../../src/ui/molecules/filter-builder/filter-builder.tsx"],"names":[],"mappings":"AAEA,OAAO,EACL,KAAK,MAAM,EACX,KAAK,qBAAqB,EAE1B,KAAK,WAAW,EAMjB,MAAM,eAAe,CAAC;AA+IvB,MAAM,WAAW,kBAAkB,CAAC,OAAO,SAAS,MAAM;IACxD,qEAAqE;IACrE,WAAW,EAAE,SAAS,qBAAqB,EAAE,CAAC;IAC9C,8DAA8D;IAC9D,KAAK,CAAC,EAAE,WAAW,CAAC,OAAO,CAAC,CAAC;IAC7B,QAAQ,EAAE,CAAC,SAAS,EAAE,WAAW,CAAC,OAAO,CAAC,KAAK,IAAI,CAAC;CACrD;AAED;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAAC,OAAO,SAAS,MAAM,EAAE,EACpD,WAAW,EACX,KAAK,EAAE,OAAO,EACd,QAAQ,GACT,EAAE,kBAAkB,CAAC,OAAO,CAAC,+BA+L7B"}
1
+ {"version":3,"file":"filter-builder.d.ts","sourceRoot":"","sources":["../../../../src/ui/molecules/filter-builder/filter-builder.tsx"],"names":[],"mappings":"AAEA,OAAO,EACL,KAAK,MAAM,EACX,KAAK,iBAAiB,EAEtB,KAAK,qBAAqB,EAE1B,KAAK,WAAW,EAMjB,MAAM,eAAe,CAAC;AA+IvB,MAAM,WAAW,kBAAkB,CAAC,OAAO,SAAS,MAAM;IACxD,qEAAqE;IACrE,WAAW,EAAE,SAAS,qBAAqB,EAAE,CAAC;IAC9C,8DAA8D;IAC9D,KAAK,CAAC,EAAE,WAAW,CAAC,OAAO,CAAC,CAAC;IAC7B,QAAQ,EAAE,CAAC,SAAS,EAAE,WAAW,CAAC,OAAO,CAAC,KAAK,IAAI,CAAC;IACpD;;;;OAIG;IACH,MAAM,CAAC,EAAE,iBAAiB,CAAC;CAC5B;AAED;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAAC,OAAO,SAAS,MAAM,EAAE,EACpD,WAAW,EACX,KAAK,EAAE,OAAO,EACd,QAAQ,EACR,MAAM,GACP,EAAE,kBAAkB,CAAC,OAAO,CAAC,+BAgM7B"}
@@ -98,7 +98,7 @@ function coerce(raw, type) {
98
98
  * Editing is a draft. `onChange` fires only on **Apply**, because the value
99
99
  * feeds a load request: emitting per keystroke would put one HTTP request on
100
100
  * the wire per character typed.
101
- */ export function FilterBuilder({ descriptors, value: applied, onChange }) {
101
+ */ export function FilterBuilder({ descriptors, value: applied, onChange, facets }) {
102
102
  var _ref;
103
103
  const t = useT();
104
104
  const idPrefix = useId();
@@ -218,6 +218,7 @@ function coerce(raw, type) {
218
218
  }),
219
219
  arity !== 'none' && /*#__PURE__*/ _jsx(FilterValueInput, {
220
220
  descriptor: descriptor,
221
+ counts: facets == null ? void 0 : facets[descriptor.name],
221
222
  arity: arity,
222
223
  value: draft.value,
223
224
  end: draft.end,
@@ -276,9 +277,17 @@ function coerce(raw, type) {
276
277
  ]
277
278
  });
278
279
  }
279
- /** The value control the member's type calls for. */ function FilterValueInput({ descriptor, arity, value, end, onValueChange, onEndChange }) {
280
+ /** The value control the member's type calls for. */ function FilterValueInput({ descriptor, counts, arity, value, end, onValueChange, onEndChange }) {
280
281
  const t = useT();
281
282
  const enumLabel = useEnumLabel();
283
+ /** A choice's label, with how many records hold it when that is known. */ const counted = (label, option)=>{
284
+ var _counts_find;
285
+ const count = counts == null ? void 0 : (_counts_find = counts.find((entry)=>String(entry.value) === option)) == null ? void 0 : _counts_find.count;
286
+ return count === undefined ? label : t('filter.withCount', {
287
+ label,
288
+ count
289
+ });
290
+ };
282
291
  if (descriptor.type === 'boolean') {
283
292
  return /*#__PURE__*/ _jsxs(Select, {
284
293
  "aria-label": t('filter.value'),
@@ -291,11 +300,11 @@ function coerce(raw, type) {
291
300
  }),
292
301
  /*#__PURE__*/ _jsx("option", {
293
302
  value: "true",
294
- children: t('value.yes')
303
+ children: counted(t('value.yes'), 'true')
295
304
  }),
296
305
  /*#__PURE__*/ _jsx("option", {
297
306
  value: "false",
298
- children: t('value.no')
307
+ children: counted(t('value.no'), 'false')
299
308
  })
300
309
  ]
301
310
  });
@@ -312,7 +321,7 @@ function coerce(raw, type) {
312
321
  }),
313
322
  descriptor.enumValues.map((option)=>/*#__PURE__*/ _jsx("option", {
314
323
  value: option,
315
- children: enumLabel(descriptor, option)
324
+ children: counted(enumLabel(descriptor, option), option)
316
325
  }, option))
317
326
  ]
318
327
  });