bitboss-ui 2.1.113 → 2.1.115

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 (423) hide show
  1. package/dist/ai/BaseButton.md +448 -0
  2. package/dist/ai/BaseCheckbox.md +494 -0
  3. package/dist/ai/BaseCheckboxGroup.md +597 -0
  4. package/dist/ai/BaseColorInput.md +461 -0
  5. package/dist/ai/BaseDatePicker.md +739 -0
  6. package/dist/ai/BaseDatePickerInput.md +1517 -0
  7. package/dist/ai/BaseDialog.md +610 -0
  8. package/dist/ai/BaseInputContainer.md +570 -0
  9. package/dist/ai/BaseNumberInput.md +509 -0
  10. package/dist/ai/BaseRadio.md +405 -0
  11. package/dist/ai/BaseRadioGroup.md +535 -0
  12. package/dist/ai/BaseRating.md +489 -0
  13. package/dist/ai/BaseSelect.md +1720 -0
  14. package/dist/ai/BaseSlider.md +871 -0
  15. package/dist/ai/BaseSwitch.md +322 -0
  16. package/dist/ai/BaseSwitchGroup.md +298 -0
  17. package/dist/ai/BaseTag.md +624 -0
  18. package/dist/ai/BaseTextInput.md +392 -0
  19. package/dist/ai/BaseTextarea.md +398 -0
  20. package/dist/ai/BbAccordion.md +135 -0
  21. package/dist/ai/BbAlert.md +226 -0
  22. package/dist/ai/BbAvatar.md +200 -0
  23. package/dist/ai/BbBadge.md +185 -0
  24. package/dist/ai/BbBreadcrumbs.md +536 -0
  25. package/dist/ai/BbButton.md +687 -0
  26. package/dist/ai/BbCheckbox.md +280 -0
  27. package/dist/ai/BbCheckboxGroup.md +387 -0
  28. package/dist/ai/BbChip.md +148 -0
  29. package/dist/ai/BbCollapsible.md +119 -0
  30. package/dist/ai/BbColorInput.md +345 -0
  31. package/dist/ai/BbColorPalette.md +360 -0
  32. package/dist/ai/BbConfirm.md +160 -0
  33. package/dist/ai/BbDatePickerInput.md +414 -0
  34. package/dist/ai/BbDialog.md +135 -0
  35. package/dist/ai/BbDropdown.md +765 -0
  36. package/dist/ai/BbDropdownButton.md +629 -0
  37. package/dist/ai/BbDropzone.md +504 -0
  38. package/dist/ai/BbIcon.md +238 -0
  39. package/dist/ai/BbIntersection.md +121 -0
  40. package/dist/ai/BbNumberInput.md +372 -0
  41. package/dist/ai/BbOffCanvas.md +549 -0
  42. package/dist/ai/BbPagination.md +562 -0
  43. package/dist/ai/BbPopover.md +580 -0
  44. package/dist/ai/BbProgress.md +97 -0
  45. package/dist/ai/BbRadio.md +256 -0
  46. package/dist/ai/BbRadioGroup.md +373 -0
  47. package/dist/ai/BbRating.md +245 -0
  48. package/dist/ai/BbRatio.md +62 -0
  49. package/dist/ai/BbRows.md +307 -0
  50. package/dist/ai/BbSelect.md +562 -0
  51. package/dist/ai/BbSelectPopover.md +2010 -0
  52. package/dist/ai/BbSlider.md +274 -0
  53. package/dist/ai/BbSmoothHeight.md +167 -0
  54. package/dist/ai/BbSpinner.md +154 -0
  55. package/dist/ai/BbSwitch.md +151 -0
  56. package/dist/ai/BbSwitchGroup.md +237 -0
  57. package/dist/ai/BbTab.md +954 -0
  58. package/dist/ai/BbTable.md +1624 -0
  59. package/dist/ai/BbTag.md +315 -0
  60. package/dist/ai/BbTextInput.md +357 -0
  61. package/dist/ai/BbTextarea.md +277 -0
  62. package/dist/ai/BbToast.md +219 -0
  63. package/dist/ai/BbTooltip.md +353 -0
  64. package/dist/ai/BbTree.md +271 -0
  65. package/dist/ai/ChipsBox.md +211 -0
  66. package/dist/ai/ClearableButton.md +67 -0
  67. package/dist/ai/CommaBox.md +212 -0
  68. package/dist/ai/CommonInputInnerContainer.md +419 -0
  69. package/dist/ai/CommonInputOuterContainer.md +56 -0
  70. package/dist/ai/CommonPopover.md +446 -0
  71. package/dist/ai/ErrorIcon.md +61 -0
  72. package/dist/ai/FlatListBox.md +382 -0
  73. package/dist/ai/GroupedListBox.md +538 -0
  74. package/dist/ai/ListBox.md +234 -0
  75. package/dist/ai/OptionsContainer.md +257 -0
  76. package/dist/ai/index.md +124 -0
  77. package/dist/components/BaseButton/BaseButton.vue.d.ts +2 -163
  78. package/dist/components/BaseButton/types.d.ts +158 -0
  79. package/dist/components/BaseCheckbox/BaseCheckbox.vue.d.ts +4 -4
  80. package/dist/components/BaseCheckboxGroup/BaseCheckboxGroup.vue.d.ts +2 -2
  81. package/dist/components/BaseCheckboxGroup/types.d.ts +16 -9
  82. package/dist/components/BaseColorInput/BaseColorInput.vue.d.ts +12 -52
  83. package/dist/components/BaseDatePicker/BaseDatePicker.vue.d.ts +4 -76
  84. package/dist/components/BaseDatePicker/types.d.ts +100 -0
  85. package/dist/components/BaseDatePickerInput/BaseDatePickerInput.vue.d.ts +18 -315
  86. package/dist/components/BaseDatePickerInput/types.d.ts +206 -0
  87. package/dist/components/BaseDialog/BaseDialog.vue.d.ts +6 -156
  88. package/dist/components/BaseDialog/types.d.ts +180 -0
  89. package/dist/components/BaseInputContainer/BaseInputContainer.vue.d.ts +1 -107
  90. package/dist/components/BaseInputContainer/types.d.ts +126 -0
  91. package/dist/components/BaseNumberInput/BaseNumberInput.vue.d.ts +7 -170
  92. package/dist/components/BaseNumberInput/types.d.ts +191 -0
  93. package/dist/components/BaseRadio/BaseRadio.vue.d.ts +6 -119
  94. package/dist/components/BaseRadio/types.d.ts +173 -0
  95. package/dist/components/BaseRadioGroup/BaseRadioGroup.vue.d.ts +4 -274
  96. package/dist/components/BaseRadioGroup/types.d.ts +240 -0
  97. package/dist/components/BaseRating/BaseRating.vue.d.ts +5 -106
  98. package/dist/components/BaseRating/types.d.ts +144 -0
  99. package/dist/components/BaseSelect/BaseSelect.vue.d.ts +2 -363
  100. package/dist/components/BaseSelect/types.d.ts +457 -0
  101. package/dist/components/BaseSlider/BaseSlider.vue.d.ts +6 -178
  102. package/dist/components/BaseSlider/types.d.ts +201 -0
  103. package/dist/components/BaseSwitch/BaseSwitch.vue.d.ts +7 -35
  104. package/dist/components/BaseSwitch/types.d.ts +25 -0
  105. package/dist/components/BaseSwitchGroup/BaseSwitchGroup.vue.d.ts +5 -11
  106. package/dist/components/BaseSwitchGroup/types.d.ts +8 -0
  107. package/dist/components/BaseTag/BaseTag.vue.d.ts +27 -222
  108. package/dist/components/BaseTag/types.d.ts +136 -0
  109. package/dist/components/BaseTextInput/BaseTextInput.vue.d.ts +5 -141
  110. package/dist/components/BaseTextInput/types.d.ts +166 -0
  111. package/dist/components/BaseTextarea/BaseTextarea.vue.d.ts +5 -131
  112. package/dist/components/BaseTextarea/types.d.ts +151 -0
  113. package/dist/components/BbAccordion/BbAccordion.vue.d.ts +3 -51
  114. package/dist/components/BbAccordion/types.d.ts +32 -0
  115. package/dist/components/BbAlert/BbAlert.vue.d.ts +3 -50
  116. package/dist/components/BbAlert/types.d.ts +42 -0
  117. package/dist/components/BbAvatar/BbAvatar.vue.d.ts +3 -23
  118. package/dist/components/BbAvatar/types.d.ts +34 -0
  119. package/dist/components/BbBadge/BbBadge.vue.d.ts +3 -40
  120. package/dist/components/BbBadge/types.d.ts +30 -0
  121. package/dist/components/BbBreadcrumbs/BbBreadcrumbs.vue.d.ts +14 -178
  122. package/dist/components/BbBreadcrumbs/types.d.ts +109 -0
  123. package/dist/components/BbButton/BbButton.vue.d.ts +4 -163
  124. package/dist/components/BbButton/types.d.ts +159 -0
  125. package/dist/components/BbCheckbox/BbCheckbox.vue.d.ts +7 -165
  126. package/dist/components/BbCheckbox/types.d.ts +130 -0
  127. package/dist/components/BbCheckboxGroup/BbCheckboxGroup.vue.d.ts +7 -324
  128. package/dist/components/BbCheckboxGroup/types.d.ts +189 -0
  129. package/dist/components/BbChip/BbChip.vue.d.ts +6 -28
  130. package/dist/components/BbChip/types.d.ts +23 -0
  131. package/dist/components/BbCollapsible/BbCollapsible.vue.d.ts +3 -24
  132. package/dist/components/BbCollapsible/types.d.ts +20 -0
  133. package/dist/components/BbColorInput/BbColorInput.vue.d.ts +10 -151
  134. package/dist/components/BbColorInput/types.d.ts +131 -0
  135. package/dist/components/BbColorPalette/BbColorPalette.vue.d.ts +2 -112
  136. package/dist/components/BbColorPalette/types.d.ts +127 -0
  137. package/dist/components/BbDatePickerInput/BbDatePickerInput.vue.d.ts +6 -212
  138. package/dist/components/BbDatePickerInput/types.d.ts +180 -0
  139. package/dist/components/BbDialog/BbDialog.vue.d.ts +2 -2
  140. package/dist/components/BbDialog/types.d.ts +1 -0
  141. package/dist/components/BbDropdown/BbDropdown.vue.d.ts +21 -247
  142. package/dist/components/BbDropdown/types.d.ts +147 -0
  143. package/dist/components/BbDropdownButton/BbDropdownButton.vue.d.ts +16 -209
  144. package/dist/components/BbDropdownButton/types.d.ts +114 -0
  145. package/dist/components/BbDropzone/BbDropzone.vue.d.ts +7 -86
  146. package/dist/components/BbDropzone/types.d.ts +67 -0
  147. package/dist/components/BbIcon/BbIcon.vue.d.ts +2 -26
  148. package/dist/components/BbIcon/types.d.ts +28 -0
  149. package/dist/components/BbIntersection/BbIntersection.vue.d.ts +3 -41
  150. package/dist/components/BbIntersection/types.d.ts +36 -0
  151. package/dist/components/BbNumberInput/BbNumberInput.vue.d.ts +44 -175
  152. package/dist/components/BbNumberInput/types.d.ts +130 -0
  153. package/dist/components/BbOffCanvas/BbOffCanvas.vue.d.ts +5 -93
  154. package/dist/components/BbOffCanvas/types.d.ts +97 -0
  155. package/dist/components/BbPagination/BbPagination.vue.d.ts +4 -87
  156. package/dist/components/BbPagination/types.d.ts +80 -0
  157. package/dist/components/BbPopover/BbPopover.vue.d.ts +9 -135
  158. package/dist/components/BbPopover/types.d.ts +99 -0
  159. package/dist/components/BbProgress/BbProgress.vue.d.ts +2 -14
  160. package/dist/components/BbProgress/types.d.ts +20 -0
  161. package/dist/components/BbRadio/BbRadio.vue.d.ts +7 -150
  162. package/dist/components/BbRadio/types.d.ts +117 -0
  163. package/dist/components/BbRadioGroup/BbRadioGroup.vue.d.ts +7 -322
  164. package/dist/components/BbRadioGroup/types.d.ts +182 -0
  165. package/dist/components/BbRating/BbRating.vue.d.ts +10 -113
  166. package/dist/components/BbRating/types.d.ts +105 -0
  167. package/dist/components/BbRatio/BbRatio.vue.d.ts +3 -18
  168. package/dist/components/BbRatio/types.d.ts +15 -0
  169. package/dist/components/BbSelect/BbSelect.vue.d.ts +7 -375
  170. package/dist/components/BbSelect/types.d.ts +351 -0
  171. package/dist/components/BbSelectPopover/BbSelectPopover.vue.d.ts +1 -1
  172. package/dist/components/BbSelectPopover/types.d.ts +351 -0
  173. package/dist/components/BbSlider/BbSlider.vue.d.ts +10 -129
  174. package/dist/components/BbSlider/types.d.ts +123 -0
  175. package/dist/components/BbSmoothHeight/BbSmoothHeight.vue.d.ts +2 -23
  176. package/dist/components/BbSmoothHeight/types.d.ts +24 -0
  177. package/dist/components/BbSpinner/BbSpinner.vue.d.ts +3 -5
  178. package/dist/components/BbSpinner/types.d.ts +8 -0
  179. package/dist/components/BbSwitch/BbSwitch.vue.d.ts +9 -65
  180. package/dist/components/BbSwitch/types.d.ts +29 -0
  181. package/dist/components/BbSwitchGroup/BbSwitchGroup.vue.d.ts +7 -190
  182. package/dist/components/BbSwitchGroup/types.d.ts +81 -0
  183. package/dist/components/BbTab/BbTab.vue.d.ts +9 -247
  184. package/dist/components/BbTab/types.d.ts +186 -0
  185. package/dist/components/BbTag/BbTag.vue.d.ts +6 -156
  186. package/dist/components/BbTag/types.d.ts +158 -0
  187. package/dist/components/BbTextInput/BbTextInput.vue.d.ts +10 -152
  188. package/dist/components/BbTextInput/types.d.ts +137 -0
  189. package/dist/components/BbTextarea/BbTextarea.vue.d.ts +10 -142
  190. package/dist/components/BbTextarea/types.d.ts +123 -0
  191. package/dist/components/BbToast/BbToast.vue.d.ts +2 -6
  192. package/dist/components/BbToast/types.d.ts +8 -0
  193. package/dist/components/BbTooltip/BbTooltip.vue.d.ts +8 -65
  194. package/dist/components/BbTooltip/types.d.ts +55 -0
  195. package/dist/components/BbTree/BbTree.vue.d.ts +2 -65
  196. package/dist/components/BbTree/types.d.ts +69 -0
  197. package/dist/components/{ChipsBox.vue.d.ts → ChipsBox/ChipsBox.vue.d.ts} +5 -6
  198. package/dist/components/ChipsBox/types.d.ts +14 -0
  199. package/dist/components/{ClearableButton.vue.d.ts → ClearableButton/ClearableButton.vue.d.ts} +2 -0
  200. package/dist/components/ClearableButton/types.d.ts +3 -0
  201. package/dist/components/{CommaBox.vue.d.ts → CommaBox/CommaBox.vue.d.ts} +5 -6
  202. package/dist/components/CommaBox/types.d.ts +14 -0
  203. package/dist/components/CommonInputInnerContainer/CommonInputInnerContainer.vue.d.ts +25 -0
  204. package/dist/components/CommonInputInnerContainer/types.d.ts +47 -0
  205. package/dist/components/CommonInputOuterContainer/CommonInputOuterContainer.vue.d.ts +17 -0
  206. package/dist/components/CommonInputOuterContainer/types.d.ts +16 -0
  207. package/dist/components/{CommonPopover.vue.d.ts → CommonPopover/CommonPopover.vue.d.ts} +5 -30
  208. package/dist/components/CommonPopover/types.d.ts +43 -0
  209. package/dist/components/{ErrorIcon.vue.d.ts → ErrorIcon/ErrorIcon.vue.d.ts} +2 -0
  210. package/dist/components/ErrorIcon/types.d.ts +3 -0
  211. package/dist/components/FlatListBox/types.d.ts +97 -0
  212. package/dist/components/GroupedListBox/types.d.ts +118 -0
  213. package/dist/components/ListBox/ListBox.vue.d.ts +30 -0
  214. package/dist/components/ListBox/types.d.ts +133 -0
  215. package/dist/components/OptionsContainer/OptionsContainer.vue.d.ts +13 -0
  216. package/dist/components/OptionsContainer/types.d.ts +96 -0
  217. package/dist/composables/useBbConfig.d.ts +1 -1
  218. package/dist/composables/useConfirm.d.ts +1 -1
  219. package/dist/index.css +1 -1
  220. package/dist/index.d.ts +18 -18
  221. package/dist/index109.js +9 -9
  222. package/dist/index110.js +50 -49
  223. package/dist/index114.js +1 -1
  224. package/dist/index118.js +1 -1
  225. package/dist/index122.js +1 -0
  226. package/dist/index124.js +4 -4
  227. package/dist/index126.js +13 -13
  228. package/dist/index132.js +22 -19
  229. package/dist/index134.js +1 -1
  230. package/dist/index136.js +5 -5
  231. package/dist/index138.js +1 -1
  232. package/dist/index14.js +1 -1
  233. package/dist/index140.js +18 -17
  234. package/dist/index144.js +1 -1
  235. package/dist/index146.js +2 -2
  236. package/dist/index149.js +2 -2
  237. package/dist/index16.js +3 -3
  238. package/dist/index18.js +3 -3
  239. package/dist/index20.js +70 -59
  240. package/dist/index22.js +14 -14
  241. package/dist/index221.js +138 -2
  242. package/dist/index222.js +2 -138
  243. package/dist/index224.js +5 -34
  244. package/dist/index225.js +7 -32
  245. package/dist/index226.js +32 -26
  246. package/dist/index227.js +7 -0
  247. package/dist/index228.js +5 -5
  248. package/dist/index229.js +5 -8
  249. package/dist/index230.js +5 -7
  250. package/dist/index231.js +3 -2
  251. package/dist/index232.js +2 -9
  252. package/dist/index233.js +6 -13
  253. package/dist/index234.js +8 -3
  254. package/dist/index235.js +268 -2
  255. package/dist/index236.js +52 -11
  256. package/dist/index237.js +50 -6
  257. package/dist/index238.js +32 -3
  258. package/dist/index239.js +60 -3
  259. package/dist/index24.js +10 -10
  260. package/dist/index240.js +13 -2
  261. package/dist/index241.js +187 -17
  262. package/dist/index242.js +3 -12
  263. package/dist/index243.js +2 -51
  264. package/dist/index244.js +2 -18
  265. package/dist/index245.js +2 -12
  266. package/dist/index246.js +12 -16
  267. package/dist/index247.js +11 -28
  268. package/dist/index248.js +48 -15
  269. package/dist/index249.js +17 -4
  270. package/dist/index250.js +2 -2
  271. package/dist/index252.js +2 -2
  272. package/dist/index254.js +3 -135
  273. package/dist/index255.js +4 -0
  274. package/dist/index256.js +4 -107
  275. package/dist/index257.js +19 -12
  276. package/dist/index258.js +6 -2
  277. package/dist/index259.js +16 -7
  278. package/dist/index26.js +3 -3
  279. package/dist/index260.js +86 -7
  280. package/dist/index262.js +32 -0
  281. package/dist/index263.js +18 -5
  282. package/dist/index264.js +12 -5
  283. package/dist/index265.js +18 -5
  284. package/dist/index266.js +2 -5
  285. package/dist/index267.js +7 -5
  286. package/dist/index268.js +7 -5
  287. package/dist/index269.js +3 -67
  288. package/dist/index270.js +4 -33
  289. package/dist/index271.js +5 -2
  290. package/dist/index272.js +5 -2
  291. package/dist/index273.js +5 -3
  292. package/dist/index274.js +135 -4
  293. package/dist/index276.js +9 -6
  294. package/dist/index277.js +7 -11
  295. package/dist/index278.js +23 -5
  296. package/dist/index279.js +3 -5
  297. package/dist/index28.js +57 -55
  298. package/dist/index280.js +21 -266
  299. package/dist/index281.js +364 -43
  300. package/dist/index283.js +32 -31
  301. package/dist/index284.js +3 -60
  302. package/dist/index285.js +25 -4
  303. package/dist/index286.js +3 -20
  304. package/dist/index287.js +18 -5
  305. package/dist/index288.js +12 -373
  306. package/dist/index289.js +109 -0
  307. package/dist/index290.js +11 -6
  308. package/dist/index291.js +66 -15
  309. package/dist/index292.js +32 -10
  310. package/dist/index294.js +5 -8
  311. package/dist/index295.js +9 -20
  312. package/dist/index296.js +2 -8
  313. package/dist/index297.js +9 -23
  314. package/dist/index298.js +52 -24
  315. package/dist/index299.js +5 -188
  316. package/dist/index30.js +3 -3
  317. package/dist/index300.js +21 -3
  318. package/dist/index301.js +28 -3
  319. package/dist/index303.js +9 -0
  320. package/dist/index304.js +2 -7
  321. package/dist/index305.js +280 -3
  322. package/dist/index306.js +2 -2
  323. package/dist/index307.js +16 -5
  324. package/dist/index308.js +2 -7
  325. package/dist/index309.js +16 -3
  326. package/dist/index310.js +2 -3
  327. package/dist/index311.js +27 -3
  328. package/dist/index312.js +2 -2
  329. package/dist/index313.js +2 -28
  330. package/dist/index314.js +2 -17
  331. package/dist/index315.js +2 -4
  332. package/dist/index316.js +1 -1
  333. package/dist/index317.js +28 -3
  334. package/dist/index318.js +2 -280
  335. package/dist/index319.js +7 -2
  336. package/dist/index32.js +2 -2
  337. package/dist/index320.js +719 -125
  338. package/dist/index321.js +366 -2
  339. package/dist/index322.js +56 -14
  340. package/dist/index323.js +4 -2
  341. package/dist/index324.js +3 -16
  342. package/dist/index325.js +17 -2
  343. package/dist/index326.js +3 -16
  344. package/dist/index327.js +3 -2
  345. package/dist/index328.js +3 -19
  346. package/dist/index329.js +3 -2
  347. package/dist/index330.js +120 -22
  348. package/dist/index331.js +2 -2
  349. package/dist/index332.js +15 -2
  350. package/dist/index333.js +2 -2
  351. package/dist/index334.js +19 -2
  352. package/dist/index335.js +2 -2
  353. package/dist/index336.js +5 -2
  354. package/dist/index337.js +5 -3
  355. package/dist/index338.js +2 -4
  356. package/dist/index339.js +4 -719
  357. package/dist/index34.js +8 -8
  358. package/dist/index340.js +2 -366
  359. package/dist/index341.js +3 -57
  360. package/dist/index342.js +3 -6
  361. package/dist/index343.js +6 -5
  362. package/dist/index344.js +6 -34
  363. package/dist/index345.js +17 -127
  364. package/dist/index346.js +7 -396
  365. package/dist/index347.js +14 -199
  366. package/dist/index348.js +5 -259
  367. package/dist/index349.js +6 -227
  368. package/dist/index352.js +35 -2
  369. package/dist/index353.js +129 -2
  370. package/dist/index354.js +378 -114
  371. package/dist/index355.js +92 -6
  372. package/dist/index356.js +226 -17
  373. package/dist/index357.js +22 -9
  374. package/dist/index359.js +7 -5
  375. package/dist/index36.js +4 -4
  376. package/dist/index360.js +200 -7
  377. package/dist/index361.js +255 -18
  378. package/dist/index362.js +136 -0
  379. package/dist/index363.js +2 -93
  380. package/dist/index364.js +2 -441
  381. package/dist/index365.js +427 -114
  382. package/dist/index366.js +127 -46
  383. package/dist/index367.js +44 -67
  384. package/dist/index368.js +66 -516
  385. package/dist/index369.js +515 -45
  386. package/dist/index370.js +52 -0
  387. package/dist/index38.js +133 -131
  388. package/dist/index40.js +8 -8
  389. package/dist/index42.js +2 -2
  390. package/dist/index44.js +16 -15
  391. package/dist/index46.js +4 -4
  392. package/dist/index50.js +28 -25
  393. package/dist/index54.js +1 -1
  394. package/dist/index56.js +1 -1
  395. package/dist/index58.js +2 -2
  396. package/dist/index60.js +2 -2
  397. package/dist/index62.js +5 -5
  398. package/dist/index66.js +3 -1
  399. package/dist/index68.js +1 -1
  400. package/dist/index74.js +4 -4
  401. package/dist/index82.js +6 -6
  402. package/dist/index84.js +1 -1
  403. package/dist/index86.js +2 -2
  404. package/dist/index88.js +3 -3
  405. package/dist/index90.js +1 -1
  406. package/dist/index93.js +3 -3
  407. package/dist/index95.js +2 -2
  408. package/dist/index97.js +5 -5
  409. package/dist/index99.js +1 -1
  410. package/dist/utilities/functions/parseSize.d.ts +1 -1
  411. package/package.json +5 -3
  412. package/dist/components/CommonInputInnerContainer.vue.d.ts +0 -81
  413. package/dist/components/CommonInputOuterContainer.vue.d.ts +0 -41
  414. package/dist/components/FlatListBox.vue.d.ts +0 -119
  415. package/dist/components/GroupedListBox.vue.d.ts +0 -153
  416. package/dist/components/ListBox.vue.d.ts +0 -170
  417. package/dist/components/OptionsContainer.vue.d.ts +0 -172
  418. package/dist/index261.js +0 -88
  419. package/dist/index275.js +0 -25
  420. package/dist/index282.js +0 -54
  421. package/dist/index293.js +0 -5
  422. package/dist/index302.js +0 -55
  423. package/dist/index358.js +0 -17
