mirror of
https://gitee.com/ant-design/ant-design.git
synced 2024-12-02 03:59:01 +08:00
commit
8084d730a0
@ -15,6 +15,27 @@ timeline: true
|
||||
|
||||
---
|
||||
|
||||
## 4.23.3
|
||||
|
||||
`2022-09-27`
|
||||
|
||||
- 🆕 Tree `showLeafIcon` could accept ReactNode for a custom leaf icon.[#37144](https://github.com/ant-design/ant-design/pull/37144) [@xWiiLLz](https://github.com/xWiiLLz)
|
||||
- 🆕 Uploader support Apple image format: heic, heif. [#37651](https://github.com/ant-design/ant-design/pull/37651) [@Johnny-young](https://github.com/Johnny-young)
|
||||
- 🐞 Fix Typography `copyable.tooltip=false` still shows the copied tooltip. [#37754](https://github.com/ant-design/ant-design/pull/37754)
|
||||
- 🐞 Fix Typography `ellipsis` not working correctly in some cases. [#37700](https://github.com/ant-design/ant-design/pull/37700) [@zheeeng](https://github.com/zheeeng)
|
||||
- 🐞 Fix Divider shows `children` when in `vertical` mode. [#37697](https://github.com/ant-design/ant-design/pull/37697)
|
||||
- 🐞 Fix Anchor `getCurrentAnchor` not updated. [#37644](https://github.com/ant-design/ant-design/pull/37644)
|
||||
- 🐞 Fix Tabs `animated: true` missing tabPane animation. [#37642](https://github.com/ant-design/ant-design/pull/37642)
|
||||
- 🐞 Fix Table `column.title` render function missing `filters` props. [#37629](https://github.com/ant-design/ant-design/pull/37629)
|
||||
- 🐞 Fix Modal.confirm instance ref legacy config `visible: true` back to show not work. [#37613](https://github.com/ant-design/ant-design/pull/37613)
|
||||
- 💄 Fix the problem of rendering an empty element with styles when Badge not pass `text` property. [#37681](https://github.com/ant-design/ant-design/pull/37681) [@Wxh16144](https://github.com/Wxh16144)
|
||||
- 💄 Fix Button wave style not work in shadow dom. [#37677](https://github.com/ant-design/ant-design/pull/37677)
|
||||
- 💄 Remove Tab.TabPane outline style when focused. [#37638](https://github.com/ant-design/ant-design/pull/37638)
|
||||
- TypeScript
|
||||
- 🤖 Update `FilterSearchType` definition for Table. [#37610](https://github.com/ant-design/ant-design/pull/37610) [@kiner-tang](https://github.com/kiner-tang)
|
||||
- 🌐 Localization
|
||||
- 🇵🇹 Add missing translations for 'Select all data' / 'Invert current page' for Transfer in pt_PT.[#37682](https://github.com/ant-design/ant-design/pull/37682) [@Dreamcreative](https://github.com/Dreamcreative), [#37701](https://github.com/ant-design/ant-design/pull/37701) [@hugobarragon](https://github.com/hugobarragon)
|
||||
|
||||
## 4.23.2
|
||||
|
||||
`2022-09-17`
|
||||
|
@ -15,6 +15,27 @@ timeline: true
|
||||
|
||||
---
|
||||
|
||||
## 4.23.3
|
||||
|
||||
`2022-09-27`
|
||||
|
||||
- 🆕 Tree `showLeafIcon` 属性支持自定义图标。[#37144](https://github.com/ant-design/ant-design/pull/37144) [@xWiiLLz](https://github.com/xWiiLLz)
|
||||
- 🆕 Uploader 支持支持 Apple 图片格式: heic、heif。[#37651](https://github.com/ant-design/ant-design/pull/37651) [@Johnny-young](https://github.com/Johnny-young)
|
||||
- 🐞 修复 Typography 在 `copyable.tooltip=false` 时,复制内容后仍然会展示提示的问题。[#37754](https://github.com/ant-design/ant-design/pull/37754)
|
||||
- 🐞 修复 Typography `ellipsis` 在某些情况下不精确的问题。[#37700](https://github.com/ant-design/ant-design/pull/37700) [@zheeeng](https://github.com/zheeeng)
|
||||
- 🐞 修复 Divider 在 `vertical` 模式下仍然会错误展示 `children` 的问题。[#37697](https://github.com/ant-design/ant-design/pull/37697)
|
||||
- 🐞 修复 Anchor `getCurrentAnchor` 不会及时更新的问题。[#37644](https://github.com/ant-design/ant-design/pull/37644)
|
||||
- 🐞 修复 Tabs `animated: true` 时面板切换动画不生效的问题。[#37642](https://github.com/ant-design/ant-design/pull/37642)
|
||||
- 🐞 修复 Table `column.title` 渲染函数丢失 `filters` 属性的问题。[#37629](https://github.com/ant-design/ant-design/pull/37629)
|
||||
- 🐞 修复 Modal.confirm 实例引用配置废弃 `visible: true` 重新展示时不生效的问题。[#37613](https://github.com/ant-design/ant-design/pull/37613)
|
||||
- 💄 修复 Badge 未传入 `text` 属性时,渲染了一个带有样式的空元素问题。[#37681](https://github.com/ant-design/ant-design/pull/37681) [@Wxh16144](https://github.com/Wxh16144)
|
||||
- 💄 修复 Button 波纹样式在 shadow dom 下不生效的问题。[#37677](https://github.com/ant-design/ant-design/pull/37677)
|
||||
- 💄 移除 Tab.TabPane focus 时的 outline 样式。[#37638](https://github.com/ant-design/ant-design/pull/37638)
|
||||
- TypeScript
|
||||
- 🤖 更新 Table 组件的 `FilterSearchType` 类型。[#37610](https://github.com/ant-design/ant-design/pull/37610) [@kiner-tang](https://github.com/kiner-tang)
|
||||
- 🌐 国际化
|
||||
- 🇵🇹 葡萄牙文 pt_PT 添加 Transfer 中 "全选" / "反选当页" 的翻译。[#37682](https://github.com/ant-design/ant-design/pull/37682) [@Dreamcreative](https://github.com/Dreamcreative),[#37701](https://github.com/ant-design/ant-design/pull/37701) [@hugobarragon](https://github.com/hugobarragon)
|
||||
|
||||
## 4.23.2
|
||||
|
||||
`2022-09-17`
|
||||
|
@ -65,9 +65,9 @@ const BackTop: React.FC<BackTopProps> = props => {
|
||||
|
||||
const handleScroll = throttleByAnimationFrame(
|
||||
(e: React.UIEvent<HTMLElement> | { target: any }) => {
|
||||
const { visibilityHeight } = props;
|
||||
const { visibilityHeight = 400 } = props;
|
||||
const scrollTop = getScroll(e.target, true);
|
||||
setVisible(scrollTop > visibilityHeight!);
|
||||
setVisible(scrollTop > visibilityHeight);
|
||||
},
|
||||
);
|
||||
|
||||
@ -140,8 +140,4 @@ const BackTop: React.FC<BackTopProps> = props => {
|
||||
);
|
||||
};
|
||||
|
||||
BackTop.defaultProps = {
|
||||
visibilityHeight: 400,
|
||||
};
|
||||
|
||||
export default React.memo(BackTop);
|
||||
|
@ -254,8 +254,13 @@ Array [
|
||||
Presets
|
||||
</span>
|
||||
</div>,
|
||||
<div>
|
||||
<div>
|
||||
<div
|
||||
class="ant-space ant-space-vertical"
|
||||
>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-bottom: 8px;"
|
||||
>
|
||||
<span
|
||||
class="ant-badge ant-badge-status ant-badge-not-a-wrapper"
|
||||
>
|
||||
@ -269,7 +274,10 @@ Array [
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-bottom: 8px;"
|
||||
>
|
||||
<span
|
||||
class="ant-badge ant-badge-status ant-badge-not-a-wrapper"
|
||||
>
|
||||
@ -283,7 +291,10 @@ Array [
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-bottom: 8px;"
|
||||
>
|
||||
<span
|
||||
class="ant-badge ant-badge-status ant-badge-not-a-wrapper"
|
||||
>
|
||||
@ -297,7 +308,10 @@ Array [
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-bottom: 8px;"
|
||||
>
|
||||
<span
|
||||
class="ant-badge ant-badge-status ant-badge-not-a-wrapper"
|
||||
>
|
||||
@ -311,7 +325,10 @@ Array [
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-bottom: 8px;"
|
||||
>
|
||||
<span
|
||||
class="ant-badge ant-badge-status ant-badge-not-a-wrapper"
|
||||
>
|
||||
@ -325,7 +342,10 @@ Array [
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-bottom: 8px;"
|
||||
>
|
||||
<span
|
||||
class="ant-badge ant-badge-status ant-badge-not-a-wrapper"
|
||||
>
|
||||
@ -339,7 +359,10 @@ Array [
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-bottom: 8px;"
|
||||
>
|
||||
<span
|
||||
class="ant-badge ant-badge-status ant-badge-not-a-wrapper"
|
||||
>
|
||||
@ -353,7 +376,10 @@ Array [
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-bottom: 8px;"
|
||||
>
|
||||
<span
|
||||
class="ant-badge ant-badge-status ant-badge-not-a-wrapper"
|
||||
>
|
||||
@ -367,7 +393,10 @@ Array [
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-bottom: 8px;"
|
||||
>
|
||||
<span
|
||||
class="ant-badge ant-badge-status ant-badge-not-a-wrapper"
|
||||
>
|
||||
@ -381,7 +410,10 @@ Array [
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-bottom: 8px;"
|
||||
>
|
||||
<span
|
||||
class="ant-badge ant-badge-status ant-badge-not-a-wrapper"
|
||||
>
|
||||
@ -395,7 +427,10 @@ Array [
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-bottom: 8px;"
|
||||
>
|
||||
<span
|
||||
class="ant-badge ant-badge-status ant-badge-not-a-wrapper"
|
||||
>
|
||||
@ -409,7 +444,10 @@ Array [
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-bottom: 8px;"
|
||||
>
|
||||
<span
|
||||
class="ant-badge ant-badge-status ant-badge-not-a-wrapper"
|
||||
>
|
||||
@ -423,7 +461,9 @@ Array [
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
>
|
||||
<span
|
||||
class="ant-badge ant-badge-status ant-badge-not-a-wrapper"
|
||||
>
|
||||
@ -448,61 +488,80 @@ Array [
|
||||
Custom
|
||||
</span>
|
||||
</div>,
|
||||
<span
|
||||
class="ant-badge ant-badge-status ant-badge-not-a-wrapper"
|
||||
<div
|
||||
class="ant-space ant-space-vertical"
|
||||
>
|
||||
<span
|
||||
class="ant-badge-status-dot"
|
||||
style="background: rgb(255, 85, 0);"
|
||||
/>
|
||||
<span
|
||||
class="ant-badge-status-text"
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-bottom: 8px;"
|
||||
>
|
||||
#f50
|
||||
</span>
|
||||
</span>,
|
||||
<br />,
|
||||
<span
|
||||
class="ant-badge ant-badge-status ant-badge-not-a-wrapper"
|
||||
>
|
||||
<span
|
||||
class="ant-badge-status-dot"
|
||||
style="background: rgb(45, 183, 245);"
|
||||
/>
|
||||
<span
|
||||
class="ant-badge-status-text"
|
||||
<span
|
||||
class="ant-badge ant-badge-status ant-badge-not-a-wrapper"
|
||||
>
|
||||
<span
|
||||
class="ant-badge-status-dot"
|
||||
style="background: rgb(255, 85, 0);"
|
||||
/>
|
||||
<span
|
||||
class="ant-badge-status-text"
|
||||
>
|
||||
#f50
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-bottom: 8px;"
|
||||
>
|
||||
#2db7f5
|
||||
</span>
|
||||
</span>,
|
||||
<br />,
|
||||
<span
|
||||
class="ant-badge ant-badge-status ant-badge-not-a-wrapper"
|
||||
>
|
||||
<span
|
||||
class="ant-badge-status-dot"
|
||||
style="background: rgb(135, 208, 104);"
|
||||
/>
|
||||
<span
|
||||
class="ant-badge-status-text"
|
||||
<span
|
||||
class="ant-badge ant-badge-status ant-badge-not-a-wrapper"
|
||||
>
|
||||
<span
|
||||
class="ant-badge-status-dot"
|
||||
style="background: rgb(45, 183, 245);"
|
||||
/>
|
||||
<span
|
||||
class="ant-badge-status-text"
|
||||
>
|
||||
rgb(45, 183, 245)
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-bottom: 8px;"
|
||||
>
|
||||
#87d068
|
||||
</span>
|
||||
</span>,
|
||||
<br />,
|
||||
<span
|
||||
class="ant-badge ant-badge-status ant-badge-not-a-wrapper"
|
||||
>
|
||||
<span
|
||||
class="ant-badge-status-dot"
|
||||
style="background: rgb(16, 142, 233);"
|
||||
/>
|
||||
<span
|
||||
class="ant-badge-status-text"
|
||||
<span
|
||||
class="ant-badge ant-badge-status ant-badge-not-a-wrapper"
|
||||
>
|
||||
<span
|
||||
class="ant-badge-status-dot"
|
||||
style="background: rgb(103, 103, 103);"
|
||||
/>
|
||||
<span
|
||||
class="ant-badge-status-text"
|
||||
>
|
||||
hsl(102, 53%, 61%)
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
>
|
||||
#108ee9
|
||||
</span>
|
||||
</span>,
|
||||
<span
|
||||
class="ant-badge ant-badge-status ant-badge-not-a-wrapper"
|
||||
>
|
||||
<span
|
||||
class="ant-badge-status-dot"
|
||||
/>
|
||||
<span
|
||||
class="ant-badge-status-text"
|
||||
>
|
||||
hwb(205 6% 9%)
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>,
|
||||
]
|
||||
`;
|
||||
|
||||
@ -1552,121 +1611,158 @@ Array [
|
||||
|
||||
exports[`renders ./components/badge/demo/status.md extend context correctly 1`] = `
|
||||
Array [
|
||||
<span
|
||||
class="ant-badge ant-badge-status ant-badge-not-a-wrapper"
|
||||
<div
|
||||
class="ant-space ant-space-horizontal ant-space-align-center"
|
||||
>
|
||||
<span
|
||||
class="ant-badge-status-dot ant-badge-status-success"
|
||||
/>
|
||||
<span
|
||||
class="ant-badge-status-text"
|
||||
/>
|
||||
</span>,
|
||||
<span
|
||||
class="ant-badge ant-badge-status ant-badge-not-a-wrapper"
|
||||
>
|
||||
<span
|
||||
class="ant-badge-status-dot ant-badge-status-error"
|
||||
/>
|
||||
<span
|
||||
class="ant-badge-status-text"
|
||||
/>
|
||||
</span>,
|
||||
<span
|
||||
class="ant-badge ant-badge-status ant-badge-not-a-wrapper"
|
||||
>
|
||||
<span
|
||||
class="ant-badge-status-dot ant-badge-status-default"
|
||||
/>
|
||||
<span
|
||||
class="ant-badge-status-text"
|
||||
/>
|
||||
</span>,
|
||||
<span
|
||||
class="ant-badge ant-badge-status ant-badge-not-a-wrapper"
|
||||
>
|
||||
<span
|
||||
class="ant-badge-status-dot ant-badge-status-processing"
|
||||
/>
|
||||
<span
|
||||
class="ant-badge-status-text"
|
||||
/>
|
||||
</span>,
|
||||
<span
|
||||
class="ant-badge ant-badge-status ant-badge-not-a-wrapper"
|
||||
>
|
||||
<span
|
||||
class="ant-badge-status-dot ant-badge-status-warning"
|
||||
/>
|
||||
<span
|
||||
class="ant-badge-status-text"
|
||||
/>
|
||||
</span>,
|
||||
<br />,
|
||||
<span
|
||||
class="ant-badge ant-badge-status ant-badge-not-a-wrapper"
|
||||
>
|
||||
<span
|
||||
class="ant-badge-status-dot ant-badge-status-success"
|
||||
/>
|
||||
<span
|
||||
class="ant-badge-status-text"
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-right: 8px;"
|
||||
>
|
||||
Success
|
||||
</span>
|
||||
</span>,
|
||||
<br />,
|
||||
<span
|
||||
class="ant-badge ant-badge-status ant-badge-not-a-wrapper"
|
||||
>
|
||||
<span
|
||||
class="ant-badge-status-dot ant-badge-status-error"
|
||||
/>
|
||||
<span
|
||||
class="ant-badge-status-text"
|
||||
<span
|
||||
class="ant-badge ant-badge-status ant-badge-not-a-wrapper"
|
||||
>
|
||||
<span
|
||||
class="ant-badge-status-dot ant-badge-status-success"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-right: 8px;"
|
||||
>
|
||||
Error
|
||||
</span>
|
||||
</span>,
|
||||
<br />,
|
||||
<span
|
||||
class="ant-badge ant-badge-status ant-badge-not-a-wrapper"
|
||||
>
|
||||
<span
|
||||
class="ant-badge-status-dot ant-badge-status-default"
|
||||
/>
|
||||
<span
|
||||
class="ant-badge-status-text"
|
||||
<span
|
||||
class="ant-badge ant-badge-status ant-badge-not-a-wrapper"
|
||||
>
|
||||
<span
|
||||
class="ant-badge-status-dot ant-badge-status-error"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-right: 8px;"
|
||||
>
|
||||
Default
|
||||
</span>
|
||||
</span>,
|
||||
<br />,
|
||||
<span
|
||||
class="ant-badge ant-badge-status ant-badge-not-a-wrapper"
|
||||
>
|
||||
<span
|
||||
class="ant-badge-status-dot ant-badge-status-processing"
|
||||
/>
|
||||
<span
|
||||
class="ant-badge-status-text"
|
||||
<span
|
||||
class="ant-badge ant-badge-status ant-badge-not-a-wrapper"
|
||||
>
|
||||
<span
|
||||
class="ant-badge-status-dot ant-badge-status-default"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-right: 8px;"
|
||||
>
|
||||
Processing
|
||||
</span>
|
||||
</span>,
|
||||
<br />,
|
||||
<span
|
||||
class="ant-badge ant-badge-status ant-badge-not-a-wrapper"
|
||||
>
|
||||
<span
|
||||
class="ant-badge-status-dot ant-badge-status-warning"
|
||||
/>
|
||||
<span
|
||||
class="ant-badge-status-text"
|
||||
<span
|
||||
class="ant-badge ant-badge-status ant-badge-not-a-wrapper"
|
||||
>
|
||||
<span
|
||||
class="ant-badge-status-dot ant-badge-status-processing"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
>
|
||||
Warning
|
||||
</span>
|
||||
</span>,
|
||||
<span
|
||||
class="ant-badge ant-badge-status ant-badge-not-a-wrapper"
|
||||
>
|
||||
<span
|
||||
class="ant-badge-status-dot ant-badge-status-warning"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
</div>,
|
||||
<br />,
|
||||
<div
|
||||
class="ant-space ant-space-vertical"
|
||||
>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-bottom: 8px;"
|
||||
>
|
||||
<span
|
||||
class="ant-badge ant-badge-status ant-badge-not-a-wrapper"
|
||||
>
|
||||
<span
|
||||
class="ant-badge-status-dot ant-badge-status-success"
|
||||
/>
|
||||
<span
|
||||
class="ant-badge-status-text"
|
||||
>
|
||||
Success
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-bottom: 8px;"
|
||||
>
|
||||
<span
|
||||
class="ant-badge ant-badge-status ant-badge-not-a-wrapper"
|
||||
>
|
||||
<span
|
||||
class="ant-badge-status-dot ant-badge-status-error"
|
||||
/>
|
||||
<span
|
||||
class="ant-badge-status-text"
|
||||
>
|
||||
Error
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-bottom: 8px;"
|
||||
>
|
||||
<span
|
||||
class="ant-badge ant-badge-status ant-badge-not-a-wrapper"
|
||||
>
|
||||
<span
|
||||
class="ant-badge-status-dot ant-badge-status-default"
|
||||
/>
|
||||
<span
|
||||
class="ant-badge-status-text"
|
||||
>
|
||||
Default
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-bottom: 8px;"
|
||||
>
|
||||
<span
|
||||
class="ant-badge ant-badge-status ant-badge-not-a-wrapper"
|
||||
>
|
||||
<span
|
||||
class="ant-badge-status-dot ant-badge-status-processing"
|
||||
/>
|
||||
<span
|
||||
class="ant-badge-status-text"
|
||||
>
|
||||
Processing
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
>
|
||||
<span
|
||||
class="ant-badge ant-badge-status ant-badge-not-a-wrapper"
|
||||
>
|
||||
<span
|
||||
class="ant-badge-status-dot ant-badge-status-warning"
|
||||
/>
|
||||
<span
|
||||
class="ant-badge-status-text"
|
||||
>
|
||||
Warning
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>,
|
||||
]
|
||||
`;
|
||||
|
||||
|
@ -254,8 +254,13 @@ Array [
|
||||
Presets
|
||||
</span>
|
||||
</div>,
|
||||
<div>
|
||||
<div>
|
||||
<div
|
||||
class="ant-space ant-space-vertical"
|
||||
>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-bottom: 8px;"
|
||||
>
|
||||
<span
|
||||
class="ant-badge ant-badge-status ant-badge-not-a-wrapper"
|
||||
>
|
||||
@ -269,7 +274,10 @@ Array [
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-bottom: 8px;"
|
||||
>
|
||||
<span
|
||||
class="ant-badge ant-badge-status ant-badge-not-a-wrapper"
|
||||
>
|
||||
@ -283,7 +291,10 @@ Array [
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-bottom: 8px;"
|
||||
>
|
||||
<span
|
||||
class="ant-badge ant-badge-status ant-badge-not-a-wrapper"
|
||||
>
|
||||
@ -297,7 +308,10 @@ Array [
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-bottom: 8px;"
|
||||
>
|
||||
<span
|
||||
class="ant-badge ant-badge-status ant-badge-not-a-wrapper"
|
||||
>
|
||||
@ -311,7 +325,10 @@ Array [
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-bottom: 8px;"
|
||||
>
|
||||
<span
|
||||
class="ant-badge ant-badge-status ant-badge-not-a-wrapper"
|
||||
>
|
||||
@ -325,7 +342,10 @@ Array [
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-bottom: 8px;"
|
||||
>
|
||||
<span
|
||||
class="ant-badge ant-badge-status ant-badge-not-a-wrapper"
|
||||
>
|
||||
@ -339,7 +359,10 @@ Array [
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-bottom: 8px;"
|
||||
>
|
||||
<span
|
||||
class="ant-badge ant-badge-status ant-badge-not-a-wrapper"
|
||||
>
|
||||
@ -353,7 +376,10 @@ Array [
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-bottom: 8px;"
|
||||
>
|
||||
<span
|
||||
class="ant-badge ant-badge-status ant-badge-not-a-wrapper"
|
||||
>
|
||||
@ -367,7 +393,10 @@ Array [
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-bottom: 8px;"
|
||||
>
|
||||
<span
|
||||
class="ant-badge ant-badge-status ant-badge-not-a-wrapper"
|
||||
>
|
||||
@ -381,7 +410,10 @@ Array [
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-bottom: 8px;"
|
||||
>
|
||||
<span
|
||||
class="ant-badge ant-badge-status ant-badge-not-a-wrapper"
|
||||
>
|
||||
@ -395,7 +427,10 @@ Array [
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-bottom: 8px;"
|
||||
>
|
||||
<span
|
||||
class="ant-badge ant-badge-status ant-badge-not-a-wrapper"
|
||||
>
|
||||
@ -409,7 +444,10 @@ Array [
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-bottom: 8px;"
|
||||
>
|
||||
<span
|
||||
class="ant-badge ant-badge-status ant-badge-not-a-wrapper"
|
||||
>
|
||||
@ -423,7 +461,9 @@ Array [
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
>
|
||||
<span
|
||||
class="ant-badge ant-badge-status ant-badge-not-a-wrapper"
|
||||
>
|
||||
@ -448,61 +488,80 @@ Array [
|
||||
Custom
|
||||
</span>
|
||||
</div>,
|
||||
<span
|
||||
class="ant-badge ant-badge-status ant-badge-not-a-wrapper"
|
||||
<div
|
||||
class="ant-space ant-space-vertical"
|
||||
>
|
||||
<span
|
||||
class="ant-badge-status-dot"
|
||||
style="background: rgb(255, 85, 0);"
|
||||
/>
|
||||
<span
|
||||
class="ant-badge-status-text"
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-bottom: 8px;"
|
||||
>
|
||||
#f50
|
||||
</span>
|
||||
</span>,
|
||||
<br />,
|
||||
<span
|
||||
class="ant-badge ant-badge-status ant-badge-not-a-wrapper"
|
||||
>
|
||||
<span
|
||||
class="ant-badge-status-dot"
|
||||
style="background: rgb(45, 183, 245);"
|
||||
/>
|
||||
<span
|
||||
class="ant-badge-status-text"
|
||||
<span
|
||||
class="ant-badge ant-badge-status ant-badge-not-a-wrapper"
|
||||
>
|
||||
<span
|
||||
class="ant-badge-status-dot"
|
||||
style="background: rgb(255, 85, 0);"
|
||||
/>
|
||||
<span
|
||||
class="ant-badge-status-text"
|
||||
>
|
||||
#f50
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-bottom: 8px;"
|
||||
>
|
||||
#2db7f5
|
||||
</span>
|
||||
</span>,
|
||||
<br />,
|
||||
<span
|
||||
class="ant-badge ant-badge-status ant-badge-not-a-wrapper"
|
||||
>
|
||||
<span
|
||||
class="ant-badge-status-dot"
|
||||
style="background: rgb(135, 208, 104);"
|
||||
/>
|
||||
<span
|
||||
class="ant-badge-status-text"
|
||||
<span
|
||||
class="ant-badge ant-badge-status ant-badge-not-a-wrapper"
|
||||
>
|
||||
<span
|
||||
class="ant-badge-status-dot"
|
||||
style="background: rgb(45, 183, 245);"
|
||||
/>
|
||||
<span
|
||||
class="ant-badge-status-text"
|
||||
>
|
||||
rgb(45, 183, 245)
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-bottom: 8px;"
|
||||
>
|
||||
#87d068
|
||||
</span>
|
||||
</span>,
|
||||
<br />,
|
||||
<span
|
||||
class="ant-badge ant-badge-status ant-badge-not-a-wrapper"
|
||||
>
|
||||
<span
|
||||
class="ant-badge-status-dot"
|
||||
style="background: rgb(16, 142, 233);"
|
||||
/>
|
||||
<span
|
||||
class="ant-badge-status-text"
|
||||
<span
|
||||
class="ant-badge ant-badge-status ant-badge-not-a-wrapper"
|
||||
>
|
||||
<span
|
||||
class="ant-badge-status-dot"
|
||||
style="background: rgb(103, 103, 103);"
|
||||
/>
|
||||
<span
|
||||
class="ant-badge-status-text"
|
||||
>
|
||||
hsl(102, 53%, 61%)
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
>
|
||||
#108ee9
|
||||
</span>
|
||||
</span>,
|
||||
<span
|
||||
class="ant-badge ant-badge-status ant-badge-not-a-wrapper"
|
||||
>
|
||||
<span
|
||||
class="ant-badge-status-dot"
|
||||
/>
|
||||
<span
|
||||
class="ant-badge-status-text"
|
||||
>
|
||||
hwb(205 6% 9%)
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>,
|
||||
]
|
||||
`;
|
||||
|
||||
@ -1552,121 +1611,158 @@ Array [
|
||||
|
||||
exports[`renders ./components/badge/demo/status.md correctly 1`] = `
|
||||
Array [
|
||||
<span
|
||||
class="ant-badge ant-badge-status ant-badge-not-a-wrapper"
|
||||
<div
|
||||
class="ant-space ant-space-horizontal ant-space-align-center"
|
||||
>
|
||||
<span
|
||||
class="ant-badge-status-dot ant-badge-status-success"
|
||||
/>
|
||||
<span
|
||||
class="ant-badge-status-text"
|
||||
/>
|
||||
</span>,
|
||||
<span
|
||||
class="ant-badge ant-badge-status ant-badge-not-a-wrapper"
|
||||
>
|
||||
<span
|
||||
class="ant-badge-status-dot ant-badge-status-error"
|
||||
/>
|
||||
<span
|
||||
class="ant-badge-status-text"
|
||||
/>
|
||||
</span>,
|
||||
<span
|
||||
class="ant-badge ant-badge-status ant-badge-not-a-wrapper"
|
||||
>
|
||||
<span
|
||||
class="ant-badge-status-dot ant-badge-status-default"
|
||||
/>
|
||||
<span
|
||||
class="ant-badge-status-text"
|
||||
/>
|
||||
</span>,
|
||||
<span
|
||||
class="ant-badge ant-badge-status ant-badge-not-a-wrapper"
|
||||
>
|
||||
<span
|
||||
class="ant-badge-status-dot ant-badge-status-processing"
|
||||
/>
|
||||
<span
|
||||
class="ant-badge-status-text"
|
||||
/>
|
||||
</span>,
|
||||
<span
|
||||
class="ant-badge ant-badge-status ant-badge-not-a-wrapper"
|
||||
>
|
||||
<span
|
||||
class="ant-badge-status-dot ant-badge-status-warning"
|
||||
/>
|
||||
<span
|
||||
class="ant-badge-status-text"
|
||||
/>
|
||||
</span>,
|
||||
<br />,
|
||||
<span
|
||||
class="ant-badge ant-badge-status ant-badge-not-a-wrapper"
|
||||
>
|
||||
<span
|
||||
class="ant-badge-status-dot ant-badge-status-success"
|
||||
/>
|
||||
<span
|
||||
class="ant-badge-status-text"
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-right: 8px;"
|
||||
>
|
||||
Success
|
||||
</span>
|
||||
</span>,
|
||||
<br />,
|
||||
<span
|
||||
class="ant-badge ant-badge-status ant-badge-not-a-wrapper"
|
||||
>
|
||||
<span
|
||||
class="ant-badge-status-dot ant-badge-status-error"
|
||||
/>
|
||||
<span
|
||||
class="ant-badge-status-text"
|
||||
<span
|
||||
class="ant-badge ant-badge-status ant-badge-not-a-wrapper"
|
||||
>
|
||||
<span
|
||||
class="ant-badge-status-dot ant-badge-status-success"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-right: 8px;"
|
||||
>
|
||||
Error
|
||||
</span>
|
||||
</span>,
|
||||
<br />,
|
||||
<span
|
||||
class="ant-badge ant-badge-status ant-badge-not-a-wrapper"
|
||||
>
|
||||
<span
|
||||
class="ant-badge-status-dot ant-badge-status-default"
|
||||
/>
|
||||
<span
|
||||
class="ant-badge-status-text"
|
||||
<span
|
||||
class="ant-badge ant-badge-status ant-badge-not-a-wrapper"
|
||||
>
|
||||
<span
|
||||
class="ant-badge-status-dot ant-badge-status-error"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-right: 8px;"
|
||||
>
|
||||
Default
|
||||
</span>
|
||||
</span>,
|
||||
<br />,
|
||||
<span
|
||||
class="ant-badge ant-badge-status ant-badge-not-a-wrapper"
|
||||
>
|
||||
<span
|
||||
class="ant-badge-status-dot ant-badge-status-processing"
|
||||
/>
|
||||
<span
|
||||
class="ant-badge-status-text"
|
||||
<span
|
||||
class="ant-badge ant-badge-status ant-badge-not-a-wrapper"
|
||||
>
|
||||
<span
|
||||
class="ant-badge-status-dot ant-badge-status-default"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-right: 8px;"
|
||||
>
|
||||
Processing
|
||||
</span>
|
||||
</span>,
|
||||
<br />,
|
||||
<span
|
||||
class="ant-badge ant-badge-status ant-badge-not-a-wrapper"
|
||||
>
|
||||
<span
|
||||
class="ant-badge-status-dot ant-badge-status-warning"
|
||||
/>
|
||||
<span
|
||||
class="ant-badge-status-text"
|
||||
<span
|
||||
class="ant-badge ant-badge-status ant-badge-not-a-wrapper"
|
||||
>
|
||||
<span
|
||||
class="ant-badge-status-dot ant-badge-status-processing"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
>
|
||||
Warning
|
||||
</span>
|
||||
</span>,
|
||||
<span
|
||||
class="ant-badge ant-badge-status ant-badge-not-a-wrapper"
|
||||
>
|
||||
<span
|
||||
class="ant-badge-status-dot ant-badge-status-warning"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
</div>,
|
||||
<br />,
|
||||
<div
|
||||
class="ant-space ant-space-vertical"
|
||||
>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-bottom: 8px;"
|
||||
>
|
||||
<span
|
||||
class="ant-badge ant-badge-status ant-badge-not-a-wrapper"
|
||||
>
|
||||
<span
|
||||
class="ant-badge-status-dot ant-badge-status-success"
|
||||
/>
|
||||
<span
|
||||
class="ant-badge-status-text"
|
||||
>
|
||||
Success
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-bottom: 8px;"
|
||||
>
|
||||
<span
|
||||
class="ant-badge ant-badge-status ant-badge-not-a-wrapper"
|
||||
>
|
||||
<span
|
||||
class="ant-badge-status-dot ant-badge-status-error"
|
||||
/>
|
||||
<span
|
||||
class="ant-badge-status-text"
|
||||
>
|
||||
Error
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-bottom: 8px;"
|
||||
>
|
||||
<span
|
||||
class="ant-badge ant-badge-status ant-badge-not-a-wrapper"
|
||||
>
|
||||
<span
|
||||
class="ant-badge-status-dot ant-badge-status-default"
|
||||
/>
|
||||
<span
|
||||
class="ant-badge-status-text"
|
||||
>
|
||||
Default
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-bottom: 8px;"
|
||||
>
|
||||
<span
|
||||
class="ant-badge ant-badge-status ant-badge-not-a-wrapper"
|
||||
>
|
||||
<span
|
||||
class="ant-badge-status-dot ant-badge-status-processing"
|
||||
/>
|
||||
<span
|
||||
class="ant-badge-status-text"
|
||||
>
|
||||
Processing
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
>
|
||||
<span
|
||||
class="ant-badge ant-badge-status ant-badge-not-a-wrapper"
|
||||
>
|
||||
<span
|
||||
class="ant-badge-status-dot ant-badge-status-warning"
|
||||
/>
|
||||
<span
|
||||
class="ant-badge-status-text"
|
||||
>
|
||||
Warning
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>,
|
||||
]
|
||||
`;
|
||||
|
||||
|
@ -165,4 +165,10 @@ describe('Badge', () => {
|
||||
|
||||
expect(container.querySelectorAll('.ant-badge')).toHaveLength(2);
|
||||
});
|
||||
|
||||
it('Badge not render status-text when text is empty string', () => {
|
||||
const { container } = render(<Badge status="default" text={undefined} />);
|
||||
|
||||
expect(container.querySelectorAll('.ant-badge > .ant-badge-status-text')).toHaveLength(0);
|
||||
});
|
||||
});
|
||||
|
@ -14,7 +14,7 @@ title:
|
||||
We preset a series of colorful Badge styles for use in different situations. You can also set it to a hex color string for custom color.
|
||||
|
||||
```tsx
|
||||
import { Badge, Divider } from 'antd';
|
||||
import { Badge, Divider, Space } from 'antd';
|
||||
import React from 'react';
|
||||
|
||||
const colors = [
|
||||
@ -36,31 +36,20 @@ const colors = [
|
||||
const App: React.FC = () => (
|
||||
<>
|
||||
<Divider orientation="left">Presets</Divider>
|
||||
<div>
|
||||
<Space direction="vertical">
|
||||
{colors.map(color => (
|
||||
<div key={color}>
|
||||
<Badge color={color} text={color} />
|
||||
</div>
|
||||
<Badge key={color} color={color} text={color} />
|
||||
))}
|
||||
</div>
|
||||
</Space>
|
||||
<Divider orientation="left">Custom</Divider>
|
||||
<>
|
||||
<Space direction="vertical">
|
||||
<Badge color="#f50" text="#f50" />
|
||||
<br />
|
||||
<Badge color="#2db7f5" text="#2db7f5" />
|
||||
<br />
|
||||
<Badge color="#87d068" text="#87d068" />
|
||||
<br />
|
||||
<Badge color="#108ee9" text="#108ee9" />
|
||||
</>
|
||||
<Badge color="rgb(45, 183, 245)" text="rgb(45, 183, 245)" />
|
||||
<Badge color="hsl(102, 53%, 61%)" text="hsl(102, 53%, 61%)" />
|
||||
<Badge color="hwb(205 6% 9%)" text="hwb(205 6% 9%)" />
|
||||
</Space>
|
||||
</>
|
||||
);
|
||||
|
||||
export default App;
|
||||
```
|
||||
|
||||
```css
|
||||
.ant-tag {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
```
|
||||
|
@ -14,26 +14,26 @@ title:
|
||||
Standalone badge with status.
|
||||
|
||||
```tsx
|
||||
import { Badge } from 'antd';
|
||||
import { Badge, Space } from 'antd';
|
||||
import React from 'react';
|
||||
|
||||
const App: React.FC = () => (
|
||||
<>
|
||||
<Badge status="success" />
|
||||
<Badge status="error" />
|
||||
<Badge status="default" />
|
||||
<Badge status="processing" />
|
||||
<Badge status="warning" />
|
||||
<Space>
|
||||
<Badge status="success" />
|
||||
<Badge status="error" />
|
||||
<Badge status="default" />
|
||||
<Badge status="processing" />
|
||||
<Badge status="warning" />
|
||||
</Space>
|
||||
<br />
|
||||
<Badge status="success" text="Success" />
|
||||
<br />
|
||||
<Badge status="error" text="Error" />
|
||||
<br />
|
||||
<Badge status="default" text="Default" />
|
||||
<br />
|
||||
<Badge status="processing" text="Processing" />
|
||||
<br />
|
||||
<Badge status="warning" text="Warning" />
|
||||
<Space direction="vertical">
|
||||
<Badge status="success" text="Success" />
|
||||
<Badge status="error" text="Error" />
|
||||
<Badge status="default" text="Default" />
|
||||
<Badge status="processing" text="Processing" />
|
||||
<Badge status="warning" text="Warning" />
|
||||
</Space>
|
||||
</>
|
||||
);
|
||||
|
||||
|
@ -169,9 +169,11 @@ const Badge: CompoundedComponent = ({
|
||||
return wrapSSR(
|
||||
<span {...restProps} className={classNames(badgeClassName, hashId)} style={mergedStyle}>
|
||||
<span className={statusCls} style={statusStyle} />
|
||||
<span style={{ color: statusTextColor }} className={`${prefixCls}-status-text`}>
|
||||
{text}
|
||||
</span>
|
||||
{text && (
|
||||
<span style={{ color: statusTextColor }} className={`${prefixCls}-status-text`}>
|
||||
{text}
|
||||
</span>
|
||||
)}
|
||||
</span>,
|
||||
);
|
||||
}
|
||||
|
@ -1,7 +1,8 @@
|
||||
import React from 'react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import mountTest from '../../../tests/shared/mountTest';
|
||||
import rtlTest from '../../../tests/shared/rtlTest';
|
||||
import { fireEvent, render } from '../../../tests/utils';
|
||||
import { screen, render } from '../../../tests/utils';
|
||||
import Button from '../../button/index';
|
||||
import Card from '../index';
|
||||
import '@testing-library/jest-dom';
|
||||
@ -36,7 +37,7 @@ describe('Card', () => {
|
||||
expect(container.firstChild).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('onTabChange should work', () => {
|
||||
it('onTabChange should work', async () => {
|
||||
const tabList = [
|
||||
{
|
||||
key: 'tab1',
|
||||
@ -48,23 +49,24 @@ describe('Card', () => {
|
||||
},
|
||||
];
|
||||
const onTabChange = jest.fn();
|
||||
const { container } = render(
|
||||
render(
|
||||
<Card onTabChange={onTabChange} tabList={tabList}>
|
||||
xxx
|
||||
</Card>,
|
||||
);
|
||||
fireEvent.click(container.querySelectorAll('.ant-tabs-tab')[1]);
|
||||
await userEvent.setup({ delay: null }).click(screen.getByRole('tab', { name: /tab2/i }));
|
||||
expect(onTabChange).toHaveBeenCalledWith('tab2');
|
||||
});
|
||||
|
||||
it('should not render when actions is number', () => {
|
||||
const { container } = render(
|
||||
const numberStub = 11;
|
||||
render(
|
||||
// @ts-ignore ingnore for the wrong action value
|
||||
<Card title="Card title" actions={11}>
|
||||
<Card title="Card title" actions={numberStub}>
|
||||
<p>Card content</p>
|
||||
</Card>,
|
||||
);
|
||||
expect(container.querySelectorAll('.ant-card-actions').length).toBe(0);
|
||||
expect(screen.queryByText(numberStub)).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('with tab props', () => {
|
||||
|
@ -198,7 +198,7 @@ exports[`Form form should support disabled 1`] = `
|
||||
/>
|
||||
</span>
|
||||
<span>
|
||||
Apple
|
||||
Apple
|
||||
</span>
|
||||
</label>
|
||||
<label
|
||||
@ -218,7 +218,7 @@ exports[`Form form should support disabled 1`] = `
|
||||
/>
|
||||
</span>
|
||||
<span>
|
||||
Pear
|
||||
Pear
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,8 +1,7 @@
|
||||
import { mount } from 'enzyme';
|
||||
import React from 'react';
|
||||
import { act } from 'react-dom/test-utils';
|
||||
import Form from '..';
|
||||
import { sleep } from '../../../tests/utils';
|
||||
import { render, fireEvent, waitFakeTimer } from '../../../tests/utils';
|
||||
import Input from '../../input';
|
||||
import type { FormListOperation } from '../FormList';
|
||||
|
||||
@ -12,12 +11,11 @@ describe('Form.List.NoStyle', () => {
|
||||
|
||||
let operation: FormListOperation;
|
||||
|
||||
const wrapper = mount(
|
||||
const { container } = render(
|
||||
<Form>
|
||||
<Form.List name="users">
|
||||
{(fields, op) => {
|
||||
operation = op;
|
||||
|
||||
return fields.map(field => (
|
||||
<Form.Item key={field.key}>
|
||||
<Form.Item
|
||||
@ -36,39 +34,33 @@ describe('Form.List.NoStyle', () => {
|
||||
);
|
||||
|
||||
// Add two
|
||||
async function addItem() {
|
||||
const addItem = async () => {
|
||||
await act(async () => {
|
||||
operation!.add();
|
||||
await sleep(100);
|
||||
jest.runAllTimers();
|
||||
wrapper.update();
|
||||
operation?.add();
|
||||
});
|
||||
}
|
||||
|
||||
addItem();
|
||||
addItem();
|
||||
await waitFakeTimer();
|
||||
};
|
||||
|
||||
await addItem();
|
||||
await addItem();
|
||||
|
||||
// Submit
|
||||
await act(async () => {
|
||||
wrapper.find('form').simulate('submit');
|
||||
await sleep(100);
|
||||
jest.runAllTimers();
|
||||
wrapper.update();
|
||||
});
|
||||
fireEvent.submit(container.querySelector('form')!);
|
||||
await waitFakeTimer();
|
||||
|
||||
// Remove first field
|
||||
await act(async () => {
|
||||
operation!.remove(0);
|
||||
await sleep(100);
|
||||
jest.runAllTimers();
|
||||
wrapper.update();
|
||||
operation?.remove(0);
|
||||
});
|
||||
await waitFakeTimer();
|
||||
|
||||
// Match error message
|
||||
expect(wrapper.find('.ant-form-item-explain-error').text()).toEqual(
|
||||
expect(container.querySelector('.ant-form-item-explain-error')?.textContent).toBe(
|
||||
"'users.1.first' is required",
|
||||
);
|
||||
|
||||
jest.clearAllTimers();
|
||||
jest.useRealTimers();
|
||||
});
|
||||
});
|
||||
|
@ -1,16 +1,24 @@
|
||||
import React from 'react';
|
||||
import type { FormListFieldData, FormListOperation } from '..';
|
||||
import Form from '..';
|
||||
import { fireEvent, render, sleep, act } from '../../../tests/utils';
|
||||
import Button from '../../button';
|
||||
import Input from '../../input';
|
||||
|
||||
describe('Form.List', () => {
|
||||
async function change(wrapper, index, value) {
|
||||
fireEvent.change(wrapper.getElementsByClassName('ant-input')[index], { target: { value } });
|
||||
const change = async (
|
||||
wrapper: ReturnType<typeof render>['container'],
|
||||
index: number,
|
||||
value: string,
|
||||
) => {
|
||||
fireEvent.change(wrapper.getElementsByClassName('ant-input')?.[index], { target: { value } });
|
||||
await sleep();
|
||||
}
|
||||
};
|
||||
|
||||
function testList(name, renderField) {
|
||||
const testList = (
|
||||
name: string,
|
||||
renderField: (value: FormListFieldData) => React.ReactNode,
|
||||
): void => {
|
||||
it(name, async () => {
|
||||
jest.useFakeTimers();
|
||||
|
||||
@ -19,30 +27,20 @@ describe('Form.List', () => {
|
||||
<Form.List name="list">
|
||||
{(fields, { add, remove }) => (
|
||||
<>
|
||||
{fields.map(field => renderField(field))}
|
||||
{fields.map(renderField)}
|
||||
<Button className="add" onClick={add}>
|
||||
Add
|
||||
</Button>
|
||||
<Button
|
||||
className="remove-0"
|
||||
onClick={() => {
|
||||
remove(0);
|
||||
}}
|
||||
/>
|
||||
<Button
|
||||
className="remove-1"
|
||||
onClick={() => {
|
||||
remove(1);
|
||||
}}
|
||||
/>
|
||||
<Button className="remove-0" onClick={() => remove(0)} />
|
||||
<Button className="remove-1" onClick={() => remove(1)} />
|
||||
</>
|
||||
)}
|
||||
</Form.List>
|
||||
</Form>,
|
||||
);
|
||||
|
||||
function operate(className) {
|
||||
fireEvent.click(container.querySelector(className));
|
||||
function operate(className: string) {
|
||||
fireEvent.click(container.querySelector(className)!);
|
||||
act(() => {
|
||||
jest.runAllTimers();
|
||||
});
|
||||
@ -75,7 +73,7 @@ describe('Form.List', () => {
|
||||
|
||||
jest.useRealTimers();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
testList('operation correctly', field => (
|
||||
<Form.Item {...field} rules={[{ required: true }]}>
|
||||
@ -93,8 +91,8 @@ describe('Form.List', () => {
|
||||
));
|
||||
|
||||
it('correct onFinish values', async () => {
|
||||
async function click(wrapper, className) {
|
||||
fireEvent.click(wrapper.querySelector(className));
|
||||
async function click(wrapper: ReturnType<typeof render>['container'], className: string) {
|
||||
fireEvent.click(wrapper.querySelector(className)!);
|
||||
}
|
||||
|
||||
const onFinish = jest.fn().mockImplementation(() => {});
|
||||
@ -134,7 +132,7 @@ describe('Form.List', () => {
|
||||
|
||||
await click(container, '.add');
|
||||
await change(container, 0, 'input1');
|
||||
fireEvent.submit(container.querySelector('form'));
|
||||
fireEvent.submit(container.querySelector('form')!);
|
||||
await sleep();
|
||||
expect(onFinish).toHaveBeenLastCalledWith({ list: ['input1'] });
|
||||
|
||||
@ -142,12 +140,12 @@ describe('Form.List', () => {
|
||||
await change(container, 1, 'input2');
|
||||
await click(container, '.add');
|
||||
await change(container, 2, 'input3');
|
||||
fireEvent.submit(container.querySelector('form'));
|
||||
fireEvent.submit(container.querySelector('form')!);
|
||||
await sleep();
|
||||
expect(onFinish).toHaveBeenLastCalledWith({ list: ['input1', 'input2', 'input3'] });
|
||||
|
||||
await click(container, '.remove'); // will remove first input
|
||||
fireEvent.submit(container.querySelector('form'));
|
||||
fireEvent.submit(container.querySelector('form')!);
|
||||
await sleep();
|
||||
expect(onFinish).toHaveBeenLastCalledWith({ list: ['input2', 'input3'] });
|
||||
});
|
||||
@ -155,7 +153,7 @@ describe('Form.List', () => {
|
||||
it('list errors', async () => {
|
||||
jest.useFakeTimers();
|
||||
|
||||
let operation;
|
||||
let operation: FormListOperation;
|
||||
const { container } = render(
|
||||
<Form>
|
||||
<Form.List
|
||||
@ -191,7 +189,7 @@ describe('Form.List', () => {
|
||||
}
|
||||
|
||||
await addItem();
|
||||
expect(container.querySelector('.ant-form-item-explain div').innerHTML).toEqual('At least 2');
|
||||
expect(container.querySelector('.ant-form-item-explain div')?.innerHTML).toEqual('At least 2');
|
||||
|
||||
await addItem();
|
||||
expect(container.getElementsByClassName('ant-form-item-explain div')).toHaveLength(0);
|
||||
@ -221,7 +219,7 @@ describe('Form.List', () => {
|
||||
<Form.List name="list">
|
||||
{fields =>
|
||||
fields.map(field => (
|
||||
<Form.Item key={field.key} {...field}>
|
||||
<Form.Item {...field} key={field.key}>
|
||||
<Input />
|
||||
</Form.Item>
|
||||
))
|
||||
@ -243,7 +241,7 @@ describe('Form.List', () => {
|
||||
};
|
||||
|
||||
const { container } = render(<Demo />);
|
||||
fireEvent.click(container.querySelector('button'));
|
||||
fireEvent.click(container.querySelector('button')!);
|
||||
|
||||
await sleep();
|
||||
|
@ -1,23 +1,21 @@
|
||||
/* eslint-disable react/jsx-key */
|
||||
|
||||
import { mount } from 'enzyme';
|
||||
import React from 'react';
|
||||
import { render, fireEvent } from '../../../tests/utils';
|
||||
import Form from '..';
|
||||
import Button from '../../button';
|
||||
import Input from '../../input';
|
||||
import Button from '../../button';
|
||||
import type { InputRef } from '../../input';
|
||||
|
||||
interface TestProps {
|
||||
show?: boolean;
|
||||
onRef: (node: React.ReactNode, originRef: InputRef) => void;
|
||||
}
|
||||
|
||||
describe('Form.Ref', () => {
|
||||
const Test = ({
|
||||
onRef,
|
||||
show,
|
||||
}: {
|
||||
onRef: (node: React.ReactElement, originRef: React.RefObject<any>) => void;
|
||||
show?: boolean;
|
||||
}) => {
|
||||
const Test: React.FC<TestProps> = ({ show, onRef }) => {
|
||||
const [form] = Form.useForm();
|
||||
const removeRef = React.useRef<any>();
|
||||
const testRef = React.useRef<any>();
|
||||
const listRef = React.useRef<any>();
|
||||
const removeRef = React.useRef<InputRef>(null);
|
||||
const testRef = React.useRef<InputRef>(null);
|
||||
const listRef = React.useRef<InputRef>(null);
|
||||
|
||||
return (
|
||||
<Form form={form} initialValues={{ list: ['light'] }}>
|
||||
@ -34,7 +32,7 @@ describe('Form.Ref', () => {
|
||||
<Form.List name="list">
|
||||
{fields =>
|
||||
fields.map(field => (
|
||||
<Form.Item {...field}>
|
||||
<Form.Item {...field} key={field.key}>
|
||||
<Input ref={listRef} />
|
||||
</Form.Item>
|
||||
))
|
||||
@ -44,7 +42,7 @@ describe('Form.Ref', () => {
|
||||
<Button
|
||||
className="ref-item"
|
||||
onClick={() => {
|
||||
onRef(form.getFieldInstance('test'), testRef.current);
|
||||
onRef(form.getFieldInstance('test'), testRef.current!);
|
||||
}}
|
||||
>
|
||||
Form.Item
|
||||
@ -52,7 +50,7 @@ describe('Form.Ref', () => {
|
||||
<Button
|
||||
className="ref-list"
|
||||
onClick={() => {
|
||||
onRef(form.getFieldInstance(['list', 0]), listRef.current);
|
||||
onRef(form.getFieldInstance(['list', 0]), listRef.current!);
|
||||
}}
|
||||
>
|
||||
Form.List
|
||||
@ -60,7 +58,7 @@ describe('Form.Ref', () => {
|
||||
<Button
|
||||
className="ref-remove"
|
||||
onClick={() => {
|
||||
onRef(form.getFieldInstance('remove'), removeRef.current);
|
||||
onRef(form.getFieldInstance('remove'), removeRef.current!);
|
||||
}}
|
||||
>
|
||||
Removed
|
||||
@ -71,21 +69,20 @@ describe('Form.Ref', () => {
|
||||
|
||||
it('should ref work', () => {
|
||||
const onRef = jest.fn();
|
||||
const wrapper = mount(<Test onRef={onRef} show />);
|
||||
const { container, rerender } = render(<Test onRef={onRef} show />);
|
||||
|
||||
wrapper.find('.ref-item').last().simulate('click');
|
||||
fireEvent.click(container.querySelector('.ref-item')!);
|
||||
expect(onRef).toHaveBeenCalled();
|
||||
expect(onRef.mock.calls[0][0]).toBe(onRef.mock.calls[0][1]);
|
||||
|
||||
onRef.mockReset();
|
||||
wrapper.find('.ref-list').last().simulate('click');
|
||||
fireEvent.click(container.querySelector('.ref-list')!);
|
||||
expect(onRef).toHaveBeenCalled();
|
||||
expect(onRef.mock.calls[0][0]).toBe(onRef.mock.calls[0][1]);
|
||||
|
||||
onRef.mockReset();
|
||||
wrapper.setProps({ show: false });
|
||||
wrapper.update();
|
||||
wrapper.find('.ref-remove').last().simulate('click');
|
||||
rerender(<Test onRef={onRef} show={false} />);
|
||||
fireEvent.click(container.querySelector('.ref-remove')!);
|
||||
expect(onRef).toHaveBeenCalledWith(undefined, null);
|
||||
});
|
||||
});
|
||||
|
@ -17,13 +17,12 @@ describe('Form.typescript', () => {
|
||||
</Form.Item>
|
||||
</Form>
|
||||
);
|
||||
|
||||
expect(form).toBeTruthy();
|
||||
});
|
||||
|
||||
describe('generic', () => {
|
||||
it('hooks', () => {
|
||||
const Demo = () => {
|
||||
const Demo: React.FC = () => {
|
||||
const [form] = Form.useForm<FormValues>();
|
||||
|
||||
form.setFieldsValue({ path1: { path2: 2333 } });
|
||||
@ -70,7 +69,7 @@ describe('Form.typescript', () => {
|
||||
});
|
||||
|
||||
it('FormItem renderProps support generic', () => {
|
||||
const Demo = () => (
|
||||
const Demo: React.FC = () => (
|
||||
<Form<FormValues>>
|
||||
<Form.Item<FormValues>>
|
||||
{({ getFieldsValue }) => {
|
||||
@ -89,7 +88,7 @@ describe('Form.typescript', () => {
|
||||
|
||||
// TODO: @crazyair fix for value types
|
||||
it('useWatch', () => {
|
||||
const Demo = () => {
|
||||
const Demo: React.FC = () => {
|
||||
const [form] = Form.useForm<FormValues>();
|
||||
const value = Form.useWatch('username', form);
|
||||
|
||||
|
@ -9772,7 +9772,7 @@ exports[`renders ./components/input/demo/tooltip.md extend context correctly 1`]
|
||||
Array [
|
||||
<input
|
||||
class="ant-input"
|
||||
maxlength="25"
|
||||
maxlength="16"
|
||||
placeholder="Input a number"
|
||||
style="width: 120px;"
|
||||
type="text"
|
||||
|
@ -3554,7 +3554,7 @@ exports[`renders ./components/input/demo/textarea-show-count.md correctly 1`] =
|
||||
exports[`renders ./components/input/demo/tooltip.md correctly 1`] = `
|
||||
<input
|
||||
class="ant-input"
|
||||
maxlength="25"
|
||||
maxlength="16"
|
||||
placeholder="Input a number"
|
||||
style="width: 120px;"
|
||||
type="text"
|
||||
|
@ -58,7 +58,7 @@ const NumericInput = (props: NumericInputProps) => {
|
||||
onChange={handleChange}
|
||||
onBlur={handleBlur}
|
||||
placeholder="Input a number"
|
||||
maxLength={25}
|
||||
maxLength={16}
|
||||
/>
|
||||
</Tooltip>
|
||||
);
|
||||
|
@ -10,8 +10,14 @@ export interface AvatarProps extends Omit<SkeletonElementProps, 'shape'> {
|
||||
shape?: 'circle' | 'square';
|
||||
}
|
||||
|
||||
const SkeletonAvatar = (props: AvatarProps) => {
|
||||
const { prefixCls: customizePrefixCls, className, active } = props;
|
||||
const SkeletonAvatar: React.FC<AvatarProps> = props => {
|
||||
const {
|
||||
prefixCls: customizePrefixCls,
|
||||
className,
|
||||
active,
|
||||
shape = 'circle',
|
||||
size = 'default',
|
||||
} = props;
|
||||
const { getPrefixCls } = React.useContext(ConfigContext);
|
||||
const prefixCls = getPrefixCls('skeleton', customizePrefixCls);
|
||||
const [wrapSSR, hashId] = useStyle(prefixCls);
|
||||
@ -29,14 +35,9 @@ const SkeletonAvatar = (props: AvatarProps) => {
|
||||
|
||||
return wrapSSR(
|
||||
<div className={cls}>
|
||||
<Element prefixCls={`${prefixCls}-avatar`} {...otherProps} />
|
||||
<Element prefixCls={`${prefixCls}-avatar`} shape={shape} size={size} {...otherProps} />
|
||||
</div>,
|
||||
);
|
||||
};
|
||||
|
||||
SkeletonAvatar.defaultProps = {
|
||||
size: 'default',
|
||||
shape: 'circle',
|
||||
};
|
||||
|
||||
export default SkeletonAvatar;
|
||||
|
@ -12,8 +12,14 @@ export interface SkeletonButtonProps extends Omit<SkeletonElementProps, 'size'>
|
||||
block?: boolean;
|
||||
}
|
||||
|
||||
const SkeletonButton = (props: SkeletonButtonProps) => {
|
||||
const { prefixCls: customizePrefixCls, className, active, block = false } = props;
|
||||
const SkeletonButton: React.FC<SkeletonButtonProps> = props => {
|
||||
const {
|
||||
prefixCls: customizePrefixCls,
|
||||
className,
|
||||
active,
|
||||
block = false,
|
||||
size = 'default',
|
||||
} = props;
|
||||
const { getPrefixCls } = React.useContext(ConfigContext);
|
||||
const prefixCls = getPrefixCls('skeleton', customizePrefixCls);
|
||||
const [wrapSSR, hashId] = useStyle(prefixCls);
|
||||
@ -32,13 +38,9 @@ const SkeletonButton = (props: SkeletonButtonProps) => {
|
||||
|
||||
return wrapSSR(
|
||||
<div className={cls}>
|
||||
<Element prefixCls={`${prefixCls}-button`} {...otherProps} />
|
||||
<Element prefixCls={`${prefixCls}-button`} size={size} {...otherProps} />
|
||||
</div>,
|
||||
);
|
||||
};
|
||||
|
||||
SkeletonButton.defaultProps = {
|
||||
size: 'default',
|
||||
};
|
||||
|
||||
export default SkeletonButton;
|
||||
|
@ -10,7 +10,7 @@ export interface SkeletonElementProps {
|
||||
active?: boolean;
|
||||
}
|
||||
|
||||
const Element = (props: SkeletonElementProps) => {
|
||||
const Element: React.FC<SkeletonElementProps> = props => {
|
||||
const { prefixCls, className, style, size, shape } = props;
|
||||
|
||||
const sizeCls = classNames({
|
||||
@ -24,14 +24,17 @@ const Element = (props: SkeletonElementProps) => {
|
||||
[`${prefixCls}-round`]: shape === 'round',
|
||||
});
|
||||
|
||||
const sizeStyle: React.CSSProperties =
|
||||
typeof size === 'number'
|
||||
? {
|
||||
width: size,
|
||||
height: size,
|
||||
lineHeight: `${size}px`,
|
||||
}
|
||||
: {};
|
||||
const sizeStyle = React.useMemo<React.CSSProperties>(
|
||||
() =>
|
||||
typeof size === 'number'
|
||||
? {
|
||||
width: size,
|
||||
height: size,
|
||||
lineHeight: `${size}px`,
|
||||
}
|
||||
: {},
|
||||
[size],
|
||||
);
|
||||
|
||||
return (
|
||||
<span
|
||||
|
@ -9,7 +9,7 @@ export interface SkeletonImageProps extends Omit<SkeletonElementProps, 'size' |
|
||||
const path =
|
||||
'M365.714286 329.142857q0 45.714286-32.036571 77.677714t-77.677714 32.036571-77.677714-32.036571-32.036571-77.677714 32.036571-77.677714 77.677714-32.036571 77.677714 32.036571 32.036571 77.677714zM950.857143 548.571429l0 256-804.571429 0 0-109.714286 182.857143-182.857143 91.428571 91.428571 292.571429-292.571429zM1005.714286 146.285714l-914.285714 0q-7.460571 0-12.873143 5.412571t-5.412571 12.873143l0 694.857143q0 7.460571 5.412571 12.873143t12.873143 5.412571l914.285714 0q7.460571 0 12.873143-5.412571t5.412571-12.873143l0-694.857143q0-7.460571-5.412571-12.873143t-12.873143-5.412571zM1097.142857 164.571429l0 694.857143q0 37.741714-26.843429 64.585143t-64.585143 26.843429l-914.285714 0q-37.741714 0-64.585143-26.843429t-26.843429-64.585143l0-694.857143q0-37.741714 26.843429-64.585143t64.585143-26.843429l914.285714 0q37.741714 0 64.585143 26.843429t26.843429 64.585143z';
|
||||
|
||||
const SkeletonImage = (props: SkeletonImageProps) => {
|
||||
const SkeletonImage: React.FC<SkeletonImageProps> = props => {
|
||||
const { prefixCls: customizePrefixCls, className, style, active } = props;
|
||||
const { getPrefixCls } = React.useContext(ConfigContext);
|
||||
const prefixCls = getPrefixCls('skeleton', customizePrefixCls);
|
||||
|
@ -12,8 +12,8 @@ export interface SkeletonInputProps extends Omit<SkeletonElementProps, 'size' |
|
||||
block?: boolean;
|
||||
}
|
||||
|
||||
const SkeletonInput = (props: SkeletonInputProps) => {
|
||||
const { prefixCls: customizePrefixCls, className, active, block } = props;
|
||||
const SkeletonInput: React.FC<SkeletonInputProps> = props => {
|
||||
const { prefixCls: customizePrefixCls, className, active, block, size = 'default' } = props;
|
||||
const { getPrefixCls } = React.useContext(ConfigContext);
|
||||
const prefixCls = getPrefixCls('skeleton', customizePrefixCls);
|
||||
const [wrapSSR, hashId] = useStyle(prefixCls);
|
||||
@ -32,13 +32,9 @@ const SkeletonInput = (props: SkeletonInputProps) => {
|
||||
|
||||
return wrapSSR(
|
||||
<div className={cls}>
|
||||
<Element prefixCls={`${prefixCls}-input`} {...otherProps} />
|
||||
<Element prefixCls={`${prefixCls}-input`} size={size} {...otherProps} />
|
||||
</div>,
|
||||
);
|
||||
};
|
||||
|
||||
SkeletonInput.defaultProps = {
|
||||
size: 'default',
|
||||
};
|
||||
|
||||
export default SkeletonInput;
|
||||
|
@ -10,7 +10,7 @@ export interface SkeletonNodeProps extends Omit<SkeletonElementProps, 'size' | '
|
||||
}
|
||||
|
||||
const SkeletonNode: React.FC<SkeletonNodeProps> = props => {
|
||||
const { prefixCls: customizePrefixCls, className, style, active } = props;
|
||||
const { prefixCls: customizePrefixCls, className, style, active, children } = props;
|
||||
const { getPrefixCls } = React.useContext(ConfigContext);
|
||||
const prefixCls = getPrefixCls('skeleton', customizePrefixCls);
|
||||
|
||||
@ -23,7 +23,7 @@ const SkeletonNode: React.FC<SkeletonNodeProps> = props => {
|
||||
className,
|
||||
);
|
||||
|
||||
const content = props.children ?? <DotChartOutlined />;
|
||||
const content = children ?? <DotChartOutlined />;
|
||||
|
||||
return (
|
||||
<div className={cls}>
|
||||
|
@ -11,7 +11,7 @@ export interface SkeletonParagraphProps {
|
||||
rows?: number;
|
||||
}
|
||||
|
||||
const Paragraph = (props: SkeletonParagraphProps) => {
|
||||
const Paragraph: React.FC<SkeletonParagraphProps> = props => {
|
||||
const getWidth = (index: number) => {
|
||||
const { width, rows = 2 } = props;
|
||||
if (Array.isArray(width)) {
|
||||
|
@ -77,16 +77,24 @@ function getParagraphBasicProps(hasAvatar: boolean, hasTitle: boolean): Skeleton
|
||||
return basicProps;
|
||||
}
|
||||
|
||||
const Skeleton = (props: SkeletonProps) => {
|
||||
interface CompoundedComponent {
|
||||
Button: typeof SkeletonButton;
|
||||
Avatar: typeof SkeletonAvatar;
|
||||
Input: typeof SkeletonInput;
|
||||
Image: typeof SkeletonImage;
|
||||
Node: typeof SkeletonNode;
|
||||
}
|
||||
|
||||
const Skeleton: React.FC<SkeletonProps> & CompoundedComponent = props => {
|
||||
const {
|
||||
prefixCls: customizePrefixCls,
|
||||
loading,
|
||||
className,
|
||||
style,
|
||||
children,
|
||||
avatar,
|
||||
title,
|
||||
paragraph,
|
||||
avatar = false,
|
||||
title = true,
|
||||
paragraph = true,
|
||||
active,
|
||||
round,
|
||||
} = props;
|
||||
@ -101,7 +109,7 @@ const Skeleton = (props: SkeletonProps) => {
|
||||
const hasParagraph = !!paragraph;
|
||||
|
||||
// Avatar
|
||||
let avatarNode;
|
||||
let avatarNode: React.ReactNode;
|
||||
if (hasAvatar) {
|
||||
const avatarProps: SkeletonAvatarProps = {
|
||||
prefixCls: `${prefixCls}-avatar`,
|
||||
@ -116,10 +124,10 @@ const Skeleton = (props: SkeletonProps) => {
|
||||
);
|
||||
}
|
||||
|
||||
let contentNode;
|
||||
let contentNode: React.ReactNode;
|
||||
if (hasTitle || hasParagraph) {
|
||||
// Title
|
||||
let $title;
|
||||
let $title: React.ReactNode;
|
||||
if (hasTitle) {
|
||||
const titleProps: SkeletonTitleProps = {
|
||||
prefixCls: `${prefixCls}-title`,
|
||||
@ -131,7 +139,7 @@ const Skeleton = (props: SkeletonProps) => {
|
||||
}
|
||||
|
||||
// Paragraph
|
||||
let paragraphNode;
|
||||
let paragraphNode: React.ReactNode;
|
||||
if (hasParagraph) {
|
||||
const paragraphProps: SkeletonParagraphProps = {
|
||||
prefixCls: `${prefixCls}-paragraph`,
|
||||
@ -172,12 +180,6 @@ const Skeleton = (props: SkeletonProps) => {
|
||||
return typeof children !== 'undefined' ? (children as React.ReactElement) : null;
|
||||
};
|
||||
|
||||
Skeleton.defaultProps = {
|
||||
avatar: false,
|
||||
title: true,
|
||||
paragraph: true,
|
||||
};
|
||||
|
||||
Skeleton.Button = SkeletonButton;
|
||||
Skeleton.Avatar = SkeletonAvatar;
|
||||
Skeleton.Input = SkeletonInput;
|
||||
|
@ -9,7 +9,7 @@ export interface SkeletonTitleProps {
|
||||
width?: number | string;
|
||||
}
|
||||
|
||||
const Title = ({ prefixCls, className, width, style }: SkeletonTitleProps) => (
|
||||
const Title: React.FC<SkeletonTitleProps> = ({ prefixCls, className, width, style }) => (
|
||||
<h3 className={classNames(prefixCls, className)} style={{ width, ...style }} />
|
||||
);
|
||||
|
||||
|
@ -3,7 +3,7 @@ import React from 'react';
|
||||
import { render } from '@testing-library/react';
|
||||
import debounce from 'lodash/debounce';
|
||||
import Spin from '..';
|
||||
import { sleep } from '../../../tests/utils';
|
||||
import { waitFakeTimer } from '../../../tests/utils';
|
||||
|
||||
jest.mock('lodash/debounce');
|
||||
(debounce as jest.Mock).mockImplementation((...args: any[]) =>
|
||||
@ -19,19 +19,17 @@ describe('delay spinning', () => {
|
||||
});
|
||||
|
||||
it('should render when delay is init set', async () => {
|
||||
jest.useFakeTimers();
|
||||
const { container } = render(<Spin spinning delay={100} />);
|
||||
|
||||
expect(container.querySelector('.ant-spin')?.classList.contains('ant-spin-spinning')).toEqual(
|
||||
false,
|
||||
);
|
||||
expect(container.querySelector('.ant-spin-spinning')).toBeFalsy();
|
||||
|
||||
// use await not jest.runAllTimers()
|
||||
// because of https://github.com/facebook/jest/issues/3465
|
||||
await sleep(500);
|
||||
await waitFakeTimer();
|
||||
|
||||
expect(container.querySelector('.ant-spin')?.classList.contains('ant-spin-spinning')).toEqual(
|
||||
true,
|
||||
);
|
||||
expect(container.querySelector('.ant-spin-spinning')).toBeTruthy();
|
||||
|
||||
jest.clearAllTimers();
|
||||
jest.useRealTimers();
|
||||
});
|
||||
|
||||
it('should cancel debounce function when unmount', async () => {
|
||||
|
@ -16584,9 +16584,6 @@ Array [
|
||||
<span
|
||||
class="ant-badge-status-dot ant-badge-status-success"
|
||||
/>
|
||||
<span
|
||||
class="ant-badge-status-text"
|
||||
/>
|
||||
</span>
|
||||
Finished
|
||||
</span>
|
||||
@ -16804,9 +16801,6 @@ Array [
|
||||
<span
|
||||
class="ant-badge-status-dot ant-badge-status-success"
|
||||
/>
|
||||
<span
|
||||
class="ant-badge-status-text"
|
||||
/>
|
||||
</span>
|
||||
Finished
|
||||
</span>
|
||||
@ -17024,9 +17018,6 @@ Array [
|
||||
<span
|
||||
class="ant-badge-status-dot ant-badge-status-success"
|
||||
/>
|
||||
<span
|
||||
class="ant-badge-status-text"
|
||||
/>
|
||||
</span>
|
||||
Finished
|
||||
</span>
|
||||
@ -17634,9 +17625,6 @@ Array [
|
||||
<span
|
||||
class="ant-badge-status-dot ant-badge-status-success"
|
||||
/>
|
||||
<span
|
||||
class="ant-badge-status-text"
|
||||
/>
|
||||
</span>
|
||||
Finished
|
||||
</span>
|
||||
@ -17854,9 +17842,6 @@ Array [
|
||||
<span
|
||||
class="ant-badge-status-dot ant-badge-status-success"
|
||||
/>
|
||||
<span
|
||||
class="ant-badge-status-text"
|
||||
/>
|
||||
</span>
|
||||
Finished
|
||||
</span>
|
||||
@ -18074,9 +18059,6 @@ Array [
|
||||
<span
|
||||
class="ant-badge-status-dot ant-badge-status-success"
|
||||
/>
|
||||
<span
|
||||
class="ant-badge-status-text"
|
||||
/>
|
||||
</span>
|
||||
Finished
|
||||
</span>
|
||||
@ -18684,9 +18666,6 @@ Array [
|
||||
<span
|
||||
class="ant-badge-status-dot ant-badge-status-success"
|
||||
/>
|
||||
<span
|
||||
class="ant-badge-status-text"
|
||||
/>
|
||||
</span>
|
||||
Finished
|
||||
</span>
|
||||
@ -18904,9 +18883,6 @@ Array [
|
||||
<span
|
||||
class="ant-badge-status-dot ant-badge-status-success"
|
||||
/>
|
||||
<span
|
||||
class="ant-badge-status-text"
|
||||
/>
|
||||
</span>
|
||||
Finished
|
||||
</span>
|
||||
@ -19124,9 +19100,6 @@ Array [
|
||||
<span
|
||||
class="ant-badge-status-dot ant-badge-status-success"
|
||||
/>
|
||||
<span
|
||||
class="ant-badge-status-text"
|
||||
/>
|
||||
</span>
|
||||
Finished
|
||||
</span>
|
||||
|
@ -12758,9 +12758,6 @@ Array [
|
||||
<span
|
||||
class="ant-badge-status-dot ant-badge-status-success"
|
||||
/>
|
||||
<span
|
||||
class="ant-badge-status-text"
|
||||
/>
|
||||
</span>
|
||||
Finished
|
||||
</span>
|
||||
@ -12847,9 +12844,6 @@ Array [
|
||||
<span
|
||||
class="ant-badge-status-dot ant-badge-status-success"
|
||||
/>
|
||||
<span
|
||||
class="ant-badge-status-text"
|
||||
/>
|
||||
</span>
|
||||
Finished
|
||||
</span>
|
||||
@ -12936,9 +12930,6 @@ Array [
|
||||
<span
|
||||
class="ant-badge-status-dot ant-badge-status-success"
|
||||
/>
|
||||
<span
|
||||
class="ant-badge-status-text"
|
||||
/>
|
||||
</span>
|
||||
Finished
|
||||
</span>
|
||||
@ -13415,9 +13406,6 @@ Array [
|
||||
<span
|
||||
class="ant-badge-status-dot ant-badge-status-success"
|
||||
/>
|
||||
<span
|
||||
class="ant-badge-status-text"
|
||||
/>
|
||||
</span>
|
||||
Finished
|
||||
</span>
|
||||
@ -13504,9 +13492,6 @@ Array [
|
||||
<span
|
||||
class="ant-badge-status-dot ant-badge-status-success"
|
||||
/>
|
||||
<span
|
||||
class="ant-badge-status-text"
|
||||
/>
|
||||
</span>
|
||||
Finished
|
||||
</span>
|
||||
@ -13593,9 +13578,6 @@ Array [
|
||||
<span
|
||||
class="ant-badge-status-dot ant-badge-status-success"
|
||||
/>
|
||||
<span
|
||||
class="ant-badge-status-text"
|
||||
/>
|
||||
</span>
|
||||
Finished
|
||||
</span>
|
||||
@ -14072,9 +14054,6 @@ Array [
|
||||
<span
|
||||
class="ant-badge-status-dot ant-badge-status-success"
|
||||
/>
|
||||
<span
|
||||
class="ant-badge-status-text"
|
||||
/>
|
||||
</span>
|
||||
Finished
|
||||
</span>
|
||||
@ -14161,9 +14140,6 @@ Array [
|
||||
<span
|
||||
class="ant-badge-status-dot ant-badge-status-success"
|
||||
/>
|
||||
<span
|
||||
class="ant-badge-status-text"
|
||||
/>
|
||||
</span>
|
||||
Finished
|
||||
</span>
|
||||
@ -14250,9 +14226,6 @@ Array [
|
||||
<span
|
||||
class="ant-badge-status-dot ant-badge-status-success"
|
||||
/>
|
||||
<span
|
||||
class="ant-badge-status-text"
|
||||
/>
|
||||
</span>
|
||||
Finished
|
||||
</span>
|
||||
|
@ -13,6 +13,7 @@ import renderSwitcherIcon from './utils/iconUtil';
|
||||
import useStyle from './style';
|
||||
|
||||
export type SwitcherIcon = React.ReactNode | ((props: AntTreeNodeProps) => React.ReactNode);
|
||||
export type TreeLeafIcon = React.ReactNode | ((props: AntTreeNodeProps) => React.ReactNode);
|
||||
|
||||
export interface AntdTreeNodeAttribute {
|
||||
eventKey: string;
|
||||
@ -109,7 +110,7 @@ export interface TreeProps<T extends BasicDataNode = DataNode>
|
||||
RcTreeProps<T>,
|
||||
'prefixCls' | 'showLine' | 'direction' | 'draggable' | 'icon' | 'switcherIcon'
|
||||
> {
|
||||
showLine?: boolean | { showLeafIcon: boolean };
|
||||
showLine?: boolean | { showLeafIcon: boolean | TreeLeafIcon };
|
||||
className?: string;
|
||||
/** 是否支持多选 */
|
||||
multiple?: boolean;
|
||||
|
@ -1786,24 +1786,8 @@ Array [
|
||||
class="ant-tree-switcher ant-tree-switcher-noop"
|
||||
>
|
||||
<span
|
||||
aria-label="file"
|
||||
class="anticon anticon-file ant-tree-switcher-line-icon"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="file"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M854.6 288.6L639.4 73.4c-6-6-14.1-9.4-22.6-9.4H192c-17.7 0-32 14.3-32 32v832c0 17.7 14.3 32 32 32h640c17.7 0 32-14.3 32-32V311.3c0-8.5-3.4-16.7-9.4-22.7zM790.2 326H602V137.8L790.2 326zm1.8 562H232V136h302v216a42 42 0 0042 42h216v494z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
class="ant-tree-switcher-leaf-line"
|
||||
/>
|
||||
</span>
|
||||
<span
|
||||
class="ant-tree-node-content-wrapper ant-tree-node-content-wrapper-normal"
|
||||
@ -1882,24 +1866,8 @@ Array [
|
||||
class="ant-tree-switcher ant-tree-switcher-noop"
|
||||
>
|
||||
<span
|
||||
aria-label="file"
|
||||
class="anticon anticon-file ant-tree-switcher-line-icon"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="file"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M854.6 288.6L639.4 73.4c-6-6-14.1-9.4-22.6-9.4H192c-17.7 0-32 14.3-32 32v832c0 17.7 14.3 32 32 32h640c17.7 0 32-14.3 32-32V311.3c0-8.5-3.4-16.7-9.4-22.7zM790.2 326H602V137.8L790.2 326zm1.8 562H232V136h302v216a42 42 0 0042 42h216v494z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
class="ant-tree-switcher-leaf-line"
|
||||
/>
|
||||
</span>
|
||||
<span
|
||||
class="ant-tree-node-content-wrapper ant-tree-node-content-wrapper-normal"
|
||||
@ -1978,24 +1946,8 @@ Array [
|
||||
class="ant-tree-switcher ant-tree-switcher-noop"
|
||||
>
|
||||
<span
|
||||
aria-label="file"
|
||||
class="anticon anticon-file ant-tree-switcher-line-icon"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="file"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M854.6 288.6L639.4 73.4c-6-6-14.1-9.4-22.6-9.4H192c-17.7 0-32 14.3-32 32v832c0 17.7 14.3 32 32 32h640c17.7 0 32-14.3 32-32V311.3c0-8.5-3.4-16.7-9.4-22.7zM790.2 326H602V137.8L790.2 326zm1.8 562H232V136h302v216a42 42 0 0042 42h216v494z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
class="ant-tree-switcher-leaf-line"
|
||||
/>
|
||||
</span>
|
||||
<span
|
||||
class="ant-tree-node-content-wrapper ant-tree-node-content-wrapper-normal"
|
||||
@ -2167,24 +2119,8 @@ Array [
|
||||
class="ant-tree-switcher ant-tree-switcher-noop"
|
||||
>
|
||||
<span
|
||||
aria-label="file"
|
||||
class="anticon anticon-file ant-tree-switcher-line-icon"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="file"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M854.6 288.6L639.4 73.4c-6-6-14.1-9.4-22.6-9.4H192c-17.7 0-32 14.3-32 32v832c0 17.7 14.3 32 32 32h640c17.7 0 32-14.3 32-32V311.3c0-8.5-3.4-16.7-9.4-22.7zM790.2 326H602V137.8L790.2 326zm1.8 562H232V136h302v216a42 42 0 0042 42h216v494z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
class="ant-tree-switcher-leaf-line"
|
||||
/>
|
||||
</span>
|
||||
<span
|
||||
class="ant-tree-node-content-wrapper ant-tree-node-content-wrapper-normal"
|
||||
@ -2348,24 +2284,8 @@ Array [
|
||||
class="ant-tree-switcher ant-tree-switcher-noop"
|
||||
>
|
||||
<span
|
||||
aria-label="file"
|
||||
class="anticon anticon-file ant-tree-switcher-line-icon"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="file"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M854.6 288.6L639.4 73.4c-6-6-14.1-9.4-22.6-9.4H192c-17.7 0-32 14.3-32 32v832c0 17.7 14.3 32 32 32h640c17.7 0 32-14.3 32-32V311.3c0-8.5-3.4-16.7-9.4-22.7zM790.2 326H602V137.8L790.2 326zm1.8 562H232V136h302v216a42 42 0 0042 42h216v494z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
class="ant-tree-switcher-leaf-line"
|
||||
/>
|
||||
</span>
|
||||
<span
|
||||
class="ant-tree-node-content-wrapper ant-tree-node-content-wrapper-normal"
|
||||
@ -3186,27 +3106,166 @@ exports[`renders ./components/tree/demo/line.md extend context correctly 1`] = `
|
||||
</button>
|
||||
<br />
|
||||
<br />
|
||||
showLeafIcon:
|
||||
<button
|
||||
aria-checked="true"
|
||||
class="ant-switch ant-switch-checked"
|
||||
role="switch"
|
||||
type="button"
|
||||
showLeafIcon:
|
||||
<div
|
||||
class="ant-select ant-select-single ant-select-show-arrow"
|
||||
>
|
||||
<div
|
||||
class="ant-switch-handle"
|
||||
/>
|
||||
<span
|
||||
class="ant-switch-inner"
|
||||
class="ant-select-selector"
|
||||
>
|
||||
<span
|
||||
class="ant-switch-inner-checked"
|
||||
/>
|
||||
class="ant-select-selection-search"
|
||||
>
|
||||
<input
|
||||
aria-activedescendant="rc_select_test_list_test"
|
||||
aria-autocomplete="list"
|
||||
aria-controls="rc_select_test_list"
|
||||
aria-haspopup="listbox"
|
||||
aria-owns="rc_select_test_list"
|
||||
autocomplete="off"
|
||||
class="ant-select-selection-search-input"
|
||||
id="rc_select_test"
|
||||
readonly=""
|
||||
role="combobox"
|
||||
style="opacity: 0;"
|
||||
type="search"
|
||||
unselectable="on"
|
||||
value=""
|
||||
/>
|
||||
</span>
|
||||
<span
|
||||
class="ant-switch-inner-unchecked"
|
||||
/>
|
||||
class="ant-select-selection-item"
|
||||
title="True"
|
||||
>
|
||||
True
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<div
|
||||
class="ant-select-dropdown ant-slide-up-appear ant-slide-up-appear-prepare ant-slide-up"
|
||||
style="opacity: 0;"
|
||||
>
|
||||
<div>
|
||||
<div
|
||||
id="rc_select_test_list"
|
||||
role="listbox"
|
||||
style="height: 0px; width: 0px; overflow: hidden;"
|
||||
>
|
||||
<div
|
||||
aria-label="True"
|
||||
aria-selected="true"
|
||||
id="rc_select_test_list_test"
|
||||
role="option"
|
||||
>
|
||||
true
|
||||
</div>
|
||||
<div
|
||||
aria-label="False"
|
||||
aria-selected="false"
|
||||
id="rc_select_test_list_test"
|
||||
role="option"
|
||||
>
|
||||
false
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="rc-virtual-list"
|
||||
style="position: relative;"
|
||||
>
|
||||
<div
|
||||
class="rc-virtual-list-holder"
|
||||
style="max-height: 256px; overflow-y: auto;"
|
||||
>
|
||||
<div>
|
||||
<div
|
||||
class="rc-virtual-list-holder-inner"
|
||||
style="display: flex; flex-direction: column;"
|
||||
>
|
||||
<div
|
||||
aria-selected="true"
|
||||
class="ant-select-item ant-select-item-option ant-select-item-option-active ant-select-item-option-selected"
|
||||
title="True"
|
||||
>
|
||||
<div
|
||||
class="ant-select-item-option-content"
|
||||
>
|
||||
True
|
||||
</div>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
class="ant-select-item-option-state"
|
||||
style="user-select: none;"
|
||||
unselectable="on"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
aria-selected="false"
|
||||
class="ant-select-item ant-select-item-option"
|
||||
title="False"
|
||||
>
|
||||
<div
|
||||
class="ant-select-item-option-content"
|
||||
>
|
||||
False
|
||||
</div>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
class="ant-select-item-option-state"
|
||||
style="user-select: none;"
|
||||
unselectable="on"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
aria-selected="false"
|
||||
class="ant-select-item ant-select-item-option"
|
||||
title="Custom icon"
|
||||
>
|
||||
<div
|
||||
class="ant-select-item-option-content"
|
||||
>
|
||||
Custom icon
|
||||
</div>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
class="ant-select-item-option-state"
|
||||
style="user-select: none;"
|
||||
unselectable="on"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
class="ant-select-arrow"
|
||||
style="user-select: none;"
|
||||
unselectable="on"
|
||||
>
|
||||
<span
|
||||
aria-label="down"
|
||||
class="anticon anticon-down ant-select-suffix"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="down"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M884 256h-75c-5.1 0-9.9 2.5-12.9 6.6L512 654.2 227.9 262.6c-3-4.1-7.8-6.6-12.9-6.6h-75c-6.5 0-10.3 7.4-6.5 12.7l352.6 486.1c12.8 17.6 39 17.6 51.7 0l352.6-486.1c3.9-5.3.1-12.7-6.4-12.7z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-tree ant-tree-icon-hide ant-tree-show-line"
|
||||
@ -4012,24 +4071,8 @@ exports[`renders ./components/tree/demo/switcher-icon.md extend context correctl
|
||||
class="ant-tree-switcher ant-tree-switcher-noop"
|
||||
>
|
||||
<span
|
||||
aria-label="file"
|
||||
class="anticon anticon-file ant-tree-switcher-line-icon"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="file"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M854.6 288.6L639.4 73.4c-6-6-14.1-9.4-22.6-9.4H192c-17.7 0-32 14.3-32 32v832c0 17.7 14.3 32 32 32h640c17.7 0 32-14.3 32-32V311.3c0-8.5-3.4-16.7-9.4-22.7zM790.2 326H602V137.8L790.2 326zm1.8 562H232V136h302v216a42 42 0 0042 42h216v494z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
class="ant-tree-switcher-leaf-line"
|
||||
/>
|
||||
</span>
|
||||
<span
|
||||
class="ant-tree-node-content-wrapper ant-tree-node-content-wrapper-normal"
|
||||
@ -4062,24 +4105,8 @@ exports[`renders ./components/tree/demo/switcher-icon.md extend context correctl
|
||||
class="ant-tree-switcher ant-tree-switcher-noop"
|
||||
>
|
||||
<span
|
||||
aria-label="file"
|
||||
class="anticon anticon-file ant-tree-switcher-line-icon"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="file"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M854.6 288.6L639.4 73.4c-6-6-14.1-9.4-22.6-9.4H192c-17.7 0-32 14.3-32 32v832c0 17.7 14.3 32 32 32h640c17.7 0 32-14.3 32-32V311.3c0-8.5-3.4-16.7-9.4-22.7zM790.2 326H602V137.8L790.2 326zm1.8 562H232V136h302v216a42 42 0 0042 42h216v494z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
class="ant-tree-switcher-leaf-line"
|
||||
/>
|
||||
</span>
|
||||
<span
|
||||
class="ant-tree-node-content-wrapper ant-tree-node-content-wrapper-normal"
|
||||
@ -4112,24 +4139,8 @@ exports[`renders ./components/tree/demo/switcher-icon.md extend context correctl
|
||||
class="ant-tree-switcher ant-tree-switcher-noop"
|
||||
>
|
||||
<span
|
||||
aria-label="file"
|
||||
class="anticon anticon-file ant-tree-switcher-line-icon"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="file"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M854.6 288.6L639.4 73.4c-6-6-14.1-9.4-22.6-9.4H192c-17.7 0-32 14.3-32 32v832c0 17.7 14.3 32 32 32h640c17.7 0 32-14.3 32-32V311.3c0-8.5-3.4-16.7-9.4-22.7zM790.2 326H602V137.8L790.2 326zm1.8 562H232V136h302v216a42 42 0 0042 42h216v494z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
class="ant-tree-switcher-leaf-line"
|
||||
/>
|
||||
</span>
|
||||
<span
|
||||
class="ant-tree-node-content-wrapper ant-tree-node-content-wrapper-normal"
|
||||
|
@ -1786,24 +1786,8 @@ Array [
|
||||
class="ant-tree-switcher ant-tree-switcher-noop"
|
||||
>
|
||||
<span
|
||||
aria-label="file"
|
||||
class="anticon anticon-file ant-tree-switcher-line-icon"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="file"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M854.6 288.6L639.4 73.4c-6-6-14.1-9.4-22.6-9.4H192c-17.7 0-32 14.3-32 32v832c0 17.7 14.3 32 32 32h640c17.7 0 32-14.3 32-32V311.3c0-8.5-3.4-16.7-9.4-22.7zM790.2 326H602V137.8L790.2 326zm1.8 562H232V136h302v216a42 42 0 0042 42h216v494z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
class="ant-tree-switcher-leaf-line"
|
||||
/>
|
||||
</span>
|
||||
<span
|
||||
class="ant-tree-node-content-wrapper ant-tree-node-content-wrapper-normal"
|
||||
@ -1882,24 +1866,8 @@ Array [
|
||||
class="ant-tree-switcher ant-tree-switcher-noop"
|
||||
>
|
||||
<span
|
||||
aria-label="file"
|
||||
class="anticon anticon-file ant-tree-switcher-line-icon"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="file"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M854.6 288.6L639.4 73.4c-6-6-14.1-9.4-22.6-9.4H192c-17.7 0-32 14.3-32 32v832c0 17.7 14.3 32 32 32h640c17.7 0 32-14.3 32-32V311.3c0-8.5-3.4-16.7-9.4-22.7zM790.2 326H602V137.8L790.2 326zm1.8 562H232V136h302v216a42 42 0 0042 42h216v494z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
class="ant-tree-switcher-leaf-line"
|
||||
/>
|
||||
</span>
|
||||
<span
|
||||
class="ant-tree-node-content-wrapper ant-tree-node-content-wrapper-normal"
|
||||
@ -1978,24 +1946,8 @@ Array [
|
||||
class="ant-tree-switcher ant-tree-switcher-noop"
|
||||
>
|
||||
<span
|
||||
aria-label="file"
|
||||
class="anticon anticon-file ant-tree-switcher-line-icon"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="file"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M854.6 288.6L639.4 73.4c-6-6-14.1-9.4-22.6-9.4H192c-17.7 0-32 14.3-32 32v832c0 17.7 14.3 32 32 32h640c17.7 0 32-14.3 32-32V311.3c0-8.5-3.4-16.7-9.4-22.7zM790.2 326H602V137.8L790.2 326zm1.8 562H232V136h302v216a42 42 0 0042 42h216v494z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
class="ant-tree-switcher-leaf-line"
|
||||
/>
|
||||
</span>
|
||||
<span
|
||||
class="ant-tree-node-content-wrapper ant-tree-node-content-wrapper-normal"
|
||||
@ -2167,24 +2119,8 @@ Array [
|
||||
class="ant-tree-switcher ant-tree-switcher-noop"
|
||||
>
|
||||
<span
|
||||
aria-label="file"
|
||||
class="anticon anticon-file ant-tree-switcher-line-icon"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="file"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M854.6 288.6L639.4 73.4c-6-6-14.1-9.4-22.6-9.4H192c-17.7 0-32 14.3-32 32v832c0 17.7 14.3 32 32 32h640c17.7 0 32-14.3 32-32V311.3c0-8.5-3.4-16.7-9.4-22.7zM790.2 326H602V137.8L790.2 326zm1.8 562H232V136h302v216a42 42 0 0042 42h216v494z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
class="ant-tree-switcher-leaf-line"
|
||||
/>
|
||||
</span>
|
||||
<span
|
||||
class="ant-tree-node-content-wrapper ant-tree-node-content-wrapper-normal"
|
||||
@ -2348,24 +2284,8 @@ Array [
|
||||
class="ant-tree-switcher ant-tree-switcher-noop"
|
||||
>
|
||||
<span
|
||||
aria-label="file"
|
||||
class="anticon anticon-file ant-tree-switcher-line-icon"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="file"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M854.6 288.6L639.4 73.4c-6-6-14.1-9.4-22.6-9.4H192c-17.7 0-32 14.3-32 32v832c0 17.7 14.3 32 32 32h640c17.7 0 32-14.3 32-32V311.3c0-8.5-3.4-16.7-9.4-22.7zM790.2 326H602V137.8L790.2 326zm1.8 562H232V136h302v216a42 42 0 0042 42h216v494z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
class="ant-tree-switcher-leaf-line"
|
||||
/>
|
||||
</span>
|
||||
<span
|
||||
class="ant-tree-node-content-wrapper ant-tree-node-content-wrapper-normal"
|
||||
@ -3186,27 +3106,67 @@ exports[`renders ./components/tree/demo/line.md correctly 1`] = `
|
||||
</button>
|
||||
<br />
|
||||
<br />
|
||||
showLeafIcon:
|
||||
<button
|
||||
aria-checked="true"
|
||||
class="ant-switch ant-switch-checked"
|
||||
role="switch"
|
||||
type="button"
|
||||
showLeafIcon:
|
||||
<div
|
||||
class="ant-select ant-select-single ant-select-show-arrow"
|
||||
>
|
||||
<div
|
||||
class="ant-switch-handle"
|
||||
/>
|
||||
<span
|
||||
class="ant-switch-inner"
|
||||
class="ant-select-selector"
|
||||
>
|
||||
<span
|
||||
class="ant-switch-inner-checked"
|
||||
/>
|
||||
class="ant-select-selection-search"
|
||||
>
|
||||
<input
|
||||
aria-activedescendant="rc_select_test_list_test"
|
||||
aria-autocomplete="list"
|
||||
aria-controls="rc_select_test_list"
|
||||
aria-haspopup="listbox"
|
||||
aria-owns="rc_select_test_list"
|
||||
autocomplete="off"
|
||||
class="ant-select-selection-search-input"
|
||||
id="rc_select_test"
|
||||
readonly=""
|
||||
role="combobox"
|
||||
style="opacity: 0;"
|
||||
type="search"
|
||||
unselectable="on"
|
||||
value=""
|
||||
/>
|
||||
</span>
|
||||
<span
|
||||
class="ant-switch-inner-unchecked"
|
||||
/>
|
||||
class="ant-select-selection-item"
|
||||
title="True"
|
||||
>
|
||||
True
|
||||
</span>
|
||||
</div>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
class="ant-select-arrow"
|
||||
style="user-select: none;"
|
||||
unselectable="on"
|
||||
>
|
||||
<span
|
||||
aria-label="down"
|
||||
class="anticon anticon-down ant-select-suffix"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="down"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M884 256h-75c-5.1 0-9.9 2.5-12.9 6.6L512 654.2 227.9 262.6c-3-4.1-7.8-6.6-12.9-6.6h-75c-6.5 0-10.3 7.4-6.5 12.7l352.6 486.1c12.8 17.6 39 17.6 51.7 0l352.6-486.1c3.9-5.3.1-12.7-6.4-12.7z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-tree ant-tree-icon-hide ant-tree-show-line"
|
||||
@ -4012,24 +3972,8 @@ exports[`renders ./components/tree/demo/switcher-icon.md correctly 1`] = `
|
||||
class="ant-tree-switcher ant-tree-switcher-noop"
|
||||
>
|
||||
<span
|
||||
aria-label="file"
|
||||
class="anticon anticon-file ant-tree-switcher-line-icon"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="file"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M854.6 288.6L639.4 73.4c-6-6-14.1-9.4-22.6-9.4H192c-17.7 0-32 14.3-32 32v832c0 17.7 14.3 32 32 32h640c17.7 0 32-14.3 32-32V311.3c0-8.5-3.4-16.7-9.4-22.7zM790.2 326H602V137.8L790.2 326zm1.8 562H232V136h302v216a42 42 0 0042 42h216v494z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
class="ant-tree-switcher-leaf-line"
|
||||
/>
|
||||
</span>
|
||||
<span
|
||||
class="ant-tree-node-content-wrapper ant-tree-node-content-wrapper-normal"
|
||||
@ -4062,24 +4006,8 @@ exports[`renders ./components/tree/demo/switcher-icon.md correctly 1`] = `
|
||||
class="ant-tree-switcher ant-tree-switcher-noop"
|
||||
>
|
||||
<span
|
||||
aria-label="file"
|
||||
class="anticon anticon-file ant-tree-switcher-line-icon"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="file"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M854.6 288.6L639.4 73.4c-6-6-14.1-9.4-22.6-9.4H192c-17.7 0-32 14.3-32 32v832c0 17.7 14.3 32 32 32h640c17.7 0 32-14.3 32-32V311.3c0-8.5-3.4-16.7-9.4-22.7zM790.2 326H602V137.8L790.2 326zm1.8 562H232V136h302v216a42 42 0 0042 42h216v494z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
class="ant-tree-switcher-leaf-line"
|
||||
/>
|
||||
</span>
|
||||
<span
|
||||
class="ant-tree-node-content-wrapper ant-tree-node-content-wrapper-normal"
|
||||
@ -4112,24 +4040,8 @@ exports[`renders ./components/tree/demo/switcher-icon.md correctly 1`] = `
|
||||
class="ant-tree-switcher ant-tree-switcher-noop"
|
||||
>
|
||||
<span
|
||||
aria-label="file"
|
||||
class="anticon anticon-file ant-tree-switcher-line-icon"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="file"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M854.6 288.6L639.4 73.4c-6-6-14.1-9.4-22.6-9.4H192c-17.7 0-32 14.3-32 32v832c0 17.7 14.3 32 32 32h640c17.7 0 32-14.3 32-32V311.3c0-8.5-3.4-16.7-9.4-22.7zM790.2 326H602V137.8L790.2 326zm1.8 562H232V136h302v216a42 42 0 0042 42h216v494z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
class="ant-tree-switcher-leaf-line"
|
||||
/>
|
||||
</span>
|
||||
<span
|
||||
class="ant-tree-node-content-wrapper ant-tree-node-content-wrapper-normal"
|
||||
|
@ -1,5 +1,5 @@
|
||||
import React from 'react';
|
||||
import { render } from '../../../tests/utils';
|
||||
import { render, screen } from '../../../tests/utils';
|
||||
import Tree from '../index';
|
||||
import type { AntTreeNodeProps } from '../Tree';
|
||||
|
||||
@ -36,20 +36,59 @@ describe('Tree', () => {
|
||||
const { container } = render(
|
||||
<Tree switcherIcon={<i className="switcherIcon" />} defaultExpandAll>
|
||||
<TreeNode icon="icon">
|
||||
<TreeNode id="node1" title="node1" icon="icon" key="0-0-2" />
|
||||
<TreeNode id="node2" title="node2" key="0-0-3" />
|
||||
<TreeNode title="node1" icon="icon" key="0-0-2" />
|
||||
<TreeNode title="node2" key="0-0-3" />
|
||||
</TreeNode>
|
||||
</Tree>,
|
||||
);
|
||||
expect(container.querySelectorAll('.switcherIcon').length).toBe(1);
|
||||
});
|
||||
|
||||
it('leaf nodes should render custom icons when provided', () => {
|
||||
const { container } = render(
|
||||
<Tree showLine={{ showLeafIcon: <i className="customLeafIcon" /> }} defaultExpandAll>
|
||||
<TreeNode icon="icon">
|
||||
<TreeNode title="node1" icon="icon" key="0-0-2" />
|
||||
<TreeNode title="node2" key="0-0-3" />
|
||||
</TreeNode>
|
||||
</Tree>,
|
||||
);
|
||||
expect(container.querySelectorAll('.customLeafIcon').length).toBe(2);
|
||||
});
|
||||
|
||||
it('leaf nodes should render custom icons when provided as render function', () => {
|
||||
const { container } = render(
|
||||
<Tree showLine={{ showLeafIcon: () => <i className="customLeafIcon" /> }} defaultExpandAll>
|
||||
<TreeNode icon="icon">
|
||||
<TreeNode title="node1" icon="icon" key="0-0-2" />
|
||||
<TreeNode title="node2" key="0-0-3" />
|
||||
</TreeNode>
|
||||
</Tree>,
|
||||
);
|
||||
|
||||
expect(container.querySelectorAll('.customLeafIcon').length).toBe(2);
|
||||
});
|
||||
|
||||
it('leaf nodes should render custom icons when provided as string', async () => {
|
||||
render(
|
||||
<Tree showLine={{ showLeafIcon: 'customLeafIcon' }} defaultExpandAll>
|
||||
<TreeNode icon="icon">
|
||||
<TreeNode title="node1" icon="icon" key="0-0-2" />
|
||||
<TreeNode title="node2" key="0-0-3" />
|
||||
</TreeNode>
|
||||
</Tree>,
|
||||
);
|
||||
|
||||
const customIcons = await screen.findAllByText('customLeafIcon');
|
||||
expect(customIcons).toHaveLength(2);
|
||||
});
|
||||
|
||||
it('switcherIcon in Tree could be string', () => {
|
||||
const { asFragment } = render(
|
||||
<Tree switcherIcon="switcherIcon" defaultExpandAll>
|
||||
<TreeNode icon="icon">
|
||||
<TreeNode id="node1" title="node1" icon="icon" key="0-0-2" />
|
||||
<TreeNode id="node2" title="node2" key="0-0-3" />
|
||||
<TreeNode title="node1" icon="icon" key="0-0-2" />
|
||||
<TreeNode title="node2" key="0-0-3" />
|
||||
</TreeNode>
|
||||
</Tree>,
|
||||
);
|
||||
@ -66,8 +105,8 @@ describe('Tree', () => {
|
||||
const { asFragment } = render(
|
||||
<Tree switcherIcon="switcherIcon" defaultExpandAll loadData={onLoadData}>
|
||||
<TreeNode icon="icon">
|
||||
<TreeNode id="node1" title="node1" icon="icon" key="0-0-2" />
|
||||
<TreeNode id="node2" title="node2" key="0-0-3" />
|
||||
<TreeNode title="node1" icon="icon" key="0-0-2" />
|
||||
<TreeNode title="node2" key="0-0-3" />
|
||||
</TreeNode>
|
||||
</Tree>,
|
||||
);
|
||||
@ -83,8 +122,8 @@ describe('Tree', () => {
|
||||
}
|
||||
>
|
||||
<TreeNode icon="icon">
|
||||
<TreeNode id="node1" title="node1" icon="icon" key="0-0-2" />
|
||||
<TreeNode id="node2" title="node2" key="0-0-3" />
|
||||
<TreeNode title="node1" icon="icon" key="0-0-2" />
|
||||
<TreeNode title="node2" key="0-0-3" />
|
||||
</TreeNode>
|
||||
</Tree>,
|
||||
);
|
||||
|
@ -1,45 +0,0 @@
|
||||
import { calcRangeKeys } from '../utils/dictUtil';
|
||||
|
||||
describe('Tree util', () => {
|
||||
describe('calcRangeKeys', () => {
|
||||
const treeData = [
|
||||
{ key: '0-0', children: [{ key: '0-0-0' }, { key: '0-0-1' }] },
|
||||
{ key: '0-1', children: [{ key: '0-1-0' }, { key: '0-1-1' }] },
|
||||
{
|
||||
key: '0-2',
|
||||
children: [
|
||||
{ key: '0-2-0', children: [{ key: '0-2-0-0' }, { key: '0-2-0-1' }, { key: '0-2-0-2' }] },
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
it('calc range keys', () => {
|
||||
const rangeKeys = calcRangeKeys({
|
||||
treeData,
|
||||
expandedKeys: ['0-0', '0-2', '0-2-0'],
|
||||
startKey: '0-2-0-1',
|
||||
endKey: '0-0-0',
|
||||
});
|
||||
const target = ['0-0-0', '0-0-1', '0-1', '0-2', '0-2-0', '0-2-0-0', '0-2-0-1'];
|
||||
expect(rangeKeys.sort()).toEqual(target.sort());
|
||||
});
|
||||
|
||||
it('return startKey when startKey === endKey', () => {
|
||||
const keys = calcRangeKeys({
|
||||
treeData,
|
||||
expandedKeys: ['0-0', '0-2', '0-2-0'],
|
||||
startKey: '0-0-0',
|
||||
endKey: '0-0-0',
|
||||
});
|
||||
expect(keys).toEqual(['0-0-0']);
|
||||
});
|
||||
|
||||
it('return empty array without startKey and endKey', () => {
|
||||
const keys = calcRangeKeys({
|
||||
treeData,
|
||||
expandedKeys: ['0-0', '0-2', '0-2-0'],
|
||||
});
|
||||
expect(keys).toEqual([]);
|
||||
});
|
||||
});
|
||||
});
|
106
components/tree/__tests__/util.test.tsx
Normal file
106
components/tree/__tests__/util.test.tsx
Normal file
@ -0,0 +1,106 @@
|
||||
import React from 'react';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import { calcRangeKeys } from '../utils/dictUtil';
|
||||
import renderSwitcherIcon from '../utils/iconUtil';
|
||||
|
||||
describe('Tree util', () => {
|
||||
describe('calcRangeKeys', () => {
|
||||
const treeData = [
|
||||
{ key: '0-0', children: [{ key: '0-0-0' }, { key: '0-0-1' }] },
|
||||
{ key: '0-1', children: [{ key: '0-1-0' }, { key: '0-1-1' }] },
|
||||
{
|
||||
key: '0-2',
|
||||
children: [
|
||||
{ key: '0-2-0', children: [{ key: '0-2-0-0' }, { key: '0-2-0-1' }, { key: '0-2-0-2' }] },
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
it('calc range keys', () => {
|
||||
const rangeKeys = calcRangeKeys({
|
||||
treeData,
|
||||
expandedKeys: ['0-0', '0-2', '0-2-0'],
|
||||
startKey: '0-2-0-1',
|
||||
endKey: '0-0-0',
|
||||
});
|
||||
const target = ['0-0-0', '0-0-1', '0-1', '0-2', '0-2-0', '0-2-0-0', '0-2-0-1'];
|
||||
expect(rangeKeys.sort()).toEqual(target.sort());
|
||||
});
|
||||
|
||||
it('return startKey when startKey === endKey', () => {
|
||||
const keys = calcRangeKeys({
|
||||
treeData,
|
||||
expandedKeys: ['0-0', '0-2', '0-2-0'],
|
||||
startKey: '0-0-0',
|
||||
endKey: '0-0-0',
|
||||
});
|
||||
expect(keys).toEqual(['0-0-0']);
|
||||
});
|
||||
|
||||
it('return empty array without startKey and endKey', () => {
|
||||
const keys = calcRangeKeys({
|
||||
treeData,
|
||||
expandedKeys: ['0-0', '0-2', '0-2-0'],
|
||||
});
|
||||
expect(keys).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('renderSwitcherIcon', () => {
|
||||
const prefixCls = 'tree';
|
||||
|
||||
it('returns a loading icon when loading', () => {
|
||||
const { container } = render(
|
||||
<>{renderSwitcherIcon(prefixCls, undefined, true, { loading: true })}</>,
|
||||
);
|
||||
expect(container.getElementsByClassName(`${prefixCls}-switcher-loading-icon`)).toHaveLength(
|
||||
1,
|
||||
);
|
||||
});
|
||||
|
||||
it('returns nothing when node is a leaf without showLine', () => {
|
||||
const { container } = render(
|
||||
<>{renderSwitcherIcon(prefixCls, undefined, false, { loading: false, isLeaf: true })}</>,
|
||||
);
|
||||
expect(container).toBeEmptyDOMElement();
|
||||
});
|
||||
|
||||
it('returns a custom leaf icon when provided', () => {
|
||||
const testId = 'custom-icon';
|
||||
const customLeafIcon = <div data-testid={testId} />;
|
||||
const { container } = render(
|
||||
<>
|
||||
{renderSwitcherIcon(
|
||||
prefixCls,
|
||||
undefined,
|
||||
{ showLeafIcon: customLeafIcon },
|
||||
{ loading: false, isLeaf: true },
|
||||
)}
|
||||
</>,
|
||||
);
|
||||
|
||||
expect(screen.getByTestId(testId)).toBeVisible();
|
||||
expect(
|
||||
container.getElementsByClassName(`${prefixCls}-switcher-line-custom-icon`),
|
||||
).toHaveLength(1);
|
||||
});
|
||||
|
||||
it.each([
|
||||
[`${prefixCls}-switcher-line-icon`, true],
|
||||
[`${prefixCls}-switcher-leaf-line`, false],
|
||||
])('returns %p element when showLeafIcon is %p', (expectedClassName, showLeafIcon) => {
|
||||
const { container } = render(
|
||||
<>
|
||||
{renderSwitcherIcon(
|
||||
prefixCls,
|
||||
undefined,
|
||||
{ showLeafIcon },
|
||||
{ loading: false, isLeaf: true },
|
||||
)}
|
||||
</>,
|
||||
);
|
||||
|
||||
expect(container.getElementsByClassName(expectedClassName)).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
});
|
@ -14,8 +14,8 @@ title:
|
||||
Tree with connected line between nodes, turn on by `showLine`, customize the preseted icon by `switcherIcon`.
|
||||
|
||||
```tsx
|
||||
import { CarryOutOutlined, FormOutlined } from '@ant-design/icons';
|
||||
import { Switch, Tree } from 'antd';
|
||||
import { CarryOutOutlined, CheckOutlined, FormOutlined } from '@ant-design/icons';
|
||||
import { Select, Switch, Tree } from 'antd';
|
||||
import type { DataNode } from 'antd/es/tree';
|
||||
import React, { useState } from 'react';
|
||||
|
||||
@ -85,36 +85,44 @@ const treeData: DataNode[] = [
|
||||
];
|
||||
|
||||
const App: React.FC = () => {
|
||||
const [showLine, setShowLine] = useState<boolean | { showLeafIcon: boolean }>(true);
|
||||
const [showLine, setShowLine] = useState<boolean>(true);
|
||||
const [showIcon, setShowIcon] = useState<boolean>(false);
|
||||
const [showLeafIcon, setShowLeafIcon] = useState<boolean>(true);
|
||||
const [showLeafIcon, setShowLeafIcon] = useState<boolean | React.ReactNode>(true);
|
||||
|
||||
const onSelect = (selectedKeys: React.Key[], info: any) => {
|
||||
console.log('selected', selectedKeys, info);
|
||||
};
|
||||
|
||||
const onSetLeafIcon = (checked: boolean) => {
|
||||
setShowLeafIcon(checked);
|
||||
setShowLine({ showLeafIcon: checked });
|
||||
};
|
||||
const handleLeafIconChange = (value: 'true' | 'false' | 'custom') => {
|
||||
if (value === 'custom') {
|
||||
return setShowLeafIcon(<CheckOutlined />);
|
||||
}
|
||||
|
||||
const onSetShowLine = (checked: boolean) => {
|
||||
setShowLine(checked ? { showLeafIcon } : false);
|
||||
if (value === 'true') {
|
||||
return setShowLeafIcon(true);
|
||||
}
|
||||
|
||||
return setShowLeafIcon(false);
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div style={{ marginBottom: 16 }}>
|
||||
showLine: <Switch checked={!!showLine} onChange={onSetShowLine} />
|
||||
showLine: <Switch checked={!!showLine} onChange={setShowLine} />
|
||||
<br />
|
||||
<br />
|
||||
showIcon: <Switch checked={showIcon} onChange={setShowIcon} />
|
||||
<br />
|
||||
<br />
|
||||
showLeafIcon: <Switch checked={showLeafIcon} onChange={onSetLeafIcon} />
|
||||
showLeafIcon:{' '}
|
||||
<Select defaultValue="true" onChange={handleLeafIconChange}>
|
||||
<Select.Option value="true">True</Select.Option>
|
||||
<Select.Option value="false">False</Select.Option>
|
||||
<Select.Option value="custom">Custom icon</Select.Option>
|
||||
</Select>
|
||||
</div>
|
||||
<Tree
|
||||
showLine={showLine}
|
||||
showLine={showLine ? { showLeafIcon } : false}
|
||||
showIcon={showIcon}
|
||||
defaultExpandedKeys={['0-0-0']}
|
||||
onSelect={onSelect}
|
||||
|
@ -43,7 +43,7 @@ Almost anything can be represented in a tree structure. Examples include directo
|
||||
| selectable | Whether can be selected | boolean | true | |
|
||||
| selectedKeys | (Controlled) Specifies the keys of the selected treeNodes | string\[] | - | |
|
||||
| showIcon | Shows the icon before a TreeNode's title. There is no default style; you must set a custom style for it if set to true | boolean | false | |
|
||||
| showLine | Shows a connecting line | boolean \| {showLeafIcon: boolean} | false | |
|
||||
| showLine | Shows a connecting line | boolean \| {showLeafIcon: boolean \| ReactNode \| ((props: AntTreeNodeProps) => ReactNode)} | false | |
|
||||
| switcherIcon | Customize collapse/expand icon of tree node | ReactNode \| ((props: AntTreeNodeProps) => ReactNode) | - | renderProps: 4.20.0 |
|
||||
| titleRender | Customize tree node title render | (nodeData) => ReactNode | - | 4.5.0 |
|
||||
| treeData | The treeNodes data Array, if set it then you need not to construct children TreeNode. (key should be unique across the whole array) | array<{ key, title, children, \[disabled, selectable] }> | - | |
|
||||
|
@ -17,7 +17,7 @@ cover: https://gw.alipayobjects.com/zos/alicdn/Xh-oWqg9k/Tree.svg
|
||||
### Tree props
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| allowDrop | 是否允许拖拽时放置在该节点 | ({ dropNode, dropPosition }) => boolean | - | |
|
||||
| autoExpandParent | 是否自动展开父节点 | boolean | false | |
|
||||
| blockNode | 是否节点占据一行 | boolean | false | |
|
||||
@ -44,7 +44,7 @@ cover: https://gw.alipayobjects.com/zos/alicdn/Xh-oWqg9k/Tree.svg
|
||||
| selectable | 是否可选中 | boolean | true | |
|
||||
| selectedKeys | (受控)设置选中的树节点 | string\[] | - | |
|
||||
| showIcon | 是否展示 TreeNode title 前的图标,没有默认样式,如设置为 true,需要自行定义图标相关样式 | boolean | false | |
|
||||
| showLine | 是否展示连接线 | boolean \| {showLeafIcon: boolean} | false | |
|
||||
| showLine | 是否展示连接线 | boolean \| {showLeafIcon: boolean \| ReactNode | ((props: AntTreeNodeProps) => ReactNode)} | false | |
|
||||
| switcherIcon | 自定义树节点的展开/折叠图标 | ReactNode \| ((props: AntTreeNodeProps) => ReactNode) | - | renderProps: 4.20.0 |
|
||||
| titleRender | 自定义渲染节点 | (nodeData) => ReactNode | - | 4.5.0 |
|
||||
| treeData | treeNodes 数据,如果设置则不需要手动构造 TreeNode 节点(key 在整个树范围内唯一) | array<{key, title, children, \[disabled, selectable]}> | - | |
|
||||
|
@ -6,12 +6,12 @@ import PlusSquareOutlined from '@ant-design/icons/PlusSquareOutlined';
|
||||
import classNames from 'classnames';
|
||||
import * as React from 'react';
|
||||
import { cloneElement, isValidElement } from '../../_util/reactNode';
|
||||
import type { AntTreeNodeProps, SwitcherIcon } from '../Tree';
|
||||
import type { AntTreeNodeProps, TreeLeafIcon, SwitcherIcon } from '../Tree';
|
||||
|
||||
export default function renderSwitcherIcon(
|
||||
prefixCls: string,
|
||||
switcherIcon: SwitcherIcon,
|
||||
showLine: boolean | { showLeafIcon: boolean } | undefined,
|
||||
showLine: boolean | { showLeafIcon: boolean | TreeLeafIcon } | undefined,
|
||||
treeNodeProps: AntTreeNodeProps,
|
||||
): React.ReactNode {
|
||||
const { isLeaf, expanded, loading } = treeNodeProps;
|
||||
@ -19,18 +19,35 @@ export default function renderSwitcherIcon(
|
||||
if (loading) {
|
||||
return <LoadingOutlined className={`${prefixCls}-switcher-loading-icon`} />;
|
||||
}
|
||||
let showLeafIcon;
|
||||
let showLeafIcon: boolean | TreeLeafIcon;
|
||||
if (showLine && typeof showLine === 'object') {
|
||||
showLeafIcon = showLine.showLeafIcon;
|
||||
}
|
||||
|
||||
if (isLeaf) {
|
||||
if (showLine) {
|
||||
if (typeof showLine === 'object' && !showLeafIcon) {
|
||||
return <span className={`${prefixCls}-switcher-leaf-line`} />;
|
||||
}
|
||||
return <FileOutlined className={`${prefixCls}-switcher-line-icon`} />;
|
||||
if (!showLine) {
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
|
||||
if (typeof showLeafIcon !== 'boolean' && !!showLeafIcon) {
|
||||
const leafIcon =
|
||||
typeof showLeafIcon === 'function' ? showLeafIcon(treeNodeProps) : showLeafIcon;
|
||||
const leafCls = `${prefixCls}-switcher-line-custom-icon`;
|
||||
|
||||
if (isValidElement(leafIcon)) {
|
||||
return cloneElement(leafIcon, {
|
||||
className: classNames(leafIcon.props.className || '', leafCls),
|
||||
});
|
||||
}
|
||||
|
||||
return leafIcon;
|
||||
}
|
||||
|
||||
return showLeafIcon ? (
|
||||
<FileOutlined className={`${prefixCls}-switcher-line-icon`} />
|
||||
) : (
|
||||
<span className={`${prefixCls}-switcher-leaf-line`} />
|
||||
);
|
||||
}
|
||||
|
||||
const switcherCls = `${prefixCls}-switcher-icon`;
|
||||
|
@ -172,6 +172,7 @@ const Ellipsis = ({ enabledMeasure, children, text, width, rows, onEllipsis }: E
|
||||
zIndex: -9999,
|
||||
visibility: 'hidden',
|
||||
pointerEvents: 'none',
|
||||
fontSize: 14,
|
||||
...style,
|
||||
}}
|
||||
>
|
||||
|
@ -107,6 +107,9 @@ function getNode(dom: React.ReactNode, defaultNode: React.ReactNode, needDom?: b
|
||||
}
|
||||
|
||||
function toList<T>(val: T | T[]): T[] {
|
||||
if (val === false) {
|
||||
return [false, false] as T[];
|
||||
}
|
||||
return Array.isArray(val) ? val : [val];
|
||||
}
|
||||
|
||||
|
@ -249,13 +249,13 @@ Array [
|
||||
Ant Design, a design language for background applications, is refined by Ant UED Team. Ant Design, a design language for background applications, is refined by Ant UED Team. Ant Design, a design language for background applications, is refined by Ant UED Team. Ant Design, a design language for background applications, is refined by Ant UED Team. Ant Design, a design language for background applications, is refined by Ant UED Team. Ant Design, a design language for background applications, is refined by Ant UED Team.
|
||||
<span
|
||||
aria-hidden="true"
|
||||
style="position: fixed; display: block; left: 0px; top: 0px; z-index: -9999; visibility: hidden; pointer-events: none; word-break: keep-all; white-space: nowrap;"
|
||||
style="position: fixed; display: block; left: 0px; top: 0px; z-index: -9999; visibility: hidden; pointer-events: none; font-size: 14px; word-break: keep-all; white-space: nowrap;"
|
||||
>
|
||||
lg
|
||||
</span>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
style="position: fixed; display: block; left: 0px; top: 0px; z-index: -9999; visibility: hidden; pointer-events: none; width: 0px; white-space: normal; margin: 0px; padding: 0px;"
|
||||
style="position: fixed; display: block; left: 0px; top: 0px; z-index: -9999; visibility: hidden; pointer-events: none; font-size: 14px; width: 0px; white-space: normal; margin: 0px; padding: 0px;"
|
||||
>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
@ -511,13 +511,13 @@ Array [
|
||||
</div>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
style="position: fixed; display: block; left: 0px; top: 0px; z-index: -9999; visibility: hidden; pointer-events: none; word-break: keep-all; white-space: nowrap;"
|
||||
style="position: fixed; display: block; left: 0px; top: 0px; z-index: -9999; visibility: hidden; pointer-events: none; font-size: 14px; word-break: keep-all; white-space: nowrap;"
|
||||
>
|
||||
lg
|
||||
</span>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
style="position: fixed; display: block; left: 0px; top: 0px; z-index: -9999; visibility: hidden; pointer-events: none; width: 0px; white-space: normal; margin: 0px; padding: 0px;"
|
||||
style="position: fixed; display: block; left: 0px; top: 0px; z-index: -9999; visibility: hidden; pointer-events: none; font-size: 14px; width: 0px; white-space: normal; margin: 0px; padding: 0px;"
|
||||
>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
@ -633,13 +633,13 @@ exports[`renders ./components/typography/demo/ellipsis-middle.md extend context
|
||||
development.
|
||||
<span
|
||||
aria-hidden="true"
|
||||
style="position: fixed; display: block; left: 0px; top: 0px; z-index: -9999; visibility: hidden; pointer-events: none; word-break: keep-all; white-space: nowrap;"
|
||||
style="position: fixed; display: block; left: 0px; top: 0px; z-index: -9999; visibility: hidden; pointer-events: none; font-size: 14px; word-break: keep-all; white-space: nowrap;"
|
||||
>
|
||||
lg
|
||||
</span>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
style="position: fixed; display: block; left: 0px; top: 0px; z-index: -9999; visibility: hidden; pointer-events: none; width: 0px; white-space: normal; margin: 0px; padding: 0px;"
|
||||
style="position: fixed; display: block; left: 0px; top: 0px; z-index: -9999; visibility: hidden; pointer-events: none; font-size: 14px; width: 0px; white-space: normal; margin: 0px; padding: 0px;"
|
||||
>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
@ -1879,13 +1879,13 @@ Array [
|
||||
--William Shakespeare
|
||||
<span
|
||||
aria-hidden="true"
|
||||
style="position: fixed; display: block; left: 0px; top: 0px; z-index: -9999; visibility: hidden; pointer-events: none; word-break: keep-all; white-space: nowrap;"
|
||||
style="position: fixed; display: block; left: 0px; top: 0px; z-index: -9999; visibility: hidden; pointer-events: none; font-size: 14px; word-break: keep-all; white-space: nowrap;"
|
||||
>
|
||||
lg
|
||||
</span>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
style="position: fixed; display: block; left: 0px; top: 0px; z-index: -9999; visibility: hidden; pointer-events: none; width: 0px; white-space: normal; margin: 0px; padding: 0px;"
|
||||
style="position: fixed; display: block; left: 0px; top: 0px; z-index: -9999; visibility: hidden; pointer-events: none; font-size: 14px; width: 0px; white-space: normal; margin: 0px; padding: 0px;"
|
||||
>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
|
@ -249,13 +249,13 @@ Array [
|
||||
Ant Design, a design language for background applications, is refined by Ant UED Team. Ant Design, a design language for background applications, is refined by Ant UED Team. Ant Design, a design language for background applications, is refined by Ant UED Team. Ant Design, a design language for background applications, is refined by Ant UED Team. Ant Design, a design language for background applications, is refined by Ant UED Team. Ant Design, a design language for background applications, is refined by Ant UED Team.
|
||||
<span
|
||||
aria-hidden="true"
|
||||
style="position: fixed; display: block; left: 0px; top: 0px; z-index: -9999; visibility: hidden; pointer-events: none; word-break: keep-all; white-space: nowrap;"
|
||||
style="position: fixed; display: block; left: 0px; top: 0px; z-index: -9999; visibility: hidden; pointer-events: none; font-size: 14px; word-break: keep-all; white-space: nowrap;"
|
||||
>
|
||||
lg
|
||||
</span>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
style="position: fixed; display: block; left: 0px; top: 0px; z-index: -9999; visibility: hidden; pointer-events: none; width: 0px; white-space: normal; margin: 0px; padding: 0px;"
|
||||
style="position: fixed; display: block; left: 0px; top: 0px; z-index: -9999; visibility: hidden; pointer-events: none; font-size: 14px; width: 0px; white-space: normal; margin: 0px; padding: 0px;"
|
||||
>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
@ -439,13 +439,13 @@ Array [
|
||||
</div>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
style="position: fixed; display: block; left: 0px; top: 0px; z-index: -9999; visibility: hidden; pointer-events: none; word-break: keep-all; white-space: nowrap;"
|
||||
style="position: fixed; display: block; left: 0px; top: 0px; z-index: -9999; visibility: hidden; pointer-events: none; font-size: 14px; word-break: keep-all; white-space: nowrap;"
|
||||
>
|
||||
lg
|
||||
</span>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
style="position: fixed; display: block; left: 0px; top: 0px; z-index: -9999; visibility: hidden; pointer-events: none; width: 0px; white-space: normal; margin: 0px; padding: 0px;"
|
||||
style="position: fixed; display: block; left: 0px; top: 0px; z-index: -9999; visibility: hidden; pointer-events: none; font-size: 14px; width: 0px; white-space: normal; margin: 0px; padding: 0px;"
|
||||
>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
@ -513,13 +513,13 @@ exports[`renders ./components/typography/demo/ellipsis-middle.md correctly 1`] =
|
||||
development.
|
||||
<span
|
||||
aria-hidden="true"
|
||||
style="position: fixed; display: block; left: 0px; top: 0px; z-index: -9999; visibility: hidden; pointer-events: none; word-break: keep-all; white-space: nowrap;"
|
||||
style="position: fixed; display: block; left: 0px; top: 0px; z-index: -9999; visibility: hidden; pointer-events: none; font-size: 14px; word-break: keep-all; white-space: nowrap;"
|
||||
>
|
||||
lg
|
||||
</span>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
style="position: fixed; display: block; left: 0px; top: 0px; z-index: -9999; visibility: hidden; pointer-events: none; width: 0px; white-space: normal; margin: 0px; padding: 0px;"
|
||||
style="position: fixed; display: block; left: 0px; top: 0px; z-index: -9999; visibility: hidden; pointer-events: none; font-size: 14px; width: 0px; white-space: normal; margin: 0px; padding: 0px;"
|
||||
>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
@ -1355,13 +1355,13 @@ Array [
|
||||
--William Shakespeare
|
||||
<span
|
||||
aria-hidden="true"
|
||||
style="position: fixed; display: block; left: 0px; top: 0px; z-index: -9999; visibility: hidden; pointer-events: none; word-break: keep-all; white-space: nowrap;"
|
||||
style="position: fixed; display: block; left: 0px; top: 0px; z-index: -9999; visibility: hidden; pointer-events: none; font-size: 14px; word-break: keep-all; white-space: nowrap;"
|
||||
>
|
||||
lg
|
||||
</span>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
style="position: fixed; display: block; left: 0px; top: 0px; z-index: -9999; visibility: hidden; pointer-events: none; width: 0px; white-space: normal; margin: 0px; padding: 0px;"
|
||||
style="position: fixed; display: block; left: 0px; top: 0px; z-index: -9999; visibility: hidden; pointer-events: none; font-size: 14px; width: 0px; white-space: normal; margin: 0px; padding: 0px;"
|
||||
>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
|
@ -5,7 +5,7 @@ import { resetWarned } from 'rc-util/lib/warning';
|
||||
import React from 'react';
|
||||
import mountTest from '../../../tests/shared/mountTest';
|
||||
import rtlTest from '../../../tests/shared/rtlTest';
|
||||
import { fireEvent, render, sleep, waitFor, act } from '../../../tests/utils';
|
||||
import { fireEvent, render, waitFor, act, waitFakeTimer } from '../../../tests/utils';
|
||||
import Base from '../Base';
|
||||
import Link from '../Link';
|
||||
import Paragraph from '../Paragraph';
|
||||
@ -88,6 +88,14 @@ describe('Typography', () => {
|
||||
|
||||
describe('Base', () => {
|
||||
describe('copyable', () => {
|
||||
/**
|
||||
* @param name Test case name
|
||||
* @param text Origin text context
|
||||
* @param target Copy to clipboard text
|
||||
* @param icon Icon
|
||||
* @param tooltips Tooltip config
|
||||
* @param format Copy context format
|
||||
*/
|
||||
function copyTest(
|
||||
name: string,
|
||||
text?: string,
|
||||
@ -99,60 +107,45 @@ describe('Typography', () => {
|
||||
it(name, async () => {
|
||||
jest.useFakeTimers();
|
||||
const onCopy = jest.fn();
|
||||
const { container: wrapper, unmount } = render(
|
||||
const { container, unmount } = render(
|
||||
<Base component="p" copyable={{ text, onCopy, icon, tooltips, format }}>
|
||||
test copy
|
||||
</Base>,
|
||||
);
|
||||
|
||||
if (icon) {
|
||||
expect(wrapper.querySelectorAll('.anticon-smile').length).toBeGreaterThan(0);
|
||||
expect(container.querySelector('.anticon-smile')).toBeTruthy();
|
||||
} else {
|
||||
expect(wrapper.querySelectorAll('.anticon-copy').length).toBeGreaterThan(0);
|
||||
expect(container.querySelector('.anticon-copy')).toBeTruthy();
|
||||
}
|
||||
|
||||
fireEvent.mouseEnter(wrapper.querySelector('.ant-typography-copy')!);
|
||||
// Mouse enter to show tooltip
|
||||
fireEvent.mouseEnter(container.querySelector('.ant-typography-copy')!);
|
||||
act(() => {
|
||||
jest.runAllTimers();
|
||||
jest.advanceTimersByTime(10000);
|
||||
});
|
||||
|
||||
if (tooltips === undefined || tooltips === true) {
|
||||
await waitFor(() => {
|
||||
expect(wrapper.querySelector('.ant-tooltip-inner')?.textContent).toBe('Copy');
|
||||
});
|
||||
expect(container.querySelector('.ant-tooltip-inner')?.textContent).toBe('Copy');
|
||||
} else if (tooltips === false) {
|
||||
await waitFor(() => {
|
||||
expect(wrapper.querySelectorAll('.ant-tooltip-inner').length).toBe(0);
|
||||
});
|
||||
expect(container.querySelector('.ant-tooltip-inner')).toBeFalsy();
|
||||
} else if ((tooltips as any)[0] === '' && (tooltips as any)[1] === '') {
|
||||
await waitFor(() => {
|
||||
expect(wrapper.querySelectorAll('.ant-tooltip-inner').length).toBe(0);
|
||||
});
|
||||
expect(container.querySelector('.ant-tooltip-inner')).toBeFalsy();
|
||||
} else if ((tooltips as any)[0] === '' && (tooltips as any)[1]) {
|
||||
await waitFor(() => {
|
||||
expect(wrapper.querySelectorAll('.ant-tooltip-inner').length).toBe(0);
|
||||
});
|
||||
expect(container.querySelector('.ant-tooltip-inner')).toBeFalsy();
|
||||
} else if ((tooltips as any)[1] === '' && (tooltips as any)[0]) {
|
||||
await waitFor(() => {
|
||||
expect(wrapper.querySelector('.ant-tooltip-inner')?.textContent).toBe(
|
||||
(tooltips as any)[0],
|
||||
);
|
||||
});
|
||||
expect(container.querySelector('.ant-tooltip-inner')?.textContent).toBe(
|
||||
(tooltips as any)[0],
|
||||
);
|
||||
} else {
|
||||
await waitFor(() => {
|
||||
expect(wrapper.querySelector('.ant-tooltip-inner')?.textContent).toBe(
|
||||
(tooltips as any)[0],
|
||||
);
|
||||
});
|
||||
expect(container.querySelector('.ant-tooltip-inner')?.textContent).toBe(
|
||||
(tooltips as any)[0],
|
||||
);
|
||||
}
|
||||
|
||||
fireEvent.click(wrapper.querySelector('.ant-typography-copy')!);
|
||||
jest.useRealTimers();
|
||||
fireEvent.mouseEnter(wrapper.querySelectorAll('.ant-typography-copy')[0]);
|
||||
// tooltips 为 ['', 'xxx'] 时,切换时需要延时 mouseEnterDelay 的时长
|
||||
if (tooltips && (tooltips as any)[0] === '' && (tooltips as any)[1]) {
|
||||
await sleep(150);
|
||||
}
|
||||
// Click to copy
|
||||
fireEvent.click(container.querySelector('.ant-typography-copy')!);
|
||||
await waitFakeTimer(1);
|
||||
|
||||
expect((copy as any).lastStr).toEqual(target);
|
||||
expect((copy as any).lastOptions.format).toEqual(format);
|
||||
@ -165,43 +158,32 @@ describe('Typography', () => {
|
||||
copiedIcon = '.anticon-check';
|
||||
}
|
||||
|
||||
expect(wrapper.querySelectorAll(copiedIcon).length).toBeGreaterThan(0);
|
||||
fireEvent.mouseEnter(wrapper.querySelectorAll('.ant-typography-copy')[0]);
|
||||
expect(container.querySelector(copiedIcon)).toBeTruthy();
|
||||
|
||||
// Timeout will makes copy tooltip back to origin
|
||||
fireEvent.mouseEnter(container.querySelector('.ant-typography-copy')!);
|
||||
await waitFakeTimer(15, 10);
|
||||
|
||||
if (tooltips === undefined || tooltips === true) {
|
||||
await waitFor(() => {
|
||||
expect(wrapper.querySelector('.ant-tooltip-inner')?.textContent).toBe('Copied');
|
||||
});
|
||||
expect(container.querySelector('.ant-tooltip-inner')?.textContent).toBe('Copied');
|
||||
} else if (tooltips === false) {
|
||||
await waitFor(() => {
|
||||
expect(wrapper.querySelectorAll('.ant-tooltip-inner').length).toBe(0);
|
||||
});
|
||||
expect(container.querySelector('.ant-tooltip-inner')).toBeFalsy();
|
||||
} else if (tooltips[0] === '' && tooltips[1] === '') {
|
||||
await waitFor(() => {
|
||||
expect(wrapper.querySelectorAll('.ant-tooltip-inner').length).toBe(0);
|
||||
});
|
||||
expect(container.querySelector('.ant-tooltip-inner')).toBeFalsy();
|
||||
} else if (tooltips[0] === '' && tooltips[1]) {
|
||||
await waitFor(() => {
|
||||
expect(wrapper.querySelector('.ant-tooltip-inner')?.textContent).toBe(tooltips[1]);
|
||||
});
|
||||
expect(container.querySelector('.ant-tooltip-inner')?.textContent).toBe(tooltips[1]);
|
||||
} else if (tooltips[1] === '' && tooltips[0]) {
|
||||
await waitFor(() => {
|
||||
expect(wrapper.querySelector('.ant-tooltip-inner')?.textContent).toBe('');
|
||||
});
|
||||
expect(container.querySelector('.ant-tooltip-inner')?.textContent).toBe('');
|
||||
} else {
|
||||
await waitFor(() => {
|
||||
expect(wrapper.querySelector('.ant-tooltip-inner')?.textContent).toBe(tooltips[1]);
|
||||
});
|
||||
expect(container.querySelector('.ant-tooltip-inner')?.textContent).toBe(tooltips[1]);
|
||||
}
|
||||
|
||||
jest.useFakeTimers();
|
||||
fireEvent.click(wrapper.querySelectorAll('.ant-typography-copy')[0]);
|
||||
jest.runAllTimers();
|
||||
|
||||
// Will set back when 3 seconds pass
|
||||
await sleep(3000);
|
||||
expect(wrapper.querySelectorAll(copiedIcon).length).toBe(0);
|
||||
await waitFakeTimer();
|
||||
expect(container.querySelector(copiedIcon)).toBeFalsy();
|
||||
|
||||
unmount();
|
||||
jest.clearAllTimers();
|
||||
jest.useRealTimers();
|
||||
});
|
||||
}
|
||||
@ -209,7 +191,7 @@ describe('Typography', () => {
|
||||
copyTest('basic copy', undefined, 'test copy');
|
||||
copyTest('customize copy', 'bamboo', 'bamboo');
|
||||
copyTest(
|
||||
'costomize copy with plain text',
|
||||
'customize copy with plain text',
|
||||
'bamboo',
|
||||
'bamboo',
|
||||
undefined,
|
||||
@ -217,14 +199,14 @@ describe('Typography', () => {
|
||||
'text/plain',
|
||||
);
|
||||
copyTest(
|
||||
'costomize copy with html text',
|
||||
'customize copy with html text',
|
||||
'bamboo',
|
||||
'bamboo',
|
||||
undefined,
|
||||
undefined,
|
||||
'text/html',
|
||||
);
|
||||
copyTest('customize copy icon', 'bamboo', 'bamboo', <SmileOutlined />);
|
||||
copyTest('customize copy icon with one', 'bamboo', 'bamboo', <SmileOutlined />);
|
||||
copyTest('customize copy icon by pass array', 'bamboo', 'bamboo', [
|
||||
<SmileOutlined key="copy-icon" />,
|
||||
]);
|
||||
|
@ -2,7 +2,6 @@
|
||||
const fetch = require('isomorphic-fetch');
|
||||
const semver = require('semver');
|
||||
const dayjs = require('dayjs');
|
||||
const inquirer = require('inquirer');
|
||||
const chalk = require('chalk');
|
||||
const { spawnSync } = require('child_process');
|
||||
const packageJson = require('../package.json');
|
||||
@ -102,6 +101,7 @@ const SAFE_DAYS_DIFF = 1000 * 60 * 60 * 24 * 3; // 3 days not update seems to be
|
||||
defaultVersion = distTags.conch;
|
||||
}
|
||||
|
||||
const { default: inquirer } = await import('inquirer');
|
||||
// Selection
|
||||
let { conchVersion } = await inquirer.prompt([
|
||||
{
|
||||
|
@ -8,7 +8,6 @@ const open = require('open');
|
||||
const fs = require('fs-extra');
|
||||
const path = require('path');
|
||||
const simpleGit = require('simple-git');
|
||||
const inquirer = require('inquirer');
|
||||
|
||||
const { JSDOM } = jsdom;
|
||||
const { window } = new JSDOM();
|
||||
@ -54,6 +53,7 @@ function getDescription(entity) {
|
||||
|
||||
async function printLog() {
|
||||
const tags = await git.tags();
|
||||
const { default: inquirer } = await import('inquirer');
|
||||
const { fromVersion } = await inquirer.prompt([
|
||||
{
|
||||
type: 'list',
|
||||
|
@ -2,22 +2,13 @@ import * as React from 'react';
|
||||
import { useIntl } from 'react-intl';
|
||||
import { Card, Row, Col } from 'antd';
|
||||
import { useSiteData } from './util';
|
||||
import type { Icons, Extra } from './util';
|
||||
import './MorePage.less';
|
||||
|
||||
type SourceType = 'zhihu' | 'yuque';
|
||||
|
||||
type Icons = { name: string; href: string }[];
|
||||
|
||||
interface MoreProps {
|
||||
title: string;
|
||||
description: string;
|
||||
date: string;
|
||||
img: string;
|
||||
source: SourceType;
|
||||
href: string;
|
||||
type MoreProps = Partial<Extra> & {
|
||||
icons?: Icons;
|
||||
loading?: boolean;
|
||||
}
|
||||
};
|
||||
|
||||
const MoreCard = ({ title, description, date, img, source, href, icons, loading }: MoreProps) => (
|
||||
<Col xs={24} sm={6}>
|
||||
@ -54,16 +45,14 @@ const MoreCard = ({ title, description, date, img, source, href, icons, loading
|
||||
|
||||
export default function MorePage() {
|
||||
const { locale } = useIntl();
|
||||
const [{ extras, icons }, loading] = useSiteData<any>();
|
||||
const [{ extras, icons }, loading] = useSiteData();
|
||||
const list = extras?.[locale === 'zh-CN' ? 'cn' : 'en'] || [];
|
||||
const loadingProps = { loading: loading || list.length === 0 } as MoreProps;
|
||||
return (
|
||||
<Row gutter={[24, 32]}>
|
||||
{(list || [loadingProps, loadingProps, loadingProps, loadingProps]).map(
|
||||
(more: any, i: number) => (
|
||||
<MoreCard key={more.title || i} {...more} icons={icons} />
|
||||
),
|
||||
)}
|
||||
{(list ?? [loadingProps, loadingProps, loadingProps, loadingProps]).map((more, i) => (
|
||||
<MoreCard key={more.title || i} {...more} icons={icons} />
|
||||
))}
|
||||
</Row>
|
||||
);
|
||||
}
|
||||
|
@ -3,21 +3,14 @@ import classNames from 'classnames';
|
||||
import { FormattedMessage, useIntl } from 'react-intl';
|
||||
import { Row, Col, Typography } from 'antd';
|
||||
import { useSiteData } from './util';
|
||||
import type { Recommendation } from './util';
|
||||
import './RecommendPage.less';
|
||||
|
||||
const { Title, Paragraph } = Typography;
|
||||
|
||||
interface Recommend {
|
||||
title?: string;
|
||||
img?: string;
|
||||
href?: string;
|
||||
popularize?: boolean;
|
||||
description?: string;
|
||||
loading?: boolean;
|
||||
}
|
||||
|
||||
interface RecommendBlockProps extends Recommend {
|
||||
interface RecommendBlockProps extends Recommendation {
|
||||
main?: boolean;
|
||||
loading?: boolean;
|
||||
}
|
||||
|
||||
const RecommendBlock = ({
|
||||
@ -59,7 +52,7 @@ const RecommendBlock = ({
|
||||
|
||||
export default function RecommendPage() {
|
||||
const { locale } = useIntl();
|
||||
const [{ recommendations }, loading] = useSiteData<any>();
|
||||
const [{ recommendations }, loading] = useSiteData();
|
||||
const list = recommendations?.[locale === 'zh-CN' ? 'cn' : 'en'];
|
||||
const isLoading = loading || !list || list.length === 0;
|
||||
return (
|
||||
|
@ -1,6 +1,71 @@
|
||||
/* eslint-disable import/prefer-default-export */
|
||||
import * as React from 'react';
|
||||
|
||||
export interface Author {
|
||||
avatar: string;
|
||||
href: string;
|
||||
type: 'design' | 'develop';
|
||||
name: string;
|
||||
}
|
||||
|
||||
export interface Article {
|
||||
title: string;
|
||||
href: string;
|
||||
date: string;
|
||||
type: 'design' | 'develop';
|
||||
author: Author['name'];
|
||||
}
|
||||
|
||||
export interface Recommendation {
|
||||
title?: string;
|
||||
img?: string;
|
||||
href?: string;
|
||||
popularize?: boolean;
|
||||
description?: string;
|
||||
}
|
||||
|
||||
type SourceType = 'zhihu' | 'yuque';
|
||||
export interface Extra {
|
||||
title: string;
|
||||
description: string;
|
||||
date: string;
|
||||
img: string;
|
||||
source: SourceType;
|
||||
href: string;
|
||||
}
|
||||
|
||||
export interface Icon {
|
||||
name: string;
|
||||
href: string;
|
||||
}
|
||||
|
||||
export type Articles = {
|
||||
cn: Article[];
|
||||
en: Article[];
|
||||
};
|
||||
|
||||
export type Authors = Author[];
|
||||
|
||||
export type Recommendations = {
|
||||
cn: Recommendation[];
|
||||
en: Recommendation[];
|
||||
};
|
||||
|
||||
export type Extras = {
|
||||
cn: Extra[];
|
||||
en: Extra[];
|
||||
};
|
||||
|
||||
export type Icons = Icon[];
|
||||
|
||||
export type SiteData = {
|
||||
articles: Articles;
|
||||
authors: Authors;
|
||||
recommendations: Recommendations;
|
||||
extras: Extras;
|
||||
icons: Icons;
|
||||
};
|
||||
|
||||
export function preLoad(list: string[]) {
|
||||
if (typeof window !== 'undefined') {
|
||||
// 图处预加载;
|
||||
@ -15,12 +80,12 @@ export function preLoad(list: string[]) {
|
||||
}
|
||||
}
|
||||
|
||||
export function useSiteData<T extends object>(): [T, boolean] {
|
||||
const [data, setData] = React.useState<T>({} as any);
|
||||
export function useSiteData(): [Partial<SiteData>, boolean] {
|
||||
const [data, setData] = React.useState<Partial<SiteData>>({});
|
||||
const [loading, setLoading] = React.useState<boolean>(false);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (Object.keys(data).length === 0 && typeof fetch !== 'undefined') {
|
||||
if (Object.keys(data ?? {}).length === 0 && typeof fetch !== 'undefined') {
|
||||
setLoading(true);
|
||||
fetch(`https://render.alipay.com/p/h5data/antd4-config_website-h5data.json`)
|
||||
.then(res => res.json())
|
||||
|
@ -18,7 +18,7 @@ export const FilledIcon: React.FC<CustomIconComponentProps> = props => {
|
||||
'704c0 53 43 96 96 96h704c53 0 96-43 96-96V16' +
|
||||
'0c0-53-43-96-96-96z';
|
||||
return (
|
||||
<svg {...(props as any)} viewBox="0 0 1024 1024">
|
||||
<svg {...props} viewBox="0 0 1024 1024">
|
||||
<path d={path} />
|
||||
</svg>
|
||||
);
|
||||
@ -32,7 +32,7 @@ export const OutlinedIcon: React.FC<CustomIconComponentProps> = props => {
|
||||
'12-12V172c0-6.6 5.4-12 12-12h680c6.6 0 12 5.4' +
|
||||
' 12 12v680c0 6.6-5.4 12-12 12z';
|
||||
return (
|
||||
<svg {...(props as any)} viewBox="0 0 1024 1024">
|
||||
<svg {...props} viewBox="0 0 1024 1024">
|
||||
<path d={path} />
|
||||
</svg>
|
||||
);
|
||||
@ -45,7 +45,7 @@ export const TwoToneIcon: React.FC<CustomIconComponentProps> = props => {
|
||||
'066 16 512z m496 368V144c203.41 0 368 164.622 3' +
|
||||
'68 368 0 203.41-164.622 368-368 368z';
|
||||
return (
|
||||
<svg {...(props as any)} viewBox="0 0 1024 1024">
|
||||
<svg {...props} viewBox="0 0 1024 1024">
|
||||
<path d={path} />
|
||||
</svg>
|
||||
);
|
||||
|
@ -4,30 +4,9 @@ import dayjs from 'dayjs';
|
||||
import { FormattedMessage, useIntl } from 'react-intl';
|
||||
import { Tabs, Skeleton, Avatar, Divider, Empty } from 'antd';
|
||||
import { useSiteData } from '../../Home/util';
|
||||
import type { Article, Authors } from '../../Home/util';
|
||||
import './index.less';
|
||||
|
||||
interface Author {
|
||||
avatar: string;
|
||||
href: string;
|
||||
type: 'design' | 'develop';
|
||||
name: string;
|
||||
}
|
||||
|
||||
interface Article {
|
||||
title: string;
|
||||
href: string;
|
||||
date: string;
|
||||
type: 'design' | 'develop';
|
||||
author: Author['name'];
|
||||
}
|
||||
|
||||
interface Articles {
|
||||
cn: Article[];
|
||||
en: Article[];
|
||||
}
|
||||
|
||||
type Authors = Author[];
|
||||
|
||||
interface ArticleListProps {
|
||||
name: React.ReactNode;
|
||||
data: Article[];
|
||||
@ -63,10 +42,7 @@ const ArticleList: React.FC<ArticleListProps> = ({ name, data = [], authors = []
|
||||
export default () => {
|
||||
const { locale } = useIntl();
|
||||
const isZhCN = locale === 'zh-CN';
|
||||
const [{ articles = { cn: [], en: [] }, authors = [] }, loading] = useSiteData<{
|
||||
articles: Articles;
|
||||
authors: Authors;
|
||||
}>();
|
||||
const [{ articles = { cn: [], en: [] }, authors = [] }, loading] = useSiteData();
|
||||
|
||||
// ========================== Data ==========================
|
||||
const mergedData = React.useMemo(() => {
|
||||
|
@ -65,8 +65,14 @@ export const triggerResize = (target: Element) => {
|
||||
target.getBoundingClientRect = originGetBoundingClientRect;
|
||||
};
|
||||
|
||||
export async function waitFakeTimer(advanceTime = 1000) {
|
||||
for (let i = 0; i < 20; i += 1) {
|
||||
/**
|
||||
* Wait for a time delay. Will wait `advanceTime * times` ms.
|
||||
*
|
||||
* @param advanceTime Default 1000
|
||||
* @param times Default 20
|
||||
*/
|
||||
export async function waitFakeTimer(advanceTime = 1000, times = 20) {
|
||||
for (let i = 0; i < times; i += 1) {
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
await act(async () => {
|
||||
await Promise.resolve();
|
||||
|
Loading…
Reference in New Issue
Block a user