This commit is contained in:
Nadar
2026-03-17 13:24:22 +03:00
commit 82e5ac9d81
554 changed files with 29637 additions and 0 deletions

View 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>