# Component/Upload/ImageUpload

> Props: component-upload-imageupload.props.txt

## Examples


### Accept Case Insensitive

**자동 정규화**: 대소문자가 혼합된 확장자를 자동으로 소문자로 변환하고 MIME 타입으로 정규화합니다.

```tsx
{
  render: (args: ImageUploadProps) => {
    const [imageList, setImageList] = useState<string[]>([]);
    const fileList: ImageFile[] = useMemo(() => imageList.map((image_url, idx) => ({
      key: `image_${idx}`,
      src: image_url,
      status: 'done'
    })), [imageList]);
    const handleDragEnd = (reorderedList: ImageFile[]) => {
      const newImageList = reorderedList.map(file => file.src || '');
      setImageList(newImageList);
    };
    const handleChange = (fileList: File | File[]) => {
      // file upload api 연동
      // return file upload status or process percent calc from server...
      const ImageUploadResult: ImageFile[] = Array.isArray(fileList) ? fileList.map(file => {
        return {
          value: file,
          status: 'success'
        };
      }) : [{
        value: fileList,
        status: 'success'
      }];
      const newImageUrls = ImageUploadResult.map(file => {
        if (file.value) {
          return URL.createObjectURL(file.value);
        }
        return '';
      }).filter(Boolean);
      setImageList([...imageList, ...newImageUrls]);
    };
    return <ImageUpload {...args} fileList={fileList} onClickFileRemove={(_, index) => setImageList(imageList.filter((_, idx) => idx !== index))} onDragEnd={handleDragEnd} onChange={handleChange} />;
  },
  args: {
    accept: 'PNG, JPG, GIF'
  },
  parameters: {
    docs: {
      description: {
        story: '**자동 정규화**: 대소문자가 혼합된 확장자를 자동으로 소문자로 변환하고 MIME 타입으로 정규화합니다.'
      }
    }
  }
}
```

### Accept Mixed Format

**혼합 형식 지원**: 확장자와 MIME 타입이 혼합된 입력을 자동으로 정규화합니다.

```tsx
{
  render: (args: ImageUploadProps) => {
    const [imageList, setImageList] = useState<string[]>([]);
    const fileList: ImageFile[] = useMemo(() => imageList.map((image_url, idx) => ({
      key: `image_${idx}`,
      src: image_url,
      status: 'done'
    })), [imageList]);
    const handleDragEnd = (reorderedList: ImageFile[]) => {
      const newImageList = reorderedList.map(file => file.src || '');
      setImageList(newImageList);
    };
    const handleChange = (fileList: File | File[]) => {
      // file upload api 연동
      // return file upload status or process percent calc from server...
      const ImageUploadResult: ImageFile[] = Array.isArray(fileList) ? fileList.map(file => {
        return {
          value: file,
          status: 'success'
        };
      }) : [{
        value: fileList,
        status: 'success'
      }];
      const newImageUrls = ImageUploadResult.map(file => {
        if (file.value) {
          return URL.createObjectURL(file.value);
        }
        return '';
      }).filter(Boolean);
      setImageList([...imageList, ...newImageUrls]);
    };
    return <ImageUpload {...args} fileList={fileList} onClickFileRemove={(_, index) => setImageList(imageList.filter((_, idx) => idx !== index))} onDragEnd={handleDragEnd} onChange={handleChange} />;
  },
  args: {
    accept: 'png,image/jpg,gif'
  },
  parameters: {
    docs: {
      description: {
        story: '**혼합 형식 지원**: 확장자와 MIME 타입이 혼합된 입력을 자동으로 정규화합니다.'
      }
    }
  }
}
```

### Accept Wildcard

✅ 기본값으로 모든 이미지 타입을 허용합니다. 기본값으로 설정되어 있습니다.

