@sesionario/blocks 1.23.0 → 1.24.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.
- package/dist/index.cjs +509 -204
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +114 -2
- package/dist/index.d.ts +114 -2
- package/dist/index.js +501 -205
- package/dist/index.js.map +1 -1
- package/dist/pdf.cjs +1045 -0
- package/dist/pdf.cjs.map +1 -0
- package/dist/pdf.d.cts +68 -0
- package/dist/pdf.d.ts +68 -0
- package/dist/pdf.js +1021 -0
- package/dist/pdf.js.map +1 -0
- package/package.json +21 -1
package/dist/pdf.cjs
ADDED
|
@@ -0,0 +1,1045 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var react = require('react');
|
|
4
|
+
var reactPdf = require('react-pdf');
|
|
5
|
+
var lucideReact = require('lucide-react');
|
|
6
|
+
var clsx = require('clsx');
|
|
7
|
+
var tailwindMerge = require('tailwind-merge');
|
|
8
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
9
|
+
require('react-pdf/dist/Page/TextLayer.css');
|
|
10
|
+
require('react-pdf/dist/Page/AnnotationLayer.css');
|
|
11
|
+
var DialogPrimitive = require('@radix-ui/react-dialog');
|
|
12
|
+
|
|
13
|
+
function _interopNamespace(e) {
|
|
14
|
+
if (e && e.__esModule) return e;
|
|
15
|
+
var n = Object.create(null);
|
|
16
|
+
if (e) {
|
|
17
|
+
Object.keys(e).forEach(function (k) {
|
|
18
|
+
if (k !== 'default') {
|
|
19
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
20
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
21
|
+
enumerable: true,
|
|
22
|
+
get: function () { return e[k]; }
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
n.default = e;
|
|
28
|
+
return Object.freeze(n);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
var DialogPrimitive__namespace = /*#__PURE__*/_interopNamespace(DialogPrimitive);
|
|
32
|
+
|
|
33
|
+
function cn(...inputs) {
|
|
34
|
+
return tailwindMerge.twMerge(clsx.clsx(inputs));
|
|
35
|
+
}
|
|
36
|
+
var ZOOM_PAN_MIN_SCALE = 1;
|
|
37
|
+
var ZOOM_PAN_MAX_SCALE = 4;
|
|
38
|
+
var ZOOM_PAN_DOUBLE_TAP_MS = 300;
|
|
39
|
+
var ZOOM_PAN_SWIPE_LOCK_PX = 8;
|
|
40
|
+
var ZOOM_PAN_SWIPE_COMMIT_PX = 56;
|
|
41
|
+
var ZOOM_PAN_SWIPE_SNAP_MS = 180;
|
|
42
|
+
var IDENTITY = { scale: 1, tx: 0, ty: 0 };
|
|
43
|
+
function clamp(value, min, max) {
|
|
44
|
+
return Math.min(max, Math.max(min, value));
|
|
45
|
+
}
|
|
46
|
+
function zoomToward(prev, nextScale, originX, originY, minScale = ZOOM_PAN_MIN_SCALE, maxScale = ZOOM_PAN_MAX_SCALE) {
|
|
47
|
+
const scale = clamp(nextScale, minScale, maxScale);
|
|
48
|
+
if (scale === minScale) return { ...IDENTITY, scale: minScale };
|
|
49
|
+
const ratio = scale / prev.scale;
|
|
50
|
+
return {
|
|
51
|
+
scale,
|
|
52
|
+
tx: originX - (originX - prev.tx) * ratio,
|
|
53
|
+
ty: originY - (originY - prev.ty) * ratio
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
function pointerDistance(a, b) {
|
|
57
|
+
return Math.hypot(b.x - a.x, b.y - a.y);
|
|
58
|
+
}
|
|
59
|
+
function prefersReducedMotion() {
|
|
60
|
+
if (typeof window === "undefined" || !window.matchMedia) return false;
|
|
61
|
+
return window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
62
|
+
}
|
|
63
|
+
function useZoomPanGestures(options = {}) {
|
|
64
|
+
const {
|
|
65
|
+
minScale = ZOOM_PAN_MIN_SCALE,
|
|
66
|
+
maxScale = ZOOM_PAN_MAX_SCALE,
|
|
67
|
+
swipeEnabled = true,
|
|
68
|
+
onSwipeCommit,
|
|
69
|
+
wheelZoom = true,
|
|
70
|
+
doubleTap = "reset"
|
|
71
|
+
} = options;
|
|
72
|
+
const [transform, setTransform] = react.useState({
|
|
73
|
+
...IDENTITY,
|
|
74
|
+
scale: minScale
|
|
75
|
+
});
|
|
76
|
+
const transformRef = react.useRef(transform);
|
|
77
|
+
transformRef.current = transform;
|
|
78
|
+
const [isSwipeDragging, setIsSwipeDragging] = react.useState(false);
|
|
79
|
+
const [snapBack, setSnapBack] = react.useState(false);
|
|
80
|
+
const stageRef = react.useRef(null);
|
|
81
|
+
const pointersRef = react.useRef(/* @__PURE__ */ new Map());
|
|
82
|
+
const pinchStartRef = react.useRef(null);
|
|
83
|
+
const panRef = react.useRef(null);
|
|
84
|
+
const swipeRef = react.useRef(null);
|
|
85
|
+
const lastTapRef = react.useRef(
|
|
86
|
+
null
|
|
87
|
+
);
|
|
88
|
+
const onSwipeCommitRef = react.useRef(onSwipeCommit);
|
|
89
|
+
onSwipeCommitRef.current = onSwipeCommit;
|
|
90
|
+
const swipeEnabledRef = react.useRef(swipeEnabled);
|
|
91
|
+
swipeEnabledRef.current = swipeEnabled;
|
|
92
|
+
const minScaleRef = react.useRef(minScale);
|
|
93
|
+
minScaleRef.current = minScale;
|
|
94
|
+
const maxScaleRef = react.useRef(maxScale);
|
|
95
|
+
maxScaleRef.current = maxScale;
|
|
96
|
+
const doubleTapRef = react.useRef(doubleTap);
|
|
97
|
+
doubleTapRef.current = doubleTap;
|
|
98
|
+
const reset = react.useCallback(() => {
|
|
99
|
+
setTransform({ ...IDENTITY, scale: minScaleRef.current });
|
|
100
|
+
setIsSwipeDragging(false);
|
|
101
|
+
setSnapBack(false);
|
|
102
|
+
}, []);
|
|
103
|
+
const setScale = react.useCallback((next) => {
|
|
104
|
+
setTransform(
|
|
105
|
+
(prev) => zoomToward(prev, next, 0, 0, minScaleRef.current, maxScaleRef.current)
|
|
106
|
+
);
|
|
107
|
+
}, []);
|
|
108
|
+
const clearSnapBack = react.useCallback(() => {
|
|
109
|
+
setSnapBack(false);
|
|
110
|
+
}, []);
|
|
111
|
+
const stageOrigin = react.useCallback((clientX, clientY) => {
|
|
112
|
+
const stage = stageRef.current;
|
|
113
|
+
if (!stage) return { x: 0, y: 0 };
|
|
114
|
+
const rect = stage.getBoundingClientRect();
|
|
115
|
+
return {
|
|
116
|
+
x: clientX - rect.left - rect.width / 2,
|
|
117
|
+
y: clientY - rect.top - rect.height / 2
|
|
118
|
+
};
|
|
119
|
+
}, []);
|
|
120
|
+
react.useEffect(() => {
|
|
121
|
+
if (!wheelZoom) return;
|
|
122
|
+
const stage = stageRef.current;
|
|
123
|
+
if (!stage) return;
|
|
124
|
+
const handleWheel = (e) => {
|
|
125
|
+
e.preventDefault();
|
|
126
|
+
e.stopPropagation();
|
|
127
|
+
const prev = transformRef.current;
|
|
128
|
+
const factor = e.deltaY > 0 ? 0.9 : 1.1;
|
|
129
|
+
const { x, y } = stageOrigin(e.clientX, e.clientY);
|
|
130
|
+
setTransform(
|
|
131
|
+
zoomToward(
|
|
132
|
+
prev,
|
|
133
|
+
prev.scale * factor,
|
|
134
|
+
x,
|
|
135
|
+
y,
|
|
136
|
+
minScaleRef.current,
|
|
137
|
+
maxScaleRef.current
|
|
138
|
+
)
|
|
139
|
+
);
|
|
140
|
+
};
|
|
141
|
+
stage.addEventListener("wheel", handleWheel, { passive: false });
|
|
142
|
+
return () => stage.removeEventListener("wheel", handleWheel);
|
|
143
|
+
}, [stageOrigin, wheelZoom]);
|
|
144
|
+
function clearSwipe() {
|
|
145
|
+
swipeRef.current = null;
|
|
146
|
+
setIsSwipeDragging(false);
|
|
147
|
+
}
|
|
148
|
+
function beginPinch() {
|
|
149
|
+
const pts = [...pointersRef.current.values()];
|
|
150
|
+
const [a, b] = pts;
|
|
151
|
+
if (!a || !b) return;
|
|
152
|
+
const midX = (a.x + b.x) / 2;
|
|
153
|
+
const midY = (a.y + b.y) / 2;
|
|
154
|
+
const { x, y } = stageOrigin(midX, midY);
|
|
155
|
+
pinchStartRef.current = {
|
|
156
|
+
distance: Math.max(pointerDistance(a, b), 1),
|
|
157
|
+
originX: x,
|
|
158
|
+
originY: y,
|
|
159
|
+
transform: { ...transformRef.current }
|
|
160
|
+
};
|
|
161
|
+
panRef.current = null;
|
|
162
|
+
clearSwipe();
|
|
163
|
+
setSnapBack(false);
|
|
164
|
+
}
|
|
165
|
+
function onPointerDown(e) {
|
|
166
|
+
e.stopPropagation();
|
|
167
|
+
const stage = stageRef.current;
|
|
168
|
+
if (!stage) return;
|
|
169
|
+
if (typeof stage.setPointerCapture === "function") {
|
|
170
|
+
stage.setPointerCapture(e.pointerId);
|
|
171
|
+
}
|
|
172
|
+
pointersRef.current.set(e.pointerId, { x: e.clientX, y: e.clientY });
|
|
173
|
+
setSnapBack(false);
|
|
174
|
+
if (pointersRef.current.size === 2) {
|
|
175
|
+
beginPinch();
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
if (transformRef.current.scale > minScaleRef.current) {
|
|
179
|
+
panRef.current = {
|
|
180
|
+
pointerId: e.pointerId,
|
|
181
|
+
startX: e.clientX,
|
|
182
|
+
startY: e.clientY,
|
|
183
|
+
originTx: transformRef.current.tx,
|
|
184
|
+
originTy: transformRef.current.ty,
|
|
185
|
+
moved: false
|
|
186
|
+
};
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
if (swipeEnabledRef.current) {
|
|
190
|
+
swipeRef.current = {
|
|
191
|
+
pointerId: e.pointerId,
|
|
192
|
+
startX: e.clientX,
|
|
193
|
+
startY: e.clientY,
|
|
194
|
+
moved: false,
|
|
195
|
+
axis: null
|
|
196
|
+
};
|
|
197
|
+
setIsSwipeDragging(true);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
function onPointerMove(e) {
|
|
201
|
+
if (!pointersRef.current.has(e.pointerId)) return;
|
|
202
|
+
pointersRef.current.set(e.pointerId, { x: e.clientX, y: e.clientY });
|
|
203
|
+
const pinchStart = pinchStartRef.current;
|
|
204
|
+
if (pointersRef.current.size >= 2 && pinchStart) {
|
|
205
|
+
const pts = [...pointersRef.current.values()];
|
|
206
|
+
const [a, b] = pts;
|
|
207
|
+
if (!a || !b) return;
|
|
208
|
+
const distance = Math.max(pointerDistance(a, b), 1);
|
|
209
|
+
const nextScale = pinchStart.transform.scale * (distance / pinchStart.distance);
|
|
210
|
+
setTransform(
|
|
211
|
+
zoomToward(
|
|
212
|
+
pinchStart.transform,
|
|
213
|
+
nextScale,
|
|
214
|
+
pinchStart.originX,
|
|
215
|
+
pinchStart.originY,
|
|
216
|
+
minScaleRef.current,
|
|
217
|
+
maxScaleRef.current
|
|
218
|
+
)
|
|
219
|
+
);
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
const pan = panRef.current;
|
|
223
|
+
if (pan && pan.pointerId === e.pointerId) {
|
|
224
|
+
const dx2 = e.clientX - pan.startX;
|
|
225
|
+
const dy2 = e.clientY - pan.startY;
|
|
226
|
+
if (Math.abs(dx2) > 2 || Math.abs(dy2) > 2) pan.moved = true;
|
|
227
|
+
setTransform((prev) => ({
|
|
228
|
+
...prev,
|
|
229
|
+
tx: pan.originTx + dx2,
|
|
230
|
+
ty: pan.originTy + dy2
|
|
231
|
+
}));
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
const swipe = swipeRef.current;
|
|
235
|
+
if (!swipe || swipe.pointerId !== e.pointerId) return;
|
|
236
|
+
const dx = e.clientX - swipe.startX;
|
|
237
|
+
const dy = e.clientY - swipe.startY;
|
|
238
|
+
if (Math.abs(dx) > 2 || Math.abs(dy) > 2) swipe.moved = true;
|
|
239
|
+
if (swipe.axis === null) {
|
|
240
|
+
const absX = Math.abs(dx);
|
|
241
|
+
const absY = Math.abs(dy);
|
|
242
|
+
if (absX < ZOOM_PAN_SWIPE_LOCK_PX && absY < ZOOM_PAN_SWIPE_LOCK_PX) {
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
swipe.axis = absX >= absY ? "x" : "y";
|
|
246
|
+
if (swipe.axis === "y") {
|
|
247
|
+
clearSwipe();
|
|
248
|
+
setTransform({ ...IDENTITY, scale: minScaleRef.current });
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
if (swipe.axis === "x") {
|
|
253
|
+
setTransform({
|
|
254
|
+
scale: minScaleRef.current,
|
|
255
|
+
tx: dx,
|
|
256
|
+
ty: 0
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
function finishSwipe(e) {
|
|
261
|
+
const swipe = swipeRef.current;
|
|
262
|
+
if (!swipe || swipe.pointerId !== e.pointerId) return false;
|
|
263
|
+
const dx = e.clientX - swipe.startX;
|
|
264
|
+
const wasMoved = swipe.moved;
|
|
265
|
+
const axis = swipe.axis;
|
|
266
|
+
clearSwipe();
|
|
267
|
+
if (axis === "x" && Math.abs(dx) >= ZOOM_PAN_SWIPE_COMMIT_PX) {
|
|
268
|
+
onSwipeCommitRef.current?.(dx < 0 ? "next" : "prev");
|
|
269
|
+
return true;
|
|
270
|
+
}
|
|
271
|
+
if (wasMoved || transformRef.current.tx !== 0) {
|
|
272
|
+
if (!prefersReducedMotion()) setSnapBack(true);
|
|
273
|
+
setTransform({ ...IDENTITY, scale: minScaleRef.current });
|
|
274
|
+
}
|
|
275
|
+
return wasMoved;
|
|
276
|
+
}
|
|
277
|
+
function onPointerUp(e) {
|
|
278
|
+
const stage = stageRef.current;
|
|
279
|
+
if (stage && typeof stage.hasPointerCapture === "function" && stage.hasPointerCapture(e.pointerId) && typeof stage.releasePointerCapture === "function") {
|
|
280
|
+
stage.releasePointerCapture(e.pointerId);
|
|
281
|
+
}
|
|
282
|
+
pointersRef.current.delete(e.pointerId);
|
|
283
|
+
if (pointersRef.current.size < 2) {
|
|
284
|
+
pinchStartRef.current = null;
|
|
285
|
+
}
|
|
286
|
+
if (pointersRef.current.size === 1) {
|
|
287
|
+
const remaining = [...pointersRef.current.entries()][0];
|
|
288
|
+
if (remaining && transformRef.current.scale > minScaleRef.current) {
|
|
289
|
+
const [pointerId, point] = remaining;
|
|
290
|
+
panRef.current = {
|
|
291
|
+
pointerId,
|
|
292
|
+
startX: point.x,
|
|
293
|
+
startY: point.y,
|
|
294
|
+
originTx: transformRef.current.tx,
|
|
295
|
+
originTy: transformRef.current.ty,
|
|
296
|
+
moved: true
|
|
297
|
+
};
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
const swipeHandled = finishSwipe(e);
|
|
301
|
+
if (swipeHandled) return;
|
|
302
|
+
const pan = panRef.current;
|
|
303
|
+
if (pan && pan.pointerId === e.pointerId) {
|
|
304
|
+
const wasMoved = pan.moved;
|
|
305
|
+
panRef.current = null;
|
|
306
|
+
if (wasMoved) return;
|
|
307
|
+
}
|
|
308
|
+
if (pointersRef.current.size === 0 && e.button === 0) {
|
|
309
|
+
const now = Date.now();
|
|
310
|
+
const last = lastTapRef.current;
|
|
311
|
+
if (last && now - last.time < ZOOM_PAN_DOUBLE_TAP_MS && Math.hypot(e.clientX - last.x, e.clientY - last.y) < 24) {
|
|
312
|
+
lastTapRef.current = null;
|
|
313
|
+
if (doubleTapRef.current === "toggle" && transformRef.current.scale <= minScaleRef.current) {
|
|
314
|
+
const { x, y } = stageOrigin(e.clientX, e.clientY);
|
|
315
|
+
setTransform(
|
|
316
|
+
zoomToward(
|
|
317
|
+
transformRef.current,
|
|
318
|
+
Math.min(2, maxScaleRef.current),
|
|
319
|
+
x,
|
|
320
|
+
y,
|
|
321
|
+
minScaleRef.current,
|
|
322
|
+
maxScaleRef.current
|
|
323
|
+
)
|
|
324
|
+
);
|
|
325
|
+
} else {
|
|
326
|
+
reset();
|
|
327
|
+
}
|
|
328
|
+
return;
|
|
329
|
+
}
|
|
330
|
+
lastTapRef.current = { time: now, x: e.clientX, y: e.clientY };
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
return {
|
|
334
|
+
stageRef,
|
|
335
|
+
transform,
|
|
336
|
+
isDragging: isSwipeDragging,
|
|
337
|
+
snapBack,
|
|
338
|
+
handlers: {
|
|
339
|
+
onPointerDown,
|
|
340
|
+
onPointerMove,
|
|
341
|
+
onPointerUp,
|
|
342
|
+
onPointerCancel: onPointerUp
|
|
343
|
+
},
|
|
344
|
+
reset,
|
|
345
|
+
setScale,
|
|
346
|
+
clearSnapBack
|
|
347
|
+
};
|
|
348
|
+
}
|
|
349
|
+
function LoadingState({
|
|
350
|
+
label = "Cargando\u2026",
|
|
351
|
+
className
|
|
352
|
+
}) {
|
|
353
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
354
|
+
"div",
|
|
355
|
+
{
|
|
356
|
+
role: "status",
|
|
357
|
+
"aria-live": "polite",
|
|
358
|
+
className: cn(
|
|
359
|
+
"flex items-center justify-center gap-2 py-12 text-sm text-muted-foreground",
|
|
360
|
+
className
|
|
361
|
+
),
|
|
362
|
+
children: [
|
|
363
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "size-4 animate-spin", "aria-hidden": "true" }),
|
|
364
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: label })
|
|
365
|
+
]
|
|
366
|
+
}
|
|
367
|
+
);
|
|
368
|
+
}
|
|
369
|
+
function ErrorState({
|
|
370
|
+
title = "Algo sali\xF3 mal",
|
|
371
|
+
description,
|
|
372
|
+
action,
|
|
373
|
+
className
|
|
374
|
+
}) {
|
|
375
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
376
|
+
"div",
|
|
377
|
+
{
|
|
378
|
+
role: "alert",
|
|
379
|
+
className: cn(
|
|
380
|
+
"flex flex-col items-center gap-3 rounded-xl border border-dashed border-destructive/40 bg-destructive/5 py-12 text-center",
|
|
381
|
+
className
|
|
382
|
+
),
|
|
383
|
+
children: [
|
|
384
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlertTriangle, { className: "size-6 text-destructive", "aria-hidden": "true" }),
|
|
385
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
386
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "font-medium", children: title }),
|
|
387
|
+
description ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1 text-sm text-muted-foreground", children: description }) : null
|
|
388
|
+
] }),
|
|
389
|
+
action
|
|
390
|
+
]
|
|
391
|
+
}
|
|
392
|
+
);
|
|
393
|
+
}
|
|
394
|
+
function LazyThumbnail({
|
|
395
|
+
pageNumber,
|
|
396
|
+
active,
|
|
397
|
+
width,
|
|
398
|
+
onClick,
|
|
399
|
+
ariaLabel
|
|
400
|
+
}) {
|
|
401
|
+
const ref = react.useRef(null);
|
|
402
|
+
const [visible, setVisible] = react.useState(false);
|
|
403
|
+
react.useEffect(() => {
|
|
404
|
+
const node = ref.current;
|
|
405
|
+
if (!node || typeof IntersectionObserver === "undefined") {
|
|
406
|
+
setVisible(true);
|
|
407
|
+
return;
|
|
408
|
+
}
|
|
409
|
+
const observer = new IntersectionObserver(
|
|
410
|
+
(entries) => {
|
|
411
|
+
if (entries.some((e) => e.isIntersecting)) {
|
|
412
|
+
setVisible(true);
|
|
413
|
+
observer.disconnect();
|
|
414
|
+
}
|
|
415
|
+
},
|
|
416
|
+
{ rootMargin: "120px 0px" }
|
|
417
|
+
);
|
|
418
|
+
observer.observe(node);
|
|
419
|
+
return () => observer.disconnect();
|
|
420
|
+
}, []);
|
|
421
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
422
|
+
"button",
|
|
423
|
+
{
|
|
424
|
+
ref,
|
|
425
|
+
type: "button",
|
|
426
|
+
onClick,
|
|
427
|
+
"aria-label": ariaLabel,
|
|
428
|
+
"aria-current": active ? "page" : void 0,
|
|
429
|
+
className: cn(
|
|
430
|
+
"block w-full overflow-hidden rounded-md border bg-background p-1 transition-colors hover:border-primary",
|
|
431
|
+
active ? "border-primary ring-2 ring-primary/30" : "border-border"
|
|
432
|
+
),
|
|
433
|
+
children: [
|
|
434
|
+
visible ? /* @__PURE__ */ jsxRuntime.jsx(reactPdf.Thumbnail, { pageNumber, width, className: "mx-auto" }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
435
|
+
"div",
|
|
436
|
+
{
|
|
437
|
+
className: "mx-auto bg-muted",
|
|
438
|
+
style: { width, height: Math.round(width * 1.4) },
|
|
439
|
+
"aria-hidden": true
|
|
440
|
+
}
|
|
441
|
+
),
|
|
442
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "mt-1 block text-center text-[10px] text-muted-foreground", children: pageNumber })
|
|
443
|
+
]
|
|
444
|
+
}
|
|
445
|
+
);
|
|
446
|
+
}
|
|
447
|
+
var configuredSrc = null;
|
|
448
|
+
function configurePdfWorker(workerSrc) {
|
|
449
|
+
if (!workerSrc || configuredSrc === workerSrc) return;
|
|
450
|
+
reactPdf.pdfjs.GlobalWorkerOptions.workerSrc = workerSrc;
|
|
451
|
+
configuredSrc = workerSrc;
|
|
452
|
+
}
|
|
453
|
+
var ZOOM_STEPS = [0.5, 0.75, 1, 1.25, 1.5, 2, 2.5, 3];
|
|
454
|
+
var THUMB_WIDTH = 120;
|
|
455
|
+
function PdfViewer({
|
|
456
|
+
fileUrl,
|
|
457
|
+
fileName,
|
|
458
|
+
downloadUrl,
|
|
459
|
+
workerSrc,
|
|
460
|
+
initialPage = 1,
|
|
461
|
+
className,
|
|
462
|
+
labels
|
|
463
|
+
}) {
|
|
464
|
+
configurePdfWorker(workerSrc);
|
|
465
|
+
const [numPages, setNumPages] = react.useState(0);
|
|
466
|
+
const [pageNumber, setPageNumber] = react.useState(initialPage);
|
|
467
|
+
const [zoomIndex, setZoomIndex] = react.useState(2);
|
|
468
|
+
const [fitMode, setFitMode] = react.useState("width");
|
|
469
|
+
const [rotation, setRotation] = react.useState(0);
|
|
470
|
+
const [containerWidth, setContainerWidth] = react.useState(0);
|
|
471
|
+
const [containerHeight, setContainerHeight] = react.useState(0);
|
|
472
|
+
const [isFullscreen, setIsFullscreen] = react.useState(false);
|
|
473
|
+
const [thumbsOpen, setThumbsOpen] = react.useState(false);
|
|
474
|
+
const [loadError, setLoadError] = react.useState(false);
|
|
475
|
+
const [pageDraft, setPageDraft] = react.useState(String(initialPage));
|
|
476
|
+
const viewportRef = react.useRef(null);
|
|
477
|
+
const shellRef = react.useRef(null);
|
|
478
|
+
const pageNumberRef = react.useRef(pageNumber);
|
|
479
|
+
pageNumberRef.current = pageNumber;
|
|
480
|
+
const numPagesRef = react.useRef(numPages);
|
|
481
|
+
numPagesRef.current = numPages;
|
|
482
|
+
const baseScale = ZOOM_STEPS[zoomIndex] ?? 1;
|
|
483
|
+
const goToPage = react.useCallback((next) => {
|
|
484
|
+
const total = numPagesRef.current;
|
|
485
|
+
if (total <= 0) return;
|
|
486
|
+
const clamped = Math.min(Math.max(1, next), total);
|
|
487
|
+
setPageNumber(clamped);
|
|
488
|
+
setPageDraft(String(clamped));
|
|
489
|
+
}, []);
|
|
490
|
+
const onSwipeCommit = react.useCallback(
|
|
491
|
+
(direction) => {
|
|
492
|
+
if (direction === "next") {
|
|
493
|
+
goToPage(pageNumberRef.current + 1);
|
|
494
|
+
} else {
|
|
495
|
+
goToPage(pageNumberRef.current - 1);
|
|
496
|
+
}
|
|
497
|
+
},
|
|
498
|
+
[goToPage]
|
|
499
|
+
);
|
|
500
|
+
const {
|
|
501
|
+
stageRef,
|
|
502
|
+
transform,
|
|
503
|
+
isDragging,
|
|
504
|
+
snapBack,
|
|
505
|
+
handlers,
|
|
506
|
+
reset,
|
|
507
|
+
clearSnapBack
|
|
508
|
+
} = useZoomPanGestures({
|
|
509
|
+
swipeEnabled: numPages > 1,
|
|
510
|
+
onSwipeCommit,
|
|
511
|
+
wheelZoom: true,
|
|
512
|
+
doubleTap: "toggle"
|
|
513
|
+
});
|
|
514
|
+
react.useEffect(() => {
|
|
515
|
+
setPageNumber(initialPage);
|
|
516
|
+
setPageDraft(String(initialPage));
|
|
517
|
+
setZoomIndex(2);
|
|
518
|
+
setFitMode("width");
|
|
519
|
+
setRotation(0);
|
|
520
|
+
setNumPages(0);
|
|
521
|
+
setLoadError(false);
|
|
522
|
+
setThumbsOpen(false);
|
|
523
|
+
reset();
|
|
524
|
+
}, [fileUrl, initialPage, reset]);
|
|
525
|
+
react.useEffect(() => {
|
|
526
|
+
reset();
|
|
527
|
+
}, [pageNumber, reset]);
|
|
528
|
+
react.useEffect(() => {
|
|
529
|
+
if (!viewportRef.current) return;
|
|
530
|
+
const el = viewportRef.current;
|
|
531
|
+
const observer = new ResizeObserver((entries) => {
|
|
532
|
+
const rect = entries[0]?.contentRect;
|
|
533
|
+
if (!rect) return;
|
|
534
|
+
setContainerWidth(rect.width);
|
|
535
|
+
setContainerHeight(rect.height);
|
|
536
|
+
});
|
|
537
|
+
observer.observe(el);
|
|
538
|
+
setContainerWidth(el.clientWidth);
|
|
539
|
+
setContainerHeight(el.clientHeight);
|
|
540
|
+
return () => observer.disconnect();
|
|
541
|
+
}, []);
|
|
542
|
+
react.useEffect(() => {
|
|
543
|
+
function onFullscreenChange() {
|
|
544
|
+
setIsFullscreen(document.fullscreenElement === shellRef.current);
|
|
545
|
+
}
|
|
546
|
+
document.addEventListener("fullscreenchange", onFullscreenChange);
|
|
547
|
+
return () => document.removeEventListener("fullscreenchange", onFullscreenChange);
|
|
548
|
+
}, []);
|
|
549
|
+
react.useEffect(() => {
|
|
550
|
+
function onKeyDown(e) {
|
|
551
|
+
const target = e.target;
|
|
552
|
+
if (target && (target.tagName === "INPUT" || target.tagName === "TEXTAREA" || target.isContentEditable)) {
|
|
553
|
+
return;
|
|
554
|
+
}
|
|
555
|
+
switch (e.key) {
|
|
556
|
+
case "ArrowLeft":
|
|
557
|
+
case "PageUp":
|
|
558
|
+
e.preventDefault();
|
|
559
|
+
goToPage(pageNumberRef.current - 1);
|
|
560
|
+
break;
|
|
561
|
+
case "ArrowRight":
|
|
562
|
+
case "PageDown":
|
|
563
|
+
e.preventDefault();
|
|
564
|
+
goToPage(pageNumberRef.current + 1);
|
|
565
|
+
break;
|
|
566
|
+
case "Home":
|
|
567
|
+
e.preventDefault();
|
|
568
|
+
goToPage(1);
|
|
569
|
+
break;
|
|
570
|
+
case "End":
|
|
571
|
+
e.preventDefault();
|
|
572
|
+
goToPage(numPagesRef.current);
|
|
573
|
+
break;
|
|
574
|
+
case "+":
|
|
575
|
+
case "=":
|
|
576
|
+
e.preventDefault();
|
|
577
|
+
setZoomIndex((i) => Math.min(i + 1, ZOOM_STEPS.length - 1));
|
|
578
|
+
break;
|
|
579
|
+
case "-":
|
|
580
|
+
e.preventDefault();
|
|
581
|
+
setZoomIndex((i) => Math.max(i - 1, 0));
|
|
582
|
+
break;
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
window.addEventListener("keydown", onKeyDown);
|
|
586
|
+
return () => window.removeEventListener("keydown", onKeyDown);
|
|
587
|
+
}, [goToPage]);
|
|
588
|
+
const fitWidth = react.useCallback(() => {
|
|
589
|
+
setFitMode("width");
|
|
590
|
+
setZoomIndex(2);
|
|
591
|
+
reset();
|
|
592
|
+
}, [reset]);
|
|
593
|
+
const fitPage = react.useCallback(() => {
|
|
594
|
+
setFitMode("page");
|
|
595
|
+
setZoomIndex(2);
|
|
596
|
+
reset();
|
|
597
|
+
}, [reset]);
|
|
598
|
+
const zoomIn = react.useCallback(() => {
|
|
599
|
+
setZoomIndex((i) => Math.min(i + 1, ZOOM_STEPS.length - 1));
|
|
600
|
+
}, []);
|
|
601
|
+
const zoomOut = react.useCallback(() => {
|
|
602
|
+
setZoomIndex((i) => Math.max(i - 1, 0));
|
|
603
|
+
}, []);
|
|
604
|
+
const toggleFullscreen = react.useCallback(async () => {
|
|
605
|
+
if (!shellRef.current) return;
|
|
606
|
+
if (document.fullscreenElement === shellRef.current) {
|
|
607
|
+
await document.exitFullscreen();
|
|
608
|
+
} else {
|
|
609
|
+
await shellRef.current.requestFullscreen();
|
|
610
|
+
}
|
|
611
|
+
}, []);
|
|
612
|
+
function submitPageJump(e) {
|
|
613
|
+
e.preventDefault();
|
|
614
|
+
const parsed = Number.parseInt(pageDraft, 10);
|
|
615
|
+
if (Number.isFinite(parsed)) goToPage(parsed);
|
|
616
|
+
else setPageDraft(String(pageNumber));
|
|
617
|
+
}
|
|
618
|
+
const pageWidth = fitMode === "width" ? Math.max(containerWidth - 32, 240) * baseScale : void 0;
|
|
619
|
+
const pageHeight = fitMode === "page" ? Math.max(containerHeight - 32, 240) * baseScale : void 0;
|
|
620
|
+
const rawDownload = downloadUrl ?? fileUrl;
|
|
621
|
+
const downloadHref = `${rawDownload}${rawDownload.includes("?") ? "&" : "?"}download=1`;
|
|
622
|
+
const { scale: gestureScale, tx, ty } = transform;
|
|
623
|
+
const transition = snapBack && !isDragging && !prefersReducedMotion() ? `transform ${ZOOM_PAN_SWIPE_SNAP_MS}ms ease-out` : void 0;
|
|
624
|
+
const pageOf = labels.pageOf?.(pageNumber, numPages) ?? (numPages > 0 ? `${pageNumber} / ${numPages}` : "\u2014");
|
|
625
|
+
function renderThumbList(onSelect) {
|
|
626
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-2", children: Array.from({ length: numPages }, (_, i) => {
|
|
627
|
+
const n = i + 1;
|
|
628
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
629
|
+
LazyThumbnail,
|
|
630
|
+
{
|
|
631
|
+
pageNumber: n,
|
|
632
|
+
active: n === pageNumber,
|
|
633
|
+
width: THUMB_WIDTH,
|
|
634
|
+
onClick: () => onSelect(n),
|
|
635
|
+
ariaLabel: labels.thumbnailAria?.(n) ?? `P\xE1gina ${n}`
|
|
636
|
+
},
|
|
637
|
+
n
|
|
638
|
+
);
|
|
639
|
+
}) });
|
|
640
|
+
}
|
|
641
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
642
|
+
"div",
|
|
643
|
+
{
|
|
644
|
+
ref: shellRef,
|
|
645
|
+
className: cn(
|
|
646
|
+
"relative flex h-full min-h-0 w-full flex-col bg-background",
|
|
647
|
+
className
|
|
648
|
+
),
|
|
649
|
+
children: [
|
|
650
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex shrink-0 items-center gap-1 overflow-x-auto border-b px-2 py-2", children: [
|
|
651
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
652
|
+
"button",
|
|
653
|
+
{
|
|
654
|
+
type: "button",
|
|
655
|
+
className: "inline-flex h-8 w-8 shrink-0 items-center justify-center rounded-md border bg-background text-foreground hover:bg-accent",
|
|
656
|
+
onClick: () => setThumbsOpen((v) => !v),
|
|
657
|
+
"aria-label": thumbsOpen ? labels.hideThumbnails ?? "Ocultar miniaturas" : labels.showThumbnails ?? "Mostrar miniaturas",
|
|
658
|
+
"aria-pressed": thumbsOpen,
|
|
659
|
+
children: thumbsOpen ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.PanelLeftClose, { className: "h-4 w-4" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.PanelLeft, { className: "h-4 w-4" })
|
|
660
|
+
}
|
|
661
|
+
),
|
|
662
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
663
|
+
"button",
|
|
664
|
+
{
|
|
665
|
+
type: "button",
|
|
666
|
+
className: "inline-flex h-8 w-8 shrink-0 items-center justify-center rounded-md border bg-background hover:bg-accent disabled:opacity-50",
|
|
667
|
+
onClick: () => goToPage(pageNumber - 1),
|
|
668
|
+
disabled: pageNumber <= 1,
|
|
669
|
+
"aria-label": labels.previousPage ?? "P\xE1gina anterior",
|
|
670
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronLeft, { className: "h-4 w-4" })
|
|
671
|
+
}
|
|
672
|
+
),
|
|
673
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
674
|
+
"form",
|
|
675
|
+
{
|
|
676
|
+
onSubmit: submitPageJump,
|
|
677
|
+
className: "flex shrink-0 items-center gap-1 text-xs text-muted-foreground",
|
|
678
|
+
children: [
|
|
679
|
+
/* @__PURE__ */ jsxRuntime.jsx("label", { className: "sr-only", htmlFor: "pdf-page-jump", children: labels.pageJumpAria ?? "Ir a p\xE1gina" }),
|
|
680
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
681
|
+
"input",
|
|
682
|
+
{
|
|
683
|
+
id: "pdf-page-jump",
|
|
684
|
+
value: pageDraft,
|
|
685
|
+
onChange: (e) => setPageDraft(e.target.value),
|
|
686
|
+
className: "h-8 w-12 rounded-md border bg-background px-1 text-center text-foreground",
|
|
687
|
+
inputMode: "numeric"
|
|
688
|
+
}
|
|
689
|
+
),
|
|
690
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-10 whitespace-nowrap", children: pageOf })
|
|
691
|
+
]
|
|
692
|
+
}
|
|
693
|
+
),
|
|
694
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
695
|
+
"button",
|
|
696
|
+
{
|
|
697
|
+
type: "button",
|
|
698
|
+
className: "inline-flex h-8 w-8 shrink-0 items-center justify-center rounded-md border bg-background hover:bg-accent disabled:opacity-50",
|
|
699
|
+
onClick: () => goToPage(pageNumber + 1),
|
|
700
|
+
disabled: pageNumber >= numPages,
|
|
701
|
+
"aria-label": labels.nextPage ?? "P\xE1gina siguiente",
|
|
702
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, { className: "h-4 w-4" })
|
|
703
|
+
}
|
|
704
|
+
),
|
|
705
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
706
|
+
"button",
|
|
707
|
+
{
|
|
708
|
+
type: "button",
|
|
709
|
+
className: "inline-flex h-8 w-8 shrink-0 items-center justify-center rounded-md border bg-background hover:bg-accent disabled:opacity-50",
|
|
710
|
+
onClick: zoomOut,
|
|
711
|
+
disabled: zoomIndex <= 0,
|
|
712
|
+
"aria-label": labels.zoomOut ?? "Alejar",
|
|
713
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ZoomOut, { className: "h-4 w-4" })
|
|
714
|
+
}
|
|
715
|
+
),
|
|
716
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
717
|
+
"button",
|
|
718
|
+
{
|
|
719
|
+
type: "button",
|
|
720
|
+
className: "inline-flex h-8 shrink-0 items-center justify-center rounded-md border bg-background px-2 text-xs hover:bg-accent",
|
|
721
|
+
onClick: fitMode === "width" ? fitPage : fitWidth,
|
|
722
|
+
children: fitMode === "width" ? labels.fitPage ?? "Ajustar p\xE1gina" : labels.fitWidth ?? "Ajustar ancho"
|
|
723
|
+
}
|
|
724
|
+
),
|
|
725
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
726
|
+
"button",
|
|
727
|
+
{
|
|
728
|
+
type: "button",
|
|
729
|
+
className: "inline-flex h-8 w-8 shrink-0 items-center justify-center rounded-md border bg-background hover:bg-accent disabled:opacity-50",
|
|
730
|
+
onClick: zoomIn,
|
|
731
|
+
disabled: zoomIndex >= ZOOM_STEPS.length - 1,
|
|
732
|
+
"aria-label": labels.zoomIn ?? "Acercar",
|
|
733
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ZoomIn, { className: "h-4 w-4" })
|
|
734
|
+
}
|
|
735
|
+
),
|
|
736
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
737
|
+
"button",
|
|
738
|
+
{
|
|
739
|
+
type: "button",
|
|
740
|
+
className: "inline-flex h-8 w-8 shrink-0 items-center justify-center rounded-md border bg-background hover:bg-accent",
|
|
741
|
+
onClick: () => setRotation((r) => (r + 90) % 360),
|
|
742
|
+
"aria-label": labels.rotate ?? "Rotar",
|
|
743
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.RotateCw, { className: "h-4 w-4" })
|
|
744
|
+
}
|
|
745
|
+
),
|
|
746
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
747
|
+
"button",
|
|
748
|
+
{
|
|
749
|
+
type: "button",
|
|
750
|
+
className: "inline-flex h-8 w-8 shrink-0 items-center justify-center rounded-md border bg-background hover:bg-accent",
|
|
751
|
+
onClick: () => void toggleFullscreen(),
|
|
752
|
+
"aria-label": isFullscreen ? labels.exitFullscreen ?? "Salir de pantalla completa" : labels.enterFullscreen ?? "Pantalla completa",
|
|
753
|
+
children: isFullscreen ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Minimize2, { className: "h-4 w-4" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Maximize2, { className: "h-4 w-4" })
|
|
754
|
+
}
|
|
755
|
+
),
|
|
756
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
757
|
+
"a",
|
|
758
|
+
{
|
|
759
|
+
href: downloadHref,
|
|
760
|
+
download: fileName,
|
|
761
|
+
"aria-label": labels.downloadAria ?? labels.download ?? "Descargar",
|
|
762
|
+
className: "inline-flex h-8 shrink-0 items-center gap-1 rounded-md border bg-background px-2 text-xs hover:bg-accent",
|
|
763
|
+
children: [
|
|
764
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Download, { className: "h-4 w-4" }),
|
|
765
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "hidden sm:inline", children: labels.download ?? "Descargar" })
|
|
766
|
+
]
|
|
767
|
+
}
|
|
768
|
+
)
|
|
769
|
+
] }),
|
|
770
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative flex min-h-0 flex-1", children: [
|
|
771
|
+
numPages > 0 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
772
|
+
"div",
|
|
773
|
+
{
|
|
774
|
+
className: cn(
|
|
775
|
+
"hidden w-40 shrink-0 overflow-y-auto border-r bg-background p-2 lg:block",
|
|
776
|
+
!thumbsOpen && "lg:hidden"
|
|
777
|
+
),
|
|
778
|
+
children: renderThumbList(goToPage)
|
|
779
|
+
}
|
|
780
|
+
),
|
|
781
|
+
thumbsOpen && numPages > 0 && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
782
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
783
|
+
"button",
|
|
784
|
+
{
|
|
785
|
+
type: "button",
|
|
786
|
+
"aria-label": labels.hideThumbnails ? `${labels.hideThumbnails} (fondo)` : "Cerrar miniaturas (fondo)",
|
|
787
|
+
className: "absolute inset-0 z-20 bg-black/40 lg:hidden",
|
|
788
|
+
onClick: () => setThumbsOpen(false)
|
|
789
|
+
}
|
|
790
|
+
),
|
|
791
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-y-0 left-0 z-30 w-40 overflow-y-auto border-r bg-background p-2 shadow-lg lg:hidden", children: renderThumbList((n) => {
|
|
792
|
+
goToPage(n);
|
|
793
|
+
setThumbsOpen(false);
|
|
794
|
+
}) })
|
|
795
|
+
] }),
|
|
796
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
797
|
+
"div",
|
|
798
|
+
{
|
|
799
|
+
ref: viewportRef,
|
|
800
|
+
className: cn(
|
|
801
|
+
"relative min-h-0 flex-1 overflow-hidden bg-muted/40",
|
|
802
|
+
gestureScale > ZOOM_PAN_MIN_SCALE && (isDragging ? "cursor-grabbing" : "cursor-grab")
|
|
803
|
+
),
|
|
804
|
+
children: loadError ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
805
|
+
ErrorState,
|
|
806
|
+
{
|
|
807
|
+
title: labels.loadError ?? "No se pudo cargar el PDF",
|
|
808
|
+
description: labels.loadErrorDescription ?? "El archivo puede estar da\xF1ado, cifrado o bloqueado.",
|
|
809
|
+
action: /* @__PURE__ */ jsxRuntime.jsx(
|
|
810
|
+
"a",
|
|
811
|
+
{
|
|
812
|
+
href: downloadHref,
|
|
813
|
+
download: fileName,
|
|
814
|
+
className: "text-sm text-primary underline",
|
|
815
|
+
children: labels.download ?? "Descargar"
|
|
816
|
+
}
|
|
817
|
+
)
|
|
818
|
+
}
|
|
819
|
+
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
820
|
+
"div",
|
|
821
|
+
{
|
|
822
|
+
ref: stageRef,
|
|
823
|
+
className: "flex min-h-full touch-none items-start justify-center p-4",
|
|
824
|
+
style: {
|
|
825
|
+
transform: `translate(${tx}px, ${ty}px) scale(${gestureScale})`,
|
|
826
|
+
transition
|
|
827
|
+
},
|
|
828
|
+
onPointerDown: handlers.onPointerDown,
|
|
829
|
+
onPointerMove: handlers.onPointerMove,
|
|
830
|
+
onPointerUp: handlers.onPointerUp,
|
|
831
|
+
onPointerCancel: handlers.onPointerCancel,
|
|
832
|
+
onTransitionEnd: clearSnapBack,
|
|
833
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
834
|
+
reactPdf.Document,
|
|
835
|
+
{
|
|
836
|
+
file: fileUrl,
|
|
837
|
+
onLoadSuccess: ({ numPages: pages }) => {
|
|
838
|
+
setNumPages(pages);
|
|
839
|
+
setLoadError(false);
|
|
840
|
+
const start = Math.min(Math.max(1, initialPage), pages);
|
|
841
|
+
setPageNumber(start);
|
|
842
|
+
setPageDraft(String(start));
|
|
843
|
+
},
|
|
844
|
+
onLoadError: () => setLoadError(true),
|
|
845
|
+
loading: /* @__PURE__ */ jsxRuntime.jsx(LoadingState, { label: labels.loading ?? "Cargando PDF\u2026" }),
|
|
846
|
+
error: /* @__PURE__ */ jsxRuntime.jsx(
|
|
847
|
+
ErrorState,
|
|
848
|
+
{
|
|
849
|
+
title: labels.loadError ?? "No se pudo cargar el PDF"
|
|
850
|
+
}
|
|
851
|
+
),
|
|
852
|
+
children: numPages > 0 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
853
|
+
reactPdf.Page,
|
|
854
|
+
{
|
|
855
|
+
pageNumber,
|
|
856
|
+
width: pageWidth,
|
|
857
|
+
height: pageHeight,
|
|
858
|
+
rotate: rotation,
|
|
859
|
+
renderTextLayer: true,
|
|
860
|
+
renderAnnotationLayer: true
|
|
861
|
+
}
|
|
862
|
+
)
|
|
863
|
+
}
|
|
864
|
+
)
|
|
865
|
+
}
|
|
866
|
+
)
|
|
867
|
+
}
|
|
868
|
+
)
|
|
869
|
+
] })
|
|
870
|
+
]
|
|
871
|
+
}
|
|
872
|
+
);
|
|
873
|
+
}
|
|
874
|
+
function Dialog({
|
|
875
|
+
...props
|
|
876
|
+
}) {
|
|
877
|
+
return /* @__PURE__ */ jsxRuntime.jsx(DialogPrimitive__namespace.Root, { "data-slot": "dialog", ...props });
|
|
878
|
+
}
|
|
879
|
+
function DialogPortal({
|
|
880
|
+
...props
|
|
881
|
+
}) {
|
|
882
|
+
return /* @__PURE__ */ jsxRuntime.jsx(DialogPrimitive__namespace.Portal, { "data-slot": "dialog-portal", ...props });
|
|
883
|
+
}
|
|
884
|
+
function DialogOverlay({
|
|
885
|
+
className,
|
|
886
|
+
...props
|
|
887
|
+
}) {
|
|
888
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
889
|
+
DialogPrimitive__namespace.Overlay,
|
|
890
|
+
{
|
|
891
|
+
"data-slot": "dialog-overlay",
|
|
892
|
+
className: cn(
|
|
893
|
+
"data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/50",
|
|
894
|
+
className
|
|
895
|
+
),
|
|
896
|
+
...props
|
|
897
|
+
}
|
|
898
|
+
);
|
|
899
|
+
}
|
|
900
|
+
function DialogContent({
|
|
901
|
+
className,
|
|
902
|
+
children,
|
|
903
|
+
showCloseButton = true,
|
|
904
|
+
...props
|
|
905
|
+
}) {
|
|
906
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(DialogPortal, { "data-slot": "dialog-portal", children: [
|
|
907
|
+
/* @__PURE__ */ jsxRuntime.jsx(DialogOverlay, {}),
|
|
908
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
909
|
+
DialogPrimitive__namespace.Content,
|
|
910
|
+
{
|
|
911
|
+
"data-slot": "dialog-content",
|
|
912
|
+
className: cn(
|
|
913
|
+
"bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border p-6 shadow-lg duration-200 outline-none sm:max-w-lg",
|
|
914
|
+
className
|
|
915
|
+
),
|
|
916
|
+
...props,
|
|
917
|
+
children: [
|
|
918
|
+
children,
|
|
919
|
+
showCloseButton && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
920
|
+
DialogPrimitive__namespace.Close,
|
|
921
|
+
{
|
|
922
|
+
"data-slot": "dialog-close",
|
|
923
|
+
className: "ring-offset-background focus:ring-ring data-[state=open]:bg-accent data-[state=open]:text-muted-foreground absolute top-4 right-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
924
|
+
children: [
|
|
925
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.XIcon, {}),
|
|
926
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Close" })
|
|
927
|
+
]
|
|
928
|
+
}
|
|
929
|
+
)
|
|
930
|
+
]
|
|
931
|
+
}
|
|
932
|
+
)
|
|
933
|
+
] });
|
|
934
|
+
}
|
|
935
|
+
function DialogTitle({
|
|
936
|
+
className,
|
|
937
|
+
...props
|
|
938
|
+
}) {
|
|
939
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
940
|
+
DialogPrimitive__namespace.Title,
|
|
941
|
+
{
|
|
942
|
+
"data-slot": "dialog-title",
|
|
943
|
+
className: cn("text-lg leading-none font-semibold", className),
|
|
944
|
+
...props
|
|
945
|
+
}
|
|
946
|
+
);
|
|
947
|
+
}
|
|
948
|
+
function DialogDescription({
|
|
949
|
+
className,
|
|
950
|
+
...props
|
|
951
|
+
}) {
|
|
952
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
953
|
+
DialogPrimitive__namespace.Description,
|
|
954
|
+
{
|
|
955
|
+
"data-slot": "dialog-description",
|
|
956
|
+
className: cn("text-muted-foreground text-sm", className),
|
|
957
|
+
...props
|
|
958
|
+
}
|
|
959
|
+
);
|
|
960
|
+
}
|
|
961
|
+
function MediaViewerDialog({
|
|
962
|
+
open,
|
|
963
|
+
onOpenChange,
|
|
964
|
+
children,
|
|
965
|
+
labels,
|
|
966
|
+
className,
|
|
967
|
+
contentClassName,
|
|
968
|
+
showCloseButton = true
|
|
969
|
+
}) {
|
|
970
|
+
const closeLabel = labels?.close ?? "Cerrar";
|
|
971
|
+
const title = labels?.title ?? "Visor";
|
|
972
|
+
const description = labels?.description ?? title;
|
|
973
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
974
|
+
DialogContent,
|
|
975
|
+
{
|
|
976
|
+
showCloseButton: false,
|
|
977
|
+
className: cn(
|
|
978
|
+
"inset-0 flex h-dvh max-h-dvh w-screen max-w-none translate-x-0 translate-y-0 top-0 left-0 gap-0 overflow-hidden rounded-none border-0 p-0 shadow-none sm:max-w-none",
|
|
979
|
+
contentClassName,
|
|
980
|
+
className
|
|
981
|
+
),
|
|
982
|
+
children: [
|
|
983
|
+
/* @__PURE__ */ jsxRuntime.jsx(DialogTitle, { className: "sr-only", children: title }),
|
|
984
|
+
/* @__PURE__ */ jsxRuntime.jsx(DialogDescription, { className: "sr-only", children: description }),
|
|
985
|
+
showCloseButton && /* @__PURE__ */ jsxRuntime.jsx(
|
|
986
|
+
"button",
|
|
987
|
+
{
|
|
988
|
+
type: "button",
|
|
989
|
+
onClick: () => onOpenChange(false),
|
|
990
|
+
"aria-label": closeLabel,
|
|
991
|
+
className: "absolute top-3 right-3 z-20 rounded-full bg-black/50 p-2 text-white transition-colors hover:bg-black/70",
|
|
992
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "h-5 w-5" })
|
|
993
|
+
}
|
|
994
|
+
),
|
|
995
|
+
children
|
|
996
|
+
]
|
|
997
|
+
}
|
|
998
|
+
) });
|
|
999
|
+
}
|
|
1000
|
+
function PdfViewerDialog({
|
|
1001
|
+
open,
|
|
1002
|
+
onOpenChange,
|
|
1003
|
+
title,
|
|
1004
|
+
fileUrl,
|
|
1005
|
+
fileName,
|
|
1006
|
+
downloadUrl,
|
|
1007
|
+
workerSrc,
|
|
1008
|
+
initialPage,
|
|
1009
|
+
labels
|
|
1010
|
+
}) {
|
|
1011
|
+
const viewerLabels = labels;
|
|
1012
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1013
|
+
MediaViewerDialog,
|
|
1014
|
+
{
|
|
1015
|
+
open,
|
|
1016
|
+
onOpenChange,
|
|
1017
|
+
labels: {
|
|
1018
|
+
close: labels.close,
|
|
1019
|
+
title,
|
|
1020
|
+
description: labels.dialogDescription ?? title
|
|
1021
|
+
},
|
|
1022
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex h-full min-h-0 flex-col pt-12", children: [
|
|
1023
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-b px-4 py-2 pr-14", children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "truncate text-sm font-medium", children: title }) }),
|
|
1024
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1025
|
+
PdfViewer,
|
|
1026
|
+
{
|
|
1027
|
+
fileUrl,
|
|
1028
|
+
fileName: fileName ?? title,
|
|
1029
|
+
downloadUrl,
|
|
1030
|
+
workerSrc,
|
|
1031
|
+
initialPage,
|
|
1032
|
+
labels: viewerLabels,
|
|
1033
|
+
className: "min-h-0 flex-1"
|
|
1034
|
+
}
|
|
1035
|
+
)
|
|
1036
|
+
] })
|
|
1037
|
+
}
|
|
1038
|
+
);
|
|
1039
|
+
}
|
|
1040
|
+
|
|
1041
|
+
exports.PdfViewer = PdfViewer;
|
|
1042
|
+
exports.PdfViewerDialog = PdfViewerDialog;
|
|
1043
|
+
exports.configurePdfWorker = configurePdfWorker;
|
|
1044
|
+
//# sourceMappingURL=pdf.cjs.map
|
|
1045
|
+
//# sourceMappingURL=pdf.cjs.map
|