attachment.tsx 3.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. import React from "react";
  2. import { FileItem } from '../upload/interface';
  3. import Image from '../image';
  4. import { IconAlertCircle, IconBriefStroked, IconClear } from '@douyinfe/semi-icons';
  5. import { strings, cssClasses } from '@douyinfe/semi-foundation/chat/constants';
  6. import cls from 'classnames';
  7. import { Progress } from "../index";
  8. const { PREFIX_ATTACHMENT, } = cssClasses;
  9. const { PIC_SUFFIX_ARRAY, PIC_PREFIX } = strings;
  10. interface AttachmentProps {
  11. className?: string;
  12. attachment?: FileItem[];
  13. onClear?: (item: FileItem) => void;
  14. showClear?: boolean
  15. }
  16. interface FileProps {
  17. url?: string;
  18. name?: string;
  19. size?: string;
  20. type?: string
  21. }
  22. export const FileAttachment = React.memo((props: FileProps) => {
  23. const { url, name, size, type } = props;
  24. return <a
  25. href={url}
  26. target="_blank"
  27. className={`${PREFIX_ATTACHMENT}-file`} rel="noreferrer"
  28. >
  29. <IconBriefStroked size="extra-large" className={`${PREFIX_ATTACHMENT}-file-icon`}/>
  30. <div className={`${PREFIX_ATTACHMENT}-file-info`}>
  31. <span className={`${PREFIX_ATTACHMENT}-file-title`}>{name}</span>
  32. <span className={`${PREFIX_ATTACHMENT}-file-metadata`}>
  33. <span className={`${PREFIX_ATTACHMENT}-file-type`}>{type}</span>
  34. {type ? ' · ' : ''}{size}
  35. </span>
  36. </div>
  37. </a>;
  38. });
  39. export const ImageAttachment = React.memo((props: {src: string}) => {
  40. const { src } = props;
  41. return <Image
  42. className={`${PREFIX_ATTACHMENT}-img`}
  43. width={60}
  44. height={60}
  45. src={src}
  46. />;
  47. });
  48. const Attachment = React.memo((props: AttachmentProps) => {
  49. const { attachment, onClear, showClear = true, className } = props;
  50. return (
  51. <div
  52. className={cls(PREFIX_ATTACHMENT, { [className]: className })}
  53. >
  54. {
  55. attachment.map(item => {
  56. const { percent, status } = item;
  57. const suffix = item?.name.split('.').pop();
  58. const isImg = item?.fileInstance?.type?.startsWith(PIC_PREFIX) || PIC_SUFFIX_ARRAY.includes(suffix);
  59. const realType = suffix ?? item?.fileInstance?.type?.split('/').pop();
  60. const showProcess = !(percent === 100 || typeof percent === 'undefined') && status === strings.FILE_STATUS.UPLOADING;
  61. return <div
  62. className={`${PREFIX_ATTACHMENT}-item`}
  63. key={item.uid}
  64. >
  65. {isImg ? (
  66. <ImageAttachment src={item.url} />
  67. ) : (
  68. <FileAttachment
  69. url={item.url}
  70. name={item.name}
  71. size={item.size}
  72. type={realType}
  73. />
  74. )}
  75. {showClear && <IconClear
  76. size="large"
  77. className={`${PREFIX_ATTACHMENT}-clear`}
  78. onClick={() => {
  79. onClear && onClear(item);
  80. }}
  81. />}
  82. {showProcess && <Progress percent={percent} type="circle" size="small" width={30} className={`${PREFIX_ATTACHMENT}-process`} aria-label="upload progress" />}
  83. {[strings.FILE_STATUS.UPLOAD_FAIL, strings.FILE_STATUS.VALID_FAIL].includes(status) && <IconAlertCircle className={`${PREFIX_ATTACHMENT}-fail`} />}
  84. </div>;
  85. })
  86. }
  87. </div>
  88. );
  89. });
  90. export default Attachment;