```tsx
{
  render: (args: ImageUploadProps) => {
    const [imageList, setImageList] = useState<string[]>([]);
    const fileList: ImageFile[] = useMemo(() => imageList.map((image_url, idx) => ({
      key: `image_${idx}`,
      src: image_url,
      status: 'done'
    })), [imageList]);
    const handleDragEnd = (reorderedList: ImageFile[]) => {
      const newImageList = reorderedList.map(file => file.src || '');
      setImageList(newImageList);
    };
    const handleChange = (fileList: File | File[]) => {
      // file upload api 연동
      // return file upload status or process percent calc from server...
      const ImageUploadResult: ImageFile[] = Array.isArray(fileList) ? fileList.map(file => {
        return {
          value: file,
          status: 'success'
        };
      }) : [{
        value: fileList,
        status: 'success'
      }];
      const newImageUrls = ImageUploadResult.map(file => {
        if (file.value) {
          return URL.createObjectURL(file.value);
        }
        return '';
      }).filter(Boolean);
      setImageList([...imageList, ...newImageUrls]);
    };
    return <ImageUpload {...args} fileList={fileList} onClickFileRemove={(_, index) => setImageList(imageList.filter((_, idx) => idx !== index))} onDragEnd={handleDragEnd} onChange={handleChange} />;
  },
  args: {
    accept: '*'
  },
  parameters: {
    docs: {
      description: {
        story: '✅ 기본값으로 모든 이미지 타입을 허용합니다. 기본값으로 설정되어 있습니다.'
      }
    }
  }
}
```

### Accept With Invalid Extensions

**자동 필터링**: 잘못된 확장자는 자동으로 필터링되고, 유효한 확장자만 MIME 타입으로 변환됩니다.

```tsx
{
  render: (args: ImageUploadProps) => {
    const [imageList, setImageList] = useState<string[]>([]);
    const fileList: ImageFile[] = useMemo(() => imageList.map((image_url, idx) => ({
      key: `image_${idx}`,
      src: image_url,
      status: 'done'
    })), [imageList]);
    const handleDragEnd = (reorderedList: ImageFile[]) => {
      const newImageList = reorderedList.map(file => file.src || '');
      setImageList(newImageList);
    };
    const handleChange = (fileList: File | File[]) => {
      // file upload api 연동
      // return file upload status or process percent calc from server...
      const ImageUploadResult: ImageFile[] = Array.isArray(fileList) ? fileList.map(file => {
        return {
          value: file,
          status: 'success'
        };
      }) : [{
        value: fileList,
        status: 'success'
      }];
      const newImageUrls = ImageUploadResult.map(file => {
        if (file.value) {
          return URL.createObjectURL(file.value);
        }
        return '';
      }).filter(Boolean);
      setImageList([...imageList, ...newImageUrls]);
    };
    return <ImageUpload {...args} fileList={fileList} onClickFileRemove={(_, index) => setImageList(imageList.filter((_, idx) => idx !== index))} onDragEnd={handleDragEnd} onChange={handleChange} />;
  },
  args: {
    accept: 'png,invalid,jpg,webp,unknown'
  },
  parameters: {
    docs: {
      description: {
        story: '**자동 필터링**: 잘못된 확장자는 자동으로 필터링되고, 유효한 확장자만 MIME 타입으로 변환됩니다.'
      }
    }
  }
}
```

### Background Dark

```tsx
{
  render: (args: ImageUploadProps) => {
    const [files, setFiles] = useState<Array<ImageFile>>([]);
    const handleChange = (fileList: File | File[]) => {
      // file upload api 연동
      // return file upload status or process percent calc from server...
      const ImageUploadResult: ImageFile[] = Array.isArray(fileList) ? fileList.map(file => {
        return {
          value: file,
          status: 'success'
        };
      }) : [{
        value: fileList,
        status: 'success'
      }];
      setFiles([...files, ...ImageUploadResult]);
    };
    const handleRemoveFile = (file: ImageFile, index: number) => {
      // file remove api 연동
      // 실제 fileRemove api를 호출후, fileList를 갱신해야합니다.
      setFiles(files.filter((_, i) => i !== index));
    };
    const handleClickDownload = (url: string, index: number) => {
      // file download api 연동
      // 실제 fileDownload uri를 호출후, fileList를 갱신해야합니다.
      console.log('handleClickDownload: ', url, index);
    };
    return <ImageUpload {...args} multiple fileList={files} onChange={handleChange} onClickFile={handleClickDownload} onClickFileRemove={handleRemoveFile} />;
  },
  args: {
    multiple: true
  },
  args: {
    ...MultipleImageUpload.args,
    backgroundDark: true
  }
}
```

