bitboss-ui 3.0.0-beta.47 → 3.0.0-beta.49

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 (398) hide show
  1. package/README.md +24 -7
  2. package/bin/bitboss-ui-mcp.mjs +15 -3
  3. package/bin/bitboss-ui.mjs +167 -14
  4. package/dist/ai/BbAccordion.md +1 -1
  5. package/dist/ai/BbAvatar.md +1 -1
  6. package/dist/ai/BbBreadcrumbs.md +65 -65
  7. package/dist/ai/BbButton.md +28 -8
  8. package/dist/ai/BbCheckbox.md +0 -2
  9. package/dist/ai/BbCheckboxGroup.md +13 -20
  10. package/dist/ai/BbCollapsible.md +1 -1
  11. package/dist/ai/BbColorPalette.md +1 -1
  12. package/dist/ai/BbConfirm.md +8 -0
  13. package/dist/ai/BbConfirmPortal.md +1 -1
  14. package/dist/ai/BbDatePickerInput.md +4 -2
  15. package/dist/ai/BbDialog.md +1 -8
  16. package/dist/ai/BbDropdown.md +231 -220
  17. package/dist/ai/BbDropdownButton.md +65 -65
  18. package/dist/ai/BbDropdownGroup.md +2 -2
  19. package/dist/ai/BbDropzone.md +10 -10
  20. package/dist/ai/BbForm.md +43 -52
  21. package/dist/ai/BbHoverCard.md +19 -7
  22. package/dist/ai/BbHoverCardPortal.md +1 -1
  23. package/dist/ai/BbNumberInput.md +88 -21
  24. package/dist/ai/BbPopover.md +47 -40
  25. package/dist/ai/BbPopoverPortal.md +1 -1
  26. package/dist/ai/BbProgress.md +48 -22
  27. package/dist/ai/BbRadioGroup.md +13 -19
  28. package/dist/ai/BbSelect.md +16 -36
  29. package/dist/ai/BbSelectPopover.md +14 -30
  30. package/dist/ai/BbSmoothHeight.md +0 -2
  31. package/dist/ai/BbSwitchGroup.md +13 -20
  32. package/dist/ai/BbTable.md +11 -10
  33. package/dist/ai/BbTabs.md +107 -106
  34. package/dist/ai/BbTabsList.md +2 -2
  35. package/dist/ai/BbTabsPanels.md +1 -1
  36. package/dist/ai/BbTabsRoot.md +3 -3
  37. package/dist/ai/BbTooltip.md +29 -13
  38. package/dist/ai/BbTree.md +14 -11
  39. package/dist/ai/CommonPopover.md +1 -1
  40. package/dist/ai/changelog.json +297 -6
  41. package/dist/ai/components.json +50 -45
  42. package/dist/ai/composables/useBbDropdownContext.md +16 -16
  43. package/dist/ai/composables/useBbFormField.md +5 -1
  44. package/dist/ai/composables/useBbTabsContext.md +14 -14
  45. package/dist/ai/guides/agent-contract.md +27 -27
  46. package/dist/ai/guides/ai-router.md +1 -1
  47. package/dist/ai/guides/component-picker.md +3 -3
  48. package/dist/ai/guides/fetch-items-playbook.md +1 -1
  49. package/dist/ai/guides/icons-policy.md +10 -10
  50. package/dist/ai/guides/inertia-helpers.md +120 -67
  51. package/dist/ai/guides/installation-and-plugin-setup.md +45 -15
  52. package/dist/ai/guides/migration/components/bb-breadcrumbs.md +3 -2
  53. package/dist/ai/guides/migration/components/bb-checkbox-group.md +16 -16
  54. package/dist/ai/guides/migration/components/bb-dropdown-button.md +9 -8
  55. package/dist/ai/guides/migration/components/bb-dropdown.md +15 -14
  56. package/dist/ai/guides/migration/components/bb-radio-group.md +2 -1
  57. package/dist/ai/guides/migration/components/bb-select-popover.md +6 -1
  58. package/dist/ai/guides/migration/components/bb-select.md +10 -2
  59. package/dist/ai/guides/migration/components/bb-switch-group.md +2 -1
  60. package/dist/ai/guides/migration/components/bb-tabs.md +9 -8
  61. package/dist/ai/guides/migration/components/bb-tooltip.md +1 -1
  62. package/dist/ai/guides/migration/v2-to-v3.md +143 -28
  63. package/dist/ai/guides/migration/v3-beta-css-classes.md +29 -27
  64. package/dist/ai/guides/migration/v3-beta-tooling.md +11 -0
  65. package/dist/ai/guides/options-items-playbook.md +30 -24
  66. package/dist/ai/guides/passthrough.md +4 -4
  67. package/dist/ai/guides/preset-components.md +18 -3
  68. package/dist/ai/guides/typescript-generic-components.md +1 -1
  69. package/dist/ai/guides/validated-forms.md +11 -22
  70. package/dist/ai/guides/validation-providers.md +4 -3
  71. package/dist/ai/helpers/inertia/manifest.json +636 -0
  72. package/dist/ai/helpers/inertia/types.ts +15 -0
  73. package/dist/ai/helpers/inertia/useAsyncFn.ts +110 -0
  74. package/dist/ai/helpers/inertia/useConfirmOnRouteLeave.ts +102 -0
  75. package/dist/ai/helpers/inertia/useDeleteCmd.ts +30 -0
  76. package/dist/ai/helpers/inertia/useHasChanged.ts +36 -0
  77. package/dist/ai/helpers/inertia/useIndexById.ts +23 -0
  78. package/dist/ai/helpers/inertia/useLazyProp.ts +148 -0
  79. package/dist/ai/helpers/inertia/useLazyPropGetter.ts +50 -0
  80. package/dist/ai/helpers/inertia/useLoading.ts +20 -0
  81. package/dist/ai/helpers/inertia/usePaginatedResponseContext.ts +88 -0
  82. package/dist/ai/helpers/inertia/usePromiseForm.ts +62 -0
  83. package/dist/ai/helpers/inertia/useProp.ts +63 -0
  84. package/dist/ai/helpers/inertia/useQuery.ts +19 -0
  85. package/dist/ai/helpers/inertia/useQueryObject.ts +116 -0
  86. package/dist/ai/helpers/inertia/useResourceContext.ts +69 -0
  87. package/dist/ai/helpers/inertia/useRouteQuery.ts +54 -0
  88. package/dist/ai/helpers/inertia/useScreenSizes.ts +23 -0
  89. package/dist/ai/helpers/inertia/useTableContext.ts +34 -0
  90. package/dist/ai/helpers/inertia/useTableSelectionContext.ts +48 -0
  91. package/dist/ai/helpers/inertia/useUntil.ts +33 -0
  92. package/dist/ai/helpers/inertia/utils.ts +24 -0
  93. package/dist/ai/index.md +6 -6
  94. package/dist/ai/manifest/components/BbAccordion.json +1 -1
  95. package/dist/ai/manifest/components/BbBreadcrumbs.json +10 -6
  96. package/dist/ai/manifest/components/BbBreadcrumbs.tree.json +1 -1
  97. package/dist/ai/manifest/components/BbButton.json +2 -1
  98. package/dist/ai/manifest/components/BbButton.tree.json +1 -1
  99. package/dist/ai/manifest/components/BbCheckboxGroup.json +2 -2
  100. package/dist/ai/manifest/components/BbCollapsible.json +1 -1
  101. package/dist/ai/manifest/components/BbColorPalette.json +1 -1
  102. package/dist/ai/manifest/components/BbConfirmPortal.json +5 -2
  103. package/dist/ai/manifest/components/BbDropdown.json +23 -20
  104. package/dist/ai/manifest/components/BbDropdown.tree.json +2 -2
  105. package/dist/ai/manifest/components/BbDropdownButton.json +22 -19
  106. package/dist/ai/manifest/components/BbDropdownButton.tree.json +1 -1
  107. package/dist/ai/manifest/components/BbDropdownGroup.json +2 -2
  108. package/dist/ai/manifest/components/BbForm.json +1 -0
  109. package/dist/ai/manifest/components/BbHoverCard.json +1 -1
  110. package/dist/ai/manifest/components/BbHoverCardPortal.json +2 -2
  111. package/dist/ai/manifest/components/BbNumberInput.json +6 -1
  112. package/dist/ai/manifest/components/BbNumberInput.tree.json +2 -1
  113. package/dist/ai/manifest/components/BbPopover.json +2 -1
  114. package/dist/ai/manifest/components/BbPopoverPortal.json +2 -2
  115. package/dist/ai/manifest/components/BbProgress.json +6 -6
  116. package/dist/ai/manifest/components/BbProgress.tree.json +1 -0
  117. package/dist/ai/manifest/components/BbRadioGroup.json +2 -2
  118. package/dist/ai/manifest/components/BbSelect.json +2 -2
  119. package/dist/ai/manifest/components/BbSelect.tree.json +2 -2
  120. package/dist/ai/manifest/components/BbSelectPopover.json +2 -2
  121. package/dist/ai/manifest/components/BbSelectPopover.tree.json +1 -1
  122. package/dist/ai/manifest/components/BbSwitchGroup.json +2 -2
  123. package/dist/ai/manifest/components/BbTabs.json +8 -7
  124. package/dist/ai/manifest/components/BbTabsList.json +3 -3
  125. package/dist/ai/manifest/components/BbTabsPanels.json +1 -1
  126. package/dist/ai/manifest/components/BbTabsRoot.json +6 -5
  127. package/dist/ai/manifest/components/BbTag.tree.json +1 -1
  128. package/dist/ai/manifest/components/BbTooltip.json +2 -2
  129. package/dist/ai/manifest/components/ChipsBox.tree.json +1 -1
  130. package/dist/ai/manifest/components/CommonPopover.json +1 -1
  131. package/dist/ai/manifest/index.json +2 -2
  132. package/dist/ai/manifest/meta.json +5 -0
  133. package/dist/ai/manifest/types.advanced.json +10 -9
  134. package/dist/ai/manifest/types.api.json +8 -5
  135. package/dist/ai/manifest/types.wrapper.json +1 -0
  136. package/dist/ai/recipes/inertia/approvals-inbox.md +16 -18
  137. package/dist/ai/recipes/inertia/inline-edit-workspace.md +23 -33
  138. package/dist/ai/recipes/inertia/layout-scaffold.md +16 -16
  139. package/dist/ai/recipes/inertia/onboarding.md +6 -10
  140. package/dist/ai/recipes/inertia/ownership-atlas.md +15 -18
  141. package/dist/ai/recipes/inertia/record-form.md +11 -11
  142. package/dist/ai/recipes/inertia/records-workspace.md +38 -41
  143. package/dist/ai/recipes/inertia/settings-workspace.md +26 -38
  144. package/dist/ai/recipes/inertia/upload-center.md +31 -39
  145. package/dist/ai/recipes/inertia/wizard-form.md +10 -19
  146. package/dist/ai/recipes/nuxt/approvals-inbox.md +7 -8
  147. package/dist/ai/recipes/nuxt/inline-edit-workspace.md +14 -24
  148. package/dist/ai/recipes/nuxt/layout-scaffold.md +16 -16
  149. package/dist/ai/recipes/nuxt/onboarding.md +2 -6
  150. package/dist/ai/recipes/nuxt/ownership-atlas.md +7 -9
  151. package/dist/ai/recipes/nuxt/record-form.md +5 -5
  152. package/dist/ai/recipes/nuxt/records-workspace.md +29 -31
  153. package/dist/ai/recipes/nuxt/settings-workspace.md +22 -34
  154. package/dist/ai/recipes/nuxt/upload-center.md +22 -29
  155. package/dist/ai/recipes/nuxt/wizard-form.md +3 -11
  156. package/dist/ai/recipes/vue/approvals-inbox.md +7 -8
  157. package/dist/ai/recipes/vue/inline-edit-workspace.md +14 -24
  158. package/dist/ai/recipes/vue/layout-scaffold.md +16 -16
  159. package/dist/ai/recipes/vue/onboarding.md +2 -6
  160. package/dist/ai/recipes/vue/ownership-atlas.md +7 -9
  161. package/dist/ai/recipes/vue/record-form.md +5 -5
  162. package/dist/ai/recipes/vue/records-workspace.md +29 -31
  163. package/dist/ai/recipes/vue/settings-workspace.md +22 -34
  164. package/dist/ai/recipes/vue/upload-center.md +22 -29
  165. package/dist/ai/recipes/vue/wizard-form.md +3 -11
  166. package/dist/ai/source/BbAccordion.md +1 -1
  167. package/dist/ai/source/BbAlert.md +3 -3
  168. package/dist/ai/source/BbBadge.md +14 -10
  169. package/dist/ai/source/BbBadgeButton.md +17 -12
  170. package/dist/ai/source/BbBaseButton.md +1 -1
  171. package/dist/ai/source/BbBaseRadioIcon.md +1 -0
  172. package/dist/ai/source/BbBaseSwitchIcon.md +1 -0
  173. package/dist/ai/source/BbBreadcrumbs.md +63 -42
  174. package/dist/ai/source/BbButton.md +84 -38
  175. package/dist/ai/source/BbCalendar.md +17 -16
  176. package/dist/ai/source/BbCheckbox.md +3 -2
  177. package/dist/ai/source/BbCheckboxGroup.md +11 -4
  178. package/dist/ai/source/BbCollapsible.md +2 -1
  179. package/dist/ai/source/BbColorInput.md +10 -9
  180. package/dist/ai/source/BbColorPalette.md +2 -1
  181. package/dist/ai/source/BbConfirm.md +18 -1
  182. package/dist/ai/source/BbConfirmPortal.md +20 -6
  183. package/dist/ai/source/BbDatePicker.md +2 -2
  184. package/dist/ai/source/BbDatePickerInput.md +47 -20
  185. package/dist/ai/source/BbDialog.md +5 -5
  186. package/dist/ai/source/BbDropdown.md +231 -158
  187. package/dist/ai/source/BbDropdownButton.md +19 -12
  188. package/dist/ai/source/BbDropdownGroup.md +127 -93
  189. package/dist/ai/source/BbForm.md +25 -1
  190. package/dist/ai/source/BbHoverCard.md +30 -3
  191. package/dist/ai/source/BbHoverCardPortal.md +18 -3
  192. package/dist/ai/source/BbIndicator.md +4 -0
  193. package/dist/ai/source/BbNumberInput.md +855 -19
  194. package/dist/ai/source/BbOffCanvas.md +27 -11
  195. package/dist/ai/source/BbPagination.md +3 -3
  196. package/dist/ai/source/BbPopover.md +185 -12
  197. package/dist/ai/source/BbPopoverPortal.md +30 -3
  198. package/dist/ai/source/BbProgress.md +82 -18
  199. package/dist/ai/source/BbRadioGroup.md +12 -5
  200. package/dist/ai/source/BbRating.md +11 -9
  201. package/dist/ai/source/BbSelect.md +16 -10
  202. package/dist/ai/source/BbSelectPopover.md +29 -23
  203. package/dist/ai/source/BbSlider.md +12 -6
  204. package/dist/ai/source/BbSwitch.md +3 -2
  205. package/dist/ai/source/BbSwitchGroup.md +5 -2
  206. package/dist/ai/source/BbTable.md +102 -18
  207. package/dist/ai/source/BbTabs.md +30 -24
  208. package/dist/ai/source/BbTabsList.md +29 -23
  209. package/dist/ai/source/BbTabsPanels.md +29 -23
  210. package/dist/ai/source/BbTabsRoot.md +28 -22
  211. package/dist/ai/source/BbTag.md +10 -9
  212. package/dist/ai/source/BbTextInput.md +5 -4
  213. package/dist/ai/source/BbTextarea.md +6 -5
  214. package/dist/ai/source/BbTimePicker.md +1 -1
  215. package/dist/ai/source/BbTimePickerInput.md +46 -9
  216. package/dist/ai/source/BbToast.md +10 -7
  217. package/dist/ai/source/BbToastPortal.md +10 -7
  218. package/dist/ai/source/BbTooltip.md +88 -11
  219. package/dist/ai/source/BbTree.md +21 -3
  220. package/dist/ai/source/CommonField.md +6 -4
  221. package/dist/ai/source/CommonFieldInput.md +15 -10
  222. package/dist/ai/source/CommonPopover.md +8 -1
  223. package/dist/ai/source/CommonTimeSelector.md +5 -4
  224. package/dist/components/BbBadge/BbBadgeButton.vue_vue_type_script_setup_true_lang.js +10 -8
  225. package/dist/components/BbBaseButton/BbBaseButton.vue_vue_type_script_setup_true_lang.js +8 -8
  226. package/dist/components/BbBreadcrumbs/BbBreadcrumbs.vue_vue_type_script_setup_true_lang.js +45 -45
  227. package/dist/components/BbBreadcrumbs/types.d.ts +25 -17
  228. package/dist/components/BbButton/BbButton.vue_vue_type_script_setup_true_lang.js +88 -70
  229. package/dist/components/BbButton/toggleRoving.d.ts +6 -0
  230. package/dist/components/BbButton/toggleRoving.js +45 -0
  231. package/dist/components/BbButton/types.d.ts +12 -4
  232. package/dist/components/BbButton/types.js +5 -1
  233. package/dist/components/BbCalendar/BbCalendar.vue_vue_type_script_setup_true_lang.js +178 -178
  234. package/dist/components/BbCalendar/CalendarMonthPanel.vue_vue_type_script_setup_true_lang.js +15 -15
  235. package/dist/components/BbCalendar/CalendarYearPanel.vue_vue_type_script_setup_true_lang.js +28 -28
  236. package/dist/components/BbCalendar/useCalendarGrid.js +141 -139
  237. package/dist/components/BbCalendar/useDayjsLocale.d.ts +38 -15
  238. package/dist/components/BbCalendar/useDayjsLocale.js +31 -30
  239. package/dist/components/BbCheckbox/BbCheckbox.vue_vue_type_script_setup_true_lang.js +48 -48
  240. package/dist/components/BbCheckboxGroup/BbCheckboxGroup.vue_vue_type_script_setup_true_lang.js +81 -80
  241. package/dist/components/BbCheckboxGroup/types.d.ts +6 -2
  242. package/dist/components/BbCollapsible/types.d.ts +2 -1
  243. package/dist/components/BbColorInput/BbColorInput.vue_vue_type_script_setup_true_lang.js +69 -69
  244. package/dist/components/BbColorPalette/types.d.ts +2 -1
  245. package/dist/components/BbConfirm/BbConfirmPortal.vue.d.ts +2 -5
  246. package/dist/components/BbConfirm/types.d.ts +15 -0
  247. package/dist/components/BbDatePickerInput/BbDatePickerInput.vue_vue_type_script_setup_true_lang.js +363 -349
  248. package/dist/components/BbDropdown/AdaptiveDropdown.vue_vue_type_script_setup_true_lang.js +91 -86
  249. package/dist/components/BbDropdown/BbDropdown.vue_vue_type_script_setup_true_lang.js +298 -289
  250. package/dist/components/BbDropdown/BbDropdownList.vue_vue_type_script_setup_true_lang.js +322 -356
  251. package/dist/components/BbDropdown/DropdownPipelineResolver.vue_vue_type_script_setup_true_lang.js +17 -15
  252. package/dist/components/BbDropdown/DropdownRow.vue.d.ts +40 -0
  253. package/dist/components/BbDropdown/DropdownRow.vue.js +5 -0
  254. package/dist/components/BbDropdown/DropdownRow.vue_vue_type_script_setup_true_lang.js +60 -0
  255. package/dist/components/BbDropdown/normalizeGroups.d.ts +8 -2
  256. package/dist/components/BbDropdown/normalizeGroups.js +60 -46
  257. package/dist/components/BbDropdown/types.d.ts +120 -88
  258. package/dist/components/BbDropdownButton/BbDropdownButton.vue_vue_type_script_setup_true_lang.js +11 -2
  259. package/dist/components/BbDropdownButton/types.d.ts +2 -2
  260. package/dist/components/BbForm/BbForm.vue.d.ts +9 -0
  261. package/dist/components/BbForm/BbForm.vue_vue_type_script_setup_true_lang.js +114 -105
  262. package/dist/components/BbForm/BbFormCustomField.js +1 -1
  263. package/dist/components/BbForm/bindFormField.js +2 -1
  264. package/dist/components/BbForm/formFields.d.ts +5 -0
  265. package/dist/components/BbHoverCard/BbHoverCard.vue_vue_type_script_setup_true_lang.js +145 -142
  266. package/dist/components/BbHoverCard/BbHoverCardPortal.vue.d.ts +2 -2
  267. package/dist/components/BbHoverCard/types.d.ts +14 -1
  268. package/dist/components/BbNumberInput/BbNumberInput.vue.d.ts +0 -1
  269. package/dist/components/BbNumberInput/BbNumberInput.vue_vue_type_script_setup_true_lang.js +452 -125
  270. package/dist/components/BbNumberInput/numberDisplay.d.ts +256 -0
  271. package/dist/components/BbNumberInput/numberDisplay.js +499 -0
  272. package/dist/components/BbNumberInput/types.d.ts +54 -1
  273. package/dist/components/BbNumberInput/warroom/corpus.d.ts +58 -0
  274. package/dist/components/BbNumberInput/warroom/currency-verify.rows.d.ts +28 -0
  275. package/dist/components/BbNumberInput/warroom/currency.rows.d.ts +2 -0
  276. package/dist/components/BbNumberInput/warroom/harness.d.ts +217 -0
  277. package/dist/components/BbNumberInput/warroom/oracle.d.ts +150 -0
  278. package/dist/components/BbPagination/BbPagination.vue_vue_type_script_setup_true_lang.js +7 -7
  279. package/dist/components/BbPopover/BbPopover.vue.d.ts +1 -0
  280. package/dist/components/BbPopover/BbPopover.vue_vue_type_script_setup_true_lang.js +207 -162
  281. package/dist/components/BbPopover/BbPopoverPortal.vue.d.ts +2 -2
  282. package/dist/components/BbPopover/types.d.ts +26 -1
  283. package/dist/components/BbProgress/BbProgress.vue_vue_type_script_setup_true_lang.js +15 -7
  284. package/dist/components/BbProgress/types.d.ts +23 -7
  285. package/dist/components/BbProgress/types.js +1 -1
  286. package/dist/components/BbRadioGroup/BbRadioGroup.vue_vue_type_script_setup_true_lang.js +102 -101
  287. package/dist/components/BbRadioGroup/types.d.ts +6 -2
  288. package/dist/components/BbRating/BbRating.vue_vue_type_script_setup_true_lang.js +63 -63
  289. package/dist/components/BbSelect/BbSelect.vue_vue_type_script_setup_true_lang.js +156 -154
  290. package/dist/components/BbSelect/types.d.ts +6 -2
  291. package/dist/components/BbSelectPopover/BbSelectPopover.vue_vue_type_script_setup_true_lang.js +2 -1
  292. package/dist/components/BbSelectPopover/types.d.ts +6 -2
  293. package/dist/components/BbSlider/BbSlider.vue_vue_type_script_setup_true_lang.js +153 -153
  294. package/dist/components/BbSwitch/BbSwitch.vue_vue_type_script_setup_true_lang.js +62 -62
  295. package/dist/components/BbSwitchGroup/BbSwitchGroup.vue_vue_type_script_setup_true_lang.js +131 -130
  296. package/dist/components/BbTable/BbTable.vue_vue_type_script_setup_true_lang.js +711 -676
  297. package/dist/components/BbTabs/BbTabs.vue_vue_type_script_setup_true_lang.js +1 -1
  298. package/dist/components/BbTabs/BbTabsList.vue_vue_type_script_setup_true_lang.js +1 -1
  299. package/dist/components/BbTabs/types.d.ts +28 -22
  300. package/dist/components/BbTag/BbTag.vue_vue_type_script_setup_true_lang.js +76 -76
  301. package/dist/components/BbTextInput/BbTextInput.vue_vue_type_script_setup_true_lang.js +58 -58
  302. package/dist/components/BbTextarea/BbTextarea.vue_vue_type_script_setup_true_lang.js +82 -82
  303. package/dist/components/BbTimePickerInput/BbTimePickerInput.vue_vue_type_script_setup_true_lang.js +246 -236
  304. package/dist/components/BbTooltip/BbTooltip.vue_vue_type_script_setup_true_lang.js +99 -86
  305. package/dist/components/BbTooltip/tooltipWarmup.d.ts +23 -0
  306. package/dist/components/BbTooltip/tooltipWarmup.js +7 -0
  307. package/dist/components/BbTooltip/types.d.ts +10 -3
  308. package/dist/components/BbTree/BbTree.vue_vue_type_script_setup_true_lang.js +29 -21
  309. package/dist/components/BbTree/BbTreeLevel.vue_vue_type_script_setup_true_lang.js +10 -7
  310. package/dist/components/CommonFieldInput/CommonFieldInput.vue_vue_type_script_setup_true_lang.js +37 -36
  311. package/dist/components/CommonPopover/types.d.ts +2 -1
  312. package/dist/components/CommonTimeSelector/CommonTimeSelector.vue_vue_type_script_setup_true_lang.js +9 -9
  313. package/dist/composables/formSubmitLock.d.ts +6 -0
  314. package/dist/composables/formSubmitLock.js +4 -0
  315. package/dist/composables/useBaseOptions.d.ts +7 -1
  316. package/dist/composables/useBaseOptions.js +32 -32
  317. package/dist/composables/useBbDropdownContext.d.ts +8 -8
  318. package/dist/composables/useBbFormField.d.ts +9 -0
  319. package/dist/composables/useBbFormField.js +5 -3
  320. package/dist/composables/useBbTabsContext.d.ts +10 -10
  321. package/dist/composables/useBbTabsContext.js +18 -18
  322. package/dist/composables/useFormBinding.d.ts +11 -0
  323. package/dist/composables/useFormBinding.js +15 -13
  324. package/dist/composables/useItemText.d.ts +5 -1
  325. package/dist/composables/useItemText.js +8 -3
  326. package/dist/composables/useItemValue.d.ts +5 -1
  327. package/dist/composables/useItemValue.js +8 -3
  328. package/dist/composables/useLocale.js +10 -9
  329. package/dist/deprecation/ai-deprecations.json.d.ts +130 -0
  330. package/dist/deprecation/ai-deprecations.json.js +1 -1
  331. package/dist/deprecation/removedProps.js +1 -1
  332. package/dist/directives/bbDropdown.js +1 -1
  333. package/dist/directives/directivePortal.d.ts +13 -7
  334. package/dist/directives/directivePortal.js +1 -4
  335. package/dist/i18n/index.d.ts +7 -12
  336. package/dist/i18n/locales/cs.json +11 -14
  337. package/dist/i18n/locales/da.json +13 -16
  338. package/dist/i18n/locales/de-CH.json +137 -0
  339. package/dist/i18n/locales/de.json +14 -17
  340. package/dist/i18n/locales/el.json +10 -13
  341. package/dist/i18n/locales/en-GB.json +137 -0
  342. package/dist/i18n/locales/en.json +8 -11
  343. package/dist/i18n/locales/es-MX.json +137 -0
  344. package/dist/i18n/locales/es.json +16 -19
  345. package/dist/i18n/locales/fi.json +8 -11
  346. package/dist/i18n/locales/fr.json +23 -26
  347. package/dist/i18n/locales/hu.json +8 -11
  348. package/dist/i18n/locales/it.json +12 -15
  349. package/dist/i18n/locales/ja.json +13 -16
  350. package/dist/i18n/locales/ko.json +10 -13
  351. package/dist/i18n/locales/nb.json +13 -16
  352. package/dist/i18n/locales/nl.json +21 -24
  353. package/dist/i18n/locales/pl.json +10 -13
  354. package/dist/i18n/locales/{pt.json → pt-BR.json} +19 -22
  355. package/dist/i18n/locales/pt-PT.json +137 -0
  356. package/dist/i18n/locales/ro.json +22 -25
  357. package/dist/i18n/locales/ru.json +11 -14
  358. package/dist/i18n/locales/sv.json +16 -19
  359. package/dist/i18n/locales/tr.json +14 -17
  360. package/dist/i18n/locales/uk.json +11 -14
  361. package/dist/i18n/locales/{zh-cn.json → zh-CN.json} +10 -13
  362. package/dist/i18n/locales/zh-HK.json +137 -0
  363. package/dist/i18n/locales/zh-TW.json +137 -0
  364. package/dist/i18n/regionHints.d.ts +16 -0
  365. package/dist/i18n/regionHints.js +49 -0
  366. package/dist/i18n/regions.d.ts +286 -0
  367. package/dist/i18n/regions.js +265 -0
  368. package/dist/index.d.ts +4 -4
  369. package/dist/index.js +4 -4
  370. package/dist/llms-full.txt +1914 -1714
  371. package/dist/llms-medium.txt +76 -46
  372. package/dist/llms.txt +7 -7
  373. package/dist/locale-blueprint.json +16 -13
  374. package/dist/styles.css +2 -2
  375. package/dist/types/passthrough.d.ts +1 -1
  376. package/dist/types/ptComponentMap.d.ts +2 -2
  377. package/dist/utilities/functions/slotKey.d.ts +2 -2
  378. package/dist/utils/versionCheck.js +1 -1
  379. package/dist/vite-plugin.d.ts +22 -19
  380. package/dist/vite.js +309 -297
  381. package/llms.txt +7 -7
  382. package/package.json +5 -3
  383. package/scripts/lib/agent-manifest.mjs +2 -1
  384. package/scripts/lib/eslint-disable.mjs +17 -4
  385. package/scripts/lib/eslint-plugin.d.ts +9 -1
  386. package/scripts/lib/eslint-plugin.mjs +256 -6
  387. package/scripts/lib/helper-canon.mjs +176 -0
  388. package/scripts/lib/helpers-add.mjs +1303 -0
  389. package/scripts/lib/local-components.mjs +33 -4
  390. package/scripts/lib/locale-check.mjs +165 -0
  391. package/scripts/lib/portal-names.mjs +458 -0
  392. package/scripts/lib/redundant-item-accessor.mjs +398 -0
  393. package/scripts/lib/renamed-item-field.mjs +343 -0
  394. package/scripts/lib/slot-key.mjs +2 -2
  395. package/scripts/lib/slot-renames.mjs +1 -1
  396. package/scripts/lib/unimported-components.mjs +5 -2
  397. package/scripts/lib/validate-bb-markup.mjs +123 -56
  398. package/dist/i18n/index.js +0 -27
