bitboss-ui 3.0.0-beta.18 → 3.0.0-beta.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +39 -7
- package/dist/ai/BbBaseCheckboxGroup.md +1 -1
- package/dist/ai/BbBaseSwitchGroup.md +1 -1
- package/dist/ai/BbDialog.md +63 -0
- package/dist/ai/BbOffCanvas.md +58 -0
- package/dist/ai/BbSelect.md +11 -5
- package/dist/ai/BbSelectPopover.md +10 -5
- package/dist/ai/BbSwitch.md +13 -0
- package/dist/ai/BbTable.md +7 -4
- package/dist/ai/changelog.json +1 -1
- package/dist/ai/components.json +26 -24
- package/dist/ai/composables/useBbConfig.md +47 -6
- package/dist/ai/guides/ai-router.md +9 -4
- package/dist/ai/guides/fetch-items-playbook.md +1 -1
- package/dist/ai/guides/installation-and-plugin-setup.md +19 -5
- package/dist/ai/guides/migration/components/bb-checkbox.md +35 -2
- package/dist/ai/guides/migration/components/bb-dialog.md +27 -7
- package/dist/ai/guides/migration/components/bb-offcanvas.md +11 -10
- package/dist/ai/guides/migration/v2-to-v3.md +10 -10
- package/dist/ai/guides/ssr-prefill.md +120 -0
- package/dist/ai/index.md +3 -2
- package/dist/ai/source/BbBaseCheckboxGroup.md +5 -1
- package/dist/ai/source/BbBaseRadioGroup.md +4 -0
- package/dist/ai/source/BbBaseSwitchGroup.md +4 -0
- package/dist/ai/source/BbCheckbox.md +15 -1
- package/dist/ai/source/BbDialog.md +85 -3
- package/dist/ai/source/BbOffCanvas.md +72 -3
- package/dist/ai/source/BbRadio.md +15 -1
- package/dist/ai/source/BbSelectPopover.md +4 -0
- package/dist/ai/source/BbSwitch.md +15 -1
- package/dist/ai/source/BbTable.md +4 -0
- package/dist/components/BbBaseCheckboxGroup/BbBaseCheckboxGroup.vue_vue_type_script_setup_true_lang.js +28 -26
- package/dist/components/BbBaseCheckboxGroup/types.d.ts +1 -1
- package/dist/components/BbBaseRadioGroup/BbBaseRadioGroup.vue_vue_type_script_setup_true_lang.js +22 -20
- package/dist/components/BbBaseSwitchGroup/BbBaseSwitchGroup.vue_vue_type_script_setup_true_lang.js +28 -26
- package/dist/components/BbDialog/BbDialog.vue_vue_type_script_setup_true_lang.js +115 -94
- package/dist/components/BbDialog/types.d.ts +23 -0
- package/dist/components/BbOffCanvas/BbOffCanvas.vue_vue_type_script_setup_true_lang.js +149 -134
- package/dist/components/BbOffCanvas/types.d.ts +23 -0
- package/dist/components/BbSelectPopover/BbSelectPopover.vue_vue_type_script_setup_true_lang.js +82 -80
- package/dist/components/BbTable/BbTable.vue_vue_type_script_setup_true_lang.js +204 -202
- package/dist/composables/useBbConfig.d.ts +11 -5
- package/dist/composables/useBbConfig.js +5 -6
- package/dist/composables/useConfig.d.ts +13 -4
- package/dist/composables/useConfig.js +1 -1
- package/dist/composables/useItemsGetter.d.ts +11 -0
- package/dist/composables/useItemsGetter.js +44 -18
- package/dist/composables/usePrefill.d.ts +21 -2
- package/dist/composables/usePrefill.js +25 -19
- package/dist/composables/useSsrState.d.ts +20 -0
- package/dist/composables/useSsrState.js +13 -0
- package/dist/deprecation/ai-deprecations.json.d.ts +0 -22
- package/dist/deprecation/ai-deprecations.json.js +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +63 -62
- package/dist/llms-full.txt +634 -245
- package/dist/llms-medium.txt +37 -18
- package/dist/llms.txt +5 -4
- package/dist/runtime/nuxt-plugin.js +28 -21
- package/dist/styles.css +1 -1
- package/dist/utilities/misc/ssrStateInjectionKey.d.ts +42 -0
- package/dist/utilities/misc/ssrStateInjectionKey.js +4 -0
- package/dist/vite.js +6 -2
- package/llms.txt +6 -5
- package/package.json +2 -2
- package/scripts/lib/eslint-plugin.d.ts +19 -1
- package/scripts/lib/eslint-plugin.mjs +146 -0
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@ Vue 3 component library used across BitBoss products. It ships typed building bl
|
|
|
6
6
|
|
|
7
7
|
## What’s in the package
|
|
8
8
|
|
|
9
|
-
Published artifacts are **`dist/`** (ESM JavaScript, `.d.ts`, the two stylesheets **`styles.css`** and **`reset.css`**, and the `dist/ai/` knowledge base), plus the **`bin/`** CLI, **`scripts/lib/`** (ESLint plugin and markup validator), the root **`llms.txt`**, and this **README**. The sections below match how the library is organised in code and in the [documentation](https://ui-components
|
|
9
|
+
Published artifacts are **`dist/`** (ESM JavaScript, `.d.ts`, the two stylesheets **`styles.css`** and **`reset.css`**, and the `dist/ai/` knowledge base), plus the **`bin/`** CLI, **`scripts/lib/`** (ESLint plugin and markup validator), the root **`llms.txt`**, and this **README**. The sections below match how the library is organised in code and in the [documentation](https://ui-components.bitboss.it/).
|
|
10
10
|
|
|
11
11
|
### Styles
|
|
12
12
|
|
|
@@ -90,7 +90,7 @@ For the public **Bb\*** components, the package exports matching **props**, **ev
|
|
|
90
90
|
|
|
91
91
|
**Primary docs (components, props, guides):**
|
|
92
92
|
|
|
93
|
-
- [BitBoss UI documentation](https://ui-components
|
|
93
|
+
- [BitBoss UI documentation](https://ui-components.bitboss.it/) — site with guides and API reference.
|
|
94
94
|
|
|
95
95
|
**For AI coding agents:**
|
|
96
96
|
|
|
@@ -100,10 +100,10 @@ v3 prerelease; pin an exact version (`bitboss-ui@3.0.0-alpha.5`) for stable
|
|
|
100
100
|
links. Sizes grow with the catalogue — treat them as the current order of
|
|
101
101
|
magnitude, not a contract.
|
|
102
102
|
|
|
103
|
-
- [Core knowledge base](https://
|
|
104
|
-
- [Index](https://
|
|
105
|
-
- [components.json](https://
|
|
106
|
-
- [Complete knowledge base](https://
|
|
103
|
+
- [Core knowledge base](https://llms-bitboss-ui.bitboss.it/dist/llms-medium.txt) (~110 KB) — **start here if you can only fetch one file.** Hard rules, setup, component picker, design language, and the full component catalogue.
|
|
104
|
+
- [Index](https://llms-bitboss-ui.bitboss.it/llms.txt) (~19 KB) — link index into every document.
|
|
105
|
+
- [components.json](https://llms-bitboss-ui.bitboss.it/dist/ai/components.json) — machine-readable API surface, for programmatic validation.
|
|
106
|
+
- [Complete knowledge base](https://llms-bitboss-ui.bitboss.it/dist/llms-full.txt) (~3.2 MB) — everything concatenated. Bulk ingestion only; too large to prompt with.
|
|
107
107
|
|
|
108
108
|
Already installed? Prefer the local copy under `node_modules/bitboss-ui/dist/ai/`,
|
|
109
109
|
run `npx bitboss-ui ai-init` to write agent pointers, and
|
|
@@ -328,6 +328,38 @@ migrations — a value that must move to a slot, directive, or CSS — are repor
|
|
|
328
328
|
with a migration-guide link but left for you. Run `eslint --fix`, then the
|
|
329
329
|
remaining reports are exactly the by-hand cases.
|
|
330
330
|
|
|
331
|
+
#### The one v2 break a codemod cannot own: `reverse`
|
|
332
|
+
|
|
333
|
+
`reverse` on `BbCheckbox` / `BbRadio` / `BbSwitch` kept its **name** and
|
|
334
|
+
inverted its **meaning** in v3. Both versions render the same default layout,
|
|
335
|
+
so only explicit values moved:
|
|
336
|
+
|
|
337
|
+
| v2 | v3 |
|
|
338
|
+
| ----------------------------- | --------- |
|
|
339
|
+
| `:reverse="false"` | `reverse` |
|
|
340
|
+
| `reverse` / `:reverse="true"` | delete it |
|
|
341
|
+
|
|
342
|
+
That is invisible to every other check — `:reverse="false"` is a declared prop,
|
|
343
|
+
correctly typed, holding its own default value — and it cannot go in the
|
|
344
|
+
rename table above, because the table is keyed by prop _name_: an entry for
|
|
345
|
+
`reverse` would rewrite the legitimate v3 spellings too.
|
|
346
|
+
|
|
347
|
+
So it has its own rule, `bitboss-ui/no-reverse-false` (in `recommended`). It
|
|
348
|
+
flags only a **literal** `:reverse="false"` and offers both corrections as
|
|
349
|
+
editor suggestions — a dynamic `:reverse="isRtl"` that merely evaluates false
|
|
350
|
+
is left alone. For a bulk sweep of a v2 codebase, opt into the fix:
|
|
351
|
+
|
|
352
|
+
```js
|
|
353
|
+
{
|
|
354
|
+
rules: {
|
|
355
|
+
'bitboss-ui/no-reverse-false': ['error', { assumeV2: true }],
|
|
356
|
+
},
|
|
357
|
+
}
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
`assumeV2` is off by default because the two readings produce opposite
|
|
361
|
+
layouts — turn it on only for files you know came from v2, then turn it off.
|
|
362
|
+
|
|
331
363
|
Every real HTML attribute (plus `aria-*` / `data-*`) falls through untouched, so
|
|
332
364
|
attribute inheritance is never flagged. Escape hatches when you do need one:
|
|
333
365
|
|
|
@@ -406,7 +438,7 @@ MIT — see [`LICENSE`](LICENSE).
|
|
|
406
438
|
|
|
407
439
|
## Support
|
|
408
440
|
|
|
409
|
-
- **Usage and APIs:** see the [documentation](https://ui-components
|
|
441
|
+
- **Usage and APIs:** see the [documentation](https://ui-components.bitboss.it/).
|
|
410
442
|
- **Company / licensing / commercial:** [BitBoss](https://www.bitboss.it/).
|
|
411
443
|
|
|
412
444
|
### Reporting a bug
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
| `depsDebounceTime` | `number \| undefined` | `0` | | Debounce delay (ms) applied when reacting to `dependencies` changes. |
|
|
23
23
|
| `direction` | `"horizontal" \| "vertical" \| undefined` | `"horizontal"` | | Direction of the group layout. - `horizontal`: options flow in rows - `vertical`: options stack in a column |
|
|
24
24
|
| `disabled` | `boolean \| undefined` | `false` | | Disables interaction for the whole group. |
|
|
25
|
-
| `enforceCoherence` | `boolean \| undefined` | `false` | | Enforces that `modelValue` contains only values present in `items`. Incoherent values are removed and `update:modelValue` is emitted with a coherent array. Please check out {@link https://ui-components
|
|
25
|
+
| `enforceCoherence` | `boolean \| undefined` | `false` | | Enforces that `modelValue` contains only values present in `items`. Incoherent values are removed and `update:modelValue` is emitted with a coherent array. Please check out {@link https://ui-components.bitboss.it/it/guides/coherence the doc… |
|
|
26
26
|
| `hasErrors` | `boolean \| undefined` | `false` | | Puts the component into an error state adds the error styling class. |
|
|
27
27
|
| `hasWarning` | `boolean \| undefined` | `false` | | Puts the component into a warning state. Errors take priority when both are set. |
|
|
28
28
|
| `hideLabel` | `boolean \| undefined` | `false` | | Visually hides each option's label text (the text rendered next to every input) while keeping it accessible to screen readers. |
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
| `depsDebounceTime` | `number \| undefined` | `0` | | Debounce delay (ms) applied when reacting to `dependencies` changes. |
|
|
23
23
|
| `direction` | `"horizontal" \| "vertical" \| undefined` | `"horizontal"` | | Direction of the group layout. - `horizontal`: options flow in rows - `vertical`: options stack in a column |
|
|
24
24
|
| `disabled` | `boolean \| undefined` | `false` | | Disables interaction for the whole group. |
|
|
25
|
-
| `enforceCoherence` | `boolean \| undefined` | `false` | | Enforces that `modelValue` contains only values present in `items`. Incoherent values are removed and `update:modelValue` is emitted with a coherent array. Please check out {@link https://ui-components
|
|
25
|
+
| `enforceCoherence` | `boolean \| undefined` | `false` | | Enforces that `modelValue` contains only values present in `items`. Incoherent values are removed and `update:modelValue` is emitted with a coherent array. Please check out {@link https://ui-components.bitboss.it/it/guides/coherence the doc… |
|
|
26
26
|
| `hasErrors` | `boolean \| undefined` | `false` | | Puts the component into an error state adds the error styling class. |
|
|
27
27
|
| `hasWarning` | `boolean \| undefined` | `false` | | Puts the component into a warning state. Errors take priority when both are set. |
|
|
28
28
|
| `hideLabel` | `boolean \| undefined` | `false` | | Visually hides each option's label text (the text rendered next to every input) while keeping it accessible to screen readers. |
|
package/dist/ai/BbDialog.md
CHANGED
|
@@ -186,6 +186,65 @@ Use the `title` slot to restyle just the title text — it stays wired to
|
|
|
186
186
|
removes the whole header (the close button then floats over the body corner
|
|
187
187
|
unless `hide-close`), and you own the accessible name.
|
|
188
188
|
|
|
189
|
+
Add `description` for one muted line under the title — the dialog's subtitle,
|
|
190
|
+
and the only thing `aria-describedby` points at:
|
|
191
|
+
|
|
192
|
+
**A described dialog**
|
|
193
|
+
|
|
194
|
+
```vue
|
|
195
|
+
<template>
|
|
196
|
+
<div
|
|
197
|
+
class="flex w-full max-w-sm flex-col gap-3 rounded-[var(--bb-radius)] border p-4"
|
|
198
|
+
>
|
|
199
|
+
<div>
|
|
200
|
+
<p class="m-0 text-sm font-medium">INV-2044</p>
|
|
201
|
+
<p class="m-0 text-xs text-[color:var(--bb-text-muted)]">
|
|
202
|
+
Northwind Traders · €1,280.00 · paid
|
|
203
|
+
</p>
|
|
204
|
+
</div>
|
|
205
|
+
<div>
|
|
206
|
+
<BbButton
|
|
207
|
+
prepend:icon="lucide:trash-2"
|
|
208
|
+
variant="outline"
|
|
209
|
+
@click="open = true"
|
|
210
|
+
>
|
|
211
|
+
Delete invoice
|
|
212
|
+
</BbButton>
|
|
213
|
+
</div>
|
|
214
|
+
</div>
|
|
215
|
+
<BbDialog
|
|
216
|
+
v-model="open"
|
|
217
|
+
description="This permanently removes the invoice and its payment history."
|
|
218
|
+
title="Delete invoice INV-2044"
|
|
219
|
+
>
|
|
220
|
+
<p class="m-0">
|
|
221
|
+
Anything that does not fit in one line belongs here, in the body — which
|
|
222
|
+
is deliberately not what <code>aria-describedby</code> points at.
|
|
223
|
+
</p>
|
|
224
|
+
<template #footer>
|
|
225
|
+
<div class="flex justify-end gap-2">
|
|
226
|
+
<BbButton variant="ghost" @click="open = false">Cancel</BbButton>
|
|
227
|
+
<BbButton variant="destructive" @click="open = false">Delete</BbButton>
|
|
228
|
+
</div>
|
|
229
|
+
</template>
|
|
230
|
+
</BbDialog>
|
|
231
|
+
</template>
|
|
232
|
+
|
|
233
|
+
<script setup lang="ts">
|
|
234
|
+
import { ref } from 'vue';
|
|
235
|
+
import { BbButton, BbDialog } from 'bitboss-ui';
|
|
236
|
+
|
|
237
|
+
const open = ref(false);
|
|
238
|
+
</script>
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
Keep it to a sentence; the detail belongs in the body, which is deliberately
|
|
242
|
+
**not** described (pointing `aria-describedby` at arbitrary markup makes a
|
|
243
|
+
screen reader read a whole form as the dialog's description). Use the
|
|
244
|
+
`description` slot when the line needs markup — it receives the prop as `text`.
|
|
245
|
+
A dialog with no `description` keeps its original single-row header, so nothing
|
|
246
|
+
shifts unless you opt in.
|
|
247
|
+
|
|
189
248
|
Prefer `title` (or the `title` slot) for the standard header. The `header` slot
|
|
190
249
|
replaces the entire header on both surfaces — you own the close control and must
|
|
191
250
|
wire `titleId` for `aria-labelledby`. Give your root element `flex-1` so it fills
|
|
@@ -762,6 +821,8 @@ default falls back to `config.adaptive`.
|
|
|
762
821
|
- The dialog is a true modal (`showModal()`): the browser contains focus within
|
|
763
822
|
it, the page behind is inert, and focus returns to the trigger when it
|
|
764
823
|
closes. `focus-target` only chooses where focus **starts**.
|
|
824
|
+
- `description` is what `aria-describedby` points at, so the dialog announces
|
|
825
|
+
its purpose and not just its name. Nothing else is described — see above.
|
|
765
826
|
- The header close button carries a localized `aria-label` out of the box
|
|
766
827
|
(`config.locale`).
|
|
767
828
|
- Don't lean on `persistent` to trap users. Keep a visible way out (a Cancel or
|
|
@@ -776,6 +837,7 @@ default falls back to `config.adaptive`.
|
|
|
776
837
|
| Prop | Type | Default | Required | Description |
|
|
777
838
|
| --- | --- | --- | --- | --- |
|
|
778
839
|
| `adaptive` | `boolean \| undefined` | ``config.adaptive` (`true`)` | | Adapt the surface to the viewport: render as a `BbOffCanvas` drawer on mobile instead of a centered dialog. The surface is resolved when the dialog opens and stays fixed for that session: resizing across the mobile breakpoint while open nev… |
|
|
840
|
+
| `description` | `string \| undefined` | | | One short line under the title, in the header — the shadcn `DialogDescription` shape: same block as the title, lower hierarchy, muted. It is also what `aria-describedby` points at. That wiring was dropped in v3 along with the old `descripti… |
|
|
779
841
|
| `disabled` | `boolean \| undefined` | `false` | | Disable EVERY user-initiated dismissal: backdrop click, Escape AND the header close (×) button (denied attempts play the deny nudge). Use it while an operation is in flight (e.g. a save) so the dialog cannot be dismissed mid-work. Compare `… |
|
|
780
842
|
| `eager` | `boolean \| undefined` | `false` | | Render dialog content immediately instead of waiting for the first open. |
|
|
781
843
|
| `focusTarget` | `string \| undefined` | | | CSS selector of the element to focus after opening. Defaults to the first tabbable element. |
|
|
@@ -800,6 +862,7 @@ default falls back to `config.adaptive`.
|
|
|
800
862
|
## Slots
|
|
801
863
|
|
|
802
864
|
- `default` — scope: `BbDialogDefaultSlotProps` — Primary body content of the dialog, rendered in the scrollable body area.
|
|
865
|
+
- `description` — scope: `BbDialogDescriptionSlotProps` — Replaces the description text under the title. Renders the header even when `title` and `description` are unset — a slotted description is a description, the same rule `#title` follows.
|
|
803
866
|
- `footer` — scope: `object` — Content rendered in the dialog footer, below the body area. Typically used for action buttons.
|
|
804
867
|
- `header` — scope: `BbDialogHeaderSlotProps` — Replaces the entire dialog header section (title + close button) on both surfaces — the desktop `<dialog>` and the mobile off-canvas. Because it replaces the default close (✕), the slot owns closing: render your own control wired to the `cl…
|
|
805
868
|
- `title` — scope: `BbDialogTitleSlotProps` — Replaces the default title text inside the header. Remains linked to the dialog through `aria-labelledby`. Providing this slot renders the header even when `title` is unset — a slotted title is a title.
|
package/dist/ai/BbOffCanvas.md
CHANGED
|
@@ -161,6 +161,11 @@ header and footer stay pinned.
|
|
|
161
161
|
|
|
162
162
|
- Use the `title` slot to restyle just the title text — it stays wired to
|
|
163
163
|
`aria-labelledby` and receives the `title` prop as `text`.
|
|
164
|
+
- **`description`** adds one muted line under the title — the panel's subtitle,
|
|
165
|
+
and the only thing `aria-describedby` points at. Keep it to a sentence; the
|
|
166
|
+
body is deliberately not described. The `description` slot takes markup and
|
|
167
|
+
receives the prop as `text`. A panel without one keeps its original
|
|
168
|
+
single-row header.
|
|
164
169
|
- The **`header` slot** replaces the whole header section; it receives
|
|
165
170
|
`titleId`, `title` and `close`, so you can build a custom header and still
|
|
166
171
|
keep the accessible name wired through `titleId`. `BbDialog` supports the
|
|
@@ -169,6 +174,55 @@ header and footer stay pinned.
|
|
|
169
174
|
- Omitting `title` (and the `header` slot) removes the header entirely — you
|
|
170
175
|
then own the accessible name.
|
|
171
176
|
|
|
177
|
+
**A described panel (via the #description slot)**
|
|
178
|
+
|
|
179
|
+
```vue
|
|
180
|
+
<template>
|
|
181
|
+
<BbButton
|
|
182
|
+
prepend:icon="lucide:user-plus"
|
|
183
|
+
variant="outline"
|
|
184
|
+
@click="open = true"
|
|
185
|
+
>
|
|
186
|
+
Invite teammate
|
|
187
|
+
</BbButton>
|
|
188
|
+
<BbOffCanvas v-model="open" side="right" title="Invite teammate">
|
|
189
|
+
<!-- The slot takes markup where the prop would only take a string. -->
|
|
190
|
+
<template #description>
|
|
191
|
+
They join the <strong>Northwind</strong> workspace as a viewer.
|
|
192
|
+
</template>
|
|
193
|
+
<div class="grid gap-3">
|
|
194
|
+
<BbTextInput
|
|
195
|
+
v-model="email"
|
|
196
|
+
compact
|
|
197
|
+
label="Email"
|
|
198
|
+
placeholder="ada@northwind.co"
|
|
199
|
+
type="email"
|
|
200
|
+
/>
|
|
201
|
+
</div>
|
|
202
|
+
<template #footer>
|
|
203
|
+
<div class="flex justify-end gap-2">
|
|
204
|
+
<BbButton variant="ghost" @click="open = false">Cancel</BbButton>
|
|
205
|
+
<BbButton
|
|
206
|
+
:disabled="!email.trim()"
|
|
207
|
+
variant="primary"
|
|
208
|
+
@click="open = false"
|
|
209
|
+
>
|
|
210
|
+
Send invite
|
|
211
|
+
</BbButton>
|
|
212
|
+
</div>
|
|
213
|
+
</template>
|
|
214
|
+
</BbOffCanvas>
|
|
215
|
+
</template>
|
|
216
|
+
|
|
217
|
+
<script setup lang="ts">
|
|
218
|
+
import { ref } from 'vue';
|
|
219
|
+
import { BbButton, BbOffCanvas, BbTextInput } from 'bitboss-ui';
|
|
220
|
+
|
|
221
|
+
const open = ref(false);
|
|
222
|
+
const email = ref('');
|
|
223
|
+
</script>
|
|
224
|
+
```
|
|
225
|
+
|
|
172
226
|
### A filters drawer
|
|
173
227
|
|
|
174
228
|
The archetypal off-canvas: search + toggles in the `default` slot, Apply/Reset
|
|
@@ -913,6 +967,8 @@ The panel is a native `<dialog>` opened with `showModal()` — the same mechanic
|
|
|
913
967
|
- The panel is a true modal (`showModal()`): focus is contained within it, the
|
|
914
968
|
page behind is inert, and focus returns to the trigger when it closes.
|
|
915
969
|
`focus-target` only chooses where focus **starts**.
|
|
970
|
+
- `description` is what `aria-describedby` points at, so the panel announces
|
|
971
|
+
its purpose and not just its name.
|
|
916
972
|
- The header close button carries a localized `aria-label` out of the box
|
|
917
973
|
(`config.locale`).
|
|
918
974
|
- Draggable dismissal is a convenience, not the only way out — the close button,
|
|
@@ -929,6 +985,7 @@ The panel is a native `<dialog>` opened with `showModal()` — the same mechanic
|
|
|
929
985
|
|
|
930
986
|
| Prop | Type | Default | Required | Description |
|
|
931
987
|
| --- | --- | --- | --- | --- |
|
|
988
|
+
| `description` | `string \| undefined` | | | One short line under the title, in the header — the shadcn `DialogDescription` shape: same block as the title, lower hierarchy, muted. It is also what `aria-describedby` points at. That wiring was dropped in v3 along with the old `descripti… |
|
|
932
989
|
| `disabled` | `boolean \| undefined` | `false` | | Disable EVERY user-initiated dismissal: backdrop click, Escape, drag-to-dismiss AND the header close (×) button (denied attempts play the deny nudge). Use it while an operation is in flight (e.g. a save) so the drawer cannot be dismissed mi… |
|
|
933
990
|
| `draggable` | `boolean \| undefined` | `false` | | Enable drag-to-dismiss. The panel can be dragged from anywhere toward its edge to close, and a grab handle is shown on the inner edge as the affordance. When `false`, the panel is static (dismiss via the close button, backdrop, or Escape on… |
|
|
934
991
|
| `eager` | `boolean \| undefined` | `false` | | Render offcanvas content immediately instead of waiting for the first open. |
|
|
@@ -955,6 +1012,7 @@ The panel is a native `<dialog>` opened with `showModal()` — the same mechanic
|
|
|
955
1012
|
## Slots
|
|
956
1013
|
|
|
957
1014
|
- `default` — scope: `{ close: () => void; }` — Primary body content of the off-canvas panel, rendered in the scrollable body area.
|
|
1015
|
+
- `description` — scope: `BbOffCanvasDescriptionSlotProps` — Replaces the description text under the title. Renders the header even when `title` and `description` are unset — a slotted description is a description, the same rule `#title` follows.
|
|
958
1016
|
- `footer` — scope: `object` — Content rendered in the panel footer, below the body area. Typically used for action buttons.
|
|
959
1017
|
- `header` — scope: `BbOffCanvasHeaderSlotProps` — Replaces the entire off-canvas header section (title + close button). Maintains accessibility wiring via the provided props.
|
|
960
1018
|
- `title` — scope: `BbOffCanvasTitleSlotProps` — Replaces the default title text inside the header. Remains linked to the panel through `aria-labelledby`. Providing this slot renders the header even when `title` is unset — a slotted title is a title.
|
package/dist/ai/BbSelect.md
CHANGED
|
@@ -613,8 +613,10 @@ later responses don't include them — no need to merge them into every response
|
|
|
613
613
|
`prefill` controls **when the first load happens**:
|
|
614
614
|
|
|
615
615
|
- `'interaction'` (default) — on the first open.
|
|
616
|
-
- `true` — immediately on mount, and during SSR
|
|
617
|
-
|
|
616
|
+
- `true` — immediately on mount, and during SSR **on hosts that can carry the
|
|
617
|
+
result to the client** (Nuxt does; see
|
|
618
|
+
[SSR prefill](./guides/ssr-prefill.md)), so the panel is warm on hydration.
|
|
619
|
+
Everywhere else the load happens on the client, right after mount.
|
|
618
620
|
- `false` — **search-first**: nothing loads until the user types. Opening is not
|
|
619
621
|
a search, so the panel opens empty and shows a _"search to begin"_ hint until
|
|
620
622
|
the first query. Use it when the result set is too big or too costly to browse
|
|
@@ -1337,9 +1339,13 @@ From the vite/nuxt plugin options:
|
|
|
1337
1339
|
|
|
1338
1340
|
Platform notes:
|
|
1339
1341
|
|
|
1340
|
-
- **SSR / Nuxt**: `prefill: true` providers
|
|
1341
|
-
|
|
1342
|
-
|
|
1342
|
+
- **SSR / Nuxt**: under `bitboss-ui/nuxt`, `prefill: true` providers run in
|
|
1343
|
+
`onServerPrefetch` AND their result travels in the Nuxt payload, so the client
|
|
1344
|
+
hydrates with the options already in hand and never re-requests them. Under any
|
|
1345
|
+
other SSR host the provider does **not** run on the server at all — the server
|
|
1346
|
+
emits the placeholder and the client loads on mount, which keeps hydration
|
|
1347
|
+
clean. Keep providers isomorphic (no `window` access) and have them return
|
|
1348
|
+
plain, serializable rows. See [SSR prefill](./guides/ssr-prefill.md).
|
|
1343
1349
|
- **Plain HTML forms / Inertia form posts**: give the select a `name` — hidden
|
|
1344
1350
|
inputs carry the values (JSON-stringified when not strings), and `required`
|
|
1345
1351
|
participates in native validation.
|
|
@@ -398,8 +398,9 @@ const destinationLabel = computed(
|
|
|
398
398
|
### Laziness, prefill and the trigger label
|
|
399
399
|
|
|
400
400
|
`prefill` controls **when the first load happens**: `'interaction'` (default) on
|
|
401
|
-
first open, `true` immediately on mount (and during SSR via `onServerPrefetch
|
|
402
|
-
|
|
401
|
+
first open, `true` immediately on mount (and during SSR via `onServerPrefetch`,
|
|
402
|
+
but only on a host that can transfer the result — see
|
|
403
|
+
[SSR prefill](./guides/ssr-prefill.md)), `false` **search-first** — nothing is fetched until the user types a query.
|
|
403
404
|
Opening the panel is not a search, so it loads nothing; until the first query the
|
|
404
405
|
list shows a _"search to begin"_ hint instead of "no data".
|
|
405
406
|
|
|
@@ -1199,9 +1200,13 @@ floating popover everywhere.
|
|
|
1199
1200
|
- **Global config** — `config.adaptive` (default for `adaptive`),
|
|
1200
1201
|
`config.mobileMaxWidth` (the mobile threshold), `config.locale` (the search
|
|
1201
1202
|
field's default accessible name and panel string defaults).
|
|
1202
|
-
- **SSR / Nuxt** — `prefill: true` providers
|
|
1203
|
-
|
|
1204
|
-
|
|
1203
|
+
- **SSR / Nuxt** — under `bitboss-ui/nuxt`, `prefill: true` providers run in
|
|
1204
|
+
`onServerPrefetch` and their result rides the Nuxt payload, so the client
|
|
1205
|
+
hydrates with options already loaded and does not fetch again. On other SSR
|
|
1206
|
+
hosts the provider stays client-side and the server renders the placeholder —
|
|
1207
|
+
deliberately, since server markup the client cannot rebuild is a hydration
|
|
1208
|
+
mismatch. Keep providers isomorphic (no `window` access) and returning plain
|
|
1209
|
+
rows. See [SSR prefill](./guides/ssr-prefill.md).
|
|
1205
1210
|
|
|
1206
1211
|
### Works well with
|
|
1207
1212
|
|
package/dist/ai/BbSwitch.md
CHANGED
|
@@ -386,6 +386,18 @@ const usageAnalytics = ref(true);
|
|
|
386
386
|
name="captions"
|
|
387
387
|
reverse
|
|
388
388
|
/>
|
|
389
|
+
<!-- A described row keeps the same trailing edge: `input-position`
|
|
390
|
+
applies on the description path too, and the switch pins to the
|
|
391
|
+
label's FIRST line rather than the centre of the two-line block. -->
|
|
392
|
+
<BbSwitch
|
|
393
|
+
v-model="downloads"
|
|
394
|
+
description="Uses storage on this device, and only over Wi-Fi."
|
|
395
|
+
direction="xxxxxx xx"
|
|
396
|
+
input-position="right"
|
|
397
|
+
label="Download for offline"
|
|
398
|
+
name="downloads"
|
|
399
|
+
reverse
|
|
400
|
+
/>
|
|
389
401
|
</div>
|
|
390
402
|
</template>
|
|
391
403
|
<script setup lang="ts">
|
|
@@ -394,6 +406,7 @@ import { BbSwitch } from 'bitboss-ui';
|
|
|
394
406
|
|
|
395
407
|
const autoplay = ref(true);
|
|
396
408
|
const captions = ref(false);
|
|
409
|
+
const downloads = ref(true);
|
|
397
410
|
</script>
|
|
398
411
|
```
|
|
399
412
|
|
package/dist/ai/BbTable.md
CHANGED
|
@@ -2754,10 +2754,13 @@ reader.
|
|
|
2754
2754
|
plugin is still on the default locale, which is `it` — set the plugin's
|
|
2755
2755
|
`locale` option, or override per table with `actions-text` (it is visually
|
|
2756
2756
|
hidden in the header but read by screen readers).
|
|
2757
|
-
- **SSR / Nuxt.**
|
|
2758
|
-
`onServerPrefetch
|
|
2759
|
-
|
|
2760
|
-
|
|
2757
|
+
- **SSR / Nuxt.** Under `bitboss-ui/nuxt` a provider `items` function
|
|
2758
|
+
participates in `onServerPrefetch` and its rows travel in the Nuxt payload, so
|
|
2759
|
+
the first page renders server-side and hydrates without re-fetching. On other
|
|
2760
|
+
SSR hosts the provider runs on the client only and the server renders the
|
|
2761
|
+
empty table — see [SSR prefill](./guides/ssr-prefill.md). The table context
|
|
2762
|
+
(and thus `table-id` pagination wiring) is client-side only — hydration-time
|
|
2763
|
+
onward.
|
|
2761
2764
|
- **Forms.** With `name`, the selection submits as hidden inputs — no JS
|
|
2762
2765
|
needed between the table and a plain `<form>` POST (Inertia included).
|
|
2763
2766
|
|
package/dist/ai/changelog.json
CHANGED
package/dist/ai/components.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 1,
|
|
3
3
|
"library": "bitboss-ui",
|
|
4
|
-
"version": "3.0.0-beta.
|
|
5
|
-
"generatedAt": "2026-
|
|
4
|
+
"version": "3.0.0-beta.19",
|
|
5
|
+
"generatedAt": "2026-09-01T10:39:24.755Z",
|
|
6
6
|
"composables": [
|
|
7
7
|
{
|
|
8
8
|
"name": "useBbConfig",
|
|
@@ -1233,7 +1233,7 @@
|
|
|
1233
1233
|
"type": "boolean | undefined",
|
|
1234
1234
|
"required": false,
|
|
1235
1235
|
"default": "false",
|
|
1236
|
-
"description": "Enforces that `modelValue` contains only values present in `items`.\nIncoherent values are removed and `update:modelValue` is emitted with a\ncoherent array. Please check out {@link https://ui-components
|
|
1236
|
+
"description": "Enforces that `modelValue` contains only values present in `items`.\nIncoherent values are removed and `update:modelValue` is emitted with a\ncoherent array. Please check out {@link https://ui-components.bitboss.it/it/guides/coherence the docs} for more information."
|
|
1237
1237
|
},
|
|
1238
1238
|
{
|
|
1239
1239
|
"name": "hasErrors",
|
|
@@ -4140,7 +4140,7 @@
|
|
|
4140
4140
|
"type": "boolean | undefined",
|
|
4141
4141
|
"required": false,
|
|
4142
4142
|
"default": "false",
|
|
4143
|
-
"description": "Enforces that `modelValue` contains only values present in `items`.\nIncoherent values are removed and `update:modelValue` is emitted with a\ncoherent array. Please check out {@link https://ui-components
|
|
4143
|
+
"description": "Enforces that `modelValue` contains only values present in `items`.\nIncoherent values are removed and `update:modelValue` is emitted with a\ncoherent array. Please check out {@link https://ui-components.bitboss.it/it/guides/coherence the docs} for more information."
|
|
4144
4144
|
},
|
|
4145
4145
|
{
|
|
4146
4146
|
"name": "hasErrors",
|
|
@@ -8043,6 +8043,12 @@
|
|
|
8043
8043
|
"default": "`config.adaptive` (`true`)",
|
|
8044
8044
|
"description": "Adapt the surface to the viewport: render as a `BbOffCanvas` drawer on\nmobile instead of a centered dialog. The surface is resolved when the\ndialog opens and stays fixed for that session: resizing across the mobile\nbreakpoint while open never swaps it.\n\nWhen unset, falls back to the global `config.adaptive`."
|
|
8045
8045
|
},
|
|
8046
|
+
{
|
|
8047
|
+
"name": "description",
|
|
8048
|
+
"type": "string | undefined",
|
|
8049
|
+
"required": false,
|
|
8050
|
+
"description": "One short line under the title, in the header — the shadcn\n`DialogDescription` shape: same block as the title, lower hierarchy,\nmuted.\n\nIt is also what `aria-describedby` points at. That wiring was dropped in\nv3 along with the old `description` prop, on the reasoning that pointing\nit at arbitrary body content would read whole forms aloud — true, and the\nreason it aims at THIS element only. Keep it to a sentence; anything\nlonger belongs in the body."
|
|
8051
|
+
},
|
|
8046
8052
|
{
|
|
8047
8053
|
"name": "disabled",
|
|
8048
8054
|
"type": "boolean | undefined",
|
|
@@ -8151,6 +8157,11 @@
|
|
|
8151
8157
|
"type": "BbDialogDefaultSlotProps",
|
|
8152
8158
|
"description": "Primary body content of the dialog, rendered in the scrollable body area."
|
|
8153
8159
|
},
|
|
8160
|
+
{
|
|
8161
|
+
"name": "description",
|
|
8162
|
+
"type": "BbDialogDescriptionSlotProps",
|
|
8163
|
+
"description": "Replaces the description text under the title. Renders the header even\nwhen `title` and `description` are unset — a slotted description is a\ndescription, the same rule `#title` follows."
|
|
8164
|
+
},
|
|
8154
8165
|
{
|
|
8155
8166
|
"name": "footer",
|
|
8156
8167
|
"type": "object",
|
|
@@ -8195,16 +8206,6 @@
|
|
|
8195
8206
|
"kind": "manual"
|
|
8196
8207
|
}
|
|
8197
8208
|
},
|
|
8198
|
-
{
|
|
8199
|
-
"name": "description",
|
|
8200
|
-
"new": null,
|
|
8201
|
-
"since": "3.0.0-unreleased",
|
|
8202
|
-
"migration": "ai/guides/migration/components/bb-dialog.md",
|
|
8203
|
-
"silent": true,
|
|
8204
|
-
"fix": {
|
|
8205
|
-
"kind": "manual"
|
|
8206
|
-
}
|
|
8207
|
-
},
|
|
8208
8209
|
{
|
|
8209
8210
|
"name": "hideHeader",
|
|
8210
8211
|
"new": null,
|
|
@@ -9437,6 +9438,12 @@
|
|
|
9437
9438
|
"contract": "ai/BbOffCanvas.md",
|
|
9438
9439
|
"source": "ai/source/BbOffCanvas.md",
|
|
9439
9440
|
"props": [
|
|
9441
|
+
{
|
|
9442
|
+
"name": "description",
|
|
9443
|
+
"type": "string | undefined",
|
|
9444
|
+
"required": false,
|
|
9445
|
+
"description": "One short line under the title, in the header — the shadcn\n`DialogDescription` shape: same block as the title, lower hierarchy,\nmuted.\n\nIt is also what `aria-describedby` points at. That wiring was dropped in\nv3 along with the old `description` prop, on the reasoning that pointing\nit at arbitrary body content would read whole forms aloud — true, and the\nreason it aims at THIS element only. Keep it to a sentence; anything\nlonger belongs in the body."
|
|
9446
|
+
},
|
|
9440
9447
|
{
|
|
9441
9448
|
"name": "disabled",
|
|
9442
9449
|
"type": "boolean | undefined",
|
|
@@ -9560,6 +9567,11 @@
|
|
|
9560
9567
|
"type": "{ close: () => void; }",
|
|
9561
9568
|
"description": "Primary body content of the off-canvas panel, rendered in the scrollable body area."
|
|
9562
9569
|
},
|
|
9570
|
+
{
|
|
9571
|
+
"name": "description",
|
|
9572
|
+
"type": "BbOffCanvasDescriptionSlotProps",
|
|
9573
|
+
"description": "Replaces the description text under the title. Renders the header even\nwhen `title` and `description` are unset — a slotted description is a\ndescription, the same rule `#title` follows."
|
|
9574
|
+
},
|
|
9563
9575
|
{
|
|
9564
9576
|
"name": "footer",
|
|
9565
9577
|
"type": "object",
|
|
@@ -9594,16 +9606,6 @@
|
|
|
9594
9606
|
"kind": "manual"
|
|
9595
9607
|
}
|
|
9596
9608
|
},
|
|
9597
|
-
{
|
|
9598
|
-
"name": "description",
|
|
9599
|
-
"new": null,
|
|
9600
|
-
"since": "3.0.0-unreleased",
|
|
9601
|
-
"migration": "ai/guides/migration/components/bb-offcanvas.md",
|
|
9602
|
-
"silent": true,
|
|
9603
|
-
"fix": {
|
|
9604
|
-
"kind": "manual"
|
|
9605
|
-
}
|
|
9606
|
-
},
|
|
9607
9609
|
{
|
|
9608
9610
|
"name": "direction",
|
|
9609
9611
|
"new": "side",
|
|
@@ -53,12 +53,53 @@ That is the route to prefer. It is right before hydration, so it is what
|
|
|
53
53
|
crawlers index, what a prerendered search index reads, and what a reader with
|
|
54
54
|
JS disabled keeps.
|
|
55
55
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
56
|
+
#### Nuxt
|
|
57
|
+
|
|
58
|
+
**Do not call `app.use(bitbossUiPlugin)` in Nuxt** — the `bitboss-ui/nuxt`
|
|
59
|
+
module registers the runtime plugin for you, and that plugin provides the
|
|
60
|
+
per-app config itself. `defineNuxtPlugin` runs per request on the server and
|
|
61
|
+
Nuxt builds one Vue app per request, so your own plugin is the per-request
|
|
62
|
+
seam:
|
|
63
|
+
|
|
64
|
+
```ts
|
|
65
|
+
// plugins/bitboss-locale.ts
|
|
66
|
+
import { useBbConfig } from 'bitboss-ui';
|
|
67
|
+
|
|
68
|
+
export default defineNuxtPlugin((nuxtApp) => {
|
|
69
|
+
const locale = localeFor(useRequestEvent());
|
|
70
|
+
// A plugin has an APP but no component instance, so hand it the app's
|
|
71
|
+
// injection context — otherwise the write cannot find this app's config
|
|
72
|
+
// and lands on the process-global defaults.
|
|
73
|
+
nuxtApp.vueApp.runWithContext(() => {
|
|
74
|
+
useBbConfig().setConfig({ locale });
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Calling `setConfig` from a component's `setup` works in Nuxt too, and is
|
|
80
|
+
per-request for the same reason. `runWithContext` is only needed where no
|
|
81
|
+
component exists yet.
|
|
82
|
+
|
|
83
|
+
> Fixed in 3.0.0-beta.19 (Q20.4). Before that the Nuxt runtime plugin never
|
|
84
|
+
> provided the config, so **every** `setConfig` under Nuxt — including from a
|
|
85
|
+
> component's `setup`, the path this page prescribed — wrote the process-global
|
|
86
|
+
> and leaked across concurrent visitors, silently. If you worked around it,
|
|
87
|
+
> you can stop.
|
|
88
|
+
|
|
89
|
+
#### The rule, and what the dev warning means
|
|
90
|
+
|
|
91
|
+
**`setConfig` during a server render needs an app to address.** From a
|
|
92
|
+
component's `setup` (or a composable a component calls), or inside
|
|
93
|
+
`app.runWithContext`, it resolves the current app and the write is
|
|
94
|
+
per-visitor. With neither — module scope, say — there is no app, the write
|
|
95
|
+
lands on the process-global build-time defaults, and it leaks into other
|
|
96
|
+
visitors being served concurrently.
|
|
97
|
+
|
|
98
|
+
The dev warning fires on exactly that: it compares where the write actually
|
|
99
|
+
landed against the build-time object, rather than guessing from the call site.
|
|
100
|
+
So it stays silent for a correct per-app write, and it still fires for a
|
|
101
|
+
global one made from inside a component — which is what a missing plugin (or,
|
|
102
|
+
before beta.19, Nuxt) produced.
|
|
62
103
|
|
|
63
104
|
On the client none of this matters: one process is one user, and `setConfig`
|
|
64
105
|
from anywhere is fine.
|
|
@@ -14,13 +14,18 @@ Knowledge base root (installed package):
|
|
|
14
14
|
Package export entry: `bitboss-ui/ai` → `dist/ai/index.md`.
|
|
15
15
|
Subpaths: `bitboss-ui/ai/components.json`, `bitboss-ui/ai/guides/…`, etc.
|
|
16
16
|
|
|
17
|
-
**Not installed, or can only fetch URLs?** The same files are served
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
[
|
|
17
|
+
**Not installed, or can only fetch URLs?** The same files are served at
|
|
18
|
+
`https://llms-bitboss-ui.bitboss.it/dist/ai/…`. If you can make only one
|
|
19
|
+
request, fetch
|
|
20
|
+
[`/dist/llms-medium.txt`](https://llms-bitboss-ui.bitboss.it/dist/llms-medium.txt)
|
|
21
21
|
— this router plus the agent contract, setup, component picker, design language
|
|
22
22
|
and the full component catalogue, in ~110 KB.
|
|
23
23
|
|
|
24
|
+
That host is a thin proxy in front of the published npm tarball. If it is ever
|
|
25
|
+
unreachable, the same paths work directly against
|
|
26
|
+
`https://cdn.jsdelivr.net/npm/bitboss-ui@beta/…` — one hop further from us, and
|
|
27
|
+
pinned to the prerelease channel rather than following it.
|
|
28
|
+
|
|
24
29
|
---
|
|
25
30
|
|
|
26
31
|
## Mandatory order (every UI task)
|
|
@@ -58,7 +58,7 @@ The corollary: **`prefill` cannot tell you an initial load from a dependency ref
|
|
|
58
58
|
|
|
59
59
|
### The `prefill` prop (`BbSelect` / `BbSelectPopover`)
|
|
60
60
|
|
|
61
|
-
`prefill` controls **when** the initial load happens: `'interaction'` (default) waits for the first user interaction, `true` loads on mount (SSR-friendly — it also runs in `onServerPrefetch`), `false` is **search-first** — nothing loads until the user types, so opening the panel fetches nothing and the list shows a "search to begin" hint until the first query. Groups and tables always load on mount.
|
|
61
|
+
`prefill` controls **when** the initial load happens: `'interaction'` (default) waits for the first user interaction, `true` loads on mount (SSR-friendly — under `bitboss-ui/nuxt` it also runs in `onServerPrefetch` and the result is transferred to the client; see [SSR prefill](./ssr-prefill.md)), `false` is **search-first** — nothing loads until the user types, so opening the panel fetches nothing and the list shows a "search to begin" hint until the first query. Groups and tables always load on mount.
|
|
62
62
|
|
|
63
63
|
Reach for `false` when the result set is too large or expensive to browse and the query is the only sensible entry point. Note that `false` and `'interaction'` differ **only** on this point: both skip the mount load, but `'interaction'` fetches on open and `false` waits for a query.
|
|
64
64
|
|