bitboss-ui 2.1.135 → 3.0.0-alpha.4

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