refactor: UploadList use rc-motion instead of rc-animate (#27923)

* chore: Update rc-motion version

* refactor: Move item into single file

* refactor: Use CSSMotion of progress bar

* chore: part style it

* chore: slit style of pic card

* chore: RM count-x

* support appendAction back

* chore: Style smooth

* fix progress makes shaking

* docs: clean up demo

* test: Update snapshot

* test: fix test case

* fix: lint

* test: Update snapshot

* test: coverage

* clean up
This commit is contained in:
二货机器人 2020-11-21 19:00:11 +08:00 committed by GitHub
parent 8a1dfe8af1
commit 388edca10b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 3274 additions and 3107 deletions

View File

@ -13,7 +13,10 @@ export function replaceElement(
): React.ReactNode {
if (!isValidElement(element)) return replacement;
return React.cloneElement(element, typeof props === 'function' ? props(element.props) : props);
return React.cloneElement(
element,
typeof props === 'function' ? props(element.props || {}) : props,
);
}
export function cloneElement(element: React.ReactNode, props?: RenderProps): React.ReactElement {

View File

@ -37674,27 +37674,63 @@ exports[`ConfigProvider components Upload configProvider 1`] = `
class="config-upload-list config-upload-list-text"
>
<div
class=""
class="config-upload-list-text-container"
>
<span>
<div
class="config-upload-list-item config-upload-list-item-done config-upload-list-item-list-type-text"
>
<div
class="config-upload-list-item config-upload-list-item-done config-upload-list-item-list-type-text"
class="config-upload-list-item-info"
>
<div
class="config-upload-list-item-info"
<span
class="config-upload-span"
>
<span>
<div
class="config-upload-text-icon"
<div
class="config-upload-text-icon"
>
<span
aria-label="paper-clip"
class="anticon anticon-paper-clip"
role="img"
>
<svg
aria-hidden="true"
data-icon="paper-clip"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M779.3 196.6c-94.2-94.2-247.6-94.2-341.7 0l-261 260.8c-1.7 1.7-2.6 4-2.6 6.4s.9 4.7 2.6 6.4l36.9 36.9a9 9 0 0012.7 0l261-260.8c32.4-32.4 75.5-50.2 121.3-50.2s88.9 17.8 121.2 50.2c32.4 32.4 50.2 75.5 50.2 121.2 0 45.8-17.8 88.8-50.2 121.2l-266 265.9-43.1 43.1c-40.3 40.3-105.8 40.3-146.1 0-19.5-19.5-30.2-45.4-30.2-73s10.7-53.5 30.2-73l263.9-263.8c6.7-6.6 15.5-10.3 24.9-10.3h.1c9.4 0 18.1 3.7 24.7 10.3 6.7 6.7 10.3 15.5 10.3 24.9 0 9.3-3.7 18.1-10.3 24.7L372.4 653c-1.7 1.7-2.6 4-2.6 6.4s.9 4.7 2.6 6.4l36.9 36.9a9 9 0 0012.7 0l215.6-215.6c19.9-19.9 30.8-46.3 30.8-74.4s-11-54.6-30.8-74.4c-41.1-41.1-107.9-41-149 0L463 364 224.8 602.1A172.22 172.22 0 00174 724.8c0 46.3 18.1 89.8 50.8 122.5 33.9 33.8 78.3 50.7 122.7 50.7 44.4 0 88.8-16.9 122.6-50.7l309.2-309C824.8 492.7 850 432 850 367.5c.1-64.6-25.1-125.3-70.7-170.9z"
/>
</svg>
</span>
</div>
<span
class="config-upload-list-item-name"
title="xxx.png"
>
xxx.png
</span>
<span
class="config-upload-list-item-card-actions"
>
<button
class="config-btn config-btn-text config-btn-sm config-btn-icon-only config-upload-list-item-card-actions-btn"
title="Remove file"
type="button"
>
<span
aria-label="paper-clip"
class="anticon anticon-paper-clip"
aria-label="delete"
class="anticon anticon-delete"
role="img"
tabindex="-1"
>
<svg
aria-hidden="true"
data-icon="paper-clip"
data-icon="delete"
fill="currentColor"
focusable="false"
height="1em"
@ -37702,51 +37738,15 @@ exports[`ConfigProvider components Upload configProvider 1`] = `
width="1em"
>
<path
d="M779.3 196.6c-94.2-94.2-247.6-94.2-341.7 0l-261 260.8c-1.7 1.7-2.6 4-2.6 6.4s.9 4.7 2.6 6.4l36.9 36.9a9 9 0 0012.7 0l261-260.8c32.4-32.4 75.5-50.2 121.3-50.2s88.9 17.8 121.2 50.2c32.4 32.4 50.2 75.5 50.2 121.2 0 45.8-17.8 88.8-50.2 121.2l-266 265.9-43.1 43.1c-40.3 40.3-105.8 40.3-146.1 0-19.5-19.5-30.2-45.4-30.2-73s10.7-53.5 30.2-73l263.9-263.8c6.7-6.6 15.5-10.3 24.9-10.3h.1c9.4 0 18.1 3.7 24.7 10.3 6.7 6.7 10.3 15.5 10.3 24.9 0 9.3-3.7 18.1-10.3 24.7L372.4 653c-1.7 1.7-2.6 4-2.6 6.4s.9 4.7 2.6 6.4l36.9 36.9a9 9 0 0012.7 0l215.6-215.6c19.9-19.9 30.8-46.3 30.8-74.4s-11-54.6-30.8-74.4c-41.1-41.1-107.9-41-149 0L463 364 224.8 602.1A172.22 172.22 0 00174 724.8c0 46.3 18.1 89.8 50.8 122.5 33.9 33.8 78.3 50.7 122.7 50.7 44.4 0 88.8-16.9 122.6-50.7l309.2-309C824.8 492.7 850 432 850 367.5c.1-64.6-25.1-125.3-70.7-170.9z"
d="M360 184h-8c4.4 0 8-3.6 8-8v8h304v-8c0 4.4 3.6 8 8 8h-8v72h72v-80c0-35.3-28.7-64-64-64H352c-35.3 0-64 28.7-64 64v80h72v-72zm504 72H160c-17.7 0-32 14.3-32 32v32c0 4.4 3.6 8 8 8h60.4l24.7 523c1.6 34.1 29.8 61 63.9 61h454c34.2 0 62.3-26.8 63.9-61l24.7-523H888c4.4 0 8-3.6 8-8v-32c0-17.7-14.3-32-32-32zM731.3 840H292.7l-24.2-512h487l-24.2 512z"
/>
</svg>
</span>
</div>
<span
class="config-upload-list-item-name config-upload-list-item-name-icon-count-1"
title="xxx.png"
>
xxx.png
</span>
<span
class="config-upload-list-item-card-actions "
>
<button
class="config-btn config-btn-text config-btn-sm config-btn-icon-only config-upload-list-item-card-actions-btn"
title="Remove file"
type="button"
>
<span
aria-label="delete"
class="anticon anticon-delete"
role="img"
tabindex="-1"
>
<svg
aria-hidden="true"
data-icon="delete"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M360 184h-8c4.4 0 8-3.6 8-8v8h304v-8c0 4.4 3.6 8 8 8h-8v72h72v-80c0-35.3-28.7-64-64-64H352c-35.3 0-64 28.7-64 64v80h72v-72zm504 72H160c-17.7 0-32 14.3-32 32v32c0 4.4 3.6 8 8 8h60.4l24.7 523c1.6 34.1 29.8 61 63.9 61h454c34.2 0 62.3-26.8 63.9-61l24.7-523H888c4.4 0 8-3.6 8-8v-32c0-17.7-14.3-32-32-32zM731.3 840H292.7l-24.2-512h487l-24.2 512z"
/>
</svg>
</span>
</button>
</span>
</button>
</span>
</div>
</span>
</div>
</span>
</div>
</div>
</div>
</span>
@ -37776,27 +37776,63 @@ exports[`ConfigProvider components Upload configProvider componentSize large 1`]
class="config-upload-list config-upload-list-text"
>
<div
class=""
class="config-upload-list-text-container"
>
<span>
<div
class="config-upload-list-item config-upload-list-item-done config-upload-list-item-list-type-text"
>
<div
class="config-upload-list-item config-upload-list-item-done config-upload-list-item-list-type-text"
class="config-upload-list-item-info"
>
<div
class="config-upload-list-item-info"
<span
class="config-upload-span"
>
<span>
<div
class="config-upload-text-icon"
<div
class="config-upload-text-icon"
>
<span
aria-label="paper-clip"
class="anticon anticon-paper-clip"
role="img"
>
<svg
aria-hidden="true"
data-icon="paper-clip"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M779.3 196.6c-94.2-94.2-247.6-94.2-341.7 0l-261 260.8c-1.7 1.7-2.6 4-2.6 6.4s.9 4.7 2.6 6.4l36.9 36.9a9 9 0 0012.7 0l261-260.8c32.4-32.4 75.5-50.2 121.3-50.2s88.9 17.8 121.2 50.2c32.4 32.4 50.2 75.5 50.2 121.2 0 45.8-17.8 88.8-50.2 121.2l-266 265.9-43.1 43.1c-40.3 40.3-105.8 40.3-146.1 0-19.5-19.5-30.2-45.4-30.2-73s10.7-53.5 30.2-73l263.9-263.8c6.7-6.6 15.5-10.3 24.9-10.3h.1c9.4 0 18.1 3.7 24.7 10.3 6.7 6.7 10.3 15.5 10.3 24.9 0 9.3-3.7 18.1-10.3 24.7L372.4 653c-1.7 1.7-2.6 4-2.6 6.4s.9 4.7 2.6 6.4l36.9 36.9a9 9 0 0012.7 0l215.6-215.6c19.9-19.9 30.8-46.3 30.8-74.4s-11-54.6-30.8-74.4c-41.1-41.1-107.9-41-149 0L463 364 224.8 602.1A172.22 172.22 0 00174 724.8c0 46.3 18.1 89.8 50.8 122.5 33.9 33.8 78.3 50.7 122.7 50.7 44.4 0 88.8-16.9 122.6-50.7l309.2-309C824.8 492.7 850 432 850 367.5c.1-64.6-25.1-125.3-70.7-170.9z"
/>
</svg>
</span>
</div>
<span
class="config-upload-list-item-name"
title="xxx.png"
>
xxx.png
</span>
<span
class="config-upload-list-item-card-actions"
>
<button
class="config-btn config-btn-text config-btn-sm config-btn-icon-only config-upload-list-item-card-actions-btn"
title="Remove file"
type="button"
>
<span
aria-label="paper-clip"
class="anticon anticon-paper-clip"
aria-label="delete"
class="anticon anticon-delete"
role="img"
tabindex="-1"
>
<svg
aria-hidden="true"
data-icon="paper-clip"
data-icon="delete"
fill="currentColor"
focusable="false"
height="1em"
@ -37804,51 +37840,15 @@ exports[`ConfigProvider components Upload configProvider componentSize large 1`]
width="1em"
>
<path
d="M779.3 196.6c-94.2-94.2-247.6-94.2-341.7 0l-261 260.8c-1.7 1.7-2.6 4-2.6 6.4s.9 4.7 2.6 6.4l36.9 36.9a9 9 0 0012.7 0l261-260.8c32.4-32.4 75.5-50.2 121.3-50.2s88.9 17.8 121.2 50.2c32.4 32.4 50.2 75.5 50.2 121.2 0 45.8-17.8 88.8-50.2 121.2l-266 265.9-43.1 43.1c-40.3 40.3-105.8 40.3-146.1 0-19.5-19.5-30.2-45.4-30.2-73s10.7-53.5 30.2-73l263.9-263.8c6.7-6.6 15.5-10.3 24.9-10.3h.1c9.4 0 18.1 3.7 24.7 10.3 6.7 6.7 10.3 15.5 10.3 24.9 0 9.3-3.7 18.1-10.3 24.7L372.4 653c-1.7 1.7-2.6 4-2.6 6.4s.9 4.7 2.6 6.4l36.9 36.9a9 9 0 0012.7 0l215.6-215.6c19.9-19.9 30.8-46.3 30.8-74.4s-11-54.6-30.8-74.4c-41.1-41.1-107.9-41-149 0L463 364 224.8 602.1A172.22 172.22 0 00174 724.8c0 46.3 18.1 89.8 50.8 122.5 33.9 33.8 78.3 50.7 122.7 50.7 44.4 0 88.8-16.9 122.6-50.7l309.2-309C824.8 492.7 850 432 850 367.5c.1-64.6-25.1-125.3-70.7-170.9z"
d="M360 184h-8c4.4 0 8-3.6 8-8v8h304v-8c0 4.4 3.6 8 8 8h-8v72h72v-80c0-35.3-28.7-64-64-64H352c-35.3 0-64 28.7-64 64v80h72v-72zm504 72H160c-17.7 0-32 14.3-32 32v32c0 4.4 3.6 8 8 8h60.4l24.7 523c1.6 34.1 29.8 61 63.9 61h454c34.2 0 62.3-26.8 63.9-61l24.7-523H888c4.4 0 8-3.6 8-8v-32c0-17.7-14.3-32-32-32zM731.3 840H292.7l-24.2-512h487l-24.2 512z"
/>
</svg>
</span>
</div>
<span
class="config-upload-list-item-name config-upload-list-item-name-icon-count-1"
title="xxx.png"
>
xxx.png
</span>
<span
class="config-upload-list-item-card-actions "
>
<button
class="config-btn config-btn-text config-btn-sm config-btn-icon-only config-upload-list-item-card-actions-btn"
title="Remove file"
type="button"
>
<span
aria-label="delete"
class="anticon anticon-delete"
role="img"
tabindex="-1"
>
<svg
aria-hidden="true"
data-icon="delete"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M360 184h-8c4.4 0 8-3.6 8-8v8h304v-8c0 4.4 3.6 8 8 8h-8v72h72v-80c0-35.3-28.7-64-64-64H352c-35.3 0-64 28.7-64 64v80h72v-72zm504 72H160c-17.7 0-32 14.3-32 32v32c0 4.4 3.6 8 8 8h60.4l24.7 523c1.6 34.1 29.8 61 63.9 61h454c34.2 0 62.3-26.8 63.9-61l24.7-523H888c4.4 0 8-3.6 8-8v-32c0-17.7-14.3-32-32-32zM731.3 840H292.7l-24.2-512h487l-24.2 512z"
/>
</svg>
</span>
</button>
</span>
</button>
</span>
</div>
</span>
</div>
</span>
</div>
</div>
</div>
</span>
@ -37878,27 +37878,63 @@ exports[`ConfigProvider components Upload configProvider componentSize middle 1`
class="config-upload-list config-upload-list-text"
>
<div
class=""
class="config-upload-list-text-container"
>
<span>
<div
class="config-upload-list-item config-upload-list-item-done config-upload-list-item-list-type-text"
>
<div
class="config-upload-list-item config-upload-list-item-done config-upload-list-item-list-type-text"
class="config-upload-list-item-info"
>
<div
class="config-upload-list-item-info"
<span
class="config-upload-span"
>
<span>
<div
class="config-upload-text-icon"
<div
class="config-upload-text-icon"
>
<span
aria-label="paper-clip"
class="anticon anticon-paper-clip"
role="img"
>
<svg
aria-hidden="true"
data-icon="paper-clip"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M779.3 196.6c-94.2-94.2-247.6-94.2-341.7 0l-261 260.8c-1.7 1.7-2.6 4-2.6 6.4s.9 4.7 2.6 6.4l36.9 36.9a9 9 0 0012.7 0l261-260.8c32.4-32.4 75.5-50.2 121.3-50.2s88.9 17.8 121.2 50.2c32.4 32.4 50.2 75.5 50.2 121.2 0 45.8-17.8 88.8-50.2 121.2l-266 265.9-43.1 43.1c-40.3 40.3-105.8 40.3-146.1 0-19.5-19.5-30.2-45.4-30.2-73s10.7-53.5 30.2-73l263.9-263.8c6.7-6.6 15.5-10.3 24.9-10.3h.1c9.4 0 18.1 3.7 24.7 10.3 6.7 6.7 10.3 15.5 10.3 24.9 0 9.3-3.7 18.1-10.3 24.7L372.4 653c-1.7 1.7-2.6 4-2.6 6.4s.9 4.7 2.6 6.4l36.9 36.9a9 9 0 0012.7 0l215.6-215.6c19.9-19.9 30.8-46.3 30.8-74.4s-11-54.6-30.8-74.4c-41.1-41.1-107.9-41-149 0L463 364 224.8 602.1A172.22 172.22 0 00174 724.8c0 46.3 18.1 89.8 50.8 122.5 33.9 33.8 78.3 50.7 122.7 50.7 44.4 0 88.8-16.9 122.6-50.7l309.2-309C824.8 492.7 850 432 850 367.5c.1-64.6-25.1-125.3-70.7-170.9z"
/>
</svg>
</span>
</div>
<span
class="config-upload-list-item-name"
title="xxx.png"
>
xxx.png
</span>
<span
class="config-upload-list-item-card-actions"
>
<button
class="config-btn config-btn-text config-btn-sm config-btn-icon-only config-upload-list-item-card-actions-btn"
title="Remove file"
type="button"
>
<span
aria-label="paper-clip"
class="anticon anticon-paper-clip"
aria-label="delete"
class="anticon anticon-delete"
role="img"
tabindex="-1"
>
<svg
aria-hidden="true"
data-icon="paper-clip"
data-icon="delete"
fill="currentColor"
focusable="false"
height="1em"
@ -37906,51 +37942,15 @@ exports[`ConfigProvider components Upload configProvider componentSize middle 1`
width="1em"
>
<path
d="M779.3 196.6c-94.2-94.2-247.6-94.2-341.7 0l-261 260.8c-1.7 1.7-2.6 4-2.6 6.4s.9 4.7 2.6 6.4l36.9 36.9a9 9 0 0012.7 0l261-260.8c32.4-32.4 75.5-50.2 121.3-50.2s88.9 17.8 121.2 50.2c32.4 32.4 50.2 75.5 50.2 121.2 0 45.8-17.8 88.8-50.2 121.2l-266 265.9-43.1 43.1c-40.3 40.3-105.8 40.3-146.1 0-19.5-19.5-30.2-45.4-30.2-73s10.7-53.5 30.2-73l263.9-263.8c6.7-6.6 15.5-10.3 24.9-10.3h.1c9.4 0 18.1 3.7 24.7 10.3 6.7 6.7 10.3 15.5 10.3 24.9 0 9.3-3.7 18.1-10.3 24.7L372.4 653c-1.7 1.7-2.6 4-2.6 6.4s.9 4.7 2.6 6.4l36.9 36.9a9 9 0 0012.7 0l215.6-215.6c19.9-19.9 30.8-46.3 30.8-74.4s-11-54.6-30.8-74.4c-41.1-41.1-107.9-41-149 0L463 364 224.8 602.1A172.22 172.22 0 00174 724.8c0 46.3 18.1 89.8 50.8 122.5 33.9 33.8 78.3 50.7 122.7 50.7 44.4 0 88.8-16.9 122.6-50.7l309.2-309C824.8 492.7 850 432 850 367.5c.1-64.6-25.1-125.3-70.7-170.9z"
d="M360 184h-8c4.4 0 8-3.6 8-8v8h304v-8c0 4.4 3.6 8 8 8h-8v72h72v-80c0-35.3-28.7-64-64-64H352c-35.3 0-64 28.7-64 64v80h72v-72zm504 72H160c-17.7 0-32 14.3-32 32v32c0 4.4 3.6 8 8 8h60.4l24.7 523c1.6 34.1 29.8 61 63.9 61h454c34.2 0 62.3-26.8 63.9-61l24.7-523H888c4.4 0 8-3.6 8-8v-32c0-17.7-14.3-32-32-32zM731.3 840H292.7l-24.2-512h487l-24.2 512z"
/>
</svg>
</span>
</div>
<span
class="config-upload-list-item-name config-upload-list-item-name-icon-count-1"
title="xxx.png"
>
xxx.png
</span>
<span
class="config-upload-list-item-card-actions "
>
<button
class="config-btn config-btn-text config-btn-sm config-btn-icon-only config-upload-list-item-card-actions-btn"
title="Remove file"
type="button"
>
<span
aria-label="delete"
class="anticon anticon-delete"
role="img"
tabindex="-1"
>
<svg
aria-hidden="true"
data-icon="delete"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M360 184h-8c4.4 0 8-3.6 8-8v8h304v-8c0 4.4 3.6 8 8 8h-8v72h72v-80c0-35.3-28.7-64-64-64H352c-35.3 0-64 28.7-64 64v80h72v-72zm504 72H160c-17.7 0-32 14.3-32 32v32c0 4.4 3.6 8 8 8h60.4l24.7 523c1.6 34.1 29.8 61 63.9 61h454c34.2 0 62.3-26.8 63.9-61l24.7-523H888c4.4 0 8-3.6 8-8v-32c0-17.7-14.3-32-32-32zM731.3 840H292.7l-24.2-512h487l-24.2 512z"
/>
</svg>
</span>
</button>
</span>
</button>
</span>
</div>
</span>
</div>
</span>
</div>
</div>
</div>
</span>
@ -37980,27 +37980,63 @@ exports[`ConfigProvider components Upload configProvider virtual and dropdownMat
class="ant-upload-list ant-upload-list-text"
>
<div
class=""
class="ant-upload-list-text-container"
>
<span>
<div
class="ant-upload-list-item ant-upload-list-item-done ant-upload-list-item-list-type-text"
>
<div
class="ant-upload-list-item ant-upload-list-item-done ant-upload-list-item-list-type-text"
class="ant-upload-list-item-info"
>
<div
class="ant-upload-list-item-info"
<span
class="ant-upload-span"
>
<span>
<div
class="ant-upload-text-icon"
<div
class="ant-upload-text-icon"
>
<span
aria-label="paper-clip"
class="anticon anticon-paper-clip"
role="img"
>
<svg
aria-hidden="true"
data-icon="paper-clip"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M779.3 196.6c-94.2-94.2-247.6-94.2-341.7 0l-261 260.8c-1.7 1.7-2.6 4-2.6 6.4s.9 4.7 2.6 6.4l36.9 36.9a9 9 0 0012.7 0l261-260.8c32.4-32.4 75.5-50.2 121.3-50.2s88.9 17.8 121.2 50.2c32.4 32.4 50.2 75.5 50.2 121.2 0 45.8-17.8 88.8-50.2 121.2l-266 265.9-43.1 43.1c-40.3 40.3-105.8 40.3-146.1 0-19.5-19.5-30.2-45.4-30.2-73s10.7-53.5 30.2-73l263.9-263.8c6.7-6.6 15.5-10.3 24.9-10.3h.1c9.4 0 18.1 3.7 24.7 10.3 6.7 6.7 10.3 15.5 10.3 24.9 0 9.3-3.7 18.1-10.3 24.7L372.4 653c-1.7 1.7-2.6 4-2.6 6.4s.9 4.7 2.6 6.4l36.9 36.9a9 9 0 0012.7 0l215.6-215.6c19.9-19.9 30.8-46.3 30.8-74.4s-11-54.6-30.8-74.4c-41.1-41.1-107.9-41-149 0L463 364 224.8 602.1A172.22 172.22 0 00174 724.8c0 46.3 18.1 89.8 50.8 122.5 33.9 33.8 78.3 50.7 122.7 50.7 44.4 0 88.8-16.9 122.6-50.7l309.2-309C824.8 492.7 850 432 850 367.5c.1-64.6-25.1-125.3-70.7-170.9z"
/>
</svg>
</span>
</div>
<span
class="ant-upload-list-item-name"
title="xxx.png"
>
xxx.png
</span>
<span
class="ant-upload-list-item-card-actions"
>
<button
class="ant-btn ant-btn-text ant-btn-sm ant-btn-icon-only ant-upload-list-item-card-actions-btn"
title="Remove file"
type="button"
>
<span
aria-label="paper-clip"
class="anticon anticon-paper-clip"
aria-label="delete"
class="anticon anticon-delete"
role="img"
tabindex="-1"
>
<svg
aria-hidden="true"
data-icon="paper-clip"
data-icon="delete"
fill="currentColor"
focusable="false"
height="1em"
@ -38008,51 +38044,15 @@ exports[`ConfigProvider components Upload configProvider virtual and dropdownMat
width="1em"
>
<path
d="M779.3 196.6c-94.2-94.2-247.6-94.2-341.7 0l-261 260.8c-1.7 1.7-2.6 4-2.6 6.4s.9 4.7 2.6 6.4l36.9 36.9a9 9 0 0012.7 0l261-260.8c32.4-32.4 75.5-50.2 121.3-50.2s88.9 17.8 121.2 50.2c32.4 32.4 50.2 75.5 50.2 121.2 0 45.8-17.8 88.8-50.2 121.2l-266 265.9-43.1 43.1c-40.3 40.3-105.8 40.3-146.1 0-19.5-19.5-30.2-45.4-30.2-73s10.7-53.5 30.2-73l263.9-263.8c6.7-6.6 15.5-10.3 24.9-10.3h.1c9.4 0 18.1 3.7 24.7 10.3 6.7 6.7 10.3 15.5 10.3 24.9 0 9.3-3.7 18.1-10.3 24.7L372.4 653c-1.7 1.7-2.6 4-2.6 6.4s.9 4.7 2.6 6.4l36.9 36.9a9 9 0 0012.7 0l215.6-215.6c19.9-19.9 30.8-46.3 30.8-74.4s-11-54.6-30.8-74.4c-41.1-41.1-107.9-41-149 0L463 364 224.8 602.1A172.22 172.22 0 00174 724.8c0 46.3 18.1 89.8 50.8 122.5 33.9 33.8 78.3 50.7 122.7 50.7 44.4 0 88.8-16.9 122.6-50.7l309.2-309C824.8 492.7 850 432 850 367.5c.1-64.6-25.1-125.3-70.7-170.9z"
d="M360 184h-8c4.4 0 8-3.6 8-8v8h304v-8c0 4.4 3.6 8 8 8h-8v72h72v-80c0-35.3-28.7-64-64-64H352c-35.3 0-64 28.7-64 64v80h72v-72zm504 72H160c-17.7 0-32 14.3-32 32v32c0 4.4 3.6 8 8 8h60.4l24.7 523c1.6 34.1 29.8 61 63.9 61h454c34.2 0 62.3-26.8 63.9-61l24.7-523H888c4.4 0 8-3.6 8-8v-32c0-17.7-14.3-32-32-32zM731.3 840H292.7l-24.2-512h487l-24.2 512z"
/>
</svg>
</span>
</div>
<span
class="ant-upload-list-item-name ant-upload-list-item-name-icon-count-1"
title="xxx.png"
>
xxx.png
</span>
<span
class="ant-upload-list-item-card-actions "
>
<button
class="ant-btn ant-btn-text ant-btn-sm ant-btn-icon-only ant-upload-list-item-card-actions-btn"
title="Remove file"
type="button"
>
<span
aria-label="delete"
class="anticon anticon-delete"
role="img"
tabindex="-1"
>
<svg
aria-hidden="true"
data-icon="delete"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M360 184h-8c4.4 0 8-3.6 8-8v8h304v-8c0 4.4 3.6 8 8 8h-8v72h72v-80c0-35.3-28.7-64-64-64H352c-35.3 0-64 28.7-64 64v80h72v-72zm504 72H160c-17.7 0-32 14.3-32 32v32c0 4.4 3.6 8 8 8h60.4l24.7 523c1.6 34.1 29.8 61 63.9 61h454c34.2 0 62.3-26.8 63.9-61l24.7-523H888c4.4 0 8-3.6 8-8v-32c0-17.7-14.3-32-32-32zM731.3 840H292.7l-24.2-512h487l-24.2 512z"
/>
</svg>
</span>
</button>
</span>
</button>
</span>
</div>
</span>
</div>
</span>
</div>
</div>
</div>
</span>
@ -38082,27 +38082,63 @@ exports[`ConfigProvider components Upload normal 1`] = `
class="ant-upload-list ant-upload-list-text"
>
<div
class=""
class="ant-upload-list-text-container"
>
<span>
<div
class="ant-upload-list-item ant-upload-list-item-done ant-upload-list-item-list-type-text"
>
<div
class="ant-upload-list-item ant-upload-list-item-done ant-upload-list-item-list-type-text"
class="ant-upload-list-item-info"
>
<div
class="ant-upload-list-item-info"
<span
class="ant-upload-span"
>
<span>
<div
class="ant-upload-text-icon"
<div
class="ant-upload-text-icon"
>
<span
aria-label="paper-clip"
class="anticon anticon-paper-clip"
role="img"
>
<svg
aria-hidden="true"
data-icon="paper-clip"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M779.3 196.6c-94.2-94.2-247.6-94.2-341.7 0l-261 260.8c-1.7 1.7-2.6 4-2.6 6.4s.9 4.7 2.6 6.4l36.9 36.9a9 9 0 0012.7 0l261-260.8c32.4-32.4 75.5-50.2 121.3-50.2s88.9 17.8 121.2 50.2c32.4 32.4 50.2 75.5 50.2 121.2 0 45.8-17.8 88.8-50.2 121.2l-266 265.9-43.1 43.1c-40.3 40.3-105.8 40.3-146.1 0-19.5-19.5-30.2-45.4-30.2-73s10.7-53.5 30.2-73l263.9-263.8c6.7-6.6 15.5-10.3 24.9-10.3h.1c9.4 0 18.1 3.7 24.7 10.3 6.7 6.7 10.3 15.5 10.3 24.9 0 9.3-3.7 18.1-10.3 24.7L372.4 653c-1.7 1.7-2.6 4-2.6 6.4s.9 4.7 2.6 6.4l36.9 36.9a9 9 0 0012.7 0l215.6-215.6c19.9-19.9 30.8-46.3 30.8-74.4s-11-54.6-30.8-74.4c-41.1-41.1-107.9-41-149 0L463 364 224.8 602.1A172.22 172.22 0 00174 724.8c0 46.3 18.1 89.8 50.8 122.5 33.9 33.8 78.3 50.7 122.7 50.7 44.4 0 88.8-16.9 122.6-50.7l309.2-309C824.8 492.7 850 432 850 367.5c.1-64.6-25.1-125.3-70.7-170.9z"
/>
</svg>
</span>
</div>
<span
class="ant-upload-list-item-name"
title="xxx.png"
>
xxx.png
</span>
<span
class="ant-upload-list-item-card-actions"
>
<button
class="ant-btn ant-btn-text ant-btn-sm ant-btn-icon-only ant-upload-list-item-card-actions-btn"
title="Remove file"
type="button"
>
<span
aria-label="paper-clip"
class="anticon anticon-paper-clip"
aria-label="delete"
class="anticon anticon-delete"
role="img"
tabindex="-1"
>
<svg
aria-hidden="true"
data-icon="paper-clip"
data-icon="delete"
fill="currentColor"
focusable="false"
height="1em"
@ -38110,51 +38146,15 @@ exports[`ConfigProvider components Upload normal 1`] = `
width="1em"
>
<path
d="M779.3 196.6c-94.2-94.2-247.6-94.2-341.7 0l-261 260.8c-1.7 1.7-2.6 4-2.6 6.4s.9 4.7 2.6 6.4l36.9 36.9a9 9 0 0012.7 0l261-260.8c32.4-32.4 75.5-50.2 121.3-50.2s88.9 17.8 121.2 50.2c32.4 32.4 50.2 75.5 50.2 121.2 0 45.8-17.8 88.8-50.2 121.2l-266 265.9-43.1 43.1c-40.3 40.3-105.8 40.3-146.1 0-19.5-19.5-30.2-45.4-30.2-73s10.7-53.5 30.2-73l263.9-263.8c6.7-6.6 15.5-10.3 24.9-10.3h.1c9.4 0 18.1 3.7 24.7 10.3 6.7 6.7 10.3 15.5 10.3 24.9 0 9.3-3.7 18.1-10.3 24.7L372.4 653c-1.7 1.7-2.6 4-2.6 6.4s.9 4.7 2.6 6.4l36.9 36.9a9 9 0 0012.7 0l215.6-215.6c19.9-19.9 30.8-46.3 30.8-74.4s-11-54.6-30.8-74.4c-41.1-41.1-107.9-41-149 0L463 364 224.8 602.1A172.22 172.22 0 00174 724.8c0 46.3 18.1 89.8 50.8 122.5 33.9 33.8 78.3 50.7 122.7 50.7 44.4 0 88.8-16.9 122.6-50.7l309.2-309C824.8 492.7 850 432 850 367.5c.1-64.6-25.1-125.3-70.7-170.9z"
d="M360 184h-8c4.4 0 8-3.6 8-8v8h304v-8c0 4.4 3.6 8 8 8h-8v72h72v-80c0-35.3-28.7-64-64-64H352c-35.3 0-64 28.7-64 64v80h72v-72zm504 72H160c-17.7 0-32 14.3-32 32v32c0 4.4 3.6 8 8 8h60.4l24.7 523c1.6 34.1 29.8 61 63.9 61h454c34.2 0 62.3-26.8 63.9-61l24.7-523H888c4.4 0 8-3.6 8-8v-32c0-17.7-14.3-32-32-32zM731.3 840H292.7l-24.2-512h487l-24.2 512z"
/>
</svg>
</span>
</div>
<span
class="ant-upload-list-item-name ant-upload-list-item-name-icon-count-1"
title="xxx.png"
>
xxx.png
</span>
<span
class="ant-upload-list-item-card-actions "
>
<button
class="ant-btn ant-btn-text ant-btn-sm ant-btn-icon-only ant-upload-list-item-card-actions-btn"
title="Remove file"
type="button"
>
<span
aria-label="delete"
class="anticon anticon-delete"
role="img"
tabindex="-1"
>
<svg
aria-hidden="true"
data-icon="delete"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M360 184h-8c4.4 0 8-3.6 8-8v8h304v-8c0 4.4 3.6 8 8 8h-8v72h72v-80c0-35.3-28.7-64-64-64H352c-35.3 0-64 28.7-64 64v80h72v-72zm504 72H160c-17.7 0-32 14.3-32 32v32c0 4.4 3.6 8 8 8h60.4l24.7 523c1.6 34.1 29.8 61 63.9 61h454c34.2 0 62.3-26.8 63.9-61l24.7-523H888c4.4 0 8-3.6 8-8v-32c0-17.7-14.3-32-32-32zM731.3 840H292.7l-24.2-512h487l-24.2 512z"
/>
</svg>
</span>
</button>
</span>
</button>
</span>
</div>
</span>
</div>
</span>
</div>
</div>
</div>
</span>
@ -38184,27 +38184,63 @@ exports[`ConfigProvider components Upload prefixCls 1`] = `
class="ant-upload-list ant-upload-list-text"
>
<div
class=""
class="ant-upload-list-text-container"
>
<span>
<div
class="ant-upload-list-item ant-upload-list-item-done ant-upload-list-item-list-type-text"
>
<div
class="ant-upload-list-item ant-upload-list-item-done ant-upload-list-item-list-type-text"
class="ant-upload-list-item-info"
>
<div
class="ant-upload-list-item-info"
<span
class="ant-upload-span"
>
<span>
<div
class="ant-upload-text-icon"
<div
class="ant-upload-text-icon"
>
<span
aria-label="paper-clip"
class="anticon anticon-paper-clip"
role="img"
>
<svg
aria-hidden="true"
data-icon="paper-clip"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M779.3 196.6c-94.2-94.2-247.6-94.2-341.7 0l-261 260.8c-1.7 1.7-2.6 4-2.6 6.4s.9 4.7 2.6 6.4l36.9 36.9a9 9 0 0012.7 0l261-260.8c32.4-32.4 75.5-50.2 121.3-50.2s88.9 17.8 121.2 50.2c32.4 32.4 50.2 75.5 50.2 121.2 0 45.8-17.8 88.8-50.2 121.2l-266 265.9-43.1 43.1c-40.3 40.3-105.8 40.3-146.1 0-19.5-19.5-30.2-45.4-30.2-73s10.7-53.5 30.2-73l263.9-263.8c6.7-6.6 15.5-10.3 24.9-10.3h.1c9.4 0 18.1 3.7 24.7 10.3 6.7 6.7 10.3 15.5 10.3 24.9 0 9.3-3.7 18.1-10.3 24.7L372.4 653c-1.7 1.7-2.6 4-2.6 6.4s.9 4.7 2.6 6.4l36.9 36.9a9 9 0 0012.7 0l215.6-215.6c19.9-19.9 30.8-46.3 30.8-74.4s-11-54.6-30.8-74.4c-41.1-41.1-107.9-41-149 0L463 364 224.8 602.1A172.22 172.22 0 00174 724.8c0 46.3 18.1 89.8 50.8 122.5 33.9 33.8 78.3 50.7 122.7 50.7 44.4 0 88.8-16.9 122.6-50.7l309.2-309C824.8 492.7 850 432 850 367.5c.1-64.6-25.1-125.3-70.7-170.9z"
/>
</svg>
</span>
</div>
<span
class="ant-upload-list-item-name"
title="xxx.png"
>
xxx.png
</span>
<span
class="ant-upload-list-item-card-actions"
>
<button
class="ant-btn ant-btn-text ant-btn-sm ant-btn-icon-only ant-upload-list-item-card-actions-btn"
title="Remove file"
type="button"
>
<span
aria-label="paper-clip"
class="anticon anticon-paper-clip"
aria-label="delete"
class="anticon anticon-delete"
role="img"
tabindex="-1"
>
<svg
aria-hidden="true"
data-icon="paper-clip"
data-icon="delete"
fill="currentColor"
focusable="false"
height="1em"
@ -38212,51 +38248,15 @@ exports[`ConfigProvider components Upload prefixCls 1`] = `
width="1em"
>
<path
d="M779.3 196.6c-94.2-94.2-247.6-94.2-341.7 0l-261 260.8c-1.7 1.7-2.6 4-2.6 6.4s.9 4.7 2.6 6.4l36.9 36.9a9 9 0 0012.7 0l261-260.8c32.4-32.4 75.5-50.2 121.3-50.2s88.9 17.8 121.2 50.2c32.4 32.4 50.2 75.5 50.2 121.2 0 45.8-17.8 88.8-50.2 121.2l-266 265.9-43.1 43.1c-40.3 40.3-105.8 40.3-146.1 0-19.5-19.5-30.2-45.4-30.2-73s10.7-53.5 30.2-73l263.9-263.8c6.7-6.6 15.5-10.3 24.9-10.3h.1c9.4 0 18.1 3.7 24.7 10.3 6.7 6.7 10.3 15.5 10.3 24.9 0 9.3-3.7 18.1-10.3 24.7L372.4 653c-1.7 1.7-2.6 4-2.6 6.4s.9 4.7 2.6 6.4l36.9 36.9a9 9 0 0012.7 0l215.6-215.6c19.9-19.9 30.8-46.3 30.8-74.4s-11-54.6-30.8-74.4c-41.1-41.1-107.9-41-149 0L463 364 224.8 602.1A172.22 172.22 0 00174 724.8c0 46.3 18.1 89.8 50.8 122.5 33.9 33.8 78.3 50.7 122.7 50.7 44.4 0 88.8-16.9 122.6-50.7l309.2-309C824.8 492.7 850 432 850 367.5c.1-64.6-25.1-125.3-70.7-170.9z"
d="M360 184h-8c4.4 0 8-3.6 8-8v8h304v-8c0 4.4 3.6 8 8 8h-8v72h72v-80c0-35.3-28.7-64-64-64H352c-35.3 0-64 28.7-64 64v80h72v-72zm504 72H160c-17.7 0-32 14.3-32 32v32c0 4.4 3.6 8 8 8h60.4l24.7 523c1.6 34.1 29.8 61 63.9 61h454c34.2 0 62.3-26.8 63.9-61l24.7-523H888c4.4 0 8-3.6 8-8v-32c0-17.7-14.3-32-32-32zM731.3 840H292.7l-24.2-512h487l-24.2 512z"
/>
</svg>
</span>
</div>
<span
class="ant-upload-list-item-name ant-upload-list-item-name-icon-count-1"
title="xxx.png"
>
xxx.png
</span>
<span
class="ant-upload-list-item-card-actions "
>
<button
class="ant-btn ant-btn-text ant-btn-sm ant-btn-icon-only ant-upload-list-item-card-actions-btn"
title="Remove file"
type="button"
>
<span
aria-label="delete"
class="anticon anticon-delete"
role="img"
tabindex="-1"
>
<svg
aria-hidden="true"
data-icon="delete"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M360 184h-8c4.4 0 8-3.6 8-8v8h304v-8c0 4.4 3.6 8 8 8h-8v72h72v-80c0-35.3-28.7-64-64-64H352c-35.3 0-64 28.7-64 64v80h72v-72zm504 72H160c-17.7 0-32 14.3-32 32v32c0 4.4 3.6 8 8 8h60.4l24.7 523c1.6 34.1 29.8 61 63.9 61h454c34.2 0 62.3-26.8 63.9-61l24.7-523H888c4.4 0 8-3.6 8-8v-32c0-17.7-14.3-32-32-32zM731.3 840H292.7l-24.2-512h487l-24.2 512z"
/>
</svg>
</span>
</button>
</span>
</button>
</span>
</div>
</span>
</div>
</span>
</div>
</div>
</div>
</span>

View File

@ -860,7 +860,7 @@
// Skeleton
// ---
@skeleton-color: rgba(190, 190, 190, .2);
@skeleton-color: rgba(190, 190, 190, 0.2);
@skeleton-to-color: shade(@skeleton-color, 5%);
@skeleton-paragraph-margin-top: 28px;
@skeleton-paragraph-li-margin-top: @margin-md;

View File

@ -1,373 +0,0 @@
import * as React from 'react';
import Animate from 'rc-animate';
import classNames from 'classnames';
import LoadingOutlined from '@ant-design/icons/LoadingOutlined';
import PaperClipOutlined from '@ant-design/icons/PaperClipOutlined';
import PictureTwoTone from '@ant-design/icons/PictureTwoTone';
import FileTwoTone from '@ant-design/icons/FileTwoTone';
import EyeOutlined from '@ant-design/icons/EyeOutlined';
import DeleteOutlined from '@ant-design/icons/DeleteOutlined';
import DownloadOutlined from '@ant-design/icons/DownloadOutlined';
import { cloneElement, isValidElement } from '../_util/reactNode';
import { UploadListProps, UploadFile, UploadListType } from './interface';
import { previewImage, isImageUrl } from './utils';
import Tooltip from '../tooltip';
import Progress from '../progress';
import { ConfigContext } from '../config-provider';
import Button, { ButtonProps } from '../button';
import useForceUpdate from '../_util/hooks/useForceUpdate';
const InternalUploadList: React.ForwardRefRenderFunction<unknown, UploadListProps> = (
{
listType,
previewFile,
onPreview,
onDownload,
onRemove,
locale,
iconRender,
isImageUrl: isImgUrl,
prefixCls: customizePrefixCls,
items = [],
showPreviewIcon,
showRemoveIcon,
showDownloadIcon,
removeIcon: customRemoveIcon,
downloadIcon: customDownloadIcon,
progress: progressProps,
appendAction,
itemRender,
},
ref,
) => {
const forceUpdate = useForceUpdate();
React.useEffect(() => {
if (listType !== 'picture' && listType !== 'picture-card') {
return;
}
(items || []).forEach(file => {
if (
typeof document === 'undefined' ||
typeof window === 'undefined' ||
!(window as any).FileReader ||
!(window as any).File ||
!(file.originFileObj instanceof File || file.originFileObj instanceof Blob) ||
file.thumbUrl !== undefined
) {
return;
}
file.thumbUrl = '';
if (previewFile) {
previewFile(file.originFileObj as File).then((previewDataUrl: string) => {
// Need append '' to avoid dead loop
file.thumbUrl = previewDataUrl || '';
forceUpdate();
});
}
});
}, [listType, items, previewFile]);
const handlePreview = (file: UploadFile, e: React.SyntheticEvent<HTMLElement>) => {
if (!onPreview) {
return;
}
e.preventDefault();
return onPreview(file);
};
const handleDownload = (file: UploadFile) => {
if (typeof onDownload === 'function') {
onDownload(file);
} else if (file.url) {
window.open(file.url);
}
};
const handleClose = (file: UploadFile) => {
if (onRemove) {
onRemove(file);
}
};
const handleIconRender = (file: UploadFile) => {
if (iconRender) {
return iconRender(file, listType);
}
const isLoading = file.status === 'uploading';
const fileIcon = isImgUrl && isImgUrl(file) ? <PictureTwoTone /> : <FileTwoTone />;
let icon: React.ReactNode = isLoading ? <LoadingOutlined /> : <PaperClipOutlined />;
if (listType === 'picture') {
icon = isLoading ? <LoadingOutlined /> : fileIcon;
} else if (listType === 'picture-card') {
icon = isLoading ? locale.uploading : fileIcon;
}
return icon;
};
const handleActionIconRender = (
customIcon: React.ReactNode,
callback: () => void,
prefixCls: string,
title?: string,
) => {
const btnProps: ButtonProps = {
type: 'text',
size: 'small',
title,
onClick: (e: React.MouseEvent<HTMLElement>) => {
callback();
if (isValidElement(customIcon) && customIcon.props.onClick) {
customIcon.props.onClick(e);
}
},
className: `${prefixCls}-list-item-card-actions-btn`,
};
if (isValidElement(customIcon)) {
const btnIcon = cloneElement(customIcon, {
...customIcon.props,
onClick: () => {},
});
return <Button {...btnProps} icon={btnIcon} />;
}
return (
<Button {...btnProps}>
<span>{customIcon}</span>
</Button>
);
};
// Test needs
React.useImperativeHandle(ref, () => ({
handlePreview,
handleDownload,
}));
const { getPrefixCls, direction } = React.useContext(ConfigContext);
const prefixCls = getPrefixCls('upload', customizePrefixCls);
const list = items.map(file => {
let progress;
const iconNode = handleIconRender(file);
let icon = <div className={`${prefixCls}-text-icon`}>{iconNode}</div>;
if (listType === 'picture' || listType === 'picture-card') {
if (file.status === 'uploading' || (!file.thumbUrl && !file.url)) {
const uploadingClassName = classNames({
[`${prefixCls}-list-item-thumbnail`]: true,
[`${prefixCls}-list-item-file`]: file.status !== 'uploading',
});
icon = <div className={uploadingClassName}>{iconNode}</div>;
} else {
const thumbnail =
isImgUrl && isImgUrl(file) ? (
<img
src={file.thumbUrl || file.url}
alt={file.name}
className={`${prefixCls}-list-item-image`}
/>
) : (
iconNode
);
const aClassName = classNames({
[`${prefixCls}-list-item-thumbnail`]: true,
[`${prefixCls}-list-item-file`]: isImgUrl && !isImgUrl(file),
});
icon = (
<a
className={aClassName}
onClick={e => handlePreview(file, e)}
href={file.url || file.thumbUrl}
target="_blank"
rel="noopener noreferrer"
>
{thumbnail}
</a>
);
}
}
if (file.status === 'uploading') {
// show loading icon if upload progress listener is disabled
const loadingProgress =
'percent' in file ? (
<Progress {...progressProps} type="line" percent={file.percent} />
) : null;
progress = (
<div className={`${prefixCls}-list-item-progress`} key="progress">
{loadingProgress}
</div>
);
}
const infoUploadingClass = classNames({
[`${prefixCls}-list-item`]: true,
[`${prefixCls}-list-item-${file.status}`]: true,
[`${prefixCls}-list-item-list-type-${listType}`]: true,
});
const linkProps =
typeof file.linkProps === 'string' ? JSON.parse(file.linkProps) : file.linkProps;
const removeIcon = showRemoveIcon
? handleActionIconRender(
(typeof customRemoveIcon === 'function' ? customRemoveIcon(file) : customRemoveIcon) || (
<DeleteOutlined />
),
() => handleClose(file),
prefixCls,
locale.removeFile,
)
: null;
const downloadIcon =
showDownloadIcon && file.status === 'done'
? handleActionIconRender(
(typeof customDownloadIcon === 'function'
? customDownloadIcon(file)
: customDownloadIcon) || <DownloadOutlined />,
() => handleDownload(file),
prefixCls,
locale.downloadFile,
)
: null;
const downloadOrDelete = listType !== 'picture-card' && (
<span
key="download-delete"
className={`${prefixCls}-list-item-card-actions ${listType === 'picture' ? 'picture' : ''}`}
>
{downloadIcon}
{removeIcon}
</span>
);
const listItemNameClass = classNames({
[`${prefixCls}-list-item-name`]: true,
[`${prefixCls}-list-item-name-icon-count-${
[downloadIcon, removeIcon].filter(x => x).length
}`]: true,
});
const preview = file.url
? [
<a
key="view"
target="_blank"
rel="noopener noreferrer"
className={listItemNameClass}
title={file.name}
{...linkProps}
href={file.url}
onClick={e => handlePreview(file, e)}
>
{file.name}
</a>,
downloadOrDelete,
]
: [
<span
key="view"
className={listItemNameClass}
onClick={e => handlePreview(file, e)}
title={file.name}
>
{file.name}
</span>,
downloadOrDelete,
];
const style: React.CSSProperties = {
pointerEvents: 'none',
opacity: 0.5,
};
const previewIcon = showPreviewIcon ? (
<a
href={file.url || file.thumbUrl}
target="_blank"
rel="noopener noreferrer"
style={file.url || file.thumbUrl ? undefined : style}
onClick={e => handlePreview(file, e)}
title={locale.previewFile}
>
<EyeOutlined />
</a>
) : null;
const actions = listType === 'picture-card' && file.status !== 'uploading' && (
<span className={`${prefixCls}-list-item-actions`}>
{previewIcon}
{file.status === 'done' && downloadIcon}
{removeIcon}
</span>
);
let message;
if (file.response && typeof file.response === 'string') {
message = file.response;
} else {
message = (file.error && file.error.statusText) || locale.uploadError;
}
const iconAndPreview = (
<span>
{icon}
{preview}
</span>
);
const dom = (
<div className={infoUploadingClass}>
<div className={`${prefixCls}-list-item-info`}>{iconAndPreview}</div>
{actions}
<Animate transitionName="fade" component="">
{progress}
</Animate>
</div>
);
const listContainerNameClass = classNames({
[`${prefixCls}-list-picture-card-container`]: listType === 'picture-card',
});
const item =
file.status === 'error' ? (
<Tooltip title={message} getPopupContainer={node => node.parentNode as HTMLElement}>
{dom}
</Tooltip>
) : (
<span>{dom}</span>
);
return (
<div key={file.uid} className={listContainerNameClass}>
{itemRender ? itemRender(item, file, items) : item}
</div>
);
});
const listClassNames = classNames({
[`${prefixCls}-list`]: true,
[`${prefixCls}-list-${listType}`]: true,
[`${prefixCls}-list-rtl`]: direction === 'rtl',
});
const animationDirection = listType === 'picture-card' ? 'animate-inline' : 'animate';
const transitionName = list.length === 0 ? '' : `${prefixCls}-${animationDirection}`;
return (
<Animate transitionName={transitionName} component="div" className={listClassNames}>
{list}
{React.isValidElement(appendAction)
? React.cloneElement(appendAction, { key: 'appendAction' })
: appendAction}
</Animate>
);
};
const UploadList = React.forwardRef<unknown, UploadListProps>(InternalUploadList);
UploadList.displayName = 'UploadList';
UploadList.defaultProps = {
listType: 'text' as UploadListType, // or picture
progress: {
strokeWidth: 2,
showInfo: false,
},
showRemoveIcon: true,
showDownloadIcon: false,
showPreviewIcon: true,
previewFile: previewImage,
isImageUrl,
};
export default UploadList;

View File

@ -0,0 +1,273 @@
import * as React from 'react';
import CSSMotion from 'rc-motion';
import classNames from 'classnames';
import EyeOutlined from '@ant-design/icons/EyeOutlined';
import DeleteOutlined from '@ant-design/icons/DeleteOutlined';
import DownloadOutlined from '@ant-design/icons/DownloadOutlined';
import Tooltip from '../../tooltip';
import Progress from '../../progress';
import {
ItemRender,
UploadFile,
UploadListProgressProps,
UploadListType,
UploadLocale,
} from '../interface';
export interface ListItemProps {
prefixCls: string;
className?: string;
style?: React.CSSProperties;
locale: UploadLocale;
file: UploadFile;
items: UploadFile[];
listType?: UploadListType;
isImgUrl?: (file: UploadFile) => boolean;
showRemoveIcon?: boolean;
showDownloadIcon?: boolean;
showPreviewIcon?: boolean;
removeIcon?: React.ReactNode | ((file: UploadFile) => React.ReactNode);
downloadIcon?: React.ReactNode | ((file: UploadFile) => React.ReactNode);
iconRender: (file: UploadFile) => React.ReactNode;
actionIconRender: (
customIcon: React.ReactNode,
callback: () => void,
prefixCls: string,
title?: string | undefined,
) => React.ReactNode;
itemRender?: ItemRender;
onPreview: (file: UploadFile, e: React.SyntheticEvent<HTMLElement>) => void;
onClose: (file: UploadFile) => void;
onDownload: (file: UploadFile) => void;
progress?: UploadListProgressProps;
}
const ListItem = React.forwardRef(
(
{
prefixCls,
className,
style,
locale,
listType,
file,
items,
progress: progressProps,
iconRender,
actionIconRender,
itemRender,
isImgUrl,
showPreviewIcon,
showRemoveIcon,
showDownloadIcon,
removeIcon: customRemoveIcon,
downloadIcon: customDownloadIcon,
onPreview,
onDownload,
onClose,
}: ListItemProps,
ref: React.Ref<HTMLDivElement>,
) => {
// Delay to show the progress bar
const [showProgress, setShowProgress] = React.useState(false);
const progressRafRef = React.useRef<any>();
React.useEffect(() => {
progressRafRef.current = setTimeout(() => {
setShowProgress(true);
}, 300);
return () => {
window.clearTimeout(progressRafRef.current);
};
}, []);
// This is used for legacy span make scrollHeight the wrong value.
// We will force these to be `display: block` with non `picture-card`
const spanClassName = `${prefixCls}-span`;
const iconNode = iconRender(file);
let icon = <div className={`${prefixCls}-text-icon`}>{iconNode}</div>;
if (listType === 'picture' || listType === 'picture-card') {
if (file.status === 'uploading' || (!file.thumbUrl && !file.url)) {
const uploadingClassName = classNames({
[`${prefixCls}-list-item-thumbnail`]: true,
[`${prefixCls}-list-item-file`]: file.status !== 'uploading',
});
icon = <div className={uploadingClassName}>{iconNode}</div>;
} else {
const thumbnail = isImgUrl?.(file) ? (
<img
src={file.thumbUrl || file.url}
alt={file.name}
className={`${prefixCls}-list-item-image`}
/>
) : (
iconNode
);
const aClassName = classNames({
[`${prefixCls}-list-item-thumbnail`]: true,
[`${prefixCls}-list-item-file`]: isImgUrl && !isImgUrl(file),
});
icon = (
<a
className={aClassName}
onClick={e => onPreview(file, e)}
href={file.url || file.thumbUrl}
target="_blank"
rel="noopener noreferrer"
>
{thumbnail}
</a>
);
}
}
const infoUploadingClass = classNames({
[`${prefixCls}-list-item`]: true,
[`${prefixCls}-list-item-${file.status}`]: true,
[`${prefixCls}-list-item-list-type-${listType}`]: true,
});
const linkProps =
typeof file.linkProps === 'string' ? JSON.parse(file.linkProps) : file.linkProps;
const removeIcon = showRemoveIcon
? actionIconRender(
(typeof customRemoveIcon === 'function' ? customRemoveIcon(file) : customRemoveIcon) || (
<DeleteOutlined />
),
() => onClose(file),
prefixCls,
locale.removeFile,
)
: null;
const downloadIcon =
showDownloadIcon && file.status === 'done'
? actionIconRender(
(typeof customDownloadIcon === 'function'
? customDownloadIcon(file)
: customDownloadIcon) || <DownloadOutlined />,
() => onDownload(file),
prefixCls,
locale.downloadFile,
)
: null;
const downloadOrDelete = listType !== 'picture-card' && (
<span
key="download-delete"
className={classNames(`${prefixCls}-list-item-card-actions`, {
picture: listType === 'picture',
})}
>
{downloadIcon}
{removeIcon}
</span>
);
const listItemNameClass = classNames(`${prefixCls}-list-item-name`);
const preview = file.url
? [
<a
key="view"
target="_blank"
rel="noopener noreferrer"
className={listItemNameClass}
title={file.name}
{...linkProps}
href={file.url}
onClick={e => onPreview(file, e)}
>
{file.name}
</a>,
downloadOrDelete,
]
: [
<span
key="view"
className={listItemNameClass}
onClick={e => onPreview(file, e)}
title={file.name}
>
{file.name}
</span>,
downloadOrDelete,
];
const previewStyle: React.CSSProperties = {
pointerEvents: 'none',
opacity: 0.5,
};
const previewIcon = showPreviewIcon ? (
<a
href={file.url || file.thumbUrl}
target="_blank"
rel="noopener noreferrer"
style={file.url || file.thumbUrl ? undefined : previewStyle}
onClick={e => onPreview(file, e)}
title={locale.previewFile}
>
<EyeOutlined />
</a>
) : null;
const actions = listType === 'picture-card' && file.status !== 'uploading' && (
<span className={`${prefixCls}-list-item-actions`}>
{previewIcon}
{file.status === 'done' && downloadIcon}
{removeIcon}
</span>
);
let message;
if (file.response && typeof file.response === 'string') {
message = file.response;
} else {
message = (file.error && file.error.statusText) || locale.uploadError;
}
const iconAndPreview = (
<span className={spanClassName}>
{icon}
{preview}
</span>
);
const dom = (
<div className={infoUploadingClass}>
<div className={`${prefixCls}-list-item-info`}>{iconAndPreview}</div>
{actions}
{showProgress && (
<CSSMotion motionName="fade" visible={file.status === 'uploading'}>
{({ className: motionClassName }) => {
// show loading icon if upload progress listener is disabled
const loadingProgress =
'percent' in file ? (
<Progress {...progressProps} type="line" percent={file.percent} />
) : null;
return (
<div className={classNames(`${prefixCls}-list-item-progress`, motionClassName)}>
{loadingProgress}
</div>
);
}}
</CSSMotion>
)}
</div>
);
const listContainerNameClass = classNames(`${prefixCls}-list-${listType}-container`, className);
const item =
file.status === 'error' ? (
<Tooltip title={message} getPopupContainer={node => node.parentNode as HTMLElement}>
{dom}
</Tooltip>
) : (
dom
);
return (
<div className={listContainerNameClass} style={style} ref={ref}>
{itemRender ? itemRender(item, file, items) : item}
</div>
);
},
);
export default ListItem;

View File

@ -0,0 +1,262 @@
import * as React from 'react';
import CSSMotion, { CSSMotionList, CSSMotionListProps } from 'rc-motion';
import classNames from 'classnames';
import LoadingOutlined from '@ant-design/icons/LoadingOutlined';
import PaperClipOutlined from '@ant-design/icons/PaperClipOutlined';
import PictureTwoTone from '@ant-design/icons/PictureTwoTone';
import FileTwoTone from '@ant-design/icons/FileTwoTone';
import { cloneElement, isValidElement } from '../../_util/reactNode';
import { UploadListProps, UploadFile, UploadListType } from '../interface';
import { previewImage, isImageUrl } from '../utils';
import collapseMotion from '../../_util/motion';
import { ConfigContext } from '../../config-provider';
import Button, { ButtonProps } from '../../button';
import useForceUpdate from '../../_util/hooks/useForceUpdate';
import ListItem from './ListItem';
const listItemMotion: Partial<CSSMotionListProps> = {
...collapseMotion,
};
delete listItemMotion.onAppearEnd;
delete listItemMotion.onEnterEnd;
delete listItemMotion.onLeaveEnd;
const InternalUploadList: React.ForwardRefRenderFunction<unknown, UploadListProps> = (
{
listType,
previewFile,
onPreview,
onDownload,
onRemove,
locale,
iconRender,
isImageUrl: isImgUrl,
prefixCls: customizePrefixCls,
items = [],
showPreviewIcon,
showRemoveIcon,
showDownloadIcon,
removeIcon,
downloadIcon,
progress,
appendAction,
itemRender,
},
ref,
) => {
const forceUpdate = useForceUpdate();
const [motionAppear, setMotionAppear] = React.useState(false);
// ============================= Effect =============================
React.useEffect(() => {
if (listType !== 'picture' && listType !== 'picture-card') {
return;
}
(items || []).forEach(file => {
if (
typeof document === 'undefined' ||
typeof window === 'undefined' ||
!(window as any).FileReader ||
!(window as any).File ||
!(file.originFileObj instanceof File || file.originFileObj instanceof Blob) ||
file.thumbUrl !== undefined
) {
return;
}
file.thumbUrl = '';
if (previewFile) {
previewFile(file.originFileObj as File).then((previewDataUrl: string) => {
// Need append '' to avoid dead loop
file.thumbUrl = previewDataUrl || '';
forceUpdate();
});
}
});
}, [listType, items, previewFile]);
React.useEffect(() => {
setMotionAppear(true);
}, []);
// ============================= Events =============================
const onInternalPreview = (file: UploadFile, e: React.SyntheticEvent<HTMLElement>) => {
if (!onPreview) {
return;
}
e.preventDefault();
return onPreview(file);
};
const onInternalDownload = (file: UploadFile) => {
if (typeof onDownload === 'function') {
onDownload(file);
} else if (file.url) {
window.open(file.url);
}
};
const onInternalClose = (file: UploadFile) => {
if (onRemove) {
onRemove(file);
}
};
const internalIconRender = (file: UploadFile) => {
if (iconRender) {
return iconRender(file, listType);
}
const isLoading = file.status === 'uploading';
const fileIcon = isImgUrl && isImgUrl(file) ? <PictureTwoTone /> : <FileTwoTone />;
let icon: React.ReactNode = isLoading ? <LoadingOutlined /> : <PaperClipOutlined />;
if (listType === 'picture') {
icon = isLoading ? <LoadingOutlined /> : fileIcon;
} else if (listType === 'picture-card') {
icon = isLoading ? locale.uploading : fileIcon;
}
return icon;
};
const actionIconRender = (
customIcon: React.ReactNode,
callback: () => void,
prefixCls: string,
title?: string,
) => {
const btnProps: ButtonProps = {
type: 'text',
size: 'small',
title,
onClick: (e: React.MouseEvent<HTMLElement>) => {
callback();
if (isValidElement(customIcon) && customIcon.props.onClick) {
customIcon.props.onClick(e);
}
},
className: `${prefixCls}-list-item-card-actions-btn`,
};
if (isValidElement(customIcon)) {
const btnIcon = cloneElement(customIcon, {
...customIcon.props,
onClick: () => {},
});
return <Button {...btnProps} icon={btnIcon} />;
}
return (
<Button {...btnProps}>
<span>{customIcon}</span>
</Button>
);
};
// ============================== Ref ===============================
// Test needs
React.useImperativeHandle(ref, () => ({
handlePreview: onInternalPreview,
handleDownload: onInternalDownload,
}));
const { getPrefixCls, direction } = React.useContext(ConfigContext);
// ============================= Render =============================
const prefixCls = getPrefixCls('upload', customizePrefixCls);
const listClassNames = classNames({
[`${prefixCls}-list`]: true,
[`${prefixCls}-list-${listType}`]: true,
[`${prefixCls}-list-rtl`]: direction === 'rtl',
});
// >>> Motion config
const motionKeyList = [
...items.map(file => ({
key: file.uid,
file,
})),
];
const animationDirection = listType === 'picture-card' ? 'animate-inline' : 'animate';
// const transitionName = list.length === 0 ? '' : `${prefixCls}-${animationDirection}`;
let motionConfig: Omit<CSSMotionListProps, 'onVisibleChanged'> = {
motionName: `${prefixCls}-${animationDirection}`,
keys: motionKeyList,
motionAppear,
};
if (listType !== 'picture-card') {
motionConfig = {
...listItemMotion,
...motionConfig,
};
}
return (
<div className={listClassNames}>
<CSSMotionList {...motionConfig} component={false}>
{({ key, file, className: motionClassName, style: motionStyle }) => {
return (
<ListItem
key={key}
locale={locale}
prefixCls={prefixCls}
className={motionClassName}
style={motionStyle}
file={file}
items={items}
progress={progress}
listType={listType}
isImgUrl={isImgUrl}
showPreviewIcon={showPreviewIcon}
showRemoveIcon={showRemoveIcon}
showDownloadIcon={showDownloadIcon}
removeIcon={removeIcon}
downloadIcon={downloadIcon}
iconRender={internalIconRender}
actionIconRender={actionIconRender}
itemRender={itemRender}
onPreview={onInternalPreview}
onDownload={onInternalDownload}
onClose={onInternalClose}
/>
);
}}
</CSSMotionList>
{/* Append action */}
{appendAction && (
<CSSMotion {...motionConfig}>
{({ className: motionClassName, style: motionStyle }) => {
return cloneElement(appendAction, oriProps => ({
className: classNames(oriProps.className, motionClassName),
style: {
...motionStyle,
...oriProps.style,
},
}));
}}
</CSSMotion>
)}
</div>
);
};
const UploadList = React.forwardRef<unknown, UploadListProps>(InternalUploadList);
UploadList.displayName = 'UploadList';
UploadList.defaultProps = {
listType: 'text' as UploadListType, // or picture
progress: {
strokeWidth: 2,
showInfo: false,
},
showRemoveIcon: true,
showDownloadIcon: false,
showPreviewIcon: true,
previewFile: previewImage,
isImageUrl,
};
export default UploadList;

File diff suppressed because it is too large Load Diff

View File

@ -131,9 +131,20 @@ describe('Upload List', () => {
);
expect(wrapper.find('.ant-upload-list-item').length).toBe(2);
wrapper.find('.ant-upload-list-item').at(0).find('.anticon-delete').simulate('click');
await sleep(1000);
wrapper.update();
expect(wrapper.find('.ant-upload-list-item').hostNodes().length).toBe(1);
await act(async () => {
await sleep(1000);
wrapper.update();
const domNode = wrapper.find('.ant-upload-list-text-container').at(0).hostNodes().instance();
const transitionEndEvent = new Event('transitionend');
domNode.dispatchEvent(transitionEndEvent);
wrapper.update();
});
// console.log(wrapper.html());
expect(wrapper.find('.ant-upload-list-text-container').hostNodes().length).toBe(1);
});
it('should be uploading when upload a file', done => {
@ -222,6 +233,10 @@ describe('Upload List', () => {
<button type="button">upload</button>
</Upload>,
);
// Has error item className
wrapper.find('.ant-upload-list-item-error').simulate('mouseenter');
expect(wrapper.find('div.ant-upload-list-item i.anticon-download').length).toBe(0);
});

View File

@ -72,6 +72,12 @@ export type UploadType = 'drag' | 'select';
export type UploadListType = 'text' | 'picture' | 'picture-card';
export type UploadListProgressProps = Omit<ProgressProps, 'percent' | 'type'>;
export type ItemRender<T = any> = (
originNode: React.ReactElement,
file: UploadFile,
fileList?: Array<UploadFile<T>>,
) => React.ReactNode;
type PreviewFileHandler = (file: File | Blob) => PromiseLike<string>;
type TransformFileHandler = (
file: RcFile,
@ -111,11 +117,7 @@ export interface UploadProps<T = any> {
iconRender?: (file: UploadFile<T>, listType?: UploadListType) => React.ReactNode;
isImageUrl?: (file: UploadFile) => boolean;
progress?: UploadListProgressProps;
itemRender?: (
originNode: React.ReactElement,
file: UploadFile,
fileList?: Array<UploadFile<T>>,
) => React.ReactNode;
itemRender?: ItemRender<T>;
}
export interface UploadState<T = any> {
@ -141,9 +143,5 @@ export interface UploadListProps<T = any> {
iconRender?: (file: UploadFile<T>, listType?: UploadListType) => React.ReactNode;
isImageUrl?: (file: UploadFile) => boolean;
appendAction?: React.ReactNode;
itemRender?: (
originNode: React.ReactElement,
file: UploadFile,
fileList?: Array<UploadFile<T>>,
) => React.ReactNode;
itemRender?: ItemRender<T>;
}

View File

@ -142,16 +142,8 @@
.reset-component;
.clearfix;
line-height: @line-height-base;
&-item-list-type-text {
&:hover {
.@{upload-prefix-cls}-list-item-name-icon-count-1 {
padding-right: 14px;
}
.@{upload-prefix-cls}-list-item-name-icon-count-2 {
padding-right: 28px;
}
}
}
// ============================ Item ============================
&-item {
position: relative;
height: @line-height-base * @font-size-base;
@ -167,10 +159,6 @@
text-overflow: ellipsis;
}
&-name-icon-count-1 {
padding-right: 14px;
}
&-card-actions {
position: absolute;
right: 0;
@ -200,7 +188,7 @@
&-info {
height: 100%;
padding: 0 12px 0 4px;
padding: 0 4px;
transition: background-color 0.3s;
> span {
@ -273,6 +261,7 @@
}
}
// =================== Picture & Picture Card ===================
&-picture,
&-picture-card {
.@{upload-item} {
@ -304,9 +293,6 @@
}
.@{upload-item}-thumbnail {
position: absolute;
top: 8px;
left: 8px;
width: 48px;
height: 48px;
line-height: 54px;
@ -370,14 +356,6 @@
transition: all 0.3s;
}
.@{upload-item}-name-icon-count-1 {
padding-right: 18px;
}
.@{upload-item}-name-icon-count-2 {
padding-right: 36px;
}
.@{upload-item}-uploading .@{upload-item}-name {
line-height: 28px;
}
@ -398,11 +376,8 @@
}
}
// ======================== Picture Card ========================
&-picture-card {
&.@{upload-prefix-cls}-list::after {
display: none;
}
&-container {
display: inline-block;
width: @upload-picture-card-size;
@ -411,6 +386,10 @@
vertical-align: top;
}
&.@{upload-prefix-cls}-list::after {
display: none;
}
.@{upload-item} {
height: 100%;
margin: 0;
@ -492,6 +471,12 @@
display: block;
}
// .@{upload-item}-thumbnail {
// position: absolute;
// top: 8px;
// left: 8px;
// }
.@{upload-item}-uploading {
&.@{upload-item} {
background-color: @background-color-light;
@ -515,27 +500,77 @@
}
}
.@{upload-prefix-cls}-success-icon {
color: @success-color;
font-weight: bold;
// ======================= Picture & Text =======================
&-text,
&-picture {
&-container {
transition: opacity @animation-duration-slow, height @animation-duration-slow;
&::before {
display: table;
width: 0;
height: 0;
content: '';
}
// Don't know why span here, just stretch it
.@{upload-prefix-cls}-span {
display: block;
flex: auto;
}
}
// text & picture no need this additional element.
// But it used for picture-card, let's keep it.
.@{upload-prefix-cls}-span {
display: flex;
align-items: center;
> * {
flex: none;
}
}
.@{upload-item}-name {
flex: auto;
padding: 0 @padding-xs;
}
.@{upload-item}-card-actions {
position: static;
}
}
.@{upload-prefix-cls}-animate-enter,
.@{upload-prefix-cls}-animate-leave,
// ============================ Text ============================
&-text {
.@{upload-prefix-cls}-text-icon {
.@{iconfont-css-prefix} {
position: static;
}
}
}
// =========================== Motion ===========================
// .@{upload-prefix-cls}-animate-appear,
// .@{upload-prefix-cls}-animate-enter,
// .@{upload-prefix-cls}-animate-leave,
.@{upload-prefix-cls}-animate-inline-appear,
.@{upload-prefix-cls}-animate-inline-enter,
.@{upload-prefix-cls}-animate-inline-leave {
animation-duration: 0.3s;
animation-duration: @animation-duration-slow;
animation-fill-mode: @ease-in-out-circ;
}
.@{upload-prefix-cls}-animate-enter {
animation-name: uploadAnimateIn;
}
// .@{upload-prefix-cls}-animate-appear,
// .@{upload-prefix-cls}-animate-enter {
// animation-name: uploadAnimateIn;
// }
.@{upload-prefix-cls}-animate-leave {
animation-name: uploadAnimateOut;
}
// .@{upload-prefix-cls}-animate-leave {
// animation-name: uploadAnimateOut;
// }
.@{upload-prefix-cls}-animate-inline-appear,
.@{upload-prefix-cls}-animate-inline-enter {
animation-name: uploadAnimateInlineIn;
}
@ -545,23 +580,23 @@
}
}
@keyframes uploadAnimateIn {
from {
height: 0;
margin: 0;
padding: 0;
opacity: 0;
}
}
// @keyframes uploadAnimateIn {
// from {
// height: 0;
// margin: 0;
// padding: 0;
// opacity: 0;
// }
// }
@keyframes uploadAnimateOut {
to {
height: 0;
margin: 0;
padding: 0;
opacity: 0;
}
}
// @keyframes uploadAnimateOut {
// to {
// height: 0;
// margin: 0;
// padding: 0;
// opacity: 0;
// }
// }
@keyframes uploadAnimateInlineIn {
from {

View File

@ -129,7 +129,7 @@
"rc-input-number": "~6.1.0",
"rc-mentions": "~1.5.0",
"rc-menu": "~8.10.0",
"rc-motion": "^2.2.0",
"rc-motion": "^2.4.0",
"rc-notification": "~4.5.2",
"rc-pagination": "~3.1.0",
"rc-picker": "~2.4.1",
@ -235,7 +235,7 @@
"open": "^7.0.3",
"preact": "^10.0.0",
"preact-compat": "^3.18.5",
"prettier": "^2.0.1",
"prettier": "^2.2.0",
"pretty-quick": "^3.0.0",
"querystring": "^0.2.0",
"rc-footer": "^0.6.3",
@ -271,7 +271,7 @@
"reqwest": "^2.0.5",
"rimraf": "^3.0.0",
"scrollama": "^2.0.0",
"simple-git": "^2.0.0",
"simple-git": "^2.23.0",
"string-replace-loader": "^2.3.0",
"stylelint": "^13.0.0",
"stylelint-config-prettier": "^8.0.0",