bitboss-ui 3.0.0-beta.57 → 3.0.0-beta.59
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-mcp.mjs +118 -31
- package/bin/bitboss-ui.mjs +43 -9
- package/dist/ai/BbBadgeButton.md +3 -3
- package/dist/ai/BbBaseButton.md +3 -3
- package/dist/ai/BbCheckbox.md +6 -6
- package/dist/ai/BbCheckboxGroup.md +6 -6
- package/dist/ai/BbColorInput.md +8 -8
- package/dist/ai/BbDatePickerInput.md +8 -8
- package/dist/ai/BbDialog.md +177 -26
- package/dist/ai/BbDropdown.md +2 -2
- package/dist/ai/BbDropdownButton.md +148 -98
- package/dist/ai/BbDropzone.md +5 -5
- package/dist/ai/BbForm.md +82 -11
- package/dist/ai/BbNumberInput.md +8 -8
- package/dist/ai/BbOffCanvas.md +33 -15
- package/dist/ai/BbRadio.md +4 -4
- package/dist/ai/BbRadioGroup.md +6 -6
- package/dist/ai/BbRating.md +7 -7
- package/dist/ai/BbSelect.md +104 -24
- package/dist/ai/BbSelectPopover.md +6 -6
- package/dist/ai/BbSlider.md +6 -6
- package/dist/ai/BbSwitch.md +6 -6
- package/dist/ai/BbSwitchGroup.md +6 -6
- package/dist/ai/BbTable.md +43 -31
- package/dist/ai/BbTag.md +8 -8
- package/dist/ai/BbTextInput.md +8 -8
- package/dist/ai/BbTextarea.md +8 -8
- package/dist/ai/BbTimePickerInput.md +6 -6
- package/dist/ai/BbTree.md +1 -1
- package/dist/ai/CommonField.md +5 -5
- package/dist/ai/CommonFieldInput.md +1 -1
- package/dist/ai/FlatListBox.md +1 -0
- package/dist/ai/GroupedListBox.md +1 -0
- package/dist/ai/ListBox.md +1 -0
- package/dist/ai/changelog.json +2052 -5
- package/dist/ai/components.json +88 -85
- package/dist/ai/composables/useBbDialogContext.md +26 -19
- package/dist/ai/composables/useBbFormContext.md +8 -10
- package/dist/ai/composables/useBbOffCanvasContext.md +4 -2
- package/dist/ai/guides/agent-contract.md +1 -1
- package/dist/ai/guides/ai-router.md +2 -1
- package/dist/ai/guides/coherence-playbook.md +3 -2
- package/dist/ai/guides/eslint-rules.md +2 -2
- package/dist/ai/guides/fetch-items-playbook.md +3 -2
- package/dist/ai/guides/icons-policy.md +6 -7
- package/dist/ai/guides/migration/components/bb-dropdown-button.md +32 -9
- package/dist/ai/guides/migration/components/bb-select.md +1 -1
- package/dist/ai/guides/migration/v2-to-v3.md +59 -3
- package/dist/ai/guides/migration/v3-beta-tooling.md +36 -9
- package/dist/ai/helpers/inertia/manifest.json +1 -1
- package/dist/ai/index.md +2 -2
- package/dist/ai/manifest/common.json +119 -0
- package/dist/ai/manifest/components/BbAccordion.json +9 -10
- package/dist/ai/manifest/components/BbAlert.json +14 -15
- package/dist/ai/manifest/components/BbAsterisk.json +1 -2
- package/dist/ai/manifest/components/BbAvatar.json +8 -9
- package/dist/ai/manifest/components/BbBadge.json +10 -11
- package/dist/ai/manifest/components/BbBadgeButton.json +41 -42
- package/dist/ai/manifest/components/BbBaseButton.json +43 -44
- package/dist/ai/manifest/components/BbBaseCheckboxIcon.json +9 -10
- package/dist/ai/manifest/components/BbBaseRadioIcon.json +8 -9
- package/dist/ai/manifest/components/BbBaseSwitchIcon.json +9 -10
- package/dist/ai/manifest/components/BbBreadcrumbs.json +10 -11
- package/dist/ai/manifest/components/BbButton.json +52 -53
- package/dist/ai/manifest/components/BbCalendar.json +29 -30
- package/dist/ai/manifest/components/BbCheckbox.json +42 -43
- package/dist/ai/manifest/components/BbCheckboxGroup.json +61 -62
- package/dist/ai/manifest/components/BbCollapsible.json +6 -7
- package/dist/ai/manifest/components/BbColorInput.json +67 -68
- package/dist/ai/manifest/components/BbColorPalette.json +22 -23
- package/dist/ai/manifest/components/BbConfirm.json +1 -2
- package/dist/ai/manifest/components/BbDatePicker.json +42 -43
- package/dist/ai/manifest/components/BbDatePickerInput.json +74 -75
- package/dist/ai/manifest/components/BbDialog.json +32 -32
- package/dist/ai/manifest/components/BbDropdown.json +33 -34
- package/dist/ai/manifest/components/BbDropdownButton.json +72 -33
- package/dist/ai/manifest/components/BbDropdownGroup.json +4 -4
- package/dist/ai/manifest/components/BbDropzone.json +21 -22
- package/dist/ai/manifest/components/BbForm.json +10 -9
- package/dist/ai/manifest/components/BbHoverCard.json +16 -17
- package/dist/ai/manifest/components/BbIcon.json +4 -5
- package/dist/ai/manifest/components/BbIndicator.json +8 -9
- package/dist/ai/manifest/components/BbNumberInput.json +66 -67
- package/dist/ai/manifest/components/BbOffCanvas.json +32 -32
- package/dist/ai/manifest/components/BbPagination.json +14 -15
- package/dist/ai/manifest/components/BbPopover.json +21 -22
- package/dist/ai/manifest/components/BbProgress.json +6 -7
- package/dist/ai/manifest/components/BbPtScope.json +1 -1
- package/dist/ai/manifest/components/BbRadio.json +37 -38
- package/dist/ai/manifest/components/BbRadioGroup.json +62 -63
- package/dist/ai/manifest/components/BbRating.json +40 -41
- package/dist/ai/manifest/components/BbSelect.json +79 -78
- package/dist/ai/manifest/components/BbSelectPopover.json +51 -52
- package/dist/ai/manifest/components/BbSelectPopover.tree.json +4 -0
- package/dist/ai/manifest/components/BbSlider.json +40 -41
- package/dist/ai/manifest/components/BbSmoothHeight.json +7 -8
- package/dist/ai/manifest/components/BbSpinner.json +3 -4
- package/dist/ai/manifest/components/BbSwitch.json +42 -43
- package/dist/ai/manifest/components/BbSwitchGroup.json +62 -63
- package/dist/ai/manifest/components/BbTable.json +68 -69
- package/dist/ai/manifest/components/BbTabs.json +27 -28
- package/dist/ai/manifest/components/BbTabsList.json +2 -3
- package/dist/ai/manifest/components/BbTabsPanels.json +1 -2
- package/dist/ai/manifest/components/BbTabsRoot.json +26 -26
- package/dist/ai/manifest/components/BbTag.json +48 -49
- package/dist/ai/manifest/components/BbTextInput.json +64 -65
- package/dist/ai/manifest/components/BbTextarea.json +59 -60
- package/dist/ai/manifest/components/BbTimePicker.json +26 -27
- package/dist/ai/manifest/components/BbTimePickerInput.json +56 -57
- package/dist/ai/manifest/components/BbToast.json +1 -2
- package/dist/ai/manifest/components/BbTooltip.json +16 -17
- package/dist/ai/manifest/components/BbTree.json +4 -5
- package/dist/ai/manifest/components/ChipsBox.json +3 -3
- package/dist/ai/manifest/components/ClearableButton.json +1 -1
- package/dist/ai/manifest/components/CommaBox.json +1 -1
- package/dist/ai/manifest/components/CommonField.json +32 -32
- package/dist/ai/manifest/components/CommonFieldInput.json +15 -15
- package/dist/ai/manifest/components/CommonPopover.json +17 -17
- package/dist/ai/manifest/components/CommonTimeSelector.json +9 -9
- package/dist/ai/manifest/components/FlatListBox.json +15 -14
- package/dist/ai/manifest/components/GroupedListBox.json +16 -15
- package/dist/ai/manifest/components/ListBox.json +18 -17
- package/dist/ai/manifest/components/OptionsContainer.json +16 -16
- package/dist/ai/manifest/index.json +89 -85
- package/dist/ai/manifest/meta.json +43 -2
- package/dist/ai/manifest/types.advanced.json +10 -10
- package/dist/ai/manifest/types.api.json +52 -49
- package/dist/ai/recipes/inertia/approvals-inbox.md +6 -0
- package/dist/ai/recipes/inertia/inline-edit-workspace.md +6 -0
- package/dist/ai/recipes/inertia/onboarding.md +6 -0
- package/dist/ai/recipes/inertia/ownership-atlas.md +6 -0
- package/dist/ai/recipes/inertia/records-workspace.md +6 -0
- package/dist/ai/recipes/inertia/settings-workspace.md +6 -0
- package/dist/ai/recipes/inertia/upload-center.md +6 -0
- package/dist/ai/source/BbBaseButton.md +9 -11
- package/dist/ai/source/BbButton.md +15 -4
- package/dist/ai/source/BbCheckbox.md +12 -12
- package/dist/ai/source/BbCheckboxGroup.md +12 -12
- package/dist/ai/source/BbColorInput.md +20 -21
- package/dist/ai/source/BbDatePickerInput.md +20 -21
- package/dist/ai/source/BbDialog.md +77 -40
- package/dist/ai/source/BbDropdownButton.md +103 -112
- package/dist/ai/source/BbDropzone.md +11 -12
- package/dist/ai/source/BbForm.md +77 -27
- package/dist/ai/source/BbNumberInput.md +20 -21
- package/dist/ai/source/BbOffCanvas.md +67 -32
- package/dist/ai/source/BbRadio.md +12 -12
- package/dist/ai/source/BbRadioGroup.md +12 -12
- package/dist/ai/source/BbRating.md +16 -16
- package/dist/ai/source/BbSelect.md +323 -282
- package/dist/ai/source/BbSelectPopover.md +946 -48
- package/dist/ai/source/BbSlider.md +12 -12
- package/dist/ai/source/BbTable.md +66 -78
- package/dist/ai/source/BbTag.md +20 -21
- package/dist/ai/source/BbTextInput.md +20 -21
- package/dist/ai/source/BbTextarea.md +20 -21
- package/dist/ai/source/BbTimePickerInput.md +14 -15
- package/dist/ai/source/BbTree.md +4 -5
- package/dist/ai/source/CommonField.md +18 -18
- package/dist/ai/source/CommonFieldInput.md +4 -4
- package/dist/ai/source/FlatListBox.md +14 -0
- package/dist/ai/source/GroupedListBox.md +14 -0
- package/dist/ai/source/ListBox.md +8 -0
- package/dist/components/BbBaseButton/types.d.ts +9 -11
- package/dist/components/BbButton/BbButton.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/components/BbButton/types.d.ts +6 -0
- package/dist/components/BbCheckbox/types.d.ts +12 -12
- package/dist/components/BbCheckboxGroup/types.d.ts +12 -12
- package/dist/components/BbColorInput/types.d.ts +20 -21
- package/dist/components/BbDatePickerInput/types.d.ts +20 -21
- package/dist/components/BbDialog/BbDialog.vue.d.ts +2 -2
- package/dist/components/BbDialog/BbDialog.vue_vue_type_script_setup_true_lang.js +192 -182
- package/dist/components/BbDialog/types.d.ts +42 -34
- package/dist/components/BbDropdownButton/BbDropdownButton.vue_vue_type_script_setup_true_lang.js +143 -100
- package/dist/components/BbDropdownButton/types.d.ts +25 -15
- package/dist/components/BbDropzone/types.d.ts +11 -12
- package/dist/components/BbForm/BbForm.vue.d.ts +17 -17
- package/dist/components/BbForm/BbForm.vue_vue_type_script_setup_true_lang.js +195 -188
- package/dist/components/BbForm/formSchema.d.ts +9 -0
- package/dist/components/BbHost/BbHostOpening.js +1 -1
- package/dist/components/BbNumberInput/types.d.ts +20 -21
- package/dist/components/BbOffCanvas/BbOffCanvas.vue.d.ts +2 -2
- package/dist/components/BbOffCanvas/BbOffCanvas.vue_vue_type_script_setup_true_lang.js +242 -234
- package/dist/components/BbOffCanvas/types.d.ts +36 -28
- package/dist/components/BbRadio/types.d.ts +12 -12
- package/dist/components/BbRadioGroup/types.d.ts +12 -12
- package/dist/components/BbRating/types.d.ts +16 -16
- package/dist/components/BbSelect/BbSelect.vue_vue_type_script_setup_true_lang.js +291 -283
- package/dist/components/BbSelect/types.d.ts +43 -31
- package/dist/components/BbSelectPopover/BbSelectPopover.vue_vue_type_script_setup_true_lang.js +773 -487
- package/dist/components/BbSelectPopover/knownItems.d.ts +60 -0
- package/dist/components/BbSelectPopover/knownItems.js +26 -0
- package/dist/components/BbSelectPopover/types.d.ts +16 -18
- package/dist/components/BbSlider/types.d.ts +12 -12
- package/dist/components/BbTable/types.d.ts +66 -78
- package/dist/components/BbTag/types.d.ts +20 -21
- package/dist/components/BbTextInput/types.d.ts +20 -21
- package/dist/components/BbTextarea/types.d.ts +20 -21
- package/dist/components/BbTimePickerInput/types.d.ts +14 -15
- package/dist/components/BbTree/types.d.ts +4 -5
- package/dist/components/CommonField/types.d.ts +18 -18
- package/dist/components/CommonFieldInput/types.d.ts +4 -4
- package/dist/components/FlatListBox/FlatListBox.vue_vue_type_script_setup_true_lang.js +73 -68
- package/dist/components/FlatListBox/types.d.ts +6 -0
- package/dist/components/GroupedListBox/GroupedListBox.vue_vue_type_script_setup_true_lang.js +35 -30
- package/dist/components/GroupedListBox/types.d.ts +6 -0
- package/dist/components/ListBox/ListBox.vue_vue_type_script_setup_true_lang.js +5 -0
- package/dist/components/ListBox/types.d.ts +6 -0
- package/dist/composables/formSubmitLock.d.ts +6 -1
- package/dist/composables/hostOpenings.d.ts +10 -4
- package/dist/composables/hostOpenings.js +1 -1
- package/dist/composables/overlayRegistry.d.ts +22 -9
- package/dist/composables/overlayRegistry.js +175 -132
- package/dist/composables/useBbDialogContext.d.ts +29 -11
- package/dist/composables/useBbDialogContext.js +17 -8
- package/dist/composables/useBbFormContext.d.ts +12 -7
- package/dist/composables/useBbFormContext.js +7 -6
- package/dist/composables/useFormBinding.d.ts +7 -9
- package/dist/composables/useOnDemandOpener.d.ts +6 -13
- package/dist/composables/useOnDemandOpener.js +47 -22
- package/dist/directives/overlayTrigger.d.ts +4 -2
- package/dist/directives/overlayTrigger.js +1 -0
- package/dist/index.d.ts +3 -3
- package/dist/llms-full.txt +943 -401
- package/dist/llms-medium.txt +3 -2
- package/dist/llms.txt +2 -2
- package/dist/styles.css +2 -2
- package/dist/utils/versionCheck.js +1 -1
- package/llms.txt +2 -2
- package/package.json +1 -1
- package/scripts/lib/agent-manifest.mjs +231 -18
- package/scripts/lib/validate-bb-markup.mjs +53 -9
package/dist/ai/BbDialog.md
CHANGED
|
@@ -203,8 +203,9 @@ reads `data` in two places:
|
|
|
203
203
|
`data` (typed `any`, so `data.name` reads with no cast);
|
|
204
204
|
- in code, `useBbDialogContext<T>(id)` returns it typed, along with `open`,
|
|
205
205
|
`show(data?)` and `hide()`. A component inside the dialog can call it too.
|
|
206
|
-
|
|
207
|
-
|
|
206
|
+
A `show()` on an open dialog changes nothing: it joins the opening (its
|
|
207
|
+
promise, its data); the new data, trigger and `onComplete` are ignored. A
|
|
208
|
+
show during the close transition opens it again.
|
|
208
209
|
|
|
209
210
|
`data` stays set until the close transition has run, so the content never
|
|
210
211
|
flashes empty while the dialog fades out. The edit-record example in
|
|
@@ -241,7 +242,8 @@ The rules:
|
|
|
241
242
|
- **An open before the dialog mounts waits for it.** A `show()`, or a
|
|
242
243
|
`v-bb-dialog` click whose own handler renders the dialog through a `v-if`,
|
|
243
244
|
is held until the dialog registers, so one click opens it (up to 1s; then
|
|
244
|
-
it settles `'missing'` with a dev warning, and `onComplete` never runs).
|
|
245
|
+
it settles `'missing'` with a dev warning, and `onComplete` never runs). A
|
|
246
|
+
`hide()` meanwhile cancels a held `show()`, silently: it settles `'hide'`.
|
|
245
247
|
The warning suggests the nearest registered id for a typo, and says when a
|
|
246
248
|
dialog with that id exists but is out of reach (inside an on-demand dialog,
|
|
247
249
|
which is private, or parked by KeepAlive) or is a `BbOffCanvas`.
|
|
@@ -323,7 +325,6 @@ const replace = (saved: Member) => {
|
|
|
323
325
|
| `'close'` | the ✕ or the slots' `close()` |
|
|
324
326
|
| `'swipe'` | the phone sheet swiped away |
|
|
325
327
|
| `'hide'` | `hide()`, or the model set to `false` (also a bound `v-model` whose parent refused the open) |
|
|
326
|
-
| `'replaced'` | a newer `show()` on the open dialog took over |
|
|
327
328
|
| `'missing'` | no dialog with that id mounted within 1s |
|
|
328
329
|
| `'unmounted'` | the dialog unmounted (or KeepAlive parked it), or a waiting `show()`'s caller went away |
|
|
329
330
|
| `'failed'` | an on-demand dialog could not render |
|
|
@@ -340,6 +341,101 @@ const replace = (saved: Member) => {
|
|
|
340
341
|
flags the unawaited promise of a bare `edit.show(row)`, write
|
|
341
342
|
`void edit.show(row)`.
|
|
342
343
|
|
|
344
|
+
#### The page saves: a promise from `onComplete`
|
|
345
|
+
|
|
346
|
+
When the page owns the save (it knows the endpoint, the list to update),
|
|
347
|
+
`onComplete` returns the request's promise. `complete(value)` calls it first,
|
|
348
|
+
and the dialog stays open and **locked** until it settles: the ✕, Cancel,
|
|
349
|
+
Escape and the backdrop are refused, and a footer `BbButton` whose click
|
|
350
|
+
returns `complete(value)` spins. Resolved, the dialog closes and the opening
|
|
351
|
+
settles `{ completed: true, value }`; rejected, it stays open with its data
|
|
352
|
+
and `complete()` rejects with the same error, so the dialog can show it.
|
|
353
|
+
|
|
354
|
+
```vue
|
|
355
|
+
<template>
|
|
356
|
+
<BbButton v-bb-dialog="{ id: 'rename', data: row, onComplete: save }">
|
|
357
|
+
Rename
|
|
358
|
+
</BbButton>
|
|
359
|
+
<BbDialog id="rename" v-slot="{ data, complete }" title="Rename">
|
|
360
|
+
<BbForm :model="data" @submit="() => complete(data)">
|
|
361
|
+
<BbTextInput label="Name" name="name" />
|
|
362
|
+
<BbButton type="submit">Save</BbButton>
|
|
363
|
+
</BbForm>
|
|
364
|
+
</BbDialog>
|
|
365
|
+
</template>
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
From code: `edit.show(row, { onComplete: save })` (both the id and the
|
|
369
|
+
component handle). A `save` function passed in `data` is no longer needed.
|
|
370
|
+
A sync `onComplete` (or none) closes at once, as before.
|
|
371
|
+
|
|
372
|
+
`onComplete` is just a function. A trigger inside a child component gets the
|
|
373
|
+
page's save the way your app already shares things: a function prop
|
|
374
|
+
(`:save="saveMember"`), a page `provide` / `inject`, or a store action. Not an
|
|
375
|
+
emit: an emit cannot return the promise.
|
|
376
|
+
|
|
377
|
+
To show a rejected save's field errors, keep them in a `ref` bound on the
|
|
378
|
+
form, `<BbForm :field-errors="fieldErrors">` (BbForm § The page's errors
|
|
379
|
+
object): the dialog stays open, and each message lands under its field until
|
|
380
|
+
the user edits it.
|
|
381
|
+
|
|
382
|
+
```vue
|
|
383
|
+
<script setup lang="ts">
|
|
384
|
+
import { ref } from 'vue';
|
|
385
|
+
|
|
386
|
+
const fieldErrors = ref<Record<string, string[]>>({});
|
|
387
|
+
</script>
|
|
388
|
+
|
|
389
|
+
<template>
|
|
390
|
+
<BbDialog id="rename" v-slot="{ data, complete }" title="Rename">
|
|
391
|
+
<BbForm
|
|
392
|
+
:field-errors="fieldErrors"
|
|
393
|
+
:model="data"
|
|
394
|
+
@submit="
|
|
395
|
+
() =>
|
|
396
|
+
complete(data).catch((error) => {
|
|
397
|
+
// Your save's rejection: the 422 body's `errors` by field path.
|
|
398
|
+
fieldErrors = error.errors ?? {};
|
|
399
|
+
})
|
|
400
|
+
"
|
|
401
|
+
>
|
|
402
|
+
<BbTextInput label="Name" name="name" />
|
|
403
|
+
<BbButton type="submit">Save</BbButton>
|
|
404
|
+
</BbForm>
|
|
405
|
+
</BbDialog>
|
|
406
|
+
</template>
|
|
407
|
+
```
|
|
408
|
+
|
|
409
|
+
With Inertia, the page's `useForm().errors` is that object already; the
|
|
410
|
+
record-form recipe (`ai/recipes/inertia/record-form.md`) binds
|
|
411
|
+
`<BbForm :field-errors="form.errors">` the same way.
|
|
412
|
+
|
|
413
|
+
An Inertia visit (`router.put`, `form.put`) returns no promise and never
|
|
414
|
+
rejects on its own, so `onComplete` wraps it: a validation error rejects
|
|
415
|
+
with the errors (the example above reads `error.errors`), success resolves,
|
|
416
|
+
and a visit cut short by another visit resolves too, closing the dialog.
|
|
417
|
+
|
|
418
|
+
```ts
|
|
419
|
+
import { router } from '@inertiajs/vue3';
|
|
420
|
+
|
|
421
|
+
type User = { id: number; name: string };
|
|
422
|
+
|
|
423
|
+
const save = (user: User) =>
|
|
424
|
+
new Promise<void>((resolve, reject) => {
|
|
425
|
+
router.put(`/users/${user.id}`, user, {
|
|
426
|
+
onSuccess: () => resolve(),
|
|
427
|
+
onError: (errors) => reject({ errors }),
|
|
428
|
+
// Cancelled or interrupted: close. Anything else that ends here
|
|
429
|
+
// unsettled (a 500, a network error) keeps the dialog open.
|
|
430
|
+
// Both are no-ops after onSuccess / onError.
|
|
431
|
+
onFinish: (visit) =>
|
|
432
|
+
visit.cancelled || visit.interrupted
|
|
433
|
+
? resolve()
|
|
434
|
+
: reject(new Error('The save failed')),
|
|
435
|
+
});
|
|
436
|
+
});
|
|
437
|
+
```
|
|
438
|
+
|
|
343
439
|
#### The data is a copy
|
|
344
440
|
|
|
345
441
|
Every opening holds its own **reactive copy** of the `data` it was given
|
|
@@ -421,7 +517,7 @@ default.
|
|
|
421
517
|
</div>
|
|
422
518
|
</template>
|
|
423
519
|
<template #footer="{ data, close, complete, reset }">
|
|
424
|
-
<!-- `reset()`
|
|
520
|
+
<!-- `reset()` clears the default's keys; an edit keeps its `id`. -->
|
|
425
521
|
<BbButton variant="ghost" @click="reset">Clear</BbButton>
|
|
426
522
|
<BbButton variant="ghost" @click="close">Cancel</BbButton>
|
|
427
523
|
<BbButton
|
|
@@ -462,9 +558,11 @@ const save = (saved: Member) => {
|
|
|
462
558
|
</script>
|
|
463
559
|
```
|
|
464
560
|
|
|
465
|
-
- **`reset()`** (the slots', or `useBbDialogContext(id).reset()`) restores
|
|
466
|
-
|
|
467
|
-
|
|
561
|
+
- **`reset()`** (the slots', or `useBbDialogContext(id).reset()`) restores
|
|
562
|
+
the keys `default-data` declares from a fresh copy, on an edit too, and keeps
|
|
563
|
+
every key it doesn't declare: the row's `id` stays, so a cleared edit still
|
|
564
|
+
saves as an edit. It doesn't go back to the row's values; Cancel is what
|
|
565
|
+
discards an edit.
|
|
468
566
|
- **Every close resets it** as well: nothing to do on `@show` or `@hidden`.
|
|
469
567
|
- **An object, not a function.** The dialog copies it every time and never
|
|
470
568
|
writes it, so a module constant is safe.
|
|
@@ -577,10 +675,16 @@ const createForDesign = async () => {
|
|
|
577
675
|
KeepAlive park. A flow that changes the URL inside one dialog (a wizard
|
|
578
676
|
whose steps are routes) opens it from the parent route or the persistent
|
|
579
677
|
layout, which stays mounted. A `show()` from a store lives until closed.
|
|
580
|
-
- **
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
678
|
+
- **From a store.** Create the handle in the setup store's body (or under
|
|
679
|
+
`app.runWithContext()`), then `show()` / `hide()` from its actions or a
|
|
680
|
+
router hook. Created in a plain module, outside any injection context,
|
|
681
|
+
`show()` settles `'failed'` with a dev warning.
|
|
682
|
+
- **One handle, one dialog.** `useBbDialogContext(Component)` is the same
|
|
683
|
+
handle as the id form (`isReady`, `open`, `data`, `show`, `hide`,
|
|
684
|
+
`complete`, `reset`), about its own dialog: a `show()` while it is open
|
|
685
|
+
joins it. Another handle (another `useBbDialogContext(Component)` call, or
|
|
686
|
+
another trigger element) opens its own instance on top, with its own
|
|
687
|
+
promise. `isReady` says a `<BbHost />` is mounted to render it.
|
|
584
688
|
- **Each opening gets its own DOM id**, so two stacked instances stay valid
|
|
585
689
|
HTML; `aria-controls` on the trigger follows it. A template dialog keeps the
|
|
586
690
|
`id` you gave it. To find one in an e2e test, use its role and title,
|
|
@@ -968,6 +1072,18 @@ const form = useBbFormContext('edit-member-form');
|
|
|
968
1072
|
field uses, `form.setErrors({ ...errors, _request: [message] })`, and shows in
|
|
969
1073
|
the form's `unmatchedErrors` (see BbForm § Server errors).
|
|
970
1074
|
|
|
1075
|
+
#### Steps in one dialog
|
|
1076
|
+
|
|
1077
|
+
- **Each step's first field gets `autofocus`**: it fires when the field
|
|
1078
|
+
mounts, so focus follows the step with no watcher (`focus-target` picks only
|
|
1079
|
+
where the opening starts).
|
|
1080
|
+
- **A final success step with no field is a status region**
|
|
1081
|
+
(`role="status"`), announced as it appears, not a focus target.
|
|
1082
|
+
- **A footer button that changes type in place** (Next, `type="button"`,
|
|
1083
|
+
becoming Accept, `type="submit"`, during its own click): give each its own
|
|
1084
|
+
`key`. Unkeyed, Vue reuses the element, its type flips mid-click, and the
|
|
1085
|
+
click on Next submits the form.
|
|
1086
|
+
|
|
971
1087
|
### Lifecycle events and lazy content
|
|
972
1088
|
|
|
973
1089
|
Four events bracket the transitions — `show` fires as the model turns `true`,
|
|
@@ -987,11 +1103,16 @@ Every way to close, side by side:
|
|
|
987
1103
|
| Escape, Back on a URL dialog, a backdrop click, a swipe | the user | yes: `persistent` too | `reason: 'escape'` / `'backdrop'` / `'swipe'` | on the key, Back, click or swipe |
|
|
988
1104
|
| `hide()` (context), the model set to `false` | your code | no | `{ completed: false, reason: 'hide' }` | at once |
|
|
989
1105
|
| `complete(value)` (slots, context) | your code | no | `{ completed: true, value }` | at once |
|
|
990
|
-
| `@hide` | the dialog | it reports a close, it can't stop one |
|
|
1106
|
+
| `@hide` | the dialog | it reports a close, it can't stop one | emits it (the same object) | as any close above **starts** |
|
|
991
1107
|
| `@hidden` | the dialog | it reports a close, it can't stop one | already settled | after the close transition; focus returns, `data` clears and the body unmounts then |
|
|
992
1108
|
|
|
993
1109
|
A refused close fires nothing and settles nothing. Use `@hide` for what
|
|
994
|
-
follows the decision (a toast, a refresh), `@hidden` for teardown.
|
|
1110
|
+
follows the decision (a toast, a refresh), `@hidden` for teardown. `@hide`
|
|
1111
|
+
carries the opening's result, so a live preview reverts on a dismissal with
|
|
1112
|
+
no flag of its own: `@hide="(r) => { if (!r.completed) restore() }"`. To
|
|
1113
|
+
tell a save from a cancel, close a save with `complete()` (slots or context),
|
|
1114
|
+
not by writing the model: on a `v-model` dialog too, it closes through the
|
|
1115
|
+
model and reports `{ completed: true }`.
|
|
995
1116
|
|
|
996
1117
|
The body lives **per opening**: nothing inside the dialog renders until it
|
|
997
1118
|
opens, and the body unmounts after the close transition (right after
|
|
@@ -1003,7 +1124,9 @@ tests that query content before opening): `data` still clears while closed (to
|
|
|
1003
1124
|
`undefined`, or the `default-data` copy), so an eager body guards its own
|
|
1004
1125
|
reads. `transition-duration` (ms, default
|
|
1005
1126
|
`250`) times both the open/close animation and when `hidden` fires — reopening
|
|
1006
|
-
during the close transition keeps the dialog open instead of snapping shut
|
|
1127
|
+
during the close transition keeps the dialog open instead of snapping shut, with
|
|
1128
|
+
a fresh body: every new opening gets one, a reopen mid-close included (an
|
|
1129
|
+
`eager` body is kept).
|
|
1007
1130
|
|
|
1008
1131
|
### Size
|
|
1009
1132
|
|
|
@@ -1056,6 +1179,11 @@ Every dismissal path is governed by two props, and by a form inside:
|
|
|
1056
1179
|
- `true`: always locked.
|
|
1057
1180
|
- `false`: never locked, not even mid-save. Closing mid-save is then on you.
|
|
1058
1181
|
|
|
1182
|
+
Binding it to your own flag: beside a `BbForm`, another async action (a
|
|
1183
|
+
footer Delete) binds `:prevent-close="deleting || undefined"`; a plain
|
|
1184
|
+
`false` while idle would switch the form's lock off. A dialog with no
|
|
1185
|
+
`BbForm` binds `:prevent-close="saving"`.
|
|
1186
|
+
|
|
1059
1187
|
`persistent` keeps the ✕ (and the slots' `close`) as the deliberate exit;
|
|
1060
1188
|
`prevent-close` removes every exit but the model.
|
|
1061
1189
|
|
|
@@ -1392,7 +1520,26 @@ const route = useRoute();
|
|
|
1392
1520
|
```
|
|
1393
1521
|
|
|
1394
1522
|
Template dialogs only: a dialog opened on demand has no place in the page URL
|
|
1395
|
-
(`navigation` is ignored there, with a dev warning).
|
|
1523
|
+
(`navigation` is ignored there, with a dev warning). A wrapper component that
|
|
1524
|
+
should live in the URL is rendered in the page and opened by id: reload opens
|
|
1525
|
+
it, Back closes it, closing strips the key. State it needs fresh on every
|
|
1526
|
+
opening (a form object made in setup) goes in its body, a small component
|
|
1527
|
+
inside the BbDialog whose setup runs per opening, or in the opening's `data`
|
|
1528
|
+
with `default-data`:
|
|
1529
|
+
|
|
1530
|
+
```vue
|
|
1531
|
+
<!-- CreatePatientDialog.vue renders
|
|
1532
|
+
<BbDialog id="create-patient" navigation query-key="create">
|
|
1533
|
+
<PatientForm /> (its own setup: a fresh form per opening)
|
|
1534
|
+
</BbDialog> -->
|
|
1535
|
+
<CreatePatientDialog />
|
|
1536
|
+
<BbButton v-bb-dialog="'create-patient'">New patient</BbButton>
|
|
1537
|
+
```
|
|
1538
|
+
|
|
1539
|
+
On demand stays for openings with no page to live in (a command palette, a
|
|
1540
|
+
store action, stacked copies of one dialog), which want no URL anyway.
|
|
1541
|
+
|
|
1542
|
+
On the phone the adaptive
|
|
1396
1543
|
sheet is the same dialog: one key, and Back is refused by the sheet's own
|
|
1397
1544
|
gates. Under Inertia, a Back that changes only dialog keys never reaches
|
|
1398
1545
|
Inertia, so the page is not remounted; this needs `bitbossUiPlugin` installed
|
|
@@ -1580,6 +1727,10 @@ A `pt` value written in `<script>` (a constant, a preset, a wrapper's
|
|
|
1580
1727
|
`href`/`to` to the button.
|
|
1581
1728
|
- **Don't toggle `v-model` from `@hide`/`@hidden` handlers** to "cancel" a
|
|
1582
1729
|
close — use `persistent` instead; the close paths already guard correctly.
|
|
1730
|
+
- **Catch `complete()` in a reusable dialog** whenever an opener may pass an
|
|
1731
|
+
`onComplete` that rejects (`complete(data).catch(…)`, as in § The page
|
|
1732
|
+
saves). Uncaught, the rejection travels through the form's `@submit` and
|
|
1733
|
+
reaches `app.config.errorHandler`.
|
|
1583
1734
|
- **Don't leave the `header` slot without a close control** — it replaces the
|
|
1584
1735
|
default ×, so you must render your own wired to `close`.
|
|
1585
1736
|
- **Don't query dialog content before it has opened, or after it has closed**,
|
|
@@ -1625,7 +1776,7 @@ A `pt` value written in `<script>` (a constant, a preset, a wrapper's
|
|
|
1625
1776
|
| --- | --- | --- | --- | --- |
|
|
1626
1777
|
| `pt:<part>`, `pt:<part>:<state>`, `pt` | `PtValue` | | | Passthrough — a class list, or `{ class, style, attrs }`, bound to one named part of the component; the state form applies only while that state is on. Parts: `close`, `content`, `description`, `footer`, `header`, `root`, `sheet`, `title`. States: `fullscreen`, `open`. What each one is: _Passthrough parts and states_ below. `pt` is the object form with the same keys minus the prefix (`{ icon: '…', 'icon:loading': '…' }`). See `guides/passthrough.md`. In `<script>` a `pt` value is typed `BbDialogProps['pt']` (`PtValue` is not exported): § Typing `pt` in `<script>`. |
|
|
1627
1778
|
| `adaptive` | `boolean \| undefined` | ``config.adaptive` (`true`)` | | On mobile, renders as a `BbOffCanvas` drawer instead of a centred dialog; the surface is chosen when the dialog opens and kept until it closes. Unset: the global `config.adaptive`. |
|
|
1628
|
-
| `defaultData` | `Record<string, any> \| undefined` | | |
|
|
1779
|
+
| `defaultData` | `Record<string, any> \| undefined` | | | What `data` is when an opening passes none (a create): an object, copied at once, so inputs bind `data.x` with no guard. An opening's data lays over it (`{ ...defaultData, ...row }`, one level). `reset()` restores its keys but keeps an edit's `id`; a close restores it. |
|
|
1629
1780
|
| `description` | `string \| undefined` | | | One short line under the title, muted (the shadcn `DialogDescription` shape), and the only element `aria-describedby` points at. Keep it to a sentence; anything longer belongs in the body. |
|
|
1630
1781
|
| `eager` | `boolean \| undefined` | `false` | | Keep the body mounted while closed, from before the first opening. Without it the body mounts per opening and unmounts after `@hidden`. `data` still clears while closed, so an eager body guards its reads. |
|
|
1631
1782
|
| `focusTarget` | `string \| undefined` | | | CSS selector of the element to focus after opening. Defaults to the first tabbable element. |
|
|
@@ -1633,16 +1784,16 @@ A `pt` value written in `<script>` (a constant, a preset, a wrapper's
|
|
|
1633
1784
|
| `hideClose` | `boolean \| undefined` | `false` | | Hide the default close (×) button. The button is shown by default; set this to remove it (e.g. for a `persistent` dialog you don't want dismissible — the × otherwise still closes a persistent dialog). |
|
|
1634
1785
|
| `id` | `string \| undefined` | | | Names the dialog for `v-bb-dialog="'edit'"` and `useBbDialogContext`, found nearest to the trigger, so two pages may reuse an id. Also the DOM `id`: one dialog per id, rows pass `data`. |
|
|
1635
1786
|
| `modelValue` | `boolean \| undefined` | `false` | | Used by v-model to open / close the dialog. A dialog with no `v-model` starts closed. |
|
|
1636
|
-
| `navigation` | `boolean \| undefined` | `false` | | Syncs the open state with the URL: opening writes `?<queryKey>=true`, closing removes it, a URL
|
|
1787
|
+
| `navigation` | `boolean \| undefined` | `false` | | Syncs the open state with the URL: opening writes `?<queryKey>=true`, closing removes it, a URL with the key opens the dialog on load, and Back closes it (refused whenever Escape is). Template dialogs only; keep a record id in your own query. |
|
|
1637
1788
|
| `offCanvasProps` | `Partial<BbOffCanvasProps> \| undefined` | | | Props for the phone sheet (the `BbOffCanvas` that `adaptive` renders on mobile), spread over its defaults. A `pt` inside it styles only the sheet (passthrough guide § Inside the sheet). |
|
|
1638
|
-
| `persistent` | `boolean \| undefined` | `false` | |
|
|
1639
|
-
| `preventClose` | `boolean \| undefined` | ``undefined` (follows a saving form inside)` | | Refuses every user close (backdrop, Escape
|
|
1789
|
+
| `persistent` | `boolean \| undefined` | `false` | | Blocks closing by outside click or Escape. The header close (×) STILL closes a persistent dialog, the documented escape hatch: add `hideClose` to remove it, or use `preventClose` to block every dismissal. Programmatic close still works. |
|
|
1790
|
+
| `preventClose` | `boolean \| undefined` | ``undefined` (follows a saving form inside)` | | Refuses every user close (backdrop, Escape, the ✕, the slots' `close`) with the deny nudge; `v-model` still closes. Unset: locked while a `BbForm` inside saves (an async `@submit`). `true`: always; `false`: never, not even mid-save. Beside a form: `busy \|\| undefined`. |
|
|
1640
1791
|
| `queryKey` | `string \| undefined` | `"dialog"` | | The query key `navigation` writes. |
|
|
1641
1792
|
| `replace` | `boolean \| undefined` | `false` | | With `navigation`, replaces the history entry instead of pushing one, so Back leaves the page instead of closing the dialog. |
|
|
1642
1793
|
| `size` | `Responsive<NonNullable<number \| CssSize \| keyof BbDialogSizes \| undefined>> \| undefined` | `"sm"` | | Controls the maximum width of the dialog. Accepts named presets from `'xs'` to `'2xl'`, a custom CSS width string, or a numeric pixel value — or a per-breakpoint map (e.g. `{ default: 'sm', lg: 'lg' }`) to switch width responsively. |
|
|
1643
1794
|
| `snap` | `BbSnapPoint \| undefined` | | | The phone sheet's snap stop (Q71.8), one of the `snapPoints` entries. The desktop dialog ignores it. |
|
|
1644
|
-
| `snapPoints` | `BbSnapPoint[] \| undefined` | | | Heights the phone sheet rests at, smallest first: a fraction
|
|
1645
|
-
| `stack` | `string \| undefined` | | | Name of
|
|
1795
|
+
| `snapPoints` | `BbSnapPoint[] \| undefined` | | | Heights the phone sheet rests at, smallest first: a screen fraction (`0.5`; `1` = as tall as it gets) or pixels (`'240px'`). The first is the opening height; `v-model:snap` reads and sets the stop. Sheet only: the centred dialog ignores it. |
|
|
1796
|
+
| `stack` | `string \| undefined` | | | Name of this dialog's stack. Dialogs with the same `stack` replace one another: only the latest opened shows, the rest of the stack hide beneath it. Dialogs in different stacks, or with no `stack`, never affect each other and stay fully visible. |
|
|
1646
1797
|
| `title` | `string \| undefined` | | | Title text announced to assistive technologies. If omitted, no header is rendered (unless a `header` slot is supplied) and accessibility must be handled manually. |
|
|
1647
1798
|
| `transitionDuration` | `number \| undefined` | `250` | | Controls the duration of the open and close animations. |
|
|
1648
1799
|
|
|
@@ -1671,7 +1822,7 @@ States are listed in precedence order: when two are on at once and their entries
|
|
|
1671
1822
|
## Events
|
|
1672
1823
|
|
|
1673
1824
|
- `hidden` — `(): void` — Emitted after the close transition completes and the dialog is fully dismissed.
|
|
1674
|
-
- `hide` — `(): void` — Emitted as soon as the dialog starts to close (model becomes false).
|
|
1825
|
+
- `hide` — `(result: BbDialogResult): void` — Emitted as soon as the dialog starts to close (model becomes false), with the opening's result: the same object its promise settles with, `{ completed: true, value }` or `{ completed: false, reason }` (Q73.6).
|
|
1675
1826
|
- `show` — `(): void` — Emitted as soon as the dialog starts to open (model becomes true).
|
|
1676
1827
|
- `shown` — `(): void` — Emitted once the open transition has run (symmetric with `hidden`): the dialog is settled, so code that measures or anchors to its content sees the final layout. Not emitted for a dialog closed before it finished opening.
|
|
1677
1828
|
- `update:modelValue` — `(value: boolean): void` — Emitted with the new value whenever `v-model` changes.
|
|
@@ -1679,10 +1830,10 @@ States are listed in precedence order: when two are on at once and their entries
|
|
|
1679
1830
|
|
|
1680
1831
|
## Slots
|
|
1681
1832
|
|
|
1682
|
-
- `default` — scope: `BbDialogDefaultSlotProps` `{ close: () => void; complete: (value?: any) => void
|
|
1833
|
+
- `default` — scope: `BbDialogDefaultSlotProps` `{ close: () => void; complete: (value?: any) => Promise<void>; reset: () => void; data: any }` — Primary body content of the dialog, rendered in the scrollable body area.
|
|
1683
1834
|
- `description` — scope: `BbDialogDescriptionSlotProps` `{ text: string; data: any }` — 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.
|
|
1684
|
-
- `footer` — scope: `BbDialogFooterSlotProps` `{ close: () => void; complete: (value?: any) => void
|
|
1685
|
-
- `header` — scope: `BbDialogHeaderSlotProps` `{ titleId: string; close: () => void; complete: (value?: any) => void
|
|
1835
|
+
- `footer` — scope: `BbDialogFooterSlotProps` `{ close: () => void; complete: (value?: any) => Promise<void>; reset: () => void; data: any }` — Content rendered in the dialog footer, below the body area. Typically used for action buttons.
|
|
1836
|
+
- `header` — scope: `BbDialogHeaderSlotProps` `{ titleId: string; close: () => void; complete: (value?: any) => Promise<void>; reset: () => void; title: string; data: any }` — Replaces the whole header (title and ✕) on both surfaces, so it owns closing: wire your control to `close`, and `titleId` onto your title. It renders even without `title`. Its root is a flex item: give it `flex-1` to fill the width.
|
|
1686
1837
|
- `title` — scope: `BbDialogTitleSlotProps` `{ text: string; data: any }` — 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.
|
|
1687
1838
|
|
|
1688
1839
|
## CSS custom properties
|
package/dist/ai/BbDropdown.md
CHANGED
|
@@ -2124,8 +2124,8 @@ A `pt` value written in `<script>` (a constant, a preset, a wrapper's
|
|
|
2124
2124
|
width; pass a number when menus must align across rows.
|
|
2125
2125
|
- Item `variant`s other than `destructive` render only a class hook — register
|
|
2126
2126
|
names via the `dropdownItemVariants` plugin option and ship their CSS.
|
|
2127
|
-
- `<BbDropdownGroup>` must sit in a `BbDropdown` (
|
|
2128
|
-
|
|
2127
|
+
- `<BbDropdownGroup>` must sit in a `BbDropdown`'s default slot (a
|
|
2128
|
+
`BbDropdownButton`'s `#dropdown`), its `id` must match a group's `id`, and a `multiple` group's
|
|
2129
2129
|
model must be an array — all three misuses throw.
|
|
2130
2130
|
- Placeholder texts default to the config locale's "Loading…" / "No results"
|
|
2131
2131
|
strings (`locale` plugin option) unless you set `loading-text` /
|