bitboss-ui 3.0.0-beta.52 → 3.0.0-beta.53

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 (86) hide show
  1. package/bin/bitboss-ui-mcp.mjs +16 -8
  2. package/dist/ai/BbBadge.md +3 -2
  3. package/dist/ai/BbColorPalette.md +4 -3
  4. package/dist/ai/BbDatePicker.md +1 -1
  5. package/dist/ai/BbDropdown.md +6 -2
  6. package/dist/ai/BbForm.md +25 -17
  7. package/dist/ai/BbHoverCard.md +1 -1
  8. package/dist/ai/BbPopover.md +5 -3
  9. package/dist/ai/BbSelectPopover.md +1 -1
  10. package/dist/ai/BbTable.md +120 -28
  11. package/dist/ai/BbTimePicker.md +1 -1
  12. package/dist/ai/BbTooltip.md +1 -1
  13. package/dist/ai/CommonPopover.md +1 -1
  14. package/dist/ai/changelog.json +52 -3
  15. package/dist/ai/components.json +14 -14
  16. package/dist/ai/guides/component-picker.md +1 -1
  17. package/dist/ai/guides/migration/from-async-validator.md +60 -46
  18. package/dist/ai/guides/migration/v2-to-v3.md +24 -0
  19. package/dist/ai/guides/options-items-playbook.md +5 -5
  20. package/dist/ai/guides/validated-forms.md +19 -8
  21. package/dist/ai/helpers/inertia/manifest.json +1 -1
  22. package/dist/ai/manifest/components/BbBadge.json +1 -1
  23. package/dist/ai/manifest/components/BbColorPalette.json +1 -1
  24. package/dist/ai/manifest/components/BbDatePicker.json +1 -1
  25. package/dist/ai/manifest/components/BbDropdown.json +1 -1
  26. package/dist/ai/manifest/components/BbHoverCard.json +1 -1
  27. package/dist/ai/manifest/components/BbPopover.json +1 -1
  28. package/dist/ai/manifest/components/BbSelectPopover.json +1 -1
  29. package/dist/ai/manifest/components/BbTable.json +4 -4
  30. package/dist/ai/manifest/components/BbTable.tree.json +18 -0
  31. package/dist/ai/manifest/components/BbTimePicker.json +1 -1
  32. package/dist/ai/manifest/components/BbTooltip.json +1 -1
  33. package/dist/ai/manifest/components/CommonPopover.json +1 -1
  34. package/dist/ai/manifest/index.json +2 -2
  35. package/dist/ai/manifest/types.api.json +1 -1
  36. package/dist/ai/recipes/inertia/approvals-inbox.md +1 -1
  37. package/dist/ai/recipes/nuxt/approvals-inbox.md +1 -1
  38. package/dist/ai/recipes/vue/approvals-inbox.md +1 -1
  39. package/dist/ai/source/BbBadge.md +3 -4
  40. package/dist/ai/source/BbBadgeButton.md +3 -4
  41. package/dist/ai/source/BbColorPalette.md +3 -1
  42. package/dist/ai/source/BbDatePicker.md +4 -1
  43. package/dist/ai/source/BbDropdown.md +5 -3
  44. package/dist/ai/source/BbDropdownGroup.md +5 -3
  45. package/dist/ai/source/BbHoverCard.md +3 -2
  46. package/dist/ai/source/BbHoverCardPortal.md +3 -2
  47. package/dist/ai/source/BbPopover.md +3 -2
  48. package/dist/ai/source/BbPopoverPortal.md +3 -2
  49. package/dist/ai/source/BbSelectPopover.md +3 -1
  50. package/dist/ai/source/BbTable.md +315 -59
  51. package/dist/ai/source/BbTimePicker.md +4 -1
  52. package/dist/ai/source/BbTooltip.md +3 -2
  53. package/dist/ai/source/CommonPopover.md +11 -8
  54. package/dist/components/BbBadge/types.d.ts +3 -4
  55. package/dist/components/BbColorPalette/types.d.ts +3 -1
  56. package/dist/components/BbDatePicker/types.d.ts +4 -1
  57. package/dist/components/BbDropdown/types.d.ts +5 -3
  58. package/dist/components/BbHoverCard/types.d.ts +3 -2
  59. package/dist/components/BbPopover/types.d.ts +3 -2
  60. package/dist/components/BbSelectPopover/types.d.ts +3 -1
  61. package/dist/components/BbTable/BbTable.vue_vue_type_script_setup_true_lang.js +931 -891
  62. package/dist/components/BbTable/BbTableDataRow.js +76 -78
  63. package/dist/components/BbTable/types.d.ts +21 -6
  64. package/dist/components/BbTable/useRowReorder.js +217 -195
  65. package/dist/components/BbTable/utils.d.ts +21 -0
  66. package/dist/components/BbTable/utils.js +19 -16
  67. package/dist/components/BbTable/warroom/harness.d.ts +7 -0
  68. package/dist/components/BbTimePicker/types.d.ts +4 -1
  69. package/dist/components/BbTooltip/types.d.ts +3 -2
  70. package/dist/components/CommonPopover/CommonPopover.vue_vue_type_script_setup_true_lang.js +1 -1
  71. package/dist/components/CommonPopover/types.d.ts +4 -4
  72. package/dist/composables/useBaseOptions.d.ts +3 -3
  73. package/dist/composables/useBaseOptions.js +11 -11
  74. package/dist/composables/useItemText.d.ts +5 -0
  75. package/dist/composables/useItemText.js +14 -14
  76. package/dist/composables/useItemValue.js +9 -9
  77. package/dist/composables/useItemsGetter.js +55 -51
  78. package/dist/composables/useSegmentedFields.js +6 -1
  79. package/dist/composables/useTableWidthContext.d.ts +6 -0
  80. package/dist/composables/useTableWidthContext.js +2 -1
  81. package/dist/llms-full.txt +281 -124
  82. package/dist/llms-medium.txt +1 -1
  83. package/dist/styles.css +2 -2
  84. package/dist/utils/versionCheck.js +1 -1
  85. package/package.json +2 -1
  86. package/scripts/lib/hand-roll-hints.mjs +11 -2
