@turinhub/atomix-common-ui 0.4.0 → 0.5.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 (69) hide show
  1. package/README.md +20 -2
  2. package/dist/AuthPanel-C_2JBE7t.cjs +2 -0
  3. package/dist/AuthPanel-C_2JBE7t.cjs.map +1 -0
  4. package/dist/AuthPanel-D2HFX8eN.js +656 -0
  5. package/dist/AuthPanel-D2HFX8eN.js.map +1 -0
  6. package/dist/auth.cjs +2 -0
  7. package/dist/auth.cjs.map +1 -0
  8. package/dist/auth.d.ts +11 -0
  9. package/dist/auth.d.ts.map +1 -0
  10. package/dist/auth.js +9 -0
  11. package/dist/auth.js.map +1 -0
  12. package/dist/components/AuthLoginPanel.d.ts +55 -0
  13. package/dist/components/AuthLoginPanel.d.ts.map +1 -0
  14. package/dist/components/AuthPageShell.d.ts +11 -0
  15. package/dist/components/AuthPageShell.d.ts.map +1 -0
  16. package/dist/components/AuthPanel.d.ts +20 -0
  17. package/dist/components/AuthPanel.d.ts.map +1 -0
  18. package/dist/components/AuthRegisterPanel.d.ts +34 -0
  19. package/dist/components/AuthRegisterPanel.d.ts.map +1 -0
  20. package/dist/components/AuthVisualCarousel.d.ts +20 -0
  21. package/dist/components/AuthVisualCarousel.d.ts.map +1 -0
  22. package/dist/components/DataTable.d.ts +2 -2
  23. package/dist/components/DataTable.d.ts.map +1 -1
  24. package/dist/components/ImageReader.d.ts +44 -0
  25. package/dist/components/ImageReader.d.ts.map +1 -0
  26. package/dist/components/VideoReader.d.ts +39 -0
  27. package/dist/components/VideoReader.d.ts.map +1 -0
  28. package/dist/components/media-utils.d.ts +9 -0
  29. package/dist/components/media-utils.d.ts.map +1 -0
  30. package/dist/data-table.cjs +1 -1
  31. package/dist/data-table.cjs.map +1 -1
  32. package/dist/data-table.js +83 -73
  33. package/dist/data-table.js.map +1 -1
  34. package/dist/image-reader.cjs +2 -0
  35. package/dist/image-reader.cjs.map +1 -0
  36. package/dist/image-reader.d.ts +3 -0
  37. package/dist/image-reader.d.ts.map +1 -0
  38. package/dist/image-reader.js +214 -0
  39. package/dist/image-reader.js.map +1 -0
  40. package/dist/index.cjs +1 -1
  41. package/dist/index.d.ts +10 -0
  42. package/dist/index.d.ts.map +1 -1
  43. package/dist/index.js +8 -2
  44. package/dist/index.js.map +1 -1
  45. package/dist/media-utils-5UPuocc1.js +23 -0
  46. package/dist/media-utils-5UPuocc1.js.map +1 -0
  47. package/dist/media-utils-X1dDYP9W.cjs +2 -0
  48. package/dist/media-utils-X1dDYP9W.cjs.map +1 -0
  49. package/dist/pdf-reader.cjs +1 -1
  50. package/dist/pdf-reader.cjs.map +1 -1
  51. package/dist/pdf-reader.js +1 -1
  52. package/dist/pdf-reader.js.map +1 -1
  53. package/dist/simple-pdf-reader.cjs +1 -1
  54. package/dist/simple-pdf-reader.cjs.map +1 -1
  55. package/dist/simple-pdf-reader.js +1 -1
  56. package/dist/simple-pdf-reader.js.map +1 -1
  57. package/dist/types/component-types.d.ts +1 -0
  58. package/dist/types/component-types.d.ts.map +1 -1
  59. package/dist/video-reader.cjs +2 -0
  60. package/dist/video-reader.cjs.map +1 -0
  61. package/dist/video-reader.d.ts +3 -0
  62. package/dist/video-reader.d.ts.map +1 -0
  63. package/dist/video-reader.js +158 -0
  64. package/dist/video-reader.js.map +1 -0
  65. package/package.json +31 -1
  66. package/dist/index-BiA_tnaq.cjs +0 -13
  67. package/dist/index-BiA_tnaq.cjs.map +0 -1
  68. package/dist/index-BypbGNpR.js +0 -18821
  69. package/dist/index-BypbGNpR.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"data-table.cjs","sources":["../src/components/DataTable.tsx"],"sourcesContent":["import { MoreVertical } from 'lucide-react';\nimport { ReactNode } from 'react';\nimport type { HTMLAttributes, ButtonHTMLAttributes } from 'react';\n\nimport type {\n UIComponent,\n ButtonComponent,\n CardComponent,\n TableComponent,\n TableRowComponent,\n TableCellComponent,\n} from '../types/component-types';\n\nimport type { TableHeaderProps } from './TableHeader';\nimport type { TablePaginationProps } from './TablePagination';\n\ntype ColumnKey<T> = Extract<keyof T, string>;\n\ntype ActionMenuItem<T> = {\n label: ReactNode;\n icon?: ReactNode;\n onClick: (record: T, index: number) => void;\n className?: string;\n separator?: never;\n};\n\ntype ActionSeparatorItem = {\n separator: true;\n className?: string;\n label?: never;\n icon?: never;\n onClick?: never;\n};\n\ntype ActionItem<T> = ActionMenuItem<T> | ActionSeparatorItem;\n\nexport interface Column<T = unknown> {\n key: ColumnKey<T>;\n title: ReactNode;\n render?: (value: T[ColumnKey<T>], record: T, index: number) => ReactNode;\n width?: string;\n align?: 'left' | 'center' | 'right';\n}\n\n/**\n * UI 组件适配器接口\n * 业务项目应该传入自己项目中的 shadcn/ui 组件\n */\nexport interface UIComponents {\n Card: CardComponent;\n CardContent: UIComponent<HTMLAttributes<HTMLDivElement>>;\n CardFooter: UIComponent<HTMLAttributes<HTMLDivElement>>;\n Table: TableComponent;\n TableBody: UIComponent<HTMLAttributes<HTMLTableSectionElement>>;\n TableCell: TableCellComponent;\n TableHead: TableCellComponent;\n TableHeader: UIComponent<HTMLAttributes<HTMLTableSectionElement>>;\n TableRow: TableRowComponent;\n Button: ButtonComponent;\n DropdownMenu: UIComponent<HTMLAttributes<HTMLDivElement>>;\n DropdownMenuTrigger: ButtonComponent;\n DropdownMenuContent: UIComponent<\n HTMLAttributes<HTMLDivElement> & { align?: 'start' | 'end' | 'center' }\n >;\n DropdownMenuItem: UIComponent<\n ButtonHTMLAttributes<HTMLDivElement> & {\n onClick?: (e: React.MouseEvent) => void;\n }\n >;\n DropdownMenuSeparator: UIComponent;\n Skeleton: UIComponent<HTMLAttributes<HTMLDivElement>>;\n TableHeaderComponent: React.ComponentType<TableHeaderProps>;\n TablePaginationComponent: React.ComponentType<TablePaginationProps>;\n}\n\nexport interface DataTableProps<T = unknown> {\n // 数据相关\n data: T[];\n loading?: boolean;\n columns: Column<T>[];\n rowKey: keyof T | ((record: T) => string);\n\n // 空状态\n emptyText?: string;\n searchActiveEmptyText?: string;\n\n // 头部配置\n header?: TableHeaderProps;\n\n // 分页配置\n pagination?: TablePaginationProps & {\n show?: boolean;\n };\n\n // 表格行样式\n rowClassName?: (record: T, index: number) => string;\n onRow?: (\n record: T,\n index: number\n ) => {\n onClick?: () => void;\n onDoubleClick?: () => void;\n };\n\n // 操作列\n actions?: {\n title?: string;\n mode?: 'expanded' | 'collapsed';\n render?: (record: T, index: number) => ReactNode;\n items?: ActionItem<T>[];\n };\n\n // UI 组件注入(可选)\n components?: UIComponents;\n\n // 自定义渲染函数(更灵活)\n renderCard?: (content: ReactNode) => ReactNode;\n renderTable?: (header: ReactNode, body: ReactNode) => ReactNode;\n renderActions?: (record: T, index: number) => ReactNode;\n}\n\n/**\n * 默认的 DataTable 实现\n * 需要通过 components prop 注入 UI 组件\n */\nexport function DataTable<T extends Record<string, any>>({\n data,\n loading = false,\n columns,\n rowKey,\n emptyText = '暂无数据',\n searchActiveEmptyText = '未找到匹配的记录',\n header,\n pagination,\n rowClassName,\n onRow,\n actions,\n components,\n renderCard,\n renderTable,\n renderActions,\n}: DataTableProps<T>) {\n if (!components) {\n return (\n <div className=\"p-4 text-center text-destructive\">\n 错误:请通过 components prop 注入 UI 组件\n <br />\n <code className=\"text-sm\">\n {'import { Card, Table, Button, ... } from \"@/components/ui\"'}\n </code>\n </div>\n );\n }\n\n const {\n Card,\n CardContent,\n CardFooter,\n Table,\n TableBody,\n TableCell,\n TableHead,\n TableHeader,\n TableRow,\n Button,\n DropdownMenu,\n DropdownMenuTrigger,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuSeparator,\n Skeleton,\n TableHeaderComponent,\n TablePaginationComponent,\n } = components;\n\n // 获取行的唯一标识\n const getRowKey = (record: T, index: number): string => {\n if (typeof rowKey === 'function') {\n return rowKey(record);\n }\n const keyVal = record[rowKey];\n return keyVal !== undefined && keyVal !== null\n ? String(keyVal)\n : `row-${index}`;\n };\n\n // 检查是否有搜索活动\n const isSearchActive = Boolean(\n header?.searchValue && header.searchValue.trim().length > 0\n );\n const hasActions = Boolean(actions?.render || actions?.items?.length);\n const actionMode: 'expanded' | 'collapsed' =\n actions?.mode ?? (actions?.items?.length ? 'collapsed' : 'expanded');\n const isSeparatorItem = (item: ActionItem<T>): item is ActionSeparatorItem =>\n item.separator === true;\n\n // 渲染操作列\n const defaultRenderActions = (record: T, index: number) => {\n if (!actions || !hasActions) return null;\n\n // 折叠模式:使用 DropdownMenu\n if (\n actionMode === 'collapsed' &&\n actions.items &&\n actions.items.length > 0\n ) {\n return (\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button\n variant=\"ghost\"\n className=\"h-8 w-8 p-0\"\n aria-label=\"打开行操作菜单\"\n >\n <MoreVertical className=\"h-4 w-4\" />\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\">\n {actions.items.map((item, itemIndex) =>\n isSeparatorItem(item) ? (\n <DropdownMenuSeparator key={`separator-${itemIndex}`} />\n ) : (\n <DropdownMenuItem\n key={`action-${itemIndex}`}\n onClick={() => item.onClick(record, index)}\n className={item.className}\n >\n {item.icon && (\n <span className=\"mr-2 h-4 w-4\">{item.icon}</span>\n )}\n {item.label}\n </DropdownMenuItem>\n )\n )}\n </DropdownMenuContent>\n </DropdownMenu>\n );\n }\n\n // 展开模式:使用自定义 render\n return actions.render ? actions.render(record, index) : null;\n };\n\n // 渲染表头\n const renderTableHeader = () => {\n return (\n <TableHeader>\n <TableRow className=\"bg-muted/50 hover:bg-muted/50\">\n {columns.map((column) => (\n <TableHead\n key={String(column.key)}\n className={`font-semibold text-foreground ${\n column.align === 'center'\n ? 'text-center'\n : column.align === 'right'\n ? 'text-right'\n : 'text-left'\n }`}\n style={{ width: column.width }}\n >\n {column.title}\n </TableHead>\n ))}\n {hasActions && (\n <TableHead className=\"text-right font-semibold text-foreground\">\n {actions?.title || '操作'}\n </TableHead>\n )}\n </TableRow>\n </TableHeader>\n );\n };\n\n // 渲染表体\n const renderTableBody = () => {\n // Loading 状态\n if (loading) {\n return (\n <TableBody>\n {Array.from({ length: 5 }).map((_, index) => (\n <TableRow key={index}>\n {columns.map((column) => (\n <TableCell\n key={String(column.key)}\n style={{ width: column.width }}\n className={\n column.align === 'center'\n ? 'text-center'\n : column.align === 'right'\n ? 'text-right'\n : ''\n }\n >\n <Skeleton className=\"h-4 w-full\" />\n </TableCell>\n ))}\n {hasActions && (\n <TableCell>\n <Skeleton className=\"ml-auto h-4 w-8\" />\n </TableCell>\n )}\n </TableRow>\n ))}\n </TableBody>\n );\n }\n\n // 空数据状态\n if (data.length === 0) {\n return (\n <TableBody>\n <TableRow>\n <TableCell\n colSpan={columns.length + (hasActions ? 1 : 0)}\n className=\"py-8 text-center text-muted-foreground\"\n >\n {isSearchActive ? searchActiveEmptyText : emptyText}\n </TableCell>\n </TableRow>\n </TableBody>\n );\n }\n\n // 数据行\n return (\n <TableBody>\n {data.map((record, index) => {\n const key = getRowKey(record, index);\n const rowProps = onRow?.(record, index);\n const className = rowClassName?.(record, index);\n\n return (\n <TableRow\n key={key}\n className={`${className || ''} hover:bg-muted/50`}\n {...rowProps}\n >\n {columns.map((column) => {\n const value = record[column.key as keyof T];\n const content = column.render\n ? column.render(value as T[ColumnKey<T>], record, index)\n : value;\n\n return (\n <TableCell\n key={String(column.key)}\n className={\n column.align === 'center'\n ? 'text-center'\n : column.align === 'right'\n ? 'text-right'\n : ''\n }\n >\n {content}\n </TableCell>\n );\n })}\n {hasActions && (\n <TableCell className=\"text-right\">\n {renderActions\n ? renderActions(record, index)\n : defaultRenderActions(record, index)}\n </TableCell>\n )}\n </TableRow>\n );\n })}\n </TableBody>\n );\n };\n\n // 默认的卡片渲染\n const defaultRenderCard = (content: ReactNode) => (\n <Card>\n {header && (\n <div className=\"p-6 pb-0\">\n <TableHeaderComponent {...header} />\n </div>\n )}\n <CardContent className=\"p-0\">{content}</CardContent>\n {pagination?.show !== false && pagination && (\n <CardFooter className=\"border-t py-4\">\n <TablePaginationComponent\n currentPage={pagination.currentPage}\n pageSize={pagination.pageSize}\n total={pagination.total}\n onPageChange={pagination.onPageChange}\n onPageSizeChange={pagination.onPageSizeChange}\n pageSizeOptions={pagination.pageSizeOptions}\n showPageSizeSelector={pagination.showPageSizeSelector}\n showJumpToPage={pagination.showJumpToPage}\n showTotal={pagination.showTotal}\n searchActive={isSearchActive}\n />\n </CardFooter>\n )}\n </Card>\n );\n\n // 默认的表格渲染\n const defaultRenderTable = (tableHeader: ReactNode, tableBody: ReactNode) => (\n <Table>\n {tableHeader}\n {tableBody}\n </Table>\n );\n\n return renderCard\n ? renderCard(\n renderTable\n ? renderTable(renderTableHeader(), renderTableBody())\n : defaultRenderTable(renderTableHeader(), renderTableBody())\n )\n : defaultRenderCard(\n renderTable\n ? renderTable(renderTableHeader(), renderTableBody())\n : defaultRenderTable(renderTableHeader(), renderTableBody())\n );\n}\n"],"names":["DataTable","data","loading","columns","rowKey","emptyText","searchActiveEmptyText","header","pagination","rowClassName","onRow","actions","components","renderCard","renderTable","renderActions","jsxs","jsx","Card","CardContent","CardFooter","Table","TableBody","TableCell","TableHead","TableHeader","TableRow","Button","DropdownMenu","DropdownMenuTrigger","DropdownMenuContent","DropdownMenuItem","DropdownMenuSeparator","Skeleton","TableHeaderComponent","TablePaginationComponent","getRowKey","record","index","keyVal","isSearchActive","hasActions","_a","actionMode","_b","isSeparatorItem","item","defaultRenderActions","MoreVertical","itemIndex","renderTableHeader","column","renderTableBody","_","key","rowProps","className","value","content","defaultRenderCard","defaultRenderTable","tableHeader","tableBody"],"mappings":"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"}
