bitboss-ui 2.1.135 → 3.0.0-alpha.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (1369) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +274 -24
  3. package/bin/bitboss-ui-mcp.mjs +662 -0
  4. package/bin/bitboss-ui.mjs +710 -0
  5. package/bin/bitboss-ui.node.test.mjs +113 -0
  6. package/dist/ai/BbAccordion.md +528 -113
  7. package/dist/ai/BbAlert.md +380 -197
  8. package/dist/ai/BbAsterisk.md +46 -0
  9. package/dist/ai/BbAvatar.md +458 -178
  10. package/dist/ai/BbBadge.md +697 -225
  11. package/dist/ai/BbBadgeButton.md +54 -0
  12. package/dist/ai/BbBaseButton.md +491 -0
  13. package/dist/ai/BbBaseCheckbox.md +49 -0
  14. package/dist/ai/BbBaseCheckboxGroup.md +64 -0
  15. package/dist/ai/BbBaseCheckboxIcon.md +176 -0
  16. package/dist/ai/BbBaseColorInput.md +64 -0
  17. package/dist/ai/BbBaseColorPalette.md +39 -0
  18. package/dist/ai/BbBaseDatePicker.md +42 -0
  19. package/dist/ai/BbBaseDatePickerInput.md +73 -0
  20. package/dist/ai/BbBaseInputContainer.md +48 -0
  21. package/dist/ai/BbBaseNumberInput.md +71 -0
  22. package/dist/ai/BbBaseRadio.md +46 -0
  23. package/dist/ai/BbBaseRadioGroup.md +64 -0
  24. package/dist/ai/BbBaseRadioIcon.md +191 -0
  25. package/dist/ai/BbBaseRating.md +51 -0
  26. package/dist/ai/BbBaseSelect.md +88 -0
  27. package/dist/ai/BbBaseSlider.md +56 -0
  28. package/dist/ai/BbBaseSwitch.md +49 -0
  29. package/dist/ai/BbBaseSwitchGroup.md +64 -0
  30. package/dist/ai/BbBaseSwitchIcon.md +186 -0
  31. package/dist/ai/BbBaseTag.md +68 -0
  32. package/dist/ai/BbBaseTextInput.md +75 -0
  33. package/dist/ai/BbBaseTextarea.md +62 -0
  34. package/dist/ai/BbBaseTimePickerInput.md +62 -0
  35. package/dist/ai/BbBreadcrumbs.md +553 -503
  36. package/dist/ai/BbButton.md +841 -636
  37. package/dist/ai/BbCheckbox.md +585 -254
  38. package/dist/ai/BbCheckboxGroup.md +573 -361
  39. package/dist/ai/BbCollapsible.md +425 -103
  40. package/dist/ai/BbColorInput.md +536 -323
  41. package/dist/ai/BbColorPalette.md +569 -330
  42. package/dist/ai/BbConfirm.md +659 -136
  43. package/dist/ai/BbConfirmPortal.md +28 -0
  44. package/dist/ai/BbDatePicker.md +244 -0
  45. package/dist/ai/BbDatePickerInput.md +720 -388
  46. package/dist/ai/BbDialog.md +778 -99
  47. package/dist/ai/BbDropdown.md +1072 -763
  48. package/dist/ai/BbDropdownButton.md +525 -614
  49. package/dist/ai/BbDropdownGroup.md +34 -0
  50. package/dist/ai/BbDropzone.md +1206 -436
  51. package/dist/ai/BbForm.md +239 -0
  52. package/dist/ai/BbIcon.md +382 -212
  53. package/dist/ai/BbIndicator.md +283 -0
  54. package/dist/ai/BbNumberInput.md +717 -355
  55. package/dist/ai/BbOffCanvas.md +897 -498
  56. package/dist/ai/BbPagination.md +489 -535
  57. package/dist/ai/BbPopover.md +591 -546
  58. package/dist/ai/BbProgress.md +462 -69
  59. package/dist/ai/BbRadio.md +352 -229
  60. package/dist/ai/BbRadioGroup.md +437 -353
  61. package/dist/ai/BbRating.md +372 -225
  62. package/dist/ai/BbSelect.md +1399 -536
  63. package/dist/ai/BbSelectPopover.md +1255 -1578
  64. package/dist/ai/BbSlider.md +500 -256
  65. package/dist/ai/BbSmoothHeight.md +485 -139
  66. package/dist/ai/BbSpinner.md +718 -131
  67. package/dist/ai/BbSwitch.md +573 -119
  68. package/dist/ai/BbSwitchGroup.md +521 -214
  69. package/dist/ai/BbTable.md +1996 -2365
  70. package/dist/ai/BbTabs.md +1147 -0
  71. package/dist/ai/BbTabsList.md +29 -0
  72. package/dist/ai/BbTabsPanes.md +27 -0
  73. package/dist/ai/BbTabsRoot.md +57 -0
  74. package/dist/ai/BbTag.md +416 -292
  75. package/dist/ai/BbTextInput.md +878 -333
  76. package/dist/ai/BbTextarea.md +850 -255
  77. package/dist/ai/BbTimePicker.md +231 -0
  78. package/dist/ai/BbTimePickerInput.md +200 -0
  79. package/dist/ai/BbToast.md +669 -196
  80. package/dist/ai/BbToastPortal.md +28 -0
  81. package/dist/ai/BbTooltip.md +453 -346
  82. package/dist/ai/BbTree.md +993 -234
  83. package/dist/ai/ChipsBox.md +27 -199
  84. package/dist/ai/ClearableButton.md +21 -55
  85. package/dist/ai/CommaBox.md +25 -200
  86. package/dist/ai/CommonInputWrapper.md +42 -0
  87. package/dist/ai/CommonPopover.md +30 -510
  88. package/dist/ai/ErrorIcon.md +19 -56
  89. package/dist/ai/FlatListBox.md +35 -379
  90. package/dist/ai/GroupedListBox.md +37 -535
  91. package/dist/ai/GuidesComponent.md +21 -0
  92. package/dist/ai/ListBox.md +38 -231
  93. package/dist/ai/OptionsContainer.md +34 -253
  94. package/dist/ai/WarningIcon.md +21 -0
  95. package/dist/ai/components.json +15897 -0
  96. package/dist/ai/composables/useBbConfig.md +80 -0
  97. package/dist/ai/composables/useBbFormContext.md +110 -0
  98. package/dist/ai/composables/useBbTableContext.md +167 -0
  99. package/dist/ai/composables/useBbTabsContext.md +118 -0
  100. package/dist/ai/composables/useBroadcastChannelInstance.md +97 -0
  101. package/dist/ai/composables/useConfirm.md +313 -0
  102. package/dist/ai/composables/useCountdown.md +86 -0
  103. package/dist/ai/composables/useId.md +60 -0
  104. package/dist/ai/composables/useMobile.md +85 -0
  105. package/dist/ai/composables/useToast.md +238 -0
  106. package/dist/ai/guides/agent-contract.md +165 -0
  107. package/dist/ai/guides/ai-router.md +113 -0
  108. package/dist/ai/guides/app-layout.md +318 -0
  109. package/dist/ai/guides/coherence-playbook.md +136 -0
  110. package/dist/ai/guides/component-picker.md +236 -0
  111. package/dist/ai/guides/design-language.md +478 -0
  112. package/dist/ai/guides/design-tokens.md +450 -0
  113. package/dist/ai/guides/fetch-items-playbook.md +161 -0
  114. package/dist/ai/guides/floating-bottom-panel.md +130 -0
  115. package/dist/ai/guides/icons-policy.md +257 -0
  116. package/dist/ai/guides/inertia-helpers.md +1443 -0
  117. package/dist/ai/guides/inline-edit-playbook.md +267 -0
  118. package/dist/ai/guides/installation-and-plugin-setup.md +440 -0
  119. package/dist/ai/guides/migration/components/bb-alert.md +37 -0
  120. package/dist/ai/guides/migration/components/bb-avatar.md +24 -0
  121. package/dist/ai/guides/migration/components/bb-badge.md +110 -0
  122. package/dist/ai/guides/migration/components/bb-breadcrumbs.md +26 -0
  123. package/dist/ai/guides/migration/components/bb-button.md +55 -0
  124. package/dist/ai/guides/migration/components/bb-checkbox-group.md +54 -0
  125. package/dist/ai/guides/migration/components/bb-checkbox.md +45 -0
  126. package/dist/ai/guides/migration/components/bb-chip.md +35 -0
  127. package/dist/ai/guides/migration/components/bb-collapsible.md +26 -0
  128. package/dist/ai/guides/migration/components/bb-color-input.md +23 -0
  129. package/dist/ai/guides/migration/components/bb-color-palette.md +31 -0
  130. package/dist/ai/guides/migration/components/bb-date-picker-input.md +84 -0
  131. package/dist/ai/guides/migration/components/bb-dialog.md +46 -0
  132. package/dist/ai/guides/migration/components/bb-dropdown-button.md +31 -0
  133. package/dist/ai/guides/migration/components/bb-dropdown.md +36 -0
  134. package/dist/ai/guides/migration/components/bb-dropzone.md +27 -0
  135. package/dist/ai/guides/migration/components/bb-icon.md +27 -0
  136. package/dist/ai/guides/migration/components/bb-offcanvas.md +63 -0
  137. package/dist/ai/guides/migration/components/bb-pagination.md +24 -0
  138. package/dist/ai/guides/migration/components/bb-popover.md +52 -0
  139. package/dist/ai/guides/migration/components/bb-rating.md +24 -0
  140. package/dist/ai/guides/migration/components/bb-select-popover.md +59 -0
  141. package/dist/ai/guides/migration/components/bb-select.md +69 -0
  142. package/dist/ai/guides/migration/components/bb-slider.md +25 -0
  143. package/dist/ai/guides/migration/components/bb-smooth-height.md +45 -0
  144. package/dist/ai/guides/migration/components/bb-spinner.md +23 -0
  145. package/dist/ai/guides/migration/components/bb-table.md +66 -0
  146. package/dist/ai/guides/migration/components/bb-tabs.md +47 -0
  147. package/dist/ai/guides/migration/components/bb-tag.md +29 -0
  148. package/dist/ai/guides/migration/components/bb-text-input.md +37 -0
  149. package/dist/ai/guides/migration/components/bb-toast.md +47 -0
  150. package/dist/ai/guides/migration/components/bb-tooltip.md +34 -0
  151. package/dist/ai/guides/migration/components/bb-tree.md +77 -0
  152. package/dist/ai/guides/migration/components/use-confirm.md +46 -0
  153. package/dist/ai/guides/migration/v2-to-v3.md +649 -0
  154. package/dist/ai/guides/options-items-playbook.md +222 -0
  155. package/dist/ai/guides/page-shell.md +113 -0
  156. package/dist/ai/guides/validated-forms.md +177 -0
  157. package/dist/ai/index.md +158 -32
  158. package/dist/ai/recipes/inertia/approvals-inbox.md +1635 -0
  159. package/dist/ai/recipes/inertia/inline-edit-workspace.md +1765 -0
  160. package/dist/ai/recipes/inertia/layout-scaffold.md +385 -0
  161. package/dist/ai/recipes/inertia/onboarding.md +1791 -0
  162. package/dist/ai/recipes/inertia/ownership-atlas.md +1327 -0
  163. package/dist/ai/recipes/inertia/record-form.md +1489 -0
  164. package/dist/ai/recipes/inertia/records-workspace.md +1416 -0
  165. package/dist/ai/recipes/inertia/upload-center.md +2003 -0
  166. package/dist/ai/recipes/inertia/wizard-form.md +1500 -0
  167. package/dist/ai/recipes/nuxt/approvals-inbox.md +1578 -0
  168. package/dist/ai/recipes/nuxt/inline-edit-workspace.md +1703 -0
  169. package/dist/ai/recipes/nuxt/layout-scaffold.md +385 -0
  170. package/dist/ai/recipes/nuxt/onboarding.md +1724 -0
  171. package/dist/ai/recipes/nuxt/record-form.md +1502 -0
  172. package/dist/ai/recipes/nuxt/records-workspace.md +1329 -0
  173. package/dist/ai/recipes/nuxt/upload-center.md +1886 -0
  174. package/dist/ai/recipes/nuxt/wizard-form.md +1509 -0
  175. package/dist/ai/recipes/vue/approvals-inbox.md +1496 -0
  176. package/dist/ai/recipes/vue/inline-edit-workspace.md +1594 -0
  177. package/dist/ai/recipes/vue/layout-scaffold.md +385 -0
  178. package/dist/ai/recipes/vue/onboarding.md +1679 -0
  179. package/dist/ai/recipes/vue/record-form.md +1586 -0
  180. package/dist/ai/recipes/vue/records-workspace.md +1245 -0
  181. package/dist/ai/recipes/vue/upload-center.md +1845 -0
  182. package/dist/ai/recipes/vue/wizard-form.md +1441 -0
  183. package/dist/ai/source/BbAccordion.md +123 -0
  184. package/dist/ai/source/BbAlert.md +401 -0
  185. package/dist/ai/source/BbAsterisk.md +32 -0
  186. package/dist/ai/source/BbAvatar.md +258 -0
  187. package/dist/ai/source/BbBadge.md +560 -0
  188. package/dist/ai/source/BbBadgeButton.md +490 -0
  189. package/dist/ai/source/BbBaseButton.md +682 -0
  190. package/dist/ai/source/BbBaseCheckbox.md +461 -0
  191. package/dist/ai/source/BbBaseCheckboxGroup.md +554 -0
  192. package/dist/ai/source/BbBaseCheckboxIcon.md +201 -0
  193. package/dist/ai/source/BbBaseColorInput.md +416 -0
  194. package/dist/ai/source/BbBaseColorPalette.md +934 -0
  195. package/dist/ai/source/BbBaseDatePicker.md +1001 -0
  196. package/dist/ai/source/BbBaseDatePickerInput.md +1785 -0
  197. package/dist/ai/source/BbBaseInputContainer.md +1210 -0
  198. package/dist/ai/source/BbBaseNumberInput.md +617 -0
  199. package/dist/ai/source/BbBaseRadio.md +377 -0
  200. package/dist/ai/source/BbBaseRadioGroup.md +533 -0
  201. package/dist/ai/source/BbBaseRadioIcon.md +153 -0
  202. package/dist/ai/source/BbBaseRating.md +573 -0
  203. package/dist/ai/source/BbBaseSelect.md +898 -0
  204. package/dist/ai/source/BbBaseSlider.md +1085 -0
  205. package/dist/ai/source/BbBaseSwitch.md +246 -0
  206. package/dist/ai/source/BbBaseSwitchGroup.md +302 -0
  207. package/dist/ai/source/BbBaseSwitchIcon.md +206 -0
  208. package/dist/ai/source/BbBaseTag.md +694 -0
  209. package/dist/ai/source/BbBaseTextInput.md +511 -0
  210. package/dist/ai/source/BbBaseTextarea.md +480 -0
  211. package/dist/ai/source/BbBaseTimePickerInput.md +1031 -0
  212. package/dist/ai/source/BbBreadcrumbs.md +815 -0
  213. package/dist/ai/source/BbButton.md +1006 -0
  214. package/dist/ai/source/BbCheckbox.md +326 -0
  215. package/dist/ai/source/BbCheckboxGroup.md +419 -0
  216. package/dist/ai/source/BbCollapsible.md +137 -0
  217. package/dist/ai/source/BbColorInput.md +322 -0
  218. package/dist/ai/source/BbColorPalette.md +371 -0
  219. package/dist/ai/source/BbConfirm.md +193 -0
  220. package/dist/ai/source/BbConfirmPortal.md +74 -0
  221. package/dist/ai/source/BbDatePicker.md +729 -0
  222. package/dist/ai/source/BbDatePickerInput.md +525 -0
  223. package/dist/ai/source/BbDialog.md +818 -0
  224. package/dist/ai/source/BbDropdown.md +2387 -0
  225. package/dist/ai/source/BbDropdownButton.md +315 -0
  226. package/dist/ai/source/BbDropdownGroup.md +1259 -0
  227. package/dist/ai/source/BbDropzone.md +864 -0
  228. package/dist/ai/source/BbForm.md +100 -0
  229. package/dist/ai/source/BbIcon.md +214 -0
  230. package/dist/ai/source/BbIndicator.md +298 -0
  231. package/dist/ai/source/BbNumberInput.md +374 -0
  232. package/dist/ai/source/BbOffCanvas.md +1266 -0
  233. package/dist/ai/source/BbPagination.md +835 -0
  234. package/dist/ai/source/BbPopover.md +860 -0
  235. package/dist/ai/source/BbProgress.md +140 -0
  236. package/dist/ai/source/BbRadio.md +303 -0
  237. package/dist/ai/source/BbRadioGroup.md +420 -0
  238. package/dist/ai/source/BbRating.md +369 -0
  239. package/dist/ai/source/BbSelect.md +688 -0
  240. package/dist/ai/source/BbSelectPopover.md +2234 -0
  241. package/dist/ai/source/BbSlider.md +378 -0
  242. package/dist/ai/source/BbSmoothHeight.md +265 -0
  243. package/dist/ai/source/BbSpinner.md +127 -0
  244. package/dist/ai/source/BbSwitch.md +175 -0
  245. package/dist/ai/source/BbSwitchGroup.md +240 -0
  246. package/dist/ai/source/BbTable.md +3433 -0
  247. package/dist/ai/source/BbTabs.md +403 -0
  248. package/dist/ai/source/BbTabsList.md +578 -0
  249. package/dist/ai/source/BbTabsPanes.md +368 -0
  250. package/dist/ai/source/BbTabsRoot.md +372 -0
  251. package/dist/ai/source/BbTag.md +390 -0
  252. package/dist/ai/source/BbTextInput.md +352 -0
  253. package/dist/ai/source/BbTextarea.md +337 -0
  254. package/dist/ai/source/BbTimePicker.md +595 -0
  255. package/dist/ai/source/BbTimePickerInput.md +376 -0
  256. package/dist/ai/source/BbToast.md +525 -0
  257. package/dist/ai/source/BbToastPortal.md +482 -0
  258. package/dist/ai/source/BbTooltip.md +522 -0
  259. package/dist/ai/source/BbTree.md +323 -0
  260. package/dist/ai/source/ChipsBox.md +201 -0
  261. package/dist/ai/source/ClearableButton.md +70 -0
  262. package/dist/ai/source/CommaBox.md +202 -0
  263. package/dist/ai/source/CommonInputWrapper.md +554 -0
  264. package/dist/ai/source/CommonPopover.md +616 -0
  265. package/dist/ai/source/ErrorIcon.md +43 -0
  266. package/dist/ai/source/FlatListBox.md +396 -0
  267. package/dist/ai/source/GroupedListBox.md +540 -0
  268. package/dist/ai/source/GuidesComponent.md +383 -0
  269. package/dist/ai/source/ListBox.md +238 -0
  270. package/dist/ai/source/OptionsContainer.md +191 -0
  271. package/dist/ai/source/WarningIcon.md +47 -0
  272. package/dist/alert-variants.d.ts +19 -0
  273. package/dist/assets/css/reset.css_inline.js +4 -0
  274. package/dist/assets/svgs/alert.svg_raw.js +4 -0
  275. package/dist/assets/svgs/calendar.svg_raw.js +4 -0
  276. package/dist/assets/svgs/check_stroke.svg_raw.js +4 -0
  277. package/dist/assets/svgs/chevron_down.svg_raw.js +4 -0
  278. package/dist/assets/svgs/chevron_right.svg_raw.js +4 -0
  279. package/dist/assets/svgs/clear.svg_raw.js +4 -0
  280. package/dist/assets/svgs/clock.svg_raw.js +4 -0
  281. package/dist/assets/svgs/error.svg_raw.js +4 -0
  282. package/dist/assets/svgs/search.svg_raw.js +4 -0
  283. package/dist/assets/svgs/sort.svg_raw.js +4 -0
  284. package/dist/assets/svgs/spinner.svg_raw.js +4 -0
  285. package/dist/assets/svgs/user.svg_raw.js +4 -0
  286. package/dist/badge-variants.d.ts +19 -0
  287. package/dist/button-variants.d.ts +21 -0
  288. package/dist/components/BbAccordion/BbAccordion.vue.d.ts +9 -3
  289. package/dist/components/BbAccordion/BbAccordion.vue.js +6 -0
  290. package/dist/components/BbAccordion/BbAccordion.vue_vue_type_script_setup_true_lang.js +66 -0
  291. package/dist/components/BbAccordion/types.d.ts +12 -8
  292. package/dist/components/BbAlert/BbAlert.vue.d.ts +12 -3
  293. package/dist/components/BbAlert/BbAlert.vue.js +6 -0
  294. package/dist/components/BbAlert/BbAlert.vue_vue_type_script_setup_true_lang.js +65 -0
  295. package/dist/components/BbAlert/types.d.ts +56 -12
  296. package/dist/components/BbAsterisk/BbAsterisk.vue.d.ts +3 -0
  297. package/dist/components/BbAsterisk/BbAsterisk.vue.js +6 -0
  298. package/dist/components/BbAsterisk/BbAsterisk.vue_vue_type_script_setup_true_lang.js +13 -0
  299. package/dist/components/BbAvatar/BbAvatar.vue.d.ts +5 -0
  300. package/dist/components/BbAvatar/BbAvatar.vue.js +6 -0
  301. package/dist/components/BbAvatar/BbAvatar.vue_vue_type_script_setup_true_lang.js +78 -0
  302. package/dist/components/BbAvatar/types.d.ts +6 -5
  303. package/dist/components/BbBadge/BadgeAppendIcon.vue.d.ts +3 -0
  304. package/dist/components/BbBadge/BadgeAppendIcon.vue.js +5 -0
  305. package/dist/components/BbBadge/BadgeAppendIcon.vue_vue_type_script_setup_true_lang.js +22 -0
  306. package/dist/components/BbBadge/BadgeBodyContent.vue.d.ts +15 -0
  307. package/dist/components/BbBadge/BadgeBodyContent.vue.js +5 -0
  308. package/dist/components/BbBadge/BadgeBodyContent.vue_vue_type_script_setup_true_lang.js +34 -0
  309. package/dist/components/BbBadge/BbBadge.vue.d.ts +8 -1
  310. package/dist/components/BbBadge/BbBadge.vue.js +6 -0
  311. package/dist/components/BbBadge/BbBadge.vue_vue_type_script_setup_true_lang.js +83 -0
  312. package/dist/components/BbBadge/BbBadgeButton.vue.d.ts +12 -0
  313. package/dist/components/BbBadge/BbBadgeButton.vue.js +5 -0
  314. package/dist/components/BbBadge/BbBadgeButton.vue_vue_type_script_setup_true_lang.js +54 -0
  315. package/dist/components/BbBadge/badgeButtonContext.d.ts +27 -0
  316. package/dist/components/BbBadge/badgeButtonContext.js +5 -0
  317. package/dist/components/BbBadge/types.d.ts +61 -16
  318. package/dist/components/BbBaseButton/BbBaseButton.vue.d.ts +13 -0
  319. package/dist/components/BbBaseButton/BbBaseButton.vue.js +6 -0
  320. package/dist/components/BbBaseButton/BbBaseButton.vue_vue_type_script_setup_true_lang.js +171 -0
  321. package/dist/components/BbBaseButton/RouterComponent.vue.js +5 -0
  322. package/dist/components/BbBaseButton/RouterComponent.vue_vue_type_script_setup_true_lang.js +29 -0
  323. package/dist/components/BbBaseButton/types.d.ts +191 -0
  324. package/dist/components/BbBaseButton/types.js +33 -0
  325. package/dist/components/BbBaseCheckbox/BbBaseCheckbox.vue.d.ts +40 -0
  326. package/dist/components/BbBaseCheckbox/BbBaseCheckbox.vue.js +6 -0
  327. package/dist/components/BbBaseCheckbox/BbBaseCheckbox.vue_vue_type_script_setup_true_lang.js +145 -0
  328. package/dist/components/BbBaseCheckbox/types.d.ts +224 -0
  329. package/dist/components/BbBaseCheckboxGroup/BbBaseCheckboxGroup.vue.d.ts +19 -0
  330. package/dist/components/BbBaseCheckboxGroup/BbBaseCheckboxGroup.vue.js +6 -0
  331. package/dist/components/BbBaseCheckboxGroup/BbBaseCheckboxGroup.vue_vue_type_script_setup_true_lang.js +190 -0
  332. package/dist/components/BbBaseCheckboxGroup/types.d.ts +257 -0
  333. package/dist/components/BbBaseCheckboxIcon/BbBaseCheckboxIcon.vue.d.ts +4 -0
  334. package/dist/components/BbBaseCheckboxIcon/BbBaseCheckboxIcon.vue.js +6 -0
  335. package/dist/components/BbBaseCheckboxIcon/BbBaseCheckboxIcon.vue_vue_type_script_setup_true_lang.js +43 -0
  336. package/dist/components/BbBaseCheckboxIcon/types.d.ts +47 -0
  337. package/dist/components/BbBaseColorInput/BbBaseColorInput.vue.d.ts +42 -0
  338. package/dist/components/BbBaseColorInput/BbBaseColorInput.vue.js +6 -0
  339. package/dist/components/BbBaseColorInput/BbBaseColorInput.vue_vue_type_script_setup_true_lang.js +178 -0
  340. package/dist/components/BbBaseColorInput/types.d.ts +210 -0
  341. package/dist/components/BbBaseColorPalette/BbBaseColorPalette.vue.d.ts +13 -0
  342. package/dist/components/BbBaseColorPalette/BbBaseColorPalette.vue.js +6 -0
  343. package/dist/components/BbBaseColorPalette/BbBaseColorPalette.vue_vue_type_script_setup_true_lang.js +395 -0
  344. package/dist/components/BbBaseColorPalette/types.d.ts +40 -0
  345. package/dist/components/BbBaseDatePicker/BbBaseDatePicker.vue.js +6 -0
  346. package/dist/components/BbBaseDatePicker/BbBaseDatePicker.vue_vue_type_script_setup_true_lang.js +300 -0
  347. package/dist/components/BbBaseDatePicker/BbBaseDatePickerInputDaySelector.vue.d.ts +44 -0
  348. package/dist/components/BbBaseDatePicker/BbBaseDatePickerInputDaySelector.vue.js +5 -0
  349. package/dist/components/BbBaseDatePicker/BbBaseDatePickerInputDaySelector.vue_vue_type_script_setup_true_lang.js +310 -0
  350. package/dist/components/BbBaseDatePicker/BbBaseDatePickerMonthSelector.vue.d.ts +5 -0
  351. package/dist/components/BbBaseDatePicker/BbBaseDatePickerMonthSelector.vue.js +5 -0
  352. package/dist/components/BbBaseDatePicker/BbBaseDatePickerMonthSelector.vue_vue_type_script_setup_true_lang.js +63 -0
  353. package/dist/components/BbBaseDatePicker/BbBaseDatePickerYearSelector.vue.d.ts +5 -0
  354. package/dist/components/BbBaseDatePicker/BbBaseDatePickerYearSelector.vue.js +5 -0
  355. package/dist/components/BbBaseDatePicker/BbBaseDatePickerYearSelector.vue_vue_type_script_setup_true_lang.js +75 -0
  356. package/dist/components/BbBaseDatePicker/typeahead.d.ts +112 -0
  357. package/dist/components/BbBaseDatePicker/typeahead.js +37 -0
  358. package/dist/components/BbBaseDatePicker/types.d.ts +97 -0
  359. package/dist/components/BbBaseDatePicker/useDatePickerContext.d.ts +58 -0
  360. package/dist/components/BbBaseDatePicker/useDatePickerContext.js +11 -0
  361. package/dist/components/BbBaseDatePickerInput/BbBaseDatePickerInput.vue.d.ts +30 -0
  362. package/dist/components/BbBaseDatePickerInput/BbBaseDatePickerInput.vue.js +6 -0
  363. package/dist/components/BbBaseDatePickerInput/BbBaseDatePickerInput.vue_vue_type_script_setup_true_lang.js +716 -0
  364. package/dist/components/BbBaseDatePickerInput/BbBaseDatePickerTimeSelector.vue.d.ts +30 -0
  365. package/dist/components/BbBaseDatePickerInput/BbBaseDatePickerTimeSelector.vue.js +6 -0
  366. package/dist/components/BbBaseDatePickerInput/BbBaseDatePickerTimeSelector.vue_vue_type_script_setup_true_lang.js +204 -0
  367. package/dist/components/BbBaseDatePickerInput/types.d.ts +311 -0
  368. package/dist/components/BbBaseInputContainer/BbBaseInputContainer.vue.d.ts +17 -0
  369. package/dist/components/BbBaseInputContainer/BbBaseInputContainer.vue.js +6 -0
  370. package/dist/components/BbBaseInputContainer/BbBaseInputContainer.vue_vue_type_script_setup_true_lang.js +191 -0
  371. package/dist/components/BbBaseInputContainer/types.d.ts +197 -0
  372. package/dist/components/BbBaseNumberInput/BbBaseNumberInput.vue.d.ts +52 -0
  373. package/dist/components/BbBaseNumberInput/BbBaseNumberInput.vue.js +6 -0
  374. package/dist/components/BbBaseNumberInput/BbBaseNumberInput.vue_vue_type_script_setup_true_lang.js +215 -0
  375. package/dist/components/BbBaseNumberInput/types.d.ts +211 -0
  376. package/dist/components/BbBaseRadio/BbBaseRadio.vue.d.ts +33 -0
  377. package/dist/components/BbBaseRadio/BbBaseRadio.vue.js +6 -0
  378. package/dist/components/BbBaseRadio/BbBaseRadio.vue_vue_type_script_setup_true_lang.js +114 -0
  379. package/dist/components/BbBaseRadio/types.d.ts +179 -0
  380. package/dist/components/BbBaseRadioGroup/BbBaseRadioGroup.vue.d.ts +19 -0
  381. package/dist/components/BbBaseRadioGroup/BbBaseRadioGroup.vue.js +6 -0
  382. package/dist/components/BbBaseRadioGroup/BbBaseRadioGroup.vue_vue_type_script_setup_true_lang.js +177 -0
  383. package/dist/components/BbBaseRadioGroup/types.d.ts +223 -0
  384. package/dist/components/BbBaseRadioIcon/BbBaseRadioIcon.vue.d.ts +4 -0
  385. package/dist/components/BbBaseRadioIcon/BbBaseRadioIcon.vue.js +6 -0
  386. package/dist/components/BbBaseRadioIcon/BbBaseRadioIcon.vue_vue_type_script_setup_true_lang.js +28 -0
  387. package/dist/components/BbBaseRadioIcon/types.d.ts +41 -0
  388. package/dist/components/BbBaseRating/BbBaseRating.vue.d.ts +38 -0
  389. package/dist/components/BbBaseRating/BbBaseRating.vue.js +6 -0
  390. package/dist/components/BbBaseRating/BbBaseRating.vue_vue_type_script_setup_true_lang.js +184 -0
  391. package/dist/components/BbBaseRating/types.d.ts +168 -0
  392. package/dist/components/BbBaseSelect/BbBaseSelect.vue.d.ts +19 -0
  393. package/dist/components/BbBaseSelect/BbBaseSelect.vue.js +6 -0
  394. package/dist/components/BbBaseSelect/BbBaseSelect.vue_vue_type_script_setup_true_lang.js +307 -0
  395. package/dist/components/BbBaseSelect/types.d.ts +297 -0
  396. package/dist/components/BbBaseSlider/BbBaseSlider.vue.d.ts +35 -0
  397. package/dist/components/BbBaseSlider/BbBaseSlider.vue.js +6 -0
  398. package/dist/components/BbBaseSlider/BbBaseSlider.vue_vue_type_script_setup_true_lang.js +324 -0
  399. package/dist/components/BbBaseSlider/types.d.ts +200 -0
  400. package/dist/components/BbBaseSwitch/BbBaseSwitch.vue.d.ts +35 -0
  401. package/dist/components/BbBaseSwitch/BbBaseSwitch.vue.js +6 -0
  402. package/dist/components/BbBaseSwitch/BbBaseSwitch.vue_vue_type_script_setup_true_lang.js +146 -0
  403. package/dist/components/BbBaseSwitch/types.d.ts +10 -0
  404. package/dist/components/BbBaseSwitchGroup/BbBaseSwitchGroup.vue.d.ts +19 -0
  405. package/dist/components/BbBaseSwitchGroup/BbBaseSwitchGroup.vue.js +6 -0
  406. package/dist/components/BbBaseSwitchGroup/BbBaseSwitchGroup.vue_vue_type_script_setup_true_lang.js +190 -0
  407. package/dist/components/BbBaseSwitchGroup/types.d.ts +8 -0
  408. package/dist/components/BbBaseSwitchIcon/BbBaseSwitchIcon.vue.d.ts +4 -0
  409. package/dist/components/BbBaseSwitchIcon/BbBaseSwitchIcon.vue.js +6 -0
  410. package/dist/components/BbBaseSwitchIcon/BbBaseSwitchIcon.vue_vue_type_script_setup_true_lang.js +30 -0
  411. package/dist/components/BbBaseSwitchIcon/types.d.ts +48 -0
  412. package/dist/components/BbBaseTag/BbBaseTag.vue.d.ts +50 -0
  413. package/dist/components/BbBaseTag/BbBaseTag.vue.js +6 -0
  414. package/dist/components/BbBaseTag/BbBaseTag.vue_vue_type_script_setup_true_lang.js +266 -0
  415. package/dist/components/BbBaseTag/types.d.ts +160 -0
  416. package/dist/components/BbBaseTextInput/BbBaseTextInput.vue.d.ts +45 -0
  417. package/dist/components/BbBaseTextInput/BbBaseTextInput.vue.js +6 -0
  418. package/dist/components/BbBaseTextInput/BbBaseTextInput.vue_vue_type_script_setup_true_lang.js +200 -0
  419. package/dist/components/BbBaseTextInput/types.d.ts +209 -0
  420. package/dist/components/BbBaseTextarea/BbBaseTextarea.vue.d.ts +39 -0
  421. package/dist/components/BbBaseTextarea/BbBaseTextarea.vue.js +6 -0
  422. package/dist/components/BbBaseTextarea/BbBaseTextarea.vue_vue_type_script_setup_true_lang.js +175 -0
  423. package/dist/components/BbBaseTextarea/types.d.ts +170 -0
  424. package/dist/components/BbBaseTimePickerInput/BbBaseTimePickerInput.vue.d.ts +27 -0
  425. package/dist/components/BbBaseTimePickerInput/BbBaseTimePickerInput.vue.js +6 -0
  426. package/dist/components/BbBaseTimePickerInput/BbBaseTimePickerInput.vue_vue_type_script_setup_true_lang.js +522 -0
  427. package/dist/components/BbBaseTimePickerInput/types.d.ts +151 -0
  428. package/dist/components/BbBreadcrumbs/BbBreadcrumbs.vue.d.ts +0 -1
  429. package/dist/components/BbBreadcrumbs/BbBreadcrumbs.vue.js +6 -0
  430. package/dist/components/BbBreadcrumbs/BbBreadcrumbs.vue_vue_type_script_setup_true_lang.js +224 -0
  431. package/dist/components/BbBreadcrumbs/estimateBreadcrumbItemWidth.js +47 -0
  432. package/dist/components/BbBreadcrumbs/types.d.ts +37 -22
  433. package/dist/components/BbButton/BbButton.vue.d.ts +6 -5
  434. package/dist/components/BbButton/BbButton.vue.js +6 -0
  435. package/dist/components/BbButton/BbButton.vue_vue_type_script_setup_true_lang.js +181 -0
  436. package/dist/components/BbButton/types.d.ts +48 -47
  437. package/dist/components/BbCheckbox/BbCheckbox.vue.d.ts +4 -3
  438. package/dist/components/BbCheckbox/BbCheckbox.vue.js +6 -0
  439. package/dist/components/BbCheckbox/BbCheckbox.vue_vue_type_script_setup_true_lang.js +146 -0
  440. package/dist/components/BbCheckbox/types.d.ts +31 -10
  441. package/dist/components/BbCheckboxGroup/BbCheckboxGroup.vue.d.ts +2 -13
  442. package/dist/components/BbCheckboxGroup/BbCheckboxGroup.vue.js +6 -0
  443. package/dist/components/BbCheckboxGroup/BbCheckboxGroup.vue_vue_type_script_setup_true_lang.js +190 -0
  444. package/dist/components/BbCheckboxGroup/types.d.ts +51 -23
  445. package/dist/components/BbCollapsible/BbCollapsible.vue.d.ts +2 -1
  446. package/dist/components/BbCollapsible/BbCollapsible.vue.js +6 -0
  447. package/dist/components/BbCollapsible/BbCollapsible.vue_vue_type_script_setup_true_lang.js +31 -0
  448. package/dist/components/BbCollapsible/types.d.ts +13 -8
  449. package/dist/components/BbColorInput/BbColorInput.vue.d.ts +10 -1
  450. package/dist/components/BbColorInput/BbColorInput.vue.js +6 -0
  451. package/dist/components/BbColorInput/BbColorInput.vue_vue_type_script_setup_true_lang.js +177 -0
  452. package/dist/components/BbColorInput/types.d.ts +44 -11
  453. package/dist/components/BbColorPalette/BbColorPalette.vue.d.ts +5 -8
  454. package/dist/components/BbColorPalette/BbColorPalette.vue.js +5 -0
  455. package/dist/components/BbColorPalette/BbColorPalette.vue_vue_type_script_setup_true_lang.js +126 -0
  456. package/dist/components/BbColorPalette/types.d.ts +71 -52
  457. package/dist/components/BbConfirm/BbConfirm.vue.js +6 -0
  458. package/dist/components/BbConfirm/BbConfirm.vue_vue_type_script_setup_true_lang.js +138 -0
  459. package/dist/components/BbConfirm/BbConfirmPortal.vue.d.ts +5 -6
  460. package/dist/components/BbConfirm/BbConfirmPortal.vue.js +5 -0
  461. package/dist/components/BbConfirm/BbConfirmPortal.vue_vue_type_script_setup_true_lang.js +19 -0
  462. package/dist/components/BbDatePicker/BbDatePicker.vue.d.ts +37 -0
  463. package/dist/components/BbDatePicker/BbDatePicker.vue.js +6 -0
  464. package/dist/components/BbDatePicker/BbDatePicker.vue_vue_type_script_setup_true_lang.js +319 -0
  465. package/dist/components/BbDatePicker/types.d.ts +159 -0
  466. package/dist/components/BbDatePickerInput/BbDatePickerInput.vue.d.ts +3 -1
  467. package/dist/components/BbDatePickerInput/BbDatePickerInput.vue.js +6 -0
  468. package/dist/components/BbDatePickerInput/BbDatePickerInput.vue_vue_type_script_setup_true_lang.js +179 -0
  469. package/dist/components/BbDatePickerInput/types.d.ts +134 -16
  470. package/dist/components/BbDialog/BbDialog.vue.d.ts +14 -6
  471. package/dist/components/BbDialog/BbDialog.vue.js +6 -0
  472. package/dist/components/BbDialog/BbDialog.vue_vue_type_script_setup_true_lang.js +214 -0
  473. package/dist/components/BbDialog/types.d.ts +146 -1
  474. package/dist/components/BbDialog/useDialogStack.d.ts +5 -0
  475. package/dist/components/BbDialog/useDialogStack.js +20 -0
  476. package/dist/components/BbDropdown/AdaptiveDropdown.vue.d.ts +24 -0
  477. package/dist/components/BbDropdown/AdaptiveDropdown.vue.js +6 -0
  478. package/dist/components/BbDropdown/AdaptiveDropdown.vue_vue_type_script_setup_true_lang.js +116 -0
  479. package/dist/components/BbDropdown/BbDropdown.vue.d.ts +14 -7
  480. package/dist/components/BbDropdown/BbDropdown.vue.js +6 -0
  481. package/dist/components/BbDropdown/BbDropdown.vue_vue_type_script_setup_true_lang.js +561 -0
  482. package/dist/components/BbDropdown/BbDropdownGroup.vue.d.ts +44 -0
  483. package/dist/components/BbDropdown/BbDropdownGroup.vue.js +5 -0
  484. package/dist/components/BbDropdown/BbDropdownGroup.vue_vue_type_script_setup_true_lang.js +36 -0
  485. package/dist/components/BbDropdown/BbDropdownList.vue.d.ts +31 -0
  486. package/dist/components/BbDropdown/BbDropdownList.vue.js +6 -0
  487. package/dist/components/BbDropdown/BbDropdownList.vue_vue_type_script_setup_true_lang.js +470 -0
  488. package/dist/components/BbDropdown/DropdownPipelineResolver.vue.d.ts +16 -0
  489. package/dist/components/BbDropdown/DropdownPipelineResolver.vue.js +5 -0
  490. package/dist/components/BbDropdown/DropdownPipelineResolver.vue_vue_type_script_setup_true_lang.js +168 -0
  491. package/dist/components/BbDropdown/normalizeGroups.d.ts +18 -0
  492. package/dist/components/BbDropdown/normalizeGroups.js +46 -0
  493. package/dist/components/BbDropdown/types.d.ts +468 -46
  494. package/dist/components/BbDropdown/types.js +4 -0
  495. package/dist/components/BbDropdown/useDropdownContext.d.ts +89 -0
  496. package/dist/components/BbDropdown/useDropdownContext.js +9 -0
  497. package/dist/components/BbDropdown/useDropdownGroupRegistry.d.ts +108 -0
  498. package/dist/components/BbDropdown/useDropdownGroupRegistry.js +5 -0
  499. package/dist/components/BbDropdownButton/BbDropdownButton.vue.d.ts +3 -3
  500. package/dist/components/BbDropdownButton/BbDropdownButton.vue.js +6 -0
  501. package/dist/components/BbDropdownButton/BbDropdownButton.vue_vue_type_script_setup_true_lang.js +119 -0
  502. package/dist/components/BbDropdownButton/types.d.ts +47 -52
  503. package/dist/components/BbDropzone/BbDropzone.vue.d.ts +5 -4
  504. package/dist/components/BbDropzone/BbDropzone.vue.js +6 -0
  505. package/dist/components/BbDropzone/BbDropzone.vue_vue_type_script_setup_true_lang.js +308 -0
  506. package/dist/components/BbDropzone/types.d.ts +77 -8
  507. package/dist/components/BbIcon/BbIcon.vue.d.ts +3 -2
  508. package/dist/components/BbIcon/BbIcon.vue.js +6 -0
  509. package/dist/components/BbIcon/BbIcon.vue_vue_type_script_setup_true_lang.js +65 -0
  510. package/dist/components/BbIcon/types.d.ts +6 -19
  511. package/dist/components/BbIndicator/BbIndicator.vue.d.ts +14 -0
  512. package/dist/components/BbIndicator/BbIndicator.vue.js +6 -0
  513. package/dist/components/BbIndicator/BbIndicator.vue_vue_type_script_setup_true_lang.js +56 -0
  514. package/dist/components/BbIndicator/types.d.ts +49 -0
  515. package/dist/components/BbNumberInput/BbNumberInput.vue.d.ts +12 -6
  516. package/dist/components/BbNumberInput/BbNumberInput.vue.js +6 -0
  517. package/dist/components/BbNumberInput/BbNumberInput.vue_vue_type_script_setup_true_lang.js +194 -0
  518. package/dist/components/BbNumberInput/types.d.ts +40 -4
  519. package/dist/components/BbOffCanvas/BbOffCanvas.vue.d.ts +16 -10
  520. package/dist/components/BbOffCanvas/BbOffCanvas.vue.js +6 -0
  521. package/dist/components/BbOffCanvas/BbOffCanvas.vue_vue_type_script_setup_true_lang.js +284 -0
  522. package/dist/components/BbOffCanvas/types.d.ts +71 -39
  523. package/dist/components/BbOffCanvas/useOffCanvasStack.d.ts +25 -0
  524. package/dist/components/BbOffCanvas/useOffCanvasStack.js +68 -0
  525. package/dist/components/BbPagination/BbPagination.vue.d.ts +9 -4
  526. package/dist/components/BbPagination/BbPagination.vue.js +6 -0
  527. package/dist/components/BbPagination/BbPagination.vue_vue_type_script_setup_true_lang.js +244 -0
  528. package/dist/components/BbPagination/paginationFit.d.ts +38 -0
  529. package/dist/components/BbPagination/paginationFit.js +13 -0
  530. package/dist/components/BbPagination/types.d.ts +51 -16
  531. package/dist/components/BbPopover/BbPopover.vue.d.ts +16 -15
  532. package/dist/components/BbPopover/BbPopover.vue.js +6 -0
  533. package/dist/components/BbPopover/BbPopover.vue_vue_type_script_setup_true_lang.js +309 -0
  534. package/dist/components/BbPopover/escapeStack.d.ts +6 -0
  535. package/dist/components/BbPopover/escapeStack.js +10 -0
  536. package/dist/components/BbPopover/types.d.ts +90 -31
  537. package/dist/components/BbProgress/BbProgress.vue.d.ts +1 -0
  538. package/dist/components/BbProgress/BbProgress.vue.js +6 -0
  539. package/dist/components/BbProgress/BbProgress.vue_vue_type_script_setup_true_lang.js +36 -0
  540. package/dist/components/BbProgress/types.d.ts +15 -1
  541. package/dist/components/BbRadio/BbRadio.vue.d.ts +5 -3
  542. package/dist/components/BbRadio/BbRadio.vue.js +6 -0
  543. package/dist/components/BbRadio/BbRadio.vue_vue_type_script_setup_true_lang.js +133 -0
  544. package/dist/components/BbRadio/types.d.ts +32 -9
  545. package/dist/components/BbRadioGroup/BbRadioGroup.vue.d.ts +4 -14
  546. package/dist/components/BbRadioGroup/BbRadioGroup.vue.js +6 -0
  547. package/dist/components/BbRadioGroup/BbRadioGroup.vue_vue_type_script_setup_true_lang.js +186 -0
  548. package/dist/components/BbRadioGroup/types.d.ts +48 -22
  549. package/dist/components/BbRating/BbRating.vue.d.ts +4 -1
  550. package/dist/components/BbRating/BbRating.vue.js +6 -0
  551. package/dist/components/BbRating/BbRating.vue_vue_type_script_setup_true_lang.js +150 -0
  552. package/dist/components/BbRating/types.d.ts +44 -10
  553. package/dist/components/BbSelect/BbSelect.vue.d.ts +2 -11
  554. package/dist/components/BbSelect/BbSelect.vue.js +6 -0
  555. package/dist/components/BbSelect/BbSelect.vue_vue_type_script_setup_true_lang.js +241 -0
  556. package/dist/components/BbSelect/types.d.ts +112 -59
  557. package/dist/components/BbSelectPopover/BbSelectPopover.vue.d.ts +1 -10
  558. package/dist/components/BbSelectPopover/BbSelectPopover.vue.js +6 -0
  559. package/dist/components/BbSelectPopover/BbSelectPopover.vue_vue_type_script_setup_true_lang.js +639 -0
  560. package/dist/components/BbSelectPopover/types.d.ts +197 -105
  561. package/dist/components/BbSlider/BbSlider.vue.d.ts +3 -6
  562. package/dist/components/BbSlider/BbSlider.vue.js +6 -0
  563. package/dist/components/BbSlider/BbSlider.vue_vue_type_script_setup_true_lang.js +166 -0
  564. package/dist/components/BbSlider/types.d.ts +44 -13
  565. package/dist/components/BbSmoothHeight/BbSmoothHeight.vue.d.ts +3 -1
  566. package/dist/components/BbSmoothHeight/BbSmoothHeight.vue.js +6 -0
  567. package/dist/components/BbSmoothHeight/BbSmoothHeight.vue_vue_type_script_setup_true_lang.js +79 -0
  568. package/dist/components/BbSmoothHeight/types.d.ts +17 -2
  569. package/dist/components/BbSpinner/BbSpinner.vue.d.ts +1 -1
  570. package/dist/components/BbSpinner/BbSpinner.vue.js +6 -0
  571. package/dist/components/BbSpinner/BbSpinner.vue_vue_type_script_setup_true_lang.js +30 -0
  572. package/dist/components/BbSpinner/types.d.ts +10 -3
  573. package/dist/components/BbSwitch/BbSwitch.vue.d.ts +5 -3
  574. package/dist/components/BbSwitch/BbSwitch.vue.js +6 -0
  575. package/dist/components/BbSwitch/BbSwitch.vue_vue_type_script_setup_true_lang.js +142 -0
  576. package/dist/components/BbSwitch/types.d.ts +3 -1
  577. package/dist/components/BbSwitchGroup/BbSwitchGroup.vue.d.ts +4 -14
  578. package/dist/components/BbSwitchGroup/BbSwitchGroup.vue.js +6 -0
  579. package/dist/components/BbSwitchGroup/BbSwitchGroup.vue_vue_type_script_setup_true_lang.js +190 -0
  580. package/dist/components/BbSwitchGroup/types.d.ts +3 -22
  581. package/dist/components/BbTable/BbTable.vue.d.ts +58 -31
  582. package/dist/components/BbTable/BbTable.vue.js +6 -0
  583. package/dist/components/BbTable/BbTable.vue_vue_type_script_setup_true_lang.js +900 -0
  584. package/dist/components/BbTable/types.d.ts +213 -37
  585. package/dist/components/BbTable/utils.d.ts +9 -1
  586. package/dist/components/BbTable/utils.js +53 -0
  587. package/dist/components/BbTabs/BbTabs.vue.d.ts +20 -0
  588. package/dist/components/BbTabs/BbTabs.vue.js +6 -0
  589. package/dist/components/BbTabs/BbTabs.vue_vue_type_script_setup_true_lang.js +64 -0
  590. package/dist/components/BbTabs/BbTabsList.vue.d.ts +19 -0
  591. package/dist/components/BbTabs/BbTabsList.vue.js +6 -0
  592. package/dist/components/BbTabs/BbTabsList.vue_vue_type_script_setup_true_lang.js +123 -0
  593. package/dist/components/BbTabs/BbTabsPanes.vue.d.ts +16 -0
  594. package/dist/components/BbTabs/BbTabsPanes.vue.js +6 -0
  595. package/dist/components/BbTabs/BbTabsPanes.vue_vue_type_script_setup_true_lang.js +35 -0
  596. package/dist/components/BbTabs/BbTabsRoot.vue.d.ts +20 -0
  597. package/dist/components/BbTabs/BbTabsRoot.vue.js +5 -0
  598. package/dist/components/BbTabs/BbTabsRoot.vue_vue_type_script_setup_true_lang.js +55 -0
  599. package/dist/components/BbTabs/types.d.ts +264 -0
  600. package/dist/components/BbTag/BbTag.vue.d.ts +19 -6
  601. package/dist/components/BbTag/BbTag.vue.js +6 -0
  602. package/dist/components/BbTag/BbTag.vue_vue_type_script_setup_true_lang.js +187 -0
  603. package/dist/components/BbTag/types.d.ts +55 -17
  604. package/dist/components/BbTextInput/BbTextInput.vue.d.ts +10 -1
  605. package/dist/components/BbTextInput/BbTextInput.vue.js +6 -0
  606. package/dist/components/BbTextInput/BbTextInput.vue_vue_type_script_setup_true_lang.js +195 -0
  607. package/dist/components/BbTextInput/types.d.ts +31 -4
  608. package/dist/components/BbTextarea/BbTextarea.vue.d.ts +10 -1
  609. package/dist/components/BbTextarea/BbTextarea.vue.js +6 -0
  610. package/dist/components/BbTextarea/BbTextarea.vue_vue_type_script_setup_true_lang.js +178 -0
  611. package/dist/components/BbTextarea/types.d.ts +33 -2
  612. package/dist/components/BbTimePicker/BbTimePicker.vue.d.ts +33 -0
  613. package/dist/components/BbTimePicker/BbTimePicker.vue.js +6 -0
  614. package/dist/components/BbTimePicker/BbTimePicker.vue_vue_type_script_setup_true_lang.js +244 -0
  615. package/dist/components/BbTimePicker/types.d.ts +133 -0
  616. package/dist/components/BbTimePickerInput/BbTimePickerInput.vue.d.ts +25 -0
  617. package/dist/components/BbTimePickerInput/BbTimePickerInput.vue.js +6 -0
  618. package/dist/components/BbTimePickerInput/BbTimePickerInput.vue_vue_type_script_setup_true_lang.js +157 -0
  619. package/dist/components/BbTimePickerInput/types.d.ts +174 -0
  620. package/dist/components/BbToast/BbToast.vue.d.ts +2 -3
  621. package/dist/components/BbToast/BbToast.vue.js +6 -0
  622. package/dist/components/BbToast/BbToast.vue_vue_type_script_setup_true_lang.js +39 -0
  623. package/dist/components/BbToast/BbToastMessage.vue.d.ts +17 -8
  624. package/dist/components/BbToast/BbToastMessage.vue.js +5 -0
  625. package/dist/components/BbToast/BbToastMessage.vue_vue_type_script_setup_true_lang.js +170 -0
  626. package/dist/components/BbToast/BbToastPortal.vue.d.ts +30 -0
  627. package/dist/components/BbToast/BbToastPortal.vue.js +5 -0
  628. package/dist/components/BbToast/BbToastPortal.vue_vue_type_script_setup_true_lang.js +19 -0
  629. package/dist/components/BbToast/BbToastRegion.vue.d.ts +8 -0
  630. package/dist/components/BbToast/BbToastRegion.vue.js +5 -0
  631. package/dist/components/BbToast/BbToastRegion.vue_vue_type_script_setup_true_lang.js +100 -0
  632. package/dist/components/BbToast/types.d.ts +69 -5
  633. package/dist/components/BbTooltip/BbTooltip.vue.d.ts +10 -3
  634. package/dist/components/BbTooltip/BbTooltip.vue.js +6 -0
  635. package/dist/components/BbTooltip/BbTooltip.vue_vue_type_script_setup_true_lang.js +160 -0
  636. package/dist/components/BbTooltip/types.d.ts +69 -11
  637. package/dist/components/BbTree/BbTree.vue.d.ts +28 -13
  638. package/dist/components/BbTree/BbTree.vue.js +6 -0
  639. package/dist/components/BbTree/BbTree.vue_vue_type_script_setup_true_lang.js +55 -0
  640. package/dist/components/BbTree/BbTreeLevel.vue.d.ts +19 -0
  641. package/dist/components/BbTree/BbTreeLevel.vue.js +5 -0
  642. package/dist/components/BbTree/BbTreeLevel.vue_vue_type_script_setup_true_lang.js +94 -0
  643. package/dist/components/BbTree/context.d.ts +17 -0
  644. package/dist/components/BbTree/context.js +4 -0
  645. package/dist/components/BbTree/types.d.ts +94 -41
  646. package/dist/components/ChipsBox/ChipsBox.vue.d.ts +2 -1
  647. package/dist/components/ChipsBox/ChipsBox.vue.js +5 -0
  648. package/dist/components/ChipsBox/ChipsBox.vue_vue_type_script_setup_true_lang.js +98 -0
  649. package/dist/components/ChipsBox/types.d.ts +12 -5
  650. package/dist/components/ClearableButton/ClearableButton.vue.d.ts +2 -1
  651. package/dist/components/ClearableButton/ClearableButton.vue.js +6 -0
  652. package/dist/components/ClearableButton/ClearableButton.vue_vue_type_script_setup_true_lang.js +19 -0
  653. package/dist/components/ClearableButton/types.d.ts +7 -1
  654. package/dist/components/CloseIcon/CloseButton.vue.d.ts +5 -0
  655. package/dist/components/CloseIcon/CloseButton.vue.js +7 -0
  656. package/dist/components/CloseIcon/CloseButton.vue_vue_type_script_setup_true_lang.js +23 -0
  657. package/dist/components/CloseIcon/types.d.ts +2 -0
  658. package/dist/components/CommaBox/CommaBox.vue.d.ts +2 -1
  659. package/dist/components/CommaBox/CommaBox.vue.js +6 -0
  660. package/dist/components/CommaBox/CommaBox.vue_vue_type_script_setup_true_lang.js +81 -0
  661. package/dist/components/CommaBox/types.d.ts +6 -7
  662. package/dist/components/CommonInputWrapper/CommonInputWrapper.vue.d.ts +19 -0
  663. package/dist/components/CommonInputWrapper/CommonInputWrapper.vue.js +6 -0
  664. package/dist/components/CommonInputWrapper/CommonInputWrapper.vue_vue_type_script_setup_true_lang.js +107 -0
  665. package/dist/components/CommonInputWrapper/types.d.ts +96 -0
  666. package/dist/components/CommonPopover/CommonPopover.vue.d.ts +9 -3
  667. package/dist/components/CommonPopover/CommonPopover.vue.js +6 -0
  668. package/dist/components/CommonPopover/CommonPopover.vue_vue_type_script_setup_true_lang.js +160 -0
  669. package/dist/components/CommonPopover/types.d.ts +65 -16
  670. package/dist/components/ErrorIcon/ErrorIcon.vue.d.ts +2 -0
  671. package/dist/components/ErrorIcon/ErrorIcon.vue.js +6 -0
  672. package/dist/components/ErrorIcon/ErrorIcon.vue_vue_type_script_setup_true_lang.js +16 -0
  673. package/dist/components/FlatListBox/FlatListBox.vue.d.ts +2 -5
  674. package/dist/components/FlatListBox/FlatListBox.vue.js +5 -0
  675. package/dist/components/FlatListBox/FlatListBox.vue_vue_type_script_setup_true_lang.js +167 -0
  676. package/dist/components/FlatListBox/types.d.ts +1 -1
  677. package/dist/components/GroupedListBox/GroupedListBox.vue.d.ts +2 -5
  678. package/dist/components/GroupedListBox/GroupedListBox.vue.js +5 -0
  679. package/dist/components/GroupedListBox/GroupedListBox.vue_vue_type_script_setup_true_lang.js +218 -0
  680. package/dist/components/ListBox/ListBox.vue.d.ts +3 -6
  681. package/dist/components/ListBox/ListBox.vue.js +5 -0
  682. package/dist/components/ListBox/ListBox.vue_vue_type_script_setup_true_lang.js +112 -0
  683. package/dist/components/ListBox/types.d.ts +1 -1
  684. package/dist/components/OptionsContainer/OptionsContainer.vue.d.ts +1 -0
  685. package/dist/components/OptionsContainer/OptionsContainer.vue.js +5 -0
  686. package/dist/components/OptionsContainer/OptionsContainer.vue_vue_type_script_setup_true_lang.js +52 -0
  687. package/dist/components/OptionsContainer/types.d.ts +14 -24
  688. package/dist/components/Transitions/ScaleFade.vue.d.ts +2 -2
  689. package/dist/components/Transitions/ScaleFade.vue.js +5 -0
  690. package/dist/components/Transitions/ScaleFade.vue_vue_type_script_setup_true_lang.js +47 -0
  691. package/dist/components/Transitions/Slide.vue.d.ts +15 -0
  692. package/dist/components/Transitions/Slide.vue.js +7 -0
  693. package/dist/components/Transitions/Slide.vue_vue_type_script_setup_true_lang.js +28 -0
  694. package/dist/components/WarningIcon/WarningIcon.vue.d.ts +5 -0
  695. package/dist/components/WarningIcon/WarningIcon.vue.js +6 -0
  696. package/dist/components/WarningIcon/WarningIcon.vue_vue_type_script_setup_true_lang.js +16 -0
  697. package/dist/components/WarningIcon/types.d.ts +3 -0
  698. package/dist/composables/__testResets.d.ts +1 -0
  699. package/dist/composables/useActiveInactiveState.d.ts +4 -0
  700. package/dist/composables/useActiveInactiveState.js +21 -0
  701. package/dist/composables/useBaseOptions.d.ts +3 -3
  702. package/dist/composables/useBaseOptions.js +31 -0
  703. package/dist/composables/useBbConfig.d.ts +8 -37
  704. package/dist/composables/useBbConfig.js +5 -0
  705. package/dist/composables/useBbDropdownContext.d.ts +89 -0
  706. package/dist/composables/useBbDropdownContext.js +46 -0
  707. package/dist/composables/useBbFormContext.d.ts +90 -0
  708. package/dist/composables/useBbFormContext.js +69 -0
  709. package/dist/composables/useBbTableContext.d.ts +195 -0
  710. package/dist/composables/useBbTableContext.js +208 -0
  711. package/dist/composables/useBbTabsContext.d.ts +111 -0
  712. package/dist/composables/useBbTabsContext.js +225 -0
  713. package/dist/composables/useBreakpoint.d.ts +13 -0
  714. package/dist/composables/useBreakpoint.js +39 -0
  715. package/dist/composables/useBroadcastChannelInstance.d.ts +1 -3
  716. package/dist/composables/useBroadcastChannelInstance.js +39 -0
  717. package/dist/composables/useCancelableFunction.js +37 -0
  718. package/dist/composables/useClosingInert.d.ts +28 -0
  719. package/dist/composables/useClosingInert.js +23 -0
  720. package/dist/composables/useCoherence.js +16 -0
  721. package/dist/composables/useConfirm.d.ts +278 -68
  722. package/dist/composables/useConfirm.js +130 -0
  723. package/dist/composables/useCountdown.js +42 -0
  724. package/dist/composables/useHashedWatcher.d.ts +17 -0
  725. package/dist/composables/useHashedWatcher.js +14 -0
  726. package/dist/composables/useId.d.ts +3 -2
  727. package/dist/composables/useIndexById.js +16 -0
  728. package/dist/composables/useInertiaPage.d.ts +10 -0
  729. package/dist/composables/useInertiaPage.js +8 -0
  730. package/dist/composables/useItemText.js +17 -0
  731. package/dist/composables/useItemValue.js +9 -0
  732. package/dist/composables/useItemsGetter.d.ts +1 -1
  733. package/dist/composables/useItemsGetter.js +30 -0
  734. package/dist/composables/useListboxFocus.js +66 -0
  735. package/dist/composables/useLocale.d.ts +1 -1
  736. package/dist/composables/useLocale.js +11 -0
  737. package/dist/composables/useLogger.d.ts +1 -1
  738. package/dist/composables/useLogger.js +10 -0
  739. package/dist/composables/useMinimalQueue.d.ts +1 -1
  740. package/dist/composables/useMobile.js +7 -0
  741. package/dist/composables/useOnFalsy.d.ts +2 -0
  742. package/dist/composables/useOnFalsy.js +9 -0
  743. package/dist/composables/useOnTruthy.d.ts +7 -0
  744. package/dist/composables/useOnTruthy.js +9 -0
  745. package/dist/composables/usePrefill.d.ts +2 -1
  746. package/dist/composables/usePrefill.js +24 -0
  747. package/dist/composables/useQuery.d.ts +15 -3
  748. package/dist/composables/useQuery.js +42 -0
  749. package/dist/composables/useRoute.js +11 -0
  750. package/dist/composables/useRouter.js +8 -0
  751. package/dist/composables/useSafeArea.d.ts +51 -0
  752. package/dist/composables/useSafeArea.js +16 -0
  753. package/dist/composables/useSegmentedFields.d.ts +104 -0
  754. package/dist/composables/useSegmentedFields.js +159 -0
  755. package/dist/composables/useTableWidthContext.d.ts +5 -0
  756. package/dist/composables/useTableWidthContext.js +42 -0
  757. package/dist/composables/useToast.d.ts +40 -70
  758. package/dist/composables/useToast.js +58 -0
  759. package/dist/composables/useTopLayer.d.ts +9 -0
  760. package/dist/composables/useTopLayer.js +7 -0
  761. package/dist/composables/useUntil.js +13 -0
  762. package/dist/composables/useViewportWidth.d.ts +17 -0
  763. package/dist/composables/useViewportWidth.js +6 -0
  764. package/dist/confirm-variants.d.ts +17 -0
  765. package/dist/deprecation/ai-deprecations.json.d.ts +784 -0
  766. package/dist/deprecation/ai-deprecations.json.js +4 -0
  767. package/dist/deprecation/removedProps.d.ts +3 -0
  768. package/dist/deprecation/removedProps.js +13 -0
  769. package/dist/directives/bbColor.d.ts +65 -0
  770. package/dist/directives/bbColor.js +24 -0
  771. package/dist/directives/bbDate.d.ts +66 -0
  772. package/dist/directives/bbDate.js +24 -0
  773. package/dist/directives/bbDropdown.d.ts +15 -11
  774. package/dist/directives/bbDropdown.js +23 -0
  775. package/dist/directives/bbTime.d.ts +64 -0
  776. package/dist/directives/bbTime.js +24 -0
  777. package/dist/directives/bbTooltip.d.ts +16 -11
  778. package/dist/directives/bbTooltip.js +24 -0
  779. package/dist/directives/createPopoverDirective.js +54 -0
  780. package/dist/dropdown-item-variants.d.ts +17 -0
  781. package/dist/i18n/index.d.ts +51 -3
  782. package/dist/i18n/index.js +27 -0
  783. package/dist/i18n/locales/cs.json +115 -0
  784. package/dist/i18n/locales/da.json +115 -0
  785. package/dist/i18n/locales/de.json +115 -0
  786. package/dist/i18n/locales/el.json +115 -0
  787. package/dist/i18n/locales/en.json +115 -0
  788. package/dist/i18n/locales/es.json +115 -0
  789. package/dist/i18n/locales/fi.json +115 -0
  790. package/dist/i18n/locales/fr.json +115 -0
  791. package/dist/i18n/locales/hu.json +115 -0
  792. package/dist/i18n/locales/it.json +115 -0
  793. package/dist/i18n/locales/ja.json +115 -0
  794. package/dist/i18n/locales/ko.json +115 -0
  795. package/dist/i18n/locales/nb.json +115 -0
  796. package/dist/i18n/locales/nl.json +115 -0
  797. package/dist/i18n/locales/pl.json +115 -0
  798. package/dist/i18n/locales/pt.json +115 -0
  799. package/dist/i18n/locales/ro.json +115 -0
  800. package/dist/i18n/locales/ru.json +115 -0
  801. package/dist/i18n/locales/sv.json +115 -0
  802. package/dist/i18n/locales/tr.json +115 -0
  803. package/dist/i18n/locales/uk.json +115 -0
  804. package/dist/i18n/locales/zh-cn.json +115 -0
  805. package/dist/icons-whitelist.d.ts +8 -0
  806. package/dist/index.d.ts +96 -79
  807. package/dist/index.js +76 -82
  808. package/dist/indicator-variants.d.ts +20 -0
  809. package/dist/llms-full.txt +79703 -0
  810. package/dist/llms-medium.txt +1514 -0
  811. package/dist/llms.txt +105 -0
  812. package/dist/locale-blueprint.json +141 -0
  813. package/dist/locale-registry.d.ts +37 -0
  814. package/dist/nuxt-module.d.ts +3 -0
  815. package/dist/nuxt.js +19 -0
  816. package/dist/plugin.d.ts +4 -0
  817. package/dist/plugin.js +22 -0
  818. package/dist/reset.css +1 -0
  819. package/dist/reset.d.ts +0 -0
  820. package/dist/runtime/nuxt-plugin.d.ts +2 -0
  821. package/dist/runtime/nuxt-plugin.js +24 -0
  822. package/dist/styles.css +2 -0
  823. package/dist/styles.d.ts +0 -0
  824. package/dist/toast-variants.d.ts +20 -0
  825. package/dist/tooltip-variants.d.ts +17 -0
  826. package/dist/types/ActionButton.d.ts +32 -0
  827. package/dist/types/AlertVariant.d.ts +16 -0
  828. package/dist/types/BadgeVariant.d.ts +16 -0
  829. package/dist/types/ButtonVariant.d.ts +17 -0
  830. package/dist/types/Classes.d.ts +1 -1
  831. package/dist/types/ColumnName.d.ts +1 -1
  832. package/dist/types/CommonProps.d.ts +68 -277
  833. package/dist/types/Config.d.ts +84 -0
  834. package/dist/types/ConfirmVariant.d.ts +15 -0
  835. package/dist/types/DropdownItemVariant.d.ts +18 -0
  836. package/dist/types/Icon.d.ts +5 -7
  837. package/dist/types/IndicatorVariant.d.ts +16 -0
  838. package/dist/types/InputDirection.d.ts +15 -0
  839. package/dist/types/ItemAccessor.d.ts +21 -0
  840. package/dist/types/Placement.d.ts +6 -0
  841. package/dist/types/ResponsiveSize.d.ts +20 -0
  842. package/dist/types/SizeScale.d.ts +8 -0
  843. package/dist/types/ToastVariant.d.ts +17 -0
  844. package/dist/types/TooltipVariant.d.ts +18 -0
  845. package/dist/utilities/functions/bytesToUnit.d.ts +2 -0
  846. package/dist/utilities/functions/bytesToUnit.js +18 -0
  847. package/dist/utilities/functions/clampPrecision.js +10 -0
  848. package/dist/utilities/functions/convertDateValue.d.ts +23 -10
  849. package/dist/utilities/functions/convertDateValue.js +12 -0
  850. package/dist/utilities/functions/deburr.js +5 -0
  851. package/dist/utilities/functions/empty.js +5 -0
  852. package/dist/utilities/functions/flattenTree.d.ts +1 -1
  853. package/dist/utilities/functions/hash.js +5 -0
  854. package/dist/utilities/functions/isDateDisabled.d.ts +1 -0
  855. package/dist/utilities/functions/isDateDisabled.js +20 -0
  856. package/dist/utilities/functions/isEqual.js +5 -0
  857. package/dist/utilities/functions/isNotEmpty.js +5 -0
  858. package/dist/utilities/functions/matchAnyKey.d.ts +1 -1
  859. package/dist/utilities/functions/matchAnyKey.js +15 -0
  860. package/dist/utilities/functions/parseSize.d.ts +1 -1
  861. package/dist/utilities/functions/parseSize.js +15 -0
  862. package/dist/utilities/functions/percentage.js +11 -0
  863. package/dist/utilities/functions/pipe.d.ts +1 -1
  864. package/dist/utilities/functions/reject.d.ts +25 -0
  865. package/dist/utilities/functions/reject.js +28 -0
  866. package/dist/utilities/functions/resolveEnumProp.d.ts +19 -0
  867. package/dist/utilities/functions/resolveEnumProp.js +5 -0
  868. package/dist/utilities/functions/slotKey.d.ts +13 -0
  869. package/dist/utilities/functions/slotKey.js +4 -0
  870. package/dist/utilities/functions/sort.d.ts +2 -2
  871. package/dist/utilities/functions/sort.js +19 -0
  872. package/dist/utilities/functions/throttle.js +5 -0
  873. package/dist/utilities/functions/waitFor.d.ts +9 -2
  874. package/dist/utilities/functions/waitFor.js +14 -0
  875. package/dist/utilities/functions/warnRemovedAttrs.d.ts +11 -0
  876. package/dist/utilities/functions/warnRemovedAttrs.js +20 -0
  877. package/dist/utilities/functions/when.js +5 -0
  878. package/dist/utilities/misc/iconsInjectionKey.d.ts +15 -0
  879. package/dist/utilities/misc/iconsInjectionKey.js +4 -0
  880. package/dist/utilities/misc/transitions.d.ts +5 -0
  881. package/dist/utilities/misc/transitions.js +8 -0
  882. package/dist/utils/injectLibraryStyles.d.ts +6 -0
  883. package/dist/utils/injectLibraryStyles.js +38 -0
  884. package/dist/validated/BbCheckbox.vue.d.ts +29 -0
  885. package/dist/validated/BbCheckbox.vue.js +5 -0
  886. package/dist/validated/BbCheckbox.vue_vue_type_script_setup_true_lang.js +75 -0
  887. package/dist/validated/BbCheckboxGroup.vue.d.ts +34 -0
  888. package/dist/validated/BbCheckboxGroup.vue.js +5 -0
  889. package/dist/validated/BbCheckboxGroup.vue_vue_type_script_setup_true_lang.js +82 -0
  890. package/dist/validated/BbColorInput.vue.d.ts +36 -0
  891. package/dist/validated/BbColorInput.vue.js +5 -0
  892. package/dist/validated/BbColorInput.vue_vue_type_script_setup_true_lang.js +71 -0
  893. package/dist/validated/BbDatePickerInput.vue.d.ts +41 -0
  894. package/dist/validated/BbDatePickerInput.vue.js +5 -0
  895. package/dist/validated/BbDatePickerInput.vue_vue_type_script_setup_true_lang.js +90 -0
  896. package/dist/validated/BbDropzone.vue.d.ts +24 -0
  897. package/dist/validated/BbDropzone.vue.js +5 -0
  898. package/dist/validated/BbDropzone.vue_vue_type_script_setup_true_lang.js +45 -0
  899. package/dist/validated/BbForm.vue.d.ts +28 -0
  900. package/dist/validated/BbForm.vue.js +5 -0
  901. package/dist/validated/BbForm.vue_vue_type_script_setup_true_lang.js +42 -0
  902. package/dist/validated/BbNumberInput.vue.d.ts +36 -0
  903. package/dist/validated/BbNumberInput.vue.js +5 -0
  904. package/dist/validated/BbNumberInput.vue_vue_type_script_setup_true_lang.js +72 -0
  905. package/dist/validated/BbRadioGroup.vue.d.ts +34 -0
  906. package/dist/validated/BbRadioGroup.vue.js +5 -0
  907. package/dist/validated/BbRadioGroup.vue_vue_type_script_setup_true_lang.js +78 -0
  908. package/dist/validated/BbRating.vue.d.ts +30 -0
  909. package/dist/validated/BbRating.vue.js +5 -0
  910. package/dist/validated/BbRating.vue_vue_type_script_setup_true_lang.js +63 -0
  911. package/dist/validated/BbSelect.vue.d.ts +46 -0
  912. package/dist/validated/BbSelect.vue.js +5 -0
  913. package/dist/validated/BbSelect.vue_vue_type_script_setup_true_lang.js +109 -0
  914. package/dist/validated/BbSlider.vue.d.ts +36 -0
  915. package/dist/validated/BbSlider.vue.js +5 -0
  916. package/dist/validated/BbSlider.vue_vue_type_script_setup_true_lang.js +69 -0
  917. package/dist/validated/BbSwitch.vue.d.ts +29 -0
  918. package/dist/validated/BbSwitch.vue.js +5 -0
  919. package/dist/validated/BbSwitch.vue_vue_type_script_setup_true_lang.js +75 -0
  920. package/dist/validated/BbSwitchGroup.vue.d.ts +34 -0
  921. package/dist/validated/BbSwitchGroup.vue.js +5 -0
  922. package/dist/validated/BbSwitchGroup.vue_vue_type_script_setup_true_lang.js +82 -0
  923. package/dist/validated/BbTag.vue.d.ts +36 -0
  924. package/dist/validated/BbTag.vue.js +5 -0
  925. package/dist/validated/BbTag.vue_vue_type_script_setup_true_lang.js +72 -0
  926. package/dist/validated/BbTextInput.vue.d.ts +36 -0
  927. package/dist/validated/BbTextInput.vue.js +5 -0
  928. package/dist/validated/BbTextInput.vue_vue_type_script_setup_true_lang.js +72 -0
  929. package/dist/validated/BbTextarea.vue.d.ts +36 -0
  930. package/dist/validated/BbTextarea.vue.js +5 -0
  931. package/dist/validated/BbTextarea.vue_vue_type_script_setup_true_lang.js +70 -0
  932. package/dist/validated/BbTimePickerInput.vue.d.ts +37 -0
  933. package/dist/validated/BbTimePickerInput.vue.js +5 -0
  934. package/dist/validated/BbTimePickerInput.vue_vue_type_script_setup_true_lang.js +81 -0
  935. package/dist/validated/index.d.ts +29 -0
  936. package/dist/validated/useValidatedField.d.ts +93 -0
  937. package/dist/validated/useValidatedField.js +51 -0
  938. package/dist/validated.js +21 -0
  939. package/dist/vite-plugin.d.ts +261 -0
  940. package/dist/vite.js +603 -0
  941. package/llms.txt +107 -0
  942. package/package.json +181 -60
  943. package/scripts/lib/__fixtures__/validated-manifest.json +65 -0
  944. package/scripts/lib/ensure-manifest.mjs +39 -0
  945. package/scripts/lib/eslint-plugin-autofix.node.test.mjs +109 -0
  946. package/scripts/lib/eslint-plugin-recommended.node.test.mjs +87 -0
  947. package/scripts/lib/eslint-plugin-slots.node.test.mjs +271 -0
  948. package/scripts/lib/eslint-plugin.mjs +702 -0
  949. package/scripts/lib/eslint-plugin.node.test.mjs +193 -0
  950. package/scripts/lib/html-attributes.mjs +191 -0
  951. package/scripts/lib/mcp-config.mjs +126 -0
  952. package/scripts/lib/migrate-fix.mjs +115 -0
  953. package/scripts/lib/validate-bb-markup.mjs +488 -0
  954. package/dist/ai/BaseButton.md +0 -449
  955. package/dist/ai/BaseCheckbox.md +0 -512
  956. package/dist/ai/BaseCheckboxGroup.md +0 -597
  957. package/dist/ai/BaseColorInput.md +0 -461
  958. package/dist/ai/BaseDatePicker.md +0 -739
  959. package/dist/ai/BaseDatePickerInput.md +0 -1517
  960. package/dist/ai/BaseDialog.md +0 -610
  961. package/dist/ai/BaseInputContainer.md +0 -570
  962. package/dist/ai/BaseNumberInput.md +0 -509
  963. package/dist/ai/BaseRadio.md +0 -405
  964. package/dist/ai/BaseRadioGroup.md +0 -535
  965. package/dist/ai/BaseRating.md +0 -489
  966. package/dist/ai/BaseSelect.md +0 -1742
  967. package/dist/ai/BaseSlider.md +0 -871
  968. package/dist/ai/BaseSwitch.md +0 -322
  969. package/dist/ai/BaseSwitchGroup.md +0 -298
  970. package/dist/ai/BaseTag.md +0 -623
  971. package/dist/ai/BaseTextInput.md +0 -392
  972. package/dist/ai/BaseTextarea.md +0 -398
  973. package/dist/ai/BbChip.md +0 -147
  974. package/dist/ai/BbIntersection.md +0 -120
  975. package/dist/ai/BbRatio.md +0 -61
  976. package/dist/ai/BbRows.md +0 -307
  977. package/dist/ai/BbTab.md +0 -950
  978. package/dist/ai/CommonInputInnerContainer.md +0 -414
  979. package/dist/ai/CommonInputOuterContainer.md +0 -55
  980. package/dist/components/BaseButton/BaseButton.vue.d.ts +0 -14
  981. package/dist/components/BaseButton/types.d.ts +0 -159
  982. package/dist/components/BaseCheckbox/BaseCheckbox.vue.d.ts +0 -39
  983. package/dist/components/BaseCheckbox/types.d.ts +0 -213
  984. package/dist/components/BaseCheckboxGroup/BaseCheckboxGroup.vue.d.ts +0 -30
  985. package/dist/components/BaseCheckboxGroup/types.d.ts +0 -282
  986. package/dist/components/BaseColorInput/BaseColorInput.vue.d.ts +0 -35
  987. package/dist/components/BaseColorInput/ColorPalette.vue.d.ts +0 -13
  988. package/dist/components/BaseColorInput/types.d.ts +0 -233
  989. package/dist/components/BaseDatePicker/BaseDatePickerHeader.vue.d.ts +0 -15
  990. package/dist/components/BaseDatePicker/BaseDatePickerInputDaySelector.vue.d.ts +0 -58
  991. package/dist/components/BaseDatePicker/BaseDatePickerMonthSelector.vue.d.ts +0 -12
  992. package/dist/components/BaseDatePicker/BaseDatePickerYearSelector.vue.d.ts +0 -12
  993. package/dist/components/BaseDatePicker/types.d.ts +0 -100
  994. package/dist/components/BaseDatePickerInput/BaseDatePickerInput.vue.d.ts +0 -26
  995. package/dist/components/BaseDatePickerInput/types.d.ts +0 -206
  996. package/dist/components/BaseDialog/BaseDialog.vue.d.ts +0 -37
  997. package/dist/components/BaseDialog/types.d.ts +0 -180
  998. package/dist/components/BaseInputContainer/BaseInputContainer.vue.d.ts +0 -18
  999. package/dist/components/BaseInputContainer/types.d.ts +0 -126
  1000. package/dist/components/BaseNumberInput/BaseNumberInput.vue.d.ts +0 -46
  1001. package/dist/components/BaseNumberInput/types.d.ts +0 -191
  1002. package/dist/components/BaseRadio/BaseRadio.vue.d.ts +0 -31
  1003. package/dist/components/BaseRadio/types.d.ts +0 -173
  1004. package/dist/components/BaseRadioGroup/BaseRadioGroup.vue.d.ts +0 -30
  1005. package/dist/components/BaseRadioGroup/types.d.ts +0 -240
  1006. package/dist/components/BaseRating/BaseRating.vue.d.ts +0 -35
  1007. package/dist/components/BaseRating/types.d.ts +0 -144
  1008. package/dist/components/BaseSelect/BaseSelect.vue.d.ts +0 -28
  1009. package/dist/components/BaseSelect/types.d.ts +0 -470
  1010. package/dist/components/BaseSlider/BaseSlider.vue.d.ts +0 -38
  1011. package/dist/components/BaseSlider/types.d.ts +0 -201
  1012. package/dist/components/BaseSwitch/BaseSwitch.vue.d.ts +0 -34
  1013. package/dist/components/BaseSwitch/types.d.ts +0 -25
  1014. package/dist/components/BaseSwitchGroup/BaseSwitchGroup.vue.d.ts +0 -30
  1015. package/dist/components/BaseSwitchGroup/types.d.ts +0 -8
  1016. package/dist/components/BaseTag/BaseTag.vue.d.ts +0 -37
  1017. package/dist/components/BaseTag/types.d.ts +0 -136
  1018. package/dist/components/BaseTextInput/BaseTextInput.vue.d.ts +0 -33
  1019. package/dist/components/BaseTextInput/types.d.ts +0 -166
  1020. package/dist/components/BaseTextarea/BaseTextarea.vue.d.ts +0 -31
  1021. package/dist/components/BaseTextarea/types.d.ts +0 -151
  1022. package/dist/components/BbChip/BbChip.vue.d.ts +0 -17
  1023. package/dist/components/BbChip/types.d.ts +0 -23
  1024. package/dist/components/BbIntersection/BbIntersection.vue.d.ts +0 -23
  1025. package/dist/components/BbIntersection/types.d.ts +0 -36
  1026. package/dist/components/BbRatio/BbRatio.vue.d.ts +0 -14
  1027. package/dist/components/BbRatio/types.d.ts +0 -15
  1028. package/dist/components/BbRows/BbRows.vue.d.ts +0 -62
  1029. package/dist/components/BbRows/types.d.ts +0 -21
  1030. package/dist/components/BbTab/BbTab.vue.d.ts +0 -27
  1031. package/dist/components/BbTab/types.d.ts +0 -186
  1032. package/dist/components/CommonInputInnerContainer/CommonInputInnerContainer.vue.d.ts +0 -15
  1033. package/dist/components/CommonInputInnerContainer/types.d.ts +0 -47
  1034. package/dist/components/CommonInputOuterContainer/CommonInputOuterContainer.vue.d.ts +0 -11
  1035. package/dist/components/CommonInputOuterContainer/types.d.ts +0 -16
  1036. package/dist/composables/useModalsState.d.ts +0 -5
  1037. package/dist/composables/useQueue.d.ts +0 -58
  1038. package/dist/composables/useWizard.d.ts +0 -85
  1039. package/dist/i18n/en.d.ts +0 -67
  1040. package/dist/i18n/it.d.ts +0 -67
  1041. package/dist/index.css +0 -2
  1042. package/dist/index100.js +0 -6
  1043. package/dist/index101.js +0 -300
  1044. package/dist/index102.js +0 -16
  1045. package/dist/index103.js +0 -16
  1046. package/dist/index104.js +0 -27
  1047. package/dist/index109.js +0 -19
  1048. package/dist/index11.js +0 -42
  1049. package/dist/index110.js +0 -12
  1050. package/dist/index111.js +0 -19
  1051. package/dist/index112.js +0 -25
  1052. package/dist/index114.js +0 -7
  1053. package/dist/index115.js +0 -241
  1054. package/dist/index116.js +0 -5
  1055. package/dist/index117.js +0 -42
  1056. package/dist/index118.js +0 -5
  1057. package/dist/index119.js +0 -53
  1058. package/dist/index120.js +0 -5
  1059. package/dist/index121.js +0 -32
  1060. package/dist/index122.js +0 -5
  1061. package/dist/index124.js +0 -52
  1062. package/dist/index125.js +0 -5
  1063. package/dist/index126.js +0 -223
  1064. package/dist/index128.js +0 -6
  1065. package/dist/index129.js +0 -162
  1066. package/dist/index13.js +0 -92
  1067. package/dist/index130.js +0 -25
  1068. package/dist/index131.js +0 -51
  1069. package/dist/index132.js +0 -5
  1070. package/dist/index133.js +0 -607
  1071. package/dist/index135.js +0 -6
  1072. package/dist/index136.js +0 -14
  1073. package/dist/index137.js +0 -153
  1074. package/dist/index139.js +0 -6
  1075. package/dist/index14.js +0 -306
  1076. package/dist/index140.js +0 -224
  1077. package/dist/index141.js +0 -5
  1078. package/dist/index143.js +0 -128
  1079. package/dist/index145.js +0 -6
  1080. package/dist/index146.js +0 -8
  1081. package/dist/index147.js +0 -182
  1082. package/dist/index149.js +0 -6
  1083. package/dist/index15.js +0 -10
  1084. package/dist/index151.js +0 -4
  1085. package/dist/index152.js +0 -95
  1086. package/dist/index154.js +0 -6
  1087. package/dist/index155.js +0 -168
  1088. package/dist/index157.js +0 -6
  1089. package/dist/index158.js +0 -145
  1090. package/dist/index16.js +0 -59
  1091. package/dist/index160.js +0 -6
  1092. package/dist/index161.js +0 -53
  1093. package/dist/index163.js +0 -6
  1094. package/dist/index164.js +0 -16
  1095. package/dist/index166.js +0 -35
  1096. package/dist/index168.js +0 -6
  1097. package/dist/index169.js +0 -89
  1098. package/dist/index171.js +0 -6
  1099. package/dist/index172.js +0 -82
  1100. package/dist/index174.js +0 -6
  1101. package/dist/index175.js +0 -38
  1102. package/dist/index176.js +0 -461
  1103. package/dist/index177.js +0 -28
  1104. package/dist/index178.js +0 -66
  1105. package/dist/index18.js +0 -35
  1106. package/dist/index180.js +0 -162
  1107. package/dist/index181.js +0 -5
  1108. package/dist/index182.js +0 -217
  1109. package/dist/index183.js +0 -5
  1110. package/dist/index184.js +0 -112
  1111. package/dist/index185.js +0 -5
  1112. package/dist/index186.js +0 -459
  1113. package/dist/index188.js +0 -6
  1114. package/dist/index19.js +0 -4
  1115. package/dist/index192.js +0 -268
  1116. package/dist/index194.js +0 -6
  1117. package/dist/index195.js +0 -124
  1118. package/dist/index197.js +0 -6
  1119. package/dist/index198.js +0 -174
  1120. package/dist/index2.js +0 -20
  1121. package/dist/index20.js +0 -9
  1122. package/dist/index200.js +0 -6
  1123. package/dist/index201.js +0 -224
  1124. package/dist/index203.js +0 -6
  1125. package/dist/index204.js +0 -135
  1126. package/dist/index206.js +0 -6
  1127. package/dist/index207.js +0 -5
  1128. package/dist/index208.js +0 -170
  1129. package/dist/index21.js +0 -35
  1130. package/dist/index210.js +0 -6
  1131. package/dist/index211.js +0 -37
  1132. package/dist/index213.js +0 -6
  1133. package/dist/index214.js +0 -63
  1134. package/dist/index216.js +0 -6
  1135. package/dist/index217.js +0 -74
  1136. package/dist/index219.js +0 -6
  1137. package/dist/index22.js +0 -6
  1138. package/dist/index220.js +0 -65
  1139. package/dist/index222.js +0 -6
  1140. package/dist/index223.js +0 -67
  1141. package/dist/index225.js +0 -6
  1142. package/dist/index226.js +0 -41
  1143. package/dist/index228.js +0 -6
  1144. package/dist/index229.js +0 -10
  1145. package/dist/index23.js +0 -7
  1146. package/dist/index230.js +0 -22
  1147. package/dist/index232.js +0 -8
  1148. package/dist/index233.js +0 -297
  1149. package/dist/index235.js +0 -6
  1150. package/dist/index236.js +0 -47
  1151. package/dist/index237.js +0 -165
  1152. package/dist/index239.js +0 -6
  1153. package/dist/index24.js +0 -9
  1154. package/dist/index241.js +0 -159
  1155. package/dist/index243.js +0 -6
  1156. package/dist/index244.js +0 -134
  1157. package/dist/index246.js +0 -6
  1158. package/dist/index247.js +0 -167
  1159. package/dist/index249.js +0 -6
  1160. package/dist/index25.js +0 -24
  1161. package/dist/index250.js +0 -147
  1162. package/dist/index252.js +0 -6
  1163. package/dist/index253.js +0 -35
  1164. package/dist/index255.js +0 -6
  1165. package/dist/index256.js +0 -65
  1166. package/dist/index258.js +0 -6
  1167. package/dist/index259.js +0 -19
  1168. package/dist/index260.js +0 -5
  1169. package/dist/index261.js +0 -160
  1170. package/dist/index263.js +0 -6
  1171. package/dist/index264.js +0 -60
  1172. package/dist/index266.js +0 -6
  1173. package/dist/index267.js +0 -134
  1174. package/dist/index269.js +0 -6
  1175. package/dist/index27.js +0 -4
  1176. package/dist/index271.js +0 -206
  1177. package/dist/index273.js +0 -6
  1178. package/dist/index274.js +0 -85
  1179. package/dist/index275.js +0 -5
  1180. package/dist/index276.js +0 -55
  1181. package/dist/index277.js +0 -5
  1182. package/dist/index278.js +0 -164
  1183. package/dist/index28.js +0 -8
  1184. package/dist/index280.js +0 -6
  1185. package/dist/index281.js +0 -145
  1186. package/dist/index283.js +0 -6
  1187. package/dist/index284.js +0 -11
  1188. package/dist/index285.js +0 -200
  1189. package/dist/index287.js +0 -6
  1190. package/dist/index288.js +0 -241
  1191. package/dist/index29.js +0 -7
  1192. package/dist/index290.js +0 -6
  1193. package/dist/index291.js +0 -21
  1194. package/dist/index293.js +0 -6
  1195. package/dist/index294.js +0 -125
  1196. package/dist/index296.js +0 -6
  1197. package/dist/index297.js +0 -161
  1198. package/dist/index299.js +0 -6
  1199. package/dist/index30.js +0 -118
  1200. package/dist/index300.js +0 -127
  1201. package/dist/index302.js +0 -6
  1202. package/dist/index303.js +0 -20
  1203. package/dist/index305.js +0 -6
  1204. package/dist/index306.js +0 -116
  1205. package/dist/index307.js +0 -5
  1206. package/dist/index308.js +0 -507
  1207. package/dist/index31.js +0 -10
  1208. package/dist/index310.js +0 -6
  1209. package/dist/index311.js +0 -196
  1210. package/dist/index313.js +0 -6
  1211. package/dist/index314.js +0 -142
  1212. package/dist/index316.js +0 -6
  1213. package/dist/index317.js +0 -134
  1214. package/dist/index319.js +0 -6
  1215. package/dist/index32.js +0 -28
  1216. package/dist/index320.js +0 -162
  1217. package/dist/index322.js +0 -6
  1218. package/dist/index323.js +0 -319
  1219. package/dist/index325.js +0 -6
  1220. package/dist/index326.js +0 -40
  1221. package/dist/index327.js +0 -43
  1222. package/dist/index328.js +0 -665
  1223. package/dist/index33.js +0 -5
  1224. package/dist/index330.js +0 -6
  1225. package/dist/index331.js +0 -155
  1226. package/dist/index333.js +0 -6
  1227. package/dist/index334.js +0 -142
  1228. package/dist/index336.js +0 -6
  1229. package/dist/index337.js +0 -155
  1230. package/dist/index339.js +0 -6
  1231. package/dist/index34.js +0 -112
  1232. package/dist/index340.js +0 -58
  1233. package/dist/index341.js +0 -5
  1234. package/dist/index342.js +0 -20
  1235. package/dist/index344.js +0 -6
  1236. package/dist/index345.js +0 -142
  1237. package/dist/index347.js +0 -6
  1238. package/dist/index349.js +0 -109
  1239. package/dist/index351.js +0 -6
  1240. package/dist/index352.js +0 -55
  1241. package/dist/index353.js +0 -24
  1242. package/dist/index354.js +0 -23
  1243. package/dist/index355.js +0 -839
  1244. package/dist/index356.js +0 -474
  1245. package/dist/index357.js +0 -52
  1246. package/dist/index358.js +0 -7
  1247. package/dist/index36.js +0 -6
  1248. package/dist/index38.js +0 -63
  1249. package/dist/index39.js +0 -63
  1250. package/dist/index40.js +0 -9
  1251. package/dist/index42.js +0 -8
  1252. package/dist/index43.js +0 -179
  1253. package/dist/index44.js +0 -21
  1254. package/dist/index46.js +0 -385
  1255. package/dist/index48.js +0 -6
  1256. package/dist/index49.js +0 -33
  1257. package/dist/index5.js +0 -34
  1258. package/dist/index50.js +0 -12
  1259. package/dist/index51.js +0 -8
  1260. package/dist/index52.js +0 -106
  1261. package/dist/index53.js +0 -330
  1262. package/dist/index54.js +0 -97
  1263. package/dist/index55.js +0 -328
  1264. package/dist/index56.js +0 -28
  1265. package/dist/index57.js +0 -102
  1266. package/dist/index58.js +0 -157
  1267. package/dist/index6.js +0 -38
  1268. package/dist/index60.js +0 -6
  1269. package/dist/index61.js +0 -131
  1270. package/dist/index62.js +0 -5
  1271. package/dist/index65.js +0 -35
  1272. package/dist/index66.js +0 -26
  1273. package/dist/index68.js +0 -6
  1274. package/dist/index69.js +0 -54
  1275. package/dist/index7.js +0 -58
  1276. package/dist/index71.js +0 -6
  1277. package/dist/index72.js +0 -14
  1278. package/dist/index74.js +0 -6
  1279. package/dist/index75.js +0 -159
  1280. package/dist/index77.js +0 -6
  1281. package/dist/index78.js +0 -4
  1282. package/dist/index79.js +0 -4
  1283. package/dist/index80.js +0 -54
  1284. package/dist/index81.js +0 -5
  1285. package/dist/index82.js +0 -5
  1286. package/dist/index83.js +0 -141
  1287. package/dist/index85.js +0 -6
  1288. package/dist/index86.js +0 -65
  1289. package/dist/index88.js +0 -6
  1290. package/dist/index89.js +0 -30
  1291. package/dist/index9.js +0 -11
  1292. package/dist/index90.js +0 -19
  1293. package/dist/index91.js +0 -17
  1294. package/dist/index92.js +0 -9
  1295. package/dist/index93.js +0 -34
  1296. package/dist/index95.js +0 -16
  1297. package/dist/index96.js +0 -10
  1298. package/dist/index97.js +0 -18
  1299. package/dist/index98.js +0 -189
  1300. package/dist/types/VoidHtmlElements.d.ts +0 -1
  1301. package/dist/utilities/functions/add.d.ts +0 -1
  1302. package/dist/utilities/functions/booleanishToBoolean.d.ts +0 -6
  1303. package/dist/utilities/functions/capitalize.d.ts +0 -4
  1304. package/dist/utilities/functions/cloneDeep.d.ts +0 -1
  1305. package/dist/utilities/functions/debounce.d.ts +0 -1
  1306. package/dist/utilities/functions/drop.d.ts +0 -1
  1307. package/dist/utilities/functions/exceedsPrecision.d.ts +0 -1
  1308. package/dist/utilities/functions/findRight.d.ts +0 -4
  1309. package/dist/utilities/functions/findRightIndex.d.ts +0 -4
  1310. package/dist/utilities/functions/flow.d.ts +0 -1
  1311. package/dist/utilities/functions/getHueFromRGB.d.ts +0 -9
  1312. package/dist/utilities/functions/groupBy.d.ts +0 -6
  1313. package/dist/utilities/functions/gt.d.ts +0 -7
  1314. package/dist/utilities/functions/hexToRGB.d.ts +0 -7
  1315. package/dist/utilities/functions/hslToHex.d.ts +0 -1
  1316. package/dist/utilities/functions/includes.d.ts +0 -1
  1317. package/dist/utilities/functions/initial.d.ts +0 -1
  1318. package/dist/utilities/functions/isCssColor.d.ts +0 -5
  1319. package/dist/utilities/functions/lt.d.ts +0 -7
  1320. package/dist/utilities/functions/makeUrl.d.ts +0 -1
  1321. package/dist/utilities/functions/mapKeys.d.ts +0 -5
  1322. package/dist/utilities/functions/mapValues.d.ts +0 -1
  1323. package/dist/utilities/functions/matchesPropertyInsensitive.d.ts +0 -1
  1324. package/dist/utilities/functions/max.d.ts +0 -2
  1325. package/dist/utilities/functions/mean.d.ts +0 -4
  1326. package/dist/utilities/functions/merge.d.ts +0 -11
  1327. package/dist/utilities/functions/millisecondsTo.d.ts +0 -1
  1328. package/dist/utilities/functions/negate.d.ts +0 -4
  1329. package/dist/utilities/functions/normalizeItemGroups.d.ts +0 -13
  1330. package/dist/utilities/functions/omit.d.ts +0 -2
  1331. package/dist/utilities/functions/overEvery.d.ts +0 -4
  1332. package/dist/utilities/functions/pick.d.ts +0 -1
  1333. package/dist/utilities/functions/replace.d.ts +0 -1
  1334. package/dist/utilities/functions/replaceInTree.d.ts +0 -4
  1335. package/dist/utilities/functions/retry.d.ts +0 -5
  1336. package/dist/utilities/functions/roundToTheNearest.d.ts +0 -8
  1337. package/dist/utilities/functions/set.d.ts +0 -15
  1338. package/dist/utilities/functions/stub.d.ts +0 -6
  1339. package/dist/utilities/functions/transposePercent.d.ts +0 -9
  1340. package/dist/utilities/functions/tryTo.d.ts +0 -2
  1341. package/dist/utilities/functions/uniqBy.d.ts +0 -1
  1342. /package/dist/{index64.js → _virtual/_plugin-vue_export-helper.js} +0 -0
  1343. /package/dist/components/{BaseButton → BbBaseButton}/RouterComponent.vue.d.ts +0 -0
  1344. /package/dist/components/{BaseDatePicker/BaseDatePicker.vue.d.ts → BbBaseDatePicker/BbBaseDatePicker.vue.d.ts} +0 -0
  1345. /package/dist/{index165.js → composables/useArray.js} +0 -0
  1346. /package/dist/{index17.js → composables/useFrameworkDetection.js} +0 -0
  1347. /package/dist/{index12.js → composables/useId.js} +0 -0
  1348. /package/dist/{index107.js → utilities/functions/chunk.js} +0 -0
  1349. /package/dist/{index8.js → utilities/functions/clamp.js} +0 -0
  1350. /package/dist/{index150.js → utilities/functions/curry.js} +0 -0
  1351. /package/dist/{index45.js → utilities/functions/extractDomContainer.js} +0 -0
  1352. /package/dist/{index270.js → utilities/functions/findInTree.js} +0 -0
  1353. /package/dist/{index348.js → utilities/functions/flattenTree.js} +0 -0
  1354. /package/dist/{index41.js → utilities/functions/get.js} +0 -0
  1355. /package/dist/{index189.js → utilities/functions/head.js} +0 -0
  1356. /package/dist/{index108.js → utilities/functions/identity.js} +0 -0
  1357. /package/dist/{index179.js → utilities/functions/indexBy.js} +0 -0
  1358. /package/dist/{index37.js → utilities/functions/isHex.js} +0 -0
  1359. /package/dist/{index94.js → utilities/functions/isNil.js} +0 -0
  1360. /package/dist/{index26.js → utilities/functions/isNotNil.js} +0 -0
  1361. /package/dist/{index105.js → utilities/functions/last.js} +0 -0
  1362. /package/dist/{index142.js → utilities/functions/noop.js} +0 -0
  1363. /package/dist/{index231.js → utilities/functions/parseWidthString.js} +0 -0
  1364. /package/dist/{index240.js → utilities/functions/pickBy.js} +0 -0
  1365. /package/dist/{index123.js → utilities/functions/range.js} +0 -0
  1366. /package/dist/{index190.js → utilities/functions/snapToStep.js} +0 -0
  1367. /package/dist/{index191.js → utilities/functions/transpose.js} +0 -0
  1368. /package/dist/{index106.js → utilities/functions/validateDateFormat.js} +0 -0
  1369. /package/dist/{index10.js → utilities/functions/wait.js} +0 -0