### Base

```tsx
{
  render: (args: ImageUploadProps) => {
    const [imageList, setImageList] = useState<string[]>([]);
    const fileList: ImageFile[] = useMemo(() => imageList.map((image_url, idx) => ({
      key: `image_${idx}`,
      src: image_url,
      status: 'done'
    })), [imageList]);
    const handleDragEnd = (reorderedList: ImageFile[]) => {
      const newImageList = reorderedList.map(file => file.src || '');
      setImageList(newImageList);
    };
    const handleChange = (fileList: File | File[]) => {
      // file upload api 연동
      // return file upload status or process percent calc from server...
      const ImageUploadResult: ImageFile[] = Array.isArray(fileList) ? fileList.map(file => {
        return {
          value: file,
          status: 'success'
        };
      }) : [{
        value: fileList,
        status: 'success'
      }];
      const newImageUrls = ImageUploadResult.map(file => {
        if (file.value) {
          return URL.createObjectURL(file.value);
        }
        return '';
      }).filter(Boolean);
      setImageList([...imageList, ...newImageUrls]);
    };
    return <ImageUpload {...args} fileList={fileList} onClickFileRemove={(_, index) => setImageList(imageList.filter((_, idx) => idx !== index))} onDragEnd={handleDragEnd} onChange={handleChange} />;
  }
}
```

### Click Upload Button

```tsx
{
  render: (args: ImageUploadProps) => {
    const [imageList, setImageList] = useState<string[]>([]);
    const fileList: ImageFile[] = useMemo(() => imageList.map((image_url, idx) => ({
      key: `image_${idx}`,
      src: image_url,
      status: 'done'
    })), [imageList]);
    const handleDragEnd = (reorderedList: ImageFile[]) => {
      const newImageList = reorderedList.map(file => file.src || '');
      setImageList(newImageList);
    };
    const handleChange = (fileList: File | File[]) => {
      // file upload api 연동
      // return file upload status or process percent calc from server...
      const ImageUploadResult: ImageFile[] = Array.isArray(fileList) ? fileList.map(file => {
        return {
          value: file,
          status: 'success'
        };
      }) : [{
        value: fileList,
        status: 'success'
      }];
      const newImageUrls = ImageUploadResult.map(file => {
        if (file.value) {
          return URL.createObjectURL(file.value);
        }
        return '';
      }).filter(Boolean);
      setImageList([...imageList, ...newImageUrls]);
    };
    return <ImageUpload {...args} fileList={fileList} onClickFileRemove={(_, index) => setImageList(imageList.filter((_, idx) => idx !== index))} onDragEnd={handleDragEnd} onChange={handleChange} />;
  },
  args: {
    onClick: () => {
      alert('click button');
    }
  }
}
```

### Custom Size

