bitboss-ui 2.1.135 → 3.0.0-alpha.4

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 (1369) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +274 -24
  3. package/bin/bitboss-ui-mcp.mjs +662 -0
  4. package/bin/bitboss-ui.mjs +710 -0
  5. package/bin/bitboss-ui.node.test.mjs +113 -0
  6. package/dist/ai/BbAccordion.md +528 -113
  7. package/dist/ai/BbAlert.md +380 -197
  8. package/dist/ai/BbAsterisk.md +46 -0
  9. package/dist/ai/BbAvatar.md +458 -178
  10. package/dist/ai/BbBadge.md +697 -225
  11. package/dist/ai/BbBadgeButton.md +54 -0
  12. package/dist/ai/BbBaseButton.md +491 -0
  13. package/dist/ai/BbBaseCheckbox.md +49 -0
  14. package/dist/ai/BbBaseCheckboxGroup.md +64 -0
  15. package/dist/ai/BbBaseCheckboxIcon.md +176 -0
  16. package/dist/ai/BbBaseColorInput.md +64 -0
  17. package/dist/ai/BbBaseColorPalette.md +39 -0
  18. package/dist/ai/BbBaseDatePicker.md +42 -0
  19. package/dist/ai/BbBaseDatePickerInput.md +73 -0
  20. package/dist/ai/BbBaseInputContainer.md +48 -0
  21. package/dist/ai/BbBaseNumberInput.md +71 -0
  22. package/dist/ai/BbBaseRadio.md +46 -0
  23. package/dist/ai/BbBaseRadioGroup.md +64 -0
  24. package/dist/ai/BbBaseRadioIcon.md +191 -0
  25. package/dist/ai/BbBaseRating.md +51 -0
  26. package/dist/ai/BbBaseSelect.md +88 -0
  27. package/dist/ai/BbBaseSlider.md +56 -0
  28. package/dist/ai/BbBaseSwitch.md +49 -0
  29. package/dist/ai/BbBaseSwitchGroup.md +64 -0
  30. package/dist/ai/BbBaseSwitchIcon.md +186 -0
  31. package/dist/ai/BbBaseTag.md +68 -0
  32. package/dist/ai/BbBaseTextInput.md +75 -0
  33. package/dist/ai/BbBaseTextarea.md +62 -0
  34. package/dist/ai/BbBaseTimePickerInput.md +62 -0
  35. package/dist/ai/BbBreadcrumbs.md +553 -503
  36. package/dist/ai/BbButton.md +841 -636
  37. package/dist/ai/BbCheckbox.md +585 -254
  38. package/dist/ai/BbCheckboxGroup.md +573 -361
  39. package/dist/ai/BbCollapsible.md +425 -103
  40. package/dist/ai/BbColorInput.md +536 -323
  41. package/dist/ai/BbColorPalette.md +569 -330
  42. package/dist/ai/BbConfirm.md +659 -136
  43. package/dist/ai/BbConfirmPortal.md +28 -0
  44. package/dist/ai/BbDatePicker.md +244 -0
  45. package/dist/ai/BbDatePickerInput.md +720 -388
  46. package/dist/ai/BbDialog.md +778 -99
  47. package/dist/ai/BbDropdown.md +1072 -763
  48. package/dist/ai/BbDropdownButton.md +525 -614
  49. package/dist/ai/BbDropdownGroup.md +34 -0
  50. package/dist/ai/BbDropzone.md +1206 -436
  51. package/dist/ai/BbForm.md +239 -0
  52. package/dist/ai/BbIcon.md +382 -212
  53. package/dist/ai/BbIndicator.md +283 -0
  54. package/dist/ai/BbNumberInput.md +717 -355
  55. package/dist/ai/BbOffCanvas.md +897 -498
  56. package/dist/ai/BbPagination.md +489 -535
  57. package/dist/ai/BbPopover.md +591 -546
  58. package/dist/ai/BbProgress.md +462 -69
  59. package/dist/ai/BbRadio.md +352 -229
  60. package/dist/ai/BbRadioGroup.md +437 -353
  61. package/dist/ai/BbRating.md +372 -225
  62. package/dist/ai/BbSelect.md +1399 -536
  63. package/dist/ai/BbSelectPopover.md +1255 -1578
  64. package/dist/ai/BbSlider.md +500 -256
  65. package/dist/ai/BbSmoothHeight.md +485 -139
  66. package/dist/ai/BbSpinner.md +718 -131
  67. package/dist/ai/BbSwitch.md +573 -119
  68. package/dist/ai/BbSwitchGroup.md +521 -214
  69. package/dist/ai/BbTable.md +1996 -2365
  70. package/dist/ai/BbTabs.md +1147 -0
  71. package/dist/ai/BbTabsList.md +29 -0
  72. package/dist/ai/BbTabsPanes.md +27 -0
  73. package/dist/ai/BbTabsRoot.md +57 -0
  74. package/dist/ai/BbTag.md +416 -292
  75. package/dist/ai/BbTextInput.md +878 -333
  76. package/dist/ai/BbTextarea.md +850 -255
  77. package/dist/ai/BbTimePicker.md +231 -0
  78. package/dist/ai/BbTimePickerInput.md +200 -0
  79. package/dist/ai/BbToast.md +669 -196
  80. package/dist/ai/BbToastPortal.md +28 -0
  81. package/dist/ai/BbTooltip.md +453 -346
  82. package/dist/ai/BbTree.md +993 -234
  83. package/dist/ai/ChipsBox.md +27 -199
  84. package/dist/ai/ClearableButton.md +21 -55
  85. package/dist/ai/CommaBox.md +25 -200
  86. package/dist/ai/CommonInputWrapper.md +42 -0
  87. package/dist/ai/CommonPopover.md +30 -510
  88. package/dist/ai/ErrorIcon.md +19 -56
  89. package/dist/ai/FlatListBox.md +35 -379
  90. package/dist/ai/GroupedListBox.md +37 -535
  91. package/dist/ai/GuidesComponent.md +21 -0
  92. package/dist/ai/ListBox.md +38 -231
  93. package/dist/ai/OptionsContainer.md +34 -253
  94. package/dist/ai/WarningIcon.md +21 -0
  95. package/dist/ai/components.json +15897 -0
  96. package/dist/ai/composables/useBbConfig.md +80 -0
  97. package/dist/ai/composables/useBbFormContext.md +110 -0
  98. package/dist/ai/composables/useBbTableContext.md +167 -0
  99. package/dist/ai/composables/useBbTabsContext.md +118 -0
  100. package/dist/ai/composables/useBroadcastChannelInstance.md +97 -0
  101. package/dist/ai/composables/useConfirm.md +313 -0
  102. package/dist/ai/composables/useCountdown.md +86 -0
  103. package/dist/ai/composables/useId.md +60 -0
  104. package/dist/ai/composables/useMobile.md +85 -0
  105. package/dist/ai/composables/useToast.md +238 -0
  106. package/dist/ai/guides/agent-contract.md +165 -0
  107. package/dist/ai/guides/ai-router.md +113 -0
  108. package/dist/ai/guides/app-layout.md +318 -0
  109. package/dist/ai/guides/coherence-playbook.md +136 -0
  110. package/dist/ai/guides/component-picker.md +236 -0
  111. package/dist/ai/guides/design-language.md +478 -0
  112. package/dist/ai/guides/design-tokens.md +450 -0
  113. package/dist/ai/guides/fetch-items-playbook.md +161 -0
  114. package/dist/ai/guides/floating-bottom-panel.md +130 -0
  115. package/dist/ai/guides/icons-policy.md +257 -0
  116. package/dist/ai/guides/inertia-helpers.md +1443 -0
  117. package/dist/ai/guides/inline-edit-playbook.md +267 -0
  118. package/dist/ai/guides/installation-and-plugin-setup.md +440 -0
  119. package/dist/ai/guides/migration/components/bb-alert.md +37 -0
  120. package/dist/ai/guides/migration/components/bb-avatar.md +24 -0
  121. package/dist/ai/guides/migration/components/bb-badge.md +110 -0
  122. package/dist/ai/guides/migration/components/bb-breadcrumbs.md +26 -0
  123. package/dist/ai/guides/migration/components/bb-button.md +55 -0
  124. package/dist/ai/guides/migration/components/bb-checkbox-group.md +54 -0
  125. package/dist/ai/guides/migration/components/bb-checkbox.md +45 -0
  126. package/dist/ai/guides/migration/components/bb-chip.md +35 -0
  127. package/dist/ai/guides/migration/components/bb-collapsible.md +26 -0
  128. package/dist/ai/guides/migration/components/bb-color-input.md +23 -0
  129. package/dist/ai/guides/migration/components/bb-color-palette.md +31 -0
  130. package/dist/ai/guides/migration/components/bb-date-picker-input.md +84 -0
  131. package/dist/ai/guides/migration/components/bb-dialog.md +46 -0
  132. package/dist/ai/guides/migration/components/bb-dropdown-button.md +31 -0
  133. package/dist/ai/guides/migration/components/bb-dropdown.md +36 -0
  134. package/dist/ai/guides/migration/components/bb-dropzone.md +27 -0
  135. package/dist/ai/guides/migration/components/bb-icon.md +27 -0
  136. package/dist/ai/guides/migration/components/bb-offcanvas.md +63 -0
  137. package/dist/ai/guides/migration/components/bb-pagination.md +24 -0
  138. package/dist/ai/guides/migration/components/bb-popover.md +52 -0
  139. package/dist/ai/guides/migration/components/bb-rating.md +24 -0
  140. package/dist/ai/guides/migration/components/bb-select-popover.md +59 -0
  141. package/dist/ai/guides/migration/components/bb-select.md +69 -0
  142. package/dist/ai/guides/migration/components/bb-slider.md +25 -0
  143. package/dist/ai/guides/migration/components/bb-smooth-height.md +45 -0
  144. package/dist/ai/guides/migration/components/bb-spinner.md +23 -0
  145. package/dist/ai/guides/migration/components/bb-table.md +66 -0
  146. package/dist/ai/guides/migration/components/bb-tabs.md +47 -0
  147. package/dist/ai/guides/migration/components/bb-tag.md +29 -0
  148. package/dist/ai/guides/migration/components/bb-text-input.md +37 -0
  149. package/dist/ai/guides/migration/components/bb-toast.md +47 -0
  150. package/dist/ai/guides/migration/components/bb-tooltip.md +34 -0
  151. package/dist/ai/guides/migration/components/bb-tree.md +77 -0
  152. package/dist/ai/guides/migration/components/use-confirm.md +46 -0
  153. package/dist/ai/guides/migration/v2-to-v3.md +649 -0
  154. package/dist/ai/guides/options-items-playbook.md +222 -0
  155. package/dist/ai/guides/page-shell.md +113 -0
  156. package/dist/ai/guides/validated-forms.md +177 -0
  157. package/dist/ai/index.md +158 -32
  158. package/dist/ai/recipes/inertia/approvals-inbox.md +1635 -0
  159. package/dist/ai/recipes/inertia/inline-edit-workspace.md +1765 -0
  160. package/dist/ai/recipes/inertia/layout-scaffold.md +385 -0
  161. package/dist/ai/recipes/inertia/onboarding.md +1791 -0
  162. package/dist/ai/recipes/inertia/ownership-atlas.md +1327 -0
  163. package/dist/ai/recipes/inertia/record-form.md +1489 -0
  164. package/dist/ai/recipes/inertia/records-workspace.md +1416 -0
  165. package/dist/ai/recipes/inertia/upload-center.md +2003 -0
  166. package/dist/ai/recipes/inertia/wizard-form.md +1500 -0
  167. package/dist/ai/recipes/nuxt/approvals-inbox.md +1578 -0
  168. package/dist/ai/recipes/nuxt/inline-edit-workspace.md +1703 -0
  169. package/dist/ai/recipes/nuxt/layout-scaffold.md +385 -0
  170. package/dist/ai/recipes/nuxt/onboarding.md +1724 -0
  171. package/dist/ai/recipes/nuxt/record-form.md +1502 -0
  172. package/dist/ai/recipes/nuxt/records-workspace.md +1329 -0
  173. package/dist/ai/recipes/nuxt/upload-center.md +1886 -0
  174. package/dist/ai/recipes/nuxt/wizard-form.md +1509 -0
  175. package/dist/ai/recipes/vue/approvals-inbox.md +1496 -0
  176. package/dist/ai/recipes/vue/inline-edit-workspace.md +1594 -0
  177. package/dist/ai/recipes/vue/layout-scaffold.md +385 -0
  178. package/dist/ai/recipes/vue/onboarding.md +1679 -0
  179. package/dist/ai/recipes/vue/record-form.md +1586 -0
  180. package/dist/ai/recipes/vue/records-workspace.md +1245 -0
  181. package/dist/ai/recipes/vue/upload-center.md +1845 -0
  182. package/dist/ai/recipes/vue/wizard-form.md +1441 -0
  183. package/dist/ai/source/BbAccordion.md +123 -0
  184. package/dist/ai/source/BbAlert.md +401 -0
  185. package/dist/ai/source/BbAsterisk.md +32 -0
  186. package/dist/ai/source/BbAvatar.md +258 -0
  187. package/dist/ai/source/BbBadge.md +560 -0
  188. package/dist/ai/source/BbBadgeButton.md +490 -0
  189. package/dist/ai/source/BbBaseButton.md +682 -0
  190. package/dist/ai/source/BbBaseCheckbox.md +461 -0
  191. package/dist/ai/source/BbBaseCheckboxGroup.md +554 -0
  192. package/dist/ai/source/BbBaseCheckboxIcon.md +201 -0
  193. package/dist/ai/source/BbBaseColorInput.md +416 -0
  194. package/dist/ai/source/BbBaseColorPalette.md +934 -0
  195. package/dist/ai/source/BbBaseDatePicker.md +1001 -0
  196. package/dist/ai/source/BbBaseDatePickerInput.md +1785 -0
  197. package/dist/ai/source/BbBaseInputContainer.md +1210 -0
  198. package/dist/ai/source/BbBaseNumberInput.md +617 -0
  199. package/dist/ai/source/BbBaseRadio.md +377 -0
  200. package/dist/ai/source/BbBaseRadioGroup.md +533 -0
  201. package/dist/ai/source/BbBaseRadioIcon.md +153 -0
  202. package/dist/ai/source/BbBaseRating.md +573 -0
  203. package/dist/ai/source/BbBaseSelect.md +898 -0
  204. package/dist/ai/source/BbBaseSlider.md +1085 -0
  205. package/dist/ai/source/BbBaseSwitch.md +246 -0
  206. package/dist/ai/source/BbBaseSwitchGroup.md +302 -0
  207. package/dist/ai/source/BbBaseSwitchIcon.md +206 -0
  208. package/dist/ai/source/BbBaseTag.md +694 -0
  209. package/dist/ai/source/BbBaseTextInput.md +511 -0
  210. package/dist/ai/source/BbBaseTextarea.md +480 -0
  211. package/dist/ai/source/BbBaseTimePickerInput.md +1031 -0
  212. package/dist/ai/source/BbBreadcrumbs.md +815 -0
  213. package/dist/ai/source/BbButton.md +1006 -0
  214. package/dist/ai/source/BbCheckbox.md +326 -0
  215. package/dist/ai/source/BbCheckboxGroup.md +419 -0
  216. package/dist/ai/source/BbCollapsible.md +137 -0
  217. package/dist/ai/source/BbColorInput.md +322 -0
  218. package/dist/ai/source/BbColorPalette.md +371 -0
  219. package/dist/ai/source/BbConfirm.md +193 -0
  220. package/dist/ai/source/BbConfirmPortal.md +74 -0
  221. package/dist/ai/source/BbDatePicker.md +729 -0
  222. package/dist/ai/source/BbDatePickerInput.md +525 -0
  223. package/dist/ai/source/BbDialog.md +818 -0
  224. package/dist/ai/source/BbDropdown.md +2387 -0
  225. package/dist/ai/source/BbDropdownButton.md +315 -0
  226. package/dist/ai/source/BbDropdownGroup.md +1259 -0
  227. package/dist/ai/source/BbDropzone.md +864 -0
  228. package/dist/ai/source/BbForm.md +100 -0
  229. package/dist/ai/source/BbIcon.md +214 -0
  230. package/dist/ai/source/BbIndicator.md +298 -0
  231. package/dist/ai/source/BbNumberInput.md +374 -0
  232. package/dist/ai/source/BbOffCanvas.md +1266 -0
  233. package/dist/ai/source/BbPagination.md +835 -0
  234. package/dist/ai/source/BbPopover.md +860 -0
  235. package/dist/ai/source/BbProgress.md +140 -0
  236. package/dist/ai/source/BbRadio.md +303 -0
  237. package/dist/ai/source/BbRadioGroup.md +420 -0
  238. package/dist/ai/source/BbRating.md +369 -0
  239. package/dist/ai/source/BbSelect.md +688 -0
  240. package/dist/ai/source/BbSelectPopover.md +2234 -0
  241. package/dist/ai/source/BbSlider.md +378 -0
  242. package/dist/ai/source/BbSmoothHeight.md +265 -0
  243. package/dist/ai/source/BbSpinner.md +127 -0
  244. package/dist/ai/source/BbSwitch.md +175 -0
  245. package/dist/ai/source/BbSwitchGroup.md +240 -0
  246. package/dist/ai/source/BbTable.md +3433 -0
  247. package/dist/ai/source/BbTabs.md +403 -0
  248. package/dist/ai/source/BbTabsList.md +578 -0
  249. package/dist/ai/source/BbTabsPanes.md +368 -0
  250. package/dist/ai/source/BbTabsRoot.md +372 -0
  251. package/dist/ai/source/BbTag.md +390 -0
  252. package/dist/ai/source/BbTextInput.md +352 -0
  253. package/dist/ai/source/BbTextarea.md +337 -0
  254. package/dist/ai/source/BbTimePicker.md +595 -0
  255. package/dist/ai/source/BbTimePickerInput.md +376 -0
  256. package/dist/ai/source/BbToast.md +525 -0
  257. package/dist/ai/source/BbToastPortal.md +482 -0
  258. package/dist/ai/source/BbTooltip.md +522 -0
  259. package/dist/ai/source/BbTree.md +323 -0
  260. package/dist/ai/source/ChipsBox.md +201 -0
  261. package/dist/ai/source/ClearableButton.md +70 -0
  262. package/dist/ai/source/CommaBox.md +202 -0
  263. package/dist/ai/source/CommonInputWrapper.md +554 -0
  264. package/dist/ai/source/CommonPopover.md +616 -0
  265. package/dist/ai/source/ErrorIcon.md +43 -0
  266. package/dist/ai/source/FlatListBox.md +396 -0
  267. package/dist/ai/source/GroupedListBox.md +540 -0
  268. package/dist/ai/source/GuidesComponent.md +383 -0
  269. package/dist/ai/source/ListBox.md +238 -0
  270. package/dist/ai/source/OptionsContainer.md +191 -0
  271. package/dist/ai/source/WarningIcon.md +47 -0
  272. package/dist/alert-variants.d.ts +19 -0
  273. package/dist/assets/css/reset.css_inline.js +4 -0
  274. package/dist/assets/svgs/alert.svg_raw.js +4 -0
  275. package/dist/assets/svgs/calendar.svg_raw.js +4 -0
  276. package/dist/assets/svgs/check_stroke.svg_raw.js +4 -0
  277. package/dist/assets/svgs/chevron_down.svg_raw.js +4 -0
  278. package/dist/assets/svgs/chevron_right.svg_raw.js +4 -0
  279. package/dist/assets/svgs/clear.svg_raw.js +4 -0
  280. package/dist/assets/svgs/clock.svg_raw.js +4 -0
  281. package/dist/assets/svgs/error.svg_raw.js +4 -0
  282. package/dist/assets/svgs/search.svg_raw.js +4 -0
  283. package/dist/assets/svgs/sort.svg_raw.js +4 -0
  284. package/dist/assets/svgs/spinner.svg_raw.js +4 -0
  285. package/dist/assets/svgs/user.svg_raw.js +4 -0
  286. package/dist/badge-variants.d.ts +19 -0
  287. package/dist/button-variants.d.ts +21 -0
  288. package/dist/components/BbAccordion/BbAccordion.vue.d.ts +9 -3
  289. package/dist/components/BbAccordion/BbAccordion.vue.js +6 -0
  290. package/dist/components/BbAccordion/BbAccordion.vue_vue_type_script_setup_true_lang.js +66 -0
  291. package/dist/components/BbAccordion/types.d.ts +12 -8
  292. package/dist/components/BbAlert/BbAlert.vue.d.ts +12 -3
  293. package/dist/components/BbAlert/BbAlert.vue.js +6 -0
  294. package/dist/components/BbAlert/BbAlert.vue_vue_type_script_setup_true_lang.js +65 -0
  295. package/dist/components/BbAlert/types.d.ts +56 -12
  296. package/dist/components/BbAsterisk/BbAsterisk.vue.d.ts +3 -0
  297. package/dist/components/BbAsterisk/BbAsterisk.vue.js +6 -0
  298. package/dist/components/BbAsterisk/BbAsterisk.vue_vue_type_script_setup_true_lang.js +13 -0
  299. package/dist/components/BbAvatar/BbAvatar.vue.d.ts +5 -0
  300. package/dist/components/BbAvatar/BbAvatar.vue.js +6 -0
  301. package/dist/components/BbAvatar/BbAvatar.vue_vue_type_script_setup_true_lang.js +78 -0
  302. package/dist/components/BbAvatar/types.d.ts +6 -5
  303. package/dist/components/BbBadge/BadgeAppendIcon.vue.d.ts +3 -0
  304. package/dist/components/BbBadge/BadgeAppendIcon.vue.js +5 -0
  305. package/dist/components/BbBadge/BadgeAppendIcon.vue_vue_type_script_setup_true_lang.js +22 -0
  306. package/dist/components/BbBadge/BadgeBodyContent.vue.d.ts +15 -0
  307. package/dist/components/BbBadge/BadgeBodyContent.vue.js +5 -0
  308. package/dist/components/BbBadge/BadgeBodyContent.vue_vue_type_script_setup_true_lang.js +34 -0
  309. package/dist/components/BbBadge/BbBadge.vue.d.ts +8 -1
  310. package/dist/components/BbBadge/BbBadge.vue.js +6 -0
  311. package/dist/components/BbBadge/BbBadge.vue_vue_type_script_setup_true_lang.js +83 -0
  312. package/dist/components/BbBadge/BbBadgeButton.vue.d.ts +12 -0
  313. package/dist/components/BbBadge/BbBadgeButton.vue.js +5 -0
  314. package/dist/components/BbBadge/BbBadgeButton.vue_vue_type_script_setup_true_lang.js +54 -0
  315. package/dist/components/BbBadge/badgeButtonContext.d.ts +27 -0
  316. package/dist/components/BbBadge/badgeButtonContext.js +5 -0
  317. package/dist/components/BbBadge/types.d.ts +61 -16
  318. package/dist/components/BbBaseButton/BbBaseButton.vue.d.ts +13 -0
  319. package/dist/components/BbBaseButton/BbBaseButton.vue.js +6 -0
  320. package/dist/components/BbBaseButton/BbBaseButton.vue_vue_type_script_setup_true_lang.js +171 -0
  321. package/dist/components/BbBaseButton/RouterComponent.vue.js +5 -0
  322. package/dist/components/BbBaseButton/RouterComponent.vue_vue_type_script_setup_true_lang.js +29 -0
  323. package/dist/components/BbBaseButton/types.d.ts +191 -0
  324. package/dist/components/BbBaseButton/types.js +33 -0
  325. package/dist/components/BbBaseCheckbox/BbBaseCheckbox.vue.d.ts +40 -0
  326. package/dist/components/BbBaseCheckbox/BbBaseCheckbox.vue.js +6 -0
  327. package/dist/components/BbBaseCheckbox/BbBaseCheckbox.vue_vue_type_script_setup_true_lang.js +145 -0
  328. package/dist/components/BbBaseCheckbox/types.d.ts +224 -0
  329. package/dist/components/BbBaseCheckboxGroup/BbBaseCheckboxGroup.vue.d.ts +19 -0
  330. package/dist/components/BbBaseCheckboxGroup/BbBaseCheckboxGroup.vue.js +6 -0
  331. package/dist/components/BbBaseCheckboxGroup/BbBaseCheckboxGroup.vue_vue_type_script_setup_true_lang.js +190 -0
  332. package/dist/components/BbBaseCheckboxGroup/types.d.ts +257 -0
  333. package/dist/components/BbBaseCheckboxIcon/BbBaseCheckboxIcon.vue.d.ts +4 -0
  334. package/dist/components/BbBaseCheckboxIcon/BbBaseCheckboxIcon.vue.js +6 -0
  335. package/dist/components/BbBaseCheckboxIcon/BbBaseCheckboxIcon.vue_vue_type_script_setup_true_lang.js +43 -0
  336. package/dist/components/BbBaseCheckboxIcon/types.d.ts +47 -0
  337. package/dist/components/BbBaseColorInput/BbBaseColorInput.vue.d.ts +42 -0
  338. package/dist/components/BbBaseColorInput/BbBaseColorInput.vue.js +6 -0
  339. package/dist/components/BbBaseColorInput/BbBaseColorInput.vue_vue_type_script_setup_true_lang.js +178 -0
  340. package/dist/components/BbBaseColorInput/types.d.ts +210 -0
  341. package/dist/components/BbBaseColorPalette/BbBaseColorPalette.vue.d.ts +13 -0
  342. package/dist/components/BbBaseColorPalette/BbBaseColorPalette.vue.js +6 -0
  343. package/dist/components/BbBaseColorPalette/BbBaseColorPalette.vue_vue_type_script_setup_true_lang.js +395 -0
  344. package/dist/components/BbBaseColorPalette/types.d.ts +40 -0
  345. package/dist/components/BbBaseDatePicker/BbBaseDatePicker.vue.js +6 -0
  346. package/dist/components/BbBaseDatePicker/BbBaseDatePicker.vue_vue_type_script_setup_true_lang.js +300 -0
  347. package/dist/components/BbBaseDatePicker/BbBaseDatePickerInputDaySelector.vue.d.ts +44 -0
  348. package/dist/components/BbBaseDatePicker/BbBaseDatePickerInputDaySelector.vue.js +5 -0
  349. package/dist/components/BbBaseDatePicker/BbBaseDatePickerInputDaySelector.vue_vue_type_script_setup_true_lang.js +310 -0
  350. package/dist/components/BbBaseDatePicker/BbBaseDatePickerMonthSelector.vue.d.ts +5 -0
  351. package/dist/components/BbBaseDatePicker/BbBaseDatePickerMonthSelector.vue.js +5 -0
  352. package/dist/components/BbBaseDatePicker/BbBaseDatePickerMonthSelector.vue_vue_type_script_setup_true_lang.js +63 -0
  353. package/dist/components/BbBaseDatePicker/BbBaseDatePickerYearSelector.vue.d.ts +5 -0
  354. package/dist/components/BbBaseDatePicker/BbBaseDatePickerYearSelector.vue.js +5 -0
  355. package/dist/components/BbBaseDatePicker/BbBaseDatePickerYearSelector.vue_vue_type_script_setup_true_lang.js +75 -0
  356. package/dist/components/BbBaseDatePicker/typeahead.d.ts +112 -0
  357. package/dist/components/BbBaseDatePicker/typeahead.js +37 -0
  358. package/dist/components/BbBaseDatePicker/types.d.ts +97 -0
  359. package/dist/components/BbBaseDatePicker/useDatePickerContext.d.ts +58 -0
  360. package/dist/components/BbBaseDatePicker/useDatePickerContext.js +11 -0
  361. package/dist/components/BbBaseDatePickerInput/BbBaseDatePickerInput.vue.d.ts +30 -0
  362. package/dist/components/BbBaseDatePickerInput/BbBaseDatePickerInput.vue.js +6 -0
  363. package/dist/components/BbBaseDatePickerInput/BbBaseDatePickerInput.vue_vue_type_script_setup_true_lang.js +716 -0
  364. package/dist/components/BbBaseDatePickerInput/BbBaseDatePickerTimeSelector.vue.d.ts +30 -0
  365. package/dist/components/BbBaseDatePickerInput/BbBaseDatePickerTimeSelector.vue.js +6 -0
  366. package/dist/components/BbBaseDatePickerInput/BbBaseDatePickerTimeSelector.vue_vue_type_script_setup_true_lang.js +204 -0
  367. package/dist/components/BbBaseDatePickerInput/types.d.ts +311 -0
  368. package/dist/components/BbBaseInputContainer/BbBaseInputContainer.vue.d.ts +17 -0
  369. package/dist/components/BbBaseInputContainer/BbBaseInputContainer.vue.js +6 -0
  370. package/dist/components/BbBaseInputContainer/BbBaseInputContainer.vue_vue_type_script_setup_true_lang.js +191 -0
  371. package/dist/components/BbBaseInputContainer/types.d.ts +197 -0
  372. package/dist/components/BbBaseNumberInput/BbBaseNumberInput.vue.d.ts +52 -0
  373. package/dist/components/BbBaseNumberInput/BbBaseNumberInput.vue.js +6 -0
  374. package/dist/components/BbBaseNumberInput/BbBaseNumberInput.vue_vue_type_script_setup_true_lang.js +215 -0
  375. package/dist/components/BbBaseNumberInput/types.d.ts +211 -0
  376. package/dist/components/BbBaseRadio/BbBaseRadio.vue.d.ts +33 -0
  377. package/dist/components/BbBaseRadio/BbBaseRadio.vue.js +6 -0
  378. package/dist/components/BbBaseRadio/BbBaseRadio.vue_vue_type_script_setup_true_lang.js +114 -0
  379. package/dist/components/BbBaseRadio/types.d.ts +179 -0
  380. package/dist/components/BbBaseRadioGroup/BbBaseRadioGroup.vue.d.ts +19 -0
  381. package/dist/components/BbBaseRadioGroup/BbBaseRadioGroup.vue.js +6 -0
  382. package/dist/components/BbBaseRadioGroup/BbBaseRadioGroup.vue_vue_type_script_setup_true_lang.js +177 -0
  383. package/dist/components/BbBaseRadioGroup/types.d.ts +223 -0
  384. package/dist/components/BbBaseRadioIcon/BbBaseRadioIcon.vue.d.ts +4 -0
  385. package/dist/components/BbBaseRadioIcon/BbBaseRadioIcon.vue.js +6 -0
  386. package/dist/components/BbBaseRadioIcon/BbBaseRadioIcon.vue_vue_type_script_setup_true_lang.js +28 -0
  387. package/dist/components/BbBaseRadioIcon/types.d.ts +41 -0
  388. package/dist/components/BbBaseRating/BbBaseRating.vue.d.ts +38 -0
  389. package/dist/components/BbBaseRating/BbBaseRating.vue.js +6 -0
  390. package/dist/components/BbBaseRating/BbBaseRating.vue_vue_type_script_setup_true_lang.js +184 -0
  391. package/dist/components/BbBaseRating/types.d.ts +168 -0
  392. package/dist/components/BbBaseSelect/BbBaseSelect.vue.d.ts +19 -0
  393. package/dist/components/BbBaseSelect/BbBaseSelect.vue.js +6 -0
  394. package/dist/components/BbBaseSelect/BbBaseSelect.vue_vue_type_script_setup_true_lang.js +307 -0
  395. package/dist/components/BbBaseSelect/types.d.ts +297 -0
  396. package/dist/components/BbBaseSlider/BbBaseSlider.vue.d.ts +35 -0
  397. package/dist/components/BbBaseSlider/BbBaseSlider.vue.js +6 -0
  398. package/dist/components/BbBaseSlider/BbBaseSlider.vue_vue_type_script_setup_true_lang.js +324 -0
  399. package/dist/components/BbBaseSlider/types.d.ts +200 -0
  400. package/dist/components/BbBaseSwitch/BbBaseSwitch.vue.d.ts +35 -0
  401. package/dist/components/BbBaseSwitch/BbBaseSwitch.vue.js +6 -0
  402. package/dist/components/BbBaseSwitch/BbBaseSwitch.vue_vue_type_script_setup_true_lang.js +146 -0
  403. package/dist/components/BbBaseSwitch/types.d.ts +10 -0
  404. package/dist/components/BbBaseSwitchGroup/BbBaseSwitchGroup.vue.d.ts +19 -0
  405. package/dist/components/BbBaseSwitchGroup/BbBaseSwitchGroup.vue.js +6 -0
  406. package/dist/components/BbBaseSwitchGroup/BbBaseSwitchGroup.vue_vue_type_script_setup_true_lang.js +190 -0
  407. package/dist/components/BbBaseSwitchGroup/types.d.ts +8 -0
  408. package/dist/components/BbBaseSwitchIcon/BbBaseSwitchIcon.vue.d.ts +4 -0
  409. package/dist/components/BbBaseSwitchIcon/BbBaseSwitchIcon.vue.js +6 -0
  410. package/dist/components/BbBaseSwitchIcon/BbBaseSwitchIcon.vue_vue_type_script_setup_true_lang.js +30 -0
  411. package/dist/components/BbBaseSwitchIcon/types.d.ts +48 -0
  412. package/dist/components/BbBaseTag/BbBaseTag.vue.d.ts +50 -0
  413. package/dist/components/BbBaseTag/BbBaseTag.vue.js +6 -0
  414. package/dist/components/BbBaseTag/BbBaseTag.vue_vue_type_script_setup_true_lang.js +266 -0
  415. package/dist/components/BbBaseTag/types.d.ts +160 -0
  416. package/dist/components/BbBaseTextInput/BbBaseTextInput.vue.d.ts +45 -0
  417. package/dist/components/BbBaseTextInput/BbBaseTextInput.vue.js +6 -0
  418. package/dist/components/BbBaseTextInput/BbBaseTextInput.vue_vue_type_script_setup_true_lang.js +200 -0
  419. package/dist/components/BbBaseTextInput/types.d.ts +209 -0
  420. package/dist/components/BbBaseTextarea/BbBaseTextarea.vue.d.ts +39 -0
  421. package/dist/components/BbBaseTextarea/BbBaseTextarea.vue.js +6 -0
  422. package/dist/components/BbBaseTextarea/BbBaseTextarea.vue_vue_type_script_setup_true_lang.js +175 -0
  423. package/dist/components/BbBaseTextarea/types.d.ts +170 -0
  424. package/dist/components/BbBaseTimePickerInput/BbBaseTimePickerInput.vue.d.ts +27 -0
  425. package/dist/components/BbBaseTimePickerInput/BbBaseTimePickerInput.vue.js +6 -0
  426. package/dist/components/BbBaseTimePickerInput/BbBaseTimePickerInput.vue_vue_type_script_setup_true_lang.js +522 -0
  427. package/dist/components/BbBaseTimePickerInput/types.d.ts +151 -0
  428. package/dist/components/BbBreadcrumbs/BbBreadcrumbs.vue.d.ts +0 -1
  429. package/dist/components/BbBreadcrumbs/BbBreadcrumbs.vue.js +6 -0
  430. package/dist/components/BbBreadcrumbs/BbBreadcrumbs.vue_vue_type_script_setup_true_lang.js +224 -0
  431. package/dist/components/BbBreadcrumbs/estimateBreadcrumbItemWidth.js +47 -0
  432. package/dist/components/BbBreadcrumbs/types.d.ts +37 -22
  433. package/dist/components/BbButton/BbButton.vue.d.ts +6 -5
  434. package/dist/components/BbButton/BbButton.vue.js +6 -0
  435. package/dist/components/BbButton/BbButton.vue_vue_type_script_setup_true_lang.js +181 -0
  436. package/dist/components/BbButton/types.d.ts +48 -47
  437. package/dist/components/BbCheckbox/BbCheckbox.vue.d.ts +4 -3
  438. package/dist/components/BbCheckbox/BbCheckbox.vue.js +6 -0
  439. package/dist/components/BbCheckbox/BbCheckbox.vue_vue_type_script_setup_true_lang.js +146 -0
  440. package/dist/components/BbCheckbox/types.d.ts +31 -10
  441. package/dist/components/BbCheckboxGroup/BbCheckboxGroup.vue.d.ts +2 -13
  442. package/dist/components/BbCheckboxGroup/BbCheckboxGroup.vue.js +6 -0
  443. package/dist/components/BbCheckboxGroup/BbCheckboxGroup.vue_vue_type_script_setup_true_lang.js +190 -0
  444. package/dist/components/BbCheckboxGroup/types.d.ts +51 -23
  445. package/dist/components/BbCollapsible/BbCollapsible.vue.d.ts +2 -1
  446. package/dist/components/BbCollapsible/BbCollapsible.vue.js +6 -0
  447. package/dist/components/BbCollapsible/BbCollapsible.vue_vue_type_script_setup_true_lang.js +31 -0
  448. package/dist/components/BbCollapsible/types.d.ts +13 -8
  449. package/dist/components/BbColorInput/BbColorInput.vue.d.ts +10 -1
  450. package/dist/components/BbColorInput/BbColorInput.vue.js +6 -0
  451. package/dist/components/BbColorInput/BbColorInput.vue_vue_type_script_setup_true_lang.js +177 -0
  452. package/dist/components/BbColorInput/types.d.ts +44 -11
  453. package/dist/components/BbColorPalette/BbColorPalette.vue.d.ts +5 -8
  454. package/dist/components/BbColorPalette/BbColorPalette.vue.js +5 -0
  455. package/dist/components/BbColorPalette/BbColorPalette.vue_vue_type_script_setup_true_lang.js +126 -0
  456. package/dist/components/BbColorPalette/types.d.ts +71 -52
  457. package/dist/components/BbConfirm/BbConfirm.vue.js +6 -0
  458. package/dist/components/BbConfirm/BbConfirm.vue_vue_type_script_setup_true_lang.js +138 -0
  459. package/dist/components/BbConfirm/BbConfirmPortal.vue.d.ts +5 -6
  460. package/dist/components/BbConfirm/BbConfirmPortal.vue.js +5 -0
  461. package/dist/components/BbConfirm/BbConfirmPortal.vue_vue_type_script_setup_true_lang.js +19 -0
  462. package/dist/components/BbDatePicker/BbDatePicker.vue.d.ts +37 -0
  463. package/dist/components/BbDatePicker/BbDatePicker.vue.js +6 -0
  464. package/dist/components/BbDatePicker/BbDatePicker.vue_vue_type_script_setup_true_lang.js +319 -0
  465. package/dist/components/BbDatePicker/types.d.ts +159 -0
  466. package/dist/components/BbDatePickerInput/BbDatePickerInput.vue.d.ts +3 -1
  467. package/dist/components/BbDatePickerInput/BbDatePickerInput.vue.js +6 -0
  468. package/dist/components/BbDatePickerInput/BbDatePickerInput.vue_vue_type_script_setup_true_lang.js +179 -0
  469. package/dist/components/BbDatePickerInput/types.d.ts +134 -16
  470. package/dist/components/BbDialog/BbDialog.vue.d.ts +14 -6
  471. package/dist/components/BbDialog/BbDialog.vue.js +6 -0
  472. package/dist/components/BbDialog/BbDialog.vue_vue_type_script_setup_true_lang.js +214 -0
  473. package/dist/components/BbDialog/types.d.ts +146 -1
  474. package/dist/components/BbDialog/useDialogStack.d.ts +5 -0
  475. package/dist/components/BbDialog/useDialogStack.js +20 -0
  476. package/dist/components/BbDropdown/AdaptiveDropdown.vue.d.ts +24 -0
  477. package/dist/components/BbDropdown/AdaptiveDropdown.vue.js +6 -0
  478. package/dist/components/BbDropdown/AdaptiveDropdown.vue_vue_type_script_setup_true_lang.js +116 -0
  479. package/dist/components/BbDropdown/BbDropdown.vue.d.ts +14 -7
  480. package/dist/components/BbDropdown/BbDropdown.vue.js +6 -0
  481. package/dist/components/BbDropdown/BbDropdown.vue_vue_type_script_setup_true_lang.js +561 -0
  482. package/dist/components/BbDropdown/BbDropdownGroup.vue.d.ts +44 -0
  483. package/dist/components/BbDropdown/BbDropdownGroup.vue.js +5 -0
  484. package/dist/components/BbDropdown/BbDropdownGroup.vue_vue_type_script_setup_true_lang.js +36 -0
  485. package/dist/components/BbDropdown/BbDropdownList.vue.d.ts +31 -0
  486. package/dist/components/BbDropdown/BbDropdownList.vue.js +6 -0
  487. package/dist/components/BbDropdown/BbDropdownList.vue_vue_type_script_setup_true_lang.js +470 -0
  488. package/dist/components/BbDropdown/DropdownPipelineResolver.vue.d.ts +16 -0
  489. package/dist/components/BbDropdown/DropdownPipelineResolver.vue.js +5 -0
  490. package/dist/components/BbDropdown/DropdownPipelineResolver.vue_vue_type_script_setup_true_lang.js +168 -0
  491. package/dist/components/BbDropdown/normalizeGroups.d.ts +18 -0
  492. package/dist/components/BbDropdown/normalizeGroups.js +46 -0
  493. package/dist/components/BbDropdown/types.d.ts +468 -46
  494. package/dist/components/BbDropdown/types.js +4 -0
  495. package/dist/components/BbDropdown/useDropdownContext.d.ts +89 -0
  496. package/dist/components/BbDropdown/useDropdownContext.js +9 -0
  497. package/dist/components/BbDropdown/useDropdownGroupRegistry.d.ts +108 -0
  498. package/dist/components/BbDropdown/useDropdownGroupRegistry.js +5 -0
  499. package/dist/components/BbDropdownButton/BbDropdownButton.vue.d.ts +3 -3
  500. package/dist/components/BbDropdownButton/BbDropdownButton.vue.js +6 -0
  501. package/dist/components/BbDropdownButton/BbDropdownButton.vue_vue_type_script_setup_true_lang.js +119 -0
  502. package/dist/components/BbDropdownButton/types.d.ts +47 -52
  503. package/dist/components/BbDropzone/BbDropzone.vue.d.ts +5 -4
  504. package/dist/components/BbDropzone/BbDropzone.vue.js +6 -0
  505. package/dist/components/BbDropzone/BbDropzone.vue_vue_type_script_setup_true_lang.js +308 -0
  506. package/dist/components/BbDropzone/types.d.ts +77 -8
  507. package/dist/components/BbIcon/BbIcon.vue.d.ts +3 -2
  508. package/dist/components/BbIcon/BbIcon.vue.js +6 -0
  509. package/dist/components/BbIcon/BbIcon.vue_vue_type_script_setup_true_lang.js +65 -0
  510. package/dist/components/BbIcon/types.d.ts +6 -19
  511. package/dist/components/BbIndicator/BbIndicator.vue.d.ts +14 -0
  512. package/dist/components/BbIndicator/BbIndicator.vue.js +6 -0
  513. package/dist/components/BbIndicator/BbIndicator.vue_vue_type_script_setup_true_lang.js +56 -0
  514. package/dist/components/BbIndicator/types.d.ts +49 -0
  515. package/dist/components/BbNumberInput/BbNumberInput.vue.d.ts +12 -6
  516. package/dist/components/BbNumberInput/BbNumberInput.vue.js +6 -0
  517. package/dist/components/BbNumberInput/BbNumberInput.vue_vue_type_script_setup_true_lang.js +194 -0
  518. package/dist/components/BbNumberInput/types.d.ts +40 -4
  519. package/dist/components/BbOffCanvas/BbOffCanvas.vue.d.ts +16 -10
  520. package/dist/components/BbOffCanvas/BbOffCanvas.vue.js +6 -0
  521. package/dist/components/BbOffCanvas/BbOffCanvas.vue_vue_type_script_setup_true_lang.js +284 -0
  522. package/dist/components/BbOffCanvas/types.d.ts +71 -39
  523. package/dist/components/BbOffCanvas/useOffCanvasStack.d.ts +25 -0
  524. package/dist/components/BbOffCanvas/useOffCanvasStack.js +68 -0
  525. package/dist/components/BbPagination/BbPagination.vue.d.ts +9 -4
  526. package/dist/components/BbPagination/BbPagination.vue.js +6 -0
  527. package/dist/components/BbPagination/BbPagination.vue_vue_type_script_setup_true_lang.js +244 -0
  528. package/dist/components/BbPagination/paginationFit.d.ts +38 -0
  529. package/dist/components/BbPagination/paginationFit.js +13 -0
  530. package/dist/components/BbPagination/types.d.ts +51 -16
  531. package/dist/components/BbPopover/BbPopover.vue.d.ts +16 -15
  532. package/dist/components/BbPopover/BbPopover.vue.js +6 -0
  533. package/dist/components/BbPopover/BbPopover.vue_vue_type_script_setup_true_lang.js +309 -0
  534. package/dist/components/BbPopover/escapeStack.d.ts +6 -0
  535. package/dist/components/BbPopover/escapeStack.js +10 -0
  536. package/dist/components/BbPopover/types.d.ts +90 -31
  537. package/dist/components/BbProgress/BbProgress.vue.d.ts +1 -0
  538. package/dist/components/BbProgress/BbProgress.vue.js +6 -0
  539. package/dist/components/BbProgress/BbProgress.vue_vue_type_script_setup_true_lang.js +36 -0
  540. package/dist/components/BbProgress/types.d.ts +15 -1
  541. package/dist/components/BbRadio/BbRadio.vue.d.ts +5 -3
  542. package/dist/components/BbRadio/BbRadio.vue.js +6 -0
  543. package/dist/components/BbRadio/BbRadio.vue_vue_type_script_setup_true_lang.js +133 -0
  544. package/dist/components/BbRadio/types.d.ts +32 -9
  545. package/dist/components/BbRadioGroup/BbRadioGroup.vue.d.ts +4 -14
  546. package/dist/components/BbRadioGroup/BbRadioGroup.vue.js +6 -0
  547. package/dist/components/BbRadioGroup/BbRadioGroup.vue_vue_type_script_setup_true_lang.js +186 -0
  548. package/dist/components/BbRadioGroup/types.d.ts +48 -22
  549. package/dist/components/BbRating/BbRating.vue.d.ts +4 -1
  550. package/dist/components/BbRating/BbRating.vue.js +6 -0
  551. package/dist/components/BbRating/BbRating.vue_vue_type_script_setup_true_lang.js +150 -0
  552. package/dist/components/BbRating/types.d.ts +44 -10
  553. package/dist/components/BbSelect/BbSelect.vue.d.ts +2 -11
  554. package/dist/components/BbSelect/BbSelect.vue.js +6 -0
  555. package/dist/components/BbSelect/BbSelect.vue_vue_type_script_setup_true_lang.js +241 -0
  556. package/dist/components/BbSelect/types.d.ts +112 -59
  557. package/dist/components/BbSelectPopover/BbSelectPopover.vue.d.ts +1 -10
  558. package/dist/components/BbSelectPopover/BbSelectPopover.vue.js +6 -0
  559. package/dist/components/BbSelectPopover/BbSelectPopover.vue_vue_type_script_setup_true_lang.js +639 -0
  560. package/dist/components/BbSelectPopover/types.d.ts +197 -105
  561. package/dist/components/BbSlider/BbSlider.vue.d.ts +3 -6
  562. package/dist/components/BbSlider/BbSlider.vue.js +6 -0
  563. package/dist/components/BbSlider/BbSlider.vue_vue_type_script_setup_true_lang.js +166 -0
  564. package/dist/components/BbSlider/types.d.ts +44 -13
  565. package/dist/components/BbSmoothHeight/BbSmoothHeight.vue.d.ts +3 -1
  566. package/dist/components/BbSmoothHeight/BbSmoothHeight.vue.js +6 -0
  567. package/dist/components/BbSmoothHeight/BbSmoothHeight.vue_vue_type_script_setup_true_lang.js +79 -0
  568. package/dist/components/BbSmoothHeight/types.d.ts +17 -2
  569. package/dist/components/BbSpinner/BbSpinner.vue.d.ts +1 -1
  570. package/dist/components/BbSpinner/BbSpinner.vue.js +6 -0
  571. package/dist/components/BbSpinner/BbSpinner.vue_vue_type_script_setup_true_lang.js +30 -0
  572. package/dist/components/BbSpinner/types.d.ts +10 -3
  573. package/dist/components/BbSwitch/BbSwitch.vue.d.ts +5 -3
  574. package/dist/components/BbSwitch/BbSwitch.vue.js +6 -0
  575. package/dist/components/BbSwitch/BbSwitch.vue_vue_type_script_setup_true_lang.js +142 -0
  576. package/dist/components/BbSwitch/types.d.ts +3 -1
  577. package/dist/components/BbSwitchGroup/BbSwitchGroup.vue.d.ts +4 -14
  578. package/dist/components/BbSwitchGroup/BbSwitchGroup.vue.js +6 -0
  579. package/dist/components/BbSwitchGroup/BbSwitchGroup.vue_vue_type_script_setup_true_lang.js +190 -0
  580. package/dist/components/BbSwitchGroup/types.d.ts +3 -22
  581. package/dist/components/BbTable/BbTable.vue.d.ts +58 -31
  582. package/dist/components/BbTable/BbTable.vue.js +6 -0
  583. package/dist/components/BbTable/BbTable.vue_vue_type_script_setup_true_lang.js +900 -0
  584. package/dist/components/BbTable/types.d.ts +213 -37
  585. package/dist/components/BbTable/utils.d.ts +9 -1
  586. package/dist/components/BbTable/utils.js +53 -0
  587. package/dist/components/BbTabs/BbTabs.vue.d.ts +20 -0
  588. package/dist/components/BbTabs/BbTabs.vue.js +6 -0
  589. package/dist/components/BbTabs/BbTabs.vue_vue_type_script_setup_true_lang.js +64 -0
  590. package/dist/components/BbTabs/BbTabsList.vue.d.ts +19 -0
  591. package/dist/components/BbTabs/BbTabsList.vue.js +6 -0
  592. package/dist/components/BbTabs/BbTabsList.vue_vue_type_script_setup_true_lang.js +123 -0
  593. package/dist/components/BbTabs/BbTabsPanes.vue.d.ts +16 -0
  594. package/dist/components/BbTabs/BbTabsPanes.vue.js +6 -0
  595. package/dist/components/BbTabs/BbTabsPanes.vue_vue_type_script_setup_true_lang.js +35 -0
  596. package/dist/components/BbTabs/BbTabsRoot.vue.d.ts +20 -0
  597. package/dist/components/BbTabs/BbTabsRoot.vue.js +5 -0
  598. package/dist/components/BbTabs/BbTabsRoot.vue_vue_type_script_setup_true_lang.js +55 -0
  599. package/dist/components/BbTabs/types.d.ts +264 -0
  600. package/dist/components/BbTag/BbTag.vue.d.ts +19 -6
  601. package/dist/components/BbTag/BbTag.vue.js +6 -0
  602. package/dist/components/BbTag/BbTag.vue_vue_type_script_setup_true_lang.js +187 -0
  603. package/dist/components/BbTag/types.d.ts +55 -17
  604. package/dist/components/BbTextInput/BbTextInput.vue.d.ts +10 -1
  605. package/dist/components/BbTextInput/BbTextInput.vue.js +6 -0
  606. package/dist/components/BbTextInput/BbTextInput.vue_vue_type_script_setup_true_lang.js +195 -0
  607. package/dist/components/BbTextInput/types.d.ts +31 -4
  608. package/dist/components/BbTextarea/BbTextarea.vue.d.ts +10 -1
  609. package/dist/components/BbTextarea/BbTextarea.vue.js +6 -0
  610. package/dist/components/BbTextarea/BbTextarea.vue_vue_type_script_setup_true_lang.js +178 -0
  611. package/dist/components/BbTextarea/types.d.ts +33 -2
  612. package/dist/components/BbTimePicker/BbTimePicker.vue.d.ts +33 -0
  613. package/dist/components/BbTimePicker/BbTimePicker.vue.js +6 -0
  614. package/dist/components/BbTimePicker/BbTimePicker.vue_vue_type_script_setup_true_lang.js +244 -0
  615. package/dist/components/BbTimePicker/types.d.ts +133 -0
  616. package/dist/components/BbTimePickerInput/BbTimePickerInput.vue.d.ts +25 -0
  617. package/dist/components/BbTimePickerInput/BbTimePickerInput.vue.js +6 -0
  618. package/dist/components/BbTimePickerInput/BbTimePickerInput.vue_vue_type_script_setup_true_lang.js +157 -0
  619. package/dist/components/BbTimePickerInput/types.d.ts +174 -0
  620. package/dist/components/BbToast/BbToast.vue.d.ts +2 -3
  621. package/dist/components/BbToast/BbToast.vue.js +6 -0
  622. package/dist/components/BbToast/BbToast.vue_vue_type_script_setup_true_lang.js +39 -0
  623. package/dist/components/BbToast/BbToastMessage.vue.d.ts +17 -8
  624. package/dist/components/BbToast/BbToastMessage.vue.js +5 -0
  625. package/dist/components/BbToast/BbToastMessage.vue_vue_type_script_setup_true_lang.js +170 -0
  626. package/dist/components/BbToast/BbToastPortal.vue.d.ts +30 -0
  627. package/dist/components/BbToast/BbToastPortal.vue.js +5 -0
  628. package/dist/components/BbToast/BbToastPortal.vue_vue_type_script_setup_true_lang.js +19 -0
  629. package/dist/components/BbToast/BbToastRegion.vue.d.ts +8 -0
  630. package/dist/components/BbToast/BbToastRegion.vue.js +5 -0
  631. package/dist/components/BbToast/BbToastRegion.vue_vue_type_script_setup_true_lang.js +100 -0
  632. package/dist/components/BbToast/types.d.ts +69 -5
  633. package/dist/components/BbTooltip/BbTooltip.vue.d.ts +10 -3
  634. package/dist/components/BbTooltip/BbTooltip.vue.js +6 -0
  635. package/dist/components/BbTooltip/BbTooltip.vue_vue_type_script_setup_true_lang.js +160 -0
  636. package/dist/components/BbTooltip/types.d.ts +69 -11
  637. package/dist/components/BbTree/BbTree.vue.d.ts +28 -13
  638. package/dist/components/BbTree/BbTree.vue.js +6 -0
  639. package/dist/components/BbTree/BbTree.vue_vue_type_script_setup_true_lang.js +55 -0
  640. package/dist/components/BbTree/BbTreeLevel.vue.d.ts +19 -0
  641. package/dist/components/BbTree/BbTreeLevel.vue.js +5 -0
  642. package/dist/components/BbTree/BbTreeLevel.vue_vue_type_script_setup_true_lang.js +94 -0
  643. package/dist/components/BbTree/context.d.ts +17 -0
  644. package/dist/components/BbTree/context.js +4 -0
  645. package/dist/components/BbTree/types.d.ts +94 -41
  646. package/dist/components/ChipsBox/ChipsBox.vue.d.ts +2 -1
  647. package/dist/components/ChipsBox/ChipsBox.vue.js +5 -0
  648. package/dist/components/ChipsBox/ChipsBox.vue_vue_type_script_setup_true_lang.js +98 -0
  649. package/dist/components/ChipsBox/types.d.ts +12 -5
  650. package/dist/components/ClearableButton/ClearableButton.vue.d.ts +2 -1
  651. package/dist/components/ClearableButton/ClearableButton.vue.js +6 -0
  652. package/dist/components/ClearableButton/ClearableButton.vue_vue_type_script_setup_true_lang.js +19 -0
  653. package/dist/components/ClearableButton/types.d.ts +7 -1
  654. package/dist/components/CloseIcon/CloseButton.vue.d.ts +5 -0
  655. package/dist/components/CloseIcon/CloseButton.vue.js +7 -0
  656. package/dist/components/CloseIcon/CloseButton.vue_vue_type_script_setup_true_lang.js +23 -0
  657. package/dist/components/CloseIcon/types.d.ts +2 -0
  658. package/dist/components/CommaBox/CommaBox.vue.d.ts +2 -1
  659. package/dist/components/CommaBox/CommaBox.vue.js +6 -0
  660. package/dist/components/CommaBox/CommaBox.vue_vue_type_script_setup_true_lang.js +81 -0
  661. package/dist/components/CommaBox/types.d.ts +6 -7
  662. package/dist/components/CommonInputWrapper/CommonInputWrapper.vue.d.ts +19 -0
  663. package/dist/components/CommonInputWrapper/CommonInputWrapper.vue.js +6 -0
  664. package/dist/components/CommonInputWrapper/CommonInputWrapper.vue_vue_type_script_setup_true_lang.js +107 -0
  665. package/dist/components/CommonInputWrapper/types.d.ts +96 -0
  666. package/dist/components/CommonPopover/CommonPopover.vue.d.ts +9 -3
  667. package/dist/components/CommonPopover/CommonPopover.vue.js +6 -0
  668. package/dist/components/CommonPopover/CommonPopover.vue_vue_type_script_setup_true_lang.js +160 -0
  669. package/dist/components/CommonPopover/types.d.ts +65 -16
  670. package/dist/components/ErrorIcon/ErrorIcon.vue.d.ts +2 -0
  671. package/dist/components/ErrorIcon/ErrorIcon.vue.js +6 -0
  672. package/dist/components/ErrorIcon/ErrorIcon.vue_vue_type_script_setup_true_lang.js +16 -0
  673. package/dist/components/FlatListBox/FlatListBox.vue.d.ts +2 -5
  674. package/dist/components/FlatListBox/FlatListBox.vue.js +5 -0
  675. package/dist/components/FlatListBox/FlatListBox.vue_vue_type_script_setup_true_lang.js +167 -0
  676. package/dist/components/FlatListBox/types.d.ts +1 -1
  677. package/dist/components/GroupedListBox/GroupedListBox.vue.d.ts +2 -5
  678. package/dist/components/GroupedListBox/GroupedListBox.vue.js +5 -0
  679. package/dist/components/GroupedListBox/GroupedListBox.vue_vue_type_script_setup_true_lang.js +218 -0
  680. package/dist/components/ListBox/ListBox.vue.d.ts +3 -6
  681. package/dist/components/ListBox/ListBox.vue.js +5 -0
  682. package/dist/components/ListBox/ListBox.vue_vue_type_script_setup_true_lang.js +112 -0
  683. package/dist/components/ListBox/types.d.ts +1 -1
  684. package/dist/components/OptionsContainer/OptionsContainer.vue.d.ts +1 -0
  685. package/dist/components/OptionsContainer/OptionsContainer.vue.js +5 -0
  686. package/dist/components/OptionsContainer/OptionsContainer.vue_vue_type_script_setup_true_lang.js +52 -0
  687. package/dist/components/OptionsContainer/types.d.ts +14 -24
  688. package/dist/components/Transitions/ScaleFade.vue.d.ts +2 -2
  689. package/dist/components/Transitions/ScaleFade.vue.js +5 -0
  690. package/dist/components/Transitions/ScaleFade.vue_vue_type_script_setup_true_lang.js +47 -0
  691. package/dist/components/Transitions/Slide.vue.d.ts +15 -0
  692. package/dist/components/Transitions/Slide.vue.js +7 -0
  693. package/dist/components/Transitions/Slide.vue_vue_type_script_setup_true_lang.js +28 -0
  694. package/dist/components/WarningIcon/WarningIcon.vue.d.ts +5 -0
  695. package/dist/components/WarningIcon/WarningIcon.vue.js +6 -0
  696. package/dist/components/WarningIcon/WarningIcon.vue_vue_type_script_setup_true_lang.js +16 -0
  697. package/dist/components/WarningIcon/types.d.ts +3 -0
  698. package/dist/composables/__testResets.d.ts +1 -0
  699. package/dist/composables/useActiveInactiveState.d.ts +4 -0
  700. package/dist/composables/useActiveInactiveState.js +21 -0
  701. package/dist/composables/useBaseOptions.d.ts +3 -3
  702. package/dist/composables/useBaseOptions.js +31 -0
  703. package/dist/composables/useBbConfig.d.ts +8 -37
  704. package/dist/composables/useBbConfig.js +5 -0
  705. package/dist/composables/useBbDropdownContext.d.ts +89 -0
  706. package/dist/composables/useBbDropdownContext.js +46 -0
  707. package/dist/composables/useBbFormContext.d.ts +90 -0
  708. package/dist/composables/useBbFormContext.js +69 -0
  709. package/dist/composables/useBbTableContext.d.ts +195 -0
  710. package/dist/composables/useBbTableContext.js +208 -0
  711. package/dist/composables/useBbTabsContext.d.ts +111 -0
  712. package/dist/composables/useBbTabsContext.js +225 -0
  713. package/dist/composables/useBreakpoint.d.ts +13 -0
  714. package/dist/composables/useBreakpoint.js +39 -0
  715. package/dist/composables/useBroadcastChannelInstance.d.ts +1 -3
  716. package/dist/composables/useBroadcastChannelInstance.js +39 -0
  717. package/dist/composables/useCancelableFunction.js +37 -0
  718. package/dist/composables/useClosingInert.d.ts +28 -0
  719. package/dist/composables/useClosingInert.js +23 -0
  720. package/dist/composables/useCoherence.js +16 -0
  721. package/dist/composables/useConfirm.d.ts +278 -68
  722. package/dist/composables/useConfirm.js +130 -0
  723. package/dist/composables/useCountdown.js +42 -0
  724. package/dist/composables/useHashedWatcher.d.ts +17 -0
  725. package/dist/composables/useHashedWatcher.js +14 -0
  726. package/dist/composables/useId.d.ts +3 -2
  727. package/dist/composables/useIndexById.js +16 -0
  728. package/dist/composables/useInertiaPage.d.ts +10 -0
  729. package/dist/composables/useInertiaPage.js +8 -0
  730. package/dist/composables/useItemText.js +17 -0
  731. package/dist/composables/useItemValue.js +9 -0
  732. package/dist/composables/useItemsGetter.d.ts +1 -1
  733. package/dist/composables/useItemsGetter.js +30 -0
  734. package/dist/composables/useListboxFocus.js +66 -0
  735. package/dist/composables/useLocale.d.ts +1 -1
  736. package/dist/composables/useLocale.js +11 -0
  737. package/dist/composables/useLogger.d.ts +1 -1
  738. package/dist/composables/useLogger.js +10 -0
  739. package/dist/composables/useMinimalQueue.d.ts +1 -1
  740. package/dist/composables/useMobile.js +7 -0
  741. package/dist/composables/useOnFalsy.d.ts +2 -0
  742. package/dist/composables/useOnFalsy.js +9 -0
  743. package/dist/composables/useOnTruthy.d.ts +7 -0
  744. package/dist/composables/useOnTruthy.js +9 -0
  745. package/dist/composables/usePrefill.d.ts +2 -1
  746. package/dist/composables/usePrefill.js +24 -0
  747. package/dist/composables/useQuery.d.ts +15 -3
  748. package/dist/composables/useQuery.js +42 -0
  749. package/dist/composables/useRoute.js +11 -0
  750. package/dist/composables/useRouter.js +8 -0
  751. package/dist/composables/useSafeArea.d.ts +51 -0
  752. package/dist/composables/useSafeArea.js +16 -0
  753. package/dist/composables/useSegmentedFields.d.ts +104 -0
  754. package/dist/composables/useSegmentedFields.js +159 -0
  755. package/dist/composables/useTableWidthContext.d.ts +5 -0
  756. package/dist/composables/useTableWidthContext.js +42 -0
  757. package/dist/composables/useToast.d.ts +40 -70
  758. package/dist/composables/useToast.js +58 -0
  759. package/dist/composables/useTopLayer.d.ts +9 -0
  760. package/dist/composables/useTopLayer.js +7 -0
  761. package/dist/composables/useUntil.js +13 -0
  762. package/dist/composables/useViewportWidth.d.ts +17 -0
  763. package/dist/composables/useViewportWidth.js +6 -0
  764. package/dist/confirm-variants.d.ts +17 -0
  765. package/dist/deprecation/ai-deprecations.json.d.ts +784 -0
  766. package/dist/deprecation/ai-deprecations.json.js +4 -0
  767. package/dist/deprecation/removedProps.d.ts +3 -0
  768. package/dist/deprecation/removedProps.js +13 -0
  769. package/dist/directives/bbColor.d.ts +65 -0
  770. package/dist/directives/bbColor.js +24 -0
  771. package/dist/directives/bbDate.d.ts +66 -0
  772. package/dist/directives/bbDate.js +24 -0
  773. package/dist/directives/bbDropdown.d.ts +15 -11
  774. package/dist/directives/bbDropdown.js +23 -0
  775. package/dist/directives/bbTime.d.ts +64 -0
  776. package/dist/directives/bbTime.js +24 -0
  777. package/dist/directives/bbTooltip.d.ts +16 -11
  778. package/dist/directives/bbTooltip.js +24 -0
  779. package/dist/directives/createPopoverDirective.js +54 -0
  780. package/dist/dropdown-item-variants.d.ts +17 -0
  781. package/dist/i18n/index.d.ts +51 -3
  782. package/dist/i18n/index.js +27 -0
  783. package/dist/i18n/locales/cs.json +115 -0
  784. package/dist/i18n/locales/da.json +115 -0
  785. package/dist/i18n/locales/de.json +115 -0
  786. package/dist/i18n/locales/el.json +115 -0
  787. package/dist/i18n/locales/en.json +115 -0
  788. package/dist/i18n/locales/es.json +115 -0
  789. package/dist/i18n/locales/fi.json +115 -0
  790. package/dist/i18n/locales/fr.json +115 -0
  791. package/dist/i18n/locales/hu.json +115 -0
  792. package/dist/i18n/locales/it.json +115 -0
  793. package/dist/i18n/locales/ja.json +115 -0
  794. package/dist/i18n/locales/ko.json +115 -0
  795. package/dist/i18n/locales/nb.json +115 -0
  796. package/dist/i18n/locales/nl.json +115 -0
  797. package/dist/i18n/locales/pl.json +115 -0
  798. package/dist/i18n/locales/pt.json +115 -0
  799. package/dist/i18n/locales/ro.json +115 -0
  800. package/dist/i18n/locales/ru.json +115 -0
  801. package/dist/i18n/locales/sv.json +115 -0
  802. package/dist/i18n/locales/tr.json +115 -0
  803. package/dist/i18n/locales/uk.json +115 -0
  804. package/dist/i18n/locales/zh-cn.json +115 -0
  805. package/dist/icons-whitelist.d.ts +8 -0
  806. package/dist/index.d.ts +96 -79
  807. package/dist/index.js +76 -82
  808. package/dist/indicator-variants.d.ts +20 -0
  809. package/dist/llms-full.txt +79703 -0
  810. package/dist/llms-medium.txt +1514 -0
  811. package/dist/llms.txt +105 -0
  812. package/dist/locale-blueprint.json +141 -0
  813. package/dist/locale-registry.d.ts +37 -0
  814. package/dist/nuxt-module.d.ts +3 -0
  815. package/dist/nuxt.js +19 -0
  816. package/dist/plugin.d.ts +4 -0
  817. package/dist/plugin.js +22 -0
  818. package/dist/reset.css +1 -0
  819. package/dist/reset.d.ts +0 -0
  820. package/dist/runtime/nuxt-plugin.d.ts +2 -0
  821. package/dist/runtime/nuxt-plugin.js +24 -0
  822. package/dist/styles.css +2 -0
  823. package/dist/styles.d.ts +0 -0
  824. package/dist/toast-variants.d.ts +20 -0
  825. package/dist/tooltip-variants.d.ts +17 -0
  826. package/dist/types/ActionButton.d.ts +32 -0
  827. package/dist/types/AlertVariant.d.ts +16 -0
  828. package/dist/types/BadgeVariant.d.ts +16 -0
  829. package/dist/types/ButtonVariant.d.ts +17 -0
  830. package/dist/types/Classes.d.ts +1 -1
  831. package/dist/types/ColumnName.d.ts +1 -1
  832. package/dist/types/CommonProps.d.ts +68 -277
  833. package/dist/types/Config.d.ts +84 -0
  834. package/dist/types/ConfirmVariant.d.ts +15 -0
  835. package/dist/types/DropdownItemVariant.d.ts +18 -0
  836. package/dist/types/Icon.d.ts +5 -7
  837. package/dist/types/IndicatorVariant.d.ts +16 -0
  838. package/dist/types/InputDirection.d.ts +15 -0
  839. package/dist/types/ItemAccessor.d.ts +21 -0
  840. package/dist/types/Placement.d.ts +6 -0
  841. package/dist/types/ResponsiveSize.d.ts +20 -0
  842. package/dist/types/SizeScale.d.ts +8 -0
  843. package/dist/types/ToastVariant.d.ts +17 -0
  844. package/dist/types/TooltipVariant.d.ts +18 -0
  845. package/dist/utilities/functions/bytesToUnit.d.ts +2 -0
  846. package/dist/utilities/functions/bytesToUnit.js +18 -0
  847. package/dist/utilities/functions/clampPrecision.js +10 -0
  848. package/dist/utilities/functions/convertDateValue.d.ts +23 -10
  849. package/dist/utilities/functions/convertDateValue.js +12 -0
  850. package/dist/utilities/functions/deburr.js +5 -0
  851. package/dist/utilities/functions/empty.js +5 -0
  852. package/dist/utilities/functions/flattenTree.d.ts +1 -1
  853. package/dist/utilities/functions/hash.js +5 -0
  854. package/dist/utilities/functions/isDateDisabled.d.ts +1 -0
  855. package/dist/utilities/functions/isDateDisabled.js +20 -0
  856. package/dist/utilities/functions/isEqual.js +5 -0
  857. package/dist/utilities/functions/isNotEmpty.js +5 -0
  858. package/dist/utilities/functions/matchAnyKey.d.ts +1 -1
  859. package/dist/utilities/functions/matchAnyKey.js +15 -0
  860. package/dist/utilities/functions/parseSize.d.ts +1 -1
  861. package/dist/utilities/functions/parseSize.js +15 -0
  862. package/dist/utilities/functions/percentage.js +11 -0
  863. package/dist/utilities/functions/pipe.d.ts +1 -1
  864. package/dist/utilities/functions/reject.d.ts +25 -0
  865. package/dist/utilities/functions/reject.js +28 -0
  866. package/dist/utilities/functions/resolveEnumProp.d.ts +19 -0
  867. package/dist/utilities/functions/resolveEnumProp.js +5 -0
  868. package/dist/utilities/functions/slotKey.d.ts +13 -0
  869. package/dist/utilities/functions/slotKey.js +4 -0
  870. package/dist/utilities/functions/sort.d.ts +2 -2
  871. package/dist/utilities/functions/sort.js +19 -0
  872. package/dist/utilities/functions/throttle.js +5 -0
  873. package/dist/utilities/functions/waitFor.d.ts +9 -2
  874. package/dist/utilities/functions/waitFor.js +14 -0
  875. package/dist/utilities/functions/warnRemovedAttrs.d.ts +11 -0
  876. package/dist/utilities/functions/warnRemovedAttrs.js +20 -0
  877. package/dist/utilities/functions/when.js +5 -0
  878. package/dist/utilities/misc/iconsInjectionKey.d.ts +15 -0
  879. package/dist/utilities/misc/iconsInjectionKey.js +4 -0
  880. package/dist/utilities/misc/transitions.d.ts +5 -0
  881. package/dist/utilities/misc/transitions.js +8 -0
  882. package/dist/utils/injectLibraryStyles.d.ts +6 -0
  883. package/dist/utils/injectLibraryStyles.js +38 -0
  884. package/dist/validated/BbCheckbox.vue.d.ts +29 -0
  885. package/dist/validated/BbCheckbox.vue.js +5 -0
  886. package/dist/validated/BbCheckbox.vue_vue_type_script_setup_true_lang.js +75 -0
  887. package/dist/validated/BbCheckboxGroup.vue.d.ts +34 -0
  888. package/dist/validated/BbCheckboxGroup.vue.js +5 -0
  889. package/dist/validated/BbCheckboxGroup.vue_vue_type_script_setup_true_lang.js +82 -0
  890. package/dist/validated/BbColorInput.vue.d.ts +36 -0
  891. package/dist/validated/BbColorInput.vue.js +5 -0
  892. package/dist/validated/BbColorInput.vue_vue_type_script_setup_true_lang.js +71 -0
  893. package/dist/validated/BbDatePickerInput.vue.d.ts +41 -0
  894. package/dist/validated/BbDatePickerInput.vue.js +5 -0
  895. package/dist/validated/BbDatePickerInput.vue_vue_type_script_setup_true_lang.js +90 -0
  896. package/dist/validated/BbDropzone.vue.d.ts +24 -0
  897. package/dist/validated/BbDropzone.vue.js +5 -0
  898. package/dist/validated/BbDropzone.vue_vue_type_script_setup_true_lang.js +45 -0
  899. package/dist/validated/BbForm.vue.d.ts +28 -0
  900. package/dist/validated/BbForm.vue.js +5 -0
  901. package/dist/validated/BbForm.vue_vue_type_script_setup_true_lang.js +42 -0
  902. package/dist/validated/BbNumberInput.vue.d.ts +36 -0
  903. package/dist/validated/BbNumberInput.vue.js +5 -0
  904. package/dist/validated/BbNumberInput.vue_vue_type_script_setup_true_lang.js +72 -0
  905. package/dist/validated/BbRadioGroup.vue.d.ts +34 -0
  906. package/dist/validated/BbRadioGroup.vue.js +5 -0
  907. package/dist/validated/BbRadioGroup.vue_vue_type_script_setup_true_lang.js +78 -0
  908. package/dist/validated/BbRating.vue.d.ts +30 -0
  909. package/dist/validated/BbRating.vue.js +5 -0
  910. package/dist/validated/BbRating.vue_vue_type_script_setup_true_lang.js +63 -0
  911. package/dist/validated/BbSelect.vue.d.ts +46 -0
  912. package/dist/validated/BbSelect.vue.js +5 -0
  913. package/dist/validated/BbSelect.vue_vue_type_script_setup_true_lang.js +109 -0
  914. package/dist/validated/BbSlider.vue.d.ts +36 -0
  915. package/dist/validated/BbSlider.vue.js +5 -0
  916. package/dist/validated/BbSlider.vue_vue_type_script_setup_true_lang.js +69 -0
  917. package/dist/validated/BbSwitch.vue.d.ts +29 -0
  918. package/dist/validated/BbSwitch.vue.js +5 -0
  919. package/dist/validated/BbSwitch.vue_vue_type_script_setup_true_lang.js +75 -0
  920. package/dist/validated/BbSwitchGroup.vue.d.ts +34 -0
  921. package/dist/validated/BbSwitchGroup.vue.js +5 -0
  922. package/dist/validated/BbSwitchGroup.vue_vue_type_script_setup_true_lang.js +82 -0
  923. package/dist/validated/BbTag.vue.d.ts +36 -0
  924. package/dist/validated/BbTag.vue.js +5 -0
  925. package/dist/validated/BbTag.vue_vue_type_script_setup_true_lang.js +72 -0
  926. package/dist/validated/BbTextInput.vue.d.ts +36 -0
  927. package/dist/validated/BbTextInput.vue.js +5 -0
  928. package/dist/validated/BbTextInput.vue_vue_type_script_setup_true_lang.js +72 -0
  929. package/dist/validated/BbTextarea.vue.d.ts +36 -0
  930. package/dist/validated/BbTextarea.vue.js +5 -0
  931. package/dist/validated/BbTextarea.vue_vue_type_script_setup_true_lang.js +70 -0
  932. package/dist/validated/BbTimePickerInput.vue.d.ts +37 -0
  933. package/dist/validated/BbTimePickerInput.vue.js +5 -0
  934. package/dist/validated/BbTimePickerInput.vue_vue_type_script_setup_true_lang.js +81 -0
  935. package/dist/validated/index.d.ts +29 -0
  936. package/dist/validated/useValidatedField.d.ts +93 -0
  937. package/dist/validated/useValidatedField.js +51 -0
  938. package/dist/validated.js +21 -0
  939. package/dist/vite-plugin.d.ts +261 -0
  940. package/dist/vite.js +603 -0
  941. package/llms.txt +107 -0
  942. package/package.json +181 -60
  943. package/scripts/lib/__fixtures__/validated-manifest.json +65 -0
  944. package/scripts/lib/ensure-manifest.mjs +39 -0
  945. package/scripts/lib/eslint-plugin-autofix.node.test.mjs +109 -0
  946. package/scripts/lib/eslint-plugin-recommended.node.test.mjs +87 -0
  947. package/scripts/lib/eslint-plugin-slots.node.test.mjs +271 -0
  948. package/scripts/lib/eslint-plugin.mjs +702 -0
  949. package/scripts/lib/eslint-plugin.node.test.mjs +193 -0
  950. package/scripts/lib/html-attributes.mjs +191 -0
  951. package/scripts/lib/mcp-config.mjs +126 -0
  952. package/scripts/lib/migrate-fix.mjs +115 -0
  953. package/scripts/lib/validate-bb-markup.mjs +488 -0
  954. package/dist/ai/BaseButton.md +0 -449
  955. package/dist/ai/BaseCheckbox.md +0 -512
  956. package/dist/ai/BaseCheckboxGroup.md +0 -597
  957. package/dist/ai/BaseColorInput.md +0 -461
  958. package/dist/ai/BaseDatePicker.md +0 -739
  959. package/dist/ai/BaseDatePickerInput.md +0 -1517
  960. package/dist/ai/BaseDialog.md +0 -610
  961. package/dist/ai/BaseInputContainer.md +0 -570
  962. package/dist/ai/BaseNumberInput.md +0 -509
  963. package/dist/ai/BaseRadio.md +0 -405
  964. package/dist/ai/BaseRadioGroup.md +0 -535
  965. package/dist/ai/BaseRating.md +0 -489
  966. package/dist/ai/BaseSelect.md +0 -1742
  967. package/dist/ai/BaseSlider.md +0 -871
  968. package/dist/ai/BaseSwitch.md +0 -322
  969. package/dist/ai/BaseSwitchGroup.md +0 -298
  970. package/dist/ai/BaseTag.md +0 -623
  971. package/dist/ai/BaseTextInput.md +0 -392
  972. package/dist/ai/BaseTextarea.md +0 -398
  973. package/dist/ai/BbChip.md +0 -147
  974. package/dist/ai/BbIntersection.md +0 -120
  975. package/dist/ai/BbRatio.md +0 -61
  976. package/dist/ai/BbRows.md +0 -307
  977. package/dist/ai/BbTab.md +0 -950
  978. package/dist/ai/CommonInputInnerContainer.md +0 -414
  979. package/dist/ai/CommonInputOuterContainer.md +0 -55
  980. package/dist/components/BaseButton/BaseButton.vue.d.ts +0 -14
  981. package/dist/components/BaseButton/types.d.ts +0 -159
  982. package/dist/components/BaseCheckbox/BaseCheckbox.vue.d.ts +0 -39
  983. package/dist/components/BaseCheckbox/types.d.ts +0 -213
  984. package/dist/components/BaseCheckboxGroup/BaseCheckboxGroup.vue.d.ts +0 -30
  985. package/dist/components/BaseCheckboxGroup/types.d.ts +0 -282
  986. package/dist/components/BaseColorInput/BaseColorInput.vue.d.ts +0 -35
  987. package/dist/components/BaseColorInput/ColorPalette.vue.d.ts +0 -13
  988. package/dist/components/BaseColorInput/types.d.ts +0 -233
  989. package/dist/components/BaseDatePicker/BaseDatePickerHeader.vue.d.ts +0 -15
  990. package/dist/components/BaseDatePicker/BaseDatePickerInputDaySelector.vue.d.ts +0 -58
  991. package/dist/components/BaseDatePicker/BaseDatePickerMonthSelector.vue.d.ts +0 -12
  992. package/dist/components/BaseDatePicker/BaseDatePickerYearSelector.vue.d.ts +0 -12
  993. package/dist/components/BaseDatePicker/types.d.ts +0 -100
  994. package/dist/components/BaseDatePickerInput/BaseDatePickerInput.vue.d.ts +0 -26
  995. package/dist/components/BaseDatePickerInput/types.d.ts +0 -206
  996. package/dist/components/BaseDialog/BaseDialog.vue.d.ts +0 -37
  997. package/dist/components/BaseDialog/types.d.ts +0 -180
  998. package/dist/components/BaseInputContainer/BaseInputContainer.vue.d.ts +0 -18
  999. package/dist/components/BaseInputContainer/types.d.ts +0 -126
  1000. package/dist/components/BaseNumberInput/BaseNumberInput.vue.d.ts +0 -46
  1001. package/dist/components/BaseNumberInput/types.d.ts +0 -191
  1002. package/dist/components/BaseRadio/BaseRadio.vue.d.ts +0 -31
  1003. package/dist/components/BaseRadio/types.d.ts +0 -173
  1004. package/dist/components/BaseRadioGroup/BaseRadioGroup.vue.d.ts +0 -30
  1005. package/dist/components/BaseRadioGroup/types.d.ts +0 -240
  1006. package/dist/components/BaseRating/BaseRating.vue.d.ts +0 -35
  1007. package/dist/components/BaseRating/types.d.ts +0 -144
  1008. package/dist/components/BaseSelect/BaseSelect.vue.d.ts +0 -28
  1009. package/dist/components/BaseSelect/types.d.ts +0 -470
  1010. package/dist/components/BaseSlider/BaseSlider.vue.d.ts +0 -38
  1011. package/dist/components/BaseSlider/types.d.ts +0 -201
  1012. package/dist/components/BaseSwitch/BaseSwitch.vue.d.ts +0 -34
  1013. package/dist/components/BaseSwitch/types.d.ts +0 -25
  1014. package/dist/components/BaseSwitchGroup/BaseSwitchGroup.vue.d.ts +0 -30
  1015. package/dist/components/BaseSwitchGroup/types.d.ts +0 -8
  1016. package/dist/components/BaseTag/BaseTag.vue.d.ts +0 -37
  1017. package/dist/components/BaseTag/types.d.ts +0 -136
  1018. package/dist/components/BaseTextInput/BaseTextInput.vue.d.ts +0 -33
  1019. package/dist/components/BaseTextInput/types.d.ts +0 -166
  1020. package/dist/components/BaseTextarea/BaseTextarea.vue.d.ts +0 -31
  1021. package/dist/components/BaseTextarea/types.d.ts +0 -151
  1022. package/dist/components/BbChip/BbChip.vue.d.ts +0 -17
  1023. package/dist/components/BbChip/types.d.ts +0 -23
  1024. package/dist/components/BbIntersection/BbIntersection.vue.d.ts +0 -23
  1025. package/dist/components/BbIntersection/types.d.ts +0 -36
  1026. package/dist/components/BbRatio/BbRatio.vue.d.ts +0 -14
  1027. package/dist/components/BbRatio/types.d.ts +0 -15
  1028. package/dist/components/BbRows/BbRows.vue.d.ts +0 -62
  1029. package/dist/components/BbRows/types.d.ts +0 -21
  1030. package/dist/components/BbTab/BbTab.vue.d.ts +0 -27
  1031. package/dist/components/BbTab/types.d.ts +0 -186
  1032. package/dist/components/CommonInputInnerContainer/CommonInputInnerContainer.vue.d.ts +0 -15
  1033. package/dist/components/CommonInputInnerContainer/types.d.ts +0 -47
  1034. package/dist/components/CommonInputOuterContainer/CommonInputOuterContainer.vue.d.ts +0 -11
  1035. package/dist/components/CommonInputOuterContainer/types.d.ts +0 -16
  1036. package/dist/composables/useModalsState.d.ts +0 -5
  1037. package/dist/composables/useQueue.d.ts +0 -58
  1038. package/dist/composables/useWizard.d.ts +0 -85
  1039. package/dist/i18n/en.d.ts +0 -67
  1040. package/dist/i18n/it.d.ts +0 -67
  1041. package/dist/index.css +0 -2
  1042. package/dist/index100.js +0 -6
  1043. package/dist/index101.js +0 -300
  1044. package/dist/index102.js +0 -16
  1045. package/dist/index103.js +0 -16
  1046. package/dist/index104.js +0 -27
  1047. package/dist/index109.js +0 -19
  1048. package/dist/index11.js +0 -42
  1049. package/dist/index110.js +0 -12
  1050. package/dist/index111.js +0 -19
  1051. package/dist/index112.js +0 -25
  1052. package/dist/index114.js +0 -7
  1053. package/dist/index115.js +0 -241
  1054. package/dist/index116.js +0 -5
  1055. package/dist/index117.js +0 -42
  1056. package/dist/index118.js +0 -5
  1057. package/dist/index119.js +0 -53
  1058. package/dist/index120.js +0 -5
  1059. package/dist/index121.js +0 -32
  1060. package/dist/index122.js +0 -5
  1061. package/dist/index124.js +0 -52
  1062. package/dist/index125.js +0 -5
  1063. package/dist/index126.js +0 -223
  1064. package/dist/index128.js +0 -6
  1065. package/dist/index129.js +0 -162
  1066. package/dist/index13.js +0 -92
  1067. package/dist/index130.js +0 -25
  1068. package/dist/index131.js +0 -51
  1069. package/dist/index132.js +0 -5
  1070. package/dist/index133.js +0 -607
  1071. package/dist/index135.js +0 -6
  1072. package/dist/index136.js +0 -14
  1073. package/dist/index137.js +0 -153
  1074. package/dist/index139.js +0 -6
  1075. package/dist/index14.js +0 -306
  1076. package/dist/index140.js +0 -224
  1077. package/dist/index141.js +0 -5
  1078. package/dist/index143.js +0 -128
  1079. package/dist/index145.js +0 -6
  1080. package/dist/index146.js +0 -8
  1081. package/dist/index147.js +0 -182
  1082. package/dist/index149.js +0 -6
  1083. package/dist/index15.js +0 -10
  1084. package/dist/index151.js +0 -4
  1085. package/dist/index152.js +0 -95
  1086. package/dist/index154.js +0 -6
  1087. package/dist/index155.js +0 -168
  1088. package/dist/index157.js +0 -6
  1089. package/dist/index158.js +0 -145
  1090. package/dist/index16.js +0 -59
  1091. package/dist/index160.js +0 -6
  1092. package/dist/index161.js +0 -53
  1093. package/dist/index163.js +0 -6
  1094. package/dist/index164.js +0 -16
  1095. package/dist/index166.js +0 -35
  1096. package/dist/index168.js +0 -6
  1097. package/dist/index169.js +0 -89
  1098. package/dist/index171.js +0 -6
  1099. package/dist/index172.js +0 -82
  1100. package/dist/index174.js +0 -6
  1101. package/dist/index175.js +0 -38
  1102. package/dist/index176.js +0 -461
  1103. package/dist/index177.js +0 -28
  1104. package/dist/index178.js +0 -66
  1105. package/dist/index18.js +0 -35
  1106. package/dist/index180.js +0 -162
  1107. package/dist/index181.js +0 -5
  1108. package/dist/index182.js +0 -217
  1109. package/dist/index183.js +0 -5
  1110. package/dist/index184.js +0 -112
  1111. package/dist/index185.js +0 -5
  1112. package/dist/index186.js +0 -459
  1113. package/dist/index188.js +0 -6
  1114. package/dist/index19.js +0 -4
  1115. package/dist/index192.js +0 -268
  1116. package/dist/index194.js +0 -6
  1117. package/dist/index195.js +0 -124
  1118. package/dist/index197.js +0 -6
  1119. package/dist/index198.js +0 -174
  1120. package/dist/index2.js +0 -20
  1121. package/dist/index20.js +0 -9
  1122. package/dist/index200.js +0 -6
  1123. package/dist/index201.js +0 -224
  1124. package/dist/index203.js +0 -6
  1125. package/dist/index204.js +0 -135
  1126. package/dist/index206.js +0 -6
  1127. package/dist/index207.js +0 -5
  1128. package/dist/index208.js +0 -170
  1129. package/dist/index21.js +0 -35
  1130. package/dist/index210.js +0 -6
  1131. package/dist/index211.js +0 -37
  1132. package/dist/index213.js +0 -6
  1133. package/dist/index214.js +0 -63
  1134. package/dist/index216.js +0 -6
  1135. package/dist/index217.js +0 -74
  1136. package/dist/index219.js +0 -6
  1137. package/dist/index22.js +0 -6
  1138. package/dist/index220.js +0 -65
  1139. package/dist/index222.js +0 -6
  1140. package/dist/index223.js +0 -67
  1141. package/dist/index225.js +0 -6
  1142. package/dist/index226.js +0 -41
  1143. package/dist/index228.js +0 -6
  1144. package/dist/index229.js +0 -10
  1145. package/dist/index23.js +0 -7
  1146. package/dist/index230.js +0 -22
  1147. package/dist/index232.js +0 -8
  1148. package/dist/index233.js +0 -297
  1149. package/dist/index235.js +0 -6
  1150. package/dist/index236.js +0 -47
  1151. package/dist/index237.js +0 -165
  1152. package/dist/index239.js +0 -6
  1153. package/dist/index24.js +0 -9
  1154. package/dist/index241.js +0 -159
  1155. package/dist/index243.js +0 -6
  1156. package/dist/index244.js +0 -134
  1157. package/dist/index246.js +0 -6
  1158. package/dist/index247.js +0 -167
  1159. package/dist/index249.js +0 -6
  1160. package/dist/index25.js +0 -24
  1161. package/dist/index250.js +0 -147
  1162. package/dist/index252.js +0 -6
  1163. package/dist/index253.js +0 -35
  1164. package/dist/index255.js +0 -6
  1165. package/dist/index256.js +0 -65
  1166. package/dist/index258.js +0 -6
  1167. package/dist/index259.js +0 -19
  1168. package/dist/index260.js +0 -5
  1169. package/dist/index261.js +0 -160
  1170. package/dist/index263.js +0 -6
  1171. package/dist/index264.js +0 -60
  1172. package/dist/index266.js +0 -6
  1173. package/dist/index267.js +0 -134
  1174. package/dist/index269.js +0 -6
  1175. package/dist/index27.js +0 -4
  1176. package/dist/index271.js +0 -206
  1177. package/dist/index273.js +0 -6
  1178. package/dist/index274.js +0 -85
  1179. package/dist/index275.js +0 -5
  1180. package/dist/index276.js +0 -55
  1181. package/dist/index277.js +0 -5
  1182. package/dist/index278.js +0 -164
  1183. package/dist/index28.js +0 -8
  1184. package/dist/index280.js +0 -6
  1185. package/dist/index281.js +0 -145
  1186. package/dist/index283.js +0 -6
  1187. package/dist/index284.js +0 -11
  1188. package/dist/index285.js +0 -200
  1189. package/dist/index287.js +0 -6
  1190. package/dist/index288.js +0 -241
  1191. package/dist/index29.js +0 -7
  1192. package/dist/index290.js +0 -6
  1193. package/dist/index291.js +0 -21
  1194. package/dist/index293.js +0 -6
  1195. package/dist/index294.js +0 -125
  1196. package/dist/index296.js +0 -6
  1197. package/dist/index297.js +0 -161
  1198. package/dist/index299.js +0 -6
  1199. package/dist/index30.js +0 -118
  1200. package/dist/index300.js +0 -127
  1201. package/dist/index302.js +0 -6
  1202. package/dist/index303.js +0 -20
  1203. package/dist/index305.js +0 -6
  1204. package/dist/index306.js +0 -116
  1205. package/dist/index307.js +0 -5
  1206. package/dist/index308.js +0 -507
  1207. package/dist/index31.js +0 -10
  1208. package/dist/index310.js +0 -6
  1209. package/dist/index311.js +0 -196
  1210. package/dist/index313.js +0 -6
  1211. package/dist/index314.js +0 -142
  1212. package/dist/index316.js +0 -6
  1213. package/dist/index317.js +0 -134
  1214. package/dist/index319.js +0 -6
  1215. package/dist/index32.js +0 -28
  1216. package/dist/index320.js +0 -162
  1217. package/dist/index322.js +0 -6
  1218. package/dist/index323.js +0 -319
  1219. package/dist/index325.js +0 -6
  1220. package/dist/index326.js +0 -40
  1221. package/dist/index327.js +0 -43
  1222. package/dist/index328.js +0 -665
  1223. package/dist/index33.js +0 -5
  1224. package/dist/index330.js +0 -6
  1225. package/dist/index331.js +0 -155
  1226. package/dist/index333.js +0 -6
  1227. package/dist/index334.js +0 -142
  1228. package/dist/index336.js +0 -6
  1229. package/dist/index337.js +0 -155
  1230. package/dist/index339.js +0 -6
  1231. package/dist/index34.js +0 -112
  1232. package/dist/index340.js +0 -58
  1233. package/dist/index341.js +0 -5
  1234. package/dist/index342.js +0 -20
  1235. package/dist/index344.js +0 -6
  1236. package/dist/index345.js +0 -142
  1237. package/dist/index347.js +0 -6
  1238. package/dist/index349.js +0 -109
  1239. package/dist/index351.js +0 -6
  1240. package/dist/index352.js +0 -55
  1241. package/dist/index353.js +0 -24
  1242. package/dist/index354.js +0 -23
  1243. package/dist/index355.js +0 -839
  1244. package/dist/index356.js +0 -474
  1245. package/dist/index357.js +0 -52
  1246. package/dist/index358.js +0 -7
  1247. package/dist/index36.js +0 -6
  1248. package/dist/index38.js +0 -63
  1249. package/dist/index39.js +0 -63
  1250. package/dist/index40.js +0 -9
  1251. package/dist/index42.js +0 -8
  1252. package/dist/index43.js +0 -179
  1253. package/dist/index44.js +0 -21
  1254. package/dist/index46.js +0 -385
  1255. package/dist/index48.js +0 -6
  1256. package/dist/index49.js +0 -33
  1257. package/dist/index5.js +0 -34
  1258. package/dist/index50.js +0 -12
  1259. package/dist/index51.js +0 -8
  1260. package/dist/index52.js +0 -106
  1261. package/dist/index53.js +0 -330
  1262. package/dist/index54.js +0 -97
  1263. package/dist/index55.js +0 -328
  1264. package/dist/index56.js +0 -28
  1265. package/dist/index57.js +0 -102
  1266. package/dist/index58.js +0 -157
  1267. package/dist/index6.js +0 -38
  1268. package/dist/index60.js +0 -6
  1269. package/dist/index61.js +0 -131
  1270. package/dist/index62.js +0 -5
  1271. package/dist/index65.js +0 -35
  1272. package/dist/index66.js +0 -26
  1273. package/dist/index68.js +0 -6
  1274. package/dist/index69.js +0 -54
  1275. package/dist/index7.js +0 -58
  1276. package/dist/index71.js +0 -6
  1277. package/dist/index72.js +0 -14
  1278. package/dist/index74.js +0 -6
  1279. package/dist/index75.js +0 -159
  1280. package/dist/index77.js +0 -6
  1281. package/dist/index78.js +0 -4
  1282. package/dist/index79.js +0 -4
  1283. package/dist/index80.js +0 -54
  1284. package/dist/index81.js +0 -5
  1285. package/dist/index82.js +0 -5
  1286. package/dist/index83.js +0 -141
  1287. package/dist/index85.js +0 -6
  1288. package/dist/index86.js +0 -65
  1289. package/dist/index88.js +0 -6
  1290. package/dist/index89.js +0 -30
  1291. package/dist/index9.js +0 -11
  1292. package/dist/index90.js +0 -19
  1293. package/dist/index91.js +0 -17
  1294. package/dist/index92.js +0 -9
  1295. package/dist/index93.js +0 -34
  1296. package/dist/index95.js +0 -16
  1297. package/dist/index96.js +0 -10
  1298. package/dist/index97.js +0 -18
  1299. package/dist/index98.js +0 -189
  1300. package/dist/types/VoidHtmlElements.d.ts +0 -1
  1301. package/dist/utilities/functions/add.d.ts +0 -1
  1302. package/dist/utilities/functions/booleanishToBoolean.d.ts +0 -6
  1303. package/dist/utilities/functions/capitalize.d.ts +0 -4
  1304. package/dist/utilities/functions/cloneDeep.d.ts +0 -1
  1305. package/dist/utilities/functions/debounce.d.ts +0 -1
  1306. package/dist/utilities/functions/drop.d.ts +0 -1
  1307. package/dist/utilities/functions/exceedsPrecision.d.ts +0 -1
  1308. package/dist/utilities/functions/findRight.d.ts +0 -4
  1309. package/dist/utilities/functions/findRightIndex.d.ts +0 -4
  1310. package/dist/utilities/functions/flow.d.ts +0 -1
  1311. package/dist/utilities/functions/getHueFromRGB.d.ts +0 -9
  1312. package/dist/utilities/functions/groupBy.d.ts +0 -6
  1313. package/dist/utilities/functions/gt.d.ts +0 -7
  1314. package/dist/utilities/functions/hexToRGB.d.ts +0 -7
  1315. package/dist/utilities/functions/hslToHex.d.ts +0 -1
  1316. package/dist/utilities/functions/includes.d.ts +0 -1
  1317. package/dist/utilities/functions/initial.d.ts +0 -1
  1318. package/dist/utilities/functions/isCssColor.d.ts +0 -5
  1319. package/dist/utilities/functions/lt.d.ts +0 -7
  1320. package/dist/utilities/functions/makeUrl.d.ts +0 -1
  1321. package/dist/utilities/functions/mapKeys.d.ts +0 -5
  1322. package/dist/utilities/functions/mapValues.d.ts +0 -1
  1323. package/dist/utilities/functions/matchesPropertyInsensitive.d.ts +0 -1
  1324. package/dist/utilities/functions/max.d.ts +0 -2
  1325. package/dist/utilities/functions/mean.d.ts +0 -4
  1326. package/dist/utilities/functions/merge.d.ts +0 -11
  1327. package/dist/utilities/functions/millisecondsTo.d.ts +0 -1
  1328. package/dist/utilities/functions/negate.d.ts +0 -4
  1329. package/dist/utilities/functions/normalizeItemGroups.d.ts +0 -13
  1330. package/dist/utilities/functions/omit.d.ts +0 -2
  1331. package/dist/utilities/functions/overEvery.d.ts +0 -4
  1332. package/dist/utilities/functions/pick.d.ts +0 -1
  1333. package/dist/utilities/functions/replace.d.ts +0 -1
  1334. package/dist/utilities/functions/replaceInTree.d.ts +0 -4
  1335. package/dist/utilities/functions/retry.d.ts +0 -5
  1336. package/dist/utilities/functions/roundToTheNearest.d.ts +0 -8
  1337. package/dist/utilities/functions/set.d.ts +0 -15
  1338. package/dist/utilities/functions/stub.d.ts +0 -6
  1339. package/dist/utilities/functions/transposePercent.d.ts +0 -9
  1340. package/dist/utilities/functions/tryTo.d.ts +0 -2
  1341. package/dist/utilities/functions/uniqBy.d.ts +0 -1
  1342. /package/dist/{index64.js → _virtual/_plugin-vue_export-helper.js} +0 -0
  1343. /package/dist/components/{BaseButton → BbBaseButton}/RouterComponent.vue.d.ts +0 -0
  1344. /package/dist/components/{BaseDatePicker/BaseDatePicker.vue.d.ts → BbBaseDatePicker/BbBaseDatePicker.vue.d.ts} +0 -0
  1345. /package/dist/{index165.js → composables/useArray.js} +0 -0
  1346. /package/dist/{index17.js → composables/useFrameworkDetection.js} +0 -0
  1347. /package/dist/{index12.js → composables/useId.js} +0 -0
  1348. /package/dist/{index107.js → utilities/functions/chunk.js} +0 -0
  1349. /package/dist/{index8.js → utilities/functions/clamp.js} +0 -0
  1350. /package/dist/{index150.js → utilities/functions/curry.js} +0 -0
  1351. /package/dist/{index45.js → utilities/functions/extractDomContainer.js} +0 -0
  1352. /package/dist/{index270.js → utilities/functions/findInTree.js} +0 -0
  1353. /package/dist/{index348.js → utilities/functions/flattenTree.js} +0 -0
  1354. /package/dist/{index41.js → utilities/functions/get.js} +0 -0
  1355. /package/dist/{index189.js → utilities/functions/head.js} +0 -0
  1356. /package/dist/{index108.js → utilities/functions/identity.js} +0 -0
  1357. /package/dist/{index179.js → utilities/functions/indexBy.js} +0 -0
  1358. /package/dist/{index37.js → utilities/functions/isHex.js} +0 -0
  1359. /package/dist/{index94.js → utilities/functions/isNil.js} +0 -0
  1360. /package/dist/{index26.js → utilities/functions/isNotNil.js} +0 -0
  1361. /package/dist/{index105.js → utilities/functions/last.js} +0 -0
  1362. /package/dist/{index142.js → utilities/functions/noop.js} +0 -0
  1363. /package/dist/{index231.js → utilities/functions/parseWidthString.js} +0 -0
  1364. /package/dist/{index240.js → utilities/functions/pickBy.js} +0 -0
  1365. /package/dist/{index123.js → utilities/functions/range.js} +0 -0
  1366. /package/dist/{index190.js → utilities/functions/snapToStep.js} +0 -0
  1367. /package/dist/{index191.js → utilities/functions/transpose.js} +0 -0
  1368. /package/dist/{index106.js → utilities/functions/validateDateFormat.js} +0 -0
  1369. /package/dist/{index10.js → utilities/functions/wait.js} +0 -0
