From ad2d6fd2f3030e6b7e3021f396aa813087f49820 Mon Sep 17 00:00:00 2001 From: "David W. Gray" Date: Thu, 23 Oct 2025 09:54:48 -0700 Subject: [PATCH 01/13] docs: refactor examples in composable documentation (#2883) --- .../composables/demo/UseBreadcrumbBasic.vue | 35 +++ .../composables/demo/UseBreadcrumbWithId.vue | 34 +++ .../composables/demo/UseColorModeBasic.vue | 23 ++ .../composables/demo/UseModalAdvanced.vue | 42 +++ .../docs/composables/demo/UseModalBasic.vue | 19 ++ .../docs/composables/demo/UseModalNested.vue | 54 ++++ .../composables/demo/UseModalReactive.vue | 31 ++ .../docs/composables/demo/UseModalSetup.vue | 5 + .../composables/demo/UsePopoverAdvanced.vue | 21 ++ .../docs/composables/demo/UsePopoverBasic.vue | 15 + .../demo/UsePopoverLifecycleAwaitUsing.ts | 10 + .../demo/UsePopoverLifecycleManual.ts | 12 + .../composables/demo/UsePopoverReactive.vue | 31 ++ .../docs/composables/demo/UsePopoverSetup.vue | 5 + .../composables/demo/UseScrollspyBasic.vue | 52 +++- .../composables/demo/UseScrollspyManual.vue | 33 ++- .../composables/demo/UseToastAdvanced.vue | 41 +++ .../docs/composables/demo/UseToastBasic.vue | 9 + .../composables/demo/UseToastProgrammatic.vue | 41 +++ .../docs/composables/demo/UseToastPromise.vue | 42 +++ .../composables/demo/UseToastReactive.vue | 39 +++ .../docs/composables/demo/UseToastSetup.vue | 5 + .../composables/demo/UseTogglePromise.vue | 31 ++ .../docs/composables/demo/UseToggleWithId.vue | 24 ++ .../src/docs/composables/useBreadcrumb.md | 83 +----- .../docs/src/docs/composables/useColorMode.md | 48 +-- apps/docs/src/docs/composables/useModal.md | 208 +------------ apps/docs/src/docs/composables/usePopover.md | 130 +------- apps/docs/src/docs/composables/useToast.md | 280 +----------------- apps/docs/src/docs/composables/useToggle.md | 88 +----- 30 files changed, 660 insertions(+), 831 deletions(-) create mode 100644 apps/docs/src/docs/composables/demo/UseBreadcrumbBasic.vue create mode 100644 apps/docs/src/docs/composables/demo/UseBreadcrumbWithId.vue create mode 100644 apps/docs/src/docs/composables/demo/UseColorModeBasic.vue create mode 100644 apps/docs/src/docs/composables/demo/UseModalAdvanced.vue create mode 100644 apps/docs/src/docs/composables/demo/UseModalBasic.vue create mode 100644 apps/docs/src/docs/composables/demo/UseModalNested.vue create mode 100644 apps/docs/src/docs/composables/demo/UseModalReactive.vue create mode 100644 apps/docs/src/docs/composables/demo/UseModalSetup.vue create mode 100644 apps/docs/src/docs/composables/demo/UsePopoverAdvanced.vue create mode 100644 apps/docs/src/docs/composables/demo/UsePopoverBasic.vue create mode 100644 apps/docs/src/docs/composables/demo/UsePopoverLifecycleAwaitUsing.ts create mode 100644 apps/docs/src/docs/composables/demo/UsePopoverLifecycleManual.ts create mode 100644 apps/docs/src/docs/composables/demo/UsePopoverReactive.vue create mode 100644 apps/docs/src/docs/composables/demo/UsePopoverSetup.vue create mode 100644 apps/docs/src/docs/composables/demo/UseToastAdvanced.vue create mode 100644 apps/docs/src/docs/composables/demo/UseToastBasic.vue create mode 100644 apps/docs/src/docs/composables/demo/UseToastProgrammatic.vue create mode 100644 apps/docs/src/docs/composables/demo/UseToastPromise.vue create mode 100644 apps/docs/src/docs/composables/demo/UseToastReactive.vue create mode 100644 apps/docs/src/docs/composables/demo/UseToastSetup.vue create mode 100644 apps/docs/src/docs/composables/demo/UseTogglePromise.vue create mode 100644 apps/docs/src/docs/composables/demo/UseToggleWithId.vue diff --git a/apps/docs/src/docs/composables/demo/UseBreadcrumbBasic.vue b/apps/docs/src/docs/composables/demo/UseBreadcrumbBasic.vue new file mode 100644 index 000000000..e16b27266 --- /dev/null +++ b/apps/docs/src/docs/composables/demo/UseBreadcrumbBasic.vue @@ -0,0 +1,35 @@ + + + diff --git a/apps/docs/src/docs/composables/demo/UseBreadcrumbWithId.vue b/apps/docs/src/docs/composables/demo/UseBreadcrumbWithId.vue new file mode 100644 index 000000000..b84c8c509 --- /dev/null +++ b/apps/docs/src/docs/composables/demo/UseBreadcrumbWithId.vue @@ -0,0 +1,34 @@ + + + diff --git a/apps/docs/src/docs/composables/demo/UseColorModeBasic.vue b/apps/docs/src/docs/composables/demo/UseColorModeBasic.vue new file mode 100644 index 000000000..13f6f9290 --- /dev/null +++ b/apps/docs/src/docs/composables/demo/UseColorModeBasic.vue @@ -0,0 +1,23 @@ + + + diff --git a/apps/docs/src/docs/composables/demo/UseModalAdvanced.vue b/apps/docs/src/docs/composables/demo/UseModalAdvanced.vue new file mode 100644 index 000000000..bd285ebf8 --- /dev/null +++ b/apps/docs/src/docs/composables/demo/UseModalAdvanced.vue @@ -0,0 +1,42 @@ + + + diff --git a/apps/docs/src/docs/composables/demo/UseModalBasic.vue b/apps/docs/src/docs/composables/demo/UseModalBasic.vue new file mode 100644 index 000000000..314cd9c6f --- /dev/null +++ b/apps/docs/src/docs/composables/demo/UseModalBasic.vue @@ -0,0 +1,19 @@ + + + diff --git a/apps/docs/src/docs/composables/demo/UseModalNested.vue b/apps/docs/src/docs/composables/demo/UseModalNested.vue new file mode 100644 index 000000000..320fb1269 --- /dev/null +++ b/apps/docs/src/docs/composables/demo/UseModalNested.vue @@ -0,0 +1,54 @@ + + + diff --git a/apps/docs/src/docs/composables/demo/UseModalReactive.vue b/apps/docs/src/docs/composables/demo/UseModalReactive.vue new file mode 100644 index 000000000..8fba93d97 --- /dev/null +++ b/apps/docs/src/docs/composables/demo/UseModalReactive.vue @@ -0,0 +1,31 @@ + + + diff --git a/apps/docs/src/docs/composables/demo/UseModalSetup.vue b/apps/docs/src/docs/composables/demo/UseModalSetup.vue new file mode 100644 index 000000000..e30d35e19 --- /dev/null +++ b/apps/docs/src/docs/composables/demo/UseModalSetup.vue @@ -0,0 +1,5 @@ + diff --git a/apps/docs/src/docs/composables/demo/UsePopoverAdvanced.vue b/apps/docs/src/docs/composables/demo/UsePopoverAdvanced.vue new file mode 100644 index 000000000..c83c865c2 --- /dev/null +++ b/apps/docs/src/docs/composables/demo/UsePopoverAdvanced.vue @@ -0,0 +1,21 @@ + + + diff --git a/apps/docs/src/docs/composables/demo/UsePopoverBasic.vue b/apps/docs/src/docs/composables/demo/UsePopoverBasic.vue new file mode 100644 index 000000000..a66fd24ec --- /dev/null +++ b/apps/docs/src/docs/composables/demo/UsePopoverBasic.vue @@ -0,0 +1,15 @@ + + + diff --git a/apps/docs/src/docs/composables/demo/UsePopoverLifecycleAwaitUsing.ts b/apps/docs/src/docs/composables/demo/UsePopoverLifecycleAwaitUsing.ts new file mode 100644 index 000000000..e6f0e9d42 --- /dev/null +++ b/apps/docs/src/docs/composables/demo/UsePopoverLifecycleAwaitUsing.ts @@ -0,0 +1,10 @@ +/* eslint-disable @typescript-eslint/no-unused-vars */ +import {usePopover} from 'bootstrap-vue-next' + +{ + const {popover} = usePopover() + + // #region snippet + await using pop = popover({title: 'Hello World!'}) + // #endregion snippet +} diff --git a/apps/docs/src/docs/composables/demo/UsePopoverLifecycleManual.ts b/apps/docs/src/docs/composables/demo/UsePopoverLifecycleManual.ts new file mode 100644 index 000000000..0b2984f10 --- /dev/null +++ b/apps/docs/src/docs/composables/demo/UsePopoverLifecycleManual.ts @@ -0,0 +1,12 @@ +import {usePopover} from 'bootstrap-vue-next' + +{ + const {popover} = usePopover() + + // #region snippet + const pop = popover({title: 'Hello World!'}) + pop.show() + // do something + pop.destroy() + // #endregion snippet +} diff --git a/apps/docs/src/docs/composables/demo/UsePopoverReactive.vue b/apps/docs/src/docs/composables/demo/UsePopoverReactive.vue new file mode 100644 index 000000000..b0a2a6917 --- /dev/null +++ b/apps/docs/src/docs/composables/demo/UsePopoverReactive.vue @@ -0,0 +1,31 @@ + + + diff --git a/apps/docs/src/docs/composables/demo/UsePopoverSetup.vue b/apps/docs/src/docs/composables/demo/UsePopoverSetup.vue new file mode 100644 index 000000000..e30d35e19 --- /dev/null +++ b/apps/docs/src/docs/composables/demo/UsePopoverSetup.vue @@ -0,0 +1,5 @@ + diff --git a/apps/docs/src/docs/composables/demo/UseScrollspyBasic.vue b/apps/docs/src/docs/composables/demo/UseScrollspyBasic.vue index 98157bbd7..115657c98 100644 --- a/apps/docs/src/docs/composables/demo/UseScrollspyBasic.vue +++ b/apps/docs/src/docs/composables/demo/UseScrollspyBasic.vue @@ -2,23 +2,54 @@ - - Section 1 - Section 2 - Section 3 + + Section 1 + Section 2 + Section 3

Section 1

-

{{ loremText }}

+

+ {{ loremText }} +

Section 2

-

{{ loremText }}

+

+ {{ loremText }} +

Section 3

-

{{ loremText }}

+

+ {{ loremText }} +

@@ -29,10 +60,11 @@ import {useTemplateRef} from 'vue' import {useScrollspy} from 'bootstrap-vue-next' -const loremText = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.' +const loremText = + 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.' const scrollContent = useTemplateRef('scrollContent') const navTarget = useTemplateRef('navTarget') const {scrollIntoView} = useScrollspy(scrollContent, navTarget) - \ No newline at end of file + diff --git a/apps/docs/src/docs/composables/demo/UseScrollspyManual.vue b/apps/docs/src/docs/composables/demo/UseScrollspyManual.vue index 578a64c5c..8e248c340 100644 --- a/apps/docs/src/docs/composables/demo/UseScrollspyManual.vue +++ b/apps/docs/src/docs/composables/demo/UseScrollspyManual.vue @@ -20,14 +20,29 @@
Introduction
-

{{ loremText }}

+

+ {{ loremText }} +

Features
-

{{ loremText }}

+

+ {{ loremText }} +

Conclusion
-

{{ loremText }}

+

+ {{ loremText }} +

@@ -35,11 +50,11 @@ \ No newline at end of file +const filteredList = computed(() => list.value.filter((item) => item.id)) + diff --git a/apps/docs/src/docs/composables/demo/UseToastAdvanced.vue b/apps/docs/src/docs/composables/demo/UseToastAdvanced.vue new file mode 100644 index 000000000..4a5453c3b --- /dev/null +++ b/apps/docs/src/docs/composables/demo/UseToastAdvanced.vue @@ -0,0 +1,41 @@ + + + diff --git a/apps/docs/src/docs/composables/demo/UseToastBasic.vue b/apps/docs/src/docs/composables/demo/UseToastBasic.vue new file mode 100644 index 000000000..bd132c320 --- /dev/null +++ b/apps/docs/src/docs/composables/demo/UseToastBasic.vue @@ -0,0 +1,9 @@ + + + diff --git a/apps/docs/src/docs/composables/demo/UseToastProgrammatic.vue b/apps/docs/src/docs/composables/demo/UseToastProgrammatic.vue new file mode 100644 index 000000000..2bfa272b5 --- /dev/null +++ b/apps/docs/src/docs/composables/demo/UseToastProgrammatic.vue @@ -0,0 +1,41 @@ + + + diff --git a/apps/docs/src/docs/composables/demo/UseToastPromise.vue b/apps/docs/src/docs/composables/demo/UseToastPromise.vue new file mode 100644 index 000000000..bb7248c39 --- /dev/null +++ b/apps/docs/src/docs/composables/demo/UseToastPromise.vue @@ -0,0 +1,42 @@ + + + diff --git a/apps/docs/src/docs/composables/demo/UseToastReactive.vue b/apps/docs/src/docs/composables/demo/UseToastReactive.vue new file mode 100644 index 000000000..52d9e7748 --- /dev/null +++ b/apps/docs/src/docs/composables/demo/UseToastReactive.vue @@ -0,0 +1,39 @@ + + + diff --git a/apps/docs/src/docs/composables/demo/UseToastSetup.vue b/apps/docs/src/docs/composables/demo/UseToastSetup.vue new file mode 100644 index 000000000..e30d35e19 --- /dev/null +++ b/apps/docs/src/docs/composables/demo/UseToastSetup.vue @@ -0,0 +1,5 @@ + diff --git a/apps/docs/src/docs/composables/demo/UseTogglePromise.vue b/apps/docs/src/docs/composables/demo/UseTogglePromise.vue new file mode 100644 index 000000000..ba9b336a7 --- /dev/null +++ b/apps/docs/src/docs/composables/demo/UseTogglePromise.vue @@ -0,0 +1,31 @@ + + + diff --git a/apps/docs/src/docs/composables/demo/UseToggleWithId.vue b/apps/docs/src/docs/composables/demo/UseToggleWithId.vue new file mode 100644 index 000000000..b94356fc3 --- /dev/null +++ b/apps/docs/src/docs/composables/demo/UseToggleWithId.vue @@ -0,0 +1,24 @@ + + + diff --git a/apps/docs/src/docs/composables/useBreadcrumb.md b/apps/docs/src/docs/composables/useBreadcrumb.md index d0b462164..3964ec7de 100644 --- a/apps/docs/src/docs/composables/useBreadcrumb.md +++ b/apps/docs/src/docs/composables/useBreadcrumb.md @@ -10,91 +10,12 @@ ## Demo - - - - Add - Clear - - +<<< DEMO ./demo/UseBreadcrumbBasic.vue You can also pass in an id to the component and composable to create a unique breadcrumb trail. - - - - Add - Clear - - +<<< DEMO ./demo/UseBreadcrumbWithId.vue diff --git a/apps/docs/src/docs/composables/useColorMode.md b/apps/docs/src/docs/composables/useColorMode.md index 59ebefe23..1d16c6375 100644 --- a/apps/docs/src/docs/composables/useColorMode.md +++ b/apps/docs/src/docs/composables/useColorMode.md @@ -8,54 +8,8 @@ ## Demo - - - - - Current color: {{ mode }} - - - - - +<<< DEMO ./demo/UseColorModeBasic.vue diff --git a/apps/docs/src/docs/composables/useModal.md b/apps/docs/src/docs/composables/useModal.md index 45050d7f7..52fc6e66e 100644 --- a/apps/docs/src/docs/composables/useModal.md +++ b/apps/docs/src/docs/composables/useModal.md @@ -14,19 +14,7 @@ To use `useModal`, you need one of the following setup approaches: The easiest way is to wrap your application with the `BApp` component, which automatically sets up the orchestrator and registry: - - - +<<< FRAGMENT ./demo/UseModalSetup.vue ### Plugin Setup (Legacy) @@ -38,67 +26,13 @@ Alternatively, you can use the traditional plugin approach. Creating a modal is done through the `create` method: - - Click me - - - +<<< DEMO ./demo/UseModalBasic.vue ### Reactivity Within `create` `create` props property can accept a `MaybeRef`, meaning that you can make properties reactive - - Click me - - - +<<< DEMO ./demo/UseModalReactive.vue ### Advanced Creation @@ -106,51 +40,11 @@ Using props can work for most situations, but it leaves some finer control to be You can also use component slots to render what you want. This is done through the `slots` property. The `slots` property is an object that contains the slot name as the key and a render function or component as the value. The render function is passed a `scope` object that contains the slots scope. - - Click me - - - +<<< DEMO ./demo/UseModalAdvanced.vue ### Return Value -The `create` method returns a promise that resolves after the modal has been hidden to a `BvTriggerableEvent` object. +The `create` method returns a promise that resolves after the modal has been hidden to a `BvTriggerableEvent` object. Using the `resolveOnHide` option (in the second argument), the promise resolves at the time the modal begins hiding, rather than after it is fully hidden. ```js @@ -211,99 +105,9 @@ await using modal = create({title: 'Hello World!'}) In addition to creating modals in a global context, you can also hide modals from anywhere in the app. This feature does not require an orchestrator component to be present. - - Open First Modal - - - - - diff --git a/apps/docs/src/docs/composables/usePopover.md b/apps/docs/src/docs/composables/usePopover.md index 07f0a8565..eaaababce 100644 --- a/apps/docs/src/docs/composables/usePopover.md +++ b/apps/docs/src/docs/composables/usePopover.md @@ -14,19 +14,7 @@ To use `usePopover`, you need one of the following setup approaches: The easiest way is to wrap your application with the `BApp` component, which automatically sets up the orchestrator and registry: - - - +<<< FRAGMENT ./demo/UsePopoverSetup.vue ### Plugin Setup (Legacy) @@ -40,88 +28,19 @@ Note: As of v0.40, there are no separate toast/modal/popover controller plugins. Popovers and tooltips can be created using the `popover` or `tooltip` methods: - - Hover me - - - +<<< DEMO ./demo/UsePopoverBasic.vue ### Reactivity Within `popover` and `tooltip` The methods accept reactive properties using `MaybeRef`, allowing dynamic updates to the popover content. - - Hover me - - - +<<< DEMO ./demo/UsePopoverReactive.vue ### Advanced Creation For more control, you can use the `component` property to render a custom component or the `slots` property to define slot content dynamically. - - Hover me - - - +<<< DEMO ./demo/UsePopoverAdvanced.vue ### Return Value @@ -138,50 +57,13 @@ The `popover` and `tooltip` methods return an awaitable controller `PromiseWithC By default, the popover is destroyed when the current scope is exited. You can manually destroy it using the `destroy` method. -```js -const pop = popover({title: 'Hello World!'}) -pop.show() -// do something -pop.destroy() -``` +<<< FRAGMENT ./demo/UsePopoverLifecycleManual.ts#snippet{ts} Alternatively, use `await using` in TypeScript 5.2+ to automatically destroy the popover when the scope is exited. -```js -await using pop = popover({title: 'Hello World!'}) -``` +<<< FRAGMENT ./demo/UsePopoverLifecycleAwaitUsing.ts#snippet{ts} diff --git a/apps/docs/src/docs/composables/useToast.md b/apps/docs/src/docs/composables/useToast.md index 0d78bf633..18417e99a 100644 --- a/apps/docs/src/docs/composables/useToast.md +++ b/apps/docs/src/docs/composables/useToast.md @@ -14,19 +14,7 @@ To use `useToast`, you need one of the following setup approaches: The easiest way is to wrap your application with the `BApp` component, which automatically sets up the orchestrator and registry: - - - +<<< FRAGMENT ./demo/UseToastSetup.vue#template{vue-html} ### Plugin Setup (Legacy) @@ -38,24 +26,7 @@ Alternatively, you can use the traditional plugin approach. Creating and showing a toast is simple: - - Show - - +<<< DEMO ./demo/UseToastBasic.vue The `create` method returns a `promise` that is resolved then the toast closes. You can give toast a unique id. Since `Toasts` are fluid and can move around a lot, returning the index at a given point in time is not ideal for as its position may be changed in the array. So, for use with the `remove` method, you need to give a unique identifier @@ -71,261 +42,26 @@ Optional second argument can be passed to `create` to some options: `keep` and ` `create` props property can accept a `MaybeRefOrGetter`, meaning that you can make properties reactive - - Show - - +<<< DEMO ./demo/UseToastReactive.vue ### Advanced usage -Using props can work for most situations, but it leaves some finer control to be desired. For instance, you can add HTML to any `slot` value. This can either be an imported SFC or an inline render function. For reactvity, you must use a getter function. - - - Show - - +<<< DEMO ./demo/UseToastAdvanced.vue ## Programmatically Hiding a Toast -Hiding a `Toast` programmatically is very simple. `create` return an object that has functions to control the toast, including `destroy` - - - - - Show the Toast - - - Hide the Toast - - - +Hiding a `Toast` programmatically is very simple. `create` returns an object that has functions to control the toast, including `destroy` - +<<< DEMO ./demo/UseToastProgrammatic.vue ## Using promises Hiding a `Toast` with promise - - - - Show the Toast - - - - - - - diff --git a/apps/docs/src/docs/composables/useToggle.md b/apps/docs/src/docs/composables/useToggle.md index 9ae2e7d93..56c9ccdd3 100644 --- a/apps/docs/src/docs/composables/useToggle.md +++ b/apps/docs/src/docs/composables/useToggle.md @@ -34,98 +34,14 @@ const {hide} = useToggle() You can also provide an id to get particular component and show/hide it. Currently, we do not support using CSS selector to find modal since the component in lazy mode may not render at page initial. If the modal component does not exist and you attempt to call any of the exposed methods, the methods will safely no-op without throwing errors. - -Click me - - Hide me - - - +<<< DEMO ./demo/UseToggleWithId.vue ## Promise Flow The `show` and `toggle` methods take a boolean argument to control wether to resolve the promise on show (`false`) or on hide (`true`). On `show` the promise resolves to `true` when shown and to `'show-prevented'` if show is prevented. On `hide` the promise resolves to the trigger that caused the hide event. The promise can be awaited to get the result. - - Click me - content - Close reason: {{ reason }} - - - +<<< DEMO ./demo/UseTogglePromise.vue From 667ea2b866bdaf5beddddb1cc69a2108596fc60d Mon Sep 17 00:00:00 2001 From: "David W. Gray" Date: Thu, 23 Oct 2025 09:55:23 -0700 Subject: [PATCH 02/13] docs(BPlaceholder): Parity pass (#2886) --- .../src/data/components/placeholder.data.ts | 36 +++++++++---------- apps/docs/src/docs/components/placeholder.md | 13 +++++-- apps/docs/src/docs/migration-guide.md | 8 +++++ 3 files changed, 37 insertions(+), 20 deletions(-) diff --git a/apps/docs/src/data/components/placeholder.data.ts b/apps/docs/src/data/components/placeholder.data.ts index d9956dd06..17173c8a9 100644 --- a/apps/docs/src/data/components/placeholder.data.ts +++ b/apps/docs/src/data/components/placeholder.data.ts @@ -21,7 +21,7 @@ export default { }, cols: { type: 'Numberish', - default: 12, // TODO item not in string format + default: 12, }, size: { type: 'PlaceholderSize', @@ -32,8 +32,8 @@ export default { default: 'span', }, variant: { - type: 'ColorVariant | null', - default: null, // TODO item not in string format + type: 'BgColorVariant | null', + default: null, }, width: { type: 'Numberish', @@ -69,7 +69,7 @@ export default { }, footerWidth: { type: 'Numberish', - default: 100, // TODO item not in string format + default: 100, }, headerAnimation: { type: 'PlaceholderAnimation', @@ -85,7 +85,7 @@ export default { }, headerWidth: { type: 'Numberish', - default: 100, // TODO item not in string format + default: 100, }, imgBlankColor: { type: 'string', @@ -97,7 +97,7 @@ export default { }, imgHeight: { type: 'Numberish', - default: 100, // TODO item not in string format + default: 100, }, imgSrc: { type: 'string', @@ -105,19 +105,19 @@ export default { }, noButton: { type: 'boolean', - default: false, // TODO item not in string format + default: false, }, noFooter: { type: 'boolean', - default: false, // TODO item not in string format + default: false, }, noHeader: { type: 'boolean', - default: false, // TODO item not in string format + default: false, }, noImg: { type: 'boolean', - default: false, // TODO item not in string format + default: false, }, size: { type: 'PlaceholderSize', @@ -155,7 +155,7 @@ export default { loading: { description: 'Determines whether the loading slot is displayed', type: 'boolean', - default: false, // TODO item not in string format + default: false, }, } satisfies PropRecord, emits: {}, @@ -180,11 +180,11 @@ export default { }, cellWidth: { type: 'Numberish', - default: 100, // TODO item not in string format + default: 100, }, columns: { type: 'Numberish', - default: 5, // TODO item not in string format + default: 5, }, footerAnimation: { type: 'PlaceholderAnimation', @@ -192,7 +192,7 @@ export default { }, footerCellWidth: { type: 'Numberish', - default: 100, // TODO item not in string format + default: 100, }, footerColumns: { type: 'Numberish', @@ -212,7 +212,7 @@ export default { }, headerCellWidth: { type: 'Numberish', - default: 100, // TODO item not in string format + default: 100, }, headerColumns: { type: 'Numberish', @@ -228,15 +228,15 @@ export default { }, noHeader: { type: 'boolean', - default: false, // TODO item not in string format + default: false, }, rows: { type: 'Numberish', - default: 3, // TODO item not in string format + default: 3, }, showFooter: { type: 'boolean', - default: false, // TODO item not in string format + default: false, }, size: { type: 'PlaceholderSize', diff --git a/apps/docs/src/docs/components/placeholder.md b/apps/docs/src/docs/components/placeholder.md index f8429a543..5225b2c63 100644 --- a/apps/docs/src/docs/components/placeholder.md +++ b/apps/docs/src/docs/components/placeholder.md @@ -2,7 +2,8 @@ -Placeholders are components that indicate that something may still be loading. +Placeholders are components that allows you to display a loading state for +several component types while your data is being fetched or computed. @@ -22,7 +23,9 @@ You can adjust the width using props `width` and `cols`. Cols is a number value Bootstrap supports two types of animations, `wave` and `glow`. -- Note: when using `BPlaceholderCard`, the image does not inherit an animation +::: info NOTE +When using `BPlaceholderCard`, the image does not inherit an animation +::: <<< DEMO ./demo/PlaceholderAnimation.vue#template{vue-html} @@ -84,6 +87,12 @@ Optionally, you can manually adjust any scope of the table using slots. The foll <<< DEMO ./demo/PlaceholderTableAdvanced.vue#template{vue-html} +## Styling and customization + +The `` component and helper components utilize Bootstrap SCSS variables, as much as +possible to best match the styling and sizing of the native components. This means if you've +customized Bootstrap SCSS, the skeleton components should adapt to fit your custom theming. + diff --git a/apps/docs/src/docs/components/demo/ToastPositioning.vue b/apps/docs/src/docs/components/demo/ToastPositioning.vue index 6b2481e2f..32e561ae0 100644 --- a/apps/docs/src/docs/components/demo/ToastPositioning.vue +++ b/apps/docs/src/docs/components/demo/ToastPositioning.vue @@ -3,7 +3,10 @@ v-for="(pos, index) in values" :key="index" > - + {{ locations[index] }} diff --git a/apps/docs/src/docs/components/toast.md b/apps/docs/src/docs/components/toast.md index 728b61564..f77d6149b 100644 --- a/apps/docs/src/docs/components/toast.md +++ b/apps/docs/src/docs/components/toast.md @@ -6,17 +6,33 @@ Push notifications to your visitors with `BToast`, `useToast` and `BOrchestrator -Toasts are lightweight notifications designed to mimic the push notifications that have been popularized by mobile and desktop operating systems. Toasts are intended to be small interruptions to your visitors or users and therefore should contain minimal, to-the-point, non-interactive content. Please refer to the Accessibility Tips section below for important usage information +Toasts are lightweight notifications designed to mimic the push notifications that have been popularized by mobile and desktop operating systems. + +Toasts are intended to be small interruptions to your visitors or users and therefore should contain minimal, to-the-point, non-interactive content. Please refer to the Accessibility Tips section below for important usage information ## Overview -This section only refers to using the raw component variation. Oftentimes, `Toasts` are generated in a global context programmatically, like showing a success message after saving a form. That functionality is covered under the composable docs [here](/docs/composables/useToast) +This section only refers to using the raw component variation. `Toasts` are often generated in a global context programmatically, like showing a success message after saving a form. That functionality is covered under the [composable docs](/docs/composables/useToast) The component variation is shown by using the `v-model` like so <<< DEMO ./demo/ToastOverview.vue -By default Toasts are rendered in place. You can use Vue's `Teleport` to change the location, commonly to `body` +By default Toasts are rendered in place. You can use Vue's `Teleport` to change the location, commonly to `body` or, more +commonly, create toasts using the [useToast](/docs/composables/useToast) composable. + +### Toast features and notes + +- Toasts can be generated programmatically via the `useToast` composable, or manually created using the `` component. +- Titles are optional but recommended for accessibility. Titles are rendered inside a `` element unless using the `title` slot. +- The close button can be hidden via the `no-close-button` prop. +- A title bar is shown when a title is provided, unless both title and close button are hidden. +- Auto-dismissing is controlled by setting `model-value` to a number of milliseconds. No default auto-hide duration. +- When auto-hide is enabled, hovering over the toast pauses the countdown. This can be disabled with the `no-hover-pause` prop. +- Toast transparency can be disabled by setting the `solid` prop to `true`. +- Toasts use Vue's `Teleport` component for positioning. By default, toasts created with `useToast` are teleported to the body. +- Toasts include built-in progress bar support via the `progress-props` prop when using timed dismissal. +- Toasts support `BLink` integration for interactive toast bodies. ## Positioning @@ -32,15 +48,24 @@ You can place toasts in static placements, and with more control by using them d ## Auto-dismissing Toasts -To create a `BToast` that dismisses automatically after a specified duration, set the `modelValue` prop to the number of **milliseconds** you want the `BToast` to remain visible. By default, the timer updates on every browser frame via `requestAnimationFrame` (roughly every 16 ms). To throttle updates for example to once per second—set the `interval` prop to `1000` (or any millisecond value). Timed Toasts automatically pause when hovered over with a mouse, but you can disable this behavior using the `noHoverPause` prop. Ensure that the `modelValue` is an integer representing milliseconds. Any change to the `modelValue` will reset the timer. +To create a `BToast` that dismisses automatically after a specified duration, set the `model-value` prop to the number of **milliseconds** you want the `BToast` to remain visible. By default, the timer updates on every browser frame via `requestAnimationFrame` (roughly every 16 ms). To throttle updates for example to once per second—set the `interval` prop to `1000` (or any millisecond value). Timed Toasts automatically pause when hovered over with a mouse, but you can disable this behavior using the `no-hover-pause` prop. Ensure that the `model-value` is an integer representing milliseconds. Any change to the `model-value` will reset the timer. -The **interval** prop determines how frequently the timer updates. While the default is `requestAnimationFrame`, you can set a custom interval. Negative values for either `modelValue` or `interval` will stop the timer. If the `modelValue` does not divide evenly by the interval, the timer will continue to the nearest interval. For example, a `modelValue` of 5400 ms with an interval of 1000 ms will run for 6000 ms. To avoid this, choose an interval that divides evenly into the `modelValue`, such as 540 ms or 1080 ms. +The **interval** prop determines how frequently the timer updates. While the default is `requestAnimationFrame`, you can set a custom interval. Negative values for either `model-value` or `interval` will stop the timer. If the `model-value` does not divide evenly by the interval, the timer will continue to the nearest interval. For example, a `model-value` of 5400 ms with an interval of 1000 ms will run for 6000 ms. To avoid this, choose an interval that divides evenly into the `model-value`, such as 540 ms or 1080 ms. <<< DEMO ./demo/ToastAutoDismiss.vue +### Toast roles + +Toasts are rendered with a default `role` attribute of `'alert'` and `aria-live` attribute of +`'assertive'`. For toasts that are meant for a casual notification, set the `is-status` prop to +`true`, which will change the `role` and `aria-live` attributes to `'status'` and `'polite'` +respectively. + +For more information, please see the [Accessibility](#accessibility) section below. + ### ProgressBar Integration -As you may have noticed in that example, there was a built-in progress bar. This is triggered when using a value that is a `number` and when `progressProps` is not `undefined`. This was implemented because it can be difficult to modify the behavior of `BToast` when using a pure method, and the appearance of a ticking down progress bar is a "nice to have". Although it is not out of the box behavior by Bootstrap, its behavior is opt-in. This functions similarly to examples in `BAlert` +As you may have noticed in that example, there was a built-in progress bar. This is triggered when using a value that is a `number` and when `progress-props` is not `undefined`. This was implemented because it can be difficult to modify the behavior of `BToast` when using a pure method, and the appearance of a ticking down progress bar is a "nice-to-have". Although it is not out of the box behavior by Bootstrap, its behavior is opt-in. This functions similarly to examples in `BAlert` ## BLink Integration @@ -58,6 +83,43 @@ Toasts are intended to be **small interruptions** to your visitors or users, so If you just need a single simple message to appear along the bottom or top of the user's window, use a fixed position `BAlert` instead. +### Accessibility tips + +Typically, toast messages should display one or two-line non-critical messages that **do not** +require user interaction. Without taking extra steps, toasts can have numerous accessibility issues +that can impact both people with and without disabilities. The following list, while not complete, +provides general guidelines when using toasts. + +- If the information needed is important for the process, e.g. for a list of errors in a form, then + use the [``](/docs/components/alert) component instead of ``. +- ``, by default, sets the attributes `role` to `'alert'` and `aria-live` to `'assertive'`. + If it's an important message like an error, this default setting is appropriate, otherwise set the + prop `is-status` to `true` which will change the attributes `role` to `'status'` and `aria-live` + to `'polite'`. +- Avoid popping up a toast message on page load. Performing unexpected actions on page load is very + confusing to screen reader users. If a toast is needed on page load or route change, delay showing + the toast by several seconds so that the screen reader will finish announcing information about + the current page without interruption by the toast. +- When the toast is persistently visible (i.e., when `model-value` is set to `true` and the toast does not auto-dismiss), you must have a close button to allow users to dismiss + the toast. If you have also set the prop `no-close-button` to `true`, you must provide your own close + button or dismiss the toast by some other means. Toasts have a tab index of `0` so that they can + be reached by keyboard-only users. If `model-value` is set to `false`, the toast is not visible and no close button is required. +- Avoid initiating many toasts in quick succession, as screen readers may interrupt reading the + current toast and announce the new toast, causing the context of the previous toast to be missed. +- For toasts with long textual content, set `model-value` to a larger timeout value, to allow + users time to read the content of the toast. The average person reads about 200 words per minute, + so a good length of time to keep messages up is 5 seconds, plus 300 extra milliseconds per word. + The shortest default that should be used as a best practice is 5 seconds (5000ms). In addition to + a reasonable default timeout, you could also allow the user to choose how long they want toasts to + stay up for. Most people inherently understand whether they are fast or slow readers. Having a + profile setting that is part of the user login will allow slow readers to pick a longer time if + the messages are going away too fast, and fast readers to pick a short time if the messages are + staying up too long. +- To account for memory loss and distraction as well as disability-related issues such as ADHD, a + best practice would be to implement a location where users can refer to a list of past toast + messages which have been shown. Preferably this list should be sortable, with the default being + chronological. + diff --git a/apps/docs/src/docs/migration-guide.md b/apps/docs/src/docs/migration-guide.md index 7d01da531..5a8d5bc49 100644 --- a/apps/docs/src/docs/migration-guide.md +++ b/apps/docs/src/docs/migration-guide.md @@ -730,34 +730,11 @@ The scoped variables available to modal slots have changed between BootstrapVue **BootstrapVue slot scope:** -```typescript -{ - ok: () => void, // Closes modal with trigger 'ok' - cancel: () => void, // Closes modal with trigger 'cancel' - close: () => void, // Closes modal with trigger 'headerclose' - hide: (trigger?: string) => void, // Closes modal with custom trigger - visible: boolean // Boolean visibility state -} -``` +<<< FRAGMENT ./demo/ModalSlotScopeBootstrapVue.ts#snippet{typescript} **BootstrapVueNext slot scope (BModalSlotsData):** -```typescript -interface BModalSlotsData extends ShowHideSlotsData { - cancel: () => void // Closes modal with trigger 'cancel' - close: () => void // Closes modal with trigger 'close' (note: 'close' not 'headerclose') - ok: () => void // Closes modal with trigger 'ok' -} - -interface ShowHideSlotsData { - id: string // Modal ID string - show: () => void // Show the modal - hide: (trigger?: string, noTriggerEmit?: boolean) => void // Enhanced hide method - toggle: () => void // Toggle modal visibility - active: boolean // Boolean - true when modal is active/visible - visible: boolean // Boolean - same as active, for compatibility -} -``` +<<< FRAGMENT ./demo/ModalSlotScopeBootstrapVueNext.ts#snippet{typescript} **Key changes:** @@ -1036,10 +1013,109 @@ The `changed` event on `BTabs` is deprecated. ### BToast - +#### Global Toast Management System Changes + +**`$bvToast` instance methods are deprecated:** + +- `this.$bvToast.show(options)` → Use `useToast` composable with `create()` method +- `this.$bvToast.hide(target)` → Use `useToast` composable or template refs with `.hide()` +- `this.$bvToast.hideAll()` → Use `useToast` composable + +**Named toaster system is deprecated:** + +- `` targets → Use Vue's `Teleport` component or `useToast` positioning +- Toaster positioning CSS → Use CSS positioning on individual toasts or toast containers + +**Alternative approaches:** + +Please see [useToast](/docs/composables/useToast) for the modern method of programmatically creating and managing toasts. + +#### Props Changes + +**Renamed props:** + +- `visible` → `model-value` - Controls both visibility and auto-dismiss timing (replaces separate `visible` model) +- `no-auto-hide` → Set `model-value` to `false` or `true` (boolean) instead of using auto-hide duration +- `auto-hide-delay` → Set `model-value` to number of milliseconds for auto-dismiss duration + +**Removed props (not implemented in BootstrapVueNext):** + +- `href` and `to` - Use `useToast` with BLink props or see [BLink Integration](/docs/components/toast#blink-integration) in the toast documentation +- `toaster` - Use `Teleport` or `useToast` positioning instead +- `append-toast` - Available on `BOrchestrator` and `useToast` instead +- `b-toaster-*` related props - Use modern positioning with `Teleport` +- `static` - BToast renders in place by default (no teleporting behavior) + +**New props in BootstrapVueNext:** + +- `progress-props` - Configure built-in progress bar for timed toasts +- `no-progress` - Hide progress bar on timed toasts +- `show-on-pause` - Control visibility when countdown is paused +- `interval` - Control countdown timer update frequency (default: `'requestAnimationFrame'`) +- `solid` - Disable toast transparency (same as BootstrapVue) + +#### Auto-dismiss Behavior Changes + +**BootstrapVue:** Used separate props for auto-hide configuration: + +<<< FRAGMENT ./demo/ToastBootstrapVue.vue#snippet{vue-html} + +**BootstrapVueNext:** Uses `model-value` for both visibility and auto-dismiss: + +<<< FRAGMENT ./demo/ToastBootstrapVueNext.vue#snippet{vue-html} + +#### Event System Changes + +**Event naming changes:** + +- No `$root` event system - toasts are managed through composables or direct component references +- All events now use the standardized show/hide event lifecycle + +**New events:** BootstrapVueNext adds several events: + +- `close-countdown` - Emitted during countdown with remaining milliseconds +- `update:model-value` - Standard v-model event for visibility/duration changes +- Standard show/hide lifecycle events: `show`, `shown`, `hide`, `hidden`, `show-prevented`, `hide-prevented`, `toggle`, `toggle-prevented` + +#### Slots Changes + +**Renamed slots:** + +- `toast-title` → `title` - Toast header title content + +**Available slots:** + +- `default` - Toast body content (enhanced with slot scope data) +- `title` - Toast header title content (was `toast-title` in BootstrapVue) +- `close` - Custom close button content (new in BootstrapVueNext) + +**Enhanced slot scope:** All slots now receive scope data with control functions: + +- `id` - Toast component ID +- `show()` - Function to show the toast +- `hide()` - Function to hide the toast +- `toggle()` - Function to toggle visibility +- `visible` - Current visibility state +- `active` - Whether countdown timer is active + +#### Accessibility Improvements + +**Enhanced ARIA support:** + +- `isStatus` prop correctly toggles between `role="alert"` (default) and `role="status"` +- Corresponding `aria-live` values: `"assertive"` (default) and `"polite"` +- `aria-atomic="true"` automatically applied for better screen reader announcements +- `tabindex="0"` for keyboard accessibility See [Show and Hide](#show-and-hide) shared properties. +### BToaster + +The `BToaster` component has been deprecated. Its functionality has been replaced by the +[`useToast`](/docs/composables/useToast) composable working in concert with the +[`BOrchestrator`](/docs/components/orchestrator) component. See the documentation for +details. + ### BTooltip See [Show and Hide](#show-and-hide) shared properties. diff --git a/apps/docs/src/utils/commonProps.ts b/apps/docs/src/utils/commonProps.ts index 338f7170b..058cc38b1 100644 --- a/apps/docs/src/utils/commonProps.ts +++ b/apps/docs/src/utils/commonProps.ts @@ -458,11 +458,52 @@ const commonProps = () => default: undefined, description: 'CSS class (or classes) to add to the wrapper element', }, + closeClass: { + type: 'ClassValue', + default: undefined, + description: 'CSS class (or classes) to apply to the close button', + }, + closeContent: { + type: 'string', + default: undefined, + description: 'Sets the text for the close button. The `close` slot takes precedence', + }, + closeLabel: { + type: 'string', + default: 'Close', + description: 'Sets the `aria-label` attribute for the close button', + }, + closeVariant: { + type: 'ButtonVariant | null', + default: null, + description: 'Sets the color variant for the close button', + }, + interval: { + type: 'number | "requestAnimationFrame"', + default: 'requestAnimationFrame', + description: 'Sets the interval for refreshing the countdown timer', + }, + isStatus: { + type: 'boolean', + default: false, + description: + 'When set to `true`, sets `aria-live="polite"` and `role="status"`; otherwise, `aria-live="assertive"` and `role="alert"`', + }, placement: { type: 'Placement', default: 'bottom-start', description: 'Placement of a floating element', }, + progressProps: { + type: "Omit", + default: undefined, + description: 'Configures the progress bar. No progress bar is shown if undefined', + }, + showOnPause: { + type: 'boolean', + default: true, + description: 'Keeps the component visible when paused', + }, }) as const const singletonProps = Object.freeze(commonProps()) diff --git a/apps/docs/src/utils/dropdownCommon.ts b/apps/docs/src/utils/dropdownCommon.ts index ecca2d3c1..541e85945 100644 --- a/apps/docs/src/utils/dropdownCommon.ts +++ b/apps/docs/src/utils/dropdownCommon.ts @@ -169,14 +169,6 @@ export const dropdownEmits = { 'toggle': { description: 'Emitted when toggle button is clicked', }, - 'cancel': { - args: undefined, - description: undefined, - }, - 'ok': { - args: undefined, - description: undefined, - }, } as const satisfies EmitRecord export const dropdownSlots = { diff --git a/apps/docs/src/utils/popover-shared.ts b/apps/docs/src/utils/popover-shared.ts index 46b2f4faf..0ffd42e84 100644 --- a/apps/docs/src/utils/popover-shared.ts +++ b/apps/docs/src/utils/popover-shared.ts @@ -242,12 +242,4 @@ const sharedEmits = { }, }, }, - 'cancel': { - args: undefined, - description: undefined, - }, - 'ok': { - args: undefined, - description: undefined, - }, } satisfies EmitRecord diff --git a/apps/docs/src/utils/showHideData.ts b/apps/docs/src/utils/showHideData.ts index 4b15a47a1..6aa0f41e8 100644 --- a/apps/docs/src/utils/showHideData.ts +++ b/apps/docs/src/utils/showHideData.ts @@ -1,7 +1,15 @@ import type {showHide} from 'bootstrap-vue-next' -import type {EmitRecord, PropRecord, SlotScopeReference} from '../types' +import type {PropRecord, SlotScopeReference} from '../types' export const showHideEmits = { + 'cancel': { + args: { + value: { + type: 'BvTriggerableEvent', + }, + }, + description: 'Emitted when a cancel action is triggered.', + }, 'hide': { description: "Always emits just before the component has hidden. Cancelable (as long as component wasn't forcibly hidden)", @@ -29,6 +37,14 @@ export const showHideEmits = { }, description: 'Always emits after the component is hidden', }, + 'ok': { + args: { + value: { + type: 'BvTriggerableEvent', + }, + }, + description: 'Emitted when an ok action is triggered.', + }, 'show': { args: { value: { @@ -74,7 +90,7 @@ export const showHideEmits = { description: 'Emitted when the component tried to toggle, but was prevented from doing so. This occurs when preventDefault() is called on the event, the user clicks escape and no-close-onbackdrop is set to true, or the user clicks on the backdrop and no-close-onbackdrop is set to true.', }, -} as const satisfies EmitRecord +} as const export const showHideProps = { initialAnimation: { @@ -152,3 +168,39 @@ export const showHideSlotsData = { description: 'Indicates if the component is visible (shown)', }, } as const satisfies SlotScopeReference + +/** + * Builds common emits for dismissible components with close and countdown functionality + * (currently used by BAlert and BToast) + */ +export const buildDismissibleEmits = () => + ({ + ...showHideEmits, + 'update:model-value': { + description: 'Emitted when the component visibility changes.', + args: { + value: { + type: 'Boolean', + description: 'The new visibility state of the component.', + }, + }, + }, + 'close': { + description: 'Emitted when the close button is clicked.', + args: { + value: { + type: 'BvTriggerableEvent', + description: 'The event object for the close button click.', + }, + }, + }, + 'close-countdown': { + description: 'Emitted during the countdown to auto-dismiss.', + args: { + value: { + type: 'number', + description: 'The remaining time in milliseconds before auto-dismissal.', + }, + }, + }, + }) as const From 87ceb85b2eb6b1e7ae3d59f67a0804e2afe8254a Mon Sep 17 00:00:00 2001 From: "David W. Gray" Date: Wed, 5 Nov 2025 16:34:20 -0800 Subject: [PATCH 05/13] docs: refactor docs to avoid duplication and boilerplate code (#2891) * docs: share description text between composables index page heading of individual pages * docs: share descriptions in composables * docs: share descriptions in directives doc * docs: clean up some bootstrap v4 references * docs: remove neeed to include explicit source path in documentation * docs: infer source code base path * docs: get rid of manual enumeration of components, etc. * docs: auto generate the header for our core doc files * docs: auto-generate configuration reference in docs * docs: auto-generate headers for customizations directory * docs: infer sourcePath in component reference * docs: update contribution guide to describe documentation format * docs: react to code review comments * Update apps/docs/.vitepress/plugins/auto-inject-doc-components.ts * docs: fix build issue * docs: add the references files into the set of files that header are auto-injected * docs: get root level documents using auto header injections * docs: make the index.md page use front matter as well * docs: fix remaining issues from code review * docs: remove spurious newlines --- .markdownlint.json | 5 +- CONTRIBUTING.md | 270 +++++++++++++++++- apps/docs/.vitepress/config.mts | 2 + .../plugins/auto-inject-doc-components.ts | 137 +++++++++ apps/docs/eslint.config.mjs | 9 +- apps/docs/package.json | 2 + .../src/components/ComponentReference.vue | 34 ++- apps/docs/src/components/PageHeader.vue | 117 +++++++- .../src/components/TableOfContentsCard.vue | 17 +- .../src/components/TableOfContentsNav.vue | 135 +++------ .../src/composables/useMarkdownRenderer.ts | 45 +++ apps/docs/src/data/components.data.ts | 16 ++ .../src/data/components/accordion.data.ts | 2 - apps/docs/src/data/components/alert.data.ts | 1 - apps/docs/src/data/components/app.data.ts | 1 - apps/docs/src/data/components/avatar.data.ts | 2 - apps/docs/src/data/components/badge.data.ts | 1 - .../src/data/components/breadcrumb.data.ts | 2 - apps/docs/src/data/components/button.data.ts | 2 - .../src/data/components/buttonGroup.data.ts | 2 +- .../src/data/components/buttonToolbar.data.ts | 2 +- apps/docs/src/data/components/card.data.ts | 9 - .../docs/src/data/components/carousel.data.ts | 2 - .../docs/src/data/components/collapse.data.ts | 1 - .../docs/src/data/components/dropdown.data.ts | 8 - apps/docs/src/data/components/form.data.ts | 7 - .../src/data/components/formCheckbox.data.ts | 2 - .../docs/src/data/components/formFile.data.ts | 3 +- .../src/data/components/formGroup.data.ts | 1 - .../src/data/components/formInput.data.ts | 1 - .../src/data/components/formRadio.data.ts | 4 +- ...{FormRating.data.ts => formRating.data.ts} | 1 - .../src/data/components/formSelect.data.ts | 7 +- .../data/components/formSpinbutton.data.ts | 1 - .../docs/src/data/components/formTags.data.ts | 6 +- .../src/data/components/formTextarea.data.ts | 1 - .../src/data/components/gridSystem.data.ts | 3 - apps/docs/src/data/components/image.data.ts | 1 - .../src/data/components/inputGroup.data.ts | 2 - apps/docs/src/data/components/link.data.ts | 1 - .../src/data/components/listGroup.data.ts | 5 +- apps/docs/src/data/components/modal.data.ts | 1 - apps/docs/src/data/components/nav.data.ts | 5 - apps/docs/src/data/components/navbar.data.ts | 4 - .../src/data/components/offcanvas.data.ts | 1 - .../src/data/components/orchestrator.data.ts | 1 + apps/docs/src/data/components/overlay.data.ts | 1 - .../src/data/components/pagination.data.ts | 1 - .../src/data/components/placeholder.data.ts | 5 - apps/docs/src/data/components/popover.data.ts | 1 - .../docs/src/data/components/progress.data.ts | 2 - apps/docs/src/data/components/spinner.data.ts | 1 - apps/docs/src/data/components/table.data.ts | 9 - apps/docs/src/data/components/tabs.data.ts | 72 ++--- apps/docs/src/data/components/toast.data.ts | 1 - apps/docs/src/data/components/tooltip.data.ts | 11 +- apps/docs/src/data/composables.data.ts | 16 ++ apps/docs/src/data/configurations.data.ts | 16 ++ apps/docs/src/data/directives.data.ts | 16 ++ apps/docs/src/data/reference.data.ts | 16 ++ apps/docs/src/docs/components.md | 220 +------------- apps/docs/src/docs/components/accordion.md | 16 +- apps/docs/src/docs/components/alert.md | 16 +- apps/docs/src/docs/components/app.md | 16 +- apps/docs/src/docs/components/avatar.md | 23 +- apps/docs/src/docs/components/badge.md | 16 +- apps/docs/src/docs/components/breadcrumb.md | 16 +- apps/docs/src/docs/components/button-group.md | 16 +- .../src/docs/components/button-toolbar.md | 12 +- apps/docs/src/docs/components/button.md | 16 +- apps/docs/src/docs/components/card.md | 16 +- apps/docs/src/docs/components/carousel.md | 23 +- apps/docs/src/docs/components/collapse.md | 21 +- apps/docs/src/docs/components/dropdown.md | 16 +- .../docs/src/docs/components/form-checkbox.md | 16 +- apps/docs/src/docs/components/form-file.md | 16 +- apps/docs/src/docs/components/form-group.md | 16 +- apps/docs/src/docs/components/form-input.md | 16 +- apps/docs/src/docs/components/form-radio.md | 16 +- apps/docs/src/docs/components/form-rating.md | 24 +- apps/docs/src/docs/components/form-select.md | 16 +- .../src/docs/components/form-spinbutton.md | 16 +- apps/docs/src/docs/components/form-tags.md | 16 +- .../docs/src/docs/components/form-textarea.md | 16 +- apps/docs/src/docs/components/form.md | 21 +- apps/docs/src/docs/components/grid-system.md | 17 +- apps/docs/src/docs/components/image.md | 16 +- apps/docs/src/docs/components/input-group.md | 16 +- apps/docs/src/docs/components/link.md | 16 +- apps/docs/src/docs/components/list-group.md | 16 +- apps/docs/src/docs/components/modal.md | 16 +- apps/docs/src/docs/components/nav.md | 19 +- apps/docs/src/docs/components/navbar.md | 16 +- apps/docs/src/docs/components/offcanvas.md | 16 +- apps/docs/src/docs/components/orchestrator.md | 16 +- apps/docs/src/docs/components/overlay.md | 16 +- apps/docs/src/docs/components/pagination.md | 19 +- apps/docs/src/docs/components/placeholder.md | 19 +- apps/docs/src/docs/components/popover.md | 23 +- apps/docs/src/docs/components/progress.md | 19 +- apps/docs/src/docs/components/spinner.md | 25 +- apps/docs/src/docs/components/table.md | 24 +- apps/docs/src/docs/components/tabs.md | 21 +- apps/docs/src/docs/components/toast.md | 16 +- apps/docs/src/docs/components/tooltip.md | 21 +- apps/docs/src/docs/composables.md | 58 +--- .../src/docs/composables/ComposableHeader.vue | 12 - .../src/docs/composables/useBreadcrumb.md | 14 +- .../docs/src/docs/composables/useColorMode.md | 14 +- apps/docs/src/docs/composables/useModal.md | 13 +- apps/docs/src/docs/composables/usePopover.md | 13 +- .../docs/src/docs/composables/useScrollspy.md | 12 +- apps/docs/src/docs/composables/useToast.md | 14 +- apps/docs/src/docs/composables/useToggle.md | 14 +- apps/docs/src/docs/configurations.md | 35 +-- .../docs/configurations/customizing-styles.md | 4 +- .../src/docs/configurations/global-options.md | 4 +- apps/docs/src/docs/directives.md | 51 +--- apps/docs/src/docs/directives/BColorMode.md | 10 +- apps/docs/src/docs/directives/BModal.md | 8 +- apps/docs/src/docs/directives/BPopover.md | 8 +- apps/docs/src/docs/directives/BToggle.md | 8 +- apps/docs/src/docs/directives/BTooltip.md | 6 +- .../src/docs/directives/DirectiveHeader.vue | 12 - apps/docs/src/docs/icons.md | 13 +- apps/docs/src/docs/migration-guide.md | 5 +- apps/docs/src/docs/reference.md | 91 +----- apps/docs/src/docs/reference/accessibility.md | 16 +- .../docs/src/docs/reference/color-variants.md | 19 +- .../src/docs/reference/form-validation.md | 16 +- apps/docs/src/docs/reference/images.md | 11 +- apps/docs/src/docs/reference/router-links.md | 18 +- apps/docs/src/docs/reference/settings.md | 14 +- .../docs/reference/size-props-and-classes.md | 16 +- .../src/docs/reference/spacing-classes.md | 16 +- .../src/docs/reference/starter-templates.md | 16 +- .../src/docs/reference/theming-bootstrap.md | 16 +- .../docs/reference/third-party-libraries.md | 16 +- .../src/docs/reference/utility-classes.md | 16 +- apps/docs/src/docs/types.md | 11 +- apps/docs/src/index.md | 11 +- apps/docs/src/types/index.ts | 5 +- apps/docs/src/utils/dataLoaderUtils.ts | 84 ++++++ pnpm-lock.yaml | 42 +++ 144 files changed, 1237 insertions(+), 1574 deletions(-) create mode 100644 apps/docs/.vitepress/plugins/auto-inject-doc-components.ts create mode 100644 apps/docs/src/composables/useMarkdownRenderer.ts create mode 100644 apps/docs/src/data/components.data.ts rename apps/docs/src/data/components/{FormRating.data.ts => formRating.data.ts} (98%) create mode 100644 apps/docs/src/data/composables.data.ts create mode 100644 apps/docs/src/data/configurations.data.ts create mode 100644 apps/docs/src/data/directives.data.ts create mode 100644 apps/docs/src/data/reference.data.ts delete mode 100644 apps/docs/src/docs/composables/ComposableHeader.vue delete mode 100644 apps/docs/src/docs/directives/DirectiveHeader.vue create mode 100644 apps/docs/src/utils/dataLoaderUtils.ts diff --git a/.markdownlint.json b/.markdownlint.json index 1f4f89584..4c98f54e2 100644 --- a/.markdownlint.json +++ b/.markdownlint.json @@ -1,4 +1,5 @@ { "MD013": false, - "MD033":false -} \ No newline at end of file + "MD033": false, + "MD041": false +} diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index bdb01da32..169a92f13 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -61,7 +61,155 @@ You can also use `pnpm dev --filter bootstrap-vue-next` to only open the main ho Improving the documentation is a great way to contribute to this project, especially if you're not quite ready to dive into the code. -We use [vitepress](https://vitepress.dev/) to build our documentation in the `./apps/docs` directory. In order to test the docs, first make sure that you follow the steps in [Setting up your workspace](#setting-up-your-workspace). Then you can run `pnpm dev` from the root and then open the **docs:dev** host. This will hot-reload the documentation to let you easily see your edits. The `*.md` files under `./apps/docs/src/docs` contains the core documentation and the `*.data.ts` files under `./apps/docs/src/data/components` contains JSON files that contain the data to build the component definitions in the documentation. +We use [vitepress](https://vitepress.dev/) to build our documentation in the `./apps/docs` directory. In order to test the docs, first make sure that you follow the steps in [Setting up your workspace](#setting-up-your-workspace). Then you can run `pnpm dev` from the root and then open the **docs:dev** host. This will hot-reload the documentation to let you easily see your edits. + +### Documentation File Structure + +- **Markdown files** (`./apps/docs/src/docs/**/*.md`): Contains the main documentation content +- **Data files** (`./apps/docs/src/data/**/*.data.ts`): Contains component/composable/directive/reference/configuration metadata used to auto-generate API reference tables + +### Critical Documentation Conventions + +Our documentation system relies on several conventions to automatically generate headers, footers, and API references. **You must follow these conventions** to ensure the documentation builds correctly: + +#### 1. Frontmatter Requirements + +**All documentation markdown files must include frontmatter** with a `description` field. This description is used in multiple places: + +```yaml +--- +description: A brief, clear description of what this component/composable/directive/reference topic does +--- +``` + +- The description should be concise (1-2 sentences) +- Use YAML folding syntax (`>`) for multi-line descriptions to avoid parsing issues: + +```yaml +--- +description: > + This is a longer description that spans multiple lines. + Use the > character to enable YAML folding syntax. +--- +``` + +- **Never use multi-line quoted strings** in YAML frontmatter as they cause parsing issues + +#### 2. Auto-Generated Headers and Footers + +The documentation system **automatically injects** page headers and component reference footers for **all documentation files** in `./apps/docs/src/docs/`. + +**DO NOT manually add:** + +- `# Page Title` headers (auto-generated from filename) +- `` components (auto-injected from frontmatter) +- `
` sections (replaced by PageHeader) + +The build system will: + +- Auto-generate an `

` title from the filename (e.g., `button-group.md` → "Button Group", `icons.md` → "Icons") +- Auto-inject a `` component with description from frontmatter +- Auto-inject a `` footer for component docs (if a corresponding `.data.ts` file exists) + +If you need to add a `