Merge pull request #46 from themesberg/chank1e/develop
feat: alert system + useToast works
This commit is contained in:
@@ -1,5 +1,13 @@
|
||||
<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">
|
||||
<toast-provider-example-child />
|
||||
</div>
|
||||
@@ -8,4 +16,7 @@
|
||||
<script setup>
|
||||
import { ToastProvider } from '../../../../src/index'
|
||||
import ToastProviderExampleChild from './ToastProviderExampleChild.vue'
|
||||
import { ref } from 'vue'
|
||||
|
||||
const transition = ref('slide-left')
|
||||
</script>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<template>
|
||||
<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">
|
||||
<Button @click="() => add('success')" color="green">success</Button>
|
||||
<Button @click="() => add('warning')" color="yellow">warning</Button>
|
||||
@@ -8,22 +9,21 @@
|
||||
<Button @click="() => add('update')" color="purple">update</Button>
|
||||
</div>
|
||||
<div class="flex">
|
||||
<Button @click="remove" color="alternative">remove</Button>
|
||||
<Button @click="remove" color="alternative">pop</Button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import { FLOWBITE_TOAST_INJECTION_KEY } from '../../../../src/components/Toast/components/ToastProvider/injection/config'
|
||||
import { inject, ref, shallowRef } from 'vue'
|
||||
import { Button } from '../../../../src/index'
|
||||
import { ref, shallowRef } from 'vue'
|
||||
import { Button, useToast } from '../../../../src/index'
|
||||
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 = () => {
|
||||
injected.add({
|
||||
const id = toast.add({
|
||||
time: parseInt(ms.value) || 0,
|
||||
text: 'A new software version is available for download.',
|
||||
component: shallowRef(UpdateToast),
|
||||
@@ -36,7 +36,7 @@ const addUpdate = () => {
|
||||
|
||||
const add = (type) => {
|
||||
if(type === 'update') return addUpdate()
|
||||
injected.add({
|
||||
toast.add({
|
||||
type,
|
||||
time: parseInt(ms.value) || 0,
|
||||
text: `${type} alert! Hello world!`,
|
||||
@@ -44,7 +44,7 @@ const add = (type) => {
|
||||
|
||||
}
|
||||
const remove = () => {
|
||||
injected.pop()
|
||||
toast.pop()
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
@@ -1,9 +1,49 @@
|
||||
.list-enter-active,
|
||||
.list-leave-active {
|
||||
|
||||
.slide-left-enter-active,
|
||||
.slide-left-leave-active {
|
||||
transition: all 0.5s ease;
|
||||
}
|
||||
.list-enter-from,
|
||||
.list-leave-to {
|
||||
.slide-left-enter-from,
|
||||
.slide-left-leave-to {
|
||||
opacity: 0;
|
||||
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">
|
||||
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 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 { useTimeoutFn } from '@vueuse/core'
|
||||
import type { PropType } from 'vue'
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
Toast: Toast as any,
|
||||
},
|
||||
props: {
|
||||
transition: {
|
||||
type: String as PropType<ToastTransition>,
|
||||
default: 'slide-left',
|
||||
},
|
||||
},
|
||||
setup() {
|
||||
const toasts = ref<ToastItemWithId[]>([])
|
||||
|
||||
@@ -17,29 +29,33 @@ export default defineComponent({
|
||||
}
|
||||
|
||||
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({
|
||||
id,
|
||||
...toast,
|
||||
})
|
||||
if (toast.time > 0)
|
||||
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 index = toasts.value.findIndex(_ => _.id === id)
|
||||
toasts.value.splice(index, 1)
|
||||
if(index >= 0) toasts.value.splice(index, 1)
|
||||
return index >= 0
|
||||
}
|
||||
|
||||
const popToast = () => {
|
||||
if (toasts.value.length === 0) return
|
||||
toasts.value.pop()
|
||||
}
|
||||
|
||||
provide(FLOWBITE_TOAST_INJECTION_KEY, {
|
||||
provide<UseToastInjection>(FLOWBITE_TOAST_INJECTION_KEY, {
|
||||
add: addToast,
|
||||
remove: removeToast,
|
||||
pop: popToast,
|
||||
remove: removeToast,
|
||||
})
|
||||
|
||||
return {
|
||||
@@ -49,6 +65,7 @@ export default defineComponent({
|
||||
},
|
||||
render() {
|
||||
const {
|
||||
$props,
|
||||
$slots,
|
||||
toasts,
|
||||
removeToast,
|
||||
@@ -57,7 +74,7 @@ export default defineComponent({
|
||||
return h('div', {}, [
|
||||
$slots.default ? $slots.default() : null, // rendering default slot
|
||||
h(TransitionGroup, {
|
||||
name: 'list',
|
||||
name: $props.transition,
|
||||
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',
|
||||
},
|
||||
|
||||
@@ -1,3 +1,29 @@
|
||||
export function useToast() {
|
||||
return ''
|
||||
import { inject } from 'vue'
|
||||
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
|
||||
}
|
||||
|
||||
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