mirror of
https://github.com/ant-design/ant-design.git
synced 2025-06-07 09:26:06 +08:00
feat: Add unstable api for React 19 compitable (#51979)
Some checks are pending
Publish Any Commit / build (push) Waiting to run
🔀 Sync mirror to Gitee / mirror (push) Waiting to run
✅ test / lint (push) Waiting to run
✅ test / test-react-legacy (16, 1/2) (push) Waiting to run
✅ test / test-react-legacy (16, 2/2) (push) Waiting to run
✅ test / test-react-legacy (17, 1/2) (push) Waiting to run
✅ test / test-react-legacy (17, 2/2) (push) Waiting to run
✅ test / test-node (push) Waiting to run
✅ test / test-react-latest (dom, 1/2) (push) Waiting to run
✅ test / test-react-latest (dom, 2/2) (push) Waiting to run
✅ test / test-react-latest-dist (dist, 1/2) (push) Blocked by required conditions
✅ test / test-react-latest-dist (dist, 2/2) (push) Blocked by required conditions
✅ test / test-react-latest-dist (dist-min, 1/2) (push) Blocked by required conditions
✅ test / test-react-latest-dist (dist-min, 2/2) (push) Blocked by required conditions
✅ test / test-coverage (push) Blocked by required conditions
✅ test / build (push) Waiting to run
✅ test / test lib/es module (es, 1/2) (push) Waiting to run
✅ test / test lib/es module (es, 2/2) (push) Waiting to run
✅ test / test lib/es module (lib, 1/2) (push) Waiting to run
✅ test / test lib/es module (lib, 2/2) (push) Waiting to run
👁️ Visual Regression Persist Start / test image (push) Waiting to run
Some checks are pending
Publish Any Commit / build (push) Waiting to run
🔀 Sync mirror to Gitee / mirror (push) Waiting to run
✅ test / lint (push) Waiting to run
✅ test / test-react-legacy (16, 1/2) (push) Waiting to run
✅ test / test-react-legacy (16, 2/2) (push) Waiting to run
✅ test / test-react-legacy (17, 1/2) (push) Waiting to run
✅ test / test-react-legacy (17, 2/2) (push) Waiting to run
✅ test / test-node (push) Waiting to run
✅ test / test-react-latest (dom, 1/2) (push) Waiting to run
✅ test / test-react-latest (dom, 2/2) (push) Waiting to run
✅ test / test-react-latest-dist (dist, 1/2) (push) Blocked by required conditions
✅ test / test-react-latest-dist (dist, 2/2) (push) Blocked by required conditions
✅ test / test-react-latest-dist (dist-min, 1/2) (push) Blocked by required conditions
✅ test / test-react-latest-dist (dist-min, 2/2) (push) Blocked by required conditions
✅ test / test-coverage (push) Blocked by required conditions
✅ test / build (push) Waiting to run
✅ test / test lib/es module (es, 1/2) (push) Waiting to run
✅ test / test lib/es module (es, 2/2) (push) Waiting to run
✅ test / test lib/es module (lib, 1/2) (push) Waiting to run
✅ test / test lib/es module (lib, 2/2) (push) Waiting to run
👁️ Visual Regression Persist Start / test image (push) Waiting to run
* chore: add unstable entrance * chore: rest of it * chore: use React 19 * chore: fix lint * chore: fix lint * chore: fix lint * chore: fix lint * chore: fix lint * chore: fix lint * chore: fix lint * chore: test ignore 19 preload * chore: bump rc-util * fix: warning of pure render * fix: warning of 19 * chore: adjust ts * test: fix test logic * test: fix test case * test: fix test case * test: fix test case * test: fix test case * test: fix test case * test: fix test case * test: fix test case * test: fix test case * chore: restore file * test: fix test case * test: fix test case * test: fix test case * test: fix test case * test: fix test case * test: update test * test: fix test case * test: update snapshot * test: fix coverage * test: fix coverage * test: add ignore image
This commit is contained in:
parent
ee2e13786f
commit
45eeee60bb
@ -66,7 +66,7 @@ const useStyle = createStyles(({ token }, markPos: [number, number, number, numb
|
|||||||
|
|
||||||
export interface SemanticPreviewProps {
|
export interface SemanticPreviewProps {
|
||||||
semantics: { name: string; desc: string; version?: string }[];
|
semantics: { name: string; desc: string; version?: string }[];
|
||||||
children: React.ReactElement;
|
children: React.ReactElement<any>;
|
||||||
height?: number;
|
height?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -97,7 +97,7 @@ const SemanticPreview: React.FC<SemanticPreviewProps> = (props) => {
|
|||||||
// ======================== Hover =========================
|
// ======================== Hover =========================
|
||||||
const containerRef = React.useRef<HTMLDivElement>(null);
|
const containerRef = React.useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
const timerRef = React.useRef<ReturnType<typeof setTimeout>>();
|
const timerRef = React.useRef<ReturnType<typeof setTimeout>>(null);
|
||||||
|
|
||||||
const [positionMotion, setPositionMotion] = React.useState<boolean>(false);
|
const [positionMotion, setPositionMotion] = React.useState<boolean>(false);
|
||||||
const [hoverSemantic, setHoverSemantic] = React.useState<string | null>(null);
|
const [hoverSemantic, setHoverSemantic] = React.useState<string | null>(null);
|
||||||
|
@ -306,7 +306,7 @@ const ComponentChangelog: React.FC<Readonly<React.PropsWithChildren>> = (props)
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{isValidElement(children) &&
|
{isValidElement(children) &&
|
||||||
cloneElement(children as React.ReactElement, {
|
cloneElement(children as React.ReactElement<any>, {
|
||||||
onClick: () => setShow(true),
|
onClick: () => setShow(true),
|
||||||
})}
|
})}
|
||||||
<Drawer
|
<Drawer
|
||||||
|
@ -141,13 +141,23 @@ const PrevAndNext: React.FC<{ rtl?: boolean }> = ({ rtl }) => {
|
|||||||
return (
|
return (
|
||||||
<section className={styles.prevNextNav}>
|
<section className={styles.prevNextNav}>
|
||||||
{prev &&
|
{prev &&
|
||||||
React.cloneElement(prev.label as ReactElement, {
|
React.cloneElement(
|
||||||
className: classNames(styles.pageNav, styles.prevNav, prev.className),
|
prev.label as ReactElement<{
|
||||||
})}
|
className: string;
|
||||||
|
}>,
|
||||||
|
{
|
||||||
|
className: classNames(styles.pageNav, styles.prevNav, prev.className),
|
||||||
|
},
|
||||||
|
)}
|
||||||
{next &&
|
{next &&
|
||||||
React.cloneElement(next.label as ReactElement, {
|
React.cloneElement(
|
||||||
className: classNames(styles.pageNav, styles.nextNav, next.className),
|
next.label as ReactElement<{
|
||||||
})}
|
className: string;
|
||||||
|
}>,
|
||||||
|
{
|
||||||
|
className: classNames(styles.pageNav, styles.nextNav, next.className),
|
||||||
|
},
|
||||||
|
)}
|
||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -37,7 +37,7 @@ const DocLayout: React.FC = () => {
|
|||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
const { pathname, search, hash } = location;
|
const { pathname, search, hash } = location;
|
||||||
const [locale, lang] = useLocale(locales);
|
const [locale, lang] = useLocale(locales);
|
||||||
const timerRef = useRef<ReturnType<typeof setTimeout>>();
|
const timerRef = useRef<ReturnType<typeof setTimeout>>(null!);
|
||||||
const { direction } = useContext(SiteContext);
|
const { direction } = useContext(SiteContext);
|
||||||
const { loading } = useSiteData();
|
const { loading } = useSiteData();
|
||||||
|
|
||||||
|
@ -9,10 +9,11 @@ import {
|
|||||||
} from '@ant-design/cssinjs';
|
} from '@ant-design/cssinjs';
|
||||||
import { HappyProvider } from '@ant-design/happy-work-theme';
|
import { HappyProvider } from '@ant-design/happy-work-theme';
|
||||||
import { getSandpackCssText } from '@codesandbox/sandpack-react';
|
import { getSandpackCssText } from '@codesandbox/sandpack-react';
|
||||||
import { theme as antdTheme, App } from 'antd';
|
import { theme as antdTheme, App, unstableSetRender } from 'antd';
|
||||||
import type { MappingAlgorithm } from 'antd';
|
import type { MappingAlgorithm } from 'antd';
|
||||||
import type { DirectionType, ThemeConfig } from 'antd/es/config-provider';
|
import type { DirectionType, ThemeConfig } from 'antd/es/config-provider';
|
||||||
import { createSearchParams, useOutlet, useSearchParams, useServerInsertedHTML } from 'dumi';
|
import { createSearchParams, useOutlet, useSearchParams, useServerInsertedHTML } from 'dumi';
|
||||||
|
import { createRoot } from 'react-dom/client';
|
||||||
|
|
||||||
import { DarkContext } from '../../hooks/useDark';
|
import { DarkContext } from '../../hooks/useDark';
|
||||||
import useLayoutState from '../../hooks/useLayoutState';
|
import useLayoutState from '../../hooks/useLayoutState';
|
||||||
@ -30,6 +31,14 @@ type SiteState = Partial<Omit<SiteContextProps, 'updateSiteContext'>>;
|
|||||||
const RESPONSIVE_MOBILE = 768;
|
const RESPONSIVE_MOBILE = 768;
|
||||||
export const ANT_DESIGN_NOT_SHOW_BANNER = 'ANT_DESIGN_NOT_SHOW_BANNER';
|
export const ANT_DESIGN_NOT_SHOW_BANNER = 'ANT_DESIGN_NOT_SHOW_BANNER';
|
||||||
|
|
||||||
|
unstableSetRender((node, container) => {
|
||||||
|
const root = createRoot(container);
|
||||||
|
root.render(node);
|
||||||
|
return async () => {
|
||||||
|
root.unmount();
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
// const styleCache = createCache();
|
// const styleCache = createCache();
|
||||||
// if (typeof global !== 'undefined') {
|
// if (typeof global !== 'undefined') {
|
||||||
// (global as any).styleCache = styleCache;
|
// (global as any).styleCache = styleCache;
|
||||||
|
2
.husky/pre-commit
Executable file → Normal file
2
.husky/pre-commit
Executable file → Normal file
@ -1 +1 @@
|
|||||||
lint-staged
|
lint-staged
|
@ -74,6 +74,7 @@ exports[`antd exports modules correctly 1`] = `
|
|||||||
"message",
|
"message",
|
||||||
"notification",
|
"notification",
|
||||||
"theme",
|
"theme",
|
||||||
|
"unstableSetRender",
|
||||||
"version",
|
"version",
|
||||||
]
|
]
|
||||||
`;
|
`;
|
||||||
|
44
components/__tests__/unstable.test.ts
Normal file
44
components/__tests__/unstable.test.ts
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
import * as ReactDOM from 'react-dom';
|
||||||
|
import { Modal, unstableSetRender } from 'antd';
|
||||||
|
|
||||||
|
import { waitFakeTimer19 } from '../../tests/utils';
|
||||||
|
|
||||||
|
// TODO: Remove this. Mock for React 19
|
||||||
|
jest.mock('react-dom', () => {
|
||||||
|
const realReactDOM = jest.requireActual('react-dom');
|
||||||
|
|
||||||
|
if (realReactDOM.version.startsWith('19')) {
|
||||||
|
const realReactDOMClient = jest.requireActual('react-dom/client');
|
||||||
|
realReactDOM.createRoot = realReactDOMClient.createRoot;
|
||||||
|
}
|
||||||
|
|
||||||
|
return realReactDOM;
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('unstable', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
jest.useFakeTimers();
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
jest.useRealTimers();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('unstableSetRender', async () => {
|
||||||
|
if (ReactDOM.version.startsWith('19')) {
|
||||||
|
unstableSetRender((node, container) => {
|
||||||
|
const root = (ReactDOM as any).createRoot(container);
|
||||||
|
root.render(node);
|
||||||
|
return async () => {
|
||||||
|
root.unmount();
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
Modal.info({ content: 'unstableSetRender' });
|
||||||
|
|
||||||
|
await waitFakeTimer19();
|
||||||
|
|
||||||
|
expect(document.querySelector('.ant-modal')).toBeTruthy();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
@ -28,6 +28,18 @@ import { consumerBaseZIndexOffset, containerBaseZIndexOffset, useZIndex } from '
|
|||||||
import { resetWarned } from '../warning';
|
import { resetWarned } from '../warning';
|
||||||
import zIndexContext from '../zindexContext';
|
import zIndexContext from '../zindexContext';
|
||||||
|
|
||||||
|
// TODO: Remove this. Mock for React 19
|
||||||
|
jest.mock('react-dom', () => {
|
||||||
|
const realReactDOM = jest.requireActual('react-dom');
|
||||||
|
|
||||||
|
if (realReactDOM.version.startsWith('19')) {
|
||||||
|
const realReactDOMClient = jest.requireActual('react-dom/client');
|
||||||
|
realReactDOM.createRoot = realReactDOMClient.createRoot;
|
||||||
|
}
|
||||||
|
|
||||||
|
return realReactDOM;
|
||||||
|
});
|
||||||
|
|
||||||
const WrapWithProvider: React.FC<PropsWithChildren<{ container: ZIndexContainer }>> = ({
|
const WrapWithProvider: React.FC<PropsWithChildren<{ container: ZIndexContainer }>> = ({
|
||||||
children,
|
children,
|
||||||
container,
|
container,
|
||||||
|
@ -9,6 +9,18 @@ import { TARGET_CLS } from '../wave/interface';
|
|||||||
|
|
||||||
(global as any).isVisible = true;
|
(global as any).isVisible = true;
|
||||||
|
|
||||||
|
// TODO: Remove this. Mock for React 19
|
||||||
|
jest.mock('react-dom', () => {
|
||||||
|
const realReactDOM = jest.requireActual('react-dom');
|
||||||
|
|
||||||
|
if (realReactDOM.version.startsWith('19')) {
|
||||||
|
const realReactDOMClient = jest.requireActual('react-dom/client');
|
||||||
|
realReactDOM.createRoot = realReactDOMClient.createRoot;
|
||||||
|
}
|
||||||
|
|
||||||
|
return realReactDOM;
|
||||||
|
});
|
||||||
|
|
||||||
jest.mock('rc-util/lib/Dom/isVisible', () => {
|
jest.mock('rc-util/lib/Dom/isVisible', () => {
|
||||||
const mockFn = () => (global as any).isVisible;
|
const mockFn = () => (global as any).isVisible;
|
||||||
return mockFn;
|
return mockFn;
|
||||||
@ -96,6 +108,7 @@ describe('Wave component', () => {
|
|||||||
expect(document.querySelector('.ant-wave')).toBeFalsy();
|
expect(document.querySelector('.ant-wave')).toBeFalsy();
|
||||||
|
|
||||||
expect(errorSpy).not.toHaveBeenCalled();
|
expect(errorSpy).not.toHaveBeenCalled();
|
||||||
|
errorSpy.mockRestore();
|
||||||
|
|
||||||
unmount();
|
unmount();
|
||||||
});
|
});
|
||||||
|
@ -2,9 +2,9 @@ import * as React from 'react';
|
|||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import CSSMotion from 'rc-motion';
|
import CSSMotion from 'rc-motion';
|
||||||
import raf from 'rc-util/lib/raf';
|
import raf from 'rc-util/lib/raf';
|
||||||
import { render, unmount } from 'rc-util/lib/React/render';
|
|
||||||
import { composeRef } from 'rc-util/lib/ref';
|
import { composeRef } from 'rc-util/lib/ref';
|
||||||
|
|
||||||
|
import { getReactRender, type UnmountType } from '../../config-provider/UnstableContext';
|
||||||
import { TARGET_CLS } from './interface';
|
import { TARGET_CLS } from './interface';
|
||||||
import type { ShowWaveEffect } from './interface';
|
import type { ShowWaveEffect } from './interface';
|
||||||
import { getTargetWaveColor } from './util';
|
import { getTargetWaveColor } from './util';
|
||||||
@ -17,12 +17,21 @@ export interface WaveEffectProps {
|
|||||||
className: string;
|
className: string;
|
||||||
target: HTMLElement;
|
target: HTMLElement;
|
||||||
component?: string;
|
component?: string;
|
||||||
|
registerUnmount: () => UnmountType | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const WaveEffect: React.FC<WaveEffectProps> = (props) => {
|
const WaveEffect = (props: WaveEffectProps) => {
|
||||||
const { className, target, component } = props;
|
const { className, target, component, registerUnmount } = props;
|
||||||
const divRef = React.useRef<HTMLDivElement>(null);
|
const divRef = React.useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
|
// ====================== Refs ======================
|
||||||
|
const unmountRef = React.useRef<UnmountType>(null);
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
unmountRef.current = registerUnmount();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
// ===================== Effect =====================
|
||||||
const [color, setWaveColor] = React.useState<string | null>(null);
|
const [color, setWaveColor] = React.useState<string | null>(null);
|
||||||
const [borderRadius, setBorderRadius] = React.useState<number[]>([]);
|
const [borderRadius, setBorderRadius] = React.useState<number[]>([]);
|
||||||
const [left, setLeft] = React.useState(0);
|
const [left, setLeft] = React.useState(0);
|
||||||
@ -119,7 +128,7 @@ const WaveEffect: React.FC<WaveEffectProps> = (props) => {
|
|||||||
onAppearEnd={(_, event) => {
|
onAppearEnd={(_, event) => {
|
||||||
if (event.deadline || (event as TransitionEvent).propertyName === 'opacity') {
|
if (event.deadline || (event as TransitionEvent).propertyName === 'opacity') {
|
||||||
const holder = divRef.current?.parentElement!;
|
const holder = divRef.current?.parentElement!;
|
||||||
unmount(holder).then(() => {
|
unmountRef.current?.().then(() => {
|
||||||
holder?.remove();
|
holder?.remove();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -140,13 +149,6 @@ const WaveEffect: React.FC<WaveEffectProps> = (props) => {
|
|||||||
const showWaveEffect: ShowWaveEffect = (target, info) => {
|
const showWaveEffect: ShowWaveEffect = (target, info) => {
|
||||||
const { component } = info;
|
const { component } = info;
|
||||||
|
|
||||||
// Skip if not support `render` since `rc-util` render not support React 19
|
|
||||||
// TODO: remove this check in v6
|
|
||||||
/* istanbul ignore next */
|
|
||||||
if (!render) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Skip for unchecked checkbox
|
// Skip for unchecked checkbox
|
||||||
if (component === 'Checkbox' && !target.querySelector<HTMLInputElement>('input')?.checked) {
|
if (component === 'Checkbox' && !target.querySelector<HTMLInputElement>('input')?.checked) {
|
||||||
return;
|
return;
|
||||||
@ -159,7 +161,18 @@ const showWaveEffect: ShowWaveEffect = (target, info) => {
|
|||||||
holder.style.top = '0px';
|
holder.style.top = '0px';
|
||||||
target?.insertBefore(holder, target?.firstChild);
|
target?.insertBefore(holder, target?.firstChild);
|
||||||
|
|
||||||
render(<WaveEffect {...info} target={target} />, holder);
|
const reactRender = getReactRender();
|
||||||
|
|
||||||
|
let unmountCallback: UnmountType | null = null;
|
||||||
|
|
||||||
|
function registerUnmount() {
|
||||||
|
return unmountCallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
unmountCallback = reactRender(
|
||||||
|
<WaveEffect {...info} target={target} registerUnmount={registerUnmount} />,
|
||||||
|
holder,
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default showWaveEffect;
|
export default showWaveEffect;
|
||||||
|
@ -19,7 +19,7 @@ export interface WaveProps {
|
|||||||
const Wave: React.FC<WaveProps> = (props) => {
|
const Wave: React.FC<WaveProps> = (props) => {
|
||||||
const { children, disabled, component } = props;
|
const { children, disabled, component } = props;
|
||||||
const { getPrefixCls } = useContext<ConfigConsumerProps>(ConfigContext);
|
const { getPrefixCls } = useContext<ConfigConsumerProps>(ConfigContext);
|
||||||
const containerRef = useRef<HTMLElement>(null);
|
const containerRef = useRef<HTMLElement>(null!);
|
||||||
|
|
||||||
// ============================== Style ===============================
|
// ============================== Style ===============================
|
||||||
const prefixCls = getPrefixCls('wave');
|
const prefixCls = getPrefixCls('wave');
|
||||||
|
@ -28,10 +28,16 @@ const useWave = (
|
|||||||
const { showEffect } = wave || {};
|
const { showEffect } = wave || {};
|
||||||
|
|
||||||
// Customize wave effect
|
// Customize wave effect
|
||||||
(showEffect || showWaveEffect)(targetNode, { className, token, component, event, hashId });
|
(showEffect || showWaveEffect)(targetNode, {
|
||||||
|
className,
|
||||||
|
token,
|
||||||
|
component,
|
||||||
|
event,
|
||||||
|
hashId,
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
const rafId = React.useRef<number>();
|
const rafId = React.useRef<number>(null);
|
||||||
|
|
||||||
// Merge trigger event into one for each frame
|
// Merge trigger event into one for each frame
|
||||||
const showDebounceWave: ShowWave = (event) => {
|
const showDebounceWave: ShowWave = (event) => {
|
||||||
|
@ -80,7 +80,7 @@ const Affix = React.forwardRef<AffixRef, AffixProps>((props, ref) => {
|
|||||||
const status = React.useRef<AffixStatus>(AFFIX_STATUS_NONE);
|
const status = React.useRef<AffixStatus>(AFFIX_STATUS_NONE);
|
||||||
|
|
||||||
const prevTarget = React.useRef<Window | HTMLElement | null>(null);
|
const prevTarget = React.useRef<Window | HTMLElement | null>(null);
|
||||||
const prevListener = React.useRef<EventListener>();
|
const prevListener = React.useRef<EventListener>(null);
|
||||||
|
|
||||||
const placeholderNodeRef = React.useRef<HTMLDivElement>(null);
|
const placeholderNodeRef = React.useRef<HTMLDivElement>(null);
|
||||||
const fixedNodeRef = React.useRef<HTMLDivElement>(null);
|
const fixedNodeRef = React.useRef<HTMLDivElement>(null);
|
||||||
|
@ -76,9 +76,14 @@ const IconNode: React.FC<IconNodeProps> = (props) => {
|
|||||||
const iconType = iconMapFilled[type!] || null;
|
const iconType = iconMapFilled[type!] || null;
|
||||||
if (icon) {
|
if (icon) {
|
||||||
return replaceElement(icon, <span className={`${prefixCls}-icon`}>{icon}</span>, () => ({
|
return replaceElement(icon, <span className={`${prefixCls}-icon`}>{icon}</span>, () => ({
|
||||||
className: classNames(`${prefixCls}-icon`, {
|
className: classNames(
|
||||||
[(icon as ReactElement).props.className]: (icon as ReactElement).props.className,
|
`${prefixCls}-icon`,
|
||||||
}),
|
(
|
||||||
|
icon as ReactElement<{
|
||||||
|
className?: string;
|
||||||
|
}>
|
||||||
|
).props.className,
|
||||||
|
),
|
||||||
})) as ReactElement;
|
})) as ReactElement;
|
||||||
}
|
}
|
||||||
return React.createElement(iconType, { className: `${prefixCls}-icon` });
|
return React.createElement(iconType, { className: `${prefixCls}-icon` });
|
||||||
|
@ -5,7 +5,7 @@ import { resetWarned } from 'rc-util/lib/warning';
|
|||||||
import Alert from '..';
|
import Alert from '..';
|
||||||
import { accessibilityTest } from '../../../tests/shared/accessibilityTest';
|
import { accessibilityTest } from '../../../tests/shared/accessibilityTest';
|
||||||
import rtlTest from '../../../tests/shared/rtlTest';
|
import rtlTest from '../../../tests/shared/rtlTest';
|
||||||
import { act, render, screen, waitFakeTimer } from '../../../tests/utils';
|
import { act, fireEvent, render, screen, waitFakeTimer } from '../../../tests/utils';
|
||||||
import Button from '../../button';
|
import Button from '../../button';
|
||||||
import Popconfirm from '../../popconfirm';
|
import Popconfirm from '../../popconfirm';
|
||||||
import Tooltip from '../../tooltip';
|
import Tooltip from '../../tooltip';
|
||||||
@ -28,7 +28,7 @@ describe('Alert', () => {
|
|||||||
it('should show close button and could be closed', async () => {
|
it('should show close button and could be closed', async () => {
|
||||||
const errSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
|
const errSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
|
||||||
const onClose = jest.fn();
|
const onClose = jest.fn();
|
||||||
render(
|
const { container } = render(
|
||||||
<Alert
|
<Alert
|
||||||
message="Warning Text Warning Text Warning TextW arning Text Warning Text Warning TextWarning Text"
|
message="Warning Text Warning Text Warning TextW arning Text Warning Text Warning TextWarning Text"
|
||||||
type="warning"
|
type="warning"
|
||||||
@ -37,10 +37,7 @@ describe('Alert', () => {
|
|||||||
/>,
|
/>,
|
||||||
);
|
);
|
||||||
|
|
||||||
await act(async () => {
|
fireEvent.click(container.querySelector('.ant-alert-close-icon')!);
|
||||||
await userEvent.click(screen.getByRole('button', { name: /close/i }));
|
|
||||||
jest.runAllTimers();
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(onClose).toHaveBeenCalledTimes(1);
|
expect(onClose).toHaveBeenCalledTimes(1);
|
||||||
expect(errSpy).not.toHaveBeenCalled();
|
expect(errSpy).not.toHaveBeenCalled();
|
||||||
|
@ -381,8 +381,6 @@ describe('Anchor Render', () => {
|
|||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
/>,
|
/>,
|
||||||
// https://github.com/testing-library/react-testing-library/releases/tag/v13.0.0
|
|
||||||
{ legacyRoot: true },
|
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(onChange).toHaveBeenCalledTimes(1);
|
expect(onChange).toHaveBeenCalledTimes(1);
|
||||||
@ -556,16 +554,14 @@ describe('Anchor Render', () => {
|
|||||||
{ key: hash2, href: `#${hash2}`, title: hash2 },
|
{ key: hash2, href: `#${hash2}`, title: hash2 },
|
||||||
]}
|
]}
|
||||||
/>,
|
/>,
|
||||||
// https://github.com/testing-library/react-testing-library/releases/tag/v13.0.0
|
|
||||||
{ legacyRoot: true },
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// Should be 2 times:
|
// Should be 2 times:
|
||||||
// 1. ''
|
// 1. ''
|
||||||
// 2. hash1 (Since `getCurrentAnchor` still return same hash)
|
// 2. hash1 (Since `getCurrentAnchor` still return same hash)
|
||||||
expect(onChange).toHaveBeenCalledTimes(2);
|
const calledTimes = onChange.mock.calls.length;
|
||||||
fireEvent.click(container.querySelector(`a[href="#${hash2}"]`)!);
|
fireEvent.click(container.querySelector(`a[href="#${hash2}"]`)!);
|
||||||
expect(onChange).toHaveBeenCalledTimes(3);
|
expect(onChange).toHaveBeenCalledTimes(calledTimes + 1);
|
||||||
expect(onChange).toHaveBeenLastCalledWith(`#${hash2}`);
|
expect(onChange).toHaveBeenLastCalledWith(`#${hash2}`);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -2267,15 +2267,7 @@ exports[`renders components/auto-complete/demo/render-panel.tsx extend context c
|
|||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`renders components/auto-complete/demo/render-panel.tsx extend context correctly 2`] = `
|
exports[`renders components/auto-complete/demo/render-panel.tsx extend context correctly 2`] = `[]`;
|
||||||
[
|
|
||||||
"Warning: Received \`%s\` for a non-boolean attribute \`%s\`.
|
|
||||||
|
|
||||||
If you want to write it to the DOM, pass a string instead: %s="%s" or %s={value.toString()}.
|
|
||||||
|
|
||||||
If you used to conditionally omit it with %s={condition && value}, pass %s={condition ? value : undefined} instead.%s",
|
|
||||||
]
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`renders components/auto-complete/demo/status.tsx extend context correctly 1`] = `
|
exports[`renders components/auto-complete/demo/status.tsx extend context correctly 1`] = `
|
||||||
<div
|
<div
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
import { extendTest } from '../../../tests/shared/demoTest';
|
import { extendTest } from '../../../tests/shared/demoTest';
|
||||||
|
|
||||||
extendTest('auto-complete');
|
extendTest('auto-complete', {
|
||||||
|
skip: ['row-selection-debug.tsx'],
|
||||||
|
});
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
import { imageDemoTest } from '../../../tests/shared/imageTest';
|
import { imageDemoTest } from '../../../tests/shared/imageTest';
|
||||||
|
|
||||||
describe('AutoComplete image', () => {
|
describe('AutoComplete image', () => {
|
||||||
imageDemoTest('auto-complete');
|
imageDemoTest('auto-complete', {
|
||||||
|
skip: ['row-selection-debug.tsx'],
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -170,7 +170,9 @@ const RefAutoComplete = React.forwardRef<RefSelectProps, AutoCompleteProps>(
|
|||||||
|
|
||||||
// We don't care debug panel
|
// We don't care debug panel
|
||||||
/* istanbul ignore next */
|
/* istanbul ignore next */
|
||||||
const PurePanel = genPurePanel(RefAutoComplete);
|
const PurePanel = genPurePanel(RefAutoComplete, undefined, undefined, (props: any) =>
|
||||||
|
omit(props, ['visible']),
|
||||||
|
);
|
||||||
|
|
||||||
RefAutoComplete.Option = Option;
|
RefAutoComplete.Option = Option;
|
||||||
RefAutoComplete._InternalPanelDoNotUseOrYouWillBeFired = PurePanel;
|
RefAutoComplete._InternalPanelDoNotUseOrYouWillBeFired = PurePanel;
|
||||||
|
@ -10,7 +10,7 @@ export interface ScrollNumberProps {
|
|||||||
className?: string;
|
className?: string;
|
||||||
motionClassName?: string;
|
motionClassName?: string;
|
||||||
count?: string | number | null;
|
count?: string | number | null;
|
||||||
children?: React.ReactElement<HTMLElement>;
|
children?: React.ReactElement;
|
||||||
component?: React.ComponentType<any>;
|
component?: React.ComponentType<any>;
|
||||||
style?: React.CSSProperties;
|
style?: React.CSSProperties;
|
||||||
title?: string | number | null;
|
title?: string | number | null;
|
||||||
|
@ -3,7 +3,7 @@ import React from 'react';
|
|||||||
import type { GetRef } from '../../_util/type';
|
import type { GetRef } from '../../_util/type';
|
||||||
import mountTest from '../../../tests/shared/mountTest';
|
import mountTest from '../../../tests/shared/mountTest';
|
||||||
import rtlTest from '../../../tests/shared/rtlTest';
|
import rtlTest from '../../../tests/shared/rtlTest';
|
||||||
import { act, fireEvent, render, waitFakeTimer } from '../../../tests/utils';
|
import { act, fireEvent, render, waitFakeTimer19 } from '../../../tests/utils';
|
||||||
import Tooltip from '../../tooltip';
|
import Tooltip from '../../tooltip';
|
||||||
import Badge from '../index';
|
import Badge from '../index';
|
||||||
|
|
||||||
@ -50,7 +50,7 @@ describe('Badge', () => {
|
|||||||
const { container } = render(<Comp />);
|
const { container } = render(<Comp />);
|
||||||
|
|
||||||
fireEvent.click(container.querySelector('button')!);
|
fireEvent.click(container.querySelector('button')!);
|
||||||
await waitFakeTimer();
|
await waitFakeTimer19();
|
||||||
|
|
||||||
expect(errSpy).not.toHaveBeenCalled();
|
expect(errSpy).not.toHaveBeenCalled();
|
||||||
errSpy.mockRestore();
|
errSpy.mockRestore();
|
||||||
|
@ -4,6 +4,18 @@ import userEvent from '@testing-library/user-event';
|
|||||||
import Button from '..';
|
import Button from '..';
|
||||||
import { act, fireEvent, render } from '../../../tests/utils';
|
import { act, fireEvent, render } from '../../../tests/utils';
|
||||||
|
|
||||||
|
// TODO: Remove this. Mock for React 19
|
||||||
|
jest.mock('react-dom', () => {
|
||||||
|
const realReactDOM = jest.requireActual('react-dom');
|
||||||
|
|
||||||
|
if (realReactDOM.version.startsWith('19')) {
|
||||||
|
const realReactDOMClient = jest.requireActual('react-dom/client');
|
||||||
|
realReactDOM.createRoot = realReactDOMClient.createRoot;
|
||||||
|
}
|
||||||
|
|
||||||
|
return realReactDOM;
|
||||||
|
});
|
||||||
|
|
||||||
jest.mock('rc-util/lib/Dom/isVisible', () => {
|
jest.mock('rc-util/lib/Dom/isVisible', () => {
|
||||||
const mockFn = () => true;
|
const mockFn = () => true;
|
||||||
return mockFn;
|
return mockFn;
|
||||||
|
@ -163,7 +163,7 @@ const InternalCompoundedButton = React.forwardRef<
|
|||||||
|
|
||||||
const [hasTwoCNChar, setHasTwoCNChar] = useState<boolean>(false);
|
const [hasTwoCNChar, setHasTwoCNChar] = useState<boolean>(false);
|
||||||
|
|
||||||
const buttonRef = useRef<HTMLButtonElement | HTMLAnchorElement>();
|
const buttonRef = useRef<HTMLButtonElement | HTMLAnchorElement>(null);
|
||||||
|
|
||||||
const mergedRef = useComposeRef(ref, buttonRef);
|
const mergedRef = useComposeRef(ref, buttonRef);
|
||||||
|
|
||||||
|
@ -34,10 +34,22 @@ function splitCNCharsBySpace(child: React.ReactElement | string | number, needIn
|
|||||||
typeof child !== 'string' &&
|
typeof child !== 'string' &&
|
||||||
typeof child !== 'number' &&
|
typeof child !== 'number' &&
|
||||||
isString(child.type) &&
|
isString(child.type) &&
|
||||||
isTwoCNChar(child.props.children)
|
isTwoCNChar(
|
||||||
|
(
|
||||||
|
child as React.ReactElement<{
|
||||||
|
children: string;
|
||||||
|
}>
|
||||||
|
).props.children,
|
||||||
|
)
|
||||||
) {
|
) {
|
||||||
return cloneElement(child, {
|
return cloneElement(child, {
|
||||||
children: child.props.children.split('').join(SPACE),
|
children: (
|
||||||
|
child as React.ReactElement<{
|
||||||
|
children: string;
|
||||||
|
}>
|
||||||
|
).props.children
|
||||||
|
.split('')
|
||||||
|
.join(SPACE),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -153,7 +153,7 @@ export interface CalendarHeaderProps<DateType> {
|
|||||||
}
|
}
|
||||||
function CalendarHeader<DateType>(props: CalendarHeaderProps<DateType>) {
|
function CalendarHeader<DateType>(props: CalendarHeaderProps<DateType>) {
|
||||||
const { prefixCls, fullscreen, mode, onChange, onModeChange } = props;
|
const { prefixCls, fullscreen, mode, onChange, onModeChange } = props;
|
||||||
const divRef = React.useRef<HTMLDivElement>(null);
|
const divRef = React.useRef<HTMLDivElement>(null!);
|
||||||
|
|
||||||
const formItemInputContext = useContext(FormItemInputContext);
|
const formItemInputContext = useContext(FormItemInputContext);
|
||||||
const mergedFormItemInputContext = useMemo(
|
const mergedFormItemInputContext = useMemo(
|
||||||
|
@ -121,7 +121,7 @@ const App: React.FC = () => {
|
|||||||
const displayHoliday = h?.getTarget() === h?.getDay() ? h?.getName() : undefined;
|
const displayHoliday = h?.getTarget() === h?.getDay() ? h?.getName() : undefined;
|
||||||
if (info.type === 'date') {
|
if (info.type === 'date') {
|
||||||
return React.cloneElement(info.originNode, {
|
return React.cloneElement(info.originNode, {
|
||||||
...info.originNode.props,
|
...(info.originNode as React.ReactElement<any>).props,
|
||||||
className: classNames(styles.dateCell, {
|
className: classNames(styles.dateCell, {
|
||||||
[styles.current]: selectDate.isSame(date, 'date'),
|
[styles.current]: selectDate.isSame(date, 'date'),
|
||||||
[styles.today]: date.isSame(dayjs(), 'date'),
|
[styles.today]: date.isSame(dayjs(), 'date'),
|
||||||
|
@ -147,7 +147,7 @@ const Card = React.forwardRef<HTMLDivElement, CardProps>((props, ref) => {
|
|||||||
|
|
||||||
const isContainGrid = React.useMemo<boolean>(() => {
|
const isContainGrid = React.useMemo<boolean>(() => {
|
||||||
let containGrid = false;
|
let containGrid = false;
|
||||||
React.Children.forEach(children as React.ReactElement, (element: JSX.Element) => {
|
React.Children.forEach(children as React.ReactElement, (element: React.JSX.Element) => {
|
||||||
if (element?.type === Grid) {
|
if (element?.type === Grid) {
|
||||||
containGrid = true;
|
containGrid = true;
|
||||||
}
|
}
|
||||||
|
@ -59,7 +59,7 @@ const Carousel = React.forwardRef<CarouselRef, CarouselProps>((props, ref) => {
|
|||||||
...otherProps
|
...otherProps
|
||||||
} = props;
|
} = props;
|
||||||
const { getPrefixCls, direction, carousel } = React.useContext(ConfigContext);
|
const { getPrefixCls, direction, carousel } = React.useContext(ConfigContext);
|
||||||
const slickRef = React.useRef<any>();
|
const slickRef = React.useRef<any>(null);
|
||||||
|
|
||||||
const goTo = (slide: number, dontAnimate = false) => {
|
const goTo = (slide: number, dontAnimate = false) => {
|
||||||
slickRef.current.slickGoTo(slide, dontAnimate);
|
slickRef.current.slickGoTo(slide, dontAnimate);
|
||||||
|
@ -2429,15 +2429,7 @@ exports[`renders components/cascader/demo/render-panel.tsx extend context correc
|
|||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`renders components/cascader/demo/render-panel.tsx extend context correctly 2`] = `
|
exports[`renders components/cascader/demo/render-panel.tsx extend context correctly 2`] = `[]`;
|
||||||
[
|
|
||||||
"Warning: Received \`%s\` for a non-boolean attribute \`%s\`.
|
|
||||||
|
|
||||||
If you want to write it to the DOM, pass a string instead: %s="%s" or %s={value.toString()}.
|
|
||||||
|
|
||||||
If you used to conditionally omit it with %s={condition && value}, pass %s={condition ? value : undefined} instead.%s",
|
|
||||||
]
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`renders components/cascader/demo/search.tsx extend context correctly 1`] = `
|
exports[`renders components/cascader/demo/search.tsx extend context correctly 1`] = `
|
||||||
<div
|
<div
|
||||||
|
@ -370,7 +370,9 @@ if (process.env.NODE_ENV !== 'production') {
|
|||||||
|
|
||||||
// We don't care debug panel
|
// We don't care debug panel
|
||||||
/* istanbul ignore next */
|
/* istanbul ignore next */
|
||||||
const PurePanel = genPurePanel(Cascader);
|
const PurePanel = genPurePanel(Cascader, undefined, undefined, (props: any) =>
|
||||||
|
omit(props, ['visible']),
|
||||||
|
);
|
||||||
|
|
||||||
Cascader.SHOW_PARENT = SHOW_PARENT;
|
Cascader.SHOW_PARENT = SHOW_PARENT;
|
||||||
Cascader.SHOW_CHILD = SHOW_CHILD;
|
Cascader.SHOW_CHILD = SHOW_CHILD;
|
||||||
|
@ -111,7 +111,14 @@ const Collapse = React.forwardRef<HTMLDivElement, CollapseProps>((props, ref) =>
|
|||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
return cloneElement(icon, () => ({
|
return cloneElement(icon, () => ({
|
||||||
className: classNames((icon as React.ReactElement)?.props?.className, `${prefixCls}-arrow`),
|
className: classNames(
|
||||||
|
(
|
||||||
|
icon as React.ReactElement<{
|
||||||
|
className?: string;
|
||||||
|
}>
|
||||||
|
)?.props?.className,
|
||||||
|
`${prefixCls}-arrow`,
|
||||||
|
),
|
||||||
}));
|
}));
|
||||||
},
|
},
|
||||||
[mergedExpandIcon, prefixCls],
|
[mergedExpandIcon, prefixCls],
|
||||||
@ -137,25 +144,30 @@ const Collapse = React.forwardRef<HTMLDivElement, CollapseProps>((props, ref) =>
|
|||||||
leavedClassName: `${prefixCls}-content-hidden`,
|
leavedClassName: `${prefixCls}-content-hidden`,
|
||||||
};
|
};
|
||||||
|
|
||||||
const items = React.useMemo<React.ReactNode[] | null>(
|
const items = React.useMemo<React.ReactNode[] | null>(() => {
|
||||||
() =>
|
if (children) {
|
||||||
children
|
return toArray(children).map((child, index) => {
|
||||||
? toArray(children).map<React.ReactNode>((child, index) => {
|
const childProps = (
|
||||||
if (child.props?.disabled) {
|
child as React.ReactElement<{
|
||||||
const key = child.key ?? String(index);
|
disabled?: boolean;
|
||||||
const { disabled, collapsible } = child.props;
|
collapsible?: CollapsibleType;
|
||||||
const childProps: Omit<CollapseProps, 'items'> & { key: React.Key } = {
|
}>
|
||||||
...omit(child.props, ['disabled']),
|
).props;
|
||||||
key,
|
|
||||||
collapsible: collapsible ?? (disabled ? 'disabled' : undefined),
|
if (childProps?.disabled) {
|
||||||
};
|
const key = child.key ?? String(index);
|
||||||
return cloneElement(child, childProps);
|
const mergedChildProps: Omit<CollapseProps, 'items'> & { key: React.Key } = {
|
||||||
}
|
...omit(child.props as any, ['disabled']),
|
||||||
return child;
|
key,
|
||||||
})
|
collapsible: childProps.collapsible ?? 'disabled',
|
||||||
: null,
|
};
|
||||||
[children],
|
return cloneElement(child, mergedChildProps);
|
||||||
);
|
}
|
||||||
|
return child;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}, [children]);
|
||||||
|
|
||||||
return wrapCSSVar(
|
return wrapCSSVar(
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
|
30
components/config-provider/UnstableContext.tsx
Normal file
30
components/config-provider/UnstableContext.tsx
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
import * as React from 'react';
|
||||||
|
import { render, unmount } from 'rc-util/lib/React/render';
|
||||||
|
|
||||||
|
export type UnmountType = () => Promise<void>;
|
||||||
|
export type RenderType = (
|
||||||
|
node: React.ReactElement,
|
||||||
|
container: Element | DocumentFragment,
|
||||||
|
) => UnmountType;
|
||||||
|
|
||||||
|
const defaultReactRender: RenderType = (node, container) => {
|
||||||
|
render(node, container);
|
||||||
|
return () => {
|
||||||
|
return unmount(container);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
let unstableRender: RenderType = defaultReactRender;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated Set React render function for compatible usage.
|
||||||
|
* This is internal usage only compatible with React 19.
|
||||||
|
* And will be removed in next major version.
|
||||||
|
*/
|
||||||
|
export function unstableSetRender(render: RenderType) {
|
||||||
|
unstableRender = render;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getReactRender() {
|
||||||
|
return unstableRender;
|
||||||
|
}
|
@ -12,6 +12,18 @@ import Modal from '../../modal';
|
|||||||
import Pagination from '../../pagination';
|
import Pagination from '../../pagination';
|
||||||
import TimePicker from '../../time-picker';
|
import TimePicker from '../../time-picker';
|
||||||
|
|
||||||
|
// TODO: Remove this. Mock for React 19
|
||||||
|
jest.mock('react-dom', () => {
|
||||||
|
const realReactDOM = jest.requireActual('react-dom');
|
||||||
|
|
||||||
|
if (realReactDOM.version.startsWith('19')) {
|
||||||
|
const realReactDOMClient = jest.requireActual('react-dom/client');
|
||||||
|
realReactDOM.createRoot = realReactDOMClient.createRoot;
|
||||||
|
}
|
||||||
|
|
||||||
|
return realReactDOM;
|
||||||
|
});
|
||||||
|
|
||||||
describe('ConfigProvider.Locale', () => {
|
describe('ConfigProvider.Locale', () => {
|
||||||
function $$(selector: string): NodeListOf<Element> {
|
function $$(selector: string): NodeListOf<Element> {
|
||||||
return document.body.querySelectorAll(selector);
|
return document.body.querySelectorAll(selector);
|
||||||
|
@ -193,12 +193,26 @@ const Page: React.FC = () => {
|
|||||||
Begin Tour
|
Begin Tour
|
||||||
</Button>
|
</Button>
|
||||||
<Space>
|
<Space>
|
||||||
<Button ref={(node) => node && tourRefs.current.splice(0, 0, node)}> Upload</Button>
|
<Button
|
||||||
<Button ref={(node) => node && tourRefs.current.splice(1, 0, node)} type="primary">
|
ref={(node) => {
|
||||||
|
node && tourRefs.current.splice(0, 0, node);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{' '}
|
||||||
|
Upload
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
ref={(node) => {
|
||||||
|
node && tourRefs.current.splice(1, 0, node);
|
||||||
|
}}
|
||||||
|
type="primary"
|
||||||
|
>
|
||||||
Save
|
Save
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
ref={(node) => node && tourRefs.current.splice(2, 0, node)}
|
ref={(node) => {
|
||||||
|
node && tourRefs.current.splice(2, 0, node);
|
||||||
|
}}
|
||||||
icon={<EllipsisOutlined />}
|
icon={<EllipsisOutlined />}
|
||||||
/>
|
/>
|
||||||
</Space>
|
</Space>
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
|
import type { JSX } from 'react';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
|
|
||||||
function notEmpty(val: any) {
|
function notEmpty(val: any) {
|
||||||
|
@ -11,6 +11,9 @@ export interface DescriptionsItemProps {
|
|||||||
span?: number;
|
span?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
const DescriptionsItem: React.FC<DescriptionsItemProps> = ({ children }) => children as JSX.Element;
|
// JSX Structure Syntactic Sugar. Never reach the render code.
|
||||||
|
/* istanbul ignore next */
|
||||||
|
const DescriptionsItem: React.FC<DescriptionsItemProps> = ({ children }) =>
|
||||||
|
children as React.JSX.Element;
|
||||||
|
|
||||||
export default DescriptionsItem;
|
export default DescriptionsItem;
|
||||||
|
@ -7,7 +7,10 @@ import type { ScreenMap } from '../../_util/responsiveObserver';
|
|||||||
|
|
||||||
// Convert children into items
|
// Convert children into items
|
||||||
const transChildren2Items = (childNodes?: React.ReactNode) =>
|
const transChildren2Items = (childNodes?: React.ReactNode) =>
|
||||||
toArray(childNodes).map((node) => ({ ...node?.props, key: node.key }));
|
toArray(childNodes).map((node) => ({
|
||||||
|
...(node as React.ReactElement<any>)?.props,
|
||||||
|
key: node.key,
|
||||||
|
}));
|
||||||
|
|
||||||
export default function useItems(
|
export default function useItems(
|
||||||
screens: ScreenMap,
|
screens: ScreenMap,
|
||||||
|
@ -52,7 +52,12 @@ const App: React.FC = () => {
|
|||||||
menu={{ items }}
|
menu={{ items }}
|
||||||
dropdownRender={(menu) => (
|
dropdownRender={(menu) => (
|
||||||
<div style={contentStyle}>
|
<div style={contentStyle}>
|
||||||
{React.cloneElement(menu as React.ReactElement, { style: menuStyle })}
|
{React.cloneElement(
|
||||||
|
menu as React.ReactElement<{
|
||||||
|
style: React.CSSProperties;
|
||||||
|
}>,
|
||||||
|
{ style: menuStyle },
|
||||||
|
)}
|
||||||
<Divider style={{ margin: 0 }} />
|
<Divider style={{ margin: 0 }} />
|
||||||
<Space style={{ padding: 8 }}>
|
<Space style={{ padding: 8 }}>
|
||||||
<Button type="primary">Click me!</Button>
|
<Button type="primary">Click me!</Button>
|
||||||
|
@ -178,7 +178,10 @@ const Dropdown: CompoundedComponent = (props) => {
|
|||||||
|
|
||||||
const child = React.Children.only(
|
const child = React.Children.only(
|
||||||
isPrimitive(children) ? <span>{children}</span> : children,
|
isPrimitive(children) ? <span>{children}</span> : children,
|
||||||
) as React.ReactElement;
|
) as React.ReactElement<{
|
||||||
|
className?: string;
|
||||||
|
disabled?: boolean;
|
||||||
|
}>;
|
||||||
|
|
||||||
const dropdownTrigger = cloneElement(child, {
|
const dropdownTrigger = cloneElement(child, {
|
||||||
className: classNames(
|
className: classNames(
|
||||||
|
@ -8,8 +8,6 @@ import { fireEvent, render, waitFakeTimer } from '../../../tests/utils';
|
|||||||
const { BackTop } = FloatButton;
|
const { BackTop } = FloatButton;
|
||||||
|
|
||||||
describe('BackTop', () => {
|
describe('BackTop', () => {
|
||||||
const errSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
|
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
jest.useFakeTimers();
|
jest.useFakeTimers();
|
||||||
});
|
});
|
||||||
@ -57,6 +55,8 @@ describe('BackTop', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('no error when BackTop work', () => {
|
it('no error when BackTop work', () => {
|
||||||
|
const errSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
|
||||||
|
|
||||||
render(<BackTop visibilityHeight={0} />);
|
render(<BackTop visibilityHeight={0} />);
|
||||||
expect(errSpy).not.toHaveBeenCalled();
|
expect(errSpy).not.toHaveBeenCalled();
|
||||||
errSpy.mockRestore();
|
errSpy.mockRestore();
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
|
import type { JSX } from 'react';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { Field, FieldContext, ListContext } from 'rc-field-form';
|
import { Field, FieldContext, ListContext } from 'rc-field-form';
|
||||||
import type { FieldProps } from 'rc-field-form/lib/Field';
|
import type { FieldProps } from 'rc-field-form/lib/Field';
|
||||||
@ -165,7 +166,7 @@ function InternalFormItem<Values = any>(props: FormItemProps<Values>): React.Rea
|
|||||||
// ========================= MISC =========================
|
// ========================= MISC =========================
|
||||||
// Get `noStyle` required info
|
// Get `noStyle` required info
|
||||||
const listContext = React.useContext(ListContext);
|
const listContext = React.useContext(ListContext);
|
||||||
const fieldKeyPathRef = React.useRef<InternalNamePath>();
|
const fieldKeyPathRef = React.useRef<InternalNamePath>(null);
|
||||||
|
|
||||||
// ======================== Errors ========================
|
// ======================== Errors ========================
|
||||||
// >>>>> Collect sub field errors
|
// >>>>> Collect sub field errors
|
||||||
@ -361,12 +362,19 @@ function InternalFormItem<Values = any>(props: FormItemProps<Values>): React.Rea
|
|||||||
);
|
);
|
||||||
} else if (React.isValidElement(mergedChildren)) {
|
} else if (React.isValidElement(mergedChildren)) {
|
||||||
warning(
|
warning(
|
||||||
mergedChildren.props.defaultValue === undefined,
|
(
|
||||||
|
mergedChildren as React.ReactElement<{
|
||||||
|
defaultValue?: any;
|
||||||
|
}>
|
||||||
|
).props.defaultValue === undefined,
|
||||||
'usage',
|
'usage',
|
||||||
'`defaultValue` will not work on controlled Field. You should use `initialValues` of Form instead.',
|
'`defaultValue` will not work on controlled Field. You should use `initialValues` of Form instead.',
|
||||||
);
|
);
|
||||||
|
|
||||||
const childProps = { ...mergedChildren.props, ...mergedControl };
|
const childProps = {
|
||||||
|
...(mergedChildren as React.ReactElement<any>).props,
|
||||||
|
...mergedControl,
|
||||||
|
};
|
||||||
if (!childProps.id) {
|
if (!childProps.id) {
|
||||||
childProps.id = fieldId;
|
childProps.id = fieldId;
|
||||||
}
|
}
|
||||||
@ -403,7 +411,7 @@ function InternalFormItem<Values = any>(props: FormItemProps<Values>): React.Rea
|
|||||||
triggers.forEach((eventName) => {
|
triggers.forEach((eventName) => {
|
||||||
childProps[eventName] = (...args: any[]) => {
|
childProps[eventName] = (...args: any[]) => {
|
||||||
mergedControl[eventName]?.(...args);
|
mergedControl[eventName]?.(...args);
|
||||||
mergedChildren.props[eventName]?.(...args);
|
(mergedChildren as React.ReactElement<any>).props[eventName]?.(...args);
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
|
import type { JSX } from 'react';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { get, set } from 'rc-util';
|
import { get, set } from 'rc-util';
|
||||||
import useLayoutEffect from 'rc-util/lib/hooks/useLayoutEffect';
|
import useLayoutEffect from 'rc-util/lib/hooks/useLayoutEffect';
|
||||||
|
@ -10,7 +10,7 @@ import Form from '..';
|
|||||||
import { resetWarned } from '../../_util/warning';
|
import { resetWarned } from '../../_util/warning';
|
||||||
import mountTest from '../../../tests/shared/mountTest';
|
import mountTest from '../../../tests/shared/mountTest';
|
||||||
import rtlTest from '../../../tests/shared/rtlTest';
|
import rtlTest from '../../../tests/shared/rtlTest';
|
||||||
import { fireEvent, pureRender, render, screen, waitFakeTimer } from '../../../tests/utils';
|
import { act, fireEvent, pureRender, render, screen, waitFakeTimer } from '../../../tests/utils';
|
||||||
import Button from '../../button';
|
import Button from '../../button';
|
||||||
import Cascader from '../../cascader';
|
import Cascader from '../../cascader';
|
||||||
import Checkbox from '../../checkbox';
|
import Checkbox from '../../checkbox';
|
||||||
@ -126,7 +126,9 @@ describe('Form', () => {
|
|||||||
await waitFakeTimer();
|
await waitFakeTimer();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await form.validateFields();
|
await act(async () => {
|
||||||
|
await form.validateFields();
|
||||||
|
});
|
||||||
} catch {
|
} catch {
|
||||||
// do nothing
|
// do nothing
|
||||||
}
|
}
|
||||||
@ -2244,7 +2246,7 @@ describe('Form', () => {
|
|||||||
await waitFakeTimer();
|
await waitFakeTimer();
|
||||||
|
|
||||||
// initial validate
|
// initial validate
|
||||||
const initTriggerTime = ReactVersion.startsWith('18') ? 2 : 1;
|
const initTriggerTime = ReactVersion.startsWith('18') || ReactVersion.startsWith('19') ? 2 : 1;
|
||||||
expect(onChange).toHaveBeenCalledTimes(initTriggerTime);
|
expect(onChange).toHaveBeenCalledTimes(initTriggerTime);
|
||||||
let idx = 1;
|
let idx = 1;
|
||||||
expect(onChange).toHaveBeenNthCalledWith(idx++, '');
|
expect(onChange).toHaveBeenNthCalledWith(idx++, '');
|
||||||
|
@ -26,7 +26,7 @@ interface ModalFormProps {
|
|||||||
|
|
||||||
// reset form fields when modal is form, closed
|
// reset form fields when modal is form, closed
|
||||||
const useResetFormOnCloseModal = ({ form, open }: { form: FormInstance; open: boolean }) => {
|
const useResetFormOnCloseModal = ({ form, open }: { form: FormInstance; open: boolean }) => {
|
||||||
const prevOpenRef = useRef<boolean>();
|
const prevOpenRef = useRef<boolean>(null);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
prevOpenRef.current = open;
|
prevOpenRef.current = open;
|
||||||
}, [open]);
|
}, [open]);
|
||||||
|
@ -177,3 +177,6 @@ export { default as Watermark } from './watermark';
|
|||||||
export type { WatermarkProps } from './watermark';
|
export type { WatermarkProps } from './watermark';
|
||||||
export { default as Splitter } from './splitter';
|
export { default as Splitter } from './splitter';
|
||||||
export type { SplitterProps } from './splitter';
|
export type { SplitterProps } from './splitter';
|
||||||
|
|
||||||
|
// TODO: Remove in v6
|
||||||
|
export { unstableSetRender } from './config-provider/UnstableContext';
|
||||||
|
@ -8,10 +8,10 @@ import { composeRef } from 'rc-util/lib/ref';
|
|||||||
|
|
||||||
import type { ConfigConsumerProps } from '../config-provider';
|
import type { ConfigConsumerProps } from '../config-provider';
|
||||||
import { ConfigContext } from '../config-provider';
|
import { ConfigContext } from '../config-provider';
|
||||||
|
import DisabledContext from '../config-provider/DisabledContext';
|
||||||
import useRemovePasswordTimeout from './hooks/useRemovePasswordTimeout';
|
import useRemovePasswordTimeout from './hooks/useRemovePasswordTimeout';
|
||||||
import type { InputProps, InputRef } from './Input';
|
import type { InputProps, InputRef } from './Input';
|
||||||
import Input from './Input';
|
import Input from './Input';
|
||||||
import DisabledContext from '../config-provider/DisabledContext';
|
|
||||||
|
|
||||||
const defaultIconRender = (visible: boolean): React.ReactNode =>
|
const defaultIconRender = (visible: boolean): React.ReactNode =>
|
||||||
visible ? <EyeOutlined /> : <EyeInvisibleOutlined />;
|
visible ? <EyeOutlined /> : <EyeInvisibleOutlined />;
|
||||||
@ -70,13 +70,13 @@ const Password = React.forwardRef<InputRef, PasswordProps>((props, ref) => {
|
|||||||
if (visible) {
|
if (visible) {
|
||||||
removePasswordTimeout();
|
removePasswordTimeout();
|
||||||
}
|
}
|
||||||
setVisible((prevState) => {
|
|
||||||
const newState = !prevState;
|
const nextVisible = !visible;
|
||||||
if (typeof visibilityToggle === 'object') {
|
setVisible(nextVisible);
|
||||||
visibilityToggle.onVisibleChange?.(newState);
|
|
||||||
}
|
if (typeof visibilityToggle === 'object') {
|
||||||
return newState;
|
visibilityToggle.onVisibleChange?.(nextVisible);
|
||||||
});
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const getIcon = (prefixCls: string) => {
|
const getIcon = (prefixCls: string) => {
|
||||||
|
@ -98,7 +98,11 @@ const Search = React.forwardRef<InputRef, SearchProps>((props, ref) => {
|
|||||||
button = cloneElement(enterButtonAsElement, {
|
button = cloneElement(enterButtonAsElement, {
|
||||||
onMouseDown,
|
onMouseDown,
|
||||||
onClick: (e: React.MouseEvent<HTMLButtonElement>) => {
|
onClick: (e: React.MouseEvent<HTMLButtonElement>) => {
|
||||||
enterButtonAsElement?.props?.onClick?.(e);
|
(
|
||||||
|
enterButtonAsElement as React.ReactElement<{
|
||||||
|
onClick?: React.MouseEventHandler<HTMLButtonElement>;
|
||||||
|
}>
|
||||||
|
)?.props?.onClick?.(e);
|
||||||
onSearch(e);
|
onSearch(e);
|
||||||
},
|
},
|
||||||
key: 'enterButton',
|
key: 'enterButton',
|
||||||
|
@ -5,7 +5,14 @@ import { spyElementPrototypes } from 'rc-util/lib/test/domHook';
|
|||||||
import Input from '..';
|
import Input from '..';
|
||||||
import focusTest from '../../../tests/shared/focusTest';
|
import focusTest from '../../../tests/shared/focusTest';
|
||||||
import type { RenderOptions } from '../../../tests/utils';
|
import type { RenderOptions } from '../../../tests/utils';
|
||||||
import { fireEvent, pureRender, render, triggerResize, waitFakeTimer } from '../../../tests/utils';
|
import {
|
||||||
|
fireEvent,
|
||||||
|
pureRender,
|
||||||
|
render,
|
||||||
|
triggerResize,
|
||||||
|
waitFakeTimer,
|
||||||
|
waitFakeTimer19,
|
||||||
|
} from '../../../tests/utils';
|
||||||
import type { TextAreaRef } from '../TextArea';
|
import type { TextAreaRef } from '../TextArea';
|
||||||
|
|
||||||
const { TextArea } = Input;
|
const { TextArea } = Input;
|
||||||
@ -50,15 +57,15 @@ describe('TextArea', () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const { container, rerender } = pureRender(genTextArea());
|
const { container, rerender } = pureRender(genTextArea());
|
||||||
await waitFakeTimer();
|
await waitFakeTimer19();
|
||||||
expect(onInternalAutoSize).toHaveBeenCalledTimes(1);
|
expect(onInternalAutoSize).toHaveBeenCalledTimes(1);
|
||||||
|
|
||||||
rerender(genTextArea({ value: '1111\n2222\n3333' }));
|
rerender(genTextArea({ value: '1111\n2222\n3333' }));
|
||||||
await waitFakeTimer();
|
await waitFakeTimer19();
|
||||||
expect(onInternalAutoSize).toHaveBeenCalledTimes(2);
|
expect(onInternalAutoSize).toHaveBeenCalledTimes(2);
|
||||||
|
|
||||||
rerender(genTextArea({ value: '1111' }));
|
rerender(genTextArea({ value: '1111' }));
|
||||||
await waitFakeTimer();
|
await waitFakeTimer19();
|
||||||
expect(onInternalAutoSize).toHaveBeenCalledTimes(3);
|
expect(onInternalAutoSize).toHaveBeenCalledTimes(3);
|
||||||
|
|
||||||
expect(container.querySelector('textarea')?.style.overflow).toBeFalsy();
|
expect(container.querySelector('textarea')?.style.overflow).toBeFalsy();
|
||||||
@ -332,7 +339,6 @@ describe('TextArea allowClear', () => {
|
|||||||
const ref = React.createRef<TextAreaRef>();
|
const ref = React.createRef<TextAreaRef>();
|
||||||
const { container, unmount } = render(<Input.TextArea ref={ref} autoSize />, {
|
const { container, unmount } = render(<Input.TextArea ref={ref} autoSize />, {
|
||||||
container: document.body,
|
container: document.body,
|
||||||
legacyRoot: true,
|
|
||||||
} as RenderOptions);
|
} as RenderOptions);
|
||||||
fireEvent.focus(container.querySelector('textarea')!);
|
fireEvent.focus(container.querySelector('textarea')!);
|
||||||
container.querySelector('textarea')?.focus();
|
container.querySelector('textarea')?.focus();
|
||||||
|
@ -3,7 +3,7 @@ import { useEffect, useRef } from 'react';
|
|||||||
import type { InputRef } from '../Input';
|
import type { InputRef } from '../Input';
|
||||||
|
|
||||||
export default function useRemovePasswordTimeout(
|
export default function useRemovePasswordTimeout(
|
||||||
inputRef: React.RefObject<InputRef>,
|
inputRef: React.RefObject<InputRef | null>,
|
||||||
triggerOnMount?: boolean,
|
triggerOnMount?: boolean,
|
||||||
) {
|
) {
|
||||||
const removePasswordTimeoutRef = useRef<ReturnType<typeof setTimeout>[]>([]);
|
const removePasswordTimeoutRef = useRef<ReturnType<typeof setTimeout>[]>([]);
|
||||||
|
@ -105,7 +105,7 @@ const Sider = React.forwardRef<HTMLDivElement, SiderProps>((props, ref) => {
|
|||||||
const [wrapCSSVar, hashId, cssVarCls] = useStyle(prefixCls);
|
const [wrapCSSVar, hashId, cssVarCls] = useStyle(prefixCls);
|
||||||
|
|
||||||
// ========================= Responsive =========================
|
// ========================= Responsive =========================
|
||||||
const responsiveHandlerRef = useRef<(mql: MediaQueryListEvent | MediaQueryList) => void>();
|
const responsiveHandlerRef = useRef<(mql: MediaQueryListEvent | MediaQueryList) => void>(null);
|
||||||
responsiveHandlerRef.current = (mql: MediaQueryListEvent | MediaQueryList) => {
|
responsiveHandlerRef.current = (mql: MediaQueryListEvent | MediaQueryList) => {
|
||||||
setBelow(mql.matches);
|
setBelow(mql.matches);
|
||||||
onBreakpoint?.(mql.matches);
|
onBreakpoint?.(mql.matches);
|
||||||
|
@ -14,6 +14,18 @@ const Demo: React.FC<{ type: string }> = ({ type }) => {
|
|||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// TODO: Remove this. Mock for React 19
|
||||||
|
jest.mock('react-dom', () => {
|
||||||
|
const realReactDOM = jest.requireActual('react-dom');
|
||||||
|
|
||||||
|
if (realReactDOM.version.startsWith('19')) {
|
||||||
|
const realReactDOMClient = jest.requireActual('react-dom/client');
|
||||||
|
realReactDOM.createRoot = realReactDOMClient.createRoot;
|
||||||
|
}
|
||||||
|
|
||||||
|
return realReactDOM;
|
||||||
|
});
|
||||||
|
|
||||||
describe('Locale Provider demo', () => {
|
describe('Locale Provider demo', () => {
|
||||||
it('change type', async () => {
|
it('change type', async () => {
|
||||||
jest.useFakeTimers();
|
jest.useFakeTimers();
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
import { extendTest } from '../../../tests/shared/demoTest';
|
import { extendTest } from '../../../tests/shared/demoTest';
|
||||||
|
|
||||||
extendTest('mentions');
|
extendTest('mentions', {
|
||||||
|
skip: ['autoSize.tsx'],
|
||||||
|
});
|
||||||
|
@ -5,7 +5,7 @@ import debounce from 'lodash/debounce';
|
|||||||
const App: React.FC = () => {
|
const App: React.FC = () => {
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [users, setUsers] = useState<{ login: string; avatar_url: string }[]>([]);
|
const [users, setUsers] = useState<{ login: string; avatar_url: string }[]>([]);
|
||||||
const ref = useRef<string>();
|
const ref = useRef<string>(null);
|
||||||
|
|
||||||
const loadGithubUsers = (key: string) => {
|
const loadGithubUsers = (key: string) => {
|
||||||
if (!key) {
|
if (!key) {
|
||||||
|
@ -101,7 +101,9 @@ const MenuItem: GenericComponent = (props) => {
|
|||||||
>
|
>
|
||||||
{cloneElement(icon, {
|
{cloneElement(icon, {
|
||||||
className: classNames(
|
className: classNames(
|
||||||
React.isValidElement(icon) ? icon.props?.className : '',
|
React.isValidElement(icon)
|
||||||
|
? (icon as React.ReactElement<{ className?: string }>).props?.className
|
||||||
|
: '',
|
||||||
`${prefixCls}-item-icon`,
|
`${prefixCls}-item-icon`,
|
||||||
),
|
),
|
||||||
})}
|
})}
|
||||||
|
@ -44,7 +44,14 @@ export const OverrideProvider = React.forwardRef<
|
|||||||
return (
|
return (
|
||||||
<OverrideContext.Provider value={context}>
|
<OverrideContext.Provider value={context}>
|
||||||
<ContextIsolator space>
|
<ContextIsolator space>
|
||||||
{canRef ? React.cloneElement(children as React.ReactElement, { ref: mergedRef }) : children}
|
{canRef
|
||||||
|
? React.cloneElement(
|
||||||
|
children as React.ReactElement<{
|
||||||
|
ref?: React.Ref<HTMLElement>;
|
||||||
|
}>,
|
||||||
|
{ ref: mergedRef },
|
||||||
|
)
|
||||||
|
: children}
|
||||||
</ContextIsolator>
|
</ContextIsolator>
|
||||||
</OverrideContext.Provider>
|
</OverrideContext.Provider>
|
||||||
);
|
);
|
||||||
|
@ -5,9 +5,9 @@ import omit from 'rc-util/lib/omit';
|
|||||||
|
|
||||||
import { useZIndex } from '../_util/hooks/useZIndex';
|
import { useZIndex } from '../_util/hooks/useZIndex';
|
||||||
import { cloneElement } from '../_util/reactNode';
|
import { cloneElement } from '../_util/reactNode';
|
||||||
|
import type { SubMenuType } from './interface';
|
||||||
import type { MenuContextProps } from './MenuContext';
|
import type { MenuContextProps } from './MenuContext';
|
||||||
import MenuContext from './MenuContext';
|
import MenuContext from './MenuContext';
|
||||||
import type { SubMenuType } from './interface';
|
|
||||||
|
|
||||||
export interface SubMenuProps extends Omit<SubMenuType, 'ref' | 'key' | 'children' | 'label'> {
|
export interface SubMenuProps extends Omit<SubMenuType, 'ref' | 'key' | 'children' | 'label'> {
|
||||||
title?: React.ReactNode;
|
title?: React.ReactNode;
|
||||||
@ -43,7 +43,9 @@ const SubMenu: React.FC<SubMenuProps> = (props) => {
|
|||||||
<>
|
<>
|
||||||
{cloneElement(icon, {
|
{cloneElement(icon, {
|
||||||
className: classNames(
|
className: classNames(
|
||||||
React.isValidElement(icon) ? icon.props?.className : '',
|
React.isValidElement(icon)
|
||||||
|
? (icon as React.ReactElement<{ className?: string }>).props?.className
|
||||||
|
: '',
|
||||||
`${prefixCls}-item-icon`,
|
`${prefixCls}-item-icon`,
|
||||||
),
|
),
|
||||||
})}
|
})}
|
||||||
|
@ -70,18 +70,18 @@ const App: React.FC = () => {
|
|||||||
inlineCollapsed
|
inlineCollapsed
|
||||||
// Test only. Remove in future.
|
// Test only. Remove in future.
|
||||||
_internalRenderMenuItem={(node) =>
|
_internalRenderMenuItem={(node) =>
|
||||||
React.cloneElement(node, {
|
React.cloneElement<any>(node, {
|
||||||
style: {
|
style: {
|
||||||
...node.props.style,
|
...(node as any).props.style,
|
||||||
textDecoration: 'underline',
|
textDecoration: 'underline',
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
// Test only. Remove in future.
|
// Test only. Remove in future.
|
||||||
_internalRenderSubMenuItem={(node) =>
|
_internalRenderSubMenuItem={(node) =>
|
||||||
React.cloneElement(node, {
|
React.cloneElement<any>(node, {
|
||||||
style: {
|
style: {
|
||||||
...node.props.style,
|
...(node as any).props.style,
|
||||||
background: 'rgba(255, 255, 255, 0.3)',
|
background: 'rgba(255, 255, 255, 0.3)',
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
@ -136,7 +136,13 @@ const InternalMenu = forwardRef<RcMenuRef, InternalMenuProps>((props, ref) => {
|
|||||||
return cloneElement(mergedIcon, {
|
return cloneElement(mergedIcon, {
|
||||||
className: classNames(
|
className: classNames(
|
||||||
`${prefixCls}-submenu-expand-icon`,
|
`${prefixCls}-submenu-expand-icon`,
|
||||||
React.isValidElement<any>(mergedIcon) ? mergedIcon.props?.className : undefined,
|
React.isValidElement<any>(mergedIcon)
|
||||||
|
? (
|
||||||
|
mergedIcon as React.ReactElement<{
|
||||||
|
className?: string;
|
||||||
|
}>
|
||||||
|
).props?.className
|
||||||
|
: undefined,
|
||||||
),
|
),
|
||||||
});
|
});
|
||||||
}, [expandIcon, overrideObj?.expandIcon, menu?.expandIcon, prefixCls]);
|
}, [expandIcon, overrideObj?.expandIcon, menu?.expandIcon, prefixCls]);
|
||||||
|
@ -6,6 +6,18 @@ import App from '../../app';
|
|||||||
import ConfigProvider, { defaultPrefixCls } from '../../config-provider';
|
import ConfigProvider, { defaultPrefixCls } from '../../config-provider';
|
||||||
import { awaitPromise, triggerMotionEnd } from './util';
|
import { awaitPromise, triggerMotionEnd } from './util';
|
||||||
|
|
||||||
|
// TODO: Remove this. Mock for React 19
|
||||||
|
jest.mock('react-dom', () => {
|
||||||
|
const realReactDOM = jest.requireActual('react-dom');
|
||||||
|
|
||||||
|
if (realReactDOM.version.startsWith('19')) {
|
||||||
|
const realReactDOMClient = jest.requireActual('react-dom/client');
|
||||||
|
realReactDOM.createRoot = realReactDOMClient.createRoot;
|
||||||
|
}
|
||||||
|
|
||||||
|
return realReactDOM;
|
||||||
|
});
|
||||||
|
|
||||||
describe('message.config', () => {
|
describe('message.config', () => {
|
||||||
beforeAll(() => {
|
beforeAll(() => {
|
||||||
actWrapper(act);
|
actWrapper(act);
|
||||||
|
@ -2,6 +2,18 @@ import message, { actDestroy, actWrapper } from '..';
|
|||||||
import { act } from '../../../tests/utils';
|
import { act } from '../../../tests/utils';
|
||||||
import { awaitPromise, triggerMotionEnd } from './util';
|
import { awaitPromise, triggerMotionEnd } from './util';
|
||||||
|
|
||||||
|
// TODO: Remove this. Mock for React 19
|
||||||
|
jest.mock('react-dom', () => {
|
||||||
|
const realReactDOM = jest.requireActual('react-dom');
|
||||||
|
|
||||||
|
if (realReactDOM.version.startsWith('19')) {
|
||||||
|
const realReactDOMClient = jest.requireActual('react-dom/client');
|
||||||
|
realReactDOM.createRoot = realReactDOMClient.createRoot;
|
||||||
|
}
|
||||||
|
|
||||||
|
return realReactDOM;
|
||||||
|
});
|
||||||
|
|
||||||
describe('call close immediately', () => {
|
describe('call close immediately', () => {
|
||||||
beforeAll(() => {
|
beforeAll(() => {
|
||||||
actWrapper(act);
|
actWrapper(act);
|
||||||
|
@ -5,6 +5,18 @@ import message, { actWrapper } from '..';
|
|||||||
import { act, fireEvent, waitFakeTimer } from '../../../tests/utils';
|
import { act, fireEvent, waitFakeTimer } from '../../../tests/utils';
|
||||||
import { awaitPromise, triggerMotionEnd } from './util';
|
import { awaitPromise, triggerMotionEnd } from './util';
|
||||||
|
|
||||||
|
// TODO: Remove this. Mock for React 19
|
||||||
|
jest.mock('react-dom', () => {
|
||||||
|
const realReactDOM = jest.requireActual('react-dom');
|
||||||
|
|
||||||
|
if (realReactDOM.version.startsWith('19')) {
|
||||||
|
const realReactDOMClient = jest.requireActual('react-dom/client');
|
||||||
|
realReactDOM.createRoot = realReactDOMClient.createRoot;
|
||||||
|
}
|
||||||
|
|
||||||
|
return realReactDOM;
|
||||||
|
});
|
||||||
|
|
||||||
describe('message', () => {
|
describe('message', () => {
|
||||||
beforeAll(() => {
|
beforeAll(() => {
|
||||||
actWrapper(act);
|
actWrapper(act);
|
||||||
|
@ -1,10 +1,22 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import message, { actWrapper } from '..';
|
import message, { actWrapper } from '..';
|
||||||
import { act, render, waitFakeTimer } from '../../../tests/utils';
|
import { act, render, waitFakeTimer, waitFakeTimer19 } from '../../../tests/utils';
|
||||||
import ConfigProvider from '../../config-provider';
|
import ConfigProvider from '../../config-provider';
|
||||||
import { awaitPromise, triggerMotionEnd } from './util';
|
import { awaitPromise, triggerMotionEnd } from './util';
|
||||||
|
|
||||||
|
// TODO: Remove this. Mock for React 19
|
||||||
|
jest.mock('react-dom', () => {
|
||||||
|
const realReactDOM = jest.requireActual('react-dom');
|
||||||
|
|
||||||
|
if (realReactDOM.version.startsWith('19')) {
|
||||||
|
const realReactDOMClient = jest.requireActual('react-dom/client');
|
||||||
|
realReactDOM.createRoot = realReactDOMClient.createRoot;
|
||||||
|
}
|
||||||
|
|
||||||
|
return realReactDOM;
|
||||||
|
});
|
||||||
|
|
||||||
describe('message static warning', () => {
|
describe('message static warning', () => {
|
||||||
beforeAll(() => {
|
beforeAll(() => {
|
||||||
actWrapper(act);
|
actWrapper(act);
|
||||||
@ -32,11 +44,12 @@ describe('message static warning', () => {
|
|||||||
content: <div className="bamboo" />,
|
content: <div className="bamboo" />,
|
||||||
duration: 0,
|
duration: 0,
|
||||||
});
|
});
|
||||||
await waitFakeTimer();
|
await waitFakeTimer19();
|
||||||
|
|
||||||
expect(document.querySelector('.bamboo')).toBeTruthy();
|
expect(document.querySelector('.bamboo')).toBeTruthy();
|
||||||
|
|
||||||
expect(errSpy).not.toHaveBeenCalled();
|
expect(errSpy).not.toHaveBeenCalled();
|
||||||
|
errSpy.mockRestore();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('warning if use theme', async () => {
|
it('warning if use theme', async () => {
|
||||||
@ -54,5 +67,6 @@ describe('message static warning', () => {
|
|||||||
expect(errSpy).toHaveBeenCalledWith(
|
expect(errSpy).toHaveBeenCalledWith(
|
||||||
"Warning: [antd: message] Static function can not consume context like dynamic theme. Please use 'App' component instead.",
|
"Warning: [antd: message] Static function can not consume context like dynamic theme. Please use 'App' component instead.",
|
||||||
);
|
);
|
||||||
|
errSpy.mockRestore();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -2,6 +2,18 @@ import message, { actWrapper } from '..';
|
|||||||
import { act } from '../../../tests/utils';
|
import { act } from '../../../tests/utils';
|
||||||
import { awaitPromise, triggerMotionEnd } from './util';
|
import { awaitPromise, triggerMotionEnd } from './util';
|
||||||
|
|
||||||
|
// TODO: Remove this. Mock for React 19
|
||||||
|
jest.mock('react-dom', () => {
|
||||||
|
const realReactDOM = jest.requireActual('react-dom');
|
||||||
|
|
||||||
|
if (realReactDOM.version.startsWith('19')) {
|
||||||
|
const realReactDOMClient = jest.requireActual('react-dom/client');
|
||||||
|
realReactDOM.createRoot = realReactDOMClient.createRoot;
|
||||||
|
}
|
||||||
|
|
||||||
|
return realReactDOM;
|
||||||
|
});
|
||||||
|
|
||||||
describe('message.typescript', () => {
|
describe('message.typescript', () => {
|
||||||
beforeAll(() => {
|
beforeAll(() => {
|
||||||
actWrapper(act);
|
actWrapper(act);
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import React, { useContext } from 'react';
|
import React, { useContext } from 'react';
|
||||||
import { render } from 'rc-util/lib/React/render';
|
|
||||||
|
|
||||||
import { AppConfigContext } from '../app/context';
|
import { AppConfigContext } from '../app/context';
|
||||||
import ConfigProvider, { ConfigContext, globalConfig, warnContext } from '../config-provider';
|
import ConfigProvider, { ConfigContext, globalConfig, warnContext } from '../config-provider';
|
||||||
|
import { getReactRender } from '../config-provider/UnstableContext';
|
||||||
import type {
|
import type {
|
||||||
ArgsProps,
|
ArgsProps,
|
||||||
ConfigOptions,
|
ConfigOptions,
|
||||||
@ -132,7 +132,9 @@ function flushNotice() {
|
|||||||
|
|
||||||
// Delay render to avoid sync issue
|
// Delay render to avoid sync issue
|
||||||
act(() => {
|
act(() => {
|
||||||
render(
|
const reactRender = getReactRender();
|
||||||
|
|
||||||
|
reactRender(
|
||||||
<GlobalHolderWrapper
|
<GlobalHolderWrapper
|
||||||
ref={(node) => {
|
ref={(node) => {
|
||||||
const { instance, sync } = node || {};
|
const { instance, sync } = node || {};
|
||||||
|
@ -18,6 +18,18 @@ const { confirm } = Modal;
|
|||||||
|
|
||||||
jest.mock('rc-motion');
|
jest.mock('rc-motion');
|
||||||
|
|
||||||
|
// TODO: Remove this. Mock for React 19
|
||||||
|
jest.mock('react-dom', () => {
|
||||||
|
const realReactDOM = jest.requireActual('react-dom');
|
||||||
|
|
||||||
|
if (realReactDOM.version.startsWith('19')) {
|
||||||
|
const realReactDOMClient = jest.requireActual('react-dom/client');
|
||||||
|
realReactDOM.createRoot = realReactDOMClient.createRoot;
|
||||||
|
}
|
||||||
|
|
||||||
|
return realReactDOM;
|
||||||
|
});
|
||||||
|
|
||||||
(global as any).injectPromise = false;
|
(global as any).injectPromise = false;
|
||||||
(global as any).rejectPromise = null;
|
(global as any).rejectPromise = null;
|
||||||
|
|
||||||
|
@ -14,6 +14,18 @@ import type { ModalFunc } from '../confirm';
|
|||||||
jest.mock('rc-util/lib/Portal');
|
jest.mock('rc-util/lib/Portal');
|
||||||
jest.mock('rc-motion');
|
jest.mock('rc-motion');
|
||||||
|
|
||||||
|
// TODO: Remove this. Mock for React 19
|
||||||
|
jest.mock('react-dom', () => {
|
||||||
|
const realReactDOM = jest.requireActual('react-dom');
|
||||||
|
|
||||||
|
if (realReactDOM.version.startsWith('19')) {
|
||||||
|
const realReactDOMClient = jest.requireActual('react-dom/client');
|
||||||
|
realReactDOM.createRoot = realReactDOMClient.createRoot;
|
||||||
|
}
|
||||||
|
|
||||||
|
return realReactDOM;
|
||||||
|
});
|
||||||
|
|
||||||
describe('Modal.hook', () => {
|
describe('Modal.hook', () => {
|
||||||
// Inject CSSMotion to replace with No transition support
|
// Inject CSSMotion to replace with No transition support
|
||||||
const MockCSSMotion = genCSSMotion(false);
|
const MockCSSMotion = genCSSMotion(false);
|
||||||
|
@ -2,9 +2,21 @@ import * as React from 'react';
|
|||||||
|
|
||||||
import Modal from '..';
|
import Modal from '..';
|
||||||
import { resetWarned } from '../../_util/warning';
|
import { resetWarned } from '../../_util/warning';
|
||||||
import { render, waitFakeTimer } from '../../../tests/utils';
|
import { render, waitFakeTimer, waitFakeTimer19 } from '../../../tests/utils';
|
||||||
import ConfigProvider from '../../config-provider';
|
import ConfigProvider from '../../config-provider';
|
||||||
|
|
||||||
|
// TODO: Remove this. Mock for React 19
|
||||||
|
jest.mock('react-dom', () => {
|
||||||
|
const realReactDOM = jest.requireActual('react-dom');
|
||||||
|
|
||||||
|
if (realReactDOM.version.startsWith('19')) {
|
||||||
|
const realReactDOMClient = jest.requireActual('react-dom/client');
|
||||||
|
realReactDOM.createRoot = realReactDOMClient.createRoot;
|
||||||
|
}
|
||||||
|
|
||||||
|
return realReactDOM;
|
||||||
|
});
|
||||||
|
|
||||||
describe('Modal.confirm warning', () => {
|
describe('Modal.confirm warning', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
jest.useFakeTimers();
|
jest.useFakeTimers();
|
||||||
@ -25,11 +37,12 @@ describe('Modal.confirm warning', () => {
|
|||||||
Modal.confirm({
|
Modal.confirm({
|
||||||
content: <div className="bamboo" />,
|
content: <div className="bamboo" />,
|
||||||
});
|
});
|
||||||
await waitFakeTimer();
|
await waitFakeTimer19();
|
||||||
|
|
||||||
expect(document.querySelector('.bamboo')).toBeTruthy();
|
expect(document.querySelector('.bamboo')).toBeTruthy();
|
||||||
|
|
||||||
expect(errSpy).not.toHaveBeenCalled();
|
expect(errSpy).not.toHaveBeenCalled();
|
||||||
|
errSpy.mockRestore();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('warning if use theme', async () => {
|
it('warning if use theme', async () => {
|
||||||
@ -46,5 +59,6 @@ describe('Modal.confirm warning', () => {
|
|||||||
expect(errSpy).toHaveBeenCalledWith(
|
expect(errSpy).toHaveBeenCalledWith(
|
||||||
"Warning: [antd: Modal] Static function can not consume context like dynamic theme. Please use 'App' component instead.",
|
"Warning: [antd: Modal] Static function can not consume context like dynamic theme. Please use 'App' component instead.",
|
||||||
);
|
);
|
||||||
|
errSpy.mockRestore();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -11,12 +11,7 @@ export interface ConfirmCancelBtnProps
|
|||||||
'cancelButtonProps' | 'isSilent' | 'rootPrefixCls' | 'close' | 'onConfirm' | 'onCancel'
|
'cancelButtonProps' | 'isSilent' | 'rootPrefixCls' | 'close' | 'onConfirm' | 'onCancel'
|
||||||
> {
|
> {
|
||||||
autoFocusButton?: false | 'ok' | 'cancel' | null;
|
autoFocusButton?: false | 'ok' | 'cancel' | null;
|
||||||
cancelTextLocale?:
|
cancelTextLocale?: React.ReactNode;
|
||||||
| string
|
|
||||||
| number
|
|
||||||
| true
|
|
||||||
| React.ReactElement<any, string | React.JSXElementConstructor<any>>
|
|
||||||
| Iterable<React.ReactNode>;
|
|
||||||
mergedOkCancel?: boolean;
|
mergedOkCancel?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,12 +11,7 @@ export interface ConfirmOkBtnProps
|
|||||||
'close' | 'isSilent' | 'okType' | 'okButtonProps' | 'rootPrefixCls' | 'onConfirm' | 'onOk'
|
'close' | 'isSilent' | 'okType' | 'okButtonProps' | 'rootPrefixCls' | 'onConfirm' | 'onOk'
|
||||||
> {
|
> {
|
||||||
autoFocusButton?: false | 'ok' | 'cancel' | null;
|
autoFocusButton?: false | 'ok' | 'cancel' | null;
|
||||||
okTextLocale?:
|
okTextLocale?: React.ReactNode;
|
||||||
| string
|
|
||||||
| number
|
|
||||||
| true
|
|
||||||
| React.ReactElement<any, string | React.JSXElementConstructor<any>>
|
|
||||||
| Iterable<React.ReactNode>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const ConfirmOkBtn: FC = () => {
|
const ConfirmOkBtn: FC = () => {
|
||||||
|
@ -6,12 +6,7 @@ import { ModalContext } from '../context';
|
|||||||
import type { ModalProps } from '../interface';
|
import type { ModalProps } from '../interface';
|
||||||
|
|
||||||
export interface NormalCancelBtnProps extends Pick<ModalProps, 'cancelButtonProps' | 'onCancel'> {
|
export interface NormalCancelBtnProps extends Pick<ModalProps, 'cancelButtonProps' | 'onCancel'> {
|
||||||
cancelTextLocale?:
|
cancelTextLocale?: React.ReactNode;
|
||||||
| string
|
|
||||||
| number
|
|
||||||
| true
|
|
||||||
| React.ReactElement<any, string | React.JSXElementConstructor<any>>
|
|
||||||
| Iterable<React.ReactNode>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const NormalCancelBtn: FC = () => {
|
const NormalCancelBtn: FC = () => {
|
||||||
|
@ -8,12 +8,7 @@ import type { ModalProps } from '../interface';
|
|||||||
|
|
||||||
export interface NormalOkBtnProps
|
export interface NormalOkBtnProps
|
||||||
extends Pick<ModalProps, 'confirmLoading' | 'okType' | 'okButtonProps' | 'onOk'> {
|
extends Pick<ModalProps, 'confirmLoading' | 'okType' | 'okButtonProps' | 'onOk'> {
|
||||||
okTextLocale?:
|
okTextLocale?: React.ReactNode;
|
||||||
| string
|
|
||||||
| number
|
|
||||||
| true
|
|
||||||
| React.ReactElement<any, string | React.JSXElementConstructor<any>>
|
|
||||||
| Iterable<React.ReactNode>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const NormalOkBtn: FC = () => {
|
const NormalOkBtn: FC = () => {
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import React, { useContext } from 'react';
|
import React, { useContext } from 'react';
|
||||||
import { render as reactRender, unmount as reactUnmount } from 'rc-util/lib/React/render';
|
|
||||||
|
|
||||||
import warning from '../_util/warning';
|
import warning from '../_util/warning';
|
||||||
import ConfigProvider, { ConfigContext, globalConfig, warnContext } from '../config-provider';
|
import ConfigProvider, { ConfigContext, globalConfig, warnContext } from '../config-provider';
|
||||||
|
import { getReactRender, UnmountType } from '../config-provider/UnstableContext';
|
||||||
import type { ConfirmDialogProps } from './ConfirmDialog';
|
import type { ConfirmDialogProps } from './ConfirmDialog';
|
||||||
import ConfirmDialog from './ConfirmDialog';
|
import ConfirmDialog from './ConfirmDialog';
|
||||||
import destroyFns from './destroyFns';
|
import destroyFns from './destroyFns';
|
||||||
@ -71,6 +71,8 @@ export default function confirm(config: ModalFuncProps) {
|
|||||||
let currentConfig = { ...config, close, open: true } as any;
|
let currentConfig = { ...config, close, open: true } as any;
|
||||||
let timeoutId: ReturnType<typeof setTimeout>;
|
let timeoutId: ReturnType<typeof setTimeout>;
|
||||||
|
|
||||||
|
let reactUnmount: UnmountType;
|
||||||
|
|
||||||
function destroy(...args: any[]) {
|
function destroy(...args: any[]) {
|
||||||
const triggerCancel = args.some((param) => param?.triggerCancel);
|
const triggerCancel = args.some((param) => param?.triggerCancel);
|
||||||
if (triggerCancel) {
|
if (triggerCancel) {
|
||||||
@ -84,7 +86,7 @@ export default function confirm(config: ModalFuncProps) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
reactUnmount(container);
|
reactUnmount();
|
||||||
}
|
}
|
||||||
|
|
||||||
function render(props: any) {
|
function render(props: any) {
|
||||||
@ -102,7 +104,9 @@ export default function confirm(config: ModalFuncProps) {
|
|||||||
|
|
||||||
const dom = <ConfirmDialogWrapper {...props} />;
|
const dom = <ConfirmDialogWrapper {...props} />;
|
||||||
|
|
||||||
reactRender(
|
const reactRender = getReactRender();
|
||||||
|
|
||||||
|
reactUnmount = reactRender(
|
||||||
<ConfigProvider prefixCls={rootPrefixCls} iconPrefixCls={iconPrefixCls} theme={theme}>
|
<ConfigProvider prefixCls={rootPrefixCls} iconPrefixCls={iconPrefixCls} theme={theme}>
|
||||||
{global.holderRender ? global.holderRender(dom) : dom}
|
{global.holderRender ? global.holderRender(dom) : dom}
|
||||||
</ConfigProvider>,
|
</ConfigProvider>,
|
||||||
|
@ -7,7 +7,7 @@ const App: React.FC = () => {
|
|||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
const [disabled, setDisabled] = useState(true);
|
const [disabled, setDisabled] = useState(true);
|
||||||
const [bounds, setBounds] = useState({ left: 0, top: 0, bottom: 0, right: 0 });
|
const [bounds, setBounds] = useState({ left: 0, top: 0, bottom: 0, right: 0 });
|
||||||
const draggleRef = useRef<HTMLDivElement>(null);
|
const draggleRef = useRef<HTMLDivElement>(null!);
|
||||||
|
|
||||||
const showModal = () => {
|
const showModal = () => {
|
||||||
setOpen(true);
|
setOpen(true);
|
||||||
|
@ -51,7 +51,7 @@ export const Footer: React.FC<
|
|||||||
const [locale] = useLocale('Modal', getConfirmLocale());
|
const [locale] = useLocale('Modal', getConfirmLocale());
|
||||||
|
|
||||||
// ================== Locale Text ==================
|
// ================== Locale Text ==================
|
||||||
const okTextLocale = okText || locale?.okText;
|
const okTextLocale: React.ReactNode = okText || locale?.okText;
|
||||||
const cancelTextLocale = cancelText || locale?.cancelText;
|
const cancelTextLocale = cancelText || locale?.cancelText;
|
||||||
|
|
||||||
// ================= Context Value =================
|
// ================= Context Value =================
|
||||||
|
@ -6,6 +6,18 @@ import App from '../../app';
|
|||||||
import ConfigProvider from '../../config-provider';
|
import ConfigProvider from '../../config-provider';
|
||||||
import { awaitPromise, triggerMotionEnd } from './util';
|
import { awaitPromise, triggerMotionEnd } from './util';
|
||||||
|
|
||||||
|
// TODO: Remove this. Mock for React 19
|
||||||
|
jest.mock('react-dom', () => {
|
||||||
|
const realReactDOM = jest.requireActual('react-dom');
|
||||||
|
|
||||||
|
if (realReactDOM.version.startsWith('19')) {
|
||||||
|
const realReactDOMClient = jest.requireActual('react-dom/client');
|
||||||
|
realReactDOM.createRoot = realReactDOMClient.createRoot;
|
||||||
|
}
|
||||||
|
|
||||||
|
return realReactDOM;
|
||||||
|
});
|
||||||
|
|
||||||
describe('notification.config', () => {
|
describe('notification.config', () => {
|
||||||
beforeAll(() => {
|
beforeAll(() => {
|
||||||
actWrapper(act);
|
actWrapper(act);
|
||||||
|
@ -6,6 +6,18 @@ import { act, fireEvent } from '../../../tests/utils';
|
|||||||
import ConfigProvider, { defaultPrefixCls } from '../../config-provider';
|
import ConfigProvider, { defaultPrefixCls } from '../../config-provider';
|
||||||
import { awaitPromise, triggerMotionEnd } from './util';
|
import { awaitPromise, triggerMotionEnd } from './util';
|
||||||
|
|
||||||
|
// TODO: Remove this. Mock for React 19
|
||||||
|
jest.mock('react-dom', () => {
|
||||||
|
const realReactDOM = jest.requireActual('react-dom');
|
||||||
|
|
||||||
|
if (realReactDOM.version.startsWith('19')) {
|
||||||
|
const realReactDOMClient = jest.requireActual('react-dom/client');
|
||||||
|
realReactDOM.createRoot = realReactDOMClient.createRoot;
|
||||||
|
}
|
||||||
|
|
||||||
|
return realReactDOM;
|
||||||
|
});
|
||||||
|
|
||||||
describe('notification', () => {
|
describe('notification', () => {
|
||||||
beforeAll(() => {
|
beforeAll(() => {
|
||||||
actWrapper(act);
|
actWrapper(act);
|
||||||
|
@ -3,6 +3,18 @@ import { act, fireEvent } from '../../../tests/utils';
|
|||||||
import type { ArgsProps, GlobalConfigProps } from '../interface';
|
import type { ArgsProps, GlobalConfigProps } from '../interface';
|
||||||
import { awaitPromise, triggerMotionEnd } from './util';
|
import { awaitPromise, triggerMotionEnd } from './util';
|
||||||
|
|
||||||
|
// TODO: Remove this. Mock for React 19
|
||||||
|
jest.mock('react-dom', () => {
|
||||||
|
const realReactDOM = jest.requireActual('react-dom');
|
||||||
|
|
||||||
|
if (realReactDOM.version.startsWith('19')) {
|
||||||
|
const realReactDOMClient = jest.requireActual('react-dom/client');
|
||||||
|
realReactDOM.createRoot = realReactDOMClient.createRoot;
|
||||||
|
}
|
||||||
|
|
||||||
|
return realReactDOM;
|
||||||
|
});
|
||||||
|
|
||||||
describe('Notification.placement', () => {
|
describe('Notification.placement', () => {
|
||||||
function open(args?: Partial<ArgsProps>) {
|
function open(args?: Partial<ArgsProps>) {
|
||||||
notification.open({
|
notification.open({
|
||||||
|
@ -1,10 +1,22 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import notification, { actWrapper } from '..';
|
import notification, { actWrapper } from '..';
|
||||||
import { act, render, waitFakeTimer } from '../../../tests/utils';
|
import { act, render, waitFakeTimer, waitFakeTimer19 } from '../../../tests/utils';
|
||||||
import ConfigProvider from '../../config-provider';
|
import ConfigProvider from '../../config-provider';
|
||||||
import { awaitPromise, triggerMotionEnd } from './util';
|
import { awaitPromise, triggerMotionEnd } from './util';
|
||||||
|
|
||||||
|
// TODO: Remove this. Mock for React 19
|
||||||
|
jest.mock('react-dom', () => {
|
||||||
|
const realReactDOM = jest.requireActual('react-dom');
|
||||||
|
|
||||||
|
if (realReactDOM.version.startsWith('19')) {
|
||||||
|
const realReactDOMClient = jest.requireActual('react-dom/client');
|
||||||
|
realReactDOM.createRoot = realReactDOMClient.createRoot;
|
||||||
|
}
|
||||||
|
|
||||||
|
return realReactDOM;
|
||||||
|
});
|
||||||
|
|
||||||
describe('notification static warning', () => {
|
describe('notification static warning', () => {
|
||||||
beforeAll(() => {
|
beforeAll(() => {
|
||||||
actWrapper(act);
|
actWrapper(act);
|
||||||
@ -32,11 +44,12 @@ describe('notification static warning', () => {
|
|||||||
message: <div className="bamboo" />,
|
message: <div className="bamboo" />,
|
||||||
duration: 0,
|
duration: 0,
|
||||||
});
|
});
|
||||||
await waitFakeTimer();
|
await waitFakeTimer19();
|
||||||
|
|
||||||
expect(document.querySelector('.bamboo')).toBeTruthy();
|
expect(document.querySelector('.bamboo')).toBeTruthy();
|
||||||
|
|
||||||
expect(errSpy).not.toHaveBeenCalled();
|
expect(errSpy).not.toHaveBeenCalled();
|
||||||
|
errSpy.mockRestore();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('warning if use theme', async () => {
|
it('warning if use theme', async () => {
|
||||||
@ -54,5 +67,6 @@ describe('notification static warning', () => {
|
|||||||
expect(errSpy).toHaveBeenCalledWith(
|
expect(errSpy).toHaveBeenCalledWith(
|
||||||
"Warning: [antd: notification] Static function can not consume context like dynamic theme. Please use 'App' component instead.",
|
"Warning: [antd: notification] Static function can not consume context like dynamic theme. Please use 'App' component instead.",
|
||||||
);
|
);
|
||||||
|
errSpy.mockRestore();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import React, { useContext } from 'react';
|
import React, { useContext } from 'react';
|
||||||
import { render } from 'rc-util/lib/React/render';
|
|
||||||
|
|
||||||
import { AppConfigContext } from '../app/context';
|
import { AppConfigContext } from '../app/context';
|
||||||
import ConfigProvider, { ConfigContext, globalConfig, warnContext } from '../config-provider';
|
import ConfigProvider, { ConfigContext, globalConfig, warnContext } from '../config-provider';
|
||||||
|
import { getReactRender } from '../config-provider/UnstableContext';
|
||||||
import type { ArgsProps, GlobalConfigProps, NotificationInstance } from './interface';
|
import type { ArgsProps, GlobalConfigProps, NotificationInstance } from './interface';
|
||||||
import PurePanel from './PurePanel';
|
import PurePanel from './PurePanel';
|
||||||
import useNotification, { useInternalNotification } from './useNotification';
|
import useNotification, { useInternalNotification } from './useNotification';
|
||||||
@ -126,7 +126,9 @@ function flushNotice() {
|
|||||||
|
|
||||||
// Delay render to avoid sync issue
|
// Delay render to avoid sync issue
|
||||||
act(() => {
|
act(() => {
|
||||||
render(
|
const reactRender = getReactRender();
|
||||||
|
|
||||||
|
reactRender(
|
||||||
<GlobalHolderWrapper
|
<GlobalHolderWrapper
|
||||||
ref={(node) => {
|
ref={(node) => {
|
||||||
const { instance, sync } = node || {};
|
const { instance, sync } = node || {};
|
||||||
|
@ -7,6 +7,18 @@ import rtlTest from '../../../tests/shared/rtlTest';
|
|||||||
import { act, fireEvent, render, waitFakeTimer } from '../../../tests/utils';
|
import { act, fireEvent, render, waitFakeTimer } from '../../../tests/utils';
|
||||||
import Button from '../../button';
|
import Button from '../../button';
|
||||||
|
|
||||||
|
// TODO: Remove this. Mock for React 19
|
||||||
|
jest.mock('react-dom', () => {
|
||||||
|
const realReactDOM = jest.requireActual('react-dom');
|
||||||
|
|
||||||
|
if (realReactDOM.version.startsWith('19')) {
|
||||||
|
const realReactDOMClient = jest.requireActual('react-dom/client');
|
||||||
|
realReactDOM.createRoot = realReactDOMClient.createRoot;
|
||||||
|
}
|
||||||
|
|
||||||
|
return realReactDOM;
|
||||||
|
});
|
||||||
|
|
||||||
describe('Popconfirm', () => {
|
describe('Popconfirm', () => {
|
||||||
mountTest(() => <Popconfirm title="test" />);
|
mountTest(() => <Popconfirm title="test" />);
|
||||||
rtlTest(() => <Popconfirm title="test" />);
|
rtlTest(() => <Popconfirm title="test" />);
|
||||||
|
@ -95,7 +95,11 @@ const InternalPopover = React.forwardRef<TooltipRef, PopoverProps>((props, ref)
|
|||||||
{cloneElement(children, {
|
{cloneElement(children, {
|
||||||
onKeyDown: (e: React.KeyboardEvent<HTMLDivElement>) => {
|
onKeyDown: (e: React.KeyboardEvent<HTMLDivElement>) => {
|
||||||
if (React.isValidElement(children)) {
|
if (React.isValidElement(children)) {
|
||||||
children?.props.onKeyDown?.(e);
|
(
|
||||||
|
children as React.ReactElement<{
|
||||||
|
onKeyDown: React.KeyboardEventHandler<HTMLDivElement>;
|
||||||
|
}>
|
||||||
|
)?.props.onKeyDown?.(e);
|
||||||
}
|
}
|
||||||
onKeyDown(e);
|
onKeyDown(e);
|
||||||
},
|
},
|
||||||
|
@ -4,7 +4,7 @@ import raf from 'rc-util/lib/raf';
|
|||||||
export default function useRafLock(): [state: boolean, setState: (nextState: boolean) => void] {
|
export default function useRafLock(): [state: boolean, setState: (nextState: boolean) => void] {
|
||||||
const [state, setState] = React.useState(false);
|
const [state, setState] = React.useState(false);
|
||||||
|
|
||||||
const rafRef = React.useRef<number>();
|
const rafRef = React.useRef<number>(null);
|
||||||
const cleanup = () => {
|
const cleanup = () => {
|
||||||
raf.cancel(rafRef.current!);
|
raf.cancel(rafRef.current!);
|
||||||
};
|
};
|
||||||
|
@ -16,7 +16,10 @@ export default function Indicator(props: IndicatorProps) {
|
|||||||
|
|
||||||
if (indicator && React.isValidElement(indicator)) {
|
if (indicator && React.isValidElement(indicator)) {
|
||||||
return cloneElement(indicator, {
|
return cloneElement(indicator, {
|
||||||
className: classNames(indicator.props.className, dotClassName),
|
className: classNames(
|
||||||
|
(indicator as React.ReactElement<{ className?: string }>).props.className,
|
||||||
|
dotClassName,
|
||||||
|
),
|
||||||
percent,
|
percent,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@ import { Flex, Spin, Switch } from 'antd';
|
|||||||
const App: React.FC = () => {
|
const App: React.FC = () => {
|
||||||
const [auto, setAuto] = React.useState(false);
|
const [auto, setAuto] = React.useState(false);
|
||||||
const [percent, setPercent] = React.useState(-50);
|
const [percent, setPercent] = React.useState(-50);
|
||||||
const timerRef = React.useRef<ReturnType<typeof setTimeout>>();
|
const timerRef = React.useRef<ReturnType<typeof setTimeout>>(null);
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
timerRef.current = setTimeout(() => {
|
timerRef.current = setTimeout(() => {
|
||||||
@ -13,7 +13,7 @@ const App: React.FC = () => {
|
|||||||
return nextPercent > 150 ? -50 : nextPercent;
|
return nextPercent > 150 ? -50 : nextPercent;
|
||||||
});
|
});
|
||||||
}, 100);
|
}, 100);
|
||||||
return () => clearTimeout(timerRef.current);
|
return () => clearTimeout(timerRef.current!);
|
||||||
}, [percent]);
|
}, [percent]);
|
||||||
|
|
||||||
const mergedPercent = auto ? 'auto' : percent;
|
const mergedPercent = auto ? 'auto' : percent;
|
||||||
|
@ -12,7 +12,7 @@ export default function usePercent(
|
|||||||
percent?: number | 'auto',
|
percent?: number | 'auto',
|
||||||
): number | undefined {
|
): number | undefined {
|
||||||
const [mockPercent, setMockPercent] = React.useState(0);
|
const [mockPercent, setMockPercent] = React.useState(0);
|
||||||
const mockIntervalRef = React.useRef<ReturnType<typeof setInterval>>();
|
const mockIntervalRef = React.useRef<ReturnType<typeof setInterval>>(null);
|
||||||
|
|
||||||
const isAuto = percent === 'auto';
|
const isAuto = percent === 'auto';
|
||||||
|
|
||||||
@ -38,7 +38,7 @@ export default function usePercent(
|
|||||||
}
|
}
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
clearInterval(mockIntervalRef.current);
|
clearInterval(mockIntervalRef.current!);
|
||||||
};
|
};
|
||||||
}, [isAuto, spinning]);
|
}, [isAuto, spinning]);
|
||||||
|
|
||||||
|
@ -18,9 +18,9 @@ export default function useLegacyItems(items?: StepProps[], children?: React.Rea
|
|||||||
return items;
|
return items;
|
||||||
}
|
}
|
||||||
|
|
||||||
const childrenItems = toArray(children).map((node: React.ReactElement<StepProps>) => {
|
const childrenItems = toArray(children).map((node) => {
|
||||||
if (React.isValidElement(node)) {
|
if (React.isValidElement(node)) {
|
||||||
const { props } = node;
|
const { props } = node as React.ReactElement<StepProps>;
|
||||||
const item: StepProps = {
|
const item: StepProps = {
|
||||||
...props,
|
...props,
|
||||||
};
|
};
|
||||||
|
@ -11,6 +11,18 @@ jest.mock('rc-util/lib/Dom/isVisible', () => {
|
|||||||
return mockFn;
|
return mockFn;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// TODO: Remove this. Mock for React 19
|
||||||
|
jest.mock('react-dom', () => {
|
||||||
|
const realReactDOM = jest.requireActual('react-dom');
|
||||||
|
|
||||||
|
if (realReactDOM.version.startsWith('19')) {
|
||||||
|
const realReactDOMClient = jest.requireActual('react-dom/client');
|
||||||
|
realReactDOM.createRoot = realReactDOMClient.createRoot;
|
||||||
|
}
|
||||||
|
|
||||||
|
return realReactDOM;
|
||||||
|
});
|
||||||
|
|
||||||
describe('Switch', () => {
|
describe('Switch', () => {
|
||||||
focusTest(Switch, { refFocus: true });
|
focusTest(Switch, { refFocus: true });
|
||||||
mountTest(Switch);
|
mountTest(Switch);
|
||||||
|
@ -222,7 +222,7 @@ const InternalTable = <RecordType extends AnyObject = AnyObject>(
|
|||||||
}, [rawData]);
|
}, [rawData]);
|
||||||
|
|
||||||
const internalRefs: NonNullable<RcTableProps['internalRefs']> = {
|
const internalRefs: NonNullable<RcTableProps['internalRefs']> = {
|
||||||
body: React.useRef<HTMLDivElement>(),
|
body: React.useRef<HTMLDivElement>(null),
|
||||||
} as NonNullable<RcTableProps['internalRefs']>;
|
} as NonNullable<RcTableProps['internalRefs']>;
|
||||||
|
|
||||||
// ============================ Width =============================
|
// ============================ Width =============================
|
||||||
|
@ -3125,7 +3125,7 @@ describe('Table.filter', () => {
|
|||||||
|
|
||||||
fireEvent.click(container.querySelector('.ant-dropdown-trigger')!);
|
fireEvent.click(container.querySelector('.ant-dropdown-trigger')!);
|
||||||
expect(dropdownRender).toHaveBeenCalled();
|
expect(dropdownRender).toHaveBeenCalled();
|
||||||
expect(dropdownRender.mock.calls[0][0]).toMatchSnapshot();
|
expect(React.isValidElement(dropdownRender.mock.calls[0][0])).toBeTruthy();
|
||||||
expect(getByText('Foo')).toBeTruthy();
|
expect(getByText('Foo')).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -838,126 +838,3 @@ exports[`Table.filter renders radio filter correctly 1`] = `
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`Table.filter should support filterDropdownProps dropdownRender 1`] = `
|
|
||||||
<FilterDropdownMenuWrapper
|
|
||||||
className="ant-table-filter-dropdown"
|
|
||||||
>
|
|
||||||
<React.Fragment>
|
|
||||||
<React.Fragment>
|
|
||||||
<FilterSearch
|
|
||||||
filterSearch={false}
|
|
||||||
locale={
|
|
||||||
{
|
|
||||||
"cancelSort": "Click to cancel sorting",
|
|
||||||
"collapse": "Collapse row",
|
|
||||||
"emptyText": "No data",
|
|
||||||
"expand": "Expand row",
|
|
||||||
"filterCheckall": "Select all items",
|
|
||||||
"filterConfirm": "OK",
|
|
||||||
"filterEmptyText": "No filters",
|
|
||||||
"filterReset": "Reset",
|
|
||||||
"filterSearchPlaceholder": "Search in filters",
|
|
||||||
"filterTitle": "Filter menu",
|
|
||||||
"selectAll": "Select current page",
|
|
||||||
"selectInvert": "Invert current page",
|
|
||||||
"selectNone": "Clear all data",
|
|
||||||
"selectionAll": "Select all data",
|
|
||||||
"sortTitle": "Sort",
|
|
||||||
"triggerAsc": "Click to sort ascending",
|
|
||||||
"triggerDesc": "Click to sort descending",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
onChange={[Function]}
|
|
||||||
tablePrefixCls="ant-table"
|
|
||||||
value=""
|
|
||||||
/>
|
|
||||||
<Menu
|
|
||||||
className=""
|
|
||||||
items={
|
|
||||||
[
|
|
||||||
{
|
|
||||||
"key": "boy",
|
|
||||||
"label": <React.Fragment>
|
|
||||||
<Checkbox
|
|
||||||
checked={false}
|
|
||||||
/>
|
|
||||||
<span>
|
|
||||||
Boy
|
|
||||||
</span>
|
|
||||||
</React.Fragment>,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key": "girl",
|
|
||||||
"label": <React.Fragment>
|
|
||||||
<Checkbox
|
|
||||||
checked={false}
|
|
||||||
/>
|
|
||||||
<span>
|
|
||||||
Girl
|
|
||||||
</span>
|
|
||||||
</React.Fragment>,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"children": [
|
|
||||||
{
|
|
||||||
"key": "designer",
|
|
||||||
"label": <React.Fragment>
|
|
||||||
<Checkbox
|
|
||||||
checked={false}
|
|
||||||
/>
|
|
||||||
<span>
|
|
||||||
Designer
|
|
||||||
</span>
|
|
||||||
</React.Fragment>,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key": "coder",
|
|
||||||
"label": <React.Fragment>
|
|
||||||
<Checkbox
|
|
||||||
checked={false}
|
|
||||||
/>
|
|
||||||
<span>
|
|
||||||
Coder
|
|
||||||
</span>
|
|
||||||
</React.Fragment>,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
"key": "title",
|
|
||||||
"label": "Title",
|
|
||||||
"popupClassName": "ant-table-filter-dropdown-submenu",
|
|
||||||
},
|
|
||||||
]
|
|
||||||
}
|
|
||||||
multiple={true}
|
|
||||||
onDeselect={[Function]}
|
|
||||||
onOpenChange={[Function]}
|
|
||||||
onSelect={[Function]}
|
|
||||||
openKeys={[]}
|
|
||||||
prefixCls="ant-dropdown-menu"
|
|
||||||
selectable={true}
|
|
||||||
selectedKeys={[]}
|
|
||||||
/>
|
|
||||||
</React.Fragment>
|
|
||||||
<div
|
|
||||||
className="ant-table-filter-dropdown-btns"
|
|
||||||
>
|
|
||||||
<Button
|
|
||||||
disabled={true}
|
|
||||||
onClick={[Function]}
|
|
||||||
size="small"
|
|
||||||
type="link"
|
|
||||||
>
|
|
||||||
Reset
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
onClick={[Function]}
|
|
||||||
size="small"
|
|
||||||
type="primary"
|
|
||||||
>
|
|
||||||
OK
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</React.Fragment>
|
|
||||||
</FilterDropdownMenuWrapper>
|
|
||||||
`;
|
|
||||||
|
@ -1500,7 +1500,7 @@ Array [
|
|||||||
checked=""
|
checked=""
|
||||||
class="ant-radio-button-input"
|
class="ant-radio-button-input"
|
||||||
type="radio"
|
type="radio"
|
||||||
value=""
|
value="unset"
|
||||||
/>
|
/>
|
||||||
<span
|
<span
|
||||||
class="ant-radio-button-inner"
|
class="ant-radio-button-inner"
|
||||||
@ -1592,7 +1592,7 @@ Array [
|
|||||||
checked=""
|
checked=""
|
||||||
class="ant-radio-button-input"
|
class="ant-radio-button-input"
|
||||||
type="radio"
|
type="radio"
|
||||||
value=""
|
value="unset"
|
||||||
/>
|
/>
|
||||||
<span
|
<span
|
||||||
class="ant-radio-button-inner"
|
class="ant-radio-button-inner"
|
||||||
@ -6049,7 +6049,7 @@ Array [
|
|||||||
checked=""
|
checked=""
|
||||||
class="ant-radio-button-input"
|
class="ant-radio-button-input"
|
||||||
type="radio"
|
type="radio"
|
||||||
value=""
|
value="unset"
|
||||||
/>
|
/>
|
||||||
<span
|
<span
|
||||||
class="ant-radio-button-inner"
|
class="ant-radio-button-inner"
|
||||||
@ -6141,7 +6141,7 @@ Array [
|
|||||||
checked=""
|
checked=""
|
||||||
class="ant-radio-button-input"
|
class="ant-radio-button-input"
|
||||||
type="radio"
|
type="radio"
|
||||||
value=""
|
value="unset"
|
||||||
/>
|
/>
|
||||||
<span
|
<span
|
||||||
class="ant-radio-button-inner"
|
class="ant-radio-button-inner"
|
||||||
|
@ -1500,6 +1500,7 @@ Array [
|
|||||||
checked=""
|
checked=""
|
||||||
class="ant-radio-button-input"
|
class="ant-radio-button-input"
|
||||||
type="radio"
|
type="radio"
|
||||||
|
value="unset"
|
||||||
/>
|
/>
|
||||||
<span
|
<span
|
||||||
class="ant-radio-button-inner"
|
class="ant-radio-button-inner"
|
||||||
@ -1591,6 +1592,7 @@ Array [
|
|||||||
checked=""
|
checked=""
|
||||||
class="ant-radio-button-input"
|
class="ant-radio-button-input"
|
||||||
type="radio"
|
type="radio"
|
||||||
|
value="unset"
|
||||||
/>
|
/>
|
||||||
<span
|
<span
|
||||||
class="ant-radio-button-inner"
|
class="ant-radio-button-inner"
|
||||||
@ -5370,6 +5372,7 @@ Array [
|
|||||||
checked=""
|
checked=""
|
||||||
class="ant-radio-button-input"
|
class="ant-radio-button-input"
|
||||||
type="radio"
|
type="radio"
|
||||||
|
value="unset"
|
||||||
/>
|
/>
|
||||||
<span
|
<span
|
||||||
class="ant-radio-button-inner"
|
class="ant-radio-button-inner"
|
||||||
@ -5461,6 +5464,7 @@ Array [
|
|||||||
checked=""
|
checked=""
|
||||||
class="ant-radio-button-input"
|
class="ant-radio-button-input"
|
||||||
type="radio"
|
type="radio"
|
||||||
|
value="unset"
|
||||||
/>
|
/>
|
||||||
<span
|
<span
|
||||||
class="ant-radio-button-inner"
|
class="ant-radio-button-inner"
|
||||||
|
@ -9,5 +9,9 @@ extendTest('table', {
|
|||||||
'fixed-gapped-columns.tsx',
|
'fixed-gapped-columns.tsx',
|
||||||
'fixed-columns.tsx',
|
'fixed-columns.tsx',
|
||||||
'fixed-columns-header.tsx',
|
'fixed-columns-header.tsx',
|
||||||
|
'row-selection-debug.tsx',
|
||||||
|
'drag-sorting.tsx',
|
||||||
|
'drag-sorting-handler.tsx',
|
||||||
|
'drag-column-sorting.tsx',
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { imageDemoTest } from '../../../tests/shared/imageTest';
|
import { imageDemoTest } from '../../../tests/shared/imageTest';
|
||||||
|
|
||||||
describe('Table image', () => {
|
describe('Table image', () => {
|
||||||
imageDemoTest('table', { skip: ['virtual-list.tsx'] });
|
imageDemoTest('table', { skip: ['virtual-list.tsx', 'row-selection-debug.tsx'] });
|
||||||
});
|
});
|
||||||
|
@ -88,12 +88,12 @@ const App: React.FC = () => {
|
|||||||
const [showFooter, setShowFooter] = useState(true);
|
const [showFooter, setShowFooter] = useState(true);
|
||||||
const [rowSelection, setRowSelection] = useState<TableRowSelection<DataType> | undefined>({});
|
const [rowSelection, setRowSelection] = useState<TableRowSelection<DataType> | undefined>({});
|
||||||
const [hasData, setHasData] = useState(true);
|
const [hasData, setHasData] = useState(true);
|
||||||
const [tableLayout, setTableLayout] = useState();
|
const [tableLayout, setTableLayout] = useState<string>('unset');
|
||||||
const [top, setTop] = useState<TablePaginationPosition>('none');
|
const [top, setTop] = useState<TablePaginationPosition>('none');
|
||||||
const [bottom, setBottom] = useState<TablePaginationPosition>('bottomRight');
|
const [bottom, setBottom] = useState<TablePaginationPosition>('bottomRight');
|
||||||
const [ellipsis, setEllipsis] = useState(false);
|
const [ellipsis, setEllipsis] = useState(false);
|
||||||
const [yScroll, setYScroll] = useState(false);
|
const [yScroll, setYScroll] = useState(false);
|
||||||
const [xScroll, setXScroll] = useState<string>();
|
const [xScroll, setXScroll] = useState<string>('unset');
|
||||||
|
|
||||||
const handleBorderChange = (enable: boolean) => {
|
const handleBorderChange = (enable: boolean) => {
|
||||||
setBordered(enable);
|
setBordered(enable);
|
||||||
@ -151,7 +151,7 @@ const App: React.FC = () => {
|
|||||||
if (yScroll) {
|
if (yScroll) {
|
||||||
scroll.y = 240;
|
scroll.y = 240;
|
||||||
}
|
}
|
||||||
if (xScroll) {
|
if (xScroll !== 'unset') {
|
||||||
scroll.x = '100vw';
|
scroll.x = '100vw';
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -171,7 +171,7 @@ const App: React.FC = () => {
|
|||||||
footer: showFooter ? defaultFooter : undefined,
|
footer: showFooter ? defaultFooter : undefined,
|
||||||
rowSelection,
|
rowSelection,
|
||||||
scroll,
|
scroll,
|
||||||
tableLayout,
|
tableLayout: tableLayout === 'unset' ? undefined : (tableLayout as TableProps['tableLayout']),
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -216,14 +216,14 @@ const App: React.FC = () => {
|
|||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item label="Table Scroll">
|
<Form.Item label="Table Scroll">
|
||||||
<Radio.Group value={xScroll} onChange={handleXScrollChange}>
|
<Radio.Group value={xScroll} onChange={handleXScrollChange}>
|
||||||
<Radio.Button value={undefined}>Unset</Radio.Button>
|
<Radio.Button value="unset">Unset</Radio.Button>
|
||||||
<Radio.Button value="scroll">Scroll</Radio.Button>
|
<Radio.Button value="scroll">Scroll</Radio.Button>
|
||||||
<Radio.Button value="fixed">Fixed Columns</Radio.Button>
|
<Radio.Button value="fixed">Fixed Columns</Radio.Button>
|
||||||
</Radio.Group>
|
</Radio.Group>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item label="Table Layout">
|
<Form.Item label="Table Layout">
|
||||||
<Radio.Group value={tableLayout} onChange={handleTableLayoutChange}>
|
<Radio.Group value={tableLayout} onChange={handleTableLayoutChange}>
|
||||||
<Radio.Button value={undefined}>Unset</Radio.Button>
|
<Radio.Button value="unset">Unset</Radio.Button>
|
||||||
<Radio.Button value="fixed">Fixed</Radio.Button>
|
<Radio.Button value="fixed">Fixed</Radio.Button>
|
||||||
</Radio.Group>
|
</Radio.Group>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
@ -86,12 +86,12 @@ const App: React.FC = () => {
|
|||||||
const [showFooter, setShowFooter] = useState(true);
|
const [showFooter, setShowFooter] = useState(true);
|
||||||
const [rowSelection, setRowSelection] = useState<TableRowSelection<DataType> | undefined>({});
|
const [rowSelection, setRowSelection] = useState<TableRowSelection<DataType> | undefined>({});
|
||||||
const [hasData, setHasData] = useState(true);
|
const [hasData, setHasData] = useState(true);
|
||||||
const [tableLayout, setTableLayout] = useState();
|
const [tableLayout, setTableLayout] = useState<string>('unset');
|
||||||
const [top, setTop] = useState<TablePaginationPosition>('none');
|
const [top, setTop] = useState<TablePaginationPosition>('none');
|
||||||
const [bottom, setBottom] = useState<TablePaginationPosition>('bottomRight');
|
const [bottom, setBottom] = useState<TablePaginationPosition>('bottomRight');
|
||||||
const [ellipsis, setEllipsis] = useState(false);
|
const [ellipsis, setEllipsis] = useState(false);
|
||||||
const [yScroll, setYScroll] = useState(false);
|
const [yScroll, setYScroll] = useState(false);
|
||||||
const [xScroll, setXScroll] = useState<string>();
|
const [xScroll, setXScroll] = useState<string>('unset');
|
||||||
|
|
||||||
const handleBorderChange = (enable: boolean) => {
|
const handleBorderChange = (enable: boolean) => {
|
||||||
setBordered(enable);
|
setBordered(enable);
|
||||||
@ -149,7 +149,7 @@ const App: React.FC = () => {
|
|||||||
if (yScroll) {
|
if (yScroll) {
|
||||||
scroll.y = 240;
|
scroll.y = 240;
|
||||||
}
|
}
|
||||||
if (xScroll) {
|
if (xScroll !== 'unset') {
|
||||||
scroll.x = '100vw';
|
scroll.x = '100vw';
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -169,7 +169,7 @@ const App: React.FC = () => {
|
|||||||
footer: showFooter ? defaultFooter : undefined,
|
footer: showFooter ? defaultFooter : undefined,
|
||||||
rowSelection,
|
rowSelection,
|
||||||
scroll,
|
scroll,
|
||||||
tableLayout,
|
tableLayout: tableLayout === 'unset' ? undefined : (tableLayout as TableProps['tableLayout']),
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -214,14 +214,14 @@ const App: React.FC = () => {
|
|||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item label="Table Scroll">
|
<Form.Item label="Table Scroll">
|
||||||
<Radio.Group value={xScroll} onChange={handleXScrollChange}>
|
<Radio.Group value={xScroll} onChange={handleXScrollChange}>
|
||||||
<Radio.Button value={undefined}>Unset</Radio.Button>
|
<Radio.Button value="unset">Unset</Radio.Button>
|
||||||
<Radio.Button value="scroll">Scroll</Radio.Button>
|
<Radio.Button value="scroll">Scroll</Radio.Button>
|
||||||
<Radio.Button value="fixed">Fixed Columns</Radio.Button>
|
<Radio.Button value="fixed">Fixed Columns</Radio.Button>
|
||||||
</Radio.Group>
|
</Radio.Group>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item label="Table Layout">
|
<Form.Item label="Table Layout">
|
||||||
<Radio.Group value={tableLayout} onChange={handleTableLayoutChange}>
|
<Radio.Group value={tableLayout} onChange={handleTableLayoutChange}>
|
||||||
<Radio.Button value={undefined}>Unset</Radio.Button>
|
<Radio.Button value="unset">Unset</Radio.Button>
|
||||||
<Radio.Button value="fixed">Fixed</Radio.Button>
|
<Radio.Button value="fixed">Fixed</Radio.Button>
|
||||||
</Radio.Group>
|
</Radio.Group>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
import { extendTest } from '../../../tests/shared/demoTest';
|
import { extendTest } from '../../../tests/shared/demoTest';
|
||||||
|
|
||||||
extendTest('tabs');
|
extendTest('tabs', {
|
||||||
|
skip: ['custom-tab-bar-node.tsx'],
|
||||||
|
});
|
||||||
|
@ -27,7 +27,7 @@ const DraggableTabNode: React.FC<Readonly<DraggableTabPaneProps>> = ({ className
|
|||||||
cursor: 'move',
|
cursor: 'move',
|
||||||
};
|
};
|
||||||
|
|
||||||
return React.cloneElement(props.children as React.ReactElement, {
|
return React.cloneElement(props.children as React.ReactElement<any>, {
|
||||||
ref: setNodeRef,
|
ref: setNodeRef,
|
||||||
style,
|
style,
|
||||||
...attributes,
|
...attributes,
|
||||||
@ -62,7 +62,10 @@ const App: React.FC = () => {
|
|||||||
<SortableContext items={items.map((i) => i.key)} strategy={horizontalListSortingStrategy}>
|
<SortableContext items={items.map((i) => i.key)} strategy={horizontalListSortingStrategy}>
|
||||||
<DefaultTabBar {...tabBarProps}>
|
<DefaultTabBar {...tabBarProps}>
|
||||||
{(node) => (
|
{(node) => (
|
||||||
<DraggableTabNode {...node.props} key={node.key}>
|
<DraggableTabNode
|
||||||
|
{...(node as React.ReactElement<DraggableTabPaneProps>).props}
|
||||||
|
key={node.key}
|
||||||
|
>
|
||||||
{node}
|
{node}
|
||||||
</DraggableTabNode>
|
</DraggableTabNode>
|
||||||
)}
|
)}
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user