@@ -2724,16 +2724,24 @@ function listChanges({
2724
2724
  guide: doc.guide,
2725
2725
  count: all.length,
2726
2726
  releases,
2727
+ // Zero counts are left out (a missing key is 0): the map grows by a
2728
+ // release each beta and must stay one small answer (beta.53 hit the
2729
+ // 3 000-char budget with every bucket spelling out its zeros).
2727
2730
  perRelease: Object.fromEntries(
2728
- Object.entries(perRelease).sort(([a], [b]) =>
2729
- a === 'unreleased'
2730
- ? 1
2731
- : b === 'unreleased'
2732
- ? -1
2733
- : compareVersions(a, b)
2734
- )
2731
+ Object.entries(perRelease)
2732
+ .sort(([a], [b]) =>
2733
+ a === 'unreleased'
2734
+ ? 1
2735
+ : b === 'unreleased'
2736
+ ? -1
2737
+ : compareVersions(a, b)
2738
+ )
2739
+ .map(([at, bucket]) => [
2740
+ at,
2741
+ Object.fromEntries(Object.entries(bucket).filter(([, n]) => n > 0)),
2742
+ ])
2735
2743
  ),
2736
- hint: 'Counts only. What a bump breaks: list_changes({ since: "<your version>" }), one line per change; from v2: since: "2". One component: { component: "BbSelect" }. Full rows: detail: "rows".',
2744
+ hint: 'Counts only (a missing count is 0). What a bump breaks: list_changes({ since: "<your version>" }), one line per change; from v2: since: "2". One component: { component: "BbSelect" }. Full rows: detail: "rows".',
2737
2745
  };
2738
2746
  }
2739
2747
 
@@ -70,7 +70,8 @@ For a small, closed status set (paid / pending / overdue, plan tiers), register
70
70
  the soft palette from
71
71
  [design language guide](./guides/design-language.md) § Using color
72
72
  (`soft-gray` / `soft-blue` / `soft-green` / `soft-amber` / `soft-red`) and style
73
- `.bb-badge--<name>` in your project stylesheet. Never invent `variant="success"`
73
+ `.bb-badge--<name>` in your project stylesheet. Type a status map as
74
+ `Record<Status, BadgeVariantType>`. Never invent `variant="success"`
74
75
  — that name is not built-in and ships no CSS. The example below uses the soft
75
76
  names: in your app it type-checks only after the `badgeVariants` registration
76
77
  and renders styled only with that CSS — both are in the linked section.
