feat: Some improvements for modal component
Added click outside, persistent and close on Esc
This commit is contained in:
@@ -2,10 +2,23 @@
|
||||
import ModalExample from './modal/examples/ModalExample.vue';
|
||||
import ModalSizeExample from './modal/examples/ModalSizeExample.vue';
|
||||
import ModalEscapableExample from './modal/examples/ModalEscapableExample.vue';
|
||||
import ModalPersistentExample from './modal/examples/ModalPersistentExample.vue';
|
||||
</script>
|
||||
# Vue Modal - Flowbite
|
||||
|
||||
## Demo
|
||||
#### Use the modal component to show interactive dialogs and notifications to your website users available in multiple sizes, colors, and styles
|
||||
|
||||
---
|
||||
|
||||
:::tip
|
||||
Original reference: [https://flowbite.com/docs/components/modal/](https://flowbite.com/docs/components/modal/)
|
||||
:::
|
||||
|
||||
The modal component can be used as an interactive dialog on top of the main content area of the website to show notifications and gather information using form elements from your website users.
|
||||
|
||||
Get started with multiple sizes, colors, and styles built with the utility classes from Tailwind CSS and the components from Flowbite.
|
||||
|
||||
## Default modal
|
||||
|
||||
<ModalExample />
|
||||
|
||||
@@ -101,3 +114,35 @@ import { Modal } from 'flowbite-vue'
|
||||
<Modal :escapable="false" />
|
||||
</template>
|
||||
```
|
||||
|
||||
## Persistent
|
||||
|
||||
Clicking outside of the element or pressing esc key will not send `close` event.
|
||||
|
||||
Demo:
|
||||
<ModalPersistentExample />
|
||||
|
||||
```vue
|
||||
<script setup>
|
||||
import { Modal } from 'flowbite-vue'
|
||||
</script>
|
||||
<template>
|
||||
<Modal persistent />
|
||||
</template>
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
### Props:
|
||||
|
||||
| Name | Values | Default |
|
||||
|------------|-----------------------------------------------------------|---------|
|
||||
| size | `md`,`lg`, `xl`, `2xl`, `3xl`, `4xl`, `5xl`, `6xl`, `7xl` | 2xl |
|
||||
| escapable | `true`, `false` | `true` |
|
||||
| persistent | `true`, `false` | `true` |
|
||||
|
||||
### Events:
|
||||
| Name | Type |
|
||||
|---------------------|----------------------------------------------------------------------------------|
|
||||
| `close` | Clicked on the close button, pressed `Esc`, or clicked outside the modal content |
|
||||
| `click:outside` | Clicked outside the modal content |
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<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 :escapable="escapable" :size="size" v-if="isShowModal" @close="closeModal">
|
||||
<Modal :escapable="escapable" :size="size" v-if="isShowModal" @close="closeModal" :persistent="persistent">
|
||||
<template #header>
|
||||
<div class="flex items-center text-lg">
|
||||
Terms of Service
|
||||
@@ -32,42 +32,22 @@
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { Modal } from '../../../../src/index'
|
||||
import type { PropType } from 'vue'
|
||||
import type { ModalSize, ModalPosition } from '../../../../src/components/Modal/types'
|
||||
import type { ModalSize } from '../../../../src/components/Modal/types'
|
||||
import { ref } from 'vue'
|
||||
|
||||
defineProps({
|
||||
children: {
|
||||
type: Array,
|
||||
default() {
|
||||
return []
|
||||
},
|
||||
},
|
||||
popup: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
position: {
|
||||
type: String as PropType<ModalPosition>,
|
||||
default: 'center',
|
||||
},
|
||||
show: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
size: {
|
||||
type: String as PropType<ModalSize>,
|
||||
default: '2xl',
|
||||
},
|
||||
escapable: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
triggerText: {
|
||||
type: String,
|
||||
default: 'Demo Modal',
|
||||
},
|
||||
interface ModalProps {
|
||||
size?: ModalSize,
|
||||
escapable?: boolean,
|
||||
persistent?: boolean,
|
||||
triggerText?: string
|
||||
}
|
||||
withDefaults(defineProps<ModalProps>(), {
|
||||
size: '2xl',
|
||||
escapable: true,
|
||||
persistent: false,
|
||||
triggerText: 'Demo Modal',
|
||||
})
|
||||
|
||||
const isShowModal = ref(false)
|
||||
function closeModal() {
|
||||
isShowModal.value = false
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
<template>
|
||||
<div class="vp-raw">
|
||||
<ModalExample trigger-text="Persistent" :persistent="true" />
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import ModalExample from './ModalExample.vue'
|
||||
</script>
|
||||
@@ -2,12 +2,13 @@
|
||||
<div>
|
||||
<div class="bg-gray-900 bg-opacity-50 dark:bg-opacity-80 fixed inset-0 z-40" />
|
||||
<div
|
||||
tabindex="-1"
|
||||
tabindex="0"
|
||||
ref="modalRef"
|
||||
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"
|
||||
v-on="escapable ? { click: closeModal } : {}"
|
||||
@keyup.esc="closeWithEsc"
|
||||
@click.self="clickOutside"
|
||||
>
|
||||
<div
|
||||
@click.stop
|
||||
class="relative p-4 w-full h-full md:h-auto"
|
||||
:class="`${modalSizeClasses[size]}`"
|
||||
>
|
||||
@@ -16,7 +17,7 @@
|
||||
<!-- Modal header -->
|
||||
<div class="p-4 rounded-t flex justify-between items-center" :class="$slots.header ? 'border-b border-gray-200 dark:border-gray-600' : ''">
|
||||
<slot name="header" />
|
||||
<button v-if="escapable" @click="closeModal" aria-label="close" 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">
|
||||
<button v-if="!persistent" @click="closeModal" aria-label="close" 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">
|
||||
<slot name="close-icon">
|
||||
<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>
|
||||
</slot>
|
||||
@@ -36,34 +37,20 @@
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import type { PropType } from 'vue'
|
||||
import type { ModalSize, ModalPosition } from './types'
|
||||
import type { ModalSize } from './types'
|
||||
import { onMounted, ref, type Ref } from 'vue'
|
||||
|
||||
const props = defineProps({
|
||||
children: {
|
||||
type: Array,
|
||||
default() {
|
||||
return []
|
||||
},
|
||||
},
|
||||
popup: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
position: {
|
||||
type: String as PropType<ModalPosition>,
|
||||
default: 'center',
|
||||
},
|
||||
size: {
|
||||
type: String as PropType<ModalSize>,
|
||||
default: '2xl',
|
||||
},
|
||||
escapable: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
interface ModalProps {
|
||||
size?: ModalSize,
|
||||
escapable?: boolean,
|
||||
persistent?: boolean
|
||||
}
|
||||
const props = withDefaults(defineProps<ModalProps>(), {
|
||||
size: '2xl',
|
||||
escapable: true,
|
||||
persistent: false,
|
||||
})
|
||||
const emit = defineEmits(['close'])
|
||||
const emit = defineEmits(['close', 'click:outside'])
|
||||
const modalSizeClasses = {
|
||||
xs: 'max-w-xs',
|
||||
sm: 'max-w-sm',
|
||||
@@ -81,12 +68,20 @@ const modalSizeClasses = {
|
||||
function closeModal() {
|
||||
emit('close')
|
||||
}
|
||||
|
||||
addEventListener("keyup", function(e) {
|
||||
if (props.escapable) {
|
||||
if (e.key === "Escape") {
|
||||
closeModal();
|
||||
function clickOutside() {
|
||||
if(!props.persistent) {
|
||||
emit('click:outside')
|
||||
closeModal()
|
||||
}
|
||||
}
|
||||
|
||||
function closeWithEsc() {
|
||||
if(props.escapable && !props.persistent) closeModal()
|
||||
}
|
||||
const modalRef: Ref<HTMLElement | null> = ref(null)
|
||||
onMounted(() => {
|
||||
if(modalRef.value) {
|
||||
modalRef.value.focus()
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user