@@ -0,0 +1,1720 @@
1
+ # BaseSelect
2
+
3
+ ## Template & Script
4
+
5
+ ```vue
6
+ <template>
7
+ <CommonInputOuterContainer
8
+ ref="outerContainer"
9
+ :class="{
10
+ 'bb-base-select': true,
11
+ 'bb-base-select--active': active,
12
+ 'bb-base-select--shown': shown,
13
+ 'bb-base-select--loading': computedLoading,
14
+ 'bb-base-select--disabled': disabled,
15
+ 'bb-base-select--errors': hasErrors,
16
+ 'bb-base-select--readonly': readonly,
17
+ 'bb-base-select--compact': compact,
18
+ }"
19
+ @click="onOuterContainerClick"
20
+ >
21
+ <template #prepend-outer
22
+ ><slot name="prepend-outer" :query="query"></slot
23
+ ></template>
24
+ <span ref="innerContainer" class="bb-base-select__inner-wrapper">
25
+ <CommonInputInnerContainer
26
+ :append:icon="props['append:icon']"
27
+ :clearable="clearable && !isEmpty(modelValue)"
28
+ :prepend:icon="props['prepend:icon']"
29
+ :prevent-focus="true"
30
+ @click:clear="onClear"
31
+ >
32
+ <template #prepend
33
+ ><slot name="prepend" :query="query" :focus="focusInput"></slot
34
+ ></template>
35
+ <template #prefix><slot name="prefix" /></template>
36
+ <BbSmoothHeight tag="span">
37
+ <span class="bb-base-select__input-container">
38
+ <template
39
+ v-if="multiple && selectedOptions.length <= maxSelectedLabels"
40
+ >
41
+ <template v-if="comma">
42
+ <CommaBox
43
+ ref="commaBox"
44
+ :options="selectedOptions"
45
+ @option:unselected="onOptionUnselected"
46
+ />
47
+ </template>
48
+ <template v-else>
49
+ <ChipsBox
50
+ ref="chipsBox"
51
+ :options="selectedOptions"
52
+ @option:unselected="onOptionUnselected"
53
+ />
54
+ </template>
55
+ </template>
56
+ <span v-else-if="multiple" class="bb-base-select__max-reached">
57
+ {{
58
+ selectedLabelsFn
59
+ ? selectedLabelsFn(selectedOptions.length)
60
+ : t('select.multipleMaxReached', selectedOptions.length)
61
+ }}
62
+ </span>
63
+ <input
64
+ :id="id"
65
+ :key="`${mounted}`"
66
+ ref="input"
67
+ v-model="query"
68
+ :aria-activedescendant="shown ? activeDescendantId : undefined"
69
+ :aria-autocomplete="'list'"
70
+ :aria-controls="renderListBox ? `${id}_listbox` : undefined"
71
+ :aria-describedby="ariaDescribedby"
72
+ :aria-expanded="shown"
73
+ :autocomplete="autocomplete"
74
+ :autofocus="autofocus"
75
+ :class="'bb-base-select__text-input'"
76
+ :disabled="disabled"
77
+ :inputmode="inputmode"
78
+ :placeholder="computedPlaceholder"
79
+ :readonly="readonly || !allowWriting"
80
+ :required="required && (!multiple || !modelValue.length)"
81
+ role="combobox"
82
+ size="1"
83
+ :style="{ '--characters': query.length }"
84
+ :type="'text'"
85
+ @blur.stop="onInputBlur"
86
+ @change.stop="onInputChange"
87
+ @focus.once.stop="onInputFirstFocus"
88
+ @focus.stop="onInputFocus"
89
+ @input.stop="onInputInput"
90
+ @keydown.stop.delete="onBackspace"
91
+ @keydown.stop.left="onArrowLeft"
92
+ @keydown.stop.prevent.down="onArrowDown"
93
+ @keydown.stop.prevent.enter="onEnter"
94
+ @keydown.stop.prevent.esc="onEscape"
95
+ @keydown.stop.prevent.up="onArrowUp"
96
+ @keydown.stop.right="onArrowRight"
97
+ />
98
+ </span>
99
+ </BbSmoothHeight>
100
+ <slot
101
+ v-if="showChevron"
102
+ :loading="!!loading"
103
+ name="chevron"
104
+ :shown="shown"
105
+ >
106
+ <svg
107
+ class="bb-base-select__chevron"
108
+ viewBox="0 0 24 24"
109
+ xmlns="http://www.w3.org/2000/svg"
110
+ >
111
+ <path
112
+ d="M7.41 8.58L12 13.17l4.59-4.59L18 10l-6 6l-6-6z"
113
+ fill="currentColor"
114
+ />
115
+ </svg>
116
+ </slot>
117
+ <template #append
118
+ ><slot name="append" :query="query" :focus="focusInput"></slot
119
+ ></template>
120
+ <template #suffix><slot name="suffix" /></template>
121
+ </CommonInputInnerContainer>
122
+ </span>
123
+ <CommonPopover
124
+ v-model="shown"
125
+ :anchor="innerContainer"
126
+ :offset="4"
127
+ :transition-duration="transitionDuration"
128
+ >
129
+ <template v-if="shown">
130
+ <slot name="options:prepend:outer" :focus="focusInput" />
131
+ </template>
132
+ <ListBox
133
+ ref="optionsContainer"
134
+ :compact="compact"
135
+ :loading="computedLoading"
136
+ :loading-text="loadingText"
137
+ :multiple="multiple"
138
+ :no-data-text="noDataText"
139
+ :open="shown"
140
+ :options="groupBy ? undefined : filteredOptions"
141
+ :groups="groupBy ? groupedOptions : undefined"
142
+ :header-height="headerHeight"
143
+ :style="optionsContainerStyles"
144
+ :option-height="itemHeight"
145
+ @focused:change="onListboxFocusedChange"
146
+ @option:selected="onOptionSelected"
147
+ @option:unselected="onOptionUnselected"
148
+ >
149
+ <template #options:prepend
150
+ ><slot v-if="shown" name="options:prepend" :focus="focusInput"
151
+ /></template>
152
+ <template #loading><slot name="loading" :query="query" /></template>
153
+ <template #no-data
154
+ ><slot name="no-data" :query="query" :focus="focusInput"
155
+ /></template>
156
+ <template #options:append
157
+ ><slot v-if="shown" name="options:append" :focus="focusInput"
158
+ /></template>
159
+ <template #option="data"
160
+ ><slot
161
+ :has-errors="hasErrors"
162
+ :loading="computedLoading"
163
+ name="option"
164
+ v-bind="data"
165
+ /></template>
166
+ <template #group="data"><slot name="group" v-bind="data" /></template>
167
+ </ListBox>
168
+ <template v-if="shown">
169
+ <slot name="options:append:outer" :focus="focusInput" />
170
+ </template>
171
+ </CommonPopover>
172
+ <template #append-outer
173
+ ><slot name="append-outer" :query="query"></slot
174
+ ></template>
175
+ <input v-for="input in hiddenInputs" :key="input.value" v-bind="input" />
176
+ </CommonInputOuterContainer>
177
+ </template>
178
+
179
+ <script setup lang="ts" generic="Item = any">
180
+ import BbSmoothHeight from '../BbSmoothHeight/BbSmoothHeight.vue';
181
+ import { computed, ref, nextTick } from 'vue';
182
+ import { hash } from '@/utilities/functions/hash';
183
+ import { isEmpty } from '@/utilities/functions/empty';
184
+ import { last } from '@/utilities/functions/last';
185
+ import { matchAnyKey } from '@/utilities/functions/matchAnyKey';
186
+ import { toRef } from 'vue';
187
+ import { useArray } from '@/composables/useArray';
188
+ import { useBaseOptions } from '@/composables/useBaseOptions';
189
+ import { useCoherence } from '@/composables/useCoherence';
190
+ import { useHashedWatcher } from '@/composables/useHashedWatcher';
191
+ import { useId } from '@/composables/useId';
192
+ import { useIndexById } from '@/composables/useIndexById';
193
+ import { useElementSize, useIntersectionObserver } from '@vueuse/core';
194
+ import { useItemsGetter } from '@/composables/useItemsGetter';
195
+ import { useLocale } from '@/composables/useLocale';
196
+ import { useMobile } from '@/composables/useMobile';
197
+ import { useMounted } from '@vueuse/core';
198
+ import { usePrefill } from '@/composables/usePrefill';
199
+ import { wait } from '@/utilities/functions/wait';
200
+ import { when } from '@/utilities/functions/when';
201
+ import ChipsBox from '../ChipsBox/ChipsBox.vue';
202
+ import CommaBox from '../CommaBox/CommaBox.vue';
203
+ import CommonInputInnerContainer from '../CommonInputInnerContainer/CommonInputInnerContainer.vue';
204
+ import CommonInputOuterContainer from '../CommonInputOuterContainer/CommonInputOuterContainer.vue';
205
+ import CommonPopover from '../CommonPopover/CommonPopover.vue';
206
+ import ListBox from '../ListBox/ListBox.vue';
207
+ import type {
208
+ BaseSelectProps,
209
+ BaseSelectEvents,
210
+ BaseSelectSlots,
211
+ } from './types';
212
+ import type { Option as BaseOption, GroupedOptions } from '@/types/Option';
213
+ import { useUntil } from '@/composables/useUntil';
214
+ import type { groupBy } from '@/utilities/functions/groupBy';
215
+ import { isNil } from '@/utilities/functions/isNil';
216
+ import { get } from '@/utilities/functions/get';
217
+ import { useLogger } from '@/composables/useLogger';
218
+
219
+ const props = withDefaults(defineProps<BaseSelectProps<Item>>(), {
220
+ allowWriting: true,
221
+ autocomplete: 'off',
222
+ depsDebounceTime: 0,
223
+ dependencies: () => [],
224
+ filterBy: () => [],
225
+ max: Infinity,
226
+ maxSelectedLabels: Infinity,
227
+ modelValueDebounceTime: 0,
228
+ prefill: 'focus',
229
+ queryDebounceTime: 500,
230
+ showChevron: true,
231
+ transitionDuration: 300,
232
+ updateOnAnimationFrame: false,
233
+ });
234
+
235
+ const emit = defineEmits<BaseSelectEvents>();
236
+ const logger = useLogger();
237
+
238
+ defineSlots<BaseSelectSlots<Item>>();
239
+
240
+ if (props.multiple && !Array.isArray(props.modelValue)) {
241
+ logger.throw(
242
+ 'BaseSelect: multiple is set to "true" but modelValue is not an array.'
243
+ );
244
+ }
245
+
246
+ const { t } = useLocale();
247
+ const mounted = useMounted();
248
+ /**
249
+ * START ELEMENT REFERENCES
250
+ */
251
+ const outerContainer = ref<InstanceType<
252
+ typeof CommonInputOuterContainer
253
+ > | null>(null);
254
+ const innerContainer = ref<HTMLElement | null>(null);
255
+ const optionsContainer = ref<any | null>(null);
256
+ const commaBox = ref<InstanceType<typeof CommaBox> | null>(null);
257
+ const chipsBox = ref<InstanceType<typeof ChipsBox> | null>(null);
258
+ const selectedBox = computed(() =>
259
+ props.comma ? commaBox.value : chipsBox.value
260
+ );
261
+ const { width: containerWidth } = useElementSize(innerContainer);
262
+ /**
263
+ * END ELEMENT REFERENCES
264
+ */
265
+
266
+ const { isMobile } = useMobile();
267
+ const inputmode = computed(() =>
268
+ props.allowWriting === 'not-mobile' && isMobile.value ? 'none' : undefined
269
+ );
270
+
271
+ // Always provide an id so that inputs can be focussed by clicking in the label
272
+ const id = props.id || useId().id.value;
273
+
274
+ const { resume, pause } = useIntersectionObserver(
275
+ innerContainer,
276
+ async ([{ intersectionRatio }]) => {
277
+ if (intersectionRatio !== 1 && shown.value) {
278
+ await close();
279
+ }
280
+ },
281
+ { threshold: [0, 1], immediate: false }
282
+ );
283
+
284
+ const optionsContainerStyles = computed(() => ({
285
+ width: `${containerWidth.value ?? 0}px`,
286
+ }));
287
+
288
+ /**
289
+ * START INPUT HANDLING
290
+ */
291
+ const input = ref<HTMLElement | null>(null);
292
+ const activeDescendantId = ref<string>();
293
+ const focusInput = () => {
294
+ if (input.value instanceof HTMLInputElement) {
295
+ input.value.focus();
296
+ }
297
+ };
298
+
299
+ /**
300
+ * When the focus goes to the input we select the current text
301
+ * so the user can replace or delete it.
302
+ * On top of that if the prefill strategy is to prefill on first focus and options
303
+ * weren't already retrieved by the watcher on mount, we do that
304
+ */
305
+ const onInputFocus = async (event: FocusEvent) => {
306
+ emit('focus', event);
307
+ setActive();
308
+ document.addEventListener('click', onOutsideInteraction);
309
+ document.addEventListener('focusin', onOutsideInteraction);
310
+ };
311
+
312
+ const onInputFirstFocus = () => {
313
+ if (props.prefill === 'focus' && !isPrefilling.value && !hasPrefilled.value) {
314
+ prefillItems();
315
+ }
316
+ };
317
+
318
+ const onInputBlur = async (event: FocusEvent) => {
319
+ emit('blur', event);
320
+ };
321
+
322
+ const onInputChange = (event: Event) => emit('change', event);
323
+
324
+ /**
325
+ * Search at every input by the user.
326
+ * When the user deletes the query unselect the current option
327
+ */
328
+ const onInputInput = (event: Event) => {
329
+ emit('input', event);
330
+ if (query.value === '') {
331
+ if (!props.multiple) {
332
+ emit('update:modelValue', null);
333
+ }
334
+ }
335
+ selectedBox.value?.blur();
336
+ if (hidden.value) {
337
+ open();
338
+ }
339
+ debouncedGetter(query.value, false, props.modelValue);
340
+ };
341
+
342
+ const onListboxFocusedChange = (id: string | undefined) => {
343
+ activeDescendantId.value = id;
344
+ };
345
+
346
+ /**
347
+ * On click outside of the container close the panel, remove active state.
348
+ * In multiple selection clear query after a timeout
349
+ */
350
+ const onOutsideInteraction = async (event: Event) => {
351
+ if (event.target instanceof Node) {
352
+ if (outerContainer.value) {
353
+ if (
354
+ !outerContainer.value.$el.contains(event.target) &&
355
+ !optionsContainer.value?.$el?.contains(event.target)
356
+ ) {
357
+ close();
358
+ setInactive();
359
+ document.removeEventListener('click', onOutsideInteraction);
360
+ document.removeEventListener('focusin', onOutsideInteraction);
361
+ await wait(props.transitionDuration);
362
+ alignQueryToState();
363
+ return;
364
+ }
365
+ }
366
+ }
367
+ };
368
+
369
+ const canProcessKeyboardBindings = computed(() => {
370
+ if (props.readonly) return false;
371
+ if (props.disabled) return false;
372
+ if (computedLoading.value) return false;
373
+ if (
374
+ !selectedBox.value &&
375
+ props.multiple &&
376
+ selectedOptions.value.length <= props.maxSelectedLabels
377
+ )
378
+ return false;
379
+ return true;
380
+ });
381
+
382
+ /**
383
+ * On arrow prevent the page from scrolling.
384
+ * Reset horizontal focus
385
+ * When the panel is open
386
+ * - Focus on the previous option
387
+ * When the panel is closed
388
+ * - focus on the first selected option
389
+ */
390
+ const onArrowUp = async () => {
391
+ if (!canProcessKeyboardBindings.value) return;
392
+ // Reset horizontal focus while moving vertically
393
+ selectedBox.value?.blur();
394
+ if (shown.value) {
395
+ optionsContainer.value?.focusPrevious();
396
+ } else {
397
+ await open();
398
+ await wait(props.transitionDuration);
399
+ optionsContainer.value?.focusLastSelected();
400
+ }
401
+ };
402
+
403
+ const onArrowDown = async () => {
404
+ if (!canProcessKeyboardBindings.value) return;
405
+ // Reset horizontal focus while moving vertically
406
+ selectedBox.value?.blur();
407
+ if (shown.value) {
408
+ optionsContainer.value?.focusNext();
409
+ } else {
410
+ await open();
411
+ await wait(props.transitionDuration);
412
+ optionsContainer.value?.focusFirstSelected();
413
+ }
414
+ };
415
+
416
+ const onArrowLeft = (event: KeyboardEvent) => {
417
+ if (!canProcessKeyboardBindings.value) return;
418
+ if (!props.multiple || query.value) return;
419
+
420
+ event.preventDefault();
421
+ // Reset vertical focus while moving horizontally
422
+ optionsContainer.value?.blur();
423
+ if (!selectedOptions.value.length) return;
424
+ selectedBox.value?.focusPrevious();
425
+ const highlightedOption = selectedBox.value?.getHighlighted();
426
+ if (highlightedOption) {
427
+ optionsContainer.value?.focusByHash(highlightedOption.valueHash);
428
+ }
429
+ };
430
+
431
+ const onArrowRight = (event: KeyboardEvent) => {
432
+ if (!canProcessKeyboardBindings.value) return;
433
+ if (!props.multiple || query.value) return;
434
+ event.preventDefault();
435
+ // Reset vertical focus while moving horizontally
436
+ optionsContainer.value?.blur();
437
+ if (!selectedOptions.value.length) return;
438
+ selectedBox.value?.focusNext();
439
+ const highlightedOption = selectedBox.value?.getHighlighted();
440
+ if (highlightedOption) {
441
+ optionsContainer.value?.focusByHash(highlightedOption.valueHash);
442
+ }
443
+ };
444
+
445
+ const onEnter = async () => {
446
+ if (!canProcessKeyboardBindings.value) {
447
+ return;
448
+ }
449
+ if (!shown.value) {
450
+ await open();
451
+ await wait(props.transitionDuration);
452
+ if (selectedOptions.value.length) {
453
+ optionsContainer.value?.focusFirstSelected();
454
+ }
455
+ return;
456
+ } else if (optionsContainer.value?.getHighlighted()) {
457
+ optionsContainer.value.confirmOption();
458
+ return;
459
+ }
460
+ const text = query.value.trim();
461
+ // Do not add manual items that are already present
462
+ if (isItemSelected(text)) return;
463
+ emit('option:add', text);
464
+ query.value = '';
465
+ };
466
+
467
+ const onEscape = async () => {
468
+ if (shown.value) {
469
+ await close();
470
+ }
471
+ };
472
+
473
+ /**
474
+ * Delete behavior is different when query is empty
475
+ * If query is empty
476
+ * If no chip is selected - select rightmost chip
477
+ * If a chip is selected - deselect that option
478
+ * If any option remains move focus to that or reset
479
+ */
480
+ const onBackspace = async () => {
481
+ if (
482
+ !canProcessKeyboardBindings.value ||
483
+ query.value ||
484
+ !selectedOptions.value.length
485
+ ) {
486
+ return;
487
+ }
488
+ if (selectedBox.value?.getHighlighted()) {
489
+ selectedBox.value.confirmOption();
490
+ }
491
+ await nextTick();
492
+ selectedBox.value?.focusPrevious();
493
+ };
494
+
495
+ const query = ref<string>('');
496
+
497
+ const {
498
+ getter,
499
+ debouncedGetter,
500
+ items: internalItems,
501
+ loading,
502
+ } = useItemsGetter({
503
+ items: toRef(props, 'items'),
504
+ debounce: props.queryDebounceTime,
505
+ });
506
+
507
+ const {
508
+ array: innerStash,
509
+ add: addToStash,
510
+ remove: removeFromStash,
511
+ set: setStash,
512
+ } = useArray<BaseOption>();
513
+
514
+ const {
515
+ hasPrefilled,
516
+ isPrefilling,
517
+ prefill: prefillItems,
518
+ } = usePrefill({
519
+ trigger: props.prefill === true,
520
+ currentValue: props.modelValue,
521
+ multiple: props.multiple,
522
+ fn: async (isPrefill) => {
523
+ await getter(query.value, isPrefill, props.modelValue);
524
+ if (props.stash) {
525
+ addToStash(...options.value.map((o) => o.item));
526
+ }
527
+ alignQueryToState();
528
+ },
529
+ });
530
+
531
+ const { data: modelValueIndexedByHash, get: isItemSelected } = useIndexById({
532
+ // Force model value to be an array
533
+ items: computed(() => [].concat(props.modelValue)),
534
+ });
535
+
536
+ const { options } = useBaseOptions({
537
+ disabled: toRef(props, 'disabled'),
538
+ items: computed(() => [...internalItems.value, ...innerStash.value]),
539
+ itemText: props.itemText,
540
+ itemValue: props.itemValue,
541
+ max: props.max,
542
+ selectable: true,
543
+ selectedIndexedByHash: modelValueIndexedByHash,
544
+ });
545
+
546
+ const { data: optionsIndexedByHash } = useIndexById({
547
+ items: options,
548
+ key: 'valueHash',
549
+ });
550
+
551
+ const { coherent, coherentValue } = useCoherence({
552
+ modelValue: toRef(props, 'modelValue'),
553
+ multiple: props.multiple,
554
+ iteratee: (item) => !!optionsIndexedByHash.value[hash(item)],
555
+ });
556
+
557
+ // 6. Selected options — resolved in modelValue order so chips stay stable
558
+ const selectedOptions = computed<BaseOption[]>(() =>
559
+ ([] as any[])
560
+ .concat(props.modelValue)
561
+ .map((v) => optionsIndexedByHash.value[hash(v)])
562
+ .filter(Boolean)
563
+ );
564
+
565
+ const computedLoading = computed(() => !!(loading.value || props.loading));
566
+
567
+ /**
568
+ * If multiple watchers are running we don't want to run the coherence watcher
569
+ * multiple times we only run it the last time
570
+ */
571
+ useHashedWatcher(
572
+ () => props.modelValue,
573
+ async () => {
574
+ if (!coherent.value) {
575
+ await getter(query.value, true, props.modelValue);
576
+ if (props.enforceCoherence) {
577
+ emit('update:modelValue', coherentValue.value);
578
+ selectedBox.value?.blur();
579
+ optionsContainer.value?.blur();
580
+ }
581
+ }
582
+ alignQueryToState();
583
+ },
584
+ { debounce: props.modelValueDebounceTime }
585
+ );
586
+ useHashedWatcher(
587
+ () => [props.dependencies, props.items],
588
+ async () => {
589
+ if (!hasPrefilled.value) return;
590
+ await getter(query.value, true, props.modelValue);
591
+ if (props.enforceCoherence && !coherent.value) {
592
+ emit('update:modelValue', coherentValue.value);
593
+ selectedBox.value?.blur();
594
+ optionsContainer.value?.blur();
595
+ }
596
+ alignQueryToState();
597
+ },
598
+ { debounce: props.depsDebounceTime }
599
+ );
600
+
601
+ const alignQueryToState = () => {
602
+ if (props.multiple) {
603
+ query.value = '';
604
+ return;
605
+ }
606
+ let option: BaseOption | undefined;
607
+ if (selectedOptions.value) {
608
+ option = last(selectedOptions.value);
609
+ }
610
+ query.value = option?.text || '';
611
+ };
612
+
613
+ const computedPlaceholder = computed(() => {
614
+ if (selectedOptions.value.length) return '';
615
+ else return props.placeholder;
616
+ });
617
+
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
+ alignQueryToState();
625
+ } else {
626
+ if (props.stash) {
627
+ setStash(option.item);
628
+ }
629
+ emit('update:modelValue', option.value);
630
+ await nextTick();
631
+ alignQueryToState();
632
+ }
633
+ focusInput();
634
+ if (!props.multiple) {
635
+ close();
636
+ }
637
+ };
638
+
639
+ const onOptionUnselected = async (option: BaseOption) => {
640
+ removeFromStash((o) => o.valueHash !== option.valueHash);
641
+ if (props.multiple) {
642
+ const copy = { ...modelValueIndexedByHash.value };
643
+ delete copy[option.valueHash];
644
+ emit('update:modelValue', Object.values(copy));
645
+ } else {
646
+ emit('update:modelValue', null);
647
+ await nextTick();
648
+ alignQueryToState();
649
+ }
650
+ focusInput();
651
+ };
652
+
653
+ /**
654
+ * Filter options to be displayed based on the current query.
655
+ * If no query is used or when query is set from the inside (after a selection) display all possible options
656
+ */
657
+ const filteredOptions = computed<BaseOption<Item>[]>(() => {
658
+ /** Only filter when a value is being searched not when the query is fully set on a selected option text */
659
+ const queryMatchesASelectedOption = selectedOptions.value.some(
660
+ (option: BaseOption) => option.text === query.value
661
+ );
662
+ const shouldFilter =
663
+ (props.multiple && query.value) ||
664
+ (props.filterBy === 'not_stashed' && query.value) ||
665
+ (query.value && !queryMatchesASelectedOption && !props.multiple);
666
+
667
+ if (!shouldFilter || !props.filterBy) return options.value;
668
+
669
+ // Build the stash lookup once, outside the loop — not per item.
670
+ const stashedHashes =
671
+ props.filterBy === 'not_stashed'
672
+ ? new Set(innerStash.value.map((o) => o.valueHash))
673
+ : null;
674
+
675
+ return options.value.filter((item: BaseOption) => {
676
+ let matchedAnything = false;
677
+ if (typeof props.filterBy === 'function') {
678
+ // Custom function is an extra matcher, not a replacement for the text
679
+ // match — consistent with the string/array filterBy modes.
680
+ matchedAnything = props.filterBy(item.value, item.item, query.value);
681
+ } else if (props.filterBy === 'not_stashed' && query.value) {
682
+ matchedAnything = !stashedHashes!.has(item.valueHash);
683
+ } else if (Array.isArray(props.filterBy) && props.filterBy.length) {
684
+ matchedAnything = matchAnyKey(
685
+ item.item,
686
+ props.filterBy,
687
+ query.value.trim()
688
+ );
689
+ }
690
+ return matchedAnything || matchAnyKey(item, ['text'], query.value.trim());
691
+ });
692
+ });
693
+
694
+ const defaultGroupSymbol = Symbol('default');
695
+
696
+ const getGroupData = (option: BaseOption) => {
697
+ if (isNil(props.groupBy)) return defaultGroupSymbol;
698
+ if (typeof props.groupBy === 'function') return props.groupBy(option.item);
699
+ return (get as any)(option.item, props.groupBy);
700
+ };
701
+
702
+ const groupedOptions = computed<GroupedOptions[]>(() => {
703
+ const groupIndex: Record<GroupedOptions['id'], GroupedOptions> = {};
704
+ for (const option of filteredOptions.value) {
705
+ const groupData = getGroupData(option);
706
+ const groupId = hash(groupData);
707
+ if (!groupIndex[groupId]) {
708
+ groupIndex[groupId] = {
709
+ id: groupId,
710
+ data: groupData ?? null,
711
+ options: [],
712
+ };
713
+ }
714
+ groupIndex[groupId].options.push(option);
715
+ }
716
+ return Object.values(groupIndex).filter((g) => g.options.length);
717
+ });
718
+
719
+ /**
720
+ * We need the transitions because elements must be hidden and shown
721
+ * to accessibility tools when they are fully closed or fully open,
722
+ * while still being animated for sighted users.
723
+ */
724
+
725
+ const shown = ref(false);
726
+ const hidden = ref(true);
727
+ const renderListBox = useUntil(shown);
728
+
729
+ const open = async () => {
730
+ resume();
731
+ hidden.value = false;
732
+ shown.value = true;
733
+ };
734
+
735
+ const close = async () => {
736
+ shown.value = false;
737
+ hidden.value = true;
738
+ activeDescendantId.value = undefined;
739
+ selectedBox.value?.blur();
740
+ pause();
741
+ };
742
+
743
+ const toggle = () => {
744
+ if (shown.value) return close();
745
+ return open();
746
+ };
747
+
748
+ /**
749
+ * Applies a class when the user is inside this whole component.
750
+ * We cannot use focus within as it doesn't work for elements that are teleported.
751
+ * Also we cannot use the <input/> if we physically move focus to the options so
752
+ * we track it manually.
753
+ */
754
+ const active = ref(false);
755
+
756
+ const setActive = () => {
757
+ active.value = true;
758
+ };
759
+ const setInactive = () => {
760
+ active.value = false;
761
+ emit('inactive');
762
+ };
763
+
764
+ /**
765
+ * When clicking on the outside container seamlessly move focus to the input and open the panel
766
+ */
767
+ const onOuterContainerClick = (event: MouseEvent) => {
768
+ event.preventDefault();
769
+ emit('click', event);
770
+ if (props.disabled || props.readonly) return;
771
+ focusInput();
772
+ toggle();
773
+ };
774
+
775
+ /**
776
+ * When using this component for submission we add a bunch of hidden
777
+ * inputs so the submitted inputs are on par with v-model
778
+ */
779
+ /**
780
+ * This is used to keep the value compatible to common html expected values.
781
+ * Convert to string everything that's not but do not double encode strings
782
+ */
783
+ const makeInputValue = when(
784
+ (item: unknown) => typeof item !== 'string',
785
+ JSON.stringify
786
+ );
787
+
788
+ const hiddenInputs = computed(() => {
789
+ return [].concat(props.modelValue).map((current) => {
790
+ const value = makeInputValue(current);
791
+ return {
792
+ disabled: props.disabled,
793
+ name: props.name,
794
+ type: 'hidden',
795
+ value: value,
796
+ };
797
+ });
798
+ });
799
+
800
+ const onClear = () => {
801
+ let value = null;
802
+ if (props.multiple) {
803
+ value = [];
804
+ }
805
+ emit('update:modelValue', value);
806
+ };
807
+ </script>
808
+ <style lang="postcss">
809
+ @import './index.css';
810
+ </style>
811
+ ```
812
+
813
+ ## Types
814
+
815
+ ```ts
816
+ import type { HTMLAttributes, InputHTMLAttributes } from 'vue';
817
+ import type { IconType } from '@/types/Icon';
818
+
819
+ export type BaseSelectProps<Item = any> = {
820
+ /**
821
+ * Controls whether manual typing is allowed in the input field.
822
+ * Use `'not-mobile'` to disable typing on mobile while keeping it on desktop.
823
+ * @defaultValue `true`
824
+ */
825
+ allowWriting?: boolean | 'not-mobile';
826
+
827
+ /**
828
+ * Name of the icon to render at the right hand side of the input.
829
+ */
830
+ // eslint-disable-next-line vue/prop-name-casing
831
+ 'append:icon'?: IconType;
832
+
833
+ /**
834
+ * Id(s) of elements describing this select for assistive technologies.
835
+ */
836
+ ariaDescribedby?: InputHTMLAttributes['aria-describedby'];
837
+
838
+ /**
839
+ * Browser autocomplete hint for the input field.
840
+ * @defaultValue `'off'`
841
+ */
842
+ autocomplete?: InputHTMLAttributes['autocomplete'];
843
+
844
+ /**
845
+ * Focus the input automatically on mount.
846
+ */
847
+ autofocus?: InputHTMLAttributes['autofocus'];
848
+
849
+ /**
850
+ * Show a clear button whenever a value is present and the control is interactive.
851
+ */
852
+ clearable?: boolean;
853
+
854
+ /**
855
+ * Display selected values as a comma-separated string instead of individual chips.
856
+ * When enabled, options cannot be deselected by clicking individual chips.
857
+ */
858
+ comma?: boolean;
859
+
860
+ /**
861
+ * Apply the compact density variant.
862
+ */
863
+ compact?: boolean;
864
+
865
+ /**
866
+ * Additional dependencies that trigger item reloading when changed.
867
+ * @defaultValue `[]`
868
+ */
869
+ dependencies?: any[];
870
+
871
+ /**
872
+ * Debounce delay (ms) for dependency-triggered reloads.
873
+ * @defaultValue `0`
874
+ */
875
+ depsDebounceTime?: number;
876
+
877
+ /**
878
+ * Disables the component.
879
+ */
880
+ disabled?: boolean;
881
+
882
+ /**
883
+ * Reset modelValue to `null` or empty array if it no longer matches available items (enforces coherence).
884
+ * For example, prevents setting v-model to a user not present in the items array.
885
+ */
886
+ enforceCoherence?: boolean;
887
+
888
+ /**
889
+ * Controls how options are filtered during search.
890
+ * Options are always filtered by display text, but can also match additional properties
891
+ * when set to a string path, array of paths, or custom function.
892
+ * Set to `false` to disable filtering, or `'not_stashed'` to exclude stashed items.
893
+ * @defaultValue `() => []`
894
+ */
895
+ filterBy?:
896
+ | string
897
+ | string[]
898
+ | false
899
+ | 'not_stashed'
900
+ | ((value: any, item: any, query: string | null) => boolean)
901
+ | null;
902
+
903
+ /**
904
+ * Path or function used to group options. When set, options are organized into
905
+ * collapsible group headers in the dropdown.
906
+ */
907
+ groupBy?: string | ((item: Item) => string | number | symbol);
908
+
909
+ /**
910
+ * Height of group headers in the listbox (px). Defaults to 24px (compact) or 32px.
911
+ * Only applies when `groupBy` is set.
912
+ */
913
+ headerHeight?: number;
914
+
915
+ /**
916
+ * Apply error styling to the select.
917
+ */
918
+ hasErrors?: boolean;
919
+
920
+ /**
921
+ * Explicit id for the input element. Used to generate ids for listbox and options.
922
+ */
923
+ id?: HTMLAttributes['id'];
924
+
925
+ /**
926
+ * Array of items or function to load them asynchronously.
927
+ * Functions receive `(query, prefill, modelValue)` and can return a promise.
928
+ * Please check out {@link https://ui-components-docs.vercel.app/it/guides/fetch-data | the docs} for more information.
929
+ * @defaultValue `[]`
930
+ */
931
+ items:
932
+ | Item[]
933
+ | ((query: string, prefill: boolean, modelValue: any[]) => Promise<Item[]>)
934
+ | ((query: string, prefill: boolean, modelValue: any[]) => Item[]);
935
+
936
+ /**
937
+ * Height of the options in the listbox (px). Necessary for option virtualization.
938
+ * @defaultValue `40`
939
+ */
940
+ itemHeight?: number;
941
+
942
+ /**
943
+ * Path to item property for display text or function to extract it.
944
+ */
945
+ itemText?: string | ((item: Item) => string) | undefined;
946
+
947
+ /**
948
+ * Defines a path that returns a property of the object to use as value or a function that returns any value.
949
+ */
950
+ itemValue?: string | ((item: Item) => string) | undefined;
951
+
952
+ /**
953
+ * Display the loading state styles.
954
+ */
955
+ loading?: boolean;
956
+
957
+ /**
958
+ * Message shown while items are being loaded.
959
+ */
960
+ loadingText?: string;
961
+
962
+ /**
963
+ * Maximum number of selectable items (limits selection when `multiple` is true).
964
+ * @defaultValue `Infinity`
965
+ */
966
+ max?: number;
967
+
968
+ /**
969
+ * Maximum number of selected items to show as individual labels before collapsing.
970
+ * @defaultValue `Infinity`
971
+ */
972
+ maxSelectedLabels?: number;
973
+
974
+ /**
975
+ * v-model value. Single value for single select, array for multiple select.
976
+ */
977
+ modelValue: any;
978
+
979
+ /**
980
+ * Debounce delay (ms) for modelValue change handling.
981
+ * @defaultValue `0`
982
+ */
983
+ modelValueDebounceTime?: number;
984
+
985
+ /**
986
+ * Enable multiple item selection. When true, modelValue must be an array.
987
+ */
988
+ multiple?: boolean;
989
+
990
+ /**
991
+ * Name attribute forwarded to the input element.
992
+ */
993
+ name?: InputHTMLAttributes['name'];
994
+
995
+ /**
996
+ * Message displayed when no items are available.
997
+ */
998
+ noDataText?: string;
999
+
1000
+ /**
1001
+ * Placeholder text when no value is selected.
1002
+ */
1003
+ placeholder?: InputHTMLAttributes['placeholder'];
1004
+
1005
+ /**
1006
+ * Controls when items are pre-loaded.
1007
+ * `'focus'` loads on first focus, `true` loads immediately, `false` loads only on search.
1008
+ * @defaultValue `'focus'`
1009
+ */
1010
+ prefill?: boolean | 'focus';
1011
+
1012
+ /**
1013
+ * Name of the icon to render at the left hand side of the input.
1014
+ */
1015
+ // eslint-disable-next-line vue/prop-name-casing
1016
+ 'prepend:icon'?: IconType;
1017
+
1018
+ /**
1019
+ * Debounce delay (ms) before triggering search queries after user input stops.
1020
+ * @defaultValue `500`
1021
+ */
1022
+ queryDebounceTime?: number;
1023
+
1024
+ /**
1025
+ * Make the input read-only while keeping the dropdown accessible.
1026
+ */
1027
+ readonly?: boolean;
1028
+
1029
+ /**
1030
+ * Mark the input as required for form validation.
1031
+ */
1032
+ required?: boolean;
1033
+
1034
+ /**
1035
+ * Show the dropdown chevron icon.
1036
+ * @defaultValue `true`
1037
+ */
1038
+ showChevron?: boolean;
1039
+
1040
+ /**
1041
+ * Accumulate selected items across searches instead of replacing them.
1042
+ * Useful when searching large databases where selections should persist.
1043
+ */
1044
+ stash?: boolean;
1045
+
1046
+ /**
1047
+ * Function to generate a summary label when selected items exceed `maxSelectedLabels`.
1048
+ * Receives the total count and returns display text.
1049
+ */
1050
+ selectedLabelsFn?: (count: number) => string;
1051
+
1052
+ /**
1053
+ * Transition duration (ms) for dropdown show/hide animations.
1054
+ * @defaultValue `300`
1055
+ */
1056
+ transitionDuration?: number;
1057
+
1058
+ /**
1059
+ * Force dropdown repositioning on every animation frame (expensive, use sparingly).
1060
+ * @defaultValue `false`
1061
+ */
1062
+ updateOnAnimationFrame?: boolean;
1063
+ };
1064
+
1065
+ export type BaseSelectEvents = {
1066
+ /**
1067
+ * Emitted when the search input loses focus.
1068
+ * Forwards the original DOM `FocusEvent`.
1069
+ */
1070
+ (e: 'blur', event: FocusEvent): void;
1071
+ /**
1072
+ * Emitted when the input fires a change event.
1073
+ * Forwards the original DOM `Event`.
1074
+ */
1075
+ (e: 'change', event: Event): void;
1076
+ /**
1077
+ * Emitted when the input receives a click interaction.
1078
+ * Forwards the original DOM `MouseEvent`.
1079
+ */
1080
+ (e: 'click', event: MouseEvent): void;
1081
+ /**
1082
+ * Emitted when the search input gains focus.
1083
+ * Forwards the original DOM `FocusEvent`.
1084
+ */
1085
+ (e: 'focus', event: FocusEvent): void;
1086
+ /**
1087
+ * Emitted when focus/click moves outside the component after it was active.
1088
+ */
1089
+ (e: 'inactive'): void;
1090
+ /**
1091
+ * Emitted on native input events from the search field.
1092
+ * Forwards the original DOM `Event`.
1093
+ */
1094
+ (e: 'input', event: Event): void;
1095
+ /**
1096
+ * Emitted with the new selected value(s) whenever the selection changes.
1097
+ * Single value for single-select, array for multiple-select.
1098
+ */
1099
+ (e: 'update:modelValue', value: any): void;
1100
+ /**
1101
+ * Emitted when the user confirms a manually typed string that does not match any option.
1102
+ * Useful for "add new" patterns.
1103
+ */
1104
+ (e: 'option:add', text: string): void;
1105
+ };
1106
+
1107
+ /**
1108
+ * Props exposed by slots that receive the current search query and a focus callback
1109
+ * (`append`, `prepend`, `no-data`).
1110
+ */
1111
+ export type BaseSelectQueryFocusSlotProps = {
1112
+ /**
1113
+ * The current text typed in the search input.
1114
+ */
1115
+ query: string;
1116
+ /**
1117
+ * Focuses the search input.
1118
+ */
1119
+ focus: () => void;
1120
+ };
1121
+
1122
+ /**
1123
+ * Props exposed by slots that receive only the current search query
1124
+ * (`append-outer`, `prepend-outer`, `loading`).
1125
+ */
1126
+ export type BaseSelectQueryOnlySlotProps = {
1127
+ /**
1128
+ * The current text typed in the search input.
1129
+ */
1130
+ query: string;
1131
+ };
1132
+
1133
+ /**
1134
+ * Props exposed by the `chevron` slot.
1135
+ */
1136
+ export type BaseSelectChevronSlotProps = {
1137
+ /**
1138
+ * Whether the component is currently loading options.
1139
+ */
1140
+ loading: boolean;
1141
+ /**
1142
+ * Whether the dropdown panel is currently open.
1143
+ */
1144
+ shown: boolean;
1145
+ };
1146
+
1147
+ /**
1148
+ * Props exposed by the `chip` slot for each selected item when `multiple` is true.
1149
+ */
1150
+ export type BaseSelectChipSlotProps = {
1151
+ /**
1152
+ * Whether this chip's remove action is disabled.
1153
+ */
1154
+ disabled: boolean | undefined;
1155
+ /**
1156
+ * Whether the select is in an error state.
1157
+ */
1158
+ hasErrors?: boolean;
1159
+ /**
1160
+ * The zero-based index of this chip among the selected items.
1161
+ */
1162
+ index: number;
1163
+ /**
1164
+ * The raw selected item from the `items` prop.
1165
+ */
1166
+ item: any;
1167
+ /**
1168
+ * Whether the component is currently loading.
1169
+ */
1170
+ loading: boolean;
1171
+ /**
1172
+ * Whether the item was added manually (typed by the user).
1173
+ */
1174
+ manual: boolean;
1175
+ /**
1176
+ * Whether this chip is in a selected state.
1177
+ */
1178
+ selected: boolean | undefined;
1179
+ /**
1180
+ * The resolved display text for this selected item.
1181
+ */
1182
+ text: string;
1183
+ /**
1184
+ * The resolved value for this selected item.
1185
+ */
1186
+ value: any;
1187
+ };
1188
+
1189
+ /**
1190
+ * Props exposed by the `option` slot for each item in the dropdown list.
1191
+ */
1192
+ export type BaseSelectOptionSlotProps<Item = any> = {
1193
+ /**
1194
+ * Whether this option is disabled.
1195
+ */
1196
+ disabled: boolean;
1197
+ /**
1198
+ * Whether this option is currently keyboard-focused.
1199
+ */
1200
+ focused: boolean;
1201
+ /**
1202
+ * The zero-based index of this option in the list.
1203
+ */
1204
+ index: number;
1205
+ /**
1206
+ * Whether the select is in an error state.
1207
+ */
1208
+ hasErrors?: boolean;
1209
+ /**
1210
+ * The raw item from the `items` prop.
1211
+ */
1212
+ item: Item;
1213
+ /**
1214
+ * Whether the component is currently loading.
1215
+ */
1216
+ loading: boolean;
1217
+ /**
1218
+ * Whether this option is currently selected.
1219
+ */
1220
+ selected: boolean;
1221
+ /**
1222
+ * The resolved display text for this option.
1223
+ */
1224
+ text: string;
1225
+ /**
1226
+ * The resolved value for this option.
1227
+ */
1228
+ value: any;
1229
+ };
1230
+
1231
+ /**
1232
+ * Props exposed by the `group` slot for each group header in the dropdown list.
1233
+ */
1234
+ export type BaseSelectGroupSlotProps<Item = any> = {
1235
+ /**
1236
+ * The display text for this group.
1237
+ */
1238
+ text: string;
1239
+ /**
1240
+ * The raw group item from the `items` prop.
1241
+ */
1242
+ item: Item;
1243
+ /**
1244
+ * The zero-based index of this group in the list.
1245
+ */
1246
+ index: number;
1247
+ /**
1248
+ * The number of options in this group.
1249
+ */
1250
+ length: number;
1251
+ /**
1252
+ * Whether this group is disabled.
1253
+ */
1254
+ disabled: boolean;
1255
+ };
1256
+
1257
+ /**
1258
+ * Props exposed by dropdown panel boundary slots
1259
+ * (`options:append`, `options:append:outer`, `options:prepend`, `options:prepend:outer`).
1260
+ */
1261
+ export type BaseSelectFocusSlotProps = {
1262
+ /**
1263
+ * Focuses the search input.
1264
+ */
1265
+ focus: () => void;
1266
+ };
1267
+
1268
+ export type BaseSelectSlots<Item = any> = {
1269
+ /**
1270
+ * Content rendered after the input area, at the end of the inner container.
1271
+ */
1272
+ append?: (props: BaseSelectQueryFocusSlotProps) => any;
1273
+ /**
1274
+ * Content rendered after the entire select control, outside the input chrome.
1275
+ */
1276
+ 'append-outer'?: (props: BaseSelectQueryOnlySlotProps) => any;
1277
+ /**
1278
+ * Replaces the default dropdown chevron/arrow icon.
1279
+ */
1280
+ chevron?: (props: BaseSelectChevronSlotProps) => any;
1281
+ /**
1282
+ * Replaces the chip rendered for each selected item when `multiple` is true.
1283
+ */
1284
+ chip?: (props: BaseSelectChipSlotProps) => any;
1285
+ /**
1286
+ * Replaces the default loading indicator rendered inside the dropdown while options are fetching.
1287
+ */
1288
+ loading?: (props: BaseSelectQueryOnlySlotProps) => any;
1289
+ /**
1290
+ * Replaces the default "no data" message rendered inside the dropdown when no options match.
1291
+ */
1292
+ 'no-data'?: (props: BaseSelectQueryFocusSlotProps) => any;
1293
+ /**
1294
+ * Replaces the default option row rendered for each item in the dropdown list.
1295
+ */
1296
+ option?: (props: BaseSelectOptionSlotProps<Item>) => any;
1297
+ /**
1298
+ * Replaces the default group header row rendered above options that belong to a group.
1299
+ */
1300
+ group?: (props: BaseSelectGroupSlotProps<Item>) => any;
1301
+ /**
1302
+ * Content rendered after the option list, inside the dropdown panel.
1303
+ */
1304
+ 'options:append'?: (props: BaseSelectFocusSlotProps) => any;
1305
+ /**
1306
+ * Content rendered after the dropdown panel, outside the scrollable options area.
1307
+ */
1308
+ 'options:append:outer'?: (props: BaseSelectFocusSlotProps) => any;
1309
+ /**
1310
+ * Content rendered before the option list, inside the dropdown panel.
1311
+ */
1312
+ 'options:prepend'?: (props: BaseSelectFocusSlotProps) => any;
1313
+ /**
1314
+ * Content rendered before the dropdown panel, outside the scrollable options area.
1315
+ */
1316
+ 'options:prepend:outer'?: (props: BaseSelectFocusSlotProps) => any;
1317
+ /**
1318
+ * Inline content rendered at the start of the input field area, before the selected value text.
1319
+ */
1320
+ prefix?: (props: object) => any;
1321
+ /**
1322
+ * Content rendered before the input area, at the start of the inner container.
1323
+ */
1324
+ prepend?: (props: BaseSelectQueryFocusSlotProps) => any;
1325
+ /**
1326
+ * Content rendered before the entire select control, outside the input chrome.
1327
+ */
1328
+ 'prepend-outer'?: (props: BaseSelectQueryOnlySlotProps) => any;
1329
+ /**
1330
+ * Inline content rendered at the end of the input field area, after the selected value text.
1331
+ */
1332
+ suffix?: (props: object) => any;
1333
+ };
1334
+ ```
1335
+
1336
+ ## Styles
1337
+
1338
+ ```css
1339
+ .bb-base-select {
1340
+ /* Get the inner height based on the largest contained element this is not to be edited with arbitrary values */
1341
+ --bb-input-inner-h: max(
1342
+ calc(var(--bb-leading) + var(--bb-input-py) * 2),
1343
+ calc(var(--bb-input-h) - 2px),
1344
+ var(--bb-input-icon)
1345
+ );
1346
+ --floating-py: calc((var(--bb-input-inner-h) - var(--bb-input-icon)) / 2);
1347
+ --bb-arrow: 0;
1348
+ box-sizing: border-box;
1349
+ display: inline-flex;
1350
+ scroll-margin: 10px;
1351
+ width: 100%;
1352
+
1353
+ &--active {
1354
+ .bb-base-select__text-input {
1355
+ /* Approximate the length of the text as min width so the character doesn't go into a newline as often*/
1356
+ min-width: min(100%, calc(var(--characters) * 12px));
1357
+ }
1358
+ }
1359
+ &--loading {
1360
+ }
1361
+ &--disabled {
1362
+ }
1363
+ &--errors {
1364
+ }
1365
+ &--readonly {
1366
+ }
1367
+ &--compact {
1368
+ --floating-py: var(--bb-input-compact-floating-py);
1369
+
1370
+ .bb-chipsbox-item {
1371
+ min-height: 20px;
1372
+ }
1373
+ }
1374
+
1375
+ &--shown {
1376
+ .bb-base-select__chevron {
1377
+ transform: rotate(180deg);
1378
+ }
1379
+ }
1380
+
1381
+ .bb-smooth-height {
1382
+ align-self: center;
1383
+ text-align: left;
1384
+ width: 100%;
1385
+ }
1386
+ .bb-base-select__inner-wrapper {
1387
+ display: block;
1388
+ flex: 1 1 auto;
1389
+
1390
+ .bb-common-input-inner-container {
1391
+ position: relative;
1392
+ align-items: flex-start;
1393
+ width: 100%;
1394
+
1395
+ > .bb-clearable-button {
1396
+ margin-top: var(--floating-py);
1397
+ }
1398
+ > .bb-spinner {
1399
+ margin-top: var(--floating-py);
1400
+ }
1401
+ > .bb-error-icon {
1402
+ margin-top: var(--floating-py);
1403
+ }
1404
+ > .bb-common-input-inner-container__prepend-icon,
1405
+ > .bb-common-input-inner-container__append-icon {
1406
+ margin-top: var(--floating-py);
1407
+ }
1408
+
1409
+ > .bb-common-input-inner-container__prefix,
1410
+ > .bb-common-input-inner-container__suffix {
1411
+ height: var(--bb-input-inner-h);
1412
+ }
1413
+
1414
+ :last-child:not(.bb-error-icon) {
1415
+ order: 1;
1416
+ }
1417
+ }
1418
+ }
1419
+ .bb-listbox {
1420
+ --option-h: var(--option-height);
1421
+ display: block;
1422
+
1423
+ &.bb-listbox--open {
1424
+ transition: min-height 0s 0s;
1425
+
1426
+ .bb-listbox__outer-container {
1427
+ grid-template-rows: 1fr;
1428
+ opacity: 1;
1429
+ transition-delay: 0s, 00ms;
1430
+
1431
+ > * {
1432
+ opacity: 1;
1433
+ transition-delay: calc(var(--transition-duration) * 0.8);
1434
+ }
1435
+ }
1436
+ }
1437
+ &.bb-listbox--no-data {
1438
+ .bb-listbox__outer-container {
1439
+ .bb-listbox__inner-container {
1440
+ .bb-listbox__no-data {
1441
+ display: block;
1442
+ }
1443
+ }
1444
+ }
1445
+ }
1446
+ &.bb-listbox--loading {
1447
+ .bb-listbox__outer-container {
1448
+ .bb-listbox__inner-container {
1449
+ .bb-listbox__loading {
1450
+ display: block;
1451
+ text-align: left;
1452
+ }
1453
+ .bb-listbox__loading {
1454
+ display: hidden;
1455
+ }
1456
+ }
1457
+ }
1458
+ }
1459
+
1460
+ &.bb-listbox--multiple {
1461
+ .autocomplete-option__checkbox {
1462
+ display: inline-block !important;
1463
+ }
1464
+ }
1465
+
1466
+ .bb-listbox__outer-container {
1467
+ background-color: var(--bb-panel);
1468
+ border-color: var(--bb-primary);
1469
+ border-radius: var(--bb-radius);
1470
+ border-width: 0px;
1471
+ display: grid;
1472
+ grid-template-rows: 0fr;
1473
+ opacity: 0;
1474
+ transition-delay: calc(var(--transition-duration) * 0.25), 0s, 0s;
1475
+ transition-duration:
1476
+ var(--transition-duration), calc(var(--transition-duration) * 1.4),
1477
+ var(--transition-duration);
1478
+ transition-property: grid-template-rows, opacity, border;
1479
+
1480
+ > * {
1481
+ opacity: 0;
1482
+ transition-delay: 0s;
1483
+ transition-duration: calc(var(--transition-duration) * 2);
1484
+ transition-property: opacity;
1485
+ }
1486
+
1487
+ .bb-listbox__inner-container {
1488
+ overflow: auto;
1489
+ text-align: left;
1490
+ /* Always show options up to the bottom of the screen, but not more than 6 options */
1491
+ max-height: min(
1492
+ calc(var(--option-h) * 6),
1493
+ calc(round(down, calc(100dvh - 130px), var(--option-h)) - 1px)
1494
+ );
1495
+
1496
+ .bb-listbox__loading,
1497
+ .bb-listbox__no-data {
1498
+ color: var(--bb-text);
1499
+ display: none;
1500
+ padding-bottom: var(--bb-select-option-py);
1501
+ padding-left: var(--bb-select-option-px);
1502
+ padding-right: var(--bb-select-option-px);
1503
+ padding-top: var(--bb-select-option-py);
1504
+ }
1505
+
1506
+ span[role='listbox'] {
1507
+ position: relative;
1508
+ width: 100%;
1509
+ display: block;
1510
+
1511
+ .bb-listbox__group {
1512
+ left: 0;
1513
+ position: absolute;
1514
+ top: 0;
1515
+ width: 100%;
1516
+ display: block;
1517
+ }
1518
+
1519
+ .bb-listbox__group-header {
1520
+ display: flex;
1521
+ align-items: center;
1522
+ height: var(--group-header-height, 32px);
1523
+ padding-left: var(--bb-select-option-px);
1524
+ padding-right: var(--bb-select-option-px);
1525
+
1526
+ user-select: none;
1527
+
1528
+ .bb-listbox__group-header-label {
1529
+ display: flex;
1530
+ align-items: center;
1531
+ gap: 16px;
1532
+ flex: auto;
1533
+ text-align: left;
1534
+ overflow: hidden;
1535
+ text-overflow: ellipsis;
1536
+ white-space: nowrap;
1537
+ color: color-mix(in srgb, var(--bb-text) 50%, transparent);
1538
+ font-size: 0.75rem;
1539
+ font-weight: 600;
1540
+ letter-spacing: 0.025em;
1541
+ text-transform: uppercase;
1542
+
1543
+ &::after {
1544
+ content: '';
1545
+ display: block;
1546
+ width: 100%;
1547
+ height: 1px;
1548
+ background-color: var(--bb-border);
1549
+ }
1550
+ }
1551
+ }
1552
+
1553
+ .bb-listbox__option {
1554
+ left: 0;
1555
+ position: absolute;
1556
+ display: block;
1557
+ top: 0;
1558
+ width: 100%;
1559
+ }
1560
+
1561
+ .bb-listbox__group > .bb-listbox__option {
1562
+ position: static;
1563
+ }
1564
+
1565
+ .autocomplete-option {
1566
+ --bg-opacity: 0;
1567
+ --bg-base-color: var(--bb-text);
1568
+ align-items: center;
1569
+ background-color: color-mix(
1570
+ in srgb,
1571
+ var(--bg-base-color) calc(100% * var(--bg-opacity)),
1572
+ transparent
1573
+ );
1574
+ color: var(--bb-text);
1575
+ cursor: pointer;
1576
+ display: flex;
1577
+ flex-grow: 1;
1578
+ gap: 8px;
1579
+ height: var(--option-h);
1580
+ padding-left: var(--bb-select-option-px);
1581
+ padding-right: var(--bb-select-option-px);
1582
+ transition-duration: 250ms;
1583
+ transition-property: color, background-color;
1584
+ transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
1585
+ width: 100%;
1586
+
1587
+ &:hover:not(.autocomplete-option--disabled) {
1588
+ --bg-opacity: 0.05;
1589
+ --bg-base-color: var(--bb-text);
1590
+ }
1591
+
1592
+ &--focused {
1593
+ --bg-opacity: 0.15;
1594
+ --bg-base-color: var(--bb-text);
1595
+ }
1596
+
1597
+ &--focused:hover:not(.autocomplete-option--disabled) {
1598
+ --bg-opacity: 0.2;
1599
+ }
1600
+
1601
+ &--selected {
1602
+ --bg-opacity: 0.1;
1603
+ --bg-base-color: var(--bb-primary) !important;
1604
+ color: var(--bb-primary);
1605
+ }
1606
+
1607
+ &--selected:hover:not(.autocomplete-option--disabled) {
1608
+ --bg-opacity: 0.15;
1609
+ }
1610
+
1611
+ &--selected.autocomplete-option--focused {
1612
+ --bg-opacity: 0.2;
1613
+ }
1614
+
1615
+ &--selected.autocomplete-option--focused:hover:not(
1616
+ .autocomplete-option--disabled
1617
+ ) {
1618
+ --bg-opacity: 0.2;
1619
+ }
1620
+
1621
+ &--disabled {
1622
+ cursor: not-allowed;
1623
+ opacity: 0.5;
1624
+
1625
+ .autocomplete-option__checkbox.autocomplete-option__checkbox {
1626
+ background-color: var(--bb-panel-disabled);
1627
+ }
1628
+ }
1629
+
1630
+ .autocomplete-option__checkbox {
1631
+ pointer-events: none;
1632
+ display: none;
1633
+ width: 16px;
1634
+ height: 16px;
1635
+ background-color: var(--bb-panel);
1636
+ border-color: var(--bb-border);
1637
+ border-radius: min(6px, var(--bb-radius));
1638
+ border-style: solid;
1639
+ border-width: 1px;
1640
+ margin-left: -6px;
1641
+ transition-duration: 300ms;
1642
+ transition-property:
1643
+ color, background-color, border-color, text-decoration-color,
1644
+ box-shadow;
1645
+ transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
1646
+
1647
+ path {
1648
+ stroke: var(--bb-contrasting);
1649
+ stroke-dasharray: 105;
1650
+ stroke-dashoffset: 105;
1651
+ transition: stroke-dashoffset 0.3s;
1652
+ }
1653
+ }
1654
+
1655
+ .autocomplete-option__label {
1656
+ display: block;
1657
+ flex: auto;
1658
+ text-align: left;
1659
+ overflow: hidden;
1660
+ text-overflow: ellipsis;
1661
+ white-space: nowrap;
1662
+ }
1663
+
1664
+ &.autocomplete-option--selected {
1665
+ .autocomplete-option__checkbox {
1666
+ background-color: var(--bb-primary);
1667
+ border-color: var(--bb-primary);
1668
+
1669
+ path {
1670
+ stroke-dashoffset: 0;
1671
+ }
1672
+ }
1673
+ }
1674
+ }
1675
+ }
1676
+ }
1677
+ }
1678
+ }
1679
+
1680
+ &__input-container {
1681
+ display: flex;
1682
+ flex-wrap: wrap;
1683
+ gap: 0.25rem;
1684
+ padding-bottom: var(--bb-input-py);
1685
+ padding-top: var(--bb-input-py);
1686
+ }
1687
+ &__max-reached {
1688
+ border-right: 1px solid var(--bb-border);
1689
+ color: var(--bb-input-color);
1690
+ font-size: var(--bb-input-font-size);
1691
+ padding-right: 4px;
1692
+ }
1693
+ .bb-chipsbox-item {
1694
+ position: relative;
1695
+ z-index: 1;
1696
+ }
1697
+ .bb-commabox-item {
1698
+ }
1699
+
1700
+ .bb-base-select__text-input {
1701
+ flex-basis: 0px !important;
1702
+ flex-grow: 1 !important;
1703
+ flex-shrink: 10000 !important;
1704
+ margin-bottom: 0px;
1705
+ margin-top: 0px;
1706
+ min-width: 0;
1707
+ }
1708
+
1709
+ &__chevron {
1710
+ background-color: inherit;
1711
+ color: var(--bb-icon-color);
1712
+ flex-shrink: 0;
1713
+ margin-top: var(--floating-py);
1714
+ order: 1;
1715
+ transform: rotate(0deg);
1716
+ transition: transform 0.2s ease-in-out;
1717
+ width: var(--bb-input-icon);
1718
+ }
1719
+ }
1720
+ ```