@@ -863,7 +864,7 @@ A `pt` value written in `<script>` (a constant, a preset, a wrapper's
863
864
  | `loading` | `boolean \| undefined` | `false` | | Shows a spinner in place of the leftmost icon (`icon` or `prepend:icon`; the `append:icon` when it is the only one; else the leading slot), as `BbButton` does, with a hidden loading announcement. |
864
865
  | `prepend:icon` | `string \| undefined` | | | Icon rendered before the label. |
865
866
  | `size` | `'xs'` \| `'sm'` \| `'md'` \| `'lg'` \| `'xl'` \| `'2xl'` | `"md"` | | Preset size of the badge. |
866
- | `variant` | `'outline'` \| `'primary'` \| `'destructive'` \| `'secondary'` \| `'none'` | `"primary"` | | Visual variant: `primary`, `secondary`, `destructive`, or `outline`. Register more via the vite plugin `badgeVariants` option and style `.bb-badge--<variant>` (set `--bg` / `--fg`). `'none'` renders no variant class — an escape hatch for a one-off look set through `--bg` / `--fg` on the element. |
867
+ | `variant` | `'outline'` \| `'primary'` \| `'destructive'` \| `'secondary'` \| `'none'` | `"primary"` | | Visual variant: `primary`, `secondary`, `destructive`, or `outline`. Status colours are a registration (vite plugin `badgeVariants`, the `soft-*` palette in design-language.md) styled as `.bb-badge--<variant>`. `'none'` renders no variant class: set `--bg` / `--fg` on the element. |
867
868
 
868
869
  ## Passthrough parts and states
869
870
 
@@ -447,8 +447,9 @@ The float itself is tuned with the popover props:
447
447
  unless you set `disable-flip`.
448
448
  - `offset` (default 4) — gap between anchor and popover; `padding` (default 6) —
449
449
  minimum space kept from the viewport edge.
450
- - `boundary` — constrain the popover inside an element (ref or CSS selector),
451
- e.g. a scrolling panel.
450
+ - `boundary` — keep the popover inside an element (ref or CSS selector)
451
+ alongside its trigger, e.g. a scrolling panel's width; it may open past the
452
+ edge away from the trigger, and only the viewport flips it.
452
453
  - `transition-duration` (default 250ms) and `eager` — render the palette content
453
454
  before it is first shown (useful for SSR/measurement; off by default so the
454
455
  body mounts lazily).
@@ -757,7 +758,7 @@ A `pt` value written in `<script>` (a constant, a preset, a wrapper's
757
758
  | `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 to the global `config.adaptive`. |
758
759
  | `alpha` | `boolean \| undefined` | `false` | | Enable the alpha channel. The picker shows an opacity slider and emits `#RRGGBBAA` hex8 values. |
759
760
  | `anchor` | `ElementOrComponentRef \| undefined` | | | Element or component ref the popover positions itself relative to. Defaults to the activator element when omitted, allowing the popover to be anchored to a larger container (e.g. the full input row) while a smaller element (e.g. a color dot) remains the click target. |
760
- | `boundary` | `ElementOrComponentRefOrSelector \| undefined` | | | Constrains the popover within a bounding element. Accepts an HTMLElement, a Vue component ref, or a CSS selector string. |
761
+ | `boundary` | `ElementOrComponentRefOrSelector \| undefined` | | | Constrains the popover within a bounding element: it stays inside it alongside its trigger (sideways for a popover above or below); away from the trigger it may pass the edge, and it flips at the viewport only. Accepts an HTMLElement, a Vue component ref, or a CSS selector string. |
761
762
  | `disabled` | `boolean \| undefined` | `false` | | Disable all interaction (activator and palette). |
762
763
  | `disableFlip` | `boolean \| undefined` | `false` | | Disables the automatic flip to the opposite side when the popover would overflow (flipping is on by default). |
763
764
  | `eager` | `boolean \| undefined` | `false` | | Renders the palette panel at mount instead of on the first open (the phone sheet's too). |
@@ -416,7 +416,7 @@ and digit typeahead; the time rail exposes labelled columns. Always pass a
416
416
  | `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`. |
417
417
  | `ampm` | `boolean \| undefined` | `false` | | 12-hour display with an AM/PM column (requires `type="datetime"`); emits stay 24h. |
418
418
  | `anchor` | `ElementOrComponentRef \| undefined` | | | Element or component ref the popover positions itself relative to. Defaults to the activator when omitted (anchor to a larger row while a smaller element stays the click target). |
419
- | `boundary` | `ElementOrComponentRefOrSelector \| undefined` | | | Constrains the popover within a bounding element or CSS selector. |
419
+ | `boundary` | `ElementOrComponentRefOrSelector \| undefined` | | | Constrains the popover within a bounding element or CSS selector: sideways only, alongside the trigger; it flips at the viewport. |
420
420
  | `disabled` | `boolean \| undefined` | `false` | | Disables the activator and the calendar. |
421
421
  | `disableFlip` | `boolean \| undefined` | `false` | | Disable the automatic flip to the opposite side on overflow. |
422
422
  | `eager` | `boolean \| undefined` | `false` | | Render popover content before it is first shown. |
@@ -1600,7 +1600,11 @@ const items: BbDropdownItem[] = [
1600
1600
  `placement` is `'cursor'`.
1601
1601
  - `offset` (gap from the anchor), `padding` (minimum space kept from the
1602
1602
  viewport edge), and `boundary` (an element, component ref, or CSS selector
1603
- that confines the panel) tune positioning; `eager` pre-renders the panel
1603
+ the panel stays inside alongside its trigger; it may still open past the
1604
+ edge away from the trigger, and only the viewport flips it) tune positioning.
1605
+ Pass `boundary` a `useTemplateRef` or a selector, not `$refs.x`: `$refs` is
1606
+ not reactive, so a menu in a table cell rendered before the ref was set keeps
1607
+ no boundary until that row happens to re-render. `eager` pre-renders the panel
1604
1608
  before first open; `transitionDuration` controls the open/close animation.
1605
1609
  - The menu closes itself on outside click/focus, on `Escape`, when another
1606
1610
  dropdown opens, and when the activator scrolls out of view. `disabled`
@@ -2170,7 +2174,7 @@ A `pt` value written in `<script>` (a constant, a preset, a wrapper's
2170
2174
  | `activator` | `Record<string, any> \| HTMLElement \| null \| undefined` | | | An external activator element or component ref: the activator slot is not rendered, and the listeners and ARIA (`aria-haspopup` / `aria-expanded` / `aria-controls`) are attached to it; don't add your own. |
2171
2175
  | `adaptive` | `boolean \| undefined` | ``config.adaptive` (`true`)` | | On mobile (below `config.mobileMaxWidth`), renders the menu as a bottom sheet that drills into submenus one level at a time instead of hover flyouts; slots and selection are unchanged. Unset: the global `config.adaptive`. |
2172
2176
  | `anchor` | `Record<string, any> \| HTMLElement \| null \| undefined` | `the activator element` | | The element the panel positions against when it should differ from the activator (a wrapper the activator is part of); an HTMLElement or component ref. It also drives a percentage `width`. Ignored with `placement="cursor"`. |
2173
- | `boundary` | `string \| Record<string, any> \| HTMLElement \| null \| undefined` | | | Constrains the dropdown within a bounding element. Accepts an HTMLElement, a Vue component ref, or a CSS selector string. |
2177
+ | `boundary` | `string \| Record<string, any> \| HTMLElement \| null \| undefined` | | | Keeps the panel inside this element alongside its trigger (sideways for a menu above or below); away from the trigger it may pass the edge, and only the viewport flips it. An HTMLElement, a component ref or a CSS selector: a `useTemplateRef`, never `$refs.x` (not reactive). |
2174
2178
  | `compact` | `boolean \| undefined` | `false` | | Compact density, the `BbSelect` ladder: flyout rows 28px → 24px, sheet rows 44px → 36px (a sheet row stays a touch target). The label size does not change. |
2175
2179
  | `disabled` | `boolean \| undefined` | `false` | | Disables the component |
2176
2180
  | `eager` | `boolean \| undefined` | `false` | | Renders the menu panel at mount instead of on the first open (the phone sheet's too), and keeps its rows after a close. Without it the rows mount on each open and go once the menu has closed. |
package/dist/ai/BbForm.md CHANGED
@@ -125,21 +125,26 @@ import {
125
125
  useBbFormContext,
126
126
  } from 'bitboss-ui';
127
127
 
128
- const signup = z
129
- .object({
130
- // An emptied text field holds `null`: the type's message covers it.
131
- name: z.string('Enter your name').trim().min(1, 'Enter your name'),
132
- // A transform: `@submit` receives the lower-cased address.
133
- email: z.email('Enter a valid email').toLowerCase(),
134
- password: z.string('Choose a password').min(8, 'At least 8 characters'),
135
- confirm: z.string('Repeat the password'),
136
- terms: z.literal(true, 'Accept the terms to continue'),
137
- })
138
- // A cross-field rule: `path` puts the message on the second field.
139
- .refine((form) => form.password === form.confirm, {
140
- message: 'The passwords do not match',
141
- path: ['confirm'],
142
- });
128
+ const fields = z.object({
129
+ // An emptied text field holds `null`: the type's message covers it.
130
+ name: z.string('Enter your name').trim().min(1, 'Enter your name'),
131
+ // A transform: `@submit` receives the lower-cased address.
132
+ email: z.email('Enter a valid email').toLowerCase(),
133
+ password: z.string('Choose a password').min(8, 'At least 8 characters'),
134
+ confirm: z.string('Repeat the password'),
135
+ terms: z.literal(true, 'Accept the terms to continue'),
136
+ });
137
+
138
+ // A cross-field rule: `path` puts the message on the second field, `when`
139
+ // runs it as soon as the two passwords parse (zod otherwise skips it while
140
+ // any other field fails).
141
+ const signup = fields.refine((form) => form.password === form.confirm, {
142
+ message: 'The passwords do not match',
143
+ path: ['confirm'],
144
+ when: (payload) =>
145
+ fields.pick({ password: true, confirm: true }).safeParse(payload.value)
146
+ .success,
147
+ });
143
148
 
144
149
  const form = useBbFormContext('signup');
145
150
  const created = ref<z.output<typeof signup> | null>(null);
@@ -165,7 +170,9 @@ What you get from the one prop:
165
170
  `name="lines[0][qty]"` (brackets read as dots). A field with no `name` is
166
171
  named after its label, `Full name` → `fullname`, so schema-driven forms set
167
172
  `name` on every field. A cross-field rule
168
- reaches the right field through its `path` (`path: ['confirm']` above).
173
+ reaches the right field through its `path` (`path: ['confirm']` above);
174
+ its `when` lets it run while other fields still fail (a zod object
175
+ refinement is skipped until the whole object parses).
169
176
  - **Submit is gated** by the schema, async refinements included, exactly as it
170
177
  is by field rules.
171
178
  - **`@submit` receives the schema's output.** Transforms and coercions have
@@ -1176,7 +1183,8 @@ first (`JSON.parse(JSON.stringify(form.values.value))`).
1176
1183
 
1177
1184
  ### `resetForm()` clears the fields, and your model
1178
1185
 
1179
- Resetting publishes the new value back through each field's
1186
+ `resetForm()` is the slot's name; from outside the form the same reset is
1187
+ `useBbFormContext(id).reset()` (the handle has no `resetForm`). Resetting publishes the new value back through each field's
1180
1188
  `update:modelValue` (and writes it into the object bound with `:model`), so
1181
1189
  the control, the form's own state and whatever ref you bound all agree
1182
1190
  afterwards.
@@ -463,7 +463,7 @@ value written in `<script>` is typed as `BbHoverCardProps['pt']`.
463
463
  | --- | --- | --- | --- | --- |
464
464
  | `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: `content`, `footer`, `header`, `panel`, `root`. States: `open`. What each one is: _Passthrough parts and states_ below. `pt` is the object form with the same keys minus the prefix (`{ icon: '…', 'icon:loading': '…' }`). See `guides/passthrough.md`. In `<script>` a `pt` value is typed `BbHoverCardProps['pt']` (`PtValue` is not exported): § Typing `pt` in `<script>`. |
465
465
  | `activator` | `ElementOrComponentRef \| undefined` | | | External activator element or component ref. When provided, the activator slot is not rendered and the hover / focus listeners are attached programmatically to the referenced element. |
466
- | `boundary` | `ElementOrComponentRefOrSelector \| undefined` | | | Constrains the card within a bounding element. When provided, the card will not overflow this container's bounds (e.g. a sidebar). Accepts an HTMLElement, a Vue component ref, or a CSS selector string. |
466
+ | `boundary` | `ElementOrComponentRefOrSelector \| undefined` | | | Constrains the card within a bounding element: it stays inside it alongside its trigger (sideways for a card above or below); away from the trigger it may pass the edge, and it flips at the viewport only. Accepts an HTMLElement, a Vue component ref, or a CSS selector string. |
467
467
  | `delay` | `number \| undefined` | `350` | | Milliseconds the pointer (or keyboard focus) rests on the activator before the card shows; longer than BbTooltip's, so passing over does not open it. Closing has a fixed grace (guide § Timing and the safe zone). |
468
468
  | `disabled` | `boolean \| undefined` | `false` | | Disables the component. Disabling an open card closes it. |
469
469
  | `eager` | `boolean \| undefined` | `false` | | Renders the card's content at mount instead of on the first open. |
@@ -472,8 +472,10 @@ Fine-tune the geometry with:
472
472
  - `offset` — gap (px) between the activator and the panel (default `4`).
473
473
  - `padding` — minimum gap (px) the panel keeps from the page edge (default
474
474
  `10`).
475
- - `boundary` — an element, ref, or CSS selector that constrains the panel so it
476
- never escapes a scrolling region or sidebar.
475
+ - `boundary` — an element, ref, or CSS selector the panel stays inside
476
+ alongside its trigger (a sidebar's width, a table's). Away from the trigger
477
+ it may pass the edge: a panel under a table's last row opens below it
478
+ rather than flipping, and only the viewport flips it.
477
479
 
478
480
  `BbPopover` is a floating **panel**, not a speech bubble — it never renders an
479
481
  arrow. Reach for `BbTooltip` when you want an arrow pointing back at the trigger
@@ -871,7 +873,7 @@ A `pt` value written in `<script>` (a constant, a preset, a wrapper's
871
873
  | `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: `content`, `footer`, `header`, `panel`, `root`, `sheet`. States: `open`. What each one is: _Passthrough parts and states_ below. `pt` is the object form with the same keys minus the prefix (`{ icon: '…', 'icon:loading': '…' }`). See `guides/passthrough.md`. In `<script>` a `pt` value is typed `BbPopoverProps['pt']` (`PtValue` is not exported): § Typing `pt` in `<script>`. |
872
874
  | `activator` | `ElementOrComponentRef \| undefined` | | | External activator element or component ref. When provided, the activator slot is not rendered and click events are attached programmatically to the referenced element. |
873
875
  | `adaptive` | `boolean \| undefined` | ``config.adaptive` (`true`)` | | On mobile (below `config.mobileMaxWidth`), renders as a bottom sheet instead of a floating panel, with the same `header`, `default` and `footer` slots. `width` is ignored there: size the sheet with `offCanvasProps`. Unset: the global `config.adaptive`. |
874
- | `boundary` | `ElementOrComponentRefOrSelector \| undefined` | | | Constrains the popover within a bounding element. When provided, the popover will not overflow this container's bounds (e.g. a sidebar). Accepts an HTMLElement, a Vue component ref, or a CSS selector string. |
876
+ | `boundary` | `ElementOrComponentRefOrSelector \| undefined` | | | Constrains the popover within a bounding element: it stays inside it alongside its trigger (sideways for a popover above or below); away from the trigger it may pass the edge, and it flips at the viewport only. Accepts an HTMLElement, a Vue component ref, or a CSS selector string. |
875
877
  | `disabled` | `boolean \| undefined` | `false` | | Disables the component. |
876
878
  | `eager` | `boolean \| undefined` | `false` | | Renders the panel's content at mount instead of on the first open (the phone sheet's too). |
877
879
  | `focusTarget` | `string \| undefined` | | | Selector for the element that receives focus after opening. Defaults to the first focusable element inside the popover. |
@@ -1758,7 +1758,7 @@ A `pt` value written in `<script>` (a constant, a preset, a wrapper's
1758
1758
  | `ariaDescribedby` | `string \| string[] \| undefined` | | | Space-separated IDREF(s) that describe this field for assistive technologies. Accepts either a string or array of ids. |
1759
1759
  | `ariaInvalid` | `boolean \| undefined` | `undefined` | | Explicit invalid state for accessibility semantics. Falls back to `hasErrors` when not provided. |
1760
1760
  | `autocomplete` | `string \| undefined` | `"off"` | | Browser autocomplete hint for the popover search input. |
1761
- | `boundary` | `string \| Record<string, any> \| HTMLElement \| null \| undefined` | | | Constrains the popover to a specific boundary element. |
1761
+ | `boundary` | `string \| Record<string, any> \| HTMLElement \| null \| undefined` | | | Constrains the popover to a specific boundary element: it stays inside it alongside its trigger (sideways for a popover above or below); away from the trigger it may pass the edge, and it flips at the viewport only. |
1762
1762
  | `clearable` | `boolean \| undefined` | `false` | | Shows a clear button in the search field, in the lens' place while there is a query or a selection; it resets both. None without a search field. Leave it off when the activator already clears (as BbSelect's does). |
1763
1763
  | `compact` | `boolean \| undefined` | `false` | | Apply the compact density variant. |
1764
1764
  | `dependencies` | `unknown[] \| undefined` | `[]` | | Additional dependencies that trigger item reloading when changed. |
@@ -373,7 +373,7 @@ scope in `#<key>:header`. With it each name gets its own scope, as on `BbTable`.
373
373
  **Add beside a header instead of replacing it** with
374
374
  `#<key>:header:prepend` / `#<key>:header:append` — rendered before / after the
375
375
  column's existing header content (the label + sort control, or your own
376
- `#<key>:header` replacement), so a resize grip or reorder handle no longer
376
+ `#<key>:header` replacement), so a resize handle or reorder handle no longer
377
377
  costs you the built-in sort button. The table-wide pair `#header:prepend` /
378
378
  `#header:append` applies one template to every data column's header (never the
379
379
  structural select/actions cells); both forms receive the header scope above
@@ -953,6 +953,20 @@ a native `<input>` / `<select>`:
953
953
  <BbTable :items="filteredItems" :columns="columns" caption="Invoices" />
954
954
  ```
955
955
 
956
+ ```ts
957
+ // An emptied (or cleared) BbTextInput writes `null`, not '' — type it so.
958
+ const search = ref<string | null>('');
959
+ const statuses = ref<string[]>([]);
960
+ const filteredItems = computed(() => {
961
+ const q = search.value?.trim().toLowerCase() ?? '';
962
+ return invoices.value.filter(
963
+ (row) =>
964
+ (!q || row.client.toLowerCase().includes(q)) &&
965
+ (!statuses.value.length || statuses.value.includes(row.status))
966
+ );
967
+ });
968
+ ```
969
+
956
970
  Pick the shape by where the rows come from:
957
971
 
958
972
  | Your situation | The filter mechanism |
@@ -1172,7 +1186,7 @@ const sortedInvoices = computed(() => {
1172
1186
  A custom `#<key>:header` slot replaces the built-in sort button, but its scope
1173
1187
  hands you `sortOrder` and `toggleSort` so your header can keep sorting alive
1174
1188
  (render your own button and call `toggleSort`). To merely add something next
1175
- to the control — a resize grip, a filter icon — use
1189
+ to the control — a resize handle, a filter icon — use
1176
1190
  `#<key>:header:prepend/append` instead and keep the built-in button (see
1177
1191
  "Custom cells and headers"). The column-level `sorted`
1178
1192
  field only seeds the header's `aria-sort` when no live model entry exists — it
@@ -1477,7 +1491,11 @@ user can select); one the model names explicitly still shows ticked.
1477
1491
 
