Merge pull request #46 from themesberg/chank1e/develop
feat: alert system + useToast works
This commit is contained in:
@@ -1,5 +1,13 @@
|
|||||||
<template>
|
<template>
|
||||||
<toast-provider>
|
<toast-provider :transition="transition">
|
||||||
|
<label for="countries" class="block mb-2 text-sm font-medium text-gray-900 dark:text-gray-400">Select transition</label>
|
||||||
|
<select v-model="transition" id="countries" class="mb-2 bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500">
|
||||||
|
<option value="slide-left">Slide left</option>
|
||||||
|
<option value="slide-right">Slide right</option>
|
||||||
|
<option value="slide-top">Slide top</option>
|
||||||
|
<option value="slide-bottom">Slide bottom</option>
|
||||||
|
<option value="fade">Fade</option>
|
||||||
|
</select>
|
||||||
<div class="vp-raw flex align-center gap-2 flex-wrap flex-col">
|
<div class="vp-raw flex align-center gap-2 flex-wrap flex-col">
|
||||||
<toast-provider-example-child />
|
<toast-provider-example-child />
|
||||||
</div>
|
</div>
|
||||||
@@ -8,4 +16,7 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { ToastProvider } from '../../../../src/index'
|
import { ToastProvider } from '../../../../src/index'
|
||||||
import ToastProviderExampleChild from './ToastProviderExampleChild.vue'
|
import ToastProviderExampleChild from './ToastProviderExampleChild.vue'
|
||||||
|
import { ref } from 'vue'
|
||||||
|
|
||||||
|
const transition = ref('slide-left')
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="flex flex-col gap-2">
|
<div class="flex flex-col gap-2">
|
||||||
<input class="text-black" type="number" v-model="ms">
|
<label for="ms" class="block text-sm font-medium text-gray-900 dark:text-gray-400">Duration(ms)</label>
|
||||||
|
<input v-model.number="ms" type="number" id="ms" class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500" placeholder="John" required>
|
||||||
<div class="flex gap-2">
|
<div class="flex gap-2">
|
||||||
<Button @click="() => add('success')" color="green">success</Button>
|
<Button @click="() => add('success')" color="green">success</Button>
|
||||||
<Button @click="() => add('warning')" color="yellow">warning</Button>
|
<Button @click="() => add('warning')" color="yellow">warning</Button>
|
||||||
@@ -8,22 +9,21 @@
|
|||||||
<Button @click="() => add('update')" color="purple">update</Button>
|
<Button @click="() => add('update')" color="purple">update</Button>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
<Button @click="remove" color="alternative">remove</Button>
|
<Button @click="remove" color="alternative">pop</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script setup>
|
<script setup>
|
||||||
import { FLOWBITE_TOAST_INJECTION_KEY } from '../../../../src/components/Toast/components/ToastProvider/injection/config'
|
import { ref, shallowRef } from 'vue'
|
||||||
import { inject, ref, shallowRef } from 'vue'
|
import { Button, useToast } from '../../../../src/index'
|
||||||
import { Button } from '../../../../src/index'
|
|
||||||
import UpdateToast from './UpdateToast.vue'
|
import UpdateToast from './UpdateToast.vue'
|
||||||
|
|
||||||
const ms = ref('5000')
|
const ms = ref(5000)
|
||||||
|
|
||||||
const injected = inject(FLOWBITE_TOAST_INJECTION_KEY)
|
const toast = useToast()
|
||||||
|
|
||||||
const addUpdate = () => {
|
const addUpdate = () => {
|
||||||
injected.add({
|
const id = toast.add({
|
||||||
time: parseInt(ms.value) || 0,
|
time: parseInt(ms.value) || 0,
|
||||||
text: 'A new software version is available for download.',
|
text: 'A new software version is available for download.',
|
||||||
component: shallowRef(UpdateToast),
|
component: shallowRef(UpdateToast),
|
||||||
@@ -36,7 +36,7 @@ const addUpdate = () => {
|
|||||||
|
|
||||||
const add = (type) => {
|
const add = (type) => {
|
||||||
if(type === 'update') return addUpdate()
|
if(type === 'update') return addUpdate()
|
||||||
injected.add({
|
toast.add({
|
||||||
type,
|
type,
|
||||||
time: parseInt(ms.value) || 0,
|
time: parseInt(ms.value) || 0,
|
||||||
text: `${type} alert! Hello world!`,
|
text: `${type} alert! Hello world!`,
|
||||||
@@ -44,7 +44,7 @@ const add = (type) => {
|
|||||||
|
|
||||||
}
|
}
|
||||||
const remove = () => {
|
const remove = () => {
|
||||||
injected.pop()
|
toast.pop()
|
||||||
}
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -1,9 +1,49 @@
|
|||||||
.list-enter-active,
|
|
||||||
.list-leave-active {
|
.slide-left-enter-active,
|
||||||
|
.slide-left-leave-active {
|
||||||
transition: all 0.5s ease;
|
transition: all 0.5s ease;
|
||||||
}
|
}
|
||||||
.list-enter-from,
|
.slide-left-enter-from,
|
||||||
.list-leave-to {
|
.slide-left-leave-to {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
transform: translateX(30px);
|
transform: translateX(30px);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.slide-right-enter-active,
|
||||||
|
.slide-right-leave-active {
|
||||||
|
transition: all 0.5s ease;
|
||||||
|
}
|
||||||
|
.slide-right-enter-from,
|
||||||
|
.slide-right-leave-to {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateX(-30px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.slide-top-enter-active,
|
||||||
|
.slide-top-leave-active {
|
||||||
|
transition: all 0.5s ease;
|
||||||
|
}
|
||||||
|
.slide-top-enter-from,
|
||||||
|
.slide-top-leave-to {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(30px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.slide-bottom-enter-active,
|
||||||
|
.slide-bottom-leave-active {
|
||||||
|
transition: all 0.5s ease;
|
||||||
|
}
|
||||||
|
.slide-bottom-enter-from,
|
||||||
|
.slide-bottom-leave-to {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(-30px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.fade-enter-active,
|
||||||
|
.fade-leave-active {
|
||||||
|
transition: all 0.5s ease;
|
||||||
|
}
|
||||||
|
.fade-enter-from,
|
||||||
|
.fade-leave-to {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,14 +1,26 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent, h, provide, ref, resolveComponent, TransitionGroup } from 'vue'
|
import { defineComponent, h, provide, ref, TransitionGroup } from 'vue'
|
||||||
import { FLOWBITE_TOAST_INJECTION_KEY } from '@/components/Toast/components/ToastProvider/injection/config'
|
import { FLOWBITE_TOAST_INJECTION_KEY } from '@/components/Toast/components/ToastProvider/injection/config'
|
||||||
import type { ToastItem, ToastItemWithId } from '@/components/Toast/components/ToastProvider/types'
|
import type {
|
||||||
|
ToastItem,
|
||||||
|
ToastItemWithId,
|
||||||
|
ToastTransition,
|
||||||
|
UseToastInjection,
|
||||||
|
} from '@/components/Toast/components/ToastProvider/types'
|
||||||
import { Toast } from '@/index'
|
import { Toast } from '@/index'
|
||||||
import { useTimeoutFn } from '@vueuse/core'
|
import { useTimeoutFn } from '@vueuse/core'
|
||||||
|
import type { PropType } from 'vue'
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components: {
|
components: {
|
||||||
Toast: Toast as any,
|
Toast: Toast as any,
|
||||||
},
|
},
|
||||||
|
props: {
|
||||||
|
transition: {
|
||||||
|
type: String as PropType<ToastTransition>,
|
||||||
|
default: 'slide-left',
|
||||||
|
},
|
||||||
|
},
|
||||||
setup() {
|
setup() {
|
||||||
const toasts = ref<ToastItemWithId[]>([])
|
const toasts = ref<ToastItemWithId[]>([])
|
||||||
|
|
||||||
@@ -17,29 +29,33 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const addToast = (toast: ToastItem) => {
|
const addToast = (toast: ToastItem) => {
|
||||||
const id = ((new Date()).getTime() * Math.random()).toString()
|
const id = parseInt(((new Date()).getTime() * Math.random()).toString()).toString()
|
||||||
toasts.value.push({
|
toasts.value.push({
|
||||||
id,
|
id,
|
||||||
...toast,
|
...toast,
|
||||||
})
|
})
|
||||||
if (toast.time > 0)
|
if (toast.time > 0)
|
||||||
runRemoveTimeout(id, toast.time)
|
runRemoveTimeout(id, toast.time)
|
||||||
|
return id
|
||||||
|
}
|
||||||
|
|
||||||
|
const popToast = () => {
|
||||||
|
if (toasts.value.length === 0) return ''
|
||||||
|
const lastId = toasts.value[toasts.value.length - 1].id
|
||||||
|
toasts.value.pop()
|
||||||
|
return lastId
|
||||||
}
|
}
|
||||||
|
|
||||||
const removeToast = (id: string) => {
|
const removeToast = (id: string) => {
|
||||||
const index = toasts.value.findIndex(_ => _.id === id)
|
const index = toasts.value.findIndex(_ => _.id === id)
|
||||||
toasts.value.splice(index, 1)
|
if(index >= 0) toasts.value.splice(index, 1)
|
||||||
|
return index >= 0
|
||||||
}
|
}
|
||||||
|
|
||||||
const popToast = () => {
|
provide<UseToastInjection>(FLOWBITE_TOAST_INJECTION_KEY, {
|
||||||
if (toasts.value.length === 0) return
|
|
||||||
toasts.value.pop()
|
|
||||||
}
|
|
||||||
|
|
||||||
provide(FLOWBITE_TOAST_INJECTION_KEY, {
|
|
||||||
add: addToast,
|
add: addToast,
|
||||||
remove: removeToast,
|
|
||||||
pop: popToast,
|
pop: popToast,
|
||||||
|
remove: removeToast,
|
||||||
})
|
})
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -49,6 +65,7 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
|
$props,
|
||||||
$slots,
|
$slots,
|
||||||
toasts,
|
toasts,
|
||||||
removeToast,
|
removeToast,
|
||||||
@@ -57,7 +74,7 @@ export default defineComponent({
|
|||||||
return h('div', {}, [
|
return h('div', {}, [
|
||||||
$slots.default ? $slots.default() : null, // rendering default slot
|
$slots.default ? $slots.default() : null, // rendering default slot
|
||||||
h(TransitionGroup, {
|
h(TransitionGroup, {
|
||||||
name: 'list',
|
name: $props.transition,
|
||||||
tag: 'div',
|
tag: 'div',
|
||||||
class: 'xl:w-1/6 md:w-1/4 sm:w-1/4 fixed top-3 right-3 flex flex-col gap-2 z-50',
|
class: 'xl:w-1/6 md:w-1/4 sm:w-1/4 fixed top-3 right-3 flex flex-col gap-2 z-50',
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,3 +1,29 @@
|
|||||||
export function useToast() {
|
import { inject } from 'vue'
|
||||||
return ''
|
import type { ToastItem, UseToastInjection } from '@/components/Toast/components/ToastProvider/types'
|
||||||
|
import { FLOWBITE_TOAST_INJECTION_KEY } from '@/components/Toast/components/ToastProvider/injection/config'
|
||||||
|
|
||||||
|
export function useToast(): UseToastInjection {
|
||||||
|
const injection = inject<UseToastInjection | null>(FLOWBITE_TOAST_INJECTION_KEY, null)
|
||||||
|
if(injection === null) console.warn('Cannot use useToast outside <toast-provider> component. Please wrap your component with <toast-provider>')
|
||||||
|
|
||||||
|
const add = (toast: ToastItem): string => {
|
||||||
|
if(!injection) return ''
|
||||||
|
return injection?.add(toast)
|
||||||
|
}
|
||||||
|
|
||||||
|
const remove = (id: string): boolean => {
|
||||||
|
if(!injection) return false
|
||||||
|
return injection?.remove(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
const pop = (): string => {
|
||||||
|
if(!injection) return ''
|
||||||
|
return injection?.pop()
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
add,
|
||||||
|
remove,
|
||||||
|
pop,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,5 +13,10 @@ export type ToastItemWithId = ToastItem & {
|
|||||||
id: string
|
id: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ToastInjection = {
|
export type ToastTransition = 'slide-left' | 'slide-right' | 'fade' | 'slide-top' | 'slide-bottom'
|
||||||
|
|
||||||
|
export type UseToastInjection = {
|
||||||
|
add: (toast: ToastItem) => string
|
||||||
|
remove: (id: string) => boolean // true if removed, false if not found
|
||||||
|
pop: () => string // empty '' string if no toast to pop
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user