forked from LinusBorg/portal-vue
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathportal.tsx
106 lines (100 loc) · 2.51 KB
/
portal.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
import Vue from 'vue'
import { VNode } from 'vue'
import { TransportInput, TransportVector } from '../types'
import { wormhole } from './wormhole'
let _id = 1
export default Vue.extend({
name: 'portal',
props: {
disabled: { type: Boolean },
name: { type: String, default: () => String(_id++) },
order: { type: Number, default: 0 },
slim: { type: Boolean },
slotProps: { type: Object, default: () => ({}) },
tag: { type: String, default: 'DIV' },
to: {
type: String,
default: () => String(Math.round(Math.random() * 10000000)),
},
},
created() {
this.$nextTick(() => {
wormhole.registerSource(this.name, this)
})
},
mounted() {
if (!this.disabled) {
this.sendUpdate()
}
},
updated() {
if (this.disabled) {
this.clear()
} else {
this.sendUpdate()
}
},
beforeDestroy() {
wormhole.unregisterSource(this.name)
this.clear()
},
watch: {
to(newValue: string, oldValue: string): void {
oldValue && oldValue !== newValue && this.clear(oldValue)
this.sendUpdate()
},
},
methods: {
clear(target?: string) {
const closer: TransportVector = {
from: this.name,
to: target || this.to,
}
wormhole.close(closer)
},
normalizeSlots(): Function[] | VNode[] | undefined {
return this.$scopedSlots.default
? [this.$scopedSlots.default]
: this.$slots.default
},
normalizeOwnChildren(children: VNode[] | Function): VNode[] {
return typeof children === 'function'
? children(this.slotProps)
: children
},
sendUpdate() {
const slotContent = this.normalizeSlots()
if (slotContent) {
const transport: TransportInput = {
from: this.name,
to: this.to,
passengers: [...slotContent],
order: this.order,
}
wormhole.open(transport)
} else {
this.clear()
}
},
},
render(h): VNode {
const children: VNode[] | Function =
this.$slots.default || this.$scopedSlots.default || []
const Tag = this.tag
if (children && this.disabled) {
return children.length <= 1 && this.slim ? (
this.normalizeOwnChildren(children)[0]
) : (
<Tag>{this.normalizeOwnChildren(children)}</Tag>
)
} else {
return this.slim
? h()
: h(Tag, {
class: { 'v-portal': true },
style: { display: 'none' },
key: 'v-portal-placeholder',
})
}
},
})