jenesius-vue-modal
Advanced tools
Comparing version 1.0.14 to 1.1.0
{ | ||
"name": "jenesius-vue-modal", | ||
"version": "1.0.14", | ||
"version": "1.1.0", | ||
"private": false, | ||
@@ -18,3 +18,4 @@ "description": "Simple modal plugin for Vue3", | ||
"dependencies": { | ||
"vue": "^3.0.6" | ||
"vue": "^3.0.6", | ||
"vue-router": "^4.0.10" | ||
}, | ||
@@ -21,0 +22,0 @@ "devDependencies": { |
@@ -1,31 +0,88 @@ | ||
import {ref, watch, shallowRef} from "vue"; | ||
/*eslint-disable*/ | ||
import {ref, watch, shallowRef, getCurrentInstance} from "vue"; | ||
import WidgetModalContainer from "./WidgetModalContainer"; | ||
export const modalQueue = ref([]); //All modals that showing now | ||
function ModalObject(id){ | ||
const object = { | ||
id: id | ||
}; | ||
const state = { | ||
modalId: 0, | ||
initialized: false, | ||
} | ||
object.close = () => { | ||
closeById(id); | ||
const guards = { | ||
store: {}, | ||
add(id, name, func){ | ||
const availableNames = ["close"]; | ||
if (!availableNames.includes(name)) return console.warn(`Name ${name} is not declaration.`); | ||
if (!this.store[id]) this.store[id] = {}; | ||
if (!this.store[id][name]) this.store[id][name] = []; | ||
if (typeof func !== "function") return console.warn("Onclose callback was provided not function:", func); | ||
this.store[id][name].push(func); | ||
}, | ||
get(id, name) { | ||
if (!(id in this.store)) return []; | ||
if (!(name in this.store[id])) return []; | ||
return this.store[id][name]; | ||
} | ||
} | ||
return object | ||
class ModalObject{ | ||
id; | ||
component; | ||
params; | ||
constructor(component, params) { | ||
this.id = state.modalId++; | ||
this.component = shallowRef(component); | ||
this.params = params; | ||
if (component.beforeModalClose) guards.add(this.id, "close", component.beforeModalClose); | ||
} | ||
close(){ | ||
return closeById(this.id); | ||
} | ||
set onclose(func) { | ||
guards.add(this.id, "close", func); | ||
} | ||
} | ||
const state = { | ||
modalId: 0, | ||
initialized: false | ||
function createModalError() { | ||
return Object.assign(new ModalError(), { | ||
isModalError: true | ||
}); | ||
} | ||
export const modalQueue = ref([]); | ||
function canOnlyBeCalledOnce(next) { | ||
let called = false; | ||
return function () { | ||
if (called) console.warn(`The "next" callback was called more than once in one modal's guard. It should be called exactly one time in each navigation guard. This will fail in production.`); | ||
if (!called) { | ||
called = true; | ||
next.apply(null, arguments); | ||
} | ||
}; | ||
} | ||
watch(modalQueue.value, () => { | ||
if (modalQueue.value.length) document.body.style.overflowY = "hidden"; | ||
else document.body.style.overflowY = "auto"; | ||
}) | ||
function closeById(id) { | ||
function closeById(id){ | ||
const indexFoRemove = modalQueue.value.findIndex(item => item.id === id); | ||
@@ -36,5 +93,58 @@ | ||
modalQueue.value.splice(indexFoRemove, 1); | ||
const arr = guards.get(id, "close").map(guard => guardToPromiseFn(guard, id)); | ||
return runGuardQueue(arr) | ||
.then(() => { | ||
modalQueue.value.splice(indexFoRemove, 1); | ||
delete guards.store[id]; | ||
delete instanceStorage[id]; | ||
}) | ||
.catch(err => (err instanceof ModalError)?err: Promise.reject(err)) | ||
} | ||
class ModalError extends Error{ | ||
isModalError; | ||
constructor() { | ||
super(); | ||
this.isModalError = true; | ||
} | ||
} | ||
function guardToPromiseFn(guard, id){ | ||
return () => new Promise((resolve, reject) => { | ||
const next = (valid) => { | ||
if (valid === false) return reject(createModalError()); | ||
if (valid instanceof Error) reject(valid); | ||
resolve(); | ||
}; | ||
Promise.resolve(guard.call(instanceStorage[id], canOnlyBeCalledOnce(next))) | ||
.then(next) | ||
.catch(err => reject(err)); | ||
}); | ||
} | ||
function runGuardQueue(guards) { | ||
return guards.reduce((promise, guard) => promise.then(() => guard()), Promise.resolve()); | ||
} | ||
watch(modalQueue.value, () => { | ||
try { | ||
if (modalQueue.value.length) document.body.style.overflowY = "hidden"; | ||
else document.body.style.overflowY = "auto"; | ||
} catch (e) { | ||
} | ||
}) | ||
/** | ||
@@ -48,12 +158,8 @@ * Function open one and close previous modals | ||
export function openModal(component, params = {}){ | ||
closeModal(); | ||
return pushModal(component, params); | ||
} | ||
return closeModal() | ||
.then(() => { | ||
if (!modalQueue.value.length) return pushModal(component, params) | ||
/** | ||
* Function close all previous modals. | ||
* | ||
* */ | ||
export function closeModal() { | ||
modalQueue.value = []; | ||
return null; | ||
}) | ||
} | ||
@@ -65,18 +171,22 @@ | ||
export function pushModal(component, params = {}) { | ||
return _addModal(component, params); | ||
} | ||
function _addModal(component, params){ | ||
if (!state.initialized) { | ||
throw `Modal Container not found. Put container from jenesius-vue-modal in App's template. Check documentation for more information https://www.npmjs.com/package/jenesius-vue-modal.`; | ||
let err = `Modal Container not found. Put container from jenesius-vue-modal in App's template. Check documentation for more information https://www.npmjs.com/package/jenesius-vue-modal.`; | ||
console.warn(err); | ||
throw err; | ||
} | ||
state.modalId++; | ||
const modal = new ModalObject(component, params); | ||
modalQueue.value.push({ | ||
component : shallowRef(component), | ||
params : params, | ||
id : state.modalId | ||
}); | ||
modalQueue.value.push(modal); | ||
return ModalObject(state.modalId); | ||
return modal; | ||
} | ||
@@ -89,23 +199,23 @@ | ||
export function popModal(){ | ||
modalQueue.value.pop(); | ||
if (modalQueue.value.length === 0) return; | ||
let lastModal = modalQueue.value[modalQueue.value.length - 1]; | ||
return lastModal.close(); | ||
} | ||
export const container = WidgetModalContainer; | ||
/** | ||
* Function close all previous modals. | ||
* | ||
* */ | ||
export function closeModal() { | ||
return runGuardQueue(modalQueue.value.map(modalObject => () => modalObject.close())) | ||
} | ||
export function useModal(){ | ||
return { | ||
openModal, | ||
closeModal, | ||
popModal, | ||
pushModal, | ||
} | ||
} | ||
export const container = WidgetModalContainer; | ||
export function initialize(){ | ||
state.initialized = true; | ||
/** | ||
@@ -115,7 +225,40 @@ * If user press Escape then close last opened modal | ||
document.addEventListener("keyup", e => { | ||
if (e.key === "Escape" || e.code === "Escape") popModal(); | ||
}) | ||
} | ||
export function onBeforeModalClose(callback){ | ||
const a = getCurrentInstance(); | ||
let modalId = a.attrs["modal-id"].replace(/[^0-9]/g, ""); | ||
guards.add(modalId, "close", callback); | ||
} | ||
//Для сохранения this | ||
const instanceStorage = {}; | ||
export function saveInstance(id, instance) { | ||
instanceStorage[id] = instance; | ||
} | ||
/** | ||
* Deprecated | ||
* */ | ||
export function useModal(){ | ||
console.warn("Function useModal is deprecated and was removed on 2.x.x version. Please use: import {openModal, closeModal, pushModal, popModal} from 'jenesius-vue-modal';"); | ||
return { | ||
openModal, | ||
closeModal, | ||
popModal, | ||
pushModal, | ||
} | ||
} |
# Jenesius Vue Modal | ||
Jenesius vue modal is simple library for **Vue 3** only.[Web](https://modal.jenesius.com/) | ||
Jenesius vue modal is simple library for **Vue 3** only. | ||
- [Site](https://modal.jenesius.com/) | ||
- [Documentation](https://modal.jenesius.com/docs.html/installation#npm) | ||
![](https://img.shields.io/github/stars/Jenesius/vue-modal) | ||
@@ -42,13 +45,3 @@ ![Greet everyone](https://github.com/Jenesius/vue-modal/actions/workflows/node.js.yml/badge.svg) | ||
``` | ||
or | ||
```js | ||
import {useModal} from "jenesius-vue-modal"; | ||
export default{ | ||
setup(){ | ||
const {openModal} = useModal(); | ||
openModal(VueComponent, props); | ||
} | ||
} | ||
``` | ||
@@ -64,2 +57,38 @@ ## Methods | ||
## onclose hook | ||
To track the closing of a modal window, you need to use **onclick** | ||
```js | ||
const modal = await openModal(Modal); | ||
modal.onclose = () => { | ||
console.log("Close"); | ||
} | ||
``` | ||
To cancel closing the window, return **false**: | ||
```js | ||
const modal = await openModal(Modal); | ||
modal.onclose = (next) => { | ||
if (something === "false") return next(false); | ||
} | ||
closeModal();//if something === false, modal will not be closed | ||
``` | ||
Inside component, you can use: | ||
```js | ||
export default{ | ||
beforeModalClose(next){} | ||
} | ||
``` | ||
or | ||
```js | ||
export default{ | ||
setup() { | ||
onBeforeModalClose((next) => { | ||
}); | ||
} | ||
} | ||
``` | ||
## Example VueModalComponent | ||
@@ -82,7 +111,5 @@ | ||
```js | ||
import {useModal} from "jenesius-vue-modal" | ||
import {openModal} from "jenesius-vue-modal" | ||
import WidgeTestModal from "WidgeTestModal.vue"; | ||
const {openModal} = useModal(); | ||
openModal(WidgeTestModal, { | ||
@@ -92,1 +119,5 @@ title: "Hello World!" | ||
``` | ||
--- | ||
####Do you like this module? Put a star on [GitHub](https://github.com/Jenesius/vue-modal) |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
14088
7
175
120
2
+ Addedvue-router@^4.0.10
+ Added@vue/devtools-api@6.6.4(transitive)
+ Addedvue-router@4.5.0(transitive)