| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339 |
- import { isArray } from '@vue/shared'
- import {
- type VaporComponentInstance,
- isVaporComponent,
- mountComponent,
- unmountComponent,
- } from './component'
- import { _child } from './dom/node'
- import { isComment, isHydrating } from './dom/hydration'
- import {
- MoveType,
- type TransitionHooks,
- type TransitionProps,
- type TransitionState,
- performTransitionEnter,
- performTransitionLeave,
- } from '@vue/runtime-dom'
- import {
- type DynamicFragment,
- type VaporFragment,
- isFragment,
- } from './fragment'
- import { isTeleportFragment } from './components/Teleport'
- export interface VaporTransitionHooks extends TransitionHooks {
- state: TransitionState
- props: TransitionProps
- instance: VaporComponentInstance
- // mark transition hooks as disabled
- disabled?: boolean
- // TransitionGroup sets this to handle applying hooks to list children
- applyGroup?: (block: Block, hooks: VaporTransitionHooks) => void
- }
- export interface TransitionOptions {
- $key?: any
- $transition?: VaporTransitionHooks
- }
- export type TransitionBlock = (
- | Node
- | VaporFragment
- | DynamicFragment
- | VaporComponentInstance
- ) &
- TransitionOptions
- export type Block =
- | Node
- | VaporFragment
- | DynamicFragment
- | VaporComponentInstance
- | Block[]
- export type BlockFn = (...args: any[]) => Block
- export function isBlock(val: NonNullable<unknown>): val is Block {
- return (
- val instanceof Node ||
- isArray(val) ||
- isVaporComponent(val) ||
- isFragment(val)
- )
- }
- export function isValidBlock(block: Block): boolean {
- if (block instanceof Node) {
- return !(block instanceof Comment)
- } else if (isVaporComponent(block)) {
- return isValidBlock(block.block)
- } else if (isArray(block)) {
- return block.length > 0 && block.some(isValidBlock)
- } else {
- // fragment
- return isValidBlock(block.nodes)
- }
- }
- export function insert(
- block: Block,
- parent: ParentNode & { $fc?: Node | null },
- anchor: Node | null | 0 = null, // 0 means prepend
- parentSuspense?: any, // TODO Suspense
- ): void {
- anchor = anchor === 0 ? parent.$fc || _child(parent) : anchor
- if (block instanceof Node) {
- if (!isHydrating) {
- // only apply transition on Element nodes
- if (
- block instanceof Element &&
- (block as TransitionBlock).$transition &&
- !(block as TransitionBlock).$transition!.disabled
- ) {
- performTransitionEnter(
- block,
- (block as TransitionBlock).$transition as TransitionHooks,
- () => parent.insertBefore(block, anchor as Node),
- parentSuspense,
- )
- } else {
- parent.insertBefore(block, anchor)
- }
- }
- } else if (isVaporComponent(block)) {
- if (block.isMounted && !block.isDeactivated) {
- insert(block.block!, parent, anchor)
- } else {
- mountComponent(block, parent, anchor)
- }
- } else if (isArray(block)) {
- for (const b of block) {
- insert(b, parent, anchor)
- }
- } else {
- if (block.anchor) {
- insert(block.anchor, parent, anchor)
- anchor = block.anchor
- }
- // fragment
- if (block.insert) {
- block.insert(parent, anchor, (block as TransitionBlock).$transition)
- } else {
- insert(block.nodes, parent, anchor, parentSuspense)
- }
- }
- }
- export function move(
- block: Block,
- parent: ParentNode & { $fc?: Node | null },
- anchor: Node | null | 0 = null, // 0 means prepend
- moveType: MoveType = MoveType.LEAVE,
- parentComponent?: VaporComponentInstance,
- parentSuspense?: any, // TODO Suspense
- ): void {
- anchor = anchor === 0 ? parent.$fc || _child(parent) : anchor
- if (block instanceof Node) {
- // only apply transition on Element nodes
- if (
- block instanceof Element &&
- (block as TransitionBlock).$transition &&
- !(block as TransitionBlock).$transition!.disabled &&
- moveType !== MoveType.REORDER
- ) {
- if (moveType === MoveType.ENTER) {
- performTransitionEnter(
- block,
- (block as TransitionBlock).$transition as TransitionHooks,
- () => parent.insertBefore(block, anchor as Node),
- parentSuspense,
- true,
- )
- } else {
- performTransitionLeave(
- block,
- (block as TransitionBlock).$transition as TransitionHooks,
- () => {
- // if the component is unmounted after leave finish, remove the block
- // to avoid retaining a detached node.
- if (
- moveType === MoveType.LEAVE &&
- parentComponent &&
- parentComponent.isUnmounted
- ) {
- block.remove()
- } else {
- parent.insertBefore(block, anchor as Node)
- }
- },
- parentSuspense,
- true,
- )
- }
- } else {
- parent.insertBefore(block, anchor)
- }
- } else if (isVaporComponent(block)) {
- if (block.isMounted) {
- move(
- block.block!,
- parent,
- anchor,
- moveType,
- parentComponent,
- parentSuspense,
- )
- } else {
- mountComponent(block, parent, anchor)
- }
- } else if (isArray(block)) {
- for (const b of block) {
- move(b, parent, anchor, moveType, parentComponent, parentSuspense)
- }
- } else {
- if (block.anchor) {
- move(
- block.anchor,
- parent,
- anchor,
- moveType,
- parentComponent,
- parentSuspense,
- )
- anchor = block.anchor
- }
- // fragment
- if (block.insert) {
- block.insert(parent, anchor, (block as TransitionBlock).$transition)
- } else {
- move(
- block.nodes,
- parent,
- anchor,
- moveType,
- parentComponent,
- parentSuspense,
- )
- }
- }
- }
- export function prepend(parent: ParentNode, ...blocks: Block[]): void {
- let i = blocks.length
- while (i--) insert(blocks[i], parent, 0)
- }
- export function remove(block: Block, parent?: ParentNode): void {
- if (block instanceof Node) {
- if ((block as TransitionBlock).$transition && block instanceof Element) {
- performTransitionLeave(
- block,
- (block as TransitionBlock).$transition as TransitionHooks,
- () => parent && parent.removeChild(block),
- )
- } else {
- parent && parent.removeChild(block)
- }
- } else if (isVaporComponent(block)) {
- unmountComponent(block, parent)
- } else if (isArray(block)) {
- for (let i = 0; i < block.length; i++) {
- remove(block[i], parent)
- }
- } else {
- // fragment
- if (block.remove) {
- block.remove(parent, (block as TransitionBlock).$transition)
- } else {
- remove(block.nodes, parent)
- }
- if (block.anchor) remove(block.anchor, parent)
- if ((block as DynamicFragment).scope) {
- ;(block as DynamicFragment).scope!.stop()
- }
- }
- }
- /**
- * dev / test only
- */
- export function normalizeBlock(block: Block): Node[] {
- if (!__DEV__ && !__TEST__) {
- throw new Error(
- 'normalizeBlock should not be used in production code paths',
- )
- }
- const nodes: Node[] = []
- if (block instanceof Node) {
- nodes.push(block)
- } else if (isArray(block)) {
- block.forEach(child => nodes.push(...normalizeBlock(child)))
- } else if (isVaporComponent(block)) {
- nodes.push(...normalizeBlock(block.block!))
- } else {
- if (isTeleportFragment(block)) {
- nodes.push(block.placeholder!, block.anchor!)
- } else {
- nodes.push(...normalizeBlock(block.nodes))
- block.anchor && nodes.push(block.anchor)
- }
- }
- return nodes
- }
- export function findBlockNode(block: Block): {
- parentNode: Node | null
- nextNode: Node | null
- } {
- const lastChild = findLastChild(block)!
- let { parentNode, nextSibling: nextNode } = lastChild
- // if nodes render as a fragment and the current nextNode is fragment
- // end anchor, need to move to the next node. Skip this when the block
- // already includes its own end anchor (for example VDOM Fragment ranges).
- if (
- nextNode &&
- isComment(nextNode, ']') &&
- isFragmentBlock(block) &&
- !isComment(lastChild, ']')
- ) {
- nextNode = nextNode.nextSibling
- }
- return {
- parentNode,
- nextNode,
- }
- }
- function findLastChild(node: Block): Node | undefined | null {
- if (node && node instanceof Node) {
- return node
- } else if (isArray(node)) {
- return findLastChild(node[node.length - 1])
- } else if (isVaporComponent(node)) {
- return findLastChild(node.block!)
- } else {
- if (node.anchor) return node.anchor
- return findLastChild(node.nodes!)
- }
- }
- export function isFragmentBlock(block: Block): boolean {
- if (isArray(block)) {
- return true
- } else if (isVaporComponent(block)) {
- return isFragmentBlock(block.block!)
- } else if (isFragment(block)) {
- return isFragmentBlock(block.nodes)
- }
- return false
- }
- export { setScopeId, setComponentScopeId } from './scopeId'
- export {
- registerTransitionHooks,
- applyTransitionHooks,
- applyTransitionLeaveHooks,
- } from './transition'
|