bitboss-ui 3.0.0-beta.21 → 3.0.0-beta.23
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 +55 -3
- package/bin/bitboss-ui-mcp.mjs +419 -9
- package/bin/bitboss-ui.mjs +293 -22
- package/dist/ai/BbAccordion.md +21 -23
- package/dist/ai/BbAlert.md +6 -12
- package/dist/ai/BbAvatar.md +60 -24
- package/dist/ai/BbBadge.md +12 -20
- package/dist/ai/BbBaseButton.md +14 -16
- package/dist/ai/BbBaseCheckboxIcon.md +6 -10
- package/dist/ai/BbBaseColorInput.md +1 -0
- package/dist/ai/BbBaseDatePickerInput.md +1 -0
- package/dist/ai/BbBaseNumberInput.md +1 -0
- package/dist/ai/BbBaseRadioIcon.md +6 -10
- package/dist/ai/BbBaseSelect.md +1 -0
- package/dist/ai/BbBaseSwitchIcon.md +5 -9
- package/dist/ai/BbBaseTag.md +1 -0
- package/dist/ai/BbBaseTextInput.md +2 -1
- package/dist/ai/BbBaseTextarea.md +1 -0
- package/dist/ai/BbBaseTimePickerInput.md +1 -0
- package/dist/ai/BbBreadcrumbs.md +23 -34
- package/dist/ai/BbButton.md +35 -47
- package/dist/ai/BbCheckbox.md +21 -37
- package/dist/ai/BbCheckboxGroup.md +13 -13
- package/dist/ai/BbCollapsible.md +14 -26
- package/dist/ai/BbColorInput.md +27 -23
- package/dist/ai/BbColorPalette.md +23 -35
- package/dist/ai/BbConfirm.md +17 -32
- package/dist/ai/BbDatePickerInput.md +29 -21
- package/dist/ai/BbDialog.md +159 -62
- package/dist/ai/BbDropdown.md +21 -25
- package/dist/ai/BbDropdownButton.md +13 -30
- package/dist/ai/BbDropzone.md +9 -11
- package/dist/ai/BbIcon.md +44 -33
- package/dist/ai/BbIndicator.md +2 -2
- package/dist/ai/BbNumberInput.md +32 -20
- package/dist/ai/BbOffCanvas.md +42 -42
- package/dist/ai/BbPagination.md +21 -23
- package/dist/ai/BbPopover.md +15 -17
- package/dist/ai/BbProgress.md +40 -51
- package/dist/ai/BbRadio.md +9 -9
- package/dist/ai/BbRadioGroup.md +7 -11
- package/dist/ai/BbRating.md +8 -12
- package/dist/ai/BbSelect.md +46 -36
- package/dist/ai/BbSelectPopover.md +19 -31
- package/dist/ai/BbSlider.md +15 -19
- package/dist/ai/BbSmoothHeight.md +16 -31
- package/dist/ai/BbSpinner.md +118 -74
- package/dist/ai/BbSwitch.md +25 -18
- package/dist/ai/BbSwitchGroup.md +9 -14
- package/dist/ai/BbTable.md +102 -55
- package/dist/ai/BbTabs.md +59 -82
- package/dist/ai/BbTag.md +26 -23
- package/dist/ai/BbTextInput.md +63 -27
- package/dist/ai/BbTextarea.md +42 -34
- package/dist/ai/BbTimePickerInput.md +14 -0
- package/dist/ai/BbToast.md +14 -34
- package/dist/ai/BbTooltip.md +22 -20
- package/dist/ai/BbTree.md +46 -72
- package/dist/ai/CommonInputWrapper.md +1 -0
- package/dist/ai/changelog.json +170 -62
- package/dist/ai/components.json +1678 -11
- package/dist/ai/composables/useConfirm.md +5 -2
- package/dist/ai/composables/useToast.md +4 -2
- package/dist/ai/guides/agent-contract.md +7 -4
- package/dist/ai/guides/ai-router.md +37 -22
- package/dist/ai/guides/component-picker.md +23 -18
- package/dist/ai/guides/design-language.md +151 -21
- package/dist/ai/guides/design-tokens.md +29 -4
- package/dist/ai/guides/icons-policy.md +46 -21
- package/dist/ai/guides/installation-and-plugin-setup.md +286 -17
- package/dist/ai/guides/migration/components/bb-rating.md +26 -1
- package/dist/ai/guides/migration/components/bb-tooltip.md +18 -0
- package/dist/ai/guides/migration/v2-to-v3.md +50 -23
- package/dist/ai/index.md +1 -1
- package/dist/ai/recipes/inertia/approvals-inbox.md +3 -3
- package/dist/ai/recipes/inertia/inline-edit-workspace.md +2 -2
- package/dist/ai/recipes/inertia/onboarding.md +2 -2
- package/dist/ai/recipes/inertia/ownership-atlas.md +6 -6
- package/dist/ai/recipes/inertia/record-form.md +5 -5
- package/dist/ai/recipes/inertia/records-workspace.md +4 -4
- package/dist/ai/recipes/inertia/upload-center.md +6 -6
- package/dist/ai/recipes/inertia/wizard-form.md +5 -5
- package/dist/ai/recipes/nuxt/approvals-inbox.md +3 -3
- package/dist/ai/recipes/nuxt/inline-edit-workspace.md +2 -2
- package/dist/ai/recipes/nuxt/onboarding.md +2 -2
- package/dist/ai/recipes/nuxt/record-form.md +5 -5
- package/dist/ai/recipes/nuxt/records-workspace.md +4 -4
- package/dist/ai/recipes/nuxt/upload-center.md +6 -6
- package/dist/ai/recipes/nuxt/wizard-form.md +5 -5
- package/dist/ai/recipes/vue/approvals-inbox.md +3 -3
- package/dist/ai/recipes/vue/inline-edit-workspace.md +2 -2
- package/dist/ai/recipes/vue/onboarding.md +2 -2
- package/dist/ai/recipes/vue/record-form.md +10 -10
- package/dist/ai/recipes/vue/records-workspace.md +4 -4
- package/dist/ai/recipes/vue/upload-center.md +6 -6
- package/dist/ai/recipes/vue/wizard-form.md +5 -5
- package/dist/ai/source/BbBadge.md +1 -1
- package/dist/ai/source/BbBaseCheckbox.md +1 -1
- package/dist/ai/source/BbBaseColorInput.md +7 -0
- package/dist/ai/source/BbBaseDatePicker.md +5 -5
- package/dist/ai/source/BbBaseDatePickerInput.md +9 -2
- package/dist/ai/source/BbBaseNumberInput.md +7 -0
- package/dist/ai/source/BbBaseRadio.md +1 -1
- package/dist/ai/source/BbBaseRating.md +5 -5
- package/dist/ai/source/BbBaseSelect.md +8 -1
- package/dist/ai/source/BbBaseSlider.md +5 -5
- package/dist/ai/source/BbBaseSwitch.md +1 -1
- package/dist/ai/source/BbBaseTag.md +7 -0
- package/dist/ai/source/BbBaseTextInput.md +7 -0
- package/dist/ai/source/BbBaseTextarea.md +7 -0
- package/dist/ai/source/BbBaseTimePickerInput.md +8 -1
- package/dist/ai/source/BbBreadcrumbs.md +20 -1
- package/dist/ai/source/BbButton.md +2 -2
- package/dist/ai/source/BbColorInput.md +14 -0
- package/dist/ai/source/BbDatePickerInput.md +14 -0
- package/dist/ai/source/BbDialog.md +39 -8
- package/dist/ai/source/BbDropdown.md +1 -1
- package/dist/ai/source/BbDropzone.md +5 -5
- package/dist/ai/source/BbIcon.md +23 -10
- package/dist/ai/source/BbNumberInput.md +14 -0
- package/dist/ai/source/BbOffCanvas.md +50 -28
- package/dist/ai/source/BbPagination.md +2 -2
- package/dist/ai/source/BbPopover.md +12 -1
- package/dist/ai/source/BbSelect.md +14 -0
- package/dist/ai/source/BbSelectPopover.md +45 -7
- package/dist/ai/source/BbSpinner.md +2 -2
- package/dist/ai/source/BbTable.md +11 -11
- package/dist/ai/source/BbTag.md +14 -0
- package/dist/ai/source/BbTextInput.md +14 -0
- package/dist/ai/source/BbTextarea.md +14 -0
- package/dist/ai/source/BbTimePickerInput.md +14 -0
- package/dist/ai/source/BbTooltip.md +57 -10
- package/dist/ai/source/ChipsBox.md +1 -1
- package/dist/ai/source/CommaBox.md +1 -1
- package/dist/ai/source/CommonInputWrapper.md +128 -33
- package/dist/ai/source/GuidesComponent.md +14 -7
- package/dist/ai/source/OptionsContainer.md +1 -1
- package/dist/components/BbBadge/BadgeBodyContent.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/components/BbBadge/BbBadge.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/components/BbBaseCheckbox/BbBaseCheckbox.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/components/BbBaseColorInput/BbBaseColorInput.vue_vue_type_script_setup_true_lang.js +4 -1
- package/dist/components/BbBaseColorInput/types.d.ts +5 -0
- package/dist/components/BbBaseDatePicker/BbBaseDatePicker.vue_vue_type_script_setup_true_lang.js +4 -4
- package/dist/components/BbBaseDatePicker/BbBaseDatePickerInputDaySelector.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/components/BbBaseDatePickerInput/BbBaseDatePickerInput.vue_vue_type_script_setup_true_lang.js +5 -2
- package/dist/components/BbBaseDatePickerInput/types.d.ts +5 -0
- package/dist/components/BbBaseInputContainer/BbBaseInputContainer.vue.d.ts +1 -1
- package/dist/components/BbBaseNumberInput/BbBaseNumberInput.vue_vue_type_script_setup_true_lang.js +4 -1
- package/dist/components/BbBaseNumberInput/types.d.ts +5 -0
- package/dist/components/BbBaseRadio/BbBaseRadio.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/components/BbBaseRating/BbBaseRating.vue_vue_type_script_setup_true_lang.js +3 -3
- package/dist/components/BbBaseSelect/BbBaseSelect.vue_vue_type_script_setup_true_lang.js +4 -1
- package/dist/components/BbBaseSelect/types.d.ts +5 -0
- package/dist/components/BbBaseSlider/BbBaseSlider.vue_vue_type_script_setup_true_lang.js +3 -3
- package/dist/components/BbBaseSwitch/BbBaseSwitch.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/components/BbBaseTag/BbBaseTag.vue_vue_type_script_setup_true_lang.js +4 -1
- package/dist/components/BbBaseTag/types.d.ts +5 -0
- package/dist/components/BbBaseTextInput/BbBaseTextInput.vue_vue_type_script_setup_true_lang.js +4 -1
- package/dist/components/BbBaseTextInput/types.d.ts +5 -0
- package/dist/components/BbBaseTextarea/BbBaseTextarea.vue_vue_type_script_setup_true_lang.js +4 -1
- package/dist/components/BbBaseTextarea/types.d.ts +5 -0
- package/dist/components/BbBaseTimePickerInput/BbBaseTimePickerInput.vue_vue_type_script_setup_true_lang.js +5 -2
- package/dist/components/BbBaseTimePickerInput/types.d.ts +5 -0
- package/dist/components/BbBreadcrumbs/BbBreadcrumbs.vue_vue_type_script_setup_true_lang.js +71 -71
- package/dist/components/BbButton/BbButton.vue_vue_type_script_setup_true_lang.js +2 -2
- package/dist/components/BbColorInput/BbColorInput.vue_vue_type_script_setup_true_lang.js +5 -2
- package/dist/components/BbColorInput/types.d.ts +12 -0
- package/dist/components/BbDatePickerInput/BbDatePickerInput.vue_vue_type_script_setup_true_lang.js +4 -2
- package/dist/components/BbDatePickerInput/types.d.ts +12 -0
- package/dist/components/BbDialog/BbDialog.vue_vue_type_script_setup_true_lang.js +102 -97
- package/dist/components/BbDropdown/AdaptiveDropdown.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/components/BbDropdown/BbDropdown.vue_vue_type_script_setup_true_lang.js +58 -58
- package/dist/components/BbDropzone/BbDropzone.vue_vue_type_script_setup_true_lang.js +2 -2
- package/dist/components/BbIcon/BbIcon.vue_vue_type_script_setup_true_lang.js +33 -35
- package/dist/components/BbIcon/iconCache.d.ts +30 -0
- package/dist/components/BbIcon/iconCache.js +21 -3
- package/dist/components/BbNumberInput/BbNumberInput.vue_vue_type_script_setup_true_lang.js +5 -2
- package/dist/components/BbNumberInput/types.d.ts +12 -0
- package/dist/components/BbOffCanvas/BbOffCanvas.vue_vue_type_script_setup_true_lang.js +57 -56
- package/dist/components/BbPagination/BbPagination.vue_vue_type_script_setup_true_lang.js +2 -2
- package/dist/components/BbPopover/BbPopover.vue_vue_type_script_setup_true_lang.js +138 -138
- package/dist/components/BbSelect/BbSelect.vue_vue_type_script_setup_true_lang.js +4 -2
- package/dist/components/BbSelect/types.d.ts +12 -0
- package/dist/components/BbSelectPopover/BbSelectPopover.vue_vue_type_script_setup_true_lang.js +43 -43
- package/dist/components/BbSpinner/BbSpinner.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/components/BbSpinner/types.d.ts +1 -1
- package/dist/components/BbTable/BbTable.vue_vue_type_script_setup_true_lang.js +8 -8
- package/dist/components/BbTable/BbTableDataRow.js +2 -2
- package/dist/components/BbTag/BbTag.vue_vue_type_script_setup_true_lang.js +5 -2
- package/dist/components/BbTag/types.d.ts +12 -0
- package/dist/components/BbTextInput/BbTextInput.vue_vue_type_script_setup_true_lang.js +5 -2
- package/dist/components/BbTextInput/types.d.ts +12 -0
- package/dist/components/BbTextarea/BbTextarea.vue_vue_type_script_setup_true_lang.js +5 -2
- package/dist/components/BbTextarea/types.d.ts +12 -0
- package/dist/components/BbTimePickerInput/BbTimePickerInput.vue_vue_type_script_setup_true_lang.js +4 -2
- package/dist/components/BbTimePickerInput/types.d.ts +12 -0
- package/dist/components/BbToast/BbToastRegion.vue_vue_type_script_setup_true_lang.js +62 -62
- package/dist/components/BbTooltip/BbTooltip.vue_vue_type_script_setup_true_lang.js +81 -78
- package/dist/components/BbTooltip/types.d.ts +8 -1
- package/dist/components/ChipsBox/ChipsBox.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/components/CommaBox/CommaBox.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/components/CommonInputWrapper/CommonInputWrapper.vue.d.ts +1 -0
- package/dist/components/CommonInputWrapper/CommonInputWrapper.vue_vue_type_script_setup_true_lang.js +4 -2
- package/dist/components/CommonInputWrapper/types.d.ts +10 -0
- package/dist/components/OptionsContainer/OptionsContainer.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/composables/useConfirm.d.ts +22 -0
- package/dist/composables/useConfirm.js +43 -40
- package/dist/composables/useSafeAreaInternal.js +1 -1
- package/dist/composables/useToast.d.ts +16 -0
- package/dist/composables/useToast.js +20 -16
- package/dist/composables/useViewportWidth.d.ts +20 -6
- package/dist/composables/useViewportWidth.js +8 -7
- package/dist/icon-scan.d.ts +276 -0
- package/dist/icon-scan.js +485 -0
- package/dist/icons-whitelist.d.ts +5 -4
- package/dist/index.d.ts +2 -0
- package/dist/input-variants.d.ts +18 -0
- package/dist/llms-full.txt +2173 -1537
- package/dist/llms-medium.txt +504 -82
- package/dist/llms.txt +1 -1
- package/dist/nuxt-module.d.ts +1 -0
- package/dist/nuxt.js +10 -7
- package/dist/plugin.js +1 -0
- package/dist/runtime/nuxt-plugin.js +2 -1
- package/dist/styles.css +1 -1
- package/dist/types/Config.d.ts +18 -0
- package/dist/types/InputVariant.d.ts +22 -0
- package/dist/utils/cssLayers.d.ts +91 -0
- package/dist/utils/cssLayers.js +43 -0
- package/dist/utils/injectLibraryStyles.d.ts +3 -1
- package/dist/utils/injectLibraryStyles.js +24 -23
- package/dist/validated/BbColorInput.vue_vue_type_script_setup_true_lang.js +1 -0
- package/dist/validated/BbDatePickerInput.vue_vue_type_script_setup_true_lang.js +1 -0
- package/dist/validated/BbNumberInput.vue_vue_type_script_setup_true_lang.js +1 -0
- package/dist/validated/BbSelect.vue_vue_type_script_setup_true_lang.js +1 -0
- package/dist/validated/BbTag.vue_vue_type_script_setup_true_lang.js +1 -0
- package/dist/validated/BbTextInput.vue_vue_type_script_setup_true_lang.js +1 -0
- package/dist/validated/BbTextarea.vue_vue_type_script_setup_true_lang.js +1 -0
- package/dist/validated/BbTimePickerInput.vue_vue_type_script_setup_true_lang.js +1 -0
- package/dist/validated/index.d.ts +1 -0
- package/dist/vite-plugin.d.ts +89 -12
- package/dist/vite.js +331 -281
- package/llms.txt +1 -1
- package/package.json +7 -5
- package/scripts/lib/ensure-manifest.mjs +28 -5
- package/scripts/lib/eslint-plugin.d.ts +35 -0
- package/scripts/lib/eslint-plugin.mjs +299 -3
- package/scripts/lib/hand-roll-hints.mjs +50 -6
- package/scripts/lib/html-attributes.mjs +42 -0
- package/scripts/lib/mcp-config.mjs +38 -34
- package/scripts/lib/public-type-exports.mjs +246 -0
- package/scripts/lib/validate-bb-markup.mjs +205 -12
|
@@ -109,7 +109,7 @@
|
|
|
109
109
|
aria-expanded="true"
|
|
110
110
|
:aria-invalid="computedAriaInvalid"
|
|
111
111
|
:aria-label="searchInputAriaLabel"
|
|
112
|
-
class="bb-select-popover__focus-proxy sr-only"
|
|
112
|
+
class="bb-select-popover__focus-proxy bb-sr-only"
|
|
113
113
|
role="combobox"
|
|
114
114
|
tabindex="-1"
|
|
115
115
|
type="button"
|
|
@@ -642,6 +642,22 @@ const onOutsideInteraction = async (event: Event) => {
|
|
|
642
642
|
const insideActivator = positionAnchorEl.value?.contains(target);
|
|
643
643
|
const insidePopover = !!target.closest('.bb-common-popover');
|
|
644
644
|
if (insideActivator || insidePopover) return;
|
|
645
|
+
// Focus landing on an ANCESTOR of the activator is a focus fallback, not
|
|
646
|
+
// the user going elsewhere. A mousedown on a non-focusable node inside a
|
|
647
|
+
// modal `<dialog>` — the field's own `<label>` — parks focus on the dialog
|
|
648
|
+
// element itself, which arrived here as an outside `focusin` and closed
|
|
649
|
+
// the panel one tick before the label's click reached the activator and
|
|
650
|
+
// reopened it: a close/open flash that a label outside any dialog never
|
|
651
|
+
// showed (focus falls to `body` there, which fires no `focusin`). Scoped
|
|
652
|
+
// to `focusin` on purpose: a CLICK whose target is that ancestor (the
|
|
653
|
+
// dialog's own padding) is a real outside click and must still close.
|
|
654
|
+
if (
|
|
655
|
+
event.type === 'focusin' &&
|
|
656
|
+
positionAnchorEl.value &&
|
|
657
|
+
target.contains(positionAnchorEl.value)
|
|
658
|
+
) {
|
|
659
|
+
return;
|
|
660
|
+
}
|
|
645
661
|
const label =
|
|
646
662
|
target instanceof HTMLLabelElement ? target : target.closest('label');
|
|
647
663
|
if (label?.control && positionAnchorEl.value?.contains(label.control)) return;
|
|
@@ -1231,8 +1247,22 @@ const open = async ({
|
|
|
1231
1247
|
// Join the shared Escape stack only in flyout mode — the sheet returned
|
|
1232
1248
|
// above and BbOffCanvas registers itself instead.
|
|
1233
1249
|
pushEscapeEntry(escapeKey);
|
|
1234
|
-
|
|
1235
|
-
|
|
1250
|
+
// CAPTURE, not bubble. Every overlay root — a `<dialog>`, an off-canvas,
|
|
1251
|
+
// another popover — binds `overlaySurfaceIsolation`, which stops `click`
|
|
1252
|
+
// from bubbling past the surface so handlers BEHIND it never hear a click
|
|
1253
|
+
// aimed at it. A select declared INSIDE such a surface is behind nothing,
|
|
1254
|
+
// but its document listener sits above the boundary all the same: a click
|
|
1255
|
+
// on the dialog's own chrome was swallowed at the dialog and never
|
|
1256
|
+
// reached a bubble-phase watcher here, so it could not close the panel.
|
|
1257
|
+
// (It used to close by accident: mousedown parked focus on the dialog and
|
|
1258
|
+
// the `focusin` path treated that as leaving — see the ancestor guard.)
|
|
1259
|
+
// Capture runs before the boundary and before any consumer `.stop`, and
|
|
1260
|
+
// the inside/label guards in `onOutsideInteraction` already carry the
|
|
1261
|
+
// meaning, so nothing inside the select's own chrome is affected.
|
|
1262
|
+
document.addEventListener('click', onOutsideInteraction, { capture: true });
|
|
1263
|
+
document.addEventListener('focusin', onOutsideInteraction, {
|
|
1264
|
+
capture: true,
|
|
1265
|
+
});
|
|
1236
1266
|
document.addEventListener('keydown', onEsc, { capture: true });
|
|
1237
1267
|
|
|
1238
1268
|
if (!focusPopoverContent) return;
|
|
@@ -1259,8 +1289,12 @@ const close = async () => {
|
|
|
1259
1289
|
|
|
1260
1290
|
pause();
|
|
1261
1291
|
removeEscapeEntry(escapeKey);
|
|
1262
|
-
document.removeEventListener('click', onOutsideInteraction
|
|
1263
|
-
|
|
1292
|
+
document.removeEventListener('click', onOutsideInteraction, {
|
|
1293
|
+
capture: true,
|
|
1294
|
+
});
|
|
1295
|
+
document.removeEventListener('focusin', onOutsideInteraction, {
|
|
1296
|
+
capture: true,
|
|
1297
|
+
});
|
|
1264
1298
|
document.removeEventListener('keydown', onEsc, { capture: true });
|
|
1265
1299
|
};
|
|
1266
1300
|
|
|
@@ -1575,8 +1609,12 @@ onBeforeUnmount(() => {
|
|
|
1575
1609
|
// `shown` is a plain local ref that unmounting never resets, so the orphaned
|
|
1576
1610
|
// capture-phase handler keeps passing its own guard and swallowing the key.
|
|
1577
1611
|
removeEscapeEntry(escapeKey);
|
|
1578
|
-
document.removeEventListener('click', onOutsideInteraction
|
|
1579
|
-
|
|
1612
|
+
document.removeEventListener('click', onOutsideInteraction, {
|
|
1613
|
+
capture: true,
|
|
1614
|
+
});
|
|
1615
|
+
document.removeEventListener('focusin', onOutsideInteraction, {
|
|
1616
|
+
capture: true,
|
|
1617
|
+
});
|
|
1580
1618
|
document.removeEventListener('keydown', onEsc, { capture: true });
|
|
1581
1619
|
});
|
|
1582
1620
|
/**
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
<template>
|
|
9
9
|
<span v-if="label" role="status">
|
|
10
10
|
<BbIcon class="bb-spinner" :icon="spinnerSvg" :size="size" />
|
|
11
|
-
<span class="sr-only">{{ label }}</span>
|
|
11
|
+
<span class="bb-sr-only">{{ label }}</span>
|
|
12
12
|
</span>
|
|
13
13
|
<BbIcon v-else class="bb-spinner" :icon="spinnerSvg" :size="size" />
|
|
14
14
|
</template>
|
|
@@ -47,7 +47,7 @@ export type Size = IconSize;
|
|
|
47
47
|
export type BbSpinnerProps = Pick<BbIconProps, 'size'> & {
|
|
48
48
|
/**
|
|
49
49
|
* Accessible loading announcement. When set, the spinner is wrapped in a
|
|
50
|
-
* `role="status"` element containing this text rendered `sr-only`, so
|
|
50
|
+
* `role="status"` element containing this text rendered `bb-sr-only`, so
|
|
51
51
|
* screen readers announce the loading state. When omitted the markup is
|
|
52
52
|
* unchanged and the spinner is purely decorative.
|
|
53
53
|
*/
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
:inert="disabled"
|
|
17
17
|
:style="containerStyle"
|
|
18
18
|
>
|
|
19
|
-
<legend v-if="selectable" class="sr-only">{{ legendText }}</legend>
|
|
19
|
+
<legend v-if="selectable" class="bb-sr-only">{{ legendText }}</legend>
|
|
20
20
|
<!-- The caption lives OUTSIDE the table role (a `caption` role is invalid
|
|
21
21
|
there for a div table) and names the table through `aria-labelledby`. -->
|
|
22
22
|
<div
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
:id="captionId"
|
|
25
25
|
class="bb-table-caption"
|
|
26
26
|
:class="{
|
|
27
|
-
'sr-only': !displayCaption,
|
|
27
|
+
'bb-sr-only': !displayCaption,
|
|
28
28
|
}"
|
|
29
29
|
>
|
|
30
30
|
{{ caption }}
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
<div
|
|
41
41
|
v-if="reorderable || resizable"
|
|
42
42
|
:id="headerInstructionsId"
|
|
43
|
-
class="sr-only"
|
|
43
|
+
class="bb-sr-only"
|
|
44
44
|
>
|
|
45
45
|
<template v-if="reorderable"
|
|
46
46
|
>{{ t('table.reorderInstructions').value }}
|
|
@@ -63,14 +63,14 @@
|
|
|
63
63
|
from outside `role="menu"`. -->
|
|
64
64
|
<span
|
|
65
65
|
aria-live="polite"
|
|
66
|
-
class="bb-table-loading__text sr-only"
|
|
66
|
+
class="bb-table-loading__text bb-sr-only"
|
|
67
67
|
role="status"
|
|
68
68
|
>{{ loading ? loadingText || t('common.loadingText').value : '' }}</span
|
|
69
69
|
>
|
|
70
70
|
<template v-if="reorderable">
|
|
71
71
|
<span
|
|
72
72
|
aria-live="polite"
|
|
73
|
-
class="bb-table__reorder-status sr-only"
|
|
73
|
+
class="bb-table__reorder-status bb-sr-only"
|
|
74
74
|
role="status"
|
|
75
75
|
>{{ columnOrderStatus }}</span
|
|
76
76
|
>
|
|
@@ -175,13 +175,13 @@
|
|
|
175
175
|
:name="`select_all_${name || ''}`"
|
|
176
176
|
:readonly="readonly"
|
|
177
177
|
/>
|
|
178
|
-
<span class="bb-table-check__label-text sr-only"
|
|
178
|
+
<span class="bb-table-check__label-text bb-sr-only"
|
|
179
179
|
>{{ selectAllLabel || t('table.selectAllLabel').value }}
|
|
180
180
|
</span>
|
|
181
181
|
</label>
|
|
182
182
|
<span
|
|
183
183
|
v-else-if="!multiple"
|
|
184
|
-
class="bb-table-radio__label-text sr-only"
|
|
184
|
+
class="bb-table-radio__label-text bb-sr-only"
|
|
185
185
|
>{{ selectText || t('table.selectText').value }}</span
|
|
186
186
|
>
|
|
187
187
|
</span>
|
|
@@ -306,7 +306,7 @@
|
|
|
306
306
|
name="header:actions"
|
|
307
307
|
:text="actionsText || t('table.actionsText').value"
|
|
308
308
|
>
|
|
309
|
-
<span class="bb-table-header__content sr-only">
|
|
309
|
+
<span class="bb-table-header__content bb-sr-only">
|
|
310
310
|
{{ actionsText || t('table.actionsText').value }}
|
|
311
311
|
</span>
|
|
312
312
|
</slot>
|
|
@@ -821,7 +821,7 @@ const {
|
|
|
821
821
|
/** Id of the caption element the grid root is labelled by. */
|
|
822
822
|
const captionId = computed(() => `${tableId.value}__caption`);
|
|
823
823
|
|
|
824
|
-
/** Id of the sr-only keyboard instructions every data header is described by. */
|
|
824
|
+
/** Id of the bb-sr-only keyboard instructions every data header is described by. */
|
|
825
825
|
const headerInstructionsId = computed(
|
|
826
826
|
() => `${tableId.value}__header_instructions`
|
|
827
827
|
);
|
|
@@ -6537,7 +6537,7 @@ export type BbTableSlots<Item = any> = {
|
|
|
6537
6537
|
|
|
6538
6538
|
/* The label is an inline-block so the affixes keep their inline flow, and
|
|
6539
6539
|
it ellipsizes within the cell; the select/actions headers keep their
|
|
6540
|
-
sr-only / control content untouched. */
|
|
6540
|
+
bb-sr-only / control content untouched. */
|
|
6541
6541
|
&-header:not(.bb-table-header--select):not(.bb-table-header--actions)
|
|
6542
6542
|
> .bb-table-header__content {
|
|
6543
6543
|
display: inline-block;
|
|
@@ -7115,7 +7115,7 @@ export type BbTableSlots<Item = any> = {
|
|
|
7115
7115
|
dependency change (a filter, a poll, an autosave round-trip). Keep the rows
|
|
7116
7116
|
on screen, mark them stale, and run an indeterminate bar along the header/body
|
|
7117
7117
|
boundary. `aria-busy` on the root already carries the semantics and the
|
|
7118
|
-
sr-only row in the body still announces, so the bar is decorative — hence a
|
|
7118
|
+
bb-sr-only row in the body still announces, so the bar is decorative — hence a
|
|
7119
7119
|
pseudo-element rather than a node. `.bb-table--empty` is "nothing to keep". */
|
|
7120
7120
|
.bb-table--loading:not(.bb-table--empty) {
|
|
7121
7121
|
& .bb-table__body {
|
package/dist/ai/source/BbTag.md
CHANGED
|
@@ -51,6 +51,7 @@
|
|
|
51
51
|
:prepend:icon="props['prepend:icon']"
|
|
52
52
|
:readonly="readonly"
|
|
53
53
|
:required="required"
|
|
54
|
+
:variant="variant"
|
|
54
55
|
v-bind="eventListeners"
|
|
55
56
|
>
|
|
56
57
|
<template #prepend-outer="data"
|
|
@@ -144,6 +145,7 @@ const eventListeners = {
|
|
|
144
145
|
## Types
|
|
145
146
|
|
|
146
147
|
```ts
|
|
148
|
+
import type { InputVariantType } from '@/types/InputVariant';
|
|
147
149
|
import type { HTMLAttributes, InputHTMLAttributes } from 'vue';
|
|
148
150
|
import type { InputDirection } from '@/types/InputDirection';
|
|
149
151
|
import type { IconType } from '@/types/Icon';
|
|
@@ -193,6 +195,18 @@ export type BbTagProps = {
|
|
|
193
195
|
*/
|
|
194
196
|
compact?: boolean;
|
|
195
197
|
|
|
198
|
+
/**
|
|
199
|
+
* Visual variant of the field box — the same names and tokens as the
|
|
200
|
+
* `BbButton` variants. Colours only: height, padding and border width are
|
|
201
|
+
* identical across variants, so a form never reflows when one changes.
|
|
202
|
+
* `'ghost'` has no border in any state (errors and warnings show through
|
|
203
|
+
* the icon and the messages); every variant keeps the focus ring.
|
|
204
|
+
* Register extra names with the plugin's `inputVariants` option.
|
|
205
|
+
*
|
|
206
|
+
* @defaultValue `'outline'`
|
|
207
|
+
*/
|
|
208
|
+
variant?: InputVariantType;
|
|
209
|
+
|
|
196
210
|
/**
|
|
197
211
|
* Descriptive text displayed below the label and above the input. Unlike the hint it is always
|
|
198
212
|
* visible, and it is linked to the input via `aria-describedby` (after any
|
|
@@ -57,6 +57,7 @@
|
|
|
57
57
|
:readonly="readonly"
|
|
58
58
|
:required="required"
|
|
59
59
|
:type="type"
|
|
60
|
+
:variant="variant"
|
|
60
61
|
v-bind="eventListeners"
|
|
61
62
|
>
|
|
62
63
|
<template #append-outer><slot name="append-outer" /></template>
|
|
@@ -136,6 +137,7 @@ const eventListeners = {
|
|
|
136
137
|
## Types
|
|
137
138
|
|
|
138
139
|
```ts
|
|
140
|
+
import type { InputVariantType } from '@/types/InputVariant';
|
|
139
141
|
import type { HTMLAttributes, InputHTMLAttributes } from 'vue';
|
|
140
142
|
import type { InputDirection } from '@/types/InputDirection';
|
|
141
143
|
import type { MaskInputOptions } from 'maska';
|
|
@@ -171,6 +173,18 @@ export type BbTextInputProps = {
|
|
|
171
173
|
*/
|
|
172
174
|
compact?: boolean;
|
|
173
175
|
|
|
176
|
+
/**
|
|
177
|
+
* Visual variant of the field box — the same names and tokens as the
|
|
178
|
+
* `BbButton` variants. Colours only: height, padding and border width are
|
|
179
|
+
* identical across variants, so a form never reflows when one changes.
|
|
180
|
+
* `'ghost'` has no border in any state (errors and warnings show through
|
|
181
|
+
* the icon and the messages); every variant keeps the focus ring.
|
|
182
|
+
* Register extra names with the plugin's `inputVariants` option.
|
|
183
|
+
*
|
|
184
|
+
* @defaultValue `'outline'`
|
|
185
|
+
*/
|
|
186
|
+
variant?: InputVariantType;
|
|
187
|
+
|
|
174
188
|
/**
|
|
175
189
|
* Descriptive text displayed below the label and above the input. Unlike the hint it is always
|
|
176
190
|
* visible, and it is linked to the input via `aria-describedby` (after any
|
|
@@ -53,6 +53,7 @@
|
|
|
53
53
|
:readonly="readonly"
|
|
54
54
|
:required="required"
|
|
55
55
|
:rows="rows"
|
|
56
|
+
:variant="variant"
|
|
56
57
|
v-bind="eventListeners"
|
|
57
58
|
>
|
|
58
59
|
<template #append-outer><slot name="append-outer" /></template>
|
|
@@ -132,6 +133,7 @@ const eventListeners = {
|
|
|
132
133
|
## Types
|
|
133
134
|
|
|
134
135
|
```ts
|
|
136
|
+
import type { InputVariantType } from '@/types/InputVariant';
|
|
135
137
|
import type { HTMLAttributes, InputHTMLAttributes } from 'vue';
|
|
136
138
|
import type { InputDirection } from '@/types/InputDirection';
|
|
137
139
|
import type { IconType } from '@/types/Icon';
|
|
@@ -172,6 +174,18 @@ export type BbTextareaProps = {
|
|
|
172
174
|
*/
|
|
173
175
|
compact?: boolean;
|
|
174
176
|
|
|
177
|
+
/**
|
|
178
|
+
* Visual variant of the field box — the same names and tokens as the
|
|
179
|
+
* `BbButton` variants. Colours only: height, padding and border width are
|
|
180
|
+
* identical across variants, so a form never reflows when one changes.
|
|
181
|
+
* `'ghost'` has no border in any state (errors and warnings show through
|
|
182
|
+
* the icon and the messages); every variant keeps the focus ring.
|
|
183
|
+
* Register extra names with the plugin's `inputVariants` option.
|
|
184
|
+
*
|
|
185
|
+
* @defaultValue `'outline'`
|
|
186
|
+
*/
|
|
187
|
+
variant?: InputVariantType;
|
|
188
|
+
|
|
175
189
|
/**
|
|
176
190
|
* Descriptive text displayed below the label and above the input. Unlike the hint it is always
|
|
177
191
|
* visible, and it is linked to the input via `aria-describedby` (after any
|
|
@@ -57,6 +57,7 @@
|
|
|
57
57
|
:seconds="seconds"
|
|
58
58
|
:step="step"
|
|
59
59
|
:transition-duration="transitionDuration"
|
|
60
|
+
:variant="variant"
|
|
60
61
|
v-bind="eventListeners"
|
|
61
62
|
>
|
|
62
63
|
<template #prepend-outer><slot name="prepend-outer"></slot></template>
|
|
@@ -136,6 +137,7 @@ const eventListeners = {
|
|
|
136
137
|
## Types
|
|
137
138
|
|
|
138
139
|
```ts
|
|
140
|
+
import type { InputVariantType } from '@/types/InputVariant';
|
|
139
141
|
import type { HTMLAttributes, InputHTMLAttributes } from 'vue';
|
|
140
142
|
import type { InputDirection } from '@/types/InputDirection';
|
|
141
143
|
import type { IconType } from '@/types/Icon';
|
|
@@ -184,6 +186,18 @@ export type BbTimePickerInputProps = {
|
|
|
184
186
|
/** Sets the component in a compact state. */
|
|
185
187
|
compact?: boolean;
|
|
186
188
|
|
|
189
|
+
/**
|
|
190
|
+
* Visual variant of the field box — the same names and tokens as the
|
|
191
|
+
* `BbButton` variants. Colours only: height, padding and border width are
|
|
192
|
+
* identical across variants, so a form never reflows when one changes.
|
|
193
|
+
* `'ghost'` has no border in any state (errors and warnings show through
|
|
194
|
+
* the icon and the messages); every variant keeps the focus ring.
|
|
195
|
+
* Register extra names with the plugin's `inputVariants` option.
|
|
196
|
+
*
|
|
197
|
+
* @defaultValue `'outline'`
|
|
198
|
+
*/
|
|
199
|
+
variant?: InputVariantType;
|
|
200
|
+
|
|
187
201
|
/**
|
|
188
202
|
* Descriptive text displayed below the label and above the input. Always
|
|
189
203
|
* visible and linked to the input via `aria-describedby` (after any
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
```vue
|
|
8
8
|
<template>
|
|
9
|
-
<span v-if="resolvedDescription" :id="descId" class="sr-only">{{
|
|
9
|
+
<span v-if="resolvedDescription" :id="descId" class="bb-sr-only">{{
|
|
10
10
|
resolvedDescription
|
|
11
11
|
}}</span>
|
|
12
12
|
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
:id="id"
|
|
49
49
|
class="bb-tooltip__content"
|
|
50
50
|
role="tooltip"
|
|
51
|
-
:style="{
|
|
51
|
+
:style="{ '--max-w': parsedWidth }"
|
|
52
52
|
>
|
|
53
53
|
<slot>{{ text }}</slot>
|
|
54
54
|
</span>
|
|
@@ -73,7 +73,6 @@ import { warnRemovedAttrs } from '@/utilities/functions/warnRemovedAttrs';
|
|
|
73
73
|
import CommonPopover from '../CommonPopover/CommonPopover.vue';
|
|
74
74
|
import { useElementSize } from '@vueuse/core';
|
|
75
75
|
import { extractDomContainer } from '@/utilities/functions/extractDomContainer';
|
|
76
|
-
import { parseWidthString } from '@/utilities/functions/parseWidthString';
|
|
77
76
|
import type { BbTooltipProps, BbTooltipSlots } from './types';
|
|
78
77
|
import { transitions } from '@/utilities/misc/transitions';
|
|
79
78
|
export type { BbTooltipProps, BbTooltipSlots };
|
|
@@ -338,10 +337,14 @@ onBeforeUnmount(() => {
|
|
|
338
337
|
document.removeEventListener('keydown', onEsc);
|
|
339
338
|
});
|
|
340
339
|
|
|
340
|
+
/** A bare number, or a number written as a string — both mean pixels. */
|
|
341
|
+
const bareNumberPattern = /^-?\d*\.?\d+$/;
|
|
342
|
+
const percentPattern = /^(-?\d*\.?\d+)%$/;
|
|
343
|
+
|
|
341
344
|
const percentWidth = computed(() => {
|
|
342
|
-
if (
|
|
343
|
-
const
|
|
344
|
-
return
|
|
345
|
+
if (typeof props.width !== 'string') return undefined;
|
|
346
|
+
const match = props.width.trim().match(percentPattern);
|
|
347
|
+
return match ? parseFloat(match[1]) : undefined;
|
|
345
348
|
});
|
|
346
349
|
|
|
347
350
|
// Only `%` widths need the activator measured — skip the ResizeObserver for
|
|
@@ -353,13 +356,29 @@ const { width: activatorWidth } = useElementSize(
|
|
|
353
356
|
box: 'border-box',
|
|
354
357
|
}
|
|
355
358
|
);
|
|
359
|
+
|
|
360
|
+
/**
|
|
361
|
+
* `width` resolved to the `--max-w` cap. `undefined` leaves the stylesheet's
|
|
362
|
+
* default measure in place, which is also what an unmeasured percentage falls
|
|
363
|
+
* back to — a `0px` cap would collapse the bubble on the first frame.
|
|
364
|
+
*
|
|
365
|
+
* A percentage is resolved here against the activator, because CSS would
|
|
366
|
+
* resolve it against the bubble's own containing block (the viewport) instead.
|
|
367
|
+
* Every other value is handed to CSS verbatim, so `calc()`, `min()` and the
|
|
368
|
+
* width keywords work and a typo styles nothing rather than throwing during
|
|
369
|
+
* render.
|
|
370
|
+
*/
|
|
356
371
|
const parsedWidth = computed(() => {
|
|
357
|
-
if (
|
|
372
|
+
if (props.width == null || props.width === '') return undefined;
|
|
358
373
|
if (percentWidth.value != null) {
|
|
359
|
-
if (!
|
|
374
|
+
if (!activatorWidth.value) return undefined;
|
|
360
375
|
return `${activatorWidth.value * (percentWidth.value / 100)}px`;
|
|
361
376
|
}
|
|
362
|
-
|
|
377
|
+
if (typeof props.width === 'number') {
|
|
378
|
+
return Number.isFinite(props.width) ? `${props.width}px` : undefined;
|
|
379
|
+
}
|
|
380
|
+
const raw = props.width.trim();
|
|
381
|
+
return bareNumberPattern.test(raw) ? `${raw}px` : raw;
|
|
363
382
|
});
|
|
364
383
|
</script>
|
|
365
384
|
|
|
@@ -466,7 +485,14 @@ export type BbTooltipProps = {
|
|
|
466
485
|
*/
|
|
467
486
|
delay?: number;
|
|
468
487
|
/**
|
|
469
|
-
*
|
|
488
|
+
* Caps the width of the tooltip bubble: it wraps at this measure but still
|
|
489
|
+
* shrinks to its text, so a short hint never sits in an oversized bubble.
|
|
490
|
+
* A bare number is read as pixels, a percentage is measured against the
|
|
491
|
+
* activator, and any other CSS length (`'20rem'`, `'min(320px, 90vw)'`)
|
|
492
|
+
* is passed through.
|
|
493
|
+
*
|
|
494
|
+
* Replaces the default cap of `40ch`, which is also reachable in CSS as
|
|
495
|
+
* `--max-w` on the tooltip root.
|
|
470
496
|
*/
|
|
471
497
|
width?: number | string;
|
|
472
498
|
};
|
|
@@ -524,6 +550,16 @@ export type BbTooltipSlots = {
|
|
|
524
550
|
--fg: var(--bb-primary-fg);
|
|
525
551
|
--border-color: var(--bb-primary);
|
|
526
552
|
--fs: calc(var(--bb-fs) - 2px);
|
|
553
|
+
/*
|
|
554
|
+
* Default measure. CommonPopover caps the bubble at the viewport minus its
|
|
555
|
+
* `padding`, which on a wide screen is a single line running the width of
|
|
556
|
+
* the page — unreadable, and the reason a hint needs a cap of its own.
|
|
557
|
+
* `ch` (not px) so the column tracks the font: the same 40ch measure the
|
|
558
|
+
* dropdown item description uses. The `width` prop overrides it by writing
|
|
559
|
+
* `--max-w` inline on the content; a consumer can override it in CSS on
|
|
560
|
+
* this root.
|
|
561
|
+
*/
|
|
562
|
+
--max-w: 40ch;
|
|
527
563
|
--px: 12px;
|
|
528
564
|
--py: 6px;
|
|
529
565
|
|
|
@@ -553,6 +589,17 @@ export type BbTooltipSlots = {
|
|
|
553
589
|
display: inline-flex;
|
|
554
590
|
font-size: var(--fs);
|
|
555
591
|
line-height: 1.4;
|
|
592
|
+
max-width: var(--max-w);
|
|
593
|
+
/* A capped bubble has to break what it cannot wrap: the hint a tooltip
|
|
594
|
+
most often carries is a file path or a URL, and a token longer than
|
|
595
|
+
the cap would otherwise run straight out of the painted bubble.
|
|
596
|
+
`anywhere`, not `break-word`: the text sits in an anonymous flex item
|
|
597
|
+
whose automatic minimum size is its min-content width, and only
|
|
598
|
+
`anywhere` lets a break point count toward min-content — under
|
|
599
|
+
`break-word` the item stays as wide as the longest token and
|
|
600
|
+
overflows the cap anyway. Max-content is untouched either way, so
|
|
601
|
+
ordinary prose still shrink-wraps to its natural width. */
|
|
602
|
+
overflow-wrap: anywhere;
|
|
556
603
|
padding: var(--py) var(--px);
|
|
557
604
|
}
|
|
558
605
|
}
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
widget role the input owns or controls, and the only fitting one,
|
|
35
35
|
`role="option"`, has children-presentational semantics — it would erase each
|
|
36
36
|
chip's ✕ button, a real tab stop, from the accessibility tree. -->
|
|
37
|
-
<span class="sr-only" role="status">{{ highlightAnnouncement }}</span>
|
|
37
|
+
<span class="bb-sr-only" role="status">{{ highlightAnnouncement }}</span>
|
|
38
38
|
</template>
|
|
39
39
|
|
|
40
40
|
<script setup lang="ts">
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
the only signal a highlight moved. This polite status node — mounted empty,
|
|
23
23
|
because a live region added together with its content does not announce —
|
|
24
24
|
says which item the cursor is on. -->
|
|
25
|
-
<span class="sr-only" role="status">{{ highlightAnnouncement }}</span>
|
|
25
|
+
<span class="bb-sr-only" role="status">{{ highlightAnnouncement }}</span>
|
|
26
26
|
</template>
|
|
27
27
|
|
|
28
28
|
<script setup lang="ts">
|