From 8ff93d210090c1a3d77208eb212f07fcc2b2df4a Mon Sep 17 00:00:00 2001 From: Haixing <65376724+HaixingOoO@users.noreply.github.com> Date: Mon, 22 Jul 2024 11:53:21 +0800 Subject: [PATCH] feat(configprovider): support attach (#3001) --- src/config-provider/config-provider.en-US.md | 1 + src/config-provider/config-provider.md | 63 ++++++++++---------- src/config-provider/type.ts | 6 +- src/dialog/Dialog.tsx | 4 +- src/hooks/useAttach.ts | 24 ++++++++ src/image-viewer/ImageViewer.tsx | 18 +++--- src/image-viewer/defaultProps.ts | 1 - src/popup/Popup.tsx | 4 +- src/popup/defaultProps.ts | 1 - 9 files changed, 76 insertions(+), 46 deletions(-) create mode 100644 src/hooks/useAttach.ts diff --git a/src/config-provider/config-provider.en-US.md b/src/config-provider/config-provider.en-US.md index becaa7bcf..72d18f47c 100644 --- a/src/config-provider/config-provider.en-US.md +++ b/src/config-provider/config-provider.en-US.md @@ -8,6 +8,7 @@ name | type | default | description | required alert | Object | - | Alert global configs。Typescript:`AlertConfig` | N anchor | Object | - | Anchor global configs。Typescript:`AnchorConfig` | N animation | Object | - | Typescript:`Partial>>` `type AnimationType = 'ripple' \| 'expand' \| 'fade'`。[see more ts definition](https://github.com/Tencent/tdesign-react/blob/develop/src/config-provider/type.ts) | N +attach | String / Object / Function | - | Typescript:`AttachNode \| { imageViewer?: AttachNode; popup?: AttachNode; dialog?: AttachNode; }`。[see more ts definition](https://github.com/Tencent/tdesign-react/blob/develop/src/common.ts) | N calendar | Object | - | Calendar global configs。Typescript:`CalendarConfig` | N cascader | Object | - | Cascader global configs。Typescript:`CascaderConfig` | N classPrefix | String | t | \- | N diff --git a/src/config-provider/config-provider.md b/src/config-provider/config-provider.md index c73e8635d..2b7552571 100644 --- a/src/config-provider/config-provider.md +++ b/src/config-provider/config-provider.md @@ -33,11 +33,12 @@ import 'tdesign-react/esm/style/index.js' ## API ### GlobalConfigProvider -名称 | 类型 | 默认值 | 说明 | 必传 +名称 | 类型 | 默认值 | 描述 | 必传 -- | -- | -- | -- | -- alert | Object | - | 警告全局配置。TS 类型:`AlertConfig` | N anchor | Object | - | 锚点全局配置。TS 类型:`AnchorConfig` | N animation | Object | - | 动画效果控制,`ripple` 指波纹动画, `expand` 指展开动画,`fade` 指渐变动画。默认为 `{ include: ['ripple','expand','fade'], exclude: [] }`。TS 类型:`Partial>>` `type AnimationType = 'ripple' \| 'expand' \| 'fade'`。[详细类型定义](https://github.com/Tencent/tdesign-react/blob/develop/src/config-provider/type.ts) | N +attach | String / Object / Function | - | TS 类型:`AttachNode \| { imageViewer?: AttachNode; popup?: AttachNode; dialog?: AttachNode; }`。[通用类型定义](https://github.com/Tencent/tdesign-react/blob/develop/src/common.ts) | N calendar | Object | - | 日历组件全局配置。TS 类型:`CalendarConfig` | N cascader | Object | - | 级联选择器全局配置。TS 类型:`CascaderConfig` | N classPrefix | String | t | CSS 类名前缀 | N @@ -68,14 +69,14 @@ upload | Object | - | 上传组件全局配置。TS 类型:`UploadConfig` | N ### InputConfig -名称 | 类型 | 默认值 | 说明 | 必传 +名称 | 类型 | 默认值 | 描述 | 必传 -- | -- | -- | -- | -- autocomplete | String | - | 是否开启自动填充功能 | N placeholder | String | - | 语言配置,“请输入”占位符描述文本 | N ### PaginationConfig -名称 | 类型 | 默认值 | 说明 | 必传 +名称 | 类型 | 默认值 | 描述 | 必传 -- | -- | -- | -- | -- itemsPerPage | String | - | 语言配置,每页条数文本,示例:`'{size} 条/页'` | N jumpTo | String | - | 语言配置,页码跳转文本,示例:'跳至' | N @@ -84,7 +85,7 @@ total | String | - | 语言配置,数据总条数文本,示例:`'共 {tota ### CalendarConfig -名称 | 类型 | 默认值 | 说明 | 必传 +名称 | 类型 | 默认值 | 描述 | 必传 -- | -- | -- | -- | -- cellMonth | String | - | 语言配置,月份描述文本,示例:'一月,二月,三月,四月,五月,六月,七月,八月,九月,十月,十一月,十二月' | N controllerConfig | Object | - | 日历右上角控制器按钮配置。TS 类型:`CalendarController`,[Calendar API Documents](./calendar?tab=api)。[详细类型定义](https://github.com/Tencent/tdesign-react/blob/develop/src/config-provider/type.ts) | N @@ -102,7 +103,7 @@ yearSelection | String | - | 语言配置,“年”选择描述文本,示例 ### CascaderConfig -名称 | 类型 | 默认值 | 说明 | 必传 +名称 | 类型 | 默认值 | 描述 | 必传 -- | -- | -- | -- | -- empty | String | - | 语言配置,“暂无数据”描述文本 | N loadingText | String | - | 语言配置,“加载中”描述文本 | N @@ -110,7 +111,7 @@ placeholder | String | - | 语言配置,“请选择”占位描述文本 | N ### ColorPickerConfig -名称 | 类型 | 默认值 | 说明 | 必传 +名称 | 类型 | 默认值 | 描述 | 必传 -- | -- | -- | -- | -- clearConfirmText | String | - | 语言配置,“确定清空最近使用的颜色吗?”清空颜色确认文案 | N recentColorTitle | String | - | 语言配置,“最近使用颜色” 区域标题文本 | N @@ -118,7 +119,7 @@ swatchColorTitle | String | - | 语言配置,\"系统预设颜色\" 区域标 ### TransferConfig -名称 | 类型 | 默认值 | 说明 | 必传 +名称 | 类型 | 默认值 | 描述 | 必传 -- | -- | -- | -- | -- empty | String | - | 语言配置,“暂无数据”空数据描述文本 | N placeholder | String | - | 语言配置,“请输入关键词搜索”占位符描述文本 | N @@ -126,7 +127,7 @@ title | String | - | 语言配置,穿梭框标题描述文本,示例:“{c ### TimePickerConfig -名称 | 类型 | 默认值 | 说明 | 必传 +名称 | 类型 | 默认值 | 描述 | 必传 -- | -- | -- | -- | -- anteMeridiem | String | - | 语言配置,“上午”描述文本 | N confirm | String | - | 语言配置,“确定”描述文本 | N @@ -136,7 +137,7 @@ postMeridiem | String | - | 语言配置,“下午”描述文本 | N ### DatePickerConfig -名称 | 类型 | 默认值 | 说明 | 必传 +名称 | 类型 | 默认值 | 描述 | 必传 -- | -- | -- | -- | -- confirm | String | - | 语言配置,“确定” 描述文本 | N dayAriaLabel | String | - | 语言配置,“日” 描述文本 | N @@ -165,7 +166,7 @@ yearAriaLabel | String | - | 语言配置,“年” 描述文本 | N ### DialogConfig -名称 | 类型 | 默认值 | 说明 | 必传 +名称 | 类型 | 默认值 | 描述 | 必传 -- | -- | -- | -- | -- cancel | Object | - | 取消按钮风格。TS 类型:`string \| ButtonProps`,[Button API Documents](./button?tab=api)。[详细类型定义](https://github.com/Tencent/tdesign-react/blob/develop/src/config-provider/type.ts) | N closeOnEscKeydown | Boolean | true | 按下 ESC 时是否触发对话框关闭事件 | N @@ -175,7 +176,7 @@ confirmBtnTheme | Object | - | 确认按钮主题色,即 Dialog 的 `theme` ### DrawerConfig -名称 | 类型 | 默认值 | 说明 | 必传 +名称 | 类型 | 默认值 | 描述 | 必传 -- | -- | -- | -- | -- cancel | String | - | 语言配置,“取消”描述文本。TS 类型:`string \| ButtonProps` | N closeOnEscKeydown | Boolean | true | 按下 ESC 时是否触发抽屉关闭事件 | N @@ -185,7 +186,7 @@ size | String | 'small' | 尺寸配置,配置Drawer尺寸 | N ### PopconfirmConfig -名称 | 类型 | 默认值 | 说明 | 必传 +名称 | 类型 | 默认值 | 描述 | 必传 -- | -- | -- | -- | -- cancel | String / Object | - | 语言配置,“取消”描述文本。TS 类型:`string \| ButtonProps`,[Button API Documents](./button?tab=api)。[详细类型定义](https://github.com/Tencent/tdesign-react/blob/develop/src/config-provider/type.ts) | N confirm | String / Object | - | 语言配置,“确定”描述文本。TS 类型:`string \| ButtonProps` | N @@ -193,7 +194,7 @@ confirmBtnTheme | Object | - | 确认按钮主题色,即 Popconfirm 的 `theme ### TableConfig -名称 | 类型 | 默认值 | 说明 | 必传 +名称 | 类型 | 默认值 | 描述 | 必传 -- | -- | -- | -- | -- cancelText | String | - | 语言配置,“取消” 描述文本 | N clearFilterResultButtonText | String | - | 语言配置,过滤功能中,“清空筛选” 描述文本 | N @@ -218,7 +219,7 @@ treeExpandAndFoldIcon | Function | undefined | 树形结构,展开和折叠图 ### SelectConfig -名称 | 类型 | 默认值 | 说明 | 必传 +名称 | 类型 | 默认值 | 描述 | 必传 -- | -- | -- | -- | -- clearIcon | Function | - | 清除图标,【注意】使用渲染函数输出图标组件。TS 类型:`TNode`。[通用类型定义](https://github.com/Tencent/tdesign-react/blob/develop/src/common.ts) | N empty | String | - | 语言配置,“暂无数据”描述文本 | N @@ -228,14 +229,14 @@ placeholder | String | - | 语言配置,“请选择”占位符描述文本 | ### TreeConfig -名称 | 类型 | 默认值 | 说明 | 必传 +名称 | 类型 | 默认值 | 描述 | 必传 -- | -- | -- | -- | -- empty | String | - | 语言配置,“暂无数据”描述文本 | N folderIcon | Function | - | 目录层级图标,传入收起状态图标即可。【注意】使用渲染函数输出图标组件。TS 类型:`TNode`。[通用类型定义](https://github.com/Tencent/tdesign-react/blob/develop/src/common.ts) | N ### TreeSelectConfig -名称 | 类型 | 默认值 | 说明 | 必传 +名称 | 类型 | 默认值 | 描述 | 必传 -- | -- | -- | -- | -- empty | String | - | 语言配置,“暂无数据”描述文本 | N loadingText | String | - | 语言配置,“加载中”描述文本 | N @@ -243,14 +244,14 @@ placeholder | String | - | 语言配置,“请选择”占位符描述文本 | ### ListConfig -名称 | 类型 | 默认值 | 说明 | 必传 +名称 | 类型 | 默认值 | 描述 | 必传 -- | -- | -- | -- | -- loadingMoreText | String | - | 语言配置,'点击加载更多' 描述文本 | N loadingText | String | - | 语言配置,'正在加载中,请稍后' 描述文本 | N ### UploadConfig -名称 | 类型 | 默认值 | 说明 | 必传 +名称 | 类型 | 默认值 | 描述 | 必传 -- | -- | -- | -- | -- cancelUploadText | String | - | 语言配置,“取消上传” 描述文本 | N dragger | Object | - | 语言配置,拖拽相关。示例:{ dragDropText: '释放图标', draggingText: '拖拽到此区域', clickAndDragText: '点击上方“选择文件”或将文件拖到此区域' }。TS 类型:`UploadConfigDragger` | N @@ -261,7 +262,7 @@ triggerUploadText | Object | - | 语言配置,上传功能触发文案。示 ### UploadConfigProgress -名称 | 类型 | 默认值 | 说明 | 必传 +名称 | 类型 | 默认值 | 描述 | 必传 -- | -- | -- | -- | -- failText | String | - | 语言配置,“上传失败”文本描述 | N successText | String | - | 语言配置,“上传成功”文本描述 | N @@ -270,7 +271,7 @@ waitingText | String | - | 语言配置,“待上传”文本描述 | N ### UploadConfigDragger -名称 | 类型 | 默认值 | 说明 | 必传 +名称 | 类型 | 默认值 | 描述 | 必传 -- | -- | -- | -- | -- clickAndDragText | String | - | 语言配置,“ 点击上方“选择文件”或将文件拖到此区域 ” 描述文本 | N dragDropText | String | - | 语言配置,“释放图标” 描述文本 | N @@ -278,7 +279,7 @@ draggingText | String | - | 语言配置,'拖拽到此区域' 描述文本 | N ### UploadConfigFileList -名称 | 类型 | 默认值 | 说明 | 必传 +名称 | 类型 | 默认值 | 描述 | 必传 -- | -- | -- | -- | -- fileNameText | String | - | 语言配置,“文件名” 描述文本 | N fileOperationDateText | String | - | 语言配置,“上传日期” 描述文本 | N @@ -288,47 +289,47 @@ fileStatusText | String | - | 语言配置,“状态” 描述文本 | N ### FormConfig -名称 | 类型 | 默认值 | 说明 | 必传 +名称 | 类型 | 默认值 | 描述 | 必传 -- | -- | -- | -- | -- errorMessage | Object | - | 表单错误信息配置,示例:`{ idcard: '请输入正确的身份证号码', max: '字符长度不能超过 ${max}' }`。TS 类型:`FormErrorMessage`,[Form API Documents](./form?tab=api)。[详细类型定义](https://github.com/Tencent/tdesign-react/blob/develop/src/config-provider/type.ts) | N requiredMark | Boolean | true | 是否显示必填符号(*),默认显示 | N ### TagConfig -名称 | 类型 | 默认值 | 说明 | 必传 +名称 | 类型 | 默认值 | 描述 | 必传 -- | -- | -- | -- | -- closeIcon | Function | - | 关闭图标,【注意】使用渲染函数输出图标组件。TS 类型:`TNode`。[通用类型定义](https://github.com/Tencent/tdesign-react/blob/develop/src/common.ts) | N ### StepsConfig -名称 | 类型 | 默认值 | 说明 | 必传 +名称 | 类型 | 默认值 | 描述 | 必传 -- | -- | -- | -- | -- checkIcon | TElement | - | 已完成步骤图标,【注意】使用渲染函数输出图标组件。TS 类型:`TNode`。[通用类型定义](https://github.com/Tencent/tdesign-react/blob/develop/src/common.ts) | N errorIcon | TElement | - | 错误步骤图标,【注意】使用渲染函数输出图标组件。TS 类型:`TNode`。[通用类型定义](https://github.com/Tencent/tdesign-react/blob/develop/src/common.ts) | N ### AlertConfig -名称 | 类型 | 默认值 | 说明 | 必传 +名称 | 类型 | 默认值 | 描述 | 必传 -- | -- | -- | -- | -- collapseText | String | - | 语言配置,“收起”描述文本 | N expandText | String | - | 语言配置,“展开更多”描述文本 | N ### AnchorConfig -名称 | 类型 | 默认值 | 说明 | 必传 +名称 | 类型 | 默认值 | 描述 | 必传 -- | -- | -- | -- | -- copySuccessText | String | - | 语言配置,“链接复制成功”描述文本 | N copyText | String | - | 语言配置,“复制链接” 描述文本 | N ### MessageConfig -名称 | 类型 | 默认值 | 说明 | 必传 +名称 | 类型 | 默认值 | 描述 | 必传 -- | -- | -- | -- | -- `MessageOptions` | \- | - | 继承 `MessageOptions` 中的全部属性 | N ### ImageConfig -名称 | 类型 | 默认值 | 说明 | 必传 +名称 | 类型 | 默认值 | 描述 | 必传 -- | -- | -- | -- | -- errorText | String | - | 图片加载失败显示的文本,中文默认为“图片无法显示” | N loadingText | String | - | 图片加载中显示的文本,中文默认为“图片加载中” | N @@ -336,7 +337,7 @@ replaceImageSrc | Function | - | 统一替换图片 `src` 地址,参数为组 ### ImageViewerConfig -名称 | 类型 | 默认值 | 说明 | 必传 +名称 | 类型 | 默认值 | 描述 | 必传 -- | -- | -- | -- | -- errorText | String | - | 全局语言配置,默认为 “图片加载失败,可尝试重新加载” | N mirrorTipText | String | - | 全局语言配置,默认为 “镜像” | N @@ -345,7 +346,7 @@ rotateTipText | String | - | 全局语言配置,默认为 “旋转” | N ### GuideConfig -名称 | 类型 | 默认值 | 说明 | 必传 +名称 | 类型 | 默认值 | 描述 | 必传 -- | -- | -- | -- | -- finishButtonProps | Object | - | 最后一步中的完成按钮,示例:`{ content: '完成', theme: 'primary' }`。TS 类型:`ButtonProps` | N nextButtonProps | Object | - | 下一步按钮,示例:`{ content: '下一步', theme: 'primary' }`。TS 类型:`ButtonProps` | N @@ -354,7 +355,7 @@ skipButtonProps | Object | - | 跳过按钮,示例:`{ content: '跳过', the ### TypographyConfig -名称 | 类型 | 默认值 | 说明 | 必传 +名称 | 类型 | 默认值 | 描述 | 必传 -- | -- | -- | -- | -- collapseText | String | - | 语言配置,“收起”描述文本 | N expandText | String | - | 语言配置,“展开”描述文本 | N diff --git a/src/config-provider/type.ts b/src/config-provider/type.ts index 17de983e3..f6ab18955 100644 --- a/src/config-provider/type.ts +++ b/src/config-provider/type.ts @@ -10,7 +10,7 @@ import { ButtonProps } from '../button'; import { FormErrorMessage } from '../form'; import { MessageOptions } from '../message'; import { ImageProps } from '../image'; -import { TNode, TElement } from '../common'; +import { TNode, TElement, AttachNode } from '../common'; export interface GlobalConfigProvider { /** @@ -25,6 +25,10 @@ export interface GlobalConfigProvider { * 动画效果控制,`ripple` 指波纹动画, `expand` 指展开动画,`fade` 指渐变动画。默认为 `{ include: ['ripple','expand','fade'], exclude: [] }` */ animation?: Partial>>; + /** + * null + */ + attach?: AttachNode | { imageViewer?: AttachNode; popup?: AttachNode; dialog?: AttachNode }; /** * 日历组件全局配置 */ diff --git a/src/dialog/Dialog.tsx b/src/dialog/Dialog.tsx index 74486d4f0..209191076 100644 --- a/src/dialog/Dialog.tsx +++ b/src/dialog/Dialog.tsx @@ -16,6 +16,7 @@ import useDialogDrag from './hooks/useDialogDrag'; import { parseValueToPx } from './utils'; import log from '../_common/js/log'; import useDefaultProps from '../hooks/useDefaultProps'; +import useAttach from '../hooks/useAttach'; export interface DialogProps extends TdDialogProps, StyledProps { isPlugin?: boolean; // 是否以插件形式调用 @@ -66,6 +67,7 @@ const Dialog = forwardRef((originalProps, ref) => { ...restState } = state; + const dialogAttach = useAttach('dialog', attach); useLockStyle({ preventScrollThrough, visible, mode, showInAttachedElement }); useDialogEsc(visible, wrapRef); useDialogPosition(visible, dialogCardRef); @@ -195,7 +197,7 @@ const Dialog = forwardRef((originalProps, ref) => { onEntered={onOpened} onExited={onAnimateLeave} > - +
globalConfig.attach.component -> globalConfig.attach -> default = 'body' + */ +const useAttach = (name: string, attach: AttachNode) => { + const globalConfig = useConfig(); + + const attachVal = useMemo( + () => attach || globalConfig?.attach?.[name] || globalConfig?.attach || defaultAttach, + [name, attach, globalConfig?.attach], + ); + + return attachVal; +}; + +export default useAttach; diff --git a/src/image-viewer/ImageViewer.tsx b/src/image-viewer/ImageViewer.tsx index 30e408d03..be6f3e4bf 100644 --- a/src/image-viewer/ImageViewer.tsx +++ b/src/image-viewer/ImageViewer.tsx @@ -12,6 +12,7 @@ import useViewerScale from './hooks/useViewerScale'; import useControlled from '../hooks/useControlled'; import useDefaultProps from '../hooks/useDefaultProps'; import { canUseDocument } from '../_util/dom'; +import useAttach from '../hooks/useAttach'; export interface ImageViewerProps extends TdImageViewerProps, StyledProps {} @@ -19,6 +20,7 @@ const ImageViewer: React.FC = (originalProps) => { const props = useDefaultProps(originalProps, imageViewerDefaultProps); const { attach, mode, trigger, images, title, imageScale: imageScaleD, viewerScale: viewerScaleD } = props; + const imageViewerAttach = useAttach('imageViewer', attach); const [visible, setVisible] = useControlled(props, 'visible', (visible, context) => { isFunction(props.onClose) && props.onClose(context); }); @@ -45,19 +47,15 @@ const ImageViewer: React.FC = (originalProps) => { const uiImage: TNode = isFunction(trigger) ? trigger({ open, close, onOpen: open, onClose: close }) : trigger; const attachElement = useMemo(() => { - if (!canUseDocument || !attach) return null; + if (!canUseDocument || !imageViewerAttach) return null; - if (attach === 'body') { - return document.body; + if (typeof imageViewerAttach === 'string') { + return document.querySelector(imageViewerAttach); } - - if (typeof attach === 'string') { - return document.querySelector(attach); - } - if (isFunction(attach)) { - return attach(); + if (isFunction(imageViewerAttach)) { + return imageViewerAttach(); } - }, [attach]); + }, [imageViewerAttach]); return ( <> diff --git a/src/image-viewer/defaultProps.ts b/src/image-viewer/defaultProps.ts index 8c570763a..d6d4a553c 100644 --- a/src/image-viewer/defaultProps.ts +++ b/src/image-viewer/defaultProps.ts @@ -5,7 +5,6 @@ import { TdImageViewerProps } from './type'; export const imageViewerDefaultProps: TdImageViewerProps = { - attach: 'body', closeBtn: true, closeOnEscKeydown: true, draggable: undefined, diff --git a/src/popup/Popup.tsx b/src/popup/Popup.tsx index 325910a32..ecf031ee4 100644 --- a/src/popup/Popup.tsx +++ b/src/popup/Popup.tsx @@ -17,6 +17,7 @@ import useMutationObserver from '../hooks/useMutationObserver'; import useWindowSize from '../hooks/useWindowSize'; import { popupDefaultProps } from './defaultProps'; import useDefaultProps from '../hooks/useDefaultProps'; +import useAttach from '../hooks/useAttach'; export interface PopupProps extends TdPopupProps { // 是否触发展开收起动画,内部下拉式组件使用 @@ -64,6 +65,7 @@ const Popup = forwardRef((originalProps, ref) => { updateScrollTop, } = props; const { classPrefix } = useConfig(); + const popupAttach = useAttach('popup', attach); // 全局配置 const { keepExpand, keepFade } = useAnimation(); @@ -170,7 +172,7 @@ const Popup = forwardRef((originalProps, ref) => { onEnter={handleEnter} onExited={handleExited} > - +