```tsx
{
  render: (args: ImageUploadProps) => {
    const [imageList, setImageList] = useState<string[]>([]);
    const fileList: ImageFile[] = useMemo(() => imageList.map((image_url, idx) => ({
      key: `image_${idx}`,
      src: image_url,
      status: 'done'
    })), [imageList]);
    const handleDragEnd = (reorderedList: ImageFile[]) => {
      const newImageList = reorderedList.map(file => file.src || '');
      setImageList(newImageList);
    };
    const handleChange = (fileList: File | File[]) => {
      // file upload api 연동
      // return file upload status or process percent calc from server...
      const ImageUploadResult: ImageFile[] = Array.isArray(fileList) ? fileList.map(file => {
        return {
          value: file,
          status: 'success'
        };
      }) : [{
        value: fileList,
        status: 'success'
      }];
      const newImageUrls = ImageUploadResult.map(file => {
        if (file.value) {
          return URL.createObjectURL(file.value);
        }
        return '';
      }).filter(Boolean);
      setImageList([...imageList, ...newImageUrls]);
    };
    return <ImageUpload {...args} fileList={fileList} onClickFileRemove={(_, index) => setImageList(imageList.filter((_, idx) => idx !== index))} onDragEnd={handleDragEnd} onChange={handleChange} />;
  },
  args: {
    width: 300,
    height: 60
  }
}
```

### Delete Upload Image

```tsx
{
  render: () => {
    const [imageList, setImageList] = useState<string[]>(['https://alpha.wms-image.kakaostyle.com/wms_image/return_qc/20250611/773/1749623019856', 'https://alpha.wms-image.kakaostyle.com/wms_image/return_qc/20250611/773/1749622834149', 'https://alpha.wms-image.kakaostyle.com/wms_image/return_qc/20250611/773/1749623031752', 'https://alpha.wms-image.kakaostyle.com/wms_image/return_qc/20250611/773/1749623019856', 'https://alpha.wms-image.kakaostyle.com/wms_image/return_qc/20250611/773/1749622834149', 'https://alpha.wms-image.kakaostyle.com/wms_image/return_qc/20250611/773/1749622565732', 'https://alpha.wms-image.kakaostyle.com/wms_image/return_qc/20250611/773/1749622551003']);
    const fileList: ImageFile[] = useMemo(() => imageList.map((image_url, idx) => ({
      key: `image_${idx}`,
      src: image_url,
      status: 'done'
    })), [imageList]);
    return <ImageUpload fileList={fileList} onClickFileRemove={(_, index) => setImageList(imageList.filter((_, idx) => idx !== index))} />;
  }
}
```

### Disabled

```tsx
{
  render: (args: ImageUploadProps) => {
    const Files: ImageFile[] = [
      {
        src: 'https://cf.image-farm.s.zigzag.kr/original/cms/2024/10/31/202410310624087665_026101.jpg?width=1029&height=1029&quality=90&format=webp&transparent=true',
        status: 'done',
      },
      {
        src: 'https://cf.image-farm.s.zigzag.kr/original/cms/2024/10/31/202410310624087665_026101.jpg?width=1029&height=1029&quality=90&format=webp&transparent=true',
        status: 'error',
      },
    ];

    return <ImageUpload fileList={Files} onClickFileRemove={() => alert('onClickFileRemove')} {...args} />;
  },
  args: {
    disabled: true
  }
}
```

### Disabled Hide Remove Button

```tsx
{
  render: (args: ImageUploadProps) => {
    const [imageList, setImageList] = useState<string[]>([]);
    const fileList: ImageFile[] = useMemo(() => imageList.map((image_url, idx) => ({
      key: `image_${idx}`,
      src: image_url,
      status: 'done'
    })), [imageList]);
    const handleDragEnd = (reorderedList: ImageFile[]) => {
      const newImageList = reorderedList.map(file => file.src || '');
      setImageList(newImageList);
    };
    const handleChange = (fileList: File | File[]) => {
      // file upload api 연동
      // return file upload status or process percent calc from server...
      const ImageUploadResult: ImageFile[] = Array.isArray(fileList) ? fileList.map(file => {
        return {
          value: file,
          status: 'success'
        };
      }) : [{
        value: fileList,
        status: 'success'
      }];
      const newImageUrls = ImageUploadResult.map(file => {
        if (file.value) {
          return URL.createObjectURL(file.value);
        }
        return '';
      }).filter(Boolean);
      setImageList([...imageList, ...newImageUrls]);
    };
    return <ImageUpload {...args} fileList={fileList} onClickFileRemove={(_, index) => setImageList(imageList.filter((_, idx) => idx !== index))} onDragEnd={handleDragEnd} onChange={handleChange} />;
  },
  args: {
    showRemoveButton: false
  }
}
```

