Skip to content

Commit 748ca19

Browse files
committed
feat: allow importing component directly
1 parent 862aacf commit 748ca19

13 files changed

+165
-190
lines changed

dist/VueFinalModal.esm.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/VueFinalModal.esm.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/VueFinalModal.umd.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/VueFinalModal.umd.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lib/ModalsContainer.vue

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,6 @@
2323
<script>
2424
export default {
2525
props: {},
26-
computed: {
27-
api() {
28-
return this[this.options.key]
29-
}
30-
},
3126
methods: {
3227
slice(index) {
3328
this.api.dynamicModals.splice(index, 1)

lib/Plugin.js

Lines changed: 54 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,61 @@
1-
import { bindPrototype, registModal, registContainer } from './PluginCore'
2-
import { DUPLICATE_KEY, DUPLICATE_COMPONENT, DUPLICATE_DYNAMIC_CONTAINER } from './utils/errors'
3-
4-
const defaultOptions = {
5-
componentName: 'VueFinalModal',
6-
dynamicContainerName: 'ModalsContainer',
7-
key: '$vfm'
1+
import { defineApi, defineModal, defineContainer } from './PluginCore'
2+
3+
/**
4+
* @description Ensure that `_vfm` is used when function `installPlugin` is executed for the first time
5+
*/
6+
let _count = 0
7+
8+
const _key = '$vfm'
9+
const _componentName = 'VueFinalModal'
10+
const _dynamicContainerName = 'ModalsContainer'
11+
12+
/**
13+
* @description Support create multiple vfm instance
14+
*/
15+
export const defineVfm = () => {
16+
let api = defineApi()
17+
return {
18+
[_key]: api,
19+
[_componentName]: defineModal(api),
20+
[_dynamicContainerName]: defineContainer(api)
21+
}
822
}
923

10-
const validPlugin = (duplicateKey, duplicateComponent, duplicateDynamicContainer) => {
11-
if (!(duplicateKey || duplicateComponent || duplicateDynamicContainer)) return true
12-
13-
if (typeof window === 'undefined') return false
14-
15-
duplicateKey && console.error(DUPLICATE_KEY)
16-
duplicateComponent && console.error(DUPLICATE_COMPONENT)
17-
duplicateDynamicContainer && console.error(DUPLICATE_DYNAMIC_CONTAINER)
18-
19-
return false
24+
/**
25+
* @description Create a vfm instance by default for directly support `import { $vfm, VueFinalModal, ModalsContainer } from 'vue-final-modal'`
26+
*/
27+
const _vfm = defineVfm()
28+
export const { $vfm, VueFinalModal, ModalsContainer } = _vfm
29+
30+
/**
31+
* @description Register vfm instance globally
32+
* @deprecated not available in vue-final-modal 4
33+
*/
34+
const installVfm = (App, options = {}) => {
35+
const { $vfm, VueFinalModal, ModalsContainer } = _count === 0 ? _vfm : defineVfm()
36+
_count += 1
37+
const key = options.key || _key
38+
const componentName = options.componentName || _componentName
39+
const dynamicContainerName = options.dynamicContainerName || _dynamicContainerName
40+
Object.defineProperty(App.config.globalProperties, key, {
41+
get() {
42+
return $vfm
43+
}
44+
})
45+
App.provide(key, $vfm)
46+
App.component(componentName, VueFinalModal)
47+
App.component(dynamicContainerName, ModalsContainer)
2048
}
2149

22-
const Plugin = pluginOptions => ({
23-
install(app, options) {
24-
const _options = Object.assign({}, defaultOptions, pluginOptions, options)
25-
const duplicateKey = app.config.globalProperties[_options.key]
26-
const duplicateComponent = app._context.components[_options.componentName]
27-
const duplicateDynamicContainer = app._context.components[_options.dynamicContainerName]
28-
29-
if (validPlugin(duplicateKey, duplicateComponent, duplicateDynamicContainer)) {
30-
bindPrototype(app, _options)
31-
registModal(app, _options)
32-
registContainer(app, _options)
33-
}
50+
/**
51+
* @description Vue plugin for register vfm instance globally
52+
* @deprecated not available in vue-final-modal 4
53+
*/
54+
export const vfmPlugin = pluginOptions => ({
55+
install(App, options) {
56+
const _options = Object.assign({}, pluginOptions, options)
57+
installVfm(App, _options)
3458
}
3559
})
3660

37-
export default Plugin
61+
vfmPlugin.install = installVfm

lib/PluginCore.js

Lines changed: 57 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -2,79 +2,72 @@ import VueFinalModal from './VueFinalModal.vue'
22
import ModalsContainer from './ModalsContainer.vue'
33
import { shallowReactive } from 'vue'
44

5-
function assignOptions(component, options) {
6-
const _component = { ...component }
7-
Object.assign(_component.props, {
8-
options: { type: Object, default: () => options }
9-
})
10-
return _component
11-
}
12-
13-
function createVfm(options) {
14-
let vfm
5+
export function defineApi() {
6+
let _modalComponent = null
157

16-
return function() {
17-
vfm = {
18-
show(modal, ...args) {
19-
switch (typeof modal) {
20-
case 'string':
21-
return this.toggle(modal, true, ...args)
22-
case 'object': {
23-
return Promise.allSettled([
24-
new Promise((resolve, reject) => {
25-
const defaultModal = {
26-
value: true,
27-
id: Symbol('dynamicModal'),
28-
component: options.componentName,
29-
bind: {},
30-
slots: {},
31-
on: {},
32-
params: args[0],
33-
reject,
34-
opened() {
35-
resolve('show')
36-
}
8+
return {
9+
show(modal, ...args) {
10+
switch (typeof modal) {
11+
case 'string':
12+
return this.toggle(modal, true, ...args)
13+
case 'object': {
14+
return Promise.allSettled([
15+
new Promise((resolve, reject) => {
16+
const defaultModal = {
17+
value: true,
18+
id: Symbol('dynamicModal'),
19+
component: _modalComponent,
20+
bind: {},
21+
slots: {},
22+
on: {},
23+
params: args[0],
24+
reject,
25+
opened() {
26+
resolve('show')
3727
}
38-
this.dynamicModals.push(shallowReactive(Object.assign(defaultModal, modal)))
39-
})
40-
])
41-
}
28+
}
29+
this.dynamicModals.push(shallowReactive(Object.assign(defaultModal, modal)))
30+
})
31+
])
4232
}
43-
},
44-
hide(...names) {
45-
return this.toggle(names, false)
46-
},
47-
hideAll() {
48-
return this.hide(...this.openedModals.map(modal => modal.props.name))
49-
},
50-
toggle(name, ...args) {
51-
const modals = Array.isArray(name) ? this.get(...name) : this.get(name)
52-
return Promise.allSettled(modals.map(modal => modal.toggle(...args)))
53-
},
54-
get(...names) {
55-
return this.modals.filter(modal => names.includes(modal.props.name))
56-
},
57-
dynamicModals: shallowReactive([]),
58-
openedModals: [],
59-
modals: []
33+
}
34+
},
35+
hide(...names) {
36+
return this.toggle(names, false)
37+
},
38+
hideAll() {
39+
return this.hide(...this.openedModals.map(modal => modal.props.name))
40+
},
41+
toggle(name, ...args) {
42+
const modals = Array.isArray(name) ? this.get(...name) : this.get(name)
43+
return Promise.allSettled(modals.map(modal => modal.toggle(...args)))
44+
},
45+
get(...names) {
46+
return this.modals.filter(modal => names.includes(modal.props.name))
47+
},
48+
dynamicModals: shallowReactive([]),
49+
openedModals: [],
50+
modals: [],
51+
_setDefaultModal(modalComponent) {
52+
_modalComponent = modalComponent
6053
}
61-
return vfm
6254
}
6355
}
6456

65-
export function bindPrototype(app, options) {
66-
const vfm = createVfm(options)()
67-
Object.defineProperty(app.config.globalProperties, options.key, {
68-
get() {
69-
return vfm
70-
}
57+
function bindApi(component, api) {
58+
const _component = { ...component, props: { ...component.props } }
59+
Object.assign(_component.props, {
60+
api: { type: Object, default: () => api }
7161
})
72-
app.provide(options.key, vfm)
62+
return _component
7363
}
7464

75-
export function registModal(app, options) {
76-
app.component(options.componentName, assignOptions(VueFinalModal, options))
65+
export function defineModal(api) {
66+
const modalComponent = bindApi(VueFinalModal, api)
67+
api._setDefaultModal(modalComponent)
68+
return modalComponent
7769
}
78-
export function registContainer(app, options) {
79-
app.component(options.dynamicContainerName, assignOptions(ModalsContainer, options))
70+
71+
export function defineContainer(api) {
72+
return bindApi(ModalsContainer, api)
8073
}

lib/VueFinalModal.vue

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,8 @@
7070
</template>
7171

7272
<script>
73-
import { ref, reactive, onMounted, onBeforeUnmount, computed, nextTick, watch, inject } from 'vue'
73+
/* eslint-disable vue/no-mutating-props */
74+
import { ref, reactive, onMounted, onBeforeUnmount, computed, nextTick, watch } from 'vue'
7475
import FocusTrap from './utils/focusTrap.js'
7576
import {
7677
setStyle,
@@ -183,8 +184,6 @@ export default {
183184
const vfmOverlayTransition = ref(null)
184185
const vfmTransition = ref(null)
185186
186-
const $vfm = inject(props.options.key)
187-
188187
const modalStackIndex = ref(null)
189188
const $focusTrap = new FocusTrap()
190189
@@ -312,7 +311,7 @@ export default {
312311
}
313312
)
314313
315-
$vfm.modals.push(getModalInfo())
314+
props.api.modals.push(getModalInfo())
316315
317316
onMounted(() => {
318317
mounted()
@@ -322,8 +321,9 @@ export default {
322321
props.lockScroll && vfmContainer.value && enableBodyScroll(vfmContainer.value)
323322
root?.value?.remove()
324323
325-
let index = $vfm.modals.findIndex(vm => vm.uid === uid)
326-
$vfm.modals.splice(index, 1)
324+
let index = props.api.modals.findIndex(vm => vm.uid === uid)
325+
326+
props.api.modals.splice(index, 1)
327327
})
328328
function getModalInfo() {
329329
return {
@@ -356,19 +356,19 @@ export default {
356356
if (target || props.attach === false) {
357357
props.attach !== false && target.appendChild(root.value)
358358
359-
let index = $vfm.openedModals.findIndex(vm => vm.uid === uid)
359+
let index = props.api.openedModals.findIndex(vm => vm.uid === uid)
360360
361361
if (index !== -1) {
362362
// if this is already exist in modalStack, delete it
363-
$vfm.openedModals.splice(index, 1)
363+
props.api.openedModals.splice(index, 1)
364364
}
365-
$vfm.openedModals.push(getModalInfo())
365+
props.api.openedModals.push(getModalInfo())
366366
367-
modalStackIndex.value = $vfm.openedModals.length - 1
367+
modalStackIndex.value = props.api.openedModals.length - 1
368368
369369
handleLockScroll()
370370
371-
$vfm.openedModals
371+
props.api.openedModals
372372
.filter(vm => vm.uid !== uid)
373373
.forEach((vm, index) => {
374374
if (vm.getAttachElement() === target) {
@@ -386,14 +386,14 @@ export default {
386386
}
387387
}
388388
function close() {
389-
let index = $vfm.openedModals.findIndex(vm => vm.uid === uid)
389+
let index = props.api.openedModals.findIndex(vm => vm.uid === uid)
390390
if (index !== -1) {
391391
// remove this in modalStack
392-
$vfm.openedModals.splice(index, 1)
392+
props.api.openedModals.splice(index, 1)
393393
}
394-
if ($vfm.openedModals.length > 0) {
394+
if (props.api.openedModals.length > 0) {
395395
// If there are still nested modals opened
396-
const $_vm = $vfm.openedModals[$vfm.openedModals.length - 1]
396+
const $_vm = props.api.openedModals[props.api.openedModals.length - 1]
397397
$_vm.props.focusTrap && $_vm.$focusTrap.firstElement().focus()
398398
if ($_vm.props.focusRetain || $_vm.props.focusTrap) {
399399
$_vm.vfmContainer.value.focus()

lib/index.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1-
import Plugin from './Plugin'
1+
import { vfmPlugin } from './Plugin'
22

3-
export default Plugin
3+
export * from './Plugin'
4+
5+
export default vfmPlugin

lib/utils/errors.js

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

0 commit comments

Comments
 (0)