1
+ {"version":3,"file":"data-table.cjs","sources":["../src/components/DataTable.tsx"],"sourcesContent":["import { MoreVertical } from 'lucide-react';\nimport { ReactNode } from 'react';\nimport type {\n HTMLAttributes,\n ButtonHTMLAttributes,\n MouseEvent,\n} from 'react';\n\nimport type {\n UIComponent,\n ButtonComponent,\n CardComponent,\n TableComponent,\n TableRowComponent,\n TableCellComponent,\n} from '../types/component-types';\n\nimport type { TableHeaderProps } from './TableHeader';\nimport type { TablePaginationProps } from './TablePagination';\n\ntype ColumnKey<T> = Extract<keyof T, string>;\n\ntype ActionMenuItem<T> = {\n label: ReactNode;\n icon?: ReactNode;\n onClick: (record: T, index: number) => void;\n className?: string;\n separator?: never;\n};\n\ntype ActionSeparatorItem = {\n separator: true;\n className?: string;\n label?: never;\n icon?: never;\n onClick?: never;\n};\n\ntype ActionItem<T> = ActionMenuItem<T> | ActionSeparatorItem;\n\nexport interface Column<T = unknown> {\n key: ColumnKey<T>;\n title: ReactNode;\n render?: (value: T[ColumnKey<T>], record: T, index: number) => ReactNode;\n width?: string;\n align?: 'left' | 'center' | 'right';\n}\n\n/**\n * UI 组件适配器接口\n * 业务项目应该传入自己项目中的 shadcn/ui 组件\n */\nexport interface UIComponents {\n Card: CardComponent;\n CardContent: UIComponent<HTMLAttributes<HTMLDivElement>>;\n CardFooter: UIComponent<HTMLAttributes<HTMLDivElement>>;\n Table: TableComponent;\n TableBody: UIComponent<HTMLAttributes<HTMLTableSectionElement>>;\n TableCell: TableCellComponent;\n TableHead: TableCellComponent;\n TableHeader: UIComponent<HTMLAttributes<HTMLTableSectionElement>>;\n TableRow: TableRowComponent;\n Button: ButtonComponent;\n DropdownMenu: UIComponent<HTMLAttributes<HTMLDivElement>>;\n DropdownMenuTrigger: ButtonComponent;\n DropdownMenuContent: UIComponent<\n HTMLAttributes<HTMLDivElement> & { align?: 'start' | 'end' | 'center' }\n >;\n DropdownMenuItem: UIComponent<\n ButtonHTMLAttributes<HTMLDivElement> & {\n onClick?: (e: MouseEvent) => void;\n }\n >;\n DropdownMenuSeparator: UIComponent;\n Skeleton: UIComponent<HTMLAttributes<HTMLDivElement>>;\n TableHeaderComponent: React.ComponentType<TableHeaderProps>;\n TablePaginationComponent: React.ComponentType<TablePaginationProps>;\n}\n\nexport interface DataTableProps<T = unknown> {\n // 数据相关\n data: T[];\n loading?: boolean;\n columns: Column<T>[];\n rowKey: keyof T | ((record: T) => string);\n\n // 空状态\n emptyText?: string;\n searchActiveEmptyText?: string;\n\n // 头部配置\n header?: TableHeaderProps;\n\n // 分页配置\n pagination?: TablePaginationProps & {\n show?: boolean;\n };\n\n // 表格行样式\n rowClassName?: (record: T, index: number) => string;\n onRow?: (\n record: T,\n index: number\n ) => {\n onClick?: () => void;\n onDoubleClick?: () => void;\n };\n\n // 操作列\n actions?: {\n title?: string;\n mode?: 'expanded' | 'collapsed';\n render?: (record: T, index: number) => ReactNode;\n items?: ActionItem<T>[];\n };\n\n // UI 组件注入(可选)\n components?: UIComponents;\n\n // 自定义渲染函数(更灵活)\n renderCard?: (content: ReactNode) => ReactNode;\n renderTable?: (header: ReactNode, body: ReactNode) => ReactNode;\n renderActions?: (record: T, index: number) => ReactNode;\n}\n\n/**\n * 默认的 DataTable 实现\n * 需要通过 components prop 注入 UI 组件\n */\nexport function DataTable<T extends Record<string, any>>({\n data,\n loading = false,\n columns,\n rowKey,\n emptyText = '暂无数据',\n searchActiveEmptyText = '未找到匹配的记录',\n header,\n pagination,\n rowClassName,\n onRow,\n actions,\n components,\n renderCard,\n renderTable,\n renderActions,\n}: DataTableProps<T>) {\n if (!components) {\n return (\n <div className=\"p-4 text-center text-destructive\">\n 错误:请通过 components prop 注入 UI 组件\n <br />\n <code className=\"text-sm\">\n {'import { Card, Table, Button, ... } from \"@/components/ui\"'}\n </code>\n </div>\n );\n }\n\n const {\n Card,\n CardContent,\n CardFooter,\n Table,\n TableBody,\n TableCell,\n TableHead,\n TableHeader,\n TableRow,\n Button,\n DropdownMenu,\n DropdownMenuTrigger,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuSeparator,\n Skeleton,\n TableHeaderComponent,\n TablePaginationComponent,\n } = components;\n\n // 获取行的唯一标识\n const getRowKey = (record: T, index: number): string => {\n if (typeof rowKey === 'function') {\n return rowKey(record);\n }\n const keyVal = record[rowKey];\n return keyVal !== undefined && keyVal !== null\n ? String(keyVal)\n : `row-${index}`;\n };\n\n // 检查是否有搜索活动\n const isSearchActive = Boolean(\n header?.searchValue && header.searchValue.trim().length > 0\n );\n const hasActions = Boolean(actions?.render || actions?.items?.length);\n const actionMode: 'expanded' | 'collapsed' =\n actions?.mode ?? (actions?.items?.length ? 'collapsed' : 'expanded');\n const isSeparatorItem = (item: ActionItem<T>): item is ActionSeparatorItem =>\n item.separator === true;\n\n // 渲染操作列\n const defaultRenderActions = (record: T, index: number) => {\n if (!actions || !hasActions) return null;\n\n // 折叠模式:使用 DropdownMenu\n if (\n actionMode === 'collapsed' &&\n actions.items &&\n actions.items.length > 0\n ) {\n return (\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button\n variant=\"ghost\"\n className=\"h-8 w-8 p-0\"\n aria-label=\"打开行操作菜单\"\n onClick={(event) => event.stopPropagation()}\n >\n <MoreVertical className=\"h-4 w-4\" />\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\">\n {actions.items.map((item, itemIndex) =>\n isSeparatorItem(item) ? (\n <DropdownMenuSeparator key={`separator-${itemIndex}`} />\n ) : (\n <DropdownMenuItem\n key={`action-${itemIndex}`}\n onClick={(event) => {\n event.stopPropagation();\n item.onClick(record, index);\n }}\n className={item.className}\n >\n {item.icon && (\n <span className=\"mr-2 h-4 w-4\">{item.icon}</span>\n )}\n {item.label}\n </DropdownMenuItem>\n )\n )}\n </DropdownMenuContent>\n </DropdownMenu>\n );\n }\n\n // 展开模式:使用自定义 render\n return actions.render ? actions.render(record, index) : null;\n };\n\n // 渲染表头\n const renderTableHeader = () => {\n return (\n <TableHeader>\n <TableRow className=\"bg-muted/50 hover:bg-muted/50\">\n {columns.map((column) => (\n <TableHead\n key={String(column.key)}\n className={`font-semibold text-foreground ${\n column.align === 'center'\n ? 'text-center'\n : column.align === 'right'\n ? 'text-right'\n : 'text-left'\n }`}\n style={{ width: column.width }}\n >\n {column.title}\n </TableHead>\n ))}\n {hasActions && (\n <TableHead className=\"text-right font-semibold text-foreground\">\n {actions?.title || '操作'}\n </TableHead>\n )}\n </TableRow>\n </TableHeader>\n );\n };\n\n // 渲染表体\n const renderTableBody = () => {\n // Loading 状态\n if (loading) {\n return (\n <TableBody>\n {Array.from({ length: 5 }).map((_, index) => (\n <TableRow key={index}>\n {columns.map((column) => (\n <TableCell\n key={String(column.key)}\n style={{ width: column.width }}\n className={\n column.align === 'center'\n ? 'text-center'\n : column.align === 'right'\n ? 'text-right'\n : ''\n }\n >\n <Skeleton className=\"h-4 w-full\" />\n </TableCell>\n ))}\n {hasActions && (\n <TableCell>\n <Skeleton className=\"ml-auto h-4 w-8\" />\n </TableCell>\n )}\n </TableRow>\n ))}\n </TableBody>\n );\n }\n\n // 空数据状态\n if (data.length === 0) {\n return (\n <TableBody>\n <TableRow>\n <TableCell\n colSpan={columns.length + (hasActions ? 1 : 0)}\n className=\"py-8 text-center text-muted-foreground\"\n >\n {isSearchActive ? searchActiveEmptyText : emptyText}\n </TableCell>\n </TableRow>\n </TableBody>\n );\n }\n\n // 数据行\n return (\n <TableBody>\n {data.map((record, index) => {\n const key = getRowKey(record, index);\n const rowProps = onRow?.(record, index);\n const className = rowClassName?.(record, index);\n\n return (\n <TableRow\n key={key}\n className={`${className || ''} hover:bg-muted/50`}\n {...rowProps}\n >\n {columns.map((column) => {\n const value = record[column.key as keyof T];\n const content = column.render\n ? column.render(value as T[ColumnKey<T>], record, index)\n : value;\n\n return (\n <TableCell\n key={String(column.key)}\n className={\n column.align === 'center'\n ? 'text-center'\n : column.align === 'right'\n ? 'text-right'\n : ''\n }\n >\n {content}\n </TableCell>\n );\n })}\n {hasActions && (\n <TableCell\n className=\"text-right\"\n onClick={(event) => event.stopPropagation()}\n >\n {renderActions\n ? renderActions(record, index)\n : defaultRenderActions(record, index)}\n </TableCell>\n )}\n </TableRow>\n );\n })}\n </TableBody>\n );\n };\n\n // 默认的卡片渲染\n const defaultRenderCard = (content: ReactNode) => (\n <Card>\n {header && (\n <div className=\"p-6 pb-0\">\n <TableHeaderComponent {...header} />\n </div>\n )}\n <CardContent className=\"p-0\">{content}</CardContent>\n {pagination?.show !== false && pagination && (\n <CardFooter className=\"border-t py-4\">\n <TablePaginationComponent\n currentPage={pagination.currentPage}\n pageSize={pagination.pageSize}\n total={pagination.total}\n onPageChange={pagination.onPageChange}\n onPageSizeChange={pagination.onPageSizeChange}\n pageSizeOptions={pagination.pageSizeOptions}\n showPageSizeSelector={pagination.showPageSizeSelector}\n showJumpToPage={pagination.showJumpToPage}\n showTotal={pagination.showTotal}\n searchActive={isSearchActive}\n />\n </CardFooter>\n )}\n </Card>\n );\n\n // 默认的表格渲染\n const defaultRenderTable = (tableHeader: ReactNode, tableBody: ReactNode) => (\n <Table>\n {tableHeader}\n {tableBody}\n </Table>\n );\n\n return renderCard\n ? renderCard(\n renderTable\n ? renderTable(renderTableHeader(), renderTableBody())\n : defaultRenderTable(renderTableHeader(), renderTableBody())\n )\n : defaultRenderCard(\n renderTable\n ? renderTable(renderTableHeader(), renderTableBody())\n : defaultRenderTable(renderTableHeader(), renderTableBody())\n );\n}\n"],"names":["DataTable","data","loading","columns","rowKey","emptyText","searchActiveEmptyText","header","pagination","rowClassName","onRow","actions","components","renderCard","renderTable","renderActions","jsxs","jsx","Card","CardContent","CardFooter","Table","TableBody","TableCell","TableHead","TableHeader","TableRow","Button","DropdownMenu","DropdownMenuTrigger","DropdownMenuContent","DropdownMenuItem","DropdownMenuSeparator","Skeleton","TableHeaderComponent","TablePaginationComponent","getRowKey","record","index","keyVal","isSearchActive","hasActions","_a","actionMode","_b","isSeparatorItem","item","defaultRenderActions","event","MoreVertical","itemIndex","renderTableHeader","column","renderTableBody","_","key","rowProps","className","value","content","defaultRenderCard","defaultRenderTable","tableHeader","tableBody"],"mappings":"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"}
@@ -1,80 +1,83 @@
1
1
  import { j as e } from "./jsx-runtime-B4hRZ52C.js";