### Draggable Image Upload

이미지를 드래그하여 순서를 변경할 수 있습니다. 드래그 중인 이미지는 그림자와 함께 최상위에 표시됩니다.

```tsx
{
  render: (args: ImageUploadProps) => {
    const Files: ImageFile[] = [
      {
        src: 'https://cf.image-farm.s.zigzag.kr/original/cms/2024/10/31/202410310624087665_026101.jpg?width=1029&height=1029&quality=90&format=webp&transparent=true',
        status: 'done',
      },
      {
        src: 'https://cf.image-farm.s.zigzag.kr/original/cms/2024/10/31/202410310624087665_026101.jpg?width=1029&height=1029&quality=90&format=webp&transparent=true',
        status: 'error',
      },
    ];

    return <ImageUpload fileList={Files} onClickFileRemove={() => alert('onClickFileRemove')} {...args} />;
  },
  render: (args: ImageUploadProps) => {
    const [imageList, setImageList] = useState<string[]>(['https://alpha.wms-image.kakaostyle.com/wms_image/return_qc/20250611/773/1749623019856', 'https://alpha.wms-image.kakaostyle.com/wms_image/return_qc/20250611/773/1749622834149', 'https://alpha.wms-image.kakaostyle.com/wms_image/return_qc/20250611/773/1749623031752', 'https://alpha.wms-image.kakaostyle.com/wms_image/return_qc/20250611/773/1749623019856', 'https://alpha.wms-image.kakaostyle.com/wms_image/return_qc/20250611/773/1749622834149', 'https://alpha.wms-image.kakaostyle.com/wms_image/return_qc/20250611/773/1749622565732', 'https://alpha.wms-image.kakaostyle.com/wms_image/return_qc/20250611/773/1749622551003']);
    const fileList: ImageFile[] = useMemo(() => imageList.map((image_url, idx) => ({
      key: `image_${idx}`,
      src: image_url,
      status: 'done'
    })), [imageList]);
    const handleDragEnd = (reorderedList: ImageFile[]) => {
      const newImageList = reorderedList.map(file => file.src || '');
      setImageList(newImageList);
    };
    const handleChange = (fileList: File | File[]) => {
      // file upload api 연동
      // return file upload status or process percent calc from server...
      const ImageUploadResult: ImageFile[] = Array.isArray(fileList) ? fileList.map(file => {
        return {
          value: file,
          status: 'success'
        };
      }) : [{
        value: fileList,
        status: 'success'
      }];
      const newImageUrls = ImageUploadResult.map(file => {
        if (file.value) {
          return URL.createObjectURL(file.value);
        }
        return '';
      }).filter(Boolean);
      setImageList([...imageList, ...newImageUrls]);
    };
    return <ImageUpload fileList={fileList} onClickFileRemove={(_, index) => setImageList(imageList.filter((_, idx) => idx !== index))} onDragEnd={handleDragEnd} onChange={handleChange} {...args} />;
  },
  args: {
    draggable: true,
    multiple: true
  },
  parameters: {
    docs: {
      description: {
        story: '이미지를 드래그하여 순서를 변경할 수 있습니다. 드래그 중인 이미지는 그림자와 함께 최상위에 표시됩니다.'
      }
    }
  }
}
```

### File Status

```tsx
{
  render: () => {
    const Files: ImageFile[] = [{
      src: 'https://cf.image-farm.s.zigzag.kr/original/cms/2024/10/31/202410310624087665_026101.jpg?width=1029&height=1029&quality=90&format=webp&transparent=true',
      status: 'done',
      label: '대표 이미지'
    }, {
      src: 'https://cf.image-farm.s.zigzag.kr/original/cms/2024/10/31/202410310624087665_026101.jpg?width=1029&height=1029&quality=90&format=webp&transparent=true',
      status: 'uploading',
      removable: false
    }, {
      src: 'https://cf.image-farm.s.zigzag.kr/original/cms/2024/10/31/202410310624087665_026101.jpg?width=1029&height=1029&quality=90&format=webp&transparent=true',
      status: 'error'
    }];
    return <ImageUpload fileList={Files} onClickFileRemove={() => alert('onClickFileRemove')} />;
  }
}
```

