promise-portal 1.0.3 → 1.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -15,12 +15,71 @@ npm install promise-portal -D
15
15
  yarn add promise-portal --D
16
16
  ```
17
17
 
18
+ ## Online Demo
19
+
20
+ [Demo on codesandbox](https://codesandbox.io/p/github/tjyuanpeng/promise-portal)
21
+
22
+ ## Relative Resourece
23
+
24
+ - [react protal](https://reactjs.org/docs/portals.html)
25
+ - [vue teleport](https://vuejs.org/guide/built-ins/teleport.html)
26
+
27
+ ## Why
28
+
29
+ like element-plus, the modal is a vue component
30
+
31
+ in development, we want use modal like a function
32
+
33
+ no `show` property to control show/hide, gettting result is more explicit
34
+
35
+ easier to control workflow, and easier to handle life-cycles
36
+
37
+ ### Before
38
+
39
+ use as acomponent, with ref value to control visibility and life-cycles
40
+
41
+ ```ts
42
+ <script setup lang="ts">
43
+ import Comp from './components/name.vue'
44
+ const show = ref(false)
45
+ const onClick = () => {
46
+ show.value = true
47
+ }
48
+ const onClosed = () => {
49
+ show.value = false
50
+ }
51
+ </script>
52
+ <template>
53
+ <el-button @click="onClick"> click to open the Dialog </el-button>
54
+ <Comp v-model="show" @closed="onClosed"> a dialog content </Comp>
55
+ </template>
56
+ ```
57
+
58
+ ### After
59
+
60
+ use as a normal promise-style function, so happy to develop
61
+
62
+ ```ts
63
+ <script setup lang="ts">
64
+ import Comp, { Input, Output } from './components/name.vue'
65
+ const func = definePortal<Output, Input>(Comp)
66
+ const onClick = async () => {
67
+ const data = await func()
68
+ console.log(data)
69
+ }
70
+ </script>
71
+ <template>
72
+ <el-button @click="onClick"> click to open the Dialog </el-button>
73
+ </template>
74
+ ```
75
+
18
76
  ## Use
19
77
 
20
78
  ### install in the entry file
21
79
 
22
80
  ```ts
23
81
  // ./main.ts
82
+ import { createApp } from 'vue'
24
83
  import { createPromisePortal } from 'promise-portal'
25
84
 
26
85
  const app = createApp(App)
