Skip to content

Commit bbd4786

Browse files
committed
feat: add stop() for @beforeOpen and beforeClose event #367
1 parent 6ed6450 commit bbd4786

File tree

5 files changed

+55
-52
lines changed

5 files changed

+55
-52
lines changed

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

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import { useToClose } from './useToClose'
66
import { useModelValue } from './useModelValue'
77
import { useFocusTrap } from './useFocusTrap'
88
import { useLockScroll } from './useBodyScrollLock'
9-
import { useEvent } from './useEvent'
109
import { useZIndex } from './useZIndex'
1110
import { vVisible } from './vVisible'
1211
import { noop, once } from '~/utils'
@@ -18,9 +17,9 @@ import { internalVfmSymbol, vfmSymbol } from '~/injectionSymbols'
1817
export interface CoreModalEmits {
1918
(e: 'update:modelValue', modelValue: boolean): void
2019
21-
(e: 'beforeOpen'): void
20+
(e: 'beforeOpen', payload: { stop: () => void }): void
2221
(e: 'opened'): void
23-
(e: 'beforeClose'): void
22+
(e: 'beforeClose', payload: { stop: () => void }): void
2423
(e: 'closed'): void
2524
2625
/** onClickOutside will only be emitted when clickToClose equal to `false` */
@@ -56,12 +55,11 @@ const vfmContentEl = ref<HTMLDivElement>()
5655
5756
const { focus, blur } = useFocusTrap(props, { focusEl: vfmRootEl })
5857
const { zIndex, refreshZIndex, resetZIndex } = useZIndex(props)
59-
const { modelValueLocal } = useModelValue(props, emit)
58+
const { modelValueLocal } = useModelValue(props, emit, { open, close })
6059
const { enableBodyScroll, disableBodyScroll } = useLockScroll(props, {
6160
lockScrollEl: vfmRootEl,
6261
modelValueLocal,
6362
})
64-
const { emitEvent } = useEvent(emit)
6563
6664
let resolveToggle: (res: string) => void = (noop)
6765
@@ -87,14 +85,14 @@ const {
8785
})
8886
},
8987
onEnter() {
90-
emitEvent('opened')
88+
emit('opened')
9189
resolveToggle('opened')
9290
},
9391
onLeave() {
9492
deleteFromOpenedModals(getModalInstance())
9593
resetZIndex()
9694
enableBodyScroll()
97-
emitEvent('closed')
95+
emit('closed')
9896
resolveToggle('closed')
9997
},
10098
})
@@ -139,28 +137,32 @@ onMounted(() => {
139137
modals.push(modalInstance)
140138
})
141139
142-
if (modelValueLocal.value)
143-
open()
140+
if (props.modelValue)
141+
modelValueLocal.value = true
144142
145-
watch(modelValueLocal, (value) => {
146-
value ? open() : close()
147-
})
148-
149-
async function open() {
150-
emitEvent('beforeOpen')
143+
function open(): boolean {
144+
let shouldStop = false
145+
emit('beforeOpen', { stop: () => shouldStop = true })
146+
if (shouldStop)
147+
return false
151148
moveToLastOpenedModals(modalInstance)
152149
moveToLastOpenedModalOverlays(modalInstance)
153150
refreshZIndex(index.value)
154151
openLastOverlay()
155152
enterTransition()
153+
return true
156154
}
157155
158-
function close() {
159-
emitEvent('beforeClose')
160-
deleteFromOpenedModalOverlays(modalInstance)
156+
function close(): boolean {
157+
let shouldStop = false
158+
emit('beforeClose', { stop: () => shouldStop = true })
159+
if (shouldStop)
160+
return false
161+
deleteFromOpenedModalOverlays(getModalInstance())
161162
openLastOverlay()
162163
blur()
163164
leaveTransition()
165+
return true
164166
}
165167
166168
onBeforeUnmount(() => {

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

Lines changed: 0 additions & 26 deletions
This file was deleted.

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

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,39 @@
1-
import type { Ref } from 'vue'
2-
import { ref, watch } from 'vue'
1+
import { computed, ref, watch } from 'vue'
32
import type CoreModal from './CoreModal.vue'
43

54
export function useModelValue(
65
props: InstanceType<typeof CoreModal>['$props'],
76
emit: InstanceType<typeof CoreModal>['$emit'],
8-
): { modelValueLocal: Ref<boolean> } {
9-
const modelValueLocal = ref<boolean>(!!props.modelValue)
7+
options: {
8+
open: () => boolean
9+
close: () => boolean
10+
},
11+
) {
12+
const { open, close } = options
13+
14+
/** The truth of modal open or close */
15+
const _modelValueLocal = ref<boolean>(false)
16+
17+
/**
18+
* A WritableComputedRef, a only variable to control open or close the modal
19+
*/
20+
const modelValueLocal = computed({
21+
get: () => _modelValueLocal.value,
22+
set: setModelValueLocal,
23+
})
24+
25+
/**
26+
* Because of the open/close can be stopped in `@beforeOpen`, `@beforeClose` events.
27+
* So the function is to make sure `_modelValueLocal`, `props.modelValue` are always the same value
28+
*/
29+
function setModelValueLocal(val: boolean) {
30+
const success = val ? open() : close()
31+
if (success)
32+
_modelValueLocal.value = val
33+
else
34+
emit('update:modelValue', !val)
35+
}
36+
1037
watch(() => props.modelValue, (val) => {
1138
modelValueLocal.value = !!val
1239
})

packages/vue-final-modal/src/useApi.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -205,9 +205,9 @@ export function byPassAllModalEvents(emit?: InstanceType<typeof CoreModal>['$emi
205205
return {
206206
'onUpdate:modelValue': (val: boolean) => emit('update:modelValue', val),
207207

208-
'onBeforeClose': () => emit('beforeClose'),
208+
'onBeforeClose': (payload: { stop: () => void }) => emit('beforeClose', payload),
209209
'onClosed': () => emit('closed'),
210-
'onBeforeOpen': () => emit('beforeOpen'),
210+
'onBeforeOpen': (payload: { stop: () => void }) => emit('beforeOpen', payload),
211211
'onOpened': () => emit('opened'),
212212

213213
/** onClickOutside will only be emitted when clickToClose equal to `false` */

viteplay/src/components/VueFinalModal/TestModal.vue

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@ const props = defineProps({
1818
1919
const emit = defineEmits<{
2020
(e: 'update:modelValue', modelValue: boolean): void
21-
(e: 'beforeOpen'): void
21+
(e: 'beforeOpen', payload: { stop: () => void }): void
2222
(e: 'opened'): void
23-
(e: 'beforeClose'): void
23+
(e: 'beforeClose', payload: { stop: () => void }): void
2424
(e: 'closed'): void
2525
/** onClickOutside will only be emitted when clickToClose equal to `false` */
2626
(e: 'clickOutside'): void

0 commit comments

Comments
 (0)