### Loading

```tsx
{
  render: (args: ImageUploadProps) => {
    const [files, setFiles] = useState<Array<ImageFile>>([]);
    const handleChange = (fileList: File | File[]) => {
      // file upload api 연동
      // return file upload status or process percent calc from server...
      const ImageUploadResult: ImageFile[] = Array.isArray(fileList) ? fileList.map(file => {
        return {
          value: file,
          status: 'success'
        };
      }) : [{
        value: fileList,
        status: 'success'
      }];
      setFiles([...files, ...ImageUploadResult]);
    };
    const handleRemoveFile = (file: ImageFile, index: number) => {
      // file remove api 연동
      // 실제 fileRemove api를 호출후, fileList를 갱신해야합니다.
      setFiles(files.filter((_, i) => i !== index));
    };
    const handleClickDownload = (url: string, index: number) => {
      // file download api 연동
      // 실제 fileDownload uri를 호출후, fileList를 갱신해야합니다.
      console.log('handleClickDownload: ', url, index);
    };
    return <ImageUpload {...args} multiple fileList={files} onChange={handleChange} onClickFile={handleClickDownload} onClickFileRemove={handleRemoveFile} />;
  },
  args: {
    multiple: true
  },
  args: {
    ...MultipleImageUpload.args,
    loading: true
  }
}
```

### Max Count

```tsx
{
  render: (args: ImageUploadProps) => {
    const [files, setFiles] = useState<Array<ImageFile>>([]);
    const handleChange = (fileList: File | File[]) => {
      // file upload api 연동
      // return file upload status or process percent calc from server...
      const ImageUploadResult: ImageFile[] = Array.isArray(fileList) ? fileList.map(file => {
        return {
          value: file,
          status: 'success'
        };
      }) : [{
        value: fileList,
        status: 'success'
      }];
      setFiles([...files, ...ImageUploadResult]);
    };
    const handleRemoveFile = (file: ImageFile, index: number) => {
      // file remove api 연동
      // 실제 fileRemove api를 호출후, fileList를 갱신해야합니다.
      setFiles(files.filter((_, i) => i !== index));
    };
    const handleClickDownload = (url: string, index: number) => {
      // file download api 연동
      // 실제 fileDownload uri를 호출후, fileList를 갱신해야합니다.
      console.log('handleClickDownload: ', url, index);
    };
    return <ImageUpload {...args} multiple fileList={files} onChange={handleChange} onClickFile={handleClickDownload} onClickFileRemove={handleRemoveFile} />;
  },
  args: {
    multiple: true
  },
  args: {
    ...MultipleImageUpload.args,
    maxCount: 3
  }
}
```

### Multiple Image Upload

```tsx
{
  render: (args: ImageUploadProps) => {
    const [files, setFiles] = useState<Array<ImageFile>>([]);
    const handleChange = (fileList: File | File[]) => {
      // file upload api 연동
      // return file upload status or process percent calc from server...
      const ImageUploadResult: ImageFile[] = Array.isArray(fileList) ? fileList.map(file => {
        return {
          value: file,
          status: 'success'
        };
      }) : [{
        value: fileList,
        status: 'success'
      }];
      setFiles([...files, ...ImageUploadResult]);
    };
    const handleRemoveFile = (file: ImageFile, index: number) => {
      // file remove api 연동
      // 실제 fileRemove api를 호출후, fileList를 갱신해야합니다.
      setFiles(files.filter((_, i) => i !== index));
    };
    const handleClickDownload = (url: string, index: number) => {
      // file download api 연동
      // 실제 fileDownload uri를 호출후, fileList를 갱신해야합니다.
      console.log('handleClickDownload: ', url, index);
    };
    return <ImageUpload {...args} multiple fileList={files} onChange={handleChange} onClickFile={handleClickDownload} onClickFileRemove={handleRemoveFile} />;
  },
  args: {
    multiple: true
  }
}
```

