@turinhub/atomix-common-ui 0.4.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. package/README.md +20 -2
  2. package/dist/AuthPanel-CTKx618F.cjs +2 -0
  3. package/dist/AuthPanel-CTKx618F.cjs.map +1 -0
  4. package/dist/AuthPanel-Cn_WwmjX.js +703 -0
  5. package/dist/AuthPanel-Cn_WwmjX.js.map +1 -0
  6. package/dist/PDFSidebar-4DtXqqzN.cjs +2 -0
  7. package/dist/PDFSidebar-4DtXqqzN.cjs.map +1 -0
  8. package/dist/PDFSidebar-ClnrF4Br.js +239 -0
  9. package/dist/PDFSidebar-ClnrF4Br.js.map +1 -0
  10. package/dist/auth.cjs +2 -0
  11. package/dist/auth.cjs.map +1 -0
  12. package/dist/auth.d.ts +11 -0
  13. package/dist/auth.d.ts.map +1 -0
  14. package/dist/auth.js +9 -0
  15. package/dist/auth.js.map +1 -0
  16. package/dist/components/AuthLoginPanel.d.ts +55 -0
  17. package/dist/components/AuthLoginPanel.d.ts.map +1 -0
  18. package/dist/components/AuthPageShell.d.ts +11 -0
  19. package/dist/components/AuthPageShell.d.ts.map +1 -0
  20. package/dist/components/AuthPanel.d.ts +20 -0
  21. package/dist/components/AuthPanel.d.ts.map +1 -0
  22. package/dist/components/AuthRegisterPanel.d.ts +34 -0
  23. package/dist/components/AuthRegisterPanel.d.ts.map +1 -0
  24. package/dist/components/AuthVisualCarousel.d.ts +22 -0
  25. package/dist/components/AuthVisualCarousel.d.ts.map +1 -0
  26. package/dist/components/DataTable.d.ts +2 -2
  27. package/dist/components/DataTable.d.ts.map +1 -1
  28. package/dist/components/ImageReader.d.ts +44 -0
  29. package/dist/components/ImageReader.d.ts.map +1 -0
  30. package/dist/components/MarkdownReader.d.ts.map +1 -1
  31. package/dist/components/PDFReader.d.ts.map +1 -1
  32. package/dist/components/PDFSidebar.d.ts.map +1 -1
  33. package/dist/components/SimplePDFReader.d.ts.map +1 -1
  34. package/dist/components/TableHeader.d.ts.map +1 -1
  35. package/dist/components/TablePagination.d.ts +2 -1
  36. package/dist/components/TablePagination.d.ts.map +1 -1
  37. package/dist/components/VideoReader.d.ts +39 -0
  38. package/dist/components/VideoReader.d.ts.map +1 -0
  39. package/dist/components/media-utils.d.ts +9 -0
  40. package/dist/components/media-utils.d.ts.map +1 -0
  41. package/dist/components/ui/switch.d.ts +5 -0
  42. package/dist/components/ui/switch.d.ts.map +1 -0
  43. package/dist/data-table.cjs +1 -1
  44. package/dist/data-table.cjs.map +1 -1
  45. package/dist/data-table.js +83 -73
  46. package/dist/data-table.js.map +1 -1
  47. package/dist/file-upload.cjs +1 -1
  48. package/dist/file-upload.cjs.map +1 -1
  49. package/dist/file-upload.js +36 -36
  50. package/dist/file-upload.js.map +1 -1
  51. package/dist/image-reader.cjs +2 -0
  52. package/dist/image-reader.cjs.map +1 -0
  53. package/dist/image-reader.d.ts +3 -0
  54. package/dist/image-reader.d.ts.map +1 -0
  55. package/dist/image-reader.js +215 -0
  56. package/dist/image-reader.js.map +1 -0
  57. package/dist/index.cjs +1 -1
  58. package/dist/index.d.ts +10 -0
  59. package/dist/index.d.ts.map +1 -1
  60. package/dist/index.js +8 -2
  61. package/dist/index.js.map +1 -1
  62. package/dist/markdown-reader.cjs +1 -1
  63. package/dist/markdown-reader.cjs.map +1 -1
  64. package/dist/markdown-reader.js +28 -24
  65. package/dist/markdown-reader.js.map +1 -1
  66. package/dist/media-utils-5UPuocc1.js +23 -0
  67. package/dist/media-utils-5UPuocc1.js.map +1 -0
  68. package/dist/media-utils-X1dDYP9W.cjs +2 -0
  69. package/dist/media-utils-X1dDYP9W.cjs.map +1 -0
  70. package/dist/pdf-reader.cjs +1 -1
  71. package/dist/pdf-reader.cjs.map +1 -1
  72. package/dist/pdf-reader.js +170 -121
  73. package/dist/pdf-reader.js.map +1 -1
  74. package/dist/pdf-sidebar.cjs +1 -1
  75. package/dist/pdf-sidebar.js +1 -1
  76. package/dist/simple-pdf-reader.cjs +1 -1
  77. package/dist/simple-pdf-reader.cjs.map +1 -1
  78. package/dist/simple-pdf-reader.js +138 -105
  79. package/dist/simple-pdf-reader.js.map +1 -1
  80. package/dist/table-header.cjs +1 -1
  81. package/dist/table-header.cjs.map +1 -1
  82. package/dist/table-header.js +42 -34
  83. package/dist/table-header.js.map +1 -1
  84. package/dist/table-pagination.cjs +1 -1
  85. package/dist/table-pagination.cjs.map +1 -1
  86. package/dist/table-pagination.js +49 -43
  87. package/dist/table-pagination.js.map +1 -1
  88. package/dist/types/component-types.d.ts +2 -0
  89. package/dist/types/component-types.d.ts.map +1 -1
  90. package/dist/video-reader.cjs +2 -0
  91. package/dist/video-reader.cjs.map +1 -0
  92. package/dist/video-reader.d.ts +3 -0
  93. package/dist/video-reader.d.ts.map +1 -0
  94. package/dist/video-reader.js +158 -0
  95. package/dist/video-reader.js.map +1 -0
  96. package/package.json +32 -1
  97. package/dist/PDFSidebar-BBtucLK6.js +0 -232
  98. package/dist/PDFSidebar-BBtucLK6.js.map +0 -1
  99. package/dist/PDFSidebar-Di0D-yPS.cjs +0 -2
  100. package/dist/PDFSidebar-Di0D-yPS.cjs.map +0 -1
  101. package/dist/index-BiA_tnaq.cjs +0 -13
  102. package/dist/index-BiA_tnaq.cjs.map +0 -1
  103. package/dist/index-BypbGNpR.js +0 -18821
  104. package/dist/index-BypbGNpR.js.map +0 -1
