bitboss-ui 3.0.0-beta.27 → 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 (111) hide show
  1. package/bin/bitboss-ui-mcp.mjs +1 -1
  2. package/dist/ai/BbColorInput.md +1 -1
  3. package/dist/ai/BbColorPalette.md +1 -13
  4. package/dist/ai/BbConfirm.md +16 -3
  5. package/dist/ai/BbDatePicker.md +8 -14
  6. package/dist/ai/BbDatePickerInput.md +14 -5
  7. package/dist/ai/BbDropdownButton.md +5 -2
  8. package/dist/ai/BbPtScope.md +136 -0
  9. package/dist/ai/BbSelect.md +8 -2
  10. package/dist/ai/BbSelectPopover.md +1 -1
  11. package/dist/ai/BbTag.md +0 -2
  12. package/dist/ai/BbTextInput.md +6 -2
  13. package/dist/ai/BbTimePicker.md +8 -14
  14. package/dist/ai/BbTimePickerInput.md +12 -3
  15. package/dist/ai/BbToast.md +10 -2
  16. package/dist/ai/changelog.json +55 -5
  17. package/dist/ai/components.json +102 -67
  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 +108 -17
  26. package/dist/ai/index.md +1 -0
  27. package/dist/ai/source/BbCheckbox.md +4 -4
  28. package/dist/ai/source/BbColorPalette.md +47 -11
  29. package/dist/ai/source/BbConfirm.md +9 -2
  30. package/dist/ai/source/BbConfirmPortal.md +7 -0
  31. package/dist/ai/source/BbDatePicker.md +62 -5
  32. package/dist/ai/source/BbDatePickerInput.md +10 -11
  33. package/dist/ai/source/BbDialog.md +7 -0
  34. package/dist/ai/source/BbDropdown.md +9 -0
  35. package/dist/ai/source/BbDropdownButton.md +45 -9
  36. package/dist/ai/source/BbOffCanvas.md +7 -0
  37. package/dist/ai/source/BbPopover.md +7 -0
  38. package/dist/ai/source/BbPtScope.md +54 -0
  39. package/dist/ai/source/BbRadio.md +4 -4
  40. package/dist/ai/source/BbSelect.md +7 -3
  41. package/dist/ai/source/BbSelectPopover.md +35 -12
  42. package/dist/ai/source/BbSlider.md +19 -2
  43. package/dist/ai/source/BbSwitch.md +4 -4
  44. package/dist/ai/source/BbTable.md +49 -2
  45. package/dist/ai/source/BbTag.md +19 -15
  46. package/dist/ai/source/BbTimePicker.md +64 -6
  47. package/dist/ai/source/BbTimePickerInput.md +14 -9
  48. package/dist/ai/source/BbToast.md +1 -1
  49. package/dist/ai/source/BbTooltip.md +7 -0
  50. package/dist/ai/source/CommonField.md +6 -2
  51. package/dist/ai/source/CommonTimeSelector.md +5 -0
  52. package/dist/components/BbColorPalette/BbColorPalette.vue_vue_type_script_setup_true_lang.js +224 -216
  53. package/dist/components/BbConfirm/BbConfirm.vue_vue_type_script_setup_true_lang.js +4 -3
  54. package/dist/components/BbConfirm/types.d.ts +7 -0
  55. package/dist/components/BbDatePicker/BbDatePicker.vue_vue_type_script_setup_true_lang.js +221 -213
  56. package/dist/components/BbDatePicker/DatePickerYearPanel.vue_vue_type_script_setup_true_lang.js +1 -0
  57. package/dist/components/BbDatePicker/types.d.ts +7 -1
  58. package/dist/components/BbDatePickerInput/BbDatePickerInput.vue_vue_type_script_setup_true_lang.js +296 -295
  59. package/dist/components/BbDatePickerInput/types.d.ts +4 -1
  60. package/dist/components/BbDialog/BbDialog.vue_vue_type_script_setup_true_lang.js +120 -120
  61. package/dist/components/BbDropdown/BbDropdown.vue_vue_type_script_setup_true_lang.js +115 -113
  62. package/dist/components/BbDropdownButton/BbDropdownButton.vue_vue_type_script_setup_true_lang.js +4 -0
  63. package/dist/components/BbDropdownButton/types.d.ts +31 -9
  64. package/dist/components/BbDropdownButton/types.js +9 -1
  65. package/dist/components/BbOffCanvas/BbOffCanvas.vue_vue_type_script_setup_true_lang.js +116 -116
  66. package/dist/components/BbPopover/BbPopover.vue_vue_type_script_setup_true_lang.js +146 -146
  67. package/dist/components/BbPtScope/BbPtScope.vue.d.ts +12 -0
  68. package/dist/components/BbPtScope/BbPtScope.vue.js +5 -0
  69. package/dist/components/BbPtScope/BbPtScope.vue_vue_type_script_setup_true_lang.js +13 -0
  70. package/dist/components/BbPtScope/types.d.ts +15 -0
  71. package/dist/components/BbSelect/BbSelect.vue_vue_type_script_setup_true_lang.js +123 -122
  72. package/dist/components/BbSelect/types.d.ts +1 -1
  73. package/dist/components/BbSelectPopover/BbSelectPopover.vue_vue_type_script_setup_true_lang.js +190 -188
  74. package/dist/components/BbSlider/BbSlider.vue_vue_type_script_setup_true_lang.js +180 -180
  75. package/dist/components/BbTable/BbTable.vue_vue_type_script_setup_true_lang.js +814 -800
  76. package/dist/components/BbTag/BbTag.vue_vue_type_script_setup_true_lang.js +145 -145
  77. package/dist/components/BbTimePicker/BbTimePicker.vue_vue_type_script_setup_true_lang.js +115 -107
  78. package/dist/components/BbTimePicker/types.d.ts +7 -1
  79. package/dist/components/BbTimePickerInput/BbTimePickerInput.vue_vue_type_script_setup_true_lang.js +246 -244
  80. package/dist/components/BbTimePickerInput/types.d.ts +5 -2
  81. package/dist/components/BbToast/BbToast.vue_vue_type_script_setup_true_lang.js +1 -1
  82. package/dist/components/BbTooltip/BbTooltip.vue_vue_type_script_setup_true_lang.js +40 -40
  83. package/dist/components/CommonField/CommonField.vue_vue_type_script_setup_true_lang.js +32 -32
  84. package/dist/components/CommonTimeSelector/CommonTimeSelector.vue_vue_type_script_setup_true_lang.js +2 -1
  85. package/dist/composables/useConfirm.d.ts +11 -2
  86. package/dist/composables/useConfirm.js +1 -1
  87. package/dist/composables/usePassthrough.d.ts +27 -1
  88. package/dist/composables/usePassthrough.js +111 -92
  89. package/dist/composables/useToast.d.ts +2 -1
  90. package/dist/composables/useToast.js +1 -1
  91. package/dist/directives/createPopoverDirective.js +68 -53
  92. package/dist/index.d.ts +4 -0
  93. package/dist/index.js +24 -23
  94. package/dist/llms-full.txt +468 -164
  95. package/dist/llms-medium.txt +52 -14
  96. package/dist/nuxt-auto-imports.js +1 -1
  97. package/dist/nuxt-module.d.ts +2 -0
  98. package/dist/nuxt.js +12 -12
  99. package/dist/pt-scope-registry.d.ts +15 -0
  100. package/dist/styles.css +1 -1
  101. package/dist/types/PtScope.d.ts +13 -0
  102. package/dist/types/passthrough.d.ts +19 -0
  103. package/dist/types/ptComponentMap.d.ts +59 -0
  104. package/dist/utils/passthrough.d.ts +12 -4
  105. package/dist/utils/passthrough.js +28 -19
  106. package/dist/utils/ptScope.d.ts +8 -0
  107. package/dist/utils/ptScope.js +4 -0
  108. package/dist/validated/index.d.ts +1 -0
  109. package/dist/vite-plugin.d.ts +38 -6
  110. package/dist/vite.js +270 -263
  111. 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
  },
