@edrlab/thorium-web 1.2.1 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (97) hide show
  1. package/dist/{ThPreferencesAdapter-DrZ5_6Dv.d.mts → ThPreferencesAdapter-D0rzsGRl.d.mts} +50 -13
  2. package/dist/{ThSettingsWrapper-8Kx0SnH4.d.mts → ThSettingsWrapper-BXuRgdqp.d.mts} +42 -4
  3. package/dist/{actions-D2CHvCHu.d.mts → actions-BLAr0oaM.d.mts} +16 -4
  4. package/dist/{actionsReducer-kc-S130w.d.mts → actionsReducer-BhG1wicI.d.mts} +37 -12
  5. package/dist/chunk-3GDQP6AS.mjs +14 -0
  6. package/dist/chunk-3GDQP6AS.mjs.map +1 -0
  7. package/dist/{chunk-72XCX5TD.mjs → chunk-3LDWKC5N.mjs} +13 -8
  8. package/dist/chunk-3LDWKC5N.mjs.map +1 -0
  9. package/dist/{chunk-NYZBHYW2.mjs → chunk-4ODYHZKD.mjs} +343 -38
  10. package/dist/chunk-4ODYHZKD.mjs.map +1 -0
  11. package/dist/{chunk-QPE574OW.mjs → chunk-4TVEDX7L.mjs} +23 -32
  12. package/dist/chunk-4TVEDX7L.mjs.map +1 -0
  13. package/dist/chunk-7CGMWOZN.mjs +20 -0
  14. package/dist/chunk-7CGMWOZN.mjs.map +1 -0
  15. package/dist/{chunk-7NEQAW7J.mjs → chunk-C236BQQB.mjs} +656 -917
  16. package/dist/chunk-C236BQQB.mjs.map +1 -0
  17. package/dist/{chunk-PXAUQJEU.mjs → chunk-D7MFLHXV.mjs} +2267 -1599
  18. package/dist/chunk-D7MFLHXV.mjs.map +1 -0
  19. package/dist/{chunk-47AIIJFO.mjs → chunk-ITDBOMY5.mjs} +3 -3
  20. package/dist/{chunk-47AIIJFO.mjs.map → chunk-ITDBOMY5.mjs.map} +1 -1
  21. package/dist/{chunk-XVSFXHYB.mjs → chunk-L4XGZAZ5.mjs} +23 -20
  22. package/dist/chunk-L4XGZAZ5.mjs.map +1 -0
  23. package/dist/chunk-OWHP7ONM.mjs +134 -0
  24. package/dist/chunk-OWHP7ONM.mjs.map +1 -0
  25. package/dist/{chunk-P4V3LA5R.mjs → chunk-RRVLWDT3.mjs} +10 -7
  26. package/dist/chunk-RRVLWDT3.mjs.map +1 -0
  27. package/dist/chunk-T2E6MRVP.mjs +862 -0
  28. package/dist/chunk-T2E6MRVP.mjs.map +1 -0
  29. package/dist/chunk-TEZB4ULX.mjs +57 -0
  30. package/dist/chunk-TEZB4ULX.mjs.map +1 -0
  31. package/dist/chunk-UCTMVCW7.mjs +833 -0
  32. package/dist/chunk-UCTMVCW7.mjs.map +1 -0
  33. package/dist/chunk-WECWPYZB.mjs +1950 -0
  34. package/dist/chunk-WECWPYZB.mjs.map +1 -0
  35. package/dist/{chunk-4VHEHMJN.mjs → chunk-XBZWGRDM.mjs} +228 -94
  36. package/dist/chunk-XBZWGRDM.mjs.map +1 -0
  37. package/dist/{chunk-K3K7TUWM.mjs → chunk-YZ3KCMKY.mjs} +237 -83
  38. package/dist/chunk-YZ3KCMKY.mjs.map +1 -0
  39. package/dist/components/Audio/index.css +1858 -0
  40. package/dist/components/Audio/index.css.map +1 -0
  41. package/dist/components/Audio/index.d.mts +103 -0
  42. package/dist/components/Audio/index.mjs +23 -0
  43. package/dist/components/Audio/index.mjs.map +1 -0
  44. package/dist/components/Epub/index.css +365 -9
  45. package/dist/components/Epub/index.css.map +1 -1
  46. package/dist/components/Epub/index.d.mts +17 -19
  47. package/dist/components/Epub/index.mjs +15 -10
  48. package/dist/components/Misc/index.css +5 -2
  49. package/dist/components/Misc/index.css.map +1 -1
  50. package/dist/components/Misc/index.mjs +4 -132
  51. package/dist/components/Misc/index.mjs.map +1 -1
  52. package/dist/components/Reader/index.css +1022 -183
  53. package/dist/components/Reader/index.css.map +1 -1
  54. package/dist/components/Reader/index.d.mts +16 -16
  55. package/dist/components/Reader/index.mjs +121 -22
  56. package/dist/components/Reader/index.mjs.map +1 -1
  57. package/dist/components/WebPub/index.css +365 -9
  58. package/dist/components/WebPub/index.css.map +1 -1
  59. package/dist/components/WebPub/index.d.mts +16 -16
  60. package/dist/components/WebPub/index.mjs +15 -10
  61. package/dist/core/Components/index.d.mts +64 -15
  62. package/dist/core/Components/index.mjs +2 -1
  63. package/dist/core/Helpers/index.d.mts +2 -2
  64. package/dist/core/Helpers/index.mjs +4 -2
  65. package/dist/core/Hooks/index.d.mts +7 -8
  66. package/dist/core/Hooks/index.mjs +3 -1
  67. package/dist/i18n/index.mjs +4 -5
  68. package/dist/lib/index.d.mts +159 -15
  69. package/dist/lib/index.mjs +4 -2
  70. package/dist/lib-M3PPQDJJ.mjs +6548 -0
  71. package/dist/lib-M3PPQDJJ.mjs.map +1 -0
  72. package/dist/locales/en/thorium-web.json +22 -0
  73. package/dist/next-lib/index.mjs +2 -0
  74. package/dist/next-lib/index.mjs.map +1 -1
  75. package/dist/preferences/index.d.mts +111 -13
  76. package/dist/preferences/index.mjs +6 -3
  77. package/dist/{settingsReducer-C1wwCAMv.d.mts → settingsReducer-Bu1zeveu.d.mts} +1 -1
  78. package/dist/{ui-CamWuqOo.d.mts → ui-nBv8gfr0.d.mts} +20 -1
  79. package/dist/useAudioNavigator-C5aW4-eT.d.mts +133 -0
  80. package/dist/{useContrast-D6sjPjxy.d.mts → useContrast-2t429O9O.d.mts} +16 -8
  81. package/dist/usePreferences-VaBf46eP.d.mts +230 -0
  82. package/dist/useReaderTransitions-JDzlBFsu.d.mts +530 -0
  83. package/dist/{useTimeline-DyMx_aWY.d.mts → useTimeline-DCZ1qoCO.d.mts} +4 -2
  84. package/package.json +15 -11
  85. package/dist/chunk-4VHEHMJN.mjs.map +0 -1
  86. package/dist/chunk-72XCX5TD.mjs.map +0 -1
  87. package/dist/chunk-7NEQAW7J.mjs.map +0 -1
  88. package/dist/chunk-K3K7TUWM.mjs.map +0 -1
  89. package/dist/chunk-NYZBHYW2.mjs.map +0 -1
  90. package/dist/chunk-P4V3LA5R.mjs.map +0 -1
  91. package/dist/chunk-PXAUQJEU.mjs.map +0 -1
  92. package/dist/chunk-QPE574OW.mjs.map +0 -1
  93. package/dist/chunk-XVSFXHYB.mjs.map +0 -1
  94. package/dist/useEpubNavigator-CwHJfoiV.d.mts +0 -42
  95. package/dist/usePreferences-BXFJbval.d.mts +0 -43
  96. package/dist/useReaderTransitions-guT-eA-Q.d.mts +0 -365
  97. package/dist/useWebPubNavigator-CuSNQKMw.d.mts +0 -39
