@clicoh/orion-library 1.2.0-beta.21 → 1.2.0-beta.22

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.
@@ -1,11 +1,15 @@
1
1
  import { type HTMLAttributes, type ReactNode } from 'react';
2
+ import { type TImageViewerDocumentLabels } from './ImageViewerDocument';
2
3
  import { type TImageCrop } from './ImageViewerImage';
3
4
  export type { TImageCrop } from './ImageViewerImage';
5
+ export type { TImageViewerDocumentLabels } from './ImageViewerDocument';
6
+ export type TImageViewType = 'image' | 'pdf';
4
7
  export type TImageView = {
5
8
  id: string;
6
9
  label: string;
7
10
  src: string;
8
11
  alt: string;
12
+ type?: TImageViewType;
9
13
  indicator?: ReactNode;
10
14
  crop?: TImageCrop;
11
15
  };
@@ -16,7 +20,7 @@ export type TImageViewerLabels = {
16
20
  rotate: string;
17
21
  enterFullscreen: string;
18
22
  exitFullscreen: string;
19
- };
23
+ } & TImageViewerDocumentLabels;
20
24
  type ImageViewerProps = {
21
25
  views: TImageView[];
22
26
  labels: TImageViewerLabels;
@@ -34,6 +38,12 @@ type ImageViewerProps = {
34
38
  * changes, whether the user picked a tab or the consumer moved `activeId`: a
35
39
  * transform that made sense for one angle rarely makes sense for the next.
36
40
  *
41
+ * Once zoomed in, the image can be panned: by dragging it with the pointer
42
+ * (mouse, touch or pen) or with the arrow keys while the panel has focus. The
43
+ * pan never leaves a gap between the image and the frame; zooming in keeps the
44
+ * point under inspection centered, zooming out to the minimum, rotating and
45
+ * toggling full screen center the image again.
46
+ *
37
47
  * Uncontrolled by default. Passing `activeId` makes the consumer own the active
38
48
  * view, so something outside the viewer (a side panel, a "next pending" action)
39
49
  * can follow or drive it; `onViewChange` reports tab picks in both modes.
@@ -49,6 +59,14 @@ type ImageViewerProps = {
49
59
  * A view's `crop` draws only that region of its image, fitted to the frame
50
60
  * like the whole image would be — a face inside a document, for instance.
51
61
  *
62
+ * A view with `type: 'pdf'` is rendered page by page into images with pdf.js,
63
+ * loaded on first use, so zoom, rotation and pan work on it exactly as on a
64
+ * photo and there is a single toolbar. A document with several pages shows a
65
+ * pager over the page; the toolbar gains an "open in a new tab" action for
66
+ * the original file. The browser fetches the PDF itself, so its origin must
67
+ * allow CORS; when it cannot be loaded, the view shows its description and
68
+ * the same link.
69
+ *
52
70
  * @component
53
71
  * @example
54
72
  * const [viewId, setViewId] = useState('front');
@@ -94,9 +112,23 @@ type ImageViewerProps = {
94
112
  * labels={labels}
95
113
  * />
96
114
  *
115
+ * @example
116
+ * <ImageViewer
117
+ * title="Insurance policy"
118
+ * views={[
119
+ * { id: 'policy', label: 'Policy', src: '/policy.pdf', alt: 'Insurance policy', type: 'pdf' },
120
+ * ]}
121
+ * labels={{
122
+ * ...labels,
123
+ * openDocument: 'Open PDF',
124
+ * previousPage: 'Previous page',
125
+ * nextPage: 'Next page',
126
+ * }}
127
+ * />
128
+ *
97
129
  * @param {Object} props - The properties of the ImageViewer component.
98
- * @param {TImageView[]} props.views - Images to display. In `tabs`, more than one renders a tab per view; in `split`, a pane per view. A view's optional `indicator` sits after its label and becomes part of the tab's accessible name, so give it its own (for an icon, `role="img"` and `aria-label`). In `tabs` with a single view there are no tabs, so no indicator is shown. A view's optional `crop` (`left`, `top`, `width`, `height` as fractions from 0 to 1 of the image) shows only that region; a crop outside the image is clamped to it, and one with no area left falls back to the whole image.
99
- * @param {TImageViewerLabels} props.labels - Accessible names of the toolbar actions.
130
+ * @param {TImageView[]} props.views - Files to display. In `tabs`, more than one renders a tab per view; in `split`, a pane per view. A view's optional `indicator` sits after its label and becomes part of the tab's accessible name, so give it its own (for an icon, `role="img"` and `aria-label`). In `tabs` with a single view there are no tabs, so no indicator is shown. A view's optional `crop` (`left`, `top`, `width`, `height` as fractions from 0 to 1 of the image) shows only that region; a crop outside the image is clamped to it, and one with no area left falls back to the whole image. A view's `type` is `image` unless set to `pdf`; `crop` is ignored on a `pdf`.
131
+ * @param {TImageViewerLabels} props.labels - Accessible names of the toolbar actions. With `pdf` views, `openDocument` names the action that opens the original file in a new tab, and `previousPage` / `nextPage` name the pager of a document with several pages; without the pair, only the first page is reachable.
100
132
  * @param {TImageViewerLayout} [props.layout='tabs'] - `tabs` shows one view at a time; `split` shows every view at once, one pane each.
101
133
  * @param {ReactNode} [props.title] - Optional heading rendered on the left of the toolbar.
102
134
  * @param {ReactNode} [props.emptyState] - Content rendered when there is no image.
@@ -1 +1 @@
1
- {"version":3,"file":"ImageViewer.d.ts","sourceRoot":"","sources":["../../../../src/components/02-molecules/ImageViewer/ImageViewer.tsx"],"names":[],"mappings":"AAGA,OAAO,EAIL,KAAK,cAAc,EACnB,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAYf,OAAO,EAAoB,KAAK,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAEvE,YAAY,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAErD,MAAM,MAAM,UAAU,GAAG;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,IAAI,CAAC,EAAE,UAAU,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG,MAAM,GAAG,OAAO,CAAC;AAElD,MAAM,MAAM,kBAAkB,GAAG;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,eAAe,EAAE,MAAM,CAAC;IACxB,cAAc,EAAE,MAAM,CAAC;CACxB,CAAC;AAEF,KAAK,gBAAgB,GAAG;IACtB,KAAK,EAAE,UAAU,EAAE,CAAC;IACpB,MAAM,EAAE,kBAAkB,CAAC;IAC3B,MAAM,CAAC,EAAE,kBAAkB,CAAC;IAC5B,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,UAAU,CAAC,EAAE,SAAS,CAAC;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;CACrC,GAAG,IAAI,CAAC,cAAc,CAAC,WAAW,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC,CAAC;AAiB5D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+EG;AACH,wBAAgB,WAAW,CAAC,EAC1B,KAAK,EACL,MAAM,EACN,MAAe,EACf,KAAK,EACL,UAAU,EACV,QAAQ,EACR,YAAY,EACZ,GAAG,SAAS,EACb,EAAE,gBAAgB,GAAG,SAAS,CAqP9B"}
1
+ {"version":3,"file":"ImageViewer.d.ts","sourceRoot":"","sources":["../../../../src/components/02-molecules/ImageViewer/ImageViewer.tsx"],"names":[],"mappings":"AAGA,OAAO,EAKL,KAAK,cAAc,EAGnB,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAaf,OAAO,EAEL,KAAK,0BAA0B,EAChC,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAGL,KAAK,UAAU,EAChB,MAAM,oBAAoB,CAAC;AAE5B,YAAY,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AACrD,YAAY,EAAE,0BAA0B,EAAE,MAAM,uBAAuB,CAAC;AAExE,MAAM,MAAM,cAAc,GAAG,OAAO,GAAG,KAAK,CAAC;AAE7C,MAAM,MAAM,UAAU,GAAG;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,cAAc,CAAC;IACtB,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,IAAI,CAAC,EAAE,UAAU,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG,MAAM,GAAG,OAAO,CAAC;AAElD,MAAM,MAAM,kBAAkB,GAAG;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,eAAe,EAAE,MAAM,CAAC;IACxB,cAAc,EAAE,MAAM,CAAC;CACxB,GAAG,0BAA0B,CAAC;AAE/B,KAAK,gBAAgB,GAAG;IACtB,KAAK,EAAE,UAAU,EAAE,CAAC;IACpB,MAAM,EAAE,kBAAkB,CAAC;IAC3B,MAAM,CAAC,EAAE,kBAAkB,CAAC;IAC5B,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,UAAU,CAAC,EAAE,SAAS,CAAC;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;CACrC,GAAG,IAAI,CAAC,cAAc,CAAC,WAAW,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC,CAAC;AA0E5D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2GG;AACH,wBAAgB,WAAW,CAAC,EAC1B,KAAK,EACL,MAAM,EACN,MAAe,EACf,KAAK,EACL,UAAU,EACV,QAAQ,EACR,YAAY,EACZ,GAAG,SAAS,EACb,EAAE,gBAAgB,GAAG,SAAS,CA6X9B"}
@@ -1,19 +1,57 @@
1
1
  'use client';
2
2
  import clsx from 'clsx';
3
- import { useEffect, useId, useState, } from 'react';
3
+ import { useEffect, useId, useRef, useState, } from 'react';
4
4
  import { createPortal } from 'react-dom';
5
- import { MdFullscreen, MdFullscreenExit, MdRotateRight, MdZoomIn, MdZoomOut, } from 'react-icons/md';
5
+ import { MdFullscreen, MdFullscreenExit, MdOpenInNew, MdRotateRight, MdZoomIn, MdZoomOut, } from 'react-icons/md';
6
6
  import { Each, Show } from '../../00-base';
7
7
  import { List, Paragraph } from '../../01-atoms';
8
8
  import { TabItem } from '../Tab/TabItem';
9
- import { ImageViewerImage } from './ImageViewerImage';
9
+ import { ImageViewerDocument, } from './ImageViewerDocument';
10
+ import { IMAGE_VIEWER_IMAGE_ATTRIBUTE, ImageViewerImage, } from './ImageViewerImage';
10
11
  const MIN_ZOOM = 1;
11
12
  const MAX_ZOOM = 3;
12
13
  const ZOOM_STEP = 0.5;
13
14
  const QUARTER_TURN = 90;
14
15
  const FULL_TURN = 360;
15
- const INITIAL_TRANSFORM = { zoom: MIN_ZOOM, rotation: 0 };
16
+ const KEYBOARD_PAN_STEP = 40;
17
+ const NO_OFFSET = { x: 0, y: 0 };
18
+ const INITIAL_TRANSFORM = {
19
+ zoom: MIN_ZOOM,
20
+ rotation: 0,
21
+ offset: NO_OFFSET,
22
+ };
23
+ /**
24
+ * Arrow keys move the viewport, so the image travels the opposite way, like
25
+ * scrolling.
26
+ */
27
+ const PAN_DIRECTIONS = {
28
+ ArrowLeft: { x: 1, y: 0 },
29
+ ArrowRight: { x: -1, y: 0 },
30
+ ArrowUp: { x: 0, y: 1 },
31
+ ArrowDown: { x: 0, y: -1 },
32
+ };
16
33
  const TOOL_CLASSNAME = 'hover:bg-gray-5 focus-visible:ring-lavender disabled:text-gray-3 dark:disabled:text-gray-1 dark:hover:bg-gray-1 flex h-8 w-8 cursor-pointer items-center justify-center rounded-sm text-lg text-black focus-visible:ring-2 focus-visible:outline-none disabled:cursor-not-allowed disabled:hover:bg-transparent dark:text-white';
34
+ /**
35
+ * How far the images may leave the center before their edge enters the pane:
36
+ * half the overflow on each axis, none when the image already fits. Read from
37
+ * the rendered elements so it holds for any crop, rotation and zoom; `scale`
38
+ * anticipates a zoom that has not been painted yet. In `split`, the pane that
39
+ * overflows the most wins, so every image can be reached.
40
+ */
41
+ const measurePanBounds = (panel, scale = 1) => Array.from(panel.querySelectorAll(`[${IMAGE_VIEWER_IMAGE_ATTRIBUTE}]`)).reduce((bounds, image) => {
42
+ const pane = image.parentElement?.getBoundingClientRect();
43
+ if (!pane)
44
+ return bounds;
45
+ const { width, height } = image.getBoundingClientRect();
46
+ return {
47
+ x: Math.max(bounds.x, (width * scale - pane.width) / 2),
48
+ y: Math.max(bounds.y, (height * scale - pane.height) / 2),
49
+ };
50
+ }, NO_OFFSET);
51
+ const clampOffset = (offset, bounds) => ({
52
+ x: Math.min(Math.max(offset.x, -bounds.x), bounds.x),
53
+ y: Math.min(Math.max(offset.y, -bounds.y), bounds.y),
54
+ });
17
55
  /**
18
56
  * ImageViewer component for inspecting one or more images of the same subject.
19
57
  *
@@ -22,6 +60,12 @@ const TOOL_CLASSNAME = 'hover:bg-gray-5 focus-visible:ring-lavender disabled:tex
22
60
  * changes, whether the user picked a tab or the consumer moved `activeId`: a
23
61
  * transform that made sense for one angle rarely makes sense for the next.
24
62
  *
63
+ * Once zoomed in, the image can be panned: by dragging it with the pointer
64
+ * (mouse, touch or pen) or with the arrow keys while the panel has focus. The
65
+ * pan never leaves a gap between the image and the frame; zooming in keeps the
66
+ * point under inspection centered, zooming out to the minimum, rotating and
67
+ * toggling full screen center the image again.
68
+ *
25
69
  * Uncontrolled by default. Passing `activeId` makes the consumer own the active
26
70
  * view, so something outside the viewer (a side panel, a "next pending" action)
27
71
  * can follow or drive it; `onViewChange` reports tab picks in both modes.
@@ -37,6 +81,14 @@ const TOOL_CLASSNAME = 'hover:bg-gray-5 focus-visible:ring-lavender disabled:tex
37
81
  * A view's `crop` draws only that region of its image, fitted to the frame
38
82
  * like the whole image would be — a face inside a document, for instance.
39
83
  *
84
+ * A view with `type: 'pdf'` is rendered page by page into images with pdf.js,
85
+ * loaded on first use, so zoom, rotation and pan work on it exactly as on a
86
+ * photo and there is a single toolbar. A document with several pages shows a
87
+ * pager over the page; the toolbar gains an "open in a new tab" action for
88
+ * the original file. The browser fetches the PDF itself, so its origin must
89
+ * allow CORS; when it cannot be loaded, the view shows its description and
90
+ * the same link.
91
+ *
40
92
  * @component
41
93
  * @example
42
94
  * const [viewId, setViewId] = useState('front');
@@ -82,9 +134,23 @@ const TOOL_CLASSNAME = 'hover:bg-gray-5 focus-visible:ring-lavender disabled:tex
82
134
  * labels={labels}
83
135
  * />
84
136
  *
137
+ * @example
138
+ * <ImageViewer
139
+ * title="Insurance policy"
140
+ * views={[
141
+ * { id: 'policy', label: 'Policy', src: '/policy.pdf', alt: 'Insurance policy', type: 'pdf' },
142
+ * ]}
143
+ * labels={{
144
+ * ...labels,
145
+ * openDocument: 'Open PDF',
146
+ * previousPage: 'Previous page',
147
+ * nextPage: 'Next page',
148
+ * }}
149
+ * />
150
+ *
85
151
  * @param {Object} props - The properties of the ImageViewer component.
86
- * @param {TImageView[]} props.views - Images to display. In `tabs`, more than one renders a tab per view; in `split`, a pane per view. A view's optional `indicator` sits after its label and becomes part of the tab's accessible name, so give it its own (for an icon, `role="img"` and `aria-label`). In `tabs` with a single view there are no tabs, so no indicator is shown. A view's optional `crop` (`left`, `top`, `width`, `height` as fractions from 0 to 1 of the image) shows only that region; a crop outside the image is clamped to it, and one with no area left falls back to the whole image.
87
- * @param {TImageViewerLabels} props.labels - Accessible names of the toolbar actions.
152
+ * @param {TImageView[]} props.views - Files to display. In `tabs`, more than one renders a tab per view; in `split`, a pane per view. A view's optional `indicator` sits after its label and becomes part of the tab's accessible name, so give it its own (for an icon, `role="img"` and `aria-label`). In `tabs` with a single view there are no tabs, so no indicator is shown. A view's optional `crop` (`left`, `top`, `width`, `height` as fractions from 0 to 1 of the image) shows only that region; a crop outside the image is clamped to it, and one with no area left falls back to the whole image. A view's `type` is `image` unless set to `pdf`; `crop` is ignored on a `pdf`.
153
+ * @param {TImageViewerLabels} props.labels - Accessible names of the toolbar actions. With `pdf` views, `openDocument` names the action that opens the original file in a new tab, and `previousPage` / `nextPage` name the pager of a document with several pages; without the pair, only the first page is reachable.
88
154
  * @param {TImageViewerLayout} [props.layout='tabs'] - `tabs` shows one view at a time; `split` shows every view at once, one pane each.
89
155
  * @param {ReactNode} [props.title] - Optional heading rendered on the left of the toolbar.
90
156
  * @param {ReactNode} [props.emptyState] - Content rendered when there is no image.
@@ -98,6 +164,9 @@ export function ImageViewer({ views, labels, layout = 'tabs', title, emptyState,
98
164
  const [internalIndex, setInternalIndex] = useState(0);
99
165
  const [transform, setTransform] = useState(INITIAL_TRANSFORM);
100
166
  const [isFullscreen, setIsFullscreen] = useState(false);
167
+ const [isDragging, setIsDragging] = useState(false);
168
+ const panelRef = useRef(null);
169
+ const dragRef = useRef(null);
101
170
  const generatedId = useId();
102
171
  /**
103
172
  * Se sigue la firma de las vistas y no el arreglo: un consumidor que lo
@@ -106,6 +175,7 @@ export function ImageViewer({ views, labels, layout = 'tabs', title, emptyState,
106
175
  */
107
176
  const viewsSignature = views.map(({ id }) => id).join('|');
108
177
  useEffect(() => {
178
+ // eslint-disable-next-line react-hooks/set-state-in-effect -- a different set of views starts again from the first one, without zoom or rotation
109
179
  setInternalIndex(0);
110
180
  setTransform(INITIAL_TRANSFORM);
111
181
  }, [viewsSignature]);
@@ -124,11 +194,17 @@ export function ImageViewer({ views, labels, layout = 'tabs', title, emptyState,
124
194
  ? Math.max(views.findIndex(({ id }) => id === activeId), 0)
125
195
  : internalIndex;
126
196
  const activeView = views[activeIndex] ?? views[0];
127
- const hasImage = Boolean(activeView);
197
+ const hasView = Boolean(activeView);
128
198
  const isSplit = layout === 'split';
129
199
  const hasTabs = !isSplit && views.length > 1;
130
- const { zoom, rotation } = transform;
131
- const imageStyle = { transform: `rotate(${rotation}deg) scale(${zoom})` };
200
+ const shownViews = isSplit ? views : activeView ? [activeView] : [];
201
+ const documentHref = !isSplit && activeView?.type === 'pdf' ? activeView.src : undefined;
202
+ const panelLabel = shownViews.map(({ alt }) => alt).join(', ') || undefined;
203
+ const { zoom, rotation, offset } = transform;
204
+ const canPan = hasView && zoom > MIN_ZOOM;
205
+ const imageStyle = {
206
+ transform: `translate(${offset.x}px, ${offset.y}px) rotate(${rotation}deg) scale(${zoom})`,
207
+ };
132
208
  /**
133
209
  * En modo controlado la vista puede cambiar sin pasar por `selectView`, asi
134
210
  * que el reinicio se ata a la vista activa y no al clic. Guardar el zoom por
@@ -149,6 +225,98 @@ export function ImageViewer({ views, labels, layout = 'tabs', title, emptyState,
149
225
  if (view.id !== activeView?.id)
150
226
  onViewChange?.(view.id);
151
227
  };
228
+ /**
229
+ * El desplazamiento se escala con el zoom para que el punto que se estaba
230
+ * mirando siga en el centro. Al acercar siempre cabe; al alejar puede quedar
231
+ * fuera del nuevo limite, asi que se acota midiendo con la escala destino.
232
+ */
233
+ const changeZoom = (delta) => {
234
+ const panel = panelRef.current;
235
+ setTransform((current) => {
236
+ const nextZoom = Math.min(Math.max(current.zoom + delta, MIN_ZOOM), MAX_ZOOM);
237
+ if (nextZoom === MIN_ZOOM) {
238
+ return { ...current, zoom: nextZoom, offset: NO_OFFSET };
239
+ }
240
+ const scale = nextZoom / current.zoom;
241
+ const scaled = {
242
+ x: current.offset.x * scale,
243
+ y: current.offset.y * scale,
244
+ };
245
+ return {
246
+ ...current,
247
+ zoom: nextZoom,
248
+ offset: panel
249
+ ? clampOffset(scaled, measurePanBounds(panel, scale))
250
+ : scaled,
251
+ };
252
+ });
253
+ };
254
+ const rotate = () => setTransform((current) => ({
255
+ ...current,
256
+ rotation: (current.rotation + QUARTER_TURN) % FULL_TURN,
257
+ offset: NO_OFFSET,
258
+ }));
259
+ const recenter = () => setTransform((current) => ({ ...current, offset: NO_OFFSET }));
260
+ const toggleFullscreen = () => {
261
+ setIsFullscreen((current) => !current);
262
+ recenter();
263
+ };
264
+ /**
265
+ * Los controles que viven sobre la imagen (el paginador de un PDF) deben
266
+ * recibir su clic: capturar el puntero aqui se lo quitaria.
267
+ */
268
+ const isControl = (target) => target instanceof Element && target.closest('button, a') !== null;
269
+ const startDrag = (event) => {
270
+ if (!canPan || event.button !== 0 || isControl(event.target))
271
+ return;
272
+ event.currentTarget.setPointerCapture(event.pointerId);
273
+ dragRef.current = {
274
+ pointerId: event.pointerId,
275
+ startX: event.clientX,
276
+ startY: event.clientY,
277
+ origin: offset,
278
+ bounds: measurePanBounds(event.currentTarget),
279
+ };
280
+ setIsDragging(true);
281
+ };
282
+ const moveDrag = (event) => {
283
+ const drag = dragRef.current;
284
+ if (drag?.pointerId !== event.pointerId)
285
+ return;
286
+ const next = clampOffset({
287
+ x: drag.origin.x + event.clientX - drag.startX,
288
+ y: drag.origin.y + event.clientY - drag.startY,
289
+ }, drag.bounds);
290
+ setTransform((current) => ({ ...current, offset: next }));
291
+ };
292
+ const endDrag = (event) => {
293
+ if (dragRef.current?.pointerId !== event.pointerId)
294
+ return;
295
+ dragRef.current = null;
296
+ setIsDragging(false);
297
+ };
298
+ const panWithKeyboard = (event) => {
299
+ const direction = PAN_DIRECTIONS[event.key];
300
+ if (!direction || !canPan)
301
+ return;
302
+ event.preventDefault();
303
+ const bounds = measurePanBounds(event.currentTarget);
304
+ setTransform((current) => ({
305
+ ...current,
306
+ offset: clampOffset({
307
+ x: current.offset.x + direction.x * KEYBOARD_PAN_STEP,
308
+ y: current.offset.y + direction.y * KEYBOARD_PAN_STEP,
309
+ }, bounds),
310
+ }));
311
+ };
312
+ const renderView = (view) => (<Show key={view.id}>
313
+ <Show.When isTrue={view.type === 'pdf'}>
314
+ <ImageViewerDocument src={view.src} alt={view.alt} style={imageStyle} isAnimated={!isDragging} labels={labels} onPageChange={recenter}/>
315
+ </Show.When>
316
+ <Show.Else>
317
+ <ImageViewerImage src={view.src} alt={view.alt} crop={view.crop} style={imageStyle} isAnimated={!isDragging}/>
318
+ </Show.Else>
319
+ </Show>);
152
320
  const frame = (<section {...restProps} className={clsx('border-gray-5 dark:border-gray-1 flex min-h-0 flex-col overflow-hidden rounded-lg border', isFullscreen ? 'h-full w-full bg-white dark:bg-black' : undefined, !isFullscreen ? restProps.className : undefined)}>
153
321
  <div className="border-gray-5 bg-gray-6 dark:border-gray-1 dark:bg-black-1 flex flex-none items-center justify-between gap-4 border-b px-4 py-3">
154
322
  <Show>
@@ -159,25 +327,19 @@ export function ImageViewer({ views, labels, layout = 'tabs', title, emptyState,
159
327
  </Show.When>
160
328
  </Show>
161
329
  <div className="ml-auto flex items-center gap-1.5">
162
- <button type="button" aria-label={labels.zoomOut} disabled={!hasImage || zoom <= MIN_ZOOM} onClick={() => setTransform((current) => ({
163
- ...current,
164
- zoom: current.zoom - ZOOM_STEP,
165
- }))} className={TOOL_CLASSNAME}>
330
+ {!!documentHref && !!labels.openDocument && (<a href={documentHref} target="_blank" rel="noopener noreferrer" aria-label={labels.openDocument} className={TOOL_CLASSNAME}>
331
+ <MdOpenInNew aria-hidden="true"/>
332
+ </a>)}
333
+ <button type="button" aria-label={labels.zoomOut} disabled={!hasView || zoom <= MIN_ZOOM} onClick={() => changeZoom(-ZOOM_STEP)} className={TOOL_CLASSNAME}>
166
334
  <MdZoomOut aria-hidden="true"/>
167
335
  </button>
168
- <button type="button" aria-label={labels.zoomIn} disabled={!hasImage || zoom >= MAX_ZOOM} onClick={() => setTransform((current) => ({
169
- ...current,
170
- zoom: current.zoom + ZOOM_STEP,
171
- }))} className={TOOL_CLASSNAME}>
336
+ <button type="button" aria-label={labels.zoomIn} disabled={!hasView || zoom >= MAX_ZOOM} onClick={() => changeZoom(ZOOM_STEP)} className={TOOL_CLASSNAME}>
172
337
  <MdZoomIn aria-hidden="true"/>
173
338
  </button>
174
- <button type="button" aria-label={labels.rotate} disabled={!hasImage} onClick={() => setTransform((current) => ({
175
- ...current,
176
- rotation: (current.rotation + QUARTER_TURN) % FULL_TURN,
177
- }))} className={TOOL_CLASSNAME}>
339
+ <button type="button" aria-label={labels.rotate} disabled={!hasView} onClick={rotate} className={TOOL_CLASSNAME}>
178
340
  <MdRotateRight aria-hidden="true"/>
179
341
  </button>
180
- <button type="button" aria-label={isFullscreen ? labels.exitFullscreen : labels.enterFullscreen} aria-pressed={isFullscreen} disabled={!hasImage} onClick={() => setIsFullscreen((current) => !current)} className={TOOL_CLASSNAME}>
342
+ <button type="button" aria-label={isFullscreen ? labels.exitFullscreen : labels.enterFullscreen} aria-pressed={isFullscreen} disabled={!hasView} onClick={toggleFullscreen} className={TOOL_CLASSNAME}>
181
343
  {isFullscreen ? (<MdFullscreenExit aria-hidden="true"/>) : (<MdFullscreen aria-hidden="true"/>)}
182
344
  </button>
183
345
  </div>
@@ -200,27 +362,27 @@ export function ImageViewer({ views, labels, layout = 'tabs', title, emptyState,
200
362
  </Show.When>
201
363
  </Show>
202
364
 
203
- <div id={`${generatedId}-panel`} role={hasTabs ? 'tabpanel' : undefined} aria-labelledby={hasTabs ? `${generatedId}-tab-${activeIndex}` : undefined} className="bg-gray-7 dark:bg-black-2 flex min-h-0 flex-1 items-center justify-center overflow-hidden p-5">
365
+ <div ref={panelRef} id={`${generatedId}-panel`} role={hasTabs ? 'tabpanel' : 'group'} aria-labelledby={hasTabs ? `${generatedId}-tab-${activeIndex}` : undefined} aria-label={hasTabs ? undefined : panelLabel} tabIndex={canPan ? 0 : undefined} onPointerDown={startDrag} onPointerMove={moveDrag} onPointerUp={endDrag} onPointerCancel={endDrag} onKeyDown={panWithKeyboard} className={clsx('bg-gray-7 dark:bg-black-2 focus-visible:ring-lavender flex min-h-0 flex-1 items-center justify-center overflow-hidden p-5 focus-visible:ring-2 focus-visible:outline-none focus-visible:ring-inset', canPan && 'touch-none select-none', canPan && (isDragging ? 'cursor-grabbing' : 'cursor-grab'))}>
204
366
  <Show>
205
- <Show.When isTrue={!!hasImage && isSplit}>
367
+ <Show.When isTrue={!!hasView && isSplit}>
206
368
  <div className="grid h-full w-full auto-rows-fr grid-cols-1 gap-5 sm:auto-cols-fr sm:grid-flow-col sm:grid-cols-none sm:grid-rows-1">
207
- <Each of={views} render={({ id, label, indicator, src, alt, crop }) => (<figure key={id} className="flex min-h-0 min-w-0 flex-col gap-2">
369
+ <Each of={views} render={(view) => (<figure key={view.id} className="flex min-h-0 min-w-0 flex-col gap-2">
208
370
  <figcaption className="flex flex-none items-center gap-1.5">
209
371
  <Paragraph size="subtitle-2" className="dark:text-white">
210
- {label}
372
+ {view.label}
211
373
  </Paragraph>
212
- {!!indicator && (<span className="flex flex-none items-center">
213
- {indicator}
374
+ {!!view.indicator && (<span className="flex flex-none items-center">
375
+ {view.indicator}
214
376
  </span>)}
215
377
  </figcaption>
216
378
  <div className="flex min-h-0 flex-1 items-center justify-center overflow-hidden">
217
- <ImageViewerImage src={src} alt={alt} crop={crop} style={imageStyle}/>
379
+ {renderView(view)}
218
380
  </div>
219
381
  </figure>)}/>
220
382
  </div>
221
383
  </Show.When>
222
- <Show.When isTrue={hasImage}>
223
- {!!activeView && (<ImageViewerImage key={activeView.id} src={activeView.src} alt={activeView.alt} crop={activeView.crop} style={imageStyle}/>)}
384
+ <Show.When isTrue={hasView}>
385
+ {!!activeView && renderView(activeView)}
224
386
  </Show.When>
225
387
  <Show.Else>{emptyState}</Show.Else>
226
388
  </Show>
@@ -1 +1 @@
1
- {"version":3,"file":"ImageViewer.jsx","sourceRoot":"","sources":["../../../../src/components/02-molecules/ImageViewer/ImageViewer.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EACL,SAAS,EACT,KAAK,EACL,QAAQ,GAGT,MAAM,OAAO,CAAC;AACf,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,EACL,YAAY,EACZ,gBAAgB,EAChB,aAAa,EACb,QAAQ,EACR,SAAS,GACV,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AACzC,OAAO,EAAE,gBAAgB,EAAmB,MAAM,oBAAoB,CAAC;AAsCvE,MAAM,QAAQ,GAAG,CAAC,CAAC;AACnB,MAAM,QAAQ,GAAG,CAAC,CAAC;AACnB,MAAM,SAAS,GAAG,GAAG,CAAC;AACtB,MAAM,YAAY,GAAG,EAAE,CAAC;AACxB,MAAM,SAAS,GAAG,GAAG,CAAC;AACtB,MAAM,iBAAiB,GAAe,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC;AAEtE,MAAM,cAAc,GAClB,iUAAiU,CAAC;AAEpU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+EG;AACH,MAAM,UAAU,WAAW,CAAC,EAC1B,KAAK,EACL,MAAM,EACN,MAAM,GAAG,MAAM,EACf,KAAK,EACL,UAAU,EACV,QAAQ,EACR,YAAY,EACZ,GAAG,SAAS,EACK;IACjB,MAAM,CAAC,aAAa,EAAE,gBAAgB,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;IACtD,MAAM,CAAC,SAAS,EAAE,YAAY,CAAC,GAAG,QAAQ,CAAa,iBAAiB,CAAC,CAAC;IAC1E,MAAM,CAAC,YAAY,EAAE,eAAe,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IACxD,MAAM,WAAW,GAAG,KAAK,EAAE,CAAC;IAE5B;;;;OAIG;IACH,MAAM,cAAc,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAE3D,SAAS,CAAC,GAAG,EAAE;QACb,gBAAgB,CAAC,CAAC,CAAC,CAAC;QACpB,YAAY,CAAC,iBAAiB,CAAC,CAAC;IAClC,CAAC,EAAE,CAAC,cAAc,CAAC,CAAC,CAAC;IAErB,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,YAAY;YAAE,OAAO;QAE1B,MAAM,aAAa,GAAG,CAAC,KAAoB,EAAE,EAAE;YAC7C,IAAI,KAAK,CAAC,GAAG,KAAK,QAAQ;gBAAE,eAAe,CAAC,KAAK,CAAC,CAAC;QACrD,CAAC,CAAC;QAEF,QAAQ,CAAC,gBAAgB,CAAC,SAAS,EAAE,aAAa,CAAC,CAAC;QACpD,OAAO,GAAG,EAAE,CAAC,QAAQ,CAAC,mBAAmB,CAAC,SAAS,EAAE,aAAa,CAAC,CAAC;IACtE,CAAC,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC;IAEnB,MAAM,YAAY,GAAG,QAAQ,KAAK,SAAS,CAAC;IAC5C,MAAM,WAAW,GAAG,YAAY;QAC9B,CAAC,CAAC,IAAI,CAAC,GAAG,CACN,KAAK,CAAC,SAAS,CAAC,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,KAAK,QAAQ,CAAC,EAC5C,CAAC,CACF;QACH,CAAC,CAAC,aAAa,CAAC;IAClB,MAAM,UAAU,GAAG,KAAK,CAAC,WAAW,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC;IAClD,MAAM,QAAQ,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IACrC,MAAM,OAAO,GAAG,MAAM,KAAK,OAAO,CAAC;IACnC,MAAM,OAAO,GAAG,CAAC,OAAO,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC;IAC7C,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,SAAS,CAAC;IACrC,MAAM,UAAU,GAAG,EAAE,SAAS,EAAE,UAAU,QAAQ,cAAc,IAAI,GAAG,EAAE,CAAC;IAE1E;;;;OAIG;IACH,MAAM,CAAC,eAAe,EAAE,kBAAkB,CAAC,GAAG,QAAQ,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;IACvE,IAAI,UAAU,EAAE,EAAE,KAAK,eAAe,EAAE,CAAC;QACvC,kBAAkB,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;QACnC,YAAY,CAAC,iBAAiB,CAAC,CAAC;IAClC,CAAC;IAED,MAAM,UAAU,GAAG,CAAC,KAAa,EAAE,EAAE;QACnC,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC;QAC1B,IAAI,CAAC,IAAI;YAAE,OAAO;QAElB,YAAY,CAAC,iBAAiB,CAAC,CAAC;QAChC,IAAI,CAAC,YAAY;YAAE,gBAAgB,CAAC,KAAK,CAAC,CAAC;QAC3C,IAAI,IAAI,CAAC,EAAE,KAAK,UAAU,EAAE,EAAE;YAAE,YAAY,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC1D,CAAC,CAAC;IAEF,MAAM,KAAK,GAAG,CACZ,CAAC,OAAO,CACN,IAAI,SAAS,CAAC,CACd,SAAS,CAAC,CAAC,IAAI,CACb,0FAA0F,EAC1F,YAAY,CAAC,CAAC,CAAC,sCAAsC,CAAC,CAAC,CAAC,SAAS,EACjE,CAAC,YAAY,CAAC,CAAC,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAChD,CAAC,CAEF;MAAA,CAAC,GAAG,CAAC,SAAS,CAAC,iIAAiI,CAC9I;QAAA,CAAC,IAAI,CACH;UAAA,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAChC;YAAA,CAAC,SAAS,CAAC,IAAI,CAAC,YAAY,CAAC,SAAS,CAAC,iBAAiB,CACtD;cAAA,CAAC,KAAK,CACR;YAAA,EAAE,SAAS,CACb;UAAA,EAAE,IAAI,CAAC,IAAI,CACb;QAAA,EAAE,IAAI,CACN;QAAA,CAAC,GAAG,CAAC,SAAS,CAAC,mCAAmC,CAChD;UAAA,CAAC,MAAM,CACL,IAAI,CAAC,QAAQ,CACb,UAAU,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAC3B,QAAQ,CAAC,CAAC,CAAC,QAAQ,IAAI,IAAI,IAAI,QAAQ,CAAC,CACxC,OAAO,CAAC,CAAC,GAAG,EAAE,CACZ,YAAY,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;YACzB,GAAG,OAAO;YACV,IAAI,EAAE,OAAO,CAAC,IAAI,GAAG,SAAS;SAC/B,CAAC,CACJ,CAAC,CACD,SAAS,CAAC,CAAC,cAAc,CAAC,CAE1B;YAAA,CAAC,SAAS,CAAC,WAAW,CAAC,MAAM,EAC/B;UAAA,EAAE,MAAM,CACR;UAAA,CAAC,MAAM,CACL,IAAI,CAAC,QAAQ,CACb,UAAU,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAC1B,QAAQ,CAAC,CAAC,CAAC,QAAQ,IAAI,IAAI,IAAI,QAAQ,CAAC,CACxC,OAAO,CAAC,CAAC,GAAG,EAAE,CACZ,YAAY,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;YACzB,GAAG,OAAO;YACV,IAAI,EAAE,OAAO,CAAC,IAAI,GAAG,SAAS;SAC/B,CAAC,CACJ,CAAC,CACD,SAAS,CAAC,CAAC,cAAc,CAAC,CAE1B;YAAA,CAAC,QAAQ,CAAC,WAAW,CAAC,MAAM,EAC9B;UAAA,EAAE,MAAM,CACR;UAAA,CAAC,MAAM,CACL,IAAI,CAAC,QAAQ,CACb,UAAU,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAC1B,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CACpB,OAAO,CAAC,CAAC,GAAG,EAAE,CACZ,YAAY,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;YACzB,GAAG,OAAO;YACV,QAAQ,EAAE,CAAC,OAAO,CAAC,QAAQ,GAAG,YAAY,CAAC,GAAG,SAAS;SACxD,CAAC,CACJ,CAAC,CACD,SAAS,CAAC,CAAC,cAAc,CAAC,CAE1B;YAAA,CAAC,aAAa,CAAC,WAAW,CAAC,MAAM,EACnC;UAAA,EAAE,MAAM,CACR;UAAA,CAAC,MAAM,CACL,IAAI,CAAC,QAAQ,CACb,UAAU,CAAC,CACT,YAAY,CAAC,CAAC,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,CAAC,MAAM,CAAC,eAChD,CAAC,CACD,YAAY,CAAC,CAAC,YAAY,CAAC,CAC3B,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CACpB,OAAO,CAAC,CAAC,GAAG,EAAE,CAAC,eAAe,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CACtD,SAAS,CAAC,CAAC,cAAc,CAAC,CAE1B;YAAA,CAAC,YAAY,CAAC,CAAC,CAAC,CACd,CAAC,gBAAgB,CAAC,WAAW,CAAC,MAAM,EAAG,CACxC,CAAC,CAAC,CAAC,CACF,CAAC,YAAY,CAAC,WAAW,CAAC,MAAM,EAAG,CACpC,CACH;UAAA,EAAE,MAAM,CACV;QAAA,EAAE,GAAG,CACP;MAAA,EAAE,GAAG,CAEL;;MAAA,CAAC,IAAI,CACH;QAAA,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CACzB;UAAA,CAAC,IAAI,CACH,IAAI,CAAC,SAAS,CACd,gBAAgB,CAAC,YAAY,CAC7B,WAAW,CAAC,YAAY,CACxB,SAAS,CAAC,0EAA0E,CAEpF;YAAA,CAAC,IAAI,CACH,EAAE,CAAC,CAAC,KAAK,CAAC,CACV,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,EAAE,KAAK,EAAE,EAAE,CAAC,CAC3C,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,cAAc,CAC9B;kBAAA,CAAC,OAAO,CACN,EAAE,CAAC,CAAC,GAAG,WAAW,QAAQ,KAAK,EAAE,CAAC,CAClC,aAAa,CAAC,CAAC,GAAG,WAAW,QAAQ,CAAC,CACtC,aAAa,CAAC,CAAC,KAAK,KAAK,WAAW,CAAC,CACrC,QAAQ,CAAC,CAAC,KAAK,KAAK,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CACzC,QAAQ,CAAC,CAAC,KAAK,KAAK,WAAW,CAAC,CAChC,OAAO,CAAC,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CACjC,SAAS,CAAC,MAAM,CAEhB;oBAAA,CAAC,IAAI,CAAC,SAAS,CAAC,kCAAkC,CAChD;sBAAA,CAAC,KAAK,CACN;sBAAA,CAAC,CAAC,CAAC,SAAS,IAAI,CACd,CAAC,IAAI,CAAC,SAAS,CAAC,6BAA6B,CAC3C;0BAAA,CAAC,SAAS,CACZ;wBAAA,EAAE,IAAI,CAAC,CACR,CACH;oBAAA,EAAE,IAAI,CACR;kBAAA,EAAE,OAAO,CACX;gBAAA,EAAE,EAAE,CAAC,CACN,CAAC,EAEN;UAAA,EAAE,IAAI,CACR;QAAA,EAAE,IAAI,CAAC,IAAI,CACb;MAAA,EAAE,IAAI,CAEN;;MAAA,CAAC,GAAG,CACF,EAAE,CAAC,CAAC,GAAG,WAAW,QAAQ,CAAC,CAC3B,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC,CACvC,eAAe,CAAC,CACd,OAAO,CAAC,CAAC,CAAC,GAAG,WAAW,QAAQ,WAAW,EAAE,CAAC,CAAC,CAAC,SAClD,CAAC,CACD,SAAS,CAAC,+FAA+F,CAEzG;QAAA,CAAC,IAAI,CACH;UAAA,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,QAAQ,IAAI,OAAO,CAAC,CACvC;YAAA,CAAC,GAAG,CAAC,SAAS,CAAC,qHAAqH,CAClI;cAAA,CAAC,IAAI,CACH,EAAE,CAAC,CAAC,KAAK,CAAC,CACV,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,CACpD,CAAC,MAAM,CACL,GAAG,CAAC,CAAC,EAAE,CAAC,CACR,SAAS,CAAC,qCAAqC,CAE/C;oBAAA,CAAC,UAAU,CAAC,SAAS,CAAC,qCAAqC,CACzD;sBAAA,CAAC,SAAS,CAAC,IAAI,CAAC,YAAY,CAAC,SAAS,CAAC,iBAAiB,CACtD;wBAAA,CAAC,KAAK,CACR;sBAAA,EAAE,SAAS,CACX;sBAAA,CAAC,CAAC,CAAC,SAAS,IAAI,CACd,CAAC,IAAI,CAAC,SAAS,CAAC,6BAA6B,CAC3C;0BAAA,CAAC,SAAS,CACZ;wBAAA,EAAE,IAAI,CAAC,CACR,CACH;oBAAA,EAAE,UAAU,CACZ;oBAAA,CAAC,GAAG,CAAC,SAAS,CAAC,iEAAiE,CAC9E;sBAAA,CAAC,gBAAgB,CACf,GAAG,CAAC,CAAC,GAAG,CAAC,CACT,GAAG,CAAC,CAAC,GAAG,CAAC,CACT,IAAI,CAAC,CAAC,IAAI,CAAC,CACX,KAAK,CAAC,CAAC,UAAU,CAAC,EAEtB;oBAAA,EAAE,GAAG,CACP;kBAAA,EAAE,MAAM,CAAC,CACV,CAAC,EAEN;YAAA,EAAE,GAAG,CACP;UAAA,EAAE,IAAI,CAAC,IAAI,CACX;UAAA,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,CAC1B;YAAA,CAAC,CAAC,CAAC,UAAU,IAAI,CACf,CAAC,gBAAgB,CACf,GAAG,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,CACnB,GAAG,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,CACpB,GAAG,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,CACpB,IAAI,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,CACtB,KAAK,CAAC,CAAC,UAAU,CAAC,EAClB,CACH,CACH;UAAA,EAAE,IAAI,CAAC,IAAI,CACX;UAAA,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,UAAU,CAAC,EAAE,IAAI,CAAC,IAAI,CACpC;QAAA,EAAE,IAAI,CACR;MAAA,EAAE,GAAG,CACP;IAAA,EAAE,OAAO,CAAC,CACX,CAAC;IAEF,IAAI,CAAC,YAAY;QAAE,OAAO,KAAK,CAAC;IAEhC,OAAO,YAAY,CACjB,CAAC,GAAG,CAAC,SAAS,CAAC,qEAAqE,CAClF;MAAA,CAAC,GAAG,CAAC,SAAS,CAAC,yBAAyB,CAAC,CAAC,KAAK,CAAC,EAAE,GAAG,CACvD;IAAA,EAAE,GAAG,CAAC,EACN,QAAQ,CAAC,IAAI,CACd,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"ImageViewer.jsx","sourceRoot":"","sources":["../../../../src/components/02-molecules/ImageViewer/ImageViewer.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,52 @@
1
+ import { type CSSProperties, type ReactNode } from 'react';
2
+ export type TImageViewerDocumentLabels = {
3
+ openDocument?: string;
4
+ previousPage?: string;
5
+ nextPage?: string;
6
+ };
7
+ type ImageViewerDocumentProps = {
8
+ src: string;
9
+ alt: string;
10
+ style: CSSProperties;
11
+ isAnimated: boolean;
12
+ labels: TImageViewerDocumentLabels;
13
+ onPageChange?: () => void;
14
+ };
15
+ /**
16
+ * PDF of one `ImageViewer` view. Each page is rendered to an image with
17
+ * pdf.js and shown through the same path as a photo, so the viewer's zoom,
18
+ * rotation and pan apply to it and the document brings no toolbar of its own.
19
+ *
20
+ * A document with several pages gets a pager over the page, when
21
+ * `labels.previousPage` and `labels.nextPage` are given; without them only
22
+ * the first page is reachable, since the buttons would have no name.
23
+ *
24
+ * While the document or the page loads it shows a spinner. When the file
25
+ * cannot be fetched or parsed it shows the description and, with
26
+ * `labels.openDocument`, a link that opens the file in a new tab.
27
+ *
28
+ * Internal to `ImageViewer`: it is not exported from the library.
29
+ *
30
+ * @component
31
+ * @example
32
+ * <ImageViewerDocument
33
+ * src="/policy.pdf"
34
+ * alt="Insurance policy"
35
+ * style={{ transform: 'translate(0px, 0px) rotate(0deg) scale(1)' }}
36
+ * isAnimated
37
+ * labels={{ openDocument: 'Open PDF', previousPage: 'Previous page', nextPage: 'Next page' }}
38
+ * />
39
+ *
40
+ * @param {Object} props - The properties of the ImageViewerDocument component.
41
+ * @param {string} props.src - PDF URL. The browser fetches it, so its origin must allow CORS.
42
+ * @param {string} props.alt - Accessible description of the document.
43
+ * @param {CSSProperties} props.style - Pan, zoom and rotation computed by the viewer.
44
+ * @param {boolean} props.isAnimated - Eases the transform; off while the user drags.
45
+ * @param {TImageViewerDocumentLabels} props.labels - `openDocument` names the fallback link; `previousPage` and `nextPage` name the pager buttons.
46
+ * @param {() => void} [props.onPageChange] - Called after the user moves to another page, so the viewer can recenter.
47
+ *
48
+ * @returns {ReactNode} The rendered document.
49
+ */
50
+ export declare function ImageViewerDocument({ src, alt, style, isAnimated, labels, onPageChange, }: ImageViewerDocumentProps): ReactNode;
51
+ export {};
52
+ //# sourceMappingURL=ImageViewerDocument.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ImageViewerDocument.d.ts","sourceRoot":"","sources":["../../../../src/components/02-molecules/ImageViewer/ImageViewerDocument.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,aAAa,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAM3D,MAAM,MAAM,0BAA0B,GAAG;IACvC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,KAAK,wBAAwB,GAAG;IAC9B,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,aAAa,CAAC;IACrB,UAAU,EAAE,OAAO,CAAC;IACpB,MAAM,EAAE,0BAA0B,CAAC;IACnC,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;CAC3B,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,wBAAgB,mBAAmB,CAAC,EAClC,GAAG,EACH,GAAG,EACH,KAAK,EACL,UAAU,EACV,MAAM,EACN,YAAY,GACb,EAAE,wBAAwB,GAAG,SAAS,CA2EtC"}
@@ -0,0 +1,78 @@
1
+ 'use client';
2
+ import { MdChevronLeft, MdChevronRight, MdPictureAsPdf } from 'react-icons/md';
3
+ import { IconButton, Paragraph, Spinner } from '../../01-atoms';
4
+ import { ImageViewerImage } from './ImageViewerImage';
5
+ import { usePdfPages } from './usePdfPages';
6
+ /**
7
+ * PDF of one `ImageViewer` view. Each page is rendered to an image with
8
+ * pdf.js and shown through the same path as a photo, so the viewer's zoom,
9
+ * rotation and pan apply to it and the document brings no toolbar of its own.
10
+ *
11
+ * A document with several pages gets a pager over the page, when
12
+ * `labels.previousPage` and `labels.nextPage` are given; without them only
13
+ * the first page is reachable, since the buttons would have no name.
14
+ *
15
+ * While the document or the page loads it shows a spinner. When the file
16
+ * cannot be fetched or parsed it shows the description and, with
17
+ * `labels.openDocument`, a link that opens the file in a new tab.
18
+ *
19
+ * Internal to `ImageViewer`: it is not exported from the library.
20
+ *
21
+ * @component
22
+ * @example
23
+ * <ImageViewerDocument
24
+ * src="/policy.pdf"
25
+ * alt="Insurance policy"
26
+ * style={{ transform: 'translate(0px, 0px) rotate(0deg) scale(1)' }}
27
+ * isAnimated
28
+ * labels={{ openDocument: 'Open PDF', previousPage: 'Previous page', nextPage: 'Next page' }}
29
+ * />
30
+ *
31
+ * @param {Object} props - The properties of the ImageViewerDocument component.
32
+ * @param {string} props.src - PDF URL. The browser fetches it, so its origin must allow CORS.
33
+ * @param {string} props.alt - Accessible description of the document.
34
+ * @param {CSSProperties} props.style - Pan, zoom and rotation computed by the viewer.
35
+ * @param {boolean} props.isAnimated - Eases the transform; off while the user drags.
36
+ * @param {TImageViewerDocumentLabels} props.labels - `openDocument` names the fallback link; `previousPage` and `nextPage` name the pager buttons.
37
+ * @param {() => void} [props.onPageChange] - Called after the user moves to another page, so the viewer can recenter.
38
+ *
39
+ * @returns {ReactNode} The rendered document.
40
+ */
41
+ export function ImageViewerDocument({ src, alt, style, isAnimated, labels, onPageChange, }) {
42
+ const { status, pageCount, pageIndex, pageSrc, goToPage } = usePdfPages(src);
43
+ if (status === 'error') {
44
+ return (<div className="flex h-full w-full flex-col items-center justify-center gap-2 px-4 text-center">
45
+ <MdPictureAsPdf aria-hidden="true" className="text-gray-2 text-3xl"/>
46
+ <Paragraph size="body-2" className="text-gray-1 dark:text-gray-2">
47
+ {alt}
48
+ </Paragraph>
49
+ {!!labels.openDocument && (<a href={src} target="_blank" rel="noopener noreferrer" className="focus-visible:ring-lavender rounded-sm text-sm font-semibold text-black underline focus-visible:ring-2 focus-visible:outline-none dark:text-white">
50
+ {labels.openDocument}
51
+ </a>)}
52
+ </div>);
53
+ }
54
+ if (!pageSrc)
55
+ return <Spinner label={alt}/>;
56
+ const hasSeveralPages = pageCount > 1;
57
+ const pagerLabels = hasSeveralPages && labels.previousPage && labels.nextPage
58
+ ? { previous: labels.previousPage, next: labels.nextPage }
59
+ : null;
60
+ const pageAlt = hasSeveralPages
61
+ ? `${alt} · ${pageIndex + 1}/${pageCount}`
62
+ : alt;
63
+ const changePage = (index) => {
64
+ goToPage(index);
65
+ onPageChange?.();
66
+ };
67
+ return (<div className="relative flex h-full w-full items-center justify-center">
68
+ <ImageViewerImage src={pageSrc} alt={pageAlt} style={style} isAnimated={isAnimated}/>
69
+ {!!pagerLabels && (<div className="border-gray-5 dark:border-gray-1 dark:bg-black-1/90 absolute bottom-3 left-1/2 flex -translate-x-1/2 items-center gap-1 rounded-full border bg-white/90 px-1.5 py-1 shadow-md backdrop-blur-sm">
70
+ <IconButton icon={<MdChevronLeft />} label={pagerLabels.previous} disabled={pageIndex === 0} onClick={() => changePage(pageIndex - 1)} className="rounded-full"/>
71
+ <Paragraph size="body-2" aria-live="polite" className="min-w-10 text-center tabular-nums dark:text-white">
72
+ {`${pageIndex + 1} / ${pageCount}`}
73
+ </Paragraph>
74
+ <IconButton icon={<MdChevronRight />} label={pagerLabels.next} disabled={pageIndex === pageCount - 1} onClick={() => changePage(pageIndex + 1)} className="rounded-full"/>
75
+ </div>)}
76
+ </div>);
77
+ }
78
+ //# sourceMappingURL=ImageViewerDocument.jsx.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ImageViewerDocument.jsx","sourceRoot":"","sources":["../../../../src/components/02-molecules/ImageViewer/ImageViewerDocument.tsx"],"names":[],"mappings":"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"}
@@ -10,7 +10,12 @@ type ImageViewerImageProps = {
10
10
  alt: string;
11
11
  crop?: TImageCrop;
12
12
  style: CSSProperties;
13
+ isAnimated?: boolean;
13
14
  };
15
+ /**
16
+ * Lets the viewer find the rendered images to measure how far they can pan.
17
+ */
18
+ export declare const IMAGE_VIEWER_IMAGE_ATTRIBUTE = "data-image-viewer-image";
14
19
  /**
15
20
  * Image of one `ImageViewer` view, fitted inside its frame. With `crop`, only
16
21
  * that region of the image is drawn, scaled to fit the frame the same way the
@@ -31,10 +36,11 @@ type ImageViewerImageProps = {
31
36
  * @param {string} props.src - Image URL.
32
37
  * @param {string} props.alt - Accessible description of the image.
33
38
  * @param {TImageCrop} [props.crop] - Region to show, as fractions (0 to 1) of the image width and height.
34
- * @param {CSSProperties} props.style - Zoom and rotation computed by the viewer.
39
+ * @param {CSSProperties} props.style - Pan, zoom and rotation computed by the viewer.
40
+ * @param {boolean} [props.isAnimated=true] - Eases the transform. The viewer turns it off while the user drags, so the image follows the pointer without lag.
35
41
  *
36
42
  * @returns {ReactNode} The rendered image.
37
43
  */
38
- export declare function ImageViewerImage({ src, alt, crop, style, }: ImageViewerImageProps): ReactNode;
44
+ export declare function ImageViewerImage({ src, alt, crop, style, isAnimated, }: ImageViewerImageProps): ReactNode;
39
45
  export {};
40
46
  //# sourceMappingURL=ImageViewerImage.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ImageViewerImage.d.ts","sourceRoot":"","sources":["../../../../src/components/02-molecules/ImageViewer/ImageViewerImage.tsx"],"names":[],"mappings":"AAGA,OAAO,EACL,KAAK,aAAa,EAClB,KAAK,SAAS,EAIf,MAAM,OAAO,CAAC;AAEf,MAAM,MAAM,UAAU,GAAG;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAOF,KAAK,qBAAqB,GAAG;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,KAAK,EAAE,aAAa,CAAC;CACtB,CAAC;AA2DF;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,gBAAgB,CAAC,EAC/B,GAAG,EACH,GAAG,EACH,IAAI,EACJ,KAAK,GACN,EAAE,qBAAqB,GAAG,SAAS,CA4DnC"}
1
+ {"version":3,"file":"ImageViewerImage.d.ts","sourceRoot":"","sources":["../../../../src/components/02-molecules/ImageViewer/ImageViewerImage.tsx"],"names":[],"mappings":"AAGA,OAAO,EACL,KAAK,aAAa,EAClB,KAAK,SAAS,EAIf,MAAM,OAAO,CAAC;AAEf,MAAM,MAAM,UAAU,GAAG;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAOF,KAAK,qBAAqB,GAAG;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,KAAK,EAAE,aAAa,CAAC;IACrB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,4BAA4B,4BAA4B,CAAC;AA2DtE;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,gBAAgB,CAAC,EAC/B,GAAG,EACH,GAAG,EACH,IAAI,EACJ,KAAK,EACL,UAAiB,GAClB,EAAE,qBAAqB,GAAG,SAAS,CAgEnC"}
@@ -1,6 +1,10 @@
1
1
  'use client';
2
2
  import clsx from 'clsx';
3
3
  import { useEffect, useId, useState, } from 'react';
4
+ /**
5
+ * Lets the viewer find the rendered images to measure how far they can pan.
6
+ */
7
+ export const IMAGE_VIEWER_IMAGE_ATTRIBUTE = 'data-image-viewer-image';
4
8
  const TRANSFORM_CLASSNAME = 'transition-transform duration-200 ease-out';
5
9
  const clampFraction = (value) => Math.min(Math.max(value, 0), 1);
6
10
  /**
@@ -67,14 +71,16 @@ const useNaturalSize = (src, isEnabled) => {
67
71
  * @param {string} props.src - Image URL.
68
72
  * @param {string} props.alt - Accessible description of the image.
69
73
  * @param {TImageCrop} [props.crop] - Region to show, as fractions (0 to 1) of the image width and height.
70
- * @param {CSSProperties} props.style - Zoom and rotation computed by the viewer.
74
+ * @param {CSSProperties} props.style - Pan, zoom and rotation computed by the viewer.
75
+ * @param {boolean} [props.isAnimated=true] - Eases the transform. The viewer turns it off while the user drags, so the image follows the pointer without lag.
71
76
  *
72
77
  * @returns {ReactNode} The rendered image.
73
78
  */
74
- export function ImageViewerImage({ src, alt, crop, style, }) {
79
+ export function ImageViewerImage({ src, alt, crop, style, isAnimated = true, }) {
75
80
  const region = normalizeCrop(crop);
76
81
  const size = useNaturalSize(src, region !== null);
77
82
  const clipId = `crop${useId().replace(/[^\w-]/g, '')}`;
83
+ const measurable = { [IMAGE_VIEWER_IMAGE_ATTRIBUTE]: '' };
78
84
  if (!region || size === 'error') {
79
85
  return (
80
86
  /**
@@ -83,7 +89,7 @@ export function ImageViewerImage({ src, alt, crop, style, }) {
83
89
  * almacenamiento externo, asi que la lista no se puede conocer.
84
90
  */
85
91
  // eslint-disable-next-line @next/next/no-img-element
86
- <img src={src} alt={alt} style={style} className={clsx('max-h-full max-w-full object-contain', TRANSFORM_CLASSNAME)}/>);
92
+ <img {...measurable} src={src} alt={alt} style={style} draggable={false} className={clsx('max-h-full max-w-full object-contain', isAnimated && TRANSFORM_CLASSNAME)}/>);
87
93
  }
88
94
  if (!size)
89
95
  return null;
@@ -97,7 +103,7 @@ export function ImageViewerImage({ src, alt, crop, style, }) {
97
103
  * `meet` centers the region but the SVG still paints whatever falls in the
98
104
  * letterbox, which is the rest of the image: the clip keeps only the region.
99
105
  */
100
- return (<svg role="img" aria-label={alt} viewBox={[box.x, box.y, box.width, box.height].join(' ')} preserveAspectRatio="xMidYMid meet" style={style} className={clsx('h-full w-full', TRANSFORM_CLASSNAME)}>
106
+ return (<svg {...measurable} role="img" aria-label={alt} viewBox={[box.x, box.y, box.width, box.height].join(' ')} preserveAspectRatio="xMidYMid meet" style={style} className={clsx('h-full w-full', isAnimated && TRANSFORM_CLASSNAME)}>
101
107
  <defs>
102
108
  <clipPath id={clipId}>
103
109
  <rect {...box}/>
@@ -1 +1 @@
1
- {"version":3,"file":"ImageViewerImage.jsx","sourceRoot":"","sources":["../../../../src/components/02-molecules/ImageViewer/ImageViewerImage.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ImageViewerImage.jsx","sourceRoot":"","sources":["../../../../src/components/02-molecules/ImageViewer/ImageViewerImage.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ export type TPdfStatus = 'loading' | 'ready' | 'error';
2
+ export type TPdfPages = {
3
+ status: TPdfStatus;
4
+ pageCount: number;
5
+ pageIndex: number;
6
+ pageSrc: string | undefined;
7
+ goToPage: (index: number) => void;
8
+ };
9
+ /**
10
+ * Loads a PDF and renders its pages to images on demand, one at a time: the
11
+ * current page is drawn when it is first shown and kept for the life of the
12
+ * document. Object URLs are revoked and the document is destroyed when `src`
13
+ * changes or the component unmounts.
14
+ *
15
+ * @param {string} src - PDF URL. The browser fetches it, so its origin must allow CORS.
16
+ *
17
+ * @returns {TPdfPages} Load status, page count, current page and its image URL, plus `goToPage`.
18
+ */
19
+ export declare const usePdfPages: (src: string) => TPdfPages;
20
+ //# sourceMappingURL=usePdfPages.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usePdfPages.d.ts","sourceRoot":"","sources":["../../../../src/components/02-molecules/ImageViewer/usePdfPages.ts"],"names":[],"mappings":"AAKA,MAAM,MAAM,UAAU,GAAG,SAAS,GAAG,OAAO,GAAG,OAAO,CAAC;AAEvD,MAAM,MAAM,SAAS,GAAG;IACtB,MAAM,EAAE,UAAU,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACnC,CAAC;AAyDF;;;;;;;;;GASG;AACH,eAAO,MAAM,WAAW,QAAS,MAAM,KAAG,SAkEzC,CAAC"}
@@ -0,0 +1,113 @@
1
+ 'use client';
2
+ import { useEffect, useRef, useState } from 'react';
3
+ /**
4
+ * Longest side of a rendered page, in device pixels. Enough for the viewer's
5
+ * maximum zoom on a high-density screen, capped so the canvas and the encoded
6
+ * image stay reasonable for a scanned document.
7
+ */
8
+ const RENDER_SIDE_BASE = 1500;
9
+ const RENDER_SIDE_MAX = 3000;
10
+ /**
11
+ * The library and its worker are loaded on first use, so a consumer that
12
+ * never shows a PDF never pays for them. The worker URL goes through
13
+ * `new URL(..., import.meta.url)`, which webpack, Turbopack and Vite turn into
14
+ * an emitted asset; `pdfjs-dist` resolves from this package's own dependency.
15
+ */
16
+ const loadPdfjs = async () => {
17
+ const pdfjs = await import('pdfjs-dist');
18
+ if (!pdfjs.GlobalWorkerOptions.workerSrc) {
19
+ pdfjs.GlobalWorkerOptions.workerSrc = new URL('pdfjs-dist/build/pdf.worker.min.mjs', import.meta.url).toString();
20
+ }
21
+ return pdfjs;
22
+ };
23
+ /**
24
+ * Draws one page on a detached canvas and hands it back as an object URL, so
25
+ * the page can go through the same `<img>` path as any other view: zoom,
26
+ * rotation and pan come for free and the PDF never needs its own controls.
27
+ */
28
+ const renderPage = async (pdf, pageNumber) => {
29
+ const page = await pdf.getPage(pageNumber);
30
+ const { width, height } = page.getViewport({ scale: 1 });
31
+ const side = Math.min(RENDER_SIDE_MAX, RENDER_SIDE_BASE * (window.devicePixelRatio || 1));
32
+ const viewport = page.getViewport({ scale: side / Math.max(width, height) });
33
+ const canvas = document.createElement('canvas');
34
+ canvas.width = Math.ceil(viewport.width);
35
+ canvas.height = Math.ceil(viewport.height);
36
+ await page.render({ canvas, viewport }).promise;
37
+ page.cleanup();
38
+ const blob = await new Promise((resolve) => canvas.toBlob(resolve, 'image/png'));
39
+ if (!blob)
40
+ throw new Error('The page could not be encoded as an image.');
41
+ return URL.createObjectURL(blob);
42
+ };
43
+ /**
44
+ * Loads a PDF and renders its pages to images on demand, one at a time: the
45
+ * current page is drawn when it is first shown and kept for the life of the
46
+ * document. Object URLs are revoked and the document is destroyed when `src`
47
+ * changes or the component unmounts.
48
+ *
49
+ * @param {string} src - PDF URL. The browser fetches it, so its origin must allow CORS.
50
+ *
51
+ * @returns {TPdfPages} Load status, page count, current page and its image URL, plus `goToPage`.
52
+ */
53
+ export const usePdfPages = (src) => {
54
+ const [status, setStatus] = useState('loading');
55
+ const [pdf, setPdf] = useState(null);
56
+ const [pageIndex, setPageIndex] = useState(0);
57
+ const [pages, setPages] = useState({});
58
+ const activePdfRef = useRef(null);
59
+ const pagesRef = useRef({});
60
+ useEffect(() => {
61
+ let isCurrent = true;
62
+ let task;
63
+ // eslint-disable-next-line react-hooks/set-state-in-effect -- clears the previous document while this effect loads the new one
64
+ setStatus('loading');
65
+ setPdf(null);
66
+ setPageIndex(0);
67
+ setPages({});
68
+ const load = async () => {
69
+ const pdfjs = await loadPdfjs();
70
+ if (!isCurrent)
71
+ return;
72
+ task = pdfjs.getDocument({ url: src });
73
+ const loaded = await task.promise;
74
+ if (!isCurrent)
75
+ return;
76
+ activePdfRef.current = loaded;
77
+ setPdf(loaded);
78
+ setStatus('ready');
79
+ };
80
+ load().catch(() => {
81
+ if (isCurrent)
82
+ setStatus('error');
83
+ });
84
+ return () => {
85
+ isCurrent = false;
86
+ activePdfRef.current = null;
87
+ task?.destroy();
88
+ Object.values(pagesRef.current).forEach((url) => URL.revokeObjectURL(url));
89
+ pagesRef.current = {};
90
+ };
91
+ }, [src]);
92
+ useEffect(() => {
93
+ if (!pdf || pagesRef.current[pageIndex])
94
+ return;
95
+ renderPage(pdf, pageIndex + 1)
96
+ .then((url) => {
97
+ if (activePdfRef.current !== pdf || pagesRef.current[pageIndex]) {
98
+ URL.revokeObjectURL(url);
99
+ return;
100
+ }
101
+ pagesRef.current = { ...pagesRef.current, [pageIndex]: url };
102
+ setPages(pagesRef.current);
103
+ })
104
+ .catch(() => {
105
+ if (activePdfRef.current === pdf)
106
+ setStatus('error');
107
+ });
108
+ }, [pdf, pageIndex]);
109
+ const pageCount = pdf?.numPages ?? 0;
110
+ const goToPage = (index) => setPageIndex(Math.min(Math.max(index, 0), Math.max(pageCount - 1, 0)));
111
+ return { status, pageCount, pageIndex, pageSrc: pages[pageIndex], goToPage };
112
+ };
113
+ //# sourceMappingURL=usePdfPages.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usePdfPages.js","sourceRoot":"","sources":["../../../../src/components/02-molecules/ImageViewer/usePdfPages.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,12 +1,13 @@
1
1
  {
2
2
  "name": "@clicoh/orion-library",
3
- "version": "1.2.0-beta.21",
3
+ "version": "1.2.0-beta.22",
4
4
  "main": "index.js",
5
5
  "dependencies": {
6
6
  "@floating-ui/react": "0.26.19",
7
7
  "clsx": "2.1.1",
8
8
  "leaflet": "^1.9.4",
9
9
  "next": "16.3.8",
10
+ "pdfjs-dist": "6.4.299",
10
11
  "react": "19.2.6",
11
12
  "react-dom": "19.2.6",
12
13
  "react-icons": "5.2.1",