# Component/Upload/ImageUpload > Props: component-upload-imageupload.props.txt ## Examples ### Accept Case Insensitive **자동 정규화**: 대소문자가 혼합된 확장자를 자동으로 소문자로 변환하고 MIME 타입으로 정규화합니다. ```tsx { render: (args: ImageUploadProps) => { const [imageList, setImageList] = useState([]); 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 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([]); 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 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([]); 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 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([]); 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 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>([]); 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 ; }, args: { multiple: true }, args: { ...MultipleImageUpload.args, backgroundDark: true } } ``` ### Base ```tsx { render: (args: ImageUploadProps) => { const [imageList, setImageList] = useState([]); 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 setImageList(imageList.filter((_, idx) => idx !== index))} onDragEnd={handleDragEnd} onChange={handleChange} />; } } ``` ### Click Upload Button ```tsx { render: (args: ImageUploadProps) => { const [imageList, setImageList] = useState([]); 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 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([]); 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 setImageList(imageList.filter((_, idx) => idx !== index))} onDragEnd={handleDragEnd} onChange={handleChange} />; }, args: { width: 300, height: 60 } } ``` ### Delete Upload Image ```tsx { render: () => { const [imageList, setImageList] = useState(['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 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 alert('onClickFileRemove')} {...args} />; }, args: { disabled: true } } ``` ### Disabled Hide Remove Button ```tsx { render: (args: ImageUploadProps) => { const [imageList, setImageList] = useState([]); 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 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 alert('onClickFileRemove')} {...args} />; }, render: (args: ImageUploadProps) => { const [imageList, setImageList] = useState(['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 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 alert('onClickFileRemove')} />; } } ``` ### Loading ```tsx { render: (args: ImageUploadProps) => { const [files, setFiles] = useState>([]); 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 ; }, args: { multiple: true }, args: { ...MultipleImageUpload.args, loading: true } } ``` ### Max Count ```tsx { render: (args: ImageUploadProps) => { const [files, setFiles] = useState>([]); 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 ; }, args: { multiple: true }, args: { ...MultipleImageUpload.args, maxCount: 3 } } ``` ### Multiple Image Upload ```tsx { render: (args: ImageUploadProps) => { const [files, setFiles] = useState>([]); 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 ; }, args: { multiple: true } } ``` ### Object Fit Cover ```tsx { render: (args: ImageUploadProps) => { const [imageList, setImageList] = useState([]); 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 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 alert('onClickFileRemove')} {...args} />; }, args: { readOnly: true } } ``` ### Small Size ```tsx { render: (args: ImageUploadProps) => { const [imageList, setImageList] = useState([]); 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 setImageList(imageList.filter((_, idx) => idx !== index))} onDragEnd={handleDragEnd} onChange={handleChange} />; }, args: { size: 'small' } } ```