chore: auto merge branches (#43498)

chore: merge master into feature
This commit is contained in:
github-actions[bot] 2023-07-12 02:48:16 +00:00 committed by GitHub
commit 493b66b641
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
37 changed files with 1051 additions and 395 deletions

View File

@ -15,6 +15,50 @@ timeline: true
---
## 5.7.0
`2023-07-11`
- 🆕 ConfigProvider now supports `className` and `style` properties for all components. Thanks to [@Yuiai01](https://github.com/Yuiai01), [@li-jia-nan](https://github.com/li-jia-nan), [@MuxinFeng](https://github.com/MuxinFeng) for their contributions.
- 🆕 Badge now supports `classNames` and `styles` properties. [#43245](https://github.com/ant-design/ant-design/pull/43245) [@li-jia-nan](https://github.com/li-jia-nan)
- 🆕 ColorPicker now supports new features such as `showText`, `destroyTooltipOnHide`, `onChangeComplete`, `panelRender` and `size`.
- [#42865](https://github.com/ant-design/ant-design/pull/42865) [@RedJue](https://github.com/RedJue)
- [#42645](https://github.com/ant-design/ant-design/pull/42645) [@linxianxi](https://github.com/linxianxi)
- [#43370](https://github.com/ant-design/ant-design/pull/43370) [@RedJue](https://github.com/RedJue)
- [#43134](https://github.com/ant-design/ant-design/pull/43134) [@RedJue](https://github.com/RedJue)
- [#43116](https://github.com/ant-design/ant-design/pull/43116) [@RedJue](https://github.com/RedJue)
- 🆕 Alert, Drawer, Modal, Notifaction, Tag, Tabs now support hiding the close button by setting `closeIcon` to null or false. [#42828](https://github.com/ant-design/ant-design/discussions/42828) [@kiner-tang](https://github.com/kiner-tang)
- 🆕 Image supports `imageRender`, `toolbarRender` attributes to support custom rendering of preview images and toolbars, also supports new props such as `onTransform`, `minScale`, `maxScale`. Image.PreviewGroup supports `items` attribute to pass in list data, and fixes that the native attributes of the img tag are not passed to preview images The problem. [#43075](https://github.com/ant-design/ant-design/pull/43075) [@linxianxi](https://github.com/linxianxi)
- 🆕 Modify the layout style of the Image preview, the `preview` attribute supports `closeIcon`, Image.PreviewGroup supports the `fallback` attribute, and fixes the problem of loading preview resources in advance. [#43167](https://github.com/ant-design/ant-design/pull/43167) [@linxianxi](https://github.com/linxianxi)
- 🆕 Changed the layout style, Preview now supports `closeIcon`, PreviewGroup now supports `fallback`, and fixed an issue where preview resources would be loaded at the beginning.[#43167](https://github.com/ant-design/ant-design/pull/43167) [@linxianxi](https://github.com/linxianxi)
- 🛠 InputNumber was refactored to use rc-input. (#42762)。[#42762](https://github.com/ant-design/ant-design/pull/42762) [@muxin](https://github.com/muxin)
- 🛠 Resolved Circular dependency issue in vite, rollup, meteor and microbundle. [#42750](https://github.com/ant-design/ant-design/pull/42750). Thanks to [@jrr997](https://github.com/jrr997), [@kiner-tang](https://github.com/kiner-tang) and [@MuxinFeng](https://github.com/MuxinFeng) for their contributions.
- 🐞 Remove default values (empty string) of `className` prop in Anchor, CollapsePanel, and Input.Group. [#43481](https://github.com/ant-design/ant-design/pull/43481) [@thinkasany](https://github.com/thinkasany)
- 🐞 Fix Upload progress bar missing fade motion. [#43471](https://github.com/ant-design/ant-design/pull/43471)
- 🐞 Added warning for deprecated Token `colorItemBgSelected` in Menu.[#43461](https://github.com/ant-design/ant-design/pull/43461) [@MadCcc](https://github.com/MadCcc)
- 🐞 Fixed an issue where some browsers had scroll bars that were not redrawn when style feature support was detected.[#43358](https://github.com/ant-design/ant-design/pull/43358) [@LeeeeeeM](https://github.com/LeeeeeeM)
- 🐞 Fixed an issue where the Tab component of Card would not be displayed at all when tabList is empty.[#43416](https://github.com/ant-design/ant-design/pull/43416) [@linxianxi](https://github.com/linxianxi)
- 🐞 Fixed an issue where the `form.validateMessages`` configuration would be lost when using ConfigProvider nestedly.[#43239](https://github.com/ant-design/ant-design/pull/43239) [@Wxh16144](https://github.com/Wxh16144)
- 🐞 Fixed an issue where the ripple effect of Tag click would sometimes be offset from the Tag element.[#43402](https://github.com/ant-design/ant-design/pull/43402)
- 🐞 Fixed an issue where clicking "now" in DatePicker when switching to the year-month panel would not work.[#43367](https://github.com/ant-design/ant-design/pull/43367) [@Yuiai01](https://github.com/Yuiai01)
- 🐞 Fixed an issue where the height set for the TextArea component would become invalid when the screen size changed.[#43169](https://github.com/ant-design/ant-design/pull/43169) [@MadCcc](https://github.com/MadCcc)
- 💄 In Slider, the `tooltip` should be centered when there is little content. [#43430](https://github.com/ant-design/ant-design/pull/43430) [@Jomorx](https://github.com/Jomorx)
- 💄 Added `colorLink` to the seed token, and `colorLinkHover` and `colorLinkActive` will be calculated from colorLink.[#43183](https://github.com/ant-design/ant-design/pull/43183) [@MadCcc](https://github.com/MadCcc)
- 💄 Adjusted some tokens in Slider to component tokens. [#42428](https://github.com/ant-design/ant-design/pull/42428) [@heiyu4585](https://github.com/heiyu4585) RTL[#42428](https://github.com/ant-design/ant-design/pull/42428) [@heiyu4585](https://github.com/heiyu4585)
- RTL
- 🤖 Progress now supports animations in rtl direction.[#43316](https://github.com/ant-design/ant-design/pull/43316) [@Yuiai01](https://github.com/Yuiai01)
- TypeScript
- 🤖 Added `RawPurePanelProps` interface description for Popover.[#43453](https://github.com/ant-design/ant-design/pull/43453) [@thinkasany](https://github.com/thinkasany)
- 🤖 Replaced `ref` type with `TooltipRef` instead of `unknown` for `Popconfirm`.[#43452](https://github.com/ant-design/ant-design/pull/43452) [@thinkasany](https://github.com/thinkasany)
- 🤖 Replaced `ref` type with `TooltipRef` instead of `unknown` for Popover.[#43450](https://github.com/ant-design/ant-design/pull/43450) [@Negentropy247](https://github.com/Negentropy247)
- 🤖 Improved type declaration of `GroupSizeContext` in ButtonGroup.[#43439](https://github.com/ant-design/ant-design/pull/43439) [@thinkasany](https://github.com/thinkasany)
- 🤖 Improved type declaration of `mode` property in Select.[#43413](https://github.com/ant-design/ant-design/pull/43413) [@thinkasany](https://github.com/thinkasany)
- 🤖 Replaced `ref` type with `CheckboxRef` instead of `unknown` for Checkbox.[#43424](https://github.com/ant-design/ant-design/pull/43424) [@li-jia-nan](https://github.com/li-jia-nan)
- 🤖 Improved internal type implementation for Table/Tag/Notification.
- [#43366](https://github.com/ant-design/ant-design/pull/43366) [@li-jia-nan](https://github.com/li-jia-nan)
- [#43357](https://github.com/ant-design/ant-design/pull/43357) [@thinkasany](https://github.com/thinkasany)
- [#43351](https://github.com/ant-design/ant-design/pull/43351) [@thinkasany](https://github.com/thinkasany)
## 5.6.4
`2023-07-03`

View File

@ -15,6 +15,50 @@ timeline: true
---
## 5.7.0
`2023-07-11`
- 🆕 ConfigProvider 支持所有组件的 `className``style` 属性控制。感谢 [@Yuiai01](https://github.com/Yuiai01)、[@li-jia-nan](https://github.com/li-jia-nan) 和 [@MuxinFeng](https://github.com/MuxinFeng) 的贡献。
- 🆕 Badge 支持 `classNames` 属性和 `styles` 属性。[#43245](https://github.com/ant-design/ant-design/pull/43245) [@li-jia-nan](https://github.com/li-jia-nan)
- 🆕 ColorPicker 支持 `showText`、`destroyTooltipOnHide`、`onChangeComplete`、`panelRender`、`size` 等新特性。
- [#42865](https://github.com/ant-design/ant-design/pull/42865) [@RedJue](https://github.com/RedJue)
- [#42645](https://github.com/ant-design/ant-design/pull/42645) [@linxianxi](https://github.com/linxianxi)
- [#43370](https://github.com/ant-design/ant-design/pull/43370) [@RedJue](https://github.com/RedJue)
- [#43134](https://github.com/ant-design/ant-design/pull/43134) [@RedJue](https://github.com/RedJue)
- [#43116](https://github.com/ant-design/ant-design/pull/43116) [@RedJue](https://github.com/RedJue)
- 🆕 Alert、Drawer、Modal、Notifaction、Tag、Tabs 均已支持通过设置 `closeIcon` 为 null 或 false 隐藏关闭按钮。 [#42828](https://github.com/ant-design/ant-design/discussions/42828) [@kiner-tang](https://github.com/kiner-tang)
- 🆕 Anchor 添加 `replace` 属性。[#43006](https://github.com/ant-design/ant-design/pull/43006) [@ds1371dani](https://github.com/ds1371dani)
- 🆕 Image 支持 `imageRender`、`toolbarRender` 属性以支持预览图和工具栏的自定义渲染,还支持了 `onTransform`、`minScale`、`maxScale` 等新属性Image.PreviewGroup 支持 `items` 属性传入列表数据,并修复了 img 标签的原生属性没有传递给预览图的问题。[#43075](https://github.com/ant-design/ant-design/pull/43075) [@linxianxi](https://github.com/linxianxi)
- 🆕 修改 Image 预览图的布局风格,`preview` 属性支持 `closeIcon`Image.PreviewGroup 支持 `fallback` 属性,修复加载预览资源提前加载的问题。[#43167](https://github.com/ant-design/ant-design/pull/43167) [@linxianxi](https://github.com/linxianxi)
- 🛠 InputNumber 使用 rc-input 进行重构。[#42762](https://github.com/ant-design/ant-design/pull/42762) [@muxin](https://github.com/muxin)
- 🛠 解决 vite、rollup、meteor、microbundle 等构建工具中遇到的循环依赖问题,并增加相关的检测。[#42750](https://github.com/ant-design/ant-design/pull/42750),感谢 [@jrr997](https://github.com/jrr997)、[@kiner-tang](https://github.com/kiner-tang) 和 [@MuxinFeng](https://github.com/MuxinFeng) 的贡献。
- 🐞 移除 Anchor/CollapsePanel/Input.Group 组件中 `className` 属性的默认值(空字符串)。 [#43481](https://github.com/ant-design/ant-design/pull/43481) [@thinkasany](https://github.com/thinkasany)
- 🐞 修复 Upload 上传进度条延迟消失且丢失动画效果的问题。[#43471](https://github.com/ant-design/ant-design/pull/43471)
- 🐞 为 Menu 中组件 Token `colorItemBgSelected` 添加废弃警告。[#43461](https://github.com/ant-design/ant-design/pull/43461) [@MadCcc](https://github.com/MadCcc)
- 🐞 修复样式特性支持检测时部分浏览器因为未重绘导致出现滚动条的问题。[#43358](https://github.com/ant-design/ant-design/pull/43358) [@LeeeeeeM](https://github.com/LeeeeeeM)
- 🐞 修复 Card `tabList` 为空时 Tab 完全不展示的问题。[#43416](https://github.com/ant-design/ant-design/pull/43416) [@linxianxi](https://github.com/linxianxi)
- 🐞 修复 ConfigProvider 嵌套使用时,`form.validateMessages` 配置会丢失的问题。[#43239](https://github.com/ant-design/ant-design/pull/43239) [@Wxh16144](https://github.com/Wxh16144)
- 🐞 修复 Tag 点击的水波纹效果有时候会和 Tag 元素产生偏移的问题。[#43402](https://github.com/ant-design/ant-design/pull/43402)
- 🐞 修复 DatePicker 切换到年月面板时,`此刻` 点击无效的问题。[#43367](https://github.com/ant-design/ant-design/pull/43367) [@Yuiai01](https://github.com/Yuiai01)
- 🐞 修复 TextArea 组件在屏幕大小变化时设置的高度失效的问题。[#43169](https://github.com/ant-design/ant-design/pull/43169) [@MadCcc](https://github.com/MadCcc)
- 💄 Slider 中 `tooltip` 在内容很少时应该居中。[#43430](https://github.com/ant-design/ant-design/pull/43430) [@Jomorx](https://github.com/Jomorx)
- 💄 将 `colorLink` 添加至 seed token 中, `colorLinkHover``colorLinkActive` 将会由 `colorLink` 计算得出。[#43183](https://github.com/ant-design/ant-design/pull/43183) [@MadCcc](https://github.com/MadCcc)
- 💄 调整 Slider 中部分 token 为 component token。[#42428](https://github.com/ant-design/ant-design/pull/42428) [@heiyu4585](https://github.com/heiyu4585)
- RTL
- 🤖 Progress 支持 rtl 方向的动画。[#43316](https://github.com/ant-design/ant-design/pull/43316) [@Yuiai01](https://github.com/Yuiai01)
- TypeScript
- 🤖 Popover 增加 `RawPurePanelProps` 接口描述。[#43453](https://github.com/ant-design/ant-design/pull/43453) [@thinkasany](https://github.com/thinkasany)
- 🤖 Popconfirm 替换 `ref` 类型 `unknown``TooltipRef`。[#43452](https://github.com/ant-design/ant-design/pull/43452) [@thinkasany](https://github.com/thinkasany)
- 🤖 Popover 替换 `ref` 类型 `unknown``TooltipRef`。[#43450](https://github.com/ant-design/ant-design/pull/43450) [@Negentropy247](https://github.com/Negentropy247)
- 🤖 改进 ButtonGroup 中 `GroupSizeContext` 的类型声明。[#43439](https://github.com/ant-design/ant-design/pull/43439) [@thinkasany](https://github.com/thinkasany)
- 🤖 改进 Select 的 `mode` 属性的类型声明。[#43413](https://github.com/ant-design/ant-design/pull/43413) [@thinkasany](https://github.com/thinkasany)
- 🤖 Checkbox 替换 `ref` 类型 `unknown``CheckboxRef`。[#43424](https://github.com/ant-design/ant-design/pull/43424) [@li-jia-nan](https://github.com/li-jia-nan)
- 🤖 改进 Table/Tag/Notification 内部类型实现。
- [#43366](https://github.com/ant-design/ant-design/pull/43366) [@li-jia-nan](https://github.com/li-jia-nan)
- [#43357](https://github.com/ant-design/ant-design/pull/43357) [@thinkasany](https://github.com/thinkasany)
- [#43351](https://github.com/ant-design/ant-design/pull/43351) [@thinkasany](https://github.com/thinkasany)
## 5.6.4
`2023-07-03`

View File

@ -96,25 +96,27 @@ const CloseIcon: React.FC<CloseIconProps> = (props) => {
) : null;
};
const Alert: React.FC<AlertProps> = ({
description,
prefixCls: customizePrefixCls,
message,
banner,
className,
rootClassName,
style,
onMouseEnter,
onMouseLeave,
onClick,
afterClose,
showIcon,
closable,
closeText,
closeIcon,
action,
...props
}) => {
const Alert: React.FC<AlertProps> = (props) => {
const {
description,
prefixCls: customizePrefixCls,
message,
banner,
className,
rootClassName,
style,
onMouseEnter,
onMouseLeave,
onClick,
afterClose,
showIcon,
closable,
closeText,
closeIcon,
action,
...otherProps
} = props;
const [closed, setClosed] = React.useState(false);
if (process.env.NODE_ENV !== 'production') {
warning(!closeText, 'Alert', '`closeText` is deprecated. Please use `closeIcon` instead.');
@ -129,14 +131,13 @@ const Alert: React.FC<AlertProps> = ({
props.onClose?.(e);
};
const getType = () => {
const { type } = props;
if (type !== undefined) {
return type;
const type = React.useMemo<AlertProps['type']>(() => {
if (props.type !== undefined) {
return props.type;
}
// banner mode defaults to 'warning'
return banner ? 'warning' : 'info';
};
}, [props.type, banner]);
// closeable when closeText or closeIcon is assigned
const isClosable = React.useMemo(() => {
@ -150,8 +151,6 @@ const Alert: React.FC<AlertProps> = ({
return closeIcon !== false && closeIcon !== null && closeIcon !== undefined;
}, [closeText, closeIcon, closable]);
const type = getType();
// banner mode defaults to Icon
const isShowIcon = banner && showIcon === undefined ? true : showIcon;
@ -170,10 +169,7 @@ const Alert: React.FC<AlertProps> = ({
hashId,
);
const dataOrAriaProps = pickAttrs(props, {
aria: true,
data: true,
});
const restProps = pickAttrs(otherProps, { aria: true, data: true });
return wrapSSR(
<CSSMotion
@ -181,9 +177,7 @@ const Alert: React.FC<AlertProps> = ({
motionName={`${prefixCls}-motion`}
motionAppear={false}
motionEnter={false}
onLeaveStart={(node) => ({
maxHeight: node.offsetHeight,
})}
onLeaveStart={(node) => ({ maxHeight: node.offsetHeight })}
onLeaveEnd={afterClose}
>
{({ className: motionClassName, style: motionStyle }) => (
@ -196,7 +190,7 @@ const Alert: React.FC<AlertProps> = ({
onMouseLeave={onMouseLeave}
onClick={onClick}
role="alert"
{...dataOrAriaProps}
{...restProps}
>
{isShowIcon ? (
<IconNode

View File

@ -114,7 +114,7 @@ const AnchorContent: React.FC<InternalAnchorProps> = (props) => {
const {
rootClassName,
anchorPrefixCls: prefixCls,
className = '',
className,
style,
offsetTop,
affix = true,

View File

@ -29,98 +29,94 @@ export interface CarouselRef {
innerSlider: any;
}
const Carousel = React.forwardRef<CarouselRef, CarouselProps>(
(
{
dots = true,
arrows = false,
draggable = false,
waitForAnimate = false,
dotPosition = 'bottom',
vertical = dotPosition === 'left' || dotPosition === 'right',
rootClassName,
className: customClassName,
style,
...props
},
const Carousel = React.forwardRef<CarouselRef, CarouselProps>((props, ref) => {
const {
dots = true,
arrows = false,
draggable = false,
waitForAnimate = false,
dotPosition = 'bottom',
vertical = dotPosition === 'left' || dotPosition === 'right',
rootClassName,
className: customClassName,
style,
...otherProps
} = props;
const { getPrefixCls, direction, carousel } = React.useContext(ConfigContext);
const slickRef = React.useRef<any>();
const goTo = (slide: number, dontAnimate = false) => {
slickRef.current.slickGoTo(slide, dontAnimate);
};
React.useImperativeHandle(
ref,
) => {
const { getPrefixCls, direction, carousel } = React.useContext(ConfigContext);
const slickRef = React.useRef<any>();
() => ({
goTo,
autoPlay: slickRef.current.innerSlider.autoPlay,
innerSlider: slickRef.current.innerSlider,
prev: slickRef.current.slickPrev,
next: slickRef.current.slickNext,
}),
[slickRef.current],
);
const goTo = (slide: number, dontAnimate = false) => {
slickRef.current.slickGoTo(slide, dontAnimate);
};
const prevCount = React.useRef(React.Children.count(props.children));
React.useImperativeHandle(
ref,
() => ({
goTo,
autoPlay: slickRef.current.innerSlider.autoPlay,
innerSlider: slickRef.current.innerSlider,
prev: slickRef.current.slickPrev,
next: slickRef.current.slickNext,
}),
[slickRef.current],
);
const prevCount = React.useRef(React.Children.count(props.children));
React.useEffect(() => {
if (prevCount.current !== React.Children.count(props.children)) {
goTo(props.initialSlide || 0, false);
prevCount.current = React.Children.count(props.children);
}
}, [props.children]);
const newProps = {
vertical,
className: classNames(customClassName, carousel?.className),
style: { ...carousel?.style, ...style },
...props,
};
if (newProps.effect === 'fade') {
newProps.fade = true;
React.useEffect(() => {
if (prevCount.current !== React.Children.count(props.children)) {
goTo(props.initialSlide || 0, false);
prevCount.current = React.Children.count(props.children);
}
}, [props.children]);
const prefixCls = getPrefixCls('carousel', newProps.prefixCls);
const dotsClass = 'slick-dots';
const newProps = {
vertical,
className: classNames(customClassName, carousel?.className),
style: { ...carousel?.style, ...style },
...otherProps,
};
const enableDots = !!dots;
const dsClass = classNames(
dotsClass,
`${dotsClass}-${dotPosition}`,
typeof dots === 'boolean' ? false : dots?.className,
);
if (newProps.effect === 'fade') {
newProps.fade = true;
}
const [wrapSSR, hashId] = useStyle(prefixCls);
const prefixCls = getPrefixCls('carousel', newProps.prefixCls);
const dotsClass = 'slick-dots';
const className = classNames(
prefixCls,
{
[`${prefixCls}-rtl`]: direction === 'rtl',
[`${prefixCls}-vertical`]: newProps.vertical,
},
hashId,
rootClassName,
);
const enableDots = !!dots;
const dsClass = classNames(
dotsClass,
`${dotsClass}-${dotPosition}`,
typeof dots === 'boolean' ? false : dots?.className,
);
return wrapSSR(
<div className={className}>
<SlickCarousel
ref={slickRef}
{...newProps}
dots={enableDots}
dotsClass={dsClass}
arrows={arrows}
draggable={draggable}
waitForAnimate={waitForAnimate}
/>
</div>,
);
},
);
const [wrapSSR, hashId] = useStyle(prefixCls);
const className = classNames(
prefixCls,
{
[`${prefixCls}-rtl`]: direction === 'rtl',
[`${prefixCls}-vertical`]: newProps.vertical,
},
hashId,
rootClassName,
);
return wrapSSR(
<div className={className}>
<SlickCarousel
ref={slickRef}
{...newProps}
dots={enableDots}
dotsClass={dsClass}
arrows={arrows}
draggable={draggable}
waitForAnimate={waitForAnimate}
/>
</div>,
);
});
if (process.env.NODE_ENV !== 'production') {
Carousel.displayName = 'Carousel';

View File

@ -51,7 +51,10 @@ export interface CheckboxProps extends AbstractCheckboxProps<CheckboxChangeEvent
}
const InternalCheckbox: React.ForwardRefRenderFunction<CheckboxRef, CheckboxProps> = (
{
props,
ref,
) => {
const {
prefixCls: customizePrefixCls,
className,
rootClassName,
@ -63,9 +66,7 @@ const InternalCheckbox: React.ForwardRefRenderFunction<CheckboxRef, CheckboxProp
skipGroup = false,
disabled,
...restProps
},
ref,
) => {
} = props;
const { getPrefixCls, direction, checkbox } = React.useContext(ConfigContext);
const checkboxGroup = React.useContext(GroupContext);
const { isFormItemInput } = React.useContext(FormItemInputContext);

View File

@ -36,8 +36,11 @@ export interface CheckboxGroupProps extends AbstractCheckboxGroupProps {
children?: React.ReactNode;
}
const InternalCheckboxGroup: React.ForwardRefRenderFunction<HTMLDivElement, CheckboxGroupProps> = (
{
const InternalGroup: React.ForwardRefRenderFunction<HTMLDivElement, CheckboxGroupProps> = (
props,
ref,
) => {
const {
defaultValue,
children,
options = [],
@ -47,9 +50,7 @@ const InternalCheckboxGroup: React.ForwardRefRenderFunction<HTMLDivElement, Chec
style,
onChange,
...restProps
},
ref,
) => {
} = props;
const { getPrefixCls, direction } = React.useContext(ConfigContext);
const [value, setValue] = React.useState<CheckboxValueType[]>(
@ -63,16 +64,16 @@ const InternalCheckboxGroup: React.ForwardRefRenderFunction<HTMLDivElement, Chec
}
}, [restProps.value]);
const getOptions = () =>
options.map((option) => {
if (typeof option === 'string' || typeof option === 'number') {
return {
label: option,
value: option,
};
}
return option;
});
const memoOptions = React.useMemo(
() =>
options.map<CheckboxOptionType>((option) => {
if (typeof option === 'string' || typeof option === 'number') {
return { label: option, value: option };
}
return option;
}),
[options],
);
const cancelValue = (val: string) => {
setRegisteredValues((prevValues) => prevValues.filter((v) => v !== val));
@ -93,13 +94,12 @@ const InternalCheckboxGroup: React.ForwardRefRenderFunction<HTMLDivElement, Chec
if (!('value' in restProps)) {
setValue(newValue);
}
const opts = getOptions();
onChange?.(
newValue
.filter((val) => registeredValues.includes(val))
.sort((a, b) => {
const indexA = opts.findIndex((opt) => opt.value === a);
const indexB = opts.findIndex((opt) => opt.value === b);
const indexA = memoOptions.findIndex((opt) => opt.value === a);
const indexB = memoOptions.findIndex((opt) => opt.value === b);
return indexA - indexB;
}),
);
@ -112,23 +112,23 @@ const InternalCheckboxGroup: React.ForwardRefRenderFunction<HTMLDivElement, Chec
const domProps = omit(restProps, ['value', 'disabled']);
if (options && options.length > 0) {
children = getOptions().map((option) => (
<Checkbox
prefixCls={prefixCls}
key={option.value.toString()}
disabled={'disabled' in option ? option.disabled : restProps.disabled}
value={option.value}
checked={value.includes(option.value)}
onChange={option.onChange}
className={`${groupPrefixCls}-item`}
style={option.style}
title={option.title}
>
{option.label}
</Checkbox>
));
}
const childrenNode = options.length
? memoOptions.map<React.ReactNode>((option) => (
<Checkbox
prefixCls={prefixCls}
key={option.value.toString()}
disabled={'disabled' in option ? option.disabled : restProps.disabled}
value={option.value}
checked={value.includes(option.value)}
onChange={option.onChange}
className={`${groupPrefixCls}-item`}
style={option.style}
title={option.title}
>
{option.label}
</Checkbox>
))
: children;
// eslint-disable-next-line react/jsx-no-constructed-context-values
const context = {
@ -151,7 +151,7 @@ const InternalCheckboxGroup: React.ForwardRefRenderFunction<HTMLDivElement, Chec
);
return wrapSSR(
<div className={classString} style={style} {...domProps} ref={ref}>
<GroupContext.Provider value={context}>{children}</GroupContext.Provider>
<GroupContext.Provider value={context}>{childrenNode}</GroupContext.Provider>
</div>,
);
};
@ -159,6 +159,6 @@ const InternalCheckboxGroup: React.ForwardRefRenderFunction<HTMLDivElement, Chec
export type { CheckboxGroupContext } from './GroupContext';
export { GroupContext };
const CheckboxGroup = React.forwardRef<HTMLDivElement, CheckboxGroupProps>(InternalCheckboxGroup);
const CheckboxGroup = React.forwardRef<HTMLDivElement, CheckboxGroupProps>(InternalGroup);
export default React.memo(CheckboxGroup);

View File

@ -30,7 +30,7 @@ const CollapsePanel = React.forwardRef<HTMLDivElement, CollapsePanelProps>((prop
);
const { getPrefixCls } = React.useContext(ConfigContext);
const { prefixCls: customizePrefixCls, className = '', showArrow = true } = props;
const { prefixCls: customizePrefixCls, className, showArrow = true } = props;
const prefixCls = getPrefixCls('collapse', customizePrefixCls);
const collapsePanelClassName = classNames(
{

View File

@ -7,10 +7,12 @@ import useMergedState from 'rc-util/lib/hooks/useMergedState';
import type { CSSProperties, FC } from 'react';
import React, { useContext, useRef, useState } from 'react';
import genPurePanel from '../_util/PurePanel';
import { getStatusClassNames } from '../_util/statusUtils';
import type { SizeType } from '../config-provider/SizeContext';
import type { ConfigConsumerProps } from '../config-provider/context';
import { ConfigContext } from '../config-provider/context';
import useSize from '../config-provider/hooks/useSize';
import { FormItemInputContext, NoFormStyle } from '../form/context';
import type { PopoverProps } from '../popover';
import Popover from '../popover';
import theme from '../theme';
@ -21,6 +23,7 @@ import useColorState from './hooks/useColorState';
import type {
ColorFormat,
ColorPickerBaseProps,
ColorValueType,
PresetsItem,
TriggerPlacement,
TriggerType,
@ -32,8 +35,8 @@ export type ColorPickerProps = Omit<
RcColorPickerProps,
'onChange' | 'value' | 'defaultValue' | 'panelRender' | 'onChangeComplete'
> & {
value?: Color | string;
defaultValue?: Color | string;
value?: ColorValueType;
defaultValue?: ColorValueType;
children?: React.ReactNode;
open?: boolean;
disabled?: boolean;
@ -114,12 +117,16 @@ const ColorPicker: CompoundedComponent = (props) => {
const prefixCls = getPrefixCls('color-picker', customizePrefixCls);
// ===================== Form Status =====================
const { status: contextStatus } = React.useContext(FormItemInputContext);
// ===================== Style =====================
const mergedSize = useSize(customizeSize);
const [wrapSSR, hashId] = useStyle(prefixCls);
const rtlCls = { [`${prefixCls}-rtl`]: direction };
const mergeRootCls = classNames(rootClassName, rtlCls);
const mergeCls = classNames(
getStatusClassNames(prefixCls, contextStatus),
{
[`${prefixCls}-sm`]: mergedSize === 'small',
[`${prefixCls}-lg`]: mergedSize === 'large',
@ -135,7 +142,8 @@ const ColorPicker: CompoundedComponent = (props) => {
const handleChange = (data: Color, type?: HsbaColorType, pickColor?: boolean) => {
let color: Color = generateColor(data);
if (colorCleared) {
const isNull = value === null || (!value && defaultValue === null);
if (colorCleared || isNull) {
setColorCleared(false);
const hsba = color.toHsb();
// ignore alpha slider
@ -199,7 +207,14 @@ const ColorPicker: CompoundedComponent = (props) => {
}
}}
content={
<ColorPickerPanel {...colorBaseProps} onChange={handleChange} onClear={handleClear} />
<NoFormStyle override status>
<ColorPickerPanel
{...colorBaseProps}
onChange={handleChange}
onChangeComplete={handleChangeComplete}
onClear={handleClear}
/>
</NoFormStyle>
}
overlayClassName={mergePopupCls}
{...popoverProps}

View File

@ -5,6 +5,7 @@ import mountTest from '../../../tests/shared/mountTest';
import rtlTest from '../../../tests/shared/rtlTest';
import { waitFakeTimer } from '../../../tests/utils';
import ConfigProvider from '../../config-provider';
import Form from '../../form';
import theme from '../../theme';
import ColorPicker from '../ColorPicker';
import type { Color } from '../color';
@ -398,7 +399,7 @@ describe('ColorPicker', () => {
expect(componentContainer).toMatchSnapshot();
});
it('Should onChangeComplete work', async () => {
it('Should null work as expect', async () => {
spyElementPrototypes(HTMLElement, {
getBoundingClientRect: () => ({
x: 0,
@ -407,6 +408,51 @@ describe('ColorPicker', () => {
height: 100,
}),
});
const { container } = render(<ColorPicker value={null} open />);
expect(
container.querySelector('.ant-color-picker-alpha-input input')?.getAttribute('value'),
).toEqual('0%');
expect(
container.querySelector('.ant-color-picker-hex-input input')?.getAttribute('value'),
).toEqual('000000');
doMouseMove(container, 0, 999);
expect(
container.querySelector('.ant-color-picker-alpha-input input')?.getAttribute('value'),
).toEqual('100%');
});
it('should support valid in form', async () => {
const Demo = () => {
const [form] = Form.useForm();
const submit = () => {
form.validateFields();
};
return (
<Form form={form} initialValues={{ 'color-picker': null }}>
<Form.Item
name="color-picker"
label="ColorPicker"
rules={[{ required: true, message: 'color is required!' }]}
>
<ColorPicker />
</Form.Item>
<button type="button" onClick={submit}>
submit
</button>
</Form>
);
};
const { container } = render(<Demo />);
expect(container.querySelector('.ant-color-picker-status-error')).toBeFalsy();
fireEvent.click(container.querySelector('button')!);
await waitFakeTimer();
expect(container.querySelector('.ant-color-picker-status-error')).toBeTruthy();
expect(container.querySelector('.ant-form-item-explain-error')?.innerHTML).toEqual(
'color is required!',
);
});
it('Should onChangeComplete work', async () => {
const handleChangeComplete = jest.fn();
const { container } = render(<ColorPicker open onChangeComplete={handleChangeComplete} />);
doMouseMove(container, 0, 999);

View File

@ -19,6 +19,9 @@ export class ColorFactory {
constructor(color: ColorGenInput<Color>) {
this.metaColor = new RcColor(color as ColorGenInput);
if (!color) {
this.metaColor.setAlpha(0);
}
}
toHsb() {

View File

@ -12,11 +12,9 @@ export interface PanelPresetsProps extends Pick<ColorPickerBaseProps, 'prefixCls
const PanelPresets: FC = () => {
const { prefixCls, value, presets, onChange } = useContext(PanelPresetsContext);
return (
Array.isArray(presets) && (
<ColorPresets value={value} presets={presets} prefixCls={prefixCls} onChange={onChange} />
)
);
return Array.isArray(presets) ? (
<ColorPresets value={value} presets={presets} prefixCls={prefixCls} onChange={onChange} />
) : null;
};
export default PanelPresets;

View File

@ -1,18 +1,19 @@
import { useEffect, useState } from 'react';
import type { Color } from '../color';
import type { ColorValueType } from '../interface';
import { generateColor } from '../util';
function hasValue(value?: Color | string) {
function hasValue(value?: ColorValueType) {
return value !== undefined;
}
const useColorState = (
defaultStateValue: Color | string,
option: { defaultValue?: Color | string; value?: Color | string },
defaultStateValue: ColorValueType,
option: { defaultValue?: ColorValueType; value?: ColorValueType },
): readonly [Color, React.Dispatch<React.SetStateAction<Color>>] => {
const { defaultValue, value } = option;
const [colorValue, setColorValue] = useState<Color>(() => {
let mergeState: string | Color | undefined;
let mergeState: ColorValueType | undefined;
if (hasValue(value)) {
mergeState = value;
} else if (hasValue(defaultValue)) {

View File

@ -33,3 +33,5 @@ export interface ColorPickerBaseProps {
onFormatChange?: ColorPickerProps['onFormatChange'];
onChangeComplete?: ColorPickerProps['onChangeComplete'];
}
export type ColorValueType = Color | string | null;

View File

@ -77,6 +77,45 @@ const genClearStyle = (
};
};
const genStatusStyle = (token: ColorPickerToken): CSSObject => {
const {
componentCls,
colorError,
colorWarning,
colorErrorBorderHover,
colorWarningBorderHover,
colorErrorOutline,
colorWarningOutline,
} = token;
return {
[`&${componentCls}-status-error`]: {
borderColor: colorError,
'&:hover': {
borderColor: colorErrorBorderHover,
},
[`&${componentCls}-trigger-active`]: {
...genActiveStyle(
mergeToken<ColorPickerToken>(token, {
controlOutline: colorErrorOutline,
}),
),
},
},
[`&${componentCls}-status-warning`]: {
borderColor: colorWarning,
'&:hover': {
borderColor: colorWarningBorderHover,
},
[`&${componentCls}-trigger-active`]: {
...genActiveStyle(
mergeToken<ColorPickerToken>(token, {
controlOutline: colorWarningOutline,
}),
),
},
},
};
};
const genSizeStyle = (token: ColorPickerToken): CSSObject => {
const {
componentCls,
@ -202,6 +241,7 @@ const genColorPickerStyle: GenerateStyle<ColorPickerToken> = (token) => {
},
...genClearStyle(token, controlHeightSM),
...genColorBlockStyle(token, controlHeightSM),
...genStatusStyle(token),
...genSizeStyle(token),
},
...genRtlStyle(token),

View File

@ -156,7 +156,7 @@ export default function generatePicker<DateType>(generateConfig: GenerateConfig<
[`${prefixCls}-borderless`]: !bordered,
},
getStatusClassNames(
prefixCls as string,
prefixCls,
getMergedStatus(contextStatus, customStatus),
hasFeedback,
),

View File

@ -318,7 +318,7 @@ function postPureProps(props: DropdownProps) {
const PurePanel = genPurePanel(Dropdown, 'dropdown', (prefixCls) => prefixCls, postPureProps);
/* istanbul ignore next */
const WrapPurePanel = (props: DropdownProps) => (
const WrapPurePanel: React.FC<DropdownProps> = (props) => (
<PurePanel {...props}>
<span />
</PurePanel>

View File

@ -20842,6 +20842,414 @@ exports[`renders components/form/demo/validate-other.tsx extend context correctl
</div>
</div>
</div>
<div
class="ant-form-item"
>
<div
class="ant-row ant-form-item-row"
>
<div
class="ant-col ant-col-6 ant-form-item-label"
>
<label
class="ant-form-item-required"
for="validate_other_color-picker"
title="ColorPicker"
>
ColorPicker
</label>
</div>
<div
class="ant-col ant-col-14 ant-form-item-control"
>
<div
class="ant-form-item-control-input"
>
<div
class="ant-form-item-control-input-content"
>
<div
class="ant-color-picker-trigger"
>
<div
class="ant-color-picker-color-block"
>
<div
class="ant-color-picker-color-block-inner"
style="background: rgba(0, 0, 0, 0);"
/>
</div>
</div>
<div
class="ant-popover ant-zoom-big-appear ant-zoom-big-appear-prepare ant-zoom-big ant-color-picker ant-popover-placement-bottomLeft"
style="--arrow-x: 0px; --arrow-y: 0px; left: -1000vw; top: -1000vh; box-sizing: border-box;"
>
<div
class="ant-popover-arrow"
style="position: absolute;"
/>
<div
class="ant-popover-content"
>
<div
class="ant-popover-inner"
role="tooltip"
>
<div
class="ant-popover-inner-content"
>
<div
class="ant-color-picker-inner-content"
>
<div
class="ant-color-picker-panel"
>
<div
class="ant-color-picker-select"
>
<div
class="ant-color-picker-palette"
style="position: relative;"
>
<div
style="position: absolute; left: 0px; top: 0px; z-index: 1;"
>
<div
class="ant-color-picker-handler"
style="background-color: rgba(0, 0, 0, 0);"
/>
</div>
<div
class="ant-color-picker-saturation"
style="background-color: rgb(255, 0, 0);"
/>
</div>
</div>
<div
class="ant-color-picker-slider-container"
>
<div
class="ant-color-picker-slider-group"
>
<div
class="ant-color-picker-slider ant-color-picker-slider-hue"
>
<div
class="ant-color-picker-palette"
style="position: relative;"
>
<div
style="position: absolute; left: 0px; top: 0px; z-index: 1;"
>
<div
class="ant-color-picker-handler ant-color-picker-handler-sm"
style="background-color: rgb(255, 0, 0);"
/>
</div>
<div
class="ant-color-picker-gradient"
style="position: absolute; inset: 0;"
/>
</div>
</div>
<div
class="ant-color-picker-slider ant-color-picker-slider-alpha"
>
<div
class="ant-color-picker-palette"
style="position: relative;"
>
<div
style="position: absolute; left: 0px; top: 0px; z-index: 1;"
>
<div
class="ant-color-picker-handler ant-color-picker-handler-sm"
style="background-color: rgba(0, 0, 0, 0);"
/>
</div>
<div
class="ant-color-picker-gradient"
style="position: absolute; inset: 0;"
/>
</div>
</div>
</div>
<div
class="ant-color-picker-color-block"
>
<div
class="ant-color-picker-color-block-inner"
style="background: rgba(0, 0, 0, 0);"
/>
</div>
</div>
</div>
<div
class="ant-color-picker-input-container"
>
<div
class="ant-select ant-select-sm ant-select-borderless ant-color-picker-format-select ant-select-single ant-select-show-arrow"
>
<div
class="ant-select-selector"
>
<span
class="ant-select-selection-search"
>
<input
aria-activedescendant="rc_select_TEST_OR_SSR_list_0"
aria-autocomplete="list"
aria-controls="rc_select_TEST_OR_SSR_list"
aria-expanded="false"
aria-haspopup="listbox"
aria-owns="rc_select_TEST_OR_SSR_list"
autocomplete="off"
class="ant-select-selection-search-input"
id="rc_select_TEST_OR_SSR"
readonly=""
role="combobox"
style="opacity: 0;"
type="search"
unselectable="on"
value=""
/>
</span>
<span
class="ant-select-selection-item"
title="HEX"
>
HEX
</span>
</div>
<div
class="ant-select-dropdown ant-slide-up-appear ant-slide-up-appear-prepare ant-slide-up ant-select-dropdown-placement-bottomRight"
style="--arrow-x: 0px; --arrow-y: 0px; left: -1000vw; top: -1000vh; box-sizing: border-box; width: 68px;"
>
<div>
<div
id="rc_select_TEST_OR_SSR_list"
role="listbox"
style="height: 0px; width: 0px; overflow: hidden;"
>
<div
aria-label="HEX"
aria-selected="true"
id="rc_select_TEST_OR_SSR_list_0"
role="option"
>
hex
</div>
<div
aria-label="HSB"
aria-selected="false"
id="rc_select_TEST_OR_SSR_list_1"
role="option"
>
hsb
</div>
</div>
<div
class="rc-virtual-list"
style="position: relative;"
>
<div
class="rc-virtual-list-holder"
style="max-height: 256px; overflow-y: auto;"
>
<div>
<div
class="rc-virtual-list-holder-inner"
style="display: flex; flex-direction: column;"
>
<div
aria-selected="true"
class="ant-select-item ant-select-item-option ant-select-item-option-active ant-select-item-option-selected"
title="HEX"
>
<div
class="ant-select-item-option-content"
>
HEX
</div>
<span
aria-hidden="true"
class="ant-select-item-option-state"
style="user-select: none;"
unselectable="on"
/>
</div>
<div
aria-selected="false"
class="ant-select-item ant-select-item-option"
title="HSB"
>
<div
class="ant-select-item-option-content"
>
HSB
</div>
<span
aria-hidden="true"
class="ant-select-item-option-state"
style="user-select: none;"
unselectable="on"
/>
</div>
<div
aria-selected="false"
class="ant-select-item ant-select-item-option"
title="RGB"
>
<div
class="ant-select-item-option-content"
>
RGB
</div>
<span
aria-hidden="true"
class="ant-select-item-option-state"
style="user-select: none;"
unselectable="on"
/>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<span
aria-hidden="true"
class="ant-select-arrow"
style="user-select: none;"
unselectable="on"
>
<span
aria-label="down"
class="anticon anticon-down ant-select-suffix"
role="img"
>
<svg
aria-hidden="true"
data-icon="down"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M884 256h-75c-5.1 0-9.9 2.5-12.9 6.6L512 654.2 227.9 262.6c-3-4.1-7.8-6.6-12.9-6.6h-75c-6.5 0-10.3 7.4-6.5 12.7l352.6 486.1c12.8 17.6 39 17.6 51.7 0l352.6-486.1c3.9-5.3.1-12.7-6.4-12.7z"
/>
</svg>
</span>
</span>
</div>
<div
class="ant-color-picker-input"
>
<span
class="ant-input-affix-wrapper ant-color-picker-hex-input ant-input-affix-wrapper-sm"
>
<span
class="ant-input-prefix"
>
#
</span>
<input
class="ant-input ant-input-sm"
type="text"
value="000000"
/>
</span>
</div>
<div
class="ant-input-number ant-input-number-sm ant-color-picker-steppers ant-color-picker-alpha-input"
>
<div
class="ant-input-number-handler-wrap"
>
<span
aria-disabled="false"
aria-label="Increase Value"
class="ant-input-number-handler ant-input-number-handler-up"
role="button"
unselectable="on"
>
<span
aria-label="up"
class="anticon anticon-up ant-input-number-handler-up-inner"
role="img"
>
<svg
aria-hidden="true"
data-icon="up"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M890.5 755.3L537.9 269.2c-12.8-17.6-39-17.6-51.7 0L133.5 755.3A8 8 0 00140 768h75c5.1 0 9.9-2.5 12.9-6.6L512 369.8l284.1 391.6c3 4.1 7.8 6.6 12.9 6.6h75c6.5 0 10.3-7.4 6.5-12.7z"
/>
</svg>
</span>
</span>
<span
aria-disabled="true"
aria-label="Decrease Value"
class="ant-input-number-handler ant-input-number-handler-down ant-input-number-handler-down-disabled"
role="button"
unselectable="on"
>
<span
aria-label="down"
class="anticon anticon-down ant-input-number-handler-down-inner"
role="img"
>
<svg
aria-hidden="true"
data-icon="down"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M884 256h-75c-5.1 0-9.9 2.5-12.9 6.6L512 654.2 227.9 262.6c-3-4.1-7.8-6.6-12.9-6.6h-75c-6.5 0-10.3 7.4-6.5 12.7l352.6 486.1c12.8 17.6 39 17.6 51.7 0l352.6-486.1c3.9-5.3.1-12.7-6.4-12.7z"
/>
</svg>
</span>
</span>
</div>
<div
class="ant-input-number-input-wrap"
>
<input
aria-valuemax="100"
aria-valuemin="0"
aria-valuenow="0"
autocomplete="off"
class="ant-input-number-input"
role="spinbutton"
step="1"
value="0%"
/>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div
class="ant-form-item"
>

View File

@ -9703,6 +9703,49 @@ exports[`renders components/form/demo/validate-other.tsx correctly 1`] = `
</div>
</div>
</div>
<div
class="ant-form-item"
>
<div
class="ant-row ant-form-item-row"
>
<div
class="ant-col ant-col-6 ant-form-item-label"
>
<label
class="ant-form-item-required"
for="validate_other_color-picker"
title="ColorPicker"
>
ColorPicker
</label>
</div>
<div
class="ant-col ant-col-14 ant-form-item-control"
>
<div
class="ant-form-item-control-input"
>
<div
class="ant-form-item-control-input-content"
>
<div
class="ant-color-picker-trigger"
>
<div
class="ant-color-picker-color-block"
>
<div
class="ant-color-picker-color-block-inner"
style="background:rgba(0, 0, 0, 0)"
/>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div
class="ant-form-item"
>

View File

@ -3,6 +3,7 @@ import {
Button,
Checkbox,
Col,
ColorPicker,
Form,
InputNumber,
Radio,
@ -40,7 +41,12 @@ const App: React.FC = () => (
name="validate_other"
{...formItemLayout}
onFinish={onFinish}
initialValues={{ 'input-number': 3, 'checkbox-group': ['A', 'B'], rate: 3.5 }}
initialValues={{
'input-number': 3,
'checkbox-group': ['A', 'B'],
rate: 3.5,
'color-picker': null,
}}
style={{ maxWidth: 600 }}
>
<Form.Item label="Plain Text">
@ -168,7 +174,6 @@ const App: React.FC = () => (
<Button icon={<UploadOutlined />}>Click to upload</Button>
</Upload>
</Form.Item>
<Form.Item label="Dragger">
<Form.Item name="dragger" valuePropName="fileList" getValueFromEvent={normFile} noStyle>
<Upload.Dragger name="files" action="/upload.do">
@ -180,6 +185,13 @@ const App: React.FC = () => (
</Upload.Dragger>
</Form.Item>
</Form.Item>
<Form.Item
name="color-picker"
label="ColorPicker"
rules={[{ required: true, message: 'color is required!' }]}
>
<ColorPicker />
</Form.Item>
<Form.Item wrapperCol={{ span: 12, offset: 6 }}>
<Space>

View File

@ -13,6 +13,7 @@ const App: React.FC = () => (
src="https://mdn.alipayobjects.com/huamei_iwk9zp/afts/file/A*uYT7SZwhJnUAAAAAAAAAAAAADgCCAQ"
/>
),
toolbarRender: () => null,
}}
src="https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png"
/>

View File

@ -1,10 +1,10 @@
## zh-CN
可以自定义工具栏并添加下载图片按钮。
可以自定义工具栏并添加下载原图或翻转旋转后图片按钮。
## en-US
You can customize the toolbar and add a button for downloading the image.
You can customize the toolbar and add a button for downloading the original image or downloading the flipped and rotated image.
```css
.toolbar-wrapper {

View File

@ -12,6 +12,8 @@ import React from 'react';
const src = 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png';
const App: React.FC = () => {
// or you can download flipped and rotated image
// https://codesandbox.io/s/zi-ding-yi-gong-ju-lan-antd-5-7-0-forked-c9jvmp
const onDownload = () => {
fetch(src)
.then((response) => response.blob())

View File

@ -13,14 +13,15 @@ export interface CompositionImage<P> extends React.FC<P> {
PreviewGroup: typeof PreviewGroup;
}
const Image: CompositionImage<ImageProps> = ({
prefixCls: customizePrefixCls,
preview,
className,
rootClassName,
style,
...otherProps
}) => {
const Image: CompositionImage<ImageProps> = (props) => {
const {
prefixCls: customizePrefixCls,
preview,
className,
rootClassName,
style,
...otherProps
} = props;
const {
getPrefixCls,
locale: contextLocale = defaultLocale,

View File

@ -1,10 +1,10 @@
import classNames from 'classnames';
import * as React from 'react';
import { useContext, useMemo } from 'react';
import warning from '../_util/warning';
import { ConfigContext } from '../config-provider';
import type { FormItemStatusContextProps } from '../form/context';
import { FormItemInputContext } from '../form/context';
import warning from '../_util/warning';
import useStyle from './style';
export interface GroupProps {
@ -22,7 +22,7 @@ export interface GroupProps {
const Group: React.FC<GroupProps> = (props) => {
const { getPrefixCls, direction } = useContext(ConfigContext);
const { prefixCls: customizePrefixCls, className = '' } = props;
const { prefixCls: customizePrefixCls, className } = props;
const prefixCls = getPrefixCls('input-group', customizePrefixCls);
const inputPrefixCls = getPrefixCls('input');
const [wrapSSR, hashId] = useStyle(inputPrefixCls);

View File

@ -6,8 +6,8 @@ import omit from 'rc-util/lib/omit';
import * as React from 'react';
import { useContext, useEffect, useRef, useState } from 'react';
import { ConfigContext } from '../config-provider';
import isNumeric from '../_util/isNumeric';
import { ConfigContext } from '../config-provider';
import { LayoutContext } from './layout';
const dimensionMaxMap = {
@ -58,172 +58,161 @@ const generateId = (() => {
};
})();
const Sider = React.forwardRef<HTMLDivElement, SiderProps>(
(
{
prefixCls: customizePrefixCls,
className,
trigger,
children,
defaultCollapsed = false,
theme = 'dark',
style = {},
collapsible = false,
reverseArrow = false,
width = 200,
collapsedWidth = 80,
zeroWidthTriggerStyle,
breakpoint,
onCollapse,
onBreakpoint,
...props
},
ref,
) => {
const { siderHook } = useContext(LayoutContext);
const Sider = React.forwardRef<HTMLDivElement, SiderProps>((props, ref) => {
const {
prefixCls: customizePrefixCls,
className,
trigger,
children,
defaultCollapsed = false,
theme = 'dark',
style = {},
collapsible = false,
reverseArrow = false,
width = 200,
collapsedWidth = 80,
zeroWidthTriggerStyle,
breakpoint,
onCollapse,
onBreakpoint,
...otherProps
} = props;
const { siderHook } = useContext(LayoutContext);
const [collapsed, setCollapsed] = useState(
'collapsed' in props ? props.collapsed : defaultCollapsed,
);
const [below, setBelow] = useState(false);
const [collapsed, setCollapsed] = useState(
'collapsed' in props ? props.collapsed : defaultCollapsed,
);
const [below, setBelow] = useState(false);
useEffect(() => {
if ('collapsed' in props) {
setCollapsed(props.collapsed);
}
}, [props.collapsed]);
useEffect(() => {
if ('collapsed' in props) {
setCollapsed(props.collapsed);
}
}, [props.collapsed]);
const handleSetCollapsed = (value: boolean, type: CollapseType) => {
if (!('collapsed' in props)) {
setCollapsed(value);
}
onCollapse?.(value, type);
};
const handleSetCollapsed = (value: boolean, type: CollapseType) => {
if (!('collapsed' in props)) {
setCollapsed(value);
}
onCollapse?.(value, type);
};
// ========================= Responsive =========================
const responsiveHandlerRef = useRef<(mql: MediaQueryListEvent | MediaQueryList) => void>();
responsiveHandlerRef.current = (mql: MediaQueryListEvent | MediaQueryList) => {
setBelow(mql.matches);
onBreakpoint?.(mql.matches);
// ========================= Responsive =========================
const responsiveHandlerRef = useRef<(mql: MediaQueryListEvent | MediaQueryList) => void>();
responsiveHandlerRef.current = (mql: MediaQueryListEvent | MediaQueryList) => {
setBelow(mql.matches);
onBreakpoint?.(mql.matches);
if (collapsed !== mql.matches) {
handleSetCollapsed(mql.matches, 'responsive');
}
};
if (collapsed !== mql.matches) {
handleSetCollapsed(mql.matches, 'responsive');
}
};
useEffect(() => {
function responsiveHandler(mql: MediaQueryListEvent | MediaQueryList) {
return responsiveHandlerRef.current!(mql);
}
useEffect(() => {
function responsiveHandler(mql: MediaQueryListEvent | MediaQueryList) {
return responsiveHandlerRef.current!(mql);
}
let mql: MediaQueryList;
if (typeof window !== 'undefined') {
const { matchMedia } = window;
if (matchMedia! && breakpoint && breakpoint in dimensionMaxMap) {
mql = matchMedia(`(max-width: ${dimensionMaxMap[breakpoint]})`);
try {
mql.addEventListener('change', responsiveHandler);
} catch (error) {
mql.addListener(responsiveHandler);
}
responsiveHandler(mql);
}
}
return () => {
let mql: MediaQueryList;
if (typeof window !== 'undefined') {
const { matchMedia } = window;
if (matchMedia! && breakpoint && breakpoint in dimensionMaxMap) {
mql = matchMedia(`(max-width: ${dimensionMaxMap[breakpoint]})`);
try {
mql?.removeEventListener('change', responsiveHandler);
mql.addEventListener('change', responsiveHandler);
} catch (error) {
mql?.removeListener(responsiveHandler);
mql.addListener(responsiveHandler);
}
};
}, [breakpoint]); // in order to accept dynamic 'breakpoint' property, we need to add 'breakpoint' into dependency array.
responsiveHandler(mql);
}
}
return () => {
try {
mql?.removeEventListener('change', responsiveHandler);
} catch (error) {
mql?.removeListener(responsiveHandler);
}
};
}, [breakpoint]); // in order to accept dynamic 'breakpoint' property, we need to add 'breakpoint' into dependency array.
useEffect(() => {
const uniqueId = generateId('ant-sider-');
siderHook.addSider(uniqueId);
return () => siderHook.removeSider(uniqueId);
}, []);
useEffect(() => {
const uniqueId = generateId('ant-sider-');
siderHook.addSider(uniqueId);
return () => siderHook.removeSider(uniqueId);
}, []);
const toggle = () => {
handleSetCollapsed(!collapsed, 'clickTrigger');
const toggle = () => {
handleSetCollapsed(!collapsed, 'clickTrigger');
};
const { getPrefixCls } = useContext(ConfigContext);
const renderSider = () => {
const prefixCls = getPrefixCls('layout-sider', customizePrefixCls);
const divProps = omit(otherProps, ['collapsed']);
const rawWidth = collapsed ? collapsedWidth : width;
// use "px" as fallback unit for width
const siderWidth = isNumeric(rawWidth) ? `${rawWidth}px` : String(rawWidth);
// special trigger when collapsedWidth == 0
const zeroWidthTrigger =
parseFloat(String(collapsedWidth || 0)) === 0 ? (
<span
onClick={toggle}
className={classNames(
`${prefixCls}-zero-width-trigger`,
`${prefixCls}-zero-width-trigger-${reverseArrow ? 'right' : 'left'}`,
)}
style={zeroWidthTriggerStyle}
>
{trigger || <BarsOutlined />}
</span>
) : null;
const iconObj = {
expanded: reverseArrow ? <RightOutlined /> : <LeftOutlined />,
collapsed: reverseArrow ? <LeftOutlined /> : <RightOutlined />,
};
const status = collapsed ? 'collapsed' : 'expanded';
const defaultTrigger = iconObj[status];
const triggerDom =
trigger !== null
? zeroWidthTrigger || (
<div className={`${prefixCls}-trigger`} onClick={toggle} style={{ width: siderWidth }}>
{trigger || defaultTrigger}
</div>
)
: null;
const divStyle: React.CSSProperties = {
...style,
flex: `0 0 ${siderWidth}`,
maxWidth: siderWidth, // Fix width transition bug in IE11
minWidth: siderWidth, // https://github.com/ant-design/ant-design/issues/6349
width: siderWidth,
};
const { getPrefixCls } = useContext(ConfigContext);
const renderSider = () => {
const prefixCls = getPrefixCls('layout-sider', customizePrefixCls);
const divProps = omit(props, ['collapsed']);
const rawWidth = collapsed ? collapsedWidth : width;
// use "px" as fallback unit for width
const siderWidth = isNumeric(rawWidth) ? `${rawWidth}px` : String(rawWidth);
// special trigger when collapsedWidth == 0
const zeroWidthTrigger =
parseFloat(String(collapsedWidth || 0)) === 0 ? (
<span
onClick={toggle}
className={classNames(
`${prefixCls}-zero-width-trigger`,
`${prefixCls}-zero-width-trigger-${reverseArrow ? 'right' : 'left'}`,
)}
style={zeroWidthTriggerStyle}
>
{trigger || <BarsOutlined />}
</span>
) : null;
const iconObj = {
expanded: reverseArrow ? <RightOutlined /> : <LeftOutlined />,
collapsed: reverseArrow ? <LeftOutlined /> : <RightOutlined />,
};
const status = collapsed ? 'collapsed' : 'expanded';
const defaultTrigger = iconObj[status];
const triggerDom =
trigger !== null
? zeroWidthTrigger || (
<div
className={`${prefixCls}-trigger`}
onClick={toggle}
style={{ width: siderWidth }}
>
{trigger || defaultTrigger}
</div>
)
: null;
const divStyle = {
...style,
flex: `0 0 ${siderWidth}`,
maxWidth: siderWidth, // Fix width transition bug in IE11
minWidth: siderWidth, // https://github.com/ant-design/ant-design/issues/6349
width: siderWidth,
};
const siderCls = classNames(
prefixCls,
`${prefixCls}-${theme}`,
{
[`${prefixCls}-collapsed`]: !!collapsed,
[`${prefixCls}-has-trigger`]: collapsible && trigger !== null && !zeroWidthTrigger,
[`${prefixCls}-below`]: !!below,
[`${prefixCls}-zero-width`]: parseFloat(siderWidth) === 0,
},
className,
);
return (
<aside className={siderCls} {...divProps} style={divStyle} ref={ref}>
<div className={`${prefixCls}-children`}>{children}</div>
{collapsible || (below && zeroWidthTrigger) ? triggerDom : null}
</aside>
);
};
const contextValue = React.useMemo(
() => ({
siderCollapsed: collapsed,
}),
[collapsed],
const siderCls = classNames(
prefixCls,
`${prefixCls}-${theme}`,
{
[`${prefixCls}-collapsed`]: !!collapsed,
[`${prefixCls}-has-trigger`]: collapsible && trigger !== null && !zeroWidthTrigger,
[`${prefixCls}-below`]: !!below,
[`${prefixCls}-zero-width`]: parseFloat(siderWidth) === 0,
},
className,
);
return (
<aside className={siderCls} {...divProps} style={divStyle} ref={ref}>
<div className={`${prefixCls}-children`}>{children}</div>
{collapsible || (below && zeroWidthTrigger) ? triggerDom : null}
</aside>
);
};
return <SiderContext.Provider value={contextValue}>{renderSider()}</SiderContext.Provider>;
},
);
const contextValue = React.useMemo(() => ({ siderCollapsed: collapsed }), [collapsed]);
return <SiderContext.Provider value={contextValue}>{renderSider()}</SiderContext.Provider>;
});
if (process.env.NODE_ENV !== 'production') {
Sider.displayName = 'Sider';

View File

@ -57,7 +57,7 @@ const Basic = React.forwardRef<HTMLElement, BasicPropsWithTagName>((props, ref)
const { getPrefixCls } = React.useContext(ConfigContext);
const prefixCls = getPrefixCls('layout', customizePrefixCls);
const [wrapSSR, hashId] = useStyle(prefixCls as string);
const [wrapSSR, hashId] = useStyle(prefixCls);
const prefixWithSuffixCls = suffixCls ? `${prefixCls}-${suffixCls}` : prefixCls;
@ -91,7 +91,7 @@ const BasicLayout = React.forwardRef<HTMLElement, BasicPropsWithTagName>((props,
const { getPrefixCls, layout } = React.useContext(ConfigContext);
const prefixCls = getPrefixCls('layout', customizePrefixCls);
const [wrapSSR, hashId] = useStyle(prefixCls as string);
const [wrapSSR, hashId] = useStyle(prefixCls);
const classString = classNames(
prefixCls,
{

View File

@ -64,7 +64,10 @@ type CompoundedComponent = React.ForwardRefExoticComponent<
};
const InternalMentions: React.ForwardRefRenderFunction<MentionsRef, MentionProps> = (
{
props,
ref,
) => {
const {
prefixCls: customizePrefixCls,
className,
rootClassName,
@ -78,9 +81,7 @@ const InternalMentions: React.ForwardRefRenderFunction<MentionsRef, MentionProps
popupClassName,
style,
...restProps
},
ref,
) => {
} = props;
const [focused, setFocused] = React.useState(false);
const innerRef = React.useRef<MentionsRef>(null);
const mergedRef = composeRef(ref, innerRef);

View File

@ -34,19 +34,20 @@ export interface PaginationConfig extends Omit<PaginationProps, 'rootClassName'>
export type { PaginationLocale };
const Pagination: React.FC<PaginationProps> = ({
prefixCls: customizePrefixCls,
selectPrefixCls: customizeSelectPrefixCls,
className,
rootClassName,
style,
size: customizeSize,
locale: customLocale,
selectComponentClass,
responsive,
showSizeChanger,
...restProps
}) => {
const Pagination: React.FC<PaginationProps> = (props) => {
const {
prefixCls: customizePrefixCls,
selectPrefixCls: customizeSelectPrefixCls,
className,
rootClassName,
style,
size: customizeSize,
locale: customLocale,
selectComponentClass,
responsive,
showSizeChanger,
...restProps
} = props;
const { xs } = useBreakpoint(responsive);
const { getPrefixCls, direction, pagination = {} } = React.useContext(ConfigContext);

View File

@ -10,7 +10,6 @@ import { ConfigContext } from '../config-provider';
import { useLocale } from '../locale';
import defaultLocale from '../locale/en_US';
import PopoverPurePanel from '../popover/PurePanel';
import useStyle from './style';
export interface PopconfirmLocale {
@ -100,7 +99,7 @@ export interface PurePanelProps
prefixCls?: string;
}
export default function PurePanel(props: PurePanelProps) {
const PurePanel: React.FC<PurePanelProps> = (props) => {
const { prefixCls: customizePrefixCls, placement, className, style, ...restProps } = props;
const { getPrefixCls } = React.useContext(ConfigContext);
@ -115,4 +114,6 @@ export default function PurePanel(props: PurePanelProps) {
content={<Overlay prefixCls={prefixCls} {...restProps} />}
/>,
);
}
};
export default PurePanel;

View File

@ -34,6 +34,7 @@ demo:
| 参数 | 说明 | 类型 | 默认值 | 版本 |
| --- | --- | --- | --- | --- |
| autoFocus | 自动获取焦点 | boolean | false | |
| allowClear | 支持清除, 单选模式有效 | boolean | false | |
| defaultValue | 设置初始取值。当 `range` 为 false 时,使用 number否则用 \[number, number] | number \| \[number, number] | 0 \| \[0, 0] | |
| disabled | 值为 true 时,滑块为禁用状态 | boolean | false | |
@ -51,6 +52,9 @@ demo:
| vertical | 值为 true 时Slider 为垂直方向 | boolean | false | |
| onAfterChange | 与 `onmouseup` 触发时机一致,把当前值作为参数传入 | (value) => void | - | |
| onChange | 当 Slider 的值发生改变时,会触发 onChange 事件,并把改变后的值作为参数传入 | (value) => void | - | |
| trackStyle | Slider 滑动条轨道样式 (选中范围内) | CSSProperties | - | |
| railStyle | Slider 滑动条轨道样式 (背景) | CSSProperties | - | |
| handleStyle | Slider 滑动滑块样式 | CSSProperties | - | |
### range

View File

@ -2,10 +2,10 @@ import DeleteOutlined from '@ant-design/icons/DeleteOutlined';
import classNames from 'classnames';
import * as React from 'react';
import type { KeyWiseTransferItem } from '.';
import Checkbox from '../checkbox';
import defaultLocale from '../locale/en_US';
import { useLocale } from '../locale';
import TransButton from '../_util/transButton';
import Checkbox from '../checkbox';
import { useLocale } from '../locale';
import defaultLocale from '../locale/en_US';
type ListItemProps<RecordType> = {
renderedText?: string | number;
@ -32,8 +32,7 @@ const ListItem = <RecordType extends KeyWiseTransferItem>(props: ListItemProps<R
showRemove,
} = props;
const className = classNames({
[`${prefixCls}-content-item`]: true,
const className = classNames(`${prefixCls}-content-item`, {
[`${prefixCls}-content-item-disabled`]: disabled || item.disabled,
[`${prefixCls}-content-item-checked`]: checked,
});

View File

@ -3,10 +3,10 @@ import classNames from 'classnames';
import type { AutoSizeType } from 'rc-textarea';
import KeyCode from 'rc-util/lib/KeyCode';
import * as React from 'react';
import type { DirectionType } from '../config-provider';
import TextArea from '../input/TextArea';
import type { TextAreaRef } from '../input/TextArea';
import { cloneElement } from '../_util/reactNode';
import type { DirectionType } from '../config-provider';
import type { TextAreaRef } from '../input/TextArea';
import TextArea from '../input/TextArea';
import useStyle from './style';
interface EditableProps {
@ -25,21 +25,22 @@ interface EditableProps {
component?: string;
}
const Editable: React.FC<EditableProps> = ({
prefixCls,
'aria-label': ariaLabel,
className,
style,
direction,
maxLength,
autoSize = true,
value,
onSave,
onCancel,
onEnd,
component,
enterIcon = <EnterOutlined />,
}) => {
const Editable: React.FC<EditableProps> = (props) => {
const {
prefixCls,
'aria-label': ariaLabel,
className,
style,
direction,
maxLength,
autoSize = true,
value,
onSave,
onCancel,
onEnd,
component,
enterIcon = <EnterOutlined />,
} = props;
const ref = React.useRef<TextAreaRef>(null);
const inComposition = React.useRef(false);

View File

@ -1,6 +1,7 @@
import { Keyframes } from '@ant-design/cssinjs';
import type { UploadToken } from '.';
import type { GenerateStyle } from '../../theme/internal';
import { initFadeMotion } from '../../style/motion';
const uploadAnimateInlineIn = new Keyframes('uploadAnimateInlineIn', {
from: {
@ -44,6 +45,9 @@ const genMotionStyle: GenerateStyle<UploadToken> = (token) => {
},
},
},
{
[`${componentCls}-wrapper`]: initFadeMotion(token),
},
uploadAnimateInlineIn,
uploadAnimateInlineOut,
];

View File

@ -238,7 +238,7 @@ exports[`renders components/watermark/demo/custom.tsx extend context correctly 1
class="ant-color-picker-input-container"
>
<div
class="ant-select ant-select-sm ant-select-borderless ant-select-in-form-item ant-color-picker-format-select ant-select-single ant-select-show-arrow"
class="ant-select ant-select-sm ant-select-borderless ant-color-picker-format-select ant-select-single ant-select-show-arrow"
>
<div
class="ant-select-selector"
@ -414,7 +414,7 @@ exports[`renders components/watermark/demo/custom.tsx extend context correctly 1
</span>
</div>
<div
class="ant-input-number ant-input-number-sm ant-input-number-in-form-item ant-color-picker-steppers ant-color-picker-alpha-input"
class="ant-input-number ant-input-number-sm ant-color-picker-steppers ant-color-picker-alpha-input"
>
<div
class="ant-input-number-handler-wrap"

View File

@ -1,6 +1,6 @@
{
"name": "antd",
"version": "5.6.4",
"version": "5.7.0",
"packageManager": "^npm@9.0.0",
"description": "An enterprise-class UI design language and React components implementation",
"title": "Ant Design",
@ -242,7 +242,7 @@
"inquirer": "^9.1.2",
"isomorphic-fetch": "^3.0.0",
"jest": "^29.4.1",
"jest-axe": "^7.0.0",
"jest-axe": "^8.0.0",
"jest-canvas-mock": "^2.4.0",
"jest-environment-jsdom": "^29.0.1",
"jest-environment-node": "^29.0.0",
@ -325,4 +325,4 @@
"*.{ts,tsx,js,jsx}": "prettier --ignore-unknown --write",
"*.{json,less,md}": "prettier --ignore-unknown --write"
}
}
}

View File

@ -57,11 +57,16 @@ async function checkCommit({ files }: StatusResult) {
async function checkRemote() {
try {
const { remote } = await git.fetch('origin', 'master');
console.log(chalk.blue('⛳ Checking origin master with `git fetch origin master`'));
if (!remote?.includes('ant-design/ant-design')) {
console.log(
chalk.yellow('😓 Your remote origin is not ant-design/ant-design, did you fork it?'),
);
exitProcess();
console.log(chalk.blue('⛳ Checking locally with `git config --get remote.origin.url`'));
const { value } = await git.getConfig('remote.origin.url');
if (!value?.includes('ant-design/ant-design')) {
console.log(
chalk.yellow('🧐 Your remote origin is not ant-design/ant-design, did you fork it?'),
);
exitProcess();
}
}
} catch {
console.log(chalk.red('🚨 Check remote failed. Skip...'));