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/llms-full.txt
CHANGED
|
@@ -27026,7 +27026,7 @@ needs is declared here, not in markup:
|
|
|
27026
27026
|
`(content, key, item) => Classes` for state-dependent styling. Table-level
|
|
27027
27027
|
`thClass` / `tdClass` / `rowClass` / `headerRowClass` apply everywhere; a
|
|
27028
27028
|
row's classes accumulate the table `rowClass` plus every column's.
|
|
27029
|
-
- **`snap`**
|
|
27029
|
+
- **`snap`** names the parent column a nested table's column sits under — see
|
|
27030
27030
|
Nested tables.
|
|
27031
27031
|
|
|
27032
27032
|
**Columns, formatters and a per-row class**
|
|
@@ -27155,11 +27155,11 @@ pre-mapping your items:
|
|
|
27155
27155
|
```
|
|
27156
27156
|
|
|
27157
27157
|
**`actions` and `select` are not columns.** Both are rendered by the table
|
|
27158
|
-
itself
|
|
27159
|
-
|
|
27160
|
-
|
|
27161
|
-
|
|
27162
|
-
builds warn.
|
|
27158
|
+
itself: the selection column from the `selectable` prop, the actions column
|
|
27159
|
+
from the `#actions` slot — providing the slot is what creates the column,
|
|
27160
|
+
there is no prop. Putting `{ key: 'actions' }` in `columns` adds an ordinary
|
|
27161
|
+
data column that reads `item.actions`, so you get a stray empty cell next to
|
|
27162
|
+
the real one. Dev builds warn.
|
|
27163
27163
|
|
|
27164
27164
|
### Custom cells and headers
|
|
27165
27165
|
|
|
@@ -27182,7 +27182,8 @@ Body cell scope: `content` (the formatted value), `item` (raw row), `value`
|
|
|
27182
27182
|
one-way state; the `toggle*` callbacks are the write path.
|
|
27183
27183
|
|
|
27184
27184
|
Header scope: `label`, `items` (the full list — handy for counts), `sortable`,
|
|
27185
|
-
`sortOrder`, `toggleSort`, `
|
|
27185
|
+
`sortOrder`, `toggleSort`, `hideColumn` (hides the column, see "Column
|
|
27186
|
+
visibility"), `classes`.
|
|
27186
27187
|
|
|
27187
27188
|
**Add beside a header instead of replacing it** with
|
|
27188
27189
|
`#header:<key>:prepend` / `#header:<key>:append` — rendered before / after the
|
|
@@ -27794,12 +27795,14 @@ The model's contract is what makes a column panel trivial:
|
|
|
27794
27795
|
|
|
27795
27796
|
- Keys listed first render first; declared columns the array omits follow, in
|
|
27796
27797
|
declaration order (a column added to `columns` later renders last).
|
|
27797
|
-
-
|
|
27798
|
-
|
|
27799
|
-
|
|
27798
|
+
- A `hidden` column (next section) keeps its slot without rendering, and keys
|
|
27799
|
+
that match no declared column render nothing but are **preserved in
|
|
27800
|
+
place** — a column that exists only for some users comes back exactly where
|
|
27801
|
+
it was.
|
|
27800
27802
|
- A user move relocates **exactly one key**; everything else, hidden keys
|
|
27801
27803
|
included, keeps its relative order. The first move on a partial (or empty)
|
|
27802
|
-
model emits the completed array —
|
|
27804
|
+
model emits the completed array — every declared key, hidden ones included
|
|
27805
|
+
— so persist that and the model is complete from then on.
|
|
27803
27806
|
- A drop that changes nothing emits nothing; unbound, the table keeps the
|
|
27804
27807
|
order as per-mount state like `sort`.
|
|
27805
27808
|
|
|
@@ -27810,8 +27813,9 @@ The model's contract is what makes a column panel trivial:
|
|
|
27810
27813
|
<div class="flex max-w-2xl flex-col gap-3">
|
|
27811
27814
|
<!-- ONE order, two writers: the panel's buttons and the table's own
|
|
27812
27815
|
header drag / keyboard handles both write `v-model:order`.
|
|
27813
|
-
|
|
27814
|
-
|
|
27816
|
+
Visibility is a flag ON the definition (`hidden`), so a hidden
|
|
27817
|
+
column stays declared, keeps its slot in the order, and comes back
|
|
27818
|
+
where it was. -->
|
|
27815
27819
|
<ul
|
|
27816
27820
|
aria-label="Columns"
|
|
27817
27821
|
class="flex flex-wrap gap-2 text-xs text-[color:var(--bb-text-muted)]"
|
|
@@ -27824,7 +27828,7 @@ The model's contract is what makes a column panel trivial:
|
|
|
27824
27828
|
<BbCheckbox
|
|
27825
27829
|
:label="column.label"
|
|
27826
27830
|
:model-value="!hidden.has(column.key)"
|
|
27827
|
-
@update:model-value="
|
|
27831
|
+
@update:model-value="setHidden(column.key, !$event)"
|
|
27828
27832
|
/>
|
|
27829
27833
|
<BbButton
|
|
27830
27834
|
:aria-label="`Move ${column.label} left`"
|
|
@@ -27850,15 +27854,30 @@ The model's contract is what makes a column panel trivial:
|
|
|
27850
27854
|
<BbTable
|
|
27851
27855
|
v-model:order="order"
|
|
27852
27856
|
caption="Invoices"
|
|
27853
|
-
:columns="
|
|
27857
|
+
:columns="columns"
|
|
27854
27858
|
compact
|
|
27855
27859
|
item-value="id"
|
|
27856
27860
|
:items="invoices"
|
|
27857
27861
|
reorderable
|
|
27858
|
-
|
|
27862
|
+
@hide:column="(key) => setHidden(key, true)"
|
|
27863
|
+
>
|
|
27864
|
+
<!-- A "hide" control beside every header: the slot's `hideColumn()` is
|
|
27865
|
+
one-way (a hidden column has no header), so the panel above
|
|
27866
|
+
is what brings a column back. -->
|
|
27867
|
+
<template #header:append="{ hideColumn, label }">
|
|
27868
|
+
<BbButton
|
|
27869
|
+
:aria-label="`Hide ${label}`"
|
|
27870
|
+
icon="lucide:eye-off"
|
|
27871
|
+
size="xs"
|
|
27872
|
+
variant="ghost"
|
|
27873
|
+
@click="hideColumn"
|
|
27874
|
+
/>
|
|
27875
|
+
</template>
|
|
27876
|
+
</BbTable>
|
|
27859
27877
|
</div>
|
|
27860
27878
|
<p class="text-xs text-[color:var(--bb-text-muted)]">
|
|
27861
|
-
Order model: <code>{{ JSON.stringify(order) }}</code>
|
|
27879
|
+
Order model: <code>{{ JSON.stringify(order) }}</code> · hidden:
|
|
27880
|
+
<code>{{ JSON.stringify([...hidden]) }}</code>
|
|
27862
27881
|
</p>
|
|
27863
27882
|
</div>
|
|
27864
27883
|
</template>
|
|
@@ -27880,8 +27899,8 @@ const euro = new Intl.NumberFormat('en-IE', {
|
|
|
27880
27899
|
currency: 'EUR',
|
|
27881
27900
|
});
|
|
27882
27901
|
|
|
27883
|
-
// The declaration: what a column IS. Never reordered.
|
|
27884
|
-
const
|
|
27902
|
+
// The declaration: what a column IS. Never reordered, never filtered.
|
|
27903
|
+
const definitions: Array<BbTableColumn<Invoice>> = [
|
|
27885
27904
|
{ key: 'number', label: 'Invoice', width: 110 },
|
|
27886
27905
|
{ key: 'client', label: 'Client' },
|
|
27887
27906
|
{ key: 'issued', label: 'Issued', width: 110 },
|
|
@@ -27925,33 +27944,41 @@ const invoices: Invoice[] = [
|
|
|
27925
27944
|
},
|
|
27926
27945
|
];
|
|
27927
27946
|
|
|
27928
|
-
// The state: render order (keys)
|
|
27929
|
-
//
|
|
27930
|
-
|
|
27947
|
+
// The state, both persistable as-is: render order (keys) and the hidden set.
|
|
27948
|
+
// A partial or empty order is fine — the first move writes back the
|
|
27949
|
+
// complete array, hidden keys in their slots, because every column stays
|
|
27950
|
+
// declared below.
|
|
27951
|
+
const order = ref<string[]>([]);
|
|
27931
27952
|
const hidden = ref(new Set<string>());
|
|
27932
27953
|
|
|
27933
|
-
//
|
|
27934
|
-
//
|
|
27935
|
-
const
|
|
27936
|
-
|
|
27954
|
+
// The definitions, with the persisted visibility mapped in. Same shape you
|
|
27955
|
+
// would use for persisted widths (`width`) — the definition is the truth.
|
|
27956
|
+
const columns = computed(() =>
|
|
27957
|
+
definitions.map((column) => ({
|
|
27958
|
+
...column,
|
|
27959
|
+
hidden: hidden.value.has(column.key),
|
|
27960
|
+
}))
|
|
27937
27961
|
);
|
|
27938
27962
|
|
|
27939
|
-
// The panel lists every declared column in the order the model has them
|
|
27940
|
-
|
|
27941
|
-
|
|
27942
|
-
|
|
27943
|
-
|
|
27944
|
-
|
|
27963
|
+
// The panel lists every declared column in the order the model has them
|
|
27964
|
+
// (omitted keys follow in declaration order, exactly as the table renders).
|
|
27965
|
+
const panelColumns = computed(() => {
|
|
27966
|
+
const rank = (key: string) => {
|
|
27967
|
+
const index = order.value.indexOf(key);
|
|
27968
|
+
return index < 0 ? order.value.length : index;
|
|
27969
|
+
};
|
|
27970
|
+
return [...definitions].sort((a, b) => rank(a.key) - rank(b.key));
|
|
27971
|
+
});
|
|
27945
27972
|
|
|
27946
|
-
const
|
|
27973
|
+
const setHidden = (key: string, value: boolean) => {
|
|
27947
27974
|
const next = new Set(hidden.value);
|
|
27948
|
-
if (
|
|
27949
|
-
else next.
|
|
27975
|
+
if (value) next.add(key);
|
|
27976
|
+
else next.delete(key);
|
|
27950
27977
|
hidden.value = next;
|
|
27951
27978
|
};
|
|
27952
27979
|
|
|
27953
27980
|
const move = (key: string, delta: 1 | -1) => {
|
|
27954
|
-
const next =
|
|
27981
|
+
const next = panelColumns.value.map((column) => column.key);
|
|
27955
27982
|
const from = next.indexOf(key);
|
|
27956
27983
|
const to = from + delta;
|
|
27957
27984
|
if (from < 0 || to < 0 || to >= next.length) return;
|
|
@@ -27962,22 +27989,50 @@ const move = (key: string, delta: 1 | -1) => {
|
|
|
27962
27989
|
</script>
|
|
27963
27990
|
```
|
|
27964
27991
|
|
|
27965
|
-
|
|
27966
|
-
|
|
27967
|
-
|
|
27968
|
-
|
|
27969
|
-
|
|
27970
|
-
|
|
27971
|
-
|
|
27972
|
-
|
|
27973
|
-
|
|
27974
|
-
|
|
27975
|
-
|
|
27976
|
-
|
|
27977
|
-
|
|
27978
|
-
|
|
27979
|
-
|
|
27980
|
-
|
|
27992
|
+
### Column visibility
|
|
27993
|
+
|
|
27994
|
+
`hidden: true` on a column definition hides it: no header, no cells, no grid
|
|
27995
|
+
track. The column stays **declared**, and that is the whole point — the order
|
|
27996
|
+
model is completed against every declared key, so a hidden column keeps its
|
|
27997
|
+
slot through any number of header drags, and it returns to that slot the
|
|
27998
|
+
moment the flag clears. Two rules follow:
|
|
27999
|
+
|
|
28000
|
+
- **Hidden means "exists, not shown".** A column panel, a persisted
|
|
28001
|
+
preference, a narrow-screen breakpoint all write `hidden` into the
|
|
28002
|
+
definition (a `computed` over your persisted set — the example above does
|
|
28003
|
+
exactly that). Filter `columns` only for a column that does **not exist**
|
|
28004
|
+
for this user (a custom field they don't have); its key, if a saved order
|
|
28005
|
+
still lists it, is preserved in place like any unknown key.
|
|
28006
|
+
- **There is no visibility model, on purpose** — the `width` shape, not the
|
|
28007
|
+
`sort` one. The definition is the single declared truth. Header slots
|
|
28008
|
+
(`#header:<key>`, `#header:<key>:append`, the table-wide `#header:append`)
|
|
28009
|
+
receive a `hideColumn()` callback for a "Hide column" control of your own; calling
|
|
28010
|
+
it hides the column for the mount and fires `@hide:column="(key) => …"`
|
|
28011
|
+
once. Persist by writing `hidden: true` back into the definition — the
|
|
28012
|
+
override matches it and stays; write `hidden: false` (the panel showing the
|
|
28013
|
+
column again) and the definition wins. Unbound, the hide lives for the
|
|
28014
|
+
mount, like an unbound resize. A hidden column has no header, so `hideColumn()`
|
|
28015
|
+
is one-way by nature: if you offer it, own the persistence and give the
|
|
28016
|
+
user a panel that shows columns again.
|
|
28017
|
+
|
|
28018
|
+
A nested table that shares its parent's keys shares its `hidden` flags too,
|
|
28019
|
+
the same way it shares `order` — a hidden parent column has no track for a
|
|
28020
|
+
child cell to land on.
|
|
28021
|
+
|
|
28022
|
+
**Pins travel with the column.** `fixed` is a field on the column
|
|
28023
|
+
definition (see "Pinned columns"), so a reorder moves the pin with the cell:
|
|
28024
|
+
drag the identity column to slot 3 and it is still sticky, now at slot 3.
|
|
28025
|
+
The offset is still positional — the pinned columns before it on the same
|
|
28026
|
+
side — so a pinned column dragged away from the edge sticks at `left: 0` and
|
|
28027
|
+
slides over the columns before it. Lock the pinned columns in place by
|
|
28028
|
+
normalizing the model in your `@update:order` handler when that matters.
|
|
28029
|
+
|
|
28030
|
+
**Nested tables.** A parent that uses `order` or `reorderable` is inherited
|
|
28031
|
+
by **position**: its columns can move, so the child's `snap` targets and
|
|
28032
|
+
same-key pairing are ignored there (dev builds warn) and the child aligns to
|
|
28033
|
+
the parent's rails slot by slot. Give both tables the same `v-model:order`
|
|
28034
|
+
when they share keys and they stay paired. Never reorder (or share the order
|
|
28035
|
+
with) a snapped child itself — dev builds warn.
|
|
27981
28036
|
|
|
27982
28037
|
Apply the model synchronously in your handler and persist afterwards: an
|
|
27983
28038
|
`await` before the write moves the cell in a later flush, after the table
|
|
@@ -28349,7 +28404,7 @@ fields.
|
|
|
28349
28404
|
Track open rows with `v-model:expanded-items` (an array of row values — set
|
|
28350
28405
|
`item-value` so expansion is stable across refetches) and render their detail
|
|
28351
28406
|
through the `#expand` slot, a full-width row below the main one. Trigger it
|
|
28352
|
-
from the `#actions` slot (
|
|
28407
|
+
from the `#actions` slot (the slot creates the actions column; label it with
|
|
28353
28408
|
`actions-text`): the scope hands you `toggleExpanded` — a **callback** — plus
|
|
28354
28409
|
the read-only `expanded` flag. Drive open/close through the callback; the
|
|
28355
28410
|
`expanded` prop is one-way state, not something to mutate.
|
|
@@ -28366,7 +28421,6 @@ the read-only `expanded` flag. Drive open/close through the callback; the
|
|
|
28366
28421
|
>
|
|
28367
28422
|
<BbTable
|
|
28368
28423
|
v-model:expanded-items="expanded"
|
|
28369
|
-
actions
|
|
28370
28424
|
actions-text="Details"
|
|
28371
28425
|
caption="Invoices"
|
|
28372
28426
|
:columns="columns"
|
|
@@ -28590,11 +28644,19 @@ above it. The mechanics:
|
|
|
28590
28644
|
- `inherit-column-widths` — `true` inherits from the nearest ancestor table;
|
|
28591
28645
|
a string targets a specific ancestor's `id` (useful when an intermediate
|
|
28592
28646
|
table has a different column count).
|
|
28593
|
-
- By default child
|
|
28594
|
-
column
|
|
28595
|
-
|
|
28596
|
-
|
|
28597
|
-
|
|
28647
|
+
- By default a child column pairs with the parent column of the **same key**,
|
|
28648
|
+
and a column the parent lacks flows into the next parent track no other
|
|
28649
|
+
column claimed. A column's `snap` names the parent column instead:
|
|
28650
|
+
`snap: 'client'` takes that track, `['client', 'amount']` spans from the
|
|
28651
|
+
start of one through the end of the other, and the parent's structural
|
|
28652
|
+
columns are targets by name (`'select'`, `'actions'` — `['name',
|
|
28653
|
+
'actions']` runs a column across the parent's actions cell too). A
|
|
28654
|
+
trailing `.digits` on a key in a pair is a fraction of that track
|
|
28655
|
+
(`['a', 'b.5']` = all of `a` plus half of `b`). Snaps and keys resolve
|
|
28656
|
+
against the parent's **rendered** columns: a target the parent hides (or
|
|
28657
|
+
never had) makes the column flow like an unsnapped one; a snap that lands
|
|
28658
|
+
before the previous column's cannot tile and flows too (dev builds warn);
|
|
28659
|
+
under a parent that reorders, snaps are ignored (see Column order).
|
|
28598
28660
|
- A child with **more** columns than the parent content-sizes the extras and
|
|
28599
28661
|
overflows into the parent's scroll (see below); with **fewer**, the leading
|
|
28600
28662
|
columns stay 1:1, the actions column inherits the parent's actions width,
|
|
@@ -28602,15 +28664,16 @@ above it. The mechanics:
|
|
|
28602
28664
|
both tables end flush (a right-aligned total lands under the parent's last
|
|
28603
28665
|
column). Give that last column a `width` or an explicit `[start, end]`
|
|
28604
28666
|
snap only if you want it to stop short — the leftover then joins the
|
|
28605
|
-
actions region instead.
|
|
28667
|
+
actions region instead. A column with nothing free left to flow into is an
|
|
28668
|
+
overflow column too.
|
|
28606
28669
|
- **An inheriting child does not scroll on its own — the parent's scrollport
|
|
28607
28670
|
is the only one.** That is what keeps the two grids locked together: a child
|
|
28608
28671
|
with its own scroll position would fall out of alignment the moment either
|
|
28609
28672
|
one moved, which is the whole thing `inherit-column-widths` exists to
|
|
28610
28673
|
prevent. One scrollbar moves both.
|
|
28611
28674
|
- **The parent's `selectable`/`actions` columns are handled for you** — the
|
|
28612
|
-
child's content columns
|
|
28613
|
-
needed for that), and the parent's select/actions _regions_ are reserved on
|
|
28675
|
+
child's content columns pair with the parent's content columns by key (no
|
|
28676
|
+
`snap` needed for that), and the parent's select/actions _regions_ are reserved on
|
|
28614
28677
|
each side: a child with its own select or actions column widens that cell
|
|
28615
28678
|
to the parent's (two equal cells, controls at the row's end, so the ⌃ sits
|
|
28616
28679
|
under the parent's); a child without one folds the region into its first/
|
|
@@ -28642,7 +28705,6 @@ above it. The mechanics:
|
|
|
28642
28705
|
>
|
|
28643
28706
|
<BbTable
|
|
28644
28707
|
v-model:expanded-items="expanded"
|
|
28645
|
-
actions
|
|
28646
28708
|
actions-text="Line items"
|
|
28647
28709
|
caption="Invoices"
|
|
28648
28710
|
:columns="columns"
|
|
@@ -28740,27 +28802,29 @@ const expanded = ref<string[]>([]);
|
|
|
28740
28802
|
|
|
28741
28803
|
#### Affixed actions on both tables
|
|
28742
28804
|
|
|
28743
|
-
A nested table can
|
|
28744
|
-
their own row actions — and both action columns pin to the
|
|
28805
|
+
A nested table can pin its own actions column with `fixed-actions` — child
|
|
28806
|
+
rows usually need their own row actions — and both action columns pin to the
|
|
28807
|
+
same visible edge:
|
|
28745
28808
|
|
|
28746
28809
|
```vue
|
|
28747
28810
|
<BbTable
|
|
28748
28811
|
id="programmes"
|
|
28749
|
-
actions
|
|
28750
28812
|
:columns="columns"
|
|
28751
|
-
|
|
28813
|
+
fixed-actions
|
|
28752
28814
|
:items="rows"
|
|
28753
28815
|
item-value="id"
|
|
28754
28816
|
>
|
|
28817
|
+
<template #actions="{ item }">…</template>
|
|
28755
28818
|
<template #expand="{ item }">
|
|
28756
28819
|
<BbTable
|
|
28757
|
-
actions
|
|
28758
28820
|
:columns="childColumns"
|
|
28759
|
-
|
|
28821
|
+
fixed-actions
|
|
28760
28822
|
inherit-column-widths="programmes"
|
|
28761
28823
|
:items="item.children"
|
|
28762
28824
|
item-value="id"
|
|
28763
|
-
|
|
28825
|
+
>
|
|
28826
|
+
<template #actions="{ item }">…</template>
|
|
28827
|
+
</BbTable>
|
|
28764
28828
|
</template>
|
|
28765
28829
|
</BbTable>
|
|
28766
28830
|
```
|
|
@@ -28769,9 +28833,10 @@ This works because the child shares the parent's scrollport. `position: sticky`
|
|
|
28769
28833
|
resolves against the nearest scrolling ancestor, and the child's own box is as
|
|
28770
28834
|
wide as the parent's **content** — so if it opened a scrollport of its own, the
|
|
28771
28835
|
child's actions would affix to an edge sitting out in the overflow, hundreds of
|
|
28772
|
-
pixels past what anyone can see, while the parent's pinned correctly.
|
|
28773
|
-
child's actions column
|
|
28774
|
-
above) so the two columns line up rather than merely both
|
|
28836
|
+
pixels past what anyone can see, while the parent's pinned correctly. The
|
|
28837
|
+
child's actions column inherits the parent's actions region by itself (the
|
|
28838
|
+
structural rule above), so the two columns line up rather than merely both
|
|
28839
|
+
being pinned.
|
|
28775
28840
|
|
|
28776
28841
|
A pinned cell is opaque — it paints the table's `--bg` surface because it
|
|
28777
28842
|
slides over its siblings — so a nested table sitting on a tinted expand row
|
|
@@ -29059,7 +29124,6 @@ open-in-new-tab for free.
|
|
|
29059
29124
|
class="max-w-2xl overflow-hidden rounded-[var(--bb-radius)] border border-[color:var(--bb-border)]"
|
|
29060
29125
|
>
|
|
29061
29126
|
<BbTable
|
|
29062
|
-
actions
|
|
29063
29127
|
actions-text="Actions"
|
|
29064
29128
|
caption="Invoices"
|
|
29065
29129
|
:columns="columns"
|
|
@@ -29395,10 +29459,8 @@ canonical palette lives in the
|
|
|
29395
29459
|
|
|
29396
29460
|
`compact` tightens row padding. `fixed-headers` makes the header stick to the
|
|
29397
29461
|
top of the nearest scroll container. `fixed` switches to an equal-width fixed
|
|
29398
|
-
layout.
|
|
29399
|
-
|
|
29400
|
-
objects; indices count rendered columns (a selection column is index 0), and
|
|
29401
|
-
an out-of-range index logs a console error and is skipped. When content can't
|
|
29462
|
+
layout. Pinned columns (next section) stick while the rest scroll
|
|
29463
|
+
horizontally. When content can't
|
|
29402
29464
|
fit, the table keeps every column at its measured minimum — its header label
|
|
29403
29465
|
included — and overflows its container instead of clipping; this is by
|
|
29404
29466
|
design, not a bug to work around. Note that truncating cells yourself
|
|
@@ -29449,13 +29511,51 @@ your wrapper actually sits on before sprinkling `min-width: 0` everywhere.)
|
|
|
29449
29511
|
</div>
|
|
29450
29512
|
```
|
|
29451
29513
|
|
|
29514
|
+
### Pinned columns
|
|
29515
|
+
|
|
29516
|
+
`fixed: 'left' | 'right'` on a column definition makes its cells
|
|
29517
|
+
`position: sticky` on that side — in place, at the column's own render
|
|
29518
|
+
position, like a spreadsheet's freeze panes. Pin a contiguous run from the
|
|
29519
|
+
edge and the offsets accumulate (the second left-pinned column sticks right
|
|
29520
|
+
after the first). The two structural columns have no definition to carry the
|
|
29521
|
+
field, so they pin through the table: `fixed-select` for the selection
|
|
29522
|
+
column and `fixed-actions` for the actions column (each has one sensible
|
|
29523
|
+
side, so both are booleans).
|
|
29524
|
+
|
|
29525
|
+
```vue
|
|
29526
|
+
<BbTable :columns="columns" fixed-actions fixed-select :items="rows" selectable>
|
|
29527
|
+
<template #actions="{ item }">…</template>
|
|
29528
|
+
</BbTable>
|
|
29529
|
+
```
|
|
29530
|
+
|
|
29531
|
+
```ts
|
|
29532
|
+
const columns = [
|
|
29533
|
+
{ key: 'name', label: 'Name', fixed: 'left' },
|
|
29534
|
+
{ key: 'region', label: 'Region' },
|
|
29535
|
+
{ key: 'amount', label: 'Amount', align: 'right' },
|
|
29536
|
+
];
|
|
29537
|
+
```
|
|
29538
|
+
|
|
29539
|
+
Three rules:
|
|
29540
|
+
|
|
29541
|
+
- **The pin is the column's.** Under `order` / `reorderable` it travels with
|
|
29542
|
+
the cell, and a `hidden` pinned column pins nothing. The offset is still
|
|
29543
|
+
positional, so a lone left-pinned column dragged to the middle sticks at
|
|
29544
|
+
`left: 0` and slides over the columns before it — by design; lock the
|
|
29545
|
+
pinned columns in place by normalizing `@update:order` if you need to.
|
|
29546
|
+
- **Pinned cells are opaque** — they paint the table's `--bg` (see Styling
|
|
29547
|
+
hooks), so a table on a tinted surface needs `--bg` set once.
|
|
29548
|
+
- **Nested tables pin against the ancestor scrollport.** A child that
|
|
29549
|
+
inherits the parent's tracks has no scrollport of its own, so both tables'
|
|
29550
|
+
pins land on the same visible edge (see Nested tables).
|
|
29551
|
+
|
|
29452
29552
|
### Virtual rows
|
|
29453
29553
|
|
|
29454
29554
|
`virtual` windows the body: only the rows in the vertical scrollport (plus a
|
|
29455
29555
|
few on each side) are mounted, and two spacer rows hold the scrollport at the
|
|
29456
29556
|
full list height, so 5,000 or 50,000 rows scroll at the cost of a few dozen.
|
|
29457
29557
|
Everything else is the same table — the rows stay in flow in the grid, so the
|
|
29458
|
-
stuck header,
|
|
29558
|
+
stuck header, pinned columns, nested tables, selection, highlight and the
|
|
29459
29559
|
keyboard grammar work untouched. One prop, no knobs.
|
|
29460
29560
|
|
|
29461
29561
|
- **Give it a scroller.** Bound the table's height (`max-height` / `height`
|
|
@@ -29513,7 +29613,6 @@ keyboard grammar work untouched. One prop, no knobs.
|
|
|
29513
29613
|
class="max-h-80"
|
|
29514
29614
|
:columns="columns"
|
|
29515
29615
|
compact
|
|
29516
|
-
:fixed-columns="[0]"
|
|
29517
29616
|
item-value="id"
|
|
29518
29617
|
:items="rows"
|
|
29519
29618
|
virtual
|
|
@@ -29533,7 +29632,7 @@ type Entry = {
|
|
|
29533
29632
|
};
|
|
29534
29633
|
|
|
29535
29634
|
const columns: Array<BbTableColumn<Entry>> = [
|
|
29536
|
-
{ key: 'number', label: 'Invoice' },
|
|
29635
|
+
{ key: 'number', label: 'Invoice', fixed: 'left' },
|
|
29537
29636
|
{ key: 'client', label: 'Client' },
|
|
29538
29637
|
{ key: 'issued', label: 'Issued' },
|
|
29539
29638
|
{ key: 'amount', label: 'Amount', align: 'right' },
|
|
@@ -29558,14 +29657,14 @@ leave the screen. Collapse instead of scroll:
|
|
|
29558
29657
|
|
|
29559
29658
|
- **Rank the columns.** Identity + status + the one number that matters stay;
|
|
29560
29659
|
everything else is secondary.
|
|
29561
|
-
- **
|
|
29562
|
-
over `useMobile()` (or your own `matchMedia`) that
|
|
29563
|
-
|
|
29564
|
-
`thClass`/`tdClass` + `display: none`:
|
|
29565
|
-
leaves its track in place and every
|
|
29566
|
-
|
|
29567
|
-
|
|
29568
|
-
order array.
|
|
29660
|
+
- **Flag the secondary ones `hidden` at the breakpoint** — a `computed`
|
|
29661
|
+
over `useMobile()` (or your own `matchMedia`) that maps the definitions
|
|
29662
|
+
with `hidden: isMobile && secondary.has(key)`. A hidden column has no grid
|
|
29663
|
+
track. Do **not** hide cells with `thClass`/`tdClass` + `display: none`:
|
|
29664
|
+
the table is a grid, a hidden cell leaves its track in place and every
|
|
29665
|
+
following cell shifts one track over. The hidden column stays declared, so
|
|
29666
|
+
it keeps its slot in `order` and returns where it was when the screen
|
|
29667
|
+
widens — never filter the order array.
|
|
29569
29668
|
- **Stack what survives into the primary cell.** The identity slot renders the
|
|
29570
29669
|
name plus the hidden facts under it, at `--bb-text-muted`, so nothing is
|
|
29571
29670
|
actually lost.
|
|
@@ -29579,7 +29678,7 @@ records list.
|
|
|
29579
29678
|
**The table's surface is `--bg`** (default `var(--bb-panel)`), a local on
|
|
29580
29679
|
`.bb-table`. Cells are transparent at rest so the row can tint them, but
|
|
29581
29680
|
anything that slides over scrolled content — the stuck header band with
|
|
29582
|
-
`fixed-headers`, and `fixed
|
|
29681
|
+
`fixed-headers`, and pinned (`fixed`) cells — is opaque and paints `--bg` (a
|
|
29583
29682
|
pinned cell also picks up its row's hover/highlight tint, so it never reads
|
|
29584
29683
|
as a hole). When a table sits on a surface that is not the panel colour, set
|
|
29585
29684
|
the one knob and everything pinned follows:
|
|
@@ -29726,8 +29825,9 @@ reader.
|
|
|
29726
29825
|
- `BbPagination` — shared page ref, or zero-wiring via `id` + `table-id`.
|
|
29727
29826
|
- `useBbTableContext` (`./composables/useBbTableContext.md`) — bulk-action
|
|
29728
29827
|
toolbars, detail panels, "reset sort" buttons living outside the table.
|
|
29729
|
-
(Column order
|
|
29730
|
-
so it lives where `
|
|
29828
|
+
(Column order and visibility are not mirrored there: a column panel writes
|
|
29829
|
+
`v-model:order` and the `hidden` flags, so it lives where `columns` is
|
|
29830
|
+
built.)
|
|
29731
29831
|
- `BbButton` — per-row links (`href`/`to`) in cells or `#actions`;
|
|
29732
29832
|
`BbDropdown` for an overflow menu of row actions.
|
|
29733
29833
|
- `BbBadge` / `BbAvatar` — status and identity cells via slots.
|
|
@@ -29753,10 +29853,17 @@ reader.
|
|
|
29753
29853
|
`(columns, item)` with the mapped cells (in **render** order — look them up
|
|
29754
29854
|
by `key`, never by position) and the raw record, and whatever it returns
|
|
29755
29855
|
becomes the checkbox's label.
|
|
29756
|
-
- `fixed
|
|
29757
|
-
|
|
29856
|
+
- A pin (`column.fixed`) travels with its column under `order`, but its
|
|
29857
|
+
offset is positional: dragged away from the edge, a pinned column sticks
|
|
29858
|
+
at `left: 0` and slides over the columns before it (see Pinned columns).
|
|
29859
|
+
- The actions column has no prop: the `#actions` slot creates it. A
|
|
29860
|
+
conditional slot (`<template v-if="…" #actions>`) adds and removes the
|
|
29861
|
+
column live.
|
|
29758
29862
|
- A column panel that holds a partial `order` receives the completed
|
|
29759
|
-
array on the user's first move — its persisted list grows to every
|
|
29863
|
+
array on the user's first move — its persisted list grows to every declared
|
|
29864
|
+
key, `hidden` ones included. Hide with the flag, not by filtering
|
|
29865
|
+
`columns`: a filtered column is undeclared, so a partial model completes
|
|
29866
|
+
without it and the key is gone from the persisted order.
|
|
29760
29867
|
- Enabling select-all does not re-emit an empty `modelValue` (see the
|
|
29761
29868
|
select-all section) — in all-mode, read `select-all` +
|
|
29762
29869
|
`unselected-items`, not `modelValue`.
|
|
@@ -29834,7 +29941,6 @@ reader.
|
|
|
29834
29941
|
| Prop | Type | Default | Required | Description |
|
|
29835
29942
|
| --- | --- | --- | --- | --- |
|
|
29836
29943
|
| `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`… |
|
|
29837
|
-
| `actions` | `boolean \| undefined` | `false` | | Displays the actions column. |
|
|
29838
29944
|
| `actionsText` | `string \| undefined` | | | Label used in the header of the actions column. |
|
|
29839
29945
|
| `align` | `"left" \| "center" \| "right" \| undefined` | `"left"` | | Text alignment of the columns. |
|
|
29840
29946
|
| `caption` | `string \| undefined` | | | Caption that describes the content of the table. Used for accessibility purposes. |
|
|
@@ -29848,8 +29954,9 @@ reader.
|
|
|
29848
29954
|
| `enforceCoherence` | `boolean \| undefined` | `false` | | 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… |
|
|
29849
29955
|
| `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`/… |
|
|
29850
29956
|
| `fixed` | `boolean \| undefined` | `false` | | 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. |
|
|
29851
|
-
| `
|
|
29957
|
+
| `fixedActions` | `boolean \| undefined` | `false` | | Pins the actions column (the one the `#actions` slot creates) to the right edge, `position: sticky`, in place. Data columns pin through `column.fixed`; this is the same feature for the structural column that has no definition to carry it. N… |
|
|
29852
29958
|
| `fixedHeaders` | `boolean \| undefined` | `false` | | Boolean that sets the headers as sticky to the top of the table. |
|
|
29959
|
+
| `fixedSelect` | `boolean \| undefined` | `false` | | Pins the selection column to the left edge, `position: sticky`, in place. Data columns pin through `column.fixed`; this is the same feature for the structural column that has no definition to carry it. No effect unless the table is `selecta… |
|
|
29853
29960
|
| `headerRowClass` | `Classes \| undefined` | | | Defines the classes to be passed to the header row. |
|
|
29854
29961
|
| `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. **Opt-in, and `undefined` is the opt-out.** Leave it unbo… |
|
|
29855
29962
|
| `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. |
|
|
@@ -29890,6 +29997,7 @@ reader.
|
|
|
29890
29997
|
- `click:row` — `(e: "click:row", event: MouseEvent, item: any): void`
|
|
29891
29998
|
- `contextmenu:row` — `(e: "contextmenu:row", event: MouseEvent, item: any): void`
|
|
29892
29999
|
- `dblclick:row` — `(e: "dblclick:row", event: MouseEvent, item: any): void`
|
|
30000
|
+
- `hide:column` — `(e: "hide:column", key: string): void` — A column was hidden from its header (a `#header:<key>` / `#header:<key>:append` control calling the slot's `hideColumn()`). Fired once; the table keeps the column hidden for the mount, or until the column's `hidden` flag changes — write `hi…
|
|
29893
30001
|
- `item:selected` — `(e: "item:selected", value: any): void`
|
|
29894
30002
|
- `item:unselected` — `(e: "item:unselected", value: any): void`
|
|
29895
30003
|
- `resize:column` — `(e: "resize:column", key: string, width: number \| null): void` — A column was resized by the user (`resizable`): the new width in px, or `null` when the handle was double-clicked to reset the column to its declared width.
|
|
@@ -29903,7 +30011,7 @@ reader.
|
|
|
29903
30011
|
|
|
29904
30012
|
## Slots
|
|
29905
30013
|
|
|
29906
|
-
- `actions` — scope: `{ expanded?: boolean \| undefined; expandProps?: ExpandControllerProps \| undefined; toggleExpanded?: (() => void) \| undefined; highlighted?: boolean \| undefi…` — Content rendered in the actions cell for each row.
|
|
30014
|
+
- `actions` — scope: `{ expanded?: boolean \| undefined; expandProps?: ExpandControllerProps \| undefined; toggleExpanded?: (() => void) \| undefined; highlighted?: boolean \| undefi…` — Content rendered in the actions cell for each row. Providing this slot is what CREATES the actions column (there is no prop): the header cell (labelled by `actions-text`, replaceable through `#header:actions`) and one cell per row appear wi…
|
|
29907
30015
|
- `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.
|
|
29908
30016
|
- `header:actions` — scope: `{ text: string; }` — Replaces the default actions header cell content.
|
|
29909
30017
|
- `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…
|
|
@@ -39250,24 +39358,24 @@ a composable you want is not in this corpus's `composables/` folder — it is no
|
|
|
39250
39358
|
here.** Check this list before inventing a name; if the need is genuinely absent,
|
|
39251
39359
|
compose it or write it yourself.
|
|
39252
39360
|
|
|
39253
|
-
| Assumed component or composable | Reality
|
|
39254
|
-
| -------------------------------------------------------------- |
|
|
39255
|
-
| `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
|
|
39256
|
-
| `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.
|
|
39257
|
-
| `BbModal` | It is [BbDialog](../BbDialog.md).
|
|
39258
|
-
| `BbDrawer` / `BbSheet` | It is [BbOffCanvas](../BbOffCanvas.md).
|
|
39259
|
-
| `BbCombobox` / `BbAutocomplete` | It is [BbSelect](../BbSelect.md) / [BbSelectPopover](../BbSelectPopover.md) — search is built in, see `disable-writing`.
|
|
39260
|
-
| `BbToggle` / `BbToggleGroup` | It is [BbButton](../BbButton.md) with `v-model` (+ `true-value` / `false-value`), which owns `aria-pressed` and the active class.
|
|
39261
|
-
| `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.
|
|
39262
|
-
| `BbTab` (singular) | The consumer API is [BbTabs](../BbTabs.md) / `BbTabsRoot`. `BbTab` appears only as the **v2 "before" side** of the migration diffs.
|
|
39263
|
-
| `BbCard` | Does not exist — a card is a `<div>` with tokens. See [design-language](./design-language.md).
|
|
39264
|
-
| `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.
|
|
39265
|
-
| `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.
|
|
39266
|
-
| `BbStepper` / `BbWizard` | Does not exist as a component; the wizard-form recipe composes one.
|
|
39267
|
-
| `BbSkeleton` (standalone) | Only `BbTable` ships skeletons, via the column `skeleton` field.
|
|
39268
|
-
| `BbCommand` / command palette | Does not exist. Compose `BbDialog` + `BbSelectPopover`.
|
|
39269
|
-
| `BbCalendar` (month / scheduling view) | Does not exist. [BbDatePicker](../BbDatePicker.md) is a picker, not a calendar surface.
|
|
39270
|
-
| `BbChart` / `BbGraph`, `BbCarousel`, `BbTimeline`, `BbDivider` | Do not exist. No charting, carousel or timeline primitive ships here.
|
|
39361
|
+
| Assumed component or composable | Reality |
|
|
39362
|
+
| -------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
39363
|
+
| `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`. |
|
|
39364
|
+
| `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. |
|
|
39365
|
+
| `BbModal` | It is [BbDialog](../BbDialog.md). |
|
|
39366
|
+
| `BbDrawer` / `BbSheet` | It is [BbOffCanvas](../BbOffCanvas.md). |
|
|
39367
|
+
| `BbCombobox` / `BbAutocomplete` | It is [BbSelect](../BbSelect.md) / [BbSelectPopover](../BbSelectPopover.md) — search is built in, see `disable-writing`. |
|
|
39368
|
+
| `BbToggle` / `BbToggleGroup` | It is [BbButton](../BbButton.md) with `v-model` (+ `true-value` / `false-value`), which owns `aria-pressed` and the active class. |
|
|
39369
|
+
| `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. |
|
|
39370
|
+
| `BbTab` (singular) | The consumer API is [BbTabs](../BbTabs.md) / `BbTabsRoot`. `BbTab` appears only as the **v2 "before" side** of the migration diffs. |
|
|
39371
|
+
| `BbCard` | Does not exist — a card is a `<div>` with tokens. See [design-language](./design-language.md). |
|
|
39372
|
+
| `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. |
|
|
39373
|
+
| `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. |
|
|
39374
|
+
| `BbStepper` / `BbWizard` | Does not exist as a component; the wizard-form recipe composes one. |
|
|
39375
|
+
| `BbSkeleton` (standalone) | Only `BbTable` ships skeletons, via the column `skeleton` field. |
|
|
39376
|
+
| `BbCommand` / command palette | Does not exist. Compose `BbDialog` + `BbSelectPopover`. |
|
|
39377
|
+
| `BbCalendar` (month / scheduling view) | Does not exist. [BbDatePicker](../BbDatePicker.md) is a picker, not a calendar surface. |
|
|
39378
|
+
| `BbChart` / `BbGraph`, `BbCarousel`, `BbTimeline`, `BbDivider` | Do not exist. No charting, carousel or timeline primitive ships here. |
|
|
39271
39379
|
|
|
39272
39380
|
App chrome — an app shell, sidebar, page header, selection dock — is
|
|
39273
39381
|
deliberately **not** a component: it is yours to own. The per-platform
|
|
@@ -40885,9 +40993,13 @@ The `bitbossUi` Vite plugin (`iconDir` option) — or the Nuxt module (config ke
|
|
|
40885
40993
|
`lucide:<name>` available; removing it makes them all errors. Nothing to
|
|
40886
40994
|
configure.
|
|
40887
40995
|
- **Dev**: all icons of installed sets are registered. Referencing an
|
|
40888
|
-
uninstalled prefix or a non-existent name fails loudly
|
|
40889
|
-
|
|
40890
|
-
|
|
40996
|
+
uninstalled prefix or a non-existent name fails loudly in the Vite error
|
|
40997
|
+
overlay with an actionable message. A typo inside an installed set reads
|
|
40998
|
+
"does not exist in the lucide icon set — did you mean `lucide:…`?"; a set
|
|
40999
|
+
that is not installed reads "no installed icon set has the prefix `mdi`
|
|
41000
|
+
(installed sets: lucide) … run: `npm install -D @iconify-json/mdi`". Read
|
|
41001
|
+
the message: a typo wants a different name, a missing set wants an install,
|
|
41002
|
+
never a guess.
|
|
40891
41003
|
- **Build**: source files (`.vue`/`.ts`/`.js`/`.tsx`/`.jsx`; tests and stories
|
|
40892
41004
|
excluded) are scanned for static `provider:name` literals; each referenced
|
|
40893
41005
|
icon is emitted as its own lazy chunk. This is why rule 4 exists — and why an
|
|
@@ -43102,19 +43214,16 @@ goes stable, so never reach for it here.
|
|
|
43102
43214
|
|
|
43103
43215
|
Peer dependency: `vue ^3.5.12` — the only required one. `@inertiajs/vue3` is an **optional** peer, needed only in Inertia apps.
|
|
43104
43216
|
|
|
43105
|
-
`@iconify/collections
|
|
43106
|
-
|
|
43107
|
-
|
|
43108
|
-
|
|
43109
|
-
|
|
43110
|
-
|
|
43111
|
-
|
|
43112
|
-
|
|
43113
|
-
|
|
43114
|
-
|
|
43115
|
-
mean …?" suggestion for a mistyped icon name) never fire — a wrong provider
|
|
43116
|
-
icon then surfaces only as `BbIcon`'s generic runtime `Icon "…" does not exist.`
|
|
43117
|
-
Nothing else changes: icons that resolve still render, in dev and in production.
|
|
43217
|
+
You do **not** need `@iconify/collections`. It is declared as an optional peer
|
|
43218
|
+
for one reason only: when it happens to be installed, the dev-overlay message
|
|
43219
|
+
for an unknown icon prefix can say for certain whether that prefix is a real
|
|
43220
|
+
Iconify set ("requires `@iconify-json/mdi`, run …") or not ("neither an
|
|
43221
|
+
installed set nor a known Iconify prefix"). Without it the same overlay fires
|
|
43222
|
+
with a hedged wording ("no installed icon set has the prefix `mdi`; if it is an
|
|
43223
|
+
Iconify set, run …"). A mistyped name inside a set you **have** installed
|
|
43224
|
+
(`lucide:eye-misspelled`) is diagnosed from the set's own data in both cases,
|
|
43225
|
+
with a "did you mean …?" suggestion. Nothing else changes: icons that resolve
|
|
43226
|
+
still render, in dev and in production.
|
|
43118
43227
|
|
|
43119
43228
|
**Known-good toolchain:** TypeScript **5.x or 6.x** if your build gate runs
|
|
43120
43229
|
`vue-tsc`. Both type-check cleanly against the shipped `.d.ts`; the library
|
|
@@ -43379,7 +43488,7 @@ utilities. (Same trap as the scoped-`<style>` case above, one level up.)
|
|
|
43379
43488
|
## 6) Icons
|
|
43380
43489
|
|
|
43381
43490
|
- `iconDir` (required) is scanned recursively for `.svg` files; each file becomes `local:<basename>`.
|
|
43382
|
-
- Provider icons (`lucide:pencil`, `mdi:home`, …) require the matching `@iconify-json/<prefix>` package installed in the consumer app.
|
|
43491
|
+
- 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.
|
|
43383
43492
|
- Production builds bundle **only statically referenced** provider icons — write icon names as literal strings (`icon="lucide:trash-2"`), never assemble them dynamically.
|
|
43384
43493
|
- 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.
|
|
43385
43494
|
|
|
@@ -45658,20 +45767,24 @@ have made the spinner invisible and removed the page's only busy signal.
|
|
|
45658
45767
|
|
|
45659
45768
|
## Changes
|
|
45660
45769
|
|
|
45661
|
-
| v2
|
|
45662
|
-
|
|
|
45663
|
-
| `allowSelectAll?: boolean` (default `true`)
|
|
45664
|
-
| refetch with rows → skeleton
|
|
45665
|
-
| rows interactive while loading
|
|
45666
|
-
| `#loading` slot fired on every load
|
|
45667
|
-
| `#no-data` replaced the empty-state `<tr>`
|
|
45668
|
-
| `<table>` / `<thead>` / `<tbody>` / `<tr>` / `<th>` / `<td>` markup _(v2 and v3 ≤ beta.5)_
|
|
45669
|
-
| `--fill` / `--natural-width` published on `.bb-table` _(v3 ≤ beta.5)_
|
|
45670
|
-
| —
|
|
45671
|
-
| —
|
|
45672
|
-
| `
|
|
45673
|
-
|
|
|
45674
|
-
|
|
|
45770
|
+
| v2 | v3 | Kind |
|
|
45771
|
+
| ------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------- |
|
|
45772
|
+
| `allowSelectAll?: boolean` (default `true`) | `disableSelectAll?: boolean` (default `false`) | rename, polarity inverted |
|
|
45773
|
+
| refetch with rows → skeleton | refetch keeps rows visible (dimmed + progress bar) | **behavior** — the skeleton only shows when there is nothing to display |
|
|
45774
|
+
| rows interactive while loading | header + rows go `inert` while loading | **behavior** — opt out with `interactive-while-loading` |
|
|
45775
|
+
| `#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 |
|
|
45776
|
+
| `#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 |
|
|
45777
|
+
| `<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 |
|
|
45778
|
+
| `--fill` / `--natural-width` published on `.bb-table` _(v3 ≤ beta.5)_ | **removed** — nothing publishes them | **⚠ silent** — see below |
|
|
45779
|
+
| — | 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 |
|
|
45780
|
+
| — | **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 |
|
|
45781
|
+
| `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 |
|
|
45782
|
+
| `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 |
|
|
45783
|
+
| 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 |
|
|
45784
|
+
| `--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 |
|
|
45785
|
+
| `useBbTableContext(id).total` _(v3 alphas ≤ 4)_ | `useBbTableContext(id).totalItems` | **hard rename** on the composable handle — see below |
|
|
45786
|
+
| `@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 |
|
|
45787
|
+
| `--bb-table-*` custom properties | same names without the `bb-` prefix | **⚠ silent** for nested-table layouts — see below |
|
|
45675
45788
|
|
|
45676
45789
|
## Columns gained `sortable` and `rowClass` — check yours first
|
|
45677
45790
|
|
|
@@ -45778,6 +45891,113 @@ If you used `#loading` to show a custom refetch treatment, that role is gone —
|
|
|
45778
45891
|
the built-in dim + progress bar covers refetches; `#loading` is now only the
|
|
45779
45892
|
first-paint placeholder.
|
|
45780
45893
|
|
|
45894
|
+
### The `#actions` slot creates the actions column — the prop is gone (v3 beta, 2026-09-07)
|
|
45895
|
+
|
|
45896
|
+
`actions` used to be a boolean prop that rendered the column, with the
|
|
45897
|
+
`#actions` slot filling it. The prop carried no information the slot did
|
|
45898
|
+
not, and it had a footgun: a consumer who declared `{ key: 'actions' }` in
|
|
45899
|
+
`columns` instead of setting the prop got a stray empty data cell and a slot
|
|
45900
|
+
that never rendered. Now the slot alone creates the column — header cell
|
|
45901
|
+
(labelled by `actions-text`, replaceable through `#header:actions`), one
|
|
45902
|
+
cell per row, and the `actions` track for nested tables — and removing the
|
|
45903
|
+
slot (or gating it with `v-if`) removes the column live.
|
|
45904
|
+
|
|
45905
|
+
```diff
|
|
45906
|
+
- <BbTable actions :columns="columns" :items="rows">
|
|
45907
|
+
+ <BbTable :columns="columns" :items="rows">
|
|
45908
|
+
<template #actions="{ item }">…</template>
|
|
45909
|
+
</BbTable>
|
|
45910
|
+
```
|
|
45911
|
+
|
|
45912
|
+
Delete the attribute. The removed-prop warner flags it in dev, the ESLint rule
|
|
45913
|
+
flags it in-editor. The only silent case is a table that set `actions`
|
|
45914
|
+
without ever providing the slot: it had an empty column, and now it does not.
|
|
45915
|
+
|
|
45916
|
+
### `fixedColumns` → `fixed` on the column, `fixed-select` / `fixed-actions` (v3 beta, 2026-09-07)
|
|
45917
|
+
|
|
45918
|
+
Pins used to be **slot indices** into the rendered column list (a selection
|
|
45919
|
+
column was index 0), like spreadsheet freeze panes: with `order` and
|
|
45920
|
+
`reorderable` the pinned _slot_ held and whichever column landed in it was
|
|
45921
|
+
pinned, which is fragile once users drag headers and hide columns. Pins are
|
|
45922
|
+
now a property of the column, the way `width` and `hidden` are, and follow
|
|
45923
|
+
it through reorders. The sticky behaviour itself is unchanged: in place, at
|
|
45924
|
+
the column's own render position, offset by the pinned columns before it on
|
|
45925
|
+
the same side.
|
|
45926
|
+
|
|
45927
|
+
```diff
|
|
45928
|
+
- <BbTable
|
|
45929
|
+
- :columns="columns"
|
|
45930
|
+
- :fixed-columns="[0, { index: columns.length + 1, position: 'right' }]"
|
|
45931
|
+
- selectable
|
|
45932
|
+
- >
|
|
45933
|
+
+ <BbTable :columns="columns" fixed-select fixed-actions selectable>
|
|
45934
|
+
<template #actions="{ item }">…</template>
|
|
45935
|
+
</BbTable>
|
|
45936
|
+
```
|
|
45937
|
+
|
|
45938
|
+
```diff
|
|
45939
|
+
const columns = [
|
|
45940
|
+
- { key: 'name', label: 'Name' },
|
|
45941
|
+
+ { key: 'name', label: 'Name', fixed: 'left' },
|
|
45942
|
+
{ key: 'amount', label: 'Amount', align: 'right' },
|
|
45943
|
+
];
|
|
45944
|
+
```
|
|
45945
|
+
|
|
45946
|
+
Translate each index to the column that sat there: data columns get
|
|
45947
|
+
`fixed: 'left' | 'right'` on their definition, the selection column becomes
|
|
45948
|
+
`fixed-select`, the actions column `fixed-actions` (each has one sensible
|
|
45949
|
+
side, so they are booleans). A nested table that pinned its own actions with
|
|
45950
|
+
`{ index: childColumns.length, position: 'right' }` now says
|
|
45951
|
+
`fixed-actions`. Silent on upgrade: the old prop is ignored (the warner and
|
|
45952
|
+
the ESLint rule flag it), so a table that pinned columns stops pinning until
|
|
45953
|
+
you move the pins onto the definitions.
|
|
45954
|
+
|
|
45955
|
+
### `snap` names the parent column, not a gridline (v3 beta, 2026-09-07)
|
|
45956
|
+
|
|
45957
|
+
A nested table's `snap` was a number: a gridline index into the parent's
|
|
45958
|
+
rendered columns, with the selection column at `0`, fractions for partial
|
|
45959
|
+
tracks and `-1` for the end of the data region. Index `k` was whatever column
|
|
45960
|
+
happened to render there, so a reorder or a hidden column on the parent
|
|
45961
|
+
moved every snap. The parent now publishes its tracks under **column keys**,
|
|
45962
|
+
and `snap` names the parent column:
|
|
45963
|
+
|
|
45964
|
+
```diff
|
|
45965
|
+
const holdings = [
|
|
45966
|
+
- { key: 'name', label: 'Resource', snap: 1 },
|
|
45967
|
+
- { key: 'kind', label: 'Type', snap: 2 },
|
|
45968
|
+
- { key: 'monthlyCost', label: '$ / mo', align: 'right', snap: [3, 4.5] },
|
|
45969
|
+
+ { key: 'name', label: 'Resource', snap: 'name' },
|
|
45970
|
+
+ { key: 'kind', label: 'Type', snap: 'team' },
|
|
45971
|
+
+ { key: 'monthlyCost', label: '$ / mo', align: 'right', snap: ['region', 'monthly.5'] },
|
|
45972
|
+
];
|
|
45973
|
+
```
|
|
45974
|
+
|
|
45975
|
+
- Translate each index to the parent column that rendered there. The
|
|
45976
|
+
selection column is `'select'`, the actions column `'actions'` — both are
|
|
45977
|
+
targets by name, so `['name', 'actions']` runs a child column across the
|
|
45978
|
+
parent's actions cell.
|
|
45979
|
+
- A pair is **inclusive**: `['client', 'amount']` spans from the start of
|
|
45980
|
+
`client` through the end of `amount` (the old `[a, b]` ended at the start
|
|
45981
|
+
of `b`). A trailing `.digits` on a key is a fraction of that track. `-1`
|
|
45982
|
+
is gone: the last column already runs to the end of the data region unless
|
|
45983
|
+
it declares a `width` or a pair.
|
|
45984
|
+
- A child column with no `snap` now pairs with the parent column of the
|
|
45985
|
+
**same key** when there is one, so most children need no snaps at all; a
|
|
45986
|
+
column the parent lacks (or hides) flows into the next free parent track.
|
|
45987
|
+
- Under a parent that uses `order` or `reorderable`, snaps and key pairing
|
|
45988
|
+
are ignored (dev builds warn) and the child inherits by position, as it
|
|
45989
|
+
always did — a moving parent can only be followed slot by slot.
|
|
45990
|
+
|
|
45991
|
+
Silent on upgrade: a numeric `snap` fails the type check but is ignored at
|
|
45992
|
+
runtime, so the child falls back to key pairing and flow, which for a child
|
|
45993
|
+
sharing the parent's keys is the same alignment as before.
|
|
45994
|
+
|
|
45995
|
+
**The published track variables changed name with it.** `--table-{id}-track-{k}`
|
|
45996
|
+
per data column became `--table-{id}-track-{key}`, the key in its slot-name
|
|
45997
|
+
spelling (`address.city` → `address_city`); `select` and `actions` are
|
|
45998
|
+
unchanged. Consumer CSS that read the numbered variables directly has to
|
|
45999
|
+
switch to the keys. Nothing else about the bridge moved.
|
|
46000
|
+
|
|
45781
46001
|
### `#no-data` is content, not a row
|
|
45782
46002
|
|
|
45783
46003
|
v2 handed the slot the whole empty-state `<tr>`, so anything that was not a
|
|
@@ -46198,8 +46418,11 @@ grid actually raises is Chrome/Edge, 114 → 117 (123 for centred cells).
|
|
|
46198
46418
|
- **Do not hide cells with `display: none`** (a `thClass`/`tdClass` of
|
|
46199
46419
|
`hidden`, the v2/early-v3 narrow-screen recipe). A hidden grid item leaves
|
|
46200
46420
|
its track in place: every following cell shifts one track over and the last
|
|
46201
|
-
track collapses. Hide a column
|
|
46202
|
-
breakpoint, which removes the track
|
|
46421
|
+
track collapses. Hide a column with `hidden: true` on its definition at the
|
|
46422
|
+
breakpoint, which removes the track while the column stays declared (so
|
|
46423
|
+
its slot in `order` survives). Filtering it out of `columns` was the
|
|
46424
|
+
interim advice and is now reserved for a column that does not exist for
|
|
46425
|
+
this user at all.
|
|
46203
46426
|
- **`contain: inline-size` on `.bb-table-expand__cell`,
|
|
46204
46427
|
`.bb-table-no-data__cell` and `.bb-table-loading__cell`.** It is the only
|
|
46205
46428
|
thing keeping a full-width cell's content from resizing the column tracks —
|
|
@@ -46220,7 +46443,7 @@ grid actually raises is Chrome/Edge, 114 → 117 (123 for centred cells).
|
|
|
46220
46443
|
|
|
46221
46444
|
### Small semantic and visual changes
|
|
46222
46445
|
|
|
46223
|
-
- **Pinned cells and the stuck header are opaque.** `fixed
|
|
46446
|
+
- **Pinned cells and the stuck header are opaque.** Pinned (`column.fixed`) cells and
|
|
46224
46447
|
the `fixed-headers` band used to be transparent, so scrolled content showed
|
|
46225
46448
|
through them. They now paint the table's surface local `--bg` (default
|
|
46226
46449
|
`var(--bb-panel)`); a pinned cell also paints its row's hover/highlight
|
|
@@ -50070,7 +50293,6 @@ export function useApprovalsInbox(): ApprovalsInboxContext {
|
|
|
50070
50293
|
v-model:highlighted="ctx.highlighted.value"
|
|
50071
50294
|
v-model:select-all="ctx.table.all.value"
|
|
50072
50295
|
v-model:unselected-items="ctx.table.unselected.value"
|
|
50073
|
-
actions
|
|
50074
50296
|
caption="Expense approvals"
|
|
50075
50297
|
:columns="columns"
|
|
50076
50298
|
compact
|
|
@@ -52264,7 +52486,6 @@ export function useBacklogWorkspace(): BacklogWorkspaceContext {
|
|
|
52264
52486
|
v-model:highlighted="highlightedIssue"
|
|
52265
52487
|
v-model:select-all="ctx.table.all.value"
|
|
52266
52488
|
v-model:unselected-items="ctx.table.unselected.value"
|
|
52267
|
-
actions
|
|
52268
52489
|
caption="Sprint 24 backlog"
|
|
52269
52490
|
:columns="columns"
|
|
52270
52491
|
compact
|
|
@@ -55847,10 +56068,10 @@ OwnerPaginator::make(...), 'tabCounts' => [...], 'ownerOptions' => [...]])` —
|
|
|
55847
56068
|
the page.
|
|
55848
56069
|
- **The expand row is a real nested `BbTable` that inherits the parent's
|
|
55849
56070
|
column tracks.** `inherit-column-widths` snaps the holdings table onto the
|
|
55850
|
-
owners table's grid;
|
|
55851
|
-
column
|
|
55852
|
-
|
|
55853
|
-
one edge. This is the recipe's signature move — the full defense is in
|
|
56071
|
+
owners table's grid; every child column carries an explicit `snap` naming
|
|
56072
|
+
the parent column it sits under (`snap: 'name'` … `'monthly'` — the
|
|
56073
|
+
parent's `select` column is accounted for by name), so Resource sits
|
|
56074
|
+
exactly under Owner and the right-aligned $/mo columns share one edge. This is the recipe's signature move — the full defense is in
|
|
55854
56075
|
"Why it is built this way" and in the
|
|
55855
56076
|
[BbTable guide](../../BbTable.md) ("Nested tables that align with the
|
|
55856
56077
|
parent").
|
|
@@ -56355,7 +56576,6 @@ export function useOwnershipAtlas(): OwnershipAtlasContext {
|
|
|
56355
56576
|
v-model:highlighted="highlightedOwner"
|
|
56356
56577
|
v-model:select-all="ctx.table.all.value"
|
|
56357
56578
|
v-model:unselected-items="ctx.table.unselected.value"
|
|
56358
|
-
actions
|
|
56359
56579
|
actions-text="Holdings"
|
|
56360
56580
|
caption="Resource owners"
|
|
56361
56581
|
class="table-flush"
|
|
@@ -56686,10 +56906,10 @@ defineProps<{ owner: Owner }>();
|
|
|
56686
56906
|
* the parent's first data column, and that inset is what reads as hierarchy.
|
|
56687
56907
|
*/
|
|
56688
56908
|
const columns: Array<BbTableColumn<Holding>> = [
|
|
56689
|
-
{ key: 'name', label: 'Resource', snap:
|
|
56690
|
-
{ key: 'kind', label: 'Type', snap:
|
|
56691
|
-
{ key: 'status', label: 'Status', snap:
|
|
56692
|
-
{ key: 'monthlyCost', label: '$ / mo', align: 'right', snap:
|
|
56909
|
+
{ key: 'name', label: 'Resource', snap: 'name' },
|
|
56910
|
+
{ key: 'kind', label: 'Type', snap: 'team' },
|
|
56911
|
+
{ key: 'status', label: 'Status', snap: 'region' },
|
|
56912
|
+
{ key: 'monthlyCost', label: '$ / mo', align: 'right', snap: 'monthly' },
|
|
56693
56913
|
];
|
|
56694
56914
|
|
|
56695
56915
|
const money = (value: number) =>
|
|
@@ -58012,7 +58232,6 @@ const ctx = useInvoiceForm();
|
|
|
58012
58232
|
<!-- Inline-editing table (§6.3): every editable cell type is its own
|
|
58013
58233
|
leaf. The amount column is virtual — computed from the row. -->
|
|
58014
58234
|
<BbTable
|
|
58015
|
-
actions
|
|
58016
58235
|
caption="Invoice line items"
|
|
58017
58236
|
:columns="columns"
|
|
58018
58237
|
compact
|
|
@@ -59216,7 +59435,6 @@ export function useInvoicesWorkspace(): InvoicesWorkspaceContext {
|
|
|
59216
59435
|
v-model="ctx.table.selected.value"
|
|
59217
59436
|
v-model:select-all="ctx.table.all.value"
|
|
59218
59437
|
v-model:unselected-items="ctx.table.unselected.value"
|
|
59219
|
-
actions
|
|
59220
59438
|
caption="Invoices"
|
|
59221
59439
|
:columns="columns"
|
|
59222
59440
|
compact
|
|
@@ -61034,7 +61252,6 @@ export function useUploadCenter(): UploadCenterContext {
|
|
|
61034
61252
|
v-model="ctx.table.selected.value"
|
|
61035
61253
|
v-model:select-all="ctx.table.all.value"
|
|
61036
61254
|
v-model:unselected-items="ctx.table.unselected.value"
|
|
61037
|
-
actions
|
|
61038
61255
|
caption="Expense receipts"
|
|
61039
61256
|
:columns="columns"
|
|
61040
61257
|
compact
|
|
@@ -64427,7 +64644,6 @@ export function useApprovalsInbox(): ApprovalsInboxContext {
|
|
|
64427
64644
|
|
|
64428
64645
|
<BbTable
|
|
64429
64646
|
id="approvals-table"
|
|
64430
|
-
actions
|
|
64431
64647
|
caption="Expense approvals"
|
|
64432
64648
|
:columns="columns"
|
|
64433
64649
|
compact
|
|
@@ -66554,7 +66770,6 @@ export function useBacklogWorkspace(): BacklogWorkspaceContext {
|
|
|
66554
66770
|
<BbTable
|
|
66555
66771
|
id="backlog-table"
|
|
66556
66772
|
v-model:highlighted="highlightedIssue"
|
|
66557
|
-
actions
|
|
66558
66773
|
caption="Sprint 24 backlog"
|
|
66559
66774
|
:columns="columns"
|
|
66560
66775
|
compact
|
|
@@ -70817,7 +71032,6 @@ const ctx = useInvoiceForm();
|
|
|
70817
71032
|
<!-- Inline-editing table (§6.3): every editable cell type is its own
|
|
70818
71033
|
leaf. The amount column is virtual — computed from the row. -->
|
|
70819
71034
|
<BbTable
|
|
70820
|
-
actions
|
|
70821
71035
|
caption="Invoice line items"
|
|
70822
71036
|
:columns="columns"
|
|
70823
71037
|
compact
|
|
@@ -72008,7 +72222,6 @@ export function useInvoicesWorkspace(): InvoicesWorkspaceContext {
|
|
|
72008
72222
|
|
|
72009
72223
|
<BbTable
|
|
72010
72224
|
id="invoices-table"
|
|
72011
|
-
actions
|
|
72012
72225
|
caption="Invoices"
|
|
72013
72226
|
:columns="columns"
|
|
72014
72227
|
compact
|
|
@@ -73718,7 +73931,6 @@ export function useUploadCenter(): UploadCenterContext {
|
|
|
73718
73931
|
|
|
73719
73932
|
<BbTable
|
|
73720
73933
|
id="receipts-table"
|
|
73721
|
-
actions
|
|
73722
73934
|
caption="Expense receipts"
|
|
73723
73935
|
:columns="columns"
|
|
73724
73936
|
compact
|
|
@@ -76961,7 +77173,6 @@ export function useApprovalsInbox(): ApprovalsInboxContext {
|
|
|
76961
77173
|
|
|
76962
77174
|
<BbTable
|
|
76963
77175
|
id="approvals-table"
|
|
76964
|
-
actions
|
|
76965
77176
|
caption="Expense approvals"
|
|
76966
77177
|
:columns="columns"
|
|
76967
77178
|
compact
|
|
@@ -78970,7 +79181,6 @@ export function useBacklogWorkspace(): BacklogWorkspaceContext {
|
|
|
78970
79181
|
<BbTable
|
|
78971
79182
|
id="backlog-table"
|
|
78972
79183
|
v-model:highlighted="highlightedIssue"
|
|
78973
|
-
actions
|
|
78974
79184
|
caption="Sprint 24 backlog"
|
|
78975
79185
|
:columns="columns"
|
|
78976
79186
|
compact
|
|
@@ -84380,7 +84590,6 @@ export function useInvoicesWorkspace(): InvoicesWorkspaceContext {
|
|
|
84380
84590
|
|
|
84381
84591
|
<BbTable
|
|
84382
84592
|
id="invoices-table"
|
|
84383
|
-
actions
|
|
84384
84593
|
caption="Invoices"
|
|
84385
84594
|
:columns="columns"
|
|
84386
84595
|
compact
|
|
@@ -86018,7 +86227,6 @@ export function useUploadCenter(): UploadCenterContext {
|
|
|
86018
86227
|
|
|
86019
86228
|
<BbTable
|
|
86020
86229
|
id="receipts-table"
|
|
86021
|
-
actions
|
|
86022
86230
|
caption="Expense receipts"
|
|
86023
86231
|
:columns="columns"
|
|
86024
86232
|
compact
|