bitboss-ui 3.0.0-beta.2 → 3.0.0-beta.21

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 (350) hide show
  1. package/README.md +72 -33
  2. package/dist/ai/BbAccordion.md +3 -3
  3. package/dist/ai/BbAlert.md +9 -5
  4. package/dist/ai/BbAsterisk.md +17 -0
  5. package/dist/ai/BbAvatar.md +12 -3
  6. package/dist/ai/BbBadge.md +15 -10
  7. package/dist/ai/BbBadgeButton.md +16 -16
  8. package/dist/ai/BbBaseButton.md +16 -16
  9. package/dist/ai/BbBaseCheckbox.md +8 -8
  10. package/dist/ai/BbBaseCheckboxGroup.md +13 -13
  11. package/dist/ai/BbBaseCheckboxIcon.md +26 -9
  12. package/dist/ai/BbBaseColorInput.md +11 -11
  13. package/dist/ai/BbBaseDatePicker.md +6 -6
  14. package/dist/ai/BbBaseDatePickerInput.md +15 -15
  15. package/dist/ai/BbBaseInputContainer.md +12 -12
  16. package/dist/ai/BbBaseNumberInput.md +8 -8
  17. package/dist/ai/BbBaseRadio.md +5 -5
  18. package/dist/ai/BbBaseRadioGroup.md +7 -7
  19. package/dist/ai/BbBaseRadioIcon.md +25 -9
  20. package/dist/ai/BbBaseRating.md +5 -5
  21. package/dist/ai/BbBaseSelect.md +22 -21
  22. package/dist/ai/BbBaseSlider.md +9 -9
  23. package/dist/ai/BbBaseSwitch.md +8 -8
  24. package/dist/ai/BbBaseSwitchGroup.md +13 -13
  25. package/dist/ai/BbBaseSwitchIcon.md +28 -10
  26. package/dist/ai/BbBaseTag.md +10 -10
  27. package/dist/ai/BbBaseTextInput.md +9 -9
  28. package/dist/ai/BbBaseTextarea.md +9 -9
  29. package/dist/ai/BbBaseTimePickerInput.md +13 -13
  30. package/dist/ai/BbBreadcrumbs.md +2 -2
  31. package/dist/ai/BbButton.md +15 -15
  32. package/dist/ai/BbCheckbox.md +18 -17
  33. package/dist/ai/BbCheckboxGroup.md +15 -14
  34. package/dist/ai/BbCollapsible.md +11 -9
  35. package/dist/ai/BbColorInput.md +15 -15
  36. package/dist/ai/BbColorPalette.md +12 -6
  37. package/dist/ai/BbConfirm.md +12 -5
  38. package/dist/ai/BbDatePicker.md +13 -13
  39. package/dist/ai/BbDatePickerInput.md +20 -20
  40. package/dist/ai/BbDialog.md +78 -12
  41. package/dist/ai/BbDropdown.md +132 -22
  42. package/dist/ai/BbDropdownButton.md +12 -12
  43. package/dist/ai/BbDropdownGroup.md +1 -1
  44. package/dist/ai/BbDropzone.md +4 -4
  45. package/dist/ai/BbForm.md +49 -14
  46. package/dist/ai/BbIcon.md +6 -0
  47. package/dist/ai/BbIndicator.md +5 -5
  48. package/dist/ai/BbNumberInput.md +11 -11
  49. package/dist/ai/BbOffCanvas.md +90 -20
  50. package/dist/ai/BbPagination.md +3 -3
  51. package/dist/ai/BbPopover.md +32 -17
  52. package/dist/ai/BbProgress.md +7 -4
  53. package/dist/ai/BbRadio.md +16 -15
  54. package/dist/ai/BbRadioGroup.md +20 -17
  55. package/dist/ai/BbRating.md +11 -11
  56. package/dist/ai/BbSelect.md +138 -37
  57. package/dist/ai/BbSelectPopover.md +40 -41
  58. package/dist/ai/BbSlider.md +37 -22
  59. package/dist/ai/BbSmoothHeight.md +1 -1
  60. package/dist/ai/BbSwitch.md +25 -10
  61. package/dist/ai/BbSwitchGroup.md +17 -14
  62. package/dist/ai/BbTable.md +920 -109
  63. package/dist/ai/BbTabs.md +28 -14
  64. package/dist/ai/BbTabsList.md +1 -1
  65. package/dist/ai/BbTabsPanes.md +1 -1
  66. package/dist/ai/BbTabsRoot.md +10 -10
  67. package/dist/ai/BbTag.md +14 -14
  68. package/dist/ai/BbTextInput.md +16 -15
  69. package/dist/ai/BbTextarea.md +13 -13
  70. package/dist/ai/BbTimePicker.md +10 -10
  71. package/dist/ai/BbTimePickerInput.md +17 -17
  72. package/dist/ai/BbToast.md +1 -1
  73. package/dist/ai/BbToastPortal.md +1 -1
  74. package/dist/ai/BbTooltip.md +12 -10
  75. package/dist/ai/BbTree.md +1 -1
  76. package/dist/ai/ChipsBox.md +1 -1
  77. package/dist/ai/CommonInputWrapper.md +10 -10
  78. package/dist/ai/CommonPopover.md +6 -6
  79. package/dist/ai/FlatListBox.md +5 -5
  80. package/dist/ai/GroupedListBox.md +5 -5
  81. package/dist/ai/ListBox.md +4 -4
  82. package/dist/ai/OptionsContainer.md +4 -4
  83. package/dist/ai/changelog.json +128 -2
  84. package/dist/ai/components.json +917 -100
  85. package/dist/ai/composables/useBbConfig.md +72 -11
  86. package/dist/ai/composables/useConfirm.md +5 -3
  87. package/dist/ai/guides/ai-router.md +9 -4
  88. package/dist/ai/guides/component-picker.md +18 -18
  89. package/dist/ai/guides/design-language.md +14 -14
  90. package/dist/ai/guides/design-tokens.md +25 -18
  91. package/dist/ai/guides/fetch-items-playbook.md +1 -1
  92. package/dist/ai/guides/icons-policy.md +11 -5
  93. package/dist/ai/guides/installation-and-plugin-setup.md +85 -23
  94. package/dist/ai/guides/migration/components/bb-checkbox-group.md +30 -0
  95. package/dist/ai/guides/migration/components/bb-checkbox.md +37 -3
  96. package/dist/ai/guides/migration/components/bb-collapsible.md +5 -5
  97. package/dist/ai/guides/migration/components/bb-dialog.md +62 -34
  98. package/dist/ai/guides/migration/components/bb-offcanvas.md +29 -13
  99. package/dist/ai/guides/migration/components/bb-rating.md +8 -2
  100. package/dist/ai/guides/migration/components/bb-select.md +5 -2
  101. package/dist/ai/guides/migration/components/bb-table.md +560 -28
  102. package/dist/ai/guides/migration/components/bb-text-input.md +6 -6
  103. package/dist/ai/guides/migration/v2-to-v3.md +260 -89
  104. package/dist/ai/guides/ssr-prefill.md +120 -0
  105. package/dist/ai/index.md +10 -9
  106. package/dist/ai/recipes/inertia/approvals-inbox.md +0 -1
  107. package/dist/ai/recipes/inertia/inline-edit-workspace.md +0 -1
  108. package/dist/ai/recipes/inertia/layout-scaffold.md +5 -1
  109. package/dist/ai/recipes/inertia/ownership-atlas.md +49 -29
  110. package/dist/ai/recipes/inertia/record-form.md +0 -1
  111. package/dist/ai/recipes/inertia/records-workspace.md +26 -8
  112. package/dist/ai/recipes/inertia/upload-center.md +0 -1
  113. package/dist/ai/recipes/nuxt/approvals-inbox.md +0 -1
  114. package/dist/ai/recipes/nuxt/inline-edit-workspace.md +0 -1
  115. package/dist/ai/recipes/nuxt/layout-scaffold.md +5 -1
  116. package/dist/ai/recipes/nuxt/record-form.md +0 -1
  117. package/dist/ai/recipes/nuxt/records-workspace.md +26 -8
  118. package/dist/ai/recipes/nuxt/upload-center.md +0 -1
  119. package/dist/ai/recipes/vue/approvals-inbox.md +0 -1
  120. package/dist/ai/recipes/vue/inline-edit-workspace.md +0 -1
  121. package/dist/ai/recipes/vue/layout-scaffold.md +5 -1
  122. package/dist/ai/recipes/vue/records-workspace.md +26 -8
  123. package/dist/ai/recipes/vue/upload-center.md +0 -1
  124. package/dist/ai/source/BbAlert.md +60 -2
  125. package/dist/ai/source/BbAvatar.md +3 -3
  126. package/dist/ai/source/BbBadge.md +60 -15
  127. package/dist/ai/source/BbBadgeButton.md +8 -2
  128. package/dist/ai/source/BbBaseButton.md +3 -1
  129. package/dist/ai/source/BbBaseCheckboxGroup.md +6 -2
  130. package/dist/ai/source/BbBaseDatePicker.md +3 -1
  131. package/dist/ai/source/BbBaseDatePickerInput.md +5 -1
  132. package/dist/ai/source/BbBaseInputContainer.md +52 -1
  133. package/dist/ai/source/BbBaseRadioGroup.md +4 -0
  134. package/dist/ai/source/BbBaseRating.md +3 -1
  135. package/dist/ai/source/BbBaseSelect.md +71 -16
  136. package/dist/ai/source/BbBaseSwitchGroup.md +4 -0
  137. package/dist/ai/source/BbBaseTimePickerInput.md +5 -1
  138. package/dist/ai/source/BbBreadcrumbs.md +31 -0
  139. package/dist/ai/source/BbButton.md +51 -24
  140. package/dist/ai/source/BbCheckbox.md +15 -1
  141. package/dist/ai/source/BbCheckboxGroup.md +2 -1
  142. package/dist/ai/source/BbCollapsible.md +7 -1
  143. package/dist/ai/source/BbColorInput.md +3 -4
  144. package/dist/ai/source/BbColorPalette.md +3 -4
  145. package/dist/ai/source/BbDatePicker.md +5 -1
  146. package/dist/ai/source/BbDatePickerInput.md +5 -1
  147. package/dist/ai/source/BbDialog.md +175 -19
  148. package/dist/ai/source/BbDropdown.md +376 -69
  149. package/dist/ai/source/BbDropdownGroup.md +330 -59
  150. package/dist/ai/source/BbForm.md +93 -5
  151. package/dist/ai/source/BbIcon.md +46 -36
  152. package/dist/ai/source/BbNumberInput.md +3 -4
  153. package/dist/ai/source/BbOffCanvas.md +474 -194
  154. package/dist/ai/source/BbPopover.md +24 -17
  155. package/dist/ai/source/BbProgress.md +2 -2
  156. package/dist/ai/source/BbRadio.md +15 -1
  157. package/dist/ai/source/BbRadioGroup.md +3 -1
  158. package/dist/ai/source/BbSelect.md +50 -2
  159. package/dist/ai/source/BbSelectPopover.md +171 -23
  160. package/dist/ai/source/BbSlider.md +3 -4
  161. package/dist/ai/source/BbSwitch.md +15 -1
  162. package/dist/ai/source/BbSwitchGroup.md +8 -5
  163. package/dist/ai/source/BbTable.md +5092 -1446
  164. package/dist/ai/source/BbTabs.md +6 -7
  165. package/dist/ai/source/BbTabsList.md +6 -7
  166. package/dist/ai/source/BbTabsPanes.md +6 -7
  167. package/dist/ai/source/BbTabsRoot.md +6 -7
  168. package/dist/ai/source/BbTag.md +3 -4
  169. package/dist/ai/source/BbTextInput.md +3 -4
  170. package/dist/ai/source/BbTextarea.md +3 -4
  171. package/dist/ai/source/BbTimePicker.md +4 -1
  172. package/dist/ai/source/BbTimePickerInput.md +5 -1
  173. package/dist/ai/source/BbToast.md +3 -1
  174. package/dist/ai/source/BbTooltip.md +5 -1
  175. package/dist/ai/source/CommonInputWrapper.md +4 -0
  176. package/dist/ai/source/CommonPopover.md +6 -0
  177. package/dist/ai/source/FlatListBox.md +11 -5
  178. package/dist/ai/source/GroupedListBox.md +7 -5
  179. package/dist/components/BbAlert/BbAlert.vue_vue_type_script_setup_true_lang.js +4 -4
  180. package/dist/components/BbAlert/types.d.ts +10 -1
  181. package/dist/components/BbAvatar/BbAvatar.vue.d.ts +1 -1
  182. package/dist/components/BbAvatar/BbAvatar.vue_vue_type_script_setup_true_lang.js +33 -33
  183. package/dist/components/BbBadge/BadgeBodyContent.vue_vue_type_script_setup_true_lang.js +22 -16
  184. package/dist/components/BbBadge/BbBadge.vue_vue_type_script_setup_true_lang.js +36 -15
  185. package/dist/components/BbBadge/badgeButtonContext.d.ts +21 -8
  186. package/dist/components/BbBadge/types.d.ts +8 -2
  187. package/dist/components/BbBaseButton/BbBaseButton.vue_vue_type_script_setup_true_lang.js +47 -47
  188. package/dist/components/BbBaseButton/RouterComponent.vue_vue_type_script_setup_true_lang.js +14 -14
  189. package/dist/components/BbBaseCheckboxGroup/BbBaseCheckboxGroup.vue_vue_type_script_setup_true_lang.js +30 -28
  190. package/dist/components/BbBaseCheckboxGroup/types.d.ts +2 -2
  191. package/dist/components/BbBaseDatePicker/BbBaseDatePicker.vue_vue_type_script_setup_true_lang.js +167 -167
  192. package/dist/components/BbBaseDatePicker/BbBaseDatePickerInputDaySelector.vue.d.ts +9 -9
  193. package/dist/components/BbBaseDatePicker/BbBaseDatePickerInputDaySelector.vue_vue_type_script_setup_true_lang.js +78 -78
  194. package/dist/components/BbBaseDatePicker/BbBaseDatePickerMonthSelector.vue_vue_type_script_setup_true_lang.js +64 -64
  195. package/dist/components/BbBaseDatePickerInput/BbBaseDatePickerInput.vue.d.ts +1 -1
  196. package/dist/components/BbBaseDatePickerInput/BbBaseDatePickerInput.vue_vue_type_script_setup_true_lang.js +138 -138
  197. package/dist/components/BbBaseInputContainer/BbBaseInputContainer.vue_vue_type_script_setup_true_lang.js +2 -2
  198. package/dist/components/BbBaseRadioGroup/BbBaseRadioGroup.vue_vue_type_script_setup_true_lang.js +24 -22
  199. package/dist/components/BbBaseRating/BbBaseRating.vue_vue_type_script_setup_true_lang.js +40 -40
  200. package/dist/components/BbBaseSelect/BbBaseSelect.vue_vue_type_script_setup_true_lang.js +74 -65
  201. package/dist/components/BbBaseSelect/types.d.ts +22 -0
  202. package/dist/components/BbBaseSlider/BbBaseSlider.vue_vue_type_script_setup_true_lang.js +5 -5
  203. package/dist/components/BbBaseSwitchGroup/BbBaseSwitchGroup.vue_vue_type_script_setup_true_lang.js +30 -28
  204. package/dist/components/BbBaseTimePickerInput/BbBaseTimePickerInput.vue.d.ts +1 -1
  205. package/dist/components/BbBaseTimePickerInput/BbBaseTimePickerInput.vue_vue_type_script_setup_true_lang.js +104 -104
  206. package/dist/components/BbBreadcrumbs/BbBreadcrumbs.vue_vue_type_script_setup_true_lang.js +35 -35
  207. package/dist/components/BbButton/BbButton.vue_vue_type_script_setup_true_lang.js +85 -81
  208. package/dist/components/BbCheckboxGroup/types.d.ts +2 -1
  209. package/dist/components/BbCollapsible/types.d.ts +7 -1
  210. package/dist/components/BbColorInput/BbColorInput.vue.d.ts +1 -1
  211. package/dist/components/BbColorInput/BbColorInput.vue_vue_type_script_setup_true_lang.js +18 -18
  212. package/dist/components/BbColorPalette/BbColorPalette.vue.d.ts +2 -2
  213. package/dist/components/BbColorPalette/BbColorPalette.vue_vue_type_script_setup_true_lang.js +50 -50
  214. package/dist/components/BbConfirm/BbConfirm.vue_vue_type_script_setup_true_lang.js +17 -17
  215. package/dist/components/BbDatePicker/BbDatePicker.vue.d.ts +1 -1
  216. package/dist/components/BbDatePicker/BbDatePicker.vue_vue_type_script_setup_true_lang.js +100 -100
  217. package/dist/components/BbDatePickerInput/BbDatePickerInput.vue_vue_type_script_setup_true_lang.js +21 -21
  218. package/dist/components/BbDialog/BbDialog.vue.d.ts +1 -1
  219. package/dist/components/BbDialog/BbDialog.vue_vue_type_script_setup_true_lang.js +133 -107
  220. package/dist/components/BbDialog/types.d.ts +29 -2
  221. package/dist/components/BbDropdown/AdaptiveDropdown.vue.d.ts +2 -0
  222. package/dist/components/BbDropdown/AdaptiveDropdown.vue_vue_type_script_setup_true_lang.js +99 -100
  223. package/dist/components/BbDropdown/BbDropdown.vue.d.ts +2 -2
  224. package/dist/components/BbDropdown/BbDropdown.vue_vue_type_script_setup_true_lang.js +208 -201
  225. package/dist/components/BbDropdown/BbDropdownList.vue_vue_type_script_setup_true_lang.js +225 -208
  226. package/dist/components/BbDropdown/DropdownPipelineResolver.vue_vue_type_script_setup_true_lang.js +21 -21
  227. package/dist/components/BbDropdown/types.d.ts +20 -5
  228. package/dist/components/BbDropdownButton/BbDropdownButton.vue_vue_type_script_setup_true_lang.js +5 -5
  229. package/dist/components/BbIcon/BbIcon.vue_vue_type_script_setup_true_lang.js +46 -46
  230. package/dist/components/BbIcon/iconCache.d.ts +33 -0
  231. package/dist/components/BbIcon/iconCache.js +17 -0
  232. package/dist/components/BbNumberInput/BbNumberInput.vue.d.ts +1 -1
  233. package/dist/components/BbNumberInput/BbNumberInput.vue_vue_type_script_setup_true_lang.js +15 -15
  234. package/dist/components/BbOffCanvas/BbOffCanvas.vue.d.ts +1 -1
  235. package/dist/components/BbOffCanvas/BbOffCanvas.vue_vue_type_script_setup_true_lang.js +254 -208
  236. package/dist/components/BbOffCanvas/types.d.ts +30 -5
  237. package/dist/components/BbPagination/BbPagination.vue.d.ts +1 -1
  238. package/dist/components/BbPopover/BbPopover.vue.d.ts +2 -2
  239. package/dist/components/BbPopover/BbPopover.vue_vue_type_script_setup_true_lang.js +149 -146
  240. package/dist/components/BbPopover/types.d.ts +3 -2
  241. package/dist/components/BbRadioGroup/types.d.ts +3 -1
  242. package/dist/components/BbSelect/BbSelect.vue_vue_type_script_setup_true_lang.js +27 -23
  243. package/dist/components/BbSelect/types.d.ts +32 -0
  244. package/dist/components/BbSelectPopover/BbSelectPopover.vue_vue_type_script_setup_true_lang.js +221 -213
  245. package/dist/components/BbSlider/BbSlider.vue.d.ts +1 -1
  246. package/dist/components/BbSlider/BbSlider.vue_vue_type_script_setup_true_lang.js +20 -20
  247. package/dist/components/BbTable/BbTable.vue.d.ts +10 -4
  248. package/dist/components/BbTable/BbTable.vue_vue_type_script_setup_true_lang.js +1433 -600
  249. package/dist/components/BbTable/BbTableDataRow.d.ts +162 -0
  250. package/dist/components/BbTable/BbTableDataRow.js +136 -0
  251. package/dist/components/BbTable/BbTableExpandRow.d.ts +73 -0
  252. package/dist/components/BbTable/BbTableExpandRow.js +52 -0
  253. package/dist/components/BbTable/types.d.ts +324 -111
  254. package/dist/components/BbTable/utils.d.ts +92 -4
  255. package/dist/components/BbTable/utils.js +71 -36
  256. package/dist/components/BbTabs/types.d.ts +0 -8
  257. package/dist/components/BbTag/BbTag.vue.d.ts +1 -1
  258. package/dist/components/BbTag/BbTag.vue_vue_type_script_setup_true_lang.js +18 -18
  259. package/dist/components/BbTextInput/BbTextInput.vue.d.ts +1 -1
  260. package/dist/components/BbTextInput/BbTextInput.vue_vue_type_script_setup_true_lang.js +18 -18
  261. package/dist/components/BbTextarea/BbTextarea.vue.d.ts +1 -1
  262. package/dist/components/BbTextarea/BbTextarea.vue_vue_type_script_setup_true_lang.js +54 -54
  263. package/dist/components/BbTimePicker/BbTimePicker.vue.d.ts +1 -1
  264. package/dist/components/BbTimePicker/BbTimePicker.vue_vue_type_script_setup_true_lang.js +80 -80
  265. package/dist/components/BbTimePickerInput/BbTimePickerInput.vue_vue_type_script_setup_true_lang.js +61 -61
  266. package/dist/components/BbToast/BbToast.vue_vue_type_script_setup_true_lang.js +17 -17
  267. package/dist/components/BbToast/BbToastMessage.vue_vue_type_script_setup_true_lang.js +13 -13
  268. package/dist/components/BbTooltip/types.d.ts +5 -1
  269. package/dist/components/ChipsBox/ChipsBox.vue_vue_type_script_setup_true_lang.js +17 -17
  270. package/dist/components/ClearableButton/ClearableButton.vue_vue_type_script_setup_true_lang.js +5 -5
  271. package/dist/components/CommonPopover/CommonPopover.vue_vue_type_script_setup_true_lang.js +2 -1
  272. package/dist/components/FlatListBox/FlatListBox.vue_vue_type_script_setup_true_lang.js +83 -83
  273. package/dist/components/GroupedListBox/GroupedListBox.vue_vue_type_script_setup_true_lang.js +56 -56
  274. package/dist/composables/useBaseOptions.js +30 -20
  275. package/dist/composables/useBbConfig.d.ts +27 -6
  276. package/dist/composables/useBbConfig.js +8 -2
  277. package/dist/composables/useConfig.d.ts +59 -0
  278. package/dist/composables/useConfig.js +9 -0
  279. package/dist/composables/useItemsGetter.d.ts +11 -0
  280. package/dist/composables/useItemsGetter.js +44 -18
  281. package/dist/composables/useLocale.js +10 -7
  282. package/dist/composables/useMobile.js +5 -5
  283. package/dist/composables/usePrefill.d.ts +21 -2
  284. package/dist/composables/usePrefill.js +25 -19
  285. package/dist/composables/useSsrState.d.ts +20 -0
  286. package/dist/composables/useSsrState.js +13 -0
  287. package/dist/composables/useTableWidthContext.d.ts +24 -4
  288. package/dist/composables/useTableWidthContext.js +31 -28
  289. package/dist/composables/useToast.js +5 -5
  290. package/dist/deprecation/ai-deprecations.json.d.ts +121 -11
  291. package/dist/deprecation/ai-deprecations.json.js +1 -1
  292. package/dist/directives/bbDropdown.d.ts +15 -4
  293. package/dist/directives/bbDropdown.js +31 -9
  294. package/dist/directives/createPopoverDirective.d.ts +62 -0
  295. package/dist/directives/createPopoverDirective.js +63 -23
  296. package/dist/i18n/locales/cs.json +4 -1
  297. package/dist/i18n/locales/da.json +4 -1
  298. package/dist/i18n/locales/de.json +4 -1
  299. package/dist/i18n/locales/el.json +4 -1
  300. package/dist/i18n/locales/en.json +4 -1
  301. package/dist/i18n/locales/es.json +4 -1
  302. package/dist/i18n/locales/fi.json +4 -1
  303. package/dist/i18n/locales/fr.json +4 -1
  304. package/dist/i18n/locales/hu.json +4 -1
  305. package/dist/i18n/locales/it.json +4 -1
  306. package/dist/i18n/locales/ja.json +4 -1
  307. package/dist/i18n/locales/ko.json +4 -1
  308. package/dist/i18n/locales/nb.json +4 -1
  309. package/dist/i18n/locales/nl.json +4 -1
  310. package/dist/i18n/locales/pl.json +4 -1
  311. package/dist/i18n/locales/pt.json +4 -1
  312. package/dist/i18n/locales/ro.json +4 -1
  313. package/dist/i18n/locales/ru.json +4 -1
  314. package/dist/i18n/locales/sv.json +4 -1
  315. package/dist/i18n/locales/tr.json +4 -1
  316. package/dist/i18n/locales/uk.json +4 -1
  317. package/dist/i18n/locales/zh-cn.json +4 -1
  318. package/dist/index.d.ts +7 -2
  319. package/dist/index.js +69 -67
  320. package/dist/llms-full.txt +3997 -1458
  321. package/dist/llms-medium.txt +140 -73
  322. package/dist/llms.txt +7 -6
  323. package/dist/locale-blueprint.json +4 -1
  324. package/dist/nuxt-auto-imports.d.ts +100 -0
  325. package/dist/nuxt-auto-imports.js +55 -0
  326. package/dist/nuxt-module.d.ts +22 -1
  327. package/dist/nuxt.js +22 -8
  328. package/dist/plugin.d.ts +10 -1
  329. package/dist/plugin.js +20 -19
  330. package/dist/runtime/nuxt-plugin.js +28 -21
  331. package/dist/styles.css +1 -1
  332. package/dist/utilities/misc/listboxMetrics.d.ts +3 -3
  333. package/dist/utilities/misc/listboxMetrics.js +2 -2
  334. package/dist/utilities/misc/ssrStateInjectionKey.d.ts +42 -0
  335. package/dist/utilities/misc/ssrStateInjectionKey.js +4 -0
  336. package/dist/validated/BbForm.vue_vue_type_script_setup_true_lang.js +45 -27
  337. package/dist/validated/BbSelect.vue.d.ts +2 -0
  338. package/dist/validated/BbSelect.vue_vue_type_script_setup_true_lang.js +1 -0
  339. package/dist/validated/useValidatedField.js +25 -23
  340. package/dist/vite.js +7 -3
  341. package/llms.txt +8 -7
  342. package/package.json +2 -2
  343. package/scripts/lib/eslint-plugin.d.ts +19 -1
  344. package/scripts/lib/eslint-plugin.mjs +155 -14
  345. package/scripts/lib/html-attributes.mjs +91 -0
  346. package/scripts/lib/validate-bb-markup.mjs +59 -11
  347. package/dist/assets/svgs/sort.svg_raw.js +0 -4
  348. package/dist/components/BbBadge/BadgeAppendIcon.vue.d.ts +0 -3
  349. package/dist/components/BbBadge/BadgeAppendIcon.vue.js +0 -5
  350. package/dist/components/BbBadge/BadgeAppendIcon.vue_vue_type_script_setup_true_lang.js +0 -22
