bitboss-ui 3.0.0-beta.65 → 3.0.0-beta.66

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 (528) hide show
  1. package/README.md +78 -16
  2. package/bin/bitboss-ui-mcp.mjs +8 -8
  3. package/bin/bitboss-ui.mjs +73 -12
  4. package/dist/ai/BbAccordion.md +4 -3
  5. package/dist/ai/BbAlert.md +1 -1
  6. package/dist/ai/BbBadge.md +1 -0
  7. package/dist/ai/BbBadgeButton.md +4 -3
  8. package/dist/ai/BbBaseButton.md +25 -20
  9. package/dist/ai/BbBaseCheckboxIcon.md +1 -0
  10. package/dist/ai/BbBaseRadioIcon.md +1 -0
  11. package/dist/ai/BbBaseSwitchIcon.md +1 -0
  12. package/dist/ai/BbBreadcrumbs.md +8 -0
  13. package/dist/ai/BbButton.md +67 -21
  14. package/dist/ai/BbCalendar.md +56 -3
  15. package/dist/ai/BbCheckbox.md +1 -1
  16. package/dist/ai/BbCheckboxGroup.md +44 -8
  17. package/dist/ai/BbColorInput.md +3 -2
  18. package/dist/ai/BbColorPalette.md +7 -3
  19. package/dist/ai/BbConfirm.md +36 -80
  20. package/dist/ai/BbConfirmPortal.md +1 -1
  21. package/dist/ai/BbDatePicker.md +41 -5
  22. package/dist/ai/BbDatePickerInput.md +38 -6
  23. package/dist/ai/BbDialog.md +63 -58
  24. package/dist/ai/BbDropdown.md +25 -24
  25. package/dist/ai/BbDropdownButton.md +5 -12
  26. package/dist/ai/BbDropzone.md +2 -3
  27. package/dist/ai/BbForm.md +66 -42
  28. package/dist/ai/BbHost.md +29 -41
  29. package/dist/ai/BbIcon.md +3 -0
  30. package/dist/ai/BbNumberInput.md +2 -2
  31. package/dist/ai/BbOffCanvas.md +16 -9
  32. package/dist/ai/BbPagination.md +17 -17
  33. package/dist/ai/BbPopover.md +8 -3
  34. package/dist/ai/BbPtScope.md +5 -5
  35. package/dist/ai/BbRadio.md +1 -1
  36. package/dist/ai/BbRadioGroup.md +44 -7
  37. package/dist/ai/BbRating.md +1 -0
  38. package/dist/ai/BbSelect.md +146 -21
  39. package/dist/ai/BbSelectPopover.md +16 -12
  40. package/dist/ai/BbSlider.md +5 -3
  41. package/dist/ai/BbSwitch.md +1 -1
  42. package/dist/ai/BbTable.md +51 -39
  43. package/dist/ai/BbTabs.md +127 -63
  44. package/dist/ai/BbTabsList.md +4 -2
  45. package/dist/ai/BbTabsPanels.md +3 -1
  46. package/dist/ai/BbTabsRoot.md +4 -4
  47. package/dist/ai/BbTag.md +2 -2
  48. package/dist/ai/BbTextInput.md +23 -9
  49. package/dist/ai/BbTextarea.md +3 -3
  50. package/dist/ai/BbTimePicker.md +5 -4
  51. package/dist/ai/BbTimePickerInput.md +3 -3
  52. package/dist/ai/BbToast.md +33 -87
  53. package/dist/ai/BbToastPortal.md +1 -1
  54. package/dist/ai/CommonFieldInput.md +2 -1
  55. package/dist/ai/FlatListBox.md +1 -1
  56. package/dist/ai/GroupedListBox.md +1 -1
  57. package/dist/ai/ListBox.md +1 -1
  58. package/dist/ai/OptionsContainer.md +1 -1
  59. package/dist/ai/changelog.json +366 -4
  60. package/dist/ai/components.json +87 -83
  61. package/dist/ai/composables/{useBbDialogContext.md → useBbDialog.md} +18 -18
  62. package/dist/ai/composables/{useBbDropdownContext.md → useBbDropdown.md} +31 -31
  63. package/dist/ai/composables/{useBbFormContext.md → useBbForm.md} +11 -11
  64. package/dist/ai/composables/useBbFormField.md +2 -2
  65. package/dist/ai/composables/{useBbOffCanvasContext.md → useBbOffCanvas.md} +13 -13
  66. package/dist/ai/composables/{useBbTableContext.md → useBbTable.md} +20 -20
  67. package/dist/ai/composables/{useBbTabsContext.md → useBbTabs.md} +12 -12
  68. package/dist/ai/composables/useConfirm.md +42 -54
  69. package/dist/ai/composables/useToast.md +9 -26
  70. package/dist/ai/guides/agent-contract.md +57 -43
  71. package/dist/ai/guides/ai-router.md +1 -1
  72. package/dist/ai/guides/app-layout.md +32 -23
  73. package/dist/ai/guides/coherence-playbook.md +4 -2
  74. package/dist/ai/guides/component-picker.md +35 -32
  75. package/dist/ai/guides/design-language.md +26 -12
  76. package/dist/ai/guides/design-tokens.md +73 -32
  77. package/dist/ai/guides/eslint-rules.md +8 -4
  78. package/dist/ai/guides/fetch-items-playbook.md +3 -3
  79. package/dist/ai/guides/floating-bottom-panel.md +1 -1
  80. package/dist/ai/guides/inertia-helpers.md +661 -210
  81. package/dist/ai/guides/installation-and-plugin-setup.md +6 -3
  82. package/dist/ai/guides/migration/adoption-checklist.md +44 -2
  83. package/dist/ai/guides/migration/components/bb-dialog.md +13 -13
  84. package/dist/ai/guides/migration/components/bb-dropdown.md +16 -16
  85. package/dist/ai/guides/migration/components/bb-host.md +15 -14
  86. package/dist/ai/guides/migration/components/bb-offcanvas.md +10 -10
  87. package/dist/ai/guides/migration/components/bb-pagination.md +9 -9
  88. package/dist/ai/guides/migration/components/bb-select.md +1 -1
  89. package/dist/ai/guides/migration/components/bb-table.md +12 -12
  90. package/dist/ai/guides/migration/components/bb-tabs.md +1 -1
  91. package/dist/ai/guides/migration/from-async-validator.md +9 -9
  92. package/dist/ai/guides/migration/v2-to-v3.md +158 -13
  93. package/dist/ai/guides/options-items-playbook.md +2 -2
  94. package/dist/ai/guides/page-shell.md +15 -3
  95. package/dist/ai/guides/passthrough.md +9 -5
  96. package/dist/ai/guides/preset-components.md +102 -43
  97. package/dist/ai/guides/typescript-generic-components.md +21 -5
  98. package/dist/ai/guides/validated-forms.md +20 -11
  99. package/dist/ai/guides/validation-providers.md +3 -3
  100. package/dist/ai/helpers/definePreset.json +11 -4
  101. package/dist/ai/helpers/definePreset.ts +98 -41
  102. package/dist/ai/helpers/inertia/manifest.json +234 -76
  103. package/dist/ai/helpers/inertia/useConfirmOnRouteLeave.ts +24 -12
  104. package/dist/ai/helpers/inertia/usePromiseForm.ts +38 -151
  105. package/dist/ai/helpers/inertia/usePromiseRouter.ts +295 -0
  106. package/dist/ai/helpers/inertia/useQueryObject.ts +36 -5
  107. package/dist/ai/helpers/inertia/useRouteQuery.ts +28 -9
  108. package/dist/ai/helpers/inertia/utils.ts +53 -10
  109. package/dist/ai/index.md +15 -15
  110. package/dist/ai/manifest/common.json +2 -1
  111. package/dist/ai/manifest/components/BbAccordion.tree.json +3 -1
  112. package/dist/ai/manifest/components/BbAlert.json +1 -1
  113. package/dist/ai/manifest/components/BbBadge.tree.json +3 -1
  114. package/dist/ai/manifest/components/BbBadgeButton.json +9 -4
  115. package/dist/ai/manifest/components/BbBadgeButton.tree.json +1 -0
  116. package/dist/ai/manifest/components/BbBaseButton.json +9 -4
  117. package/dist/ai/manifest/components/BbBaseCheckboxIcon.tree.json +3 -1
  118. package/dist/ai/manifest/components/BbBaseRadioIcon.tree.json +3 -1
  119. package/dist/ai/manifest/components/BbBaseSwitchIcon.tree.json +3 -1
  120. package/dist/ai/manifest/components/BbBreadcrumbs.tree.json +7 -3
  121. package/dist/ai/manifest/components/BbButton.json +9 -4
  122. package/dist/ai/manifest/components/BbButton.tree.json +5 -3
  123. package/dist/ai/manifest/components/BbCalendar.json +4 -3
  124. package/dist/ai/manifest/components/BbCalendar.tree.json +10 -1
  125. package/dist/ai/manifest/components/BbCheckbox.json +1 -1
  126. package/dist/ai/manifest/components/BbCheckbox.tree.json +1 -1
  127. package/dist/ai/manifest/components/BbCheckboxGroup.json +1 -1
  128. package/dist/ai/manifest/components/BbCheckboxGroup.tree.json +62 -3
  129. package/dist/ai/manifest/components/BbCollapsible.json +4 -1
  130. package/dist/ai/manifest/components/BbColorInput.json +1 -1
  131. package/dist/ai/manifest/components/BbColorInput.tree.json +5 -3
  132. package/dist/ai/manifest/components/BbColorPalette.json +3 -0
  133. package/dist/ai/manifest/components/BbColorPalette.tree.json +7 -2
  134. package/dist/ai/manifest/components/BbConfirm.tree.json +2 -2
  135. package/dist/ai/manifest/components/BbDatePicker.json +7 -3
  136. package/dist/ai/manifest/components/BbDatePicker.tree.json +3 -4
  137. package/dist/ai/manifest/components/BbDatePickerInput.json +4 -3
  138. package/dist/ai/manifest/components/BbDatePickerInput.tree.json +5 -3
  139. package/dist/ai/manifest/components/BbDialog.json +1 -1
  140. package/dist/ai/manifest/components/BbDialog.tree.json +2 -2
  141. package/dist/ai/manifest/components/BbDropdown.json +3 -3
  142. package/dist/ai/manifest/components/BbDropdown.tree.json +2 -2
  143. package/dist/ai/manifest/components/BbDropdownButton.json +11 -6
  144. package/dist/ai/manifest/components/BbDropdownButton.tree.json +2 -3
  145. package/dist/ai/manifest/components/BbDropzone.json +4 -1
  146. package/dist/ai/manifest/components/BbForm.json +2 -2
  147. package/dist/ai/manifest/components/BbHost.json +1 -1
  148. package/dist/ai/manifest/components/BbHost.tree.json +1 -1
  149. package/dist/ai/manifest/components/BbHoverCard.json +1 -1
  150. package/dist/ai/manifest/components/BbNumberInput.json +1 -1
  151. package/dist/ai/manifest/components/BbNumberInput.tree.json +1 -1
  152. package/dist/ai/manifest/components/BbOffCanvas.json +1 -1
  153. package/dist/ai/manifest/components/BbOffCanvas.tree.json +3 -1
  154. package/dist/ai/manifest/components/BbPagination.json +4 -4
  155. package/dist/ai/manifest/components/BbPagination.tree.json +2 -1
  156. package/dist/ai/manifest/components/BbPopover.json +1 -1
  157. package/dist/ai/manifest/components/BbPopover.tree.json +1 -1
  158. package/dist/ai/manifest/components/BbProgress.json +4 -1
  159. package/dist/ai/manifest/components/BbRadio.json +1 -1
  160. package/dist/ai/manifest/components/BbRadio.tree.json +1 -1
  161. package/dist/ai/manifest/components/BbRadioGroup.json +5 -5
  162. package/dist/ai/manifest/components/BbRadioGroup.tree.json +62 -3
  163. package/dist/ai/manifest/components/BbRating.tree.json +3 -1
  164. package/dist/ai/manifest/components/BbSelect.json +5 -5
  165. package/dist/ai/manifest/components/BbSelect.tree.json +3 -3
  166. package/dist/ai/manifest/components/BbSelectPopover.json +7 -3
  167. package/dist/ai/manifest/components/BbSelectPopover.tree.json +2 -2
  168. package/dist/ai/manifest/components/BbSlider.json +3 -3
  169. package/dist/ai/manifest/components/BbSlider.tree.json +3 -0
  170. package/dist/ai/manifest/components/BbSmoothHeight.json +4 -1
  171. package/dist/ai/manifest/components/BbSwitch.json +1 -1
  172. package/dist/ai/manifest/components/BbSwitch.tree.json +1 -1
  173. package/dist/ai/manifest/components/BbSwitchGroup.tree.json +1 -1
  174. package/dist/ai/manifest/components/BbTable.json +6 -2
  175. package/dist/ai/manifest/components/BbTable.tree.json +4 -1
  176. package/dist/ai/manifest/components/BbTabs.json +9 -12
  177. package/dist/ai/manifest/components/BbTabs.tree.json +4 -1
  178. package/dist/ai/manifest/components/BbTabsList.json +4 -7
  179. package/dist/ai/manifest/components/BbTabsList.tree.json +4 -1
  180. package/dist/ai/manifest/components/BbTabsPanels.json +1 -1
  181. package/dist/ai/manifest/components/BbTabsPanels.tree.json +4 -1
  182. package/dist/ai/manifest/components/BbTabsRoot.json +5 -5
  183. package/dist/ai/manifest/components/BbTag.json +1 -1
  184. package/dist/ai/manifest/components/BbTag.tree.json +2 -2
  185. package/dist/ai/manifest/components/BbTextInput.json +4 -4
  186. package/dist/ai/manifest/components/BbTextInput.tree.json +1 -1
  187. package/dist/ai/manifest/components/BbTextarea.json +2 -2
  188. package/dist/ai/manifest/components/BbTextarea.tree.json +1 -1
  189. package/dist/ai/manifest/components/BbTimePicker.json +4 -1
  190. package/dist/ai/manifest/components/BbTimePicker.tree.json +5 -3
  191. package/dist/ai/manifest/components/BbTimePickerInput.json +2 -2
  192. package/dist/ai/manifest/components/BbTimePickerInput.tree.json +5 -3
  193. package/dist/ai/manifest/components/BbToast.json +1 -1
  194. package/dist/ai/manifest/components/BbToast.tree.json +3 -1
  195. package/dist/ai/manifest/components/BbTooltip.json +3 -0
  196. package/dist/ai/manifest/components/ChipsBox.tree.json +1 -1
  197. package/dist/ai/manifest/components/CommonField.tree.json +1 -0
  198. package/dist/ai/manifest/components/CommonFieldInput.tree.json +4 -2
  199. package/dist/ai/manifest/components/CommonTimeSelector.tree.json +1 -0
  200. package/dist/ai/manifest/components/FlatListBox.json +1 -1
  201. package/dist/ai/manifest/components/GroupedListBox.json +1 -1
  202. package/dist/ai/manifest/components/ListBox.json +1 -1
  203. package/dist/ai/manifest/components/OptionsContainer.json +2 -2
  204. package/dist/ai/manifest/index.json +3 -3
  205. package/dist/ai/manifest/meta.json +31 -16
  206. package/dist/ai/manifest/types.advanced.json +15 -11
  207. package/dist/ai/manifest/types.api.json +2 -2
  208. package/dist/ai/recipes/inertia/approvals-inbox.md +86 -115
  209. package/dist/ai/recipes/inertia/inline-edit-workspace.md +112 -120
  210. package/dist/ai/recipes/inertia/layout-scaffold.md +15 -4
  211. package/dist/ai/recipes/inertia/onboarding.md +76 -58
  212. package/dist/ai/recipes/inertia/ownership-atlas.md +74 -105
  213. package/dist/ai/recipes/inertia/record-form.md +18 -7
  214. package/dist/ai/recipes/inertia/records-workspace.md +106 -127
  215. package/dist/ai/recipes/inertia/settings-workspace.md +131 -73
  216. package/dist/ai/recipes/inertia/upload-center.md +97 -121
  217. package/dist/ai/recipes/inertia/wizard-form.md +25 -15
  218. package/dist/ai/recipes/nuxt/approvals-inbox.md +67 -48
  219. package/dist/ai/recipes/nuxt/inline-edit-workspace.md +73 -58
  220. package/dist/ai/recipes/nuxt/layout-scaffold.md +15 -4
  221. package/dist/ai/recipes/nuxt/onboarding.md +27 -10
  222. package/dist/ai/recipes/nuxt/ownership-atlas.md +40 -22
  223. package/dist/ai/recipes/nuxt/record-form.md +20 -7
  224. package/dist/ai/recipes/nuxt/records-workspace.md +120 -96
  225. package/dist/ai/recipes/nuxt/settings-workspace.md +36 -23
  226. package/dist/ai/recipes/nuxt/upload-center.md +63 -37
  227. package/dist/ai/recipes/nuxt/wizard-form.md +28 -16
  228. package/dist/ai/recipes/vue/approvals-inbox.md +74 -46
  229. package/dist/ai/recipes/vue/inline-edit-workspace.md +83 -56
  230. package/dist/ai/recipes/vue/layout-scaffold.md +15 -4
  231. package/dist/ai/recipes/vue/onboarding.md +27 -10
  232. package/dist/ai/recipes/vue/ownership-atlas.md +40 -22
  233. package/dist/ai/recipes/vue/record-form.md +20 -7
  234. package/dist/ai/recipes/vue/records-workspace.md +132 -95
  235. package/dist/ai/recipes/vue/settings-workspace.md +36 -23
  236. package/dist/ai/recipes/vue/upload-center.md +73 -37
  237. package/dist/ai/recipes/vue/wizard-form.md +28 -16
  238. package/dist/ai/source/BbAccordion.md +36 -6
  239. package/dist/ai/source/BbAlert.md +11 -5
  240. package/dist/ai/source/BbAsterisk.md +4 -1
  241. package/dist/ai/source/BbAvatar.md +11 -5
  242. package/dist/ai/source/BbBadge.md +42 -11
  243. package/dist/ai/source/BbBadgeButton.md +41 -8
  244. package/dist/ai/source/BbBaseButton.md +57 -15
  245. package/dist/ai/source/BbBaseCheckboxIcon.md +37 -13
  246. package/dist/ai/source/BbBaseRadioIcon.md +32 -9
  247. package/dist/ai/source/BbBaseSwitchIcon.md +31 -7
  248. package/dist/ai/source/BbBreadcrumbs.md +32 -9
  249. package/dist/ai/source/BbButton.md +91 -27
  250. package/dist/ai/source/BbCalendar.md +571 -300
  251. package/dist/ai/source/BbCheckbox.md +18 -7
  252. package/dist/ai/source/BbCheckboxGroup.md +16 -5
  253. package/dist/ai/source/BbCollapsible.md +15 -6
  254. package/dist/ai/source/BbColorInput.md +68 -20
  255. package/dist/ai/source/BbColorPalette.md +107 -23
  256. package/dist/ai/source/BbConfirmPortal.md +1 -1
  257. package/dist/ai/source/BbDatePicker.md +106 -25
  258. package/dist/ai/source/BbDatePickerInput.md +105 -42
  259. package/dist/ai/source/BbDialog.md +60 -44
  260. package/dist/ai/source/BbDropdown.md +44 -32
  261. package/dist/ai/source/BbDropdownButton.md +26 -20
  262. package/dist/ai/source/BbDropdownGroup.md +5 -5
  263. package/dist/ai/source/BbDropzone.md +53 -16
  264. package/dist/ai/source/BbForm.md +18 -7
  265. package/dist/ai/source/BbHost.md +25 -12
  266. package/dist/ai/source/BbHoverCard.md +20 -9
  267. package/dist/ai/source/BbIcon.md +9 -3
  268. package/dist/ai/source/BbIndicator.md +11 -4
  269. package/dist/ai/source/BbNumberInput.md +23 -6
  270. package/dist/ai/source/BbOffCanvas.md +73 -32
  271. package/dist/ai/source/BbPagination.md +59 -31
  272. package/dist/ai/source/BbPopover.md +28 -16
  273. package/dist/ai/source/BbProgress.md +13 -5
  274. package/dist/ai/source/BbRadio.md +16 -9
  275. package/dist/ai/source/BbRadioGroup.md +15 -4
  276. package/dist/ai/source/BbRating.md +51 -10
  277. package/dist/ai/source/BbSelect.md +56 -27
  278. package/dist/ai/source/BbSelectPopover.md +81 -35
  279. package/dist/ai/source/BbSlider.md +111 -33
  280. package/dist/ai/source/BbSmoothHeight.md +16 -7
  281. package/dist/ai/source/BbSpinner.md +9 -3
  282. package/dist/ai/source/BbSwitch.md +16 -9
  283. package/dist/ai/source/BbSwitchGroup.md +18 -7
  284. package/dist/ai/source/BbTable.md +172 -38
  285. package/dist/ai/source/BbTabs.md +58 -40
  286. package/dist/ai/source/BbTabsList.md +109 -50
  287. package/dist/ai/source/BbTabsPanels.md +65 -31
  288. package/dist/ai/source/BbTabsRoot.md +35 -24
  289. package/dist/ai/source/BbTag.md +18 -4
  290. package/dist/ai/source/BbTextInput.md +20 -3
  291. package/dist/ai/source/BbTextarea.md +15 -1
  292. package/dist/ai/source/BbTimePicker.md +81 -21
  293. package/dist/ai/source/BbTimePickerInput.md +63 -15
  294. package/dist/ai/source/BbToast.md +20 -3
  295. package/dist/ai/source/BbToastPortal.md +21 -4
  296. package/dist/ai/source/BbTooltip.md +16 -8
  297. package/dist/ai/source/BbTree.md +10 -3
  298. package/dist/ai/source/ClearableButton.md +5 -1
  299. package/dist/ai/source/CommonField.md +65 -9
  300. package/dist/ai/source/CommonFieldInput.md +61 -27
  301. package/dist/ai/source/CommonPopover.md +17 -6
  302. package/dist/ai/source/CommonTimeSelector.md +21 -2
  303. package/dist/ai/source/ErrorIcon.md +4 -0
  304. package/dist/ai/source/ListBox.md +9 -1
  305. package/dist/ai/source/OptionsContainer.md +5 -1
  306. package/dist/ai/source/WarningIcon.md +4 -0
  307. package/dist/components/BbAccordion/BbAccordion.vue.d.ts +2 -1
  308. package/dist/components/BbAccordion/BbAccordion.vue_vue_type_script_setup_true_lang.js +6 -6
  309. package/dist/components/BbAlert/BbAlert.vue.d.ts +2 -1
  310. package/dist/components/BbAlert/BbAlert.vue_vue_type_script_setup_true_lang.js +10 -10
  311. package/dist/components/BbAsterisk/BbAsterisk.vue.d.ts +3 -1
  312. package/dist/components/BbAvatar/BbAvatar.vue.d.ts +3 -1
  313. package/dist/components/BbAvatar/BbAvatar.vue_vue_type_script_setup_true_lang.js +7 -7
  314. package/dist/components/BbBadge/BbBadge.vue.d.ts +5 -3
  315. package/dist/components/BbBadge/BbBadge.vue_vue_type_script_setup_true_lang.js +7 -7
  316. package/dist/components/BbBadge/BbBadgeButton.vue.d.ts +3 -1
  317. package/dist/components/BbBadge/BbBadgeButton.vue_vue_type_script_setup_true_lang.js +7 -7
  318. package/dist/components/BbBaseButton/BbBaseButton.vue.d.ts +3 -1
  319. package/dist/components/BbBaseButton/BbBaseButton.vue_vue_type_script_setup_true_lang.js +85 -85
  320. package/dist/components/BbBaseButton/types.d.ts +8 -5
  321. package/dist/components/BbBaseButton/useLinkState.d.ts +2 -0
  322. package/dist/components/BbBaseButton/useLinkState.js +21 -20
  323. package/dist/components/BbBaseCheckboxIcon/BbBaseCheckboxIcon.vue.d.ts +3 -1
  324. package/dist/components/BbBaseRadioIcon/BbBaseRadioIcon.vue.d.ts +3 -1
  325. package/dist/components/BbBaseSwitchIcon/BbBaseSwitchIcon.vue.d.ts +3 -1
  326. package/dist/components/BbBreadcrumbs/BbBreadcrumbs.vue.d.ts +3 -1
  327. package/dist/components/BbBreadcrumbs/BbBreadcrumbs.vue_vue_type_script_setup_true_lang.js +7 -7
  328. package/dist/components/BbButton/BbButton.vue.d.ts +2 -1
  329. package/dist/components/BbButton/BbButton.vue_vue_type_script_setup_true_lang.js +93 -93
  330. package/dist/components/BbButton/types.d.ts +7 -4
  331. package/dist/components/BbCalendar/BbCalendar.vue.d.ts +157 -30
  332. package/dist/components/BbCalendar/BbCalendar.vue_vue_type_script_setup_true_lang.js +364 -331
  333. package/dist/components/BbCalendar/CalendarMonthPanel.vue_vue_type_script_setup_true_lang.js +5 -5
  334. package/dist/components/BbCalendar/types.d.ts +36 -8
  335. package/dist/components/BbCalendar/useCalendarGrid.d.ts +133 -0
  336. package/dist/components/BbCalendar/useCalendarGrid.js +193 -183
  337. package/dist/components/BbCalendar/useDayGrid.d.ts +24 -19
  338. package/dist/components/BbCalendar/useDayGrid.js +105 -102
  339. package/dist/components/BbCheckbox/BbCheckbox.vue.d.ts +4 -2
  340. package/dist/components/BbCheckboxGroup/BbCheckboxGroup.vue.d.ts +327 -2
  341. package/dist/components/BbCollapsible/BbCollapsible.vue.d.ts +3 -1
  342. package/dist/components/BbCollapsible/BbCollapsible.vue_vue_type_script_setup_true_lang.js +6 -6
  343. package/dist/components/BbColorInput/BbColorInput.vue.d.ts +8 -5
  344. package/dist/components/BbColorInput/BbColorInput.vue_vue_type_script_setup_true_lang.js +5 -5
  345. package/dist/components/BbColorInput/types.d.ts +2 -0
  346. package/dist/components/BbColorPalette/BbColorPalette.vue.d.ts +7 -5
  347. package/dist/components/BbColorPalette/BbColorPalette.vue_vue_type_script_setup_true_lang.js +216 -215
  348. package/dist/components/BbConfirm/BbConfirm.vue_vue_type_script_setup_true_lang.js +25 -25
  349. package/dist/components/BbDatePicker/BbDatePicker.vue.d.ts +206 -41
  350. package/dist/components/BbDatePicker/BbDatePicker.vue_vue_type_script_setup_true_lang.js +112 -106
  351. package/dist/components/BbDatePicker/types.d.ts +27 -8
  352. package/dist/components/BbDatePickerInput/BbDatePickerInput.vue.d.ts +519 -37
  353. package/dist/components/BbDatePickerInput/BbDatePickerInput.vue_vue_type_script_setup_true_lang.js +11 -8
  354. package/dist/components/BbDatePickerInput/types.d.ts +31 -9
  355. package/dist/components/BbDialog/BbDialog.vue.d.ts +6 -5
  356. package/dist/components/BbDialog/BbDialog.vue_vue_type_script_setup_true_lang.js +231 -233
  357. package/dist/components/BbDialog/types.d.ts +7 -7
  358. package/dist/components/BbDialog/useDialogStack.d.ts +2 -0
  359. package/dist/components/BbDialog/useDialogStack.js +6 -2
  360. package/dist/components/BbDropdown/AdaptiveDropdown.vue_vue_type_script_setup_true_lang.js +25 -25
  361. package/dist/components/BbDropdown/BbDropdown.vue.d.ts +8 -6
  362. package/dist/components/BbDropdown/BbDropdown.vue_vue_type_script_setup_true_lang.js +226 -225
  363. package/dist/components/BbDropdown/BbDropdownList.vue_vue_type_script_setup_true_lang.js +49 -49
  364. package/dist/components/BbDropdown/DropdownPipelineResolver.vue_vue_type_script_setup_true_lang.js +7 -7
  365. package/dist/components/BbDropdown/normalizeGroups.js +14 -14
  366. package/dist/components/BbDropdown/types.d.ts +5 -5
  367. package/dist/components/BbDropdown/useDropdownContext.js +1 -1
  368. package/dist/components/BbDropdown/useDropdownGroupRegistry.d.ts +1 -1
  369. package/dist/components/BbDropdownButton/BbDropdownButton.vue.d.ts +6 -4
  370. package/dist/components/BbDropdownButton/BbDropdownButton.vue_vue_type_script_setup_true_lang.js +36 -38
  371. package/dist/components/BbDropdownButton/types.js +4 -4
  372. package/dist/components/BbDropzone/BbDropzone.vue.d.ts +57 -22
  373. package/dist/components/BbDropzone/BbDropzone.vue_vue_type_script_setup_true_lang.js +4 -4
  374. package/dist/components/BbDropzone/types.d.ts +16 -4
  375. package/dist/components/BbForm/BbForm.vue.d.ts +52 -4
  376. package/dist/components/BbForm/BbForm.vue_vue_type_script_setup_true_lang.js +1 -1
  377. package/dist/components/BbHost/BbHost.vue_vue_type_script_setup_true_lang.js +19 -23
  378. package/dist/components/BbHost/BbHostOpening.js +1 -1
  379. package/dist/components/BbHoverCard/BbHoverCard.vue.d.ts +5 -4
  380. package/dist/components/BbHoverCard/BbHoverCard.vue_vue_type_script_setup_true_lang.js +116 -116
  381. package/dist/components/BbIcon/BbIcon.vue.d.ts +3 -1
  382. package/dist/components/BbIcon/BbIcon.vue_vue_type_script_setup_true_lang.js +7 -7
  383. package/dist/components/BbIndicator/BbIndicator.vue.d.ts +3 -1
  384. package/dist/components/BbNumberInput/BbNumberInput.vue.d.ts +6 -3
  385. package/dist/components/BbNumberInput/types.d.ts +2 -0
  386. package/dist/components/BbOffCanvas/BbOffCanvas.vue.d.ts +5 -4
  387. package/dist/components/BbOffCanvas/BbOffCanvas.vue_vue_type_script_setup_true_lang.js +366 -369
  388. package/dist/components/BbOffCanvas/sheetAttrs.d.ts +9 -0
  389. package/dist/components/BbOffCanvas/sheetAttrs.js +10 -0
  390. package/dist/components/BbOffCanvas/types.d.ts +7 -7
  391. package/dist/components/BbOffCanvas/useOffCanvasStack.d.ts +2 -0
  392. package/dist/components/BbOffCanvas/useOffCanvasStack.js +7 -3
  393. package/dist/components/BbPagination/BbPagination.vue.d.ts +2 -1
  394. package/dist/components/BbPagination/BbPagination.vue_vue_type_script_setup_true_lang.js +8 -8
  395. package/dist/components/BbPagination/types.d.ts +5 -5
  396. package/dist/components/BbPopover/BbPopover.vue.d.ts +5 -4
  397. package/dist/components/BbPopover/BbPopover.vue_vue_type_script_setup_true_lang.js +92 -91
  398. package/dist/components/BbProgress/BbProgress.vue.d.ts +6 -1
  399. package/dist/components/BbRadio/BbRadio.vue.d.ts +4 -2
  400. package/dist/components/BbRadioGroup/BbRadioGroup.vue.d.ts +281 -1
  401. package/dist/components/BbRating/BbRating.vue.d.ts +4 -2
  402. package/dist/components/BbRating/BbRating.vue_vue_type_script_setup_true_lang.js +7 -7
  403. package/dist/components/BbSelect/BbSelect.vue.d.ts +575 -4
  404. package/dist/components/BbSelect/BbSelect.vue_vue_type_script_setup_true_lang.js +7 -7
  405. package/dist/components/BbSelect/types.d.ts +12 -2
  406. package/dist/components/BbSelectPopover/BbSelectPopover.vue.d.ts +105 -3
  407. package/dist/components/BbSelectPopover/BbSelectPopover.vue_vue_type_script_setup_true_lang.js +688 -685
  408. package/dist/components/BbSelectPopover/types.d.ts +9 -1
  409. package/dist/components/BbSlider/BbSlider.vue.d.ts +135 -33
  410. package/dist/components/BbSlider/BbSlider.vue_vue_type_script_setup_true_lang.js +5 -5
  411. package/dist/components/BbSlider/types.d.ts +19 -4
  412. package/dist/components/BbSmoothHeight/BbSmoothHeight.vue.d.ts +3 -1
  413. package/dist/components/BbSpinner/BbSpinner.vue.d.ts +3 -1
  414. package/dist/components/BbSwitch/BbSwitch.vue.d.ts +4 -2
  415. package/dist/components/BbSwitchGroup/BbSwitchGroup.vue.d.ts +131 -1
  416. package/dist/components/BbTable/BbTable.vue.d.ts +5 -2
  417. package/dist/components/BbTable/BbTable.vue_vue_type_script_setup_true_lang.js +593 -578
  418. package/dist/components/BbTable/types.d.ts +14 -1
  419. package/dist/components/BbTable/utils.d.ts +2 -1
  420. package/dist/components/BbTable/utils.js +37 -38
  421. package/dist/components/BbTabs/BbTabs.vue.d.ts +96 -2
  422. package/dist/components/BbTabs/BbTabs.vue_vue_type_script_setup_true_lang.js +8 -6
  423. package/dist/components/BbTabs/BbTabsList.vue.d.ts +11 -1
  424. package/dist/components/BbTabs/BbTabsList.vue_vue_type_script_setup_true_lang.js +102 -92
  425. package/dist/components/BbTabs/BbTabsPanels.vue.d.ts +9 -1
  426. package/dist/components/BbTabs/BbTabsPanels.vue_vue_type_script_setup_true_lang.js +20 -17
  427. package/dist/components/BbTabs/BbTabsRoot.vue_vue_type_script_setup_true_lang.js +1 -1
  428. package/dist/components/BbTabs/types.d.ts +34 -23
  429. package/dist/components/BbTag/BbTag.vue.d.ts +5 -2
  430. package/dist/components/BbTag/types.d.ts +2 -0
  431. package/dist/components/BbTextInput/BbTextInput.vue.d.ts +195 -2
  432. package/dist/components/BbTextInput/BbTextInput.vue_vue_type_script_setup_true_lang.js +5 -5
  433. package/dist/components/BbTextInput/types.d.ts +2 -0
  434. package/dist/components/BbTextarea/BbTextarea.vue.d.ts +193 -2
  435. package/dist/components/BbTextarea/types.d.ts +2 -0
  436. package/dist/components/BbTimePicker/BbTimePicker.vue.d.ts +78 -38
  437. package/dist/components/BbTimePicker/BbTimePicker.vue_vue_type_script_setup_true_lang.js +138 -137
  438. package/dist/components/BbTimePicker/types.d.ts +18 -4
  439. package/dist/components/BbTimePickerInput/BbTimePickerInput.vue.d.ts +272 -33
  440. package/dist/components/BbTimePickerInput/BbTimePickerInput.vue_vue_type_script_setup_true_lang.js +16 -16
  441. package/dist/components/BbTimePickerInput/types.d.ts +20 -5
  442. package/dist/components/BbToast/BbToastMessage.vue_vue_type_script_setup_true_lang.js +6 -6
  443. package/dist/components/BbToast/BbToastRegion.vue_vue_type_script_setup_true_lang.js +20 -20
  444. package/dist/components/BbTooltip/BbTooltip.vue.d.ts +3 -2
  445. package/dist/components/BbTooltip/BbTooltip.vue_vue_type_script_setup_true_lang.js +109 -109
  446. package/dist/components/BbTree/BbTree.vue.d.ts +1 -1
  447. package/dist/components/ClearableButton/ClearableButton.vue.d.ts +3 -1
  448. package/dist/components/CloseIcon/CloseButton.vue.d.ts +3 -1
  449. package/dist/components/CloseIcon/CloseButton.vue.js +1 -1
  450. package/dist/components/CommonField/CommonField.vue.d.ts +3 -1
  451. package/dist/components/CommonFieldInput/CommonFieldInput.vue.d.ts +5 -3
  452. package/dist/components/CommonPopover/CommonPopover.vue.d.ts +5 -4
  453. package/dist/components/CommonPopover/CommonPopover.vue_vue_type_script_setup_true_lang.js +55 -55
  454. package/dist/components/ErrorIcon/ErrorIcon.vue.d.ts +3 -1
  455. package/dist/components/FlatListBox/FlatListBox.vue_vue_type_script_setup_true_lang.js +124 -124
  456. package/dist/components/GroupedListBox/GroupedListBox.vue_vue_type_script_setup_true_lang.js +71 -71
  457. package/dist/components/ListBox/ListBox.vue.d.ts +1 -1
  458. package/dist/components/OptionsContainer/OptionsContainer.vue.d.ts +1 -1
  459. package/dist/components/OptionsContainer/OptionsContainer.vue_vue_type_script_setup_true_lang.js +4 -4
  460. package/dist/components/Transitions/Slide.vue.d.ts +1 -1
  461. package/dist/components/WarningIcon/WarningIcon.vue.d.ts +3 -1
  462. package/dist/composables/autoHost.d.ts +22 -0
  463. package/dist/composables/autoHost.js +20 -0
  464. package/dist/composables/hostOpenings.d.ts +3 -3
  465. package/dist/composables/hostOpenings.js +1 -1
  466. package/dist/composables/hostRegistry.d.ts +10 -2
  467. package/dist/composables/hostRegistry.js +5 -3
  468. package/dist/composables/overlayRegistry.d.ts +1 -1
  469. package/dist/composables/overlayRegistry.js +2 -2
  470. package/dist/composables/{useBbDialogContext.d.ts → useBbDialog.d.ts} +9 -9
  471. package/dist/composables/{useBbDialogContext.js → useBbDialog.js} +4 -4
  472. package/dist/composables/{useBbDropdownContext.d.ts → useBbDropdown.d.ts} +14 -14
  473. package/dist/composables/{useBbDropdownContext.js → useBbDropdown.js} +2 -2
  474. package/dist/composables/{useBbFormContext.d.ts → useBbForm.d.ts} +8 -8
  475. package/dist/composables/{useBbFormContext.js → useBbForm.js} +3 -3
  476. package/dist/composables/useBbOffCanvas.d.ts +23 -0
  477. package/dist/composables/{useBbOffCanvasContext.js → useBbOffCanvas.js} +3 -3
  478. package/dist/composables/{useBbTableContext.d.ts → useBbTable.d.ts} +29 -29
  479. package/dist/composables/{useBbTableContext.js → useBbTable.js} +2 -2
  480. package/dist/composables/{useBbTabsContext.d.ts → useBbTabs.d.ts} +19 -3
  481. package/dist/composables/useBbTabs.js +266 -0
  482. package/dist/composables/useConfirm.d.ts +6 -7
  483. package/dist/composables/useConfirm.js +1 -1
  484. package/dist/composables/useOnDemandOpener.d.ts +4 -4
  485. package/dist/composables/useOnDemandOpener.js +1 -1
  486. package/dist/composables/useToast.d.ts +4 -5
  487. package/dist/composables/useToast.js +1 -1
  488. package/dist/directives/bbDialog.d.ts +1 -1
  489. package/dist/directives/bbDropdown.js +3 -3
  490. package/dist/directives/bbOffCanvas.d.ts +1 -1
  491. package/dist/directives/overlayTrigger.js +18 -18
  492. package/dist/index.d.ts +15 -15
  493. package/dist/index.js +55 -55
  494. package/dist/llms-full.txt +4355 -2761
  495. package/dist/llms-medium.txt +127 -93
  496. package/dist/llms.txt +12 -12
  497. package/dist/nuxt-auto-imports.js +6 -6
  498. package/dist/nuxt.js +1 -1
  499. package/dist/plugin.js +30 -28
  500. package/dist/runtime/nuxt-plugin.js +30 -28
  501. package/dist/styles.css +2 -2
  502. package/dist/types/ShapeErased.d.ts +15 -0
  503. package/dist/types/fallthrough.d.ts +134 -0
  504. package/dist/utilities/functions/normalizeDateBound.d.ts +7 -5
  505. package/dist/utilities/functions/normalizeDateBound.js +9 -9
  506. package/dist/utils/versionCheck.js +1 -1
  507. package/llms.txt +12 -12
  508. package/package.json +1 -1
  509. package/scripts/lib/adoption-checklist.json +2 -1
  510. package/scripts/lib/css-class-surface.mjs +39 -3
  511. package/scripts/lib/eslint-disable.mjs +9 -1
  512. package/scripts/lib/eslint-plugin.d.ts +7 -1
  513. package/scripts/lib/eslint-plugin.mjs +280 -3
  514. package/scripts/lib/form-v-model.mjs +2 -2
  515. package/scripts/lib/helper-canon.mjs +34 -2
  516. package/scripts/lib/helpers-add.mjs +80 -13
  517. package/scripts/lib/hidden-label-placeholder.mjs +138 -0
  518. package/scripts/lib/html-attributes.mjs +82 -0
  519. package/scripts/lib/idiom-scan.mjs +175 -2
  520. package/scripts/lib/portal-names.mjs +3 -3
  521. package/scripts/lib/prefer-v-bb-dialog.mjs +1 -1
  522. package/scripts/lib/tab-links.mjs +209 -0
  523. package/scripts/lib/token-color-mix.mjs +114 -0
  524. package/scripts/lib/toolchain-check.mjs +34 -3
  525. package/scripts/lib/unstyled-variants.mjs +57 -0
  526. package/scripts/lib/validate-bb-markup.mjs +72 -1
  527. package/dist/composables/useBbOffCanvasContext.d.ts +0 -23
  528. package/dist/composables/useBbTabsContext.js +0 -252