@@ -1428,12 +1428,14 @@ export type BbOffCanvasSlots = {
1428
1428
  }
1429
1429
  &.bb-offcanvas--right::after {
1430
1430
  bottom: 0;
1431
+ /* stylelint-disable-next-line property-disallowed-list -- geometry: the `side` prop names a physical edge */
1431
1432
  left: 100%;
1432
1433
  top: 0;
1433
1434
  width: var(--stack-fill);
1434
1435
  }
1435
1436
  &.bb-offcanvas--left::after {
1436
1437
  bottom: 0;
1438
+ /* stylelint-disable-next-line property-disallowed-list -- geometry: the `side` prop names a physical edge */
1437
1439
  right: 100%;
1438
1440
  top: 0;
1439
1441
  width: var(--stack-fill);
@@ -1441,13 +1443,13 @@ export type BbOffCanvasSlots = {
1441
1443
  &.bb-offcanvas--top::after {
1442
1444
  bottom: 100%;
1443
1445
  height: var(--stack-fill);
1444
- left: 0;
1445
- right: 0;
1446
+ inset-inline-end: 0;
1447
+ inset-inline-start: 0;
1446
1448
  }
1447
1449
  &.bb-offcanvas--bottom::after {
1448
1450
  height: var(--stack-fill);
1449
- left: 0;
1450
- right: 0;
1451
+ inset-inline-end: 0;
1452
+ inset-inline-start: 0;
1451
1453
  top: 100%;
1452
1454
  }
1453
1455
 
@@ -1474,6 +1476,7 @@ export type BbOffCanvasSlots = {
1474
1476
  --inset-left: var(--safe-left);
1475
1477
  --translate-x: -100%;
1476
1478
  border-radius: 0 var(--bb-radius-surface) var(--bb-radius-surface) 0;
1479
+ /* stylelint-disable-next-line property-disallowed-list -- geometry: the `side` prop names a physical edge */
1477
1480
  left: 0px;
1478
1481
  transform-origin: left center;
1479
1482
  }
@@ -1483,14 +1486,17 @@ export type BbOffCanvasSlots = {
1483
1486
  --inset-bottom: var(--safe-bottom);
1484
1487
  --translate-x: 100%;
1485
1488
  border-radius: var(--bb-radius-surface) 0 0 var(--bb-radius-surface);
1489
+ /* stylelint-disable-next-line property-disallowed-list -- geometry: the `side` prop names a physical edge */
1486
1490
  left: auto;
1491
+ /* stylelint-disable-next-line property-disallowed-list -- geometry: the `side` prop names a physical edge */
1487
1492
  right: 0px;
1488
1493
  transform-origin: right center;
1489
1494
  }
1490
1495
  &.bb-offcanvas--top,
1491
1496
  &.bb-offcanvas--bottom {
1492
1497
  height: var(--max-size);
1493
- left: 0;
1498
+ inset-inline-end: 0;
1499
+ inset-inline-start: 0;
1494
1500
  /* `height` already applies `--max-size` (a length or the `fit-content`
1495
1501
  keyword for `size="auto"`); this only caps the panel to the viewport so a
1496
1502
  tall/auto sheet scrolls internally instead of overflowing off-screen. Must
@@ -1498,7 +1504,6 @@ export type BbOffCanvasSlots = {
1498
1504
  drop the cap entirely, letting a bottom sheet run past the top edge. */
1499
1505
  max-height: 100%;
1500
1506
  max-width: 100%;
1501
- right: 0;
1502
1507
  width: 100%;
1503
1508
  }
1504
1509
  &.bb-offcanvas--top {
@@ -1630,10 +1635,12 @@ export type BbOffCanvasSlots = {
1630
1635
  top-right), a right drawer (its top-left). */
1631
1636
  &.bb-offcanvas--bottom > .bb-offcanvas__header,
1632
1637
  &.bb-offcanvas--bottom.bb-offcanvas--no-header > .bb-offcanvas__content {
1638
+ /* stylelint-disable-next-line property-disallowed-list -- geometry: the `side` prop names a physical edge */
1633
1639
  border-top-left-radius: max(
1634
1640
  0px,
1635
1641
  calc(var(--bb-radius-surface) - var(--bb-border-w))
1636
1642
  );
1643
+ /* stylelint-disable-next-line property-disallowed-list -- geometry: the `side` prop names a physical edge */
1637
1644
  border-top-right-radius: max(
1638
1645
  0px,
1639
1646
  calc(var(--bb-radius-surface) - var(--bb-border-w))
@@ -1641,6 +1648,7 @@ export type BbOffCanvasSlots = {
1641
1648
  }
1642
1649
  &.bb-offcanvas--left > .bb-offcanvas__header,
1643
1650
  &.bb-offcanvas--left.bb-offcanvas--no-header > .bb-offcanvas__content {
1651
+ /* stylelint-disable-next-line property-disallowed-list -- geometry: the `side` prop names a physical edge */
1644
1652
  border-top-right-radius: max(
1645
1653
  0px,
1646
1654
  calc(var(--bb-radius-surface) - var(--bb-border-w))
@@ -1648,6 +1656,7 @@ export type BbOffCanvasSlots = {
1648
1656
  }
1649
1657
  &.bb-offcanvas--right > .bb-offcanvas__header,
1650
1658
  &.bb-offcanvas--right.bb-offcanvas--no-header > .bb-offcanvas__content {
1659
+ /* stylelint-disable-next-line property-disallowed-list -- geometry: the `side` prop names a physical edge */
1651
1660
  border-top-left-radius: max(
1652
1661
  0px,
1653
1662
  calc(var(--bb-radius-surface) - var(--bb-border-w))
@@ -1660,10 +1669,12 @@ export type BbOffCanvasSlots = {
1660
1669
  &.bb-offcanvas--top > .bb-offcanvas__footer,
1661
1670
  &.bb-offcanvas--top:not(:has(> .bb-offcanvas__footer:not(:empty)))
1662
1671
  > .bb-offcanvas__content {
1672
+ /* stylelint-disable-next-line property-disallowed-list -- geometry: the `side` prop names a physical edge */
1663
1673
  border-bottom-left-radius: max(
1664
1674
  0px,
1665
1675
  calc(var(--bb-radius-surface) - var(--bb-border-w))
1666
1676
  );
1677
+ /* stylelint-disable-next-line property-disallowed-list -- geometry: the `side` prop names a physical edge */
1667
1678
  border-bottom-right-radius: max(
1668
1679
  0px,
1669
1680
  calc(var(--bb-radius-surface) - var(--bb-border-w))
@@ -1672,6 +1683,7 @@ export type BbOffCanvasSlots = {
1672
1683
  &.bb-offcanvas--left > .bb-offcanvas__footer,
1673
1684
  &.bb-offcanvas--left:not(:has(> .bb-offcanvas__footer:not(:empty)))
1674
1685
  > .bb-offcanvas__content {
1686
+ /* stylelint-disable-next-line property-disallowed-list -- geometry: the `side` prop names a physical edge */
1675
1687
  border-bottom-right-radius: max(
1676
1688
  0px,
1677
1689
  calc(var(--bb-radius-surface) - var(--bb-border-w))
@@ -1680,6 +1692,7 @@ export type BbOffCanvasSlots = {
1680
1692
  &.bb-offcanvas--right > .bb-offcanvas__footer,
1681
1693
  &.bb-offcanvas--right:not(:has(> .bb-offcanvas__footer:not(:empty)))
1682
1694
  > .bb-offcanvas__content {
1695
+ /* stylelint-disable-next-line property-disallowed-list -- geometry: the `side` prop names a physical edge */
1683
1696
  border-bottom-left-radius: max(
1684
1697
  0px,
1685
1698
  calc(var(--bb-radius-surface) - var(--bb-border-w))
@@ -1789,6 +1802,7 @@ export type BbOffCanvasSlots = {
1789
1802
  &.bb-offcanvas--bottom .bb-offcanvas__handle,
1790
1803
  &.bb-offcanvas--top .bb-offcanvas__handle {
1791
1804
  height: var(--handle-h);
1805
+ /* stylelint-disable-next-line property-disallowed-list -- geometry: centred with a physical translate */
1792
1806
  left: 50%;
1793
1807
  translate: -50% 0;
1794
1808
  width: var(--handle-w);
@@ -1808,9 +1822,11 @@ export type BbOffCanvasSlots = {
1808
1822
  width: var(--handle-h);
1809
1823
  }
1810
1824
  &.bb-offcanvas--left .bb-offcanvas__handle {
1825
+ /* stylelint-disable-next-line property-disallowed-list -- geometry: the `side` prop names a physical edge */
1811
1826
  right: 8px;
1812
1827
  }
1813
1828
  &.bb-offcanvas--right .bb-offcanvas__handle {
1829
+ /* stylelint-disable-next-line property-disallowed-list -- geometry: the `side` prop names a physical edge */
1814
1830
  left: 8px;
1815
1831
  }
1816
1832
 
@@ -1866,7 +1882,7 @@ export type BbOffCanvasSlots = {
1866
1882
  * the space here instead — only when there is actually a control to
1867
1883
  * clear, so `hideClose` keeps the full width. */
1868
1884
  &:has(~ .bb-close-button) {
1869
- padding-right: calc(var(--close-size) + 4px);
1885
+ padding-inline-end: calc(var(--close-size) + 4px);
1870
1886
  }
1871
1887
  }
1872
1888
  /* Only when a description is present. A header without one keeps its
@@ -1888,7 +1904,7 @@ export type BbOffCanvasSlots = {
1888
1904
  does. The × sits at the top-right, and a one-line title is short
1889
1905
  enough that the description's first line can still run under it. */
1890
1906
  &:has(~ .bb-close-button) {
1891
- padding-right: calc(var(--close-size) + 4px);
1907
+ padding-inline-end: calc(var(--close-size) + 4px);
1892
1908
  }
1893
1909
  }
1894
1910
 
@@ -1900,8 +1916,8 @@ export type BbOffCanvasSlots = {
1900
1916
  > .bb-close-button {
1901
1917
  --size: var(--close-size);
1902
1918
  --p: 7px;
1919
+ inset-inline-end: calc(var(--px) - var(--p));
1903
1920
  position: absolute;
1904
- right: calc(var(--px) - var(--p));
1905
1921
  top: calc(var(--py) - var(--p));
1906
1922
  }
1907
1923
  }
@@ -1956,8 +1972,8 @@ export type BbOffCanvasSlots = {
1956
1972
  > .bb-close-button {
1957
1973
  --size: 28px;
1958
1974
  --p: 7px;
1975
+ inset-inline-end: calc(var(--px) - var(--p));
1959
1976
  position: absolute;
1960
- right: calc(var(--px) - var(--p));
1961
1977
  top: calc(var(--py) - var(--p));
1962
1978
  }
1963
1979
  }
@@ -2042,7 +2058,7 @@ export type BbOffCanvasSlots = {
2042
2058
 
2043
2059
  body:has(.bb-offcanvas--visible) {
2044
2060
  overflow: hidden;
2045
- padding-right: var(--scrollbar-width);
2061
+ padding-inline-end: var(--scrollbar-width);
2046
2062
  }
2047
2063
 
2048
2064
  @keyframes bb-offcanvas-deny-bounce-x {
@@ -864,13 +864,13 @@ export type BbPaginationSlots = {
864
864
 
865
865
  &--right {
866
866
  .bb-pagination__pages {
867
- margin-left: auto;
867
+ margin-inline-start: auto;
868
868
  }
869
869
  }
870
870
  &--center {
871
871
  .bb-pagination__pages {
872
- margin-left: auto;
873
- margin-right: auto;
872
+ margin-inline-end: auto;
873
+ margin-inline-start: auto;
874
874
  }
875
875
  }
876
876
 
@@ -88,11 +88,11 @@
88
88
  ref="popover-ref"
89
89
  v-model="isOpen"
90
90
  :anchor="effectiveAnchor"
91
- :aria-labelledby="hasOpenedOnce ? activatorId : undefined"
91
+ :aria-labelledby="hasOpenedOnce ? labelledById : undefined"
92
92
  :boundary="boundary"
93
93
  :bubble-attrs="panelAttrs"
94
94
  class="bb-popover"
95
- dialog
95
+ :dialog="modal"
96
96
  :eager="eager"
97
97
  hide-arrow
98
98
  :offset="offset"
@@ -100,7 +100,7 @@
100
100
  :placement="placement === 'cursor' ? 'bottom-start' : placement"
101
101
  :style="{ width: parsedWidth }"
102
102
  :transition-duration="transitionDuration"
103
- v-bind="mergeProps($attrs, passthrough.root)"
103
+ v-bind="mergeProps(nonModalAttrs, $attrs, passthrough.root)"
104
104
  @hidden="onPanelHidden"
105
105
  @shown="emit('shown')"
106
106
  >
@@ -150,7 +150,7 @@
150
150
  </template>
151
151
 
152
152
  <script setup lang="ts">
153
- // Attributes land on the floating panel's `<dialog>` on desktop, the sheet's `<dialog>` on a phone (without `class` there).
153
+ // Attributes land on the floating panel on desktop (a `<dialog>` when `modal`, else a `<div role="dialog">`), the sheet's `<dialog>` on a phone (without `class` there).
154
154
  // Measured 2026-09-23 (Q49.23); read by components.json.
155
155
  // @attrTargets dialog
156
156
  import {
@@ -168,6 +168,7 @@ import {
168
168
  pushEscapeEntry,
169
169
  removeEscapeEntry,
170
170
  isTopEscapeEntry,
171
+ topDeliberateSurface,
171
172
  } from '@/utils/overlayEscapeStack';
172
173
  import { useId } from '@/composables/useId';
173
174
  import { useElementSize, useIntersectionObserver } from '@vueuse/core';
@@ -209,6 +210,7 @@ const props = withDefaults(defineProps<BbPopoverProps>(), {
209
210
  // A declared default disables that absent→false cast while still keeping the
210
211
  // Boolean type — so the `<Popover adaptive>` shorthand (valueless→`true`) works.
211
212
  adaptive: undefined,
213
+ modal: false,
212
214
  offset: 4,
213
215
  padding: 10,
214
216
  placement: 'bottom',
@@ -231,6 +233,15 @@ const activatorId = props.id ?? id.value;
231
233
  const popoverId = `bbp_${activatorId}`;
232
234
 
233
235
  const activatorEl = ref<HTMLElement>();
236
+ /**
237
+ * The id the panel is labelled by. An external activator that already has an
238
+ * id keeps it (like BbDropdown and BbSelectPopover): overwriting it broke the
239
+ * consumer's own `id` (an anchor target, a `<label for>`, a test hook). Only an
240
+ * element with no id gets `activatorId`.
241
+ */
242
+ const labelledById = computed(
243
+ () => (hasExternalActivator.value && activatorEl.value?.id) || activatorId
244
+ );
234
245
  const popoverRef = useTemplateRef('popover-ref');
235
246
  const popoverEl = computed(() => extractDomContainer(popoverRef.value));
236
247
 
@@ -286,7 +297,7 @@ const offcanvasBindings = computed(() => ({
286
297
  // BbOffCanvas already points `aria-labelledby` at that heading, and this
287
298
  // fallthrough attribute would win over it.
288
299
  ...(hasOpenedOnce.value && !props.offCanvasProps?.title
289
- ? { 'aria-labelledby': activatorId }
300
+ ? { 'aria-labelledby': labelledById.value }
290
301
  : {}),
291
302
  }));
292
303
 
@@ -405,12 +416,17 @@ watch(
405
416
  }
406
417
 
407
418
  el.setAttribute('aria-haspopup', 'dialog');
419
+ // Adopt an existing id; assign one only when absent, and take back only
420
+ // what was assigned.
421
+ const assignedId = !el.id;
422
+ if (assignedId) el.setAttribute('id', activatorId);
408
423
 
409
424
  onCleanup(() => {
410
425
  removers.forEach((fn) => fn());
411
426
  el.removeAttribute('aria-expanded');
412
427
  el.removeAttribute('aria-controls');
413
428
  el.removeAttribute('aria-haspopup');
429
+ if (assignedId && el.id === activatorId) el.removeAttribute('id');
414
430
  });
415
431
  },
416
432
  { immediate: true }
@@ -421,7 +437,6 @@ watch(
421
437
  [activatorEl, isOpen, hasOpenedOnce] as const,
422
438
  ([el, open, opened]) => {
423
439
  if (!el || !hasExternalActivator.value || !opened) return;
424
- el.setAttribute('id', activatorId);
425
440
  el.setAttribute('aria-expanded', String(open));
426
441
  el.setAttribute('aria-controls', popoverId);
427
442
  },
@@ -472,6 +487,113 @@ const onDocumentClick = (event: MouseEvent) => {
472
487
  }
473
488
  };
474
489
 
490
+ // --- Non-modal dismissal (Q60.10) ---
491
+ //
492
+ // Without `modal` the panel is a plain top-layer popover: the page stays live,
493
+ // so leaving the panel is how it closes. A press outside (the press itself
494
+ // still lands on what it hit: nothing here prevents it), or focus moving out
495
+ // (Tab past the last control, Shift+Tab before the first, a click that focuses
496
+ // something else), closes it. Neither returns focus to the activator, which
497
+ // would steal it from where the user just went.
498
+
499
+ /** The `role` a non-modal panel needs: a `<div>` is no dialog on its own. */
500
+ const nonModalAttrs = computed(() =>
501
+ props.modal ? {} : { role: 'dialog' as const }
502
+ );
503
+
504
+ /** Set by an outside dismissal, so the close leaves focus where it went. */
505
+ let dismissedOutside = false;
506
+
507
+ /**
508
+ * True from a press on the activator until the task that delivers it ends.
509
+ * The press focuses the activator before its click toggles the panel; that
510
+ * `focusin` is not the user leaving (the click owns the toggle). A keyboard
511
+ * move onto the activator (Shift+Tab out of the panel) is not a press, and
512
+ * still closes. Same guard as BbDropdown.
513
+ */
514
+ let activatorPress = false;
515
+
516
+ /**
517
+ * Whether `target` belongs to an overlay opened on top of this panel (a menu or
518
+ * a dialog launched from inside it): that overlay owns the interaction, as it
519
+ * owns Escape. A press outside everything still closes both.
520
+ */
521
+ const ownedByOverlayOnTop = (target: Node) => {
522
+ if (isTopEscapeEntry(escapeKey)) return false;
523
+ const top = topDeliberateSurface();
524
+ if (!top) return false;
525
+ return !top.element || top.element.contains(target);
526
+ };
527
+
528
+ /**
529
+ * The `<dialog>`s around the activator that were already open when the panel
530
+ * opened. One that opens later (a dialog mounted open with this popover open
531
+ * inside it) moves focus to its own first control: that is the dialog's
532
+ * initial focus, not the user leaving, so its first `focusin` is let through.
533
+ */
534
+ let hostDialogs = new Set<HTMLDialogElement>();
535
+ const collectHostDialogs = () => {
536
+ hostDialogs = new Set();
537
+ let dialog = activatorEl.value?.closest('dialog');
538
+ while (dialog) {
539
+ if (dialog.open) hostDialogs.add(dialog);
540
+ dialog = dialog.parentElement?.closest('dialog');
541
+ }
542
+ };
543
+
544
+ const dismissOutside = () => {
545
+ dismissedOutside = true;
546
+ close();
547
+ };
548
+
549
+ const onDocumentPointerDown = (event: PointerEvent) => {
550
+ if (event.timeStamp <= listenersAddedAt) return;
551
+ const target = event.target;
552
+ if (!(target instanceof Node)) return;
553
+ if (activatorEl.value?.contains(target)) {
554
+ activatorPress = true;
555
+ setTimeout(() => (activatorPress = false), 0);
556
+ return;
557
+ }
558
+ if (popoverEl.value?.contains(target)) return;
559
+ if (ownedByOverlayOnTop(target)) return;
560
+ dismissOutside();
561
+ };
562
+
563
+ /**
564
+ * A click outside with no press before it (a scripted `.click()`, a keyboard
565
+ * activation of an outside control) closes too. After a real press the panel
566
+ * is already closed and this does nothing.
567
+ */
568
+ const onDocumentOutsideClick = (event: MouseEvent) => {
569
+ if (!isOpen.value || event.timeStamp <= listenersAddedAt) return;
570
+ const target = event.target;
571
+ if (!(target instanceof Node)) return;
572
+ if (activatorEl.value?.contains(target)) return;
573
+ if (popoverEl.value?.contains(target)) return;
574
+ if (ownedByOverlayOnTop(target)) return;
575
+ dismissOutside();
576
+ };
577
+
578
+ const onDocumentFocusIn = (event: FocusEvent) => {
579
+ const target = event.target;
580
+ if (!(target instanceof Node)) return;
581
+ const panel = popoverEl.value;
582
+ if (panel?.contains(target)) return;
583
+ if (activatorPress && activatorEl.value?.contains(target)) return;
584
+ // Focus landing on an ANCESTOR of the panel is the browser's fallback for a
585
+ // press on non-focusable panel content (the panel renders in place), not
586
+ // the user going elsewhere.
587
+ if (target instanceof Element && panel && target.contains(panel)) return;
588
+ const host = target instanceof Element ? target.closest('dialog') : null;
589
+ if (host && panel && host.contains(panel) && !hostDialogs.has(host)) {
590
+ hostDialogs.add(host);
591
+ return;
592
+ }
593
+ if (ownedByOverlayOnTop(target)) return;
594
+ dismissOutside();
595
+ };
596
+
475
597
  // Identifies this popover instance in the module-level Escape stack.
476
598
  const escapeKey = Symbol('bb-popover');
477
599
 
@@ -490,8 +612,26 @@ const addGlobalListeners = () => {
490
612
  // inside it (Q63.7).
491
613
  pushEscapeEntry(escapeKey, { element: () => popoverEl.value });
492
614
  listenersAddedAt = performance.now();
493
- document.addEventListener('click', onDocumentClick, { passive: true });
494
- document.addEventListener('contextmenu', onDocumentClick, { passive: true });
615
+ if (props.modal) {
616
+ document.addEventListener('click', onDocumentClick, { passive: true });
617
+ document.addEventListener('contextmenu', onDocumentClick, {
618
+ passive: true,
619
+ });
620
+ } else {
621
+ dismissedOutside = false;
622
+ collectHostDialogs();
623
+ document.addEventListener('pointerdown', onDocumentPointerDown, {
624
+ passive: true,
625
+ capture: true,
626
+ });
627
+ document.addEventListener('focusin', onDocumentFocusIn, { passive: true });
628
+ document.addEventListener('click', onDocumentOutsideClick, {
629
+ passive: true,
630
+ });
631
+ document.addEventListener('contextmenu', onDocumentOutsideClick, {
632
+ passive: true,
633
+ });
634
+ }
495
635
  document.addEventListener('keydown', onKeydown, { capture: true });
496
636
  };
497
637
 
@@ -499,6 +639,12 @@ const removeGlobalListeners = () => {
499
639
  removeEscapeEntry(escapeKey);
500
640
  document.removeEventListener('click', onDocumentClick);
501
641
  document.removeEventListener('contextmenu', onDocumentClick);
642
+ document.removeEventListener('pointerdown', onDocumentPointerDown, {
643
+ capture: true,
644
+ });
645
+ document.removeEventListener('focusin', onDocumentFocusIn);
646
+ document.removeEventListener('click', onDocumentOutsideClick);
647
+ document.removeEventListener('contextmenu', onDocumentOutsideClick);
502
648
  document.removeEventListener('keydown', onKeydown, { capture: true });
503
649
  };
504
650
 
@@ -554,9 +700,9 @@ const runCloseEffects = () => {
554
700
 
555
701
  removeGlobalListeners();
556
702
 
557
- if (activatorEl.value) {
558
- activatorEl.value.focus();
559
- }
703
+ // An outside dismissal leaves focus where the user took it (Q60.10).
704
+ if (dismissedOutside) dismissedOutside = false;
705
+ else if (activatorEl.value) activatorEl.value.focus();
560
706
  };
561
707
 
562
708
  // Set by a floating close until CommonPopover reports `hidden`. A close that
@@ -842,7 +988,8 @@ export type BbPopoverProps = {
842
988
  */
843
989
  disabled?: boolean;
844
990
  /**
845
- * Prevents rendering content before it's made visible.
991
+ * Renders the panel's content at mount instead of on the first open
992
+ * (the phone sheet's too).
846
993
  */
847
994
  eager?: boolean;
848
995
  /**
@@ -855,6 +1002,17 @@ export type BbPopoverProps = {
855
1002
  * Generated when omitted.
856
1003
  */
857
1004
  id?: HTMLAttributes['id'];
1005
+ /**
1006
+ * Makes the floating panel modal: the page behind it goes inert and
1007
+ * cannot scroll, and Tab stays inside the panel until it closes. Off by
1008
+ * default, the panel is a non-modal dialog: the page stays usable, a
1009
+ * click outside closes it and still reaches what was clicked, and Tab
1010
+ * past its last control (or Shift+Tab before its first) leaves it and
1011
+ * closes it. The phone sheet is modal either way.
1012
+ *
1013
+ * @defaultValue `false`
1014
+ */
1015
+ modal?: boolean;
858
1016
  /**
859
1017
  * Space the floating container will maintain from the activator.
860
1018
  *
@@ -986,6 +1144,21 @@ export type BbPopoverSlots = {
986
1144
  */
987
1145
  footer?: (props: BbPopoverDefaultSlotProps) => any;
988
1146
  };
1147
+
1148
+ /**
1149
+ * The default slot scope of `<BbPopoverPortal>`: the ONE place this family's
1150
+ * portal slot is typed (Q63.8), so tooling that infers `props` from the call
1151
+ * sites hooks a single type: `P`, the type of `props`, is the seam it will
1152
+ * feed (through a type-only prop on the portal component). Until then `P` is
1153
+ * `any`, so `props.person.name` type-checks with no cast.
1154
+ */
1155
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- the default is the point (Q63.8)
1156
+ export type BbPopoverPortalSlotProps<P = any> = {
1157
+ /** The `portalProps` the `v-bb-popover` passed. */
1158
+ props: P;
1159
+ /** Closes the popover. */
1160
+ close: () => void;
1161
+ };
989
1162
  ```
990
1163
 
991
1164
  ## Styles
@@ -8,8 +8,8 @@
8
8
  <template><!-- registers content; renders nothing of its own --></template>
9
9
  <script setup lang="ts">
10
10
  import { watchEffect } from 'vue';
11
+ import type { BbPopoverPortalSlotProps } from './types';
11
12
  import {
12
- type DirectivePortalSlotProps,
13
13
  popoverPortals,
14
14
  useDirectivePortal,
15
15
  } from '@/directives/directivePortal';
@@ -25,7 +25,7 @@ const props = defineProps<{
25
25
  }>();
26
26
  const slots = defineSlots<{
27
27
  /** The popover body. `props` is the directive's `portalProps`; `close` closes the popover. */
28
- default?: (props: DirectivePortalSlotProps) => any;
28
+ default?: (props: BbPopoverPortalSlotProps) => any;
29
29
  }>();
30
30
 
31
31
  watchEffect(
@@ -131,7 +131,8 @@ export type BbPopoverProps = {
131
131
  */
132
132
  disabled?: boolean;
133
133
  /**
134
- * Prevents rendering content before it's made visible.
134
+ * Renders the panel's content at mount instead of on the first open
135
+ * (the phone sheet's too).
135
136
  */
136
137
  eager?: boolean;
137
138
  /**
@@ -144,6 +145,17 @@ export type BbPopoverProps = {
144
145
  * Generated when omitted.
145
146
  */
146
147
  id?: HTMLAttributes['id'];
148
+ /**
149
+ * Makes the floating panel modal: the page behind it goes inert and
150
+ * cannot scroll, and Tab stays inside the panel until it closes. Off by
151
+ * default, the panel is a non-modal dialog: the page stays usable, a
152
+ * click outside closes it and still reaches what was clicked, and Tab
153
+ * past its last control (or Shift+Tab before its first) leaves it and
154
+ * closes it. The phone sheet is modal either way.
155
+ *
156
+ * @defaultValue `false`
157
+ */
158
+ modal?: boolean;
147
159
  /**
148
160
  * Space the floating container will maintain from the activator.
149
161
  *
@@ -275,6 +287,21 @@ export type BbPopoverSlots = {
275
287
  */
276
288
  footer?: (props: BbPopoverDefaultSlotProps) => any;
277
289
  };
290
+
291
+ /**
292
+ * The default slot scope of `<BbPopoverPortal>`: the ONE place this family's
293
+ * portal slot is typed (Q63.8), so tooling that infers `props` from the call
294
+ * sites hooks a single type: `P`, the type of `props`, is the seam it will
295
+ * feed (through a type-only prop on the portal component). Until then `P` is
296
+ * `any`, so `props.person.name` type-checks with no cast.
297
+ */
298
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- the default is the point (Q63.8)
299
+ export type BbPopoverPortalSlotProps<P = any> = {
300
+ /** The `portalProps` the `v-bb-popover` passed. */
301
+ props: P;
302
+ /** Closes the popover. */
303
+ close: () => void;
304
+ };
278
305
  ```
279
306
 
280
307
  ## Styles