@@ -60,11 +119,19 @@ const onClick = async () => {
60
119
 
61
120
  - createPromisePortal
62
121
 
63
- create promise-portal instance
122
+ create promise-portal instance, set to vue instance
64
123
 
65
124
  ```ts
66
125
  const instance = createPromisePortal()
67
- app.use(instance) // vue instance
126
+ app.use(instance)
127
+ ```
128
+
129
+ you can set default config to instance
130
+
131
+ ```ts
132
+ const instance = createPromisePortal({
133
+ unmountDelay: 100,
134
+ })
68
135
  ```
69
136
 
70
137
  - getActiveInstance
@@ -88,11 +155,12 @@ const onClick = async () => {
88
155
  a vue composition api, use in portal component to get context of portal
89
156
 
90
157
  ```ts
91
- const { resolve, reject, el, vNode } = usePortalContext()
158
+ const { resolve, reject, el, vNode, setUnmountDelay } = usePortalContext()
92
159
  // resolve: promise resolve handler
93
160
  // reject: promise reject handler
94
161
  // el: portal base element, injecting to body element
95
162
  // vNode: portal base vue vnode
163
+ // setUnmountDelay: set unmount delay to this portal
96
164
  ```
97
165
 
98
166
  you can use typescript generic types
@@ -169,8 +237,29 @@ const onClick = async () => {
169
237
  })
170
238
  ```
171
239
 
172
- ## Link
240
+ - detectPromisePortalInstance
241
+
242
+ Check if the instance has been properly destroyed
173
243
 
174
- [@filez/portal](https://github.com/lenovo-filez/portal)
244
+ ```ts
245
+ // main.ts
246
+ if (import.meta.env.DEV) {
247
+ detectPromisePortalInstance()
248
+ }
249
+ ```
250
+
251
+ You can pass in other values to customize it.
252
+
253
+ ```ts
254
+ // default value
255
+ detectPromisePortalInstance({
256
+ style = 'position:fixed;top:0;right:0;text-align:right;line-height:1.3;color:red;z-index:9999;',
257
+ text = `Detected that the promise-portal instance has not been properly destroyed<br>
258
+ Please make sure to call resolve/reject to release the instance correctly.`,
259
+ })
260
+ ```
261
+
262
+ ## Link
175
263
 
176
- [promise-modal](https://github.com/liruifengv/promise-modal)
264
+ - [@filez/portal](https://github.com/lenovo-filez/portal)
265
+ - [promise-modal](https://github.com/liruifengv/promise-modal)
package/dist/index.cjs ADDED
@@ -0,0 +1,124 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var src_exports = {};
22
+ __export(src_exports, {
23
+ createPromisePortal: () => createPromisePortal,
24
+ definePortal: () => definePortal,
25
+ detectPromisePortalInstance: () => detectPromisePortalInstance,
26
+ getActiveInstance: () => getActiveInstance,
27
+ setActiveInstance: () => setActiveInstance,
28
+ usePortalContext: () => usePortalContext
29
+ });
30
+ module.exports = __toCommonJS(src_exports);
31
+ var import_vue = require("vue");
32
+ var promisePortalSymbol = process.env.NODE_ENV !== "production" ? Symbol("promise-portal") : Symbol();
33
+ var activeInstance;
34
+ var getActiveInstance = () => activeInstance;
35
+ var setActiveInstance = (instance) => activeInstance = instance;
36
+ var createPromisePortal = (defaultOptions = {}) => {
37
+ const instance = {
38
+ defaultOptions,
39
+ app: void 0,
40
+ map: /* @__PURE__ */ new WeakMap(),
41
+ install(app) {
42
+ instance.app = app;
43
+ setActiveInstance(instance);
44
+ app.provide(promisePortalSymbol, instance);
45
+ }
46
+ };
47
+ return instance;
48
+ };
49
+ var usePortalContext = () => {
50
+ const instance = (0, import_vue.inject)(promisePortalSymbol);
51
+ if (!instance) {
52
+ throw new Error("[promise-portal]: no instance found.");
53
+ }
54
+ const ins = (0, import_vue.getCurrentInstance)();
55
+ if (!ins?.vnode) {
56
+ throw new Error("[promise-portal]: no vnode found.");
57
+ }
58
+ const data = instance.map.get(ins.vnode);
59
+ if (!data) {
60
+ throw new Error("[promise-portal]: no inject data found.");
61
+ }
62
+ return data;
63
+ };
64
+ var definePortal = (component, { instance, unmountDelay } = {}) => {
65
+ const _instance = instance || (0, import_vue.getCurrentInstance)() && (0, import_vue.inject)(promisePortalSymbol) || activeInstance;
66
+ if (!_instance) {
67
+ throw new Error("[promise-portal]: no instance found. Do you forget install promise-portal?");
68
+ }
69
+ return (props, children) => {
70
+ let el = document.createElement("div");
71
+ el.setAttribute("data-promise-portal-container", "");
72
+ document.body.appendChild(el);
73
+ let _delay = unmountDelay || _instance.defaultOptions?.unmountDelay;
74
+ const setUnmountDelay = (delay) => {
75
+ _delay = delay;
76
+ };
77
+ let vNode;
78
+ const p = new Promise((resolve, reject) => {
79
+ vNode = (0, import_vue.createVNode)(component, props, children);
80
+ _instance.map.set(vNode, { resolve, reject, el, vNode, setUnmountDelay });
81
+ vNode.appContext = _instance.app._context;
82
+ (0, import_vue.render)(vNode, el);
83
+ });
84
+ p.finally(() => {
85
+ setTimeout(() => {
86
+ if (el) {
87
+ (0, import_vue.render)(null, el);
88
+ document.body.removeChild(el);
89
+ }
90
+ el = null;
91
+ vNode = null;
92
+ }, _delay);
93
+ });
94
+ return p;
95
+ };
96
+ };
97
+ var detectPromisePortalInstance = ({
98
+ style = "position:fixed;top:0;right:0;text-align:right;line-height:1.3;color:red;z-index:9999;",
99
+ text = `Detected that the promise-portal instance has not been properly destroyed<br>Please make sure to call resolve/reject to release the instance correctly.`
100
+ } = {}) => {
101
+ const nodes = document.querySelectorAll("[data-promise-portal-container]");
102
+ if (nodes.length > 0) {
103
+ let el = document.querySelector("[data-promise-portal-detector]");
104
+ if (!el) {
105
+ el = document.createElement("div");
106
+ el.setAttribute("data-promise-portal-detector", "");
107
+ el.setAttribute("style", style);
108
+ el.innerHTML = text;
109
+ document.body.appendChild(el);
110
+ }
111
+ } else {
112
+ document.querySelector("[data-promise-portal-detector]")?.remove();
113
+ }
114
+ setTimeout(detectPromisePortalInstance, 200);
115
+ };
116
+ // Annotate the CommonJS export names for ESM import in node:
117
+ 0 && (module.exports = {
118
+ createPromisePortal,
119
+ definePortal,
120
+ detectPromisePortalInstance,
121
+ getActiveInstance,
122
+ setActiveInstance,
123
+ usePortalContext
124
+ });
@@ -0,0 +1,32 @@
1
+ import { VNode, App, Component } from 'vue';
2
+
3
+ interface PortalContext<R> {
4
+ resolve: (value: R | PromiseLike<R>) => void;
5
+ reject: (reason?: any) => void;
6
+ el: HTMLDivElement;
7
+ vNode: VNode;
8
+ setUnmountDelay: (unmountDelay: number) => void;
9
+ }
10
+ interface PromisePortal<R = any> {
11
+ defaultOptions: {
12
+ unmountDelay?: number;
13
+ };
14
+ app: App;
15
+ map: WeakMap<VNode, PortalContext<R>>;
16
+ install: (app: App) => void;
17
+ }
18
+ interface PortalOptions<R> {
19
+ instance?: PromisePortal<R>;
20
+ unmountDelay?: number;
21
+ }
22
+ declare const getActiveInstance: () => PromisePortal<any>;
23
+ declare const setActiveInstance: (instance: PromisePortal) => PromisePortal<any>;
24
+ declare const createPromisePortal: (defaultOptions?: {}) => PromisePortal<any>;
25
+ declare const usePortalContext: <TOutput = any>() => PortalContext<TOutput>;
26
+ declare const definePortal: <TOutput = any, TProps = any>(component: Component, { instance, unmountDelay }?: PortalOptions<TOutput>) => (props?: TProps | undefined, children?: unknown) => Promise<TOutput>;
27
+ declare const detectPromisePortalInstance: ({ style, text, }?: {
28
+ style?: string | undefined;
29
+ text?: string | undefined;
30
+ }) => void;
31
+
32
+ export { PortalContext, PortalOptions, PromisePortal, createPromisePortal, definePortal, detectPromisePortalInstance, getActiveInstance, setActiveInstance, usePortalContext };
package/dist/index.js ADDED
@@ -0,0 +1,94 @@
1
+ // src/index.ts
2
+ import { createVNode, render, inject, getCurrentInstance } from "vue";
3
+ var promisePortalSymbol = process.env.NODE_ENV !== "production" ? Symbol("promise-portal") : Symbol();
4
+ var activeInstance;
5
+ var getActiveInstance = () => activeInstance;
6
+ var setActiveInstance = (instance) => activeInstance = instance;
7
+ var createPromisePortal = (defaultOptions = {}) => {
8
+ const instance = {
9
+ defaultOptions,
10
+ app: void 0,
11
+ map: /* @__PURE__ */ new WeakMap(),
12
+ install(app) {
13
+ instance.app = app;
14
+ setActiveInstance(instance);
15
+ app.provide(promisePortalSymbol, instance);
16
+ }
17
+ };
18
+ return instance;
19
+ };
20
+ var usePortalContext = () => {
21
+ const instance = inject(promisePortalSymbol);
22
+ if (!instance) {
23
+ throw new Error("[promise-portal]: no instance found.");
24
+ }
25
+ const ins = getCurrentInstance();
26
+ if (!ins?.vnode) {
27
+ throw new Error("[promise-portal]: no vnode found.");
28
+ }
29
+ const data = instance.map.get(ins.vnode);
30
+ if (!data) {
31
+ throw new Error("[promise-portal]: no inject data found.");
32
+ }
33
+ return data;
34
+ };
35
+ var definePortal = (component, { instance, unmountDelay } = {}) => {
36
+ const _instance = instance || getCurrentInstance() && inject(promisePortalSymbol) || activeInstance;
37
+ if (!_instance) {
38
+ throw new Error("[promise-portal]: no instance found. Do you forget install promise-portal?");
39
+ }
40
+ return (props, children) => {
41
+ let el = document.createElement("div");
42
+ el.setAttribute("data-promise-portal-container", "");
43
+ document.body.appendChild(el);
44
+ let _delay = unmountDelay || _instance.defaultOptions?.unmountDelay;
45
+ const setUnmountDelay = (delay) => {
46
+ _delay = delay;
47
+ };
48
+ let vNode;
49
+ const p = new Promise((resolve, reject) => {
50
+ vNode = createVNode(component, props, children);
51
+ _instance.map.set(vNode, { resolve, reject, el, vNode, setUnmountDelay });
52
+ vNode.appContext = _instance.app._context;
53
+ render(vNode, el);
54
+ });
55
+ p.finally(() => {
56
+ setTimeout(() => {
57
+ if (el) {
58
+ render(null, el);
59
+ document.body.removeChild(el);
60
+ }
61
+ el = null;
62
+ vNode = null;
63
+ }, _delay);
64
+ });
65
+ return p;
66
+ };
67
+ };
68
+ var detectPromisePortalInstance = ({
69
+ style = "position:fixed;top:0;right:0;text-align:right;line-height:1.3;color:red;z-index:9999;",
70
+ text = `Detected that the promise-portal instance has not been properly destroyed<br>Please make sure to call resolve/reject to release the instance correctly.`
71
+ } = {}) => {
72
+ const nodes = document.querySelectorAll("[data-promise-portal-container]");
73
+ if (nodes.length > 0) {
74
+ let el = document.querySelector("[data-promise-portal-detector]");
75
+ if (!el) {
76
+ el = document.createElement("div");
77
+ el.setAttribute("data-promise-portal-detector", "");
78
+ el.setAttribute("style", style);
79
+ el.innerHTML = text;
80
+ document.body.appendChild(el);
81
+ }
82
+ } else {
83
+ document.querySelector("[data-promise-portal-detector]")?.remove();
84
+ }
85
+ setTimeout(detectPromisePortalInstance, 200);
86
+ };
87
+ export {
88
+ createPromisePortal,
89
+ definePortal,
90
+ detectPromisePortalInstance,
91
+ getActiveInstance,
92
+ setActiveInstance,
93
+ usePortalContext
94
+ };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "promise-portal",
3
- "version": "1.0.3",
4
- "description": "a vite plugin to load svg icon for element-plus",
3
+ "version": "1.0.5",
4
+ "description": "let you use react portal in vue, and with promise",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",
7
7
  "module": "dist/index.js",