@@ -1,1669 +1,1346 @@
1
1
  # BbSelectPopover
2
2
 
3
- ## Template & Script
3
+ ## Agent Contract
4
+
5
+ - Safety level: **Consumer API**
6
+ - Group: **Selection**
7
+ - Description: Provides popover-driven option selection and search.
8
+ - Usage rule: Prefer this component for consumer-facing implementations.
9
+ - Implementation source (only when the contract below is not enough): [source/BbSelectPopover.md](./source/BbSelectPopover.md)
10
+
11
+ ## Usage & Guidelines
12
+
13
+ ### When to use
14
+
15
+ `BbSelectPopover` is `BbSelect` with the inline form input removed: **you own the
16
+ trigger**, it owns search, filtering, keyboard navigation, single/multiple
17
+ selection and the virtualized options list. Reach for it when the control that
18
+ opens the picker is _not_ a form field — a status pill, an avatar stack, a role
19
+ badge, a toolbar button, a table-cell chip. It is the right tool for
20
+ command-palette and inline-edit patterns.
21
+
22
+ Prefer a sibling when the shape is different:
23
+
24
+ - You want a **labelled, bordered form control** with hint/error/description
25
+ states → `BbSelect` (`./BbSelect.md`). That is a field, not a trigger.
26
+ - A small, always-visible exclusive choice → `BbRadioGroup`; small static
27
+ multi-choice → `BbCheckboxGroup` / `BbSwitchGroup`.
28
+ - Values the user _invents_ → `BbTag`; a known-but-growable set →
29
+ `BbSelectPopover` (or `BbSelect`) with `option:add`.
30
+
31
+ Everything from the **Options and Items** and **Fetch Items** playbooks carries
32
+ over unchanged — this component shares `BbSelect`'s option engine. This guide
33
+ covers what is _specific_ to the popover: the activator, and the traps of
34
+ driving a trigger you render yourself.
35
+
36
+ ### Map options with `item-text` / `item-value`
37
+
38
+ Pass your domain objects to `items` as they are and name the display/value
39
+ fields with `item-text` / `item-value` (dot-paths or extractor functions). The
40
+ `v-model` holds the resolved **value**, not the whole object. The value-identity
41
+ rules are the shared ones (see the Options and Items playbook), in brief:
42
+
43
+ - Primitive `items` (`string[]` / `number[]`) need no mapping props; for object
44
+ items always set both.
45
+ - Matching compares **value hashes** (deep structural equality), so object
46
+ values survive refetches — but prefer stable primitive ids.
47
+ - Options resolving to a **duplicate value are silently dropped** (first wins).
48
+ - Gate individual options with `selectable` — a boolean (`false` disables every
49
+ option) or a predicate `(item) => boolean`; rejected options render disabled
50
+ and keyboard navigation skips them. A `disabled` field on the item object is
51
+ inert domain data — feed it to the predicate
52
+ (`:selectable="(item) => !item.disabled"`) if it encodes availability.
53
+
54
+ ### Wire up an activator
55
+
56
+ Provide the trigger through the `#activator` slot and **spread its `props` onto
57
+ your element** with `v-bind="props"` — that wires the popover reference and the
58
+ open/close handlers. The full slot scope:
59
+
60
+ - `props` — spread onto the focusable trigger element.
61
+ - `shown` — is the popover open (reflect it visually).
62
+ - `toggle` / `open` / `close` — imperative open-state control (all async).
63
+ - `clear` — empty the selection (and query).
64
+ - `focus` — focus the search field (or the listbox when writing is disabled).
65
+ - `query` — the current search string.
66
+ - `selectedOptions` — the resolved selected options (`.text` / `.value` /
67
+ `.item`) — **popover state** (see below).
68
+ - `text` — display text of the current selection — **popover state** (see below).
69
+ - `disabled` / `readonly` / `loading` — state mirrors for styling the trigger.
70
+
71
+ **The trigger must not depend on the popover's state — label it from your own
72
+ data.** The popover is an _optional_ editing affordance: it may never be opened,
73
+ and whether it has been opened must never change how the trigger reads. `text`
74
+ and `selectedOptions` resolve the model against **loaded options**, so with a
75
+ provider they stay empty until that provider first runs — by default, the first
76
+ open. A trigger fed from them renders blank and then flickers into truth; a
77
+ trigger fed from your own data is correct on first paint and stays that way.
78
+
79
+ The robust pattern — used in the example — is a `computed` that resolves the
80
+ label from the model against your own data:
81
+
82
+ ```ts
83
+ const assigneeLabel = computed(
84
+ () => people.find((p) => p.id === assignee.value)?.name ?? 'Unassigned'
85
+ );
86
+ ```
87
+
88
+ (Array `items` do resolve on mount, so `text` is populated from the first paint
89
+ there — but keep labelling from your own data anyway: it is the same amount of
90
+ code, and it does not change meaning the day the array becomes a provider.)
91
+
92
+ **Filter-pill assignee picker**
4
93
 
