bitboss-ui 2.1.134 → 3.0.0-alpha.1

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