@@ -27,7 +27,6 @@ Sibling recipes: [Nuxt](../nuxt/approvals-inbox.md) ·
27
27
  those files before anything below, and do not hand-roll replacements —
28
28
  the peek stack, the close semantics and the sidebar's out-of-flow
29
29
  behaviour are all load-bearing here.
30
- - `<BbHost />` mounted once in the app root (`App.vue`) — never in a page.
31
30
  - Each toast and alert variant's icon set once in the build config; the
32
31
  code below passes no `icon` for them:
33
32
  `toastVariants: { success: { icon: 'lucide:circle-check' }, destructive: { icon: 'lucide:circle-x' } }`
@@ -47,7 +46,7 @@ Sibling recipes: [Nuxt](../nuxt/approvals-inbox.md) ·
47
46
 
48
47
  - **Highlight drives the peek, not a click handler.** The table gets
49
48
  `keyboard-navigation`; `ctx.table.highlighted` (the coopted table
50
- context, seeded with `highlighted: null` because highlight is opt-in) is
49
+ handle, seeded with `highlighted: null` because highlight is opt-in) is
51
50
  watched in `context.ts`, and every highlight change replaces the
52
51
  sidebar's stack with that expense — a click, or Enter on a focused row,
53
52
  opens it with zero markup in `Index.vue`. Arrows only move focus (the
@@ -59,7 +58,7 @@ Sibling recipes: [Nuxt](../nuxt/approvals-inbox.md) ·
59
58
  `{ all, unselected, filters }` instead of the ids, and `selectedCount`
60
59
  (the total minus the unticked rows) is what the bar and the dialog show.
61
60
  - **One coopting page context.** `provideApprovalsInbox()` joins the
62
- page-shell stack and the table context once, owns filters/tab and when
61
+ page-shell stack and the table handle once, owns filters/tab and when
63
62
  the dialogs open, and exposes complete actions. Every leaf calls `useApprovalsInbox()` and
64
63
  nothing else.
65
64
  - **Three dispatch surfaces, one set of actions.** Approve / reject /
@@ -79,9 +78,10 @@ Sibling recipes: [Nuxt](../nuxt/approvals-inbox.md) ·
79
78
  - **Clicking a submitter's name always stacks**, from a row or from inside
80
79
  the expense peek — the back arrow appears once the stack is two deep,
81
80
  exactly the "peek vs stack" grammar of the flagship.
82
- - **Tabs are URL filters with live counts** (`Needs approval` / `Approved`
83
- / `Rejected` / `All`), same shape as every other workspace in the
84
- folder.
81
+ - **The status strip is a URL filter with live counts**, a `BbRadioGroup` with
82
+ the tabs look (`variant="pill"`): one value over one table, so radios, not a
83
+ tablist (`Needs approval` / `Approved` / `Rejected` / `All`), same shape as
84
+ every other workspace in the folder.
85
85
  - **Buttons are `md` by default**; `sm`/`xs` apply only where the doctrine
86
86
  allows it — table rows, the peek footers, the bulk bar, the shortcut
87
87
  bar.
@@ -124,13 +124,13 @@ Chrome assumed from the guides: [App Layout](../../guides/app-layout.md)
124
124
  | 3 | Filter by category | filter rail pill | `BbSelectPopover` multiple |
125
125
  | 4 | Quick filter: amount over | filter rail pill | `BbSelectPopover` single, preset thresholds |
126
126
  | 5 | Clear filters | rail right (only when active) | context `clearFilters()` |
127
- | 6 | Switch tab | href tabs with counts | URL + fetch dependency |
127
+ | 6 | Switch tab | URL status strip with counts | URL + fetch dependency |
128
128
  | 7 | Arrow through rows | `keyboard-navigation` roving tabindex | table's own Arrow/Home/End |
129
129
  | 8 | Preview an expense | highlight a row (click, Enter/Space, arrow-then-Enter) | `ctx.table.highlighted` watcher → `peekExpense` (replace) |
130
130
  | 9 | Approve (one click) | row icon button, peek footer, key `A` | `approve(expense)` — API + refresh + toast |
131
131
  | 10 | Reject with reason | row icon button, peek footer, key `R` | `v-bb-dialog` / `openReject` → `RejectDialog` (required `BbTextarea`) |
132
132
  | 11 | Snooze | row icon button, peek footer, key `S` | `v-bb-dialog` / `openSnooze` → `SnoozeDialog` (`BbDatePickerInput`) |
133
- | 12 | Select rows / select all | table checkboxes | table context |
133
+ | 12 | Select rows / select all | table checkboxes | table handle |
134
134
  | 13 | Bulk approve | floating bottom panel | `bulkApprove()`: the ids, or `{ all, unselected, filters }` |
135
135
  | 14 | Bulk reject with reason | floating bottom panel | `v-bb-dialog` → `BulkRejectDialog`, destructive |
136
136
  | 15 | Stack a submitter | submitter cell / peek property | `stackSubmitter(id)` → shell stack, back arrow |
@@ -161,13 +161,14 @@ import {
161
161
  type InjectionKey,
162
162
  type Ref,
163
163
  } from 'vue';
164
+ import { useRoute, useRouter } from 'vue-router';
164
165
  import { useMagicKeys, whenever } from '@vueuse/core';
165
166
  import {
166
- useBbDialogContext,
167
- useBbTableContext,
167
+ useBbDialog,
168
+ useBbTable,
168
169
  useConfirm,
169
170
  useToast,
170
- type BbTableContext,
171
+ type BbTableHandle,
171
172
  type BbTableItemsContext,
172
173
  } from 'bitboss-ui';
173
174
  import {
@@ -214,7 +215,7 @@ export const CATEGORY_OPTIONS = (
214
215
  ).map((value) => ({ value, text: CATEGORY_LABEL[value] }));
215
216
 
216
217
  export interface ApprovalsFilters {
217
- search: string;
218
+ search: string | null;
218
219
  submitterId: number | null;
219
220
  categories: ExpenseCategory[];
220
221
  /** Preset threshold from the quick filter (`50`, `100`, `250`…), or `null`. */
@@ -222,9 +223,9 @@ export interface ApprovalsFilters {
222
223
  }
223
224
 
224
225
  export interface ApprovalsInboxContext {
225
- // -- Coopted contexts ------------------------------------------------------
226
+ // -- Coopted contexts and handles ------------------------------------------
226
227
  shell: PageShellContext<PeekItem>;
227
- table: BbTableContext;
228
+ table: BbTableHandle;
228
229
  // -- Page-owned state --------------------------------------------------------
229
230
  filters: ApprovalsFilters;
230
231
  hasActiveFilters: ComputedRef<boolean>;
@@ -270,13 +271,27 @@ const isInteractiveElementFocused = (): boolean => {
270
271
 
271
272
  export function provideApprovalsInbox(): ApprovalsInboxContext {
272
273
  const { toast } = useToast();
274
+ // A write that fails tells the user instead of escaping as an
275
+ // `Uncaught (in promise)`: the action resolves, the page stays as it was.
276
+ const failSoft =
277
+ <A extends unknown[]>(action: (...args: A) => Promise<unknown>) =>
278
+ async (...args: A) => {
279
+ try {
280
+ await action(...args);
281
+ } catch {
282
+ toast({
283
+ title: 'That did not go through. Try again.',
284
+ variant: 'destructive',
285
+ });
286
+ }
287
+ };
273
288
  const { confirm } = useConfirm();
274
289
 
275
- // -- Coopt the specific contexts: once, here, for the whole page. ----------
290
+ // -- Coopt the shell and the table handle: once, for the whole page. -------
276
291
  const shell = usePageShellContext<PeekItem>();
277
292
  // Highlight is opt-in: seeding it with `null` switches it on. Unseeded, a
278
293
  // row click highlights nothing and the peek never opens.
279
- const table = useBbTableContext('approvals-table', {
294
+ const table = useBbTable('approvals-table', {
280
295
  perPage: 25,
281
296
  highlighted: null,
282
297
  });
@@ -290,12 +305,21 @@ export function provideApprovalsInbox(): ApprovalsInboxContext {
290
305
  });
291
306
  const hasActiveFilters = computed(
292
307
  () =>
293
- filters.search !== '' ||
308
+ !!filters.search ||
294
309
  filters.submitterId !== null ||
295
310
  filters.categories.length > 0 ||
296
311
  filters.amountOver !== null
297
312
  );
298
- const tab = ref<ApprovalsTab>('needsApproval');
313
+ // The tab lives in `?tab=`: seeded from it, mirrored back with `replace`
314
+ // (a filter pick is not a history entry), the other query keys kept.
315
+ const route = useRoute();
316
+ const router = useRouter();
317
+ const tab = ref<ApprovalsTab>(
318
+ (route.query.tab as ApprovalsTab | undefined) ?? 'needsApproval'
319
+ );
320
+ watch(tab, (next) => {
321
+ void router.replace({ query: { ...route.query, tab: next } });
322
+ });
299
323
  const tabCounts = ref<Record<ApprovalsTab, number>>({
300
324
  needsApproval: 0,
301
325
  approved: 0,
@@ -306,9 +330,9 @@ export function provideApprovalsInbox(): ApprovalsInboxContext {
306
330
  // The page owns WHEN its dialogs open (row actions, the peek, the
307
331
  // shortcuts) through these handles; each dialog is opened by id and reads
308
332
  // its subject as `data`, so no open-state refs live here.
309
- const rejectDialog = useBbDialogContext<Expense>('reject-expense');
310
- const snoozeDialog = useBbDialogContext<Expense>('snooze-expense');
311
- const bulkRejectDialog = useBbDialogContext('bulk-reject');
333
+ const rejectDialog = useBbDialog<Expense>('reject-expense');
334
+ const snoozeDialog = useBbDialog<Expense>('snooze-expense');
335
+ const bulkRejectDialog = useBbDialog('bulk-reject');
312
336
 
313
337
  const clearFilters = () => {
314
338
  filters.search = '';
@@ -319,7 +343,7 @@ export function provideApprovalsInbox(): ApprovalsInboxContext {
319
343
 
320
344
  // -- Data -----------------------------------------------------------------------
321
345
  // Cached so the keyboard shortcuts and the peek watcher can resolve a full
322
- // expense from the id the table context reports.
346
+ // expense from the id the table handle reports.
323
347
  const lastItems = ref<Expense[]>([]);
324
348
  const fetchExpenses = async ({
325
349
  signal,
@@ -400,21 +424,21 @@ export function provideApprovalsInbox(): ApprovalsInboxContext {
400
424
  table.all.value = false;
401
425
  };
402
426
 
403
- const approve = async (expense: Expense) => {
427
+ const approve = failSoft(async (expense: Expense) => {
404
428
  await api.expenses.approve(expense.id);
405
429
  refresh();
406
430
  toast({
407
431
  title: `Approved ${expense.merchant} — $${expense.amount.toFixed(2)}.`,
408
432
  variant: 'success',
409
433
  });
410
- };
434
+ });
411
435
 
412
436
  // The R / S shortcuts open these dialogs from code; the row and peek
413
437
  // buttons carry `v-bb-dialog` themselves.
414
438
  const openReject = (expense: Expense) => {
415
439
  rejectDialog.show(expense);
416
440
  };
417
- const reject = async (expense: Expense, reason: string) => {
441
+ const reject = failSoft(async (expense: Expense, reason: string) => {
418
442
  await api.expenses.reject(expense.id, reason);
419
443
  rejectDialog.hide();
420
444
  refresh();
@@ -422,12 +446,12 @@ export function provideApprovalsInbox(): ApprovalsInboxContext {
422
446
  title: `Rejected ${expense.merchant}.`,
423
447
  variant: 'success',
424
448
  });
425
- };
449
+ });
426
450
 
427
451
  const openSnooze = (expense: Expense) => {
428
452
  snoozeDialog.show(expense);
429
453
  };
430
- const snooze = async (expense: Expense, until: string) => {
454
+ const snooze = failSoft(async (expense: Expense, until: string) => {
431
455
  await api.expenses.snooze(expense.id, until);
432
456
  snoozeDialog.hide();
433
457
  refresh();
@@ -435,9 +459,9 @@ export function provideApprovalsInbox(): ApprovalsInboxContext {
435
459
  title: `${expense.merchant} snoozed.`,
436
460
  variant: 'success',
437
461
  });
438
- };
462
+ });
439
463
 
440
- const bulkApprove = async () => {
464
+ const bulkApprove = failSoft(async () => {
441
465
  const count = selectedCount.value;
442
466
  await api.expenses.approveMany(bulkSelection());
443
467
  clearSelection();
@@ -446,9 +470,9 @@ export function provideApprovalsInbox(): ApprovalsInboxContext {
446
470
  title: `${count} expenses approved.`,
447
471
  variant: 'success',
448
472
  });
449
- };
473
+ });
450
474
 
451
- const bulkReject = async (reason: string) => {
475
+ const bulkReject = failSoft(async (reason: string) => {
452
476
  const count = selectedCount.value;
453
477
  const ok = await confirm({
454
478
  variant: 'destructive',
@@ -466,7 +490,7 @@ export function provideApprovalsInbox(): ApprovalsInboxContext {
466
490
  title: `${count} expenses rejected.`,
467
491
  variant: 'success',
468
492
  });
469
- };
493
+ });
470
494
 
471
495
  // -- Keyboard-shortcut dispatch: same actions, resolved against the row
472
496
  // under the roving tabindex. Guarded exactly like `useDeleteCmd`.
@@ -566,32 +590,34 @@ export function useApprovalsInbox(): ApprovalsInboxContext {
566
590
  <FilterRail />
567
591
 
568
592
  <div class="flex items-center justify-between gap-2">
569
- <!-- Tabs as URL filters: counts come from the server on every fetch. -->
570
- <BbTabs
593
+ <!-- The status filter: one value over one table, so a radio group
594
+ with the tabs look (a tablist would promise panels). The context
595
+ keeps it in `?tab=`; the counts come from the server on every
596
+ fetch. -->
597
+ <BbRadioGroup
571
598
  v-model="ctx.tab.value"
572
599
  compact
600
+ hide-legend
573
601
  :items="[
574
602
  {
575
603
  value: 'needsApproval',
576
604
  label: `Needs approval · ${ctx.tabCounts.value.needsApproval}`,
577
- href: '?tab=needsApproval',
578
605
  },
579
606
  {
580
607
  value: 'approved',
581
608
  label: `Approved · ${ctx.tabCounts.value.approved}`,
582
- href: '?tab=approved',
583
609
  },
584
610
  {
585
611
  value: 'rejected',
586
612
  label: `Rejected · ${ctx.tabCounts.value.rejected}`,
587
- href: '?tab=rejected',
588
613
  },
589
614
  {
590
615
  value: 'all',
591
616
  label: `All · ${ctx.tabCounts.value.all}`,
592
- href: '?tab=all',
593
617
  },
594
618
  ]"
619
+ legend="Status"
620
+ variant="pill"
595
621
  />
596
622
  <ShortcutsHint />
597
623
  </div>
@@ -697,8 +723,8 @@ import {
697
723
  BbBreadcrumbs,
698
724
  BbButton,
699
725
  BbPagination,
726
+ BbRadioGroup,
700
727
  BbTable,
701
- BbTabs,
702
728
  BbTextInput,
703
729
  } from 'bitboss-ui';
704
730
  import PageShell from '@/components/layout/PageShell.vue';
@@ -1094,7 +1120,7 @@ import {
1094
1120
  BbDialog,
1095
1121
  BbForm,
1096
1122
  BbTextarea,
1097
- useBbDialogContext,
1123
+ useBbDialog,
1098
1124
  } from 'bitboss-ui';
1099
1125
  import { useApprovalsInbox } from './context';
1100
1126
  import type { Expense } from '@/types';
@@ -1103,7 +1129,7 @@ const ctx = useApprovalsInbox();
1103
1129
 
1104
1130
  // The expense the opener handed over (the context closes the dialog after
1105
1131
  // the request succeeds).
1106
- const { data: expense } = useBbDialogContext<Expense>('reject-expense');
1132
+ const { data: expense } = useBbDialog<Expense>('reject-expense');
1107
1133
 
1108
1134
  const reason = ref<string | null>('');
1109
1135
  const submit = () =>
@@ -1211,14 +1237,14 @@ import {
1211
1237
  BbDatePickerInput,
1212
1238
  BbDialog,
1213
1239
  BbForm,
1214
- useBbDialogContext,
1240
+ useBbDialog,
1215
1241
  } from 'bitboss-ui';
1216
1242
  import { useApprovalsInbox } from './context';
1217
1243
  import type { Expense } from '@/types';
1218
1244
 
1219
1245
  const ctx = useApprovalsInbox();
1220
1246
 
1221
- const { data: expense } = useBbDialogContext<Expense>('snooze-expense');
1247
+ const { data: expense } = useBbDialog<Expense>('snooze-expense');
1222
1248
 
1223
1249
  // Tomorrow as a LOCAL `YYYY-MM-DD` (`toISOString()` is the UTC date, a day
1224
1250
  // early east of Greenwich just after midnight).
@@ -1229,9 +1255,11 @@ const tomorrow = [
1229
1255
  String(next.getMonth() + 1).padStart(2, '0'),
1230
1256
  String(next.getDate()).padStart(2, '0'),
1231
1257
  ].join('-');
1232
- const until = ref(tomorrow);
1258
+ const until = ref<string | null>(tomorrow);
1233
1259
  const submit = () =>
1234
- expense.value ? ctx.snooze(expense.value, until.value) : undefined;
1260
+ expense.value && until.value
1261
+ ? ctx.snooze(expense.value, until.value)
1262
+ : undefined;
1235
1263
  </script>
1236
1264
  ```
1237
1265
 
@@ -1587,7 +1615,7 @@ const currency = new Intl.NumberFormat('en-US', {
1587
1615
  `v-bb-dialog="{ id: 'reject-expense', data: expense }"` (the selection
1588
1616
  bar's Reject `v-bb-dialog="'bulk-reject'"`), and the `R` shortcut, which
1589
1617
  has no button, calls the context's `openReject(expense)` →
1590
- `useBbDialogContext<Expense>('reject-expense').show(expense)`. The dialog
1618
+ `useBbDialog<Expense>('reject-expense').show(expense)`. The dialog
1591
1619
  reads that expense as `data`, and the context closes it with `hide()`
1592
1620
  once the request succeeds — no open-state refs, no `v-model`, no event
1593
1621
  for a parent to turn into `show()`. Each form is a `BbForm` whose
@@ -70,7 +70,7 @@ label state) · [Page Shell](../../guides/page-shell.md) ·
70
70
  `v-model` autosave is one request per keystroke. Pickers commit on pick —
71
71
  the click already _is_ the commit.
72
72
  - **One coopting page context.** `provideBacklogWorkspace()` joins the
73
- page-shell stack and the table context once, owns filters/tab/overlay, and
73
+ page-shell stack and the table handle once, owns filters/tab/overlay, and
74
74
  exposes complete actions. Eleven components share everything through one
75
75
  `useBacklogWorkspace()` call — zero prop drilling.
76
76
  - **Options resolve once, at page level.** Status and priority are static
@@ -116,29 +116,29 @@ needs a modal to edit.
116
116
 
117
117
  ## Action inventory
118
118
 
119
- | # | Action | Trigger | Mechanism |
120
- | --- | ------------------------ | ---------------------------------- | ------------------------------------------------------ |
121
- | 1 | New issue | topbar, the page's one `primary` | navigation (`/issues/new`) |
122
- | 2 | Page search | topbar right | `filters.search` → fetch dependency |
123
- | 3 | Switch sprint tab | href tabs with live counts | URL + fetch dependency |
124
- | 4 | Filter by status | rail pill | `BbSelectPopover` multiple over the static catalog |
125
- | 5 | Filter by priority | rail pill | `BbSelectPopover` multiple over the static catalog |
126
- | 6 | Filter by assignee | rail pill | the shared people provider, single select |
127
- | 7 | Clear filters | rail right (only when active) | context `clearFilters()` |
128
- | 8 | Rename issue | title cell (grid) | commit-on-blur `@change` → `persistField('title')` |
129
- | 9 | Re-estimate | estimate cell (grid) | commit-on-change number → `persistField('estimate')` |
130
- | 10 | Change status | status badge (grid **and** peek) | pick = commit; spinner in the chevron (autosave cells) |
131
- | 11 | Change priority | priority badge (grid **and** peek) | same grammar, its own leaf |
132
- | 12 | Reassign | assignee badge (grid **and** peek) | async people search; one shared provider |
133
- | 13 | Peek issue | issue ref cell | `peekIssue(id)` → shell stack |
134
- | 14 | Duplicate | row `…` dropdown | context action + toast |
135
- | 15 | Move to next sprint | row `…` **and** bulk bar | `moveToNextSprint` / `bulkMoveToNextSprint` |
136
- | 16 | Delete | row `…`, peek footer | destructive behind `useConfirm` |
137
- | 17 | Bulk set status | bottom panel picker | `bulkStatus` on `table.selected` |
138
- | 18 | Bulk assign | bottom panel picker | `bulkAssign` on `table.selected` |
139
- | 19 | Select rows / select all | table checkboxes | table context |
140
- | 20 | Open full issue | peek footer | navigation (`/issues/:id`) |
141
- | 21 | Close peek | shell chrome | shell stack close |
119
+ | # | Action | Trigger | Mechanism |
120
+ | --- | ------------------------ | ----------------------------------- | ------------------------------------------------------ |
121
+ | 1 | New issue | topbar, the page's one `primary` | navigation (`/issues/new`) |
122
+ | 2 | Page search | topbar right | `filters.search` → fetch dependency |
123
+ | 3 | Switch sprint tab | a URL status strip with live counts | URL + fetch dependency |
124
+ | 4 | Filter by status | rail pill | `BbSelectPopover` multiple over the static catalog |
125
+ | 5 | Filter by priority | rail pill | `BbSelectPopover` multiple over the static catalog |
126
+ | 6 | Filter by assignee | rail pill | the shared people provider, single select |
127
+ | 7 | Clear filters | rail right (only when active) | context `clearFilters()` |
128
+ | 8 | Rename issue | title cell (grid) | commit-on-blur `@change` → `persistField('title')` |
129
+ | 9 | Re-estimate | estimate cell (grid) | commit-on-change number → `persistField('estimate')` |
130
+ | 10 | Change status | status badge (grid **and** peek) | pick = commit; spinner in the chevron (autosave cells) |
131
+ | 11 | Change priority | priority badge (grid **and** peek) | same grammar, its own leaf |
132
+ | 12 | Reassign | assignee badge (grid **and** peek) | async people search; one shared provider |
133
+ | 13 | Peek issue | issue ref cell | `peekIssue(id)` → shell stack |
134
+ | 14 | Duplicate | row `…` dropdown | context action + toast |
135
+ | 15 | Move to next sprint | row `…` **and** bulk bar | `moveToNextSprint` / `bulkMoveToNextSprint` |
136
+ | 16 | Delete | row `…`, peek footer | destructive behind `useConfirm` |
137
+ | 17 | Bulk set status | bottom panel picker | `bulkStatus` on `table.selected` |
138
+ | 18 | Bulk assign | bottom panel picker | `bulkAssign` on `table.selected` |
139
+ | 19 | Select rows / select all | table checkboxes | table handle |
140
+ | 20 | Open full issue | peek footer | navigation (`/issues/:id`) |
141
+ | 21 | Close peek | shell chrome | shell stack close |
142
142
 
143
143
  Rows 8–12 are the recipe's reason to exist: five editable fields of three
144
144
  different control kinds, each persisting itself, two of them able to be in
@@ -219,17 +219,19 @@ import {
219
219
  provide,
220
220
  reactive,
221
221
  ref,
222
+ watch,
222
223
  type ComputedRef,
223
224
  type InjectionKey,
224
225
  type Ref,
225
226
  } from 'vue';
227
+ import { useRoute, useRouter } from 'vue-router';
226
228
  import {
227
- useBbTableContext,
229
+ useBbTable,
228
230
  useConfirm,
229
231
  useToast,
230
232
  type BadgeVariantType,
231
233
  type BbSelectPopoverItemsContext,
232
- type BbTableContext,
234
+ type BbTableHandle,
233
235
  type BbTableItemsContext,
234
236
  } from 'bitboss-ui';
235
237
  import {
@@ -267,7 +269,7 @@ export type IssuePatch = Partial<
267
269
  export type EditableKey = keyof IssuePatch;
268
270
 
269
271
  export interface BacklogFilters {
270
- search: string;
272
+ search: string | null;
271
273
  status: IssueStatus[];
272
274
  priority: IssuePriority[];
273
275
  /** The whole member, not an id — the pill labels itself with zero fetches. */
@@ -336,9 +338,9 @@ export const searchMembers = async ({
336
338
  };
337
339
 
338
340
  export interface BacklogWorkspaceContext {
339
- // -- Coopted contexts ------------------------------------------------------
341
+ // -- Coopted contexts and handles ------------------------------------------
340
342
  shell: PageShellContext<PeekItem>;
341
- table: BbTableContext;
343
+ table: BbTableHandle;
342
344
  // -- Page-owned state ------------------------------------------------------
343
345
  filters: BacklogFilters;
344
346
  hasActiveFilters: ComputedRef<boolean>;
@@ -387,11 +389,25 @@ const key: InjectionKey<BacklogWorkspaceContext> = Symbol('backlog-workspace');
387
389
 
388
390
  export function provideBacklogWorkspace(): BacklogWorkspaceContext {
389
391
  const { toast } = useToast();
392
+ // A write that fails tells the user instead of escaping as an
393
+ // `Uncaught (in promise)`: the action resolves, the page stays as it was.
394
+ const failSoft =
395
+ <A extends unknown[]>(action: (...args: A) => Promise<unknown>) =>
396
+ async (...args: A) => {
397
+ try {
398
+ await action(...args);
399
+ } catch {
400
+ toast({
401
+ title: 'That did not go through. Try again.',
402
+ variant: 'destructive',
403
+ });
404
+ }
405
+ };
390
406
  const { confirm } = useConfirm();
391
407
 
392
- // -- Coopt the specific contexts: once, here, for the whole page. ----------
408
+ // -- Coopt the shell and the table handle: once, for the whole page. -------
393
409
  const shell = usePageShellContext<PeekItem>();
394
- const table = useBbTableContext('backlog-table', { perPage: 25 });
410
+ const table = useBbTable('backlog-table', { perPage: 25 });
395
411
 
396
412
  // -- Page state -------------------------------------------------------------
397
413
  const filters = reactive<BacklogFilters>({
@@ -402,12 +418,21 @@ export function provideBacklogWorkspace(): BacklogWorkspaceContext {
402
418
  });
403
419
  const hasActiveFilters = computed(
404
420
  () =>
405
- filters.search !== '' ||
421
+ !!filters.search ||
406
422
  filters.status.length > 0 ||
407
423
  filters.priority.length > 0 ||
408
424
  filters.assignee !== null
409
425
  );
410
- const tab = ref<SprintTab>('current');
426
+ // The tab lives in `?tab=`: seeded from it, mirrored back with `replace`
427
+ // (a filter pick is not a history entry), the other query keys kept.
428
+ const route = useRoute();
429
+ const router = useRouter();
430
+ const tab = ref<SprintTab>(
431
+ (route.query.tab as SprintTab | undefined) ?? 'current'
432
+ );
433
+ watch(tab, (next) => {
434
+ void router.replace({ query: { ...route.query, tab: next } });
435
+ });
411
436
  const tabCounts = ref<Record<SprintTab, number>>({
412
437
  backlog: 0,
413
438
  current: 0,
@@ -517,7 +542,7 @@ export function provideBacklogWorkspace(): BacklogWorkspaceContext {
517
542
 
518
543
  // -- Data ---------------------------------------------------------------------
519
544
  // The one place the list is fetched. Writes the paging totals into the
520
- // table context, keeps the tab counts live, and — the autosave subtlety —
545
+ // table handle, keeps the tab counts live, and — the autosave subtlety —
521
546
  // retires the overlay.
522
547
  // The filters as the api takes them. The assignee pill holds the WHOLE
523
548
  // member; the wire takes its id, and `'none'` is "unassigned" (`id: null`),
@@ -584,25 +609,25 @@ export function provideBacklogWorkspace(): BacklogWorkspaceContext {
584
609
  refreshKey.value++;
585
610
  };
586
611
 
587
- const duplicateIssue = async (issue: Issue) => {
612
+ const duplicateIssue = failSoft(async (issue: Issue) => {
588
613
  const copy = await api.issues.duplicate(issue.id);
589
614
  refresh();
590
615
  toast({
591
616
  title: `Duplicated as ${copy.ref}.`,
592
617
  variant: 'success',
593
618
  });
594
- };
619
+ });
595
620
 
596
- const moveToNextSprint = async (issue: Issue) => {
621
+ const moveToNextSprint = failSoft(async (issue: Issue) => {
597
622
  await api.issues.moveToNextSprint([issue.id]);
598
623
  refresh();
599
624
  toast({
600
625
  title: `${issue.ref} moved to Sprint 25.`,
601
626
  variant: 'success',
602
627
  });
603
- };
628
+ });
604
629
 
605
- const deleteIssue = async (issue: Issue) => {
630
+ const deleteIssue = failSoft(async (issue: Issue) => {
606
631
  const ok = await confirm({
607
632
  variant: 'destructive',
608
633
  title: 'Delete issue',
@@ -617,9 +642,9 @@ export function provideBacklogWorkspace(): BacklogWorkspaceContext {
617
642
  title: `${issue.ref} deleted.`,
618
643
  variant: 'success',
619
644
  });
620
- };
645
+ });
621
646
 
622
- // Bulk actions read and clear the coopted table context themselves. The
647
+ // Bulk actions read and clear the coopted table handle themselves. The
623
648
  // header checkbox is BbTable's "all across pages" select-all: it enumerates
624
649
  // no ids, so the payload becomes `{ all, unselected, filters }` — what is
625
650
  // on screen minus the exceptions — and the count is the total minus those
@@ -643,7 +668,7 @@ export function provideBacklogWorkspace(): BacklogWorkspaceContext {
643
668
  table.all.value = false;
644
669
  };
645
670
 
646
- const bulkStatus = async (status: IssueStatus) => {
671
+ const bulkStatus = failSoft(async (status: IssueStatus) => {
647
672
  const count = selectedCount.value;
648
673
  await api.issues.patchMany(bulkSelection(), { status });
649
674
  clearSelection();
@@ -653,9 +678,9 @@ export function provideBacklogWorkspace(): BacklogWorkspaceContext {
653
678
  title: `${count} issues moved to ${label}.`,
654
679
  variant: 'success',
655
680
  });
656
- };
681
+ });
657
682
 
658
- const bulkAssign = async (assignee: Member) => {
683
+ const bulkAssign = failSoft(async (assignee: Member) => {
659
684
  const count = selectedCount.value;
660
685
  await api.issues.patchMany(bulkSelection(), { assignee });
661
686
  clearSelection();
@@ -664,9 +689,9 @@ export function provideBacklogWorkspace(): BacklogWorkspaceContext {
664
689
  title: `${count} issues assigned to ${assignee.name}.`,
665
690
  variant: 'success',
666
691
  });
667
- };
692
+ });
668
693
 
669
- const bulkMoveToNextSprint = async () => {
694
+ const bulkMoveToNextSprint = failSoft(async () => {
670
695
  const count = selectedCount.value;
671
696
  await api.issues.moveToNextSprint(bulkSelection());
672
697
  clearSelection();
@@ -675,7 +700,7 @@ export function provideBacklogWorkspace(): BacklogWorkspaceContext {
675
700
  title: `${count} issues moved to Sprint 25.`,
676
701
  variant: 'success',
677
702
  });
678
- };
703
+ });
679
704
 
680
705
  const ctx: BacklogWorkspaceContext = {
681
706
  shell,
@@ -760,28 +785,30 @@ export function useBacklogWorkspace(): BacklogWorkspaceContext {
760
785
  <div class="flex flex-col gap-3 p-4">
761
786
  <FilterRail />
762
787
 
763
- <!-- Tabs as URL filters: href updates the query, the key feeds the
764
- fetch. Counts come back from the server on every fetch. -->
765
- <BbTabs
788
+ <!-- The sprint filter: one value over one table, so a radio group
789
+ with the tabs look (a tablist would promise panels). The context
790
+ keeps it in `?tab=`; the counts come from the server on every
791
+ fetch. -->
792
+ <BbRadioGroup
766
793
  v-model="ctx.tab.value"
767
794
  compact
795
+ hide-legend
768
796
  :items="[
769
797
  {
770
798
  value: 'backlog',
771
799
  label: `Backlog · ${ctx.tabCounts.value.backlog}`,
772
- href: '?tab=backlog',
773
800
  },
774
801
  {
775
802
  value: 'current',
776
803
  label: `Current sprint · ${ctx.tabCounts.value.current}`,
777
- href: '?tab=current',
778
804
  },
779
805
  {
780
806
  value: 'done',
781
807
  label: `Done · ${ctx.tabCounts.value.done}`,
782
- href: '?tab=done',
783
808
  },
784
809
  ]"
810
+ legend="Sprint"
811
+ variant="pill"
785
812
  />
786
813
 
787
814
  <BbTable
@@ -886,7 +913,7 @@ export function useBacklogWorkspace(): BacklogWorkspaceContext {
886
913
  </template>
887
914
  </BbTable>
888
915
 
889
- <!-- Joins the table context by id: no page/totalPages wiring at all. -->
916
+ <!-- Joins the table by id: no page/totalPages wiring at all. -->
890
917
  <BbPagination label="Backlog pagination" table-id="backlog-table" />
891
918
  </div>
892
919
 
@@ -913,11 +940,11 @@ import { computed } from 'vue';
913
940
  import {
914
941
  BbBaseButton,
915
942
  BbBreadcrumbs,
916
- BbIcon,
917
943
  BbButton,
944
+ BbIcon,
918
945
  BbPagination,
946
+ BbRadioGroup,
919
947
  BbTable,
920
- BbTabs,
921
948
  BbTextInput,
922
949
  } from 'bitboss-ui';
923
950
  import PageShell from '@/components/layout/PageShell.vue';