]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
refactor: rename `<portal>` to `<teleport>`
authorEvan You <yyx990803@gmail.com>
Tue, 31 Mar 2020 14:52:42 +0000 (10:52 -0400)
committerEvan You <yyx990803@gmail.com>
Thu, 2 Apr 2020 01:55:19 +0000 (21:55 -0400)
BREAKING CHANGE: `<portal>` has been renamed to `<teleport>`.

    `target` prop is also renmaed to `to`, so the new usage will be:

    ```html
    <Teleport to="#modal-layer" :disabled="isMobile">
      <div class="modal">
        hello
      </div>
    </Teleport>
    ```

    The primary reason for the renaming is to avoid potential naming
    conflict with [native portals](https://wicg.github.io/portals/).

26 files changed:
packages/compiler-core/__tests__/transforms/transformElement.spec.ts
packages/compiler-core/src/runtimeHelpers.ts
packages/compiler-core/src/transforms/transformElement.ts
packages/compiler-core/src/transforms/vIf.ts
packages/compiler-core/src/utils.ts
packages/compiler-ssr/__tests__/ssrPortal.spec.ts
packages/compiler-ssr/src/errors.ts
packages/compiler-ssr/src/runtimeHelpers.ts
packages/compiler-ssr/src/transforms/ssrTransformComponent.ts
packages/compiler-ssr/src/transforms/ssrTransformTeleport.ts [moved from packages/compiler-ssr/src/transforms/ssrTransformPortal.ts with 83% similarity]
packages/runtime-core/__tests__/components/Suspense.spec.ts
packages/runtime-core/__tests__/components/Teleport.spec.ts [moved from packages/runtime-core/__tests__/components/Portal.spec.ts with 68% similarity]
packages/runtime-core/__tests__/hydration.spec.ts
packages/runtime-core/src/apiOptions.ts
packages/runtime-core/src/components/Teleport.ts [moved from packages/runtime-core/src/components/Portal.ts with 73% similarity]
packages/runtime-core/src/h.ts
packages/runtime-core/src/hydration.ts
packages/runtime-core/src/index.ts
packages/runtime-core/src/renderer.ts
packages/runtime-core/src/vnode.ts
packages/server-renderer/__tests__/ssrTeleport.spec.ts [moved from packages/server-renderer/__tests__/ssrPortal.spec.ts with 51% similarity]
packages/server-renderer/src/helpers/ssrRenderTeleport.ts [moved from packages/server-renderer/src/helpers/ssrRenderPortal.ts with 54% similarity]
packages/server-renderer/src/index.ts
packages/server-renderer/src/renderToString.ts
packages/shared/src/shapeFlags.ts
packages/vue/examples/transition/modal.html

index 6434b51c81422a28fbb95af4e94396d3b3efcacf..14cbb39e0bf201bdadc9f7b703e026c22cc1576b 100644 (file)
@@ -11,7 +11,7 @@ import {
   RESOLVE_DIRECTIVE,
   TO_HANDLERS,
   helperNameMap,
-  PORTAL,
+  TELEPORT,
   RESOLVE_DYNAMIC_COMPONENT,
   SUSPENSE,
   KEEP_ALIVE,
@@ -272,16 +272,16 @@ describe('compiler: element transform', () => {
     })
   })
 
