"use client"; import { useEffect, useId, useRef, useState, type ChangeEvent, type CSSProperties, type DragEvent, } from "react"; import { FoxFormLabel, type FoxFormLabelRequirement } from "../fox-form-label"; import { cx } from "../../utils"; import { FoxButton } from "../fox-button"; import { FoxIconButton } from "../fox-icon-button"; import { FoxInput } from "../fox-input"; import { FoxTextButton } from "../fox-text-button"; export type FoxFileUploadMode = "default" | "area" | "image"; /** 목록에 그릴 파일 한 줄. 업로드 상태는 호출부가 이 모양으로 바꿔서 넘긴다. */ export interface FoxFileItem { /** 목록에서 구분하는 키. */ id: string; /** 확장자를 뺀 이름. 길면 말줄임된다. */ name: string; /** 이름 뒤에 붙는 표기 — 시안은 `.PDF (20KB)`. 줄어들지 않는다. */ meta?: string; /** 참이면 줄이 붉어지고 `message`가 아래에 붙는다. */ error?: boolean; message?: string; /** image 모드에서 썸네일로 쓸 주소. */ previewUrl?: string; } export interface FoxFileUploadProps { mode?: FoxFileUploadMode; /** 주면 제어 컴포넌트가 된다. 없으면 고른 파일을 안에서 들고 있는다. */ files?: FoxFileItem[]; defaultFiles?: FoxFileItem[]; /** 목록이 바뀔 때(고르기·삭제) 부른다. */ onFilesChange?: (files: FoxFileItem[]) => void; /** 파일을 고르면 원본 `File`을 그대로 넘긴다 — 업로드는 호출부가 한다. */ onSelect?: (picked: File[]) => void; onRemove?: (id: string) => void; accept?: string; multiple?: boolean; /** * 네이티브 파일 입력의 `name`. 주면 고른 파일이 감싼 `