bitboss-ui 3.0.0-beta.4 → 3.0.0-beta.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +36 -29
- package/dist/ai/BbBadge.md +10 -5
- package/dist/ai/BbSelect.md +8 -0
- package/dist/ai/BbTable.md +257 -51
- package/dist/ai/changelog.json +86 -2
- package/dist/ai/components.json +25 -15
- package/dist/ai/guides/design-language.md +14 -14
- package/dist/ai/guides/design-tokens.md +25 -18
- package/dist/ai/guides/installation-and-plugin-setup.md +1 -1
- package/dist/ai/guides/migration/components/bb-dialog.md +35 -29
- package/dist/ai/guides/migration/components/bb-table.md +406 -28
- package/dist/ai/guides/migration/v2-to-v3.md +175 -75
- package/dist/ai/index.md +1 -1
- package/dist/ai/recipes/inertia/layout-scaffold.md +5 -1
- package/dist/ai/recipes/inertia/ownership-atlas.md +41 -20
- package/dist/ai/recipes/inertia/records-workspace.md +26 -7
- package/dist/ai/recipes/nuxt/layout-scaffold.md +5 -1
- package/dist/ai/recipes/nuxt/records-workspace.md +26 -7
- package/dist/ai/recipes/vue/layout-scaffold.md +5 -1
- package/dist/ai/recipes/vue/records-workspace.md +26 -7
- package/dist/ai/source/BbBaseInputContainer.md +26 -0
- package/dist/ai/source/BbBreadcrumbs.md +31 -0
- package/dist/ai/source/BbDialog.md +15 -9
- package/dist/ai/source/BbOffCanvas.md +17 -11
- package/dist/ai/source/BbProgress.md +2 -2
- package/dist/ai/source/BbTable.md +837 -787
- package/dist/ai/source/CommonInputWrapper.md +4 -0
- package/dist/components/BbPagination/BbPagination.vue.d.ts +1 -1
- package/dist/components/BbTable/BbTable.vue.d.ts +5 -2
- package/dist/components/BbTable/BbTable.vue_vue_type_script_setup_true_lang.js +439 -484
- package/dist/components/BbTable/types.d.ts +83 -21
- package/dist/components/BbTable/utils.d.ts +18 -3
- package/dist/components/BbTable/utils.js +36 -28
- package/dist/index.d.ts +5 -1
- package/dist/index.js +68 -67
- package/dist/llms-full.txt +1065 -265
- package/dist/llms-medium.txt +15 -15
- package/dist/llms.txt +1 -1
- package/dist/styles.css +1 -1
- package/llms.txt +1 -1
- package/package.json +1 -1
- package/dist/assets/svgs/sort.svg_raw.js +0 -4
package/README.md
CHANGED
|
@@ -36,46 +36,53 @@ Full detail: `ai/guides/installation-and-plugin-setup.md`.
|
|
|
36
36
|
|
|
37
37
|
### Composables
|
|
38
38
|
|
|
39
|
-
| Composable
|
|
40
|
-
|
|
|
41
|
-
| `useBbConfig`
|
|
42
|
-
| `
|
|
43
|
-
| `
|
|
44
|
-
| `
|
|
45
|
-
| `
|
|
46
|
-
| `
|
|
47
|
-
| `
|
|
48
|
-
| `
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
-
|
|
39
|
+
| Composable | Role |
|
|
40
|
+
| ---------------------- | --------------------------------------------------------------------- |
|
|
41
|
+
| `useBbConfig` | Global options for the kit (locale, defaults, etc.). |
|
|
42
|
+
| `useBbDropdownContext` | Read a `BbDropdown`'s resolved groups/selections from anywhere by id. |
|
|
43
|
+
| `useBbTableContext` | Imperative handle onto a `BbTable` by id. |
|
|
44
|
+
| `useBbTabsContext` | Programmatic tab selection for a `BbTabs` by id. |
|
|
45
|
+
| `useConfirm` | Programmatic confirm / modal flows. |
|
|
46
|
+
| `useCountdown` | Countdown timer state. |
|
|
47
|
+
| `useId` | SSR-safe unique ids. |
|
|
48
|
+
| `useMobile` | Mobile / viewport-oriented behaviour. |
|
|
49
|
+
| `useSafeArea` | Claim a screen edge for a docked panel so toasts avoid it. |
|
|
50
|
+
| `useToast` | Toast notifications API. |
|
|
51
|
+
|
|
52
|
+
### Utilities
|
|
53
|
+
|
|
54
|
+
- **`slotKey`** — the normalizer behind every dynamic per-item named slot (`BbDropdown`, `BbTable`, `BbTabs`, `BbTree`, `BbBreadcrumbs`). Import it when building slot names programmatically instead of restating the rule.
|
|
55
|
+
|
|
56
|
+
### Directives
|
|
57
|
+
|
|
58
|
+
`vBbTooltip`, `vBbDropdown`, `vBbColor`, `vBbDate`, `vBbTime` — plus a
|
|
59
|
+
`Bb*DirectivePlugin` for each, for app-level registration. Prefer the directive
|
|
60
|
+
over the component for simple no-slot cases.
|
|
61
|
+
|
|
62
|
+
### Base\* primitives
|
|
63
|
+
|
|
64
|
+
The styled `Base*` input controls and the input chrome (`BbBaseInputContainer`,
|
|
65
|
+
`CommonInputWrapper` — label, prepend/append, prefix/suffix, clear button,
|
|
66
|
+
spacing) are **internal composition layers and are not exported**. Use the full
|
|
67
|
+
public inputs (`BbTextInput`, `BbSelect`, …); pass `hideLabel` for a
|
|
68
|
+
bare/inline control. The exported primitives are **`BbBaseButton`** and the
|
|
69
|
+
presentational glyphs **`BbBaseCheckboxIcon`**, **`BbBaseRadioIcon`**,
|
|
70
|
+
**`BbBaseSwitchIcon`**.
|
|
60
71
|
|
|
61
72
|
### Bb\* components (composed)
|
|
62
73
|
|
|
63
74
|
Product-ready components with labels, hints, errors, and consistent styling:
|
|
64
75
|
|
|
65
|
-
- **Forms & actions:** `BbTextInput`, `BbTextarea`, `BbNumberInput`, `BbSelect`, `BbCheckbox`, `BbCheckboxGroup`, `BbRadio`, `BbRadioGroup`, `BbSwitch`, `BbSwitchGroup`, `BbSlider`, `BbRating`, `BbColorInput`, `BbDatePickerInput`, `BbButton`, `BbBadge`, `BbIndicator`, `BbTag`, `BbDropdown`, `BbDropdownButton`
|
|
66
|
-
- **Feedback:** `BbAlert`, `BbProgress`, `BbSpinner`, `BbToast`, `BbTooltip`
|
|
67
|
-
- **Layout & navigation:** `BbAccordion`, `BbCollapsible`, `
|
|
76
|
+
- **Forms & actions:** `BbTextInput`, `BbTextarea`, `BbNumberInput`, `BbSelect`, `BbSelectPopover`, `BbCheckbox`, `BbCheckboxGroup`, `BbRadio`, `BbRadioGroup`, `BbSwitch`, `BbSwitchGroup`, `BbSlider`, `BbRating`, `BbColorInput`, `BbColorPalette`, `BbDatePicker`, `BbDatePickerInput`, `BbTimePicker`, `BbTimePickerInput`, `BbButton`, `BbBadge`, `BbBadgeButton`, `BbIndicator`, `BbTag`, `BbDropdown`, `BbDropdownGroup`, `BbDropdownButton`, `BbAsterisk`
|
|
77
|
+
- **Feedback:** `BbAlert`, `BbProgress`, `BbSpinner`, `BbToast`, `BbToastPortal`, `BbTooltip`
|
|
78
|
+
- **Layout & navigation:** `BbAccordion`, `BbCollapsible`, `BbTabs` (+ `BbTabsRoot`, `BbTabsList`, `BbTabsPanes`), `BbBreadcrumbs`, `BbPagination`, `BbSmoothHeight`
|
|
68
79
|
- **Overlays & panels:** `BbDialog`, `BbConfirm`, `BbConfirmPortal`, `BbOffCanvas`, `BbPopover`
|
|
69
80
|
- **Data:** `BbTable`, `BbTree`
|
|
70
81
|
- **Media & files:** `BbAvatar`, `BbDropzone`, `BbIcon`
|
|
71
82
|
|
|
72
|
-
### Shared input shells _(internal layout primitives - not for direct consumer use)_
|
|
73
|
-
|
|
74
|
-
- **`CommonInputWrapper`** — the internal input-chrome primitive (label, prepend/append, prefix/suffix, clear button, spacing) that every `Bb*` input composes. Not exported; use the full public inputs (`BbTextInput`, `BbSelect`, …).
|
|
75
|
-
|
|
76
83
|
### Exported component types
|
|
77
84
|
|
|
78
|
-
For
|
|
85
|
+
For the public **Bb\*** components, the package exports matching **props**, **events**, and (where relevant) **slots** types (for example `BbSelectProps`, `BbTableEvents`), plus supporting shapes like `BbDropdownItem` and `DropdownGroupItemsGetter`. Use them for typed wrappers and design-system layers; the docs list the full set per component.
|
|
79
86
|
|
|
80
87
|
---
|
|
81
88
|
|
package/dist/ai/BbBadge.md
CHANGED
|
@@ -309,9 +309,12 @@ state in the handler. Prefer `secondary` / `outline` for filter chips; reserve
|
|
|
309
309
|
```
|
|
310
310
|
|
|
311
311
|
The clear button inherits the variant's foreground, so it reads on every surface
|
|
312
|
-
— light on a filled `primary`, dark on a `secondary`/`outline`.
|
|
313
|
-
|
|
314
|
-
|
|
312
|
+
— light on a filled `primary`, dark on a `secondary`/`outline`. By default its
|
|
313
|
+
accessible name composes the localized verb with the badge's own text — a chip
|
|
314
|
+
reading "Italy" announces "Remove Italy", with no per-chip wiring. Set
|
|
315
|
+
`clearable-label` only when that composition is wrong for the context (it
|
|
316
|
+
replaces the whole name). With a `BbBadgeButton` body the composition is
|
|
317
|
+
skipped and the button falls back to the bare localized `badge.clearLabel`.
|
|
315
318
|
|
|
316
319
|
Icons combine with `clearable`: a **`prepend:icon`** stays (it leads the label);
|
|
317
320
|
an **`append:icon`** shares the trailing slot with the clear button — the icon
|
|
@@ -695,8 +698,10 @@ selectors like `.bb-badge > .bb-badge__content`, which no longer match.
|
|
|
695
698
|
- An icon-only badge (`icon`) has no visible text; the default slot is rendered
|
|
696
699
|
as a screen-reader-only label — never leave it empty. In button mode that
|
|
697
700
|
label is also the **button's accessible name**, so it is doubly required.
|
|
698
|
-
- The `clearable` button
|
|
699
|
-
localized `badge.clearLabel`
|
|
701
|
+
- The `clearable` button's accessible name is composed by default: the
|
|
702
|
+
localized `badge.clearLabel` verb plus the badge body's text ("Remove
|
|
703
|
+
Italy"). `clearable-label` replaces the whole name; with a `BbBadgeButton`
|
|
704
|
+
body the composition is skipped (bare verb only).
|
|
700
705
|
- A clickable **and** clearable badge is two tab stops (body, then clear). That
|
|
701
706
|
is intended: two actions, two controls.
|
|
702
707
|
- Keyboard focus on either control rings the whole pill, so the focused target
|
package/dist/ai/BbSelect.md
CHANGED
|
@@ -1212,6 +1212,14 @@ Shipped behavior — never reimplement it:
|
|
|
1212
1212
|
library default) — `direction="horizontal"` gives a label-beside-field row.
|
|
1213
1213
|
Only `floating`/`inside` label modes force the vertical layout, since they
|
|
1214
1214
|
embed the label in the field itself.
|
|
1215
|
+
- **A long `placeholder` or a long selected label never widens the control's
|
|
1216
|
+
track.** The trigger is a button, not an `<input>`, so the placeholder is
|
|
1217
|
+
real text rather than a paint-only `::placeholder` — but the field's minimum
|
|
1218
|
+
size is capped so that text cannot become the floor of a grid or flex track.
|
|
1219
|
+
Put a select with a paragraph-length placeholder in
|
|
1220
|
+
`grid-template-columns: repeat(3, 1fr)` and you still get three equal
|
|
1221
|
+
columns, with the text ellipsised inside its field. You do **not** need
|
|
1222
|
+
`min-w-0` on the item or `minmax(0, 1fr)` on the track to get this.
|
|
1215
1223
|
|
|
1216
1224
|
### Adaptive mobile sheet
|
|
1217
1225
|
|
package/dist/ai/BbTable.md
CHANGED
|
@@ -55,13 +55,15 @@ needs is declared here, not in markup:
|
|
|
55
55
|
`align` prop sets the default for the whole table (`left`).
|
|
56
56
|
- **`width`** freezes the column: numbers and bare numeric strings are px
|
|
57
57
|
(`130`, `'130'`); anything carrying a unit passes through (`'12rem'`,
|
|
58
|
-
`'20%'`).
|
|
59
|
-
|
|
60
|
-
|
|
58
|
+
`'20%'`). A declared width is the column's grid track and holds exactly;
|
|
59
|
+
unfrozen columns size to their content and share any leftover space equally
|
|
60
|
+
(the table is a CSS grid — the tracks are the width API, there is no
|
|
61
|
+
`table-layout`). When _every_ column declares a width, the surplus is shared
|
|
62
|
+
in proportion to the declared widths so the table still fills its container.
|
|
61
63
|
- **`skeleton`** picks the loading placeholder shape (see Loading below).
|
|
62
64
|
- **`sortable` / `sorted`** — see Sorting.
|
|
63
65
|
- **`thClass` / `tdClass` / `rowClass`** style the header cell, the data cells,
|
|
64
|
-
and the whole
|
|
66
|
+
and the whole row. `tdClass` and `rowClass` may be functions
|
|
65
67
|
`(content, key, item) => Classes` for state-dependent styling. Table-level
|
|
66
68
|
`thClass` / `tdClass` / `rowClass` / `headerRowClass` apply everywhere; a
|
|
67
69
|
row's classes accumulate the table `rowClass` plus every column's.
|
|
@@ -155,7 +157,7 @@ const invoices: Invoice[] = [
|
|
|
155
157
|
},
|
|
156
158
|
];
|
|
157
159
|
|
|
158
|
-
// `row-class` is applied to each
|
|
160
|
+
// `row-class` is applied to each row (`.bb-table-data__row`); use it to flag rows by state. Soft amber
|
|
159
161
|
// wash matches the design-language attention accent — public API, no internals.
|
|
160
162
|
const rowClass = (invoice: Invoice) =>
|
|
161
163
|
invoice.status === 'overdue'
|
|
@@ -207,7 +209,11 @@ Override any column's body with a `#<key>` slot and its header with a
|
|
|
207
209
|
characters turned into `_` (dashes are kept as-is), **lowercased**:
|
|
208
210
|
`address.city` → `#address_city`, `first_name` → `#first_name`, `issued-at` →
|
|
209
211
|
`#issued-at`, but also `issuedAt` → `#issuedat` — prefer snake_case keys so
|
|
210
|
-
slot names read naturally.
|
|
212
|
+
slot names read naturally. Building slot names in code (columns from config, a
|
|
213
|
+
dynamic `<template>` loop)? Import the normalizer itself — `import { slotKey }
|
|
214
|
+
from 'bitboss-ui'` — instead of restating the rule: a hand copy that differs by
|
|
215
|
+
one character (`\W+` collapses dashes; the real rule keeps them) makes the slot
|
|
216
|
+
silently never match. Keep the column in `columns`
|
|
211
217
|
even when you fully slot it: label, alignment and width still come from there.
|
|
212
218
|
|
|
213
219
|
Body cell scope: `content` (the formatted value), `item` (raw row), `value`
|
|
@@ -219,6 +225,22 @@ one-way state; the `toggle*` callbacks are the write path.
|
|
|
219
225
|
Header scope: `label`, `items` (the full list — handy for counts), `sortable`,
|
|
220
226
|
`sortOrder`, `toggleSort`, `classes`.
|
|
221
227
|
|
|
228
|
+
**Add beside a header instead of replacing it** with
|
|
229
|
+
`#header:<key>:prepend` / `#header:<key>:append` — rendered before / after the
|
|
230
|
+
column's existing header content (the label + sort control, or your own
|
|
231
|
+
`#header:<key>` replacement), so a resize grip or reorder handle no longer
|
|
232
|
+
costs you the built-in sort button. The table-wide pair `#header:prepend` /
|
|
233
|
+
`#header:append` applies one template to every data column's header (never the
|
|
234
|
+
structural select/actions cells); both forms receive the header scope above
|
|
235
|
+
plus `columnKey` (the raw column key) so a table-wide template can branch per
|
|
236
|
+
column. When both a per-column and the table-wide slot are provided for the
|
|
237
|
+
same side, the per-column one wins for that column — they never stack. Affixes
|
|
238
|
+
render even beside a full `#header:<key>` replacement (the same rule as
|
|
239
|
+
BbDropdown's `#<key>:prepend/append`). One caveat: a column key that
|
|
240
|
+
normalizes to `prepend` or `append` collides with the table-wide slot names;
|
|
241
|
+
the table-wide interpretation wins, per-column header slots are unavailable
|
|
242
|
+
for that column, and dev builds warn.
|
|
243
|
+
|
|
222
244
|
Below, the status badges carry brand glyphs shipped in the app's `iconDir`,
|
|
223
245
|
referenced as `local:*` names on the badge's `prepend:icon`. Per the icons
|
|
224
246
|
policy the dynamic status maps to **full-name literals** (a lookup object) —
|
|
@@ -365,7 +387,10 @@ Beyond per-column slots, the structural slots cover every other region:
|
|
|
365
387
|
(replace the per-row checkbox/radio; scope: `item`, `value`, `checked`,
|
|
366
388
|
`disabled`, `readonly`, `inputName`, `toggleSelected`), `#loading`, `#no-data`
|
|
367
389
|
(both below), and `#thead` / `#tbody` / `#tfoot` to replace an entire region
|
|
368
|
-
when you need full control (you then own its markup and semantics
|
|
390
|
+
when you need full control (you then own its markup and semantics: the table
|
|
391
|
+
is a CSS grid, so pass `<div role="row">` rows holding `<div role="cell">` /
|
|
392
|
+
`<div role="columnheader">` cells — never `<tr>`/`<td>`; a spanning cell uses
|
|
393
|
+
`grid-column: span N` with `#tfoot`'s `columnCount`, see **Styling hooks**).
|
|
369
394
|
|
|
370
395
|
### Loading and empty states
|
|
371
396
|
|
|
@@ -396,8 +421,9 @@ it renders only when there is nothing to keep. (Scope: the current, possibly
|
|
|
396
421
|
stale `items` — handy for matching the previous row count.) When `items` resolves
|
|
397
422
|
empty the table shows its no-data row — localized default text, overridable via
|
|
398
423
|
`no-data-text` or fully via the `#no-data` slot. That slot fills the table's own
|
|
399
|
-
full-width empty-state cell (already centred,
|
|
400
|
-
the content — a message, a "clear filters" button — not a
|
|
424
|
+
full-width empty-state cell (already centred, already spanning every column),
|
|
425
|
+
so pass the content — a message, a "clear filters" button — not a row of your
|
|
426
|
+
own.
|
|
401
427
|
|
|
402
428
|
`loading-text` is the loading row's `aria-live` announcement. Like
|
|
403
429
|
`no-data-text` it has a **localized default** (`common.loadingText` —
|
|
@@ -693,6 +719,11 @@ sorts first. The table only reports the model; **apply it to your data**
|
|
|
693
719
|
(client-side, as below) or forward it to the server as `orderBy` and refetch
|
|
694
720
|
via `dependencies`.
|
|
695
721
|
|
|
722
|
+
The affordance is one arrow: nothing at rest, a faint arrow previewed while
|
|
723
|
+
the header is hovered or focused, solid once the column is sorted (up for
|
|
724
|
+
ascending, down for descending — the AG Grid convention), gone again on the
|
|
725
|
+
third click.
|
|
726
|
+
|
|
696
727
|
**Sortable headers driving a client-side sort**
|
|
697
728
|
|
|
698
729
|
```vue
|
|
@@ -773,7 +804,10 @@ const sortedInvoices = computed(() => {
|
|
|
773
804
|
|
|
774
805
|
A custom `#header:<key>` slot replaces the built-in sort button, but its scope
|
|
775
806
|
hands you `sortOrder` and `toggleSort` so your header can keep sorting alive
|
|
776
|
-
(render your own button and call `toggleSort`).
|
|
807
|
+
(render your own button and call `toggleSort`). To merely add something next
|
|
808
|
+
to the control — a resize grip, a filter icon — use
|
|
809
|
+
`#header:<key>:prepend/append` instead and keep the built-in button (see
|
|
810
|
+
"Custom cells and headers"). The column-level `sorted`
|
|
777
811
|
field only seeds the header's `aria-sort` when no live model entry exists — it
|
|
778
812
|
does not move the visual indicator; to start pre-sorted, seed `v-model:sort`
|
|
779
813
|
instead (as the example does).
|
|
@@ -1282,7 +1316,7 @@ _detail about the row_ rather than _children of it_.
|
|
|
1282
1316
|
A `BbTable` rendered inside another's `#expand` slot is independent by
|
|
1283
1317
|
default. Add `inherit-column-widths` and it snaps its columns to the parent's
|
|
1284
1318
|
tracks, so a line-items breakdown reads as a continuation of the invoice row
|
|
1285
|
-
above it
|
|
1319
|
+
above it. The mechanics:
|
|
1286
1320
|
|
|
1287
1321
|
- `inherit-column-widths` — `true` inherits from the nearest ancestor table;
|
|
1288
1322
|
a string targets a specific ancestor's `id` (useful when an intermediate
|
|
@@ -1293,23 +1327,34 @@ above it (this also forces fixed layout). The mechanics:
|
|
|
1293
1327
|
allowed; `end: -1` runs to the end of the data region). Structural columns
|
|
1294
1328
|
(`select`, actions) are accounted for automatically.
|
|
1295
1329
|
- A child with **more** columns than the parent content-sizes the extras and
|
|
1296
|
-
|
|
1297
|
-
tables end flush.
|
|
1298
|
-
- **
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1330
|
+
overflows into the parent's scroll (see below); with fewer, the last
|
|
1331
|
+
width-free column absorbs the slack so both tables end flush.
|
|
1332
|
+
- **An inheriting child does not scroll on its own — the parent's scrollport
|
|
1333
|
+
is the only one.** That is what keeps the two grids locked together: a child
|
|
1334
|
+
with its own scroll position would fall out of alignment the moment either
|
|
1335
|
+
one moved, which is the whole thing `inherit-column-widths` exists to
|
|
1336
|
+
prevent. One scrollbar moves both.
|
|
1337
|
+
- **The parent's `selectable`/`actions` columns are handled for you** — the
|
|
1338
|
+
child's content columns map to the parent's content columns 1:1 (no `snap`
|
|
1339
|
+
needed for that), and the parent's select/actions _regions_ are reserved on
|
|
1340
|
+
each side: a child with its own select or actions column widens that cell
|
|
1341
|
+
to the parent's (two equal cells, controls at the row's end, so the ⌃ sits
|
|
1342
|
+
under the parent's); a child without one folds the region into its first/
|
|
1343
|
+
last cell as _padding_, so its content stays flush with the parent's data
|
|
1344
|
+
grid on both edges (the inset reads as hierarchy). Only a child cell
|
|
1345
|
+
_wider_ than the parent's — a select the parent lacks, more buttons — moves
|
|
1346
|
+
anything, and only the adjacent content column: it shrinks by the surplus
|
|
1347
|
+
so every other rail holds. What a child publishes to its own children is
|
|
1348
|
+
the same contract (content rails + regions), so a three-level nest aligns
|
|
1349
|
+
at every depth.
|
|
1308
1350
|
- **Scope any page-level cell-padding overrides to the parent's own cells.** A
|
|
1309
|
-
bare `:deep(
|
|
1310
|
-
clobbers the offset padding it computes to stay aligned — use
|
|
1311
|
-
|
|
1312
|
-
|
|
1351
|
+
bare `:deep([role='cell']:first-child)` also matches the nested table's
|
|
1352
|
+
cells and clobbers the offset padding it computes to stay aligned — use the
|
|
1353
|
+
direct-child chain through the grid's containers
|
|
1354
|
+
(`:deep(> .bb-table__table > .bb-table__body > [role='row'] > :first-child)`)
|
|
1355
|
+
so the child, which lives inside `.bb-table-expand__cell`, keeps its
|
|
1356
|
+
structural padding. The canonical `.table-flush` idiom is under **Styling
|
|
1357
|
+
hooks**.
|
|
1313
1358
|
|
|
1314
1359
|
**Invoice lines aligned under the invoice columns**
|
|
1315
1360
|
|
|
@@ -1419,6 +1464,41 @@ const expanded = ref<string[]>([]);
|
|
|
1419
1464
|
</script>
|
|
1420
1465
|
```
|
|
1421
1466
|
|
|
1467
|
+
#### Affixed actions on both tables
|
|
1468
|
+
|
|
1469
|
+
A nested table can carry its own `fixed-columns` — child rows usually need
|
|
1470
|
+
their own row actions — and both action columns pin to the same visible edge:
|
|
1471
|
+
|
|
1472
|
+
```vue
|
|
1473
|
+
<BbTable
|
|
1474
|
+
id="programmes"
|
|
1475
|
+
actions
|
|
1476
|
+
:columns="columns"
|
|
1477
|
+
:fixed-columns="[{ index: columns.length, position: 'right' }]"
|
|
1478
|
+
:items="rows"
|
|
1479
|
+
item-value="id"
|
|
1480
|
+
>
|
|
1481
|
+
<template #expand="{ item }">
|
|
1482
|
+
<BbTable
|
|
1483
|
+
actions
|
|
1484
|
+
:columns="childColumns"
|
|
1485
|
+
:fixed-columns="[{ index: childColumns.length, position: 'right' }]"
|
|
1486
|
+
inherit-column-widths="programmes"
|
|
1487
|
+
:items="item.children"
|
|
1488
|
+
item-value="id"
|
|
1489
|
+
/>
|
|
1490
|
+
</template>
|
|
1491
|
+
</BbTable>
|
|
1492
|
+
```
|
|
1493
|
+
|
|
1494
|
+
This works because the child shares the parent's scrollport. `position: sticky`
|
|
1495
|
+
resolves against the nearest scrolling ancestor, and the child's own box is as
|
|
1496
|
+
wide as the parent's **content** — so if it opened a scrollport of its own, the
|
|
1497
|
+
child's actions would affix to an edge sitting out in the overflow, hundreds of
|
|
1498
|
+
pixels past what anyone can see, while the parent's pinned correctly. Snap the
|
|
1499
|
+
child's actions column onto the parent's actions track (see the snapping rule
|
|
1500
|
+
above) so the two columns line up rather than merely both being pinned.
|
|
1501
|
+
|
|
1422
1502
|
#### Flush tables + inherited widths: mind the edge padding
|
|
1423
1503
|
|
|
1424
1504
|
`table-flush` removes the outer cell padding so the table reads edge-to-edge in
|
|
@@ -1432,9 +1512,10 @@ Two rules keep them honest:
|
|
|
1432
1512
|
1. **Snap against the same base you paint.** Measure the parent's columns with
|
|
1433
1513
|
the same flush/padded state the child renders in — never measure padded and
|
|
1434
1514
|
render flush.
|
|
1435
|
-
2. **Never add nest padding on the body only.** Padding the child's
|
|
1436
|
-
not its header (or vice versa) reintroduces exactly
|
|
1437
|
-
removed. Put the inset on the nest container, where
|
|
1515
|
+
2. **Never add nest padding on the body only.** Padding the child's body
|
|
1516
|
+
(`.bb-table__body`) but not its header (or vice versa) reintroduces exactly
|
|
1517
|
+
the offset the snap just removed. Put the inset on the nest container, where
|
|
1518
|
+
both row groups inherit it.
|
|
1438
1519
|
|
|
1439
1520
|
### Row highlight (master–detail)
|
|
1440
1521
|
|
|
@@ -1636,9 +1717,11 @@ const rowClass = (event: AuditEvent) =>
|
|
|
1636
1717
|
```
|
|
1637
1718
|
|
|
1638
1719
|
Row events: `click:row`, `dblclick:row` and `contextmenu:row` fire with
|
|
1639
|
-
`(event,
|
|
1640
|
-
|
|
1641
|
-
|
|
1720
|
+
`(event, item)` — the native event and **your record exactly as you passed it
|
|
1721
|
+
in `items`**, nothing else. No wrapper to unpack, no third argument; selection
|
|
1722
|
+
state is already yours through the `v-model`, and the row's value resolves
|
|
1723
|
+
from the record through `item-value` exactly as the models do. Reserve these
|
|
1724
|
+
events for side effects that are not navigation —
|
|
1642
1725
|
logging, opening a drawer (though `v-model:highlighted` usually covers that
|
|
1643
1726
|
without any handler).
|
|
1644
1727
|
|
|
@@ -2057,10 +2140,11 @@ leave the screen. Collapse instead of scroll:
|
|
|
2057
2140
|
|
|
2058
2141
|
- **Rank the columns.** Identity + status + the one number that matters stay;
|
|
2059
2142
|
everything else is secondary.
|
|
2060
|
-
- **
|
|
2061
|
-
`
|
|
2062
|
-
|
|
2063
|
-
|
|
2143
|
+
- **Drop the secondary ones from `columns` at the breakpoint** — a `computed`
|
|
2144
|
+
over `useMobile()` (or your own `matchMedia`) that filters the secondary keys
|
|
2145
|
+
out. Removing the column removes its grid track. Do **not** hide cells with
|
|
2146
|
+
`thClass`/`tdClass` + `display: none`: the table is a grid, a hidden cell
|
|
2147
|
+
leaves its track in place and every following cell shifts one track over.
|
|
2064
2148
|
- **Stack what survives into the primary cell.** The identity slot renders the
|
|
2065
2149
|
name plus the hidden facts under it, at `--bb-text-muted`, so nothing is
|
|
2066
2150
|
actually lost.
|
|
@@ -2069,6 +2153,125 @@ Keep the sticky/pinned identity column for the case where the full grid really
|
|
|
2069
2153
|
must stay reachable (a spreadsheet-shaped tool), not as the default for a
|
|
2070
2154
|
records list.
|
|
2071
2155
|
|
|
2156
|
+
### Styling hooks
|
|
2157
|
+
|
|
2158
|
+
**The table's surface is `--bg`** (default `var(--bb-panel)`), a local on
|
|
2159
|
+
`.bb-table`. Cells are transparent at rest so the row can tint them, but
|
|
2160
|
+
anything that slides over scrolled content — the stuck header band with
|
|
2161
|
+
`fixed-headers`, and `fixed-columns` cells — is opaque and paints `--bg` (a
|
|
2162
|
+
pinned cell also picks up its row's hover/highlight tint, so it never reads
|
|
2163
|
+
as a hole). When a table sits on a surface that is not the panel colour, set
|
|
2164
|
+
the one knob and everything pinned follows:
|
|
2165
|
+
|
|
2166
|
+
```css
|
|
2167
|
+
.my-card .bb-table {
|
|
2168
|
+
--bg: var(--card-bg);
|
|
2169
|
+
}
|
|
2170
|
+
```
|
|
2171
|
+
|
|
2172
|
+
The table is a **CSS grid of `<div>`s with ARIA roles, not a `<table>`**: the
|
|
2173
|
+
root `.bb-table__table[role=table]` owns the column tracks and every row group
|
|
2174
|
+
and row is a subgrid of it. Style it through the classes and the roles — never
|
|
2175
|
+
through element names, which match nothing:
|
|
2176
|
+
|
|
2177
|
+
| Region | Class | Role |
|
|
2178
|
+
| ------------ | -------------------------------------------------------- | ----------------------------------------- |
|
|
2179
|
+
| grid root | `.bb-table__table` | `table` |
|
|
2180
|
+
| header group | `.bb-table__head` | `rowgroup` |
|
|
2181
|
+
| header row | `.bb-table-header-row` | `row` |
|
|
2182
|
+
| header cell | `.bb-table-header` (+ `--select`, `--actions`) | `columnheader` |
|
|
2183
|
+
| body group | `.bb-table__body` | `rowgroup` |
|
|
2184
|
+
| data row | `.bb-table-data__row` (+ `--highlighted`) | `row` |
|
|
2185
|
+
| data cell | `.bb-table-data__cell` (+ `--select`) | `cell` |
|
|
2186
|
+
| actions cell | `.bb-table__cell--actions` | `cell` |
|
|
2187
|
+
| expand row | `.bb-table-expand__row` > `.bb-table-expand__cell` | `row` > `cell` |
|
|
2188
|
+
| empty state | `.bb-table-no-data__row` > `.bb-table-no-data__cell` | `row` > `cell` |
|
|
2189
|
+
| footer group | `.bb-table__foot` (`#tfoot` content) | `rowgroup` only when `#tfoot` is provided |
|
|
2190
|
+
| caption | `.bb-table-caption` (before the root, `aria-labelledby`) | — |
|
|
2191
|
+
|
|
2192
|
+
`[role='row']`, `[role='cell']` and `[role='columnheader']` are supported
|
|
2193
|
+
hooks, not incidental markup — use them when you mean "every row kind" or
|
|
2194
|
+
"every cell"; use the classes when you mean one kind. Cells are direct
|
|
2195
|
+
children of their row, so `:first-child` / `:last-child` / `:nth-child(n)`
|
|
2196
|
+
address columns.
|
|
2197
|
+
|
|
2198
|
+
The full-bleed idiom every workspace page reaches for — the table bleeds past
|
|
2199
|
+
the content padding and hands the inset back to its outermost cells — is
|
|
2200
|
+
written with a **direct-child chain** so a nested table inheriting the
|
|
2201
|
+
parent's tracks (it lives inside `.bb-table-expand__cell`) is never touched:
|
|
2202
|
+
|
|
2203
|
+
```css
|
|
2204
|
+
.table-flush {
|
|
2205
|
+
--page-inset: 1rem;
|
|
2206
|
+
margin-inline: calc(var(--page-inset) * -1);
|
|
2207
|
+
width: calc(100% + var(--page-inset) * 2);
|
|
2208
|
+
}
|
|
2209
|
+
|
|
2210
|
+
.table-flush
|
|
2211
|
+
:deep(> .bb-table__table > .bb-table__head > [role='row'] > :first-child),
|
|
2212
|
+
.table-flush
|
|
2213
|
+
:deep(
|
|
2214
|
+
> .bb-table__table
|
|
2215
|
+
> .bb-table__body
|
|
2216
|
+
> [role='row']
|
|
2217
|
+
> :first-child:not(.bb-table-expand__cell)
|
|
2218
|
+
) {
|
|
2219
|
+
padding-inline-start: var(--page-inset);
|
|
2220
|
+
}
|
|
2221
|
+
|
|
2222
|
+
.table-flush
|
|
2223
|
+
:deep(> .bb-table__table > .bb-table__head > [role='row'] > :last-child),
|
|
2224
|
+
.table-flush
|
|
2225
|
+
:deep(
|
|
2226
|
+
> .bb-table__table
|
|
2227
|
+
> .bb-table__body
|
|
2228
|
+
> [role='row']
|
|
2229
|
+
> :last-child:not(.bb-table-expand__cell)
|
|
2230
|
+
) {
|
|
2231
|
+
padding-inline-end: var(--page-inset);
|
|
2232
|
+
}
|
|
2233
|
+
|
|
2234
|
+
/* Expand rows stay edge-to-edge so the nested table can snap onto the parent
|
|
2235
|
+
tracks without an extra inset shifting it sideways. */
|
|
2236
|
+
.table-flush
|
|
2237
|
+
:deep(
|
|
2238
|
+
> .bb-table__table > .bb-table__body > [role='row'] > .bb-table-expand__cell
|
|
2239
|
+
) {
|
|
2240
|
+
padding-inline: 0;
|
|
2241
|
+
}
|
|
2242
|
+
```
|
|
2243
|
+
|
|
2244
|
+
Leave the geometry alone: `display: grid` / `gap: 0` on the root, row groups
|
|
2245
|
+
and rows, `grid-column: 1 / -1` **and `contain: inline-size`** on the
|
|
2246
|
+
full-width cells (without the containment, expand-row content resizes the
|
|
2247
|
+
parent's columns), `white-space: nowrap` on the actions cell (it sizes the
|
|
2248
|
+
actions track), and `position: sticky` on `.bb-table__head` under
|
|
2249
|
+
`fixed-headers`.
|
|
2250
|
+
|
|
2251
|
+
When you replace a region with `#thead` / `#tbody` / `#tfoot`, ship the same
|
|
2252
|
+
shape the table does — role-complete rows, spanning with `grid-column` rather
|
|
2253
|
+
than `colspan`:
|
|
2254
|
+
|
|
2255
|
+
```vue
|
|
2256
|
+
<template #tfoot="{ columnCount }">
|
|
2257
|
+
<div role="row">
|
|
2258
|
+
<div
|
|
2259
|
+
role="cell"
|
|
2260
|
+
:aria-colspan="columnCount - 1"
|
|
2261
|
+
:style="{ gridColumn: `span ${columnCount - 1}` }"
|
|
2262
|
+
>
|
|
2263
|
+
Total
|
|
2264
|
+
</div>
|
|
2265
|
+
<div role="cell" class="text-right">{{ total }}</div>
|
|
2266
|
+
</div>
|
|
2267
|
+
</template>
|
|
2268
|
+
```
|
|
2269
|
+
|
|
2270
|
+
A `<tr>` inside the grid is not merely unsemantic — the browser wraps it in an
|
|
2271
|
+
implicit `<table>` and the cells never land on the tracks. Nothing lints the
|
|
2272
|
+
roles: a `<div>` row without them renders fine and is invisible to a screen
|
|
2273
|
+
reader.
|
|
2274
|
+
|
|
2072
2275
|
### Config and platform
|
|
2073
2276
|
|
|
2074
2277
|
- **Locale.** The plugin's `locale` (`it`/`en`) drives the built-in strings:
|
|
@@ -2119,7 +2322,8 @@ records list.
|
|
|
2119
2322
|
- Enabling select-all does not re-emit an empty `modelValue` (see the
|
|
2120
2323
|
select-all section) — in all-mode, read `select-all` +
|
|
2121
2324
|
`unselected-items`, not `modelValue`.
|
|
2122
|
-
- Row event payloads are
|
|
2325
|
+
- Row event payloads are `(event, item)` with `item` your raw record — there is
|
|
2326
|
+
no wrapper to unpack and no `selected` argument.
|
|
2123
2327
|
- A mistyped context/pagination `id` does not error; it silently syncs with
|
|
2124
2328
|
nothing. If a toolbar "works" but the table never reacts, check the id.
|
|
2125
2329
|
- In multiple mode `modelValue` must be an array, or it throws.
|
|
@@ -2195,13 +2399,13 @@ records list.
|
|
|
2195
2399
|
| `displayCaption` | `boolean \| undefined` | | | Boolean that defines whether to display or hide the caption. By default is true and the caption is hidden. |
|
|
2196
2400
|
| `enforceCoherence` | `boolean \| undefined` | | | After every load (initial, `dependencies` refetch or a change of the `items` array) prunes the row-keyed models of values whose row is no longer in the result set: `modelValue`, `unselected-items`, `highlighted` and `expanded-items`. Values… |
|
|
2197
2401
|
| `expandedItems` | `any[] \| undefined` | `[]` | | Used by `v-model:expandedItems`. Array of the currently expanded items — toggled by the row expand control and by external writes (mirrors the `highlighted`/`sort` v-model surfaces). Drives the `#expand` slot rows and their `aria-expanded`/… |
|
|
2198
|
-
| `fixed` | `boolean \| undefined` | | |
|
|
2402
|
+
| `fixed` | `boolean \| undefined` | | | Splits the width equally among the columns that declare no `width` (each undeclared column becomes a `minmax(0, 1fr)` track) making each column take up the same amount of space. |
|
|
2199
2403
|
| `fixedColumns` | `(number \| { index: number; position: "left" \| "right"; })[] \| undefined` | `[]` | | Definition for which column should be fixed. It can be an array of index of the column to fix on the left side of the table or an array of objects indicating the index and the position `left` or `right` where to affix the columns. |
|
|
2200
2404
|
| `fixedHeaders` | `boolean \| undefined` | | | Boolean that sets the headers as sticky to the top of the table. |
|
|
2201
|
-
| `headerRowClass` | `Classes \| undefined` | | | Defines the classes to be passed to the header
|
|
2405
|
+
| `headerRowClass` | `Classes \| undefined` | | | Defines the classes to be passed to the header row. |
|
|
2202
2406
|
| `highlighted` | `any` | `undefined` | | Used by `v-model:highlighted`. A parallel, UI-intent state to selection — typically "the row whose details are open". A single item value (or `null`) — highlight is single by design. Purely mechanical: highlighted rows only get the `bb-tabl… |
|
|
2203
2407
|
| `id` | `string \| undefined` | | | Stable id for this table's width context. When omitted a unique id is generated. Nested tables use the nearest ancestor id to inherit widths. |
|
|
2204
|
-
| `inheritColumnWidths` | `string \| boolean \| undefined` | | | Opt a nested table into inheriting its column widths from an ancestor table's matching tracks (accounting for `select`/`actions` columns). This also
|
|
2408
|
+
| `inheritColumnWidths` | `string \| boolean \| undefined` | | | Opt a nested table into inheriting its column widths from an ancestor table's matching tracks (accounting for `select`/`actions` columns). This also makes the parent's tracks authoritative, so it is **off by default** — a nested table rende… |
|
|
2205
2409
|
| `interactiveWhileLoading` | `boolean \| undefined` | | | Keeps the table interactive while it is loading. The header and the rows are `inert` while loading by default — a refetch is about to replace the rows, so editing, selecting or sorting them races the incoming data. This escape hatch exists … |
|
|
2206
2410
|
| `items` | `Item[] \| ((prefill: boolean, modelValue?: any) => Item[] \| Promise<Item[]>)` | `[]` | yes | Rows to render, or a fetcher that returns them. |
|
|
2207
2411
|
| `itemValue` | `ItemAccessor<Item> \| undefined` | | | |
|
|
@@ -2217,23 +2421,23 @@ records list.
|
|
|
2217
2421
|
| `page` | `string \| number \| undefined` | | | Current page number starting from 1, used for accessibility purposes. Also flows into the shared table context, so a `BbPagination` paired through `id` reads it as the current page. Numeric strings are coerced (server pagination fields ofte… |
|
|
2218
2422
|
| `perPage` | `string \| number \| undefined` | | | Number of items per page, used for accessibility purposes. Also flows into the shared table context read by a `BbPagination` paired through `id`. When omitted, an array `items` table infers it from `items.length`; an explicit value (or a co… |
|
|
2219
2423
|
| `readonly` | `boolean \| undefined` | | | Sets the input in a readonly state. |
|
|
2220
|
-
| `rowClass` | `RowClasses<Item> \| undefined` | | | Defines the classes to be passed to each data
|
|
2424
|
+
| `rowClass` | `RowClasses<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. |
|
|
2221
2425
|
| `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. |
|
|
2222
2426
|
| `selectAll` | `boolean \| undefined` | `false` | | Defines whether the "Select all" checkbox is checked. |
|
|
2223
2427
|
| `selectAllLabel` | `string \| undefined` | | | Text of the label used by the "Select all" boolean. |
|
|
2224
2428
|
| `selectText` | `string \| undefined` | | | Text of the header used for the radio inputs when the table is not `multiple`. |
|
|
2225
2429
|
| `sort` | `BbTableSortEntry[] \| undefined` | `[]` | | Used by `v-model:sort`. Ordered array of `[columnKey, direction]` entries, one per actively sorted column. Bidirectional: the header buttons of `sortable` columns update it, and external writes update the header indicators. The table does n… |
|
|
2226
|
-
| `tdClass` | `ColumnClasses<Item> \| undefined` | | | Defines the classes to be passed to
|
|
2227
|
-
| `thClass` | `Classes \| undefined` | | | Defines the classes to be passed to
|
|
2430
|
+
| `tdClass` | `ColumnClasses<Item> \| undefined` | | | Defines the classes to be passed to every data cell. Can also be a function for dynamic values. |
|
|
2431
|
+
| `thClass` | `Classes \| undefined` | | | Defines the classes to be passed to every header cell. |
|
|
2228
2432
|
| `totalItems` | `string \| number \| undefined` | | | Total number of items there is. Also flows into the shared table context, where a `BbPagination` paired through `id` derives its page count from it. When omitted, an array `items` table infers it from `items.length`; an explicit value (or a… |
|
|
2229
2433
|
| `totalPages` | `string \| number \| undefined` | | | Seeds the page count shown by a `BbPagination` paired through `id`. A shortcut for when the server reports a page count rather than a row count: the table renders nothing from it, it only flows into the shared table context. A known total a… |
|
|
2230
2434
|
| `unselectedItems` | `any[] \| undefined` | `[]` | | Items that are not selected. |
|
|
2231
2435
|
|
|
2232
2436
|
## Events
|
|
2233
2437
|
|
|
2234
|
-
- `click:row` — `(e: "click:row", event: MouseEvent, item: any
|
|
2235
|
-
- `contextmenu:row` — `(e: "contextmenu:row", event: MouseEvent, item: any
|
|
2236
|
-
- `dblclick:row` — `(e: "dblclick:row", event: MouseEvent, item: any
|
|
2438
|
+
- `click:row` — `(e: "click:row", event: MouseEvent, item: any): void`
|
|
2439
|
+
- `contextmenu:row` — `(e: "contextmenu:row", event: MouseEvent, item: any): void`
|
|
2440
|
+
- `dblclick:row` — `(e: "dblclick:row", event: MouseEvent, item: any): void`
|
|
2237
2441
|
- `item:selected` — `(e: "item:selected", value: any): void`
|
|
2238
2442
|
- `item:unselected` — `(e: "item:unselected", value: any): void`
|
|
2239
2443
|
- `update:expandedItems` — `(e: "update:expandedItems", value: any[]): void`
|
|
@@ -2248,13 +2452,15 @@ records list.
|
|
|
2248
2452
|
- `actions` — scope: `{ expanded?: boolean \| undefined; expandProps?: ExpandControllerProps \| undefined; toggleExpanded?: (() => void) \| undefined; highlighted?: boolean \| undefi…` — Content rendered in the actions cell for each row.
|
|
2249
2453
|
- `expand` — scope: `{ expanded: boolean; expandProps?: ExpandControllerProps \| undefined; toggleExpanded: () => void; highlighted?: boolean \| undefined; toggleHighlighted?: (() =…` — Full-width expandable content row rendered below each main row when expanded.
|
|
2250
2454
|
- `header:actions` — scope: `{ text: string; }` — Replaces the default actions header cell content.
|
|
2455
|
+
- `header:append` — scope: `BbTableHeaderAffixSlotProps<Item>` — Content rendered after every data column's header cell content — the label + sort control, or the column's own `header:<key>` replacement. A column's `header:<key>:append` slot wins over this one for that column; they never stack. Branch on…
|
|
2456
|
+
- `header:prepend` — scope: `BbTableHeaderAffixSlotProps<Item>` — Content rendered before every data column's header cell content — the label + sort control, or the column's own `header:<key>` replacement. A column's `header:<key>:prepend` slot wins over this one for that column; they never stack. Branch …
|
|
2251
2457
|
- `header:select` — scope: `{ multiple: boolean; selectAll: boolean; text: string; }` — Replaces the default selection header cell content (checkbox or radio label).
|
|
2252
2458
|
- `loading` — scope: `{ items: Item[]; }` — Content shown while table rows are loading (replaces the skeleton rows).
|
|
2253
|
-
- `no-data` — scope: `object` — Content shown when the items list is empty and not loading. It fills the table's own full-width empty-state cell (
|
|
2459
|
+
- `no-data` — scope: `object` — Content shown when the items list is empty and not loading. It fills the table's own full-width empty-state cell (it already spans the selection/actions columns), so provide the *content* — a message, an illustration, a "clear filters" butt…
|
|
2254
2460
|
- `select` — scope: `{ item: Item; value: any; checked: boolean; disabled: boolean; inputName: string; readonly: boolean; toggleSelected?: (() => void) \| undefined; }` — Replaces the default checkbox/radio in the selection cell for each row.
|
|
2255
|
-
- `tbody` — scope: `object` — Replaces the
|
|
2256
|
-
- `tfoot` — scope: `{ columnCount: number; }` —
|
|
2257
|
-
- `thead` — scope: `object` — Replaces the
|
|
2461
|
+
- `tbody` — scope: `object` — Replaces the content of the body row group (`.bb-table__body`). Use when you need full control over the body markup. Provide role-complete rows — `<div role="row">` holding one `<div role="cell">` per column — never a `<tr>`/`<td>`. A full-…
|
|
2462
|
+
- `tfoot` — scope: `{ columnCount: number; }` — Fills the footer row group (`.bb-table__foot`). Use when you need a footer. Provide role-complete rows — `<div role="row">` holding `<div role="cell">` elements — never a `<tr>`/`<td>`.
|
|
2463
|
+
- `thead` — scope: `object` — Replaces the content of the header row group (`.bb-table__head`). Use when you need full control over the header markup. The table is a CSS grid, not a `<table>`: provide role-complete rows — `<div role="row">` holding one `<div role="colum…
|
|
2258
2464
|
|
|
2259
2465
|
## See Also
|
|
2260
2466
|
|