bitboss-ui 3.0.0-beta.48 → 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 (356) hide show
  1. package/README.md +24 -7
  2. package/bin/bitboss-ui-mcp.mjs +15 -3
  3. package/bin/bitboss-ui.mjs +115 -13
  4. package/dist/ai/BbAvatar.md +1 -1
  5. package/dist/ai/BbBreadcrumbs.md +65 -65
  6. package/dist/ai/BbButton.md +16 -5
  7. package/dist/ai/BbCheckbox.md +0 -2
  8. package/dist/ai/BbCheckboxGroup.md +13 -20
  9. package/dist/ai/BbDatePickerInput.md +4 -2
  10. package/dist/ai/BbDialog.md +1 -8
  11. package/dist/ai/BbDropdown.md +231 -220
  12. package/dist/ai/BbDropdownButton.md +65 -65
  13. package/dist/ai/BbDropdownGroup.md +2 -2
  14. package/dist/ai/BbDropzone.md +10 -10
  15. package/dist/ai/BbForm.md +43 -52
  16. package/dist/ai/BbHoverCard.md +4 -2
  17. package/dist/ai/BbNumberInput.md +88 -21
  18. package/dist/ai/BbPopover.md +29 -23
  19. package/dist/ai/BbProgress.md +48 -22
  20. package/dist/ai/BbRadioGroup.md +13 -19
  21. package/dist/ai/BbSelect.md +16 -36
  22. package/dist/ai/BbSelectPopover.md +14 -30
  23. package/dist/ai/BbSmoothHeight.md +0 -2
  24. package/dist/ai/BbSwitchGroup.md +13 -20
  25. package/dist/ai/BbTable.md +11 -10
  26. package/dist/ai/BbTabs.md +106 -105
  27. package/dist/ai/BbTabsList.md +2 -2
  28. package/dist/ai/BbTabsPanels.md +1 -1
  29. package/dist/ai/BbTabsRoot.md +2 -2
  30. package/dist/ai/BbTooltip.md +24 -10
  31. package/dist/ai/BbTree.md +14 -11
  32. package/dist/ai/changelog.json +256 -5
  33. package/dist/ai/components.json +36 -34
  34. package/dist/ai/composables/useBbDropdownContext.md +16 -16
  35. package/dist/ai/composables/useBbFormField.md +5 -1
  36. package/dist/ai/composables/useBbTabsContext.md +14 -14
  37. package/dist/ai/guides/agent-contract.md +27 -27
  38. package/dist/ai/guides/ai-router.md +1 -1
  39. package/dist/ai/guides/component-picker.md +3 -3
  40. package/dist/ai/guides/fetch-items-playbook.md +1 -1
  41. package/dist/ai/guides/icons-policy.md +10 -10
  42. package/dist/ai/guides/inertia-helpers.md +120 -67
  43. package/dist/ai/guides/installation-and-plugin-setup.md +43 -15
  44. package/dist/ai/guides/migration/components/bb-breadcrumbs.md +3 -2
  45. package/dist/ai/guides/migration/components/bb-checkbox-group.md +16 -16
  46. package/dist/ai/guides/migration/components/bb-dropdown-button.md +9 -8
  47. package/dist/ai/guides/migration/components/bb-dropdown.md +15 -14
  48. package/dist/ai/guides/migration/components/bb-radio-group.md +2 -1
  49. package/dist/ai/guides/migration/components/bb-select-popover.md +6 -1
  50. package/dist/ai/guides/migration/components/bb-select.md +10 -2
  51. package/dist/ai/guides/migration/components/bb-switch-group.md +2 -1
  52. package/dist/ai/guides/migration/components/bb-tabs.md +9 -8
  53. package/dist/ai/guides/migration/components/bb-tooltip.md +1 -1
  54. package/dist/ai/guides/migration/v2-to-v3.md +114 -17
  55. package/dist/ai/guides/migration/v3-beta-tooling.md +11 -0
  56. package/dist/ai/guides/options-items-playbook.md +30 -24
  57. package/dist/ai/guides/passthrough.md +2 -2
  58. package/dist/ai/guides/preset-components.md +18 -3
  59. package/dist/ai/guides/typescript-generic-components.md +1 -1
  60. package/dist/ai/guides/validated-forms.md +11 -22
  61. package/dist/ai/guides/validation-providers.md +4 -3
  62. package/dist/ai/helpers/inertia/manifest.json +636 -0
  63. package/dist/ai/helpers/inertia/types.ts +15 -0
  64. package/dist/ai/helpers/inertia/useAsyncFn.ts +110 -0
  65. package/dist/ai/helpers/inertia/useConfirmOnRouteLeave.ts +102 -0
  66. package/dist/ai/helpers/inertia/useDeleteCmd.ts +30 -0
  67. package/dist/ai/helpers/inertia/useHasChanged.ts +36 -0
  68. package/dist/ai/helpers/inertia/useIndexById.ts +23 -0
  69. package/dist/ai/helpers/inertia/useLazyProp.ts +148 -0
  70. package/dist/ai/helpers/inertia/useLazyPropGetter.ts +50 -0
  71. package/dist/ai/helpers/inertia/useLoading.ts +20 -0
  72. package/dist/ai/helpers/inertia/usePaginatedResponseContext.ts +88 -0
  73. package/dist/ai/helpers/inertia/usePromiseForm.ts +62 -0
  74. package/dist/ai/helpers/inertia/useProp.ts +63 -0
  75. package/dist/ai/helpers/inertia/useQuery.ts +19 -0
  76. package/dist/ai/helpers/inertia/useQueryObject.ts +116 -0
  77. package/dist/ai/helpers/inertia/useResourceContext.ts +69 -0
  78. package/dist/ai/helpers/inertia/useRouteQuery.ts +54 -0
  79. package/dist/ai/helpers/inertia/useScreenSizes.ts +23 -0
  80. package/dist/ai/helpers/inertia/useTableContext.ts +34 -0
  81. package/dist/ai/helpers/inertia/useTableSelectionContext.ts +48 -0
  82. package/dist/ai/helpers/inertia/useUntil.ts +33 -0
  83. package/dist/ai/helpers/inertia/utils.ts +24 -0
  84. package/dist/ai/index.md +6 -6
  85. package/dist/ai/manifest/components/BbBreadcrumbs.json +10 -6
  86. package/dist/ai/manifest/components/BbBreadcrumbs.tree.json +1 -1
  87. package/dist/ai/manifest/components/BbButton.json +1 -1
  88. package/dist/ai/manifest/components/BbCheckboxGroup.json +2 -2
  89. package/dist/ai/manifest/components/BbDropdown.json +23 -20
  90. package/dist/ai/manifest/components/BbDropdown.tree.json +2 -2
  91. package/dist/ai/manifest/components/BbDropdownButton.json +22 -19
  92. package/dist/ai/manifest/components/BbDropdownButton.tree.json +1 -1
  93. package/dist/ai/manifest/components/BbDropdownGroup.json +2 -2
  94. package/dist/ai/manifest/components/BbForm.json +1 -0
  95. package/dist/ai/manifest/components/BbNumberInput.json +6 -1
  96. package/dist/ai/manifest/components/BbNumberInput.tree.json +2 -1
  97. package/dist/ai/manifest/components/BbPopover.json +1 -0
  98. package/dist/ai/manifest/components/BbProgress.json +6 -6
  99. package/dist/ai/manifest/components/BbProgress.tree.json +1 -0
  100. package/dist/ai/manifest/components/BbRadioGroup.json +2 -2
  101. package/dist/ai/manifest/components/BbSelect.json +2 -2
  102. package/dist/ai/manifest/components/BbSelectPopover.json +2 -2
  103. package/dist/ai/manifest/components/BbSwitchGroup.json +2 -2
  104. package/dist/ai/manifest/components/BbTabs.json +7 -6
  105. package/dist/ai/manifest/components/BbTabsList.json +3 -3
  106. package/dist/ai/manifest/components/BbTabsPanels.json +1 -1
  107. package/dist/ai/manifest/components/BbTabsRoot.json +5 -4
  108. package/dist/ai/manifest/components/BbTooltip.json +1 -1
  109. package/dist/ai/manifest/index.json +2 -2
  110. package/dist/ai/manifest/meta.json +2 -0
  111. package/dist/ai/manifest/types.advanced.json +10 -9
  112. package/dist/ai/manifest/types.api.json +5 -4
  113. package/dist/ai/recipes/inertia/approvals-inbox.md +16 -18
  114. package/dist/ai/recipes/inertia/inline-edit-workspace.md +23 -33
  115. package/dist/ai/recipes/inertia/layout-scaffold.md +16 -16
  116. package/dist/ai/recipes/inertia/onboarding.md +6 -10
  117. package/dist/ai/recipes/inertia/ownership-atlas.md +15 -18
  118. package/dist/ai/recipes/inertia/record-form.md +11 -11
  119. package/dist/ai/recipes/inertia/records-workspace.md +38 -41
  120. package/dist/ai/recipes/inertia/settings-workspace.md +26 -38
  121. package/dist/ai/recipes/inertia/upload-center.md +31 -39
  122. package/dist/ai/recipes/inertia/wizard-form.md +10 -19
  123. package/dist/ai/recipes/nuxt/approvals-inbox.md +7 -8
  124. package/dist/ai/recipes/nuxt/inline-edit-workspace.md +14 -24
  125. package/dist/ai/recipes/nuxt/layout-scaffold.md +16 -16
  126. package/dist/ai/recipes/nuxt/onboarding.md +2 -6
  127. package/dist/ai/recipes/nuxt/ownership-atlas.md +7 -9
  128. package/dist/ai/recipes/nuxt/record-form.md +5 -5
  129. package/dist/ai/recipes/nuxt/records-workspace.md +29 -31
  130. package/dist/ai/recipes/nuxt/settings-workspace.md +22 -34
  131. package/dist/ai/recipes/nuxt/upload-center.md +22 -29
  132. package/dist/ai/recipes/nuxt/wizard-form.md +3 -11
  133. package/dist/ai/recipes/vue/approvals-inbox.md +7 -8
  134. package/dist/ai/recipes/vue/inline-edit-workspace.md +14 -24
  135. package/dist/ai/recipes/vue/layout-scaffold.md +16 -16
  136. package/dist/ai/recipes/vue/onboarding.md +2 -6
  137. package/dist/ai/recipes/vue/ownership-atlas.md +7 -9
  138. package/dist/ai/recipes/vue/record-form.md +5 -5
  139. package/dist/ai/recipes/vue/records-workspace.md +29 -31
  140. package/dist/ai/recipes/vue/settings-workspace.md +22 -34
  141. package/dist/ai/recipes/vue/upload-center.md +22 -29
  142. package/dist/ai/recipes/vue/wizard-form.md +3 -11
  143. package/dist/ai/source/BbAccordion.md +1 -1
  144. package/dist/ai/source/BbAlert.md +3 -3
  145. package/dist/ai/source/BbBadge.md +2 -2
  146. package/dist/ai/source/BbBadgeButton.md +5 -4
  147. package/dist/ai/source/BbBaseButton.md +1 -1
  148. package/dist/ai/source/BbBaseRadioIcon.md +1 -0
  149. package/dist/ai/source/BbBaseSwitchIcon.md +1 -0
  150. package/dist/ai/source/BbBreadcrumbs.md +63 -42
  151. package/dist/ai/source/BbButton.md +71 -33
  152. package/dist/ai/source/BbCalendar.md +17 -16
  153. package/dist/ai/source/BbCheckbox.md +3 -2
  154. package/dist/ai/source/BbCheckboxGroup.md +11 -4
  155. package/dist/ai/source/BbColorInput.md +10 -9
  156. package/dist/ai/source/BbConfirm.md +1 -1
  157. package/dist/ai/source/BbConfirmPortal.md +1 -1
  158. package/dist/ai/source/BbDatePicker.md +2 -2
  159. package/dist/ai/source/BbDatePickerInput.md +47 -20
  160. package/dist/ai/source/BbDialog.md +5 -5
  161. package/dist/ai/source/BbDropdown.md +230 -158
  162. package/dist/ai/source/BbDropdownButton.md +19 -12
  163. package/dist/ai/source/BbDropdownGroup.md +126 -93
  164. package/dist/ai/source/BbForm.md +25 -1
  165. package/dist/ai/source/BbIndicator.md +4 -0
  166. package/dist/ai/source/BbNumberInput.md +855 -19
  167. package/dist/ai/source/BbOffCanvas.md +27 -11
  168. package/dist/ai/source/BbPagination.md +3 -3
  169. package/dist/ai/source/BbPopover.md +152 -8
  170. package/dist/ai/source/BbPopoverPortal.md +11 -0
  171. package/dist/ai/source/BbProgress.md +82 -18
  172. package/dist/ai/source/BbRadioGroup.md +12 -5
  173. package/dist/ai/source/BbRating.md +11 -9
  174. package/dist/ai/source/BbSelect.md +16 -10
  175. package/dist/ai/source/BbSelectPopover.md +29 -23
  176. package/dist/ai/source/BbSlider.md +12 -6
  177. package/dist/ai/source/BbSwitch.md +3 -2
  178. package/dist/ai/source/BbSwitchGroup.md +5 -2
  179. package/dist/ai/source/BbTable.md +102 -18
  180. package/dist/ai/source/BbTabs.md +27 -23
  181. package/dist/ai/source/BbTabsList.md +26 -22
  182. package/dist/ai/source/BbTabsPanels.md +26 -22
  183. package/dist/ai/source/BbTabsRoot.md +25 -21
  184. package/dist/ai/source/BbTag.md +10 -9
  185. package/dist/ai/source/BbTextInput.md +5 -4
  186. package/dist/ai/source/BbTextarea.md +6 -5
  187. package/dist/ai/source/BbTimePicker.md +1 -1
  188. package/dist/ai/source/BbTimePickerInput.md +46 -9
  189. package/dist/ai/source/BbToast.md +10 -7
  190. package/dist/ai/source/BbToastPortal.md +10 -7
  191. package/dist/ai/source/BbTooltip.md +54 -8
  192. package/dist/ai/source/BbTree.md +21 -3
  193. package/dist/ai/source/CommonField.md +6 -4
  194. package/dist/ai/source/CommonFieldInput.md +15 -10
  195. package/dist/ai/source/CommonPopover.md +6 -0
  196. package/dist/ai/source/CommonTimeSelector.md +5 -4
  197. package/dist/components/BbBadge/BbBadgeButton.vue_vue_type_script_setup_true_lang.js +10 -8
  198. package/dist/components/BbBaseButton/BbBaseButton.vue_vue_type_script_setup_true_lang.js +8 -8
  199. package/dist/components/BbBreadcrumbs/BbBreadcrumbs.vue_vue_type_script_setup_true_lang.js +45 -45
  200. package/dist/components/BbBreadcrumbs/types.d.ts +25 -17
  201. package/dist/components/BbButton/BbButton.vue_vue_type_script_setup_true_lang.js +84 -71
  202. package/dist/components/BbButton/toggleRoving.d.ts +6 -0
  203. package/dist/components/BbButton/toggleRoving.js +45 -0
  204. package/dist/components/BbButton/types.d.ts +4 -1
  205. package/dist/components/BbCalendar/BbCalendar.vue_vue_type_script_setup_true_lang.js +178 -178
  206. package/dist/components/BbCalendar/CalendarMonthPanel.vue_vue_type_script_setup_true_lang.js +15 -15
  207. package/dist/components/BbCalendar/CalendarYearPanel.vue_vue_type_script_setup_true_lang.js +28 -28
  208. package/dist/components/BbCalendar/useCalendarGrid.js +141 -139
  209. package/dist/components/BbCalendar/useDayjsLocale.d.ts +38 -15
  210. package/dist/components/BbCalendar/useDayjsLocale.js +31 -30
  211. package/dist/components/BbCheckbox/BbCheckbox.vue_vue_type_script_setup_true_lang.js +48 -48
  212. package/dist/components/BbCheckboxGroup/BbCheckboxGroup.vue_vue_type_script_setup_true_lang.js +81 -80
  213. package/dist/components/BbCheckboxGroup/types.d.ts +6 -2
  214. package/dist/components/BbColorInput/BbColorInput.vue_vue_type_script_setup_true_lang.js +69 -69
  215. package/dist/components/BbDatePickerInput/BbDatePickerInput.vue_vue_type_script_setup_true_lang.js +363 -349
  216. package/dist/components/BbDropdown/AdaptiveDropdown.vue_vue_type_script_setup_true_lang.js +91 -86
  217. package/dist/components/BbDropdown/BbDropdown.vue_vue_type_script_setup_true_lang.js +298 -289
  218. package/dist/components/BbDropdown/BbDropdownList.vue_vue_type_script_setup_true_lang.js +322 -356
  219. package/dist/components/BbDropdown/DropdownPipelineResolver.vue_vue_type_script_setup_true_lang.js +17 -15
  220. package/dist/components/BbDropdown/DropdownRow.vue.d.ts +40 -0
  221. package/dist/components/BbDropdown/DropdownRow.vue.js +5 -0
  222. package/dist/components/BbDropdown/DropdownRow.vue_vue_type_script_setup_true_lang.js +60 -0
  223. package/dist/components/BbDropdown/normalizeGroups.d.ts +8 -2
  224. package/dist/components/BbDropdown/normalizeGroups.js +60 -46
  225. package/dist/components/BbDropdown/types.d.ts +119 -88
  226. package/dist/components/BbDropdownButton/BbDropdownButton.vue_vue_type_script_setup_true_lang.js +11 -2
  227. package/dist/components/BbDropdownButton/types.d.ts +2 -2
  228. package/dist/components/BbForm/BbForm.vue.d.ts +9 -0
  229. package/dist/components/BbForm/BbForm.vue_vue_type_script_setup_true_lang.js +114 -105
  230. package/dist/components/BbForm/BbFormCustomField.js +1 -1
  231. package/dist/components/BbForm/bindFormField.js +2 -1
  232. package/dist/components/BbForm/formFields.d.ts +5 -0
  233. package/dist/components/BbNumberInput/BbNumberInput.vue.d.ts +0 -1
  234. package/dist/components/BbNumberInput/BbNumberInput.vue_vue_type_script_setup_true_lang.js +452 -125
  235. package/dist/components/BbNumberInput/numberDisplay.d.ts +256 -0
  236. package/dist/components/BbNumberInput/numberDisplay.js +499 -0
  237. package/dist/components/BbNumberInput/types.d.ts +54 -1
  238. package/dist/components/BbNumberInput/warroom/corpus.d.ts +58 -0
  239. package/dist/components/BbNumberInput/warroom/currency-verify.rows.d.ts +28 -0
  240. package/dist/components/BbNumberInput/warroom/currency.rows.d.ts +2 -0
  241. package/dist/components/BbNumberInput/warroom/harness.d.ts +217 -0
  242. package/dist/components/BbNumberInput/warroom/oracle.d.ts +150 -0
  243. package/dist/components/BbPagination/BbPagination.vue_vue_type_script_setup_true_lang.js +7 -7
  244. package/dist/components/BbPopover/BbPopover.vue.d.ts +1 -0
  245. package/dist/components/BbPopover/BbPopover.vue_vue_type_script_setup_true_lang.js +207 -164
  246. package/dist/components/BbPopover/types.d.ts +11 -0
  247. package/dist/components/BbProgress/BbProgress.vue_vue_type_script_setup_true_lang.js +15 -7
  248. package/dist/components/BbProgress/types.d.ts +23 -7
  249. package/dist/components/BbProgress/types.js +1 -1
  250. package/dist/components/BbRadioGroup/BbRadioGroup.vue_vue_type_script_setup_true_lang.js +102 -101
  251. package/dist/components/BbRadioGroup/types.d.ts +6 -2
  252. package/dist/components/BbRating/BbRating.vue_vue_type_script_setup_true_lang.js +63 -63
  253. package/dist/components/BbSelect/BbSelect.vue_vue_type_script_setup_true_lang.js +156 -154
  254. package/dist/components/BbSelect/types.d.ts +6 -2
  255. package/dist/components/BbSelectPopover/BbSelectPopover.vue_vue_type_script_setup_true_lang.js +2 -1
  256. package/dist/components/BbSelectPopover/types.d.ts +6 -2
  257. package/dist/components/BbSlider/BbSlider.vue_vue_type_script_setup_true_lang.js +153 -153
  258. package/dist/components/BbSwitch/BbSwitch.vue_vue_type_script_setup_true_lang.js +62 -62
  259. package/dist/components/BbSwitchGroup/BbSwitchGroup.vue_vue_type_script_setup_true_lang.js +131 -130
  260. package/dist/components/BbTable/BbTable.vue_vue_type_script_setup_true_lang.js +711 -676
  261. package/dist/components/BbTabs/BbTabs.vue_vue_type_script_setup_true_lang.js +1 -1
  262. package/dist/components/BbTabs/BbTabsList.vue_vue_type_script_setup_true_lang.js +1 -1
  263. package/dist/components/BbTabs/types.d.ts +25 -21
  264. package/dist/components/BbTag/BbTag.vue_vue_type_script_setup_true_lang.js +76 -76
  265. package/dist/components/BbTextInput/BbTextInput.vue_vue_type_script_setup_true_lang.js +58 -58
  266. package/dist/components/BbTextarea/BbTextarea.vue_vue_type_script_setup_true_lang.js +82 -82
  267. package/dist/components/BbTimePickerInput/BbTimePickerInput.vue_vue_type_script_setup_true_lang.js +246 -236
  268. package/dist/components/BbTooltip/BbTooltip.vue_vue_type_script_setup_true_lang.js +102 -97
  269. package/dist/components/BbTooltip/tooltipWarmup.d.ts +23 -0
  270. package/dist/components/BbTooltip/tooltipWarmup.js +7 -0
  271. package/dist/components/BbTooltip/types.d.ts +7 -2
  272. package/dist/components/BbTree/BbTree.vue_vue_type_script_setup_true_lang.js +29 -21
  273. package/dist/components/BbTree/BbTreeLevel.vue_vue_type_script_setup_true_lang.js +10 -7
  274. package/dist/components/CommonFieldInput/CommonFieldInput.vue_vue_type_script_setup_true_lang.js +37 -36
  275. package/dist/components/CommonTimeSelector/CommonTimeSelector.vue_vue_type_script_setup_true_lang.js +9 -9
  276. package/dist/composables/formSubmitLock.d.ts +6 -0
  277. package/dist/composables/formSubmitLock.js +4 -0
  278. package/dist/composables/useBaseOptions.d.ts +7 -1
  279. package/dist/composables/useBaseOptions.js +32 -32
  280. package/dist/composables/useBbDropdownContext.d.ts +8 -8
  281. package/dist/composables/useBbFormField.d.ts +9 -0
  282. package/dist/composables/useBbFormField.js +5 -3
  283. package/dist/composables/useBbTabsContext.d.ts +10 -10
  284. package/dist/composables/useBbTabsContext.js +18 -18
  285. package/dist/composables/useFormBinding.d.ts +11 -0
  286. package/dist/composables/useFormBinding.js +15 -13
  287. package/dist/composables/useItemText.d.ts +5 -1
  288. package/dist/composables/useItemText.js +8 -3
  289. package/dist/composables/useItemValue.d.ts +5 -1
  290. package/dist/composables/useItemValue.js +8 -3
  291. package/dist/composables/useLocale.js +10 -9
  292. package/dist/deprecation/ai-deprecations.json.d.ts +130 -0
  293. package/dist/deprecation/ai-deprecations.json.js +1 -1
  294. package/dist/deprecation/removedProps.js +1 -1
  295. package/dist/directives/bbDropdown.js +1 -1
  296. package/dist/i18n/index.d.ts +7 -12
  297. package/dist/i18n/locales/cs.json +11 -14
  298. package/dist/i18n/locales/da.json +13 -16
  299. package/dist/i18n/locales/de-CH.json +137 -0
  300. package/dist/i18n/locales/de.json +14 -17
  301. package/dist/i18n/locales/el.json +10 -13
  302. package/dist/i18n/locales/en-GB.json +137 -0
  303. package/dist/i18n/locales/en.json +8 -11
  304. package/dist/i18n/locales/es-MX.json +137 -0
  305. package/dist/i18n/locales/es.json +16 -19
  306. package/dist/i18n/locales/fi.json +8 -11
  307. package/dist/i18n/locales/fr.json +23 -26
  308. package/dist/i18n/locales/hu.json +8 -11
  309. package/dist/i18n/locales/it.json +12 -15
  310. package/dist/i18n/locales/ja.json +13 -16
  311. package/dist/i18n/locales/ko.json +10 -13
  312. package/dist/i18n/locales/nb.json +13 -16
  313. package/dist/i18n/locales/nl.json +21 -24
  314. package/dist/i18n/locales/pl.json +10 -13
  315. package/dist/i18n/locales/{pt.json → pt-BR.json} +19 -22
  316. package/dist/i18n/locales/pt-PT.json +137 -0
  317. package/dist/i18n/locales/ro.json +22 -25
  318. package/dist/i18n/locales/ru.json +11 -14
  319. package/dist/i18n/locales/sv.json +16 -19
  320. package/dist/i18n/locales/tr.json +14 -17
  321. package/dist/i18n/locales/uk.json +11 -14
  322. package/dist/i18n/locales/{zh-cn.json → zh-CN.json} +10 -13
  323. package/dist/i18n/locales/zh-HK.json +137 -0
  324. package/dist/i18n/locales/zh-TW.json +137 -0
  325. package/dist/i18n/regionHints.d.ts +16 -0
  326. package/dist/i18n/regionHints.js +49 -0
  327. package/dist/i18n/regions.d.ts +286 -0
  328. package/dist/i18n/regions.js +265 -0
  329. package/dist/index.d.ts +1 -1
  330. package/dist/index.js +4 -4
  331. package/dist/llms-full.txt +1785 -1637
  332. package/dist/llms-medium.txt +74 -46
  333. package/dist/llms.txt +7 -7
  334. package/dist/locale-blueprint.json +16 -13
  335. package/dist/styles.css +2 -2
  336. package/dist/types/ptComponentMap.d.ts +1 -1
  337. package/dist/utilities/functions/slotKey.d.ts +2 -2
  338. package/dist/utils/versionCheck.js +1 -1
  339. package/dist/vite-plugin.d.ts +22 -19
  340. package/dist/vite.js +309 -297
  341. package/llms.txt +7 -7
  342. package/package.json +5 -3
  343. package/scripts/lib/agent-manifest.mjs +2 -1
  344. package/scripts/lib/eslint-disable.mjs +12 -4
  345. package/scripts/lib/eslint-plugin.d.ts +5 -1
  346. package/scripts/lib/eslint-plugin.mjs +187 -6
  347. package/scripts/lib/helper-canon.mjs +176 -0
  348. package/scripts/lib/helpers-add.mjs +1303 -0
  349. package/scripts/lib/local-components.mjs +33 -4
  350. package/scripts/lib/locale-check.mjs +165 -0
  351. package/scripts/lib/redundant-item-accessor.mjs +398 -0
  352. package/scripts/lib/renamed-item-field.mjs +343 -0
  353. package/scripts/lib/slot-key.mjs +2 -2
  354. package/scripts/lib/slot-renames.mjs +1 -1
  355. package/scripts/lib/validate-bb-markup.mjs +123 -56
  356. package/dist/i18n/index.js +0 -27
