@zinejs/core 0.7.4 → 0.8.2

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.
@@ -0,0 +1,725 @@
1
+ import { i as e, n as t, t as n } from "./registry-5nuYFMd4.js";
2
+ import { i as r, n as i, r as a, t as o } from "./styles-B8fFoYm_.js";
3
+ //#region src/controls/builtins.ts
4
+ var s = Math.SQRT2, c = (e) => e.zine.container.ownerDocument?.fullscreenElement === e.zine.container;
5
+ function l() {
6
+ t({
7
+ id: "prev",
8
+ title: "Previous page",
9
+ icon: a.prev,
10
+ isDisabled: (e) => !e.zine.canFlipPrev(),
11
+ action: (e) => e.zine.flipPrev()
12
+ }), t({
13
+ id: "next",
14
+ title: "Next page",
15
+ icon: a.next,
16
+ isDisabled: (e) => !e.zine.canFlipNext(),
17
+ action: (e) => e.zine.flipNext()
18
+ });
19
+ let e = (e) => e.zine.getDirection() === "rtl";
20
+ t({
21
+ id: "first",
22
+ title: "First page",
23
+ icon: (t) => e(t) ? a.last : a.first,
24
+ isDisabled: (e) => !e.zine.canFlipPrev(),
25
+ action: (e) => {
26
+ e.zine.flipTo(0), e.close();
27
+ }
28
+ }), t({
29
+ id: "last",
30
+ title: "Last page",
31
+ icon: (t) => e(t) ? a.first : a.last,
32
+ isDisabled: (e) => !e.zine.canFlipNext(),
33
+ action: (e) => {
34
+ e.zine.flipTo(e.zine.getPageCount() - 1), e.close();
35
+ }
36
+ }), t({
37
+ id: "zoomIn",
38
+ title: "Zoom in",
39
+ icon: a.zoomIn,
40
+ isDisabled: (e) => e.zine.getZoom() >= e.zine.getMaxZoom() - 1e-6,
41
+ action: (e) => e.zine.setZoom(e.zine.getZoom() * s)
42
+ }), t({
43
+ id: "zoomOut",
44
+ title: "Zoom out",
45
+ icon: a.zoomOut,
46
+ isDisabled: (e) => e.zine.getZoom() <= 1.000001,
47
+ action: (e) => e.zine.setZoom(e.zine.getZoom() / s)
48
+ }), t({
49
+ id: "fullscreen",
50
+ title: "Fullscreen",
51
+ icon: a.fullscreen,
52
+ isVisible: (e) => typeof e.zine.container.requestFullscreen == "function",
53
+ isActive: c,
54
+ action: (e) => {
55
+ let t = e.zine.container.ownerDocument;
56
+ c(e) ? t?.exitFullscreen?.() : e.zine.container.requestFullscreen?.(), e.close();
57
+ }
58
+ }), t({
59
+ id: "share",
60
+ title: "Share",
61
+ icon: a.share,
62
+ action: (e) => {
63
+ e.close(), import("./share-WXdscwp3.js").then(({ ShareDialog: t }) => new t(e.zine, e.zine.container, e.colorScheme)).catch(() => {
64
+ navigator.clipboard?.writeText(e.zine.pageLink()).catch(() => {});
65
+ });
66
+ }
67
+ }), t({
68
+ id: "download",
69
+ title: "Download PDF",
70
+ icon: a.download,
71
+ isVisible: (e) => e.zine.canDownload(),
72
+ action: async (e) => {
73
+ await e.zine.download(), e.close();
74
+ }
75
+ }), t({
76
+ id: "spread",
77
+ title: (e) => e.zine.isSinglePage() ? "Show two pages" : "Show one page",
78
+ icon: (e) => e.zine.isSinglePage() ? a.twoPages : a.onePage,
79
+ isVisible: (e) => !e.zine.isResponsiveSingle(),
80
+ action: (e) => {
81
+ e.zine.toggleSpreadMode(), e.close();
82
+ }
83
+ }), t({
84
+ id: "print",
85
+ title: "Print",
86
+ icon: a.print,
87
+ isVisible: (e) => e.zine.canPrint(),
88
+ action: async (e) => {
89
+ await e.zine.print(), e.close();
90
+ }
91
+ }), t({
92
+ id: "menu",
93
+ title: "More",
94
+ icon: a.menu,
95
+ children: [
96
+ "first",
97
+ "last",
98
+ "spread",
99
+ "thumbnails",
100
+ "outline",
101
+ "print",
102
+ "download"
103
+ ]
104
+ });
105
+ }
106
+ //#endregion
107
+ //#region src/controls/sidebar.ts
108
+ var u = class {
109
+ root;
110
+ #e;
111
+ #t = null;
112
+ #n = null;
113
+ #r = null;
114
+ #i = null;
115
+ #a;
116
+ #o = null;
117
+ #s = null;
118
+ constructor(e, t, n) {
119
+ this.#a = e, this.#e = e.createElement("div"), this.#e.className = "zine-panel-holder", this.#e.style.width = `${n.width}px`, this.#o = n.pageBox ?? null, this.root = e.createElement("div"), this.root.className = `zine-panel ${n.className}`, this.root.setAttribute("role", "listbox"), this.root.setAttribute("aria-label", n.label), this.#e.appendChild(this.root);
120
+ for (let e of [
121
+ "pointerdown",
122
+ "pointerup",
123
+ "pointermove",
124
+ "click",
125
+ "dblclick",
126
+ "wheel"
127
+ ]) this.root.addEventListener(e, (e) => e.stopPropagation());
128
+ this.#u(e, t, n.rtl ?? !1, n.overlay ?? !1), n.onDismiss && this.#d(e, n.onDismiss), this.#c(t);
129
+ }
130
+ #c(e) {
131
+ this.#o && (this.#l(), !(typeof ResizeObserver > "u") && (this.#s = new ResizeObserver(() => this.#l()), this.#s.observe(e)));
132
+ }
133
+ #l() {
134
+ let e = this.#o?.();
135
+ e && (this.#e.style.top = `${e.y}px`, this.#e.style.bottom = "auto", this.#e.style.height = `${e.height}px`);
136
+ }
137
+ setWidth(e) {
138
+ this.#e.style.width = `${e}px`;
139
+ }
140
+ #u(e, t, n, r) {
141
+ if (!t.parentNode) {
142
+ this.#e.classList.add("zine-panel-overlay"), t.appendChild(this.#e);
143
+ return;
144
+ }
145
+ let i = t.closest(".zine-controls-wrap") ?? t, a = e.createElement("div");
146
+ a.className = "zine-panel-wrap", n && a.classList.add("zine-panel-wrap-rtl"), r && a.classList.add("zine-panel-wrap-overlay"), i.parentNode.insertBefore(a, i), a.append(this.#e, i), this.#t = a;
147
+ }
148
+ #d(e, t) {
149
+ let n = e.createElement("button");
150
+ if (n.type = "button", n.className = "zine-panel-close", n.setAttribute("aria-label", "Close"), n.appendChild(r(e, a.close)), n.addEventListener("click", (e) => {
151
+ e.stopPropagation(), t();
152
+ }), this.#e.appendChild(n), this.#r = n, this.#t) {
153
+ let n = e.createElement("div");
154
+ n.className = "zine-panel-scrim", this.#t.insertBefore(n, this.#e);
155
+ for (let e of ["pointerdown", "click"]) n.addEventListener(e, (e) => {
156
+ e.stopPropagation(), t();
157
+ });
158
+ this.#n = n;
159
+ }
160
+ this.#i = (e) => {
161
+ e.key === "Escape" && t();
162
+ }, e.addEventListener("keydown", this.#i);
163
+ }
164
+ destroy() {
165
+ this.#s?.disconnect(), this.#s = null, this.#i &&= (this.#a.removeEventListener("keydown", this.#i), null), this.#n?.remove(), this.#n = null, this.#r = null, this.#e.remove();
166
+ let e = this.#t;
167
+ if (e?.parentNode) {
168
+ for (; e.firstChild;) e.parentNode.insertBefore(e.firstChild, e);
169
+ e.remove();
170
+ }
171
+ this.#t = null;
172
+ }
173
+ }, d = 78, f = class {
174
+ root;
175
+ #e;
176
+ #t;
177
+ #n;
178
+ #r = [];
179
+ #i = null;
180
+ #a = [];
181
+ constructor(e, t, n = {}) {
182
+ this.#e = e;
183
+ let r = t.ownerDocument;
184
+ this.#t = r, this.#n = new u(r, t, {
185
+ className: "zine-thumbs",
186
+ label: "Pages",
187
+ width: 90,
188
+ onDismiss: n.onDismiss,
189
+ rtl: e.getDirection() === "rtl",
190
+ pageBox: () => e.getPageBox()
191
+ }), this.root = this.#n.root, this.#o(), this.#a.push(e.on("pageChanged", () => this.#l())), this.#l();
192
+ }
193
+ #o() {
194
+ let e = this.#e.getSpreads(), t = this.#e.getDirection() === "rtl", n = e.some((e) => e.left !== null && e.right !== null);
195
+ this.#n.root.classList.toggle("zine-thumbs-solo", !n), n && this.#n.setWidth(170);
196
+ for (let [r, i] of e.entries()) {
197
+ let e = this.#t.createElement("button");
198
+ e.type = "button", e.className = "zine-thumbs-row", e.setAttribute("role", "option"), t && (e.style.flexDirection = "row-reverse");
199
+ let a = [i.left, i.right].filter((e) => e !== null);
200
+ n && a.length === 1 && e.classList.add("zine-thumbs-row-lone");
201
+ for (let t of a) {
202
+ let n = this.#t.createElement("span");
203
+ n.className = "zine-thumbs-cell", n.dataset.page = String(t), e.appendChild(n);
204
+ }
205
+ let o = [...a].sort((e, t) => e - t).map((e) => e + 1);
206
+ e.setAttribute("aria-label", o.length > 1 ? `Pages ${o[0]}–${o.at(-1)}` : `Page ${o[0] ?? ""}`);
207
+ let s = this.#t.createElement("span");
208
+ s.className = "zine-thumbs-caption", s.textContent = o.join("–"), e.appendChild(s), e.addEventListener("click", () => {
209
+ a.length > 0 && this.#e.flipTo(Math.min(...a));
210
+ }), this.#n.root.appendChild(e), this.#r.push({
211
+ el: e,
212
+ spread: r,
213
+ pages: a
214
+ });
215
+ }
216
+ this.#s();
217
+ }
218
+ #s() {
219
+ let e = [...this.#n.root.querySelectorAll(".zine-thumbs-cell[data-page]")];
220
+ if (typeof IntersectionObserver > "u") {
221
+ for (let t of e) this.#c(t);
222
+ return;
223
+ }
224
+ this.#i = new IntersectionObserver((e, t) => {
225
+ for (let n of e) n.isIntersecting && (t.unobserve(n.target), this.#c(n.target));
226
+ }, {
227
+ root: this.#n.root,
228
+ rootMargin: "200px"
229
+ });
230
+ for (let t of e) this.#i.observe(t);
231
+ }
232
+ async #c(e) {
233
+ let t = Number(e.dataset.page), n = await this.#e.getPageImage(t);
234
+ if (!n || !e.isConnected) return;
235
+ let r = n.width, i = n.height;
236
+ if (!r || !i) return;
237
+ let a = Math.min(2, globalThis.devicePixelRatio || 1), o = this.#t.createElement("canvas");
238
+ o.width = Math.max(1, Math.round(d * a)), o.height = Math.max(1, Math.round(d * i / r * a)), o.className = "zine-thumbs-img";
239
+ let s = o.getContext("2d");
240
+ if (s) {
241
+ try {
242
+ s.drawImage(n, 0, 0, o.width, o.height);
243
+ } catch {
244
+ return;
245
+ }
246
+ e.replaceChildren(o);
247
+ }
248
+ }
249
+ #l() {
250
+ let e = this.#e.getPage();
251
+ for (let { el: t, pages: n } of this.#r) {
252
+ let r = n.includes(e);
253
+ t.classList.toggle("zine-panel-active", r), t.setAttribute("aria-selected", String(r)), r && t.scrollIntoView?.({ block: "nearest" });
254
+ }
255
+ }
256
+ destroy() {
257
+ for (let e of this.#a) e();
258
+ this.#a = [], this.#i?.disconnect(), this.#i = null, this.#n.destroy();
259
+ }
260
+ }, p = 208, m = 12, h = class {
261
+ root;
262
+ #e;
263
+ #t;
264
+ #n;
265
+ #r = [];
266
+ #i = [];
267
+ #a;
268
+ constructor(e, t, n = {}) {
269
+ this.#e = e;
270
+ let r = t.ownerDocument;
271
+ this.#t = r, this.#a = n.onDismiss, this.#n = new u(r, t, {
272
+ className: "zine-outline",
273
+ label: "Outline",
274
+ width: p,
275
+ onDismiss: n.onDismiss,
276
+ rtl: e.getDirection() === "rtl",
277
+ overlay: !0,
278
+ pageBox: () => e.getPageBox()
279
+ }), this.root = this.#n.root, this.#o("Loading…"), this.#s(), this.#i.push(e.on("pageChanged", () => this.#l()));
280
+ }
281
+ #o(e) {
282
+ let t = this.#t.createElement("div");
283
+ t.className = "zine-panel-note", t.textContent = e, this.#n.root.replaceChildren(t);
284
+ }
285
+ async #s() {
286
+ let e = await this.#e.getOutline();
287
+ if (this.#n.root.isConnected) {
288
+ if (e.length === 0) {
289
+ this.#o("This document has no outline.");
290
+ return;
291
+ }
292
+ this.#n.root.replaceChildren(), this.#c(e, 0), this.#l();
293
+ }
294
+ }
295
+ #c(e, t) {
296
+ for (let n of e) {
297
+ let e = this.#t.createElement("button");
298
+ if (e.type = "button", e.className = "zine-outline-row", e.setAttribute("role", "option"), e.style.paddingLeft = `${8 + t * m}px`, e.textContent = n.title, e.title = n.title, n.page === null) e.disabled = !0;
299
+ else {
300
+ let t = n.page;
301
+ e.setAttribute("aria-label", `${n.title}, page ${t + 1}`), e.addEventListener("click", () => {
302
+ this.#e.flipTo(t), this.#a?.();
303
+ }), this.#r.push({
304
+ el: e,
305
+ page: t
306
+ });
307
+ }
308
+ this.#n.root.appendChild(e), n.children.length > 0 && this.#c(n.children, t + 1);
309
+ }
310
+ }
311
+ #l() {
312
+ let e = this.#e.getPage(), t = null, n = -1;
313
+ for (let { el: r, page: i } of this.#r) r.classList.remove("zine-panel-active"), r.removeAttribute("aria-selected"), i <= e && i >= n && (t = r, n = i);
314
+ t && (t.classList.add("zine-panel-active"), t.setAttribute("aria-selected", "true"), t.scrollIntoView?.({ block: "nearest" }));
315
+ }
316
+ destroy() {
317
+ for (let e of this.#i) e();
318
+ this.#i = [], this.#n.destroy();
319
+ }
320
+ }, g = 208, _ = 180, v = 2, y = class {
321
+ root;
322
+ #e;
323
+ #t;
324
+ #n;
325
+ #r;
326
+ #i;
327
+ #a = 0;
328
+ #o = null;
329
+ #s;
330
+ constructor(e, t, n = {}) {
331
+ this.#e = e;
332
+ let r = t.ownerDocument;
333
+ this.#t = r, this.#s = n.onDismiss, this.#n = new u(r, t, {
334
+ className: "zine-search",
335
+ label: "Search results",
336
+ width: g,
337
+ onDismiss: n.onDismiss,
338
+ rtl: e.getDirection() === "rtl",
339
+ overlay: !0,
340
+ pageBox: () => e.getPageBox()
341
+ }), this.root = this.#n.root, this.#r = r.createElement("input"), this.#r.type = "search", this.#r.className = "zine-search-input", this.#r.placeholder = "Search…", this.#r.setAttribute("aria-label", "Search the document"), this.#r.addEventListener("input", () => {
342
+ this.#o && clearTimeout(this.#o), this.#o = setTimeout(() => void this.#l(), _);
343
+ }), this.#r.addEventListener("keydown", (e) => {
344
+ e.key === "Enter" && (this.#o && clearTimeout(this.#o), this.#l());
345
+ }), this.#i = r.createElement("div"), this.#i.className = "zine-search-hits", this.#n.root.append(this.#r, this.#i), this.#r.focus();
346
+ }
347
+ #c(e) {
348
+ let t = this.#t.createElement("div");
349
+ t.className = "zine-panel-note", t.textContent = e, this.#i.replaceChildren(t);
350
+ }
351
+ async #l() {
352
+ let e = this.#r.value.trim(), t = ++this.#a;
353
+ if (e.length < v) {
354
+ this.#i.replaceChildren();
355
+ return;
356
+ }
357
+ this.#c("Searching…");
358
+ let n = await this.#e.search(e);
359
+ if (!(t !== this.#a || !this.#n.root.isConnected)) {
360
+ if (n.length === 0) {
361
+ this.#c(`No matches for “${e}”`);
362
+ return;
363
+ }
364
+ this.#i.replaceChildren(...n.map((e) => {
365
+ let t = this.#t.createElement("button");
366
+ t.type = "button", t.className = "zine-search-hit", t.setAttribute("role", "option"), t.setAttribute("aria-label", `Page ${e.page + 1}: ${e.excerpt}`);
367
+ let n = this.#t.createElement("span");
368
+ n.className = "zine-search-page", n.textContent = `Page ${e.page + 1}`;
369
+ let r = this.#t.createElement("small");
370
+ return r.textContent = e.excerpt, t.append(n, r), t.addEventListener("click", () => {
371
+ this.#e.flipTo(e.page), this.#s?.();
372
+ }), t;
373
+ }));
374
+ }
375
+ }
376
+ destroy() {
377
+ this.#o && clearTimeout(this.#o), this.#o = null, this.#a++, this.#n.destroy();
378
+ }
379
+ }, b = class {
380
+ #e;
381
+ #t;
382
+ #n;
383
+ #r = null;
384
+ #i;
385
+ #a = [];
386
+ constructor(e, t, n = "auto", r = null) {
387
+ this.#e = e, this.#i = r;
388
+ let i = t.ownerDocument, s = e.getDirection() === "rtl";
389
+ if (this.#t = this.#o(i, s ? a.next : a.prev, "Previous page", () => e.flipPrev()), this.#n = this.#o(i, s ? a.prev : a.next, "Next page", () => e.flipNext()), this.#s(i, t), this.#r) o(this.#r, n);
390
+ else for (let e of [this.#t, this.#n]) o(e, n);
391
+ this.#a.push(e.on("pageChanged", ({ page: e }) => this.#c(e))), this.#a.push(e.on("flipEnd", () => this.#c())), this.#c();
392
+ }
393
+ #o(e, t, n, i) {
394
+ let a = e.createElement("button");
395
+ a.type = "button", a.className = "zine-arrow", a.title = n, a.setAttribute("aria-label", n), a.appendChild(r(e, t)), a.addEventListener("click", i);
396
+ for (let e of [
397
+ "pointerdown",
398
+ "pointerup",
399
+ "click"
400
+ ]) a.addEventListener(e, (e) => e.stopPropagation());
401
+ return a;
402
+ }
403
+ #s(e, t) {
404
+ let n = t.closest(".zine-panel-wrap") ?? t.closest(".zine-controls-wrap") ?? t, r = n.parentNode;
405
+ if (!r) return;
406
+ let i = e.createElement("div");
407
+ i.className = "zine-arrows-wrap", this.#i && i.classList.add(`zine-arrows-${this.#i}`), r.insertBefore(i, n), i.append(this.#t, n, this.#n), this.#r = i;
408
+ }
409
+ #c(e) {
410
+ let { prev: t, next: n } = this.#l(e);
411
+ for (let [e, r] of [[this.#t, t], [this.#n, n]]) e.disabled = !r, e.classList.toggle("zine-arrow-hidden", !r);
412
+ }
413
+ #l(e) {
414
+ if (e !== void 0) {
415
+ let t = this.#e.getSpreads(), n = t.findIndex((t) => t.left === e || t.right === e);
416
+ if (n >= 0) return {
417
+ prev: n > 0,
418
+ next: n + 1 < t.length
419
+ };
420
+ }
421
+ return {
422
+ prev: this.#e.canFlipPrev(),
423
+ next: this.#e.canFlipNext()
424
+ };
425
+ }
426
+ destroy() {
427
+ for (let e of this.#a) e();
428
+ this.#a = [], this.#t.remove(), this.#n.remove();
429
+ let e = this.#r;
430
+ if (e?.parentNode) {
431
+ for (; e.firstChild;) e.parentNode.insertBefore(e.firstChild, e);
432
+ e.remove();
433
+ }
434
+ this.#r = null;
435
+ }
436
+ }, x = {
437
+ thumbnails: f,
438
+ outline: h,
439
+ search: y
440
+ }, S = [
441
+ "pointerdown",
442
+ "pointerup",
443
+ "pointermove",
444
+ "click",
445
+ "dblclick",
446
+ "wheel",
447
+ "keydown"
448
+ ], C = class {
449
+ #e;
450
+ #t;
451
+ #n;
452
+ #r;
453
+ #i = [];
454
+ #a = null;
455
+ #o = [];
456
+ #s = null;
457
+ #c = null;
458
+ #l;
459
+ #u = null;
460
+ #d = null;
461
+ #f = null;
462
+ #p = null;
463
+ #m;
464
+ #h;
465
+ constructor(e, t, n) {
466
+ this.#e = e, this.#l = t;
467
+ let r = t.ownerDocument;
468
+ this.#t = r, i(r), this.#m = n.colorScheme ?? "auto";
469
+ let a = n.position ?? "bottom";
470
+ this.#h = a;
471
+ let s = n.docked ?? !0;
472
+ this.#n = r.createElement("div"), this.#n.className = [
473
+ "zine-controls",
474
+ `zine-controls-${a}`,
475
+ s ? "zine-controls-docked" : "zine-controls-floating",
476
+ n.className
477
+ ].filter(Boolean).join(" "), this.#n.setAttribute("role", "toolbar"), this.#n.setAttribute("aria-label", "Flipbook controls"), o(this.#n, this.#m), this.#r = r.createElement("div"), this.#r.className = "zine-controls-bar", this.#n.appendChild(this.#r), this.#n.addEventListener("keydown", (e) => this.#k(e));
478
+ for (let e of S) this.#n.addEventListener(e, (e) => this.#_(e));
479
+ this.#g(t, a, s);
480
+ let c = () => this.#A();
481
+ this.#o.push(e.on("pageChanged", c)), this.#o.push(e.on("zoomChanged", c)), this.#o.push(e.on("flipEnd", c));
482
+ let l = (e) => {
483
+ if (!this.#a) return;
484
+ let t = e.target;
485
+ this.#a.el.contains(t) || this.#a.trigger.contains(t) || this.#O();
486
+ };
487
+ r.addEventListener("pointerdown", l, !0), this.#o.push(() => r.removeEventListener("pointerdown", l, !0));
488
+ }
489
+ #g(e, t, n) {
490
+ if (!n) {
491
+ e.appendChild(this.#n);
492
+ return;
493
+ }
494
+ let r = e.parentNode;
495
+ if (!r) {
496
+ this.#n.classList.replace("zine-controls-docked", "zine-controls-floating"), e.appendChild(this.#n);
497
+ return;
498
+ }
499
+ let i = this.#t.createElement("div");
500
+ i.className = `zine-controls-wrap zine-controls-wrap-${t}`, r.insertBefore(i, e), i.appendChild(e), t === "top" || t === "left" ? i.insertBefore(this.#n, e) : i.appendChild(this.#n), this.#c = i;
501
+ }
502
+ mount(e) {
503
+ this.#y(e.items ?? n);
504
+ let t = e.arrows ?? !0;
505
+ t !== !1 && (this.#p = new b(this.#e, this.#l, this.#m, t === !0 ? null : t)), this.#A(), this.#N();
506
+ }
507
+ destroy() {
508
+ for (let e of this.#o) e();
509
+ this.#o = [], this.#O(), this.#u?.destroy(), this.#u = null, this.#d = null, this.#n.remove();
510
+ let e = this.#c;
511
+ e?.parentNode && (e.parentNode.insertBefore(e.firstChild, e), e.remove()), this.#c = null, this.#p?.destroy(), this.#p = null;
512
+ }
513
+ #_(e) {
514
+ e.stopPropagation();
515
+ }
516
+ #v(e = () => this.#O()) {
517
+ return {
518
+ zine: this.#e,
519
+ close: e,
520
+ colorScheme: this.#m
521
+ };
522
+ }
523
+ #y(t) {
524
+ for (let n of t) {
525
+ if (n === "|") {
526
+ let e = this.#t.createElement("div");
527
+ e.className = "zine-controls-sep", this.#r.appendChild(e);
528
+ continue;
529
+ }
530
+ let t = e(n), r;
531
+ t.render ? (r = t.render(this.#v()), this.#i.push({
532
+ el: r,
533
+ def: t
534
+ })) : r = this.#S(t, "zine-controls-btn"), this.#r.appendChild(r);
535
+ }
536
+ }
537
+ #b(e) {
538
+ return typeof e.title == "function" ? e.title(this.#v()) : e.title;
539
+ }
540
+ #x(e) {
541
+ return typeof e.icon == "function" ? e.icon(this.#v()) : e.icon;
542
+ }
543
+ #S(e, t, n = !1) {
544
+ let i = this.#t.createElement("button"), a = this.#b(e), o = this.#x(e);
545
+ if (i.type = "button", i.className = t, i.title = a, i.setAttribute("aria-label", a), o && i.appendChild(r(this.#t, o)), n || !o) {
546
+ let e = this.#t.createElement("span");
547
+ e.className = "zine-controls-label", e.textContent = a, i.appendChild(e);
548
+ }
549
+ return i.addEventListener("click", () => this.#C(e, i)), this.#i.push({
550
+ el: i,
551
+ def: e
552
+ }), i;
553
+ }
554
+ #C(e, t) {
555
+ if (e.isDisabled?.(this.#v())) return;
556
+ if (e.children) {
557
+ this.#a?.trigger === t ? this.#O() : this.#T(e, t);
558
+ return;
559
+ }
560
+ if (t.classList.contains("zine-controls-busy")) return;
561
+ let n = e.action?.(this.#v());
562
+ n && typeof n.then == "function" && (this.#w(t, !0), n.finally(() => {
563
+ this.#w(t, !1), this.#A();
564
+ })), this.#A();
565
+ }
566
+ #w(e, t) {
567
+ e.classList.toggle("zine-controls-busy", t), e.setAttribute("aria-busy", String(t)), e.disabled = t;
568
+ }
569
+ #T(t, n) {
570
+ this.#O();
571
+ let r = this.#t.createElement("div");
572
+ r.className = "zine-controls-menu", r.setAttribute("role", "menu");
573
+ let i = this.#v();
574
+ for (let n of t.children ?? []) {
575
+ if (n === "|") continue;
576
+ let t = e(n);
577
+ if (t.isVisible && !t.isVisible(i)) continue;
578
+ let a;
579
+ t.render ? (a = t.render(this.#v()), this.#i.push({
580
+ el: a,
581
+ def: t
582
+ })) : a = this.#S(t, "zine-controls-btn", !0), a.setAttribute("role", "menuitem"), r.appendChild(a);
583
+ }
584
+ this.#E(r, n), this.#A(), r.querySelector("button")?.focus();
585
+ }
586
+ #E(e, t) {
587
+ this.#n.appendChild(e), this.#a = {
588
+ el: e,
589
+ trigger: t
590
+ }, t.setAttribute("aria-expanded", "true"), this.#D(e, t);
591
+ }
592
+ #D(e, t) {
593
+ let n = this.#n.getBoundingClientRect(), r = t.getBoundingClientRect(), i = e.getBoundingClientRect();
594
+ if (!n.width || !i.width) return;
595
+ let a = r.left - n.left + r.width / 2 - i.width / 2;
596
+ a = Math.max(4, Math.min(a, n.width - i.width - 4)), e.style.left = `${a}px`;
597
+ let o = r.bottom - n.top + 6, s = r.top - n.top - i.height - 6;
598
+ e.style.top = `${this.#h === "bottom" || s >= 0 ? s : o}px`;
599
+ }
600
+ #O() {
601
+ if (!this.#a) return;
602
+ let { el: e, trigger: t } = this.#a;
603
+ this.#a = null, t.removeAttribute("aria-expanded"), this.#i = this.#i.filter((t) => !e.contains(t.el)), e.remove(), this.#t.activeElement && e.contains(this.#t.activeElement) && t.focus();
604
+ }
605
+ #k(e) {
606
+ if (e.key === "Escape" && this.#a) {
607
+ let { trigger: t } = this.#a;
608
+ this.#O(), t.focus(), e.preventDefault();
609
+ return;
610
+ }
611
+ let t = [...this.#n.querySelectorAll("button, input")], n = t.indexOf(this.#t.activeElement);
612
+ if (n < 0 || this.#t.activeElement instanceof HTMLInputElement) return;
613
+ let r = e.key === "ArrowRight" || e.key === "ArrowDown" ? 1 : e.key === "ArrowLeft" || e.key === "ArrowUp" ? -1 : 0;
614
+ r !== 0 && (t[(n + r + t.length) % t.length]?.focus(), e.preventDefault());
615
+ }
616
+ #A() {
617
+ let e = this.#v();
618
+ for (let { el: t, def: n } of this.#i) {
619
+ let i = n.children ? this.#M(n, e) : n.isVisible?.(e);
620
+ i !== void 0 && (t.style.display = i ? "" : "none");
621
+ let a = t.classList.contains("zine-controls-busy"), o = (n.isDisabled?.(e) ?? !1) || a;
622
+ for (let e of this.#j(t)) e.disabled = o;
623
+ if (this.#j(t).length || t.setAttribute("aria-disabled", String(o)), t.classList.toggle("zine-controls-off", o), n.isActive && t.setAttribute("aria-pressed", String(n.isActive(e))), typeof n.title == "function") {
624
+ let r = n.title(e);
625
+ t.title = r, t.setAttribute("aria-label", r);
626
+ let i = t.querySelector(".zine-controls-label");
627
+ i && (i.textContent = r);
628
+ }
629
+ typeof n.icon == "function" && t.querySelector("svg")?.replaceWith(r(this.#t, n.icon(e)));
630
+ }
631
+ this.#s && this.#t.activeElement !== this.#s && (this.#s.value = String(this.#e.getPage() + 1));
632
+ }
633
+ #j(e) {
634
+ return e instanceof HTMLButtonElement || e instanceof HTMLInputElement ? [e] : [...e.querySelectorAll("button, input")];
635
+ }
636
+ #M(t, n) {
637
+ return t.isVisible && !t.isVisible(n) ? !1 : (t.children ?? []).some((t) => {
638
+ if (t === "|") return !1;
639
+ let r = e(t);
640
+ return !r.isVisible || r.isVisible(n);
641
+ });
642
+ }
643
+ makePageInput() {
644
+ let e = this.#t.createElement("div");
645
+ e.className = "zine-controls-page";
646
+ let t = this.#t.createElement("input");
647
+ t.type = "number", t.min = "1", t.max = String(this.#e.getPageCount()), t.value = String(this.#e.getPage() + 1), t.setAttribute("aria-label", "Page number");
648
+ let n = this.#t.createElement("span");
649
+ n.textContent = `/ ${this.#e.getPageCount()}`;
650
+ let r = !1, i = () => {
651
+ if (r) return;
652
+ r = !0;
653
+ let e = Number(t.value), n = Math.max(0, this.#e.getPageCount() - 1), i = Number.isFinite(e) ? Math.min(Math.max(Math.round(e) - 1, 0), n) : this.#e.getPage();
654
+ i === this.#e.getPage() ? t.value = String(this.#e.getPage() + 1) : this.#e.flipTo(i);
655
+ };
656
+ return t.addEventListener("focus", () => {
657
+ r = !1;
658
+ }), t.addEventListener("keydown", (e) => {
659
+ e.key === "Enter" && (i(), t.blur());
660
+ }), t.addEventListener("blur", i), e.append(t, n), this.#s = t, e;
661
+ }
662
+ openPanel() {
663
+ return this.#d;
664
+ }
665
+ hasOutline() {
666
+ return this.#f === !0;
667
+ }
668
+ #N() {
669
+ this.#f !== null || !this.#e.canOutline() || (this.#f = !1, this.#e.getOutline().then((e) => {
670
+ if (e.length === 0) return;
671
+ this.#f = !0, this.#A();
672
+ let t = this.#a;
673
+ if (t) {
674
+ let e = this.#i.find((e) => e.el === t.trigger)?.def;
675
+ this.#O(), e && this.#T(e, t.trigger);
676
+ }
677
+ }));
678
+ }
679
+ togglePanel(e) {
680
+ let t = this.#d;
681
+ this.#u?.destroy(), this.#u = null, this.#d = null, t !== e && (this.#u = new x[e](this.#e, this.#l, { onDismiss: () => this.togglePanel(e) }), o(this.#u.root, this.#m), this.#d = e), this.#A();
682
+ }
683
+ };
684
+ function w(e) {
685
+ l(), t({
686
+ id: "thumbnails",
687
+ title: () => e.openPanel() === "thumbnails" ? "Hide thumbnails" : "Show thumbnails",
688
+ icon: a.thumbnails,
689
+ isVisible: (e) => e.zine.isDocument(),
690
+ isActive: () => e.openPanel() === "thumbnails",
691
+ action: (t) => {
692
+ e.togglePanel("thumbnails"), t.close();
693
+ }
694
+ }), t({
695
+ id: "outline",
696
+ title: () => e.openPanel() === "outline" ? "Hide outline" : "Show outline",
697
+ icon: a.outline,
698
+ isVisible: () => e.hasOutline(),
699
+ isActive: () => e.openPanel() === "outline",
700
+ action: (t) => {
701
+ e.togglePanel("outline"), t.close();
702
+ }
703
+ }), t({
704
+ id: "pageInput",
705
+ title: "Page",
706
+ render: () => e.makePageInput()
707
+ }), t({
708
+ id: "search",
709
+ title: () => e.openPanel() === "search" ? "Hide search" : "Search",
710
+ icon: a.search,
711
+ isVisible: (e) => e.zine.canSearch(),
712
+ isActive: () => e.openPanel() === "search",
713
+ action: () => e.togglePanel("search")
714
+ });
715
+ }
716
+ //#endregion
717
+ //#region src/controls/controls.ts
718
+ function T(e, t, n = {}) {
719
+ let r = new C(e, t, n);
720
+ return w(r), r.mount(n), () => r.destroy();
721
+ }
722
+ //#endregion
723
+ export { T as mountControls };
724
+
725
+ //# sourceMappingURL=controls-DgEXR2zi.js.map