5
94
  ```vue
6
95
  <template>
7
- <slot
8
- v-if="!hasExternalActivator"
9
- name="activator"
10
- v-bind="{
11
- props: {
12
- ref: setActivatorRef,
13
- },
14
- shown,
15
- disabled,
16
- readonly,
17
- loading: computedLoading,
18
- query,
19
- selectedOptions,
20
- text: triggerInputValue,
21
- clear: onClear,
22
- open,
23
- close,
24
- toggle,
25
- }"
26
- />
27
- <CommonPopover
28
- v-model="shown"
29
- v-bind="$attrs"
30
- :anchor="activatorEl"
31
- :arrow-padding="arrowPadding"
32
- :boundary="boundary"
33
- class="bb-select-popover"
34
- :class="{
35
- 'bb-select-popover--errors': hasErrors,
36
- 'bb-select-popover--loading': computedLoading,
37
- }"
38
- :flip="flip"
39
- :placement="placement"
40
- :offset="offset"
41
- :padding="padding"
42
- :transition-duration="transitionDuration"
43
- :hide-arrow="hideArrow"
44
- :style="panelStyles"
96
+ <div
97
+ class="flex max-w-sm items-center gap-1.5 rounded-[var(--bb-radius)] border p-2"
45
98
  >
46
- <div
47
- v-if="computedAllowWriting"
48
- class="bb-select-popover__search-container"
49
- >
50
- <input
51
- :id="`${id}_search`"
52
- ref="searchInput"
53
- v-model="query"
54
- :aria-activedescendant="activeDescendantId"
55
- :aria-controls="renderListBox ? `${id}_listbox` : undefined"
56
- :aria-describedby="computedAriaDescribedby"
57
- :aria-invalid="computedAriaInvalid"
58
- :aria-label="searchInputAriaLabel"
59
- :autocomplete="autocomplete"
60
- class="bb-select-popover__search-input"
61
- :inputmode="inputmode"
62
- :tabindex="shown ? 0 : -1"
63
- role="searchbox"
64
- :type="'text'"
65
- @blur.stop="onSearchInputBlur"
66
- @change.stop="onSearchInputChange"
67
- @focus.stop="onSearchInputFocus"
68
- @input.stop="onSearchInputInput"
69
- @keydown.stop.prevent.down="onArrowDown"
70
- @keydown.stop.prevent.enter="onEnter"
71
- @keydown.stop.prevent.esc="onEscape"
72
- @keydown.stop.prevent.up="onArrowUp"
73
- />
74
- <ErrorIcon
75
- aria-hidden="true"
76
- class="bb-select-popover__search-error-icon"
77
- focusable="false"
78
- />
79
- <BbSpinner
80
- aria-hidden="true"
81
- class="bb-select-popover__search-spinner"
82
- focusable="false"
83
- />
84
- <svg
85
- class="bb-select-popover__search-icon"
86
- xmlns="http://www.w3.org/2000/svg"
87
- viewBox="0 0 24 24"
88
- aria-hidden="true"
89
- >
90
- <path
91
- fill="none"
92
- stroke="currentColor"
93
- stroke-linecap="round"
94
- stroke-linejoin="round"
95
- stroke-width="2"
96
- d="m21 21-4.343-4.343m0 0A8 8 0 1 0 5.343 5.343a8 8 0 0 0 11.314 11.314"
97
- />
98
- </svg>
99
- </div>
100
- <button
101
- v-else
102
- ref="popoverFocusProxy"
103
- class="bb-select-popover__focus-proxy sr-only"
104
- type="button"
105
- :aria-controls="`${id}_listbox`"
106
- :aria-describedby="computedAriaDescribedby"
107
- :aria-invalid="computedAriaInvalid"
108
- :aria-label="searchInputAriaLabel"
109
- tabindex="-1"
110
- @focus="onPopoverFocusProxyFocus"
111
- @keydown.stop.prevent.down="onArrowDown"
112
- @keydown.stop.prevent.up="onArrowUp"
113
- @keydown.stop.prevent.enter="onEnter"
114
- @keydown.stop.prevent.esc="onEscape"
99
+ <span class="pr-1 text-xs font-medium text-[color:var(--bb-text-muted)]"
100
+ >Assignee</span
115
101
  >
116
- Focus options
117
- </button>
118
- <div
119
- class="bb-select-popover__options-outer"
120
- :aria-hidden="shown ? undefined : 'true'"
121
- :inert="!shown"
102
+ <BbSelectPopover
103
+ v-model="assignee"
104
+ compact
105
+ item-text="fullName"
106
+ item-value="id"
107
+ :items="teammates"
108
+ width="240px"
122
109
  >
123
- <slot name="options:prepend:outer" :focus="focusPopoverContent" />
124
- </div>
125
- <ListBox
126
- :id="`${id}_listbox`"
127
- ref="optionsContainer"
128
- :compact="compact"
129
- :loading="computedLoading"
130
- :loading-text="loadingText"
131
- :multiple="multiple"
132
- :no-data-text="noDataText"
133
- :open="shown"
134
- :options="groupBy ? undefined : filteredOptions"
135
- :groups="groupBy ? groupedOptions : undefined"
136
- :header-height="headerHeight"
137
- :option-height="itemHeight"
138
- @focused:change="onListboxFocusedChange"
139
- @option:selected="onOptionSelected"
140
- @option:unselected="onOptionUnselected"
141
- >
142
- <template #options:prepend
143
- ><slot name="options:prepend" :focus="focusPopoverContent"
144
- /></template>
145
- <template #loading><slot name="loading" :query="query" /></template>
146
- <template #no-data
147
- ><slot name="no-data" :query="query" :focus="focusPopoverContent"
148
- /></template>
149
- <template #options:append
150
- ><slot name="options:append" :focus="focusPopoverContent"
151
- /></template>
152
- <template #option="data"
153
- ><slot :loading="computedLoading" name="option" v-bind="data"
154
- /></template>
155
- <template #group="data"><slot name="group" v-bind="data" /></template>
156
- </ListBox>
157
- <div
158
- class="bb-select-popover__options-outer"
159
- :aria-hidden="shown ? undefined : 'true'"
160
- :inert="!shown"
161
- >
162
- <slot name="options:append:outer" :focus="focusPopoverContent" />
163
- </div>
164
- </CommonPopover>
110
+ <template #activator="{ props }">
111
+ <!-- The badge IS the trigger — Linear filter-pill grammar. Label
112
+ from our own state, never the slot's `text` (empty until first open
113
+ with a provider). -->
114
+ <BbBadge
115
+ append:icon="lucide:chevron-down"
116
+ prepend:icon="lucide:user"
117
+ size="lg"
118
+ variant="outline"
119
+ >
120
+ <BbBadgeButton v-bind="props">{{
121
+ assigneeLabel || 'Assign'
122
+ }}</BbBadgeButton>
123
+ </BbBadge>
124
+ </template>
125
+ </BbSelectPopover>
126
+ </div>
165
127
  </template>
128
+ <script setup lang="ts">
129
+ import { computed, ref } from 'vue';
130
+ import { BbBadge, BbBadgeButton, BbSelectPopover } from 'bitboss-ui';
166
131
 
167
- <script setup lang="ts" generic="Item = any">
168
- import type { HTMLAttributes, InputHTMLAttributes } from 'vue';
169
- import type { CommonProps } from '@/types/CommonProps';
170
- import type { Option as BaseOption, GroupedOptions } from '@/types/Option';
171
- import { computed, ref, nextTick, watch, onBeforeUnmount } from 'vue';
172
- import { extractDomContainer } from '@/utilities/functions/extractDomContainer';
173
- import { get } from '@/utilities/functions/get';
174
- import { hash } from '@/utilities/functions/hash';
175
- import { isNil } from '@/utilities/functions/isNil';
176
- import { matchAnyKey } from '@/utilities/functions/matchAnyKey';
177
- import { parseWidthString } from '@/utilities/functions/parseWidthString';
178
- import { toRef } from 'vue';
179
- import { useArray } from '@/composables/useArray';
180
- import { useBaseOptions } from '@/composables/useBaseOptions';
181
- import { useCoherence } from '@/composables/useCoherence';
182
- import { useElementSize, useIntersectionObserver } from '@vueuse/core';
183
- import { useHashedWatcher } from '@/composables/useHashedWatcher';
184
- import { useId } from '@/composables/useId';
185
- import { useIndexById } from '@/composables/useIndexById';
186
- import { useItemsGetter } from '@/composables/useItemsGetter';
187
- import { useMobile } from '@/composables/useMobile';
188
- import { usePrefill } from '@/composables/usePrefill';
189
- import { useUntil } from '@/composables/useUntil';
190
- import { wait } from '@/utilities/functions/wait';
191
- import { BbSpinner } from '@/index';
192
- import CommonPopover from '../CommonPopover/CommonPopover.vue';
193
- import ErrorIcon from '../ErrorIcon/ErrorIcon.vue';
194
- import ListBox from '../ListBox/ListBox.vue';
195
- import { waitFor } from '@/utilities/functions/waitFor';
196
- import type {
197
- BbSelectPopoverEvents,
198
- BbSelectPopoverProps,
199
- BbSelectPopoverSlots,
200
- } from './types';
201
-
202
- const props = withDefaults(defineProps<BbSelectPopoverProps<Item>>(), {
203
- allowWriting: true,
204
- arrowPadding: 10,
205
- autocomplete: 'off',
206
- depsDebounceTime: 0,
207
- dependencies: () => [],
208
- filterBy: () => [],
209
- flip: true,
210
- hideArrow: true,
211
- max: Infinity,
212
- modelValueDebounceTime: 0,
213
- offset: 4,
214
- padding: 10,
215
- placement: 'bottom',
216
- prefill: 'interaction',
217
- queryDebounceTime: 500,
218
- transitionDuration: 300,
219
- width: '200',
220
- });
221
-
222
- const emit = defineEmits<BbSelectPopoverEvents>();
223
-
224
- defineSlots<BbSelectPopoverSlots<Item>>();
225
- defineOptions({ inheritAttrs: false });
226
-
227
- if (props.multiple && !Array.isArray(props.modelValue)) {
228
- throw new Error('Multiple is set to "true" but modelValue is not an array.');
229
- }
230
-
231
- /**
232
- * START ELEMENT REFERENCES
233
- */
234
- const activatorEl = ref<HTMLElement>();
235
- const optionsContainer = ref<any | null>(null);
236
- const searchInput = ref<HTMLInputElement | null>(null);
237
- const popoverFocusProxy = ref<HTMLButtonElement | null>(null);
238
- const activeDescendantId = ref<string>();
239
- const { width: activatorWidth } = useElementSize(
240
- activatorEl,
241
- { width: 0, height: 0 },
242
- {
243
- box: 'border-box',
244
- }
245
- );
246
- /**
247
- * END ELEMENT REFERENCES
248
- */
249
-
250
- /**
251
- * START ACTIVATOR MANAGEMENT
252
- */
253
- const hasExternalActivator = computed(() => props.activator != null);
254
-
255
- const setActivatorRef = (reference: unknown) => {
256
- const el = extractDomContainer(reference);
257
- if (!el) return;
258
- activatorEl.value = el;
132
+ type Teammate = {
133
+ id: string;
134
+ fullName: string;
259
135
  };
260
136
 
261
- watch(
262
- () => props.activator,
263
- (val) => {
264
- if (val) setActivatorRef(val);
265
- },
266
- { immediate: true }
267
- );
268
- /**
269
- * END ACTIVATOR MANAGEMENT
270
- */
137
+ const teammates: Teammate[] = [
138
+ { id: 'ada', fullName: 'Ada Lovelace' },
139
+ { id: 'grace', fullName: 'Grace Hopper' },
140
+ { id: 'alan', fullName: 'Alan Turing' },
141
+ { id: 'maggie', fullName: 'Margaret Hamilton' },
142
+ ];
271
143
 
272
- const { isMobile } = useMobile();
273
- const computedAllowWriting = computed(() => {
274
- if (props.allowWriting === 'not-mobile') return !isMobile.value;
275
- return !!props.allowWriting;
276
- });
277
- const inputmode = computed(() =>
278
- props.allowWriting === 'not-mobile' && isMobile.value ? 'none' : undefined
279
- );
280
- const searchInputAriaLabel = computed(
281
- () => props.searchInputAriaLabel ?? 'Search options'
282
- );
144
+ const assignee = ref<string | null>(null);
283
145
 
284
- const id = props.id || useId().id.value;
285
- const computedAriaInvalid = computed(() => {
286
- const isInvalid = props.ariaInvalid ?? !!props.hasErrors;
287
- return isInvalid ? 'true' : undefined;
288
- });
289
- const computedAriaDescribedby = computed(() => {
290
- const describedBy = props.ariaDescribedby;
291
- if (Array.isArray(describedBy)) {
292
- const normalized = describedBy
293
- .map((value) => value.trim())
294
- .filter(Boolean)
295
- .join(' ');
296
- return normalized || undefined;
297
- }
298
- if (typeof describedBy === 'string') {
299
- const normalized = describedBy.trim();
300
- return normalized || undefined;
301
- }
302
- return undefined;
303
- });
304
-
305
- const { resume, pause } = useIntersectionObserver(
306
- activatorEl,
307
- async ([{ intersectionRatio }]) => {
308
- if (intersectionRatio !== 1 && shown.value) {
309
- await close();
310
- }
311
- },
312
- { threshold: [0, 1], immediate: false }
146
+ const assigneeLabel = computed(
147
+ () => teammates.find((t) => t.id === assignee.value)?.fullName ?? ''
313
148
  );
149
+ </script>
150
+ ```
314
151
 
