promise-portal 1.2.1 → 2.0.1
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 +46 -67
- package/dist/index.cjs +110 -158
- package/dist/index.d.cts +41 -0
- package/dist/index.d.mts +41 -0
- package/dist/index.mjs +113 -0
- package/package.json +28 -26
- package/dist/index.d.ts +0 -41
- package/dist/index.js +0 -131
package/README.md
CHANGED
|
@@ -5,14 +5,7 @@ use component as a promisd-like function
|
|
|
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,15 +79,11 @@ 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
|
-
createPromisePortal({
|
|
85
|
-
unmountDelay: 200,
|
|
86
|
-
})
|
|
87
|
-
)
|
|
86
|
+
app.use(createPromisePortal())
|
|
88
87
|
```
|
|
89
88
|
|
|
90
89
|
### use `ContextProvider` to set context globally
|
|
@@ -95,10 +94,11 @@ app.use(
|
|
|
95
94
|
import locale from 'ant-design-vue/es/locale/zh_CN'
|
|
96
95
|
import { ContextProvider } from 'promise-portal'
|
|
97
96
|
</script>
|
|
97
|
+
|
|
98
98
|
<template>
|
|
99
99
|
<a-config-provider :locale="locale">
|
|
100
100
|
<ContextProvider>
|
|
101
|
-
<router-view
|
|
101
|
+
<router-view />
|
|
102
102
|
</ContextProvider>
|
|
103
103
|
</a-config-provider>
|
|
104
104
|
</template>
|
|
@@ -110,6 +110,7 @@ import { ContextProvider } from 'promise-portal'
|
|
|
110
110
|
<!-- ./components/comp.vue -->
|
|
111
111
|
<script setup lang="ts">
|
|
112
112
|
import { usePortalContext } from 'promise-portal'
|
|
113
|
+
|
|
113
114
|
export interface Output {
|
|
114
115
|
confirm: boolean
|
|
115
116
|
}
|
|
@@ -122,8 +123,11 @@ const onCancel = () => {
|
|
|
122
123
|
resolve({ confirm: false })
|
|
123
124
|
}
|
|
124
125
|
</script>
|
|
126
|
+
|
|
125
127
|
<template>
|
|
126
|
-
<a-modal v-model:open="show" @cancel="resolve">
|
|
128
|
+
<a-modal v-model:open="show" @cancel="resolve">
|
|
129
|
+
{{ props.input }}
|
|
130
|
+
</a-modal>
|
|
127
131
|
</template>
|
|
128
132
|
```
|
|
129
133
|
|
|
@@ -133,6 +137,7 @@ const onCancel = () => {
|
|
|
133
137
|
// ./App.vue
|
|
134
138
|
import { definePortal } from 'promise-portal'
|
|
135
139
|
import Comp, { Input, Output } from './components/comp.vue'
|
|
140
|
+
|
|
136
141
|
const [func] = definePortal<Output, Input>(Comp)
|
|
137
142
|
const onClick = async () => {
|
|
138
143
|
const result = await func({
|
|
@@ -153,35 +158,6 @@ const instance = createPromisePortal()
|
|
|
153
158
|
app.use(instance)
|
|
154
159
|
```
|
|
155
160
|
|
|
156
|
-
you can set default options to instance
|
|
157
|
-
|
|
158
|
-
```ts
|
|
159
|
-
const instance = createPromisePortal({
|
|
160
|
-
// set a time gap before portal unmount,
|
|
161
|
-
// in general, it is to wait for animation effect
|
|
162
|
-
unmountDelay: 200,
|
|
163
|
-
|
|
164
|
-
// initial value to property show, default value is true
|
|
165
|
-
initialShowValue: true,
|
|
166
|
-
})
|
|
167
|
-
```
|
|
168
|
-
|
|
169
|
-
### getActiveInstance
|
|
170
|
-
|
|
171
|
-
get active promise-portal instance
|
|
172
|
-
|
|
173
|
-
```ts
|
|
174
|
-
const instance = getActiveInstance()
|
|
175
|
-
```
|
|
176
|
-
|
|
177
|
-
### setActiveInstance
|
|
178
|
-
|
|
179
|
-
set active promise-portal instance
|
|
180
|
-
|
|
181
|
-
```ts
|
|
182
|
-
setActiveInstance(instance)
|
|
183
|
-
```
|
|
184
|
-
|
|
185
161
|
### ContextProvider
|
|
186
162
|
|
|
187
163
|
a component to set context globally
|
|
@@ -191,10 +167,11 @@ a component to set context globally
|
|
|
191
167
|
import locale from 'ant-design-vue/es/locale/zh_CN'
|
|
192
168
|
import { ContextProvider } from 'promise-portal'
|
|
193
169
|
</script>
|
|
170
|
+
|
|
194
171
|
<template>
|
|
195
172
|
<a-config-provider :locale="locale">
|
|
196
173
|
<ContextProvider>
|
|
197
|
-
<router-view
|
|
174
|
+
<router-view />
|
|
198
175
|
</ContextProvider>
|
|
199
176
|
</a-config-provider>
|
|
200
177
|
</template>
|
|
@@ -211,16 +188,15 @@ const { resolve } = usePortalContext()
|
|
|
211
188
|
const {
|
|
212
189
|
resolve, // promise resolve handler
|
|
213
190
|
reject, // promise reject handler
|
|
214
|
-
el, // portal base element,
|
|
191
|
+
el, // portal base element, injected into 'appendTo' element
|
|
215
192
|
vnode, // portal base vue vnode
|
|
216
|
-
|
|
217
|
-
show, //
|
|
193
|
+
unmountDelay, // Ref for portal unmount delay (ms)
|
|
194
|
+
show, // Ref for modal display state (controlled by portal)
|
|
218
195
|
} = usePortalContext({
|
|
219
|
-
//
|
|
220
|
-
// in general, it is to wait for animation effect
|
|
196
|
+
// Unmount delay (ms) for portal, usually for animation effects
|
|
221
197
|
unmountDelay: 200,
|
|
222
198
|
|
|
223
|
-
//
|
|
199
|
+
// Initial value for the show ref (defaults to true)
|
|
224
200
|
initialShowValue: true,
|
|
225
201
|
})
|
|
226
202
|
```
|
|
@@ -247,8 +223,9 @@ use `initialShowValue` to set inital value, default inital value is `true`
|
|
|
247
223
|
<script setup lang="ts">
|
|
248
224
|
const { resolve, show } = usePortalContext<Output>({ initialShowValue: true })
|
|
249
225
|
</script>
|
|
226
|
+
|
|
250
227
|
<template>
|
|
251
|
-
<a-modal v-model:open="show" @cancel="resolve"
|
|
228
|
+
<a-modal v-model:open="show" @cancel="resolve" />
|
|
252
229
|
</template>
|
|
253
230
|
```
|
|
254
231
|
|
|
@@ -258,6 +235,7 @@ define a portal, return a portal function
|
|
|
258
235
|
|
|
259
236
|
```ts
|
|
260
237
|
import Comp from './component.vue'
|
|
238
|
+
|
|
261
239
|
const portalFunc = definePortal(Comp)
|
|
262
240
|
portalFunc()
|
|
263
241
|
```
|
|
@@ -266,6 +244,9 @@ you can define generic types to check input object and output object
|
|
|
266
244
|
|
|
267
245
|
```ts
|
|
268
246
|
// component.vue
|
|
247
|
+
// App.vue
|
|
248
|
+
import Comp, { Input, Output } from './component.vue'
|
|
249
|
+
|
|
269
250
|
export interface Input {
|
|
270
251
|
firstName: string
|
|
271
252
|
lastName: string
|
|
@@ -278,9 +259,6 @@ export interface Output {
|
|
|
278
259
|
|
|
279
260
|
const props = defineProps<Input>()
|
|
280
261
|
const { resolve } = usePortalContext<Output>()
|
|
281
|
-
|
|
282
|
-
// App.vue
|
|
283
|
-
import Comp, { Input, Output } from './component.vue'
|
|
284
262
|
const portal = definePortal<Output, Input>(Comp)
|
|
285
263
|
const output = await portal({
|
|
286
264
|
firstName: 'joe',
|
|
@@ -292,15 +270,15 @@ define a portal with empty parameter
|
|
|
292
270
|
|
|
293
271
|
```ts
|
|
294
272
|
// component.vue
|
|
273
|
+
// App.vue
|
|
274
|
+
import Comp, { Output } from './component.vue'
|
|
275
|
+
|
|
295
276
|
export interface Output {
|
|
296
277
|
fullName: string
|
|
297
278
|
confirm: boolean
|
|
298
279
|
}
|
|
299
280
|
|
|
300
281
|
const { resolve } = usePortalContext<Output>()
|
|
301
|
-
|
|
302
|
-
// App.vue
|
|
303
|
-
import Comp, { Output } from './component.vue'
|
|
304
282
|
const portal = definePortal<Output, void>(Comp)
|
|
305
283
|
const output = await portal() // only allow empty parameter
|
|
306
284
|
```
|
|
@@ -309,14 +287,15 @@ you can set a options to definePortal
|
|
|
309
287
|
|
|
310
288
|
```ts
|
|
311
289
|
definePortal(Comp, {
|
|
312
|
-
//
|
|
290
|
+
// Unmount delay (ms) for portal, usually for animation effects
|
|
313
291
|
unmountDelay: 200,
|
|
314
292
|
|
|
315
|
-
//
|
|
293
|
+
// Initial value for the show ref (defaults to true)
|
|
316
294
|
initialShowValue: true,
|
|
317
295
|
|
|
318
|
-
//
|
|
319
|
-
|
|
296
|
+
// a dom element or CSS selector or Ref value or a function returing a dom element,
|
|
297
|
+
// append the portal element to (defaults to document.body)
|
|
298
|
+
appendTo: document.body,
|
|
320
299
|
})
|
|
321
300
|
```
|
|
322
301
|
|
|
@@ -347,9 +326,9 @@ detectPromisePortalInstance({
|
|
|
347
326
|
})
|
|
348
327
|
```
|
|
349
328
|
|
|
350
|
-
#
|
|
329
|
+
# Acknowledgements
|
|
351
330
|
|
|
352
|
-
- [react
|
|
331
|
+
- [react portal](https://reactjs.org/docs/portals.html)
|
|
353
332
|
- [vue teleport](https://vuejs.org/guide/built-ins/teleport.html)
|
|
354
333
|
- [@filez/portal](https://github.com/lenovo-filez/portal)
|
|
355
334
|
- [promise-modal](https://github.com/liruifengv/promise-modal)
|
package/dist/index.cjs
CHANGED
|
@@ -1,165 +1,117 @@
|
|
|
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);
|
|
1
|
+
let vue = require("vue");
|
|
19
2
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
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
|
+
};
|
|
33
24
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
app.provide(promisePortalSymbol, instance);
|
|
51
|
-
}
|
|
52
|
-
};
|
|
53
|
-
return instance;
|
|
25
|
+
//#endregion
|
|
26
|
+
//#region src/portal.ts
|
|
27
|
+
const promisePortalSymbol = Symbol("promise-portal");
|
|
28
|
+
let activeInstance;
|
|
29
|
+
const createPromisePortal = () => {
|
|
30
|
+
const instance = {
|
|
31
|
+
app: void 0,
|
|
32
|
+
map: /* @__PURE__ */ new WeakMap(),
|
|
33
|
+
provides: void 0,
|
|
34
|
+
install(app) {
|
|
35
|
+
instance.app = app;
|
|
36
|
+
activeInstance = instance;
|
|
37
|
+
app.provide(promisePortalSymbol, instance);
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
return instance;
|
|
54
41
|
};
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
if (!data) {
|
|
66
|
-
throw new Error("[promise-portal]: no inject data found.");
|
|
67
|
-
}
|
|
68
|
-
if (options.unmountDelay != void 0) {
|
|
69
|
-
data.setUnmountDelay(options.unmountDelay);
|
|
70
|
-
}
|
|
71
|
-
if (options.initialShowValue != void 0) {
|
|
72
|
-
data.show.value = options.initialShowValue;
|
|
73
|
-
}
|
|
74
|
-
return data;
|
|
42
|
+
const usePortalContext = (options = {}) => {
|
|
43
|
+
const instance = (0, vue.inject)(promisePortalSymbol);
|
|
44
|
+
if (!instance) throw new Error("[promise-portal]: no instance found. Did you forget to install promise-portal?");
|
|
45
|
+
const vnode = (0, vue.getCurrentInstance)()?.vnode;
|
|
46
|
+
if (!vnode) throw new Error("[promise-portal]: no vnode found in current component instance.");
|
|
47
|
+
const scope = instance.map.get(vnode);
|
|
48
|
+
if (!scope) throw new Error("[promise-portal]: no inject scope found.");
|
|
49
|
+
if (options.unmountDelay !== void 0) scope.unmountDelay.value = options.unmountDelay;
|
|
50
|
+
if (options.initialShowValue !== void 0) scope.show.value = options.initialShowValue;
|
|
51
|
+
return scope;
|
|
75
52
|
};
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
let appContext = (0, import_vue.getCurrentInstance)()?.appContext;
|
|
82
|
-
let contextHolderProvides = null;
|
|
83
|
-
const ContextHolder = (0, import_vue.defineComponent)(() => () => {
|
|
84
|
-
appContext = (0, import_vue.getCurrentInstance)()?.appContext;
|
|
85
|
-
contextHolderProvides = (0, import_vue.getCurrentInstance)()?.provides;
|
|
86
|
-
});
|
|
87
|
-
const portal = (props, children) => {
|
|
88
|
-
const el = document.createElement("div");
|
|
89
|
-
el.setAttribute("data-promise-portal-container", "");
|
|
90
|
-
document.body.appendChild(el);
|
|
91
|
-
let unmountDelay = options.unmountDelay ?? instance.defaultOptions.unmountDelay;
|
|
92
|
-
const setUnmountDelay = (delay) => {
|
|
93
|
-
unmountDelay = delay;
|
|
94
|
-
};
|
|
95
|
-
const show = (0, import_vue.ref)(options.initialShowValue ?? instance.defaultOptions.initialShowValue ?? true);
|
|
96
|
-
let vnode;
|
|
97
|
-
const p = new Promise((resolve, reject) => {
|
|
98
|
-
vnode = (0, import_vue.createVNode)(component, props, children);
|
|
99
|
-
instance.map.set(vnode, { resolve, reject, el, vnode, setUnmountDelay, show });
|
|
100
|
-
const ac = appContext ?? instance.app._context;
|
|
101
|
-
vnode.appContext = Object.create(ac, {
|
|
102
|
-
provides: {
|
|
103
|
-
value: contextHolderProvides ?? instance.provides ?? ac.provides
|
|
104
|
-
}
|
|
105
|
-
});
|
|
106
|
-
(0, import_vue.render)(vnode, el);
|
|
107
|
-
});
|
|
108
|
-
p.finally(() => {
|
|
109
|
-
show.value = false;
|
|
110
|
-
setTimeout(() => {
|
|
111
|
-
(0, import_vue.render)(null, el);
|
|
112
|
-
document.body.removeChild(el);
|
|
113
|
-
}, unmountDelay);
|
|
114
|
-
});
|
|
115
|
-
return p;
|
|
116
|
-
};
|
|
117
|
-
return [portal, ContextHolder];
|
|
53
|
+
const resolveTarget = (to) => {
|
|
54
|
+
if (typeof to === "string") return document.querySelector(to);
|
|
55
|
+
else if ((0, vue.isRef)(to)) return (0, vue.unref)(to);
|
|
56
|
+
else if (typeof to === "function") return to();
|
|
57
|
+
return to;
|
|
118
58
|
};
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
59
|
+
const definePortal = (component, options = {}) => {
|
|
60
|
+
const instance = ((0, vue.getCurrentInstance)() && (0, vue.inject)(promisePortalSymbol)) ?? activeInstance;
|
|
61
|
+
if (!instance) throw new Error("[promise-portal]: no instance found. Did you forget to install promise-portal?");
|
|
62
|
+
let appContext = (0, vue.getCurrentInstance)()?.appContext ?? instance.app._context;
|
|
63
|
+
let provides = instance.provides ?? appContext.provides;
|
|
64
|
+
const ContextHolder = (0, vue.defineComponent)(() => () => {
|
|
65
|
+
const ci = (0, vue.getCurrentInstance)();
|
|
66
|
+
if (ci) {
|
|
67
|
+
appContext = ci.appContext;
|
|
68
|
+
provides = ci.provides;
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
const portal = (props, children) => {
|
|
72
|
+
const el = document.createElement("div");
|
|
73
|
+
el.setAttribute("data-promise-portal-container", "");
|
|
74
|
+
const target = resolveTarget(options.appendTo ?? document.body);
|
|
75
|
+
if (!target) throw new Error("[promise-portal]: invalid appendTo target - no element found or provided.");
|
|
76
|
+
target.appendChild(el);
|
|
77
|
+
const unmountDelay = (0, vue.ref)(options.unmountDelay ?? 0);
|
|
78
|
+
const show = (0, vue.ref)(options.initialShowValue ?? true);
|
|
79
|
+
const promise = new Promise((resolve, reject) => {
|
|
80
|
+
const vnode = (0, vue.createVNode)(component, props, children);
|
|
81
|
+
vnode.appContext = Object.create(appContext, { provides: { value: provides } });
|
|
82
|
+
instance.map.set(vnode, {
|
|
83
|
+
resolve,
|
|
84
|
+
reject,
|
|
85
|
+
el,
|
|
86
|
+
vnode,
|
|
87
|
+
unmountDelay,
|
|
88
|
+
show
|
|
89
|
+
});
|
|
90
|
+
(0, vue.render)(vnode, el);
|
|
91
|
+
});
|
|
92
|
+
promise.finally(() => {
|
|
93
|
+
show.value = false;
|
|
94
|
+
setTimeout(() => {
|
|
95
|
+
(0, vue.render)(null, el);
|
|
96
|
+
el?.remove();
|
|
97
|
+
}, unmountDelay.value);
|
|
98
|
+
});
|
|
99
|
+
return promise;
|
|
100
|
+
};
|
|
101
|
+
return [portal, ContextHolder];
|
|
154
102
|
};
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
setActiveInstance,
|
|
163
|
-
usePortalContext,
|
|
164
|
-
version
|
|
103
|
+
const ContextProvider = (0, vue.defineComponent)({
|
|
104
|
+
name: "PromisePortalContextProvider",
|
|
105
|
+
setup(_props, { slots }) {
|
|
106
|
+
const provides = (0, vue.getCurrentInstance)()?.provides;
|
|
107
|
+
if (provides && activeInstance) activeInstance.provides = provides;
|
|
108
|
+
return () => slots.default?.();
|
|
109
|
+
}
|
|
165
110
|
});
|
|
111
|
+
|
|
112
|
+
//#endregion
|
|
113
|
+
exports.ContextProvider = ContextProvider;
|
|
114
|
+
exports.createPromisePortal = createPromisePortal;
|
|
115
|
+
exports.definePortal = definePortal;
|
|
116
|
+
exports.detectPromisePortalInstance = detectPromisePortalInstance;
|
|
117
|
+
exports.usePortalContext = usePortalContext;
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import * as vue0 from "vue";
|
|
2
|
+
import { App, Component, Ref, 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
|
+
interface UsePortalContextOptions {
|
|
13
|
+
unmountDelay?: number;
|
|
14
|
+
initialShowValue?: boolean;
|
|
15
|
+
}
|
|
16
|
+
interface DefinePortalOptions extends UsePortalContextOptions {
|
|
17
|
+
appendTo?: string | HTMLElement | Ref<HTMLElement> | (() => HTMLElement);
|
|
18
|
+
}
|
|
19
|
+
type DefinePortalResult<Output, Input> = [(props?: Input, children?: unknown) => Promise<Output>, Component];
|
|
20
|
+
interface Scope<R> {
|
|
21
|
+
resolve: (value: R | PromiseLike<R>) => void;
|
|
22
|
+
reject: (reason?: any) => void;
|
|
23
|
+
el: HTMLDivElement;
|
|
24
|
+
vnode: VNode;
|
|
25
|
+
unmountDelay: Ref<number>;
|
|
26
|
+
show: Ref<boolean>;
|
|
27
|
+
}
|
|
28
|
+
interface Instance<R = any> {
|
|
29
|
+
app: App;
|
|
30
|
+
map: WeakMap<VNode, Scope<R>>;
|
|
31
|
+
provides: any;
|
|
32
|
+
install: (app: App) => void;
|
|
33
|
+
}
|
|
34
|
+
declare const createPromisePortal: () => Instance<any>;
|
|
35
|
+
declare const usePortalContext: <Output = any>(options?: UsePortalContextOptions) => Scope<Output>;
|
|
36
|
+
declare const definePortal: <Output = any, Input = any>(component: Component, options?: DefinePortalOptions) => DefinePortalResult<Output, Input>;
|
|
37
|
+
declare const ContextProvider: vue0.DefineComponent<{}, () => VNode<vue0.RendererNode, vue0.RendererElement, {
|
|
38
|
+
[key: string]: any;
|
|
39
|
+
}>[] | undefined, {}, {}, {}, vue0.ComponentOptionsMixin, vue0.ComponentOptionsMixin, {}, string, vue0.PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, vue0.ComponentProvideOptions, true, {}, any>;
|
|
40
|
+
//#endregion
|
|
41
|
+
export { ContextProvider, DefinePortalOptions, DefinePortalResult, DetectorOptions, Instance, Scope, UsePortalContextOptions, createPromisePortal, definePortal, detectPromisePortalInstance, usePortalContext };
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import * as vue0 from "vue";
|
|
2
|
+
import { App, Component, Ref, 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
|
+
interface UsePortalContextOptions {
|
|
13
|
+
unmountDelay?: number;
|
|
14
|
+
initialShowValue?: boolean;
|
|
15
|
+
}
|
|
16
|
+
interface DefinePortalOptions extends UsePortalContextOptions {
|
|
17
|
+
appendTo?: string | HTMLElement | Ref<HTMLElement> | (() => HTMLElement);
|
|
18
|
+
}
|
|
19
|
+
type DefinePortalResult<Output, Input> = [(props?: Input, children?: unknown) => Promise<Output>, Component];
|
|
20
|
+
interface Scope<R> {
|
|
21
|
+
resolve: (value: R | PromiseLike<R>) => void;
|
|
22
|
+
reject: (reason?: any) => void;
|
|
23
|
+
el: HTMLDivElement;
|
|
24
|
+
vnode: VNode;
|
|
25
|
+
unmountDelay: Ref<number>;
|
|
26
|
+
show: Ref<boolean>;
|
|
27
|
+
}
|
|
28
|
+
interface Instance<R = any> {
|
|
29
|
+
app: App;
|
|
30
|
+
map: WeakMap<VNode, Scope<R>>;
|
|
31
|
+
provides: any;
|
|
32
|
+
install: (app: App) => void;
|
|
33
|
+
}
|
|
34
|
+
declare const createPromisePortal: () => Instance<any>;
|
|
35
|
+
declare const usePortalContext: <Output = any>(options?: UsePortalContextOptions) => Scope<Output>;
|
|
36
|
+
declare const definePortal: <Output = any, Input = any>(component: Component, options?: DefinePortalOptions) => DefinePortalResult<Output, Input>;
|
|
37
|
+
declare const ContextProvider: vue0.DefineComponent<{}, () => VNode<vue0.RendererNode, vue0.RendererElement, {
|
|
38
|
+
[key: string]: any;
|
|
39
|
+
}>[] | undefined, {}, {}, {}, vue0.ComponentOptionsMixin, vue0.ComponentOptionsMixin, {}, string, vue0.PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, vue0.ComponentProvideOptions, true, {}, any>;
|
|
40
|
+
//#endregion
|
|
41
|
+
export { ContextProvider, DefinePortalOptions, DefinePortalResult, DetectorOptions, Instance, Scope, UsePortalContextOptions, createPromisePortal, definePortal, detectPromisePortalInstance, usePortalContext };
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { createVNode, defineComponent, getCurrentInstance, inject, isRef, ref, render, unref } 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
|
+
let activeInstance;
|
|
29
|
+
const createPromisePortal = () => {
|
|
30
|
+
const instance = {
|
|
31
|
+
app: void 0,
|
|
32
|
+
map: /* @__PURE__ */ new WeakMap(),
|
|
33
|
+
provides: void 0,
|
|
34
|
+
install(app) {
|
|
35
|
+
instance.app = app;
|
|
36
|
+
activeInstance = instance;
|
|
37
|
+
app.provide(promisePortalSymbol, instance);
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
return instance;
|
|
41
|
+
};
|
|
42
|
+
const usePortalContext = (options = {}) => {
|
|
43
|
+
const instance = inject(promisePortalSymbol);
|
|
44
|
+
if (!instance) throw new Error("[promise-portal]: no instance found. Did you forget to install promise-portal?");
|
|
45
|
+
const vnode = getCurrentInstance()?.vnode;
|
|
46
|
+
if (!vnode) throw new Error("[promise-portal]: no vnode found in current component instance.");
|
|
47
|
+
const scope = instance.map.get(vnode);
|
|
48
|
+
if (!scope) throw new Error("[promise-portal]: no inject scope found.");
|
|
49
|
+
if (options.unmountDelay !== void 0) scope.unmountDelay.value = options.unmountDelay;
|
|
50
|
+
if (options.initialShowValue !== void 0) scope.show.value = options.initialShowValue;
|
|
51
|
+
return scope;
|
|
52
|
+
};
|
|
53
|
+
const resolveTarget = (to) => {
|
|
54
|
+
if (typeof to === "string") return document.querySelector(to);
|
|
55
|
+
else if (isRef(to)) return unref(to);
|
|
56
|
+
else if (typeof to === "function") return to();
|
|
57
|
+
return to;
|
|
58
|
+
};
|
|
59
|
+
const definePortal = (component, options = {}) => {
|
|
60
|
+
const instance = (getCurrentInstance() && inject(promisePortalSymbol)) ?? activeInstance;
|
|
61
|
+
if (!instance) throw new Error("[promise-portal]: no instance found. Did you forget to install promise-portal?");
|
|
62
|
+
let appContext = getCurrentInstance()?.appContext ?? instance.app._context;
|
|
63
|
+
let provides = instance.provides ?? appContext.provides;
|
|
64
|
+
const ContextHolder = defineComponent(() => () => {
|
|
65
|
+
const ci = getCurrentInstance();
|
|
66
|
+
if (ci) {
|
|
67
|
+
appContext = ci.appContext;
|
|
68
|
+
provides = ci.provides;
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
const portal = (props, children) => {
|
|
72
|
+
const el = document.createElement("div");
|
|
73
|
+
el.setAttribute("data-promise-portal-container", "");
|
|
74
|
+
const target = resolveTarget(options.appendTo ?? document.body);
|
|
75
|
+
if (!target) throw new Error("[promise-portal]: invalid appendTo target - no element found or provided.");
|
|
76
|
+
target.appendChild(el);
|
|
77
|
+
const unmountDelay = ref(options.unmountDelay ?? 0);
|
|
78
|
+
const show = ref(options.initialShowValue ?? true);
|
|
79
|
+
const promise = new Promise((resolve, reject) => {
|
|
80
|
+
const vnode = createVNode(component, props, children);
|
|
81
|
+
vnode.appContext = Object.create(appContext, { provides: { value: provides } });
|
|
82
|
+
instance.map.set(vnode, {
|
|
83
|
+
resolve,
|
|
84
|
+
reject,
|
|
85
|
+
el,
|
|
86
|
+
vnode,
|
|
87
|
+
unmountDelay,
|
|
88
|
+
show
|
|
89
|
+
});
|
|
90
|
+
render(vnode, el);
|
|
91
|
+
});
|
|
92
|
+
promise.finally(() => {
|
|
93
|
+
show.value = false;
|
|
94
|
+
setTimeout(() => {
|
|
95
|
+
render(null, el);
|
|
96
|
+
el?.remove();
|
|
97
|
+
}, unmountDelay.value);
|
|
98
|
+
});
|
|
99
|
+
return promise;
|
|
100
|
+
};
|
|
101
|
+
return [portal, ContextHolder];
|
|
102
|
+
};
|
|
103
|
+
const ContextProvider = defineComponent({
|
|
104
|
+
name: "PromisePortalContextProvider",
|
|
105
|
+
setup(_props, { slots }) {
|
|
106
|
+
const provides = getCurrentInstance()?.provides;
|
|
107
|
+
if (provides && activeInstance) activeInstance.provides = provides;
|
|
108
|
+
return () => slots.default?.();
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
//#endregion
|
|
113
|
+
export { ContextProvider, createPromisePortal, definePortal, detectPromisePortalInstance, usePortalContext };
|
package/package.json
CHANGED
|
@@ -1,33 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "promise-portal",
|
|
3
|
-
"version": "1.2.1",
|
|
4
|
-
"description": "use component as a promisd-like function",
|
|
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.1",
|
|
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
|
+
],
|
|
38
|
+
"peerDependencies": {
|
|
39
|
+
"vue": "3"
|
|
40
|
+
},
|
|
41
|
+
"devDependencies": {
|
|
42
|
+
"tsdown": "0.20.1",
|
|
43
|
+
"typescript": "~5.9.3"
|
|
44
|
+
},
|
|
45
45
|
"scripts": {
|
|
46
|
-
"
|
|
47
|
-
"
|
|
46
|
+
"dev": "tsdown --watch",
|
|
47
|
+
"build": "tsdown",
|
|
48
|
+
"typecheck": "tsc --noEmit",
|
|
49
|
+
"lint": "eslint ."
|
|
48
50
|
}
|
|
49
51
|
}
|
package/dist/index.d.ts
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import * as vue from 'vue';
|
|
2
|
-
import { VNode, Ref, App, Component } from 'vue';
|
|
3
|
-
|
|
4
|
-
declare const version = "1.2.1";
|
|
5
|
-
interface Options {
|
|
6
|
-
unmountDelay?: number;
|
|
7
|
-
initialShowValue?: boolean;
|
|
8
|
-
}
|
|
9
|
-
interface Context<R> {
|
|
10
|
-
resolve: (value: R | PromiseLike<R>) => void;
|
|
11
|
-
reject: (reason?: any) => void;
|
|
12
|
-
el: HTMLDivElement;
|
|
13
|
-
vnode: VNode;
|
|
14
|
-
setUnmountDelay: (unmountDelay: number) => void;
|
|
15
|
-
show: Ref<boolean>;
|
|
16
|
-
}
|
|
17
|
-
interface Instance<R = any> {
|
|
18
|
-
defaultOptions: Options;
|
|
19
|
-
app: App;
|
|
20
|
-
map: WeakMap<VNode, Context<R>>;
|
|
21
|
-
provides: any;
|
|
22
|
-
install: (app: App) => void;
|
|
23
|
-
}
|
|
24
|
-
declare const getActiveInstance: () => Instance<any>;
|
|
25
|
-
declare const setActiveInstance: (instance: Instance) => Instance<any>;
|
|
26
|
-
declare const createPromisePortal: (defaultOptions?: Options) => Instance<any>;
|
|
27
|
-
declare const usePortalContext: <TOutput = any>(options?: Options) => Context<TOutput>;
|
|
28
|
-
declare const definePortal: <TOutput = any, TProps = any>(component: Component, options?: Options & {
|
|
29
|
-
instance?: Instance<TOutput> | undefined;
|
|
30
|
-
}) => [(props?: TProps | undefined, children?: unknown) => Promise<TOutput>, Component<any, any, any, vue.ComputedOptions, vue.MethodOptions>];
|
|
31
|
-
declare const ContextProvider: vue.DefineComponent<{}, () => VNode<vue.RendererNode, vue.RendererElement, {
|
|
32
|
-
[key: string]: any;
|
|
33
|
-
}>[] | undefined, {}, {}, {}, vue.ComponentOptionsMixin, vue.ComponentOptionsMixin, {}, string, vue.VNodeProps & vue.AllowedComponentProps & vue.ComponentCustomProps, Readonly<vue.ExtractPropTypes<{}>>, {}, {}>;
|
|
34
|
-
|
|
35
|
-
interface DetectorOptions {
|
|
36
|
-
style?: string;
|
|
37
|
-
text?: string;
|
|
38
|
-
}
|
|
39
|
-
declare const detectPromisePortalInstance: (options?: DetectorOptions) => () => void;
|
|
40
|
-
|
|
41
|
-
export { Context, ContextProvider, DetectorOptions, Instance, Options, createPromisePortal, definePortal, detectPromisePortalInstance, getActiveInstance, setActiveInstance, usePortalContext, version };
|
package/dist/index.js
DELETED
|
@@ -1,131 +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 version = `1.2.1`;
|
|
5
|
-
var activeInstance;
|
|
6
|
-
var getActiveInstance = () => activeInstance;
|
|
7
|
-
var setActiveInstance = (instance) => activeInstance = instance;
|
|
8
|
-
var createPromisePortal = (defaultOptions = {}) => {
|
|
9
|
-
const instance = {
|
|
10
|
-
defaultOptions,
|
|
11
|
-
app: void 0,
|
|
12
|
-
map: /* @__PURE__ */ new WeakMap(),
|
|
13
|
-
provides: void 0,
|
|
14
|
-
install(app) {
|
|
15
|
-
instance.app = app;
|
|
16
|
-
setActiveInstance(instance);
|
|
17
|
-
app.provide(promisePortalSymbol, instance);
|
|
18
|
-
}
|
|
19
|
-
};
|
|
20
|
-
return instance;
|
|
21
|
-
};
|
|
22
|
-
var usePortalContext = (options = {}) => {
|
|
23
|
-
const instance = inject(promisePortalSymbol);
|
|
24
|
-
if (!instance) {
|
|
25
|
-
throw new Error("[promise-portal]: no instance found.");
|
|
26
|
-
}
|
|
27
|
-
const vnode = getCurrentInstance()?.vnode;
|
|
28
|
-
if (!vnode) {
|
|
29
|
-
throw new Error("[promise-portal]: no vnode found.");
|
|
30
|
-
}
|
|
31
|
-
const data = instance.map.get(vnode);
|
|
32
|
-
if (!data) {
|
|
33
|
-
throw new Error("[promise-portal]: no inject data found.");
|
|
34
|
-
}
|
|
35
|
-
if (options.unmountDelay != void 0) {
|
|
36
|
-
data.setUnmountDelay(options.unmountDelay);
|
|
37
|
-
}
|
|
38
|
-
if (options.initialShowValue != void 0) {
|
|
39
|
-
data.show.value = options.initialShowValue;
|
|
40
|
-
}
|
|
41
|
-
return data;
|
|
42
|
-
};
|
|
43
|
-
var definePortal = (component, options = {}) => {
|
|
44
|
-
const instance = options.instance ?? (getCurrentInstance() && inject(promisePortalSymbol)) ?? getActiveInstance();
|
|
45
|
-
if (!instance) {
|
|
46
|
-
throw new Error("[promise-portal]: no instance found. Do you forget install promise-portal?");
|
|
47
|
-
}
|
|
48
|
-
let appContext = getCurrentInstance()?.appContext;
|
|
49
|
-
let contextHolderProvides = null;
|
|
50
|
-
const ContextHolder = defineComponent(() => () => {
|
|
51
|
-
appContext = getCurrentInstance()?.appContext;
|
|
52
|
-
contextHolderProvides = getCurrentInstance()?.provides;
|
|
53
|
-
});
|
|
54
|
-
const portal = (props, children) => {
|
|
55
|
-
const el = document.createElement("div");
|
|
56
|
-
el.setAttribute("data-promise-portal-container", "");
|
|
57
|
-
document.body.appendChild(el);
|
|
58
|
-
let unmountDelay = options.unmountDelay ?? instance.defaultOptions.unmountDelay;
|
|
59
|
-
const setUnmountDelay = (delay) => {
|
|
60
|
-
unmountDelay = delay;
|
|
61
|
-
};
|
|
62
|
-
const show = ref(options.initialShowValue ?? instance.defaultOptions.initialShowValue ?? true);
|
|
63
|
-
let vnode;
|
|
64
|
-
const p = new Promise((resolve, reject) => {
|
|
65
|
-
vnode = createVNode(component, props, children);
|
|
66
|
-
instance.map.set(vnode, { resolve, reject, el, vnode, setUnmountDelay, show });
|
|
67
|
-
const ac = appContext ?? instance.app._context;
|
|
68
|
-
vnode.appContext = Object.create(ac, {
|
|
69
|
-
provides: {
|
|
70
|
-
value: contextHolderProvides ?? instance.provides ?? ac.provides
|
|
71
|
-
}
|
|
72
|
-
});
|
|
73
|
-
render(vnode, el);
|
|
74
|
-
});
|
|
75
|
-
p.finally(() => {
|
|
76
|
-
show.value = false;
|
|
77
|
-
setTimeout(() => {
|
|
78
|
-
render(null, el);
|
|
79
|
-
document.body.removeChild(el);
|
|
80
|
-
}, unmountDelay);
|
|
81
|
-
});
|
|
82
|
-
return p;
|
|
83
|
-
};
|
|
84
|
-
return [portal, ContextHolder];
|
|
85
|
-
};
|
|
86
|
-
var ContextProvider = defineComponent({
|
|
87
|
-
name: "PromisePortalContextProvider",
|
|
88
|
-
setup(_props, { slots }) {
|
|
89
|
-
const p = getCurrentInstance()?.provides;
|
|
90
|
-
const instance = getActiveInstance();
|
|
91
|
-
if (p && instance) {
|
|
92
|
-
instance.provides = p;
|
|
93
|
-
}
|
|
94
|
-
return () => slots.default?.();
|
|
95
|
-
}
|
|
96
|
-
});
|
|
97
|
-
|
|
98
|
-
// src/detector.ts
|
|
99
|
-
function detect(options) {
|
|
100
|
-
const {
|
|
101
|
-
style = "position:fixed;top:0;right:0;text-align:right;line-height:1.3;color:red;z-index:9999;",
|
|
102
|
-
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.`
|
|
103
|
-
} = options;
|
|
104
|
-
const containers = document.querySelectorAll("[data-promise-portal-container]");
|
|
105
|
-
const detector = document.querySelector("[data-promise-portal-detector]");
|
|
106
|
-
if (containers.length === 0) {
|
|
107
|
-
detector?.remove();
|
|
108
|
-
return;
|
|
109
|
-
}
|
|
110
|
-
if (!detector) {
|
|
111
|
-
const el = document.createElement("div");
|
|
112
|
-
el.setAttribute("data-promise-portal-detector", "");
|
|
113
|
-
el.setAttribute("style", style);
|
|
114
|
-
el.innerHTML = text;
|
|
115
|
-
document.body.appendChild(el);
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
var detectPromisePortalInstance = (options = {}) => {
|
|
119
|
-
const timer = setInterval(() => detect(options), 200);
|
|
120
|
-
return () => clearInterval(timer);
|
|
121
|
-
};
|
|
122
|
-
export {
|
|
123
|
-
ContextProvider,
|
|
124
|
-
createPromisePortal,
|
|
125
|
-
definePortal,
|
|
126
|
-
detectPromisePortalInstance,
|
|
127
|
-
getActiveInstance,
|
|
128
|
-
setActiveInstance,
|
|
129
|
-
usePortalContext,
|
|
130
|
-
version
|
|
131
|
-
};
|