bitboss-ui 3.0.0-beta.26 → 3.0.0-beta.28

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (122) hide show
  1. package/bin/bitboss-ui-mcp.mjs +1 -1
  2. package/dist/ai/BbColorInput.md +5 -4
  3. package/dist/ai/BbColorPalette.md +8 -5
  4. package/dist/ai/BbConfirm.md +16 -3
  5. package/dist/ai/BbDatePicker.md +24 -12
  6. package/dist/ai/BbDatePickerInput.md +16 -7
  7. package/dist/ai/BbDropdownButton.md +5 -2
  8. package/dist/ai/BbPtScope.md +136 -0
  9. package/dist/ai/BbSelect.md +10 -4
  10. package/dist/ai/BbSelectPopover.md +9 -8
  11. package/dist/ai/BbTag.md +0 -2
  12. package/dist/ai/BbTextInput.md +6 -2
  13. package/dist/ai/BbTimePicker.md +14 -5
  14. package/dist/ai/BbTimePickerInput.md +14 -4
  15. package/dist/ai/BbToast.md +10 -2
  16. package/dist/ai/changelog.json +63 -5
  17. package/dist/ai/components.json +347 -61
  18. package/dist/ai/guides/agent-contract.md +14 -3
  19. package/dist/ai/guides/app-layout.md +3 -1
  20. package/dist/ai/guides/design-language.md +10 -6
  21. package/dist/ai/guides/design-tokens.md +2 -1
  22. package/dist/ai/guides/installation-and-plugin-setup.md +27 -5
  23. package/dist/ai/guides/migration/components/bb-color-palette.md +9 -9
  24. package/dist/ai/guides/migration/v2-to-v3.md +62 -58
  25. package/dist/ai/guides/passthrough.md +182 -73
  26. package/dist/ai/index.md +1 -0
  27. package/dist/ai/source/BbCheckbox.md +4 -4
  28. package/dist/ai/source/BbColorInput.md +6 -4
  29. package/dist/ai/source/BbColorPalette.md +234 -183
  30. package/dist/ai/source/BbConfirm.md +9 -2
  31. package/dist/ai/source/BbConfirmPortal.md +7 -0
  32. package/dist/ai/source/BbDatePicker.md +406 -325
  33. package/dist/ai/source/BbDatePickerInput.md +12 -13
  34. package/dist/ai/source/BbDialog.md +7 -0
  35. package/dist/ai/source/BbDropdown.md +9 -0
  36. package/dist/ai/source/BbDropdownButton.md +45 -9
  37. package/dist/ai/source/BbOffCanvas.md +7 -0
  38. package/dist/ai/source/BbPopover.md +7 -0
  39. package/dist/ai/source/BbPtScope.md +54 -0
  40. package/dist/ai/source/BbRadio.md +4 -4
  41. package/dist/ai/source/BbSelect.md +8 -4
  42. package/dist/ai/source/BbSelectPopover.md +47 -12
  43. package/dist/ai/source/BbSlider.md +19 -2
  44. package/dist/ai/source/BbSwitch.md +4 -4
  45. package/dist/ai/source/BbTable.md +49 -2
  46. package/dist/ai/source/BbTag.md +19 -15
  47. package/dist/ai/source/BbTimePicker.md +132 -46
  48. package/dist/ai/source/BbTimePickerInput.md +61 -34
  49. package/dist/ai/source/BbToast.md +1 -1
  50. package/dist/ai/source/BbTooltip.md +7 -0
  51. package/dist/ai/source/CommonField.md +6 -2
  52. package/dist/ai/source/CommonTimeSelector.md +6 -1
  53. package/dist/components/BbColorInput/BbColorInput.vue_vue_type_script_setup_true_lang.js +8 -0
  54. package/dist/components/BbColorInput/types.d.ts +5 -4
  55. package/dist/components/BbColorInput/types.js +1 -0
  56. package/dist/components/BbColorPalette/BbColorPalette.vue_vue_type_script_setup_true_lang.js +253 -244
  57. package/dist/components/BbColorPalette/types.d.ts +3 -3
  58. package/dist/components/BbColorPalette/types.js +1 -0
  59. package/dist/components/BbConfirm/BbConfirm.vue_vue_type_script_setup_true_lang.js +4 -3
  60. package/dist/components/BbConfirm/types.d.ts +7 -0
  61. package/dist/components/BbDatePicker/BbDatePicker.vue_vue_type_script_setup_true_lang.js +252 -232
  62. package/dist/components/BbDatePicker/DatePickerYearPanel.vue_vue_type_script_setup_true_lang.js +1 -0
  63. package/dist/components/BbDatePicker/types.d.ts +10 -4
  64. package/dist/components/BbDatePicker/types.js +1 -0
  65. package/dist/components/BbDatePickerInput/BbDatePickerInput.vue_vue_type_script_setup_true_lang.js +297 -296
  66. package/dist/components/BbDatePickerInput/types.d.ts +5 -2
  67. package/dist/components/BbDialog/BbDialog.vue_vue_type_script_setup_true_lang.js +120 -120
  68. package/dist/components/BbDropdown/BbDropdown.vue_vue_type_script_setup_true_lang.js +115 -113
  69. package/dist/components/BbDropdownButton/BbDropdownButton.vue_vue_type_script_setup_true_lang.js +4 -0
  70. package/dist/components/BbDropdownButton/types.d.ts +31 -9
  71. package/dist/components/BbDropdownButton/types.js +9 -1
  72. package/dist/components/BbOffCanvas/BbOffCanvas.vue_vue_type_script_setup_true_lang.js +116 -116
  73. package/dist/components/BbPopover/BbPopover.vue_vue_type_script_setup_true_lang.js +146 -146
  74. package/dist/components/BbPtScope/BbPtScope.vue.d.ts +12 -0
  75. package/dist/components/BbPtScope/BbPtScope.vue.js +5 -0
  76. package/dist/components/BbPtScope/BbPtScope.vue_vue_type_script_setup_true_lang.js +13 -0
  77. package/dist/components/BbPtScope/types.d.ts +15 -0
  78. package/dist/components/BbSelect/BbSelect.vue_vue_type_script_setup_true_lang.js +124 -123
  79. package/dist/components/BbSelect/types.d.ts +1 -1
  80. package/dist/components/BbSelectPopover/BbSelectPopover.vue_vue_type_script_setup_true_lang.js +151 -143
  81. package/dist/components/BbSelectPopover/types.d.ts +3 -3
  82. package/dist/components/BbSelectPopover/types.js +1 -0
  83. package/dist/components/BbSlider/BbSlider.vue_vue_type_script_setup_true_lang.js +180 -180
  84. package/dist/components/BbTable/BbTable.vue_vue_type_script_setup_true_lang.js +814 -800
  85. package/dist/components/BbTag/BbTag.vue_vue_type_script_setup_true_lang.js +145 -145
  86. package/dist/components/BbTimePicker/BbTimePicker.vue_vue_type_script_setup_true_lang.js +134 -121
  87. package/dist/components/BbTimePicker/types.d.ts +10 -4
  88. package/dist/components/BbTimePicker/types.js +1 -0
  89. package/dist/components/BbTimePickerInput/BbTimePickerInput.vue_vue_type_script_setup_true_lang.js +249 -243
  90. package/dist/components/BbTimePickerInput/types.d.ts +6 -3
  91. package/dist/components/BbToast/BbToast.vue_vue_type_script_setup_true_lang.js +1 -1
  92. package/dist/components/BbTooltip/BbTooltip.vue_vue_type_script_setup_true_lang.js +40 -40
  93. package/dist/components/CommonField/CommonField.vue_vue_type_script_setup_true_lang.js +32 -32
  94. package/dist/components/CommonTimeSelector/CommonTimeSelector.vue_vue_type_script_setup_true_lang.js +2 -1
  95. package/dist/composables/useConfirm.d.ts +11 -2
  96. package/dist/composables/useConfirm.js +1 -1
  97. package/dist/composables/usePassthrough.d.ts +27 -1
  98. package/dist/composables/usePassthrough.js +111 -92
  99. package/dist/composables/useToast.d.ts +2 -1
  100. package/dist/composables/useToast.js +1 -1
  101. package/dist/directives/createPopoverDirective.js +68 -53
  102. package/dist/index.d.ts +4 -0
  103. package/dist/index.js +24 -23
  104. package/dist/llms-full.txt +589 -216
  105. package/dist/llms-medium.txt +52 -14
  106. package/dist/nuxt-auto-imports.js +1 -1
  107. package/dist/nuxt-module.d.ts +2 -0
  108. package/dist/nuxt.js +12 -12
  109. package/dist/pt-scope-registry.d.ts +15 -0
  110. package/dist/styles.css +1 -1
  111. package/dist/types/PtScope.d.ts +13 -0
  112. package/dist/types/passthrough.d.ts +19 -0
  113. package/dist/types/ptComponentMap.d.ts +59 -0
  114. package/dist/utils/passthrough.d.ts +12 -4
  115. package/dist/utils/passthrough.js +28 -19
  116. package/dist/utils/ptScope.d.ts +8 -0
  117. package/dist/utils/ptScope.js +4 -0
  118. package/dist/validated/BbColorInput.vue_vue_type_script_setup_true_lang.js +7 -0
  119. package/dist/validated/index.d.ts +1 -0
  120. package/dist/vite-plugin.d.ts +38 -6
  121. package/dist/vite.js +270 -263
  122. package/package.json +1 -1
@@ -937,7 +937,7 @@ function buildServer() {
937
937
  .boolean()
938
938
  .optional()
939
939
  .describe(
940
- 'Include reference-only internal components (BbBase*, Common*). Default false — these are not consumer API and should not be recommended.'
940
+ 'Include reference-only internal components (Common*, listbox internals). Default false — these are not consumer API and should not be recommended. BbBaseButton and the BbBase*Icon glyphs are consumer API and are always included.'
941
941
  ),
942
942
  },