@@ -48,31 +48,33 @@ handling in markup — hand `BbDropdown` an `items` array.
48
48
 
49
49
  An `items` entry is one of three shapes, and you can mix them freely:
50
50
 
51
- - a **menu item** — an object with a `key` and a `text`;
51
+ - a **menu item** — an object with a `value` and a `label`;
52
52
  - a **separator section** — a nested `[ … ]` array, rendered as its own
53
53
  divider-separated anonymous group;
54
- - a **group object** — `{ key, label?, items, selectable?, … }`, a titled and/or
55
- selectable section (next sections). A group's heading is `label` (not `text`);
54
+ - a **group object** — `{ id, label?, items, selectable?, … }`, a titled and/or
55
+ selectable section (next sections). A group's heading is its `label` too;
56
56
  add `hideLabel` to keep the `label` for the adaptive sheet title / chips /
57
57
  `useBbDropdownContext` while rendering no heading in the menu.
58
58
 
59
59
  Each item extends `BbBaseButton`'s prop surface, so an item is an action, a
60
60
  link, or a submenu opener depending on which fields it carries:
61
61
 
62
- - `key` — stable identity. **Required** wherever something outside the menu
63
- reads it: a row in a `selectable` group (the v-model holds it), a row or
64
- group with a slot of its own (`#<key>` is named by it), and a group that is
65
- selectable or bound by a `<BbDropdownGroup id>`. **Optional** on a plain
66
- action row (one with an `onClick`, `href` or submenu) and on a layout-only
67
- group: the dropdown then keys the row internally from its text, and nothing
68
- outside ever sees that identity. Why the split: an identifier something
69
- outside reads must be one you wrote — derived from the label it would change
70
- with every translation and copy edit. So a keyless row in a selectable group
71
- renders but can't be selected, and two keyless rows with the same text in one
72
- group need keys (the same text across groups is fine); `bitboss-ui check`
73
- flags both when the items are in the same file.
74
- - `text` — the label; `description` adds a muted second line (the row grows,
75
- icons stay aligned with the title line).
62
+ - `value` — a row's stable identity (a group's is its `id`). **Required**
63
+ wherever something outside the menu reads it: a row in a `selectable` group
64
+ (the v-model holds it), a row with a slot of its own (`#<value>` is named by
65
+ it), and a group that has a slot, is selectable or is bound by a
66
+ `<BbDropdownGroup id>` (its `id`). **Optional** on a plain action row (one
67
+ with an `onClick`, `href` or submenu) and on a layout-only group: the
68
+ dropdown then keys the row internally from its label, and nothing outside
69
+ ever sees that identity. Why the split: an identifier something outside
70
+ reads must be one you wrote — derived from the label it would change with
71
+ every translation and copy edit. So a row without a `value` in a selectable
72
+ group renders but can't be selected, and two such rows with the same label in
73
+ one group need values (the same label across groups is fine); `bitboss-ui
74
+ check` flags both (`missing-value`, `duplicate-row-label`) when the items are
75
+ in the same file.
76
+ - `label` — the row's text; `description` adds a muted second line (the row
77
+ grows, icons stay aligned with the title line).
76
78
  - `onClick` — makes it an **action**. Never navigate from here.
