bitboss-ui 2.1.135 → 3.0.0-alpha.1

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