315
- const normalizedWidth = computed(() => {
316
- if (props.width === 'auto') return 'auto';
317
- if (props.width == null || props.width === '') {
318
- return activatorWidth.value ? `${activatorWidth.value}px` : '320px';
319
- }
152
+ ### Multiple selection
320
153
 
321
- try {
322
- const { value, unit } = parseWidthString(props.width);
323
- if (unit === '%') {
324
- if (!activatorWidth.value) return '320px';
325
- return `${activatorWidth.value * (value / 100)}px`;
326
- }
327
- return `${value}${unit}`;
328
- } catch {
329
- if (typeof props.width === 'string') return props.width.trim();
330
- return activatorWidth.value ? `${activatorWidth.value}px` : '320px';
331
- }
332
- });
154
+ Add `multiple` and the model becomes an array — it **must be seeded as one**
155
+ (`ref<string[]>([])`); a non-array model **throws at setup**
156
+ (`"Multiple is set to \"true\" but modelValue is not an array."`). Cap the count
157
+ with `max`: at the cap, unselected options auto-disable while selected ones never
158
+ do, so the user can always deselect. Because the trigger is yours, _you_
159
+ summarise the selection — a count, a chip cluster, an avatar stack — from
160
+ `selectedOptions` or your own model.
333
161
 
