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
@@ -249,26 +249,33 @@ watch(
249
249
  );
250
250
 
251
251
  /**
252
- * BbButton-bound props for the main action, taken from the first leaf item.
253
- * Icons and visual variant come from the component's own props instead, so they
254
- * are dropped here along with dropdown-only fields (`key`, `items`, `group`).
252
+ * BbButton-bound props for the main action, taken from the first leaf item: its
253
+ * `label` becomes the button's text. Icons and visual variant come from the
254
+ * component's own props instead, so they are dropped here along with the
255
+ * row-only fields (`value`, `label`, `meta`, `description`, `items`, `group`).
255
256
  */
256
257
  const OMITTED_MAIN_FIELDS = new Set([
257
- 'key',
258
+ 'value',
259
+ 'label',
260
+ 'meta',
261
+ 'description',
258
262
  'items',
259
263
  'group',
260
264
  'variant',
261
265
  'prepend:icon',
262
266
  'append:icon',
263
267
  ]);
264
- const mainBtnProps = computed(
265
- () =>
266
- Object.fromEntries(
267
- Object.entries(flatMappedItems.value[0] ?? {}).filter(
268
+ const mainBtnProps = computed(() => {
269
+ const first = flatMappedItems.value[0];
270
+ return {
271
+ ...Object.fromEntries(
272
+ Object.entries(first ?? {}).filter(
268
273
  ([key]) => !OMITTED_MAIN_FIELDS.has(key)
269
274
  )
270
- ) as Partial<InternalItem>
271
- );
275
+ ),
276
+ text: first?.label,
277
+ } as Omit<Partial<InternalItem>, 'text'> & { text?: string };
278
+ });
272
279
  </script>
273
280
 
274
281
  <style lang="postcss">
@@ -570,8 +577,8 @@ export type BbDropdownButtonItemSlotProps = {
570
577
  open: boolean;
571
578
  /** The current placement of the dropdown panel. */
572
579
  placement: BbDropdownProps['placement'];
573
- /** The resolved display text for this item. */
574
- text: MappedItem['text'];
580
+ /** The row's label. */
581
+ label: MappedItem['label'];
575
582
  };
576
583
 
577
584
  /**
@@ -276,9 +276,9 @@ export type { DropdownItemVariantType };
276
276
  export type DropdownTrigger = 'click' | 'contextMenu';
277
277
 
278
278
  /**
279
- * Props shared between {@link InternalItem} and {@link InternalGroup}. Both are
280
- * dropdown entries identified by `key` with optional icons, a variant, and a
281
- * click handler.
279
+ * Props shared between {@link InternalItem} and {@link InternalGroup}: optional
280
+ * icons, a variant, a click handler and `meta`. A row is identified by its
281
+ * `value`, a group by its `id`.
282
282
  */
283
283
  type DropdownEntryBase = {
284
284
  /**
@@ -287,25 +287,11 @@ type DropdownEntryBase = {
287
287
  * group (the check is), or when an append slot fills the region.
288
288
  */
289
289
  'append:icon'?: IconType;
290
- /**
291
- * Key used to identify the entry. REQUIRED when anything outside the menu
292
- * reads it: a row in a `selectable` group (the v-model holds it), a row or
293
- * group with its own slot (`#<key>` is named by it), a group bound by a
294
- * `<BbDropdownGroup id>` or selectable. Optional on a plain action row (it
295
- * runs its `onClick`) and a layout-only group: the dropdown then derives an
296
- * internal identity from the text that nothing outside ever sees. A keyless
297
- * row in a selectable group renders but can't be selected. Load-bearing
298
- * identifiers are written, never derived — `bitboss-ui check` flags a
299
- * missing required key where the items are in the same file.
300
- */
301
- key?: string;
302
- /** @internal Set by the dropdown on a row it derived a key for (Q53.17). */
303
- keyless?: true;
304
290
  /**
305
291
  * Your own data for this entry, carried untouched to its slots (as
306
292
  * `item.meta`) and to per-item `pt` functions. The dropdown never reads it
307
293
  * and never puts it on the DOM. Typically the record the entry stands for,
308
- * e.g. `{ key: clinic.id, text: clinic.name, meta: clinic }`; a fetched
294
+ * e.g. `{ value: clinic.id, label: clinic.name, meta: clinic }`; a fetched
309
295
  * group sets it through `itemProps` (`(clinic) => ({ meta: clinic })`).
310
296
  */
311
297
  meta?: any;
@@ -324,14 +310,14 @@ type DropdownEntryBase = {
324
310
 
325
311
  /**
326
312
  * The `itemProps` fields of a fetched (pipeline) dropdown group: everything a
327
- * hand-written row accepts except its identity and structure (`key`, `text`,
328
- * `items`, `group`) and `disabled`. See {@link InternalGroup.itemProps}.
313
+ * hand-written row accepts except its identity and structure (`value`,
314
+ * `label`, `items`, `group`) and `disabled`. See {@link InternalGroup.itemProps}.
329
315
  */
330
316
  export type DropdownItemFields = Omit<
331
317
  BbBaseButtonProps,
332
318
  'block' | 'tag' | 'type' | 'text' | 'disabled'
333
319
  > &
334
- Omit<DropdownEntryBase, 'key'> & {
320
+ DropdownEntryBase & {
335
321
  /** Muted second line under the row text. */
336
322
  description: string;
337
323
  };
@@ -374,13 +360,46 @@ type SubmenuExclusive =
374
360
  }
375
361
  | { items?: undefined };
376
362
 
377
- export type InternalItem = Omit<BbBaseButtonProps, 'block' | 'tag' | 'type'> &
363
+ export type InternalItem = Omit<
364
+ BbBaseButtonProps,
365
+ 'block' | 'tag' | 'type' | 'text'
366
+ > &
378
367
  SubmenuExclusive &
379
368
  DropdownEntryBase & {
380
- /** Display text rendered as the button label. */
381
- text: string;
369
+ /** The row's text. */
370
+ label: string;
371
+ /**
372
+ * The row's identity, any type: what `v-model` holds when its group is
373
+ * `selectable` (compared by `hash()`, like `BbSelect` options, so `null`
374
+ * and objects are values too: a `value: null` row is the group's "None"),
375
+ * the name of its own slots (`#<value>`, a string or number value
376
+ * through `slotKey`; any other type gets the shared slots only) and the
377
+ * seed of its submenu's id.
378
+ *
379
+ * REQUIRED when anything outside the menu reads it: a row in a
380
+ * `selectable` group, a row with its own slot. Optional on a plain
381
+ * action row (it runs its `onClick`): the dropdown then derives an
382
+ * internal identity from the label that nothing outside ever sees. A row
383
+ * without a `value` in a selectable group renders disabled. Load-bearing
384
+ * identifiers are written, never derived — `bitboss-ui check` flags a
385
+ * missing required `value` where the items are in the same file.
386
+ */
387
+ value?: unknown;
388
+ /** Rows have no `key` (that is `value`). Guards against the old shape. */
389
+ key?: never;
390
+ /** Rows have no `text` (that is `label`). Guards against the old shape. */
391
+ text?: never;
392
+ /** @internal Set by the dropdown on a row it derived an identity for (Q53.17). */
393
+ keyless?: true;
394
+ /**
395
+ * @internal The row's selection key, set by the dropdown: `hash(value)`,
396
+ * or the identity it derived for a row without a `value`.
397
+ */
398
+ rowKey?: string;
399
+ /** @internal The row's readable DOM token, set by the dropdown (submenu ids). */
400
+ domKey?: string;
382
401
  /**
383
- * Muted descriptive line rendered below `text`. The row grows to fit it,
402
+ * Muted descriptive line rendered below `label`. The row grows to fit it,
384
403
  * while icons/check/chevron stay aligned with the title line.
385
404
  */
386
405
  description?: string;
@@ -407,7 +426,7 @@ export type InternalItem = Omit<BbBaseButtonProps, 'block' | 'tag' | 'type'> &
407
426
  * async items load (`'loading'`), when it resolved empty (`'empty'`), or
408
427
  * when its latest load FAILED (`'failed'`: the footer under whatever rows a
409
428
  * `stash` keeps listed, Q61.15). Rendered as a non-interactive row that
410
- * shows `text` or, when provided, the dropdown's `loading` / `empty` slot.
429
+ * shows `label` or, when provided, the dropdown's `loading` / `empty` slot.
411
430
  * Internal — set by `BbDropdownGroup`.
412
431
  */
413
432
  placeholder?: 'loading' | 'empty' | 'failed';
@@ -427,8 +446,8 @@ export type InternalItem = Omit<BbBaseButtonProps, 'block' | 'tag' | 'type'> &
427
446
  /**
428
447
  * Optional slot token used to resolve per-item named slots. Primarily set
429
448
  * by the pipeline resolver so slot names can be derived from the resolved
430
- * `itemValue` (readable), while `key` remains the hash-based selection id.
431
- * Internal.
449
+ * `itemValue` (readable), while `rowKey` remains the hash-based selection
450
+ * id. Internal.
432
451
  */
433
452
  slotKey?: string;
434
453
  };
@@ -469,6 +488,18 @@ export type DropdownGroupItemsGetter =
469
488
  ) => any[] | Promise<any[]>);
470
489
 
471
490
  export type InternalGroup = DropdownEntryBase & {
491
+ /**
492
+ * The group's identity: REQUIRED on a `selectable` group (its picks are
493
+ * stored under it, and `useBbDropdownContext` keys the group by it), on a
494
+ * group bound by a `<BbDropdownGroup id>` (the same word) and on a group
495
+ * with its own slots (`#<id>:item`, `#<id>`). Optional on a layout-only
496
+ * group; a selectable group without one renders as a plain group.
497
+ */
498
+ id?: string;
499
+ /** Groups have no `key` (that is `id`). Guards against the old shape. */
500
+ key?: never;
501
+ /** Groups have no `value`; their rows do. */
502
+ value?: never;
472
503
  /** Pipeline groups only. Re-run the async getter when any of these change. */
473
504
  dependencies?: unknown[];
474
505
  /** Pipeline groups only. Debounce (ms) for `dependencies`-driven re-fetch. */
@@ -507,17 +538,19 @@ export type InternalGroup = DropdownEntryBase & {
507
538
  | any[]
508
539
  | DropdownGroupItemsGetter;
509
540
  /**
510
- * Pipeline groups only. Path/getter producing each item's display text.
511
- * Defaults to `JSON.stringify(item)` (or the string itself for strings).
541
+ * Pipeline groups only. Path/getter producing each item's display text
542
+ * (a string item is its own text).
543
+ *
544
+ * Unset: own `label`, else `text` (`{ label, value }` needs no accessor).
512
545
  *
513
- * @defaultValue `JSON.stringify(item)`
546
+ * @defaultValue own `label`, else `text`, else `JSON.stringify(item)`
514
547
  */
515
548
  itemText?: string | ((item: any) => string);
516
549
  /**
517
550
  * Pipeline groups only. The ADDITIONAL fields of each fetched row — never its
518
551
  * text or value, which stay on `itemText` / `itemValue`. A fetched row takes
519
552
  * every field a hand-written row accepts except its identity and structure
520
- * (`key`, `text`, `items`, `group`) and `disabled`: `description`, the icons,
553
+ * (`value`, `label`, `items`, `group`) and `disabled`: `description`, the icons,
521
554
  * `variant`, `onClick`, `href` / `to` and the rest of the link and Inertia
522
555
  * options.
523
556
  *
@@ -528,17 +561,18 @@ export type InternalGroup = DropdownEntryBase & {
528
561
  * the handler: `onClick: (user) => () => open(user)`.
529
562
  *
530
563
  * Nothing is read off the raw item implicitly — without `itemProps` a row
531
- * has only its text. An empty value means the field is absent. To disable
564
+ * has only its label. An empty value means the field is absent. To disable
532
565
  * individual rows use a `selectable` predicate on the group; fetched groups
533
566
  * are for selection (see plans/ITEM-DESCRIPTION.md v2.4).
534
567
  */
535
568
  itemProps?: BbDropdownItemProps;
536
569
  /**
537
570
  * Pipeline groups only. Path/getter producing each item's value — what
538
- * `v-model` surfaces; its hash is the internal selection key. Defaults to the
539
- * whole item (so the key is the hash of the entire object).
571
+ * `v-model` surfaces; its hash is the internal selection key.
540
572
  *
541
- * @defaultValue the whole item
573
+ * Unset: own `value`, even `null`.
574
+ *
575
+ * @defaultValue own `value`, else the whole item
542
576
  */
543
577
  itemValue?: string | ((item: any) => any);
544
578
  /** Pipeline groups only. Placeholder row text while async items load. */
@@ -629,7 +663,7 @@ export type InternalGroup = DropdownEntryBase & {
629
663
  */
630
664
  selectable?: boolean | ((item: any) => boolean);
631
665
  /**
632
- * Searchable pipeline groups only. Accumulate the items behind *selected* keys
666
+ * Searchable pipeline groups only. Accumulate the items behind *selected* values
633
667
  * so they stay resolvable across searches. Without it, selecting an item in one
634
668
  * search and then searching for something else leaves the earlier selection
635
669
  * unresolvable (its value/text is gone from the current results) — which in a
@@ -674,7 +708,7 @@ export const groupItemsAsArray = (
674
708
  * - an array of items — rendered as an anonymous divider-separated group;
675
709
  * - a {@link InternalGroup} object — a titled / selectable section.
676
710
  *
677
- * The shapes can be mixed, e.g. `[item, [item, item], { key, title, items }]`.
711
+ * The shapes can be mixed, e.g. `[item, [item, item], { id, label, items }]`.
678
712
  */
679
713
  export type Item = InternalItem | InternalGroup | Item[];
680
714
 
@@ -719,10 +753,11 @@ export const isGroup = (entry: Item): entry is InternalGroup =>
719
753
  * defaults are resolved here. Produced by `normalizeGroups`.
720
754
  */
721
755
  /**
722
- * A row after normalization: its `key` is always set — the consumer's, or one
723
- * the dropdown derived for a keyless action row (`keyless`, Q53.17).
756
+ * A row after normalization: its `rowKey` is always set — `hash(value)`, or an
757
+ * identity the dropdown derived for an action row without a `value`
758
+ * (`keyless`, Q53.17).
724
759
  */
725
- export type KeyedItem = InternalItem & { key: string };
760
+ export type KeyedItem = InternalItem & { rowKey: string; domKey: string };
726
761
 
727
762
  export type NormalizedGroup = {
728
763
  'append:icon'?: IconType;
@@ -730,11 +765,11 @@ export type NormalizedGroup = {
730
765
  clearable?: boolean;
731
766
  /** Whether a divider is rendered before this group. */
732
767
  divider: boolean;
733
- /** Keys matched against each raw item when searching (empty ⇒ match text). */
768
+ /** Keys matched against each raw item when searching (empty ⇒ match the label). */
734
769
  filterBy?: string[];
735
770
  items: KeyedItem[];
736
- /** Group key (when it originated from a {@link InternalGroup} object). */
737
- key?: string;
771
+ /** Group id (when it originated from a {@link InternalGroup} object). */
772
+ id?: string;
738
773
  /** Fixed max-height (px number or CSS length) of this group's item region. */
739
774
  maxHeight?: number | string;
740
775
  /** The group's own `meta`, untouched. */
@@ -747,7 +782,7 @@ export type NormalizedGroup = {
747
782
  /** Placeholder for this group's search field. */
748
783
  searchPlaceholder?: string;
749
784
  selectable: boolean;
750
- /** Selected item keys (injected by `BbDropdown`; empty for non-selectable groups). */
785
+ /** Selected row keys (`rowKey`; injected by `BbDropdown`; empty for non-selectable groups). */
751
786
  selected: string[];
752
787
  /** The group's label. Loose/anonymous groups have none. */
753
788
  label?: string;
@@ -771,7 +806,7 @@ export type MappedItem = InternalItem & {
771
806
  * Passthrough parts of `BbDropdown` (plans/passthrough/BbDropdown.md). Groups,
772
807
  * headings and dividers are not parts.
773
808
  *
774
- * Per-item functions: on the instance, an entry part (`item`, `itemText`, `itemIcon`, `itemDescription`) also accepts `({ item, selected, … }) => PtValue | false | null | undefined` — `item` is the menu entry (an `Item`: its `text`, `key`, `description`, whatever else you put on it), and every state a boolean beside it, on for it (`selected`, `disabled`, …) — in the `pt` object or the `:pt:<part>` attribute, never on a `<part>:<state>` key and never in the global map or a scope (they ship as JSON). Its result is merged last, after every state entry, through the same deduper; a falsy result leaves the entry as it was. See the passthrough guide, _Per-item functions_.
809
+ * Per-item functions: on the instance, an entry part (`item`, `itemText`, `itemIcon`, `itemDescription`) also accepts `({ item, selected, … }) => PtValue | false | null | undefined` — `item` is the menu entry (an `Item`: its `label`, `value`, `description`, whatever else you put on it), and every state a boolean beside it, on for it (`selected`, `disabled`, …) — in the `pt` object or the `:pt:<part>` attribute, never on a `<part>:<state>` key and never in the global map or a scope (they ship as JSON). Its result is merged last, after every state entry, through the same deduper; a falsy result leaves the entry as it was. See the passthrough guide, _Per-item functions_.
775
810
  *
776
811
  * @part root - The floating element — an invisible positioning wrapper; a
777
812
  * `class` on the component lands here. No node on the phone sheet: style
@@ -791,13 +826,13 @@ export type MappedItem = InternalItem & {
791
826
  * headings and dividers are not parts.
792
827
  * @part item - One menu entry, submenus included — a broadcast resolved per
793
828
  * entry. Also takes a per-item function, called with the entry.
794
- * @part itemText - An entry's label (its `text`) — resolved with that
795
- * entry's states. A per-entry `#<key>` slot replaces it. Also takes a
829
+ * @part itemText - An entry's label (its `label`) — resolved with that
830
+ * entry's states. A per-entry `#<value>` slot replaces it. Also takes a
796
831
  * per-item function.
797
832
  * @part itemIcon - An entry's prepend / append icons — resolved with that
798
833
  * entry's states. Also takes a per-item function.
799
834
  * @part itemDescription - An entry's muted second line (its `description`) —
800
- * resolved with that entry's states. A per-entry `#<key>` slot replaces it.
835
+ * resolved with that entry's states. A per-entry `#<value>` slot replaces it.
801
836
  * Also takes a per-item function.
802
837
  */
803
838
  export type BbDropdownPtPart =
@@ -936,7 +971,8 @@ export type BbDropdownProps = {
936
971
  disabled?: boolean;
937
972
  /**
938
973
  * Renders the menu panel at mount instead of on the first open (the phone
939
- * sheet's too).
974
+ * sheet's too), and keeps its rows after a close. Without it the rows mount
975
+ * on each open and go once the menu has closed.
940
976
  */
941
977
  eager?: boolean;
942
978
  /**
@@ -1063,8 +1099,8 @@ export type BbDropdownEvents = {
1063
1099
  /**
1064
1100
  * The user selected a row in a selectable group, at the click — also when a
1065
1101
  * controlled companion's app then refuses the value. The payload is the
1066
- * item's resolved value (its `item-value` for pipeline groups, else its
1067
- * `key`) — symmetric with `BbTable`'s `item:selected`.
1102
+ * row's value (its `item-value` for pipeline groups, else its `value`) —
1103
+ * symmetric with `BbTable`'s `item:selected`.
1068
1104
  */
1069
1105
  (e: 'item:selected', value: any): void;
1070
1106
  /**
@@ -1110,11 +1146,11 @@ export type BbDropdownEdgeSlotProps = {
1110
1146
 
1111
1147
  /**
1112
1148
  * The group a slot renders in, as item slots see it. Anonymous groups (loose
1113
- * items, plain arrays) have no `key` and no `label`.
1149
+ * items, plain arrays) have no `id` and no `label`.
1114
1150
  */
1115
1151
  export type BbDropdownSlotGroup = {
1116
- /** The group's key, when it was declared as a group object. */
1117
- key?: string;
1152
+ /** The group's id, when it was declared as a group object. */
1153
+ id?: string;
1118
1154
  /** The group's label, when it has one (also when `hideLabel` hides it). */
1119
1155
  label?: string;
1120
1156
  /** The group's own `meta`. */
@@ -1162,14 +1198,14 @@ export type BbDropdownItemSlotProps = {
1162
1198
  placement: BbDropdownProps['placement'];
1163
1199
  /** Whether the item currently sits in a selectable group and is selected. */
1164
1200
  selected: boolean;
1165
- /** The resolved display text for this item. */
1166
- text: InternalItem['text'];
1201
+ /** The row's label (on a group's title line, the group's label). */
1202
+ label: InternalItem['label'];
1167
1203
  };
1168
1204
 
1169
1205
  /** Props exposed by the `loading` and `empty` placeholder slots. */
1170
1206
  export type BbDropdownPlaceholderSlotProps = {
1171
- /** Key of the group this placeholder belongs to. */
1172
- groupKey?: string;
1207
+ /** Id of the group this placeholder belongs to. */
1208
+ groupId?: string;
1173
1209
  /** Resolved placeholder text (group `loadingText`/`emptyText`/`failedText` → dropdown default). */
1174
1210
  text: string;
1175
1211
  /**
@@ -1181,23 +1217,24 @@ export type BbDropdownPlaceholderSlotProps = {
1181
1217
  };
1182
1218
 
1183
1219
  /**
1184
- * Besides the fixed slots, every entry gets named slots from its key run
1185
- * through `slotKey` (`'practice-switcher'` → `practice_switcher`). The most
1186
- * specific slot a row has wins: its own, then its group's, then the shared
1187
- * `item:prepend` / `item:append`. Each edge has ONE occupant: a slot replaces
1188
- * the `prepend:icon` / `append:icon`. On the trailing edge the selected row's
1189
- * check beats every slot, a row's own `#<key>:append` beats the submenu
1190
- * chevron, and the chevron beats the group-wide and shared slots.
1220
+ * Besides the fixed slots, every row gets named slots from its `value` (a
1221
+ * string or number) run through `slotKey` (`'practice-switcher'` →
1222
+ * `practice-switcher`, `'Delete file'` → `delete-file`), and every group from
1223
+ * its `id`. The most specific slot a row has wins: its own, then its group's,
1224
+ * then the shared `item:prepend` / `item:append`. Each edge has ONE occupant: a
1225
+ * slot replaces the `prepend:icon` / `append:icon`. On the trailing edge the
1226
+ * selected row's check beats every slot, a row's own `#<value>:append` beats
1227
+ * the submenu chevron, and the chevron beats the group-wide and shared slots.
1191
1228
  *
1192
- * @dynamicSlot `<key>` {BbDropdownItemSlotProps} - One row's content (text and description), by its key; in a fetched group, by its resolved `itemValue`.
1193
- * @dynamicSlot `<key>:prepend` {BbDropdownItemSlotProps} - One row's leading region; replaces its `prepend:icon`.
1194
- * @dynamicSlot `<key>:append` {BbDropdownItemSlotProps} - One row's trailing region; replaces its `append:icon` and its submenu chevron. The check takes its place on the selected row.
1195
- * @dynamicSlot `<groupKey>:item` {BbDropdownItemSlotProps} - The content of every row of that group, and no other; a row's own `#<key>` still wins.
1196
- * @dynamicSlot `<groupKey>:item:prepend` {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`.
1197
- * @dynamicSlot `<groupKey>:item:append` {BbDropdownItemSlotProps} - The trailing region of every row of that group; replaces their `append:icon`. The check takes its place on the selected row.
1198
- * @dynamicSlot `<groupKey>` {BbDropdownItemSlotProps} - That group's title line (the group is passed as `item`, `groupTitle` is `true`).
1199
- * @dynamicSlot `<groupKey>:prepend` {BbDropdownItemSlotProps} - The leading region of that group's title line.
1200
- * @dynamicSlot `<groupKey>:append` {BbDropdownItemSlotProps} - The trailing region of that group's title line.
1229
+ * @dynamicSlot `<value>` {BbDropdownItemSlotProps} - One row's content (label and description), by its value; in a fetched group, by its resolved `itemValue`.
1230
+ * @dynamicSlot `<value>:prepend` {BbDropdownItemSlotProps} - One row's leading region; replaces its `prepend:icon`.
1231
+ * @dynamicSlot `<value>:append` {BbDropdownItemSlotProps} - One row's trailing region; replaces its `append:icon` and its submenu chevron. The check takes its place on the selected row.
1232
+ * @dynamicSlot `<groupId>:item` {BbDropdownItemSlotProps} - The content of every row of that group, and no other; a row's own `#<value>` still wins.
1233
+ * @dynamicSlot `<groupId>:item:prepend` {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`.
1234
+ * @dynamicSlot `<groupId>:item:append` {BbDropdownItemSlotProps} - The trailing region of every row of that group; replaces their `append:icon`. The check takes its place on the selected row.
1235
+ * @dynamicSlot `<groupId>` {BbDropdownItemSlotProps} - That group's title line (the group is passed as `item`, `groupTitle` is `true`).
1236
+ * @dynamicSlot `<groupId>:prepend` {BbDropdownItemSlotProps} - The leading region of that group's title line.
1237
+ * @dynamicSlot `<groupId>:append` {BbDropdownItemSlotProps} - The trailing region of that group's title line.
1201
1238
  */
1202
1239
  export type BbDropdownSlots = {
1203
1240
  /**
@@ -1245,17 +1282,13 @@ export type BbDropdownSlots = {
1245
1282
  } & Record<string, (props: BbDropdownItemSlotProps) => any>;
1246
1283
 
1247
1284
  /**
1248
- * `v-model` value of `<BbDropdownGroup>`.
1249
- *
1250
- * - **Legacy group** (pre-shaped `items` with explicit `key`/`text` in
1251
- * `BbDropdown.items`): the model mirrors the selected item *keys* —
1252
- * `string | null` (single) or `string[]` (multiple).
1253
- * - **Pipeline group** (`items` getter + `item-text`/`item-value` in
1254
- * `BbDropdown.items`): the model mirrors the selected *values* produced by
1255
- * `item-value` (the whole object by default) — `T | null` (single) or `T[]`
1256
- * (multiple).
1285
+ * `v-model` value of `<BbDropdownGroup>`: the selected rows' values — a
1286
+ * hand-written row's `value`, or what `item-value` produces in a pipeline group
1287
+ * (its own `value`, else the whole item). `T | null` (single) or `T[]`
1288
+ * (multiple). A single group whose model is `null` shows its `value: null` row
1289
+ * (the "None" row) checked, when it has one.
1257
1290
  */
1258
- export type BbDropdownGroupModel<T = any> = T[] | T | string[] | string | null;
1291
+ export type BbDropdownGroupModel<T = any> = T[] | T | null;
1259
1292
 
1260
1293
  /**
1261
1294
  * Props of the `<BbDropdownGroup>` companion. Intentionally minimal: the group
@@ -1265,7 +1298,7 @@ export type BbDropdownGroupModel<T = any> = T[] | T | string[] | string | null;
1265
1298
  */
1266
1299
  export type BbDropdownGroupProps = {
1267
1300
  /**
1268
- * Identifier of the group to bind to — must match the `key` of a group
1301
+ * Identifier of the group to bind to — must match the `id` of a group
1269
1302
  * declared in the host `BbDropdown`'s `items`.
1270
1303
  */
1271
1304
  id: string;
@@ -1280,8 +1313,8 @@ export type BbDropdownGroupEvents = {
1280
1313
  (e: 'update:modelValue', value: BbDropdownGroupModel): void;
1281
1314
  /**
1282
1315
  * The user picked a row, at the click, a pick you then refuse included —
1283
- * with the item's resolved value (its `item-value` for pipeline groups, else
1284
- * its `key`), symmetric with `BbTable`. Your own `v-model` changes fire none.
1316
+ * with the row's value (its `item-value` for pipeline groups, else its
1317
+ * `value`), symmetric with `BbTable`. Your own `v-model` changes fire none.
1285
1318
  */
1286
1319
  (e: 'item:selected', value: any): void;
1287
1320
  /** The user unpicked a row (or a single pick replaced it), with its resolved value. */
@@ -1656,7 +1689,7 @@ export type BbDropdownGroupEvents = {
1656
1689
  min-width: 0;
1657
1690
  padding: 2px 6px;
1658
1691
  position: relative;
1659
- text-align: left;
1692
+ text-align: start;
1660
1693
  width: 100%;
1661
1694
 
1662
1695
  /* `:focus-visible`, NOT `:focus`. Rows are `tabindex="-1"` (ARIA menu
@@ -2007,7 +2040,7 @@ export type BbDropdownGroupEvents = {
2007
2040
  height: var(--sheet-row-h, 44px);
2008
2041
  /* Flyout rows are `2px 6px`. +4px start so the label shares the
2009
2042
  search field's text edge (`padding-inline: 0.75rem` on the fill). */
2010
- padding-left: calc(6px + 4px);
2043
+ padding-inline-start: calc(6px + 4px);
2011
2044
  /* iOS treats a <button> as a tap target and will not hand the pan to
2012
2045
  the sheet body unless the control itself opts into vertical panning.
2013
2046
  Without this, dismiss/scroll work on the handle and miss on rows. */
@@ -2034,7 +2067,7 @@ export type BbDropdownGroupEvents = {
2034
2067
 
2035
2068
  .bb-dropdown__placeholder {
2036
2069
  min-height: var(--sheet-row-h, 44px);
2037
- padding-left: calc(6px + 4px);
2070
+ padding-inline-start: calc(6px + 4px);
2038
2071
  }
2039
2072
 
2040
2073
  /* Icons scale with the label they sit beside. The desktop sizes (16px
@@ -2101,7 +2134,7 @@ export type BbDropdownGroupEvents = {
2101
2134
  .bb-dropdown__sheet-selection {
2102
2135
  flex-shrink: 0;
2103
2136
  padding: 0 0 0.5rem;
2104
- text-align: left;
2137
+ text-align: start;
2105
2138
  }
2106
2139
 
2107
2140
  .bb-dropdown__sheet-chips {
@@ -2145,7 +2178,7 @@ export type BbDropdownGroupEvents = {
2145
2178
  Use `--bb-panel-p`, not `--px`: BbButton redefines `--px` as its
2146
2179
  own padding token, which collapsed the inset to 10px. */
2147
2180
  .bb-dropdown__nav-back {
2148
- left: var(--bb-panel-p);
2181
+ inset-inline-start: var(--bb-panel-p);
2149
2182
  position: absolute;
2150
2183
  top: var(--bb-panel-p);
2151
2184
 
@@ -96,6 +96,7 @@ import {
96
96
  schemaRequires,
97
97
  toFormSchema,
98
98
  } from './formSchema';
99
+ import { BB_FORM_SUBMIT_LOCK } from '@/composables/formSubmitLock';
99
100
  import {
100
101
  BB_FORM_FIELDS,
101
102
  type BbFormField,
@@ -173,6 +174,15 @@ const props = defineProps<{
173
174
  * drops once the user edits the field, call `setErrors` instead.
174
175
  */
175
176
  fieldErrors?: Record<string, unknown> | null;
177
+ /**
178
+ * Keep the fields editable while a save runs. By default, while a
179
+ * `@submit` that returned a promise is pending, every field joined to the
180
+ * form is read-only (never disabled: values stay readable and focusable)
181
+ * and every `type="submit"` BbButton inside the form shows its spinner;
182
+ * both end when the promise settles. A `@submit` that returns nothing
183
+ * never locks.
184
+ */
185
+ disableSubmitLock?: boolean;
176
186
  }>();
177
187
 
178
188
  // Declared for the public typing and the manifest. The submit handler is
@@ -312,6 +322,7 @@ provide(BB_FORM_CONNECTION, {
312
322
  });
313
323
 
314
324
  provide(BB_FORM_FIELDS, {
325
+ locked: () => submitLocked(),
315
326
  isRequired: (name) => schemaRequires(unref(props.schema), name),
316
327
  validationMode: () => props.validationMode,
317
328
  fieldErrors: fieldErrorsAt,
@@ -653,6 +664,11 @@ const onInvalidSubmit = async (context: InvalidSubmissionContext) => {
653
664
  */
654
665
  const instance = getCurrentInstance();
655
666
 
667
+ /** Q60.17: saves still pending (a second submit can overlap the first). */
668
+ const savesInFlight = ref(0);
669
+ const submitLocked = () => savesInFlight.value > 0 && !props.disableSubmitLock;
670
+ provide(BB_FORM_SUBMIT_LOCK, { locked: submitLocked });
671
+
656
672
  type SubmitListener = (values: Record<string, unknown>) => unknown;
657
673
 
658
674
  /** `@submit.once` compiles to a SEPARATE `onSubmitOnce` prop — Vue's own emit
@@ -712,7 +728,15 @@ const runSubmitListeners = (formValues: Record<string, unknown>) => {
712
728
  }
713
729
  // Await only what is actually awaitable, so a sync handler keeps the exact
714
730
  // timing it has today rather than being pushed a microtask later.
715
- return pending.length ? Promise.all(pending) : undefined;
731
+ if (!pending.length) return undefined;
732
+ // Q60.17: the form locks for exactly as long as the save runs. Its own
733
+ // flag, not vee-validate's `isSubmitting`, which is also true while
734
+ // validation runs, so a sync submit would flash the lock.
735
+ const save = Promise.all(pending);
736
+ savesInFlight.value++;
737
+ return save.finally(() => {
738
+ savesInFlight.value--;
739
+ });
716
740
  };
717
741
 
718
742
  // With a schema, `formValues` is the schema's OUTPUT: vee-validate hands the
@@ -278,12 +278,14 @@ export type BbIndicatorSlots = {
278
278
  font-weight: 500;
279
279
  gap: var(--gap);
280
280
  justify-content: center;
281
+ /* stylelint-disable-next-line property-disallowed-list -- geometry: the `left` prop names a physical side */
281
282
  left: auto;
282
283
  line-height: 1;
283
284
  min-height: var(--min-size);
284
285
  min-width: var(--min-size);
285
286
  padding: 0 var(--px);
286
287
  position: absolute;
288
+ /* stylelint-disable-next-line property-disallowed-list -- geometry: the `left` prop names a physical side */
287
289
  right: calc(0% - var(--position-offset));
288
290
  top: calc(0% - var(--position-offset));
289
291
  transition:
@@ -314,7 +316,9 @@ export type BbIndicatorSlots = {
314
316
  }
315
317
 
316
318
  &.bb-indicator--left .bb-indicator__bubble {
319
+ /* stylelint-disable-next-line property-disallowed-list -- geometry: the `left` prop names a physical side */
317
320
  left: calc(0% - var(--position-offset));
321
+ /* stylelint-disable-next-line property-disallowed-list -- geometry: the `left` prop names a physical side */
318
322
  right: auto;
319
323
  }
320
324