feat: add slot-listener for dropdown and others
This commit is contained in:
@@ -72,6 +72,7 @@ function getUtils() {
|
|||||||
return [
|
return [
|
||||||
{ text: 'Flowbite Themable', link: '/components/flowbiteThemable/flowbiteThemable.md' },
|
{ text: 'Flowbite Themable', link: '/components/flowbiteThemable/flowbiteThemable.md' },
|
||||||
{ text: 'Toast Provider', link: '/components/toastProvider/toastProvider.md' },
|
{ text: 'Toast Provider', link: '/components/toastProvider/toastProvider.md' },
|
||||||
|
{ text: 'PLAYGROUND', link: '/components/PLAYGROUND/PLAYGROUND.md' },
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
5
docs/components/PLAYGROUND/PLAYGROUND.md
Normal file
5
docs/components/PLAYGROUND/PLAYGROUND.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
<script setup>
|
||||||
|
import SlotListenerExample from './examples/SlotListenerExample.vue'
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<SlotListenerExample />
|
||||||
17
docs/components/PLAYGROUND/examples/SlotListenerExample.vue
Normal file
17
docs/components/PLAYGROUND/examples/SlotListenerExample.vue
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
<template>
|
||||||
|
<slot-listener @click="onClick" @mouseleave="onMouseleave" @mouseenter="onMouseenter">
|
||||||
|
<Button>HELLO</Button>
|
||||||
|
</slot-listener>
|
||||||
|
</template>
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { SlotListener, Button } from '../../../../src/index'
|
||||||
|
const onClick = () => {
|
||||||
|
console.log('onClick from slot-listener')
|
||||||
|
}
|
||||||
|
const onMouseenter = () => {
|
||||||
|
console.log('onMouseenter from slot-listener')
|
||||||
|
}
|
||||||
|
const onMouseleave = () => {
|
||||||
|
console.log('onMouseleave from slot-listener')
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import DropdownPlacementExample from './examples/DropdownPlacementExample.vue';
|
import DropdownPlacementExample from './examples/DropdownPlacementExample.vue';
|
||||||
import DropdownListGroupExample from './examples/DropdownListGroupExample.vue';
|
import DropdownListGroupExample from './examples/DropdownListGroupExample.vue';
|
||||||
|
import DropdownTriggerExample from './examples/DropdownTriggerExample.vue';
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
# Dropdown
|
# Dropdown
|
||||||
@@ -90,3 +91,47 @@ import { Dropdown, ListGroup, ListGroupItem } from 'flowbite-vue'
|
|||||||
```
|
```
|
||||||
|
|
||||||
<DropdownListGroupExample />
|
<DropdownListGroupExample />
|
||||||
|
|
||||||
|
## Slot - trigger
|
||||||
|
|
||||||
|
```vue
|
||||||
|
<script setup>
|
||||||
|
import { Dropdown, ListGroup, ListGroupItem } from 'flowbite-vue'
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<dropdown text="Bottom">
|
||||||
|
<template #trigger>
|
||||||
|
<span>Click trigger</span>
|
||||||
|
</template>
|
||||||
|
<list-group>
|
||||||
|
<list-group-item>
|
||||||
|
<template #prefix>
|
||||||
|
<svg class="w-4 h-4 fill-current" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-6-3a2 2 0 11-4 0 2 2 0 014 0zm-2 4a5 5 0 00-4.546 2.916A5.986 5.986 0 0010 16a5.986 5.986 0 004.546-2.084A5 5 0 0010 11z" clip-rule="evenodd"></path></svg>
|
||||||
|
</template>
|
||||||
|
Profile
|
||||||
|
</list-group-item>
|
||||||
|
<list-group-item>
|
||||||
|
<template #prefix>
|
||||||
|
<svg class="w-4 h-4 fill-current" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M5 4a1 1 0 00-2 0v7.268a2 2 0 000 3.464V16a1 1 0 102 0v-1.268a2 2 0 000-3.464V4zM11 4a1 1 0 10-2 0v1.268a2 2 0 000 3.464V16a1 1 0 102 0V8.732a2 2 0 000-3.464V4zM16 3a1 1 0 011 1v7.268a2 2 0 010 3.464V16a1 1 0 11-2 0v-1.268a2 2 0 010-3.464V4a1 1 0 011-1z"></path></svg>
|
||||||
|
</template>
|
||||||
|
Settings
|
||||||
|
</list-group-item>
|
||||||
|
<list-group-item>
|
||||||
|
<template #prefix>
|
||||||
|
<svg class="w-4 h-4 fill-current" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M5 3a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2V5a2 2 0 00-2-2H5zm0 2h10v7h-2l-1 2H8l-1-2H5V5z" clip-rule="evenodd"></path></svg>
|
||||||
|
</template>
|
||||||
|
Messages
|
||||||
|
</list-group-item>
|
||||||
|
<list-group-item>
|
||||||
|
<template #prefix>
|
||||||
|
<svg class="w-4 h-4 fill-current" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M2 9.5A3.5 3.5 0 005.5 13H9v2.586l-1.293-1.293a1 1 0 00-1.414 1.414l3 3a1 1 0 001.414 0l3-3a1 1 0 00-1.414-1.414L11 15.586V13h2.5a4.5 4.5 0 10-.616-8.958 4.002 4.002 0 10-7.753 1.977A3.5 3.5 0 002 9.5zm9 3.5H9V8a1 1 0 012 0v5z" clip-rule="evenodd"></path></svg>
|
||||||
|
</template>
|
||||||
|
Download
|
||||||
|
</list-group-item>
|
||||||
|
</list-group>
|
||||||
|
</dropdown>
|
||||||
|
</template>
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
<DropdownTriggerExample />
|
||||||
|
|||||||
38
docs/components/dropdown/examples/DropdownTriggerExample.vue
Normal file
38
docs/components/dropdown/examples/DropdownTriggerExample.vue
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
<template>
|
||||||
|
<div class="vp-raw inline-flex align-center gap-2 flex-wrap">
|
||||||
|
<dropdown text="Bottom">
|
||||||
|
<template #trigger>
|
||||||
|
<span>Click trigger</span>
|
||||||
|
</template>
|
||||||
|
<list-group>
|
||||||
|
<list-group-item>
|
||||||
|
<template #prefix>
|
||||||
|
<svg class="w-4 h-4 fill-current" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-6-3a2 2 0 11-4 0 2 2 0 014 0zm-2 4a5 5 0 00-4.546 2.916A5.986 5.986 0 0010 16a5.986 5.986 0 004.546-2.084A5 5 0 0010 11z" clip-rule="evenodd"></path></svg>
|
||||||
|
</template>
|
||||||
|
Profile
|
||||||
|
</list-group-item>
|
||||||
|
<list-group-item>
|
||||||
|
<template #prefix>
|
||||||
|
<svg class="w-4 h-4 fill-current" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M5 4a1 1 0 00-2 0v7.268a2 2 0 000 3.464V16a1 1 0 102 0v-1.268a2 2 0 000-3.464V4zM11 4a1 1 0 10-2 0v1.268a2 2 0 000 3.464V16a1 1 0 102 0V8.732a2 2 0 000-3.464V4zM16 3a1 1 0 011 1v7.268a2 2 0 010 3.464V16a1 1 0 11-2 0v-1.268a2 2 0 010-3.464V4a1 1 0 011-1z"></path></svg>
|
||||||
|
</template>
|
||||||
|
Settings
|
||||||
|
</list-group-item>
|
||||||
|
<list-group-item>
|
||||||
|
<template #prefix>
|
||||||
|
<svg class="w-4 h-4 fill-current" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M5 3a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2V5a2 2 0 00-2-2H5zm0 2h10v7h-2l-1 2H8l-1-2H5V5z" clip-rule="evenodd"></path></svg>
|
||||||
|
</template>
|
||||||
|
Messages
|
||||||
|
</list-group-item>
|
||||||
|
<list-group-item>
|
||||||
|
<template #prefix>
|
||||||
|
<svg class="w-4 h-4 fill-current" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M2 9.5A3.5 3.5 0 005.5 13H9v2.586l-1.293-1.293a1 1 0 00-1.414 1.414l3 3a1 1 0 001.414 0l3-3a1 1 0 00-1.414-1.414L11 15.586V13h2.5a4.5 4.5 0 10-.616-8.958 4.002 4.002 0 10-7.753 1.977A3.5 3.5 0 002 9.5zm9 3.5H9V8a1 1 0 012 0v5z" clip-rule="evenodd"></path></svg>
|
||||||
|
</template>
|
||||||
|
Download
|
||||||
|
</list-group-item>
|
||||||
|
</list-group>
|
||||||
|
</dropdown>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script setup>
|
||||||
|
import { Dropdown, Button, ListGroup, ListGroupItem } from '../../../../src/index'
|
||||||
|
</script>
|
||||||
6
package-lock.json
generated
6
package-lock.json
generated
@@ -343,6 +343,12 @@
|
|||||||
"integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==",
|
"integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"@types/lodash": {
|
||||||
|
"version": "4.14.182",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.182.tgz",
|
||||||
|
"integrity": "sha512-/THyiqyQAP9AfARo4pF+aCGcyiQ94tX/Is2I7HofNRqoYLgN1PBoOWu2/zTA5zMxzP5EFutMtWtGAFRKUe961Q==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"@types/node": {
|
"@types/node": {
|
||||||
"version": "18.6.2",
|
"version": "18.6.2",
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.6.2.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.6.2.tgz",
|
||||||
|
|||||||
@@ -36,6 +36,7 @@
|
|||||||
"tailwindcss": "^3"
|
"tailwindcss": "^3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@types/lodash": "^4.14.182",
|
||||||
"@types/node": "^18.0.0",
|
"@types/node": "^18.0.0",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.30.0",
|
"@typescript-eslint/eslint-plugin": "^5.30.0",
|
||||||
"@typescript-eslint/parser": "^5.30.0",
|
"@typescript-eslint/parser": "^5.30.0",
|
||||||
@@ -50,6 +51,7 @@
|
|||||||
"eslint-plugin-vue": "^9.1.1",
|
"eslint-plugin-vue": "^9.1.1",
|
||||||
"flowbite": "^1.4.2",
|
"flowbite": "^1.4.2",
|
||||||
"jsdom": "^20.0.0",
|
"jsdom": "^20.0.0",
|
||||||
|
"lodash": "^4.17.21",
|
||||||
"postcss": "^8.4.14",
|
"postcss": "^8.4.14",
|
||||||
"postcss-prefix-selector": "^1.16.0",
|
"postcss-prefix-selector": "^1.16.0",
|
||||||
"prettier": "^2.3.2",
|
"prettier": "^2.3.2",
|
||||||
|
|||||||
@@ -1,14 +1,20 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="inline-flex relative" ref="wrapper">
|
<div class="inline-flex relative" ref="wrapper">
|
||||||
<div class="inline-flex items-center">
|
<div class="inline-flex items-center">
|
||||||
<slot name="trigger" :show="onShow" :hide="onHide" :toggle="onToggle">
|
<slot-listener @click="onToggle">
|
||||||
<Button @click="onToggle">
|
<slot name="trigger">
|
||||||
|
<Button>
|
||||||
{{ text }}
|
{{ text }}
|
||||||
<template #suffix>
|
<template #suffix>
|
||||||
<svg class="w-4 h-4 ml-2" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"></path></svg>
|
<svg class="w-4 h-4 ml-2" fill="none" stroke="currentColor" viewBox="0 0 24 24"
|
||||||
|
xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"></path>
|
||||||
|
</svg>
|
||||||
</template>
|
</template>
|
||||||
</Button>
|
</Button>
|
||||||
</slot>
|
</slot>
|
||||||
|
</slot-listener>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<transition :name="transitionName">
|
<transition :name="transitionName">
|
||||||
<div ref="content" v-if="visible" :style="contentStyles" :class="[contentClasses]">
|
<div ref="content" v-if="visible" :style="contentStyles" :class="[contentClasses]">
|
||||||
@@ -24,6 +30,7 @@ import type { DropdownPlacement } from './types'
|
|||||||
import { useDropdownClasses } from './composables/useDropdownClasses'
|
import { useDropdownClasses } from './composables/useDropdownClasses'
|
||||||
import Button from '../Button/Button.vue'
|
import Button from '../Button/Button.vue'
|
||||||
import { onClickOutside } from '@vueuse/core'
|
import { onClickOutside } from '@vueuse/core'
|
||||||
|
import SlotListener from '@/components/utils/SlotListener/SlotListener.vue'
|
||||||
|
|
||||||
const visible = ref(false)
|
const visible = ref(false)
|
||||||
|
|
||||||
|
|||||||
132
src/components/utils/SlotListener/SlotListener.vue
Normal file
132
src/components/utils/SlotListener/SlotListener.vue
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { defineComponent } from 'vue'
|
||||||
|
import type { VNode, PropType } from 'vue'
|
||||||
|
import type { SlotListenerTrigger, TriggerEventHandlers } from '@/components/utils/SlotListener/types'
|
||||||
|
import { getFirstSlotVNode } from '@/utils/getFirstSlotNode'
|
||||||
|
import pick from 'lodash/pick'
|
||||||
|
|
||||||
|
// inspired from https://github.com/TuSimple/naive-ui/blob/main/src/popover/src/Popover.tsx
|
||||||
|
|
||||||
|
const triggerEventMap: Record<SlotListenerTrigger, string[]> = {
|
||||||
|
focus: ['onFocus', 'onBlur'],
|
||||||
|
click: ['onClick'],
|
||||||
|
hover: ['onMouseenter', 'onMouseleave'],
|
||||||
|
}
|
||||||
|
|
||||||
|
function appendEvents(
|
||||||
|
vNode: VNode,
|
||||||
|
events: TriggerEventHandlers,
|
||||||
|
): void {
|
||||||
|
Object.entries(triggerEventMap).forEach(([, eventNames]) => {
|
||||||
|
eventNames.forEach((eventName) => {
|
||||||
|
if (!vNode.props) vNode.props = {}
|
||||||
|
else {
|
||||||
|
vNode.props = Object.assign({}, vNode.props)
|
||||||
|
}
|
||||||
|
const originalHandler = vNode.props[eventName]
|
||||||
|
const handler = events[eventName as keyof typeof events]
|
||||||
|
if (!originalHandler) vNode.props[eventName] = handler
|
||||||
|
else {
|
||||||
|
vNode.props[eventName] = (...args: unknown[]) => {
|
||||||
|
originalHandler(...args)
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
;(handler as any)(...args)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'SlotListener',
|
||||||
|
emits: ['click', 'focus', 'blur', 'mouseenter', 'mouseleave'],
|
||||||
|
props: {
|
||||||
|
trigger: {
|
||||||
|
type: String as PropType<SlotListenerTrigger>,
|
||||||
|
default: 'click',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
setup(props, { emit }) {
|
||||||
|
const handleFocus = (e: FocusEvent) => {
|
||||||
|
emit('focus', e)
|
||||||
|
}
|
||||||
|
const handleBlur = (e: FocusEvent) => {
|
||||||
|
emit('blur', e)
|
||||||
|
}
|
||||||
|
const handleClick = (e: MouseEvent) => {
|
||||||
|
emit('click', e)
|
||||||
|
}
|
||||||
|
const handleMouseEnter = (e: MouseEvent) => {
|
||||||
|
emit('mouseenter', e)
|
||||||
|
}
|
||||||
|
const handleMouseLeave = (e: MouseEvent) => {
|
||||||
|
emit('mouseleave', e)
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
handleClick,
|
||||||
|
handleBlur,
|
||||||
|
handleFocus,
|
||||||
|
handleMouseLeave,
|
||||||
|
handleMouseEnter,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
render() {
|
||||||
|
const {
|
||||||
|
$slots,
|
||||||
|
} = this
|
||||||
|
|
||||||
|
const handlers = {
|
||||||
|
onClick: this.handleClick,
|
||||||
|
onMouseenter: this.handleMouseEnter,
|
||||||
|
onMouseleave: this.handleMouseLeave,
|
||||||
|
onFocus: this.handleFocus,
|
||||||
|
onBlur: this.handleBlur,
|
||||||
|
}
|
||||||
|
|
||||||
|
let triggerVNode = getFirstSlotVNode($slots, 'default')
|
||||||
|
|
||||||
|
const ascendantAndCurrentHandlers: TriggerEventHandlers[] = [
|
||||||
|
handlers,
|
||||||
|
]
|
||||||
|
if (triggerVNode?.props)
|
||||||
|
ascendantAndCurrentHandlers.push(pick(triggerVNode.props, 'onClick', 'onMouseenter', 'onMouseleave', 'onFocus', 'onBlur'))
|
||||||
|
|
||||||
|
const mergedHandlers: TriggerEventHandlers = {
|
||||||
|
onBlur: (e: FocusEvent) => {
|
||||||
|
ascendantAndCurrentHandlers.forEach((_handlers) => {
|
||||||
|
_handlers?.onBlur?.(e)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
onFocus: (e: FocusEvent) => {
|
||||||
|
ascendantAndCurrentHandlers.forEach((_handlers) => {
|
||||||
|
_handlers?.onFocus?.(e)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
onClick: (e: MouseEvent) => {
|
||||||
|
ascendantAndCurrentHandlers.forEach((_handlers) => {
|
||||||
|
_handlers?.onClick?.(e)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
onMouseenter: (e: MouseEvent) => {
|
||||||
|
ascendantAndCurrentHandlers.forEach((_handlers) => {
|
||||||
|
_handlers?.onMouseenter?.(e)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
onMouseleave: (e: MouseEvent) => {
|
||||||
|
ascendantAndCurrentHandlers.forEach((_handlers) => {
|
||||||
|
_handlers?.onMouseleave?.(e)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if (triggerVNode)
|
||||||
|
appendEvents(
|
||||||
|
triggerVNode,
|
||||||
|
mergedHandlers,
|
||||||
|
)
|
||||||
|
|
||||||
|
return triggerVNode
|
||||||
|
},
|
||||||
|
})
|
||||||
|
</script>
|
||||||
10
src/components/utils/SlotListener/types.ts
Normal file
10
src/components/utils/SlotListener/types.ts
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
export type SlotListenerTrigger = 'click' | 'focus' | 'hover'
|
||||||
|
|
||||||
|
|
||||||
|
export type TriggerEventHandlers = {
|
||||||
|
onClick: (e: MouseEvent) => void
|
||||||
|
onMouseenter: (e: MouseEvent) => void
|
||||||
|
onMouseleave: (e: MouseEvent) => void
|
||||||
|
onFocus: (e: FocusEvent) => void
|
||||||
|
onBlur: (e: FocusEvent) => void
|
||||||
|
}
|
||||||
@@ -31,4 +31,6 @@ export { default as Tooltip } from './components/Tooltip/Tooltip.vue'
|
|||||||
|
|
||||||
export { default as Input } from './components/Input/Input.vue'
|
export { default as Input } from './components/Input/Input.vue'
|
||||||
|
|
||||||
|
export { default as SlotListener } from './components/utils/SlotListener/SlotListener.vue'
|
||||||
|
|
||||||
export * from './composables'
|
export * from './composables'
|
||||||
|
|||||||
24
src/utils/getFirstSlotNode.ts
Normal file
24
src/utils/getFirstSlotNode.ts
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
import type { Slots, VNode } from 'vue'
|
||||||
|
import { flatten } from './flatten'
|
||||||
|
|
||||||
|
// ref: https://github.com/TuSimple/naive-ui/blob/main/src/popover/src/Popover.tsx
|
||||||
|
|
||||||
|
export function getFirstSlotVNode (
|
||||||
|
slots: Slots,
|
||||||
|
slotName = 'default',
|
||||||
|
props: unknown = undefined,
|
||||||
|
): VNode | null {
|
||||||
|
const slot = slots[slotName]
|
||||||
|
if (!slot) {
|
||||||
|
console.warn('getFirstSlotVNode', `slot[${slotName}] is empty`)
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
const slotContent = flatten(slot(props))
|
||||||
|
// vue will normalize the slot, so slot must be an array
|
||||||
|
if (slotContent.length === 1) {
|
||||||
|
return slotContent[0]
|
||||||
|
} else {
|
||||||
|
console.warn('getFirstSlotVNode', `slot[${slotName}] should have exactly one child`)
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user