77
79
  - `href` (anchor / Inertia visit, with `method`/`data`) or `to` (vue-router) —
78
80
  makes it a **navigation link**; the dropdown renders an `<a>` / router link,
@@ -141,22 +143,22 @@ const { confirm } = useConfirm();
141
143
  const items: BbDropdownItem[] = [
142
144
  // Plain leaf actions carry an `onClick`.
143
145
  {
144
- key: 'rename',
145
- text: 'Rename',
146
+ value: 'rename',
147
+ label: 'Rename',
146
148
  'prepend:icon': 'lucide:pencil',
147
149
  onClick: () => (last.value = 'Renamed'),
148
150
  },
149
151
  {
150
- key: 'duplicate',
151
- text: 'Duplicate',
152
+ value: 'duplicate',
153
+ label: 'Duplicate',
152
154
  'prepend:icon': 'lucide:copy',
153
155
  onClick: () => (last.value = 'Duplicated'),
154
156
  },
155
157
  // A navigation item: the dropdown renders an <a>. Never wire navigation
156
158
  // through onClick — pass href (or `to` in a router app) instead.
157
159
  {
158
- key: 'preview',
159
- text: 'Open preview',
160
+ value: 'preview',
161
+ label: 'Open preview',
160
162
  'prepend:icon': 'lucide:external-link',
161
163
  href: '#preview',
162
164
  target: '_blank',
@@ -166,8 +168,8 @@ const items: BbDropdownItem[] = [
166
168
  // proceeds on a yes.
167
169
  [
168
170
  {
169
- key: 'delete',
170
- text: 'Delete file',
171
+ value: 'delete',
172
+ label: 'Delete file',
171
173
  description: 'This cannot be undone',
172
174
  'prepend:icon': 'lucide:trash-2',
173
175
  variant: 'destructive',
@@ -196,9 +198,9 @@ import type { BbDropdownItem } from 'bitboss-ui';
196
198
 
197
199
  const items: BbDropdownItem[] = [
198
200
  // Nuxt / vue-router route
199
- { key: 'settings', text: 'Settings', to: { name: 'settings' } },
201
+ { value: 'settings', label: 'Settings', to: { name: 'settings' } },
200
202
  // Inertia visit
201
- { key: 'logout', text: 'Log out', href: '/logout', method: 'post' },
203
+ { value: 'logout', label: 'Log out', href: '/logout', method: 'post' },
202
204
  ];
203
205
  </script>
204
206
  ```
@@ -258,8 +260,8 @@ const status = ref('Idle');
258
260
  // activator can stay busy while the work runs in the background.
259
261
  const items: BbDropdownItem[] = [
260
262
  {
261
- key: 'sync',
262
- text: 'Sync now',
263
+ value: 'sync',
264
+ label: 'Sync now',
263
265
  'prepend:icon': 'lucide:refresh-cw',
264
266
  onClick: async () => {
265
267
  status.value = 'Syncing…';
@@ -268,8 +270,8 @@ const items: BbDropdownItem[] = [
268
270
  },
269
271
  },
270
272
  {
271
- key: 'history',
272
- text: 'View sync history',
273
+ value: 'history',
274
+ label: 'View sync history',
273
275
  'prepend:icon': 'lucide:history',
274
276
  href: '#history',
275
277
  },
@@ -320,32 +322,32 @@ import type { BbDropdownItem } from 'bitboss-ui';
320
322
  // a chevron replaces the item's own `append:icon`.
321
323
  const items: BbDropdownItem[] = [
322
324
  {
323
- key: 'account',
324
- text: 'Account',
325
+ value: 'account',
326
+ label: 'Account',
325
327
  'prepend:icon': 'lucide:user',
326
328
  items: [
327
- { key: 'profile', text: 'View profile', href: '#profile' },
328
- { key: 'billing', text: 'Billing & plans', href: '#billing' },
329
+ { value: 'profile', label: 'View profile', href: '#profile' },
330
+ { value: 'billing', label: 'Billing & plans', href: '#billing' },
329
331
  {
330
- key: 'security',
331
- text: 'Security',
332
+ value: 'security',
333
+ label: 'Security',
332
334
  items: [
333
- { key: '2fa', text: 'Two-factor auth', href: '#2fa' },
334
- { key: 'sessions', text: 'Active sessions', href: '#sessions' },
335
+ { value: '2fa', label: 'Two-factor auth', href: '#2fa' },
336
+ { value: 'sessions', label: 'Active sessions', href: '#sessions' },
335
337
  ],
336
338
  },
337
339
  ],
338
340
  },
339
341
  {
340
- key: 'help',
341
- text: 'Help & support',
342
+ value: 'help',
343
+ label: 'Help & support',
342
344
  'prepend:icon': 'lucide:life-buoy',
343
345
  href: '#help',
344
346
  },
345
347
  [
346
348
  {
347
- key: 'signout',
348
- text: 'Sign out',
349
+ value: 'signout',
350
+ label: 'Sign out',
349
351
  'prepend:icon': 'lucide:log-out',
350
352
  href: '#signout',
351
353
  },
@@ -360,24 +362,24 @@ Turn a group into a chooser by marking it `selectable` (single choice, radio
360
362
  semantics) or `selectable` + `multiple` (many choices, checkbox semantics).
361
363
  Selected rows render a check on the right (replacing any `append:icon`).
362
364
  **Bind the selection with a `<BbDropdownGroup>` companion** whose `id` is the
363
- group's `key` (details below):
365
+ group's `id` (details below):
364
366
 
365
367
  ```vue
366
368
  <BbDropdown
367
369
  :items="[
368
370
  {
369
- key: 'status',
371
+ id: 'status',
370
372
  label: 'Status',
371
373
  selectable: true,
372
374
  multiple: true,
373
375
  items: [
374
- { key: 'open', text: 'Open' },
375
- { key: 'paid', text: 'Paid' },
376
+ { value: 'open', label: 'Open' },
377
+ { value: 'paid', label: 'Paid' },
376
378
  ],
377
379
  },
378
380
  ]"
379
381
  >
380
- <!-- selectedStatuses = ref<string[]>([]) — the checked rows' keys -->
382
+ <!-- selectedStatuses = ref<string[]>([]) — the checked rows' values -->
381
383
  <BbDropdownGroup id="status" v-model="selectedStatuses" />
382
384
  </BbDropdown>
383
385
  ```
@@ -391,7 +393,7 @@ Behavior you can rely on:
391
393
  (the same one included) also closes the menu;
392
394
  - a **multiple** group keeps the menu open while you toggle;
393
395
  - the dropdown emits `item:selected` / `item:unselected` with the item's
394
- **value** (its `item-value` for pipeline groups, else its `key`) when the user
396
+ **value** (its `itemValue` for pipeline groups, else its own `value`) when the user
395
397
  picks or unpicks a row, never for your own changes to a group's value — the
396
398
  same value shape and meaning as `BbTable`'s (and the companion's pair).
397
399
 
@@ -400,7 +402,7 @@ Behavior you can rely on:
400
402
 
401
403
  ```ts
402
404
  const statusGroup = {
403
- key: 'status',
405
+ id: 'status',
404
406
  multiple: true,
405
407
  selectable: (row: { archived?: boolean }) => !row.archived,
406
408
  items: statuses,
@@ -418,19 +420,19 @@ const statusGroup = {
418
420
  selected ones stay live so the user can swap.
419
421
  - The function receives the **row object** in a hand-written group and the
420
422
  **raw fetched item** in a fetched group.
421
- - `useBbDropdownContext(id).groups[key].selectable` stays a plain `true`.
423
+ - `useBbDropdownContext(id).groups[groupId].selectable` stays a plain `true`.
422
424
 
423
425
  This is also how a fetched row gets disabled — see
424
426
  [why fetched rows have no `disabled`](#additional-row-fields-itemprops).
425
427
 
426
428
  Selection state lives on the dropdown; a companion `<BbDropdownGroup>` in the
427
429
  default slot binds to it. The companion is intentionally minimal — it takes
428
- only the group's `id` (which must match the group's `key` in `items`) and a
430
+ only the group's `id` (which must match the group's `id` in `items`) and a
429
431
  `v-model`; the options themselves stay declared in the host's `items`. Its
430
432
  `v-model` seeds the initial selection before the menu ever opens, and it emits
431
433
  the same `item:selected` / `item:unselected` pair. Two hard rules, enforced
432
434
  with thrown errors: a `multiple` group's model must be an array, and the `id`
433
- must point at a _group_ (not a plain item, not a missing key).
435
+ must point at a _group_ (not a plain item, not a missing id).
434
436
 
435
437
  A companion you listen to (`v-model`, or `@update:model-value`) is
436
438
  **controlled**, like a `BbCheckbox`: the menu shows your value and nothing
@@ -491,24 +493,24 @@ import type { BbDropdownItem } from 'bitboss-ui';
491
493
  // `multiple` → many choices (checkbox semantics, stays open while toggling).
492
494
  const items: BbDropdownItem[] = [
493
495
  {
494
- key: 'sort',
496
+ id: 'sort',
495
497
  label: 'Sort by',
496
498
  selectable: true,
497
499
  items: [
498
- { key: 'recent', text: 'Most recent' },
499
- { key: 'name', text: 'Name (A–Z)' },
500
- { key: 'amount', text: 'Amount (high → low)' },
500
+ { value: 'recent', label: 'Most recent' },
501
+ { value: 'name', label: 'Name (A–Z)' },
502
+ { value: 'amount', label: 'Amount (high → low)' },
501
503
  ],
502
504
  },
503
505
  {
504
- key: 'tags',
506
+ id: 'tags',
505
507
  label: 'Tags',
506
508
  selectable: true,
507
509
  multiple: true,
508
510
  items: [
509
- { key: 'overdue', text: 'Overdue' },
510
- { key: 'vip', text: 'VIP' },
511
- { key: 'review', text: 'Needs review' },
511
+ { value: 'overdue', label: 'Overdue' },
512
+ { value: 'vip', label: 'VIP' },
513
+ { value: 'review', label: 'Needs review' },
512
514
  ],
513
515
  },
514
516
  ];
@@ -520,14 +522,14 @@ const tags = ref<string[]>(['overdue']);
520
522
 
521
523
  #### The same choices in two places
522
524
 
523
- Item keys are scoped to their **group** for selection. Two groups can both
525
+ Row values are scoped to their **group** for selection. Two groups can both
524
526
  list `doctors` and `rooms` (say a day layout at the top level and a week
525
527
  layout inside a `Week ›` submenu) and each keeps its own pick, with its own
526
528
  companion and `v-model`.
527
529
 
528
530
  To show a submenu's current pick on its parent row, compute the row from the
529
531
  same state. `items` is reactive config, so the parent's `description` (or its
530
- `#<key>:append` slot) follows the submenu group's `v-model`:
532
+ `#<value>:append` slot) follows the submenu group's `v-model`:
531
533
 
532
534
  **A submenu's pick on its parent row**
533
535
 
@@ -545,7 +547,7 @@ same state. `items` is reactive config, so the parent's `description` (or its
545
547
  Layout
546
548
  </BbButton>
547
549
  </template>
548
- <!-- Both groups list the same keys; each keeps its own selection. -->
550
+ <!-- Both groups list the same values; each keeps its own selection. -->
549
551
  <BbDropdownGroup id="day" v-model="day" />
550
552
  <BbDropdownGroup id="week" v-model="week" />
551
553
  </BbDropdown>
@@ -561,11 +563,11 @@ import { BbButton, BbDropdown, BbDropdownGroup } from 'bitboss-ui';
561
563
  import type { BbDropdownItem } from 'bitboss-ui';
562
564
 
563
565
  const choices = [
564
- { key: 'doctors', text: 'Doctors' },
565
- { key: 'rooms', text: 'Rooms' },
566
+ { value: 'doctors', label: 'Doctors' },
567
+ { value: 'rooms', label: 'Rooms' },
566
568
  ];
567
- const label = (key: string) =>
568
- choices.find((choice) => choice.key === key)?.text ?? key;
569
+ const label = (value: string) =>
570
+ choices.find((choice) => choice.value === value)?.label ?? value;
569
571
 
570
572
  const day = ref('doctors');
571
573
  const week = ref('rooms');
@@ -574,32 +576,33 @@ const week = ref('rooms');
574
576
  // from the same state its group writes, so the parent row always shows the
575
577
  // current pick ("Week · Rooms") without opening the submenu.
576
578
  const items = computed<BbDropdownItem[]>(() => [
577
- { key: 'day', label: 'Day', selectable: true, items: choices },
579
+ { id: 'day', label: 'Day', selectable: true, items: choices },
578
580
  {
579
- key: 'week-menu',
580
- text: 'Week',
581
+ value: 'week-menu',
582
+ label: 'Week',
581
583
  description: label(week.value),
582
- items: [{ key: 'week', selectable: true, items: choices }],
584
+ items: [{ id: 'week', selectable: true, items: choices }],
583
585
  },
584
586
  ]);
585
587
  </script>
586
588
  ```
587
589
 
588
- Three things still go by the bare key across the whole menu, so give those
589
- rows distinct keys when it matters:
590
+ Three things still go by the bare value across the whole menu, so give those
591
+ rows distinct values when it matters:
590
592
 
591
- - **`#<key>` row slots.** `#doctors` fills every row keyed `doctors`, in every
592
- group. Use `#<groupKey>:item` (with the `item` payload) to target one
593
+ - **`#<value>` row slots.** `#doctors` fills every row whose value is `doctors`,
594
+ in every group. Use `#<groupId>:item` (with the `item` payload) to target one
593
595
  group's rows.
594
596
  - **The async loading flag.** While a row's async `onClick` runs, every row
595
- with that key shows as loading.
596
- - **Submenu parents.** A row that opens a submenu needs a key unique in the
597
+ with that value shows as loading.
598
+ - **Submenu parents.** A row that opens a submenu needs a value unique in the
597
599
  whole menu; the flyout is addressed by it.
598
600
 
599
601
  ### Loading options on demand
600
602
 
601
603
  For options that come from an API, make the group a **pipeline group**: pass an
602
- (async) getter as `items` and an `item-text` / `item-value` pair. This mirrors
604
+ (async) getter as `items`, and an `itemText` / `itemValue` pair unless the raw
605
+ rows already carry `label` and `value`. This mirrors
603
606
  `BbSelect`'s fetch model, so the same data source drops into either component.
604
607
  The full grammar:
605
608
 
@@ -619,7 +622,8 @@ The full grammar:
619
622
  A getter **throws** to fail: the group shows `failedText` (or the `#empty`
620
623
  slot with its `error` prop) instead of "no data".
621
624
  - `itemText` / `itemValue` — a path string or getter producing each raw item's
622
- label and value. `v-model` on the companion surfaces the selected value(s);
625
+ label and value; without them a row reads its own `label` (else `text`) and
626
+ `value`. `v-model` on the companion surfaces the selected value(s);
623
627
  internally the selection key is a hash of the value.
624
628
  - `itemProps` — every **additional** field of a row (see
625
629
  [Additional row fields](#additional-row-fields-itemprops) below). Nothing
@@ -629,7 +633,7 @@ The full grammar:
629
633
  - `loadingText` / `emptyText` / `failedText` — placeholder row text per
630
634
  group; the dropdown-level `loading-text` / `empty-text` / `failed-text` props
631
635
  set the default for all groups, and the `#loading` / `#empty` slots (payload:
632
- `{ text, groupKey }`, `#empty` also `error`) replace the placeholder rows
636
+ `{ text, groupId }`, `#empty` also `error`) replace the placeholder rows
633
637
  entirely.
634
638
  - `dependencies: [...]` + `depsDebounceTime` — re-run the getter (debounced)
635
639
  when any dependency changes, e.g. a search field feeding the fetch.
@@ -689,7 +693,7 @@ const team: Member[] = [
689
693
  // (prefill is always `true` here — menus have no search field).
690
694
  const items: BbDropdownItem[] = [
691
695
  {
692
- key: 'assignees',
696
+ id: 'assignees',
693
697
  label: 'Assign to',
694
698
  selectable: true,
695
699
  multiple: true,
@@ -795,16 +799,16 @@ const loadMembers = (): Promise<Member[]> =>
795
799
  // refetch. `enforceCoherence` then drops picks missing from the fresh items.
796
800
  const menu = computed<BbDropdownItem[]>(() => [
797
801
  {
798
- key: 'board',
802
+ id: 'board',
799
803
  label: 'Board',
800
804
  selectable: true,
801
805
  items: [
802
- { key: 'website', text: 'Website' },
803
- { key: 'mobile-app', text: 'Mobile app' },
806
+ { value: 'website', label: 'Website' },
807
+ { value: 'mobile-app', label: 'Mobile app' },
804
808
  ],
805
809
  },
806
810
  {
807
- key: 'assignees',
811
+ id: 'assignees',
808
812
  label: 'Assignee',
809
813
  selectable: true,
810
814
  multiple: true,
@@ -828,14 +832,15 @@ const assigneeNames = computed(() =>
828
832
 
829
833
  ### Additional row fields: `itemProps`
830
834
 
831
- A fetched row's **text** and **value** come from `itemText` and `itemValue`.
835
+ A fetched row's **label** and **value** come from `itemText` and `itemValue` (by
836
+ default the raw item's own `label` and `value`).
832
837
  Everything **else** about the row comes from `itemProps` — and only from there.
833
838
  The raw item is data: a `href`, `disabled` or `prepend:icon` field sitting on it
834
839
  does nothing on its own.
835
840
 
836
841
  ```ts
837
842
  const assigneeGroup = {
838
- key: 'assignee',
843
+ id: 'assignee',
839
844
  selectable: true,
840
845
  items: () => api.users(),
841
846
  itemText: 'name',
@@ -908,10 +913,11 @@ const team: Member[] = [
908
913
 
909
914
  const items: BbDropdownItem[] = [
910
915
  {
911
- key: 'assignees',
916
+ id: 'assignees',
912
917
  label: 'Assign to',
913
918
  multiple: true,
914
- // Fetched rows take their text and value from `itemText` / `itemValue`,
919
+ // Fetched rows take their text and value from `itemText` / `itemValue`
920
+ // (without them, the row's own `label` and `value`),
915
921
  // and EVERY other field only from `itemProps` — a raw `disabled` or
916
922
  // `prepend:icon` sitting on the item would do nothing.
917
923
  itemText: 'name',
@@ -981,14 +987,14 @@ const recent: Project[] = [
981
987
  const lastOpened = ref<string | null>(null);
982
988
 
983
989
  const items: BbDropdownItem[] = [
984
- { key: 'new', text: 'New project', 'prepend:icon': 'lucide:plus' },
990
+ { value: 'new', label: 'New project', 'prepend:icon': 'lucide:plus' },
985
991
  {
986
992
  // A fetched group of LINKS (not selectable). Its rows get `href`, an icon,
987
993
  // a description and a click handler from `itemProps`, using the function
988
994
  // form. In the object form a function is a GETTER, so a handler would be
989
995
  // written `onClick: (project) => () => …`; here the function form returns
990
996
  // the handler directly.
991
- key: 'recent',
997
+ id: 'recent',
992
998
  label: 'Recent',
993
999
  itemText: 'name',
994
1000
  itemValue: 'id',
@@ -1021,11 +1027,11 @@ reject the common slip `onClick: () => openProfile()`, because it doesn't return
1021
1027
  a function.)
1022
1028
 
1023
1029
  **Which fields.** Everything a hand-written row accepts, except its identity and
1024
- structure — `key`, `text`, `items`, `group` — and `disabled`:
1030
+ structure — `value`, `label`, `items`, `group` — and `disabled`:
1025
1031
 
1026
1032
  - `description` — a muted second line under the text, announced as the row's
1027
1033
  description (never part of its name), searched with the text, and exposed as
1028
- `description` on `useBbDropdownContext(id).groups[key].selectedOptions`.
1034
+ `description` on `useBbDropdownContext(id).groups[groupId].selectedOptions`.
1029
1035
  - `prepend:icon`, `append:icon`, `variant`.
1030
1036
  - `onClick`, `href`, `to`, `target`, `rel`, `download`, `external`, and the
1031
1037
  Inertia visit options.
@@ -1066,7 +1072,7 @@ group owns an independent query.
1066
1072
  <BbDropdown
1067
1073
  :items="[
1068
1074
  {
1069
- key: 'assignee',
1075
+ id: 'assignee',
1070
1076
  label: 'Assignee',
1071
1077
  searchable: true,
1072
1078
  searchPlaceholder: 'Find a teammate…',
@@ -1136,17 +1142,17 @@ const { isReady, open, groups } = useBbDropdownContext('invoice-filters');
1136
1142
 
1137
1143
  - `isReady` — a dropdown with that id is mounted.
1138
1144
  - `open` — the panel/sheet is open.
1139
- - `groups` — one entry per **selectable** group, keyed by group key.
1145
+ - `groups` — one entry per **selectable** group, keyed by the group's `id`.
1140
1146
 
1141
1147
  Each entry is **the group exactly as you declared it, with live state on top**,
1142
1148
  so a chip can be driven entirely from the group config:
1143
1149
 
1144
- | From your config | Added live |
1145
- | ---------------------------------------------------------------------------- | ------------------------------------------------------------------------------- |
1146
- | `key`, `label`, `hideLabel`, `max`, `filterBy`, `prepend:icon`, `variant`, … | `value` (the `v-model`), `selectedOptions`, `multiple`, `selectable`, `loading` |
1150
+ | From your config | Added live |
1151
+ | --------------------------------------------------------------------------- | ------------------------------------------------------------------------------- |
1152
+ | `id`, `label`, `hideLabel`, `max`, `filterBy`, `prepend:icon`, `variant`, … | `value` (the `v-model`), `selectedOptions`, `multiple`, `selectable`, `loading` |
1147
1153
 
1148
- `selectedOptions` is `{ value, text?, original? }[]`. `value` is always there;
1149
- `text`/`original` fill in once the owning group has the item — so use
1154
+ `selectedOptions` is `{ value, label?, original? }[]`. `value` is always there;
1155
+ `label`/`original` fill in once the owning group has the item — so use
1150
1156
  `hideLabel` when a group's name is already shown by its parent category but you
1151
1157
  still want a chip prefix.
1152
1158
 
@@ -1165,55 +1171,55 @@ its resolved counterpart.
1165
1171
  ### Per-item and per-group slots
1166
1172
 
1167
1173
  Every row (and every titled group header) can be customized without leaving
1168
- the config-driven model. Slot names come from keys through `slotKey`, which is
1169
- kebab-case (words split at separators, camelCase humps and digits, lowercased,
1170
- joined by `-`): key `"Delete file"`, `"delete_file"` and `"deleteFile"` all →
1171
- `#delete-file`. For a key with accents, non-Latin letters or punctuation, or
1174
+ the config-driven model. Slot names come from a row's `value` (a group's `id`)
1175
+ through `slotKey`, which is kebab-case (words split at separators, camelCase
1176
+ humps and digits, lowercased, joined by `-`): `"Delete file"`, `"delete_file"`
1177
+ and `"deleteFile"` all → `#delete-file`. For a value with accents, non-Latin letters or punctuation, or
1172
1178
  when unsure, write `#[slotKey('Qualità')]` (`import { slotKey } from
1173
1179
  'bitboss-ui'`) instead of spelling it by hand.
1174
1180
 
1175
- | Slot | Renders for |
1176
- | --------------------------------------------------------------- | --------------------------------------------------------- |
1177
- | `#<key>`, `#<key>:prepend`, `#<key>:append` | one row — its content, leading or trailing region |
1178
- | `#<groupKey>:item`, `#<groupKey>:item:prepend`, `…:item:append` | **every row of that group**, and nothing else |
1179
- | `#<groupKey>`, `#<groupKey>:prepend`, `#<groupKey>:append` | that group's title line |
1180
- | `item:prepend`, `item:append` | every row **and** every group title line, across the menu |
1181
+ | Slot | Renders for |
1182
+ | ------------------------------------------------------------- | --------------------------------------------------------- |
1183
+ | `#<value>`, `#<value>:prepend`, `#<value>:append` | one row — its content, leading or trailing region |
1184
+ | `#<groupId>:item`, `#<groupId>:item:prepend`, `…:item:append` | **every row of that group**, and nothing else |
1185
+ | `#<groupId>`, `#<groupId>:prepend`, `#<groupId>:append` | that group's title line |
1186
+ | `item:prepend`, `item:append` | every row **and** every group title line, across the menu |
1181
1187
 
1182
1188
  Each edge of a row has **one occupant** — nothing renders side by side. From
1183
1189
  strongest to weakest:
1184
1190
 
1185
- | Leading edge | Trailing edge |
1186
- | -------------------------- | -------------------------------------------------------- |
1187
- | — | the check, on the **selected** row of a selectable group |
1188
- | `#<key>:prepend` | `#<key>:append` |
1189
- | — | the submenu chevron |
1190
- | `#<groupKey>:item:prepend` | `#<groupKey>:item:append` |
1191
- | `item:prepend` | `item:append` |
1192
- | `prepend:icon` | `append:icon` |
1191
+ | Leading edge | Trailing edge |
1192
+ | ------------------------- | -------------------------------------------------------- |
1193
+ | — | the check, on the **selected** row of a selectable group |
1194
+ | `#<value>:prepend` | `#<value>:append` |
1195
+ | — | the submenu chevron |
1196
+ | `#<groupId>:item:prepend` | `#<groupId>:item:append` |
1197
+ | `item:prepend` | `item:append` |
1198
+ | `prepend:icon` | `append:icon` |
1193
1199
 
1194
1200
  So a slot always replaces the row's icon and the most specific slot wins. A
1195
- row's own `#<key>:append` is written for that one row, so it may replace its
1201
+ row's own `#<value>:append` is written for that one row, so it may replace its
1196
1202
  submenu chevron; the group-wide and shared append slots never do, so a submenu
1197
1203
  row keeps its chevron unless you name it. The check beats everything — as in
1198
1204
  `BbSelect`, it takes the append content's place on the selected row only, so unselected rows of a selectable group still show their
1199
1205
  `append:icon` or append slot. Group title lines follow the same order with
1200
- their own `#<groupKey>:prepend` / `:append`. In fetched groups a row's `#<key>`
1206
+ their own `#<groupId>:prepend` / `:append`. In fetched groups a row's `#<value>`
1201
1207
  derives from its resolved `itemValue`.
1202
1208
 
1203
1209
  The payload is one-way — no callbacks; clicks and selection stay wired by the
1204
1210
  dropdown, so keep slot content presentational:
1205
1211
 
1206
- - `item`, `text`, `description`, `index`, `selected`, `disabled`, `loading`,
1212
+ - `item`, `label`, `description`, `index`, `selected`, `disabled`, `loading`,
1207
1213
  `open`, `placement`
1208
- - `group` — `{ key, label, meta, selectable, multiple }` of the group the row
1209
- sits in (`key` is `undefined` for loose rows and plain arrays)
1214
+ - `group` — `{ id, label, meta, selectable, multiple }` of the group the row
1215
+ sits in (`id` is `undefined` for loose rows and plain arrays)
1210
1216
  - `level` — `0` in the root menu, `1` in a submenu, and so on, on the flyout
1211
1217
  and the phone sheet alike
1212
1218
  - `groupTitle` — `true` when the shared `item:prepend` / `item:append` is
1213
1219
  drawing a group's title line (with the group as `item`), `false` on a row
1214
1220
 
1215
1221
  There is **no** bare `#item` slot: restyle every row with the shared edge
1216
- slots, one group's rows with `#<groupKey>:item…`, one row with its key.
1222
+ slots, one group's rows with `#<groupId>:item…`, one row with its value.
1217
1223
 
1218
1224
  **Status dots and a per-row badge**
1219
1225
 
@@ -1248,11 +1254,11 @@ slots, one group's rows with `#<groupKey>:item…`, one row with its key.
1248
1254
  />
1249
1255
  </template>
1250
1256
 
1251
- <!-- Per-key slot: replaces just this row's label region. The name is
1252
- the item's `key` in kebab-case (`slotKey`: `billingInfo` → `#billing-info`). -->
1253
- <template #billing="{ text }">
1257
+ <!-- Per-row slot: replaces just this row's label region. The name is
1258
+ the row's `value` in kebab-case (`slotKey`: `billingInfo` → `#billing-info`). -->
1259
+ <template #billing="{ label }">
1254
1260
  <span class="flex flex-1 items-center justify-between gap-2 text-left">
1255
- {{ text }}
1261
+ {{ label }}
1256
1262
  <BbBadge variant="soft-amber">3 due</BbBadge>
1257
1263
  </span>
1258
1264
  </template>
@@ -1264,13 +1270,13 @@ import { BbBadge, BbButton, BbDropdown, BbIcon } from 'bitboss-ui';
1264
1270
  import type { BbDropdownItem, IconType } from 'bitboss-ui';
1265
1271
 
1266
1272
  const items: BbDropdownItem[] = [
1267
- { key: 'production', text: 'Production', href: '#production' },
1268
- { key: 'staging', text: 'Staging', href: '#staging' },
1269
- [{ key: 'billing', text: 'Billing', href: '#billing' }],
1273
+ { value: 'production', label: 'Production', href: '#production' },
1274
+ { value: 'staging', label: 'Staging', href: '#staging' },
1275
+ [{ value: 'billing', label: 'Billing', href: '#billing' }],
1270
1276
  ];
1271
1277
 
1272
1278
  /** Status glyph per workspace row — color inherits via currentColor. */
1273
- // `key` is optional on a row (Q53.17), so a slot reading it may see none.
1279
+ // `value` is optional on a row (Q53.17), so a slot reading it may see none.
1274
1280
  const envIcon = (key?: string): IconType => {
1275
1281
  if (key === 'production') return 'lucide:circle-check';
1276
1282
  if (key === 'staging') return 'lucide:circle-dashed';
@@ -1307,7 +1313,7 @@ pieces, and nothing else:
1307
1313
  announces the current one with the built-in check; `searchable` plus a
1308
1314
  fetched `items` getter scales to hundreds; bind its `<BbDropdownGroup
1309
1315
  v-model>` to the current id and switch when it changes.
1310
- 3. **`meta` + `#<groupKey>:item:prepend`** — every entry takes a `meta`: your
1316
+ 3. **`meta` + `#<groupId>:item:prepend`** — every entry takes a `meta`: your
1311
1317
  own data, carried untouched to its slots as `item.meta` (and to per-item
1312
1318
  `pt` functions), never read by the dropdown, never put on the DOM. A
1313
1319
  hand-written row sets it directly (`meta: workspace`); a fetched row sets it
@@ -1388,7 +1394,7 @@ const initials = (workspace: Workspace) =>
1388
1394
  // A constant, so the fetched group is declared once while the row above it
1389
1395
  // follows the current workspace.
1390
1396
  const switcher: BbDropdownItem = {
1391
- key: 'workspaces',
1397
+ id: 'workspaces',
1392
1398
  label: 'Switch workspace',
1393
1399
  // The row that opens this submenu already names it.
1394
1400
  hideLabel: true,
@@ -1399,7 +1405,7 @@ const switcher: BbDropdownItem = {
1399
1405
  itemText: 'name',
1400
1406
  itemValue: 'id',
1401
1407
  // `meta` hands each row its workspace, so the slot draws from the record
1402
- // instead of looking it up by key.
1408
+ // instead of looking it up by value.
1403
1409
  itemProps: (workspace: Workspace) => ({
1404
1410
  description: workspace.plan,
1405
1411
  meta: workspace,
@@ -1417,30 +1423,30 @@ const switcher: BbDropdownItem = {
1417
1423
 
1418
1424
  const items = computed<BbDropdownItem[]>(() => [
1419
1425
  {
1420
- key: 'current-workspace',
1421
- text: current.value?.name ?? 'Choose a workspace',
1426
+ value: 'current-workspace',
1427
+ label: current.value?.name ?? 'Choose a workspace',
1422
1428
  description: current.value?.plan,
1423
1429
  meta: current.value,
1424
1430
  items: [switcher],
1425
1431
  },
1426
1432
  [
1427
1433
  {
1428
- key: 'profile',
1429
- text: 'Profile',
1434
+ value: 'profile',
1435
+ label: 'Profile',
1430
1436
  'prepend:icon': 'lucide:user',
1431
1437
  href: '#profile',
1432
1438
  },
1433
1439
  {
1434
- key: 'settings',
1435
- text: 'Settings',
1440
+ value: 'settings',
1441
+ label: 'Settings',
1436
1442
  'prepend:icon': 'lucide:settings',
1437
1443
  href: '#settings',
1438
1444
  },
1439
1445
  ],
1440
1446
  [
1441
1447
  {
1442
- key: 'sign-out',
1443
- text: 'Sign out',
1448
+ value: 'sign-out',
1449
+ label: 'Sign out',
1444
1450
  'prepend:icon': 'lucide:log-out',
1445
1451
  href: '#sign-out',
1446
1452
  },
@@ -1451,8 +1457,8 @@ const items = computed<BbDropdownItem[]>(() => [
1451
1457
 
1452
1458
  Two things this replaces, both seen in real apps:
1453
1459
 
1454
- - **Matching keys in the shared slots** (`v-if="item.key === 'current'"`,
1455
- `v-else-if="clinicsById.get(item.key)"`) to tell a record row from an action
1460
+ - **Matching values in the shared slots** (`v-if="item.value === 'current'"`,
1461
+ `v-else-if="clinicsById.get(item.value)"`) to tell a record row from an action
1456
1462
  row, and a lookup map rebuilt from the fetch to get the record back. The
1457
1463
  group row slot is the "which rows" answer; `item.meta` is the record.
1458
1464
  - **Re-drawing the other rows' icons**, because a shared `item:prepend`
@@ -1471,9 +1477,9 @@ the sheet's pinned header and footer.
1471
1477
  ```vue
1472
1478
  <BbDropdown
1473
1479
  :items="[
1474
- { key: 'jan', text: 'January', href: '#jan' },
1475
- { key: 'feb', text: 'February', href: '#feb' },
1476
- { key: 'mar', text: 'March', href: '#mar' },
1480
+ { value: 'jan', label: 'January', href: '#jan' },
1481
+ { value: 'feb', label: 'February', href: '#feb' },
1482
+ { value: 'mar', label: 'March', href: '#mar' },
1477
1483
  ]"
1478
1484
  :width="240"
1479
1485
  >
@@ -1553,14 +1559,14 @@ const last = ref('Right-click the row');
1553
1559
 
1554
1560
  const items: BbDropdownItem[] = [
1555
1561
  {
1556
- key: 'download',
1557
- text: 'Download PDF',
1562
+ value: 'download',
1563
+ label: 'Download PDF',
1558
1564
  'prepend:icon': 'lucide:download',
1559
1565
  onClick: () => (last.value = 'Downloading'),
1560
1566
  },
1561
1567
  {
1562
- key: 'share',
1563
- text: 'Share link',
1568
+ value: 'share',
1569
+ label: 'Share link',
1564
1570
  'prepend:icon': 'lucide:link',
1565
1571
  href: '#share',
1566
1572
  },
@@ -1568,8 +1574,8 @@ const items: BbDropdownItem[] = [
1568
1574
  // awaits useConfirm — see the mixed action menu example.
1569
1575
  [
1570
1576
  {
1571
- key: 'trash',
1572
- text: 'Move to trash',
1577
+ value: 'trash',
1578
+ label: 'Move to trash',
1573
1579
  'prepend:icon': 'lucide:trash-2',
1574
1580
  onClick: () => (last.value = 'Moved to trash'),
1575
1581
  },
@@ -1608,15 +1614,20 @@ const items: BbDropdownItem[] = [
1608
1614
  width="100%"
1609
1615
  :items="[
1610
1616
  {
1611
- key: 'starter',
1612
- text: 'Starter',
1617
+ value: 'starter',
1618
+ label: 'Starter',
1613
1619
  description: 'For side projects',
1614
1620
  href: '#starter',
1615
1621
  },
1616
- { key: 'pro', text: 'Pro', description: 'For growing teams', href: '#pro' },
1617
1622
  {
1618
- key: 'enterprise',
1619
- text: 'Enterprise',
1623
+ value: 'pro',
1624
+ label: 'Pro',
1625
+ description: 'For growing teams',
1626
+ href: '#pro',
1627
+ },
1628
+ {
1629
+ value: 'enterprise',
1630
+ label: 'Enterprise',
1620
1631
  description: 'Custom contracts',
1621
1632
  href: '#enterprise',
1622
1633
  },
@@ -1678,16 +1689,16 @@ long lists.
1678
1689
  ```vue
1679
1690
  <BbButton
1680
1691
  v-bb-dropdown="[
1681
- { key: 'profile', text: 'View profile', href: '#profile' },
1692
+ { value: 'profile', label: 'View profile', href: '#profile' },
1682
1693
  {
1683
- key: 'settings',
1684
- text: 'Settings',
1694
+ value: 'settings',
1695
+ label: 'Settings',
1685
1696
  'prepend:icon': 'lucide:settings',
1686
1697
  href: '#settings',
1687
1698
  },
1688
1699
  {
1689
- key: 'signout',
1690
- text: 'Sign out',
1700
+ value: 'signout',
1701
+ label: 'Sign out',
1691
1702
  variant: 'destructive',
1692
1703
  href: '#signout',
1693
1704
  },
@@ -1727,8 +1738,8 @@ the same floor the select's own sheet holds.
1727
1738
  v-bb-dropdown="{
1728
1739
  compact: true,
1729
1740
  items: [
1730
- { key: 'rename', text: 'Rename' },
1731
- { key: 'duplicate', text: 'Duplicate' },
1741
+ { value: 'rename', label: 'Rename' },
1742
+ { value: 'duplicate', label: 'Duplicate' },
1732
1743
  ],
1733
1744
  }"
1734
1745
  size="sm"
@@ -1772,8 +1783,8 @@ broadcast, on the flyout and the phone sheet alike; its magnifier is chrome),
1772
1783
  — a flex column with a 1px gap; a submenu's list is not reached), `item` — every entry, submenus included, a broadcast
1773
1784
  resolved per entry — and `itemText` / `itemIcon` / `itemDescription`, that
1774
1785
  entry's label, its prepend / append icons and its muted second line (the item's
1775
- `text` / `prepend:icon` · `append:icon` / `description`), resolved with the entry's
1776
- states (a per-entry `#<key>` slot replaces the label and description). States: `open`, and `selected` / `disabled` per entry.
1786
+ `label` / `prepend:icon` · `append:icon` / `description`), resolved with the entry's
1787
+ states (a per-entry `#<value>` slot replaces the label and description). States: `open`, and `selected` / `disabled` per entry.
1777
1788
  Groups, headings and dividers are not parts.
1778
1789
 
1779
1790
  The invoice View menu, restyled through those parts: a muted wash on
@@ -1836,30 +1847,30 @@ import type { BbDropdownItem } from 'bitboss-ui';
1836
1847
  // container instead).
1837
1848
  const items: BbDropdownItem[] = [
1838
1849
  {
1839
- key: 'sort',
1850
+ id: 'sort',
1840
1851
  label: 'Sort by',
1841
1852
  selectable: true,
1842
1853
  items: [
1843
- { key: 'recent', text: 'Most recent' },
1844
- { key: 'name', text: 'Name (A–Z)' },
1845
- { key: 'amount', text: 'Amount (high → low)' },
1854
+ { value: 'recent', label: 'Most recent' },
1855
+ { value: 'name', label: 'Name (A–Z)' },
1856
+ { value: 'amount', label: 'Amount (high → low)' },
1846
1857
  ],
1847
1858
  },
1848
1859
  {
1849
- key: 'tags',
1860
+ id: 'tags',
1850
1861
  label: 'Tags',
1851
1862
  selectable: true,
1852
1863
  multiple: true,
1853
1864
  items: [
1854
- { key: 'overdue', text: 'Overdue' },
1855
- { key: 'vip', text: 'VIP' },
1856
- { key: 'review', text: 'Needs review' },
1865
+ { value: 'overdue', label: 'Overdue' },
1866
+ { value: 'vip', label: 'VIP' },
1867
+ { value: 'review', label: 'Needs review' },
1857
1868
  ],
1858
1869
  },
1859
1870
  [
1860
1871
  {
1861
- key: 'export',
1862
- text: 'Export CSV',
1872
+ value: 'export',
1873
+ label: 'Export CSV',
1863
1874
  disabled: true,
1864
1875
  },
1865
1876
  ],
@@ -1929,23 +1940,23 @@ const run = (name: string) => () => {
1929
1940
  };
1930
1941
 
1931
1942
  const items: Action[] = [
1932
- { key: 'rename', text: 'Rename', onClick: run('rename') },
1933
- { key: 'duplicate', text: 'Duplicate', onClick: run('duplicate') },
1943
+ { value: 'rename', label: 'Rename', onClick: run('rename') },
1944
+ { value: 'duplicate', label: 'Duplicate', onClick: run('duplicate') },
1934
1945
  {
1935
- key: 'archive',
1936
- text: 'Archive',
1946
+ value: 'archive',
1947
+ label: 'Archive',
1937
1948
  description: 'Hidden from the board, kept for 30 days',
1938
1949
  onClick: run('archive'),
1939
1950
  },
1940
1951
  {
1941
- key: 'delete',
1942
- text: 'Delete project',
1952
+ value: 'delete',
1953
+ label: 'Delete project',
1943
1954
  danger: true,
1944
1955
  onClick: run('delete'),
1945
1956
  },
1946
1957
  {
1947
- key: 'purge',
1948
- text: 'Purge history',
1958
+ value: 'purge',
1959
+ label: 'Purge history',
1949
1960
  danger: true,
1950
1961
  disabled: true,
1951
1962
  },
@@ -1964,7 +1975,7 @@ const dangerText = ({ item }: { item: Action }) => item.danger && 'font-medium';
1964
1975
  ```
1965
1976
 
1966
1977
  The function can also map a VALUE to its own classes. Here every status in a
1967
- single-choice group gets its own tone: `pt:item-icon` looks the entry's `key`
1978
+ single-choice group gets its own tone: `pt:item-icon` looks the entry's `value`
1968
1979
  up in a map for the dot's color, and `pt:item` adds a wash of the same tone
1969
1980
  while that entry is the `selected` one. Adding a status is one row in the map.
1970
1981
 
@@ -2005,7 +2016,7 @@ import { ref } from 'vue';
2005
2016
  import { BbButton, BbDropdown, BbDropdownGroup } from 'bitboss-ui';
2006
2017
  import type { BbDropdownItem } from 'bitboss-ui';
2007
2018
 
2008
- // One look per VALUE: the per-item function reads the entry's `key` and looks
2019
+ // One look per VALUE: the per-item function reads the entry's `value` and looks
2009
2020
  // its classes up in a map, so every status gets its own tone — the dot on
2010
2021
  // `:pt:item-icon`, a wash of the same tone on `item` while it is the `selected`
2011
2022
  // one. A new status is one row in `tones`.
@@ -2027,12 +2038,12 @@ const labels: Record<Status, string> = {
2027
2038
 
2028
2039
  const items: BbDropdownItem[] = [
2029
2040
  {
2030
- key: 'status',
2041
+ id: 'status',
2031
2042
  label: 'Set status',
2032
2043
  selectable: true,
2033
2044
  items: (Object.keys(labels) as Status[]).map((key) => ({
2034
- key,
2035
- text: labels[key],
2045
+ value: key,
2046
+ label: labels[key],
2036
2047
  'prepend:icon': 'lucide:circle',
2037
2048
  })),
2038
2049
  },
@@ -2040,10 +2051,10 @@ const items: BbDropdownItem[] = [
2040
2051
 
2041
2052
  const status = ref<Status>('overdue');
2042
2053
 
2043
- // A group has no `key` in `tones`, so only the status entries match.
2044
- // (`BbDropdownItem` also covers a nested list, which has no `key`.)
2054
+ // A group has no `value`, so only the status rows match.
2055
+ // (`BbDropdownItem` also covers a nested list, which has no `value`.)
2045
2056
  const toneOf = (item: BbDropdownItem) =>
2046
- 'key' in item ? tones[item.key as Status] : undefined;
2057
+ 'value' in item ? tones[item.value as Status] : undefined;
2047
2058
  </script>
2048
2059
  ```
2049
2060
 
@@ -2083,12 +2094,12 @@ A `pt` value written in `<script>` (a constant, a preset, a wrapper's
2083
2094
  - **Don't rebuild selection** with `onClick` + your own state — mark the group
2084
2095
  `selectable` and bind a `<BbDropdownGroup v-model>`.
2085
2096
  - **There is no bare `#item` slot** — a template slot named `item` renders
2086
- nothing. Use `item:prepend`/`item:append`, a group's `#<groupKey>:item…`, or
2087
- a per-key slot.
2088
- - **Don't sort rows by key inside the shared slots.** When only one group's
2089
- rows need a custom look, use `#<groupKey>:item:prepend`; when a slot needs the
2097
+ nothing. Use `item:prepend`/`item:append`, a group's `#<groupId>:item…`, or
2098
+ a per-row `#<value>` slot.
2099
+ - **Don't sort rows by value inside the shared slots.** When only one group's
2100
+ rows need a custom look, use `#<groupId>:item:prepend`; when a slot needs the
2090
2101
  record behind a row, put it in `meta` (through `itemProps` on a fetched group)
2091
- instead of looking it up by `item.key`.
2102
+ instead of looking it up by `item.value`.
2092
2103
  - **Don't hand-roll the "current" mark in a switcher** (a custom `variant` plus
2093
2104
  a check in `item:append`). Make the group `selectable` and bind its
2094
2105
  `v-model` to the current id — the check, `aria-checked` and the radio role
@@ -2098,7 +2109,7 @@ A `pt` value written in `<script>` (a constant, a preset, a wrapper's
2098
2109
  - Item `variant`s other than `destructive` render only a class hook — register
2099
2110
  names via the `dropdownItemVariants` plugin option and ship their CSS.
2100
2111
  - `<BbDropdownGroup>` must sit in a `BbDropdown` (or `BbDropdownButton`)
2101
- default slot, its `id` must match a group `key`, and a `multiple` group's
2112
+ default slot, its `id` must match a group's `id`, and a `multiple` group's
2102
2113
  model must be an array — all three misuses throw.
2103
2114
  - Placeholder texts default to the config locale's "Loading…" / "No results"
2104
2115
  strings (`locale` plugin option) unless you set `loading-text` /
@@ -2158,7 +2169,7 @@ A `pt` value written in `<script>` (a constant, a preset, a wrapper's
2158
2169
  | `boundary` | `string \| Record<string, any> \| HTMLElement \| null \| undefined` | | | Constrains the dropdown within a bounding element. Accepts an HTMLElement, a Vue component ref, or a CSS selector string. |
2159
2170
  | `compact` | `boolean \| undefined` | `false` | | Apply the compact density variant — the same ladder `BbSelect` uses, on both surfaces: flyout rows go 28px → 24px, sheet rows 44px → 36px. The label size does not change; density here is height, as it is for a select. A menu row is a touch target in a way a select option is not quite — a mis-tap fires the neighbouring COMMAND rather than picking the wrong value — so the compact sheet stops at 36px and never follows the flyout down to 24px. That is the same floor the select's sheet holds. |
2160
2171
  | `disabled` | `boolean \| undefined` | `false` | | Disables the component |
2161
- | `eager` | `boolean \| undefined` | `false` | | Renders the menu panel at mount instead of on the first open (the phone sheet's too). |
2172
+ | `eager` | `boolean \| undefined` | `false` | | Renders the menu panel at mount instead of on the first open (the phone sheet's too), and keeps its rows after a close. Without it the rows mount on each open and go once the menu has closed. |
2162
2173
  | `emptyText` | `string \| undefined` | | | Default placeholder text shown when a pipeline group resolves to no items. A group's own `emptyText` overrides this; both fall back to the localized `common.emptyText` (`'No data to display'`). |
2163
2174
  | `enforceCoherence` | `boolean \| undefined` | `false` | | Default for pipeline groups: drop selections that are no longer present in a group's current items (e.g. after a `dependencies` re-fetch) from the selection and `v-model`. A group's own `enforceCoherence` overrides this. |
2164
2175
  | `failedText` | `string \| undefined` | | | Default placeholder text shown when a pipeline group's latest load FAILED (its `items` getter threw). A group's own `failedText` overrides this; both fall back to the localized `common.failedText` (`"Couldn't load items"`). |
@@ -2188,9 +2199,9 @@ A `pt` value written in `<script>` (a constant, a preset, a wrapper's
2188
2199
  | `input` | A searchable group's search field — a broadcast: it lands on every searchable group's field, desktop and phone alike. Its magnifier glyph is chrome. |
2189
2200
  | `list` | The top-level items container between the bands — the node that lays the entries out (a flex column with a 1px gap; on a phone, the sheet's items container). A submenu's list is not reached. Groups, headings and dividers are not parts. |
2190
2201
  | `item` | One menu entry, submenus included — a broadcast resolved per entry. Also takes a per-item function, called with the entry. |
2191
- | `itemText` | An entry's label (its `text`) — resolved with that entry's states. A per-entry `#<key>` slot replaces it. Also takes a per-item function. |
2202
+ | `itemText` | An entry's label (its `label`) — resolved with that entry's states. A per-entry `#<value>` slot replaces it. Also takes a per-item function. |
2192
2203
  | `itemIcon` | An entry's prepend / append icons — resolved with that entry's states. Also takes a per-item function. |
2193
- | `itemDescription` | An entry's muted second line (its `description`) — resolved with that entry's states. A per-entry `#<key>` slot replaces it. Also takes a per-item function. |
2204
+ | `itemDescription` | An entry's muted second line (its `description`) — resolved with that entry's states. A per-entry `#<value>` slot replaces it. Also takes a per-item function. |
2194
2205
 
2195
2206
  States are listed in precedence order: when two are on at once and their entries conflict, the later one wins.
2196
2207
 
@@ -2204,7 +2215,7 @@ States are listed in precedence order: when two are on at once and their entries
2204
2215
 
2205
2216
  - `hidden` — `(): void` — Emitted once the menu has finished closing.
2206
2217
  - `hide` — `(): void` — Emitted as soon as the menu starts to close.
2207
- - `item:selected` — `(value: any): void` — The user selected a row in a selectable group, at the click — also when a controlled companion's app then refuses the value. The payload is the item's resolved value (its `item-value` for pipeline groups, else its `key`) — symmetric with `BbTable`'s `item:selected`.
2218
+ - `item:selected` — `(value: any): void` — The user selected a row in a selectable group, at the click — also when a controlled companion's app then refuses the value. The payload is the row's value (its `item-value` for pipeline groups, else its `value`) — symmetric with `BbTable`'s `item:selected`.
2208
2219
  - `item:unselected` — `(value: any): void` — The user unselected a row (a multiple toggle, a `clearable` re-click, a chip ×, or the old value a single pick replaces). Payload is the item's resolved value, matching `item:selected`.
2209
2220
  - `show` — `(): void` — Emitted as soon as the menu (the popover, or the sheet on a phone) starts to open.
2210
2221
  - `shown` — `(): void` — Emitted once the menu is open and its open transition has finished.
@@ -2213,21 +2224,21 @@ States are listed in precedence order: when two are on at once and their entries
2213
2224
 
2214
2225
  - `activator` — scope: `BbDropdownActivatorSlotProps` `{ disabled?: boolean; loading: boolean; open: boolean; placement: Placement \| "cursor"; props: BbDropdownActivatorProps }` — The element that triggers the dropdown to open. Spread `props` onto your trigger element.
2215
2226
  - `default` — scope: `any` — Hosts `<BbDropdownGroup>` companions. They register their group with the dropdown and render nothing themselves.
2216
- - `empty` — scope: `BbDropdownPlaceholderSlotProps` `{ groupKey?: string; text: string; error?: unknown }` — Replaces the default "no data" placeholder row shown in a pipeline group that resolved to no items. Rendered once per empty group.
2227
+ - `empty` — scope: `BbDropdownPlaceholderSlotProps` `{ groupId?: string; text: string; error?: unknown }` — Replaces the default "no data" placeholder row shown in a pipeline group that resolved to no items. Rendered once per empty group.
2217
2228
  - `footer` — scope: `BbDropdownEdgeSlotProps` `{ disabled?: boolean; open: boolean; placement: Placement \| "cursor" }` — Content pinned to the bottom of the dropdown panel, outside the scroll area. Stays visible while the items scroll and is separated from them by a divider — for action buttons.
2218
2229
  - `header` — scope: `BbDropdownEdgeSlotProps` `{ disabled?: boolean; open: boolean; placement: Placement \| "cursor" }` — Content pinned to the top of the dropdown panel, outside the scroll area. Stays visible while the items scroll and is separated from them by a divider — for a title or a filter field.
2219
- - `item:append` — scope: `BbDropdownItemSlotProps` `{ description?: string; disabled?: boolean; group: BbDropdownSlotGroup; groupTitle: boolean; level: number; index: number; item: InternalItem; loading: boolean; open: boolean; placement: Placement \| "cursor"; selected: boolean; text: string }` — The trailing region of every row (and group title line), replacing its `append:icon`. A named slot wins over it; the submenu chevron and the check on a selected row take its place.
2220
- - `item:prepend` — scope: `BbDropdownItemSlotProps` `{ description?: string; disabled?: boolean; group: BbDropdownSlotGroup; groupTitle: boolean; level: number; index: number; item: InternalItem; loading: boolean; open: boolean; placement: Placement \| "cursor"; selected: boolean; text: string }` — The leading region of every row (and group title line), replacing its `prepend:icon`. A row's own or its group's named slot wins over it.
2221
- - `loading` — scope: `BbDropdownPlaceholderSlotProps` `{ groupKey?: string; text: string; error?: unknown }` — Replaces the default loading placeholder row shown in a pipeline group while its async items load. Rendered once per loading group.
2222
- - `#<key>` (named from data) — scope: `BbDropdownItemSlotProps` — One row's content (text and description), by its key; in a fetched group, by its resolved `itemValue`. Reserved keys (their slot is one of this component's own, so a key spelled like them is an error): `activator`, `default`, `empty`, `footer`, `header`, `item`, `loading`.
2223
- - `#<key>:prepend` (named from data) — scope: `BbDropdownItemSlotProps` — One row's leading region; replaces its `prepend:icon`.
2224
- - `#<key>:append` (named from data) — scope: `BbDropdownItemSlotProps` — One row's trailing region; replaces its `append:icon` and its submenu chevron. The check takes its place on the selected row.
2225
- - `#<groupKey>:item` (named from data) — scope: `BbDropdownItemSlotProps` — The content of every row of that group, and no other; a row's own `#<key>` still wins.
2226
- - `#<groupKey>:item:prepend` (named from data) — scope: `BbDropdownItemSlotProps` — The leading region of every row of that group — e.g. an avatar per record, drawn from `item.meta`, while other rows keep their `prepend:icon`.
2227
- - `#<groupKey>:item:append` (named from data) — scope: `BbDropdownItemSlotProps` — The trailing region of every row of that group; replaces their `append:icon`. The check takes its place on the selected row.
2228
- - `#<groupKey>` (named from data) — scope: `BbDropdownItemSlotProps` — That group's title line (the group is passed as `item`, `groupTitle` is `true`). Reserved keys (their slot is one of this component's own, so a key spelled like them is an error): `activator`, `default`, `empty`, `footer`, `header`, `item`, `loading`.
2229
- - `#<groupKey>:prepend` (named from data) — scope: `BbDropdownItemSlotProps` — The leading region of that group's title line.
2230
- - `#<groupKey>:append` (named from data) — scope: `BbDropdownItemSlotProps` — The trailing region of that group's title line.
2230
+ - `item:append` — scope: `BbDropdownItemSlotProps` `{ description?: string; disabled?: boolean; group: BbDropdownSlotGroup; groupTitle: boolean; level: number; index: number; item: InternalItem; loading: boolean; open: boolean; placement: Placement \| "cursor"; selected: boolean; label: string }` — The trailing region of every row (and group title line), replacing its `append:icon`. A named slot wins over it; the submenu chevron and the check on a selected row take its place.
2231
+ - `item:prepend` — scope: `BbDropdownItemSlotProps` `{ description?: string; disabled?: boolean; group: BbDropdownSlotGroup; groupTitle: boolean; level: number; index: number; item: InternalItem; loading: boolean; open: boolean; placement: Placement \| "cursor"; selected: boolean; label: string }` — The leading region of every row (and group title line), replacing its `prepend:icon`. A row's own or its group's named slot wins over it.
2232
+ - `loading` — scope: `BbDropdownPlaceholderSlotProps` `{ groupId?: string; text: string; error?: unknown }` — Replaces the default loading placeholder row shown in a pipeline group while its async items load. Rendered once per loading group.
2233
+ - `#<value>` (named from data) — scope: `BbDropdownItemSlotProps` — One row's content (label and description), by its value; in a fetched group, by its resolved `itemValue`. Reserved names (their slot is one of this component's own, so an item value or column key spelled like them is an error): `activator`, `default`, `empty`, `footer`, `header`, `item`, `loading`.
2234
+ - `#<value>:prepend` (named from data) — scope: `BbDropdownItemSlotProps` — One row's leading region; replaces its `prepend:icon`.
2235
+ - `#<value>:append` (named from data) — scope: `BbDropdownItemSlotProps` — One row's trailing region; replaces its `append:icon` and its submenu chevron. The check takes its place on the selected row.
2236
+ - `#<groupId>:item` (named from data) — scope: `BbDropdownItemSlotProps` — The content of every row of that group, and no other; a row's own `#<value>` still wins.
2237
+ - `#<groupId>:item:prepend` (named from data) — scope: `BbDropdownItemSlotProps` — The leading region of every row of that group — e.g. an avatar per record, drawn from `item.meta`, while other rows keep their `prepend:icon`.
2238
+ - `#<groupId>:item:append` (named from data) — scope: `BbDropdownItemSlotProps` — The trailing region of every row of that group; replaces their `append:icon`. The check takes its place on the selected row.
2239
+ - `#<groupId>` (named from data) — scope: `BbDropdownItemSlotProps` — That group's title line (the group is passed as `item`, `groupTitle` is `true`). Reserved names (their slot is one of this component's own, so an item value or column key spelled like them is an error): `activator`, `default`, `empty`, `footer`, `header`, `item`, `loading`.
2240
+ - `#<groupId>:prepend` (named from data) — scope: `BbDropdownItemSlotProps` — The leading region of that group's title line.
2241
+ - `#<groupId>:append` (named from data) — scope: `BbDropdownItemSlotProps` — The trailing region of that group's title line.
2231
2242
 
2232
2243
  ## CSS custom properties
2233
2244
 
@@ -2249,12 +2260,12 @@ Set these on the element, or on a class you put on it, to retune this component
2249
2260
 
2250
2261
  - `BbDropdown` _(this component)_ — its own template binds: `panel` → `CommonPopover`, `root` → `CommonPopover`, `header` → `div.bb-dropdown__header`, `list` → `span.bb-dropdown__list`, `footer` → `div.bb-dropdown__footer`
2251
2262
  - `BbDropdownList` _(internal — not importable, reach it through `BbDropdown`)_ — also mounts `BbIcon`, `ErrorIcon`, `CommonPopover`, `BbDropdownList`
2252
- - `BbBaseButton` _(public — [contract](./BbBaseButton.md))_ — its own pt parts (`BbBaseButton`): `root` → `RouterComponent`, `root` → `a`, `root` → `component`; also mounts `RouterComponent`
2253
2263
  - `BbBadge` _(public — [contract](./BbBadge.md))_ — its own pt parts (`BbBadge`): `spinner` → `BbSpinner`, `icon` → `BbIcon`, `clear` → `button.bb-badge__clear`; documented CSS variables: `--bg`, `--fg`, `--bw`, `--ring-color`, `--ring-size`, `--min-size-md`, `--min-size`, `--elev`, `--r`, `--fs`, `--icon-size`, `--gap`, `--px`, `--clear-size`, `--bg-disabled`, `--fg-disabled`, `--border-disabled`, `--pad-left`; also mounts `BbIcon`, `BbSpinner`, `BadgeBodyContent`
2254
2264
  - `AdaptiveDropdown` _(internal — not importable, reach it through `BbDropdown`)_ — hands `BbOffCanvas` the pt map `{ header: 'header', footer: 'footer', panel: 'root', sheet: 'root' }` (ours → theirs); also mounts `BbSmoothHeight`, `BbDropdownList`
2255
2265
  - `BbOffCanvas` _(public — [contract](./BbOffCanvas.md))_ — its own pt parts (`BbOffCanvas`): `header` → `div.bb-offcanvas__header`, `title` → `span.bb-offcanvas__title`, `description` → `p.bb-offcanvas__description`, `close` → `CloseButton`, `content` → `div.bb-offcanvas__content`, `footer` → `div.bb-offcanvas__footer`; documented CSS variables: `--stack-x`, `--stack-fill`, `--stack-transition-duration`, `--px`, `--handle-w`, `--handle-h`, `--handle-bg`, `--safe-top`, `--close-size`
2256
2266
  - `CloseButton` _(internal — not importable, reach it through `BbOffCanvas`)_ — documented CSS variables: `--size`, `--p`
2257
- - `BbButton` _(public — [contract](./BbButton.md))_ — its own pt parts (`BbButton`): `root` → `BbBaseButton`, `spinner` → `BbSpinner`, `icon` → `BbIcon`, `text` → `span.bb-button__text`; documented CSS variables: `--h-xs`, `--h`, `--icon-size`, `--px`, `--fs`, `--r`, `--gap`, `--bg`, `--bg-hover`, `--bg-pressed`, `--fg`, `--border-color`, `--ring-color`, `--ring-size`, `--bw`, `--fg-hover`, `--border-hover`, `--fg-pressed`, `--border-pressed`, `--bg-disabled`, `--fg-disabled`, `--border-disabled`, `--opacity-disabled`, `--elev-tier`, `--elev`; also mounts `BbIcon`, `BbBaseButton`, `BbSpinner`
2267
+ - `BbButton` _(public — [contract](./BbButton.md))_ — its own pt parts (`BbButton`): `root` → `BbBaseButton`, `spinner` → `BbSpinner`, `icon` → `BbIcon`, `text` → `span.bb-button__text`; documented CSS variables: `--h-xs`, `--h`, `--icon-size`, `--px`, `--fs`, `--r`, `--gap`, `--bg`, `--bg-hover`, `--bg-pressed`, `--fg`, `--border-color`, `--ring-color`, `--ring-size`, `--bw`, `--fg-hover`, `--border-hover`, `--fg-pressed`, `--border-pressed`, `--bg-disabled`, `--fg-disabled`, `--border-disabled`, `--opacity-disabled`, `--elev-tier`, `--elev`; also mounts `BbIcon`, `BbSpinner`
2268
+ - `BbBaseButton` _(public — [contract](./BbBaseButton.md))_ — its own pt parts (`BbBaseButton`): `root` → `RouterComponent`, `root` → `a`, `root` → `component`; also mounts `RouterComponent`
2258
2269
  - Also mounts `CommonPopover`, `DropdownPipelineResolver`
2259
2270
 
2260
2271
  ## See Also