This commit is contained in:
2026-05-25 17:08:18 +08:00
parent df501f6151
commit f1259b71b5
9178 changed files with 1626125 additions and 0 deletions
@@ -0,0 +1,7 @@
import * as React from 'react';
export type MemoChildrenProps = {
shouldUpdate: boolean;
children: React.ReactNode;
};
declare const _default: React.MemoExoticComponent<({ children }: MemoChildrenProps) => React.ReactElement<any, string | React.JSXElementConstructor<any>>>;
export default _default;
@@ -0,0 +1,6 @@
import * as React from 'react';
export default /*#__PURE__*/React.memo(({
children
}) => children, (_, {
shouldUpdate
}) => !shouldUpdate);
@@ -0,0 +1,16 @@
import React from 'react';
import type { IDialogPropTypes } from '../../IDialogPropTypes';
export interface PanelProps extends Omit<IDialogPropTypes, 'getOpenCount'> {
prefixCls: string;
ariaId?: string;
onMouseDown?: React.MouseEventHandler;
onMouseUp?: React.MouseEventHandler;
holderRef?: React.Ref<HTMLDivElement>;
/** Used for focus lock. When true and open, focus will lock into the panel */
isFixedPos?: boolean;
}
export type PanelRef = {
focus: () => void;
};
declare const Panel: React.ForwardRefExoticComponent<PanelProps & React.RefAttributes<PanelRef>>;
export default Panel;
@@ -0,0 +1,136 @@
function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
import { clsx } from 'clsx';
import { useComposeRef } from "@rc-component/util/es/ref";
import { useLockFocus } from "@rc-component/util/es/Dom/focus";
import React, { useMemo, useRef } from 'react';
import { RefContext } from "../../context";
import MemoChildren from "./MemoChildren";
import pickAttrs from "@rc-component/util/es/pickAttrs";
const Panel = /*#__PURE__*/React.forwardRef((props, ref) => {
const {
prefixCls,
className,
style,
title,
ariaId,
footer,
closable,
closeIcon,
onClose,
children,
bodyStyle,
bodyProps,
modalRender,
onMouseDown,
onMouseUp,
holderRef,
visible,
forceRender,
width,
height,
classNames: modalClassNames,
styles: modalStyles,
isFixedPos,
focusTrap
} = props;
// ================================= Refs =================================
const {
panel: panelRef
} = React.useContext(RefContext);
const internalRef = useRef(null);
const mergedRef = useComposeRef(holderRef, panelRef, internalRef);
const [ignoreElement] = useLockFocus(visible && isFixedPos && focusTrap !== false, () => internalRef.current);
React.useImperativeHandle(ref, () => ({
focus: () => {
internalRef.current?.focus({
preventScroll: true
});
}
}));
// ================================ Style =================================
const contentStyle = {};
if (width !== undefined) {
contentStyle.width = width;
}
if (height !== undefined) {
contentStyle.height = height;
}
// ================================ Render ================================
const footerNode = footer ? /*#__PURE__*/React.createElement("div", {
className: clsx(`${prefixCls}-footer`, modalClassNames?.footer),
style: {
...modalStyles?.footer
}
}, footer) : null;
const headerNode = title ? /*#__PURE__*/React.createElement("div", {
className: clsx(`${prefixCls}-header`, modalClassNames?.header),
style: {
...modalStyles?.header
}
}, /*#__PURE__*/React.createElement("div", {
className: clsx(`${prefixCls}-title`, modalClassNames?.title),
id: ariaId,
style: {
...modalStyles?.title
}
}, title)) : null;
const closableObj = useMemo(() => {
if (typeof closable === 'object' && closable !== null) {
return closable;
}
if (closable) {
return {
closeIcon: closeIcon ?? /*#__PURE__*/React.createElement("span", {
className: `${prefixCls}-close-x`
})
};
}
return {};
}, [closable, closeIcon, prefixCls]);
const ariaProps = pickAttrs(closableObj, true);
const closeBtnIsDisabled = typeof closable === 'object' && closable.disabled;
const closerNode = closable ? /*#__PURE__*/React.createElement("button", _extends({
type: "button",
onClick: onClose,
"aria-label": "Close"
}, ariaProps, {
className: `${prefixCls}-close`,
disabled: closeBtnIsDisabled
}), closableObj.closeIcon) : null;
const content = /*#__PURE__*/React.createElement("div", {
className: clsx(`${prefixCls}-container`, modalClassNames?.container),
style: modalStyles?.container
}, closerNode, headerNode, /*#__PURE__*/React.createElement("div", _extends({
className: clsx(`${prefixCls}-body`, modalClassNames?.body),
style: {
...bodyStyle,
...modalStyles?.body
}
}, bodyProps), children), footerNode);
return /*#__PURE__*/React.createElement("div", {
key: "dialog-element",
role: "dialog",
"aria-labelledby": title ? ariaId : null,
"aria-modal": "true",
ref: mergedRef,
style: {
...style,
...contentStyle
},
className: clsx(prefixCls, className),
onMouseDown: onMouseDown,
onMouseUp: onMouseUp,
tabIndex: -1,
onFocus: e => {
ignoreElement(e.target);
}
}, /*#__PURE__*/React.createElement(MemoChildren, {
shouldUpdate: visible || forceRender
}, modalRender ? modalRender(content) : content));
});
if (process.env.NODE_ENV !== 'production') {
Panel.displayName = 'Panel';
}
export default Panel;
@@ -0,0 +1,16 @@
import * as React from 'react';
import type { PanelProps, PanelRef } from './Panel';
import type { CSSMotionRef } from '@rc-component/motion/es/CSSMotion';
export type CSSMotionStateRef = Pick<CSSMotionRef, 'inMotion' | 'enableMotion'>;
export type ContentRef = PanelRef & CSSMotionStateRef;
export type ContentProps = {
motionName: string;
ariaId: string;
onVisibleChanged: (visible: boolean) => void;
} & PanelProps;
declare const Content: React.ForwardRefExoticComponent<{
motionName: string;
ariaId: string;
onVisibleChanged: (visible: boolean) => void;
} & PanelProps & React.RefAttributes<ContentRef>>;
export default Content;
@@ -0,0 +1,76 @@
function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
import * as React from 'react';
import { useRef } from 'react';
import { clsx } from 'clsx';
import CSSMotion from '@rc-component/motion';
import { offset } from "../../util";
import Panel from "./Panel";
const Content = /*#__PURE__*/React.forwardRef((props, ref) => {
const {
prefixCls,
title,
style,
className,
visible,
forceRender,
destroyOnHidden,
motionName,
ariaId,
onVisibleChanged,
mousePosition
} = props;
const dialogRef = useRef(null);
const panelRef = useRef(null);
// ============================== Refs ==============================
React.useImperativeHandle(ref, () => ({
...panelRef.current,
inMotion: dialogRef.current.inMotion,
enableMotion: dialogRef.current.enableMotion
}));
// ============================= Style ==============================
const [transformOrigin, setTransformOrigin] = React.useState();
const contentStyle = {};
if (transformOrigin) {
contentStyle.transformOrigin = transformOrigin;
}
function onPrepare() {
if (!dialogRef.current?.nativeElement) {
return;
}
const elementOffset = offset(dialogRef.current.nativeElement);
setTransformOrigin(mousePosition && (mousePosition.x || mousePosition.y) ? `${mousePosition.x - elementOffset.left}px ${mousePosition.y - elementOffset.top}px` : '');
}
// ============================= Render =============================
return /*#__PURE__*/React.createElement(CSSMotion, {
visible: visible,
onVisibleChanged: onVisibleChanged,
onAppearPrepare: onPrepare,
onEnterPrepare: onPrepare,
forceRender: forceRender,
motionName: motionName,
removeOnLeave: destroyOnHidden,
ref: dialogRef
}, ({
className: motionClassName,
style: motionStyle
}, motionRef) => /*#__PURE__*/React.createElement(Panel, _extends({}, props, {
ref: panelRef,
title: title,
ariaId: ariaId,
prefixCls: prefixCls,
holderRef: motionRef,
style: {
...motionStyle,
...style,
...contentStyle
},
className: clsx(className, motionClassName)
})));
});
if (process.env.NODE_ENV !== 'production') {
Content.displayName = 'Content';
}
export default Content;
+11
View File
@@ -0,0 +1,11 @@
import * as React from 'react';
export type MaskProps = {
prefixCls: string;
visible: boolean;
motionName?: string;
style?: React.CSSProperties;
maskProps?: React.HTMLAttributes<HTMLDivElement>;
className?: string;
};
declare const Mask: React.FC<MaskProps>;
export default Mask;
+31
View File
@@ -0,0 +1,31 @@
function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
import * as React from 'react';
import { clsx } from 'clsx';
import CSSMotion from '@rc-component/motion';
const Mask = props => {
const {
prefixCls,
style,
visible,
maskProps,
motionName,
className
} = props;
return /*#__PURE__*/React.createElement(CSSMotion, {
key: "mask",
visible: visible,
motionName: motionName,
leavedClassName: `${prefixCls}-mask-hidden`
}, ({
className: motionClassName,
style: motionStyle
}, ref) => /*#__PURE__*/React.createElement("div", _extends({
ref: ref,
style: {
...motionStyle,
...style
},
className: clsx(`${prefixCls}-mask`, motionClassName, className)
}, maskProps)));
};
export default Mask;
@@ -0,0 +1,4 @@
import * as React from 'react';
import type { IDialogPropTypes } from '../IDialogPropTypes';
declare const Dialog: React.FC<IDialogPropTypes>;
export default Dialog;
+178
View File
@@ -0,0 +1,178 @@
function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
import { clsx } from 'clsx';
import contains from "@rc-component/util/es/Dom/contains";
import useId from "@rc-component/util/es/hooks/useId";
import pickAttrs from "@rc-component/util/es/pickAttrs";
import * as React from 'react';
import { useEffect, useRef } from 'react';
import { getMotionName } from "../util";
import Content from "./Content";
import Mask from "./Mask";
import { warning } from "@rc-component/util/es/warning";
const Dialog = props => {
const {
prefixCls = 'rc-dialog',
zIndex,
visible = false,
focusTriggerAfterClose = true,
wrapStyle,
wrapClassName,
wrapProps,
onClose,
afterOpenChange,
afterClose,
// Dialog
transitionName,
animation,
closable = true,
// Mask
mask = true,
maskTransitionName,
maskAnimation,
maskClosable = true,
maskStyle,
maskProps,
rootClassName,
rootStyle,
classNames: modalClassNames,
styles: modalStyles
} = props;
if (process.env.NODE_ENV !== 'production') {
['wrapStyle', 'bodyStyle', 'maskStyle'].forEach(prop => {
warning(!(prop in props), `${prop} is deprecated, please use styles instead.`);
});
if ('wrapClassName' in props) {
warning(false, `wrapClassName is deprecated, please use classNames instead.`);
}
}
const lastOutSideActiveElementRef = useRef(null);
const wrapperRef = useRef(null);
const contentRef = useRef(null);
const [animatedVisible, setAnimatedVisible] = React.useState(visible);
const [isFixedPos, setIsFixedPos] = React.useState(false);
// ========================== Init ==========================
const ariaId = useId();
function saveLastOutSideActiveElementRef() {
if (!contains(wrapperRef.current, document.activeElement)) {
lastOutSideActiveElementRef.current = document.activeElement;
}
}
function focusDialogContent() {
if (!contains(wrapperRef.current, document.activeElement)) {
contentRef.current?.focus();
}
}
// ========================= Events =========================
// Close action will trigger by:
// 1. When hide motion end
// 2. Controlled `open` to `false` immediately after set to `true` which will not trigger motion
function doClose() {
// Clean up scroll bar & focus back
setAnimatedVisible(false);
if (mask && lastOutSideActiveElementRef.current && focusTriggerAfterClose) {
try {
lastOutSideActiveElementRef.current.focus({
preventScroll: true
});
} catch (e) {
// Do nothing
}
lastOutSideActiveElementRef.current = null;
}
// Trigger afterClose only when change visible from true to false
if (animatedVisible) {
afterClose?.();
}
}
function onDialogVisibleChanged(newVisible) {
// Try to focus
if (newVisible) {
focusDialogContent();
} else {
doClose();
}
afterOpenChange?.(newVisible);
}
function onInternalClose(e) {
onClose?.(e);
}
// >>> Content
const mouseDownOnMaskRef = useRef(false);
// >>> Wrapper
// Close only when element not on dialog
let onWrapperClick = null;
if (maskClosable) {
onWrapperClick = e => {
if (wrapperRef.current === e.target && mouseDownOnMaskRef.current) {
onInternalClose(e);
}
};
}
function onWrapperMouseDown(e) {
mouseDownOnMaskRef.current = e.target === wrapperRef.current;
}
// ========================= Effect =========================
useEffect(() => {
if (visible) {
mouseDownOnMaskRef.current = false;
setAnimatedVisible(true);
saveLastOutSideActiveElementRef();
// Calc the position style
if (wrapperRef.current) {
const computedWrapStyle = getComputedStyle(wrapperRef.current);
setIsFixedPos(computedWrapStyle.position === 'fixed');
}
} else if (animatedVisible && contentRef.current.enableMotion() && !contentRef.current.inMotion()) {
doClose();
}
}, [visible]);
const mergedStyle = {
zIndex,
...wrapStyle,
...modalStyles?.wrapper,
display: !animatedVisible ? 'none' : null
};
// ========================= Render =========================
return /*#__PURE__*/React.createElement("div", _extends({
className: clsx(`${prefixCls}-root`, rootClassName),
style: rootStyle
}, pickAttrs(props, {
data: true
})), /*#__PURE__*/React.createElement(Mask, {
prefixCls: prefixCls,
visible: mask && visible,
motionName: getMotionName(prefixCls, maskTransitionName, maskAnimation),
style: {
zIndex,
...maskStyle,
...modalStyles?.mask
},
maskProps: maskProps,
className: modalClassNames?.mask
}), /*#__PURE__*/React.createElement("div", _extends({
className: clsx(`${prefixCls}-wrap`, wrapClassName, modalClassNames?.wrapper),
ref: wrapperRef,
onClick: onWrapperClick,
onMouseDown: onWrapperMouseDown,
style: mergedStyle
}, wrapProps), /*#__PURE__*/React.createElement(Content, _extends({}, props, {
isFixedPos: isFixedPos,
ref: contentRef,
closable: closable,
ariaId: ariaId,
prefixCls: prefixCls,
visible: visible && animatedVisible,
onClose: onInternalClose,
onVisibleChanged: onDialogVisibleChanged,
motionName: getMotionName(prefixCls, transitionName, animation)
}))));
};
export default Dialog;
+4
View File
@@ -0,0 +1,4 @@
import * as React from 'react';
import type { IDialogPropTypes } from './IDialogPropTypes';
declare const DialogWrap: React.FC<IDialogPropTypes>;
export default DialogWrap;
+75
View File
@@ -0,0 +1,75 @@
function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
import Portal from '@rc-component/portal';
import * as React from 'react';
import { RefContext } from "./context";
import Dialog from "./Dialog";
// fix issue #10656
/*
* getContainer remarks
* Custom container should not be return, because in the Portal component, it will remove the
* return container element here, if the custom container is the only child of it's component,
* like issue #10656, It will has a conflict with removeChild method in react-dom.
* So here should add a child (div element) to custom container.
* */
const DialogWrap = props => {
const {
visible,
getContainer,
forceRender,
destroyOnHidden = false,
afterClose,
closable,
panelRef,
keyboard = true,
onClose
} = props;
const [animatedVisible, setAnimatedVisible] = React.useState(visible);
const refContext = React.useMemo(() => ({
panel: panelRef
}), [panelRef]);
const onEsc = ({
top,
event
}) => {
if (top && keyboard) {
event.stopPropagation();
onClose?.(event);
return;
}
};
React.useEffect(() => {
if (visible) {
setAnimatedVisible(true);
}
}, [visible]);
// Destroy on close will remove wrapped div
if (!forceRender && destroyOnHidden && !animatedVisible) {
return null;
}
return /*#__PURE__*/React.createElement(RefContext.Provider, {
value: refContext
}, /*#__PURE__*/React.createElement(Portal, {
open: visible || forceRender || animatedVisible,
onEsc: onEsc,
autoDestroy: false,
getContainer: getContainer,
autoLock: visible || animatedVisible
}, /*#__PURE__*/React.createElement(Dialog, _extends({}, props, {
destroyOnHidden: destroyOnHidden,
afterClose: () => {
const closableObj = closable && typeof closable === 'object' ? closable : {};
const {
afterClose: closableAfterClose
} = closableObj || {};
closableAfterClose?.();
afterClose?.();
setAnimatedVisible(false);
}
}))));
};
if (process.env.NODE_ENV !== 'production') {
DialogWrap.displayName = 'Dialog';
}
export default DialogWrap;
@@ -0,0 +1,56 @@
import type { GetContainer } from '@rc-component/util/lib/PortalWrapper';
import type { CSSProperties, ReactNode, SyntheticEvent } from 'react';
export type SemanticName = 'header' | 'body' | 'footer' | 'container' | 'title' | 'wrapper' | 'mask';
export type ModalClassNames = Partial<Record<SemanticName, string>>;
export type ModalStyles = Partial<Record<SemanticName, CSSProperties>>;
export type ClosableType = {
closeIcon?: React.ReactNode;
disabled?: boolean;
afterClose?: () => any;
};
export type IDialogPropTypes = {
className?: string;
keyboard?: boolean;
style?: CSSProperties;
rootStyle?: CSSProperties;
mask?: boolean;
children?: React.ReactNode;
afterClose?: () => any;
afterOpenChange?: (open: boolean) => void;
onClose?: (e: SyntheticEvent | KeyboardEvent) => any;
closable?: boolean | (ClosableType & React.AriaAttributes);
maskClosable?: boolean;
visible?: boolean;
destroyOnHidden?: boolean;
mousePosition?: {
x: number;
y: number;
} | null;
title?: ReactNode;
footer?: ReactNode;
transitionName?: string;
maskTransitionName?: string;
animation?: any;
maskAnimation?: any;
wrapStyle?: Record<string, any>;
bodyStyle?: Record<string, any>;
maskStyle?: Record<string, any>;
prefixCls?: string;
wrapClassName?: string;
width?: string | number;
height?: string | number;
zIndex?: number;
bodyProps?: any;
maskProps?: any;
rootClassName?: string;
classNames?: ModalClassNames;
styles?: ModalStyles;
wrapProps?: any;
getContainer?: GetContainer | false;
closeIcon?: ReactNode;
modalRender?: (node: ReactNode) => ReactNode;
forceRender?: boolean;
focusTriggerAfterClose?: boolean;
focusTrap?: boolean;
panelRef?: React.Ref<HTMLDivElement>;
};
@@ -0,0 +1 @@
export {};
+5
View File
@@ -0,0 +1,5 @@
import * as React from 'react';
export interface RefContextProps {
panel?: React.Ref<HTMLDivElement>;
}
export declare const RefContext: React.Context<RefContextProps>;
+2
View File
@@ -0,0 +1,2 @@
import * as React from 'react';
export const RefContext = /*#__PURE__*/React.createContext({});
+6
View File
@@ -0,0 +1,6 @@
import DialogWrap from './DialogWrap';
import Panel from './Dialog/Content/Panel';
import type { IDialogPropTypes as DialogProps } from './IDialogPropTypes';
export type { DialogProps };
export { Panel };
export default DialogWrap;
+4
View File
@@ -0,0 +1,4 @@
import DialogWrap from "./DialogWrap";
import Panel from "./Dialog/Content/Panel";
export { Panel };
export default DialogWrap;
+5
View File
@@ -0,0 +1,5 @@
export declare function getMotionName(prefixCls: string, transitionName?: string, animationName?: string): string;
export declare function offset(el: Element): {
left: number;
top: number;
};
+34
View File
@@ -0,0 +1,34 @@
// =============================== Motion ===============================
export function getMotionName(prefixCls, transitionName, animationName) {
let motionName = transitionName;
if (!motionName && animationName) {
motionName = `${prefixCls}-${animationName}`;
}
return motionName;
}
// =============================== Offset ===============================
function getScroll(w, top) {
let ret = w[`page${top ? 'Y' : 'X'}Offset`];
const method = `scroll${top ? 'Top' : 'Left'}`;
if (typeof ret !== 'number') {
const d = w.document;
ret = d.documentElement[method];
if (typeof ret !== 'number') {
ret = d.body[method];
}
}
return ret;
}
export function offset(el) {
const rect = el.getBoundingClientRect();
const pos = {
left: rect.left,
top: rect.top
};
const doc = el.ownerDocument;
const w = doc.defaultView || doc.parentWindow;
pos.left += getScroll(w);
pos.top += getScroll(w, true);
return pos;
}