@@ -3,23 +3,23 @@ import { UploadCloud as fs, FileText as hs, X as ps, Loader2 as gs, CheckCircle2
3
3
  import { useState as V, useRef as vs, useEffect as Ns } from "react";
4
4
  import { c as R } from "./utils-B6yFEsav.js";
5
5
  const bs = (r) => r < 1024 ? `${r} B` : r < 1024 * 1024 ? `${(r / 1024).toFixed(1)} KB` : r < 1024 * 1024 * 1024 ? `${(r / 1024 / 1024).toFixed(1)} MB` : `${(r / 1024 / 1024 / 1024).toFixed(1)} GB`, q = (r) => `${r.name}-${r.size}-${r.lastModified}-${Math.random().toString(36).slice(2)}`, ws = (r) => {
6
- const o = r.lastIndexOf(".");
7
- return o > -1 ? r.slice(o).toLowerCase() : "";
8
- }, ks = (r, o) => {
9
- if (!o) return !0;
6
+ const c = r.lastIndexOf(".");
7
+ return c > -1 ? r.slice(c).toLowerCase() : "";
8
+ }, ks = (r, c) => {
9
+ if (!c) return !0;
10
10
  const u = r.type.toLowerCase(), j = ws(r.name);
11
- return o.split(",").map((d) => d.trim().toLowerCase()).filter(Boolean).some((d) => d.startsWith(".") ? j === d : d.endsWith("/*") ? u.startsWith(d.slice(0, -1)) : u === d);
12
- }, Cs = (r, o) => r instanceof Error && r.message ? r.message : typeof r == "string" && r ? r : o;
11
+ return c.split(",").map((d) => d.trim().toLowerCase()).filter(Boolean).some((d) => d.startsWith(".") ? j === d : d.endsWith("/*") ? u.startsWith(d.slice(0, -1)) : u === d);
12
+ }, Cs = (r, c) => r instanceof Error && r.message ? r.message : typeof r == "string" && r ? r : c;
13
13
  function Is({
14
14
  components: r,
15
- title: o = "文件上传",
15
+ title: c = "文件上传",
16
16
  description: u = "选择文件后开始上传,支持 Tale SDK 的直接上传和预签名上传流程。",
17
17
  helperText: j,
18
18
  accept: d,
19
19
  multiple: N = !1,
20
20
  maxFiles: J,
21
21
  maxSize: b,
22
- disabled: c = !1,
22
+ disabled: o = !1,
23
23
  autoUpload: Q = !1,
24
24
  showUploadButton: Y,
25
25
  showResetButton: w = !0,
@@ -49,11 +49,11 @@ function Is({
49
49
  }, [l, y]), !r)
50
50
  return /* @__PURE__ */ e.jsx("div", { className: "p-4 text-center text-destructive", children: "错误:请通过 components prop 注入 UI 组件" });
51
51
  const {
52
- Card: cs,
52
+ Card: os,
53
53
  CardHeader: O,
54
54
  CardTitle: I,
55
55
  CardDescription: B,
56
- CardContent: os,
56
+ CardContent: cs,
57
57
  CardFooter: P,
58
58
  Button: f
59
59
  } = r, h = (s) => {
@@ -132,7 +132,7 @@ function Is({
132
132
  for (const t of s)
133
133
  await F(t);
134
134
  }, G = (s) => {
135
- if (!s || c) return;
135
+ if (!s || o) return;
136
136
  const t = Array.from(s);
137
137
  h((i) => {
138
138
  const a = ds(t, i);
@@ -170,14 +170,14 @@ function Is({
170
170
  /* @__PURE__ */ e.jsx(ys, { className: "h-3.5 w-3.5" }),
171
171
  W
172
172
  ] }) : /* @__PURE__ */ e.jsx("span", { className: "text-xs text-muted-foreground", children: "待上传" }), H = /* @__PURE__ */ e.jsxs(e.Fragment, { children: [
173
- o && I && /* @__PURE__ */ e.jsx(I, { children: o }),
174
- o && !I && /* @__PURE__ */ e.jsx("div", { className: "text-lg font-semibold leading-none tracking-tight", children: o }),
173
+ c && I && /* @__PURE__ */ e.jsx(I, { children: c }),
174
+ c && !I && /* @__PURE__ */ e.jsx("div", { className: "text-lg font-semibold leading-none tracking-tight", children: c }),
175
175
  u && B && /* @__PURE__ */ e.jsx(B, { children: u }),
176
176
  u && !B && /* @__PURE__ */ e.jsx("div", { className: "text-sm text-muted-foreground", children: u })
177
177
  ] });
178
- return /* @__PURE__ */ e.jsxs(cs, { className: R("overflow-hidden", ts), children: [
179
- O && (o || u) ? /* @__PURE__ */ e.jsx(O, { children: H }) : (o || u) && /* @__PURE__ */ e.jsx("div", { className: "space-y-1.5 p-6", children: H }),
180
- /* @__PURE__ */ e.jsxs(os, { className: "space-y-4", children: [
178
+ return /* @__PURE__ */ e.jsxs(os, { className: R("overflow-hidden", ts), children: [
179
+ O && (c || u) ? /* @__PURE__ */ e.jsx(O, { children: H }) : (c || u) && /* @__PURE__ */ e.jsx("div", { className: "space-y-1.5 p-6", children: H }),
180
+ /* @__PURE__ */ e.jsxs(cs, { className: "space-y-4", children: [
181
181
  /* @__PURE__ */ e.jsx(
182
182
  "input",
183
183
  {
@@ -187,31 +187,31 @@ function Is({
187
187
  multiple: N,
188
188
  className: "sr-only",
189
189
  onChange: (s) => G(s.target.files),
190
- disabled: c
190
+ disabled: o
191
191
  }
192
192
  ),
193
193
  /* @__PURE__ */ e.jsxs(
194
194
  "div",
195
195
  {
196
196
  role: "button",
197
- tabIndex: c ? -1 : 0,
198
- "aria-disabled": c,
197
+ tabIndex: o ? -1 : 0,
198
+ "aria-disabled": o,
199
199
  className: R(
200
- "flex min-h-40 cursor-pointer flex-col items-center justify-center rounded-lg border border-dashed border-muted-foreground/30 bg-muted/20 px-6 py-8 text-center transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
201
- is && "border-primary bg-primary/5",
202
- c && "cursor-not-allowed opacity-60",
200
+ "flex min-h-40 cursor-pointer touch-manipulation flex-col items-center justify-center rounded-lg border border-dashed border-muted-foreground/30 bg-muted/20 px-6 py-8 text-center transition-colors duration-150 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background",
201
+ is && "border-primary bg-primary/10 shadow-inner",
202
+ o && "cursor-not-allowed opacity-60",
203
203
  ns
204
204
  ),
205
205
  onClick: () => {
206
206
  var s;
207
- c || (s = p.current) == null || s.click();
207
+ o || (s = p.current) == null || s.click();
208
208
  },
209
209
  onKeyDown: (s) => {
210
210
  var t;
211
- !c && (s.key === "Enter" || s.key === " ") && (s.preventDefault(), (t = p.current) == null || t.click());
211
+ !o && (s.key === "Enter" || s.key === " ") && (s.preventDefault(), (t = p.current) == null || t.click());
212
212
  },
213
213
  onDragOver: (s) => {
214
- s.preventDefault(), c || M(!0);
214
+ s.preventDefault(), o || M(!0);
215
215
  },
216
216
  onDragLeave: () => M(!1),
217
217
  onDrop: ls,
@@ -226,7 +226,7 @@ function Is({
226
226
  size: "sm",
227
227
  variant: "secondary",
228
228
  className: "mt-4",
229
- disabled: c,
229
+ disabled: o,
230
230
  onClick: (s) => {
231
231
  var t;
232
232
  s.stopPropagation(), (t = p.current) == null || t.click();
@@ -238,11 +238,11 @@ function Is({
238
238
  }
239
239
  ),
240
240
  j && /* @__PURE__ */ e.jsx("div", { className: "text-sm text-muted-foreground", children: j }),
241
- /* @__PURE__ */ e.jsx("div", { className: R("space-y-3", as), children: l.length === 0 ? /* @__PURE__ */ e.jsx("div", { className: "rounded-md border border-dashed px-4 py-3 text-sm text-muted-foreground", children: U }) : l.map((s) => /* @__PURE__ */ e.jsx(
241
+ /* @__PURE__ */ e.jsx("div", { className: R("space-y-3", as), children: l.length === 0 ? /* @__PURE__ */ e.jsx("div", { className: "rounded-md border border-dashed bg-muted/20 px-4 py-3 text-sm text-muted-foreground", children: U }) : l.map((s) => /* @__PURE__ */ e.jsx(
242
242
  "div",
243
243
  {
244
- className: "rounded-lg border bg-background px-4 py-3",
245
- children: /* @__PURE__ */ e.jsxs("div", { className: "flex items-start gap-3", children: [
244
+ className: "rounded-lg border bg-background px-4 py-3 shadow-sm",
245
+ children: /* @__PURE__ */ e.jsxs("div", { className: "flex min-w-0 items-start gap-3", children: [
246
246
  /* @__PURE__ */ e.jsx("div", { className: "mt-0.5 rounded-md bg-muted p-2 text-muted-foreground", children: /* @__PURE__ */ e.jsx(hs, { className: "h-4 w-4" }) }),
247
247
  /* @__PURE__ */ e.jsxs("div", { className: "min-w-0 flex-1 space-y-2", children: [
248
248
  /* @__PURE__ */ e.jsxs("div", { className: "flex flex-wrap items-start justify-between gap-2", children: [
@@ -273,7 +273,7 @@ function Is({
273
273
  )
274
274
  }
275
275
  ),
276
- s.error && /* @__PURE__ */ e.jsx("div", { className: "text-xs text-destructive", children: s.error })
276
+ s.error && /* @__PURE__ */ e.jsx("div", { className: "break-words text-xs text-destructive", children: s.error })
277
277
  ] }),
278
278
  /* @__PURE__ */ e.jsxs("div", { className: "flex shrink-0 items-center gap-1", children: [
279
279
  s.status === "error" && m && /* @__PURE__ */ e.jsx(
@@ -282,7 +282,7 @@ function Is({
282
282
  type: "button",
283
283
  variant: "ghost",
284
284
  size: "sm",
285
- disabled: c || g,
285
+ disabled: o || g,
286
286
  onClick: () => xs(s),
287
287
  children: _
288
288
  }
@@ -294,7 +294,7 @@ function Is({
294
294
  variant: "ghost",
295
295
  size: "icon",
296
296
  "aria-label": `移除 ${s.name}`,
297
- disabled: c || s.status === "uploading",
297
+ disabled: o || s.status === "uploading",
298
298
  onClick: () => us(s.id),
299
299
  children: /* @__PURE__ */ e.jsx(ps, { className: "h-4 w-4" })
300
300
  }
@@ -311,7 +311,7 @@ function Is({
311
311
  {
312
312
  type: "button",
313
313
  variant: "outline",
314
- disabled: c || g || l.length === 0,
314
+ disabled: o || g || l.length === 0,
315
315
  onClick: () => D([]),
316
316
  children: T
317
317
  }
@@ -320,7 +320,7 @@ function Is({
320
320
  f,
321
321
  {
322
322
  type: "button",
323
- disabled: c || g || !L || !m,
323
+ disabled: o || g || !L || !m,
324
324
  onClick: z,
325
325
  children: S
326
326
  }
@@ -331,7 +331,7 @@ function Is({
331
331
  {
332
332
  type: "button",
333
333
  variant: "outline",
334
- disabled: c || g || l.length === 0,
334
+ disabled: o || g || l.length === 0,
335
335
  onClick: () => D([]),
336
336
  children: T
337
337
  }
@@ -340,7 +340,7 @@ function Is({
340
340
  f,
341
341
  {
342
342
  type: "button",
343
- disabled: c || g || !L || !m,
343
+ disabled: o || g || !L || !m,
344
344
  onClick: z,
345
345
  children: S
346
346
  }
@@ -1 +1 @@
1
- {"version":3,"file":"file-upload.js","sources":["../src/components/FileUpload.tsx"],"sourcesContent":["import {\n CheckCircle2,\n FileText,\n Loader2,\n UploadCloud,\n X,\n XCircle,\n} from 'lucide-react';\nimport { useEffect, useRef, useState } from 'react';\nimport type { DragEvent, HTMLAttributes, ReactNode } from 'react';\n\nimport { cn } from '../lib/utils';\nimport type {\n ButtonComponent,\n CardComponent,\n UIComponent,\n} from '../types/component-types';\n\nexport type FileUploadStatus = 'ready' | 'uploading' | 'success' | 'error';\n\nexport interface FileUploadItem<TResult = unknown> {\n id: string;\n file: File;\n name: string;\n size: number;\n type: string;\n status: FileUploadStatus;\n progress: number;\n error?: string;\n result?: TResult;\n}\n\nexport interface FileUploadHelpers {\n setProgress: (progress: number) => void;\n}\n\nexport interface FileUploadUIComponents {\n Card: CardComponent;\n CardHeader?: UIComponent<HTMLAttributes<HTMLDivElement>>;\n CardTitle?: UIComponent<HTMLAttributes<HTMLDivElement>>;\n CardDescription?: UIComponent<HTMLAttributes<HTMLDivElement>>;\n CardContent: UIComponent<HTMLAttributes<HTMLDivElement>>;\n CardFooter?: UIComponent<HTMLAttributes<HTMLDivElement>>;\n Button: ButtonComponent;\n}\n\nexport interface FileUploadProps<TResult = unknown> {\n components?: FileUploadUIComponents;\n title?: ReactNode;\n description?: ReactNode;\n helperText?: ReactNode;\n accept?: string;\n multiple?: boolean;\n maxFiles?: number;\n maxSize?: number;\n disabled?: boolean;\n autoUpload?: boolean;\n showUploadButton?: boolean;\n showResetButton?: boolean;\n selectLabel?: string;\n uploadLabel?: string;\n retryLabel?: string;\n resetLabel?: string;\n emptyLabel?: ReactNode;\n dropzoneLabel?: ReactNode;\n dropzoneDescription?: ReactNode;\n uploadingText?: string;\n successText?: string;\n errorText?: string;\n className?: string;\n dropzoneClassName?: string;\n listClassName?: string;\n formatFileSize?: (size: number) => string;\n validateFile?: (\n file: File,\n currentItems: FileUploadItem<TResult>[]\n ) => string | undefined;\n onFilesChange?: (items: FileUploadItem<TResult>[]) => void;\n onUpload?: (\n item: FileUploadItem<TResult>,\n helpers: FileUploadHelpers\n ) => Promise<TResult> | TResult;\n onUploadComplete?: (item: FileUploadItem<TResult>) => void;\n onUploadError?: (item: FileUploadItem<TResult>, error: unknown) => void;\n}\n\nconst defaultFormatFileSize = (size: number) => {\n if (size < 1024) return `${size} B`;\n if (size < 1024 * 1024) return `${(size / 1024).toFixed(1)} KB`;\n if (size < 1024 * 1024 * 1024) {\n return `${(size / 1024 / 1024).toFixed(1)} MB`;\n }\n return `${(size / 1024 / 1024 / 1024).toFixed(1)} GB`;\n};\n\nconst createFileId = (file: File) =>\n `${file.name}-${file.size}-${file.lastModified}-${Math.random()\n .toString(36)\n .slice(2)}`;\n\nconst getFileExtension = (fileName: string) => {\n const index = fileName.lastIndexOf('.');\n return index > -1 ? fileName.slice(index).toLowerCase() : '';\n};\n\nconst matchesAccept = (file: File, accept?: string) => {\n if (!accept) return true;\n\n const fileType = file.type.toLowerCase();\n const fileExtension = getFileExtension(file.name);\n\n return accept\n .split(',')\n .map((item) => item.trim().toLowerCase())\n .filter(Boolean)\n .some((rule) => {\n if (rule.startsWith('.')) {\n return fileExtension === rule;\n }\n if (rule.endsWith('/*')) {\n return fileType.startsWith(rule.slice(0, -1));\n }\n return fileType === rule;\n });\n};\n\nconst getErrorMessage = (error: unknown, fallback: string) => {\n if (error instanceof Error && error.message) {\n return error.message;\n }\n if (typeof error === 'string' && error) {\n return error;\n }\n return fallback;\n};\n\nexport function FileUpload<TResult = unknown>({\n components,\n title = '文件上传',\n description = '选择文件后开始上传,支持 Tale SDK 的直接上传和预签名上传流程。',\n helperText,\n accept,\n multiple = false,\n maxFiles,\n maxSize,\n disabled = false,\n autoUpload = false,\n showUploadButton,\n showResetButton = true,\n selectLabel = '选择文件',\n uploadLabel = '开始上传',\n retryLabel = '重试',\n resetLabel = '清空',\n emptyLabel = '尚未选择文件',\n dropzoneLabel = '拖拽文件到这里,或点击选择',\n dropzoneDescription = '上传前会先完成文件校验,上传逻辑由业务侧注入。',\n uploadingText = '上传中',\n successText = '上传完成',\n errorText = '上传失败',\n className,\n dropzoneClassName,\n listClassName,\n formatFileSize = defaultFormatFileSize,\n validateFile,\n onFilesChange,\n onUpload,\n onUploadComplete,\n onUploadError,\n}: FileUploadProps<TResult>) {\n const [items, setItems] = useState<FileUploadItem<TResult>[]>([]);\n const [isDragging, setIsDragging] = useState(false);\n const inputRef = useRef<HTMLInputElement>(null);\n const shouldShowUploadButton = showUploadButton ?? Boolean(onUpload);\n const resolvedMaxFiles = multiple ? maxFiles : 1;\n const hasUploadableItems = items.some((item) => item.status === 'ready');\n const isUploading = items.some((item) => item.status === 'uploading');\n\n useEffect(() => {\n onFilesChange?.(items);\n }, [items, onFilesChange]);\n\n if (!components) {\n return (\n <div className=\"p-4 text-center text-destructive\">\n 错误:请通过 components prop 注入 UI 组件\n </div>\n );\n }\n\n const {\n Card,\n CardHeader,\n CardTitle,\n CardDescription,\n CardContent,\n CardFooter,\n Button,\n } = components;\n\n const updateItems = (\n updater: (\n currentItems: FileUploadItem<TResult>[]\n ) => FileUploadItem<TResult>[]\n ) => {\n setItems((currentItems) => updater(currentItems));\n };\n\n const getValidationError = (\n file: File,\n currentItems: FileUploadItem<TResult>[]\n ) => {\n if (maxSize && file.size > maxSize) {\n return `文件不能超过 ${formatFileSize(maxSize)}`;\n }\n if (!matchesAccept(file, accept)) {\n return '文件类型不符合要求';\n }\n return validateFile?.(file, currentItems);\n };\n\n const createItemsFromFiles = (\n files: File[],\n currentItems: FileUploadItem<TResult>[]\n ) => {\n const nextItems = multiple ? [...currentItems] : [];\n const remainingSlots =\n resolvedMaxFiles === undefined\n ? files.length\n : Math.max(resolvedMaxFiles - nextItems.length, 0);\n\n files.slice(0, remainingSlots).forEach((file) => {\n const error = getValidationError(file, nextItems);\n nextItems.push({\n id: createFileId(file),\n file,\n name: file.name,\n size: file.size,\n type: file.type,\n status: error ? 'error' : 'ready',\n progress: 0,\n error,\n });\n });\n\n if (resolvedMaxFiles !== undefined && files.length > remainingSlots) {\n files.slice(remainingSlots).forEach((file) => {\n nextItems.push({\n id: createFileId(file),\n file,\n name: file.name,\n size: file.size,\n type: file.type,\n status: 'error',\n progress: 0,\n error: `最多只能选择 ${resolvedMaxFiles} 个文件`,\n });\n });\n }\n\n return nextItems;\n };\n\n const uploadItem = async (targetItem: FileUploadItem<TResult>) => {\n if (!onUpload || targetItem.status === 'uploading') return;\n\n updateItems((currentItems) =>\n currentItems.map((item) =>\n item.id === targetItem.id\n ? { ...item, status: 'uploading', progress: item.progress || 5 }\n : item\n )\n );\n\n const setProgress = (progress: number) => {\n updateItems((currentItems) =>\n currentItems.map((item) =>\n item.id === targetItem.id\n ? {\n ...item,\n progress: Math.max(0, Math.min(100, Math.round(progress))),\n }\n : item\n )\n );\n };\n\n try {\n const result = await onUpload(targetItem, { setProgress });\n const completedItem = {\n ...targetItem,\n status: 'success' as const,\n progress: 100,\n error: undefined,\n result,\n };\n updateItems((currentItems) =>\n currentItems.map((item) =>\n item.id === targetItem.id ? completedItem : item\n )\n );\n onUploadComplete?.(completedItem);\n } catch (error) {\n const failedItem = {\n ...targetItem,\n status: 'error' as const,\n progress: 0,\n error: getErrorMessage(error, errorText),\n };\n updateItems((currentItems) =>\n currentItems.map((item) =>\n item.id === targetItem.id ? failedItem : item\n )\n );\n onUploadError?.(failedItem, error);\n }\n };\n\n const uploadReadyItems = async () => {\n const readyItems = items.filter((item) => item.status === 'ready');\n for (const item of readyItems) {\n await uploadItem(item);\n }\n };\n\n const handleFiles = (fileList: FileList | null) => {\n if (!fileList || disabled) return;\n const files = Array.from(fileList);\n updateItems((currentItems) => {\n const nextItems = createItemsFromFiles(files, currentItems);\n if (autoUpload && onUpload) {\n nextItems\n .filter((item) => item.status === 'ready')\n .forEach((item) => {\n window.setTimeout(() => uploadItem(item), 0);\n });\n }\n return nextItems;\n });\n if (inputRef.current) {\n inputRef.current.value = '';\n }\n };\n\n const handleDrop = (event: DragEvent<HTMLDivElement>) => {\n event.preventDefault();\n setIsDragging(false);\n handleFiles(event.dataTransfer.files);\n };\n\n const handleRemove = (id: string) => {\n updateItems((currentItems) =>\n currentItems.filter((item) => item.id !== id)\n );\n };\n\n const handleRetry = (item: FileUploadItem<TResult>) => {\n const error = getValidationError(\n item.file,\n items.filter((currentItem) => currentItem.id !== item.id)\n );\n if (error) {\n updateItems((currentItems) =>\n currentItems.map((currentItem) =>\n currentItem.id === item.id ? { ...currentItem, error } : currentItem\n )\n );\n return;\n }\n uploadItem({ ...item, status: 'ready', error: undefined, progress: 0 });\n };\n\n const renderStatus = (item: FileUploadItem<TResult>) => {\n if (item.status === 'uploading') {\n return (\n <span className=\"inline-flex items-center gap-1 text-xs font-medium text-blue-600 dark:text-blue-300\">\n <Loader2 className=\"h-3.5 w-3.5 animate-spin\" />\n {uploadingText}\n </span>\n );\n }\n if (item.status === 'success') {\n return (\n <span className=\"inline-flex items-center gap-1 text-xs font-medium text-emerald-600 dark:text-emerald-300\">\n <CheckCircle2 className=\"h-3.5 w-3.5\" />\n {successText}\n </span>\n );\n }\n if (item.status === 'error') {\n return (\n <span className=\"inline-flex items-center gap-1 text-xs font-medium text-destructive\">\n <XCircle className=\"h-3.5 w-3.5\" />\n {errorText}\n </span>\n );\n }\n return <span className=\"text-xs text-muted-foreground\">待上传</span>;\n };\n\n const header = (\n <>\n {title && CardTitle && <CardTitle>{title}</CardTitle>}\n {title && !CardTitle && (\n <div className=\"text-lg font-semibold leading-none tracking-tight\">\n {title}\n </div>\n )}\n {description && CardDescription && (\n <CardDescription>{description}</CardDescription>\n )}\n {description && !CardDescription && (\n <div className=\"text-sm text-muted-foreground\">{description}</div>\n )}\n </>\n );\n\n return (\n <Card className={cn('overflow-hidden', className)}>\n {CardHeader && (title || description) ? (\n <CardHeader>{header}</CardHeader>\n ) : (\n (title || description) && (\n <div className=\"space-y-1.5 p-6\">{header}</div>\n )\n )}\n <CardContent className=\"space-y-4\">\n <input\n ref={inputRef}\n type=\"file\"\n accept={accept}\n multiple={multiple}\n className=\"sr-only\"\n onChange={(event) => handleFiles(event.target.files)}\n disabled={disabled}\n />\n <div\n role=\"button\"\n tabIndex={disabled ? -1 : 0}\n aria-disabled={disabled}\n className={cn(\n 'flex min-h-40 cursor-pointer flex-col items-center justify-center rounded-lg border border-dashed border-muted-foreground/30 bg-muted/20 px-6 py-8 text-center transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring',\n isDragging && 'border-primary bg-primary/5',\n disabled && 'cursor-not-allowed opacity-60',\n dropzoneClassName\n )}\n onClick={() => {\n if (!disabled) {\n inputRef.current?.click();\n }\n }}\n onKeyDown={(event) => {\n if (!disabled && (event.key === 'Enter' || event.key === ' ')) {\n event.preventDefault();\n inputRef.current?.click();\n }\n }}\n onDragOver={(event) => {\n event.preventDefault();\n if (!disabled) {\n setIsDragging(true);\n }\n }}\n onDragLeave={() => setIsDragging(false)}\n onDrop={handleDrop}\n >\n <div className=\"mb-3 rounded-full bg-primary/10 p-3 text-primary\">\n <UploadCloud className=\"h-6 w-6\" />\n </div>\n <div className=\"text-sm font-medium\">{dropzoneLabel}</div>\n {dropzoneDescription && (\n <div className=\"mt-1 max-w-md text-sm text-muted-foreground\">\n {dropzoneDescription}\n </div>\n )}\n <Button\n type=\"button\"\n size=\"sm\"\n variant=\"secondary\"\n className=\"mt-4\"\n disabled={disabled}\n onClick={(event) => {\n event.stopPropagation();\n inputRef.current?.click();\n }}\n >\n {selectLabel}\n </Button>\n </div>\n\n {helperText && (\n <div className=\"text-sm text-muted-foreground\">{helperText}</div>\n )}\n\n <div className={cn('space-y-3', listClassName)}>\n {items.length === 0 ? (\n <div className=\"rounded-md border border-dashed px-4 py-3 text-sm text-muted-foreground\">\n {emptyLabel}\n </div>\n ) : (\n items.map((item) => (\n <div\n key={item.id}\n className=\"rounded-lg border bg-background px-4 py-3\"\n >\n <div className=\"flex items-start gap-3\">\n <div className=\"mt-0.5 rounded-md bg-muted p-2 text-muted-foreground\">\n <FileText className=\"h-4 w-4\" />\n </div>\n <div className=\"min-w-0 flex-1 space-y-2\">\n <div className=\"flex flex-wrap items-start justify-between gap-2\">\n <div className=\"min-w-0\">\n <div className=\"truncate text-sm font-medium\">\n {item.name}\n </div>\n <div className=\"text-xs text-muted-foreground\">\n {formatFileSize(item.size)}\n {item.type ? ` · ${item.type}` : ''}\n </div>\n </div>\n {renderStatus(item)}\n </div>\n {item.status === 'uploading' && (\n <div\n className=\"h-2 overflow-hidden rounded-full bg-muted\"\n aria-label={`${item.name} 上传进度`}\n role=\"progressbar\"\n aria-valuenow={item.progress}\n aria-valuemin={0}\n aria-valuemax={100}\n >\n <div\n className=\"h-full rounded-full bg-primary transition-all\"\n style={{ width: `${item.progress}%` }}\n />\n </div>\n )}\n {item.error && (\n <div className=\"text-xs text-destructive\">\n {item.error}\n </div>\n )}\n </div>\n <div className=\"flex shrink-0 items-center gap-1\">\n {item.status === 'error' && onUpload && (\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n disabled={disabled || isUploading}\n onClick={() => handleRetry(item)}\n >\n {retryLabel}\n </Button>\n )}\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon\"\n aria-label={`移除 ${item.name}`}\n disabled={disabled || item.status === 'uploading'}\n onClick={() => handleRemove(item.id)}\n >\n <X className=\"h-4 w-4\" />\n </Button>\n </div>\n </div>\n </div>\n ))\n )}\n </div>\n </CardContent>\n {(shouldShowUploadButton || showResetButton) &&\n (CardFooter ? (\n <CardFooter className=\"justify-end gap-2\">\n {showResetButton && (\n <Button\n type=\"button\"\n variant=\"outline\"\n disabled={disabled || isUploading || items.length === 0}\n onClick={() => setItems([])}\n >\n {resetLabel}\n </Button>\n )}\n {shouldShowUploadButton && (\n <Button\n type=\"button\"\n disabled={\n disabled || isUploading || !hasUploadableItems || !onUpload\n }\n onClick={uploadReadyItems}\n >\n {uploadLabel}\n </Button>\n )}\n </CardFooter>\n ) : (\n <div className=\"flex justify-end gap-2 p-6 pt-0\">\n {showResetButton && (\n <Button\n type=\"button\"\n variant=\"outline\"\n disabled={disabled || isUploading || items.length === 0}\n onClick={() => setItems([])}\n >\n {resetLabel}\n </Button>\n )}\n {shouldShowUploadButton && (\n <Button\n type=\"button\"\n disabled={\n disabled || isUploading || !hasUploadableItems || !onUpload\n }\n onClick={uploadReadyItems}\n >\n {uploadLabel}\n </Button>\n )}\n </div>\n ))}\n </Card>\n );\n}\n"],"names":["defaultFormatFileSize","size","createFileId","file","getFileExtension","fileName","index","matchesAccept","accept","fileType","fileExtension","item","rule","getErrorMessage","error","fallback","FileUpload","components","title","description","helperText","multiple","maxFiles","maxSize","disabled","autoUpload","showUploadButton","showResetButton","selectLabel","uploadLabel","retryLabel","resetLabel","emptyLabel","dropzoneLabel","dropzoneDescription","uploadingText","successText","errorText","className","dropzoneClassName","listClassName","formatFileSize","validateFile","onFilesChange","onUpload","onUploadComplete","onUploadError","items","setItems","useState","isDragging","setIsDragging","inputRef","useRef","shouldShowUploadButton","resolvedMaxFiles","hasUploadableItems","isUploading","useEffect","jsx","Card","CardHeader","CardTitle","CardDescription","CardContent","CardFooter","Button","updateItems","updater","currentItems","getValidationError","createItemsFromFiles","files","nextItems","remainingSlots","uploadItem","targetItem","setProgress","progress","result","completedItem","failedItem","uploadReadyItems","readyItems","handleFiles","fileList","handleDrop","event","handleRemove","id","handleRetry","currentItem","renderStatus","jsxs","Loader2","CheckCircle2","XCircle","header","Fragment","cn","_a","UploadCloud","FileText","X"],"mappings":"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"}
1
+ {"version":3,"file":"file-upload.js","sources":["../src/components/FileUpload.tsx"],"sourcesContent":["import {\n CheckCircle2,\n FileText,\n Loader2,\n UploadCloud,\n X,\n XCircle,\n} from 'lucide-react';\nimport { useEffect, useRef, useState } from 'react';\nimport type { DragEvent, HTMLAttributes, ReactNode } from 'react';\n\nimport { cn } from '../lib/utils';\nimport type {\n ButtonComponent,\n CardComponent,\n UIComponent,\n} from '../types/component-types';\n\nexport type FileUploadStatus = 'ready' | 'uploading' | 'success' | 'error';\n\nexport interface FileUploadItem<TResult = unknown> {\n id: string;\n file: File;\n name: string;\n size: number;\n type: string;\n status: FileUploadStatus;\n progress: number;\n error?: string;\n result?: TResult;\n}\n\nexport interface FileUploadHelpers {\n setProgress: (progress: number) => void;\n}\n\nexport interface FileUploadUIComponents {\n Card: CardComponent;\n CardHeader?: UIComponent<HTMLAttributes<HTMLDivElement>>;\n CardTitle?: UIComponent<HTMLAttributes<HTMLDivElement>>;\n CardDescription?: UIComponent<HTMLAttributes<HTMLDivElement>>;\n CardContent: UIComponent<HTMLAttributes<HTMLDivElement>>;\n CardFooter?: UIComponent<HTMLAttributes<HTMLDivElement>>;\n Button: ButtonComponent;\n}\n\nexport interface FileUploadProps<TResult = unknown> {\n components?: FileUploadUIComponents;\n title?: ReactNode;\n description?: ReactNode;\n helperText?: ReactNode;\n accept?: string;\n multiple?: boolean;\n maxFiles?: number;\n maxSize?: number;\n disabled?: boolean;\n autoUpload?: boolean;\n showUploadButton?: boolean;\n showResetButton?: boolean;\n selectLabel?: string;\n uploadLabel?: string;\n retryLabel?: string;\n resetLabel?: string;\n emptyLabel?: ReactNode;\n dropzoneLabel?: ReactNode;\n dropzoneDescription?: ReactNode;\n uploadingText?: string;\n successText?: string;\n errorText?: string;\n className?: string;\n dropzoneClassName?: string;\n listClassName?: string;\n formatFileSize?: (size: number) => string;\n validateFile?: (\n file: File,\n currentItems: FileUploadItem<TResult>[]\n ) => string | undefined;\n onFilesChange?: (items: FileUploadItem<TResult>[]) => void;\n onUpload?: (\n item: FileUploadItem<TResult>,\n helpers: FileUploadHelpers\n ) => Promise<TResult> | TResult;\n onUploadComplete?: (item: FileUploadItem<TResult>) => void;\n onUploadError?: (item: FileUploadItem<TResult>, error: unknown) => void;\n}\n\nconst defaultFormatFileSize = (size: number) => {\n if (size < 1024) return `${size} B`;\n if (size < 1024 * 1024) return `${(size / 1024).toFixed(1)} KB`;\n if (size < 1024 * 1024 * 1024) {\n return `${(size / 1024 / 1024).toFixed(1)} MB`;\n }\n return `${(size / 1024 / 1024 / 1024).toFixed(1)} GB`;\n};\n\nconst createFileId = (file: File) =>\n `${file.name}-${file.size}-${file.lastModified}-${Math.random()\n .toString(36)\n .slice(2)}`;\n\nconst getFileExtension = (fileName: string) => {\n const index = fileName.lastIndexOf('.');\n return index > -1 ? fileName.slice(index).toLowerCase() : '';\n};\n\nconst matchesAccept = (file: File, accept?: string) => {\n if (!accept) return true;\n\n const fileType = file.type.toLowerCase();\n const fileExtension = getFileExtension(file.name);\n\n return accept\n .split(',')\n .map((item) => item.trim().toLowerCase())\n .filter(Boolean)\n .some((rule) => {\n if (rule.startsWith('.')) {\n return fileExtension === rule;\n }\n if (rule.endsWith('/*')) {\n return fileType.startsWith(rule.slice(0, -1));\n }\n return fileType === rule;\n });\n};\n\nconst getErrorMessage = (error: unknown, fallback: string) => {\n if (error instanceof Error && error.message) {\n return error.message;\n }\n if (typeof error === 'string' && error) {\n return error;\n }\n return fallback;\n};\n\nexport function FileUpload<TResult = unknown>({\n components,\n title = '文件上传',\n description = '选择文件后开始上传,支持 Tale SDK 的直接上传和预签名上传流程。',\n helperText,\n accept,\n multiple = false,\n maxFiles,\n maxSize,\n disabled = false,\n autoUpload = false,\n showUploadButton,\n showResetButton = true,\n selectLabel = '选择文件',\n uploadLabel = '开始上传',\n retryLabel = '重试',\n resetLabel = '清空',\n emptyLabel = '尚未选择文件',\n dropzoneLabel = '拖拽文件到这里,或点击选择',\n dropzoneDescription = '上传前会先完成文件校验,上传逻辑由业务侧注入。',\n uploadingText = '上传中',\n successText = '上传完成',\n errorText = '上传失败',\n className,\n dropzoneClassName,\n listClassName,\n formatFileSize = defaultFormatFileSize,\n validateFile,\n onFilesChange,\n onUpload,\n onUploadComplete,\n onUploadError,\n}: FileUploadProps<TResult>) {\n const [items, setItems] = useState<FileUploadItem<TResult>[]>([]);\n const [isDragging, setIsDragging] = useState(false);\n const inputRef = useRef<HTMLInputElement>(null);\n const shouldShowUploadButton = showUploadButton ?? Boolean(onUpload);\n const resolvedMaxFiles = multiple ? maxFiles : 1;\n const hasUploadableItems = items.some((item) => item.status === 'ready');\n const isUploading = items.some((item) => item.status === 'uploading');\n\n useEffect(() => {\n onFilesChange?.(items);\n }, [items, onFilesChange]);\n\n if (!components) {\n return (\n <div className=\"p-4 text-center text-destructive\">\n 错误:请通过 components prop 注入 UI 组件\n </div>\n );\n }\n\n const {\n Card,\n CardHeader,\n CardTitle,\n CardDescription,\n CardContent,\n CardFooter,\n Button,\n } = components;\n\n const updateItems = (\n updater: (\n currentItems: FileUploadItem<TResult>[]\n ) => FileUploadItem<TResult>[]\n ) => {\n setItems((currentItems) => updater(currentItems));\n };\n\n const getValidationError = (\n file: File,\n currentItems: FileUploadItem<TResult>[]\n ) => {\n if (maxSize && file.size > maxSize) {\n return `文件不能超过 ${formatFileSize(maxSize)}`;\n }\n if (!matchesAccept(file, accept)) {\n return '文件类型不符合要求';\n }\n return validateFile?.(file, currentItems);\n };\n\n const createItemsFromFiles = (\n files: File[],\n currentItems: FileUploadItem<TResult>[]\n ) => {\n const nextItems = multiple ? [...currentItems] : [];\n const remainingSlots =\n resolvedMaxFiles === undefined\n ? files.length\n : Math.max(resolvedMaxFiles - nextItems.length, 0);\n\n files.slice(0, remainingSlots).forEach((file) => {\n const error = getValidationError(file, nextItems);\n nextItems.push({\n id: createFileId(file),\n file,\n name: file.name,\n size: file.size,\n type: file.type,\n status: error ? 'error' : 'ready',\n progress: 0,\n error,\n });\n });\n\n if (resolvedMaxFiles !== undefined && files.length > remainingSlots) {\n files.slice(remainingSlots).forEach((file) => {\n nextItems.push({\n id: createFileId(file),\n file,\n name: file.name,\n size: file.size,\n type: file.type,\n status: 'error',\n progress: 0,\n error: `最多只能选择 ${resolvedMaxFiles} 个文件`,\n });\n });\n }\n\n return nextItems;\n };\n\n const uploadItem = async (targetItem: FileUploadItem<TResult>) => {\n if (!onUpload || targetItem.status === 'uploading') return;\n\n updateItems((currentItems) =>\n currentItems.map((item) =>\n item.id === targetItem.id\n ? { ...item, status: 'uploading', progress: item.progress || 5 }\n : item\n )\n );\n\n const setProgress = (progress: number) => {\n updateItems((currentItems) =>\n currentItems.map((item) =>\n item.id === targetItem.id\n ? {\n ...item,\n progress: Math.max(0, Math.min(100, Math.round(progress))),\n }\n : item\n )\n );\n };\n\n try {\n const result = await onUpload(targetItem, { setProgress });\n const completedItem = {\n ...targetItem,\n status: 'success' as const,\n progress: 100,\n error: undefined,\n result,\n };\n updateItems((currentItems) =>\n currentItems.map((item) =>\n item.id === targetItem.id ? completedItem : item\n )\n );\n onUploadComplete?.(completedItem);\n } catch (error) {\n const failedItem = {\n ...targetItem,\n status: 'error' as const,\n progress: 0,\n error: getErrorMessage(error, errorText),\n };\n updateItems((currentItems) =>\n currentItems.map((item) =>\n item.id === targetItem.id ? failedItem : item\n )\n );\n onUploadError?.(failedItem, error);\n }\n };\n\n const uploadReadyItems = async () => {\n const readyItems = items.filter((item) => item.status === 'ready');\n for (const item of readyItems) {\n await uploadItem(item);\n }\n };\n\n const handleFiles = (fileList: FileList | null) => {\n if (!fileList || disabled) return;\n const files = Array.from(fileList);\n updateItems((currentItems) => {\n const nextItems = createItemsFromFiles(files, currentItems);\n if (autoUpload && onUpload) {\n nextItems\n .filter((item) => item.status === 'ready')\n .forEach((item) => {\n window.setTimeout(() => uploadItem(item), 0);\n });\n }\n return nextItems;\n });\n if (inputRef.current) {\n inputRef.current.value = '';\n }\n };\n\n const handleDrop = (event: DragEvent<HTMLDivElement>) => {\n event.preventDefault();\n setIsDragging(false);\n handleFiles(event.dataTransfer.files);\n };\n\n const handleRemove = (id: string) => {\n updateItems((currentItems) =>\n currentItems.filter((item) => item.id !== id)\n );\n };\n\n const handleRetry = (item: FileUploadItem<TResult>) => {\n const error = getValidationError(\n item.file,\n items.filter((currentItem) => currentItem.id !== item.id)\n );\n if (error) {\n updateItems((currentItems) =>\n currentItems.map((currentItem) =>\n currentItem.id === item.id ? { ...currentItem, error } : currentItem\n )\n );\n return;\n }\n uploadItem({ ...item, status: 'ready', error: undefined, progress: 0 });\n };\n\n const renderStatus = (item: FileUploadItem<TResult>) => {\n if (item.status === 'uploading') {\n return (\n <span className=\"inline-flex items-center gap-1 text-xs font-medium text-blue-600 dark:text-blue-300\">\n <Loader2 className=\"h-3.5 w-3.5 animate-spin\" />\n {uploadingText}\n </span>\n );\n }\n if (item.status === 'success') {\n return (\n <span className=\"inline-flex items-center gap-1 text-xs font-medium text-emerald-600 dark:text-emerald-300\">\n <CheckCircle2 className=\"h-3.5 w-3.5\" />\n {successText}\n </span>\n );\n }\n if (item.status === 'error') {\n return (\n <span className=\"inline-flex items-center gap-1 text-xs font-medium text-destructive\">\n <XCircle className=\"h-3.5 w-3.5\" />\n {errorText}\n </span>\n );\n }\n return <span className=\"text-xs text-muted-foreground\">待上传</span>;\n };\n\n const header = (\n <>\n {title && CardTitle && <CardTitle>{title}</CardTitle>}\n {title && !CardTitle && (\n <div className=\"text-lg font-semibold leading-none tracking-tight\">\n {title}\n </div>\n )}\n {description && CardDescription && (\n <CardDescription>{description}</CardDescription>\n )}\n {description && !CardDescription && (\n <div className=\"text-sm text-muted-foreground\">{description}</div>\n )}\n </>\n );\n\n return (\n <Card className={cn('overflow-hidden', className)}>\n {CardHeader && (title || description) ? (\n <CardHeader>{header}</CardHeader>\n ) : (\n (title || description) && (\n <div className=\"space-y-1.5 p-6\">{header}</div>\n )\n )}\n <CardContent className=\"space-y-4\">\n <input\n ref={inputRef}\n type=\"file\"\n accept={accept}\n multiple={multiple}\n className=\"sr-only\"\n onChange={(event) => handleFiles(event.target.files)}\n disabled={disabled}\n />\n <div\n role=\"button\"\n tabIndex={disabled ? -1 : 0}\n aria-disabled={disabled}\n className={cn(\n 'flex min-h-40 cursor-pointer touch-manipulation flex-col items-center justify-center rounded-lg border border-dashed border-muted-foreground/30 bg-muted/20 px-6 py-8 text-center transition-colors duration-150 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background',\n isDragging && 'border-primary bg-primary/10 shadow-inner',\n disabled && 'cursor-not-allowed opacity-60',\n dropzoneClassName\n )}\n onClick={() => {\n if (!disabled) {\n inputRef.current?.click();\n }\n }}\n onKeyDown={(event) => {\n if (!disabled && (event.key === 'Enter' || event.key === ' ')) {\n event.preventDefault();\n inputRef.current?.click();\n }\n }}\n onDragOver={(event) => {\n event.preventDefault();\n if (!disabled) {\n setIsDragging(true);\n }\n }}\n onDragLeave={() => setIsDragging(false)}\n onDrop={handleDrop}\n >\n <div className=\"mb-3 rounded-full bg-primary/10 p-3 text-primary\">\n <UploadCloud className=\"h-6 w-6\" />\n </div>\n <div className=\"text-sm font-medium\">{dropzoneLabel}</div>\n {dropzoneDescription && (\n <div className=\"mt-1 max-w-md text-sm text-muted-foreground\">\n {dropzoneDescription}\n </div>\n )}\n <Button\n type=\"button\"\n size=\"sm\"\n variant=\"secondary\"\n className=\"mt-4\"\n disabled={disabled}\n onClick={(event) => {\n event.stopPropagation();\n inputRef.current?.click();\n }}\n >\n {selectLabel}\n </Button>\n </div>\n\n {helperText && (\n <div className=\"text-sm text-muted-foreground\">{helperText}</div>\n )}\n\n <div className={cn('space-y-3', listClassName)}>\n {items.length === 0 ? (\n <div className=\"rounded-md border border-dashed bg-muted/20 px-4 py-3 text-sm text-muted-foreground\">\n {emptyLabel}\n </div>\n ) : (\n items.map((item) => (\n <div\n key={item.id}\n className=\"rounded-lg border bg-background px-4 py-3 shadow-sm\"\n >\n <div className=\"flex min-w-0 items-start gap-3\">\n <div className=\"mt-0.5 rounded-md bg-muted p-2 text-muted-foreground\">\n <FileText className=\"h-4 w-4\" />\n </div>\n <div className=\"min-w-0 flex-1 space-y-2\">\n <div className=\"flex flex-wrap items-start justify-between gap-2\">\n <div className=\"min-w-0\">\n <div className=\"truncate text-sm font-medium\">\n {item.name}\n </div>\n <div className=\"text-xs text-muted-foreground\">\n {formatFileSize(item.size)}\n {item.type ? ` · ${item.type}` : ''}\n </div>\n </div>\n {renderStatus(item)}\n </div>\n {item.status === 'uploading' && (\n <div\n className=\"h-2 overflow-hidden rounded-full bg-muted\"\n aria-label={`${item.name} 上传进度`}\n role=\"progressbar\"\n aria-valuenow={item.progress}\n aria-valuemin={0}\n aria-valuemax={100}\n >\n <div\n className=\"h-full rounded-full bg-primary transition-all\"\n style={{ width: `${item.progress}%` }}\n />\n </div>\n )}\n {item.error && (\n <div className=\"break-words text-xs text-destructive\">\n {item.error}\n </div>\n )}\n </div>\n <div className=\"flex shrink-0 items-center gap-1\">\n {item.status === 'error' && onUpload && (\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n disabled={disabled || isUploading}\n onClick={() => handleRetry(item)}\n >\n {retryLabel}\n </Button>\n )}\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon\"\n aria-label={`移除 ${item.name}`}\n disabled={disabled || item.status === 'uploading'}\n onClick={() => handleRemove(item.id)}\n >\n <X className=\"h-4 w-4\" />\n </Button>\n </div>\n </div>\n </div>\n ))\n )}\n </div>\n </CardContent>\n {(shouldShowUploadButton || showResetButton) &&\n (CardFooter ? (\n <CardFooter className=\"justify-end gap-2\">\n {showResetButton && (\n <Button\n type=\"button\"\n variant=\"outline\"\n disabled={disabled || isUploading || items.length === 0}\n onClick={() => setItems([])}\n >\n {resetLabel}\n </Button>\n )}\n {shouldShowUploadButton && (\n <Button\n type=\"button\"\n disabled={\n disabled || isUploading || !hasUploadableItems || !onUpload\n }\n onClick={uploadReadyItems}\n >\n {uploadLabel}\n </Button>\n )}\n </CardFooter>\n ) : (\n <div className=\"flex justify-end gap-2 p-6 pt-0\">\n {showResetButton && (\n <Button\n type=\"button\"\n variant=\"outline\"\n disabled={disabled || isUploading || items.length === 0}\n onClick={() => setItems([])}\n >\n {resetLabel}\n </Button>\n )}\n {shouldShowUploadButton && (\n <Button\n type=\"button\"\n disabled={\n disabled || isUploading || !hasUploadableItems || !onUpload\n }\n onClick={uploadReadyItems}\n >\n {uploadLabel}\n </Button>\n )}\n </div>\n ))}\n </Card>\n );\n}\n"],"names":["defaultFormatFileSize","size","createFileId","file","getFileExtension","fileName","index","matchesAccept","accept","fileType","fileExtension","item","rule","getErrorMessage","error","fallback","FileUpload","components","title","description","helperText","multiple","maxFiles","maxSize","disabled","autoUpload","showUploadButton","showResetButton","selectLabel","uploadLabel","retryLabel","resetLabel","emptyLabel","dropzoneLabel","dropzoneDescription","uploadingText","successText","errorText","className","dropzoneClassName","listClassName","formatFileSize","validateFile","onFilesChange","onUpload","onUploadComplete","onUploadError","items","setItems","useState","isDragging","setIsDragging","inputRef","useRef","shouldShowUploadButton","resolvedMaxFiles","hasUploadableItems","isUploading","useEffect","jsx","Card","CardHeader","CardTitle","CardDescription","CardContent","CardFooter","Button","updateItems","updater","currentItems","getValidationError","createItemsFromFiles","files","nextItems","remainingSlots","uploadItem","targetItem","setProgress","progress","result","completedItem","failedItem","uploadReadyItems","readyItems","handleFiles","fileList","handleDrop","event","handleRemove","id","handleRetry","currentItem","renderStatus","jsxs","Loader2","CheckCircle2","XCircle","header","Fragment","cn","_a","UploadCloud","FileText","X"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./jsx-runtime-BB_1_6y_.cjs"),u=require("lucide-react"),r=require("react"),I=require("./utils-IjLH3w2e.cjs"),$=require("./media-utils-X1dDYP9W.cjs"),z=["jpg","jpeg","png","gif","webp","svg","bmp","avif","ico"],L=["image/jpeg","image/png","image/gif","image/webp","image/svg+xml","image/bmp","image/avif","image/x-icon","image/vnd.microsoft.icon"],pe=s=>s?s instanceof Error?s:new Error(s):null,je=(s,c,a)=>Math.min(Math.max(s,c),a);function Ee({src:s,alt:c="",fileName:a,mimeType:d,components:B,loading:F=!1,error:X,className:M,containerClassName:Y,imageClassName:Z,toolbarClassName:H,loadingText:J="正在加载图片...",errorText:S="图片加载失败",unsupportedText:K="暂不支持该图片格式",showToolbar:Q=!0,showOpenInNewTab:V=!0,objectFit:W="contain",initialScale:C=1,minScale:p=.25,maxScale:j=4,scaleStep:y=.25,scale:E,onScaleChange:l,rotation:f,onRotationChange:m,allowUnsupportedFormat:ee=!1,supportedExtensions:te=z,supportedMimeTypes:se=L,onLoad:g,onError:R,style:ne,...re}){const{Card:P,CardContent:_,Button:O,Skeleton:b}=B||{},[ie,oe]=r.useState(C),[ae,xe]=r.useState(0),[ue,h]=r.useState(!0),[le,v]=r.useState(null),o=E??ie,w=f??ae,i=pe(X)||le,k=ee||$.isSupportedMediaSource({src:s,fileName:a,mimeType:d,supportedExtensions:te,supportedMimeTypes:se}),q=F||ue&&!i,T=r.useCallback(t=>{const n=je(t,p,j);E===void 0&&oe(n),l==null||l(n)},[E,j,p,l]),U=r.useCallback(t=>{const n=(t%360+360)%360;f===void 0&&xe(n),m==null||m(n)},[f,m]),me=r.useMemo(()=>{const t=$.getMediaExtension(s,a);return t?t.toUpperCase():d||"图片"},[a,d,s]);r.useEffect(()=>{h(!0),v(null)},[s]);const x=(t,n,D,G)=>{const de="inline-flex h-8 w-8 items-center justify-center rounded-md border border-input bg-background text-foreground shadow-sm transition-colors hover:bg-accent hover:text-accent-foreground disabled:pointer-events-none disabled:opacity-50";return O?e.jsxRuntimeExports.jsx(O,{"aria-label":t,className:"h-8 w-8",disabled:G,onClick:D,size:"icon",title:t,type:"button",variant:"outline",children:n}):e.jsxRuntimeExports.jsx("button",{"aria-label":t,className:de,disabled:G,onClick:D,title:t,type:"button",children:n})},ce=()=>e.jsxRuntimeExports.jsx("div",{className:"w-full space-y-3 p-4",role:"status","aria-live":"polite",children:b?e.jsxRuntimeExports.jsxs(e.jsxRuntimeExports.Fragment,{children:[e.jsxRuntimeExports.jsx(b,{className:"h-4 w-32"}),e.jsxRuntimeExports.jsx(b,{className:"h-80 w-full"})]}):e.jsxRuntimeExports.jsx("p",{className:"text-sm text-muted-foreground",children:J})}),A=t=>e.jsxRuntimeExports.jsxs("div",{className:"p-4 text-center text-sm text-destructive",role:"alert",children:[e.jsxRuntimeExports.jsx("p",{className:"font-medium",children:t||S}),i!=null&&i.message?e.jsxRuntimeExports.jsx("p",{className:"mt-1 opacity-80",children:i.message}):null]}),N=e.jsxRuntimeExports.jsxs("div",{className:I.cn("flex h-full min-h-[360px] flex-col overflow-hidden rounded-md border bg-background",Y),children:[Q?e.jsxRuntimeExports.jsxs("div",{className:I.cn("flex flex-wrap items-center justify-between gap-2 border-b px-3 py-2",H),children:[e.jsxRuntimeExports.jsx("span",{className:"text-xs font-medium text-muted-foreground",children:me}),e.jsxRuntimeExports.jsxs("div",{className:"flex items-center gap-1",children:[x("缩小",e.jsxRuntimeExports.jsx(u.ZoomOut,{className:"h-4 w-4"}),()=>T(o-y),o<=p),e.jsxRuntimeExports.jsxs("span",{className:"min-w-14 text-center text-xs text-muted-foreground",children:[Math.round(o*100),"%"]}),x("放大",e.jsxRuntimeExports.jsx(u.ZoomIn,{className:"h-4 w-4"}),()=>T(o+y),o>=j),x("向左旋转",e.jsxRuntimeExports.jsx(u.RotateCcw,{className:"h-4 w-4"}),()=>U(w-90)),x("向右旋转",e.jsxRuntimeExports.jsx(u.RotateCw,{className:"h-4 w-4"}),()=>U(w+90)),V?x("新窗口打开",e.jsxRuntimeExports.jsx(u.ExternalLink,{className:"h-4 w-4"}),()=>window.open(s,"_blank","noreferrer")):null]})]}):null,e.jsxRuntimeExports.jsxs("div",{className:"relative flex min-h-0 flex-1 items-center justify-center overflow-auto bg-muted/20 p-4",children:[k?i?A():null:A(K),k&&!i?e.jsxRuntimeExports.jsxs(e.jsxRuntimeExports.Fragment,{children:[q?ce():null,e.jsxRuntimeExports.jsx("img",{...re,alt:c,className:I.cn("max-h-full max-w-full transition-transform",q?"invisible absolute":"visible",Z),onError:()=>{const t=new Error(S);h(!1),v(t),R==null||R(t)},onLoad:()=>{h(!1),v(null),g==null||g()},src:s,decoding:"async",style:{objectFit:W,transform:`scale(${o}) rotate(${w}deg)`,transformOrigin:"center center",...ne}})]}):null]})]});return P?e.jsxRuntimeExports.jsx(P,{className:M,children:_?e.jsxRuntimeExports.jsx(_,{children:N}):N}):e.jsxRuntimeExports.jsx("div",{className:M,children:N})}exports.ImageReader=Ee;exports.SUPPORTED_IMAGE_EXTENSIONS=z;exports.SUPPORTED_IMAGE_MIME_TYPES=L;
2
+ //# sourceMappingURL=image-reader.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"image-reader.cjs","sources":["../src/components/ImageReader.tsx"],"sourcesContent":["import {\n ExternalLink as ExternalLinkIcon,\n RotateCcw as RotateCcwIcon,\n RotateCw as RotateCwIcon,\n ZoomIn as ZoomInIcon,\n ZoomOut as ZoomOutIcon,\n} from 'lucide-react';\nimport { useCallback, useEffect, useMemo, useState } from 'react';\nimport type { HTMLAttributes, ImgHTMLAttributes, ReactNode } from 'react';\n\nimport { cn } from '../lib/utils';\nimport type {\n ButtonComponent,\n CardComponent,\n SkeletonComponent,\n UIComponent,\n} from '../types/component-types';\n\nimport { getMediaExtension, isSupportedMediaSource } from './media-utils';\n\nexport const SUPPORTED_IMAGE_EXTENSIONS = [\n 'jpg',\n 'jpeg',\n 'png',\n 'gif',\n 'webp',\n 'svg',\n 'bmp',\n 'avif',\n 'ico',\n] as const;\n\nexport const SUPPORTED_IMAGE_MIME_TYPES = [\n 'image/jpeg',\n 'image/png',\n 'image/gif',\n 'image/webp',\n 'image/svg+xml',\n 'image/bmp',\n 'image/avif',\n 'image/x-icon',\n 'image/vnd.microsoft.icon',\n] as const;\n\nexport interface ImageReaderUIComponents {\n Card?: CardComponent;\n CardContent?: UIComponent<HTMLAttributes<HTMLDivElement>>;\n Button?: ButtonComponent;\n Skeleton?: SkeletonComponent;\n}\n\nexport interface ImageReaderProps extends Omit<\n ImgHTMLAttributes<HTMLImageElement>,\n 'alt' | 'children' | 'className' | 'loading' | 'onError' | 'onLoad' | 'src'\n> {\n src: string;\n alt?: string;\n fileName?: string;\n mimeType?: string;\n components?: ImageReaderUIComponents;\n loading?: boolean;\n error?: Error | string | null;\n className?: string;\n containerClassName?: string;\n imageClassName?: string;\n toolbarClassName?: string;\n loadingText?: string;\n errorText?: string;\n unsupportedText?: string;\n showToolbar?: boolean;\n showOpenInNewTab?: boolean;\n objectFit?: 'contain' | 'cover' | 'fill' | 'none' | 'scale-down';\n initialScale?: number;\n minScale?: number;\n maxScale?: number;\n scaleStep?: number;\n scale?: number;\n onScaleChange?: (scale: number) => void;\n rotation?: number;\n onRotationChange?: (rotation: number) => void;\n allowUnsupportedFormat?: boolean;\n supportedExtensions?: readonly string[];\n supportedMimeTypes?: readonly string[];\n onLoad?: () => void;\n onError?: (error: Error) => void;\n}\n\nconst normalizeError = (error: Error | string | null | undefined) => {\n if (!error) return null;\n return error instanceof Error ? error : new Error(error);\n};\n\nconst clamp = (value: number, min: number, max: number) =>\n Math.min(Math.max(value, min), max);\n\nexport function ImageReader({\n src,\n alt = '',\n fileName,\n mimeType,\n components,\n loading = false,\n error,\n className,\n containerClassName,\n imageClassName,\n toolbarClassName,\n loadingText = '正在加载图片...',\n errorText = '图片加载失败',\n unsupportedText = '暂不支持该图片格式',\n showToolbar = true,\n showOpenInNewTab = true,\n objectFit = 'contain',\n initialScale = 1,\n minScale = 0.25,\n maxScale = 4,\n scaleStep = 0.25,\n scale: controlledScale,\n onScaleChange,\n rotation: controlledRotation,\n onRotationChange,\n allowUnsupportedFormat = false,\n supportedExtensions = SUPPORTED_IMAGE_EXTENSIONS,\n supportedMimeTypes = SUPPORTED_IMAGE_MIME_TYPES,\n onLoad,\n onError,\n style,\n ...imageProps\n}: ImageReaderProps) {\n const { Card, CardContent, Button, Skeleton } = components || {};\n const [internalScale, setInternalScale] = useState(initialScale);\n const [internalRotation, setInternalRotation] = useState(0);\n const [isImageLoading, setIsImageLoading] = useState(true);\n const [imageError, setImageError] = useState<Error | null>(null);\n\n const scale = controlledScale ?? internalScale;\n const rotation = controlledRotation ?? internalRotation;\n const displayedError = normalizeError(error) || imageError;\n const isSupported =\n allowUnsupportedFormat ||\n isSupportedMediaSource({\n src,\n fileName,\n mimeType,\n supportedExtensions,\n supportedMimeTypes,\n });\n const isLoading = loading || (isImageLoading && !displayedError);\n\n const setNextScale = useCallback(\n (nextScale: number) => {\n const clampedScale = clamp(nextScale, minScale, maxScale);\n if (controlledScale === undefined) {\n setInternalScale(clampedScale);\n }\n onScaleChange?.(clampedScale);\n },\n [controlledScale, maxScale, minScale, onScaleChange]\n );\n\n const setNextRotation = useCallback(\n (nextRotation: number) => {\n const normalizedRotation = ((nextRotation % 360) + 360) % 360;\n if (controlledRotation === undefined) {\n setInternalRotation(normalizedRotation);\n }\n onRotationChange?.(normalizedRotation);\n },\n [controlledRotation, onRotationChange]\n );\n\n const formatLabel = useMemo(() => {\n const extension = getMediaExtension(src, fileName);\n return extension ? extension.toUpperCase() : mimeType || '图片';\n }, [fileName, mimeType, src]);\n\n useEffect(() => {\n setIsImageLoading(true);\n setImageError(null);\n }, [src]);\n\n const renderButton = (\n label: string,\n icon: ReactNode,\n onClick: () => void,\n disabled?: boolean\n ) => {\n const buttonClassName =\n 'inline-flex h-8 w-8 items-center justify-center rounded-md border border-input bg-background text-foreground shadow-sm transition-colors hover:bg-accent hover:text-accent-foreground disabled:pointer-events-none disabled:opacity-50';\n\n if (Button) {\n return (\n <Button\n aria-label={label}\n className=\"h-8 w-8\"\n disabled={disabled}\n onClick={onClick}\n size=\"icon\"\n title={label}\n type=\"button\"\n variant=\"outline\"\n >\n {icon}\n </Button>\n );\n }\n\n return (\n <button\n aria-label={label}\n className={buttonClassName}\n disabled={disabled}\n onClick={onClick}\n title={label}\n type=\"button\"\n >\n {icon}\n </button>\n );\n };\n\n const renderLoading = () => (\n <div className=\"w-full space-y-3 p-4\" role=\"status\" aria-live=\"polite\">\n {Skeleton ? (\n <>\n <Skeleton className=\"h-4 w-32\" />\n <Skeleton className=\"h-80 w-full\" />\n </>\n ) : (\n <p className=\"text-sm text-muted-foreground\">{loadingText}</p>\n )}\n </div>\n );\n\n const renderError = (message?: string) => (\n <div className=\"p-4 text-center text-sm text-destructive\" role=\"alert\">\n <p className=\"font-medium\">{message || errorText}</p>\n {displayedError?.message ? (\n <p className=\"mt-1 opacity-80\">{displayedError.message}</p>\n ) : null}\n </div>\n );\n\n const body = (\n <div\n className={cn(\n 'flex h-full min-h-[360px] flex-col overflow-hidden rounded-md border bg-background',\n containerClassName\n )}\n >\n {showToolbar ? (\n <div\n className={cn(\n 'flex flex-wrap items-center justify-between gap-2 border-b px-3 py-2',\n toolbarClassName\n )}\n >\n <span className=\"text-xs font-medium text-muted-foreground\">\n {formatLabel}\n </span>\n <div className=\"flex items-center gap-1\">\n {renderButton(\n '缩小',\n <ZoomOutIcon className=\"h-4 w-4\" />,\n () => setNextScale(scale - scaleStep),\n scale <= minScale\n )}\n <span className=\"min-w-14 text-center text-xs text-muted-foreground\">\n {Math.round(scale * 100)}%\n </span>\n {renderButton(\n '放大',\n <ZoomInIcon className=\"h-4 w-4\" />,\n () => setNextScale(scale + scaleStep),\n scale >= maxScale\n )}\n {renderButton(\n '向左旋转',\n <RotateCcwIcon className=\"h-4 w-4\" />,\n () => setNextRotation(rotation - 90)\n )}\n {renderButton(\n '向右旋转',\n <RotateCwIcon className=\"h-4 w-4\" />,\n () => setNextRotation(rotation + 90)\n )}\n {showOpenInNewTab\n ? renderButton(\n '新窗口打开',\n <ExternalLinkIcon className=\"h-4 w-4\" />,\n () => window.open(src, '_blank', 'noreferrer')\n )\n : null}\n </div>\n </div>\n ) : null}\n <div className=\"relative flex min-h-0 flex-1 items-center justify-center overflow-auto bg-muted/20 p-4\">\n {!isSupported\n ? renderError(unsupportedText)\n : displayedError\n ? renderError()\n : null}\n {isSupported && !displayedError ? (\n <>\n {isLoading ? renderLoading() : null}\n <img\n {...imageProps}\n alt={alt}\n className={cn(\n 'max-h-full max-w-full transition-transform',\n isLoading ? 'invisible absolute' : 'visible',\n imageClassName\n )}\n onError={() => {\n const nextError = new Error(errorText);\n setIsImageLoading(false);\n setImageError(nextError);\n onError?.(nextError);\n }}\n onLoad={() => {\n setIsImageLoading(false);\n setImageError(null);\n onLoad?.();\n }}\n src={src}\n decoding=\"async\"\n style={{\n objectFit,\n transform: `scale(${scale}) rotate(${rotation}deg)`,\n transformOrigin: 'center center',\n ...style,\n }}\n />\n </>\n ) : null}\n </div>\n </div>\n );\n\n if (Card) {\n return (\n <Card className={className}>\n {CardContent ? <CardContent>{body}</CardContent> : body}\n </Card>\n );\n }\n\n return <div className={className}>{body}</div>;\n}\n"],"names":["SUPPORTED_IMAGE_EXTENSIONS","SUPPORTED_IMAGE_MIME_TYPES","normalizeError","error","clamp","value","min","max","ImageReader","src","alt","fileName","mimeType","components","loading","className","containerClassName","imageClassName","toolbarClassName","loadingText","errorText","unsupportedText","showToolbar","showOpenInNewTab","objectFit","initialScale","minScale","maxScale","scaleStep","controlledScale","onScaleChange","controlledRotation","onRotationChange","allowUnsupportedFormat","supportedExtensions","supportedMimeTypes","onLoad","onError","style","imageProps","Card","CardContent","Button","Skeleton","internalScale","setInternalScale","useState","internalRotation","setInternalRotation","isImageLoading","setIsImageLoading","imageError","setImageError","scale","rotation","displayedError","isSupported","isSupportedMediaSource","isLoading","setNextScale","useCallback","nextScale","clampedScale","setNextRotation","nextRotation","normalizedRotation","formatLabel","useMemo","extension","getMediaExtension","useEffect","renderButton","label","icon","onClick","disabled","buttonClassName","jsx","renderLoading","jsxs","Fragment","renderError","message","body","cn","ZoomOutIcon","ZoomInIcon","RotateCcwIcon","RotateCwIcon","ExternalLinkIcon","nextError"],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ export { ImageReader, SUPPORTED_IMAGE_EXTENSIONS, SUPPORTED_IMAGE_MIME_TYPES, } from './components/ImageReader';
2
+ export type { ImageReaderProps, ImageReaderUIComponents, } from './components/ImageReader';
3
+ //# sourceMappingURL=image-reader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"image-reader.d.ts","sourceRoot":"","sources":["../src/image-reader.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,WAAW,EACX,0BAA0B,EAC1B,0BAA0B,GAC3B,MAAM,0BAA0B,CAAC;AAClC,YAAY,EACV,gBAAgB,EAChB,uBAAuB,GACxB,MAAM,0BAA0B,CAAC"}