Skip to content

Commit

Permalink
feat(useModalController): add confirm/show methods to globally create…
Browse files Browse the repository at this point in the history
… modals (bootstrap-vue-next#1701)

refactor: syncref

feat!: required vue 3.4

feat!: rename "Toast" type to OrchestratedToast

feat(useModalController): show/confirm accept reactive inputs

feat(useToast): show to accept reactive inputs

feat(useToast)!: rename "hide" to "remove" to be more in line with useModalController

perf(useToast): use shallowRef

perf(BTabs): more efficient unregisterTab function

feat(useModalController): add confirm/show methods to globally create modals
  • Loading branch information
VividLemon authored Dec 31, 2023
1 parent 6c2c118 commit ca16a16
Show file tree
Hide file tree
Showing 21 changed files with 1,073 additions and 1,698 deletions.
2 changes: 2 additions & 0 deletions apps/docs/.vitepress/theme/Layout.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<template>
<BNavbar variant="primary" sticky="top" toggleable="lg" :container="true" v-b-color-mode="'dark'">
<BToastOrchestrator />
<BModalOrchestrator />
<div class="d-flex gap-2 align-items-center">
<BNavbarToggle v-b-toggle.sidebar-menu />
<BNavbarBrand :to="withBase('/')" class="p-0 me-0 me-lg-2">
Expand Down Expand Up @@ -161,6 +162,7 @@ import {
vBToggle,
vBColorMode,
BToastOrchestrator,
BModalOrchestrator,
} from 'bootstrap-vue-next'
import {inject, ref, computed, watch} from 'vue'
import GithubIcon from '~icons/bi/github'
Expand Down
14 changes: 7 additions & 7 deletions apps/docs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,25 +13,25 @@
},
"devDependencies": {
"@iconify-json/bi": "^1.1.22",
"@iconify-json/simple-icons": "^1.1.85",
"@iconify-json/simple-icons": "^1.1.86",
"@rushstack/eslint-patch": "^1.6.1",
"@tsconfig/node20": "^20.1.2",
"@types/node": "^20.10.5",
"@vue/eslint-config-prettier": "^8.0.0",
"@types/node": "^20.10.6",
"@vue/eslint-config-prettier": "^9.0.0",
"@vue/eslint-config-typescript": "^12.0.0",
"@vue/tsconfig": "^0.5.1",
"@vueuse/core": "^10.7.0",
"@vueuse/core": "^10.7.1",
"bootstrap": "^5.3.2",
"bootstrap-vue-next": "workspace:^",
"cross-env": "^7.0.3",
"eslint": "^8.56.0",
"eslint-define-config": "^2.0.0",
"eslint-define-config": "^2.1.0",
"eslint-plugin-vue": "^9.19.2",
"prettier": "^3.1.1",
"typescript": "^5.3.3",
"unplugin-icons": "^0.18.1",
"vitepress": "1.0.0-rc.32",
"vue": "^3.3.13"
"vitepress": "1.0.0-rc.33",
"vue": "^3.4.3"
},
"lint-staged": {
"*.{js,ts,vue}": "eslint --cache --fix",
Expand Down
12 changes: 0 additions & 12 deletions apps/docs/src/data/package.data.ts

This file was deleted.

16 changes: 10 additions & 6 deletions apps/docs/src/docs.md
Original file line number Diff line number Diff line change
Expand Up @@ -358,13 +358,18 @@ BootstrapVueNext is available through `jsdelivr`. You can add the package by usi

<BCard class="bg-body-tertiary">

```html-vue
<script src="https://cdn.jsdelivr.net/npm/bootstrap-vue-next@{{data.latestVersion}}/dist/bootstrap-vue-next.umd.min.js"></script>
<link href="https://cdn.jsdelivr.net/npm/bootstrap-vue-next@{{data.latestVersion}}/dist/bootstrap-vue-next.min.css" rel="stylesheet">
```html
<script src="https://cdn.jsdelivr.net/npm/bootstrap-vue-next@{{version}}/dist/bootstrap-vue-next.umd.min.js"></script>
<link
href="https://cdn.jsdelivr.net/npm/bootstrap-vue-next@{{version}}/dist/bootstrap-vue-next.min.css"
rel="stylesheet"
/>
```

</BCard>

- **NOTE** Do not forget to set the version!

<BAlert :model-value="true" variant="info">
Links should be loaded after Bootstrap and Vue
</BAlert>
Expand All @@ -373,9 +378,9 @@ Alternatively the ESM package is available as well

<BCard class="bg-body-tertiary">

```html-vue
```html
<script type="module">
import bootstrapVueNext from 'https://cdn.jsdelivr.net/npm/bootstrap-vue-next@{{data.latestVersion}}/+esm'
import bootstrapVueNext from 'https://cdn.jsdelivr.net/npm/bootstrap-vue-next@{{version}}/+esm'
</script>
```

Expand All @@ -392,7 +397,6 @@ BootstrapVue is the parent project for which this is based on. We consider Boots
<script setup lang="ts">
import {BCard, BCardBody, BAlert, BTab, BTabs} from 'bootstrap-vue-next'
import {useLocalStorage} from '@vueuse/core'
import {data} from './data/package.data'

const codePreference = useLocalStorage('code-group-preference', 0)
</script>
4 changes: 4 additions & 0 deletions apps/docs/src/docs/components/modal.md
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,10 @@ const nestedModal3 = ref(false)

To programmatically control your modals with global state, refer to our documentation at [useModal](/docs/composables/useModal) and [useModalController](/docs/composables/useModalController)

### Programmatically Create Modals

To programmatically create modals, refer to the documentation at [useModalController](/docs/composables/useModalController)

<ComponentReference :data="data" />

<script setup lang="ts">
Expand Down
136 changes: 134 additions & 2 deletions apps/docs/src/docs/components/toast.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,31 @@ const {show} = useToast()
</template>
</HighlightCard>

- Note that if the usage of the useToast is inside the same parent component that `BToastOrchestrator` is in, it may not work correctly. Instead, what you will want to do is grab the template ref of the `BToastOrchestrator` and access the exposed functions of it

<HighlightCard>

```vue
<template>
<BToastOrchestrator ref="orchestrator" />
</template>
<script setup lang="ts">
const orchestrator = ref<null | InstanceType<typeof BToastOrchestrator>>(null)
const showToast = () => {
orchestrator.value?.show()
}
</script>
```

</HighlightCard>

## Options

### String

There are two acceptable options for the `show` function. The first set of options is a `string` followed by an `object`. The string corresponds to the body of the `Toast`. If only the string is passed, a simple `Toast` is made, and by default, it is made at the `top-right` and it will expire in `5000` ms. You can pass in an optional `object` for the second parameter where you have a list of options, such as `pos`, `value`, `variant`, etc. Many of the values correspond to props for the `BToast` component. However, some props are taken out as they are reserved
There are three acceptable options for the `show` function. The first set of options is a `string` followed by an `object`. The string corresponds to the body of the `Toast`. If only the string is passed, a simple `Toast` is made, and by default, it is made at the `top-right` and it will expire in `5000` ms. You can pass in an optional `object` for the second parameter where you have a list of options, such as `pos`, `value`, `variant`, etc. Many of the values correspond to props for the `BToast` component. However, some props are taken out as they are reserved

<HighlightCard>
<BButton
Expand Down Expand Up @@ -141,6 +161,89 @@ const {show} = useToast()

</HighlightCard>

### Reactivity within show

All variations of the `show` method accept reactive inputs. Meaning that you can pass in `Ref`s

<HighlightCard>
<BButton
@click="showReactive"
>
Show
</BButton>
<template #html>

```vue
<template>
<BButton @click="showReactive"> Show </BButton>
</template>
<script setup lang="ts">
const {show} = useToast()
const toastShowStr = ref('foo')
setInterval(() => {
toastShowStr.value = toastShowStr.value === 'foo' ? 'bar' : 'foo'
}, 1000)
const showReactive = () => {
show(toastShowStr, () => ({
variant: toastShowStr.value === 'bar' ? 'danger' : 'info',
}))
}
</script>
```

</template>

</HighlightCard>

The third and final variation is discussed next

## Advanced Usage

The third variation of `show` accepts a `component`. Meaning you are capable of manipulating slots directly for more advanced control. This can either be an SFC or direct render function. The following example will use a render function, but to use an SFC, simply import your variation. **NOTE** both SFC and render functions depend on the `destroyed` event being emitted. This is only an issue if your component is wrapped in another element. If it is, you must declare the `destroyed` event with it `symbol`. Similarly, the second, optional parameter is the same object described above

<HighlightCard>
<BButton
@click="showAdvanced"
>
Show
</BButton>
<template #html>

```vue
<template>
<BButton @click="showAdvanced"> Show </BButton>
</template>
<script setup lang="ts">
const {show} = useToast()
const toastVariant = ref<ColorVariant>('danger')
setInterval(() => {
toastVariant.value = toastVariant.value === 'danger' ? 'info' : 'danger'
}, 1000)
const showAdvanced = () => {
show(
h(BToast, null, {
default: () => 'title?',
}),
() => ({
variant: toastVariant.value,
})
)
}
</script>
```

</template>

</HighlightCard>

## Positioning

You can position toasts in all of the typical ways that one would expect from a notification system
Expand Down Expand Up @@ -358,7 +461,7 @@ import {data} from '../../data/components/toast.data'
import ComponentReference from '../../components/ComponentReference.vue'
import {BButtonGroup, BButton, BToast, useToast} from 'bootstrap-vue-next'
import HighlightCard from '../../components/HighlightCard.vue'
import {ref} from 'vue'
import {ref, h} from 'vue'

const {show, hide, toasts} = useToast()

Expand Down Expand Up @@ -392,4 +495,33 @@ const hideMe = () => {
hide(showValue)
showValue = undefined
}

const toastShowStr = ref('foo')

setInterval(() => {
toastShowStr.value = toastShowStr.value === 'foo' ? 'bar' : 'foo'
}, 1000)

const showReactive = () => {
show(toastShowStr, () => ({
variant: toastShowStr.value === 'bar' ? 'danger' : 'info',
}))
}

const toastVariant = ref('danger')

setInterval(() => {
toastVariant.value = toastVariant.value === 'danger' ? 'info' : 'danger'
}, 1000)

const showAdvanced = () => {
show(
h(BToast, null, {
default: () => 'title?',
}),
() => ({
variant: toastVariant.value,
})
)
}
</script>
Loading

0 comments on commit ca16a16

Please sign in to comment.