bitboss-ui 3.0.0-beta.20 → 3.0.0-beta.21
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/dist/ai/BbTable.md +206 -98
- package/dist/ai/changelog.json +21 -3
- package/dist/ai/components.json +40 -15
- package/dist/ai/guides/component-picker.md +18 -18
- package/dist/ai/guides/icons-policy.md +7 -3
- package/dist/ai/guides/installation-and-plugin-setup.md +11 -14
- package/dist/ai/guides/migration/components/bb-table.md +131 -17
- package/dist/ai/recipes/inertia/approvals-inbox.md +0 -1
- package/dist/ai/recipes/inertia/inline-edit-workspace.md +0 -1
- package/dist/ai/recipes/inertia/ownership-atlas.md +8 -9
- package/dist/ai/recipes/inertia/record-form.md +0 -1
- package/dist/ai/recipes/inertia/records-workspace.md +0 -1
- package/dist/ai/recipes/inertia/upload-center.md +0 -1
- package/dist/ai/recipes/nuxt/approvals-inbox.md +0 -1
- package/dist/ai/recipes/nuxt/inline-edit-workspace.md +0 -1
- package/dist/ai/recipes/nuxt/record-form.md +0 -1
- package/dist/ai/recipes/nuxt/records-workspace.md +0 -1
- package/dist/ai/recipes/nuxt/upload-center.md +0 -1
- package/dist/ai/recipes/vue/approvals-inbox.md +0 -1
- package/dist/ai/recipes/vue/inline-edit-workspace.md +0 -1
- package/dist/ai/recipes/vue/records-workspace.md +0 -1
- package/dist/ai/recipes/vue/upload-center.md +0 -1
- package/dist/ai/source/BbTable.md +564 -173
- package/dist/components/BbTable/BbTable.vue.d.ts +2 -0
- package/dist/components/BbTable/BbTable.vue_vue_type_script_setup_true_lang.js +865 -735
- package/dist/components/BbTable/types.d.ts +98 -46
- package/dist/components/BbTable/utils.d.ts +21 -16
- package/dist/components/BbTable/utils.js +8 -8
- package/dist/composables/useTableWidthContext.d.ts +24 -4
- package/dist/composables/useTableWidthContext.js +31 -28
- package/dist/deprecation/ai-deprecations.json.d.ts +22 -0
- package/dist/deprecation/ai-deprecations.json.js +1 -1
- package/dist/llms-full.txt +381 -173
- package/dist/llms-medium.txt +29 -32
- package/dist/vite.js +1 -1
- package/package.json +1 -1
- package/scripts/lib/eslint-plugin.mjs +9 -14
- package/scripts/lib/validate-bb-markup.mjs +0 -7
package/dist/ai/components.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 1,
|
|
3
3
|
"library": "bitboss-ui",
|
|
4
|
-
"version": "3.0.0-beta.
|
|
5
|
-
"generatedAt": "2026-09-
|
|
4
|
+
"version": "3.0.0-beta.21",
|
|
5
|
+
"generatedAt": "2026-09-07T15:58:18.552Z",
|
|
6
6
|
"composables": [
|
|
7
7
|
{
|
|
8
8
|
"name": "useBbConfig",
|
|
@@ -13161,13 +13161,6 @@
|
|
|
13161
13161
|
"required": false,
|
|
13162
13162
|
"description": "Function that accepts the columns and the current item as\narguments and returns a label to be used for accessibility purposes.\nThe cells arrive in RENDER order (they follow `order`, so the\nlabel reads like the row) — look a cell up by `key`, never by position."
|
|
13163
13163
|
},
|
|
13164
|
-
{
|
|
13165
|
-
"name": "actions",
|
|
13166
|
-
"type": "boolean | undefined",
|
|
13167
|
-
"required": false,
|
|
13168
|
-
"default": "false",
|
|
13169
|
-
"description": "Displays the actions column."
|
|
13170
|
-
},
|
|
13171
13164
|
{
|
|
13172
13165
|
"name": "actionsText",
|
|
13173
13166
|
"type": "string | undefined",
|
|
@@ -13258,11 +13251,11 @@
|
|
|
13258
13251
|
"description": "Splits the width equally among the columns that declare no `width`\n(each undeclared column becomes a `minmax(0, 1fr)` track)\nmaking each column take up the same amount of space."
|
|
13259
13252
|
},
|
|
13260
13253
|
{
|
|
13261
|
-
"name": "
|
|
13262
|
-
"type": "
|
|
13254
|
+
"name": "fixedActions",
|
|
13255
|
+
"type": "boolean | undefined",
|
|
13263
13256
|
"required": false,
|
|
13264
|
-
"default": "
|
|
13265
|
-
"description": "
|
|
13257
|
+
"default": "false",
|
|
13258
|
+
"description": "Pins the actions column (the one the `#actions` slot creates) to the\nright edge, `position: sticky`, in place. Data columns pin through\n`column.fixed`; this is the same feature for the structural column that\nhas no definition to carry it. No effect without an `#actions` slot."
|
|
13266
13259
|
},
|
|
13267
13260
|
{
|
|
13268
13261
|
"name": "fixedHeaders",
|
|
@@ -13271,6 +13264,13 @@
|
|
|
13271
13264
|
"default": "false",
|
|
13272
13265
|
"description": "Boolean that sets the headers as sticky to the top of the table."
|
|
13273
13266
|
},
|
|
13267
|
+
{
|
|
13268
|
+
"name": "fixedSelect",
|
|
13269
|
+
"type": "boolean | undefined",
|
|
13270
|
+
"required": false,
|
|
13271
|
+
"default": "false",
|
|
13272
|
+
"description": "Pins the selection column to the left edge, `position: sticky`, in\nplace. Data columns pin through `column.fixed`; this is the same feature\nfor the structural column that has no definition to carry it. No effect\nunless the table is `selectable`."
|
|
13273
|
+
},
|
|
13274
13274
|
{
|
|
13275
13275
|
"name": "headerRowClass",
|
|
13276
13276
|
"type": "Classes | undefined",
|
|
@@ -13381,7 +13381,7 @@
|
|
|
13381
13381
|
"type": "string[] | undefined",
|
|
13382
13382
|
"required": false,
|
|
13383
13383
|
"default": "[]",
|
|
13384
|
-
"description": "Used by `v-model:order`. Ordered array of column keys — the render\norder of the data columns. Keys listed here render first, in this order;\ndeclared columns it omits follow, in declaration order (so a column added\nto `columns` later renders last); keys that match no declared column render\nnothing but are PRESERVED in place on every write
|
|
13384
|
+
"description": "Used by `v-model:order`. Ordered array of column keys — the render\norder of the data columns. Keys listed here render first, in this order;\ndeclared columns it omits follow, in declaration order (so a column added\nto `columns` later renders last); a `hidden` column keeps its slot\nwithout rendering, and keys that match no declared column render\nnothing but are PRESERVED in place on every write. The header drag /\nkeyboard reorder of `reorderable` writes it back complete (every\ndeclared key present, hidden ones included, duplicates dropped — first\noccurrence wins) with exactly the moved column relocated: every other\nkey keeps its relative order, and a drop that changes nothing emits\nnothing. Works uncontrolled when unbound, exactly like `sort`. The\n`select` and `actions` columns are structural and never part of it."
|
|
13385
13385
|
},
|
|
13386
13386
|
{
|
|
13387
13387
|
"name": "page",
|
|
@@ -13506,6 +13506,11 @@
|
|
|
13506
13506
|
"name": "dblclick:row",
|
|
13507
13507
|
"signature": "(e: \"dblclick:row\", event: MouseEvent, item: any): void"
|
|
13508
13508
|
},
|
|
13509
|
+
{
|
|
13510
|
+
"name": "hide:column",
|
|
13511
|
+
"signature": "(e: \"hide:column\", key: string): void",
|
|
13512
|
+
"description": "A column was hidden from its header (a `#header:<key>` /\n`#header:<key>:append` control calling the slot's `hideColumn()`). Fired once;\nthe table keeps the column hidden for the mount, or until the column's\n`hidden` flag changes — write `hidden: true` into the definition to\npersist it, `hidden: false` (a column panel) to show it again."
|
|
13513
|
+
},
|
|
13509
13514
|
{
|
|
13510
13515
|
"name": "item:selected",
|
|
13511
13516
|
"signature": "(e: \"item:selected\", value: any): void"
|
|
@@ -13552,7 +13557,7 @@
|
|
|
13552
13557
|
{
|
|
13553
13558
|
"name": "actions",
|
|
13554
13559
|
"type": "{ expanded?: boolean | undefined; expandProps?: ExpandControllerProps | undefined; toggleExpanded?: (() => void) | undefined; highlighted?: boolean | undefined; toggleHighlighted?: (() => void) | undefined; selected?: boolean | undefined; toggleSelected?: (() => void) | undefined; item: Item; value: any; }",
|
|
13555
|
-
"description": "Content rendered in the actions cell for each row."
|
|
13560
|
+
"description": "Content rendered in the actions cell for each row. Providing this slot\nis what CREATES the actions column (there is no prop): the header cell\n(labelled by `actions-text`, replaceable through `#header:actions`) and\none cell per row appear with it, and go away with it. Pin it with\n`fixed-actions`."
|
|
13556
13561
|
},
|
|
13557
13562
|
{
|
|
13558
13563
|
"name": "expand",
|
|
@@ -13661,6 +13666,26 @@
|
|
|
13661
13666
|
"fix": {
|
|
13662
13667
|
"kind": "rename"
|
|
13663
13668
|
}
|
|
13669
|
+
},
|
|
13670
|
+
{
|
|
13671
|
+
"name": "actions",
|
|
13672
|
+
"new": null,
|
|
13673
|
+
"since": "3.0.0-beta.21",
|
|
13674
|
+
"migration": "ai/guides/migration/components/bb-table.md",
|
|
13675
|
+
"silent": true,
|
|
13676
|
+
"fix": {
|
|
13677
|
+
"kind": "remove"
|
|
13678
|
+
}
|
|
13679
|
+
},
|
|
13680
|
+
{
|
|
13681
|
+
"name": "fixedColumns",
|
|
13682
|
+
"new": null,
|
|
13683
|
+
"since": "3.0.0-beta.21",
|
|
13684
|
+
"migration": "ai/guides/migration/components/bb-table.md",
|
|
13685
|
+
"silent": true,
|
|
13686
|
+
"fix": {
|
|
13687
|
+
"kind": "manual"
|
|
13688
|
+
}
|
|
13664
13689
|
}
|
|
13665
13690
|
],
|
|
13666
13691
|
"renamed": [
|
|
@@ -231,24 +231,24 @@ a composable you want is not in this corpus's `composables/` folder — it is no
|
|
|
231
231
|
here.** Check this list before inventing a name; if the need is genuinely absent,
|
|
232
232
|
compose it or write it yourself.
|
|
233
233
|
|
|
234
|
-
| Assumed component or composable | Reality
|
|
235
|
-
| -------------------------------------------------------------- |
|
|
236
|
-
| `BbColumnManager` — show/hide/reorder columns | Does not exist as a component. Order is `v-model:order` on `BbTable` (an array of keys any panel can write; `reorderable` adds the built-in header drag + keyboard handle); visibility is
|
|
237
|
-
| `BbKanban` / drag-and-drop board | Does not exist. There is no reusable DnD primitive in the library (`BbTable`'s header drag is internal to the table) — compose the board from `BbTable` (a table/list view of the same data) or hand-roll the drag-and-drop interaction yourself.
|
|
238
|
-
| `BbModal` | It is [BbDialog](../BbDialog.md).
|
|
239
|
-
| `BbDrawer` / `BbSheet` | It is [BbOffCanvas](../BbOffCanvas.md).
|
|
240
|
-
| `BbCombobox` / `BbAutocomplete` | It is [BbSelect](../BbSelect.md) / [BbSelectPopover](../BbSelectPopover.md) — search is built in, see `disable-writing`.
|
|
241
|
-
| `BbToggle` / `BbToggleGroup` | It is [BbButton](../BbButton.md) with `v-model` (+ `true-value` / `false-value`), which owns `aria-pressed` and the active class.
|
|
242
|
-
| `TagChip` / colored, read-only tag chip | It is [BbBadge](../BbBadge.md) — [BbTag](../BbTag.md) is a tags-_input_ only, not a display component. Use `BbBadge` with a registered `soft-*` variant for a fixed palette, or a one-off `--bg`/`--color` override per row for arbitrary/data-driven colors (BbBadge.md § One-off colors) — not a registered variant per distinct color.
|
|
243
|
-
| `BbTab` (singular) | The consumer API is [BbTabs](../BbTabs.md) / `BbTabsRoot`. `BbTab` appears only as the **v2 "before" side** of the migration diffs.
|
|
244
|
-
| `BbCard` | Does not exist — a card is a `<div>` with tokens. See [design-language](./design-language.md).
|
|
245
|
-
| `BbList` / `BbListItem` / `BbDescriptionList` | Do not exist — a list row is an `<li>` with tokens, and [BbBaseButton](../BbBaseButton.md) makes the whole row navigable. See the note under Data Display.
|
|
246
|
-
| `useLiveFeed` / any polling or cross-tab feed helper | Does not exist, and neither does a cross-tab helper — `useBroadcastChannelInstance` was removed (cross-tab messaging is not a UI concern). Use `useBroadcastChannel` from `@vueuse/core`; the polling and the merge are yours.
|
|
247
|
-
| `BbStepper` / `BbWizard` | Does not exist as a component; the wizard-form recipe composes one.
|
|
248
|
-
| `BbSkeleton` (standalone) | Only `BbTable` ships skeletons, via the column `skeleton` field.
|
|
249
|
-
| `BbCommand` / command palette | Does not exist. Compose `BbDialog` + `BbSelectPopover`.
|
|
250
|
-
| `BbCalendar` (month / scheduling view) | Does not exist. [BbDatePicker](../BbDatePicker.md) is a picker, not a calendar surface.
|
|
251
|
-
| `BbChart` / `BbGraph`, `BbCarousel`, `BbTimeline`, `BbDivider` | Do not exist. No charting, carousel or timeline primitive ships here.
|
|
234
|
+
| Assumed component or composable | Reality |
|
|
235
|
+
| -------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
236
|
+
| `BbColumnManager` — show/hide/reorder columns | Does not exist as a component. Order is `v-model:order` on `BbTable` (an array of keys any panel can write; `reorderable` adds the built-in header drag + keyboard handle); visibility is `hidden: true` on the column definition (the column stays declared and keeps its slot in the order; header slots get a `hideColumn()` that fires `hide:column`). Compose the panel from `BbPopover` + `BbCheckbox`. |
|
|
237
|
+
| `BbKanban` / drag-and-drop board | Does not exist. There is no reusable DnD primitive in the library (`BbTable`'s header drag is internal to the table) — compose the board from `BbTable` (a table/list view of the same data) or hand-roll the drag-and-drop interaction yourself. |
|
|
238
|
+
| `BbModal` | It is [BbDialog](../BbDialog.md). |
|
|
239
|
+
| `BbDrawer` / `BbSheet` | It is [BbOffCanvas](../BbOffCanvas.md). |
|
|
240
|
+
| `BbCombobox` / `BbAutocomplete` | It is [BbSelect](../BbSelect.md) / [BbSelectPopover](../BbSelectPopover.md) — search is built in, see `disable-writing`. |
|
|
241
|
+
| `BbToggle` / `BbToggleGroup` | It is [BbButton](../BbButton.md) with `v-model` (+ `true-value` / `false-value`), which owns `aria-pressed` and the active class. |
|
|
242
|
+
| `TagChip` / colored, read-only tag chip | It is [BbBadge](../BbBadge.md) — [BbTag](../BbTag.md) is a tags-_input_ only, not a display component. Use `BbBadge` with a registered `soft-*` variant for a fixed palette, or a one-off `--bg`/`--color` override per row for arbitrary/data-driven colors (BbBadge.md § One-off colors) — not a registered variant per distinct color. |
|
|
243
|
+
| `BbTab` (singular) | The consumer API is [BbTabs](../BbTabs.md) / `BbTabsRoot`. `BbTab` appears only as the **v2 "before" side** of the migration diffs. |
|
|
244
|
+
| `BbCard` | Does not exist — a card is a `<div>` with tokens. See [design-language](./design-language.md). |
|
|
245
|
+
| `BbList` / `BbListItem` / `BbDescriptionList` | Do not exist — a list row is an `<li>` with tokens, and [BbBaseButton](../BbBaseButton.md) makes the whole row navigable. See the note under Data Display. |
|
|
246
|
+
| `useLiveFeed` / any polling or cross-tab feed helper | Does not exist, and neither does a cross-tab helper — `useBroadcastChannelInstance` was removed (cross-tab messaging is not a UI concern). Use `useBroadcastChannel` from `@vueuse/core`; the polling and the merge are yours. |
|
|
247
|
+
| `BbStepper` / `BbWizard` | Does not exist as a component; the wizard-form recipe composes one. |
|
|
248
|
+
| `BbSkeleton` (standalone) | Only `BbTable` ships skeletons, via the column `skeleton` field. |
|
|
249
|
+
| `BbCommand` / command palette | Does not exist. Compose `BbDialog` + `BbSelectPopover`. |
|
|
250
|
+
| `BbCalendar` (month / scheduling view) | Does not exist. [BbDatePicker](../BbDatePicker.md) is a picker, not a calendar surface. |
|
|
251
|
+
| `BbChart` / `BbGraph`, `BbCarousel`, `BbTimeline`, `BbDivider` | Do not exist. No charting, carousel or timeline primitive ships here. |
|
|
252
252
|
|
|
253
253
|
App chrome — an app shell, sidebar, page header, selection dock — is
|
|
254
254
|
deliberately **not** a component: it is yours to own. The per-platform
|
|
@@ -36,9 +36,13 @@ The `bitbossUi` Vite plugin (`iconDir` option) — or the Nuxt module (config ke
|
|
|
36
36
|
`lucide:<name>` available; removing it makes them all errors. Nothing to
|
|
37
37
|
configure.
|
|
38
38
|
- **Dev**: all icons of installed sets are registered. Referencing an
|
|
39
|
-
uninstalled prefix or a non-existent name fails loudly
|
|
40
|
-
|
|
41
|
-
|
|
39
|
+
uninstalled prefix or a non-existent name fails loudly in the Vite error
|
|
40
|
+
overlay with an actionable message. A typo inside an installed set reads
|
|
41
|
+
"does not exist in the lucide icon set — did you mean `lucide:…`?"; a set
|
|
42
|
+
that is not installed reads "no installed icon set has the prefix `mdi`
|
|
43
|
+
(installed sets: lucide) … run: `npm install -D @iconify-json/mdi`". Read
|
|
44
|
+
the message: a typo wants a different name, a missing set wants an install,
|
|
45
|
+
never a guess.
|
|
42
46
|
- **Build**: source files (`.vue`/`.ts`/`.js`/`.tsx`/`.jsx`; tests and stories
|
|
43
47
|
excluded) are scanned for static `provider:name` literals; each referenced
|
|
44
48
|
icon is emitted as its own lazy chunk. This is why rule 4 exists — and why an
|
|
@@ -31,19 +31,16 @@ goes stable, so never reach for it here.
|
|
|
31
31
|
|
|
32
32
|
Peer dependency: `vue ^3.5.12` — the only required one. `@inertiajs/vue3` is an **optional** peer, needed only in Inertia apps.
|
|
33
33
|
|
|
34
|
-
`@iconify/collections
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
mean …?" suggestion for a mistyped icon name) never fire — a wrong provider
|
|
45
|
-
icon then surfaces only as `BbIcon`'s generic runtime `Icon "…" does not exist.`
|
|
46
|
-
Nothing else changes: icons that resolve still render, in dev and in production.
|
|
34
|
+
You do **not** need `@iconify/collections`. It is declared as an optional peer
|
|
35
|
+
for one reason only: when it happens to be installed, the dev-overlay message
|
|
36
|
+
for an unknown icon prefix can say for certain whether that prefix is a real
|
|
37
|
+
Iconify set ("requires `@iconify-json/mdi`, run …") or not ("neither an
|
|
38
|
+
installed set nor a known Iconify prefix"). Without it the same overlay fires
|
|
39
|
+
with a hedged wording ("no installed icon set has the prefix `mdi`; if it is an
|
|
40
|
+
Iconify set, run …"). A mistyped name inside a set you **have** installed
|
|
41
|
+
(`lucide:eye-misspelled`) is diagnosed from the set's own data in both cases,
|
|
42
|
+
with a "did you mean …?" suggestion. Nothing else changes: icons that resolve
|
|
43
|
+
still render, in dev and in production.
|
|
47
44
|
|
|
48
45
|
**Known-good toolchain:** TypeScript **5.x or 6.x** if your build gate runs
|
|
49
46
|
`vue-tsc`. Both type-check cleanly against the shipped `.d.ts`; the library
|
|
@@ -308,7 +305,7 @@ utilities. (Same trap as the scoped-`<style>` case above, one level up.)
|
|
|
308
305
|
## 6) Icons
|
|
309
306
|
|
|
310
307
|
- `iconDir` (required) is scanned recursively for `.svg` files; each file becomes `local:<basename>`.
|
|
311
|
-
- Provider icons (`lucide:pencil`, `mdi:home`, …) require the matching `@iconify-json/<prefix>` package installed in the consumer app.
|
|
308
|
+
- Provider icons (`lucide:pencil`, `mdi:home`, …) require the matching `@iconify-json/<prefix>` package installed in the consumer app. In dev, every `prefix:name` the registry does not know produces a Vite error overlay with the fix: a mistyped name inside an installed set gets a "did you mean …?" hint, and an uninstalled prefix gets the list of installed sets plus the `npm install -D @iconify-json/<prefix>` command (the optional `@iconify/collections` peer only sharpens that wording, see [Install](#1-install)). A missing `local:` icon is a missing file in `iconDir` and surfaces as `BbIcon`'s runtime error naming it. Production builds report none of this — the scan simply drops what does not resolve, so a wrong name fails at runtime there.
|
|
312
309
|
- Production builds bundle **only statically referenced** provider icons — write icon names as literal strings (`icon="lucide:trash-2"`), never assemble them dynamically.
|
|
313
310
|
- The plugin also writes `node_modules/.bitboss-ui/local-icons.json` and (in dev, unless `vscodeSettings: false`) wires `.vscode/settings.json` so the Iconify editor extension previews local icons.
|
|
314
311
|
|
|
@@ -7,20 +7,24 @@ summary: 'The table renders as a CSS grid of divs with ARIA roles, not a <table>
|
|
|
7
7
|
|
|
8
8
|
## Changes
|
|
9
9
|
|
|
10
|
-
| v2
|
|
11
|
-
|
|
|
12
|
-
| `allowSelectAll?: boolean` (default `true`)
|
|
13
|
-
| refetch with rows → skeleton
|
|
14
|
-
| rows interactive while loading
|
|
15
|
-
| `#loading` slot fired on every load
|
|
16
|
-
| `#no-data` replaced the empty-state `<tr>`
|
|
17
|
-
| `<table>` / `<thead>` / `<tbody>` / `<tr>` / `<th>` / `<td>` markup _(v2 and v3 ≤ beta.5)_
|
|
18
|
-
| `--fill` / `--natural-width` published on `.bb-table` _(v3 ≤ beta.5)_
|
|
19
|
-
| —
|
|
20
|
-
| —
|
|
21
|
-
| `
|
|
22
|
-
|
|
|
23
|
-
|
|
|
10
|
+
| v2 | v3 | Kind |
|
|
11
|
+
| ------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------- |
|
|
12
|
+
| `allowSelectAll?: boolean` (default `true`) | `disableSelectAll?: boolean` (default `false`) | rename, polarity inverted |
|
|
13
|
+
| refetch with rows → skeleton | refetch keeps rows visible (dimmed + progress bar) | **behavior** — the skeleton only shows when there is nothing to display |
|
|
14
|
+
| rows interactive while loading | header + rows go `inert` while loading | **behavior** — opt out with `interactive-while-loading` |
|
|
15
|
+
| `#loading` slot fired on every load | fires on the **first load only** (it replaces the skeleton, so it follows the skeleton's rule) | **⚠ silent** for anyone styling refetches through it |
|
|
16
|
+
| `#no-data` replaced the empty-state `<tr>` | fills the table's own full-width cell (`aria-colspan` counted, centred) | **behavior** — pass content, not a row |
|
|
17
|
+
| `<table>` / `<thead>` / `<tbody>` / `<tr>` / `<th>` / `<td>` markup _(v2 and v3 ≤ beta.5)_ | a CSS grid of `<div>`s carrying `role="table\|rowgroup\|row\|columnheader\|cell"`; `.bb-table__table` / `__head` / `__body` / `__foot` are the new containers, every `.bb-table*` class survives | **⚠ silent** for element selectors, `#thead`/`#tbody`/`#tfoot` markup, copy/paste and print — see below |
|
|
18
|
+
| `--fill` / `--natural-width` published on `.bb-table` _(v3 ≤ beta.5)_ | **removed** — nothing publishes them | **⚠ silent** — see below |
|
|
19
|
+
| — | props `enforceCoherence` (prunes row-keyed models after each load; incompatible with pagination-via-`dependencies`), `expandedItems` + `#expand`, `sort`, `keyboardNavigation`, `highlighted`, `rowClass`, `order` (v-model) + `reorderable`, `resizable` + `resize:column`, header-slot `hideColumn()` + `hide:column`, `fixedSelect` / `fixedActions` | additive |
|
|
20
|
+
| — | **column** fields `sortable?: boolean`, `rowClass?: ColumnClasses`, `hidden?: boolean` (the column stays declared — the way to hide, see § Do not override), `fixed?: 'left' \| 'right'` (replaces `fixedColumns`, see below) | additive, **collides** — see below |
|
|
21
|
+
| `actions?: boolean` prop _(v2 and v3 ≤ beta.20)_ | **removed** — the `#actions` slot creates the column by itself | **⚠ silent** if you passed the prop without the slot — see below |
|
|
22
|
+
| `fixedColumns` prop (rendered-slot indices, `[0, { index, position }]`) _(v2 and v3 ≤ beta.20)_ | **removed** — `fixed: 'left' \| 'right'` on the column definition, `fixed-select` / `fixed-actions` for the structural columns | **⚠ silent** — see below |
|
|
23
|
+
| column `snap?: number \| [number, number]` — gridline indices into the parent's rendered columns (`select` at 0, fractions, `-1` = data end) _(v3 ≤ beta.20)_ | `snap?: string \| [string, string]` — the PARENT's column key, or `'select'` / `'actions'`; a pair is inclusive; `'amount.5'` is a fraction. Same-key columns pair by default. Ignored (dev warning) under a parent that uses `order` / `reorderable` | **⚠ silent** — see below |
|
|
24
|
+
| `--table-{id}-track-{index}` published per data column _(v3 ≤ beta.20)_ | `--table-{id}-track-{key}` — the column key in its slot-name spelling (`address_city`); `select` / `actions` unchanged | **⚠ silent** for CSS that read the vars by index — see below |
|
|
25
|
+
| `useBbTableContext(id).total` _(v3 alphas ≤ 4)_ | `useBbTableContext(id).totalItems` | **hard rename** on the composable handle — see below |
|
|
26
|
+
| `@click:row` / `@contextmenu:row` / `@dblclick:row` handlers receive `(event, item, selected)` _(v2 and v3 ≤ beta.5)_ | `(event, item)` — `item` is now your raw record (was the internal row wrapper, record at `row.item`); the trailing `selected` boolean is gone | **payload slimmed** — see below |
|
|
27
|
+
| `--bb-table-*` custom properties | same names without the `bb-` prefix | **⚠ silent** for nested-table layouts — see below |
|
|
24
28
|
|
|
25
29
|
## Columns gained `sortable` and `rowClass` — check yours first
|
|
26
30
|
|
|
@@ -127,6 +131,113 @@ If you used `#loading` to show a custom refetch treatment, that role is gone —
|
|
|
127
131
|
the built-in dim + progress bar covers refetches; `#loading` is now only the
|
|
128
132
|
first-paint placeholder.
|
|
129
133
|
|
|
134
|
+
### The `#actions` slot creates the actions column — the prop is gone (v3 beta, 2026-09-07)
|
|
135
|
+
|
|
136
|
+
`actions` used to be a boolean prop that rendered the column, with the
|
|
137
|
+
`#actions` slot filling it. The prop carried no information the slot did
|
|
138
|
+
not, and it had a footgun: a consumer who declared `{ key: 'actions' }` in
|
|
139
|
+
`columns` instead of setting the prop got a stray empty data cell and a slot
|
|
140
|
+
that never rendered. Now the slot alone creates the column — header cell
|
|
141
|
+
(labelled by `actions-text`, replaceable through `#header:actions`), one
|
|
142
|
+
cell per row, and the `actions` track for nested tables — and removing the
|
|
143
|
+
slot (or gating it with `v-if`) removes the column live.
|
|
144
|
+
|
|
145
|
+
```diff
|
|
146
|
+
- <BbTable actions :columns="columns" :items="rows">
|
|
147
|
+
+ <BbTable :columns="columns" :items="rows">
|
|
148
|
+
<template #actions="{ item }">…</template>
|
|
149
|
+
</BbTable>
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
Delete the attribute. The removed-prop warner flags it in dev, the ESLint rule
|
|
153
|
+
flags it in-editor. The only silent case is a table that set `actions`
|
|
154
|
+
without ever providing the slot: it had an empty column, and now it does not.
|
|
155
|
+
|
|
156
|
+
### `fixedColumns` → `fixed` on the column, `fixed-select` / `fixed-actions` (v3 beta, 2026-09-07)
|
|
157
|
+
|
|
158
|
+
Pins used to be **slot indices** into the rendered column list (a selection
|
|
159
|
+
column was index 0), like spreadsheet freeze panes: with `order` and
|
|
160
|
+
`reorderable` the pinned _slot_ held and whichever column landed in it was
|
|
161
|
+
pinned, which is fragile once users drag headers and hide columns. Pins are
|
|
162
|
+
now a property of the column, the way `width` and `hidden` are, and follow
|
|
163
|
+
it through reorders. The sticky behaviour itself is unchanged: in place, at
|
|
164
|
+
the column's own render position, offset by the pinned columns before it on
|
|
165
|
+
the same side.
|
|
166
|
+
|
|
167
|
+
```diff
|
|
168
|
+
- <BbTable
|
|
169
|
+
- :columns="columns"
|
|
170
|
+
- :fixed-columns="[0, { index: columns.length + 1, position: 'right' }]"
|
|
171
|
+
- selectable
|
|
172
|
+
- >
|
|
173
|
+
+ <BbTable :columns="columns" fixed-select fixed-actions selectable>
|
|
174
|
+
<template #actions="{ item }">…</template>
|
|
175
|
+
</BbTable>
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
```diff
|
|
179
|
+
const columns = [
|
|
180
|
+
- { key: 'name', label: 'Name' },
|
|
181
|
+
+ { key: 'name', label: 'Name', fixed: 'left' },
|
|
182
|
+
{ key: 'amount', label: 'Amount', align: 'right' },
|
|
183
|
+
];
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
Translate each index to the column that sat there: data columns get
|
|
187
|
+
`fixed: 'left' | 'right'` on their definition, the selection column becomes
|
|
188
|
+
`fixed-select`, the actions column `fixed-actions` (each has one sensible
|
|
189
|
+
side, so they are booleans). A nested table that pinned its own actions with
|
|
190
|
+
`{ index: childColumns.length, position: 'right' }` now says
|
|
191
|
+
`fixed-actions`. Silent on upgrade: the old prop is ignored (the warner and
|
|
192
|
+
the ESLint rule flag it), so a table that pinned columns stops pinning until
|
|
193
|
+
you move the pins onto the definitions.
|
|
194
|
+
|
|
195
|
+
### `snap` names the parent column, not a gridline (v3 beta, 2026-09-07)
|
|
196
|
+
|
|
197
|
+
A nested table's `snap` was a number: a gridline index into the parent's
|
|
198
|
+
rendered columns, with the selection column at `0`, fractions for partial
|
|
199
|
+
tracks and `-1` for the end of the data region. Index `k` was whatever column
|
|
200
|
+
happened to render there, so a reorder or a hidden column on the parent
|
|
201
|
+
moved every snap. The parent now publishes its tracks under **column keys**,
|
|
202
|
+
and `snap` names the parent column:
|
|
203
|
+
|
|
204
|
+
```diff
|
|
205
|
+
const holdings = [
|
|
206
|
+
- { key: 'name', label: 'Resource', snap: 1 },
|
|
207
|
+
- { key: 'kind', label: 'Type', snap: 2 },
|
|
208
|
+
- { key: 'monthlyCost', label: '$ / mo', align: 'right', snap: [3, 4.5] },
|
|
209
|
+
+ { key: 'name', label: 'Resource', snap: 'name' },
|
|
210
|
+
+ { key: 'kind', label: 'Type', snap: 'team' },
|
|
211
|
+
+ { key: 'monthlyCost', label: '$ / mo', align: 'right', snap: ['region', 'monthly.5'] },
|
|
212
|
+
];
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
- Translate each index to the parent column that rendered there. The
|
|
216
|
+
selection column is `'select'`, the actions column `'actions'` — both are
|
|
217
|
+
targets by name, so `['name', 'actions']` runs a child column across the
|
|
218
|
+
parent's actions cell.
|
|
219
|
+
- A pair is **inclusive**: `['client', 'amount']` spans from the start of
|
|
220
|
+
`client` through the end of `amount` (the old `[a, b]` ended at the start
|
|
221
|
+
of `b`). A trailing `.digits` on a key is a fraction of that track. `-1`
|
|
222
|
+
is gone: the last column already runs to the end of the data region unless
|
|
223
|
+
it declares a `width` or a pair.
|
|
224
|
+
- A child column with no `snap` now pairs with the parent column of the
|
|
225
|
+
**same key** when there is one, so most children need no snaps at all; a
|
|
226
|
+
column the parent lacks (or hides) flows into the next free parent track.
|
|
227
|
+
- Under a parent that uses `order` or `reorderable`, snaps and key pairing
|
|
228
|
+
are ignored (dev builds warn) and the child inherits by position, as it
|
|
229
|
+
always did — a moving parent can only be followed slot by slot.
|
|
230
|
+
|
|
231
|
+
Silent on upgrade: a numeric `snap` fails the type check but is ignored at
|
|
232
|
+
runtime, so the child falls back to key pairing and flow, which for a child
|
|
233
|
+
sharing the parent's keys is the same alignment as before.
|
|
234
|
+
|
|
235
|
+
**The published track variables changed name with it.** `--table-{id}-track-{k}`
|
|
236
|
+
per data column became `--table-{id}-track-{key}`, the key in its slot-name
|
|
237
|
+
spelling (`address.city` → `address_city`); `select` and `actions` are
|
|
238
|
+
unchanged. Consumer CSS that read the numbered variables directly has to
|
|
239
|
+
switch to the keys. Nothing else about the bridge moved.
|
|
240
|
+
|
|
130
241
|
### `#no-data` is content, not a row
|
|
131
242
|
|
|
132
243
|
v2 handed the slot the whole empty-state `<tr>`, so anything that was not a
|
|
@@ -547,8 +658,11 @@ grid actually raises is Chrome/Edge, 114 → 117 (123 for centred cells).
|
|
|
547
658
|
- **Do not hide cells with `display: none`** (a `thClass`/`tdClass` of
|
|
548
659
|
`hidden`, the v2/early-v3 narrow-screen recipe). A hidden grid item leaves
|
|
549
660
|
its track in place: every following cell shifts one track over and the last
|
|
550
|
-
track collapses. Hide a column
|
|
551
|
-
breakpoint, which removes the track
|
|
661
|
+
track collapses. Hide a column with `hidden: true` on its definition at the
|
|
662
|
+
breakpoint, which removes the track while the column stays declared (so
|
|
663
|
+
its slot in `order` survives). Filtering it out of `columns` was the
|
|
664
|
+
interim advice and is now reserved for a column that does not exist for
|
|
665
|
+
this user at all.
|
|
552
666
|
- **`contain: inline-size` on `.bb-table-expand__cell`,
|
|
553
667
|
`.bb-table-no-data__cell` and `.bb-table-loading__cell`.** It is the only
|
|
554
668
|
thing keeping a full-width cell's content from resizing the column tracks —
|
|
@@ -569,7 +683,7 @@ grid actually raises is Chrome/Edge, 114 → 117 (123 for centred cells).
|
|
|
569
683
|
|
|
570
684
|
### Small semantic and visual changes
|
|
571
685
|
|
|
572
|
-
- **Pinned cells and the stuck header are opaque.** `fixed
|
|
686
|
+
- **Pinned cells and the stuck header are opaque.** Pinned (`column.fixed`) cells and
|
|
573
687
|
the `fixed-headers` band used to be transparent, so scrolled content showed
|
|
574
688
|
through them. They now paint the table's surface local `--bg` (default
|
|
575
689
|
`var(--bb-panel)`); a pinned cell also paints its row's hover/highlight
|
|
@@ -596,7 +596,6 @@ export function useApprovalsInbox(): ApprovalsInboxContext {
|
|
|
596
596
|
v-model:highlighted="ctx.highlighted.value"
|
|
597
597
|
v-model:select-all="ctx.table.all.value"
|
|
598
598
|
v-model:unselected-items="ctx.table.unselected.value"
|
|
599
|
-
actions
|
|
600
599
|
caption="Expense approvals"
|
|
601
600
|
:columns="columns"
|
|
602
601
|
compact
|
|
@@ -826,7 +826,6 @@ export function useBacklogWorkspace(): BacklogWorkspaceContext {
|
|
|
826
826
|
v-model:highlighted="highlightedIssue"
|
|
827
827
|
v-model:select-all="ctx.table.all.value"
|
|
828
828
|
v-model:unselected-items="ctx.table.unselected.value"
|
|
829
|
-
actions
|
|
830
829
|
caption="Sprint 24 backlog"
|
|
831
830
|
:columns="columns"
|
|
832
831
|
compact
|
|
@@ -63,10 +63,10 @@ OwnerPaginator::make(...), 'tabCounts' => [...], 'ownerOptions' => [...]])` —
|
|
|
63
63
|
the page.
|
|
64
64
|
- **The expand row is a real nested `BbTable` that inherits the parent's
|
|
65
65
|
column tracks.** `inherit-column-widths` snaps the holdings table onto the
|
|
66
|
-
owners table's grid;
|
|
67
|
-
column
|
|
68
|
-
|
|
69
|
-
one edge. This is the recipe's signature move — the full defense is in
|
|
66
|
+
owners table's grid; every child column carries an explicit `snap` naming
|
|
67
|
+
the parent column it sits under (`snap: 'name'` … `'monthly'` — the
|
|
68
|
+
parent's `select` column is accounted for by name), so Resource sits
|
|
69
|
+
exactly under Owner and the right-aligned $/mo columns share one edge. This is the recipe's signature move — the full defense is in
|
|
70
70
|
"Why it is built this way" and in the
|
|
71
71
|
[BbTable guide](../../BbTable.md) ("Nested tables that align with the
|
|
72
72
|
parent").
|
|
@@ -571,7 +571,6 @@ export function useOwnershipAtlas(): OwnershipAtlasContext {
|
|
|
571
571
|
v-model:highlighted="highlightedOwner"
|
|
572
572
|
v-model:select-all="ctx.table.all.value"
|
|
573
573
|
v-model:unselected-items="ctx.table.unselected.value"
|
|
574
|
-
actions
|
|
575
574
|
actions-text="Holdings"
|
|
576
575
|
caption="Resource owners"
|
|
577
576
|
class="table-flush"
|
|
@@ -902,10 +901,10 @@ defineProps<{ owner: Owner }>();
|
|
|
902
901
|
* the parent's first data column, and that inset is what reads as hierarchy.
|
|
903
902
|
*/
|
|
904
903
|
const columns: Array<BbTableColumn<Holding>> = [
|
|
905
|
-
{ key: 'name', label: 'Resource', snap:
|
|
906
|
-
{ key: 'kind', label: 'Type', snap:
|
|
907
|
-
{ key: 'status', label: 'Status', snap:
|
|
908
|
-
{ key: 'monthlyCost', label: '$ / mo', align: 'right', snap:
|
|
904
|
+
{ key: 'name', label: 'Resource', snap: 'name' },
|
|
905
|
+
{ key: 'kind', label: 'Type', snap: 'team' },
|
|
906
|
+
{ key: 'status', label: 'Status', snap: 'region' },
|
|
907
|
+
{ key: 'monthlyCost', label: '$ / mo', align: 'right', snap: 'monthly' },
|
|
909
908
|
];
|
|
910
909
|
|
|
911
910
|
const money = (value: number) =>
|
|
@@ -817,7 +817,6 @@ const ctx = useInvoiceForm();
|
|
|
817
817
|
<!-- Inline-editing table (§6.3): every editable cell type is its own
|
|
818
818
|
leaf. The amount column is virtual — computed from the row. -->
|
|
819
819
|
<BbTable
|
|
820
|
-
actions
|
|
821
820
|
caption="Invoice line items"
|
|
822
821
|
:columns="columns"
|
|
823
822
|
compact
|
|
@@ -531,7 +531,6 @@ export function useInvoicesWorkspace(): InvoicesWorkspaceContext {
|
|
|
531
531
|
v-model="ctx.table.selected.value"
|
|
532
532
|
v-model:select-all="ctx.table.all.value"
|
|
533
533
|
v-model:unselected-items="ctx.table.unselected.value"
|
|
534
|
-
actions
|
|
535
534
|
caption="Invoices"
|
|
536
535
|
:columns="columns"
|
|
537
536
|
compact
|
|
@@ -687,7 +687,6 @@ export function useUploadCenter(): UploadCenterContext {
|
|
|
687
687
|
v-model="ctx.table.selected.value"
|
|
688
688
|
v-model:select-all="ctx.table.all.value"
|
|
689
689
|
v-model:unselected-items="ctx.table.unselected.value"
|
|
690
|
-
actions
|
|
691
690
|
caption="Expense receipts"
|
|
692
691
|
:columns="columns"
|
|
693
692
|
compact
|
|
@@ -846,7 +846,6 @@ const ctx = useInvoiceForm();
|
|
|
846
846
|
<!-- Inline-editing table (§6.3): every editable cell type is its own
|
|
847
847
|
leaf. The amount column is virtual — computed from the row. -->
|
|
848
848
|
<BbTable
|
|
849
|
-
actions
|
|
850
849
|
caption="Invoice line items"
|
|
851
850
|
:columns="columns"
|
|
852
851
|
compact
|