attachment.tsx 3.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. import React from "react";
  2. import { FileItem } from '../upload/interface';
  3. import Image from '../image';
  4. import { 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 === '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. </div>;
  84. })
  85. }
  86. </div>
  87. );
  88. });
  89. export default Attachment;