@@ -761,7 +761,7 @@ Set these on the element, or on a class you put on it, to retune this component
761
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)
762
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`
763
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`
764
- - `BbColorPalette` _(public — [contract](./BbColorPalette.md))_ — its own pt parts (`BbColorPalette`): `swatch` → `button.bb-color-palette__swatch`, `root` → `BbOffCanvas`, `panel` → `div`, `panel` → `CommonPopover`, `root` → `CommonPopover`; 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`
765
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`
766
766
  - `CloseButton` _(internal — not importable, reach it through `BbOffCanvas`)_ — documented CSS variables: `--size`, `--p`
767
767
 
@@ -14,21 +14,9 @@
14
14
 
15
15
  | pt part | Lands on | In |
16
16
  | --- | --- | --- |
17
- | `pt:root` | the root of `BbOffCanvas` | `BbOffCanvas` ([contract](./BbOffCanvas.md)) |
18
17
  | `pt:panel` | the root of `CommonPopover` | `CommonPopover` _(internal)_ |
19
- | `pt:root` | the root of `CommonPopover` | `CommonPopover` _(internal)_ |
20
18
  | `pt:sheet` | `pt:root` of `BbOffCanvas` | `BbOffCanvas` ([contract](./BbOffCanvas.md)) |
21
19
 
