Skip to content

Commit 509a405

Browse files
committed
feat: support value of displayDirective
1 parent 1f3b855 commit 509a405

File tree

7 files changed

+87
-18
lines changed

7 files changed

+87
-18
lines changed

docs/components/content/ModalDragResize.vue

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ function dragResize(newRect) {
2323
<VueFinalModal
2424
display-directive="show"
2525
background="interactive"
26+
content-transition="vfm-fade"
2627
:hide-overlay="true"
2728
@update:model-value="val => emit('update:modelValue', val)"
2829
>

docs/components/content/ModalDragResizePreview.vue

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
<script setup lang="ts">
22
import { ModalsContainer, useModal } from 'vue-final-modal'
33
4-
const { open } = useModal({
4+
const { open, destroy } = useModal({
55
keepAlive: true,
66
component: defineAsyncComponent(() => import('./ModalDragResize.vue')),
77
})
8+
9+
onBeforeUnmount(() => {
10+
destroy()
11+
})
812
</script>
913

1014
<template>

docs/content/3.api/1.components/1.vue-final-modal.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -58,12 +58,12 @@ Display the modal or not.
5858

5959
### displayDirective
6060

61-
Render the modal content via `'if'`{lang=ts} or `'show'`{lang=ts} directive.
62-
if you need to keep the status of the modal, you can use `'show'` directive. for example if you have a draggable and resizable modal and you need to keep the size and position of the modal while re-open it ([see example](/use-cases/modal-drag-resize)).
61+
Render the modal via `'if'`{lang=ts}, `'show'`{lang=ts} or `'visible'`{lang=ts} directive.
62+
If you need to keep the modal alive, you can use `'show'` or `'visible'` directive. for example if you have a draggable and resizable modal and need to keep the size and position of the modal while re-open it ([see example](/use-cases/modal-drag-resize)).
6363

6464
- Type:
65-
- JS: `'if' | 'show'`{lang=ts}
66-
- TS: `PropType<'if' | 'show'>`{lang=ts}
65+
- JS: `'if' | 'show' | 'visible'`{lang=ts}
66+
- TS: `PropType<'if' | 'show' | 'visible'>`{lang=ts}
6767
- Default: `'if'`{lang=ts}
6868

6969
### hideOverlay

docs/content/4.use-cases/8.modal-drag-resize.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,14 @@ Here is a basic drag and resize modal example that using [vue3-drag-resize](http
2020
<script setup lang="ts">
2121
import { ModalsContainer, useModal } from 'vue-final-modal'
2222
23-
const { open } = useModal({
23+
const { open, destroy } = useModal({
2424
keepAlive: true,
2525
component: defineAsyncComponent(() => import('./ModalDragResize.vue')),
2626
})
27+
28+
onBeforeUnmount(() => {
29+
destroy()
30+
})
2731
</script>
2832
2933
<template>
@@ -65,6 +69,7 @@ Here is a basic drag and resize modal example that using [vue3-drag-resize](http
6569
<VueFinalModal
6670
display-directive="show"
6771
background="interactive"
72+
content-transition="vfm-fade"
6873
:hide-overlay="true"
6974
@update:model-value="val => emit('update:modelValue', val)"
7075
>

packages/vue-final-modal/src/components/CoreModal/CoreModal.vue

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { useFocusTrap } from './useFocusTrap'
88
import { useLockScroll } from './useBodyScrollLock'
99
import { useEvent } from './useEvent'
1010
import { useZIndex } from './useZIndex'
11+
import { vVisible } from './vVisible'
1112
import { noop, once } from '~/utils'
1213
import type { InternalVfm, Modal, Vfm } from '~/Modal'
1314
import { useSwipeToClose } from '~/useSwipeToClose'
@@ -177,6 +178,7 @@ onBeforeUnmount(() => {
177178
v-if="displayDirective !== 'if' || visible"
178179
v-show="displayDirective !== 'show' || visible"
179180
ref="vfmRootEl"
181+
v-visible="displayDirective !== 'visible' || visible"
180182
class="vfm vfm--fixed vfm--inset"
181183
:class="{ 'vfm--prevent-none': background === 'interactive' }"
182184
:style="{ zIndex }"
@@ -186,19 +188,23 @@ onBeforeUnmount(() => {
186188
@mouseup.self="() => onMouseupRoot()"
187189
@mousedown.self="e => onMousedown(e)"
188190
>
189-
<Transition v-if="!hideOverlay" v-bind="overlayTransition" :appear="displayDirective === 'if'" v-on="overlayListeners">
191+
<Transition v-if="!hideOverlay" v-bind="overlayTransition" :appear="true" v-on="overlayListeners">
190192
<div
191-
v-if="overlayVisible"
193+
v-if="displayDirective !== 'if' || overlayVisible"
194+
v-show="displayDirective !== 'show' || overlayVisible"
195+
v-visible="displayDirective !== 'visible' || overlayVisible"
192196
class="vfm__overlay vfm--overlay vfm--absolute vfm--inset vfm--prevent-none"
193197
:class="overlayClass"
194198
:style="overlayStyle"
195199
aria-hidden="true"
196200
/>
197201
</Transition>
198-
<Transition v-bind="contentTransition" :appear="displayDirective === 'if'" v-on="contentListeners">
202+
<Transition v-bind="contentTransition" :appear="true" v-on="contentListeners">
199203
<div
200-
v-show="contentVisible"
204+
v-if="displayDirective !== 'if' || contentVisible"
205+
v-show="displayDirective !== 'show' || contentVisible"
201206
ref="vfmContentEl"
207+
v-visible="displayDirective !== 'visible' || contentVisible"
202208
class="vfm__content vfm--outline-none"
203209
:class="[contentClass, { 'vfm--prevent-auto': background === 'interactive' }]"
204210
:style="contentStyle"
@@ -259,15 +265,22 @@ onBeforeUnmount(() => {
259265
outline: none;
260266
}
261267
262-
.vfm-fade-enter-active,
263-
.vfm-fade-leave-active {
264-
transition: opacity .3s;
268+
@keyframes fade-in {
269+
from { opacity: 0; }
270+
to { opacity: 1; }
265271
}
266-
.vfm-fade-enter-from,
267-
.vfm-fade-leave-to {
268-
opacity: 0;
272+
273+
@keyframes fade-out {
274+
from { opacity: 1 }
275+
to { opacity: 0 }
269276
}
270277
278+
.vfm-fade-enter-active {
279+
animation: fade-in .3s ease;
280+
}
281+
.vfm-fade-leave-active {
282+
animation: fade-out .3s ease;
283+
}
271284
.vfm-bounce-back {
272285
transition-property: transform;
273286
transition-duration: .3s;

packages/vue-final-modal/src/components/CoreModal/CoreModalProps.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,9 @@ export const coreModalProps = {
4444
* ```
4545
*/
4646
displayDirective: {
47-
type: String as PropType<'if' | 'show'>,
47+
type: String as PropType<'if' | 'show' | 'visible'>,
4848
default: 'if',
49-
validator: (prop: any) => ['if', 'show'].includes(prop),
49+
validator: (prop: any) => ['if', 'show', 'visible'].includes(prop),
5050
},
5151
/**
5252
* @description Hide the overlay or not.
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import type { Directive } from 'vue'
2+
3+
interface VVisibleElement extends HTMLElement {
4+
// _vov = vue original visibility
5+
_vov: string
6+
}
7+
8+
export const vVisible: Directive = {
9+
beforeMount(el, { value }, { transition }) {
10+
el._vov = el.style.visibility === 'hidden' ? '' : el.style.visibility
11+
if (transition && value)
12+
transition.beforeEnter(el)
13+
else
14+
setVisibility(el, value)
15+
},
16+
mounted(el, { value }, { transition }) {
17+
if (transition && value)
18+
transition.enter(el)
19+
},
20+
updated(el, { value, oldValue }, { transition }) {
21+
if (!value === !oldValue)
22+
return
23+
if (transition) {
24+
if (value) {
25+
transition.beforeEnter(el)
26+
setVisibility(el, true)
27+
transition.enter(el)
28+
}
29+
else {
30+
transition.leave(el, () => {
31+
setVisibility(el, false)
32+
})
33+
}
34+
}
35+
else {
36+
setVisibility(el, value)
37+
}
38+
},
39+
beforeUnmount(el, { value }) {
40+
setVisibility(el, value)
41+
},
42+
}
43+
44+
function setVisibility(el: VVisibleElement, value: unknown): void {
45+
el.style.visibility = value ? el._vov : 'hidden'
46+
}

0 commit comments

Comments
 (0)