index.js 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. "use client";
  2. import _toConsumableArray from "@babel/runtime/helpers/esm/toConsumableArray";
  3. import * as React from 'react';
  4. import FileTwoTone from "@ant-design/icons/es/icons/FileTwoTone";
  5. import LoadingOutlined from "@ant-design/icons/es/icons/LoadingOutlined";
  6. import PaperClipOutlined from "@ant-design/icons/es/icons/PaperClipOutlined";
  7. import PictureTwoTone from "@ant-design/icons/es/icons/PictureTwoTone";
  8. import classNames from 'classnames';
  9. import CSSMotion, { CSSMotionList } from 'rc-motion';
  10. import omit from "rc-util/es/omit";
  11. import useForceUpdate from '../../_util/hooks/useForceUpdate';
  12. import initCollapseMotion from '../../_util/motion';
  13. import { cloneElement } from '../../_util/reactNode';
  14. import Button from '../../button';
  15. import { ConfigContext } from '../../config-provider';
  16. import { isImageUrl, previewImage } from '../utils';
  17. import ListItem from './ListItem';
  18. const InternalUploadList = (props, ref) => {
  19. const {
  20. listType = 'text',
  21. previewFile = previewImage,
  22. onPreview,
  23. onDownload,
  24. onRemove,
  25. locale,
  26. iconRender,
  27. isImageUrl: isImgUrl = isImageUrl,
  28. prefixCls: customizePrefixCls,
  29. items = [],
  30. showPreviewIcon = true,
  31. showRemoveIcon = true,
  32. showDownloadIcon = false,
  33. removeIcon,
  34. previewIcon,
  35. downloadIcon,
  36. extra,
  37. progress = {
  38. size: [-1, 2],
  39. showInfo: false
  40. },
  41. appendAction,
  42. appendActionVisible = true,
  43. itemRender,
  44. disabled
  45. } = props;
  46. const forceUpdate = useForceUpdate();
  47. const [motionAppear, setMotionAppear] = React.useState(false);
  48. const isPictureCardOrCirle = ['picture-card', 'picture-circle'].includes(listType);
  49. // ============================= Effect =============================
  50. React.useEffect(() => {
  51. if (!listType.startsWith('picture')) {
  52. return;
  53. }
  54. (items || []).forEach(file => {
  55. if (!(file.originFileObj instanceof File || file.originFileObj instanceof Blob) || file.thumbUrl !== undefined) {
  56. return;
  57. }
  58. file.thumbUrl = '';
  59. previewFile === null || previewFile === void 0 ? void 0 : previewFile(file.originFileObj).then(previewDataUrl => {
  60. // Need append '' to avoid dead loop
  61. file.thumbUrl = previewDataUrl || '';
  62. forceUpdate();
  63. });
  64. });
  65. }, [listType, items, previewFile]);
  66. React.useEffect(() => {
  67. setMotionAppear(true);
  68. }, []);
  69. // ============================= Events =============================
  70. const onInternalPreview = (file, e) => {
  71. if (!onPreview) {
  72. return;
  73. }
  74. e === null || e === void 0 ? void 0 : e.preventDefault();
  75. return onPreview(file);
  76. };
  77. const onInternalDownload = file => {
  78. if (typeof onDownload === 'function') {
  79. onDownload(file);
  80. } else if (file.url) {
  81. window.open(file.url);
  82. }
  83. };
  84. const onInternalClose = file => {
  85. onRemove === null || onRemove === void 0 ? void 0 : onRemove(file);
  86. };
  87. const internalIconRender = file => {
  88. if (iconRender) {
  89. return iconRender(file, listType);
  90. }
  91. const isLoading = file.status === 'uploading';
  92. if (listType.startsWith('picture')) {
  93. const loadingIcon = listType === 'picture' ? /*#__PURE__*/React.createElement(LoadingOutlined, null) : locale.uploading;
  94. const fileIcon = (isImgUrl === null || isImgUrl === void 0 ? void 0 : isImgUrl(file)) ? /*#__PURE__*/React.createElement(PictureTwoTone, null) : /*#__PURE__*/React.createElement(FileTwoTone, null);
  95. return isLoading ? loadingIcon : fileIcon;
  96. }
  97. return isLoading ? /*#__PURE__*/React.createElement(LoadingOutlined, null) : /*#__PURE__*/React.createElement(PaperClipOutlined, null);
  98. };
  99. const actionIconRender = (customIcon, callback, prefixCls, title, acceptUploadDisabled) => {
  100. const btnProps = {
  101. type: 'text',
  102. size: 'small',
  103. title,
  104. onClick: e => {
  105. var _a, _b;
  106. callback();
  107. if (/*#__PURE__*/React.isValidElement(customIcon)) {
  108. (_b = (_a = customIcon.props).onClick) === null || _b === void 0 ? void 0 : _b.call(_a, e);
  109. }
  110. },
  111. className: `${prefixCls}-list-item-action`,
  112. disabled: acceptUploadDisabled ? disabled : false
  113. };
  114. return /*#__PURE__*/React.isValidElement(customIcon) ? (/*#__PURE__*/React.createElement(Button, Object.assign({}, btnProps, {
  115. icon: cloneElement(customIcon, Object.assign(Object.assign({}, customIcon.props), {
  116. onClick: () => {}
  117. }))
  118. }))) : (/*#__PURE__*/React.createElement(Button, Object.assign({}, btnProps), /*#__PURE__*/React.createElement("span", null, customIcon)));
  119. };
  120. // ============================== Ref ===============================
  121. // Test needs
  122. React.useImperativeHandle(ref, () => ({
  123. handlePreview: onInternalPreview,
  124. handleDownload: onInternalDownload
  125. }));
  126. const {
  127. getPrefixCls
  128. } = React.useContext(ConfigContext);
  129. // ============================= Render =============================
  130. const prefixCls = getPrefixCls('upload', customizePrefixCls);
  131. const rootPrefixCls = getPrefixCls();
  132. const listClassNames = classNames(`${prefixCls}-list`, `${prefixCls}-list-${listType}`);
  133. const listItemMotion = React.useMemo(() => omit(initCollapseMotion(rootPrefixCls), ['onAppearEnd', 'onEnterEnd', 'onLeaveEnd']), [rootPrefixCls]);
  134. const motionConfig = Object.assign(Object.assign({}, isPictureCardOrCirle ? {} : listItemMotion), {
  135. motionDeadline: 2000,
  136. motionName: `${prefixCls}-${isPictureCardOrCirle ? 'animate-inline' : 'animate'}`,
  137. keys: _toConsumableArray(items.map(file => ({
  138. key: file.uid,
  139. file
  140. }))),
  141. motionAppear
  142. });
  143. return /*#__PURE__*/React.createElement("div", {
  144. className: listClassNames
  145. }, /*#__PURE__*/React.createElement(CSSMotionList, Object.assign({}, motionConfig, {
  146. component: false
  147. }), ({
  148. key,
  149. file,
  150. className: motionClassName,
  151. style: motionStyle
  152. }) => (/*#__PURE__*/React.createElement(ListItem, {
  153. key: key,
  154. locale: locale,
  155. prefixCls: prefixCls,
  156. className: motionClassName,
  157. style: motionStyle,
  158. file: file,
  159. items: items,
  160. progress: progress,
  161. listType: listType,
  162. isImgUrl: isImgUrl,
  163. showPreviewIcon: showPreviewIcon,
  164. showRemoveIcon: showRemoveIcon,
  165. showDownloadIcon: showDownloadIcon,
  166. removeIcon: removeIcon,
  167. previewIcon: previewIcon,
  168. downloadIcon: downloadIcon,
  169. extra: extra,
  170. iconRender: internalIconRender,
  171. actionIconRender: actionIconRender,
  172. itemRender: itemRender,
  173. onPreview: onInternalPreview,
  174. onDownload: onInternalDownload,
  175. onClose: onInternalClose
  176. }))), appendAction && (/*#__PURE__*/React.createElement(CSSMotion, Object.assign({}, motionConfig, {
  177. visible: appendActionVisible,
  178. forceRender: true
  179. }), ({
  180. className: motionClassName,
  181. style: motionStyle
  182. }) => cloneElement(appendAction, oriProps => ({
  183. className: classNames(oriProps.className, motionClassName),
  184. style: Object.assign(Object.assign(Object.assign({}, motionStyle), {
  185. // prevent the element has hover css pseudo-class that may cause animation to end prematurely.
  186. pointerEvents: motionClassName ? 'none' : undefined
  187. }), oriProps.style)
  188. })))));
  189. };
  190. const UploadList = /*#__PURE__*/React.forwardRef(InternalUploadList);
  191. if (process.env.NODE_ENV !== 'production') {
  192. UploadList.displayName = 'UploadList';
  193. }
  194. export default UploadList;