@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
@@ -1 +1 @@
1
- {"version":3,"file":"breadcrumbs.d.ts","sourceRoot":"","sources":["../../../../src/ui/molecules/breadcrumbs/breadcrumbs.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,wBAAwB,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAKjE,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,gBAAiB,SAAQ,IAAI,CAC5C,wBAAwB,CAAC,KAAK,CAAC,EAC/B,UAAU,CACX;IACC,KAAK,EAAE,cAAc,EAAE,CAAC;IACxB,4BAA4B;IAC5B,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB;;;;OAIG;IACH;;;;;OAKG;IACH,UAAU,CAAC,EAAE,CACX,IAAI,EAAE,QAAQ,CAAC,cAAc,CAAC,GAAG;QAAE,SAAS,EAAE,MAAM,CAAA;KAAE,KACnD,SAAS,CAAC;CAChB;AAKD,+EAA+E;AAC/E,wBAAgB,WAAW,CAAC,EAC1B,KAAK,EACL,SAAe,EACf,UAAU,EACV,SAAS,EACT,GAAG,KAAK,EACT,EAAE,gBAAgB,+BA4ClB"}
1
+ {"version":3,"file":"breadcrumbs.d.ts","sourceRoot":"","sources":["../../../../src/ui/molecules/breadcrumbs/breadcrumbs.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,wBAAwB,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAIjE,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,gBAAiB,SAAQ,IAAI,CAC5C,wBAAwB,CAAC,KAAK,CAAC,EAC/B,UAAU,CACX;IACC,KAAK,EAAE,cAAc,EAAE,CAAC;IACxB;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,4BAA4B;IAC5B,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB;;;;OAIG;IACH;;;;;OAKG;IACH,UAAU,CAAC,EAAE,CACX,IAAI,EAAE,QAAQ,CAAC,cAAc,CAAC,GAAG;QAAE,SAAS,EAAE,MAAM,CAAA;KAAE,KACnD,SAAS,CAAC;CAChB;AAMD;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,EAC1B,KAAK,EACL,KAAoB,EACpB,SAAe,EACf,UAAU,EACV,SAAS,EACT,GAAG,KAAK,EACT,EAAE,gBAAgB,+BA0ClB"}
@@ -1,20 +1,22 @@
1
- 'use client';
2
1
  import { _ as _extends } from "@swc/helpers/_/_extends";
3
2
  import { _ as _object_without_properties_loose } from "@swc/helpers/_/_object_without_properties_loose";
4
3
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
5
- import { useT } from '../../../i18n/index.js';
6
4
  import { cn } from '../../utils/cn.js';
7
- /** How a breadcrumb link looks, wherever it is rendered from. */ const LINK_CLASS = 'focus-ring rounded-sm hover:text-content hover:underline';
8
- /** Accessible breadcrumb trail. Presentational only — no routing knowledge. */ export function Breadcrumbs(_0) {
9
- let { items, separator = '/', renderLink, className } = _0, props = _object_without_properties_loose(_0, [
5
+ /** How a breadcrumb link looks, wherever it is rendered from. */ const LINK_CLASS = 'focus-ring inline-flex min-h-(--target-min) min-w-(--target-min) items-center justify-center rounded-sm hover:text-content hover:underline';
6
+ /**
7
+ * Accessible breadcrumb trail. Presentational only — no routing knowledge, and
8
+ * no hooks: every label arrives as a prop, so a server component renders it
9
+ * and a storefront never pays a client boundary for its trail.
10
+ */ export function Breadcrumbs(_0) {
11
+ let { items, label = 'Breadcrumb', separator = '/', renderLink, className } = _0, props = _object_without_properties_loose(_0, [
10
12
  "items",
13
+ "label",
11
14
  "separator",
12
15
  "renderLink",
13
16
  "className"
14
17
  ]);
15
- const t = useT();
16
18
  return /*#__PURE__*/ _jsx("nav", _extends({
17
- "aria-label": t('breadcrumbs.label'),
19
+ "aria-label": label,
18
20
  className: cn('text-step-sm text-content-muted', className)
19
21
  }, props, {
20
22
  children: /*#__PURE__*/ _jsx("ol", {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/ui/molecules/breadcrumbs/breadcrumbs.tsx"],"sourcesContent":["'use client';\n\nimport type { ComponentPropsWithoutRef, ReactNode } from 'react';\n\nimport { useT } from '../../../i18n/index.js';\nimport { cn } from '../../utils/cn.js';\n\nexport interface BreadcrumbItem {\n label: string;\n href?: string;\n}\n\nexport interface BreadcrumbsProps extends Omit<\n ComponentPropsWithoutRef<'nav'>,\n 'children'\n> {\n items: BreadcrumbItem[];\n /** Glyph between crumbs. */\n separator?: ReactNode;\n /**\n * Optional custom link renderer for a crumb that has an `href` and is not the\n * last one — lets a Next shell inject `<Link>` for client-side navigation.\n * Falls back to a plain `<a>`.\n */\n /**\n * Routing escape hatch. It receives `className` alongside the item and must\n * spread it onto whatever it renders — the design system owns how a\n * breadcrumb link looks, including its focus ring, and a host that supplied\n * only an href silently lost both.\n */\n renderLink?: (\n item: Required<BreadcrumbItem> & { className: string },\n ) => ReactNode;\n}\n\n/** How a breadcrumb link looks, wherever it is rendered from. */\nconst LINK_CLASS = 'focus-ring rounded-sm hover:text-content hover:underline';\n\n/** Accessible breadcrumb trail. Presentational only — no routing knowledge. */\nexport function Breadcrumbs({\n items,\n separator = '/',\n renderLink,\n className,\n ...props\n}: BreadcrumbsProps) {\n const t = useT();\n\n return (\n <nav\n aria-label={t('breadcrumbs.label')}\n className={cn('text-step-sm text-content-muted', className)}\n {...props}\n >\n <ol className=\"flex flex-wrap items-center gap-2xs\">\n {items.map((item, index) => {\n const isLast = index === items.length - 1;\n const linkable = item.href !== undefined && !isLast;\n return (\n <li\n key={`${item.label}-${index}`}\n className=\"flex items-center gap-2xs\"\n >\n {linkable ? (\n renderLink ? (\n renderLink({\n ...(item as Required<BreadcrumbItem>),\n className: LINK_CLASS,\n })\n ) : (\n <a href={item.href} className={LINK_CLASS}>\n {item.label}\n </a>\n )\n ) : (\n <span\n aria-current={isLast ? 'page' : undefined}\n className={cn(isLast && 'font-medium text-content')}\n >\n {item.label}\n </span>\n )}\n {!isLast && <span aria-hidden=\"true\">{separator}</span>}\n </li>\n );\n })}\n </ol>\n </nav>\n );\n}\n"],"names":["useT","cn","LINK_CLASS","Breadcrumbs","items","separator","renderLink","className","props","t","nav","aria-label","ol","map","item","index","isLast","length","linkable","href","undefined","li","a","label","span","aria-current","aria-hidden"],"mappings":"AAAA;;;;AAIA,SAASA,IAAI,QAAQ,yBAAyB;AAC9C,SAASC,EAAE,QAAQ,oBAAoB;AA8BvC,+DAA+D,GAC/D,MAAMC,aAAa;AAEnB,6EAA6E,GAC7E,OAAO,SAASC,YAAY,EAMT;QANS,EAC1BC,KAAK,EACLC,YAAY,GAAG,EACfC,UAAU,EACVC,SAAS,EAEQ,OADdC;;;;;;IAEH,MAAMC,IAAIT;IAEV,qBACE,KAACU;QACCC,cAAYF,EAAE;QACdF,WAAWN,GAAG,mCAAmCM;OAC7CC;kBAEJ,cAAA,KAACI;YAAGL,WAAU;sBACXH,MAAMS,GAAG,CAAC,CAACC,MAAMC;gBAChB,MAAMC,SAASD,UAAUX,MAAMa,MAAM,GAAG;gBACxC,MAAMC,WAAWJ,KAAKK,IAAI,KAAKC,aAAa,CAACJ;gBAC7C,qBACE,MAACK;oBAECd,WAAU;;wBAETW,WACCZ,aACEA,WAAW,aACLQ;4BACJP,WAAWL;4CAGb,KAACoB;4BAAEH,MAAML,KAAKK,IAAI;4BAAEZ,WAAWL;sCAC5BY,KAAKS,KAAK;2CAIf,KAACC;4BACCC,gBAAcT,SAAS,SAASI;4BAChCb,WAAWN,GAAGe,UAAU;sCAEvBF,KAAKS,KAAK;;wBAGd,CAACP,wBAAU,KAACQ;4BAAKE,eAAY;sCAAQrB;;;mBAtBjC,GAAGS,KAAKS,KAAK,CAAC,CAAC,EAAER,OAAO;YAyBnC;;;AAIR"}
1
+ {"version":3,"sources":["../../../../src/ui/molecules/breadcrumbs/breadcrumbs.tsx"],"sourcesContent":["import type { ComponentPropsWithoutRef, ReactNode } from 'react';\n\nimport { cn } from '../../utils/cn.js';\n\nexport interface BreadcrumbItem {\n label: string;\n href?: string;\n}\n\nexport interface BreadcrumbsProps extends Omit<\n ComponentPropsWithoutRef<'nav'>,\n 'children'\n> {\n items: BreadcrumbItem[];\n /**\n * The trail's accessible name. English when omitted; a host with a catalog\n * passes its own (the controls catalog's `breadcrumbs.label`).\n */\n label?: string;\n /** Glyph between crumbs. */\n separator?: ReactNode;\n /**\n * Optional custom link renderer for a crumb that has an `href` and is not the\n * last one — lets a Next shell inject `<Link>` for client-side navigation.\n * Falls back to a plain `<a>`.\n */\n /**\n * Routing escape hatch. It receives `className` alongside the item and must\n * spread it onto whatever it renders — the design system owns how a\n * breadcrumb link looks, including its focus ring, and a host that supplied\n * only an href silently lost both.\n */\n renderLink?: (\n item: Required<BreadcrumbItem> & { className: string },\n ) => ReactNode;\n}\n\n/** How a breadcrumb link looks, wherever it is rendered from. */\nconst LINK_CLASS =\n 'focus-ring inline-flex min-h-(--target-min) min-w-(--target-min) items-center justify-center rounded-sm hover:text-content hover:underline';\n\n/**\n * Accessible breadcrumb trail. Presentational only — no routing knowledge, and\n * no hooks: every label arrives as a prop, so a server component renders it\n * and a storefront never pays a client boundary for its trail.\n */\nexport function Breadcrumbs({\n items,\n label = 'Breadcrumb',\n separator = '/',\n renderLink,\n className,\n ...props\n}: BreadcrumbsProps) {\n return (\n <nav\n aria-label={label}\n className={cn('text-step-sm text-content-muted', className)}\n {...props}\n >\n <ol className=\"flex flex-wrap items-center gap-2xs\">\n {items.map((item, index) => {\n const isLast = index === items.length - 1;\n const linkable = item.href !== undefined && !isLast;\n return (\n <li\n key={`${item.label}-${index}`}\n className=\"flex items-center gap-2xs\"\n >\n {linkable ? (\n renderLink ? (\n renderLink({\n ...(item as Required<BreadcrumbItem>),\n className: LINK_CLASS,\n })\n ) : (\n <a href={item.href} className={LINK_CLASS}>\n {item.label}\n </a>\n )\n ) : (\n <span\n aria-current={isLast ? 'page' : undefined}\n className={cn(isLast && 'font-medium text-content')}\n >\n {item.label}\n </span>\n )}\n {!isLast && <span aria-hidden=\"true\">{separator}</span>}\n </li>\n );\n })}\n </ol>\n </nav>\n );\n}\n"],"names":["cn","LINK_CLASS","Breadcrumbs","items","label","separator","renderLink","className","props","nav","aria-label","ol","map","item","index","isLast","length","linkable","href","undefined","li","a","span","aria-current","aria-hidden"],"mappings":";;;AAEA,SAASA,EAAE,QAAQ,oBAAoB;AAmCvC,+DAA+D,GAC/D,MAAMC,aACJ;AAEF;;;;CAIC,GACD,OAAO,SAASC,YAAY,EAOT;QAPS,EAC1BC,KAAK,EACLC,QAAQ,YAAY,EACpBC,YAAY,GAAG,EACfC,UAAU,EACVC,SAAS,EAEQ,OADdC;;;;;;;IAEH,qBACE,KAACC;QACCC,cAAYN;QACZG,WAAWP,GAAG,mCAAmCO;OAC7CC;kBAEJ,cAAA,KAACG;YAAGJ,WAAU;sBACXJ,MAAMS,GAAG,CAAC,CAACC,MAAMC;gBAChB,MAAMC,SAASD,UAAUX,MAAMa,MAAM,GAAG;gBACxC,MAAMC,WAAWJ,KAAKK,IAAI,KAAKC,aAAa,CAACJ;gBAC7C,qBACE,MAACK;oBAECb,WAAU;;wBAETU,WACCX,aACEA,WAAW,aACLO;4BACJN,WAAWN;4CAGb,KAACoB;4BAAEH,MAAML,KAAKK,IAAI;4BAAEX,WAAWN;sCAC5BY,KAAKT,KAAK;2CAIf,KAACkB;4BACCC,gBAAcR,SAAS,SAASI;4BAChCZ,WAAWP,GAAGe,UAAU;sCAEvBF,KAAKT,KAAK;;wBAGd,CAACW,wBAAU,KAACO;4BAAKE,eAAY;sCAAQnB;;;mBAtBjC,GAAGQ,KAAKT,KAAK,CAAC,CAAC,EAAEU,OAAO;YAyBnC;;;AAIR"}
@@ -1 +1 @@
1
- {"version":3,"file":"bulk-action-bar.d.ts","sourceRoot":"","sources":["../../../../src/ui/molecules/bulk-action-bar/bulk-action-bar.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAMvD,MAAM,WAAW,kBAAkB;IACjC,4CAA4C;IAC5C,KAAK,EAAE,MAAM,CAAC;IACd;;;;;OAKG;IACH,QAAQ,EAAE,SAAS,iBAAiB,EAAE,CAAC;IACvC;;;;;;;OAOG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,mBAAmB,CAAC,EAAE,MAAM,IAAI,CAAC;IACjC,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB;;;;;;;OAOG;IACH,SAAS,EAAE,CAAC,OAAO,EAAE,iBAAiB,KAAK,IAAI,CAAC;IAChD,gDAAgD;IAChD,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAAC,EAC5B,KAAK,EACL,QAAQ,EACR,aAAa,EACb,mBAAmB,EACnB,OAAO,EACP,SAAS,EACT,IAAY,EACZ,SAAS,GACV,EAAE,kBAAkB,+BA2DpB"}
1
+ {"version":3,"file":"bulk-action-bar.d.ts","sourceRoot":"","sources":["../../../../src/ui/molecules/bulk-action-bar/bulk-action-bar.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAOvD,MAAM,WAAW,kBAAkB;IACjC,4CAA4C;IAC5C,KAAK,EAAE,MAAM,CAAC;IACd;;;;;OAKG;IACH,QAAQ,EAAE,SAAS,iBAAiB,EAAE,CAAC;IACvC;;;;;;;OAOG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,mBAAmB,CAAC,EAAE,MAAM,IAAI,CAAC;IACjC,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB;;;;;;;OAOG;IACH,SAAS,EAAE,CAAC,OAAO,EAAE,iBAAiB,KAAK,IAAI,CAAC;IAChD,gDAAgD;IAChD,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAAC,EAC5B,KAAK,EACL,QAAQ,EACR,aAAa,EACb,mBAAmB,EACnB,OAAO,EACP,SAAS,EACT,IAAY,EACZ,SAAS,GACV,EAAE,kBAAkB,+BAmDpB"}
@@ -3,6 +3,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { useT, useTranslateKey } from '../../../i18n/index.js';
4
4
  import { Button } from '../../atoms/button/index.js';
5
5
  import { cn } from '../../utils/cn.js';
6
+ import { ActionBar, itemsForUseCases } from '../action-bar/index.js';
6
7
  /**
7
8
  * The bar that appears once rows are selected: what is selected, what can be
8
9
  * done to it, and the way out.
@@ -37,16 +38,13 @@ import { cn } from '../../utils/cn.js';
37
38
  count: matchingTotal
38
39
  })
39
40
  }),
40
- useCases.map((descriptor)=>{
41
- var _descriptor_confirm;
42
- return /*#__PURE__*/ _jsx(Button, {
43
- type: "button",
44
- variant: ((_descriptor_confirm = descriptor.confirm) == null ? void 0 : _descriptor_confirm.tone) === 'destructive' ? 'destructive' : 'secondary',
45
- size: "sm",
46
- disabled: busy,
47
- onClick: ()=>onUseCase(descriptor),
48
- children: translateKey(descriptor.labelKey)
49
- }, descriptor.key);
41
+ useCases.length > 0 && /*#__PURE__*/ _jsx(ActionBar, {
42
+ // A size container takes no width from its content, so in a bar
43
+ // that wraps it would shrink to nothing and its buttons would spill
44
+ // over Clear. A basis makes the bar wrap first.
45
+ className: "basis-64",
46
+ surface: "bulk-bar",
47
+ items: itemsForUseCases(useCases, translateKey, onUseCase, busy)
50
48
  }),
51
49
  /*#__PURE__*/ _jsx(Button, {
52
50
  type: "button",
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/ui/molecules/bulk-action-bar/bulk-action-bar.tsx"],"sourcesContent":["'use client';\n\nimport type { UseCaseDescriptor } from '@entifix/core';\n\nimport { useT, useTranslateKey } from '../../../i18n/index.js';\nimport { Button } from '../../atoms/button/index.js';\nimport { cn } from '../../utils/cn.js';\n\nexport interface BulkActionBarProps {\n /** How many rows the action would touch. */\n count: number;\n /**\n * The collection-bound verbs this caller may run, already filtered against\n * the verified principal by the service. The bar renders what it is given and\n * re-checks nothing — hiding an action protects nothing, the route guard is\n * the enforcement.\n */\n useCases: readonly UseCaseDescriptor[];\n /**\n * Offered only when the selection is a page's worth of ids *and* more rows\n * match than are shown. Absent means there is no larger set to escalate to.\n *\n * It is a **separate affordance carrying the count**, never a widening of the\n * header checkbox: \"select all on this page\" and \"select all 3.200 matching\"\n * are different actions and the second has to be chosen deliberately.\n */\n matchingTotal?: number;\n onSelectAllMatching?: () => void;\n onClear: () => void;\n /**\n * Hands back the descriptor it rendered, not just its key.\n *\n * The caller has to know whether the verb asked to be confirmed, and the bar\n * is already holding the answer. Passing the key alone forced a lookup back\n * into the same list — a branch for \"not found\" that cannot happen, since\n * every key here came from this array.\n */\n onUseCase: (useCase: UseCaseDescriptor) => void;\n /** Disables every verb while one is running. */\n busy?: boolean;\n className?: string;\n}\n\n/**\n * The bar that appears once rows are selected: what is selected, what can be\n * done to it, and the way out.\n *\n * It is `aria-live=\"polite\"` on the count rather than on the whole region — a\n * region that re-announces its buttons every time one more row is ticked is\n * noise, and the count is the only part that changed. `role=\"region\"` with a\n * name is what lets a screen-reader user jump to it at all, since it appears\n * without the focus moving.\n */\nexport function BulkActionBar({\n count,\n useCases,\n matchingTotal,\n onSelectAllMatching,\n onClear,\n onUseCase,\n busy = false,\n className,\n}: BulkActionBarProps) {\n const t = useT();\n const translateKey = useTranslateKey();\n\n return (\n <div\n role=\"region\"\n aria-label={t('bulk.barLabel')}\n data-testid=\"bulk-action-bar\"\n className={cn(\n 'flex flex-wrap items-center gap-2xs rounded-lg border border-border bg-surface-elevated px-s py-2xs',\n className,\n )}\n >\n <span aria-live=\"polite\" className=\"text-step-sm text-content\">\n {t('table.selectedCount', { count })}\n </span>\n\n {matchingTotal !== undefined && onSelectAllMatching && (\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n onClick={onSelectAllMatching}\n >\n {t('table.selectAllMatching', { count: matchingTotal })}\n </Button>\n )}\n\n {useCases.map(descriptor => (\n <Button\n key={descriptor.key}\n type=\"button\"\n variant={\n descriptor.confirm?.tone === 'destructive'\n ? 'destructive'\n : 'secondary'\n }\n size=\"sm\"\n disabled={busy}\n onClick={() => onUseCase(descriptor)}\n >\n {/* A descriptor's label is a *runtime* catalog key — the type system\n cannot see a typo here, a host's catalog check is what does. */}\n {translateKey(descriptor.labelKey)}\n </Button>\n ))}\n\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n disabled={busy}\n onClick={onClear}\n >\n {t('table.clearSelection')}\n </Button>\n </div>\n );\n}\n"],"names":["useT","useTranslateKey","Button","cn","BulkActionBar","count","useCases","matchingTotal","onSelectAllMatching","onClear","onUseCase","busy","className","t","translateKey","div","role","aria-label","data-testid","span","aria-live","undefined","type","variant","size","onClick","map","descriptor","confirm","tone","disabled","labelKey","key"],"mappings":"AAAA;;AAIA,SAASA,IAAI,EAAEC,eAAe,QAAQ,yBAAyB;AAC/D,SAASC,MAAM,QAAQ,8BAA8B;AACrD,SAASC,EAAE,QAAQ,oBAAoB;AAqCvC;;;;;;;;;CASC,GACD,OAAO,SAASC,cAAc,EAC5BC,KAAK,EACLC,QAAQ,EACRC,aAAa,EACbC,mBAAmB,EACnBC,OAAO,EACPC,SAAS,EACTC,OAAO,KAAK,EACZC,SAAS,EACU;IACnB,MAAMC,IAAIb;IACV,MAAMc,eAAeb;IAErB,qBACE,MAACc;QACCC,MAAK;QACLC,cAAYJ,EAAE;QACdK,eAAY;QACZN,WAAWT,GACT,uGACAS;;0BAGF,KAACO;gBAAKC,aAAU;gBAASR,WAAU;0BAChCC,EAAE,uBAAuB;oBAAER;gBAAM;;YAGnCE,kBAAkBc,aAAab,qCAC9B,KAACN;gBACCoB,MAAK;gBACLC,SAAQ;gBACRC,MAAK;gBACLC,SAASjB;0BAERK,EAAE,2BAA2B;oBAAER,OAAOE;gBAAc;;YAIxDD,SAASoB,GAAG,CAACC,CAAAA;oBAKRA;qCAJJ,KAACzB;oBAECoB,MAAK;oBACLC,SACEI,EAAAA,sBAAAA,WAAWC,OAAO,qBAAlBD,oBAAoBE,IAAI,MAAK,gBACzB,gBACA;oBAENL,MAAK;oBACLM,UAAUnB;oBACVc,SAAS,IAAMf,UAAUiB;8BAIxBb,aAAaa,WAAWI,QAAQ;mBAb5BJ,WAAWK,GAAG;;0BAiBvB,KAAC9B;gBACCoB,MAAK;gBACLC,SAAQ;gBACRC,MAAK;gBACLM,UAAUnB;gBACVc,SAAShB;0BAERI,EAAE;;;;AAIX"}
1
+ {"version":3,"sources":["../../../../src/ui/molecules/bulk-action-bar/bulk-action-bar.tsx"],"sourcesContent":["'use client';\n\nimport type { UseCaseDescriptor } from '@entifix/core';\n\nimport { useT, useTranslateKey } from '../../../i18n/index.js';\nimport { Button } from '../../atoms/button/index.js';\nimport { cn } from '../../utils/cn.js';\nimport { ActionBar, itemsForUseCases } from '../action-bar/index.js';\n\nexport interface BulkActionBarProps {\n /** How many rows the action would touch. */\n count: number;\n /**\n * The collection-bound verbs this caller may run, already filtered against\n * the verified principal by the service. The bar renders what it is given and\n * re-checks nothing — hiding an action protects nothing, the route guard is\n * the enforcement.\n */\n useCases: readonly UseCaseDescriptor[];\n /**\n * Offered only when the selection is a page's worth of ids *and* more rows\n * match than are shown. Absent means there is no larger set to escalate to.\n *\n * It is a **separate affordance carrying the count**, never a widening of the\n * header checkbox: \"select all on this page\" and \"select all 3.200 matching\"\n * are different actions and the second has to be chosen deliberately.\n */\n matchingTotal?: number;\n onSelectAllMatching?: () => void;\n onClear: () => void;\n /**\n * Hands back the descriptor it rendered, not just its key.\n *\n * The caller has to know whether the verb asked to be confirmed, and the bar\n * is already holding the answer. Passing the key alone forced a lookup back\n * into the same list — a branch for \"not found\" that cannot happen, since\n * every key here came from this array.\n */\n onUseCase: (useCase: UseCaseDescriptor) => void;\n /** Disables every verb while one is running. */\n busy?: boolean;\n className?: string;\n}\n\n/**\n * The bar that appears once rows are selected: what is selected, what can be\n * done to it, and the way out.\n *\n * It is `aria-live=\"polite\"` on the count rather than on the whole region — a\n * region that re-announces its buttons every time one more row is ticked is\n * noise, and the count is the only part that changed. `role=\"region\"` with a\n * name is what lets a screen-reader user jump to it at all, since it appears\n * without the focus moving.\n */\nexport function BulkActionBar({\n count,\n useCases,\n matchingTotal,\n onSelectAllMatching,\n onClear,\n onUseCase,\n busy = false,\n className,\n}: BulkActionBarProps) {\n const t = useT();\n const translateKey = useTranslateKey();\n\n return (\n <div\n role=\"region\"\n aria-label={t('bulk.barLabel')}\n data-testid=\"bulk-action-bar\"\n className={cn(\n 'flex flex-wrap items-center gap-2xs rounded-lg border border-border bg-surface-elevated px-s py-2xs',\n className,\n )}\n >\n <span aria-live=\"polite\" className=\"text-step-sm text-content\">\n {t('table.selectedCount', { count })}\n </span>\n\n {matchingTotal !== undefined && onSelectAllMatching && (\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n onClick={onSelectAllMatching}\n >\n {t('table.selectAllMatching', { count: matchingTotal })}\n </Button>\n )}\n\n {useCases.length > 0 && (\n <ActionBar\n // A size container takes no width from its content, so in a bar\n // that wraps it would shrink to nothing and its buttons would spill\n // over Clear. A basis makes the bar wrap first.\n className=\"basis-64\"\n surface=\"bulk-bar\"\n items={itemsForUseCases(useCases, translateKey, onUseCase, busy)}\n />\n )}\n\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n disabled={busy}\n onClick={onClear}\n >\n {t('table.clearSelection')}\n </Button>\n </div>\n );\n}\n"],"names":["useT","useTranslateKey","Button","cn","ActionBar","itemsForUseCases","BulkActionBar","count","useCases","matchingTotal","onSelectAllMatching","onClear","onUseCase","busy","className","t","translateKey","div","role","aria-label","data-testid","span","aria-live","undefined","type","variant","size","onClick","length","surface","items","disabled"],"mappings":"AAAA;;AAIA,SAASA,IAAI,EAAEC,eAAe,QAAQ,yBAAyB;AAC/D,SAASC,MAAM,QAAQ,8BAA8B;AACrD,SAASC,EAAE,QAAQ,oBAAoB;AACvC,SAASC,SAAS,EAAEC,gBAAgB,QAAQ,yBAAyB;AAqCrE;;;;;;;;;CASC,GACD,OAAO,SAASC,cAAc,EAC5BC,KAAK,EACLC,QAAQ,EACRC,aAAa,EACbC,mBAAmB,EACnBC,OAAO,EACPC,SAAS,EACTC,OAAO,KAAK,EACZC,SAAS,EACU;IACnB,MAAMC,IAAIf;IACV,MAAMgB,eAAef;IAErB,qBACE,MAACgB;QACCC,MAAK;QACLC,cAAYJ,EAAE;QACdK,eAAY;QACZN,WAAWX,GACT,uGACAW;;0BAGF,KAACO;gBAAKC,aAAU;gBAASR,WAAU;0BAChCC,EAAE,uBAAuB;oBAAER;gBAAM;;YAGnCE,kBAAkBc,aAAab,qCAC9B,KAACR;gBACCsB,MAAK;gBACLC,SAAQ;gBACRC,MAAK;gBACLC,SAASjB;0BAERK,EAAE,2BAA2B;oBAAER,OAAOE;gBAAc;;YAIxDD,SAASoB,MAAM,GAAG,mBACjB,KAACxB;gBACC,gEAAgE;gBAChE,oEAAoE;gBACpE,gDAAgD;gBAChDU,WAAU;gBACVe,SAAQ;gBACRC,OAAOzB,iBAAiBG,UAAUQ,cAAcJ,WAAWC;;0BAI/D,KAACX;gBACCsB,MAAK;gBACLC,SAAQ;gBACRC,MAAK;gBACLK,UAAUlB;gBACVc,SAAShB;0BAERI,EAAE;;;;AAIX"}
@@ -22,9 +22,9 @@ export interface BulkResultProps {
22
22
  * because the user walks away believing the work is done. So both counts are
23
23
  * always stated, and every failure is named with its own reason.
24
24
  *
25
- * `role="status"`, not `role="alert"`: a partial failure is an outcome to read,
26
- * not an interruption, and `alert` on a list this long is hostile. The region
27
- * is `tabIndex={-1}` so the caller can move focus to it once the run ends,
25
+ * `role="alert"` when anything failed, `role="status"` when nothing did
26
+ * (ADR 0028): rows the user believes were written and were not are news that
27
+ * cannot wait its turn. The region is `tabIndex={-1}` so the caller can move focus to it once the run ends,
28
28
  * which is the only reliable way a keyboard user learns the result arrived.
29
29
  */
30
30
  export declare function BulkResult({ outcomes, labelFor, onRetryFailed, onDismiss, busy, className, }: BulkResultProps): import("react").JSX.Element;
@@ -13,9 +13,9 @@ import { cn } from '../../utils/cn.js';
13
13
  * because the user walks away believing the work is done. So both counts are
14
14
  * always stated, and every failure is named with its own reason.
15
15
  *
16
- * `role="status"`, not `role="alert"`: a partial failure is an outcome to read,
17
- * not an interruption, and `alert` on a list this long is hostile. The region
18
- * is `tabIndex={-1}` so the caller can move focus to it once the run ends,
16
+ * `role="alert"` when anything failed, `role="status"` when nothing did
17
+ * (ADR 0028): rows the user believes were written and were not are news that
18
+ * cannot wait its turn. The region is `tabIndex={-1}` so the caller can move focus to it once the run ends,
19
19
  * which is the only reliable way a keyboard user learns the result arrived.
20
20
  */ export function BulkResult({ outcomes, labelFor, onRetryFailed, onDismiss, busy = false, className }) {
21
21
  const t = useT();
@@ -23,7 +23,7 @@ import { cn } from '../../utils/cn.js';
23
23
  const failed = outcomes.filter((outcome)=>!outcome.ok);
24
24
  const succeeded = succeededCount(outcomes);
25
25
  return /*#__PURE__*/ _jsxs("div", {
26
- role: "status",
26
+ role: failed.length > 0 ? 'alert' : 'status',
27
27
  tabIndex: -1,
28
28
  "aria-label": t('bulk.resultLabel'),
29
29
  "data-testid": "bulk-result",
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/ui/molecules/bulk-result/bulk-result.tsx"],"sourcesContent":["'use client';\n\nimport {\n type BulkOutcome,\n type EntityId,\n failedIds,\n succeededCount,\n} from '@entifix/core';\n\nimport { useT, useTranslateKey } from '../../../i18n/index.js';\nimport { Button } from '../../atoms/button/index.js';\nimport { cn } from '../../utils/cn.js';\n\nexport interface BulkResultProps {\n outcomes: readonly BulkOutcome[];\n /**\n * How a failed row is named to the user. An id is not an answer to \"which\n * ones failed\" — the caller holds the rows and can render the same label the\n * table shows. Falls back to the id when the row is no longer on the page.\n */\n labelFor?: (id: EntityId) => string | undefined;\n /** Re-runs the failures **only**. Absent hides the affordance. */\n onRetryFailed?: (ids: EntityId[]) => void;\n onDismiss: () => void;\n busy?: boolean;\n className?: string;\n}\n\n/**\n * What a bulk action actually did, per row.\n *\n * The requirement this exists for: 40 selected, 3 fail. A single notice lies\n * whichever way it is written — as a failure it hides the 37 rows that were\n * written, and as a success it hides the 3 that were not, which is worse\n * because the user walks away believing the work is done. So both counts are\n * always stated, and every failure is named with its own reason.\n *\n * `role=\"status\"`, not `role=\"alert\"`: a partial failure is an outcome to read,\n * not an interruption, and `alert` on a list this long is hostile. The region\n * is `tabIndex={-1}` so the caller can move focus to it once the run ends,\n * which is the only reliable way a keyboard user learns the result arrived.\n */\nexport function BulkResult({\n outcomes,\n labelFor,\n onRetryFailed,\n onDismiss,\n busy = false,\n className,\n}: BulkResultProps) {\n const t = useT();\n const translateKey = useTranslateKey();\n\n const failed = outcomes.filter(outcome => !outcome.ok);\n const succeeded = succeededCount(outcomes);\n\n return (\n <div\n role=\"status\"\n tabIndex={-1}\n aria-label={t('bulk.resultLabel')}\n data-testid=\"bulk-result\"\n className={cn(\n 'flex flex-col gap-2xs rounded-lg border border-border bg-surface-elevated px-s py-2xs',\n className,\n )}\n >\n <div className=\"flex flex-wrap items-center gap-2xs\">\n <span className=\"text-step-sm text-content\">\n {t('bulk.succeeded', { count: succeeded })}\n </span>\n {failed.length > 0 && (\n <span className=\"text-step-sm text-danger\">\n {t('bulk.failed', { count: failed.length })}\n </span>\n )}\n {failed.length > 0 && onRetryFailed && (\n <Button\n type=\"button\"\n variant=\"secondary\"\n size=\"sm\"\n disabled={busy}\n onClick={() => onRetryFailed(failedIds(outcomes))}\n >\n {t('bulk.retryFailed')}\n </Button>\n )}\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n disabled={busy}\n onClick={onDismiss}\n >\n {t('bulk.dismiss')}\n </Button>\n </div>\n\n {failed.length > 0 && (\n <ul className=\"flex flex-col gap-3xs\">\n {failed.map(outcome => (\n <li\n key={String(outcome.id)}\n className=\"text-step-sm text-content-muted\"\n >\n <span className=\"text-content\">\n {labelFor?.(outcome.id) ?? String(outcome.id)}\n </span>\n {' — '}\n {/* The reason is a *code*, resolved through the shared `errors`\n catalog — the same vocabulary a service's `{ error, code }`\n body is rendered from, so a new failure reason is\n translatable rather than English, and a host's catalog\n check fails the build on one the catalog lacks. `unexpected` is the\n browser-side fallback the catalog already carries. */}\n {translateKey(`errors:${outcome.code ?? 'unexpected'}`)}\n </li>\n ))}\n </ul>\n )}\n </div>\n );\n}\n"],"names":["failedIds","succeededCount","useT","useTranslateKey","Button","cn","BulkResult","outcomes","labelFor","onRetryFailed","onDismiss","busy","className","t","translateKey","failed","filter","outcome","ok","succeeded","div","role","tabIndex","aria-label","data-testid","span","count","length","type","variant","size","disabled","onClick","ul","map","li","id","String","code"],"mappings":"AAAA;;AAEA,SAGEA,SAAS,EACTC,cAAc,QACT,gBAAgB;AAEvB,SAASC,IAAI,EAAEC,eAAe,QAAQ,yBAAyB;AAC/D,SAASC,MAAM,QAAQ,8BAA8B;AACrD,SAASC,EAAE,QAAQ,oBAAoB;AAiBvC;;;;;;;;;;;;;CAaC,GACD,OAAO,SAASC,WAAW,EACzBC,QAAQ,EACRC,QAAQ,EACRC,aAAa,EACbC,SAAS,EACTC,OAAO,KAAK,EACZC,SAAS,EACO;IAChB,MAAMC,IAAIX;IACV,MAAMY,eAAeX;IAErB,MAAMY,SAASR,SAASS,MAAM,CAACC,CAAAA,UAAW,CAACA,QAAQC,EAAE;IACrD,MAAMC,YAAYlB,eAAeM;IAEjC,qBACE,MAACa;QACCC,MAAK;QACLC,UAAU,CAAC;QACXC,cAAYV,EAAE;QACdW,eAAY;QACZZ,WAAWP,GACT,yFACAO;;0BAGF,MAACQ;gBAAIR,WAAU;;kCACb,KAACa;wBAAKb,WAAU;kCACbC,EAAE,kBAAkB;4BAAEa,OAAOP;wBAAU;;oBAEzCJ,OAAOY,MAAM,GAAG,mBACf,KAACF;wBAAKb,WAAU;kCACbC,EAAE,eAAe;4BAAEa,OAAOX,OAAOY,MAAM;wBAAC;;oBAG5CZ,OAAOY,MAAM,GAAG,KAAKlB,+BACpB,KAACL;wBACCwB,MAAK;wBACLC,SAAQ;wBACRC,MAAK;wBACLC,UAAUpB;wBACVqB,SAAS,IAAMvB,cAAcT,UAAUO;kCAEtCM,EAAE;;kCAGP,KAACT;wBACCwB,MAAK;wBACLC,SAAQ;wBACRC,MAAK;wBACLC,UAAUpB;wBACVqB,SAAStB;kCAERG,EAAE;;;;YAINE,OAAOY,MAAM,GAAG,mBACf,KAACM;gBAAGrB,WAAU;0BACXG,OAAOmB,GAAG,CAACjB,CAAAA;8BAegBA;yCAd1B,MAACkB;wBAECvB,WAAU;;0CAEV,KAACa;gCAAKb,WAAU;kDACbJ,4BAAAA,SAAWS,QAAQmB,EAAE,oBAAKC,OAAOpB,QAAQmB,EAAE;;4BAE7C;4BAOAtB,aAAa,CAAC,OAAO,GAAEG,gBAAAA,QAAQqB,IAAI,YAAZrB,gBAAgB,cAAc;;uBAbjDoB,OAAOpB,QAAQmB,EAAE;;;;;AAoBpC"}
1
+ {"version":3,"sources":["../../../../src/ui/molecules/bulk-result/bulk-result.tsx"],"sourcesContent":["'use client';\n\nimport {\n type BulkOutcome,\n type EntityId,\n failedIds,\n succeededCount,\n} from '@entifix/core';\n\nimport { useT, useTranslateKey } from '../../../i18n/index.js';\nimport { Button } from '../../atoms/button/index.js';\nimport { cn } from '../../utils/cn.js';\n\nexport interface BulkResultProps {\n outcomes: readonly BulkOutcome[];\n /**\n * How a failed row is named to the user. An id is not an answer to \"which\n * ones failed\" — the caller holds the rows and can render the same label the\n * table shows. Falls back to the id when the row is no longer on the page.\n */\n labelFor?: (id: EntityId) => string | undefined;\n /** Re-runs the failures **only**. Absent hides the affordance. */\n onRetryFailed?: (ids: EntityId[]) => void;\n onDismiss: () => void;\n busy?: boolean;\n className?: string;\n}\n\n/**\n * What a bulk action actually did, per row.\n *\n * The requirement this exists for: 40 selected, 3 fail. A single notice lies\n * whichever way it is written — as a failure it hides the 37 rows that were\n * written, and as a success it hides the 3 that were not, which is worse\n * because the user walks away believing the work is done. So both counts are\n * always stated, and every failure is named with its own reason.\n *\n * `role=\"alert\"` when anything failed, `role=\"status\"` when nothing did\n * (ADR 0028): rows the user believes were written and were not are news that\n * cannot wait its turn. The region is `tabIndex={-1}` so the caller can move focus to it once the run ends,\n * which is the only reliable way a keyboard user learns the result arrived.\n */\nexport function BulkResult({\n outcomes,\n labelFor,\n onRetryFailed,\n onDismiss,\n busy = false,\n className,\n}: BulkResultProps) {\n const t = useT();\n const translateKey = useTranslateKey();\n\n const failed = outcomes.filter(outcome => !outcome.ok);\n const succeeded = succeededCount(outcomes);\n\n return (\n <div\n role={failed.length > 0 ? 'alert' : 'status'}\n tabIndex={-1}\n aria-label={t('bulk.resultLabel')}\n data-testid=\"bulk-result\"\n className={cn(\n 'flex flex-col gap-2xs rounded-lg border border-border bg-surface-elevated px-s py-2xs',\n className,\n )}\n >\n <div className=\"flex flex-wrap items-center gap-2xs\">\n <span className=\"text-step-sm text-content\">\n {t('bulk.succeeded', { count: succeeded })}\n </span>\n {failed.length > 0 && (\n <span className=\"text-step-sm text-danger\">\n {t('bulk.failed', { count: failed.length })}\n </span>\n )}\n {failed.length > 0 && onRetryFailed && (\n <Button\n type=\"button\"\n variant=\"secondary\"\n size=\"sm\"\n disabled={busy}\n onClick={() => onRetryFailed(failedIds(outcomes))}\n >\n {t('bulk.retryFailed')}\n </Button>\n )}\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n disabled={busy}\n onClick={onDismiss}\n >\n {t('bulk.dismiss')}\n </Button>\n </div>\n\n {failed.length > 0 && (\n <ul className=\"flex flex-col gap-3xs\">\n {failed.map(outcome => (\n <li\n key={String(outcome.id)}\n className=\"text-step-sm text-content-muted\"\n >\n <span className=\"text-content\">\n {labelFor?.(outcome.id) ?? String(outcome.id)}\n </span>\n {' — '}\n {/* The reason is a *code*, resolved through the shared `errors`\n catalog — the same vocabulary a service's `{ error, code }`\n body is rendered from, so a new failure reason is\n translatable rather than English, and a host's catalog\n check fails the build on one the catalog lacks. `unexpected` is the\n browser-side fallback the catalog already carries. */}\n {translateKey(`errors:${outcome.code ?? 'unexpected'}`)}\n </li>\n ))}\n </ul>\n )}\n </div>\n );\n}\n"],"names":["failedIds","succeededCount","useT","useTranslateKey","Button","cn","BulkResult","outcomes","labelFor","onRetryFailed","onDismiss","busy","className","t","translateKey","failed","filter","outcome","ok","succeeded","div","role","length","tabIndex","aria-label","data-testid","span","count","type","variant","size","disabled","onClick","ul","map","li","id","String","code"],"mappings":"AAAA;;AAEA,SAGEA,SAAS,EACTC,cAAc,QACT,gBAAgB;AAEvB,SAASC,IAAI,EAAEC,eAAe,QAAQ,yBAAyB;AAC/D,SAASC,MAAM,QAAQ,8BAA8B;AACrD,SAASC,EAAE,QAAQ,oBAAoB;AAiBvC;;;;;;;;;;;;;CAaC,GACD,OAAO,SAASC,WAAW,EACzBC,QAAQ,EACRC,QAAQ,EACRC,aAAa,EACbC,SAAS,EACTC,OAAO,KAAK,EACZC,SAAS,EACO;IAChB,MAAMC,IAAIX;IACV,MAAMY,eAAeX;IAErB,MAAMY,SAASR,SAASS,MAAM,CAACC,CAAAA,UAAW,CAACA,QAAQC,EAAE;IACrD,MAAMC,YAAYlB,eAAeM;IAEjC,qBACE,MAACa;QACCC,MAAMN,OAAOO,MAAM,GAAG,IAAI,UAAU;QACpCC,UAAU,CAAC;QACXC,cAAYX,EAAE;QACdY,eAAY;QACZb,WAAWP,GACT,yFACAO;;0BAGF,MAACQ;gBAAIR,WAAU;;kCACb,KAACc;wBAAKd,WAAU;kCACbC,EAAE,kBAAkB;4BAAEc,OAAOR;wBAAU;;oBAEzCJ,OAAOO,MAAM,GAAG,mBACf,KAACI;wBAAKd,WAAU;kCACbC,EAAE,eAAe;4BAAEc,OAAOZ,OAAOO,MAAM;wBAAC;;oBAG5CP,OAAOO,MAAM,GAAG,KAAKb,+BACpB,KAACL;wBACCwB,MAAK;wBACLC,SAAQ;wBACRC,MAAK;wBACLC,UAAUpB;wBACVqB,SAAS,IAAMvB,cAAcT,UAAUO;kCAEtCM,EAAE;;kCAGP,KAACT;wBACCwB,MAAK;wBACLC,SAAQ;wBACRC,MAAK;wBACLC,UAAUpB;wBACVqB,SAAStB;kCAERG,EAAE;;;;YAINE,OAAOO,MAAM,GAAG,mBACf,KAACW;gBAAGrB,WAAU;0BACXG,OAAOmB,GAAG,CAACjB,CAAAA;8BAegBA;yCAd1B,MAACkB;wBAECvB,WAAU;;0CAEV,KAACc;gCAAKd,WAAU;kDACbJ,4BAAAA,SAAWS,QAAQmB,EAAE,oBAAKC,OAAOpB,QAAQmB,EAAE;;4BAE7C;4BAOAtB,aAAa,CAAC,OAAO,GAAEG,gBAAAA,QAAQqB,IAAI,YAAZrB,gBAAgB,cAAc;;uBAbjDoB,OAAOpB,QAAQmB,EAAE;;;;;AAoBpC"}
@@ -52,7 +52,7 @@ function move(names, from, to) {
52
52
  }),
53
53
  /*#__PURE__*/ _jsxs(PopoverPanel, {
54
54
  anchor: "bottom end",
55
- className: "w-64 z-10 mt-3xs rounded-xl border border-border bg-surface-elevated p-2xs shadow-card",
55
+ className: "w-64 z-(--z-dropdown) mt-3xs rounded-xl border border-border bg-surface-elevated p-2xs shadow-card",
56
56
  children: [
57
57
  /*#__PURE__*/ _jsx(Text, {
58
58
  step: -2,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/ui/molecules/column-settings/column-settings.tsx"],"sourcesContent":["'use client';\n\nimport { Popover, PopoverButton, PopoverPanel } from '@headlessui/react';\n\nimport { useT } from '../../../i18n/index.js';\nimport { Button } from '../../atoms/button/index.js';\nimport { Checkbox } from '../../atoms/field/index.js';\nimport { Text } from '../../atoms/text/index.js';\n\n/**\n * The user's column layout for one table. Stored through the UI-preferences\n * port, so it is deliberately plain JSON: names only, no descriptors — a column\n * that disappears from the entity simply stops matching.\n */\nexport interface ColumnPersonalization {\n /** Column names, most-significant first. Unlisted columns keep their default\n * position at the end, so a new entity member never breaks a saved layout. */\n order?: string[];\n /** Column names the user hid. */\n hidden?: string[];\n}\n\nexport interface ColumnSettingsColumn {\n name: string;\n label: string;\n}\n\nexport interface ColumnSettingsProps {\n /** Columns in their currently resolved order. */\n columns: readonly ColumnSettingsColumn[];\n hidden: readonly string[];\n onChange: (next: ColumnPersonalization) => void;\n}\n\nfunction move(names: readonly string[], from: number, to: number): string[] {\n const next = [...names];\n const [moved] = next.splice(from, 1);\n next.splice(to, 0, moved);\n return next;\n}\n\n/**\n * Popover for reordering and hiding columns. Reordering uses explicit up/down\n * buttons rather than drag-and-drop: it needs no dependency, works on touch, and\n * is keyboard-operable for free.\n */\nexport function ColumnSettings({\n columns,\n hidden,\n onChange,\n}: ColumnSettingsProps) {\n const order = columns.map(column => column.name);\n\n const toggle = (name: string) =>\n onChange({\n order,\n hidden: hidden.includes(name)\n ? hidden.filter(entry => entry !== name)\n : [...hidden, name],\n });\n\n const t = useT();\n\n const shift = (index: number, delta: number) => {\n const target = index + delta;\n // Defence in depth: the buttons are already disabled at both ends, so this\n // is unreachable through the UI — but an out-of-range splice would silently\n // corrupt the order rather than no-op.\n /* v8 ignore next */\n if (target < 0 || target >= order.length) return;\n onChange({ order: move(order, index, target), hidden: [...hidden] });\n };\n\n return (\n <Popover className=\"relative\">\n <PopoverButton as={Button} type=\"button\" variant=\"secondary\" size=\"sm\">\n {t('columns.title')}\n </PopoverButton>\n <PopoverPanel\n anchor=\"bottom end\"\n className=\"w-64 z-10 mt-3xs rounded-xl border border-border bg-surface-elevated p-2xs shadow-card\"\n >\n <Text step={-2} tone=\"muted\" className=\"px-3xs pb-3xs\">\n {t('columns.subtitle')}\n </Text>\n <ul className=\"flex flex-col gap-3xs\">\n {columns.map((column, index) => (\n <li\n key={column.name}\n className=\"flex items-center justify-between gap-2xs px-3xs\"\n >\n <Checkbox\n label={column.label}\n checked={!hidden.includes(column.name)}\n onChange={() => toggle(column.name)}\n />\n <span className=\"flex gap-3xs\">\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n aria-label={t('columns.moveUp', { column: column.label })}\n disabled={index === 0}\n onClick={() => shift(index, -1)}\n >\n ↑\n </Button>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n aria-label={t('columns.moveDown', { column: column.label })}\n disabled={index === columns.length - 1}\n onClick={() => shift(index, 1)}\n >\n ↓\n </Button>\n </span>\n </li>\n ))}\n </ul>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n className=\"mt-2xs w-full\"\n onClick={() => onChange({})}\n >\n {t('columns.reset')}\n </Button>\n </PopoverPanel>\n </Popover>\n );\n}\n"],"names":["Popover","PopoverButton","PopoverPanel","useT","Button","Checkbox","Text","move","names","from","to","next","moved","splice","ColumnSettings","columns","hidden","onChange","order","map","column","name","toggle","includes","filter","entry","t","shift","index","delta","target","length","className","as","type","variant","size","anchor","step","tone","ul","li","label","checked","span","aria-label","disabled","onClick"],"mappings":"AAAA;;AAEA,SAASA,OAAO,EAAEC,aAAa,EAAEC,YAAY,QAAQ,oBAAoB;AAEzE,SAASC,IAAI,QAAQ,yBAAyB;AAC9C,SAASC,MAAM,QAAQ,8BAA8B;AACrD,SAASC,QAAQ,QAAQ,6BAA6B;AACtD,SAASC,IAAI,QAAQ,4BAA4B;AA2BjD,SAASC,KAAKC,KAAwB,EAAEC,IAAY,EAAEC,EAAU;IAC9D,MAAMC,OAAO;WAAIH;KAAM;IACvB,MAAM,CAACI,MAAM,GAAGD,KAAKE,MAAM,CAACJ,MAAM;IAClCE,KAAKE,MAAM,CAACH,IAAI,GAAGE;IACnB,OAAOD;AACT;AAEA;;;;CAIC,GACD,OAAO,SAASG,eAAe,EAC7BC,OAAO,EACPC,MAAM,EACNC,QAAQ,EACY;IACpB,MAAMC,QAAQH,QAAQI,GAAG,CAACC,CAAAA,SAAUA,OAAOC,IAAI;IAE/C,MAAMC,SAAS,CAACD,OACdJ,SAAS;YACPC;YACAF,QAAQA,OAAOO,QAAQ,CAACF,QACpBL,OAAOQ,MAAM,CAACC,CAAAA,QAASA,UAAUJ,QACjC;mBAAIL;gBAAQK;aAAK;QACvB;IAEF,MAAMK,IAAIvB;IAEV,MAAMwB,QAAQ,CAACC,OAAeC;QAC5B,MAAMC,SAASF,QAAQC;QACvB,2EAA2E;QAC3E,4EAA4E;QAC5E,uCAAuC;QACvC,kBAAkB,GAClB,IAAIC,SAAS,KAAKA,UAAUZ,MAAMa,MAAM,EAAE;QAC1Cd,SAAS;YAAEC,OAAOX,KAAKW,OAAOU,OAAOE;YAASd,QAAQ;mBAAIA;aAAO;QAAC;IACpE;IAEA,qBACE,MAAChB;QAAQgC,WAAU;;0BACjB,KAAC/B;gBAAcgC,IAAI7B;gBAAQ8B,MAAK;gBAASC,SAAQ;gBAAYC,MAAK;0BAC/DV,EAAE;;0BAEL,MAACxB;gBACCmC,QAAO;gBACPL,WAAU;;kCAEV,KAAC1B;wBAAKgC,MAAM,CAAC;wBAAGC,MAAK;wBAAQP,WAAU;kCACpCN,EAAE;;kCAEL,KAACc;wBAAGR,WAAU;kCACXjB,QAAQI,GAAG,CAAC,CAACC,QAAQQ,sBACpB,MAACa;gCAECT,WAAU;;kDAEV,KAAC3B;wCACCqC,OAAOtB,OAAOsB,KAAK;wCACnBC,SAAS,CAAC3B,OAAOO,QAAQ,CAACH,OAAOC,IAAI;wCACrCJ,UAAU,IAAMK,OAAOF,OAAOC,IAAI;;kDAEpC,MAACuB;wCAAKZ,WAAU;;0DACd,KAAC5B;gDACC8B,MAAK;gDACLC,SAAQ;gDACRC,MAAK;gDACLS,cAAYnB,EAAE,kBAAkB;oDAAEN,QAAQA,OAAOsB,KAAK;gDAAC;gDACvDI,UAAUlB,UAAU;gDACpBmB,SAAS,IAAMpB,MAAMC,OAAO,CAAC;0DAC9B;;0DAGD,KAACxB;gDACC8B,MAAK;gDACLC,SAAQ;gDACRC,MAAK;gDACLS,cAAYnB,EAAE,oBAAoB;oDAAEN,QAAQA,OAAOsB,KAAK;gDAAC;gDACzDI,UAAUlB,UAAUb,QAAQgB,MAAM,GAAG;gDACrCgB,SAAS,IAAMpB,MAAMC,OAAO;0DAC7B;;;;;+BA1BER,OAAOC,IAAI;;kCAiCtB,KAACjB;wBACC8B,MAAK;wBACLC,SAAQ;wBACRC,MAAK;wBACLJ,WAAU;wBACVe,SAAS,IAAM9B,SAAS,CAAC;kCAExBS,EAAE;;;;;;AAKb"}
1
+ {"version":3,"sources":["../../../../src/ui/molecules/column-settings/column-settings.tsx"],"sourcesContent":["'use client';\n\nimport { Popover, PopoverButton, PopoverPanel } from '@headlessui/react';\n\nimport { useT } from '../../../i18n/index.js';\nimport { Button } from '../../atoms/button/index.js';\nimport { Checkbox } from '../../atoms/field/index.js';\nimport { Text } from '../../atoms/text/index.js';\n\n/**\n * The user's column layout for one table. Stored through the UI-preferences\n * port, so it is deliberately plain JSON: names only, no descriptors — a column\n * that disappears from the entity simply stops matching.\n */\nexport interface ColumnPersonalization {\n /** Column names, most-significant first. Unlisted columns keep their default\n * position at the end, so a new entity member never breaks a saved layout. */\n order?: string[];\n /** Column names the user hid. */\n hidden?: string[];\n}\n\nexport interface ColumnSettingsColumn {\n name: string;\n label: string;\n}\n\nexport interface ColumnSettingsProps {\n /** Columns in their currently resolved order. */\n columns: readonly ColumnSettingsColumn[];\n hidden: readonly string[];\n onChange: (next: ColumnPersonalization) => void;\n}\n\nfunction move(names: readonly string[], from: number, to: number): string[] {\n const next = [...names];\n const [moved] = next.splice(from, 1);\n next.splice(to, 0, moved);\n return next;\n}\n\n/**\n * Popover for reordering and hiding columns. Reordering uses explicit up/down\n * buttons rather than drag-and-drop: it needs no dependency, works on touch, and\n * is keyboard-operable for free.\n */\nexport function ColumnSettings({\n columns,\n hidden,\n onChange,\n}: ColumnSettingsProps) {\n const order = columns.map(column => column.name);\n\n const toggle = (name: string) =>\n onChange({\n order,\n hidden: hidden.includes(name)\n ? hidden.filter(entry => entry !== name)\n : [...hidden, name],\n });\n\n const t = useT();\n\n const shift = (index: number, delta: number) => {\n const target = index + delta;\n // Defence in depth: the buttons are already disabled at both ends, so this\n // is unreachable through the UI — but an out-of-range splice would silently\n // corrupt the order rather than no-op.\n /* v8 ignore next */\n if (target < 0 || target >= order.length) return;\n onChange({ order: move(order, index, target), hidden: [...hidden] });\n };\n\n return (\n <Popover className=\"relative\">\n <PopoverButton as={Button} type=\"button\" variant=\"secondary\" size=\"sm\">\n {t('columns.title')}\n </PopoverButton>\n <PopoverPanel\n anchor=\"bottom end\"\n className=\"w-64 z-(--z-dropdown) mt-3xs rounded-xl border border-border bg-surface-elevated p-2xs shadow-card\"\n >\n <Text step={-2} tone=\"muted\" className=\"px-3xs pb-3xs\">\n {t('columns.subtitle')}\n </Text>\n <ul className=\"flex flex-col gap-3xs\">\n {columns.map((column, index) => (\n <li\n key={column.name}\n className=\"flex items-center justify-between gap-2xs px-3xs\"\n >\n <Checkbox\n label={column.label}\n checked={!hidden.includes(column.name)}\n onChange={() => toggle(column.name)}\n />\n <span className=\"flex gap-3xs\">\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n aria-label={t('columns.moveUp', { column: column.label })}\n disabled={index === 0}\n onClick={() => shift(index, -1)}\n >\n ↑\n </Button>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n aria-label={t('columns.moveDown', { column: column.label })}\n disabled={index === columns.length - 1}\n onClick={() => shift(index, 1)}\n >\n ↓\n </Button>\n </span>\n </li>\n ))}\n </ul>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n className=\"mt-2xs w-full\"\n onClick={() => onChange({})}\n >\n {t('columns.reset')}\n </Button>\n </PopoverPanel>\n </Popover>\n );\n}\n"],"names":["Popover","PopoverButton","PopoverPanel","useT","Button","Checkbox","Text","move","names","from","to","next","moved","splice","ColumnSettings","columns","hidden","onChange","order","map","column","name","toggle","includes","filter","entry","t","shift","index","delta","target","length","className","as","type","variant","size","anchor","step","tone","ul","li","label","checked","span","aria-label","disabled","onClick"],"mappings":"AAAA;;AAEA,SAASA,OAAO,EAAEC,aAAa,EAAEC,YAAY,QAAQ,oBAAoB;AAEzE,SAASC,IAAI,QAAQ,yBAAyB;AAC9C,SAASC,MAAM,QAAQ,8BAA8B;AACrD,SAASC,QAAQ,QAAQ,6BAA6B;AACtD,SAASC,IAAI,QAAQ,4BAA4B;AA2BjD,SAASC,KAAKC,KAAwB,EAAEC,IAAY,EAAEC,EAAU;IAC9D,MAAMC,OAAO;WAAIH;KAAM;IACvB,MAAM,CAACI,MAAM,GAAGD,KAAKE,MAAM,CAACJ,MAAM;IAClCE,KAAKE,MAAM,CAACH,IAAI,GAAGE;IACnB,OAAOD;AACT;AAEA;;;;CAIC,GACD,OAAO,SAASG,eAAe,EAC7BC,OAAO,EACPC,MAAM,EACNC,QAAQ,EACY;IACpB,MAAMC,QAAQH,QAAQI,GAAG,CAACC,CAAAA,SAAUA,OAAOC,IAAI;IAE/C,MAAMC,SAAS,CAACD,OACdJ,SAAS;YACPC;YACAF,QAAQA,OAAOO,QAAQ,CAACF,QACpBL,OAAOQ,MAAM,CAACC,CAAAA,QAASA,UAAUJ,QACjC;mBAAIL;gBAAQK;aAAK;QACvB;IAEF,MAAMK,IAAIvB;IAEV,MAAMwB,QAAQ,CAACC,OAAeC;QAC5B,MAAMC,SAASF,QAAQC;QACvB,2EAA2E;QAC3E,4EAA4E;QAC5E,uCAAuC;QACvC,kBAAkB,GAClB,IAAIC,SAAS,KAAKA,UAAUZ,MAAMa,MAAM,EAAE;QAC1Cd,SAAS;YAAEC,OAAOX,KAAKW,OAAOU,OAAOE;YAASd,QAAQ;mBAAIA;aAAO;QAAC;IACpE;IAEA,qBACE,MAAChB;QAAQgC,WAAU;;0BACjB,KAAC/B;gBAAcgC,IAAI7B;gBAAQ8B,MAAK;gBAASC,SAAQ;gBAAYC,MAAK;0BAC/DV,EAAE;;0BAEL,MAACxB;gBACCmC,QAAO;gBACPL,WAAU;;kCAEV,KAAC1B;wBAAKgC,MAAM,CAAC;wBAAGC,MAAK;wBAAQP,WAAU;kCACpCN,EAAE;;kCAEL,KAACc;wBAAGR,WAAU;kCACXjB,QAAQI,GAAG,CAAC,CAACC,QAAQQ,sBACpB,MAACa;gCAECT,WAAU;;kDAEV,KAAC3B;wCACCqC,OAAOtB,OAAOsB,KAAK;wCACnBC,SAAS,CAAC3B,OAAOO,QAAQ,CAACH,OAAOC,IAAI;wCACrCJ,UAAU,IAAMK,OAAOF,OAAOC,IAAI;;kDAEpC,MAACuB;wCAAKZ,WAAU;;0DACd,KAAC5B;gDACC8B,MAAK;gDACLC,SAAQ;gDACRC,MAAK;gDACLS,cAAYnB,EAAE,kBAAkB;oDAAEN,QAAQA,OAAOsB,KAAK;gDAAC;gDACvDI,UAAUlB,UAAU;gDACpBmB,SAAS,IAAMpB,MAAMC,OAAO,CAAC;0DAC9B;;0DAGD,KAACxB;gDACC8B,MAAK;gDACLC,SAAQ;gDACRC,MAAK;gDACLS,cAAYnB,EAAE,oBAAoB;oDAAEN,QAAQA,OAAOsB,KAAK;gDAAC;gDACzDI,UAAUlB,UAAUb,QAAQgB,MAAM,GAAG;gDACrCgB,SAAS,IAAMpB,MAAMC,OAAO;0DAC7B;;;;;+BA1BER,OAAOC,IAAI;;kCAiCtB,KAACjB;wBACC8B,MAAK;wBACLC,SAAQ;wBACRC,MAAK;wBACLJ,WAAU;wBACVe,SAAS,IAAM9B,SAAS,CAAC;kCAExBS,EAAE;;;;;;AAKb"}
@@ -1,31 +1,46 @@
1
1
  export type ConfirmTone = 'destructive' | 'neutral';
2
2
  export interface ConfirmDialogProps {
3
3
  open: boolean;
4
- /** Already-resolved copy — this control renders text, it does not translate. */
4
+ /**
5
+ * Already-resolved copy — this control renders text, it does not translate.
6
+ * A question naming what is affected and how many: "Delete Acme?",
7
+ * "Archive 12 invoices?".
8
+ */
5
9
  title: string;
10
+ /** The consequence, in one or two sentences. */
6
11
  message: string;
7
12
  /** `destructive` paints the confirm button in the danger tokens. */
8
13
  tone?: ConfirmTone;
14
+ /**
15
+ * The confirming button. Repeat the verb, with the count when there is more
16
+ * than one — "Delete 12" — so the reader does not go back to the title to
17
+ * learn what they are agreeing to. Defaults to "Confirm".
18
+ */
9
19
  confirmLabel?: string;
10
20
  cancelLabel?: string;
21
+ /**
22
+ * Asks the reader to type this — the record's name, or the count — before
23
+ * the confirming button enables: for a destruction too large to be one
24
+ * misplaced click.
25
+ */
26
+ typed?: string;
11
27
  busy?: boolean;
12
28
  onConfirm: () => void;
13
29
  onCancel: () => void;
14
30
  }
15
31
  /**
16
- * Asks before an irreversible act.
32
+ * Asks before an irreversible act
33
+ * ([ADR 0026](../../../../../../../docs/adr/0026-actions-hierarchy-overflow-and-destructive-verbs.md)).
17
34
  *
18
- * It exists because a use-case descriptor may carry
19
- * `confirm: { tone, messageKey }`, and a surface that renders such a descriptor
20
- * without asking would fire the act on the first click — `revoke-sessions` ends
21
- * every session a user holds. The descriptor names the tone and the message key;
22
- * resolving that key is the caller's job, so this control stays copy-free apart
23
- * from its own two buttons.
35
+ * An `alertdialog`, not a `dialog`: it interrupts to ask a question that must
36
+ * be answered. Its message is wired as the dialog's description, so it is read
37
+ * with the title on opening, and **Cancel takes the initial focus** — Enter on
38
+ * a dialog that opened under the reader's hand keeps what they have.
24
39
  *
25
40
  * The dialog element fills the viewport rather than wrapping a `fixed` child in
26
41
  * a `relative` box, for the reason `EntityLinkPicker` records: a zero-sized
27
42
  * dialog is invisible to anything that measures it — assistive tech and
28
43
  * Playwright alike — even with a painted panel inside.
29
44
  */
30
- export declare function ConfirmDialog({ open, title, message, tone, confirmLabel, cancelLabel, busy, onConfirm, onCancel, }: ConfirmDialogProps): import("react").JSX.Element;
45
+ export declare function ConfirmDialog({ open, title, message, tone, confirmLabel, cancelLabel, typed, busy, onConfirm, onCancel, }: ConfirmDialogProps): import("react").JSX.Element;
31
46
  //# sourceMappingURL=confirm-dialog.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"confirm-dialog.d.ts","sourceRoot":"","sources":["../../../../src/ui/molecules/confirm-dialog/confirm-dialog.tsx"],"names":[],"mappings":"AAOA,MAAM,MAAM,WAAW,GAAG,aAAa,GAAG,SAAS,CAAC;AAEpD,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,OAAO,CAAC;IACd,gFAAgF;IAChF,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,oEAAoE;IACpE,IAAI,CAAC,EAAE,WAAW,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,SAAS,EAAE,MAAM,IAAI,CAAC;IACtB,QAAQ,EAAE,MAAM,IAAI,CAAC;CACtB;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,aAAa,CAAC,EAC5B,IAAI,EACJ,KAAK,EACL,OAAO,EACP,IAAgB,EAChB,YAAY,EACZ,WAAW,EACX,IAAY,EACZ,SAAS,EACT,QAAQ,GACT,EAAE,kBAAkB,+BAuCpB"}
1
+ {"version":3,"file":"confirm-dialog.d.ts","sourceRoot":"","sources":["../../../../src/ui/molecules/confirm-dialog/confirm-dialog.tsx"],"names":[],"mappings":"AAcA,MAAM,MAAM,WAAW,GAAG,aAAa,GAAG,SAAS,CAAC;AAEpD,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,OAAO,CAAC;IACd;;;;OAIG;IACH,KAAK,EAAE,MAAM,CAAC;IACd,gDAAgD;IAChD,OAAO,EAAE,MAAM,CAAC;IAChB,oEAAoE;IACpE,IAAI,CAAC,EAAE,WAAW,CAAC;IACnB;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;OAIG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,SAAS,EAAE,MAAM,IAAI,CAAC;IACtB,QAAQ,EAAE,MAAM,IAAI,CAAC;CACtB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,aAAa,CAAC,EAC5B,IAAI,EACJ,KAAK,EACL,OAAO,EACP,IAAgB,EAChB,YAAY,EACZ,WAAW,EACX,KAAK,EACL,IAAY,EACZ,SAAS,EACT,QAAQ,GACT,EAAE,kBAAkB,+BA4DpB"}
@@ -1,32 +1,37 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { Dialog, DialogPanel, DialogTitle } from '@headlessui/react';
3
+ import { Dialog, DialogDescription, DialogPanel, DialogTitle } from '@headlessui/react';
4
+ import { useId, useState } from 'react';
4
5
  import { useT } from '../../../i18n/index.js';
5
6
  import { Button } from '../../atoms/button/index.js';
7
+ import { TextInput } from '../../atoms/field/index.js';
6
8
  /**
7
- * Asks before an irreversible act.
9
+ * Asks before an irreversible act
10
+ * ([ADR 0026](../../../../../../../docs/adr/0026-actions-hierarchy-overflow-and-destructive-verbs.md)).
8
11
  *
9
- * It exists because a use-case descriptor may carry
10
- * `confirm: { tone, messageKey }`, and a surface that renders such a descriptor
11
- * without asking would fire the act on the first click — `revoke-sessions` ends
12
- * every session a user holds. The descriptor names the tone and the message key;
13
- * resolving that key is the caller's job, so this control stays copy-free apart
14
- * from its own two buttons.
12
+ * An `alertdialog`, not a `dialog`: it interrupts to ask a question that must
13
+ * be answered. Its message is wired as the dialog's description, so it is read
14
+ * with the title on opening, and **Cancel takes the initial focus** — Enter on
15
+ * a dialog that opened under the reader's hand keeps what they have.
15
16
  *
16
17
  * The dialog element fills the viewport rather than wrapping a `fixed` child in
17
18
  * a `relative` box, for the reason `EntityLinkPicker` records: a zero-sized
18
19
  * dialog is invisible to anything that measures it — assistive tech and
19
20
  * Playwright alike — even with a painted panel inside.
20
- */ export function ConfirmDialog({ open, title, message, tone = 'neutral', confirmLabel, cancelLabel, busy = false, onConfirm, onCancel }) {
21
+ */ export function ConfirmDialog({ open, title, message, tone = 'neutral', confirmLabel, cancelLabel, typed, busy = false, onConfirm, onCancel }) {
21
22
  const t = useT();
23
+ const inputId = useId();
24
+ const [entered, setEntered] = useState('');
25
+ const matches = typed === undefined || entered.trim() === typed;
22
26
  return /*#__PURE__*/ _jsxs(Dialog, {
23
27
  open: open,
28
+ role: "alertdialog",
24
29
  onClose: onCancel,
25
- className: "inset-0 fixed z-50 flex items-center justify-center overflow-y-auto p-s",
30
+ className: "inset-0 fixed z-(--z-overlay) flex items-center justify-center overflow-y-auto p-s",
26
31
  children: [
27
32
  /*#__PURE__*/ _jsx("div", {
28
33
  "aria-hidden": true,
29
- className: "inset-0 bg-black/40 fixed"
34
+ className: "inset-0 fixed bg-scrim"
30
35
  }),
31
36
  /*#__PURE__*/ _jsxs(DialogPanel, {
32
37
  "data-testid": "confirm-dialog",
@@ -36,16 +41,36 @@ import { Button } from '../../atoms/button/index.js';
36
41
  className: "text-step-1 font-semibold text-content",
37
42
  children: title
38
43
  }),
39
- /*#__PURE__*/ _jsx("p", {
44
+ /*#__PURE__*/ _jsx(DialogDescription, {
40
45
  className: "mt-2xs text-step-sm text-content-muted",
41
46
  children: message
42
47
  }),
48
+ typed !== undefined && /*#__PURE__*/ _jsxs("div", {
49
+ className: "mt-s flex flex-col gap-3xs",
50
+ children: [
51
+ /*#__PURE__*/ _jsx("label", {
52
+ htmlFor: inputId,
53
+ className: "text-step-sm text-content",
54
+ children: t('confirm.typeToConfirm', {
55
+ expected: typed
56
+ })
57
+ }),
58
+ /*#__PURE__*/ _jsx(TextInput, {
59
+ id: inputId,
60
+ autoComplete: "off",
61
+ spellCheck: false,
62
+ value: entered,
63
+ onChange: (event)=>setEntered(event.currentTarget.value)
64
+ })
65
+ ]
66
+ }),
43
67
  /*#__PURE__*/ _jsxs("div", {
44
68
  className: "mt-s flex justify-end gap-xs",
45
69
  children: [
46
70
  /*#__PURE__*/ _jsx(Button, {
47
71
  type: "button",
48
72
  variant: "ghost",
73
+ "data-autofocus": true,
49
74
  onClick: onCancel,
50
75
  disabled: busy,
51
76
  children: cancelLabel != null ? cancelLabel : t('confirm.cancel')
@@ -54,7 +79,7 @@ import { Button } from '../../atoms/button/index.js';
54
79
  type: "button",
55
80
  variant: tone === 'destructive' ? 'destructive' : 'primary',
56
81
  onClick: onConfirm,
57
- disabled: busy,
82
+ disabled: busy || !matches,
58
83
  children: confirmLabel != null ? confirmLabel : t('confirm.confirm')
59
84
  })
60
85
  ]
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/ui/molecules/confirm-dialog/confirm-dialog.tsx"],"sourcesContent":["'use client';\n\nimport { Dialog, DialogPanel, DialogTitle } from '@headlessui/react';\n\nimport { useT } from '../../../i18n/index.js';\nimport { Button } from '../../atoms/button/index.js';\n\nexport type ConfirmTone = 'destructive' | 'neutral';\n\nexport interface ConfirmDialogProps {\n open: boolean;\n /** Already-resolved copy — this control renders text, it does not translate. */\n title: string;\n message: string;\n /** `destructive` paints the confirm button in the danger tokens. */\n tone?: ConfirmTone;\n confirmLabel?: string;\n cancelLabel?: string;\n busy?: boolean;\n onConfirm: () => void;\n onCancel: () => void;\n}\n\n/**\n * Asks before an irreversible act.\n *\n * It exists because a use-case descriptor may carry\n * `confirm: { tone, messageKey }`, and a surface that renders such a descriptor\n * without asking would fire the act on the first click — `revoke-sessions` ends\n * every session a user holds. The descriptor names the tone and the message key;\n * resolving that key is the caller's job, so this control stays copy-free apart\n * from its own two buttons.\n *\n * The dialog element fills the viewport rather than wrapping a `fixed` child in\n * a `relative` box, for the reason `EntityLinkPicker` records: a zero-sized\n * dialog is invisible to anything that measures it — assistive tech and\n * Playwright alike — even with a painted panel inside.\n */\nexport function ConfirmDialog({\n open,\n title,\n message,\n tone = 'neutral',\n confirmLabel,\n cancelLabel,\n busy = false,\n onConfirm,\n onCancel,\n}: ConfirmDialogProps) {\n const t = useT();\n\n return (\n <Dialog\n open={open}\n onClose={onCancel}\n className=\"inset-0 fixed z-50 flex items-center justify-center overflow-y-auto p-s\"\n >\n <div aria-hidden className=\"inset-0 bg-black/40 fixed\" />\n <DialogPanel\n data-testid=\"confirm-dialog\"\n className=\"max-w-md relative w-full rounded-lg border border-border bg-surface p-s shadow-overlay\"\n >\n <DialogTitle className=\"text-step-1 font-semibold text-content\">\n {title}\n </DialogTitle>\n <p className=\"mt-2xs text-step-sm text-content-muted\">{message}</p>\n <div className=\"mt-s flex justify-end gap-xs\">\n <Button\n type=\"button\"\n variant=\"ghost\"\n onClick={onCancel}\n disabled={busy}\n >\n {cancelLabel ?? t('confirm.cancel')}\n </Button>\n <Button\n type=\"button\"\n variant={tone === 'destructive' ? 'destructive' : 'primary'}\n onClick={onConfirm}\n disabled={busy}\n >\n {confirmLabel ?? t('confirm.confirm')}\n </Button>\n </div>\n </DialogPanel>\n </Dialog>\n );\n}\n"],"names":["Dialog","DialogPanel","DialogTitle","useT","Button","ConfirmDialog","open","title","message","tone","confirmLabel","cancelLabel","busy","onConfirm","onCancel","t","onClose","className","div","aria-hidden","data-testid","p","type","variant","onClick","disabled"],"mappings":"AAAA;;AAEA,SAASA,MAAM,EAAEC,WAAW,EAAEC,WAAW,QAAQ,oBAAoB;AAErE,SAASC,IAAI,QAAQ,yBAAyB;AAC9C,SAASC,MAAM,QAAQ,8BAA8B;AAkBrD;;;;;;;;;;;;;;CAcC,GACD,OAAO,SAASC,cAAc,EAC5BC,IAAI,EACJC,KAAK,EACLC,OAAO,EACPC,OAAO,SAAS,EAChBC,YAAY,EACZC,WAAW,EACXC,OAAO,KAAK,EACZC,SAAS,EACTC,QAAQ,EACW;IACnB,MAAMC,IAAIZ;IAEV,qBACE,MAACH;QACCM,MAAMA;QACNU,SAASF;QACTG,WAAU;;0BAEV,KAACC;gBAAIC,aAAW;gBAACF,WAAU;;0BAC3B,MAAChB;gBACCmB,eAAY;gBACZH,WAAU;;kCAEV,KAACf;wBAAYe,WAAU;kCACpBV;;kCAEH,KAACc;wBAAEJ,WAAU;kCAA0CT;;kCACvD,MAACU;wBAAID,WAAU;;0CACb,KAACb;gCACCkB,MAAK;gCACLC,SAAQ;gCACRC,SAASV;gCACTW,UAAUb;0CAETD,sBAAAA,cAAeI,EAAE;;0CAEpB,KAACX;gCACCkB,MAAK;gCACLC,SAASd,SAAS,gBAAgB,gBAAgB;gCAClDe,SAASX;gCACTY,UAAUb;0CAETF,uBAAAA,eAAgBK,EAAE;;;;;;;;AAM/B"}
1
+ {"version":3,"sources":["../../../../src/ui/molecules/confirm-dialog/confirm-dialog.tsx"],"sourcesContent":["'use client';\n\nimport {\n Dialog,\n DialogDescription,\n DialogPanel,\n DialogTitle,\n} from '@headlessui/react';\nimport { useId, useState } from 'react';\n\nimport { useT } from '../../../i18n/index.js';\nimport { Button } from '../../atoms/button/index.js';\nimport { TextInput } from '../../atoms/field/index.js';\n\nexport type ConfirmTone = 'destructive' | 'neutral';\n\nexport interface ConfirmDialogProps {\n open: boolean;\n /**\n * Already-resolved copy — this control renders text, it does not translate.\n * A question naming what is affected and how many: \"Delete Acme?\",\n * \"Archive 12 invoices?\".\n */\n title: string;\n /** The consequence, in one or two sentences. */\n message: string;\n /** `destructive` paints the confirm button in the danger tokens. */\n tone?: ConfirmTone;\n /**\n * The confirming button. Repeat the verb, with the count when there is more\n * than one — \"Delete 12\" — so the reader does not go back to the title to\n * learn what they are agreeing to. Defaults to \"Confirm\".\n */\n confirmLabel?: string;\n cancelLabel?: string;\n /**\n * Asks the reader to type this — the record's name, or the count — before\n * the confirming button enables: for a destruction too large to be one\n * misplaced click.\n */\n typed?: string;\n busy?: boolean;\n onConfirm: () => void;\n onCancel: () => void;\n}\n\n/**\n * Asks before an irreversible act\n * ([ADR 0026](../../../../../../../docs/adr/0026-actions-hierarchy-overflow-and-destructive-verbs.md)).\n *\n * An `alertdialog`, not a `dialog`: it interrupts to ask a question that must\n * be answered. Its message is wired as the dialog's description, so it is read\n * with the title on opening, and **Cancel takes the initial focus** — Enter on\n * a dialog that opened under the reader's hand keeps what they have.\n *\n * The dialog element fills the viewport rather than wrapping a `fixed` child in\n * a `relative` box, for the reason `EntityLinkPicker` records: a zero-sized\n * dialog is invisible to anything that measures it — assistive tech and\n * Playwright alike — even with a painted panel inside.\n */\nexport function ConfirmDialog({\n open,\n title,\n message,\n tone = 'neutral',\n confirmLabel,\n cancelLabel,\n typed,\n busy = false,\n onConfirm,\n onCancel,\n}: ConfirmDialogProps) {\n const t = useT();\n const inputId = useId();\n const [entered, setEntered] = useState('');\n const matches = typed === undefined || entered.trim() === typed;\n\n return (\n <Dialog\n open={open}\n role=\"alertdialog\"\n onClose={onCancel}\n className=\"inset-0 fixed z-(--z-overlay) flex items-center justify-center overflow-y-auto p-s\"\n >\n <div aria-hidden className=\"inset-0 fixed bg-scrim\" />\n <DialogPanel\n data-testid=\"confirm-dialog\"\n className=\"max-w-md relative w-full rounded-lg border border-border bg-surface p-s shadow-overlay\"\n >\n <DialogTitle className=\"text-step-1 font-semibold text-content\">\n {title}\n </DialogTitle>\n <DialogDescription className=\"mt-2xs text-step-sm text-content-muted\">\n {message}\n </DialogDescription>\n {typed !== undefined && (\n <div className=\"mt-s flex flex-col gap-3xs\">\n <label htmlFor={inputId} className=\"text-step-sm text-content\">\n {t('confirm.typeToConfirm', { expected: typed })}\n </label>\n <TextInput\n id={inputId}\n autoComplete=\"off\"\n spellCheck={false}\n value={entered}\n onChange={event => setEntered(event.currentTarget.value)}\n />\n </div>\n )}\n <div className=\"mt-s flex justify-end gap-xs\">\n <Button\n type=\"button\"\n variant=\"ghost\"\n data-autofocus\n onClick={onCancel}\n disabled={busy}\n >\n {cancelLabel ?? t('confirm.cancel')}\n </Button>\n <Button\n type=\"button\"\n variant={tone === 'destructive' ? 'destructive' : 'primary'}\n onClick={onConfirm}\n disabled={busy || !matches}\n >\n {confirmLabel ?? t('confirm.confirm')}\n </Button>\n </div>\n </DialogPanel>\n </Dialog>\n );\n}\n"],"names":["Dialog","DialogDescription","DialogPanel","DialogTitle","useId","useState","useT","Button","TextInput","ConfirmDialog","open","title","message","tone","confirmLabel","cancelLabel","typed","busy","onConfirm","onCancel","t","inputId","entered","setEntered","matches","undefined","trim","role","onClose","className","div","aria-hidden","data-testid","label","htmlFor","expected","id","autoComplete","spellCheck","value","onChange","event","currentTarget","type","variant","data-autofocus","onClick","disabled"],"mappings":"AAAA;;AAEA,SACEA,MAAM,EACNC,iBAAiB,EACjBC,WAAW,EACXC,WAAW,QACN,oBAAoB;AAC3B,SAASC,KAAK,EAAEC,QAAQ,QAAQ,QAAQ;AAExC,SAASC,IAAI,QAAQ,yBAAyB;AAC9C,SAASC,MAAM,QAAQ,8BAA8B;AACrD,SAASC,SAAS,QAAQ,6BAA6B;AAkCvD;;;;;;;;;;;;;CAaC,GACD,OAAO,SAASC,cAAc,EAC5BC,IAAI,EACJC,KAAK,EACLC,OAAO,EACPC,OAAO,SAAS,EAChBC,YAAY,EACZC,WAAW,EACXC,KAAK,EACLC,OAAO,KAAK,EACZC,SAAS,EACTC,QAAQ,EACW;IACnB,MAAMC,IAAId;IACV,MAAMe,UAAUjB;IAChB,MAAM,CAACkB,SAASC,WAAW,GAAGlB,SAAS;IACvC,MAAMmB,UAAUR,UAAUS,aAAaH,QAAQI,IAAI,OAAOV;IAE1D,qBACE,MAAChB;QACCU,MAAMA;QACNiB,MAAK;QACLC,SAAST;QACTU,WAAU;;0BAEV,KAACC;gBAAIC,aAAW;gBAACF,WAAU;;0BAC3B,MAAC3B;gBACC8B,eAAY;gBACZH,WAAU;;kCAEV,KAAC1B;wBAAY0B,WAAU;kCACpBlB;;kCAEH,KAACV;wBAAkB4B,WAAU;kCAC1BjB;;oBAEFI,UAAUS,2BACT,MAACK;wBAAID,WAAU;;0CACb,KAACI;gCAAMC,SAASb;gCAASQ,WAAU;0CAChCT,EAAE,yBAAyB;oCAAEe,UAAUnB;gCAAM;;0CAEhD,KAACR;gCACC4B,IAAIf;gCACJgB,cAAa;gCACbC,YAAY;gCACZC,OAAOjB;gCACPkB,UAAUC,CAAAA,QAASlB,WAAWkB,MAAMC,aAAa,CAACH,KAAK;;;;kCAI7D,MAACT;wBAAID,WAAU;;0CACb,KAACtB;gCACCoC,MAAK;gCACLC,SAAQ;gCACRC,gBAAc;gCACdC,SAAS3B;gCACT4B,UAAU9B;0CAETF,sBAAAA,cAAeK,EAAE;;0CAEpB,KAACb;gCACCoC,MAAK;gCACLC,SAAS/B,SAAS,gBAAgB,gBAAgB;gCAClDiC,SAAS5B;gCACT6B,UAAU9B,QAAQ,CAACO;0CAElBV,uBAAAA,eAAgBM,EAAE;;;;;;;;AAM/B"}
@@ -0,0 +1,17 @@
1
+ import type { ComponentPropsWithoutRef, ReactNode } from 'react';
2
+ export interface DescriptionListItem {
3
+ /** A stable key; the term itself when it is unique. */
4
+ readonly key?: string;
5
+ readonly term: ReactNode;
6
+ readonly description: ReactNode;
7
+ }
8
+ export interface DescriptionListProps extends Omit<ComponentPropsWithoutRef<'dl'>, 'children'> {
9
+ items: readonly DescriptionListItem[];
10
+ }
11
+ /**
12
+ * Terms and what they are — a record's facts, a product's specifications —
13
+ * as a real `<dl>`, so each value is announced with the term it belongs to.
14
+ * Two columns where there is room, stacked where there is not. Server-safe.
15
+ */
16
+ export declare function DescriptionList({ items, className, ...props }: DescriptionListProps): import("react").JSX.Element;
17
+ //# sourceMappingURL=description-list.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"description-list.d.ts","sourceRoot":"","sources":["../../../../src/ui/molecules/description-list/description-list.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,wBAAwB,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAIjE,MAAM,WAAW,mBAAmB;IAClC,uDAAuD;IACvD,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IACzB,QAAQ,CAAC,WAAW,EAAE,SAAS,CAAC;CACjC;AAED,MAAM,WAAW,oBAAqB,SAAQ,IAAI,CAChD,wBAAwB,CAAC,IAAI,CAAC,EAC9B,UAAU,CACX;IACC,KAAK,EAAE,SAAS,mBAAmB,EAAE,CAAC;CACvC;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,EAC9B,KAAK,EACL,SAAS,EACT,GAAG,KAAK,EACT,EAAE,oBAAoB,+BAiBtB"}
@@ -0,0 +1,36 @@
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
+ * Terms and what they are — a record's facts, a product's specifications —
7
+ * as a real `<dl>`, so each value is announced with the term it belongs to.
8
+ * Two columns where there is room, stacked where there is not. Server-safe.
9
+ */ export function DescriptionList(_0) {
10
+ let { items, className } = _0, props = _object_without_properties_loose(_0, [
11
+ "items",
12
+ "className"
13
+ ]);
14
+ return /*#__PURE__*/ _jsx("dl", _extends({
15
+ className: cn('m-0 sm:grid-cols-[minmax(0,1fr)_minmax(0,2fr)] grid grid-cols-1 gap-x-m gap-y-2xs text-step-sm', className)
16
+ }, props, {
17
+ children: items.map((item, index)=>{
18
+ var _item_key;
19
+ return /*#__PURE__*/ _jsxs("div", {
20
+ className: "contents",
21
+ children: [
22
+ /*#__PURE__*/ _jsx("dt", {
23
+ className: "font-medium text-content-muted",
24
+ children: item.term
25
+ }),
26
+ /*#__PURE__*/ _jsx("dd", {
27
+ className: "m-0 text-content",
28
+ children: item.description
29
+ })
30
+ ]
31
+ }, (_item_key = item.key) != null ? _item_key : index);
32
+ })
33
+ }));
34
+ }
35
+
36
+ //# sourceMappingURL=description-list.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/ui/molecules/description-list/description-list.tsx"],"sourcesContent":["import type { ComponentPropsWithoutRef, ReactNode } from 'react';\n\nimport { cn } from '../../utils/cn.js';\n\nexport interface DescriptionListItem {\n /** A stable key; the term itself when it is unique. */\n readonly key?: string;\n readonly term: ReactNode;\n readonly description: ReactNode;\n}\n\nexport interface DescriptionListProps extends Omit<\n ComponentPropsWithoutRef<'dl'>,\n 'children'\n> {\n items: readonly DescriptionListItem[];\n}\n\n/**\n * Terms and what they are — a record's facts, a product's specifications —\n * as a real `<dl>`, so each value is announced with the term it belongs to.\n * Two columns where there is room, stacked where there is not. Server-safe.\n */\nexport function DescriptionList({\n items,\n className,\n ...props\n}: DescriptionListProps) {\n return (\n <dl\n className={cn(\n 'm-0 sm:grid-cols-[minmax(0,1fr)_minmax(0,2fr)] grid grid-cols-1 gap-x-m gap-y-2xs text-step-sm',\n className,\n )}\n {...props}\n >\n {items.map((item, index) => (\n <div key={item.key ?? index} className=\"contents\">\n <dt className=\"font-medium text-content-muted\">{item.term}</dt>\n <dd className=\"m-0 text-content\">{item.description}</dd>\n </div>\n ))}\n </dl>\n );\n}\n"],"names":["cn","DescriptionList","items","className","props","dl","map","item","index","div","dt","term","dd","description","key"],"mappings":";;;AAEA,SAASA,EAAE,QAAQ,oBAAoB;AAgBvC;;;;CAIC,GACD,OAAO,SAASC,gBAAgB,EAIT;QAJS,EAC9BC,KAAK,EACLC,SAAS,EAEY,OADlBC;;;;IAEH,qBACE,KAACC;QACCF,WAAWH,GACT,kGACAG;OAEEC;kBAEHF,MAAMI,GAAG,CAAC,CAACC,MAAMC;gBACND;iCAAV,MAACE;gBAA4BN,WAAU;;kCACrC,KAACO;wBAAGP,WAAU;kCAAkCI,KAAKI,IAAI;;kCACzD,KAACC;wBAAGT,WAAU;kCAAoBI,KAAKM,WAAW;;;gBAF1CN,YAAAA,KAAKO,GAAG,YAARP,YAAYC;;;AAO9B"}
@@ -0,0 +1,2 @@
1
+ export * from './description-list.js';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/ui/molecules/description-list/index.ts"],"names":[],"mappings":"AAAA,cAAc,uBAAuB,CAAC"}
@@ -0,0 +1,3 @@
1
+ export * from './description-list.js';
2
+
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/ui/molecules/description-list/index.ts"],"sourcesContent":["export * from './description-list.js';\n"],"names":[],"mappings":"AAAA,cAAc,wBAAwB"}
@@ -18,11 +18,11 @@ import { cn } from '../../utils/cn.js';
18
18
  return /*#__PURE__*/ _jsxs(Dialog, {
19
19
  open: open,
20
20
  onClose: onClose,
21
- className: "relative z-50",
21
+ className: "relative z-(--z-overlay)",
22
22
  children: [
23
23
  /*#__PURE__*/ _jsx("div", {
24
24
  "aria-hidden": true,
25
- className: "inset-0 bg-black/40 fixed"
25
+ className: "inset-0 fixed bg-scrim"
26
26
  }),
27
27
  /*#__PURE__*/ _jsx("div", {
28
28
  className: "inset-0 fixed flex",
@@ -30,7 +30,7 @@ import { cn } from '../../utils/cn.js';
30
30
  "data-testid": "drawer",
31
31
  className: cn(// 200ms is `--default-transition-duration`, the beat every other
32
32
  // transition in the system already uses.
33
- 'w-72 flex max-w-[85vw] flex-col gap-m overflow-y-auto border-r border-border bg-surface-elevated p-s transition duration-200', className),
33
+ 'w-72 flex max-w-(--overlay-max-inline) flex-col gap-m overflow-y-auto border-r border-border bg-surface-elevated p-s transition duration-200', className),
34
34
  children: [
35
35
  /*#__PURE__*/ _jsxs(DialogTitle, {
36
36
  className: "flex items-center justify-between gap-2xs text-step-1 font-semibold text-content",
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/ui/molecules/drawer/drawer.tsx"],"sourcesContent":["'use client';\n\nimport { Dialog, DialogPanel, DialogTitle } from '@headlessui/react';\nimport type { ReactNode } from 'react';\n\nimport { Button } from '../../atoms/button/index.js';\nimport { cn } from '../../utils/cn.js';\n\nexport interface DrawerProps {\n open: boolean;\n onClose: () => void;\n /** Names the dialog. A dialog with no accessible name is announced as \"dialog\". */\n title: ReactNode;\n /** Accessible name for the close control. */\n closeLabel: string;\n children: ReactNode;\n className?: string;\n}\n\n/**\n * An off-canvas panel anchored to the inline start of the viewport.\n *\n * Built on Headless UI's `Dialog`, like {@link ConfirmDialog} and the entity link\n * picker, so the focus trap, `Escape`, the backdrop click and focus restoration\n * to the trigger are the library's rather than four hand-written behaviours that\n * each have to be got right — and a drawer that traps focus badly is worse than\n * no drawer, because a keyboard visitor cannot leave it.\n *\n * It carries no viewport logic. *When* a drawer is the right shape is the page\n * shell's decision (`useViewportMode`); this is only the shape.\n */\nexport function Drawer({\n open,\n onClose,\n title,\n closeLabel,\n children,\n className,\n}: DrawerProps) {\n return (\n <Dialog open={open} onClose={onClose} className=\"relative z-50\">\n <div aria-hidden className=\"inset-0 bg-black/40 fixed\" />\n <div className=\"inset-0 fixed flex\">\n <DialogPanel\n data-testid=\"drawer\"\n className={cn(\n // 200ms is `--default-transition-duration`, the beat every other\n // transition in the system already uses.\n 'w-72 flex max-w-[85vw] flex-col gap-m overflow-y-auto border-r border-border bg-surface-elevated p-s transition duration-200',\n className,\n )}\n >\n <DialogTitle className=\"flex items-center justify-between gap-2xs text-step-1 font-semibold text-content\">\n {title}\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n aria-label={closeLabel}\n onClick={onClose}\n >\n <span aria-hidden=\"true\">✕</span>\n </Button>\n </DialogTitle>\n {children}\n </DialogPanel>\n </div>\n </Dialog>\n );\n}\n"],"names":["Dialog","DialogPanel","DialogTitle","Button","cn","Drawer","open","onClose","title","closeLabel","children","className","div","aria-hidden","data-testid","type","variant","size","aria-label","onClick","span"],"mappings":"AAAA;;AAEA,SAASA,MAAM,EAAEC,WAAW,EAAEC,WAAW,QAAQ,oBAAoB;AAGrE,SAASC,MAAM,QAAQ,8BAA8B;AACrD,SAASC,EAAE,QAAQ,oBAAoB;AAavC;;;;;;;;;;;CAWC,GACD,OAAO,SAASC,OAAO,EACrBC,IAAI,EACJC,OAAO,EACPC,KAAK,EACLC,UAAU,EACVC,QAAQ,EACRC,SAAS,EACG;IACZ,qBACE,MAACX;QAAOM,MAAMA;QAAMC,SAASA;QAASI,WAAU;;0BAC9C,KAACC;gBAAIC,aAAW;gBAACF,WAAU;;0BAC3B,KAACC;gBAAID,WAAU;0BACb,cAAA,MAACV;oBACCa,eAAY;oBACZH,WAAWP,GACT,iEAAiE;oBACjE,yCAAyC;oBACzC,gIACAO;;sCAGF,MAACT;4BAAYS,WAAU;;gCACpBH;8CACD,KAACL;oCACCY,MAAK;oCACLC,SAAQ;oCACRC,MAAK;oCACLC,cAAYT;oCACZU,SAASZ;8CAET,cAAA,KAACa;wCAAKP,eAAY;kDAAO;;;;;wBAG5BH;;;;;;AAKX"}
1
+ {"version":3,"sources":["../../../../src/ui/molecules/drawer/drawer.tsx"],"sourcesContent":["'use client';\n\nimport { Dialog, DialogPanel, DialogTitle } from '@headlessui/react';\nimport type { ReactNode } from 'react';\n\nimport { Button } from '../../atoms/button/index.js';\nimport { cn } from '../../utils/cn.js';\n\nexport interface DrawerProps {\n open: boolean;\n onClose: () => void;\n /** Names the dialog. A dialog with no accessible name is announced as \"dialog\". */\n title: ReactNode;\n /** Accessible name for the close control. */\n closeLabel: string;\n children: ReactNode;\n className?: string;\n}\n\n/**\n * An off-canvas panel anchored to the inline start of the viewport.\n *\n * Built on Headless UI's `Dialog`, like {@link ConfirmDialog} and the entity link\n * picker, so the focus trap, `Escape`, the backdrop click and focus restoration\n * to the trigger are the library's rather than four hand-written behaviours that\n * each have to be got right — and a drawer that traps focus badly is worse than\n * no drawer, because a keyboard visitor cannot leave it.\n *\n * It carries no viewport logic. *When* a drawer is the right shape is the page\n * shell's decision (`useViewportMode`); this is only the shape.\n */\nexport function Drawer({\n open,\n onClose,\n title,\n closeLabel,\n children,\n className,\n}: DrawerProps) {\n return (\n <Dialog open={open} onClose={onClose} className=\"relative z-(--z-overlay)\">\n <div aria-hidden className=\"inset-0 fixed bg-scrim\" />\n <div className=\"inset-0 fixed flex\">\n <DialogPanel\n data-testid=\"drawer\"\n className={cn(\n // 200ms is `--default-transition-duration`, the beat every other\n // transition in the system already uses.\n 'w-72 flex max-w-(--overlay-max-inline) flex-col gap-m overflow-y-auto border-r border-border bg-surface-elevated p-s transition duration-200',\n className,\n )}\n >\n <DialogTitle className=\"flex items-center justify-between gap-2xs text-step-1 font-semibold text-content\">\n {title}\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n aria-label={closeLabel}\n onClick={onClose}\n >\n <span aria-hidden=\"true\">✕</span>\n </Button>\n </DialogTitle>\n {children}\n </DialogPanel>\n </div>\n </Dialog>\n );\n}\n"],"names":["Dialog","DialogPanel","DialogTitle","Button","cn","Drawer","open","onClose","title","closeLabel","children","className","div","aria-hidden","data-testid","type","variant","size","aria-label","onClick","span"],"mappings":"AAAA;;AAEA,SAASA,MAAM,EAAEC,WAAW,EAAEC,WAAW,QAAQ,oBAAoB;AAGrE,SAASC,MAAM,QAAQ,8BAA8B;AACrD,SAASC,EAAE,QAAQ,oBAAoB;AAavC;;;;;;;;;;;CAWC,GACD,OAAO,SAASC,OAAO,EACrBC,IAAI,EACJC,OAAO,EACPC,KAAK,EACLC,UAAU,EACVC,QAAQ,EACRC,SAAS,EACG;IACZ,qBACE,MAACX;QAAOM,MAAMA;QAAMC,SAASA;QAASI,WAAU;;0BAC9C,KAACC;gBAAIC,aAAW;gBAACF,WAAU;;0BAC3B,KAACC;gBAAID,WAAU;0BACb,cAAA,MAACV;oBACCa,eAAY;oBACZH,WAAWP,GACT,iEAAiE;oBACjE,yCAAyC;oBACzC,gJACAO;;sCAGF,MAACT;4BAAYS,WAAU;;gCACpBH;8CACD,KAACL;oCACCY,MAAK;oCACLC,SAAQ;oCACRC,MAAK;oCACLC,cAAYT;oCACZU,SAASZ;8CAET,cAAA,KAACa;wCAAKP,eAAY;kDAAO;;;;;wBAG5BH;;;;;;AAKX"}