feat: Modal component improvements

This commit is contained in:
Ilya Artamonov
2022-10-07 17:21:54 +03:00
parent dc369d19c3
commit e0d08d6d52
6 changed files with 92 additions and 107 deletions

View File

@@ -1,24 +1,15 @@
<template>
<div class="vp-raw flex flex-col">
<Modal :size="size">
<template #trigger="props">
<button @click="props.show()" type="button" class="mt-5 text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800">
{{triggerText}}
</button>
</template>
<template #header="props">
<div class="flex justify-between">
<div class="flex items-center text-lg">
Terms of Service
</div>
<div>
<button @click="props.hide()" type="button" class="text-gray-400 bg-transparent hover:bg-gray-200 hover:text-gray-900 rounded-lg text-sm p-1.5 ml-auto inline-flex items-center dark:hover:bg-gray-600 dark:hover:text-white">
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clip-rule="evenodd"></path></svg>
</button>
</div>
<div class="vp-raw flex justify-start">
<button @click="showModal" type="button" class="mt-5 text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800">
{{ triggerText }}
</button>
<Modal :size="size" v-if="isShowModal" @close="closeModal">
<template #header>
<div class="flex items-center text-lg">
Terms of Service
</div>
</template>
<template v-slot:body>
<template #body>
<p class="text-base leading-relaxed text-gray-500 dark:text-gray-400">
With less than a month to go before the European Union enacts new consumer privacy laws for its citizens, companies around the world are updating their terms of service agreements to comply.
</p>
@@ -26,12 +17,12 @@
The European Unions General Data Protection Regulation (G.D.P.R.) goes into effect on May 25 and is meant to ensure a common set of data rights in the European Union. It requires organizations to notify users as soon as possible of high-risk data breaches that could personally affect them.
</p>
</template>
<template #footer="props">
<template #footer>
<div class="flex justify-between">
<button @click="props.hide()" type="button" class="text-gray-500 bg-white hover:bg-gray-100 focus:ring-4 focus:outline-none focus:ring-blue-300 rounded-lg border border-gray-200 text-sm font-medium px-5 py-2.5 hover:text-gray-900 focus:z-10 dark:bg-gray-700 dark:text-gray-300 dark:border-gray-500 dark:hover:text-white dark:hover:bg-gray-600 dark:focus:ring-gray-600">
<button @click="closeModal" type="button" class="text-gray-500 bg-white hover:bg-gray-100 focus:ring-4 focus:outline-none focus:ring-blue-300 rounded-lg border border-gray-200 text-sm font-medium px-5 py-2.5 hover:text-gray-900 focus:z-10 dark:bg-gray-700 dark:text-gray-300 dark:border-gray-500 dark:hover:text-white dark:hover:bg-gray-600 dark:focus:ring-gray-600">
Decline
</button>
<button @click="props.hide()" type="button" class="text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800">
<button @click="closeModal" type="button" class="text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800">
I accept
</button>
</div>
@@ -43,7 +34,9 @@
import { Modal } from '../../../../src/index'
import type { PropType } from 'vue'
import type { ModalSize, ModalPosition } from '../../../../src/components/Modal/types'
const props = defineProps({
import { ref } from 'vue'
defineProps({
children: {
type: Array,
default() {
@@ -71,4 +64,11 @@ const props = defineProps({
default: 'Demo Modal',
},
})
const isShowModal = ref(false)
function closeModal() {
isShowModal.value = false
}
function showModal() {
isShowModal.value = true
}
</script>

View File

@@ -1,7 +1,7 @@
<template>
<div class="vp-raw flex justify-between">
<div class="vp-raw flex justify-start space-x-2">
<span>
<ModalExample size="xs" trigger-text="XS Modal" />
<ModalExample size="xs" trigger-text="SM Modal" />
</span>
<span>
<ModalExample size="md" trigger-text="MD Modal" />

View File

@@ -11,67 +11,64 @@ import ModalSizeExample from './examples/ModalSizeExample.vue';
```vue
<script setup>
import { Modal } from 'flowbite-vue'
import { ref } from 'vue'
const isShowModal = ref(false)
function closeModal() {
isShowModal.value = false
}
function showModal() {
isShowModal.value = true
}
</script>
<template>
<Modal>
<template #trigger="props">
<button @click="props.show()" type="button" class="mt-5 text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800">
Show Modal
</button>
</template>
<template #header="props">
<div class="flex justify-between">
<div class="flex items-center text-lg">
Terms of Service
<button @click="showModal" type="button" class="mt-5 text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800">
Show modal
</button>
<Modal size="xs" v-if="isShowModal">
<template #header>
<div class="flex justify-between">
<div class="flex items-center text-lg">
Terms of Service
</div>
<div>
<button @click="closeModal" type="button" class="text-gray-400 bg-transparent hover:bg-gray-200 hover:text-gray-900 rounded-lg text-sm p-1.5 ml-auto inline-flex items-center dark:hover:bg-gray-600 dark:hover:text-white">
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clip-rule="evenodd"></path></svg>
</button>
</div>
</div>
<div>
<button @click="props.hide()" type="button" class="text-gray-400 bg-transparent hover:bg-gray-200 hover:text-gray-900 rounded-lg text-sm p-1.5 ml-auto inline-flex items-center dark:hover:bg-gray-600 dark:hover:text-white">
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clip-rule="evenodd"></path></svg>
</template>
<template #body>
<p class="text-base leading-relaxed text-gray-500 dark:text-gray-400">
With less than a month to go before the European Union enacts new consumer privacy laws for its citizens, companies around the world are updating their terms of service agreements to comply.
</p>
<p class="text-base leading-relaxed text-gray-500 dark:text-gray-400">
The European Unions General Data Protection Regulation (G.D.P.R.) goes into effect on May 25 and is meant to ensure a common set of data rights in the European Union. It requires organizations to notify users as soon as possible of high-risk data breaches that could personally affect them.
</p>
</template>
<template #footer>
<div class="flex justify-between">
<button @click="closeModal" type="button" class="text-gray-500 bg-white hover:bg-gray-100 focus:ring-4 focus:outline-none focus:ring-blue-300 rounded-lg border border-gray-200 text-sm font-medium px-5 py-2.5 hover:text-gray-900 focus:z-10 dark:bg-gray-700 dark:text-gray-300 dark:border-gray-500 dark:hover:text-white dark:hover:bg-gray-600 dark:focus:ring-gray-600">
Decline
</button>
<button @click="closeModal" type="button" class="text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800">
I accept
</button>
</div>
</div>
</template>
<template v-slot:body>
<p class="text-base leading-relaxed text-gray-500 dark:text-gray-400">
With less than a month to go before the European Union enacts new consumer privacy laws for its citizens, companies around the world are updating their terms of service agreements to comply.
</p>
<p class="text-base leading-relaxed text-gray-500 dark:text-gray-400">
The European Unions General Data Protection Regulation (G.D.P.R.) goes into effect on May 25 and is meant to ensure a common set of data rights in the European Union. It requires organizations to notify users as soon as possible of high-risk data breaches that could personally affect them.
</p>
</template>
<template #footer="props">
<div class="flex justify-between">
<button @click="props.hide()" type="button" class="text-gray-500 bg-white hover:bg-gray-100 focus:ring-4 focus:outline-none focus:ring-blue-300 rounded-lg border border-gray-200 text-sm font-medium px-5 py-2.5 hover:text-gray-900 focus:z-10 dark:bg-gray-700 dark:text-gray-300 dark:border-gray-500 dark:hover:text-white dark:hover:bg-gray-600 dark:focus:ring-gray-600">
Decline
</button>
<button @click="props.hide()" type="button" class="text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800">
I accept
</button>
</div>
</template>
</Modal>
</template>
</Modal>
</template>
```
## Slot Properties
## Sizes
Modal slots receive the following functions to interact with the modal:
1. `show` = show the modal
2. `hide` = hide the modal
3. `toggle` = toggles the modal from current state (e.g. if shown, then hide)
These properties allow your code to set the open/closed state of the modal easily.
## Sizes
The modal can come in the following sizes (based on TailwindCSS classes).
You can use four different modal sizing options starting from small to extra large, but keep in mind that the width of these modals will remain the same when browsing on smaller devices.
`xs`, `sm`, `md`, `lg`, `xl`, `2xl`, `3xl`, `4xl`, `5xl`, `6xl`, `7xl`
The default value is: `2xl`
Demo:
Demo:
<ModalSizeExample/>
```vue
@@ -84,4 +81,4 @@ import { Modal } from 'flowbite-vue'
<Modal size="xl" />
<Modal size="5xl" />
</template>
```
```

View File

@@ -54,5 +54,5 @@ const props = defineProps({
const model = useVModel(props, 'modelValue')
const {inputClasses, labelClasses} = useInputClasses(toRefs(props))
const { inputClasses, labelClasses } = useInputClasses(toRefs(props))
</script>

View File

@@ -1,25 +1,29 @@
<template>
<div>
<slot name="trigger" :show="showModal" :hide="hideModal" :toggle="toggleModal"/>
<div v-if="!isHidden" class="bg-gray-900 bg-opacity-50 dark:bg-opacity-80 fixed inset-0 z-40"/>
<div v-if="!isHidden" tabindex="-1" :aria-hidden="isHidden ? 'true' : 'false'"
class="overflow-y-auto overflow-x-hidden fixed top-0 right-0 left-0 z-50 w-full md:inset-0 h-modal md:h-full justify-center items-center flex">
<div class="relative p-4 w-full h-full md:h-auto"
:class="`${modalSizeClasses[size]}`">
<div class="bg-gray-900 bg-opacity-50 dark:bg-opacity-80 fixed inset-0 z-40" />
<div
tabindex="-1"
class="overflow-y-auto overflow-x-hidden fixed top-0 right-0 left-0 z-50 w-full md:inset-0 h-modal md:h-full justify-center items-center flex"
>
<div class="relative p-4 w-full h-full md:h-auto" :class="`${modalSizeClasses[size]}`">
<!-- Modal content -->
<div class="relative bg-white rounded-lg shadow dark:bg-gray-700">
<!-- Modal header -->
<div class="p-4 rounded-t"
:class="$slots.header ? 'border-b' : ''">
<slot name="header" :show="showModal" :hide="hideModal" :toggle="toggleModal"/>
<div class="p-4 rounded-t flex justify-between items-center" :class="$slots.header ? 'border-b' : ''">
<slot name="header" />
<div>
<button @click="closeModal" type="button" class="text-gray-400 bg-transparent hover:bg-gray-200 hover:text-gray-900 rounded-lg text-sm p-1.5 ml-auto inline-flex items-center dark:hover:bg-gray-600 dark:hover:text-white">
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clip-rule="evenodd"></path></svg>
</button>
</div>
</div>
<!-- Modal body -->
<div class="p-6" :class="$slots.header ? '' : 'pt-0'">
<slot name="body" :show="showModal" :hide="hideModal" :toggle="toggleModal"/>
<slot name="body" />
</div>
<!-- Modal footer -->
<div v-if="$slots.footer" class="p-6 rounded-b border-gray-200">
<slot name="footer" :show="showModal" :hide="hideModal" :toggle="toggleModal"/>
<div v-if="$slots.footer" class="p-6 rounded-b border-gray-200 border-t dark:border-gray-600">
<slot name="footer" />
</div>
</div>
</div>
@@ -27,11 +31,10 @@
</div>
</template>
<script lang="ts" setup>
import { ref } from 'vue'
import type { PropType, Ref } from 'vue'
import type { PropType } from 'vue'
import type { ModalSize, ModalPosition } from './types'
const props = defineProps({
defineProps({
children: {
type: Array,
default() {
@@ -46,16 +49,12 @@ const props = defineProps({
type: String as PropType<ModalPosition>,
default: 'center',
},
show: {
type: Boolean,
default: false,
},
size: {
type: String as PropType<ModalSize>,
default: '2xl',
},
})
const emit = defineEmits(['close'])
const modalSizeClasses = {
xs: 'max-w-xs',
sm: 'max-w-sm',
@@ -70,18 +69,7 @@ const modalSizeClasses = {
'7xl': 'max-w-7xl',
}
const isHidden: Ref<boolean> = ref(!props.show)
function toggleModal() {
isHidden.value = !isHidden.value
function closeModal() {
emit('close')
}
function hideModal() {
isHidden.value = true
}
function showModal() {
isHidden.value = false
}
</script>

View File

@@ -1,2 +1,2 @@
export type ModalPosition = 'bottom-left' | 'bottom-right' | 'bottom-center' | 'top-left' | 'top-center' | 'top-right' | 'center-left' | 'center' | 'center-right';
export type ModalSize = 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | '4xl' | '5xl' | '6xl' | '7xl';
export type ModalSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | '4xl' | '5xl' | '6xl' | '7xl';