flex-image-viewer 1.0.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 (67) hide show
  1. package/README.md +160 -0
  2. package/dist/FlexImageViewer/Content/index.js +193 -0
  3. package/dist/FlexImageViewer/Footer/Actions.js +115 -0
  4. package/dist/FlexImageViewer/Footer/index.js +56 -0
  5. package/dist/FlexImageViewer/Header/Actions.js +80 -0
  6. package/dist/FlexImageViewer/Header/index.js +42 -0
  7. package/dist/FlexImageViewer/Info/index.js +52 -0
  8. package/dist/FlexImageViewer/Thumbnail/index.js +90 -0
  9. package/dist/FlexImageViewer/index.css +582 -0
  10. package/dist/FlexImageViewer/index.js +117 -0
  11. package/dist/components/ActionItem.js +10 -0
  12. package/dist/components/BaseActions.js +69 -0
  13. package/dist/components/Icon/index.js +48 -0
  14. package/dist/components/Icon/svg/arrow-left.js +15 -0
  15. package/dist/components/Icon/svg/arrow-right.js +15 -0
  16. package/dist/components/Icon/svg/caret-right.js +15 -0
  17. package/dist/components/Icon/svg/check.js +15 -0
  18. package/dist/components/Icon/svg/clear.js +15 -0
  19. package/dist/components/Icon/svg/close.js +16 -0
  20. package/dist/components/Icon/svg/default-image.js +17 -0
  21. package/dist/components/Icon/svg/down.js +15 -0
  22. package/dist/components/Icon/svg/info-circle.js +20 -0
  23. package/dist/components/Icon/svg/rotate-left.js +20 -0
  24. package/dist/components/Icon/svg/rotate-right.js +20 -0
  25. package/dist/components/Icon/svg/save.js +15 -0
  26. package/dist/components/Icon/svg/size.js +19 -0
  27. package/dist/components/Icon/svg/thumbnail.js +19 -0
  28. package/dist/components/Icon/svg/zoom-adapt.js +24 -0
  29. package/dist/components/Icon/svg/zoom-in.js +15 -0
  30. package/dist/components/Icon/svg/zoom-out.js +15 -0
  31. package/dist/components/Image.js +148 -0
  32. package/dist/components/Modal.js +98 -0
  33. package/dist/components/PercentSelect.js +160 -0
  34. package/dist/components/ThumbnailIamge.js +65 -0
  35. package/dist/components/index.js +6 -0
  36. package/dist/context/ViewerContext.js +208 -0
  37. package/dist/hooks/useImageOperations.js +113 -0
  38. package/dist/hooks/useImageSource.js +52 -0
  39. package/dist/index.js +2 -0
  40. package/dist/rspress.config.d.ts +2 -0
  41. package/dist/src/FlexImageViewer/Content/index.d.ts +11 -0
  42. package/dist/src/FlexImageViewer/Footer/Actions.d.ts +13 -0
  43. package/dist/src/FlexImageViewer/Footer/index.d.ts +8 -0
  44. package/dist/src/FlexImageViewer/Header/Actions.d.ts +15 -0
  45. package/dist/src/FlexImageViewer/Header/index.d.ts +11 -0
  46. package/dist/src/FlexImageViewer/Info/index.d.ts +5 -0
  47. package/dist/src/FlexImageViewer/Thumbnail/index.d.ts +5 -0
  48. package/dist/src/FlexImageViewer/index.d.ts +21 -0
  49. package/dist/src/components/ActionItem.d.ts +6 -0
  50. package/dist/src/components/BaseActions.d.ts +17 -0
  51. package/dist/src/components/Icon/index.d.ts +6 -0
  52. package/dist/src/components/Image.d.ts +18 -0
  53. package/dist/src/components/Modal.d.ts +9 -0
  54. package/dist/src/components/PercentSelect.d.ts +17 -0
  55. package/dist/src/components/ThumbnailIamge.d.ts +8 -0
  56. package/dist/src/components/index.d.ts +13 -0
  57. package/dist/src/context/ViewerContext.d.ts +13 -0
  58. package/dist/src/hooks/useImageOperations.d.ts +12 -0
  59. package/dist/src/hooks/useImageSource.d.ts +7 -0
  60. package/dist/src/index.d.ts +6 -0
  61. package/dist/src/utils/dict.d.ts +1 -0
  62. package/dist/src/utils/exif.d.ts +2 -0
  63. package/dist/src/utils/source.d.ts +1 -0
  64. package/dist/utils/dict.js +16 -0
  65. package/dist/utils/exif.js +17 -0
  66. package/dist/utils/source.js +2 -0
  67. package/package.json +74 -0
