initial
This commit is contained in:
69
layers/ui/components/renderless/index.vue
Normal file
69
layers/ui/components/renderless/index.vue
Normal file
@@ -0,0 +1,69 @@
|
||||
<script lang="ts">
|
||||
import {
|
||||
Comment,
|
||||
Fragment,
|
||||
Text,
|
||||
cloneVNode,
|
||||
defineComponent,
|
||||
h,
|
||||
withDirectives,
|
||||
} from 'vue'
|
||||
|
||||
// eslint-disable-next-line vue/prefer-import-from-vue
|
||||
import { isObject } from '@vue/shared'
|
||||
import type { VNode } from 'vue'
|
||||
import useClassname from '../../composables/use-classname'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'UiRenderless',
|
||||
setup(_, { slots, attrs }) {
|
||||
return () => {
|
||||
const defaultSlot = slots.default?.(attrs)
|
||||
if (!defaultSlot)
|
||||
return null
|
||||
|
||||
if (defaultSlot.length > 1)
|
||||
return null
|
||||
|
||||
const firstLegitNode = findFirstLegitChild(defaultSlot)
|
||||
if (!firstLegitNode)
|
||||
return null
|
||||
|
||||
return withDirectives(cloneVNode(firstLegitNode!, attrs, true), [])
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
function findFirstLegitChild(node: VNode[] | undefined): VNode | null {
|
||||
if (!node)
|
||||
return null
|
||||
const children = node as VNode[]
|
||||
for (const child of children) {
|
||||
/**
|
||||
* when user uses h(Fragment, [text]) to render plain string,
|
||||
* this switch case just cannot handle, when the value is primitives
|
||||
* we should just return the wrapped string
|
||||
*/
|
||||
if (isObject(child)) {
|
||||
switch (child.type) {
|
||||
case Comment:
|
||||
continue
|
||||
case Text:
|
||||
case 'svg':
|
||||
return wrapTextContent(child)
|
||||
case Fragment:
|
||||
return findFirstLegitChild(child.children as VNode[])
|
||||
default:
|
||||
return child
|
||||
}
|
||||
}
|
||||
return wrapTextContent(child)
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
function wrapTextContent(s: string | VNode) {
|
||||
const cn = useClassname('ui-renderless')
|
||||
return h('span', { class: cn.e('content') }, [s])
|
||||
}
|
||||
</script>
|
||||
Reference in New Issue
Block a user