@@ -0,0 +1,1886 @@
1
+ ---
2
+ title: Upload Center (Nuxt)
3
+ summary: Full-anatomy expense-receipts upload center for Nuxt — multi-file dropzone into an inline-editable table (text, category popover, amount, date cells), per-file progress with inline retry, submit-all with count, bulk bottom panel, and a stacked receipt/merchant peek sidebar, filters URL-synced and drafts fetched with useAsyncData while the upload queue stays client-only, all through one coopting page context.
4
+ ---
5
+
6
+ # Recipe: Upload Center (Nuxt)
7
+
8
+ The Expensify-grade expense receipts submission page adapted for **Nuxt**:
9
+ the same multi-file dropzone feeding an inline-editable table, per-file
10
+ upload progress with inline retry, one-click category cells, bulk actions
11
+ in the floating bottom panel, and a stacked receipt/merchant peek sidebar —
12
+ but filters and the active tab live in the URL, the drafts page loads
13
+ through `useAsyncData` watching `route.query`, and the live upload queue
14
+ stays exactly what it is: client-only reactive state merged above the
15
+ fetched rows. Anatomy, components, the context shape, copy and data are
16
+ identical to the Vue recipe; only the data/URL/mutation layer changes.
17
+
18
+ Sibling recipes: [Vue](../vue/upload-center.md) ·
19
+ [Inertia](../inertia/upload-center.md).
20
+
21
+ ## Prerequisites
22
+
23
+ - **[Layout Scaffold](./layout-scaffold.md) — build it first.** This recipe
24
+ imports `PageShell`, `usePageShellContext` and `FloatingBottomPanel` from your own app.
25
+ They are not package exports; the scaffold recipe is their source. Copy
26
+ those files before anything below, and do not hand-roll replacements —
27
+ the peek stack, the close semantics and the sidebar's out-of-flow
28
+ behaviour are all load-bearing here.
29
+ - `<BbConfirm />` and `<BbToast />` mounted once in `app.vue` — never in a page.
30
+ - [App Layout](../../guides/app-layout.md), [Page Shell](../../guides/page-shell.md)
31
+ and [Floating Bottom Panel](../../guides/floating-bottom-panel.md) copied
32
+ into `src/components/layout/` per their guides — every recipe page assumes
33
+ this chrome exists and renders inside it.
34
+ - A `useCategoriesStore()` Pinia store exposing the shared expense-category
35
+ catalog (Travel, Meals & entertainment, Lodging, Rideshare & transit,
36
+ Software & subscriptions, Office supplies, Fuel, Client entertainment).
37
+ - Server routes: `GET /api/receipts` (accepts `search`, `categoryIds[]`,
38
+ `merchant`, `spentBetween[]`, `tab`, `page`, `perPage`, returns
39
+ `{ data, total, tabCounts, readyCount }`), `GET /api/merchants/search`,
40
+ plus the mutation routes referenced below (`PATCH /api/receipts/:id`,
41
+ `POST /api/receipts/:id/submit`, `POST /api/receipts/submit-drafts`,
42
+ `DELETE /api/receipts/:id`, `PATCH /api/receipts/bulk/categorize`,
43
+ `POST /api/receipts/bulk/delete`). A dedicated `POST /api/receipts/upload`
44
+ endpoint backs `api.receipts.upload()` — see the upload note below.
45
+
46
+ ## Key ideas
47
+
48
+ - **One coopting page context.** `provideUploadCenter()` joins the
49
+ page-shell stack and the table context once, coopts the shared category
50
+ catalog from `useCategoriesStore()`, owns the URL-backed filters/tab and
51
+ the **upload queue**, and exposes complete actions. Every leaf calls
52
+ `useUploadCenter()` and nothing else.
53
+ - **Filters and tab live in the URL, not in local refs.** They are seeded
54
+ from `route.query` at setup and every change writes back through
55
+ `navigateTo` — the page is bookmarkable and survives reload.
56
+ - **`useAsyncData` watches `route.query`.** That single watch source is
57
+ the whole refetch trigger for the _server_ page — filters, tab and page
58
+ changes all funnel through the URL first, so there is exactly one fetch
59
+ path for drafts/submitted/reimbursed rows.
60
+ - **The upload queue is untouched by the data-layer swap.** It stays
61
+ client-only reactive state (`uploads`), merged above the fetched server
62
+ rows in a computed (`rows`) passed straight to `BbTable`'s `:items` —
63
+ no `dependencies`, no `refreshKey`; progress ticks mutate the queue rows
64
+ in place and Vue's own reactivity re-renders the one cell reading them.
65
+ - **Capture and transfer are two layers.** `BbDropzone` only validates and
66
+ hands over `File[]`; the context runs the uploads (AbortController +
67
+ progress callback per file) and the dropzone leaf immediately drains its
68
+ model into `ctx.enqueueFiles()`. `$fetch` has no upload-progress events,
69
+ so the transfer itself posts `FormData` through a small XHR wrapper in
70
+ `@/api` — the call site (`api.receipts.upload(file, { signal, onProgress })`)
71
+ stays identical to the other platforms.
72
+ - **Every draft cell edits in place**, exactly as in the Vue recipe:
73
+ merchant (§6.3), category (§6.1), amount, date — each its own leaf with
74
+ a single `receipt` prop, failed saves revert via `refresh()` and toast
75
+ destructive.
76
+ - **Tabs are URL filters.** Drafts / Submitted / Reimbursed carry `href`
77
+ (`?tab=drafts`) and live counts from every fetch; the same table is the
78
+ pane, read-only outside Drafts.
79
+ - **Clicking the name of a thing peeks it.** Filename → receipt peek
80
+ (fresh stack); merchant name inside the peek → merchant peek **stacked**
81
+ with a back arrow. Peeks fetch their own JSON and re-run whenever
82
+ `ctx.rows.value` changes (the same signal a server `refresh()` updates).
83
+ - **Buttons are `md` by default**; `sm`/`xs` only in the table rows, the
84
+ filter pills, the peek footers and the bottom bar. One
85
+ `variant="primary"`: **Submit all** with its live count. Internal SPA
86
+ navigation (the merchant peek's "All receipts from…" link) uses `to`;
87
+ the file-download links (`Download original`) stay a raw `href` — they
88
+ serve a real file, not a Nuxt page, so they must not be intercepted by
89
+ the router.
90
+
91
+ ## Page anatomy
92
+
93
+ ```
94
+ UploadCenter/
95
+ Index.vue ← assembly: PageShell slots, dropzone, tabs, table, pagination
96
+ context.ts ← coopting page context (shell + table + categories + URL filters + upload queue + actions)
97
+ ReceiptDropzone.vue ← multi-file capture, constraint errors mapped to messages
98
+ FilterRail.vue ← pill filters + clear-all
99
+ ReceiptFileCell.vue ← file icon + name (peek link) + size, both row kinds
100
+ UploadProgressCell.vue ← per-file BbProgress / failed state with inline retry
101
+ MerchantCell.vue ← inline text edit, commit on blur/Enter (§6.3)
102
+ CategoryCell.vue ← one-click badge → BbSelectPopover (§6.1)
103
+ AmountCell.vue ← inline number edit with $ prefix
104
+ DateCell.vue ← date picker cell, commit on pick
105
+ RowActions.vue ← remove-from-queue / per-receipt "…" dropdown
106
+ SelectionBar.vue ← bulk categorize + bulk remove in the floating bottom panel
107
+ ReceiptPeek.vue ← sidebar workbench, stack level 1
108
+ MerchantPeek.vue ← stacked peek, back arrow via the shell
109
+ ```
110
+
111
+ Chrome assumed from the guides: [App Layout](../../guides/app-layout.md)
112
+ (left nav + fat footer), [Page Shell](../../guides/page-shell.md),
113
+ [Floating Bottom Panel](../../guides/floating-bottom-panel.md).
114
+
115
+ ## Action inventory
116
+
117
+ | # | Action | Trigger | Mechanism |
118
+ | --- | --------------------------------- | ---------------------------------- | ----------------------------------------------------- |
119
+ | 1 | Upload receipts | dropzone (drag, click, Browse) | `enqueueFiles()` → per-file upload with progress |
120
+ | 2 | Retry a failed upload | inline in the progress cell | `retryUpload(id)` re-issues the request |
121
+ | 3 | Remove an in-flight upload | row actions (x) | `removeUpload(id)` aborts + drops the row |
122
+ | 4 | Page search | topbar right | `filters.search` → URL → `useAsyncData` refetch |
123
+ | 5 | Filter category / merchant / date | filter rail pills | `BbSelectPopover` multiple / query-aware / date range |
124
+ | 6 | Clear filters | rail right (only when active) | context `clearFilters()` |
125
+ | 7 | Switch tab | href tabs with counts | URL + `useAsyncData` refetch |
126
+ | 8 | Edit merchant inline | merchant cell | commit on blur/Enter, Esc reverts (§6.3) |
127
+ | 9 | Change category one-click | category badge in row & peek | `BbSelectPopover` on the badge (§6.1) |
128
+ | 10 | Edit amount inline | amount cell ($ prefix) | commit on blur/Enter, Esc reverts |
129
+ | 11 | Edit expense date inline | date cell | commit on pick |
130
+ | 12 | Submit one receipt | row `…`, peek footer | `submitReceipt()` ($fetch + refresh + toast) |
131
+ | 13 | Submit all with count | topbar, the page's one `primary` | `submitAll()` — count from every fetch |
132
+ | 14 | Remove a draft | row `…`, peek footer | destructive behind `useConfirm` |
133
+ | 15 | Bulk categorize | floating bottom panel popover | `bulkCategorize()` on `table.selected` |
134
+ | 16 | Bulk remove | floating bottom panel | destructive behind `useConfirm`, count in message |
135
+ | 17 | Select rows / select all | table checkboxes (drafts only) | table context, `selectable` predicate |
136
+ | 18 | Peek receipt | filename cell / merchant peek list | `peekReceipt(id)` → shell stack |
137
+ | 19 | Peek merchant (stacked) | merchant name inside the peek | `stackMerchant(name)` → back arrow |
138
+ | 20 | Download original | row `…`, peek footer | navigation (raw `href`, real file endpoint) |
139
+
140
+ ## The code
141
+
142
+ ### context.ts
143
+
144
+ ```ts
145
+ // UploadCenter/context.ts
146
+ import {
147
+ computed,
148
+ inject,
149
+ provide,
150
+ reactive,
151
+ ref,
152
+ watch,
153
+ type ComputedRef,
154
+ type InjectionKey,
155
+ type Ref,
156
+ } from 'vue';
157
+ import {
158
+ useBbTableContext,
159
+ useConfirm,
160
+ useToast,
161
+ type BbTableContext,
162
+ } from 'bitboss-ui';
163
+ import {
164
+ usePageShellContext,
165
+ type PageShellContext,
166
+ } from '@/components/layout/usePageShellContext';
167
+ import { useCategoriesStore } from '@/stores/categories';
168
+ import { api } from '@/api';
169
+ import { watchDebounced } from '@vueuse/core';
170
+ import type { Category, Receipt } from '@/types';
171
+
172
+ /** What the stacked sidebar can show. Clicking a name pushes one of these. */
173
+ export type PeekItem =
174
+ | { type: 'receipt'; id: string }
175
+ | { type: 'merchant'; name: string };
176
+
177
+ export type UploadCenterTab = 'drafts' | 'submitted' | 'reimbursed';
178
+
179
+ export interface ReceiptFilters {
180
+ search: string;
181
+ categoryIds: string[];
182
+ merchant: string | null;
183
+ /**
184
+ * `[start, end]` as `YYYY-MM-DD`, or `[]` when unset. Range mode requires an
185
+ * array modelValue -- binding `null` throws, so the empty filter is `[]`.
186
+ */
187
+ spentBetween: string[];
188
+ }
189
+
190
+ /** A dropped file whose transfer is still in flight (or failed). Local-only. */
191
+ export type UploadRow = {
192
+ /** Local id (`upload-…`) — never collides with server receipt ids. */
193
+ id: string;
194
+ kind: 'upload';
195
+ filename: string;
196
+ size: number;
197
+ /** 0–100. Mutated in place per progress tick — reactive, no refetch. */
198
+ progress: number;
199
+ failed: boolean;
200
+ };
201
+
202
+ /** A server receipt as the table renders it. */
203
+ export type ReceiptRow = Receipt & { kind: 'receipt' };
204
+
205
+ /** What the table actually lists on the Drafts tab: uploads first. */
206
+ export type UploadCenterRow = UploadRow | ReceiptRow;
207
+
208
+ /** The only fields the inline cells may change. */
209
+ export type ReceiptPatch = Partial<
210
+ Pick<Receipt, 'merchant' | 'categoryId' | 'amount' | 'date'>
211
+ >;
212
+
213
+ type ReceiptListResponse = {
214
+ data: Receipt[];
215
+ total: number;
216
+ tabCounts: Record<UploadCenterTab, number>;
217
+ readyCount: number;
218
+ };
219
+
220
+ export interface UploadCenterContext {
221
+ // -- Coopted contexts ------------------------------------------------------
222
+ shell: PageShellContext<PeekItem>;
223
+ table: BbTableContext;
224
+ /** Shared expense-category catalog, coopted from the store. */
225
+ categories: ComputedRef<Category[]>;
226
+ // -- Page-owned state ------------------------------------------------------
227
+ filters: ReceiptFilters;
228
+ hasActiveFilters: ComputedRef<boolean>;
229
+ tab: Ref<UploadCenterTab>;
230
+ tabCounts: ComputedRef<Record<UploadCenterTab, number>>;
231
+ /** Drafts that are complete (merchant + category + amount + date). */
232
+ readyCount: ComputedRef<number>;
233
+ /** The live upload queue — in-flight and failed transfers. */
234
+ uploads: Ref<UploadRow[]>;
235
+ // -- Data (server-rendered, URL-driven) -------------------------------------
236
+ /** Drafts tab: queue rows first, then the fetched server page. */
237
+ rows: ComputedRef<UploadCenterRow[]>;
238
+ rowsPending: Ref<boolean>;
239
+ searchMerchants: (query: string) => Promise<string[]>;
240
+ // -- Peek grammar ----------------------------------------------------------
241
+ peekReceipt: (id: string) => void;
242
+ stackReceipt: (id: string) => void;
243
+ stackMerchant: (name: string) => void;
244
+ // -- Actions (complete: API + refresh + toast) ------------------------------
245
+ clearFilters: () => void;
246
+ enqueueFiles: (files: File[]) => void;
247
+ retryUpload: (id: string) => void;
248
+ removeUpload: (id: string) => void;
249
+ updateReceipt: (receipt: Receipt, patch: ReceiptPatch) => Promise<void>;
250
+ submitReceipt: (receipt: Receipt) => Promise<void>;
251
+ submitAll: () => Promise<void>;
252
+ /** Resolves `true` when the receipt was actually deleted (confirm accepted). */
253
+ deleteReceipt: (receipt: Receipt) => Promise<boolean>;
254
+ bulkCategorize: (categoryId: string) => Promise<void>;
255
+ bulkRemove: () => Promise<void>;
256
+ }
257
+
258
+ const key: InjectionKey<UploadCenterContext> = Symbol('upload-center');
259
+
260
+ /** Comma-joined query value → string[] (or null when absent). */
261
+ const toArray = (value: unknown): string[] | null => {
262
+ if (value == null || value === '') return null;
263
+ return Array.isArray(value) ? value.map(String) : String(value).split(',');
264
+ };
265
+
266
+ export function provideUploadCenter(): UploadCenterContext {
267
+ const { toast } = useToast();
268
+ const { confirm } = useConfirm();
269
+ const route = useRoute();
270
+
271
+ // -- Coopt the specific contexts: once, here, for the whole page. ----------
272
+ const shell = usePageShellContext<PeekItem>();
273
+ const table = useBbTableContext('receipts-table', { perPage: 25 });
274
+ const categoriesStore = useCategoriesStore();
275
+ const categories = computed(() => categoriesStore.categories);
276
+
277
+ // -- Filters + tab: seeded from the URL, the single source of truth. -------
278
+ const filters = reactive<ReceiptFilters>({
279
+ search: (route.query.search as string) ?? '',
280
+ categoryIds: toArray(route.query.categoryIds) ?? [],
281
+ merchant: (route.query.merchant as string) ?? null,
282
+ spentBetween: toArray(route.query.spentBetween) ?? [],
283
+ });
284
+ const tab = ref<UploadCenterTab>(
285
+ (route.query.tab as UploadCenterTab) ?? 'drafts'
286
+ );
287
+
288
+ const hasActiveFilters = computed(
289
+ () =>
290
+ filters.search !== '' ||
291
+ filters.categoryIds.length > 0 ||
292
+ filters.merchant !== null ||
293
+ filters.spentBetween.length > 0
294
+ );
295
+
296
+ const clearFilters = () => {
297
+ filters.search = '';
298
+ filters.categoryIds = [];
299
+ filters.merchant = null;
300
+ filters.spentBetween = [];
301
+ };
302
+
303
+ // Every filter/tab change mirrors into the query string; `useAsyncData`
304
+ // below watches `route.query`, so this is the whole refetch trigger.
305
+ const syncQuery = () =>
306
+ navigateTo({
307
+ query: {
308
+ search: filters.search || undefined,
309
+ categoryIds: filters.categoryIds.length
310
+ ? filters.categoryIds.join(',')
311
+ : undefined,
312
+ merchant: filters.merchant ?? undefined,
313
+ spentBetween: filters.spentBetween.length
314
+ ? filters.spentBetween.join(',')
315
+ : undefined,
316
+ tab: tab.value,
317
+ },
318
+ });
319
+ watchDebounced(filters, syncQuery, { deep: true, debounce: 300 });
320
+ watch(tab, () => {
321
+ table.page.value = 1;
322
+ syncQuery();
323
+ });
324
+
325
+ // -- Data ---------------------------------------------------------------------
326
+ // The one place the *server* page is fetched. A drafts page looks like:
327
+ // { id: 'rcp_3128', filename: 'uber-2026-07-08.pdf', merchant: 'Uber',
328
+ // categoryId: 'cat-rideshare', amount: 42.8, date: '2026-07-08', … }
329
+ // { id: 'rcp_3127', filename: 'IMG_4021.jpg', merchant: 'Starbucks Reserve',
330
+ // categoryId: 'cat-meals', amount: 11.4, date: '2026-07-08', … }
331
+ // { id: 'rcp_3120', filename: 'delta-ticket-0472.pdf', merchant: 'Delta Air Lines',
332
+ // categoryId: 'cat-travel', amount: 428.6, date: '2026-07-06', … }
333
+ // { id: 'rcp_3117', filename: 'marriott-folio.pdf', merchant: 'Marriott Marquis SF',
334
+ // categoryId: 'cat-lodging', amount: 612.33, date: '2026-07-05', … }
335
+ // The live upload queue is NOT part of this response — it is client-only
336
+ // reactive state merged in below, ahead of the fetched rows.
337
+ const { data, pending, refresh } = useAsyncData<ReceiptListResponse>(
338
+ 'receipts',
339
+ () =>
340
+ $fetch<ReceiptListResponse>('/api/receipts', {
341
+ query: {
342
+ search: filters.search || undefined,
343
+ categoryIds: filters.categoryIds,
344
+ merchant: filters.merchant ?? undefined,
345
+ spentBetween: filters.spentBetween.length
346
+ ? filters.spentBetween
347
+ : undefined,
348
+ tab: tab.value,
349
+ page: table.page.value,
350
+ perPage: table.perPage.value,
351
+ },
352
+ }),
353
+ { watch: [() => route.query, table.page] }
354
+ );
355
+ const serverRows = computed<ReceiptRow[]>(
356
+ () =>
357
+ data.value?.data.map(
358
+ (receipt): ReceiptRow => ({ ...receipt, kind: 'receipt' })
359
+ ) ?? []
360
+ );
361
+ // Drafts tab: queue rows render above the fetched page; a completed upload
362
+ // re-enters here once the next `refresh()` lands it as a server draft.
363
+ const uploads = ref<UploadRow[]>([]);
364
+ const rows = computed<UploadCenterRow[]>(() =>
365
+ tab.value === 'drafts'
366
+ ? [...uploads.value, ...serverRows.value]
367
+ : serverRows.value
368
+ );
369
+ const rowsPending = pending;
370
+ const tabCounts = computed(
371
+ () => data.value?.tabCounts ?? { drafts: 0, submitted: 0, reimbursed: 0 }
372
+ );
373
+ const readyCount = computed(() => data.value?.readyCount ?? 0);
374
+ watch(
375
+ data,
376
+ (response) => {
377
+ if (response) table.total.value = response.total;
378
+ },
379
+ { immediate: true }
380
+ );
381
+
382
+ const searchMerchants = (query: string): Promise<string[]> =>
383
+ $fetch<string[]>('/api/merchants/search', { query: { q: query } });
384
+
385
+ // -- Upload machinery ----------------------------------------------------------
386
+ // Untouched by the URL/useAsyncData swap: the queue is client-only state,
387
+ // mutated in place per progress tick — reactive, no refetch — and `rows`
388
+ // above re-derives on every push/filter. Files and abort controllers live
389
+ // in closure maps, not render state.
390
+ const uploadFiles = new Map<string, File>();
391
+ const controllers = new Map<string, AbortController>();
392
+
393
+ const startUpload = async (id: string) => {
394
+ const file = uploadFiles.get(id);
395
+ const row = uploads.value.find((upload) => upload.id === id);
396
+ if (!file || !row) return;
397
+ row.failed = false;
398
+ row.progress = 0;
399
+ const controller = new AbortController();
400
+ controllers.set(id, controller);
401
+ try {
402
+ // `$fetch` has no upload-progress events, so `api.receipts.upload`
403
+ // posts FormData through a small XHR wrapper in `@/api` instead of
404
+ // `$fetch` — the call shape here is identical to the other platforms.
405
+ await api.receipts.upload(file, {
406
+ signal: controller.signal,
407
+ onProgress: (percent) => {
408
+ row.progress = percent;
409
+ },
410
+ });
411
+ // Success: the file re-enters as a server draft with OCR-extracted
412
+ // merchant/amount/date prefilled — the refresh swaps the rows.
413
+ uploads.value = uploads.value.filter((upload) => upload.id !== id);
414
+ uploadFiles.delete(id);
415
+ await refresh();
416
+ } catch {
417
+ // Keep the row: the progress cell renders the inline Retry.
418
+ row.failed = true;
419
+ } finally {
420
+ controllers.delete(id);
421
+ }
422
+ };
423
+
424
+ const enqueueFiles = (files: File[]) => {
425
+ for (const file of files) {
426
+ const id = `upload-${crypto.randomUUID()}`;
427
+ uploadFiles.set(id, file);
428
+ uploads.value.push({
429
+ id,
430
+ kind: 'upload',
431
+ filename: file.name,
432
+ size: file.size,
433
+ progress: 0,
434
+ failed: false,
435
+ });
436
+ void startUpload(id);
437
+ }
438
+ };
439
+
440
+ const retryUpload = (id: string) => {
441
+ void startUpload(id);
442
+ };
443
+
444
+ const removeUpload = (id: string) => {
445
+ controllers.get(id)?.abort();
446
+ controllers.delete(id);
447
+ uploadFiles.delete(id);
448
+ uploads.value = uploads.value.filter((upload) => upload.id !== id);
449
+ };
450
+
451
+ // -- Peek grammar ----------------------------------------------------------------
452
+ // peekX opens a fresh stack (from the list); stackX drills down (from a peek).
453
+ const peekReceipt = (id: string) => shell.push({ type: 'receipt', id }, true);
454
+ const stackReceipt = (id: string) => shell.push({ type: 'receipt', id });
455
+ const stackMerchant = (name: string) =>
456
+ shell.push({ type: 'merchant', name });
457
+
458
+ // -- Actions --------------------------------------------------------------------
459
+ const updateReceipt = async (receipt: Receipt, patch: ReceiptPatch) => {
460
+ try {
461
+ await $fetch(`/api/receipts/${receipt.id}`, {
462
+ method: 'PATCH',
463
+ body: patch,
464
+ });
465
+ await refresh(); // silent on success — the cell already shows the new value
466
+ } catch {
467
+ await refresh(); // the refetch reverts the cell to the server value
468
+ toast({
469
+ title: `Could not save ${receipt.filename}. Changes were reverted.`,
470
+ variant: 'destructive',
471
+ });
472
+ }
473
+ };
474
+
475
+ const submitReceipt = async (receipt: Receipt) => {
476
+ await $fetch(`/api/receipts/${receipt.id}/submit`, { method: 'POST' });
477
+ await refresh();
478
+ toast({
479
+ title: `${receipt.merchant ?? receipt.filename} submitted for approval.`,
480
+ variant: 'success',
481
+ });
482
+ };
483
+
484
+ const submitAll = async () => {
485
+ const { submitted } = await $fetch<{ submitted: number }>(
486
+ '/api/receipts/submit-drafts',
487
+ { method: 'POST' }
488
+ );
489
+ await refresh();
490
+ toast({
491
+ title: `${submitted} receipts submitted for approval.`,
492
+ variant: 'success',
493
+ });
494
+ };
495
+
496
+ const deleteReceipt = async (receipt: Receipt): Promise<boolean> => {
497
+ const ok = await confirm({
498
+ variant: 'destructive',
499
+ title: 'Remove receipt',
500
+ text: `Remove ${receipt.filename}? The file is deleted and cannot be recovered.`,
501
+ yes: 'Remove',
502
+ no: 'Cancel',
503
+ });
504
+ if (!ok) return false;
505
+ await $fetch(`/api/receipts/${receipt.id}`, { method: 'DELETE' });
506
+ await refresh();
507
+ toast({ title: `${receipt.filename} removed.`, variant: 'success' });
508
+ return true;
509
+ };
510
+
511
+ // Bulk actions read and clear the coopted table context themselves. Only
512
+ // draft receipt rows are selectable, so `selected` holds receipt ids.
513
+ const bulkIds = (): string[] => table.selected.value;
514
+ const clearSelection = () => {
515
+ table.selected.value = [];
516
+ };
517
+
518
+ const bulkCategorize = async (categoryId: string) => {
519
+ const ids = bulkIds();
520
+ await $fetch('/api/receipts/bulk/categorize', {
521
+ method: 'PATCH',
522
+ body: { ids, categoryId },
523
+ });
524
+ const category = categories.value.find((entry) => entry.id === categoryId);
525
+ clearSelection();
526
+ await refresh();
527
+ toast({
528
+ title: `${ids.length} receipts filed under ${category?.name ?? 'the selected category'}.`,
529
+ variant: 'success',
530
+ });
531
+ };
532
+
533
+ const bulkRemove = async () => {
534
+ const ids = bulkIds();
535
+ const ok = await confirm({
536
+ variant: 'destructive',
537
+ title: 'Remove receipts',
538
+ text: `Remove ${ids.length} receipts? Their files are deleted and cannot be recovered.`,
539
+ yes: 'Remove',
540
+ no: 'Cancel',
541
+ });
542
+ if (!ok) return;
543
+ await $fetch('/api/receipts/bulk/delete', {
544
+ method: 'POST',
545
+ body: { ids },
546
+ });
547
+ clearSelection();
548
+ await refresh();
549
+ toast({ title: `${ids.length} receipts removed.`, variant: 'success' });
550
+ };
551
+
552
+ const ctx: UploadCenterContext = {
553
+ shell,
554
+ table,
555
+ categories,
556
+ filters,
557
+ hasActiveFilters,
558
+ tab,
559
+ tabCounts,
560
+ readyCount,
561
+ uploads,
562
+ rows,
563
+ rowsPending,
564
+ searchMerchants,
565
+ peekReceipt,
566
+ stackReceipt,
567
+ stackMerchant,
568
+ clearFilters,
569
+ enqueueFiles,
570
+ retryUpload,
571
+ removeUpload,
572
+ updateReceipt,
573
+ submitReceipt,
574
+ submitAll,
575
+ deleteReceipt,
576
+ bulkCategorize,
577
+ bulkRemove,
578
+ };
579
+ provide(key, ctx);
580
+ return ctx;
581
+ }
582
+
583
+ export function useUploadCenter(): UploadCenterContext {
584
+ const ctx = inject(key);
585
+ if (!ctx) throw new Error('useUploadCenter() called outside UploadCenter');
586
+ return ctx;
587
+ }
588
+ ```
589
+
590
+ ### Index.vue — the assembly
591
+
592
+ ```vue
593
+ <!-- UploadCenter/Index.vue -->
594
+ <template>
595
+ <PageShell>
596
+ <!-- Topbar: breadcrumbs left, page search + submit-all right. -->
597
+ <template #topbar>
598
+ <div class="flex items-center justify-between gap-4 border-b px-4 py-2">
599
+ <!-- Breadcrumbs take the row's slack on a stable basis (min-w-0 flex-auto);
600
+ without it their overflow recompute fights the flex layout every frame. -->
601
+ <BbBreadcrumbs
602
+ class="min-w-0 flex-auto"
603
+ :items="[
604
+ { key: 'dashboard', text: 'Dashboard', to: '/dashboard' },
605
+ { key: 'expenses', text: 'Expenses', to: '/expenses' },
606
+ { key: 'receipts', text: 'Receipts' },
607
+ ]"
608
+ />
609
+ <div class="flex shrink-0 items-center gap-2">
610
+ <BbTextInput
611
+ v-model="ctx.filters.search"
612
+ autocomplete="off"
613
+ clearable
614
+ compact
615
+ hide-label
616
+ label="Search receipts"
617
+ placeholder="Search merchant or filename…"
618
+ prepend:icon="lucide:search"
619
+ />
620
+ <!-- The page's single primary: submit-all with a live count.
621
+ BbButton tracks the async handler, so it shows its own
622
+ loading state while the batch submits. -->
623
+ <BbButton
624
+ :disabled="ctx.readyCount.value === 0"
625
+ prepend:icon="lucide:send"
626
+ variant="primary"
627
+ @click="ctx.submitAll"
628
+ >
629
+ {{ submitLabel }}
630
+ </BbButton>
631
+ </div>
632
+ </div>
633
+ </template>
634
+
635
+ <div class="flex flex-col gap-3 p-4">
636
+ <!-- Capture surface: drafts tab only. -->
637
+ <ReceiptDropzone v-if="ctx.tab.value === 'drafts'" />
638
+
639
+ <FilterRail />
640
+
641
+ <!-- Tabs as URL filters: href updates the query, the key feeds the
642
+ fetch. Counts come from the server on every fetch. -->
643
+ <BbTabs
644
+ v-model="ctx.tab.value"
645
+ compact
646
+ :items="[
647
+ {
648
+ key: 'drafts',
649
+ label: `Drafts · ${ctx.tabCounts.value.drafts}`,
650
+ href: '?tab=drafts',
651
+ },
652
+ {
653
+ key: 'submitted',
654
+ label: `Submitted · ${ctx.tabCounts.value.submitted}`,
655
+ href: '?tab=submitted',
656
+ },
657
+ {
658
+ key: 'reimbursed',
659
+ label: `Reimbursed · ${ctx.tabCounts.value.reimbursed}`,
660
+ href: '?tab=reimbursed',
661
+ },
662
+ ]"
663
+ />
664
+
665
+ <BbTable
666
+ id="receipts-table"
667
+ actions
668
+ caption="Expense receipts"
669
+ :columns="columns"
670
+ compact
671
+ item-value="id"
672
+ :items="ctx.rows.value"
673
+ :loading="ctx.rowsPending.value"
674
+ loading-text="Loading receipts…"
675
+ :row-class="rowClass"
676
+ :selectable="isDraft"
677
+ >
678
+ <!-- Clicking the NAME of a thing peeks it. -->
679
+ <template #filename="{ item }">
680
+ <ReceiptFileCell :row="item" />
681
+ </template>
682
+
683
+ <!-- Editable cells on draft rows; plain text everywhere else. -->
684
+ <template #merchant="{ item }">
685
+ <MerchantCell v-if="isDraft(item)" :receipt="item" />
686
+ <span
687
+ v-else-if="item.kind === 'upload'"
688
+ class="text-[color:var(--bb-text-muted)]"
689
+ >—</span
690
+ >
691
+ <span v-else>{{ item.merchant ?? '—' }}</span>
692
+ </template>
693
+
694
+ <template #categoryId="{ item }">
695
+ <CategoryCell v-if="isDraft(item)" :receipt="item" />
696
+ <span
697
+ v-else-if="item.kind === 'upload'"
698
+ class="text-[color:var(--bb-text-muted)]"
699
+ >—</span
700
+ >
701
+ <span v-else>{{ categoryName(item.categoryId) }}</span>
702
+ </template>
703
+
704
+ <template #amount="{ item }">
705
+ <AmountCell v-if="isDraft(item)" :receipt="item" />
706
+ <span
707
+ v-else-if="item.kind === 'upload'"
708
+ class="text-[color:var(--bb-text-muted)]"
709
+ >—</span
710
+ >
711
+ <span v-else>{{
712
+ item.amount === null ? '—' : currency.format(item.amount)
713
+ }}</span>
714
+ </template>
715
+
716
+ <template #date="{ item }">
717
+ <DateCell v-if="isDraft(item)" :receipt="item" />
718
+ <span
719
+ v-else-if="item.kind === 'upload'"
720
+ class="text-[color:var(--bb-text-muted)]"
721
+ >—</span
722
+ >
723
+ <span v-else>{{ item.date ? shortDate(item.date) : '—' }}</span>
724
+ </template>
725
+
726
+ <!-- Status column doubles as the transfer surface for queue rows. -->
727
+ <template #status="{ item }">
728
+ <UploadProgressCell v-if="item.kind === 'upload'" :upload="item" />
729
+ <BbBadge v-else variant="outline">{{ item.status }}</BbBadge>
730
+ </template>
731
+
732
+ <template #actions="{ item }">
733
+ <RowActions :row="item" />
734
+ </template>
735
+
736
+ <template #no-data>
737
+ <div class="flex flex-col items-center gap-2 p-6 text-center">
738
+ <p class="text-sm text-[color:var(--bb-text-muted)]">
739
+ {{
740
+ ctx.hasActiveFilters.value
741
+ ? 'No receipts match the current filters.'
742
+ : ctx.tab.value === 'drafts'
743
+ ? 'No drafts — drop receipts above to get started.'
744
+ : 'Nothing here yet.'
745
+ }}
746
+ </p>
747
+ <BbButton
748
+ v-if="ctx.hasActiveFilters.value"
749
+ variant="ghost"
750
+ @click="ctx.clearFilters"
751
+ >
752
+ Clear filters
753
+ </BbButton>
754
+ </div>
755
+ </template>
756
+ </BbTable>
757
+
758
+ <!-- Joins the table context by id: no page/totalPages wiring at all. -->
759
+ <BbPagination table-id="receipts-table" />
760
+ </div>
761
+
762
+ <SelectionBar />
763
+
764
+ <!-- Stacked peek sidebar: the shell owns back/close; we render by type. -->
765
+ <template #sidebar>
766
+ <ReceiptPeek
767
+ v-if="ctx.shell.current.value?.type === 'receipt'"
768
+ :receipt-id="ctx.shell.current.value.id"
769
+ />
770
+ <MerchantPeek
771
+ v-else-if="ctx.shell.current.value?.type === 'merchant'"
772
+ :merchant-name="ctx.shell.current.value.name"
773
+ />
774
+ </template>
775
+ </PageShell>
776
+ </template>
777
+
778
+ <script setup lang="ts">
779
+ import { computed } from 'vue';
780
+ import {
781
+ BbBadge,
782
+ BbBreadcrumbs,
783
+ BbButton,
784
+ BbPagination,
785
+ BbTable,
786
+ BbTabs,
787
+ BbTextInput,
788
+ } from 'bitboss-ui';
789
+ import PageShell from '@/components/layout/PageShell.vue';
790
+ import {
791
+ provideUploadCenter,
792
+ type ReceiptRow,
793
+ type UploadCenterRow,
794
+ } from './context';
795
+ import AmountCell from './AmountCell.vue';
796
+ import CategoryCell from './CategoryCell.vue';
797
+ import DateCell from './DateCell.vue';
798
+ import FilterRail from './FilterRail.vue';
799
+ import MerchantCell from './MerchantCell.vue';
800
+ import MerchantPeek from './MerchantPeek.vue';
801
+ import ReceiptDropzone from './ReceiptDropzone.vue';
802
+ import ReceiptFileCell from './ReceiptFileCell.vue';
803
+ import ReceiptPeek from './ReceiptPeek.vue';
804
+ import RowActions from './RowActions.vue';
805
+ import SelectionBar from './SelectionBar.vue';
806
+ import UploadProgressCell from './UploadProgressCell.vue';
807
+
808
+ const ctx = provideUploadCenter();
809
+
810
+ const currency = new Intl.NumberFormat('en-US', {
811
+ style: 'currency',
812
+ currency: 'USD',
813
+ });
814
+ const shortDate = (value: string) =>
815
+ new Date(value).toLocaleDateString('en-US', {
816
+ month: 'short',
817
+ day: 'numeric',
818
+ });
819
+
820
+ // Every cell renders through a slot, so columns stay label-only definitions.
821
+ const columns = [
822
+ { key: 'filename', label: 'Receipt' },
823
+ { key: 'merchant', label: 'Merchant' },
824
+ { key: 'categoryId', label: 'Category' },
825
+ { key: 'amount', label: 'Amount', align: 'right' as const },
826
+ { key: 'date', label: 'Date' },
827
+ { key: 'status', label: 'Status' },
828
+ ];
829
+
830
+ // Only server-side drafts are editable and selectable; queue rows and
831
+ // submitted/reimbursed receipts are not.
832
+ const isDraft = (item: UploadCenterRow): item is ReceiptRow =>
833
+ item.kind === 'receipt' && item.status === 'draft';
834
+
835
+ // Failed transfers get a tinted row — public row-class API, no internals.
836
+ const rowClass = (item: UploadCenterRow) =>
837
+ item.kind === 'upload' && item.failed
838
+ ? 'bg-red-50 dark:bg-red-950/20'
839
+ : undefined;
840
+
841
+ const categoryName = (categoryId: string | null) =>
842
+ ctx.categories.value.find((category) => category.id === categoryId)?.name ??
843
+ '—';
844
+
845
+ const submitLabel = computed(() =>
846
+ ctx.readyCount.value === 0
847
+ ? 'Submit receipts'
848
+ : `Submit ${ctx.readyCount.value} ${ctx.readyCount.value === 1 ? 'receipt' : 'receipts'}`
849
+ );
850
+ </script>
851
+ ```
852
+
853
+ ### ReceiptDropzone.vue
854
+
855
+ ```vue
856
+ <!-- UploadCenter/ReceiptDropzone.vue -->
857
+ <template>
858
+ <BbDropzone
859
+ v-model="pending"
860
+ :accept="ACCEPT"
861
+ :errors="dropError"
862
+ :max-files="20"
863
+ :max-size="MAX_SIZE"
864
+ multiple
865
+ @error="onError"
866
+ >
867
+ <template #default="{ dragging, focused, open }">
868
+ <div
869
+ class="flex flex-col items-center gap-2 rounded-[var(--bb-radius)] border-2 border-dashed p-6 text-center transition-colors"
870
+ :class="[
871
+ dragging ? 'border-[var(--bb-primary)]' : 'border-[var(--bb-border)]',
872
+ focused ? 'ring-2 ring-[var(--bb-primary)] ring-offset-2' : '',
873
+ ]"
874
+ >
875
+ <BbIcon
876
+ class="text-[color:var(--bb-text-muted)]"
877
+ icon="lucide:receipt"
878
+ size="lg"
879
+ />
880
+ <p class="text-sm font-medium">
881
+ {{ dragging ? 'Drop to add receipts' : 'Drop receipts here' }}
882
+ </p>
883
+ <p class="text-xs text-[color:var(--bb-text-muted)]">
884
+ JPG, PNG, HEIC or PDF · up to 10 MB each · 20 files per drop
885
+ </p>
886
+ <BbButton
887
+ prepend:icon="lucide:folder-open"
888
+ variant="ghost"
889
+ @click="open"
890
+ >
891
+ Browse files
892
+ </BbButton>
893
+ </div>
894
+ </template>
895
+ </BbDropzone>
896
+ </template>
897
+
898
+ <script setup lang="ts">
899
+ import { ref, watch } from 'vue';
900
+ import { BbButton, BbDropzone, BbIcon, type DropZoneError } from 'bitboss-ui';
901
+ import { useUploadCenter } from './context';
902
+
903
+ // Pair every extension with its MIME type: the MIME rule matches by content
904
+ // type, the .ext rule catches drag-drops where the OS leaves file.type empty.
905
+ const ACCEPT = [
906
+ 'image/jpeg',
907
+ '.jpg',
908
+ '.jpeg',
909
+ 'image/png',
910
+ '.png',
911
+ 'image/heic',
912
+ '.heic',
913
+ 'application/pdf',
914
+ '.pdf',
915
+ ];
916
+ const MAX_SIZE = 10 * 1024 * 1024; // 10 MB per receipt
917
+
918
+ const ctx = useUploadCenter();
919
+
920
+ // BbDropzone captures and validates; the context uploads (posting FormData
921
+ // through an XHR wrapper — see context.ts). The model is a hand-off buffer:
922
+ // drain every validated batch into the queue, then clear it (which also
923
+ // resets the duplicate check for future corrections).
924
+ const pending = ref<File[]>([]);
925
+ watch(pending, (files) => {
926
+ if (files.length === 0) return;
927
+ dropError.value = undefined;
928
+ ctx.enqueueFiles(files);
929
+ pending.value = [];
930
+ });
931
+
932
+ // The errors display is a round-trip: map each typed reject to a sentence
933
+ // and feed it back through the `errors` prop (rendered in the built-in
934
+ // aria-live region and referenced from the input's aria-describedby). Batch drops emit one error per file; showing the last
935
+ // message keeps the surface calm.
936
+ const dropError = ref<string | undefined>();
937
+ const onError = (error: DropZoneError) => {
938
+ if (error.type === 'maxSize') {
939
+ dropError.value = `${error.filename} is ${error.formattedSize} — receipts are capped at ${error.formattedMaxSize}.`;
940
+ } else if (error.type === 'accept') {
941
+ dropError.value = `${error.filename} is not a JPG, PNG, HEIC or PDF.`;
942
+ } else if (error.type === 'uniqueness') {
943
+ dropError.value = `${error.filename} is already in this drop.`;
944
+ } else {
945
+ dropError.value = `That drop had ${error.totalFiles} files — add at most 20 at a time.`;
946
+ }
947
+ };
948
+ </script>
949
+ ```
950
+
951
+ ### FilterRail.vue
952
+
953
+ ```vue
954
+ <!-- UploadCenter/FilterRail.vue -->
955
+ <template>
956
+ <div class="flex flex-wrap items-center gap-2">
957
+ <!-- Category: multi-select pill over the coopted catalog. -->
958
+ <BbSelectPopover
959
+ v-model="ctx.filters.categoryIds"
960
+ item-text="name"
961
+ item-value="id"
962
+ :items="ctx.categories.value"
963
+ multiple
964
+ width="240px"
965
+ >
966
+ <template #activator="{ props }">
967
+ <BbButton
968
+ v-bind="props"
969
+ append:icon="lucide:chevron-down"
970
+ size="sm"
971
+ variant="outline"
972
+ >
973
+ Category{{
974
+ ctx.filters.categoryIds.length
975
+ ? ` · ${ctx.filters.categoryIds.length}`
976
+ : ''
977
+ }}
978
+ </BbButton>
979
+ </template>
980
+ </BbSelectPopover>
981
+
982
+ <!-- Merchant: query-aware search. Merchant names are their own values,
983
+ so the pill labels itself straight from the filter state. -->
984
+ <BbSelectPopover
985
+ v-model="ctx.filters.merchant"
986
+ :items="ctx.searchMerchants"
987
+ width="240px"
988
+ >
989
+ <template #activator="{ props }">
990
+ <BbButton
991
+ v-bind="props"
992
+ append:icon="lucide:chevron-down"
993
+ size="sm"
994
+ variant="outline"
995
+ >
996
+ {{ ctx.filters.merchant ?? 'Merchant' }}
997
+ </BbButton>
998
+ </template>
999
+ </BbSelectPopover>
1000
+
1001
+ <!-- Spent-between range: a compact input is 28px — flush with the pills. -->
1002
+ <BbDatePickerInput
1003
+ v-model="ctx.filters.spentBetween"
1004
+ clearable
1005
+ compact
1006
+ floating
1007
+ hide-label
1008
+ label="Spent between"
1009
+ placeholder="Spent between…"
1010
+ range
1011
+ />
1012
+
1013
+ <!-- Clear-all renders only while something is active. -->
1014
+ <BbButton
1015
+ v-if="ctx.hasActiveFilters.value"
1016
+ class="ml-auto"
1017
+ prepend:icon="lucide:x"
1018
+ size="sm"
1019
+ variant="ghost"
1020
+ @click="ctx.clearFilters"
1021
+ >
1022
+ Clear filters
1023
+ </BbButton>
1024
+ </div>
1025
+ </template>
1026
+
1027
+ <script setup lang="ts">
1028
+ import { BbButton, BbDatePickerInput, BbSelectPopover } from 'bitboss-ui';
1029
+ import { useUploadCenter } from './context';
1030
+
1031
+ const ctx = useUploadCenter();
1032
+ </script>
1033
+ ```
1034
+
1035
+ ### ReceiptFileCell.vue
1036
+
1037
+ ```vue
1038
+ <!-- UploadCenter/ReceiptFileCell.vue -->
1039
+ <template>
1040
+ <div class="flex items-center gap-2">
1041
+ <BbIcon
1042
+ class="shrink-0 text-[color:var(--bb-text-muted)]"
1043
+ :icon="fileIcon"
1044
+ size="16"
1045
+ />
1046
+ <div class="flex min-w-0 flex-col">
1047
+ <!-- Server receipts peek on click; queue rows are not peekable yet. -->
1048
+ <BbButton
1049
+ v-if="row.kind === 'receipt'"
1050
+ class="justify-start"
1051
+ size="sm"
1052
+ variant="link"
1053
+ @click="() => ctx.peekReceipt(row.id)"
1054
+ >
1055
+ {{ row.filename }}
1056
+ </BbButton>
1057
+ <span v-else class="truncate text-sm">{{ row.filename }}</span>
1058
+ <span class="text-xs text-[color:var(--bb-text-muted)]">{{
1059
+ formattedSize
1060
+ }}</span>
1061
+ </div>
1062
+ </div>
1063
+ </template>
1064
+
1065
+ <script setup lang="ts">
1066
+ import { computed } from 'vue';
1067
+ import { BbButton, BbIcon } from 'bitboss-ui';
1068
+ import { useUploadCenter, type UploadCenterRow } from './context';
1069
+
1070
+ const props = defineProps<{ row: UploadCenterRow }>();
1071
+
1072
+ const ctx = useUploadCenter();
1073
+
1074
+ const fileIcon = computed(() =>
1075
+ props.row.filename.toLowerCase().endsWith('.pdf')
1076
+ ? 'lucide:file-text'
1077
+ : 'lucide:image'
1078
+ );
1079
+
1080
+ const formattedSize = computed(() => {
1081
+ const bytes =
1082
+ props.row.kind === 'upload' ? props.row.size : props.row.fileSize;
1083
+ return bytes >= 1024 * 1024
1084
+ ? `${(bytes / (1024 * 1024)).toFixed(1)} MB`
1085
+ : `${Math.max(1, Math.round(bytes / 1024))} KB`;
1086
+ });
1087
+ </script>
1088
+ ```
1089
+
1090
+ ### UploadProgressCell.vue
1091
+
1092
+ ```vue
1093
+ <!-- UploadCenter/UploadProgressCell.vue -->
1094
+ <template>
1095
+ <!-- In flight: a live bar. `upload.progress` is a reactive field mutated
1096
+ by the context's progress callback — no refetch per tick. -->
1097
+ <div v-if="!upload.failed" class="flex min-w-32 items-center gap-2">
1098
+ <BbProgress
1099
+ :aria-label="`Uploading ${upload.filename}`"
1100
+ class="flex-1"
1101
+ :model-value="upload.progress"
1102
+ />
1103
+ <span class="text-xs tabular-nums text-[color:var(--bb-text-muted)]"
1104
+ >{{ upload.progress }}%</span
1105
+ >
1106
+ </div>
1107
+
1108
+ <!-- Failed: say so and retry inline. `xs` is fine here — this is the
1109
+ densest surface on the page. -->
1110
+ <div v-else class="flex items-center gap-2">
1111
+ <span class="text-xs font-medium text-red-600 dark:text-red-400"
1112
+ >Upload failed</span
1113
+ >
1114
+ <BbButton
1115
+ prepend:icon="lucide:rotate-cw"
1116
+ size="xs"
1117
+ variant="outline"
1118
+ @click="() => ctx.retryUpload(upload.id)"
1119
+ >
1120
+ Retry
1121
+ </BbButton>
1122
+ </div>
1123
+ </template>
1124
+
1125
+ <script setup lang="ts">
1126
+ import { BbButton, BbProgress } from 'bitboss-ui';
1127
+ import { useUploadCenter, type UploadRow } from './context';
1128
+
1129
+ defineProps<{ upload: UploadRow }>();
1130
+
1131
+ const ctx = useUploadCenter();
1132
+ </script>
1133
+ ```
1134
+
1135
+ ### MerchantCell.vue
1136
+
1137
+ ```vue
1138
+ <!-- UploadCenter/MerchantCell.vue -->
1139
+ <template>
1140
+ <BbTextInput
1141
+ v-model="draft"
1142
+ compact
1143
+ hide-label
1144
+ label="Merchant"
1145
+ placeholder="Add merchant"
1146
+ @blur="commit"
1147
+ @keydown.enter="commit"
1148
+ @keydown.esc="revert"
1149
+ />
1150
+ </template>
1151
+
1152
+ <script setup lang="ts">
1153
+ import { ref, watch } from 'vue';
1154
+ import { BbTextInput } from 'bitboss-ui';
1155
+ import { useUploadCenter } from './context';
1156
+ import type { Receipt } from '@/types';
1157
+
1158
+ const props = defineProps<{ receipt: Receipt }>();
1159
+
1160
+ const ctx = useUploadCenter();
1161
+
1162
+ // Inline-edit doctrine (§6.3): a local draft, commit on blur/Enter, revert
1163
+ // on Esc. The server value re-seeds the draft whenever a refetch updates the
1164
+ // row — which is also how a failed save reverts.
1165
+ const draft = ref<string | null>(props.receipt.merchant);
1166
+ watch(
1167
+ () => props.receipt.merchant,
1168
+ (value) => {
1169
+ draft.value = value;
1170
+ }
1171
+ );
1172
+
1173
+ const commit = () => {
1174
+ const merchant = draft.value?.trim() || null;
1175
+ if (merchant === props.receipt.merchant) return;
1176
+ void ctx.updateReceipt(props.receipt, { merchant });
1177
+ };
1178
+ const revert = () => {
1179
+ draft.value = props.receipt.merchant;
1180
+ };
1181
+ </script>
1182
+ ```
1183
+
1184
+ ### CategoryCell.vue
1185
+
1186
+ ```vue
1187
+ <!-- UploadCenter/CategoryCell.vue -->
1188
+ <template>
1189
+ <BbSelectPopover
1190
+ compact
1191
+ disable-writing
1192
+ item-text="name"
1193
+ item-value="id"
1194
+ :items="ctx.categories.value"
1195
+ :model-value="receipt.categoryId"
1196
+ width="220px"
1197
+ @update:model-value="(categoryId) => pick(categoryId as string)"
1198
+ >
1199
+ <template #activator="{ props: activatorProps, shown }">
1200
+ <!-- One-click pattern (§6.1): the badge is the focusable trigger —
1201
+ BbBadgeButton takes over the badge body, the trailing chevron says
1202
+ "this can change", and while the save runs `loading` swaps the
1203
+ spinner into the chevron's place. A category is a label, not a
1204
+ semantic status, so a set category reads neutral (`secondary`);
1205
+ only the unset state stays `outline` so empty cells read as
1206
+ quieter to-dos, not values. -->
1207
+ <BbBadge
1208
+ append:icon="lucide:chevron-down"
1209
+ :class="{ 'category-cell--open': shown }"
1210
+ :loading="saving"
1211
+ :variant="receipt.categoryId ? 'secondary' : 'outline'"
1212
+ >
1213
+ <BbBadgeButton v-bind="activatorProps">{{
1214
+ categoryName
1215
+ }}</BbBadgeButton>
1216
+ </BbBadge>
1217
+ </template>
1218
+ </BbSelectPopover>
1219
+ </template>
1220
+
1221
+ <script setup lang="ts">
1222
+ import { computed, ref } from 'vue';
1223
+ import { BbBadge, BbBadgeButton, BbSelectPopover } from 'bitboss-ui';
1224
+ import { useUploadCenter } from './context';
1225
+ import type { Receipt } from '@/types';
1226
+
1227
+ const props = defineProps<{ receipt: Receipt }>();
1228
+
1229
+ const ctx = useUploadCenter();
1230
+
1231
+ // In-flight flag for the save feedback — rung-1 local state, not context.
1232
+ const saving = ref(false);
1233
+ const pick = async (categoryId: string) => {
1234
+ saving.value = true;
1235
+ try {
1236
+ await ctx.updateReceipt(props.receipt, { categoryId });
1237
+ } finally {
1238
+ saving.value = false;
1239
+ }
1240
+ };
1241
+
1242
+ // The trigger labels itself from the coopted catalog, never from the
1243
+ // popover's lazy `text` slot prop.
1244
+ const categoryName = computed(
1245
+ () =>
1246
+ ctx.categories.value.find(
1247
+ (category) => category.id === props.receipt.categoryId
1248
+ )?.name ?? 'Set category'
1249
+ );
1250
+ </script>
1251
+
1252
+ <style scoped>
1253
+ /* Open = the badge's own hue, deepened, plus its variant ring — the same
1254
+ grammar as every badge-activator cell. */
1255
+ .category-cell--open {
1256
+ --bg: color-mix(in oklab, var(--color) 24%, var(--bb-panel));
1257
+ --border-color: color-mix(in oklab, var(--color) 45%, var(--bb-panel));
1258
+ box-shadow: 0 0 0 var(--bb-ring-size) var(--ring);
1259
+ }
1260
+ </style>
1261
+ ```
1262
+
1263
+ ### AmountCell.vue
1264
+
1265
+ ```vue
1266
+ <!-- UploadCenter/AmountCell.vue -->
1267
+ <template>
1268
+ <BbNumberInput
1269
+ v-model="draft"
1270
+ compact
1271
+ hide-label
1272
+ label="Amount"
1273
+ :max-precision="2"
1274
+ :min="0"
1275
+ placeholder="0.00"
1276
+ @blur="commit"
1277
+ @keydown.enter="commit"
1278
+ @keydown.esc="revert"
1279
+ >
1280
+ <template #prefix>$</template>
1281
+ </BbNumberInput>
1282
+ </template>
1283
+
1284
+ <script setup lang="ts">
1285
+ import { ref, watch } from 'vue';
1286
+ import { BbNumberInput } from 'bitboss-ui';
1287
+ import { useUploadCenter } from './context';
1288
+ import type { Receipt } from '@/types';
1289
+
1290
+ const props = defineProps<{ receipt: Receipt }>();
1291
+
1292
+ const ctx = useUploadCenter();
1293
+
1294
+ // Same commit/revert contract as the merchant cell, on the number model.
1295
+ const draft = ref<number | string | null>(props.receipt.amount);
1296
+ watch(
1297
+ () => props.receipt.amount,
1298
+ (value) => {
1299
+ draft.value = value;
1300
+ }
1301
+ );
1302
+
1303
+ const commit = () => {
1304
+ const amount =
1305
+ draft.value === null || draft.value === '' ? null : Number(draft.value);
1306
+ if (amount === props.receipt.amount) return;
1307
+ void ctx.updateReceipt(props.receipt, { amount });
1308
+ };
1309
+ const revert = () => {
1310
+ draft.value = props.receipt.amount;
1311
+ };
1312
+ </script>
1313
+ ```
1314
+
1315
+ ### DateCell.vue
1316
+
1317
+ ```vue
1318
+ <!-- UploadCenter/DateCell.vue -->
1319
+ <template>
1320
+ <!-- Picking a date IS the commit — no blur dance for calendar input.
1321
+ `floating` keeps the model a plain YYYY-MM-DD string. -->
1322
+ <BbDatePickerInput
1323
+ compact
1324
+ floating
1325
+ hide-label
1326
+ label="Expense date"
1327
+ :model-value="receipt.date"
1328
+ placeholder="YYYY-MM-DD"
1329
+ @update:model-value="commit"
1330
+ />
1331
+ </template>
1332
+
1333
+ <script setup lang="ts">
1334
+ import { BbDatePickerInput } from 'bitboss-ui';
1335
+ import { useUploadCenter } from './context';
1336
+ import type { Receipt } from '@/types';
1337
+
1338
+ const props = defineProps<{ receipt: Receipt }>();
1339
+
1340
+ const ctx = useUploadCenter();
1341
+
1342
+ const commit = (value: string | string[] | null) => {
1343
+ const date = Array.isArray(value) ? (value[0] ?? null) : value;
1344
+ if (date === props.receipt.date) return;
1345
+ void ctx.updateReceipt(props.receipt, { date });
1346
+ };
1347
+ </script>
1348
+ ```
1349
+
1350
+ ### RowActions.vue
1351
+
1352
+ ```vue
1353
+ <!-- UploadCenter/RowActions.vue -->
1354
+ <template>
1355
+ <!-- Queue rows: one explicit remove (aborts the transfer). -->
1356
+ <BbButton
1357
+ v-if="row.kind === 'upload'"
1358
+ :aria-label="`Remove ${row.filename} from the queue`"
1359
+ icon="lucide:x"
1360
+ size="sm"
1361
+ variant="ghost"
1362
+ @click="() => ctx.removeUpload(row.id)"
1363
+ />
1364
+
1365
+ <!-- Server receipts: contextual dropdown, entries vary by status. -->
1366
+ <BbDropdown v-else :items="items">
1367
+ <template #activator="{ props }">
1368
+ <BbButton v-bind="props" icon="lucide:ellipsis" size="sm" variant="ghost">
1369
+ Receipt actions
1370
+ </BbButton>
1371
+ </template>
1372
+ </BbDropdown>
1373
+ </template>
1374
+
1375
+ <script setup lang="ts">
1376
+ import { computed } from 'vue';
1377
+ import { BbButton, BbDropdown } from 'bitboss-ui';
1378
+ import { useUploadCenter, type UploadCenterRow } from './context';
1379
+
1380
+ const props = defineProps<{ row: UploadCenterRow }>();
1381
+
1382
+ const ctx = useUploadCenter();
1383
+
1384
+ const items = computed(() => {
1385
+ if (props.row.kind !== 'receipt') return [];
1386
+ const receipt = props.row;
1387
+ const isDraft = receipt.status === 'draft';
1388
+ return [
1389
+ ...(isDraft
1390
+ ? [
1391
+ {
1392
+ key: 'submit',
1393
+ text: 'Submit for approval',
1394
+ 'prepend:icon': 'lucide:send',
1395
+ onClick: () => ctx.submitReceipt(receipt),
1396
+ },
1397
+ ]
1398
+ : []),
1399
+ {
1400
+ // A real file download, not a Nuxt page — a raw `href` triggers a
1401
+ // normal browser navigation instead of being intercepted by the
1402
+ // router, which is what a client-side `to` would otherwise do.
1403
+ key: 'download',
1404
+ text: 'Download original',
1405
+ 'prepend:icon': 'lucide:download',
1406
+ href: `/receipts/${receipt.id}/file`,
1407
+ },
1408
+ ...(isDraft
1409
+ ? [
1410
+ {
1411
+ key: 'remove',
1412
+ text: 'Remove',
1413
+ 'prepend:icon': 'lucide:trash-2',
1414
+ variant: 'destructive' as const,
1415
+ onClick: () => ctx.deleteReceipt(receipt),
1416
+ },
1417
+ ]
1418
+ : []),
1419
+ ];
1420
+ });
1421
+ </script>
1422
+ ```
1423
+
1424
+ ### SelectionBar.vue
1425
+
1426
+ ```vue
1427
+ <!-- UploadCenter/SelectionBar.vue -->
1428
+ <template>
1429
+ <FloatingBottomPanel :open="selectedCount > 0">
1430
+ <span class="px-2 text-sm">{{ selectedCount }} selected</span>
1431
+
1432
+ <!-- Bulk categorize: the picker lives right in the bar — a one-shot
1433
+ popover (model stays null) whose selection IS the action. -->
1434
+ <BbSelectPopover
1435
+ item-text="name"
1436
+ item-value="id"
1437
+ :items="ctx.categories.value"
1438
+ :model-value="null"
1439
+ placement="top"
1440
+ width="220px"
1441
+ @update:model-value="
1442
+ (categoryId) => categoryId && ctx.bulkCategorize(categoryId)
1443
+ "
1444
+ >
1445
+ <template #activator="{ props }">
1446
+ <BbButton
1447
+ v-bind="props"
1448
+ prepend:icon="lucide:tag"
1449
+ size="sm"
1450
+ variant="ghost"
1451
+ >
1452
+ Set category
1453
+ </BbButton>
1454
+ </template>
1455
+ </BbSelectPopover>
1456
+
1457
+ <div class="floating-bottom-panel__right flex items-center gap-1">
1458
+ <BbButton size="sm" variant="destructive" @click="ctx.bulkRemove"
1459
+ >Remove</BbButton
1460
+ >
1461
+ <BbButton
1462
+ aria-label="Clear selection"
1463
+ icon="lucide:x"
1464
+ size="sm"
1465
+ variant="ghost"
1466
+ @click="clearSelection"
1467
+ />
1468
+ </div>
1469
+ </FloatingBottomPanel>
1470
+ </template>
1471
+
1472
+ <script setup lang="ts">
1473
+ import { computed } from 'vue';
1474
+ import { BbButton, BbSelectPopover } from 'bitboss-ui';
1475
+ import FloatingBottomPanel from '@/components/layout/FloatingBottomPanel.vue';
1476
+ import { useUploadCenter } from './context';
1477
+
1478
+ const ctx = useUploadCenter();
1479
+
1480
+ const selectedCount = computed(() => ctx.table.selected.value?.length ?? 0);
1481
+ const clearSelection = () => {
1482
+ ctx.table.selected.value = [];
1483
+ };
1484
+ </script>
1485
+ ```
1486
+
1487
+ ### ReceiptPeek.vue
1488
+
1489
+ ```vue
1490
+ <!-- UploadCenter/ReceiptPeek.vue -->
1491
+ <template>
1492
+ <div v-if="receipt" class="flex flex-col gap-4 text-sm">
1493
+ <!-- Header: merchant identity + amount + status. The merchant name
1494
+ drills DOWN — stacked peek, back arrow via the shell. -->
1495
+ <header class="flex flex-col gap-1.5">
1496
+ <div class="flex items-center justify-between gap-2">
1497
+ <BbButton
1498
+ v-if="receipt.merchant"
1499
+ size="sm"
1500
+ variant="link"
1501
+ @click="() => ctx.stackMerchant(receipt!.merchant!)"
1502
+ >
1503
+ {{ receipt.merchant }}
1504
+ </BbButton>
1505
+ <span v-else class="text-[color:var(--bb-text-muted)]"
1506
+ >No merchant yet</span
1507
+ >
1508
+ <BbBadge variant="outline">{{ receipt.status }}</BbBadge>
1509
+ </div>
1510
+ <p class="text-xl font-semibold">
1511
+ {{
1512
+ receipt.amount === null
1513
+ ? 'Amount missing'
1514
+ : currency.format(receipt.amount)
1515
+ }}
1516
+ </p>
1517
+ <p class="text-xs text-[color:var(--bb-text-muted)]">
1518
+ {{ receipt.filename }} · spent
1519
+ {{ receipt.date ? longDate(receipt.date) : '—' }}
1520
+ </p>
1521
+ </header>
1522
+
1523
+ <!-- Preview placeholder: the real app renders the scanned image here. -->
1524
+ <div
1525
+ class="flex h-44 flex-col items-center justify-center gap-1 rounded-[var(--bb-radius)] border bg-[var(--bb-panel)] text-[color:var(--bb-text-muted)]"
1526
+ >
1527
+ <BbIcon icon="lucide:receipt" size="lg" />
1528
+ <span class="text-xs">Receipt preview</span>
1529
+ </div>
1530
+
1531
+ <!-- Extracted fields: what OCR read off the scan, with confidence. -->
1532
+ <section class="flex flex-col gap-1.5">
1533
+ <div class="flex items-center justify-between">
1534
+ <h3
1535
+ class="text-xs font-semibold uppercase tracking-wide text-[color:var(--bb-text-muted)]"
1536
+ >
1537
+ Extracted fields
1538
+ </h3>
1539
+ <BbBadge size="xs" variant="outline">{{
1540
+ `OCR · ${receipt.extracted.confidence}%`
1541
+ }}</BbBadge>
1542
+ </div>
1543
+ <dl class="grid grid-cols-[auto_1fr] gap-x-4 gap-y-1.5">
1544
+ <dt class="text-[color:var(--bb-text-muted)]">Merchant</dt>
1545
+ <dd>{{ receipt.extracted.merchant ?? '—' }}</dd>
1546
+ <dt class="text-[color:var(--bb-text-muted)]">Total</dt>
1547
+ <dd>
1548
+ {{
1549
+ receipt.extracted.total === null
1550
+ ? '—'
1551
+ : currency.format(receipt.extracted.total)
1552
+ }}
1553
+ </dd>
1554
+ <dt class="text-[color:var(--bb-text-muted)]">Tax</dt>
1555
+ <dd>
1556
+ {{
1557
+ receipt.extracted.tax === null
1558
+ ? '—'
1559
+ : currency.format(receipt.extracted.tax)
1560
+ }}
1561
+ </dd>
1562
+ <dt class="text-[color:var(--bb-text-muted)]">Date</dt>
1563
+ <dd>
1564
+ {{ receipt.extracted.date ? longDate(receipt.extracted.date) : '—' }}
1565
+ </dd>
1566
+ <dt class="text-[color:var(--bb-text-muted)]">Paid with</dt>
1567
+ <dd>{{ receipt.extracted.paymentMethod ?? '—' }}</dd>
1568
+ </dl>
1569
+ </section>
1570
+
1571
+ <!-- Properties: the peek is a workbench — the category is the same
1572
+ one-click cell as in the table. -->
1573
+ <section class="flex flex-col gap-1.5">
1574
+ <h3
1575
+ class="text-xs font-semibold uppercase tracking-wide text-[color:var(--bb-text-muted)]"
1576
+ >
1577
+ Details
1578
+ </h3>
1579
+ <dl class="grid grid-cols-[auto_1fr] items-center gap-x-4 gap-y-1.5">
1580
+ <dt class="text-[color:var(--bb-text-muted)]">Category</dt>
1581
+ <dd><CategoryCell :receipt="receipt" /></dd>
1582
+ <dt class="text-[color:var(--bb-text-muted)]">Uploaded</dt>
1583
+ <dd>{{ longDate(receipt.uploadedAt) }}</dd>
1584
+ <dt class="text-[color:var(--bb-text-muted)]">Report</dt>
1585
+ <dd>{{ receipt.reportName ?? 'Not on a report yet' }}</dd>
1586
+ </dl>
1587
+ </section>
1588
+
1589
+ <!-- Activity feed. -->
1590
+ <section class="flex flex-col gap-1.5">
1591
+ <h3
1592
+ class="text-xs font-semibold uppercase tracking-wide text-[color:var(--bb-text-muted)]"
1593
+ >
1594
+ Activity
1595
+ </h3>
1596
+ <ul class="flex flex-col gap-2">
1597
+ <li
1598
+ v-for="entry in receipt.activity"
1599
+ :key="entry.id"
1600
+ class="flex gap-2"
1601
+ >
1602
+ <BbIcon
1603
+ class="mt-0.5 shrink-0 text-[color:var(--bb-text-muted)]"
1604
+ :icon="entry.icon"
1605
+ size="14"
1606
+ />
1607
+ <div class="flex flex-col">
1608
+ <span>{{ entry.text }}</span>
1609
+ <span class="text-xs text-[color:var(--bb-text-muted)]"
1610
+ >{{ entry.actor }} · {{ longDate(entry.at) }}</span
1611
+ >
1612
+ </div>
1613
+ </li>
1614
+ </ul>
1615
+ </section>
1616
+
1617
+ <!-- Act here, or leave for the original file. -->
1618
+ <footer class="mt-2 flex items-center gap-2 border-t pt-3">
1619
+ <BbButton
1620
+ v-if="receipt.status === 'draft'"
1621
+ prepend:icon="lucide:send"
1622
+ size="sm"
1623
+ variant="secondary"
1624
+ @click="() => ctx.submitReceipt(receipt!)"
1625
+ >
1626
+ Submit
1627
+ </BbButton>
1628
+ <!-- A real file download, not a Nuxt page — stays a raw `href`. -->
1629
+ <BbButton
1630
+ append:icon="lucide:arrow-up-right"
1631
+ :href="`/receipts/${receipt.id}/file`"
1632
+ size="sm"
1633
+ variant="ghost"
1634
+ >
1635
+ Download original
1636
+ </BbButton>
1637
+ <BbButton
1638
+ v-if="receipt.status === 'draft'"
1639
+ class="ml-auto"
1640
+ prepend:icon="lucide:trash-2"
1641
+ size="sm"
1642
+ variant="destructive"
1643
+ @click="removeAndClose"
1644
+ >
1645
+ Remove
1646
+ </BbButton>
1647
+ </footer>
1648
+ </div>
1649
+
1650
+ <div v-else class="flex justify-center p-8">
1651
+ <BbSpinner />
1652
+ </div>
1653
+ </template>
1654
+
1655
+ <script setup lang="ts">
1656
+ import { ref, watchEffect } from 'vue';
1657
+ import { BbBadge, BbButton, BbIcon, BbSpinner } from 'bitboss-ui';
1658
+ import CategoryCell from './CategoryCell.vue';
1659
+ import { useUploadCenter } from './context';
1660
+ import type { ReceiptDetail } from '@/types';
1661
+
1662
+ const props = defineProps<{ receiptId: string }>();
1663
+
1664
+ const ctx = useUploadCenter();
1665
+
1666
+ // Re-fetches whenever the stack shows a different receipt; `ctx.rows` changes
1667
+ // on every server `refresh()` (mutations) or upload completion, so watching
1668
+ // it makes inline edits (category, submit) reflect here immediately.
1669
+ const receipt = ref<ReceiptDetail | null>(null);
1670
+ watchEffect(async () => {
1671
+ void ctx.rows.value;
1672
+ receipt.value = await $fetch<ReceiptDetail>(
1673
+ `/api/receipts/${props.receiptId}`
1674
+ );
1675
+ });
1676
+
1677
+ // deleteReceipt resolves true only when the confirm was accepted — don't
1678
+ // close the peek on a cancelled dialog.
1679
+ const removeAndClose = async () => {
1680
+ if (!receipt.value) return;
1681
+ if (await ctx.deleteReceipt(receipt.value)) ctx.shell.close();
1682
+ };
1683
+
1684
+ const currency = new Intl.NumberFormat('en-US', {
1685
+ style: 'currency',
1686
+ currency: 'USD',
1687
+ });
1688
+ const longDate = (value: string) =>
1689
+ new Date(value).toLocaleDateString('en-US', {
1690
+ month: 'short',
1691
+ day: 'numeric',
1692
+ year: 'numeric',
1693
+ });
1694
+ </script>
1695
+ ```
1696
+
1697
+ ### MerchantPeek.vue
1698
+
1699
+ ```vue
1700
+ <!-- UploadCenter/MerchantPeek.vue -->
1701
+ <template>
1702
+ <div v-if="merchant" class="flex flex-col gap-4 text-sm">
1703
+ <header class="flex items-center gap-3">
1704
+ <div
1705
+ class="grid h-9 w-9 shrink-0 place-items-center rounded-[var(--bb-radius)] border"
1706
+ >
1707
+ <BbIcon
1708
+ class="text-[color:var(--bb-text-muted)]"
1709
+ icon="lucide:store"
1710
+ size="18"
1711
+ />
1712
+ </div>
1713
+ <div class="flex flex-col">
1714
+ <h2 class="text-base font-semibold">{{ merchant.name }}</h2>
1715
+ <p class="text-xs text-[color:var(--bb-text-muted)]">
1716
+ {{ merchant.defaultCategoryName }} · this year
1717
+ </p>
1718
+ </div>
1719
+ </header>
1720
+
1721
+ <!-- Stat strip. -->
1722
+ <div class="grid grid-cols-3 gap-2">
1723
+ <div class="rounded-[var(--bb-radius)] border p-2">
1724
+ <p class="text-xs text-[color:var(--bb-text-muted)]">Total spent</p>
1725
+ <p class="font-semibold">{{ currency.format(merchant.totalSpent) }}</p>
1726
+ </div>
1727
+ <div class="rounded-[var(--bb-radius)] border p-2">
1728
+ <p class="text-xs text-[color:var(--bb-text-muted)]">Receipts</p>
1729
+ <p class="font-semibold">{{ merchant.receiptCount }}</p>
1730
+ </div>
1731
+ <div class="rounded-[var(--bb-radius)] border p-2">
1732
+ <p class="text-xs text-[color:var(--bb-text-muted)]">Average</p>
1733
+ <p class="font-semibold">
1734
+ {{ currency.format(merchant.averageAmount) }}
1735
+ </p>
1736
+ </div>
1737
+ </div>
1738
+
1739
+ <!-- Recent receipts: names drill down again — the stack keeps growing. -->
1740
+ <section class="flex flex-col gap-1.5">
1741
+ <h3
1742
+ class="text-xs font-semibold uppercase tracking-wide text-[color:var(--bb-text-muted)]"
1743
+ >
1744
+ Recent receipts
1745
+ </h3>
1746
+ <ul class="flex flex-col">
1747
+ <li
1748
+ v-for="recent in merchant.recentReceipts"
1749
+ :key="recent.id"
1750
+ class="flex items-center justify-between gap-2 border-b py-1.5 last:border-b-0"
1751
+ >
1752
+ <BbButton
1753
+ size="sm"
1754
+ variant="link"
1755
+ @click="() => ctx.stackReceipt(recent.id)"
1756
+ >
1757
+ {{ recent.filename }}
1758
+ </BbButton>
1759
+ <BbBadge variant="outline">{{ recent.status }}</BbBadge>
1760
+ <span class="text-xs tabular-nums text-[color:var(--bb-text-muted)]">
1761
+ {{ currency.format(recent.amount) }}
1762
+ </span>
1763
+ </li>
1764
+ </ul>
1765
+ </section>
1766
+
1767
+ <footer class="mt-2 flex items-center gap-2 border-t pt-3">
1768
+ <!-- An internal listing page — a real Nuxt route, so this uses `to`. -->
1769
+ <BbButton
1770
+ append:icon="lucide:arrow-up-right"
1771
+ size="sm"
1772
+ :to="`/expenses/receipts?merchant=${encodeURIComponent(merchant.name)}`"
1773
+ variant="ghost"
1774
+ >
1775
+ All receipts from {{ merchant.name }}
1776
+ </BbButton>
1777
+ </footer>
1778
+ </div>
1779
+
1780
+ <div v-else class="flex justify-center p-8">
1781
+ <BbSpinner />
1782
+ </div>
1783
+ </template>
1784
+
1785
+ <script setup lang="ts">
1786
+ import { ref, watchEffect } from 'vue';
1787
+ import { BbBadge, BbButton, BbIcon, BbSpinner } from 'bitboss-ui';
1788
+ import { useUploadCenter } from './context';
1789
+ import type { MerchantSummary } from '@/types';
1790
+
1791
+ const props = defineProps<{ merchantName: string }>();
1792
+
1793
+ const ctx = useUploadCenter();
1794
+
1795
+ const merchant = ref<MerchantSummary | null>(null);
1796
+ watchEffect(async () => {
1797
+ merchant.value = await $fetch<MerchantSummary>(
1798
+ `/api/merchants/${encodeURIComponent(props.merchantName)}`
1799
+ );
1800
+ });
1801
+
1802
+ const currency = new Intl.NumberFormat('en-US', {
1803
+ style: 'currency',
1804
+ currency: 'USD',
1805
+ });
1806
+ </script>
1807
+ ```
1808
+
1809
+ ## Why it is built this way
1810
+
1811
+ - **The context coopts, leaves consume.** `shell`, `table` **and the
1812
+ category catalog** are joined once in `provideUploadCenter()`; thirteen
1813
+ components share the filters, the queue, selection, the peek stack and
1814
+ every action through one `useUploadCenter()` call. No leaf imports
1815
+ `$fetch`, `@/api` or a store directly — even the query-aware merchant
1816
+ pill gets its provider (`ctx.searchMerchants`) from the context, so the
1817
+ page has exactly one import surface.
1818
+ - **The URL is the filter store, `useAsyncData` is the fetch.** Filters
1819
+ and tab are seeded from `route.query` once at setup, mirrored back with
1820
+ `navigateTo` on every change (debounced for free text), and
1821
+ `useAsyncData('receipts', …, { watch: [() => route.query, table.page] })`
1822
+ is the single refetch trigger for the _server_ page — there is exactly
1823
+ one place server data loads.
1824
+ - **The upload queue crosses the data-layer swap untouched.** It was
1825
+ always client-only reactive state, so it needed no adaptation: `uploads`
1826
+ stays a plain `ref`, progress ticks still mutate the row objects in
1827
+ place, and `rows` (a computed merging `uploads` ahead of the fetched
1828
+ `serverRows`) is what `BbTable` binds to directly — no items function, no
1829
+ `dependencies`, no `refreshKey`. A completed upload's own `refresh()`
1830
+ call is what swaps it into `serverRows` on the next tick.
1831
+ - **`$fetch` can't stream upload progress, so the transfer itself doesn't
1832
+ use it.** `api.receipts.upload()` posts `FormData` through a small XHR
1833
+ wrapper instead — the only place this recipe steps outside `$fetch` —
1834
+ while every other mutation (`updateReceipt`, `submitReceipt`, the bulk
1835
+ actions) is a plain `$fetch` call followed by `await refresh()`.
1836
+ - **The table context still owns paging and selection.** `useBbTableContext`
1837
+ is unchanged from the Vue recipe: it seeds `perPage`, `BbPagination`
1838
+ joins by `table-id`, and `SelectionBar` reads `table.selected` — only the
1839
+ _server_ rows move from an items-function to a resolved array merged
1840
+ into `rows`.
1841
+ - **Peeks watch `ctx.rows.value`, not a manual refresh counter.** Since
1842
+ every mutation already calls the list's `refresh()`, and `rows` recomputes
1843
+ whenever the underlying `data` changes, a peek's `watchEffect(() => {
1844
+ void ctx.rows.value; … })` re-fetches its own JSON detail for free — the
1845
+ same signal drives both surfaces.
1846
+ - **`peekX` vs `stackX` is the whole stack grammar.** Filename →
1847
+ `peekReceipt` (replaces the stack); merchant name inside the peek →
1848
+ `stackMerchant` (pushes, back arrow appears); a recent receipt inside
1849
+ the merchant peek → `stackReceipt` (deeper still). The grammar lives in
1850
+ the context — a leaf cannot accidentally nuke the stack.
1851
+ - **Tabs carry `href` and live counts**, exactly as in the Vue recipe — the
1852
+ client-side pushState they perform keeps `route.query.tab` in sync, which
1853
+ is what seeds `tab` on load and what `useAsyncData`'s `route.query` watch
1854
+ reacts to.
1855
+ - **Internal links use `to`; real file downloads stay `href`.** The
1856
+ merchant peek's "All receipts from…" link is a genuine Nuxt route, so it
1857
+ uses `to` for client-side navigation. "Download original" (row `…`, peek
1858
+ footer) hits a raw file-serving endpoint, not a page — it deliberately
1859
+ keeps a plain `href` so the browser performs a real download instead of
1860
+ the router trying to resolve it as a route.
1861
+ - **Sizing:** topbar follows `md`-first (`compact` search at 28px flush
1862
+ beside the default-size primary); `sm` appears exactly where the
1863
+ doctrine allows — row actions, pills, peek footers, the bulk bar — and
1864
+ the one `xs` (inline Retry) sits inside a table cell, the densest
1865
+ surface on the page. **One `variant="primary"`** (Submit all, with its
1866
+ live count and auto-tracked loading). Destructive actions — single,
1867
+ bulk, in-peek — all ride `useConfirm` with the filename or count in the
1868
+ message.
1869
+
1870
+ ## Variations
1871
+
1872
+ - **Expense reports**: group receipts into named reports (a `reportId`
1873
+ column + a "Add to report" bulk action feeding a `BbSelectPopover` of
1874
+ open reports); the Submit-all primary becomes "Submit report".
1875
+ - **Policy checks**: server flags out-of-policy drafts
1876
+ (`receipt.policyWarning`); tint the row, badge the amount cell, and
1877
+ render a `BbAlert` above the table summarizing the count.
1878
+ - **Camera-first mobile**: keep `accept` image-heavy and rely on the
1879
+ native picker offering the camera; the dropzone slot collapses to a
1880
+ single "Snap a receipt" affordance under the mobile breakpoint.
1881
+ - **Auto-submit on high confidence**: when `extracted.confidence` ≥ 95 and
1882
+ all four fields resolved, submit server-side on upload and toast an
1883
+ undo — the Drafts tab then only holds receipts needing review.
1884
+ - **SSR-populated peeks**: swap the peeks' `$fetch` calls for
1885
+ `useAsyncData` keyed by id if the peek content should be part of the
1886
+ server-rendered payload rather than a client-side follow-up fetch.