mirror of
https://gitee.com/ant-design/ant-design.git
synced 2024-11-30 02:59:04 +08:00
chore: fix merge
This commit is contained in:
commit
5912c0d7b2
2
.jest.js
2
.jest.js
@ -34,7 +34,7 @@ function getTestRegex(libDir) {
|
||||
module.exports = {
|
||||
verbose: true,
|
||||
testEnvironment: 'jsdom',
|
||||
setupFiles: ['./tests/setup.js'],
|
||||
setupFiles: ['./tests/setup.js', 'jest-canvas-mock'],
|
||||
setupFilesAfterEnv: ['./tests/setupAfterEnv.ts'],
|
||||
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'md'],
|
||||
modulePathIgnorePatterns: ['/_site/'],
|
||||
|
15
README.md
15
README.md
@ -10,20 +10,11 @@
|
||||
|
||||
An enterprise-class UI design language and React UI library.
|
||||
|
||||
[![CI status][github-action-image]][github-action-url]
|
||||
[![codecov][codecov-image]][codecov-url]
|
||||
[![NPM version][npm-image]][npm-url]
|
||||
[![NPM downloads][download-image]][download-url]
|
||||
[![CI status][github-action-image]][github-action-url] [![codecov][codecov-image]][codecov-url] [![NPM version][npm-image]][npm-url] [![NPM downloads][download-image]][download-url]
|
||||
|
||||
[![Total alerts][lgtm-image]][lgtm-url]
|
||||
[![][bundlephobia-image]][bundlephobia-url]
|
||||
[![][bundlesize-js-image]][unpkg-js-url]
|
||||
[![FOSSA Status][fossa-image]][fossa-url]
|
||||
[![Total alerts][lgtm-image]][lgtm-url] [![][bundlephobia-image]][bundlephobia-url] [![][bundlesize-js-image]][unpkg-js-url] [![FOSSA Status][fossa-image]][fossa-url]
|
||||
|
||||
[![Follow Twitter][twitter-image]][twitter-url]
|
||||
[![Renovate status][renovate-image]][renovate-dashboard-url]
|
||||
[![][issues-helper-image]][issues-helper-url]
|
||||
[![Issues need help][help-wanted-image]][help-wanted-url]
|
||||
[![Follow Twitter][twitter-image]][twitter-url] [![Renovate status][renovate-image]][renovate-dashboard-url] [![][issues-helper-image]][issues-helper-url] [![Issues need help][help-wanted-image]][help-wanted-url]
|
||||
|
||||
[npm-image]: http://img.shields.io/npm/v/antd.svg?style=flat-square
|
||||
[npm-url]: http://npmjs.org/package/antd
|
||||
|
@ -5,6 +5,7 @@ exports[`antd exports modules correctly 1`] = `
|
||||
"Affix",
|
||||
"Alert",
|
||||
"Anchor",
|
||||
"App",
|
||||
"AutoComplete",
|
||||
"Avatar",
|
||||
"BackTop",
|
||||
@ -40,6 +41,7 @@ exports[`antd exports modules correctly 1`] = `
|
||||
"Popconfirm",
|
||||
"Popover",
|
||||
"Progress",
|
||||
"QRCode",
|
||||
"Radio",
|
||||
"Rate",
|
||||
"Result",
|
||||
@ -65,6 +67,7 @@ exports[`antd exports modules correctly 1`] = `
|
||||
"TreeSelect",
|
||||
"Typography",
|
||||
"Upload",
|
||||
"Watermark",
|
||||
"message",
|
||||
"notification",
|
||||
"theme",
|
||||
|
@ -1,14 +0,0 @@
|
||||
import ResponsiveObserve, { responsiveMap } from '../responsiveObserve';
|
||||
|
||||
describe('Test ResponsiveObserve', () => {
|
||||
it('test ResponsiveObserve subscribe and unsubscribe', () => {
|
||||
const { xs } = responsiveMap;
|
||||
const subscribeFunc = jest.fn();
|
||||
const token = ResponsiveObserve.subscribe(subscribeFunc);
|
||||
expect(ResponsiveObserve.matchHandlers[xs].mql.matches).toBeTruthy();
|
||||
expect(subscribeFunc).toHaveBeenCalledTimes(1);
|
||||
|
||||
ResponsiveObserve.unsubscribe(token);
|
||||
expect(ResponsiveObserve.matchHandlers[xs].mql.removeListener).toHaveBeenCalled();
|
||||
});
|
||||
});
|
26
components/_util/__tests__/responsiveObserve.test.tsx
Normal file
26
components/_util/__tests__/responsiveObserve.test.tsx
Normal file
@ -0,0 +1,26 @@
|
||||
import React from 'react';
|
||||
import { render } from '../../../tests/utils';
|
||||
import useResponsiveObserve from '../responsiveObserve';
|
||||
|
||||
describe('Test ResponsiveObserve', () => {
|
||||
it('test ResponsiveObserve subscribe and unsubscribe', () => {
|
||||
let responsiveObserveRef: any;
|
||||
const Demo = () => {
|
||||
const responsiveObserve = useResponsiveObserve();
|
||||
responsiveObserveRef = responsiveObserve;
|
||||
return null;
|
||||
};
|
||||
render(<Demo />);
|
||||
const subscribeFunc = jest.fn();
|
||||
const token = responsiveObserveRef.subscribe(subscribeFunc);
|
||||
expect(
|
||||
responsiveObserveRef.matchHandlers[responsiveObserveRef.responsiveMap.xs].mql.matches,
|
||||
).toBeTruthy();
|
||||
expect(subscribeFunc).toHaveBeenCalledTimes(1);
|
||||
|
||||
responsiveObserveRef.unsubscribe(token);
|
||||
expect(
|
||||
responsiveObserveRef.matchHandlers[responsiveObserveRef.responsiveMap.xs].mql.removeListener,
|
||||
).toHaveBeenCalled();
|
||||
});
|
||||
});
|
@ -1,74 +1,85 @@
|
||||
import React from 'react';
|
||||
import type { GlobalToken } from '../theme/interface';
|
||||
import { useToken } from '../theme/internal';
|
||||
|
||||
export type Breakpoint = 'xxl' | 'xl' | 'lg' | 'md' | 'sm' | 'xs';
|
||||
export type BreakpointMap = Record<Breakpoint, string>;
|
||||
export type ScreenMap = Partial<Record<Breakpoint, boolean>>;
|
||||
export type ScreenSizeMap = Partial<Record<Breakpoint, number>>;
|
||||
|
||||
export const responsiveArray: Breakpoint[] = ['xxl', 'xl', 'lg', 'md', 'sm', 'xs'];
|
||||
|
||||
export const responsiveMap: BreakpointMap = {
|
||||
xs: '(max-width: 575px)',
|
||||
sm: '(min-width: 576px)',
|
||||
md: '(min-width: 768px)',
|
||||
lg: '(min-width: 992px)',
|
||||
xl: '(min-width: 1200px)',
|
||||
xxl: '(min-width: 1600px)',
|
||||
};
|
||||
|
||||
type SubscribeFunc = (screens: ScreenMap) => void;
|
||||
const subscribers = new Map<Number, SubscribeFunc>();
|
||||
let subUid = -1;
|
||||
let screens = {};
|
||||
|
||||
const responsiveObserve = {
|
||||
matchHandlers: {} as {
|
||||
[prop: string]: {
|
||||
mql: MediaQueryList;
|
||||
listener: ((this: MediaQueryList, ev: MediaQueryListEvent) => any) | null;
|
||||
};
|
||||
},
|
||||
dispatch(pointMap: ScreenMap) {
|
||||
screens = pointMap;
|
||||
subscribers.forEach((func) => func(screens));
|
||||
return subscribers.size >= 1;
|
||||
},
|
||||
subscribe(func: SubscribeFunc): number {
|
||||
if (!subscribers.size) this.register();
|
||||
subUid += 1;
|
||||
subscribers.set(subUid, func);
|
||||
func(screens);
|
||||
return subUid;
|
||||
},
|
||||
unsubscribe(token: number) {
|
||||
subscribers.delete(token);
|
||||
if (!subscribers.size) this.unregister();
|
||||
},
|
||||
unregister() {
|
||||
Object.keys(responsiveMap).forEach((screen: Breakpoint) => {
|
||||
const matchMediaQuery = responsiveMap[screen];
|
||||
const handler = this.matchHandlers[matchMediaQuery];
|
||||
handler?.mql.removeListener(handler?.listener);
|
||||
});
|
||||
subscribers.clear();
|
||||
},
|
||||
register() {
|
||||
Object.keys(responsiveMap).forEach((screen: Breakpoint) => {
|
||||
const matchMediaQuery = responsiveMap[screen];
|
||||
const listener = ({ matches }: { matches: boolean }) => {
|
||||
this.dispatch({
|
||||
...screens,
|
||||
[screen]: matches,
|
||||
const getResponsiveMap = (token: GlobalToken): BreakpointMap => ({
|
||||
xs: `(max-width: ${token.screenXSMax}px)`,
|
||||
sm: `(min-width: ${token.screenSM}px)`,
|
||||
md: `(min-width: ${token.screenMD}px)`,
|
||||
lg: `(min-width: ${token.screenLG}px)`,
|
||||
xl: `(min-width: ${token.screenXL}px)`,
|
||||
xxl: `(min-width: ${token.screenXXL}px)`,
|
||||
});
|
||||
|
||||
export default function useResponsiveObserver() {
|
||||
const [, token] = useToken();
|
||||
const responsiveMap: BreakpointMap = getResponsiveMap(token);
|
||||
|
||||
// To avoid repeat create instance, we add `useMemo` here.
|
||||
return React.useMemo(() => {
|
||||
const subscribers = new Map<Number, SubscribeFunc>();
|
||||
let subUid = -1;
|
||||
let screens = {};
|
||||
|
||||
return {
|
||||
matchHandlers: {} as {
|
||||
[prop: string]: {
|
||||
mql: MediaQueryList;
|
||||
listener: ((this: MediaQueryList, ev: MediaQueryListEvent) => any) | null;
|
||||
};
|
||||
},
|
||||
dispatch(pointMap: ScreenMap) {
|
||||
screens = pointMap;
|
||||
subscribers.forEach((func) => func(screens));
|
||||
return subscribers.size >= 1;
|
||||
},
|
||||
subscribe(func: SubscribeFunc): number {
|
||||
if (!subscribers.size) this.register();
|
||||
subUid += 1;
|
||||
subscribers.set(subUid, func);
|
||||
func(screens);
|
||||
return subUid;
|
||||
},
|
||||
unsubscribe(paramToken: number) {
|
||||
subscribers.delete(paramToken);
|
||||
if (!subscribers.size) this.unregister();
|
||||
},
|
||||
unregister() {
|
||||
Object.keys(responsiveMap).forEach((screen: Breakpoint) => {
|
||||
const matchMediaQuery = responsiveMap[screen];
|
||||
const handler = this.matchHandlers[matchMediaQuery];
|
||||
handler?.mql.removeListener(handler?.listener);
|
||||
});
|
||||
};
|
||||
const mql = window.matchMedia(matchMediaQuery);
|
||||
mql.addListener(listener);
|
||||
this.matchHandlers[matchMediaQuery] = {
|
||||
mql,
|
||||
listener,
|
||||
};
|
||||
subscribers.clear();
|
||||
},
|
||||
register() {
|
||||
Object.keys(responsiveMap).forEach((screen: Breakpoint) => {
|
||||
const matchMediaQuery = responsiveMap[screen];
|
||||
const listener = ({ matches }: { matches: boolean }) => {
|
||||
this.dispatch({
|
||||
...screens,
|
||||
[screen]: matches,
|
||||
});
|
||||
};
|
||||
const mql = window.matchMedia(matchMediaQuery);
|
||||
mql.addListener(listener);
|
||||
this.matchHandlers[matchMediaQuery] = {
|
||||
mql,
|
||||
listener,
|
||||
};
|
||||
|
||||
listener(mql);
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
export default responsiveObserve;
|
||||
listener(mql);
|
||||
});
|
||||
},
|
||||
responsiveMap,
|
||||
};
|
||||
}, [token]);
|
||||
}
|
||||
|
@ -6,10 +6,18 @@ import type { ConfigConsumerProps } from '../config-provider';
|
||||
import { ConfigContext } from '../config-provider';
|
||||
import getScroll from '../_util/getScroll';
|
||||
import scrollTo from '../_util/scrollTo';
|
||||
import warning from '../_util/warning';
|
||||
import AnchorContext from './context';
|
||||
import type { AnchorLinkBaseProps } from './AnchorLink';
|
||||
import AnchorLink from './AnchorLink';
|
||||
|
||||
import useStyle from './style';
|
||||
|
||||
export interface AnchorLinkItemProps extends AnchorLinkBaseProps {
|
||||
key: React.Key;
|
||||
children?: AnchorLinkItemProps[];
|
||||
}
|
||||
|
||||
export type AnchorContainer = HTMLElement | Window;
|
||||
|
||||
function getDefaultContainer() {
|
||||
@ -45,6 +53,9 @@ export interface AnchorProps {
|
||||
prefixCls?: string;
|
||||
className?: string;
|
||||
style?: React.CSSProperties;
|
||||
/**
|
||||
* @deprecated Please use `items` instead.
|
||||
*/
|
||||
children?: React.ReactNode;
|
||||
offsetTop?: number;
|
||||
bounds?: number;
|
||||
@ -61,6 +72,7 @@ export interface AnchorProps {
|
||||
targetOffset?: number;
|
||||
/** Listening event when scrolling change active link */
|
||||
onChange?: (currentActiveLink: string) => void;
|
||||
items?: AnchorLinkItemProps[];
|
||||
}
|
||||
|
||||
interface InternalAnchorProps extends AnchorProps {
|
||||
@ -100,6 +112,7 @@ const AnchorContent: React.FC<InternalAnchorProps> = (props) => {
|
||||
affix = true,
|
||||
showInkInFixed = false,
|
||||
children,
|
||||
items,
|
||||
bounds,
|
||||
targetOffset,
|
||||
onClick,
|
||||
@ -108,6 +121,11 @@ const AnchorContent: React.FC<InternalAnchorProps> = (props) => {
|
||||
getCurrentAnchor,
|
||||
} = props;
|
||||
|
||||
// =================== Warning =====================
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
warning(!children, 'Anchor', '`Anchor children` is deprecated. Please use `items` instead.');
|
||||
}
|
||||
|
||||
const [links, setLinks] = React.useState<string[]>([]);
|
||||
const [activeLink, setActiveLink] = React.useState<string | null>(null);
|
||||
const activeLinkRef = React.useRef<string | null>(activeLink);
|
||||
@ -257,13 +275,22 @@ const AnchorContent: React.FC<InternalAnchorProps> = (props) => {
|
||||
...style,
|
||||
};
|
||||
|
||||
const createNestedLink = (options?: AnchorLinkItemProps[]) =>
|
||||
Array.isArray(options)
|
||||
? options.map((item) => (
|
||||
<AnchorLink {...item} key={item.key}>
|
||||
{createNestedLink(item.children)}
|
||||
</AnchorLink>
|
||||
))
|
||||
: null;
|
||||
|
||||
const anchorContent = (
|
||||
<div ref={wrapperRef} className={wrapperClass} style={wrapperStyle}>
|
||||
<div className={anchorClass}>
|
||||
<div className={`${prefixCls}-ink`}>
|
||||
<span className={inkClass} ref={spanLinkNode} />
|
||||
</div>
|
||||
{children}
|
||||
{'items' in props ? createNestedLink(items) : children}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
@ -5,15 +5,18 @@ import { ConfigConsumer } from '../config-provider';
|
||||
import type { AntAnchor } from './Anchor';
|
||||
import AnchorContext from './context';
|
||||
|
||||
export interface AnchorLinkProps {
|
||||
export interface AnchorLinkBaseProps {
|
||||
prefixCls?: string;
|
||||
href: string;
|
||||
target?: string;
|
||||
title: React.ReactNode;
|
||||
children?: React.ReactNode;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export interface AnchorLinkProps extends AnchorLinkBaseProps {
|
||||
children?: React.ReactNode;
|
||||
}
|
||||
|
||||
const AnchorLink: React.FC<AnchorLinkProps> = (props) => {
|
||||
const { href = '#', title, prefixCls: customizePrefixCls, children, className, target } = props;
|
||||
|
||||
|
@ -432,4 +432,64 @@ describe('Anchor Render', () => {
|
||||
}).not.toThrow();
|
||||
});
|
||||
});
|
||||
|
||||
it('renders items correctly', () => {
|
||||
const { container, asFragment } = render(
|
||||
<Anchor
|
||||
items={[
|
||||
{
|
||||
key: '1',
|
||||
href: '#components-anchor-demo-basic',
|
||||
title: 'Item Basic Demo',
|
||||
},
|
||||
{
|
||||
key: '2',
|
||||
href: '#components-anchor-demo-static',
|
||||
title: 'Static demo',
|
||||
},
|
||||
{
|
||||
key: '3',
|
||||
href: '#api',
|
||||
title: 'API',
|
||||
children: [
|
||||
{
|
||||
key: '4',
|
||||
href: '#anchor-props',
|
||||
title: 'Anchor Props',
|
||||
children: [
|
||||
{
|
||||
key: '5',
|
||||
href: '#link-props',
|
||||
title: 'Link Props',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
]}
|
||||
/>,
|
||||
);
|
||||
expect(container.querySelectorAll('.ant-anchor .ant-anchor-link').length).toBe(5);
|
||||
const linkTitles = Array.from(container.querySelector('.ant-anchor')?.childNodes!)
|
||||
.slice(1)
|
||||
.map((n) => (n as HTMLElement).querySelector('.ant-anchor-link-title'));
|
||||
expect((linkTitles[0] as HTMLAnchorElement).href).toContain('#components-anchor-demo-basic');
|
||||
expect((linkTitles[1] as HTMLAnchorElement).href).toContain('#components-anchor-demo-static');
|
||||
expect((linkTitles[2] as HTMLAnchorElement).href).toContain('#api');
|
||||
expect(asFragment().firstChild).toMatchSnapshot();
|
||||
expect(
|
||||
(
|
||||
container.querySelector(
|
||||
'.ant-anchor .ant-anchor-link .ant-anchor-link .ant-anchor-link-title',
|
||||
) as HTMLAnchorElement
|
||||
)?.href,
|
||||
).toContain('#anchor-props');
|
||||
expect(
|
||||
(
|
||||
container.querySelector(
|
||||
'.ant-anchor .ant-anchor-link .ant-anchor-link .ant-anchor-link .ant-anchor-link-title',
|
||||
) as HTMLAnchorElement
|
||||
)?.href,
|
||||
).toContain('#link-props');
|
||||
});
|
||||
});
|
||||
|
@ -0,0 +1,81 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Anchor Render renders items correctly 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class=""
|
||||
>
|
||||
<div
|
||||
class="ant-anchor-wrapper"
|
||||
style="max-height: 100vh;"
|
||||
>
|
||||
<div
|
||||
class="ant-anchor"
|
||||
>
|
||||
<div
|
||||
class="ant-anchor-ink"
|
||||
>
|
||||
<span
|
||||
class="ant-anchor-ink-ball"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="ant-anchor-link"
|
||||
>
|
||||
<a
|
||||
class="ant-anchor-link-title"
|
||||
href="#components-anchor-demo-basic"
|
||||
title="Item Basic Demo"
|
||||
>
|
||||
Item Basic Demo
|
||||
</a>
|
||||
</div>
|
||||
<div
|
||||
class="ant-anchor-link"
|
||||
>
|
||||
<a
|
||||
class="ant-anchor-link-title"
|
||||
href="#components-anchor-demo-static"
|
||||
title="Static demo"
|
||||
>
|
||||
Static demo
|
||||
</a>
|
||||
</div>
|
||||
<div
|
||||
class="ant-anchor-link"
|
||||
>
|
||||
<a
|
||||
class="ant-anchor-link-title"
|
||||
href="#api"
|
||||
title="API"
|
||||
>
|
||||
API
|
||||
</a>
|
||||
<div
|
||||
class="ant-anchor-link"
|
||||
>
|
||||
<a
|
||||
class="ant-anchor-link-title"
|
||||
href="#anchor-props"
|
||||
title="Anchor Props"
|
||||
>
|
||||
Anchor Props
|
||||
</a>
|
||||
<div
|
||||
class="ant-anchor-link"
|
||||
>
|
||||
<a
|
||||
class="ant-anchor-link-title"
|
||||
href="#link-props"
|
||||
title="Link Props"
|
||||
>
|
||||
Link Props
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
@ -156,6 +156,86 @@ exports[`renders ./components/anchor/demo/customizeHighlight.tsx extend context
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/anchor/demo/legacy-anchor.tsx extend context correctly 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class=""
|
||||
>
|
||||
<div
|
||||
class="ant-anchor-wrapper"
|
||||
style="max-height:100vh"
|
||||
>
|
||||
<div
|
||||
class="ant-anchor"
|
||||
>
|
||||
<div
|
||||
class="ant-anchor-ink"
|
||||
>
|
||||
<span
|
||||
class="ant-anchor-ink-ball"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="ant-anchor-link"
|
||||
>
|
||||
<a
|
||||
class="ant-anchor-link-title"
|
||||
href="#components-anchor-demo-basic"
|
||||
title="Basic demo"
|
||||
>
|
||||
Basic demo
|
||||
</a>
|
||||
</div>
|
||||
<div
|
||||
class="ant-anchor-link"
|
||||
>
|
||||
<a
|
||||
class="ant-anchor-link-title"
|
||||
href="#components-anchor-demo-static"
|
||||
title="Static demo"
|
||||
>
|
||||
Static demo
|
||||
</a>
|
||||
</div>
|
||||
<div
|
||||
class="ant-anchor-link"
|
||||
>
|
||||
<a
|
||||
class="ant-anchor-link-title"
|
||||
href="#api"
|
||||
title="API"
|
||||
>
|
||||
API
|
||||
</a>
|
||||
<div
|
||||
class="ant-anchor-link"
|
||||
>
|
||||
<a
|
||||
class="ant-anchor-link-title"
|
||||
href="#anchor-props"
|
||||
title="Anchor Props"
|
||||
>
|
||||
Anchor Props
|
||||
</a>
|
||||
</div>
|
||||
<div
|
||||
class="ant-anchor-link"
|
||||
>
|
||||
<a
|
||||
class="ant-anchor-link-title"
|
||||
href="#link-props"
|
||||
title="Link Props"
|
||||
>
|
||||
Link Props
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/anchor/demo/onChange.tsx extend context correctly 1`] = `
|
||||
<div
|
||||
class="ant-anchor-wrapper"
|
||||
|
@ -156,6 +156,86 @@ exports[`renders ./components/anchor/demo/customizeHighlight.tsx correctly 1`] =
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/anchor/demo/legacy-anchor.tsx correctly 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class=""
|
||||
>
|
||||
<div
|
||||
class="ant-anchor-wrapper"
|
||||
style="max-height:100vh"
|
||||
>
|
||||
<div
|
||||
class="ant-anchor"
|
||||
>
|
||||
<div
|
||||
class="ant-anchor-ink"
|
||||
>
|
||||
<span
|
||||
class="ant-anchor-ink-ball"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="ant-anchor-link"
|
||||
>
|
||||
<a
|
||||
class="ant-anchor-link-title"
|
||||
href="#components-anchor-demo-basic"
|
||||
title="Basic demo"
|
||||
>
|
||||
Basic demo
|
||||
</a>
|
||||
</div>
|
||||
<div
|
||||
class="ant-anchor-link"
|
||||
>
|
||||
<a
|
||||
class="ant-anchor-link-title"
|
||||
href="#components-anchor-demo-static"
|
||||
title="Static demo"
|
||||
>
|
||||
Static demo
|
||||
</a>
|
||||
</div>
|
||||
<div
|
||||
class="ant-anchor-link"
|
||||
>
|
||||
<a
|
||||
class="ant-anchor-link-title"
|
||||
href="#api"
|
||||
title="API"
|
||||
>
|
||||
API
|
||||
</a>
|
||||
<div
|
||||
class="ant-anchor-link"
|
||||
>
|
||||
<a
|
||||
class="ant-anchor-link-title"
|
||||
href="#anchor-props"
|
||||
title="Anchor Props"
|
||||
>
|
||||
Anchor Props
|
||||
</a>
|
||||
</div>
|
||||
<div
|
||||
class="ant-anchor-link"
|
||||
>
|
||||
<a
|
||||
class="ant-anchor-link-title"
|
||||
href="#link-props"
|
||||
title="Link Props"
|
||||
>
|
||||
Link Props
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/anchor/demo/onChange.tsx correctly 1`] = `
|
||||
<div
|
||||
class="ant-anchor-wrapper"
|
||||
|
@ -1,8 +1,6 @@
|
||||
import React from 'react';
|
||||
import { Anchor, Row, Col } from 'antd';
|
||||
|
||||
const { Link } = Anchor;
|
||||
|
||||
const App: React.FC = () => (
|
||||
<Row>
|
||||
<Col span={16}>
|
||||
@ -11,11 +9,25 @@ const App: React.FC = () => (
|
||||
<div id="part-3" style={{ height: '100vh', background: 'rgba(0,0,255,0.02)' }} />
|
||||
</Col>
|
||||
<Col span={8}>
|
||||
<Anchor>
|
||||
<Link href="#part-1" title="Part 1" />
|
||||
<Link href="#part-2" title="Part 2" />
|
||||
<Link href="#part-3" title="Part 3" />
|
||||
</Anchor>
|
||||
<Anchor
|
||||
items={[
|
||||
{
|
||||
key: 'part-1',
|
||||
href: '#part-1',
|
||||
title: 'Part 1',
|
||||
},
|
||||
{
|
||||
key: 'part-2',
|
||||
href: '#part-2',
|
||||
title: 'Part 2',
|
||||
},
|
||||
{
|
||||
key: 'part-3',
|
||||
href: '#part-3',
|
||||
title: 'Part 3',
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
);
|
||||
|
@ -1,19 +1,42 @@
|
||||
import React from 'react';
|
||||
import { Anchor } from 'antd';
|
||||
|
||||
const { Link } = Anchor;
|
||||
|
||||
const getCurrentAnchor = () => '#components-anchor-demo-static';
|
||||
|
||||
const App: React.FC = () => (
|
||||
<Anchor affix={false} getCurrentAnchor={getCurrentAnchor}>
|
||||
<Link href="#components-anchor-demo-basic" title="Basic demo" />
|
||||
<Link href="#components-anchor-demo-static" title="Static demo" />
|
||||
<Link href="#api" title="API">
|
||||
<Link href="#anchor-props" title="Anchor Props" />
|
||||
<Link href="#link-props" title="Link Props" />
|
||||
</Link>
|
||||
</Anchor>
|
||||
<Anchor
|
||||
affix={false}
|
||||
getCurrentAnchor={getCurrentAnchor}
|
||||
items={[
|
||||
{
|
||||
key: '1',
|
||||
href: '#components-anchor-demo-basic',
|
||||
title: 'Basic demo',
|
||||
},
|
||||
{
|
||||
key: '2',
|
||||
href: '#components-anchor-demo-static',
|
||||
title: 'Static demo',
|
||||
},
|
||||
{
|
||||
key: '3',
|
||||
href: '#api',
|
||||
title: 'API',
|
||||
children: [
|
||||
{
|
||||
key: '4',
|
||||
href: '#anchor-props',
|
||||
title: 'Anchor Props',
|
||||
},
|
||||
{
|
||||
key: '5',
|
||||
href: '#link-props',
|
||||
title: 'Link Props',
|
||||
},
|
||||
],
|
||||
},
|
||||
]}
|
||||
/>
|
||||
);
|
||||
|
||||
export default App;
|
||||
|
7
components/anchor/demo/legacy-anchor.md
Normal file
7
components/anchor/demo/legacy-anchor.md
Normal file
@ -0,0 +1,7 @@
|
||||
## zh-CN
|
||||
|
||||
Debug usage
|
||||
|
||||
## en-US
|
||||
|
||||
Debug usage
|
17
components/anchor/demo/legacy-anchor.tsx
Normal file
17
components/anchor/demo/legacy-anchor.tsx
Normal file
@ -0,0 +1,17 @@
|
||||
import React from 'react';
|
||||
import { Anchor } from 'antd';
|
||||
|
||||
const { Link } = Anchor;
|
||||
|
||||
const App: React.FC = () => (
|
||||
<Anchor>
|
||||
<Link href="#components-anchor-demo-basic" title="Basic demo" />
|
||||
<Link href="#components-anchor-demo-static" title="Static demo" />
|
||||
<Link href="#api" title="API">
|
||||
<Link href="#anchor-props" title="Anchor Props" />
|
||||
<Link href="#link-props" title="Link Props" />
|
||||
</Link>
|
||||
</Anchor>
|
||||
);
|
||||
|
||||
export default App;
|
@ -1,21 +1,44 @@
|
||||
import React from 'react';
|
||||
import { Anchor } from 'antd';
|
||||
|
||||
const { Link } = Anchor;
|
||||
|
||||
const onChange = (link: string) => {
|
||||
console.log('Anchor:OnChange', link);
|
||||
};
|
||||
|
||||
const App: React.FC = () => (
|
||||
<Anchor affix={false} onChange={onChange}>
|
||||
<Link href="#components-anchor-demo-basic" title="Basic demo" />
|
||||
<Link href="#components-anchor-demo-static" title="Static demo" />
|
||||
<Link href="#api" title="API">
|
||||
<Link href="#anchor-props" title="Anchor Props" />
|
||||
<Link href="#link-props" title="Link Props" />
|
||||
</Link>
|
||||
</Anchor>
|
||||
<Anchor
|
||||
affix={false}
|
||||
onChange={onChange}
|
||||
items={[
|
||||
{
|
||||
key: '1',
|
||||
href: '#components-anchor-demo-basic',
|
||||
title: 'Basic demo',
|
||||
},
|
||||
{
|
||||
key: '2',
|
||||
href: '#components-anchor-demo-static',
|
||||
title: 'Static demo',
|
||||
},
|
||||
{
|
||||
key: '3',
|
||||
href: '#api',
|
||||
title: 'API',
|
||||
children: [
|
||||
{
|
||||
key: '4',
|
||||
href: '#anchor-props',
|
||||
title: 'Anchor Props',
|
||||
},
|
||||
{
|
||||
key: '5',
|
||||
href: '#link-props',
|
||||
title: 'Link Props',
|
||||
},
|
||||
],
|
||||
},
|
||||
]}
|
||||
/>
|
||||
);
|
||||
|
||||
export default App;
|
||||
|
@ -1,8 +1,6 @@
|
||||
import React from 'react';
|
||||
import { Anchor } from 'antd';
|
||||
|
||||
const { Link } = Anchor;
|
||||
|
||||
const handleClick = (
|
||||
e: React.MouseEvent<HTMLElement>,
|
||||
link: {
|
||||
@ -15,14 +13,39 @@ const handleClick = (
|
||||
};
|
||||
|
||||
const App: React.FC = () => (
|
||||
<Anchor affix={false} onClick={handleClick}>
|
||||
<Link href="#components-anchor-demo-basic" title="Basic demo" />
|
||||
<Link href="#components-anchor-demo-static" title="Static demo" />
|
||||
<Link href="#api" title="API">
|
||||
<Link href="#anchor-props" title="Anchor Props" />
|
||||
<Link href="#link-props" title="Link Props" />
|
||||
</Link>
|
||||
</Anchor>
|
||||
<Anchor
|
||||
affix={false}
|
||||
onClick={handleClick}
|
||||
items={[
|
||||
{
|
||||
key: '1',
|
||||
href: '#components-anchor-demo-basic',
|
||||
title: 'Basic demo',
|
||||
},
|
||||
{
|
||||
key: '2',
|
||||
href: '#components-anchor-demo-static',
|
||||
title: 'Static demo',
|
||||
},
|
||||
{
|
||||
key: '3',
|
||||
href: '#api',
|
||||
title: 'API',
|
||||
children: [
|
||||
{
|
||||
key: '4',
|
||||
href: '#anchor-props',
|
||||
title: 'Anchor Props',
|
||||
},
|
||||
{
|
||||
key: '5',
|
||||
href: '#link-props',
|
||||
title: 'Link Props',
|
||||
},
|
||||
],
|
||||
},
|
||||
]}
|
||||
/>
|
||||
);
|
||||
|
||||
export default App;
|
||||
|
@ -1,17 +1,39 @@
|
||||
import React from 'react';
|
||||
import { Anchor } from 'antd';
|
||||
|
||||
const { Link } = Anchor;
|
||||
|
||||
const App: React.FC = () => (
|
||||
<Anchor affix={false}>
|
||||
<Link href="#components-anchor-demo-basic" title="Basic demo" />
|
||||
<Link href="#components-anchor-demo-static" title="Static demo" />
|
||||
<Link href="#api" title="API">
|
||||
<Link href="#anchor-props" title="Anchor Props" />
|
||||
<Link href="#link-props" title="Link Props" />
|
||||
</Link>
|
||||
</Anchor>
|
||||
<Anchor
|
||||
affix={false}
|
||||
items={[
|
||||
{
|
||||
key: '1',
|
||||
href: '#components-anchor-demo-basic',
|
||||
title: 'Basic demo',
|
||||
},
|
||||
{
|
||||
key: '2',
|
||||
href: '#components-anchor-demo-static',
|
||||
title: 'Static demo',
|
||||
},
|
||||
{
|
||||
key: '3',
|
||||
href: '#api',
|
||||
title: 'API',
|
||||
children: [
|
||||
{
|
||||
key: '4',
|
||||
href: '#anchor-props',
|
||||
title: 'Anchor Props',
|
||||
},
|
||||
{
|
||||
key: '5',
|
||||
href: '#link-props',
|
||||
title: 'Link Props',
|
||||
},
|
||||
],
|
||||
},
|
||||
]}
|
||||
/>
|
||||
);
|
||||
|
||||
export default App;
|
||||
|
@ -1,8 +1,6 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { Anchor, Row, Col } from 'antd';
|
||||
|
||||
const { Link } = Anchor;
|
||||
|
||||
const App: React.FC = () => {
|
||||
const topRef = React.useRef<HTMLDivElement>(null);
|
||||
const [targetOffset, setTargetOffset] = useState<number | undefined>(undefined);
|
||||
@ -29,11 +27,26 @@ const App: React.FC = () => {
|
||||
</div>
|
||||
</Col>
|
||||
<Col span={6}>
|
||||
<Anchor targetOffset={targetOffset}>
|
||||
<Link href="#part-1" title="Part 1" />
|
||||
<Link href="#part-2" title="Part 2" />
|
||||
<Link href="#part-3" title="Part 3" />
|
||||
</Anchor>
|
||||
<Anchor
|
||||
targetOffset={targetOffset}
|
||||
items={[
|
||||
{
|
||||
key: 'part-1',
|
||||
href: '#part-1',
|
||||
title: 'Part 1',
|
||||
},
|
||||
{
|
||||
key: 'part-2',
|
||||
href: '#part-2',
|
||||
title: 'Part 2',
|
||||
},
|
||||
{
|
||||
key: 'part-3',
|
||||
href: '#part-3',
|
||||
title: 'Part 3',
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
|
@ -28,6 +28,7 @@ For displaying anchor hyperlinks on page and jumping between them.
|
||||
<code src="./demo/customizeHighlight.tsx">Customize the anchor highlight</code>
|
||||
<code src="./demo/targetOffset.tsx" iframe="200">Set Anchor scroll offset</code>
|
||||
<code src="./demo/onChange.tsx">Listening for anchor link change</code>
|
||||
<code src="./demo/legacy-anchor.tsx" debug>Deprecated JSX demo</code>
|
||||
|
||||
## API
|
||||
|
||||
@ -44,6 +45,7 @@ For displaying anchor hyperlinks on page and jumping between them.
|
||||
| targetOffset | Anchor scroll offset, default as `offsetTop`, [example](#components-anchor-demo-targetOffset) | number | - | |
|
||||
| onChange | Listening for anchor link change | (currentActiveLink: string) => void | | |
|
||||
| onClick | Set the handler to handle `click` event | (e: MouseEvent, link: object) => void | - | |
|
||||
| items | Data configuration option content, support nesting through children | { href, title, target, children }\[] | - | |
|
||||
|
||||
### Link Props
|
||||
|
||||
|
@ -29,6 +29,7 @@ group:
|
||||
<code src="./demo/customizeHighlight.tsx">自定义锚点高亮</code>
|
||||
<code src="./demo/targetOffset.tsx" iframe="200">设置锚点滚动偏移量</code>
|
||||
<code src="./demo/onChange.tsx">监听锚点链接改变</code>
|
||||
<code src="./demo/legacy-anchor.tsx" debug>废弃的 JSX 示例</code>
|
||||
|
||||
## API
|
||||
|
||||
@ -45,6 +46,7 @@ group:
|
||||
| targetOffset | 锚点滚动偏移量,默认与 offsetTop 相同,[例子](#components-anchor-demo-targetOffset) | number | - | |
|
||||
| onChange | 监听锚点链接改变 | (currentActiveLink: string) => void | - | |
|
||||
| onClick | `click` 事件的 handler | (e: MouseEvent, link: object) => void | - | |
|
||||
| items | 数据化配置选项内容,支持通过 children 嵌套 | { href, title, target, children }\[] | - | |
|
||||
|
||||
### Link Props
|
||||
|
||||
|
@ -0,0 +1,50 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`renders ./components/app/demo/basic.tsx extend context correctly 1`] = `
|
||||
<div
|
||||
class="ant-app"
|
||||
>
|
||||
<div
|
||||
class="ant-space ant-space-horizontal ant-space-align-center"
|
||||
>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-right:8px"
|
||||
>
|
||||
<button
|
||||
class="ant-btn ant-btn-primary"
|
||||
type="button"
|
||||
>
|
||||
<span>
|
||||
Open message
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-right:8px"
|
||||
>
|
||||
<button
|
||||
class="ant-btn ant-btn-primary"
|
||||
type="button"
|
||||
>
|
||||
<span>
|
||||
Open modal
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
>
|
||||
<button
|
||||
class="ant-btn ant-btn-primary"
|
||||
type="button"
|
||||
>
|
||||
<span>
|
||||
Open notification
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
50
components/app/__tests__/__snapshots__/demo.test.ts.snap
Normal file
50
components/app/__tests__/__snapshots__/demo.test.ts.snap
Normal file
@ -0,0 +1,50 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`renders ./components/app/demo/basic.tsx correctly 1`] = `
|
||||
<div
|
||||
class="ant-app"
|
||||
>
|
||||
<div
|
||||
class="ant-space ant-space-horizontal ant-space-align-center"
|
||||
>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-right:8px"
|
||||
>
|
||||
<button
|
||||
class="ant-btn ant-btn-primary"
|
||||
type="button"
|
||||
>
|
||||
<span>
|
||||
Open message
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-right:8px"
|
||||
>
|
||||
<button
|
||||
class="ant-btn ant-btn-primary"
|
||||
type="button"
|
||||
>
|
||||
<span>
|
||||
Open modal
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
>
|
||||
<button
|
||||
class="ant-btn ant-btn-primary"
|
||||
type="button"
|
||||
>
|
||||
<span>
|
||||
Open notification
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
17
components/app/__tests__/__snapshots__/index.test.tsx.snap
Normal file
17
components/app/__tests__/__snapshots__/index.test.tsx.snap
Normal file
@ -0,0 +1,17 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`App rtl render component should be rendered correctly in RTL direction 1`] = `
|
||||
<div
|
||||
class="ant-app"
|
||||
/>
|
||||
`;
|
||||
|
||||
exports[`App single 1`] = `
|
||||
<div
|
||||
class="ant-app"
|
||||
>
|
||||
<div>
|
||||
Hello World
|
||||
</div>
|
||||
</div>
|
||||
`;
|
3
components/app/__tests__/demo-extend.test.ts
Normal file
3
components/app/__tests__/demo-extend.test.ts
Normal file
@ -0,0 +1,3 @@
|
||||
import { extendTest } from '../../../tests/shared/demoTest';
|
||||
|
||||
extendTest('app');
|
3
components/app/__tests__/demo.test.ts
Normal file
3
components/app/__tests__/demo.test.ts
Normal file
@ -0,0 +1,3 @@
|
||||
import demoTest from '../../../tests/shared/demoTest';
|
||||
|
||||
demoTest('app');
|
5
components/app/__tests__/image.test.ts
Normal file
5
components/app/__tests__/image.test.ts
Normal file
@ -0,0 +1,5 @@
|
||||
import { imageDemoTest } from '../../../tests/shared/imageTest';
|
||||
|
||||
describe('app', () => {
|
||||
imageDemoTest('app');
|
||||
});
|
33
components/app/__tests__/index.test.tsx
Normal file
33
components/app/__tests__/index.test.tsx
Normal file
@ -0,0 +1,33 @@
|
||||
import React from 'react';
|
||||
import App from '..';
|
||||
import mountTest from '../../../tests/shared/mountTest';
|
||||
import rtlTest from '../../../tests/shared/rtlTest';
|
||||
import { render } from '../../../tests/utils';
|
||||
|
||||
describe('App', () => {
|
||||
mountTest(App);
|
||||
rtlTest(App);
|
||||
|
||||
it('single', () => {
|
||||
// Sub page
|
||||
const MyPage = () => {
|
||||
const { message } = App.useApp();
|
||||
React.useEffect(() => {
|
||||
message.success('Good!');
|
||||
}, [message]);
|
||||
|
||||
return <div>Hello World</div>;
|
||||
};
|
||||
|
||||
// Entry component
|
||||
const MyApp = () => (
|
||||
<App>
|
||||
<MyPage />
|
||||
</App>
|
||||
);
|
||||
|
||||
const { getByText, container } = render(<MyApp />);
|
||||
expect(getByText('Hello World')).toBeTruthy();
|
||||
expect(container.firstChild).toMatchSnapshot();
|
||||
});
|
||||
});
|
19
components/app/context.ts
Normal file
19
components/app/context.ts
Normal file
@ -0,0 +1,19 @@
|
||||
import React from 'react';
|
||||
import type { MessageInstance } from '../message/interface';
|
||||
import type { NotificationInstance } from '../notification/interface';
|
||||
import type { ModalStaticFunctions } from '../modal/confirm';
|
||||
|
||||
type ModalType = Omit<ModalStaticFunctions, 'warn'>;
|
||||
export interface useAppProps {
|
||||
message: MessageInstance;
|
||||
notification: NotificationInstance;
|
||||
modal: ModalType;
|
||||
}
|
||||
|
||||
const AppContext = React.createContext<useAppProps>({
|
||||
message: {},
|
||||
notification: {},
|
||||
modal: {},
|
||||
} as useAppProps);
|
||||
|
||||
export default AppContext;
|
7
components/app/demo/basic.md
Normal file
7
components/app/demo/basic.md
Normal file
@ -0,0 +1,7 @@
|
||||
## zh-CN
|
||||
|
||||
获取 `message`, `notification`, `modal` 静态方法。
|
||||
|
||||
## en-US
|
||||
|
||||
Static method for `message`, `notification`, `modal`.
|
47
components/app/demo/basic.tsx
Normal file
47
components/app/demo/basic.tsx
Normal file
@ -0,0 +1,47 @@
|
||||
import React from 'react';
|
||||
import { App, Button, Space } from 'antd';
|
||||
|
||||
// Sub page
|
||||
const MyPage = () => {
|
||||
const { message, modal, notification } = App.useApp();
|
||||
|
||||
const showMessage = () => {
|
||||
message.success('Success!');
|
||||
};
|
||||
|
||||
const showModal = () => {
|
||||
modal.warning({
|
||||
title: 'This is a warning message',
|
||||
content: 'some messages...some messages...',
|
||||
});
|
||||
};
|
||||
|
||||
const showNotification = () => {
|
||||
notification.info({
|
||||
message: `Notification topLeft`,
|
||||
description: 'Hello, Ant Design!!',
|
||||
placement: 'topLeft',
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<Space>
|
||||
<Button type="primary" onClick={showMessage}>
|
||||
Open message
|
||||
</Button>
|
||||
<Button type="primary" onClick={showModal}>
|
||||
Open modal
|
||||
</Button>
|
||||
<Button type="primary" onClick={showNotification}>
|
||||
Open notification
|
||||
</Button>
|
||||
</Space>
|
||||
);
|
||||
};
|
||||
|
||||
// Entry component
|
||||
export default () => (
|
||||
<App>
|
||||
<MyPage />
|
||||
</App>
|
||||
);
|
119
components/app/index.en-US.md
Normal file
119
components/app/index.en-US.md
Normal file
@ -0,0 +1,119 @@
|
||||
---
|
||||
category: Components
|
||||
group: Other
|
||||
title: App
|
||||
cover: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*HJz8SZos2wgAAAAAAAAAAAAADrJ8AQ/original
|
||||
demo:
|
||||
cols: 2
|
||||
---
|
||||
|
||||
New App Component which provide global style & static function replacement.
|
||||
|
||||
## When To Use
|
||||
|
||||
Static function in React 18 concurrent mode will not well support. In v5, we recommend to use hooks for the static replacement. But it will make user manual work on define this.
|
||||
|
||||
## Examples
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
<code src="./demo/basic.tsx">basic</code>
|
||||
|
||||
## How to use
|
||||
|
||||
### Basic usage
|
||||
|
||||
App provides upstream and downstream method calls through `Context`, because useApp needs to be used as a subcomponent, we recommend encapsulating App at the top level in the application.
|
||||
|
||||
```tsx
|
||||
import React from 'react';
|
||||
import { App } from 'antd';
|
||||
|
||||
const MyPage: React.FC = () => {
|
||||
const { message, notification, modal } = App.useApp();
|
||||
message.success('Good!');
|
||||
notification.info({ message: 'Good' });
|
||||
modal.warning({ title: 'Good' });
|
||||
// ....
|
||||
// other message, notification, modal static function
|
||||
return <div>Hello word</div>;
|
||||
};
|
||||
|
||||
const MyApp: React.FC = () => (
|
||||
<App>
|
||||
<MyPage />
|
||||
</App>
|
||||
);
|
||||
|
||||
export default MyApp;
|
||||
```
|
||||
|
||||
Note: App.useApp must be available under App.
|
||||
|
||||
### Sequence with ConfigProvider
|
||||
|
||||
The App component can only use the token in the `ConfigProvider`, if you need to use the Token, the ConfigProvider and the App component must appear in pairs.
|
||||
|
||||
```tsx
|
||||
<ConfigProvider theme={{ ... }}>
|
||||
<App>
|
||||
...
|
||||
</App>
|
||||
</ConfigProvider>
|
||||
```
|
||||
|
||||
### Embedded usage scenarios (if not necessary, try not to do nesting)
|
||||
|
||||
```tsx
|
||||
<App>
|
||||
<Space>
|
||||
...
|
||||
<App>...</App>
|
||||
</Space>
|
||||
</App>
|
||||
```
|
||||
|
||||
### Global scene (redux scene)
|
||||
|
||||
```tsx
|
||||
// Entry component
|
||||
import React, { useEffect } from 'react';
|
||||
import { App } from 'antd';
|
||||
import type { MessageInstance } from 'antd/es/message/interface';
|
||||
import type { NotificationInstance } from 'antd/es/notification/interface';
|
||||
import type { ModalStaticFunctions } from 'antd/es/modal/confirm';
|
||||
|
||||
let message: MessageInstance;
|
||||
let notification: NotificationInstance;
|
||||
let modal: Omit<ModalStaticFunctions, 'warn'>;
|
||||
|
||||
export default () => {
|
||||
const staticFunction = App.useApp();
|
||||
message = staticFunction.message;
|
||||
modal = staticFunction.modal;
|
||||
notification = staticFunction.notification;
|
||||
return null;
|
||||
};
|
||||
|
||||
export { message, notification, modal };
|
||||
```
|
||||
|
||||
```tsx
|
||||
// sub page
|
||||
import React from 'react';
|
||||
import { Button, Space } from 'antd';
|
||||
import { message, modal, notification } from './store';
|
||||
|
||||
export default () => {
|
||||
const showMessage = () => {
|
||||
message.success('Success!');
|
||||
};
|
||||
|
||||
return (
|
||||
<Space>
|
||||
<Button type="primary" onClick={showMessage}>
|
||||
Open message
|
||||
</Button>
|
||||
</Space>
|
||||
);
|
||||
};
|
||||
```
|
59
components/app/index.tsx
Normal file
59
components/app/index.tsx
Normal file
@ -0,0 +1,59 @@
|
||||
import React, { useContext } from 'react';
|
||||
import type { ReactNode } from 'react';
|
||||
import classNames from 'classnames';
|
||||
import type { ConfigConsumerProps } from '../config-provider';
|
||||
import { ConfigContext } from '../config-provider';
|
||||
import useStyle from './style';
|
||||
import useMessage from '../message/useMessage';
|
||||
import useNotification from '../notification/useNotification';
|
||||
import useModal from '../modal/useModal';
|
||||
import AppContext from './context';
|
||||
import type { useAppProps } from './context';
|
||||
|
||||
export type AppProps = {
|
||||
className?: string;
|
||||
prefixCls?: string;
|
||||
children?: ReactNode;
|
||||
};
|
||||
|
||||
const useApp = () => React.useContext<useAppProps>(AppContext);
|
||||
|
||||
const App: React.FC<AppProps> & { useApp: () => useAppProps } = (props) => {
|
||||
const { prefixCls: customizePrefixCls, children, className } = props;
|
||||
const { getPrefixCls } = useContext<ConfigConsumerProps>(ConfigContext);
|
||||
const prefixCls = getPrefixCls('app', customizePrefixCls);
|
||||
const [wrapSSR, hashId] = useStyle(prefixCls);
|
||||
const customClassName = classNames(hashId, prefixCls, className);
|
||||
|
||||
const [messageApi, messageContextHolder] = useMessage();
|
||||
const [notificationApi, notificationContextHolder] = useNotification();
|
||||
const [ModalApi, ModalContextHolder] = useModal();
|
||||
|
||||
const memoizedContextValue = React.useMemo<useAppProps>(
|
||||
() => ({
|
||||
message: messageApi,
|
||||
notification: notificationApi,
|
||||
modal: ModalApi,
|
||||
}),
|
||||
[messageApi, notificationApi, ModalApi],
|
||||
);
|
||||
|
||||
return wrapSSR(
|
||||
<AppContext.Provider value={memoizedContextValue}>
|
||||
<div className={customClassName}>
|
||||
{ModalContextHolder}
|
||||
{messageContextHolder}
|
||||
{notificationContextHolder}
|
||||
{children}
|
||||
</div>
|
||||
</AppContext.Provider>,
|
||||
);
|
||||
};
|
||||
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
App.displayName = 'App';
|
||||
}
|
||||
|
||||
App.useApp = useApp;
|
||||
|
||||
export default App;
|
121
components/app/index.zh-CN.md
Normal file
121
components/app/index.zh-CN.md
Normal file
@ -0,0 +1,121 @@
|
||||
---
|
||||
category: Components
|
||||
subtitle: 包裹组件
|
||||
group: 其他
|
||||
title: App
|
||||
cover: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*HJz8SZos2wgAAAAAAAAAAAAADrJ8AQ/original
|
||||
demo:
|
||||
cols: 2
|
||||
---
|
||||
|
||||
新的包裹组件,提供重置样式和提供消费上下文的默认环境。
|
||||
|
||||
## 何时使用
|
||||
|
||||
- 提供可消费 React context 的 `message.xxx`、`Modal.xxx`、`notification.xxx` 的静态方法,可以简化 useMessage 等方法需要手动植入 `contextHolder` 的问题。
|
||||
- 提供基于 `.ant-app` 的默认重置样式,解决原生元素没有 antd 规范样式的问题。
|
||||
|
||||
## 代码演示
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
<code src="./demo/basic.tsx">basic</code>
|
||||
|
||||
## 如何使用
|
||||
|
||||
### 基础用法
|
||||
|
||||
App 组件通过 `Context` 提供上下文方法调用,因而 useApp 需要作为子组件才能使用,我们推荐在应用中顶层包裹 App。
|
||||
|
||||
```tsx
|
||||
import React from 'react';
|
||||
import { App } from 'antd';
|
||||
|
||||
const MyPage: React.FC = () => {
|
||||
const { message, notification, modal } = App.useApp();
|
||||
message.success('Good!');
|
||||
notification.info({ message: 'Good' });
|
||||
modal.warning({ title: 'Good' });
|
||||
// ....
|
||||
// other message, notification, modal static function
|
||||
return <div>Hello word</div>;
|
||||
};
|
||||
|
||||
const MyApp: React.FC = () => (
|
||||
<App>
|
||||
<MyPage />
|
||||
</App>
|
||||
);
|
||||
|
||||
export default MyApp;
|
||||
```
|
||||
|
||||
注意:App.useApp 必须在 App 之下方可使用。
|
||||
|
||||
### 与 ConfigProvider 先后顺序
|
||||
|
||||
App 组件只能在 `ConfigProvider` 之下才能使用 Design Token, 如果需要使用其样式重置能力,则 ConfigProvider 与 App 组件必须成对出现。
|
||||
|
||||
```tsx
|
||||
<ConfigProvider theme={{ ... }}>
|
||||
<App>
|
||||
...
|
||||
</App>
|
||||
</ConfigProvider>
|
||||
```
|
||||
|
||||
### 内嵌使用场景(如无必要,尽量不做嵌套)
|
||||
|
||||
```tsx
|
||||
<App>
|
||||
<Space>
|
||||
...
|
||||
<App>...</App>
|
||||
</Space>
|
||||
</App>
|
||||
```
|
||||
|
||||
### 全局场景(redux 场景)
|
||||
|
||||
```tsx
|
||||
// Entry component
|
||||
import React, { useEffect } from 'react';
|
||||
import { App } from 'antd';
|
||||
import type { MessageInstance } from 'antd/es/message/interface';
|
||||
import type { NotificationInstance } from 'antd/es/notification/interface';
|
||||
import type { ModalStaticFunctions } from 'antd/es/modal/confirm';
|
||||
|
||||
let message: MessageInstance;
|
||||
let notification: NotificationInstance;
|
||||
let modal: Omit<ModalStaticFunctions, 'warn'>;
|
||||
|
||||
export default () => {
|
||||
const staticFunction = App.useApp();
|
||||
message = staticFunction.message;
|
||||
modal = staticFunction.modal;
|
||||
notification = staticFunction.notification;
|
||||
return null;
|
||||
};
|
||||
|
||||
export { message, notification, modal };
|
||||
```
|
||||
|
||||
```tsx
|
||||
// sub page
|
||||
import React from 'react';
|
||||
import { Button, Space } from 'antd';
|
||||
import { message, modal, notification } from './store';
|
||||
|
||||
export default () => {
|
||||
const showMessage = () => {
|
||||
message.success('Success!');
|
||||
};
|
||||
|
||||
return (
|
||||
<Space>
|
||||
<Button type="primary" onClick={showMessage}>
|
||||
Open message
|
||||
</Button>
|
||||
</Space>
|
||||
);
|
||||
};
|
||||
```
|
22
components/app/style/index.tsx
Normal file
22
components/app/style/index.tsx
Normal file
@ -0,0 +1,22 @@
|
||||
import type { FullToken, GenerateStyle } from '../../theme/internal';
|
||||
import { genComponentStyleHook } from '../../theme/internal';
|
||||
|
||||
export type ComponentToken = {};
|
||||
|
||||
interface AppToken extends FullToken<'App'> {}
|
||||
|
||||
// =============================== Base ===============================
|
||||
const genBaseStyle: GenerateStyle<AppToken> = (token) => {
|
||||
const { componentCls, colorText, fontSize, lineHeight, fontFamily } = token;
|
||||
return {
|
||||
[componentCls]: {
|
||||
color: colorText,
|
||||
fontSize,
|
||||
lineHeight,
|
||||
fontFamily,
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
// ============================== Export ==============================
|
||||
export default genComponentStyleHook('App', (token) => [genBaseStyle(token)]);
|
@ -10,7 +10,7 @@ import type {
|
||||
import useMergedState from 'rc-util/lib/hooks/useMergedState';
|
||||
import * as React from 'react';
|
||||
import { ConfigContext } from '../config-provider';
|
||||
import LocaleReceiver from '../locale-provider/LocaleReceiver';
|
||||
import LocaleReceiver from '../locale/LocaleReceiver';
|
||||
import CalendarHeader from './Header';
|
||||
import enUS from './locale/en_US';
|
||||
|
||||
|
3
components/calendar/locale/eu_ES.tsx
Normal file
3
components/calendar/locale/eu_ES.tsx
Normal file
@ -0,0 +1,3 @@
|
||||
import euES from '../../date-picker/locale/eu_ES';
|
||||
|
||||
export default euES;
|
@ -7,6 +7,7 @@ import { act, fireEvent, render } from '../../../tests/utils';
|
||||
import Button from '../../button';
|
||||
import Input from '../../input';
|
||||
import Table from '../../table';
|
||||
import Select from '../../select';
|
||||
|
||||
describe('ConfigProvider', () => {
|
||||
mountTest(() => (
|
||||
@ -113,6 +114,15 @@ describe('ConfigProvider', () => {
|
||||
expect(container.querySelector('input')?.autocomplete).toEqual('off');
|
||||
});
|
||||
|
||||
it('select showSearch', () => {
|
||||
const { container } = render(
|
||||
<ConfigProvider select={{ showSearch: true }}>
|
||||
<Select />
|
||||
</ConfigProvider>,
|
||||
);
|
||||
expect(container.querySelectorAll('.ant-select-show-search').length).toBe(1);
|
||||
});
|
||||
|
||||
it('render empty', () => {
|
||||
let rendered = false;
|
||||
let cacheRenderEmpty;
|
||||
|
@ -2,8 +2,8 @@ import React from 'react';
|
||||
import { closePicker, openPicker, selectCell } from '../../date-picker/__tests__/utils';
|
||||
import ConfigProvider from '..';
|
||||
import DatePicker from '../../date-picker';
|
||||
import type { Locale } from '../../locale-provider';
|
||||
import LocaleProvider from '../../locale-provider';
|
||||
import type { Locale } from '../../locale';
|
||||
import LocaleProvider from '../../locale';
|
||||
import enUS from '../../locale/en_US';
|
||||
import zhCN from '../../locale/zh_CN';
|
||||
import Modal from '../../modal';
|
||||
|
@ -1,7 +1,7 @@
|
||||
import * as React from 'react';
|
||||
import type { DerivativeFunc } from '@ant-design/cssinjs';
|
||||
import type { RequiredMark } from '../form/Form';
|
||||
import type { Locale } from '../locale-provider';
|
||||
import type { Locale } from '../locale';
|
||||
import type { AliasToken, MapToken, OverrideToken, SeedToken } from '../theme/interface';
|
||||
import type { RenderEmptyHandler } from './defaultRenderEmpty';
|
||||
import type { SizeType } from './SizeContext';
|
||||
@ -63,6 +63,9 @@ export interface ConfigConsumerProps {
|
||||
colon?: boolean;
|
||||
};
|
||||
theme?: ThemeConfig;
|
||||
select?: {
|
||||
showSearch?: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
const defaultGetPrefixCls = (suffixCls?: string, customizePrefixCls?: string) => {
|
||||
|
@ -57,6 +57,7 @@ Some components use dynamic style to support wave effect. You can config `csp` p
|
||||
| getTargetContainer | Config Affix, Anchor scroll target container | () => HTMLElement | () => window | 4.2.0 |
|
||||
| iconPrefixCls | Set icon prefix className | string | `anticon` | 4.11.0 |
|
||||
| input | Set Input common props | { autoComplete?: string } | - | 4.2.0 |
|
||||
| select | Set Select common props | { showSearch?: boolean } | - | |
|
||||
| locale | Language package setting, you can find the packages in [antd/locale](http://unpkg.com/antd/locale/) | object | - | |
|
||||
| prefixCls | Set prefix className | string | `ant` | |
|
||||
| renderEmpty | Set empty content of components. Ref [Empty](/components/empty/) | function(componentName: string): ReactNode | - | |
|
||||
|
@ -6,9 +6,9 @@ import useMemo from 'rc-util/lib/hooks/useMemo';
|
||||
import * as React from 'react';
|
||||
import type { ReactElement } from 'react';
|
||||
import type { RequiredMark } from '../form/Form';
|
||||
import type { Locale } from '../locale-provider';
|
||||
import LocaleProvider, { ANT_MARK } from '../locale-provider';
|
||||
import LocaleReceiver from '../locale-provider/LocaleReceiver';
|
||||
import type { Locale } from '../locale';
|
||||
import LocaleProvider, { ANT_MARK } from '../locale';
|
||||
import LocaleReceiver from '../locale/LocaleReceiver';
|
||||
import defaultLocale from '../locale/en_US';
|
||||
import { DesignTokenContext } from '../theme/internal';
|
||||
import defaultSeedToken from '../theme/themes/seed';
|
||||
@ -53,6 +53,7 @@ const PASSED_PROPS: Exclude<keyof ConfigConsumerProps, 'rootPrefixCls' | 'getPre
|
||||
'input',
|
||||
'pagination',
|
||||
'form',
|
||||
'select',
|
||||
];
|
||||
|
||||
export interface ConfigProviderProps {
|
||||
@ -72,6 +73,9 @@ export interface ConfigProviderProps {
|
||||
input?: {
|
||||
autoComplete?: string;
|
||||
};
|
||||
select?: {
|
||||
showSearch?: boolean;
|
||||
};
|
||||
pagination?: {
|
||||
showSizeChanger?: boolean;
|
||||
};
|
||||
|
@ -58,6 +58,7 @@ export default () => (
|
||||
| getTargetContainer | 配置 Affix、Anchor 滚动监听容器。 | () => HTMLElement | () => window | 4.2.0 |
|
||||
| iconPrefixCls | 设置图标统一样式前缀 | string | `anticon` | 4.11.0 |
|
||||
| input | 设置 Input 组件的通用属性 | { autoComplete?: string } | - | 4.2.0 |
|
||||
| select | 设置 Select 组件的通用属性 | { showSearch?: boolean } | - | |
|
||||
| locale | 语言包配置,语言包可到 [antd/locale](http://unpkg.com/antd/locale/) 目录下寻找 | object | - | |
|
||||
| prefixCls | 设置统一样式前缀 | string | `ant` | |
|
||||
| renderEmpty | 自定义组件空状态。参考 [空状态](/components/empty-cn) | function(componentName: string): ReactNode | - | |
|
||||
|
@ -4,9 +4,9 @@ import customParseFormat from 'dayjs/plugin/customParseFormat';
|
||||
import React from 'react';
|
||||
import DatePicker from '..';
|
||||
import ConfigProvider from '../../config-provider';
|
||||
import type { Locale } from '../../locale-provider';
|
||||
import LocaleProvider from '../../locale-provider';
|
||||
import locale from '../../locale-provider/zh_CN';
|
||||
import type { Locale } from '../../locale';
|
||||
import LocaleProvider from '../../locale';
|
||||
import locale from '../../locale/zh_CN';
|
||||
import jaJP from '../../locale/ja_JP';
|
||||
import zhTW from '../locale/zh_TW';
|
||||
import { render } from '../../../tests/utils';
|
||||
|
@ -14,7 +14,7 @@ import DisabledContext from '../../config-provider/DisabledContext';
|
||||
import SizeContext from '../../config-provider/SizeContext';
|
||||
import { FormItemInputContext } from '../../form/context';
|
||||
import { useCompactItemContext } from '../../space/Compact';
|
||||
import LocaleReceiver from '../../locale-provider/LocaleReceiver';
|
||||
import LocaleReceiver from '../../locale/LocaleReceiver';
|
||||
import { getMergedStatus, getStatusClassNames } from '../../_util/statusUtils';
|
||||
import enUS from '../locale/en_US';
|
||||
import { getRangePlaceholder, transPlacement2DropdownAlign } from '../util';
|
||||
|
@ -14,7 +14,7 @@ import { ConfigContext } from '../../config-provider';
|
||||
import DisabledContext from '../../config-provider/DisabledContext';
|
||||
import SizeContext from '../../config-provider/SizeContext';
|
||||
import { FormItemInputContext } from '../../form/context';
|
||||
import LocaleReceiver from '../../locale-provider/LocaleReceiver';
|
||||
import LocaleReceiver from '../../locale/LocaleReceiver';
|
||||
import type { InputStatus } from '../../_util/statusUtils';
|
||||
import { getMergedStatus, getStatusClassNames } from '../../_util/statusUtils';
|
||||
import warning from '../../_util/warning';
|
||||
|
20
components/date-picker/locale/eu_ES.tsx
Normal file
20
components/date-picker/locale/eu_ES.tsx
Normal file
@ -0,0 +1,20 @@
|
||||
import CalendarLocale from 'rc-picker/lib/locale/eu_ES';
|
||||
import TimePickerLocale from '../../time-picker/locale/eu_ES';
|
||||
import type { PickerLocale } from '../generatePicker';
|
||||
|
||||
// Merge into a locale object
|
||||
const locale: PickerLocale = {
|
||||
lang: {
|
||||
placeholder: 'Hautatu data',
|
||||
rangePlaceholder: ['Hasierako data', 'Amaiera data'],
|
||||
...CalendarLocale,
|
||||
},
|
||||
timePickerLocale: {
|
||||
...TimePickerLocale,
|
||||
},
|
||||
};
|
||||
|
||||
// All settings at:
|
||||
// https://github.com/ant-design/ant-design/blob/master/components/date-picker/locale/example.json
|
||||
|
||||
export default locale;
|
@ -6,7 +6,14 @@ import type { PickerLocale } from '../generatePicker';
|
||||
const locale: PickerLocale = {
|
||||
lang: {
|
||||
placeholder: 'Sélectionner une date',
|
||||
yearPlaceholder: 'Sélectionner une année',
|
||||
quarterPlaceholder: 'Sélectionner un trimestre',
|
||||
monthPlaceholder: 'Sélectionner un mois',
|
||||
weekPlaceholder: 'Sélectionner une semaine',
|
||||
rangePlaceholder: ['Date de début', 'Date de fin'],
|
||||
rangeYearPlaceholder: ['Année de début', 'Année de fin'],
|
||||
rangeMonthPlaceholder: ['Mois de début', 'Mois de fin'],
|
||||
rangeWeekPlaceholder: ['Semaine de début', 'Semaine de fin'],
|
||||
...CalendarLocale,
|
||||
},
|
||||
timePickerLocale: {
|
||||
|
@ -5,7 +5,7 @@ import * as React from 'react';
|
||||
import { ConfigContext } from '../config-provider';
|
||||
import { cloneElement } from '../_util/reactNode';
|
||||
import type { Breakpoint, ScreenMap } from '../_util/responsiveObserve';
|
||||
import ResponsiveObserve, { responsiveArray } from '../_util/responsiveObserve';
|
||||
import useResponsiveObserve, { responsiveArray } from '../_util/responsiveObserve';
|
||||
import warning from '../_util/warning';
|
||||
import DescriptionsItem from './Item';
|
||||
import Row from './Row';
|
||||
@ -135,10 +135,11 @@ function Descriptions({
|
||||
const mergedColumn = getColumn(column, screens);
|
||||
|
||||
const [wrapSSR, hashId] = useStyle(prefixCls);
|
||||
const responsiveObserve = useResponsiveObserve();
|
||||
|
||||
// Responsive
|
||||
React.useEffect(() => {
|
||||
const token = ResponsiveObserve.subscribe((newScreens) => {
|
||||
const token = responsiveObserve.subscribe((newScreens) => {
|
||||
if (typeof column !== 'object') {
|
||||
return;
|
||||
}
|
||||
@ -146,7 +147,7 @@ function Descriptions({
|
||||
});
|
||||
|
||||
return () => {
|
||||
ResponsiveObserve.unsubscribe(token);
|
||||
responsiveObserve.unsubscribe(token);
|
||||
};
|
||||
}, []);
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
import classNames from 'classnames';
|
||||
import * as React from 'react';
|
||||
import { ConfigContext } from '../config-provider';
|
||||
import LocaleReceiver from '../locale-provider/LocaleReceiver';
|
||||
import LocaleReceiver from '../locale/LocaleReceiver';
|
||||
import DefaultEmptyImg from './empty';
|
||||
import SimpleEmptyImg from './simple';
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React, { useRef, memo, useContext } from 'react';
|
||||
import React, { useRef, memo, useContext, useEffect, useCallback, useMemo } from 'react';
|
||||
import CloseOutlined from '@ant-design/icons/CloseOutlined';
|
||||
import FileTextOutlined from '@ant-design/icons/FileTextOutlined';
|
||||
import classNames from 'classnames';
|
||||
@ -41,23 +41,11 @@ const FloatButtonGroup: React.FC<FloatButtonGroupProps> = (props) => {
|
||||
|
||||
const [open, setOpen] = useMergedState(false, { value: props.open });
|
||||
|
||||
const clickAction = useRef<React.HTMLAttributes<HTMLAnchorElement | HTMLButtonElement>>({});
|
||||
const floatButtonGroupRef = useRef<HTMLDivElement>(null);
|
||||
const floatButtonRef = useRef<HTMLButtonElement | HTMLAnchorElement>(null);
|
||||
|
||||
const hoverAction = useRef<React.HTMLAttributes<HTMLDivElement>>({});
|
||||
|
||||
if (trigger === 'click') {
|
||||
clickAction.current = {
|
||||
onClick() {
|
||||
setOpen((prevState) => {
|
||||
onOpenChange?.(!prevState);
|
||||
return !prevState;
|
||||
});
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
if (trigger === 'hover') {
|
||||
hoverAction.current = {
|
||||
const hoverAction = useMemo(() => {
|
||||
const hoverTypeAction = {
|
||||
onMouseEnter() {
|
||||
setOpen(true);
|
||||
onOpenChange?.(true);
|
||||
@ -67,11 +55,42 @@ const FloatButtonGroup: React.FC<FloatButtonGroupProps> = (props) => {
|
||||
onOpenChange?.(false);
|
||||
},
|
||||
};
|
||||
}
|
||||
return trigger === 'hover' ? hoverTypeAction : {};
|
||||
}, [trigger]);
|
||||
|
||||
const handleOpenChange = () => {
|
||||
setOpen((prevState) => {
|
||||
onOpenChange?.(!prevState);
|
||||
return !prevState;
|
||||
});
|
||||
};
|
||||
|
||||
const onClick = useCallback(
|
||||
(e: MouseEvent) => {
|
||||
if (floatButtonGroupRef.current!.contains(e.target as Node)) {
|
||||
if (floatButtonRef.current!.contains(e.target as Node)) {
|
||||
handleOpenChange();
|
||||
}
|
||||
return;
|
||||
}
|
||||
setOpen(false);
|
||||
onOpenChange?.(false);
|
||||
},
|
||||
[trigger],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (trigger === 'click') {
|
||||
document.addEventListener('click', onClick);
|
||||
return () => {
|
||||
document.removeEventListener('click', onClick);
|
||||
};
|
||||
}
|
||||
}, [trigger]);
|
||||
|
||||
return wrapSSR(
|
||||
<FloatButtonGroupProvider value={shape}>
|
||||
<div className={groupCls} style={style} {...hoverAction.current}>
|
||||
<div ref={floatButtonGroupRef} className={groupCls} style={style} {...hoverAction}>
|
||||
{trigger && ['click', 'hover'].includes(trigger) ? (
|
||||
<>
|
||||
<CSSMotion visible={open} motionName={`${groupPrefixCls}-wrap`}>
|
||||
@ -80,11 +99,11 @@ const FloatButtonGroup: React.FC<FloatButtonGroupProps> = (props) => {
|
||||
)}
|
||||
</CSSMotion>
|
||||
<FloatButton
|
||||
ref={floatButtonRef}
|
||||
type={type}
|
||||
shape={shape}
|
||||
icon={open ? closeIcon : icon}
|
||||
description={description}
|
||||
{...clickAction.current}
|
||||
/>
|
||||
</>
|
||||
) : (
|
||||
|
@ -58,4 +58,30 @@ describe('FloatButtonGroup', () => {
|
||||
fireEvent.mouseLeave(container.querySelector('.ant-float-btn-group')!);
|
||||
expect(onOpenChange).toHaveBeenCalled();
|
||||
});
|
||||
it('support click floatButtonGroup not close', () => {
|
||||
const onOpenChange = jest.fn();
|
||||
const { container } = render(
|
||||
<FloatButton.Group trigger="click" onOpenChange={onOpenChange}>
|
||||
<FloatButton />
|
||||
<FloatButton />
|
||||
<FloatButton />
|
||||
</FloatButton.Group>,
|
||||
);
|
||||
fireEvent.click(container.querySelector('.ant-float-btn')!);
|
||||
fireEvent.click(container.querySelector('.ant-float-btn-group')!);
|
||||
expect(onOpenChange).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
it('support click out auto close', () => {
|
||||
const onOpenChange = jest.fn();
|
||||
const { container } = render(
|
||||
<FloatButton.Group trigger="click" onOpenChange={onOpenChange}>
|
||||
<FloatButton />
|
||||
<FloatButton />
|
||||
<FloatButton />
|
||||
</FloatButton.Group>,
|
||||
);
|
||||
fireEvent.click(container.querySelector('.ant-float-btn')!);
|
||||
fireEvent.click(container);
|
||||
expect(onOpenChange).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
});
|
||||
|
@ -3,7 +3,7 @@ import classNames from 'classnames';
|
||||
import * as React from 'react';
|
||||
import type { ColProps } from '../grid/col';
|
||||
import Col from '../grid/col';
|
||||
import { useLocaleReceiver } from '../locale-provider/LocaleReceiver';
|
||||
import { useLocaleReceiver } from '../locale/LocaleReceiver';
|
||||
import defaultLocale from '../locale/en_US';
|
||||
import type { TooltipProps } from '../tooltip';
|
||||
import Tooltip from '../tooltip';
|
||||
|
@ -2,9 +2,36 @@ import React from 'react';
|
||||
import { Col, Row } from '..';
|
||||
import mountTest from '../../../tests/shared/mountTest';
|
||||
import rtlTest from '../../../tests/shared/rtlTest';
|
||||
import ResponsiveObserve from '../../_util/responsiveObserve';
|
||||
import useBreakpoint from '../hooks/useBreakpoint';
|
||||
import { render, act } from '../../../tests/utils';
|
||||
import { render } from '../../../tests/utils';
|
||||
|
||||
// Mock for `responsiveObserve` to test `unsubscribe` call
|
||||
jest.mock('../../_util/responsiveObserve', () => {
|
||||
const modules = jest.requireActual('../../_util/responsiveObserve');
|
||||
const originHook = modules.default;
|
||||
|
||||
const useMockResponsiveObserver = (...args: any[]) => {
|
||||
const entity = originHook(...args);
|
||||
if (!entity.unsubscribe.mocked) {
|
||||
const originUnsubscribe = entity.unsubscribe;
|
||||
entity.unsubscribe = (...uArgs: any[]) => {
|
||||
const inst = global as any;
|
||||
inst.unsubscribeCnt = (inst.unsubscribeCnt || 0) + 1;
|
||||
|
||||
originUnsubscribe.call(entity, ...uArgs);
|
||||
};
|
||||
entity.unsubscribe.mocked = true;
|
||||
}
|
||||
|
||||
return entity;
|
||||
};
|
||||
|
||||
return {
|
||||
...modules,
|
||||
__esModule: true,
|
||||
default: useMockResponsiveObserver,
|
||||
};
|
||||
});
|
||||
|
||||
describe('Grid', () => {
|
||||
mountTest(Row);
|
||||
@ -13,8 +40,8 @@ describe('Grid', () => {
|
||||
rtlTest(Row);
|
||||
rtlTest(Col);
|
||||
|
||||
afterEach(() => {
|
||||
ResponsiveObserve.unregister();
|
||||
beforeEach(() => {
|
||||
(global as any).unsubscribeCnt = 0;
|
||||
});
|
||||
|
||||
it('should render Col', () => {
|
||||
@ -88,13 +115,12 @@ describe('Grid', () => {
|
||||
expect(asFragment().firstChild).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('ResponsiveObserve.unsubscribe should be called when unmounted', () => {
|
||||
const Unmount = jest.spyOn(ResponsiveObserve, 'unsubscribe');
|
||||
it('useResponsiveObserve.unsubscribe should be called when unmounted', () => {
|
||||
const { unmount } = render(<Row gutter={{ xs: 20 }} />);
|
||||
act(() => {
|
||||
unmount();
|
||||
});
|
||||
expect(Unmount).toHaveBeenCalled();
|
||||
const called: number = (global as any).unsubscribeCnt;
|
||||
|
||||
unmount();
|
||||
expect((global as any).unsubscribeCnt).toEqual(called + 1);
|
||||
});
|
||||
|
||||
it('should work correct when gutter is object', () => {
|
||||
|
@ -1,6 +1,6 @@
|
||||
## zh-CN
|
||||
|
||||
参照 Bootstrap 的 [响应式设计](http://getbootstrap.com/css/#grid-media-queries),预设六个响应尺寸:`xs` `sm` `md` `lg` `xl` `xxl`。
|
||||
参照 Bootstrap 的 [响应式设计](http://getbootstrap.com/css/#grid-media-queries),预设六个响应尺寸:`xs` `sm` `md` `lg` `xl` `xxl`。
|
||||
|
||||
## en-US
|
||||
|
||||
|
@ -1,21 +1,22 @@
|
||||
import { useEffect, useRef } from 'react';
|
||||
import useForceUpdate from '../../_util/hooks/useForceUpdate';
|
||||
import type { ScreenMap } from '../../_util/responsiveObserve';
|
||||
import ResponsiveObserve from '../../_util/responsiveObserve';
|
||||
import useResponsiveObserve from '../../_util/responsiveObserve';
|
||||
|
||||
function useBreakpoint(refreshOnChange: boolean = true): ScreenMap {
|
||||
const screensRef = useRef<ScreenMap>({});
|
||||
const forceUpdate = useForceUpdate();
|
||||
const responsiveObserve = useResponsiveObserve();
|
||||
|
||||
useEffect(() => {
|
||||
const token = ResponsiveObserve.subscribe((supportScreens) => {
|
||||
const token = responsiveObserve.subscribe((supportScreens) => {
|
||||
screensRef.current = supportScreens;
|
||||
if (refreshOnChange) {
|
||||
forceUpdate();
|
||||
}
|
||||
});
|
||||
|
||||
return () => ResponsiveObserve.unsubscribe(token);
|
||||
return () => responsiveObserve.unsubscribe(token);
|
||||
}, []);
|
||||
|
||||
return screensRef.current;
|
||||
|
@ -3,7 +3,7 @@ import * as React from 'react';
|
||||
import { ConfigContext } from '../config-provider';
|
||||
import useFlexGapSupport from '../_util/hooks/useFlexGapSupport';
|
||||
import type { Breakpoint, ScreenMap } from '../_util/responsiveObserve';
|
||||
import ResponsiveObserve, { responsiveArray } from '../_util/responsiveObserve';
|
||||
import useResponsiveObserve, { responsiveArray } from '../_util/responsiveObserve';
|
||||
import RowContext from './RowContext';
|
||||
import { useRowStyle } from './style';
|
||||
|
||||
@ -103,9 +103,11 @@ const Row = React.forwardRef<HTMLDivElement, RowProps>((props, ref) => {
|
||||
|
||||
const gutterRef = React.useRef<Gutter | [Gutter, Gutter]>(gutter);
|
||||
|
||||
const responsiveObserve = useResponsiveObserve();
|
||||
|
||||
// ================================== Effect ==================================
|
||||
React.useEffect(() => {
|
||||
const token = ResponsiveObserve.subscribe((screen) => {
|
||||
const token = responsiveObserve.subscribe((screen) => {
|
||||
setCurScreens(screen);
|
||||
const currentGutter = gutterRef.current || 0;
|
||||
if (
|
||||
@ -116,7 +118,7 @@ const Row = React.forwardRef<HTMLDivElement, RowProps>((props, ref) => {
|
||||
setScreens(screen);
|
||||
}
|
||||
});
|
||||
return () => ResponsiveObserve.unsubscribe(token);
|
||||
return () => responsiveObserve.unsubscribe(token);
|
||||
}, []);
|
||||
|
||||
// ================================== Render ==================================
|
||||
|
@ -135,6 +135,7 @@ export { default as Tooltip } from './tooltip';
|
||||
export type { TooltipProps } from './tooltip';
|
||||
export { default as Tour } from './tour';
|
||||
export type { TourProps, TourStepProps } from './tour/interface';
|
||||
export { default as App } from './app';
|
||||
export { default as Transfer } from './transfer';
|
||||
export type { TransferProps } from './transfer';
|
||||
export { default as Tree } from './tree';
|
||||
@ -149,4 +150,8 @@ export { default as Typography } from './typography';
|
||||
export type { TypographyProps } from './typography';
|
||||
export { default as Upload } from './upload';
|
||||
export type { UploadFile, UploadProps } from './upload';
|
||||
export { default as Watermark } from './watermark';
|
||||
export type { WatermarkProps } from './watermark';
|
||||
export { default as QRCode } from './qrcode';
|
||||
export type { QRCodeProps, QRPropsCanvas } from './qrcode/interface';
|
||||
export { default as version } from './version';
|
||||
|
@ -1,64 +1,6 @@
|
||||
import * as React from 'react';
|
||||
import type { Locale } from '.';
|
||||
import type { LocaleContextProps } from './context';
|
||||
import LocaleContext from './context';
|
||||
import defaultLocaleData from '../locale/en_US';
|
||||
// locale-provider 文件夹的移除需要修改 @ant-design/tools 和 antd-img-crop
|
||||
import LocaleReceiver from '../locale/LocaleReceiver';
|
||||
|
||||
export type LocaleComponentName = Exclude<keyof Locale, 'locale'>;
|
||||
|
||||
export interface LocaleReceiverProps<C extends LocaleComponentName = LocaleComponentName> {
|
||||
componentName?: C;
|
||||
defaultLocale?: Locale[C] | (() => Locale[C]);
|
||||
children: (
|
||||
locale: NonNullable<Locale[C]>,
|
||||
localeCode: string,
|
||||
fullLocale: Locale,
|
||||
) => React.ReactElement;
|
||||
}
|
||||
|
||||
const LocaleReceiver = <C extends LocaleComponentName = LocaleComponentName>(
|
||||
props: LocaleReceiverProps<C>,
|
||||
) => {
|
||||
const { componentName = 'global' as C, defaultLocale, children } = props;
|
||||
const antLocale = React.useContext<LocaleContextProps | undefined>(LocaleContext);
|
||||
|
||||
const getLocale = React.useMemo<NonNullable<Locale[C]>>(() => {
|
||||
const locale = defaultLocale || defaultLocaleData[componentName];
|
||||
const localeFromContext = antLocale?.[componentName] ?? {};
|
||||
return {
|
||||
...(locale instanceof Function ? locale() : locale),
|
||||
...(localeFromContext || {}),
|
||||
};
|
||||
}, [componentName, defaultLocale, antLocale]);
|
||||
|
||||
const getLocaleCode = React.useMemo<string>(() => {
|
||||
const localeCode = antLocale && antLocale.locale;
|
||||
// Had use LocaleProvide but didn't set locale
|
||||
if (antLocale && antLocale.exist && !localeCode) {
|
||||
return defaultLocaleData.locale;
|
||||
}
|
||||
return localeCode!;
|
||||
}, [antLocale]);
|
||||
|
||||
return children(getLocale, getLocaleCode, antLocale!);
|
||||
};
|
||||
export * from '../locale/LocaleReceiver';
|
||||
|
||||
export default LocaleReceiver;
|
||||
|
||||
export const useLocaleReceiver = <C extends LocaleComponentName = LocaleComponentName>(
|
||||
componentName: C,
|
||||
defaultLocale?: Locale[C] | (() => Locale[C]),
|
||||
): [Locale[C]] => {
|
||||
const antLocale = React.useContext<LocaleContextProps | undefined>(LocaleContext);
|
||||
|
||||
const getLocale = React.useMemo<NonNullable<Locale[C]>>(() => {
|
||||
const locale = defaultLocale || defaultLocaleData[componentName];
|
||||
const localeFromContext = antLocale?.[componentName] ?? {};
|
||||
return {
|
||||
...(typeof locale === 'function' ? locale() : locale),
|
||||
...(localeFromContext || {}),
|
||||
};
|
||||
}, [componentName, defaultLocale, antLocale]);
|
||||
|
||||
return [getLocale];
|
||||
};
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,7 +1,7 @@
|
||||
import React, { memo, useContext } from 'react';
|
||||
import { fireEvent, pureRender } from '../../../tests/utils';
|
||||
import LocaleProvider from '..';
|
||||
import LocaleContext from '../context';
|
||||
import LocaleProvider from '../../locale';
|
||||
import LocaleContext from '../../locale/context';
|
||||
|
||||
let innerCount = 0;
|
||||
let outerCount = 0;
|
||||
|
@ -2,7 +2,7 @@ import React, { useEffect } from 'react';
|
||||
import { Modal } from '../..';
|
||||
import { waitFakeTimer, render, fireEvent } from '../../../tests/utils';
|
||||
import ConfigProvider from '../../config-provider';
|
||||
import zhCN from '../zh_CN';
|
||||
import zhCN from '../../locale/zh_CN';
|
||||
|
||||
const Demo: React.FC<{ type: string }> = ({ type }) => {
|
||||
useEffect(() => {
|
||||
|
@ -68,8 +68,8 @@ import preParsePostFormat from 'dayjs/plugin/preParsePostFormat';
|
||||
import MockDate from 'mockdate';
|
||||
import React from 'react';
|
||||
import { render } from '../../../tests/utils';
|
||||
import type { Locale } from '..';
|
||||
import LocaleProvider from '..';
|
||||
import type { Locale } from '../../locale';
|
||||
import LocaleProvider from '../../locale';
|
||||
import {
|
||||
Calendar,
|
||||
DatePicker,
|
||||
@ -82,73 +82,74 @@ import {
|
||||
Transfer,
|
||||
} from '../..';
|
||||
import mountTest from '../../../tests/shared/mountTest';
|
||||
import arEG from '../ar_EG';
|
||||
import azAZ from '../az_AZ';
|
||||
import bgBG from '../bg_BG';
|
||||
import bnBD from '../bn_BD';
|
||||
import byBY from '../by_BY';
|
||||
import caES from '../ca_ES';
|
||||
import csCZ from '../cs_CZ';
|
||||
import daDK from '../da_DK';
|
||||
import deDE from '../de_DE';
|
||||
import elGR from '../el_GR';
|
||||
import enGB from '../en_GB';
|
||||
import enUS from '../en_US';
|
||||
import esES from '../es_ES';
|
||||
import etEE from '../et_EE';
|
||||
import faIR from '../fa_IR';
|
||||
import fiFI from '../fi_FI';
|
||||
import frBE from '../fr_BE';
|
||||
import frCA from '../fr_CA';
|
||||
import frFR from '../fr_FR';
|
||||
import gaIE from '../ga_IE';
|
||||
import glES from '../gl_ES';
|
||||
import heIL from '../he_IL';
|
||||
import hiIN from '../hi_IN';
|
||||
import hrHR from '../hr_HR';
|
||||
import huHU from '../hu_HU';
|
||||
import hyAM from '../hy_AM';
|
||||
import idID from '../id_ID';
|
||||
import isIS from '../is_IS';
|
||||
import itIT from '../it_IT';
|
||||
import jaJP from '../ja_JP';
|
||||
import kaGE from '../ka_GE';
|
||||
import kkKZ from '../kk_KZ';
|
||||
import kmrIQ from '../kmr_IQ';
|
||||
import kmKH from '../km_KH';
|
||||
import knIN from '../kn_IN';
|
||||
import koKR from '../ko_KR';
|
||||
import kuIQ from '../ku_IQ';
|
||||
import ltLT from '../lt_LT';
|
||||
import lvLV from '../lv_LV';
|
||||
import mkMK from '../mk_MK';
|
||||
import mlIN from '../ml_IN';
|
||||
import mnMN from '../mn_MN';
|
||||
import msMY from '../ms_MY';
|
||||
import nbNO from '../nb_NO';
|
||||
import neNP from '../ne_NP';
|
||||
import nlBE from '../nl_BE';
|
||||
import nlNL from '../nl_NL';
|
||||
import plPL from '../pl_PL';
|
||||
import ptBR from '../pt_BR';
|
||||
import ptPT from '../pt_PT';
|
||||
import roRO from '../ro_RO';
|
||||
import ruRU from '../ru_RU';
|
||||
import siLK from '../si_LK';
|
||||
import skSK from '../sk_SK';
|
||||
import slSI from '../sl_SI';
|
||||
import srRS from '../sr_RS';
|
||||
import svSE from '../sv_SE';
|
||||
import taIN from '../ta_IN';
|
||||
import thTH from '../th_TH';
|
||||
import tkTK from '../tk_TK';
|
||||
import trTR from '../tr_TR';
|
||||
import ukUA from '../uk_UA';
|
||||
import urPK from '../ur_PK';
|
||||
import viVN from '../vi_VN';
|
||||
import zhCN from '../zh_CN';
|
||||
import zhHK from '../zh_HK';
|
||||
import zhTW from '../zh_TW';
|
||||
import arEG from '../../locale/ar_EG';
|
||||
import azAZ from '../../locale/az_AZ';
|
||||
import bgBG from '../../locale/bg_BG';
|
||||
import bnBD from '../../locale/bn_BD';
|
||||
import byBY from '../../locale/by_BY';
|
||||
import caES from '../../locale/ca_ES';
|
||||
import csCZ from '../../locale/cs_CZ';
|
||||
import daDK from '../../locale/da_DK';
|
||||
import deDE from '../../locale/de_DE';
|
||||
import elGR from '../../locale/el_GR';
|
||||
import enGB from '../../locale/en_GB';
|
||||
import enUS from '../../locale/en_US';
|
||||
import esES from '../../locale/es_ES';
|
||||
import etEE from '../../locale/et_EE';
|
||||
import euES from '../../locale/eu_ES';
|
||||
import faIR from '../../locale/fa_IR';
|
||||
import fiFI from '../../locale/fi_FI';
|
||||
import frBE from '../../locale/fr_BE';
|
||||
import frCA from '../../locale/fr_CA';
|
||||
import frFR from '../../locale/fr_FR';
|
||||
import gaIE from '../../locale/ga_IE';
|
||||
import glES from '../../locale/gl_ES';
|
||||
import heIL from '../../locale/he_IL';
|
||||
import hiIN from '../../locale/hi_IN';
|
||||
import hrHR from '../../locale/hr_HR';
|
||||
import huHU from '../../locale/hu_HU';
|
||||
import hyAM from '../../locale/hy_AM';
|
||||
import idID from '../../locale/id_ID';
|
||||
import isIS from '../../locale/is_IS';
|
||||
import itIT from '../../locale/it_IT';
|
||||
import jaJP from '../../locale/ja_JP';
|
||||
import kaGE from '../../locale/ka_GE';
|
||||
import kkKZ from '../../locale/kk_KZ';
|
||||
import kmrIQ from '../../locale/kmr_IQ';
|
||||
import kmKH from '../../locale/km_KH';
|
||||
import knIN from '../../locale/kn_IN';
|
||||
import koKR from '../../locale/ko_KR';
|
||||
import kuIQ from '../../locale/ku_IQ';
|
||||
import ltLT from '../../locale/lt_LT';
|
||||
import lvLV from '../../locale/lv_LV';
|
||||
import mkMK from '../../locale/mk_MK';
|
||||
import mlIN from '../../locale/ml_IN';
|
||||
import mnMN from '../../locale/mn_MN';
|
||||
import msMY from '../../locale/ms_MY';
|
||||
import nbNO from '../../locale/nb_NO';
|
||||
import neNP from '../../locale/ne_NP';
|
||||
import nlBE from '../../locale/nl_BE';
|
||||
import nlNL from '../../locale/nl_NL';
|
||||
import plPL from '../../locale/pl_PL';
|
||||
import ptBR from '../../locale/pt_BR';
|
||||
import ptPT from '../../locale/pt_PT';
|
||||
import roRO from '../../locale/ro_RO';
|
||||
import ruRU from '../../locale/ru_RU';
|
||||
import siLK from '../../locale/si_LK';
|
||||
import skSK from '../../locale/sk_SK';
|
||||
import slSI from '../../locale/sl_SI';
|
||||
import srRS from '../../locale/sr_RS';
|
||||
import svSE from '../../locale/sv_SE';
|
||||
import taIN from '../../locale/ta_IN';
|
||||
import thTH from '../../locale/th_TH';
|
||||
import tkTK from '../../locale/tk_TK';
|
||||
import trTR from '../../locale/tr_TR';
|
||||
import ukUA from '../../locale/uk_UA';
|
||||
import urPK from '../../locale/ur_PK';
|
||||
import viVN from '../../locale/vi_VN';
|
||||
import zhCN from '../../locale/zh_CN';
|
||||
import zhHK from '../../locale/zh_HK';
|
||||
import zhTW from '../../locale/zh_TW';
|
||||
|
||||
dayjs.extend(preParsePostFormat);
|
||||
|
||||
@ -167,6 +168,7 @@ const locales = [
|
||||
enUS,
|
||||
esES,
|
||||
etEE,
|
||||
euES,
|
||||
faIR,
|
||||
fiFI,
|
||||
frBE,
|
||||
|
@ -1,3 +0,0 @@
|
||||
import locale from '../locale/ar_EG';
|
||||
|
||||
export default locale;
|
@ -1,3 +0,0 @@
|
||||
import locale from '../locale/az_AZ';
|
||||
|
||||
export default locale;
|
@ -1,3 +0,0 @@
|
||||
import locale from '../locale/bg_BG';
|
||||
|
||||
export default locale;
|
@ -1,3 +0,0 @@
|
||||
import locale from '../locale/bn_BD';
|
||||
|
||||
export default locale;
|
@ -1,3 +0,0 @@
|
||||
import locale from '../locale/by_BY';
|
||||
|
||||
export default locale;
|
@ -1,3 +0,0 @@
|
||||
import locale from '../locale/ca_ES';
|
||||
|
||||
export default locale;
|
@ -1,3 +0,0 @@
|
||||
import locale from '../locale/cs_CZ';
|
||||
|
||||
export default locale;
|
@ -1,3 +0,0 @@
|
||||
import locale from '../locale/da_DK';
|
||||
|
||||
export default locale;
|
@ -1,3 +0,0 @@
|
||||
import locale from '../locale/de_DE';
|
||||
|
||||
export default locale;
|
@ -1,3 +0,0 @@
|
||||
import locale from '../locale/el_GR';
|
||||
|
||||
export default locale;
|
@ -1,3 +0,0 @@
|
||||
import locale from '../locale/en_GB';
|
||||
|
||||
export default locale;
|
@ -1,3 +0,0 @@
|
||||
import locale from '../locale/en_US';
|
||||
|
||||
export default locale;
|
@ -1,3 +0,0 @@
|
||||
import locale from '../locale/es_ES';
|
||||
|
||||
export default locale;
|
@ -1,3 +0,0 @@
|
||||
import locale from '../locale/et_EE';
|
||||
|
||||
export default locale;
|
@ -1,3 +0,0 @@
|
||||
import locale from '../locale/fa_IR';
|
||||
|
||||
export default locale;
|
@ -1,3 +0,0 @@
|
||||
import locale from '../locale/fi_FI';
|
||||
|
||||
export default locale;
|
@ -1,3 +0,0 @@
|
||||
import locale from '../locale/fr_BE';
|
||||
|
||||
export default locale;
|
@ -1,3 +0,0 @@
|
||||
import locale from '../locale/fr_CA';
|
||||
|
||||
export default locale;
|
@ -1,3 +0,0 @@
|
||||
import locale from '../locale/fr_FR';
|
||||
|
||||
export default locale;
|
@ -1,3 +0,0 @@
|
||||
import locale from '../locale/ga_IE';
|
||||
|
||||
export default locale;
|
@ -1,3 +0,0 @@
|
||||
import locale from '../locale/gl_ES';
|
||||
|
||||
export default locale;
|
@ -1,3 +0,0 @@
|
||||
import locale from '../locale/he_IL';
|
||||
|
||||
export default locale;
|
@ -1,3 +0,0 @@
|
||||
import locale from '../locale/hi_IN';
|
||||
|
||||
export default locale;
|
@ -1,3 +0,0 @@
|
||||
import locale from '../locale/hr_HR';
|
||||
|
||||
export default locale;
|
@ -1,3 +0,0 @@
|
||||
import locale from '../locale/hu_HU';
|
||||
|
||||
export default locale;
|
@ -1,3 +0,0 @@
|
||||
import locale from '../locale/hy_AM';
|
||||
|
||||
export default locale;
|
@ -1,3 +0,0 @@
|
||||
import locale from '../locale/id_ID';
|
||||
|
||||
export default locale;
|
6
components/locale-provider/index.ts
Normal file
6
components/locale-provider/index.ts
Normal file
@ -0,0 +1,6 @@
|
||||
// locale-provider 文件夹的移除需要修改 @ant-design/tools 和 antd-img-crop
|
||||
import locale from '../locale';
|
||||
|
||||
export * from '../locale';
|
||||
|
||||
export default locale;
|
@ -1,3 +0,0 @@
|
||||
import locale from '../locale/is_IS';
|
||||
|
||||
export default locale;
|
@ -1,3 +0,0 @@
|
||||
import locale from '../locale/it_IT';
|
||||
|
||||
export default locale;
|
@ -1,3 +0,0 @@
|
||||
import locale from '../locale/ja_JP';
|
||||
|
||||
export default locale;
|
@ -1,3 +0,0 @@
|
||||
import locale from '../locale/ka_GE';
|
||||
|
||||
export default locale;
|
@ -1,3 +0,0 @@
|
||||
import locale from '../locale/kk_KZ';
|
||||
|
||||
export default locale;
|
@ -1,3 +0,0 @@
|
||||
import locale from '../locale/km_KH';
|
||||
|
||||
export default locale;
|
@ -1,3 +0,0 @@
|
||||
import locale from '../locale/kmr_IQ';
|
||||
|
||||
export default locale;
|
@ -1,3 +0,0 @@
|
||||
import locale from '../locale/kn_IN';
|
||||
|
||||
export default locale;
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user