22
- **CSS variables you can set through those parts** — declared deeper in the tree, so set one on the part that reads it (`pt:<part>="[--name:value]"`), never on `BbColorPalette`'s root:
23
-
24
- | Variable | Set through | Declared by | What it is |
25
- | --- | --- | --- | --- |
26
- | `--stack-x` | `pt:root` | `BbOffCanvas` | Inward shift applied to a parent panel while a child is stacked on top. |
27
- | `--stack-fill` | `pt:root` | `BbOffCanvas` | Length of the pad (see `::after`) that fills from the panel's anchored edge out to the screen edge, so no empty band shows when a descendant is dragged away or shrinks. |
28
- | `--stack-transition-duration` | `pt:root` | `BbOffCanvas` | Duration for the stack shift + pad. Zeroed while a peer resizes so parents track the live size instead of lagging behind a 250ms animation. |
29
- | `--px` | `pt:root` | `BbOffCanvas` | Axis split of --bb-panel-p: --px (inline) / --py (block), each branching off it. Set the pair only when the axes differ; setting --bb-panel-p alone keeps them equal. Local on this root class (not :roo… |
30
- | `--close-size` | `pt:root` | `BbOffCanvas` | Shared by the close control and by the space the title reserves for it, * so the two can never drift apart. |
31
-
32
20
  ## Usage & Guidelines
33
21
 
34
22
  ### When to use
@@ -789,7 +777,7 @@ The full grammar, the merge rules and the global map are in the
789
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).
790
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`.
791
779
 
792
- - `BbColorPalette` _(this component)_ — its own template binds: `swatch` → `button.bb-color-palette__swatch`, `root` → `BbOffCanvas`, `panel` → `div`, `panel` → `CommonPopover`, `root` → `CommonPopover`; 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)
793
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`
794
782
  - `CloseButton` _(internal — not importable, reach it through `BbOffCanvas`)_ — documented CSS variables: `--size`, `--p`
795
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,21 +17,9 @@
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:root` | the root of `BbOffCanvas` | `BbOffCanvas` ([contract](./BbOffCanvas.md)) |
21
20
  | `pt:panel` | the root of `CommonPopover` | `CommonPopover` _(internal)_ |
22
- | `pt:root` | the root of `CommonPopover` | `CommonPopover` _(internal)_ |
23
21
  | `pt:sheet` | `pt:root` of `BbOffCanvas` | `BbOffCanvas` ([contract](./BbOffCanvas.md)) |
24
22
 
25
- **CSS variables you can set through those parts** — declared deeper in the tree, so set one on the part that reads it (`pt:<part>="[--name:value]"`), never on `BbDatePicker`'s root:
26
-
27
- | Variable | Set through | Declared by | What it is |
28
- | --- | --- | --- | --- |
29
- | `--stack-x` | `pt:root` | `BbOffCanvas` | Inward shift applied to a parent panel while a child is stacked on top. |
30
- | `--stack-fill` | `pt:root` | `BbOffCanvas` | Length of the pad (see `::after`) that fills from the panel's anchored edge out to the screen edge, so no empty band shows when a descendant is dragged away or shrinks. |
31
- | `--stack-transition-duration` | `pt:root` | `BbOffCanvas` | Duration for the stack shift + pad. Zeroed while a peer resizes so parents track the live size instead of lagging behind a 250ms animation. |
32
- | `--px` | `pt:root` | `BbOffCanvas` | Axis split of --bb-panel-p: --px (inline) / --py (block), each branching off it. Set the pair only when the axes differ; setting --bb-panel-p alone keeps them equal. Local on this root class (not :roo… |
33
- | `--close-size` | `pt:root` | `BbOffCanvas` | Shared by the close control and by the space the title reserves for it, * so the two can never drift apart. |
34
-
35
23
  ## Usage & Guidelines
36
24
 
37
25
  ### When to use
@@ -221,6 +209,12 @@ props with `offCanvasProps`). Position the desktop popover with `placement`,
221
209
  `offset`, `padding`, `boundary`, and `disableFlip` — the same knobs as the other
222
210
  overlays. Escape and backdrop clicks close it; focus returns to the activator.
223
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
+
224
218
  ### The `v-bb-date` directive
225
219
 
226
220
  For the leanest case — a date cell in a table where you don't want a component
@@ -388,7 +382,7 @@ and digit typeahead; the time rail exposes labelled columns. Always pass a
388
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. |
389
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… |
390
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… |
391
- | `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 ✕ … |
392
386
  | `offset` | `number \| undefined` | `4` | | Space the popover keeps from the activator. |
