@peeekpage/viewer 0.3.13

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/README.md ADDED
@@ -0,0 +1,91 @@
1
+ # @peeekpage/viewer
2
+
3
+ Embeddable document viewers for [peeek.page](https://peeek.page). This package
4
+ ships **PeeekViewer**, an animated 3D flipbook React component. It reads the
5
+ preview manifest that the renderer writes to your bucket and renders the page
6
+ images. No telemetry, no runtime dependencies.
7
+
8
+ ## Install
9
+
10
+ ```bash
11
+ npm install @peeekpage/viewer
12
+ ```
13
+
14
+ React 18+ is a peer dependency.
15
+
16
+ ## Usage
17
+
18
+ ```tsx
19
+ import { PeeekViewer } from '@peeekpage/viewer'
20
+ import '@peeekpage/viewer/styles.css'
21
+
22
+ export function Preview() {
23
+ return (
24
+ <PeeekViewer
25
+ src="https://your-bucket.example.com/previews/doc-123/manifest.json"
26
+ accentColor="#0362FC"
27
+ layout="double"
28
+ downloadUrl="https://your-bucket.example.com/originals/doc-123.pdf"
29
+ />
30
+ )
31
+ }
32
+ ```
33
+
34
+ ### In-memory pages
35
+
36
+ When the host already holds the rendered page URLs (e.g. a live render it is
37
+ polling itself), pass them via `pages` instead of `src`. No fetch happens, and
38
+ the array can grow over time as a render streams in:
39
+
40
+ ```tsx
41
+ <PeeekViewer
42
+ mode="coverflow"
43
+ pages={pageUrls} // string[] of presigned image URLs
44
+ filename="report.pdf"
45
+ mimeType="application/pdf"
46
+ />
47
+ ```
48
+
49
+ ## Props
50
+
51
+ | Prop | Type | Default | Notes |
52
+ | --- | --- | --- | --- |
53
+ | `src` | `string` | - | Manifest `.json` URL. Required unless `pages` is given. |
54
+ | `pages` | `string[]` | - | In-memory page image URLs. When set, the viewer renders these directly and does not fetch `src`. URLs are sanitized like the manifest path. |
55
+ | `filename` | `string` | - | Header filename for the `pages` path (coverflow). |
56
+ | `mimeType` | `string` | - | Header type badge for the `pages` path (coverflow). |
57
+ | `mode` | `'flip' \| 'coverflow'` | `'flip'` | `flip` is the 3D page-turn book; `coverflow` is a peeking 3D carousel with a header and thumbnail strip. |
58
+ | `logo` | `string` | - | Logo image URL. |
59
+ | `logoLink` | `string` | - | Logo link (http/https only). |
60
+ | `accentColor` | `string` | `#6E79D6` | Hex or `rgb()`. |
61
+ | `background` | `'color' \| 'image' \| 'transparent'` | `'color'` | |
62
+ | `backgroundColor` | `string` | - | Solid or gradient CSS. |
63
+ | `backgroundImage` | `string` | - | Used when `background='image'`. |
64
+ | `layout` | `'single' \| 'double'` | `'double'` | |
65
+ | `pageShadows` | `boolean` | `true` | |
66
+ | `rtl` | `boolean` | `false` | |
67
+ | `animateInteractions` | `boolean` | `true` | |
68
+ | `skin` | `'classic' \| 'minimal'` | `'classic'` | |
69
+ | `language` | `'en' \| 'pt-BR'` | `'en'` | Tooltip language. |
70
+ | `autoTransition` | `boolean` | `false` | |
71
+ | `autoTransitionInterval` | `number` | `5000` | ms. |
72
+ | `navigationControls` | `boolean` | `true` | Master toolbar toggle. |
73
+ | `fullscreen` | `boolean` | `true` | |
74
+ | `arrows` | `boolean` | `true` | |
75
+ | `navigationBar` | `boolean` | `true` | |
76
+ | `pagesOverview` | `boolean` | `true` | Thumbnails. |
77
+ | `downloadUrl` | `string` | - | Shows a download button when set. |
78
+ | `pollInterval` | `number` | `2000` | ms between WIP polls. |
79
+ | `className` | `string` | - | Extra class on the root. |
80
+
81
+ `coverflow` mode honors `logo`/`accentColor`/`background`, `fullscreen`, `arrows`,
82
+ `pagesOverview` (thumbnails), `rtl`, `autoTransition`/`autoTransitionInterval`,
83
+ `downloadUrl` and `language`. The flip-only props (`layout`, `pageShadows`,
84
+ `navigationBar`) are ignored in `coverflow`.
85
+
86
+ ## Security
87
+
88
+ All host-provided URLs (`logo`, `logoLink`, `backgroundImage`, `downloadUrl`,
89
+ and every page URL in the manifest) are validated against an http/https
90
+ allowlist before they reach the DOM. The component never injects raw HTML and
91
+ makes no network calls beyond fetching the manifest and loading page images.
@@ -0,0 +1,54 @@
1
+ import { JSX as JSX_2 } from 'react';
2
+
3
+ export declare type Background = 'color' | 'image' | 'transparent';
4
+
5
+ export declare type Lang = (typeof LANGUAGES)[number];
6
+
7
+ declare const LANGUAGES: readonly ["en", "pt-BR"];
8
+
9
+ export declare type Layout = 'single' | 'double';
10
+
11
+ export declare type Mode = 'flip' | 'coverflow';
12
+
13
+ /**
14
+ * PeeekViewer: embeddable document viewer. Reads the worker manifest at `src`
15
+ * (or host-provided `pages`) and renders its pages in the selected mode (flip
16
+ * or coverflow) with branding and a gated toolbar. Every host-provided URL is
17
+ * sanitized before it reaches the DOM.
18
+ */
19
+ export declare function PeeekViewer(props: PeeekViewerProps): JSX_2.Element;
20
+
21
+ export declare interface PeeekViewerProps {
22
+ src?: string;
23
+ pages?: string[];
24
+ filename?: string;
25
+ mimeType?: string;
26
+ mode?: Mode;
27
+ logo?: string;
28
+ logoLink?: string;
29
+ accentColor?: string;
30
+ background?: Background;
31
+ backgroundColor?: string;
32
+ backgroundImage?: string;
33
+ layout?: Layout;
34
+ fillHeight?: boolean;
35
+ pageShadows?: boolean;
36
+ rtl?: boolean;
37
+ animateInteractions?: boolean;
38
+ skin?: Skin;
39
+ language?: Lang;
40
+ autoTransition?: boolean;
41
+ autoTransitionInterval?: number;
42
+ navigationControls?: boolean;
43
+ fullscreen?: boolean;
44
+ arrows?: boolean;
45
+ navigationBar?: boolean;
46
+ pagesOverview?: boolean;
47
+ downloadUrl?: string;
48
+ pollInterval?: number;
49
+ className?: string;
50
+ }
51
+
52
+ export declare type Skin = 'classic' | 'minimal' | 'showcase';
53
+
54
+ export { }
package/dist/index.js ADDED
@@ -0,0 +1,788 @@
1
+ import { jsxs as v, jsx as o, Fragment as Ue } from "react/jsx-runtime";
2
+ import { useState as T, useRef as U, useEffect as $, useCallback as S, useMemo as Be } from "react";
3
+ const De = /* @__PURE__ */ new Set(["http:", "https:"]);
4
+ function Z(t) {
5
+ if (typeof t != "string") return null;
6
+ const e = t.trim();
7
+ if (e === "" || e.includes(" ")) return null;
8
+ const n = typeof window < "u" ? window.location.href : void 0;
9
+ let r;
10
+ try {
11
+ r = new URL(e, n);
12
+ } catch {
13
+ return null;
14
+ }
15
+ return De.has(r.protocol) ? r.href : null;
16
+ }
17
+ const je = /^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/, Xe = /^rgba?\([ \t]*\d{1,3}[ \t]*,[ \t]*\d{1,3}[ \t]*,[ \t]*\d{1,3}[ \t]*(?:,[ \t]*(?:0|1|0?\.\d+)[ \t]*)?\)$/;
18
+ function me(t) {
19
+ if (typeof t != "string") return null;
20
+ const e = t.trim();
21
+ return je.test(e) || Xe.test(e) ? e : null;
22
+ }
23
+ const He = /url\(|image\(|image-set\(|element\(|expression|@|\/\*|;|\{|\}|<|>|\\/i, Ge = /^(repeating-)?(linear|radial|conic)-gradient\([a-z0-9#.,%()\/\s-]*\)$/i, Ye = /^hsla?\([a-z0-9.,%\/\s-]*\)$/i;
24
+ function Ve(t) {
25
+ if (typeof t != "string") return null;
26
+ const e = t.trim();
27
+ if (e === "" || He.test(e)) return null;
28
+ const n = me(e);
29
+ return n !== null ? n : Ye.test(e) || Ge.test(e) ? e : null;
30
+ }
31
+ const We = ["en", "pt-BR"], ge = {
32
+ prev: "Previous page",
33
+ next: "Next page",
34
+ zoom: "Zoom level",
35
+ zoomIn: "Zoom in",
36
+ zoomOut: "Zoom out",
37
+ thumbnails: "Page thumbnails",
38
+ fullscreen: "Fullscreen",
39
+ openFullscreen: "View page fullscreen",
40
+ download: "Download",
41
+ page: "page",
42
+ pages: "pages",
43
+ loading: "Loading document…",
44
+ error: "Could not load this document."
45
+ }, qe = {
46
+ prev: "Página anterior",
47
+ next: "Próxima página",
48
+ zoom: "Nível de zoom",
49
+ zoomIn: "Ampliar",
50
+ zoomOut: "Reduzir",
51
+ thumbnails: "Miniaturas das páginas",
52
+ fullscreen: "Tela cheia",
53
+ openFullscreen: "Ver página em tela cheia",
54
+ download: "Baixar",
55
+ page: "página",
56
+ pages: "páginas",
57
+ loading: "Carregando documento…",
58
+ error: "Não foi possível carregar este documento."
59
+ }, Je = { en: ge, "pt-BR": qe };
60
+ function Ke(t) {
61
+ return Je[t] ?? ge;
62
+ }
63
+ const Qe = "#6E79D6";
64
+ function C(t, e) {
65
+ return typeof t == "boolean" ? t : e;
66
+ }
67
+ function j(t, e, n) {
68
+ return e.includes(t) ? t : n;
69
+ }
70
+ function et(t) {
71
+ return {
72
+ src: typeof t.src == "string" ? t.src : "",
73
+ mode: j(t.mode, ["flip", "coverflow"], "flip"),
74
+ logo: Z(t.logo),
75
+ logoLink: Z(t.logoLink),
76
+ accentColor: me(t.accentColor) ?? Qe,
77
+ background: j(t.background, ["color", "image", "transparent"], "color"),
78
+ backgroundColor: Ve(t.backgroundColor),
79
+ backgroundImage: Z(t.backgroundImage),
80
+ layout: j(t.layout, ["single", "double"], "double"),
81
+ fillHeight: C(t.fillHeight, !1),
82
+ pageShadows: C(t.pageShadows, !0),
83
+ rtl: C(t.rtl, !1),
84
+ animateInteractions: C(t.animateInteractions, !0),
85
+ skin: j(t.skin, ["classic", "minimal", "showcase"], "classic"),
86
+ language: j(t.language, We, "en"),
87
+ autoTransition: C(t.autoTransition, !1),
88
+ autoTransitionInterval: typeof t.autoTransitionInterval == "number" && t.autoTransitionInterval > 0 ? t.autoTransitionInterval : 5e3,
89
+ navigationControls: C(t.navigationControls, !0),
90
+ fullscreen: C(t.fullscreen, !0),
91
+ arrows: C(t.arrows, !0),
92
+ navigationBar: C(t.navigationBar, !0),
93
+ pagesOverview: C(t.pagesOverview, !0),
94
+ downloadUrl: Z(t.downloadUrl),
95
+ pollInterval: typeof t.pollInterval == "number" && t.pollInterval > 0 ? t.pollInterval : 2e3,
96
+ className: typeof t.className == "string" ? t.className : ""
97
+ };
98
+ }
99
+ const ne = 5e3;
100
+ function X(t) {
101
+ return typeof t == "string" ? t : "";
102
+ }
103
+ function tt(t) {
104
+ if (t === null || typeof t != "object" || Array.isArray(t))
105
+ return { ok: !1, error: "manifest is not an object" };
106
+ const e = t;
107
+ if (!Array.isArray(e.pages))
108
+ return { ok: !1, error: "manifest.pages is missing or not an array" };
109
+ if (e.pages.length > ne)
110
+ return { ok: !1, error: "manifest.pages exceeds the maximum" };
111
+ const n = e.total_pages, r = typeof n == "number" && Number.isFinite(n) && n >= 0 ? n : e.pages.length;
112
+ if (r > ne)
113
+ return { ok: !1, error: "manifest.total_pages exceeds the maximum" };
114
+ const l = [];
115
+ for (const g of e.pages) {
116
+ if (g === null || typeof g != "object") continue;
117
+ const s = Z(g.url);
118
+ s && l.push(s);
119
+ }
120
+ if (l.length === 0)
121
+ return { ok: !1, error: "manifest has no usable pages" };
122
+ const c = e.status === "wip" ? "wip" : "done", f = e.metadata && typeof e.metadata == "object" ? e.metadata : {}, h = {
123
+ fileId: X(f.file_id),
124
+ filename: X(f.filename),
125
+ creationDate: X(f.creation_date),
126
+ fileSize: X(f.file_size),
127
+ mimeType: X(f.mime_type)
128
+ };
129
+ return {
130
+ ok: !0,
131
+ value: { status: c, totalPages: r, pages: l, metadata: h }
132
+ };
133
+ }
134
+ function nt(t, e) {
135
+ if (!Array.isArray(t) || t.length > ne) return null;
136
+ const n = [];
137
+ for (const l of t) {
138
+ const c = Z(l);
139
+ c && n.push(c);
140
+ }
141
+ return n.length === 0 ? null : {
142
+ status: "done",
143
+ totalPages: typeof e.total == "number" && Number.isFinite(e.total) && e.total > n.length ? e.total : n.length,
144
+ pages: n,
145
+ metadata: {
146
+ fileId: "",
147
+ filename: typeof e.filename == "string" ? e.filename : "",
148
+ creationDate: "",
149
+ fileSize: "",
150
+ mimeType: typeof e.mimeType == "string" ? e.mimeType : ""
151
+ }
152
+ };
153
+ }
154
+ function rt(t, e) {
155
+ const [n, r] = T("loading"), [l, c] = T(null), [f, h] = T(null), g = U(null);
156
+ return $(() => {
157
+ let s = !1;
158
+ if (r("loading"), c(null), h(null), !t) return;
159
+ const b = () => {
160
+ g.current !== null && (clearTimeout(g.current), g.current = null);
161
+ }, p = async () => {
162
+ let u;
163
+ try {
164
+ const _ = await fetch(t);
165
+ if (!_.ok) throw new Error(`HTTP ${_.status}`);
166
+ u = await _.json();
167
+ } catch (_) {
168
+ if (s) return;
169
+ h(_ instanceof Error ? _.message : "fetch failed"), r("error");
170
+ return;
171
+ }
172
+ if (s) return;
173
+ const i = tt(u);
174
+ if (!i.ok) {
175
+ h(i.error), r("error");
176
+ return;
177
+ }
178
+ c(i.value), r("ready"), i.value.status === "wip" && (g.current = setTimeout(p, e));
179
+ };
180
+ return p(), () => {
181
+ s = !0, b();
182
+ };
183
+ }, [t, e]), { state: n, manifest: l, error: f };
184
+ }
185
+ function at(t) {
186
+ const [e, n] = T(!1);
187
+ $(() => {
188
+ const l = () => n(document.fullscreenElement != null);
189
+ return document.addEventListener("fullscreenchange", l), () => document.removeEventListener("fullscreenchange", l);
190
+ }, []);
191
+ const r = S(async () => {
192
+ const l = t.current;
193
+ if (l)
194
+ try {
195
+ document.fullscreenElement ? await document.exitFullscreen() : await l.requestFullscreen();
196
+ } catch {
197
+ }
198
+ }, [t]);
199
+ return { isFullscreen: e, toggle: r };
200
+ }
201
+ const fe = "(prefers-reduced-motion: reduce)";
202
+ function pe() {
203
+ const [t, e] = T(() => {
204
+ var n;
205
+ return ((n = matchMedia == null ? void 0 : matchMedia(fe)) == null ? void 0 : n.matches) ?? !1;
206
+ });
207
+ return $(() => {
208
+ const n = typeof matchMedia == "function" ? matchMedia(fe) : void 0;
209
+ if (!(n != null && n.addEventListener)) return;
210
+ const r = () => e(n.matches);
211
+ return n.addEventListener("change", r), () => n.removeEventListener("change", r);
212
+ }, []), t;
213
+ }
214
+ function re(t, e) {
215
+ return t <= 0 ? 0 : e === "single" ? t : 1 + Math.ceil((t - 1) / 2);
216
+ }
217
+ function ot(t, e) {
218
+ return e === "single" ? t : t <= 0 ? 0 : Math.floor((t - 1) / 2) + 1;
219
+ }
220
+ function Y(t, e, n) {
221
+ if (e <= 0) return { left: -1, right: -1 };
222
+ if (n === "single")
223
+ return { left: -1, right: t >= 0 && t < e ? t : -1 };
224
+ if (t <= 0)
225
+ return { left: -1, right: 0 };
226
+ const r = 2 * t - 1, l = 2 * t;
227
+ return { left: r < e ? r : -1, right: l < e ? l : -1 };
228
+ }
229
+ function he(t, e, n) {
230
+ const { left: r, right: l } = Y(t, e, n), c = [];
231
+ return r >= 0 && c.push(r), l >= 0 && c.push(l), c;
232
+ }
233
+ function Q(t, e, n) {
234
+ const r = re(e, n) - 1;
235
+ return t < 0 ? 0 : t > r ? r : t;
236
+ }
237
+ function lt(t) {
238
+ const {
239
+ strings: e,
240
+ label: n,
241
+ progress: r,
242
+ zoom: l,
243
+ minZoom: c,
244
+ maxZoom: f,
245
+ thumbsOpen: h,
246
+ isFullscreen: g,
247
+ downloadUrl: s,
248
+ show: b,
249
+ onZoomIn: p,
250
+ onZoomOut: u,
251
+ onZoomSet: i,
252
+ onToggleThumbs: _,
253
+ onToggleFullscreen: L
254
+ } = t;
255
+ return /* @__PURE__ */ v("div", { className: "peeek__toolbar", children: [
256
+ /* @__PURE__ */ o("span", { className: "peeek__label", children: n }),
257
+ b.bar && /* @__PURE__ */ o("div", { className: "peeek__scrubber", "aria-hidden": !0, children: /* @__PURE__ */ o("div", { className: "peeek__scrubber-fill", style: { width: `${r}%` } }) }),
258
+ /* @__PURE__ */ o(
259
+ "button",
260
+ {
261
+ type: "button",
262
+ className: "peeek__btn",
263
+ "aria-label": e.zoomOut,
264
+ disabled: l <= c,
265
+ onClick: u,
266
+ children: "−"
267
+ }
268
+ ),
269
+ /* @__PURE__ */ o(
270
+ "input",
271
+ {
272
+ type: "range",
273
+ "aria-label": e.zoom,
274
+ min: c,
275
+ max: f,
276
+ step: 0.25,
277
+ value: l,
278
+ onChange: (w) => i(Number(w.target.value))
279
+ }
280
+ ),
281
+ /* @__PURE__ */ o(
282
+ "button",
283
+ {
284
+ type: "button",
285
+ className: "peeek__btn",
286
+ "aria-label": e.zoomIn,
287
+ disabled: l >= f,
288
+ onClick: p,
289
+ children: "+"
290
+ }
291
+ ),
292
+ b.thumbnails && /* @__PURE__ */ o(
293
+ "button",
294
+ {
295
+ type: "button",
296
+ className: `peeek__btn${h ? " peeek__btn--active" : ""}`,
297
+ "aria-label": e.thumbnails,
298
+ "aria-pressed": h,
299
+ onClick: _,
300
+ children: "▦"
301
+ }
302
+ ),
303
+ s && /* @__PURE__ */ o(
304
+ "a",
305
+ {
306
+ className: "peeek__btn",
307
+ href: s,
308
+ "aria-label": e.download,
309
+ target: "_blank",
310
+ rel: "noopener noreferrer",
311
+ download: !0,
312
+ children: "↓"
313
+ }
314
+ ),
315
+ b.fullscreen && /* @__PURE__ */ o(
316
+ "button",
317
+ {
318
+ type: "button",
319
+ className: `peeek__btn${g ? " peeek__btn--active" : ""}`,
320
+ "aria-label": e.fullscreen,
321
+ "aria-pressed": g,
322
+ onClick: L,
323
+ children: "⛶"
324
+ }
325
+ )
326
+ ] });
327
+ }
328
+ function st({ pages: t, layout: e, rtl: n, activePages: r, onJump: l }) {
329
+ const c = t.length, f = new Set(r), h = re(c, e);
330
+ return /* @__PURE__ */ o("div", { className: "peeek__thumbs", role: "group", "aria-label": "Pages", children: Array.from({ length: h }, (g, s) => {
331
+ const b = he(s, c, e), p = b.length === 2;
332
+ return /* @__PURE__ */ v("div", { className: "peeek__thumb-group", children: [
333
+ b.map((u, i) => {
334
+ let _ = "";
335
+ return p && (_ = (n ? i === 1 : i === 0) ? " peeek__thumb--flat-right" : " peeek__thumb--flat-left"), /* @__PURE__ */ o(
336
+ "button",
337
+ {
338
+ type: "button",
339
+ "aria-label": `Go to page ${u + 1}`,
340
+ "aria-current": f.has(u),
341
+ className: `peeek__thumb${f.has(u) ? " peeek__thumb--active" : ""}${_}`,
342
+ onClick: () => l(u),
343
+ children: /* @__PURE__ */ o("img", { src: t[u], alt: "", loading: "lazy", referrerPolicy: "no-referrer" })
344
+ },
345
+ u
346
+ );
347
+ }),
348
+ /* @__PURE__ */ o("span", { className: "peeek__thumb-badge", "aria-hidden": !0, children: b.map((u) => u + 1).join("-") })
349
+ ] }, s);
350
+ }) });
351
+ }
352
+ const ee = 1, te = 2, de = 0.25;
353
+ function it(t) {
354
+ const {
355
+ pages: e,
356
+ strings: n,
357
+ layout: r,
358
+ rtl: l,
359
+ pageShadows: c,
360
+ animateInteractions: f,
361
+ autoTransition: h,
362
+ autoTransitionInterval: g,
363
+ show: s,
364
+ downloadUrl: b,
365
+ isFullscreen: p,
366
+ onToggleFullscreen: u
367
+ } = t, i = e.length, _ = re(i, r), w = pe() || !f, [V, z] = T(0), [N, B] = T(1), [H, y] = T(!1), [m, x] = T({ x: 0, y: 0 }), [F, O] = T(!1), G = U(null), ae = U(null), [k, oe] = T(null), le = U(null), [be, _e] = T(0.707);
368
+ $(() => {
369
+ if (!e[0]) return;
370
+ const a = new globalThis.Image();
371
+ a.onload = () => {
372
+ a.naturalWidth && a.naturalHeight && _e(a.naturalWidth / a.naturalHeight);
373
+ }, a.src = e[0];
374
+ }, [e]);
375
+ const P = Q(V, i, r), ke = P <= 0, W = P >= _ - 1, A = S(
376
+ (a) => {
377
+ k || z((d) => {
378
+ const I = Q(d + a, i, r);
379
+ return I === d ? d : w ? I : (oe({ dir: a, to: I }), d);
380
+ });
381
+ },
382
+ [i, r, w, k]
383
+ ), ye = S(() => {
384
+ oe((a) => (a && z(a.to), null));
385
+ }, []);
386
+ $(() => {
387
+ if (!k) return;
388
+ const a = le.current;
389
+ if (!a) return;
390
+ a.style.transform = "rotateY(0deg)";
391
+ let d = 0;
392
+ const I = requestAnimationFrame(() => {
393
+ d = requestAnimationFrame(() => {
394
+ a.style.transform = `rotateY(${k.dir === 1 ? -180 : 180}deg)`;
395
+ });
396
+ });
397
+ return () => {
398
+ cancelAnimationFrame(I), cancelAnimationFrame(d);
399
+ };
400
+ }, [k]);
401
+ const ve = S(
402
+ (a) => {
403
+ z(Q(ot(a, r), i, r));
404
+ },
405
+ [i, r]
406
+ ), we = S(
407
+ (a) => {
408
+ a.key === "ArrowRight" ? A(l ? -1 : 1) : a.key === "ArrowLeft" && A(l ? 1 : -1);
409
+ },
410
+ [A, l]
411
+ );
412
+ $(() => {
413
+ if (!h || W) return;
414
+ const a = setTimeout(() => A(1), g);
415
+ return () => clearTimeout(a);
416
+ }, [h, g, W, P, A]);
417
+ const Te = () => B((a) => Math.min(te, a + de)), Ne = () => B((a) => Math.max(ee, a - de)), q = S((a, d, I) => {
418
+ const K = ae.current;
419
+ if (!K || I <= 1) return { x: 0, y: 0 };
420
+ const ce = (I - 1) * K.clientWidth / 2, ue = (I - 1) * K.clientHeight / 2;
421
+ return { x: Math.max(-ce, Math.min(ce, a)), y: Math.max(-ue, Math.min(ue, d)) };
422
+ }, []);
423
+ $(() => x((a) => q(a.x, a.y, N)), [N, q]), $(() => x({ x: 0, y: 0 }), [P]);
424
+ const Ie = (a) => {
425
+ N <= 1 || (G.current = { x: a.clientX, y: a.clientY, px: m.x, py: m.y }, O(!0), a.currentTarget.setPointerCapture(a.pointerId));
426
+ }, xe = (a) => {
427
+ const d = G.current;
428
+ d && x(q(d.px + (a.clientX - d.x), d.py + (a.clientY - d.y), N));
429
+ }, se = (a) => {
430
+ if (G.current) {
431
+ G.current = null, O(!1);
432
+ try {
433
+ a.currentTarget.releasePointerCapture(a.pointerId);
434
+ } catch {
435
+ }
436
+ }
437
+ }, D = he(P, i, r), J = D[0] ?? 0, Ce = r === "double" && D.length === 2 ? `${D[0] + 1} - ${D[1] + 1} / ${i}` : `${J + 1} / ${i}`, $e = _ <= 1 ? 100 : P / (_ - 1) * 100, Fe = n.prev, Pe = n.next, Me = k ? k.to : P, E = Y(Me, i, r), Se = E.left < 0 && E.right >= 0, ze = E.left >= 0 && E.right < 0, Ae = E.left >= 0 && E.right >= 0, Ee = Se ? "-25%" : ze ? "25%" : "0%", M = Y(P, i, r), R = k ? Y(k.to, i, r) : M, Le = k ? k.dir === 1 ? M.right >= 0 ? M.right : M.left : M.left >= 0 ? M.left : M.right : J, Oe = k ? k.dir === 1 ? R.left >= 0 ? R.left : R.right : R.right >= 0 ? R.right : R.left : J, Re = k ? k.dir === 1 ? "left" : "right" : null, ie = (a) => a === Re ? M[a] : E[a], Ze = [
438
+ ["left", ie("left")],
439
+ ["right", ie("right")]
440
+ ];
441
+ return /* @__PURE__ */ v(Ue, { children: [
442
+ /* @__PURE__ */ v(
443
+ "div",
444
+ {
445
+ ref: ae,
446
+ className: "peeek__stage",
447
+ tabIndex: 0,
448
+ onKeyDown: we,
449
+ style: { "--peeek-aspect": `${be}` },
450
+ children: [
451
+ s.arrows && /* @__PURE__ */ o(
452
+ "button",
453
+ {
454
+ type: "button",
455
+ className: "peeek__arrow peeek__arrow--prev",
456
+ "aria-label": Fe,
457
+ disabled: ke,
458
+ onClick: () => A(-1),
459
+ children: "‹"
460
+ }
461
+ ),
462
+ /* @__PURE__ */ o(
463
+ "div",
464
+ {
465
+ className: `peeek__zoom${N > 1 ? " peeek__zoom--pannable" : ""}`,
466
+ style: {
467
+ transform: `translate(${m.x}px, ${m.y}px) scale(${N})`,
468
+ transition: w || F ? "none" : void 0
469
+ },
470
+ onPointerDown: Ie,
471
+ onPointerMove: xe,
472
+ onPointerUp: se,
473
+ onPointerCancel: se,
474
+ children: /* @__PURE__ */ v(
475
+ "div",
476
+ {
477
+ className: `peeek__spread${c ? " peeek--shadows" : ""}${Ae ? " peeek__spread--pair" : ""}`,
478
+ style: { transform: `translateX(${Ee})` },
479
+ children: [
480
+ Ze.map(([a, d]) => {
481
+ const I = d >= 0 && s.fullscreen && !p && !k && N === 1;
482
+ return /* @__PURE__ */ o(
483
+ "div",
484
+ {
485
+ className: `peeek__page peeek__page--${a}${d < 0 ? " peeek__page--empty" : ""}`,
486
+ children: d >= 0 && (I ? /* @__PURE__ */ o(
487
+ "button",
488
+ {
489
+ type: "button",
490
+ className: "peeek__page-btn",
491
+ "aria-label": n.openFullscreen,
492
+ onClick: u,
493
+ children: /* @__PURE__ */ o("img", { src: e[d], alt: `Page ${d + 1}`, loading: "lazy", referrerPolicy: "no-referrer" })
494
+ }
495
+ ) : /* @__PURE__ */ o("img", { src: e[d], alt: `Page ${d + 1}`, loading: "lazy", referrerPolicy: "no-referrer" }))
496
+ },
497
+ a
498
+ );
499
+ }),
500
+ k && /* @__PURE__ */ v(
501
+ "div",
502
+ {
503
+ ref: le,
504
+ className: `peeek__leaf peeek__leaf--${k.dir === 1 ? "fwd" : "back"}`,
505
+ onTransitionEnd: ye,
506
+ children: [
507
+ /* @__PURE__ */ o("div", { className: "peeek__leaf-face peeek__leaf-face--front", children: /* @__PURE__ */ o("img", { src: e[Le], alt: "", referrerPolicy: "no-referrer" }) }),
508
+ /* @__PURE__ */ o("div", { className: "peeek__leaf-face peeek__leaf-face--back", children: /* @__PURE__ */ o("img", { src: e[Oe], alt: "", referrerPolicy: "no-referrer" }) })
509
+ ]
510
+ }
511
+ )
512
+ ]
513
+ }
514
+ )
515
+ }
516
+ ),
517
+ s.arrows && /* @__PURE__ */ o(
518
+ "button",
519
+ {
520
+ type: "button",
521
+ className: "peeek__arrow peeek__arrow--next",
522
+ "aria-label": Pe,
523
+ disabled: W,
524
+ onClick: () => A(1),
525
+ children: "›"
526
+ }
527
+ )
528
+ ]
529
+ }
530
+ ),
531
+ s.toolbar && /* @__PURE__ */ o(
532
+ lt,
533
+ {
534
+ strings: n,
535
+ label: Ce,
536
+ progress: $e,
537
+ zoom: N,
538
+ minZoom: ee,
539
+ maxZoom: te,
540
+ thumbsOpen: H,
541
+ isFullscreen: p,
542
+ downloadUrl: b,
543
+ show: { bar: s.bar, fullscreen: s.fullscreen, thumbnails: s.thumbnails && s.overview },
544
+ onZoomIn: Te,
545
+ onZoomOut: Ne,
546
+ onZoomSet: (a) => B(Math.min(te, Math.max(ee, a))),
547
+ onToggleThumbs: () => y((a) => !a),
548
+ onToggleFullscreen: u
549
+ }
550
+ ),
551
+ s.overview && H && /* @__PURE__ */ o(st, { pages: e, layout: r, rtl: l, activePages: D, onJump: ve })
552
+ ] });
553
+ }
554
+ function ct(t, e) {
555
+ const n = e.toLowerCase();
556
+ if (n.includes("pdf")) return "PDF";
557
+ if (n.includes("wordprocessingml")) return "DOCX";
558
+ if (n.includes("msword")) return "DOC";
559
+ const r = t.toLowerCase().split(".").pop() ?? "";
560
+ return r ? r.toUpperCase().slice(0, 4) : "FILE";
561
+ }
562
+ function ut(t, e) {
563
+ if (t === 0) return { transform: "translateX(0) scale(1)", zIndex: 30, opacity: 1 };
564
+ const n = t < 0 ? -1 : 1, r = e ? -1 : 1;
565
+ return {
566
+ transform: `translateX(${r * n * 62}%) scale(0.82) rotateY(${-r * n * 28}deg)`,
567
+ zIndex: 20 - Math.abs(t),
568
+ opacity: 0.55
569
+ };
570
+ }
571
+ function ft(t) {
572
+ const {
573
+ pages: e,
574
+ strings: n,
575
+ filename: r,
576
+ mimeType: l,
577
+ rtl: c,
578
+ autoTransition: f,
579
+ autoTransitionInterval: h,
580
+ downloadUrl: g,
581
+ isFullscreen: s,
582
+ onToggleFullscreen: b,
583
+ show: p
584
+ } = t, u = e.length, [i, _] = T(0), L = pe(), w = S(
585
+ (y) => _((m) => Math.max(0, Math.min(u - 1, m + y))),
586
+ [u]
587
+ ), V = i <= 0, z = i >= u - 1, N = U([]);
588
+ $(() => {
589
+ var y, m;
590
+ (m = (y = N.current[i]) == null ? void 0 : y.scrollIntoView) == null || m.call(y, { behavior: "smooth", inline: "center", block: "nearest" });
591
+ }, [i]), $(() => {
592
+ if (!f || L || z) return;
593
+ const y = setTimeout(() => w(1), h);
594
+ return () => clearTimeout(y);
595
+ }, [f, h, L, z, i, w]);
596
+ const B = S(
597
+ (y) => {
598
+ y.key === "ArrowRight" ? w(c ? -1 : 1) : y.key === "ArrowLeft" && w(c ? 1 : -1);
599
+ },
600
+ [w, c]
601
+ ), H = ct(r, l);
602
+ return /* @__PURE__ */ v("div", { className: "peeek__cf", children: [
603
+ /* @__PURE__ */ v("div", { className: "peeek__cf-header", children: [
604
+ /* @__PURE__ */ o("span", { className: "peeek__cf-badge", children: H }),
605
+ /* @__PURE__ */ v("div", { className: "peeek__cf-meta", children: [
606
+ /* @__PURE__ */ o("span", { className: "peeek__cf-name", children: r }),
607
+ /* @__PURE__ */ v("span", { className: "peeek__cf-count", children: [
608
+ u,
609
+ " ",
610
+ u === 1 ? n.page : n.pages
611
+ ] })
612
+ ] }),
613
+ /* @__PURE__ */ v("span", { className: "peeek__cf-indicator", children: [
614
+ i + 1,
615
+ " / ",
616
+ u
617
+ ] }),
618
+ g && /* @__PURE__ */ o(
619
+ "a",
620
+ {
621
+ className: "peeek__btn",
622
+ href: g,
623
+ "aria-label": n.download,
624
+ target: "_blank",
625
+ rel: "noopener noreferrer",
626
+ download: !0,
627
+ children: "↓"
628
+ }
629
+ ),
630
+ p.fullscreen && /* @__PURE__ */ o(
631
+ "button",
632
+ {
633
+ type: "button",
634
+ className: `peeek__btn${s ? " peeek__btn--active" : ""}`,
635
+ "aria-label": n.fullscreen,
636
+ "aria-pressed": s,
637
+ onClick: b,
638
+ children: "⛶"
639
+ }
640
+ )
641
+ ] }),
642
+ /* @__PURE__ */ v(
643
+ "div",
644
+ {
645
+ className: "peeek__cf-stage",
646
+ tabIndex: 0,
647
+ onKeyDown: B,
648
+ children: [
649
+ p.arrows && /* @__PURE__ */ o(
650
+ "button",
651
+ {
652
+ type: "button",
653
+ className: "peeek__arrow peeek__arrow--prev",
654
+ "aria-label": n.prev,
655
+ disabled: V,
656
+ onClick: () => w(-1),
657
+ children: "‹"
658
+ }
659
+ ),
660
+ e.map((y, m) => {
661
+ const x = m - i;
662
+ if (Math.abs(x) > 1) return null;
663
+ const F = x === 0, O = F && p.fullscreen;
664
+ return /* @__PURE__ */ o(
665
+ "button",
666
+ {
667
+ type: "button",
668
+ className: `peeek__cf-card${F ? " peeek__cf-card--center" : ""}${O ? " peeek__cf-card--zoom" : ""}`,
669
+ style: ut(x, c),
670
+ tabIndex: F ? 0 : -1,
671
+ "aria-label": O ? n.openFullscreen : `Go to page ${m + 1}`,
672
+ onClick: () => O ? b() : _(m),
673
+ children: /* @__PURE__ */ o("img", { src: y, alt: F ? `Page ${m + 1}` : "", loading: "lazy", referrerPolicy: "no-referrer" })
674
+ },
675
+ m
676
+ );
677
+ }),
678
+ p.arrows && /* @__PURE__ */ o(
679
+ "button",
680
+ {
681
+ type: "button",
682
+ className: "peeek__arrow peeek__arrow--next",
683
+ "aria-label": n.next,
684
+ disabled: z,
685
+ onClick: () => w(1),
686
+ children: "›"
687
+ }
688
+ )
689
+ ]
690
+ }
691
+ ),
692
+ p.thumbnails && /* @__PURE__ */ o("div", { className: "peeek__cf-thumbs", role: "group", "aria-label": "Pages", children: e.map((y, m) => {
693
+ const x = m === i;
694
+ return /* @__PURE__ */ v(
695
+ "button",
696
+ {
697
+ ref: (F) => {
698
+ N.current[m] = F;
699
+ },
700
+ type: "button",
701
+ className: `peeek__cf-thumb${x ? " peeek__cf-thumb--active" : ""}`,
702
+ "aria-label": `Go to page ${m + 1}`,
703
+ "aria-current": x ? "page" : void 0,
704
+ onClick: () => _(m),
705
+ children: [
706
+ /* @__PURE__ */ o("img", { src: y, alt: "", loading: "lazy", referrerPolicy: "no-referrer" }),
707
+ /* @__PURE__ */ o("span", { className: "peeek__cf-thumb-num", children: String(m + 1).padStart(2, "0") })
708
+ ]
709
+ },
710
+ m
711
+ );
712
+ }) })
713
+ ] });
714
+ }
715
+ function dt({ logo: t, logoLink: e }) {
716
+ if (!t) return null;
717
+ const n = /* @__PURE__ */ o("img", { src: t, alt: "Logo", loading: "lazy", referrerPolicy: "no-referrer" });
718
+ return /* @__PURE__ */ o("div", { className: "peeek__branding", children: e ? /* @__PURE__ */ o("a", { href: e, target: "_blank", rel: "noopener noreferrer", children: n }) : n });
719
+ }
720
+ function pt(t) {
721
+ const e = et(t), n = Ke(e.language), r = U(null), { isFullscreen: l, toggle: c } = at(r), f = t.pages !== void 0, h = Be(
722
+ () => f ? nt(t.pages, { filename: t.filename, mimeType: t.mimeType }) : null,
723
+ [f, t.pages, t.filename, t.mimeType]
724
+ ), g = rt(f ? null : e.src, e.pollInterval), s = f ? h : g.manifest, b = f ? h ? "ready" : "loading" : g.state, p = {
725
+ "--peeek-accent": e.accentColor
726
+ };
727
+ e.background === "transparent" ? p["--peeek-bg"] = "transparent" : e.background === "color" && e.backgroundColor ? p["--peeek-bg"] = e.backgroundColor : e.background === "image" && e.backgroundImage && (p["--peeek-bg"] = `center / cover no-repeat url("${e.backgroundImage}")`);
728
+ const u = {
729
+ toolbar: e.navigationControls,
730
+ bar: e.navigationBar,
731
+ fullscreen: e.fullscreen,
732
+ thumbnails: e.pagesOverview,
733
+ arrows: e.arrows,
734
+ overview: e.pagesOverview
735
+ };
736
+ return /* @__PURE__ */ v(
737
+ "div",
738
+ {
739
+ ref: r,
740
+ className: `peeek${e.fillHeight ? " peeek--fill-height" : ""}${e.className ? " " + e.className : ""}`,
741
+ "data-skin": e.skin,
742
+ "data-layout": e.layout,
743
+ dir: e.rtl ? "rtl" : void 0,
744
+ style: p,
745
+ children: [
746
+ /* @__PURE__ */ o(dt, { logo: e.logo, logoLink: e.logoLink }),
747
+ b === "loading" && /* @__PURE__ */ o("div", { className: "peeek__state", children: n.loading }),
748
+ b === "error" && /* @__PURE__ */ o("div", { className: "peeek__state", children: n.error }),
749
+ b === "ready" && s && e.mode === "coverflow" && /* @__PURE__ */ o(
750
+ ft,
751
+ {
752
+ pages: s.pages,
753
+ strings: n,
754
+ filename: s.metadata.filename,
755
+ mimeType: s.metadata.mimeType,
756
+ rtl: e.rtl,
757
+ autoTransition: e.autoTransition,
758
+ autoTransitionInterval: e.autoTransitionInterval,
759
+ downloadUrl: e.downloadUrl,
760
+ isFullscreen: l,
761
+ onToggleFullscreen: c,
762
+ show: { arrows: e.arrows, thumbnails: e.pagesOverview, fullscreen: e.fullscreen }
763
+ }
764
+ ),
765
+ b === "ready" && s && e.mode === "flip" && /* @__PURE__ */ o(
766
+ it,
767
+ {
768
+ pages: s.pages,
769
+ strings: n,
770
+ layout: e.layout,
771
+ rtl: e.rtl,
772
+ pageShadows: e.pageShadows,
773
+ animateInteractions: e.animateInteractions,
774
+ autoTransition: e.autoTransition,
775
+ autoTransitionInterval: e.autoTransitionInterval,
776
+ show: u,
777
+ downloadUrl: e.downloadUrl,
778
+ isFullscreen: l,
779
+ onToggleFullscreen: c
780
+ }
781
+ )
782
+ ]
783
+ }
784
+ );
785
+ }
786
+ export {
787
+ pt as PeeekViewer
788
+ };
@@ -0,0 +1 @@
1
+ .peeek{--peeek-accent: #6E79D6;--peeek-bg: #0b0b10;--peeek-surface: rgba(255, 255, 255, .06);--peeek-text: #f5f5fa;--peeek-radius: 16px;position:relative;display:flex;flex-direction:column;width:100%;color:var(--peeek-text);background:var(--peeek-bg);border-radius:var(--peeek-radius);overflow:hidden;font-family:ui-sans-serif,system-ui,sans-serif}.peeek__stage{position:relative;display:flex;align-items:center;justify-content:center;flex:1;min-height:24rem;padding:1.75rem 3rem;overflow:hidden;perspective:2000px}.peeek__zoom{display:flex;align-items:center;justify-content:center;width:100%;height:100%;transform-origin:center center}.peeek__zoom--pannable{cursor:grab;touch-action:none}.peeek__zoom--pannable:active{cursor:grabbing}.peeek__zoom--pannable img{pointer-events:none;-webkit-user-select:none;user-select:none;-webkit-user-drag:none}.peeek__spread{position:relative;display:flex;width:100%;transition:transform .5s cubic-bezier(.6,.05,.3,.95);transform-style:preserve-3d}.peeek__page{position:relative;width:50%;aspect-ratio:var(--peeek-aspect, .707);background:#fff;overflow:hidden}.peeek__page--empty{background:transparent;box-shadow:none}.peeek__page--left{border-top-left-radius:8px;border-bottom-left-radius:8px}.peeek__page--right{border-top-right-radius:8px;border-bottom-right-radius:8px}.peeek__spread:not(.peeek__spread--pair) .peeek__page{border-radius:8px}.peeek__page img{display:block;width:100%;height:100%;object-fit:contain}.peeek__page-btn{all:unset;display:block;width:100%;height:100%;cursor:zoom-in}.peeek--shadows .peeek__spread{box-shadow:0 24px 60px -24px #000000b3}.peeek--shadows.peeek__spread--pair .peeek__page--left{box-shadow:inset -30px 0 36px -22px #0009}.peeek--shadows.peeek__spread--pair .peeek__page--right{box-shadow:inset 30px 0 36px -22px #0009}.peeek--shadows.peeek__spread--pair .peeek__page--left:after,.peeek--shadows.peeek__spread--pair .peeek__page--right:after{content:"";position:absolute;top:0;bottom:0;width:14px;pointer-events:none}.peeek--shadows.peeek__spread--pair .peeek__page--left:after{right:0;background:linear-gradient(to right,#0000,#00000047)}.peeek--shadows.peeek__spread--pair .peeek__page--right:after{left:0;background:linear-gradient(to left,#0000,#00000047)}.peeek__leaf{position:absolute;top:0;width:50%;height:100%;z-index:3;transform-style:preserve-3d;transition:transform .62s cubic-bezier(.55,.06,.3,.98);will-change:transform}.peeek__leaf--fwd{left:50%;transform-origin:left center}.peeek__leaf--back{right:50%;transform-origin:right center}.peeek__leaf-face{position:absolute;top:0;right:0;bottom:0;left:0;backface-visibility:hidden;background:#fff;overflow:hidden}.peeek__leaf-face img{display:block;width:100%;height:100%;object-fit:contain}.peeek__leaf-face--back{transform:rotateY(180deg)}.peeek__leaf-face:after{content:"";position:absolute;top:0;right:0;bottom:0;left:0;pointer-events:none;opacity:.15;animation:peeek-curl .62s cubic-bezier(.55,.06,.3,.98) forwards;background:linear-gradient(var(--peeek-curl-dir, to right),rgba(0,0,0,.34),rgba(0,0,0,0) 58%,rgba(255,255,255,.05))}.peeek__leaf--fwd .peeek__leaf-face:after{--peeek-curl-dir: to right}.peeek__leaf--back .peeek__leaf-face:after{--peeek-curl-dir: to left}.peeek__leaf-face--back:after{transform:scaleX(-1)}@keyframes peeek-curl{0%{opacity:.15}45%{opacity:1}to{opacity:.55}}.peeek__arrow{position:absolute;top:50%;transform:translateY(-50%);z-index:2;display:flex;align-items:center;justify-content:center;width:2.5rem;height:2.5rem;border:none;border-radius:9999px;background:#00000059;color:#fff;cursor:pointer}.peeek__arrow:disabled{opacity:.3;cursor:default}.peeek__arrow--prev{left:.75rem}.peeek__arrow--next{right:.75rem}.peeek__toolbar{display:flex;align-items:center;gap:.75rem;padding:.75rem 1rem;border-top:1px solid rgba(255,255,255,.08);font-size:14px}.peeek__scrubber{flex:1;height:2px;background:#ffffff26;border-radius:9999px;overflow:hidden}.peeek__scrubber-fill{height:100%;background:var(--peeek-accent)}.peeek__btn{display:inline-flex;align-items:center;justify-content:center;width:2rem;height:2rem;border:none;border-radius:8px;background:transparent;color:var(--peeek-text);cursor:pointer}.peeek__btn:disabled{opacity:.3;cursor:default}.peeek__btn--active{color:var(--peeek-accent)}.peeek__thumbs{display:flex;gap:.4rem;overflow-x:auto;padding:.75rem 1rem;border-top:1px solid rgba(255,255,255,.08)}.peeek__thumb-group{flex:0 0 auto;display:flex;gap:2px;position:relative}.peeek__thumb{flex:0 0 auto;width:4rem;height:5rem;padding:0;border:2px solid transparent;border-radius:6px;background:#fff;cursor:pointer;overflow:hidden}.peeek__thumb img{width:100%;height:100%;object-fit:contain}.peeek__thumb--active{border-color:var(--peeek-accent)}.peeek__thumb--flat-right{border-top-right-radius:0;border-bottom-right-radius:0}.peeek__thumb--flat-left{border-top-left-radius:0;border-bottom-left-radius:0}.peeek__branding{display:flex;align-items:center;gap:.5rem;padding:.5rem 1rem}.peeek__branding img{height:1.5rem;width:auto}.peeek__state{display:flex;align-items:center;justify-content:center;min-height:24rem;font-size:16px;color:var(--peeek-text)}.peeek[data-skin=minimal] .peeek__toolbar,.peeek[data-skin=minimal] .peeek__thumbs{border-top:none;background:#00000040}.peeek[data-skin=minimal] .peeek__arrow{background:#0003}.peeek[dir=rtl] .peeek__leaf{transform-origin:right center}.peeek__cf{display:flex;flex:1;flex-direction:column;min-height:0}.peeek__cf-header{display:flex;align-items:center;gap:.75rem;padding:.75rem 1rem;border-bottom:1px solid rgba(255,255,255,.08);font-size:14px}.peeek__cf-badge{display:flex;align-items:center;justify-content:center;width:2.5rem;height:2.75rem;flex:0 0 auto;border-radius:6px;background:var(--peeek-accent);color:#fff;font-size:13px;font-weight:700}.peeek__cf-meta{display:flex;min-width:0;flex:1;flex-direction:column}.peeek__cf-name{overflow:hidden;font-weight:600;text-overflow:ellipsis;white-space:nowrap}.peeek__cf-count{font-size:14px;opacity:.6}.peeek__cf-indicator{padding:.25rem .75rem;border:1px solid rgba(255,255,255,.1);border-radius:8px;font-family:ui-monospace,monospace;font-size:14px}.peeek__cf-stage{position:relative;display:flex;flex:1;align-items:center;justify-content:center;min-height:20rem;overflow:hidden;perspective:1400px}.peeek__cf-card{position:absolute;display:flex;max-width:55%;align-items:center;justify-content:center;padding:0;border:none;background:transparent;cursor:pointer;transition:transform .3s ease-out,opacity .3s ease-out}.peeek__cf-card--center{max-width:70%}.peeek__cf-card--zoom{cursor:zoom-in}.peeek__cf-card img{max-width:100%;max-height:19rem;border-radius:8px;background:#fff;object-fit:contain;box-shadow:0 18px 40px -12px #0009}.peeek__cf-thumbs{display:flex;gap:.5rem;overflow-x:auto;padding:.75rem 1rem;border-top:1px solid rgba(255,255,255,.08);scrollbar-width:none}.peeek__cf-thumbs::-webkit-scrollbar{display:none}.peeek__cf-thumb{display:flex;flex:0 0 auto;flex-direction:column;align-items:center;gap:.25rem;padding:.25rem;border:2px solid transparent;border-radius:8px;background:transparent;cursor:pointer}.peeek__cf-thumb img{width:3rem;height:4rem;border-radius:4px;background:#fff;object-fit:cover;opacity:.8}.peeek__cf-thumb--active{border-color:var(--peeek-accent);background:#ffffff0f}.peeek__cf-thumb--active img{opacity:1}.peeek__cf-thumb-num{font-family:ui-monospace,monospace;font-size:14px;opacity:.6}.peeek__cf-thumb--active .peeek__cf-thumb-num{color:var(--peeek-accent);opacity:1}.peeek:fullscreen .peeek__cf-card img{max-height:78vh}.peeek:fullscreen .peeek__spread{width:auto;height:100%}.peeek:fullscreen .peeek__page{width:auto;height:100%}.peeek[data-skin=minimal] .peeek__cf-header,.peeek[data-skin=minimal] .peeek__cf-thumbs{border-color:transparent;background:#00000040}.peeek[data-skin=showcase] .peeek__label{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:14px}.peeek[data-skin=showcase] .peeek__scrubber{height:2px}.peeek[data-skin=showcase] .peeek__scrubber-fill{background:var(--peeek-accent)}.peeek[data-skin=showcase] .peeek__arrow{width:2.5rem;height:2.5rem;border-radius:9999px;background:#0000004d;color:#fff;-webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px)}.peeek[data-skin=showcase] .peeek__arrow:hover{background:#00000080}.peeek__thumb-badge{position:absolute;right:2px;bottom:2px;padding:0 4px;border-radius:4px;background:#000000b3;color:#fff;font-size:14px;font-weight:500;pointer-events:none}.peeek--fill-height{height:100%}.peeek--fill-height .peeek__stage{min-height:0}.peeek--fill-height .peeek__spread,.peeek--fill-height .peeek__page{width:auto;height:100%}.peeek[data-layout=double] .peeek__spread:not(.peeek__spread--pair) .peeek__page--right{border-radius:0 8px 8px 0}.peeek[data-layout=double] .peeek__spread:not(.peeek__spread--pair) .peeek__page--left{border-radius:8px 0 0 8px}.peeek[data-layout=double] .peeek__leaf--fwd .peeek__leaf-face--front{border-top-right-radius:8px;border-bottom-right-radius:8px}.peeek[data-layout=double] .peeek__leaf--fwd .peeek__leaf-face--back,.peeek[data-layout=double] .peeek__leaf--back .peeek__leaf-face--front{border-top-left-radius:8px;border-bottom-left-radius:8px}.peeek[data-layout=double] .peeek__leaf--back .peeek__leaf-face--back{border-top-right-radius:8px;border-bottom-right-radius:8px}.peeek[data-layout=single] .peeek__leaf-face{border-radius:8px}
package/package.json ADDED
@@ -0,0 +1,39 @@
1
+ {
2
+ "name": "@peeekpage/viewer",
3
+ "version": "0.3.13",
4
+ "description": "PeeekViewer: embeddable document viewer (flip and coverflow) for peeek.page.",
5
+ "type": "module",
6
+ "license": "UNLICENSED",
7
+ "private": false,
8
+ "publishConfig": {
9
+ "access": "public"
10
+ },
11
+ "homepage": "https://peeek.page",
12
+ "files": [
13
+ "dist"
14
+ ],
15
+ "main": "./dist/index.js",
16
+ "module": "./dist/index.js",
17
+ "types": "./dist/index.d.ts",
18
+ "exports": {
19
+ ".": {
20
+ "types": "./dist/index.d.ts",
21
+ "import": "./dist/index.js"
22
+ },
23
+ "./styles.css": "./dist/peeekviewer.css"
24
+ },
25
+ "sideEffects": [
26
+ "**/*.css"
27
+ ],
28
+ "scripts": {
29
+ "build": "tsc --noEmit && vite build",
30
+ "test": "vitest run",
31
+ "test:watch": "vitest",
32
+ "lint": "tsc --noEmit",
33
+ "prepublishOnly": "npm run build"
34
+ },
35
+ "peerDependencies": {
36
+ "react": ">=18",
37
+ "react-dom": ">=18"
38
+ }
39
+ }