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.
- package/README.md +24 -7
- package/bin/bitboss-ui-mcp.mjs +15 -3
- package/bin/bitboss-ui.mjs +115 -13
- package/dist/ai/BbAvatar.md +1 -1
- package/dist/ai/BbBreadcrumbs.md +65 -65
- package/dist/ai/BbButton.md +16 -5
- package/dist/ai/BbCheckbox.md +0 -2
- package/dist/ai/BbCheckboxGroup.md +13 -20
- package/dist/ai/BbDatePickerInput.md +4 -2
- package/dist/ai/BbDialog.md +1 -8
- package/dist/ai/BbDropdown.md +231 -220
- package/dist/ai/BbDropdownButton.md +65 -65
- package/dist/ai/BbDropdownGroup.md +2 -2
- package/dist/ai/BbDropzone.md +10 -10
- package/dist/ai/BbForm.md +43 -52
- package/dist/ai/BbHoverCard.md +4 -2
- package/dist/ai/BbNumberInput.md +88 -21
- package/dist/ai/BbPopover.md +29 -23
- package/dist/ai/BbProgress.md +48 -22
- package/dist/ai/BbRadioGroup.md +13 -19
- package/dist/ai/BbSelect.md +16 -36
- package/dist/ai/BbSelectPopover.md +14 -30
- package/dist/ai/BbSmoothHeight.md +0 -2
- package/dist/ai/BbSwitchGroup.md +13 -20
- package/dist/ai/BbTable.md +11 -10
- package/dist/ai/BbTabs.md +106 -105
- package/dist/ai/BbTabsList.md +2 -2
- package/dist/ai/BbTabsPanels.md +1 -1
- package/dist/ai/BbTabsRoot.md +2 -2
- package/dist/ai/BbTooltip.md +24 -10
- package/dist/ai/BbTree.md +14 -11
- package/dist/ai/changelog.json +256 -5
- package/dist/ai/components.json +36 -34
- package/dist/ai/composables/useBbDropdownContext.md +16 -16
- package/dist/ai/composables/useBbFormField.md +5 -1
- package/dist/ai/composables/useBbTabsContext.md +14 -14
- package/dist/ai/guides/agent-contract.md +27 -27
- package/dist/ai/guides/ai-router.md +1 -1
- package/dist/ai/guides/component-picker.md +3 -3
- package/dist/ai/guides/fetch-items-playbook.md +1 -1
- package/dist/ai/guides/icons-policy.md +10 -10
- package/dist/ai/guides/inertia-helpers.md +120 -67
- package/dist/ai/guides/installation-and-plugin-setup.md +43 -15
- package/dist/ai/guides/migration/components/bb-breadcrumbs.md +3 -2
- package/dist/ai/guides/migration/components/bb-checkbox-group.md +16 -16
- package/dist/ai/guides/migration/components/bb-dropdown-button.md +9 -8
- package/dist/ai/guides/migration/components/bb-dropdown.md +15 -14
- package/dist/ai/guides/migration/components/bb-radio-group.md +2 -1
- package/dist/ai/guides/migration/components/bb-select-popover.md +6 -1
- package/dist/ai/guides/migration/components/bb-select.md +10 -2
- package/dist/ai/guides/migration/components/bb-switch-group.md +2 -1
- package/dist/ai/guides/migration/components/bb-tabs.md +9 -8
- package/dist/ai/guides/migration/components/bb-tooltip.md +1 -1
- package/dist/ai/guides/migration/v2-to-v3.md +114 -17
- package/dist/ai/guides/migration/v3-beta-tooling.md +11 -0
- package/dist/ai/guides/options-items-playbook.md +30 -24
- package/dist/ai/guides/passthrough.md +2 -2
- package/dist/ai/guides/preset-components.md +18 -3
- package/dist/ai/guides/typescript-generic-components.md +1 -1
- package/dist/ai/guides/validated-forms.md +11 -22
- package/dist/ai/guides/validation-providers.md +4 -3
- package/dist/ai/helpers/inertia/manifest.json +636 -0
- package/dist/ai/helpers/inertia/types.ts +15 -0
- package/dist/ai/helpers/inertia/useAsyncFn.ts +110 -0
- package/dist/ai/helpers/inertia/useConfirmOnRouteLeave.ts +102 -0
- package/dist/ai/helpers/inertia/useDeleteCmd.ts +30 -0
- package/dist/ai/helpers/inertia/useHasChanged.ts +36 -0
- package/dist/ai/helpers/inertia/useIndexById.ts +23 -0
- package/dist/ai/helpers/inertia/useLazyProp.ts +148 -0
- package/dist/ai/helpers/inertia/useLazyPropGetter.ts +50 -0
- package/dist/ai/helpers/inertia/useLoading.ts +20 -0
- package/dist/ai/helpers/inertia/usePaginatedResponseContext.ts +88 -0
- package/dist/ai/helpers/inertia/usePromiseForm.ts +62 -0
- package/dist/ai/helpers/inertia/useProp.ts +63 -0
- package/dist/ai/helpers/inertia/useQuery.ts +19 -0
- package/dist/ai/helpers/inertia/useQueryObject.ts +116 -0
- package/dist/ai/helpers/inertia/useResourceContext.ts +69 -0
- package/dist/ai/helpers/inertia/useRouteQuery.ts +54 -0
- package/dist/ai/helpers/inertia/useScreenSizes.ts +23 -0
- package/dist/ai/helpers/inertia/useTableContext.ts +34 -0
- package/dist/ai/helpers/inertia/useTableSelectionContext.ts +48 -0
- package/dist/ai/helpers/inertia/useUntil.ts +33 -0
- package/dist/ai/helpers/inertia/utils.ts +24 -0
- package/dist/ai/index.md +6 -6
- package/dist/ai/manifest/components/BbBreadcrumbs.json +10 -6
- package/dist/ai/manifest/components/BbBreadcrumbs.tree.json +1 -1
- package/dist/ai/manifest/components/BbButton.json +1 -1
- package/dist/ai/manifest/components/BbCheckboxGroup.json +2 -2
- package/dist/ai/manifest/components/BbDropdown.json +23 -20
- package/dist/ai/manifest/components/BbDropdown.tree.json +2 -2
- package/dist/ai/manifest/components/BbDropdownButton.json +22 -19
- package/dist/ai/manifest/components/BbDropdownButton.tree.json +1 -1
- package/dist/ai/manifest/components/BbDropdownGroup.json +2 -2
- package/dist/ai/manifest/components/BbForm.json +1 -0
- package/dist/ai/manifest/components/BbNumberInput.json +6 -1
- package/dist/ai/manifest/components/BbNumberInput.tree.json +2 -1
- package/dist/ai/manifest/components/BbPopover.json +1 -0
- package/dist/ai/manifest/components/BbProgress.json +6 -6
- package/dist/ai/manifest/components/BbProgress.tree.json +1 -0
- package/dist/ai/manifest/components/BbRadioGroup.json +2 -2
- package/dist/ai/manifest/components/BbSelect.json +2 -2
- package/dist/ai/manifest/components/BbSelectPopover.json +2 -2
- package/dist/ai/manifest/components/BbSwitchGroup.json +2 -2
- package/dist/ai/manifest/components/BbTabs.json +7 -6
- package/dist/ai/manifest/components/BbTabsList.json +3 -3
- package/dist/ai/manifest/components/BbTabsPanels.json +1 -1
- package/dist/ai/manifest/components/BbTabsRoot.json +5 -4
- package/dist/ai/manifest/components/BbTooltip.json +1 -1
- package/dist/ai/manifest/index.json +2 -2
- package/dist/ai/manifest/meta.json +2 -0
- package/dist/ai/manifest/types.advanced.json +10 -9
- package/dist/ai/manifest/types.api.json +5 -4
- package/dist/ai/recipes/inertia/approvals-inbox.md +16 -18
- package/dist/ai/recipes/inertia/inline-edit-workspace.md +23 -33
- package/dist/ai/recipes/inertia/layout-scaffold.md +16 -16
- package/dist/ai/recipes/inertia/onboarding.md +6 -10
- package/dist/ai/recipes/inertia/ownership-atlas.md +15 -18
- package/dist/ai/recipes/inertia/record-form.md +11 -11
- package/dist/ai/recipes/inertia/records-workspace.md +38 -41
- package/dist/ai/recipes/inertia/settings-workspace.md +26 -38
- package/dist/ai/recipes/inertia/upload-center.md +31 -39
- package/dist/ai/recipes/inertia/wizard-form.md +10 -19
- package/dist/ai/recipes/nuxt/approvals-inbox.md +7 -8
- package/dist/ai/recipes/nuxt/inline-edit-workspace.md +14 -24
- package/dist/ai/recipes/nuxt/layout-scaffold.md +16 -16
- package/dist/ai/recipes/nuxt/onboarding.md +2 -6
- package/dist/ai/recipes/nuxt/ownership-atlas.md +7 -9
- package/dist/ai/recipes/nuxt/record-form.md +5 -5
- package/dist/ai/recipes/nuxt/records-workspace.md +29 -31
- package/dist/ai/recipes/nuxt/settings-workspace.md +22 -34
- package/dist/ai/recipes/nuxt/upload-center.md +22 -29
- package/dist/ai/recipes/nuxt/wizard-form.md +3 -11
- package/dist/ai/recipes/vue/approvals-inbox.md +7 -8
- package/dist/ai/recipes/vue/inline-edit-workspace.md +14 -24
- package/dist/ai/recipes/vue/layout-scaffold.md +16 -16
- package/dist/ai/recipes/vue/onboarding.md +2 -6
- package/dist/ai/recipes/vue/ownership-atlas.md +7 -9
- package/dist/ai/recipes/vue/record-form.md +5 -5
- package/dist/ai/recipes/vue/records-workspace.md +29 -31
- package/dist/ai/recipes/vue/settings-workspace.md +22 -34
- package/dist/ai/recipes/vue/upload-center.md +22 -29
- package/dist/ai/recipes/vue/wizard-form.md +3 -11
- package/dist/ai/source/BbAccordion.md +1 -1
- package/dist/ai/source/BbAlert.md +3 -3
- package/dist/ai/source/BbBadge.md +2 -2
- package/dist/ai/source/BbBadgeButton.md +5 -4
- package/dist/ai/source/BbBaseButton.md +1 -1
- package/dist/ai/source/BbBaseRadioIcon.md +1 -0
- package/dist/ai/source/BbBaseSwitchIcon.md +1 -0
- package/dist/ai/source/BbBreadcrumbs.md +63 -42
- package/dist/ai/source/BbButton.md +71 -33
- package/dist/ai/source/BbCalendar.md +17 -16
- package/dist/ai/source/BbCheckbox.md +3 -2
- package/dist/ai/source/BbCheckboxGroup.md +11 -4
- package/dist/ai/source/BbColorInput.md +10 -9
- package/dist/ai/source/BbConfirm.md +1 -1
- package/dist/ai/source/BbConfirmPortal.md +1 -1
- package/dist/ai/source/BbDatePicker.md +2 -2
- package/dist/ai/source/BbDatePickerInput.md +47 -20
- package/dist/ai/source/BbDialog.md +5 -5
- package/dist/ai/source/BbDropdown.md +230 -158
- package/dist/ai/source/BbDropdownButton.md +19 -12
- package/dist/ai/source/BbDropdownGroup.md +126 -93
- package/dist/ai/source/BbForm.md +25 -1
- package/dist/ai/source/BbIndicator.md +4 -0
- package/dist/ai/source/BbNumberInput.md +855 -19
- package/dist/ai/source/BbOffCanvas.md +27 -11
- package/dist/ai/source/BbPagination.md +3 -3
- package/dist/ai/source/BbPopover.md +152 -8
- package/dist/ai/source/BbPopoverPortal.md +11 -0
- package/dist/ai/source/BbProgress.md +82 -18
- package/dist/ai/source/BbRadioGroup.md +12 -5
- package/dist/ai/source/BbRating.md +11 -9
- package/dist/ai/source/BbSelect.md +16 -10
- package/dist/ai/source/BbSelectPopover.md +29 -23
- package/dist/ai/source/BbSlider.md +12 -6
- package/dist/ai/source/BbSwitch.md +3 -2
- package/dist/ai/source/BbSwitchGroup.md +5 -2
- package/dist/ai/source/BbTable.md +102 -18
- package/dist/ai/source/BbTabs.md +27 -23
- package/dist/ai/source/BbTabsList.md +26 -22
- package/dist/ai/source/BbTabsPanels.md +26 -22
- package/dist/ai/source/BbTabsRoot.md +25 -21
- package/dist/ai/source/BbTag.md +10 -9
- package/dist/ai/source/BbTextInput.md +5 -4
- package/dist/ai/source/BbTextarea.md +6 -5
- package/dist/ai/source/BbTimePicker.md +1 -1
- package/dist/ai/source/BbTimePickerInput.md +46 -9
- package/dist/ai/source/BbToast.md +10 -7
- package/dist/ai/source/BbToastPortal.md +10 -7
- package/dist/ai/source/BbTooltip.md +54 -8
- package/dist/ai/source/BbTree.md +21 -3
- package/dist/ai/source/CommonField.md +6 -4
- package/dist/ai/source/CommonFieldInput.md +15 -10
- package/dist/ai/source/CommonPopover.md +6 -0
- package/dist/ai/source/CommonTimeSelector.md +5 -4
- package/dist/components/BbBadge/BbBadgeButton.vue_vue_type_script_setup_true_lang.js +10 -8
- package/dist/components/BbBaseButton/BbBaseButton.vue_vue_type_script_setup_true_lang.js +8 -8
- package/dist/components/BbBreadcrumbs/BbBreadcrumbs.vue_vue_type_script_setup_true_lang.js +45 -45
- package/dist/components/BbBreadcrumbs/types.d.ts +25 -17
- package/dist/components/BbButton/BbButton.vue_vue_type_script_setup_true_lang.js +84 -71
- package/dist/components/BbButton/toggleRoving.d.ts +6 -0
- package/dist/components/BbButton/toggleRoving.js +45 -0
- package/dist/components/BbButton/types.d.ts +4 -1
- package/dist/components/BbCalendar/BbCalendar.vue_vue_type_script_setup_true_lang.js +178 -178
- package/dist/components/BbCalendar/CalendarMonthPanel.vue_vue_type_script_setup_true_lang.js +15 -15
- package/dist/components/BbCalendar/CalendarYearPanel.vue_vue_type_script_setup_true_lang.js +28 -28
- package/dist/components/BbCalendar/useCalendarGrid.js +141 -139
- package/dist/components/BbCalendar/useDayjsLocale.d.ts +38 -15
- package/dist/components/BbCalendar/useDayjsLocale.js +31 -30
- package/dist/components/BbCheckbox/BbCheckbox.vue_vue_type_script_setup_true_lang.js +48 -48
- package/dist/components/BbCheckboxGroup/BbCheckboxGroup.vue_vue_type_script_setup_true_lang.js +81 -80
- package/dist/components/BbCheckboxGroup/types.d.ts +6 -2
- package/dist/components/BbColorInput/BbColorInput.vue_vue_type_script_setup_true_lang.js +69 -69
- package/dist/components/BbDatePickerInput/BbDatePickerInput.vue_vue_type_script_setup_true_lang.js +363 -349
- package/dist/components/BbDropdown/AdaptiveDropdown.vue_vue_type_script_setup_true_lang.js +91 -86
- package/dist/components/BbDropdown/BbDropdown.vue_vue_type_script_setup_true_lang.js +298 -289
- package/dist/components/BbDropdown/BbDropdownList.vue_vue_type_script_setup_true_lang.js +322 -356
- package/dist/components/BbDropdown/DropdownPipelineResolver.vue_vue_type_script_setup_true_lang.js +17 -15
- package/dist/components/BbDropdown/DropdownRow.vue.d.ts +40 -0
- package/dist/components/BbDropdown/DropdownRow.vue.js +5 -0
- package/dist/components/BbDropdown/DropdownRow.vue_vue_type_script_setup_true_lang.js +60 -0
- package/dist/components/BbDropdown/normalizeGroups.d.ts +8 -2
- package/dist/components/BbDropdown/normalizeGroups.js +60 -46
- package/dist/components/BbDropdown/types.d.ts +119 -88
- package/dist/components/BbDropdownButton/BbDropdownButton.vue_vue_type_script_setup_true_lang.js +11 -2
- package/dist/components/BbDropdownButton/types.d.ts +2 -2
- package/dist/components/BbForm/BbForm.vue.d.ts +9 -0
- package/dist/components/BbForm/BbForm.vue_vue_type_script_setup_true_lang.js +114 -105
- package/dist/components/BbForm/BbFormCustomField.js +1 -1
- package/dist/components/BbForm/bindFormField.js +2 -1
- package/dist/components/BbForm/formFields.d.ts +5 -0
- package/dist/components/BbNumberInput/BbNumberInput.vue.d.ts +0 -1
- package/dist/components/BbNumberInput/BbNumberInput.vue_vue_type_script_setup_true_lang.js +452 -125
- package/dist/components/BbNumberInput/numberDisplay.d.ts +256 -0
- package/dist/components/BbNumberInput/numberDisplay.js +499 -0
- package/dist/components/BbNumberInput/types.d.ts +54 -1
- package/dist/components/BbNumberInput/warroom/corpus.d.ts +58 -0
- package/dist/components/BbNumberInput/warroom/currency-verify.rows.d.ts +28 -0
- package/dist/components/BbNumberInput/warroom/currency.rows.d.ts +2 -0
- package/dist/components/BbNumberInput/warroom/harness.d.ts +217 -0
- package/dist/components/BbNumberInput/warroom/oracle.d.ts +150 -0
- package/dist/components/BbPagination/BbPagination.vue_vue_type_script_setup_true_lang.js +7 -7
- package/dist/components/BbPopover/BbPopover.vue.d.ts +1 -0
- package/dist/components/BbPopover/BbPopover.vue_vue_type_script_setup_true_lang.js +207 -164
- package/dist/components/BbPopover/types.d.ts +11 -0
- package/dist/components/BbProgress/BbProgress.vue_vue_type_script_setup_true_lang.js +15 -7
- package/dist/components/BbProgress/types.d.ts +23 -7
- package/dist/components/BbProgress/types.js +1 -1
- package/dist/components/BbRadioGroup/BbRadioGroup.vue_vue_type_script_setup_true_lang.js +102 -101
- package/dist/components/BbRadioGroup/types.d.ts +6 -2
- package/dist/components/BbRating/BbRating.vue_vue_type_script_setup_true_lang.js +63 -63
- package/dist/components/BbSelect/BbSelect.vue_vue_type_script_setup_true_lang.js +156 -154
- package/dist/components/BbSelect/types.d.ts +6 -2
- package/dist/components/BbSelectPopover/BbSelectPopover.vue_vue_type_script_setup_true_lang.js +2 -1
- package/dist/components/BbSelectPopover/types.d.ts +6 -2
- package/dist/components/BbSlider/BbSlider.vue_vue_type_script_setup_true_lang.js +153 -153
- package/dist/components/BbSwitch/BbSwitch.vue_vue_type_script_setup_true_lang.js +62 -62
- package/dist/components/BbSwitchGroup/BbSwitchGroup.vue_vue_type_script_setup_true_lang.js +131 -130
- package/dist/components/BbTable/BbTable.vue_vue_type_script_setup_true_lang.js +711 -676
- package/dist/components/BbTabs/BbTabs.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/components/BbTabs/BbTabsList.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/components/BbTabs/types.d.ts +25 -21
- package/dist/components/BbTag/BbTag.vue_vue_type_script_setup_true_lang.js +76 -76
- package/dist/components/BbTextInput/BbTextInput.vue_vue_type_script_setup_true_lang.js +58 -58
- package/dist/components/BbTextarea/BbTextarea.vue_vue_type_script_setup_true_lang.js +82 -82
- package/dist/components/BbTimePickerInput/BbTimePickerInput.vue_vue_type_script_setup_true_lang.js +246 -236
- package/dist/components/BbTooltip/BbTooltip.vue_vue_type_script_setup_true_lang.js +102 -97
- package/dist/components/BbTooltip/tooltipWarmup.d.ts +23 -0
- package/dist/components/BbTooltip/tooltipWarmup.js +7 -0
- package/dist/components/BbTooltip/types.d.ts +7 -2
- package/dist/components/BbTree/BbTree.vue_vue_type_script_setup_true_lang.js +29 -21
- package/dist/components/BbTree/BbTreeLevel.vue_vue_type_script_setup_true_lang.js +10 -7
- package/dist/components/CommonFieldInput/CommonFieldInput.vue_vue_type_script_setup_true_lang.js +37 -36
- package/dist/components/CommonTimeSelector/CommonTimeSelector.vue_vue_type_script_setup_true_lang.js +9 -9
- package/dist/composables/formSubmitLock.d.ts +6 -0
- package/dist/composables/formSubmitLock.js +4 -0
- package/dist/composables/useBaseOptions.d.ts +7 -1
- package/dist/composables/useBaseOptions.js +32 -32
- package/dist/composables/useBbDropdownContext.d.ts +8 -8
- package/dist/composables/useBbFormField.d.ts +9 -0
- package/dist/composables/useBbFormField.js +5 -3
- package/dist/composables/useBbTabsContext.d.ts +10 -10
- package/dist/composables/useBbTabsContext.js +18 -18
- package/dist/composables/useFormBinding.d.ts +11 -0
- package/dist/composables/useFormBinding.js +15 -13
- package/dist/composables/useItemText.d.ts +5 -1
- package/dist/composables/useItemText.js +8 -3
- package/dist/composables/useItemValue.d.ts +5 -1
- package/dist/composables/useItemValue.js +8 -3
- package/dist/composables/useLocale.js +10 -9
- package/dist/deprecation/ai-deprecations.json.d.ts +130 -0
- package/dist/deprecation/ai-deprecations.json.js +1 -1
- package/dist/deprecation/removedProps.js +1 -1
- package/dist/directives/bbDropdown.js +1 -1
- package/dist/i18n/index.d.ts +7 -12
- package/dist/i18n/locales/cs.json +11 -14
- package/dist/i18n/locales/da.json +13 -16
- package/dist/i18n/locales/de-CH.json +137 -0
- package/dist/i18n/locales/de.json +14 -17
- package/dist/i18n/locales/el.json +10 -13
- package/dist/i18n/locales/en-GB.json +137 -0
- package/dist/i18n/locales/en.json +8 -11
- package/dist/i18n/locales/es-MX.json +137 -0
- package/dist/i18n/locales/es.json +16 -19
- package/dist/i18n/locales/fi.json +8 -11
- package/dist/i18n/locales/fr.json +23 -26
- package/dist/i18n/locales/hu.json +8 -11
- package/dist/i18n/locales/it.json +12 -15
- package/dist/i18n/locales/ja.json +13 -16
- package/dist/i18n/locales/ko.json +10 -13
- package/dist/i18n/locales/nb.json +13 -16
- package/dist/i18n/locales/nl.json +21 -24
- package/dist/i18n/locales/pl.json +10 -13
- package/dist/i18n/locales/{pt.json → pt-BR.json} +19 -22
- package/dist/i18n/locales/pt-PT.json +137 -0
- package/dist/i18n/locales/ro.json +22 -25
- package/dist/i18n/locales/ru.json +11 -14
- package/dist/i18n/locales/sv.json +16 -19
- package/dist/i18n/locales/tr.json +14 -17
- package/dist/i18n/locales/uk.json +11 -14
- package/dist/i18n/locales/{zh-cn.json → zh-CN.json} +10 -13
- package/dist/i18n/locales/zh-HK.json +137 -0
- package/dist/i18n/locales/zh-TW.json +137 -0
- package/dist/i18n/regionHints.d.ts +16 -0
- package/dist/i18n/regionHints.js +49 -0
- package/dist/i18n/regions.d.ts +286 -0
- package/dist/i18n/regions.js +265 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +4 -4
- package/dist/llms-full.txt +1785 -1637
- package/dist/llms-medium.txt +74 -46
- package/dist/llms.txt +7 -7
- package/dist/locale-blueprint.json +16 -13
- package/dist/styles.css +2 -2
- package/dist/types/ptComponentMap.d.ts +1 -1
- package/dist/utilities/functions/slotKey.d.ts +2 -2
- package/dist/utils/versionCheck.js +1 -1
- package/dist/vite-plugin.d.ts +22 -19
- package/dist/vite.js +309 -297
- package/llms.txt +7 -7
- package/package.json +5 -3
- package/scripts/lib/agent-manifest.mjs +2 -1
- package/scripts/lib/eslint-disable.mjs +12 -4
- package/scripts/lib/eslint-plugin.d.ts +5 -1
- package/scripts/lib/eslint-plugin.mjs +187 -6
- package/scripts/lib/helper-canon.mjs +176 -0
- package/scripts/lib/helpers-add.mjs +1303 -0
- package/scripts/lib/local-components.mjs +33 -4
- package/scripts/lib/locale-check.mjs +165 -0
- package/scripts/lib/redundant-item-accessor.mjs +398 -0
- package/scripts/lib/renamed-item-field.mjs +343 -0
- package/scripts/lib/slot-key.mjs +2 -2
- package/scripts/lib/slot-renames.mjs +1 -1
- package/scripts/lib/validate-bb-markup.mjs +123 -56
- package/dist/i18n/index.js +0 -27
|
@@ -83,7 +83,11 @@
|
|
|
83
83
|
:role="panelIsDialog ? 'none' : 'menu'"
|
|
84
84
|
v-bind="passthrough.list"
|
|
85
85
|
>
|
|
86
|
-
<BbDropdownList
|
|
86
|
+
<BbDropdownList
|
|
87
|
+
v-if="rowsMounted"
|
|
88
|
+
ref="root-list"
|
|
89
|
+
:groups="renderGroups"
|
|
90
|
+
/>
|
|
87
91
|
</span>
|
|
88
92
|
<!-- Announcement channel for the placeholder rows. Sits OUTSIDE the
|
|
89
93
|
menu container: `role="menu"` admits only items and groups, and a
|
|
@@ -261,6 +265,14 @@ const hasOpenedOnce = useUntil(open, { initialValue: props.eager });
|
|
|
261
265
|
* CommonPopover fades it out, so it stays reachable until the fade ends.
|
|
262
266
|
*/
|
|
263
267
|
const panelInert = useClosingInert(open, () => props.transitionDuration);
|
|
268
|
+
/**
|
|
269
|
+
* The rows live while the panel shows: mounted on open, dropped once the
|
|
270
|
+
* fade-out ends (the moment the panel goes `inert`), so a closed menu doesn't
|
|
271
|
+
* keep a node tree per row — 20 MB at 1,000 rows (PERF-MEASURE § BbDropdown).
|
|
272
|
+
* The panel and its `menu` container stay, so `aria-controls` still points at
|
|
273
|
+
* something. `eager` keeps them, as it always has.
|
|
274
|
+
*/
|
|
275
|
+
const rowsMounted = computed(() => props.eager || !panelInert.value);
|
|
264
276
|
|
|
265
277
|
/**
|
|
266
278
|
* Bound on CommonPopover's bubble, which is the root panel. `--max-h` caps it
|
|
@@ -432,7 +444,7 @@ const { resume, pause } = useIntersectionObserver(
|
|
|
432
444
|
|
|
433
445
|
// --- selection state (owned by the dropdown) ----------------------------
|
|
434
446
|
|
|
435
|
-
/** Current selection (
|
|
447
|
+
/** Current selection (row keys) per selectable group, keyed by group id. */
|
|
436
448
|
const internalSelection = reactive<Record<string, string[]>>({});
|
|
437
449
|
|
|
438
450
|
// --- group registry (for <BbDropdownGroup> companions) ------------------
|
|
@@ -469,7 +481,7 @@ const findGroupById = (
|
|
|
469
481
|
): InternalGroup | undefined => {
|
|
470
482
|
for (const entry of items) {
|
|
471
483
|
if (isGroup(entry)) {
|
|
472
|
-
if (entry.
|
|
484
|
+
if (entry.id === groupId) return entry;
|
|
473
485
|
for (const child of groupItemsAsArray(entry.items)) {
|
|
474
486
|
const list = Array.isArray(child) ? child : [child];
|
|
475
487
|
for (const childItem of list) {
|
|
@@ -513,11 +525,11 @@ const findEntryKindById = (
|
|
|
513
525
|
continue;
|
|
514
526
|
}
|
|
515
527
|
if (isGroup(entry)) {
|
|
516
|
-
if (entry.
|
|
528
|
+
if (entry.id === key) return 'group';
|
|
517
529
|
for (const child of groupItemsAsArray(entry.items)) {
|
|
518
530
|
const list = Array.isArray(child) ? child : [child];
|
|
519
531
|
for (const childItem of list) {
|
|
520
|
-
if (childItem.
|
|
532
|
+
if (childItem.value === key) return 'item';
|
|
521
533
|
if (childItem.items) {
|
|
522
534
|
const found = findEntryKindById(childItem.items, key);
|
|
523
535
|
if (found) return found;
|
|
@@ -526,7 +538,7 @@ const findEntryKindById = (
|
|
|
526
538
|
}
|
|
527
539
|
continue;
|
|
528
540
|
}
|
|
529
|
-
if (entry.
|
|
541
|
+
if (entry.value === key) return 'item';
|
|
530
542
|
if (entry.items) {
|
|
531
543
|
const found = findEntryKindById(entry.items, key);
|
|
532
544
|
if (found) return found;
|
|
@@ -545,7 +557,7 @@ const companionGroups = computed<DropdownGroupDescriptor[]>(() =>
|
|
|
545
557
|
/**
|
|
546
558
|
* Merges a companion descriptor onto the inline group it references. The
|
|
547
559
|
* companion only overrides the fields it actually declares: anything it leaves
|
|
548
|
-
* `undefined` (e.g. `items`/`
|
|
560
|
+
* `undefined` (e.g. `items`/`label` on a bare `<BbDropdownGroup id v-model />`)
|
|
549
561
|
* falls back to the inline definition, so a companion can simply attach a
|
|
550
562
|
* `v-model` to a group already declared in `items`.
|
|
551
563
|
*/
|
|
@@ -555,7 +567,7 @@ const mergeCompanionGroup = (
|
|
|
555
567
|
): InternalGroup => ({
|
|
556
568
|
...inline,
|
|
557
569
|
group: true,
|
|
558
|
-
|
|
570
|
+
id: inline.id,
|
|
559
571
|
// Propagate the raw values; the selectable/non-selectable decision is made
|
|
560
572
|
// once in `normalizeGroups` (a group is selectable only when `selectable` or
|
|
561
573
|
// `multiple` is explicitly set).
|
|
@@ -576,7 +588,7 @@ const toGroupFromCompanion = (
|
|
|
576
588
|
): InternalGroup => {
|
|
577
589
|
return {
|
|
578
590
|
group: true,
|
|
579
|
-
|
|
591
|
+
id: companion.key,
|
|
580
592
|
label: companion.label ?? baseline?.label,
|
|
581
593
|
hideLabel: companion.hideLabel ?? baseline?.hideLabel,
|
|
582
594
|
items: companion.items ?? baseline?.items ?? [],
|
|
@@ -607,7 +619,7 @@ const applyCompanionToItems = (
|
|
|
607
619
|
|
|
608
620
|
const nextItems = items.map((entry) => {
|
|
609
621
|
if (isGroup(entry)) {
|
|
610
|
-
if (entry.
|
|
622
|
+
if (entry.id === group.id) {
|
|
611
623
|
found = true;
|
|
612
624
|
return mergeCompanionGroup(entry, group);
|
|
613
625
|
}
|
|
@@ -638,7 +650,7 @@ const applyCompanionToItems = (
|
|
|
638
650
|
|
|
639
651
|
/**
|
|
640
652
|
* `props.items` with companion groups merged in: a companion merges onto the
|
|
641
|
-
* inline group sharing its `
|
|
653
|
+
* inline group sharing its `id` (inheriting any fields it doesn't declare),
|
|
642
654
|
* otherwise it is appended.
|
|
643
655
|
*/
|
|
644
656
|
const mergedItems = computed<Item[]>(() => {
|
|
@@ -653,12 +665,12 @@ const mergedItems = computed<Item[]>(() => {
|
|
|
653
665
|
logger.throw(
|
|
654
666
|
`[BbDropdownGroup] "${companion.key}" refers to a menu item, not a selectable group. ` +
|
|
655
667
|
'`<BbDropdownGroup>` can only attach to a group (an entry with `selectable`, `multiple`, or `group: true`). ' +
|
|
656
|
-
'Point `id` at a group
|
|
668
|
+
'Point `id` at a group `id`.'
|
|
657
669
|
);
|
|
658
670
|
}
|
|
659
671
|
logger.throw(
|
|
660
672
|
`[BbDropdownGroup] Missing minimum config for group "${companion.key}". ` +
|
|
661
|
-
'Provide `items`, `selectable`, `multiple`, or `group` keys in order to identify a group or define a baseline group with the same
|
|
673
|
+
'Provide `items`, `selectable`, `multiple`, or `group` keys in order to identify a group or define a baseline group with the same `id` in `BbDropdown.items`.'
|
|
662
674
|
);
|
|
663
675
|
}
|
|
664
676
|
|
|
@@ -669,15 +681,39 @@ const mergedItems = computed<Item[]>(() => {
|
|
|
669
681
|
return base;
|
|
670
682
|
});
|
|
671
683
|
|
|
684
|
+
/**
|
|
685
|
+
* What a group shows checked: its selection, or — on a single group with
|
|
686
|
+
* nothing selected, i.e. a `null` model — its "None" row, the row whose value
|
|
687
|
+
* is `null` (Q64.3, owner 2026-10-07): BbSelect and BbRadioGroup show a `null`
|
|
688
|
+
* model the same way, matching by hash. Display only: the selection stays
|
|
689
|
+
* empty, so the model stays `null` and no event fires.
|
|
690
|
+
*/
|
|
691
|
+
const displayedSelection = (group: NormalizedGroup): string[] => {
|
|
692
|
+
const keys = internalSelection[group.id ?? ''] ?? [];
|
|
693
|
+
if (group.multiple || keys.length || !group.id) return keys;
|
|
694
|
+
const pipeline = pipelineGroupKeys.value.includes(group.id);
|
|
695
|
+
const none = group.items.find(
|
|
696
|
+
(item) =>
|
|
697
|
+
!item.keyless &&
|
|
698
|
+
!item.placeholder &&
|
|
699
|
+
(pipeline
|
|
700
|
+
? pipelineMaps[group.id!]?.valueByKey.get(item.rowKey) === null
|
|
701
|
+
: item.value === null)
|
|
702
|
+
);
|
|
703
|
+
return none ? [none.rowKey] : keys;
|
|
704
|
+
};
|
|
705
|
+
|
|
706
|
+
const normalizedGroups = computed(() => normalizeGroups(mergedItems.value));
|
|
707
|
+
|
|
672
708
|
/**
|
|
673
709
|
* Groups handed to the panel, with the live selection injected from
|
|
674
|
-
* {@link internalSelection} for selectable groups.
|
|
710
|
+
* {@link internalSelection} for selectable groups. Normalized in a step of its
|
|
711
|
+
* own so a pick re-runs only this map: the rows keep their objects, and a row
|
|
712
|
+
* whose state didn't change isn't re-rendered (PERF-MEASURE § BbDropdown).
|
|
675
713
|
*/
|
|
676
714
|
const renderGroups = computed(() =>
|
|
677
|
-
|
|
678
|
-
group.selectable
|
|
679
|
-
? { ...group, selected: internalSelection[group.key ?? ''] ?? [] }
|
|
680
|
-
: group
|
|
715
|
+
normalizedGroups.value.map((group) =>
|
|
716
|
+
group.selectable ? { ...group, selected: displayedSelection(group) } : group
|
|
681
717
|
)
|
|
682
718
|
);
|
|
683
719
|
|
|
@@ -733,11 +769,11 @@ const isPipelineGroup = (group: InternalGroup) =>
|
|
|
733
769
|
group.itemValue != null ||
|
|
734
770
|
group.max != null;
|
|
735
771
|
|
|
736
|
-
/**
|
|
772
|
+
/** Ids of every pipeline group declared in `items`, at any nesting depth. */
|
|
737
773
|
const collectPipelineKeys = (items: Item[], acc: string[] = []): string[] => {
|
|
738
774
|
for (const entry of items) {
|
|
739
775
|
if (isGroup(entry)) {
|
|
740
|
-
if (entry.
|
|
776
|
+
if (entry.id && isPipelineGroup(entry)) acc.push(entry.id);
|
|
741
777
|
for (const child of groupItemsAsArray(entry.items)) {
|
|
742
778
|
for (const item of Array.isArray(child) ? child : [child]) {
|
|
743
779
|
if (item.items) collectPipelineKeys(item.items, acc);
|
|
@@ -765,10 +801,10 @@ const pipelineGroupKeys = computed(() =>
|
|
|
765
801
|
const topLevelPipelineKeys = computed(() =>
|
|
766
802
|
(props.items ?? [])
|
|
767
803
|
.filter(
|
|
768
|
-
(entry): entry is InternalGroup & {
|
|
769
|
-
isGroup(entry) && !!entry.
|
|
804
|
+
(entry): entry is InternalGroup & { id: string } =>
|
|
805
|
+
isGroup(entry) && !!entry.id && isPipelineGroup(entry)
|
|
770
806
|
)
|
|
771
|
-
.map((entry) => entry.
|
|
807
|
+
.map((entry) => entry.id as string)
|
|
772
808
|
);
|
|
773
809
|
|
|
774
810
|
/** Per-pipeline-group key⇄value/item/text maps, published by the resolvers. */
|
|
@@ -791,15 +827,18 @@ const groupLoading = reactive<Record<string, boolean>>({});
|
|
|
791
827
|
const groupFetching = reactive<Record<string, boolean>>({});
|
|
792
828
|
|
|
793
829
|
/**
|
|
794
|
-
* Resolve a selection key to the
|
|
795
|
-
* pipeline groups, else the
|
|
796
|
-
* Shared by the registry and the panel's own
|
|
797
|
-
*
|
|
830
|
+
* Resolve a selection key to the row's value — the mapped `item-value` for
|
|
831
|
+
* pipeline groups, else the hand-written row's `value` (`undefined` when no
|
|
832
|
+
* row has that key). Shared by the registry and the panel's own
|
|
833
|
+
* `toggleSelect` so both emit the same value in
|
|
834
|
+
* `item:selected`/`item:unselected` (symmetric with `BbTable`).
|
|
798
835
|
*/
|
|
799
836
|
const valueForItemKey = (groupKey: string, itemKey: string) =>
|
|
800
837
|
pipelineGroupKeys.value.includes(groupKey)
|
|
801
838
|
? pipelineMaps[groupKey]?.valueByKey.get(itemKey)
|
|
802
|
-
:
|
|
839
|
+
: findRenderGroupDeep(groupKey)?.items.find(
|
|
840
|
+
(item) => item.rowKey === itemKey && !item.keyless
|
|
841
|
+
)?.value;
|
|
803
842
|
|
|
804
843
|
/**
|
|
805
844
|
* A group's `multiple`/`selectable` flags, derived from its raw config at ANY
|
|
@@ -818,11 +857,11 @@ const groupFlagsFor = (key: string) => {
|
|
|
818
857
|
};
|
|
819
858
|
};
|
|
820
859
|
|
|
821
|
-
/** A normalized group (with resolved items) by
|
|
860
|
+
/** A normalized group (with resolved items) by id at any nesting depth. */
|
|
822
861
|
const findRenderGroupDeep = (key: string): NormalizedGroup | undefined => {
|
|
823
862
|
const walk = (items: Item[]): NormalizedGroup | undefined => {
|
|
824
863
|
for (const group of normalizeGroups(items)) {
|
|
825
|
-
if (group.
|
|
864
|
+
if (group.id === key) return group;
|
|
826
865
|
for (const item of group.items) {
|
|
827
866
|
if (item.items) {
|
|
828
867
|
const found = walk(item.items);
|
|
@@ -835,9 +874,8 @@ const findRenderGroupDeep = (key: string): NormalizedGroup | undefined => {
|
|
|
835
874
|
return walk(mergedItems.value);
|
|
836
875
|
};
|
|
837
876
|
|
|
838
|
-
/** Selection key for a value
|
|
839
|
-
const keyForValue = (
|
|
840
|
-
pipelineGroupKeys.value.includes(key) ? hash(value) : value;
|
|
877
|
+
/** Selection key for a value: its `hash`, the key every row is stored under. */
|
|
878
|
+
const keyForValue = (_key: string, value: any) => hash(value);
|
|
841
879
|
|
|
842
880
|
/**
|
|
843
881
|
* A group's current selection in `v-model` shape: a companion's raw v-model when
|
|
@@ -907,14 +945,14 @@ provideDropdownGroupRegistry({
|
|
|
907
945
|
else companionModels.set(key, value);
|
|
908
946
|
},
|
|
909
947
|
modelValueFor,
|
|
910
|
-
// Pipeline groups resolve to the mapped value
|
|
911
|
-
// aren't loaded yet — the companion
|
|
912
|
-
// externally-set v-model).
|
|
948
|
+
// Pipeline groups resolve to the mapped value, hand-written ones to the
|
|
949
|
+
// row's `value` (`undefined` when items aren't loaded yet — the companion
|
|
950
|
+
// uses that to avoid clobbering an externally-set v-model).
|
|
913
951
|
valueForKey: valueForItemKey,
|
|
914
952
|
keyForValue,
|
|
915
953
|
itemForKey: (key, itemKey) =>
|
|
916
954
|
pipelineMaps[key]?.itemByKey.get(itemKey) ??
|
|
917
|
-
findRenderGroupDeep(key)?.items.find((item) => item.
|
|
955
|
+
findRenderGroupDeep(key)?.items.find((item) => item.rowKey === itemKey),
|
|
918
956
|
// Raw, pre-merge group definition: the companion reads its pipeline config
|
|
919
957
|
// (items getter, itemText/itemValue, max, …) from here. Must come from
|
|
920
958
|
// `props.items`, not `mergedItems` — the latter already has this group's
|
|
@@ -927,11 +965,11 @@ provideDropdownGroupRegistry({
|
|
|
927
965
|
|
|
928
966
|
// --- public read-only context (`useBbDropdownContext`) -------------------
|
|
929
967
|
|
|
930
|
-
/**
|
|
968
|
+
/** Ids of every selectable group declared in `items`, at any nesting depth. */
|
|
931
969
|
const collectSelectableKeys = (items: Item[], acc: string[] = []): string[] => {
|
|
932
970
|
for (const entry of items) {
|
|
933
971
|
if (isGroup(entry)) {
|
|
934
|
-
if (entry.
|
|
972
|
+
if (entry.id && isSelectableGroup(entry)) acc.push(entry.id);
|
|
935
973
|
for (const child of groupItemsAsArray(entry.items)) {
|
|
936
974
|
for (const item of Array.isArray(child) ? child : [child]) {
|
|
937
975
|
if (item.items) collectSelectableKeys(item.items, acc);
|
|
@@ -950,7 +988,7 @@ const collectSelectableKeys = (items: Item[], acc: string[] = []): string[] => {
|
|
|
950
988
|
* Per-group state mirrored to `useBbDropdownContext`. Built from data the
|
|
951
989
|
* dropdown already holds — selection + the resolvers' published value/text/item
|
|
952
990
|
* maps — so reading it costs no fetch. A selected value the owning group has not
|
|
953
|
-
* yet loaded resolves to `{ value }` alone (
|
|
991
|
+
* yet loaded resolves to `{ value }` alone (label/original fill in lazily).
|
|
954
992
|
*/
|
|
955
993
|
const contextGroups = computed<Record<string, BbDropdownContextGroup>>(() => {
|
|
956
994
|
const result: Record<string, BbDropdownContextGroup> = {};
|
|
@@ -974,24 +1012,19 @@ const contextGroups = computed<Record<string, BbDropdownContextGroup>>(() => {
|
|
|
974
1012
|
result[key] = {
|
|
975
1013
|
// Config first, live state second: the fields below always win.
|
|
976
1014
|
...(config as Omit<InternalGroup, 'items'>),
|
|
977
|
-
key,
|
|
1015
|
+
id: key,
|
|
978
1016
|
value: model,
|
|
979
1017
|
multiple: declared?.multiple ?? false,
|
|
980
1018
|
selectable: declared ? isSelectableGroup(declared) : false,
|
|
981
1019
|
loading: !!groupFetching[key],
|
|
982
1020
|
selectedOptions: values.map((value) => {
|
|
983
1021
|
const itemKey = keyForValue(key, value);
|
|
1022
|
+
const row = group?.items.find((item) => item.rowKey === itemKey);
|
|
984
1023
|
return {
|
|
985
1024
|
value,
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
description:
|
|
990
|
-
maps?.descriptionByKey.get(itemKey) ??
|
|
991
|
-
group?.items.find((item) => item.key === itemKey)?.description,
|
|
992
|
-
original:
|
|
993
|
-
maps?.itemByKey.get(itemKey) ??
|
|
994
|
-
group?.items.find((item) => item.key === itemKey),
|
|
1025
|
+
label: maps?.textByKey.get(itemKey) ?? row?.label,
|
|
1026
|
+
description: maps?.descriptionByKey.get(itemKey) ?? row?.description,
|
|
1027
|
+
original: maps?.itemByKey.get(itemKey) ?? row,
|
|
995
1028
|
};
|
|
996
1029
|
}),
|
|
997
1030
|
};
|
|
@@ -1012,7 +1045,7 @@ const selectableGroupCount = computed(
|
|
|
1012
1045
|
|
|
1013
1046
|
/**
|
|
1014
1047
|
* Toggles `item` in `group` (passed by the panel, so nested-submenu groups work
|
|
1015
|
-
* too). Single-select groups are radios: they keep one
|
|
1048
|
+
* too). Single-select groups are radios: they keep one row, and re-clicking the
|
|
1016
1049
|
* selected item keeps it — unless the group is `clearable`, when the re-click
|
|
1017
1050
|
* clears it (Q47.2, owner 2026-09-22). Multi-select groups toggle. Emits
|
|
1018
1051
|
* `item:selected`/`item:unselected` per changed item (none for a no-op
|
|
@@ -1025,18 +1058,20 @@ const selectableGroupCount = computed(
|
|
|
1025
1058
|
* below still describe the click, refused or not (D2a, D4).
|
|
1026
1059
|
*/
|
|
1027
1060
|
const toggleSelect = (group: NormalizedGroup, item: KeyedItem) => {
|
|
1028
|
-
const groupId = group.
|
|
1061
|
+
const groupId = group.id;
|
|
1029
1062
|
if (!groupId) return;
|
|
1030
1063
|
|
|
1031
|
-
|
|
1064
|
+
// What the group shows (the "None" row of a `null` model included), so a
|
|
1065
|
+
// click on the row already shown checked is a re-click, not a new pick.
|
|
1066
|
+
const prev = displayedSelection(group);
|
|
1032
1067
|
const set = new Set(prev);
|
|
1033
1068
|
if (group.multiple) {
|
|
1034
|
-
set.has(item.
|
|
1035
|
-
} else if (set.has(item.
|
|
1069
|
+
set.has(item.rowKey) ? set.delete(item.rowKey) : set.add(item.rowKey);
|
|
1070
|
+
} else if (set.has(item.rowKey)) {
|
|
1036
1071
|
if (group.clearable) set.clear();
|
|
1037
1072
|
} else {
|
|
1038
1073
|
set.clear();
|
|
1039
|
-
set.add(item.
|
|
1074
|
+
set.add(item.rowKey);
|
|
1040
1075
|
}
|
|
1041
1076
|
const next = [...set];
|
|
1042
1077
|
const added = next.filter((key) => !prev.includes(key));
|
|
@@ -1044,8 +1079,8 @@ const toggleSelect = (group: NormalizedGroup, item: KeyedItem) => {
|
|
|
1044
1079
|
|
|
1045
1080
|
const controlled = isControlled(groupId);
|
|
1046
1081
|
if (controlled) {
|
|
1047
|
-
const value = valueForItemKey(groupId, item.
|
|
1048
|
-
if (added.length) pickListeners.get(groupId)?.(item.
|
|
1082
|
+
const value = valueForItemKey(groupId, item.rowKey);
|
|
1083
|
+
if (added.length) pickListeners.get(groupId)?.(item.rowKey);
|
|
1049
1084
|
if (group.multiple) {
|
|
1050
1085
|
if (added.length) requestChange(groupId, { add: value });
|
|
1051
1086
|
else if (removed.length) requestChange(groupId, { remove: value });
|
|
@@ -1056,7 +1091,7 @@ const toggleSelect = (group: NormalizedGroup, item: KeyedItem) => {
|
|
|
1056
1091
|
}
|
|
1057
1092
|
|
|
1058
1093
|
const itemByKey = (key: string) =>
|
|
1059
|
-
group.items.find((candidate) => candidate.
|
|
1094
|
+
group.items.find((candidate) => candidate.rowKey === key);
|
|
1060
1095
|
// Emit the item's resolved value, symmetric with `BbTable` and the companion.
|
|
1061
1096
|
added.forEach((key) => {
|
|
1062
1097
|
if (itemByKey(key)) emit('item:selected', valueForItemKey(groupId, key));
|
|
@@ -1072,10 +1107,11 @@ const toggleSelect = (group: NormalizedGroup, item: KeyedItem) => {
|
|
|
1072
1107
|
// Radio-like sole top-level selectable group: close once a selection is made.
|
|
1073
1108
|
const isTopLevelSole =
|
|
1074
1109
|
selectableGroupCount.value === 1 &&
|
|
1075
|
-
renderGroups.value.some((g) => g.selectable && g.
|
|
1110
|
+
renderGroups.value.some((g) => g.selectable && g.id === groupId);
|
|
1076
1111
|
// A re-click that kept the pick is a pick of the same value: close too.
|
|
1077
1112
|
const picked =
|
|
1078
|
-
added.length > 0 ||
|
|
1113
|
+
added.length > 0 ||
|
|
1114
|
+
(prev.includes(item.rowKey) && next.includes(item.rowKey));
|
|
1079
1115
|
if (picked && !group.multiple && isTopLevelSole) {
|
|
1080
1116
|
closeDropdown();
|
|
1081
1117
|
focusActivator();
|
|
@@ -1123,11 +1159,11 @@ const runItemAction = async (
|
|
|
1123
1159
|
|
|
1124
1160
|
if (!isThenable(result)) return;
|
|
1125
1161
|
|
|
1126
|
-
loadingKeys.add(item.
|
|
1162
|
+
loadingKeys.add(item.rowKey);
|
|
1127
1163
|
try {
|
|
1128
1164
|
await result;
|
|
1129
1165
|
} finally {
|
|
1130
|
-
loadingKeys.delete(item.
|
|
1166
|
+
loadingKeys.delete(item.rowKey);
|
|
1131
1167
|
}
|
|
1132
1168
|
};
|
|
1133
1169
|
|
|
@@ -1168,7 +1204,10 @@ provideDropdownContext({
|
|
|
1168
1204
|
isGroupLoading: (key) => !!groupLoading[key],
|
|
1169
1205
|
isTopLevelPipeline: (key) => topLevelPipelineKeys.value.includes(key),
|
|
1170
1206
|
queryDebounceTime: computed(() => props.queryDebounceTime ?? 300),
|
|
1171
|
-
selectedFor: (key) =>
|
|
1207
|
+
selectedFor: (key) => {
|
|
1208
|
+
const group = findRenderGroupDeep(key);
|
|
1209
|
+
return group ? displayedSelection(group) : (internalSelection[key] ?? []);
|
|
1210
|
+
},
|
|
1172
1211
|
loadingText: computed(() => props.loadingText),
|
|
1173
1212
|
emptyText: computed(() => props.emptyText),
|
|
1174
1213
|
failedText: computed(() => props.failedText),
|
|
@@ -1182,7 +1221,7 @@ provideDropdownContext({
|
|
|
1182
1221
|
key: itemKey,
|
|
1183
1222
|
text:
|
|
1184
1223
|
maps?.textByKey.get(itemKey) ??
|
|
1185
|
-
group?.items.find((item) => item.
|
|
1224
|
+
group?.items.find((item) => item.rowKey === itemKey)?.label ??
|
|
1186
1225
|
readableValue(
|
|
1187
1226
|
valueForItemKey(key, itemKey) ?? appValueFor(key, itemKey)
|
|
1188
1227
|
),
|
|
@@ -1617,9 +1656,9 @@ export type { DropdownItemVariantType };
|
|
|
1617
1656
|
export type DropdownTrigger = 'click' | 'contextMenu';
|
|
1618
1657
|
|
|
1619
1658
|
/**
|
|
1620
|
-
* Props shared between {@link InternalItem} and {@link InternalGroup}
|
|
1621
|
-
*
|
|
1622
|
-
*
|
|
1659
|
+
* Props shared between {@link InternalItem} and {@link InternalGroup}: optional
|
|
1660
|
+
* icons, a variant, a click handler and `meta`. A row is identified by its
|
|
1661
|
+
* `value`, a group by its `id`.
|
|
1623
1662
|
*/
|
|
1624
1663
|
type DropdownEntryBase = {
|
|
1625
1664
|
/**
|
|
@@ -1628,25 +1667,11 @@ type DropdownEntryBase = {
|
|
|
1628
1667
|
* group (the check is), or when an append slot fills the region.
|
|
1629
1668
|
*/
|
|
1630
1669
|
'append:icon'?: IconType;
|
|
1631
|
-
/**
|
|
1632
|
-
* Key used to identify the entry. REQUIRED when anything outside the menu
|
|
1633
|
-
* reads it: a row in a `selectable` group (the v-model holds it), a row or
|
|
1634
|
-
* group with its own slot (`#<key>` is named by it), a group bound by a
|
|
1635
|
-
* `<BbDropdownGroup id>` or selectable. Optional on a plain action row (it
|
|
1636
|
-
* runs its `onClick`) and a layout-only group: the dropdown then derives an
|
|
1637
|
-
* internal identity from the text that nothing outside ever sees. A keyless
|
|
1638
|
-
* row in a selectable group renders but can't be selected. Load-bearing
|
|
1639
|
-
* identifiers are written, never derived — `bitboss-ui check` flags a
|
|
1640
|
-
* missing required key where the items are in the same file.
|
|
1641
|
-
*/
|
|
1642
|
-
key?: string;
|
|
1643
|
-
/** @internal Set by the dropdown on a row it derived a key for (Q53.17). */
|
|
1644
|
-
keyless?: true;
|
|
1645
1670
|
/**
|
|
1646
1671
|
* Your own data for this entry, carried untouched to its slots (as
|
|
1647
1672
|
* `item.meta`) and to per-item `pt` functions. The dropdown never reads it
|
|
1648
1673
|
* and never puts it on the DOM. Typically the record the entry stands for,
|
|
1649
|
-
* e.g. `{
|
|
1674
|
+
* e.g. `{ value: clinic.id, label: clinic.name, meta: clinic }`; a fetched
|
|
1650
1675
|
* group sets it through `itemProps` (`(clinic) => ({ meta: clinic })`).
|
|
1651
1676
|
*/
|
|
1652
1677
|
meta?: any;
|
|
@@ -1665,14 +1690,14 @@ type DropdownEntryBase = {
|
|
|
1665
1690
|
|
|
1666
1691
|
/**
|
|
1667
1692
|
* The `itemProps` fields of a fetched (pipeline) dropdown group: everything a
|
|
1668
|
-
* hand-written row accepts except its identity and structure (`
|
|
1669
|
-
* `items`, `group`) and `disabled`. See {@link InternalGroup.itemProps}.
|
|
1693
|
+
* hand-written row accepts except its identity and structure (`value`,
|
|
1694
|
+
* `label`, `items`, `group`) and `disabled`. See {@link InternalGroup.itemProps}.
|
|
1670
1695
|
*/
|
|
1671
1696
|
export type DropdownItemFields = Omit<
|
|
1672
1697
|
BbBaseButtonProps,
|
|
1673
1698
|
'block' | 'tag' | 'type' | 'text' | 'disabled'
|
|
1674
1699
|
> &
|
|
1675
|
-
|
|
1700
|
+
DropdownEntryBase & {
|
|
1676
1701
|
/** Muted second line under the row text. */
|
|
1677
1702
|
description: string;
|
|
1678
1703
|
};
|
|
@@ -1715,13 +1740,46 @@ type SubmenuExclusive =
|
|
|
1715
1740
|
}
|
|
1716
1741
|
| { items?: undefined };
|
|
1717
1742
|
|
|
1718
|
-
export type InternalItem = Omit<
|
|
1743
|
+
export type InternalItem = Omit<
|
|
1744
|
+
BbBaseButtonProps,
|
|
1745
|
+
'block' | 'tag' | 'type' | 'text'
|
|
1746
|
+
> &
|
|
1719
1747
|
SubmenuExclusive &
|
|
1720
1748
|
DropdownEntryBase & {
|
|
1721
|
-
/**
|
|
1722
|
-
|
|
1749
|
+
/** The row's text. */
|
|
1750
|
+
label: string;
|
|
1723
1751
|
/**
|
|
1724
|
-
*
|
|
1752
|
+
* The row's identity, any type: what `v-model` holds when its group is
|
|
1753
|
+
* `selectable` (compared by `hash()`, like `BbSelect` options, so `null`
|
|
1754
|
+
* and objects are values too: a `value: null` row is the group's "None"),
|
|
1755
|
+
* the name of its own slots (`#<value>`, a string or number value
|
|
1756
|
+
* through `slotKey`; any other type gets the shared slots only) and the
|
|
1757
|
+
* seed of its submenu's id.
|
|
1758
|
+
*
|
|
1759
|
+
* REQUIRED when anything outside the menu reads it: a row in a
|
|
1760
|
+
* `selectable` group, a row with its own slot. Optional on a plain
|
|
1761
|
+
* action row (it runs its `onClick`): the dropdown then derives an
|
|
1762
|
+
* internal identity from the label that nothing outside ever sees. A row
|
|
1763
|
+
* without a `value` in a selectable group renders disabled. Load-bearing
|
|
1764
|
+
* identifiers are written, never derived — `bitboss-ui check` flags a
|
|
1765
|
+
* missing required `value` where the items are in the same file.
|
|
1766
|
+
*/
|
|
1767
|
+
value?: unknown;
|
|
1768
|
+
/** Rows have no `key` (that is `value`). Guards against the old shape. */
|
|
1769
|
+
key?: never;
|
|
1770
|
+
/** Rows have no `text` (that is `label`). Guards against the old shape. */
|
|
1771
|
+
text?: never;
|
|
1772
|
+
/** @internal Set by the dropdown on a row it derived an identity for (Q53.17). */
|
|
1773
|
+
keyless?: true;
|
|
1774
|
+
/**
|
|
1775
|
+
* @internal The row's selection key, set by the dropdown: `hash(value)`,
|
|
1776
|
+
* or the identity it derived for a row without a `value`.
|
|
1777
|
+
*/
|
|
1778
|
+
rowKey?: string;
|
|
1779
|
+
/** @internal The row's readable DOM token, set by the dropdown (submenu ids). */
|
|
1780
|
+
domKey?: string;
|
|
1781
|
+
/**
|
|
1782
|
+
* Muted descriptive line rendered below `label`. The row grows to fit it,
|
|
1725
1783
|
* while icons/check/chevron stay aligned with the title line.
|
|
1726
1784
|
*/
|
|
1727
1785
|
description?: string;
|
|
@@ -1748,7 +1806,7 @@ export type InternalItem = Omit<BbBaseButtonProps, 'block' | 'tag' | 'type'> &
|
|
|
1748
1806
|
* async items load (`'loading'`), when it resolved empty (`'empty'`), or
|
|
1749
1807
|
* when its latest load FAILED (`'failed'`: the footer under whatever rows a
|
|
1750
1808
|
* `stash` keeps listed, Q61.15). Rendered as a non-interactive row that
|
|
1751
|
-
* shows `
|
|
1809
|
+
* shows `label` or, when provided, the dropdown's `loading` / `empty` slot.
|
|
1752
1810
|
* Internal — set by `BbDropdownGroup`.
|
|
1753
1811
|
*/
|
|
1754
1812
|
placeholder?: 'loading' | 'empty' | 'failed';
|
|
@@ -1768,8 +1826,8 @@ export type InternalItem = Omit<BbBaseButtonProps, 'block' | 'tag' | 'type'> &
|
|
|
1768
1826
|
/**
|
|
1769
1827
|
* Optional slot token used to resolve per-item named slots. Primarily set
|
|
1770
1828
|
* by the pipeline resolver so slot names can be derived from the resolved
|
|
1771
|
-
* `itemValue` (readable), while `
|
|
1772
|
-
* Internal.
|
|
1829
|
+
* `itemValue` (readable), while `rowKey` remains the hash-based selection
|
|
1830
|
+
* id. Internal.
|
|
1773
1831
|
*/
|
|
1774
1832
|
slotKey?: string;
|
|
1775
1833
|
};
|
|
@@ -1810,6 +1868,18 @@ export type DropdownGroupItemsGetter =
|
|
|
1810
1868
|
) => any[] | Promise<any[]>);
|
|
1811
1869
|
|
|
1812
1870
|
export type InternalGroup = DropdownEntryBase & {
|
|
1871
|
+
/**
|
|
1872
|
+
* The group's identity: REQUIRED on a `selectable` group (its picks are
|
|
1873
|
+
* stored under it, and `useBbDropdownContext` keys the group by it), on a
|
|
1874
|
+
* group bound by a `<BbDropdownGroup id>` (the same word) and on a group
|
|
1875
|
+
* with its own slots (`#<id>:item`, `#<id>`). Optional on a layout-only
|
|
1876
|
+
* group; a selectable group without one renders as a plain group.
|
|
1877
|
+
*/
|
|
1878
|
+
id?: string;
|
|
1879
|
+
/** Groups have no `key` (that is `id`). Guards against the old shape. */
|
|
1880
|
+
key?: never;
|
|
1881
|
+
/** Groups have no `value`; their rows do. */
|
|
1882
|
+
value?: never;
|
|
1813
1883
|
/** Pipeline groups only. Re-run the async getter when any of these change. */
|
|
1814
1884
|
dependencies?: unknown[];
|
|
1815
1885
|
/** Pipeline groups only. Debounce (ms) for `dependencies`-driven re-fetch. */
|
|
@@ -1848,17 +1918,19 @@ export type InternalGroup = DropdownEntryBase & {
|
|
|
1848
1918
|
| any[]
|
|
1849
1919
|
| DropdownGroupItemsGetter;
|
|
1850
1920
|
/**
|
|
1851
|
-
* Pipeline groups only. Path/getter producing each item's display text
|
|
1852
|
-
*
|
|
1921
|
+
* Pipeline groups only. Path/getter producing each item's display text
|
|
1922
|
+
* (a string item is its own text).
|
|
1853
1923
|
*
|
|
1854
|
-
*
|
|
1924
|
+
* Unset: own `label`, else `text` (`{ label, value }` needs no accessor).
|
|
1925
|
+
*
|
|
1926
|
+
* @defaultValue own `label`, else `text`, else `JSON.stringify(item)`
|
|
1855
1927
|
*/
|
|
1856
1928
|
itemText?: string | ((item: any) => string);
|
|
1857
1929
|
/**
|
|
1858
1930
|
* Pipeline groups only. The ADDITIONAL fields of each fetched row — never its
|
|
1859
1931
|
* text or value, which stay on `itemText` / `itemValue`. A fetched row takes
|
|
1860
1932
|
* every field a hand-written row accepts except its identity and structure
|
|
1861
|
-
* (`
|
|
1933
|
+
* (`value`, `label`, `items`, `group`) and `disabled`: `description`, the icons,
|
|
1862
1934
|
* `variant`, `onClick`, `href` / `to` and the rest of the link and Inertia
|
|
1863
1935
|
* options.
|
|
1864
1936
|
*
|
|
@@ -1869,17 +1941,18 @@ export type InternalGroup = DropdownEntryBase & {
|
|
|
1869
1941
|
* the handler: `onClick: (user) => () => open(user)`.
|
|
1870
1942
|
*
|
|
1871
1943
|
* Nothing is read off the raw item implicitly — without `itemProps` a row
|
|
1872
|
-
* has only its
|
|
1944
|
+
* has only its label. An empty value means the field is absent. To disable
|
|
1873
1945
|
* individual rows use a `selectable` predicate on the group; fetched groups
|
|
1874
1946
|
* are for selection (see plans/ITEM-DESCRIPTION.md v2.4).
|
|
1875
1947
|
*/
|
|
1876
1948
|
itemProps?: BbDropdownItemProps;
|
|
1877
1949
|
/**
|
|
1878
1950
|
* Pipeline groups only. Path/getter producing each item's value — what
|
|
1879
|
-
* `v-model` surfaces; its hash is the internal selection key.
|
|
1880
|
-
*
|
|
1951
|
+
* `v-model` surfaces; its hash is the internal selection key.
|
|
1952
|
+
*
|
|
1953
|
+
* Unset: own `value`, even `null`.
|
|
1881
1954
|
*
|
|
1882
|
-
* @defaultValue the whole item
|
|
1955
|
+
* @defaultValue own `value`, else the whole item
|
|
1883
1956
|
*/
|
|
1884
1957
|
itemValue?: string | ((item: any) => any);
|
|
1885
1958
|
/** Pipeline groups only. Placeholder row text while async items load. */
|
|
@@ -1970,7 +2043,7 @@ export type InternalGroup = DropdownEntryBase & {
|
|
|
1970
2043
|
*/
|
|
1971
2044
|
selectable?: boolean | ((item: any) => boolean);
|
|
1972
2045
|
/**
|
|
1973
|
-
* Searchable pipeline groups only. Accumulate the items behind *selected*
|
|
2046
|
+
* Searchable pipeline groups only. Accumulate the items behind *selected* values
|
|
1974
2047
|
* so they stay resolvable across searches. Without it, selecting an item in one
|
|
1975
2048
|
* search and then searching for something else leaves the earlier selection
|
|
1976
2049
|
* unresolvable (its value/text is gone from the current results) — which in a
|
|
@@ -2015,7 +2088,7 @@ export const groupItemsAsArray = (
|
|
|
2015
2088
|
* - an array of items — rendered as an anonymous divider-separated group;
|
|
2016
2089
|
* - a {@link InternalGroup} object — a titled / selectable section.
|
|
2017
2090
|
*
|
|
2018
|
-
* The shapes can be mixed, e.g. `[item, [item, item], {
|
|
2091
|
+
* The shapes can be mixed, e.g. `[item, [item, item], { id, label, items }]`.
|
|
2019
2092
|
*/
|
|
2020
2093
|
export type Item = InternalItem | InternalGroup | Item[];
|
|
2021
2094
|
|
|
@@ -2060,10 +2133,11 @@ export const isGroup = (entry: Item): entry is InternalGroup =>
|
|
|
2060
2133
|
* defaults are resolved here. Produced by `normalizeGroups`.
|
|
2061
2134
|
*/
|
|
2062
2135
|
/**
|
|
2063
|
-
* A row after normalization: its `
|
|
2064
|
-
* the dropdown derived for
|
|
2136
|
+
* A row after normalization: its `rowKey` is always set — `hash(value)`, or an
|
|
2137
|
+
* identity the dropdown derived for an action row without a `value`
|
|
2138
|
+
* (`keyless`, Q53.17).
|
|
2065
2139
|
*/
|
|
2066
|
-
export type KeyedItem = InternalItem & {
|
|
2140
|
+
export type KeyedItem = InternalItem & { rowKey: string; domKey: string };
|
|
2067
2141
|
|
|
2068
2142
|
export type NormalizedGroup = {
|
|
2069
2143
|
'append:icon'?: IconType;
|
|
@@ -2071,11 +2145,11 @@ export type NormalizedGroup = {
|
|
|
2071
2145
|
clearable?: boolean;
|
|
2072
2146
|
/** Whether a divider is rendered before this group. */
|
|
2073
2147
|
divider: boolean;
|
|
2074
|
-
/** Keys matched against each raw item when searching (empty ⇒ match
|
|
2148
|
+
/** Keys matched against each raw item when searching (empty ⇒ match the label). */
|
|
2075
2149
|
filterBy?: string[];
|
|
2076
2150
|
items: KeyedItem[];
|
|
2077
|
-
/** Group
|
|
2078
|
-
|
|
2151
|
+
/** Group id (when it originated from a {@link InternalGroup} object). */
|
|
2152
|
+
id?: string;
|
|
2079
2153
|
/** Fixed max-height (px number or CSS length) of this group's item region. */
|
|
2080
2154
|
maxHeight?: number | string;
|
|
2081
2155
|
/** The group's own `meta`, untouched. */
|
|
@@ -2088,7 +2162,7 @@ export type NormalizedGroup = {
|
|
|
2088
2162
|
/** Placeholder for this group's search field. */
|
|
2089
2163
|
searchPlaceholder?: string;
|
|
2090
2164
|
selectable: boolean;
|
|
2091
|
-
/** Selected
|
|
2165
|
+
/** Selected row keys (`rowKey`; injected by `BbDropdown`; empty for non-selectable groups). */
|
|
2092
2166
|
selected: string[];
|
|
2093
2167
|
/** The group's label. Loose/anonymous groups have none. */
|
|
2094
2168
|
label?: string;
|
|
@@ -2112,7 +2186,7 @@ export type MappedItem = InternalItem & {
|
|
|
2112
2186
|
* Passthrough parts of `BbDropdown` (plans/passthrough/BbDropdown.md). Groups,
|
|
2113
2187
|
* headings and dividers are not parts.
|
|
2114
2188
|
*
|
|
2115
|
-
* 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 `
|
|
2189
|
+
* 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_.
|
|
2116
2190
|
*
|
|
2117
2191
|
* @part root - The floating element — an invisible positioning wrapper; a
|
|
2118
2192
|
* `class` on the component lands here. No node on the phone sheet: style
|
|
@@ -2132,13 +2206,13 @@ export type MappedItem = InternalItem & {
|
|
|
2132
2206
|
* headings and dividers are not parts.
|
|
2133
2207
|
* @part item - One menu entry, submenus included — a broadcast resolved per
|
|
2134
2208
|
* entry. Also takes a per-item function, called with the entry.
|
|
2135
|
-
* @part itemText - An entry's label (its `
|
|
2136
|
-
* entry's states. A per-entry `#<
|
|
2209
|
+
* @part itemText - An entry's label (its `label`) — resolved with that
|
|
2210
|
+
* entry's states. A per-entry `#<value>` slot replaces it. Also takes a
|
|
2137
2211
|
* per-item function.
|
|
2138
2212
|
* @part itemIcon - An entry's prepend / append icons — resolved with that
|
|
2139
2213
|
* entry's states. Also takes a per-item function.
|
|
2140
2214
|
* @part itemDescription - An entry's muted second line (its `description`) —
|
|
2141
|
-
* resolved with that entry's states. A per-entry `#<
|
|
2215
|
+
* resolved with that entry's states. A per-entry `#<value>` slot replaces it.
|
|
2142
2216
|
* Also takes a per-item function.
|
|
2143
2217
|
*/
|
|
2144
2218
|
export type BbDropdownPtPart =
|
|
@@ -2277,7 +2351,8 @@ export type BbDropdownProps = {
|
|
|
2277
2351
|
disabled?: boolean;
|
|
2278
2352
|
/**
|
|
2279
2353
|
* Renders the menu panel at mount instead of on the first open (the phone
|
|
2280
|
-
* sheet's too).
|
|
2354
|
+
* sheet's too), and keeps its rows after a close. Without it the rows mount
|
|
2355
|
+
* on each open and go once the menu has closed.
|
|
2281
2356
|
*/
|
|
2282
2357
|
eager?: boolean;
|
|
2283
2358
|
/**
|
|
@@ -2404,8 +2479,8 @@ export type BbDropdownEvents = {
|
|
|
2404
2479
|
/**
|
|
2405
2480
|
* The user selected a row in a selectable group, at the click — also when a
|
|
2406
2481
|
* controlled companion's app then refuses the value. The payload is the
|
|
2407
|
-
*
|
|
2408
|
-
*
|
|
2482
|
+
* row's value (its `item-value` for pipeline groups, else its `value`) —
|
|
2483
|
+
* symmetric with `BbTable`'s `item:selected`.
|
|
2409
2484
|
*/
|
|
2410
2485
|
(e: 'item:selected', value: any): void;
|
|
2411
2486
|
/**
|
|
@@ -2451,11 +2526,11 @@ export type BbDropdownEdgeSlotProps = {
|
|
|
2451
2526
|
|
|
2452
2527
|
/**
|
|
2453
2528
|
* The group a slot renders in, as item slots see it. Anonymous groups (loose
|
|
2454
|
-
* items, plain arrays) have no `
|
|
2529
|
+
* items, plain arrays) have no `id` and no `label`.
|
|
2455
2530
|
*/
|
|
2456
2531
|
export type BbDropdownSlotGroup = {
|
|
2457
|
-
/** The group's
|
|
2458
|
-
|
|
2532
|
+
/** The group's id, when it was declared as a group object. */
|
|
2533
|
+
id?: string;
|
|
2459
2534
|
/** The group's label, when it has one (also when `hideLabel` hides it). */
|
|
2460
2535
|
label?: string;
|
|
2461
2536
|
/** The group's own `meta`. */
|
|
@@ -2503,14 +2578,14 @@ export type BbDropdownItemSlotProps = {
|
|
|
2503
2578
|
placement: BbDropdownProps['placement'];
|
|
2504
2579
|
/** Whether the item currently sits in a selectable group and is selected. */
|
|
2505
2580
|
selected: boolean;
|
|
2506
|
-
/** The
|
|
2507
|
-
|
|
2581
|
+
/** The row's label (on a group's title line, the group's label). */
|
|
2582
|
+
label: InternalItem['label'];
|
|
2508
2583
|
};
|
|
2509
2584
|
|
|
2510
2585
|
/** Props exposed by the `loading` and `empty` placeholder slots. */
|
|
2511
2586
|
export type BbDropdownPlaceholderSlotProps = {
|
|
2512
|
-
/**
|
|
2513
|
-
|
|
2587
|
+
/** Id of the group this placeholder belongs to. */
|
|
2588
|
+
groupId?: string;
|
|
2514
2589
|
/** Resolved placeholder text (group `loadingText`/`emptyText`/`failedText` → dropdown default). */
|
|
2515
2590
|
text: string;
|
|
2516
2591
|
/**
|
|
@@ -2522,23 +2597,24 @@ export type BbDropdownPlaceholderSlotProps = {
|
|
|
2522
2597
|
};
|
|
2523
2598
|
|
|
2524
2599
|
/**
|
|
2525
|
-
* Besides the fixed slots, every
|
|
2526
|
-
* through `slotKey` (`'practice-switcher'` →
|
|
2527
|
-
*
|
|
2528
|
-
*
|
|
2529
|
-
* the `prepend
|
|
2530
|
-
*
|
|
2531
|
-
*
|
|
2600
|
+
* Besides the fixed slots, every row gets named slots from its `value` (a
|
|
2601
|
+
* string or number) run through `slotKey` (`'practice-switcher'` →
|
|
2602
|
+
* `practice-switcher`, `'Delete file'` → `delete-file`), and every group from
|
|
2603
|
+
* its `id`. The most specific slot a row has wins: its own, then its group's,
|
|
2604
|
+
* then the shared `item:prepend` / `item:append`. Each edge has ONE occupant: a
|
|
2605
|
+
* slot replaces the `prepend:icon` / `append:icon`. On the trailing edge the
|
|
2606
|
+
* selected row's check beats every slot, a row's own `#<value>:append` beats
|
|
2607
|
+
* the submenu chevron, and the chevron beats the group-wide and shared slots.
|
|
2532
2608
|
*
|
|
2533
|
-
* @dynamicSlot `<
|
|
2534
|
-
* @dynamicSlot `<
|
|
2535
|
-
* @dynamicSlot `<
|
|
2536
|
-
* @dynamicSlot `<
|
|
2537
|
-
* @dynamicSlot `<
|
|
2538
|
-
* @dynamicSlot `<
|
|
2539
|
-
* @dynamicSlot `<
|
|
2540
|
-
* @dynamicSlot `<
|
|
2541
|
-
* @dynamicSlot `<
|
|
2609
|
+
* @dynamicSlot `<value>` {BbDropdownItemSlotProps} - One row's content (label and description), by its value; in a fetched group, by its resolved `itemValue`.
|
|
2610
|
+
* @dynamicSlot `<value>:prepend` {BbDropdownItemSlotProps} - One row's leading region; replaces its `prepend:icon`.
|
|
2611
|
+
* @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.
|
|
2612
|
+
* @dynamicSlot `<groupId>:item` {BbDropdownItemSlotProps} - The content of every row of that group, and no other; a row's own `#<value>` still wins.
|
|
2613
|
+
* @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`.
|
|
2614
|
+
* @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.
|
|
2615
|
+
* @dynamicSlot `<groupId>` {BbDropdownItemSlotProps} - That group's title line (the group is passed as `item`, `groupTitle` is `true`).
|
|
2616
|
+
* @dynamicSlot `<groupId>:prepend` {BbDropdownItemSlotProps} - The leading region of that group's title line.
|
|
2617
|
+
* @dynamicSlot `<groupId>:append` {BbDropdownItemSlotProps} - The trailing region of that group's title line.
|
|
2542
2618
|
*/
|
|
2543
2619
|
export type BbDropdownSlots = {
|
|
2544
2620
|
/**
|
|
@@ -2586,17 +2662,13 @@ export type BbDropdownSlots = {
|
|
|
2586
2662
|
} & Record<string, (props: BbDropdownItemSlotProps) => any>;
|
|
2587
2663
|
|
|
2588
2664
|
/**
|
|
2589
|
-
* `v-model` value of `<BbDropdownGroup
|
|
2590
|
-
*
|
|
2591
|
-
*
|
|
2592
|
-
*
|
|
2593
|
-
*
|
|
2594
|
-
* - **Pipeline group** (`items` getter + `item-text`/`item-value` in
|
|
2595
|
-
* `BbDropdown.items`): the model mirrors the selected *values* produced by
|
|
2596
|
-
* `item-value` (the whole object by default) — `T | null` (single) or `T[]`
|
|
2597
|
-
* (multiple).
|
|
2665
|
+
* `v-model` value of `<BbDropdownGroup>`: the selected rows' values — a
|
|
2666
|
+
* hand-written row's `value`, or what `item-value` produces in a pipeline group
|
|
2667
|
+
* (its own `value`, else the whole item). `T | null` (single) or `T[]`
|
|
2668
|
+
* (multiple). A single group whose model is `null` shows its `value: null` row
|
|
2669
|
+
* (the "None" row) checked, when it has one.
|
|
2598
2670
|
*/
|
|
2599
|
-
export type BbDropdownGroupModel<T = any> = T[] | T |
|
|
2671
|
+
export type BbDropdownGroupModel<T = any> = T[] | T | null;
|
|
2600
2672
|
|
|
2601
2673
|
/**
|
|
2602
2674
|
* Props of the `<BbDropdownGroup>` companion. Intentionally minimal: the group
|
|
@@ -2606,7 +2678,7 @@ export type BbDropdownGroupModel<T = any> = T[] | T | string[] | string | null;
|
|
|
2606
2678
|
*/
|
|
2607
2679
|
export type BbDropdownGroupProps = {
|
|
2608
2680
|
/**
|
|
2609
|
-
* Identifier of the group to bind to — must match the `
|
|
2681
|
+
* Identifier of the group to bind to — must match the `id` of a group
|
|
2610
2682
|
* declared in the host `BbDropdown`'s `items`.
|
|
2611
2683
|
*/
|
|
2612
2684
|
id: string;
|
|
@@ -2621,8 +2693,8 @@ export type BbDropdownGroupEvents = {
|
|
|
2621
2693
|
(e: 'update:modelValue', value: BbDropdownGroupModel): void;
|
|
2622
2694
|
/**
|
|
2623
2695
|
* The user picked a row, at the click, a pick you then refuse included —
|
|
2624
|
-
* with the
|
|
2625
|
-
*
|
|
2696
|
+
* with the row's value (its `item-value` for pipeline groups, else its
|
|
2697
|
+
* `value`), symmetric with `BbTable`. Your own `v-model` changes fire none.
|
|
2626
2698
|
*/
|
|
2627
2699
|
(e: 'item:selected', value: any): void;
|
|
2628
2700
|
/** The user unpicked a row (or a single pick replaced it), with its resolved value. */
|
|
@@ -2997,7 +3069,7 @@ export type BbDropdownGroupEvents = {
|
|
|
2997
3069
|
min-width: 0;
|
|
2998
3070
|
padding: 2px 6px;
|
|
2999
3071
|
position: relative;
|
|
3000
|
-
text-align:
|
|
3072
|
+
text-align: start;
|
|
3001
3073
|
width: 100%;
|
|
3002
3074
|
|
|
3003
3075
|
/* `:focus-visible`, NOT `:focus`. Rows are `tabindex="-1"` (ARIA menu
|
|
@@ -3348,7 +3420,7 @@ export type BbDropdownGroupEvents = {
|
|
|
3348
3420
|
height: var(--sheet-row-h, 44px);
|
|
3349
3421
|
/* Flyout rows are `2px 6px`. +4px start so the label shares the
|
|
3350
3422
|
search field's text edge (`padding-inline: 0.75rem` on the fill). */
|
|
3351
|
-
padding-
|
|
3423
|
+
padding-inline-start: calc(6px + 4px);
|
|
3352
3424
|
/* iOS treats a <button> as a tap target and will not hand the pan to
|
|
3353
3425
|
the sheet body unless the control itself opts into vertical panning.
|
|
3354
3426
|
Without this, dismiss/scroll work on the handle and miss on rows. */
|
|
@@ -3375,7 +3447,7 @@ export type BbDropdownGroupEvents = {
|
|
|
3375
3447
|
|
|
3376
3448
|
.bb-dropdown__placeholder {
|
|
3377
3449
|
min-height: var(--sheet-row-h, 44px);
|
|
3378
|
-
padding-
|
|
3450
|
+
padding-inline-start: calc(6px + 4px);
|
|
3379
3451
|
}
|
|
3380
3452
|
|
|
3381
3453
|
/* Icons scale with the label they sit beside. The desktop sizes (16px
|
|
@@ -3442,7 +3514,7 @@ export type BbDropdownGroupEvents = {
|
|
|
3442
3514
|
.bb-dropdown__sheet-selection {
|
|
3443
3515
|
flex-shrink: 0;
|
|
3444
3516
|
padding: 0 0 0.5rem;
|
|
3445
|
-
text-align:
|
|
3517
|
+
text-align: start;
|
|
3446
3518
|
}
|
|
3447
3519
|
|
|
3448
3520
|
.bb-dropdown__sheet-chips {
|
|
@@ -3486,7 +3558,7 @@ export type BbDropdownGroupEvents = {
|
|
|
3486
3558
|
Use `--bb-panel-p`, not `--px`: BbButton redefines `--px` as its
|
|
3487
3559
|
own padding token, which collapsed the inset to 10px. */
|
|
3488
3560
|
.bb-dropdown__nav-back {
|
|
3489
|
-
|
|
3561
|
+
inset-inline-start: var(--bb-panel-p);
|
|
3490
3562
|
position: absolute;
|
|
3491
3563
|
top: var(--bb-panel-p);
|
|
3492
3564
|
|