393
387
  | `padding` | `number \| undefined` | | | Minimum empty space to keep from the edge of the page. |
394
388
  | `placement` | `Placement \| undefined` | | | Position of the popover relative to the activator/anchor. |
@@ -446,7 +440,7 @@ Set these on the element, or on a class you put on it, to retune this component
446
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).
447
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`.
448
442
 
449
- - `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`, `root` → `BbOffCanvas`, `panel` → `div`, `panel` → `CommonPopover`, `root` → `CommonPopover`; 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)
450
444
  - `BbBaseButton` _(public — [contract](./BbBaseButton.md))_ — its own pt parts (`BbBaseButton`): `root` → `RouterComponent`, `root` → `a`, `root` → `component`; also mounts `RouterComponent`
451
445
  - `CommonTimeSelector` _(internal — not importable, reach it through `BbDatePicker`)_ — documented CSS variables: `--time-mark`; also mounts `BbBaseButton`
452
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`
@@ -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.
@@ -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: '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)
946
- - `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`, `root` → `BbOffCanvas`, `panel` → `div`, `panel` → `CommonPopover`, `root` → `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`
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).
@@ -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: 'panel', 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`, `panel` → `div.bb-select-popover`, `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`
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`)_
@@ -1617,7 +1617,7 @@ Set these on the element, or on a class you put on it, to retune this component
1617
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).
1618
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`.
1619
1619
 
1620
- - `BbSelectPopover` _(this component)_ — its own template binds: `input` → `input.bb-select-popover__search-input`, `clear` → `ClearableButton`, `root` → `BbOffCanvas`, `panel` → `div.bb-select-popover`, `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
+ - `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)
1621
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`
1622
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`
1623
1623
  - `CloseButton` _(internal — not importable, reach it through `BbOffCanvas`)_ — documented CSS variables: `--size`, `--p`
package/dist/ai/BbTag.md CHANGED
@@ -560,8 +560,6 @@ Set these on the element, or on a class you put on it, to retune this component
560
560
  | Property | Set on | Default | What it is |
561
561
  | --- | --- | --- | --- |
562
562
  | `--compensation-multiplier` | `.bb-tag__field` | `0.3` | Fraction of the shell's inner padding the chip row is pulled back by when no prepend icon precedes it (see the negative margin below). |
563
- | `--inner-h` | `.bb-tag__field` | `max( calc(var(--bb-leading) + var(--bb-input-py) * 2), calc(var(--bb-input-h) - …` | The first chip row's height: the tallest of one line plus its vertical padding, the input height less its borders, and the icon box. Feeds `--floating-py` and nothing else. |
564
- | `--floating-py` | `.bb-tag__field` | `calc((var(--inner-h) - var(--bb-input-icon)) / 2)` | Top offset for centring icons and affixes on that first row — the same value BbTextarea uses for that. Nothing in the library reads it, so this and the compact override below are currently inert. |
565
563
  | `--border-color` | `pt:box` | `per variant` | The resting border, at the fixed --bb-border-w. Errors and warnings paint their frame over it, so `pt:box="[--border-color:…]"` recolours the rest without hiding the state; a plain `border-*` utility on the base pt:box would hide it (ESLint… |
566
564
 
567
565
  ## Component tree
@@ -511,8 +511,12 @@ The native attributes that only mean something on the input itself —
511
511
  `maxlength`, `minlength`, `pattern`, `spellcheck`, `autocapitalize`,
512
512
  `autocorrect`, `enterkeyhint`, `list`, `form`, `dirname` — go straight to the
513
513
  native `<input>` (the same holds for BbTextarea, BbNumberInput, BbTag and
514
- BbColorInput, where `wrap` joins them on the textarea). Any other attribute
515
- you set lands on the field's outer element; reach the input with
514
+ BbColorInput, where `wrap` joins them on the textarea). The controls without
515
+ a text input route only what their native control reads: BbSelect sends
516
+ `form` to its hidden inputs, BbDatePickerInput and BbTimePickerInput send
517
+ `form`, `spellcheck`, `autocapitalize`, `autocorrect` and `enterkeyhint` to
518
+ every segment (each segment keeps its own `maxlength` and parsing). Any other
519
+ attribute you set lands on the field's outer element; reach the input with
516
520
  `pt:input="{ attrs: { … } }"`, which also wins over the attributes above.
517
521
 
518
522
  **An OTP field: text type, numeric keyboard, masked**
@@ -14,22 +14,10 @@
14
14
 
15
15
  | pt part | Lands on | In |
16
16
  | --- | --- | --- |
17
- | `pt:root` | the root of `BbOffCanvas` | `BbOffCanvas` ([contract](./BbOffCanvas.md)) |
18
17
  | `pt:panel` | the root of `CommonPopover` | `CommonPopover` _(internal)_ |
19
- | `pt:root` | the root of `CommonPopover` | `CommonPopover` _(internal)_ |
20
18
  | `pt:sheet` | `pt:root` of `BbOffCanvas` | `BbOffCanvas` ([contract](./BbOffCanvas.md)) |
21
19
  | `pt:item` | the root of `BbBaseButton` | `BbBaseButton` ([contract](./BbBaseButton.md)) |
22
20
 
23
- **CSS variables you can set through those parts** — declared deeper in the tree, so set one on the part that reads it (`pt:<part>="[--name:value]"`), never on `BbTimePicker`'s root:
24
-
25
- | Variable | Set through | Declared by | What it is |
26
- | --- | --- | --- | --- |
27
- | `--stack-x` | `pt:root` | `BbOffCanvas` | Inward shift applied to a parent panel while a child is stacked on top. |
28
- | `--stack-fill` | `pt:root` | `BbOffCanvas` | Length of the pad (see `::after`) that fills from the panel's anchored edge out to the screen edge, so no empty band shows when a descendant is dragged away or shrinks. |
29
- | `--stack-transition-duration` | `pt:root` | `BbOffCanvas` | Duration for the stack shift + pad. Zeroed while a peer resizes so parents track the live size instead of lagging behind a 250ms animation. |
30
- | `--px` | `pt:root` | `BbOffCanvas` | Axis split of --bb-panel-p: --px (inline) / --py (block), each branching off it. Set the pair only when the axes differ; setting --bb-panel-p alone keeps them equal. Local on this root class (not :roo… |
31
- | `--close-size` | `pt:root` | `BbOffCanvas` | Shared by the close control and by the space the title reserves for it, * so the two can never drift apart. |
32
-
33
21
  ## Usage & Guidelines
34
22
 
35
23
  ### When to use
@@ -158,6 +146,12 @@ props with `offCanvasProps`). Position the desktop popover with `placement`,
158
146
  `offset`, `padding`, `boundary`, and `disableFlip` — the same knobs as the other
159
147
  overlays. Escape and backdrop clicks close it; focus returns to the activator.
160
148
 
149
+ The sheet can be **dragged down to dismiss** and shows **no ✕** — picking,
150
+ drag, backdrop tap and Escape close it. The time wheels are no-drag zones: a
151
+ swipe there scrolls the wheel and never moves the sheet, even at the top of the
152
+ list. `offCanvasProps` is spread over those defaults: `{ hideClose: false }`
153
+ brings the ✕ back, `{ draggable: false }` pins the sheet.
154
+
161
155
  ### The `v-bb-time` directive
162
156
 
163
157
  For the leanest case — a time cell in a schedule table where you don't want a
@@ -285,7 +279,7 @@ typeahead. Always pass a `label` when the trigger is an unlabelled cell or icon.
285
279
  | `max` | `string \| undefined` | | | Maximum selectable time in `HH:mm` format. Values outside the pattern throw during setup to surface configuration mistakes. |
286
280
  | `min` | `string \| undefined` | | | Minimum selectable time in `HH:mm` format. Values outside the pattern throw during setup to surface configuration mistakes. |
287
281
  | `modelValue` | `string \| string[] \| null` | | yes | v-model value: `null` for empty, a 24-hour `HH:mm` (or `HH:mm:ss` with `seconds`) string, or a two-element `[start, end]` array when `range` is true. |
288
- | `offCanvasProps` | `Partial<BbOffCanvasProps> \| undefined` | | | Extra props forwarded to the `BbOffCanvas` sheet when adaptive on mobile. |
282
+ | `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 never drag it) and hides its ✕ (picking, backdrop… |
289
283
  | `offset` | `number \| undefined` | `4` | | Space the popover keeps from the activator. |
290
284
  | `padding` | `number \| undefined` | | | Minimum empty space to keep from the edge of the page. |
291
285
  | `placement` | `Placement \| undefined` | | | Position of the popover relative to the activator/anchor. |
@@ -319,7 +313,7 @@ typeahead. Always pass a `label` when the trigger is an unlabelled cell or icon.
319
313
  - **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 `BbTimePicker`'s root, where the node's own declaration masks it (design-tokens guide, _Overriding one from a consumer app_, rule 0).
320
314
  - Listed nodes are the ones `BbTimePicker`'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`.
321
315
 
322
- - `BbTimePicker` _(this component)_ — its own template binds: `root` → `BbOffCanvas`, `panel` → `div`, `panel` → `CommonPopover`, `root` → `CommonPopover`; hands `BbOffCanvas` the pt map `{ sheet: 'root' }` (ours → theirs)
316
+ - `BbTimePicker` _(this component)_ — its own template binds: `panel` → `div`, `panel` → `CommonPopover`; hands `BbOffCanvas` the pt map `{ sheet: 'root' }` (ours → theirs)
323
317
  - `CommonTimeSelector` _(internal — not importable, reach it through `BbTimePicker`)_ — `BbTimePicker`'s pt parts land here: `item` → `BbBaseButton`; documented CSS variables: `--time-mark`
324
318
  - `BbBaseButton` _(public — [contract](./BbBaseButton.md))_ — its own pt parts (`BbBaseButton`): `root` → `RouterComponent`, `root` → `a`, `root` → `component`; also mounts `RouterComponent`
325
319
  - `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`
@@ -101,6 +101,13 @@ is required.
101
101
  <BbTimePickerInput v-model="state.slotAt" ampm :step="15" label="Pickup slot" />
102
102
  ```
103
103
 
104
+ Native attributes that describe typing — `spellcheck`, `autocapitalize`,
105
+ `autocorrect`, `enterkeyhint` — and `form` go to **every segment** (each one
106
+ is a real `<input>` that posts its own `<name>-<field>`); `maxlength`,
107
+ `pattern` and `list` are not routed, because each segment sets its own length
108
+ and parses its own digits. Any other attribute lands on the field root; a
109
+ `pt:input` attribute reaches every segment and wins over the routed ones.
110
+
104
111
  ### Bounds & ranges
105
112
 
106
113
  `min` / `max` (`HH:mm`) clamp typed times when interaction ends — the value
@@ -126,7 +133,9 @@ end]`; typing an inverted pair swaps it on blur with the usual
126
133
 
127
134
  The popover follows the family's adaptive pattern: on mobile (with the global
128
135
  `config.adaptive`, or the `adaptive` prop) the columns open in a bottom sheet
129
- (`offCanvasProps` forwards extras). `disableWriting` (`true` / `'mobile'` /
136
+ that drags down to dismiss and shows no ✕ (the wheels never drag it;
137
+ `offCanvasProps` is spread over those defaults — `{ hideClose: false }` brings
138
+ the ✕ back). `disableWriting` (`true` / `'mobile'` /
130
139
  `'desktop'`) turns off typing per platform — the columns then carry the
131
140
  interaction.
132
141
 
@@ -291,7 +300,7 @@ Messages _also_ render in an `aria-live="polite"` region.
291
300
  | `min` | `string \| undefined` | | | Minimum selectable time in `HH:mm` format. Values outside the pattern throw during setup to surface configuration mistakes. |
292
301
  | `modelValue` | `string \| string[] \| null` | | yes | v-model value: `null` for empty, a 24-hour `HH:mm` (or `HH:mm:ss` with `seconds`) string, or a two-element array when `range` is true. |
293
302
  | `name` | `string \| undefined` | | | Defines the name of the input. |
294
- | `offCanvasProps` | `Partial<BbOffCanvasProps> \| undefined` | | | Extra props forwarded to the `BbOffCanvas` sheet when `adaptive` is active on mobile (e.g. `title`, `size`, `persistent`). |
303
+ | `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 never drag it) and hides its ✕ (picking, backdrop… |
295
304
  | `persistentHint` | `boolean \| undefined` | `false` | | Keeps the hint displayed. |
296
305
  | `placeholder` | `string \| undefined` | | | String displayed when there's no data. |
297
306
  | `prepend:icon` | `string \| undefined` | | | Name of the icon to be added at the start of the input. |
@@ -355,7 +364,7 @@ Set these on the element, or on a class you put on it, to retune this component
355
364
  - **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 `BbTimePickerInput`'s root, where the node's own declaration masks it (design-tokens guide, _Overriding one from a consumer app_, rule 0).
356
365
  - Listed nodes are the ones `BbTimePickerInput`'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`.
357
366
 
358
- - `BbTimePickerInput` _(this component)_ — its own template binds: `input` → `input.bb-segmented-field__field`, `suffix` → `span.bb-field-input__suffix`, `panel` → `div`, `panel` → `CommonPopover`; hands `BbOffCanvas` the pt map `{ sheet: 'root' }` (ours → theirs)
367
+ - `BbTimePickerInput` _(this component)_ — its own template binds: `controlAttrs` → `input.bb-segmented-field__field`, `input` → `input.bb-segmented-field__field`, `suffix` → `span.bb-field-input__suffix`, `panel` → `div`, `panel` → `CommonPopover`; hands `BbOffCanvas` the pt map `{ sheet: 'root' }` (ours → theirs)
359
368
  - `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`
360
369
  - `CloseButton` _(internal — not importable, reach it through `BbOffCanvas`)_ — documented CSS variables: `--size`, `--p`
361
370
  - `CommonField` _(internal — not importable, reach it through `BbTimePickerInput`)_ — `BbTimePickerInput`'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`
@@ -57,6 +57,14 @@ import { BbToast } from 'bitboss-ui';
57
57
  </script>
58
58
  ```
59
59
 
60
+ **Areas with their own look.** A toast takes the passthrough scope and the
61
+ tokens of the place its HOST is mounted, not of the code that fired it. When
62
+ the app is split into areas that each wrap their pages in `<BbPtScope>`
63
+ ([passthrough guide](./guides/passthrough.md) § Named scopes), mount one
64
+ `<BbToast />` inside each area's layout, within its scope, and none at the app
65
+ root. That still means one host at a time — as long as **every** page renders
66
+ inside exactly one of those layouts.
67
+
60
68
  On Nuxt the host goes in `app.vue`; on Inertia, in the `createInertiaApp`
61
69
  render root — one mount above the router, so every page shares it and no page
62
70
  mounts its own. **Every example on this page mounts its own `<BbToast />` only
@@ -736,8 +744,8 @@ The full grammar, the merge rules and the global map are in the
736
744
 
737
745
  - **No host, no toasts**: `toast(...)` without a mounted `<BbToast />`
738
746
  enqueues silently — and the messages never expire, because the dismiss timer
739
- lives inside the host. Mount exactly one host, at the app root — never one per
740
- page or per component.
747
+ lives inside the host. Mount exactly one host at a time: at the app root
748
+ (or one per area layout, see _Setup_) — never one per page or per component.
741
749
  - Don't hand-roll notification markup or timers; between variants, upsert,
742
750
  portals, and persistence the component covers it.
743
751
  - Don't put must-act information only in a toast — it self-dismisses.