mirror of
https://gitee.com/ant-design/ant-design.git
synced 2024-11-30 02:59:04 +08:00
merge feature into master
This commit is contained in:
commit
7085e22a96
@ -5,10 +5,16 @@ import { LegacyButtonType, ButtonProps, convertLegacyProps } from '../button/but
|
||||
export interface ActionButtonProps {
|
||||
type?: LegacyButtonType;
|
||||
actionFn?: (...args: any[]) => any | PromiseLike<any>;
|
||||
closeModal: Function;
|
||||
close: Function;
|
||||
autoFocus?: boolean;
|
||||
prefixCls: string;
|
||||
buttonProps?: ButtonProps;
|
||||
emitEvent?: boolean;
|
||||
quitOnNullishReturnValue?: boolean;
|
||||
}
|
||||
|
||||
function isThenable(thing?: PromiseLike<any>): boolean {
|
||||
return !!(thing && !!thing.then);
|
||||
}
|
||||
|
||||
const ActionButton: React.FC<ActionButtonProps> = props => {
|
||||
@ -30,16 +36,16 @@ const ActionButton: React.FC<ActionButtonProps> = props => {
|
||||
}, []);
|
||||
|
||||
const handlePromiseOnOk = (returnValueOfOnOk?: PromiseLike<any>) => {
|
||||
const { closeModal } = props;
|
||||
if (!returnValueOfOnOk || !returnValueOfOnOk.then) {
|
||||
const { close } = props;
|
||||
if (!isThenable(returnValueOfOnOk)) {
|
||||
return;
|
||||
}
|
||||
setLoading(true);
|
||||
returnValueOfOnOk.then(
|
||||
returnValueOfOnOk!.then(
|
||||
(...args: any[]) => {
|
||||
// It's unnecessary to set loading=false, for the Modal will be unmounted after close.
|
||||
// setState({ loading: false });
|
||||
closeModal(...args);
|
||||
setLoading(false);
|
||||
close(...args);
|
||||
clickedRef.current = false;
|
||||
},
|
||||
(e: Error) => {
|
||||
// Emit error when catch promise reject
|
||||
@ -52,25 +58,32 @@ const ActionButton: React.FC<ActionButtonProps> = props => {
|
||||
);
|
||||
};
|
||||
|
||||
const onClick = () => {
|
||||
const { actionFn, closeModal } = props;
|
||||
const onClick = (e: React.MouseEvent<HTMLButtonElement>) => {
|
||||
const { actionFn, close } = props;
|
||||
if (clickedRef.current) {
|
||||
return;
|
||||
}
|
||||
clickedRef.current = true;
|
||||
if (!actionFn) {
|
||||
closeModal();
|
||||
close();
|
||||
return;
|
||||
}
|
||||
let returnValueOfOnOk;
|
||||
if (actionFn.length) {
|
||||
returnValueOfOnOk = actionFn(closeModal);
|
||||
if (props.emitEvent) {
|
||||
returnValueOfOnOk = actionFn(e);
|
||||
if (props.quitOnNullishReturnValue && !isThenable(returnValueOfOnOk)) {
|
||||
clickedRef.current = false;
|
||||
close(e);
|
||||
return;
|
||||
}
|
||||
} else if (actionFn.length) {
|
||||
returnValueOfOnOk = actionFn(close);
|
||||
// https://github.com/ant-design/ant-design/issues/23358
|
||||
clickedRef.current = false;
|
||||
} else {
|
||||
returnValueOfOnOk = actionFn();
|
||||
if (!returnValueOfOnOk) {
|
||||
closeModal();
|
||||
close();
|
||||
return;
|
||||
}
|
||||
}
|
@ -3,7 +3,10 @@ import { MotionEvent } from 'rc-motion/lib/interface';
|
||||
|
||||
// ================== Collapse Motion ==================
|
||||
const getCollapsedHeight: MotionEventHandler = () => ({ height: 0, opacity: 0 });
|
||||
const getRealHeight: MotionEventHandler = node => ({ height: node.scrollHeight, opacity: 1 });
|
||||
const getRealHeight: MotionEventHandler = node => {
|
||||
const { scrollHeight } = node;
|
||||
return { height: scrollHeight, opacity: 1 };
|
||||
};
|
||||
const getCurrentHeight: MotionEventHandler = node => ({ height: node ? node.offsetHeight : 0 });
|
||||
const skipOpacityTransition: MotionEndEventHandler = (_, event: MotionEvent) =>
|
||||
event?.deadline === true || (event as TransitionEvent).propertyName === 'height';
|
||||
|
@ -193,4 +193,22 @@ describe('Avatar Render', () => {
|
||||
wrapper.detach();
|
||||
global.document.body.removeChild(div);
|
||||
});
|
||||
|
||||
it('should exist crossorigin attribute', () => {
|
||||
const LOAD_SUCCESS_SRC = 'https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png';
|
||||
const wrapper = mount(
|
||||
<Avatar src={LOAD_SUCCESS_SRC} crossOrigin="anonymous">
|
||||
crossorigin
|
||||
</Avatar>,
|
||||
);
|
||||
expect(wrapper.html().includes('crossorigin')).toEqual(true);
|
||||
expect(wrapper.find('img').prop('crossOrigin')).toEqual('anonymous');
|
||||
});
|
||||
|
||||
it('should not exist crossorigin attribute', () => {
|
||||
const LOAD_SUCCESS_SRC = 'https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png';
|
||||
const wrapper = mount(<Avatar src={LOAD_SUCCESS_SRC}>crossorigin</Avatar>);
|
||||
expect(wrapper.html().includes('crossorigin')).toEqual(false);
|
||||
expect(wrapper.find('img').prop('crossOrigin')).toEqual(undefined);
|
||||
});
|
||||
});
|
||||
|
@ -29,6 +29,7 @@ export interface AvatarProps {
|
||||
className?: string;
|
||||
children?: React.ReactNode;
|
||||
alt?: string;
|
||||
crossOrigin?: '' | 'anonymous' | 'use-credentials';
|
||||
/* callback when img load error */
|
||||
/* return false to prevent Avatar show default fallback behavior, then you can do fallback by your self */
|
||||
onError?: () => boolean;
|
||||
@ -95,6 +96,7 @@ const InternalAvatar: React.ForwardRefRenderFunction<unknown, AvatarProps> = (pr
|
||||
alt,
|
||||
draggable,
|
||||
children,
|
||||
crossOrigin,
|
||||
...others
|
||||
} = props;
|
||||
|
||||
@ -158,7 +160,14 @@ const InternalAvatar: React.ForwardRefRenderFunction<unknown, AvatarProps> = (pr
|
||||
let childrenToRender;
|
||||
if (typeof src === 'string' && isImgExist) {
|
||||
childrenToRender = (
|
||||
<img src={src} draggable={draggable} srcSet={srcSet} onError={handleImgLoadError} alt={alt} />
|
||||
<img
|
||||
src={src}
|
||||
draggable={draggable}
|
||||
srcSet={srcSet}
|
||||
onError={handleImgLoadError}
|
||||
alt={alt}
|
||||
crossOrigin={crossOrigin}
|
||||
/>
|
||||
);
|
||||
} else if (hasImageElement) {
|
||||
childrenToRender = src;
|
||||
|
@ -21,6 +21,7 @@ Avatars can be used to represent people or objects. It supports images, `Icon`s,
|
||||
| src | The address of the image for an image avatar or image element | string \| ReactNode | - | ReactNode: 4.8.0 |
|
||||
| srcSet | A list of sources to use for different screen resolutions | string | - | |
|
||||
| draggable | Whether the picture is allowed to be dragged | boolean \| `'true'` \| `'false'` | - | |
|
||||
| crossOrigin | CORS settings attributes | `'anonymous'` \| `'use-credentials'` \| `''` | - | 4.17.0 |
|
||||
| onError | Handler when img load error, return false to prevent default fallback behavior | () => boolean | - | |
|
||||
|
||||
> Tip: You can set `icon` or `children` as the fallback for image load error, with the priority of `icon` > `children`
|
||||
|
@ -26,6 +26,7 @@ cover: https://gw.alipayobjects.com/zos/antfincdn/aBcnbw68hP/Avatar.svg
|
||||
| src | 图片类头像的资源地址或者图片元素 | string \| ReactNode | - | ReactNode: 4.8.0 |
|
||||
| srcSet | 设置图片类头像响应式资源地址 | string | - | |
|
||||
| draggable | 图片是否允许拖动 | boolean \| `'true'` \| `'false'` | - | |
|
||||
| crossOrigin | CORS 属性设置 | `'anonymous'` \| `'use-credentials'` \| `''` | - | 4.17.0 |
|
||||
| onError | 图片加载失败的事件,返回 false 会关闭组件默认的 fallback 行为 | () => boolean | - | |
|
||||
|
||||
> Tip:你可以设置 `icon` 或 `children` 作为图片加载失败的默认 fallback 行为,优先级为 `icon` > `children`
|
||||
|
3
components/calendar/locale/bn_BD.tsx
Normal file
3
components/calendar/locale/bn_BD.tsx
Normal file
@ -0,0 +1,3 @@
|
||||
import bnBD from '../../date-picker/locale/bn_BD';
|
||||
|
||||
export default bnBD;
|
3
components/calendar/locale/ml_IN.tsx
Normal file
3
components/calendar/locale/ml_IN.tsx
Normal file
@ -0,0 +1,3 @@
|
||||
import mlIN from '../../date-picker/locale/ml_IN';
|
||||
|
||||
export default mlIN;
|
3
components/calendar/locale/ur_PK.tsx
Normal file
3
components/calendar/locale/ur_PK.tsx
Normal file
@ -0,0 +1,3 @@
|
||||
import urPK from '../../date-picker/locale/ur_PK';
|
||||
|
||||
export default urPK;
|
@ -209,6 +209,7 @@ exports[`renders ./components/cascader/demo/default-value.md correctly 1`] = `
|
||||
>
|
||||
<span
|
||||
class="ant-cascader-picker-label"
|
||||
title="Zhejiang / Hangzhou / West Lake"
|
||||
>
|
||||
Zhejiang / Hangzhou / West Lake
|
||||
</span>
|
||||
|
@ -1117,6 +1117,7 @@ exports[`Cascader support controlled mode 1`] = `
|
||||
>
|
||||
<span
|
||||
class="ant-cascader-picker-label"
|
||||
title="Zhejiang / Hangzhou / West Lake"
|
||||
>
|
||||
Zhejiang / Hangzhou / West Lake
|
||||
</span>
|
||||
|
@ -316,7 +316,7 @@ class Cascader extends React.Component<CascaderProps, CascaderState> {
|
||||
};
|
||||
|
||||
getLabel() {
|
||||
const { options, displayRender = defaultDisplayRender as Function } = this.props;
|
||||
const { options, displayRender = defaultDisplayRender } = this.props;
|
||||
const names = getFilledFieldNames(this.props);
|
||||
const { value } = this.state;
|
||||
const unwrappedValue = Array.isArray(value[0]) ? value[0] : value;
|
||||
@ -618,9 +618,15 @@ class Cascader extends React.Component<CascaderProps, CascaderState> {
|
||||
inputIcon = <DownOutlined className={arrowCls} />;
|
||||
}
|
||||
|
||||
const label = this.getLabel();
|
||||
const input: React.ReactElement = children || (
|
||||
<span style={style} className={pickerCls}>
|
||||
<span className={`${prefixCls}-picker-label`}>{this.getLabel()}</span>
|
||||
<span
|
||||
className={`${prefixCls}-picker-label`}
|
||||
title={typeof label === 'string' && label ? label : undefined}
|
||||
>
|
||||
{label}
|
||||
</span>
|
||||
<Input
|
||||
{...inputProps}
|
||||
tabIndex={-1}
|
||||
|
@ -48,7 +48,7 @@
|
||||
direction: ltr;
|
||||
background-color: @checkbox-check-bg;
|
||||
border: @checkbox-border-width @border-style-base @border-color-base;
|
||||
border-radius: @border-radius-base;
|
||||
border-radius: @checkbox-border-radius;
|
||||
// Fix IE checked style
|
||||
// https://github.com/ant-design/ant-design/issues/12597
|
||||
border-collapse: separate;
|
||||
|
@ -12199,7 +12199,7 @@ exports[`ConfigProvider components Drawer configProvider 1`] = `
|
||||
/>
|
||||
<div
|
||||
class="config-drawer-content-wrapper"
|
||||
style="transform:translateX(100%);-ms-transform:translateX(100%);width:256px"
|
||||
style="transform:translateX(100%);-ms-transform:translateX(100%);width:378px"
|
||||
>
|
||||
<div
|
||||
class="config-drawer-content"
|
||||
@ -12208,34 +12208,37 @@ exports[`ConfigProvider components Drawer configProvider 1`] = `
|
||||
class="config-drawer-wrapper-body"
|
||||
>
|
||||
<div
|
||||
class="config-drawer-header-no-title"
|
||||
class="config-drawer-header config-drawer-header-close-only"
|
||||
>
|
||||
<button
|
||||
aria-label="Close"
|
||||
class="config-drawer-close"
|
||||
style="--scroll-bar:0px"
|
||||
type="button"
|
||||
<div
|
||||
class="config-drawer-header-title"
|
||||
>
|
||||
<span
|
||||
aria-label="close"
|
||||
class="anticon anticon-close"
|
||||
role="img"
|
||||
<button
|
||||
aria-label="Close"
|
||||
class="config-drawer-close"
|
||||
type="button"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="close"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
<span
|
||||
aria-label="close"
|
||||
class="anticon anticon-close"
|
||||
role="img"
|
||||
>
|
||||
<path
|
||||
d="M563.8 512l262.5-312.9c4.4-5.2.7-13.1-6.1-13.1h-79.8c-4.7 0-9.2 2.1-12.3 5.7L511.6 449.8 295.1 191.7c-3-3.6-7.5-5.7-12.3-5.7H203c-6.8 0-10.5 7.9-6.1 13.1L459.4 512 196.9 824.9A7.95 7.95 0 00203 838h79.8c4.7 0 9.2-2.1 12.3-5.7l216.5-258.1 216.5 258.1c3 3.6 7.5 5.7 12.3 5.7h79.8c6.8 0 10.5-7.9 6.1-13.1L563.8 512z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</button>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="close"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M563.8 512l262.5-312.9c4.4-5.2.7-13.1-6.1-13.1h-79.8c-4.7 0-9.2 2.1-12.3 5.7L511.6 449.8 295.1 191.7c-3-3.6-7.5-5.7-12.3-5.7H203c-6.8 0-10.5 7.9-6.1 13.1L459.4 512 196.9 824.9A7.95 7.95 0 00203 838h79.8c4.7 0 9.2-2.1 12.3-5.7l216.5-258.1 216.5 258.1c3 3.6 7.5 5.7 12.3 5.7h79.8c6.8 0 10.5-7.9 6.1-13.1L563.8 512z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="config-drawer-body"
|
||||
@ -12260,7 +12263,7 @@ exports[`ConfigProvider components Drawer configProvider componentSize large 1`]
|
||||
/>
|
||||
<div
|
||||
class="config-drawer-content-wrapper"
|
||||
style="transform:translateX(100%);-ms-transform:translateX(100%);width:256px"
|
||||
style="transform:translateX(100%);-ms-transform:translateX(100%);width:378px"
|
||||
>
|
||||
<div
|
||||
class="config-drawer-content"
|
||||
@ -12269,34 +12272,37 @@ exports[`ConfigProvider components Drawer configProvider componentSize large 1`]
|
||||
class="config-drawer-wrapper-body"
|
||||
>
|
||||
<div
|
||||
class="config-drawer-header-no-title"
|
||||
class="config-drawer-header config-drawer-header-close-only"
|
||||
>
|
||||
<button
|
||||
aria-label="Close"
|
||||
class="config-drawer-close"
|
||||
style="--scroll-bar:0px"
|
||||
type="button"
|
||||
<div
|
||||
class="config-drawer-header-title"
|
||||
>
|
||||
<span
|
||||
aria-label="close"
|
||||
class="anticon anticon-close"
|
||||
role="img"
|
||||
<button
|
||||
aria-label="Close"
|
||||
class="config-drawer-close"
|
||||
type="button"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="close"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
<span
|
||||
aria-label="close"
|
||||
class="anticon anticon-close"
|
||||
role="img"
|
||||
>
|
||||
<path
|
||||
d="M563.8 512l262.5-312.9c4.4-5.2.7-13.1-6.1-13.1h-79.8c-4.7 0-9.2 2.1-12.3 5.7L511.6 449.8 295.1 191.7c-3-3.6-7.5-5.7-12.3-5.7H203c-6.8 0-10.5 7.9-6.1 13.1L459.4 512 196.9 824.9A7.95 7.95 0 00203 838h79.8c4.7 0 9.2-2.1 12.3-5.7l216.5-258.1 216.5 258.1c3 3.6 7.5 5.7 12.3 5.7h79.8c6.8 0 10.5-7.9 6.1-13.1L563.8 512z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</button>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="close"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M563.8 512l262.5-312.9c4.4-5.2.7-13.1-6.1-13.1h-79.8c-4.7 0-9.2 2.1-12.3 5.7L511.6 449.8 295.1 191.7c-3-3.6-7.5-5.7-12.3-5.7H203c-6.8 0-10.5 7.9-6.1 13.1L459.4 512 196.9 824.9A7.95 7.95 0 00203 838h79.8c4.7 0 9.2-2.1 12.3-5.7l216.5-258.1 216.5 258.1c3 3.6 7.5 5.7 12.3 5.7h79.8c6.8 0 10.5-7.9 6.1-13.1L563.8 512z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="config-drawer-body"
|
||||
@ -12321,7 +12327,7 @@ exports[`ConfigProvider components Drawer configProvider componentSize middle 1`
|
||||
/>
|
||||
<div
|
||||
class="config-drawer-content-wrapper"
|
||||
style="transform:translateX(100%);-ms-transform:translateX(100%);width:256px"
|
||||
style="transform:translateX(100%);-ms-transform:translateX(100%);width:378px"
|
||||
>
|
||||
<div
|
||||
class="config-drawer-content"
|
||||
@ -12330,34 +12336,37 @@ exports[`ConfigProvider components Drawer configProvider componentSize middle 1`
|
||||
class="config-drawer-wrapper-body"
|
||||
>
|
||||
<div
|
||||
class="config-drawer-header-no-title"
|
||||
class="config-drawer-header config-drawer-header-close-only"
|
||||
>
|
||||
<button
|
||||
aria-label="Close"
|
||||
class="config-drawer-close"
|
||||
style="--scroll-bar:0px"
|
||||
type="button"
|
||||
<div
|
||||
class="config-drawer-header-title"
|
||||
>
|
||||
<span
|
||||
aria-label="close"
|
||||
class="anticon anticon-close"
|
||||
role="img"
|
||||
<button
|
||||
aria-label="Close"
|
||||
class="config-drawer-close"
|
||||
type="button"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="close"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
<span
|
||||
aria-label="close"
|
||||
class="anticon anticon-close"
|
||||
role="img"
|
||||
>
|
||||
<path
|
||||
d="M563.8 512l262.5-312.9c4.4-5.2.7-13.1-6.1-13.1h-79.8c-4.7 0-9.2 2.1-12.3 5.7L511.6 449.8 295.1 191.7c-3-3.6-7.5-5.7-12.3-5.7H203c-6.8 0-10.5 7.9-6.1 13.1L459.4 512 196.9 824.9A7.95 7.95 0 00203 838h79.8c4.7 0 9.2-2.1 12.3-5.7l216.5-258.1 216.5 258.1c3 3.6 7.5 5.7 12.3 5.7h79.8c6.8 0 10.5-7.9 6.1-13.1L563.8 512z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</button>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="close"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M563.8 512l262.5-312.9c4.4-5.2.7-13.1-6.1-13.1h-79.8c-4.7 0-9.2 2.1-12.3 5.7L511.6 449.8 295.1 191.7c-3-3.6-7.5-5.7-12.3-5.7H203c-6.8 0-10.5 7.9-6.1 13.1L459.4 512 196.9 824.9A7.95 7.95 0 00203 838h79.8c4.7 0 9.2-2.1 12.3-5.7l216.5-258.1 216.5 258.1c3 3.6 7.5 5.7 12.3 5.7h79.8c6.8 0 10.5-7.9 6.1-13.1L563.8 512z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="config-drawer-body"
|
||||
@ -12382,7 +12391,7 @@ exports[`ConfigProvider components Drawer configProvider virtual and dropdownMat
|
||||
/>
|
||||
<div
|
||||
class="ant-drawer-content-wrapper"
|
||||
style="transform:translateX(100%);-ms-transform:translateX(100%);width:256px"
|
||||
style="transform:translateX(100%);-ms-transform:translateX(100%);width:378px"
|
||||
>
|
||||
<div
|
||||
class="ant-drawer-content"
|
||||
@ -12391,34 +12400,37 @@ exports[`ConfigProvider components Drawer configProvider virtual and dropdownMat
|
||||
class="ant-drawer-wrapper-body"
|
||||
>
|
||||
<div
|
||||
class="ant-drawer-header-no-title"
|
||||
class="ant-drawer-header ant-drawer-header-close-only"
|
||||
>
|
||||
<button
|
||||
aria-label="Close"
|
||||
class="ant-drawer-close"
|
||||
style="--scroll-bar:0px"
|
||||
type="button"
|
||||
<div
|
||||
class="ant-drawer-header-title"
|
||||
>
|
||||
<span
|
||||
aria-label="close"
|
||||
class="anticon anticon-close"
|
||||
role="img"
|
||||
<button
|
||||
aria-label="Close"
|
||||
class="ant-drawer-close"
|
||||
type="button"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="close"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
<span
|
||||
aria-label="close"
|
||||
class="anticon anticon-close"
|
||||
role="img"
|
||||
>
|
||||
<path
|
||||
d="M563.8 512l262.5-312.9c4.4-5.2.7-13.1-6.1-13.1h-79.8c-4.7 0-9.2 2.1-12.3 5.7L511.6 449.8 295.1 191.7c-3-3.6-7.5-5.7-12.3-5.7H203c-6.8 0-10.5 7.9-6.1 13.1L459.4 512 196.9 824.9A7.95 7.95 0 00203 838h79.8c4.7 0 9.2-2.1 12.3-5.7l216.5-258.1 216.5 258.1c3 3.6 7.5 5.7 12.3 5.7h79.8c6.8 0 10.5-7.9 6.1-13.1L563.8 512z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</button>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="close"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M563.8 512l262.5-312.9c4.4-5.2.7-13.1-6.1-13.1h-79.8c-4.7 0-9.2 2.1-12.3 5.7L511.6 449.8 295.1 191.7c-3-3.6-7.5-5.7-12.3-5.7H203c-6.8 0-10.5 7.9-6.1 13.1L459.4 512 196.9 824.9A7.95 7.95 0 00203 838h79.8c4.7 0 9.2-2.1 12.3-5.7l216.5-258.1 216.5 258.1c3 3.6 7.5 5.7 12.3 5.7h79.8c6.8 0 10.5-7.9 6.1-13.1L563.8 512z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-drawer-body"
|
||||
@ -12443,7 +12455,7 @@ exports[`ConfigProvider components Drawer normal 1`] = `
|
||||
/>
|
||||
<div
|
||||
class="ant-drawer-content-wrapper"
|
||||
style="transform:translateX(100%);-ms-transform:translateX(100%);width:256px"
|
||||
style="transform:translateX(100%);-ms-transform:translateX(100%);width:378px"
|
||||
>
|
||||
<div
|
||||
class="ant-drawer-content"
|
||||
@ -12452,34 +12464,37 @@ exports[`ConfigProvider components Drawer normal 1`] = `
|
||||
class="ant-drawer-wrapper-body"
|
||||
>
|
||||
<div
|
||||
class="ant-drawer-header-no-title"
|
||||
class="ant-drawer-header ant-drawer-header-close-only"
|
||||
>
|
||||
<button
|
||||
aria-label="Close"
|
||||
class="ant-drawer-close"
|
||||
style="--scroll-bar:0px"
|
||||
type="button"
|
||||
<div
|
||||
class="ant-drawer-header-title"
|
||||
>
|
||||
<span
|
||||
aria-label="close"
|
||||
class="anticon anticon-close"
|
||||
role="img"
|
||||
<button
|
||||
aria-label="Close"
|
||||
class="ant-drawer-close"
|
||||
type="button"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="close"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
<span
|
||||
aria-label="close"
|
||||
class="anticon anticon-close"
|
||||
role="img"
|
||||
>
|
||||
<path
|
||||
d="M563.8 512l262.5-312.9c4.4-5.2.7-13.1-6.1-13.1h-79.8c-4.7 0-9.2 2.1-12.3 5.7L511.6 449.8 295.1 191.7c-3-3.6-7.5-5.7-12.3-5.7H203c-6.8 0-10.5 7.9-6.1 13.1L459.4 512 196.9 824.9A7.95 7.95 0 00203 838h79.8c4.7 0 9.2-2.1 12.3-5.7l216.5-258.1 216.5 258.1c3 3.6 7.5 5.7 12.3 5.7h79.8c6.8 0 10.5-7.9 6.1-13.1L563.8 512z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</button>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="close"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M563.8 512l262.5-312.9c4.4-5.2.7-13.1-6.1-13.1h-79.8c-4.7 0-9.2 2.1-12.3 5.7L511.6 449.8 295.1 191.7c-3-3.6-7.5-5.7-12.3-5.7H203c-6.8 0-10.5 7.9-6.1 13.1L459.4 512 196.9 824.9A7.95 7.95 0 00203 838h79.8c4.7 0 9.2-2.1 12.3-5.7l216.5-258.1 216.5 258.1c3 3.6 7.5 5.7 12.3 5.7h79.8c6.8 0 10.5-7.9 6.1-13.1L563.8 512z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-drawer-body"
|
||||
@ -12504,7 +12519,7 @@ exports[`ConfigProvider components Drawer prefixCls 1`] = `
|
||||
/>
|
||||
<div
|
||||
class="prefix-Drawer-content-wrapper"
|
||||
style="transform:translateX(100%);-ms-transform:translateX(100%);width:256px"
|
||||
style="transform:translateX(100%);-ms-transform:translateX(100%);width:378px"
|
||||
>
|
||||
<div
|
||||
class="prefix-Drawer-content"
|
||||
@ -12513,34 +12528,37 @@ exports[`ConfigProvider components Drawer prefixCls 1`] = `
|
||||
class="prefix-Drawer-wrapper-body"
|
||||
>
|
||||
<div
|
||||
class="prefix-Drawer-header-no-title"
|
||||
class="prefix-Drawer-header prefix-Drawer-header-close-only"
|
||||
>
|
||||
<button
|
||||
aria-label="Close"
|
||||
class="prefix-Drawer-close"
|
||||
style="--scroll-bar:0px"
|
||||
type="button"
|
||||
<div
|
||||
class="prefix-Drawer-header-title"
|
||||
>
|
||||
<span
|
||||
aria-label="close"
|
||||
class="anticon anticon-close"
|
||||
role="img"
|
||||
<button
|
||||
aria-label="Close"
|
||||
class="prefix-Drawer-close"
|
||||
type="button"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="close"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
<span
|
||||
aria-label="close"
|
||||
class="anticon anticon-close"
|
||||
role="img"
|
||||
>
|
||||
<path
|
||||
d="M563.8 512l262.5-312.9c4.4-5.2.7-13.1-6.1-13.1h-79.8c-4.7 0-9.2 2.1-12.3 5.7L511.6 449.8 295.1 191.7c-3-3.6-7.5-5.7-12.3-5.7H203c-6.8 0-10.5 7.9-6.1 13.1L459.4 512 196.9 824.9A7.95 7.95 0 00203 838h79.8c4.7 0 9.2-2.1 12.3-5.7l216.5-258.1 216.5 258.1c3 3.6 7.5 5.7 12.3 5.7h79.8c6.8 0 10.5-7.9 6.1-13.1L563.8 512z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</button>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="close"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M563.8 512l262.5-312.9c4.4-5.2.7-13.1-6.1-13.1h-79.8c-4.7 0-9.2 2.1-12.3 5.7L511.6 449.8 295.1 191.7c-3-3.6-7.5-5.7-12.3-5.7H203c-6.8 0-10.5 7.9-6.1 13.1L459.4 512 196.9 824.9A7.95 7.95 0 00203 838h79.8c4.7 0 9.2-2.1 12.3-5.7l216.5-258.1 216.5 258.1c3 3.6 7.5 5.7 12.3 5.7h79.8c6.8 0 10.5-7.9 6.1-13.1L563.8 512z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="prefix-Drawer-body"
|
||||
@ -13260,9 +13278,10 @@ exports[`ConfigProvider components Form configProvider 1`] = `
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="config-form-item-explain config-form-item-explain-error"
|
||||
class="config-form-item-explain config-form-item-explain-connected"
|
||||
>
|
||||
<div
|
||||
class="config-form-item-explain-error"
|
||||
role="alert"
|
||||
>
|
||||
Bamboo is Light
|
||||
@ -13297,9 +13316,10 @@ exports[`ConfigProvider components Form configProvider componentSize large 1`] =
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="config-form-item-explain config-form-item-explain-error"
|
||||
class="config-form-item-explain config-form-item-explain-connected"
|
||||
>
|
||||
<div
|
||||
class="config-form-item-explain-error"
|
||||
role="alert"
|
||||
>
|
||||
Bamboo is Light
|
||||
@ -13334,9 +13354,10 @@ exports[`ConfigProvider components Form configProvider componentSize middle 1`]
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="config-form-item-explain config-form-item-explain-error"
|
||||
class="config-form-item-explain config-form-item-explain-connected"
|
||||
>
|
||||
<div
|
||||
class="config-form-item-explain-error"
|
||||
role="alert"
|
||||
>
|
||||
Bamboo is Light
|
||||
@ -13371,9 +13392,10 @@ exports[`ConfigProvider components Form configProvider virtual and dropdownMatch
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-form-item-explain ant-form-item-explain-error"
|
||||
class="ant-form-item-explain ant-form-item-explain-connected"
|
||||
>
|
||||
<div
|
||||
class="ant-form-item-explain-error"
|
||||
role="alert"
|
||||
>
|
||||
Bamboo is Light
|
||||
@ -13408,9 +13430,10 @@ exports[`ConfigProvider components Form normal 1`] = `
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-form-item-explain ant-form-item-explain-error"
|
||||
class="ant-form-item-explain ant-form-item-explain-connected"
|
||||
>
|
||||
<div
|
||||
class="ant-form-item-explain-error"
|
||||
role="alert"
|
||||
>
|
||||
Bamboo is Light
|
||||
@ -13445,9 +13468,10 @@ exports[`ConfigProvider components Form prefixCls 1`] = `
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="prefix-Form-item-explain prefix-Form-item-explain-error"
|
||||
class="prefix-Form-item-explain prefix-Form-item-explain-connected"
|
||||
>
|
||||
<div
|
||||
class="prefix-Form-item-explain-error"
|
||||
role="alert"
|
||||
>
|
||||
Bamboo is Light
|
||||
@ -35502,11 +35526,11 @@ exports[`ConfigProvider components Tree configProvider 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="config-tree config-tree-icon-hide"
|
||||
role="tree"
|
||||
>
|
||||
<div
|
||||
role="tree"
|
||||
>
|
||||
<div>
|
||||
<input
|
||||
aria-label="for screen reader"
|
||||
style="width:0;height:0;display:flex;overflow:hidden;opacity:0;border:0;padding:0;margin:0"
|
||||
tabindex="0"
|
||||
value=""
|
||||
@ -35565,11 +35589,11 @@ exports[`ConfigProvider components Tree configProvider 1`] = `
|
||||
</div>
|
||||
<div
|
||||
class="config-tree config-tree-block-node config-tree-directory"
|
||||
role="tree"
|
||||
>
|
||||
<div
|
||||
role="tree"
|
||||
>
|
||||
<div>
|
||||
<input
|
||||
aria-label="for screen reader"
|
||||
style="width:0;height:0;display:flex;overflow:hidden;opacity:0;border:0;padding:0;margin:0"
|
||||
tabindex="0"
|
||||
value=""
|
||||
@ -35656,11 +35680,11 @@ exports[`ConfigProvider components Tree configProvider componentSize large 1`] =
|
||||
<div>
|
||||
<div
|
||||
class="config-tree config-tree-icon-hide"
|
||||
role="tree"
|
||||
>
|
||||
<div
|
||||
role="tree"
|
||||
>
|
||||
<div>
|
||||
<input
|
||||
aria-label="for screen reader"
|
||||
style="width:0;height:0;display:flex;overflow:hidden;opacity:0;border:0;padding:0;margin:0"
|
||||
tabindex="0"
|
||||
value=""
|
||||
@ -35719,11 +35743,11 @@ exports[`ConfigProvider components Tree configProvider componentSize large 1`] =
|
||||
</div>
|
||||
<div
|
||||
class="config-tree config-tree-block-node config-tree-directory"
|
||||
role="tree"
|
||||
>
|
||||
<div
|
||||
role="tree"
|
||||
>
|
||||
<div>
|
||||
<input
|
||||
aria-label="for screen reader"
|
||||
style="width:0;height:0;display:flex;overflow:hidden;opacity:0;border:0;padding:0;margin:0"
|
||||
tabindex="0"
|
||||
value=""
|
||||
@ -35810,11 +35834,11 @@ exports[`ConfigProvider components Tree configProvider componentSize middle 1`]
|
||||
<div>
|
||||
<div
|
||||
class="config-tree config-tree-icon-hide"
|
||||
role="tree"
|
||||
>
|
||||
<div
|
||||
role="tree"
|
||||
>
|
||||
<div>
|
||||
<input
|
||||
aria-label="for screen reader"
|
||||
style="width:0;height:0;display:flex;overflow:hidden;opacity:0;border:0;padding:0;margin:0"
|
||||
tabindex="0"
|
||||
value=""
|
||||
@ -35873,11 +35897,11 @@ exports[`ConfigProvider components Tree configProvider componentSize middle 1`]
|
||||
</div>
|
||||
<div
|
||||
class="config-tree config-tree-block-node config-tree-directory"
|
||||
role="tree"
|
||||
>
|
||||
<div
|
||||
role="tree"
|
||||
>
|
||||
<div>
|
||||
<input
|
||||
aria-label="for screen reader"
|
||||
style="width:0;height:0;display:flex;overflow:hidden;opacity:0;border:0;padding:0;margin:0"
|
||||
tabindex="0"
|
||||
value=""
|
||||
@ -35964,11 +35988,11 @@ exports[`ConfigProvider components Tree configProvider virtual and dropdownMatch
|
||||
<div>
|
||||
<div
|
||||
class="ant-tree ant-tree-icon-hide"
|
||||
role="tree"
|
||||
>
|
||||
<div
|
||||
role="tree"
|
||||
>
|
||||
<div>
|
||||
<input
|
||||
aria-label="for screen reader"
|
||||
style="width:0;height:0;display:flex;overflow:hidden;opacity:0;border:0;padding:0;margin:0"
|
||||
tabindex="0"
|
||||
value=""
|
||||
@ -36027,11 +36051,11 @@ exports[`ConfigProvider components Tree configProvider virtual and dropdownMatch
|
||||
</div>
|
||||
<div
|
||||
class="ant-tree ant-tree-block-node ant-tree-directory"
|
||||
role="tree"
|
||||
>
|
||||
<div
|
||||
role="tree"
|
||||
>
|
||||
<div>
|
||||
<input
|
||||
aria-label="for screen reader"
|
||||
style="width:0;height:0;display:flex;overflow:hidden;opacity:0;border:0;padding:0;margin:0"
|
||||
tabindex="0"
|
||||
value=""
|
||||
@ -36118,11 +36142,11 @@ exports[`ConfigProvider components Tree normal 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="ant-tree ant-tree-icon-hide"
|
||||
role="tree"
|
||||
>
|
||||
<div
|
||||
role="tree"
|
||||
>
|
||||
<div>
|
||||
<input
|
||||
aria-label="for screen reader"
|
||||
style="width:0;height:0;display:flex;overflow:hidden;opacity:0;border:0;padding:0;margin:0"
|
||||
tabindex="0"
|
||||
value=""
|
||||
@ -36181,11 +36205,11 @@ exports[`ConfigProvider components Tree normal 1`] = `
|
||||
</div>
|
||||
<div
|
||||
class="ant-tree ant-tree-block-node ant-tree-directory"
|
||||
role="tree"
|
||||
>
|
||||
<div
|
||||
role="tree"
|
||||
>
|
||||
<div>
|
||||
<input
|
||||
aria-label="for screen reader"
|
||||
style="width:0;height:0;display:flex;overflow:hidden;opacity:0;border:0;padding:0;margin:0"
|
||||
tabindex="0"
|
||||
value=""
|
||||
@ -36272,11 +36296,11 @@ exports[`ConfigProvider components Tree prefixCls 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="prefix-Tree prefix-Tree-icon-hide"
|
||||
role="tree"
|
||||
>
|
||||
<div
|
||||
role="tree"
|
||||
>
|
||||
<div>
|
||||
<input
|
||||
aria-label="for screen reader"
|
||||
style="width:0;height:0;display:flex;overflow:hidden;opacity:0;border:0;padding:0;margin:0"
|
||||
tabindex="0"
|
||||
value=""
|
||||
@ -36335,11 +36359,11 @@ exports[`ConfigProvider components Tree prefixCls 1`] = `
|
||||
</div>
|
||||
<div
|
||||
class="prefix-Tree prefix-Tree-block-node prefix-Tree-directory"
|
||||
role="tree"
|
||||
>
|
||||
<div
|
||||
role="tree"
|
||||
>
|
||||
<div>
|
||||
<input
|
||||
aria-label="for screen reader"
|
||||
style="width:0;height:0;display:flex;overflow:hidden;opacity:0;border:0;padding:0;margin:0"
|
||||
tabindex="0"
|
||||
value=""
|
||||
|
@ -61,7 +61,8 @@ Setting `Modal`、`Message`、`Notification` rootPrefixCls.
|
||||
|
||||
```jsx
|
||||
ConfigProvider.config({
|
||||
prefixCls: 'ant',
|
||||
prefixCls: 'ant', // 4.13.0+
|
||||
iconPrefixCls: 'anticon', // 4.17.0+
|
||||
});
|
||||
```
|
||||
|
||||
|
@ -85,11 +85,19 @@ interface ProviderChildrenProps extends ConfigProviderProps {
|
||||
}
|
||||
|
||||
export const defaultPrefixCls = 'ant';
|
||||
export const defaultIconPrefixCls = 'anticon';
|
||||
let globalPrefixCls: string;
|
||||
let globalIconPrefixCls: string;
|
||||
|
||||
const setGlobalConfig = (params: Pick<ConfigProviderProps, 'prefixCls'>) => {
|
||||
if (params.prefixCls !== undefined) {
|
||||
globalPrefixCls = params.prefixCls;
|
||||
const setGlobalConfig = ({
|
||||
prefixCls,
|
||||
iconPrefixCls,
|
||||
}: Pick<ConfigProviderProps, 'prefixCls' | 'iconPrefixCls'>) => {
|
||||
if (prefixCls !== undefined) {
|
||||
globalPrefixCls = prefixCls;
|
||||
}
|
||||
if (iconPrefixCls !== undefined) {
|
||||
globalIconPrefixCls = iconPrefixCls;
|
||||
}
|
||||
};
|
||||
|
||||
@ -97,11 +105,16 @@ function getGlobalPrefixCls() {
|
||||
return globalPrefixCls || defaultPrefixCls;
|
||||
}
|
||||
|
||||
function getGlobalIconPrefixCls() {
|
||||
return globalIconPrefixCls || defaultIconPrefixCls;
|
||||
}
|
||||
|
||||
export const globalConfig = () => ({
|
||||
getPrefixCls: (suffixCls?: string, customizePrefixCls?: string) => {
|
||||
if (customizePrefixCls) return customizePrefixCls;
|
||||
return suffixCls ? `${getGlobalPrefixCls()}-${suffixCls}` : getGlobalPrefixCls();
|
||||
},
|
||||
getIconPrefixCls: getGlobalIconPrefixCls,
|
||||
getRootPrefixCls: (rootPrefixCls?: string, customizePrefixCls?: string) => {
|
||||
// Customize rootPrefixCls is first priority
|
||||
if (rootPrefixCls) {
|
||||
|
@ -62,7 +62,8 @@ export default () => (
|
||||
|
||||
```jsx
|
||||
ConfigProvider.config({
|
||||
prefixCls: 'ant',
|
||||
prefixCls: 'ant', // 4.13.0+
|
||||
iconPrefixCls: 'anticon', // 4.17.0+
|
||||
});
|
||||
```
|
||||
|
||||
|
27
components/date-picker/locale/bn_BD.tsx
Normal file
27
components/date-picker/locale/bn_BD.tsx
Normal file
@ -0,0 +1,27 @@
|
||||
import CalendarLocale from 'rc-picker/lib/locale/bn_BD';
|
||||
import TimePickerLocale from '../../time-picker/locale/bn_BD';
|
||||
import { PickerLocale } from '../generatePicker';
|
||||
|
||||
// Merge into a locale object
|
||||
const locale: PickerLocale = {
|
||||
lang: {
|
||||
placeholder: 'তারিখ নির্বাচন',
|
||||
yearPlaceholder: 'বছর নির্বাচন',
|
||||
quarterPlaceholder: 'কোয়ার্টার নির্বাচন',
|
||||
monthPlaceholder: 'মাস নির্বাচন',
|
||||
weekPlaceholder: 'সপ্তাহ নির্বাচন',
|
||||
rangePlaceholder: ['শুরুর তারিখ', 'শেষ তারিখ'],
|
||||
rangeYearPlaceholder: ['শুরুর বছর', 'শেষ বছর'],
|
||||
rangeMonthPlaceholder: ['শুরুর মাস', 'শেষ মাস'],
|
||||
rangeWeekPlaceholder: ['শুরুর সপ্তাহ', 'শেষ সপ্তাহ'],
|
||||
...CalendarLocale,
|
||||
},
|
||||
timePickerLocale: {
|
||||
...TimePickerLocale,
|
||||
},
|
||||
};
|
||||
|
||||
// All settings at:
|
||||
// https://github.com/ant-design/ant-design/blob/master/components/date-picker/locale/example.json
|
||||
|
||||
export default locale;
|
27
components/date-picker/locale/ml_IN.tsx
Normal file
27
components/date-picker/locale/ml_IN.tsx
Normal file
@ -0,0 +1,27 @@
|
||||
import CalendarLocale from 'rc-picker/lib/locale/ml_IN';
|
||||
import TimePickerLocale from '../../time-picker/locale/ml_IN';
|
||||
import { PickerLocale } from '../generatePicker';
|
||||
|
||||
// Merge into a locale object
|
||||
const locale: PickerLocale = {
|
||||
lang: {
|
||||
placeholder: 'തിയതി തിരഞ്ഞെടുക്കുക',
|
||||
yearPlaceholder: 'വർഷം തിരഞ്ഞെടുക്കുക',
|
||||
quarterPlaceholder: 'ത്രൈമാസം തിരഞ്ഞെടുക്കുക',
|
||||
monthPlaceholder: 'മാസം തിരഞ്ഞെടുക്കുക',
|
||||
weekPlaceholder: 'വാരം തിരഞ്ഞെടുക്കുക',
|
||||
rangePlaceholder: ['ആരംഭ ദിനം', 'അവസാന ദിനം'],
|
||||
rangeYearPlaceholder: ['ആരംഭ വർഷം', 'അവസാന വർഷം'],
|
||||
rangeMonthPlaceholder: ['ആരംഭ മാസം', 'അവസാന മാസം'],
|
||||
rangeWeekPlaceholder: ['ആരംഭ വാരം', 'അവസാന വാരം'],
|
||||
...CalendarLocale,
|
||||
},
|
||||
timePickerLocale: {
|
||||
...TimePickerLocale,
|
||||
},
|
||||
};
|
||||
|
||||
// All settings at:
|
||||
// https://github.com/ant-design/ant-design/blob/master/components/date-picker/locale/example.json
|
||||
|
||||
export default locale;
|
27
components/date-picker/locale/ur_PK.tsx
Normal file
27
components/date-picker/locale/ur_PK.tsx
Normal file
@ -0,0 +1,27 @@
|
||||
import CalendarLocale from 'rc-picker/lib/locale/ur_PK';
|
||||
import TimePickerLocale from '../../time-picker/locale/ur_PK';
|
||||
import { PickerLocale } from '../generatePicker';
|
||||
|
||||
// Merge into a locale object
|
||||
const locale: PickerLocale = {
|
||||
lang: {
|
||||
placeholder: 'تاریخ منتخب کریں',
|
||||
yearPlaceholder: 'سال کو منتخب کریں',
|
||||
quarterPlaceholder: 'کوارٹر منتخب کریں',
|
||||
monthPlaceholder: 'ماہ منتخب کریں',
|
||||
weekPlaceholder: 'ہفتہ منتخب کریں',
|
||||
rangePlaceholder: ['شروع کرنے کی تاریخ', 'آخری تاریخ'],
|
||||
rangeYearPlaceholder: ['آغاز سال', 'آخر سال'],
|
||||
rangeMonthPlaceholder: ['مہینہ شروع', 'اختتامی مہینہ'],
|
||||
rangeWeekPlaceholder: ['ہفتے شروع کریں', 'اختتام ہفتہ'],
|
||||
...CalendarLocale,
|
||||
},
|
||||
timePickerLocale: {
|
||||
...TimePickerLocale,
|
||||
},
|
||||
};
|
||||
|
||||
// All settings at:
|
||||
// https://github.com/ant-design/ant-design/blob/master/components/date-picker/locale/example.json
|
||||
|
||||
export default locale;
|
@ -13,7 +13,7 @@ exports[`Drawer className is test_drawer 1`] = `
|
||||
/>
|
||||
<div
|
||||
class="ant-drawer-content-wrapper"
|
||||
style="transform:translateX(100%);-ms-transform:translateX(100%);width:256px"
|
||||
style="transform:translateX(100%);-ms-transform:translateX(100%);width:378px"
|
||||
>
|
||||
<div
|
||||
class="ant-drawer-content"
|
||||
@ -23,34 +23,37 @@ exports[`Drawer className is test_drawer 1`] = `
|
||||
style="opacity:0;transition:opacity .3s"
|
||||
>
|
||||
<div
|
||||
class="ant-drawer-header-no-title"
|
||||
class="ant-drawer-header ant-drawer-header-close-only"
|
||||
>
|
||||
<button
|
||||
aria-label="Close"
|
||||
class="ant-drawer-close"
|
||||
style="--scroll-bar:0px"
|
||||
type="button"
|
||||
<div
|
||||
class="ant-drawer-header-title"
|
||||
>
|
||||
<span
|
||||
aria-label="close"
|
||||
class="anticon anticon-close"
|
||||
role="img"
|
||||
<button
|
||||
aria-label="Close"
|
||||
class="ant-drawer-close"
|
||||
type="button"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="close"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
<span
|
||||
aria-label="close"
|
||||
class="anticon anticon-close"
|
||||
role="img"
|
||||
>
|
||||
<path
|
||||
d="M563.8 512l262.5-312.9c4.4-5.2.7-13.1-6.1-13.1h-79.8c-4.7 0-9.2 2.1-12.3 5.7L511.6 449.8 295.1 191.7c-3-3.6-7.5-5.7-12.3-5.7H203c-6.8 0-10.5 7.9-6.1 13.1L459.4 512 196.9 824.9A7.95 7.95 0 00203 838h79.8c4.7 0 9.2-2.1 12.3-5.7l216.5-258.1 216.5 258.1c3 3.6 7.5 5.7 12.3 5.7h79.8c6.8 0 10.5-7.9 6.1-13.1L563.8 512z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</button>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="close"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M563.8 512l262.5-312.9c4.4-5.2.7-13.1-6.1-13.1h-79.8c-4.7 0-9.2 2.1-12.3 5.7L511.6 449.8 295.1 191.7c-3-3.6-7.5-5.7-12.3-5.7H203c-6.8 0-10.5 7.9-6.1 13.1L459.4 512 196.9 824.9A7.95 7.95 0 00203 838h79.8c4.7 0 9.2-2.1 12.3-5.7l216.5-258.1 216.5 258.1c3 3.6 7.5 5.7 12.3 5.7h79.8c6.8 0 10.5-7.9 6.1-13.1L563.8 512z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-drawer-body"
|
||||
@ -77,7 +80,7 @@ exports[`Drawer closable is false 1`] = `
|
||||
/>
|
||||
<div
|
||||
class="ant-drawer-content-wrapper"
|
||||
style="transform:translateX(100%);-ms-transform:translateX(100%);width:256px"
|
||||
style="transform:translateX(100%);-ms-transform:translateX(100%);width:378px"
|
||||
>
|
||||
<div
|
||||
class="ant-drawer-content"
|
||||
@ -110,7 +113,7 @@ exports[`Drawer destroyOnClose is true 1`] = `
|
||||
/>
|
||||
<div
|
||||
class="ant-drawer-content-wrapper"
|
||||
style="transform:translateX(100%);-ms-transform:translateX(100%);width:256px"
|
||||
style="transform:translateX(100%);-ms-transform:translateX(100%);width:378px"
|
||||
>
|
||||
<div
|
||||
class="ant-drawer-content"
|
||||
@ -120,34 +123,37 @@ exports[`Drawer destroyOnClose is true 1`] = `
|
||||
style="opacity:0;transition:opacity .3s"
|
||||
>
|
||||
<div
|
||||
class="ant-drawer-header-no-title"
|
||||
class="ant-drawer-header ant-drawer-header-close-only"
|
||||
>
|
||||
<button
|
||||
aria-label="Close"
|
||||
class="ant-drawer-close"
|
||||
style="--scroll-bar:0px"
|
||||
type="button"
|
||||
<div
|
||||
class="ant-drawer-header-title"
|
||||
>
|
||||
<span
|
||||
aria-label="close"
|
||||
class="anticon anticon-close"
|
||||
role="img"
|
||||
<button
|
||||
aria-label="Close"
|
||||
class="ant-drawer-close"
|
||||
type="button"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="close"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
<span
|
||||
aria-label="close"
|
||||
class="anticon anticon-close"
|
||||
role="img"
|
||||
>
|
||||
<path
|
||||
d="M563.8 512l262.5-312.9c4.4-5.2.7-13.1-6.1-13.1h-79.8c-4.7 0-9.2 2.1-12.3 5.7L511.6 449.8 295.1 191.7c-3-3.6-7.5-5.7-12.3-5.7H203c-6.8 0-10.5 7.9-6.1 13.1L459.4 512 196.9 824.9A7.95 7.95 0 00203 838h79.8c4.7 0 9.2-2.1 12.3-5.7l216.5-258.1 216.5 258.1c3 3.6 7.5 5.7 12.3 5.7h79.8c6.8 0 10.5-7.9 6.1-13.1L563.8 512z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</button>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="close"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M563.8 512l262.5-312.9c4.4-5.2.7-13.1-6.1-13.1h-79.8c-4.7 0-9.2 2.1-12.3 5.7L511.6 449.8 295.1 191.7c-3-3.6-7.5-5.7-12.3-5.7H203c-6.8 0-10.5 7.9-6.1 13.1L459.4 512 196.9 824.9A7.95 7.95 0 00203 838h79.8c4.7 0 9.2-2.1 12.3-5.7l216.5-258.1 216.5 258.1c3 3.6 7.5 5.7 12.3 5.7h79.8c6.8 0 10.5-7.9 6.1-13.1L563.8 512z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-drawer-body"
|
||||
@ -186,34 +192,37 @@ exports[`Drawer getContainer return undefined 2`] = `
|
||||
class="ant-drawer-wrapper-body"
|
||||
>
|
||||
<div
|
||||
class="ant-drawer-header-no-title"
|
||||
class="ant-drawer-header ant-drawer-header-close-only"
|
||||
>
|
||||
<button
|
||||
aria-label="Close"
|
||||
class="ant-drawer-close"
|
||||
style="--scroll-bar: 0px;"
|
||||
type="button"
|
||||
<div
|
||||
class="ant-drawer-header-title"
|
||||
>
|
||||
<span
|
||||
aria-label="close"
|
||||
class="anticon anticon-close"
|
||||
role="img"
|
||||
<button
|
||||
aria-label="Close"
|
||||
class="ant-drawer-close"
|
||||
type="button"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="close"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
<span
|
||||
aria-label="close"
|
||||
class="anticon anticon-close"
|
||||
role="img"
|
||||
>
|
||||
<path
|
||||
d="M563.8 512l262.5-312.9c4.4-5.2.7-13.1-6.1-13.1h-79.8c-4.7 0-9.2 2.1-12.3 5.7L511.6 449.8 295.1 191.7c-3-3.6-7.5-5.7-12.3-5.7H203c-6.8 0-10.5 7.9-6.1 13.1L459.4 512 196.9 824.9A7.95 7.95 0 00203 838h79.8c4.7 0 9.2-2.1 12.3-5.7l216.5-258.1 216.5 258.1c3 3.6 7.5 5.7 12.3 5.7h79.8c6.8 0 10.5-7.9 6.1-13.1L563.8 512z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</button>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="close"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M563.8 512l262.5-312.9c4.4-5.2.7-13.1-6.1-13.1h-79.8c-4.7 0-9.2 2.1-12.3 5.7L511.6 449.8 295.1 191.7c-3-3.6-7.5-5.7-12.3-5.7H203c-6.8 0-10.5 7.9-6.1 13.1L459.4 512 196.9 824.9A7.95 7.95 0 00203 838h79.8c4.7 0 9.2-2.1 12.3-5.7l216.5-258.1 216.5 258.1c3 3.6 7.5 5.7 12.3 5.7h79.8c6.8 0 10.5-7.9 6.1-13.1L563.8 512z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-drawer-body"
|
||||
@ -241,7 +250,7 @@ exports[`Drawer have a footer 1`] = `
|
||||
/>
|
||||
<div
|
||||
class="ant-drawer-content-wrapper"
|
||||
style="transform:translateX(100%);-ms-transform:translateX(100%);width:256px"
|
||||
style="transform:translateX(100%);-ms-transform:translateX(100%);width:378px"
|
||||
>
|
||||
<div
|
||||
class="ant-drawer-content"
|
||||
@ -250,34 +259,37 @@ exports[`Drawer have a footer 1`] = `
|
||||
class="ant-drawer-wrapper-body"
|
||||
>
|
||||
<div
|
||||
class="ant-drawer-header-no-title"
|
||||
class="ant-drawer-header ant-drawer-header-close-only"
|
||||
>
|
||||
<button
|
||||
aria-label="Close"
|
||||
class="ant-drawer-close"
|
||||
style="--scroll-bar:0px"
|
||||
type="button"
|
||||
<div
|
||||
class="ant-drawer-header-title"
|
||||
>
|
||||
<span
|
||||
aria-label="close"
|
||||
class="anticon anticon-close"
|
||||
role="img"
|
||||
<button
|
||||
aria-label="Close"
|
||||
class="ant-drawer-close"
|
||||
type="button"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="close"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
<span
|
||||
aria-label="close"
|
||||
class="anticon anticon-close"
|
||||
role="img"
|
||||
>
|
||||
<path
|
||||
d="M563.8 512l262.5-312.9c4.4-5.2.7-13.1-6.1-13.1h-79.8c-4.7 0-9.2 2.1-12.3 5.7L511.6 449.8 295.1 191.7c-3-3.6-7.5-5.7-12.3-5.7H203c-6.8 0-10.5 7.9-6.1 13.1L459.4 512 196.9 824.9A7.95 7.95 0 00203 838h79.8c4.7 0 9.2-2.1 12.3-5.7l216.5-258.1 216.5 258.1c3 3.6 7.5 5.7 12.3 5.7h79.8c6.8 0 10.5-7.9 6.1-13.1L563.8 512z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</button>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="close"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M563.8 512l262.5-312.9c4.4-5.2.7-13.1-6.1-13.1h-79.8c-4.7 0-9.2 2.1-12.3 5.7L511.6 449.8 295.1 191.7c-3-3.6-7.5-5.7-12.3-5.7H203c-6.8 0-10.5 7.9-6.1 13.1L459.4 512 196.9 824.9A7.95 7.95 0 00203 838h79.8c4.7 0 9.2-2.1 12.3-5.7l216.5-258.1 216.5 258.1c3 3.6 7.5 5.7 12.3 5.7h79.8c6.8 0 10.5-7.9 6.1-13.1L563.8 512z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-drawer-body"
|
||||
@ -309,7 +321,7 @@ exports[`Drawer have a title 1`] = `
|
||||
/>
|
||||
<div
|
||||
class="ant-drawer-content-wrapper"
|
||||
style="transform:translateX(100%);-ms-transform:translateX(100%);width:256px"
|
||||
style="transform:translateX(100%);-ms-transform:translateX(100%);width:378px"
|
||||
>
|
||||
<div
|
||||
class="ant-drawer-content"
|
||||
@ -321,36 +333,39 @@ exports[`Drawer have a title 1`] = `
|
||||
class="ant-drawer-header"
|
||||
>
|
||||
<div
|
||||
class="ant-drawer-title"
|
||||
class="ant-drawer-header-title"
|
||||
>
|
||||
Test Title
|
||||
</div>
|
||||
<button
|
||||
aria-label="Close"
|
||||
class="ant-drawer-close"
|
||||
style="--scroll-bar:0px"
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="close"
|
||||
class="anticon anticon-close"
|
||||
role="img"
|
||||
<button
|
||||
aria-label="Close"
|
||||
class="ant-drawer-close"
|
||||
type="button"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="close"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
<span
|
||||
aria-label="close"
|
||||
class="anticon anticon-close"
|
||||
role="img"
|
||||
>
|
||||
<path
|
||||
d="M563.8 512l262.5-312.9c4.4-5.2.7-13.1-6.1-13.1h-79.8c-4.7 0-9.2 2.1-12.3 5.7L511.6 449.8 295.1 191.7c-3-3.6-7.5-5.7-12.3-5.7H203c-6.8 0-10.5 7.9-6.1 13.1L459.4 512 196.9 824.9A7.95 7.95 0 00203 838h79.8c4.7 0 9.2-2.1 12.3-5.7l216.5-258.1 216.5 258.1c3 3.6 7.5 5.7 12.3 5.7h79.8c6.8 0 10.5-7.9 6.1-13.1L563.8 512z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</button>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="close"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M563.8 512l262.5-312.9c4.4-5.2.7-13.1-6.1-13.1h-79.8c-4.7 0-9.2 2.1-12.3 5.7L511.6 449.8 295.1 191.7c-3-3.6-7.5-5.7-12.3-5.7H203c-6.8 0-10.5 7.9-6.1 13.1L459.4 512 196.9 824.9A7.95 7.95 0 00203 838h79.8c4.7 0 9.2-2.1 12.3-5.7l216.5-258.1 216.5 258.1c3 3.6 7.5 5.7 12.3 5.7h79.8c6.8 0 10.5-7.9 6.1-13.1L563.8 512z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</button>
|
||||
<div
|
||||
class="ant-drawer-title"
|
||||
>
|
||||
Test Title
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-drawer-body"
|
||||
@ -386,34 +401,37 @@ exports[`Drawer render correctly 1`] = `
|
||||
class="ant-drawer-wrapper-body"
|
||||
>
|
||||
<div
|
||||
class="ant-drawer-header-no-title"
|
||||
class="ant-drawer-header ant-drawer-header-close-only"
|
||||
>
|
||||
<button
|
||||
aria-label="Close"
|
||||
class="ant-drawer-close"
|
||||
style="--scroll-bar:0px"
|
||||
type="button"
|
||||
<div
|
||||
class="ant-drawer-header-title"
|
||||
>
|
||||
<span
|
||||
aria-label="close"
|
||||
class="anticon anticon-close"
|
||||
role="img"
|
||||
<button
|
||||
aria-label="Close"
|
||||
class="ant-drawer-close"
|
||||
type="button"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="close"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
<span
|
||||
aria-label="close"
|
||||
class="anticon anticon-close"
|
||||
role="img"
|
||||
>
|
||||
<path
|
||||
d="M563.8 512l262.5-312.9c4.4-5.2.7-13.1-6.1-13.1h-79.8c-4.7 0-9.2 2.1-12.3 5.7L511.6 449.8 295.1 191.7c-3-3.6-7.5-5.7-12.3-5.7H203c-6.8 0-10.5 7.9-6.1 13.1L459.4 512 196.9 824.9A7.95 7.95 0 00203 838h79.8c4.7 0 9.2-2.1 12.3-5.7l216.5-258.1 216.5 258.1c3 3.6 7.5 5.7 12.3 5.7h79.8c6.8 0 10.5-7.9 6.1-13.1L563.8 512z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</button>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="close"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M563.8 512l262.5-312.9c4.4-5.2.7-13.1-6.1-13.1h-79.8c-4.7 0-9.2 2.1-12.3 5.7L511.6 449.8 295.1 191.7c-3-3.6-7.5-5.7-12.3-5.7H203c-6.8 0-10.5 7.9-6.1 13.1L459.4 512 196.9 824.9A7.95 7.95 0 00203 838h79.8c4.7 0 9.2-2.1 12.3-5.7l216.5-258.1 216.5 258.1c3 3.6 7.5 5.7 12.3 5.7h79.8c6.8 0 10.5-7.9 6.1-13.1L563.8 512z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-drawer-body"
|
||||
@ -449,34 +467,37 @@ exports[`Drawer render top drawer 1`] = `
|
||||
class="ant-drawer-wrapper-body"
|
||||
>
|
||||
<div
|
||||
class="ant-drawer-header-no-title"
|
||||
class="ant-drawer-header ant-drawer-header-close-only"
|
||||
>
|
||||
<button
|
||||
aria-label="Close"
|
||||
class="ant-drawer-close"
|
||||
style="--scroll-bar:0px"
|
||||
type="button"
|
||||
<div
|
||||
class="ant-drawer-header-title"
|
||||
>
|
||||
<span
|
||||
aria-label="close"
|
||||
class="anticon anticon-close"
|
||||
role="img"
|
||||
<button
|
||||
aria-label="Close"
|
||||
class="ant-drawer-close"
|
||||
type="button"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="close"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
<span
|
||||
aria-label="close"
|
||||
class="anticon anticon-close"
|
||||
role="img"
|
||||
>
|
||||
<path
|
||||
d="M563.8 512l262.5-312.9c4.4-5.2.7-13.1-6.1-13.1h-79.8c-4.7 0-9.2 2.1-12.3 5.7L511.6 449.8 295.1 191.7c-3-3.6-7.5-5.7-12.3-5.7H203c-6.8 0-10.5 7.9-6.1 13.1L459.4 512 196.9 824.9A7.95 7.95 0 00203 838h79.8c4.7 0 9.2-2.1 12.3-5.7l216.5-258.1 216.5 258.1c3 3.6 7.5 5.7 12.3 5.7h79.8c6.8 0 10.5-7.9 6.1-13.1L563.8 512z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</button>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="close"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M563.8 512l262.5-312.9c4.4-5.2.7-13.1-6.1-13.1h-79.8c-4.7 0-9.2 2.1-12.3 5.7L511.6 449.8 295.1 191.7c-3-3.6-7.5-5.7-12.3-5.7H203c-6.8 0-10.5 7.9-6.1 13.1L459.4 512 196.9 824.9A7.95 7.95 0 00203 838h79.8c4.7 0 9.2-2.1 12.3-5.7l216.5-258.1 216.5 258.1c3 3.6 7.5 5.7 12.3 5.7h79.8c6.8 0 10.5-7.9 6.1-13.1L563.8 512z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-drawer-body"
|
||||
@ -506,7 +527,7 @@ exports[`Drawer style/drawerStyle/headerStyle/bodyStyle should work 1`] = `
|
||||
/>
|
||||
<div
|
||||
class="ant-drawer-content-wrapper"
|
||||
style="transform:translateX(100%);-ms-transform:translateX(100%);width:256px"
|
||||
style="transform:translateX(100%);-ms-transform:translateX(100%);width:378px"
|
||||
>
|
||||
<div
|
||||
class="ant-drawer-content"
|
||||
@ -516,35 +537,38 @@ exports[`Drawer style/drawerStyle/headerStyle/bodyStyle should work 1`] = `
|
||||
style="background-color:#08c"
|
||||
>
|
||||
<div
|
||||
class="ant-drawer-header-no-title"
|
||||
class="ant-drawer-header ant-drawer-header-close-only"
|
||||
style="background-color:#08c"
|
||||
>
|
||||
<button
|
||||
aria-label="Close"
|
||||
class="ant-drawer-close"
|
||||
style="--scroll-bar:0px"
|
||||
type="button"
|
||||
<div
|
||||
class="ant-drawer-header-title"
|
||||
>
|
||||
<span
|
||||
aria-label="close"
|
||||
class="anticon anticon-close"
|
||||
role="img"
|
||||
<button
|
||||
aria-label="Close"
|
||||
class="ant-drawer-close"
|
||||
type="button"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="close"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
<span
|
||||
aria-label="close"
|
||||
class="anticon anticon-close"
|
||||
role="img"
|
||||
>
|
||||
<path
|
||||
d="M563.8 512l262.5-312.9c4.4-5.2.7-13.1-6.1-13.1h-79.8c-4.7 0-9.2 2.1-12.3 5.7L511.6 449.8 295.1 191.7c-3-3.6-7.5-5.7-12.3-5.7H203c-6.8 0-10.5 7.9-6.1 13.1L459.4 512 196.9 824.9A7.95 7.95 0 00203 838h79.8c4.7 0 9.2-2.1 12.3-5.7l216.5-258.1 216.5 258.1c3 3.6 7.5 5.7 12.3 5.7h79.8c6.8 0 10.5-7.9 6.1-13.1L563.8 512z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</button>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="close"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M563.8 512l262.5-312.9c4.4-5.2.7-13.1-6.1-13.1h-79.8c-4.7 0-9.2 2.1-12.3 5.7L511.6 449.8 295.1 191.7c-3-3.6-7.5-5.7-12.3-5.7H203c-6.8 0-10.5 7.9-6.1 13.1L459.4 512 196.9 824.9A7.95 7.95 0 00203 838h79.8c4.7 0 9.2-2.1 12.3-5.7l216.5-258.1 216.5 258.1c3 3.6 7.5 5.7 12.3 5.7h79.8c6.8 0 10.5-7.9 6.1-13.1L563.8 512z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-drawer-body"
|
||||
@ -581,18 +605,21 @@ exports[`Drawer support closeIcon 1`] = `
|
||||
class="ant-drawer-wrapper-body"
|
||||
>
|
||||
<div
|
||||
class="ant-drawer-header-no-title"
|
||||
class="ant-drawer-header ant-drawer-header-close-only"
|
||||
>
|
||||
<button
|
||||
aria-label="Close"
|
||||
class="ant-drawer-close"
|
||||
style="--scroll-bar:0px"
|
||||
type="button"
|
||||
<div
|
||||
class="ant-drawer-header-title"
|
||||
>
|
||||
<span>
|
||||
close
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
aria-label="Close"
|
||||
class="ant-drawer-close"
|
||||
type="button"
|
||||
>
|
||||
<span>
|
||||
close
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-drawer-body"
|
||||
|
@ -22,7 +22,7 @@ exports[`Drawer render correctly 1`] = `
|
||||
/>
|
||||
<div
|
||||
class="ant-drawer-content-wrapper"
|
||||
style="width: 256px;"
|
||||
style="width: 378px;"
|
||||
>
|
||||
<div
|
||||
class="ant-drawer-content"
|
||||
@ -31,34 +31,37 @@ exports[`Drawer render correctly 1`] = `
|
||||
class="ant-drawer-wrapper-body"
|
||||
>
|
||||
<div
|
||||
class="ant-drawer-header-no-title"
|
||||
class="ant-drawer-header ant-drawer-header-close-only"
|
||||
>
|
||||
<button
|
||||
aria-label="Close"
|
||||
class="ant-drawer-close"
|
||||
style="--scroll-bar: 0px;"
|
||||
type="button"
|
||||
<div
|
||||
class="ant-drawer-header-title"
|
||||
>
|
||||
<span
|
||||
aria-label="close"
|
||||
class="anticon anticon-close"
|
||||
role="img"
|
||||
<button
|
||||
aria-label="Close"
|
||||
class="ant-drawer-close"
|
||||
type="button"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="close"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
<span
|
||||
aria-label="close"
|
||||
class="anticon anticon-close"
|
||||
role="img"
|
||||
>
|
||||
<path
|
||||
d="M563.8 512l262.5-312.9c4.4-5.2.7-13.1-6.1-13.1h-79.8c-4.7 0-9.2 2.1-12.3 5.7L511.6 449.8 295.1 191.7c-3-3.6-7.5-5.7-12.3-5.7H203c-6.8 0-10.5 7.9-6.1 13.1L459.4 512 196.9 824.9A7.95 7.95 0 00203 838h79.8c4.7 0 9.2-2.1 12.3-5.7l216.5-258.1 216.5 258.1c3 3.6 7.5 5.7 12.3 5.7h79.8c6.8 0 10.5-7.9 6.1-13.1L563.8 512z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</button>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="close"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M563.8 512l262.5-312.9c4.4-5.2.7-13.1-6.1-13.1h-79.8c-4.7 0-9.2 2.1-12.3 5.7L511.6 449.8 295.1 191.7c-3-3.6-7.5-5.7-12.3-5.7H203c-6.8 0-10.5 7.9-6.1 13.1L459.4 512 196.9 824.9A7.95 7.95 0 00203 838h79.8c4.7 0 9.2-2.1 12.3-5.7l216.5-258.1 216.5 258.1c3 3.6 7.5 5.7 12.3 5.7h79.8c6.8 0 10.5-7.9 6.1-13.1L563.8 512z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-drawer-body"
|
||||
|
@ -26,6 +26,111 @@ exports[`renders ./components/drawer/demo/config-provider.md correctly 1`] = `
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/drawer/demo/extra.md correctly 1`] = `
|
||||
<div
|
||||
class="ant-space ant-space-horizontal ant-space-align-center"
|
||||
>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-right:8px"
|
||||
>
|
||||
<div
|
||||
class="ant-radio-group ant-radio-group-outline"
|
||||
>
|
||||
<label
|
||||
class="ant-radio-wrapper"
|
||||
>
|
||||
<span
|
||||
class="ant-radio"
|
||||
>
|
||||
<input
|
||||
class="ant-radio-input"
|
||||
type="radio"
|
||||
value="top"
|
||||
/>
|
||||
<span
|
||||
class="ant-radio-inner"
|
||||
/>
|
||||
</span>
|
||||
<span>
|
||||
top
|
||||
</span>
|
||||
</label>
|
||||
<label
|
||||
class="ant-radio-wrapper ant-radio-wrapper-checked"
|
||||
>
|
||||
<span
|
||||
class="ant-radio ant-radio-checked"
|
||||
>
|
||||
<input
|
||||
checked=""
|
||||
class="ant-radio-input"
|
||||
type="radio"
|
||||
value="right"
|
||||
/>
|
||||
<span
|
||||
class="ant-radio-inner"
|
||||
/>
|
||||
</span>
|
||||
<span>
|
||||
right
|
||||
</span>
|
||||
</label>
|
||||
<label
|
||||
class="ant-radio-wrapper"
|
||||
>
|
||||
<span
|
||||
class="ant-radio"
|
||||
>
|
||||
<input
|
||||
class="ant-radio-input"
|
||||
type="radio"
|
||||
value="bottom"
|
||||
/>
|
||||
<span
|
||||
class="ant-radio-inner"
|
||||
/>
|
||||
</span>
|
||||
<span>
|
||||
bottom
|
||||
</span>
|
||||
</label>
|
||||
<label
|
||||
class="ant-radio-wrapper"
|
||||
>
|
||||
<span
|
||||
class="ant-radio"
|
||||
>
|
||||
<input
|
||||
class="ant-radio-input"
|
||||
type="radio"
|
||||
value="left"
|
||||
/>
|
||||
<span
|
||||
class="ant-radio-inner"
|
||||
/>
|
||||
</span>
|
||||
<span>
|
||||
left
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
>
|
||||
<button
|
||||
class="ant-btn ant-btn-primary"
|
||||
type="button"
|
||||
>
|
||||
<span>
|
||||
Open
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/drawer/demo/form-in-drawer.md correctly 1`] = `
|
||||
<button
|
||||
class="ant-btn ant-btn-primary"
|
||||
@ -55,7 +160,7 @@ exports[`renders ./components/drawer/demo/form-in-drawer.md correctly 1`] = `
|
||||
</svg>
|
||||
</span>
|
||||
<span>
|
||||
New account
|
||||
New account
|
||||
</span>
|
||||
</button>
|
||||
`;
|
||||
@ -217,7 +322,7 @@ exports[`renders ./components/drawer/demo/render-in-current.md correctly 1`] = `
|
||||
/>
|
||||
<div
|
||||
class="ant-drawer-content-wrapper"
|
||||
style="transform:translateX(100%);-ms-transform:translateX(100%);width:256px"
|
||||
style="transform:translateX(100%);-ms-transform:translateX(100%);width:378px"
|
||||
>
|
||||
<div
|
||||
class="ant-drawer-content"
|
||||
@ -229,9 +334,13 @@ exports[`renders ./components/drawer/demo/render-in-current.md correctly 1`] = `
|
||||
class="ant-drawer-header"
|
||||
>
|
||||
<div
|
||||
class="ant-drawer-title"
|
||||
class="ant-drawer-header-title"
|
||||
>
|
||||
Basic Drawer
|
||||
<div
|
||||
class="ant-drawer-title"
|
||||
>
|
||||
Basic Drawer
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
@ -249,6 +358,38 @@ exports[`renders ./components/drawer/demo/render-in-current.md correctly 1`] = `
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/drawer/demo/size.md correctly 1`] = `
|
||||
<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 Default Size (378px)
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
>
|
||||
<button
|
||||
class="ant-btn ant-btn-primary"
|
||||
type="button"
|
||||
>
|
||||
<span>
|
||||
Open Large Size (736px)
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/drawer/demo/user-profile.md correctly 1`] = `
|
||||
<div
|
||||
class="ant-list ant-list-split ant-list-bordered"
|
||||
|
@ -7,7 +7,7 @@ title:
|
||||
|
||||
## zh-CN
|
||||
|
||||
基础抽屉,点击触发按钮抽屉从右滑出,点击遮罩区关闭
|
||||
基础抽屉,点击触发按钮抽屉从右滑出,点击遮罩区关闭。
|
||||
|
||||
## en-US
|
||||
|
||||
@ -30,13 +30,7 @@ const App: React.FC = () => {
|
||||
<Button type="primary" onClick={showDrawer}>
|
||||
Open
|
||||
</Button>
|
||||
<Drawer
|
||||
title="Basic Drawer"
|
||||
placement="right"
|
||||
closable={false}
|
||||
onClose={onClose}
|
||||
visible={visible}
|
||||
>
|
||||
<Drawer title="Basic Drawer" placement="right" onClose={onClose} visible={visible}>
|
||||
<p>Some contents...</p>
|
||||
<p>Some contents...</p>
|
||||
<p>Some contents...</p>
|
||||
|
71
components/drawer/demo/extra.md
Normal file
71
components/drawer/demo/extra.md
Normal file
@ -0,0 +1,71 @@
|
||||
---
|
||||
order: 1.1
|
||||
title:
|
||||
zh-CN: 额外操作
|
||||
en-US: Extra Actions
|
||||
---
|
||||
|
||||
## zh-CN
|
||||
|
||||
在 Ant Design 规范中,操作按钮建议放在抽屉的右上角,可以使用 `extra` 属性来实现。
|
||||
|
||||
## en-US
|
||||
|
||||
Extra actions should be placed at corner of drawer in Ant Design, you can using `extra` prop for that.
|
||||
|
||||
```tsx
|
||||
import React, { useState } from 'react';
|
||||
import { Drawer, Button, Space, Radio } from 'antd';
|
||||
import { DrawerProps } from 'antd/es/drawer';
|
||||
import { RadioChangeEvent } from 'antd/es/radio';
|
||||
|
||||
const App: React.FC = () => {
|
||||
const [visible, setVisible] = useState(false);
|
||||
const [placement, setPlacement] = useState<DrawerProps['placement']>('right');
|
||||
const showDrawer = () => {
|
||||
setVisible(true);
|
||||
};
|
||||
const onChange = (e: RadioChangeEvent) => {
|
||||
setPlacement(e.target.value);
|
||||
};
|
||||
const onClose = () => {
|
||||
setVisible(false);
|
||||
};
|
||||
return (
|
||||
<>
|
||||
<Space>
|
||||
<Radio.Group value={placement} onChange={onChange}>
|
||||
<Radio value="top">top</Radio>
|
||||
<Radio value="right">right</Radio>
|
||||
<Radio value="bottom">bottom</Radio>
|
||||
<Radio value="left">left</Radio>
|
||||
</Radio.Group>
|
||||
<Button type="primary" onClick={showDrawer}>
|
||||
Open
|
||||
</Button>
|
||||
</Space>
|
||||
<Drawer
|
||||
title="Drawer with extra actions"
|
||||
placement={placement}
|
||||
width={500}
|
||||
onClose={onClose}
|
||||
visible={visible}
|
||||
extra={
|
||||
<Space>
|
||||
<Button onClick={onClose}>Cancel</Button>
|
||||
<Button type="primary" onClick={onClose}>
|
||||
OK
|
||||
</Button>
|
||||
</Space>
|
||||
}
|
||||
>
|
||||
<p>Some contents...</p>
|
||||
<p>Some contents...</p>
|
||||
<p>Some contents...</p>
|
||||
</Drawer>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
ReactDOM.render(<App />, mountNode);
|
||||
```
|
@ -14,7 +14,7 @@ title:
|
||||
Use a form in Drawer with a submit button.
|
||||
|
||||
```jsx
|
||||
import { Drawer, Form, Button, Col, Row, Input, Select, DatePicker } from 'antd';
|
||||
import { Drawer, Form, Button, Col, Row, Input, Select, DatePicker, Space } from 'antd';
|
||||
import { PlusOutlined } from '@ant-design/icons';
|
||||
|
||||
const { Option } = Select;
|
||||
@ -37,8 +37,8 @@ class DrawerForm extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<>
|
||||
<Button type="primary" onClick={this.showDrawer}>
|
||||
<PlusOutlined /> New account
|
||||
<Button type="primary" onClick={this.showDrawer} icon={<PlusOutlined />}>
|
||||
New account
|
||||
</Button>
|
||||
<Drawer
|
||||
title="Create a new account"
|
||||
@ -46,19 +46,13 @@ class DrawerForm extends React.Component {
|
||||
onClose={this.onClose}
|
||||
visible={this.state.visible}
|
||||
bodyStyle={{ paddingBottom: 80 }}
|
||||
footer={
|
||||
<div
|
||||
style={{
|
||||
textAlign: 'right',
|
||||
}}
|
||||
>
|
||||
<Button onClick={this.onClose} style={{ marginRight: 8 }}>
|
||||
Cancel
|
||||
</Button>
|
||||
extra={
|
||||
<Space>
|
||||
<Button onClick={this.onClose}>Cancel</Button>
|
||||
<Button onClick={this.onClose} type="primary">
|
||||
Submit
|
||||
</Button>
|
||||
</div>
|
||||
</Space>
|
||||
}
|
||||
>
|
||||
<Form layout="vertical" hideRequiredMark>
|
||||
|
@ -7,7 +7,7 @@ title:
|
||||
|
||||
## zh-CN
|
||||
|
||||
自定义位置,点击触发按钮抽屉从相应的位置滑出,点击遮罩区关闭
|
||||
自定义位置,点击触发按钮抽屉从相应的位置滑出,点击遮罩区关闭。
|
||||
|
||||
## en-US
|
||||
|
||||
@ -42,7 +42,7 @@ class App extends React.Component {
|
||||
return (
|
||||
<>
|
||||
<Space>
|
||||
<Radio.Group defaultValue={placement} onChange={this.onChange}>
|
||||
<Radio.Group value={placement} onChange={this.onChange}>
|
||||
<Radio value="top">top</Radio>
|
||||
<Radio value="right">right</Radio>
|
||||
<Radio value="bottom">bottom</Radio>
|
||||
|
@ -7,11 +7,11 @@ title:
|
||||
|
||||
## zh-CN
|
||||
|
||||
渲染在当前 dom 里。自定义容器,查看 getContainer。
|
||||
渲染在当前 dom 里。自定义容器,查看 `getContainer`。
|
||||
|
||||
## en-US
|
||||
|
||||
Render in current dom. custom container, check getContainer.
|
||||
Render in current dom. custom container, check `getContainer`.
|
||||
|
||||
```jsx
|
||||
import { Drawer, Button } from 'antd';
|
||||
|
69
components/drawer/demo/size.md
Normal file
69
components/drawer/demo/size.md
Normal file
@ -0,0 +1,69 @@
|
||||
---
|
||||
order: 10
|
||||
title:
|
||||
zh-CN: 预设宽度
|
||||
en-US: Presetted size
|
||||
---
|
||||
|
||||
## zh-CN
|
||||
|
||||
抽屉的默认宽度为 `378px`,另外还提供一个大号抽屉 `736px`,可以用 `size` 属性来设置。
|
||||
|
||||
## en-US
|
||||
|
||||
The default width (or height) of Drawer is `378px`, and there is a presetted large size `736px`.
|
||||
|
||||
```tsx
|
||||
import React, { useState } from 'react';
|
||||
import { Drawer, Button, Space } from 'antd';
|
||||
import { DrawerProps } from 'antd/es/drawer';
|
||||
|
||||
const App: React.FC = () => {
|
||||
const [visible, setVisible] = useState(false);
|
||||
const [size, setSize] = useState<DrawerProps['size']>();
|
||||
const showDefaultDrawer = () => {
|
||||
setSize('default');
|
||||
setVisible(true);
|
||||
};
|
||||
const showLargeDrawer = () => {
|
||||
setSize('large');
|
||||
setVisible(true);
|
||||
};
|
||||
const onClose = () => {
|
||||
setVisible(false);
|
||||
};
|
||||
return (
|
||||
<>
|
||||
<Space>
|
||||
<Button type="primary" onClick={showDefaultDrawer}>
|
||||
Open Default Size (378px)
|
||||
</Button>
|
||||
<Button type="primary" onClick={showLargeDrawer}>
|
||||
Open Large Size (736px)
|
||||
</Button>
|
||||
</Space>
|
||||
<Drawer
|
||||
title={`${size} Drawer`}
|
||||
placement="right"
|
||||
size={size}
|
||||
onClose={onClose}
|
||||
visible={visible}
|
||||
extra={
|
||||
<Space>
|
||||
<Button onClick={onClose}>Cancel</Button>
|
||||
<Button type="primary" onClick={onClose}>
|
||||
OK
|
||||
</Button>
|
||||
</Space>
|
||||
}
|
||||
>
|
||||
<p>Some contents...</p>
|
||||
<p>Some contents...</p>
|
||||
<p>Some contents...</p>
|
||||
</Drawer>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
ReactDOM.render(<App />, mountNode);
|
||||
```
|
@ -28,6 +28,7 @@ A Drawer is a panel that is typically overlaid on top of a page and slides in fr
|
||||
| contentWrapperStyle | Style of the drawer wrapper of content part | CSSProperties | - | |
|
||||
| destroyOnClose | Whether to unmount child components on closing drawer or not | boolean | false | |
|
||||
| drawerStyle | Style of the popup layer element | object | - | |
|
||||
| extra | Extra actions area at corner | ReactNode | - | 4.17.0 |
|
||||
| footer | The footer for Drawer | ReactNode | - | |
|
||||
| footerStyle | Style of the drawer footer part | CSSProperties | - | |
|
||||
| forceRender | Prerender Drawer component forcely | boolean | false | |
|
||||
@ -41,8 +42,9 @@ A Drawer is a panel that is typically overlaid on top of a page and slides in fr
|
||||
| placement | The placement of the Drawer | `top` \| `right` \| `bottom` \| `left` | `right` | |
|
||||
| push | Nested drawers push behavior | boolean \| { distance: string \| number } | { distance: 180 } | 4.5.0+ |
|
||||
| style | Style of wrapper element which **contains mask** compare to `drawerStyle` | CSSProperties | - | |
|
||||
| size | presetted size of drawer, default `378px` and large `736px` | 'default' \| 'large' | 'default' | 4.17.0 |
|
||||
| title | The title for Drawer | ReactNode | - | |
|
||||
| visible | Whether the Drawer dialog is visible or not | boolean | false | |
|
||||
| width | Width of the Drawer dialog | string \| number | 256 | |
|
||||
| width | Width of the Drawer dialog | string \| number | 378 | |
|
||||
| zIndex | The `z-index` of the Drawer | number | 1000 | |
|
||||
| onClose | Specify a callback that will be called when a user clicks mask, close button or Cancel button | function(e) | - | |
|
||||
|
@ -1,6 +1,5 @@
|
||||
import * as React from 'react';
|
||||
import RcDrawer from 'rc-drawer';
|
||||
import getScrollBarSize from 'rc-util/lib/getScrollBarSize';
|
||||
import CloseOutlined from '@ant-design/icons/CloseOutlined';
|
||||
import classNames from 'classnames';
|
||||
import { ConfigContext, DirectionType } from '../config-provider';
|
||||
@ -23,6 +22,9 @@ type getContainerFunc = () => HTMLElement;
|
||||
const PlacementTypes = tuple('top', 'right', 'bottom', 'left');
|
||||
type placementType = typeof PlacementTypes[number];
|
||||
|
||||
const SizeTypes = tuple('default', 'large');
|
||||
type sizeType = typeof SizeTypes[number];
|
||||
|
||||
export interface PushState {
|
||||
distance: string | number;
|
||||
}
|
||||
@ -36,6 +38,7 @@ export interface DrawerProps {
|
||||
mask?: boolean;
|
||||
maskStyle?: React.CSSProperties;
|
||||
style?: React.CSSProperties;
|
||||
size?: sizeType;
|
||||
/** Wrapper dom node style of header and body */
|
||||
drawerStyle?: React.CSSProperties;
|
||||
headerStyle?: React.CSSProperties;
|
||||
@ -54,6 +57,7 @@ export interface DrawerProps {
|
||||
className?: string;
|
||||
handler?: React.ReactNode;
|
||||
keyboard?: boolean;
|
||||
extra?: React.ReactNode;
|
||||
footer?: React.ReactNode;
|
||||
footerStyle?: React.CSSProperties;
|
||||
level?: string | string[] | null | undefined;
|
||||
@ -72,8 +76,9 @@ const defaultPushState: PushState = { distance: 180 };
|
||||
const Drawer = React.forwardRef<DrawerRef, InternalDrawerProps>(
|
||||
(
|
||||
{
|
||||
width = 256,
|
||||
height = 256,
|
||||
width,
|
||||
height,
|
||||
size = 'default',
|
||||
closable = true,
|
||||
placement = 'right' as placementType,
|
||||
maskClosable = true,
|
||||
@ -97,6 +102,7 @@ const Drawer = React.forwardRef<DrawerRef, InternalDrawerProps>(
|
||||
onClose,
|
||||
footer,
|
||||
footerStyle,
|
||||
extra,
|
||||
...rest
|
||||
},
|
||||
ref,
|
||||
@ -168,9 +174,11 @@ const Drawer = React.forwardRef<DrawerRef, InternalDrawerProps>(
|
||||
}
|
||||
const offsetStyle: any = {};
|
||||
if (placement === 'left' || placement === 'right') {
|
||||
offsetStyle.width = width;
|
||||
const defaultWidth = size === 'large' ? 736 : 378;
|
||||
offsetStyle.width = typeof width === 'undefined' ? defaultWidth : width;
|
||||
} else {
|
||||
offsetStyle.height = height;
|
||||
const defaultHeight = size === 'large' ? 736 : 378;
|
||||
offsetStyle.height = typeof height === 'undefined' ? defaultHeight : height;
|
||||
}
|
||||
return offsetStyle;
|
||||
};
|
||||
@ -205,36 +213,29 @@ const Drawer = React.forwardRef<DrawerRef, InternalDrawerProps>(
|
||||
};
|
||||
};
|
||||
|
||||
function renderCloseIcon() {
|
||||
return (
|
||||
closable && (
|
||||
<button
|
||||
type="button"
|
||||
onClick={onClose}
|
||||
aria-label="Close"
|
||||
className={`${prefixCls}-close`}
|
||||
style={
|
||||
{
|
||||
'--scroll-bar': `${getScrollBarSize()}px`,
|
||||
} as any
|
||||
}
|
||||
>
|
||||
{closeIcon}
|
||||
</button>
|
||||
)
|
||||
);
|
||||
}
|
||||
const closeIconNode = closable && (
|
||||
<button type="button" onClick={onClose} aria-label="Close" className={`${prefixCls}-close`}>
|
||||
{closeIcon}
|
||||
</button>
|
||||
);
|
||||
|
||||
function renderHeader() {
|
||||
if (!title && !closable) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const headerClassName = title ? `${prefixCls}-header` : `${prefixCls}-header-no-title`;
|
||||
return (
|
||||
<div className={headerClassName} style={headerStyle}>
|
||||
{title && <div className={`${prefixCls}-title`}>{title}</div>}
|
||||
{closable && renderCloseIcon()}
|
||||
<div
|
||||
className={classNames(`${prefixCls}-header`, {
|
||||
[`${prefixCls}-header-close-only`]: closable && !title && !extra,
|
||||
})}
|
||||
style={headerStyle}
|
||||
>
|
||||
<div className={`${prefixCls}-header-title`}>
|
||||
{closeIconNode}
|
||||
{title && <div className={`${prefixCls}-title`}>{title}</div>}
|
||||
</div>
|
||||
{extra && <div className={`${prefixCls}-extra`}>{extra}</div>}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -27,6 +27,7 @@ cover: https://gw.alipayobjects.com/zos/alicdn/7z8NJQhFb/Drawer.svg
|
||||
| contentWrapperStyle | 可用于设置 Drawer 包裹内容部分的样式 | CSSProperties | - | |
|
||||
| destroyOnClose | 关闭时销毁 Drawer 里的子元素 | boolean | false | |
|
||||
| drawerStyle | 用于设置 Drawer 弹出层的样式 | CSSProperties | - | |
|
||||
| extra | 抽屉右上角的操作区域 | ReactNode | - | 4.17.0 |
|
||||
| footer | 抽屉的页脚 | ReactNode | - | |
|
||||
| footerStyle | 抽屉页脚部件的样式 | CSSProperties | - | |
|
||||
| forceRender | 预渲染 Drawer 内元素 | boolean | false | |
|
||||
@ -39,9 +40,10 @@ cover: https://gw.alipayobjects.com/zos/alicdn/7z8NJQhFb/Drawer.svg
|
||||
| maskStyle | 遮罩样式 | CSSProperties | {} | |
|
||||
| placement | 抽屉的方向 | `top` \| `right` \| `bottom` \| `left` | `right` | |
|
||||
| push | 用于设置多层 Drawer 的推动行为 | boolean \| { distance: string \| number } | { distance: 180 } | 4.5.0+ |
|
||||
| size | 预设抽屉宽度(或高度),default `378px` 和 large `736px` | 'default' \| 'large' | 'default' | 4.17.0 |
|
||||
| style | 可用于设置 Drawer 最外层容器的样式,和 `drawerStyle` 的区别是作用节点包括 `mask` | CSSProperties | - | |
|
||||
| title | 标题 | ReactNode | - | |
|
||||
| visible | Drawer 是否可见 | boolean | - | |
|
||||
| width | 宽度 | string \| number | 256 | |
|
||||
| width | 宽度 | string \| number | 378 | |
|
||||
| zIndex | 设置 Drawer 的 `z-index` | number | 1000 | |
|
||||
| onClose | 点击遮罩层或右上角叉或取消按钮的回调 | function(e) | - | |
|
||||
|
@ -148,12 +148,8 @@
|
||||
}
|
||||
|
||||
&-close {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
z-index: @zindex-popup-close;
|
||||
display: block;
|
||||
padding: @drawer-header-close-padding;
|
||||
display: inline-block;
|
||||
margin-right: 12px;
|
||||
color: @modal-close-color;
|
||||
font-weight: 700;
|
||||
font-size: @font-size-lg;
|
||||
@ -174,26 +170,29 @@
|
||||
color: @icon-color-hover;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.@{drawer-prefix-cls}-header-no-title & {
|
||||
margin-right: var(--scroll-bar);
|
||||
/* stylelint-disable-next-line function-calc-no-invalid */
|
||||
padding-right: ~'calc(@{drawer-header-close-padding} - var(--scroll-bar))';
|
||||
}
|
||||
}
|
||||
|
||||
&-header {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: @drawer-header-padding;
|
||||
color: @text-color;
|
||||
background: @drawer-bg;
|
||||
border-bottom: @border-width-base @border-style-base @border-color-split;
|
||||
border-radius: @border-radius-base @border-radius-base 0 0;
|
||||
}
|
||||
|
||||
&-header-no-title {
|
||||
color: @text-color;
|
||||
background: @drawer-bg;
|
||||
&-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
&-close-only {
|
||||
padding-bottom: 0;
|
||||
border: none;
|
||||
}
|
||||
}
|
||||
|
||||
&-wrapper-body {
|
||||
|
@ -9,8 +9,8 @@
|
||||
|
||||
&-close {
|
||||
.@{drawer-prefix-cls}-rtl & {
|
||||
right: auto;
|
||||
left: 0;
|
||||
margin-right: 0;
|
||||
margin-left: 12px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,95 +1,117 @@
|
||||
import * as React from 'react';
|
||||
import classNames from 'classnames';
|
||||
import CSSMotion from 'rc-motion';
|
||||
import useMemo from 'rc-util/lib/hooks/useMemo';
|
||||
import useCacheErrors from './hooks/useCacheErrors';
|
||||
import useForceUpdate from '../_util/hooks/useForceUpdate';
|
||||
import CSSMotion, { CSSMotionList } from 'rc-motion';
|
||||
import { FormItemPrefixContext } from './context';
|
||||
import { ConfigContext } from '../config-provider';
|
||||
import { ValidateStatus } from './FormItem';
|
||||
import collapseMotion from '../_util/motion';
|
||||
|
||||
const EMPTY_LIST: React.ReactNode[] = [];
|
||||
|
||||
interface ErrorEntity {
|
||||
error: React.ReactNode;
|
||||
errorStatus?: ValidateStatus;
|
||||
key: string;
|
||||
}
|
||||
|
||||
function toErrorEntity(
|
||||
error: React.ReactNode,
|
||||
errorStatus: ValidateStatus | undefined,
|
||||
prefix: string,
|
||||
index: number = 0,
|
||||
): ErrorEntity {
|
||||
return {
|
||||
key: typeof error === 'string' ? error : `${prefix}-${index}`,
|
||||
error,
|
||||
errorStatus,
|
||||
};
|
||||
}
|
||||
|
||||
export interface ErrorListProps {
|
||||
errors?: React.ReactNode[];
|
||||
/** @private Internal Usage. Do not use in your production */
|
||||
help?: React.ReactNode;
|
||||
/** @private Internal Usage. Do not use in your production */
|
||||
onDomErrorVisibleChange?: (visible: boolean) => void;
|
||||
helpStatus?: ValidateStatus;
|
||||
errors?: React.ReactNode[];
|
||||
warnings?: React.ReactNode[];
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export default function ErrorList({
|
||||
errors = EMPTY_LIST,
|
||||
help,
|
||||
onDomErrorVisibleChange,
|
||||
helpStatus,
|
||||
errors = EMPTY_LIST,
|
||||
warnings = EMPTY_LIST,
|
||||
className: rootClassName,
|
||||
}: ErrorListProps) {
|
||||
const forceUpdate = useForceUpdate();
|
||||
const { prefixCls, status } = React.useContext(FormItemPrefixContext);
|
||||
const { prefixCls } = React.useContext(FormItemPrefixContext);
|
||||
const { getPrefixCls } = React.useContext(ConfigContext);
|
||||
|
||||
const [visible, cacheErrors] = useCacheErrors(
|
||||
errors,
|
||||
changedVisible => {
|
||||
if (changedVisible) {
|
||||
/**
|
||||
* We trigger in sync to avoid dom shaking but this get warning in react 16.13.
|
||||
*
|
||||
* So use Promise to keep in micro async to handle this.
|
||||
* https://github.com/ant-design/ant-design/issues/21698#issuecomment-593743485
|
||||
*/
|
||||
Promise.resolve().then(() => {
|
||||
onDomErrorVisibleChange?.(true);
|
||||
});
|
||||
}
|
||||
forceUpdate();
|
||||
},
|
||||
!!help,
|
||||
);
|
||||
|
||||
const memoErrors = useMemo(
|
||||
() => cacheErrors,
|
||||
visible,
|
||||
(_, nextVisible) => nextVisible,
|
||||
);
|
||||
|
||||
// Memo status in same visible
|
||||
const [innerStatus, setInnerStatus] = React.useState(status);
|
||||
React.useEffect(() => {
|
||||
if (visible && status) {
|
||||
setInnerStatus(status);
|
||||
}
|
||||
}, [visible, status]);
|
||||
|
||||
const baseClassName = `${prefixCls}-item-explain`;
|
||||
const rootPrefixCls = getPrefixCls();
|
||||
|
||||
const fullKeyList = React.useMemo(() => {
|
||||
if (help !== undefined && help !== null) {
|
||||
return [toErrorEntity(help, helpStatus, 'help')];
|
||||
}
|
||||
|
||||
return [
|
||||
...errors.map((error, index) => toErrorEntity(error, 'error', 'error', index)),
|
||||
...warnings.map((warning, index) => toErrorEntity(warning, 'warning', 'warning', index)),
|
||||
];
|
||||
}, [help, helpStatus, errors, warnings]);
|
||||
|
||||
return (
|
||||
<CSSMotion
|
||||
motionDeadline={500}
|
||||
visible={visible}
|
||||
{...collapseMotion}
|
||||
motionName={`${rootPrefixCls}-show-help`}
|
||||
onLeaveEnd={() => {
|
||||
onDomErrorVisibleChange?.(false);
|
||||
motionAppear={false}
|
||||
motionEnter={false}
|
||||
visible={!!fullKeyList.length}
|
||||
onLeaveStart={node => {
|
||||
// Force disable css override style in index.less configured
|
||||
node.style.height = 'auto';
|
||||
return { height: node.offsetHeight };
|
||||
}}
|
||||
>
|
||||
{({ className: motionClassName }: { className?: string }) => (
|
||||
<div
|
||||
className={classNames(
|
||||
baseClassName,
|
||||
{
|
||||
[`${baseClassName}-${innerStatus}`]: innerStatus,
|
||||
},
|
||||
motionClassName,
|
||||
)}
|
||||
key="help"
|
||||
>
|
||||
{memoErrors.map((error, index) => (
|
||||
// eslint-disable-next-line react/no-array-index-key
|
||||
<div key={index} role="alert">
|
||||
{error}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
{holderProps => {
|
||||
const { className: holderClassName, style: holderStyle } = holderProps;
|
||||
|
||||
return (
|
||||
<div
|
||||
className={classNames(baseClassName, holderClassName, rootClassName)}
|
||||
style={holderStyle}
|
||||
>
|
||||
<CSSMotionList
|
||||
keys={fullKeyList}
|
||||
{...collapseMotion}
|
||||
motionName={`${rootPrefixCls}-show-help-item`}
|
||||
component={false}
|
||||
>
|
||||
{itemProps => {
|
||||
const {
|
||||
key,
|
||||
error,
|
||||
errorStatus,
|
||||
className: itemClassName,
|
||||
style: itemStyle,
|
||||
} = itemProps;
|
||||
|
||||
return (
|
||||
<div
|
||||
key={key}
|
||||
role="alert"
|
||||
className={classNames(itemClassName, {
|
||||
[`${baseClassName}-${errorStatus}`]: errorStatus,
|
||||
})}
|
||||
style={itemStyle}
|
||||
>
|
||||
{error}
|
||||
</div>
|
||||
);
|
||||
}}
|
||||
</CSSMotionList>
|
||||
</div>
|
||||
);
|
||||
}}
|
||||
</CSSMotion>
|
||||
);
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
import * as React from 'react';
|
||||
import { useContext, useRef } from 'react';
|
||||
import isEqual from 'lodash/isEqual';
|
||||
import { useContext } from 'react';
|
||||
import classNames from 'classnames';
|
||||
import { Field, FormInstance } from 'rc-field-form';
|
||||
import { FieldProps } from 'rc-field-form/lib/Field';
|
||||
@ -14,14 +13,20 @@ import { tuple } from '../_util/type';
|
||||
import devWarning from '../_util/devWarning';
|
||||
import FormItemLabel, { FormItemLabelProps, LabelTooltipType } from './FormItemLabel';
|
||||
import FormItemInput, { FormItemInputProps } from './FormItemInput';
|
||||
import { FormContext, FormItemContext } from './context';
|
||||
import { FormContext, NoStyleItemContext } from './context';
|
||||
import { toArray, getFieldId } from './util';
|
||||
import { cloneElement, isValidElement } from '../_util/reactNode';
|
||||
import useFrameState from './hooks/useFrameState';
|
||||
import useDebounce from './hooks/useDebounce';
|
||||
import useItemRef from './hooks/useItemRef';
|
||||
|
||||
const NAME_SPLIT = '__SPLIT__';
|
||||
|
||||
interface FieldError {
|
||||
errors: string[];
|
||||
warnings: string[];
|
||||
}
|
||||
|
||||
const ValidateStatuses = tuple('success', 'warning', 'error', 'validating', '');
|
||||
export type ValidateStatus = typeof ValidateStatuses[number];
|
||||
|
||||
@ -31,7 +36,7 @@ type ChildrenType<Values = any> = RenderChildren<Values> | React.ReactNode;
|
||||
|
||||
interface MemoInputProps {
|
||||
value: any;
|
||||
update: number;
|
||||
update: any;
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
@ -68,6 +73,16 @@ function hasValidName(name?: NamePath): Boolean {
|
||||
return !(name === undefined || name === null);
|
||||
}
|
||||
|
||||
function genEmptyMeta(): Meta {
|
||||
return {
|
||||
errors: [],
|
||||
warnings: [],
|
||||
touched: false,
|
||||
validating: false,
|
||||
name: [],
|
||||
};
|
||||
}
|
||||
|
||||
function FormItem<Values = any>(props: FormItemProps<Values>): React.ReactElement {
|
||||
const {
|
||||
name,
|
||||
@ -91,104 +106,109 @@ function FormItem<Values = any>(props: FormItemProps<Values>): React.ReactElemen
|
||||
hidden,
|
||||
...restProps
|
||||
} = props;
|
||||
const destroyRef = useRef(false);
|
||||
const { getPrefixCls } = useContext(ConfigContext);
|
||||
const { name: formName, requiredMark } = useContext(FormContext);
|
||||
const { updateItemErrors } = useContext(FormItemContext);
|
||||
const [domErrorVisible, innerSetDomErrorVisible] = React.useState(!!help);
|
||||
const [inlineErrors, setInlineErrors] = useFrameState<Record<string, string[]>>({});
|
||||
const isRenderProps = typeof children === 'function';
|
||||
const notifyParentMetaChange = useContext(NoStyleItemContext);
|
||||
|
||||
const { validateTrigger: contextValidateTrigger } = useContext(FieldContext);
|
||||
const mergedValidateTrigger =
|
||||
validateTrigger !== undefined ? validateTrigger : contextValidateTrigger;
|
||||
|
||||
const setDomErrorVisible = (visible: boolean) => {
|
||||
if (!destroyRef.current) {
|
||||
innerSetDomErrorVisible(visible);
|
||||
}
|
||||
};
|
||||
|
||||
const hasName = hasValidName(name);
|
||||
|
||||
// Cache Field NamePath
|
||||
const nameRef = useRef<(string | number)[]>([]);
|
||||
|
||||
// Should clean up if Field removed
|
||||
React.useEffect(
|
||||
() => () => {
|
||||
destroyRef.current = true;
|
||||
updateItemErrors(nameRef.current.join(NAME_SPLIT), []);
|
||||
},
|
||||
[],
|
||||
);
|
||||
|
||||
const prefixCls = getPrefixCls('form', customizePrefixCls);
|
||||
|
||||
// ======================== Errors ========================
|
||||
// Collect noStyle Field error to the top FormItem
|
||||
const updateChildItemErrors = noStyle
|
||||
? updateItemErrors
|
||||
: (subName: string, subErrors: string[], originSubName?: string) => {
|
||||
setInlineErrors((prevInlineErrors = {}) => {
|
||||
// Clean up origin error when name changed
|
||||
if (originSubName && originSubName !== subName) {
|
||||
delete prevInlineErrors[originSubName];
|
||||
}
|
||||
// >>>>> Collect sub field errors
|
||||
const [subFieldErrors, setSubFieldErrors] = useFrameState<Record<string, FieldError>>({});
|
||||
|
||||
if (!isEqual(prevInlineErrors[subName], subErrors)) {
|
||||
return {
|
||||
...prevInlineErrors,
|
||||
[subName]: subErrors,
|
||||
};
|
||||
}
|
||||
return prevInlineErrors;
|
||||
});
|
||||
// >>>>> Current field errors
|
||||
const [meta, setMeta] = React.useState<Meta>(() => genEmptyMeta());
|
||||
|
||||
const onMetaChange = (nextMeta: Meta & { destroy?: boolean }) => {
|
||||
// Destroy will reset all the meta
|
||||
setMeta(nextMeta.destroy ? genEmptyMeta() : nextMeta);
|
||||
|
||||
// Bump to parent since noStyle
|
||||
if (noStyle && notifyParentMetaChange) {
|
||||
let namePath = nextMeta.name;
|
||||
if (fieldKey !== undefined) {
|
||||
namePath = Array.isArray(fieldKey) ? fieldKey : [fieldKey!];
|
||||
}
|
||||
notifyParentMetaChange(nextMeta, namePath);
|
||||
}
|
||||
};
|
||||
|
||||
// >>>>> Collect noStyle Field error to the top FormItem
|
||||
const onSubItemMetaChange = (subMeta: Meta & { destroy: boolean }, uniqueKeys: React.Key[]) => {
|
||||
// Only `noStyle` sub item will trigger
|
||||
setSubFieldErrors(prevSubFieldErrors => {
|
||||
const clone = {
|
||||
...prevSubFieldErrors,
|
||||
};
|
||||
|
||||
// name: ['user', 1] + key: [4] = ['user', 4]
|
||||
const mergedNamePath = [...subMeta.name.slice(0, -1), ...uniqueKeys];
|
||||
const mergedNameKey = mergedNamePath.join(NAME_SPLIT);
|
||||
|
||||
if (subMeta.destroy) {
|
||||
// Remove
|
||||
delete clone[mergedNameKey];
|
||||
} else {
|
||||
// Update
|
||||
clone[mergedNameKey] = subMeta;
|
||||
}
|
||||
|
||||
return clone;
|
||||
});
|
||||
};
|
||||
|
||||
// >>>>> Get merged errors
|
||||
const [mergedErrors, mergedWarnings] = React.useMemo(() => {
|
||||
const errorList: string[] = [...meta.errors];
|
||||
const warningList: string[] = [...meta.warnings];
|
||||
|
||||
Object.values(subFieldErrors).forEach(subFieldError => {
|
||||
errorList.push(...(subFieldError.errors || []));
|
||||
warningList.push(...(subFieldError.warnings || []));
|
||||
});
|
||||
|
||||
return [errorList, warningList];
|
||||
}, [subFieldErrors, meta.errors, meta.warnings]);
|
||||
|
||||
const debounceErrors = useDebounce(mergedErrors);
|
||||
const debounceWarnings = useDebounce(mergedWarnings);
|
||||
|
||||
// ===================== Children Ref =====================
|
||||
const getItemRef = useItemRef();
|
||||
|
||||
// ======================== Render ========================
|
||||
function renderLayout(
|
||||
baseChildren: React.ReactNode,
|
||||
fieldId?: string,
|
||||
meta?: Meta,
|
||||
isRequired?: boolean,
|
||||
): React.ReactNode {
|
||||
if (noStyle && !hidden) {
|
||||
return baseChildren;
|
||||
}
|
||||
|
||||
// ======================== Errors ========================
|
||||
// >>> collect sub errors
|
||||
let subErrorList: string[] = [];
|
||||
Object.keys(inlineErrors).forEach(subName => {
|
||||
subErrorList = [...subErrorList, ...(inlineErrors[subName] || [])];
|
||||
});
|
||||
|
||||
// >>> merged errors
|
||||
let mergedErrors: React.ReactNode[];
|
||||
if (help !== undefined && help !== null) {
|
||||
mergedErrors = toArray(help);
|
||||
} else {
|
||||
mergedErrors = meta ? meta.errors : [];
|
||||
mergedErrors = [...mergedErrors, ...subErrorList];
|
||||
}
|
||||
|
||||
// ======================== Status ========================
|
||||
let mergedValidateStatus: ValidateStatus = '';
|
||||
if (validateStatus !== undefined) {
|
||||
mergedValidateStatus = validateStatus;
|
||||
} else if (meta?.validating) {
|
||||
mergedValidateStatus = 'validating';
|
||||
} else if (meta?.errors?.length || subErrorList.length) {
|
||||
} else if (debounceErrors.length) {
|
||||
mergedValidateStatus = 'error';
|
||||
} else if (debounceWarnings.length) {
|
||||
mergedValidateStatus = 'warning';
|
||||
} else if (meta?.touched) {
|
||||
mergedValidateStatus = 'success';
|
||||
}
|
||||
|
||||
const itemClassName = {
|
||||
[`${prefixCls}-item`]: true,
|
||||
[`${prefixCls}-item-with-help`]: domErrorVisible || !!help,
|
||||
[`${prefixCls}-item-with-help`]: help || debounceErrors.length || debounceWarnings.length,
|
||||
[`${className}`]: !!className,
|
||||
|
||||
// Status
|
||||
@ -238,26 +258,21 @@ function FormItem<Values = any>(props: FormItemProps<Values>): React.ReactElemen
|
||||
<FormItemInput
|
||||
{...props}
|
||||
{...meta}
|
||||
errors={mergedErrors}
|
||||
errors={debounceErrors}
|
||||
warnings={debounceWarnings}
|
||||
prefixCls={prefixCls}
|
||||
status={mergedValidateStatus}
|
||||
onDomErrorVisibleChange={setDomErrorVisible}
|
||||
validateStatus={mergedValidateStatus}
|
||||
help={help}
|
||||
>
|
||||
<FormItemContext.Provider value={{ updateItemErrors: updateChildItemErrors }}>
|
||||
<NoStyleItemContext.Provider value={onSubItemMetaChange}>
|
||||
{baseChildren}
|
||||
</FormItemContext.Provider>
|
||||
</NoStyleItemContext.Provider>
|
||||
</FormItemInput>
|
||||
</Row>
|
||||
);
|
||||
}
|
||||
|
||||
const isRenderProps = typeof children === 'function';
|
||||
|
||||
// Record for real component render
|
||||
const updateRef = useRef(0);
|
||||
updateRef.current += 1;
|
||||
|
||||
if (!hasName && !isRenderProps && !dependencies) {
|
||||
return renderLayout(children) as JSX.Element;
|
||||
}
|
||||
@ -272,46 +287,31 @@ function FormItem<Values = any>(props: FormItemProps<Values>): React.ReactElemen
|
||||
variables = { ...variables, ...messageVariables };
|
||||
}
|
||||
|
||||
// >>>>> With Field
|
||||
return (
|
||||
<Field
|
||||
{...props}
|
||||
messageVariables={variables}
|
||||
trigger={trigger}
|
||||
validateTrigger={mergedValidateTrigger}
|
||||
onReset={() => {
|
||||
setDomErrorVisible(false);
|
||||
}}
|
||||
onMetaChange={onMetaChange}
|
||||
>
|
||||
{(control, meta, context) => {
|
||||
const { errors } = meta;
|
||||
|
||||
const mergedName = toArray(name).length && meta ? meta.name : [];
|
||||
{(control, renderMeta, context) => {
|
||||
const mergedName = toArray(name).length && renderMeta ? renderMeta.name : [];
|
||||
const fieldId = getFieldId(mergedName, formName);
|
||||
|
||||
if (noStyle) {
|
||||
// Clean up origin one
|
||||
const originErrorName = nameRef.current.join(NAME_SPLIT);
|
||||
|
||||
nameRef.current = [...mergedName];
|
||||
if (fieldKey) {
|
||||
const fieldKeys = Array.isArray(fieldKey) ? fieldKey : [fieldKey];
|
||||
nameRef.current = [...mergedName.slice(0, -1), ...fieldKeys];
|
||||
}
|
||||
updateItemErrors(nameRef.current.join(NAME_SPLIT), errors, originErrorName);
|
||||
}
|
||||
|
||||
const isRequired =
|
||||
required !== undefined
|
||||
? required
|
||||
: !!(
|
||||
rules &&
|
||||
rules.some(rule => {
|
||||
if (rule && typeof rule === 'object' && rule.required) {
|
||||
if (rule && typeof rule === 'object' && rule.required && !rule.warningOnly) {
|
||||
return true;
|
||||
}
|
||||
if (typeof rule === 'function') {
|
||||
const ruleEntity = rule(context);
|
||||
return ruleEntity && ruleEntity.required;
|
||||
return ruleEntity && ruleEntity.required && !ruleEntity.warningOnly;
|
||||
}
|
||||
return false;
|
||||
})
|
||||
@ -379,10 +379,7 @@ function FormItem<Values = any>(props: FormItemProps<Values>): React.ReactElemen
|
||||
});
|
||||
|
||||
childNode = (
|
||||
<MemoInput
|
||||
value={mergedControl[props.valuePropName || 'value']}
|
||||
update={updateRef.current}
|
||||
>
|
||||
<MemoInput value={mergedControl[props.valuePropName || 'value']} update={children}>
|
||||
{cloneElement(children, childProps)}
|
||||
</MemoInput>
|
||||
);
|
||||
@ -397,7 +394,7 @@ function FormItem<Values = any>(props: FormItemProps<Values>): React.ReactElemen
|
||||
childNode = children;
|
||||
}
|
||||
|
||||
return renderLayout(childNode, fieldId, meta, isRequired);
|
||||
return renderLayout(childNode, fieldId, isRequired);
|
||||
}}
|
||||
</Field>
|
||||
);
|
||||
|
@ -14,9 +14,9 @@ interface FormItemInputMiscProps {
|
||||
prefixCls: string;
|
||||
children: React.ReactNode;
|
||||
errors: React.ReactNode[];
|
||||
warnings: React.ReactNode[];
|
||||
hasFeedback?: boolean;
|
||||
validateStatus?: ValidateStatus;
|
||||
onDomErrorVisibleChange: (visible: boolean) => void;
|
||||
/** @private Internal Usage, do not use in any of your production. */
|
||||
_internalItemRender?: {
|
||||
mark: string;
|
||||
@ -33,9 +33,9 @@ interface FormItemInputMiscProps {
|
||||
|
||||
export interface FormItemInputProps {
|
||||
wrapperCol?: ColProps;
|
||||
help?: React.ReactNode;
|
||||
extra?: React.ReactNode;
|
||||
status?: ValidateStatus;
|
||||
help?: React.ReactNode;
|
||||
}
|
||||
|
||||
const iconMap: { [key: string]: any } = {
|
||||
@ -51,13 +51,13 @@ const FormItemInput: React.FC<FormItemInputProps & FormItemInputMiscProps> = pro
|
||||
status,
|
||||
wrapperCol,
|
||||
children,
|
||||
help,
|
||||
errors,
|
||||
onDomErrorVisibleChange,
|
||||
warnings,
|
||||
hasFeedback,
|
||||
_internalItemRender: formItemRender,
|
||||
validateStatus,
|
||||
extra,
|
||||
help,
|
||||
} = props;
|
||||
const baseClassName = `${prefixCls}-item`;
|
||||
|
||||
@ -67,13 +67,6 @@ const FormItemInput: React.FC<FormItemInputProps & FormItemInputMiscProps> = pro
|
||||
|
||||
const className = classNames(`${baseClassName}-control`, mergedWrapperCol.className);
|
||||
|
||||
React.useEffect(
|
||||
() => () => {
|
||||
onDomErrorVisibleChange(false);
|
||||
},
|
||||
[],
|
||||
);
|
||||
|
||||
// Should provides additional icon if `hasFeedback`
|
||||
const IconNode = validateStatus && iconMap[validateStatus];
|
||||
const icon =
|
||||
@ -96,7 +89,13 @@ const FormItemInput: React.FC<FormItemInputProps & FormItemInputMiscProps> = pro
|
||||
);
|
||||
const errorListDom = (
|
||||
<FormItemPrefixContext.Provider value={{ prefixCls, status }}>
|
||||
<ErrorList errors={errors} help={help} onDomErrorVisibleChange={onDomErrorVisibleChange} />
|
||||
<ErrorList
|
||||
errors={errors}
|
||||
warnings={warnings}
|
||||
help={help}
|
||||
helpStatus={status}
|
||||
className={`${baseClassName}-explain-connected`}
|
||||
/>
|
||||
</FormItemPrefixContext.Provider>
|
||||
);
|
||||
|
||||
|
@ -25,7 +25,7 @@ export interface FormListProps {
|
||||
children: (
|
||||
fields: FormListFieldData[],
|
||||
operation: FormListOperation,
|
||||
meta: { errors: React.ReactNode[] },
|
||||
meta: { errors: React.ReactNode[]; warnings: React.ReactNode[] },
|
||||
) => React.ReactNode;
|
||||
}
|
||||
|
||||
@ -48,6 +48,7 @@ const FormList: React.FC<FormListProps> = ({
|
||||
operation,
|
||||
{
|
||||
errors: meta.errors,
|
||||
warnings: meta.warnings,
|
||||
},
|
||||
)}
|
||||
</FormItemPrefixContext.Provider>
|
||||
|
@ -306,6 +306,7 @@ exports[`renders ./components/form/demo/advanced-search.md correctly 1`] = `
|
||||
|
||||
exports[`renders ./components/form/demo/basic.md correctly 1`] = `
|
||||
<form
|
||||
autocomplete="off"
|
||||
class="ant-form ant-form-horizontal"
|
||||
id="basic"
|
||||
>
|
||||
@ -1073,9 +1074,10 @@ exports[`renders ./components/form/demo/disabled-input-debug.md correctly 1`] =
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-form-item-explain ant-form-item-explain-error"
|
||||
class="ant-form-item-explain ant-form-item-explain-connected"
|
||||
>
|
||||
<div
|
||||
class="ant-form-item-explain-error"
|
||||
role="alert"
|
||||
>
|
||||
Buggy!
|
||||
@ -1115,9 +1117,10 @@ exports[`renders ./components/form/demo/disabled-input-debug.md correctly 1`] =
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-form-item-explain ant-form-item-explain-error"
|
||||
class="ant-form-item-explain ant-form-item-explain-connected"
|
||||
>
|
||||
<div
|
||||
class="ant-form-item-explain-error"
|
||||
role="alert"
|
||||
>
|
||||
Buggy!
|
||||
@ -1188,9 +1191,10 @@ exports[`renders ./components/form/demo/disabled-input-debug.md correctly 1`] =
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-form-item-explain ant-form-item-explain-error"
|
||||
class="ant-form-item-explain ant-form-item-explain-connected"
|
||||
>
|
||||
<div
|
||||
class="ant-form-item-explain-error"
|
||||
role="alert"
|
||||
>
|
||||
Buggy!
|
||||
@ -1230,9 +1234,10 @@ exports[`renders ./components/form/demo/disabled-input-debug.md correctly 1`] =
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-form-item-explain ant-form-item-explain-error"
|
||||
class="ant-form-item-explain ant-form-item-explain-connected"
|
||||
>
|
||||
<div
|
||||
class="ant-form-item-explain-error"
|
||||
role="alert"
|
||||
>
|
||||
Buggy!
|
||||
@ -1329,9 +1334,10 @@ exports[`renders ./components/form/demo/disabled-input-debug.md correctly 1`] =
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-form-item-explain ant-form-item-explain-error"
|
||||
class="ant-form-item-explain ant-form-item-explain-connected"
|
||||
>
|
||||
<div
|
||||
class="ant-form-item-explain-error"
|
||||
role="alert"
|
||||
>
|
||||
Buggy!
|
||||
@ -1384,9 +1390,10 @@ exports[`renders ./components/form/demo/disabled-input-debug.md correctly 1`] =
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-form-item-explain ant-form-item-explain-error"
|
||||
class="ant-form-item-explain ant-form-item-explain-connected"
|
||||
>
|
||||
<div
|
||||
class="ant-form-item-explain-error"
|
||||
role="alert"
|
||||
>
|
||||
Buggy!
|
||||
@ -1475,9 +1482,10 @@ exports[`renders ./components/form/demo/disabled-input-debug.md correctly 1`] =
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-form-item-explain ant-form-item-explain-error"
|
||||
class="ant-form-item-explain ant-form-item-explain-connected"
|
||||
>
|
||||
<div
|
||||
class="ant-form-item-explain-error"
|
||||
role="alert"
|
||||
>
|
||||
Buggy!
|
||||
@ -1526,9 +1534,10 @@ exports[`renders ./components/form/demo/disabled-input-debug.md correctly 1`] =
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-form-item-explain ant-form-item-explain-error"
|
||||
class="ant-form-item-explain ant-form-item-explain-connected"
|
||||
>
|
||||
<div
|
||||
class="ant-form-item-explain-error"
|
||||
role="alert"
|
||||
>
|
||||
Buggy!
|
||||
@ -3427,6 +3436,7 @@ exports[`renders ./components/form/demo/register.md correctly 1`] = `
|
||||
>
|
||||
<span
|
||||
class="ant-cascader-picker-label"
|
||||
title="Zhejiang / Hangzhou / West Lake"
|
||||
>
|
||||
Zhejiang / Hangzhou / West Lake
|
||||
</span>
|
||||
@ -6591,9 +6601,10 @@ exports[`renders ./components/form/demo/validate-static.md correctly 1`] = `
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-form-item-explain ant-form-item-explain-error"
|
||||
class="ant-form-item-explain ant-form-item-explain-connected"
|
||||
>
|
||||
<div
|
||||
class="ant-form-item-explain-error"
|
||||
role="alert"
|
||||
>
|
||||
Should be combination of numbers & alphabets
|
||||
@ -6716,9 +6727,10 @@ exports[`renders ./components/form/demo/validate-static.md correctly 1`] = `
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="ant-form-item-explain ant-form-item-explain-validating"
|
||||
class="ant-form-item-explain ant-form-item-explain-connected"
|
||||
>
|
||||
<div
|
||||
class="ant-form-item-explain-validating"
|
||||
role="alert"
|
||||
>
|
||||
The information is being validated...
|
||||
@ -6893,9 +6905,10 @@ exports[`renders ./components/form/demo/validate-static.md correctly 1`] = `
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="ant-form-item-explain ant-form-item-explain-error"
|
||||
class="ant-form-item-explain ant-form-item-explain-connected"
|
||||
>
|
||||
<div
|
||||
class="ant-form-item-explain-error"
|
||||
role="alert"
|
||||
>
|
||||
Should be combination of numbers & alphabets
|
||||
@ -7273,9 +7286,10 @@ exports[`renders ./components/form/demo/validate-static.md correctly 1`] = `
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="ant-form-item-explain ant-form-item-explain-validating"
|
||||
class="ant-form-item-explain ant-form-item-explain-connected"
|
||||
>
|
||||
<div
|
||||
class="ant-form-item-explain-validating"
|
||||
role="alert"
|
||||
>
|
||||
The information is being validated...
|
||||
@ -7361,9 +7375,10 @@ exports[`renders ./components/form/demo/validate-static.md correctly 1`] = `
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-form-item-explain ant-form-item-explain-error"
|
||||
class="ant-form-item-explain ant-form-item-explain-connected"
|
||||
>
|
||||
<div
|
||||
class="ant-form-item-explain-error"
|
||||
role="alert"
|
||||
>
|
||||
Please select the correct date
|
||||
@ -7839,6 +7854,97 @@ exports[`renders ./components/form/demo/validate-static.md correctly 1`] = `
|
||||
</form>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/form/demo/warning-only.md correctly 1`] = `
|
||||
<form
|
||||
autocomplete="off"
|
||||
class="ant-form ant-form-vertical"
|
||||
>
|
||||
<div
|
||||
style="overflow:hidden"
|
||||
>
|
||||
<div
|
||||
class="ant-row ant-form-item"
|
||||
>
|
||||
<div
|
||||
class="ant-col ant-form-item-label"
|
||||
>
|
||||
<label
|
||||
class="ant-form-item-required"
|
||||
for="url"
|
||||
title="URL"
|
||||
>
|
||||
URL
|
||||
</label>
|
||||
</div>
|
||||
<div
|
||||
class="ant-col ant-form-item-control"
|
||||
>
|
||||
<div
|
||||
class="ant-form-item-control-input"
|
||||
>
|
||||
<div
|
||||
class="ant-form-item-control-input-content"
|
||||
>
|
||||
<input
|
||||
class="ant-input"
|
||||
id="url"
|
||||
placeholder="input placeholder"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-row ant-form-item"
|
||||
>
|
||||
<div
|
||||
class="ant-col ant-form-item-control"
|
||||
>
|
||||
<div
|
||||
class="ant-form-item-control-input"
|
||||
>
|
||||
<div
|
||||
class="ant-form-item-control-input-content"
|
||||
>
|
||||
<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="submit"
|
||||
>
|
||||
<span>
|
||||
Submit
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
>
|
||||
<button
|
||||
class="ant-btn"
|
||||
type="button"
|
||||
>
|
||||
<span>
|
||||
Fill
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/form/demo/without-form-create.md correctly 1`] = `
|
||||
<form
|
||||
class="ant-form ant-form-horizontal"
|
||||
@ -7944,9 +8050,10 @@ exports[`renders ./components/form/demo/without-form-create.md correctly 1`] = `
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-form-item-explain"
|
||||
class="ant-form-item-explain ant-form-item-explain-connected"
|
||||
>
|
||||
<div
|
||||
class=""
|
||||
role="alert"
|
||||
>
|
||||
A prime is a natural number greater than 1 that has no positive divisors other than 1 and itself.
|
||||
|
@ -1,5 +1,6 @@
|
||||
import React, { Component } from 'react';
|
||||
import { mount } from 'enzyme';
|
||||
import { act } from 'react-dom/test-utils';
|
||||
import scrollIntoView from 'scroll-into-view-if-needed';
|
||||
import Form from '..';
|
||||
import Input from '../../input';
|
||||
@ -20,10 +21,17 @@ describe('Form', () => {
|
||||
scrollIntoView.mockImplementation(() => {});
|
||||
const errorSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
|
||||
|
||||
async function change(wrapper, index, value) {
|
||||
async function change(wrapper, index, value, executeMockTimer) {
|
||||
wrapper.find(Input).at(index).simulate('change', { target: { value } });
|
||||
await sleep(200);
|
||||
wrapper.update();
|
||||
|
||||
if (executeMockTimer) {
|
||||
act(() => {
|
||||
jest.runAllTimers();
|
||||
wrapper.update();
|
||||
});
|
||||
await sleep(1);
|
||||
}
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
@ -42,6 +50,8 @@ describe('Form', () => {
|
||||
|
||||
describe('noStyle Form.Item', () => {
|
||||
it('work', async () => {
|
||||
jest.useFakeTimers();
|
||||
|
||||
const onChange = jest.fn();
|
||||
|
||||
const wrapper = mount(
|
||||
@ -54,14 +64,18 @@ describe('Form', () => {
|
||||
</Form>,
|
||||
);
|
||||
|
||||
await change(wrapper, 0, '');
|
||||
await change(wrapper, 0, '', true);
|
||||
expect(wrapper.find('.ant-form-item-with-help').length).toBeTruthy();
|
||||
expect(wrapper.find('.ant-form-item-has-error').length).toBeTruthy();
|
||||
|
||||
expect(onChange).toHaveBeenCalled();
|
||||
|
||||
jest.useRealTimers();
|
||||
});
|
||||
|
||||
it('should clean up', async () => {
|
||||
jest.useFakeTimers();
|
||||
|
||||
const Demo = () => {
|
||||
const [form] = Form.useForm();
|
||||
|
||||
@ -105,12 +119,14 @@ describe('Form', () => {
|
||||
};
|
||||
|
||||
const wrapper = mount(<Demo />);
|
||||
await change(wrapper, 0, '1');
|
||||
await change(wrapper, 0, '1', true);
|
||||
expect(wrapper.find('.ant-form-item-explain').text()).toEqual('aaa');
|
||||
await change(wrapper, 0, '2');
|
||||
await change(wrapper, 0, '2', true);
|
||||
expect(wrapper.find('.ant-form-item-explain').text()).toEqual('ccc');
|
||||
await change(wrapper, 0, '1');
|
||||
await change(wrapper, 0, '1', true);
|
||||
expect(wrapper.find('.ant-form-item-explain').text()).toEqual('aaa');
|
||||
|
||||
jest.useRealTimers();
|
||||
});
|
||||
});
|
||||
|
||||
@ -315,6 +331,8 @@ describe('Form', () => {
|
||||
|
||||
// https://github.com/ant-design/ant-design/issues/20706
|
||||
it('Error change should work', async () => {
|
||||
jest.useFakeTimers();
|
||||
|
||||
const wrapper = mount(
|
||||
<Form>
|
||||
<Form.Item
|
||||
@ -338,15 +356,17 @@ describe('Form', () => {
|
||||
|
||||
/* eslint-disable no-await-in-loop */
|
||||
for (let i = 0; i < 3; i += 1) {
|
||||
await change(wrapper, 0, '');
|
||||
await change(wrapper, 0, '', true);
|
||||
expect(wrapper.find('.ant-form-item-explain').first().text()).toEqual("'name' is required");
|
||||
|
||||
await change(wrapper, 0, 'p');
|
||||
await change(wrapper, 0, 'p', true);
|
||||
await sleep(100);
|
||||
wrapper.update();
|
||||
expect(wrapper.find('.ant-form-item-explain').first().text()).toEqual('not a p');
|
||||
}
|
||||
/* eslint-enable */
|
||||
|
||||
jest.useRealTimers();
|
||||
});
|
||||
|
||||
// https://github.com/ant-design/ant-design/issues/20813
|
||||
@ -428,6 +448,8 @@ describe('Form', () => {
|
||||
});
|
||||
|
||||
it('Form.Item with `help` should display error style when validate failed', async () => {
|
||||
jest.useFakeTimers();
|
||||
|
||||
const wrapper = mount(
|
||||
<Form>
|
||||
<Form.Item name="test" help="help" rules={[{ required: true, message: 'message' }]}>
|
||||
@ -436,12 +458,16 @@ describe('Form', () => {
|
||||
</Form>,
|
||||
);
|
||||
|
||||
await change(wrapper, 0, '');
|
||||
await change(wrapper, 0, '', true);
|
||||
expect(wrapper.find('.ant-form-item').first().hasClass('ant-form-item-has-error')).toBeTruthy();
|
||||
expect(wrapper.find('.ant-form-item-explain').text()).toEqual('help');
|
||||
|
||||
jest.useRealTimers();
|
||||
});
|
||||
|
||||
it('clear validation message when ', async () => {
|
||||
jest.useFakeTimers();
|
||||
|
||||
const wrapper = mount(
|
||||
<Form>
|
||||
<Form.Item name="username" rules={[{ required: true, message: 'message' }]}>
|
||||
@ -449,14 +475,18 @@ describe('Form', () => {
|
||||
</Form.Item>
|
||||
</Form>,
|
||||
);
|
||||
await change(wrapper, 0, '1');
|
||||
await change(wrapper, 0, '1', true);
|
||||
expect(wrapper.find('.ant-form-item-explain').length).toBeFalsy();
|
||||
await change(wrapper, 0, '');
|
||||
|
||||
await change(wrapper, 0, '', true);
|
||||
expect(wrapper.find('.ant-form-item-explain').length).toBeTruthy();
|
||||
await change(wrapper, 0, '123');
|
||||
|
||||
await change(wrapper, 0, '123', true);
|
||||
await sleep(800);
|
||||
wrapper.update();
|
||||
expect(wrapper.find('.ant-form-item-explain').length).toBeFalsy();
|
||||
|
||||
jest.useRealTimers();
|
||||
});
|
||||
|
||||
// https://github.com/ant-design/ant-design/issues/21167
|
||||
|
@ -200,34 +200,6 @@ describe('Form.List', () => {
|
||||
jest.useRealTimers();
|
||||
});
|
||||
|
||||
describe('ErrorList component', () => {
|
||||
it('should trigger onDomErrorVisibleChange by motion end', async () => {
|
||||
jest.useFakeTimers();
|
||||
|
||||
const onDomErrorVisibleChange = jest.fn();
|
||||
const wrapper = mount(
|
||||
<Form.ErrorList
|
||||
errors={['bamboo is light']}
|
||||
onDomErrorVisibleChange={onDomErrorVisibleChange}
|
||||
/>,
|
||||
);
|
||||
|
||||
await act(async () => {
|
||||
await sleep();
|
||||
jest.runAllTimers();
|
||||
wrapper.update();
|
||||
});
|
||||
|
||||
act(() => {
|
||||
wrapper.find('CSSMotion').props().onLeaveEnd();
|
||||
});
|
||||
|
||||
expect(onDomErrorVisibleChange).toHaveBeenCalledWith(false);
|
||||
|
||||
jest.useRealTimers();
|
||||
});
|
||||
});
|
||||
|
||||
it('should render empty without errors', () => {
|
||||
const wrapper = mount(<Form.ErrorList />);
|
||||
expect(wrapper.render()).toMatchSnapshot();
|
||||
|
@ -1,5 +1,6 @@
|
||||
import * as React from 'react';
|
||||
import omit from 'rc-util/lib/omit';
|
||||
import { Meta } from 'rc-field-form/lib/interface';
|
||||
import { FormProvider as RcFormProvider } from 'rc-field-form';
|
||||
import { FormProviderProps as RcFormProviderProps } from 'rc-field-form/lib/FormContext';
|
||||
import { ColProps } from '../grid/col';
|
||||
@ -25,14 +26,9 @@ export const FormContext = React.createContext<FormContextProps>({
|
||||
itemRef: (() => {}) as any,
|
||||
});
|
||||
|
||||
/** Form Item Context. Used for Form noStyle Item error collection */
|
||||
export interface FormItemContextProps {
|
||||
updateItemErrors: (name: string, errors: string[], originName?: string) => void;
|
||||
}
|
||||
|
||||
export const FormItemContext = React.createContext<FormItemContextProps>({
|
||||
updateItemErrors: () => {},
|
||||
});
|
||||
/** `noStyle` Form Item Context. Used for error collection */
|
||||
export type ReportMetaChange = (meta: Meta, uniqueKeys: React.Key[]) => void;
|
||||
export const NoStyleItemContext = React.createContext<ReportMetaChange | null>(null);
|
||||
|
||||
/** Form Provider */
|
||||
export interface FormProviderProps extends Omit<RcFormProviderProps, 'validateMessages'> {
|
||||
|
@ -33,6 +33,7 @@ const Demo = () => {
|
||||
initialValues={{ remember: true }}
|
||||
onFinish={onFinish}
|
||||
onFinishFailed={onFinishFailed}
|
||||
autoComplete="off"
|
||||
>
|
||||
<Form.Item
|
||||
label="Username"
|
||||
|
@ -15,7 +15,7 @@ We recommend use `Form.useForm` to create data control. If you are using class c
|
||||
|
||||
```tsx
|
||||
import { Form, Input, Button, Select } from 'antd';
|
||||
import { FormInstance } from 'antd/lib/form';
|
||||
import { FormInstance } from 'antd/es/form';
|
||||
|
||||
const { Option } = Select;
|
||||
|
||||
|
73
components/form/demo/warning-only.md
Normal file
73
components/form/demo/warning-only.md
Normal file
@ -0,0 +1,73 @@
|
||||
---
|
||||
order: 3.2
|
||||
title:
|
||||
zh-CN: 非阻塞校验
|
||||
en-US: No block rule
|
||||
---
|
||||
|
||||
## zh-CN
|
||||
|
||||
`rule` 添加 `warningOnly` 后校验不再阻塞表单提交。
|
||||
|
||||
## en-US
|
||||
|
||||
`rule` with `warningOnly` will not block form submit.
|
||||
|
||||
```tsx
|
||||
import React from 'react';
|
||||
import { Form, Input, message, Button, Space } from 'antd';
|
||||
|
||||
const Demo = () => {
|
||||
const [form] = Form.useForm();
|
||||
|
||||
const onFinish = () => {
|
||||
message.success('Submit success!');
|
||||
};
|
||||
|
||||
const onFinishFailed = () => {
|
||||
message.error('Submit failed!');
|
||||
};
|
||||
|
||||
const onFill = () => {
|
||||
form.setFieldsValue({
|
||||
url: 'https://taobao.com/',
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<Form
|
||||
form={form}
|
||||
layout="vertical"
|
||||
onFinish={onFinish}
|
||||
onFinishFailed={onFinishFailed}
|
||||
autoComplete="off"
|
||||
>
|
||||
<div style={{ overflow: 'hidden' }}>
|
||||
<Form.Item
|
||||
name="url"
|
||||
label="URL"
|
||||
rules={[
|
||||
{ required: true },
|
||||
{ type: 'url', warningOnly: true },
|
||||
{ type: 'string', min: 6 },
|
||||
]}
|
||||
>
|
||||
<Input placeholder="input placeholder" />
|
||||
</Form.Item>
|
||||
</div>
|
||||
<Form.Item>
|
||||
<Space>
|
||||
<Button type="primary" htmlType="submit">
|
||||
Submit
|
||||
</Button>
|
||||
<Button htmlType="button" onClick={onFill}>
|
||||
Fill
|
||||
</Button>
|
||||
</Space>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
|
||||
ReactDOM.render(<Demo />, mountNode);
|
||||
```
|
@ -1,47 +0,0 @@
|
||||
import * as React from 'react';
|
||||
import useForceUpdate from '../../_util/hooks/useForceUpdate';
|
||||
|
||||
/** Always debounce error to avoid [error -> null -> error] blink */
|
||||
export default function useCacheErrors(
|
||||
errors: React.ReactNode[],
|
||||
changeTrigger: (visible: boolean) => void,
|
||||
directly: boolean,
|
||||
): [boolean, React.ReactNode[]] {
|
||||
const cacheRef = React.useRef({
|
||||
errors,
|
||||
visible: !!errors.length,
|
||||
});
|
||||
|
||||
const forceUpdate = useForceUpdate();
|
||||
|
||||
const update = () => {
|
||||
const prevVisible = cacheRef.current.visible;
|
||||
const newVisible = !!errors.length;
|
||||
|
||||
const prevErrors = cacheRef.current.errors;
|
||||
cacheRef.current.errors = errors;
|
||||
cacheRef.current.visible = newVisible;
|
||||
|
||||
if (prevVisible !== newVisible) {
|
||||
changeTrigger(newVisible);
|
||||
} else if (
|
||||
prevErrors.length !== errors.length ||
|
||||
prevErrors.some((prevErr, index) => prevErr !== errors[index])
|
||||
) {
|
||||
forceUpdate();
|
||||
}
|
||||
};
|
||||
|
||||
React.useEffect(() => {
|
||||
if (!directly) {
|
||||
const timeout = setTimeout(update, 10);
|
||||
return () => clearTimeout(timeout);
|
||||
}
|
||||
}, [errors]);
|
||||
|
||||
if (directly) {
|
||||
update();
|
||||
}
|
||||
|
||||
return [cacheRef.current.visible, cacheRef.current.errors];
|
||||
}
|
19
components/form/hooks/useDebounce.ts
Normal file
19
components/form/hooks/useDebounce.ts
Normal file
@ -0,0 +1,19 @@
|
||||
import * as React from 'react';
|
||||
|
||||
export default function useDebounce<T>(value: T[]): T[] {
|
||||
const [cacheValue, setCacheValue] = React.useState(value);
|
||||
React.useEffect(() => {
|
||||
const timeout = setTimeout(
|
||||
() => {
|
||||
setCacheValue(value);
|
||||
},
|
||||
value.length ? 0 : 10,
|
||||
);
|
||||
|
||||
return () => {
|
||||
clearTimeout(timeout);
|
||||
};
|
||||
}, [value]);
|
||||
|
||||
return cacheValue;
|
||||
}
|
@ -302,22 +302,23 @@ Rule supports a config object, or a function returning config object:
|
||||
type Rule = RuleConfig | ((form: FormInstance) => RuleConfig);
|
||||
```
|
||||
|
||||
| Name | Description | Type |
|
||||
| --- | --- | --- |
|
||||
| defaultField | Validate rule for all array elements, valid when `type` is `array` | [rule](#Rule) |
|
||||
| enum | Match enum value. You need to set `type` to `enum` to enable this | any\[] |
|
||||
| fields | Validate rule for child elements, valid when `type` is `array` or `object` | Record<string, [rule](#Rule)> |
|
||||
| len | Length of string, number, array | number |
|
||||
| max | `type` required: max length of `string`, `number`, `array` | number |
|
||||
| message | Error message. Will auto generate by [template](#validateMessages) if not provided | string |
|
||||
| min | `type` required: min length of `string`, `number`, `array` | number |
|
||||
| pattern | Regex pattern | RegExp |
|
||||
| required | Required field | boolean |
|
||||
| transform | Transform value to the rule before validation | (value) => any |
|
||||
| type | Normally `string` \|`number` \|`boolean` \|`url` \| `email`. More type to ref [here](https://github.com/yiminghe/async-validator#type) | string |
|
||||
| validateTrigger | Set validate trigger event. Must be the sub set of `validateTrigger` in Form.Item | string \| string\[] |
|
||||
| validator | Customize validation rule. Accept Promise as return. See [example](#components-form-demo-register) | ([rule](#Rule), value) => Promise |
|
||||
| whitespace | Failed if only has whitespace, only work with `type: 'string'` rule | boolean |
|
||||
| Name | Description | Type | Version |
|
||||
| --- | --- | --- | --- |
|
||||
| defaultField | Validate rule for all array elements, valid when `type` is `array` | [rule](#Rule) | |
|
||||
| enum | Match enum value. You need to set `type` to `enum` to enable this | any\[] | |
|
||||
| fields | Validate rule for child elements, valid when `type` is `array` or `object` | Record<string, [rule](#Rule)> | |
|
||||
| len | Length of string, number, array | number | |
|
||||
| max | `type` required: max length of `string`, `number`, `array` | number | |
|
||||
| message | Error message. Will auto generate by [template](#validateMessages) if not provided | string | |
|
||||
| min | `type` required: min length of `string`, `number`, `array` | number | |
|
||||
| pattern | Regex pattern | RegExp | |
|
||||
| required | Required field | boolean | |
|
||||
| transform | Transform value to the rule before validation | (value) => any | |
|
||||
| type | Normally `string` \|`number` \|`boolean` \|`url` \| `email`. More type to ref [here](https://github.com/yiminghe/async-validator#type) | string | |
|
||||
| validateTrigger | Set validate trigger event. Must be the sub set of `validateTrigger` in Form.Item | string \| string\[] | |
|
||||
| validator | Customize validation rule. Accept Promise as return. See [example](#components-form-demo-register) | ([rule](#Rule), value) => Promise | |
|
||||
| warningOnly | Warning only. Not block form submit | boolean | 4.17.0 |
|
||||
| whitespace | Failed if only has whitespace, only work with `type: 'string'` rule | boolean | |
|
||||
|
||||
## Migrate to v4
|
||||
|
||||
|
@ -301,22 +301,23 @@ Rule 支持接收 object 进行配置,也支持 function 来动态获取 form
|
||||
type Rule = RuleConfig | ((form: FormInstance) => RuleConfig);
|
||||
```
|
||||
|
||||
| 名称 | 说明 | 类型 |
|
||||
| --- | --- | --- |
|
||||
| defaultField | 仅在 `type` 为 `array` 类型时有效,用于指定数组元素的校验规则 | [rule](#Rule) |
|
||||
| enum | 是否匹配枚举中的值(需要将 `type` 设置为 `enum`) | any\[] |
|
||||
| fields | 仅在 `type` 为 `array` 或 `object` 类型时有效,用于指定子元素的校验规则 | Record<string, [rule](#Rule)> |
|
||||
| len | string 类型时为字符串长度;number 类型时为确定数字; array 类型时为数组长度 | number |
|
||||
| max | 必须设置 `type`:string 类型为字符串最大长度;number 类型时为最大值;array 类型时为数组最大长度 | number |
|
||||
| message | 错误信息,不设置时会通过[模板](#validateMessages)自动生成 | string |
|
||||
| min | 必须设置 `type`:string 类型为字符串最小长度;number 类型时为最小值;array 类型时为数组最小长度 | number |
|
||||
| pattern | 正则表达式匹配 | RegExp |
|
||||
| required | 是否为必选字段 | boolean |
|
||||
| transform | 将字段值转换成目标值后进行校验 | (value) => any |
|
||||
| type | 类型,常见有 `string` \|`number` \|`boolean` \|`url` \| `email`。更多请参考[此处](https://github.com/yiminghe/async-validator#type) | string |
|
||||
| validateTrigger | 设置触发验证时机,必须是 Form.Item 的 `validateTrigger` 的子集 | string \| string\[] |
|
||||
| validator | 自定义校验,接收 Promise 作为返回值。[示例](#components-form-demo-register)参考 | ([rule](#Rule), value) => Promise |
|
||||
| whitespace | 如果字段仅包含空格则校验不通过,只在 `type: 'string'` 时生效 | boolean |
|
||||
| 名称 | 说明 | 类型 | 版本 |
|
||||
| --- | --- | --- | --- |
|
||||
| defaultField | 仅在 `type` 为 `array` 类型时有效,用于指定数组元素的校验规则 | [rule](#Rule) | |
|
||||
| enum | 是否匹配枚举中的值(需要将 `type` 设置为 `enum`) | any\[] | |
|
||||
| fields | 仅在 `type` 为 `array` 或 `object` 类型时有效,用于指定子元素的校验规则 | Record<string, [rule](#Rule)> | |
|
||||
| len | string 类型时为字符串长度;number 类型时为确定数字; array 类型时为数组长度 | number | |
|
||||
| max | 必须设置 `type`:string 类型为字符串最大长度;number 类型时为最大值;array 类型时为数组最大长度 | number | |
|
||||
| message | 错误信息,不设置时会通过[模板](#validateMessages)自动生成 | string | |
|
||||
| min | 必须设置 `type`:string 类型为字符串最小长度;number 类型时为最小值;array 类型时为数组最小长度 | number | |
|
||||
| pattern | 正则表达式匹配 | RegExp | |
|
||||
| required | 是否为必选字段 | boolean | |
|
||||
| transform | 将字段值转换成目标值后进行校验 | (value) => any | |
|
||||
| type | 类型,常见有 `string` \|`number` \|`boolean` \|`url` \| `email`。更多请参考[此处](https://github.com/yiminghe/async-validator#type) | string | |
|
||||
| validateTrigger | 设置触发验证时机,必须是 Form.Item 的 `validateTrigger` 的子集 | string \| string\[] | |
|
||||
| validator | 自定义校验,接收 Promise 作为返回值。[示例](#components-form-demo-register)参考 | ([rule](#Rule), value) => Promise | |
|
||||
| warningOnly | 仅警告,不阻塞表单提交 | boolean | 4.17.0 |
|
||||
| whitespace | 如果字段仅包含空格则校验不通过,只在 `type: 'string'` 时生效 | boolean | |
|
||||
|
||||
## 从 v3 升级到 v4
|
||||
|
||||
|
@ -61,9 +61,12 @@
|
||||
|
||||
margin-bottom: @form-item-margin-bottom;
|
||||
vertical-align: top;
|
||||
// We delay one frame (0.017s) here to let CSSMotion goes
|
||||
transition: margin-bottom @animation-duration-slow 0.017s linear;
|
||||
|
||||
&-with-help {
|
||||
margin-bottom: 0;
|
||||
transition: none;
|
||||
}
|
||||
|
||||
&-hidden,
|
||||
@ -179,10 +182,12 @@
|
||||
}
|
||||
}
|
||||
|
||||
// ==============================================================
|
||||
// = Explain =
|
||||
// ==============================================================
|
||||
&-explain,
|
||||
&-extra {
|
||||
clear: both;
|
||||
min-height: @form-item-margin-bottom;
|
||||
color: @text-color-secondary;
|
||||
font-size: @font-size-base;
|
||||
line-height: @line-height-base;
|
||||
@ -190,43 +195,64 @@
|
||||
.explainAndExtraDistance((@form-item-margin-bottom - @form-font-height) / 2);
|
||||
}
|
||||
|
||||
&-explain-connected {
|
||||
height: 0;
|
||||
min-height: 0;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
&-extra {
|
||||
min-height: @form-item-margin-bottom;
|
||||
}
|
||||
|
||||
.@{ant-prefix}-input-textarea-show-count {
|
||||
&::after {
|
||||
margin-bottom: -22px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.show-help-motion(@className, @keyframeName, @duration: @animation-duration-slow) {
|
||||
@name: ~'@{ant-prefix}-@{className}';
|
||||
.make-motion(@name, @keyframeName, @duration);
|
||||
.@{name}-enter,
|
||||
.@{name}-appear {
|
||||
opacity: 0;
|
||||
animation-timing-function: @ease-in-out;
|
||||
}
|
||||
.@{name}-leave {
|
||||
animation-timing-function: @ease-in-out;
|
||||
}
|
||||
}
|
||||
|
||||
.show-help-motion(show-help, antShowHelp, 0.3s);
|
||||
|
||||
@keyframes antShowHelpIn {
|
||||
0% {
|
||||
transform: translateY(-5px);
|
||||
opacity: 0;
|
||||
}
|
||||
100% {
|
||||
transform: translateY(0);
|
||||
&-with-help &-explain {
|
||||
height: auto;
|
||||
min-height: @form-item-margin-bottom;
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes antShowHelpOut {
|
||||
to {
|
||||
// >>>>>>>>>> Motion <<<<<<<<<<
|
||||
// Explain holder
|
||||
.@{ant-prefix}-show-help {
|
||||
transition: height @animation-duration-slow linear, min-height @animation-duration-slow linear,
|
||||
margin-bottom @animation-duration-slow @ease-in-out,
|
||||
opacity @animation-duration-slow @ease-in-out;
|
||||
|
||||
&-leave {
|
||||
min-height: @form-item-margin-bottom;
|
||||
|
||||
&-active {
|
||||
min-height: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Explain
|
||||
.@{ant-prefix}-show-help-item {
|
||||
overflow: hidden;
|
||||
transition: height @animation-duration-slow @ease-in-out,
|
||||
opacity @animation-duration-slow @ease-in-out, transform @animation-duration-slow @ease-in-out !important;
|
||||
|
||||
&-appear,
|
||||
&-enter {
|
||||
transform: translateY(-5px);
|
||||
opacity: 0;
|
||||
|
||||
&-active {
|
||||
transform: translateY(0);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
&-leave-active {
|
||||
transform: translateY(-5px);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -9,11 +9,11 @@
|
||||
// ========================= Explain =========================
|
||||
/* To support leave along ErrorList. We add additional className to handle explain style */
|
||||
&-explain {
|
||||
&&-error {
|
||||
&-error {
|
||||
color: @error-color;
|
||||
}
|
||||
|
||||
&&-warning {
|
||||
&-warning {
|
||||
color: @warning-color;
|
||||
}
|
||||
}
|
||||
|
@ -17,10 +17,11 @@ When a numeric value needs to be provided.
|
||||
| --- | --- | --- | --- | --- |
|
||||
| autoFocus | If get focus when component mounted | boolean | false | - |
|
||||
| bordered | Whether has border style | boolean | true | 4.12.0 |
|
||||
| controls | Whether to show `+-` controls | boolean | true | 4.17.0 |
|
||||
| decimalSeparator | Decimal separator | string | - | - |
|
||||
| defaultValue | The initial value | number | - | - |
|
||||
| disabled | If disable the input | boolean | false | - |
|
||||
| formatter | Specifies the format of the value presented | function(value: number \| string): string | - | - |
|
||||
| formatter | Specifies the format of the value presented | function(value: number \| string, info: { userTyping: boolean, input: string }): string | - | info: 4.17.0 |
|
||||
| keyboard | If enable keyboard behavior | boolean | true | 4.12.0 |
|
||||
| max | The max value | number | [Number.MAX_SAFE_INTEGER](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/MAX_SAFE_INTEGER) | - |
|
||||
| min | The min value | number | [Number.MIN_SAFE_INTEGER](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/MIN_SAFE_INTEGER) | - |
|
||||
|
@ -20,10 +20,11 @@ cover: https://gw.alipayobjects.com/zos/alicdn/XOS8qZ0kU/InputNumber.svg
|
||||
| --- | --- | --- | --- | --- |
|
||||
| autoFocus | 自动获取焦点 | boolean | false | - |
|
||||
| bordered | 是否有边框 | boolean | true | 4.12.0 |
|
||||
| controls | 是否显示增减按钮 | boolean | true | 4.17.0 |
|
||||
| decimalSeparator | 小数点 | string | - | - |
|
||||
| defaultValue | 初始值 | number | - | - |
|
||||
| disabled | 禁用 | boolean | false | - |
|
||||
| formatter | 指定输入框展示值的格式 | function(value: number \| string): string | - | - |
|
||||
| formatter | 指定输入框展示值的格式 | function(value: number \| string, info: { userTyping: boolean, input: string }): string | - | info: 4.17.0 |
|
||||
| keyboard | 是否启用键盘快捷行为 | boolean | true | 4.12.0 |
|
||||
| max | 最大值 | number | [Number.MAX_SAFE_INTEGER](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Number/MAX_SAFE_INTEGER) | - |
|
||||
| min | 最小值 | number | [Number.MIN_SAFE_INTEGER](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Number/MIN_SAFE_INTEGER) | - |
|
||||
|
@ -696,6 +696,7 @@ Array [
|
||||
>
|
||||
<span
|
||||
class="ant-cascader-picker-label"
|
||||
title="Zhejiang / Hangzhou / West Lake"
|
||||
>
|
||||
Zhejiang / Hangzhou / West Lake
|
||||
</span>
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -19,6 +19,7 @@ import LocaleProvider from '..';
|
||||
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';
|
||||
@ -53,6 +54,7 @@ import kuIQ from '../ku_IQ';
|
||||
import lvLV from '../lv_LV';
|
||||
import ltLT from '../lt_LT';
|
||||
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';
|
||||
@ -76,11 +78,13 @@ import viVN from '../vi_VN';
|
||||
import zhCN from '../zh_CN';
|
||||
import zhHK from '../zh_HK';
|
||||
import zhTW from '../zh_TW';
|
||||
import urPK from '../ur_PK';
|
||||
|
||||
const locales = [
|
||||
azAZ,
|
||||
arEG,
|
||||
bgBG,
|
||||
bnBD,
|
||||
byBY,
|
||||
caES,
|
||||
csCZ,
|
||||
@ -113,6 +117,7 @@ const locales = [
|
||||
kuIQ,
|
||||
ltLT,
|
||||
mkMK,
|
||||
mlIN,
|
||||
msMY,
|
||||
mnMN,
|
||||
nbNO,
|
||||
@ -138,6 +143,7 @@ const locales = [
|
||||
zhCN,
|
||||
zhHK,
|
||||
zhTW,
|
||||
urPK,
|
||||
];
|
||||
|
||||
const { Option } = Select;
|
||||
@ -229,9 +235,10 @@ describe('Locale Provider', () => {
|
||||
<ModalDemo />
|
||||
</LocaleProvider>,
|
||||
);
|
||||
const currentConfirmNode = document.querySelectorAll('.ant-modal-confirm')[
|
||||
document.querySelectorAll('.ant-modal-confirm').length - 1
|
||||
];
|
||||
const currentConfirmNode =
|
||||
document.querySelectorAll('.ant-modal-confirm')[
|
||||
document.querySelectorAll('.ant-modal-confirm').length - 1
|
||||
];
|
||||
let cancelButtonText = currentConfirmNode.querySelectorAll(
|
||||
'.ant-btn:not(.ant-btn-primary) span',
|
||||
)[0].innerHTML;
|
||||
|
3
components/locale-provider/bn_BD.tsx
Normal file
3
components/locale-provider/bn_BD.tsx
Normal file
@ -0,0 +1,3 @@
|
||||
import locale from '../locale/bn_BD';
|
||||
|
||||
export default locale;
|
3
components/locale-provider/ml_IN.tsx
Normal file
3
components/locale-provider/ml_IN.tsx
Normal file
@ -0,0 +1,3 @@
|
||||
import locale from '../locale/ml_IN';
|
||||
|
||||
export default locale;
|
3
components/locale-provider/ur_PK.tsx
Normal file
3
components/locale-provider/ur_PK.tsx
Normal file
@ -0,0 +1,3 @@
|
||||
import locale from '../locale/ur_PK';
|
||||
|
||||
export default locale;
|
134
components/locale/bn_BD.tsx
Normal file
134
components/locale/bn_BD.tsx
Normal file
@ -0,0 +1,134 @@
|
||||
/* eslint-disable no-template-curly-in-string */
|
||||
import Pagination from 'rc-pagination/lib/locale/bn_BD';
|
||||
import DatePicker from '../date-picker/locale/bn_BD';
|
||||
import TimePicker from '../time-picker/locale/bn_BD';
|
||||
import Calendar from '../calendar/locale/bn_BD';
|
||||
import { Locale } from '../locale-provider';
|
||||
|
||||
const typeTemplate = '${label} টি সঠিক ${type} নয়।';
|
||||
|
||||
const localeValues: Locale = {
|
||||
locale: 'bn-bd',
|
||||
Pagination,
|
||||
DatePicker,
|
||||
TimePicker,
|
||||
Calendar,
|
||||
global: {
|
||||
placeholder: 'অনুগ্রহ করে নির্বাচন করুন',
|
||||
},
|
||||
Table: {
|
||||
filterTitle: 'ফিল্টার মেনু',
|
||||
filterConfirm: 'ঠিক',
|
||||
filterReset: 'রিসেট',
|
||||
filterEmptyText: 'ফিল্টার নেই',
|
||||
emptyText: 'কোনও ডেটা নেই',
|
||||
selectAll: 'বর্তমান পৃষ্ঠা নির্বাচন করুন',
|
||||
selectInvert: 'বর্তমান পৃষ্ঠাটি উল্টে দিন',
|
||||
selectNone: 'সমস্ত ডেটা সাফ করুন',
|
||||
selectionAll: 'সমস্ত ডেটা নির্বাচন করুন',
|
||||
sortTitle: 'সাজান',
|
||||
expand: 'সারি প্রসারিত করুন',
|
||||
collapse: 'সারি সঙ্কুচিত করুন',
|
||||
triggerDesc: 'অবতরণকে সাজানোর জন্য ক্লিক করুন',
|
||||
triggerAsc: 'আরোহী বাছাই করতে ক্লিক করুন',
|
||||
cancelSort: 'বাছাই বাতিল করতে ক্লিক করুন',
|
||||
},
|
||||
Modal: {
|
||||
okText: 'ঠিক',
|
||||
cancelText: 'বাতিল',
|
||||
justOkText: 'ঠিক',
|
||||
},
|
||||
Popconfirm: {
|
||||
okText: 'ঠিক',
|
||||
cancelText: 'বাতিল',
|
||||
},
|
||||
Transfer: {
|
||||
titles: ['', ''],
|
||||
searchPlaceholder: 'এখানে অনুসন্ধান',
|
||||
itemUnit: 'আইটেম',
|
||||
itemsUnit: 'আইটেমসমূহ',
|
||||
remove: 'অপসারণ',
|
||||
selectCurrent: 'বর্তমান পৃষ্ঠা নির্বাচন করুন',
|
||||
removeCurrent: 'বর্তমান পৃষ্ঠাটি সরান',
|
||||
selectAll: 'সমস্ত ডেটা নির্বাচন করুন',
|
||||
removeAll: 'সমস্ত ডেটা সরান',
|
||||
selectInvert: 'বর্তমান পৃষ্ঠাটি উল্টে দিন',
|
||||
},
|
||||
Upload: {
|
||||
uploading: 'আপলোড হচ্ছে ...',
|
||||
removeFile: 'ফাইল সরান',
|
||||
uploadError: 'আপলোডে সমস্যা',
|
||||
previewFile: 'ফাইলের পূর্বরূপ',
|
||||
downloadFile: 'ফাইল ডাউনলোড',
|
||||
},
|
||||
Empty: {
|
||||
description: 'কোনও ডেটা নেই',
|
||||
},
|
||||
Icon: {
|
||||
icon: 'আইকন',
|
||||
},
|
||||
Text: {
|
||||
edit: 'সম্পাদনা',
|
||||
copy: 'অনুলিপি',
|
||||
copied: 'অনুলিপি হয়েছে',
|
||||
expand: 'বিস্তৃত করা',
|
||||
},
|
||||
PageHeader: {
|
||||
back: 'পেছনে',
|
||||
},
|
||||
Form: {
|
||||
optional: '(ঐচ্ছিক)',
|
||||
defaultValidateMessages: {
|
||||
default: '${label} এর ক্ষেত্রে ক্ষেত্র বৈধতা ত্রুটি',
|
||||
required: 'অনুগ্রহ করে ${label} প্রবেশ করান',
|
||||
enum: '${label} অবশ্যই [${enum}] এর মধ্যে একটি হতে হবে',
|
||||
whitespace: '${label} ফাঁকা অক্ষর হতে পারে না',
|
||||
date: {
|
||||
format: '${label} তারিখ ফরমেট সঠিক নয়।',
|
||||
parse: '${label} তারিখে রূপান্তর করা যায় না',
|
||||
invalid: '${label} একটি সঠিক তারিখ না।',
|
||||
},
|
||||
types: {
|
||||
string: typeTemplate,
|
||||
method: typeTemplate,
|
||||
array: typeTemplate,
|
||||
object: typeTemplate,
|
||||
number: typeTemplate,
|
||||
date: typeTemplate,
|
||||
boolean: typeTemplate,
|
||||
integer: typeTemplate,
|
||||
float: typeTemplate,
|
||||
regexp: typeTemplate,
|
||||
email: typeTemplate,
|
||||
url: typeTemplate,
|
||||
hex: typeTemplate,
|
||||
},
|
||||
string: {
|
||||
len: '${label} অবশ্যই ${len} অক্ষরের হতে হবে।',
|
||||
min: '${label} অবশ্যই অন্তত ${min} অক্ষরের হতে হবে।',
|
||||
max: '${label} অবশ্যই ${max} পর্যন্ত অক্ষরের হতে হবে।',
|
||||
range: '${label} অবশ্যই ${min}-${max} অক্ষরের এর মধ্যে হতে হবে।',
|
||||
},
|
||||
number: {
|
||||
len: '${label} অবশ্যই ${len} এর সমান হতে হবে',
|
||||
min: '${label} অবশ্যই সর্বনিম্ন ${min} হতে হবে',
|
||||
max: '${label} অবশ্যই সর্বোচ্চ ${max} হতে হবে',
|
||||
range: '${label} অবশ্যই ${min}-${max} এর মধ্যে হতে হবে',
|
||||
},
|
||||
array: {
|
||||
len: 'অবশ্যই ${len} ${label} হতে হবে',
|
||||
min: 'কমপক্ষে ${min} ${label}',
|
||||
max: 'সর্বাধিক হিসাবে ${max} ${label}',
|
||||
range: '${label} এর পরিমাণ অবশ্যই ${min}-${max} এর মধ্যে হতে হবে',
|
||||
},
|
||||
pattern: {
|
||||
mismatch: '${label} এই ${pattern} প্যাটার্নের সাথে মেলে না',
|
||||
},
|
||||
},
|
||||
},
|
||||
Image: {
|
||||
preview: 'পূর্বরূপ',
|
||||
},
|
||||
};
|
||||
|
||||
export default localeValues;
|
134
components/locale/ml_IN.tsx
Normal file
134
components/locale/ml_IN.tsx
Normal file
@ -0,0 +1,134 @@
|
||||
/* eslint-disable no-template-curly-in-string */
|
||||
import Pagination from 'rc-pagination/lib/locale/ml_IN';
|
||||
import DatePicker from '../date-picker/locale/ml_IN';
|
||||
import TimePicker from '../time-picker/locale/ml_IN';
|
||||
import Calendar from '../calendar/locale/ml_IN';
|
||||
import { Locale } from '../locale-provider';
|
||||
|
||||
const typeTemplate = '${label} അസാധുവായ ${type} ആണ്';
|
||||
|
||||
const localeValues: Locale = {
|
||||
locale: 'ml',
|
||||
Pagination,
|
||||
DatePicker,
|
||||
TimePicker,
|
||||
Calendar,
|
||||
global: {
|
||||
placeholder: 'ദയവായി തിരഞ്ഞെടുക്കുക',
|
||||
},
|
||||
Table: {
|
||||
filterTitle: 'ഫിൽറ്റർ',
|
||||
filterConfirm: 'ശരിയാണ്',
|
||||
filterReset: 'പുനഃക്രമീകരിക്കുക',
|
||||
filterEmptyText: 'ഫിൽറ്ററുകളൊന്നുമില്ല',
|
||||
emptyText: 'ഡാറ്റയൊന്നുമില്ല',
|
||||
selectAll: 'നിലവിലെ പേജ് തിരഞ്ഞെടുക്കുക',
|
||||
selectInvert: 'നിലവിലെ പേജിൽ ഇല്ലാത്തത് തിരഞ്ഞെടുക്കുക',
|
||||
selectNone: 'എല്ലാ ഡാറ്റയും നീക്കം ചെയ്യുക',
|
||||
selectionAll: 'എല്ലാ ഡാറ്റയും തിരഞ്ഞെടുക്കുക',
|
||||
sortTitle: 'ക്രമമാക്കുക',
|
||||
expand: 'വരി വികസിപ്പിക്കുക',
|
||||
collapse: 'വരി ചുരുക്കുക',
|
||||
triggerDesc: 'അവരോഹണ ക്രമത്തിനായി ക്ലിക്ക് ചെയ്യുക',
|
||||
triggerAsc: 'ആരോഹണ ക്രമത്തിനായി ക്ലിക്ക് ചെയ്യുക',
|
||||
cancelSort: 'ക്രമീകരണം ഒഴിവാക്കുന്നതിനായി ക്ലിക്ക് ചെയ്യുക',
|
||||
},
|
||||
Modal: {
|
||||
okText: 'ശരിയാണ്',
|
||||
cancelText: 'റദ്ദാക്കുക',
|
||||
justOkText: 'ശരിയാണ്',
|
||||
},
|
||||
Popconfirm: {
|
||||
okText: 'ശരിയാണ്',
|
||||
cancelText: 'റദ്ദാക്കുക',
|
||||
},
|
||||
Transfer: {
|
||||
titles: ['', ''],
|
||||
searchPlaceholder: 'ഇവിടെ തിരയുക',
|
||||
itemUnit: 'ഇനം',
|
||||
itemsUnit: 'ഇനങ്ങൾ',
|
||||
remove: 'നീക്കം ചെയ്യുക',
|
||||
selectCurrent: 'നിലവിലെ പേജ് തിരഞ്ഞെടുക്കുക',
|
||||
removeCurrent: 'നിലവിലെ പേജ് നീക്കം ചെയ്യുക',
|
||||
selectAll: 'എല്ലാ ഡാറ്റയും തിരഞ്ഞെടുക്കുക',
|
||||
removeAll: 'എല്ലാ ഡാറ്റയും നീക്കം ചെയ്യുക',
|
||||
selectInvert: 'നിലവിലെ പേജിൽ ഇല്ലാത്തത് തിരഞ്ഞെടുക്കുക',
|
||||
},
|
||||
Upload: {
|
||||
uploading: 'അപ്ലോഡ് ചെയ്തു കൊണ്ടിരിക്കുന്നു...',
|
||||
removeFile: 'ഫയൽ നീക്കം ചെയ്യുക',
|
||||
uploadError: 'അപ്ലോഡിൽ പിശക് സംഭവിച്ചിരിക്കുന്നു',
|
||||
previewFile: 'ഫയൽ പ്രിവ്യൂ ചെയ്യുക',
|
||||
downloadFile: 'ഫയൽ ഡൗൺലോഡ് ചെയ്യുക',
|
||||
},
|
||||
Empty: {
|
||||
description: 'ഡാറ്റയൊന്നുമില്ല',
|
||||
},
|
||||
Icon: {
|
||||
icon: 'ഐക്കൺ',
|
||||
},
|
||||
Text: {
|
||||
edit: 'തിരുത്തുക',
|
||||
copy: 'കോപ്പി ചെയ്യുക',
|
||||
copied: 'കോപ്പി ചെയ്തു',
|
||||
expand: 'വികസിപ്പിക്കുക',
|
||||
},
|
||||
PageHeader: {
|
||||
back: 'തിരികെ',
|
||||
},
|
||||
Form: {
|
||||
optional: '(optional)',
|
||||
defaultValidateMessages: {
|
||||
default: '${label} ഫീൽഡിൽ വാലിഡേഷൻ പിശകുണ്ട്',
|
||||
required: 'ദയവായി ${label} രേഖപ്പെടുത്തുക',
|
||||
enum: '${label} നിർബന്ധമായും [${enum}]-ൽ നിന്നുള്ളതായിരിക്കണം',
|
||||
whitespace: '${label} ശൂന്യമായി വെക്കാനാകില്ല',
|
||||
date: {
|
||||
format: '${label} തീയതി രൂപരേഖ അസാധുവാണ്',
|
||||
parse: '${label} ഒരു തീയതിയാക്കി മാറ്റാൻ സാധിക്കില്ല',
|
||||
invalid: '${label} ഒരു അസാധുവായ തീയതി ആണ്',
|
||||
},
|
||||
types: {
|
||||
string: typeTemplate,
|
||||
method: typeTemplate,
|
||||
array: typeTemplate,
|
||||
object: typeTemplate,
|
||||
number: typeTemplate,
|
||||
date: typeTemplate,
|
||||
boolean: typeTemplate,
|
||||
integer: typeTemplate,
|
||||
float: typeTemplate,
|
||||
regexp: typeTemplate,
|
||||
email: typeTemplate,
|
||||
url: typeTemplate,
|
||||
hex: typeTemplate,
|
||||
},
|
||||
string: {
|
||||
len: '${label} നിർബന്ധമായും ${len} അക്ഷരങ്ങൾ ഉണ്ടായിരിക്കണം',
|
||||
min: '${label} നിർബന്ധമായും ${min} അക്ഷരങ്ങൾ എങ്കിലും ഉണ്ടായിരിക്കണം',
|
||||
max: '${label} നിർബന്ധമായും ${max} അക്ഷരങ്ങളിൽ കൂടാൻ പാടില്ല',
|
||||
range: '${label} നിർബന്ധമായും ${min}-നും ${max}-നും ഇടയിൽ അക്ഷരങ്ങൾ ഉള്ളതായിരിക്കണം',
|
||||
},
|
||||
number: {
|
||||
len: '${label} നിർബന്ധമായും ${len}-നു തുല്യമായിരിക്കണം',
|
||||
min: '${label} നിർബന്ധമായും ${min}-ൽ കുറയാൻ പാടില്ല',
|
||||
max: '${label} നിർബന്ധമായും ${max}-ൽ കൂടാൻ പാടില്ല',
|
||||
range: '${label} നിർബന്ധമായും ${min}-നും ${max}-നും ഇടയിൽ ആയിരിക്കണം',
|
||||
},
|
||||
array: {
|
||||
len: 'നിർബന്ധമായും ${len} ${label} ഉണ്ടായിരിക്കണം',
|
||||
min: 'കുറഞ്ഞപക്ഷം ${min} ${label} എങ്കിലും ഉണ്ടായിരിക്കണം',
|
||||
max: 'അങ്ങേയറ്റം ${max} ${label} ആയിരിക്കണം',
|
||||
range: '${label}-ന്റെ എണ്ണം നിർബന്ധമായും ${min}-നും ${max}-നും ഇടയിൽ ആയിരിക്കണം',
|
||||
},
|
||||
pattern: {
|
||||
mismatch: '${label} ${pattern} മാതൃകയുമായി യോജിക്കുന്നില്ല',
|
||||
},
|
||||
},
|
||||
},
|
||||
Image: {
|
||||
preview: 'പ്രിവ്യൂ',
|
||||
},
|
||||
};
|
||||
|
||||
export default localeValues;
|
134
components/locale/ur_PK.tsx
Normal file
134
components/locale/ur_PK.tsx
Normal file
@ -0,0 +1,134 @@
|
||||
/* eslint-disable no-template-curly-in-string */
|
||||
import Pagination from 'rc-pagination/lib/locale/ur_PK';
|
||||
import DatePicker from '../date-picker/locale/ur_PK';
|
||||
import TimePicker from '../time-picker/locale/ur_PK';
|
||||
import Calendar from '../calendar/locale/ur_PK';
|
||||
import { Locale } from '../locale-provider';
|
||||
|
||||
const typeTemplate = '${label} درست نہیں ہے ${type}';
|
||||
|
||||
const localeValues: Locale = {
|
||||
locale: 'ur',
|
||||
Pagination,
|
||||
DatePicker,
|
||||
TimePicker,
|
||||
Calendar,
|
||||
global: {
|
||||
placeholder: 'منتخب کریں',
|
||||
},
|
||||
Table: {
|
||||
filterTitle: 'فلٹر مینو',
|
||||
filterConfirm: 'ٹھیک ہے',
|
||||
filterReset: 'ری سیٹ کریں',
|
||||
filterEmptyText: 'فلٹرز نہیں',
|
||||
emptyText: 'کوئی ڈیٹا نہیں',
|
||||
selectAll: 'موجودہ صفحہ منتخب کریں',
|
||||
selectInvert: 'موجودہ صفحے کو الٹ دیں',
|
||||
selectNone: 'تمام ڈیٹا صاف کریں',
|
||||
selectionAll: 'تمام ڈیٹا کو منتخب کریں',
|
||||
sortTitle: 'ترتیب دیں',
|
||||
expand: 'پھیلائیں',
|
||||
collapse: 'سمیٹیں',
|
||||
triggerDesc: 'نزولی کو ترتیب دینے کیلئے کلک کریں',
|
||||
triggerAsc: 'چڑھنے کو ترتیب دینے کیلئے کلک کریں',
|
||||
cancelSort: 'ترتیب کو منسوخ کرنے کیلئے دبائیں',
|
||||
},
|
||||
Modal: {
|
||||
okText: 'ٹھیک ہے',
|
||||
cancelText: 'منسوخ کریں',
|
||||
justOkText: 'ٹھیک ہے',
|
||||
},
|
||||
Popconfirm: {
|
||||
okText: 'ٹھیک ہے',
|
||||
cancelText: 'منسوخ کریں',
|
||||
},
|
||||
Transfer: {
|
||||
titles: ['', ''],
|
||||
searchPlaceholder: 'یہاں تلاش کریں',
|
||||
itemUnit: 'شے',
|
||||
itemsUnit: 'اشیاء',
|
||||
remove: 'ہٹائیں',
|
||||
selectCurrent: 'موجودہ صفحہ منتخب کریں',
|
||||
removeCurrent: 'موجودہ صفحہ ہٹائیں',
|
||||
selectAll: 'تمام ڈیٹا کو منتخب کریں',
|
||||
removeAll: 'تمام ڈیٹا کو ہٹا دیں',
|
||||
selectInvert: 'موجودہ صفحے کو الٹ دیں',
|
||||
},
|
||||
Upload: {
|
||||
uploading: 'اپ لوڈ ہو رہا ہے…',
|
||||
removeFile: 'فائل کو ہٹا دیں',
|
||||
uploadError: 'اپ لوڈ کی خرابی',
|
||||
previewFile: 'پیش نظار فائل',
|
||||
downloadFile: 'فائل ڈاؤن لوڈ کریں',
|
||||
},
|
||||
Empty: {
|
||||
description: 'کوئی ڈیٹا نہیں',
|
||||
},
|
||||
Icon: {
|
||||
icon: 'آئیکن',
|
||||
},
|
||||
Text: {
|
||||
edit: 'ترمیم',
|
||||
copy: 'کاپی',
|
||||
copied: 'کاپی ہوگیا',
|
||||
expand: 'پھیلائیں',
|
||||
},
|
||||
PageHeader: {
|
||||
back: 'پیچھے',
|
||||
},
|
||||
Form: {
|
||||
optional: '(اختیاری)',
|
||||
defaultValidateMessages: {
|
||||
default: ' ${label} کیلئے فیلڈ کی توثیق میں نقص',
|
||||
required: 'درج کریں ${label}',
|
||||
enum: '${label} ایک ہونا ضروری ہے [${enum}]',
|
||||
whitespace: '${label} خالی نہیں ہوسکتا',
|
||||
date: {
|
||||
format: '${label} تاریخ کی شکل غلط ہے',
|
||||
parse: '${label} تاریخ میں تبدیل نہیں کیا جاسکتا',
|
||||
invalid: '${label} غلط تاریخ ہے',
|
||||
},
|
||||
types: {
|
||||
string: typeTemplate,
|
||||
method: typeTemplate,
|
||||
array: typeTemplate,
|
||||
object: typeTemplate,
|
||||
number: typeTemplate,
|
||||
date: typeTemplate,
|
||||
boolean: typeTemplate,
|
||||
integer: typeTemplate,
|
||||
float: typeTemplate,
|
||||
regexp: typeTemplate,
|
||||
email: typeTemplate,
|
||||
url: typeTemplate,
|
||||
hex: typeTemplate,
|
||||
},
|
||||
string: {
|
||||
len: '${label} ضروری ہے ${len} حروف',
|
||||
min: '${label} کم از کم ہونا چاہئے ${min} حروف',
|
||||
max: '${label} تک ہونا چاہئے ${max} حروف',
|
||||
range: '${label} کے درمیان ہونا چاہئے ${min}-${max} حروف',
|
||||
},
|
||||
number: {
|
||||
len: '${label} کے برابر ہونا چاہئے ${len}',
|
||||
min: '${label} کم از کم ہونا چاہئے ${min}',
|
||||
max: '${label} زیادہ سے زیادہ ہونا چاہئے ${max}',
|
||||
range: '${label} کے درمیان ہونا چاہئے ${min}-${max}',
|
||||
},
|
||||
array: {
|
||||
len: 'ضروری ہے ${len} ${label}',
|
||||
min: 'کم از کم ${min} ${label}',
|
||||
max: 'زیادہ سے زیادہ ${max} ${label}',
|
||||
range: 'کی رقم ${label} کے درمیان ہونا چاہئے ${min}-${max}',
|
||||
},
|
||||
pattern: {
|
||||
mismatch: '${label} پیٹرن سے ملتا نہیں ہے ${pattern}',
|
||||
},
|
||||
},
|
||||
},
|
||||
Image: {
|
||||
preview: 'پیش نظارہ',
|
||||
},
|
||||
};
|
||||
|
||||
export default localeValues;
|
32
components/menu/MenuDivider.tsx
Normal file
32
components/menu/MenuDivider.tsx
Normal file
@ -0,0 +1,32 @@
|
||||
import * as React from 'react';
|
||||
import classNames from 'classnames';
|
||||
import { Divider } from 'rc-menu';
|
||||
import { ConfigContext } from '../config-provider';
|
||||
|
||||
export interface MenuDividerProps extends React.HTMLAttributes<HTMLLIElement> {
|
||||
className?: string;
|
||||
prefixCls?: string;
|
||||
style?: React.CSSProperties;
|
||||
dashed?: boolean;
|
||||
}
|
||||
|
||||
const MenuDivider: React.FC<MenuDividerProps> = ({
|
||||
prefixCls: customizePrefixCls,
|
||||
className,
|
||||
dashed,
|
||||
...restProps
|
||||
}) => {
|
||||
const { getPrefixCls } = React.useContext(ConfigContext);
|
||||
|
||||
const prefixCls = getPrefixCls('menu', customizePrefixCls);
|
||||
const classString = classNames(
|
||||
{
|
||||
[`${prefixCls}-item-divider-dashed`]: !!dashed,
|
||||
},
|
||||
className,
|
||||
);
|
||||
|
||||
return <Divider className={classString} {...restProps} />;
|
||||
};
|
||||
|
||||
export default MenuDivider;
|
@ -821,4 +821,25 @@ describe('Menu', () => {
|
||||
expect(wrapper.find('.ant-menu-inline-collapsed-noicon').first().text()).toEqual('L');
|
||||
expect(wrapper.find('.ant-menu-inline-collapsed-noicon').last().text()).toEqual('B');
|
||||
});
|
||||
|
||||
it('divider should show', () => {
|
||||
const wrapper = mount(
|
||||
<Menu mode="vertical">
|
||||
<SubMenu key="sub1" title="Navigation One">
|
||||
<Menu.Item key="1">Option 1</Menu.Item>
|
||||
</SubMenu>
|
||||
<Menu.Divider dashed />
|
||||
<SubMenu key="sub2" title="Navigation Two">
|
||||
<Menu.Item key="2">Option 2</Menu.Item>
|
||||
</SubMenu>
|
||||
<Menu.Divider />
|
||||
<SubMenu key="sub4" title="Navigation Three">
|
||||
<Menu.Item key="3">Option 3</Menu.Item>
|
||||
</SubMenu>
|
||||
</Menu>,
|
||||
);
|
||||
|
||||
expect(wrapper.find('li.ant-menu-item-divider').length).toBe(2);
|
||||
expect(wrapper.find('li.ant-menu-item-divider-dashed').length).toBe(1);
|
||||
});
|
||||
});
|
||||
|
@ -30,7 +30,7 @@ ReactDOM.render(
|
||||
<Menu.Item key="1">Option 1</Menu.Item>
|
||||
<Menu.Item key="2">Option 2</Menu.Item>
|
||||
</Menu.ItemGroup>
|
||||
<Menu.ItemGroup title="Iteom 2">
|
||||
<Menu.ItemGroup title="Item 2">
|
||||
<Menu.Item key="3">Option 3</Menu.Item>
|
||||
<Menu.Item key="4">Option 4</Menu.Item>
|
||||
</Menu.ItemGroup>
|
||||
|
@ -111,6 +111,10 @@ More layouts with navigation: [Layout](/components/layout).
|
||||
|
||||
Divider line in between menu items, only used in vertical popup Menu or Dropdown Menu.
|
||||
|
||||
| Param | Description | Type | Default value | Version |
|
||||
| ------ | ---------------------- | ------- | ------------- | ------- |
|
||||
| dashed | Whether line is dashed | boolean | false | 4.17.0 |
|
||||
|
||||
## FAQ
|
||||
|
||||
### Why will Menu's children be rendered twice?
|
||||
|
@ -1,5 +1,5 @@
|
||||
import * as React from 'react';
|
||||
import RcMenu, { Divider, ItemGroup, MenuProps as RcMenuProps } from 'rc-menu';
|
||||
import RcMenu, { ItemGroup, MenuProps as RcMenuProps } from 'rc-menu';
|
||||
import classNames from 'classnames';
|
||||
import omit from 'rc-util/lib/omit';
|
||||
import EllipsisOutlined from '@ant-design/icons/EllipsisOutlined';
|
||||
@ -11,6 +11,9 @@ import { SiderContext, SiderContextProps } from '../layout/Sider';
|
||||
import collapseMotion from '../_util/motion';
|
||||
import { cloneElement } from '../_util/reactNode';
|
||||
import MenuContext, { MenuTheme } from './MenuContext';
|
||||
import MenuDivider from './MenuDivider';
|
||||
|
||||
export { MenuDividerProps } from './MenuDivider';
|
||||
|
||||
export { MenuItemGroupProps } from 'rc-menu';
|
||||
|
||||
@ -113,7 +116,7 @@ class InternalMenu extends React.Component<InternalMenuProps> {
|
||||
|
||||
// We should keep this as ref-able
|
||||
class Menu extends React.Component<MenuProps, {}> {
|
||||
static Divider = Divider;
|
||||
static Divider = MenuDivider;
|
||||
|
||||
static Item = Item;
|
||||
|
||||
|
@ -112,6 +112,10 @@ cover: https://gw.alipayobjects.com/zos/alicdn/3XZcjGpvK/Menu.svg
|
||||
|
||||
菜单项分割线,只用在弹出菜单内。
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|
||||
| ------ | -------- | ------- | ------ | ------ |
|
||||
| dashed | 是否虚线 | boolean | false | 4.17.0 |
|
||||
|
||||
## FAQ
|
||||
|
||||
### 为何 Menu 的子元素会渲染两次?
|
||||
|
@ -118,10 +118,15 @@
|
||||
}
|
||||
|
||||
&-item-divider {
|
||||
height: 1px;
|
||||
overflow: hidden;
|
||||
line-height: 0;
|
||||
background-color: @border-color-split;
|
||||
border-color: @border-color-split;
|
||||
border-style: solid;
|
||||
border-width: 1px 0 0;
|
||||
}
|
||||
|
||||
&-item-divider-dashed {
|
||||
border-style: dashed;
|
||||
}
|
||||
|
||||
&-horizontal &-item,
|
||||
@ -238,12 +243,8 @@
|
||||
}
|
||||
|
||||
& > &-item-divider {
|
||||
height: 1px;
|
||||
margin: 1px 0;
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
line-height: 0;
|
||||
background-color: @border-color-split;
|
||||
}
|
||||
|
||||
&-submenu {
|
||||
|
@ -96,19 +96,20 @@ describe('message.config', () => {
|
||||
});
|
||||
|
||||
it('should be able to global config rootPrefixCls', () => {
|
||||
ConfigProvider.config({ prefixCls: 'prefix-test' });
|
||||
ConfigProvider.config({ prefixCls: 'prefix-test', iconPrefixCls: 'bamboo' });
|
||||
message.info('last');
|
||||
expect(document.querySelectorAll('.ant-message-notice').length).toBe(0);
|
||||
expect(document.querySelectorAll('.prefix-test-message-notice').length).toBe(1);
|
||||
ConfigProvider.config({ prefixCls: 'ant' });
|
||||
expect(document.querySelectorAll('.ant-message-notice')).toHaveLength(0);
|
||||
expect(document.querySelectorAll('.prefix-test-message-notice')).toHaveLength(1);
|
||||
expect(document.querySelectorAll('.bamboo-info-circle')).toHaveLength(1);
|
||||
ConfigProvider.config({ prefixCls: 'ant', iconPrefixCls: null });
|
||||
});
|
||||
it('should be able to config prefixCls', () => {
|
||||
message.config({
|
||||
prefixCls: 'prefix-test',
|
||||
});
|
||||
message.info('last');
|
||||
expect(document.querySelectorAll('.ant-message-notice').length).toBe(0);
|
||||
expect(document.querySelectorAll('.prefix-test-notice').length).toBe(1);
|
||||
expect(document.querySelectorAll('.ant-message-notice')).toHaveLength(0);
|
||||
expect(document.querySelectorAll('.prefix-test-notice')).toHaveLength(1);
|
||||
message.config({
|
||||
prefixCls: '', // can be set to empty, ant default value is set in ConfigProvider
|
||||
});
|
||||
@ -119,7 +120,7 @@ describe('message.config', () => {
|
||||
transitionName: '',
|
||||
});
|
||||
message.info('last');
|
||||
expect(document.querySelectorAll('.ant-move-up-enter').length).toBe(0);
|
||||
expect(document.querySelectorAll('.ant-move-up-enter')).toHaveLength(0);
|
||||
message.config({
|
||||
transitionName: 'ant-move-up',
|
||||
});
|
||||
|
@ -11,7 +11,7 @@ import CloseCircleFilled from '@ant-design/icons/CloseCircleFilled';
|
||||
import CheckCircleFilled from '@ant-design/icons/CheckCircleFilled';
|
||||
import InfoCircleFilled from '@ant-design/icons/InfoCircleFilled';
|
||||
import createUseMessage from './hooks/useMessage';
|
||||
import { globalConfig } from '../config-provider';
|
||||
import ConfigProvider, { globalConfig } from '../config-provider';
|
||||
|
||||
type NoticeType = 'info' | 'success' | 'error' | 'warning' | 'loading';
|
||||
|
||||
@ -74,16 +74,18 @@ function getRCNotificationInstance(
|
||||
callback: (info: {
|
||||
prefixCls: string;
|
||||
rootPrefixCls: string;
|
||||
iconPrefixCls: string;
|
||||
instance: RCNotificationInstance;
|
||||
}) => void,
|
||||
) {
|
||||
const { prefixCls: customizePrefixCls } = args;
|
||||
const { getPrefixCls, getRootPrefixCls } = globalConfig();
|
||||
const { getPrefixCls, getRootPrefixCls, getIconPrefixCls } = globalConfig();
|
||||
const prefixCls = getPrefixCls('message', customizePrefixCls || localPrefixCls);
|
||||
const rootPrefixCls = getRootPrefixCls(args.rootPrefixCls, prefixCls);
|
||||
const iconPrefixCls = getIconPrefixCls();
|
||||
|
||||
if (messageInstance) {
|
||||
callback({ prefixCls, rootPrefixCls, instance: messageInstance });
|
||||
callback({ prefixCls, rootPrefixCls, iconPrefixCls, instance: messageInstance });
|
||||
return;
|
||||
}
|
||||
|
||||
@ -97,7 +99,7 @@ function getRCNotificationInstance(
|
||||
|
||||
RCNotification.newInstance(instanceConfig, (instance: any) => {
|
||||
if (messageInstance) {
|
||||
callback({ prefixCls, rootPrefixCls, instance: messageInstance });
|
||||
callback({ prefixCls, rootPrefixCls, iconPrefixCls, instance: messageInstance });
|
||||
return;
|
||||
}
|
||||
messageInstance = instance;
|
||||
@ -106,7 +108,7 @@ function getRCNotificationInstance(
|
||||
(messageInstance as any).config = instanceConfig;
|
||||
}
|
||||
|
||||
callback({ prefixCls, rootPrefixCls, instance });
|
||||
callback({ prefixCls, rootPrefixCls, iconPrefixCls, instance });
|
||||
});
|
||||
}
|
||||
|
||||
@ -139,7 +141,11 @@ export interface ArgsProps {
|
||||
onClick?: (e: React.MouseEvent<HTMLDivElement>) => void;
|
||||
}
|
||||
|
||||
function getRCNoticeProps(args: ArgsProps, prefixCls: string): NoticeContent {
|
||||
function getRCNoticeProps(
|
||||
args: ArgsProps,
|
||||
prefixCls: string,
|
||||
iconPrefixCls?: string,
|
||||
): NoticeContent {
|
||||
const duration = args.duration !== undefined ? args.duration : defaultDuration;
|
||||
const IconComponent = typeToIcon[args.type];
|
||||
const messageClass = classNames(`${prefixCls}-custom-content`, {
|
||||
@ -152,10 +158,12 @@ function getRCNoticeProps(args: ArgsProps, prefixCls: string): NoticeContent {
|
||||
style: args.style || {},
|
||||
className: args.className,
|
||||
content: (
|
||||
<div className={messageClass}>
|
||||
{args.icon || (IconComponent && <IconComponent />)}
|
||||
<span>{args.content}</span>
|
||||
</div>
|
||||
<ConfigProvider iconPrefixCls={iconPrefixCls}>
|
||||
<div className={messageClass}>
|
||||
{args.icon || (IconComponent && <IconComponent />)}
|
||||
<span>{args.content}</span>
|
||||
</div>
|
||||
</ConfigProvider>
|
||||
),
|
||||
onClose: args.onClose,
|
||||
onClick: args.onClick,
|
||||
@ -172,8 +180,10 @@ function notice(args: ArgsProps): MessageType {
|
||||
return resolve(true);
|
||||
};
|
||||
|
||||
getRCNotificationInstance(args, ({ prefixCls, instance }) => {
|
||||
instance.notice(getRCNoticeProps({ ...args, key: target, onClose: callback }, prefixCls));
|
||||
getRCNotificationInstance(args, ({ prefixCls, iconPrefixCls, instance }) => {
|
||||
instance.notice(
|
||||
getRCNoticeProps({ ...args, key: target, onClose: callback }, prefixCls, iconPrefixCls),
|
||||
);
|
||||
});
|
||||
});
|
||||
const result: any = () => {
|
||||
|
@ -1,7 +1,7 @@
|
||||
import * as React from 'react';
|
||||
import classNames from 'classnames';
|
||||
import Dialog, { ModalFuncProps } from './Modal';
|
||||
import ActionButton from './ActionButton';
|
||||
import ActionButton from '../_util/ActionButton';
|
||||
import devWarning from '../_util/devWarning';
|
||||
import ConfigProvider from '../config-provider';
|
||||
import { getTransitionName } from '../_util/motion';
|
||||
@ -11,6 +11,7 @@ interface ConfirmDialogProps extends ModalFuncProps {
|
||||
close: (...args: any[]) => void;
|
||||
autoFocusButton?: null | 'ok' | 'cancel';
|
||||
rootPrefixCls: string;
|
||||
iconPrefixCls?: string;
|
||||
}
|
||||
|
||||
const ConfirmDialog = (props: ConfirmDialogProps) => {
|
||||
@ -33,6 +34,7 @@ const ConfirmDialog = (props: ConfirmDialogProps) => {
|
||||
direction,
|
||||
prefixCls,
|
||||
rootPrefixCls,
|
||||
iconPrefixCls,
|
||||
bodyStyle,
|
||||
closable = false,
|
||||
closeIcon,
|
||||
@ -68,7 +70,7 @@ const ConfirmDialog = (props: ConfirmDialogProps) => {
|
||||
const cancelButton = okCancel && (
|
||||
<ActionButton
|
||||
actionFn={onCancel}
|
||||
closeModal={close}
|
||||
close={close}
|
||||
autoFocus={autoFocusButton === 'cancel'}
|
||||
buttonProps={cancelButtonProps}
|
||||
prefixCls={`${rootPrefixCls}-btn`}
|
||||
@ -78,33 +80,33 @@ const ConfirmDialog = (props: ConfirmDialogProps) => {
|
||||
);
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
prefixCls={prefixCls}
|
||||
className={classString}
|
||||
wrapClassName={classNames({ [`${contentPrefixCls}-centered`]: !!props.centered })}
|
||||
onCancel={() => close({ triggerCancel: true })}
|
||||
visible={visible}
|
||||
title=""
|
||||
footer=""
|
||||
transitionName={getTransitionName(rootPrefixCls, 'zoom', props.transitionName)}
|
||||
maskTransitionName={getTransitionName(rootPrefixCls, 'fade', props.maskTransitionName)}
|
||||
mask={mask}
|
||||
maskClosable={maskClosable}
|
||||
maskStyle={maskStyle}
|
||||
style={style}
|
||||
width={width}
|
||||
zIndex={zIndex}
|
||||
afterClose={afterClose}
|
||||
keyboard={keyboard}
|
||||
centered={centered}
|
||||
getContainer={getContainer}
|
||||
closable={closable}
|
||||
closeIcon={closeIcon}
|
||||
modalRender={modalRender}
|
||||
focusTriggerAfterClose={focusTriggerAfterClose}
|
||||
>
|
||||
<div className={`${contentPrefixCls}-body-wrapper`}>
|
||||
<ConfigProvider prefixCls={rootPrefixCls} direction={direction}>
|
||||
<ConfigProvider prefixCls={rootPrefixCls} iconPrefixCls={iconPrefixCls} direction={direction}>
|
||||
<Dialog
|
||||
prefixCls={prefixCls}
|
||||
className={classString}
|
||||
wrapClassName={classNames({ [`${contentPrefixCls}-centered`]: !!props.centered })}
|
||||
onCancel={() => close({ triggerCancel: true })}
|
||||
visible={visible}
|
||||
title=""
|
||||
footer=""
|
||||
transitionName={getTransitionName(rootPrefixCls, 'zoom', props.transitionName)}
|
||||
maskTransitionName={getTransitionName(rootPrefixCls, 'fade', props.maskTransitionName)}
|
||||
mask={mask}
|
||||
maskClosable={maskClosable}
|
||||
maskStyle={maskStyle}
|
||||
style={style}
|
||||
width={width}
|
||||
zIndex={zIndex}
|
||||
afterClose={afterClose}
|
||||
keyboard={keyboard}
|
||||
centered={centered}
|
||||
getContainer={getContainer}
|
||||
closable={closable}
|
||||
closeIcon={closeIcon}
|
||||
modalRender={modalRender}
|
||||
focusTriggerAfterClose={focusTriggerAfterClose}
|
||||
>
|
||||
<div className={`${contentPrefixCls}-body-wrapper`}>
|
||||
<div className={`${contentPrefixCls}-body`} style={bodyStyle}>
|
||||
{icon}
|
||||
{props.title === undefined ? null : (
|
||||
@ -112,22 +114,22 @@ const ConfirmDialog = (props: ConfirmDialogProps) => {
|
||||
)}
|
||||
<div className={`${contentPrefixCls}-content`}>{props.content}</div>
|
||||
</div>
|
||||
</ConfigProvider>
|
||||
<div className={`${contentPrefixCls}-btns`}>
|
||||
{cancelButton}
|
||||
<ActionButton
|
||||
type={okType}
|
||||
actionFn={onOk}
|
||||
closeModal={close}
|
||||
autoFocus={autoFocusButton === 'ok'}
|
||||
buttonProps={okButtonProps}
|
||||
prefixCls={`${rootPrefixCls}-btn`}
|
||||
>
|
||||
{okText}
|
||||
</ActionButton>
|
||||
<div className={`${contentPrefixCls}-btns`}>
|
||||
{cancelButton}
|
||||
<ActionButton
|
||||
type={okType}
|
||||
actionFn={onOk}
|
||||
close={close}
|
||||
autoFocus={autoFocusButton === 'ok'}
|
||||
buttonProps={okButtonProps}
|
||||
prefixCls={`${rootPrefixCls}-btn`}
|
||||
>
|
||||
{okText}
|
||||
</ActionButton>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Dialog>
|
||||
</Dialog>
|
||||
</ConfigProvider>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -1,5 +1,7 @@
|
||||
import * as React from 'react';
|
||||
import TestUtils, { act } from 'react-dom/test-utils';
|
||||
import CSSMotion from 'rc-motion';
|
||||
import { SmileOutlined } from '@ant-design/icons';
|
||||
import { genCSSMotion } from 'rc-motion/lib/CSSMotion';
|
||||
import KeyCode from 'rc-util/lib/KeyCode';
|
||||
import { resetWarned } from 'rc-util/lib/warning';
|
||||
@ -472,13 +474,14 @@ describe('Modal.confirm triggers callbacks correctly', () => {
|
||||
|
||||
it('should be able to global config rootPrefixCls', () => {
|
||||
jest.useFakeTimers();
|
||||
ConfigProvider.config({ prefixCls: 'my' });
|
||||
confirm({ title: 'title' });
|
||||
ConfigProvider.config({ prefixCls: 'my', iconPrefixCls: 'bamboo' });
|
||||
confirm({ title: 'title', icon: <SmileOutlined /> });
|
||||
jest.runAllTimers();
|
||||
expect(document.querySelectorAll('.ant-btn').length).toBe(0);
|
||||
expect(document.querySelectorAll('.my-btn').length).toBe(2);
|
||||
expect(document.querySelectorAll('.bamboo-smile').length).toBe(1);
|
||||
expect(document.querySelectorAll('.my-modal-confirm').length).toBe(1);
|
||||
ConfigProvider.config({ prefixCls: 'ant' });
|
||||
ConfigProvider.config({ prefixCls: 'ant', iconPrefixCls: null });
|
||||
jest.useRealTimers();
|
||||
});
|
||||
|
||||
|
@ -59,16 +59,18 @@ export default function confirm(config: ModalFuncProps) {
|
||||
*/
|
||||
setTimeout(() => {
|
||||
const runtimeLocale = getConfirmLocale();
|
||||
const { getPrefixCls } = globalConfig();
|
||||
const { getPrefixCls, getIconPrefixCls } = globalConfig();
|
||||
// because Modal.config set rootPrefixCls, which is different from other components
|
||||
const rootPrefixCls = getPrefixCls(undefined, getRootPrefixCls());
|
||||
const prefixCls = customizePrefixCls || `${rootPrefixCls}-modal`;
|
||||
const iconPrefixCls = getIconPrefixCls();
|
||||
|
||||
ReactDOM.render(
|
||||
<ConfirmDialog
|
||||
{...props}
|
||||
prefixCls={prefixCls}
|
||||
rootPrefixCls={rootPrefixCls}
|
||||
iconPrefixCls={iconPrefixCls}
|
||||
okText={okText || (props.okCancel ? runtimeLocale.okText : runtimeLocale.justOkText)}
|
||||
cancelText={cancelText || runtimeLocale.cancelText}
|
||||
/>,
|
||||
|
@ -11,7 +11,7 @@ title:
|
||||
|
||||
## en-US
|
||||
|
||||
Asynchronously close a modal dialog when a the OK button is pressed. For example, you can use this pattern when you submit a form.
|
||||
Asynchronously close a modal dialog when the OK button is pressed. For example, you can use this pattern when you submit a form.
|
||||
|
||||
```jsx
|
||||
import { Modal, Button } from 'antd';
|
||||
|
@ -11,7 +11,6 @@ import confirm, {
|
||||
import useModal from './useModal';
|
||||
import destroyFns from './destroyFns';
|
||||
|
||||
export { ActionButtonProps } from './ActionButton';
|
||||
export { ModalProps, ModalFuncProps } from './Modal';
|
||||
|
||||
function modalWarn(props: ModalFuncProps) {
|
||||
|
44
components/notification/__tests__/config.test.js
Normal file
44
components/notification/__tests__/config.test.js
Normal file
@ -0,0 +1,44 @@
|
||||
import notification, { getInstance } from '..';
|
||||
import { sleep } from '../../../tests/utils';
|
||||
|
||||
describe('notification.config', () => {
|
||||
beforeEach(() => {
|
||||
jest.useFakeTimers();
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
notification.destroy();
|
||||
});
|
||||
|
||||
it('should be able to config maxCount', async () => {
|
||||
notification.config({
|
||||
maxCount: 5,
|
||||
duration: 0.5,
|
||||
});
|
||||
|
||||
for (let i = 0; i < 10; i += 1) {
|
||||
notification.open({
|
||||
message: 'Notification message',
|
||||
key: i,
|
||||
});
|
||||
}
|
||||
|
||||
notification.open({
|
||||
message: 'Notification last',
|
||||
key: '11',
|
||||
});
|
||||
|
||||
await Promise.resolve();
|
||||
|
||||
expect(document.querySelectorAll('.ant-notification-notice').length).toBe(5);
|
||||
expect(document.querySelectorAll('.ant-notification-notice')[4].textContent).toBe(
|
||||
'Notification last',
|
||||
);
|
||||
|
||||
jest.runAllTimers();
|
||||
await sleep(500);
|
||||
expect((await getInstance('ant-notification-topRight')).component.state.notices).toHaveLength(
|
||||
0,
|
||||
);
|
||||
});
|
||||
});
|
@ -102,11 +102,12 @@ describe('notification', () => {
|
||||
});
|
||||
|
||||
it('should be able to global config rootPrefixCls', () => {
|
||||
ConfigProvider.config({ prefixCls: 'prefix-test' });
|
||||
notification.open({ message: 'Notification Title', duration: 0 });
|
||||
expect(document.querySelectorAll('.ant-notification-notice').length).toBe(0);
|
||||
expect(document.querySelectorAll('.prefix-test-notification-notice').length).toBe(1);
|
||||
ConfigProvider.config({ prefixCls: 'ant' });
|
||||
ConfigProvider.config({ prefixCls: 'prefix-test', iconPrefixCls: 'bamboo' });
|
||||
notification.success({ message: 'Notification Title', duration: 0 });
|
||||
expect(document.querySelectorAll('.ant-notification-notice')).toHaveLength(0);
|
||||
expect(document.querySelectorAll('.prefix-test-notification-notice')).toHaveLength(1);
|
||||
expect(document.querySelectorAll('.bamboo-check-circle')).toHaveLength(1);
|
||||
ConfigProvider.config({ prefixCls: 'ant', iconPrefixCls: null });
|
||||
});
|
||||
|
||||
it('should be able to config prefixCls', () => {
|
||||
@ -117,8 +118,8 @@ describe('notification', () => {
|
||||
message: 'Notification Title',
|
||||
duration: 0,
|
||||
});
|
||||
expect(document.querySelectorAll('.ant-notification-notice').length).toBe(0);
|
||||
expect(document.querySelectorAll('.prefix-test-notice').length).toBe(1);
|
||||
expect(document.querySelectorAll('.ant-notification-notice')).toHaveLength(0);
|
||||
expect(document.querySelectorAll('.prefix-test-notice')).toHaveLength(1);
|
||||
notification.config({
|
||||
prefixCls: '',
|
||||
});
|
||||
|
@ -65,7 +65,7 @@ notification.config({
|
||||
```
|
||||
|
||||
| Property | Description | Type | Default |
|
||||
| --- | --- | --- | --- |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| bottom | Distance from the bottom of the viewport, when `placement` is `bottomRight` or `bottomLeft` (unit: pixels) | number | 24 |
|
||||
| closeIcon | Custom close icon | ReactNode | - |
|
||||
| duration | Time in seconds before Notification is closed. When set to 0 or null, it will never be closed automatically | number | 4.5 |
|
||||
@ -73,6 +73,7 @@ notification.config({
|
||||
| placement | Position of Notification, can be one of `topLeft` `topRight` `bottomLeft` `bottomRight` | string | `topRight` |
|
||||
| rtl | Whether to enable RTL mode | boolean | false |
|
||||
| top | Distance from the top of the viewport, when `placement` is `topRight` or `topLeft` (unit: pixels) | number | 24 |
|
||||
| maxCount | Max Notification show, drop oldest if exceed limit | number | - | |
|
||||
|
||||
## FAQ
|
||||
|
||||
@ -100,4 +101,4 @@ return (
|
||||
|
||||
### How to set static methods prefixCls ?
|
||||
|
||||
You can config with [`ConfigProvider.config`](/components/config-provider/#ConfigProvider.config()-4.13.0+)
|
||||
You can config with [`ConfigProvider.config`](</components/config-provider/#ConfigProvider.config()-4.13.0+>)
|
||||
|
@ -8,7 +8,7 @@ import CloseCircleOutlined from '@ant-design/icons/CloseCircleOutlined';
|
||||
import ExclamationCircleOutlined from '@ant-design/icons/ExclamationCircleOutlined';
|
||||
import InfoCircleOutlined from '@ant-design/icons/InfoCircleOutlined';
|
||||
import createUseNotification from './hooks/useNotification';
|
||||
import { globalConfig } from '../config-provider';
|
||||
import ConfigProvider, { globalConfig } from '../config-provider';
|
||||
|
||||
export type NotificationPlacement = 'topLeft' | 'topRight' | 'bottomLeft' | 'bottomRight';
|
||||
|
||||
@ -25,6 +25,7 @@ let defaultPlacement: NotificationPlacement = 'topRight';
|
||||
let defaultGetContainer: () => HTMLElement;
|
||||
let defaultCloseIcon: React.ReactNode;
|
||||
let rtl = false;
|
||||
let maxCount: number;
|
||||
|
||||
export interface ConfigProps {
|
||||
top?: number;
|
||||
@ -35,6 +36,7 @@ export interface ConfigProps {
|
||||
getContainer?: () => HTMLElement;
|
||||
closeIcon?: React.ReactNode;
|
||||
rtl?: boolean;
|
||||
maxCount?: number;
|
||||
}
|
||||
|
||||
function setNotificationConfig(options: ConfigProps) {
|
||||
@ -65,6 +67,9 @@ function setNotificationConfig(options: ConfigProps) {
|
||||
if (options.rtl !== undefined) {
|
||||
rtl = options.rtl;
|
||||
}
|
||||
if (options.maxCount !== undefined) {
|
||||
maxCount = options.maxCount;
|
||||
}
|
||||
}
|
||||
|
||||
function getPlacementStyle(
|
||||
@ -108,7 +113,11 @@ function getPlacementStyle(
|
||||
|
||||
function getNotificationInstance(
|
||||
args: ArgsProps,
|
||||
callback: (info: { prefixCls: string; instance: RCNotificationInstance }) => void,
|
||||
callback: (info: {
|
||||
prefixCls: string;
|
||||
iconPrefixCls: string;
|
||||
instance: RCNotificationInstance;
|
||||
}) => void,
|
||||
) {
|
||||
const {
|
||||
placement = defaultPlacement,
|
||||
@ -118,14 +127,15 @@ function getNotificationInstance(
|
||||
closeIcon = defaultCloseIcon,
|
||||
prefixCls: customizePrefixCls,
|
||||
} = args;
|
||||
const { getPrefixCls } = globalConfig();
|
||||
const { getPrefixCls, getIconPrefixCls } = globalConfig();
|
||||
const prefixCls = getPrefixCls('notification', customizePrefixCls || defaultPrefixCls);
|
||||
const iconPrefixCls = getIconPrefixCls();
|
||||
|
||||
const cacheKey = `${prefixCls}-${placement}`;
|
||||
const cacheInstance = notificationInstance[cacheKey];
|
||||
if (cacheInstance) {
|
||||
Promise.resolve(cacheInstance).then(instance => {
|
||||
callback({ prefixCls: `${prefixCls}-notice`, instance });
|
||||
callback({ prefixCls: `${prefixCls}-notice`, iconPrefixCls, instance });
|
||||
});
|
||||
|
||||
return;
|
||||
@ -149,11 +159,13 @@ function getNotificationInstance(
|
||||
style: getPlacementStyle(placement, top, bottom),
|
||||
getContainer,
|
||||
closeIcon: closeIconToRender,
|
||||
maxCount,
|
||||
},
|
||||
notification => {
|
||||
resolve(notification);
|
||||
callback({
|
||||
prefixCls: `${prefixCls}-notice`,
|
||||
iconPrefixCls,
|
||||
instance: notification,
|
||||
});
|
||||
},
|
||||
@ -188,7 +200,7 @@ export interface ArgsProps {
|
||||
closeIcon?: React.ReactNode;
|
||||
}
|
||||
|
||||
function getRCNoticeProps(args: ArgsProps, prefixCls: string) {
|
||||
function getRCNoticeProps(args: ArgsProps, prefixCls: string, iconPrefixCls?: string) {
|
||||
const {
|
||||
duration: durationArg,
|
||||
icon,
|
||||
@ -221,15 +233,17 @@ function getRCNoticeProps(args: ArgsProps, prefixCls: string) {
|
||||
|
||||
return {
|
||||
content: (
|
||||
<div className={iconNode ? `${prefixCls}-with-icon` : ''} role="alert">
|
||||
{iconNode}
|
||||
<div className={`${prefixCls}-message`}>
|
||||
{autoMarginTag}
|
||||
{message}
|
||||
<ConfigProvider iconPrefixCls={iconPrefixCls}>
|
||||
<div className={iconNode ? `${prefixCls}-with-icon` : ''} role="alert">
|
||||
{iconNode}
|
||||
<div className={`${prefixCls}-message`}>
|
||||
{autoMarginTag}
|
||||
{message}
|
||||
</div>
|
||||
<div className={`${prefixCls}-description`}>{description}</div>
|
||||
{btn ? <span className={`${prefixCls}-btn`}>{btn}</span> : null}
|
||||
</div>
|
||||
<div className={`${prefixCls}-description`}>{description}</div>
|
||||
{btn ? <span className={`${prefixCls}-btn`}>{btn}</span> : null}
|
||||
</div>
|
||||
</ConfigProvider>
|
||||
),
|
||||
duration,
|
||||
closable: true,
|
||||
@ -244,8 +258,8 @@ function getRCNoticeProps(args: ArgsProps, prefixCls: string) {
|
||||
}
|
||||
|
||||
function notice(args: ArgsProps) {
|
||||
getNotificationInstance(args, ({ prefixCls, instance }) => {
|
||||
instance.notice(getRCNoticeProps(args, prefixCls));
|
||||
getNotificationInstance(args, ({ prefixCls, iconPrefixCls, instance }) => {
|
||||
instance.notice(getRCNoticeProps(args, prefixCls, iconPrefixCls));
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -66,7 +66,7 @@ notification.config({
|
||||
```
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 |
|
||||
| --- | --- | --- | --- |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| bottom | 消息从底部弹出时,距离底部的位置,单位像素 | number | 24 |
|
||||
| closeIcon | 自定义关闭图标 | ReactNode | - |
|
||||
| duration | 默认自动关闭延时,单位秒 | number | 4.5 |
|
||||
@ -74,6 +74,7 @@ notification.config({
|
||||
| placement | 弹出位置,可选 `topLeft` `topRight` `bottomLeft` `bottomRight` | string | `topRight` |
|
||||
| rtl | 是否开启 RTL 模式 | boolean | false |
|
||||
| top | 消息从顶部弹出时,距离顶部的位置,单位像素 | number | 24 |
|
||||
| maxCount | 最大显示数, 超过限制时,最早的消息会被自动关闭 | number | - | |
|
||||
|
||||
## FAQ
|
||||
|
||||
@ -101,4 +102,4 @@ return (
|
||||
|
||||
### 静态方法如何设置 prefixCls ?
|
||||
|
||||
你可以通过 [`ConfigProvider.config`](/components/config-provider/#ConfigProvider.config()-4.13.0+) 进行设置。
|
||||
你可以通过 [`ConfigProvider.config`](</components/config-provider/#ConfigProvider.config()-4.13.0+>) 进行设置。
|
||||
|
@ -179,3 +179,14 @@ exports[`renders ./components/popconfirm/demo/placement.md correctly 1`] = `
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/popconfirm/demo/promise.md correctly 1`] = `
|
||||
<button
|
||||
class="ant-btn ant-btn-primary"
|
||||
type="button"
|
||||
>
|
||||
<span>
|
||||
Open Popconfirm with Promise
|
||||
</span>
|
||||
</button>
|
||||
`;
|
||||
|
@ -131,6 +131,24 @@ describe('Popconfirm', () => {
|
||||
expect(onVisibleChange).toHaveBeenLastCalledWith(false, eventObject);
|
||||
});
|
||||
|
||||
it('should support onConfirm to return Promise', async () => {
|
||||
const confirm = () => new Promise(res => setTimeout(res, 300));
|
||||
const onVisibleChange = jest.fn();
|
||||
const popconfirm = mount(
|
||||
<Popconfirm title="code" onConfirm={confirm} onVisibleChange={onVisibleChange}>
|
||||
<span>show me your code</span>
|
||||
</Popconfirm>,
|
||||
);
|
||||
|
||||
const triggerNode = popconfirm.find('span').at(0);
|
||||
triggerNode.simulate('click');
|
||||
expect(onVisibleChange).toHaveBeenCalledTimes(1);
|
||||
|
||||
popconfirm.find('.ant-btn').at(0).simulate('click');
|
||||
await sleep(400);
|
||||
expect(onVisibleChange).toHaveBeenCalledWith(false, eventObject);
|
||||
});
|
||||
|
||||
it('should support customize icon', () => {
|
||||
const wrapper = mount(
|
||||
<Popconfirm title="code" icon={<span className="customize-icon">custom-icon</span>}>
|
||||
|
37
components/popconfirm/demo/promise.md
Normal file
37
components/popconfirm/demo/promise.md
Normal file
@ -0,0 +1,37 @@
|
||||
---
|
||||
order: 7
|
||||
title:
|
||||
zh-CN: 基于 Promise 的异步关闭
|
||||
en-US: Asynchronously close on Promise
|
||||
---
|
||||
|
||||
## zh-CN
|
||||
|
||||
点击确定后异步关闭 Popconfirm,例如提交表单。
|
||||
|
||||
## en-US
|
||||
|
||||
Asynchronously close a popconfirm when the OK button is pressed. For example, you can use this pattern when you submit a form.
|
||||
|
||||
```jsx
|
||||
import { Button, Popconfirm } from 'antd';
|
||||
|
||||
const App = () => {
|
||||
const confirm = () =>
|
||||
new Promise(resolve => {
|
||||
setTimeout(() => resolve(), 3000);
|
||||
});
|
||||
|
||||
return (
|
||||
<Popconfirm
|
||||
title="Title"
|
||||
onConfirm={confirm}
|
||||
onVisibleChange={() => console.log('visible change')}
|
||||
>
|
||||
<Button type="primary">Open Popconfirm with Promise</Button>
|
||||
</Popconfirm>
|
||||
);
|
||||
};
|
||||
|
||||
ReactDOM.render(<App />, mountNode);
|
||||
```
|
@ -12,6 +12,7 @@ import { ConfigContext } from '../config-provider';
|
||||
import { getRenderPropValue, RenderFunction } from '../_util/getRenderPropValue';
|
||||
import { cloneElement } from '../_util/reactNode';
|
||||
import { getTransitionName } from '../_util/motion';
|
||||
import ActionButton from '../_util/ActionButton';
|
||||
|
||||
export interface PopconfirmProps extends AbstractTooltipProps {
|
||||
title: React.ReactNode | RenderFunction;
|
||||
@ -40,6 +41,7 @@ export interface PopconfirmLocale {
|
||||
}
|
||||
|
||||
const Popconfirm = React.forwardRef<unknown, PopconfirmProps>((props, ref) => {
|
||||
const { getPrefixCls } = React.useContext(ConfigContext);
|
||||
const [visible, setVisible] = useMergedState(false, {
|
||||
value: props.visible,
|
||||
defaultValue: props.defaultVisible,
|
||||
@ -54,11 +56,12 @@ const Popconfirm = React.forwardRef<unknown, PopconfirmProps>((props, ref) => {
|
||||
props.onVisibleChange?.(value, e);
|
||||
};
|
||||
|
||||
const onConfirm = (e: React.MouseEvent<HTMLButtonElement>) => {
|
||||
const close = (e: React.MouseEvent<HTMLButtonElement>) => {
|
||||
settingVisible(false, e);
|
||||
props.onConfirm?.call(this, e);
|
||||
};
|
||||
|
||||
const onConfirm = (e: React.MouseEvent<HTMLButtonElement>) => props.onConfirm?.call(this, e);
|
||||
|
||||
const onCancel = (e: React.MouseEvent<HTMLButtonElement>) => {
|
||||
settingVisible(false, e);
|
||||
props.onCancel?.call(this, e);
|
||||
@ -90,21 +93,21 @@ const Popconfirm = React.forwardRef<unknown, PopconfirmProps>((props, ref) => {
|
||||
<Button onClick={onCancel} size="small" {...cancelButtonProps}>
|
||||
{cancelText || popconfirmLocale.cancelText}
|
||||
</Button>
|
||||
<Button
|
||||
onClick={onConfirm}
|
||||
{...convertLegacyProps(okType)}
|
||||
size="small"
|
||||
{...okButtonProps}
|
||||
<ActionButton
|
||||
buttonProps={{ size: 'small', ...convertLegacyProps(okType), ...okButtonProps }}
|
||||
actionFn={onConfirm}
|
||||
close={close}
|
||||
prefixCls={getPrefixCls('btn')}
|
||||
quitOnNullishReturnValue
|
||||
emitEvent
|
||||
>
|
||||
{okText || popconfirmLocale.okText}
|
||||
</Button>
|
||||
</ActionButton>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const { getPrefixCls } = React.useContext(ConfigContext);
|
||||
|
||||
const {
|
||||
prefixCls: customizePrefixCls,
|
||||
placement,
|
||||
|
@ -6,11 +6,12 @@ import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
|
||||
|
||||
export interface SkeletonButtonProps extends Omit<SkeletonElementProps, 'size'> {
|
||||
size?: 'large' | 'small' | 'default';
|
||||
block?: boolean;
|
||||
}
|
||||
|
||||
const SkeletonButton = (props: SkeletonButtonProps) => {
|
||||
const renderSkeletonButton = ({ getPrefixCls }: ConfigConsumerProps) => {
|
||||
const { prefixCls: customizePrefixCls, className, active } = props;
|
||||
const { prefixCls: customizePrefixCls, className, active, block = false } = props;
|
||||
const prefixCls = getPrefixCls('skeleton', customizePrefixCls);
|
||||
const otherProps = omit(props, ['prefixCls']);
|
||||
const cls = classNames(
|
||||
@ -18,6 +19,7 @@ const SkeletonButton = (props: SkeletonButtonProps) => {
|
||||
`${prefixCls}-element`,
|
||||
{
|
||||
[`${prefixCls}-active`]: active,
|
||||
[`${prefixCls}-block`]: block,
|
||||
},
|
||||
className,
|
||||
);
|
||||
|
@ -118,18 +118,6 @@ Array [
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-right:8px"
|
||||
>
|
||||
<div
|
||||
class="ant-skeleton ant-skeleton-element"
|
||||
>
|
||||
<span
|
||||
class="ant-skeleton-button"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-right:8px"
|
||||
@ -157,6 +145,15 @@ Array [
|
||||
</div>,
|
||||
<br />,
|
||||
<br />,
|
||||
<div
|
||||
class="ant-skeleton ant-skeleton-element"
|
||||
>
|
||||
<span
|
||||
class="ant-skeleton-button"
|
||||
/>
|
||||
</div>,
|
||||
<br />,
|
||||
<br />,
|
||||
<div
|
||||
class="ant-skeleton ant-skeleton-element"
|
||||
>
|
||||
@ -222,6 +219,45 @@ Array [
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-row ant-form-item"
|
||||
>
|
||||
<div
|
||||
class="ant-col ant-form-item-label"
|
||||
>
|
||||
<label
|
||||
class=""
|
||||
title="Button Block"
|
||||
>
|
||||
Button Block
|
||||
</label>
|
||||
</div>
|
||||
<div
|
||||
class="ant-col ant-form-item-control"
|
||||
>
|
||||
<div
|
||||
class="ant-form-item-control-input"
|
||||
>
|
||||
<div
|
||||
class="ant-form-item-control-input-content"
|
||||
>
|
||||
<button
|
||||
aria-checked="false"
|
||||
class="ant-switch"
|
||||
role="switch"
|
||||
type="button"
|
||||
>
|
||||
<div
|
||||
class="ant-switch-handle"
|
||||
/>
|
||||
<span
|
||||
class="ant-switch-inner"
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-row ant-form-item"
|
||||
>
|
||||
|
@ -250,6 +250,16 @@ exports[`Skeleton button element active 1`] = `
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`Skeleton button element block 1`] = `
|
||||
<div
|
||||
class="ant-skeleton ant-skeleton-element ant-skeleton-block"
|
||||
>
|
||||
<span
|
||||
class="ant-skeleton-button"
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`Skeleton button element shape 1`] = `
|
||||
<div
|
||||
class="ant-skeleton ant-skeleton-element"
|
||||
|
@ -80,6 +80,10 @@ describe('Skeleton', () => {
|
||||
const wrapper = genSkeletonButton({ active: true });
|
||||
expect(wrapper.render()).toMatchSnapshot();
|
||||
});
|
||||
it('block', () => {
|
||||
const wrapper = genSkeletonButton({ block: true });
|
||||
expect(wrapper.render()).toMatchSnapshot();
|
||||
});
|
||||
it('size', () => {
|
||||
const wrapperDefault = genSkeletonButton({ size: 'default' });
|
||||
expect(wrapperDefault.render()).toMatchSnapshot();
|
||||
|
@ -19,6 +19,7 @@ import { Skeleton, Space, Divider, Switch, Form, Radio } from 'antd';
|
||||
class Demo extends React.Component {
|
||||
state = {
|
||||
active: false,
|
||||
block: false,
|
||||
size: 'default',
|
||||
buttonShape: 'default',
|
||||
avatarShape: 'circle',
|
||||
@ -28,6 +29,10 @@ class Demo extends React.Component {
|
||||
this.setState({ active: checked });
|
||||
};
|
||||
|
||||
handleBlockChange = checked => {
|
||||
this.setState({ block: checked });
|
||||
};
|
||||
|
||||
handleSizeChange = e => {
|
||||
this.setState({ size: e.target.value });
|
||||
};
|
||||
@ -37,23 +42,28 @@ class Demo extends React.Component {
|
||||
};
|
||||
|
||||
render() {
|
||||
const { active, size, buttonShape, avatarShape } = this.state;
|
||||
const { active, size, buttonShape, avatarShape, block } = this.state;
|
||||
return (
|
||||
<>
|
||||
<Space>
|
||||
<Skeleton.Button active={active} size={size} shape={buttonShape} />
|
||||
<Skeleton.Button active={active} size={size} shape={buttonShape} />
|
||||
<Skeleton.Button active={active} size={size} shape={buttonShape} block={block} />
|
||||
<Skeleton.Avatar active={active} size={size} shape={avatarShape} />
|
||||
<Skeleton.Input style={{ width: 200 }} active={active} size={size} />
|
||||
</Space>
|
||||
<br />
|
||||
<br />
|
||||
<Skeleton.Button active={active} size={size} shape={buttonShape} block={block} />
|
||||
<br />
|
||||
<br />
|
||||
<Skeleton.Image />
|
||||
<Divider />
|
||||
<Form layout="inline" style={{ margin: '16px 0' }}>
|
||||
<Form.Item label="Active">
|
||||
<Switch checked={active} onChange={this.handleActiveChange} />
|
||||
</Form.Item>
|
||||
<Form.Item label="Button Block">
|
||||
<Switch checked={block} onChange={this.handleBlockChange} />
|
||||
</Form.Item>
|
||||
<Form.Item label="Size">
|
||||
<Radio.Group value={size} onChange={this.handleSizeChange}>
|
||||
<Radio.Button value="default">Default</Radio.Button>
|
||||
|
@ -38,9 +38,9 @@ Provide a placeholder while you wait for content to load, or to visualise conten
|
||||
|
||||
### SkeletonTitleProps
|
||||
|
||||
| Property | Description | Type | Default |
|
||||
| --- | --- | --- | --- |
|
||||
| width | Set the width of title | number \| string | - |
|
||||
| Property | Description | Type | Default |
|
||||
| -------- | ---------------------- | ---------------- | ------- |
|
||||
| width | Set the width of title | number \| string | - |
|
||||
|
||||
### SkeletonParagraphProps
|
||||
|
||||
@ -54,12 +54,13 @@ Provide a placeholder while you wait for content to load, or to visualise conten
|
||||
| Property | Description | Type | Default |
|
||||
| --- | --- | --- | --- |
|
||||
| active | Show animation effect | boolean | false |
|
||||
| block | Option to fit button width to its parent width | boolean | false |
|
||||
| shape | Set the shape of button | `circle` \| `round` \| `default` | - |
|
||||
| size | Set the size of button | `large` \| `small` \| `default` | - |
|
||||
|
||||
### SkeletonInputProps
|
||||
|
||||
| Property | Description | Type | Default |
|
||||
| --- | --- | --- | --- |
|
||||
| active | Show animation effect | boolean | false |
|
||||
| size | Set the size of input | `large` \| `small` \| `default` | - |
|
||||
| Property | Description | Type | Default |
|
||||
| -------- | --------------------- | ------------------------------- | ------- |
|
||||
| active | Show animation effect | boolean | false |
|
||||
| size | Set the size of input | `large` \| `small` \| `default` | - |
|
||||
|
@ -39,9 +39,9 @@ cover: https://gw.alipayobjects.com/zos/alicdn/KpcciCJgv/Skeleton.svg
|
||||
|
||||
### SkeletonTitleProps
|
||||
|
||||
| 属性 | 说明 | 类型 | 默认值 |
|
||||
| --- | --- | --- | --- |
|
||||
| width | 设置标题占位图的宽度 | number \| string | - |
|
||||
| 属性 | 说明 | 类型 | 默认值 |
|
||||
| ----- | -------------------- | ---------------- | ------ |
|
||||
| width | 设置标题占位图的宽度 | number \| string | - |
|
||||
|
||||
### SkeletonParagraphProps
|
||||
|
||||
@ -52,15 +52,16 @@ cover: https://gw.alipayobjects.com/zos/alicdn/KpcciCJgv/Skeleton.svg
|
||||
|
||||
### SkeletonButtonProps
|
||||
|
||||
| 属性 | 说明 | 类型 | 默认值 |
|
||||
| --- | --- | --- | --- |
|
||||
| active | 是否展示动画效果 | boolean | false |
|
||||
| shape | 指定按钮的形状 | `circle` \| `round` \| `default` | - |
|
||||
| size | 设置按钮的大小 | `large` \| `small` \| `default` | - |
|
||||
| 属性 | 说明 | 类型 | 默认值 |
|
||||
| ------ | ------------------------------ | -------------------------------- | ------ |
|
||||
| active | 是否展示动画效果 | boolean | false |
|
||||
| block | 将按钮宽度调整为其父宽度的选项 | boolean | false |
|
||||
| shape | 指定按钮的形状 | `circle` \| `round` \| `default` | - |
|
||||
| size | 设置按钮的大小 | `large` \| `small` \| `default` | - |
|
||||
|
||||
### SkeletonInputProps
|
||||
|
||||
| 属性 | 说明 | 类型 | 默认值 |
|
||||
| --- | --- | --- | --- |
|
||||
| active | 是否展示动画效果 | boolean | false |
|
||||
| size | 设置输入框的大小 | `large` \| `small` \| `default` | - |
|
||||
| 属性 | 说明 | 类型 | 默认值 |
|
||||
| ------ | ---------------- | ------------------------------- | ------ |
|
||||
| active | 是否展示动画效果 | boolean | false |
|
||||
| size | 设置输入框的大小 | `large` \| `small` \| `default` | - |
|
||||
|
@ -109,6 +109,15 @@
|
||||
}
|
||||
}
|
||||
|
||||
// Skeleton Block Button
|
||||
&.@{skeleton-prefix-cls}-block {
|
||||
width: 100%;
|
||||
|
||||
.@{skeleton-button-prefix-cls} {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
// Skeleton element
|
||||
&-element {
|
||||
display: inline-block;
|
||||
@ -214,10 +223,12 @@
|
||||
|
||||
.skeleton-element-button-size(@size) {
|
||||
width: @size * 2;
|
||||
min-width: @size * 2;
|
||||
.skeleton-element-common-size(@size);
|
||||
|
||||
&.@{skeleton-button-prefix-cls}-circle {
|
||||
width: @size;
|
||||
min-width: @size;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
|
@ -230,6 +230,7 @@
|
||||
@checkbox-check-color: #fff;
|
||||
@checkbox-check-bg: @checkbox-check-color;
|
||||
@checkbox-border-width: @border-width-base;
|
||||
@checkbox-border-radius: @border-radius-base;
|
||||
@checkbox-group-item-margin-right: 8px;
|
||||
|
||||
// Descriptions
|
||||
|
@ -16705,7 +16705,21 @@ exports[`renders ./components/table/demo/sticky.md correctly 1`] = `
|
||||
colspan="2"
|
||||
style="position:sticky;left:0"
|
||||
>
|
||||
Fix Left
|
||||
<button
|
||||
aria-checked="false"
|
||||
class="ant-switch"
|
||||
role="switch"
|
||||
type="button"
|
||||
>
|
||||
<div
|
||||
class="ant-switch-handle"
|
||||
/>
|
||||
<span
|
||||
class="ant-switch-inner"
|
||||
>
|
||||
Fixed Top
|
||||
</span>
|
||||
</button>
|
||||
</td>
|
||||
<td
|
||||
class="ant-table-cell"
|
||||
|
@ -14,7 +14,7 @@ title:
|
||||
For long table,need to scroll to view the header and scroll bar,then you can now set the fixed header and scroll bar to follow the page.
|
||||
|
||||
```jsx
|
||||
import { Table } from 'antd';
|
||||
import { Table, Switch } from 'antd';
|
||||
|
||||
const columns = [
|
||||
{
|
||||
@ -93,26 +93,38 @@ for (let i = 0; i < 100; i++) {
|
||||
});
|
||||
}
|
||||
|
||||
ReactDOM.render(
|
||||
<Table
|
||||
columns={columns}
|
||||
dataSource={data}
|
||||
scroll={{ x: 1500 }}
|
||||
summary={pageData => (
|
||||
<Table.Summary fixed>
|
||||
<Table.Summary.Row>
|
||||
<Table.Summary.Cell index={0} colSpan={2}>
|
||||
Fix Left
|
||||
</Table.Summary.Cell>
|
||||
<Table.Summary.Cell index={2} colSpan={8}>
|
||||
Scroll Context
|
||||
</Table.Summary.Cell>
|
||||
<Table.Summary.Cell index={10}>Fix Right</Table.Summary.Cell>
|
||||
</Table.Summary.Row>
|
||||
</Table.Summary>
|
||||
)}
|
||||
sticky
|
||||
/>,
|
||||
mountNode,
|
||||
);
|
||||
const Demo = () => {
|
||||
const [fixedTop, setFixedTop] = React.useState(false);
|
||||
|
||||
return (
|
||||
<Table
|
||||
columns={columns}
|
||||
dataSource={data}
|
||||
scroll={{ x: 1500 }}
|
||||
summary={pageData => (
|
||||
<Table.Summary fixed={fixedTop ? 'top' : 'bottom'}>
|
||||
<Table.Summary.Row>
|
||||
<Table.Summary.Cell index={0} colSpan={2}>
|
||||
<Switch
|
||||
checkedChildren="Fixed Top"
|
||||
unCheckedChildren="Fixed Top"
|
||||
checked={fixedTop}
|
||||
onChange={() => {
|
||||
setFixedTop(!fixedTop);
|
||||
}}
|
||||
/>
|
||||
</Table.Summary.Cell>
|
||||
<Table.Summary.Cell index={2} colSpan={8}>
|
||||
Scroll Context
|
||||
</Table.Summary.Cell>
|
||||
<Table.Summary.Cell index={10}>Fix Right</Table.Summary.Cell>
|
||||
</Table.Summary.Row>
|
||||
</Table.Summary>
|
||||
)}
|
||||
sticky
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
ReactDOM.render(<Demo />, mountNode);
|
||||
```
|
||||
|
8
components/time-picker/locale/bn_BD.tsx
Normal file
8
components/time-picker/locale/bn_BD.tsx
Normal file
@ -0,0 +1,8 @@
|
||||
import { TimePickerLocale } from '../index';
|
||||
|
||||
const locale: TimePickerLocale = {
|
||||
placeholder: 'সময় নির্বাচন',
|
||||
rangePlaceholder: ['সময় শুরু', 'শেষ সময়'],
|
||||
};
|
||||
|
||||
export default locale;
|
8
components/time-picker/locale/ml_IN.tsx
Normal file
8
components/time-picker/locale/ml_IN.tsx
Normal file
@ -0,0 +1,8 @@
|
||||
import { TimePickerLocale } from '../index';
|
||||
|
||||
const locale: TimePickerLocale = {
|
||||
placeholder: 'സമയം തിരഞ്ഞെടുക്കുക',
|
||||
rangePlaceholder: ['ആരംഭ സമയം', 'അവസാന സമയം'],
|
||||
};
|
||||
|
||||
export default locale;
|
8
components/time-picker/locale/ur_PK.tsx
Normal file
8
components/time-picker/locale/ur_PK.tsx
Normal file
@ -0,0 +1,8 @@
|
||||
import { TimePickerLocale } from '../index';
|
||||
|
||||
const locale: TimePickerLocale = {
|
||||
placeholder: 'وقت منتخب کریں',
|
||||
rangePlaceholder: ['وقت منتخب کریں', 'آخر وقت'],
|
||||
};
|
||||
|
||||
export default locale;
|
@ -146,11 +146,11 @@ exports[`renders ./components/transfer/demo/advanced.md correctly 1`] = `
|
||||
>
|
||||
<button
|
||||
class="ant-btn ant-btn-sm"
|
||||
style="float:right;margin:5px"
|
||||
style="float:left;margin:5px"
|
||||
type="button"
|
||||
>
|
||||
<span>
|
||||
reload
|
||||
Left button reload
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
@ -361,7 +361,7 @@ exports[`renders ./components/transfer/demo/advanced.md correctly 1`] = `
|
||||
type="button"
|
||||
>
|
||||
<span>
|
||||
reload
|
||||
Right button reload
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
@ -4247,11 +4247,11 @@ exports[`renders ./components/transfer/demo/tree-transfer.md correctly 1`] = `
|
||||
>
|
||||
<div
|
||||
class="ant-tree ant-tree-icon-hide ant-tree-block-node"
|
||||
role="tree"
|
||||
>
|
||||
<div
|
||||
role="tree"
|
||||
>
|
||||
<div>
|
||||
<input
|
||||
aria-label="for screen reader"
|
||||
style="width:0;height:0;display:flex;overflow:hidden;opacity:0;border:0;padding:0;margin:0"
|
||||
tabindex="0"
|
||||
value=""
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user