Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

jenesius-vue-modal

Package Overview
Dependencies
Maintainers
1
Versions
69
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

jenesius-vue-modal - npm Package Compare versions

Comparing version 1.5.5 to 1.6.0

tests/before-modal-close.spec.ts

24

dist/dts/utils/Modal.d.ts

@@ -6,15 +6,7 @@ /**

import { GuardFunctionWithHandle } from "./types";
declare type EventCallback = (data?: any) => any;
/**
* Value can be an EventCallback[]
* В Будущем можно обновить методы on и emit и сделать так, чтобы они работали
* с массивом эвентов.
* */
export interface EventCallbacksStorage {
[name: string]: EventCallback;
}
import EventEmitter from "jenesius-event-emitter";
export interface ModalOptions {
backgroundClose?: boolean;
}
export default class Modal {
export default class Modal extends EventEmitter {
/**

@@ -24,2 +16,3 @@ * @description Unique id of each modal window.

id: number;
events: {};
/**

@@ -39,7 +32,2 @@ * @description Computed value. True - when the modal was closed.

/**
* @description Storage for events.
* modal.on(eventName, callback) will makeStorage: {eventName: callback}
* */
eventCallbacks: EventCallbacksStorage;
/**
* @description Click on the background will close modal windows.

@@ -55,2 +43,3 @@ * */

* @param {Object} props Object of input params. Used like props.
* @param {Object} options
* */

@@ -70,7 +59,2 @@ constructor(component: Component | any, props: any, options: ModalOptions);

get instance(): import("./types").ModalComponentInterface;
/**
* @description Event handler
* */
on(eventName: string, callback: EventCallback): void;
}
export {};

@@ -11,6 +11,6 @@ /**

* */
import guards from "./guards";
import { ModalComponentInterface } from "./types";
declare const modalQueue: import("vue").Ref<{
id: number;
events: {};
closed: any;

@@ -28,3 +28,3 @@ component: import("vue").FunctionalComponent<any, any> | {

render?: Function | undefined;
components?: Record<string, import("vue").Component<any, any, any, Record<string, import("vue").ComputedGetter<any> | import("vue").WritableComputedOptions<any>>, import("vue").MethodOptions>> | undefined;
components?: Record<string, import("vue").Component<any, any, any, import("vue").ComputedOptions, import("vue").MethodOptions>> | undefined;
directives?: Record<string, import("vue").Directive<any, any>> | undefined;

@@ -89,22 +89,25 @@ inheritAttrs?: boolean | undefined;

PRIVATE_APIS?: boolean | "suppress-warning" | undefined;
MODE?: 2 | 3 | ((comp: import("vue").ComponentOptions<any, any, any, Record<string, import("vue").ComputedGetter<any> | import("vue").WritableComputedOptions<any>>, import("vue").MethodOptions, any, any, any> | import("vue").FunctionalComponent<any, any> | {
new (...args: any[]): any;
__isFragment?: undefined;
__isTeleport?: undefined;
__isSuspense?: undefined;
} | null) => 2 | 3) | undefined;
MODE?: 2 | 3 | ((comp: import("vue").Component<any, any, any, import("vue").ComputedOptions, import("vue").MethodOptions> | null) => 2 | 3) | undefined;
} | undefined;
data?: ((this: any, vm: any) => any) | undefined;
computed?: Record<string, import("vue").ComputedGetter<any> | import("vue").WritableComputedOptions<any>> | undefined;
computed?: import("vue").ComputedOptions | undefined;
methods?: import("vue").MethodOptions | undefined;
watch?: Record<string, string | import("vue").WatchCallback<any, any> | ({
handler: string | import("vue").WatchCallback<any, any>;
} & import("vue").WatchOptions<boolean>) | (string | import("vue").WatchCallback<any, any> | ({
handler: string | import("vue").WatchCallback<any, any>;
} & import("vue").WatchOptions<boolean>))[]> | undefined;
provide?: Function | Record<string | symbol, unknown> | undefined;
inject?: string[] | Record<string | symbol, string | symbol | {
from?: string | symbol | undefined;
default?: unknown;
}> | undefined;
watch?: {
[x: string]: (string | import("vue").WatchCallback<any, any> | ({
handler: string | import("vue").WatchCallback<any, any>;
} & import("vue").WatchOptions<boolean>)) | (string | import("vue").WatchCallback<any, any> | ({
handler: string | import("vue").WatchCallback<any, any>;
} & import("vue").WatchOptions<boolean>))[];
} | undefined;
provide?: import("vue").ComponentProvideOptions | undefined;
inject?: (string[] | {
[x: string]: string | symbol | {
from?: string | symbol | undefined;
default?: unknown;
};
[x: symbol]: string | symbol | {
from?: string | symbol | undefined;
default?: unknown;
};
}) | undefined;
filters?: Record<string, Function> | undefined;

@@ -138,3 +141,2 @@ mixins?: any[] | undefined;

props: any;
eventCallbacks: import("./Modal").EventCallbacksStorage;
backgroundClose: boolean;

@@ -144,3 +146,6 @@ close: () => Promise<void>;

readonly instance: ModalComponentInterface;
on: (eventName: string, callback: (data?: any) => any) => void;
on: (name: string, callback: import("jenesius-event-emitter").Callback) => () => void;
emit: (name: string, data?: any) => void;
off: (name: string, callback: import("jenesius-event-emitter").Callback) => void;
cleanEvents: () => void;
}[]>;

@@ -155,2 +160,2 @@ interface InstancesStorageInterface {

declare const state: StateInterface;
export { modalQueue, guards, state };
export { modalQueue, state };
/*!
* jenesius-vue-modal v1.5.5
* jenesius-vue-modal v1.6.0
* (c) 2022 Jenesius

@@ -8,7 +8,18 @@ * @license MIT

Object.defineProperty(exports, '__esModule', { value: true });
Object.defineProperty(exports, '__esModule', {
value: true
});
var vue = require('vue');
/******************************************************************************
var EventEmitter = require('jenesius-event-emitter');
function _interopDefaultLegacy(e) {
return e && typeof e === 'object' && 'default' in e ? e : {
'default': e
};
}
var EventEmitter__default = /*#__PURE__*/_interopDefaultLegacy(EventEmitter);
/*! *****************************************************************************
Copyright (c) Microsoft Corporation.

@@ -27,120 +38,256 @@

***************************************************************************** */
/* global Reflect, Promise */
var extendStatics = function(d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
return extendStatics(d, b);
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf || {
__proto__: []
} instanceof Array && function (d, b) {
d.__proto__ = b;
} || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
};
return extendStatics(d, b);
};
function __extends(d, b) {
if (typeof b !== "function" && b !== null)
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
extendStatics(d, b);
function __() {
this.constructor = d;
}
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
}
function __awaiter(thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
function adopt(value) {
return value instanceof P ? value : new P(function (resolve) {
resolve(value);
});
}
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) {
try {
step(generator.next(value));
} catch (e) {
reject(e);
}
}
function rejected(value) {
try {
step(generator["throw"](value));
} catch (e) {
reject(e);
}
}
function step(result) {
result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected);
}
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
}
function __generator(thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (_) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
var _ = {
label: 0,
sent: function () {
if (t[0] & 1) throw t[1];
return t[1];
},
trys: [],
ops: []
},
f,
y,
t,
g;
return g = {
next: verb(0),
"throw": verb(1),
"return": verb(2)
}, typeof Symbol === "function" && (g[Symbol.iterator] = function () {
return this;
}), g;
function verb(n) {
return function (v) {
return step([n, v]);
};
}
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (_) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0:
case 1:
t = op;
break;
case 4:
_.label++;
return {
value: op[1],
done: false
};
case 5:
_.label++;
y = op[1];
op = [0];
continue;
case 7:
op = _.ops.pop();
_.trys.pop();
continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) {
_ = 0;
continue;
}
if (op[0] === 3 && (!t || op[1] > t[0] && op[1] < t[3])) {
_.label = op[1];
break;
}
if (op[0] === 6 && _.label < t[1]) {
_.label = t[1];
t = op;
break;
}
if (t && _.label < t[2]) {
_.label = t[2];
_.ops.push(op);
break;
}
if (t[2]) _.ops.pop();
_.trys.pop();
continue;
}
op = body.call(thisArg, _);
} catch (e) {
op = [6, e];
y = 0;
} finally {
f = t = 0;
}
if (op[0] & 5) throw op[1];
return {
value: op[0] ? op[1] : void 0,
done: true
};
}
}
/**
* last change: 25.11.2021
* */
var ModalError = /** @class */ (function (_super) {
__extends(ModalError, _super);
function ModalError(message, details) {
if (details === void 0) { details = null; }
var _this = _super.call(this) || this;
_this.isModalError = true;
_this.message = message;
_this.details = details;
return _this;
var ModalError =
/** @class */
function (_super) {
__extends(ModalError, _super);
function ModalError(message, details) {
if (details === void 0) {
details = null;
}
ModalError.Undefined = function (id) {
return new ModalError("Modal with id: " + id + " not founded. The modal window may have been closed earlier.");
};
ModalError.UndefinedGuardName = function (name) {
return new ModalError("Guard's name " + name + " is not declaration.");
};
ModalError.NextReject = function (id) {
return new ModalError("Guard returned false. Modal navigation was stopped. Modal id " + id);
};
ModalError.GuardDeclarationType = function (func) {
return new ModalError("Guard's type should be a function. Provided:", func);
};
ModalError.ConfigurationType = function (config) {
return new ModalError("Configuration type must be an Object. Provided", config);
};
ModalError.ConfigurationUndefinedParam = function (param, availableParams) {
return new ModalError("In configuration founded unknown parameter: " + param + ". Available are " + availableParams.join(", ") + " ");
};
ModalError.QueueNoEmpty = function () {
return new ModalError("Modal's queue is not empty. Probably some modal reject closing by onClose hook.");
};
ModalError.EmptyModalQueue = function () {
return new ModalError("Modal queue is empty.");
};
ModalError.NotInitialized = function () {
return new ModalError("Modal Container not found. Put container from jenesius-vue-modal in App's template. Check documentation for more information https://modal.jenesius.com/docs.html/installation#getting-started.");
};
ModalError.ModalComponentNotProvided = function () {
return new ModalError("The first parameter(VueComponent) was not specified.");
};
ModalError.DuplicatedRouterIntegration = function () {
return new ModalError('useModalRouter.init should escaped only once.');
};
ModalError.ModalRouterIntegrationNotInitialized = function () {
return new ModalError("The integration was not initialized. Please, use useModalRouter.init(router). For more information: https://modal.jenesius.com/docs.html/integration-vue-router#installation");
};
ModalError.ModalEventNameMustBeString = function (eventName) {
return new ModalError("Event name must be a string. Provided: " + eventName);
};
return ModalError;
}(Error));
var _this = _super.call(this) || this;
_this.isModalError = true;
_this.message = message;
_this.details = details;
return _this;
}
ModalError.Undefined = function (id) {
return new ModalError("Modal with id: ".concat(id, " not founded. The modal window may have been closed earlier."));
};
ModalError.UndefinedGuardName = function (name) {
return new ModalError("Guard's name ".concat(name, " is not declaration."));
};
ModalError.NextReject = function (id) {
return new ModalError("Guard returned false. Modal navigation was stopped. Modal id ".concat(id));
};
ModalError.GuardDeclarationType = function (func) {
return new ModalError("Guard's type should be a function. Provided:", func);
};
ModalError.ConfigurationType = function (config) {
return new ModalError("Configuration type must be an Object. Provided", config);
};
ModalError.ConfigurationUndefinedParam = function (param, availableParams) {
return new ModalError("In configuration founded unknown parameter: ".concat(param, ". Available are ").concat(availableParams.join(", "), " "));
};
ModalError.QueueNoEmpty = function () {
return new ModalError("Modal's queue is not empty. Probably some modal reject closing by onClose hook.");
};
ModalError.EmptyModalQueue = function () {
return new ModalError("Modal queue is empty.");
};
ModalError.NotInitialized = function () {
return new ModalError("Modal Container not found. Put container from jenesius-vue-modal in App's template. Check documentation for more information https://modal.jenesius.com/docs.html/installation#getting-started.");
};
ModalError.ModalComponentNotProvided = function () {
return new ModalError("The first parameter(VueComponent) was not specified.");
};
ModalError.DuplicatedRouterIntegration = function () {
return new ModalError('useModalRouter.init should escaped only once.');
};
ModalError.ModalRouterIntegrationNotInitialized = function () {
return new ModalError("The integration was not initialized. Please, use useModalRouter.init(router). For more information: https://modal.jenesius.com/docs.html/integration-vue-router#installation");
};
ModalError.ModalEventNameMustBeString = function (eventName) {
return new ModalError("Event name must be a string. Provided: ".concat(eventName));
};
return ModalError;
}(Error);
/**
* last change: 18.02.2022
* */
var configuration = {
scrollLock: true,
animation: "modal-list",
backgroundClose: true,
escClose: true,
scrollLock: true,
animation: "modal-list",
backgroundClose: true,
escClose: true // Closing on press ESC key
};

@@ -155,8 +302,7 @@ /**

* */
function config(options) {
if (typeof options !== "object")
throw ModalError.ConfigurationType(options);
Object.assign(configuration, options);
if (typeof options !== "object") throw ModalError.ConfigurationType(options);
Object.assign(configuration, options);
}
/**

@@ -172,45 +318,37 @@ * last change: 25.11.2021

* */
var modalQueue = vue.ref([]); //All modals that showing now
var state$1 = {
initialized: false,
instanceStorage: {},
initialized: false,
instanceStorage: {}
};
vue.watch(modalQueue.value, function () {
if (!configuration.scrollLock)
return;
if (modalQueue.value.length)
document.body.style.overflowY = "hidden";
else
document.body.style.overflowY = "auto";
if (!configuration.scrollLock) return;
if (modalQueue.value.length) document.body.style.overflowY = "hidden";else document.body.style.overflowY = "auto";
});
/**
* last change: 25.11.2021
* */
var guards = {
store: {},
add: function (modalId, name, func) {
var _a;
if (typeof func !== "function")
throw ModalError.GuardDeclarationType(func);
if (!this.store[modalId])
this.store[modalId] = (_a = {},
_a[name] = [],
_a);
if (!this.store[modalId][name])
this.store[modalId][name] = [];
this.store[modalId][name].push(func);
},
get: function (id, name) {
if (!(id in this.store))
return [];
if (!(name in this.store[id]))
return [];
return this.store[id][name];
},
delete: function (id) {
if (!(id in this.store))
return;
delete this.store[id];
}
store: {},
add: function (modalId, name, func) {
var _a;
if (typeof func !== "function") throw ModalError.GuardDeclarationType(func);
if (!this.store[modalId]) this.store[modalId] = (_a = {}, _a[name] = [], _a);
if (!this.store[modalId][name]) this.store[modalId][name] = [];
this.store[modalId][name].push(func);
},
get: function (id, name) {
if (!(id in this.store)) return [];
if (!(name in this.store[id])) return [];
return this.store[id][name];
},
delete: function (id) {
if (!(id in this.store)) return;
delete this.store[id];
}
};

@@ -220,6 +358,9 @@ /**

* */
function runGuardQueue(guards) {
return guards.reduce(function (promiseAccumulator, guard) {
return promiseAccumulator.then(function () { return guard(); });
}, Promise.resolve());
return guards.reduce(function (promiseAccumulator, guard) {
return promiseAccumulator.then(function () {
return guard();
});
}, Promise.resolve());
}

@@ -233,36 +374,47 @@ /**

* */
function guardToPromiseFn(guard, id) {
return function () { return new Promise(function (resolve, reject) {
/**
* Next - hook for returned value from guard.
* */
var next = function (valid) {
if (valid === void 0) { valid = true; }
if (valid === false)
reject(ModalError.NextReject(id));
resolve();
};
Promise.resolve(guard.call(state$1.instanceStorage[id]))
.then(next)
.catch(function (err) { return reject(err); });
}); };
return function () {
return new Promise(function (resolve, reject) {
/**
* Next - hook for returned value from guard.
* */
var next = function (valid) {
if (valid === void 0) {
valid = true;
}
if (valid === false) reject(ModalError.NextReject(id));
resolve();
};
Promise.resolve(guard.call(state$1.instanceStorage[id])).then(next).catch(function (err) {
return reject(err);
});
});
};
}
/**
* @description Try to close all modals windows. Throw error if some modal has onClose hook with returned false value.
* */
function closeModal() {
return runGuardQueue(modalQueue.value.map(function (modalObject) { return function () { return modalObject.close(); }; }));
return runGuardQueue(modalQueue.value.map(function (modalObject) {
return function () {
return modalObject.close();
};
}));
}
/**
* @description Try to close the last opened modal window.
* */
function popModal() {
if (modalQueue.value.length === 0)
return Promise.resolve();
var lastModal = modalQueue.value[modalQueue.value.length - 1];
return lastModal.close();
if (modalQueue.value.length === 0) return Promise.resolve();
var lastModal = modalQueue.value[modalQueue.value.length - 1];
return lastModal.close();
}
/**

@@ -272,17 +424,19 @@ * @description Закрывает модальное окно по идентификатору

* */
function closeById(id) {
var indexRemoveElement = modalQueue.value.findIndex(function (item) { return item.id === id; });
//Modal with id not found
if (indexRemoveElement === -1)
return Promise.reject(ModalError.Undefined(id));
var arr = guards.get(id, "close")
.map(function (guard) { return guardToPromiseFn(guard, id); });
return runGuardQueue(arr)
.then(function () {
modalQueue.value.splice(indexRemoveElement, 1);
delete state$1.instanceStorage[id];
guards.delete(id);
});
var indexRemoveElement = modalQueue.value.findIndex(function (item) {
return item.id === id;
}); //Modal with id not found
if (indexRemoveElement === -1) return Promise.reject(ModalError.Undefined(id));
var arr = guards.get(id, "close").map(function (guard) {
return guardToPromiseFn(guard, id);
});
return runGuardQueue(arr).then(function () {
modalQueue.value.splice(indexRemoveElement, 1);
delete state$1.instanceStorage[id];
guards.delete(id);
});
}
/**

@@ -296,118 +450,117 @@ * last change: 05.12.2021

* * */
function saveInstance(id, instance) {
state$1.instanceStorage[id] = instance;
state$1.instanceStorage[id] = instance;
}
function getInstance(id) {
return state$1.instanceStorage[id];
return state$1.instanceStorage[id];
}
function DtoModalOptions(options) {
var output = {
backgroundClose: configuration.backgroundClose
};
if (options.backgroundClose !== undefined)
output.backgroundClose = options.backgroundClose;
return output;
var output = {
backgroundClose: configuration.backgroundClose
};
if (options.backgroundClose !== undefined) output.backgroundClose = options.backgroundClose;
return output;
}
/**
* last change: 18.02.2022
* */
var Modal = /** @class */ (function () {
var Modal =
/** @class */
function (_super) {
__extends(Modal, _super);
/**
* Создаёт объект управления модальным окном.
* Для управления идентификатором используется статическое поле modalId.
* ЕСЛИ В КОМПОНЕНТЕ ЕСТЬ beforeModalClose параметр, то добавляем его в guards
*
* @param {Object} component Any VueComponent that will be used like modal window
* @param {Object} props Object of input params. Used like props.
* @param {Object} options
* */
function Modal(component, props, options) {
var _this = _super.call(this) || this;
_this.events = vue.reactive({});
/**
* Создаёт объект управления модальным окном.
* Для управления идентификатором используется статическое поле modalId.
* ЕСЛИ В КОМПОНЕНТЕ ЕСТЬ beforeModalClose параметр, то добавляем его в guards
*
* @param {Object} component Any VueComponent that will be used like modal window
* @param {Object} props Object of input params. Used like props.
* @description Click on the background will close modal windows.
* */
function Modal(component, props, options) {
var _this = this;
/**
* @description Storage for events.
* modal.on(eventName, callback) will makeStorage: {eventName: callback}
* */
this.eventCallbacks = vue.reactive({});
/**
* @description Click on the background will close modal windows.
* */
this.backgroundClose = true;
this.id = Modal.modalId++;
this.component = component;
this.props = vue.ref(props);
/**
* БЛЯТЬ, ПОЧЕМУ ОНО ТАК?
* ОТВЕТ: ЭТОТ ЕБУЧИЙ ВЬЮ, ПРИ ДОБАВЛЕНИИ В modalQueue
* РАСКРЫВАЕТ COMPUTED(THIS.CLOSED) И КЛАДЁТ ТУДА ТУПО ЗНАЧЕНИЕ, А НЕ
* COMPUTED PROP {VALUE: BOOLEAN}
* ЧТО ЛОГИЧНО, НО ПО УЕБАНСКИ
* ----
* Более деликатное объяснение:
* Раньше в modalQueue ложили просто объект Modal.
* modalQueue.value.push(Modal)
* Т.к. modalQueue является реактивным объектом, оно автоматически делает
* реактивным и все свойства объекта, который кладётся в него. И у нас
* closed.value пропадало, оставалось лишь closed. Т.к. modalQueue и так
* полностью реактивно.
* Сейчас в modalQueue кладётся markRaw(помечаем, что не надо делать об
* ект реактивным). И close.value - остаётся
*
* 10.02.2022 @ЖЕНЯ, КОТОРЫЙ ЕЩЁ ПЛОХО ЗНАЕТ TS.
* */
this.closed = vue.computed(function () { return !modalQueue.value.includes(_this); });
/*
this.closed = computed(
() => !modalQueue.value.find(item => item.id === this.id)
);
*/
if (component.beforeModalClose)
guards.add(this.id, "close", component.beforeModalClose);
var dtoOptions = DtoModalOptions(options);
this.backgroundClose = dtoOptions.backgroundClose;
}
_this.backgroundClose = true;
_this.id = Modal.modalId++;
_this.component = component;
_this.props = vue.ref(props);
/**
* @description Method for closing the modal window
* БЛЯТЬ, ПОЧЕМУ ОНО ТАК?
* ОТВЕТ: ЭТОТ ЕБУЧИЙ ВЬЮ, ПРИ ДОБАВЛЕНИИ В modalQueue
* РАСКРЫВАЕТ COMPUTED(THIS.CLOSED) И КЛАДЁТ ТУДА ТУПО ЗНАЧЕНИЕ, А НЕ
* COMPUTED PROP {VALUE: BOOLEAN}
* ЧТО ЛОГИЧНО, НО ПО УЕБАНСКИ
* ----
* Более деликатное объяснение:
* Раньше в modalQueue ложили просто объект Modal.
* modalQueue.value.push(Modal)
* Т.к. modalQueue является реактивным объектом, оно автоматически делает
* реактивным и все свойства объекта, который кладётся в него. И у нас
* closed.value пропадало, оставалось лишь closed. Т.к. modalQueue и так
* полностью реактивно.
* Сейчас в modalQueue кладётся markRaw(помечаем, что не надо делать об
* ект реактивным). И close.value - остаётся
*
* 10.02.2022 @ЖЕНЯ, КОТОРЫЙ ЕЩЁ ПЛОХО ЗНАЕТ TS.
* */
Modal.prototype.close = function () {
return closeById(this.id);
};
Object.defineProperty(Modal.prototype, "onclose", {
/**
* @description Hook for handling modal closing
* */
set: function (func) {
guards.add(this.id, "close", func);
},
enumerable: false,
configurable: true
_this.closed = vue.computed(function () {
return !modalQueue.value.includes(_this);
});
Object.defineProperty(Modal.prototype, "instance", {
/**
* @description Return instance of modal component
* */
get: function () {
return getInstance(this.id);
},
enumerable: false,
configurable: true
});
/*
this.closed = computed(
() => !modalQueue.value.find(item => item.id === this.id)
);
*/
if (component.beforeModalClose) guards.add(_this.id, "close", component.beforeModalClose);
var dtoOptions = DtoModalOptions(options);
_this.backgroundClose = dtoOptions.backgroundClose;
return _this;
}
/**
* @description Method for closing the modal window
* */
Modal.prototype.close = function () {
return closeById(this.id);
};
Object.defineProperty(Modal.prototype, "onclose", {
/**
* @description Event handler
* @description Hook for handling modal closing
* */
Modal.prototype.on = function (eventName, callback) {
if (typeof eventName !== 'string')
throw ModalError.ModalEventNameMustBeString(eventName);
eventName = 'on' + eventName.charAt(0).toUpperCase() + eventName.slice(1);
// If eventName was added firstly
/*
if (!(eventName in this.eventCallbacks))
this.eventCallbacks[eventName] = []
*/
this.eventCallbacks[eventName] = callback.bind(this.instance);
};
Modal.modalId = 0;
return Modal;
}());
set: function (func) {
guards.add(this.id, "close", func);
},
enumerable: false,
configurable: true
});
Object.defineProperty(Modal.prototype, "instance", {
/**
* @description Return instance of modal component
* */
get: function () {
return getInstance(this.id);
},
enumerable: false,
configurable: true
});
Modal.modalId = 0;
return Modal;
}(EventEmitter__default["default"]);
/**

@@ -419,40 +572,49 @@ * Sync function for adding modal window.

* */
function _addModal(component, params, options) {
if (!state$1.initialized)
throw ModalError.NotInitialized();
if (!component)
throw ModalError.ModalComponentNotProvided();
var modal = new Modal(component, params, options);
/**
* modalQueue.value.push(Object.freeze(modal)) - фундаментальная ошибка!
* Таким способо мы запрещаем изменение любых свойст объекта - что является
* недопустим исключением, ведь объект может хранить, например, свойство
* `version`, которое по итогу будет не изменяемым.
*
* computed свойство 'closed' так-же потеряет реактивность в таком случае
*
* modalQueue.value.push(modal) - ошибка!
* Т.к. modalQueue является реактивным объектом и создаётся при помощи ref.
* В итоге все элементы, добавленные в неё, становятся реактивными полностью.
* Так же получим небольшие проблемы с computed свойствами, поскольку они
* И так уже находятся в реактивном объекте и разложаться.
*
* markRaw - пометка для vue, что к данному элементу не надо добавлять никак
* ой реактивности.
*
* */
//modalQueue.value.push(modal);
modalQueue.value.push(vue.markRaw(modal));
return modal;
if (!state$1.initialized) throw ModalError.NotInitialized();
if (!component) throw ModalError.ModalComponentNotProvided();
var modal = new Modal(component, params, options);
/**
* modalQueue.value.push(Object.freeze(modal)) - фундаментальная ошибка!
* Таким способо мы запрещаем изменение любых свойст объекта - что является
* недопустим исключением, ведь объект может хранить, например, свойство
* `version`, которое по итогу будет не изменяемым.
*
* computed свойство 'closed' так-же потеряет реактивность в таком случае
*
* modalQueue.value.push(modal) - ошибка!
* Т.к. modalQueue является реактивным объектом и создаётся при помощи ref.
* В итоге все элементы, добавленные в неё, становятся реактивными полностью.
* Так же получим небольшие проблемы с computed свойствами, поскольку они
* И так уже находятся в реактивном объекте и разложаться.
*
* markRaw - пометка для vue, что к данному элементу не надо добавлять никак
* ой реактивности.
*
* */
//modalQueue.value.push(modal);
modalQueue.value.push(vue.markRaw(modal));
return modal;
}
/**
* @description Method push modal to queue. Using this method you can open multiple windows. For closing use popModal
* */
function pushModal(component, props, options) {
if (props === void 0) { props = {}; }
if (options === void 0) { options = {}; }
return Promise.resolve().then(function () { return _addModal(component, props, options); });
if (props === void 0) {
props = {};
}
if (options === void 0) {
options = {};
}
return Promise.resolve().then(function () {
return _addModal(component, props, options);
});
}
/**

@@ -467,65 +629,32 @@ * @description OpenModal that was provided as component.

* */
function openModal(component, props, options) {
if (props === void 0) { props = {}; }
return closeModal()
.then(function () {
if (modalQueue.value.length)
throw ModalError.QueueNoEmpty();
})
.then(function () { return pushModal(component, props, options); });
if (props === void 0) {
props = {};
}
return closeModal().then(function () {
if (modalQueue.value.length) throw ModalError.QueueNoEmpty();
}).then(function () {
return pushModal(component, props, options);
});
}
function onBeforeModalClose(callback) {
var _a;
var a = vue.getCurrentInstance();
var attrModalId = String((_a = a === null || a === void 0 ? void 0 : a.attrs) === null || _a === void 0 ? void 0 : _a["modal-id"]);
var modalId = attrModalId.replace(/[^0-9]/g, "");
guards.add(Number(modalId), "close", callback);
var _a, _b, _c;
var a = vue.getCurrentInstance();
var attrModalId = String(((_a = a === null || a === void 0 ? void 0 : a.props) === null || _a === void 0 ? void 0 : _a.modalId) || ((_b = a === null || a === void 0 ? void 0 : a.props) === null || _b === void 0 ? void 0 : _b["modal-id"]) || ((_c = a === null || a === void 0 ? void 0 : a.attrs) === null || _c === void 0 ? void 0 : _c.modalId));
var modalId = attrModalId.replace(/[^0-9]/g, "");
guards.add(Number(modalId), "close", callback);
}
var script$1 = {
props: {
id : Number, // uniq identifier of modals,
},
setup(props){
const modalRef = vue.ref(null);
const containerRef = vue.ref(null);
vue.watch(() => modalRef.value, newValue => {
saveInstance(props.id, newValue);
});
function getModalById(id){
return modalQueue.value.find(elem => elem.id === id);
}
const modal = getModalById(props.id);
return () => vue.h("div", {
class: ["widget__modal-container__item", "modal-container"],
ref: containerRef,
onClick: e => {
if (e.target !== containerRef.value) return;
if (modal.backgroundClose) return popModal().catch(() => {})
}
}, [
vue.h(modal.component, {
...modal.props.value,
class: ["modal-item", "widget__modal-wrap"],//Save for compatibility
"modal-id": `_modal_${props.id}`,
ref: modalRef,
...modal.eventCallbacks
})
])
},
};
function styleInject(css, ref) {
if ( ref === void 0 ) ref = {};
if (ref === void 0) ref = {};
var insertAt = ref.insertAt;
if (!css || typeof document === 'undefined') { return; }
if (!css || typeof document === 'undefined') {
return;
}

@@ -556,7 +685,62 @@ var head = document.head || document.getElementsByTagName('head')[0];

script$1.__file = "plugin/components/WidgetModalContainerItem.vue";
var _export_sfc = (sfc, props) => {
const target = sfc.__vccOpts || sfc;
for (const [key, val] of props) {
target[key] = val;
}
return target;
};
const _sfc_main$1 = {
__name: 'WidgetModalContainerItem',
props: {
id: Number
},
setup(__props) {
const props = __props;
const modalRef = vue.ref(null);
const containerRef = vue.ref(null);
const modal = getModalById(props.id);
function getModalById(id) {
return modalQueue.value.find(elem => elem.id === id);
}
function handelClick(e) {
if (e.target !== containerRef.value) return;
if (modal.backgroundClose) return popModal().catch(() => {});
}
vue.watch(() => modalRef.value, newValue => {
saveInstance(props.id, newValue);
});
return (_ctx, _cache) => {
return vue.openBlock(), vue.createElementBlock("div", {
class: "widget__modal-container__item modal-container",
ref_key: "containerRef",
ref: containerRef,
onClick: handelClick
}, [(vue.openBlock(), vue.createBlock(vue.resolveDynamicComponent(vue.unref(modal).component), vue.mergeProps(vue.unref(modal).props.value, {
class: "modal-item widget__modal-wrap",
modalId: `_modal_${__props.id}`,
ref_key: "modalRef",
ref: modalRef
}, vue.toHandlers(vue.unref(modal).events)), null, 16
/* FULL_PROPS */
, ["modalId"]))], 512
/* NEED_PATCH */
);
};
}
};
var WidgetContainerModalItem = /*#__PURE__*/_export_sfc(_sfc_main$1, [['__file', "WidgetModalContainerItem.vue"]]);
/**
* last change: 18.02.2022
* */
/**

@@ -566,35 +750,37 @@ * @description Function run when ModalContainer was mounted in user's interface.

* */
function initialize() {
state$1.initialized = true;
document.addEventListener("keyup", function (e) {
// Closing the last modal window when user pressed Escape
if (configuration.escClose && e.key === "Escape" || e.code === "Escape")
popModal();
});
state$1.initialized = true;
document.addEventListener("keyup", function (e) {
// Closing the last modal window when user pressed Escape
if (configuration.escClose && e.key === "Escape" || e.code === "Escape") popModal();
});
}
var script = {
setup(){
vue.onMounted(initialize);
return () => {
return vue.h(vue.TransitionGroup, {name: configuration.animation}, {
default: () =>modalQueue.value.map(modalObject => {
return vue.h(script$1, {
key: modalObject.id,
id: modalObject.id,
});
})
})
}
},
components: {WidgetContainerModalItem: script$1}
};
var css_248z = "\n.modal-list-enter-active,\r\n .modal-list-leave-active,\r\n .modal-list-enter-active .modal-item,\r\n .modal-list-leave-active .modal-item\r\n {\r\n transition: all 0.2s ease;\n}\n.modal-list-enter-from,\r\n .modal-list-leave-to{\r\n\t\topacity: 0 !important;\n}\n.modal-list-enter-from .modal-item,\r\n .modal-list-leave-to .modal-item{\r\n\t\ttransform: translateY(-60px);\n}\r\n";
styleInject(css_248z);
const _sfc_main = {
setup() {
vue.onMounted(initialize);
return () => {
return vue.h(vue.TransitionGroup, {
name: configuration.animation
}, {
default: () => modalQueue.value.map(modalObject => {
return vue.h(WidgetContainerModalItem, {
key: modalObject.id,
id: modalObject.id
});
})
});
};
},
script.__file = "plugin/components/WidgetModalContainer.vue";
components: {
WidgetContainerModalItem
}
};
var WidgetModalContainer = /*#__PURE__*/_export_sfc(_sfc_main, [['__file', "WidgetModalContainer.vue"]]);
/**

@@ -650,77 +836,122 @@ * 18.02.2022

* */
var state = {
router: null
router: null
};
function init(router) {
var _this = this;
if (state.router)
throw ModalError.DuplicatedRouterIntegration();
state.router = router;
/**
* @description Функция для поиска объекта, который интегрирован с модальным
* окном. Если среди matched роутами и их находится компонента, которая явля
* ется обёрткой(ModalRoute, которую возвращает useModalRoute), то поиск пре
* кратится и вёрнтся ссылка на данный объект. Иначе null.
*
* @Return ModalRoute | null
* */
function findModal(routerLocation) {
for (var i = routerLocation.matched.length - 1; i >= 0; i--) {
var components = routerLocation.matched[i].components;
/**
* Problem:
* Object.values(components)
* return (RouteComponent | ModalRouterInterface)[]
*
* How to do it in TypeScript
* */
// @ts-ignore
var a = Object.values(components).find(function (route) { return route._isModal; });
if (a)
return a;
var _this = this;
if (state.router) throw ModalError.DuplicatedRouterIntegration();
state.router = router;
/**
* @description Функция для поиска объекта, который интегрирован с модальным
* окном. Если среди matched роутами и их находится компонента, которая явля
* ется обёрткой(ModalRoute, которую возвращает useModalRoute), то поиск пре
* кратится и вёрнтся ссылка на данный объект. Иначе null.
*
* @Return ModalRoute | null
* */
function findModal(routerLocation) {
for (var i = routerLocation.matched.length - 1; i >= 0; i--) {
var components = routerLocation.matched[i].components;
/**
* Problem:
* Object.values(components)
* return (RouteComponent | ModalRouterInterface)[]
*
* How to do it in TypeScript
* */
// @ts-ignore
var a = Object.values(components).find(function (route) {
return route._isModal;
});
if (a) return a;
}
return null;
}
/**
* @description Hook only for closing #1
* */
router.beforeEach(function (to, from) {
return __awaiter(_this, void 0, void 0, function () {
var modalRoute;
var _a, _b;
return __generator(this, function (_c) {
switch (_c.label) {
case 0:
_c.trys.push([0, 3,, 4]);
modalRoute = findModal(from);
if (!(modalRoute && !((_b = (_a = modalRoute.getModalObject()) === null || _a === void 0 ? void 0 : _a.closed) === null || _b === void 0 ? void 0 : _b.value))) return [3
/*break*/
, 2];
return [4
/*yield*/
, modalRoute.close(true)];
case 1:
_c.sent();
_c.label = 2;
case 2:
return [3
/*break*/
, 4];
case 3:
_c.sent();
return [2
/*return*/
, false];
case 4:
return [2
/*return*/
];
}
return null;
}
/**
* @description Hook only for closing #1
* */
router.beforeEach(function (to, from) { return __awaiter(_this, void 0, void 0, function () {
var modalRoute;
var _a, _b;
return __generator(this, function (_c) {
switch (_c.label) {
case 0:
_c.trys.push([0, 3, , 4]);
modalRoute = findModal(from);
if (!(modalRoute && !((_b = (_a = modalRoute.getModalObject()) === null || _a === void 0 ? void 0 : _a.closed) === null || _b === void 0 ? void 0 : _b.value))) return [3 /*break*/, 2];
return [4 /*yield*/, modalRoute.close(true)];
case 1:
_c.sent();
_c.label = 2;
case 2: return [3 /*break*/, 4];
case 3:
_c.sent();
return [2 /*return*/, false];
case 4: return [2 /*return*/];
}
});
}); });
/**
* @description Hook for opening modal #2
* */
router.afterEach(function (to) { return __awaiter(_this, void 0, void 0, function () {
var modal;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
modal = findModal(to);
if (!modal) return [3 /*break*/, 2];
return [4 /*yield*/, modal.initialize()];
case 1:
_a.sent();
_a.label = 2;
case 2: return [2 /*return*/];
}
});
}); });
});
});
});
/**
* @description Hook for opening modal #2
* */
router.afterEach(function (to) {
return __awaiter(_this, void 0, void 0, function () {
var modal;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
modal = findModal(to);
if (!modal) return [3
/*break*/
, 2];
return [4
/*yield*/
, modal.initialize()];
case 1:
_a.sent();
_a.label = 2;
case 2:
return [2
/*return*/
];
}
});
});
});
}