334
- const panelStyles = computed(() => ({
335
- '--bb-select-popover-width': normalizedWidth.value,
336
- }));
162
+ **Reviewers filter pill with a live count**
337
163
 
338
- /**
339
- * START FOCUS HELPERS
340
- */
341
- const focusActivator = () => {
342
- activatorEl.value?.focus();
343
- };
344
- const focusSearchInput = () => {
345
- if (searchInput.value instanceof HTMLInputElement) {
346
- searchInput.value.focus();
347
- }
348
- };
349
- const focusPopoverFocusProxy = () => {
350
- if (popoverFocusProxy.value instanceof HTMLButtonElement) {
351
- popoverFocusProxy.value.focus();
352
- }
353
- };
354
- const focusPopoverContent = () => {
355
- if (computedAllowWriting.value) {
356
- focusSearchInput();
357
- return;
358
- }
359
- focusPopoverFocusProxy();
360
- };
361
- /**
362
- * END FOCUS HELPERS
363
- */
164
+ ```vue
165
+ <template>
166
+ <div
167
+ class="flex max-w-sm items-center gap-1.5 rounded-[var(--bb-radius)] border p-2"
168
+ >
169
+ <span class="pr-1 text-xs font-medium text-[color:var(--bb-text-muted)]"
170
+ >Filters</span
171
+ >
172
+ <BbSelectPopover
173
+ v-model="reviewers"
174
+ compact
175
+ item-text="name"
176
+ item-value="id"
177
+ :items="people"
178
+ :max="4"
179
+ multiple
180
+ width="240px"
181
+ >
182
+ <template #activator="{ props }">
183
+ <!-- Summarise the multi-select yourself — a live count on the pill. -->
184
+ <BbBadge
185
+ append:icon="lucide:chevron-down"
186
+ prepend:icon="lucide:users"
187
+ size="lg"
188
+ variant="outline"
189
+ >
190
+ <BbBadgeButton v-bind="props"
191
+ >Reviewers ({{ reviewers.length }})</BbBadgeButton
192
+ >
193
+ </BbBadge>
194
+ </template>
195
+ </BbSelectPopover>
196
+ </div>
197
+ </template>
198
+ <script setup lang="ts">
199
+ import { ref } from 'vue';
200
+ import { BbBadge, BbBadgeButton, BbSelectPopover } from 'bitboss-ui';
201
+
202
+ type Person = { id: string; name: string };
203
+
204
+ const people: Person[] = [
205
+ { id: 'ada', name: 'Ada Lovelace' },
206
+ { id: 'grace', name: 'Grace Hopper' },
207
+ { id: 'alan', name: 'Alan Turing' },
208
+ { id: 'katherine', name: 'Katherine Johnson' },
209
+ { id: 'ken', name: 'Ken Thompson' },
210
+ ];
211
+
212
+ // `multiple` requires an array model from the start.
213
+ const reviewers = ref<string[]>(['ada', 'grace']);
214
+ </script>
215
+ ```
364
216
 
365
- /**
366
- * Search input focus keeps the whole control in active state.
367
- */
368
- const onSearchInputFocus = (event: FocusEvent) => {
369
- emit('focus', event);
370
- setActive();
371
- };
217
+ ### Custom option rows
372
218
 
373
- const onSearchInputBlur = (event: FocusEvent) => {
374
- emit('blur', event);
375
- syncActiveStateOnBlur();
376
- };
219
+ The `#option` slot replaces each row — exposing the raw `item`, resolved `text` /
220
+ `value`, the row `index`, and `selected` / `focused` / `disabled` / `loading`
221
+ flags — so options can carry avatars, badges or secondary metadata. Rows are
222
+ fixed-height and virtualized: if your markup is taller than the default 40px
223
+ (compact 32px), set `item-height` to match — and `header-height` for grouped
224
+ headers.
377
225
 
378
- const onSearchInputChange = (event: Event) => {
379
- emit('change', event);
380
- };
226
+ **Option rows with avatar initials**
381
227
 
382
- const onPopoverFocusProxyFocus = (_event: FocusEvent) => {
383
- setActive();
384
- };
228
+ ```vue
229
+ <template>
230
+ <div
231
+ class="flex max-w-sm items-center gap-1.5 rounded-[var(--bb-radius)] border p-2"
232
+ >
233
+ <span class="pr-1 text-xs font-medium text-[color:var(--bb-text-muted)]"
234
+ >Owner</span
235
+ >
236
+ <BbSelectPopover
237
+ v-model="owner"
238
+ compact
239
+ :item-height="40"
240
+ item-text="label"
241
+ item-value="value"
242
+ :items="people"
243
+ width="240px"
244
+ >
245
+ <template #activator="{ props }">
246
+ <BbBadge
247
+ append:icon="lucide:chevron-down"
248
+ prepend:icon="lucide:user"
249
+ size="lg"
250
+ variant="outline"
251
+ >
252
+ <BbBadgeButton v-bind="props">{{
253
+ ownerLabel || 'Set owner'
254
+ }}</BbBadgeButton>
255
+ </BbBadge>
256
+ </template>
257
+ <template #option="{ item, text, selected }">
258
+ <span class="flex w-full items-center gap-2">
259
+ <BbAvatar :alt="text" size="sm">{{ item.initials }}</BbAvatar>
260
+ <span class="min-w-0 flex-1 truncate">{{ text }}</span>
261
+ <BbIcon
262
+ v-if="selected"
263
+ class="shrink-0 text-[color:var(--bb-text-muted)]"
264
+ icon="lucide:check"
265
+ :size="14"
266
+ />
267
+ </span>
268
+ </template>
269
+ </BbSelectPopover>
270
+ </div>
271
+ </template>
272
+ <script setup lang="ts">
273
+ import { computed, ref } from 'vue';
274
+ import {
275
+ BbAvatar,
276
+ BbBadge,
277
+ BbBadgeButton,
278
+ BbIcon,
279
+ BbSelectPopover,
280
+ } from 'bitboss-ui';
281
+
282
+ type Person = { label: string; value: string; initials: string };
283
+
284
+ const people: Person[] = [
285
+ { label: 'Ada Lovelace', value: 'ada', initials: 'AL' },
286
+ { label: 'Grace Hopper', value: 'grace', initials: 'GH' },
287
+ { label: 'Alan Turing', value: 'alan', initials: 'AT' },
288
+ ];
289
+
290
+ const owner = ref<string | null>(null);
291
+ const ownerLabel = computed(
292
+ () => people.find((p) => p.value === owner.value)?.label ?? ''
293
+ );
294
+ </script>
295
+ ```
385
296
 
386
- /**
387
- * Search on user typing inside the popover search field.
388
- */
389
- const onSearchInputInput = (event: Event) => {
390
- emit('input', event);
391
- debouncedGetter(query.value, false, props.modelValue);
392
- };
297
+ ### Fetch options with a provider
393
298
 
394
- const onListboxFocusedChange = (id: string | undefined) => {
395
- activeDescendantId.value = id;
396
- };
299
+ When options come from a backend, pass a **function** to `items`. It receives
300
+ `(query, prefill, modelValue)` and returns `Item[]` or a `Promise<Item[]>` — the
301
+ full call matrix is the shared one in the Fetch Items playbook. The essentials:
397
302
 
398
- /**
399
- * On click outside of the activator and popover, close the panel and remove active state.
400
- */
401
- const onOutsideInteraction = async (event: Event) => {
402
- const target =
403
- event.target instanceof Element
404
- ? event.target
405
- : event.target instanceof Text
406
- ? event.target.parentElement
407
- : null;
408
- if (!target) return;
409
- const insideActivator = activatorEl.value?.contains(target);
410
- const insidePopover = !!target.closest('.bb-common-popover');
411
- if (insideActivator || insidePopover) return;
412
- await close();
413
- setInactive();
414
- };
303
+ - `prefill === false` means exactly one thing: **the user typed** — search then.
304
+ - Every component-initiated call (first load, dependency change, model change)
305
+ passes `prefill === true` and expects the current selection to stay resolvable
306
+ in the response — so return the selected items (by id) to keep the trigger
307
+ label and chips accurate.
308
+ - `modelValue` is your v-model as-is; the prop types it `any` — an array in
309
+ `multiple` mode, the raw model value (possibly `null`) in single mode.
415
310
 
416
- const canProcessKeyboardBindings = computed(() => {
417
- if (props.readonly) return false;
418
- if (props.disabled) return false;
419
- if (computedLoading.value) return false;
420
- return true;
421
- });
311
+ Runtime guarantees you should not re-implement: **debouncing** (`query-debounce-time`
312
+ default 500ms; `deps-debounce-time` and `model-value-debounce-time` default 0),
313
+ **race protection** (out-of-order responses discarded), **loading** (in-flight
314
+ requests set the slot's `loading` flag automatically — the `loading` prop is only
315
+ for _external_ pending state), and **errors** (a rejected provider is logged and
316
+ the previous items kept — surface failures yourself via `useToast`). Enable
317
+ `stash` to accumulate picked options across searches so chosen values stay
318
+ resolvable even when later responses omit them.
422
319
 
423
- /**
424
- * On first open the listbox is lazily mounted.
425
- * Wait a few micro-cycles so imperative focus calls don't no-op.
426
- */
427
- const waitForOptionsContainer = async () =>
428
- waitFor(() => !!optionsContainer.value, 100);
320
+ **Async, debounced destination picker**
429
321
 
430
- const focusFirstSelectedOption = () => {
431
- const firstSelected = selectedOptions.value[0];
432
- if (firstSelected?.valueHash) {
433
- optionsContainer.value?.focusByHash(firstSelected.valueHash);
434
- return;
435
- }
436
- optionsContainer.value?.focusFirstSelected();
437
- };
322
+ ```vue
323
+ <template>
324
+ <div
325
+ class="flex max-w-sm items-center gap-1.5 rounded-[var(--bb-radius)] border p-2"
326
+ >
327
+ <span class="pr-1 text-xs font-medium text-[color:var(--bb-text-muted)]"
328
+ >Trip</span
329
+ >
330
+ <BbSelectPopover
331
+ v-model="destination"
332
+ compact
333
+ item-text="label"
334
+ item-value="value"
335
+ :items="searchCities"
336
+ loading-text="Searching…"
337
+ no-data-text="No city found"
338
+ :query-debounce-time="250"
339
+ width="240px"
340
+ >
341
+ <template #activator="{ props, loading }">
342
+ <!-- Badge `loading` reflects the provider's in-flight fetch. Label
343
+ from our own pool — never the slot's `text`. -->
344
+ <BbBadge
345
+ append:icon="lucide:chevron-down"
346
+ :loading="loading"
347
+ prepend:icon="lucide:map-pin"
348
+ size="lg"
349
+ variant="outline"
350
+ >
351
+ <BbBadgeButton v-bind="props">{{
352
+ destinationLabel || 'Add destination'
353
+ }}</BbBadgeButton>
354
+ </BbBadge>
355
+ </template>
356
+ </BbSelectPopover>
357
+ </div>
358
+ </template>
359
+ <script setup lang="ts">
360
+ import { computed, ref } from 'vue';
361
+ import { BbBadge, BbBadgeButton, BbSelectPopover } from 'bitboss-ui';
362
+
363
+ type City = { label: string; value: string };
364
+
365
+ const pool: City[] = [
366
+ { label: 'Amsterdam', value: 'amsterdam' },
367
+ { label: 'Athens', value: 'athens' },
368
+ { label: 'Barcelona', value: 'barcelona' },
369
+ { label: 'Copenhagen', value: 'copenhagen' },
370
+ { label: 'Dublin', value: 'dublin' },
371
+ { label: 'Prague', value: 'prague' },
372
+ ];
373
+
374
+ const fetchFromApi = (predicate: (city: City) => boolean) =>
375
+ new Promise<City[]>((resolve) => {
376
+ setTimeout(() => resolve(pool.filter(predicate)), 250);
377
+ });
438
378
 
439
- const focusLastSelectedOption = () => {
440
- const lastSelected = selectedOptions.value[selectedOptions.value.length - 1];
441
- if (lastSelected?.valueHash) {
442
- optionsContainer.value?.focusByHash(lastSelected.valueHash);
443
- return;
379
+ const searchCities = (
380
+ query: string,
381
+ prefill: boolean,
382
+ // The raw v-model — type it with your own model shape: a single value (or
383
+ // null) here, an array in multiple mode.
384
+ modelValue: string | null
385
+ ): Promise<City[]> => {
386
+ // Prefill: resolve the current selection so the trigger label stays accurate.
387
+ if (prefill && modelValue) {
388
+ return fetchFromApi((city) => city.value === modelValue);
444
389
  }
445
- optionsContainer.value?.focusLastSelected();
390
+ if (!query.trim()) return Promise.resolve([]);
391
+ const q = query.trim().toLowerCase();
392
+ return fetchFromApi((city) => city.label.toLowerCase().includes(q));
446
393
  };
447
394
 
448
- /**
449
- * On arrow up:
450
- * When the panel is open — focus on the previous option
451
- * When the panel is closed — open and focus on the last selected option
452
- */
453
- const onArrowUp = async () => {
454
- if (!canProcessKeyboardBindings.value) return;
455
- if (shown.value) {
456
- optionsContainer.value?.focusPrevious();
457
- } else {
458
- await open({ focusPopoverContent: false });
459
- await waitForOptionsContainer();
460
- await wait(props.transitionDuration);
461
- focusLastSelectedOption();
462
- }
463
- };
395
+ const destination = ref<string | null>(null);
396
+ const destinationLabel = computed(
397
+ () => pool.find((c) => c.value === destination.value)?.label ?? ''
398
+ );
399
+ </script>
400
+ ```
464
401
 
