promise-portal 1.1.0 → 2.0.0
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 +75 -62
- package/dist/index.cjs +108 -142
- package/dist/index.d.cts +42 -0
- package/dist/index.d.mts +42 -0
- package/dist/index.mjs +109 -0
- package/package.json +29 -27
- package/LICENSE +0 -21
- package/dist/index.d.ts +0 -36
- package/dist/index.js +0 -116
package/README.md
CHANGED
|
@@ -1,18 +1,11 @@
|
|
|
1
1
|
# promise-portal
|
|
2
2
|
|
|
3
|
-
use component
|
|
3
|
+
use component as a promisd-like function
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
|
-
// pnpm
|
|
9
8
|
pnpm add promise-portal
|
|
10
|
-
|
|
11
|
-
// npm
|
|
12
|
-
npm install promise-portal
|
|
13
|
-
|
|
14
|
-
// yarn
|
|
15
|
-
yarn add promise-portal
|
|
16
9
|
```
|
|
17
10
|
|
|
18
11
|
## Online Demo
|
|
@@ -38,6 +31,7 @@ use as a component, with ref value to control visibility and life-cycles
|
|
|
38
31
|
```vue
|
|
39
32
|
<script setup lang="ts">
|
|
40
33
|
import Comp from './components/name.vue'
|
|
34
|
+
|
|
41
35
|
const show = ref(false)
|
|
42
36
|
const onClick = () => {
|
|
43
37
|
show.value = true
|
|
@@ -46,9 +40,14 @@ const onClosed = () => {
|
|
|
46
40
|
show.value = false
|
|
47
41
|
}
|
|
48
42
|
</script>
|
|
43
|
+
|
|
49
44
|
<template>
|
|
50
|
-
<el-button @click="onClick">
|
|
51
|
-
|
|
45
|
+
<el-button @click="onClick">
|
|
46
|
+
click to open the Dialog
|
|
47
|
+
</el-button>
|
|
48
|
+
<Comp v-model="show" @closed="onClosed">
|
|
49
|
+
a dialog content
|
|
50
|
+
</Comp>
|
|
52
51
|
</template>
|
|
53
52
|
```
|
|
54
53
|
|
|
@@ -59,14 +58,18 @@ use as a normal promise-style function, so happy to develop
|
|
|
59
58
|
```vue
|
|
60
59
|
<script setup lang="ts">
|
|
61
60
|
import Comp from './components/name.vue'
|
|
61
|
+
|
|
62
62
|
const func = definePortal(Comp)
|
|
63
63
|
const onClick = async () => {
|
|
64
64
|
const data = await func()
|
|
65
65
|
console.log(data)
|
|
66
66
|
}
|
|
67
67
|
</script>
|
|
68
|
+
|
|
68
69
|
<template>
|
|
69
|
-
<el-button @click="onClick">
|
|
70
|
+
<el-button @click="onClick">
|
|
71
|
+
open the Dialog
|
|
72
|
+
</el-button>
|
|
70
73
|
</template>
|
|
71
74
|
```
|
|
72
75
|
|
|
@@ -76,23 +79,38 @@ const onClick = async () => {
|
|
|
76
79
|
|
|
77
80
|
```ts
|
|
78
81
|
// ./main.ts
|
|
79
|
-
import { createApp } from 'vue'
|
|
80
82
|
import { createPromisePortal } from 'promise-portal'
|
|
83
|
+
import { createApp } from 'vue'
|
|
81
84
|
|
|
82
85
|
const app = createApp(App)
|
|
83
|
-
app.use(
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
86
|
+
app.use(createPromisePortal())
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### use `ContextProvider` to set context globally
|
|
90
|
+
|
|
91
|
+
```vue
|
|
92
|
+
<!-- ./App.vue -->
|
|
93
|
+
<script setup lang="ts">
|
|
94
|
+
import locale from 'ant-design-vue/es/locale/zh_CN'
|
|
95
|
+
import { ContextProvider } from 'promise-portal'
|
|
96
|
+
</script>
|
|
97
|
+
|
|
98
|
+
<template>
|
|
99
|
+
<a-config-provider :locale="locale">
|
|
100
|
+
<ContextProvider>
|
|
101
|
+
<router-view />
|
|
102
|
+
</ContextProvider>
|
|
103
|
+
</a-config-provider>
|
|
104
|
+
</template>
|
|
88
105
|
```
|
|
89
106
|
|
|
90
107
|
### in component, use `usePortalContext` to use portal context
|
|
91
108
|
|
|
92
109
|
```vue
|
|
110
|
+
<!-- ./components/comp.vue -->
|
|
93
111
|
<script setup lang="ts">
|
|
94
|
-
// ./components/comp.vue
|
|
95
112
|
import { usePortalContext } from 'promise-portal'
|
|
113
|
+
|
|
96
114
|
export interface Output {
|
|
97
115
|
confirm: boolean
|
|
98
116
|
}
|
|
@@ -105,8 +123,11 @@ const onCancel = () => {
|
|
|
105
123
|
resolve({ confirm: false })
|
|
106
124
|
}
|
|
107
125
|
</script>
|
|
126
|
+
|
|
108
127
|
<template>
|
|
109
|
-
<a-modal v-model:open="show" @cancel="resolve">
|
|
128
|
+
<a-modal v-model:open="show" @cancel="resolve">
|
|
129
|
+
{{ props.input }}
|
|
130
|
+
</a-modal>
|
|
110
131
|
</template>
|
|
111
132
|
```
|
|
112
133
|
|
|
@@ -116,6 +137,7 @@ const onCancel = () => {
|
|
|
116
137
|
// ./App.vue
|
|
117
138
|
import { definePortal } from 'promise-portal'
|
|
118
139
|
import Comp, { Input, Output } from './components/comp.vue'
|
|
140
|
+
|
|
119
141
|
const [func] = definePortal<Output, Input>(Comp)
|
|
120
142
|
const onClick = async () => {
|
|
121
143
|
const result = await func({
|
|
@@ -136,33 +158,23 @@ const instance = createPromisePortal()
|
|
|
136
158
|
app.use(instance)
|
|
137
159
|
```
|
|
138
160
|
|
|
139
|
-
|
|
161
|
+
### ContextProvider
|
|
140
162
|
|
|
141
|
-
|
|
142
|
-
const instance = createPromisePortal({
|
|
143
|
-
// set a time gap before portal unmount,
|
|
144
|
-
// in general, it is to wait for animation effect
|
|
145
|
-
unmountDelay: 200,
|
|
146
|
-
|
|
147
|
-
// initial value to property show, default value is true
|
|
148
|
-
initialShowValue: true,
|
|
149
|
-
})
|
|
150
|
-
```
|
|
163
|
+
a component to set context globally
|
|
151
164
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
const instance = getActiveInstance()
|
|
158
|
-
```
|
|
159
|
-
|
|
160
|
-
### setActiveInstance
|
|
161
|
-
|
|
162
|
-
set active promise-portal instance
|
|
165
|
+
```vue
|
|
166
|
+
<script setup lang="ts">
|
|
167
|
+
import locale from 'ant-design-vue/es/locale/zh_CN'
|
|
168
|
+
import { ContextProvider } from 'promise-portal'
|
|
169
|
+
</script>
|
|
163
170
|
|
|
164
|
-
|
|
165
|
-
|
|
171
|
+
<template>
|
|
172
|
+
<a-config-provider :locale="locale">
|
|
173
|
+
<ContextProvider>
|
|
174
|
+
<router-view />
|
|
175
|
+
</ContextProvider>
|
|
176
|
+
</a-config-provider>
|
|
177
|
+
</template>
|
|
166
178
|
```
|
|
167
179
|
|
|
168
180
|
### usePortalContext
|
|
@@ -176,16 +188,15 @@ const { resolve } = usePortalContext()
|
|
|
176
188
|
const {
|
|
177
189
|
resolve, // promise resolve handler
|
|
178
190
|
reject, // promise reject handler
|
|
179
|
-
el, // portal base element,
|
|
191
|
+
el, // portal base element, injected into 'appendTo' element
|
|
180
192
|
vnode, // portal base vue vnode
|
|
181
|
-
|
|
182
|
-
show, //
|
|
193
|
+
unmountDelay, // Ref for portal unmount delay (ms)
|
|
194
|
+
show, // Ref for modal display state (controlled by portal)
|
|
183
195
|
} = usePortalContext({
|
|
184
|
-
//
|
|
185
|
-
// in general, it is to wait for animation effect
|
|
196
|
+
// Unmount delay (ms) for portal, usually for animation effects
|
|
186
197
|
unmountDelay: 200,
|
|
187
198
|
|
|
188
|
-
//
|
|
199
|
+
// Initial value for the show ref (defaults to true)
|
|
189
200
|
initialShowValue: true,
|
|
190
201
|
})
|
|
191
202
|
```
|
|
@@ -212,8 +223,9 @@ use `initialShowValue` to set inital value, default inital value is `true`
|
|
|
212
223
|
<script setup lang="ts">
|
|
213
224
|
const { resolve, show } = usePortalContext<Output>({ initialShowValue: true })
|
|
214
225
|
</script>
|
|
226
|
+
|
|
215
227
|
<template>
|
|
216
|
-
<a-modal v-model:open="show" @cancel="resolve"
|
|
228
|
+
<a-modal v-model:open="show" @cancel="resolve" />
|
|
217
229
|
</template>
|
|
218
230
|
```
|
|
219
231
|
|
|
@@ -223,6 +235,7 @@ define a portal, return a portal function
|
|
|
223
235
|
|
|
224
236
|
```ts
|
|
225
237
|
import Comp from './component.vue'
|
|
238
|
+
|
|
226
239
|
const portalFunc = definePortal(Comp)
|
|
227
240
|
portalFunc()
|
|
228
241
|
```
|
|
@@ -231,6 +244,9 @@ you can define generic types to check input object and output object
|
|
|
231
244
|
|
|
232
245
|
```ts
|
|
233
246
|
// component.vue
|
|
247
|
+
// App.vue
|
|
248
|
+
import Comp, { Input, Output } from './component.vue'
|
|
249
|
+
|
|
234
250
|
export interface Input {
|
|
235
251
|
firstName: string
|
|
236
252
|
lastName: string
|
|
@@ -243,9 +259,6 @@ export interface Output {
|
|
|
243
259
|
|
|
244
260
|
const props = defineProps<Input>()
|
|
245
261
|
const { resolve } = usePortalContext<Output>()
|
|
246
|
-
|
|
247
|
-
// App.vue
|
|
248
|
-
import Comp, { Input, Output } from './component.vue'
|
|
249
262
|
const portal = definePortal<Output, Input>(Comp)
|
|
250
263
|
const output = await portal({
|
|
251
264
|
firstName: 'joe',
|
|
@@ -257,15 +270,15 @@ define a portal with empty parameter
|
|
|
257
270
|
|
|
258
271
|
```ts
|
|
259
272
|
// component.vue
|
|
273
|
+
// App.vue
|
|
274
|
+
import Comp, { Output } from './component.vue'
|
|
275
|
+
|
|
260
276
|
export interface Output {
|
|
261
277
|
fullName: string
|
|
262
278
|
confirm: boolean
|
|
263
279
|
}
|
|
264
280
|
|
|
265
281
|
const { resolve } = usePortalContext<Output>()
|
|
266
|
-
|
|
267
|
-
// App.vue
|
|
268
|
-
import Comp, { Output } from './component.vue'
|
|
269
282
|
const portal = definePortal<Output, void>(Comp)
|
|
270
283
|
const output = await portal() // only allow empty parameter
|
|
271
284
|
```
|
|
@@ -274,14 +287,14 @@ you can set a options to definePortal
|
|
|
274
287
|
|
|
275
288
|
```ts
|
|
276
289
|
definePortal(Comp, {
|
|
277
|
-
//
|
|
290
|
+
// Unmount delay (ms) for portal, usually for animation effects
|
|
278
291
|
unmountDelay: 200,
|
|
279
292
|
|
|
280
|
-
//
|
|
293
|
+
// Initial value for the show ref (defaults to true)
|
|
281
294
|
initialShowValue: true,
|
|
282
295
|
|
|
283
|
-
//
|
|
284
|
-
|
|
296
|
+
// a dom element or CSS selector to append the portal element to (defaults to document.body)
|
|
297
|
+
appendTo: document.body,
|
|
285
298
|
})
|
|
286
299
|
```
|
|
287
300
|
|
|
@@ -312,9 +325,9 @@ detectPromisePortalInstance({
|
|
|
312
325
|
})
|
|
313
326
|
```
|
|
314
327
|
|
|
315
|
-
#
|
|
328
|
+
# Acknowledgements
|
|
316
329
|
|
|
317
|
-
- [react
|
|
330
|
+
- [react portal](https://reactjs.org/docs/portals.html)
|
|
318
331
|
- [vue teleport](https://vuejs.org/guide/built-ins/teleport.html)
|
|
319
332
|
- [@filez/portal](https://github.com/lenovo-filez/portal)
|
|
320
333
|
- [promise-modal](https://github.com/liruifengv/promise-modal)
|
package/dist/index.cjs
CHANGED
|
@@ -1,148 +1,114 @@
|
|
|
1
|
-
|
|
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);
|
|
1
|
+
let vue = require("vue");
|
|
31
2
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
3
|
+
//#region src/detector.ts
|
|
4
|
+
function detect(options) {
|
|
5
|
+
const { style = "position:fixed;top:0;right:0;text-align:right;line-height:1.3;color:red;z-index:9999;", 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.` } = options;
|
|
6
|
+
const containers = document.querySelectorAll("[data-promise-portal-container]");
|
|
7
|
+
const detector = document.querySelector("[data-promise-portal-detector]");
|
|
8
|
+
if (containers.length === 0) {
|
|
9
|
+
detector?.remove();
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
if (!detector) {
|
|
13
|
+
const el = document.createElement("div");
|
|
14
|
+
el.setAttribute("data-promise-portal-detector", "");
|
|
15
|
+
el.setAttribute("style", style);
|
|
16
|
+
el.innerHTML = text;
|
|
17
|
+
document.body.appendChild(el);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
const detectPromisePortalInstance = (options = {}) => {
|
|
21
|
+
const timer = setInterval(() => detect(options), 200);
|
|
22
|
+
return () => clearInterval(timer);
|
|
50
23
|
};
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
}
|
|
70
|
-
return data;
|
|
24
|
+
|
|
25
|
+
//#endregion
|
|
26
|
+
//#region src/portal.ts
|
|
27
|
+
const promisePortalSymbol = Symbol("promise-portal");
|
|
28
|
+
const version = `2.0.0`;
|
|
29
|
+
let activeInstance;
|
|
30
|
+
const createPromisePortal = () => {
|
|
31
|
+
const instance = {
|
|
32
|
+
app: void 0,
|
|
33
|
+
map: /* @__PURE__ */ new WeakMap(),
|
|
34
|
+
provides: void 0,
|
|
35
|
+
install(app) {
|
|
36
|
+
instance.app = app;
|
|
37
|
+
activeInstance = instance;
|
|
38
|
+
app.provide(promisePortalSymbol, instance);
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
return instance;
|
|
71
42
|
};
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
});
|
|
83
|
-
const portal = (props, children) => {
|
|
84
|
-
const el = document.createElement("div");
|
|
85
|
-
el.setAttribute("data-promise-portal-container", "");
|
|
86
|
-
document.body.appendChild(el);
|
|
87
|
-
let unmountDelay = options.unmountDelay ?? instance.defaultOptions.unmountDelay;
|
|
88
|
-
const setUnmountDelay = (delay) => {
|
|
89
|
-
unmountDelay = delay;
|
|
90
|
-
};
|
|
91
|
-
const show = (0, import_vue.ref)(options.initialShowValue ?? instance.defaultOptions.initialShowValue ?? true);
|
|
92
|
-
let vnode;
|
|
93
|
-
const p = new Promise((resolve, reject) => {
|
|
94
|
-
vnode = (0, import_vue.createVNode)(component, props, children);
|
|
95
|
-
instance.map.set(vnode, { resolve, reject, el, vnode, setUnmountDelay, show });
|
|
96
|
-
const ac = appContext ?? instance.app._context;
|
|
97
|
-
vnode.appContext = Object.create(ac, {
|
|
98
|
-
provides: {
|
|
99
|
-
value: contextHolderProvides ?? ac.provides
|
|
100
|
-
}
|
|
101
|
-
});
|
|
102
|
-
(0, import_vue.render)(vnode, el);
|
|
103
|
-
});
|
|
104
|
-
p.finally(() => {
|
|
105
|
-
show.value = false;
|
|
106
|
-
setTimeout(() => {
|
|
107
|
-
(0, import_vue.render)(null, el);
|
|
108
|
-
document.body.removeChild(el);
|
|
109
|
-
}, unmountDelay);
|
|
110
|
-
});
|
|
111
|
-
return p;
|
|
112
|
-
};
|
|
113
|
-
return [portal, ContextHolder];
|
|
43
|
+
const usePortalContext = (options = {}) => {
|
|
44
|
+
const instance = (0, vue.inject)(promisePortalSymbol);
|
|
45
|
+
if (!instance) throw new Error("[promise-portal]: no instance found. Did you forget to install promise-portal?");
|
|
46
|
+
const vnode = (0, vue.getCurrentInstance)()?.vnode;
|
|
47
|
+
if (!vnode) throw new Error("[promise-portal]: no vnode found in current component instance.");
|
|
48
|
+
const scope = instance.map.get(vnode);
|
|
49
|
+
if (!scope) throw new Error("[promise-portal]: no inject scope found.");
|
|
50
|
+
if (options.unmountDelay !== void 0) scope.unmountDelay.value = options.unmountDelay;
|
|
51
|
+
if (options.initialShowValue !== void 0) scope.show.value = options.initialShowValue;
|
|
52
|
+
return scope;
|
|
114
53
|
};
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
54
|
+
const resolveTarget = (to) => typeof to === "string" ? document.querySelector(to) : to;
|
|
55
|
+
const definePortal = (component, options = {}) => {
|
|
56
|
+
const instance = ((0, vue.getCurrentInstance)() && (0, vue.inject)(promisePortalSymbol)) ?? activeInstance;
|
|
57
|
+
if (!instance) throw new Error("[promise-portal]: no instance found. Did you forget to install promise-portal?");
|
|
58
|
+
let appContext = (0, vue.getCurrentInstance)()?.appContext ?? instance.app._context;
|
|
59
|
+
let provides = instance.provides ?? appContext.provides;
|
|
60
|
+
const ContextHolder = (0, vue.defineComponent)(() => () => {
|
|
61
|
+
const ci = (0, vue.getCurrentInstance)();
|
|
62
|
+
if (ci) {
|
|
63
|
+
appContext = ci.appContext;
|
|
64
|
+
provides = ci.provides;
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
const portal = (props, children) => {
|
|
68
|
+
const el = document.createElement("div");
|
|
69
|
+
el.setAttribute("data-promise-portal-container", "");
|
|
70
|
+
const target = resolveTarget(options.appendTo ?? document.body);
|
|
71
|
+
if (!target) throw new Error("[promise-portal]: invalid appendTo target - no element found or provided.");
|
|
72
|
+
target.appendChild(el);
|
|
73
|
+
const unmountDelay = (0, vue.ref)(options.unmountDelay ?? 0);
|
|
74
|
+
const show = (0, vue.ref)(options.initialShowValue ?? true);
|
|
75
|
+
const promise = new Promise((resolve, reject) => {
|
|
76
|
+
const vnode = (0, vue.createVNode)(component, props, children);
|
|
77
|
+
vnode.appContext = Object.create(appContext, { provides: { value: provides } });
|
|
78
|
+
instance.map.set(vnode, {
|
|
79
|
+
resolve,
|
|
80
|
+
reject,
|
|
81
|
+
el,
|
|
82
|
+
vnode,
|
|
83
|
+
unmountDelay,
|
|
84
|
+
show
|
|
85
|
+
});
|
|
86
|
+
(0, vue.render)(vnode, el);
|
|
87
|
+
});
|
|
88
|
+
promise.finally(() => {
|
|
89
|
+
show.value = false;
|
|
90
|
+
setTimeout(() => {
|
|
91
|
+
(0, vue.render)(null, el);
|
|
92
|
+
el?.remove();
|
|
93
|
+
}, unmountDelay.value);
|
|
94
|
+
});
|
|
95
|
+
return promise;
|
|
96
|
+
};
|
|
97
|
+
return [portal, ContextHolder];
|
|
139
98
|
};
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
usePortalContext
|
|
99
|
+
const ContextProvider = (0, vue.defineComponent)({
|
|
100
|
+
name: "PromisePortalContextProvider",
|
|
101
|
+
setup(_props, { slots }) {
|
|
102
|
+
const provides = (0, vue.getCurrentInstance)()?.provides;
|
|
103
|
+
if (provides && activeInstance) activeInstance.provides = provides;
|
|
104
|
+
return () => slots.default?.();
|
|
105
|
+
}
|
|
148
106
|
});
|
|
107
|
+
|
|
108
|
+
//#endregion
|
|
109
|
+
exports.ContextProvider = ContextProvider;
|
|
110
|
+
exports.createPromisePortal = createPromisePortal;
|
|
111
|
+
exports.definePortal = definePortal;
|
|
112
|
+
exports.detectPromisePortalInstance = detectPromisePortalInstance;
|
|
113
|
+
exports.usePortalContext = usePortalContext;
|
|
114
|
+
exports.version = version;
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import * as vue0 from "vue";
|
|
2
|
+
import { App, Component, Ref, RendererElement, VNode } from "vue";
|
|
3
|
+
|
|
4
|
+
//#region src/detector.d.ts
|
|
5
|
+
interface DetectorOptions {
|
|
6
|
+
style?: string;
|
|
7
|
+
text?: string;
|
|
8
|
+
}
|
|
9
|
+
declare const detectPromisePortalInstance: (options?: DetectorOptions) => () => void;
|
|
10
|
+
//#endregion
|
|
11
|
+
//#region src/portal.d.ts
|
|
12
|
+
declare const version = "2.0.0";
|
|
13
|
+
interface UsePortalContextOptions {
|
|
14
|
+
unmountDelay?: number;
|
|
15
|
+
initialShowValue?: boolean;
|
|
16
|
+
}
|
|
17
|
+
interface DefinePortalOptions extends UsePortalContextOptions {
|
|
18
|
+
appendTo?: string | RendererElement | null | undefined;
|
|
19
|
+
}
|
|
20
|
+
type DefinePortalResult<Output, Input> = [(props?: Input, children?: unknown) => Promise<Output>, Component];
|
|
21
|
+
interface Scope<R> {
|
|
22
|
+
resolve: (value: R | PromiseLike<R>) => void;
|
|
23
|
+
reject: (reason?: any) => void;
|
|
24
|
+
el: HTMLDivElement;
|
|
25
|
+
vnode: VNode;
|
|
26
|
+
unmountDelay: Ref<number>;
|
|
27
|
+
show: Ref<boolean>;
|
|
28
|
+
}
|
|
29
|
+
interface Instance<R = any> {
|
|
30
|
+
app: App;
|
|
31
|
+
map: WeakMap<VNode, Scope<R>>;
|
|
32
|
+
provides: any;
|
|
33
|
+
install: (app: App) => void;
|
|
34
|
+
}
|
|
35
|
+
declare const createPromisePortal: () => Instance<any>;
|
|
36
|
+
declare const usePortalContext: <Output = any>(options?: UsePortalContextOptions) => Scope<Output>;
|
|
37
|
+
declare const definePortal: <Output = any, Input = any>(component: Component, options?: DefinePortalOptions) => DefinePortalResult<Output, Input>;
|
|
38
|
+
declare const ContextProvider: vue0.DefineComponent<{}, () => VNode<vue0.RendererNode, RendererElement, {
|
|
39
|
+
[key: string]: any;
|
|
40
|
+
}>[] | undefined, {}, {}, {}, vue0.ComponentOptionsMixin, vue0.ComponentOptionsMixin, {}, string, vue0.PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, vue0.ComponentProvideOptions, true, {}, any>;
|
|
41
|
+
//#endregion
|
|
42
|
+
export { ContextProvider, DefinePortalOptions, DefinePortalResult, DetectorOptions, Instance, Scope, UsePortalContextOptions, createPromisePortal, definePortal, detectPromisePortalInstance, usePortalContext, version };
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import * as vue0 from "vue";
|
|
2
|
+
import { App, Component, Ref, RendererElement, VNode } from "vue";
|
|
3
|
+
|
|
4
|
+
//#region src/detector.d.ts
|
|
5
|
+
interface DetectorOptions {
|
|
6
|
+
style?: string;
|
|
7
|
+
text?: string;
|
|
8
|
+
}
|
|
9
|
+
declare const detectPromisePortalInstance: (options?: DetectorOptions) => () => void;
|
|
10
|
+
//#endregion
|
|
11
|
+
//#region src/portal.d.ts
|
|
12
|
+
declare const version = "2.0.0";
|
|
13
|
+
interface UsePortalContextOptions {
|
|
14
|
+
unmountDelay?: number;
|
|
15
|
+
initialShowValue?: boolean;
|
|
16
|
+
}
|
|
17
|
+
interface DefinePortalOptions extends UsePortalContextOptions {
|
|
18
|
+
appendTo?: string | RendererElement | null | undefined;
|
|
19
|
+
}
|
|
20
|
+
type DefinePortalResult<Output, Input> = [(props?: Input, children?: unknown) => Promise<Output>, Component];
|
|
21
|
+
interface Scope<R> {
|
|
22
|
+
resolve: (value: R | PromiseLike<R>) => void;
|
|
23
|
+
reject: (reason?: any) => void;
|
|
24
|
+
el: HTMLDivElement;
|
|
25
|
+
vnode: VNode;
|
|
26
|
+
unmountDelay: Ref<number>;
|
|
27
|
+
show: Ref<boolean>;
|
|
28
|
+
}
|
|
29
|
+
interface Instance<R = any> {
|
|
30
|
+
app: App;
|
|
31
|
+
map: WeakMap<VNode, Scope<R>>;
|
|
32
|
+
provides: any;
|
|
33
|
+
install: (app: App) => void;
|
|
34
|
+
}
|
|
35
|
+
declare const createPromisePortal: () => Instance<any>;
|
|
36
|
+
declare const usePortalContext: <Output = any>(options?: UsePortalContextOptions) => Scope<Output>;
|
|
37
|
+
declare const definePortal: <Output = any, Input = any>(component: Component, options?: DefinePortalOptions) => DefinePortalResult<Output, Input>;
|
|
38
|
+
declare const ContextProvider: vue0.DefineComponent<{}, () => VNode<vue0.RendererNode, RendererElement, {
|
|
39
|
+
[key: string]: any;
|
|
40
|
+
}>[] | undefined, {}, {}, {}, vue0.ComponentOptionsMixin, vue0.ComponentOptionsMixin, {}, string, vue0.PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, vue0.ComponentProvideOptions, true, {}, any>;
|
|
41
|
+
//#endregion
|
|
42
|
+
export { ContextProvider, DefinePortalOptions, DefinePortalResult, DetectorOptions, Instance, Scope, UsePortalContextOptions, createPromisePortal, definePortal, detectPromisePortalInstance, usePortalContext, version };
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { createVNode, defineComponent, getCurrentInstance, inject, ref, render } from "vue";
|
|
2
|
+
|
|
3
|
+
//#region src/detector.ts
|
|
4
|
+
function detect(options) {
|
|
5
|
+
const { style = "position:fixed;top:0;right:0;text-align:right;line-height:1.3;color:red;z-index:9999;", 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.` } = options;
|
|
6
|
+
const containers = document.querySelectorAll("[data-promise-portal-container]");
|
|
7
|
+
const detector = document.querySelector("[data-promise-portal-detector]");
|
|
8
|
+
if (containers.length === 0) {
|
|
9
|
+
detector?.remove();
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
if (!detector) {
|
|
13
|
+
const el = document.createElement("div");
|
|
14
|
+
el.setAttribute("data-promise-portal-detector", "");
|
|
15
|
+
el.setAttribute("style", style);
|
|
16
|
+
el.innerHTML = text;
|
|
17
|
+
document.body.appendChild(el);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
const detectPromisePortalInstance = (options = {}) => {
|
|
21
|
+
const timer = setInterval(() => detect(options), 200);
|
|
22
|
+
return () => clearInterval(timer);
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
//#endregion
|
|
26
|
+
//#region src/portal.ts
|
|
27
|
+
const promisePortalSymbol = Symbol("promise-portal");
|
|
28
|
+
const version = `2.0.0`;
|
|
29
|
+
let activeInstance;
|
|
30
|
+
const createPromisePortal = () => {
|
|
31
|
+
const instance = {
|
|
32
|
+
app: void 0,
|
|
33
|
+
map: /* @__PURE__ */ new WeakMap(),
|
|
34
|
+
provides: void 0,
|
|
35
|
+
install(app) {
|
|
36
|
+
instance.app = app;
|
|
37
|
+
activeInstance = instance;
|
|
38
|
+
app.provide(promisePortalSymbol, instance);
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
return instance;
|
|
42
|
+
};
|
|
43
|
+
const usePortalContext = (options = {}) => {
|
|
44
|
+
const instance = inject(promisePortalSymbol);
|
|
45
|
+
if (!instance) throw new Error("[promise-portal]: no instance found. Did you forget to install promise-portal?");
|
|
46
|
+
const vnode = getCurrentInstance()?.vnode;
|
|
47
|
+
if (!vnode) throw new Error("[promise-portal]: no vnode found in current component instance.");
|
|
48
|
+
const scope = instance.map.get(vnode);
|
|
49
|
+
if (!scope) throw new Error("[promise-portal]: no inject scope found.");
|
|
50
|
+
if (options.unmountDelay !== void 0) scope.unmountDelay.value = options.unmountDelay;
|
|
51
|
+
if (options.initialShowValue !== void 0) scope.show.value = options.initialShowValue;
|
|
52
|
+
return scope;
|
|
53
|
+
};
|
|
54
|
+
const resolveTarget = (to) => typeof to === "string" ? document.querySelector(to) : to;
|
|
55
|
+
const definePortal = (component, options = {}) => {
|
|
56
|
+
const instance = (getCurrentInstance() && inject(promisePortalSymbol)) ?? activeInstance;
|
|
57
|
+
if (!instance) throw new Error("[promise-portal]: no instance found. Did you forget to install promise-portal?");
|
|
58
|
+
let appContext = getCurrentInstance()?.appContext ?? instance.app._context;
|
|
59
|
+
let provides = instance.provides ?? appContext.provides;
|
|
60
|
+
const ContextHolder = defineComponent(() => () => {
|
|
61
|
+
const ci = getCurrentInstance();
|
|
62
|
+
if (ci) {
|
|
63
|
+
appContext = ci.appContext;
|
|
64
|
+
provides = ci.provides;
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
const portal = (props, children) => {
|
|
68
|
+
const el = document.createElement("div");
|
|
69
|
+
el.setAttribute("data-promise-portal-container", "");
|
|
70
|
+
const target = resolveTarget(options.appendTo ?? document.body);
|
|
71
|
+
if (!target) throw new Error("[promise-portal]: invalid appendTo target - no element found or provided.");
|
|
72
|
+
target.appendChild(el);
|
|
73
|
+
const unmountDelay = ref(options.unmountDelay ?? 0);
|
|
74
|
+
const show = ref(options.initialShowValue ?? true);
|
|
75
|
+
const promise = new Promise((resolve, reject) => {
|
|
76
|
+
const vnode = createVNode(component, props, children);
|
|
77
|
+
vnode.appContext = Object.create(appContext, { provides: { value: provides } });
|
|
78
|
+
instance.map.set(vnode, {
|
|
79
|
+
resolve,
|
|
80
|
+
reject,
|
|
81
|
+
el,
|
|
82
|
+
vnode,
|
|
83
|
+
unmountDelay,
|
|
84
|
+
show
|
|
85
|
+
});
|
|
86
|
+
render(vnode, el);
|
|
87
|
+
});
|
|
88
|
+
promise.finally(() => {
|
|
89
|
+
show.value = false;
|
|
90
|
+
setTimeout(() => {
|
|
91
|
+
render(null, el);
|
|
92
|
+
el?.remove();
|
|
93
|
+
}, unmountDelay.value);
|
|
94
|
+
});
|
|
95
|
+
return promise;
|
|
96
|
+
};
|
|
97
|
+
return [portal, ContextHolder];
|
|
98
|
+
};
|
|
99
|
+
const ContextProvider = defineComponent({
|
|
100
|
+
name: "PromisePortalContextProvider",
|
|
101
|
+
setup(_props, { slots }) {
|
|
102
|
+
const provides = getCurrentInstance()?.provides;
|
|
103
|
+
if (provides && activeInstance) activeInstance.provides = provides;
|
|
104
|
+
return () => slots.default?.();
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
//#endregion
|
|
109
|
+
export { ContextProvider, createPromisePortal, definePortal, detectPromisePortalInstance, usePortalContext, version };
|
package/package.json
CHANGED
|
@@ -1,33 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "promise-portal",
|
|
3
|
-
"version": "1.1.0",
|
|
4
|
-
"description": "let you use react portal in vue, and with promise",
|
|
5
3
|
"type": "module",
|
|
6
|
-
"
|
|
7
|
-
"
|
|
8
|
-
"types": "dist/index.d.ts",
|
|
9
|
-
"exports": {
|
|
10
|
-
".": {
|
|
11
|
-
"require": "./dist/index.cjs",
|
|
12
|
-
"import": "./dist/index.js",
|
|
13
|
-
"types": "./dist/index.d.ts"
|
|
14
|
-
}
|
|
15
|
-
},
|
|
16
|
-
"files": [
|
|
17
|
-
"dist"
|
|
18
|
-
],
|
|
19
|
-
"peerDependencies": {
|
|
20
|
-
"vue": "^3.2.13"
|
|
21
|
-
},
|
|
22
|
-
"devDependencies": {
|
|
23
|
-
"tsup": "^6.2.3",
|
|
24
|
-
"typescript": "^4.8.2",
|
|
25
|
-
"vue": "^3.3.8"
|
|
26
|
-
},
|
|
4
|
+
"version": "2.0.0",
|
|
5
|
+
"description": "use component as a promisd-like function",
|
|
27
6
|
"author": {
|
|
28
7
|
"name": "tjyuanpeng",
|
|
29
8
|
"email": "tjyuanpeng@gmail.com"
|
|
30
9
|
},
|
|
10
|
+
"license": "MIT",
|
|
31
11
|
"homepage": "https://github.com/tjyuanpeng/promise-portal",
|
|
32
12
|
"repository": {
|
|
33
13
|
"type": "git",
|
|
@@ -36,14 +16,36 @@
|
|
|
36
16
|
"bugs": {
|
|
37
17
|
"url": "https://github.com/tjyuanpeng/promise-portal/issues"
|
|
38
18
|
},
|
|
39
|
-
"license": "MIT",
|
|
40
19
|
"keywords": [
|
|
41
20
|
"vue",
|
|
42
21
|
"promise",
|
|
43
22
|
"portal"
|
|
44
23
|
],
|
|
24
|
+
"sideEffects": false,
|
|
25
|
+
"exports": {
|
|
26
|
+
".": {
|
|
27
|
+
"require": "./dist/index.cjs",
|
|
28
|
+
"import": "./dist/index.mjs"
|
|
29
|
+
},
|
|
30
|
+
"./package.json": "./package.json"
|
|
31
|
+
},
|
|
32
|
+
"main": "./dist/index.cjs",
|
|
33
|
+
"module": "./dist/index.mjs",
|
|
34
|
+
"types": "./dist/index.d.cts",
|
|
35
|
+
"files": [
|
|
36
|
+
"dist"
|
|
37
|
+
],
|
|
45
38
|
"scripts": {
|
|
46
|
-
"
|
|
47
|
-
"
|
|
39
|
+
"dev": "tsdown --watch",
|
|
40
|
+
"build": "tsdown",
|
|
41
|
+
"typecheck": "tsc --noEmit",
|
|
42
|
+
"lint": "eslint ."
|
|
43
|
+
},
|
|
44
|
+
"peerDependencies": {
|
|
45
|
+
"vue": "3"
|
|
46
|
+
},
|
|
47
|
+
"devDependencies": {
|
|
48
|
+
"tsdown": "catalog:",
|
|
49
|
+
"typescript": "catalog:"
|
|
48
50
|
}
|
|
49
|
-
}
|
|
51
|
+
}
|
package/LICENSE
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
MIT License Copyright (c) 2022 yuanpeng
|
|
2
|
-
|
|
3
|
-
Permission is hereby granted, free of
|
|
4
|
-
charge, to any person obtaining a copy of this software and associated
|
|
5
|
-
documentation files (the "Software"), to deal in the Software without
|
|
6
|
-
restriction, including without limitation the rights to use, copy, modify, merge,
|
|
7
|
-
publish, distribute, sublicense, and/or sell copies of the Software, and to
|
|
8
|
-
permit persons to whom the Software is furnished to do so, subject to the
|
|
9
|
-
following conditions:
|
|
10
|
-
|
|
11
|
-
The above copyright notice and this permission notice
|
|
12
|
-
(including the next paragraph) shall be included in all copies or substantial
|
|
13
|
-
portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
|
16
|
-
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
17
|
-
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
|
|
18
|
-
EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
|
19
|
-
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
20
|
-
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
-
THE SOFTWARE.
|
package/dist/index.d.ts
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import * as vue from 'vue';
|
|
2
|
-
import { VNode, Ref, App, Component } from 'vue';
|
|
3
|
-
|
|
4
|
-
interface Options {
|
|
5
|
-
unmountDelay?: number;
|
|
6
|
-
initialShowValue?: boolean;
|
|
7
|
-
}
|
|
8
|
-
interface Context<R> {
|
|
9
|
-
resolve: (value: R | PromiseLike<R>) => void;
|
|
10
|
-
reject: (reason?: any) => void;
|
|
11
|
-
el: HTMLDivElement;
|
|
12
|
-
vnode: VNode;
|
|
13
|
-
setUnmountDelay: (unmountDelay: number) => void;
|
|
14
|
-
show: Ref<boolean>;
|
|
15
|
-
}
|
|
16
|
-
interface Instance<R = any> {
|
|
17
|
-
defaultOptions: Options;
|
|
18
|
-
app: App;
|
|
19
|
-
map: WeakMap<VNode, Context<R>>;
|
|
20
|
-
install: (app: App) => void;
|
|
21
|
-
}
|
|
22
|
-
declare const getActiveInstance: () => Instance<any>;
|
|
23
|
-
declare const setActiveInstance: (instance: Instance) => Instance<any>;
|
|
24
|
-
declare const createPromisePortal: (defaultOptions?: Options) => Instance<any>;
|
|
25
|
-
declare const usePortalContext: <TOutput = any>(options?: Options) => Context<TOutput>;
|
|
26
|
-
declare const definePortal: <TOutput = any, TProps = any>(component: Component, options?: Options & {
|
|
27
|
-
instance?: Instance<TOutput> | undefined;
|
|
28
|
-
}) => [(props?: TProps | undefined, children?: unknown) => Promise<TOutput>, Component<any, any, any, vue.ComputedOptions, vue.MethodOptions>];
|
|
29
|
-
|
|
30
|
-
interface DetectorOptions {
|
|
31
|
-
style?: string;
|
|
32
|
-
text?: string;
|
|
33
|
-
}
|
|
34
|
-
declare const detectPromisePortalInstance: (options?: DetectorOptions) => () => void;
|
|
35
|
-
|
|
36
|
-
export { Context, DetectorOptions, Instance, Options, createPromisePortal, definePortal, detectPromisePortalInstance, getActiveInstance, setActiveInstance, usePortalContext };
|
package/dist/index.js
DELETED
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
// src/portal.ts
|
|
2
|
-
import { createVNode, render, inject, getCurrentInstance, defineComponent, ref } 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 = (options = {}) => {
|
|
21
|
-
const instance = inject(promisePortalSymbol);
|
|
22
|
-
if (!instance) {
|
|
23
|
-
throw new Error("[promise-portal]: no instance found.");
|
|
24
|
-
}
|
|
25
|
-
const vnode = getCurrentInstance()?.vnode;
|
|
26
|
-
if (!vnode) {
|
|
27
|
-
throw new Error("[promise-portal]: no vnode found.");
|
|
28
|
-
}
|
|
29
|
-
const data = instance.map.get(vnode);
|
|
30
|
-
if (!data) {
|
|
31
|
-
throw new Error("[promise-portal]: no inject data found.");
|
|
32
|
-
}
|
|
33
|
-
if (options.unmountDelay != void 0) {
|
|
34
|
-
data.setUnmountDelay(options.unmountDelay);
|
|
35
|
-
}
|
|
36
|
-
if (options.initialShowValue != void 0) {
|
|
37
|
-
data.show.value = options.initialShowValue;
|
|
38
|
-
}
|
|
39
|
-
return data;
|
|
40
|
-
};
|
|
41
|
-
var definePortal = (component, options = {}) => {
|
|
42
|
-
const instance = options.instance ?? (getCurrentInstance() && inject(promisePortalSymbol)) ?? getActiveInstance();
|
|
43
|
-
if (!instance) {
|
|
44
|
-
throw new Error("[promise-portal]: no instance found. Do you forget install promise-portal?");
|
|
45
|
-
}
|
|
46
|
-
let appContext = getCurrentInstance()?.appContext;
|
|
47
|
-
let contextHolderProvides = null;
|
|
48
|
-
const ContextHolder = defineComponent(() => () => {
|
|
49
|
-
appContext = getCurrentInstance()?.appContext;
|
|
50
|
-
contextHolderProvides = getCurrentInstance()?.provides;
|
|
51
|
-
});
|
|
52
|
-
const portal = (props, children) => {
|
|
53
|
-
const el = document.createElement("div");
|
|
54
|
-
el.setAttribute("data-promise-portal-container", "");
|
|
55
|
-
document.body.appendChild(el);
|
|
56
|
-
let unmountDelay = options.unmountDelay ?? instance.defaultOptions.unmountDelay;
|
|
57
|
-
const setUnmountDelay = (delay) => {
|
|
58
|
-
unmountDelay = delay;
|
|
59
|
-
};
|
|
60
|
-
const show = ref(options.initialShowValue ?? instance.defaultOptions.initialShowValue ?? true);
|
|
61
|
-
let vnode;
|
|
62
|
-
const p = new Promise((resolve, reject) => {
|
|
63
|
-
vnode = createVNode(component, props, children);
|
|
64
|
-
instance.map.set(vnode, { resolve, reject, el, vnode, setUnmountDelay, show });
|
|
65
|
-
const ac = appContext ?? instance.app._context;
|
|
66
|
-
vnode.appContext = Object.create(ac, {
|
|
67
|
-
provides: {
|
|
68
|
-
value: contextHolderProvides ?? ac.provides
|
|
69
|
-
}
|
|
70
|
-
});
|
|
71
|
-
render(vnode, el);
|
|
72
|
-
});
|
|
73
|
-
p.finally(() => {
|
|
74
|
-
show.value = false;
|
|
75
|
-
setTimeout(() => {
|
|
76
|
-
render(null, el);
|
|
77
|
-
document.body.removeChild(el);
|
|
78
|
-
}, unmountDelay);
|
|
79
|
-
});
|
|
80
|
-
return p;
|
|
81
|
-
};
|
|
82
|
-
return [portal, ContextHolder];
|
|
83
|
-
};
|
|
84
|
-
|
|
85
|
-
// src/detector.ts
|
|
86
|
-
function detect(options) {
|
|
87
|
-
const {
|
|
88
|
-
style = "position:fixed;top:0;right:0;text-align:right;line-height:1.3;color:red;z-index:9999;",
|
|
89
|
-
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.`
|
|
90
|
-
} = options;
|
|
91
|
-
const containers = document.querySelectorAll("[data-promise-portal-container]");
|
|
92
|
-
const detector = document.querySelector("[data-promise-portal-detector]");
|
|
93
|
-
if (containers.length === 0) {
|
|
94
|
-
detector?.remove();
|
|
95
|
-
return;
|
|
96
|
-
}
|
|
97
|
-
if (!detector) {
|
|
98
|
-
const el = document.createElement("div");
|
|
99
|
-
el.setAttribute("data-promise-portal-detector", "");
|
|
100
|
-
el.setAttribute("style", style);
|
|
101
|
-
el.innerHTML = text;
|
|
102
|
-
document.body.appendChild(el);
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
var detectPromisePortalInstance = (options = {}) => {
|
|
106
|
-
const timer = setInterval(() => detect(options), 200);
|
|
107
|
-
return () => clearInterval(timer);
|
|
108
|
-
};
|
|
109
|
-
export {
|
|
110
|
-
createPromisePortal,
|
|
111
|
-
definePortal,
|
|
112
|
-
detectPromisePortalInstance,
|
|
113
|
-
getActiveInstance,
|
|
114
|
-
setActiveInstance,
|
|
115
|
-
usePortalContext
|
|
116
|
-
};
|