@@ -1,23 +1,30 @@
1
1
  ---
2
2
  title: 'Migration v2→v3: BbTable'
3
- summary: 'allowSelectAll inverted to disableSelectAll; loading no longer blanks populated tables and now inerts rows; #loading is first-load-only; #no-data fills a full-width table cell instead of replacing the row; columns gained sortable + rowClass, which collide with same-named consumer fields.'
3
+ summary: 'The table renders as a CSS grid of divs with ARIA roles, not a <table> — every element selector (table/thead/tbody/tr/th/td) under .bb-table matches nothing, #thead/#tbody/#tfoot take role-complete div rows, --fill/--natural-width are gone, column widths drift within documented bounds, copy-to-spreadsheet and print header repetition degrade; allowSelectAll inverted to disableSelectAll; loading no longer blanks populated tables and now inerts rows; #loading is first-load-only; #no-data fills a full-width cell instead of replacing the row; row events drop the selected argument; columns gained sortable + rowClass, which collide with same-named consumer fields.'
4
4
  ---
5
5
 
6
6
  # BbTable — v2 → v3
7
7
 
8
8
  ## Changes
9
9
 
10
- | v2 | v3 | Kind |
11
- | ----------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------- |
12
- | `allowSelectAll?: boolean` (default `true`) | `disableSelectAll?: boolean` (default `false`) | rename, polarity inverted |
13
- | refetch with rows → skeleton | refetch keeps rows visible (dimmed + progress bar) | **behavior** — the skeleton only shows when there is nothing to display |
14
- | rows interactive while loading | header + rows go `inert` while loading | **behavior** — opt out with `interactive-while-loading` |
15
- | `#loading` slot fired on every load | fires on the **first load only** (it replaces the skeleton, so it follows the skeleton's rule) | **⚠ silent** for anyone styling refetches through it |
16
- | `#no-data` replaced the empty-state `<tr>` | fills the table's own full-width `<td>` (colspan counted, centred) | **behavior** — pass content, not a row |
17
- | — | props `enforceCoherence` (prunes row-keyed models after each load; incompatible with pagination-via-`dependencies`), `expandedItems` + `#expand`, `sort`, `keyboardNavigation`, `highlighted`, `rowClass` | additive |
18
- | | **column** fields `sortable?: boolean`, `rowClass?: ColumnClasses` | additive, **collides** — see below |
19
- | `useBbTableContext(id).total` _(v3 alphas 4)_ | `useBbTableContext(id).totalItems` | **hard rename** on the composable handle see below |
20
- | `--bb-table-*` custom properties | same names without the `bb-` prefix | **⚠ silent** for nested-table layouts — see below |
10
+ | v2 | v3 | Kind |
11
+ | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------- |
12
+ | `allowSelectAll?: boolean` (default `true`) | `disableSelectAll?: boolean` (default `false`) | rename, polarity inverted |
13
+ | refetch with rows → skeleton | refetch keeps rows visible (dimmed + progress bar) | **behavior** — the skeleton only shows when there is nothing to display |
14
+ | rows interactive while loading | header + rows go `inert` while loading | **behavior** — opt out with `interactive-while-loading` |
15
+ | `#loading` slot fired on every load | fires on the **first load only** (it replaces the skeleton, so it follows the skeleton's rule) | **⚠ silent** for anyone styling refetches through it |
16
+ | `#no-data` replaced the empty-state `<tr>` | fills the table's own full-width cell (`aria-colspan` counted, centred) | **behavior** — pass content, not a row |
17
+ | `<table>` / `<thead>` / `<tbody>` / `<tr>` / `<th>` / `<td>` markup _(v2 and v3 beta.5)_ | a CSS grid of `<div>`s carrying `role="table\|rowgroup\|row\|columnheader\|cell"`; `.bb-table__table` / `__head` / `__body` / `__foot` are the new containers, every `.bb-table*` class survives | **⚠ silent** for element selectors, `#thead`/`#tbody`/`#tfoot` markup, copy/paste and print — see below |
18
+ | `--fill` / `--natural-width` published on `.bb-table` _(v3 ≤ beta.5)_ | **removed** nothing publishes them | **⚠ silent** — see below |
19
+ | — | props `enforceCoherence` (prunes row-keyed models after each load; incompatible with pagination-via-`dependencies`), `expandedItems` + `#expand`, `sort`, `keyboardNavigation`, `highlighted`, `rowClass`, `order` (v-model) + `reorderable`, `resizable` + `resize:column`, header-slot `hideColumn()` + `hide:column`, `fixedSelect` / `fixedActions` | additive |
20
+ | — | **column** fields `sortable?: boolean`, `rowClass?: ColumnClasses`, `hidden?: boolean` (the column stays declared — the way to hide, see § Do not override), `fixed?: 'left' \| 'right'` (replaces `fixedColumns`, see below) | additive, **collides** — see below |
21
+ | `actions?: boolean` prop _(v2 and v3 ≤ beta.20)_ | **removed** — the `#actions` slot creates the column by itself | **⚠ silent** if you passed the prop without the slot — see below |
22
+ | `fixedColumns` prop (rendered-slot indices, `[0, { index, position }]`) _(v2 and v3 ≤ beta.20)_ | **removed** — `fixed: 'left' \| 'right'` on the column definition, `fixed-select` / `fixed-actions` for the structural columns | **⚠ silent** — see below |
23
+ | column `snap?: number \| [number, number]` — gridline indices into the parent's rendered columns (`select` at 0, fractions, `-1` = data end) _(v3 ≤ beta.20)_ | `snap?: string \| [string, string]` — the PARENT's column key, or `'select'` / `'actions'`; a pair is inclusive; `'amount.5'` is a fraction. Same-key columns pair by default. Ignored (dev warning) under a parent that uses `order` / `reorderable` | **⚠ silent** — see below |
24
+ | `--table-{id}-track-{index}` published per data column _(v3 ≤ beta.20)_ | `--table-{id}-track-{key}` — the column key in its slot-name spelling (`address_city`); `select` / `actions` unchanged | **⚠ silent** for CSS that read the vars by index — see below |
25
+ | `useBbTableContext(id).total` _(v3 alphas ≤ 4)_ | `useBbTableContext(id).totalItems` | **hard rename** on the composable handle — see below |
26
+ | `@click:row` / `@contextmenu:row` / `@dblclick:row` handlers receive `(event, item, selected)` _(v2 and v3 ≤ beta.5)_ | `(event, item)` — `item` is now your raw record (was the internal row wrapper, record at `row.item`); the trailing `selected` boolean is gone | **payload slimmed** — see below |
27
+ | `--bb-table-*` custom properties | same names without the `bb-` prefix | **⚠ silent** for nested-table layouts — see below |
21
28
 
22
29
  ## Columns gained `sortable` and `rowClass` — check yours first
23
30
 
@@ -70,7 +77,8 @@ migration. Fix it at the type, not at the call sites:
70
77
  `BbTable` coerces the field (`sortable: !!column.sortable` in `BbTable.vue`), so
71
78
  **any** truthy value counts — including a sort-key string like
72
79
  `'patients.created_at'`. The header stops rendering a plain label and renders a
73
- `.bb-table-sort` button instead, and the `<th>` gains `aria-sort="none"`. An app
80
+ `.bb-table-sort` button instead, and the header cell (`.bb-table-header`,
81
+ `role="columnheader"`) gains `aria-sort="none"`. An app
74
82
  that already ships its own sortable-header UI now draws two.
75
83
 
76
84
  The damage is bounded: `sort` is a controlled model (`v-model:sort`), so the
@@ -88,8 +96,9 @@ const tableColumns = computed(() =>
88
96
 
89
97
  Column `rowClass` is the same shape of trap without the type error, because
90
98
  `ColumnClasses` already accepts `string`: a leftover `rowClass: 'w-40'` you
91
- meant for the column typechecks fine and is now merged onto the whole row's
92
- `<tr>`, alongside the table-level `rowClass` prop. A non-`Classes` shape
99
+ meant for the column typechecks fine and is now merged onto the whole row
100
+ (`.bb-table-data__row`), alongside the table-level `rowClass` prop. A
101
+ non-`Classes` shape
93
102
  (`rowClass?: { colspan: number }`) does error, with the same `undefined`
94
103
  wording.
95
104
 
@@ -122,14 +131,125 @@ If you used `#loading` to show a custom refetch treatment, that role is gone —
122
131
  the built-in dim + progress bar covers refetches; `#loading` is now only the
123
132
  first-paint placeholder.
124
133
 
134
+ ### The `#actions` slot creates the actions column — the prop is gone (v3 beta, 2026-09-07)
135
+
136
+ `actions` used to be a boolean prop that rendered the column, with the
137
+ `#actions` slot filling it. The prop carried no information the slot did
138
+ not, and it had a footgun: a consumer who declared `{ key: 'actions' }` in
139
+ `columns` instead of setting the prop got a stray empty data cell and a slot
140
+ that never rendered. Now the slot alone creates the column — header cell
141
+ (labelled by `actions-text`, replaceable through `#header:actions`), one
142
+ cell per row, and the `actions` track for nested tables — and removing the
143
+ slot (or gating it with `v-if`) removes the column live.
144
+
145
+ ```diff
146
+ - <BbTable actions :columns="columns" :items="rows">
147
+ + <BbTable :columns="columns" :items="rows">
148
+ <template #actions="{ item }">…</template>
149
+ </BbTable>
150
+ ```
151
+
152
+ Delete the attribute. The removed-prop warner flags it in dev, the ESLint rule
153
+ flags it in-editor. The only silent case is a table that set `actions`
154
+ without ever providing the slot: it had an empty column, and now it does not.
155
+
156
+ ### `fixedColumns` → `fixed` on the column, `fixed-select` / `fixed-actions` (v3 beta, 2026-09-07)
157
+
158
+ Pins used to be **slot indices** into the rendered column list (a selection
159
+ column was index 0), like spreadsheet freeze panes: with `order` and
160
+ `reorderable` the pinned _slot_ held and whichever column landed in it was
161
+ pinned, which is fragile once users drag headers and hide columns. Pins are
162
+ now a property of the column, the way `width` and `hidden` are, and follow
163
+ it through reorders. The sticky behaviour itself is unchanged: in place, at
164
+ the column's own render position, offset by the pinned columns before it on
165
+ the same side.
166
+
167
+ ```diff
168
+ - <BbTable
169
+ - :columns="columns"
170
+ - :fixed-columns="[0, { index: columns.length + 1, position: 'right' }]"
171
+ - selectable
172
+ - >
173
+ + <BbTable :columns="columns" fixed-select fixed-actions selectable>
174
+ <template #actions="{ item }">…</template>
175
+ </BbTable>
176
+ ```
177
+
178
+ ```diff
179
+ const columns = [
180
+ - { key: 'name', label: 'Name' },
181
+ + { key: 'name', label: 'Name', fixed: 'left' },
182
+ { key: 'amount', label: 'Amount', align: 'right' },
183
+ ];
184
+ ```
185
+
186
+ Translate each index to the column that sat there: data columns get
187
+ `fixed: 'left' | 'right'` on their definition, the selection column becomes
188
+ `fixed-select`, the actions column `fixed-actions` (each has one sensible
189
+ side, so they are booleans). A nested table that pinned its own actions with
190
+ `{ index: childColumns.length, position: 'right' }` now says
191
+ `fixed-actions`. Silent on upgrade: the old prop is ignored (the warner and
192
+ the ESLint rule flag it), so a table that pinned columns stops pinning until
193
+ you move the pins onto the definitions.
194
+
195
+ ### `snap` names the parent column, not a gridline (v3 beta, 2026-09-07)
196
+
197
+ A nested table's `snap` was a number: a gridline index into the parent's
198
+ rendered columns, with the selection column at `0`, fractions for partial
199
+ tracks and `-1` for the end of the data region. Index `k` was whatever column
200
+ happened to render there, so a reorder or a hidden column on the parent
201
+ moved every snap. The parent now publishes its tracks under **column keys**,
202
+ and `snap` names the parent column:
203
+
204
+ ```diff
205
+ const holdings = [
206
+ - { key: 'name', label: 'Resource', snap: 1 },
207
+ - { key: 'kind', label: 'Type', snap: 2 },
208
+ - { key: 'monthlyCost', label: '$ / mo', align: 'right', snap: [3, 4.5] },
209
+ + { key: 'name', label: 'Resource', snap: 'name' },
210
+ + { key: 'kind', label: 'Type', snap: 'team' },
211
+ + { key: 'monthlyCost', label: '$ / mo', align: 'right', snap: ['region', 'monthly.5'] },
212
+ ];
213
+ ```
214
+
215
+ - Translate each index to the parent column that rendered there. The
216
+ selection column is `'select'`, the actions column `'actions'` — both are
217
+ targets by name, so `['name', 'actions']` runs a child column across the
218
+ parent's actions cell.
219
+ - A pair is **inclusive**: `['client', 'amount']` spans from the start of
220
+ `client` through the end of `amount` (the old `[a, b]` ended at the start
221
+ of `b`). A trailing `.digits` on a key is a fraction of that track. `-1`
222
+ is gone: the last column already runs to the end of the data region unless
223
+ it declares a `width` or a pair.
224
+ - A child column with no `snap` now pairs with the parent column of the
225
+ **same key** when there is one, so most children need no snaps at all; a
226
+ column the parent lacks (or hides) flows into the next free parent track.
227
+ - Under a parent that uses `order` or `reorderable`, snaps and key pairing
228
+ are ignored (dev builds warn) and the child inherits by position, as it
229
+ always did — a moving parent can only be followed slot by slot.
230
+
231
+ Silent on upgrade: a numeric `snap` fails the type check but is ignored at
232
+ runtime, so the child falls back to key pairing and flow, which for a child
233
+ sharing the parent's keys is the same alignment as before.
234
+
235
+ **The published track variables changed name with it.** `--table-{id}-track-{k}`
236
+ per data column became `--table-{id}-track-{key}`, the key in its slot-name
237
+ spelling (`address.city` → `address_city`); `select` and `actions` are
238
+ unchanged. Consumer CSS that read the numbered variables directly has to
239
+ switch to the keys. Nothing else about the bridge moved.
240
+
125
241
  ### `#no-data` is content, not a row
126
242
 
127
243
  v2 handed the slot the whole empty-state `<tr>`, so anything that was not a
128
244
  row — the usual `<div>` with a message and a "clear filters" button — landed
129
245
  loose inside `<tbody>` and rendered left-aligned at content width instead of
130
- spanning the table. v3 keeps the `<tr>`/`<td>` shell (with the colspan already
131
- counting the selection and actions columns) and puts the slot inside it, so
132
- that same markup now centres across the full width.
246
+ spanning the table. v3 owns the row/cell shell itself
247
+ (`.bb-table-no-data__row[role=row]` > `.bb-table-no-data__cell[role=cell]`,
248
+ spanning every column with `grid-column: 1 / -1` and an `aria-colspan` that
249
+ already counts the selection and actions columns) and puts the slot inside it,
250
+ so that same markup now centres across the full width. A v2 `<tr>`/`<td>`
251
+ passed here is not just redundant any more — it is table markup inside a
252
+ grid, which is why the diff below deletes it rather than keeping it.
133
253
 
134
254
  ```diff
135
255
  <BbTable :items="rows" :columns="columns" selectable actions>
@@ -184,6 +304,415 @@ unrelated and does not change.
184
304
  `BbPagination` consumers see the same rename through `table-id`; see
185
305
  [BbPagination](./bb-pagination.md).
186
306
 
307
+ ### Row events carry `(event, item)` — your raw record (v3 beta, 2026-08-26)
308
+
309
+ `click:row`, `contextmenu:row` and `dblclick:row` used to pass **the table's
310
+ internal row wrapper** (cells, classes, selection/highlight/expansion flags,
311
+ value hash — your record buried at `row.item`) plus a third `selected`
312
+ argument. Both are gone: the payload is the native event and **the record
313
+ exactly as you passed it in `items`**, nothing else. Selection state is
314
+ already yours through the `v-model` / `unselected-items` models, so the
315
+ handler read it from a second source of truth — and the owner wants row events
316
+ to carry the row, not a state dump.
317
+
318
+ ```diff
319
+ - <BbTable @click:row="(event, row, selected) => open(row.item, selected)" />
320
+ + <BbTable @click:row="(event, item) => open(item, selectedIds.includes(item.id))" />
321
+ ```
322
+
323
+ Two silent JavaScript failures and one loud one: `row.item` is now
324
+ `undefined` (the record has no `.item` field unless yours does), the third
325
+ parameter is simply `undefined`, and any handler typed against `BbTableEvents`
326
+ with three parameters is a **type error** under `vue-tsc` 3. Grep:
327
+ `rg '(click|contextmenu|dblclick):row' --type vue` and inspect every handler
328
+ for `.item` reads and a third parameter.
329
+
330
+ ### Highlight is opt-in — bind `ref(null)`, not `ref()` (v3 beta, 2026-08-27)
331
+
332
+ Row highlight used to run whether or not you bound it. With nothing bound the
333
+ table wrote to `defineModel`'s **local** fallback, so clicking any row applied
334
+ `bb-table-data__row--highlighted` and `aria-current="true"` and drove a state
335
+ your app could neither read nor clear. Invisible while the class shipped
336
+ unstyled; once a default cursor shipped, every table in the app started tinting
337
+ rows on click.
338
+
339
+ Highlight is now inert until something is connected, and **the model's value is
340
+ the switch**: `undefined` means "never initialised" (off), `null` means
341
+ "initialised and currently empty" (on).
342
+
343
+ ```diff
344
+ - const highlighted = ref();
345
+ + const highlighted = ref(null);
346
+ // <BbTable v-model:highlighted="highlighted" … />
347
+ ```
348
+
349
+ A bound-but-`undefined` model **warns in dev** naming the fix, so this does not
350
+ fail silently. A value seeded through the context counts the same and needs no
351
+ prop:
352
+
353
+ ```ts
354
+ const highlighted = ref(null);
355
+ useBbTableContext('invoices-table', { highlighted });
356
+ ```
357
+
358
+ Two things that did **not** change: `click:row` still fires on every row click,
359
+ connected or not — if you only wanted click notifications you never needed the
360
+ model and nothing breaks; and a table that already binds a real value or `null`
361
+ behaves exactly as before.
362
+
363
+ What to check: any table relying on the free highlight **without** binding the
364
+ model — styling `.bb-table-data__row--highlighted` yourself, or reading
365
+ `aria-current` in a test or E2E selector. Those now need the model bound.
366
+ `rg 'bb-table-data__row--highlighted|aria-current' --type vue --type css` and
367
+ keep the hits on tables whose `highlighted` is unbound. A `toggleHighlighted`
368
+ call from a cell slot on an unconnected table does nothing and warns once.
369
+
370
+ ## The table is a CSS grid, not a `<table>` (v3 beta, 2026-08-26)
371
+
372
+ `BbTable` no longer renders a single `<table>` element. The substrate is a CSS
373
+ grid of `<div>`s: the root owns `grid-template-columns` (the column tracks
374
+ _are_ the width API — `columns[].width`, `fixed`, `inherit-column-widths` and
375
+ `snap` all resolve to tracks), and every row group and row is a `subgrid` of
376
+ it, so a cell lands on its column through two levels without a width of its
377
+ own. Nothing about the props, slots, events or models changed for this; what
378
+ changed is everything that touched the **markup** — CSS element selectors,
379
+ the markup you hand to `#thead` / `#tbody` / `#tfoot`, two published custom
380
+ properties, and a handful of things browsers do for real tables that they do
381
+ not do for grids (copy/paste, print, global element CSS).
382
+
383
+ ### What renders now
384
+
385
+ ```
386
+ .bb-table container (div, or fieldset when selectable) — unchanged: [data-bb-table-id], aria-busy, overflow-x: auto
387
+ legend.sr-only (selectable) — unchanged
388
+ .bb-table-caption[id] replaces <caption>; sr-only unless display-caption; sits BEFORE the grid root
389
+ .bb-table__table[role=table] grid root — aria-labelledby → the caption, aria-rowcount
390
+ .bb-table__head[role=rowgroup] replaces <thead>; goes inert while loading; hosts the busy bar
391
+ .bb-table-header-row[role=row]
392
+ .bb-table-header[role=columnheader] (+ --select / --actions / --edge-start / --edge-end, aria-sort)
393
+ .bb-table__body[role=rowgroup] replaces <tbody>
394
+ .bb-table-data__row[role=row] tabindex / aria-rowindex / aria-current / inert / row events — as before
395
+ .bb-table-data__cell[role=cell] (+ --select / --edge-start / --edge-end)
396
+ .bb-table__cell.bb-table__cell--actions[role=cell]
397
+ .bb-table-expand__row[role=row] id="expanded_{hash}" (the aria-controls target) — unchanged
398
+ .bb-table-expand__cell[role=cell] aria-colspan=N, grid-column: 1 / -1
399
+ .bb-table-no-data__row > .bb-table-no-data__cell[role=cell] aria-colspan=N, grid-column: 1 / -1
400
+ .bb-table-skeleton__row > .bb-table-skeleton__cell[role=cell]
401
+ .bb-table-loading__row > .bb-table-loading__cell[role=cell] > span.bb-table-loading__text[role=status][aria-live=polite]
402
+ .bb-table__foot replaces <tfoot>; always rendered, role=rowgroup only when #tfoot is provided
403
+ ```
404
+
405
+ **Every `.bb-table*` class survives on the equivalent node** — including the
406
+ asymmetric `bb-table__cell--actions` and the caption's `bb-table-caption` (no
407
+ `__`). The one exception is the transient `bb-table--measuring` state class,
408
+ which was never documented and existed only to hide the old probe's
409
+ scrollbar flash: it is gone with the probe. Four container classes are new: `.bb-table__table`, `.bb-table__head`,
410
+ `.bb-table__body`, `.bb-table__foot`. Every row carries `role="row"`, every
411
+ header cell `role="columnheader"`, every body/foot cell `role="cell"`. The
412
+ role chain `table → rowgroup → row → columnheader|cell` is what assistive
413
+ technology reads as a table; without it the whole tree is a pile of generic
414
+ `div`s. `aria-colspan` replaces the deleted `colspan` on the three full-width
415
+ cells (expand, no-data, loading).
416
+
417
+ ### Selector translation
418
+
419
+ Element selectors are the break. Nothing throws: a rule on `tbody td` matches
420
+ nothing, the browser applies nothing, and the page renders with the
421
+ override silently missing. Translate every element name under `.bb-table`:
422
+
423
+ | v2 element | v3 selector |
424
+ | --------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
425
+ | `table` | `.bb-table__table` |
426
+ | `thead` | `.bb-table__head` |
427
+ | `tbody` | `.bb-table__body` |
428
+ | `tfoot` | `.bb-table__foot` |
429
+ | `caption` | `.bb-table-caption` |
430
+ | `tr` | `[role=row]` — or `.bb-table-data__row` for data rows only (the old bare `tr` matched every row kind: header, skeleton, no-data, expand, loading) |
431
+ | `th` | `[role=columnheader]` / `.bb-table-header` |
432
+ | `td` | `[role=cell]` / `.bb-table-data__cell` |
433
+ | `:first-child` / `:last-child` / `:not(.bb-table-expand__cell)` | **verbatim** — cells stay siblings inside their row |
434
+ | `td:nth-of-type(n)` | `:nth-child(n)` — the children are type-uniform now, so `nth-of-type` and `nth-child` mean the same thing |
435
+ | `colgroup` / `col` | **gone** — use `columns[].width` |
436
+
437
+ `[role=row]`, `[role=cell]` and `[role=columnheader]` are **supported styling
438
+ hooks**, not incidental markup: the role tree is pinned by the component's own
439
+ tests, so a future move to `role="grid"` would be a deliberate selector break,
440
+ not an accident. There are no `data-*` hooks and no shim classes — the roles
441
+ plus the four container classes are the whole translation.
442
+
443
+ **Specificity caveat.** `[role=cell]` is an attribute selector, specificity
444
+ (0,1,0); `td` was a type selector, (0,0,1). A translated rule is therefore
445
+ _stronger_ than the one it replaces, and an override that used to lose to a
446
+ library rule (or to another of your own rules) by one type-selector point can
447
+ now win. Diff any page where two rules targeted the same cell, and prefer the
448
+ class forms (`.bb-table-data__cell`) when you need the old ordering back.
449
+
450
+ The library's own body-cell rules are deliberately held at **(0,2,0)** — the
451
+ row step is wrapped in `:where()` — so a scoped override of yours that beat
452
+ the old `.bb-table tbody tr td` (0,1,3) at (0,2,0) or better keeps winning.
453
+ An override written at exactly (0,1,x) (one class plus type selectors) is
454
+ the only band that loses ground: give it one more class.
455
+
456
+ The one idiom that dominates real apps — a full-bleed table that re-adds the
457
+ page inset on its outermost cells, scoped with direct-child combinators so a
458
+ nested table inheriting the parent's tracks is not touched — translates like
459
+ this:
460
+
461
+ ```diff
462
+ - .table-flush :deep(> table > thead > tr > th:first-child),
463
+ - .table-flush :deep(> table > tbody > tr > td:first-child:not(.bb-table-expand__cell)) {
464
+ + .table-flush :deep(> .bb-table__table > .bb-table__head > [role='row'] > :first-child),
465
+ + .table-flush :deep(> .bb-table__table > .bb-table__body > [role='row'] > :first-child:not(.bb-table-expand__cell)) {
466
+ padding-inline-start: var(--page-inset);
467
+ }
468
+
469
+ - .table-flush :deep(> table > tbody > tr > td.bb-table-expand__cell) {
470
+ + .table-flush :deep(> .bb-table__table > .bb-table__body > [role='row'] > .bb-table-expand__cell) {
471
+ padding-inline: 0;
472
+ }
473
+ ```
474
+
475
+ The direct-child chain matters exactly as before: `.table-flush` lands on the
476
+ container, `.bb-table__table` is its direct child, and a nested table lives
477
+ inside `.bb-table-expand__cell`, so `>` at every step keeps the override off
478
+ the child's cells (whose padding is the alignment mechanism).
479
+
480
+ Grep for the hits: element names inside `:deep()`, inside `.bb-table` rules,
481
+ and — easy to miss — any **global** table CSS (`table { … }`, `td { padding }`,
482
+ `.prose table`), which reached the v2 markup and now reaches nothing (see
483
+ "Global element CSS" below).
484
+
485
+ ### `#thead` / `#tbody` / `#tfoot` take role-complete rows
486
+
487
+ These three slots replace a whole row group, and the markup you pass into them
488
+ is now grid markup: a `<div role="row">` per row holding one
489
+ `<div role="columnheader">` (head) or `<div role="cell">` (body, foot) per
490
+ column — **never** a `<tr>` / `<th>` / `<td>`. A `<tr>` inside a grid is not
491
+ just wrong semantically: the `<tr>` is blockified into a single grid item and
492
+ the browser wraps its `<td>`s in an anonymous CSS table (under SSR the parser
493
+ drops the tags outright), so the cells never land on the tracks.
494
+
495
+ Rows are subgrid rows, so a cell takes the matching column track with no
496
+ width of its own. A cell that spans columns uses `grid-column`, not `colspan`:
497
+ the slot's `columnCount` (total rendered columns, selection and actions
498
+ included) is still handed to `#tfoot`, and it now feeds `grid-column: span N`
499
+ / `grid-column: 1 / -1` instead of a `colspan` attribute. Add `aria-colspan`
500
+ on a spanning cell so column math stays right for assistive technology.
501
+
502
+ ```diff
503
+ <template #tfoot="{ columnCount }">
504
+ - <tr>
505
+ - <td :colspan="columnCount - 1">Total</td>
506
+ - <td class="text-right">{{ total }}</td>
507
+ - </tr>
508
+ + <div role="row">
509
+ + <div
510
+ + role="cell"
511
+ + :aria-colspan="columnCount - 1"
512
+ + :style="{ gridColumn: `span ${columnCount - 1}` }"
513
+ + >
514
+ + Total
515
+ + </div>
516
+ + <div role="cell" class="text-right">{{ total }}</div>
517
+ + </div>
518
+ </template>
519
+ ```
520
+
521
+ A full-width row is `grid-column: 1 / -1` on its single cell (plus
522
+ `aria-colspan="columnCount"`). Keep the invariant the component keeps: no
523
+ role-bearing element between the row group and the row, and every child of a
524
+ row is a `cell` or `columnheader`. **Nothing lints this** — a slot ported to
525
+ `<div>`s without roles renders fine and ships a table screen readers cannot
526
+ read; the docs are the only guard, hence the emphasis.
527
+
528
+ Two side effects of replacing the header: the table measures its column
529
+ tracks off the header cells, so with a custom `#thead` it falls back to the
530
+ first row with one child per track (the first data row) — **a custom header
531
+ over an empty table publishes no tracks**, and a nested table cannot inherit
532
+ from it until rows arrive. And under `fixed-headers`, a `#thead` with several
533
+ rows now sticks as a block (all rows stack); the old cell-level sticky stacked
534
+ them on top of each other.
535
+
536
+ ### `--fill` and `--natural-width` are removed, not renamed
537
+
538
+ Both were plumbing for the `table-layout: fixed` self-correction loop (a
539
+ measured natural width the table could never shrink below, and a fill
540
+ correction that compensated fixed-layout arithmetic). The grid has no such
541
+ loop: tracks are sized by the engine from the declarations, in one layout
542
+ pass, with no offscreen probe. Republishing the sum of the resolved tracks
543
+ under the same names would publish the _container_ width under a name
544
+ promising the _natural_ width — wrong by 2× in the panel's probe — so they
545
+ are dropped outright, the same treatment `--available-height` got. No consumer
546
+ outside the component's own stylesheet ever read them; a
547
+ `var(--natural-width)` in your CSS now resolves to its fallback.
548
+
549
+ ### Column widths: what holds and what drifts
550
+
551
+ Frozen widths (`columns[].width`) hold **exactly**: a `120px` column is
552
+ 120px. The overflow threshold (the container width at which the table starts
553
+ scrolling) and the wrap floor (the narrowest a column gets before its text
554
+ wraps) are **pixel-identical** to table auto layout — the panel measured 905px
555
+ against 905px. `fixed` still splits the width equally (`minmax(0, 1fr)` per
556
+ column). Everything else below is documented drift, each with the numbers
557
+ from the panel's probes (`plans/BBTABLE-GRID.md` § Tracks and § v2.1), so
558
+ you know what a screenshot diff is showing you:
559
+
560
+ - **Roomy containers share the surplus equally, not proportionally to
561
+ content.** Two auto columns that the table sized 748px / 52px now come out
562
+ 544px / 256px. Short columns get wider; long ones narrower. Add a `width` to
563
+ any column whose proportion you relied on.
564
+ - **Constrained wrapping distributes differently.** When several wrappable
565
+ columns compete for a narrow container, tracks grow in equal increments up
566
+ to their max-content instead of proportionally — the longest column ends up
567
+ ~22% narrower and its rows taller. The table starts scrolling at the same
568
+ width as before; only the split before that point moved.
569
+ - **Frozen + auto mixes drift ≤ ~19px per column** — the fixed-layout regime
570
+ where declared widths sat next to unfrozen ones.
571
+ - **All-frozen tables inflate their data columns exactly as before, but not
572
+ the structural ones.** When every column declares a width and the sum is
573
+ below the container, the surplus is still shared in proportion to the
574
+ declared widths (`[100, 200, 100]` at 600px → `[150, 300, 150]`, `%` too),
575
+ so the table keeps filling. The selection and actions columns stay at
576
+ content width instead of inflating with the rest.
577
+ - **A cell that is its own scroll container no longer floors the column.**
578
+ Under table auto layout an `overflow: hidden` / `auto` cell still
579
+ contributed its content width to the column. Under grid it does not — which
580
+ means native `text-overflow: ellipsis` finally works in a cell — **and the
581
+ classic table trick `max-width: 0` breaks**: the cell collapses to its
582
+ padding. Delete every `max-width: 0` you added to make ellipsis work.
583
+ - **Percentage widths in an overflowing table resolve against the grid's
584
+ min-content width**, not the container: a `30%` column that the table gave
585
+ 181px gets 303px once the table overflows. Non-overflowing tables are
586
+ identical. (`width: fit-content` on the grid root keeps the root's box
587
+ covering its tracks only without `%` tracks under overflow — a `%`-wide
588
+ overflowing table is the one case where row backgrounds can paint short of
589
+ the scroll width.)
590
+ - **Expand-row content never widens the parent's columns.** A wide nested
591
+ table or a long unbroken string in `#expand` used to push an auto-layout
592
+ parent's columns apart (a 300px track became 500px in the probe); the grid
593
+ contains the full-width cells (`contain: inline-size`), so the parent's
594
+ tracks hold and the content overflows into the scrollport instead. Fixed
595
+ layout was already immune; auto layout was not; the grid always is.
596
+ - **A `snap` on a column whose table has no parent** used to fall into an
597
+ accidental equal split. It now sizes like any other unfrozen column
598
+ (`auto`).
599
+ - **Nested tables align by contract, at any depth.** A child's select/actions
600
+ cell is widened to the parent's region (`minmax(region, max-content)` — two
601
+ equal cells, controls at the row's end); a child without one folds the
602
+ region into its edge cell's padding. A child cell _wider_ than the parent's
603
+ is reclaimed from the adjacent content column only. What each table
604
+ publishes to its own children is the pure content rails plus the two
605
+ regions, so a grandchild aligns with the root — previously the middle
606
+ table's padding compensation was invisible to its children. The fill
607
+ column now only ever grows (`minmax(<its rail>, 1fr)`); it no longer
608
+ shrinks to absorb a wider actions column.
609
+
610
+ ### Copy-to-spreadsheet degrades
611
+
612
+ Selecting rows in a real `<table>` and pasting into a spreadsheet gave one
613
+ cell per column. Chrome's selection serializer keys off the computed
614
+ `display`, not the element or its role, so a grid pastes **one value per
615
+ line** — the columns are lost. Accepted: the substrate is not going to carry a
616
+ hidden `<table>` for the clipboard. The sanctioned path is an app-level
617
+ "copy as TSV" action built from the **items model** (the same rows you gave
618
+ `items`, joined with tabs and newlines and written with `navigator.clipboard`)
619
+ — a recipe for it is queued (FOLLOWUPS Q7.4); do not scrape the DOM for it.
620
+
621
+ ### Print: header repetition is gone
622
+
623
+ Browsers repeat a `<thead>` at the top of every printed page; there is no
624
+ grid equivalent, so a long table prints its header once. Data rows carry
625
+ `break-inside: avoid` so a row is never split across pages, which is the most
626
+ the substrate can do. No `@media print` rule exists in the library, so nothing
627
+ of yours is fighting one — but if a printed report depended on the repeated
628
+ header, that is a real regression to plan for (a print-specific view, or
629
+ paginated sections with their own headers).
630
+
631
+ ### Global element CSS no longer reaches the table
632
+
633
+ Any CSS that reached `BbTable` through element names now misses it: a reset
634
+ (`table { border-collapse: … }`, `td, th { padding: 0 }`), Tailwind's
635
+ `.prose table` typography, a stray `td { vertical-align: top }` in a legacy
636
+ sheet. This cuts both ways. It is an **immunity** — the table no longer
637
+ inherits whatever global table styling the app carries — and it is a **silent
638
+ change** on every page where that global CSS was, knowingly or not, part of
639
+ the look. Diff those pages; then re-express what you actually wanted on
640
+ `.bb-table-data__cell` / `[role=cell]` scoped to a table.
641
+
642
+ ### Browser floor
643
+
644
+ The table requires `grid-template-columns: subgrid`: **Chrome/Edge 117,
645
+ Firefox 71, Safari 16**. There is no `@supports` fallback and none is planned —
646
+ maintaining two substrates defeats the rewrite. Cell content is centred
647
+ vertically with `align-content` on a block container, which lands one notch
648
+ higher: **Chrome 123, Safari 17.4, Firefox 125**. Below that, cells still lay
649
+ out correctly but content sits at the top of the cell instead of the middle.
650
+
651
+ All of this sits inside the library-wide floor — **Chrome/Edge 114, Safari 17,
652
+ Firefox 125**, set by the native Popover API (see
653
+ `installation-and-plugin-setup.md` § Browser support) — so the only engine the
654
+ grid actually raises is Chrome/Edge, 114 → 117 (123 for centred cells).
655
+
656
+ ### Do not override
657
+
658
+ - **Do not hide cells with `display: none`** (a `thClass`/`tdClass` of
659
+ `hidden`, the v2/early-v3 narrow-screen recipe). A hidden grid item leaves
660
+ its track in place: every following cell shifts one track over and the last
661
+ track collapses. Hide a column with `hidden: true` on its definition at the
662
+ breakpoint, which removes the track while the column stays declared (so
663
+ its slot in `order` survives). Filtering it out of `columns` was the
664
+ interim advice and is now reserved for a column that does not exist for
665
+ this user at all.
666
+ - **`contain: inline-size` on `.bb-table-expand__cell`,
667
+ `.bb-table-no-data__cell` and `.bb-table-loading__cell`.** It is the only
668
+ thing keeping a full-width cell's content from resizing the column tracks —
669
+ `min-width: 0` and `width: 100%` wrappers do not work here, and with a nested
670
+ inheriting table inside the expand row the result without it is a feedback
671
+ loop. Removing it (or setting `contain: none` on a cell) is not a styling
672
+ choice.
673
+ - **`gap: 0` on `.bb-table__table`.** A gap set on the root cannot be undone
674
+ from a subgrid level; it opens gutters between every column.
675
+ - **`display: grid` on the root, row groups and rows**, and the
676
+ `grid-column: 1 / -1` on the full-width cells — the geometry.
677
+ - **`white-space: nowrap` on `.bb-table__cell--actions`** — the actions track
678
+ is `max-content`, and `nowrap` is what makes that the width of the controls
679
+ side by side rather than a wrapped stack.
680
+ - **`position: sticky` on `.bb-table__head`** under `fixed-headers`: sticky
681
+ lives on the row group, not on cells — a sticky cell inside the subgrid
682
+ cannot stick in any engine.
683
+
684
+ ### Small semantic and visual changes
685
+
686
+ - **Pinned cells and the stuck header are opaque.** Pinned (`column.fixed`) cells and
687
+ the `fixed-headers` band used to be transparent, so scrolled content showed
688
+ through them. They now paint the table's surface local `--bg` (default
689
+ `var(--bb-panel)`); a pinned cell also paints its row's hover/highlight
690
+ tint. On a non-panel surface set `.bb-table { --bg: … }` once. The
691
+ highlighted row's left accent bar moved from the row onto its first cell
692
+ (same position; an opaque pinned first column would have hidden it).
693
+ - **The sort glyph is one arrow.** The two-chevron `sort.svg` (with its
694
+ inner `sort-icon__asc` / `sort-icon__desc` paths) is gone; the sort button
695
+ renders an inline `<svg class="bb-table-sort__icon">` — a single arrow,
696
+ hidden at rest, faint on hover/focus, solid when sorted: up for ascending,
697
+ rotated down for descending (the AG Grid convention). Apps that copied the old glyph to rebuild
698
+ a header no longer need to (use the header prepend/append slots); any CSS
699
+ on `.sort-icon__asc` / `.sort-icon__desc` matches nothing.
700
+ - **Caption reading order.** The caption is now a `div` _before_ the table
701
+ role, named through `aria-labelledby`, rather than a `<caption>` inside it.
702
+ The accessible name is identical; a screen reader reading linearly meets the
703
+ caption text just before the table instead of as its first child.
704
+ - **The busy bar rides with a stuck header.** With `fixed-headers`, the
705
+ refetch progress bar is anchored to the sticky head row group, so it stays
706
+ at the header/body boundary while you scroll. It used to anchor to the
707
+ in-flow `<thead>` box and scroll away while the header cells stuck — the
708
+ documented intent, now the behavior.
709
+ - **Multi-row `#thead` heads stack when stuck** (above).
710
+ - **`aria-rowcount` now counts the header row**: it is `totalItems + 1`, so
711
+ the last row's `aria-rowindex` no longer exceeds the count. Anything
712
+ asserting the old value must add one.
713
+ - **Row heights change with the wrapping drift** — expect it in screenshot
714
+ diffs of narrow, text-heavy tables.
715
+
187
716
  ## The custom properties the table _publishes_ lost the `bb-` prefix
