Merge pull request #42 from themesberg/chank1e/develop

feat: toast-provider and useToast initial
This commit is contained in:
Alexandr P
2022-07-26 22:26:46 +03:00
committed by GitHub
17 changed files with 185 additions and 9 deletions

View File

@@ -58,6 +58,7 @@ function getComponents() {
function getUtils() {
return [
{ text: 'Flowbite Themable', link: '/components/flowbiteThemable/flowbiteThemable.md' },
{ text: 'ToastProvider', link: '/components/toastProvider/toastProvider.md' },
]
}

View File

@@ -4,4 +4,12 @@ import DefaultTheme from 'vitepress/theme'
import './clear.css'
export default DefaultTheme
import { TransitionGroup } from "vue";
export default {
...DefaultTheme,
enhanceApp({ app, router, siteData }) {
// strange thing, but there is no global transition-group component inside vitepress app
app.component('TransitionGroup', TransitionGroup)
}
}

View File

@@ -4,6 +4,7 @@ import ToastClosableExample from './examples/ToastClosableExample.vue';
import ToastIconExample from './examples/ToastIconExample.vue';
import ToastDivideExample from './examples/ToastDivideExample.vue';
import ToastMessageExample from './examples/ToastMessageExample.vue';
import ToastProviderExample from './examples/ToastProviderExample.vue';
import ToastInteractiveExample from './examples/ToastInteractiveExample.vue'
</script>
# Toast
@@ -176,3 +177,6 @@ import { Toast } from 'flowbite-vue'
```
<ToastIconExample />
---
<ToastProviderExample />

View File

@@ -0,0 +1,11 @@
<template>
<toast-provider>
<div class="vp-raw flex align-center gap-2 flex-wrap flex-col">
<toast-provider-example-child />
</div>
</toast-provider>
</template>
<script setup>
import { ToastProvider } from '../../../../src/index'
import ToastProviderExampleChild from './ToastProviderExampleChild.vue'
</script>

View File

@@ -0,0 +1,33 @@
<template>
<div class="flex flex-col gap-2">
<input class="text-black" type="number" v-model="ms">
<div class="flex gap-2">
<Button @click="() => add('success')" color="green">success</Button>
<Button @click="() => add('warning')" color="yellow">warning</Button>
<Button @click="() => add('danger')" color="red">danger</Button>
</div>
<div class="flex">
<Button @click="remove" color="alternative">remove</Button>
</div>
</div>
</template>
<script setup>
import { FLOWBITE_TOAST_INJECTION_KEY } from '../../../../src/components/Toast/components/ToastProvider/injection/config'
import { inject, ref } from 'vue'
import { Button } from '../../../../src/index'
const ms = ref('5000')
const injected = inject(FLOWBITE_TOAST_INJECTION_KEY)
const add = (type) => {
injected.add({
time: parseInt(ms.value) || 0,
type: type,
text: `${type} alert! Hello world!`,
})
}
const remove = () => {
injected.pop()
}
</script>

View File

@@ -0,0 +1,6 @@
<script setup>
import ToastProviderExample from './examples/ToastProviderExample.vue';
</script>
# Toast provider
<ToastProviderExample />

View File

@@ -1,6 +1,6 @@
{
"name": "flowbite-vue",
"version": "0.0.3",
"version": "0.0.4",
"repository": "https://github.com/themesberg/flowbite-vue.git",
"author": "themesberg",
"license": "MIT",

View File

@@ -23,7 +23,7 @@
</div>
</template>
<script lang="ts" setup>
import type { ToastAlign, ToastPreset } from '@/components/Toast/types'
import type { ToastAlign, ToastType } from '@/components/Toast/types'
import type { PropType } from 'vue'
import { useToastClasses } from './composables/useToastClasses'
import { ref, toRefs } from 'vue'
@@ -32,7 +32,7 @@ import FlowbiteThemableChild
const props = defineProps({
type: {
type: String as PropType<ToastPreset>,
type: String as PropType<ToastType>,
default: 'empty',
},
alignment: {
@@ -59,5 +59,4 @@ const onClose = () => {
emit('close')
visible.value = false
}
</script>

View File

@@ -0,0 +1,9 @@
.list-enter-active,
.list-leave-active {
transition: all 0.5s ease;
}
.list-enter-from,
.list-leave-to {
opacity: 0;
transform: translateX(30px);
}

View File

@@ -0,0 +1,79 @@
<script lang="ts">
import { defineComponent, h, provide, ref, resolveComponent } 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 { Toast } from '@/index'
import { useTimeoutFn } from '@vueuse/core'
export default defineComponent({
components: {
Toast: Toast as any,
},
setup() {
const toasts = ref<ToastItemWithId[]>([])
const runRemoveTimeout = (id: string, ms: number) => {
useTimeoutFn(() => removeToast(id), ms)
}
const addToast = (toast: ToastItem) => {
const id = ((new Date()).getTime() * Math.random()).toString()
toasts.value.push({
id,
...toast,
})
if(toast.time > 0)
runRemoveTimeout(id, toast.time)
}
const removeToast = (id: string) => {
const index = toasts.value.findIndex(_ => _.id === id)
toasts.value.splice(index, 1)
}
const popToast = () => {
if(toasts.value.length === 0) return
toasts.value.pop()
}
provide(FLOWBITE_TOAST_INJECTION_KEY, {
add: addToast,
remove: removeToast,
pop: popToast,
})
return {
toasts,
removeToast,
}
},
render() {
const {
$slots,
toasts,
removeToast,
} = this
return h('div', {}, [
$slots.default ? $slots.default() : null, // rendering default slot
h(resolveComponent('TransitionGroup'), {
name: 'list',
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',
},
toasts.map(_toast => // rendering every toast
h(resolveComponent('Toast'), {
closable: true,
type: _toast.type,
key: _toast.id,
onClose: () => removeToast(_toast.id),
}, _toast.text),
),
),
])
},
})
</script>
<style lang="scss" scoped src="./ToastProvider.css"></style>

View File

@@ -0,0 +1,3 @@
export function useToast() {
return ''
}

View File

@@ -0,0 +1 @@
export const FLOWBITE_TOAST_INJECTION_KEY = 'flowbite-toast-injection-key'

View File

@@ -0,0 +1,14 @@
import type { ToastType } from '@/components/Toast/types'
export type ToastItem = {
time: number // ms
type: ToastType
text: string
}
export type ToastItemWithId = ToastItem & {
id: string
}
export type ToastInjection = {
}

View File

@@ -1,6 +1,6 @@
import type { Ref } from 'vue'
import { computed } from 'vue'
import type { ToastPreset } from '@/components/Toast/types'
import type { ToastType } from '@/components/Toast/types'
import { simplifyTailwindClasses } from '@/utils/simplifyTailwindClasses'
import type { ToastAlign } from '@/components/Toast/types'
@@ -11,12 +11,12 @@ type UseToastClassesReturns = {
}
type UseToastClassesProps = {
type: Ref<ToastPreset>
type: Ref<ToastType>
divide: Ref<boolean>
alignment: Ref<ToastAlign>
}
const typeClassesMap: Record<ToastPreset, string> = {
const typeClassesMap: Record<ToastType, string> = {
danger: 'text-red-500 bg-red-100 dark:bg-red-800 dark:text-red-200',
empty: '',
success: 'text-green-500 bg-green-100 dark:bg-green-800 dark:text-green-200',

View File

@@ -1,2 +1,2 @@
export type ToastPreset = 'success' | 'warning' | 'danger' | 'empty'
export type ToastType = 'success' | 'warning' | 'danger' | 'empty'
export type ToastAlign = 'start' | 'center' | 'end'

5
src/composables.ts Normal file
View File

@@ -0,0 +1,5 @@
import { useToast } from '@/components/Toast/components/ToastProvider/composables/useToast'
export {
useToast,
}

View File

@@ -26,4 +26,7 @@ export { default as Sidebar } from './components/Sidebar/Sidebar.vue'
export { default as Table } from './components/Table/Table.vue'
export { default as Timeline } from './components/Timeline/Timeline.vue'
export { default as Toast } from './components/Toast/Toast.vue'
export { default as ToastProvider } from './components/Toast/components/ToastProvider/ToastProvider.vue'
export { default as Tooltip } from './components/Tooltip/Tooltip.vue'
export * from './composables'