465
- const onArrowDown = async () => {
466
- if (!canProcessKeyboardBindings.value) return;
467
- if (shown.value) {
468
- optionsContainer.value?.focusNext();
469
- } else {
470
- await open({ focusPopoverContent: false });
471
- await waitForOptionsContainer();
472
- await wait(props.transitionDuration);
473
- focusFirstSelectedOption();
474
- }
475
- };
402
+ ### Laziness, prefill and the trigger label
403
+
404
+ `prefill` controls **when the first load happens**: `'interaction'` (default) on
405
+ first open, `true` immediately on mount (and during SSR via `onServerPrefetch`),
406
+ `false` **search-first** — nothing is fetched until the user types a query.
407
+ Opening the panel is not a search, so it loads nothing; until the first query the
408
+ list shows a _"search to begin"_ hint instead of "no data".
409
+
410
+ Reach for `false` when the result set is too large or too expensive to browse and
411
+ the query is the only sensible entry point — a user picker over thousands of
412
+ rows. Note the panel is deliberately empty on open: that is the mode telling the
413
+ user to type.
414
+
415
+ **Search-first needs both a way to search and something to defer**, so `false`
416
+ falls back to loading on open when either is missing:
417
+
418
+ - **Writing is disabled** (`disable-writing`, including the per-surface
419
+ `'mobile'`/`'desktop'` forms) — there is no search field, so a user could never
420
+ trigger the load and the panel would stay empty forever.
421
+ - **The model is non-empty** — its text has to resolve for the selection to
422
+ render. (In-field `BbSelect` upgrades this to a mount prefill; see below.)
423
+
424
+ **Two further cases ignore `prefill` entirely and always load**, because deferring
425
+ would buy nothing or break a promise you made:
426
+
427
+ - **`items` is an array.** There is no request to defer, so laziness would only
428
+ leave the selection unresolved. Options resolve on mount, whatever `prefill`
429
+ says — free, and it makes `text`/`selectedOptions` and coherence work from the
430
+ first paint.
431
+ - **`enforce-coherence` over a non-empty model.** Validating a value is
432
+ impossible without options, so the popover loads and checks on that first load.
433
+ An empty model stays lazy — empty is always coherent, so there is nothing to
434
+ check.
435
+
436
+ Outside those two, a standalone popover with a **provider does not** auto-upgrade
437
+ a seeded model to an eager prefill the way in-field `BbSelect` does. That
438
+ laziness is deliberate: a fetch per instance must be something you ask for (see
439
+ _One popover per table row_).
440
+
441
+ **Do not reach for `prefill: true` to fix a trigger label.** Resolve the label
442
+ from your own state instead (above) — a trigger that needs a fetch to render is
443
+ a trigger that renders wrong until the fetch lands.
444
+
445
+ ### Dependent fields and coherence
446
+
447
+ When one picker constrains another, list the upstream value in `dependencies`:
448
+ the provider re-runs whenever a dependency changes (value-hash compared, so array
449
+ identity churn doesn't refetch), debounced by `deps-debounce-time`. Add
450
+ `enforce-coherence` to auto-clean a now-invalid selection — multiple emits the
451
+ **filtered array**, single emits **`null`**, an already-empty selection stays
452
+ quiet. Because enforcement checks the merged result (fetched + stashed), a
453
+ provider that returns `[]` on a `prefill: true` call **wipes a valid selection** —
454
+ always resolve the current selection on component-initiated calls, or enable
455
+ `stash`. The full mechanics are in the Coherence playbook.
456
+
457
+ **You do not need `prefill: true` to make this work.** Asking for
458
+ `enforce-coherence` over a seeded model _is_ a request to validate it, and that
459
+ is impossible without options — so the popover loads on mount by itself and runs
460
+ the check on that first load. The filter bar below relies on exactly that: no
461
+ `prefill` prop anywhere, yet switching the project re-runs the milestone provider
462
+ and clears a milestone the new project lacks, while a still-valid one survives.
463
+
464
+ What that costs is honest and worth knowing: **`enforce-coherence` opts each
465
+ instance into its own load**. One filter, one request. Fifty rows with a provider
466
+ each, fifty requests. That is the trade you asked for by enabling it — and it is
467
+ the reason the table pattern below hands every row the _same array_ instead.
468
+
469
+ #### Never share one ref across instances
470
+
471
+ Independent popovers each with their own model and their own `enforce-coherence`
472
+ are fine: every instance judges **its own** value against **its own** options, so
473
+ they never interfere. What breaks is binding them all to **one** ref:
476
474
 
477
- const onEnter = async () => {
478
- if (!canProcessKeyboardBindings.value) {
479
- return;
480
- }
481
- if (!shown.value) {
482
- await open({ focusPopoverContent: false });
483
- await waitForOptionsContainer();
484
- await wait(props.transitionDuration);
485
- if (selectedOptions.value.length) {
486
- focusFirstSelectedOption();
487
- } else if (computedAllowWriting.value) {
488
- focusSearchInput();
489
- } else {
490
- focusPopoverFocusProxy();
491
- }
492
- return;
493
- } else if (optionsContainer.value?.getHighlighted()) {
494
- optionsContainer.value.confirmOption();
495
- return;
496
- }
497
- if (!computedAllowWriting.value) return;
498
- const text = query.value.trim();
499
- if (isItemSelected(text)) return;
500
- emit('option:add', text);
501
- query.value = '';
502
- };
475
+ ```vue
476
+ <!-- WRONG: every row writes the same value -->
477
+ <script setup>
478
+ const status = ref(null); // ← one ref, shared by every row
479
+ </script>
480
+ <BbSelectPopover v-for="row in rows" v-model="status" enforce-coherence … />
481
+ ```
503
482
 
504
- const onEscape = async () => {
505
- if (shown.value) {
506
- await close();
507
- focusActivator();
508
- }
509
- };
483
+ Now every instance judges **the same** value against **its own** options, and
484
+ coherence's answer to a value it doesn't recognise is `null`. Pick a value only
485
+ one row's options contain and the others each emit `null` in turn — measured with
486
+ 5 rows: the pick lands, four instances overwrite it, the model ends `null`. The
487
+ user watches their choice vanish, with nothing logged.
510
488
 
511
- const query = ref<string>('');
512
- const hasInteracted = ref(false);
513
-
514
- const {
515
- getter,
516
- debouncedGetter,
517
- items: internalItems,
518
- loading,
519
- } = useItemsGetter({
520
- items: toRef(props, 'items'),
521
- debounce: props.queryDebounceTime,
522
- });
523
-
524
- const {
525
- array: innerStash,
526
- add: addToStash,
527
- remove: removeFromStash,
528
- set: setStash,
529
- } = useArray<BaseOption>();
530
-
531
- const {
532
- hasPrefilled,
533
- isPrefilling,
534
- canLoad,
535
- prefill: prefillItems,
536
- } = usePrefill({
537
- trigger: computed(
538
- () =>
539
- props.prefill === true ||
540
- (props.prefill === 'interaction' && hasInteracted.value)
541
- ),
542
- currentValue: undefined,
543
- multiple: false,
544
- fn: async (isPrefill) => {
545
- await getter(query.value, isPrefill, props.modelValue);
546
- if (props.stash) {
547
- addToStash(...options.value.map((o) => o.item));
548
- }
549
- },
550
- });
551
-
552
- const { data: modelValueIndexedByHash, get: isItemSelected } = useIndexById({
553
- items: computed(() => [].concat(props.modelValue)),
554
- });
555
-
556
- const { options } = useBaseOptions({
557
- disabled: toRef(props, 'disabled'),
558
- items: computed(() => [...internalItems.value, ...innerStash.value]),
559
- itemText: props.itemText,
560
- itemValue: props.itemValue,
561
- max: props.max,
562
- selectable: true,
563
- selectedIndexedByHash: modelValueIndexedByHash,
564
- });
565
-
566
- const { data: optionsIndexedByHash } = useIndexById({
567
- items: options,
568
- key: 'valueHash',
569
- });
570
-
571
- const { coherent, coherentValue } = useCoherence({
572
- modelValue: toRef(props, 'modelValue'),
573
- multiple: props.multiple,
574
- iteratee: (item) => !!optionsIndexedByHash.value[hash(item)],
575
- });
576
-
577
- const selectedOptions = computed<BaseOption[]>(() =>
578
- ([] as any[])
579
- .concat(props.modelValue)
580
- .map((v) => optionsIndexedByHash.value[hash(v)])
581
- .filter(Boolean)
582
- );
489
+ The component cannot catch this for you: it receives a **value**, not a ref
490
+ identity, and two rows legitimately holding the same value is ordinary. Give
491
+ every row its own model.
583
492
 
584
- const computedLoading = computed(() => !!(loading.value || props.loading));
585
- const hasErrors = computed(() => !!props.hasErrors);
586
- const triggerInputValue = computed(() => {
587
- if (props.multiple) return '';
588
- return selectedOptions.value[0]?.text ?? '';
589
- });
590
-
591
- useHashedWatcher(
592
- () => props.modelValue,
593
- async () => {
594
- if (!canLoad.value) return;
595
- if (!coherent.value) {
596
- await getter(query.value, true, props.modelValue);
597
- if (props.enforceCoherence) {
598
- emit('update:modelValue', coherentValue.value);
599
- optionsContainer.value?.blur();
600
- }
601
- }
602
- },
603
- { debounce: props.modelValueDebounceTime }
493
+ **Toolbar filter pills — milestone follows project**
494
+
495
+ ```vue
496
+ <template>
497
+ <div
498
+ class="flex max-w-md flex-wrap items-center gap-1.5 rounded-[var(--bb-radius)] border p-2"
499
+ >
500
+ <span class="pr-1 text-xs font-medium text-[color:var(--bb-text-muted)]"
501
+ >Filters</span
502
+ >
503
+ <BbSelectPopover
504
+ v-model="project"
505
+ compact
506
+ disable-writing
507
+ item-text="name"
508
+ item-value="id"
509
+ :items="projects"
510
+ width="200px"
511
+ >
512
+ <template #activator="{ props }">
513
+ <BbBadge
514
+ append:icon="lucide:chevron-down"
515
+ prepend:icon="lucide:folder"
516
+ size="lg"
517
+ variant="outline"
518
+ >
519
+ <BbBadgeButton v-bind="props">{{ projectLabel }}</BbBadgeButton>
520
+ </BbBadge>
521
+ </template>
522
+ </BbSelectPopover>
523
+ <BbSelectPopover
524
+ v-model="milestone"
525
+ compact
526
+ :dependencies="[project]"
527
+ :deps-debounce-time="150"
528
+ enforce-coherence
529
+ item-text="title"
530
+ item-value="id"
531
+ :items="fetchMilestones"
532
+ no-data-text="No milestone matches"
533
+ width="220px"
534
+ >
535
+ <template #activator="{ props }">
536
+ <BbBadge
537
+ append:icon="lucide:chevron-down"
538
+ prepend:icon="lucide:flag"
539
+ size="lg"
540
+ variant="outline"
541
+ >
542
+ <BbBadgeButton v-bind="props">{{
543
+ milestoneLabel || 'Milestone'
544
+ }}</BbBadgeButton>
545
+ </BbBadge>
546
+ </template>
547
+ </BbSelectPopover>
548
+ </div>
549
+ </template>
550
+ <script setup lang="ts">
551
+ import { computed, ref } from 'vue';
552
+ import { BbBadge, BbBadgeButton, BbSelectPopover } from 'bitboss-ui';
553
+
554
+ type Project = { id: string; name: string };
555
+ type Milestone = { id: string; title: string; project: string };
556
+
557
+ const projects: Project[] = [
558
+ { id: 'mobile', name: 'Mobile app' },
559
+ { id: 'web', name: 'Web dashboard' },
560
+ { id: 'design', name: 'Design system' },
561
+ ];
562
+
563
+ const milestonePool: Milestone[] = [
564
+ { id: 'ms-beta', title: 'Private beta', project: 'mobile' },
565
+ { id: 'ms-launch', title: 'App Store launch', project: 'mobile' },
566
+ { id: 'ms-ga', title: 'GA rollout', project: 'web' },
567
+ { id: 'ms-audit', title: 'SOC 2 audit', project: 'web' },
568
+ { id: 'ms-tokens', title: 'Token overhaul', project: 'design' },
569
+ ];
570
+
571
+ const project = ref<string>('mobile');
572
+ const milestone = ref<string | null>('ms-beta');
573
+
574
+ // Trigger labels come from our own state — the slot's `text` is empty until
575
+ // the popover first matches the model against loaded items.
576
+ const projectLabel = computed(
577
+ () => projects.find((p) => p.id === project.value)?.name ?? 'Project'
604
578
  );
605
- useHashedWatcher(
606
- () => [props.dependencies, props.items],
607
- async () => {
608
- if (!canLoad.value) return;
609
- await getter(query.value, true, props.modelValue);
610
- if (props.enforceCoherence && !coherent.value) {
611
- emit('update:modelValue', coherentValue.value);
612
- optionsContainer.value?.blur();
613
- }
614
- },
615
- { debounce: props.depsDebounceTime }
579
+ const milestoneLabel = computed(
580
+ () => milestonePool.find((m) => m.id === milestone.value)?.title ?? ''
616
581
  );
617
582
 
618
- const onOptionSelected = async (option: BaseOption) => {
619
- if (props.multiple) {
620
- emit('update:modelValue', props.modelValue.concat(option.value));
621
- if (props.stash) {
622
- addToStash(option.item);
623
- }
624
- } else {
625
- if (props.stash) {
626
- setStash(option.item);
627
- }
628
- emit('update:modelValue', option.value);
629
- await nextTick();
630
- }
631
- if (props.multiple && computedAllowWriting.value && shown.value) {
632
- focusSearchInput();
633
- } else {
634
- focusActivator();
635
- }
636
- if (!props.multiple) {
637
- close();
638
- }
639
- };
640
-
641
- const onOptionUnselected = async (option: BaseOption) => {
642
- removeFromStash((o) => o.valueHash !== option.valueHash);
643
- if (props.multiple) {
644
- const copy = { ...modelValueIndexedByHash.value };
645
- delete copy[option.valueHash];
646
- emit('update:modelValue', Object.values(copy));
647
- } else {
648
- emit('update:modelValue', null);
649
- }
650
- if (props.multiple && computedAllowWriting.value && shown.value) {
651
- focusSearchInput();
652
- } else {
653
- focusActivator();
654
- }
583
+ // Query-aware provider. Component-initiated calls (the mount load, project
584
+ // changes via `dependencies`) pass `prefill === true` and get the project's
585
+ // full list back, so a still-valid selection stays resolvable —
586
+ // `enforce-coherence` then clears only a milestone the new project lacks.
587
+ // No `prefill` prop needed: `enforce-coherence` over a seeded model loads on
588
+ // mount by itself, because validating a value requires having the options.
589
+ const fetchMilestones = (
590
+ query: string,
591
+ prefill: boolean,
592
+ _modelValue: string | null
593
+ ): Promise<Milestone[]> => {
594
+ const inProject = milestonePool.filter((m) => m.project === project.value);
595
+ const q = query.trim().toLowerCase();
596
+ const matches = prefill
597
+ ? inProject
598
+ : inProject.filter((m) => m.title.toLowerCase().includes(q));
599
+ return new Promise((resolve) => setTimeout(() => resolve(matches), 200));
655
600
  };
601
+ </script>
602
+ ```
656
603
 
657
- /**
658
- * Filter options based on the current query.
659
- */
660
- const filteredOptions = computed<BaseOption<Item>[]>(() => {
661
- const queryMatchesASelectedOption = selectedOptions.value.some(
662
- (option: BaseOption) => option.text === query.value
663
- );
664
- const shouldFilter =
665
- (props.multiple && query.value) ||
666
- (props.filterBy === 'not_stashed' && query.value) ||
667
- (query.value && !queryMatchesASelectedOption && !props.multiple);
668
-
669
- if (!shouldFilter || !props.filterBy) return options.value;
670
-
671
- const stashedHashes =
672
- props.filterBy === 'not_stashed'
673
- ? new Set(innerStash.value.map((o) => o.valueHash))
674
- : null;
675
-
676
- return options.value.filter((item: BaseOption) => {
677
- let matchedAnything = false;
678
- if (typeof props.filterBy === 'function') {
679
- matchedAnything = props.filterBy(item.value, item.item, query.value);
680
- } else if (props.filterBy === 'not_stashed' && query.value) {
681
- matchedAnything = !stashedHashes!.has(item.valueHash);
682
- } else if (Array.isArray(props.filterBy) && props.filterBy.length) {
683
- matchedAnything = matchAnyKey(
684
- item.item,
685
- props.filterBy,
686
- query.value.trim()
687
- );
688
- }
689
- return matchedAnything || matchAnyKey(item, ['text'], query.value.trim());
690
- });
691
- });
604
+ ### One popover per table row (inline edit)
692
605
 
693
- const defaultGroupSymbol = Symbol('default');
606
+ The status-pill-in-a-table is the popover's signature use — and the structure of
607
+ the **page** decides whether it scales. Three rules, in priority order:
694
608
 
695
- const getGroupData = (option: BaseOption) => {
696
- if (isNil(props.groupBy)) return defaultGroupSymbol;
697
- if (typeof props.groupBy === 'function') return props.groupBy(option.item);
698
- return (get as any)(option.item, props.groupBy);
699
- };
609
+ **1. Resolve the options once, for the whole page. Pass an array, not a provider.**
610
+ This is the load-bearing decision. A provider is per-instance, so 50 rows means
611
+ 50 popovers each owning a fetch. Lift the fetch to the page, `await` it once, and
612
+ hand every row the same array — 50 rows, **zero** requests, because there is
613
+ nothing left to fetch. Array `items` are never lazy either: every row resolves on
614
+ mount, so selections and coherence work immediately with no `prefill` prop.
700
615
 
701
- const groupedOptions = computed<GroupedOptions[]>(() => {
702
- const groupIndex: Record<GroupedOptions['id'], GroupedOptions> = {};
703
- for (const option of filteredOptions.value) {
704
- const groupData = getGroupData(option);
705
- const groupId = hash(groupData);
706
- if (!groupIndex[groupId]) {
707
- groupIndex[groupId] = {
708
- id: groupId,
709
- data: groupData ?? null,
710
- options: [],
711
- };
712
- }
713
- groupIndex[groupId].options.push(option);
714
- }
715
- return Object.values(groupIndex).filter((g) => g.options.length);
716
- });
616
+ ```ts
617
+ // Page level — once, not per row.
618
+ const statuses = ref<Status[]>([]);
619
+ onMounted(async () => (statuses.value = await api.statuses.list()));
620
+ ```
717
621
 
718
- /**
719
- * START POPOVER STATE
720
- */
721
- const shown = ref(false);
722
- const renderListBox = useUntil(shown);
723
-
724
- const open = async ({
725
- focusPopoverContent = true,
726
- }: { focusPopoverContent?: boolean } = {}) => {
727
- if (props.disabled || props.readonly) return;
728
- if (shown.value) return;
729
- hasInteracted.value = true;
730
- resume();
731
- shown.value = true;
732
-
733
- if (!hasPrefilled.value && !isPrefilling.value) {
734
- await prefillItems();
735
- }
622
+ **2. Hold the edit off the row — a page-level draft map keyed by id.** Never
623
+ `v-model="item.status"`: writing straight back onto the slot's `item` mutates the
624
+ table's data, so any refetch (a filter change, a poll) silently discards the edit,
625
+ and a partially-dirty row has no clean before/after. Instead bind the value _down_
626
+ (`:model-value="valueOf(item, 'status')"`) and commit it _up_ into a `drafts` map
627
+ (`@update:model-value="setField(item, 'status', $event)"`). The map is the dirty
628
+ set **and** the save payload; the row object stays pristine. This is the table
629
+ case of the [inline-edit playbook](../../ai/guides/inline-edit-playbook.md) —
630
+ reach for autosave there instead when the domain wants every pick to persist on
631
+ the spot.
736
632
 
737
- await nextTick();
738
- document.addEventListener('click', onOutsideInteraction);
739
- document.addEventListener('focusin', onOutsideInteraction);
633
+ **3. Label the pill from your own state, not from the popover.**
634
+ `{{ labelFor(valueOf(item, 'status')) }}` resolved against your page-level array —
635
+ never the slot's `text`. The badge must read correctly on first paint for every
636
+ row, including the hundreds nobody ever opens.
740
637
 
741
- if (!focusPopoverContent) return;
638
+ **Inline status cell — soft badge editor**
742
639
 
743
- if (computedAllowWriting.value) {
744
- await wait(0);
745
- focusSearchInput();
746
- } else {
747
- await wait(0);
748
- focusPopoverFocusProxy();
749
- }
750
- };
640
+ ```vue
641
+ <template>
642
+ <div class="flex max-w-xl flex-col gap-1.5">
643
+ <div
644
+ class="overflow-hidden rounded-[var(--bb-radius)] border border-[color:var(--bb-border)]"
645
+ >
646
+ <BbTable
647
+ caption="Tickets — edit statuses, then Save the batch"
648
+ :columns="columns"
649
+ compact
650
+ item-value="id"
651
+ :items="tickets"
652
+ >
653
+ <!-- One popover per row. Three rules keep it cheap and correct:
654
+ 1. `:items="statuses"` is the SAME array for every row — resolved
655
+ once at page level, so N rows cost zero extra requests.
656
+ 2. The edit is held in a page-level `drafts` map keyed by row id,
657
+ NEVER written back onto `item`. Bind the value down with
658
+ `valueOf` and commit up with `setField`; the row object stays
659
+ pristine, so a refetch (filter, poll) can't wipe an edit.
660
+ 3. The pill renders from `valueOf(item, 'status')`, our own state —
661
+ never the slot's `text` — so it is correct on first paint
662
+ whether or not the popover is ever opened. -->
663
+ <template #status="{ item }">
664
+ <BbSelectPopover
665
+ compact
666
+ disable-writing
667
+ item-text="label"
668
+ item-value="value"
669
+ :items="statuses"
670
+ :model-value="valueOf(item, 'status')"
671
+ width="180px"
672
+ @update:model-value="setField(item, 'status', $event as Status)"
673
+ >
674
+ <template #activator="{ props, shown }">
675
+ <!-- Soft status pill: the badge IS the trigger. A dirty pill
676
+ (edited, not yet saved) keeps a deeper border until Save. -->
677
+ <BbBadge
678
+ append:icon="lucide:chevron-down"
679
+ :class="{
680
+ 'status-trigger--editing': shown,
681
+ 'status-trigger--dirty': isDirty(item),
682
+ }"
683
+ size="lg"
684
+ :variant="variantFor(valueOf(item, 'status'))"
685
+ >
686
+ <BbBadgeButton v-bind="props">{{
687
+ labelFor(valueOf(item, 'status'))
688
+ }}</BbBadgeButton>
689
+ </BbBadge>
690
+ </template>
691
+ </BbSelectPopover>
692
+ </template>
693
+ </BbTable>
694
+ </div>
751
695
 
752
- const close = async () => {
753
- if (!shown.value) return;
754
- shown.value = false;
755
- optionsContainer.value?.blur();
756
- activeDescendantId.value = undefined;
757
- pause();
758
- document.removeEventListener('click', onOutsideInteraction);
759
- document.removeEventListener('focusin', onOutsideInteraction);
760
- query.value = '';
761
- };
696
+ <div class="flex items-center gap-2">
697
+ <BbButton :disabled="!dirtyCount" size="sm" @click="save">
698
+ Save{{ dirtyCount ? ` (${dirtyCount})` : '' }}
699
+ </BbButton>
700
+ <span class="text-xs text-[color:var(--bb-text-muted)]">
701
+ Edits live in a draft map keyed by row id — the map is the save payload.
702
+ Rows are never mutated, so nothing is lost on a refetch.
703
+ </span>
704
+ </div>
705
+ </div>
706
+ </template>
707
+ <script setup lang="ts">
708
+ import { computed, reactive, ref } from 'vue';
709
+ import {
710
+ BbBadge,
711
+ BbBadgeButton,
712
+ BbButton,
713
+ BbSelectPopover,
714
+ BbTable,
715
+ } from 'bitboss-ui';
716
+ import type { BadgeVariantType, BbTableColumn } from 'bitboss-ui';
717
+
718
+ type Status = 'open' | 'in-progress' | 'blocked' | 'done';
719
+ type Ticket = { id: string; ref: string; title: string; status: Status };
720
+ type Patch = Partial<Pick<Ticket, 'status'>>;
762
721
 
763
- const toggle = () => {
764
- if (shown.value) return close();
765
- return open();
766
- };
767
722
  /**
768
- * END POPOVER STATE
723
+ * The option list is resolved ONCE for the whole page and handed to every row as
724
+ * a plain array. With a provider per row, each popover would own its own fetch;
725
+ * as an array there is no request at all, and every row resolves on mount.
769
726
  */
727
+ const statuses: Array<{ value: Status; label: string }> = [
728
+ { value: 'open', label: 'Open' },
729
+ { value: 'in-progress', label: 'In progress' },
730
+ { value: 'blocked', label: 'Blocked' },
731
+ { value: 'done', label: 'Done' },
732
+ ];
733
+
734
+ const tickets = ref<Ticket[]>([
735
+ {
736
+ id: 't-1',
737
+ ref: 'BB-104',
738
+ title: 'Popover drops focus on Esc',
739
+ status: 'open',
740
+ },
741
+ {
742
+ id: 't-2',
743
+ ref: 'BB-118',
744
+ title: 'Table header misaligns at 320px',
745
+ status: 'in-progress',
746
+ },
747
+ {
748
+ id: 't-3',
749
+ ref: 'BB-121',
750
+ title: 'Token audit for dark mode',
751
+ status: 'blocked',
752
+ },
753
+ {
754
+ id: 't-4',
755
+ ref: 'BB-130',
756
+ title: 'Ship the migration guide',
757
+ status: 'done',
758
+ },
759
+ ]);
770
760
 
771
- /**
772
- * START ACTIVE STATE
773
- * Tracks whether the user is inside this whole component.
774
- * We cannot use :focus-within as it doesn't work for teleported elements.
775
- */
776
- const active = ref(false);
761
+ const columns: Array<BbTableColumn<Ticket>> = [
762
+ { key: 'ref', label: 'Ref', width: 90 },
763
+ { key: 'title', label: 'Title' },
764
+ { key: 'status', label: 'Status', width: 140 },
765
+ ];
777
766
 
778
- const setActive = () => {
779
- active.value = true;
780
- };
781
- const setInactive = () => {
782
- if (!active.value) return;
783
- active.value = false;
784
- emit('inactive');
785
- };
767
+ /* ---- Draft map: the edit lives here, never on the row -------------------- */
786
768
 
787
- const isFocusInsideComponent = (target: EventTarget | null) => {
788
- if (!(target instanceof Node)) return false;
789
- const insideActivator = !!activatorEl.value?.contains(target);
790
- const insidePopover = !!optionsContainer.value?.$el
791
- ?.closest('.bb-common-popover')
792
- ?.contains(target);
793
- return insideActivator || insidePopover;
769
+ const drafts = reactive<Record<string, Patch>>({});
770
+
771
+ /**
772
+ * Read-through: the draft wins, the row is the fallback. Use a `key in` check,
773
+ * NOT `??` — a field legitimately drafted to a nullish value would otherwise
774
+ * fall through to the row.
775
+ */
776
+ const valueOf = <K extends keyof Patch>(item: Ticket, key: K): Ticket[K] => {
777
+ const draft = drafts[item.id];
778
+ return draft && key in draft ? (draft[key] as Ticket[K]) : item[key];
794
779
  };
795
780
 
796
- const syncActiveStateOnBlur = () => {
797
- setTimeout(() => {
798
- if (isFocusInsideComponent(document.activeElement)) {
799
- setActive();
800
- return;
781
+ /** One setter covers every field; re-picking the original un-dirties for free. */
782
+ const setField = <K extends keyof Patch>(
783
+ item: Ticket,
784
+ key: K,
785
+ value: Patch[K]
786
+ ) => {
787
+ if (value === item[key]) {
788
+ delete drafts[item.id]?.[key];
789
+ if (drafts[item.id] && !Object.keys(drafts[item.id]).length) {
790
+ delete drafts[item.id];
801
791
  }
802
- setInactive();
803
- }, 0);
792
+ return;
793
+ }
794
+ (drafts[item.id] ??= {})[key] = value;
804
795
  };
805
- /**
806
- * END ACTIVE STATE
807
- */
808
796
 
809
- const onClear = () => {
810
- emit('update:modelValue', props.multiple ? [] : null);
797
+ const isDirty = (item: Ticket) => drafts[item.id]?.status !== undefined;
798
+ const dirtyCount = computed(() => Object.keys(drafts).length);
799
+
800
+ /** The map IS the payload. Here it patches the local rows; a real app PATCHes. */
801
+ const save = () => {
802
+ tickets.value = tickets.value.map((row) =>
803
+ drafts[row.id] ? { ...row, ...drafts[row.id] } : row
804
+ );
805
+ Object.keys(drafts).forEach((id) => delete drafts[id]);
811
806
  };
812
807
 
813
- /**
814
- * START ACTIVATOR LISTENERS
815
- * Programmatically attach accessibility attributes and event listeners
816
- * to the activator element, following the BbDropdown pattern.
817
- */
818
- let cleanupActivator: (() => void) | null = null;
819
-
820
- watch(
821
- activatorEl,
822
- (el) => {
823
- if (cleanupActivator) {
824
- cleanupActivator();
825
- cleanupActivator = null;
826
- }
827
- if (!el) return;
828
-
829
- el.setAttribute('role', 'combobox');
830
- el.setAttribute('aria-haspopup', 'listbox');
831
-
832
- const handleClick = (event: MouseEvent) => {
833
- emit('click', event);
834
- if (props.disabled || props.readonly) return;
835
- event.preventDefault();
836
- toggle();
837
- };
838
-
839
- const handleKeydown = (event: KeyboardEvent) => {
840
- switch (event.key) {
841
- case 'ArrowDown':
842
- event.preventDefault();
843
- onArrowDown();
844
- break;
845
- case 'ArrowUp':
846
- event.preventDefault();
847
- onArrowUp();
848
- break;
849
- case 'Enter':
850
- event.preventDefault();
851
- onEnter();
852
- break;
853
- case 'Escape':
854
- if (shown.value) {
855
- event.preventDefault();
856
- onEscape();
857
- }
858
- break;
859
- }
860
- };
861
-
862
- const handleFocus = (event: FocusEvent) => {
863
- emit('focus', event);
864
- setActive();
865
- };
866
-
867
- const handleBlur = (event: FocusEvent) => {
868
- emit('blur', event);
869
- syncActiveStateOnBlur();
870
- };
871
-
872
- el.addEventListener('click', handleClick);
873
- el.addEventListener('keydown', handleKeydown);
874
- el.addEventListener('focus', handleFocus);
875
- el.addEventListener('blur', handleBlur);
876
-
877
- cleanupActivator = () => {
878
- el.removeEventListener('click', handleClick);
879
- el.removeEventListener('keydown', handleKeydown);
880
- el.removeEventListener('focus', handleFocus);
881
- el.removeEventListener('blur', handleBlur);
882
- el.removeAttribute('role');
883
- el.removeAttribute('aria-haspopup');
884
- el.removeAttribute('aria-expanded');
885
- el.removeAttribute('aria-controls');
886
- el.removeAttribute('aria-invalid');
887
- el.removeAttribute('aria-describedby');
888
- el.removeAttribute('aria-activedescendant');
889
- };
890
- },
891
- { immediate: true }
892
- );
808
+ /* Row labels come from our own state — stable regardless of popover state. */
809
+ const labelFor = (status: Status) =>
810
+ statuses.find((s) => s.value === status)?.label ?? '—';
893
811
 
894
- watch(
895
- [
896
- activatorEl,
897
- shown,
898
- renderListBox,
899
- computedAriaInvalid,
900
- computedAriaDescribedby,
901
- activeDescendantId,
902
- ] as const,
903
- ([el, isShown, hasListBox, ariaInvalid, ariaDescribedby, descendantId]) => {
904
- if (!el) return;
905
- el.setAttribute('aria-expanded', String(isShown));
906
- if (ariaInvalid != null) {
907
- el.setAttribute('aria-invalid', ariaInvalid);
908
- } else {
909
- el.removeAttribute('aria-invalid');
910
- }
911
- if (hasListBox) {
912
- el.setAttribute('aria-controls', `${id}_listbox`);
913
- } else {
914
- el.removeAttribute('aria-controls');
915
- }
916
- if (ariaDescribedby != null) {
917
- el.setAttribute('aria-describedby', ariaDescribedby);
918
- } else {
919
- el.removeAttribute('aria-describedby');
920
- }
921
- if (isShown && descendantId) {
922
- el.setAttribute('aria-activedescendant', descendantId);
923
- } else {
924
- el.removeAttribute('aria-activedescendant');
925
- }
926
- },
927
- { immediate: true }
928
- );
812
+ const VARIANT: Record<Status, BadgeVariantType> = {
813
+ open: 'soft-gray',
814
+ 'in-progress': 'soft-blue',
815
+ blocked: 'soft-red',
816
+ done: 'soft-green',
817
+ };
929
818
 
930
- onBeforeUnmount(() => {
931
- cleanupActivator?.();
932
- document.removeEventListener('click', onOutsideInteraction);
933
- document.removeEventListener('focusin', onOutsideInteraction);
934
- });
935
- /**
936
- * END ACTIVATOR LISTENERS
937
- */
819
+ const variantFor = (status: Status) => VARIANT[status];
938
820
  </script>
939
821
 
940
- <style lang="postcss">
941
- .bb-select-popover {
942
- width: var(--bb-select-popover-width, 320px);
822
+ <!-- Soft status palette — canonical source: ai/guides/design-language.md § Using color.
823
+ Non-scoped so variant classes on the child badge receive the accents. -->
824
+ <style>
825
+ .bb-badge.bb-badge--soft-gray {
826
+ --accent: #64748b;
827
+ }
828
+ .bb-badge.bb-badge--soft-blue {
829
+ --accent: #2563eb;
830
+ }
831
+ .bb-badge.bb-badge--soft-green {
832
+ --accent: #16a34a;
833
+ }
834
+ .bb-badge.bb-badge--soft-red {
835
+ --accent: #dc2626;
836
+ }
837
+ .bb-badge.bb-badge--soft-gray,
838
+ .bb-badge.bb-badge--soft-blue,
839
+ .bb-badge.bb-badge--soft-green,
840
+ .bb-badge.bb-badge--soft-red {
841
+ --bg: color-mix(in oklab, var(--accent) 15%, var(--bb-panel));
842
+ --color: color-mix(in oklab, var(--accent) 80%, var(--bb-text));
843
+ --border-width: 1px;
844
+ --border-color: color-mix(in oklab, var(--accent) 25%, var(--bb-panel));
845
+ --ring: color-mix(in oklab, var(--accent) 45%, transparent);
846
+ }
943
847
 
944
- .bb-select-popover__search-container {
945
- align-items: center;
946
- border-bottom: 1px solid var(--bb-border);
947
- display: flex;
948
- padding: 0.375rem 0.75rem;
949
- position: relative;
950
- }
848
+ /* Unsaved edit: hold a deeper border until the batch is saved. */
849
+ .status-trigger--dirty {
850
+ --border-width: 1px;
851
+ --border-color: color-mix(in oklab, var(--color) 60%, var(--bb-panel));
852
+ }
951
853
 
952
- .bb-select-popover__search-icon,
953
- .bb-select-popover__search-spinner,
954
- .bb-select-popover__search-error-icon {
955
- color: var(--bb-icon-color);
956
- flex-shrink: 0;
957
- width: var(--bb-input-icon);
958
- position: absolute;
959
- right: 0.75rem;
960
- top: 50%;
961
- transform: translateY(-50%);
962
- opacity: 0;
963
- transition:
964
- color 0.3s,
965
- opacity 0.3s;
966
- pointer-events: none;
967
- }
854
+ /* While open, deepen the badge's own hue — not a generic indigo ring. */
855
+ .status-trigger--editing {
856
+ --bg: color-mix(in oklab, var(--color) 25%, var(--bb-panel));
857
+ --border-color: color-mix(in oklab, var(--color) 45%, var(--bb-panel));
858
+ box-shadow: 0 0 0 var(--bb-ring-size) var(--ring);
859
+ }
860
+ </style>
861
+ ```
968
862
 
969
- .bb-select-popover__search-input {
970
- background-color: transparent;
971
- border: 0;
972
- color: var(--bb-input-color);
973
- flex: 1 1 auto;
974
- font-size: var(--bb-input-font-size);
975
- line-height: var(--bb-leading);
976
- outline: none;
977
- padding: 0;
978
- padding-right: calc(var(--bb-input-icon) + 0.5rem);
979
- width: 100%;
980
- }
863
+ **Why this shape and not the obvious one.** The instinct is to give each row a
864
+ provider and `enforce-coherence` so rows keep themselves honest. That inverts the
865
+ cost: coherence with a seeded model makes every row load, so the table's request
866
+ count tracks its row count, and each row can rewrite its own model from a
867
+ response you never see. The page-level array collapses all of it — one source,
868
+ one fetch, every row consistent by construction, nothing to prune because every
869
+ row already draws from the same list.
870
+
871
+ If rows genuinely need **different** option sets (per-type statuses, say),
872
+ resolve _those_ lists at page level too — one fetch per distinct set, keyed by
873
+ type — and pass the right array down. Still zero per-row requests. Reach for a
874
+ per-row provider only when the options truly depend on that row's identity and
875
+ cannot be batched, and then expect the request count to follow the row count.
876
+
877
+ Pruning stale values in a table is a **page-level** job, not a per-row one: when
878
+ the source list narrows, reconcile the rows yourself in one pass, where you can
879
+ show the user what changed (or ask them) instead of nulling values invisibly.
880
+
881
+ ### Create options on the fly (`option:add`)
882
+
883
+ Pressing Enter in the search field with **no option highlighted** emits
884
+ `option:add` with the trimmed query (it can be `''`, and it won't fire if the
885
+ query already matches a selected option). The component creates nothing itself:
886
+ append the new item to `items` and select it. This is the idiomatic pattern for
887
+ closed-but-growable vocabularies — the same as `BbSelect`. The behaviour is gated
888
+ by the search field existing; `disable-writing` (which removes the field) also
889
+ disables it.
981
890
 
982
- .bb-select-popover__search-icon {
983
- opacity: 1;
984
- }
891
+ ```ts
892
+ const roles = ref<string[]>(['Reviewer', 'Approver']);
893
+ const role = ref<string | null>(null);
894
+
895
+ const onAdd = (text: string) => {
896
+ const name = text.trim();
897
+ if (!name || roles.value.includes(name)) return;
898
+ roles.value.push(name);
899
+ role.value = name;
900
+ };
901
+ ```
985
902
 
986
- &.bb-select-popover--errors {
987
- .bb-select-popover__search-error-icon {
988
- color: var(--bb-danger);
989
- opacity: 1;
990
- }
903
+ ### Group options
991
904
 
992
- .bb-select-popover__search-icon,
993
- .bb-select-popover__search-spinner {
994
- opacity: 0;
995
- }
996
- }
905
+ `group-by` (a field path or a function) buckets options under headers; the
906
+ `#group` slot styles each header and receives `{ text, item, index, length,
907
+ disabled }` — `length` is the group size, `index` the list index of its first
908
+ option. Identical to `BbSelect`, anchored to your trigger.
997
909
 
998
- &.bb-select-popover--loading {
999
- .bb-select-popover__search-spinner {
1000
- opacity: 1;
1001
- }
910
+ **Roles grouped by department**
1002
911
 
1003
- .bb-select-popover__search-icon,
1004
- .bb-select-popover__search-error-icon {
1005
- opacity: 0;
1006
- }
1007
- }
912
+ ```vue
913
+ <template>
914
+ <div
915
+ class="flex max-w-sm items-center gap-1.5 rounded-[var(--bb-radius)] border p-2"
916
+ >
917
+ <span class="pr-1 text-xs font-medium text-[color:var(--bb-text-muted)]"
918
+ >Role</span
919
+ >
920
+ <BbSelectPopover
921
+ v-model="role"
922
+ compact
923
+ group-by="department"
924
+ item-text="label"
925
+ item-value="value"
926
+ :items="roles"
927
+ width="240px"
928
+ >
929
+ <template #activator="{ props }">
930
+ <BbBadge
931
+ append:icon="lucide:chevron-down"
932
+ prepend:icon="lucide:briefcase"
933
+ size="lg"
934
+ variant="outline"
935
+ >
936
+ <BbBadgeButton v-bind="props">{{
937
+ roleLabel || 'Assign role'
938
+ }}</BbBadgeButton>
939
+ </BbBadge>
940
+ </template>
941
+ <template #group="{ text, length }">
942
+ <div
943
+ class="flex items-center justify-between px-2 text-xs font-medium text-[color:var(--bb-text-muted)]"
944
+ >
945
+ <span>{{ text }}</span>
946
+ <span>{{ length }}</span>
947
+ </div>
948
+ </template>
949
+ </BbSelectPopover>
950
+ </div>
951
+ </template>
952
+ <script setup lang="ts">
953
+ import { computed, ref } from 'vue';
954
+ import { BbBadge, BbBadgeButton, BbSelectPopover } from 'bitboss-ui';
955
+
956
+ type Role = { label: string; value: string; department: string };
957
+
958
+ const roles: Role[] = [
959
+ { label: 'Analyst', value: 'mkt-analyst', department: 'Marketing' },
960
+ { label: 'Manager', value: 'mkt-manager', department: 'Marketing' },
961
+ { label: 'Frontend', value: 'eng-fe', department: 'Engineering' },
962
+ { label: 'Backend', value: 'eng-be', department: 'Engineering' },
963
+ ];
964
+
965
+ const role = ref<string | null>(null);
966
+ const roleLabel = computed(
967
+ () => roles.find((r) => r.value === role.value)?.label ?? ''
968
+ );
969
+ </script>
970
+ ```
1008
971
 
1009
- .bb-listbox {
1010
- --option-h: var(--option-height);
1011
- display: block;
972
+ ### Panel header, footer and empty/loading states
1012
973
 
1013
- &.bb-listbox--open {
1014
- transition: min-height 0s 0s;
974
+ `#header` and `#footer` pin content above the search field and below the options
975
+ list, in **both** the desktop popover and the mobile adaptive sheet. Both receive
976
+ `{ close, clear, focus, query, selectedOptions }` — ideal for a title and a
977
+ "Done" action. Two more panel slots cover async states: `#loading` and
978
+ `#no-data` (both receive `{ query }`; `#no-data` also a `focus()` callback), or
979
+ their string equivalents `loading-text` / `no-data-text`.
1015
980
 
1016
- .bb-listbox__outer-container {
1017
- grid-template-rows: 1fr;
1018
- opacity: 1;
1019
- transition-delay: 0s, 00ms;
981
+ **A titled panel with a done action**
1020
982
 
1021
- > * {
1022
- opacity: 1;
1023
- transition-delay: calc(var(--transition-duration) * 0.8);
1024
- }
1025
- }
1026
- }
1027
- &.bb-listbox--no-data {
1028
- .bb-listbox__outer-container {
1029
- .bb-listbox__inner-container {
1030
- .bb-listbox__no-data {
1031
- display: block;
1032
- }
1033
- }
1034
- }
1035
- }
1036
- &.bb-listbox--loading {
1037
- .bb-listbox__outer-container {
1038
- .bb-listbox__inner-container {
1039
- .bb-listbox__loading {
1040
- display: block;
1041
- text-align: left;
1042
- }
1043
- .bb-listbox__loading {
1044
- display: hidden;
1045
- }
1046
- }
1047
- }
1048
- }
983
+ ```vue
984
+ <template>
985
+ <div
986
+ class="flex max-w-sm items-center gap-1.5 rounded-[var(--bb-radius)] border p-2"
987
+ >
988
+ <span class="pr-1 text-xs font-medium text-[color:var(--bb-text-muted)]"
989
+ >Destination</span
990
+ >
991
+ <BbSelectPopover
992
+ v-model="city"
993
+ compact
994
+ item-text="label"
995
+ item-value="value"
996
+ :items="cities"
997
+ width="240px"
998
+ >
999
+ <template #activator="{ props }">
1000
+ <BbBadge
1001
+ append:icon="lucide:chevron-down"
1002
+ prepend:icon="lucide:map-pin"
1003
+ size="lg"
1004
+ variant="outline"
1005
+ >
1006
+ <BbBadgeButton v-bind="props">{{
1007
+ cityLabel || 'Add destination'
1008
+ }}</BbBadgeButton>
1009
+ </BbBadge>
1010
+ </template>
1011
+ <template #header>
1012
+ <span class="text-sm font-medium">Popular destinations</span>
1013
+ </template>
1014
+ <template #footer="{ close, clear }">
1015
+ <div class="flex w-full items-center gap-2">
1016
+ <BbButton class="mr-auto" variant="ghost" @click="clear"
1017
+ >Clear</BbButton
1018
+ >
1019
+ <BbButton variant="primary" @click="close">Done</BbButton>
1020
+ </div>
1021
+ </template>
1022
+ </BbSelectPopover>
1023
+ </div>
1024
+ </template>
1025
+ <script setup lang="ts">
1026
+ import { computed, ref } from 'vue';
1027
+ import { BbBadge, BbBadgeButton, BbButton, BbSelectPopover } from 'bitboss-ui';
1028
+
1029
+ type City = { label: string; value: string };
1030
+
1031
+ const cities: City[] = [
1032
+ { label: 'Amsterdam', value: 'ams' },
1033
+ { label: 'Berlin', value: 'ber' },
1034
+ { label: 'Lisbon', value: 'lis' },
1035
+ { label: 'Milan', value: 'mil' },
1036
+ ];
1037
+
1038
+ const city = ref<string | null>(null);
1039
+ const cityLabel = computed(
1040
+ () => cities.find((c) => c.value === city.value)?.label ?? ''
1041
+ );
1042
+ </script>
1043
+ ```
1049
1044
 
1050
- &.bb-listbox--multiple {
1051
- .autocomplete-option__checkbox {
1052
- display: inline-block !important;
1053
- }
1054
- }
1045
+ ### Search field and filtering
1055
1046
 
1056
- .bb-listbox__outer-container {
1057
- background-color: var(--bb-panel);
1058
- border-color: var(--bb-primary);
1059
- border-radius: var(--bb-radius);
1060
- border-width: 0px;
1061
- display: grid;
1062
- grid-template-rows: 0fr;
1063
- opacity: 0;
1064
- transition-delay: calc(var(--transition-duration) * 0.25), 0s, 0s;
1065
- transition-duration:
1066
- var(--transition-duration), calc(var(--transition-duration) * 1.4),
1067
- var(--transition-duration);
1068
- transition-property: grid-template-rows, opacity, border;
1069
-
1070
- > * {
1071
- opacity: 0;
1072
- transition-delay: 0s;
1073
- transition-duration: calc(var(--transition-duration) * 2);
1074
- transition-property: opacity;
1075
- }
1076
-
1077
- .bb-listbox__inner-container {
1078
- overflow: auto;
1079
- overflow-x: clip;
1080
- text-align: left;
1081
- /* Always show options up to the bottom of the screen, but not more than 6 options */
1082
- max-height: min(
1083
- calc(var(--option-h) * 6),
1084
- calc(round(down, calc(100dvh - 130px), var(--option-h)) - 1px)
1085
- );
1086
-
1087
- .bb-listbox__loading,
1088
- .bb-listbox__no-data {
1089
- color: var(--bb-text);
1090
- display: none;
1091
- padding-bottom: var(--bb-select-option-py);
1092
- padding-left: var(--bb-select-option-px);
1093
- padding-right: var(--bb-select-option-px);
1094
- padding-top: var(--bb-select-option-py);
1095
- }
1096
-
1097
- span[role='listbox'] {
1098
- position: relative;
1099
- width: 100%;
1100
- display: block;
1101
-
1102
- .bb-listbox__group {
1103
- left: 0;
1104
- position: absolute;
1105
- top: 0;
1106
- width: 100%;
1107
- display: block;
1108
- }
1109
-
1110
- .bb-listbox__group-header {
1111
- display: flex;
1112
- align-items: center;
1113
- height: var(--group-header-height, 32px);
1114
- padding-left: var(--bb-select-option-px);
1115
- padding-right: var(--bb-select-option-px);
1116
-
1117
- user-select: none;
1118
-
1119
- .bb-listbox__group-header-label {
1120
- display: flex;
1121
- align-items: center;
1122
- gap: 16px;
1123
- flex: auto;
1124
- text-align: left;
1125
- overflow: hidden;
1126
- text-overflow: ellipsis;
1127
- white-space: nowrap;
1128
- color: color-mix(in srgb, var(--bb-text) 50%, transparent);
1129
- font-size: 0.75rem;
1130
- font-weight: 600;
1131
- letter-spacing: 0.025em;
1132
- text-transform: uppercase;
1133
-
1134
- &::after {
1135
- content: '';
1136
- display: block;
1137
- width: 100%;
1138
- height: 1px;
1139
- background-color: var(--bb-border);
1140
- }
1141
- }
1142
- }
1143
-
1144
- .bb-listbox__option {
1145
- left: 0;
1146
- position: absolute;
1147
- display: block;
1148
- top: 0;
1149
- width: 100%;
1150
- }
1151
-
1152
- .bb-listbox__group > .bb-listbox__option {
1153
- position: static;
1154
- }
1155
-
1156
- .autocomplete-option {
1157
- --bg-opacity: 0;
1158
- --bg-base-color: var(--bb-text);
1159
- align-items: center;
1160
- background-color: color-mix(
1161
- in srgb,
1162
- var(--bg-base-color) calc(100% * var(--bg-opacity)),
1163
- transparent
1164
- );
1165
- color: var(--bb-text);
1166
- cursor: pointer;
1167
- display: flex;
1168
- flex-grow: 1;
1169
- gap: 8px;
1170
- height: var(--option-h);
1171
- padding-left: var(--bb-select-option-px);
1172
- padding-right: var(--bb-select-option-px);
1173
- transition-duration: 250ms;
1174
- transition-property: color, background-color;
1175
- transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
1176
- width: 100%;
1177
-
1178
- &:hover:not(.autocomplete-option--disabled) {
1179
- --bg-opacity: 0.05;
1180
- --bg-base-color: var(--bb-text);
1181
- }
1182
-
1183
- &--focused {
1184
- --bg-opacity: 0.15;
1185
- --bg-base-color: var(--bb-text);
1186
- }
1187
-
1188
- &--focused:hover:not(.autocomplete-option--disabled) {
1189
- --bg-opacity: 0.2;
1190
- }
1191
-
1192
- &--selected {
1193
- --bg-opacity: 0.1;
1194
- --bg-base-color: var(--bb-primary) !important;
1195
- color: var(--bb-primary);
1196
- }
1197
-
1198
- &--selected:hover:not(.autocomplete-option--disabled) {
1199
- --bg-opacity: 0.15;
1200
- }
1201
-
1202
- &--selected.autocomplete-option--focused {
1203
- --bg-opacity: 0.2;
1204
- }
1205
-
1206
- &--selected.autocomplete-option--focused:hover:not(
1207
- .autocomplete-option--disabled
1208
- ) {
1209
- --bg-opacity: 0.2;
1210
- }
1211
-
1212
- &--disabled {
1213
- cursor: not-allowed;
1214
- opacity: 0.5;
1215
-
1216
- .autocomplete-option__checkbox.autocomplete-option__checkbox {
1217
- background-color: var(--bb-panel-disabled);
1218
- }
1219
- }
1220
-
1221
- .autocomplete-option__checkbox {
1222
- pointer-events: none;
1223
- display: none;
1224
- width: 16px;
1225
- height: 16px;
1226
- background-color: var(--bb-panel);
1227
- border-color: var(--bb-border);
1228
- border-radius: min(6px, var(--bb-radius));
1229
- border-style: solid;
1230
- border-width: 1px;
1231
- margin-left: -6px;
1232
- transition-duration: 300ms;
1233
- transition-property:
1234
- color, background-color, border-color, text-decoration-color,
1235
- box-shadow;
1236
- transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
1237
-
1238
- path {
1239
- stroke: var(--bb-contrasting);
1240
- stroke-dasharray: 105;
1241
- stroke-dashoffset: 105;
1242
- transition: stroke-dashoffset 0.3s;
1243
- }
1244
- }
1245
-
1246
- .autocomplete-option__label {
1247
- display: block;
1248
- flex: auto;
1249
- text-align: left;
1250
- overflow: hidden;
1251
- text-overflow: ellipsis;
1252
- white-space: nowrap;
1253
- }
1254
-
1255
- &.autocomplete-option--selected {
1256
- .autocomplete-option__checkbox {
1257
- background-color: var(--bb-primary);
1258
- border-color: var(--bb-primary);
1259
-
1260
- path {
1261
- stroke-dashoffset: 0;
1262
- }
1263
- }
1264
- }
1265
- }
1266
- }
1267
- }
1268
- }
1269
- }
1270
- }
1271
- </style>
1272
- ```
1047
+ The panel carries a search field (role `searchbox`). Filtering follows the shared
1048
+ semantics (Options/Fetch playbooks): array items filter locally by
1049
+ case-insensitive **substring** against the display text; `filter-by: ['path', …]`
1050
+ searches the listed paths **instead of** the text (every path must exist on every
1051
+ item or matching throws); with a provider, the local substring filter **still
1052
+ applies on top of** the response, so keep server matches substring-compatible.
1273
1053
 
1274
- ## Types
1054
+ `disable-writing` removes the search field entirely — `true` everywhere, or
1055
+ `'mobile'` / `'desktop'` to drop it on one platform only. It is also the
1056
+ supported way to disable typing/filtering (and, with it, `option:add`); use it
1057
+ when the option list is short enough to just scroll.
1275
1058
 
1276
- ```ts
1277
- import type { HTMLAttributes, InputHTMLAttributes } from 'vue';
1278
- import type { CommonProps } from '@/types/CommonProps';
1279
-
1280
- export type BbSelectPopoverProps<Item> = {
1281
- /**
1282
- * External activator element or component ref.
1283
- * When provided, the activator slot is not rendered and event listeners
1284
- * are attached programmatically to the referenced element.
1285
- */
1286
- activator?: HTMLElement | Record<string, any> | null;
1287
-
1288
- /**
1289
- * Controls whether the search input is shown inside the popover panel.
1290
- * Use `'not-mobile'` to hide the search input on mobile.
1291
- *
1292
- * @defaultValue `false`
1293
- */
1294
- allowWriting?: boolean | 'not-mobile';
1295
-
1296
- /**
1297
- * Browser autocomplete hint for the popover search input.
1298
- *
1299
- * @defaultValue `'off'`
1300
- */
1301
- autocomplete?: InputHTMLAttributes['autocomplete'];
1302
-
1303
- /**
1304
- * Apply the compact density variant.
1305
- */
1306
- compact?: boolean;
1307
-
1308
- /**
1309
- * Space the arrow keeps from popover edges. Useful with rounded corners.
1310
- *
1311
- * @defaultValue `10`
1312
- */
1313
- arrowPadding?: CommonProps['arrowPadding'];
1314
-
1315
- /**
1316
- * Constrains the popover to a specific boundary element.
1317
- */
1318
- boundary?: HTMLElement | Record<string, any> | string | null;
1319
-
1320
- /**
1321
- * Additional dependencies that trigger item reloading when changed.
1322
- *
1323
- * @defaultValue `[]`
1324
- */
1325
- dependencies?: any[];
1326
-
1327
- /**
1328
- * Debounce delay (ms) for dependency-triggered reloads.
1329
- *
1330
- * @defaultValue `0`
1331
- */
1332
- depsDebounceTime?: number;
1333
-
1334
- /**
1335
- * Disables the component.
1336
- */
1337
- disabled?: boolean;
1338
-
1339
- /**
1340
- * Marks the component as being in error state.
1341
- */
1342
- hasErrors?: boolean;
1343
-
1344
- /**
1345
- * Explicit invalid state for accessibility semantics.
1346
- * Falls back to `hasErrors` when not provided.
1347
- */
1348
- ariaInvalid?: boolean;
1349
-
1350
- /**
1351
- * Space-separated IDREF(s) that describe this field for assistive technologies.
1352
- * Accepts either a string or array of ids.
1353
- */
1354
- ariaDescribedby?: string | string[];
1355
-
1356
- /**
1357
- * Enable or disable floating flip behavior.
1358
- *
1359
- * @defaultValue `true`
1360
- */
1361
- flip?: boolean;
1362
-
1363
- /**
1364
- * Whether the floating arrow is hidden.
1365
- *
1366
- * @defaultValue `true`
1367
- */
1368
- hideArrow?: boolean;
1369
-
1370
- /**
1371
- * Reset modelValue to `null` or empty array if it no longer matches available items.
1372
- */
1373
- enforceCoherence?: boolean;
1374
-
1375
- /**
1376
- * Controls how options are filtered during search.
1377
- *
1378
- * @defaultValue `() => []`
1379
- */
1380
- filterBy?:
1381
- | string
1382
- | string[]
1383
- | false
1384
- | 'not_stashed'
1385
- | ((value: any, item: any, query: string | null) => boolean)
1386
- | null;
1387
-
1388
- /** Path to item property for grouping options. */
1389
- groupBy?: string | ((item: Item) => string | number | symbol);
1390
-
1391
- /**
1392
- * Height of group headers in the listbox (px). Defaults to 24px (compact) or 32px.
1393
- * Only applies when `groupBy` is set.
1394
- */
1395
- headerHeight?: number;
1396
-
1397
- /**
1398
- * Explicit id for the component. Used to generate ids for listbox and options.
1399
- */
1400
- id?: HTMLAttributes['id'];
1401
-
1402
- /**
1403
- * Array of items or function to load them asynchronously.
1404
- * Functions receive `(query, prefill, modelValue)` and can return a promise.
1405
- *
1406
- * @defaultValue `[]`
1407
- */
1408
- items:
1409
- | Item[]
1410
- | ((query: string, prefill: boolean, modelValue: any[]) => Promise<Item[]>)
1411
- | ((query: string, prefill: boolean, modelValue: any[]) => Item[]);
1412
-
1413
- /**
1414
- * Height of the options in the listbox (px).
1415
- *
1416
- * @defaultValue `40`
1417
- */
1418
- itemHeight?: number;
1419
-
1420
- /**
1421
- * Path to item property for display text or function to extract it.
1422
- */
1423
- itemText?: string | ((item: Item) => string) | undefined;
1424
-
1425
- /**
1426
- * Path to item property for value or function to extract it.
1427
- */
1428
- itemValue?: string | ((item: Item) => string) | undefined;
1429
-
1430
- /**
1431
- * Display the loading state styles.
1432
- */
1433
- loading?: boolean;
1434
-
1435
- /**
1436
- * Message shown while items are being loaded.
1437
- */
1438
- loadingText?: string;
1439
-
1440
- /**
1441
- * Maximum number of selectable items (limits selection when `multiple` is true).
1442
- *
1443
- * @defaultValue `Infinity`
1444
- */
1445
- max?: number;
1446
-
1447
- /**
1448
- * v-model value. Single value for single select, array for multiple select.
1449
- */
1450
- modelValue: any;
1451
-
1452
- /**
1453
- * Debounce delay (ms) for modelValue change handling.
1454
- *
1455
- * @defaultValue `0`
1456
- */
1457
- modelValueDebounceTime?: number;
1458
-
1459
- /**
1460
- * Enable multiple item selection. When true, modelValue must be an array.
1461
- */
1462
- multiple?: boolean;
1463
-
1464
- /**
1465
- * Message displayed when no items are available.
1466
- */
1467
- noDataText?: string;
1468
-
1469
- /**
1470
- * Distance (px) between the activator and the popover.
1471
- *
1472
- * @defaultValue `4`
1473
- */
1474
- offset?: number;
1475
-
1476
- /**
1477
- * Minimum page padding used by floating shift middleware.
1478
- *
1479
- * @defaultValue `0`
1480
- */
1481
- padding?: CommonProps['padding'];
1482
-
1483
- /**
1484
- * Floating placement of the popover.
1485
- *
1486
- * @defaultValue `'bottom'`
1487
- */
1488
- placement?: CommonProps['placement'];
1489
-
1490
- /**
1491
- * Controls when items are pre-loaded.
1492
- * `'interaction'` loads on first user interaction, `true` loads immediately,
1493
- * `false` loads only on explicit search/open flows.
1494
- *
1495
- * @defaultValue `'interaction'`
1496
- */
1497
- prefill?: boolean | 'interaction';
1498
-
1499
- /**
1500
- * Debounce delay (ms) before triggering search queries after user input stops.
1501
- *
1502
- * @defaultValue `500`
1503
- */
1504
- queryDebounceTime?: number;
1505
-
1506
- /**
1507
- * Prevents opening the popover while keeping the activator accessible.
1508
- */
1509
- readonly?: boolean;
1510
-
1511
- /**
1512
- * Accessible label used by the search input rendered inside the popover.
1513
- *
1514
- * @defaultValue `'Search options'`
1515
- */
1516
- searchInputAriaLabel?: string;
1517
-
1518
- /**
1519
- * Accumulate selected items across searches instead of replacing them.
1520
- */
1521
- stash?: boolean;
1522
-
1523
- /**
1524
- * Transition duration (ms) for popover show/hide animations.
1525
- *
1526
- * @defaultValue `300`
1527
- */
1528
- transitionDuration?: number;
1529
-
1530
- /**
1531
- * Width of the popover in pixels, percentage, or `'auto'`.
1532
- */
1533
- width?: number | string;
1534
- };
1059
+ **Scroll-only status pill**
1535
1060
 
1536
- export type BbSelectPopoverEvents = {
1537
- /**
1538
- * Emitted when the activator loses focus.
1539
- */
1540
- (e: 'blur', event: FocusEvent): void;
1541
- /**
1542
- * Emitted when the value changes via native change event.
1543
- */
1544
- (e: 'change', event: Event): void;
1545
- /**
1546
- * Emitted when the activator is clicked.
1547
- */
1548
- (e: 'click', event: MouseEvent): void;
1549
- /**
1550
- * Emitted when the activator receives focus.
1551
- */
1552
- (e: 'focus', event: FocusEvent): void;
1553
- /**
1554
- * Emitted when focus moves outside the entire component after it was active.
1555
- */
1556
- (e: 'inactive'): void;
1557
- /**
1558
- * Emitted on native input events from the search input.
1559
- */
1560
- (e: 'input', event: Event): void;
1561
- /**
1562
- * Emitted with the next selection value whenever selection changes.
1563
- */
1564
- (e: 'update:modelValue', value: any): void;
1565
- /**
1566
- * Emitted when the user types a new value and confirms it (Enter key) when `allowWriting` is enabled.
1567
- */
1568
- (e: 'option:add', text: string): void;
1569
- };
1061
+ ```vue
1062
+ <template>
1063
+ <div
1064
+ class="flex max-w-sm items-center gap-1.5 rounded-[var(--bb-radius)] border p-2"
1065
+ >
1066
+ <span class="pr-1 text-xs font-medium text-[color:var(--bb-text-muted)]"
1067
+ >Status</span
1068
+ >
1069
+ <BbSelectPopover
1070
+ v-model="status"
1071
+ compact
1072
+ disable-writing
1073
+ :items="statuses"
1074
+ width="200px"
1075
+ >
1076
+ <template #activator="{ props, shown }">
1077
+ <BbBadge
1078
+ append:icon="lucide:chevron-down"
1079
+ :class="{ 'status-trigger--editing': shown }"
1080
+ size="lg"
1081
+ :variant="variantFor(status)"
1082
+ >
1083
+ <BbBadgeButton v-bind="props">{{
1084
+ status ?? 'Set status'
1085
+ }}</BbBadgeButton>
1086
+ </BbBadge>
1087
+ </template>
1088
+ </BbSelectPopover>
1089
+ </div>
1090
+ </template>
1091
+ <script setup lang="ts">
1092
+ import { BbBadge, BbBadgeButton, BbSelectPopover } from 'bitboss-ui';
1093
+ import type { BadgeVariantType } from 'bitboss-ui';
1094
+ import { ref } from 'vue';
1570
1095
 
1571
- /** Props exposed by the `activator` slot. */
1572
- export type BbSelectPopoverActivatorSlotProps = {
1573
- /** Bind onto the activator element with `v-bind="props"` to wire up the popover reference. */
1574
- props: {
1575
- ref: (reference: unknown) => void;
1576
- };
1577
- /** Whether the popover is currently open. */
1578
- shown: boolean;
1579
- /** Whether the select is disabled. */
1580
- disabled: boolean | undefined;
1581
- /** Whether the select is read-only. */
1582
- readonly: boolean | undefined;
1583
- /** Whether options are currently being fetched. */
1584
- loading: boolean;
1585
- /** The current search query string. */
1586
- query: string;
1587
- /** Clears the current selection and query. */
1588
- clear: () => void;
1589
- /** Opens the popover. */
1590
- open: () => Promise<void>;
1591
- /** Closes the popover. */
1592
- close: () => Promise<void>;
1593
- /** Toggles the popover open/closed. */
1594
- toggle: () => Promise<void>;
1595
- };
1096
+ const statuses = ['Draft', 'In review', 'Approved', 'Published'];
1097
+ type Status = (typeof statuses)[number];
1596
1098
 
1597
- /** Props exposed by the `option` slot. */
1598
- export type BbSelectPopoverOptionSlotProps<Item> = {
1599
- /** Whether this option is disabled. */
1600
- disabled: boolean;
1601
- /** Whether this option currently has keyboard focus. */
1602
- focused: boolean;
1603
- /** Zero-based index of this option in the list. */
1604
- index: number;
1605
- /** The raw item from the `items` prop. */
1606
- item: Item;
1607
- /** Whether items are still being fetched. */
1608
- loading: boolean;
1609
- /** Whether this option is currently selected. */
1610
- selected: boolean;
1611
- /** The resolved display text for this option. */
1612
- text: string;
1613
- /** The resolved value for this option. */
1614
- value: any;
1615
- };
1099
+ const status = ref<Status | null>(null);
1616
1100
 
1617
- /** Props exposed by the `group` slot. */
1618
- export type BbSelectPopoverGroupSlotProps<Item> = {
1619
- /** The display text for this group. */
1620
- text: string;
1621
- /** The raw group item. */
1622
- item: Item;
1623
- /** Zero-based index of the first option in this group. */
1624
- index: number;
1625
- /** Number of options in this group. */
1626
- length: number;
1627
- /** Whether all options in this group are disabled. */
1628
- disabled: boolean;
1101
+ const VARIANT: Record<Status, BadgeVariantType> = {
1102
+ Draft: 'soft-gray',
1103
+ 'In review': 'soft-amber',
1104
+ Approved: 'soft-blue',
1105
+ Published: 'soft-green',
1629
1106
  };
1630
1107
 
1631
- export type BbSelectPopoverSlots<Item> = {
1632
- /**
1633
- * Replaces the default trigger element that opens the select popover.
1634
- */
1635
- activator?: (props: BbSelectPopoverActivatorSlotProps) => any;
1636
- /**
1637
- * Content shown inside the options dropdown while items are loading.
1638
- */
1639
- loading?: (props: { query: string }) => any;
1640
- /**
1641
- * Content shown when no options match the query or the list is empty.
1642
- */
1643
- 'no-data'?: (props: { query: string; focus: () => void }) => any;
1644
- /**
1645
- * Replaces the default rendering of each option row in the dropdown.
1646
- */
1647
- option?: (props: BbSelectPopoverOptionSlotProps<Item>) => any;
1648
- /**
1649
- * Replaces the default group header rendered above grouped options.
1650
- */
1651
- group?: (props: BbSelectPopoverGroupSlotProps<Item>) => any;
1652
- /**
1653
- * Content appended inside the options list, after the last option.
1654
- */
1655
- 'options:append'?: (props: { focus: () => void }) => any;
1656
- /**
1657
- * Content appended outside the options list container.
1658
- */
1659
- 'options:append:outer'?: (props: { focus: () => void }) => any;
1660
- /**
1661
- * Content prepended inside the options list, before the first option.
1662
- */
1663
- 'options:prepend'?: (props: { focus: () => void }) => any;
1664
- /**
1665
- * Content prepended outside the options list container.
1666
- */
1667
- 'options:prepend:outer'?: (props: { focus: () => void }) => any;
1668
- };
1108
+ const variantFor = (value: Status | null): BadgeVariantType =>
1109
+ value ? VARIANT[value] : 'outline';
1110
+ </script>
1111
+
1112
+ <!-- Soft status palette — canonical source: ai/guides/design-language.md § Using color. -->
1113
+ <style>
1114
+ .bb-badge.bb-badge--soft-gray {
1115
+ --accent: #64748b;
1116
+ }
1117
+ .bb-badge.bb-badge--soft-blue {
1118
+ --accent: #2563eb;
1119
+ }
1120
+ .bb-badge.bb-badge--soft-green {
1121
+ --accent: #16a34a;
1122
+ }
1123
+ .bb-badge.bb-badge--soft-amber {
1124
+ --accent: #d97706;
1125
+ }
1126
+ .bb-badge.bb-badge--soft-gray,
1127
+ .bb-badge.bb-badge--soft-blue,
1128
+ .bb-badge.bb-badge--soft-green,
1129
+ .bb-badge.bb-badge--soft-amber {
1130
+ --bg: color-mix(in oklab, var(--accent) 15%, var(--bb-panel));
1131
+ --color: color-mix(in oklab, var(--accent) 80%, var(--bb-text));
1132
+ --border-width: 1px;
1133
+ --border-color: color-mix(in oklab, var(--accent) 25%, var(--bb-panel));
1134
+ --ring: color-mix(in oklab, var(--accent) 45%, transparent);
1135
+ }
1136
+
1137
+ .status-trigger--editing {
1138
+ --bg: color-mix(in oklab, var(--color) 25%, var(--bb-panel));
1139
+ --border-color: color-mix(in oklab, var(--color) 45%, var(--bb-panel));
1140
+ box-shadow: 0 0 0 var(--bb-ring-size) var(--ring);
1141
+ }
1142
+ </style>
1669
1143
  ```
1144
+
1145
+ ### Sizing and layout
1146
+
1147
+ - `width` sets the popover width — a number (px), a CSS string (`'240px'`,
1148
+ `'100%'`), or `'auto'`. Unlike `BbSelect` (whose panel always matches the
1149
+ control), here the trigger and panel are independent, so size the panel
1150
+ explicitly.
1151
+ - `compact` applies the dense density variant (32px options, 24px group headers).
1152
+ - `item-height` / `header-height` tune the virtualized row heights when you use
1153
+ taller custom `#option` / `#group` markup.
1154
+ - Placement props mirror the palette/dropdown float: `placement`, `offset`
1155
+ (default 4), `padding`, `boundary`, `disable-flip`, `transition-duration`. The
1156
+ panel is a frame, not a bubble — it never shows an arrow.
1157
+
1158
+ ### Adaptive mobile sheet
1159
+
1160
+ With `adaptive` (default: global `config.adaptive`, which is `true`), the panel
1161
+ opens as a bottom off-canvas sheet on mobile viewports (below
1162
+ `config.mobileMaxWidth`) instead of a floating popover — same search, options and
1163
+ `#header`/`#footer` slots, plus a representation of the current selection between
1164
+ them. The surface is **latched per open cycle**: a mid-open resize never swaps
1165
+ popover ↔ sheet. `off-canvas-props` forwards extra `BbOffCanvas` props to the
1166
+ sheet (`size`, `draggable`, `fullscreen`, `stack`); `:adaptive="false"` keeps a
1167
+ floating popover everywhere.
1168
+
1169
+ ### Events and v-model
1170
+
1171
+ - `update:modelValue` — the resolved value (single) or array (multiple), on pick,
1172
+ `clear`, coherence enforcement, and — in `multiple` mode only — deselect.
1173
+ A second click on the current option in single mode emits nothing.
1174
+ - `option:add` — Enter on a non-matching query with nothing highlighted (above).
1175
+ - `focus` / `blur` — the activator gaining/losing focus.
1176
+ - `input` / `change` — native events from the panel search field.
1177
+ - `click` — the activator was clicked.
1178
+ - `inactive` — focus has fully left the component (**trigger and panel**). Because
1179
+ focus legitimately moves into the panel while open, validate/react on
1180
+ `inactive`, not on `blur`.
1181
+
1182
+ ### Config and platform
1183
+
1184
+ - **No teleport** — the popover renders **in the component's own subtree** (it is
1185
+ not portalled to `<body>`), so it inherits your CSS context and is directly
1186
+ queryable (handy for tests: the open panel is `.bb-listbox--open` on the same
1187
+ root, no portal hop).
1188
+ - **Global config** — `config.adaptive` (default for `adaptive`),
1189
+ `config.mobileMaxWidth` (the mobile threshold), `config.locale` (the search
1190
+ field's default accessible name and panel string defaults).
1191
+ - **SSR / Nuxt** — `prefill: true` providers also run in `onServerPrefetch`, so
1192
+ server-rendered pages hydrate with options loaded; keep providers isomorphic
1193
+ (no `window` access).
1194
+
1195
+ ### Works well with
1196
+
1197
+ - `BbSelect` — the same engine as a labelled form field; swap when the trigger
1198
+ should be an inline input with hint/error states.
1199
+ - `BbTable` — popover triggers as inline-edit cells or toolbar filters; list
1200
+ their models in the table provider's `dependencies`.
1201
+ - `BbButton` — the natural activator (it forwards `props` and exposes a
1202
+ `loading` state to reflect fetches).
1203
+ - `useToast` — surface provider failures the component only logs.
1204
+
1205
+ ### Gotchas and constraints
1206
+
1207
+ - `multiple` with a non-array model **throws at setup** — seed `ref([])`.
1208
+ - A seeded model shows **no trigger `text`** until the first load (no eager
1209
+ prefill upgrade, by design) — resolve the label from your own state. Array
1210
+ `items` resolve on mount, so this only bites providers.
1211
+ - The local substring filter also applies to provider results — server matches
1212
+ whose text doesn't contain the query are hidden.
1213
+ - `filter-by` is `string[]` only and matches exactly those paths; each must exist
1214
+ on every item or matching throws.
1215
+ - `prefill: false` is search-first: opening fetches nothing and the panel shows
1216
+ the "search to begin" hint until the user types. It quietly falls back to
1217
+ loading on open when writing is disabled, the model is non-empty, or `items` is
1218
+ an array.
1219
+ - `enforce-coherence` + a provider that drops the selection on component-initiated
1220
+ (`prefill === true`) calls = wiped model — and since the check now runs on the
1221
+ **first** load, that wipe happens at mount rather than later. Resolve the
1222
+ current selection in those responses, or enable `stash`.
1223
+ - `enforce-coherence` opts **each instance** into its own load. One field, one
1224
+ request; N provider-backed rows, N requests.
1225
+ - `option:add` can fire with an empty string — trim and guard.
1226
+ - **Clicking the selected option does not clear a single select** — it re-picks
1227
+ it and closes the panel. Emptying is the `clear` callback (activator/panel
1228
+ slot scope), never an accidental second click. Multiple mode still toggles.
1229
+ - **`null` as a real "All" option** works — it resolves and renders as the
1230
+ selection — but it overloads the value the component uses for _nothing
1231
+ selected_. So a `null` model stays lazy (nothing to resolve, no load, not even
1232
+ with `enforce-coherence`), `clear` is indistinguishable from picking "All", and
1233
+ an `enforce-coherence` prune emits `null` — i.e. a stale value **widens to
1234
+ "All"** rather than clearing. Fine if you want it; use a sentinel
1235
+ (`'all'`) if "everything" and "nothing" must stay distinct.
1236
+
1237
+ ### Anti-patterns
1238
+
1239
+ - Reading `text` (or `selectedOptions`) for the trigger label instead of
1240
+ computing it from your own state — with a provider they are empty until the
1241
+ first load, so the trigger's appearance ends up depending on whether the panel
1242
+ was ever opened.
1243
+ - Binding many instances to **one shared ref**: each judges the same value against
1244
+ its own options and every instance that disagrees emits `null`, so the user's
1245
+ pick is overwritten by its neighbours. One model per row.
1246
+ - Giving every table row its own **provider**: N rows becomes N requests. Resolve
1247
+ the options once at page level and pass the same array down.
1248
+ - Reaching for `prefill: true` to populate a trigger label.
1249
+ - Rebuilding chips, counts or select-all in wrapper markup when `max`,
1250
+ `selectedOptions` and the panel slots cover it.
1251
+ - Hand-rolled debounce/loading refs around the provider.
1252
+ - `watch(filter, refetch)` when `dependencies` exists; blind `model = null`
1253
+ resets when `enforce-coherence` would preserve still-valid values.
1254
+ - Using it where an inline labelled field is wanted (that's `BbSelect`), or for a
1255
+ static three-option choice (that's `BbRadioGroup`).
1256
+
1257
+ ### Accessibility
1258
+
1259
+ - The activator carries the accessible name — make it a real focusable element (a
1260
+ `<button>` or `BbButton`), and give icon-only triggers an `aria-label`.
1261
+ - The in-panel search field is labelled by `search-input-aria-label` (defaults to
1262
+ "Search options"); override it to match your domain.
1263
+ - The component manages listbox roles, `aria-activedescendant`, the full keyboard
1264
+ model and focus return to the trigger on close — do not reimplement them.
1265
+ - Because the trigger is yours, reflect the open state visually (the `shown` slot
1266
+ prop) so keyboard and low-vision users can see the popover is expanded.
1267
+
1268
+ ## v-model
1269
+
1270
+ - `v-model` — type: `any`
1271
+
1272
+ ## Props
1273
+
1274
+ | Prop | Type | Default | Required | Description |
1275
+ | --- | --- | --- | --- | --- |
1276
+ | `activator` | `Record<string, any> \| HTMLElement \| null \| undefined` | | | External activator element or component ref. When provided, the activator slot is not rendered and event listeners are attached programmatically to the referenced element. |
1277
+ | `adaptive` | `boolean \| undefined` | `undefined` | | When `true`, the panel opens as a bottom off-canvas sheet on mobile viewports instead of a floating popover; on desktop it stays a popover. The sheet reuses the same search field and options list, adding a representation of the current sele… |
1278
+ | `anchor` | `Record<string, any> \| HTMLElement \| null \| undefined` | `null` | | Override the element used for popover positioning and width measurement. Useful when the focusable activator is narrower than its visual container (e.g. a button inside a wrapper). Falls back to `activatorEl` when omitted. |
1279
+ | `ariaDescribedby` | `string \| string[] \| undefined` | | | Space-separated IDREF(s) that describe this field for assistive technologies. Accepts either a string or array of ids. |
1280
+ | `ariaInvalid` | `boolean \| undefined` | `undefined` | | Explicit invalid state for accessibility semantics. Falls back to `hasErrors` when not provided. |
1281
+ | `autocomplete` | `string \| undefined` | `"off"` | | Browser autocomplete hint for the popover search input. |
1282
+ | `boundary` | `string \| Record<string, any> \| HTMLElement \| null \| undefined` | | | Constrains the popover to a specific boundary element. |
1283
+ | `clearable` | `boolean \| undefined` | | | Shows a clear button inside the search field's icon stack: it takes the lens' place on hover/focus while there is a query or selection to clear, and resets both. Off by default. Leave it off when the component is wrapped by a control that a… |
1284
+ | `compact` | `boolean \| undefined` | | | Apply the compact density variant. |
1285
+ | `dependencies` | `unknown[] \| undefined` | `[]` | | Additional dependencies that trigger item reloading when changed. |
1286
+ | `depsDebounceTime` | `number \| undefined` | `0` | | Debounce delay (ms) for dependency-triggered reloads. |
1287
+ | `disabled` | `boolean \| undefined` | | | Disables the component. |
1288
+ | `disableFlip` | `boolean \| undefined` | | | Disables the automatic flip to the opposite side when the popover would overflow (flipping is on by default). |
1289
+ | `disableWriting` | `boolean \| "mobile" \| "desktop" \| undefined` | | | Controls whether the search input is shown inside the popover panel. Use `'mobile'` to hide the search input on mobile, `'desktop'` to hide it on desktop. |
1290
+ | `enforceCoherence` | `boolean \| undefined` | | | Reset modelValue to `null` or empty array if it no longer matches available items. |
1291
+ | `filterBy` | `string[] \| undefined` | `[]` | | Property paths used to filter options when the user types in the search input. When empty (default) options are matched against their display text. When non-empty the provided paths are searched instead of the display text. To disable filte… |
1292
+ | `groupBy` | `string \| ((item: Item) => string \| number \| symbol) \| undefined` | | | Path to item property for grouping options. |
1293
+ | `hasErrors` | `boolean \| undefined` | | | Marks the component as being in error state. |
1294
+ | `hasWarning` | `boolean \| undefined` | | | Marks the component as being in a warning state. Visually mirrors `hasErrors` but uses `--bb-warn` chrome; errors take priority when both are set. |
1295
+ | `headerHeight` | `number \| undefined` | | | Height of group headers in the listbox (px). Defaults to 24px (compact) or 32px. Only applies when `groupBy` is set. |
1296
+ | `id` | `string \| undefined` | | | Explicit id for the component. Used to generate ids for listbox and options. |
1297
+ | `itemHeight` | `number \| undefined` | | | Height of the options in the listbox (px). |
1298
+ | `items` | `Item[] \| ((query: string, prefill: boolean, modelValue: any) => Promise<Item[]>) \| ((query: string, prefill: boolean, modelValue: any) => Item[])` | | yes | Array of items or function to load them asynchronously. Functions receive `(query, prefill, modelValue)` and can return a promise. `modelValue` is the raw v-model: an array in `multiple` mode, the raw model value (possibly `null`) in single… |
1299
+ | `itemText` | `ItemAccessor<Item, string> \| undefined` | | | Path to item property for display text or function to extract it. |
1300
+ | `itemValue` | `ItemAccessor<Item> \| undefined` | | | Path to item property for value or function to extract it. |
1301
+ | `loading` | `boolean \| undefined` | | | Display the loading state styles. |
1302
+ | `loadingText` | `string \| undefined` | | | Message shown while items are being loaded. |
1303
+ | `max` | `number \| undefined` | `Infinity` | | Maximum number of selectable items (limits selection when `multiple` is true). |
1304
+ | `modelValue` | `any` | | yes | v-model value. Single value for single select, array for multiple select. |
1305
+ | `modelValueDebounceTime` | `number \| undefined` | `0` | | Debounce delay (ms) for modelValue change handling. |
1306
+ | `multiple` | `boolean \| undefined` | | | Enable multiple item selection. When true, modelValue must be an array. |
1307
+ | `noDataText` | `string \| undefined` | | | Message displayed when no items are available. |
1308
+ | `offCanvasProps` | `Partial<BbOffCanvasProps> \| undefined` | | | Extra props forwarded to the `BbOffCanvas` sheet when `adaptive` is active on mobile (e.g. `size`, `draggable`, `fullscreen`, `stack`). |
1309
+ | `offset` | `number \| undefined` | `4` | | Distance (px) between the activator and the popover. |
1310
+ | `padding` | `number \| undefined` | `10` | | Minimum page padding used by floating shift middleware. |
1311
+ | `placement` | `Placement \| undefined` | `"bottom"` | | Floating placement of the popover. |
1312
+ | `prefill` | `boolean \| "interaction" \| undefined` | `"interaction"` | | Controls when items are pre-loaded. `'interaction'` loads on the first user interaction (opening the popover), `true` loads immediately on mount (and during SSR via `onServerPrefetch`), `false` is *search-first*: nothing is fetched until th… |
1313
+ | `queryDebounceTime` | `number \| undefined` | `500` | | Debounce delay (ms) before triggering search queries after user input stops. |
1314
+ | `readonly` | `boolean \| undefined` | | | Prevents opening the popover while keeping the activator accessible. |
1315
+ | `searchInputAriaLabel` | `string \| undefined` | | | Accessible label used by the search input rendered inside the popover. Falls back to the localized `select.searchLabel` key when omitted. |
1316
+ | `selectable` | `boolean \| ((item: Item) => boolean) \| undefined` | `true` | | Defines whether options are selectable. Can be a global boolean that affects all options or a function that accepts an item and returns a boolean that only affects that item. Non-selectable options are rendered disabled. |
1317
+ | `stash` | `boolean \| undefined` | | | Accumulate selected items across searches instead of replacing them. |
1318
+ | `transitionDuration` | `number \| undefined` | `transitions.medium` | | Transition duration (ms) for popover show/hide animations. |
1319
+ | `width` | `string \| number \| undefined` | `"200"` | | Width of the popover in pixels, percentage, or `'auto'`. A bare number is read as pixels — the default is the string `'200'`, not the number `200`. |
1320
+
1321
+ ## Events
1322
+
1323
+ - `active` — `(e: "active"): void` — Emitted when the component becomes active (focus enters it).
1324
+ - `blur` — `(e: "blur", event: FocusEvent): void` — Emitted when the activator loses focus.
1325
+ - `change` — `(e: "change", event: Event): void` — Emitted when the value changes via native change event.
1326
+ - `click` — `(e: "click", event: MouseEvent): void` — Emitted when the activator is clicked.
1327
+ - `focus` — `(e: "focus", event: FocusEvent): void` — Emitted when the activator receives focus.
1328
+ - `inactive` — `(e: "inactive"): void` — Emitted when focus moves outside the entire component after it was active.
1329
+ - `input` — `(e: "input", event: Event): void` — Emitted on native input events from the search input.
1330
+ - `option:add` — `(e: "option:add", text: string): void` — Emitted when the user types a new value and confirms it (Enter key) while writing is enabled (i.e. `disableWriting` does not suppress the search input for the current surface).
1331
+ - `update:modelValue` — `(e: "update:modelValue", value: any): void` — Emitted with the next selection value whenever selection changes.
1332
+
1333
+ ## Slots
1334
+
1335
+ - `activator` — scope: `BbSelectPopoverActivatorSlotProps` — Replaces the default trigger element that opens the select popover.
1336
+ - `footer` — scope: `BbSelectPopoverPanelSlotProps` — Content pinned to the bottom of the panel, below the options list. Rendered in both the desktop popover and the adaptive sheet.
1337
+ - `group` — scope: `BbSelectPopoverGroupSlotProps<Item>` — Replaces the default group header rendered above grouped options.
1338
+ - `header` — scope: `BbSelectPopoverPanelSlotProps` — Content pinned to the top of the panel, above the search field. Rendered in both the desktop popover and the adaptive sheet.
1339
+ - `loading` — scope: `{ query: string; }` — Content shown inside the options dropdown while items are loading.
1340
+ - `no-data` — scope: `{ query: string; focus: () => void; }` — Content shown when no options match the query or the list is empty.
1341
+ - `option` — scope: `BbSelectPopoverOptionSlotProps<Item>` — Replaces the default rendering of each option row in the dropdown.
1342
+
1343
+ ## See Also
1344
+
1345
+ - [BbSelect](./BbSelect.md) — Selects one or many options from structured data.
1346
+ - [BbPopover](./BbPopover.md) — Anchors floating content to reference elements.