188
717
 
189
718
  These are not theming inputs — they are values `BbTable` measures at runtime and
@@ -191,18 +720,21 @@ writes onto its own DOM, for the table's CSS and for descendants to read. You
191
720
  reach for them for exactly one reason: aligning a nested table's columns to its
192
721
  parent's. They all dropped the prefix.
193
722
 
194
- | v2 | v3 |
195
- | ------------------------------------------- | ------------------------------------------- |
196
- | `--bb-table-{id}-track-{key}` | `--table-{id}-track-{key}` |
197
- | `--bb-table-offset-start` / `-end` | `--offset-start` / `--offset-end` |
198
- | `--bb-table-offset-internal-start` / `-end` | `--offset-internal-start` / `-internal-end` |
199
- | `--bb-table-offset-external-start` / `-end` | `--offset-external-start` / `-external-end` |
200
- | `--bb-table-fill` | `--fill` |
201
- | `--bb-table-natural-width` | `--natural-width` |
202
- | `--bb-table-cell-h` | `--cell-h` |
723
+ | v2 | v3 |
724
+ | ------------------------------------------- | -------------------------------------------------- |
725
+ | `--bb-table-{id}-track-{key}` | `--table-{id}-track-{key}` |
726
+ | `--bb-table-offset-start` / `-end` | `--offset-start` / `--offset-end` |
727
+ | `--bb-table-offset-internal-start` / `-end` | `--offset-internal-start` / `-internal-end` |
728
+ | `--bb-table-offset-external-start` / `-end` | `--offset-external-start` / `-external-end` |
729
+ | `--bb-table-fill` | **removed** (was `--fill` in v3 ≤ beta.5) |
730
+ | `--bb-table-natural-width` | **removed** (was `--natural-width` in v3 ≤ beta.5) |
731
+ | `--bb-table-cell-h` | `--cell-h` |
203
732
 
204
733
  Only the track bridge keeps a `table-` segment, because it crosses component
205
- boundaries; the rest are plain locals on `.bb-table`. `--padding-x`,
734
+ boundaries; the rest are plain locals on `.bb-table`. `--fill` and
735
+ `--natural-width` were the fixed-layout self-correction values; the grid
736
+ substrate (next section) has no such loop, so they are gone rather than
737
+ republished under a name that would lie about what they hold. `--padding-x`,
206
738
  `--padding-y` and `--actions-spacing` were already unprefixed in v2 and keep
207
739
  their names (their _values_ tightened: `16px`/`8px` → `12px`/`6px`, and the cell
208
740
  height `42px` → `36px`).