/
Slot.ts
47 lines (39 loc) · 1.52 KB
/
Slot.ts
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
import { Comment, cloneVNode, defineComponent, mergeProps } from 'vue'
import { renderSlotFragments } from '@/shared'
export const Slot = defineComponent({
name: 'PrimitiveSlot',
inheritAttrs: false,
setup(_, { attrs, slots }) {
return () => {
if (!slots.default)
return null
const childrens = renderSlotFragments(slots.default())
const firstNonCommentChildrenIndex = childrens.findIndex(child => child.type !== Comment)
if (firstNonCommentChildrenIndex === -1)
return childrens
const firstNonCommentChildren = childrens[firstNonCommentChildrenIndex]
// remove props ref from being inferred
delete firstNonCommentChildren.props?.ref
const mergedProps = firstNonCommentChildren.props
? mergeProps(attrs, firstNonCommentChildren.props)
: attrs
// remove class to prevent duplicated
if (attrs.class && firstNonCommentChildren.props?.class)
delete firstNonCommentChildren.props.class
const cloned = cloneVNode(firstNonCommentChildren, mergedProps)
// Explicitly override props starting with `on`.
// It seems cloneVNode from Vue doesn't like overriding `onXXX` props.
// So we have to do it manually.
for (const prop in mergedProps) {
if (prop.startsWith('on')) {
cloned.props ||= {}
cloned.props[prop] = mergedProps[prop]
}
}
if (childrens.length === 1)
return cloned
childrens[firstNonCommentChildrenIndex] = cloned
return childrens
}
},
})