@@ -731,78 +962,116 @@ /**

* */
function useModalRouter(component) {
//Ссылка на modalObject
var modal = null;
//Ссылка на modalObject
var modal = null;
/**
* isNavigationClosingGuard используется в качестве реле при закрытии модаль
* ного окна. Т.к. мы подписываемся на закрытии модального окна и вызываем
* переход на шаг назад в router, мы можем перейти сразу на два шага назад:
* При управляемом переходе(при нажатии на предыдущую страницу, кнопку назад)
* происходит сперва обычный переход на предыдущий route, а затем ещё один
* переход назад: в onclose модального окна.
*
* Именно по этому, в onclose стоит проверка на isNavigationClosingGuard, а
* в обработчике #1 передаётся true, указывающее на то, что при закрытии мод
* ального кона не надо возвращаться на шаг назад в route.
* */
var isNavigationClosingGuard = false;
function initialize() {
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
if (!state.router) throw ModalError.ModalRouterIntegrationNotInitialized();
isNavigationClosingGuard = false;
modal = null;
return [4
/*yield*/
, openModal(component, vue.computed(function () {
var _a;
return (_a = state.router) === null || _a === void 0 ? void 0 : _a.currentRoute.value.params;
}))];
case 1:
modal = _a.sent();
modal.onclose = function () {
var _a;
if (!isNavigationClosingGuard) (_a = state.router) === null || _a === void 0 ? void 0 : _a.back();
};
return [2
/*return*/
];
}
});
});
}
return {
getModalObject: function () {
return modal;
},
/**
* isNavigationClosingGuard используется в качестве реле при закрытии модаль
* ного окна. Т.к. мы подписываемся на закрытии модального окна и вызываем
* переход на шаг назад в router, мы можем перейти сразу на два шага назад:
* При управляемом переходе(при нажатии на предыдущую страницу, кнопку назад)
* происходит сперва обычный переход на предыдущий route, а затем ещё один
* переход назад: в onclose модального окна.
*
* Именно по этому, в onclose стоит проверка на isNavigationClosingGuard, а
* в обработчике #1 передаётся true, указывающее на то, что при закрытии мод
* ального кона не надо возвращаться на шаг назад в route.
Флаг, использующийся для определения того, что данная компонента -
обёртка модального окна
*/
_isModal: true,
close: function (v) {
if (v === void 0) {
v = false;
}
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
isNavigationClosingGuard = v;
if (!modal) return [3
/*break*/
, 2];
return [4
/*yield*/
, modal.close()];
case 1:
return [2
/*return*/
, _a.sent()];
case 2:
return [2
/*return*/
];
}
});
});
},
initialize: initialize,
/**
* Мнимая обёртка. Для того, чтобы рендеринг запускался.
* -----
* (19.02.2022)
* Try to change null to RouterView, using this way we can use children
* in router configuration.
* */
var isNavigationClosingGuard = false;
function initialize() {
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
if (!state.router)
throw ModalError.ModalRouterIntegrationNotInitialized();
isNavigationClosingGuard = false;
modal = null;
return [4 /*yield*/, openModal(component, vue.computed(function () { var _a; return (_a = state.router) === null || _a === void 0 ? void 0 : _a.currentRoute.value.params; }))];
case 1:
modal = _a.sent();
modal.onclose = function () {
var _a;
if (!isNavigationClosingGuard)
(_a = state.router) === null || _a === void 0 ? void 0 : _a.back();
};
return [2 /*return*/];
}
});
});
setup: function () {
return function () {
return null;
};
}
return {
getModalObject: function () { return modal; },
/**
Флаг, использующийся для определения того, что данная компонента -
обёртка модального окна
*/
_isModal: true,
close: function (v) {
if (v === void 0) { v = false; }
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
isNavigationClosingGuard = v;
if (!modal) return [3 /*break*/, 2];
return [4 /*yield*/, modal.close()];
case 1: return [2 /*return*/, _a.sent()];
case 2: return [2 /*return*/];
}
});
});
},
initialize: initialize,
/**
* Мнимая обёртка. Для того, чтобы рендеринг запускался.
* -----
* (19.02.2022)
* Try to change null to RouterView, using this way we can use children
* in router configuration.
* */
setup: function () { return function () { return null; }; }
};
};
}
useModalRouter.init = init;
exports.closeModal = closeModal;
exports.config = config;
exports.container = script;
exports.container = WidgetModalContainer;
exports.modalQueue = modalQueue;

