bitboss-ui 3.0.0-beta.0 → 3.0.0-beta.2
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/bin/bitboss-ui.mjs +133 -12
- package/dist/ai/changelog.json +1 -1
- package/dist/ai/components.json +2 -2
- package/dist/ai/guides/ai-router.md +2 -2
- package/dist/ai/guides/design-tokens.md +46 -6
- package/dist/ai/guides/installation-and-plugin-setup.md +71 -5
- package/dist/ai/guides/migration/components/bb-alert.md +37 -0
- package/dist/ai/guides/migration/components/bb-avatar.md +47 -8
- package/dist/ai/guides/migration/components/bb-badge.md +23 -1
- package/dist/ai/guides/migration/components/bb-button.md +64 -0
- package/dist/ai/guides/migration/components/bb-checkbox-group.md +55 -1
- package/dist/ai/guides/migration/components/bb-date-picker-input.md +9 -2
- package/dist/ai/guides/migration/components/bb-dialog.md +121 -11
- package/dist/ai/guides/migration/components/bb-icon.md +42 -0
- package/dist/ai/guides/migration/components/bb-offcanvas.md +35 -1
- package/dist/ai/guides/migration/components/bb-rating.md +52 -1
- package/dist/ai/guides/migration/components/bb-select.md +48 -0
- package/dist/ai/guides/migration/components/bb-table.md +156 -10
- package/dist/ai/guides/migration/components/bb-tabs.md +79 -1
- package/dist/ai/guides/migration/components/bb-text-input.md +23 -1
- package/dist/ai/guides/migration/components/bb-toast.md +44 -10
- package/dist/ai/guides/migration/components/use-confirm.md +48 -13
- package/dist/ai/guides/migration/v2-to-v3.md +626 -108
- package/dist/ai/index.md +9 -9
- package/dist/ai/source/BbDialog.md +0 -3
- package/dist/ai/source/BbDropdown.md +24 -1
- package/dist/ai/source/BbDropdownGroup.md +24 -1
- package/dist/index.d.ts +2 -1
- package/dist/llms-full.txt +1814 -367
- package/dist/llms-medium.txt +82 -16
- package/dist/llms.txt +11 -11
- package/dist/styles.css +1 -1
- package/llms.txt +12 -12
- package/package.json +2 -1
- package/scripts/lib/validate-bb-markup.mjs +105 -17
|
@@ -1,21 +1,103 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: 'Migration v2→v3: BbTable'
|
|
3
|
-
summary: 'allowSelectAll inverted to disableSelectAll; loading no longer blanks populated tables and now inerts rows; #loading is first-load-only; #no-data fills a full-width table cell instead of replacing the row.'
|
|
3
|
+
summary: 'allowSelectAll inverted to disableSelectAll; loading no longer blanks populated tables and now inerts rows; #loading is first-load-only; #no-data fills a full-width table cell instead of replacing the row; columns gained sortable + rowClass, which collide with same-named consumer fields.'
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# BbTable — v2 → v3
|
|
7
7
|
|
|
8
8
|
## Changes
|
|
9
9
|
|
|
10
|
-
| v2 | v3
|
|
11
|
-
| ----------------------------------------------- |
|
|
12
|
-
| `allowSelectAll?: boolean` (default `true`) | `disableSelectAll?: boolean` (default `false`)
|
|
13
|
-
| refetch with rows → skeleton | refetch keeps rows visible (dimmed + progress bar)
|
|
14
|
-
| rows interactive while loading | header + rows go `inert` 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)
|
|
16
|
-
| `#no-data` replaced the empty-state `<tr>` | fills the table's own full-width `<td>` (colspan counted, centred)
|
|
17
|
-
| — | `enforceCoherence` (prunes row-keyed models after each load; incompatible with pagination-via-`dependencies`), `expandedItems` + `#expand`, `sort`, `keyboardNavigation`, `highlighted`, `rowClass` | additive |
|
|
18
|
-
|
|
|
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 `<td>` (colspan counted, centred) | **behavior** — pass content, not a row |
|
|
17
|
+
| — | props `enforceCoherence` (prunes row-keyed models after each load; incompatible with pagination-via-`dependencies`), `expandedItems` + `#expand`, `sort`, `keyboardNavigation`, `highlighted`, `rowClass` | additive |
|
|
18
|
+
| — | **column** fields `sortable?: boolean`, `rowClass?: ColumnClasses` | additive, **collides** — see below |
|
|
19
|
+
| `useBbTableContext(id).total` _(v3 alphas ≤ 4)_ | `useBbTableContext(id).totalItems` | **hard rename** on the composable handle — see below |
|
|
20
|
+
| `--bb-table-*` custom properties | same names without the `bb-` prefix | **⚠ silent** for nested-table layouts — see below |
|
|
21
|
+
|
|
22
|
+
## Columns gained `sortable` and `rowClass` — check yours first
|
|
23
|
+
|
|
24
|
+
v2's `BbTableColumn` had neither field (`grep sortable` over the whole 2.1.135
|
|
25
|
+
`BbTable/types.d.ts` exits empty), and extra fields on a column object were
|
|
26
|
+
inert — so apps parked their own data there. A backend sort key named
|
|
27
|
+
`sortable`. A per-column class named `rowClass`. Both are now real library
|
|
28
|
+
fields, and both break in two directions at once: the **type** stops compiling
|
|
29
|
+
and the **behaviour** silently changes.
|
|
30
|
+
|
|
31
|
+
### The type collision
|
|
32
|
+
|
|
33
|
+
Your column type is almost certainly an intersection:
|
|
34
|
+
|
|
35
|
+
```ts
|
|
36
|
+
type Column = BbTableColumn<Patient> & { sortable?: string }; // backend sort key
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
The intersection makes `sortable` `boolean & string` — i.e. `never`, whose
|
|
40
|
+
optional form TypeScript reports as `undefined`. Every column literal in your
|
|
41
|
+
app fails, and the message never mentions `BbTableColumn`:
|
|
42
|
+
|
|
43
|
+
```
|
|
44
|
+
error TS2322: Type 'string' is not assignable to type 'undefined'.
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
If your field is **required** (`{ sortable: string }`, no `?`) the whole object
|
|
48
|
+
type collapses to `never` and you get one error per property per literal:
|
|
49
|
+
|
|
50
|
+
```
|
|
51
|
+
error TS2322: Type '"id"' is not assignable to type 'never'.
|
|
52
|
+
error TS2322: Type 'string' is not assignable to type 'never'.
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
That fan-out is why a single shared column type produced 166 errors in one real
|
|
56
|
+
migration. Fix it at the type, not at the call sites:
|
|
57
|
+
|
|
58
|
+
```diff
|
|
59
|
+
- type Column = BbTableColumn<Patient> & { sortable?: string };
|
|
60
|
+
+ type Column = BbTableColumn<Patient> & { sortKey?: string };
|
|
61
|
+
|
|
62
|
+
// or keep the name and take the field off the library type
|
|
63
|
+
+ type Column = Omit<BbTableColumn<Patient>, 'sortable'> & { sortable?: string };
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
`Omit` compiles, but read the next section before choosing it.
|
|
67
|
+
|
|
68
|
+
### The behaviour half — a truthy `sortable` turns on the built-in sort UI
|
|
69
|
+
|
|
70
|
+
`BbTable` coerces the field (`sortable: !!column.sortable` in `BbTable.vue`), so
|
|
71
|
+
**any** truthy value counts — including a sort-key string like
|
|
72
|
+
`'patients.created_at'`. The header stops rendering a plain label and renders a
|
|
73
|
+
`.bb-table-sort` button instead, and the `<th>` gains `aria-sort="none"`. An app
|
|
74
|
+
that already ships its own sortable-header UI now draws two.
|
|
75
|
+
|
|
76
|
+
The damage is bounded: `sort` is a controlled model (`v-model:sort`), so the
|
|
77
|
+
extra button emits and does nothing else — it cannot reorder your rows behind
|
|
78
|
+
your back. But it is visible, focusable, and announced.
|
|
79
|
+
|
|
80
|
+
So `Omit` silences the compiler and keeps the bug. Rename the field, or strip
|
|
81
|
+
it at the `BbTable` boundary:
|
|
82
|
+
|
|
83
|
+
```ts
|
|
84
|
+
const tableColumns = computed(() =>
|
|
85
|
+
columns.value.map(({ sortable, ...rest }) => rest)
|
|
86
|
+
);
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Column `rowClass` is the same shape of trap without the type error, because
|
|
90
|
+
`ColumnClasses` already accepts `string`: a leftover `rowClass: 'w-40'` you
|
|
91
|
+
meant for the column typechecks fine and is now merged onto the whole row's
|
|
92
|
+
`<tr>`, alongside the table-level `rowClass` prop. A non-`Classes` shape
|
|
93
|
+
(`rowClass?: { colspan: number }`) does error, with the same `undefined`
|
|
94
|
+
wording.
|
|
95
|
+
|
|
96
|
+
Grep both before you start:
|
|
97
|
+
|
|
98
|
+
```sh
|
|
99
|
+
rg -n 'sortable|rowClass' --type ts --type vue # keep the hits on column objects
|
|
100
|
+
```
|
|
19
101
|
|
|
20
102
|
## Edits
|
|
21
103
|
|
|
@@ -101,3 +183,67 @@ unrelated and does not change.
|
|
|
101
183
|
|
|
102
184
|
`BbPagination` consumers see the same rename through `table-id`; see
|
|
103
185
|
[BbPagination](./bb-pagination.md).
|
|
186
|
+
|
|
187
|
+
## The custom properties the table _publishes_ lost the `bb-` prefix
|
|
188
|
+
|
|
189
|
+
These are not theming inputs — they are values `BbTable` measures at runtime and
|
|
190
|
+
writes onto its own DOM, for the table's CSS and for descendants to read. You
|
|
191
|
+
reach for them for exactly one reason: aligning a nested table's columns to its
|
|
192
|
+
parent's. They all dropped the prefix.
|
|
193
|
+
|
|
194
|
+
| v2 | v3 |
|
|
195
|
+
| ------------------------------------------- | ------------------------------------------- |
|
|
196
|
+
| `--bb-table-{id}-track-{key}` | `--table-{id}-track-{key}` |
|
|
197
|
+
| `--bb-table-offset-start` / `-end` | `--offset-start` / `--offset-end` |
|
|
198
|
+
| `--bb-table-offset-internal-start` / `-end` | `--offset-internal-start` / `-internal-end` |
|
|
199
|
+
| `--bb-table-offset-external-start` / `-end` | `--offset-external-start` / `-external-end` |
|
|
200
|
+
| `--bb-table-fill` | `--fill` |
|
|
201
|
+
| `--bb-table-natural-width` | `--natural-width` |
|
|
202
|
+
| `--bb-table-cell-h` | `--cell-h` |
|
|
203
|
+
|
|
204
|
+
Only the track bridge keeps a `table-` segment, because it crosses component
|
|
205
|
+
boundaries; the rest are plain locals on `.bb-table`. `--padding-x`,
|
|
206
|
+
`--padding-y` and `--actions-spacing` were already unprefixed in v2 and keep
|
|
207
|
+
their names (their _values_ tightened: `16px`/`8px` → `12px`/`6px`, and the cell
|
|
208
|
+
height `42px` → `36px`).
|
|
209
|
+
|
|
210
|
+
**Every one of these fails silently.** They are read as
|
|
211
|
+
`var(--offset-internal-start)` with a fallback, so a v2 override lands on a name
|
|
212
|
+
nothing consumes and the layout quietly falls back to its default. The worst
|
|
213
|
+
case is code that _scans_ for them — a nested-table helper matching
|
|
214
|
+
`/--bb-table-[\w-]+-track/` over `element.style` matches nothing at all, no
|
|
215
|
+
error, just columns that no longer line up:
|
|
216
|
+
|
|
217
|
+
```diff
|
|
218
|
+
- const track = /--bb-table-[\w-]+-track/;
|
|
219
|
+
+ const track = /--table-[\w-]+-track/;
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
Grep your app CSS and any style-scanning JS for `--bb-table-` — no name with
|
|
223
|
+
that prefix exists in v3.
|
|
224
|
+
|
|
225
|
+
The table is not the only component this happened to. Four more published
|
|
226
|
+
variables lost the prefix the same way: `--bb-select-popover-width` → `--w` on
|
|
227
|
+
`.bb-select-popover` (and the supported path is now the `width` prop, not a CSS
|
|
228
|
+
override), `--bb-icon-dimensions-w` → `--w` on `.bb-icon`,
|
|
229
|
+
`--bb-breadcrumbs-flex-basis` / `-flex-grow` → `--flex-basis` / `--flex-grow`,
|
|
230
|
+
and `--bb-picker-preview-color` → `--picker-preview-color`. Widen the grep
|
|
231
|
+
accordingly: `--bb-select-popover-`, `--bb-icon-dimensions-`, `--bb-breadcrumbs-`,
|
|
232
|
+
`--bb-picker-`. See
|
|
233
|
+
[design-tokens.md](../../design-tokens.md#migration-from-the-old-tokens) for the
|
|
234
|
+
theming-token side of the same rename.
|
|
235
|
+
|
|
236
|
+
## `caption` names the selection fieldset when `legend` is absent
|
|
237
|
+
|
|
238
|
+
A `selectable` table wraps itself in a `<fieldset>` and needs an accessible
|
|
239
|
+
name. v3 resolves it as `legend`, then `caption`, then a generic localized
|
|
240
|
+
string — so a table that already has a `caption` is correctly named and does not
|
|
241
|
+
need a `legend`.
|
|
242
|
+
|
|
243
|
+
`npx bitboss-ui check` (and the ESLint rule behind it) still asks for `legend`
|
|
244
|
+
specifically, so `<BbTable selectable caption="Patients" />` fails the check
|
|
245
|
+
even though its fieldset is named. That one is a **quality nudge, not a broken
|
|
246
|
+
affordance** — unlike the other partner-prop pairs, ignoring it does not leave
|
|
247
|
+
anything silently doing nothing. Pass a `legend` when it says something the
|
|
248
|
+
caption does not ("select invoices to export" vs "Invoices"); otherwise suppress
|
|
249
|
+
the rule at the call site rather than duplicating the caption into a `<legend>`.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: 'Migration v2→v3: BbTabs (was BbTab)'
|
|
3
|
-
summary: Component renamed; querykey→queryKey; animations default on; label slots renamed and all dynamic names/URL slugs normalized.
|
|
3
|
+
summary: Component renamed; querykey→queryKey; animations default on; label slots renamed and all dynamic names/URL slugs normalized; the entire .bb-tab BEM tree renamed to .bb-tabs / .bb-tabs-list / .bb-tabs-panes.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# BbTabs — v2 → v3
|
|
@@ -19,6 +19,8 @@ aliases survive as deprecated re-exports, the tag name does not).
|
|
|
19
19
|
| pane slot `#<key>` (raw) | `#<slotKey(key)>` | normalization |
|
|
20
20
|
| URL value = raw key | URL value = normalized slug | **⚠ breaking for deep links** |
|
|
21
21
|
| tab/panel DOM ids from raw key | normalized (also fixes invalid ids for spaced keys) | check E2E selectors |
|
|
22
|
+
| `.bb-tab*` CSS | `.bb-tabs*` / `.bb-tabs-list*` / `.bb-tabs-panes` | **⚠ silent** — the whole BEM tree renamed, see below |
|
|
23
|
+
| — | `block` (full-width, equal-width triggers) | additive — replaces hand-rolled full-width classes |
|
|
22
24
|
|
|
23
25
|
`slotKey(key)` lowercases and replaces every non-word run with `_`:
|
|
24
26
|
`"In Review"` → `in_review`, `"2024-03-15"` → `2024_03_15`. Keys that are
|
|
@@ -45,3 +47,79 @@ still selects that tab; only slots, ids, and the URL use the slug.
|
|
|
45
47
|
the normalized slug (`?section=in_review`, not `?section=In%20Review`).
|
|
46
48
|
Existing bookmarks with raw values fall back to the default tab — add a
|
|
47
49
|
redirect if those links matter.
|
|
50
|
+
|
|
51
|
+
## CSS: every class renamed with the component
|
|
52
|
+
|
|
53
|
+
The component rename took the whole BEM tree with it. v2 kept everything under
|
|
54
|
+
one block, `.bb-tab`; v3 splits it into `.bb-tabs` (root) plus two blocks of
|
|
55
|
+
their own, `.bb-tabs-list` (the strip) and `.bb-tabs-panes` (the pane wrapper).
|
|
56
|
+
**No `.bb-tab*` selector survives**, and nothing warns — your v2 tab CSS just
|
|
57
|
+
stops matching and the shipped styling shows through.
|
|
58
|
+
|
|
59
|
+
| v2 | v3 |
|
|
60
|
+
| ----------------------------------------- | ----------------------------------------------------------------- |
|
|
61
|
+
| `.bb-tab` | `.bb-tabs` |
|
|
62
|
+
| `.bb-tab--horizontal` | `.bb-tabs--horizontal` (+ `.bb-tabs-list--horizontal`) |
|
|
63
|
+
| `.bb-tab--vertical` | `.bb-tabs--vertical` (+ `.bb-tabs-list--vertical`) |
|
|
64
|
+
| `.bb-tab--disabled` | `.bb-tabs--disabled` (+ `.bb-tabs-list--disabled`) |
|
|
65
|
+
| `.bb-tab__label-boundary` | `.bb-tabs-list` |
|
|
66
|
+
| `.bb-tab__label-container` | `.bb-tabs-list__tablist` |
|
|
67
|
+
| `.bb-tab__label-container--no-transition` | `.bb-tabs-list__tablist--no-transition` |
|
|
68
|
+
| `.bb-tab__btn` | `.bb-tabs__trigger` |
|
|
69
|
+
| `.bb-tab__btn--active` | `.bb-tabs__trigger--active` |
|
|
70
|
+
| `.bb-tab__label` | `.bb-tabs__trigger-label`, wrapped in `.bb-tabs__trigger-content` |
|
|
71
|
+
| `.bb-tab__panes-container` | `.bb-tabs-panes` |
|
|
72
|
+
| `.bb-tab__pane` | `.bb-tabs__pane` |
|
|
73
|
+
| `.bb-tab__pane--shown` | `.bb-tabs__pane--shown` |
|
|
74
|
+
|
|
75
|
+
New in v3 with no v2 counterpart: `.bb-tabs--block` / `.bb-tabs-list--block`,
|
|
76
|
+
`.bb-tabs--compact` / `.bb-tabs-list--compact`, `.bb-tabs-list__prepend` and
|
|
77
|
+
`__append`, `.bb-tabs-list__tablist--measuring`.
|
|
78
|
+
|
|
79
|
+
Four things to know while porting rules:
|
|
80
|
+
|
|
81
|
+
- **The nesting did not change.** `.bb-tab__label-container` and
|
|
82
|
+
`.bb-tabs-list__tablist` are the same `<ul>`. The sliding active pill is
|
|
83
|
+
still that element's `::before`, still positioned from `--left` / `--top` /
|
|
84
|
+
`--width` / `--height` set inline on it. A v2 pill override moves by name
|
|
85
|
+
only, not up or down a level.
|
|
86
|
+
- **`.bb-tabs--horizontal` is rendered.** The direction modifier is applied
|
|
87
|
+
unconditionally (`bb-tabs--${direction}`, default `'horizontal'`), so a
|
|
88
|
+
renamed v2 rule keeps working. The library ships no _rule_ for the horizontal
|
|
89
|
+
modifier — only `--vertical` is styled — but that does not affect your
|
|
90
|
+
selectors. Do **not** rewrite these as `:not(.bb-tabs--vertical)`.
|
|
91
|
+
- **The `<ul>` is no longer an only child.** `.bb-tabs-list` is a grid holding
|
|
92
|
+
`__prepend`, the tablist, and `__append`. A v2 rule written as
|
|
93
|
+
`.bb-tab__label-boundary > *` now over-matches; target
|
|
94
|
+
`.bb-tabs-list__tablist` by name.
|
|
95
|
+
- **Block naming is not uniform** between the two new blocks: the pane wrapper
|
|
96
|
+
is `.bb-tabs-panes`, but the pane inside it is an element of the root,
|
|
97
|
+
`.bb-tabs__pane`. There is no `.bb-tabs-panes__pane`.
|
|
98
|
+
|
|
99
|
+
Grep for survivors — this catches every v2 name and no v3 one:
|
|
100
|
+
|
|
101
|
+
```sh
|
|
102
|
+
rg -n 'bb-tab(__|--)|\.bb-tab\b'
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## `block` replaces hand-rolled full-width tabs
|
|
106
|
+
|
|
107
|
+
v2 shipped no full-width tab list, so apps minted their own class — commonly a
|
|
108
|
+
`bb-tab--full-width` / `bb-tabs--full-width` rule stretching the `<ul>` and
|
|
109
|
+
setting `flex: 1` on each button. v3 has the prop:
|
|
110
|
+
|
|
111
|
+
```diff
|
|
112
|
+
- <BbTab :items="items" class="bb-tabs--full-width">
|
|
113
|
+
+ <BbTabs :items="items" block>
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
`block` sets `.bb-tabs--block` and `.bb-tabs-list--block`: the strip stretches
|
|
117
|
+
to 100% and every trigger takes an equal share of the free space, floored at
|
|
118
|
+
the widest trigger's measured width (published as `--eq` on the tablist) so the
|
|
119
|
+
triggers stay equal even when the strip overflows and scrolls. Horizontal only
|
|
120
|
+
— the vertical strip skips the measurement.
|
|
121
|
+
|
|
122
|
+
Delete the hand-rolled rule when you switch. Left in place it fights `--block`
|
|
123
|
+
over the same `flex` and `min-width` declarations, and because your class name
|
|
124
|
+
is now unrecognised (`bb-tabs--full-width` collides with nothing the library
|
|
125
|
+
ships) neither the checker nor ESLint will tell you which one won.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: 'Migration v2→v3: BbTextInput'
|
|
3
|
-
summary: The type prop narrows to the text-like input types — number/date values must move to their dedicated components.
|
|
3
|
+
summary: The type prop narrows to the text-like input types — number/date values must move to their dedicated components; a bare `floating` attribute was never a prop, the spelling is label-mode="floating".
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# BbTextInput — v2 → v3
|
|
@@ -36,6 +36,28 @@ Also relevant here: the shared input wrapper's CSS block was renamed — any CSS
|
|
|
36
36
|
or test selectors on `.bb-common-input-inner-container*` must move to
|
|
37
37
|
`.common-input-wrapper--*` (see [main guide §5](../v2-to-v3.md)).
|
|
38
38
|
|
|
39
|
+
## `floating` is not a prop — it is a value of `label-mode`
|
|
40
|
+
|
|
41
|
+
```diff
|
|
42
|
+
- <BbTextInput v-model="email" label="Email" floating />
|
|
43
|
+
+ <BbTextInput v-model="email" label="Email" label-mode="floating" />
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
`labelMode?: 'outside' | 'floating' | 'inside'` — same in v2 as in v3. A bare
|
|
47
|
+
`floating` was never a `BbTextInput` prop on either version; it falls through
|
|
48
|
+
`$attrs` onto the root element and does nothing, silently. Applies to the whole
|
|
49
|
+
input family, which shares `labelMode`.
|
|
50
|
+
|
|
51
|
+
`bitboss-ui check` flags it, but points the wrong way:
|
|
52
|
+
|
|
53
|
+
> prop `floating` is not in BbTextInput's API — `floating` belongs to
|
|
54
|
+
> BbDatePicker, BbDatePickerInput, not BbTextInput
|
|
55
|
+
|
|
56
|
+
That is true and irrelevant. Those two do declare a real `floating` boolean, and
|
|
57
|
+
it means something else entirely there (emit plain calendar strings instead of
|
|
58
|
+
zoned ISO instants). The answer is `label-mode="floating"` on the component you
|
|
59
|
+
already have.
|
|
60
|
+
|
|
39
61
|
## DOM: `--hidden-label` layout class removed (2026-08-07)
|
|
40
62
|
|
|
41
63
|
`BbBaseInputContainer` — the wrapper behind every labelled control in the
|
|
@@ -22,24 +22,58 @@ plugin's `toastPosition` config (default `bottom-right`).
|
|
|
22
22
|
|
|
23
23
|
## `toast()` options
|
|
24
24
|
|
|
25
|
-
| v2
|
|
26
|
-
|
|
|
27
|
-
| `theme?: string`
|
|
28
|
-
| `
|
|
29
|
-
| `
|
|
30
|
-
|
|
|
25
|
+
| v2 | v3 | Kind |
|
|
26
|
+
| -------------------------------------- | ---------------------------------------------------------------------------------------------------------- | ------------------------- |
|
|
27
|
+
| `theme?: string` | `variant?: ToastVariantType` (built-ins `default, success, info, warning, destructive`) | typed rename |
|
|
28
|
+
| `timeout?: number` | `duration?: number` | rename |
|
|
29
|
+
| `showClose?: boolean` (default `true`) | `hideClose?: boolean` (default `false`) | rename, polarity inverted |
|
|
30
|
+
| `persistent` | unchanged | |
|
|
31
|
+
| `title`, `text`, `icon` | unchanged (`text` is now optional) | |
|
|
32
|
+
| — | `position`, `loading`, `id` + `updateToast()`, `dismissToast(reason)`, `portal` / `portalProps`, `actions` | additive |
|
|
31
33
|
|
|
32
|
-
`
|
|
33
|
-
|
|
34
|
+
`timeout` → `duration` is the one to grep for. It is an options-object key, not
|
|
35
|
+
a template attribute, so neither `bitboss-ui check` nor the eslint plugin sees
|
|
36
|
+
it; TS catches a literal `toast({ timeout: 8000 })` on excess-property grounds,
|
|
37
|
+
but a JS call site — or options built up in a variable — just drops the key and
|
|
38
|
+
takes the default, which also shortened: **v2 6000ms, v3 4000ms**. Same rule at
|
|
39
|
+
both ends: a non-positive value throws. `rg -n 'timeout' --type ts --type js`
|
|
40
|
+
over your toast call sites.
|
|
41
|
+
|
|
42
|
+
`showClose` inverts, it does not disappear: `showClose: false` → `hideClose: true`,
|
|
43
|
+
and `showClose: true` was the default so **delete it**.
|
|
34
44
|
|
|
35
45
|
```diff
|
|
36
|
-
- toast({ title: 'Deleted', theme: 'success' });
|
|
37
|
-
+ toast({ title: 'Deleted', variant: 'success' });
|
|
46
|
+
- toast({ title: 'Deleted', theme: 'success', timeout: 4000, showClose: false });
|
|
47
|
+
+ toast({ title: 'Deleted', variant: 'success', duration: 4000, hideClose: true });
|
|
38
48
|
|
|
39
49
|
// the hand-rolled undo pattern collapses to:
|
|
40
50
|
+ toast({ title: 'Deleted', actions: [{ text: 'Undo', onClick: restore }] });
|
|
41
51
|
```
|
|
42
52
|
|
|
53
|
+
`toast('plain string')` still works. The `BbToastMessage` type export is gone
|
|
54
|
+
— type options as `BbToastOptions` (and a partial update as `BbToastUpdate`).
|
|
55
|
+
|
|
56
|
+
## What `useToast()` returns
|
|
57
|
+
|
|
58
|
+
| v2 | v3 |
|
|
59
|
+
| -------------------------------- | ------------------------------------------------------------ |
|
|
60
|
+
| `{ toast, dismiss, dismissAll }` | `{ toast, dismiss, update }` |
|
|
61
|
+
| `dismiss(id)` — id required | `dismiss(id?, reason?)` — **no argument dismisses them all** |
|
|
62
|
+
| `dismissAll()` | removed — call `dismiss()` with no argument |
|
|
63
|
+
| — | `update(id, options)` |
|
|
64
|
+
|
|
65
|
+
```diff
|
|
66
|
+
- const { toast, dismissAll } = useToast();
|
|
67
|
+
- dismissAll();
|
|
68
|
+
+ const { toast, dismiss } = useToast();
|
|
69
|
+
+ dismiss();
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Nothing catches this for you — `dismissAll` is not a template attribute, so
|
|
73
|
+
`bitboss-ui check` and the eslint plugin never see it. Grep:
|
|
74
|
+
`rg -n 'dismissAll' --type ts --type js --type vue`. Hits on a `useConfirm()`
|
|
75
|
+
destructure are fine: `dismissAll` is **new** there, and unrelated.
|
|
76
|
+
|
|
43
77
|
Notes on `actions` (additive but with rules): handlers run with a spinner and
|
|
44
78
|
sibling-disable, and hold the dismiss timer; portal toasts ignore `actions`.
|
|
45
79
|
Styling hooks moved from `theme` classes to `bb-toast-message--<variant>` —
|
|
@@ -1,25 +1,34 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: 'Migration v2→v3: confirm() / useConfirm'
|
|
3
|
-
summary: yesText/onYes/noText/onNo collapse into yes/no configs, actions becomes an array-or-false, labels are localized, footer buttons default md.
|
|
3
|
+
summary: yesText/onYes/noText/onNo collapse into yes/no configs, actions becomes an array-or-false, theme→variant, timeout→duration, autoClose flips to default-true, labels are localized, footer buttons default md.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# `confirm()` / `useConfirm` — v2 → v3
|
|
7
7
|
|
|
8
8
|
## Options
|
|
9
9
|
|
|
10
|
-
| v2 | v3
|
|
11
|
-
| ------------------------------------------------------------------------------------ |
|
|
12
|
-
| `yes?: boolean`, `yesText?: string`, `onYes?: () => …` | `yes?: false \| string \| ConfirmButtonConfig` (`{ text, variant, size, icon?, onClick? }`)
|
|
13
|
-
| `no?: boolean`, `noText?: string`, `onNo?: () => …` | `no?: false \| string \| ConfirmButtonConfig`
|
|
14
|
-
| `actions?: boolean` | `actions?: false \| ConfirmButtonConfig[]`
|
|
15
|
-
| default labels `"OK"` / `"Annulla"` (hard-coded) | localized via the active `locale`
|
|
16
|
-
| footer buttons `lg` | footer buttons default `md`
|
|
17
|
-
| `size` | `size?: keyof DialogSizes` — forwards to `BbDialog`
|
|
18
|
-
|
|
|
19
|
-
|
|
|
10
|
+
| v2 | v3 | Kind |
|
|
11
|
+
| ------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
|
|
12
|
+
| `yes?: boolean`, `yesText?: string`, `onYes?: () => …` | `yes?: false \| string \| ConfirmButtonConfig` (`{ text, variant, size, icon?, onClick? }`) | collapsed — **`yes: false` still hides the button, unchanged from v2.** Leave it alone; only `yesText`/`onYes` move into the config |
|
|
13
|
+
| `no?: boolean`, `noText?: string`, `onNo?: () => …` | `no?: false \| string \| ConfirmButtonConfig` | collapsed — same: **`no: false` is a no-op migration**, it hides the button exactly as in v2 |
|
|
14
|
+
| `actions?: boolean` | `actions?: false \| ConfirmButtonConfig[]` | `false` hides the footer; an array replaces the yes/no pair with custom buttons |
|
|
15
|
+
| default labels `"OK"` / `"Annulla"` (hard-coded) | localized via the active `locale` | **⚠ silent** — English apps stop showing Italian "Annulla"; apps that _wanted_ the literals must pass them |
|
|
16
|
+
| footer buttons `lg` | footer buttons default `md` | visual |
|
|
17
|
+
| `size` | `size?: keyof DialogSizes` — forwards to `BbDialog` | see the dialog width change in [main guide §2](../v2-to-v3.md) |
|
|
18
|
+
| `theme?: string` | `variant?: ConfirmVariantType` (built-ins `default`, `destructive`) | typed rename — unregistered names are a compile error; add yours via the plugin's `confirmVariants` |
|
|
19
|
+
| `timeout?: number` | `duration?: number` | rename — auto-dismisses, resolves `false` quietly (no `no.onClick`), and implicitly forces `autoClose: true` |
|
|
20
|
+
| `autoClose?: boolean` — **opt-in**, omitted means the dialog stays open | `autoClose?: boolean` — **default `true`** | **⚠ silent behavior flip** — a v2 multi-step flow that kept the dialog open after resolve must now pass `autoClose: false` |
|
|
21
|
+
| `hideHeader?: boolean` (a union that made `title` required when `false`) | removed — `title` is plain optional; omit it and no header renders | removed |
|
|
22
|
+
| `useConfirm().setLoading(value)` | removed — busy state is driven by the button's `onClick` promise | removed — `useConfirm()` now returns `{ confirm, close, dismissAll }` |
|
|
23
|
+
| — | `hideClose`, `portal` / `portalProps` (mutually exclusive with `text`) | additive |
|
|
24
|
+
| second `confirm()` while one is open: first promise **never settled** (hung forever) | the superseded promise resolves `false` (implicit dismiss, no callbacks) | **⚠ behavioral** (bugfix 2026-07-18; the replace-not-queue semantics are unchanged) |
|
|
20
25
|
|
|
21
|
-
`
|
|
22
|
-
|
|
26
|
+
`title`, `text`, and the returned promise semantics otherwise carry over.
|
|
27
|
+
`autoClose` does **not** — see its row above.
|
|
28
|
+
|
|
29
|
+
Grep for the collapsed keys: `rg -n 'yesText|noText|onYes|onNo|hideHeader|setLoading|autoClose|timeout' --type ts --type js --type vue`.
|
|
30
|
+
TypeScript catches all of them (excess-property checks on the options literal,
|
|
31
|
+
a hard property error on `setLoading`); a JS app gets no signal at all.
|
|
23
32
|
|
|
24
33
|
## Edits
|
|
25
34
|
|
|
@@ -52,3 +61,29 @@ drops the whole footer. Both spellings survive v2 → v3 untouched.
|
|
|
52
61
|
|
|
53
62
|
If you only ever called `confirm('Are you sure?')`, nothing changes except the
|
|
54
63
|
(localized) button labels and their size.
|
|
64
|
+
|
|
65
|
+
## CSS hooks
|
|
66
|
+
|
|
67
|
+
| v2 | v3 |
|
|
68
|
+
| ------------------------------------------- | ------------------------------------------------------------------------------------- |
|
|
69
|
+
| `.bb-confirm__content`, `.bb-confirm__text` | unchanged — still the right targets for the body copy |
|
|
70
|
+
| `.bb-confirm__no` / `.bb-confirm__yes` | **gone** — the footer buttons render as bare `BbButton`s with no confirm class |
|
|
71
|
+
| `.bb-confirm .bb-base-dialog__*` | `.bb-confirm .bb-dialog__*` — plus `.bb-offcanvas__*`, the adaptive sheet's parts |
|
|
72
|
+
| — | `.bb-confirm--<variant>` on the dialog root — the lever for per-variant confirm skins |
|
|
73
|
+
|
|
74
|
+
`.bb-confirm__text` survives, so a v2 rule targeting the body copy still lands;
|
|
75
|
+
do not relocate it onto `.bb-dialog__body`.
|
|
76
|
+
|
|
77
|
+
The cancel button is the one that lost its hook. Restyle it per call instead of
|
|
78
|
+
in CSS — v3 defaults it to `size: 'md', variant: 'outline'`, and the Yes button
|
|
79
|
+
to `primary` (or `destructive` when the confirm `variant` is `destructive`):
|
|
80
|
+
|
|
81
|
+
```diff
|
|
82
|
+
- .bb-confirm .bb-base-dialog__footer .bb-confirm__no:hover:not(:disabled) {
|
|
83
|
+
- --color: var(--bb-primary);
|
|
84
|
+
- }
|
|
85
|
+
+ confirm({ title: '…', no: { text: 'Keep', variant: 'ghost' } });
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
For a whole-skin change, register a confirm variant and hang the rules off
|
|
89
|
+
`.bb-confirm--<name>` rather than reaching for the old element classes.
|