### Object Fit Cover

```tsx
{
  render: (args: ImageUploadProps) => {
    const [imageList, setImageList] = useState<string[]>([]);
    const fileList: ImageFile[] = useMemo(() => imageList.map((image_url, idx) => ({
      key: `image_${idx}`,
      src: image_url,
      status: 'done'
    })), [imageList]);
    const handleDragEnd = (reorderedList: ImageFile[]) => {
      const newImageList = reorderedList.map(file => file.src || '');
      setImageList(newImageList);
    };
    const handleChange = (fileList: File | File[]) => {
      // file upload api 연동
      // return file upload status or process percent calc from server...
      const ImageUploadResult: ImageFile[] = Array.isArray(fileList) ? fileList.map(file => {
        return {
          value: file,
          status: 'success'
        };
      }) : [{
        value: fileList,
        status: 'success'
      }];
      const newImageUrls = ImageUploadResult.map(file => {
        if (file.value) {
          return URL.createObjectURL(file.value);
        }
        return '';
      }).filter(Boolean);
      setImageList([...imageList, ...newImageUrls]);
    };
    return <ImageUpload {...args} fileList={fileList} onClickFileRemove={(_, index) => setImageList(imageList.filter((_, idx) => idx !== index))} onDragEnd={handleDragEnd} onChange={handleChange} />;
  },
  args: {
    objectFit: 'cover'
  }
}
```

### Read Only

```tsx
{
  render: (args: ImageUploadProps) => {
    const Files: ImageFile[] = [
      {
        src: 'https://cf.image-farm.s.zigzag.kr/original/cms/2024/10/31/202410310624087665_026101.jpg?width=1029&height=1029&quality=90&format=webp&transparent=true',
        status: 'done',
      },
      {
        src: 'https://cf.image-farm.s.zigzag.kr/original/cms/2024/10/31/202410310624087665_026101.jpg?width=1029&height=1029&quality=90&format=webp&transparent=true',
        status: 'error',
      },
    ];

    return <ImageUpload fileList={Files} onClickFileRemove={() => alert('onClickFileRemove')} {...args} />;
  },
  args: {
    readOnly: true
  }
}
```

### Small Size

```tsx
{
  render: (args: ImageUploadProps) => {
    const [imageList, setImageList] = useState<string[]>([]);
    const fileList: ImageFile[] = useMemo(() => imageList.map((image_url, idx) => ({
      key: `image_${idx}`,
      src: image_url,
      status: 'done'
    })), [imageList]);
    const handleDragEnd = (reorderedList: ImageFile[]) => {
      const newImageList = reorderedList.map(file => file.src || '');
      setImageList(newImageList);
    };
    const handleChange = (fileList: File | File[]) => {
      // file upload api 연동
      // return file upload status or process percent calc from server...
      const ImageUploadResult: ImageFile[] = Array.isArray(fileList) ? fileList.map(file => {
        return {
          value: file,
          status: 'success'
        };
      }) : [{
        value: fileList,
        status: 'success'
      }];
      const newImageUrls = ImageUploadResult.map(file => {
        if (file.value) {
          return URL.createObjectURL(file.value);
        }
        return '';
      }).filter(Boolean);
      setImageList([...imageList, ...newImageUrls]);
    };
    return <ImageUpload {...args} fileList={fileList} onClickFileRemove={(_, index) => setImageList(imageList.filter((_, idx) => idx !== index))} onDragEnd={handleDragEnd} onChange={handleChange} />;
  },
  args: {
    size: 'small'
  }
}
```