@@ -0,0 +1,833 @@
1
+ import { useReaderHeaderBase, thorium_web_reader_app_default, StatefulBackLink, thorium_web_reader_header_default, StatefulCollapsibleActionsBar, thorium_web_overflow_default, useNavigator } from './chunk-D7MFLHXV.mjs';
2
+ import { isInteractiveElement, makeBreakpointsMap, getBestMatchingProgressionFormat } from './chunk-ITDBOMY5.mjs';
3
+ import { useAppSelector, useAppDispatch, setHovering } from './chunk-YZ3KCMKY.mjs';
4
+ import { usePreferences } from './chunk-WECWPYZB.mjs';
5
+ import { ThRunningHeadFormat, ThProgressionFormat } from './chunk-L4XGZAZ5.mjs';
6
+ import { getPlatform, buildShortcut } from './chunk-5LUMM7FW.mjs';
7
+ import { ThInteractiveOverlay, ThHeader, ThFooter, ThRunningHead, ThPagination } from './chunk-4ODYHZKD.mjs';
8
+ import { useI18n } from './chunk-IYAFKTPL.mjs';
9
+ import { useRef, useCallback, useEffect, useMemo, useState } from 'react';
10
+ import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
11
+ import classNames from 'classnames';
12
+ import { useFocusWithin } from 'react-aria';
13
+
14
+ var StatefulReaderRunningHead = ({
15
+ formatPref
16
+ }) => {
17
+ const { t } = useI18n();
18
+ const unstableTimeline = useAppSelector((state) => state.publication.unstableTimeline);
19
+ const isImmersive = useAppSelector((state) => state.reader.isImmersive);
20
+ const isHovering = useAppSelector((state) => state.reader.isHovering);
21
+ const isFullscreen = useAppSelector((state) => state.reader.isFullscreen);
22
+ const breakpoint = useAppSelector((state) => state.theming.breakpoint);
23
+ const fallbackFormat = useMemo(() => ({
24
+ variants: "title" /* title */,
25
+ displayInImmersive: true,
26
+ displayInFullscreen: true
27
+ }), []);
28
+ const breakpointsMap = useMemo(() => {
29
+ return makeBreakpointsMap({
30
+ defaultValue: formatPref?.default || fallbackFormat,
31
+ fromEnum: ThRunningHeadFormat,
32
+ pref: formatPref?.breakpoints,
33
+ validateKey: "variants"
34
+ });
35
+ }, [formatPref, fallbackFormat]);
36
+ const currentPrefs = useMemo(() => {
37
+ if (!breakpoint) return formatPref?.default || fallbackFormat;
38
+ return breakpointsMap[breakpoint] || formatPref?.default || fallbackFormat;
39
+ }, [breakpoint, breakpointsMap, formatPref?.default, fallbackFormat]);
40
+ const { variants, displayInImmersive, displayInFullscreen } = currentPrefs;
41
+ const displayFormat = useMemo(() => {
42
+ if (!variants) return "title" /* title */;
43
+ if (isImmersive && displayInImmersive === false && !isHovering) {
44
+ return "none" /* none */;
45
+ }
46
+ if (isImmersive && isFullscreen && displayInFullscreen === false && !isHovering) {
47
+ return "none" /* none */;
48
+ }
49
+ return variants;
50
+ }, [variants, isImmersive, displayInImmersive, isHovering, isFullscreen, displayInFullscreen]);
51
+ const runningHead = useMemo(() => {
52
+ if (displayFormat === "title" /* title */) {
53
+ return unstableTimeline?.title || "";
54
+ } else if (displayFormat === "chapter" /* chapter */) {
55
+ return unstableTimeline?.progression?.currentChapter || unstableTimeline?.title || "";
56
+ }
57
+ return "";
58
+ }, [displayFormat, unstableTimeline]);
59
+ if (!runningHead || displayFormat === "none" /* none */) return null;
60
+ return /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsx(
61
+ ThRunningHead,
62
+ {
63
+ label: runningHead,
64
+ "aria-label": t("reader.app.header.runningHead")
65
+ }
66
+ ) });
67
+ };
68
+ var StatefulReaderHeader = ({
69
+ actionKeys,
70
+ actionsOrder,
71
+ layout,
72
+ runningHeadFormatPref
73
+ }) => {
74
+ const {
75
+ headerRef,
76
+ focusWithinProps,
77
+ setHover,
78
+ removeHover,
79
+ listActionItems,
80
+ isImmersive,
81
+ isHovering,
82
+ isScroll,
83
+ t
84
+ } = useReaderHeaderBase(actionKeys);
85
+ const { preferences } = usePreferences();
86
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
87
+ /* @__PURE__ */ jsx(
88
+ ThInteractiveOverlay,
89
+ {
90
+ className: classNames(thorium_web_reader_app_default.barOverlay, thorium_web_reader_app_default.headerOverlay),
91
+ isActive: layout === "layered-ui" /* layered */ && isImmersive && !isHovering,
92
+ onMouseEnter: setHover,
93
+ onMouseLeave: removeHover
94
+ }
95
+ ),
96
+ /* @__PURE__ */ jsxs(
97
+ ThHeader,
98
+ {
99
+ ref: headerRef,
100
+ className: classNames(thorium_web_reader_app_default.topBar, thorium_web_reader_header_default.header),
101
+ "aria-label": t("reader.app.header.label"),
102
+ onMouseEnter: setHover,
103
+ onMouseLeave: removeHover,
104
+ ...focusWithinProps,
105
+ children: [
106
+ preferences.theming.header?.backLink && /* @__PURE__ */ jsx(StatefulBackLink, { className: thorium_web_reader_header_default.backlinkWrapper }),
107
+ /* @__PURE__ */ jsx(StatefulReaderRunningHead, { formatPref: runningHeadFormatPref }),
108
+ /* @__PURE__ */ jsx(
109
+ StatefulCollapsibleActionsBar,
110
+ {
111
+ id: "reader-header-overflowMenu",
112
+ items: listActionItems(),
113
+ prefs: { ...preferences.actions, displayOrder: actionsOrder },
114
+ className: thorium_web_reader_header_default.actionsWrapper,
115
+ "aria-label": t("reader.app.header.actions"),
116
+ overflowMenuClassName: !isScroll || preferences.affordances.scroll.hintInImmersive ? thorium_web_overflow_default.hint : void 0
117
+ }
118
+ )
119
+ ]
120
+ }
121
+ )
122
+ ] });
123
+ };
124
+
125
+ // src/components/assets/styles/thorium-web.reader.pagination.module.css
126
+ var thorium_web_reader_pagination_default = {
127
+ wrapper: "thorium_web_reader_pagination_wrapper",
128
+ listItem: "thorium_web_reader_pagination_listItem",
129
+ previousButton: "thorium_web_reader_pagination_previousButton",
130
+ progression: "thorium_web_reader_pagination_progression",
131
+ nextButton: "thorium_web_reader_pagination_nextButton",
132
+ label: "thorium_web_reader_pagination_label"
133
+ };
134
+
135
+ // src/components/assets/styles/thorium-web.reader.progression.module.css
136
+ var thorium_web_reader_progression_default = {
137
+ wrapper: "thorium_web_reader_progression_wrapper"
138
+ };
139
+ var ThProgression = ({
140
+ ref,
141
+ children,
142
+ ...props
143
+ }) => {
144
+ return /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsx(
145
+ "div",
146
+ {
147
+ ref,
148
+ ...props,
149
+ children
150
+ }
151
+ ) });
152
+ };
153
+ var StatefulReaderProgression = ({
154
+ className,
155
+ formatPref,
156
+ fallbackVariant
157
+ }) => {
158
+ const { t } = useI18n();
159
+ const unstableTimeline = useAppSelector((state) => state.publication.unstableTimeline);
160
+ const isImmersive = useAppSelector((state) => state.reader.isImmersive);
161
+ const isFullscreen = useAppSelector((state) => state.reader.isFullscreen);
162
+ const isHovering = useAppSelector((state) => state.reader.isHovering);
163
+ const breakpoint = useAppSelector((state) => state.theming.breakpoint);
164
+ const [displayText, setDisplayText] = useState("");
165
+ const fallbackFormat = useMemo(() => {
166
+ return {
167
+ variants: fallbackVariant,
168
+ displayInImmersive: true,
169
+ displayInFullscreen: true
170
+ };
171
+ }, [fallbackVariant]);
172
+ const breakpointsMap = useMemo(() => {
173
+ return makeBreakpointsMap({
174
+ defaultValue: formatPref?.default || fallbackFormat,
175
+ fromEnum: ThProgressionFormat,
176
+ pref: formatPref?.breakpoints,
177
+ validateKey: "variants"
178
+ });
179
+ }, [formatPref, fallbackFormat]);
180
+ const currentPrefs = useMemo(() => {
181
+ if (!breakpoint) return formatPref?.default || fallbackFormat;
182
+ return breakpointsMap[breakpoint] || formatPref?.default || fallbackFormat;
183
+ }, [breakpoint, breakpointsMap, formatPref?.default, fallbackFormat]);
184
+ const { variants, displayInImmersive, displayInFullscreen } = currentPrefs;
185
+ const displayFormat = useMemo(() => {
186
+ if (!variants) return fallbackFormat.variants;
187
+ if (isImmersive && displayInImmersive === false && !isHovering) {
188
+ return "none" /* none */;
189
+ }
190
+ if (isImmersive && isFullscreen && displayInFullscreen === false && !isHovering) {
191
+ return "none" /* none */;
192
+ }
193
+ if (Array.isArray(variants)) {
194
+ return getBestMatchingProgressionFormat(variants, unstableTimeline?.progression) || fallbackFormat.variants;
195
+ }
196
+ return variants;
197
+ }, [variants, unstableTimeline?.progression, fallbackFormat, isImmersive, isHovering, isFullscreen, displayInImmersive, displayInFullscreen]);
198
+ useEffect(() => {
199
+ if (displayFormat === "none" /* none */ || !unstableTimeline?.progression) {
200
+ setDisplayText("");
201
+ return;
202
+ }
203
+ const {
204
+ currentPositions = [],
205
+ totalPositions,
206
+ relativeProgression,
207
+ totalProgression,
208
+ currentChapter,
209
+ positionsLeft,
210
+ totalItems,
211
+ currentIndex
212
+ } = unstableTimeline.progression;
213
+ let text = "";
214
+ const formatPositions = (positions) => {
215
+ if (positions.length === 2) {
216
+ return positions.join("\u2013");
217
+ }
218
+ return positions[0]?.toString() || "";
219
+ };
220
+ switch (displayFormat) {
221
+ case "positions" /* positions */:
222
+ if (currentPositions.length > 0) {
223
+ text = formatPositions(currentPositions);
224
+ }
225
+ break;
226
+ case "positionsOfTotal" /* positionsOfTotal */:
227
+ if (currentPositions.length > 0 && totalPositions) {
228
+ text = t("reader.progression.xOfY.compact", {
229
+ x: formatPositions(currentPositions),
230
+ y: totalPositions
231
+ });
232
+ }
233
+ break;
234
+ case "positionsPercentOfTotal" /* positionsPercentOfTotal */:
235
+ if (currentPositions.length > 0 && totalPositions) {
236
+ const percentage = Math.round((totalProgression || 0) * 100);
237
+ text = t("reader.progression.xOfY.descriptive", {
238
+ x: formatPositions(currentPositions),
239
+ y: totalPositions,
240
+ z: `${percentage}%`
241
+ });
242
+ }
243
+ break;
244
+ case "positionsLeft" /* positionsLeft */:
245
+ if (positionsLeft !== void 0) {
246
+ text = t(`reader.progression.positionsLeftInChapter.descriptive`, {
247
+ count: positionsLeft
248
+ });
249
+ }
250
+ break;
251
+ case "overallProgression" /* overallProgression */:
252
+ if (totalProgression !== void 0) {
253
+ const percentage = Math.round(totalProgression * 100);
254
+ text = `${percentage}%`;
255
+ }
256
+ break;
257
+ case "resourceProgression" /* resourceProgression */:
258
+ if (relativeProgression !== void 0) {
259
+ const percentage = Math.round(relativeProgression * 100);
260
+ text = `${percentage}%`;
261
+ }
262
+ break;
263
+ case "progressionOfResource" /* progressionOfResource */:
264
+ if (relativeProgression !== void 0) {
265
+ const percentage = Math.round(relativeProgression * 100);
266
+ text = t("reader.progression.xOfY.compact", {
267
+ x: `${percentage}%`,
268
+ y: currentChapter || t("reader.app.progression.referenceFallback")
269
+ });
270
+ }
271
+ break;
272
+ case "readingOrderIndex" /* readingOrderIndex */:
273
+ if (currentIndex !== void 0 && totalItems !== void 0) {
274
+ text = t("reader.progression.xOfY.compact", {
275
+ x: currentIndex,
276
+ y: totalItems
277
+ });
278
+ }
279
+ break;
280
+ }
281
+ setDisplayText(text);
282
+ }, [displayFormat, unstableTimeline?.progression, t]);
283
+ if (!displayText || displayFormat === "none" /* none */) {
284
+ return null;
285
+ }
286
+ return /* @__PURE__ */ jsx(
287
+ ThProgression,
288
+ {
289
+ id: "current-progression",
290
+ className: classNames(thorium_web_reader_progression_default.wrapper, className),
291
+ "aria-label": t("reader.app.progression.wrapper"),
292
+ children: displayText
293
+ }
294
+ );
295
+ };
296
+ var StatefulReaderPagination = ({
297
+ ref,
298
+ links,
299
+ compounds,
300
+ children,
301
+ ...props
302
+ }) => {
303
+ const previousButtonRef = useRef(null);
304
+ const nextButtonRef = useRef(null);
305
+ const updatedCompounds = {
306
+ ...compounds,
307
+ previousButton: {
308
+ ...compounds?.previousButton,
309
+ ref: previousButtonRef,
310
+ onKeyDown: (e) => {
311
+ if (e.key === "Escape") {
312
+ previousButtonRef.current?.blur();
313
+ }
314
+ }
315
+ },
316
+ nextButton: {
317
+ ...compounds?.nextButton,
318
+ ref: nextButtonRef,
319
+ onKeyDown: (e) => {
320
+ if (e.key === "Escape") {
321
+ nextButtonRef.current?.blur();
322
+ }
323
+ }
324
+ }
325
+ };
326
+ return /* @__PURE__ */ jsx(
327
+ ThPagination,
328
+ {
329
+ ref,
330
+ className: thorium_web_reader_pagination_default.wrapper,
331
+ links,
332
+ compounds: updatedCompounds,
333
+ ...props,
334
+ children
335
+ }
336
+ );
337
+ };
338
+ var StatefulReaderFooter = ({
339
+ layout,
340
+ progressionFormatPref,
341
+ progressionFormatFallback
342
+ }) => {
343
+ const { t } = useI18n();
344
+ const footerRef = useRef(null);
345
+ const readerProfile = useAppSelector((state) => state.reader.profile);
346
+ const isImmersive = useAppSelector((state) => state.reader.isImmersive);
347
+ const isHovering = useAppSelector((state) => state.reader.isHovering);
348
+ const hasScrollAffordance = useAppSelector((state) => state.reader.hasScrollAffordance);
349
+ const scroll = useAppSelector((state) => state.settings.scroll);
350
+ const isFXL = useAppSelector((state) => state.publication.isFXL);
351
+ const isScroll = scroll && !isFXL;
352
+ const breakpoint = useAppSelector((state) => state.theming.breakpoint);
353
+ const reducedMotion = useAppSelector((state) => state.theming.prefersReducedMotion);
354
+ const timeline = useAppSelector((state) => state.publication.unstableTimeline);
355
+ const dispatch = useAppDispatch();
356
+ const { focusWithinProps } = useFocusWithin({
357
+ onFocusWithin() {
358
+ dispatch(setHovering(true));
359
+ },
360
+ onBlurWithin() {
361
+ dispatch(setHovering(false));
362
+ }
363
+ });
364
+ const setHover = () => {
365
+ if (!hasScrollAffordance) {
366
+ dispatch(setHovering(true));
367
+ }
368
+ };
369
+ const removeHover = () => {
370
+ if (!hasScrollAffordance) {
371
+ dispatch(setHovering(false));
372
+ }
373
+ };
374
+ const { previousLocator, nextLocator, go } = useNavigator().unified;
375
+ const updateLinks = useCallback(() => {
376
+ const links = {
377
+ previous: void 0,
378
+ next: void 0
379
+ };
380
+ const previous = previousLocator();
381
+ const next = nextLocator();
382
+ if (previous) {
383
+ links.previous = {
384
+ node: breakpoint !== "compact" /* compact */ && breakpoint !== "medium" /* medium */ ? /* @__PURE__ */ jsxs(Fragment, { children: [
385
+ /* @__PURE__ */ jsx("span", { className: thorium_web_reader_app_default.srOnly, children: t(isFXL ? "reader.actions.goToPreviousPage.descriptive" : "reader.actions.goToPreviousChapter.descriptive") }),
386
+ /* @__PURE__ */ jsx("span", { className: thorium_web_reader_pagination_default.label, children: timeline?.previousItem?.title || previous.title || t(isFXL ? "reader.actions.goToPreviousPage.compact" : "reader.actions.goToPreviousChapter.compact") })
387
+ ] }) : /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsx("span", { className: thorium_web_reader_pagination_default.label, children: t(isFXL ? "reader.actions.goToPreviousPage.compact" : "reader.actions.goToPreviousChapter.compact") }) }),
388
+ onPress: () => go(previous, !reducedMotion, () => {
389
+ })
390
+ };
391
+ }
392
+ if (next) {
393
+ links.next = {
394
+ node: breakpoint !== "compact" /* compact */ && breakpoint !== "medium" /* medium */ ? /* @__PURE__ */ jsxs(Fragment, { children: [
395
+ /* @__PURE__ */ jsx("span", { className: thorium_web_reader_app_default.srOnly, children: t(isFXL ? "reader.actions.goToNextPage.descriptive" : "reader.actions.goToNextChapter.descriptive") }),
396
+ /* @__PURE__ */ jsx("span", { className: thorium_web_reader_pagination_default.label, children: timeline?.nextItem?.title || next.title || t(isFXL ? "reader.actions.goToNextPage.compact" : "reader.actions.goToNextChapter.compact") })
397
+ ] }) : /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsx("span", { className: thorium_web_reader_pagination_default.label, children: t(isFXL ? "reader.actions.goToNextPage.compact" : "reader.actions.goToNextChapter.compact") }) }),
398
+ onPress: () => go(next, !reducedMotion, () => {
399
+ })
400
+ };
401
+ }
402
+ return links;
403
+ }, [go, previousLocator, nextLocator, t, timeline, breakpoint, reducedMotion, isFXL]);
404
+ useEffect(() => {
405
+ updateLinks();
406
+ }, [timeline, updateLinks]);
407
+ useEffect(() => {
408
+ if (isImmersive) {
409
+ const focusElement = document.activeElement;
410
+ if (focusElement && footerRef.current?.contains(focusElement)) {
411
+ focusElement.blur();
412
+ }
413
+ }
414
+ }, [isImmersive]);
415
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
416
+ /* @__PURE__ */ jsx(
417
+ ThInteractiveOverlay,
418
+ {
419
+ className: classNames(thorium_web_reader_app_default.barOverlay, thorium_web_reader_app_default.footerOverlay),
420
+ isActive: layout === "layered-ui" /* layered */ && isImmersive && !isHovering,
421
+ onMouseEnter: setHover,
422
+ onMouseLeave: removeHover
423
+ }
424
+ ),
425
+ /* @__PURE__ */ jsx(
426
+ ThFooter,
427
+ {
428
+ ref: footerRef,
429
+ className: thorium_web_reader_app_default.bottomBar,
430
+ "aria-label": t("reader.app.footer.label"),
431
+ onMouseEnter: setHover,
432
+ onMouseLeave: removeHover,
433
+ ...focusWithinProps,
434
+ children: isScroll || readerProfile === "webPub" ? /* @__PURE__ */ jsx(
435
+ StatefulReaderPagination,
436
+ {
437
+ "aria-label": t("reader.navigation.scroll.wrapper"),
438
+ links: updateLinks(),
439
+ compounds: {
440
+ listItem: {
441
+ className: thorium_web_reader_pagination_default.listItem
442
+ },
443
+ previousButton: {
444
+ className: thorium_web_reader_pagination_default.previousButton,
445
+ preventFocusOnPress: true
446
+ },
447
+ nextButton: {
448
+ className: thorium_web_reader_pagination_default.nextButton,
449
+ preventFocusOnPress: true
450
+ }
451
+ },
452
+ children: /* @__PURE__ */ jsx(
453
+ StatefulReaderProgression,
454
+ {
455
+ className: thorium_web_reader_pagination_default.progression,
456
+ formatPref: progressionFormatPref,
457
+ fallbackVariant: progressionFormatFallback
458
+ }
459
+ )
460
+ }
461
+ ) : /* @__PURE__ */ jsx(
462
+ StatefulReaderProgression,
463
+ {
464
+ formatPref: progressionFormatPref,
465
+ fallbackVariant: progressionFormatFallback
466
+ }
467
+ )
468
+ }
469
+ )
470
+ ] });
471
+ };
472
+
473
+ // src/core/Hooks/fonts/androidPatchCss.ts
474
+ var getAndroidPatchCss = () => {
475
+ if (typeof window === "undefined") {
476
+ return "";
477
+ }
478
+ const origin = window.location.origin;
479
+ return `/* Readium CSS
480
+ Android Fonts Patch module
481
+
482
+ A stylesheet aligning Android generic serif and sans-serif fonts on other platforms
483
+
484
+ Repo: https://github.com/readium/css */
485
+
486
+ /* Android resolves sans-serif to Roboto, and serif to Droid Serif
487
+ This created issues for FXL EPUBs relying on Times (New Roman),
488
+ Helvetica or Arial while not embedding the font files in the package.
489
+
490
+ See https://github.com/readium/css/issues/149
491
+
492
+ Unfortunately it is no possible to target generic family using @font-face,
493
+ we have to target specific font-family names e.g. Times, Arial, etc.
494
+
495
+ This stylesheet/patch should be loaded only for this case i.e.
496
+ a Fixed-Layout EPUB with text but no embedded font on an Android device.
497
+ The logic for checking these conditions are up to implementers.
498
+ */
499
+
500
+ /* Serif (Times + Times New Roman) */
501
+
502
+ @font-face {
503
+ font-family: Times;
504
+ src: url("${new URL("/fonts/AndroidPatch/serif/NimbusRoman.woff", origin).toString()}") format("woff");
505
+ font-weight: normal;
506
+ font-style: normal;
507
+ }
508
+
509
+ @font-face {
510
+ font-family: "Times New Roman";
511
+ src: url("${new URL("/fonts/AndroidPatch/serif/NimbusRoman.woff", origin).toString()}") format("woff");
512
+ font-weight: normal;
513
+ font-style: normal;
514
+ }
515
+
516
+ @font-face {
517
+ font-family: Times;
518
+ src: url("${new URL("/fonts/AndroidPatch/serif/NimbusRoman-Italic.woff", origin).toString()}") format("woff");
519
+ font-weight: normal;
520
+ font-style: italic;
521
+ }
522
+
523
+ @font-face {
524
+ font-family: "Times New Roman";
525
+ src: url("${new URL("/fonts/AndroidPatch/serif/NimbusRoman-Italic.woff", origin).toString()}") format("woff");
526
+ font-weight: normal;
527
+ font-style: italic;
528
+ }
529
+
530
+ @font-face {
531
+ font-family: Times;
532
+ src: url("${new URL("/fonts/AndroidPatch/serif/NimbusRoman-Bold.woff", origin).toString()}") format("woff");
533
+ font-weight: bold;
534
+ font-style: normal;
535
+ }
536
+
537
+ @font-face {
538
+ font-family: "Times New Roman";
539
+ src: url("${new URL("/fonts/AndroidPatch/serif/NimbusRoman-Bold.woff", origin).toString()}") format("woff");
540
+ font-weight: bold;
541
+ font-style: normal;
542
+ }
543
+
544
+ @font-face {
545
+ font-family: Times;
546
+ src: url("${new URL("/fonts/AndroidPatch/serif/NimbusRoman-BoldItalic.woff", origin).toString()}") format("woff");
547
+ font-weight: bold;
548
+ font-style: italic;
549
+ }
550
+
551
+ @font-face {
552
+ font-family: "Times New Roman";
553
+ src: url("${new URL("/fonts/AndroidPatch/serif/NimbusRoman-BoldItalic.woff", origin).toString()}") format("woff");
554
+ font-weight: bold;
555
+ font-style: italic;
556
+ }
557
+
558
+ /* Sans-serif (Helvetica + Arial) */
559
+
560
+ @font-face {
561
+ font-family: Helvetica;
562
+ src: url("${new URL("/fonts/AndroidPatch/sans-serif/NimbusSans.woff", origin).toString()}") format("woff");
563
+ font-weight: normal;
564
+ font-style: normal;
565
+ }
566
+
567
+ @font-face {
568
+ font-family: Arial;
569
+ src: url("${new URL("/fonts/AndroidPatch/sans-serif/NimbusSans.woff", origin).toString()}") format("woff");
570
+ font-weight: normal;
571
+ font-style: normal;
572
+ }
573
+
574
+ @font-face {
575
+ font-family: Helvetica;
576
+ src: url("${new URL("/fonts/AndroidPatch/sans-serif/NimbusSans-Italic.woff", origin).toString()}") format("woff");
577
+ font-weight: normal;
578
+ font-style: italic;
579
+ }
580
+
581
+ @font-face {
582
+ font-family: Arial;
583
+ src: url("${new URL("/fonts/AndroidPatch/sans-serif/NimbusSans-Italic.woff", origin).toString()}") format("woff");
584
+ font-weight: normal;
585
+ font-style: italic;
586
+ }
587
+
588
+ @font-face {
589
+ font-family: Helvetica;
590
+ src: url("${new URL("/fonts/AndroidPatch/sans-serif/NimbusSans-Bold.woff", origin).toString()}") format("woff");
591
+ font-weight: bold;
592
+ font-style: normal;
593
+ }
594
+
595
+ @font-face {
596
+ font-family: Arial;
597
+ src: url("${new URL("/fonts/AndroidPatch/sans-serif/NimbusSans-Bold.woff", origin).toString()}") format("woff");
598
+ font-weight: bold;
599
+ font-style: normal;
600
+ }
601
+
602
+ @font-face {
603
+ font-family: Helvetica;
604
+ src: url("${new URL("/fonts/AndroidPatch/sans-serif/NimbusSans-BoldItalic.woff", origin).toString()}") format("woff");
605
+ font-weight: bold;
606
+ font-style: italic;
607
+ }
608
+
609
+ @font-face {
610
+ font-family: Arial;
611
+ src: url("${new URL("/fonts/AndroidPatch/sans-serif/NimbusSans-BoldItalic.woff", origin).toString()}") format("woff");
612
+ font-weight: bold;
613
+ font-style: italic;
614
+ }`;
615
+ };
616
+
617
+ // src/core/Hooks/fonts/useFonts.ts
618
+ var useFonts = (fontResources) => {
619
+ const injectedElementsRef = useRef({
620
+ prepend: [],
621
+ append: []
622
+ });
623
+ const createLinkElement = useCallback((resource) => {
624
+ const link = document.createElement("link");
625
+ if ("attributes" in resource && resource.attributes) {
626
+ Object.entries(resource.attributes).forEach(([key, value]) => {
627
+ link.setAttribute(key, value);
628
+ });
629
+ }
630
+ link.rel = resource.rel;
631
+ link.as = resource.as;
632
+ if ("url" in resource) {
633
+ link.href = resource.url;
634
+ } else if ("blob" in resource && resource.blob) {
635
+ link.href = URL.createObjectURL(resource.blob);
636
+ }
637
+ return link;
638
+ }, []);
639
+ const removeInjectedElements = useCallback(() => {
640
+ const { prepend, append } = injectedElementsRef.current;
641
+ [...prepend, ...append].forEach((element) => {
642
+ if (element.parentNode) {
643
+ element.parentNode.removeChild(element);
644
+ }
645
+ if (element instanceof HTMLLinkElement && element.href.startsWith("blob:")) {
646
+ URL.revokeObjectURL(element.href);
647
+ }
648
+ });
649
+ injectedElementsRef.current = {
650
+ prepend: [],
651
+ append: []
652
+ };
653
+ }, []);
654
+ const injectFontResources = useCallback((resources) => {
655
+ if (typeof document === "undefined") return;
656
+ removeInjectedElements();
657
+ if (!resources) return;
658
+ const { prepend, append } = resources;
659
+ const injectedElements = injectedElementsRef.current;
660
+ prepend.forEach((resource) => {
661
+ const element = createLinkElement(resource);
662
+ document.head.insertBefore(element, document.head.firstChild);
663
+ injectedElements.prepend.push(element);
664
+ });
665
+ append.forEach((resource) => {
666
+ const element = createLinkElement(resource);
667
+ document.head.appendChild(element);
668
+ injectedElements.append.push(element);
669
+ });
670
+ }, [createLinkElement, removeInjectedElements]);
671
+ const getAndroidFXLPatch = useCallback(() => {
672
+ const platform = getPlatform();
673
+ const isAndroid = platform === "android";
674
+ if (!isAndroid) {
675
+ return null;
676
+ }
677
+ const cssContent = getAndroidPatchCss();
678
+ const blob = new Blob([cssContent], { type: "text/css" });
679
+ return {
680
+ as: "link",
681
+ rel: "stylesheet",
682
+ blob
683
+ };
684
+ }, []);
685
+ useEffect(() => {
686
+ injectFontResources(fontResources || null);
687
+ return () => {
688
+ removeInjectedElements();
689
+ };
690
+ }, [fontResources, injectFontResources, removeInjectedElements]);
691
+ return {
692
+ injectFontResources,
693
+ removeFontResources: removeInjectedElements,
694
+ getAndroidFXLPatch
695
+ };
696
+ };
697
+
698
+ // src/helpers/peripherals.ts
699
+ var Peripherals = class {
700
+ observers = ["keydown"];
701
+ targets = [];
702
+ callbacks;
703
+ store;
704
+ actionsPref;
705
+ shortcuts;
706
+ constructor(store, actionsPref, callbacks) {
707
+ this.observers.forEach((method) => {
708
+ this["on" + method] = this["on" + method].bind(this);
709
+ });
710
+ this.store = store;
711
+ this.actionsPref = actionsPref;
712
+ this.callbacks = callbacks;
713
+ this.shortcuts = this.retrieveShortcuts();
714
+ }
715
+ getPlatformModifier() {
716
+ return this.store.getState().reader.platformModifier.modifier;
717
+ }
718
+ retrieveShortcuts() {
719
+ if (!this.actionsPref) return {};
720
+ const shortcutsObj = {};
721
+ const displayOrder = this.store.getState().publication.isFXL ? this.actionsPref.fxlOrder : this.actionsPref.reflowOrder;
722
+ for (const actionKey of displayOrder) {
723
+ const shortcutString = this.actionsPref.keys[actionKey].shortcut;
724
+ if (shortcutString) {
725
+ const shortcutObj = buildShortcut(shortcutString);
726
+ if (shortcutObj?.key) {
727
+ Object.defineProperty(shortcutsObj, shortcutObj.key, {
728
+ value: {
729
+ actionKey,
730
+ modifiers: shortcutObj.modifiers
731
+ },
732
+ writable: false,
733
+ enumerable: true
734
+ });
735
+ }
736
+ }
737
+ }
738
+ return shortcutsObj;
739
+ }
740
+ destroy() {
741
+ this.targets.forEach((t) => this.unobserve(t));
742
+ }
743
+ unobserve(item) {
744
+ if (!item) return;
745
+ this.observers.forEach((EventName) => {
746
+ item.removeEventListener(
747
+ EventName,
748
+ this["on" + EventName],
749
+ false
750
+ );
751
+ });
752
+ this.targets = this.targets.filter((t) => t !== item);
753
+ }
754
+ observe(item) {
755
+ if (!item) return;
756
+ if (this.targets.includes(item)) return;
757
+ this.observers.forEach((EventName) => {
758
+ item.addEventListener(EventName, this["on" + EventName], false);
759
+ });
760
+ this.targets.push(item);
761
+ }
762
+ onkeydown(e) {
763
+ const focusIsSafe = !isInteractiveElement(document.activeElement);
764
+ switch (e.code) {
765
+ case "Space":
766
+ focusIsSafe && this.callbacks.goProgression(e.shiftKey);
767
+ break;
768
+ case "ArrowRight":
769
+ focusIsSafe && this.callbacks.moveTo("right");
770
+ break;
771
+ case "ArrowLeft":
772
+ focusIsSafe && this.callbacks.moveTo("left");
773
+ break;
774
+ case "ArrowUp":
775
+ case "PageUp":
776
+ focusIsSafe && this.callbacks.moveTo("up");
777
+ break;
778
+ case "ArrowDown":
779
+ case "PageDown":
780
+ focusIsSafe && this.callbacks.moveTo("down");
781
+ break;
782
+ case "Home":
783
+ focusIsSafe && this.callbacks.moveTo("home");
784
+ break;
785
+ case "End":
786
+ focusIsSafe && this.callbacks.moveTo("end");
787
+ break;
788
+ default:
789
+ if (this.shortcuts.hasOwnProperty(e.code)) {
790
+ const customShortcutObj = this.shortcuts[e.code];
791
+ const sendCallback = Object.entries(customShortcutObj.modifiers).every(([modifier, value]) => {
792
+ if (modifier === "platformKey") {
793
+ return e[this.getPlatformModifier()] === value;
794
+ } else {
795
+ return e[modifier] === value;
796
+ }
797
+ });
798
+ if (sendCallback) {
799
+ e.preventDefault();
800
+ this.callbacks.toggleAction(customShortcutObj.actionKey);
801
+ }
802
+ }
803
+ break;
804
+ }
805
+ }
806
+ };
807
+ var LAYOUT_CLASSES = {
808
+ ["stacked-ui" /* stacked */]: "thorium_web_stackedUI",
809
+ ["layered-ui" /* layered */]: "thorium_web_layeredUI"
810
+ };
811
+ function getReaderClassNames(options) {
812
+ const {
813
+ layoutUI,
814
+ isScroll,
815
+ isImmersive = false,
816
+ isHovering = false,
817
+ isFXL = false,
818
+ breakpoint
819
+ } = options;
820
+ return classNames(
821
+ thorium_web_reader_app_default.shell,
822
+ isScroll ? "thorium_web_isScroll" : "thorium_web_isPaged",
823
+ isImmersive && "thorium_web_isImmersive",
824
+ isHovering && "thorium_web_isHovering",
825
+ isFXL ? "thorium_web_isFXL" : "thorium_web_isReflow",
826
+ LAYOUT_CLASSES[layoutUI],
827
+ breakpoint ? `thorium_web_is${breakpoint.charAt(0).toUpperCase() + breakpoint.slice(1)}` : void 0
828
+ );
829
+ }
830
+
831
+ export { Peripherals, StatefulReaderFooter, StatefulReaderHeader, getReaderClassNames, useFonts };
832
+ //# sourceMappingURL=chunk-UCTMVCW7.mjs.map
833
+ //# sourceMappingURL=chunk-UCTMVCW7.mjs.map