mirror of
https://github.com/ant-design/ant-design.git
synced 2024-11-27 20:49:53 +08:00
chore: merge master into feature
This commit is contained in:
commit
60a2ae6319
@ -183,6 +183,10 @@ const CustomTheme = () => {
|
||||
style={{ height: 'calc(100vh - 64px - 56px)' }}
|
||||
onThemeChange={(newTheme) => {
|
||||
setTheme(newTheme.config);
|
||||
setThemeConfigContent({
|
||||
json: newTheme.config,
|
||||
text: undefined,
|
||||
});
|
||||
}}
|
||||
locale={lang === 'cn' ? zhCN : enUS}
|
||||
/>
|
||||
|
@ -15,6 +15,25 @@ timeline: true
|
||||
|
||||
---
|
||||
|
||||
## 5.6.4
|
||||
|
||||
`2023-07-03`
|
||||
|
||||
- Form
|
||||
- 🐞 Fix `onFieldsChange` event will still be triggered incorrectly when the field is not configured with `rules` when the Form is submitted. [#43290](https://github.com/ant-design/ant-design/pull/43290)
|
||||
- 🐞 Fix the problem that the warning message that `name` is empty is falsely reported when the `name` of Form.List is 0. [#43199](https://github.com/ant-design/ant-design/pull/43199) [@Yuiai01](https://github.com/Yuiai01)
|
||||
- 🐞 Fix the Badge `color` attribute does not take effect. [#43304](https://github.com/ant-design/ant-design/pull/43304)
|
||||
- 🐞 Fix the position of Select clear icon when FormItem sets `hasFeedback`. [#43302](https://github.com/ant-design/ant-design/pull/43302) [@tinyfind](https://github.com/tinyfind)
|
||||
- 🐞 Fix Transfer paging drop-down button is hidden and `showSizeChanger` method is invalid. [#41906](https://github.com/ant-design/ant-design/pull/41906) [@Yuiai01](https://github.com/Yuiai01)
|
||||
- 🐞 Fix the invalid modification of `colorText` and `fontSize` of Popconfirm component. [#43212](https://github.com/ant-design/ant-design/pull/43212) [@MadCcc](https://github.com/MadCcc)
|
||||
- 🐞 Fix the problem that deleting files after Upload configures `maxCount` will not trigger `onChange`. [#43193](https://github.com/ant-design/ant-design/pull/43193)
|
||||
- 💄 Fix Button disabled style error when it has `link` or `href` attribute. [#43091](https://github.com/ant-design/ant-design/pull/43091) [@BoyYangzai](https://github.com/BoyYangzai)
|
||||
- TypeScript
|
||||
- 🤖 Optimize Breadcrumb `params` type and support generics. [#43211](https://github.com/ant-design/ant-design/pull/43211)
|
||||
- 🤖 Optimize Breadcrumb `params` type and support generics. [#43257](https://github.com/ant-design/ant-design/pull/43257) [@thinkasany](https://github.com/thinkasany)
|
||||
- 🤖 Remove redundant number type from Button `loading`. [#43256](https://github.com/ant-design/ant-design/pull/43256) [@thinkasany](https://github.com/thinkasany)
|
||||
- 🤖 Transparently pass Cascader `optionType` generic. [#43231](https://github.com/ant-design/ant-design/pull/43231) [@ZWkang](https://github.com/ZWkang)
|
||||
|
||||
## 5.6.3
|
||||
|
||||
`2023-06-25`
|
||||
|
@ -15,6 +15,25 @@ timeline: true
|
||||
|
||||
---
|
||||
|
||||
## 5.6.4
|
||||
|
||||
`2023-07-03`
|
||||
|
||||
- Form
|
||||
- 🐞 修复 Form 在提交时,字段没有配置 `rules` 时仍会错误触发 `onFieldsChange` 事件的问题。[#43290](https://github.com/ant-design/ant-design/pull/43290)
|
||||
- 🐞 修复 Form.List 的 `name` 为 0 时误报 `name` 为空的警告信息的问题。[#43199](https://github.com/ant-design/ant-design/pull/43199) [@Yuiai01](https://github.com/Yuiai01)
|
||||
- 🐞 修复 Badge `color` 属性不生效的问题。[#43304](https://github.com/ant-design/ant-design/pull/43304)
|
||||
- 🐞 修复 Select 组件的消除图标在 FormItem 设置 `hasFeedback` 时的位置问题。[#43302](https://github.com/ant-design/ant-design/pull/43302) [@tinyfind](https://github.com/tinyfind)
|
||||
- 🐞 修复 Transfer 分页下拉按钮被隐藏以及 `showSizeChanger` 方法无效。[#41906](https://github.com/ant-design/ant-design/pull/41906) [@Yuiai01](https://github.com/Yuiai01)
|
||||
- 🐞 修复 Popconfirm 组件 `colorText` 和 `fontSize` 修改无效的问题。[#43212](https://github.com/ant-design/ant-design/pull/43212) [@MadCcc](https://github.com/MadCcc)
|
||||
- 🐞 修复 Upload 配置 `maxCount` 后删除文件不会触发 `onChange` 的问题。[#43193](https://github.com/ant-design/ant-design/pull/43193)
|
||||
- 💄 修复 Button 在有 `link` 或 `href` 属性时禁用样式错误。[#43091](https://github.com/ant-design/ant-design/pull/43091) [@BoyYangzai](https://github.com/BoyYangzai)
|
||||
- TypeScript
|
||||
- 🤖 优化 Breadcrumb `params` 类型,支持泛型。[#43211](https://github.com/ant-design/ant-design/pull/43211)
|
||||
- 🤖 优化 Typography `copyIdRef` 类型。[#43257](https://github.com/ant-design/ant-design/pull/43257) [@thinkasany](https://github.com/thinkasany)
|
||||
- 🤖 移除 Button `loading` 多余 number 类型。[#43256](https://github.com/ant-design/ant-design/pull/43256) [@thinkasany](https://github.com/thinkasany)
|
||||
- 🤖 透传 Cascader `optionType` 泛型。[#43231](https://github.com/ant-design/ant-design/pull/43231) [@ZWkang](https://github.com/ZWkang)
|
||||
|
||||
## 5.6.3
|
||||
|
||||
`2023-06-25`
|
||||
|
@ -13,7 +13,7 @@ Application wrapper for some global usages.
|
||||
## When To Use
|
||||
|
||||
- Provide reset styles based on `.ant-app` element.
|
||||
- You could use static methods of `message/notification/Modal` form `useApp` without put `contextHolder` mannully.
|
||||
- You could use static methods of `message/notification/Modal` form `useApp` without writing `contextHolder` manually.
|
||||
|
||||
## Examples
|
||||
|
||||
@ -95,7 +95,7 @@ export default () => {
|
||||
return null;
|
||||
};
|
||||
|
||||
export { message, notification, modal };
|
||||
export { message, modal, notification };
|
||||
```
|
||||
|
||||
```tsx
|
||||
|
@ -42,7 +42,7 @@ const App: React.FC<AppProps> & { useApp: typeof useApp } = (props) => {
|
||||
message: { ...appConfig.message, ...message },
|
||||
notification: { ...appConfig.notification, ...notification },
|
||||
}),
|
||||
[message, notification, appConfig.message, appConfig.message],
|
||||
[message, notification, appConfig.message, appConfig.notification],
|
||||
);
|
||||
|
||||
const [messageApi, messageContextHolder] = useMessage(mergedAppConfig.message);
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,5 +1,5 @@
|
||||
import React from 'react';
|
||||
import { Badge, Space } from 'antd';
|
||||
import React from 'react';
|
||||
|
||||
const colors = [
|
||||
'pink',
|
||||
@ -17,24 +17,35 @@ const colors = [
|
||||
'lime',
|
||||
];
|
||||
|
||||
const AvatarItem = ({ color }: { color: string }) => (
|
||||
<div
|
||||
style={{
|
||||
width: 90,
|
||||
height: 90,
|
||||
lineHeight: '90px',
|
||||
background: '#ccc',
|
||||
textAlign: 'center',
|
||||
}}
|
||||
>
|
||||
{color}
|
||||
</div>
|
||||
);
|
||||
|
||||
const App: React.FC = () => (
|
||||
<Space wrap size={['large', 'middle']}>
|
||||
{colors.map((color) => (
|
||||
<Badge color={color} count={44} key={color}>
|
||||
<div
|
||||
style={{
|
||||
width: 90,
|
||||
height: 90,
|
||||
lineHeight: '90px',
|
||||
background: '#ccc',
|
||||
textAlign: 'center',
|
||||
}}
|
||||
>
|
||||
{color}
|
||||
</div>
|
||||
</Badge>
|
||||
))}
|
||||
</Space>
|
||||
<>
|
||||
<Space wrap size={['large', 'middle']}>
|
||||
{colors.map((color) => (
|
||||
<Badge color={color} count={44} key={color}>
|
||||
<AvatarItem color={color} />
|
||||
</Badge>
|
||||
))}
|
||||
</Space>
|
||||
<Space wrap size={['large', 'middle']}>
|
||||
{colors.map((color) => (
|
||||
<Badge status="processing" color={color} text="loading" key={color} />
|
||||
))}
|
||||
</Space>
|
||||
</>
|
||||
);
|
||||
|
||||
export default App;
|
||||
|
@ -1,5 +1,5 @@
|
||||
import React from 'react';
|
||||
import { Badge, Card, Space } from 'antd';
|
||||
import React from 'react';
|
||||
|
||||
const App: React.FC = () => (
|
||||
<Space direction="vertical" size="middle" style={{ width: '100%' }}>
|
||||
@ -8,12 +8,7 @@ const App: React.FC = () => (
|
||||
and raises the spyglass.
|
||||
</Card>
|
||||
</Badge.Ribbon>
|
||||
<Badge.Ribbon text={
|
||||
<div>
|
||||
Hippies <br />
|
||||
Happy
|
||||
</div>
|
||||
} color="pink">
|
||||
<Badge.Ribbon text="Hippies" color="pink">
|
||||
<Card title="Pushes open the window" size="small">
|
||||
and raises the spyglass.
|
||||
</Card>
|
||||
|
@ -74,8 +74,11 @@ const genSharedBadgeStyle: GenerateStyle<BadgeToken> = (token: BadgeToken): CSSO
|
||||
const ribbonWrapperPrefixCls = `${antCls}-ribbon-wrapper`;
|
||||
|
||||
const colorPreset = genPresetColor(token, (colorKey, { darkColor }) => ({
|
||||
[`${componentCls}-color-${colorKey}`]: {
|
||||
[`&${componentCls} ${componentCls}-color-${colorKey}`]: {
|
||||
background: darkColor,
|
||||
[`&:not(${componentCls}-count)`]: {
|
||||
color: darkColor,
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
||||
|
@ -46,9 +46,9 @@ export type ItemType = Partial<BreadcrumbItemType & BreadcrumbSeparatorType>;
|
||||
|
||||
export type InternalRouteType = Partial<BreadcrumbItemType & BreadcrumbSeparatorType>;
|
||||
|
||||
export interface BreadcrumbProps {
|
||||
export interface BreadcrumbProps<T extends Record<PropertyKey, any> = any> {
|
||||
prefixCls?: string;
|
||||
params?: any;
|
||||
params?: T;
|
||||
separator?: React.ReactNode;
|
||||
style?: React.CSSProperties;
|
||||
className?: string;
|
||||
@ -60,19 +60,13 @@ export interface BreadcrumbProps {
|
||||
|
||||
items?: ItemType[];
|
||||
|
||||
itemRender?: (
|
||||
route: ItemType,
|
||||
params: any,
|
||||
routes: ItemType[],
|
||||
paths: string[],
|
||||
) => React.ReactNode;
|
||||
itemRender?: (route: ItemType, params: T, routes: ItemType[], paths: string[]) => React.ReactNode;
|
||||
}
|
||||
|
||||
const getPath = (params: any, path?: string) => {
|
||||
const getPath = <T extends Record<PropertyKey, any> = any>(params: T, path?: string) => {
|
||||
if (path === undefined) {
|
||||
return path;
|
||||
}
|
||||
|
||||
let mergedPath = (path || '').replace(/^\//, '');
|
||||
Object.keys(params).forEach((key) => {
|
||||
mergedPath = mergedPath.replace(`:${key}`, params[key]!);
|
||||
@ -80,7 +74,7 @@ const getPath = (params: any, path?: string) => {
|
||||
return mergedPath;
|
||||
};
|
||||
|
||||
const Breadcrumb = (props: BreadcrumbProps) => {
|
||||
const Breadcrumb = <T extends Record<PropertyKey, any> = any>(props: BreadcrumbProps<T>) => {
|
||||
const {
|
||||
prefixCls: customizePrefixCls,
|
||||
separator = '/',
|
||||
@ -113,7 +107,7 @@ const Breadcrumb = (props: BreadcrumbProps) => {
|
||||
// generated by route
|
||||
const paths: string[] = [];
|
||||
|
||||
const itemRenderRoutes: any = items || legacyRoutes;
|
||||
const itemRenderRoutes = items || legacyRoutes;
|
||||
|
||||
crumbs = mergedItems.map((item, index) => {
|
||||
const {
|
||||
@ -168,7 +162,7 @@ const Breadcrumb = (props: BreadcrumbProps) => {
|
||||
onClick={onClick}
|
||||
prefixCls={prefixCls}
|
||||
>
|
||||
{mergedItemRender(item as BreadcrumbItemType, params, itemRenderRoutes, paths, href)}
|
||||
{mergedItemRender(item, params, itemRenderRoutes!, paths, href)}
|
||||
</InternalBreadcrumbItem>
|
||||
);
|
||||
});
|
||||
|
@ -37,7 +37,7 @@ export interface BreadcrumbItemProps extends SeparatorType {
|
||||
overlay?: DropdownProps['overlay'];
|
||||
}
|
||||
|
||||
export const InternalBreadcrumbItem = (props: BreadcrumbItemProps) => {
|
||||
export const InternalBreadcrumbItem: React.FC<BreadcrumbItemProps> = (props) => {
|
||||
const { prefixCls, separator = '/', children, menu, overlay, dropdownProps, href } = props;
|
||||
|
||||
// Warning for deprecated usage
|
||||
@ -103,11 +103,15 @@ export const InternalBreadcrumbItem = (props: BreadcrumbItemProps) => {
|
||||
return null;
|
||||
};
|
||||
|
||||
const BreadcrumbItem = (props: BreadcrumbItemProps) => {
|
||||
type CompoundedComponent = React.FC<BreadcrumbItemProps> & {
|
||||
/** @internal */
|
||||
__ANT_BREADCRUMB_ITEM: boolean;
|
||||
};
|
||||
|
||||
const BreadcrumbItem: CompoundedComponent = (props) => {
|
||||
const { prefixCls: customizePrefixCls, children, href, ...restProps } = props;
|
||||
const { getPrefixCls } = React.useContext(ConfigContext);
|
||||
const prefixCls = getPrefixCls('breadcrumb', customizePrefixCls);
|
||||
|
||||
return (
|
||||
<InternalBreadcrumbItem {...restProps} prefixCls={prefixCls}>
|
||||
{renderItem(prefixCls, restProps as ItemType, children, href)}
|
||||
|
@ -384,4 +384,19 @@ describe('Breadcrumb', () => {
|
||||
);
|
||||
expect(document.querySelector('.ant-dropdown')).toBeTruthy();
|
||||
});
|
||||
|
||||
it('Breadcrumb params type test', () => {
|
||||
interface Params {
|
||||
key1?: number;
|
||||
key2?: string;
|
||||
}
|
||||
expect(
|
||||
<Breadcrumb<Params>
|
||||
params={{
|
||||
key1: 1,
|
||||
key2: 'test',
|
||||
}}
|
||||
/>,
|
||||
).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
@ -76,8 +76,6 @@ type CompoundedComponent = React.ForwardRefExoticComponent<
|
||||
__ANT_BUTTON: boolean;
|
||||
};
|
||||
|
||||
type Loading = number | boolean;
|
||||
|
||||
type LoadingConfigType = {
|
||||
loading: boolean;
|
||||
delay: number;
|
||||
@ -137,7 +135,7 @@ const InternalButton: React.ForwardRefRenderFunction<
|
||||
|
||||
const loadingOrDelay = useMemo<LoadingConfigType>(() => getLoadingConfig(loading), [loading]);
|
||||
|
||||
const [innerLoading, setLoading] = useState<Loading>(loadingOrDelay.loading);
|
||||
const [innerLoading, setLoading] = useState<boolean>(loadingOrDelay.loading);
|
||||
|
||||
const [hasTwoCNChar, setHasTwoCNChar] = useState<boolean>(false);
|
||||
|
||||
@ -218,8 +216,6 @@ const InternalButton: React.ForwardRefRenderFunction<
|
||||
|
||||
const linkButtonRestProps = omit(rest as ButtonProps & { navigate: any }, ['navigate']);
|
||||
|
||||
const hrefAndDisabled = linkButtonRestProps.href !== undefined && mergedDisabled;
|
||||
|
||||
const classes = classNames(
|
||||
prefixCls,
|
||||
hashId,
|
||||
@ -234,7 +230,6 @@ const InternalButton: React.ForwardRefRenderFunction<
|
||||
[`${prefixCls}-block`]: block,
|
||||
[`${prefixCls}-dangerous`]: !!danger,
|
||||
[`${prefixCls}-rtl`]: direction === 'rtl',
|
||||
[`${prefixCls}-disabled`]: hrefAndDisabled,
|
||||
},
|
||||
compactItemClassnames,
|
||||
className,
|
||||
@ -263,7 +258,9 @@ const InternalButton: React.ForwardRefRenderFunction<
|
||||
return wrapSSR(
|
||||
<a
|
||||
{...linkButtonRestProps}
|
||||
className={classes}
|
||||
className={classNames(classes, {
|
||||
[`${prefixCls}-disabled`]: mergedDisabled,
|
||||
})}
|
||||
style={fullStyle}
|
||||
onClick={handleClick}
|
||||
ref={buttonRef as React.Ref<HTMLAnchorElement>}
|
||||
|
@ -115,8 +115,12 @@ const genSharedButtonStyle: GenerateStyle<ButtonToken, CSSObject> = (token): CSS
|
||||
};
|
||||
};
|
||||
|
||||
const genHoverActiveButtonStyle = (hoverStyle: CSSObject, activeStyle: CSSObject): CSSObject => ({
|
||||
'&:not(:disabled)': {
|
||||
const genHoverActiveButtonStyle = (
|
||||
btnCls: string,
|
||||
hoverStyle: CSSObject,
|
||||
activeStyle: CSSObject,
|
||||
): CSSObject => ({
|
||||
[`&:not(:disabled):not(${btnCls}-disabled)`]: {
|
||||
'&:hover': hoverStyle,
|
||||
'&:active': activeStyle,
|
||||
},
|
||||
@ -161,6 +165,7 @@ const genGhostButtonStyle = (
|
||||
boxShadow: 'none',
|
||||
|
||||
...genHoverActiveButtonStyle(
|
||||
btnCls,
|
||||
{
|
||||
backgroundColor: 'transparent',
|
||||
...hoverStyle,
|
||||
@ -180,7 +185,7 @@ const genGhostButtonStyle = (
|
||||
});
|
||||
|
||||
const genSolidDisabledButtonStyle: GenerateStyle<ButtonToken, CSSObject> = (token) => ({
|
||||
'&:disabled': {
|
||||
[`&:disabled, &${token.componentCls}-disabled`]: {
|
||||
...genDisabledStyle(token),
|
||||
},
|
||||
});
|
||||
@ -190,7 +195,7 @@ const genSolidButtonStyle: GenerateStyle<ButtonToken, CSSObject> = (token) => ({
|
||||
});
|
||||
|
||||
const genPureDisabledButtonStyle: GenerateStyle<ButtonToken, CSSObject> = (token) => ({
|
||||
'&:disabled': {
|
||||
[`&:disabled, &${token.componentCls}-disabled`]: {
|
||||
cursor: 'not-allowed',
|
||||
color: token.colorTextDisabled,
|
||||
},
|
||||
@ -206,6 +211,7 @@ const genDefaultButtonStyle: GenerateStyle<ButtonToken, CSSObject> = (token) =>
|
||||
boxShadow: `0 ${token.controlOutlineWidth}px 0 ${token.controlTmpOutline}`,
|
||||
|
||||
...genHoverActiveButtonStyle(
|
||||
token.componentCls,
|
||||
{
|
||||
color: token.colorPrimaryHover,
|
||||
borderColor: token.colorPrimaryHover,
|
||||
@ -229,6 +235,7 @@ const genDefaultButtonStyle: GenerateStyle<ButtonToken, CSSObject> = (token) =>
|
||||
borderColor: token.colorError,
|
||||
|
||||
...genHoverActiveButtonStyle(
|
||||
token.componentCls,
|
||||
{
|
||||
color: token.colorErrorHover,
|
||||
borderColor: token.colorErrorBorderHover,
|
||||
@ -260,6 +267,7 @@ const genPrimaryButtonStyle: GenerateStyle<ButtonToken, CSSObject> = (token) =>
|
||||
boxShadow: `0 ${token.controlOutlineWidth}px 0 ${token.controlOutline}`,
|
||||
|
||||
...genHoverActiveButtonStyle(
|
||||
token.componentCls,
|
||||
{
|
||||
color: token.colorTextLightSolid,
|
||||
backgroundColor: token.colorPrimaryHover,
|
||||
@ -291,6 +299,7 @@ const genPrimaryButtonStyle: GenerateStyle<ButtonToken, CSSObject> = (token) =>
|
||||
boxShadow: `0 ${token.controlOutlineWidth}px 0 ${token.colorErrorOutline}`,
|
||||
|
||||
...genHoverActiveButtonStyle(
|
||||
token.componentCls,
|
||||
{
|
||||
backgroundColor: token.colorErrorHover,
|
||||
},
|
||||
@ -329,6 +338,7 @@ const genLinkButtonStyle: GenerateStyle<ButtonToken, CSSObject> = (token) => ({
|
||||
color: token.colorLink,
|
||||
|
||||
...genHoverActiveButtonStyle(
|
||||
token.componentCls,
|
||||
{
|
||||
color: token.colorLinkHover,
|
||||
},
|
||||
@ -343,6 +353,7 @@ const genLinkButtonStyle: GenerateStyle<ButtonToken, CSSObject> = (token) => ({
|
||||
color: token.colorError,
|
||||
|
||||
...genHoverActiveButtonStyle(
|
||||
token.componentCls,
|
||||
{
|
||||
color: token.colorErrorHover,
|
||||
},
|
||||
@ -358,6 +369,7 @@ const genLinkButtonStyle: GenerateStyle<ButtonToken, CSSObject> = (token) => ({
|
||||
// Type: Text
|
||||
const genTextButtonStyle: GenerateStyle<ButtonToken, CSSObject> = (token) => ({
|
||||
...genHoverActiveButtonStyle(
|
||||
token.componentCls,
|
||||
{
|
||||
color: token.colorText,
|
||||
backgroundColor: token.colorBgTextHover,
|
||||
@ -375,6 +387,7 @@ const genTextButtonStyle: GenerateStyle<ButtonToken, CSSObject> = (token) => ({
|
||||
|
||||
...genPureDisabledButtonStyle(token),
|
||||
...genHoverActiveButtonStyle(
|
||||
token.componentCls,
|
||||
{
|
||||
color: token.colorErrorHover,
|
||||
backgroundColor: token.colorErrorBg,
|
||||
@ -387,14 +400,6 @@ const genTextButtonStyle: GenerateStyle<ButtonToken, CSSObject> = (token) => ({
|
||||
},
|
||||
});
|
||||
|
||||
// Href and Disabled
|
||||
const genDisabledButtonStyle: GenerateStyle<ButtonToken, CSSObject> = (token) => ({
|
||||
...genDisabledStyle(token),
|
||||
[`&${token.componentCls}:hover`]: {
|
||||
...genDisabledStyle(token),
|
||||
},
|
||||
});
|
||||
|
||||
const genTypeButtonStyle: GenerateStyle<ButtonToken> = (token) => {
|
||||
const { componentCls } = token;
|
||||
|
||||
@ -404,7 +409,6 @@ const genTypeButtonStyle: GenerateStyle<ButtonToken> = (token) => {
|
||||
[`${componentCls}-dashed`]: genDashedButtonStyle(token),
|
||||
[`${componentCls}-link`]: genLinkButtonStyle(token),
|
||||
[`${componentCls}-text`]: genTextButtonStyle(token),
|
||||
[`${componentCls}-disabled`]: genDisabledButtonStyle(token),
|
||||
};
|
||||
};
|
||||
|
||||
@ -528,7 +532,7 @@ export default genComponentStyleHook('Button', (token) => {
|
||||
// Block
|
||||
genBlockButtonStyle(buttonToken),
|
||||
|
||||
// Group (type, ghost, danger, disabled, loading)
|
||||
// Group (type, ghost, danger, loading)
|
||||
genTypeButtonStyle(buttonToken),
|
||||
|
||||
// Button Group
|
||||
|
@ -96,30 +96,39 @@ const defaultSearchRender: ShowSearchType['render'] = (inputValue, path, prefixC
|
||||
return optionList;
|
||||
};
|
||||
|
||||
type SingleCascaderProps = Omit<RcSingleCascaderProps, 'checkable' | 'options'> & {
|
||||
type SingleCascaderProps<OptionType extends BaseOptionType> = Omit<
|
||||
RcSingleCascaderProps<OptionType>,
|
||||
'checkable' | 'options'
|
||||
> & {
|
||||
multiple?: false;
|
||||
};
|
||||
type MultipleCascaderProps = Omit<RcMultipleCascaderProps, 'checkable' | 'options'> & {
|
||||
type MultipleCascaderProps<OptionType extends BaseOptionType> = Omit<
|
||||
RcMultipleCascaderProps<OptionType>,
|
||||
'checkable' | 'options'
|
||||
> & {
|
||||
multiple: true;
|
||||
};
|
||||
|
||||
type UnionCascaderProps = SingleCascaderProps | MultipleCascaderProps;
|
||||
type UnionCascaderProps<OptionType extends BaseOptionType> =
|
||||
| SingleCascaderProps<OptionType>
|
||||
| MultipleCascaderProps<OptionType>;
|
||||
|
||||
export type CascaderProps<DataNodeType = any> = UnionCascaderProps & {
|
||||
multiple?: boolean;
|
||||
size?: SizeType;
|
||||
disabled?: boolean;
|
||||
bordered?: boolean;
|
||||
placement?: SelectCommonPlacement;
|
||||
suffixIcon?: React.ReactNode;
|
||||
options?: DataNodeType[];
|
||||
status?: InputStatus;
|
||||
export type CascaderProps<DataNodeType extends BaseOptionType = any> =
|
||||
UnionCascaderProps<DataNodeType> & {
|
||||
multiple?: boolean;
|
||||
size?: SizeType;
|
||||
disabled?: boolean;
|
||||
bordered?: boolean;
|
||||
placement?: SelectCommonPlacement;
|
||||
suffixIcon?: React.ReactNode;
|
||||
options?: DataNodeType[];
|
||||
status?: InputStatus;
|
||||
|
||||
rootClassName?: string;
|
||||
popupClassName?: string;
|
||||
/** @deprecated Please use `popupClassName` instead */
|
||||
dropdownClassName?: string;
|
||||
};
|
||||
rootClassName?: string;
|
||||
popupClassName?: string;
|
||||
/** @deprecated Please use `popupClassName` instead */
|
||||
dropdownClassName?: string;
|
||||
};
|
||||
|
||||
export interface CascaderRef {
|
||||
focus: () => void;
|
||||
|
@ -83,7 +83,7 @@ The following APIs are shared by DatePicker, RangePicker.
|
||||
| className | The picker className | string | - | |
|
||||
| dateRender | Custom rendering function for date cells, >= 5.4.0 use `cellRender` instead. | function(currentDate: dayjs, today: dayjs) => React.ReactNode | - | < 5.4.0 |
|
||||
| changeOnBlur | Trigger `change` when blur. e.g. datetime picker no need click confirm button | boolean | false | 5.5.0 |
|
||||
| cellRender | Custom rendering function for picker cells | function(current: dayjs, today: dayjs, info: { originNode: React.ReactElement,today: DateType, range?: 'start' \| 'end', type: PanelMode, locale?: Locale, subType?: 'hour' \| 'minute' \| 'second' \| 'meridiem' }) => React.ReactNode | - | 5.4.0 |
|
||||
| cellRender | Custom rendering function for picker cells | (current: dayjs, info: { originNode: React.ReactElement,today: DateType, range?: 'start' \| 'end', type: PanelMode, locale?: Locale, subType?: 'hour' \| 'minute' \| 'second' \| 'meridiem' }) => React.ReactNode | - | 5.4.0 |
|
||||
| disabled | Determine whether the DatePicker is disabled | boolean | false | |
|
||||
| disabledDate | Specify the date that cannot be selected | (currentDate: dayjs) => boolean | - | |
|
||||
| format | To set the date format, support multi-format matching when it is an array, display the first one shall prevail. refer to [dayjs#format](https://day.js.org/docs/en/display/format). for example: [Custom Format](#components-date-picker-demo-format) | [formatType](#formattype) | [rc-picker](https://github.com/react-component/picker/blob/f512f18ed59d6791280d1c3d7d37abbb9867eb0b/src/utils/uiUtil.ts#L155-L177) | |
|
||||
@ -187,7 +187,7 @@ Added in `4.1.0`.
|
||||
| --- | --- | --- | --- | --- |
|
||||
| allowEmpty | Allow start or end input leave empty | \[boolean, boolean] | \[false, false] | |
|
||||
| dateRender | Custom rendering function for date cells, >= 5.4.0 use `cellRender` instead. | function(currentDate: dayjs, today: dayjs) => React.ReactNode | - | < 5.4.0 |
|
||||
| cellRender | Custom rendering function for picker cells | function(current: dayjs, today: dayjs, info: { originNode: React.ReactElement,today: DateType, range?: 'start' \| 'end', type: PanelMode, locale?: Locale, subType?: 'hour' \| 'minute' \| 'second' \| 'meridiem' }) => React.ReactNode | - | 5.4.0 |
|
||||
| cellRender | Custom rendering function for picker cells | (current: dayjs, info: { originNode: React.ReactElement,today: DateType, range?: 'start' \| 'end', type: PanelMode, locale?: Locale, subType?: 'hour' \| 'minute' \| 'second' \| 'meridiem' }) => React.ReactNode | - | 5.4.0 |
|
||||
| defaultPickerValue | To set default picker date | \[[dayjs](https://day.js.org/), [dayjs](https://day.js.org/)] | - | |
|
||||
| defaultValue | To set default date | \[[dayjs](https://day.js.org/), [dayjs](https://day.js.org/)] | - | |
|
||||
| disabled | If disable start or end | \[boolean, boolean] | - | |
|
||||
@ -248,8 +248,9 @@ Please use correct [language](/docs/react/i18n) ([#5605](https://github.com/ant-
|
||||
```js
|
||||
import dayjs from 'dayjs';
|
||||
import 'dayjs/locale/zh-cn';
|
||||
import 'dayjs/plugin/updateLocale';
|
||||
import updateLocale from 'dayjs/plugin/updateLocale';
|
||||
|
||||
dayjs.extend(updateLocale);
|
||||
dayjs.updateLocale('zh-cn', {
|
||||
weekStart: 0,
|
||||
});
|
||||
|
@ -84,7 +84,7 @@ import locale from 'antd/locale/zh_CN';
|
||||
| className | 选择器 className | string | - | |
|
||||
| dateRender | 自定义日期单元格的内容,5.4.0 起用 `cellRender` 代替 | function(currentDate: dayjs, today: dayjs) => React.ReactNode | - | < 5.4.0 |
|
||||
| changeOnBlur | 失去焦点时触发 `change` 事件,例如 datetime 下不再需要点击确认按钮 | boolean | false | 5.5.0 |
|
||||
| cellRender | 自定义单元格的内容 | function(current: dayjs, today: dayjs, info: { originNode: React.ReactElement,today: DateType, range?: 'start' \| 'end', type: PanelMode, locale?: Locale, subType?: 'hour' \| 'minute' \| 'second' \| 'meridiem' }) => React.ReactNode | - | 5.4.0 |
|
||||
| cellRender | 自定义单元格的内容 | (current: dayjs, info: { originNode: React.ReactElement,today: DateType, range?: 'start' \| 'end', type: PanelMode, locale?: Locale, subType?: 'hour' \| 'minute' \| 'second' \| 'meridiem' }) => React.ReactNode | - | 5.4.0 |
|
||||
| disabled | 禁用 | boolean | false | |
|
||||
| disabledDate | 不可选择的日期 | (currentDate: dayjs) => boolean | - | |
|
||||
| format | 设置日期格式,为数组时支持多格式匹配,展示以第一个为准。配置参考 [dayjs#format](https://day.js.org/docs/zh-CN/display/format#%E6%94%AF%E6%8C%81%E7%9A%84%E6%A0%BC%E5%BC%8F%E5%8C%96%E5%8D%A0%E4%BD%8D%E7%AC%A6%E5%88%97%E8%A1%A8)。示例:[自定义格式](#components-date-picker-demo-format) | [formatType](#formattype) | [rc-picker](https://github.com/react-component/picker/blob/f512f18ed59d6791280d1c3d7d37abbb9867eb0b/src/utils/uiUtil.ts#L155-L177) | |
|
||||
@ -188,7 +188,7 @@ import locale from 'antd/locale/zh_CN';
|
||||
| --- | --- | --- | --- | --- |
|
||||
| allowEmpty | 允许起始项部分为空 | \[boolean, boolean] | \[false, false] | |
|
||||
| dateRender | 自定义日期单元格的内容,5.4.0 起用 `cellRender` 代替 | function(currentDate: dayjs, today: dayjs) => React.ReactNode | - | < 5.4.0 |
|
||||
| cellRender | 自定义单元格的内容。 | function(current: dayjs, today: dayjs, info: { originNode: React.ReactElement,today: DateType, range?: 'start' \| 'end', type: PanelMode, locale?: Locale, subType?: 'hour' \| 'minute' \| 'second' \| 'meridiem' }) => React.ReactNode | - | 5.4.0 |
|
||||
| cellRender | 自定义单元格的内容。 | (current: dayjs, info: { originNode: React.ReactElement,today: DateType, range?: 'start' \| 'end', type: PanelMode, locale?: Locale, subType?: 'hour' \| 'minute' \| 'second' \| 'meridiem' }) => React.ReactNode | - | 5.4.0 |
|
||||
| defaultPickerValue | 默认面板日期 | [dayjs](https://day.js.org/)\[] | - | |
|
||||
| defaultValue | 默认日期 | [dayjs](https://day.js.org/)\[] | - | |
|
||||
| disabled | 禁用起始项 | \[boolean, boolean] | - | |
|
||||
@ -243,8 +243,10 @@ export type FormatType = Generic | GenericFn | Array<Generic | GenericFn>;
|
||||
```js
|
||||
import dayjs from 'dayjs';
|
||||
import 'dayjs/locale/zh-cn';
|
||||
import 'dayjs/plugin/updateLocale';
|
||||
|
||||
import updateLocale from 'dayjs/plugin/updateLocale';
|
||||
|
||||
dayjs.extend(updateLocale);
|
||||
dayjs.updateLocale('zh-cn', {
|
||||
weekStart: 0,
|
||||
});
|
||||
|
@ -1,8 +1,8 @@
|
||||
import { List } from 'rc-field-form';
|
||||
import type { StoreValue, ValidatorRule } from 'rc-field-form/lib/interface';
|
||||
import * as React from 'react';
|
||||
import { ConfigContext } from '../config-provider';
|
||||
import warning from '../_util/warning';
|
||||
import { ConfigContext } from '../config-provider';
|
||||
import { FormItemPrefixContext } from './context';
|
||||
|
||||
export interface FormListFieldData {
|
||||
@ -35,7 +35,12 @@ const FormList: React.FC<FormListProps> = ({
|
||||
children,
|
||||
...props
|
||||
}) => {
|
||||
warning(!!props.name, 'Form.List', 'Miss `name` prop.');
|
||||
warning(
|
||||
typeof props.name === 'number' ||
|
||||
(Array.isArray(props.name) ? !!props.name.length : !!props.name),
|
||||
'Form.List',
|
||||
'Miss `name` prop.',
|
||||
);
|
||||
|
||||
const { getPrefixCls } = React.useContext(ConfigContext);
|
||||
const prefixCls = getPrefixCls('form', customizePrefixCls);
|
||||
|
@ -7591,9 +7591,9 @@ exports[`renders components/form/demo/layout-can-wrap.tsx extend context correct
|
||||
<label
|
||||
class="ant-form-item-required ant-form-item-no-colon"
|
||||
for="wrap_username"
|
||||
title="正常标签文案"
|
||||
title="Normal label"
|
||||
>
|
||||
正常标签文案
|
||||
Normal label
|
||||
</label>
|
||||
</div>
|
||||
<div
|
||||
@ -7631,9 +7631,9 @@ exports[`renders components/form/demo/layout-can-wrap.tsx extend context correct
|
||||
<label
|
||||
class="ant-form-item-required ant-form-item-no-colon"
|
||||
for="wrap_password"
|
||||
title="超长标签文案超长标签文案"
|
||||
title="A super long label text"
|
||||
>
|
||||
超长标签文案超长标签文案
|
||||
A super long label text
|
||||
</label>
|
||||
</div>
|
||||
<div
|
||||
|
@ -4844,9 +4844,9 @@ exports[`renders components/form/demo/layout-can-wrap.tsx correctly 1`] = `
|
||||
<label
|
||||
class="ant-form-item-required ant-form-item-no-colon"
|
||||
for="wrap_username"
|
||||
title="正常标签文案"
|
||||
title="Normal label"
|
||||
>
|
||||
正常标签文案
|
||||
Normal label
|
||||
</label>
|
||||
</div>
|
||||
<div
|
||||
@ -4884,9 +4884,9 @@ exports[`renders components/form/demo/layout-can-wrap.tsx correctly 1`] = `
|
||||
<label
|
||||
class="ant-form-item-required ant-form-item-no-colon"
|
||||
for="wrap_password"
|
||||
title="超长标签文案超长标签文案"
|
||||
title="A super long label text"
|
||||
>
|
||||
超长标签文案超长标签文案
|
||||
A super long label text
|
||||
</label>
|
||||
</div>
|
||||
<div
|
||||
|
@ -262,4 +262,70 @@ describe('Form.List', () => {
|
||||
|
||||
errorSpy.mockRestore();
|
||||
});
|
||||
|
||||
it('no warning when name is 0', () => {
|
||||
const errorSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
|
||||
|
||||
render(
|
||||
<Form>
|
||||
<Form.List name={0}>
|
||||
{(fields) =>
|
||||
fields.map((field) => (
|
||||
<Form.Item {...field} key={field.key}>
|
||||
<Input />
|
||||
</Form.Item>
|
||||
))
|
||||
}
|
||||
</Form.List>
|
||||
</Form>,
|
||||
);
|
||||
|
||||
expect(errorSpy).not.toHaveBeenCalled();
|
||||
|
||||
errorSpy.mockRestore();
|
||||
});
|
||||
|
||||
it('warning when name is empty array', () => {
|
||||
const errorSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
|
||||
|
||||
render(
|
||||
<Form>
|
||||
<Form.List name={[]}>
|
||||
{(fields) =>
|
||||
fields.map((field) => (
|
||||
<Form.Item {...field} key={field.key}>
|
||||
<Input />
|
||||
</Form.Item>
|
||||
))
|
||||
}
|
||||
</Form.List>
|
||||
</Form>,
|
||||
);
|
||||
|
||||
expect(errorSpy).toHaveBeenCalled();
|
||||
|
||||
errorSpy.mockRestore();
|
||||
});
|
||||
|
||||
it('warning when name is null', () => {
|
||||
const errorSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
|
||||
|
||||
render(
|
||||
<Form>
|
||||
<Form.List name={null!!}>
|
||||
{(fields) =>
|
||||
fields.map((field) => (
|
||||
<Form.Item {...field} key={field.key}>
|
||||
<Input />
|
||||
</Form.Item>
|
||||
))
|
||||
}
|
||||
</Form.List>
|
||||
</Form>,
|
||||
);
|
||||
|
||||
expect(errorSpy).toHaveBeenCalled();
|
||||
|
||||
errorSpy.mockRestore();
|
||||
});
|
||||
});
|
||||
|
@ -1,5 +1,5 @@
|
||||
import React from 'react';
|
||||
import { Button, Form, Input } from 'antd';
|
||||
import React from 'react';
|
||||
|
||||
const App: React.FC = () => (
|
||||
<Form
|
||||
@ -11,11 +11,11 @@ const App: React.FC = () => (
|
||||
colon={false}
|
||||
style={{ maxWidth: 600 }}
|
||||
>
|
||||
<Form.Item label="正常标签文案" name="username" rules={[{ required: true }]}>
|
||||
<Form.Item label="Normal label" name="username" rules={[{ required: true }]}>
|
||||
<Input />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item label="超长标签文案超长标签文案" name="password" rules={[{ required: true }]}>
|
||||
<Form.Item label="A super long label text" name="password" rules={[{ required: true }]}>
|
||||
<Input />
|
||||
</Form.Item>
|
||||
|
||||
|
@ -12,6 +12,7 @@ const genBaseStyle: GenerateStyle<PopconfirmToken> = (token) => {
|
||||
const {
|
||||
componentCls,
|
||||
iconCls,
|
||||
antCls,
|
||||
zIndexPopup,
|
||||
colorText,
|
||||
colorWarning,
|
||||
@ -25,7 +26,10 @@ const genBaseStyle: GenerateStyle<PopconfirmToken> = (token) => {
|
||||
return {
|
||||
[componentCls]: {
|
||||
zIndex: zIndexPopup,
|
||||
color: colorText,
|
||||
|
||||
[`&${antCls}-popover`]: {
|
||||
fontSize,
|
||||
},
|
||||
|
||||
[`${componentCls}-message`]: {
|
||||
marginBottom: marginXS,
|
||||
@ -51,6 +55,7 @@ const genBaseStyle: GenerateStyle<PopconfirmToken> = (token) => {
|
||||
|
||||
[`${componentCls}-description`]: {
|
||||
marginTop: marginXXS,
|
||||
color: colorText,
|
||||
},
|
||||
},
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
import type { CSSObject } from '@ant-design/cssinjs';
|
||||
import { Keyframes } from '@ant-design/cssinjs';
|
||||
import { resetComponent } from '../../style';
|
||||
import type { FullToken, GenerateStyle } from '../../theme/internal';
|
||||
import { genComponentStyleHook, mergeToken } from '../../theme/internal';
|
||||
import { resetComponent } from '../../style';
|
||||
|
||||
export interface ComponentToken {}
|
||||
|
||||
@ -16,20 +16,23 @@ interface ProgressToken extends FullToken<'Progress'> {
|
||||
progressActiveMotionDuration: string;
|
||||
}
|
||||
|
||||
const antProgressActive = new Keyframes('antProgressActive', {
|
||||
'0%': {
|
||||
transform: 'translateX(-100%) scaleX(0)',
|
||||
opacity: 0.1,
|
||||
},
|
||||
'20%': {
|
||||
transform: 'translateX(-100%) scaleX(0)',
|
||||
opacity: 0.5,
|
||||
},
|
||||
to: {
|
||||
transform: 'translateX(0) scaleX(1)',
|
||||
opacity: 0,
|
||||
},
|
||||
});
|
||||
const genAntProgressActive = (isRtl?: boolean) => {
|
||||
const direction = isRtl ? '100%' : '-100%';
|
||||
return new Keyframes(`antProgress${isRtl ? 'RTL' : 'LTR'}Active`, {
|
||||
'0%': {
|
||||
transform: `translateX(${direction}) scaleX(0)`,
|
||||
opacity: 0.1,
|
||||
},
|
||||
'20%': {
|
||||
transform: `translateX(${direction}) scaleX(0)`,
|
||||
opacity: 0.5,
|
||||
},
|
||||
to: {
|
||||
transform: 'translateX(0) scaleX(1)',
|
||||
opacity: 0,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const genBaseStyle: GenerateStyle<ProgressToken> = (token) => {
|
||||
const { componentCls: progressCls, iconCls: iconPrefixCls } = token;
|
||||
@ -116,7 +119,7 @@ const genBaseStyle: GenerateStyle<ProgressToken> = (token) => {
|
||||
backgroundColor: token.colorBgContainer,
|
||||
borderRadius: token.progressLineRadius,
|
||||
opacity: 0,
|
||||
animationName: antProgressActive,
|
||||
animationName: genAntProgressActive(),
|
||||
animationDuration: token.progressActiveMotionDuration,
|
||||
animationTimingFunction: token.motionEaseOutQuint,
|
||||
animationIterationCount: 'infinite',
|
||||
@ -124,6 +127,12 @@ const genBaseStyle: GenerateStyle<ProgressToken> = (token) => {
|
||||
},
|
||||
},
|
||||
|
||||
[`&${progressCls}-rtl${progressCls}-status-active`]: {
|
||||
[`${progressCls}-bg::before`]: {
|
||||
animationName: genAntProgressActive(true),
|
||||
},
|
||||
},
|
||||
|
||||
[`&${progressCls}-status-exception`]: {
|
||||
[`${progressCls}-bg`]: {
|
||||
backgroundColor: token.colorError,
|
||||
|
@ -235,7 +235,7 @@ const genBaseStyle: GenerateStyle<SelectToken> = (token) => {
|
||||
// ========================= Feedback ==========================
|
||||
[`${componentCls}-has-feedback`]: {
|
||||
[`${componentCls}-clear`]: {
|
||||
insetInlineEnd: inputPaddingHorizontalBase + token.fontSize + token.paddingXXS,
|
||||
insetInlineEnd: inputPaddingHorizontalBase + token.fontSize + token.paddingXS,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
@ -61,10 +61,10 @@ function renderIndicator(prefixCls: string, props: SpinClassProps): React.ReactN
|
||||
|
||||
return (
|
||||
<span className={classNames(dotClassName, `${prefixCls}-dot-spin`)}>
|
||||
<i className={`${prefixCls}-dot-item`} />
|
||||
<i className={`${prefixCls}-dot-item`} />
|
||||
<i className={`${prefixCls}-dot-item`} />
|
||||
<i className={`${prefixCls}-dot-item`} />
|
||||
<i className={`${prefixCls}-dot-item`} key={1} />
|
||||
<i className={`${prefixCls}-dot-item`} key={2} />
|
||||
<i className={`${prefixCls}-dot-item`} key={3} />
|
||||
<i className={`${prefixCls}-dot-item`} key={4} />
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
@ -1,9 +1,9 @@
|
||||
import type { DragEndEvent } from '@dnd-kit/core';
|
||||
import { DndContext } from '@dnd-kit/core';
|
||||
import { DndContext, PointerSensor, useSensor, useSensors } from '@dnd-kit/core';
|
||||
import { restrictToVerticalAxis } from '@dnd-kit/modifiers';
|
||||
import {
|
||||
arrayMove,
|
||||
SortableContext,
|
||||
arrayMove,
|
||||
useSortable,
|
||||
verticalListSortingStrategy,
|
||||
} from '@dnd-kit/sortable';
|
||||
@ -77,6 +77,15 @@ const App: React.FC = () => {
|
||||
},
|
||||
]);
|
||||
|
||||
const sensors = useSensors(
|
||||
useSensor(PointerSensor, {
|
||||
activationConstraint: {
|
||||
// https://docs.dndkit.com/api-documentation/sensors/pointer#activation-constraints
|
||||
distance: 1,
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
const onDragEnd = ({ active, over }: DragEndEvent) => {
|
||||
if (active.id !== over?.id) {
|
||||
setDataSource((prev) => {
|
||||
@ -88,7 +97,7 @@ const App: React.FC = () => {
|
||||
};
|
||||
|
||||
return (
|
||||
<DndContext modifiers={[restrictToVerticalAxis]} onDragEnd={onDragEnd}>
|
||||
<DndContext sensors={sensors} modifiers={[restrictToVerticalAxis]} onDragEnd={onDragEnd}>
|
||||
<SortableContext
|
||||
// rowKey array
|
||||
items={dataSource.map((i) => i.key)}
|
||||
|
@ -1,14 +1,14 @@
|
||||
import React, { useState } from 'react';
|
||||
import { Tag } from 'antd';
|
||||
import { DndContext, PointerSensor, useSensor, useSensors, closestCenter } from '@dnd-kit/core';
|
||||
import {
|
||||
arrayMove,
|
||||
useSortable,
|
||||
SortableContext,
|
||||
horizontalListSortingStrategy,
|
||||
} from '@dnd-kit/sortable';
|
||||
import type { FC } from 'react';
|
||||
import { DndContext, PointerSensor, closestCenter, useSensor, useSensors } from '@dnd-kit/core';
|
||||
import type { DragEndEvent } from '@dnd-kit/core/dist/types/index';
|
||||
import {
|
||||
SortableContext,
|
||||
arrayMove,
|
||||
horizontalListSortingStrategy,
|
||||
useSortable,
|
||||
} from '@dnd-kit/sortable';
|
||||
import { Tag } from 'antd';
|
||||
import type { FC } from 'react';
|
||||
import React, { useState } from 'react';
|
||||
|
||||
type Item = {
|
||||
id: number;
|
||||
@ -25,14 +25,14 @@ const DraggableTag: FC<DraggableTagProps> = (props) => {
|
||||
|
||||
const commonStyle = {
|
||||
cursor: 'move',
|
||||
transition: 'unset', // 防止拖拽完毕之后元素抖动
|
||||
transition: 'unset', // Prevent element from shaking after drag
|
||||
};
|
||||
|
||||
const style = transform
|
||||
? {
|
||||
...commonStyle,
|
||||
transform: `translate3d(${transform.x}px, ${transform.y}px, 0)`,
|
||||
transition: isDragging ? 'unset' : transition, // 处理拖拽中的元素不跟手的问题
|
||||
transition: isDragging ? 'unset' : transition, // Improve performance/visual effect when dragging
|
||||
}
|
||||
: commonStyle;
|
||||
|
||||
|
@ -50,6 +50,7 @@ dayjs.extend(customParseFormat)
|
||||
| allowClear | Whether allow clearing text | boolean | true | |
|
||||
| autoFocus | If get focus when component mounted | boolean | false | |
|
||||
| bordered | Whether has border style | boolean | true | |
|
||||
| cellRender | Custom rendering function for picker cells | (current: number, info: { originNode: React.ReactElement, today: dayjs, range?: 'start' \| 'end', subType: 'hour' \| 'minute' \| 'second' \| 'meridiem' }) => React.ReactNode | - | 5.4.0 |
|
||||
| changeOnBlur | Trigger `change` when blur. e.g. datetime picker no need click confirm button | boolean | false | 5.5.0 |
|
||||
| className | The className of picker | string | - | |
|
||||
| clearIcon | The custom clear icon | ReactNode | - | |
|
||||
|
@ -50,6 +50,7 @@ dayjs.extend(customParseFormat)
|
||||
| allowClear | 是否展示清除按钮 | boolean | true | |
|
||||
| autoFocus | 自动获取焦点 | boolean | false | |
|
||||
| bordered | 是否有边框 | boolean | true | |
|
||||
| cellRender | 自定义单元格的内容 | (current: number, info: { originNode: React.ReactNode, today: dayjs, range?: 'start' \| 'end', subType: 'hour' \| 'minute' \| 'second' \| 'meridiem' }) => React.ReactNode | - | 5.4.0 |
|
||||
| changeOnBlur | 失去焦点时触发 `change` 事件,例如 datetime 下不再需要点击确认按钮 | boolean | false | 5.5.0 |
|
||||
| className | 选择器类名 | string | - | |
|
||||
| clearIcon | 自定义的清除图标 | ReactNode | - | |
|
||||
|
@ -1,14 +1,17 @@
|
||||
import classNames from 'classnames';
|
||||
import * as React from 'react';
|
||||
|
||||
import useMergedState from 'rc-util/lib/hooks/useMergedState';
|
||||
import type { KeyWiseTransferItem } from '.';
|
||||
import type { PaginationType } from './interface';
|
||||
import type { RenderedItem, TransferListProps } from './list';
|
||||
import Pagination from '../pagination';
|
||||
import ListItem from './ListItem';
|
||||
import type { PaginationType } from './interface';
|
||||
import type { RenderedItem, TransferListProps } from './list';
|
||||
|
||||
export const OmitProps = ['handleFilter', 'handleClear', 'checkedKeys'] as const;
|
||||
export type OmitProp = typeof OmitProps[number];
|
||||
export type OmitProp = (typeof OmitProps)[number];
|
||||
type PartialTransferListProps<RecordType> = Omit<TransferListProps<RecordType>, OmitProp>;
|
||||
type ExistPagination = Exclude<PaginationType, boolean>;
|
||||
|
||||
export interface TransferListBodyProps<RecordType> extends PartialTransferListProps<RecordType> {
|
||||
filteredItems: RecordType[];
|
||||
@ -16,25 +19,15 @@ export interface TransferListBodyProps<RecordType> extends PartialTransferListPr
|
||||
selectedKeys: string[];
|
||||
}
|
||||
|
||||
const parsePagination = (pagination?: PaginationType) => {
|
||||
if (!pagination) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const parsePagination = (pagination?: ExistPagination) => {
|
||||
const defaultPagination: PaginationType = {
|
||||
pageSize: 10,
|
||||
simple: true,
|
||||
showSizeChanger: false,
|
||||
showLessItems: false,
|
||||
};
|
||||
|
||||
if (typeof pagination === 'object') {
|
||||
return { ...defaultPagination, ...pagination };
|
||||
}
|
||||
|
||||
return defaultPagination;
|
||||
return { ...defaultPagination, ...pagination };
|
||||
};
|
||||
|
||||
export interface ListBodyRef<RecordType extends KeyWiseTransferItem> {
|
||||
items?: RenderedItem<RecordType>[];
|
||||
}
|
||||
@ -57,16 +50,28 @@ const TransferListBody: React.ForwardRefRenderFunction<
|
||||
onItemSelect,
|
||||
onItemRemove,
|
||||
} = props;
|
||||
|
||||
const [current, setCurrent] = React.useState<number>(1);
|
||||
|
||||
const mergedPagination = React.useMemo(() => {
|
||||
if (!pagination) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const convertPagination = typeof pagination === 'object' ? pagination : {};
|
||||
|
||||
return parsePagination(convertPagination);
|
||||
}, [pagination]);
|
||||
|
||||
const [pageSize, setPageSize] = useMergedState<number>(10, {
|
||||
value: mergedPagination?.pageSize,
|
||||
});
|
||||
|
||||
React.useEffect(() => {
|
||||
const mergedPagination = parsePagination(pagination);
|
||||
if (mergedPagination) {
|
||||
const maxPageCount = Math.ceil(filteredRenderItems.length / mergedPagination.pageSize!);
|
||||
const maxPageCount = Math.ceil(filteredRenderItems.length / pageSize!);
|
||||
setCurrent(Math.min(current, maxPageCount));
|
||||
}
|
||||
}, [filteredRenderItems, pagination]);
|
||||
}, [filteredRenderItems, mergedPagination, pageSize]);
|
||||
|
||||
const onClick = (item: RecordType) => {
|
||||
onItemSelect?.(item.key, !selectedKeys.includes(item.key));
|
||||
@ -80,33 +85,33 @@ const TransferListBody: React.ForwardRefRenderFunction<
|
||||
setCurrent(cur);
|
||||
};
|
||||
|
||||
const onSizeChange = (cur: number, size: number) => {
|
||||
setCurrent(cur);
|
||||
setPageSize(size);
|
||||
};
|
||||
|
||||
const memoizedItems = React.useMemo<RenderedItem<RecordType>[]>(() => {
|
||||
const mergedPagination = parsePagination(pagination);
|
||||
const displayItems = mergedPagination
|
||||
? filteredRenderItems.slice(
|
||||
(current - 1) * mergedPagination.pageSize!,
|
||||
current * mergedPagination.pageSize!,
|
||||
)
|
||||
? filteredRenderItems.slice((current - 1) * pageSize!, current * pageSize!)
|
||||
: filteredRenderItems;
|
||||
return displayItems;
|
||||
}, [current, filteredRenderItems, pagination]);
|
||||
}, [current, filteredRenderItems, mergedPagination, pageSize]);
|
||||
|
||||
React.useImperativeHandle(ref, () => ({ items: memoizedItems }));
|
||||
|
||||
const mergedPagination = parsePagination(pagination);
|
||||
|
||||
const paginationNode: React.ReactNode = mergedPagination ? (
|
||||
<Pagination
|
||||
size="small"
|
||||
disabled={globalDisabled}
|
||||
simple={mergedPagination.simple}
|
||||
pageSize={mergedPagination.pageSize}
|
||||
pageSize={pageSize}
|
||||
showLessItems={mergedPagination.showLessItems}
|
||||
showSizeChanger={mergedPagination.showSizeChanger}
|
||||
className={`${prefixCls}-pagination`}
|
||||
total={filteredRenderItems.length}
|
||||
current={current}
|
||||
onChange={onPageChange}
|
||||
onShowSizeChange={onSizeChange}
|
||||
/>
|
||||
) : null;
|
||||
|
||||
|
@ -73,6 +73,19 @@ const searchTransferProps = {
|
||||
targetKeys: ['3', '4'],
|
||||
};
|
||||
|
||||
const generateData = (n = 20) => {
|
||||
const data = [];
|
||||
for (let i = 0; i < n; i++) {
|
||||
data.push({
|
||||
key: `${i}`,
|
||||
title: `content${i}`,
|
||||
description: `description of content${i}`,
|
||||
chosen: false,
|
||||
});
|
||||
}
|
||||
return data;
|
||||
};
|
||||
|
||||
describe('Transfer', () => {
|
||||
mountTest(Transfer);
|
||||
rtlTest(Transfer);
|
||||
@ -595,6 +608,32 @@ describe('Transfer', () => {
|
||||
);
|
||||
await waitFor(() => expect(getAllByTitle('1/1')).toHaveLength(2));
|
||||
});
|
||||
|
||||
it('should support change pageSize', () => {
|
||||
const dataSource = generateData();
|
||||
const { container } = render(
|
||||
<Transfer dataSource={dataSource} pagination={{ showSizeChanger: true, simple: false }} />,
|
||||
);
|
||||
|
||||
fireEvent.mouseDown(container.querySelector('.ant-select-selector')!);
|
||||
fireEvent.click(container.querySelectorAll('.ant-select-item-option')[1]);
|
||||
expect(container.querySelectorAll('.ant-transfer-list-content-item').length).toBe(20);
|
||||
});
|
||||
|
||||
it('should be used first when pagination has pagesize', () => {
|
||||
const dataSource = generateData(30);
|
||||
|
||||
const { container } = render(
|
||||
<Transfer
|
||||
dataSource={dataSource}
|
||||
pagination={{ showSizeChanger: true, simple: false, pageSize: 20 }}
|
||||
/>,
|
||||
);
|
||||
|
||||
fireEvent.mouseDown(container.querySelector('.ant-select-selector')!);
|
||||
fireEvent.click(container.querySelectorAll('.ant-select-item-option')[2]);
|
||||
expect(container.querySelectorAll('.ant-transfer-list-content-item').length).toBe(20);
|
||||
});
|
||||
});
|
||||
|
||||
it('remove by click icon', () => {
|
||||
|
@ -110,7 +110,6 @@ const TransferList = <RecordType extends KeyWiseTransferItem>(
|
||||
} = props;
|
||||
|
||||
const [filterValue, setFilterValue] = useState<string>('');
|
||||
|
||||
const listBodyRef = useRef<ListBodyRef<RecordType>>({});
|
||||
|
||||
const internalHandleFilter = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
|
@ -101,6 +101,7 @@ const genTransferListStyle: GenerateStyle<TransferToken> = (token: TransferToken
|
||||
marginXS,
|
||||
paddingSM,
|
||||
lineType,
|
||||
antCls,
|
||||
iconCls,
|
||||
motionDurationSlow,
|
||||
controlItemBgHover,
|
||||
@ -174,8 +175,9 @@ const genTransferListStyle: GenerateStyle<TransferToken> = (token: TransferToken
|
||||
display: 'flex',
|
||||
flex: 'auto',
|
||||
flexDirection: 'column',
|
||||
overflow: 'hidden',
|
||||
fontSize: token.fontSize,
|
||||
// https://blog.csdn.net/qq449245884/article/details/107373672/
|
||||
minHeight: 0,
|
||||
|
||||
'&-search-wrapper': {
|
||||
position: 'relative',
|
||||
@ -262,6 +264,10 @@ const genTransferListStyle: GenerateStyle<TransferToken> = (token: TransferToken
|
||||
padding: `${token.paddingXS}px 0`,
|
||||
textAlign: 'end',
|
||||
borderTop: `${lineWidth}px ${lineType} ${colorSplit}`,
|
||||
|
||||
[`${antCls}-pagination-options`]: {
|
||||
paddingInlineEnd: token.paddingXS,
|
||||
},
|
||||
},
|
||||
|
||||
'&-body-not-found': {
|
||||
|
@ -1,9 +1,9 @@
|
||||
/* eslint-disable @typescript-eslint/no-shadow */
|
||||
import React from 'react';
|
||||
import type { TreeProps } from 'antd';
|
||||
import { Tree, Switch } from 'antd';
|
||||
import { CarryOutOutlined } from '@ant-design/icons';
|
||||
import type { TreeProps } from 'antd';
|
||||
import { Switch, Tree } from 'antd';
|
||||
import type { DataNode } from 'rc-tree/lib/interface';
|
||||
import React from 'react';
|
||||
|
||||
const x = 3;
|
||||
const y = 2;
|
||||
@ -40,7 +40,7 @@ const App: React.FC = () => {
|
||||
|
||||
const onDragEnter: TreeProps['onDragEnter'] = (info) => {
|
||||
console.log(info);
|
||||
// expandedKeys 需要受控时设置
|
||||
// expandedKeys, set it when controlled is needed
|
||||
setExpandedKeys(info.expandedKeys);
|
||||
};
|
||||
|
||||
@ -79,7 +79,7 @@ const App: React.FC = () => {
|
||||
// Drop on the content
|
||||
loop(data, dropKey, (item) => {
|
||||
item.children = item.children || [];
|
||||
// where to insert 示例添加到尾部,可以是随意位置
|
||||
// where to insert. New item was inserted to the end of the array in this example, but can be anywhere
|
||||
item.children.push(dragObj);
|
||||
});
|
||||
} else if (
|
||||
@ -89,7 +89,7 @@ const App: React.FC = () => {
|
||||
) {
|
||||
loop(data, dropKey, (item) => {
|
||||
item.children = item.children || [];
|
||||
// where to insert 示例添加到头部,可以是随意位置
|
||||
// where to insert. New item was inserted to the start of the array in this example, but can be anywhere
|
||||
item.children.unshift(dragObj);
|
||||
});
|
||||
} else {
|
||||
|
@ -1,6 +1,6 @@
|
||||
import React, { useState } from 'react';
|
||||
import { Tree } from 'antd';
|
||||
import type { DataNode, TreeProps } from 'antd/es/tree';
|
||||
import React, { useState } from 'react';
|
||||
|
||||
const x = 3;
|
||||
const y = 2;
|
||||
@ -36,7 +36,7 @@ const App: React.FC = () => {
|
||||
|
||||
const onDragEnter: TreeProps['onDragEnter'] = (info) => {
|
||||
console.log(info);
|
||||
// expandedKeys 需要受控时设置
|
||||
// expandedKeys, set it when controlled is needed
|
||||
// setExpandedKeys(info.expandedKeys)
|
||||
};
|
||||
|
||||
@ -74,7 +74,7 @@ const App: React.FC = () => {
|
||||
// Drop on the content
|
||||
loop(data, dropKey, (item) => {
|
||||
item.children = item.children || [];
|
||||
// where to insert 示例添加到头部,可以是随意位置
|
||||
// where to insert. New item was inserted to the start of the array in this example, but can be anywhere
|
||||
item.children.unshift(dragObj);
|
||||
});
|
||||
} else if (
|
||||
@ -84,7 +84,7 @@ const App: React.FC = () => {
|
||||
) {
|
||||
loop(data, dropKey, (item) => {
|
||||
item.children = item.children || [];
|
||||
// where to insert 示例添加到头部,可以是随意位置
|
||||
// where to insert. New item was inserted to the start of the array in this example, but can be anywhere
|
||||
item.children.unshift(dragObj);
|
||||
// in previous version, we use item.children.push(dragObj) to insert the
|
||||
// item to the tail of the children
|
||||
|
@ -11,17 +11,17 @@ import useMergedState from 'rc-util/lib/hooks/useMergedState';
|
||||
import omit from 'rc-util/lib/omit';
|
||||
import { composeRef } from 'rc-util/lib/ref';
|
||||
import * as React from 'react';
|
||||
import { isStyleSupport } from '../../_util/styleChecker';
|
||||
import TransButton from '../../_util/transButton';
|
||||
import { ConfigContext } from '../../config-provider';
|
||||
import useLocale from '../../locale/useLocale';
|
||||
import type { TooltipProps } from '../../tooltip';
|
||||
import Tooltip from '../../tooltip';
|
||||
import { isStyleSupport } from '../../_util/styleChecker';
|
||||
import TransButton from '../../_util/transButton';
|
||||
import Editable from '../Editable';
|
||||
import useMergedConfig from '../hooks/useMergedConfig';
|
||||
import useUpdatedEffect from '../hooks/useUpdatedEffect';
|
||||
import type { TypographyProps } from '../Typography';
|
||||
import Typography from '../Typography';
|
||||
import useMergedConfig from '../hooks/useMergedConfig';
|
||||
import useUpdatedEffect from '../hooks/useUpdatedEffect';
|
||||
import Ellipsis from './Ellipsis';
|
||||
import EllipsisTooltip from './EllipsisTooltip';
|
||||
|
||||
@ -193,7 +193,7 @@ const Base = React.forwardRef<HTMLElement, BlockProps>((props, ref) => {
|
||||
// ========================== Copyable ==========================
|
||||
const [enableCopy, copyConfig] = useMergedConfig<CopyConfig>(copyable);
|
||||
const [copied, setCopied] = React.useState(false);
|
||||
const copyIdRef = React.useRef<number>();
|
||||
const copyIdRef = React.useRef<NodeJS.Timeout | null>(null);
|
||||
|
||||
const copyOptions: Pick<CopyConfig, 'format'> = {};
|
||||
if (copyConfig.format) {
|
||||
@ -201,7 +201,9 @@ const Base = React.forwardRef<HTMLElement, BlockProps>((props, ref) => {
|
||||
}
|
||||
|
||||
const cleanCopyId = () => {
|
||||
window.clearTimeout(copyIdRef.current!);
|
||||
if (copyIdRef.current) {
|
||||
clearTimeout(copyIdRef.current);
|
||||
}
|
||||
};
|
||||
|
||||
const onCopyClick = (e?: React.MouseEvent<HTMLDivElement>) => {
|
||||
@ -214,7 +216,7 @@ const Base = React.forwardRef<HTMLElement, BlockProps>((props, ref) => {
|
||||
|
||||
// Trigger tips update
|
||||
cleanCopyId();
|
||||
copyIdRef.current = window.setTimeout(() => {
|
||||
copyIdRef.current = setTimeout(() => {
|
||||
setCopied(false);
|
||||
}, 3000);
|
||||
|
||||
|
@ -234,3 +234,34 @@ Here are some typical wrong examples:
|
||||
## Do you guys have any channel or website for submitting monetary donations, like through PayPal or Alipay?
|
||||
|
||||
[https://opencollective.com/ant-design](https://opencollective.com/ant-design)
|
||||
|
||||
## Use Form's `setFieldsValue` method to report an error if the object type contains `null`
|
||||
|
||||
When we try to set the form value using the `setFieldsValue` method in the form instance of the form component, if the passed object contains the type null, such as:
|
||||
|
||||
```tsx
|
||||
// This is not real world code, just for explain
|
||||
import { Form } from 'antd';
|
||||
|
||||
type Test = {
|
||||
value: string[] | null;
|
||||
};
|
||||
|
||||
export default () => {
|
||||
const [form] = Form.useForm<Test>();
|
||||
|
||||
form.setFieldsValue({
|
||||
value: null, // Error: Type "null" cannot be assigned to type "string[] | undefined".
|
||||
});
|
||||
};
|
||||
```
|
||||
|
||||
If you encounter the above error, please check the current project `tsconfig.json` contains the following configuration:
|
||||
|
||||
```json
|
||||
{
|
||||
"strictNullChecks": true
|
||||
}
|
||||
```
|
||||
|
||||
The above problem occurs if `strictNullChecks` is set to `true`, If you can determine the project don't need this configuration (see [strictNullChecks](https://www.typescriptlang.org/zh/tsconfig#strictNullChecks) to judge whether need the configuration). You can try changing to `false` to turn off the control strict check. However, if you do need to enable this feature, you can avoid this situation by using other types instead of `null` when designing types
|
||||
|
@ -256,3 +256,34 @@ import { ConfigProvider } from 'antd';
|
||||
## 你们有接受捐助的渠道吗,比如支付宝或者微信支付?
|
||||
|
||||
[https://opencollective.com/ant-design](https://opencollective.com/ant-design)
|
||||
|
||||
## 使用表单组件的 `setFieldsValue` 方法如果对象类型中含有 `null` 时 TS 类型报错
|
||||
|
||||
当我们尝试使用表单组件的表单实例当中的 `setFieldsValue` 方法设置表单值时,如果在传入的对象中包含有 `null` 类型,如:
|
||||
|
||||
```tsx
|
||||
// This is not real world code, just for explain
|
||||
import { Form } from 'antd';
|
||||
|
||||
type Test = {
|
||||
value: string[] | null;
|
||||
};
|
||||
|
||||
export default () => {
|
||||
const [form] = Form.useForm<Test>();
|
||||
|
||||
form.setFieldsValue({
|
||||
value: null, // Error: 不能将类型“null”分配给类型“string[] | undefined”。
|
||||
});
|
||||
};
|
||||
```
|
||||
|
||||
如果你遇到上述报错,请检查当前项目的 `tsconfig.json` 中是否包含如下配置:
|
||||
|
||||
```json
|
||||
{
|
||||
"strictNullChecks": true
|
||||
}
|
||||
```
|
||||
|
||||
如果 `strictNullChecks` 的值被设置为 `true` 就会出现上述问题,如果你确定项目中可以不需要这个检测配置(查看[strictNullChecks](https://www.typescriptlang.org/zh/tsconfig#strictNullChecks)判断是否需要该配置),可以尝试改为 `false` 关闭控制严格检查功能。但如果你确实需要开启这个功能,那么,你可以在设计类型时,使用其他类型替代 `null` 以避免出现这种情况。
|
||||
|
@ -66,7 +66,7 @@ title: 数据格式
|
||||
<img class="preview-img bad" alt="不推荐示例" description="“千”不能以单位的形式展示。" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*iuEARoq_-o0AAAAAAAAAAABkARQnAQ">
|
||||
</ImagePreview>
|
||||
|
||||
**大额计量:** 如果一个金额很大,那么数值中的“万”“亿”单位可采用汉字。如果一个数值很大,那么数值中的“万”“亿”单位可采用汉字。
|
||||
**大额计量:** 如果一个数值很大,那么数值中的“万”“亿”单位可采用汉字。
|
||||
|
||||
### 日期时间
|
||||
|
||||
|
@ -16,19 +16,19 @@ Our Gray Matter are wired to react to dynamic things like movement,shape change
|
||||
## Maintain Context While Changing Views
|
||||
|
||||
<video class="transition-video-player" alt="example of Slide In and Slide Out
|
||||
" src="https://os.alipayobjects.com/rmsportal/EejaUGsyExkXyXr.mp4" />
|
||||
" src="https://os.alipayobjects.com/rmsportal/EejaUGsyExkXyXr.mp4"></video>
|
||||
|
||||
Slide In and Slide Out: Create an illusion of virtual space.
|
||||
|
||||
<br>
|
||||
|
||||
<video class="transition-video-player" alt="example of Carousel" src="https://os.alipayobjects.com/rmsportal/GIutPgZMTyfFfrH.mp4" />
|
||||
<video class="transition-video-player" alt="example of Carousel" src="https://os.alipayobjects.com/rmsportal/GIutPgZMTyfFfrH.mp4"></video>
|
||||
|
||||
Carousel: Carousels are great for extending virtual space.
|
||||
|
||||
<br>
|
||||
|
||||
<video class="transition-video-player" alt="example of Accordion" src="https://os.alipayobjects.com/rmsportal/ERKhqHlcHiCDSQu.mp4" />
|
||||
<video class="transition-video-player" alt="example of Accordion" src="https://os.alipayobjects.com/rmsportal/ERKhqHlcHiCDSQu.mp4"></video>
|
||||
|
||||
Accordion: Accordion helps maintain context while switching views.
|
||||
|
||||
@ -38,25 +38,25 @@ Accordion: Accordion helps maintain context while switching views.
|
||||
|
||||
## Explain What Just Happened
|
||||
|
||||
<video class="transition-video-player" alt="example of Adding an Object" description="When an object is added, the highlighted area shows it to the user. The highlight fades in several seconds in order not to interfere the user flow." src="https://os.alipayobjects.com/rmsportal/FqkQMyFqNqielOw.mp4" />
|
||||
<video class="transition-video-player" alt="example of Adding an Object" description="When an object is added, the highlighted area shows it to the user. The highlight fades in several seconds in order not to interfere the user flow." src="https://os.alipayobjects.com/rmsportal/FqkQMyFqNqielOw.mp4"></video>
|
||||
|
||||
Adding an Object: Add an object in the table or chart.
|
||||
|
||||
<br>
|
||||
|
||||
<video class="transition-video-player" alt="example of Deleting Objects" src="https://os.alipayobjects.com/rmsportal/pnNkNIMoowmGUQy.mp4" />
|
||||
<video class="transition-video-player" alt="example of Deleting Objects" src="https://os.alipayobjects.com/rmsportal/pnNkNIMoowmGUQy.mp4"></video>
|
||||
|
||||
Deleting an Object: Delete an object in the table or chart.
|
||||
|
||||
<br>
|
||||
|
||||
<video class="transition-video-player" alt="example of Modifying an object" description="Status No.1: The user modifies the value of Detail. <br>Status No.2: After the user click the save button, a yellow fill is displayed in the grid of Detail, which indicates the change of the object. <br>Status No.3: The fill fades in several seconds and returned to normal." src="https://os.alipayobjects.com/rmsportal/XrUIWmsmOlEnZGc.mp4" />
|
||||
<video class="transition-video-player" alt="example of Modifying an object" description="Status No.1: The user modifies the value of Detail. <br>Status No.2: After the user click the save button, a yellow fill is displayed in the grid of Detail, which indicates the change of the object. <br>Status No.3: The fill fades in several seconds and returned to normal." src="https://os.alipayobjects.com/rmsportal/XrUIWmsmOlEnZGc.mp4"></video>
|
||||
|
||||
Modifying an Object: Modify an object in the table or chart.
|
||||
|
||||
<br>
|
||||
|
||||
<video class="transition-video-player" alt="example of Calling out an Object" src="https://os.alipayobjects.com/rmsportal/gSNilqbiXOufDXF.mp4" />
|
||||
<video class="transition-video-player" alt="example of Calling out an Object" src="https://os.alipayobjects.com/rmsportal/gSNilqbiXOufDXF.mp4"></video>
|
||||
|
||||
Calling out an Object: Click the page element and call out a new object.
|
||||
|
||||
|
@ -15,19 +15,19 @@ title: 巧用过渡
|
||||
|
||||
## 在视图变化时保持上下文
|
||||
|
||||
<video class="transition-video-player" alt="滑入与滑出示例" src="https://os.alipayobjects.com/rmsportal/EejaUGsyExkXyXr.mp4" />
|
||||
<video class="transition-video-player" alt="滑入与滑出示例" src="https://os.alipayobjects.com/rmsportal/EejaUGsyExkXyXr.mp4"></video>
|
||||
|
||||
滑入与滑出:可以有效构建虚拟空间。
|
||||
|
||||
<br>
|
||||
|
||||
<video class="transition-video-player" alt="传送带示例" src="https://os.alipayobjects.com/rmsportal/GIutPgZMTyfFfrH.mp4" />
|
||||
<video class="transition-video-player" alt="传送带示例" src="https://os.alipayobjects.com/rmsportal/GIutPgZMTyfFfrH.mp4"></video>
|
||||
|
||||
传送带:可极大地扩展虚拟空间。
|
||||
|
||||
<br>
|
||||
|
||||
<video class="transition-video-player" alt="折叠窗口示例" src="https://os.alipayobjects.com/rmsportal/ERKhqHlcHiCDSQu.mp4" />
|
||||
<video class="transition-video-player" alt="折叠窗口示例" src="https://os.alipayobjects.com/rmsportal/ERKhqHlcHiCDSQu.mp4"></video>
|
||||
|
||||
折叠窗口:在视图切换时,有助于保持上下文,同时也能拓展虚拟空间。
|
||||
|
||||
@ -37,25 +37,25 @@ title: 巧用过渡
|
||||
|
||||
## 解释刚刚发生了什么
|
||||
|
||||
<video class="transition-video-player" alt="对象增加示例" description="新增一条对象时,该行「高亮」告知用户这是新增项;几秒后「高亮」消失,以免过度干扰用户。" src="https://os.alipayobjects.com/rmsportal/FqkQMyFqNqielOw.mp4" />
|
||||
<video class="transition-video-player" alt="对象增加示例" description="新增一条对象时,该行「高亮」告知用户这是新增项;几秒后「高亮」消失,以免过度干扰用户。" src="https://os.alipayobjects.com/rmsportal/FqkQMyFqNqielOw.mp4"></video>
|
||||
|
||||
对象增加:在列表/表格中,新增了一个对象。
|
||||
|
||||
<br>
|
||||
|
||||
<video class="transition-video-player" alt="对象删除示例" src="https://os.alipayobjects.com/rmsportal/pnNkNIMoowmGUQy.mp4" />
|
||||
<video class="transition-video-player" alt="对象删除示例" src="https://os.alipayobjects.com/rmsportal/pnNkNIMoowmGUQy.mp4"></video>
|
||||
|
||||
对象删除:在列表/表格中,删除了一个对象。
|
||||
|
||||
<br>
|
||||
|
||||
<video class="transition-video-player" alt="对象更改示例" description="状态一:用户更改了「详情」中的值;<br>状态二:用户点击「保存」后,详情所在的网格出现「黄底」,表明该对象发生了更改;<br>状态三:底色持续几秒后,恢复正常。" src="https://os.alipayobjects.com/rmsportal/XrUIWmsmOlEnZGc.mp4" />
|
||||
<video class="transition-video-player" alt="对象更改示例" description="状态一:用户更改了「详情」中的值;<br>状态二:用户点击「保存」后,详情所在的网格出现「黄底」,表明该对象发生了更改;<br>状态三:底色持续几秒后,恢复正常。" src="https://os.alipayobjects.com/rmsportal/XrUIWmsmOlEnZGc.mp4"></video>
|
||||
|
||||
对象更改:在列表/表格中,更改了一个对象。
|
||||
|
||||
<br>
|
||||
|
||||
<video class="transition-video-player" alt="对象呼出示例" src="https://os.alipayobjects.com/rmsportal/gSNilqbiXOufDXF.mp4" />
|
||||
<video class="transition-video-player" alt="对象呼出示例" src="https://os.alipayobjects.com/rmsportal/gSNilqbiXOufDXF.mp4"></video>
|
||||
|
||||
对象呼出:点击页面中元素,呼出一个新对象。
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "antd",
|
||||
"version": "5.6.3",
|
||||
"version": "5.6.4",
|
||||
"packageManager": "^npm@9.0.0",
|
||||
"description": "An enterprise-class UI design language and React components implementation",
|
||||
"title": "Ant Design",
|
||||
@ -128,7 +128,7 @@
|
||||
"rc-dialog": "~9.1.0",
|
||||
"rc-drawer": "~6.2.0",
|
||||
"rc-dropdown": "~4.1.0",
|
||||
"rc-field-form": "~1.33.0",
|
||||
"rc-field-form": "~1.34.0",
|
||||
"rc-image": "~6.1.0",
|
||||
"rc-input": "~1.1.0",
|
||||
"rc-input-number": "~8.0.0",
|
||||
@ -299,8 +299,7 @@
|
||||
"typescript": "~5.1.3",
|
||||
"vanilla-jsoneditor": "^0.17.1",
|
||||
"webpack-bundle-analyzer": "^4.1.0",
|
||||
"xhr-mock": "^2.4.1",
|
||||
"file-system-cache": "2.3.0"
|
||||
"xhr-mock": "^2.4.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=16.9.0",
|
||||
|
Loading…
Reference in New Issue
Block a user