package/README.md ADDED
@@ -0,0 +1,160 @@
1
+ # flex-image-viewer
2
+
3
+ 一个功能丰富的 React 图片查看器组件,支持缩放、旋转、缩略图导航、信息面板等交互功能。
4
+
5
+ ## 特性
6
+
7
+ - **图片浏览** — 支持多张图片切换浏览,可配置循环模式
8
+ - **缩放操作** — 支持放大、缩小、自适应缩放,以及鼠标滚轮缩放
9
+ - **旋转功能** — 支持左旋、右旋
10
+ - **缩略图导航** — 底部缩略图列表,快速定位图片
11
+ - **信息面板** — 展示图片详细信息(尺寸、大小等)
12
+ - **EXIF 方向识别** — 自动识别并应用图片的 EXIF 方向信息
13
+ - **预加载** — 支持图片预加载以提升浏览体验
14
+ - **禁用右键** — 支持禁用图片右键菜单
15
+ - **自定义操作** — 头部和底部操作栏支持自定义渲染
16
+ - **加载状态** — 图片加载时显示加载指示器
17
+
18
+ ## 安装
19
+
20
+ ```bash
21
+ pnpm install
22
+ ```
23
+
24
+ ## 使用
25
+
26
+ ```tsx
27
+ import { FlexImageViewer, ActionItem } from 'flex-image-viewer';
28
+ import type { FileData } from 'flex-image-viewer';
29
+
30
+ function App() {
31
+ const [visible, setVisible] = useState(false);
32
+ const [current, setCurrent] = useState(1);
33
+
34
+ const files: FileData[] = [
35
+ {
36
+ name: 'image1.png',
37
+ src: 'https://example.com/image1.png',
38
+ alt: '图片1',
39
+ width: 1920,
40
+ height: 1080,
41
+ size: '2.5 MB',
42
+ infoData: [
43
+ { label: '尺寸', value: '1920x1080' },
44
+ { label: '格式', value: 'PNG' },
45
+ ],
46
+ },
47
+ ];
48
+
49
+ return (
50
+ <>
51
+ <button onClick={() => setVisible(true)}>打开查看器</button>
52
+ <FlexImageViewer
53
+ files={files}
54
+ visible={visible}
55
+ current={current}
56
+ onClose={() => setVisible(false)}
57
+ onIndexChange={setCurrent}
58
+ wheelZoom
59
+ disableRightClick={false}
60
+ />
61
+ </>
62
+ );
63
+ }
64
+ ```
65
+
66
+ ## Props
67
+
68
+ | 属性 | 类型 | 默认值 | 说明 |
69
+ | ----------------- | ---------------------------------------- | ------- | ----------------------------- |
70
+ | files | `FileData[]` | `[]` | 图片数据列表 |
71
+ | current | `number` | `1` | 当前显示的图片索引(从1开始) |
72
+ | visible | `boolean` | - | 是否显示查看器 |
73
+ | loop | `boolean` | `false` | 是否循环浏览 |
74
+ | onClose | `() => void` | - | 关闭回调 |
75
+ | onIndexChange | `(index: number) => void` | - | 图片切换回调 |
76
+ | onClear | `() => void` | - | 重置操作回调 |
77
+ | wheelZoom | `boolean` | `true` | 是否启用鼠标滚轮缩放 |
78
+ | wheelZoomStep | `number` | `0.1` | 滚轮缩放步长 |
79
+ | preload | `boolean` | `false` | 是否预加载图片 |
80
+ | disableRightClick | `boolean` | `false` | 是否禁用右键菜单 |
81
+ | getSrc | `(file: T) => Promise<string> \| string` | - | 自定义获取原图地址 |
82
+ | getThumbnail | `(file: T) => Promise<string> \| string` | - | 自定义获取缩略图地址 |
83
+ | renderInfo | `(file: T) => ReactNode` | - | 自定义信息面板渲染 |
84
+ | headerProps | `{ renderAction? }` | - | 头部操作栏配置 |
85
+ | footerProps | `{ renderAction? }` | - | 底部操作栏配置 |
86
+
87
+ ## FileData 数据结构
88
+
89
+ ```ts
90
+ interface FileData {
91
+ name?: string; // 文件名
92
+ description?: string; // 描述
93
+ src?: string; // 图片地址
94
+ alt?: string; // 替代文本
95
+ size?: string; // 文件大小
96
+ width?: string | number; // 图片宽度
97
+ height?: string | number; // 图片高度
98
+ angle?: number; // 旋转角度
99
+ scale?: number; // 缩放比例
100
+ infoData?: { label: string; value: string }[]; // 信息面板数据
101
+ orientation?: number; // EXIF 方向值
102
+ }
103
+ ```
104
+
105
+ ## 开发
106
+
107
+ ### 启动开发模式
108
+
109
+ ```bash
110
+ pnpm run dev
111
+ ```
112
+
113
+ ### 构建
114
+
115
+ ```bash
116
+ pnpm run build
117
+ ```
118
+
119
+ ### 运行测试
120
+
121
+ ```bash
122
+ pnpm run test
123
+ ```
124
+
125
+ ### 启动 Storybook
126
+
127
+ ```bash
128
+ pnpm run storybook
129
+ ```
130
+
131
+ ### 启动文档站点
132
+
133
+ ```bash
134
+ pnpm run doc
135
+ ```
136
+
137
+ ### 代码检查
138
+
139
+ ```bash
140
+ pnpm run lint
141
+ ```
142
+
143
+ ### 代码格式化
144
+
145
+ ```bash
146
+ pnpm run format
147
+ ```
148
+
149
+ ## 技术栈
150
+
151
+ - React 19
152
+ - TypeScript
153
+ - Rslib(构建工具)
154
+ - ahooks
155
+ - es-toolkit
156
+ - rc-slider / rc-tooltip
157
+
158
+ ## License
159
+
160
+ MIT
@@ -0,0 +1,193 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { useCallback, useEffect, useState } from "react";
3
+ import { useViewerDispatch, useViewerState } from "../../context/ViewerContext.js";
4
+ import { Icon, Image } from "../../components/index.js";
5
+ function Content(props) {
6
+ const { preload = true, wheelZoom, wheelZoomStep, disableRightClick, getSrc } = props;
7
+ const state = useViewerState();
8
+ const dispatch = useViewerDispatch();
9
+ const current = state.currentIndex;
10
+ const files = state.files;
11
+ const imageOptions = state.imageOptions;
12
+ const [displayIndices, setDisplayIndices] = useState([]);
13
+ useEffect(()=>{
14
+ const index = current - 1;
15
+ if (!files || 0 === files.length) return void setDisplayIndices([]);
16
+ let list = [];
17
+ if (preload) {
18
+ const prevIndex = index > 0 ? index - 1 : null;
19
+ const nextIndex = index < files.length - 1 ? index + 1 : null;
20
+ list = [
21
+ prevIndex,
22
+ index,
23
+ nextIndex
24
+ ];
25
+ } else list = [
26
+ index
27
+ ];
28
+ const newIndices = list.filter((idx)=>null !== idx);
29
+ setDisplayIndices(newIndices);
30
+ }, [
31
+ current,
32
+ files,
33
+ preload
34
+ ]);
35
+ const index = current - 1;
36
+ const handleAdapt = useCallback((zoom)=>{
37
+ dispatch({
38
+ type: 'ADAPT_ZOOM',
39
+ payload: {
40
+ index,
41
+ scale: zoom
42
+ }
43
+ });
44
+ }, [
45
+ dispatch,
46
+ index
47
+ ]);
48
+ const handleWheelZoom = useCallback((scale)=>{
49
+ dispatch({
50
+ type: 'SET_ZOOM',
51
+ payload: {
52
+ index,
53
+ scale
54
+ }
55
+ });
56
+ }, [
57
+ dispatch,
58
+ index
59
+ ]);
60
+ const handleOrientation = useCallback((displayIndex, orientation)=>{
61
+ dispatch({
62
+ type: 'UPDATE_FILE',
63
+ payload: {
64
+ index: displayIndex,
65
+ file: {
66
+ orientation
67
+ }
68
+ }
69
+ });
70
+ }, [
71
+ dispatch
72
+ ]);
73
+ useEffect(()=>{
74
+ const handleKeyDown = (e)=>{
75
+ switch(e.key){
76
+ case 'ArrowLeft':
77
+ e.preventDefault();
78
+ dispatch({
79
+ type: 'PREV_IMAGE'
80
+ });
81
+ break;
82
+ case 'ArrowRight':
83
+ e.preventDefault();
84
+ dispatch({
85
+ type: 'NEXT_IMAGE'
86
+ });
87
+ break;
88
+ case '+':
89
+ case '=':
90
+ e.preventDefault();
91
+ dispatch({
92
+ type: 'ZOOM_IN',
93
+ payload: {
94
+ index,
95
+ step: 0.1
96
+ }
97
+ });
98
+ break;
99
+ case '-':
100
+ e.preventDefault();
101
+ dispatch({
102
+ type: 'ZOOM_OUT',
103
+ payload: {
104
+ index,
105
+ step: 0.1
106
+ }
107
+ });
108
+ break;
109
+ case 'r':
110
+ case 'R':
111
+ e.preventDefault();
112
+ {
113
+ const file = files[index];
114
+ dispatch({
115
+ type: 'CLEAR_IMAGE',
116
+ payload: {
117
+ index,
118
+ angle: file?.angle ?? 0,
119
+ scale: file?.scale ?? 1
120
+ }
121
+ });
122
+ }
123
+ break;
124
+ }
125
+ };
126
+ document.addEventListener('keydown', handleKeyDown);
127
+ return ()=>{
128
+ document.removeEventListener('keydown', handleKeyDown);
129
+ };
130
+ }, [
131
+ dispatch,
132
+ index,
133
+ files
134
+ ]);
135
+ return /*#__PURE__*/ jsxs("main", {
136
+ className: "flex-image-viewer-content",
137
+ "aria-label": "图片内容",
138
+ children: [
139
+ /*#__PURE__*/ jsx("div", {
140
+ className: "flex-image-viewer-content-tool-left",
141
+ children: /*#__PURE__*/ jsx("span", {
142
+ onClick: ()=>dispatch({
143
+ type: 'PREV_IMAGE'
144
+ }),
145
+ "aria-label": "上一张图片",
146
+ role: "button",
147
+ tabIndex: 0,
148
+ children: /*#__PURE__*/ jsx(Icon, {
149
+ name: "ArrowLeft"
150
+ })
151
+ })
152
+ }),
153
+ /*#__PURE__*/ jsx("div", {
154
+ className: "flex-image-viewer-content-image",
155
+ children: displayIndices.map((displayIndex)=>{
156
+ const isVisible = displayIndex === index;
157
+ return /*#__PURE__*/ jsx(Image, {
158
+ file: files?.[displayIndex],
159
+ scale: imageOptions?.[displayIndex]?.scale,
160
+ angle: imageOptions?.[displayIndex]?.angle,
161
+ isAdapt: imageOptions?.[displayIndex]?.isAdapt,
162
+ onAdapt: handleAdapt,
163
+ wheelZoom: wheelZoom,
164
+ wheelZoomStep: wheelZoomStep,
165
+ onWheelZoom: handleWheelZoom,
166
+ getSrc: getSrc,
167
+ onOrientation: (orientation)=>handleOrientation(displayIndex, orientation),
168
+ disableRightClick: disableRightClick,
169
+ style: {
170
+ display: isVisible ? 'flex' : 'none'
171
+ }
172
+ }, displayIndex);
173
+ })
174
+ }),
175
+ /*#__PURE__*/ jsx("div", {
176
+ className: "flex-image-viewer-content-tool-right",
177
+ children: /*#__PURE__*/ jsx("span", {
178
+ onClick: ()=>dispatch({
179
+ type: 'NEXT_IMAGE'
180
+ }),
181
+ "aria-label": "下一张图片",
182
+ role: "button",
183
+ tabIndex: 0,
184
+ children: /*#__PURE__*/ jsx(Icon, {
185
+ name: "ArrowRight"
186
+ })
187
+ })
188
+ })
189
+ ]
190
+ });
191
+ }
192
+ const FlexImageViewer_Content = Content;
193
+ export default FlexImageViewer_Content;
@@ -0,0 +1,115 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ import "react";
3
+ import { BaseActions } from "../../components/index.js";
4
+ import { useViewerDispatch, useViewerState } from "../../context/ViewerContext.js";
5
+ const FOOTER_ITEMS = [
6
+ {
7
+ key: 'thumbnail',
8
+ type: 'icon',
9
+ tooltipKey: 'thumbnail',
10
+ iconName: 'Thumbnail'
11
+ },
12
+ {
13
+ key: 'info',
14
+ type: 'icon',
15
+ tooltipKey: 'info',
16
+ iconName: 'Info'
17
+ },
18
+ {
19
+ key: 'zoomAdapt',
20
+ type: 'icon',
21
+ tooltipKey: 'zoomAdapt',
22
+ iconName: 'ZoomAdapt'
23
+ },
24
+ {
25
+ key: 'zoomSelect',
26
+ type: 'select',
27
+ valueKey: 'zoom'
28
+ },
29
+ {
30
+ key: 'zoomOut',
31
+ type: 'icon',
32
+ tooltipKey: 'zoomOut',
33
+ iconName: 'ZoomOut'
34
+ },
35
+ {
36
+ key: 'zoomSlider',
37
+ type: 'slider',
38
+ valueKey: 'zoom'
39
+ },
40
+ {
41
+ key: 'zoomIn',
42
+ type: 'icon',
43
+ tooltipKey: 'zoomIn',
44
+ iconName: 'ZoomIn'
45
+ }
46
+ ];
47
+ function Actions(props) {
48
+ const { zoom = 1, updateCurrentFile, renderAction } = props;
49
+ const dispatch = useViewerDispatch();
50
+ const state = useViewerState();
51
+ const index = state.currentIndex - 1;
52
+ const handleAction = (key, value, _event)=>{
53
+ switch(key){
54
+ case 'thumbnail':
55
+ dispatch({
56
+ type: 'TOGGLE_THUMBNAIL'
57
+ });
58
+ break;
59
+ case 'info':
60
+ dispatch({
61
+ type: 'TOGGLE_INFO'
62
+ });
63
+ break;
64
+ case 'zoomAdapt':
65
+ dispatch({
66
+ type: 'ADAPT_ZOOM',
67
+ payload: {
68
+ index,
69
+ scale: zoom / 100
70
+ }
71
+ });
72
+ break;
73
+ case 'zoomSelect':
74
+ case 'zoomSlider':
75
+ if (void 0 !== value) dispatch({
76
+ type: 'SET_ZOOM',
77
+ payload: {
78
+ index,
79
+ scale: value / 100
80
+ }
81
+ });
82
+ break;
83
+ case 'zoomOut':
84
+ dispatch({
85
+ type: 'ZOOM_OUT',
86
+ payload: {
87
+ index,
88
+ step: 0.1
89
+ }
90
+ });
91
+ break;
92
+ case 'zoomIn':
93
+ dispatch({
94
+ type: 'ZOOM_IN',
95
+ payload: {
96
+ index,
97
+ step: 0.1
98
+ }
99
+ });
100
+ break;
101
+ }
102
+ };
103
+ const context = {
104
+ zoom,
105
+ updateCurrentFile: updateCurrentFile ?? (()=>{})
106
+ };
107
+ return /*#__PURE__*/ jsx(BaseActions, {
108
+ items: FOOTER_ITEMS,
109
+ contextValues: context,
110
+ renderAction: renderAction,
111
+ onAction: handleAction
112
+ });
113
+ }
114
+ const Footer_Actions = Actions;
115
+ export default Footer_Actions;
@@ -0,0 +1,56 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { useViewerState } from "../../context/ViewerContext.js";
3
+ import { Icon } from "../../components/index.js";
4
+ import { shouldSwapDimensions } from "../../utils/exif.js";
5
+ import Actions from "./Actions.js";
6
+ function Footer({ renderAction, updateCurrentFile }) {
7
+ const state = useViewerState();
8
+ const zoom = (state.imageOptions[state.currentIndex - 1]?.scale ?? 1) * 100;
9
+ const files = state.files;
10
+ const current = state.currentIndex;
11
+ const fileData = files[current - 1];
12
+ const width = fileData?.width;
13
+ const height = fileData?.height;
14
+ const sizeArr = shouldSwapDimensions(fileData?.orientation) ? [
15
+ height,
16
+ width
17
+ ].filter(Boolean) : [
18
+ width,
19
+ height
20
+ ].filter(Boolean);
21
+ return /*#__PURE__*/ jsxs("footer", {
22
+ className: "flex-image-viewer-footer",
23
+ children: [
24
+ /*#__PURE__*/ jsxs("div", {
25
+ className: "flex-image-viewer-footer-title",
26
+ children: [
27
+ 2 === sizeArr.length && /*#__PURE__*/ jsxs("div", {
28
+ className: "flex-image-viewer-footer-size",
29
+ children: [
30
+ /*#__PURE__*/ jsx(Icon, {
31
+ name: "Size"
32
+ }),
33
+ sizeArr.join(' x ')
34
+ ]
35
+ }),
36
+ !!fileData?.size && /*#__PURE__*/ jsxs("div", {
37
+ className: "flex-image-viewer-footer-memory",
38
+ children: [
39
+ /*#__PURE__*/ jsx(Icon, {
40
+ name: "Save"
41
+ }),
42
+ fileData?.size
43
+ ]
44
+ })
45
+ ]
46
+ }),
47
+ /*#__PURE__*/ jsx(Actions, {
48
+ zoom: zoom,
49
+ renderAction: renderAction,
50
+ updateCurrentFile: updateCurrentFile
51
+ })
52
+ ]
53
+ });
54
+ }
55
+ const FlexImageViewer_Footer = Footer;
56
+ export default FlexImageViewer_Footer;
@@ -0,0 +1,80 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ import "react";
3
+ import { useViewerDispatch, useViewerState } from "../../context/ViewerContext.js";
4
+ import { BaseActions } from "../../components/index.js";
5
+ const HEADER_ITEMS = [
6
+ {
7
+ key: 'rotateLeft',
8
+ type: 'icon',
9
+ tooltipKey: 'rotateLeft',
10
+ iconName: 'RotateLeft',
11
+ tooltipPlacement: 'bottomRight'
12
+ },
13
+ {
14
+ key: 'rotateRight',
15
+ type: 'icon',
16
+ tooltipKey: 'rotateRight',
17
+ iconName: 'RotateRight',
18
+ tooltipPlacement: 'bottomRight'
19
+ },
20
+ {
21
+ key: 'clear',
22
+ type: 'icon',
23
+ tooltipKey: 'clear',
24
+ iconName: 'Clear',
25
+ tooltipPlacement: 'bottomRight'
26
+ },
27
+ {
28
+ key: 'close',
29
+ type: 'icon',
30
+ tooltipKey: 'close',
31
+ iconName: 'Close',
32
+ tooltipPlacement: 'bottomRight'
33
+ }
34
+ ];
35
+ function Actions(props) {
36
+ const { rotate = 0, updateCurrentFile, renderAction, onClear, onClose } = props;
37
+ const dispatch = useViewerDispatch();
38
+ const state = useViewerState();
39
+ const index = state.currentIndex - 1;
40
+ const handleAction = (key, _value, event)=>{
41
+ switch(key){
42
+ case 'rotateLeft':
43
+ dispatch({
44
+ type: 'ROTATE_LEFT',
45
+ payload: {
46
+ index
47
+ }
48
+ });
49
+ break;
50
+ case 'rotateRight':
51
+ dispatch({
52
+ type: 'ROTATE_RIGHT',
53
+ payload: {
54
+ index
55
+ }
56
+ });
57
+ break;
58
+ case 'clear':
59
+ onClear?.();
60
+ break;
61
+ case 'close':
62
+ onClose?.(event);
63
+ break;
64
+ }
65
+ };
66
+ const context = {
67
+ rotate,
68
+ updateCurrentFile: updateCurrentFile ?? (()=>{}),
69
+ onClear,
70
+ onClose
71
+ };
72
+ return /*#__PURE__*/ jsx(BaseActions, {
73
+ items: HEADER_ITEMS,
74
+ contextValues: context,
75
+ renderAction: renderAction,
76
+ onAction: handleAction
77
+ });
78
+ }
79
+ const Header_Actions = Actions;
80
+ export default Header_Actions;
@@ -0,0 +1,42 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import "react";
3
+ import { useViewerState } from "../../context/ViewerContext.js";
4
+ import Actions from "./Actions.js";
5
+ function Header({ renderAction, onClose, onClear, updateCurrentFile }) {
6
+ const state = useViewerState();
7
+ const current = state.currentIndex;
8
+ const total = state.filesLength;
9
+ const name = state.files[current - 1]?.name;
10
+ const rotate = state.imageOptions[current - 1]?.angle ?? 0;
11
+ return /*#__PURE__*/ jsxs("header", {
12
+ className: "flex-image-viewer-header",
13
+ children: [
14
+ /*#__PURE__*/ jsxs("div", {
15
+ className: "flex-image-viewer-header-title",
16
+ children: [
17
+ /*#__PURE__*/ jsxs("div", {
18
+ className: "flex-image-viewer-header-count",
19
+ children: [
20
+ current,
21
+ "/",
22
+ total
23
+ ]
24
+ }),
25
+ /*#__PURE__*/ jsx("div", {
26
+ className: "flex-image-viewer-header-name",
27
+ children: name
28
+ })
29
+ ]
30
+ }),
31
+ /*#__PURE__*/ jsx(Actions, {
32
+ rotate: rotate,
33
+ renderAction: renderAction,
34
+ onClose: onClose,
35
+ onClear: onClear,
36
+ updateCurrentFile: updateCurrentFile
37
+ })
38
+ ]
39
+ });
40
+ }
41
+ const FlexImageViewer_Header = Header;
42
+ export default FlexImageViewer_Header;
@@ -0,0 +1,52 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { useCreation } from "ahooks";
3
+ import { useViewerDispatch, useViewerState } from "../../context/ViewerContext.js";
4
+ import { Icon } from "../../components/index.js";
5
+ function Info(props) {
6
+ const { renderInfo } = props;
7
+ const state = useViewerState();
8
+ const dispatch = useViewerDispatch();
9
+ const visible = state.infoVisible;
10
+ const files = state.files;
11
+ const current = state.currentIndex;
12
+ const fileData = files[current];
13
+ const content = useCreation(()=>renderInfo ? renderInfo(fileData) : /*#__PURE__*/ jsx("ul", {
14
+ children: fileData?.infoData?.map((item, index)=>/*#__PURE__*/ jsxs("li", {
15
+ children: [
16
+ /*#__PURE__*/ jsxs("span", {
17
+ children: [
18
+ item.label,
19
+ ":"
20
+ ]
21
+ }),
22
+ /*#__PURE__*/ jsx("p", {
23
+ children: item.value
24
+ })
25
+ ]
26
+ }, index))
27
+ }), [
28
+ fileData,
29
+ renderInfo
30
+ ]);
31
+ return /*#__PURE__*/ jsxs("div", {
32
+ className: `flex-image-viewer-info ${visible ? 'visible' : ''}`,
33
+ children: [
34
+ /*#__PURE__*/ jsx("div", {
35
+ className: "flex-image-viewer-info-tool",
36
+ children: /*#__PURE__*/ jsx("span", {
37
+ "aria-label": "切换信息面板",
38
+ role: "button",
39
+ tabIndex: 0,
40
+ onClick: ()=>dispatch({
41
+ type: 'TOGGLE_INFO'
42
+ }),
43
+ children: /*#__PURE__*/ jsx(Icon, {
44
+ name: "CaretRight"
45
+ })
46
+ })
47
+ }),
48
+ content
49
+ ]
50
+ });
51
+ }
52
+ export default Info;