mirror of
https://github.com/ant-design/ant-design.git
synced 2026-02-17 23:02:28 +08:00
Compare commits
38 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
09dd53915e | ||
|
|
fb8be1e249 | ||
|
|
5f6470d8f3 | ||
|
|
88ae028321 | ||
|
|
6b90477b53 | ||
|
|
bf72f5538a | ||
|
|
7e223c1edc | ||
|
|
221a38db91 | ||
|
|
ae650485a0 | ||
|
|
2005546d22 | ||
|
|
c47bfb0c91 | ||
|
|
77cbf724cf | ||
|
|
d561d73614 | ||
|
|
3507a01798 | ||
|
|
948ba88629 | ||
|
|
dd547aabfd | ||
|
|
a6180008c5 | ||
|
|
852fad9e3b | ||
|
|
008dc3e7f5 | ||
|
|
c53e8ac4c9 | ||
|
|
e11da52bf7 | ||
|
|
453eafe68d | ||
|
|
507fdc44ae | ||
|
|
73f4b9bcd7 | ||
|
|
7274a2ef4a | ||
|
|
19606b375c | ||
|
|
875e190ac7 | ||
|
|
fb839f096c | ||
|
|
e25f03206c | ||
|
|
92ab198198 | ||
|
|
04d7a81ff7 | ||
|
|
902f5617db | ||
|
|
24a86df257 | ||
|
|
fbef76e943 | ||
|
|
9b6db94fdf | ||
|
|
54b6bab2bf | ||
|
|
d5eda4f87e | ||
|
|
d8215589de |
@@ -15,10 +15,41 @@ timeline: true
|
||||
|
||||
---
|
||||
|
||||
## 4.6.2
|
||||
|
||||
`2020-08-31`
|
||||
|
||||
- Upload
|
||||
- 🐞 Fix Upload list status issue when in control mode. [#26481](https://github.com/ant-design/ant-design/pull/26481)
|
||||
- 💄 Fix Upload `picture-card` style unexpected margin in Form.Item. [#26367](https://github.com/ant-design/ant-design/pull/26367)
|
||||
- 💄 Fix Select focus shadow style. [#26465](https://github.com/ant-design/ant-design/pull/26465) [@Rainy](https://github.com/Rainy)
|
||||
- Table
|
||||
- 🐞 Fix Table Pagination not hide with empty data when show on top position. [#26143](https://github.com/ant-design/ant-design/pull/26143) [@zhangchen915](https://github.com/zhangchen915)
|
||||
- 💄 Fix Table expand icon size issue when `@font-size-base` is `12px`. [#26409](https://github.com/ant-design/ant-design/pull/26409)
|
||||
- Space
|
||||
- 🐞 Fix Space not support React.Fragment issue. [#26444](https://github.com/ant-design/ant-design/pull/26444)
|
||||
- 🐞 Fix Space preserve empty dom node when `children` contains empty node. [#26389](https://github.com/ant-design/ant-design/pull/26389)
|
||||
- 🐞 Fix Badge not work when `status` or `color` is empty. [#26375](https://github.com/ant-design/ant-design/pull/26375) [@zhangchen915](https://github.com/zhangchen915)
|
||||
- 💄 Fix Tree draggable transition style. [#26387](https://github.com/ant-design/ant-design/pull/26387)
|
||||
- 🐞 Fix `colorPalette is not defined` when customize theme in some situation. [#26395](https://github.com/ant-design/ant-design/pull/26395)
|
||||
- TypeScript
|
||||
- 🐞 Fix TimePicker.RangePicker typescript need `picker` issue. [#26446](https://github.com/ant-design/ant-design/pull/26446)
|
||||
- 🐞 Upload extended `showUploadList` of Upload with `removeIcon` and `downloadIcon` properties. [#26406](https://github.com/ant-design/ant-design/pull/26406) [@bencallaway](https://github.com/bencallaway)
|
||||
- RTL
|
||||
- 🐞 Fix the rtl style of Col. [#26479](https://github.com/ant-design/ant-design/pull/26479) [#26482](https://github.com/ant-design/ant-design/pull/26482) [@TrueMoein](https://github.com/TrueMoein)
|
||||
|
||||
## 4.6.1
|
||||
|
||||
`2020-08-24`
|
||||
|
||||
- TypeScript
|
||||
- 🐞 Fix Upload type declaration missing `children`. [#26347](https://github.com/ant-design/ant-design/pull/26347)
|
||||
|
||||
## 4.6.0
|
||||
|
||||
`2020-08-23`
|
||||
|
||||
- 💄 Darker `@text-color` for WCAG 2.0 on contrast ratio. [#25630](https://github.com/ant-design/ant-design/pull/25630)
|
||||
- 🔥 New Image component. [#26296](https://github.com/ant-design/ant-design/pull/26296)
|
||||
- 🔥 Table support `sticky` prop to sticky header and scroll bar. [#25939](https://github.com/ant-design/ant-design/pull/25939)
|
||||
- Form
|
||||
@@ -56,10 +87,8 @@ timeline: true
|
||||
- 💄 Optimize the display effect of Descriptions when there is more content. [#25903](https://github.com/ant-design/ant-design/pull/25903)
|
||||
- 🆕 message could be detroied by `message.desctroy(key)`. [#26052](https://github.com/ant-design/ant-design/pull/26052) [@lihqi](https://github.com/lihqi)
|
||||
- 💄 Adjust InputNumber handler bar to be hidden when `readOnly`. [#25998](https://github.com/ant-design/ant-design/pull/25998)
|
||||
- 💄 Lighten `@text-color` color in dark theme. [#25923](https://github.com/ant-design/ant-design/pull/25923)
|
||||
- 💄 Darken `@text-color` color in default theme. [#25630](https://github.com/ant-design/ant-design/pull/25630)
|
||||
- Locale
|
||||
- 🏴 Add Galician Locale support. [#26015](https://github.com/ant-design/ant-design/pull/26015) [@barreeeiroo](https://github.com/barreeeiroo)
|
||||
- 🌐 Add Galician locale support. [#26015](https://github.com/ant-design/ant-design/pull/26015) [@barreeeiroo](https://github.com/barreeeiroo)
|
||||
- 🇱🇹 Add Lithuanian locale support. [#26312](https://github.com/ant-design/ant-design/pull/26312) [@mslotvinskij](https://github.com/mslotvinskij)
|
||||
- 🌐 Use `kmr_IQ` to replace `ku_IQ`. [#26030](https://github.com/ant-design/ant-design/pull/26030)
|
||||
- RTL
|
||||
|
||||
@@ -15,10 +15,41 @@ timeline: true
|
||||
|
||||
---
|
||||
|
||||
## 4.6.2
|
||||
|
||||
`2020-08-31`
|
||||
|
||||
- Upload
|
||||
- 🐞 修复 Upload 在受控模式下同步更新导致的状态错误问题。[#26481](https://github.com/ant-design/ant-design/pull/26481)
|
||||
- 💄 修复 Upload 图片样式在 Form.Item 中有异常 margin 的问题。[#26367](https://github.com/ant-design/ant-design/pull/26367)
|
||||
- 💄 修复 Select focus 状态样式无阴影。[#26465](https://github.com/ant-design/ant-design/pull/26465) [@Rainy](https://github.com/Rainy)
|
||||
- Table
|
||||
- 🐞 修复 Table Pagination 展示于上侧且没有数据时不消失的问题。[#26143](https://github.com/ant-design/ant-design/pull/26143) [@zhangchen915](https://github.com/zhangchen915)
|
||||
- 💄 修复 Table 展开图标在 `@font-size-base` 为 `12px` 时样式错位的问题。[#26409](https://github.com/ant-design/ant-design/pull/26409)
|
||||
- Space
|
||||
- 🐞 修复 Space 不支持 React.Fragment 的问题。[#26444](https://github.com/ant-design/ant-design/pull/26444)
|
||||
- 🐞 修复 Space 在 `children` 中包含空节点时会出现空 dom 的问题。[#26389](https://github.com/ant-design/ant-design/pull/26389)
|
||||
- 🐞 修复 Badge 在 `status` 或 `color` 为空时不展示。[#26375](https://github.com/ant-design/ant-design/pull/26375) [@zhangchen915](https://github.com/zhangchen915)
|
||||
- 💄 修复 Tree `draggable` 切换时样式 transition 变化的问题。[#26387](https://github.com/ant-design/ant-design/pull/26387)
|
||||
- 🐞 修复使用主题有时会报 `colorPalette is not defined` 的问题。[#26395](https://github.com/ant-design/ant-design/pull/26395)
|
||||
- TypeScript
|
||||
- 🐞 修复 TimePicker.RangePicker 定义需要 `picker` 的问题。[#26446](https://github.com/ant-design/ant-design/pull/26446)
|
||||
- 🐞 Upload 组件 `showUploadList` 类型添加 `removeIcon` 和 `downloadIcon` 属性声明。[#26406](https://github.com/ant-design/ant-design/pull/26406) [@bencallaway](https://github.com/bencallaway)
|
||||
- RTL
|
||||
- 🐞 修复 Col RTL 样式。[#26479](https://github.com/ant-design/ant-design/pull/26479) [#26482](https://github.com/ant-design/ant-design/pull/26482) [@TrueMoein](https://github.com/TrueMoein)
|
||||
|
||||
## 4.6.1
|
||||
|
||||
`2020-08-24`
|
||||
|
||||
- TypeScript
|
||||
- 🐞 修复 Upload 类型声明丢失 `children` 的问题。[#26347](https://github.com/ant-design/ant-design/pull/26347)
|
||||
|
||||
## 4.6.0
|
||||
|
||||
`2020-08-23`
|
||||
|
||||
- 💄 加深默认文本 `@text-color` 以满足 WCAG 2.0 对比度的规范。[#25630](https://github.com/ant-design/ant-design/pull/25630)
|
||||
- 🔥 新增图片组件 Image。[#26296](https://github.com/ant-design/ant-design/pull/26296)
|
||||
- 🔥 Table 新增 `sticky` 属性以支持固定表头和滚动条。[#25939](https://github.com/ant-design/ant-design/pull/25939)
|
||||
- Form
|
||||
@@ -26,22 +57,22 @@ timeline: true
|
||||
- 🆕 Form.List 中的 `add` 方法支持第二个 `index` 参数。[#26081](https://github.com/ant-design/ant-design/pull/26081)
|
||||
- 🆕 虚拟滚动支持无闪动滚动,修复 Select/TreeSelect 滚动时列表空白的问题。[#26306](https://github.com/ant-design/ant-design/pull/26306)
|
||||
- Typography
|
||||
- 🆕 新增 Typography.Text success 类型。[#26145](https://github.com/ant-design/ant-design/pull/26145) [@llwslc](https://github.com/llwslc)
|
||||
- 🆕 新增 Typography.Text `success` 类型。[#26145](https://github.com/ant-design/ant-design/pull/26145) [@llwslc](https://github.com/llwslc)
|
||||
- 🆕 Typography `copyable` 支持隐藏提示,`editable` 支持设置图标与提示。[#25953](https://github.com/ant-design/ant-design/pull/25953) [@llwslc](https://github.com/llwslc)
|
||||
- 🆕 新增 Typography.Title 5 级标题。[#25861](https://github.com/ant-design/ant-design/pull/25861)
|
||||
- 🆕 Typography 的 `editable` 配置中增加了 `maxLength` & `autoSize` 支持。[#25373](https://github.com/ant-design/ant-design/pull/25373) [@CornerSkyless](https://github.com/CornerSkyless)
|
||||
- 🆕 Typography 的 `editable` 配置中增加了 `maxLength` 和 `autoSize` 属性。[#25373](https://github.com/ant-design/ant-design/pull/25373) [@CornerSkyless](https://github.com/CornerSkyless)
|
||||
- 🐞 修复 Transfer 搜索空格时 `filterOption` 没有触发的问题。[#26335](https://github.com/ant-design/ant-design/pull/26335)
|
||||
- Progress
|
||||
- 🐞 修复 Progress `steps` 属性对于 `trailColor` 不生效的问题。[#26323](https://github.com/ant-design/ant-design/pull/26323)
|
||||
- 🐞 修复 Progress 当 `type="circle"` 时 `success.percent` 不生效的问题。[#26307](https://github.com/ant-design/ant-design/pull/26307)
|
||||
- 🐞 修复 Textarea 当 `value` 为 `undefined` 时未显示 `defaultValue` 问题。[#26327](https://github.com/ant-design/ant-design/pull/26327)
|
||||
- Cascader
|
||||
- 🐞 修复 Cascader 在按下 ESC 键,然后通过输入进行搜索时 options 不展开的问题。[#26271](https://github.com/ant-design/ant-design/pull/26271) [@flyerH](https://github.com/flyerH)
|
||||
- 🐞 修复 Cascader 在按下 ESC 键,然后通过输入进行搜索时 `options` 不展开的问题。[#26271](https://github.com/ant-design/ant-design/pull/26271) [@flyerH](https://github.com/flyerH)
|
||||
- 💄 优化 Cascader 清除动画效果。[#26186](https://github.com/ant-design/ant-design/pull/26186)
|
||||
- 🗑 移除遗留的 Button.Group 支持,请使用 Space 代替。[#26260](https://github.com/ant-design/ant-design/pull/26260)
|
||||
- Select
|
||||
- 🆕 Select 支持 onClear 属性。[#25907](https://github.com/ant-design/ant-design/pull/25907)
|
||||
- 🐞 修复 Select mode="tags" 搜索显示两条重复条目的问题。[#25907](https://github.com/ant-design/ant-design/pull/25907)
|
||||
- 🆕 Select 支持 `onClear` 属性。[#25907](https://github.com/ant-design/ant-design/pull/25907)
|
||||
- 🐞 修复 Select `mode="tags"` 搜索显示两条重复条目的问题。[#25907](https://github.com/ant-design/ant-design/pull/25907)
|
||||
- 🐞 修复 Select 聚焦时被禁用的样式异常问题。[#26255](https://github.com/ant-design/ant-design/pull/26255)
|
||||
- 🐞 修复多选模式的 Select 在 `showArrow` 时图标重叠问题。[#26168](https://github.com/ant-design/ant-design/pull/26168) [@zhangchen915](https://github.com/zhangchen915)
|
||||
- DatePicker
|
||||
@@ -56,12 +87,10 @@ timeline: true
|
||||
- 💄 优化 Descriptions 在内容比较多时的显示效果。[#25903](https://github.com/ant-design/ant-design/pull/25903)
|
||||
- 🆕 message 支持通过 `message.desctroy(key)` 销毁。[#26052](https://github.com/ant-design/ant-design/pull/26052) [@lihqi](https://github.com/lihqi)
|
||||
- 💄 调整 InputNumber 操作栏在 `readOnly` 时为隐藏。[#25998](https://github.com/ant-design/ant-design/pull/25998)
|
||||
- 💄 加深暗色主题下 `@text-color` 颜色。[#25923](https://github.com/ant-design/ant-design/pull/25923)
|
||||
- 💄 加深默认主题下 `@text-color` 颜色。[#25630](https://github.com/ant-design/ant-design/pull/25630)
|
||||
- 国际化
|
||||
- 🏴 添加加利西亚语支持。[#26015](https://github.com/ant-design/ant-design/pull/26015) [@barreeeiroo](https://github.com/barreeeiroo)
|
||||
- 🌐 添加加利西亚语支持。[#26015](https://github.com/ant-design/ant-design/pull/26015) [@barreeeiroo](https://github.com/barreeeiroo)
|
||||
- 🇱🇹 添加立陶宛语支持。[#26312](https://github.com/ant-design/ant-design/pull/26312) [@mslotvinskij](https://github.com/mslotvinskij)
|
||||
- 🌐 用 `kmr_IQ` 替换 `ku_IQ` 缩写。[#26030](https://github.com/ant-design/ant-design/pull/26030)
|
||||
- 🌐 新增 `kmr_IQ` 语言包用以代替 ku_IQ。[#26030](https://github.com/ant-design/ant-design/pull/26030)
|
||||
- RTL
|
||||
- 💄 优化 Tree RTL 模式下连接线的样式。[#26205](https://github.com/ant-design/ant-design/pull/26205)
|
||||
- 💄 优化 Dropdown RTL 写法避免暗黑模式样式覆盖。[#26206](https://github.com/ant-design/ant-design/pull/26206)
|
||||
|
||||
@@ -13,6 +13,7 @@ class AffixMounter extends React.Component<{
|
||||
offsetBottom?: number;
|
||||
offsetTop?: number;
|
||||
onTestUpdatePosition?(): void;
|
||||
onChange?: () => void;
|
||||
}> {
|
||||
private container: HTMLDivElement;
|
||||
|
||||
@@ -131,13 +132,15 @@ describe('Affix Render', () => {
|
||||
|
||||
it('updatePosition when offsetTop changed', async () => {
|
||||
document.body.innerHTML = '<div id="mounter" />';
|
||||
const onChange = jest.fn();
|
||||
|
||||
affixMounterWrapper = mount(<AffixMounter offsetTop={0} />, {
|
||||
affixMounterWrapper = mount(<AffixMounter offsetTop={0} onChange={onChange} />, {
|
||||
attachTo: document.getElementById('mounter'),
|
||||
});
|
||||
await sleep(20);
|
||||
|
||||
await movePlaceholder(-100);
|
||||
expect(onChange).toHaveBeenLastCalledWith(true);
|
||||
expect(affixMounterWrapper.instance().affix.state.affixStyle?.top).toBe(0);
|
||||
affixMounterWrapper.setProps({
|
||||
offsetTop: 10,
|
||||
|
||||
@@ -30,7 +30,7 @@ exports[`AutoComplete legacy dataSource should accept react element option 1`] =
|
||||
<div>
|
||||
<div
|
||||
class="ant-select-dropdown"
|
||||
style="opacity:0"
|
||||
style="opacity:0;pointer-events:none"
|
||||
>
|
||||
<div>
|
||||
<div
|
||||
|
||||
@@ -141,6 +141,17 @@ describe('Badge', () => {
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('Badge should work when status/color is empty string', () => {
|
||||
const wrapper = mount(
|
||||
<>
|
||||
<Badge color="" text="text" />
|
||||
<Badge status="" text="text" />
|
||||
</>,
|
||||
);
|
||||
|
||||
expect(wrapper.find('.ant-badge')).toHaveLength(2);
|
||||
});
|
||||
|
||||
it('render Badge size when contains children', () => {
|
||||
const wrapper = render(
|
||||
<>
|
||||
|
||||
@@ -62,9 +62,7 @@ const Badge: CompoundedComponent = ({
|
||||
return displayCount as string | number | null;
|
||||
};
|
||||
|
||||
const hasStatus = (): boolean => {
|
||||
return !!status || !!color;
|
||||
};
|
||||
const hasStatus = (): boolean => (status !== null && status !== undefined) || (color !== null && color !== undefined);
|
||||
|
||||
const isZero = () => {
|
||||
const numberedDisplayCount = getNumberedDisplayCount();
|
||||
|
||||
@@ -29,11 +29,13 @@ describe('Calendar', () => {
|
||||
|
||||
it('Calendar should be selectable', () => {
|
||||
const onSelect = jest.fn();
|
||||
const wrapper = mount(<Calendar onSelect={onSelect} />);
|
||||
const onChange = jest.fn();
|
||||
const wrapper = mount(<Calendar onSelect={onSelect} onChange={onChange} />);
|
||||
wrapper.find('.ant-picker-cell').at(0).simulate('click');
|
||||
expect(onSelect).toHaveBeenCalledWith(expect.anything());
|
||||
const value = onSelect.mock.calls[0][0];
|
||||
expect(Moment.isMoment(value)).toBe(true);
|
||||
expect(onChange).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('only Valid range should be selectable', () => {
|
||||
|
||||
@@ -4,7 +4,7 @@ exports[`Cascader can be selected 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="ant-cascader-menus"
|
||||
style="opacity:0"
|
||||
style="opacity:0;pointer-events:none"
|
||||
>
|
||||
<div>
|
||||
<ul
|
||||
@@ -117,7 +117,7 @@ exports[`Cascader can be selected 2`] = `
|
||||
<div>
|
||||
<div
|
||||
class="ant-cascader-menus"
|
||||
style="opacity:0"
|
||||
style="opacity:0;pointer-events:none"
|
||||
>
|
||||
<div>
|
||||
<ul
|
||||
@@ -364,7 +364,7 @@ exports[`Cascader can be selected in RTL direction 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="ant-cascader-menus ant-cascader-menu-rtl"
|
||||
style="opacity:0"
|
||||
style="opacity:0;pointer-events:none"
|
||||
>
|
||||
<div>
|
||||
<ul
|
||||
@@ -477,7 +477,7 @@ exports[`Cascader can be selected in RTL direction 2`] = `
|
||||
<div>
|
||||
<div
|
||||
class="ant-cascader-menus ant-cascader-menu-rtl"
|
||||
style="opacity:0"
|
||||
style="opacity:0;pointer-events:none"
|
||||
>
|
||||
<div>
|
||||
<ul
|
||||
@@ -601,7 +601,7 @@ exports[`Cascader have a notFoundContent that fit trigger input width 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="ant-cascader-menus"
|
||||
style="opacity: 0;"
|
||||
style="opacity: 0; pointer-events: none;"
|
||||
>
|
||||
<div>
|
||||
<ul
|
||||
@@ -679,7 +679,7 @@ exports[`Cascader popup correctly when panel is open 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="ant-cascader-menus"
|
||||
style="opacity:0"
|
||||
style="opacity:0;pointer-events:none"
|
||||
>
|
||||
<div>
|
||||
<ul
|
||||
@@ -757,7 +757,7 @@ exports[`Cascader popup correctly with defaultValue 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="ant-cascader-menus"
|
||||
style="opacity:0"
|
||||
style="opacity:0;pointer-events:none"
|
||||
>
|
||||
<div>
|
||||
<ul
|
||||
@@ -881,7 +881,7 @@ exports[`Cascader popup correctly with defaultValue RTL 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="ant-cascader-menus ant-cascader-menu-rtl"
|
||||
style="opacity:0"
|
||||
style="opacity:0;pointer-events:none"
|
||||
>
|
||||
<div>
|
||||
<ul
|
||||
@@ -1133,6 +1133,7 @@ exports[`Cascader should highlight keyword and filter when search in Cascader 1`
|
||||
style={
|
||||
Object {
|
||||
"opacity": 0,
|
||||
"pointerEvents": "none",
|
||||
"zIndex": undefined,
|
||||
}
|
||||
}
|
||||
@@ -1144,6 +1145,7 @@ exports[`Cascader should highlight keyword and filter when search in Cascader 1`
|
||||
style={
|
||||
Object {
|
||||
"opacity": 0,
|
||||
"pointerEvents": "none",
|
||||
"zIndex": undefined,
|
||||
}
|
||||
}
|
||||
@@ -1442,7 +1444,7 @@ exports[`Cascader should highlight keyword and filter when search in Cascader wi
|
||||
<div>
|
||||
<div
|
||||
class="ant-cascader-menus"
|
||||
style="opacity: 0;"
|
||||
style="opacity: 0; pointer-events: none;"
|
||||
>
|
||||
<div>
|
||||
<ul
|
||||
@@ -1573,6 +1575,7 @@ exports[`Cascader should render not found content 1`] = `
|
||||
style={
|
||||
Object {
|
||||
"opacity": 0,
|
||||
"pointerEvents": "none",
|
||||
"zIndex": undefined,
|
||||
}
|
||||
}
|
||||
@@ -1584,6 +1587,7 @@ exports[`Cascader should render not found content 1`] = `
|
||||
style={
|
||||
Object {
|
||||
"opacity": 0,
|
||||
"pointerEvents": "none",
|
||||
"zIndex": undefined,
|
||||
}
|
||||
}
|
||||
@@ -1894,6 +1898,7 @@ exports[`Cascader should show not found content when options.length is 0 1`] = `
|
||||
style={
|
||||
Object {
|
||||
"opacity": 0,
|
||||
"pointerEvents": "none",
|
||||
"zIndex": undefined,
|
||||
}
|
||||
}
|
||||
@@ -1905,6 +1910,7 @@ exports[`Cascader should show not found content when options.length is 0 1`] = `
|
||||
style={
|
||||
Object {
|
||||
"opacity": 0,
|
||||
"pointerEvents": "none",
|
||||
"zIndex": undefined,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ Checkbox component.
|
||||
| defaultValue | Default selected value | string\[] | \[] | |
|
||||
| disabled | If disable all checkboxes | boolean | false | |
|
||||
| name | The `name` property of all `input[type="checkbox"]` children | string | - | |
|
||||
| options | Specifies options | string\[] | \[] | |
|
||||
| options | Specifies options | string\[] \| Option\[] | \[] | |
|
||||
| value | Used for setting the currently selected value | string\[] | \[] | |
|
||||
| onChange | The callback function that is triggered when the state changes | function(checkedValue) | - | |
|
||||
|
||||
|
||||
@@ -18826,7 +18826,7 @@ exports[`ConfigProvider components Popconfirm configProvider 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="config-popover config-popconfirm"
|
||||
style="opacity:0"
|
||||
style="opacity:0;pointer-events:none"
|
||||
>
|
||||
<div
|
||||
class="config-popover-content"
|
||||
@@ -18910,7 +18910,7 @@ exports[`ConfigProvider components Popconfirm configProvider componentSize large
|
||||
<div>
|
||||
<div
|
||||
class="config-popover config-popconfirm"
|
||||
style="opacity:0"
|
||||
style="opacity:0;pointer-events:none"
|
||||
>
|
||||
<div
|
||||
class="config-popover-content"
|
||||
@@ -18994,7 +18994,7 @@ exports[`ConfigProvider components Popconfirm configProvider componentSize middl
|
||||
<div>
|
||||
<div
|
||||
class="config-popover config-popconfirm"
|
||||
style="opacity:0"
|
||||
style="opacity:0;pointer-events:none"
|
||||
>
|
||||
<div
|
||||
class="config-popover-content"
|
||||
@@ -19078,7 +19078,7 @@ exports[`ConfigProvider components Popconfirm configProvider virtual and dropdow
|
||||
<div>
|
||||
<div
|
||||
class="ant-popover ant-popconfirm"
|
||||
style="opacity:0"
|
||||
style="opacity:0;pointer-events:none"
|
||||
>
|
||||
<div
|
||||
class="ant-popover-content"
|
||||
@@ -19162,7 +19162,7 @@ exports[`ConfigProvider components Popconfirm normal 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="ant-popover ant-popconfirm"
|
||||
style="opacity:0"
|
||||
style="opacity:0;pointer-events:none"
|
||||
>
|
||||
<div
|
||||
class="ant-popover-content"
|
||||
@@ -19246,7 +19246,7 @@ exports[`ConfigProvider components Popconfirm prefixCls 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="prefix-Popconfirm prefix-Popconfirm"
|
||||
style="opacity:0"
|
||||
style="opacity:0;pointer-events:none"
|
||||
>
|
||||
<div
|
||||
class="prefix-Popconfirm-content"
|
||||
@@ -19330,7 +19330,7 @@ exports[`ConfigProvider components Popover configProvider 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="config-popover"
|
||||
style="opacity:0"
|
||||
style="opacity:0;pointer-events:none"
|
||||
>
|
||||
<div
|
||||
class="config-popover-content"
|
||||
@@ -19366,7 +19366,7 @@ exports[`ConfigProvider components Popover configProvider componentSize large 1`
|
||||
<div>
|
||||
<div
|
||||
class="config-popover"
|
||||
style="opacity:0"
|
||||
style="opacity:0;pointer-events:none"
|
||||
>
|
||||
<div
|
||||
class="config-popover-content"
|
||||
@@ -19402,7 +19402,7 @@ exports[`ConfigProvider components Popover configProvider componentSize middle 1
|
||||
<div>
|
||||
<div
|
||||
class="config-popover"
|
||||
style="opacity:0"
|
||||
style="opacity:0;pointer-events:none"
|
||||
>
|
||||
<div
|
||||
class="config-popover-content"
|
||||
@@ -19438,7 +19438,7 @@ exports[`ConfigProvider components Popover configProvider virtual and dropdownMa
|
||||
<div>
|
||||
<div
|
||||
class="ant-popover"
|
||||
style="opacity:0"
|
||||
style="opacity:0;pointer-events:none"
|
||||
>
|
||||
<div
|
||||
class="ant-popover-content"
|
||||
@@ -19474,7 +19474,7 @@ exports[`ConfigProvider components Popover normal 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="ant-popover"
|
||||
style="opacity:0"
|
||||
style="opacity:0;pointer-events:none"
|
||||
>
|
||||
<div
|
||||
class="ant-popover-content"
|
||||
@@ -19510,7 +19510,7 @@ exports[`ConfigProvider components Popover prefixCls 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="prefix-Popover"
|
||||
style="opacity:0"
|
||||
style="opacity:0;pointer-events:none"
|
||||
>
|
||||
<div
|
||||
class="prefix-Popover-content"
|
||||
@@ -21879,7 +21879,7 @@ exports[`ConfigProvider components Select configProvider 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="config-select-dropdown"
|
||||
style="opacity:0"
|
||||
style="opacity:0;pointer-events:none"
|
||||
>
|
||||
<div>
|
||||
<div
|
||||
@@ -22005,7 +22005,7 @@ exports[`ConfigProvider components Select configProvider componentSize large 1`]
|
||||
<div>
|
||||
<div
|
||||
class="config-select-dropdown"
|
||||
style="opacity:0"
|
||||
style="opacity:0;pointer-events:none"
|
||||
>
|
||||
<div>
|
||||
<div
|
||||
@@ -22131,7 +22131,7 @@ exports[`ConfigProvider components Select configProvider componentSize middle 1`
|
||||
<div>
|
||||
<div
|
||||
class="config-select-dropdown"
|
||||
style="opacity:0"
|
||||
style="opacity:0;pointer-events:none"
|
||||
>
|
||||
<div>
|
||||
<div
|
||||
@@ -22257,7 +22257,7 @@ exports[`ConfigProvider components Select configProvider virtual and dropdownMat
|
||||
<div>
|
||||
<div
|
||||
class="ant-select-dropdown"
|
||||
style="opacity:0"
|
||||
style="opacity:0;pointer-events:none"
|
||||
>
|
||||
<div>
|
||||
<div
|
||||
@@ -22383,7 +22383,7 @@ exports[`ConfigProvider components Select normal 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="ant-select-dropdown"
|
||||
style="opacity:0"
|
||||
style="opacity:0;pointer-events:none"
|
||||
>
|
||||
<div>
|
||||
<div
|
||||
@@ -22509,7 +22509,7 @@ exports[`ConfigProvider components Select prefixCls 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="prefix-Select-dropdown"
|
||||
style="opacity:0"
|
||||
style="opacity:0;pointer-events:none"
|
||||
>
|
||||
<div>
|
||||
<div
|
||||
@@ -22797,7 +22797,7 @@ exports[`ConfigProvider components Slider configProvider 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="config-tooltip config-slider-tooltip"
|
||||
style="opacity:0"
|
||||
style="opacity:0;pointer-events:none"
|
||||
>
|
||||
<div
|
||||
class="config-tooltip-content"
|
||||
@@ -22851,7 +22851,7 @@ exports[`ConfigProvider components Slider configProvider componentSize large 1`]
|
||||
<div>
|
||||
<div
|
||||
class="config-tooltip config-slider-tooltip"
|
||||
style="opacity:0"
|
||||
style="opacity:0;pointer-events:none"
|
||||
>
|
||||
<div
|
||||
class="config-tooltip-content"
|
||||
@@ -22905,7 +22905,7 @@ exports[`ConfigProvider components Slider configProvider componentSize middle 1`
|
||||
<div>
|
||||
<div
|
||||
class="config-tooltip config-slider-tooltip"
|
||||
style="opacity:0"
|
||||
style="opacity:0;pointer-events:none"
|
||||
>
|
||||
<div
|
||||
class="config-tooltip-content"
|
||||
@@ -22959,7 +22959,7 @@ exports[`ConfigProvider components Slider configProvider virtual and dropdownMat
|
||||
<div>
|
||||
<div
|
||||
class="ant-tooltip ant-slider-tooltip"
|
||||
style="opacity:0"
|
||||
style="opacity:0;pointer-events:none"
|
||||
>
|
||||
<div
|
||||
class="ant-tooltip-content"
|
||||
@@ -23013,7 +23013,7 @@ exports[`ConfigProvider components Slider normal 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="ant-tooltip ant-slider-tooltip"
|
||||
style="opacity:0"
|
||||
style="opacity:0;pointer-events:none"
|
||||
>
|
||||
<div
|
||||
class="ant-tooltip-content"
|
||||
@@ -23067,7 +23067,7 @@ exports[`ConfigProvider components Slider prefixCls 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="prefix-Slider-tooltip prefix-Slider-tooltip"
|
||||
style="opacity:0"
|
||||
style="opacity:0;pointer-events:none"
|
||||
>
|
||||
<div
|
||||
class="prefix-Slider-tooltip-content"
|
||||
@@ -23822,7 +23822,7 @@ exports[`ConfigProvider components Table configProvider 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="config-dropdown"
|
||||
style="opacity:0"
|
||||
style="opacity:0;pointer-events:none"
|
||||
>
|
||||
<div
|
||||
class="config-table-filter-dropdown"
|
||||
@@ -24096,7 +24096,7 @@ exports[`ConfigProvider components Table configProvider componentSize large 1`]
|
||||
<div>
|
||||
<div
|
||||
class="config-dropdown"
|
||||
style="opacity:0"
|
||||
style="opacity:0;pointer-events:none"
|
||||
>
|
||||
<div
|
||||
class="config-table-filter-dropdown"
|
||||
@@ -24370,7 +24370,7 @@ exports[`ConfigProvider components Table configProvider componentSize middle 1`]
|
||||
<div>
|
||||
<div
|
||||
class="config-dropdown"
|
||||
style="opacity:0"
|
||||
style="opacity:0;pointer-events:none"
|
||||
>
|
||||
<div
|
||||
class="config-table-filter-dropdown"
|
||||
@@ -24644,7 +24644,7 @@ exports[`ConfigProvider components Table configProvider virtual and dropdownMatc
|
||||
<div>
|
||||
<div
|
||||
class="ant-dropdown"
|
||||
style="opacity:0"
|
||||
style="opacity:0;pointer-events:none"
|
||||
>
|
||||
<div
|
||||
class="ant-table-filter-dropdown"
|
||||
@@ -24918,7 +24918,7 @@ exports[`ConfigProvider components Table normal 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="ant-dropdown"
|
||||
style="opacity:0"
|
||||
style="opacity:0;pointer-events:none"
|
||||
>
|
||||
<div
|
||||
class="ant-table-filter-dropdown"
|
||||
@@ -25192,7 +25192,7 @@ exports[`ConfigProvider components Table prefixCls 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="ant-dropdown"
|
||||
style="opacity:0"
|
||||
style="opacity:0;pointer-events:none"
|
||||
>
|
||||
<div
|
||||
class="prefix-Table-filter-dropdown"
|
||||
@@ -25992,7 +25992,7 @@ Array [
|
||||
<div>
|
||||
<div
|
||||
class="config-picker-dropdown"
|
||||
style="opacity:0"
|
||||
style="opacity:0;pointer-events:none"
|
||||
>
|
||||
<div
|
||||
class="config-picker-panel-container"
|
||||
@@ -27404,7 +27404,7 @@ Array [
|
||||
<div>
|
||||
<div
|
||||
class="config-picker-dropdown"
|
||||
style="opacity:0"
|
||||
style="opacity:0;pointer-events:none"
|
||||
>
|
||||
<div
|
||||
class="config-picker-panel-container"
|
||||
@@ -28816,7 +28816,7 @@ Array [
|
||||
<div>
|
||||
<div
|
||||
class="config-picker-dropdown"
|
||||
style="opacity:0"
|
||||
style="opacity:0;pointer-events:none"
|
||||
>
|
||||
<div
|
||||
class="config-picker-panel-container"
|
||||
@@ -30228,7 +30228,7 @@ Array [
|
||||
<div>
|
||||
<div
|
||||
class="ant-picker-dropdown"
|
||||
style="opacity:0"
|
||||
style="opacity:0;pointer-events:none"
|
||||
>
|
||||
<div
|
||||
class="ant-picker-panel-container"
|
||||
@@ -31640,7 +31640,7 @@ Array [
|
||||
<div>
|
||||
<div
|
||||
class="ant-picker-dropdown"
|
||||
style="opacity:0"
|
||||
style="opacity:0;pointer-events:none"
|
||||
>
|
||||
<div
|
||||
class="ant-picker-panel-container"
|
||||
@@ -33052,7 +33052,7 @@ Array [
|
||||
<div>
|
||||
<div
|
||||
class="prefix-TimePicker-dropdown"
|
||||
style="opacity:0"
|
||||
style="opacity:0;pointer-events:none"
|
||||
>
|
||||
<div
|
||||
class="prefix-TimePicker-panel-container"
|
||||
@@ -34558,7 +34558,7 @@ Array [
|
||||
<div>
|
||||
<div
|
||||
class="config-tooltip"
|
||||
style="opacity:0"
|
||||
style="opacity:0;pointer-events:none"
|
||||
>
|
||||
<div
|
||||
class="config-tooltip-content"
|
||||
@@ -34592,7 +34592,7 @@ Array [
|
||||
<div>
|
||||
<div
|
||||
class="config-tooltip"
|
||||
style="opacity:0"
|
||||
style="opacity:0;pointer-events:none"
|
||||
>
|
||||
<div
|
||||
class="config-tooltip-content"
|
||||
@@ -34626,7 +34626,7 @@ Array [
|
||||
<div>
|
||||
<div
|
||||
class="config-tooltip"
|
||||
style="opacity:0"
|
||||
style="opacity:0;pointer-events:none"
|
||||
>
|
||||
<div
|
||||
class="config-tooltip-content"
|
||||
@@ -34660,7 +34660,7 @@ Array [
|
||||
<div>
|
||||
<div
|
||||
class="ant-tooltip"
|
||||
style="opacity:0"
|
||||
style="opacity:0;pointer-events:none"
|
||||
>
|
||||
<div
|
||||
class="ant-tooltip-content"
|
||||
@@ -34694,7 +34694,7 @@ Array [
|
||||
<div>
|
||||
<div
|
||||
class="ant-tooltip"
|
||||
style="opacity:0"
|
||||
style="opacity:0;pointer-events:none"
|
||||
>
|
||||
<div
|
||||
class="ant-tooltip-content"
|
||||
@@ -34728,7 +34728,7 @@ Array [
|
||||
<div>
|
||||
<div
|
||||
class="prefix-Tooltip"
|
||||
style="opacity:0"
|
||||
style="opacity:0;pointer-events:none"
|
||||
>
|
||||
<div
|
||||
class="prefix-Tooltip-content"
|
||||
@@ -37149,7 +37149,7 @@ exports[`ConfigProvider components TreeSelect configProvider 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="config-select-dropdown config-tree-select-dropdown"
|
||||
style="opacity:0"
|
||||
style="opacity:0;pointer-events:none"
|
||||
>
|
||||
<div>
|
||||
<div>
|
||||
@@ -37267,7 +37267,7 @@ exports[`ConfigProvider components TreeSelect configProvider componentSize large
|
||||
<div>
|
||||
<div
|
||||
class="config-select-dropdown config-tree-select-dropdown"
|
||||
style="opacity:0"
|
||||
style="opacity:0;pointer-events:none"
|
||||
>
|
||||
<div>
|
||||
<div>
|
||||
@@ -37385,7 +37385,7 @@ exports[`ConfigProvider components TreeSelect configProvider componentSize middl
|
||||
<div>
|
||||
<div
|
||||
class="config-select-dropdown config-tree-select-dropdown"
|
||||
style="opacity:0"
|
||||
style="opacity:0;pointer-events:none"
|
||||
>
|
||||
<div>
|
||||
<div>
|
||||
@@ -37503,7 +37503,7 @@ exports[`ConfigProvider components TreeSelect configProvider virtual and dropdow
|
||||
<div>
|
||||
<div
|
||||
class="ant-select-dropdown ant-tree-select-dropdown"
|
||||
style="opacity:0"
|
||||
style="opacity:0;pointer-events:none"
|
||||
>
|
||||
<div>
|
||||
<div>
|
||||
@@ -37621,7 +37621,7 @@ exports[`ConfigProvider components TreeSelect normal 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="ant-select-dropdown ant-tree-select-dropdown"
|
||||
style="opacity:0"
|
||||
style="opacity:0;pointer-events:none"
|
||||
>
|
||||
<div>
|
||||
<div>
|
||||
@@ -37739,7 +37739,7 @@ exports[`ConfigProvider components TreeSelect prefixCls 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="prefix-TreeSelect-dropdown prefix-TreeSelect-dropdown"
|
||||
style="opacity:0"
|
||||
style="opacity:0;pointer-events:none"
|
||||
>
|
||||
<div>
|
||||
<div>
|
||||
|
||||
@@ -78,4 +78,106 @@ describe('DatePicker', () => {
|
||||
const wrapper = mount(<DatePicker placeholder={undefined} />);
|
||||
expect(wrapper.find('input').props().placeholder).toEqual('Select date');
|
||||
});
|
||||
|
||||
it('showTime={{ showHour: true, showMinute: true }}', () => {
|
||||
const wrapper = mount(
|
||||
<DatePicker
|
||||
defaultValue={moment()}
|
||||
showTime={{ showHour: true, showMinute: true }}
|
||||
format="YYYY-MM-DD"
|
||||
open
|
||||
/>,
|
||||
);
|
||||
expect(wrapper.find('.ant-picker-time-panel-column').length).toBe(2);
|
||||
expect(
|
||||
wrapper.find('.ant-picker-time-panel-column').at(0).find('.ant-picker-time-panel-cell')
|
||||
.length,
|
||||
).toBe(24);
|
||||
expect(
|
||||
wrapper.find('.ant-picker-time-panel-column').at(1).find('.ant-picker-time-panel-cell')
|
||||
.length,
|
||||
).toBe(60);
|
||||
});
|
||||
|
||||
it('showTime={{ showHour: true, showSecond: true }}', () => {
|
||||
const wrapper = mount(
|
||||
<DatePicker
|
||||
defaultValue={moment()}
|
||||
showTime={{ showHour: true, showSecond: true }}
|
||||
format="YYYY-MM-DD"
|
||||
open
|
||||
/>,
|
||||
);
|
||||
expect(wrapper.find('.ant-picker-time-panel-column').length).toBe(2);
|
||||
expect(
|
||||
wrapper.find('.ant-picker-time-panel-column').at(0).find('.ant-picker-time-panel-cell')
|
||||
.length,
|
||||
).toBe(24);
|
||||
expect(
|
||||
wrapper.find('.ant-picker-time-panel-column').at(1).find('.ant-picker-time-panel-cell')
|
||||
.length,
|
||||
).toBe(60);
|
||||
});
|
||||
|
||||
it('showTime={{ showMinute: true, showSecond: true }}', () => {
|
||||
const wrapper = mount(
|
||||
<DatePicker
|
||||
defaultValue={moment()}
|
||||
showTime={{ showMinute: true, showSecond: true }}
|
||||
format="YYYY-MM-DD"
|
||||
open
|
||||
/>,
|
||||
);
|
||||
expect(wrapper.find('.ant-picker-time-panel-column').length).toBe(2);
|
||||
expect(
|
||||
wrapper.find('.ant-picker-time-panel-column').at(0).find('.ant-picker-time-panel-cell')
|
||||
.length,
|
||||
).toBe(60);
|
||||
expect(
|
||||
wrapper.find('.ant-picker-time-panel-column').at(1).find('.ant-picker-time-panel-cell')
|
||||
.length,
|
||||
).toBe(60);
|
||||
});
|
||||
|
||||
it('12 hours', () => {
|
||||
const wrapper = mount(
|
||||
<DatePicker defaultValue={moment()} showTime format="YYYY-MM-DD HH:mm:ss A" open />,
|
||||
);
|
||||
expect(wrapper.find('.ant-picker-time-panel-column').length).toBe(4);
|
||||
expect(
|
||||
wrapper.find('.ant-picker-time-panel-column').at(0).find('.ant-picker-time-panel-cell')
|
||||
.length,
|
||||
).toBe(12);
|
||||
expect(
|
||||
wrapper.find('.ant-picker-time-panel-column').at(1).find('.ant-picker-time-panel-cell')
|
||||
.length,
|
||||
).toBe(60);
|
||||
expect(
|
||||
wrapper.find('.ant-picker-time-panel-column').at(2).find('.ant-picker-time-panel-cell')
|
||||
.length,
|
||||
).toBe(60);
|
||||
expect(
|
||||
wrapper.find('.ant-picker-time-panel-column').at(3).find('.ant-picker-time-panel-cell')
|
||||
.length,
|
||||
).toBe(2);
|
||||
});
|
||||
|
||||
it('24 hours', () => {
|
||||
const wrapper = mount(
|
||||
<DatePicker defaultValue={moment()} showTime format="YYYY-MM-DD HH:mm:ss" open />,
|
||||
);
|
||||
expect(wrapper.find('.ant-picker-time-panel-column').length).toBe(3);
|
||||
expect(
|
||||
wrapper.find('.ant-picker-time-panel-column').at(0).find('.ant-picker-time-panel-cell')
|
||||
.length,
|
||||
).toBe(24);
|
||||
expect(
|
||||
wrapper.find('.ant-picker-time-panel-column').at(1).find('.ant-picker-time-panel-cell')
|
||||
.length,
|
||||
).toBe(60);
|
||||
expect(
|
||||
wrapper.find('.ant-picker-time-panel-column').at(2).find('.ant-picker-time-panel-cell')
|
||||
.length,
|
||||
).toBe(60);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -45,7 +45,7 @@ Array [
|
||||
<div>
|
||||
<div
|
||||
class="ant-picker-dropdown"
|
||||
style="opacity: 0;"
|
||||
style="opacity: 0; pointer-events: none;"
|
||||
>
|
||||
<div
|
||||
class="ant-picker-panel-container"
|
||||
@@ -669,7 +669,7 @@ Array [
|
||||
<div>
|
||||
<div
|
||||
class="ant-picker-dropdown"
|
||||
style="opacity: 0;"
|
||||
style="opacity: 0; pointer-events: none;"
|
||||
>
|
||||
<div
|
||||
class="ant-picker-panel-container"
|
||||
|
||||
@@ -150,7 +150,7 @@ Array [
|
||||
<div>
|
||||
<div
|
||||
class="ant-picker-dropdown ant-picker-dropdown-range"
|
||||
style="opacity:0"
|
||||
style="opacity:0;pointer-events:none"
|
||||
>
|
||||
<div
|
||||
class="ant-picker-range-wrapper ant-picker-date-range-wrapper"
|
||||
|
||||
@@ -4,7 +4,7 @@ exports[`MonthPicker and WeekPicker render MonthPicker 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="ant-picker-dropdown"
|
||||
style="opacity:0"
|
||||
style="opacity:0;pointer-events:none"
|
||||
>
|
||||
<div
|
||||
class="ant-picker-panel-container"
|
||||
@@ -197,7 +197,7 @@ exports[`MonthPicker and WeekPicker render WeekPicker 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="ant-picker-dropdown"
|
||||
style="opacity:0"
|
||||
style="opacity:0;pointer-events:none"
|
||||
>
|
||||
<div
|
||||
class="ant-picker-panel-container"
|
||||
|
||||
@@ -156,7 +156,7 @@ Added in `4.1.0`.
|
||||
| defaultValue | To set default date | \[[moment](http://momentjs.com/), [moment](http://momentjs.com/)] | - | |
|
||||
| defaultPickerValue | To set default picker date | \[[moment](http://momentjs.com/), [moment](http://momentjs.com/)\] | - | |
|
||||
| disabled | If disable start or end | \[boolean, boolean] | - | |
|
||||
| disabledTime | To specify the time that cannot be selected | function(dates: \[moment, moment], partial: `start` \| `end`) | - | |
|
||||
| disabledTime | To specify the time that cannot be selected | function(date: moment, partial: `start` \| `end`) | - | |
|
||||
| format | To set the date format, refer to [moment.js](http://momentjs.com/). When an array is provided, all values are used for parsing and first value is used for formatting | string \| string[] | `YYYY-MM-DD HH:mm:ss` | |
|
||||
| ranges | The preseted ranges for quick selection | { \[range: string]: [moment](http://momentjs.com/)\[] } \| { \[range: string]: () => [moment](http://momentjs.com/)\[] } | - | |
|
||||
| renderExtraFooter | Render extra footer in panel | () => React.ReactNode | - | |
|
||||
|
||||
@@ -157,7 +157,7 @@ import locale from 'antd/es/locale/zh_CN';
|
||||
| defaultValue | 默认日期 | [moment](http://momentjs.com/)\[] | - | |
|
||||
| defaultPickerValue | 默认面板日期 | [moment](http://momentjs.com/)\[] | - | |
|
||||
| disabled | 禁用起始项 | \[boolean, boolean] | - | |
|
||||
| disabledTime | 不可选择的时间 | function(dates: \[moment, moment\], partial: `start` \| `end`) | - | |
|
||||
| disabledTime | 不可选择的时间 | function(date: moment, partial: `start` \| `end`) | - | |
|
||||
| format | 展示的日期格式 | string | `YYYY-MM-DD HH:mm:ss` | |
|
||||
| ranges | 预设时间范围快捷选择 | { \[range: string]: [moment](http://momentjs.com/)\[] } \| { \[range: string]: () => [moment](http://momentjs.com/)\[] } | - | |
|
||||
| renderExtraFooter | 在面板中添加额外的页脚 | () => React.ReactNode | - | |
|
||||
|
||||
@@ -11,7 +11,7 @@ Array [
|
||||
<div>
|
||||
<div
|
||||
class="ant-dropdown"
|
||||
style="opacity:0"
|
||||
style="opacity:0;pointer-events:none"
|
||||
>
|
||||
<div>
|
||||
menu
|
||||
@@ -32,7 +32,7 @@ Array [
|
||||
<div>
|
||||
<div
|
||||
class="ant-dropdown"
|
||||
style="opacity:0"
|
||||
style="opacity:0;pointer-events:none"
|
||||
>
|
||||
<span>
|
||||
string
|
||||
|
||||
@@ -6055,7 +6055,7 @@ exports[`renders ./components/form/demo/validate-other.md correctly 1`] = `
|
||||
</svg>
|
||||
</span>
|
||||
<span>
|
||||
Click to upload
|
||||
Click to upload
|
||||
</span>
|
||||
</button>
|
||||
</span>
|
||||
|
||||
@@ -177,9 +177,7 @@ const Demo = () => {
|
||||
extra="longgggggggggggggggggggggggggggggggggg"
|
||||
>
|
||||
<Upload name="logo" action="/upload.do" listType="picture">
|
||||
<Button>
|
||||
<UploadOutlined /> Click to upload
|
||||
</Button>
|
||||
<Button icon={<UploadOutlined />}>Click to upload</Button>
|
||||
</Upload>
|
||||
</Form.Item>
|
||||
|
||||
|
||||
@@ -338,6 +338,10 @@ Before Modal opens, children elements do not exist in the view. You can set `for
|
||||
|
||||
Components inside Form.Item with name property will turn into controlled mode, which makes `defaultValue` not work anymore. Please try `initialValues` of Form to set default value.
|
||||
|
||||
### Why can not call `ref` of From at first time?
|
||||
|
||||
`ref` only receives the mounted instance. please ref React official doc: https://reactjs.org/docs/refs-and-the-dom.html#accessing-refs
|
||||
|
||||
### Why `resetFields` will re-mount component?
|
||||
|
||||
`resetFields` will re-mount component under Field to clean up customize component side effects (like async data, cached state, etc.). It's by design.
|
||||
|
||||
@@ -340,6 +340,10 @@ validator(rule, value, callback) => {
|
||||
|
||||
当你为 Form.Item 设置 `name` 属性后,子组件会转为受控模式。因而 `defaultValue` 不会生效。你需要在 Form 上通过 `initialValues` 设置默认值。
|
||||
|
||||
### 为什么第一次调用 `ref` 的 From 为空?
|
||||
|
||||
`ref` 仅在节点被加载时才会被赋值,请参考 React 官方文档:https://reactjs.org/docs/refs-and-the-dom.html#accessing-refs
|
||||
|
||||
### 为什么 `resetFields` 会重新 mount 组件?
|
||||
|
||||
`resetFields` 会重置整个 Field,因而其子组件也会重新 mount 从而消除自定义组件可能存在的副作用(例如异步数据、状态等等)。
|
||||
|
||||
@@ -7,13 +7,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
.@{ant-prefix}-col {
|
||||
&&-rtl {
|
||||
float: right;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
// mixin
|
||||
.loop-grid-columns(@index, @class) when (@index > 0) {
|
||||
.@{ant-prefix}-col@{class}-push-@{index} {
|
||||
|
||||
@@ -3,7 +3,7 @@ category: Components
|
||||
type: Data Display
|
||||
title: Image
|
||||
cols: 2
|
||||
cover: https://gw.alipayobjects.com/zos/bmw-prod/a77ae075-27de-49c9-9f44-a505f2be07fa.svg
|
||||
cover: https://gw.alipayobjects.com/zos/antfincdn/D1dXz9PZqa/image.svg
|
||||
---
|
||||
|
||||
Previewable image.
|
||||
|
||||
@@ -4,7 +4,7 @@ subtitle: 图片
|
||||
type: 数据展示
|
||||
title: Image
|
||||
cols: 2
|
||||
cover: https://gw.alipayobjects.com/zos/bmw-prod/a77ae075-27de-49c9-9f44-a505f2be07fa.svg
|
||||
cover: https://gw.alipayobjects.com/zos/antfincdn/D1dXz9PZqa/image.svg
|
||||
---
|
||||
|
||||
可预览的图片。
|
||||
|
||||
@@ -112,28 +112,22 @@ class InternalSider extends React.Component<InternalSideProps, SiderState> {
|
||||
this.responsiveHandler(this.mql);
|
||||
}
|
||||
|
||||
if (this.props.siderHook) {
|
||||
this.props.siderHook.addSider(this.uniqueId);
|
||||
}
|
||||
this.props?.siderHook.addSider(this.uniqueId);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
if (this.mql) {
|
||||
this.mql.removeListener(this.responsiveHandler as any);
|
||||
}
|
||||
|
||||
if (this.props.siderHook) {
|
||||
this.props.siderHook.removeSider(this.uniqueId);
|
||||
}
|
||||
this?.mql?.removeListener(this.responsiveHandler as any);
|
||||
this.props?.siderHook.removeSider(this.uniqueId);
|
||||
}
|
||||
|
||||
responsiveHandler = (mql: MediaQueryListEvent | MediaQueryList) => {
|
||||
this.setState({ below: mql.matches });
|
||||
const { onBreakpoint } = this.props;
|
||||
const { collapsed } = this.state;
|
||||
if (onBreakpoint) {
|
||||
onBreakpoint(mql.matches);
|
||||
}
|
||||
if (this.state.collapsed !== mql.matches) {
|
||||
if (collapsed !== mql.matches) {
|
||||
this.setCollapsed(mql.matches, 'responsive');
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React from 'react';
|
||||
import React, { useState } from 'react';
|
||||
import { mount, render } from 'enzyme';
|
||||
import Layout from '..';
|
||||
import Icon from '../../icon';
|
||||
@@ -14,7 +14,7 @@ describe('Layout', () => {
|
||||
mountTest(Sider);
|
||||
mountTest(() => (
|
||||
<Layout>
|
||||
<Sider />
|
||||
<Sider breakpoint="xs" />
|
||||
<Content />
|
||||
</Layout>
|
||||
));
|
||||
@@ -23,7 +23,7 @@ describe('Layout', () => {
|
||||
rtlTest(Content);
|
||||
rtlTest(Sider);
|
||||
|
||||
it('detect the sider as children', async () => {
|
||||
it('detect the sider as children', () => {
|
||||
const wrapper = mount(
|
||||
<Layout>
|
||||
<Sider>Sider</Sider>
|
||||
@@ -31,6 +31,34 @@ describe('Layout', () => {
|
||||
</Layout>,
|
||||
);
|
||||
expect(wrapper.find('.ant-layout').hasClass('ant-layout-has-sider')).toBe(true);
|
||||
wrapper.unmount();
|
||||
});
|
||||
|
||||
it('umount from multiple siders', async () => {
|
||||
const App = () => {
|
||||
const [hide1, setHide1] = useState(false);
|
||||
const [hide2, setHide2] = useState(false);
|
||||
return (
|
||||
<Layout>
|
||||
{hide1 ? null : <Sider>Sider</Sider>}
|
||||
{hide2 ? null : <Sider>Sider</Sider>}
|
||||
<Content>
|
||||
<button onClick={() => setHide1(true)} type="button">
|
||||
hide sider 1
|
||||
</button>
|
||||
<button onClick={() => setHide2(true)} type="button">
|
||||
hide sider 2
|
||||
</button>
|
||||
</Content>
|
||||
</Layout>
|
||||
);
|
||||
};
|
||||
const wrapper = mount(<App />);
|
||||
expect(wrapper.find('.ant-layout').hasClass('ant-layout-has-sider')).toBe(true);
|
||||
wrapper.find('button').at(0).simulate('click');
|
||||
expect(wrapper.find('.ant-layout').hasClass('ant-layout-has-sider')).toBe(true);
|
||||
wrapper.find('button').at(1).simulate('click');
|
||||
expect(wrapper.find('.ant-layout').hasClass('ant-layout-has-sider')).toBe(false);
|
||||
});
|
||||
|
||||
it('detect the sider inside the children', async () => {
|
||||
|
||||
@@ -396,7 +396,7 @@ exports[`List.pagination should change page size work 2`] = `
|
||||
<div>
|
||||
<div
|
||||
class="ant-select-dropdown"
|
||||
style="min-width: 0; opacity: 0;"
|
||||
style="min-width: 0; opacity: 0; pointer-events: none;"
|
||||
>
|
||||
<div>
|
||||
<div
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -46,6 +46,7 @@ import jaJP from '../ja_JP';
|
||||
import knIN from '../kn_IN';
|
||||
import koKR from '../ko_KR';
|
||||
import kmrIQ from '../kmr_IQ';
|
||||
import kuIQ from '../ku_IQ';
|
||||
import lvLV from '../lv_LV';
|
||||
import ltLT from '../lt_LT';
|
||||
import mkMK from '../mk_MK';
|
||||
@@ -103,6 +104,7 @@ const locales = [
|
||||
knIN,
|
||||
koKR,
|
||||
kmrIQ,
|
||||
kuIQ,
|
||||
ltLT,
|
||||
mkMK,
|
||||
msMY,
|
||||
|
||||
@@ -16,16 +16,6 @@ export interface MenuItemProps extends Omit<RcMenuItemProps, 'title'> {
|
||||
export default class MenuItem extends React.Component<MenuItemProps> {
|
||||
static isMenuItem = true;
|
||||
|
||||
private menuItem: this;
|
||||
|
||||
onKeyDown = (e: React.MouseEvent<HTMLElement>) => {
|
||||
this.menuItem.onKeyDown(e);
|
||||
};
|
||||
|
||||
saveMenuItem = (menuItem: this) => {
|
||||
this.menuItem = menuItem;
|
||||
};
|
||||
|
||||
renderItemChildren(inlineCollapsed: boolean) {
|
||||
const { icon, children, level, rootPrefixCls } = this.props;
|
||||
// inline-collapsed.md demo 依赖 span 来隐藏文字,有 icon 属性,则内部包裹一个 span
|
||||
@@ -79,7 +69,6 @@ export default class MenuItem extends React.Component<MenuItemProps> {
|
||||
(icon ? childrenLength + 1 : childrenLength) === 1,
|
||||
})}
|
||||
title={title}
|
||||
ref={this.saveMenuItem}
|
||||
>
|
||||
{icon}
|
||||
{this.renderItemChildren(inlineCollapsed)}
|
||||
|
||||
@@ -31,16 +31,6 @@ class SubMenu extends React.Component<SubMenuProps, any> {
|
||||
// fix issue:https://github.com/ant-design/ant-design/issues/8666
|
||||
static isSubMenu = 1;
|
||||
|
||||
private subMenu: any;
|
||||
|
||||
onKeyDown = (e: React.MouseEvent<HTMLElement>) => {
|
||||
this.subMenu.onKeyDown(e);
|
||||
};
|
||||
|
||||
saveSubMenu = (subMenu: any) => {
|
||||
this.subMenu = subMenu;
|
||||
};
|
||||
|
||||
renderTitle(inlineCollapsed: boolean) {
|
||||
const { icon, title, level, rootPrefixCls } = this.props;
|
||||
if (!icon) {
|
||||
@@ -69,7 +59,6 @@ class SubMenu extends React.Component<SubMenuProps, any> {
|
||||
<RcSubMenu
|
||||
{...omit(this.props, ['icon'])}
|
||||
title={this.renderTitle(inlineCollapsed)}
|
||||
ref={this.saveSubMenu}
|
||||
popupClassName={classNames(
|
||||
rootPrefixCls,
|
||||
`${rootPrefixCls}-${antdMenuTheme}`,
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import TestUtils from 'react-dom/test-utils';
|
||||
import Modal from '..';
|
||||
import { destroyFns } from '../Modal';
|
||||
|
||||
@@ -140,6 +141,42 @@ describe('Modal.confirm triggers callbacks correctly', () => {
|
||||
jest.useRealTimers();
|
||||
});
|
||||
|
||||
it('should close confirm modal when click cancel button', () => {
|
||||
jest.useFakeTimers();
|
||||
const onCancel = jest.fn();
|
||||
Modal.confirm({
|
||||
title: 'title',
|
||||
content: 'content',
|
||||
onCancel,
|
||||
});
|
||||
jest.runAllTimers();
|
||||
expect($$(`.ant-modal-confirm-confirm`)).toHaveLength(1);
|
||||
$$('.ant-btn')[0].click();
|
||||
jest.runAllTimers();
|
||||
expect($$(`.ant-modal-confirm-confirm`)).toHaveLength(0);
|
||||
expect(onCancel).toHaveBeenCalledTimes(1);
|
||||
jest.useRealTimers();
|
||||
});
|
||||
|
||||
it('should close confirm modal when press ESC', () => {
|
||||
jest.useFakeTimers();
|
||||
const onCancel = jest.fn();
|
||||
Modal.confirm({
|
||||
title: 'title',
|
||||
content: 'content',
|
||||
onCancel,
|
||||
});
|
||||
jest.runAllTimers();
|
||||
expect($$(`.ant-modal-confirm-confirm`)).toHaveLength(1);
|
||||
TestUtils.Simulate.keyDown($$('.ant-modal')[0], {
|
||||
keyCode: 27,
|
||||
});
|
||||
jest.runAllTimers();
|
||||
expect($$(`.ant-modal-confirm-confirm`)).toHaveLength(0);
|
||||
expect(onCancel).toHaveBeenCalledTimes(1);
|
||||
jest.useRealTimers();
|
||||
});
|
||||
|
||||
it('should not close modals when click confirm button when onOk has argument', () => {
|
||||
jest.useFakeTimers();
|
||||
['info', 'success', 'warning', 'error'].forEach(type => {
|
||||
|
||||
@@ -18,6 +18,7 @@ When requiring users to interact with the application, but without jumping to a
|
||||
| afterClose | Specify a function that will be called when modal is closed completely | function | - |
|
||||
| bodyStyle | Body style for modal body element. Such as height, padding etc | CSSProperties | {} |
|
||||
| cancelText | Text of the Cancel button | string \| ReactNode | `Cancel` |
|
||||
| cancelButtonProps | The cancel button props | [ButtonProps](/components/button/#API) | - |
|
||||
| centered | Centered Modal | boolean | false |
|
||||
| closable | Whether a close (x) button is visible on top right of the modal dialog or not | boolean | true |
|
||||
| closeIcon | Custom close icon | ReactNode | <CloseOutlined /> |
|
||||
@@ -26,21 +27,21 @@ When requiring users to interact with the application, but without jumping to a
|
||||
| footer | Footer content, set as `footer={null}` when you don't need default buttons | string \| ReactNode | (OK and Cancel buttons) |
|
||||
| forceRender | Force render Modal | boolean | false |
|
||||
| getContainer | Return the mount node for Modal | HTMLElement \| () => HTMLElement \| Selectors \| false | document.body |
|
||||
| keyboard | Whether support press esc to close | boolean | true |
|
||||
| mask | Whether show mask or not | boolean | true |
|
||||
| maskClosable | Whether to close the modal dialog when the mask (area outside the modal) is clicked | boolean | true |
|
||||
| maskStyle | Style for modal's mask element | object | {} |
|
||||
| okButtonProps | The ok button props | [ButtonProps](/components/button/#API) | - |
|
||||
| okText | Text of the OK button | string \| ReactNode | `OK` |
|
||||
| okType | Button `type` of the OK button | string | `primary` |
|
||||
| okButtonProps | The ok button props | [ButtonProps](/components/button/#API) | - |
|
||||
| cancelButtonProps | The cancel button props | [ButtonProps](/components/button/#API) | - |
|
||||
| onCancel | Specify a function that will be called when a user clicks mask, close button on top right or Cancel button | function(e) | - |
|
||||
| onOk | Specify a function that will be called when a user clicks the OK button | function(e) | - |
|
||||
| style | Style of floating layer, typically used at least for adjusting the position | CSSProperties | - |
|
||||
| title | The modal dialog's title | string \| ReactNode | - |
|
||||
| visible | Whether the modal dialog is visible or not | boolean | false |
|
||||
| width | Width of the modal dialog | string \| number | 520 |
|
||||
| wrapClassName | The class name of the container of the modal dialog | string | - |
|
||||
| zIndex | The `z-index` of the Modal | number | 1000 |
|
||||
| onCancel | Specify a function that will be called when a user clicks mask, close button on top right or Cancel button | function(e) | - |
|
||||
| onOk | Specify a function that will be called when a user clicks the OK button | function(e) | - |
|
||||
|
||||
#### Note
|
||||
|
||||
@@ -63,23 +64,26 @@ The items listed above are all functions, expecting a settings object as paramet
|
||||
| Property | Description | Type | Default | Version |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| autoFocusButton | Specify which button to autofocus | null \| `ok` \| `cancel` | `ok` | |
|
||||
| cancelButtonProps | The cancel button props | [ButtonProps](/components/button/#API) | - | |
|
||||
| cancelText | Text of the Cancel button with Modal.confirm | string | `Cancel` | |
|
||||
| centered | Centered Modal | boolean | false | |
|
||||
| className | The className of container | string | - | |
|
||||
| content | Content | string \| ReactNode | - | |
|
||||
| getContainer | Return the mount node for Modal | HTMLElement \| () => HTMLElement \| Selectors \| false | document.body | |
|
||||
| icon | Custom icon | ReactNode | <QuestionCircle /> | 3.12.0 |
|
||||
| keyboard | Whether support press esc to close | boolean | true | |
|
||||
| mask | Whether show mask or not. | boolean | true | |
|
||||
| maskClosable | Whether to close the modal dialog when the mask (area outside the modal) is clicked | boolean | false | |
|
||||
| maskStyle | Style for modal's mask element | object | {} | |
|
||||
| okButtonProps | The ok button props | [ButtonProps](/components/button/#API) | - | |
|
||||
| okText | Text of the OK button | string | `OK` | |
|
||||
| okType | Button `type` of the OK button | string | `primary` | |
|
||||
| okButtonProps | The ok button props | [ButtonProps](/components/button/#API) | - | |
|
||||
| cancelButtonProps | The cancel button props | [ButtonProps](/components/button/#API) | - | |
|
||||
| onCancel | Specify a function that will be called when the user clicks the Cancel button. The parameter of this function is a function whose execution should include closing the dialog. You can also just return a promise and when the promise is resolved, the modal dialog will also be closed | function(close) | - | |
|
||||
| onOk | Specify a function that will be called when the user clicks the OK button. The parameter of this function is a function whose execution should include closing the dialog. You can also just return a promise and when the promise is resolved, the modal dialog will also be closed | function(close) | - | |
|
||||
| style | Style of floating layer, typically used at least for adjusting the position | CSSProperties | - | |
|
||||
| title | Title | string \| ReactNode | - | |
|
||||
| width | Width of the modal dialog | string \| number | 416 | |
|
||||
| zIndex | The `z-index` of the Modal | number | 1000 | |
|
||||
| onCancel | Specify a function that will be called when the user clicks the Cancel button. The parameter of this function is a function whose execution should include closing the dialog. You can also just return a promise and when the promise is resolved, the modal dialog will also be closed | function(close) | - | |
|
||||
| onOk | Specify a function that will be called when the user clicks the OK button. The parameter of this function is a function whose execution should include closing the dialog. You can also just return a promise and when the promise is resolved, the modal dialog will also be closed | function(close) | - | |
|
||||
|
||||
All the `Modal.method`s will return a reference, and then we can update and close the modal dialog by the reference.
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ cover: https://gw.alipayobjects.com/zos/alicdn/3StSdUlSH/Modal.svg
|
||||
| --- | --- | --- | --- |
|
||||
| afterClose | Modal 完全关闭后的回调 | function | - |
|
||||
| bodyStyle | Modal body 样式 | object | {} |
|
||||
| cancelButtonProps | cancel 按钮 props | [ButtonProps](/components/button/#API) | - |
|
||||
| cancelText | 取消按钮文字 | string \| ReactNode | `取消` |
|
||||
| centered | 垂直居中展示 Modal | boolean | false |
|
||||
| closable | 是否显示右上角的关闭按钮 | boolean | true |
|
||||
@@ -33,18 +34,17 @@ cover: https://gw.alipayobjects.com/zos/alicdn/3StSdUlSH/Modal.svg
|
||||
| mask | 是否展示遮罩 | boolean | true |
|
||||
| maskClosable | 点击蒙层是否允许关闭 | boolean | true |
|
||||
| maskStyle | 遮罩样式 | object | {} |
|
||||
| okButtonProps | ok 按钮 props | [ButtonProps](/components/button/#API) | - |
|
||||
| okText | 确认按钮文字 | string \| ReactNode | `确定` |
|
||||
| okType | 确认按钮类型 | string | `primary` |
|
||||
| okButtonProps | ok 按钮 props | [ButtonProps](/components/button/#API) | - |
|
||||
| cancelButtonProps | cancel 按钮 props | [ButtonProps](/components/button/#API) | - |
|
||||
| onCancel | 点击遮罩层或右上角叉或取消按钮的回调 | function(e) | - |
|
||||
| onOk | 点击确定回调 | function(e) | - |
|
||||
| style | 可用于设置浮层的样式,调整浮层位置等 | CSSProperties | - |
|
||||
| title | 标题 | string \| ReactNode | - |
|
||||
| visible | 对话框是否可见 | boolean | - |
|
||||
| width | 宽度 | string \| number | 520 |
|
||||
| wrapClassName | 对话框外层容器的类名 | string | - |
|
||||
| zIndex | 设置 Modal 的 `z-index` | number | 1000 |
|
||||
| onCancel | 点击遮罩层或右上角叉或取消按钮的回调 | function(e) | - |
|
||||
| onOk | 点击确定回调 | function(e) | - |
|
||||
|
||||
#### 注意
|
||||
|
||||
@@ -67,21 +67,26 @@ cover: https://gw.alipayobjects.com/zos/alicdn/3StSdUlSH/Modal.svg
|
||||
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| autoFocusButton | 指定自动获得焦点的按钮 | null \| `ok` \| `cancel` | `ok` | |
|
||||
| cancelButtonProps | cancel 按钮 props | [ButtonProps](/components/button/#API) | - | |
|
||||
| cancelText | 设置 Modal.confirm 取消按钮文字 | string | `取消` | |
|
||||
| centered | 垂直居中展示 Modal | boolean | false | |
|
||||
| className | 容器类名 | string | - | |
|
||||
| content | 内容 | string \| ReactNode | - | |
|
||||
| getContainer | 指定 Modal 挂载的 HTML 节点, false 为挂载在当前 dom | HTMLElement \| () => HTMLElement \| Selectors \| false | document.body | |
|
||||
| icon | 自定义图标 | ReactNode | <QuestionCircle /> | 3.12.0 |
|
||||
| keyboard | 是否支持键盘 esc 关闭 | boolean | true | |
|
||||
| mask | 是否展示遮罩 | boolean | true | |
|
||||
| maskClosable | 点击蒙层是否允许关闭 | boolean | false | |
|
||||
| maskStyle | 遮罩样式 | object | {} | |
|
||||
| okButtonProps | ok 按钮 props | [ButtonProps](/components/button/#API) | - | |
|
||||
| okText | 确认按钮文字 | string | `确定` | |
|
||||
| okType | 确认按钮类型 | string | `primary` | |
|
||||
| okButtonProps | ok 按钮 props | [ButtonProps](/components/button/#API) | - | |
|
||||
| cancelButtonProps | cancel 按钮 props | [ButtonProps](/components/button/#API) | - | |
|
||||
| onCancel | 取消回调,参数为关闭函数,返回 promise 时 resolve 后自动关闭 | function(close) | - | |
|
||||
| onOk | 点击确定回调,参数为关闭函数,返回 promise 时 resolve 后自动关闭 | function(close) | - | |
|
||||
| style | 可用于设置浮层的样式,调整浮层位置等 | CSSProperties | - | |
|
||||
| title | 标题 | string \| ReactNode | - | |
|
||||
| width | 宽度 | string \| number | 416 | |
|
||||
| zIndex | 设置 Modal 的 `z-index` | number | 1000 | |
|
||||
| onCancel | 取消回调,参数为关闭函数,返回 promise 时 resolve 后自动关闭 | function(close) | - | |
|
||||
| onOk | 点击确定回调,参数为关闭函数,返回 promise 时 resolve 后自动关闭 | function(close) | - | |
|
||||
|
||||
以上函数调用后,会返回一个引用,可以通过该引用更新和关闭弹窗。
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ Array [
|
||||
<div>
|
||||
<div
|
||||
class="ant-popover ant-popover-rtl"
|
||||
style="opacity:0"
|
||||
style="opacity:0;pointer-events:none"
|
||||
>
|
||||
<div
|
||||
class="ant-popover-content"
|
||||
|
||||
@@ -7,7 +7,7 @@ import { ConfigContext } from '../config-provider';
|
||||
import SizeContext from '../config-provider/SizeContext';
|
||||
import { RadioGroupContextProvider } from './context';
|
||||
|
||||
const RadioGroup = React.forwardRef<unknown, RadioGroupProps>((props, ref) => {
|
||||
const RadioGroup: React.FC<RadioGroupProps> = props => {
|
||||
const { getPrefixCls, direction } = React.useContext(ConfigContext);
|
||||
const size = React.useContext(SizeContext);
|
||||
|
||||
@@ -53,7 +53,6 @@ const RadioGroup = React.forwardRef<unknown, RadioGroupProps>((props, ref) => {
|
||||
// 此处类型自动推导为 string
|
||||
return (
|
||||
<Radio
|
||||
ref={ref}
|
||||
key={option}
|
||||
prefixCls={optionsPrefixCls}
|
||||
disabled={disabled}
|
||||
@@ -67,7 +66,6 @@ const RadioGroup = React.forwardRef<unknown, RadioGroupProps>((props, ref) => {
|
||||
// 此处类型自动推导为 { label: string value: string }
|
||||
return (
|
||||
<Radio
|
||||
ref={ref}
|
||||
key={`radio-group-value-options-${option.value}`}
|
||||
prefixCls={optionsPrefixCls}
|
||||
disabled={option.disabled || disabled}
|
||||
@@ -116,7 +114,7 @@ const RadioGroup = React.forwardRef<unknown, RadioGroupProps>((props, ref) => {
|
||||
{renderGroup()}
|
||||
</RadioGroupContextProvider>
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
RadioGroup.defaultProps = {
|
||||
buttonStyle: 'outline' as RadioGroupButtonStyle,
|
||||
|
||||
@@ -735,7 +735,7 @@ exports[`renders ./components/select/demo/custom-dropdown-menu.md correctly 1`]
|
||||
|
||||
exports[`renders ./components/select/demo/custom-tag-render.md correctly 1`] = `
|
||||
<div
|
||||
class="ant-select ant-select-multiple ant-select-show-search"
|
||||
class="ant-select ant-select-multiple ant-select-show-arrow ant-select-show-search"
|
||||
style="width:100%"
|
||||
>
|
||||
<div
|
||||
@@ -825,6 +825,33 @@ exports[`renders ./components/select/demo/custom-tag-render.md correctly 1`] = `
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
class="ant-select-arrow"
|
||||
style="user-select:none;-webkit-user-select:none"
|
||||
unselectable="on"
|
||||
>
|
||||
<span
|
||||
aria-label="down"
|
||||
class="anticon anticon-down ant-select-suffix"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class=""
|
||||
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>
|
||||
`;
|
||||
|
||||
@@ -1091,7 +1118,7 @@ exports[`renders ./components/select/demo/label-in-value.md correctly 1`] = `
|
||||
exports[`renders ./components/select/demo/multiple.md correctly 1`] = `
|
||||
Array [
|
||||
<div
|
||||
class="ant-select ant-select-multiple ant-select-show-search"
|
||||
class="ant-select ant-select-multiple ant-select-allow-clear ant-select-show-search"
|
||||
style="width:100%"
|
||||
>
|
||||
<div
|
||||
@@ -1195,6 +1222,33 @@ Array [
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
class="ant-select-clear"
|
||||
style="user-select:none;-webkit-user-select:none"
|
||||
unselectable="on"
|
||||
>
|
||||
<span
|
||||
aria-label="close-circle"
|
||||
class="anticon anticon-close-circle"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class=""
|
||||
data-icon="close-circle"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm165.4 618.2l-66-.3L512 563.4l-99.3 118.4-66.1.3c-4.4 0-8-3.5-8-8 0-1.9.7-3.7 1.9-5.2l130.1-155L340.5 359a8.32 8.32 0 01-1.9-5.2c0-4.4 3.6-8 8-8l66.1.3L512 464.6l99.3-118.4 66-.3c4.4 0 8 3.5 8 8 0 1.9-.7 3.7-1.9 5.2L553.5 514l130 155c1.2 1.5 1.9 3.3 1.9 5.2 0 4.4-3.6 8-8 8z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
</div>,
|
||||
<br />,
|
||||
<div
|
||||
|
||||
@@ -7,11 +7,11 @@ title:
|
||||
|
||||
## zh-CN
|
||||
|
||||
允许自定义选择标签的样式
|
||||
允许自定义选择标签的样式。
|
||||
|
||||
## en-US
|
||||
|
||||
Allows for custom rendering of tags
|
||||
Allows for custom rendering of tags.
|
||||
|
||||
```jsx
|
||||
import { Select, Tag } from 'antd';
|
||||
@@ -31,6 +31,7 @@ function tagRender(props) {
|
||||
ReactDOM.render(
|
||||
<Select
|
||||
mode="multiple"
|
||||
showArrow
|
||||
tagRender={tagRender}
|
||||
defaultValue={['gold', 'cyan']}
|
||||
style={{ width: '100%' }}
|
||||
|
||||
@@ -31,6 +31,7 @@ ReactDOM.render(
|
||||
<>
|
||||
<Select
|
||||
mode="multiple"
|
||||
allowClear
|
||||
style={{ width: '100%' }}
|
||||
placeholder="Please select"
|
||||
defaultValue={['a10', 'c12']}
|
||||
|
||||
@@ -7,11 +7,11 @@ title:
|
||||
|
||||
## zh-CN
|
||||
|
||||
tags select,随意输入的内容(scroll the menu)
|
||||
tags select,随意输入的内容(scroll the menu)。
|
||||
|
||||
## en-US
|
||||
|
||||
Select with tags, transform input to tag (scroll the menu)
|
||||
Select with tags, transform input to tag (scroll the menu).
|
||||
|
||||
```jsx
|
||||
import { Select } from 'antd';
|
||||
|
||||
@@ -27,7 +27,10 @@ Select component to select value from options.
|
||||
| allowClear | Show clear button | boolean | false | |
|
||||
| autoClearSearchValue | Whether the current search will be cleared on selecting an item. Only applies when `mode` is set to `multiple` or `tags` | boolean | true | |
|
||||
| autoFocus | Get focus by default | boolean | false | |
|
||||
| bordered | Whether has border style | boolean | true | |
|
||||
| clearIcon | The custom clear icon | ReactNode | - | |
|
||||
| defaultActiveFirstOption | Whether active first option by default | boolean | true | |
|
||||
| defaultOpen | Initial open state of dropdown | boolean | - | |
|
||||
| defaultValue | Initial selected option | string \| string\[]<br />number \| number\[]<br />LabeledValue \| LabeledValue[] | - | |
|
||||
| disabled | Whether disabled select | boolean | false | |
|
||||
| dropdownClassName | The className of dropdown menu | string | - | |
|
||||
@@ -36,32 +39,20 @@ Select component to select value from options.
|
||||
| dropdownStyle | The style of dropdown menu | CSSProperties | - | |
|
||||
| filterOption | If true, filter options by input, if function, filter options against it. The function will receive two arguments, `inputValue` and `option`, if the function returns `true`, the option will be included in the filtered set; Otherwise, it will be excluded | boolean \| function(inputValue, option) | true | |
|
||||
| getPopupContainer | Parent Node which the selector should be rendered to. Default to `body`. When position issues happen, try to modify it into scrollable content and position it relative. [Example](https://codesandbox.io/s/4j168r7jw0) | function(triggerNode) | () => document.body | |
|
||||
| labelInValue | Whether to embed label in value, turn the format of value from `string` to `{ value: string, label: ReactNode }` | boolean | false | |
|
||||
| labelInValue | Whether to embed label in value, turn the format of value from `string` to { value: string, label: ReactNode } | boolean | false | |
|
||||
| listHeight | Config popup height | number | 256 | |
|
||||
| loading | Indicate loading state | boolean | false | |
|
||||
| maxTagCount | Max tag count to show | number | - | |
|
||||
| maxTagTextLength | Max tag text length to show | number | - | |
|
||||
| maxTagPlaceholder | Placeholder for not showing tags | ReactNode \| function(omittedValues) | - | |
|
||||
| tagRender | Customize tag render | (props) => ReactNode | - | |
|
||||
| maxTagTextLength | Max tag text length to show | number | - | |
|
||||
| menuItemSelectedIcon | The custom menuItemSelected icon with multiple options | ReactNode | - | |
|
||||
| mode | Set mode of Select | `multiple` \| `tags` | - | |
|
||||
| notFoundContent | Specify content to show when no result matches | ReactNode | `Not Found` | |
|
||||
| options | Select options. Will get better perf than jsx definition | { label, value }[] | - | |
|
||||
| optionFilterProp | Which prop value of option will be used for filter if filterOption is true | string | `value` | |
|
||||
| optionLabelProp | Which prop value of option will render as content of select. [Example](https://codesandbox.io/s/antd-reproduction-template-tk678) | string | `children` | |
|
||||
| placeholder | Placeholder of select | string \| ReactNode | - | |
|
||||
| showArrow | Whether to show the drop-down arrow | boolean | true(for single select), false(for multiple select) | |
|
||||
| showSearch | Whether show search input in single mode | boolean | false | |
|
||||
| size | Size of Select input | `large` \| `middle` \| `small` | - | |
|
||||
| suffixIcon | The custom suffix icon | ReactNode | - | |
|
||||
| removeIcon | The custom remove icon | ReactNode | - | |
|
||||
| clearIcon | The custom clear icon | ReactNode | - | |
|
||||
| menuItemSelectedIcon | The custom menuItemSelected icon with multiple options | ReactNode | - | |
|
||||
| tokenSeparators | Separator used to tokenize on tag \| multiple mode | string\[] | - | |
|
||||
| value | Current selected option | string \| string\[]<br />number \| number\[]<br />LabeledValue \| LabeledValue[] | - | |
|
||||
| virtual | Disable virtual scroll when set to false | boolean | true | 4.1.0 |
|
||||
| onBlur | Called when blur | function | - | |
|
||||
| onChange | Called when select an option or input value change | function(value, option:Option \| Array<Option>) | - | |
|
||||
| onClear | Called when clear | function | - | 4.6.0 |
|
||||
| onDeselect | Called when a option is deselected, param is the selected option's value. Only called for multiple or tags, effective in multiple or tags mode only | function(string \| number \| LabeledValue) | - | |
|
||||
| onDeselect | Called when a option is deselected, param is the selected option's value. Only called for `multiple` or `tags`, effective in multiple or tags mode only | function(string \| number \| LabeledValue) | - | |
|
||||
| onDropdownVisibleChange | Called when dropdown open | function(open) | - | |
|
||||
| onFocus | Called when focus | function | - | |
|
||||
| onInputKeyDown | Called when key pressed | function | - | |
|
||||
| onMouseEnter | Called when mouse enter | function | - | |
|
||||
@@ -69,11 +60,22 @@ Select component to select value from options.
|
||||
| onPopupScroll | Called when dropdown scrolls | function | - | |
|
||||
| onSearch | Callback function that is fired when input changed | function(value: string) | - | |
|
||||
| onSelect | Called when a option is selected, the params are option's value (or key) and option instance | function(string \| number \| LabeledValue, option: Option) | - | |
|
||||
| defaultOpen | Initial open state of dropdown | boolean | - | |
|
||||
| open | Controlled open state of dropdown | boolean | - | |
|
||||
| onDropdownVisibleChange | Call when dropdown open | function(open) | - | |
|
||||
| loading | Indicate loading state | boolean | false | |
|
||||
| bordered | Whether has border style | boolean | true | |
|
||||
| options | Select options. Will get better perf than jsx definition | { label, value }[] | - | |
|
||||
| optionFilterProp | Which prop value of option will be used for filter if filterOption is true | string | `value` | |
|
||||
| optionLabelProp | Which prop value of option will render as content of select. [Example](https://codesandbox.io/s/antd-reproduction-template-tk678) | string | `children` | |
|
||||
| placeholder | Placeholder of select | string \| ReactNode | - | |
|
||||
| removeIcon | The custom remove icon | ReactNode | - | |
|
||||
| showArrow | Whether to show the drop-down arrow | boolean | true(for single select), false(for multiple select) | |
|
||||
| showSearch | Whether show search input in single mode | boolean | false | |
|
||||
| size | Size of Select input | `large` \| `middle` \| `small` | - | |
|
||||
| suffixIcon | The custom suffix icon | ReactNode | - | |
|
||||
| tagRender | Customize tag render | (props) => ReactNode | - | |
|
||||
| tokenSeparators | Separator used to tokenize on `tag` and `multiple` mode | string\[] | - | |
|
||||
| value | Current selected option | string \| string\[]<br />number \| number\[]<br />LabeledValue \| LabeledValue[] | - | |
|
||||
| virtual | Disable virtual scroll when set to false | boolean | true | 4.1.0 |
|
||||
|
||||
> Note, if you find that the drop-down menu scrolls with the page, or you need to trigger Select in other popup layers, please try to use `getPopupContainer={triggerNode => triggerNode.parentElement}` to fix the drop-down popup rendering node in the parent element of the trigger .
|
||||
|
||||
### Select Methods
|
||||
|
||||
@@ -86,10 +88,10 @@ Select component to select value from options.
|
||||
|
||||
| Property | Description | Type | Default | Version |
|
||||
| --------- | ------------------------------------------ | ---------------- | ------- | ------- |
|
||||
| className | The additional class to option | string | - | |
|
||||
| disabled | Disable this option | boolean | false | |
|
||||
| title | `title` of Select after select this Option | string | - | |
|
||||
| value | Default to filter with this property | string \| number | - | |
|
||||
| className | The additional class to option | string | - | |
|
||||
|
||||
### OptGroup props
|
||||
|
||||
|
||||
@@ -28,7 +28,10 @@ cover: https://gw.alipayobjects.com/zos/alicdn/_0XzgOis7/Select.svg
|
||||
| allowClear | 支持清除 | boolean | false | |
|
||||
| autoClearSearchValue | 是否在选中项后清空搜索框,只在 `mode` 为 `multiple` 或 `tags` 时有效 | boolean | true | |
|
||||
| autoFocus | 默认获取焦点 | boolean | false | |
|
||||
| bordered | 是否有边框 | boolean | true | |
|
||||
| clearIcon | 自定义的多选框清空图标 | ReactNode | - | |
|
||||
| defaultActiveFirstOption | 是否默认高亮第一个选项 | boolean | true | |
|
||||
| defaultOpen | 是否默认展开下拉菜单 | boolean | - | |
|
||||
| defaultValue | 指定默认选中的条目 | string \| string\[]<br />number \| number\[]<br />LabeledValue \| LabeledValue[] | - | |
|
||||
| disabled | 是否禁用 | boolean | false | |
|
||||
| dropdownClassName | 下拉菜单的 className 属性 | string | - | |
|
||||
@@ -37,32 +40,20 @@ cover: https://gw.alipayobjects.com/zos/alicdn/_0XzgOis7/Select.svg
|
||||
| dropdownStyle | 下拉菜单的 style 属性 | CSSProperties | - | |
|
||||
| filterOption | 是否根据输入项进行筛选。当其为一个函数时,会接收 `inputValue` `option` 两个参数,当 `option` 符合筛选条件时,应返回 true,反之则返回 false | boolean \| function(inputValue, option) | true | |
|
||||
| getPopupContainer | 菜单渲染父节点。默认渲染到 body 上,如果你遇到菜单滚动定位问题,试试修改为滚动的区域,并相对其定位。[示例](https://codesandbox.io/s/4j168r7jw0) | function(triggerNode) | () => document.body | |
|
||||
| labelInValue | 是否把每个选项的 label 包装到 value 中,会把 Select 的 value 类型从 `string` 变为 `{ value: string, label: ReactNode }` 的格式 | boolean | false | |
|
||||
| labelInValue | 是否把每个选项的 label 包装到 value 中,会把 Select 的 value 类型从 `string` 变为 { value: string, label: ReactNode } 的格式 | boolean | false | |
|
||||
| listHeight | 设置弹窗滚动高度 | number | 256 | |
|
||||
| loading | 加载中状态 | boolean | false | |
|
||||
| maxTagCount | 最多显示多少个 tag | number | - | |
|
||||
| maxTagTextLength | 最大显示的 tag 文本长度 | number | - | |
|
||||
| maxTagPlaceholder | 隐藏 tag 时显示的内容 | ReactNode \| function(omittedValues) | - | |
|
||||
| tagRender | 自定义 tag 内容 render | (props) => ReactNode | - | |
|
||||
| maxTagTextLength | 最大显示的 tag 文本长度 | number | - | |
|
||||
| menuItemSelectedIcon | 自定义多选时当前选中的条目图标 | ReactNode | - | |
|
||||
| mode | 设置 Select 的模式为多选或标签 | `multiple` \| `tags` | - | |
|
||||
| notFoundContent | 当下拉列表为空时显示的内容 | ReactNode | `Not Found` | |
|
||||
| options | 数据化配置选项内容,相比 jsx 定义会获得更好的渲染性能 | { label, value }[] | - | |
|
||||
| optionFilterProp | 搜索时过滤对应的 option 属性,如设置为 children 表示对内嵌内容进行搜索。[示例](https://codesandbox.io/s/antd-reproduction-template-tk678) | string | `value` | |
|
||||
| optionLabelProp | 回填到选择框的 Option 的属性值,默认是 Option 的子元素。比如在子元素需要高亮效果时,此值可以设为 `value` | string | `children` | |
|
||||
| placeholder | 选择框默认文字 | string | - | |
|
||||
| showArrow | 是否显示下拉小箭头 | boolean | 单选为 true,多选为 false | |
|
||||
| showSearch | 使单选模式可搜索 | boolean | false | |
|
||||
| size | 选择框大小 | `large` \| `middle` \| `small` | - | |
|
||||
| suffixIcon | 自定义的选择框后缀图标 | ReactNode | - | |
|
||||
| removeIcon | 自定义的多选框清除图标 | ReactNode | - | |
|
||||
| clearIcon | 自定义的多选框清空图标 | ReactNode | - | |
|
||||
| menuItemSelectedIcon | 自定义多选时当前选中的条目图标 | ReactNode | - | |
|
||||
| tokenSeparators | 在 tags 和 multiple 模式下自动分词的分隔符 | string\[] | - | |
|
||||
| value | 指定当前选中的条目 | string \| string\[]<br />number \| number\[]<br />LabeledValue \| LabeledValue[] | - | |
|
||||
| virtual | 设置 false 时关闭虚拟滚动 | boolean | true | 4.1.0 |
|
||||
| onBlur | 失去焦点时回调 | function | - | |
|
||||
| onChange | 选中 option,或 input 的 value 变化时,调用此函数 | function(value, option:Option \| Array<Option>) | - | |
|
||||
| onClear | 清除内容时回调 | function | - | 4.6.0 |
|
||||
| onDeselect | 取消选中时调用,参数为选中项的 value (或 key) 值,仅在 multiple 或 tags 模式下生效 | function(string \| number \| LabeledValue) | - | |
|
||||
| onDeselect | 取消选中时调用,参数为选中项的 value (或 key) 值,仅在 `multiple` 或 `tags` 模式下生效 | function(string \| number \| LabeledValue) | - | |
|
||||
| onDropdownVisibleChange | 展开下拉菜单的回调 | function(open) | - | |
|
||||
| onFocus | 获得焦点时回调 | function | - | |
|
||||
| onInputKeyDown | 按键按下时回调 | function | - | |
|
||||
| onMouseEnter | 鼠标移入时回调 | function | - | |
|
||||
@@ -70,11 +61,20 @@ cover: https://gw.alipayobjects.com/zos/alicdn/_0XzgOis7/Select.svg
|
||||
| onPopupScroll | 下拉列表滚动时的回调 | function | - | |
|
||||
| onSearch | 文本框值变化时回调 | function(value: string) | - | |
|
||||
| onSelect | 被选中时调用,参数为选中项的 value (或 key) 值 | function(string \| number \| LabeledValue, option: Option) | - | |
|
||||
| defaultOpen | 是否默认展开下拉菜单 | boolean | - | |
|
||||
| open | 是否展开下拉菜单 | boolean | - | |
|
||||
| onDropdownVisibleChange | 展开下拉菜单的回调 | function(open) | - | |
|
||||
| loading | 加载中状态 | boolean | false | |
|
||||
| bordered | 是否有边框 | boolean | true | |
|
||||
| options | 数据化配置选项内容,相比 jsx 定义会获得更好的渲染性能 | { label, value }[] | - | |
|
||||
| optionFilterProp | 搜索时过滤对应的 option 属性,如设置为 children 表示对内嵌内容进行搜索。[示例](https://codesandbox.io/s/antd-reproduction-template-tk678) | string | `value` | |
|
||||
| optionLabelProp | 回填到选择框的 Option 的属性值,默认是 Option 的子元素。比如在子元素需要高亮效果时,此值可以设为 `value` | string | `children` | |
|
||||
| placeholder | 选择框默认文字 | string | - | |
|
||||
| removeIcon | 自定义的多选框清除图标 | ReactNode | - | |
|
||||
| showArrow | 是否显示下拉小箭头 | boolean | 单选为 true,多选为 false | |
|
||||
| showSearch | 使单选模式可搜索 | boolean | false | |
|
||||
| size | 选择框大小 | `large` \| `middle` \| `small` | - | |
|
||||
| suffixIcon | 自定义的选择框后缀图标 | ReactNode | - | |
|
||||
| tagRender | 自定义 tag 内容 render | (props) => ReactNode | - | |
|
||||
| tokenSeparators | 在 `tags` 和 `multiple` 模式下自动分词的分隔符 | string\[] | - | |
|
||||
| value | 指定当前选中的条目 | string \| string\[]<br />number \| number\[]<br />LabeledValue \| LabeledValue[] | - | |
|
||||
| virtual | 设置 false 时关闭虚拟滚动 | boolean | true | 4.1.0 |
|
||||
|
||||
> 注意,如果发现下拉菜单跟随页面滚动,或者需要在其他弹层中触发 Select,请尝试使用 `getPopupContainer={triggerNode => triggerNode.parentElement}` 将下拉弹层渲染节点固定在触发器的父元素中。
|
||||
|
||||
@@ -89,10 +89,10 @@ cover: https://gw.alipayobjects.com/zos/alicdn/_0XzgOis7/Select.svg
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|
||||
| --------- | --------------------------------- | ---------------- | ------ | ---- |
|
||||
| className | Option 器类名 | string | - | |
|
||||
| disabled | 是否禁用 | boolean | false | |
|
||||
| title | 选中该 Option 后,Select 的 title | string | - | |
|
||||
| value | 默认根据此属性值进行筛选 | string \| number | - | |
|
||||
| className | Option 器类名 | string | - | |
|
||||
|
||||
### OptGroup props
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
.@{select-prefix-cls}-focused&:not(.@{select-prefix-cls}-disabled&) {
|
||||
.@{select-prefix-cls}-focused:not(.@{select-prefix-cls}-disabled)& {
|
||||
.active();
|
||||
}
|
||||
|
||||
|
||||
@@ -957,7 +957,7 @@ exports[`renders ./components/slider/demo/show-tooltip.md correctly 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="ant-tooltip ant-slider-tooltip"
|
||||
style="opacity:0"
|
||||
style="opacity:0;pointer-events:none"
|
||||
>
|
||||
<div
|
||||
class="ant-tooltip-content"
|
||||
|
||||
@@ -57,7 +57,7 @@ exports[`Slider should render in RTL direction 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="ant-tooltip ant-slider-tooltip ant-tooltip-rtl"
|
||||
style="opacity:0"
|
||||
style="opacity:0;pointer-events:none"
|
||||
>
|
||||
<div
|
||||
class="ant-tooltip-content"
|
||||
@@ -88,7 +88,7 @@ exports[`Slider should show correct placement tooltip when set tooltipPlacement
|
||||
<div>
|
||||
<div
|
||||
class="ant-tooltip ant-slider-tooltip"
|
||||
style="opacity:0"
|
||||
style="opacity:0;pointer-events:none"
|
||||
>
|
||||
<div
|
||||
class="ant-tooltip-content"
|
||||
@@ -141,7 +141,7 @@ exports[`Slider should show tooltip when hovering slider handler 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="ant-tooltip ant-slider-tooltip"
|
||||
style="opacity:0"
|
||||
style="opacity:0;pointer-events:none"
|
||||
>
|
||||
<div
|
||||
class="ant-tooltip-content"
|
||||
|
||||
49
components/space/Item.tsx
Normal file
49
components/space/Item.tsx
Normal file
@@ -0,0 +1,49 @@
|
||||
import * as React from 'react';
|
||||
import { LastIndexContext } from '.';
|
||||
import { SizeType } from '../config-provider/SizeContext';
|
||||
|
||||
const spaceSize = {
|
||||
small: 8,
|
||||
middle: 16,
|
||||
large: 24,
|
||||
};
|
||||
|
||||
export interface ItemProps {
|
||||
className: string;
|
||||
children: React.ReactNode;
|
||||
index: number;
|
||||
direction?: 'horizontal' | 'vertical';
|
||||
size?: SizeType | number;
|
||||
marginDirection: 'marginLeft' | 'marginRight';
|
||||
}
|
||||
|
||||
export default function Item({
|
||||
className,
|
||||
direction,
|
||||
index,
|
||||
size,
|
||||
marginDirection,
|
||||
children,
|
||||
}: ItemProps) {
|
||||
const latestIndex = React.useContext(LastIndexContext);
|
||||
|
||||
if (children === null || children === undefined) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
className={className}
|
||||
style={
|
||||
index >= latestIndex
|
||||
? {}
|
||||
: {
|
||||
[direction === 'vertical' ? 'marginBottom' : marginDirection]:
|
||||
typeof size === 'string' ? spaceSize[size] : size,
|
||||
}
|
||||
}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -395,12 +395,6 @@ exports[`renders ./components/space/demo/debug.md correctly 1`] = `
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
/>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
/>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-right:8px"
|
||||
|
||||
@@ -43,8 +43,8 @@ describe('Space', () => {
|
||||
</Space>,
|
||||
);
|
||||
|
||||
expect(wrapper.find('.ant-space-item').at(0).prop('style').marginRight).toBe(10);
|
||||
expect(wrapper.find('.ant-space-item').at(1).prop('style').marginRight).toBeUndefined();
|
||||
expect(wrapper.find('div.ant-space-item').at(0).prop('style').marginRight).toBe(10);
|
||||
expect(wrapper.find('div.ant-space-item').at(1).prop('style').marginRight).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should render vertical space width customize size', () => {
|
||||
@@ -55,8 +55,8 @@ describe('Space', () => {
|
||||
</Space>,
|
||||
);
|
||||
|
||||
expect(wrapper.find('.ant-space-item').at(0).prop('style').marginBottom).toBe(10);
|
||||
expect(wrapper.find('.ant-space-item').at(1).prop('style').marginBottom).toBeUndefined();
|
||||
expect(wrapper.find('div.ant-space-item').at(0).prop('style').marginBottom).toBe(10);
|
||||
expect(wrapper.find('div.ant-space-item').at(1).prop('style').marginBottom).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should render correct with children', () => {
|
||||
@@ -78,7 +78,7 @@ describe('Space', () => {
|
||||
</Space>,
|
||||
);
|
||||
|
||||
expect(wrapper.find('.ant-space-item').length).toBe(3);
|
||||
expect(wrapper.find('div.ant-space-item').length).toBe(3);
|
||||
});
|
||||
|
||||
it('should be keep store', () => {
|
||||
|
||||
@@ -19,8 +19,10 @@ import { Space, Button, Popconfirm } from 'antd';
|
||||
|
||||
ReactDOM.render(
|
||||
<Space>
|
||||
Button
|
||||
<Button>Button</Button>
|
||||
<>
|
||||
Button
|
||||
<Button>Button</Button>
|
||||
</>
|
||||
Button
|
||||
<Popconfirm title="Are you sure delete this task?" okText="Yes" cancelText="No">
|
||||
<Button>Delete</Button>
|
||||
@@ -32,6 +34,8 @@ ReactDOM.render(
|
||||
{false}
|
||||
{1}
|
||||
Button
|
||||
{null}
|
||||
{undefined}
|
||||
</Space>,
|
||||
mountNode,
|
||||
);
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
import * as React from 'react';
|
||||
import classNames from 'classnames';
|
||||
import toArray from 'rc-util/lib/Children/toArray';
|
||||
import { ConfigConsumerProps, ConfigContext } from '../config-provider';
|
||||
import { SizeType } from '../config-provider/SizeContext';
|
||||
import Item from './Item';
|
||||
|
||||
export const LastIndexContext = React.createContext(0);
|
||||
|
||||
export interface SpaceProps {
|
||||
prefixCls?: string;
|
||||
@@ -13,12 +17,6 @@ export interface SpaceProps {
|
||||
align?: 'start' | 'end' | 'center' | 'baseline';
|
||||
}
|
||||
|
||||
const spaceSize = {
|
||||
small: 8,
|
||||
middle: 16,
|
||||
large: 24,
|
||||
};
|
||||
|
||||
const Space: React.FC<SpaceProps> = props => {
|
||||
const { getPrefixCls, space, direction: directionConfig }: ConfigConsumerProps = React.useContext(
|
||||
ConfigContext,
|
||||
@@ -34,9 +32,9 @@ const Space: React.FC<SpaceProps> = props => {
|
||||
...otherProps
|
||||
} = props;
|
||||
|
||||
const len = React.Children.count(children);
|
||||
const childNodes = toArray(children, { keepEmpty: true });
|
||||
|
||||
if (len === 0) {
|
||||
if (childNodes.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -56,25 +54,32 @@ const Space: React.FC<SpaceProps> = props => {
|
||||
|
||||
const marginDirection = directionConfig === 'rtl' ? 'marginLeft' : 'marginRight';
|
||||
|
||||
// Calculate latest one
|
||||
let latestIndex = 0;
|
||||
const nodes = childNodes.map((child, i) => {
|
||||
if (child !== null && child !== undefined) {
|
||||
latestIndex = i;
|
||||
}
|
||||
|
||||
/* eslint-disable react/no-array-index-key */
|
||||
return (
|
||||
<Item
|
||||
className={itemClassName}
|
||||
key={`${itemClassName}-${i}`}
|
||||
direction={direction}
|
||||
size={size}
|
||||
index={i}
|
||||
marginDirection={marginDirection}
|
||||
>
|
||||
{child}
|
||||
</Item>
|
||||
);
|
||||
/* eslint-enable */
|
||||
});
|
||||
|
||||
return (
|
||||
<div className={cn} {...otherProps}>
|
||||
{React.Children.map(children, (child, i) => (
|
||||
<div
|
||||
className={itemClassName}
|
||||
// eslint-disable-next-line react/no-array-index-key
|
||||
key={`${itemClassName}-${i}`}
|
||||
style={
|
||||
i === len - 1 || child === null || child === undefined
|
||||
? {}
|
||||
: {
|
||||
[direction === 'vertical' ? 'marginBottom' : marginDirection]:
|
||||
typeof size === 'string' ? spaceSize[size] : size,
|
||||
}
|
||||
}
|
||||
>
|
||||
{child}
|
||||
</div>
|
||||
))}
|
||||
<LastIndexContext.Provider value={latestIndex}>{nodes}</LastIndexContext.Provider>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -420,7 +420,7 @@ function Table<RecordType extends object = any>(props: TableProps<RecordType>) {
|
||||
|
||||
let topPaginationNode: React.ReactNode;
|
||||
let bottomPaginationNode: React.ReactNode;
|
||||
if (pagination !== false) {
|
||||
if (pagination !== false && mergedPagination?.total) {
|
||||
let paginationSize: TablePaginationConfig['size'];
|
||||
if (mergedPagination.size) {
|
||||
paginationSize = mergedPagination.size;
|
||||
@@ -495,7 +495,7 @@ function Table<RecordType extends object = any>(props: TableProps<RecordType>) {
|
||||
internalRefs={internalRefs as any}
|
||||
transformColumns={transformColumns}
|
||||
/>
|
||||
{mergedData && mergedData.length > 0 && bottomPaginationNode}
|
||||
{bottomPaginationNode}
|
||||
</Spin>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -378,39 +378,24 @@ describe('Table.pagination', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('should render pagination after last item on last page being removed with async mode', () => {
|
||||
const lastPageNum = data.length;
|
||||
it('should render pagination after last item on last page being removed', () => {
|
||||
const total = data.length;
|
||||
const paginationProp = {
|
||||
pageSize: 1,
|
||||
total,
|
||||
current: total,
|
||||
position: ['topLeft', 'bottomLeft'],
|
||||
};
|
||||
const wrapper = mount(
|
||||
createTable({ pagination: { pageSize: 1, total: data.length, current: lastPageNum } }),
|
||||
createTable({
|
||||
pagination: paginationProp,
|
||||
}),
|
||||
);
|
||||
|
||||
const newCol = [
|
||||
{
|
||||
title: 'Name',
|
||||
dataIndex: 'name',
|
||||
},
|
||||
{
|
||||
title: 'Action',
|
||||
dataIndex: 'name',
|
||||
render(_, record) {
|
||||
const deleteRow = () => {
|
||||
const newData = data.filter(d => d.key !== record.key);
|
||||
wrapper.setProps({
|
||||
dataSource: newData,
|
||||
pagination: { pageSize: 1, total: newData.length, current: lastPageNum },
|
||||
});
|
||||
};
|
||||
return (
|
||||
<span className="btn-delete" onClick={deleteRow}>
|
||||
Delete
|
||||
</span>
|
||||
);
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
wrapper.setProps({ columns: newCol });
|
||||
wrapper.find('.btn-delete').simulate('click');
|
||||
expect(wrapper.find('.ant-pagination')).toHaveLength(1);
|
||||
wrapper.setProps({
|
||||
dataSource: data.slice(total - 1),
|
||||
pagination: { ...paginationProp, total: total - 1 },
|
||||
});
|
||||
expect(wrapper.find('.ant-pagination')).toHaveLength(2);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -226,7 +226,7 @@ exports[`Table.filter renders custom filter icon with right Tooltip title 1`] =
|
||||
<div>
|
||||
<div
|
||||
class="ant-tooltip"
|
||||
style="opacity: 0;"
|
||||
style="opacity: 0; pointer-events: none;"
|
||||
>
|
||||
<div
|
||||
class="ant-tooltip-content"
|
||||
@@ -709,7 +709,7 @@ exports[`Table.filter should support getPopupContainer 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="ant-dropdown"
|
||||
style="opacity: 0;"
|
||||
style="opacity: 0; pointer-events: none;"
|
||||
>
|
||||
<div
|
||||
class="ant-table-filter-dropdown"
|
||||
@@ -942,7 +942,7 @@ exports[`Table.filter should support getPopupContainer from ConfigProvider 1`] =
|
||||
<div>
|
||||
<div
|
||||
class="ant-dropdown"
|
||||
style="opacity: 0;"
|
||||
style="opacity: 0; pointer-events: none;"
|
||||
>
|
||||
<div
|
||||
class="ant-table-filter-dropdown"
|
||||
|
||||
@@ -1038,7 +1038,7 @@ exports[`Table.rowSelection should support getPopupContainer 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="ant-dropdown"
|
||||
style="opacity: 0;"
|
||||
style="opacity: 0; pointer-events: none;"
|
||||
>
|
||||
<ul
|
||||
class="ant-dropdown-menu ant-dropdown-menu-light ant-dropdown-menu-root ant-dropdown-menu-vertical"
|
||||
@@ -1368,7 +1368,7 @@ exports[`Table.rowSelection should support getPopupContainer from ConfigProvider
|
||||
<div>
|
||||
<div
|
||||
class="ant-dropdown"
|
||||
style="opacity: 0;"
|
||||
style="opacity: 0; pointer-events: none;"
|
||||
>
|
||||
<ul
|
||||
class="ant-dropdown-menu ant-dropdown-menu-light ant-dropdown-menu-root ant-dropdown-menu-vertical"
|
||||
|
||||
@@ -16978,9 +16978,28 @@ exports[`renders ./components/table/demo/virtual-list.md correctly 1`] = `
|
||||
style="overflow:hidden"
|
||||
>
|
||||
<table
|
||||
style="table-layout:fixed;visibility:hidden"
|
||||
style="table-layout:fixed"
|
||||
>
|
||||
<colgroup />
|
||||
<colgroup>
|
||||
<col
|
||||
style="width:150px;min-width:150px"
|
||||
/>
|
||||
<col
|
||||
style="width:0;min-width:0"
|
||||
/>
|
||||
<col
|
||||
style="width:0;min-width:0"
|
||||
/>
|
||||
<col
|
||||
style="width:0;min-width:0"
|
||||
/>
|
||||
<col
|
||||
style="width:200px;min-width:200px"
|
||||
/>
|
||||
<col
|
||||
style="width:100px;min-width:100px"
|
||||
/>
|
||||
</colgroup>
|
||||
<thead
|
||||
class="ant-table-thead"
|
||||
>
|
||||
|
||||
@@ -172,6 +172,7 @@ Properties for expandable.
|
||||
| defaultExpandedRowKeys | Initial expanded row keys | string\[] | - |
|
||||
| expandIcon | Customize row expand Icon. Ref [example](https://codesandbox.io/s/fervent-bird-nuzpr) | function(props): ReactNode | - |
|
||||
| expandIconColumnIndex | Customize expand icon column index. Not render when `-1` | number | - |
|
||||
| expandedRowClassName | Expanded row's className | function(record, index, indent): string | - |
|
||||
| expandedRowKeys | Current expanded row keys | string\[] | - |
|
||||
| expandedRowRender | Expanded container render for each row | function(record, index, indent, expanded): ReactNode | - |
|
||||
| expandRowByClick | Whether to expand row by clicking anywhere in the whole row | boolean | false |
|
||||
|
||||
@@ -179,6 +179,7 @@ const columns = [
|
||||
| defaultExpandedRowKeys | 默认展开的行 | string\[] | - |
|
||||
| expandIcon | 自定义展开图标,参考[示例](https://codesandbox.io/s/fervent-bird-nuzpr) | function(props): ReactNode | - |
|
||||
| expandIconColumnIndex | 自定义展开按钮的列顺序,`-1` 时不展示 | number | - |
|
||||
| expandedRowClassName | 展开行的 className | function(record, index, indent): string | - |
|
||||
| expandedRowKeys | 展开的行,控制属性 | string\[] | - |
|
||||
| expandedRowRender | 额外的展开行 | function(record, index, indent, expanded): ReactNode | - |
|
||||
| expandRowByClick | 通过点击行来展开子行 | boolean | false |
|
||||
|
||||
@@ -412,12 +412,13 @@
|
||||
float: left;
|
||||
box-sizing: border-box;
|
||||
|
||||
width: ceil(@font-size-sm * 1.4);
|
||||
height: ceil(@font-size-sm * 1.4);
|
||||
width: ceil((@font-size-sm * 1.4 - @border-width-base * 3) / 2) * 2 + @border-width-base * 3;
|
||||
height: ceil((@font-size-sm * 1.4 - @border-width-base * 3) / 2) * 2 + @border-width-base * 3;
|
||||
padding: 0;
|
||||
color: inherit;
|
||||
line-height: @font-size-sm;
|
||||
vertical-align: floor((@font-size-base - ceil(@font-size-sm * 1.4)) / 2);
|
||||
line-height: ceil((@font-size-sm * 1.4 - @border-width-base * 3) / 2) * 2 + @border-width-base *
|
||||
3;
|
||||
// vertical-align: floor((@font-size-base - ceil(@font-size-sm * 1.4)) / 2);
|
||||
background: @table-expand-icon-bg;
|
||||
border: @border-width-base @border-style-base @border-color-split;
|
||||
border-radius: @border-radius-base;
|
||||
@@ -440,7 +441,7 @@
|
||||
}
|
||||
|
||||
&::before {
|
||||
top: 7px;
|
||||
top: ceil((@font-size-sm * 1.4 - @border-width-base * 3) / 2);
|
||||
right: 3px;
|
||||
left: 3px;
|
||||
height: @border-width-base;
|
||||
@@ -449,7 +450,7 @@
|
||||
&::after {
|
||||
top: 3px;
|
||||
bottom: 3px;
|
||||
left: 7px;
|
||||
left: ceil((@font-size-sm * 1.4 - @border-width-base * 3) / 2);
|
||||
width: @border-width-base;
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
@@ -474,7 +475,8 @@
|
||||
}
|
||||
|
||||
.@{table-prefix-cls}-row-indent + & {
|
||||
margin-top: (@font-size-base * @line-height-base - ceil(@font-size-sm * 1.4)) / 2;
|
||||
margin-top: (@font-size-base * @line-height-base - @border-width-base * 3) / 2 -
|
||||
ceil((@font-size-sm * 1.4 - @border-width-base * 3) / 2);
|
||||
margin-right: @padding-xs;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,16 +30,16 @@ const OperationsSlot = {
|
||||
const options = ['left', 'right'];
|
||||
|
||||
const Demo = () => {
|
||||
const [positon, setPosition] = React.useState(['left', 'right']);
|
||||
const [position, setPosition] = React.useState(['left', 'right']);
|
||||
|
||||
const slot = React.useMemo(() => {
|
||||
if (positon.length === 0) return null;
|
||||
if (position.length === 0) return null;
|
||||
|
||||
return positon.reduce(
|
||||
(acc, direaction) => ({ ...acc, [direaction]: OperationsSlot[direaction] }),
|
||||
return position.reduce(
|
||||
(acc, direction) => ({ ...acc, [direction]: OperationsSlot[direction] }),
|
||||
{},
|
||||
);
|
||||
}, [positon]);
|
||||
}, [position]);
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -61,7 +61,7 @@ const Demo = () => {
|
||||
<Divider />
|
||||
<CheckboxGroup
|
||||
options={options}
|
||||
value={positon}
|
||||
value={position}
|
||||
onChange={value => {
|
||||
setPosition(value);
|
||||
}}
|
||||
|
||||
@@ -118,7 +118,7 @@ Array [
|
||||
<div>
|
||||
<div
|
||||
class="ant-picker-dropdown"
|
||||
style="opacity: 0;"
|
||||
style="opacity: 0; pointer-events: none;"
|
||||
>
|
||||
<div
|
||||
class="ant-picker-panel-container"
|
||||
|
||||
10
components/time-picker/__tests__/type.test.tsx
Normal file
10
components/time-picker/__tests__/type.test.tsx
Normal file
@@ -0,0 +1,10 @@
|
||||
import * as React from 'react';
|
||||
import TimePicker from '..';
|
||||
|
||||
describe('TimePicker.typescript', () => {
|
||||
it('No need picker props', () => {
|
||||
const rangePicker = <TimePicker.RangePicker />;
|
||||
|
||||
expect(rangePicker).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -12,7 +12,7 @@ export interface TimePickerLocale {
|
||||
rangePlaceholder?: [string, string];
|
||||
}
|
||||
|
||||
export interface TimeRangePickerProps extends RangePickerTimeProps<Moment> {}
|
||||
export interface TimeRangePickerProps extends Omit<RangePickerTimeProps<Moment>, 'picker'> {}
|
||||
|
||||
const RangePicker = React.forwardRef<any, TimeRangePickerProps>((props, ref) => {
|
||||
return <InternalRangePicker {...props} picker="time" mode={undefined} ref={ref} />;
|
||||
|
||||
@@ -34,7 +34,7 @@ exports[`TreeSelect TreeSelect Custom Icons should \`treeIcon\` work 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="ant-select-dropdown ant-tree-select-dropdown"
|
||||
style="opacity: 0; min-width: 0; width: 0px;"
|
||||
style="opacity: 0; pointer-events: none; min-width: 0; width: 0px;"
|
||||
>
|
||||
<div>
|
||||
<div>
|
||||
|
||||
@@ -45,4 +45,9 @@ describe('TreeSelect', () => {
|
||||
expect(wrapper.render()).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
it('should support notFoundContent', () => {
|
||||
const wrapper = mount(<TreeSelect treeIcon open notFoundContent="notFoundContent" />);
|
||||
expect(wrapper.text()).toBe('notFoundContent');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -35,12 +35,10 @@
|
||||
}
|
||||
}
|
||||
|
||||
// ========================== Tree ==========================
|
||||
.antTreeFn(@select-tree-prefix-cls);
|
||||
|
||||
// change switcher icon rotation in rtl direction
|
||||
.@{select-tree-prefix-cls} {
|
||||
// >>> Switcher
|
||||
.antTreeFn(@select-tree-prefix-cls);
|
||||
|
||||
// change switcher icon rotation in rtl direction
|
||||
& &-switcher {
|
||||
&_close {
|
||||
.@{select-tree-prefix-cls}-switcher-icon {
|
||||
|
||||
@@ -17,7 +17,7 @@ Almost anything can be represented in a tree structure. Examples include directo
|
||||
|
||||
| Property | Description | Type | Default | Version |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| autoExpandParent | Whether to automatically expand a parent treeNode | boolean | true | |
|
||||
| autoExpandParent | Whether to automatically expand a parent treeNode | boolean | false | |
|
||||
| blockNode | Whether treeNode fill remaining horizontal space | boolean | false | |
|
||||
| checkable | Add a Checkbox before the treeNodes | boolean | false | |
|
||||
| checkedKeys | (Controlled) Specifies the keys of the checked treeNodes (PS: When this specifies the key of a treeNode which is also a parent treeNode, all the children treeNodes of will be checked; and vice versa, when it specifies the key of a treeNode which is a child treeNode, its parent treeNode will also be checked. When `checkable` and `checkStrictly` is true, its object has `checked` and `halfChecked` property. Regardless of whether the child or parent treeNode is checked, they won't impact each other | string\[] \| {checked: string\[], halfChecked: string\[]} | \[] | |
|
||||
|
||||
@@ -18,7 +18,7 @@ cover: https://gw.alipayobjects.com/zos/alicdn/Xh-oWqg9k/Tree.svg
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| autoExpandParent | 是否自动展开父节点 | boolean | true | |
|
||||
| autoExpandParent | 是否自动展开父节点 | boolean | false | |
|
||||
| blockNode | 是否节点占据一行 | boolean | false | |
|
||||
| checkable | 节点前添加 Checkbox 复选框 | boolean | false | |
|
||||
| checkedKeys | (受控)选中复选框的树节点(注意:父子节点有关联,如果传入父节点 key,则子节点自动选中;相应当子节点 key 都传入,父节点也自动选中。当设置`checkable`和`checkStrictly`,它是一个有`checked`和`halfChecked`属性的对象,并且父子节点的选中与否不再关联 | string\[] \| {checked: string\[], halfChecked: string\[]} | \[] | |
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
|
||||
.antCheckboxFn(@checkbox-prefix-cls: ~'@{ant-prefix}-tree-checkbox');
|
||||
|
||||
.antTreeFn(@tree-prefix-cls);
|
||||
.@{tree-prefix-cls} {
|
||||
.antTreeFn(@tree-prefix-cls);
|
||||
}
|
||||
|
||||
@import './rtl';
|
||||
|
||||
@@ -31,233 +31,231 @@
|
||||
|
||||
.antTreeFn(@custom-tree-prefix-cls) {
|
||||
@custom-tree-node-prefix-cls: ~'@{custom-tree-prefix-cls}-treenode';
|
||||
.@{custom-tree-prefix-cls} {
|
||||
.reset-component;
|
||||
background: @tree-bg;
|
||||
.reset-component;
|
||||
background: @tree-bg;
|
||||
border-radius: @border-radius-base;
|
||||
transition: background-color 0.3s;
|
||||
|
||||
&-focused:not(:hover):not(&-active-focused) {
|
||||
background: @primary-1;
|
||||
}
|
||||
|
||||
// =================== Virtual List ===================
|
||||
&-list-holder-inner {
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
&.@{custom-tree-prefix-cls}-block-node {
|
||||
.@{custom-tree-prefix-cls}-list-holder-inner {
|
||||
align-items: stretch;
|
||||
|
||||
// >>> Title
|
||||
.@{custom-tree-prefix-cls}-node-content-wrapper {
|
||||
flex: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ===================== TreeNode =====================
|
||||
.@{custom-tree-node-prefix-cls} {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
padding: 0 0 (@padding-xs / 2) 0;
|
||||
outline: none;
|
||||
// Disabled
|
||||
&-disabled {
|
||||
// >>> Title
|
||||
.@{custom-tree-prefix-cls}-node-content-wrapper {
|
||||
color: @disabled-color;
|
||||
cursor: not-allowed;
|
||||
|
||||
&:hover {
|
||||
background: transparent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-active .@{custom-tree-prefix-cls}-node-content-wrapper {
|
||||
background: @tree-node-hover-bg;
|
||||
}
|
||||
}
|
||||
|
||||
// >>> Indent
|
||||
&-indent {
|
||||
align-self: stretch;
|
||||
white-space: nowrap;
|
||||
user-select: none;
|
||||
|
||||
&-unit {
|
||||
display: inline-block;
|
||||
width: @tree-title-height;
|
||||
}
|
||||
}
|
||||
|
||||
// >>> Switcher
|
||||
& &-switcher {
|
||||
.antTreeSwitcherIcon();
|
||||
flex: none;
|
||||
|
||||
width: @tree-title-height;
|
||||
height: @tree-title-height;
|
||||
margin: 0;
|
||||
line-height: @tree-title-height;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
|
||||
&-noop {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
&_close {
|
||||
.@{custom-tree-prefix-cls}-switcher-icon {
|
||||
svg {
|
||||
transform: rotate(-90deg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-loading-icon {
|
||||
color: @primary-color;
|
||||
}
|
||||
|
||||
&-leaf-line {
|
||||
z-index: 1;
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
&::before {
|
||||
position: absolute;
|
||||
height: @tree-title-height;
|
||||
margin-left: -1px;
|
||||
border-left: 1px solid @normal-color;
|
||||
content: ' ';
|
||||
}
|
||||
&::after {
|
||||
position: absolute;
|
||||
width: @tree-title-height - 14px;
|
||||
height: @tree-title-height - 10px;
|
||||
margin-left: -1px;
|
||||
border-bottom: 1px solid @normal-color;
|
||||
content: ' ';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// >>> Checkbox
|
||||
& &-checkbox {
|
||||
top: initial;
|
||||
margin: ((@tree-title-height - @checkbox-size) / 2) 8px 0 0;
|
||||
}
|
||||
|
||||
// >>> Title
|
||||
& &-node-content-wrapper {
|
||||
min-height: @tree-title-height;
|
||||
margin: 0;
|
||||
padding: 0 4px;
|
||||
color: inherit;
|
||||
line-height: @tree-title-height;
|
||||
background: transparent;
|
||||
border-radius: @border-radius-base;
|
||||
transition: background-color 0.3s;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s, border 0s, line-height 0s;
|
||||
|
||||
&-focused:not(:hover):not(&-active-focused) {
|
||||
background: @primary-1;
|
||||
&:hover {
|
||||
background-color: @tree-node-hover-bg;
|
||||
}
|
||||
|
||||
// =================== Virtual List ===================
|
||||
&-list-holder-inner {
|
||||
align-items: flex-start;
|
||||
&.@{custom-tree-prefix-cls}-node-selected {
|
||||
background-color: @tree-node-selected-bg;
|
||||
}
|
||||
|
||||
&.@{custom-tree-prefix-cls}-block-node {
|
||||
.@{custom-tree-prefix-cls}-list-holder-inner {
|
||||
align-items: stretch;
|
||||
|
||||
// >>> Title
|
||||
.@{custom-tree-prefix-cls}-node-content-wrapper {
|
||||
flex: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ===================== TreeNode =====================
|
||||
.@{custom-tree-node-prefix-cls} {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
padding: 0 0 (@padding-xs / 2) 0;
|
||||
outline: none;
|
||||
// Disabled
|
||||
&-disabled {
|
||||
// >>> Title
|
||||
.@{custom-tree-prefix-cls}-node-content-wrapper {
|
||||
color: @disabled-color;
|
||||
cursor: not-allowed;
|
||||
|
||||
&:hover {
|
||||
background: transparent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-active .@{custom-tree-prefix-cls}-node-content-wrapper {
|
||||
background: @tree-node-hover-bg;
|
||||
}
|
||||
}
|
||||
|
||||
// >>> Indent
|
||||
&-indent {
|
||||
align-self: stretch;
|
||||
white-space: nowrap;
|
||||
user-select: none;
|
||||
|
||||
&-unit {
|
||||
display: inline-block;
|
||||
width: @tree-title-height;
|
||||
}
|
||||
}
|
||||
|
||||
// >>> Switcher
|
||||
& &-switcher {
|
||||
.antTreeSwitcherIcon();
|
||||
flex: none;
|
||||
|
||||
// Icon
|
||||
.@{custom-tree-prefix-cls}-iconEle {
|
||||
display: inline-block;
|
||||
width: @tree-title-height;
|
||||
height: @tree-title-height;
|
||||
margin: 0;
|
||||
line-height: @tree-title-height;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
|
||||
&-noop {
|
||||
cursor: default;
|
||||
vertical-align: top;
|
||||
&:empty {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&_close {
|
||||
.@{custom-tree-prefix-cls}-switcher-icon {
|
||||
svg {
|
||||
transform: rotate(-90deg);
|
||||
}
|
||||
}
|
||||
}
|
||||
// ==================== Draggable =====================
|
||||
&-node-content-wrapper[draggable='true'] {
|
||||
line-height: @tree-title-height - 4px;
|
||||
border-top: 2px transparent solid;
|
||||
border-bottom: 2px transparent solid;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
&-loading-icon {
|
||||
color: @primary-color;
|
||||
}
|
||||
.@{custom-tree-node-prefix-cls}.drag-over {
|
||||
> [draggable] {
|
||||
color: white;
|
||||
background-color: @primary-color;
|
||||
opacity: 0.8;
|
||||
}
|
||||
}
|
||||
.@{custom-tree-node-prefix-cls}.drag-over-gap-top {
|
||||
> [draggable] {
|
||||
border-top-color: @primary-color;
|
||||
}
|
||||
}
|
||||
.@{custom-tree-node-prefix-cls}.drag-over-gap-bottom {
|
||||
> [draggable] {
|
||||
border-bottom-color: @primary-color;
|
||||
}
|
||||
}
|
||||
|
||||
&-leaf-line {
|
||||
z-index: 1;
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
// ==================== Show Line =====================
|
||||
&-show-line {
|
||||
// ================ Indent lines ================
|
||||
.@{custom-tree-prefix-cls}-indent {
|
||||
&-unit {
|
||||
position: relative;
|
||||
height: 100%;
|
||||
|
||||
&:first-child::after {
|
||||
position: absolute;
|
||||
top: calc(100% - @tree-title-height - 4px);
|
||||
right: @tree-title-height / 2;
|
||||
bottom: -4px;
|
||||
border-right: 1px solid @border-color-base;
|
||||
content: '';
|
||||
}
|
||||
|
||||
&::before {
|
||||
position: absolute;
|
||||
height: @tree-title-height;
|
||||
margin-left: -1px;
|
||||
border-left: 1px solid @normal-color;
|
||||
content: ' ';
|
||||
top: calc(100% - 4px);
|
||||
right: -@tree-title-height / 2;
|
||||
bottom: -@tree-title-height - 4px;
|
||||
border-right: 1px solid @border-color-base;
|
||||
content: '';
|
||||
}
|
||||
&::after {
|
||||
position: absolute;
|
||||
width: @tree-title-height - 14px;
|
||||
height: @tree-title-height - 10px;
|
||||
margin-left: -1px;
|
||||
border-bottom: 1px solid @normal-color;
|
||||
content: ' ';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// >>> Checkbox
|
||||
& &-checkbox {
|
||||
top: initial;
|
||||
margin: ((@tree-title-height - @checkbox-size) / 2) 8px 0 0;
|
||||
}
|
||||
|
||||
// >>> Title
|
||||
& &-node-content-wrapper {
|
||||
min-height: @tree-title-height;
|
||||
margin: 0;
|
||||
padding: 0 4px;
|
||||
color: inherit;
|
||||
line-height: @tree-title-height;
|
||||
background: transparent;
|
||||
border-radius: @border-radius-base;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
|
||||
&:hover {
|
||||
background-color: @tree-node-hover-bg;
|
||||
}
|
||||
|
||||
&.@{custom-tree-prefix-cls}-node-selected {
|
||||
background-color: @tree-node-selected-bg;
|
||||
}
|
||||
|
||||
// Icon
|
||||
.@{custom-tree-prefix-cls}-iconEle {
|
||||
display: inline-block;
|
||||
width: @tree-title-height;
|
||||
height: @tree-title-height;
|
||||
line-height: @tree-title-height;
|
||||
text-align: center;
|
||||
vertical-align: top;
|
||||
&:empty {
|
||||
&-end::before,
|
||||
&-end-first-level::after {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== Draggable =====================
|
||||
&-node-content-wrapper[draggable='true'] {
|
||||
line-height: @tree-title-height - 4px;
|
||||
border-top: 2px transparent solid;
|
||||
border-bottom: 2px transparent solid;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.@{custom-tree-node-prefix-cls}.drag-over {
|
||||
> [draggable] {
|
||||
color: white;
|
||||
background-color: @primary-color;
|
||||
opacity: 0.8;
|
||||
}
|
||||
}
|
||||
.@{custom-tree-node-prefix-cls}.drag-over-gap-top {
|
||||
> [draggable] {
|
||||
border-top-color: @primary-color;
|
||||
}
|
||||
}
|
||||
.@{custom-tree-node-prefix-cls}.drag-over-gap-bottom {
|
||||
> [draggable] {
|
||||
border-bottom-color: @primary-color;
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== Show Line =====================
|
||||
&-show-line {
|
||||
// ================ Indent lines ================
|
||||
.@{custom-tree-prefix-cls}-indent {
|
||||
&-unit {
|
||||
position: relative;
|
||||
height: 100%;
|
||||
|
||||
&:first-child::after {
|
||||
position: absolute;
|
||||
top: calc(100% - @tree-title-height - 4px);
|
||||
right: @tree-title-height / 2;
|
||||
bottom: -4px;
|
||||
border-right: 1px solid @border-color-base;
|
||||
content: '';
|
||||
}
|
||||
|
||||
&::before {
|
||||
position: absolute;
|
||||
top: calc(100% - 4px);
|
||||
right: -@tree-title-height / 2;
|
||||
bottom: -@tree-title-height - 4px;
|
||||
border-right: 1px solid @border-color-base;
|
||||
content: '';
|
||||
}
|
||||
|
||||
&-end::before,
|
||||
&-end-first-level::after {
|
||||
display: none;
|
||||
}
|
||||
/* Motion should hide line of measure */
|
||||
.@{custom-tree-node-prefix-cls}-motion:not(.@{tree-motion}-leave):not(.@{tree-motion}-appear-active) {
|
||||
.@{custom-tree-prefix-cls}-indent-unit {
|
||||
&::after,
|
||||
&::before {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Motion should hide line of measure */
|
||||
.@{custom-tree-node-prefix-cls}-motion:not(.@{tree-motion}-leave):not(.@{tree-motion}-appear-active) {
|
||||
.@{custom-tree-prefix-cls}-indent-unit {
|
||||
&::after,
|
||||
&::before {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ============== Cover Background ==============
|
||||
.@{custom-tree-prefix-cls}-switcher {
|
||||
z-index: 1;
|
||||
background: @component-background;
|
||||
}
|
||||
// ============== Cover Background ==============
|
||||
.@{custom-tree-prefix-cls}-switcher {
|
||||
z-index: 1;
|
||||
background: @component-background;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import Dragger from './Dragger';
|
||||
import UploadList from './UploadList';
|
||||
import {
|
||||
RcFile,
|
||||
ShowUploadListInterface,
|
||||
UploadProps,
|
||||
UploadFile,
|
||||
UploadLocale,
|
||||
@@ -17,7 +18,6 @@ import LocaleReceiver from '../locale-provider/LocaleReceiver';
|
||||
import defaultLocale from '../locale/default';
|
||||
import { ConfigContext } from '../config-provider';
|
||||
import devWarning from '../_util/devWarning';
|
||||
import useSyncState from '../_util/hooks/useSyncState';
|
||||
import useForceUpdate from '../_util/hooks/useForceUpdate';
|
||||
|
||||
export { UploadProps };
|
||||
@@ -44,15 +44,18 @@ const InternalUpload: React.ForwardRefRenderFunction<unknown, UploadProps> = (pr
|
||||
style,
|
||||
} = props;
|
||||
|
||||
const [getFileList, setFileList] = useSyncState<Array<UploadFile>>(
|
||||
fileListProp || defaultFileList || [],
|
||||
);
|
||||
const [dragState, setDragState] = React.useState<string>('drop');
|
||||
const forceUpdate = useForceUpdate();
|
||||
|
||||
// `fileListRef` used for internal state sync to avoid control mode set it back when sync update.
|
||||
// `visibleFileList` used for display in UploadList instead.
|
||||
// It's a workaround and not the best solution.
|
||||
const fileListRef = React.useRef(fileListProp || defaultFileList || []);
|
||||
const visibleFileList = fileListProp || fileListRef.current;
|
||||
|
||||
const upload = React.useRef<any>();
|
||||
|
||||
React.useEffect(() => {
|
||||
setFileList(fileListProp || defaultFileList || []);
|
||||
devWarning(
|
||||
'fileList' in props || !('value' in props),
|
||||
'Upload',
|
||||
@@ -61,15 +64,15 @@ const InternalUpload: React.ForwardRefRenderFunction<unknown, UploadProps> = (pr
|
||||
}, []);
|
||||
|
||||
React.useEffect(() => {
|
||||
if ('fileList' in props) {
|
||||
setFileList(fileListProp || []);
|
||||
if (fileListProp !== undefined && fileListProp !== fileListRef.current) {
|
||||
fileListRef.current = fileListProp;
|
||||
forceUpdate();
|
||||
}
|
||||
}, [fileListProp]);
|
||||
|
||||
const onChange = (info: UploadChangeParam) => {
|
||||
if (!('fileList' in props)) {
|
||||
setFileList(info.fileList);
|
||||
}
|
||||
fileListRef.current = info.fileList;
|
||||
forceUpdate();
|
||||
|
||||
const { onChange: onChangeProp } = props;
|
||||
if (onChangeProp) {
|
||||
@@ -84,7 +87,7 @@ const InternalUpload: React.ForwardRefRenderFunction<unknown, UploadProps> = (pr
|
||||
const targetItem = fileToObject(file);
|
||||
targetItem.status = 'uploading';
|
||||
|
||||
const nextFileList = getFileList().concat();
|
||||
const nextFileList = fileListRef.current.concat();
|
||||
|
||||
const fileIndex = nextFileList.findIndex(({ uid }: UploadFile) => uid === targetItem.uid);
|
||||
if (fileIndex === -1) {
|
||||
@@ -107,7 +110,7 @@ const InternalUpload: React.ForwardRefRenderFunction<unknown, UploadProps> = (pr
|
||||
} catch (e) {
|
||||
/* do nothing */
|
||||
}
|
||||
const targetItem = getFileItem(file, getFileList());
|
||||
const targetItem = getFileItem(file, fileListRef.current);
|
||||
// removed
|
||||
if (!targetItem) {
|
||||
return;
|
||||
@@ -117,12 +120,12 @@ const InternalUpload: React.ForwardRefRenderFunction<unknown, UploadProps> = (pr
|
||||
targetItem.xhr = xhr;
|
||||
onChange({
|
||||
file: { ...targetItem },
|
||||
fileList: getFileList().concat(),
|
||||
fileList: fileListRef.current.concat(),
|
||||
});
|
||||
};
|
||||
|
||||
const onProgress = (e: { percent: number }, file: UploadFile) => {
|
||||
const targetItem = getFileItem(file, getFileList());
|
||||
const targetItem = getFileItem(file, fileListRef.current);
|
||||
// removed
|
||||
if (!targetItem) {
|
||||
return;
|
||||
@@ -131,12 +134,12 @@ const InternalUpload: React.ForwardRefRenderFunction<unknown, UploadProps> = (pr
|
||||
onChange({
|
||||
event: e,
|
||||
file: { ...targetItem },
|
||||
fileList: getFileList().concat(),
|
||||
fileList: fileListRef.current.concat(),
|
||||
});
|
||||
};
|
||||
|
||||
const onError = (error: Error, response: any, file: UploadFile) => {
|
||||
const targetItem = getFileItem(file, getFileList());
|
||||
const targetItem = getFileItem(file, fileListRef.current);
|
||||
// removed
|
||||
if (!targetItem) {
|
||||
return;
|
||||
@@ -146,7 +149,7 @@ const InternalUpload: React.ForwardRefRenderFunction<unknown, UploadProps> = (pr
|
||||
targetItem.status = 'error';
|
||||
onChange({
|
||||
file: { ...targetItem },
|
||||
fileList: getFileList().concat(),
|
||||
fileList: fileListRef.current.concat(),
|
||||
});
|
||||
};
|
||||
|
||||
@@ -157,7 +160,7 @@ const InternalUpload: React.ForwardRefRenderFunction<unknown, UploadProps> = (pr
|
||||
return;
|
||||
}
|
||||
|
||||
const removedFileList = removeFileItem(file, getFileList());
|
||||
const removedFileList = removeFileItem(file, fileListRef.current);
|
||||
|
||||
if (removedFileList) {
|
||||
file.status = 'removed';
|
||||
@@ -186,13 +189,11 @@ const InternalUpload: React.ForwardRefRenderFunction<unknown, UploadProps> = (pr
|
||||
if (result === false) {
|
||||
// Get unique file list
|
||||
const uniqueList: UploadFile<any>[] = [];
|
||||
getFileList()
|
||||
.concat(fileListArgs.map(fileToObject))
|
||||
.forEach(f => {
|
||||
if (uniqueList.every(uf => uf.uid !== f.uid)) {
|
||||
uniqueList.push(f);
|
||||
}
|
||||
});
|
||||
fileListRef.current.concat(fileListArgs.map(fileToObject)).forEach(f => {
|
||||
if (uniqueList.every(uf => uf.uid !== f.uid)) {
|
||||
uniqueList.push(f);
|
||||
}
|
||||
});
|
||||
|
||||
onChange({
|
||||
file,
|
||||
@@ -206,46 +207,16 @@ const InternalUpload: React.ForwardRefRenderFunction<unknown, UploadProps> = (pr
|
||||
return true;
|
||||
};
|
||||
// Test needs
|
||||
const forceUpdate = useForceUpdate();
|
||||
React.useImperativeHandle(ref, () => ({
|
||||
onStart,
|
||||
onSuccess,
|
||||
onProgress,
|
||||
onError,
|
||||
fileList: getFileList(),
|
||||
fileList: fileListRef.current,
|
||||
upload: upload.current,
|
||||
forceUpdate,
|
||||
}));
|
||||
|
||||
const renderUploadList = (locale: UploadLocale) => {
|
||||
const {
|
||||
showRemoveIcon,
|
||||
showPreviewIcon,
|
||||
showDownloadIcon,
|
||||
removeIcon,
|
||||
downloadIcon,
|
||||
} = showUploadList as any;
|
||||
return (
|
||||
<UploadList
|
||||
listType={listType}
|
||||
items={getFileList()}
|
||||
previewFile={previewFile}
|
||||
onPreview={onPreview}
|
||||
onDownload={onDownload}
|
||||
onRemove={handleRemove}
|
||||
showRemoveIcon={!disabled && showRemoveIcon}
|
||||
showPreviewIcon={showPreviewIcon}
|
||||
showDownloadIcon={showDownloadIcon}
|
||||
removeIcon={removeIcon}
|
||||
downloadIcon={downloadIcon}
|
||||
iconRender={iconRender}
|
||||
locale={{ ...locale, ...propLocale }}
|
||||
isImageUrl={isImageUrl}
|
||||
progress={progress}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
const { getPrefixCls, direction } = React.useContext(ConfigContext);
|
||||
|
||||
const prefixCls = getPrefixCls('upload', customizePrefixCls);
|
||||
@@ -271,18 +242,46 @@ const InternalUpload: React.ForwardRefRenderFunction<unknown, UploadProps> = (pr
|
||||
delete rcUploadProps.id;
|
||||
}
|
||||
|
||||
const uploadList = showUploadList ? (
|
||||
<LocaleReceiver componentName="Upload" defaultLocale={defaultLocale.Upload}>
|
||||
{renderUploadList}
|
||||
</LocaleReceiver>
|
||||
) : null;
|
||||
const renderUploadList = (button?: React.ReactNode) =>
|
||||
showUploadList ? (
|
||||
<LocaleReceiver componentName="Upload" defaultLocale={defaultLocale.Upload}>
|
||||
{(locale: UploadLocale) => {
|
||||
const { showRemoveIcon, showPreviewIcon, showDownloadIcon, removeIcon, downloadIcon } =
|
||||
typeof showUploadList === 'boolean' ? ({} as ShowUploadListInterface) : showUploadList;
|
||||
return (
|
||||
<UploadList
|
||||
listType={listType}
|
||||
items={visibleFileList}
|
||||
previewFile={previewFile}
|
||||
onPreview={onPreview}
|
||||
onDownload={onDownload}
|
||||
onRemove={handleRemove}
|
||||
showRemoveIcon={!disabled && showRemoveIcon}
|
||||
showPreviewIcon={showPreviewIcon}
|
||||
showDownloadIcon={showDownloadIcon}
|
||||
removeIcon={removeIcon}
|
||||
downloadIcon={downloadIcon}
|
||||
iconRender={iconRender}
|
||||
locale={{ ...locale, ...propLocale }}
|
||||
isImageUrl={isImageUrl}
|
||||
progress={progress}
|
||||
appendAction={button}
|
||||
/>
|
||||
);
|
||||
}}
|
||||
</LocaleReceiver>
|
||||
) : (
|
||||
button
|
||||
);
|
||||
|
||||
if (type === 'drag') {
|
||||
const dragCls = classNames(
|
||||
prefixCls,
|
||||
{
|
||||
[`${prefixCls}-drag`]: true,
|
||||
[`${prefixCls}-drag-uploading`]: getFileList().some(file => file.status === 'uploading'),
|
||||
[`${prefixCls}-drag-uploading`]: fileListRef.current.some(
|
||||
file => file.status === 'uploading',
|
||||
),
|
||||
[`${prefixCls}-drag-hover`]: dragState === 'dragover',
|
||||
[`${prefixCls}-disabled`]: disabled,
|
||||
[`${prefixCls}-rtl`]: direction === 'rtl',
|
||||
@@ -302,7 +301,7 @@ const InternalUpload: React.ForwardRefRenderFunction<unknown, UploadProps> = (pr
|
||||
<div className={`${prefixCls}-drag-container`}>{children}</div>
|
||||
</RcUpload>
|
||||
</div>
|
||||
{uploadList}
|
||||
{renderUploadList()}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
@@ -323,8 +322,7 @@ const InternalUpload: React.ForwardRefRenderFunction<unknown, UploadProps> = (pr
|
||||
if (listType === 'picture-card') {
|
||||
return (
|
||||
<span className={classNames(className, `${prefixCls}-picture-card-wrapper`)}>
|
||||
{uploadList}
|
||||
{uploadButton}
|
||||
{renderUploadList(uploadButton)}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
@@ -332,13 +330,15 @@ const InternalUpload: React.ForwardRefRenderFunction<unknown, UploadProps> = (pr
|
||||
return (
|
||||
<span className={className}>
|
||||
{uploadButton}
|
||||
{uploadList}
|
||||
{renderUploadList()}
|
||||
</span>
|
||||
);
|
||||
};
|
||||
|
||||
interface CompoundedComponent
|
||||
extends React.ForwardRefExoticComponent<UploadProps & React.RefAttributes<any>> {
|
||||
extends React.ForwardRefExoticComponent<
|
||||
React.PropsWithChildren<UploadProps> & React.RefAttributes<any>
|
||||
> {
|
||||
Dragger: typeof Dragger;
|
||||
}
|
||||
|
||||
|
||||
@@ -36,6 +36,7 @@ const InternalUploadList: React.ForwardRefRenderFunction<unknown, UploadListProp
|
||||
removeIcon: customRemoveIcon,
|
||||
downloadIcon: customDownloadIcon,
|
||||
progress: progressProps,
|
||||
appendAction,
|
||||
},
|
||||
ref,
|
||||
) => {
|
||||
@@ -334,13 +335,13 @@ const InternalUploadList: React.ForwardRefRenderFunction<unknown, UploadListProp
|
||||
[`${prefixCls}-list-rtl`]: direction === 'rtl',
|
||||
});
|
||||
const animationDirection = listType === 'picture-card' ? 'animate-inline' : 'animate';
|
||||
const transitionName = list.length === 0 ? '' : `${prefixCls}-${animationDirection}`;
|
||||
return (
|
||||
<Animate
|
||||
transitionName={`${prefixCls}-${animationDirection}`}
|
||||
component="div"
|
||||
className={listClassNames}
|
||||
>
|
||||
<Animate transitionName={transitionName} component="div" className={listClassNames}>
|
||||
{list}
|
||||
{React.isValidElement(appendAction)
|
||||
? React.cloneElement(appendAction, { key: 'appendAction' })
|
||||
: appendAction}
|
||||
</Animate>
|
||||
);
|
||||
};
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -28,7 +28,7 @@ exports[`Upload List handle error 1`] = `
|
||||
class="ant-upload-list ant-upload-list-text"
|
||||
>
|
||||
<div
|
||||
class="ant-upload-animate-enter"
|
||||
class=""
|
||||
>
|
||||
<div
|
||||
class="ant-upload-list-item ant-upload-list-item-error ant-upload-list-item-list-type-text"
|
||||
@@ -262,7 +262,7 @@ exports[`Upload List should be uploading when upload a file 2`] = `
|
||||
class="ant-upload-list ant-upload-list-text"
|
||||
>
|
||||
<div
|
||||
class="ant-upload-animate-enter"
|
||||
class=""
|
||||
>
|
||||
<span>
|
||||
<div
|
||||
|
||||
30
components/upload/__tests__/type.test.tsx
Normal file
30
components/upload/__tests__/type.test.tsx
Normal file
@@ -0,0 +1,30 @@
|
||||
import React from 'react';
|
||||
import Upload from '..';
|
||||
|
||||
describe('Upload.typescript', () => {
|
||||
it('Upload', () => {
|
||||
const upload = (
|
||||
<Upload>
|
||||
<span>click to upload</span>
|
||||
</Upload>
|
||||
);
|
||||
expect(upload).toBeTruthy();
|
||||
});
|
||||
|
||||
it('showUploadList', () => {
|
||||
const upload = (
|
||||
<Upload
|
||||
showUploadList={{
|
||||
showPreviewIcon: true,
|
||||
showRemoveIcon: true,
|
||||
showDownloadIcon: true,
|
||||
removeIcon: 'Remove',
|
||||
downloadIcon: 'Download',
|
||||
}}
|
||||
>
|
||||
<span>click to upload</span>
|
||||
</Upload>
|
||||
);
|
||||
expect(upload).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -1,6 +1,7 @@
|
||||
/* eslint-disable react/no-string-refs, react/prefer-es6-class */
|
||||
import React from 'react';
|
||||
import { mount } from 'enzyme';
|
||||
import { act } from 'react-dom/test-utils';
|
||||
import Upload from '..';
|
||||
import Form from '../../form';
|
||||
import { T, fileToObject, getFileItem, removeFileItem } from '../utils';
|
||||
@@ -554,4 +555,66 @@ describe('Upload', () => {
|
||||
wrapper.find('.ant-upload').at(1).simulate('mouseLeave');
|
||||
expect(onMouseLeave).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
// https://github.com/ant-design/ant-design/issues/26427
|
||||
it('should sync file list with control mode', done => {
|
||||
let callTimes = 0;
|
||||
|
||||
const customRequest = jest.fn(async options => {
|
||||
options.onProgress({ percent: 0 });
|
||||
const url = Promise.resolve('https://ant.design');
|
||||
options.onProgress({ percent: 100 });
|
||||
options.onSuccess({}, { ...options.file, url });
|
||||
});
|
||||
|
||||
const Demo = () => {
|
||||
const [fileList, setFileList] = React.useState([]);
|
||||
|
||||
const onChange = e => {
|
||||
const newFileList = Array.isArray(e) ? e : e.fileList;
|
||||
setFileList(newFileList);
|
||||
const file = newFileList[0];
|
||||
|
||||
callTimes += 1;
|
||||
|
||||
switch (callTimes) {
|
||||
case 1:
|
||||
case 2:
|
||||
expect(file).toEqual(expect.objectContaining({ status: 'uploading', percent: 0 }));
|
||||
break;
|
||||
|
||||
case 3:
|
||||
expect(file).toEqual(expect.objectContaining({ status: 'uploading', percent: 100 }));
|
||||
break;
|
||||
|
||||
case 4:
|
||||
expect(file).toEqual(expect.objectContaining({ status: 'done', percent: 100 }));
|
||||
break;
|
||||
|
||||
default:
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
if (callTimes >= 4) {
|
||||
done();
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Upload customRequest={customRequest} onChange={onChange} fileList={fileList}>
|
||||
<button type="button">Upload</button>
|
||||
</Upload>
|
||||
);
|
||||
};
|
||||
|
||||
const wrapper = mount(<Demo />);
|
||||
|
||||
act(() => {
|
||||
wrapper.find('input').simulate('change', {
|
||||
target: {
|
||||
files: [{ file: 'foo.png' }],
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import React from 'react';
|
||||
import { act } from 'react-dom/test-utils';
|
||||
import { mount } from 'enzyme';
|
||||
import Upload from '..';
|
||||
import UploadList from '../UploadList';
|
||||
@@ -801,14 +802,23 @@ describe('Upload List', () => {
|
||||
const nonImageFile = new File([''], 'foo.7z', { type: 'application/x-7z-compressed' });
|
||||
it('should render <img /> when upload non-image file and configure thumbUrl in onChange', done => {
|
||||
let wrapper;
|
||||
const onChange = async ({ fileList: files }) => {
|
||||
const newfileList = files.map(item => ({
|
||||
const onChange = async ({ file, fileList: files }) => {
|
||||
const newFileList = files.map(item => ({
|
||||
...item,
|
||||
thumbUrl: 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png',
|
||||
}));
|
||||
wrapper.setProps({ fileList: newfileList });
|
||||
|
||||
await sleep();
|
||||
wrapper.setProps({ fileList: newFileList });
|
||||
|
||||
if (file.status === 'uploading') {
|
||||
return;
|
||||
}
|
||||
|
||||
act(async () => {
|
||||
await sleep();
|
||||
wrapper.update();
|
||||
});
|
||||
|
||||
const imgNode = wrapper.find('.ant-upload-list-item-thumbnail img');
|
||||
expect(imgNode.length).toBe(1);
|
||||
done();
|
||||
@@ -880,4 +890,27 @@ describe('Upload List', () => {
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('should render button inside UploadList when listStyle is picture-card', () => {
|
||||
const wrapper = mount(
|
||||
<Upload
|
||||
action="http://jsonplaceholder.typicode.com/posts/"
|
||||
listType="picture-card"
|
||||
fileList={[
|
||||
{
|
||||
uid: '0',
|
||||
name: 'xxx.png',
|
||||
},
|
||||
]}
|
||||
showUploadList
|
||||
>
|
||||
<button className="trigger" type="button">
|
||||
upload
|
||||
</button>
|
||||
</Upload>,
|
||||
);
|
||||
expect(wrapper.exists('.ant-upload-list button.trigger')).toBe(true);
|
||||
wrapper.setProps({ showUploadList: false });
|
||||
expect(wrapper.exists('.ant-upload-list button.trigger')).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -61,13 +61,13 @@ class Avatar extends React.Component {
|
||||
};
|
||||
|
||||
render() {
|
||||
const { loading, imageUrl } = this.state;
|
||||
const uploadButton = (
|
||||
<div>
|
||||
{this.state.loading ? <LoadingOutlined /> : <PlusOutlined />}
|
||||
<div className="ant-upload-text">Upload</div>
|
||||
{loading ? <LoadingOutlined /> : <PlusOutlined />}
|
||||
<div style={{ marginTop: 8 }}>Upload</div>
|
||||
</div>
|
||||
);
|
||||
const { imageUrl } = this.state;
|
||||
return (
|
||||
<Upload
|
||||
name="avatar"
|
||||
|
||||
@@ -37,9 +37,7 @@ const props = {
|
||||
|
||||
ReactDOM.render(
|
||||
<Upload {...props}>
|
||||
<Button>
|
||||
<UploadOutlined /> Click to Upload
|
||||
</Button>
|
||||
<Button icon={<UploadOutlined />}>Click to Upload</Button>
|
||||
</Upload>,
|
||||
mountNode,
|
||||
);
|
||||
|
||||
@@ -45,9 +45,7 @@ const props = {
|
||||
|
||||
ReactDOM.render(
|
||||
<Upload {...props}>
|
||||
<Button>
|
||||
<UploadOutlined /> Click to Upload
|
||||
</Button>
|
||||
<Button icon={<UploadOutlined />}>Click to Upload</Button>
|
||||
</Upload>,
|
||||
mountNode,
|
||||
);
|
||||
|
||||
@@ -50,9 +50,7 @@ const props = {
|
||||
|
||||
ReactDOM.render(
|
||||
<Upload {...props}>
|
||||
<Button>
|
||||
<UploadOutlined /> Upload
|
||||
</Button>
|
||||
<Button icon={<UploadOutlined />}>Upload</Button>
|
||||
</Upload>,
|
||||
mountNode,
|
||||
);
|
||||
|
||||
@@ -19,9 +19,7 @@ import { UploadOutlined } from '@ant-design/icons';
|
||||
|
||||
ReactDOM.render(
|
||||
<Upload action="https://www.mocky.io/v2/5cc8019d300000980a055e76" directory>
|
||||
<Button>
|
||||
<UploadOutlined /> Upload Directory
|
||||
</Button>
|
||||
<Button icon={<UploadOutlined />}>Upload Directory</Button>
|
||||
</Upload>,
|
||||
mountNode,
|
||||
);
|
||||
|
||||
@@ -116,11 +116,11 @@ class PicturesWall extends React.Component {
|
||||
const uploadButton = (
|
||||
<div>
|
||||
<PlusOutlined />
|
||||
<div className="ant-upload-text">Upload</div>
|
||||
<div style={{ marginTop: 8 }}>Upload</div>
|
||||
</div>
|
||||
);
|
||||
return (
|
||||
<div className="clearfix">
|
||||
<>
|
||||
<Upload
|
||||
action="https://www.mocky.io/v2/5cc8019d300000980a055e76"
|
||||
listType="picture-card"
|
||||
@@ -134,23 +134,10 @@ class PicturesWall extends React.Component {
|
||||
<Modal visible={previewVisible} footer={null} onCancel={this.handleCancel}>
|
||||
<img alt="example" style={{ width: '100%' }} src={previewImage} />
|
||||
</Modal>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
ReactDOM.render(<PicturesWall />, mountNode);
|
||||
```
|
||||
|
||||
```css
|
||||
/* you can make up upload button and sample style by using stylesheets */
|
||||
.ant-upload-select-picture-card i {
|
||||
color: #999;
|
||||
font-size: 32px;
|
||||
}
|
||||
|
||||
.ant-upload-select-picture-card .ant-upload-text {
|
||||
margin-top: 8px;
|
||||
color: #666;
|
||||
}
|
||||
```
|
||||
|
||||
@@ -64,9 +64,7 @@ class MyUpload extends React.Component {
|
||||
};
|
||||
return (
|
||||
<Upload {...props} fileList={this.state.fileList}>
|
||||
<Button>
|
||||
<UploadOutlined /> Upload
|
||||
</Button>
|
||||
<Button icon={<UploadOutlined />}>Upload</Button>
|
||||
</Upload>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -56,6 +56,13 @@ class PicturesWall extends React.Component {
|
||||
status: 'done',
|
||||
url: 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png',
|
||||
},
|
||||
{
|
||||
uid: '-xxx',
|
||||
percent: 50,
|
||||
name: 'image.png',
|
||||
status: 'uploading',
|
||||
url: 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png',
|
||||
},
|
||||
{
|
||||
uid: '-5',
|
||||
name: 'image.png',
|
||||
@@ -85,11 +92,11 @@ class PicturesWall extends React.Component {
|
||||
const uploadButton = (
|
||||
<div>
|
||||
<PlusOutlined />
|
||||
<div className="ant-upload-text">Upload</div>
|
||||
<div style={{ marginTop: 8 }}>Upload</div>
|
||||
</div>
|
||||
);
|
||||
return (
|
||||
<div className="clearfix">
|
||||
<>
|
||||
<Upload
|
||||
action="https://www.mocky.io/v2/5cc8019d300000980a055e76"
|
||||
listType="picture-card"
|
||||
@@ -107,23 +114,10 @@ class PicturesWall extends React.Component {
|
||||
>
|
||||
<img alt="example" style={{ width: '100%' }} src={previewImage} />
|
||||
</Modal>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
ReactDOM.render(<PicturesWall />, mountNode);
|
||||
```
|
||||
|
||||
```css
|
||||
/* you can make up upload button and sample style by using stylesheets */
|
||||
.ant-upload-select-picture-card i {
|
||||
color: #999;
|
||||
font-size: 32px;
|
||||
}
|
||||
|
||||
.ant-upload-select-picture-card .ant-upload-text {
|
||||
margin-top: 8px;
|
||||
color: #666;
|
||||
}
|
||||
```
|
||||
|
||||
@@ -32,32 +32,24 @@ const fileList = [
|
||||
},
|
||||
];
|
||||
|
||||
const props = {
|
||||
action: 'https://www.mocky.io/v2/5cc8019d300000980a055e76',
|
||||
listType: 'picture',
|
||||
defaultFileList: [...fileList],
|
||||
};
|
||||
|
||||
const props2 = {
|
||||
action: 'https://www.mocky.io/v2/5cc8019d300000980a055e76',
|
||||
listType: 'picture',
|
||||
defaultFileList: [...fileList],
|
||||
className: 'upload-list-inline',
|
||||
};
|
||||
|
||||
ReactDOM.render(
|
||||
<>
|
||||
<Upload {...props}>
|
||||
<Button>
|
||||
<UploadOutlined /> Upload
|
||||
</Button>
|
||||
<Upload
|
||||
action="https://www.mocky.io/v2/5cc8019d300000980a055e76"
|
||||
listType="picture"
|
||||
defaultFileList={[...fileList]}
|
||||
>
|
||||
<Button icon={<UploadOutlined />}>Upload</Button>
|
||||
</Upload>
|
||||
<br />
|
||||
<br />
|
||||
<Upload {...props2}>
|
||||
<Button>
|
||||
<UploadOutlined /> Upload
|
||||
</Button>
|
||||
<Upload
|
||||
action="https://www.mocky.io/v2/5cc8019d300000980a055e76"
|
||||
listType="picture"
|
||||
defaultFileList={[...fileList]}
|
||||
className="upload-list-inline"
|
||||
>
|
||||
<Button icon={<UploadOutlined />}>Upload</Button>
|
||||
</Upload>
|
||||
</>,
|
||||
mountNode,
|
||||
@@ -75,10 +67,4 @@ ReactDOM.render(
|
||||
.upload-list-inline [class*='-upload-list-rtl'] .ant-upload-list-item {
|
||||
float: right;
|
||||
}
|
||||
.upload-list-inline .ant-upload-animate-enter {
|
||||
animation-name: uploadAnimateInlineIn;
|
||||
}
|
||||
.upload-list-inline .ant-upload-animate-leave {
|
||||
animation-name: uploadAnimateInlineOut;
|
||||
}
|
||||
```
|
||||
|
||||
@@ -34,9 +34,7 @@ const props = {
|
||||
|
||||
ReactDOM.render(
|
||||
<Upload {...props}>
|
||||
<Button>
|
||||
<UploadOutlined /> Upload
|
||||
</Button>
|
||||
<Button icon={<UploadOutlined />}>Upload</Button>
|
||||
</Upload>,
|
||||
mountNode,
|
||||
);
|
||||
|
||||
@@ -43,9 +43,7 @@ const props = {
|
||||
ReactDOM.render(
|
||||
<>
|
||||
<Upload {...props}>
|
||||
<Button>
|
||||
<UploadOutlined /> Upload
|
||||
</Button>
|
||||
<Button icon={<UploadOutlined />}>Upload</Button>
|
||||
</Upload>
|
||||
</>,
|
||||
mountNode,
|
||||
|
||||
@@ -56,9 +56,7 @@ const props = {
|
||||
|
||||
ReactDOM.render(
|
||||
<Upload {...props}>
|
||||
<Button>
|
||||
<UploadOutlined /> Upload
|
||||
</Button>
|
||||
<Button icon={<UploadOutlined />}>Upload</Button>
|
||||
</Upload>,
|
||||
mountNode,
|
||||
);
|
||||
|
||||
@@ -82,9 +82,7 @@ class Demo extends React.Component {
|
||||
return (
|
||||
<>
|
||||
<Upload {...props}>
|
||||
<Button>
|
||||
<UploadOutlined /> Select File
|
||||
</Button>
|
||||
<Button icon={<UploadOutlined />}>Select File</Button>
|
||||
</Upload>
|
||||
<Button
|
||||
type="primary"
|
||||
|
||||
@@ -36,9 +36,7 @@ const Uploader = () => {
|
||||
};
|
||||
return (
|
||||
<Upload {...props}>
|
||||
<Button>
|
||||
<UploadOutlined /> Upload png only
|
||||
</Button>
|
||||
<Button icon={<UploadOutlined />}>Upload png only</Button>
|
||||
</Upload>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -114,9 +114,7 @@ class AliyunOSSUpload extends React.Component {
|
||||
};
|
||||
return (
|
||||
<Upload {...props}>
|
||||
<Button>
|
||||
<UploadOutlined /> Click to Upload
|
||||
</Button>
|
||||
<Button icon={<UploadOutlined />}>Click to Upload</Button>
|
||||
</Upload>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -56,6 +56,8 @@ export interface ShowUploadListInterface {
|
||||
showRemoveIcon?: boolean;
|
||||
showPreviewIcon?: boolean;
|
||||
showDownloadIcon?: boolean;
|
||||
removeIcon?: React.ReactNode;
|
||||
downloadIcon?: React.ReactNode;
|
||||
}
|
||||
|
||||
export interface UploadLocale {
|
||||
@@ -133,4 +135,5 @@ export interface UploadListProps<T = any> {
|
||||
previewFile?: PreviewFileHandler;
|
||||
iconRender?: (file: UploadFile<T>, listType?: UploadListType) => React.ReactNode;
|
||||
isImageUrl?: (file: UploadFile) => boolean;
|
||||
appendAction?: React.ReactNode;
|
||||
}
|
||||
|
||||
@@ -34,8 +34,6 @@
|
||||
}
|
||||
|
||||
&&-select-picture-card {
|
||||
display: table;
|
||||
float: left;
|
||||
width: @upload-picture-card-size;
|
||||
height: @upload-picture-card-size;
|
||||
margin-right: 8px;
|
||||
@@ -46,15 +44,14 @@
|
||||
border: @border-width-base dashed @border-color-base;
|
||||
border-radius: @border-radius-base;
|
||||
cursor: pointer;
|
||||
transition: border-color 0.3s ease;
|
||||
transition: border-color 0.3s;
|
||||
|
||||
> .@{upload-prefix-cls} {
|
||||
display: table-cell;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 100%;
|
||||
padding: @padding-xs;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
@@ -408,17 +405,16 @@
|
||||
}
|
||||
|
||||
&-container {
|
||||
float: left;
|
||||
display: inline-block;
|
||||
width: @upload-picture-card-size;
|
||||
height: @upload-picture-card-size;
|
||||
margin: 0 @margin-xs @margin-xs 0;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.@{upload-item} {
|
||||
float: left;
|
||||
width: @upload-picture-card-size;
|
||||
height: @upload-picture-card-size;
|
||||
margin: 0 @margin-xs @margin-xs 0;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.@{upload-item}-info {
|
||||
@@ -515,6 +511,7 @@
|
||||
|
||||
.@{upload-item}-progress {
|
||||
bottom: 32px;
|
||||
width: calc(100% - 14px);
|
||||
padding-left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ title: 结果页
|
||||
|
||||
结果页是用一个页面反馈操作结果,是反馈模式中最强的一种。
|
||||
|
||||
## 设何时使用
|
||||
## 何时使用
|
||||
|
||||
当完成一个流程操作后,需给与用户明确的结果反馈时,例如分步表单的最后一步。<br/> 当有大量的信息需要在结果页展示时。
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "antd",
|
||||
"version": "4.6.0",
|
||||
"version": "4.6.2",
|
||||
"description": "An enterprise-class UI design language and React components implementation",
|
||||
"title": "Ant Design",
|
||||
"keywords": [
|
||||
@@ -147,8 +147,8 @@
|
||||
"rc-tree": "~3.9.0",
|
||||
"rc-tree-select": "~4.1.1",
|
||||
"rc-trigger": "~4.4.0",
|
||||
"rc-upload": "~3.2.0",
|
||||
"rc-util": "^5.0.1",
|
||||
"rc-upload": "~3.2.1",
|
||||
"rc-util": "^5.1.0",
|
||||
"scroll-into-view-if-needed": "^2.2.25",
|
||||
"warning": "^4.0.3"
|
||||
},
|
||||
|
||||
@@ -90,7 +90,12 @@ module.exports = {
|
||||
config.resolve.alias = { ...config.resolve.alias, react: require.resolve('react') };
|
||||
} else if (process.env.ESBUILD) {
|
||||
// use esbuild
|
||||
config.optimization.minimizer = [new EsbuildPlugin(), new CssMinimizerPlugin()];
|
||||
config.optimization.minimizer = [
|
||||
new EsbuildPlugin({
|
||||
target: 'chrome49',
|
||||
}),
|
||||
new CssMinimizerPlugin(),
|
||||
];
|
||||
}
|
||||
|
||||
alertBabelConfig(config.module.rules);
|
||||
|
||||
@@ -135,7 +135,7 @@ class MainContent extends Component {
|
||||
return (
|
||||
<Menu.ItemGroup title={menuItem.title} key={menuItem.title}>
|
||||
{menuItem.children
|
||||
.sort((a, b) => a.title.charCodeAt(0) - b.title.charCodeAt(0))
|
||||
.sort((a, b) => a.title.localeCompare(b.title))
|
||||
.map(leaf => this.generateMenuItem(false, leaf, footerNavIcons))}
|
||||
</Menu.ItemGroup>
|
||||
);
|
||||
|
||||
@@ -99,7 +99,9 @@ if (process.env.RUN_ENV === 'PRODUCTION') {
|
||||
config.optimization.usedExports = true;
|
||||
// use esbuild
|
||||
if (process.env.ESBUILD || process.env.CSB_REPO) {
|
||||
config.optimization.minimizer[0] = new EsbuildPlugin();
|
||||
config.optimization.minimizer[0] = new EsbuildPlugin({
|
||||
target: 'chrome49',
|
||||
});
|
||||
}
|
||||
|
||||
config.plugins.push(
|
||||
|
||||
Reference in New Issue
Block a user