From fb20b7b1a28c0581e2fe7a7819c20fd8956742de Mon Sep 17 00:00:00 2001 From: FlowerBlackG Date: Thu, 9 Oct 2025 20:18:20 +0800 Subject: [PATCH 01/10] feat(dialog): add sizeDraggable to props #3634 --- packages/components/dialog/Dialog.tsx | 14 ++ packages/components/dialog/defaultProps.ts | 2 +- packages/components/dialog/dialog.en-US.md | 1 + packages/components/dialog/dialog.md | 1 + .../components/dialog/hooks/useDialogDrag.ts | 22 +- .../dialog/hooks/useDialogResize.ts | 219 ++++++++++++++++++ packages/components/dialog/type.ts | 12 + packages/components/hooks/useMouseEvent.ts | 4 +- 8 files changed, 271 insertions(+), 4 deletions(-) create mode 100644 packages/components/dialog/hooks/useDialogResize.ts diff --git a/packages/components/dialog/Dialog.tsx b/packages/components/dialog/Dialog.tsx index 50f2a818f3..7e1e3bafa8 100644 --- a/packages/components/dialog/Dialog.tsx +++ b/packages/components/dialog/Dialog.tsx @@ -19,6 +19,7 @@ import useLockStyle from './hooks/useLockStyle'; import { parseValueToPx } from './utils'; import type { StyledProps } from '../common'; import type { DialogInstance, TdDialogProps } from './type'; +import useDialogResize from './hooks/useDialogResize'; export interface DialogProps extends TdDialogProps, StyledProps { isPlugin?: boolean; // 是否以插件形式调用 @@ -39,6 +40,8 @@ const Dialog = forwardRef((originalProps, ref) => { const [state, setState] = useSetState({ isPlugin: false, ...restProps }); const [local] = useLocaleReceiver('dialog'); + const dragResizing = useRef(false); + const { className, dialogClassName, @@ -77,6 +80,13 @@ const Dialog = forwardRef((originalProps, ref) => { useLockStyle({ preventScrollThrough, visible, mode, showInAttachedElement }); useDialogEsc(visible, wrapRef); useDialogPosition(visible, dialogCardRef); + + useDialogResize({ + dialogCardRef, + sizeDraggableProps: mode === 'modeless' ? props.sizeDraggable : false, + onDragResizeChange(resizing) { dragResizing.current = resizing; }, + }); + useDialogDrag({ dialogCardRef, canDraggable: draggable && mode === 'modeless', @@ -113,6 +123,10 @@ const Dialog = forwardRef((originalProps, ref) => { } const onMaskClick = (e: React.MouseEvent) => { + if (dragResizing.current) { + return; + } + if (showOverlay && (closeOnOverlayClick ?? local.closeOnOverlayClick)) { // 判断点击事件初次点击是否为内容区域 if (contentClickRef.current) { diff --git a/packages/components/dialog/defaultProps.ts b/packages/components/dialog/defaultProps.ts index 919abbcbf7..4eb9713f67 100644 --- a/packages/components/dialog/defaultProps.ts +++ b/packages/components/dialog/defaultProps.ts @@ -21,5 +21,5 @@ export const dialogDefaultProps: TdDialogProps = { preventScrollThrough: true, showInAttachedElement: false, showOverlay: true, - lazy: true, + sizeDraggable: false, }; diff --git a/packages/components/dialog/dialog.en-US.md b/packages/components/dialog/dialog.en-US.md index 4f238034b4..aa770db5bd 100644 --- a/packages/components/dialog/dialog.en-US.md +++ b/packages/components/dialog/dialog.en-US.md @@ -38,6 +38,7 @@ placement | String | top | options: top/center | N preventScrollThrough | Boolean | true | \- | N showInAttachedElement | Boolean | false | \- | N showOverlay | Boolean | true | \- | N +sizeDraggable | Boolean / Object | false | allow resizing drawer width/height, set max or min to limit size.。Typescript:`boolean \| SizeDragLimit` `interface SizeDragLimit { maxWidth: number\|undefined, minWidth: number\|undefined, maxHeight: number\|undefined, minHeight: number\|undefined }`。[see more ts definition](https://github.com/Tencent/tdesign-react/blob/develop/packages/components/dialog/type.ts) | N theme | String | default | options: default/info/warning/danger/success | N top | String / Number | - | \- | N visible | Boolean | - | \- | N diff --git a/packages/components/dialog/dialog.md b/packages/components/dialog/dialog.md index bf479a31de..cd5a959f7f 100644 --- a/packages/components/dialog/dialog.md +++ b/packages/components/dialog/dialog.md @@ -59,6 +59,7 @@ placement | String | top | 对话框位置,内置两种:垂直水平居中 preventScrollThrough | Boolean | true | 防止滚动穿透 | N showInAttachedElement | Boolean | false | 仅在挂载元素中显示抽屉,默认在浏览器可视区域显示。父元素需要有定位属性,如:position: relative | N showOverlay | Boolean | true | 是否显示遮罩层 | N +sizeDraggable | Boolean / Object | false | 弹窗大小可拖拽调整。`sizeDraggable.maxWidth`、`sizeDraggable.minWidth`、`sizeDraggable.maxHeight`、`sizeDraggable.minHeight` 用于控制拖拽尺寸大小限制。。TS 类型:`boolean \| SizeDragLimit` `interface SizeDragLimit { maxWidth: number\|undefined, minWidth: number\|undefined, maxHeight: number\|undefined, minHeight: number\|undefined }`。[详细类型定义](https://github.com/Tencent/tdesign-react/blob/develop/packages/components/dialog/type.ts) | N theme | String | default | 对话框风格。可选项:default/info/warning/danger/success | N top | String / Number | - | 用于弹框具体窗口顶部的距离,优先级大于 placement | N visible | Boolean | - | 控制对话框是否显示 | N diff --git a/packages/components/dialog/hooks/useDialogDrag.ts b/packages/components/dialog/hooks/useDialogDrag.ts index decff73b17..e7d5f3439e 100644 --- a/packages/components/dialog/hooks/useDialogDrag.ts +++ b/packages/components/dialog/hooks/useDialogDrag.ts @@ -6,6 +6,8 @@ interface DialogDragProps { canDraggable?: boolean; } +const RESERVED_BORDER_WIDTH = 8; // 保留边框宽度,避免拖拽时误操作 + const useDialogDrag = (props: DialogDragProps) => { const { dialogCardRef, canDraggable } = props; @@ -15,18 +17,31 @@ const useDialogDrag = (props: DialogDragProps) => { const dragOffset = useRef({ x: 0, y: 0 }); + const moving = useRef(false); + useMouseEvent(dialogCardRef, { enabled: canDraggable, onDown: (e) => { const { offsetLeft, offsetTop, offsetWidth, offsetHeight, style } = dialogCardRef.current; - if (offsetWidth > screenWidth || offsetHeight > screenHeight) return; + if (offsetWidth > screenWidth || offsetHeight > screenHeight) + return; + + if (e.clientX - offsetLeft <= RESERVED_BORDER_WIDTH || e.clientX - offsetLeft >= offsetWidth - RESERVED_BORDER_WIDTH) + return; + if (e.clientY - offsetTop <= RESERVED_BORDER_WIDTH || e.clientY - offsetTop >= offsetHeight - RESERVED_BORDER_WIDTH) + return; + style.cursor = 'move'; + moving.current = true; dragOffset.current = { x: e.clientX - offsetLeft, y: e.clientY - offsetTop, }; }, onMove: (e) => { + if (!moving.current) + return; + const { offsetWidth, offsetHeight, style } = dialogCardRef.current; let diffX = e.clientX - dragOffset.current.x; let diffY = e.clientY - dragOffset.current.y; @@ -40,7 +55,10 @@ const useDialogDrag = (props: DialogDragProps) => { style.top = `${diffY}px`; }, onUp: () => { - dialogCardRef.current.style.cursor = 'default'; + if (moving.current) { + moving.current = false; + dialogCardRef.current.style.cursor = 'default'; + } }, }); }; diff --git a/packages/components/dialog/hooks/useDialogResize.ts b/packages/components/dialog/hooks/useDialogResize.ts new file mode 100644 index 0000000000..53851213d7 --- /dev/null +++ b/packages/components/dialog/hooks/useDialogResize.ts @@ -0,0 +1,219 @@ +import React from "react"; +import useMouseEvent from "../../hooks/useMouseEvent"; +import { SizeDragLimit } from "../type"; + + +const RESIZE_BORDER_WIDTH = 8; // 边框宽度,拖拽时的感应区域 + + +interface DialogResizeProps { + dialogCardRef: React.MutableRefObject; + sizeDraggableProps: boolean | SizeDragLimit; + onDragResizeChange: (resizing: boolean) => void; +} + + +type ResizeDirection = 'n' | 's' | 'e' | 'w' | 'ne' | 'nw' | 'se' | 'sw' | false; + + +function mouseOnBorder( + e: React.MouseEvent, + dialogCardRef: React.MutableRefObject +): ResizeDirection { + const mouseX = e.clientX; + const mouseY = e.clientY; + const { left, top, width, height } = dialogCardRef.current.getBoundingClientRect(); + + const borderWidth = RESIZE_BORDER_WIDTH; + const onLeftBorder = mouseX >= left - borderWidth && mouseX <= left + borderWidth; + const onRightBorder = mouseX >= left + width - borderWidth && mouseX <= left + width + borderWidth; + const onTopBorder = mouseY >= top - borderWidth && mouseY <= top + borderWidth; + const onBottomBorder = mouseY >= top + height - borderWidth && mouseY <= top + height + borderWidth; + if (onLeftBorder && onTopBorder) + return 'nw'; + if (onRightBorder && onBottomBorder) + return 'se'; + if (onRightBorder && onTopBorder) + return 'ne'; + if (onLeftBorder && onBottomBorder) + return 'sw'; + if (onLeftBorder) + return 'w'; + if (onRightBorder) + return 'e'; + if (onTopBorder) + return 'n'; + if (onBottomBorder) + return 's'; + return false; +} + + +const useDialogResize = (props: DialogResizeProps) => { + const { dialogCardRef, sizeDraggableProps } = props; + + const validWindow = typeof window === 'object'; + + const getWindowHeight = () => (validWindow ? window.innerHeight || document.documentElement.clientHeight : undefined); + const getWindowWidth = () => (validWindow ? window.innerWidth || document.documentElement.clientWidth : undefined); + + const dialogSize = React.useRef({ x: 0, y: 0, width: 0, height: 0 }); + + const resizingDirection = React.useRef(false); + + const minWidth = React.useRef(0); + const maxWidth = React.useRef(Number.MAX_VALUE); + const minHeight = React.useRef(undefined); // If undefined, set to current height on first drag (lower than which causes buttons overflow). + const maxHeight = React.useRef(Number.MAX_VALUE); + + + React.useEffect(() => { + if (sizeDraggableProps === undefined || typeof sizeDraggableProps === 'boolean') { + minWidth.current = undefined; + maxWidth.current = Number.MAX_VALUE; + minHeight.current = 0; + maxHeight.current = Number.MAX_VALUE; + return; + } + + if (sizeDraggableProps.maxHeight !== undefined) { + maxHeight.current = sizeDraggableProps.maxHeight; + } + + if (sizeDraggableProps.minHeight !== undefined) { + minHeight.current = sizeDraggableProps.minHeight; + } + + if (sizeDraggableProps.maxWidth !== undefined) { + maxWidth.current = sizeDraggableProps.maxWidth; + } + + if (sizeDraggableProps.minWidth !== undefined) { + minWidth.current = sizeDraggableProps.minWidth; + } + + }, [sizeDraggableProps]); + + + useMouseEvent(dialogCardRef, { + enabled: sizeDraggableProps !== undefined && sizeDraggableProps !== false, + alwaysEmitOnMove: sizeDraggableProps !== undefined && sizeDraggableProps !== false, + onDown: (e: React.MouseEvent) => { + if (minHeight.current === undefined && dialogCardRef.current) { + minHeight.current = dialogCardRef.current.offsetHeight; + } + + resizingDirection.current = mouseOnBorder(e, dialogCardRef); + if (resizingDirection.current !== false) { + dialogSize.current = { + x: dialogCardRef.current.offsetLeft, + y: dialogCardRef.current.offsetTop, + width: dialogCardRef.current.offsetWidth, + height: dialogCardRef.current.offsetHeight, + }; + + props.onDragResizeChange(true); + + e.stopPropagation(); + e.preventDefault(); + } + }, + onMove: (e: React.MouseEvent) => { + // Check whether we should update cursor style. + const direction = mouseOnBorder(e, dialogCardRef); + if (direction) { + let cursor = ''; + if (direction === 'n' || direction === 's') + cursor = `${direction}-resize`; + else if (direction === 'e' || direction === 'w') + cursor = `${direction}-resize`; + else if (direction === 'ne' || direction === 'sw') + cursor = 'nesw-resize'; + else if (direction === 'nw' || direction === 'se') + cursor = 'nwse-resize'; + dialogCardRef.current.style.cursor = cursor; + } else { + if (resizingDirection.current === false) + dialogCardRef.current.style.cursor = 'default'; + } + + if (resizingDirection.current === false) + return; + + + // Do resize. + const dir = resizingDirection.current; + const style = dialogCardRef.current.style; + + style.position = 'absolute'; + + const mouseX = e.clientX; + const mouseY = e.clientY; + + if (mouseX <= 4 || mouseY <= 4 || mouseX >= getWindowWidth() - 4 || mouseY >= getWindowHeight() - 4) { + return; // Just ignore. + } + + let nextHeight = dialogCardRef.current.offsetHeight; + let nextWidth = dialogCardRef.current.offsetWidth; + let nextTop = dialogCardRef.current.offsetTop; + let nextLeft = dialogCardRef.current.offsetLeft; + + + if (dir.includes('n')) { // upper + const deltaY = mouseY - dialogSize.current.y; + nextHeight = dialogSize.current.height - deltaY; + nextTop = dialogSize.current.y + deltaY; + } + else if (dir.includes('s')) { // lower + const deltaY = mouseY - dialogSize.current.y - dialogSize.current.height; + nextHeight = dialogSize.current.height + deltaY; + } + + if (dir.includes('w')) { // left + const deltaX = mouseX - dialogSize.current.x; + nextWidth = dialogSize.current.width - deltaX; + nextLeft = dialogSize.current.x + deltaX; + } + else if (dir.includes('e')) { // right + const deltaX = mouseX - dialogSize.current.x - dialogSize.current.width; + nextWidth = dialogSize.current.width + deltaX; + } + + + style.left = `${nextLeft}px`; + style.width = `${nextWidth}px`; + dialogSize.current.x = nextLeft; + dialogSize.current.width = nextWidth; + + + if (nextHeight >= minHeight.current) { + style.top = `${nextTop}px`; + style.height = `${nextHeight}px`; + dialogSize.current.y = nextTop; + dialogSize.current.height = nextHeight; + } + + e.stopPropagation(); + e.preventDefault(); + + }, + onUp: (e: React.MouseEvent) => { + + if (resizingDirection.current === false) + return; + + resizingDirection.current = false; + + // prevent triggering overlay click. + setTimeout(() => { + props.onDragResizeChange(false); + }, 0); + + e.stopPropagation(); + e.preventDefault(); + }, + }); +}; + +export default useDialogResize; diff --git a/packages/components/dialog/type.ts b/packages/components/dialog/type.ts index 61e082508d..95b71f9ae0 100644 --- a/packages/components/dialog/type.ts +++ b/packages/components/dialog/type.ts @@ -111,6 +111,11 @@ export interface TdDialogProps { * @default true */ showOverlay?: boolean; + /** + * 弹窗大小可拖拽调整。`sizeDraggable.maxWidth`、`sizeDraggable.minWidth`、`sizeDraggable.maxHeight`、`sizeDraggable.minHeight` 用于控制拖拽尺寸大小限制。 + * @default false + */ + sizeDraggable?: boolean | SizeDragLimit; /** * 对话框风格 * @default default @@ -230,6 +235,13 @@ export interface DialogInstance { update: (props: DialogOptions) => void; } +export interface SizeDragLimit { + maxWidth: number | undefined; + minWidth: number | undefined; + maxHeight: number | undefined; + minHeight: number | undefined; +} + export type DialogEventSource = 'esc' | 'close-btn' | 'cancel' | 'overlay'; export interface DialogCloseContext { diff --git a/packages/components/hooks/useMouseEvent.ts b/packages/components/hooks/useMouseEvent.ts index 9855f0e4bc..fd7b59105c 100644 --- a/packages/components/hooks/useMouseEvent.ts +++ b/packages/components/hooks/useMouseEvent.ts @@ -22,6 +22,8 @@ type MouseEventOptions = { onUp?: (e: MouseCallback, ctx: MouseContext) => void; onEnter?: (e: MouseCallback, ctx: MouseContext) => void; onLeave?: (e: MouseCallback, ctx: MouseContext) => void; + + alwaysEmitOnMove?: boolean }; const useMouseEvent = (elementRef: React.RefObject, options: MouseEventOptions) => { @@ -66,7 +68,7 @@ const useMouseEvent = (elementRef: React.RefObject, options: MouseE }; const handleMouseMove = (e: MouseEventLike) => { - if (!isMovingRef.current) return; + if (!isMovingRef.current && !options.alwaysEmitOnMove) return; e.preventDefault(); emitMouseChange(e, options.onMove); }; From 8b53c6fbe1af8683f334c032e57571fb9fae0e6f Mon Sep 17 00:00:00 2001 From: FlowerBlackG Date: Thu, 9 Oct 2025 20:25:12 +0800 Subject: [PATCH 02/10] style(dialog): lint --- packages/components/dialog/hooks/useDialogResize.ts | 6 ++---- packages/components/dialog/type.ts | 2 +- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/packages/components/dialog/hooks/useDialogResize.ts b/packages/components/dialog/hooks/useDialogResize.ts index 53851213d7..71777e8820 100644 --- a/packages/components/dialog/hooks/useDialogResize.ts +++ b/packages/components/dialog/hooks/useDialogResize.ts @@ -132,10 +132,8 @@ const useDialogResize = (props: DialogResizeProps) => { else if (direction === 'nw' || direction === 'se') cursor = 'nwse-resize'; dialogCardRef.current.style.cursor = cursor; - } else { - if (resizingDirection.current === false) + } else if (resizingDirection.current === false) dialogCardRef.current.style.cursor = 'default'; - } if (resizingDirection.current === false) return; @@ -143,7 +141,7 @@ const useDialogResize = (props: DialogResizeProps) => { // Do resize. const dir = resizingDirection.current; - const style = dialogCardRef.current.style; + const {style} = dialogCardRef.current; style.position = 'absolute'; diff --git a/packages/components/dialog/type.ts b/packages/components/dialog/type.ts index 95b71f9ae0..0564ccdb8b 100644 --- a/packages/components/dialog/type.ts +++ b/packages/components/dialog/type.ts @@ -235,7 +235,7 @@ export interface DialogInstance { update: (props: DialogOptions) => void; } -export interface SizeDragLimit { +interface SizeDragLimit { maxWidth: number | undefined; minWidth: number | undefined; maxHeight: number | undefined; From 5bfe0085928ef5dc444a6a47d553570b6d9ce07c Mon Sep 17 00:00:00 2001 From: FlowerBlackG Date: Thu, 9 Oct 2025 21:12:10 +0800 Subject: [PATCH 03/10] fix(dialog): rename SizeDragLimit to DialogSizeDragLimit so it won't conflict --- packages/components/dialog/dialog.en-US.md | 2 +- packages/components/dialog/dialog.md | 2 +- packages/components/dialog/hooks/useDialogResize.ts | 4 ++-- packages/components/dialog/type.ts | 6 +++--- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/components/dialog/dialog.en-US.md b/packages/components/dialog/dialog.en-US.md index aa770db5bd..e8dcab7e11 100644 --- a/packages/components/dialog/dialog.en-US.md +++ b/packages/components/dialog/dialog.en-US.md @@ -38,7 +38,7 @@ placement | String | top | options: top/center | N preventScrollThrough | Boolean | true | \- | N showInAttachedElement | Boolean | false | \- | N showOverlay | Boolean | true | \- | N -sizeDraggable | Boolean / Object | false | allow resizing drawer width/height, set max or min to limit size.。Typescript:`boolean \| SizeDragLimit` `interface SizeDragLimit { maxWidth: number\|undefined, minWidth: number\|undefined, maxHeight: number\|undefined, minHeight: number\|undefined }`。[see more ts definition](https://github.com/Tencent/tdesign-react/blob/develop/packages/components/dialog/type.ts) | N +sizeDraggable | Boolean / Object | false | allow resizing drawer width/height, set max or min to limit size.。Typescript:`boolean \| DialogSizeDragLimit` `interface DialogSizeDragLimit { maxWidth: number\|undefined, minWidth: number\|undefined, maxHeight: number\|undefined, minHeight: number\|undefined }`。[see more ts definition](https://github.com/Tencent/tdesign-react/blob/develop/packages/components/dialog/type.ts) | N theme | String | default | options: default/info/warning/danger/success | N top | String / Number | - | \- | N visible | Boolean | - | \- | N diff --git a/packages/components/dialog/dialog.md b/packages/components/dialog/dialog.md index cd5a959f7f..fd31969f2e 100644 --- a/packages/components/dialog/dialog.md +++ b/packages/components/dialog/dialog.md @@ -59,7 +59,7 @@ placement | String | top | 对话框位置,内置两种:垂直水平居中 preventScrollThrough | Boolean | true | 防止滚动穿透 | N showInAttachedElement | Boolean | false | 仅在挂载元素中显示抽屉,默认在浏览器可视区域显示。父元素需要有定位属性,如:position: relative | N showOverlay | Boolean | true | 是否显示遮罩层 | N -sizeDraggable | Boolean / Object | false | 弹窗大小可拖拽调整。`sizeDraggable.maxWidth`、`sizeDraggable.minWidth`、`sizeDraggable.maxHeight`、`sizeDraggable.minHeight` 用于控制拖拽尺寸大小限制。。TS 类型:`boolean \| SizeDragLimit` `interface SizeDragLimit { maxWidth: number\|undefined, minWidth: number\|undefined, maxHeight: number\|undefined, minHeight: number\|undefined }`。[详细类型定义](https://github.com/Tencent/tdesign-react/blob/develop/packages/components/dialog/type.ts) | N +sizeDraggable | Boolean / Object | false | 弹窗大小可拖拽调整。`dialogSizeDragLimit.maxWidth`、`dialogSizeDragLimit.minWidth`、`dialogSizeDragLimit.maxHeight`、`dialogSizeDragLimit.minHeight` 用于控制拖拽尺寸大小限制。。TS 类型:`boolean \| DialogSizeDragLimit` `interface DialogSizeDragLimit { maxWidth: number\|undefined, minWidth: number\|undefined, maxHeight: number\|undefined, minHeight: number\|undefined }`。[详细类型定义](https://github.com/Tencent/tdesign-react/blob/develop/packages/components/dialog/type.ts) | N theme | String | default | 对话框风格。可选项:default/info/warning/danger/success | N top | String / Number | - | 用于弹框具体窗口顶部的距离,优先级大于 placement | N visible | Boolean | - | 控制对话框是否显示 | N diff --git a/packages/components/dialog/hooks/useDialogResize.ts b/packages/components/dialog/hooks/useDialogResize.ts index 71777e8820..82eebe03c4 100644 --- a/packages/components/dialog/hooks/useDialogResize.ts +++ b/packages/components/dialog/hooks/useDialogResize.ts @@ -1,6 +1,6 @@ import React from "react"; import useMouseEvent from "../../hooks/useMouseEvent"; -import { SizeDragLimit } from "../type"; +import { DialogSizeDragLimit } from "../type"; const RESIZE_BORDER_WIDTH = 8; // 边框宽度,拖拽时的感应区域 @@ -8,7 +8,7 @@ const RESIZE_BORDER_WIDTH = 8; // 边框宽度,拖拽时的感应区域 interface DialogResizeProps { dialogCardRef: React.MutableRefObject; - sizeDraggableProps: boolean | SizeDragLimit; + sizeDraggableProps: boolean | DialogSizeDragLimit; onDragResizeChange: (resizing: boolean) => void; } diff --git a/packages/components/dialog/type.ts b/packages/components/dialog/type.ts index 0564ccdb8b..3718f1a79b 100644 --- a/packages/components/dialog/type.ts +++ b/packages/components/dialog/type.ts @@ -112,10 +112,10 @@ export interface TdDialogProps { */ showOverlay?: boolean; /** - * 弹窗大小可拖拽调整。`sizeDraggable.maxWidth`、`sizeDraggable.minWidth`、`sizeDraggable.maxHeight`、`sizeDraggable.minHeight` 用于控制拖拽尺寸大小限制。 + * 弹窗大小可拖拽调整。`dialogSizeDragLimit.maxWidth`、`dialogSizeDragLimit.minWidth`、`dialogSizeDragLimit.maxHeight`、`dialogSizeDragLimit.minHeight` 用于控制拖拽尺寸大小限制。 * @default false */ - sizeDraggable?: boolean | SizeDragLimit; + sizeDraggable?: boolean | DialogSizeDragLimit; /** * 对话框风格 * @default default @@ -235,7 +235,7 @@ export interface DialogInstance { update: (props: DialogOptions) => void; } -interface SizeDragLimit { +export interface DialogSizeDragLimit { maxWidth: number | undefined; minWidth: number | undefined; maxHeight: number | undefined; From 67bc72bec34af23d4961b851b4c0ee246d702475 Mon Sep 17 00:00:00 2001 From: FlowerBlackG Date: Fri, 10 Oct 2025 15:23:12 +0800 Subject: [PATCH 04/10] chore(dialog): fix docs --- packages/components/dialog/dialog.en-US.md | 2 +- packages/components/dialog/dialog.md | 2 +- packages/components/dialog/type.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/components/dialog/dialog.en-US.md b/packages/components/dialog/dialog.en-US.md index e8dcab7e11..9f626ac7ca 100644 --- a/packages/components/dialog/dialog.en-US.md +++ b/packages/components/dialog/dialog.en-US.md @@ -38,7 +38,7 @@ placement | String | top | options: top/center | N preventScrollThrough | Boolean | true | \- | N showInAttachedElement | Boolean | false | \- | N showOverlay | Boolean | true | \- | N -sizeDraggable | Boolean / Object | false | allow resizing drawer width/height, set max or min to limit size.。Typescript:`boolean \| DialogSizeDragLimit` `interface DialogSizeDragLimit { maxWidth: number\|undefined, minWidth: number\|undefined, maxHeight: number\|undefined, minHeight: number\|undefined }`。[see more ts definition](https://github.com/Tencent/tdesign-react/blob/develop/packages/components/dialog/type.ts) | N +sizeDraggable | Boolean / Object | false | allow resizing dialog width/height, set max or min to limit size.。Typescript:`boolean \| DialogSizeDragLimit` `interface DialogSizeDragLimit { maxWidth: number\|undefined, minWidth: number\|undefined, maxHeight: number\|undefined, minHeight: number\|undefined }`。[see more ts definition](https://github.com/Tencent/tdesign-react/blob/develop/packages/components/dialog/type.ts) | N theme | String | default | options: default/info/warning/danger/success | N top | String / Number | - | \- | N visible | Boolean | - | \- | N diff --git a/packages/components/dialog/dialog.md b/packages/components/dialog/dialog.md index fd31969f2e..32064e5d55 100644 --- a/packages/components/dialog/dialog.md +++ b/packages/components/dialog/dialog.md @@ -59,7 +59,7 @@ placement | String | top | 对话框位置,内置两种:垂直水平居中 preventScrollThrough | Boolean | true | 防止滚动穿透 | N showInAttachedElement | Boolean | false | 仅在挂载元素中显示抽屉,默认在浏览器可视区域显示。父元素需要有定位属性,如:position: relative | N showOverlay | Boolean | true | 是否显示遮罩层 | N -sizeDraggable | Boolean / Object | false | 弹窗大小可拖拽调整。`dialogSizeDragLimit.maxWidth`、`dialogSizeDragLimit.minWidth`、`dialogSizeDragLimit.maxHeight`、`dialogSizeDragLimit.minHeight` 用于控制拖拽尺寸大小限制。。TS 类型:`boolean \| DialogSizeDragLimit` `interface DialogSizeDragLimit { maxWidth: number\|undefined, minWidth: number\|undefined, maxHeight: number\|undefined, minHeight: number\|undefined }`。[详细类型定义](https://github.com/Tencent/tdesign-react/blob/develop/packages/components/dialog/type.ts) | N +sizeDraggable | Boolean / Object | false | 弹窗大小可拖拽调整。`sizeDraggable.maxWidth`、`sizeDraggable.minWidth`、`sizeDraggable.maxHeight`、`sizeDraggable.minHeight` 用于控制拖拽尺寸大小限制。。TS 类型:`boolean \| DialogSizeDragLimit` `interface DialogSizeDragLimit { maxWidth: number\|undefined, minWidth: number\|undefined, maxHeight: number\|undefined, minHeight: number\|undefined }`。[详细类型定义](https://github.com/Tencent/tdesign-react/blob/develop/packages/components/dialog/type.ts) | N theme | String | default | 对话框风格。可选项:default/info/warning/danger/success | N top | String / Number | - | 用于弹框具体窗口顶部的距离,优先级大于 placement | N visible | Boolean | - | 控制对话框是否显示 | N diff --git a/packages/components/dialog/type.ts b/packages/components/dialog/type.ts index 3718f1a79b..d716d646eb 100644 --- a/packages/components/dialog/type.ts +++ b/packages/components/dialog/type.ts @@ -112,7 +112,7 @@ export interface TdDialogProps { */ showOverlay?: boolean; /** - * 弹窗大小可拖拽调整。`dialogSizeDragLimit.maxWidth`、`dialogSizeDragLimit.minWidth`、`dialogSizeDragLimit.maxHeight`、`dialogSizeDragLimit.minHeight` 用于控制拖拽尺寸大小限制。 + * 弹窗大小可拖拽调整。`sizeDraggable.maxWidth`、`sizeDraggable.minWidth`、`sizeDraggable.maxHeight`、`sizeDraggable.minHeight` 用于控制拖拽尺寸大小限制。 * @default false */ sizeDraggable?: boolean | DialogSizeDragLimit; From c049de54289c3fe90a40087f822999810267b9f0 Mon Sep 17 00:00:00 2001 From: FlowerBlackG Date: Fri, 17 Oct 2025 15:03:51 +0800 Subject: [PATCH 05/10] fix(dialog): no detect border when rendered somewhere strange --- packages/components/dialog/hooks/useDialogDrag.ts | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/packages/components/dialog/hooks/useDialogDrag.ts b/packages/components/dialog/hooks/useDialogDrag.ts index e7d5f3439e..a645c9342c 100644 --- a/packages/components/dialog/hooks/useDialogDrag.ts +++ b/packages/components/dialog/hooks/useDialogDrag.ts @@ -26,10 +26,13 @@ const useDialogDrag = (props: DialogDragProps) => { if (offsetWidth > screenWidth || offsetHeight > screenHeight) return; - if (e.clientX - offsetLeft <= RESERVED_BORDER_WIDTH || e.clientX - offsetLeft >= offsetWidth - RESERVED_BORDER_WIDTH) - return; - if (e.clientY - offsetTop <= RESERVED_BORDER_WIDTH || e.clientY - offsetTop >= offsetHeight - RESERVED_BORDER_WIDTH) - return; + + if (offsetLeft != 0 || offsetTop != 0 || offsetWidth != 0 || offsetHeight != 0) { + if (e.clientX - offsetLeft <= RESERVED_BORDER_WIDTH || e.clientX - offsetLeft >= offsetWidth - RESERVED_BORDER_WIDTH) + return; + if (e.clientY - offsetTop <= RESERVED_BORDER_WIDTH || e.clientY - offsetTop >= offsetHeight - RESERVED_BORDER_WIDTH) + return; + } style.cursor = 'move'; moving.current = true; From ce96eb565b452d6d7e11220c32d40f348973c377 Mon Sep 17 00:00:00 2001 From: GuanTouYu <36918894+FlowerBlackG@users.noreply.github.com> Date: Fri, 17 Oct 2025 15:04:50 +0800 Subject: [PATCH 06/10] Update packages/components/dialog/hooks/useDialogResize.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- packages/components/dialog/hooks/useDialogResize.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/components/dialog/hooks/useDialogResize.ts b/packages/components/dialog/hooks/useDialogResize.ts index 82eebe03c4..1c121498c0 100644 --- a/packages/components/dialog/hooks/useDialogResize.ts +++ b/packages/components/dialog/hooks/useDialogResize.ts @@ -63,7 +63,7 @@ const useDialogResize = (props: DialogResizeProps) => { const minWidth = React.useRef(0); const maxWidth = React.useRef(Number.MAX_VALUE); - const minHeight = React.useRef(undefined); // If undefined, set to current height on first drag (lower than which causes buttons overflow). + const minHeight = React.useRef(undefined); // If undefined, set to current height on first drag (lower than which causes buttons overflow). const maxHeight = React.useRef(Number.MAX_VALUE); From dc558d69b26da5e3becf828991b3a6d0d831424b Mon Sep 17 00:00:00 2001 From: FlowerBlackG Date: Fri, 17 Oct 2025 15:07:18 +0800 Subject: [PATCH 07/10] fix(dialog): set default minWidth to 0 (useDialogResize) --- packages/components/dialog/hooks/useDialogResize.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/components/dialog/hooks/useDialogResize.ts b/packages/components/dialog/hooks/useDialogResize.ts index 82eebe03c4..c02ba4a412 100644 --- a/packages/components/dialog/hooks/useDialogResize.ts +++ b/packages/components/dialog/hooks/useDialogResize.ts @@ -69,7 +69,7 @@ const useDialogResize = (props: DialogResizeProps) => { React.useEffect(() => { if (sizeDraggableProps === undefined || typeof sizeDraggableProps === 'boolean') { - minWidth.current = undefined; + minWidth.current = 0; maxWidth.current = Number.MAX_VALUE; minHeight.current = 0; maxHeight.current = Number.MAX_VALUE; From 51ad547167805eddc82197be8f24a2ffbe28f9a2 Mon Sep 17 00:00:00 2001 From: FlowerBlackG Date: Fri, 17 Oct 2025 15:09:08 +0800 Subject: [PATCH 08/10] fix(dialog): fix a bug that resizer might change cursor style when dragging (move) --- packages/components/dialog/hooks/useDialogResize.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/components/dialog/hooks/useDialogResize.ts b/packages/components/dialog/hooks/useDialogResize.ts index c02ba4a412..f759e70416 100644 --- a/packages/components/dialog/hooks/useDialogResize.ts +++ b/packages/components/dialog/hooks/useDialogResize.ts @@ -119,6 +119,9 @@ const useDialogResize = (props: DialogResizeProps) => { } }, onMove: (e: React.MouseEvent) => { + if (dialogCardRef.current.style.cursor === 'move') + return; + // Check whether we should update cursor style. const direction = mouseOnBorder(e, dialogCardRef); if (direction) { From de1e3647c94e5511864ba7ce9f36ae8850817b8c Mon Sep 17 00:00:00 2001 From: FlowerBlackG Date: Fri, 17 Oct 2025 15:13:26 +0800 Subject: [PATCH 09/10] fix(dialog): change some != to !== --- packages/components/dialog/hooks/useDialogDrag.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/components/dialog/hooks/useDialogDrag.ts b/packages/components/dialog/hooks/useDialogDrag.ts index a645c9342c..d0e2da7d15 100644 --- a/packages/components/dialog/hooks/useDialogDrag.ts +++ b/packages/components/dialog/hooks/useDialogDrag.ts @@ -27,7 +27,7 @@ const useDialogDrag = (props: DialogDragProps) => { return; - if (offsetLeft != 0 || offsetTop != 0 || offsetWidth != 0 || offsetHeight != 0) { + if (offsetLeft !== 0 || offsetTop !== 0 || offsetWidth !== 0 || offsetHeight !== 0) { if (e.clientX - offsetLeft <= RESERVED_BORDER_WIDTH || e.clientX - offsetLeft >= offsetWidth - RESERVED_BORDER_WIDTH) return; if (e.clientY - offsetTop <= RESERVED_BORDER_WIDTH || e.clientY - offsetTop >= offsetHeight - RESERVED_BORDER_WIDTH) From ad769b8709d99561db7f61e31eb3364e011f4e8c Mon Sep 17 00:00:00 2001 From: FlowerBlackG Date: Fri, 17 Oct 2025 16:02:44 +0800 Subject: [PATCH 10/10] fix(dialog): restore "lazy: true" to defaultProps --- packages/components/dialog/defaultProps.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/components/dialog/defaultProps.ts b/packages/components/dialog/defaultProps.ts index 4eb9713f67..8cfe577f57 100644 --- a/packages/components/dialog/defaultProps.ts +++ b/packages/components/dialog/defaultProps.ts @@ -21,5 +21,6 @@ export const dialogDefaultProps: TdDialogProps = { preventScrollThrough: true, showInAttachedElement: false, showOverlay: true, + lazy: true, sizeDraggable: false, };