943
943
  },
@@ -14,6 +14,7 @@
14
14
 
15
15
  | pt part | Lands on | In |
16
16
  | --- | --- | --- |
17
+ | `pt:panel` | `pt:panel` of `BbColorPalette` | `BbColorPalette` ([contract](./BbColorPalette.md)) |
17
18
  | `pt:sheet` | `pt:sheet` of `BbColorPalette` | `BbColorPalette` ([contract](./BbColorPalette.md)) |
18
19
  | `pt:swatch` | `pt:swatch` of `BbColorPalette` | `BbColorPalette` ([contract](./BbColorPalette.md)) |
19
20
  | `pt:root` | `div.bb-field` | `CommonField` _(internal)_ |
@@ -504,7 +505,7 @@ the `BbTextInput` guide.
504
505
 
505
506
  `pt` reaches a named part of the control with a class list — or, in the
506
507
  object form, a style and attributes — optionally only while a state is on.
507
- Parts: `root` (the container), `label`, `description`, `message` (the errors / warnings region — one node each, only one ever shows), `hint` (the helper line — shown on focus, or always with `persistent-hint`), `box` (the bordered field box), `input` (the native control), `icon` (`prepend:icon` + `append:icon` — a broadcast; the state glyphs are chrome), `spinner` (the spinner shown while `loading`), `prefix`, `suffix`, `clear` (the ✕ that empties the field). Plus `indicator` (the colour dot that opens the palette), `sheet` (the bottom sheet the color palette opens in on a phone — no node on desktop) and `swatch` (one palette swatch, after the `swatches` prop — a broadcast).
508
+ Parts: `root` (the container), `label`, `description`, `message` (the errors / warnings region — one node each, only one ever shows), `hint` (the helper line — shown on focus, or always with `persistent-hint`), `box` (the bordered field box), `input` (the native control), `icon` (`prepend:icon` + `append:icon` — a broadcast; the state glyphs are chrome), `spinner` (the spinner shown while `loading`), `prefix`, `suffix`, `clear` (the ✕ that empties the field). Plus `indicator` (the colour dot that opens the palette), `panel` (the palette box — the popover's painted bubble on desktop, the box inside the sheet on a phone), `sheet` (the bottom sheet the color palette opens in on a phone — no node on desktop) and `swatch` (one palette swatch, after the `swatches` prop — a broadcast).
508
509
  States: `errors`, `warnings` (never beside errors), `loading`, `disabled`, `readonly`, `has-value` (written `pt:box:has-value`), on every part; plus `selected` on `swatch` only — the swatch matching the value (`pt:swatch:selected`). A name outside that list is a type error and an
509
510
  ESLint error.
510
511
 
@@ -663,7 +664,7 @@ of it. The full grammar, the merge rules and the global map are in the
663
664
 
664
665
  | Prop | Type | Default | Required | Description |
665
666
  | --- | --- | --- | --- | --- |
666
- | `pt:<part>`, `pt:<part>:<state>`, `pt` | `PtValue` | | | Passthrough — a class list, or `{ class, style, attrs }`, bound to one named part of the component; the state form applies only while that state is on. Parts: `box`, `clear`, `description`, `hint`, `icon`, `indicator`, `input`, `label`, `message`, `prefix`, `root`, `sheet`, `spinner`, `suffix`, `swatch`. States: `disabled`, `errors`, `has-value`, `loading`, `readonly`, `warnings`, `selected`. `pt` is the object form with the same keys minus the prefix (`{ icon: '…', 'icon:loading': '…' }`). See `guides/passthrough.md`. |
667
+ | `pt:<part>`, `pt:<part>:<state>`, `pt` | `PtValue` | | | Passthrough — a class list, or `{ class, style, attrs }`, bound to one named part of the component; the state form applies only while that state is on. Parts: `box`, `clear`, `description`, `hint`, `icon`, `indicator`, `input`, `label`, `message`, `panel`, `prefix`, `root`, `sheet`, `spinner`, `suffix`, `swatch`. States: `disabled`, `errors`, `has-value`, `loading`, `readonly`, `warnings`, `selected`. `pt` is the object form with the same keys minus the prefix (`{ icon: '…', 'icon:loading': '…' }`). See `guides/passthrough.md`. |
667
668
  | `adaptive` | `boolean \| undefined` | ``config.adaptive` (`true`)` | | When `true`, the color palette opens as a bottom off-canvas sheet on mobile viewports instead of a floating popover; on desktop it stays a popover. Mirrors the adaptive behaviour of `BbSelect`/`BbDatePickerInput`. When unset, falls back to … |
668
669
  | `alpha` | `boolean \| undefined` | `false` | | Enable the alpha channel. Shows an opacity slider and uses `#RRGGBBAA` hex8 format. |
669
670
  | `append:icon` | `string \| undefined` | | | Name of the icon to be added at the end of the input. |
@@ -757,10 +758,10 @@ Set these on the element, or on a class you put on it, to retune this component
757
758
  - **CSS custom properties** listed on a node are declared on THAT node's root and read by elements inside it. Set one on that node's root or on the element inside it that reads it — the pt part that lands there is how you reach it (`pt:box="[--border-color:…]"` on a text input) — never on `BbColorInput`'s root, where the node's own declaration masks it (design-tokens guide, _Overriding one from a consumer app_, rule 0).
758
759
  - Listed nodes are the ones `BbColorInput`'s API reaches or that declare a documented CSS variable; the rest fold into "also mounts". The complete tree, repeats and undocumented locals included, is the `tree` field of this component in `components.json`.
759
760
 
760
- - `BbColorInput` _(this component)_ — its own template binds: `controlAttrs` → `input.bb-color-input__input`, `input` → `input.bb-color-input__input`, `indicator` → `button.bb-color-input__indicator`, `suffix` → `span.bb-field-input__suffix`; hands `BbColorPalette` the pt map `{ sheet: 'sheet', swatch: 'swatch' }` (ours → theirs)
761
+ - `BbColorInput` _(this component)_ — its own template binds: `controlAttrs` → `input.bb-color-input__input`, `input` → `input.bb-color-input__input`, `indicator` → `button.bb-color-input__indicator`, `suffix` → `span.bb-field-input__suffix`; hands `BbColorPalette` the pt map `{ panel: 'panel', sheet: 'sheet', swatch: 'swatch' }` (ours → theirs)
761
762
  - `CommonField` _(internal — not importable, reach it through `BbColorInput`)_ — `BbColorInput`'s pt parts land here: `root` → `div.bb-field`, `label` → `component`, `description` → `span.bb-field__description`, `hint` → `span.bb-field__hint-text`, `message` → `div.bb-field__errors`, `message` → `div.bb-field__warnings`
762
763
  - `CommonFieldInput` _(internal — not importable, reach it through `BbColorInput`)_ — `BbColorInput`'s pt parts land here: `box` → `span.bb-field-input__box`, `prefix` → `span.bb-field-input__prefix`, `icon` → `BbIcon`, `clear` → `ClearableButton`, `spinner` → `BbSpinner`, `suffix` → `span.bb-field-input__suffix`; documented CSS variables: `--bg`, `--bg-hover`, `--bg-focus`, `--bg-disabled`, `--border-color`, `--border-focus`, `--ring-size`, `--ring-color`, `--elev`, `--frost`, `--inside-label-clearance`; also mounts `ErrorIcon`, `WarningIcon`, `ClearableButton`, `BbIcon`, `BbSpinner`
763
- - `BbColorPalette` _(public — [contract](./BbColorPalette.md))_ — its own pt parts (`BbColorPalette`): `root` → `div.bb-color-palette__picker`, `swatch` → `button.bb-color-palette__swatch`; hands `BbOffCanvas` the pt map `{ sheet: 'root' }` (ours → theirs); also mounts `CommonPopover`
764
+ - `BbColorPalette` _(public — [contract](./BbColorPalette.md))_ — its own pt parts (`BbColorPalette`): `swatch` → `button.bb-color-palette__swatch`, `panel` → `div`, `panel` → `CommonPopover`; hands `BbOffCanvas` the pt map `{ sheet: 'root' }` (ours → theirs); also mounts `CommonPopover`
764
765
  - `BbOffCanvas` _(public — [contract](./BbOffCanvas.md))_ — its own pt parts (`BbOffCanvas`): `header` → `div.bb-offcanvas__header`, `title` → `span.bb-offcanvas__title`, `description` → `p.bb-offcanvas__description`, `close` → `CloseButton`, `content` → `div.bb-offcanvas__body`, `footer` → `div.bb-offcanvas__footer`; documented CSS variables: `--stack-x`, `--stack-fill`, `--stack-transition-duration`, `--px`, `--close-size`
765
766
  - `CloseButton` _(internal — not importable, reach it through `BbOffCanvas`)_ — documented CSS variables: `--size`, `--p`
766
767
 
@@ -14,6 +14,7 @@
14
14
 
15
15
  | pt part | Lands on | In |
16
16
  | --- | --- | --- |
17
+ | `pt:panel` | the root of `CommonPopover` | `CommonPopover` _(internal)_ |
17
18
  | `pt:sheet` | `pt:root` of `BbOffCanvas` | `BbOffCanvas` ([contract](./BbOffCanvas.md)) |
18
19
 
19
20
  ## Usage & Guidelines
@@ -556,9 +557,11 @@ styling (a caret, a highlight). Two props gate interaction:
556
557
 
557
558
  `pt` reaches a named part with a class list — or, in the object form, a
558
559
  style and attributes — optionally only while a state is on. Parts: `root`
559
- (the palette — canvas, sliders, swatches; the same node in the popover and in
560
- the sheet), `sheet` (the bottom sheet around it on a phone — no node on
561
- desktop) and `swatch` (one swatch, named after the `swatches` prop — a
560
+ (the floating element — the bottom sheet on a phone), `panel` (the palette box you
561
+ see: the popover's painted bubble on desktop, the box inside the sheet on a
562
+ phone — canvas, sliders, swatches; `pt:panel="px-1"`
563
+ tightens its padding), `sheet` (the bottom sheet on a phone only, applied
564
+ after `root`) and `swatch` (one swatch, named after the `swatches` prop — a
562
565
  broadcast). States: `open`, and
563
566
  `selected` per swatch (the one matching the value). The canvas and the sliders
564
567
  are not parts.
@@ -733,7 +736,7 @@ The full grammar, the merge rules and the global map are in the
733
736
 
734
737
  | Prop | Type | Default | Required | Description |
735
738
  | --- | --- | --- | --- | --- |
736
- | `pt:<part>`, `pt:<part>:<state>`, `pt` | `PtValue` | | | Passthrough — a class list, or `{ class, style, attrs }`, bound to one named part of the component; the state form applies only while that state is on. Parts: `root`, `sheet`, `swatch`. States: `open`, `selected`. `pt` is the object form with the same keys minus the prefix (`{ icon: '…', 'icon:loading': '…' }`). See `guides/passthrough.md`. |
739
+ | `pt:<part>`, `pt:<part>:<state>`, `pt` | `PtValue` | | | Passthrough — a class list, or `{ class, style, attrs }`, bound to one named part of the component; the state form applies only while that state is on. Parts: `panel`, `root`, `sheet`, `swatch`. States: `open`, `selected`. `pt` is the object form with the same keys minus the prefix (`{ icon: '…', 'icon:loading': '…' }`). See `guides/passthrough.md`. |
737
740
  | `activator` | `ElementOrComponentRef \| undefined` | | | External activator element or component ref. When provided, the `activator` slot is not rendered and click listeners are attached programmatically to the referenced element — mirroring the BbDropdown activator API. |
738
741
  | `adaptive` | `boolean \| undefined` | ``config.adaptive` (`true`)` | | When `true`, the palette opens as a bottom off-canvas sheet on mobile viewports instead of a floating popover; on desktop it stays a popover. Mirrors the adaptive behaviour of `BbPopover`/`BbDropdown`/`BbDatePicker`. When unset, falls back … |
739
742
  | `alpha` | `boolean \| undefined` | `false` | | Enable the alpha channel. The picker shows an opacity slider and emits `#RRGGBBAA` hex8 values. |
@@ -774,7 +777,7 @@ The full grammar, the merge rules and the global map are in the
774
777
  - **CSS custom properties** listed on a node are declared on THAT node's root and read by elements inside it. Set one on that node's root or on the element inside it that reads it — the pt part that lands there is how you reach it (`pt:box="[--border-color:…]"` on a text input) — never on `BbColorPalette`'s root, where the node's own declaration masks it (design-tokens guide, _Overriding one from a consumer app_, rule 0).
775
778
  - Listed nodes are the ones `BbColorPalette`'s API reaches or that declare a documented CSS variable; the rest fold into "also mounts". The complete tree, repeats and undocumented locals included, is the `tree` field of this component in `components.json`.
776
779
 
777
- - `BbColorPalette` _(this component)_ — its own template binds: `root` → `div.bb-color-palette__picker`, `swatch` → `button.bb-color-palette__swatch`; hands `BbOffCanvas` the pt map `{ sheet: 'root' }` (ours → theirs)
780
+ - `BbColorPalette` _(this component)_ — its own template binds: `swatch` → `button.bb-color-palette__swatch`, `panel` → `div`, `panel` → `CommonPopover`; hands `BbOffCanvas` the pt map `{ sheet: 'root' }` (ours → theirs)
778
781
  - `BbOffCanvas` _(public — [contract](./BbOffCanvas.md))_ — its own pt parts (`BbOffCanvas`): `header` → `div.bb-offcanvas__header`, `title` → `span.bb-offcanvas__title`, `description` → `p.bb-offcanvas__description`, `close` → `CloseButton`, `content` → `div.bb-offcanvas__body`, `footer` → `div.bb-offcanvas__footer`; documented CSS variables: `--stack-x`, `--stack-fill`, `--stack-transition-duration`, `--px`, `--close-size`
779
782
  - `CloseButton` _(internal — not importable, reach it through `BbOffCanvas`)_ — documented CSS variables: `--size`, `--p`
780
783
  - Also mounts `CommonPopover`
@@ -72,6 +72,13 @@ Mounting a second host renders every dialog twice
72
72
  (nothing warns you). Mounting none is worse: `await confirm(...)` never settles
73
73
  and the caller hangs.
74
74
 
75
+ **Areas with their own look.** The dialog takes the passthrough scope and the
76
+ tokens of the place its HOST is mounted. When the app is split into areas that
77
+ each wrap their pages in `<BbPtScope>` ([passthrough guide](./guides/passthrough.md) § Named scopes),
78
+ mount one `<BbConfirm />` inside each area's layout, within its scope, and none
79
+ at the app root — which holds only if **every** page renders inside exactly one
80
+ of those layouts, so there is still one host at a time.
81
+
75
82
  ```vue
76
83
  <template>
77
84
  <RouterView />
@@ -87,9 +94,12 @@ import { BbConfirm } from 'bitboss-ui';
87
94
  standalone example has no app root to mount it in.** In a real app the host is
88
95
  already mounted at the root; a page that calls `confirm()` mounts nothing.
89
96
 
90
- The component itself takes no props: everything — content, buttons, size,
91
- behavior — travels in the message you pass to `confirm()`. At least one of
92
- `title`, `text`, `portal` should be set (dev warning otherwise).
97
+ The component itself takes almost no props: everything — content, buttons,
98
+ behavior — travels in the message you pass to `confirm()`. The one exception is
99
+ `size`, a host-wide default width every confirm inherits unless its message
100
+ sets its own (see [Size, fullscreen and focus](#size-fullscreen-and-focus)).
101
+ At least one of `title`, `text`, `portal` should be set (dev warning
102
+ otherwise).
93
103
 
94
104
  ### The destructive flow
95
105
 
@@ -636,6 +646,8 @@ standard footer and resolve from inside the slot with its `yes` / `no` helpers.
636
646
 
637
647
  - `size` picks a maximum-width preset (`'xs'` … `'2xl'`, resolvable through
638
648
  the plugin config's `dialogDefaultSizes`); default confirms are compact.
649
+ To widen every confirm at once, set the same `size` on the host instead —
650
+ `<BbConfirm size="lg" />` — and let individual messages override it.
639
651
  - `fullscreen: true` takes over the whole screen; `fullscreen: 'mobile'`
640
652
  restricts that to small viewports.
641
653
  - `focusTarget` is a CSS selector focused after opening (default: the first
@@ -768,6 +780,7 @@ The full grammar, the merge rules and the global map are in the
768
780
  | Prop | Type | Default | Required | Description |
769
781
  | --- | --- | --- | --- | --- |
770
782
  | `pt:<part>`, `pt:<part>:<state>`, `pt` | `PtValue` | | | Passthrough — a class list, or `{ class, style, attrs }`, bound to one named part of the component; the state form applies only while that state is on. Parts: `action`, `close`, `content`, `footer`, `header`, `root`, `sheet`, `text`, `title`. States: `open`. `pt` is the object form with the same keys minus the prefix (`{ icon: '…', 'icon:loading': '…' }`). See `guides/passthrough.md`. |
783
+ | `size` | `keyof Sizes \| undefined` | | | Default maximum width for every confirm this host renders, as one of the dialog presets (`'xs'` – `'2xl'`). A per-call `size` in the message wins. When neither is set the dialog falls back to the `BbDialog` default. |
771
784
 
772
785
  ## Events
773
786
 
@@ -17,6 +17,7 @@
17
17
  | `pt:arrow` | the root of `BbBaseButton` | `BbBaseButton` ([contract](./BbBaseButton.md)) |
18
18
  | `pt:month` | the root of `BbBaseButton` | `BbBaseButton` ([contract](./BbBaseButton.md)) |
19
19
  | `pt:year` | the root of `BbBaseButton` | `BbBaseButton` ([contract](./BbBaseButton.md)) |
20
+ | `pt:panel` | the root of `CommonPopover` | `CommonPopover` _(internal)_ |
20
21
  | `pt:sheet` | `pt:root` of `BbOffCanvas` | `BbOffCanvas` ([contract](./BbOffCanvas.md)) |
21
22
 
22
23
  ## Usage & Guidelines
@@ -208,6 +209,12 @@ props with `offCanvasProps`). Position the desktop popover with `placement`,
208
209
  `offset`, `padding`, `boundary`, and `disableFlip` — the same knobs as the other
209
210
  overlays. Escape and backdrop clicks close it; focus returns to the activator.
210
211
 
212
+ The sheet can be **dragged down to dismiss** and shows **no ✕** — picking,
213
+ drag, backdrop tap and Escape close it. The time wheels and the year list are
214
+ no-drag zones: a swipe there scrolls the list and never moves the sheet, even at
215
+ its top. `offCanvasProps` is spread over those defaults: `{ hideClose: false }`
216
+ brings the ✕ back, `{ draggable: false }` pins the sheet.
217
+
211
218
  ### The `v-bb-date` directive
212
219
 
213
220
  For the leanest case — a date cell in a table where you don't want a component
@@ -252,8 +259,11 @@ into, `BbDatePickerInput` when there is.
252
259
 
253
260
  `pt` reaches a named part with a class list — or, in the object form, a
254
261
  style and attributes — optionally only while a state is on. Parts: `root`
255
- (the calendar panel, in the popover and in the sheet alike), `sheet` (the
256
- bottom sheet around it on a phone — no node on desktop), `header` (the
262
+ (the floating element — the bottom sheet on a phone), `panel` (the calendar box you
263
+ see: the popover's painted bubble on desktop, the box inside the sheet on a
264
+ phone — it also carries the sizing tokens, so
265
+ `pt:panel="[--pad-x:2px]"` tightens the padding and the grid width follows), `sheet` (the
266
+ bottom sheet on a phone only, applied after `root`), `header` (the
257
267
  navigation bar), `arrow` (the previous / next buttons), `month` and `year`
258
268
  (the heading buttons), `column-header` (each weekday letter), `day` (one whole
259
269
  day cell) and `day-button` (the button inside it), `month-item` and
@@ -355,7 +365,7 @@ and digit typeahead; the time rail exposes labelled columns. Always pass a
355
365
 
356
366
  | Prop | Type | Default | Required | Description |
357
367
  | --- | --- | --- | --- | --- |
358
- | `pt:<part>`, `pt:<part>:<state>`, `pt` | `PtValue` | | | Passthrough — a class list, or `{ class, style, attrs }`, bound to one named part of the component; the state form applies only while that state is on. Parts: `arrow`, `column-header`, `day`, `day-button`, `header`, `month`, `month-item`, `root`, `sheet`, `year`, `year-item`. States: `active`, `disabled`, `highlighted`, `in-range`, `open`, `outside`, `range-end`, `range-start`, `selected`, `today`. `pt` is the object form with the same keys minus the prefix (`{ icon: '…', 'icon:loading': '…' }`). See `guides/passthrough.md`. |
368
+ | `pt:<part>`, `pt:<part>:<state>`, `pt` | `PtValue` | | | Passthrough — a class list, or `{ class, style, attrs }`, bound to one named part of the component; the state form applies only while that state is on. Parts: `arrow`, `column-header`, `day`, `day-button`, `header`, `month`, `month-item`, `panel`, `root`, `sheet`, `year`, `year-item`. States: `active`, `disabled`, `highlighted`, `in-range`, `open`, `outside`, `range-end`, `range-start`, `selected`, `today`. `pt` is the object form with the same keys minus the prefix (`{ icon: '…', 'icon:loading': '…' }`). See `guides/passthrough.md`. |
359
369
  | `activator` | `ElementOrComponentRef \| undefined` | | | External activator element or component ref. When provided, the `activator` slot is not rendered and click + ARIA are attached programmatically to the referenced element — mirroring the `BbColorPalette` activator API. |
360
370
  | `activeSegment` | `BbDatePickerSegment \| undefined` | | | Which end the time rail edits in range + `type="datetime"` (`v-model:active-segment`). Standalone use manages this internally; an embedding host (the date input) drives it from its focused field. Ignored outside range + datetime. |
361
371
  | `adaptive` | `boolean \| undefined` | ``config.adaptive` (`true`)` | | On mobile, open in a bottom off-canvas sheet instead of a floating popover. When unset, falls back to the global `config.adaptive`. |
@@ -372,7 +382,7 @@ and digit typeahead; the time rail exposes labelled columns. Always pass a
372
382
  | `min` | `string \| undefined` | | | Minimum selectable value, in this `type`'s shape — `YYYY-MM-DD` (`YYYY-MM-DDTHH:mm` with `datetime`, `YYYY-MM` with `month`, `YYYY` with `year`). A finer bound is accepted and floored to the unit, with a warning. |
373
383
  | `modelValue` | `string \| string[] \| null` | | yes | v-model value. `null` for empty, a single string for single selection, or a two-element `[start, end]` array when `range` is true. The string shape follows `type`: `YYYY-MM-DD` when `floating` (`YYYY-MM` for `month`, `YYYY` for `year`), oth… |
374
384
  | `multiple` | `boolean \| undefined` | `false` | | Enables multi-selection: every pick toggles a value in or out of a sorted array, and the panel stays open until it is dismissed. Works in whatever `type` selects — days, months or years — and requires an array `modelValue` (use `[]` for emp… |
375
- | `offCanvasProps` | `Partial<BbOffCanvasProps> \| undefined` | | | Extra props forwarded to the `BbOffCanvas` sheet when adaptive on mobile. |
385
+ | `offCanvasProps` | `Partial<BbOffCanvasProps> \| undefined` | | | Extra props forwarded to the `BbOffCanvas` sheet when `adaptive` is active on mobile (e.g. `title`, `size`, `persistent`). Spread over the defaults: the sheet is `draggable` (the time wheels and the year list never drag it) and hides its ✕ … |
376
386
  | `offset` | `number \| undefined` | `4` | | Space the popover keeps from the activator. |
377
387
  | `padding` | `number \| undefined` | | | Minimum empty space to keep from the edge of the page. |
378
388
  | `placement` | `Placement \| undefined` | | | Position of the popover relative to the activator/anchor. |
@@ -410,14 +420,16 @@ Set these on the element, or on a class you put on it, to retune this component
410
420
 
411
421
  | Property | Set on | Default | What it is |
412
422
  | --- | --- | --- | --- |
413
- | `--cell` | `.bb-date-picker__grid` | `28px` | Cell size drives all grid math: 224px ÷ 7 = 32px exactly |
414
- | `--pad-x` | `.bb-date-picker__grid` | `6px` | |
415
- | `--pad-y` | `.bb-date-picker__grid` | `8px` | |
416
- | `--nav-button-h` | `.bb-date-picker__grid` | `24px` | |
423
+ | `--cell` | `.bb-date-picker__panel` | `28px` | Cell size drives all grid math: 224px ÷ 7 = 32px exactly |
424
+ | `--pad-x` | `.bb-date-picker__panel` | `6px` | |
425
+ | `--pad-y` | `.bb-date-picker__panel` | `8px` | |
426
+ | `--nav-button-h` | `.bb-date-picker__panel` | `24px` | |
427
+ | `--day-slot-allowance` | `.bb-date-picker__panel` | `0px` | Allowance for the day slot append area - needed for the slot to be visible |
428
+ | `--unit-row` | `.bb-date-picker__panel` | `calc(var(--cell) * 1.25)` | Row pitch for the coarse grids (month/year), where a "row" is one of four month rows rather than a week. Roomier than --cell because twelve months in a 4×3 grid have space the 6×7 day grid does not. |
417
429
  | `--weeks` | `.bb-date-picker__grid` | `6` | |
418
- | `--day-slot-allowance` | `.bb-date-picker__grid` | `0px` | Allowance for the day slot append area - needed for the slot to be visible |
419
- | `--unit-row` | `.bb-date-picker__grid` | `calc(var(--cell) * 1.25)` | Row pitch for the coarse grids (month/year), where a "row" is one of four month rows rather than a week. Roomier than --cell because twelve months in a 4×3 grid have space the 6×7 day grid does not. |
420
- | `--sheet-cell` | `.bb-date-picker__calendar--sheet` | `40px` | Declared on the container so the time rail (the calendar's sibling) can align its wheels to the same column grid. |
430
+ | `--sheet-cell` | `.bb-date-picker__panel--sheet` | `40px` | Declared on the container so the time rail (the calendar's sibling) can align its wheels to the same column grid. |
431
+ | `--cell` | `.bb-date-picker__panel--sheet` | `var(--sheet-cell)` | One touch scale for the whole sheet: 40px day cells (36px marks), and a nav row to match — on the panel, where the tokens live. |
432
+ | `--nav-button-h` | `.bb-date-picker__panel--sheet` | `40px` | |
421
433
 
422
434
  ## Component tree
423
435
 
@@ -428,7 +440,7 @@ Set these on the element, or on a class you put on it, to retune this component
428
440
  - **CSS custom properties** listed on a node are declared on THAT node's root and read by elements inside it. Set one on that node's root or on the element inside it that reads it — the pt part that lands there is how you reach it (`pt:box="[--border-color:…]"` on a text input) — never on `BbDatePicker`'s root, where the node's own declaration masks it (design-tokens guide, _Overriding one from a consumer app_, rule 0).
429
441
  - Listed nodes are the ones `BbDatePicker`'s API reaches or that declare a documented CSS variable; the rest fold into "also mounts". The complete tree, repeats and undocumented locals included, is the `tree` field of this component in `components.json`.
430
442
 
431
- - `BbDatePicker` _(this component)_ — its own template binds: `root` → `div.bb-date-picker__calendar`, `header` → `div.bb-date-picker__controls`, `arrow` → `BbBaseButton`, `month` → `BbBaseButton`, `year` → `BbBaseButton`, `day` → `div.bb-date-picker__date`, `day-button` → `button.bb-date-picker__date-button`; hands `BbOffCanvas` the pt map `{ sheet: 'root' }` (ours → theirs)
443
+ - `BbDatePicker` _(this component)_ — its own template binds: `header` → `div.bb-date-picker__controls`, `arrow` → `BbBaseButton`, `month` → `BbBaseButton`, `year` → `BbBaseButton`, `day` → `div.bb-date-picker__date`, `day-button` → `button.bb-date-picker__date-button`, `panel` → `div`, `panel` → `CommonPopover`; hands `BbOffCanvas` the pt map `{ sheet: 'root' }` (ours → theirs)
432
444
  - `BbBaseButton` _(public — [contract](./BbBaseButton.md))_ — its own pt parts (`BbBaseButton`): `root` → `RouterComponent`, `root` → `a`, `root` → `component`; also mounts `RouterComponent`
433
445
  - `CommonTimeSelector` _(internal — not importable, reach it through `BbDatePicker`)_ — documented CSS variables: `--time-mark`; also mounts `BbBaseButton`
434
446
  - `BbOffCanvas` _(public — [contract](./BbOffCanvas.md))_ — its own pt parts (`BbOffCanvas`): `header` → `div.bb-offcanvas__header`, `title` → `span.bb-offcanvas__title`, `description` → `p.bb-offcanvas__description`, `close` → `CloseButton`, `content` → `div.bb-offcanvas__body`, `footer` → `div.bb-offcanvas__footer`; documented CSS variables: `--stack-x`, `--stack-fill`, `--stack-transition-duration`, `--px`, `--close-size`
@@ -14,7 +14,7 @@
14
14
 
15
15
  | pt part | Lands on | In |
16
16
  | --- | --- | --- |
17
- | `pt:panel` | `pt:root` of `BbDatePicker` | `BbDatePicker` ([contract](./BbDatePicker.md)) |
17
+ | `pt:panel` | `pt:panel` of `BbDatePicker` | `BbDatePicker` ([contract](./BbDatePicker.md)) |
18
18
  | `pt:sheet` | `pt:sheet` of `BbDatePicker` | `BbDatePicker` ([contract](./BbDatePicker.md)) |
19
19
  | `pt:header` | `pt:header` of `BbDatePicker` | `BbDatePicker` ([contract](./BbDatePicker.md)) |
20
20
  | `pt:arrow` | `pt:arrow` of `BbDatePicker` | `BbDatePicker` ([contract](./BbDatePicker.md)) |
@@ -206,6 +206,13 @@ An incomplete date is never emitted: the model updates only once a segment
206
206
  parses to a real date, and a half-typed segment is restored to the last coherent
207
207
  value when focus leaves the control.
208
208
 
209
+ Native attributes that describe typing — `spellcheck`, `autocapitalize`,
210
+ `autocorrect`, `enterkeyhint` — and `form` go to **every segment** (each one
211
+ is a real `<input>` that posts its own `<name>-<field>`); `maxlength`,
212
+ `pattern` and `list` are not routed, because each segment sets its own length
213
+ and parses its own digits. Any other attribute lands on the field root; a
214
+ `pt:input` attribute reaches every segment and wins over the routed ones.
215
+
209
216
  ### Bounds & per-day gating
210
217
 
211
218
  `min` and `max` (each a `YYYY-MM-DD` string) constrain the selectable window;
@@ -543,8 +550,10 @@ The picker adapts to touch vs pointer, and you can steer that explicitly:
543
550
  - **`adaptive`** (defaults to the project's `config.adaptive`): on mobile the
544
551
  calendar opens in a bottom `BbOffCanvas` sheet instead of a floating popover.
545
552
  The surface is **latched** when the panel opens, so a mid-session resize never
546
- swaps a live popover into a sheet. Forward sheet options via `offCanvasProps`
547
- (e.g. `title`, `size`, `persistent`, `draggable`). Set `:adaptive="false"` to
553
+ swaps a live popover into a sheet. The sheet drags down to dismiss and shows
554
+ no ✕ (the time wheels and the year list never drag it). Forward sheet options
555
+ via `offCanvasProps`, spread over those defaults (e.g. `title`, `size`,
556
+ `persistent`, `{ hideClose: false }` to bring the ✕ back). Set `:adaptive="false"` to
548
557
  force the floating popover on every viewport (deterministic in tests).
549
558
  - **`disableWriting`**: block typing so the calendar is the only way in. Use
550
559
  `'mobile'` / `'desktop'` to disable typing on just one platform.
@@ -707,7 +716,7 @@ the `BbTextInput` guide.
707
716
 
708
717
  `pt` reaches a named part of the control with a class list — or, in the
709
718
  object form, a style and attributes — optionally only while a state is on.
710
- Parts: `root` (the container), `label`, `description`, `message` (the errors / warnings region — one node each, only one ever shows), `hint` (the helper line — shown on focus, or always with `persistent-hint`), `box` (the bordered field box), `input` (the native control), `icon` (`prepend:icon` + `append:icon` — a broadcast; the state glyphs are chrome), `spinner` (the spinner shown while `loading`), `prefix`, `suffix`, `clear` (the ✕ that empties the field). Plus `panel` (the calendar, in the popover and in the sheet alike), `sheet` (the bottom sheet around it on a phone only) and the calendar's own parts, forwarded to it: `header`, `arrow`, `month`, `year`, `column-header`, `day` (the whole cell), `day-button` (the mark inside it), `month-item` and `year-item` — the `BbDatePicker` guide describes each node. `input` is every segment field; the calendar trigger is chrome.
719
+ Parts: `root` (the container), `label`, `description`, `message` (the errors / warnings region — one node each, only one ever shows), `hint` (the helper line — shown on focus, or always with `persistent-hint`), `box` (the bordered field box), `input` (the native control), `icon` (`prepend:icon` + `append:icon` — a broadcast; the state glyphs are chrome), `spinner` (the spinner shown while `loading`), `prefix`, `suffix`, `clear` (the ✕ that empties the field). Plus `panel` (the calendar box you see — the popover's painted bubble on desktop, the box inside the sheet on a phone; it carries the sizing tokens, so `pt:panel="[--pad-x:2px]"` tightens it), `sheet` (the bottom sheet on a phone only) and the calendar's own parts, forwarded to it: `header`, `arrow`, `month`, `year`, `column-header`, `day` (the whole cell), `day-button` (the mark inside it), `month-item` and `year-item` — the `BbDatePicker` guide describes each node. `input` is every segment field; the calendar trigger is chrome.
711
720
  States: `errors`, `warnings` (never beside errors), `loading`, `disabled`, `readonly`, `has-value` (written `pt:box:has-value`). Plus `open` (the calendar is showing), and the calendar's per-node states: `selected`, `disabled`, `today`, `outside`, `range-start` / `range-end` / `in-range` and `highlighted` on the cells, `active` on `month` / `year`. A name outside that list is a type error and an
712
721
  ESLint error.
713
722
 
@@ -871,7 +880,7 @@ label>')` matches nothing; query each segment by its own label instead. See
871
880
  | `min` | `string \| undefined` | | | Minimum selectable date in `YYYY-MM-DD` format — or, with `type="datetime"`, `YYYY-MM-DDTHH:mm` to tighten the boundary day to a minute. Values outside both patterns throw during setup to surface configuration mistakes. |
872
881
  | `modelValue` | `string \| string[] \| null` | | yes | Used by v-model. Can be null, a single string, or an array of strings based on whether a range or single date is needed. |
873
882
  | `name` | `string \| undefined` | | | Defines the name of the input. |
874
- | `offCanvasProps` | `Partial<BbOffCanvasProps> \| undefined` | | | Extra props forwarded to the `BbOffCanvas` sheet when `adaptive` is active on mobile (e.g. `title`, `size`, `persistent`). |
883
+ | `offCanvasProps` | `Partial<BbOffCanvasProps> \| undefined` | | | Extra props forwarded to the `BbOffCanvas` sheet when `adaptive` is active on mobile (e.g. `title`, `size`, `persistent`). Spread over the defaults: the sheet is `draggable` (the time wheels and the year list never drag it) and hides its ✕ … |
875
884
  | `persistentHint` | `boolean \| undefined` | `false` | | Keeps the hint displayed. |
876
885
  | `placeholder` | `string \| undefined` | | | String displayed when there's no data. |
877
886
  | `prepend:icon` | `string \| undefined` | | | Name of the icon to be added at the start of the input. |
@@ -942,8 +951,8 @@ Set these on the element, or on a class you put on it, to retune this component
942
951
  - **CSS custom properties** listed on a node are declared on THAT node's root and read by elements inside it. Set one on that node's root or on the element inside it that reads it — the pt part that lands there is how you reach it (`pt:box="[--border-color:…]"` on a text input) — never on `BbDatePickerInput`'s root, where the node's own declaration masks it (design-tokens guide, _Overriding one from a consumer app_, rule 0).
943
952
  - Listed nodes are the ones `BbDatePickerInput`'s API reaches or that declare a documented CSS variable; the rest fold into "also mounts". The complete tree, repeats and undocumented locals included, is the `tree` field of this component in `components.json`.
944
953
 
945
- - `BbDatePickerInput` _(this component)_ — its own template binds: `input` → `input.bb-segmented-field__field`, `suffix` → `span.bb-field-input__suffix`; hands `BbDatePicker` the pt map `{ panel: 'root', sheet: 'sheet', header: 'header', arrow: 'arrow', month: 'month', year: 'year', 'column-header': 'column-header', day: 'day', 'day-button': 'day-button', 'month-item': 'month-item', 'year-item': 'year-item', }` (ours → theirs)
946
- - `BbDatePicker` _(public — [contract](./BbDatePicker.md))_ — its own pt parts (`BbDatePicker`): `root` → `div.bb-date-picker__calendar`, `header` → `div.bb-date-picker__controls`, `arrow` → `BbBaseButton`, `month` → `BbBaseButton`, `year` → `BbBaseButton`, `day` → `div.bb-date-picker__date`, `day-button` → `button.bb-date-picker__date-button`; hands `BbOffCanvas` the pt map `{ sheet: 'root' }` (ours → theirs); documented CSS variables: `--cell`, `--day-slot-allowance`, `--unit-row`, `--sheet-cell`; also mounts `CommonPopover`, `ScaleFade`, `Slide`, `DatePickerMonthPanel`, `DatePickerYearPanel`
954
+ - `BbDatePickerInput` _(this component)_ — its own template binds: `controlAttrs` → `input.bb-segmented-field__field`, `input` → `input.bb-segmented-field__field`, `suffix` → `span.bb-field-input__suffix`; hands `BbDatePicker` the pt map `{ panel: 'panel', sheet: 'sheet', header: 'header', arrow: 'arrow', month: 'month', year: 'year', 'column-header': 'column-header', day: 'day', 'day-button': 'day-button', 'month-item': 'month-item', 'year-item': 'year-item', }` (ours → theirs)
955
+ - `BbDatePicker` _(public — [contract](./BbDatePicker.md))_ — its own pt parts (`BbDatePicker`): `header` → `div.bb-date-picker__controls`, `arrow` → `BbBaseButton`, `month` → `BbBaseButton`, `year` → `BbBaseButton`, `day` → `div.bb-date-picker__date`, `day-button` → `button.bb-date-picker__date-button`, `panel` → `div`, `panel` → `CommonPopover`; hands `BbOffCanvas` the pt map `{ sheet: 'root' }` (ours → theirs); documented CSS variables: `--cell`, `--day-slot-allowance`, `--unit-row`, `--sheet-cell`, `--cell`; also mounts `CommonPopover`, `ScaleFade`, `Slide`, `DatePickerMonthPanel`, `DatePickerYearPanel`
947
956
  - `BbBaseButton` _(public — [contract](./BbBaseButton.md))_ — its own pt parts (`BbBaseButton`): `root` → `RouterComponent`, `root` → `a`, `root` → `component`; also mounts `RouterComponent`
948
957
  - `CommonTimeSelector` _(internal — not importable, reach it through `BbDatePicker`)_ — documented CSS variables: `--time-mark`; also mounts `BbBaseButton`
949
958
  - `BbOffCanvas` _(public — [contract](./BbOffCanvas.md))_ — its own pt parts (`BbOffCanvas`): `header` → `div.bb-offcanvas__header`, `title` → `span.bb-offcanvas__title`, `description` → `p.bb-offcanvas__description`, `close` → `CloseButton`, `content` → `div.bb-offcanvas__body`, `footer` → `div.bb-offcanvas__footer`; documented CSS variables: `--stack-x`, `--stack-fill`, `--stack-transition-duration`, `--px`, `--close-size`
@@ -484,7 +484,10 @@ the menu becomes on a phone, only), `item` (every entry), and `item-text` /
484
484
  `item-icon` / `item-description` (an entry's label, its icons and its muted
485
485
  second line) — all handed to the `BbDropdown` under the same words, so
486
486
  `pt:panel:open`, `pt:item:disabled` and `pt:item-text` resolve there, on the
487
- flyout and on the phone sheet alike. States: `loading`, `disabled`, `open`.
487
+ flyout and on the phone sheet alike. States: `loading`, `disabled`, `open` on
488
+ every part, and `selected` (a selectable group's checked entry) on the entry
489
+ parts only — `pt:item:selected` is the menu's word, `pt:root:selected` a type
490
+ error.
488
491
 
489
492
  The Save split on INV-2048, restyled through those parts: the brand token on
490
493
  `pt:icon` (the main button's glyph — the chevron is chrome), muted
@@ -592,7 +595,7 @@ The full grammar, the merge rules and the global map are in the
592
595
 
593
596
  | Prop | Type | Default | Required | Description |
594
597
  | --- | --- | --- | --- | --- |
595
- | `pt:<part>`, `pt:<part>:<state>`, `pt` | `PtValue` | | | Passthrough — a class list, or `{ class, style, attrs }`, bound to one named part of the component; the state form applies only while that state is on. Parts: `icon`, `item`, `item-description`, `item-icon`, `item-text`, `panel`, `root`, `sheet`, `spinner`, `text`. States: `disabled`, `loading`, `open`. `pt` is the object form with the same keys minus the prefix (`{ icon: '…', 'icon:loading': '…' }`). See `guides/passthrough.md`. |
598
+ | `pt:<part>`, `pt:<part>:<state>`, `pt` | `PtValue` | | | Passthrough — a class list, or `{ class, style, attrs }`, bound to one named part of the component; the state form applies only while that state is on. Parts: `icon`, `item`, `item-description`, `item-icon`, `item-text`, `panel`, `root`, `sheet`, `spinner`, `text`. States: `disabled`, `loading`, `open`, `selected`. `pt` is the object form with the same keys minus the prefix (`{ icon: '…', 'icon:loading': '…' }`). See `guides/passthrough.md`. |
596
599
  | `append:icon` | `string \| undefined` | | | Icon to be added on the right of the text. |
597
600
  | `block` | `boolean \| undefined` | `false` | | Displays the component as full width. |
598
601
  | `disableAutoLoading` | `boolean \| undefined` | `false` | | Disables the automatic loading state that tracks async actions (enabled by default). Only affects the main action button: the split toggle half still mirrors the dropdown's internal async-action loading state. |
@@ -0,0 +1,136 @@
1
+ # BbPtScope
2
+
3
+ ## Agent Contract
4
+
5
+ - Safety level: **Consumer API**
6
+ - Group: **Layout & Utility**
7
+ - Description: Renderless provider that switches on a named passthrough scope (`ptScopes` in the plugin config) for its subtree — a backoffice and a member area with different looks in one app.
8
+ - Usage rule: Prefer this component for consumer-facing implementations.
9
+ - Implementation source (only when the contract below is not enough): [source/BbPtScope.md](./source/BbPtScope.md)
10
+
11
+ ## Usage & Guidelines
12
+
13
+ ### When to use
14
+
15
+ The global passthrough map (`bitbossUi({ pt })`) styles every instance in the
16
+ app. When the app has **areas with different looks** — a backoffice next to a
17
+ member webapp, per-tenant areas, a marketing section beside the product — give
18
+ each area a named map in `ptScopes` and wrap the area in `<BbPtScope>`:
19
+
20
+ ```ts
21
+ // bitboss-ui.pt.ts
22
+ import { definePt } from 'bitboss-ui/vite';
23
+
24
+ export const pt = definePt({
25
+ BbTextInput: { label: 'text-xs font-medium' },
26
+ });
27
+
28
+ export const ptScopes = {
29
+ webapp: definePt({
30
+ BbTextInput: { label: 'text-white/60' },
31
+ BbButton: { root: 'rounded-full' },
32
+ }),
33
+ backoffice: definePt({
34
+ BbButton: { root: 'rounded-md' },
35
+ }),
36
+ };
37
+ ```
38
+
39
+ ```vue
40
+ <!-- WebappLayout.vue -->
41
+ <template>
42
+ <BbPtScope name="webapp">
43
+ <slot />
44
+ </BbPtScope>
45
+ </template>
46
+
47
+ <script setup lang="ts">
48
+ import { BbPtScope } from 'bitboss-ui';
49
+ </script>
50
+ ```
51
+
52
+ Everything rendered inside the scope — however deep — resolves the `webapp`
53
+ entries on top of the global map. Outside it, nothing changes.
54
+
55
+ ### Order and nesting
56
+
57
+ For each part, the sources merge in this order:
58
+
59
+ 1. the global map (`pt`),
60
+ 2. every active scope, outermost `<BbPtScope>` first,
61
+ 3. the instance's `class`, `pt` object and `pt:*` attributes.
62
+
63
+ Nested scopes **add up**: an inner scope merges after the outer one, it never
64
+ hides it. Everything goes through the same merge and class deduper as the rest
65
+ of `pt`, so a conflicting utility on an instance replaces the scope's.
66
+
67
+ ```vue
68
+ <template>
69
+ <BbPtScope name="webapp">
70
+ <!-- the scope's `rounded-full`, then this instance's `rounded-none` wins -->
71
+ <BbButton pt:root="rounded-none">Save</BbButton>
72
+ </BbPtScope>
73
+ </template>
74
+
75
+ <script setup lang="ts">
76
+ import { BbButton, BbPtScope } from 'bitboss-ui';
77
+ </script>
78
+ ```
79
+
80
+ ### The name is typed
81
+
82
+ `name` is a `BbPtScopeName`: the plugin generates the union of your `ptScopes`
83
+ keys (`'webapp' | 'backoffice'`) when the dev server or a build runs, so a
84
+ misspelt scope is a `vue-tsc` error. Every component name and key inside a
85
+ scope is checked against the library's manifest at build time, exactly like
86
+ the global map. `name` is reactive: switching it restyles the subtree.
87
+
88
+ ### Overlays, directives, toasts and confirms
89
+
90
+ The scope follows the **component tree**, not the DOM:
91
+
92
+ - A dialog, sheet, popover, dropdown or picker opened inside the scope resolves
93
+ it wherever it paints.
94
+ - `v-bb-tooltip`, `v-bb-dropdown`, `v-bb-date`, `v-bb-time` and `v-bb-color`
95
+ resolve the scope around the component whose **template** they are written
96
+ in. A directive written directly in `<BbPtScope>`'s slot, in the same
97
+ template as the scope, sees the scope above it instead — keep the scope in a
98
+ layout or a parent component.
99
+ - `<BbToast>` and `<BbConfirm>` render every message where the **host** is
100
+ mounted. For toasts and confirms in the area's look, mount one of each inside
101
+ each area's layout, within its scope, and none at the app root — valid only
102
+ when every page renders inside exactly one of those layouts (see
103
+ [Agent Contract § Global Host Rule](./guides/agent-contract.md)).
104
+
105
+ ### When NOT to use it
106
+
107
+ - **One look for the whole app** — that is the global `pt` map.
108
+ - **Colours, radii, sizes for a subtree** — those are tokens: a `.bb-theme`
109
+ island ([design tokens](./guides/design-tokens.md)). A scope restyles parts;
110
+ an area usually wants both.
111
+ - **One instance** — use `pt:*` on that instance.
112
+
113
+ ### Works well with
114
+
115
+ - `BbToast` / `BbConfirm` — mount their hosts inside each scoped area layout.
116
+ - The [passthrough guide](./guides/passthrough.md) — grammar, merging and the
117
+ full parts table.
118
+
119
+ ## Props
120
+
121
+ | Prop | Type | Default | Required | Description |
122
+ | --- | --- | --- | --- | --- |
123
+ | `name` | `BbPtScopeName` | | yes | The scope to switch on for everything inside: a key of the plugin's `ptScopes` option (`BbPtScopeName`, generated from your config). Nested scopes add up: the outer scope's entries apply first, the inner scope's after them. Reactive — chang… |
124
+
125
+ ## Events
126
+
127
+ - None.
128
+
129
+ ## Slots
130
+
131
+ - `default` — scope: `any` — The subtree the scope applies to. Rendered as is — no wrapper element.
132
+
133
+ ## See Also
134
+
135
+ - [BbToast](./BbToast.md) — Shows transient notification messages (includes the co-located BbToastPortal export).
136
+ - [BbConfirm](./BbConfirm.md) — Prompts users to confirm or cancel critical actions (includes co-located BbConfirmPortal export).
@@ -14,7 +14,7 @@
14
14
 
15
15
  | pt part | Lands on | In |
16
16
  | --- | --- | --- |
17
- | `pt:panel` | `pt:root` of `BbSelectPopover` | `BbSelectPopover` ([contract](./BbSelectPopover.md)) |
17
+ | `pt:panel` | `pt:panel` of `BbSelectPopover` | `BbSelectPopover` ([contract](./BbSelectPopover.md)) |
18
18
  | `pt:sheet` | `pt:sheet` of `BbSelectPopover` | `BbSelectPopover` ([contract](./BbSelectPopover.md)) |
19
19
  | `pt:option` | `pt:option` of `BbSelectPopover` | `BbSelectPopover` ([contract](./BbSelectPopover.md)) |
20
20
  | `pt:item-text` | `pt:item-text` of `BbSelectPopover` | `BbSelectPopover` ([contract](./BbSelectPopover.md)) |
@@ -1576,7 +1576,7 @@ the `BbTextInput` guide.
1576
1576
 
1577
1577
  `pt` reaches a named part of the control with a class list — or, in the
1578
1578
  object form, a style and attributes — optionally only while a state is on.
1579
- Parts: `root` (the container), `label`, `description`, `message` (the errors / warnings region — one node each, only one ever shows), `hint` (the helper line — shown on focus, or always with `persistent-hint`), `box` (the bordered field box), `input` (the native control), `icon` (`prepend:icon` + `append:icon` — a broadcast; the state glyphs are chrome), `spinner` (the spinner shown while `loading`), `prefix`, `suffix`, `clear` (the ✕ that empties the field). Plus `panel` (the options surface — the sheet on mobile), `sheet` (that bottom sheet on a phone only, applied after `panel`) `option` (one listbox option, a broadcast), `item-text` (that option's label), `item-icon` (its `itemProps` prepend / append icons — never the field's `icon`) and `item-description` (its muted second line from `itemProps.description` — never the field's `description`), all with the option's `selected` / `disabled`; a custom `#option` slot replaces the label and description. `input` is the activator — the thing you act on to enter the value; the chevron and the clear ✕ are chrome.
1579
+ Parts: `root` (the container), `label`, `description`, `message` (the errors / warnings region — one node each, only one ever shows), `hint` (the helper line — shown on focus, or always with `persistent-hint`), `box` (the bordered field box), `input` (the native control), `icon` (`prepend:icon` + `append:icon` — a broadcast; the state glyphs are chrome), `spinner` (the spinner shown while `loading`), `prefix`, `suffix`, `clear` (the ✕ that empties the field). Plus `panel` (the options box you see — the popover's painted bubble on desktop, the box inside the sheet on a phone), `sheet` (the bottom sheet on a phone only), `option` (one listbox option, a broadcast), `item-text` (that option's label), `item-icon` (its `itemProps` prepend / append icons — never the field's `icon`) and `item-description` (its muted second line from `itemProps.description` — never the field's `description`), all with the option's `selected` / `disabled`; a custom `#option` slot replaces the label and description. `input` is the activator — the thing you act on to enter the value; the chevron and the clear ✕ are chrome.
1580
1580
  States: `errors`, `warnings` (never beside errors), `loading`, `disabled`, `readonly`, `has-value` (written `pt:box:has-value`). Plus `open` (the options surface is showing) and `selected`, resolved per option. A name outside that list is a type error and an
1581
1581
  ESLint error.
1582
1582
 
@@ -1665,6 +1665,12 @@ The full grammar, the merge rules and the global map are in the
1665
1665
 
1666
1666
  ### Gotchas and constraints
1667
1667
 
1668
+ - **A `form` attribute goes to the hidden inputs** — the select's value
1669
+ channel — so a select rendered outside its `<form>` still posts with it
1670
+ (`form="checkout"`). No other native attribute is routed: the activator is a
1671
+ button, not a text field, so `spellcheck` and friends have nothing to land
1672
+ on and stay on the field root like any attribute.
1673
+
1668
1674
  - **Clicking the selected option does not clear a single select** — it re-picks
1669
1675
  it and closes the panel. Add `clearable` for an explicit clear button; a
1670
1676
  required status field should not empty itself because someone clicked twice.
@@ -1863,11 +1869,11 @@ Set these on the element, or on a class you put on it, to retune this component
1863
1869
  - **CSS custom properties** listed on a node are declared on THAT node's root and read by elements inside it. Set one on that node's root or on the element inside it that reads it — the pt part that lands there is how you reach it (`pt:box="[--border-color:…]"` on a text input) — never on `BbSelect`'s root, where the node's own declaration masks it (design-tokens guide, _Overriding one from a consumer app_, rule 0).
1864
1870
  - Listed nodes are the ones `BbSelect`'s API reaches or that declare a documented CSS variable; the rest fold into "also mounts". The complete tree, repeats and undocumented locals included, is the `tree` field of this component in `components.json`.
1865
1871
 
1866
- - `BbSelect` _(this component)_ — its own template binds: `input` → `input.bb-select__activator`; hands `BbSelectPopover` the pt map `{ panel: 'root', sheet: 'sheet', option: 'option', 'item-text': 'item-text', 'item-icon': 'item-icon', 'item-description': 'item-description', }` (ours → theirs)
1872
+ - `BbSelect` _(this component)_ — its own template binds: `input` → `input.bb-select__activator`, `controlAttrs` → `input`; hands `BbSelectPopover` the pt map `{ panel: 'panel', sheet: 'sheet', option: 'option', 'item-text': 'item-text', 'item-icon': 'item-icon', 'item-description': 'item-description', }` (ours → theirs)
1867
1873
  - `CommonField` _(internal — not importable, reach it through `BbSelect`)_ — `BbSelect`'s pt parts land here: `root` → `div.bb-field`, `label` → `component`, `description` → `span.bb-field__description`, `hint` → `span.bb-field__hint-text`, `message` → `div.bb-field__errors`, `message` → `div.bb-field__warnings`
1868
1874
  - `CommonFieldInput` _(internal — not importable, reach it through `BbSelect`)_ — `BbSelect`'s pt parts land here: `box` → `span.bb-field-input__box`, `prefix` → `span.bb-field-input__prefix`, `icon` → `BbIcon`, `clear` → `ClearableButton`, `spinner` → `BbSpinner`, `suffix` → `span.bb-field-input__suffix`; documented CSS variables: `--bg`, `--bg-hover`, `--bg-focus`, `--bg-disabled`, `--border-color`, `--border-focus`, `--ring-size`, `--ring-color`, `--elev`, `--frost`, `--inside-label-clearance`; also mounts `ErrorIcon`, `WarningIcon`, `ClearableButton`, `BbIcon`, `BbSpinner`
1869
1875
  - `BbBadge` _(public — [contract](./BbBadge.md))_ — its own pt parts (`BbBadge`): `spinner` → `BbSpinner`, `icon` → `BbIcon`, `clear` → `button.bb-badge__clear-button`; documented CSS variables: `--bg`, `--fg`, `--border-width`, `--ring`, `--min-size-md`, `--min-size`, `--elev`, `--radius`, `--font-size`, `--icon-size`, `--gap`, `--padding-inline`, `--clear-size`, `--pad-left`; also mounts `BbIcon`, `BbSpinner`, `BadgeBodyContent`
1870
- - `BbSelectPopover` _(public — [contract](./BbSelectPopover.md))_ — its own pt parts (`BbSelectPopover`): `input` → `input.bb-select-popover__search-input`, `clear` → `ClearableButton`, `root` → `BbOffCanvas`, `root` → `CommonPopover`, `header` → `div.bb-select-popover__header`, `footer` → `div.bb-select-popover__footer`; hands `BbOffCanvas` the pt map `{ header: 'header', footer: 'footer', sheet: 'root' }` (ours → theirs); also mounts `BbBadge`, `BbIcon`, `ClearableButton`, `CommonPopover`, `ErrorIcon`, `WarningIcon`, `BbSmoothHeight`
1876
+ - `BbSelectPopover` _(public — [contract](./BbSelectPopover.md))_ — its own pt parts (`BbSelectPopover`): `input` → `input.bb-select-popover__search-input`, `clear` → `ClearableButton`, `root` → `BbOffCanvas`, `panel` → `CommonPopover`, `root` → `CommonPopover`, `header` → `div.bb-select-popover__header`, `footer` → `div.bb-select-popover__footer`; hands `BbOffCanvas` the pt map `{ header: 'header', footer: 'footer', sheet: 'root' }` (ours → theirs); also mounts `BbBadge`, `BbIcon`, `ClearableButton`, `CommonPopover`, `ErrorIcon`, `WarningIcon`, `BbSmoothHeight`
1871
1877
  - `BbOffCanvas` _(public — [contract](./BbOffCanvas.md))_ — its own pt parts (`BbOffCanvas`): `header` → `div.bb-offcanvas__header`, `title` → `span.bb-offcanvas__title`, `description` → `p.bb-offcanvas__description`, `close` → `CloseButton`, `content` → `div.bb-offcanvas__body`, `footer` → `div.bb-offcanvas__footer`; documented CSS variables: `--stack-x`, `--stack-fill`, `--stack-transition-duration`, `--px`, `--close-size`
1872
1878
  - `CloseButton` _(internal — not importable, reach it through `BbOffCanvas`)_ — documented CSS variables: `--size`, `--p`
1873
1879
  - `ListBox` _(internal — not importable, reach it through `BbSelectPopover`)_
@@ -16,6 +16,7 @@
16
16
  | --- | --- | --- |
17
17
  | `pt:clear` | the root of `ClearableButton` | `ClearableButton` _(internal)_ |
18
18
  | `pt:root` | the root of `BbOffCanvas` | `BbOffCanvas` ([contract](./BbOffCanvas.md)) |
19
+ | `pt:panel` | the root of `CommonPopover` | `CommonPopover` _(internal)_ |
19
20
  | `pt:root` | the root of `CommonPopover` | `CommonPopover` _(internal)_ |
20
21
  | `pt:header` | `pt:header` of `BbOffCanvas` | `BbOffCanvas` ([contract](./BbOffCanvas.md)) |
21
22
  | `pt:footer` | `pt:footer` of `BbOffCanvas` | `BbOffCanvas` ([contract](./BbOffCanvas.md)) |
@@ -1326,18 +1327,18 @@ floating popover everywhere.
1326
1327
 
1327
1328
  `pt` reaches a named part of the popover with a class list — or, in the
1328
1329
  object form, a style and attributes — optionally only while a state is on.
1329
- Parts: `root` (the flyout — the sheet on mobile), `sheet` (the bottom sheet the surface becomes on a phone — only that sheet, never the desktop surface; applied after `root`, so it wins a conflict there), `input` (the search
1330
+ Parts: `root` (the floating element — the sheet on a phone), `panel` (the options box you see: the popover's painted bubble on desktop, the box inside the sheet on a phone), `sheet` (the bottom sheet the surface becomes on a phone — only that sheet, never the desktop surface; applied after `root`, so it wins a conflict there), `input` (the search
1330
1331
  field), `option` (every listbox option, a broadcast resolved per option), `item-text` (that option's label), `item-icon` (its `itemProps` icons) and `item-description` (its muted second line, `itemProps.description`) — all with the option's states; a custom `#option` slot replaces the label and description,
1331
1332
  `header`, `footer`. States: `open`, and `selected` / `disabled` per option.
1332
1333
  `BbSelect` forwards its own `panel` / `sheet` / `option` here.
1333
1334
 
1334
1335
  The filter-pill assignee picker above, restyled through those parts: mono on
1335
1336
  the search `pt:input`, a muted wash on the chosen option
1336
- (`pt:option:selected` is per node), a primary ring on `pt:root:open` (the
1337
- flyout — the sheet on mobile). The activator is yours; don't restyle it
1337
+ (`pt:option:selected` is per node), a primary ring on `pt:panel:open` (the
1338
+ options box — the box inside the sheet on a phone). The activator is yours; don't restyle it
1338
1339
  through `pt`.
1339
1340
 
1340
- **pt:input / pt:option:selected / pt:root:open — assignee pill**
1341
+ **pt:input / pt:option:selected / pt:panel:open — assignee pill**
1341
1342
 
1342
1343
  ```vue
1343
1344
  <template>
@@ -1355,7 +1356,7 @@ through `pt`.
1355
1356
  :items="teammates"
1356
1357
  pt:input="font-mono text-sm"
1357
1358
  pt:option:selected="bg-(--bb-muted) font-semibold"
1358
- pt:root:open="ring-1 ring-(--bb-primary)"
1359
+ pt:panel:open="ring-1 ring-(--bb-primary)"
1359
1360
  width="240px"
1360
1361
  >
1361
1362
  <template #activator="{ props }">
@@ -1385,7 +1386,7 @@ type Teammate = {
1385
1386
 
1386
1387
  // Same filter-pill assignee picker as `AssigneePicker.vue`, restyled through
1387
1388
  // passthrough: mono on the search `pt:input`, a muted wash on the chosen
1388
- // option (`pt:option:selected` is per node), a primary ring on `pt:root:open`
1389
+ // option (`pt:option:selected` is per node), a primary ring on `pt:panel:open`
1389
1390
  // (the flyout — the sheet on mobile).
1390
1391
  const teammates: Teammate[] = [
1391
1392
  { id: 'ada', fullName: 'Ada Lovelace' },
@@ -1524,7 +1525,7 @@ in the [passthrough guide](./guides/passthrough.md).
1524
1525
 
1525
1526
  | Prop | Type | Default | Required | Description |
1526
1527
  | --- | --- | --- | --- | --- |
1527
- | `pt:<part>`, `pt:<part>:<state>`, `pt` | `PtValue` | | | Passthrough — a class list, or `{ class, style, attrs }`, bound to one named part of the component; the state form applies only while that state is on. Parts: `clear`, `footer`, `header`, `input`, `item-description`, `item-icon`, `item-text`, `option`, `root`, `sheet`. States: `disabled`, `open`, `selected`. `pt` is the object form with the same keys minus the prefix (`{ icon: '…', 'icon:loading': '…' }`). See `guides/passthrough.md`. |
1528
+ | `pt:<part>`, `pt:<part>:<state>`, `pt` | `PtValue` | | | Passthrough — a class list, or `{ class, style, attrs }`, bound to one named part of the component; the state form applies only while that state is on. Parts: `clear`, `footer`, `header`, `input`, `item-description`, `item-icon`, `item-text`, `option`, `panel`, `root`, `sheet`. States: `disabled`, `open`, `selected`. `pt` is the object form with the same keys minus the prefix (`{ icon: '…', 'icon:loading': '…' }`). See `guides/passthrough.md`. |
1528
1529
  | `activator` | `Record<string, any> \| HTMLElement \| null \| undefined` | | | External activator element or component ref. When provided, the activator slot is not rendered and event listeners are attached programmatically to the referenced element. |
1529
1530
  | `adaptive` | `boolean \| undefined` | ``config.adaptive` (`true`)` | | When `true`, the panel opens as a bottom off-canvas sheet on mobile viewports instead of a floating popover; on desktop it stays a popover. The sheet reuses the same search field and options list, adding a representation of the current sele… |
1530
1531
  | `anchor` | `Record<string, any> \| HTMLElement \| null \| undefined` | `null` | | Override the element used for popover positioning and width measurement. Useful when the focusable activator is narrower than its visual container (e.g. a button inside a wrapper). Falls back to `activatorEl` when omitted. |
@@ -1616,7 +1617,7 @@ Set these on the element, or on a class you put on it, to retune this component
1616
1617
  - **CSS custom properties** listed on a node are declared on THAT node's root and read by elements inside it. Set one on that node's root or on the element inside it that reads it — the pt part that lands there is how you reach it (`pt:box="[--border-color:…]"` on a text input) — never on `BbSelectPopover`'s root, where the node's own declaration masks it (design-tokens guide, _Overriding one from a consumer app_, rule 0).
1617
1618
  - Listed nodes are the ones `BbSelectPopover`'s API reaches or that declare a documented CSS variable; the rest fold into "also mounts". The complete tree, repeats and undocumented locals included, is the `tree` field of this component in `components.json`.
1618
1619
 
1619
- - `BbSelectPopover` _(this component)_ — its own template binds: `input` → `input.bb-select-popover__search-input`, `clear` → `ClearableButton`, `root` → `BbOffCanvas`, `root` → `CommonPopover`, `header` → `div.bb-select-popover__header`, `footer` → `div.bb-select-popover__footer`; hands `BbOffCanvas` the pt map `{ header: 'header', footer: 'footer', sheet: 'root' }` (ours → theirs)
1620
+ - `BbSelectPopover` _(this component)_ — its own template binds: `input` → `input.bb-select-popover__search-input`, `clear` → `ClearableButton`, `root` → `BbOffCanvas`, `panel` → `CommonPopover`, `root` → `CommonPopover`, `header` → `div.bb-select-popover__header`, `footer` → `div.bb-select-popover__footer`; hands `BbOffCanvas` the pt map `{ header: 'header', footer: 'footer', sheet: 'root' }` (ours → theirs)
1620
1621
  - `BbBadge` _(public — [contract](./BbBadge.md))_ — its own pt parts (`BbBadge`): `spinner` → `BbSpinner`, `icon` → `BbIcon`, `clear` → `button.bb-badge__clear-button`; documented CSS variables: `--bg`, `--fg`, `--border-width`, `--ring`, `--min-size-md`, `--min-size`, `--elev`, `--radius`, `--font-size`, `--icon-size`, `--gap`, `--padding-inline`, `--clear-size`, `--pad-left`; also mounts `BbIcon`, `BbSpinner`, `BadgeBodyContent`
1621
1622
  - `BbOffCanvas` _(public — [contract](./BbOffCanvas.md))_ — its own pt parts (`BbOffCanvas`): `header` → `div.bb-offcanvas__header`, `title` → `span.bb-offcanvas__title`, `description` → `p.bb-offcanvas__description`, `close` → `CloseButton`, `content` → `div.bb-offcanvas__body`, `footer` → `div.bb-offcanvas__footer`; documented CSS variables: `--stack-x`, `--stack-fill`, `--stack-transition-duration`, `--px`, `--close-size`
1622
1623
  - `CloseButton` _(internal — not importable, reach it through `BbOffCanvas`)_ — documented CSS variables: `--size`, `--p`