Also adds documentation to withVaporCtx explaining its purpose and exceptions.
import { genDirectiveModifiers, genDirectivesForElement } from './directive'
import { genBlock } from './block'
import { genModelHandler } from './vModel'
-import { isBuiltInComponent, isTransitionTag } from '../utils'
+import {
+ isBuiltInComponent,
+ isKeepAliveTag,
+ isTeleportTag,
+ isTransitionGroupTag,
+} from '../utils'
export function genCreateComponent(
operation: CreateComponentIRNode,
if (
node.type === NodeTypes.ELEMENT &&
- (!isBuiltInComponent(node.tag) || isTransitionTag(node.tag))
+ // Not a real component
+ !isTeleportTag(node.tag) &&
+ // Needs to determine whether to activate/deactivate based on instance.parent being KeepAlive
+ !isKeepAliveTag(node.tag) &&
+ // Slot updates need to trigger TransitionGroup's onBeforeUpdate/onUpdated hook
+ !isTransitionGroupTag(node.tag)
) {
// wrap with withVaporCtx to ensure correct currentInstance inside slot
blockFn = [`${context.helper('withVaporCtx')}(`, ...blockFn, `)`]
}
}
+/**
+ * Wraps a slot function to execute in the parent component's context.
+ *
+ * This ensures that:
+ * 1. Reactive effects created inside the slot (e.g., `renderEffect`) bind to the
+ * parent's instance, so the parent's lifecycle hooks fire when the slot's
+ * reactive dependencies change.
+ * 2. Elements created in the slot inherit the parent's scopeId for proper style
+ * scoping in scoped CSS.
+ *
+ * **Rationale**: Slots are defined in the parent's template, so the parent should
+ * own the rendering context and be aware of updates.
+ *
+ */
export function withVaporCtx(fn: Function): BlockFn {
const instance = currentInstance as VaporComponentInstance
return (...args: any[]) => {
let prevChildren: TransitionBlock[]
let children: TransitionBlock[]
- let slottedBlock: Block
+ const slottedBlock = slots.default && slots.default()
onBeforeUpdate(() => {
prevChildren = []
if (!prevChildren.length) {
return
}
-
const moveClass = props.moveClass || `${props.name || 'v'}-move`
const firstChild = getFirstConnectedChild(prevChildren)
if (
prevChildren = []
})
- slottedBlock = slots.default && slots.default()
-
// store props and state on fragment for reusing during insert new items
setTransitionHooksOnFragment(slottedBlock, {
props: cssTransitionProps,