]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
wip: save
authordaiwei <daiwei521@126.com>
Mon, 3 Mar 2025 03:44:57 +0000 (11:44 +0800)
committerdaiwei <daiwei521@126.com>
Mon, 3 Mar 2025 03:44:57 +0000 (11:44 +0800)
packages/runtime-vapor/src/block.ts
packages/runtime-vapor/src/components/Transition.ts

index e0748fe879b104b400baf8535fc12f1590cc6a09..8b62dad1308060303e7372316cfde18469d7735e 100644 (file)
@@ -25,10 +25,10 @@ export type Block = (
 export type TransitionBlock = {
   key?: any
   transition?: TransitionHooks
-  applyLeavingHooks?: (
+  applyTransitionLeavingHooks?: (
     block: Block,
     afterLeaveCb: () => void,
-  ) => TransitionHooks
+  ) => TransitionHooks | undefined
 }
 
 export type BlockFn = (...args: any[]) => Block
@@ -39,10 +39,10 @@ export class VaporFragment {
   insert?: (parent: ParentNode, anchor: Node | null) => void
   remove?: (parent?: ParentNode) => void
   transition?: TransitionHooks
-  applyLeavingHooks?: (
+  applyTransitionLeavingHooks?: (
     block: Block,
     afterLeaveCb: () => void,
-  ) => TransitionHooks
+  ) => TransitionHooks | undefined
 
   constructor(nodes: Block) {
     this.nodes = nodes
@@ -70,7 +70,7 @@ export class DynamicFragment extends VaporFragment {
     pauseTracking()
     const parent = this.anchor.parentNode
 
-    const renderNewBranch = () => {
+    const renderBranch = () => {
       if (render) {
         this.scope = new EffectScope()
         this.nodes = this.scope.run(render) || []
@@ -79,14 +79,6 @@ export class DynamicFragment extends VaporFragment {
         this.scope = undefined
         this.nodes = []
       }
-
-      if (this.fallback && !isValidBlock(this.nodes)) {
-        parent && remove(this.nodes, parent, this.transition)
-        this.nodes =
-          (this.scope || (this.scope = new EffectScope())).run(this.fallback) ||
-          []
-        parent && insert(this.nodes, parent, this.anchor, this.transition)
-      }
     }
 
     // teardown previous branch
@@ -94,7 +86,10 @@ export class DynamicFragment extends VaporFragment {
       this.scope.stop()
       const mode = this.transition && this.transition.mode
       if (mode) {
-        const transition = this.applyLeavingHooks!(this.nodes, renderNewBranch)
+        const transition = this.applyTransitionLeavingHooks!(
+          this.nodes,
+          renderBranch,
+        )
         parent && remove(this.nodes, parent, transition)
         if (mode === 'out-in') {
           resetTracking()
@@ -105,7 +100,16 @@ export class DynamicFragment extends VaporFragment {
       }
     }
 
-    renderNewBranch()
+    renderBranch()
+
+    if (this.fallback && !isValidBlock(this.nodes)) {
+      parent && remove(this.nodes, parent, this.transition)
+      this.nodes =
+        (this.scope || (this.scope = new EffectScope())).run(this.fallback) ||
+        []
+      parent && insert(this.nodes, parent, this.anchor, this.transition)
+    }
+
     resetTracking()
   }
 }
@@ -145,7 +149,8 @@ export function insert(
 ): void {
   anchor = anchor === 0 ? parent.firstChild : anchor
   if (block instanceof Node) {
-    if (transition) {
+    // don't apply transition on text or comment nodes
+    if (transition && block instanceof Element) {
       applyTransitionEnter(
         block,
         transition,
@@ -183,7 +188,7 @@ export function remove(
   transition: TransitionHooks | undefined = block.transition,
 ): void {
   if (block instanceof Node) {
-    if (transition) {
+    if (transition && block instanceof Element) {
       applyTransitionLeave(
         block,
         transition,
index b203db46698f1d2daa9a0724570ff8a05c95e047..28c6cd0a7f0ed505bec365adfbe5ebbd79b623eb 100644 (file)
@@ -11,6 +11,7 @@ import {
   leaveCbKey,
   registerVaporTransition,
   useTransitionState,
+  warn,
 } from '@vue/runtime-dom'
 import type { Block } from '../block'
 import { isVaporComponent } from '../component'
@@ -21,12 +22,10 @@ export const vaporTransitionImpl: VaporTransitionInterface = {
     slots: { default: () => Block },
   ) => {
     const children = slots.default && slots.default()
-    if (!children) {
-      return
-    }
+    if (!children) return
 
-    // TODO find non-comment node
-    const child = children
+    const child = findElementChild(children)
+    if (!child) return
 
     const state = useTransitionState()
     let enterHooks = resolveTransitionHooks(
@@ -39,12 +38,23 @@ export const vaporTransitionImpl: VaporTransitionInterface = {
     setTransitionHooks(child, enterHooks)
 
     const { mode } = props
-    // TODO check mode
+    if (
+      __DEV__ &&
+      mode &&
+      mode !== 'in-out' &&
+      mode !== 'out-in' &&
+      mode !== 'default'
+    ) {
+      warn(`invalid <transition> mode: ${mode}`)
+    }
 
-    child.applyLeavingHooks = (
-      leavingBlock: Block,
+    child.applyTransitionLeavingHooks = (
+      block: Block,
       afterLeaveCb: () => void,
     ) => {
+      const leavingBlock = findElementChild(block)
+      if (!leavingBlock) return undefined
+
       let leavingHooks = resolveTransitionHooks(
         leavingBlock as any,
         props,
@@ -87,15 +97,15 @@ export const vaporTransitionImpl: VaporTransitionInterface = {
   },
 }
 
-function resolveTransitionHooks(
+const getTransitionHooksContext = (
+  leavingNodeCache: Record<string, Block>,
+  key: string,
   block: Block,
   props: TransitionProps,
   state: TransitionState,
   instance: GenericComponentInstance,
-  postClone?: (hooks: TransitionHooks) => void,
-): TransitionHooks {
-  const key = String(block.key)
-  const leavingNodeCache = getLeavingNodesForBlock(state, block)
+  postClone: ((hooks: TransitionHooks) => void) | undefined,
+) => {
   const context: TransitionHooksContext = {
     setLeavingNodeCache: () => {
       leavingNodeCache[key] = block
@@ -124,6 +134,27 @@ function resolveTransitionHooks(
       return hooks
     },
   }
+  return context
+}
+
+function resolveTransitionHooks(
+  block: Block,
+  props: TransitionProps,
+  state: TransitionState,
+  instance: GenericComponentInstance,
+  postClone?: (hooks: TransitionHooks) => void,
+): TransitionHooks {
+  const key = String(block.key)
+  const leavingNodeCache = getLeavingNodesForBlock(state, block)
+  const context = getTransitionHooksContext(
+    leavingNodeCache,
+    key,
+    block,
+    props,
+    state,
+    instance,
+    postClone,
+  )
   return baseResolveTransitionHooks(context, props, state, instance)
 }
 
@@ -141,11 +172,47 @@ function getLeavingNodesForBlock(
 }
 
 function setTransitionHooks(block: Block, hooks: TransitionHooks) {
-  if (isVaporComponent(block)) {
-    setTransitionHooks(block.block, hooks)
+  block.transition = hooks
+}
+
+function findElementChild(block: Block): Block | undefined {
+  let child: Block | undefined
+  // transition can only be applied on Element child
+  if (block instanceof Element) {
+    child = block
+  } else if (isVaporComponent(block)) {
+    child = findElementChild(block.block)
+  } else if (Array.isArray(block)) {
+    child = block[0]
+    let hasFound = false
+    for (const c of block) {
+      const item = findElementChild(c)
+      if (item instanceof Element) {
+        if (__DEV__ && hasFound) {
+          // warn more than one non-comment child
+          warn(
+            '<transition> can only be used on a single element or component. ' +
+              'Use <transition-group> for lists.',
+          )
+          break
+        }
+        child = item
+        hasFound = true
+        if (!__DEV__) break
+      }
+    }
   } else {
-    block.transition = hooks
+    // fragment
+    // store transition hooks on fragment itself, so it can apply to both
+    // previous and new branch during updates.
+    child = block
   }
+
+  if (__DEV__ && !child) {
+    warn('Transition component has no valid child element')
+  }
+
+  return child
 }
 
 let registered = false