@@ -809,0 +1078,0 @@ exports.onBeforeModalClose = onBeforeModalClose;

{
"name": "jenesius-vue-modal",
"version": "1.5.5",
"version": "1.6.0",
"private": false,

@@ -36,20 +36,22 @@ "description": "Simple modal plugin for Vue3",

"@rollup/plugin-typescript": "^8.3.0",
"@testing-library/vue": "^6.6.1",
"@types/jest": "^26.0.24",
"@vitejs/plugin-vue": "^2.3.3",
"@vue/cli-plugin-babel": "~4.5.0",
"@vue/cli-plugin-typescript": "~4.5.0",
"@vue/cli-service": "^4.5.15",
"@vue/test-utils": "^2.0.0-rc.17",
"@vue/test-utils": "^2.0.2",
"@vue/vue3-jest": "^26.0.1",
"core-js": "^3.6.5",
"jest": "26.6.3",
"metrohash": "^2.8.0",
"jest-environment-jsdom": "^26.6.2",
"rollup": "^2.75.7",
"rollup-plugin-postcss": "^4.0.2",
"rollup-plugin-vue": "^6.0.0",
"ts-jest": "^26.5.5",
"tslib": "^2.4.0",
"typescript": "~4.1.5",
"ts-jest": "^26.5.6",
"ts-node": "^10.9.1",
"typescript": "~4.7.4",
"vitepress": "^1.0.0-alpha.1",
"vue-jest": "^5.0.0-alpha.10",
"vue-router": "^4.0.12",
"vue-template-compiler": "2.6.14",
"vuex": "^4.0.2"
"vuex": "^4.0.2",
"@rollup/plugin-babel": "^5.3.1"
},

@@ -75,3 +77,6 @@ "browserslist": [

"types": "dist/dts/index.d.ts",
"url": "https://github.com/Jenesius/vue-modal/issues"
"url": "https://github.com/Jenesius/vue-modal/issues",
"dependencies": {
"jenesius-event-emitter": "^1.0.4"
}
}
{
"presets": [
["@babel/preset-env", {"targets": {"node": "current"}}],
["@babel/preset-env", {"targets": {"node": "current"}, "modules": "commonjs"}],
"@babel/preset-typescript"
]
}

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc