@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,29 +1,68 @@
1
- import type { ComponentPropsWithoutRef } from 'react';
2
- export type TabStripProps = ComponentPropsWithoutRef<'div'>;
1
+ import { type ComponentPropsWithoutRef, type ReactNode } from 'react';
2
+ export interface TabStripProps extends Omit<ComponentPropsWithoutRef<'div'>, 'children'> {
3
+ /** The {@link Tab}s, in order. */
4
+ children?: ReactNode;
5
+ /** The tablist's accessible name; the controls catalog's `tabs.list` when omitted. */
6
+ label?: string;
7
+ /**
8
+ * What sits after the tabs — a {@link TabAddButton}. It is outside the
9
+ * tablist, because a tablist may own nothing but tabs.
10
+ */
11
+ actions?: ReactNode;
12
+ }
3
13
  /**
4
- * The workspace tab strip: a horizontally scrolling row of {@link Tab}s sitting
5
- * on the workspace surface. Presentational only — the open set, order, and
6
- * active tab come from the caller (the tabs store lives in the shell).
14
+ * The workspace tab strip, on the WAI-ARIA tabs pattern: one Tab stop for the
15
+ * whole list, Arrow Left/Right (wrapping), Home and End move between tabs, and
16
+ * Enter or Space activates the focused one — activation is manual, because a
17
+ * tab's body is a whole screen and rendering every one an arrow passes over is
18
+ * work nobody asked for. Delete closes a closable tab (see {@link Tab}).
19
+ *
20
+ * Presentational: the open set, the order and the active tab come from the
21
+ * caller. Each tab controls one {@link TabPanel}, which the caller renders.
22
+ * Below the width of its tabs the list scrolls on its own, so the strip
23
+ * reflows at 320px rather than widening the page.
7
24
  */
8
- export declare function TabStrip({ className, children, ...props }: TabStripProps): import("react").JSX.Element;
25
+ export declare function TabStrip({ className, children, label, actions, ...props }: TabStripProps): import("react").JSX.Element;
9
26
  /** `dirty` = unsaved draft; `saving` = autosave in flight; `error` = save failed. */
10
27
  export type TabState = 'idle' | 'dirty' | 'saving' | 'error';
11
28
  export interface TabProps {
29
+ /** The tab's element id, which its {@link TabPanel} is labelled by. */
30
+ id: string;
12
31
  label: string;
32
+ /** The id of the {@link TabPanel} this tab shows, when it is the active one. */
33
+ controls?: string;
13
34
  active?: boolean;
14
35
  state?: TabState;
15
36
  onSelect?: () => void;
37
+ /** Makes the tab closable: by the × beside it, or Delete while it has focus. */
16
38
  onClose?: () => void;
17
39
  className?: string;
40
+ /** Set by {@link TabStrip} on the first tab when none is active. */
41
+ tabStop?: boolean;
42
+ }
43
+ /**
44
+ * One tab. `role="tab"` sits on the button itself, so the tab is a single
45
+ * interactive element; the close × beside it is a pointer convenience only —
46
+ * hidden from assistive technology and out of the Tab order — and Delete on the
47
+ * focused tab is its keyboard equivalent, announced through `aria-keyshortcuts`.
48
+ *
49
+ * The active tab lifts onto the surface (`bg-surface-elevated` + `-mb-px`, so
50
+ * its base dissolves into the content plane below), and a non-idle tab shows
51
+ * the autosave dot and its name says the same thing in words, since a dot alone is
52
+ * colour carrying meaning (WCAG 1.4.1).
53
+ */
54
+ export declare function Tab({ id, label, controls, active, state, onSelect, onClose, className, tabStop, }: TabProps): import("react").JSX.Element;
55
+ export interface TabPanelProps extends ComponentPropsWithoutRef<'div'> {
56
+ id: string;
57
+ /** The id of the {@link Tab} that shows this panel. */
58
+ labelledBy?: string;
18
59
  }
19
60
  /**
20
- * One tab. The active tab lifts onto the surface (`bg-surface-elevated` +
21
- * `-mb-px` so its base dissolves into the content plane below — the seam), and
22
- * a non-idle tab shows the autosave dot: it breathes while `saving`, turns
23
- * `danger` on `error`. The one place the chrome gets loud, on purpose.
61
+ * The region a tab shows. Focusable, as the pattern asks, so a keyboard user
62
+ * can reach a panel whose content has nothing focusable of its own.
24
63
  */
25
- export declare function Tab({ label, active, state, onSelect, onClose, className, }: TabProps): import("react").JSX.Element;
64
+ export declare function TabPanel({ labelledBy, className, ...props }: TabPanelProps): import("react").JSX.Element;
26
65
  export type TabAddButtonProps = ComponentPropsWithoutRef<'button'>;
27
- /** The "+" that opens a new tab. */
66
+ /** The "+" that opens a new tab. Pass it as {@link TabStrip}'s `actions`. */
28
67
  export declare function TabAddButton({ className, ...props }: TabAddButtonProps): import("react").JSX.Element;
29
68
  //# sourceMappingURL=tab-strip.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"tab-strip.d.ts","sourceRoot":"","sources":["../../../../src/ui/molecules/tab-strip/tab-strip.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,OAAO,CAAC;AAKtD,MAAM,MAAM,aAAa,GAAG,wBAAwB,CAAC,KAAK,CAAC,CAAC;AAE5D;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,EAAE,SAAS,EAAE,QAAQ,EAAE,GAAG,KAAK,EAAE,EAAE,aAAa,+BAaxE;AAED,qFAAqF;AACrF,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG,OAAO,GAAG,QAAQ,GAAG,OAAO,CAAC;AAE7D,MAAM,WAAW,QAAQ;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,QAAQ,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;GAKG;AACH,wBAAgB,GAAG,CAAC,EAClB,KAAK,EACL,MAAc,EACd,KAAc,EACd,QAAQ,EACR,OAAO,EACP,SAAS,GACV,EAAE,QAAQ,+BAyDV;AAED,MAAM,MAAM,iBAAiB,GAAG,wBAAwB,CAAC,QAAQ,CAAC,CAAC;AAEnE,oCAAoC;AACpC,wBAAgB,YAAY,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,iBAAiB,+BAkBtE"}
1
+ {"version":3,"file":"tab-strip.d.ts","sourceRoot":"","sources":["../../../../src/ui/molecules/tab-strip/tab-strip.tsx"],"names":[],"mappings":"AAEA,OAAO,EAGL,KAAK,wBAAwB,EAI7B,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAKf,MAAM,WAAW,aAAc,SAAQ,IAAI,CACzC,wBAAwB,CAAC,KAAK,CAAC,EAC/B,UAAU,CACX;IACC,kCAAkC;IAClC,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,sFAAsF;IACtF,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;OAGG;IACH,OAAO,CAAC,EAAE,SAAS,CAAC;CACrB;AAuBD;;;;;;;;;;;GAWG;AACH,wBAAgB,QAAQ,CAAC,EACvB,SAAS,EACT,QAAQ,EACR,KAAK,EACL,OAAO,EACP,GAAG,KAAK,EACT,EAAE,aAAa,+BAmCf;AAED,qFAAqF;AACrF,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG,OAAO,GAAG,QAAQ,GAAG,OAAO,CAAC;AAE7D,MAAM,WAAW,QAAQ;IACvB,uEAAuE;IACvE,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,gFAAgF;IAChF,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,QAAQ,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB,gFAAgF;IAChF,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,oEAAoE;IACpE,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,GAAG,CAAC,EAClB,EAAE,EACF,KAAK,EACL,QAAQ,EACR,MAAc,EACd,KAAc,EACd,QAAQ,EACR,OAAO,EACP,SAAS,EACT,OAAgB,GACjB,EAAE,QAAQ,+BAgFV;AAED,MAAM,WAAW,aAAc,SAAQ,wBAAwB,CAAC,KAAK,CAAC;IACpE,EAAE,EAAE,MAAM,CAAC;IACX,uDAAuD;IACvD,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,EAAE,UAAU,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,aAAa,+BAY1E;AAED,MAAM,MAAM,iBAAiB,GAAG,wBAAwB,CAAC,QAAQ,CAAC,CAAC;AAEnE,6EAA6E;AAC7E,wBAAgB,YAAY,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,iBAAiB,+BAkBtE"}
@@ -2,67 +2,158 @@
2
2
  import { _ as _extends } from "@swc/helpers/_/_extends";
3
3
  import { _ as _object_without_properties_loose } from "@swc/helpers/_/_object_without_properties_loose";
4
4
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
5
+ import { Children, cloneElement, isValidElement } from 'react';
5
6
  import { useT } from '../../../i18n/index.js';
6
7
  import { cn } from '../../utils/cn.js';
7
8
  /**
8
- * The workspace tab strip: a horizontally scrolling row of {@link Tab}s sitting
9
- * on the workspace surface. Presentational only — the open set, order, and
10
- * active tab come from the caller (the tabs store lives in the shell).
9
+ * Arrow Left/Right (wrapping), Home and End move focus to a sibling tab in the
10
+ * same tablist. Each tab handles its own keys, so the tablist stays a plain
11
+ * container and the keyboard model holds for a Tab rendered anywhere.
12
+ */ function moveFocus(event) {
13
+ var _all_to;
14
+ const list = event.currentTarget.closest('[role="tablist"]');
15
+ if (!list) return false;
16
+ const all = [
17
+ ...list.querySelectorAll('[role="tab"]')
18
+ ];
19
+ const from = all.indexOf(event.currentTarget);
20
+ const to = {
21
+ ArrowRight: (from + 1) % all.length,
22
+ ArrowLeft: (from - 1 + all.length) % all.length,
23
+ Home: 0,
24
+ End: all.length - 1
25
+ }[event.key];
26
+ if (to === undefined) return false;
27
+ (_all_to = all[to]) == null ? void 0 : _all_to.focus();
28
+ return true;
29
+ }
30
+ /**
31
+ * The workspace tab strip, on the WAI-ARIA tabs pattern: one Tab stop for the
32
+ * whole list, Arrow Left/Right (wrapping), Home and End move between tabs, and
33
+ * Enter or Space activates the focused one — activation is manual, because a
34
+ * tab's body is a whole screen and rendering every one an arrow passes over is
35
+ * work nobody asked for. Delete closes a closable tab (see {@link Tab}).
36
+ *
37
+ * Presentational: the open set, the order and the active tab come from the
38
+ * caller. Each tab controls one {@link TabPanel}, which the caller renders.
39
+ * Below the width of its tabs the list scrolls on its own, so the strip
40
+ * reflows at 320px rather than widening the page.
11
41
  */ export function TabStrip(_0) {
12
- let { className, children } = _0, props = _object_without_properties_loose(_0, [
42
+ let { className, children, label, actions } = _0, props = _object_without_properties_loose(_0, [
13
43
  "className",
14
- "children"
44
+ "children",
45
+ "label",
46
+ "actions"
15
47
  ]);
16
- return /*#__PURE__*/ _jsx("div", _extends({
17
- role: "tablist",
18
- className: cn('flex items-end gap-3xs overflow-x-auto border-b border-border bg-surface px-2xs', className)
48
+ const t = useT();
49
+ const tabs = Children.toArray(children);
50
+ // Roving tabindex: the active tab is the list's Tab stop, or the first tab
51
+ // when none is active (a dead link shows no tab as its own).
52
+ const anyActive = tabs.some((tab)=>/*#__PURE__*/ isValidElement(tab) && tab.props.active === true);
53
+ const items = anyActive ? tabs : tabs.map((tab, index)=>index === 0 && /*#__PURE__*/ isValidElement(tab) ? /*#__PURE__*/ cloneElement(tab, {
54
+ tabStop: true
55
+ }) : tab);
56
+ return /*#__PURE__*/ _jsxs("div", _extends({
57
+ className: cn('min-w-0 flex w-full items-end gap-3xs border-b border-border bg-surface px-2xs', className)
19
58
  }, props, {
20
- children: children
59
+ children: [
60
+ /*#__PURE__*/ _jsx("div", {
61
+ role: "tablist",
62
+ "aria-label": label != null ? label : t('tabs.list'),
63
+ "aria-orientation": "horizontal",
64
+ className: "min-w-0 flex flex-1 items-end gap-3xs overflow-x-auto",
65
+ children: items
66
+ }),
67
+ actions
68
+ ]
21
69
  }));
22
70
  }
23
71
  /**
24
- * One tab. The active tab lifts onto the surface (`bg-surface-elevated` +
25
- * `-mb-px` so its base dissolves into the content plane below — the seam), and
26
- * a non-idle tab shows the autosave dot: it breathes while `saving`, turns
27
- * `danger` on `error`. The one place the chrome gets loud, on purpose.
28
- */ export function Tab({ label, active = false, state = 'idle', onSelect, onClose, className }) {
72
+ * One tab. `role="tab"` sits on the button itself, so the tab is a single
73
+ * interactive element; the close × beside it is a pointer convenience only —
74
+ * hidden from assistive technology and out of the Tab order — and Delete on the
75
+ * focused tab is its keyboard equivalent, announced through `aria-keyshortcuts`.
76
+ *
77
+ * The active tab lifts onto the surface (`bg-surface-elevated` + `-mb-px`, so
78
+ * its base dissolves into the content plane below), and a non-idle tab shows
79
+ * the autosave dot and its name says the same thing in words, since a dot alone is
80
+ * colour carrying meaning (WCAG 1.4.1).
81
+ */ export function Tab({ id, label, controls, active = false, state = 'idle', onSelect, onClose, className, tabStop = active }) {
29
82
  const t = useT();
30
83
  return /*#__PURE__*/ _jsxs("div", {
31
- role: "tab",
32
- "aria-selected": active,
33
- className: cn('group relative flex items-center gap-2xs rounded-t-md px-s py-2xs text-step-sm', 'transition duration-200 ease-smooth', active ? '-mb-px bg-surface-elevated font-medium text-content shadow-edge' : 'text-content-muted hover:bg-surface-elevated/60', state === 'error' && 'bg-danger-subtle text-danger', className),
84
+ role: "none",
85
+ className: cn('group relative flex shrink-0 items-center rounded-t-md text-step-sm', 'transition duration-200 ease-smooth', active ? '-mb-px bg-surface-elevated font-medium text-content shadow-edge' : 'text-content-muted hover:bg-surface-elevated/60', state === 'error' && 'bg-danger-subtle text-danger', className),
34
86
  children: [
35
87
  active && /*#__PURE__*/ _jsx("span", {
36
88
  "aria-hidden": "true",
37
- className: "inset-x-0 top-0 absolute h-[2px] rounded-full bg-accent"
89
+ className: "inset-x-0 top-0 h-0.5 pointer-events-none absolute rounded-full bg-accent"
38
90
  }),
39
- /*#__PURE__*/ _jsx("button", {
91
+ /*#__PURE__*/ _jsxs("button", {
40
92
  type: "button",
93
+ role: "tab",
94
+ id: id,
95
+ "aria-selected": active,
96
+ "aria-controls": active ? controls : undefined,
97
+ "aria-keyshortcuts": onClose ? 'Delete' : undefined,
98
+ tabIndex: tabStop ? 0 : -1,
41
99
  onClick: onSelect,
42
- className: "max-w-[12rem] truncate focus-ring",
43
- children: label
44
- }),
45
- state !== 'idle' && /*#__PURE__*/ _jsx("span", {
46
- "data-testid": "tab-indicator",
47
- "aria-hidden": "true",
48
- className: cn('size-[6px] shrink-0 rounded-full', state === 'error' ? 'bg-danger' : 'bg-accent', state === 'saving' && 'animate-pulse motion-reduce:animate-none')
100
+ "aria-label": state === 'idle' ? undefined : t('tabs.withState', {
101
+ label,
102
+ state: t(`tabs.${state}`)
103
+ }),
104
+ onKeyDown: (event)=>{
105
+ if (event.key === 'Delete' && onClose) {
106
+ event.preventDefault();
107
+ onClose();
108
+ } else if (moveFocus(event)) {
109
+ event.preventDefault();
110
+ }
111
+ },
112
+ className: cn('max-w-48 flex min-h-(--target-min) items-center gap-2xs rounded-t-md py-2xs pl-s focus-ring', onClose ? 'pr-3xs' : 'pr-s'),
113
+ children: [
114
+ /*#__PURE__*/ _jsx("span", {
115
+ className: "truncate",
116
+ children: label
117
+ }),
118
+ state !== 'idle' && /*#__PURE__*/ _jsx("span", {
119
+ "data-testid": "tab-indicator",
120
+ "aria-hidden": "true",
121
+ className: cn('size-1.5 shrink-0 rounded-full', state === 'error' ? 'bg-danger' : 'bg-accent', state === 'saving' && 'animate-pulse motion-reduce:animate-none')
122
+ })
123
+ ]
49
124
  }),
50
125
  onClose && /*#__PURE__*/ _jsx("button", {
51
126
  type: "button",
52
- "aria-label": t('tabs.close', {
127
+ "aria-hidden": "true",
128
+ tabIndex: -1,
129
+ title: t('tabs.close', {
53
130
  label
54
131
  }),
55
132
  onClick: onClose,
56
- className: cn('rounded ml-2xs p-3xs text-content-muted opacity-0 focus-ring transition', 'group-hover:opacity-100 hover:bg-surface hover:text-content focus:opacity-100', active && 'opacity-100'),
57
- children: /*#__PURE__*/ _jsx("span", {
58
- "aria-hidden": "true",
59
- children: "×"
60
- })
133
+ className: cn('rounded mr-3xs flex min-h-(--target-min) min-w-(--target-min) items-center justify-center text-content-muted opacity-0 transition', 'group-focus-within:opacity-100 group-hover:opacity-100 hover:bg-surface hover:text-content', active && 'opacity-100'),
134
+ children: "×"
61
135
  })
62
136
  ]
63
137
  });
64
138
  }
65
- /** The "+" that opens a new tab. */ export function TabAddButton(_0) {
139
+ /**
140
+ * The region a tab shows. Focusable, as the pattern asks, so a keyboard user
141
+ * can reach a panel whose content has nothing focusable of its own.
142
+ */ export function TabPanel(_0) {
143
+ let { labelledBy, className } = _0, props = _object_without_properties_loose(_0, [
144
+ "labelledBy",
145
+ "className"
146
+ ]);
147
+ return /*#__PURE__*/ _jsx("div", _extends({
148
+ role: "tabpanel",
149
+ // The tabs pattern makes the panel itself a Tab stop.
150
+ // eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex
151
+ tabIndex: 0,
152
+ "aria-labelledby": labelledBy,
153
+ className: cn('focus-ring', className)
154
+ }, props));
155
+ }
156
+ /** The "+" that opens a new tab. Pass it as {@link TabStrip}'s `actions`. */ export function TabAddButton(_0) {
66
157
  let { className } = _0, props = _object_without_properties_loose(_0, [
67
158
  "className"
68
159
  ]);
@@ -70,7 +161,7 @@ import { cn } from '../../utils/cn.js';
70
161
  return /*#__PURE__*/ _jsx("button", _extends({
71
162
  type: "button",
72
163
  "aria-label": t('tabs.new'),
73
- className: cn('mb-3xs shrink-0 rounded-md px-2xs py-3xs text-step-sm text-content-muted', 'transition hover:bg-surface-elevated hover:text-content', 'focus-ring', className)
164
+ className: cn('mb-3xs flex min-h-(--target-min) min-w-(--target-min) shrink-0 items-center justify-center rounded-md px-2xs text-step-sm text-content-muted', 'transition hover:bg-surface-elevated hover:text-content', 'focus-ring', className)
74
165
  }, props, {
75
166
  children: /*#__PURE__*/ _jsx("span", {
76
167
  "aria-hidden": "true",
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/ui/molecules/tab-strip/tab-strip.tsx"],"sourcesContent":["'use client';\n\nimport type { ComponentPropsWithoutRef } from 'react';\n\nimport { useT } from '../../../i18n/index.js';\nimport { cn } from '../../utils/cn.js';\n\nexport type TabStripProps = ComponentPropsWithoutRef<'div'>;\n\n/**\n * The workspace tab strip: a horizontally scrolling row of {@link Tab}s sitting\n * on the workspace surface. Presentational only — the open set, order, and\n * active tab come from the caller (the tabs store lives in the shell).\n */\nexport function TabStrip({ className, children, ...props }: TabStripProps) {\n return (\n <div\n role=\"tablist\"\n className={cn(\n 'flex items-end gap-3xs overflow-x-auto border-b border-border bg-surface px-2xs',\n className,\n )}\n {...props}\n >\n {children}\n </div>\n );\n}\n\n/** `dirty` = unsaved draft; `saving` = autosave in flight; `error` = save failed. */\nexport type TabState = 'idle' | 'dirty' | 'saving' | 'error';\n\nexport interface TabProps {\n label: string;\n active?: boolean;\n state?: TabState;\n onSelect?: () => void;\n onClose?: () => void;\n className?: string;\n}\n\n/**\n * One tab. The active tab lifts onto the surface (`bg-surface-elevated` +\n * `-mb-px` so its base dissolves into the content plane below — the seam), and\n * a non-idle tab shows the autosave dot: it breathes while `saving`, turns\n * `danger` on `error`. The one place the chrome gets loud, on purpose.\n */\nexport function Tab({\n label,\n active = false,\n state = 'idle',\n onSelect,\n onClose,\n className,\n}: TabProps) {\n const t = useT();\n\n return (\n <div\n role=\"tab\"\n aria-selected={active}\n className={cn(\n 'group relative flex items-center gap-2xs rounded-t-md px-s py-2xs text-step-sm',\n 'transition duration-200 ease-smooth',\n active\n ? '-mb-px bg-surface-elevated font-medium text-content shadow-edge'\n : 'text-content-muted hover:bg-surface-elevated/60',\n state === 'error' && 'bg-danger-subtle text-danger',\n className,\n )}\n >\n {active && (\n <span\n aria-hidden=\"true\"\n className=\"inset-x-0 top-0 absolute h-[2px] rounded-full bg-accent\"\n />\n )}\n <button\n type=\"button\"\n onClick={onSelect}\n className=\"max-w-[12rem] truncate focus-ring\"\n >\n {label}\n </button>\n {state !== 'idle' && (\n <span\n data-testid=\"tab-indicator\"\n aria-hidden=\"true\"\n className={cn(\n 'size-[6px] shrink-0 rounded-full',\n state === 'error' ? 'bg-danger' : 'bg-accent',\n state === 'saving' && 'animate-pulse motion-reduce:animate-none',\n )}\n />\n )}\n {onClose && (\n <button\n type=\"button\"\n aria-label={t('tabs.close', { label })}\n onClick={onClose}\n className={cn(\n 'rounded ml-2xs p-3xs text-content-muted opacity-0 focus-ring transition',\n 'group-hover:opacity-100 hover:bg-surface hover:text-content focus:opacity-100',\n active && 'opacity-100',\n )}\n >\n <span aria-hidden=\"true\">×</span>\n </button>\n )}\n </div>\n );\n}\n\nexport type TabAddButtonProps = ComponentPropsWithoutRef<'button'>;\n\n/** The \"+\" that opens a new tab. */\nexport function TabAddButton({ className, ...props }: TabAddButtonProps) {\n const t = useT();\n\n return (\n <button\n type=\"button\"\n aria-label={t('tabs.new')}\n className={cn(\n 'mb-3xs shrink-0 rounded-md px-2xs py-3xs text-step-sm text-content-muted',\n 'transition hover:bg-surface-elevated hover:text-content',\n 'focus-ring',\n className,\n )}\n {...props}\n >\n <span aria-hidden=\"true\">+</span>\n </button>\n );\n}\n"],"names":["useT","cn","TabStrip","className","children","props","div","role","Tab","label","active","state","onSelect","onClose","t","aria-selected","span","aria-hidden","button","type","onClick","data-testid","aria-label","TabAddButton"],"mappings":"AAAA;;;;AAIA,SAASA,IAAI,QAAQ,yBAAyB;AAC9C,SAASC,EAAE,QAAQ,oBAAoB;AAIvC;;;;CAIC,GACD,OAAO,SAASC,SAAS,EAAgD;QAAhD,EAAEC,SAAS,EAAEC,QAAQ,EAA2B,OAAtBC;;;;IACjD,qBACE,KAACC;QACCC,MAAK;QACLJ,WAAWF,GACT,mFACAE;OAEEE;kBAEHD;;AAGP;AAcA;;;;;CAKC,GACD,OAAO,SAASI,IAAI,EAClBC,KAAK,EACLC,SAAS,KAAK,EACdC,QAAQ,MAAM,EACdC,QAAQ,EACRC,OAAO,EACPV,SAAS,EACA;IACT,MAAMW,IAAId;IAEV,qBACE,MAACM;QACCC,MAAK;QACLQ,iBAAeL;QACfP,WAAWF,GACT,kFACA,uCACAS,SACI,oEACA,mDACJC,UAAU,WAAW,gCACrBR;;YAGDO,wBACC,KAACM;gBACCC,eAAY;gBACZd,WAAU;;0BAGd,KAACe;gBACCC,MAAK;gBACLC,SAASR;gBACTT,WAAU;0BAETM;;YAEFE,UAAU,wBACT,KAACK;gBACCK,eAAY;gBACZJ,eAAY;gBACZd,WAAWF,GACT,oCACAU,UAAU,UAAU,cAAc,aAClCA,UAAU,YAAY;;YAI3BE,yBACC,KAACK;gBACCC,MAAK;gBACLG,cAAYR,EAAE,cAAc;oBAAEL;gBAAM;gBACpCW,SAASP;gBACTV,WAAWF,GACT,2EACA,iFACAS,UAAU;0BAGZ,cAAA,KAACM;oBAAKC,eAAY;8BAAO;;;;;AAKnC;AAIA,kCAAkC,GAClC,OAAO,SAASM,aAAa,EAA0C;QAA1C,EAAEpB,SAAS,EAA+B,OAA1BE;;;IAC3C,MAAMS,IAAId;IAEV,qBACE,KAACkB;QACCC,MAAK;QACLG,cAAYR,EAAE;QACdX,WAAWF,GACT,4EACA,2DACA,cACAE;OAEEE;kBAEJ,cAAA,KAACW;YAAKC,eAAY;sBAAO;;;AAG/B"}
1
+ {"version":3,"sources":["../../../../src/ui/molecules/tab-strip/tab-strip.tsx"],"sourcesContent":["'use client';\n\nimport {\n Children,\n cloneElement,\n type ComponentPropsWithoutRef,\n isValidElement,\n type KeyboardEvent,\n type ReactElement,\n type ReactNode,\n} from 'react';\n\nimport { useT } from '../../../i18n/index.js';\nimport { cn } from '../../utils/cn.js';\n\nexport interface TabStripProps extends Omit<\n ComponentPropsWithoutRef<'div'>,\n 'children'\n> {\n /** The {@link Tab}s, in order. */\n children?: ReactNode;\n /** The tablist's accessible name; the controls catalog's `tabs.list` when omitted. */\n label?: string;\n /**\n * What sits after the tabs — a {@link TabAddButton}. It is outside the\n * tablist, because a tablist may own nothing but tabs.\n */\n actions?: ReactNode;\n}\n\n/**\n * Arrow Left/Right (wrapping), Home and End move focus to a sibling tab in the\n * same tablist. Each tab handles its own keys, so the tablist stays a plain\n * container and the keyboard model holds for a Tab rendered anywhere.\n */\nfunction moveFocus(event: KeyboardEvent<HTMLButtonElement>): boolean {\n const list = event.currentTarget.closest('[role=\"tablist\"]');\n if (!list) return false;\n const all = [...list.querySelectorAll<HTMLElement>('[role=\"tab\"]')];\n const from = all.indexOf(event.currentTarget);\n const to = {\n ArrowRight: (from + 1) % all.length,\n ArrowLeft: (from - 1 + all.length) % all.length,\n Home: 0,\n End: all.length - 1,\n }[event.key];\n if (to === undefined) return false;\n all[to]?.focus();\n return true;\n}\n\n/**\n * The workspace tab strip, on the WAI-ARIA tabs pattern: one Tab stop for the\n * whole list, Arrow Left/Right (wrapping), Home and End move between tabs, and\n * Enter or Space activates the focused one — activation is manual, because a\n * tab's body is a whole screen and rendering every one an arrow passes over is\n * work nobody asked for. Delete closes a closable tab (see {@link Tab}).\n *\n * Presentational: the open set, the order and the active tab come from the\n * caller. Each tab controls one {@link TabPanel}, which the caller renders.\n * Below the width of its tabs the list scrolls on its own, so the strip\n * reflows at 320px rather than widening the page.\n */\nexport function TabStrip({\n className,\n children,\n label,\n actions,\n ...props\n}: TabStripProps) {\n const t = useT();\n const tabs = Children.toArray(children);\n // Roving tabindex: the active tab is the list's Tab stop, or the first tab\n // when none is active (a dead link shows no tab as its own).\n const anyActive = tabs.some(\n tab => isValidElement<TabProps>(tab) && tab.props.active === true,\n );\n const items = anyActive\n ? tabs\n : tabs.map((tab, index) =>\n index === 0 && isValidElement<TabProps>(tab)\n ? cloneElement(tab as ReactElement<TabProps>, { tabStop: true })\n : tab,\n );\n\n return (\n <div\n className={cn(\n 'min-w-0 flex w-full items-end gap-3xs border-b border-border bg-surface px-2xs',\n className,\n )}\n {...props}\n >\n <div\n role=\"tablist\"\n aria-label={label ?? t('tabs.list')}\n aria-orientation=\"horizontal\"\n className=\"min-w-0 flex flex-1 items-end gap-3xs overflow-x-auto\"\n >\n {items}\n </div>\n {actions}\n </div>\n );\n}\n\n/** `dirty` = unsaved draft; `saving` = autosave in flight; `error` = save failed. */\nexport type TabState = 'idle' | 'dirty' | 'saving' | 'error';\n\nexport interface TabProps {\n /** The tab's element id, which its {@link TabPanel} is labelled by. */\n id: string;\n label: string;\n /** The id of the {@link TabPanel} this tab shows, when it is the active one. */\n controls?: string;\n active?: boolean;\n state?: TabState;\n onSelect?: () => void;\n /** Makes the tab closable: by the × beside it, or Delete while it has focus. */\n onClose?: () => void;\n className?: string;\n /** Set by {@link TabStrip} on the first tab when none is active. */\n tabStop?: boolean;\n}\n\n/**\n * One tab. `role=\"tab\"` sits on the button itself, so the tab is a single\n * interactive element; the close × beside it is a pointer convenience only —\n * hidden from assistive technology and out of the Tab order — and Delete on the\n * focused tab is its keyboard equivalent, announced through `aria-keyshortcuts`.\n *\n * The active tab lifts onto the surface (`bg-surface-elevated` + `-mb-px`, so\n * its base dissolves into the content plane below), and a non-idle tab shows\n * the autosave dot and its name says the same thing in words, since a dot alone is\n * colour carrying meaning (WCAG 1.4.1).\n */\nexport function Tab({\n id,\n label,\n controls,\n active = false,\n state = 'idle',\n onSelect,\n onClose,\n className,\n tabStop = active,\n}: TabProps) {\n const t = useT();\n\n return (\n <div\n role=\"none\"\n className={cn(\n 'group relative flex shrink-0 items-center rounded-t-md text-step-sm',\n 'transition duration-200 ease-smooth',\n active\n ? '-mb-px bg-surface-elevated font-medium text-content shadow-edge'\n : 'text-content-muted hover:bg-surface-elevated/60',\n state === 'error' && 'bg-danger-subtle text-danger',\n className,\n )}\n >\n {active && (\n <span\n aria-hidden=\"true\"\n className=\"inset-x-0 top-0 h-0.5 pointer-events-none absolute rounded-full bg-accent\"\n />\n )}\n <button\n type=\"button\"\n role=\"tab\"\n id={id}\n aria-selected={active}\n aria-controls={active ? controls : undefined}\n aria-keyshortcuts={onClose ? 'Delete' : undefined}\n tabIndex={tabStop ? 0 : -1}\n onClick={onSelect}\n aria-label={\n state === 'idle'\n ? undefined\n : t('tabs.withState', { label, state: t(`tabs.${state}`) })\n }\n onKeyDown={event => {\n if (event.key === 'Delete' && onClose) {\n event.preventDefault();\n onClose();\n } else if (moveFocus(event)) {\n event.preventDefault();\n }\n }}\n className={cn(\n 'max-w-48 flex min-h-(--target-min) items-center gap-2xs rounded-t-md py-2xs pl-s focus-ring',\n onClose ? 'pr-3xs' : 'pr-s',\n )}\n >\n <span className=\"truncate\">{label}</span>\n {state !== 'idle' && (\n <span\n data-testid=\"tab-indicator\"\n aria-hidden=\"true\"\n className={cn(\n 'size-1.5 shrink-0 rounded-full',\n state === 'error' ? 'bg-danger' : 'bg-accent',\n state === 'saving' && 'animate-pulse motion-reduce:animate-none',\n )}\n />\n )}\n </button>\n {onClose && (\n <button\n type=\"button\"\n aria-hidden=\"true\"\n tabIndex={-1}\n title={t('tabs.close', { label })}\n onClick={onClose}\n className={cn(\n 'rounded mr-3xs flex min-h-(--target-min) min-w-(--target-min) items-center justify-center text-content-muted opacity-0 transition',\n 'group-focus-within:opacity-100 group-hover:opacity-100 hover:bg-surface hover:text-content',\n active && 'opacity-100',\n )}\n >\n ×\n </button>\n )}\n </div>\n );\n}\n\nexport interface TabPanelProps extends ComponentPropsWithoutRef<'div'> {\n id: string;\n /** The id of the {@link Tab} that shows this panel. */\n labelledBy?: string;\n}\n\n/**\n * The region a tab shows. Focusable, as the pattern asks, so a keyboard user\n * can reach a panel whose content has nothing focusable of its own.\n */\nexport function TabPanel({ labelledBy, className, ...props }: TabPanelProps) {\n return (\n <div\n role=\"tabpanel\"\n // The tabs pattern makes the panel itself a Tab stop.\n // eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex\n tabIndex={0}\n aria-labelledby={labelledBy}\n className={cn('focus-ring', className)}\n {...props}\n />\n );\n}\n\nexport type TabAddButtonProps = ComponentPropsWithoutRef<'button'>;\n\n/** The \"+\" that opens a new tab. Pass it as {@link TabStrip}'s `actions`. */\nexport function TabAddButton({ className, ...props }: TabAddButtonProps) {\n const t = useT();\n\n return (\n <button\n type=\"button\"\n aria-label={t('tabs.new')}\n className={cn(\n 'mb-3xs flex min-h-(--target-min) min-w-(--target-min) shrink-0 items-center justify-center rounded-md px-2xs text-step-sm text-content-muted',\n 'transition hover:bg-surface-elevated hover:text-content',\n 'focus-ring',\n className,\n )}\n {...props}\n >\n <span aria-hidden=\"true\">+</span>\n </button>\n );\n}\n"],"names":["Children","cloneElement","isValidElement","useT","cn","moveFocus","event","all","list","currentTarget","closest","querySelectorAll","from","indexOf","to","ArrowRight","length","ArrowLeft","Home","End","key","undefined","focus","TabStrip","className","children","label","actions","props","t","tabs","toArray","anyActive","some","tab","active","items","map","index","tabStop","div","role","aria-label","aria-orientation","Tab","id","controls","state","onSelect","onClose","span","aria-hidden","button","type","aria-selected","aria-controls","aria-keyshortcuts","tabIndex","onClick","onKeyDown","preventDefault","data-testid","title","TabPanel","labelledBy","aria-labelledby","TabAddButton"],"mappings":"AAAA;;;;AAEA,SACEA,QAAQ,EACRC,YAAY,EAEZC,cAAc,QAIT,QAAQ;AAEf,SAASC,IAAI,QAAQ,yBAAyB;AAC9C,SAASC,EAAE,QAAQ,oBAAoB;AAiBvC;;;;CAIC,GACD,SAASC,UAAUC,KAAuC;QAYxDC;IAXA,MAAMC,OAAOF,MAAMG,aAAa,CAACC,OAAO,CAAC;IACzC,IAAI,CAACF,MAAM,OAAO;IAClB,MAAMD,MAAM;WAAIC,KAAKG,gBAAgB,CAAc;KAAgB;IACnE,MAAMC,OAAOL,IAAIM,OAAO,CAACP,MAAMG,aAAa;IAC5C,MAAMK,KAAK;QACTC,YAAY,AAACH,CAAAA,OAAO,CAAA,IAAKL,IAAIS,MAAM;QACnCC,WAAW,AAACL,CAAAA,OAAO,IAAIL,IAAIS,MAAM,AAAD,IAAKT,IAAIS,MAAM;QAC/CE,MAAM;QACNC,KAAKZ,IAAIS,MAAM,GAAG;IACpB,CAAC,CAACV,MAAMc,GAAG,CAAC;IACZ,IAAIN,OAAOO,WAAW,OAAO;KAC7Bd,UAAAA,GAAG,CAACO,GAAG,qBAAPP,QAASe,KAAK;IACd,OAAO;AACT;AAEA;;;;;;;;;;;CAWC,GACD,OAAO,SAASC,SAAS,EAMT;QANS,EACvBC,SAAS,EACTC,QAAQ,EACRC,KAAK,EACLC,OAAO,EAEO,OADXC;;;;;;IAEH,MAAMC,IAAI1B;IACV,MAAM2B,OAAO9B,SAAS+B,OAAO,CAACN;IAC9B,2EAA2E;IAC3E,6DAA6D;IAC7D,MAAMO,YAAYF,KAAKG,IAAI,CACzBC,CAAAA,oBAAOhC,eAAyBgC,QAAQA,IAAIN,KAAK,CAACO,MAAM,KAAK;IAE/D,MAAMC,QAAQJ,YACVF,OACAA,KAAKO,GAAG,CAAC,CAACH,KAAKI,QACbA,UAAU,mBAAKpC,eAAyBgC,qBACpCjC,aAAaiC,KAA+B;YAAEK,SAAS;QAAK,KAC5DL;IAGV,qBACE,MAACM;QACChB,WAAWpB,GACT,kFACAoB;OAEEI;;0BAEJ,KAACY;gBACCC,MAAK;gBACLC,YAAU,EAAEhB,gBAAAA,QAASG,EAAE;gBACvBc,oBAAiB;gBACjBnB,WAAU;0BAETY;;YAEFT;;;AAGP;AAqBA;;;;;;;;;;CAUC,GACD,OAAO,SAASiB,IAAI,EAClBC,EAAE,EACFnB,KAAK,EACLoB,QAAQ,EACRX,SAAS,KAAK,EACdY,QAAQ,MAAM,EACdC,QAAQ,EACRC,OAAO,EACPzB,SAAS,EACTe,UAAUJ,MAAM,EACP;IACT,MAAMN,IAAI1B;IAEV,qBACE,MAACqC;QACCC,MAAK;QACLjB,WAAWpB,GACT,uEACA,uCACA+B,SACI,oEACA,mDACJY,UAAU,WAAW,gCACrBvB;;YAGDW,wBACC,KAACe;gBACCC,eAAY;gBACZ3B,WAAU;;0BAGd,MAAC4B;gBACCC,MAAK;gBACLZ,MAAK;gBACLI,IAAIA;gBACJS,iBAAenB;gBACfoB,iBAAepB,SAASW,WAAWzB;gBACnCmC,qBAAmBP,UAAU,WAAW5B;gBACxCoC,UAAUlB,UAAU,IAAI,CAAC;gBACzBmB,SAASV;gBACTN,cACEK,UAAU,SACN1B,YACAQ,EAAE,kBAAkB;oBAAEH;oBAAOqB,OAAOlB,EAAE,CAAC,KAAK,EAAEkB,OAAO;gBAAE;gBAE7DY,WAAWrD,CAAAA;oBACT,IAAIA,MAAMc,GAAG,KAAK,YAAY6B,SAAS;wBACrC3C,MAAMsD,cAAc;wBACpBX;oBACF,OAAO,IAAI5C,UAAUC,QAAQ;wBAC3BA,MAAMsD,cAAc;oBACtB;gBACF;gBACApC,WAAWpB,GACT,+FACA6C,UAAU,WAAW;;kCAGvB,KAACC;wBAAK1B,WAAU;kCAAYE;;oBAC3BqB,UAAU,wBACT,KAACG;wBACCW,eAAY;wBACZV,eAAY;wBACZ3B,WAAWpB,GACT,kCACA2C,UAAU,UAAU,cAAc,aAClCA,UAAU,YAAY;;;;YAK7BE,yBACC,KAACG;gBACCC,MAAK;gBACLF,eAAY;gBACZM,UAAU,CAAC;gBACXK,OAAOjC,EAAE,cAAc;oBAAEH;gBAAM;gBAC/BgC,SAAST;gBACTzB,WAAWpB,GACT,qIACA,8FACA+B,UAAU;0BAEb;;;;AAMT;AAQA;;;CAGC,GACD,OAAO,SAAS4B,SAAS,EAAkD;QAAlD,EAAEC,UAAU,EAAExC,SAAS,EAA2B,OAAtBI;;;;IACnD,qBACE,KAACY;QACCC,MAAK;QACL,sDAAsD;QACtD,+DAA+D;QAC/DgB,UAAU;QACVQ,mBAAiBD;QACjBxC,WAAWpB,GAAG,cAAcoB;OACxBI;AAGV;AAIA,2EAA2E,GAC3E,OAAO,SAASsC,aAAa,EAA0C;QAA1C,EAAE1C,SAAS,EAA+B,OAA1BI;;;IAC3C,MAAMC,IAAI1B;IAEV,qBACE,KAACiD;QACCC,MAAK;QACLX,cAAYb,EAAE;QACdL,WAAWpB,GACT,gJACA,2DACA,cACAoB;OAEEI;kBAEJ,cAAA,KAACsB;YAAKC,eAAY;sBAAO;;;AAG/B"}
@@ -6,8 +6,10 @@ export interface TableToolbarProps {
6
6
  end?: ReactNode;
7
7
  /** Expanded panel rendered below the bar (filters, sorting). */
8
8
  panel?: ReactNode;
9
+ /** The panel's id, for the toggle that opens it to name in `aria-controls`. */
10
+ panelId?: string;
9
11
  className?: string;
10
12
  }
11
13
  /** Bar above a table: actions on one line, an optional expanded panel below. */
12
- export declare function TableToolbar({ start, end, panel, className, }: TableToolbarProps): import("react").JSX.Element;
14
+ export declare function TableToolbar({ start, end, panel, panelId, className, }: TableToolbarProps): import("react").JSX.Element;
13
15
  //# sourceMappingURL=table-toolbar.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"table-toolbar.d.ts","sourceRoot":"","sources":["../../../../src/ui/molecules/table-toolbar/table-toolbar.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAIvC,MAAM,WAAW,iBAAiB;IAChC,8DAA8D;IAC9D,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,mEAAmE;IACnE,GAAG,CAAC,EAAE,SAAS,CAAC;IAChB,gEAAgE;IAChE,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,gFAAgF;AAChF,wBAAgB,YAAY,CAAC,EAC3B,KAAK,EACL,GAAG,EACH,KAAK,EACL,SAAS,GACV,EAAE,iBAAiB,+BAcnB"}
1
+ {"version":3,"file":"table-toolbar.d.ts","sourceRoot":"","sources":["../../../../src/ui/molecules/table-toolbar/table-toolbar.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAIvC,MAAM,WAAW,iBAAiB;IAChC,8DAA8D;IAC9D,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,mEAAmE;IACnE,GAAG,CAAC,EAAE,SAAS,CAAC;IAChB,gEAAgE;IAChE,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,+EAA+E;IAC/E,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,gFAAgF;AAChF,wBAAgB,YAAY,CAAC,EAC3B,KAAK,EACL,GAAG,EACH,KAAK,EACL,OAAO,EACP,SAAS,GACV,EAAE,iBAAiB,+BAmBnB"}
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { cn } from '../../utils/cn.js';
3
- /** Bar above a table: actions on one line, an optional expanded panel below. */ export function TableToolbar({ start, end, panel, className }) {
3
+ /** Bar above a table: actions on one line, an optional expanded panel below. */ export function TableToolbar({ start, end, panel, panelId, className }) {
4
4
  return /*#__PURE__*/ _jsxs("div", {
5
5
  className: cn('flex flex-col gap-2xs', className),
6
6
  children: [
@@ -8,7 +8,7 @@ import { cn } from '../../utils/cn.js';
8
8
  className: "flex flex-wrap items-center justify-between gap-2xs",
9
9
  children: [
10
10
  /*#__PURE__*/ _jsx("div", {
11
- className: "flex flex-wrap items-center gap-2xs",
11
+ className: "min-w-0 flex flex-1 flex-wrap items-center gap-2xs",
12
12
  children: start
13
13
  }),
14
14
  /*#__PURE__*/ _jsx("div", {
@@ -18,6 +18,7 @@ import { cn } from '../../utils/cn.js';
18
18
  ]
19
19
  }),
20
20
  panel && /*#__PURE__*/ _jsx("div", {
21
+ id: panelId,
21
22
  className: "rounded-xl border border-border bg-surface p-s",
22
23
  children: panel
23
24
  })
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/ui/molecules/table-toolbar/table-toolbar.tsx"],"sourcesContent":["import type { ReactNode } from 'react';\n\nimport { cn } from '../../utils/cn.js';\n\nexport interface TableToolbarProps {\n /** Actions aligned to the start — titles, primary actions. */\n start?: ReactNode;\n /** Actions aligned to the end — column settings, panel toggles. */\n end?: ReactNode;\n /** Expanded panel rendered below the bar (filters, sorting). */\n panel?: ReactNode;\n className?: string;\n}\n\n/** Bar above a table: actions on one line, an optional expanded panel below. */\nexport function TableToolbar({\n start,\n end,\n panel,\n className,\n}: TableToolbarProps) {\n return (\n <div className={cn('flex flex-col gap-2xs', className)}>\n <div className=\"flex flex-wrap items-center justify-between gap-2xs\">\n <div className=\"flex flex-wrap items-center gap-2xs\">{start}</div>\n <div className=\"flex flex-wrap items-center gap-2xs\">{end}</div>\n </div>\n {panel && (\n <div className=\"rounded-xl border border-border bg-surface p-s\">\n {panel}\n </div>\n )}\n </div>\n );\n}\n"],"names":["cn","TableToolbar","start","end","panel","className","div"],"mappings":";AAEA,SAASA,EAAE,QAAQ,oBAAoB;AAYvC,8EAA8E,GAC9E,OAAO,SAASC,aAAa,EAC3BC,KAAK,EACLC,GAAG,EACHC,KAAK,EACLC,SAAS,EACS;IAClB,qBACE,MAACC;QAAID,WAAWL,GAAG,yBAAyBK;;0BAC1C,MAACC;gBAAID,WAAU;;kCACb,KAACC;wBAAID,WAAU;kCAAuCH;;kCACtD,KAACI;wBAAID,WAAU;kCAAuCF;;;;YAEvDC,uBACC,KAACE;gBAAID,WAAU;0BACZD;;;;AAKX"}
1
+ {"version":3,"sources":["../../../../src/ui/molecules/table-toolbar/table-toolbar.tsx"],"sourcesContent":["import type { ReactNode } from 'react';\n\nimport { cn } from '../../utils/cn.js';\n\nexport interface TableToolbarProps {\n /** Actions aligned to the start — titles, primary actions. */\n start?: ReactNode;\n /** Actions aligned to the end — column settings, panel toggles. */\n end?: ReactNode;\n /** Expanded panel rendered below the bar (filters, sorting). */\n panel?: ReactNode;\n /** The panel's id, for the toggle that opens it to name in `aria-controls`. */\n panelId?: string;\n className?: string;\n}\n\n/** Bar above a table: actions on one line, an optional expanded panel below. */\nexport function TableToolbar({\n start,\n end,\n panel,\n panelId,\n className,\n}: TableToolbarProps) {\n return (\n <div className={cn('flex flex-col gap-2xs', className)}>\n <div className=\"flex flex-wrap items-center justify-between gap-2xs\">\n <div className=\"min-w-0 flex flex-1 flex-wrap items-center gap-2xs\">\n {start}\n </div>\n <div className=\"flex flex-wrap items-center gap-2xs\">{end}</div>\n </div>\n {panel && (\n <div\n id={panelId}\n className=\"rounded-xl border border-border bg-surface p-s\"\n >\n {panel}\n </div>\n )}\n </div>\n );\n}\n"],"names":["cn","TableToolbar","start","end","panel","panelId","className","div","id"],"mappings":";AAEA,SAASA,EAAE,QAAQ,oBAAoB;AAcvC,8EAA8E,GAC9E,OAAO,SAASC,aAAa,EAC3BC,KAAK,EACLC,GAAG,EACHC,KAAK,EACLC,OAAO,EACPC,SAAS,EACS;IAClB,qBACE,MAACC;QAAID,WAAWN,GAAG,yBAAyBM;;0BAC1C,MAACC;gBAAID,WAAU;;kCACb,KAACC;wBAAID,WAAU;kCACZJ;;kCAEH,KAACK;wBAAID,WAAU;kCAAuCH;;;;YAEvDC,uBACC,KAACG;gBACCC,IAAIH;gBACJC,WAAU;0BAETF;;;;AAKX"}
@@ -5,39 +5,83 @@ import { useErrorMessage } from '../../../i18n/index.js';
5
5
  * `code`, and anything else that reached the user keeps its `message`.
6
6
  */
7
7
  export type ToastFailure = Parameters<ReturnType<typeof useErrorMessage>>[0];
8
- /** One failure waiting in the region, under the id it was shown with. */
9
- export interface FailureToast {
10
- readonly id: number;
11
- readonly failure: ToastFailure;
8
+ /**
9
+ * What a toast reports
10
+ * ([ADR 0028](../../../../../../../docs/adr/0028-states-an-organism-must-render.md)):
11
+ * a write that worked, one that can still be taken back, something worth
12
+ * knowing, or a failure. Only a failure interrupts.
13
+ */
14
+ export type ToastTone = 'success' | 'undo' | 'info' | 'failure';
15
+ /** The one thing a toast offers to do about what it reports. */
16
+ export interface ToastAction {
17
+ /** The button's text, already in the reader's language. */
18
+ readonly label: string;
19
+ readonly onAction: () => void;
12
20
  }
21
+ /**
22
+ * A toast to show. A failure carries the failure itself, rendered through the
23
+ * same {@link useErrorMessage} a form's error slot uses; every other tone
24
+ * carries a sentence already in the reader's language. An `undo` toast without
25
+ * its Undo would be a success toast, so the type asks for the action.
26
+ */
27
+ export type ToastInput = {
28
+ readonly tone: 'success' | 'info';
29
+ readonly message: string;
30
+ readonly action?: ToastAction;
31
+ } | {
32
+ readonly tone: 'undo';
33
+ readonly message: string;
34
+ readonly action: ToastAction;
35
+ } | {
36
+ readonly tone: 'failure';
37
+ readonly failure: ToastFailure;
38
+ readonly action?: ToastAction;
39
+ };
40
+ /** One toast waiting in the region, under the id it was shown with. */
41
+ export type Toast = ToastInput & {
42
+ readonly id: number;
43
+ };
13
44
  export interface Toasts {
14
- /** The failures shown, oldest first. */
15
- readonly failures: readonly FailureToast[];
16
- /** Shows a failure until it is dismissed, and answers its id. */
17
- readonly showFailure: (failure: ToastFailure) => number;
45
+ /** The toasts shown, oldest first. */
46
+ readonly toasts: readonly Toast[];
47
+ /** Shows a toast, and answers its id. */
48
+ readonly show: (toast: ToastInput) => number;
18
49
  readonly dismiss: (id: number) => void;
19
50
  }
51
+ /**
52
+ * How long a toast that is neither a failure nor offers an action stays, in
53
+ * milliseconds. A failure stays until it is dismissed: it reports something
54
+ * that already happened, often after the screen that started it was left, and
55
+ * a message that times out is one a slow reader never gets. A toast with an
56
+ * action stays too, for the same reader.
57
+ */
58
+ export declare const TOAST_TIMEOUT_MS = 8000;
59
+ export interface ToastProviderProps {
60
+ readonly children: ReactNode;
61
+ /** How long a success, undo or info toast stays. */
62
+ readonly timeoutMs?: number;
63
+ }
20
64
  /**
21
65
  * Holds the toasts one host shows. Mounted once, above everything that can
22
66
  * fail asynchronously, with a {@link ToastRegion} somewhere inside it.
23
67
  */
24
- export declare function ToastProvider({ children }: {
25
- readonly children: ReactNode;
26
- }): import("react").JSX.Element;
68
+ export declare function ToastProvider({ children, timeoutMs, }: ToastProviderProps): import("react").JSX.Element;
27
69
  /**
28
70
  * The {@link ToastProvider} above, or `undefined` outside one: a caller with
29
- * no region to show a failure in keeps it where it can, rather than having it
30
- * vanish.
71
+ * no region to show a toast in keeps what it has to say where it can, rather
72
+ * than having it vanish.
31
73
  */
32
74
  export declare const useToasts: () => Toasts | undefined;
33
75
  /**
34
- * Where a host's toasts render: each failure in the reader's language,
35
- * through the same {@link useErrorMessage} a form's error slot uses, so an
36
- * asynchronous failure reads exactly as a synchronous one would.
76
+ * Where a host's toasts render, each through {@link Alert}: a failure is
77
+ * `role="alert"` and every other tone `role="status"`.
37
78
  *
38
- * A failure stays until it is dismissed. It reports something that already
39
- * happened, often after the screen that started it was left, and a message
40
- * that times out is one a slow reader never gets.
79
+ * ⚠️ **An empty region takes no room and no clicks.** It stays mounted, so a
80
+ * toast lands in a region that already exists, but at zero size and with
81
+ * `pointer-events: none` — a fixed box that kept its padding once covered two
82
+ * focused links and swallowed clicks (WCAG 2.4.11). While toasts show, the
83
+ * document's bottom scroll padding is the region's height, so a control
84
+ * focused by keyboard scrolls clear of it. F6 moves focus into the region.
41
85
  */
42
86
  export declare function ToastRegion(): import("react").JSX.Element | null;
43
87
  //# sourceMappingURL=toast-region.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"toast-region.d.ts","sourceRoot":"","sources":["../../../../src/ui/molecules/toast-region/toast-region.tsx"],"names":[],"mappings":"AAEA,OAAO,EAEL,KAAK,SAAS,EAMf,MAAM,OAAO,CAAC;AAEf,OAAO,EAAE,eAAe,EAAQ,MAAM,wBAAwB,CAAC;AAG/D;;;GAGG;AACH,MAAM,MAAM,YAAY,GAAG,UAAU,CAAC,UAAU,CAAC,OAAO,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAE7E,yEAAyE;AACzE,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,OAAO,EAAE,YAAY,CAAC;CAChC;AAED,MAAM,WAAW,MAAM;IACrB,wCAAwC;IACxC,QAAQ,CAAC,QAAQ,EAAE,SAAS,YAAY,EAAE,CAAC;IAC3C,iEAAiE;IACjE,QAAQ,CAAC,WAAW,EAAE,CAAC,OAAO,EAAE,YAAY,KAAK,MAAM,CAAC;IACxD,QAAQ,CAAC,OAAO,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;CACxC;AAID;;;GAGG;AACH,wBAAgB,aAAa,CAAC,EAAE,QAAQ,EAAE,EAAE;IAAE,QAAQ,CAAC,QAAQ,EAAE,SAAS,CAAA;CAAE,+BAqB3E;AAED;;;;GAIG;AACH,eAAO,MAAM,SAAS,QAAO,MAAM,GAAG,SAAqC,CAAC;AAE5E;;;;;;;;GAQG;AACH,wBAAgB,WAAW,uCA6B1B"}
1
+ {"version":3,"file":"toast-region.d.ts","sourceRoot":"","sources":["../../../../src/ui/molecules/toast-region/toast-region.tsx"],"names":[],"mappings":"AAEA,OAAO,EAEL,KAAK,SAAS,EAOf,MAAM,OAAO,CAAC;AAEf,OAAO,EAAE,eAAe,EAAQ,MAAM,wBAAwB,CAAC;AAM/D;;;GAGG;AACH,MAAM,MAAM,YAAY,GAAG,UAAU,CAAC,UAAU,CAAC,OAAO,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAE7E;;;;;GAKG;AACH,MAAM,MAAM,SAAS,GAAG,SAAS,GAAG,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;AAEhE,gEAAgE;AAChE,MAAM,WAAW,WAAW;IAC1B,2DAA2D;IAC3D,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,QAAQ,EAAE,MAAM,IAAI,CAAC;CAC/B;AAED;;;;;GAKG;AACH,MAAM,MAAM,UAAU,GAClB;IACE,QAAQ,CAAC,IAAI,EAAE,SAAS,GAAG,MAAM,CAAC;IAClC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC;CAC/B,GACD;IACE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;CAC9B,GACD;IACE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IACzB,QAAQ,CAAC,OAAO,EAAE,YAAY,CAAC;IAC/B,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC;CAC/B,CAAC;AAEN,uEAAuE;AACvE,MAAM,MAAM,KAAK,GAAG,UAAU,GAAG;IAAE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;CAAE,CAAC;AAEzD,MAAM,WAAW,MAAM;IACrB,sCAAsC;IACtC,QAAQ,CAAC,MAAM,EAAE,SAAS,KAAK,EAAE,CAAC;IAClC,yCAAyC;IACzC,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,MAAM,CAAC;IAC7C,QAAQ,CAAC,OAAO,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;CACxC;AAED;;;;;;GAMG;AACH,eAAO,MAAM,gBAAgB,OAAO,CAAC;AAIrC,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,QAAQ,EAAE,SAAS,CAAC;IAC7B,oDAAoD;IACpD,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,EAC5B,QAAQ,EACR,SAA4B,GAC7B,EAAE,kBAAkB,+BA4CpB;AAED;;;;GAIG;AACH,eAAO,MAAM,SAAS,QAAO,MAAM,GAAG,SAAqC,CAAC;AA0D5E;;;;;;;;;;GAUG;AACH,wBAAgB,WAAW,uCA8C1B"}