2
2
  import { MoreVertical as ee } from "lucide-react";
3
3
  function le({
4
- data: S,
5
- loading: B = !1,
6
- columns: x,
7
- rowKey: m,
8
- emptyText: D = "暂无数据",
9
- searchActiveEmptyText: $ = "未找到匹配的记录",
10
- header: a,
4
+ data: N,
5
+ loading: D = !1,
6
+ columns: c,
7
+ rowKey: u,
8
+ emptyText: $ = "暂无数据",
9
+ searchActiveEmptyText: A = "未找到匹配的记录",
10
+ header: h,
11
11
  pagination: n,
12
- rowClassName: p,
12
+ rowClassName: m,
13
13
  onRow: f,
14
14
  actions: r,
15
- components: N,
16
- renderCard: w,
17
- renderTable: g,
15
+ components: w,
16
+ renderCard: P,
17
+ renderTable: x,
18
18
  renderActions: T
19
19
  }) {
20
- var k, z;
21
- if (!N)
20
+ var z, M;
21
+ if (!w)
22
22
  return /* @__PURE__ */ e.jsxs("div", { className: "p-4 text-center text-destructive", children: [
23
23
  "错误:请通过 components prop 注入 UI 组件",
24
24
  /* @__PURE__ */ e.jsx("br", {}),
25
25
  /* @__PURE__ */ e.jsx("code", { className: "text-sm", children: 'import { Card, Table, Button, ... } from "@/components/ui"' })
26
26
  ] });
27
27
  const {
28
- Card: A,
29
- CardContent: H,
30
- CardFooter: V,
31
- Table: I,
28
+ Card: H,
29
+ CardContent: V,
30
+ CardFooter: I,
31
+ Table: J,
32
32
  TableBody: b,
33
33
  TableCell: d,
34
- TableHead: y,
35
- TableHeader: J,
36
- TableRow: o,
37
- Button: O,
38
- DropdownMenu: R,
39
- DropdownMenuTrigger: E,
40
- DropdownMenuContent: F,
41
- DropdownMenuItem: U,
42
- DropdownMenuSeparator: _,
43
- Skeleton: C,
44
- TableHeaderComponent: q,
45
- TablePaginationComponent: G
46
- } = N, L = (t, s) => {
47
- if (typeof m == "function")
48
- return m(t);
49
- const l = t[m];
34
+ TableHead: C,
35
+ TableHeader: O,
36
+ TableRow: g,
37
+ Button: R,
38
+ DropdownMenu: E,
39
+ DropdownMenuTrigger: F,
40
+ DropdownMenuContent: U,
41
+ DropdownMenuItem: _,
42
+ DropdownMenuSeparator: q,
43
+ Skeleton: y,
44
+ TableHeaderComponent: G,
45
+ TablePaginationComponent: L
46
+ } = w, Q = (t, s) => {
47
+ if (typeof u == "function")
48
+ return u(t);
49
+ const l = t[u];
50
50
  return l != null ? String(l) : `row-${s}`;
51
- }, P = !!(a != null && a.searchValue && a.searchValue.trim().length > 0), c = !!(r != null && r.render || (k = r == null ? void 0 : r.items) != null && k.length), Q = (r == null ? void 0 : r.mode) ?? ((z = r == null ? void 0 : r.items) != null && z.length ? "collapsed" : "expanded"), W = (t) => t.separator === !0, X = (t, s) => !r || !c ? null : Q === "collapsed" && r.items && r.items.length > 0 ? /* @__PURE__ */ e.jsxs(R, { children: [
52
- /* @__PURE__ */ e.jsx(E, { asChild: !0, children: /* @__PURE__ */ e.jsx(
53
- O,
51
+ }, k = !!(h != null && h.searchValue && h.searchValue.trim().length > 0), o = !!(r != null && r.render || (z = r == null ? void 0 : r.items) != null && z.length), W = (r == null ? void 0 : r.mode) ?? ((M = r == null ? void 0 : r.items) != null && M.length ? "collapsed" : "expanded"), X = (t) => t.separator === !0, Y = (t, s) => !r || !o ? null : W === "collapsed" && r.items && r.items.length > 0 ? /* @__PURE__ */ e.jsxs(E, { children: [
52
+ /* @__PURE__ */ e.jsx(F, { asChild: !0, children: /* @__PURE__ */ e.jsx(
53
+ R,
54
54
  {
55
55
  variant: "ghost",
56
56
  className: "h-8 w-8 p-0",
57
57
  "aria-label": "打开行操作菜单",
58
+ onClick: (l) => l.stopPropagation(),
58
59
  children: /* @__PURE__ */ e.jsx(ee, { className: "h-4 w-4" })
59
60
  }
60
61
  ) }),
61
- /* @__PURE__ */ e.jsx(F, { align: "end", children: r.items.map(
62
- (l, u) => W(l) ? /* @__PURE__ */ e.jsx(_, {}, `separator-${u}`) : /* @__PURE__ */ e.jsxs(
63
- U,
62
+ /* @__PURE__ */ e.jsx(U, { align: "end", children: r.items.map(
63
+ (l, j) => X(l) ? /* @__PURE__ */ e.jsx(q, {}, `separator-${j}`) : /* @__PURE__ */ e.jsxs(
64
+ _,
64
65
  {
65
- onClick: () => l.onClick(t, s),
66
+ onClick: (S) => {
67
+ S.stopPropagation(), l.onClick(t, s);
68
+ },
66
69
  className: l.className,
67
70
  children: [
68
71
  l.icon && /* @__PURE__ */ e.jsx("span", { className: "mr-2 h-4 w-4", children: l.icon }),
69
72
  l.label
70
73
  ]
71
74
  },
72
- `action-${u}`
75
+ `action-${j}`
73
76
  )
74
77
  ) })
75
- ] }) : r.render ? r.render(t, s) : null, j = () => /* @__PURE__ */ e.jsx(J, { children: /* @__PURE__ */ e.jsxs(o, { className: "bg-muted/50 hover:bg-muted/50", children: [
76
- x.map((t) => /* @__PURE__ */ e.jsx(
77
- y,
78
+ ] }) : r.render ? r.render(t, s) : null, i = () => /* @__PURE__ */ e.jsx(O, { children: /* @__PURE__ */ e.jsxs(g, { className: "bg-muted/50 hover:bg-muted/50", children: [
79
+ c.map((t) => /* @__PURE__ */ e.jsx(
80
+ C,
78
81
  {
79
82
  className: `font-semibold text-foreground ${t.align === "center" ? "text-center" : t.align === "right" ? "text-right" : "text-left"}`,
80
83
  style: { width: t.width },
@@ -82,54 +85,61 @@ function le({
82
85
  },
83
86
  String(t.key)
84
87
  )),
85
- c && /* @__PURE__ */ e.jsx(y, { className: "text-right font-semibold text-foreground", children: (r == null ? void 0 : r.title) || "操作" })
86
- ] }) }), i = () => B ? /* @__PURE__ */ e.jsx(b, { children: Array.from({ length: 5 }).map((t, s) => /* @__PURE__ */ e.jsxs(o, { children: [
87
- x.map((l) => /* @__PURE__ */ e.jsx(
88
+ o && /* @__PURE__ */ e.jsx(C, { className: "text-right font-semibold text-foreground", children: (r == null ? void 0 : r.title) || "操作" })
89
+ ] }) }), p = () => D ? /* @__PURE__ */ e.jsx(b, { children: Array.from({ length: 5 }).map((t, s) => /* @__PURE__ */ e.jsxs(g, { children: [
90
+ c.map((l) => /* @__PURE__ */ e.jsx(
88
91
  d,
89
92
  {
90
93
  style: { width: l.width },
91
94
  className: l.align === "center" ? "text-center" : l.align === "right" ? "text-right" : "",
92
- children: /* @__PURE__ */ e.jsx(C, { className: "h-4 w-full" })
95
+ children: /* @__PURE__ */ e.jsx(y, { className: "h-4 w-full" })
93
96
  },
94
97
  String(l.key)
95
98
  )),
96
- c && /* @__PURE__ */ e.jsx(d, { children: /* @__PURE__ */ e.jsx(C, { className: "ml-auto h-4 w-8" }) })
97
- ] }, s)) }) : S.length === 0 ? /* @__PURE__ */ e.jsx(b, { children: /* @__PURE__ */ e.jsx(o, { children: /* @__PURE__ */ e.jsx(
99
+ o && /* @__PURE__ */ e.jsx(d, { children: /* @__PURE__ */ e.jsx(y, { className: "ml-auto h-4 w-8" }) })
100
+ ] }, s)) }) : N.length === 0 ? /* @__PURE__ */ e.jsx(b, { children: /* @__PURE__ */ e.jsx(g, { children: /* @__PURE__ */ e.jsx(
98
101
  d,
99
102
  {
100
- colSpan: x.length + (c ? 1 : 0),
103
+ colSpan: c.length + (o ? 1 : 0),
101
104
  className: "py-8 text-center text-muted-foreground",
102
- children: P ? $ : D
105
+ children: k ? A : $
103
106
  }
104
- ) }) }) : /* @__PURE__ */ e.jsx(b, { children: S.map((t, s) => {
105
- const l = L(t, s), u = f == null ? void 0 : f(t, s), Z = p == null ? void 0 : p(t, s);
107
+ ) }) }) : /* @__PURE__ */ e.jsx(b, { children: N.map((t, s) => {
108
+ const l = Q(t, s), j = f == null ? void 0 : f(t, s), S = m == null ? void 0 : m(t, s);
106
109
  return /* @__PURE__ */ e.jsxs(
107
- o,
110
+ g,
108
111
  {
109
- className: `${Z || ""} hover:bg-muted/50`,
110
- ...u,
112
+ className: `${S || ""} hover:bg-muted/50`,
113
+ ...j,
111
114
  children: [
112
- x.map((h) => {
113
- const M = t[h.key], K = h.render ? h.render(M, t, s) : M;
115
+ c.map((a) => {
116
+ const B = t[a.key], K = a.render ? a.render(B, t, s) : B;
114
117
  return /* @__PURE__ */ e.jsx(
115
118
  d,
116
119
  {
117
- className: h.align === "center" ? "text-center" : h.align === "right" ? "text-right" : "",
120
+ className: a.align === "center" ? "text-center" : a.align === "right" ? "text-right" : "",
118
121
  children: K
119
122
  },
120
- String(h.key)
123
+ String(a.key)
121
124
  );
122
125
  }),
123
- c && /* @__PURE__ */ e.jsx(d, { className: "text-right", children: T ? T(t, s) : X(t, s) })
126
+ o && /* @__PURE__ */ e.jsx(
127
+ d,
128
+ {
129
+ className: "text-right",
130
+ onClick: (a) => a.stopPropagation(),
131
+ children: T ? T(t, s) : Y(t, s)
132
+ }
133
+ )
124
134
  ]
125
135
  },
126
136
  l
127
137
  );
128
- }) }), Y = (t) => /* @__PURE__ */ e.jsxs(A, { children: [
129
- a && /* @__PURE__ */ e.jsx("div", { className: "p-6 pb-0", children: /* @__PURE__ */ e.jsx(q, { ...a }) }),
130
- /* @__PURE__ */ e.jsx(H, { className: "p-0", children: t }),
131
- (n == null ? void 0 : n.show) !== !1 && n && /* @__PURE__ */ e.jsx(V, { className: "border-t py-4", children: /* @__PURE__ */ e.jsx(
132
- G,
138
+ }) }), Z = (t) => /* @__PURE__ */ e.jsxs(H, { children: [
139
+ h && /* @__PURE__ */ e.jsx("div", { className: "p-6 pb-0", children: /* @__PURE__ */ e.jsx(G, { ...h }) }),
140
+ /* @__PURE__ */ e.jsx(V, { className: "p-0", children: t }),
141
+ (n == null ? void 0 : n.show) !== !1 && n && /* @__PURE__ */ e.jsx(I, { className: "border-t py-4", children: /* @__PURE__ */ e.jsx(
142
+ L,
133
143
  {
134
144
  currentPage: n.currentPage,
135
145
  pageSize: n.pageSize,
@@ -140,17 +150,17 @@ function le({
140
150
  showPageSizeSelector: n.showPageSizeSelector,
141
151
  showJumpToPage: n.showJumpToPage,
142
152
  showTotal: n.showTotal,
143
- searchActive: P
153
+ searchActive: k
144
154
  }
145
155
  ) })
146
- ] }), v = (t, s) => /* @__PURE__ */ e.jsxs(I, { children: [
156
+ ] }), v = (t, s) => /* @__PURE__ */ e.jsxs(J, { children: [
147
157
  t,
148
158
  s
149
159
  ] });
150
- return w ? w(
151
- g ? g(j(), i()) : v(j(), i())
152
- ) : Y(
153
- g ? g(j(), i()) : v(j(), i())
160
+ return P ? P(
161
+ x ? x(i(), p()) : v(i(), p())
162
+ ) : Z(
163
+ x ? x(i(), p()) : v(i(), p())
154
164
  );
155
165
  }
156
166
  export {
@@ -1 +1 @@
1
- {"version":3,"file":"data-table.js","sources":["../src/components/DataTable.tsx"],"sourcesContent":["import { MoreVertical } from 'lucide-react';\nimport { ReactNode } from 'react';\nimport type { HTMLAttributes, ButtonHTMLAttributes } from 'react';\n\nimport type {\n UIComponent,\n ButtonComponent,\n CardComponent,\n TableComponent,\n TableRowComponent,\n TableCellComponent,\n} from '../types/component-types';\n\nimport type { TableHeaderProps } from './TableHeader';\nimport type { TablePaginationProps } from './TablePagination';\n\ntype ColumnKey<T> = Extract<keyof T, string>;\n\ntype ActionMenuItem<T> = {\n label: ReactNode;\n icon?: ReactNode;\n onClick: (record: T, index: number) => void;\n className?: string;\n separator?: never;\n};\n\ntype ActionSeparatorItem = {\n separator: true;\n className?: string;\n label?: never;\n icon?: never;\n onClick?: never;\n};\n\ntype ActionItem<T> = ActionMenuItem<T> | ActionSeparatorItem;\n\nexport interface Column<T = unknown> {\n key: ColumnKey<T>;\n title: ReactNode;\n render?: (value: T[ColumnKey<T>], record: T, index: number) => ReactNode;\n width?: string;\n align?: 'left' | 'center' | 'right';\n}\n\n/**\n * UI 组件适配器接口\n * 业务项目应该传入自己项目中的 shadcn/ui 组件\n */\nexport interface UIComponents {\n Card: CardComponent;\n CardContent: UIComponent<HTMLAttributes<HTMLDivElement>>;\n CardFooter: UIComponent<HTMLAttributes<HTMLDivElement>>;\n Table: TableComponent;\n TableBody: UIComponent<HTMLAttributes<HTMLTableSectionElement>>;\n TableCell: TableCellComponent;\n TableHead: TableCellComponent;\n TableHeader: UIComponent<HTMLAttributes<HTMLTableSectionElement>>;\n TableRow: TableRowComponent;\n Button: ButtonComponent;\n DropdownMenu: UIComponent<HTMLAttributes<HTMLDivElement>>;\n DropdownMenuTrigger: ButtonComponent;\n DropdownMenuContent: UIComponent<\n HTMLAttributes<HTMLDivElement> & { align?: 'start' | 'end' | 'center' }\n >;\n DropdownMenuItem: UIComponent<\n ButtonHTMLAttributes<HTMLDivElement> & {\n onClick?: (e: React.MouseEvent) => void;\n }\n >;\n DropdownMenuSeparator: UIComponent;\n Skeleton: UIComponent<HTMLAttributes<HTMLDivElement>>;\n TableHeaderComponent: React.ComponentType<TableHeaderProps>;\n TablePaginationComponent: React.ComponentType<TablePaginationProps>;\n}\n\nexport interface DataTableProps<T = unknown> {\n // 数据相关\n data: T[];\n loading?: boolean;\n columns: Column<T>[];\n rowKey: keyof T | ((record: T) => string);\n\n // 空状态\n emptyText?: string;\n searchActiveEmptyText?: string;\n\n // 头部配置\n header?: TableHeaderProps;\n\n // 分页配置\n pagination?: TablePaginationProps & {\n show?: boolean;\n };\n\n // 表格行样式\n rowClassName?: (record: T, index: number) => string;\n onRow?: (\n record: T,\n index: number\n ) => {\n onClick?: () => void;\n onDoubleClick?: () => void;\n };\n\n // 操作列\n actions?: {\n title?: string;\n mode?: 'expanded' | 'collapsed';\n render?: (record: T, index: number) => ReactNode;\n items?: ActionItem<T>[];\n };\n\n // UI 组件注入(可选)\n components?: UIComponents;\n\n // 自定义渲染函数(更灵活)\n renderCard?: (content: ReactNode) => ReactNode;\n renderTable?: (header: ReactNode, body: ReactNode) => ReactNode;\n renderActions?: (record: T, index: number) => ReactNode;\n}\n\n/**\n * 默认的 DataTable 实现\n * 需要通过 components prop 注入 UI 组件\n */\nexport function DataTable<T extends Record<string, any>>({\n data,\n loading = false,\n columns,\n rowKey,\n emptyText = '暂无数据',\n searchActiveEmptyText = '未找到匹配的记录',\n header,\n pagination,\n rowClassName,\n onRow,\n actions,\n components,\n renderCard,\n renderTable,\n renderActions,\n}: DataTableProps<T>) {\n if (!components) {\n return (\n <div className=\"p-4 text-center text-destructive\">\n 错误:请通过 components prop 注入 UI 组件\n <br />\n <code className=\"text-sm\">\n {'import { Card, Table, Button, ... } from \"@/components/ui\"'}\n </code>\n </div>\n );\n }\n\n const {\n Card,\n CardContent,\n CardFooter,\n Table,\n TableBody,\n TableCell,\n TableHead,\n TableHeader,\n TableRow,\n Button,\n DropdownMenu,\n DropdownMenuTrigger,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuSeparator,\n Skeleton,\n TableHeaderComponent,\n TablePaginationComponent,\n } = components;\n\n // 获取行的唯一标识\n const getRowKey = (record: T, index: number): string => {\n if (typeof rowKey === 'function') {\n return rowKey(record);\n }\n const keyVal = record[rowKey];\n return keyVal !== undefined && keyVal !== null\n ? String(keyVal)\n : `row-${index}`;\n };\n\n // 检查是否有搜索活动\n const isSearchActive = Boolean(\n header?.searchValue && header.searchValue.trim().length > 0\n );\n const hasActions = Boolean(actions?.render || actions?.items?.length);\n const actionMode: 'expanded' | 'collapsed' =\n actions?.mode ?? (actions?.items?.length ? 'collapsed' : 'expanded');\n const isSeparatorItem = (item: ActionItem<T>): item is ActionSeparatorItem =>\n item.separator === true;\n\n // 渲染操作列\n const defaultRenderActions = (record: T, index: number) => {\n if (!actions || !hasActions) return null;\n\n // 折叠模式:使用 DropdownMenu\n if (\n actionMode === 'collapsed' &&\n actions.items &&\n actions.items.length > 0\n ) {\n return (\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button\n variant=\"ghost\"\n className=\"h-8 w-8 p-0\"\n aria-label=\"打开行操作菜单\"\n >\n <MoreVertical className=\"h-4 w-4\" />\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\">\n {actions.items.map((item, itemIndex) =>\n isSeparatorItem(item) ? (\n <DropdownMenuSeparator key={`separator-${itemIndex}`} />\n ) : (\n <DropdownMenuItem\n key={`action-${itemIndex}`}\n onClick={() => item.onClick(record, index)}\n className={item.className}\n >\n {item.icon && (\n <span className=\"mr-2 h-4 w-4\">{item.icon}</span>\n )}\n {item.label}\n </DropdownMenuItem>\n )\n )}\n </DropdownMenuContent>\n </DropdownMenu>\n );\n }\n\n // 展开模式:使用自定义 render\n return actions.render ? actions.render(record, index) : null;\n };\n\n // 渲染表头\n const renderTableHeader = () => {\n return (\n <TableHeader>\n <TableRow className=\"bg-muted/50 hover:bg-muted/50\">\n {columns.map((column) => (\n <TableHead\n key={String(column.key)}\n className={`font-semibold text-foreground ${\n column.align === 'center'\n ? 'text-center'\n : column.align === 'right'\n ? 'text-right'\n : 'text-left'\n }`}\n style={{ width: column.width }}\n >\n {column.title}\n </TableHead>\n ))}\n {hasActions && (\n <TableHead className=\"text-right font-semibold text-foreground\">\n {actions?.title || '操作'}\n </TableHead>\n )}\n </TableRow>\n </TableHeader>\n );\n };\n\n // 渲染表体\n const renderTableBody = () => {\n // Loading 状态\n if (loading) {\n return (\n <TableBody>\n {Array.from({ length: 5 }).map((_, index) => (\n <TableRow key={index}>\n {columns.map((column) => (\n <TableCell\n key={String(column.key)}\n style={{ width: column.width }}\n className={\n column.align === 'center'\n ? 'text-center'\n : column.align === 'right'\n ? 'text-right'\n : ''\n }\n >\n <Skeleton className=\"h-4 w-full\" />\n </TableCell>\n ))}\n {hasActions && (\n <TableCell>\n <Skeleton className=\"ml-auto h-4 w-8\" />\n </TableCell>\n )}\n </TableRow>\n ))}\n </TableBody>\n );\n }\n\n // 空数据状态\n if (data.length === 0) {\n return (\n <TableBody>\n <TableRow>\n <TableCell\n colSpan={columns.length + (hasActions ? 1 : 0)}\n className=\"py-8 text-center text-muted-foreground\"\n >\n {isSearchActive ? searchActiveEmptyText : emptyText}\n </TableCell>\n </TableRow>\n </TableBody>\n );\n }\n\n // 数据行\n return (\n <TableBody>\n {data.map((record, index) => {\n const key = getRowKey(record, index);\n const rowProps = onRow?.(record, index);\n const className = rowClassName?.(record, index);\n\n return (\n <TableRow\n key={key}\n className={`${className || ''} hover:bg-muted/50`}\n {...rowProps}\n >\n {columns.map((column) => {\n const value = record[column.key as keyof T];\n const content = column.render\n ? column.render(value as T[ColumnKey<T>], record, index)\n : value;\n\n return (\n <TableCell\n key={String(column.key)}\n className={\n column.align === 'center'\n ? 'text-center'\n : column.align === 'right'\n ? 'text-right'\n : ''\n }\n >\n {content}\n </TableCell>\n );\n })}\n {hasActions && (\n <TableCell className=\"text-right\">\n {renderActions\n ? renderActions(record, index)\n : defaultRenderActions(record, index)}\n </TableCell>\n )}\n </TableRow>\n );\n })}\n </TableBody>\n );\n };\n\n // 默认的卡片渲染\n const defaultRenderCard = (content: ReactNode) => (\n <Card>\n {header && (\n <div className=\"p-6 pb-0\">\n <TableHeaderComponent {...header} />\n </div>\n )}\n <CardContent className=\"p-0\">{content}</CardContent>\n {pagination?.show !== false && pagination && (\n <CardFooter className=\"border-t py-4\">\n <TablePaginationComponent\n currentPage={pagination.currentPage}\n pageSize={pagination.pageSize}\n total={pagination.total}\n onPageChange={pagination.onPageChange}\n onPageSizeChange={pagination.onPageSizeChange}\n pageSizeOptions={pagination.pageSizeOptions}\n showPageSizeSelector={pagination.showPageSizeSelector}\n showJumpToPage={pagination.showJumpToPage}\n showTotal={pagination.showTotal}\n searchActive={isSearchActive}\n />\n </CardFooter>\n )}\n </Card>\n );\n\n // 默认的表格渲染\n const defaultRenderTable = (tableHeader: ReactNode, tableBody: ReactNode) => (\n <Table>\n {tableHeader}\n {tableBody}\n </Table>\n );\n\n return renderCard\n ? renderCard(\n renderTable\n ? renderTable(renderTableHeader(), renderTableBody())\n : defaultRenderTable(renderTableHeader(), renderTableBody())\n )\n : defaultRenderCard(\n renderTable\n ? renderTable(renderTableHeader(), renderTableBody())\n : defaultRenderTable(renderTableHeader(), renderTableBody())\n );\n}\n"],"names":["DataTable","data","loading","columns","rowKey","emptyText","searchActiveEmptyText","header","pagination","rowClassName","onRow","actions","components","renderCard","renderTable","renderActions","jsxs","jsx","Card","CardContent","CardFooter","Table","TableBody","TableCell","TableHead","TableHeader","TableRow","Button","DropdownMenu","DropdownMenuTrigger","DropdownMenuContent","DropdownMenuItem","DropdownMenuSeparator","Skeleton","TableHeaderComponent","TablePaginationComponent","getRowKey","record","index","keyVal","isSearchActive","hasActions","_a","actionMode","_b","isSeparatorItem","item","defaultRenderActions","MoreVertical","itemIndex","renderTableHeader","column","renderTableBody","_","key","rowProps","className","value","content","defaultRenderCard","defaultRenderTable","tableHeader","tableBody"],"mappings":"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"}
1
+ {"version":3,"file":"data-table.js","sources":["../src/components/DataTable.tsx"],"sourcesContent":["import { MoreVertical } from 'lucide-react';\nimport { ReactNode } from 'react';\nimport type {\n HTMLAttributes,\n ButtonHTMLAttributes,\n MouseEvent,\n} from 'react';\n\nimport type {\n UIComponent,\n ButtonComponent,\n CardComponent,\n TableComponent,\n TableRowComponent,\n TableCellComponent,\n} from '../types/component-types';\n\nimport type { TableHeaderProps } from './TableHeader';\nimport type { TablePaginationProps } from './TablePagination';\n\ntype ColumnKey<T> = Extract<keyof T, string>;\n\ntype ActionMenuItem<T> = {\n label: ReactNode;\n icon?: ReactNode;\n onClick: (record: T, index: number) => void;\n className?: string;\n separator?: never;\n};\n\ntype ActionSeparatorItem = {\n separator: true;\n className?: string;\n label?: never;\n icon?: never;\n onClick?: never;\n};\n\ntype ActionItem<T> = ActionMenuItem<T> | ActionSeparatorItem;\n\nexport interface Column<T = unknown> {\n key: ColumnKey<T>;\n title: ReactNode;\n render?: (value: T[ColumnKey<T>], record: T, index: number) => ReactNode;\n width?: string;\n align?: 'left' | 'center' | 'right';\n}\n\n/**\n * UI 组件适配器接口\n * 业务项目应该传入自己项目中的 shadcn/ui 组件\n */\nexport interface UIComponents {\n Card: CardComponent;\n CardContent: UIComponent<HTMLAttributes<HTMLDivElement>>;\n CardFooter: UIComponent<HTMLAttributes<HTMLDivElement>>;\n Table: TableComponent;\n TableBody: UIComponent<HTMLAttributes<HTMLTableSectionElement>>;\n TableCell: TableCellComponent;\n TableHead: TableCellComponent;\n TableHeader: UIComponent<HTMLAttributes<HTMLTableSectionElement>>;\n TableRow: TableRowComponent;\n Button: ButtonComponent;\n DropdownMenu: UIComponent<HTMLAttributes<HTMLDivElement>>;\n DropdownMenuTrigger: ButtonComponent;\n DropdownMenuContent: UIComponent<\n HTMLAttributes<HTMLDivElement> & { align?: 'start' | 'end' | 'center' }\n >;\n DropdownMenuItem: UIComponent<\n ButtonHTMLAttributes<HTMLDivElement> & {\n onClick?: (e: MouseEvent) => void;\n }\n >;\n DropdownMenuSeparator: UIComponent;\n Skeleton: UIComponent<HTMLAttributes<HTMLDivElement>>;\n TableHeaderComponent: React.ComponentType<TableHeaderProps>;\n TablePaginationComponent: React.ComponentType<TablePaginationProps>;\n}\n\nexport interface DataTableProps<T = unknown> {\n // 数据相关\n data: T[];\n loading?: boolean;\n columns: Column<T>[];\n rowKey: keyof T | ((record: T) => string);\n\n // 空状态\n emptyText?: string;\n searchActiveEmptyText?: string;\n\n // 头部配置\n header?: TableHeaderProps;\n\n // 分页配置\n pagination?: TablePaginationProps & {\n show?: boolean;\n };\n\n // 表格行样式\n rowClassName?: (record: T, index: number) => string;\n onRow?: (\n record: T,\n index: number\n ) => {\n onClick?: () => void;\n onDoubleClick?: () => void;\n };\n\n // 操作列\n actions?: {\n title?: string;\n mode?: 'expanded' | 'collapsed';\n render?: (record: T, index: number) => ReactNode;\n items?: ActionItem<T>[];\n };\n\n // UI 组件注入(可选)\n components?: UIComponents;\n\n // 自定义渲染函数(更灵活)\n renderCard?: (content: ReactNode) => ReactNode;\n renderTable?: (header: ReactNode, body: ReactNode) => ReactNode;\n renderActions?: (record: T, index: number) => ReactNode;\n}\n\n/**\n * 默认的 DataTable 实现\n * 需要通过 components prop 注入 UI 组件\n */\nexport function DataTable<T extends Record<string, any>>({\n data,\n loading = false,\n columns,\n rowKey,\n emptyText = '暂无数据',\n searchActiveEmptyText = '未找到匹配的记录',\n header,\n pagination,\n rowClassName,\n onRow,\n actions,\n components,\n renderCard,\n renderTable,\n renderActions,\n}: DataTableProps<T>) {\n if (!components) {\n return (\n <div className=\"p-4 text-center text-destructive\">\n 错误:请通过 components prop 注入 UI 组件\n <br />\n <code className=\"text-sm\">\n {'import { Card, Table, Button, ... } from \"@/components/ui\"'}\n </code>\n </div>\n );\n }\n\n const {\n Card,\n CardContent,\n CardFooter,\n Table,\n TableBody,\n TableCell,\n TableHead,\n TableHeader,\n TableRow,\n Button,\n DropdownMenu,\n DropdownMenuTrigger,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuSeparator,\n Skeleton,\n TableHeaderComponent,\n TablePaginationComponent,\n } = components;\n\n // 获取行的唯一标识\n const getRowKey = (record: T, index: number): string => {\n if (typeof rowKey === 'function') {\n return rowKey(record);\n }\n const keyVal = record[rowKey];\n return keyVal !== undefined && keyVal !== null\n ? String(keyVal)\n : `row-${index}`;\n };\n\n // 检查是否有搜索活动\n const isSearchActive = Boolean(\n header?.searchValue && header.searchValue.trim().length > 0\n );\n const hasActions = Boolean(actions?.render || actions?.items?.length);\n const actionMode: 'expanded' | 'collapsed' =\n actions?.mode ?? (actions?.items?.length ? 'collapsed' : 'expanded');\n const isSeparatorItem = (item: ActionItem<T>): item is ActionSeparatorItem =>\n item.separator === true;\n\n // 渲染操作列\n const defaultRenderActions = (record: T, index: number) => {\n if (!actions || !hasActions) return null;\n\n // 折叠模式:使用 DropdownMenu\n if (\n actionMode === 'collapsed' &&\n actions.items &&\n actions.items.length > 0\n ) {\n return (\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button\n variant=\"ghost\"\n className=\"h-8 w-8 p-0\"\n aria-label=\"打开行操作菜单\"\n onClick={(event) => event.stopPropagation()}\n >\n <MoreVertical className=\"h-4 w-4\" />\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\">\n {actions.items.map((item, itemIndex) =>\n isSeparatorItem(item) ? (\n <DropdownMenuSeparator key={`separator-${itemIndex}`} />\n ) : (\n <DropdownMenuItem\n key={`action-${itemIndex}`}\n onClick={(event) => {\n event.stopPropagation();\n item.onClick(record, index);\n }}\n className={item.className}\n >\n {item.icon && (\n <span className=\"mr-2 h-4 w-4\">{item.icon}</span>\n )}\n {item.label}\n </DropdownMenuItem>\n )\n )}\n </DropdownMenuContent>\n </DropdownMenu>\n );\n }\n\n // 展开模式:使用自定义 render\n return actions.render ? actions.render(record, index) : null;\n };\n\n // 渲染表头\n const renderTableHeader = () => {\n return (\n <TableHeader>\n <TableRow className=\"bg-muted/50 hover:bg-muted/50\">\n {columns.map((column) => (\n <TableHead\n key={String(column.key)}\n className={`font-semibold text-foreground ${\n column.align === 'center'\n ? 'text-center'\n : column.align === 'right'\n ? 'text-right'\n : 'text-left'\n }`}\n style={{ width: column.width }}\n >\n {column.title}\n </TableHead>\n ))}\n {hasActions && (\n <TableHead className=\"text-right font-semibold text-foreground\">\n {actions?.title || '操作'}\n </TableHead>\n )}\n </TableRow>\n </TableHeader>\n );\n };\n\n // 渲染表体\n const renderTableBody = () => {\n // Loading 状态\n if (loading) {\n return (\n <TableBody>\n {Array.from({ length: 5 }).map((_, index) => (\n <TableRow key={index}>\n {columns.map((column) => (\n <TableCell\n key={String(column.key)}\n style={{ width: column.width }}\n className={\n column.align === 'center'\n ? 'text-center'\n : column.align === 'right'\n ? 'text-right'\n : ''\n }\n >\n <Skeleton className=\"h-4 w-full\" />\n </TableCell>\n ))}\n {hasActions && (\n <TableCell>\n <Skeleton className=\"ml-auto h-4 w-8\" />\n </TableCell>\n )}\n </TableRow>\n ))}\n </TableBody>\n );\n }\n\n // 空数据状态\n if (data.length === 0) {\n return (\n <TableBody>\n <TableRow>\n <TableCell\n colSpan={columns.length + (hasActions ? 1 : 0)}\n className=\"py-8 text-center text-muted-foreground\"\n >\n {isSearchActive ? searchActiveEmptyText : emptyText}\n </TableCell>\n </TableRow>\n </TableBody>\n );\n }\n\n // 数据行\n return (\n <TableBody>\n {data.map((record, index) => {\n const key = getRowKey(record, index);\n const rowProps = onRow?.(record, index);\n const className = rowClassName?.(record, index);\n\n return (\n <TableRow\n key={key}\n className={`${className || ''} hover:bg-muted/50`}\n {...rowProps}\n >\n {columns.map((column) => {\n const value = record[column.key as keyof T];\n const content = column.render\n ? column.render(value as T[ColumnKey<T>], record, index)\n : value;\n\n return (\n <TableCell\n key={String(column.key)}\n className={\n column.align === 'center'\n ? 'text-center'\n : column.align === 'right'\n ? 'text-right'\n : ''\n }\n >\n {content}\n </TableCell>\n );\n })}\n {hasActions && (\n <TableCell\n className=\"text-right\"\n onClick={(event) => event.stopPropagation()}\n >\n {renderActions\n ? renderActions(record, index)\n : defaultRenderActions(record, index)}\n </TableCell>\n )}\n </TableRow>\n );\n })}\n </TableBody>\n );\n };\n\n // 默认的卡片渲染\n const defaultRenderCard = (content: ReactNode) => (\n <Card>\n {header && (\n <div className=\"p-6 pb-0\">\n <TableHeaderComponent {...header} />\n </div>\n )}\n <CardContent className=\"p-0\">{content}</CardContent>\n {pagination?.show !== false && pagination && (\n <CardFooter className=\"border-t py-4\">\n <TablePaginationComponent\n currentPage={pagination.currentPage}\n pageSize={pagination.pageSize}\n total={pagination.total}\n onPageChange={pagination.onPageChange}\n onPageSizeChange={pagination.onPageSizeChange}\n pageSizeOptions={pagination.pageSizeOptions}\n showPageSizeSelector={pagination.showPageSizeSelector}\n showJumpToPage={pagination.showJumpToPage}\n showTotal={pagination.showTotal}\n searchActive={isSearchActive}\n />\n </CardFooter>\n )}\n </Card>\n );\n\n // 默认的表格渲染\n const defaultRenderTable = (tableHeader: ReactNode, tableBody: ReactNode) => (\n <Table>\n {tableHeader}\n {tableBody}\n </Table>\n );\n\n return renderCard\n ? renderCard(\n renderTable\n ? renderTable(renderTableHeader(), renderTableBody())\n : defaultRenderTable(renderTableHeader(), renderTableBody())\n )\n : defaultRenderCard(\n renderTable\n ? renderTable(renderTableHeader(), renderTableBody())\n : defaultRenderTable(renderTableHeader(), renderTableBody())\n );\n}\n"],"names":["DataTable","data","loading","columns","rowKey","emptyText","searchActiveEmptyText","header","pagination","rowClassName","onRow","actions","components","renderCard","renderTable","renderActions","jsxs","jsx","Card","CardContent","CardFooter","Table","TableBody","TableCell","TableHead","TableHeader","TableRow","Button","DropdownMenu","DropdownMenuTrigger","DropdownMenuContent","DropdownMenuItem","DropdownMenuSeparator","Skeleton","TableHeaderComponent","TablePaginationComponent","getRowKey","record","index","keyVal","isSearchActive","hasActions","_a","actionMode","_b","isSeparatorItem","item","defaultRenderActions","event","MoreVertical","itemIndex","renderTableHeader","column","renderTableBody","_","key","rowProps","className","value","content","defaultRenderCard","defaultRenderTable","tableHeader","tableBody"],"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:P=.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:_,CardContent:y,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-P),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+P),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,style:{objectFit:W,transform:`scale(${o}) rotate(${w}deg)`,transformOrigin:"center center",...ne}})]}):null]})]});return _?e.jsxRuntimeExports.jsx(_,{className:M,children:y?e.jsxRuntimeExports.jsx(y,{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\n extends Omit<\n ImgHTMLAttributes<HTMLImageElement>,\n | 'alt'\n | 'children'\n | 'className'\n | 'loading'\n | 'onError'\n | 'onLoad'\n | '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 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"}