From d1d008665affad31204c0720b5861d6085b58dde Mon Sep 17 00:00:00 2001 From: fcppddl <112799728+fcppddl@users.noreply.github.com> Date: Tue, 17 Dec 2024 19:36:28 +0800 Subject: [PATCH] =?UTF-8?q?feat(portal-context):=20Provider=20=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=20portal=20=E5=8F=82=E6=95=B0=EF=BC=8C=E6=94=AF?= =?UTF-8?q?=E6=8C=81=E9=85=8D=E7=BD=AE=E5=85=A8=E5=B1=80=20container=20(#3?= =?UTF-8?q?060)=20(#3061)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat(container-context): add container package (#3060) * chore(container-context): 规范代码 (#3060) * chore(portal-context): 改写名字代码 (#3060) * chore(portal-context): 规范记录(#3060) * chore(portal-context): 删除多余代码(#3060) * chore(portal-context): 删除多余空格(#3060) --------- Co-authored-by: wanjinping --- .changeset/little-rabbits-change.md | 12 +++++ packages/core/core/package.json | 3 +- packages/core/core/src/index.ts | 3 ++ packages/ui/drawer/src/Drawer.tsx | 6 ++- packages/ui/loading/src/Loading.tsx | 7 ++- packages/ui/modal/src/Modal.tsx | 7 ++- packages/ui/portal-context/README.md | 11 ++++ .../__tests__/portal-context.test.js | 5 ++ packages/ui/portal-context/hi-docs.config.mdx | 15 ++++++ packages/ui/portal-context/jest.config.js | 1 + packages/ui/portal-context/package.json | 54 +++++++++++++++++++ .../ui/portal-context/src/PortalContext.tsx | 11 ++++ .../ui/portal-context/src/PortalProvider.tsx | 18 +++++++ packages/ui/portal-context/src/index.ts | 4 ++ .../portal-context/stories/basic.stories.tsx | 16 ++++++ .../portal-context/stories/index.stories.tsx | 8 +++ packages/ui/portal-context/tsconfig.json | 4 ++ packages/ui/preview/src/Preview.tsx | 17 +++++- packages/ui/provider/src/Provider.tsx | 21 ++++++-- 19 files changed, 209 insertions(+), 14 deletions(-) create mode 100644 .changeset/little-rabbits-change.md create mode 100644 packages/ui/portal-context/README.md create mode 100644 packages/ui/portal-context/__tests__/portal-context.test.js create mode 100644 packages/ui/portal-context/hi-docs.config.mdx create mode 100644 packages/ui/portal-context/jest.config.js create mode 100644 packages/ui/portal-context/package.json create mode 100644 packages/ui/portal-context/src/PortalContext.tsx create mode 100644 packages/ui/portal-context/src/PortalProvider.tsx create mode 100644 packages/ui/portal-context/src/index.ts create mode 100644 packages/ui/portal-context/stories/basic.stories.tsx create mode 100644 packages/ui/portal-context/stories/index.stories.tsx create mode 100644 packages/ui/portal-context/tsconfig.json diff --git a/.changeset/little-rabbits-change.md b/.changeset/little-rabbits-change.md new file mode 100644 index 000000000..63083e1ed --- /dev/null +++ b/.changeset/little-rabbits-change.md @@ -0,0 +1,12 @@ +--- +"@hi-ui/core": minor +"@hi-ui/container-context": minor +"@hi-ui/drawer": minor +"@hi-ui/hiui": minor +"@hi-ui/loading": minor +"@hi-ui/modal": minor +"@hi-ui/preview": minor +"@hi-ui/provider": minor +--- + +feat(portal-context): Provider 增加 portal 参数,支持配置全局 container (#3060) diff --git a/packages/core/core/package.json b/packages/core/core/package.json index 51d288763..7db5b834e 100644 --- a/packages/core/core/package.json +++ b/packages/core/core/package.json @@ -45,6 +45,7 @@ "devDependencies": {}, "dependencies": { "@hi-ui/core-css": "^4.1.5", - "@hi-ui/locale-context": "^4.0.8" + "@hi-ui/locale-context": "^4.0.8", + "@hi-ui/portal-context": "^4.0.0" } } diff --git a/packages/core/core/src/index.ts b/packages/core/core/src/index.ts index e9f7afbbd..62fb093b8 100644 --- a/packages/core/core/src/index.ts +++ b/packages/core/core/src/index.ts @@ -73,3 +73,6 @@ export type HiBaseSizeEnum = ValueOf // 将 core 设为 peer:保证 context 实例引用一致性 export { useLocaleContext, LocaleProvider } from '@hi-ui/locale-context' export type { UseLocaleContext, LocaleProviderProps } from '@hi-ui/locale-context' + +export { usePortalContext, PortalProvider } from '@hi-ui/portal-context' +export type { UsePortalContext, PortalProviderProps } from '@hi-ui/portal-context' diff --git a/packages/ui/drawer/src/Drawer.tsx b/packages/ui/drawer/src/Drawer.tsx index 32c359fc6..0e9178545 100644 --- a/packages/ui/drawer/src/Drawer.tsx +++ b/packages/ui/drawer/src/Drawer.tsx @@ -1,7 +1,7 @@ import React, { forwardRef, useCallback, useEffect } from 'react' import { cx, getPrefixCls, getPrefixStyleVar } from '@hi-ui/classname' import { __DEV__ } from '@hi-ui/env' -import { HiBaseHTMLProps } from '@hi-ui/core' +import { HiBaseHTMLProps, usePortalContext } from '@hi-ui/core' import { CSSTransition } from 'react-transition-group' import { Portal } from '@hi-ui/portal' import { useModal, UseModalProps } from '@hi-ui/modal' @@ -33,7 +33,7 @@ export const Drawer = forwardRef( onExited: onExitedProp, title, footer, - container, + container: containerProp, closeIcon = defaultCloseIcon, width, height, @@ -51,6 +51,8 @@ export const Drawer = forwardRef( ) => { const [transitionVisible, transitionVisibleAction] = useToggle(false) const [transitionExited, transitionExitedAction] = useToggle(true) + const globalContainer = usePortalContext()?.container + const container = containerProp ?? globalContainer const { rootProps, getModalProps, getModalWrapperProps } = useModal({ ...rest, diff --git a/packages/ui/loading/src/Loading.tsx b/packages/ui/loading/src/Loading.tsx index bb80c766d..e71c49e11 100644 --- a/packages/ui/loading/src/Loading.tsx +++ b/packages/ui/loading/src/Loading.tsx @@ -3,7 +3,7 @@ import { CSSTransition } from 'react-transition-group' import { cx, getPrefixCls } from '@hi-ui/classname' import { __DEV__ } from '@hi-ui/env' import { Portal } from '@hi-ui/portal' -import { HiBaseHTMLProps, HiBaseSizeEnum } from '@hi-ui/core' +import { HiBaseHTMLProps, HiBaseSizeEnum, usePortalContext } from '@hi-ui/core' import { useLatestCallback } from '@hi-ui/use-latest' import Spinner from '@hi-ui/spinner' import { useLoading } from './use-loading' @@ -18,7 +18,7 @@ export const Loading = forwardRef( className, children, role = _role, - container, + container: containerProp, content, visible = true, full = false, @@ -38,6 +38,9 @@ export const Loading = forwardRef( ) => { const { internalVisible, setInternalVisible } = useLoading({ visible, delay }) + const globalContainer = usePortalContext()?.container + const container = containerProp ?? globalContainer + useImperativeHandle(innerRef, () => ({ close: () => setInternalVisible(false), })) diff --git a/packages/ui/modal/src/Modal.tsx b/packages/ui/modal/src/Modal.tsx index b37e21984..f3115b0e0 100644 --- a/packages/ui/modal/src/Modal.tsx +++ b/packages/ui/modal/src/Modal.tsx @@ -1,6 +1,6 @@ import React, { useEffect, forwardRef, useCallback, useImperativeHandle } from 'react' import { cx, getPrefixCls } from '@hi-ui/classname' -import { HiBaseHTMLProps, HiBaseSizeEnum, useLocaleContext } from '@hi-ui/core' +import { HiBaseHTMLProps, HiBaseSizeEnum, useLocaleContext, usePortalContext } from '@hi-ui/core' import { __DEV__ } from '@hi-ui/env' import { CSSTransition } from 'react-transition-group' import { Portal } from '@hi-ui/portal' @@ -57,7 +57,7 @@ export const Modal = forwardRef( onClose, onCancel, onConfirm, - container, + container: containerProp, closeIcon = defaultCloseIcon, showMask = true, showHeaderDivider = true, @@ -74,6 +74,9 @@ export const Modal = forwardRef( ) => { const i18n = useLocaleContext() + const globalContainer = usePortalContext()?.container + const container = containerProp ?? globalContainer + const cancelText = isUndef(cancelTextProp) ? i18n.get('modal.cancelText') : cancelTextProp const confirmText = isUndef(confirmTextProp) ? i18n.get('modal.confirmText') : confirmTextProp diff --git a/packages/ui/portal-context/README.md b/packages/ui/portal-context/README.md new file mode 100644 index 000000000..4dc431622 --- /dev/null +++ b/packages/ui/portal-context/README.md @@ -0,0 +1,11 @@ +# `@hi-ui/portal-context` + +> TODO: description + +## Usage + +``` +const PortalContext = require('@hi-ui/portal-context'); + +// TODO: DEMONSTRATE API +``` diff --git a/packages/ui/portal-context/__tests__/portal-context.test.js b/packages/ui/portal-context/__tests__/portal-context.test.js new file mode 100644 index 000000000..3f29b2da5 --- /dev/null +++ b/packages/ui/portal-context/__tests__/portal-context.test.js @@ -0,0 +1,5 @@ +const PortalContext = require('../src') + +describe('@hi-ui/portal-context', () => { + it('needs tests', () => {}) +}) diff --git a/packages/ui/portal-context/hi-docs.config.mdx b/packages/ui/portal-context/hi-docs.config.mdx new file mode 100644 index 000000000..9eb1b9a64 --- /dev/null +++ b/packages/ui/portal-context/hi-docs.config.mdx @@ -0,0 +1,15 @@ +# PortalContext 上下文 + +容器设置上下文。 + +## 何时使用 + +组件使用场景中文介绍 + +## 使用示例 + + + +## Props + + diff --git a/packages/ui/portal-context/jest.config.js b/packages/ui/portal-context/jest.config.js new file mode 100644 index 000000000..e33c14b5d --- /dev/null +++ b/packages/ui/portal-context/jest.config.js @@ -0,0 +1 @@ +module.exports = require('../../../jest.config') diff --git a/packages/ui/portal-context/package.json b/packages/ui/portal-context/package.json new file mode 100644 index 000000000..031673f4a --- /dev/null +++ b/packages/ui/portal-context/package.json @@ -0,0 +1,54 @@ +{ + "name": "@hi-ui/portal-context", + "version": "4.0.0", + "description": "A sub-package for @hi-ui/hiui.", + "keywords": [], + "author": "HiUI ", + "homepage": "https://github.com/XiaoMi/hiui/tree/master/packages/ui/container-context#readme", + "license": "MIT", + "directories": { + "lib": "lib", + "test": "__tests__" + }, + "files": [ + "lib" + ], + "main": "lib/cjs/index.js", + "module": "lib/esm/index.js", + "types": "lib/types/index.d.ts", + "typings": "lib/types/index.d.ts", + "exports": { + ".": { + "require": "./lib/cjs/index.js", + "default": "./lib/esm/index.js" + } + }, + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/XiaoMi/hiui.git" + }, + "scripts": { + "test": "jest", + "clean": "rimraf lib", + "prebuild": "yarn clean", + "build:esm": "hi-build ./src/index.ts --format esm -d ./lib/esm", + "build:cjs": "hi-build ./src/index.ts --format cjs -d ./lib/cjs", + "build:types": "tsc --emitDeclarationOnly --declaration --declarationDir lib/types", + "build": "concurrently yarn:build:*" + }, + "bugs": { + "url": "https://github.com/XiaoMi/hiui/issues" + }, + "dependencies": {}, + "peerDependencies": { + "react": ">=16.8.6", + "react-dom": ">=16.8.6" + }, + "devDependencies": { + "react": "^17.0.1", + "react-dom": "^17.0.1" + } +} diff --git a/packages/ui/portal-context/src/PortalContext.tsx b/packages/ui/portal-context/src/PortalContext.tsx new file mode 100644 index 000000000..cc1ad4650 --- /dev/null +++ b/packages/ui/portal-context/src/PortalContext.tsx @@ -0,0 +1,11 @@ +import { createContext, useContext } from 'react' + +export const PortalContext = createContext(null) + +export const usePortalContext = () => { + const context = useContext(PortalContext) + + return context +} + +export type UsePortalContext = { container?: HTMLElement | null | undefined } | null | undefined diff --git a/packages/ui/portal-context/src/PortalProvider.tsx b/packages/ui/portal-context/src/PortalProvider.tsx new file mode 100644 index 000000000..b07ac6fa5 --- /dev/null +++ b/packages/ui/portal-context/src/PortalProvider.tsx @@ -0,0 +1,18 @@ +import React from 'react' +import { PortalContext, UsePortalContext } from './PortalContext' +import { __DEV__ } from '@hi-ui/env' + +export const PortalProvider: React.FC = ({ children, portal }) => { + return {children} +} + +export interface PortalProviderProps { + /** + * 指定 portal 的容器 + */ + portal?: UsePortalContext +} + +if (__DEV__) { + PortalProvider.displayName = 'PortalProvider' +} diff --git a/packages/ui/portal-context/src/index.ts b/packages/ui/portal-context/src/index.ts new file mode 100644 index 000000000..b8bb08a2c --- /dev/null +++ b/packages/ui/portal-context/src/index.ts @@ -0,0 +1,4 @@ +export * from './PortalContext' +export * from './PortalProvider' + +export { PortalProvider as default } from './PortalProvider' diff --git a/packages/ui/portal-context/stories/basic.stories.tsx b/packages/ui/portal-context/stories/basic.stories.tsx new file mode 100644 index 000000000..798c4a5b4 --- /dev/null +++ b/packages/ui/portal-context/stories/basic.stories.tsx @@ -0,0 +1,16 @@ +import React, { useContext } from 'react' +import { PortalContext } from '../src' + +/** + * @title 基础用法 + */ +export const Basic = () => { + useContext(PortalContext) + + return ( + <> +

Basic

+
+ + ) +} diff --git a/packages/ui/portal-context/stories/index.stories.tsx b/packages/ui/portal-context/stories/index.stories.tsx new file mode 100644 index 000000000..a856fc7e8 --- /dev/null +++ b/packages/ui/portal-context/stories/index.stories.tsx @@ -0,0 +1,8 @@ +import React from 'react' + +export * from './basic.stories' + +export default { + title: 'Private(暂不对外)/PortalContext', + decorators: [(story: Function) =>
{story()}
], +} diff --git a/packages/ui/portal-context/tsconfig.json b/packages/ui/portal-context/tsconfig.json new file mode 100644 index 000000000..f7bbdb2fe --- /dev/null +++ b/packages/ui/portal-context/tsconfig.json @@ -0,0 +1,4 @@ +{ + "extends": "../../../tsconfig.json", + "include": ["./src"] +} diff --git a/packages/ui/preview/src/Preview.tsx b/packages/ui/preview/src/Preview.tsx index 8f7bf5ae1..608368fd5 100644 --- a/packages/ui/preview/src/Preview.tsx +++ b/packages/ui/preview/src/Preview.tsx @@ -5,7 +5,7 @@ import { Portal } from '@hi-ui/portal' import { Watermark, WatermarkProps } from '@hi-ui/watermark' import { CSSTransition } from 'react-transition-group' import { useUncontrolledState } from '@hi-ui/use-uncontrolled-state' -import { HiBaseHTMLProps } from '@hi-ui/core' +import { HiBaseHTMLProps, usePortalContext } from '@hi-ui/core' import { useLatestCallback } from '@hi-ui/use-latest' import { ZoomInOutlined, @@ -46,11 +46,16 @@ export const Preview = forwardRef( src, watermarkProps, disabledDownload = false, + container: containerProp, + disabledPortal = false, }, ref ) => { const cls = cx(prefixCls, className) + const globalContainer = usePortalContext()?.container + const container = containerProp ?? globalContainer + const [active, setActive] = useUncontrolledState(defaultCurrent || 0, current, onPreviewChange) const [isMoving, setIsMoving] = useState(false) @@ -199,7 +204,7 @@ export const Preview = forwardRef( ) return ( - +
, 'onError'> { * 当前预览图片索引(受控) */ onPreviewChange?: (current: number) => void + /** + * 指定 portal 的容器 + */ + container?: HTMLElement | null + /** + * 是否禁用 portal + */ + disabledPortal?: boolean } if (__DEV__) { diff --git a/packages/ui/provider/src/Provider.tsx b/packages/ui/provider/src/Provider.tsx index 34c307e14..fdb1b4960 100644 --- a/packages/ui/provider/src/Provider.tsx +++ b/packages/ui/provider/src/Provider.tsx @@ -1,6 +1,11 @@ import React, { useEffect } from 'react' import { __DEV__ } from '@hi-ui/env' -import { LocaleProvider, LocaleProviderProps } from '@hi-ui/core' +import { + LocaleProvider, + LocaleProviderProps, + PortalProvider, + PortalProviderProps, +} from '@hi-ui/core' import { DesignSystemAccentColorEnum, DesignSystemProps } from './types' import { createSystem, extendsTheme } from './theme' import { getAccentColorTheme } from './accent-color' @@ -13,6 +18,7 @@ export const Provider: React.FC & { extends: ProviderExtendsFunc languages, accentColor, theme, + portal, }) => { /** * global css var config @@ -31,13 +37,18 @@ export const Provider: React.FC & { extends: ProviderExtendsFunc }, [accentColor, theme]) return ( - - {children} - + + + {children} + + ) } -export interface ProviderProps extends LocaleProviderProps, ThemeProviderProps {} +export interface ProviderProps + extends LocaleProviderProps, + PortalProviderProps, + ThemeProviderProps {} interface ThemeProviderProps { /**