From 4884cb8efadaa0c00c0d60b0b7b6180fcd46928d Mon Sep 17 00:00:00 2001
From: inottn <inottn@outlook.com>
Date: Fri, 30 Aug 2024 21:45:44 +0800
Subject: [PATCH] feat(Overlay): add teleport prop (#13087)

---
 packages/vant/src/overlay/Overlay.tsx         | 23 +++++++++++++++----
 packages/vant/src/overlay/README.md           |  1 +
 packages/vant/src/overlay/README.zh-CN.md     |  1 +
 packages/vant/src/overlay/test/index.spec.tsx | 12 ++++++++++
 4 files changed, 33 insertions(+), 4 deletions(-)

diff --git a/packages/vant/src/overlay/Overlay.tsx b/packages/vant/src/overlay/Overlay.tsx
index 6660829f6..269d58860 100644
--- a/packages/vant/src/overlay/Overlay.tsx
+++ b/packages/vant/src/overlay/Overlay.tsx
@@ -1,10 +1,12 @@
 import {
   ref,
-  Transition,
   defineComponent,
+  Teleport,
+  Transition,
   type PropType,
   type CSSProperties,
   type ExtractPropTypes,
+  type TeleportProps,
 } from 'vue';
 
 // Utils
@@ -33,6 +35,7 @@ export const overlayProps = {
   lockScroll: truthProp,
   lazyRender: truthProp,
   customStyle: Object as PropType<CSSProperties>,
+  teleport: [String, Object] as PropType<TeleportProps['to']>,
 };
 
 export type OverlayProps = ExtractPropTypes<typeof overlayProps>;
@@ -79,8 +82,20 @@ export default defineComponent({
       target: root,
     });
 
-    return () => (
-      <Transition v-slots={{ default: renderOverlay }} name="van-fade" appear />
-    );
+    return () => {
+      const Content = (
+        <Transition
+          v-slots={{ default: renderOverlay }}
+          name="van-fade"
+          appear
+        />
+      );
+
+      if (props.teleport) {
+        return <Teleport to={props.teleport}>{Content}</Teleport>;
+      }
+
+      return Content;
+    };
   },
 });
diff --git a/packages/vant/src/overlay/README.md b/packages/vant/src/overlay/README.md
index 269b650f0..a42311f7e 100644
--- a/packages/vant/src/overlay/README.md
+++ b/packages/vant/src/overlay/README.md
@@ -82,6 +82,7 @@ The default z-index level of the Overlay component is `1`. You can set its z-ind
 | custom-class | Custom style | _object_ | - |
 | lock-scroll | Whether to lock background scroll | _boolean_ | `true` |
 | lazy-render | Whether to lazy render util appeared | _boolean_ | `true` |
+| teleport | Specifies a target element where Overlay will be mounted | _string \| Element_ | - |
 
 ### Events
 
diff --git a/packages/vant/src/overlay/README.zh-CN.md b/packages/vant/src/overlay/README.zh-CN.md
index 9a0cf716c..14af83ec9 100644
--- a/packages/vant/src/overlay/README.zh-CN.md
+++ b/packages/vant/src/overlay/README.zh-CN.md
@@ -84,6 +84,7 @@ Overlay 组件默认的 z-index 层级为 `1`,你可以通过 `z-index` 属性
 | custom-style | 自定义样式 | _object_ | - |
 | lock-scroll | 是否锁定背景滚动,锁定时蒙层里的内容也将无法滚动 | _boolean_ | `true` |
 | lazy-render | 是否在显示时才渲染节点 | _boolean_ | `true` |
+| teleport | 指定挂载的节点,等同于 Teleport 组件的 [to 属性](https://cn.vuejs.org/api/built-in-components.html#teleport) | _string \| Element_ | - |
 
 ### Events
 
diff --git a/packages/vant/src/overlay/test/index.spec.tsx b/packages/vant/src/overlay/test/index.spec.tsx
index 2eb6ef0a5..597011c88 100644
--- a/packages/vant/src/overlay/test/index.spec.tsx
+++ b/packages/vant/src/overlay/test/index.spec.tsx
@@ -104,3 +104,15 @@ test('should allow to disable lazy-render', async () => {
 
   expect(wrapper.html()).toMatchSnapshot();
 });
+
+test('should allow to use the teleport prop', () => {
+  const root = document.createElement('div');
+  mount(Overlay, {
+    props: {
+      show: true,
+      teleport: root,
+    },
+  });
+
+  expect(root.querySelector('.van-overlay')).toBeTruthy();
+});