| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118 |
- import type { RawSlots, Slots } from '../componentSlots'
- import {
- type ContextualRenderFn,
- currentRenderingInstance,
- } from '../componentRenderContext'
- import {
- Comment,
- Fragment,
- type VNode,
- type VNodeArrayChildren,
- createBlock,
- createVNode,
- isVNode,
- openBlock,
- } from '../vnode'
- import { PatchFlags, SlotFlags, isSymbol } from '@vue/shared'
- import { warn } from '../warning'
- import { isAsyncWrapper } from '../apiAsyncComponent'
- import type { Data } from '../component'
- /**
- * Compiler runtime helper for rendering `<slot/>`
- * @private
- */
- export function renderSlot(
- slots: Slots,
- name: string,
- props: Data = {},
- // this is not a user-facing function, so the fallback is always generated by
- // the compiler and guaranteed to be a function returning an array
- fallback?: () => VNodeArrayChildren,
- noSlotted?: boolean,
- ): VNode {
- if (
- currentRenderingInstance &&
- (currentRenderingInstance.ce ||
- (currentRenderingInstance.parent &&
- isAsyncWrapper(currentRenderingInstance.parent) &&
- currentRenderingInstance.parent.ce))
- ) {
- // in custom element mode, render <slot/> as actual slot outlets
- // wrap it with a fragment because in shadowRoot: false mode the slot
- // element gets replaced by injected content
- if (name !== 'default') props.name = name
- return (
- openBlock(),
- createBlock(
- Fragment,
- null,
- [createVNode('slot', props, fallback && fallback())],
- PatchFlags.STABLE_FRAGMENT,
- )
- )
- }
- let slot = slots[name]
- if (__DEV__ && slot && slot.length > 1) {
- warn(
- `SSR-optimized slot function detected in a non-SSR-optimized render ` +
- `function. You need to mark this component with $dynamic-slots in the ` +
- `parent template.`,
- )
- slot = () => []
- }
- // a compiled slot disables block tracking by default to avoid manual
- // invocation interfering with template-based block tracking, but in
- // `renderSlot` we can be sure that it's template-based so we can force
- // enable it.
- if (slot && (slot as ContextualRenderFn)._c) {
- ;(slot as ContextualRenderFn)._d = false
- }
- openBlock()
- const validSlotContent = slot && ensureValidVNode(slot(props))
- const slotKey =
- props.key ||
- // slot content array of a dynamic conditional slot may have a branch
- // key attached in the `createSlots` helper, respect that
- (validSlotContent && (validSlotContent as any).key)
- const rendered = createBlock(
- Fragment,
- {
- key:
- (slotKey && !isSymbol(slotKey) ? slotKey : `_${name}`) +
- // #7256 force differentiate fallback content from actual content
- (!validSlotContent && fallback ? '_fb' : ''),
- },
- validSlotContent || (fallback ? fallback() : []),
- validSlotContent && (slots as RawSlots)._ === SlotFlags.STABLE
- ? PatchFlags.STABLE_FRAGMENT
- : PatchFlags.BAIL,
- )
- if (!noSlotted && rendered.scopeId) {
- rendered.slotScopeIds = [rendered.scopeId + '-s']
- }
- if (slot && (slot as ContextualRenderFn)._c) {
- ;(slot as ContextualRenderFn)._d = true
- }
- return rendered
- }
- export function ensureValidVNode(
- vnodes: VNodeArrayChildren,
- ): VNodeArrayChildren | null {
- return vnodes.some(child => {
- if (!isVNode(child)) return true
- if (child.type === Comment) return false
- if (
- child.type === Fragment &&
- !ensureValidVNode(child.children as VNodeArrayChildren)
- )
- return false
- return true
- })
- ? vnodes
- : null
- }
|