1478
1492
  To drive a toolbar that lives **outside** the table subtree, give the table an
1479
1493
  `id` and read `useBbTableContext(id).selected` — the handle mirrors the
1480
- table's selection both ways, so a bulk-action bar needs no prop drilling. As
1494
+ table's selection both ways, so a bulk-action bar needs no prop drilling.
1495
+ Count from `all` and `unselected` too: the header checkbox is select-all,
1496
+ which leaves `selected` empty (see [§ Single select, select-all and
1497
+ limits](#single-select-select-all-and-limits)), so a bar that reads
1498
+ `selected` alone vanishes while every row shows ticked. As
1481
1499
  everywhere in the library, the destructive bulk action is gated by
1482
1500
  `useConfirm` before it touches the data.
1483
1501
 
@@ -1566,14 +1584,27 @@ const selected = ref<string[]>([]);
1566
1584
 
1567
1585
  // Same id as the table — the handle mirrors the table's selection both ways.
1568
1586
  const ctx = useBbTableContext('member-selection', { selected: [] });
1569
- const selectedCount = computed(() => ctx.selected.value?.length ?? 0);
1570
- const clear = () => (ctx.selected.value = []);
1587
+ // The header checkbox is "select all": it sets `all` and leaves `selected`
1588
+ // empty (built for "all across pages"), with the rows unticked since in
1589
+ // `unselected`. A client-side table reads the chosen rows from both.
1590
+ const chosenIds = computed<string[]>(() =>
1591
+ ctx.all.value
1592
+ ? members.value
1593
+ .map((member) => member.id)
1594
+ .filter((id) => !ctx.unselected.value.includes(id))
1595
+ : (ctx.selected.value ?? [])
1596
+ );
1597
+ const selectedCount = computed(() => chosenIds.value.length);
1598
+ const clear = () => {
1599
+ ctx.all.value = false;
1600
+ ctx.selected.value = [];
1601
+ };
1571
1602
 
1572
1603
  const { confirm } = useConfirm();
1573
1604
 
1574
1605
  // Destructive bulk action: `await` the decision, act only on a yes.
1575
1606
  const removeSelected = async () => {
1576
- const ids: string[] = ctx.selected.value ?? [];
1607
+ const ids = chosenIds.value;
1577
1608
  const ok = await confirm({
1578
1609
  title: `Delete ${ids.length} ${ids.length === 1 ? 'member' : 'members'}?`,
1579
1610
  text: 'They will lose access to this workspace immediately.',
@@ -1981,7 +2012,7 @@ _detail about the row_ rather than _children of it_.
1981
2012
 
1982
2013
  ### Reordering rows
1983
2014
 
1984
- `reorderable-rows` adds a slim grip at the start of every row: the user drags
2015
+ `reorderable-rows` adds a slim drag handle at the start of every row: the user drags
1985
2016
  a row to a new place and the table reports the move with **`reorder:rows`**.
1986
2017
  The table never reorders `items` itself. Your handler splices the array, and
1987
2018
  saves the order if it should outlive the page:
@@ -1993,8 +2024,8 @@ saves the order if it should outlive the page:
1993
2024
  <div class="flex max-w-2xl flex-col gap-3">
1994
2025
  <!-- The table only REPORTS the move: `reorder:rows` says which item went
1995
2026
  from where to where, and the handler below splices the array and
1996
- saves the order. Drag a row by its grip (or anywhere on it with a
1997
- mouse), or focus a grip and use Space, the arrow keys and Space. -->
2027
+ saves the order. Drag a row by its handle (or anywhere on it with a
2028
+ mouse), or focus a handle and use Space, the arrow keys and Space. -->
1998
2029
  <div
1999
2030
  class="overflow-hidden rounded-(--bb-radius) border border-(--bb-border)"
2000
2031
  >
@@ -2108,11 +2139,11 @@ function move({ from, to }: { from: number; to: number }) {
2108
2139
  `items` (`items.indexOf(item)` finds it); `from` and `to` index the `items`
2109
2140
  the table holds. Remove at `from`, insert at `to`. A drop where the row
2110
2141
  already was emits nothing.
2111
- - **Mouse and pen** drag from the grip, or from anywhere on the row once the
2142
+ - **Mouse and pen** drag from the handle, or from anywhere on the row once the
2112
2143
  pointer has moved 5px. A press on a control inside the row never starts a
2113
2144
  drag (a button, a link, an input, the select checkbox, anything with a
2114
2145
  widget role or `draggable`), and a press that sets off sideways selects text
2115
- instead. **Touch** drags from the grip only, at once (no long-press), so a
2146
+ instead. **Touch** drags from the handle only, at once (no long-press), so a
2116
2147
  finger on the row still scrolls. The click that ends a drag is not a row
2117
2148
  click: no `click:row`, no highlight.
2118
2149
  - **While it drags**, a copy of the row follows the pointer with its real cell
@@ -2121,10 +2152,10 @@ function move({ from, to }: { from: number; to: number }) {
2121
2152
  Near the top or bottom edge the nearest scroll container scrolls, `virtual`
2122
2153
  tables included, and the rows that scroll in are targets; the wheel scrolls
2123
2154
  too.
2124
- - **Keyboard:** the grip is a button. Space or Enter picks the row up, ↑ / ↓ /
2155
+ - **Keyboard:** the drag handle is a button. Space or Enter picks the row up, ↑ / ↓ /
2125
2156
  Home / End move it, Space or Enter drops it, Esc or Tab cancels. Under
2126
- `keyboard-navigation`, Space or Enter on the grip's cell picks it up at once.
2127
- - **Accessibility:** each grip is named "Move row" + the row's label (its
2157
+ `keyboard-navigation`, Space or Enter on the handle's cell picks it up at once.
2158
+ - **Accessibility:** each drag handle is named "Move row" + the row's label (its
2128
2159
  cell in the `rowHeader: true` column, else the first column) and described by the keyboard
2129
2160
  instructions. A polite live region announces the pick-up, each position
2130
2161
  ("Position 3 of 6"), the drop and a cancel.
@@ -2137,10 +2168,16 @@ function move({ from, to }: { from: number; to: number }) {
2137
2168
  - **Server pages:** the indexes are into the page the table holds. For the
2138
2169
  whole list, add the page's offset (`(page - 1) * perPage + from`). Moving a
2139
2170
  row to another page is not supported.
2140
- - **Sorting:** the grips stay enabled while a column sort is active, so a move
2141
- is reported against the sorted rows. What that means for your stored order
2142
- is your app's call (clear the sort first, or hide reordering while sorted).
2143
- - **Pinning and RTL:** the grip column is structural, like the select column:
2171
+ - **Sorting:** the drag handles stay enabled while a column sort is active, and a
2172
+ move is reported against the sorted rows, the order the user sees. This is
2173
+ easy to get wrong: splicing your stored array changes nothing a sort shows,
2174
+ so the row snaps back. Give the drop a meaning the sort can show. Sorted by
2175
+ a rank the drag edits (priority, position), write the new ranks in the order
2176
+ the user now sees and the sort reproduces the drop. Sorted by something the
2177
+ drag cannot change (a name, a date), turn the drag handles off for that sort
2178
+ (`:reorderable-rows="!sort.length || sort[0][0] === 'priority'"`) rather
2179
+ than snapping back or clearing the user's sort behind their back.
2180
+ - **Pinning and RTL:** the drag handle column is structural, like the select column:
2144
2181
  it never appears in `order` and never moves, it pins with the first
2145
2182
  left-pinned column, and in RTL it sits at the logical start (the right
2146
2183
  edge).
@@ -2148,7 +2185,7 @@ function move({ from, to }: { from: number; to: number }) {
2148
2185
  goes on while its row is still there, and cancels cleanly, announced, when
2149
2186
  it is gone. Expanding or collapsing one of the table's own rows cancels it.
2150
2187
  While `loading`, no new drag starts.
2151
- - **No grips** with a custom `#tbody`.
2188
+ - **No drag handles** with a custom `#tbody`.
2152
2189
  - **Styling:** `pt:dragHandle` takes a class list or an object (no per-row
2153
2190
  function).
2154
2191
 
@@ -2196,6 +2233,13 @@ put, and both columns are reported. A table that inherits its widths from a
2196
2233
  parent (`inherit-column-widths`) renders no handles — its tracks are the
2197
2234
  parent's.
2198
2235
 
2236
+ **Lock one column with `resizable: false`** on its definition, the way
2237
+ `reorderable: false` locks its place: its header has no handle, Alt+←/→ on
2238
+ it does nothing, and a neighbour's Shift+drag resizes the neighbour alone. Use
2239
+ it for control columns sized to their content (an expand chevron, a row
2240
+ number at `width: 'max-content'`). The lock stops the user, not your code: a
2241
+ `width` you set still applies.
2242
+
2199
2243
  **Resizable columns reporting widths back into the definition**
2200
2244
 
2201
2245
  ```vue
@@ -2342,7 +2386,7 @@ above it. The mechanics:
2342
2386
  </template>
2343
2387
 
2344
2388
  <template #expand="{ item }">
2345
- <div class="bg-(--bb-muted) px-1 py-1">
2389
+ <div class="bg-(--bb-muted) py-1">
2346
2390
  <BbTable
2347
2391
  :caption="`Line items of ${item.number}`"
2348
2392
  :columns="lineColumns"
@@ -2478,7 +2522,42 @@ Two rules keep them honest:
2478
2522
  2. **Never add nest padding on the body only.** Padding the child's body
2479
2523
  (`.bb-table__body`) but not its header (or vice versa) reintroduces exactly
2480
2524
  the offset the snap just removed. Put the inset on the nest container, where
2481
- both row groups inherit it.
2525
+ both row groups inherit it, and keep it **vertical** (`py-1`): the child
2526
+ inherits the parent's track widths, not their positions, so horizontal
2527
+ padding moves every column off its rail by that much and pushes the child
2528
+ past the parent's edge into its scroll.
2529
+
2530
+ #### Indenting nested levels
2531
+
2532
+ Two CSS tokens on the **root** table step each nested level in, the way a
2533
+ tree reads, while every other column stays on the parent's columns:
2534
+
2535
+ - `--indent` — the step per level (a length; `0px` by default, no indent).
2536
+ - `--indent-at` — where the step goes: `drag-handle`, `select` (the default) or
2537
+ `content`.
2538
+
2539
+ ```css
2540
+ .services-table {
2541
+ --indent: 24px;
2542
+ --indent-at: select;
2543
+ }
2544
+ ```
2545
+
2546
+ | `--indent-at` | Stays in one column at every level | Steps in per level |
2547
+ | ------------- | ---------------------------------- | ---------------------------------------- |
2548
+ | `drag-handle` | nothing before the content | the drag handle, the select, the content |
2549
+ | `select` | the drag handle | the select and the content |
2550
+ | `content` | the drag handle and the select | the first column's content |
2551
+
2552
+ Each nested level adds one step before the anchor and takes it from its
2553
+ first content column, so Status, Total or any other column never moves and
2554
+ level three lands two steps in by itself. A missing anchor falls through: no
2555
+ drag handle column behaves as `select`, no select column as `content`. Set the tokens
2556
+ on the root table (nested tables inherit them), or on one nested table to
2557
+ change the anchor from that level down. `--indent-at` is read when the table
2558
+ measures (mount, resize): set it in CSS, not from an animation. A nested
2559
+ table also carries `--depth` (1, 2, …) for styling by level, e.g. a group bar:
2560
+ `border-inline-start: calc(var(--depth) * 2px) solid var(--bb-primary)`.
2482
2561
 
2483
2562
  ### Row highlight (master–detail)
2484
2563
 
@@ -3883,8 +3962,13 @@ for a preset that fits any row type (never `<any>`), not an imported
3883
3962
  - `loading-text` is `sr-only` — it is announced, never painted. The visible
3884
3963
  loading signal is the skeleton (or your `#loading` slot). It defaults to the
3885
3964
  localized `common.loadingText`, so an unset value still announces.
3886
- - Row selection labels default to every cell's content inside the locale's
3887
- "select" template (`Select {0}`, `{0} auswählen`). `accessible-label` overrides that per row — it is called
3965
+ - Row selection labels default to the row's **name** inside the locale's
3966
+ "select" template (`Select {0}`, `{0} auswählen`): its `rowHeader` cells,
3967
+ else its first column ("Select INV-1041"), the same name the drag handle
3968
+ uses. Not every cell: a name tells rows apart, and a screen reader reads the
3969
+ other cells with their headers in table navigation. Mark the identity
3970
+ column `rowHeader` when it is not the first (a receipt thumbnail leads).
3971
+ `accessible-label` overrides that per row — it is called
3888
3972
  `(columns, item)` with the mapped cells (in **render** order — look them up
3889
3973
  by `key`, never by position) and the raw record, and whatever it returns
3890
3974
  becomes the checkbox's label.
@@ -3939,8 +4023,9 @@ for a preset that fits any row type (never `<any>`), not an imported
3939
4023
  (`role="rowheader"`), and a screen reader reading across a row, or down
3940
4024
  another column, announces that name with each value — "Ada Lovelace,
3941
4025
  ada@x.io" instead of a bare "ada@x.io". The cells look the same.
3942
- `accessible-label` is a different thing: it only names each row's
3943
- selection checkbox. The column:
4026
+ It also names the row's selection checkbox and drag handle ("Select Ada
4027
+ Lovelace", "Move row Ada Lovelace"); `accessible-label` overrides only the
4028
+ checkbox. The column:
3944
4029
  `{ key: 'name', label: 'Name', rowHeader: true }`.
3945
4030
 
3946
4031
  - Set `item-value` so selection, expansion and highlight track rows by stable
@@ -4004,7 +4089,7 @@ for a preset that fits any row type (never `<any>`), not an imported
4004
4089
  | Prop | Type | Default | Required | Description |
4005
4090
  | --- | --- | --- | --- | --- |
4006
4091
  | `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: `body`, `caption`, `cell`, `cellColumnHeader`, `dragHandle`, `dragIcon`, `firstRow`, `foot`, `head`, `headerRow`, `lastRow`, `root`, `row`, `selectIcon`, `sortIcon`, `table`. States: `disabled`, `empty`, `expanded`, `highlighted`, `indeterminate`, `loading`, `selected`, `sorted`, `sortedDesc`. What each one is: _Passthrough parts and states_ below. `pt` is the object form with the same keys minus the prefix (`{ icon: '…', 'icon:loading': '…' }`). See `guides/passthrough.md`. In `<script>` a `pt` value is typed `BbTableProps<Row>['pt']` (`BbTableProps['pt']` for a preset that fits any row type, never `<any>`) (`PtValue` is not exported): § Typing `pt` in `<script>`. |
4007
- | `accessibleLabel` | `((columns: MappedCell[], item: any) => string) \| undefined` | | | Function that accepts the columns and the current item as arguments and returns a label to be used for accessibility purposes. The cells arrive in RENDER order (they follow `order`, so the label reads like the row) — look a cell up by `key`, never by position. |
4092
+ | `accessibleLabel` | `((columns: MappedCell[], item: any) => string) \| undefined` | | | The row's selection checkbox label, from `(columns, item)`. Unset: the row's name in the locale's select template (its `rowHeader` cells, else its first column: "Select INV-1041"). The cells arrive in render order: look one up by `key`, never by position. |
4008
4093
  | `actionsText` | `string \| undefined` | | | Label used in the header of the actions column. |
4009
4094
  | `align` | `"left" \| "center" \| "right" \| undefined` | `"left"` | | Text alignment of the columns. |
4010
4095
  | `caption` | `string \| undefined` | | | Caption that describes the content of the table. Used for accessibility purposes. |
@@ -4046,7 +4131,7 @@ for a preset that fits any row type (never `<any>`), not an imported
4046
4131
  | `perPage` | `string \| number \| undefined` | | | Rows per page, for `aria-rowindex` and a paired `BbPagination`. Doesn't slice `items`. Unset, an array `items` infers it from its length; an explicit value wins. Numeric strings are coerced. |
4047
4132
  | `readonly` | `boolean \| undefined` | `false` | | Sets the input in a readonly state. |
4048
4133
  | `reorderable` | `boolean \| undefined` | `false` | | Lets the user reorder the data columns: drag a header, or Shift+←/→ on a focused header. Every move writes `v-model:order`; a column panel that only writes `order` does not need it. `select` / `actions` and a custom `#thead` never move. |
4049
- | `reorderableRows` | `boolean \| undefined` | `false` | | Adds a grip at the start of each row: the user drags a row, or lifts it with Space / Enter and the arrow keys, and `reorder:rows` reports `{ item, from, to }`. The table never reorders `items`: splice it in the handler. |
4134
+ | `reorderableRows` | `boolean \| undefined` | `false` | | Adds a drag handle at the start of each row: the user drags a row, or lifts it with Space / Enter and the arrow keys, and `reorder:rows` reports `{ item, from, to }`. The table never reorders `items`: splice it in the handler. |
4050
4135
  | `resizable` | `boolean \| undefined` | `false` | | Lets the user resize the data columns (drag a header's trailing edge, or Alt+←/→; double-click resets). Each commit fires `resize:column(key, width)` once: write the width back into the column definition to keep it. Ignored when inheriting widths. |
4051
4136
  | `rowClass` | `BbTableRowClasses<Item> \| undefined` | | | Defines the classes to be passed to each data row. Can also be a function of the row's item for dynamic values. |
4052
4137
  | `selectable` | `boolean \| ((item: Item) => boolean) \| undefined` | | | Defines whether the table is selectable. Can be a global boolean that affects all rows or a function that accepts an item and returns a boolean that only affects that item. |
@@ -4081,7 +4166,7 @@ for a preset that fits any row type (never `<any>`), not an imported
4081
4166
  | `lastRow` | The row of `#<key>:last` cells, after the data rows (a totals row: `pt:lastRow="font-semibold"`). |
4082
4167
  | `selectIcon` | The selection glyph: each row's checkbox (radio with single selection) and the select-all checkbox — resolved per node. Not rendered when the `select` / `select:header` slots replace them. |
4083
4168
  | `dragIcon` | The move glyph on the chip that follows a column drag (`reorderable`). |
4084
- | `dragHandle` | Each row's grip button (`reorderable-rows`), resolved with its row's states. A class list or an object; no per-row function. |
4169
+ | `dragHandle` | Each row's drag handle button (`reorderable-rows`), resolved with its row's states. A class list or an object; no per-row function. |
4085
4170
  | `foot` | The footer row group (the `tfoot` slot's container). |
4086
4171
 
4087
4172
  States are listed in precedence order: when two are on at once and their entries conflict, the later one wins.
@@ -4150,6 +4235,13 @@ Set these on the element, or on a class you put on it, to retune this component
4150
4235
  | `--actions-spacing` | `.bb-table` | `8px` | |
4151
4236
  | `--offset-start` | `.bb-table` | `0px` | Raw structural edge offset measured by the component (the parent's select/actions track width). Default 0 keeps every calc at its base. |
4152
4237
  | `--offset-end` | `.bb-table` | `0px` | |
4238
+ | `--ig` | `.bb-table` | `0px` | Nested indent locals (see `indentAnchor` in BbTable.vue): the step lands on ONE cell's leading padding. Reset on every table so a parent's step never inherits into a child's cells; the modifier picks the anchor. |
4239
+ | `--is` | `.bb-table` | `0px` | |
4240
+ | `--ic` | `.bb-table` | `0px` | |
4241
+ | `--depth` | `.bb-table` | `0` | Nesting depth (0 at the root) and the parent-region floors of the own structural tracks, both set inline by the component on nested tables; declared here so a parent's values never inherit into a child. |
4242
+ | `--min-g` | `.bb-table` | `0px` | |
4243
+ | `--min-s` | `.bb-table` | `0px` | |
4244
+ | `--min-a` | `.bb-table` | `0px` | |
4153
4245
  | `--offset-internal-start` | `.bb-table` | `var(--offset-start)` | Routing of that offset. By default it is "internal": added to the first/last cell padding and folded into the first/last column width. Swap internal↔external (set internal to 0 and external to the raw offset) to pad the whole table instead of the edge cells. |
4154
4246
  | `--offset-internal-end` | `.bb-table` | `var(--offset-end)` | |
4155
4247
  | `--offset-external-start` | `.bb-table` | `0px` | |
@@ -289,7 +289,7 @@ typeahead. Always pass a `label` when the trigger is an unlabelled cell or icon.
289
289
  | `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`. |
290
290
  | `ampm` | `boolean \| undefined` | `false` | | 12-hour display with an AM/PM column; emitted values stay 24-hour. |
291
291
  | `anchor` | `ElementOrComponentRef \| undefined` | | | Element or component ref the popover positions itself relative to. Defaults to the activator when omitted (anchor to a larger row while a smaller element stays the click target). |
292
- | `boundary` | `ElementOrComponentRefOrSelector \| undefined` | | | Constrains the popover within a bounding element or CSS selector. |
292
+ | `boundary` | `ElementOrComponentRefOrSelector \| undefined` | | | Constrains the popover within a bounding element or CSS selector: sideways only, alongside the trigger; it flips at the viewport. |
293
293
  | `disabled` | `boolean \| undefined` | `false` | | Disables the activator and the columns. |
294
294
  | `disableFlip` | `boolean \| undefined` | `false` | | Disable the automatic flip to the opposite side on overflow. |
295
295
  | `eager` | `boolean \| undefined` | `false` | | Render popover content before it is first shown. |
@@ -597,7 +597,7 @@ A `pt` value written in `<script>` (a constant, a preset, a wrapper's
597
597
  | `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`. States: `open`. What each one is: _Passthrough parts and states_ below. `pt` is the object form with the same keys minus the prefix (`{ icon: '…', 'icon:loading': '…' }`). See `guides/passthrough.md`. In `<script>` a `pt` value is typed `BbTooltipProps['pt']` (`PtValue` is not exported): § Typing `pt` in `<script>`. |
598
598
  | `activator` | `ElementOrComponentRef \| 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. |
599
599
  | `arrowPadding` | `number \| undefined` | `10` | | Space the arrow will maintain to the edge of the tooltip bubble. Useful when the floating element has border radius so it won't appear broken |
600
- | `boundary` | `ElementOrComponentRefOrSelector \| undefined` | | | Constrains the tooltip within a bounding element. When provided, the tooltip will not overflow this container's bounds (e.g. a sidebar). Accepts an HTMLElement, a Vue component ref, or a CSS selector string. |
600
+ | `boundary` | `ElementOrComponentRefOrSelector \| undefined` | | | Constrains the tooltip within a bounding element: it stays inside it alongside its trigger (sideways for a tooltip above or below); away from the trigger it may pass the edge, and it flips at the viewport only. Accepts an HTMLElement, a Vue component ref, or a CSS selector string. |
601
601
  | `delay` | `number \| undefined` | `100` | | Milliseconds a pointer rests on the activator before the tooltip shows (`0`: at once). Keyboard focus shows it at once, and so does a pointer arriving while another tooltip shows or within 300 ms of one closing. |
602
602
  | `disabled` | `boolean \| undefined` | `false` | | Disables the component |
603
603
  | `eager` | `boolean \| undefined` | `false` | | Renders the tooltip's popover and content at mount instead of on the first open. The description screen readers hear exists from mount either way. |
@@ -18,7 +18,7 @@
18
18
  | --- | --- | --- | --- | --- |
19
19
  | `anchor` | `any` | | | The element the popover positions itself relative to. Accepts an HTMLElement, a Vue component ref, or a virtual element with a `getBoundingClientRect` method. |
20
20
  | `arrowPadding` | `number \| undefined` | | | Space the arrow will maintain to the edge of the dropdown. Useful when the floating element has border radius so it won't appear broken |
21
- | `boundary` | `string \| Record<string, any> \| HTMLElement \| null \| undefined` | | | Constrains the popover's placement (`flip` / `shift` keep it inside); it never clamps the size, so a short boundary never collapses the bubble: use `overflowBoundary` for that. An HTMLElement, a component ref or a CSS selector. |
21
+ | `boundary` | `string \| Record<string, any> \| HTMLElement \| null \| undefined` | | | Keeps the popover inside this element alongside its anchor (sideways above or below, vertically beside it); away from the anchor it may pass the edge, and only the viewport flips it. It never clamps the size (that is `overflowBoundary`). An HTMLElement, component ref or selector. |
22
22
  | `bubbleAttrs` | `Record<string, unknown> \| ((space: CommonPopoverAvailableSpace) => Record<string, unknown>) \| undefined` | | | Attributes bound on the bubble (`class`, `style`, `inert`, …) after its own class, so the owner can make the bubble its layout container. The function form receives the default slot's free space (for a height cap). |
23
23
  | `dialog` | `boolean \| undefined` | `false` | | Renders the popover as a `<dialog>` element (modal overlay) instead of a `<span>` with the Popover API. |
24
24
  | `disableFlip` | `boolean \| undefined` | `false` | | Disables the automatic flip to the opposite side when the popover would overflow (flipping is on by default). |