-  test('should handle <Portal> with normal children', () => {
+  test('should handle <Teleport> with normal children', () => {
     function assert(tag: string) {
       const { root, node } = parseWithElementTransform(
         `<${tag} target="#foo"><span /></${tag}>`
       )
       expect(root.components.length).toBe(0)
-      expect(root.helpers).toContain(PORTAL)
+      expect(root.helpers).toContain(TELEPORT)
 
       expect(node).toMatchObject({
-        tag: PORTAL,
+        tag: TELEPORT,
         props: createObjectMatcher({
           target: '#foo'
         }),
@@ -298,8 +298,8 @@ describe('compiler: element transform', () => {
       })
     }
 
-    assert(`portal`)
-    assert(`Portal`)
+    assert(`teleport`)
+    assert(`Teleport`)
   })
 
   test('should handle <Suspense>', () => {
index 39409a6ba51fb22af22c86610193e0cfea196147..8577622410a771527e7c71b8e4c884a6e7d311bf 100644 (file)
@@ -1,5 +1,5 @@
 export const FRAGMENT = Symbol(__DEV__ ? `Fragment` : ``)
-export const PORTAL = Symbol(__DEV__ ? `Portal` : ``)
+export const TELEPORT = Symbol(__DEV__ ? `Teleport` : ``)
 export const SUSPENSE = Symbol(__DEV__ ? `Suspense` : ``)
 export const KEEP_ALIVE = Symbol(__DEV__ ? `KeepAlive` : ``)
 export const BASE_TRANSITION = Symbol(__DEV__ ? `BaseTransition` : ``)
@@ -33,7 +33,7 @@ export const WITH_CTX = Symbol(__DEV__ ? `withCtx` : ``)
 // Using `any` here because TS doesn't allow symbols as index type.
 export const helperNameMap: any = {
   [FRAGMENT]: `Fragment`,
-  [PORTAL]: `Portal`,
+  [TELEPORT]: `Teleport`,
   [SUSPENSE]: `Suspense`,
   [KEEP_ALIVE]: `KeepAlive`,
   [BASE_TRANSITION]: `BaseTransition`,
index ad7a119c431d6619498fe087ebf392588c80ea0a..8e2a7ac64d1366391677e85db80d9d7c34a89f61 100644 (file)
@@ -28,7 +28,7 @@ import {
   RESOLVE_DYNAMIC_COMPONENT,
   MERGE_PROPS,
   TO_HANDLERS,
-  PORTAL,
+  TELEPORT,
   KEEP_ALIVE
 } from '../runtimeHelpers'
 import {
@@ -124,8 +124,8 @@ export const transformElement: NodeTransform = (node, context) => {
 
       const shouldBuildAsSlots =
         isComponent &&
-        // Portal is not a real component and has dedicated runtime handling
-        vnodeTag !== PORTAL &&
+        // Teleport is not a real component and has dedicated runtime handling
+        vnodeTag !== TELEPORT &&
         // explained above.
         vnodeTag !== KEEP_ALIVE
 
@@ -135,7 +135,7 @@ export const transformElement: NodeTransform = (node, context) => {
         if (hasDynamicSlots) {
           patchFlag |= PatchFlags.DYNAMIC_SLOTS
         }
-      } else if (node.children.length === 1 && vnodeTag !== PORTAL) {
+      } else if (node.children.length === 1 && vnodeTag !== TELEPORT) {
         const child = node.children[0]
         const type = child.type
         // check for dynamic text children
@@ -217,7 +217,7 @@ export function resolveComponentType(
     }
   }
 
-  // 2. built-in components (Portal, Transition, KeepAlive, Suspense...)
+  // 2. built-in components (Teleport, Transition, KeepAlive, Suspense...)
   const builtIn = isCoreComponent(tag) || context.isBuiltInComponent(tag)
   if (builtIn) {
     // built-ins are simply fallthroughs / have special handling during ssr
index ac60c4cd7d688de9ed1b95c4438a8fc4994a479d..6109558846f409ec9b5e2dd0cfc9457e6f8bee86 100644 (file)
@@ -27,7 +27,7 @@ import {
   FRAGMENT,
   CREATE_COMMENT,
   OPEN_BLOCK,
-  PORTAL
+  TELEPORT
 } from '../runtimeHelpers'
 import { injectProp } from '../utils'
 import { PatchFlags, PatchFlagNames } from '@vue/shared'
@@ -218,8 +218,8 @@ function createChildrenCodegenNode(
       // component vnodes are always tracked and its children are
       // compiled into slots so no need to make it a block
       ((firstChild as ElementNode).tagType !== ElementTypes.COMPONENT ||
-        // portal has component type but isn't always tracked
-        vnodeCall.tag === PORTAL)
+        // teleport has component type but isn't always tracked
+        vnodeCall.tag === TELEPORT)
     ) {
       vnodeCall.isBlock = true
       helper(OPEN_BLOCK)
index 12e16c59f7689b034d0cea5e8da90931ec75867e..3555e9a3d425e5c48b3b4af2063ceb45cd4bc5d4 100644 (file)
@@ -25,7 +25,7 @@ import {
 import { TransformContext } from './transform'
 import {
   MERGE_PROPS,
-  PORTAL,
+  TELEPORT,
   SUSPENSE,
   KEEP_ALIVE,
   BASE_TRANSITION
@@ -38,8 +38,8 @@ export const isBuiltInType = (tag: string, expected: string): boolean =>
   tag === expected || tag === hyphenate(expected)
 
 export function isCoreComponent(tag: string): symbol | void {
-  if (isBuiltInType(tag, 'Portal')) {
-    return PORTAL
+  if (isBuiltInType(tag, 'Teleport')) {
+    return TELEPORT
   } else if (isBuiltInType(tag, 'Suspense')) {
     return SUSPENSE
   } else if (isBuiltInType(tag, 'KeepAlive')) {
index 7f0f448a9b20df3406c4ca9c4ba38647f0837875..36d6138d3aa2ec875ae571f42c4954b527419219 100644 (file)
@@ -1,13 +1,13 @@
 import { compile } from '../src'
 
-describe('ssr compile: portal', () => {
+describe('ssr compile: teleport', () => {
   test('should work', () => {
-    expect(compile(`<portal :target="target"><div/></portal>`).code)
+    expect(compile(`<teleport :target="target"><div/></teleport>`).code)
       .toMatchInlineSnapshot(`
-      "const { ssrRenderPortal: _ssrRenderPortal } = require(\\"@vue/server-renderer\\")
+      "const { ssrRenderTeleport: _ssrRenderTeleport } = require(\\"@vue/server-renderer\\")
 
       return function ssrRender(_ctx, _push, _parent) {
-        _ssrRenderPortal(_push, (_push) => {
+        _ssrRenderTeleport(_push, (_push) => {
           _push(\`<div></div>\`)
         }, _ctx.target, false, _parent)
       }"
@@ -15,24 +15,26 @@ describe('ssr compile: portal', () => {
   })
 
   test('disabled prop handling', () => {
-    expect(compile(`<portal :target="target" disabled><div/></portal>`).code)
-      .toMatchInlineSnapshot(`
-    "const { ssrRenderPortal: _ssrRenderPortal } = require(\\"@vue/server-renderer\\")
+    expect(
+      compile(`<teleport :target="target" disabled><div/></teleport>`).code
+    ).toMatchInlineSnapshot(`
+    "const { ssrRenderTeleport: _ssrRenderTeleport } = require(\\"@vue/server-renderer\\")
 
     return function ssrRender(_ctx, _push, _parent) {
-      _ssrRenderPortal(_push, (_push) => {
+      _ssrRenderTeleport(_push, (_push) => {
         _push(\`<div></div>\`)
       }, _ctx.target, true, _parent)
     }"
   `)
 
     expect(
-      compile(`<portal :target="target" :disabled="foo"><div/></portal>`).code
+      compile(`<teleport :target="target" :disabled="foo"><div/></teleport>`)
+        .code
     ).toMatchInlineSnapshot(`
-    "const { ssrRenderPortal: _ssrRenderPortal } = require(\\"@vue/server-renderer\\")
+    "const { ssrRenderTeleport: _ssrRenderTeleport } = require(\\"@vue/server-renderer\\")
 
     return function ssrRender(_ctx, _push, _parent) {
-      _ssrRenderPortal(_push, (_push) => {
+      _ssrRenderTeleport(_push, (_push) => {
         _push(\`<div></div>\`)
       }, _ctx.target, _ctx.foo, _parent)
     }"
index fdc99160b01d240067cdeda9539d143eda69b131..282c918f92629a9a728c5acc38189b3d155c8f06 100644 (file)
@@ -19,11 +19,11 @@ export function createSSRCompilerError(
 export const enum SSRErrorCodes {
   X_SSR_CUSTOM_DIRECTIVE_NO_TRANSFORM = DOMErrorCodes.__EXTEND_POINT__,
   X_SSR_UNSAFE_ATTR_NAME,
-  X_SSR_NO_PORTAL_TARGET
+  X_SSR_NO_TELEPORT_TARGET
 }
 
 export const SSRErrorMessages: { [code: number]: string } = {
   [SSRErrorCodes.X_SSR_CUSTOM_DIRECTIVE_NO_TRANSFORM]: `Custom directive is missing corresponding SSR transform and will be ignored.`,
   [SSRErrorCodes.X_SSR_UNSAFE_ATTR_NAME]: `Unsafe attribute name for SSR.`,
-  [SSRErrorCodes.X_SSR_NO_PORTAL_TARGET]: `No target prop on portal element.`
+  [SSRErrorCodes.X_SSR_NO_TELEPORT_TARGET]: `No target prop on teleport element.`
 }
index bfd8370891aca9da80809264ff1c7d59b00290c3..c2732d19e43884ac00d68962520cea7410615599 100644 (file)
@@ -13,7 +13,7 @@ export const SSR_LOOSE_EQUAL = Symbol(`ssrLooseEqual`)
 export const SSR_LOOSE_CONTAIN = Symbol(`ssrLooseContain`)
 export const SSR_RENDER_DYNAMIC_MODEL = Symbol(`ssrRenderDynamicModel`)
 export const SSR_GET_DYNAMIC_MODEL_PROPS = Symbol(`ssrGetDynamicModelProps`)
-export const SSR_RENDER_PORTAL = Symbol(`ssrRenderPortal`)
+export const SSR_RENDER_TELEPORT = Symbol(`ssrRenderTeleport`)
 export const SSR_RENDER_SUSPENSE = Symbol(`ssrRenderSuspense`)
 
 export const ssrHelpers = {
@@ -30,7 +30,7 @@ export const ssrHelpers = {
   [SSR_LOOSE_CONTAIN]: `ssrLooseContain`,
   [SSR_RENDER_DYNAMIC_MODEL]: `ssrRenderDynamicModel`,
   [SSR_GET_DYNAMIC_MODEL_PROPS]: `ssrGetDynamicModelProps`,
-  [SSR_RENDER_PORTAL]: `ssrRenderPortal`,
+  [SSR_RENDER_TELEPORT]: `ssrRenderTeleport`,
   [SSR_RENDER_SUSPENSE]: `ssrRenderSuspense`
 }
 
index ff4ea8fa9a2fa64aa97fea31522b8a957ab2775f..95eace9ad507faf65633fac19a211f56cfda16a4 100644 (file)
@@ -11,7 +11,7 @@ import {
   buildSlots,
   FunctionExpression,
   TemplateChildNode,
-  PORTAL,
+  TELEPORT,
   createIfStatement,
   createSimpleExpression,
   getBaseTransformPreset,
@@ -39,7 +39,7 @@ import {
   processChildren,
   processChildrenAsStatement
 } from '../ssrCodegenTransform'
-import { ssrProcessPortal } from './ssrTransformPortal'
+import { ssrProcessTeleport } from './ssrTransformTeleport'
 import {
   ssrProcessSuspense,
   ssrTransformSuspense
@@ -146,8 +146,8 @@ export function ssrProcessComponent(
   if (!node.ssrCodegenNode) {
     // this is a built-in component that fell-through.
     const component = componentTypeMap.get(node)!
-    if (component === PORTAL) {
-      return ssrProcessPortal(node, context)
+    if (component === TELEPORT) {
+      return ssrProcessTeleport(node, context)
     } else if (component === SUSPENSE) {
       return ssrProcessSuspense(node, context)
     } else {
similarity index 83%
rename from packages/compiler-ssr/src/transforms/ssrTransformPortal.ts
rename to packages/compiler-ssr/src/transforms/ssrTransformTeleport.ts
index e67a585218490be5d5e6929fa646c30e4c3d7560..5a39688db240814ea8363f6c2c5c08e68d16791c 100644 (file)
@@ -12,17 +12,17 @@ import {
   processChildrenAsStatement
 } from '../ssrCodegenTransform'
 import { createSSRCompilerError, SSRErrorCodes } from '../errors'
-import { SSR_RENDER_PORTAL } from '../runtimeHelpers'
+import { SSR_RENDER_TELEPORT } from '../runtimeHelpers'
 
 // Note: this is a 2nd-pass codegen transform.
-export function ssrProcessPortal(
+export function ssrProcessTeleport(
   node: ComponentNode,
   context: SSRTransformContext
 ) {
   const targetProp = findProp(node, 'target')
   if (!targetProp) {
     context.onError(
-      createSSRCompilerError(SSRErrorCodes.X_SSR_NO_PORTAL_TARGET, node.loc)
+      createSSRCompilerError(SSRErrorCodes.X_SSR_NO_TELEPORT_TARGET, node.loc)
     )
     return
   }
@@ -37,7 +37,7 @@ export function ssrProcessPortal(
   if (!target) {
     context.onError(
       createSSRCompilerError(
-        SSRErrorCodes.X_SSR_NO_PORTAL_TARGET,
+        SSRErrorCodes.X_SSR_NO_TELEPORT_TARGET,
         targetProp.loc
       )
     )
@@ -60,7 +60,7 @@ export function ssrProcessPortal(
   )
   contentRenderFn.body = processChildrenAsStatement(node.children, context)
   context.pushStatement(
-    createCallExpression(context.helper(SSR_RENDER_PORTAL), [
+    createCallExpression(context.helper(SSR_RENDER_TELEPORT), [
       `_push`,
       contentRenderFn,
       target,
index 994bd71a3414793fe4bab4ba4fe97fd928797221..4738c80ef7840f2ba9bf4a1bb59b7dda012eb6a5 100644 (file)
@@ -731,5 +731,5 @@ describe('Suspense', () => {
     expect(serializeInner(root)).toBe(`<div>Child A</div><div>Child B</div>`)
   })
 
-  test.todo('portal inside suspense')
+  test.todo('teleport inside suspense')
 })
similarity index 68%
rename from packages/runtime-core/__tests__/components/Portal.spec.ts
rename to packages/runtime-core/__tests__/components/Teleport.spec.ts
index 651c87396bec96ed9cb8fa871192f323050f35be..99bea073072da0ccc52bd94a6c623acf64511388 100644 (file)
@@ -3,28 +3,28 @@ import {
   serializeInner,
   render,
   h,
-  Portal,
+  Teleport,
   Text,
   ref,
   nextTick
 } from '@vue/runtime-test'
 import { createVNode, Fragment } from '../../src/vnode'
 
-describe('renderer: portal', () => {
+describe('renderer: teleport', () => {
   test('should work', () => {
     const target = nodeOps.createElement('div')
     const root = nodeOps.createElement('div')
 
     render(
       h(() => [
-        h(Portal, { target }, h('div', 'teleported')),
+        h(Teleport, { to: target }, h('div', 'teleported')),
         h('div', 'root')
       ]),
       root
     )
 
     expect(serializeInner(root)).toMatchInlineSnapshot(
-      `"<!--portal start--><!--portal end--><div>root</div>"`
+      `"<!--teleport start--><!--teleport end--><div>root</div>"`
     )
     expect(serializeInner(target)).toMatchInlineSnapshot(
       `"<div>teleported</div>"`
@@ -39,14 +39,14 @@ describe('renderer: portal', () => {
 
     render(
       h(() => [
-        h(Portal, { target: target.value }, h('div', 'teleported')),
+        h(Teleport, { to: target.value }, h('div', 'teleported')),
         h('div', 'root')
       ]),
       root
     )
 
     expect(serializeInner(root)).toMatchInlineSnapshot(
-      `"<!--portal start--><!--portal end--><div>root</div>"`
+      `"<!--teleport start--><!--teleport end--><div>root</div>"`
     )
     expect(serializeInner(targetA)).toMatchInlineSnapshot(
       `"<div>teleported</div>"`
@@ -57,7 +57,7 @@ describe('renderer: portal', () => {
     await nextTick()
 
     expect(serializeInner(root)).toMatchInlineSnapshot(
-      `"<!--portal start--><!--portal end--><div>root</div>"`
+      `"<!--teleport start--><!--teleport end--><div>root</div>"`
     )
     expect(serializeInner(targetA)).toMatchInlineSnapshot(`""`)
     expect(serializeInner(targetB)).toMatchInlineSnapshot(
@@ -70,7 +70,7 @@ describe('renderer: portal', () => {
     const root = nodeOps.createElement('div')
     const children = ref([h('div', 'teleported')])
 
-    render(h(Portal, { target }, children.value), root)
+    render(h(Teleport, { to: target }, children.value), root)
     expect(serializeInner(target)).toMatchInlineSnapshot(
       `"<div>teleported</div>"`
     )
@@ -96,7 +96,7 @@ describe('renderer: portal', () => {
 
     render(
       h(() => [
-        h(Portal, { target }, h('div', 'teleported')),
+        h(Teleport, { to: target }, h('div', 'teleported')),
         h('div', 'root')
       ]),
       root
@@ -109,28 +109,28 @@ describe('renderer: portal', () => {
     expect(serializeInner(target)).toBe('')
   })
 
-  test('multiple portal with same target', () => {
+  test('multiple teleport with same target', () => {
     const target = nodeOps.createElement('div')
     const root = nodeOps.createElement('div')
 
     render(
       h('div', [
-        h(Portal, { target }, h('div', 'one')),
-        h(Portal, { target }, 'two')
+        h(Teleport, { to: target }, h('div', 'one')),
+        h(Teleport, { to: target }, 'two')
       ]),
       root
     )
 
     expect(serializeInner(root)).toMatchInlineSnapshot(
-      `"<div><!--portal start--><!--portal end--><!--portal start--><!--portal end--></div>"`
+      `"<div><!--teleport start--><!--teleport end--><!--teleport start--><!--teleport end--></div>"`
     )
     expect(serializeInner(target)).toMatchInlineSnapshot(`"<div>one</div>two"`)
 
     // update existing content
     render(
       h('div', [
-        h(Portal, { target }, [h('div', 'one'), h('div', 'two')]),
-        h(Portal, { target }, 'three')
+        h(Teleport, { to: target }, [h('div', 'one'), h('div', 'two')]),
+        h(Teleport, { to: target }, 'three')
       ]),
       root
     )
@@ -139,38 +139,38 @@ describe('renderer: portal', () => {
     )
 
     // toggling
-    render(h('div', [null, h(Portal, { target }, 'three')]), root)
+    render(h('div', [null, h(Teleport, { to: target }, 'three')]), root)
     expect(serializeInner(root)).toMatchInlineSnapshot(
-      `"<div><!----><!--portal start--><!--portal end--></div>"`
+      `"<div><!----><!--teleport start--><!--teleport end--></div>"`
     )
     expect(serializeInner(target)).toMatchInlineSnapshot(`"three"`)
 
     // toggle back
     render(
       h('div', [
-        h(Portal, { target }, [h('div', 'one'), h('div', 'two')]),
-        h(Portal, { target }, 'three')
+        h(Teleport, { to: target }, [h('div', 'one'), h('div', 'two')]),
+        h(Teleport, { to: target }, 'three')
       ]),
       root
     )
     expect(serializeInner(root)).toMatchInlineSnapshot(
-      `"<div><!--portal start--><!--portal end--><!--portal start--><!--portal end--></div>"`
+      `"<div><!--teleport start--><!--teleport end--><!--teleport start--><!--teleport end--></div>"`
     )
     // should append
     expect(serializeInner(target)).toMatchInlineSnapshot(
       `"three<div>one</div><div>two</div>"`
     )
 
-    // toggle the other portal
+    // toggle the other teleport
     render(
       h('div', [
-        h(Portal, { target }, [h('div', 'one'), h('div', 'two')]),
+        h(Teleport, { to: target }, [h('div', 'one'), h('div', 'two')]),
         null
       ]),
       root
     )
     expect(serializeInner(root)).toMatchInlineSnapshot(
-      `"<div><!--portal start--><!--portal end--><!----></div>"`
+      `"<div><!--teleport start--><!--teleport end--><!----></div>"`
     )
     expect(serializeInner(target)).toMatchInlineSnapshot(
       `"<div>one</div><div>two</div>"`
@@ -183,14 +183,14 @@ describe('renderer: portal', () => {
 
     const renderWithDisabled = (disabled: boolean) => {
       return h(Fragment, [
-        h(Portal, { target, disabled }, h('div', 'teleported')),
+        h(Teleport, { to: target, disabled }, h('div', 'teleported')),
         h('div', 'root')
       ])
     }
 
     render(renderWithDisabled(false), root)
     expect(serializeInner(root)).toMatchInlineSnapshot(
-      `"<!--portal start--><!--portal end--><div>root</div>"`
+      `"<!--teleport start--><!--teleport end--><div>root</div>"`
     )
     expect(serializeInner(target)).toMatchInlineSnapshot(
       `"<div>teleported</div>"`
@@ -198,33 +198,33 @@ describe('renderer: portal', () => {
 
     render(renderWithDisabled(true), root)
     expect(serializeInner(root)).toMatchInlineSnapshot(
-      `"<!--portal start--><div>teleported</div><!--portal end--><div>root</div>"`
+      `"<!--teleport start--><div>teleported</div><!--teleport end--><div>root</div>"`
     )
     expect(serializeInner(target)).toBe(``)
 
     // toggle back
     render(renderWithDisabled(false), root)
     expect(serializeInner(root)).toMatchInlineSnapshot(
-      `"<!--portal start--><!--portal end--><div>root</div>"`
+      `"<!--teleport start--><!--teleport end--><div>root</div>"`
     )
     expect(serializeInner(target)).toMatchInlineSnapshot(
       `"<div>teleported</div>"`
     )
   })
 
-  test('moving portal while enabled', () => {
+  test('moving teleport while enabled', () => {
     const target = nodeOps.createElement('div')
     const root = nodeOps.createElement('div')
 
     render(
       h(Fragment, [
-        h(Portal, { target }, h('div', 'teleported')),
+        h(Teleport, { to: target }, h('div', 'teleported')),
         h('div', 'root')
       ]),
       root
     )
     expect(serializeInner(root)).toMatchInlineSnapshot(
-      `"<!--portal start--><!--portal end--><div>root</div>"`
+      `"<!--teleport start--><!--teleport end--><div>root</div>"`
     )
     expect(serializeInner(target)).toMatchInlineSnapshot(
       `"<div>teleported</div>"`
@@ -233,12 +233,12 @@ describe('renderer: portal', () => {
     render(
       h(Fragment, [
         h('div', 'root'),
-        h(Portal, { target }, h('div', 'teleported'))
+        h(Teleport, { to: target }, h('div', 'teleported'))
       ]),
       root
     )
     expect(serializeInner(root)).toMatchInlineSnapshot(
-      `"<div>root</div><!--portal start--><!--portal end-->"`
+      `"<div>root</div><!--teleport start--><!--teleport end-->"`
     )
     expect(serializeInner(target)).toMatchInlineSnapshot(
       `"<div>teleported</div>"`
@@ -246,56 +246,56 @@ describe('renderer: portal', () => {
 
     render(
       h(Fragment, [
-        h(Portal, { target }, h('div', 'teleported')),
+        h(Teleport, { to: target }, h('div', 'teleported')),
         h('div', 'root')
       ]),
       root
     )
     expect(serializeInner(root)).toMatchInlineSnapshot(
-      `"<!--portal start--><!--portal end--><div>root</div>"`
+      `"<!--teleport start--><!--teleport end--><div>root</div>"`
     )
     expect(serializeInner(target)).toMatchInlineSnapshot(
       `"<div>teleported</div>"`
     )
   })
 
-  test('moving portal while disabled', () => {
+  test('moving teleport while disabled', () => {
     const target = nodeOps.createElement('div')
     const root = nodeOps.createElement('div')
 
     render(
       h(Fragment, [
-        h(Portal, { target, disabled: true }, h('div', 'teleported')),
+        h(Teleport, { to: target, disabled: true }, h('div', 'teleported')),
         h('div', 'root')
       ]),
       root
     )
     expect(serializeInner(root)).toMatchInlineSnapshot(
-      `"<!--portal start--><div>teleported</div><!--portal end--><div>root</div>"`
+      `"<!--teleport start--><div>teleported</div><!--teleport end--><div>root</div>"`
     )
     expect(serializeInner(target)).toBe('')
 
     render(
       h(Fragment, [
         h('div', 'root'),
-        h(Portal, { target, disabled: true }, h('div', 'teleported'))
+        h(Teleport, { to: target, disabled: true }, h('div', 'teleported'))
       ]),
       root
     )
     expect(serializeInner(root)).toMatchInlineSnapshot(
-      `"<div>root</div><!--portal start--><div>teleported</div><!--portal end-->"`
+      `"<div>root</div><!--teleport start--><div>teleported</div><!--teleport end-->"`
     )
     expect(serializeInner(target)).toBe('')
 
     render(
       h(Fragment, [
-        h(Portal, { target, disabled: true }, h('div', 'teleported')),
+        h(Teleport, { to: target, disabled: true }, h('div', 'teleported')),
         h('div', 'root')
       ]),
       root
     )
     expect(serializeInner(root)).toMatchInlineSnapshot(
-      `"<!--portal start--><div>teleported</div><!--portal end--><div>root</div>"`
+      `"<!--teleport start--><div>teleported</div><!--teleport end--><div>root</div>"`
     )
     expect(serializeInner(target)).toBe('')
   })
index 510c14e02c6306e8a986d6a3cb28695cf7e65c2d..837be3ee541084d4af79386a922444716bd80bd7 100644 (file)
@@ -4,7 +4,7 @@ import {
   ref,
   nextTick,
   VNode,
-  Portal,
+  Teleport,
   createStaticVNode,
   Suspense,
   onMounted,
@@ -153,18 +153,18 @@ describe('SSR hydration', () => {
     )
   })
 
-  test('Portal', async () => {
+  test('Teleport', async () => {
     const msg = ref('foo')
     const fn = jest.fn()
-    const portalContainer = document.createElement('div')
-    portalContainer.id = 'portal'
-    portalContainer.innerHTML = `<span>foo</span><span class="foo"></span><!---->`
-    document.body.appendChild(portalContainer)
+    const teleportContainer = document.createElement('div')
+    teleportContainer.id = 'teleport'
+    teleportContainer.innerHTML = `<span>foo</span><span class="foo"></span><!---->`
+    document.body.appendChild(teleportContainer)
 
     const { vnode, container } = mountWithHydration(
-      '<!--portal start--><!--portal end-->',
+      '<!--teleport start--><!--teleport end-->',
       () =>
-        h(Portal, { target: '#portal' }, [
+        h(Teleport, { to: '#teleport' }, [
           h('span', msg.value),
           h('span', { class: msg.value, onClick: fn })
         ])
@@ -173,120 +173,120 @@ describe('SSR hydration', () => {
     expect(vnode.el).toBe(container.firstChild)
     expect(vnode.anchor).toBe(container.lastChild)
 
-    expect(vnode.target).toBe(portalContainer)
+    expect(vnode.target).toBe(teleportContainer)
     expect((vnode.children as VNode[])[0].el).toBe(
-      portalContainer.childNodes[0]
+      teleportContainer.childNodes[0]
     )
     expect((vnode.children as VNode[])[1].el).toBe(
-      portalContainer.childNodes[1]
+      teleportContainer.childNodes[1]
     )
-    expect(vnode.targetAnchor).toBe(portalContainer.childNodes[2])
+    expect(vnode.targetAnchor).toBe(teleportContainer.childNodes[2])
 
     // event handler
-    triggerEvent('click', portalContainer.querySelector('.foo')!)
+    triggerEvent('click', teleportContainer.querySelector('.foo')!)
     expect(fn).toHaveBeenCalled()
 
     msg.value = 'bar'
     await nextTick()
-    expect(portalContainer.innerHTML).toBe(
+    expect(teleportContainer.innerHTML).toBe(
       `<span>bar</span><span class="bar"></span><!---->`
     )
   })
 
-  test('Portal (multiple + integration)', async () => {
+  test('Teleport (multiple + integration)', async () => {
     const msg = ref('foo')
     const fn1 = jest.fn()
     const fn2 = jest.fn()
 
     const Comp = () => [
-      h(Portal, { target: '#portal2' }, [
+      h(Teleport, { to: '#teleport2' }, [
         h('span', msg.value),
         h('span', { class: msg.value, onClick: fn1 })
       ]),
-      h(Portal, { target: '#portal2' }, [
+      h(Teleport, { to: '#teleport2' }, [
         h('span', msg.value + '2'),
         h('span', { class: msg.value + '2', onClick: fn2 })
       ])
     ]
 
-    const portalContainer = document.createElement('div')
-    portalContainer.id = 'portal2'
+    const teleportContainer = document.createElement('div')
+    teleportContainer.id = 'teleport2'
     const ctx: SSRContext = {}
     const mainHtml = await renderToString(h(Comp), ctx)
     expect(mainHtml).toMatchInlineSnapshot(
-      `"<!--[--><!--portal start--><!--portal end--><!--portal start--><!--portal end--><!--]-->"`
+      `"<!--[--><!--teleport start--><!--teleport end--><!--teleport start--><!--teleport end--><!--]-->"`
     )
 
-    const portalHtml = ctx.portals!['#portal2']
-    expect(portalHtml).toMatchInlineSnapshot(
+    const teleportHtml = ctx.teleports!['#teleport2']
+    expect(teleportHtml).toMatchInlineSnapshot(
       `"<span>foo</span><span class=\\"foo\\"></span><!----><span>foo2</span><span class=\\"foo2\\"></span><!---->"`
     )
 
-    portalContainer.innerHTML = portalHtml
-    document.body.appendChild(portalContainer)
+    teleportContainer.innerHTML = teleportHtml
+    document.body.appendChild(teleportContainer)
 
     const { vnode, container } = mountWithHydration(mainHtml, Comp)
     expect(vnode.el).toBe(container.firstChild)
-    const portalVnode1 = (vnode.children as VNode[])[0]
-    const portalVnode2 = (vnode.children as VNode[])[1]
-    expect(portalVnode1.el).toBe(container.childNodes[1])
-    expect(portalVnode1.anchor).toBe(container.childNodes[2])
-    expect(portalVnode2.el).toBe(container.childNodes[3])
-    expect(portalVnode2.anchor).toBe(container.childNodes[4])
-
-    expect(portalVnode1.target).toBe(portalContainer)
-    expect((portalVnode1 as any).children[0].el).toBe(
-      portalContainer.childNodes[0]
+    const teleportVnode1 = (vnode.children as VNode[])[0]
+    const teleportVnode2 = (vnode.children as VNode[])[1]
+    expect(teleportVnode1.el).toBe(container.childNodes[1])
+    expect(teleportVnode1.anchor).toBe(container.childNodes[2])
+    expect(teleportVnode2.el).toBe(container.childNodes[3])
+    expect(teleportVnode2.anchor).toBe(container.childNodes[4])
+
+    expect(teleportVnode1.target).toBe(teleportContainer)
+    expect((teleportVnode1 as any).children[0].el).toBe(
+      teleportContainer.childNodes[0]
     )
-    expect(portalVnode1.targetAnchor).toBe(portalContainer.childNodes[2])
+    expect(teleportVnode1.targetAnchor).toBe(teleportContainer.childNodes[2])
 
-    expect(portalVnode2.target).toBe(portalContainer)
-    expect((portalVnode2 as any).children[0].el).toBe(
-      portalContainer.childNodes[3]
+    expect(teleportVnode2.target).toBe(teleportContainer)
+    expect((teleportVnode2 as any).children[0].el).toBe(
+      teleportContainer.childNodes[3]
     )
-    expect(portalVnode2.targetAnchor).toBe(portalContainer.childNodes[5])
+    expect(teleportVnode2.targetAnchor).toBe(teleportContainer.childNodes[5])
 
     // // event handler
-    triggerEvent('click', portalContainer.querySelector('.foo')!)
+    triggerEvent('click', teleportContainer.querySelector('.foo')!)
     expect(fn1).toHaveBeenCalled()
 
-    triggerEvent('click', portalContainer.querySelector('.foo2')!)
+    triggerEvent('click', teleportContainer.querySelector('.foo2')!)
     expect(fn2).toHaveBeenCalled()
 
     msg.value = 'bar'
     await nextTick()
-    expect(portalContainer.innerHTML).toMatchInlineSnapshot(
+    expect(teleportContainer.innerHTML).toMatchInlineSnapshot(
       `"<span>bar</span><span class=\\"bar\\"></span><!----><span>bar2</span><span class=\\"bar2\\"></span><!---->"`
     )
   })
 
-  test('Portal (disabled)', async () => {
+  test('Teleport (disabled)', async () => {
     const msg = ref('foo')
     const fn1 = jest.fn()
     const fn2 = jest.fn()
 
     const Comp = () => [
       h('div', 'foo'),
-      h(Portal, { target: '#portal3', disabled: true }, [
+      h(Teleport, { to: '#teleport3', disabled: true }, [
         h('span', msg.value),
         h('span', { class: msg.value, onClick: fn1 })
       ]),
       h('div', { class: msg.value + '2', onClick: fn2 }, 'bar')
     ]
 
-    const portalContainer = document.createElement('div')
-    portalContainer.id = 'portal3'
+    const teleportContainer = document.createElement('div')
+    teleportContainer.id = 'teleport3'
     const ctx: SSRContext = {}
     const mainHtml = await renderToString(h(Comp), ctx)
     expect(mainHtml).toMatchInlineSnapshot(
-      `"<!--[--><div>foo</div><!--portal start--><span>foo</span><span class=\\"foo\\"></span><!--portal end--><div class=\\"foo2\\">bar</div><!--]-->"`
+      `"<!--[--><div>foo</div><!--teleport start--><span>foo</span><span class=\\"foo\\"></span><!--teleport end--><div class=\\"foo2\\">bar</div><!--]-->"`
     )
 
-    const portalHtml = ctx.portals!['#portal3']
-    expect(portalHtml).toMatchInlineSnapshot(`"<!---->"`)
+    const teleportHtml = ctx.teleports!['#teleport3']
+    expect(teleportHtml).toMatchInlineSnapshot(`"<!---->"`)
 
-    portalContainer.innerHTML = portalHtml
-    document.body.appendChild(portalContainer)
+    teleportContainer.innerHTML = teleportHtml
+    document.body.appendChild(teleportContainer)
 
     const { vnode, container } = mountWithHydration(mainHtml, Comp)
     expect(vnode.el).toBe(container.firstChild)
@@ -294,19 +294,19 @@ describe('SSR hydration', () => {
 
     expect(children[0].el).toBe(container.childNodes[1])
 
-    const portalVnode = children[1]
-    expect(portalVnode.el).toBe(container.childNodes[2])
-    expect((portalVnode.children as VNode[])[0].el).toBe(
+    const teleportVnode = children[1]
+    expect(teleportVnode.el).toBe(container.childNodes[2])
+    expect((teleportVnode.children as VNode[])[0].el).toBe(
       container.childNodes[3]
     )
-    expect((portalVnode.children as VNode[])[1].el).toBe(
+    expect((teleportVnode.children as VNode[])[1].el).toBe(
       container.childNodes[4]
     )
-    expect(portalVnode.anchor).toBe(container.childNodes[5])
+    expect(teleportVnode.anchor).toBe(container.childNodes[5])
     expect(children[2].el).toBe(container.childNodes[6])
 
-    expect(portalVnode.target).toBe(portalContainer)
-    expect(portalVnode.targetAnchor).toBe(portalContainer.childNodes[0])
+    expect(teleportVnode.target).toBe(teleportContainer)
+    expect(teleportVnode.targetAnchor).toBe(teleportContainer.childNodes[0])
 
     // // event handler
     triggerEvent('click', container.querySelector('.foo')!)
@@ -318,7 +318,7 @@ describe('SSR hydration', () => {
     msg.value = 'bar'
     await nextTick()
     expect(container.innerHTML).toMatchInlineSnapshot(
-      `"<!--[--><div>foo</div><!--portal start--><span>bar</span><span class=\\"bar\\"></span><!--portal end--><div class=\\"bar2\\">bar</div><!--]-->"`
+      `"<!--[--><div>foo</div><!--teleport start--><span>bar</span><span class=\\"bar\\"></span><!--teleport end--><div class=\\"bar2\\">bar</div><!--]-->"`
     )
   })
 
index 8db8b20d027e8ea69bfc1704890b85ad5af14cae..0ed0e5c2dab5a4dd1dcb0098c3a5870e9046696b 100644 (file)
@@ -88,7 +88,7 @@ export interface ComponentOptionsBase<
   call?: never
   // type-only differentiators for built-in Vnode types
   __isFragment?: never
-  __isPortal?: never
+  __isTeleport?: never
   __isSuspense?: never
 }
 
similarity index 73%
rename from packages/runtime-core/src/components/Portal.ts
rename to packages/runtime-core/src/components/Teleport.ts
index 9a4241a3ce87a58e7dd51f6ce25ab94e0e32eec8..8091f014408bc395f9f254cde56f9ed5b924297b 100644 (file)
@@ -11,26 +11,26 @@ import { VNode, VNodeArrayChildren, VNodeProps } from '../vnode'
 import { isString, ShapeFlags } from '@vue/shared'
 import { warn } from '../warning'
 
-export interface PortalProps {
-  target: string | RendererElement
+export interface TeleportProps {
+  to: string | RendererElement
   disabled?: boolean
 }
 
-export const isPortal = (type: any): boolean => type.__isPortal
+export const isTeleport = (type: any): boolean => type.__isTeleport
 
-const isPortalDisabled = (props: VNode['props']): boolean =>
+const isTeleportDisabled = (props: VNode['props']): boolean =>
   props && (props.disabled || props.disabled === '')
 
 const resolveTarget = <T = RendererElement>(
-  props: PortalProps | null,
+  props: TeleportProps | null,
   select: RendererOptions['querySelector']
 ): T | null => {
-  const targetSelector = props && props.target
+  const targetSelector = props && props.to
   if (isString(targetSelector)) {
     if (!select) {
       __DEV__ &&
         warn(
-          `Current renderer does not support string target for Portals. ` +
+          `Current renderer does not support string target for Teleports. ` +
             `(missing querySelector renderer option)`
         )
       return null
@@ -39,21 +39,21 @@ const resolveTarget = <T = RendererElement>(
       if (!target) {
         __DEV__ &&
           warn(
-            `Failed to locate Portal target with selector "${targetSelector}".`
+            `Failed to locate Teleport target with selector "${targetSelector}".`
           )
       }
       return target as any
     }
   } else {
     if (__DEV__ && !targetSelector) {
-      warn(`Invalid Portal target: ${targetSelector}`)
+      warn(`Invalid Teleport target: ${targetSelector}`)
     }
     return targetSelector as any
   }
 }
 
-export const PortalImpl = {
-  __isPortal: true,
+export const TeleportImpl = {
+  __isTeleport: true,
   process(
     n1: VNode | null,
     n2: VNode,
@@ -72,32 +72,32 @@ export const PortalImpl = {
       o: { insert, querySelector, createText, createComment }
     } = internals
 
-    const disabled = isPortalDisabled(n2.props)
+    const disabled = isTeleportDisabled(n2.props)
     const { shapeFlag, children } = n2
     if (n1 == null) {
       // insert anchors in the main view
       const placeholder = (n2.el = __DEV__
-        ? createComment('portal start')
+        ? createComment('teleport start')
         : createText(''))
       const mainAnchor = (n2.anchor = __DEV__
-        ? createComment('portal end')
+        ? createComment('teleport end')
         : createText(''))
       insert(placeholder, container, anchor)
       insert(mainAnchor, container, anchor)
 
       const target = (n2.target = resolveTarget(
-        n2.props as PortalProps,
+        n2.props as TeleportProps,
         querySelector
       ))
       const targetAnchor = (n2.targetAnchor = createText(''))
       if (target) {
         insert(targetAnchor, target)
       } else if (__DEV__) {
-        warn('Invalid Portal target on mount:', target, `(${typeof target})`)
+        warn('Invalid Teleport target on mount:', target, `(${typeof target})`)
       }
 
       const mount = (container: RendererElement, anchor: RendererNode) => {
-        // Portal *always* has Array children. This is enforced in both the
+        // Teleport *always* has Array children. This is enforced in both the
         // compiler and vnode children normalization.
         if (shapeFlag & ShapeFlags.ARRAY_CHILDREN) {
           mountChildren(
@@ -123,12 +123,12 @@ export const PortalImpl = {
       const mainAnchor = (n2.anchor = n1.anchor)!
       const target = (n2.target = n1.target)!
       const targetAnchor = (n2.targetAnchor = n1.targetAnchor)!
-      const wasDisabled = isPortalDisabled(n1.props)
+      const wasDisabled = isTeleportDisabled(n1.props)
       const currentContainer = wasDisabled ? container : target
       const currentAnchor = wasDisabled ? mainAnchor : targetAnchor
 
       if (n2.dynamicChildren) {
-        // fast path when the portal happens to be a block root
+        // fast path when the teleport happens to be a block root
         patchBlockChildren(
           n1.dynamicChildren!,
           n2.dynamicChildren,
@@ -153,45 +153,45 @@ export const PortalImpl = {
         if (!wasDisabled) {
           // enabled -> disabled
           // move into main container
-          movePortal(
+          moveTeleport(
             n2,
             container,
             mainAnchor,
             internals,
-            PortalMoveTypes.TOGGLE
+            TeleportMoveTypes.TOGGLE
           )
         }
       } else {
         // target changed
-        if ((n2.props && n2.props.target) !== (n1.props && n1.props.target)) {
+        if ((n2.props && n2.props.to) !== (n1.props && n1.props.to)) {
           const nextTarget = (n2.target = resolveTarget(
-            n2.props as PortalProps,
+            n2.props as TeleportProps,
             querySelector
           ))
           if (nextTarget) {
-            movePortal(
+            moveTeleport(
               n2,
               nextTarget,
               null,
               internals,
-              PortalMoveTypes.TARGET_CHANGE
+              TeleportMoveTypes.TARGET_CHANGE
             )
           } else if (__DEV__) {
             warn(
-              'Invalid Portal target on update:',
+              'Invalid Teleport target on update:',
               target,
               `(${typeof target})`
             )
           }
         } else if (wasDisabled) {
           // disabled -> enabled
-          // move into portal target
-          movePortal(
+          // move into teleport target
+          moveTeleport(
             n2,
             target,
             targetAnchor,
             internals,
-            PortalMoveTypes.TOGGLE
+            TeleportMoveTypes.TOGGLE
           )
         }
       }
@@ -211,38 +211,38 @@ export const PortalImpl = {
     }
   },
 
-  move: movePortal,
-  hydrate: hydratePortal
+  move: moveTeleport,
+  hydrate: hydrateTeleport
 }
 
-export const enum PortalMoveTypes {
+export const enum TeleportMoveTypes {
   TARGET_CHANGE,
   TOGGLE, // enable / disable
   REORDER // moved in the main view
 }
 
-function movePortal(
+function moveTeleport(
   vnode: VNode,
   container: RendererElement,
   parentAnchor: RendererNode | null,
   { o: { insert }, m: move }: RendererInternals,
-  moveType: PortalMoveTypes = PortalMoveTypes.REORDER
+  moveType: TeleportMoveTypes = TeleportMoveTypes.REORDER
 ) {
   // move target anchor if this is a target change.
-  if (moveType === PortalMoveTypes.TARGET_CHANGE) {
+  if (moveType === TeleportMoveTypes.TARGET_CHANGE) {
     insert(vnode.targetAnchor!, container, parentAnchor)
   }
   const { el, anchor, shapeFlag, children, props } = vnode
-  const isReorder = moveType === PortalMoveTypes.REORDER
+  const isReorder = moveType === TeleportMoveTypes.REORDER
   // move main view anchor if this is a re-order.
   if (isReorder) {
     insert(el!, container, parentAnchor)
   }
-  // if this is a re-order and portal is enabled (content is in target)
+  // if this is a re-order and teleport is enabled (content is in target)
   // do not move children. So the opposite is: only move children if this
-  // is not a reorder, or the portal is disabled
-  if (!isReorder || isPortalDisabled(props)) {
-    // Portal has either Array children or no children.
+  // is not a reorder, or the teleport is disabled
+  if (!isReorder || isTeleportDisabled(props)) {
+    // Teleport has either Array children or no children.
     if (shapeFlag & ShapeFlags.ARRAY_CHILDREN) {
       for (let i = 0; i < (children as VNode[]).length; i++) {
         move(
@@ -260,12 +260,12 @@ function movePortal(
   }
 }
 
-interface PortalTargetElement extends Element {
-  // last portal target
+interface TeleportTargetElement extends Element {
+  // last teleport target
   _lpa?: Node | null
 }
 
-function hydratePortal(
+function hydrateTeleport(
   node: Node,
   vnode: VNode,
   parentComponent: ComponentInternalInstance | null,
@@ -284,15 +284,16 @@ function hydratePortal(
   ) => Node | null
 ): Node | null {
   const target = (vnode.target = resolveTarget<Element>(
-    vnode.props as PortalProps,
+    vnode.props as TeleportProps,
     querySelector
   ))
   if (target) {
-    // if multiple portals rendered to the same target element, we need to
-    // pick up from where the last portal finished instead of the first node
-    const targetNode = (target as PortalTargetElement)._lpa || target.firstChild
+    // if multiple teleports rendered to the same target element, we need to
+    // pick up from where the last teleport finished instead of the first node
+    const targetNode =
+      (target as TeleportTargetElement)._lpa || target.firstChild
     if (vnode.shapeFlag & ShapeFlags.ARRAY_CHILDREN) {
-      if (isPortalDisabled(vnode.props)) {
+      if (isTeleportDisabled(vnode.props)) {
         vnode.anchor = hydrateChildren(
           nextSibling(node),
           vnode,
@@ -313,7 +314,7 @@ function hydratePortal(
           optimized
         )
       }
-      ;(target as PortalTargetElement)._lpa = nextSibling(
+      ;(target as TeleportTargetElement)._lpa = nextSibling(
         vnode.targetAnchor as Node
       )
     }
@@ -322,7 +323,7 @@ function hydratePortal(
 }
 
 // Force-casted public typing for h and TSX props inference
-export const Portal = (PortalImpl as any) as {
-  __isPortal: true
-  new (): { $props: VNodeProps & PortalProps }
+export const Teleport = (TeleportImpl as any) as {
+  __isTeleport: true
+  new (): { $props: VNodeProps & TeleportProps }
 }
index e6f07fb1f1f861ef979a47c3ab4a9d5497c5348c..ee091035a386a56397a3e3ca6b93b9df9a964b81 100644 (file)
@@ -6,7 +6,7 @@ import {
   Fragment,
   isVNode
 } from './vnode'
-import { Portal, PortalProps } from './components/Portal'
+import { Teleport, TeleportProps } from './components/Teleport'
 import { Suspense, SuspenseProps } from './components/Suspense'
 import { isObject, isArray } from '@vue/shared'
 import { RawSlots } from './componentSlots'
@@ -68,7 +68,7 @@ type RawChildren =
 // fake constructor type returned from `defineComponent`
 interface Constructor<P = any> {
   __isFragment?: never
-  __isPortal?: never
+  __isTeleport?: never
   __isSuspense?: never
   new (): { $props: P }
 }
@@ -92,10 +92,10 @@ export function h(
   children?: VNodeArrayChildren
 ): VNode
 
-// portal (target prop is required)
+// teleport (target prop is required)
 export function h(
-  type: typeof Portal,
-  props: RawProps & PortalProps,
+  type: typeof Teleport,
+  props: RawProps & TeleportProps,
   children: RawChildren
 ): VNode
 
index 55d6e558598da056f8783446e7c8f2f3e2201d3a..03dc33bb8984712f2949428df751b83fa5c66e6f 100644 (file)
@@ -18,7 +18,7 @@ import {
   SuspenseBoundary,
   queueEffectWithSuspense
 } from './components/Suspense'
-import { PortalImpl } from './components/Portal'
+import { TeleportImpl } from './components/Teleport'
 
 export type RootHydrateFunction = (
   vnode: VNode<Node, Element>,
@@ -172,11 +172,11 @@ export function createHydrationFunctions(
           return isFragmentStart
             ? locateClosingAsyncAnchor(node)
             : nextSibling(node)
-        } else if (shapeFlag & ShapeFlags.PORTAL) {
+        } else if (shapeFlag & ShapeFlags.TELEPORT) {
           if (domType !== DOMNodeTypes.COMMENT) {
             return onMismatch()
           }
-          return (vnode.type as typeof PortalImpl).hydrate(
+          return (vnode.type as typeof TeleportImpl).hydrate(
             node,
             vnode,
             parentComponent,
index 190a30f99efdc45bc29d0028823f8505d404cfd9..b9abec16b8a1c5e636a4a41ef637d752054edf55 100644 (file)
@@ -53,7 +53,7 @@ export {
 } from './vnode'
 // Internal Components
 export { Text, Comment, Fragment } from './vnode'
-export { Portal, PortalProps } from './components/Portal'
+export { Teleport, TeleportProps } from './components/Teleport'
 export { Suspense, SuspenseProps } from './components/Suspense'
 export { KeepAlive, KeepAliveProps } from './components/KeepAlive'
 export {
index 6b571358675153db9ec2778785a49c6c1875bd5d..f28bf2500c31304d2a2daebf48a9e42251336d63 100644 (file)
@@ -58,7 +58,7 @@ import {
   queueEffectWithSuspense,
   SuspenseImpl
 } from './components/Suspense'
-import { PortalImpl } from './components/Portal'
+import { TeleportImpl } from './components/Teleport'
 import { KeepAliveSink, isKeepAlive } from './components/KeepAlive'
 import { registerHMR, unregisterHMR } from './hmr'
 import {
@@ -412,8 +412,8 @@ function baseCreateRenderer(
             isSVG,
             optimized
           )
-        } else if (shapeFlag & ShapeFlags.PORTAL) {
-          ;(type as typeof PortalImpl).process(
+        } else if (shapeFlag & ShapeFlags.TELEPORT) {
+          ;(type as typeof TeleportImpl).process(
             n1,
             n2,
             container,
@@ -1207,7 +1207,7 @@ function baseCreateRenderer(
         patch(
           prevTree,
           nextTree,
-          // parent may have changed if it's in a portal
+          // parent may have changed if it's in a teleport
           hostParentNode(prevTree.el!)!,
           // anchor may have changed if it's in a fragment
           getNextHostNode(prevTree),
@@ -1653,8 +1653,8 @@ function baseCreateRenderer(
       return
     }
 
-    if (shapeFlag & ShapeFlags.PORTAL) {
-      ;(type as typeof PortalImpl).move(vnode, container, anchor, internals)
+    if (shapeFlag & ShapeFlags.TELEPORT) {
+      ;(type as typeof TeleportImpl).move(vnode, container, anchor, internals)
       return
     }
 
@@ -1739,9 +1739,9 @@ function baseCreateRenderer(
         unmountChildren(children as VNode[], parentComponent, parentSuspense)
       }
 
-      // an unmounted portal should always remove its children
-      if (shapeFlag & ShapeFlags.PORTAL) {
-        ;(vnode.type as typeof PortalImpl).remove(vnode, internals)
+      // an unmounted teleport should always remove its children
+      if (shapeFlag & ShapeFlags.TELEPORT) {
+        ;(vnode.type as typeof TeleportImpl).remove(vnode, internals)
       }
 
       if (doRemove) {
index 0396323c5bd3dfe38a91e17a2f07b7b95f544d51..a05d9d22bc4615ec50ebf30c673cb7726bdbf3f8 100644 (file)
@@ -29,7 +29,7 @@ import { DirectiveBinding } from './directives'
 import { TransitionHooks } from './components/BaseTransition'
 import { warn } from './warning'
 import { currentScopeId } from './helpers/scopeId'
-import { PortalImpl, isPortal } from './components/Portal'
+import { TeleportImpl, isTeleport } from './components/Teleport'
 import { currentRenderingInstance } from './componentRenderUtils'
 import { RendererNode, RendererElement } from './renderer'
 
@@ -50,7 +50,7 @@ export type VNodeTypes =
   | typeof Static
   | typeof Comment
   | typeof Fragment
-  | typeof PortalImpl
+  | typeof TeleportImpl
   | typeof SuspenseImpl
 
 export type VNodeRef =
@@ -113,8 +113,8 @@ export interface VNode<HostNode = RendererNode, HostElement = RendererElement> {
   // DOM
   el: HostNode | null
   anchor: HostNode | null // fragment anchor
-  target: HostElement | null // portal target
-  targetAnchor: HostNode | null // portal target anchor
+  target: HostElement | null // teleport target
+  targetAnchor: HostNode | null // teleport target anchor
 
   // optimization only
   shapeFlag: number
@@ -283,8 +283,8 @@ function _createVNode(
     ? ShapeFlags.ELEMENT
     : __FEATURE_SUSPENSE__ && isSuspense(type)
       ? ShapeFlags.SUSPENSE
-      : isPortal(type)
-        ? ShapeFlags.PORTAL
+      : isTeleport(type)
+        ? ShapeFlags.TELEPORT
         : isObject(type)
           ? ShapeFlags.STATEFUL_COMPONENT
           : isFunction(type)
@@ -430,7 +430,7 @@ export function normalizeChildren(vnode: VNode, children: unknown) {
   } else if (typeof children === 'object') {
     // Normalize slot to plain children
     if (
-      (shapeFlag & ShapeFlags.ELEMENT || shapeFlag & ShapeFlags.PORTAL) &&
+      (shapeFlag & ShapeFlags.ELEMENT || shapeFlag & ShapeFlags.TELEPORT) &&
       (children as any).default
     ) {
       normalizeChildren(vnode, (children as any).default())
@@ -446,8 +446,8 @@ export function normalizeChildren(vnode: VNode, children: unknown) {
     type = ShapeFlags.SLOTS_CHILDREN
   } else {
     children = String(children)
-    // force portal children to array so it can be moved around
-    if (shapeFlag & ShapeFlags.PORTAL) {
+    // force teleport children to array so it can be moved around
+    if (shapeFlag & ShapeFlags.TELEPORT) {
       type = ShapeFlags.ARRAY_CHILDREN
       children = [createTextVNode(children as string)]
     } else {
similarity index 51%
rename from packages/server-renderer/__tests__/ssrPortal.spec.ts
rename to packages/server-renderer/__tests__/ssrTeleport.spec.ts
index 0a095e0720736daf4b786d435093f7255a06861d..c990e600643dc3a143e60e1de65df17ef7ee5fb2 100644 (file)
@@ -1,9 +1,9 @@
-import { createApp, h, Portal } from 'vue'
+import { createApp, h, Teleport } from 'vue'
 import { renderToString, SSRContext } from '../src/renderToString'
-import { ssrRenderPortal } from '../src/helpers/ssrRenderPortal'
+import { ssrRenderTeleport } from '../src/helpers/ssrRenderTeleport'
 
-describe('ssrRenderPortal', () => {
-  test('portal rendering (compiled)', async () => {
+describe('ssrRenderTeleport', () => {
+  test('teleport rendering (compiled)', async () => {
     const ctx: SSRContext = {}
     const html = await renderToString(
       createApp({
@@ -11,7 +11,7 @@ describe('ssrRenderPortal', () => {
           return { msg: 'hello' }
         },
         ssrRender(_ctx, _push, _parent) {
-          ssrRenderPortal(
+          ssrRenderTeleport(
             _push,
             _push => {
               _push(`<div>content</div>`)
@@ -24,11 +24,11 @@ describe('ssrRenderPortal', () => {
       }),
       ctx
     )
-    expect(html).toBe('<!--portal start--><!--portal end-->')
-    expect(ctx.portals!['#target']).toBe(`<div>content</div><!---->`)
+    expect(html).toBe('<!--teleport start--><!--teleport end-->')
+    expect(ctx.teleports!['#target']).toBe(`<div>content</div><!---->`)
   })
 
-  test('portal rendering (compiled + disabled)', async () => {
+  test('teleport rendering (compiled + disabled)', async () => {
     const ctx: SSRContext = {}
     const html = await renderToString(
       createApp({
@@ -36,7 +36,7 @@ describe('ssrRenderPortal', () => {
           return { msg: 'hello' }
         },
         ssrRender(_ctx, _push, _parent) {
-          ssrRenderPortal(
+          ssrRenderTeleport(
             _push,
             _push => {
               _push(`<div>content</div>`)
@@ -49,62 +49,66 @@ describe('ssrRenderPortal', () => {
       }),
       ctx
     )
-    expect(html).toBe('<!--portal start--><div>content</div><!--portal end-->')
-    expect(ctx.portals!['#target']).toBe(`<!---->`)
+    expect(html).toBe(
+      '<!--teleport start--><div>content</div><!--teleport end-->'
+    )
+    expect(ctx.teleports!['#target']).toBe(`<!---->`)
   })
 
-  test('portal rendering (vnode)', async () => {
+  test('teleport rendering (vnode)', async () => {
     const ctx: SSRContext = {}
     const html = await renderToString(
       h(
-        Portal,
+        Teleport,
         {
-          target: `#target`
+          to: `#target`
         },
         h('span', 'hello')
       ),
       ctx
     )
-    expect(html).toBe('<!--portal start--><!--portal end-->')
-    expect(ctx.portals!['#target']).toBe('<span>hello</span><!---->')
+    expect(html).toBe('<!--teleport start--><!--teleport end-->')
+    expect(ctx.teleports!['#target']).toBe('<span>hello</span><!---->')
   })
 
-  test('portal rendering (vnode + disabled)', async () => {
+  test('teleport rendering (vnode + disabled)', async () => {
     const ctx: SSRContext = {}
     const html = await renderToString(
       h(
-        Portal,
+        Teleport,
         {
-          target: `#target`,
+          to: `#target`,
           disabled: true
         },
         h('span', 'hello')
       ),
       ctx
     )
-    expect(html).toBe('<!--portal start--><span>hello</span><!--portal end-->')
-    expect(ctx.portals!['#target']).toBe(`<!---->`)
+    expect(html).toBe(
+      '<!--teleport start--><span>hello</span><!--teleport end-->'
+    )
+    expect(ctx.teleports!['#target']).toBe(`<!---->`)
   })
 
-  test('multiple portals with same target', async () => {
+  test('multiple teleports with same target', async () => {
     const ctx: SSRContext = {}
     const html = await renderToString(
       h('div', [
         h(
-          Portal,
+          Teleport,
           {
-            target: `#target`
+            to: `#target`
           },
           h('span', 'hello')
         ),
-        h(Portal, { target: `#target` }, 'world')
+        h(Teleport, { to: `#target` }, 'world')
       ]),
       ctx
     )
     expect(html).toBe(
-      '<div><!--portal start--><!--portal end--><!--portal start--><!--portal end--></div>'
+      '<div><!--teleport start--><!--teleport end--><!--teleport start--><!--teleport end--></div>'
     )
-    expect(ctx.portals!['#target']).toBe(
+    expect(ctx.teleports!['#target']).toBe(
       '<span>hello</span><!---->world<!---->'
     )
   })
similarity index 54%
rename from packages/server-renderer/src/helpers/ssrRenderPortal.ts
rename to packages/server-renderer/src/helpers/ssrRenderTeleport.ts
index 2f694cbdf771e7e83b36dd4c0f7f7daea57867b1..66772265d68233bf34ca1afb8c15b2ebb8d5af4d 100644 (file)
@@ -6,37 +6,37 @@ import {
   SSRBufferItem
 } from '../renderToString'
 
-export function ssrRenderPortal(
+export function ssrRenderTeleport(
   parentPush: PushFn,
   contentRenderFn: (push: PushFn) => void,
   target: string,
   disabled: boolean,
   parentComponent: ComponentInternalInstance
 ) {
-  parentPush('<!--portal start-->')
+  parentPush('<!--teleport start-->')
 
-  let portalContent: SSRBufferItem
+  let teleportContent: SSRBufferItem
 
   if (disabled) {
     contentRenderFn(parentPush)
-    portalContent = `<!---->`
+    teleportContent = `<!---->`
   } else {
     const { getBuffer, push } = createBuffer()
     contentRenderFn(push)
-    push(`<!---->`) // portal end anchor
-    portalContent = getBuffer()
+    push(`<!---->`) // teleport end anchor
+    teleportContent = getBuffer()
   }
 
   const context = parentComponent.appContext.provides[
     ssrContextKey as any
   ] as SSRContext
-  const portalBuffers =
-    context.__portalBuffers || (context.__portalBuffers = {})
-  if (portalBuffers[target]) {
-    portalBuffers[target].push(portalContent)
+  const teleportBuffers =
+    context.__teleportBuffers || (context.__teleportBuffers = {})
+  if (teleportBuffers[target]) {
+    teleportBuffers[target].push(teleportContent)
   } else {
-    portalBuffers[target] = [portalContent]
+    teleportBuffers[target] = [teleportContent]
   }
 
-  parentPush('<!--portal end-->')
+  parentPush('<!--teleport end-->')
 }
index 48915c63f61ecb79627b96f32f7909f176bd959b..f685295bec10bfde3438b7376fbeac109ad8e424 100644 (file)
@@ -13,7 +13,7 @@ export {
 } from './helpers/ssrRenderAttrs'
 export { ssrInterpolate } from './helpers/ssrInterpolate'
 export { ssrRenderList } from './helpers/ssrRenderList'
-export { ssrRenderPortal } from './helpers/ssrRenderPortal'
+export { ssrRenderTeleport } from './helpers/ssrRenderTeleport'
 export { ssrRenderSuspense } from './helpers/ssrRenderSuspense'
 
 // v-model helpers
index 8cb4b392f305062532f4ae8cfc2b45818af8a0c8..7f384dd8dc4b060d66e566cf38162ce9c651251e 100644 (file)
@@ -32,7 +32,7 @@ import { compile } from '@vue/compiler-ssr'
 import { ssrRenderAttrs } from './helpers/ssrRenderAttrs'
 import { SSRSlots } from './helpers/ssrRenderSlot'
 import { CompilerError } from '@vue/compiler-dom'
-import { ssrRenderPortal } from './helpers/ssrRenderPortal'
+import { ssrRenderTeleport } from './helpers/ssrRenderTeleport'
 
 const {
   isVNode,
@@ -63,8 +63,8 @@ export type Props = Record<string, unknown>
 
 export type SSRContext = {
   [key: string]: any
-  portals?: Record<string, string>
-  __portalBuffers?: Record<string, SSRBuffer>
+  teleports?: Record<string, string>
+  __teleportBuffers?: Record<string, SSRBuffer>
 }
 
 export function createBuffer() {
@@ -123,7 +123,7 @@ export async function renderToString(
   input.provide(ssrContextKey, context)
   const buffer = await renderComponentVNode(vnode)
 
-  await resolvePortals(context)
+  await resolveTeleports(context)
 
   return unrollBuffer(buffer)
 }
@@ -256,8 +256,8 @@ function renderVNode(
         renderElementVNode(push, vnode, parentComponent)
       } else if (shapeFlag & ShapeFlags.COMPONENT) {
         push(renderComponentVNode(vnode, parentComponent))
-      } else if (shapeFlag & ShapeFlags.PORTAL) {
-        renderPortalVNode(push, vnode, parentComponent)
+      } else if (shapeFlag & ShapeFlags.TELEPORT) {
+        renderTeleportVNode(push, vnode, parentComponent)
       } else if (shapeFlag & ShapeFlags.SUSPENSE) {
         renderVNode(
           push,
@@ -360,24 +360,24 @@ function applySSRDirectives(
   return mergeProps(rawProps || {}, ...toMerge)
 }
 
-function renderPortalVNode(
+function renderTeleportVNode(
   push: PushFn,
   vnode: VNode,
   parentComponent: ComponentInternalInstance
 ) {
-  const target = vnode.props && vnode.props.target
+  const target = vnode.props && vnode.props.to
   const disabled = vnode.props && vnode.props.disabled
   if (!target) {
-    warn(`[@vue/server-renderer] Portal is missing target prop.`)
+    warn(`[@vue/server-renderer] Teleport is missing target prop.`)
     return []
   }
   if (!isString(target)) {
     warn(
-      `[@vue/server-renderer] Portal target must be a query selector string.`
+      `[@vue/server-renderer] Teleport target must be a query selector string.`
     )
     return []
   }
-  ssrRenderPortal(
+  ssrRenderTeleport(
     push,
     push => {
       renderVNodeChildren(
@@ -392,14 +392,14 @@ function renderPortalVNode(
   )
 }
 
-async function resolvePortals(context: SSRContext) {
-  if (context.__portalBuffers) {
-    context.portals = context.portals || {}
-    for (const key in context.__portalBuffers) {
+async function resolveTeleports(context: SSRContext) {
+  if (context.__teleportBuffers) {
+    context.teleports = context.teleports || {}
+    for (const key in context.__teleportBuffers) {
       // note: it's OK to await sequentially here because the Promises were
       // created eagerly in parallel.
-      context.portals[key] = unrollBuffer(
-        await Promise.all(context.__portalBuffers[key])
+      context.teleports[key] = unrollBuffer(
+        await Promise.all(context.__teleportBuffers[key])
       )
     }
   }
index 93c5f78234b4faa7a4572523dd553bfe593d9069..8defb8a3bf3ae5536f5d78a840ce40294beb8332 100644 (file)
@@ -5,7 +5,7 @@ export const enum ShapeFlags {
   TEXT_CHILDREN = 1 << 3,
   ARRAY_CHILDREN = 1 << 4,
   SLOTS_CHILDREN = 1 << 5,
-  PORTAL = 1 << 6,
+  TELEPORT = 1 << 6,
   SUSPENSE = 1 << 7,
   COMPONENT_SHOULD_KEEP_ALIVE = 1 << 8,
   COMPONENT_KEPT_ALIVE = 1 << 9,
index 3c8f1d071d03605f0e0c242e8834491b4e64954d..03180539a4c34f2000830d084e52c1d629341210 100644 (file)
@@ -45,14 +45,14 @@ const Modal = {
 <!-- app -->
 <div id="app">
   <button id="show-modal" @click="showModal = true">Show Modal</button>
-  <portal target="#modal-container">
+  <teleport to="#modal-container">
     <!-- use the modal component, pass in the prop -->
     <modal :show="showModal" @close="showModal = false">
       <template #header>
         <h3>custom header</h3>
       </template>
     </modal>
-  </portal>
+  </teleport>
 </div>
 
 <script>