@edrlab/thorium-web 1.2.1 → 1.3.1

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 (100) 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-XWTGGNUd.d.mts} +46 -14
  5. package/dist/chunk-2ORXUOH3.mjs +134 -0
  6. package/dist/chunk-2ORXUOH3.mjs.map +1 -0
  7. package/dist/chunk-3GDQP6AS.mjs +14 -0
  8. package/dist/chunk-3GDQP6AS.mjs.map +1 -0
  9. package/dist/chunk-6BUN7DEA.mjs +854 -0
  10. package/dist/chunk-6BUN7DEA.mjs.map +1 -0
  11. package/dist/{chunk-IYAFKTPL.mjs → chunk-6EHFW43Y.mjs} +5 -4
  12. package/dist/chunk-6EHFW43Y.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-4VHEHMJN.mjs → chunk-A3FZBEUL.mjs} +228 -94
  16. package/dist/chunk-A3FZBEUL.mjs.map +1 -0
  17. package/dist/{chunk-NYZBHYW2.mjs → chunk-DETZMFZ7.mjs} +366 -61
  18. package/dist/chunk-DETZMFZ7.mjs.map +1 -0
  19. package/dist/{chunk-QPE574OW.mjs → chunk-DMZFSOHK.mjs} +28 -36
  20. package/dist/chunk-DMZFSOHK.mjs.map +1 -0
  21. package/dist/{chunk-7NEQAW7J.mjs → chunk-DTPO3J2C.mjs} +676 -930
  22. package/dist/chunk-DTPO3J2C.mjs.map +1 -0
  23. package/dist/{chunk-K3K7TUWM.mjs → chunk-EZG6SBSO.mjs} +358 -94
  24. package/dist/chunk-EZG6SBSO.mjs.map +1 -0
  25. package/dist/chunk-GPWW5OML.mjs +1955 -0
  26. package/dist/chunk-GPWW5OML.mjs.map +1 -0
  27. package/dist/{chunk-P4V3LA5R.mjs → chunk-I4BKU5NN.mjs} +13 -9
  28. package/dist/chunk-I4BKU5NN.mjs.map +1 -0
  29. package/dist/{chunk-47AIIJFO.mjs → chunk-ITDBOMY5.mjs} +3 -3
  30. package/dist/{chunk-47AIIJFO.mjs.map → chunk-ITDBOMY5.mjs.map} +1 -1
  31. package/dist/{chunk-XVSFXHYB.mjs → chunk-L4XGZAZ5.mjs} +23 -20
  32. package/dist/chunk-L4XGZAZ5.mjs.map +1 -0
  33. package/dist/{chunk-PXAUQJEU.mjs → chunk-LP3JFZ4A.mjs} +2425 -1634
  34. package/dist/chunk-LP3JFZ4A.mjs.map +1 -0
  35. package/dist/{chunk-72XCX5TD.mjs → chunk-NKO3K3QS.mjs} +14 -9
  36. package/dist/chunk-NKO3K3QS.mjs.map +1 -0
  37. package/dist/chunk-SAUOY37Q.mjs +862 -0
  38. package/dist/chunk-SAUOY37Q.mjs.map +1 -0
  39. package/dist/chunk-TEZB4ULX.mjs +57 -0
  40. package/dist/chunk-TEZB4ULX.mjs.map +1 -0
  41. package/dist/components/Audio/index.css +1858 -0
  42. package/dist/components/Audio/index.css.map +1 -0
  43. package/dist/components/Audio/index.d.mts +103 -0
  44. package/dist/components/Audio/index.mjs +23 -0
  45. package/dist/components/Audio/index.mjs.map +1 -0
  46. package/dist/components/Epub/index.css +365 -9
  47. package/dist/components/Epub/index.css.map +1 -1
  48. package/dist/components/Epub/index.d.mts +17 -19
  49. package/dist/components/Epub/index.mjs +18 -13
  50. package/dist/components/Misc/index.css +7 -4
  51. package/dist/components/Misc/index.css.map +1 -1
  52. package/dist/components/Misc/index.mjs +5 -133
  53. package/dist/components/Misc/index.mjs.map +1 -1
  54. package/dist/components/Reader/index.css +1022 -183
  55. package/dist/components/Reader/index.css.map +1 -1
  56. package/dist/components/Reader/index.d.mts +16 -16
  57. package/dist/components/Reader/index.mjs +124 -25
  58. package/dist/components/Reader/index.mjs.map +1 -1
  59. package/dist/components/WebPub/index.css +365 -9
  60. package/dist/components/WebPub/index.css.map +1 -1
  61. package/dist/components/WebPub/index.d.mts +16 -16
  62. package/dist/components/WebPub/index.mjs +18 -13
  63. package/dist/core/Components/index.d.mts +64 -15
  64. package/dist/core/Components/index.mjs +2 -1
  65. package/dist/core/Helpers/index.d.mts +2 -2
  66. package/dist/core/Helpers/index.mjs +4 -2
  67. package/dist/core/Hooks/index.d.mts +7 -8
  68. package/dist/core/Hooks/index.mjs +3 -1
  69. package/dist/i18n/index.mjs +6 -7
  70. package/dist/lib/index.d.mts +159 -15
  71. package/dist/lib/index.mjs +4 -2
  72. package/dist/lib-M3PPQDJJ.mjs +6548 -0
  73. package/dist/lib-M3PPQDJJ.mjs.map +1 -0
  74. package/dist/locales/en/thorium-web.json +22 -0
  75. package/dist/next-lib/index.mjs +2 -0
  76. package/dist/next-lib/index.mjs.map +1 -1
  77. package/dist/preferences/index.d.mts +111 -13
  78. package/dist/preferences/index.mjs +6 -3
  79. package/dist/{settingsReducer-C1wwCAMv.d.mts → settingsReducer-Bu1zeveu.d.mts} +1 -1
  80. package/dist/{ui-CamWuqOo.d.mts → ui-nBv8gfr0.d.mts} +20 -1
  81. package/dist/useAudioNavigator-C5aW4-eT.d.mts +133 -0
  82. package/dist/{useContrast-D6sjPjxy.d.mts → useContrast-2t429O9O.d.mts} +16 -8
  83. package/dist/usePreferences-VaBf46eP.d.mts +230 -0
  84. package/dist/useReaderTransitions-IBGdE7qi.d.mts +530 -0
  85. package/dist/{useTimeline-DyMx_aWY.d.mts → useTimeline-DCZ1qoCO.d.mts} +4 -2
  86. package/package.json +17 -13
  87. package/dist/chunk-4VHEHMJN.mjs.map +0 -1
  88. package/dist/chunk-72XCX5TD.mjs.map +0 -1
  89. package/dist/chunk-7NEQAW7J.mjs.map +0 -1
  90. package/dist/chunk-IYAFKTPL.mjs.map +0 -1
  91. package/dist/chunk-K3K7TUWM.mjs.map +0 -1
  92. package/dist/chunk-NYZBHYW2.mjs.map +0 -1
  93. package/dist/chunk-P4V3LA5R.mjs.map +0 -1
  94. package/dist/chunk-PXAUQJEU.mjs.map +0 -1
  95. package/dist/chunk-QPE574OW.mjs.map +0 -1
  96. package/dist/chunk-XVSFXHYB.mjs.map +0 -1
  97. package/dist/useEpubNavigator-CwHJfoiV.d.mts +0 -42
  98. package/dist/usePreferences-BXFJbval.d.mts +0 -43
  99. package/dist/useReaderTransitions-guT-eA-Q.d.mts +0 -365
  100. package/dist/useWebPubNavigator-CuSNQKMw.d.mts +0 -39
@@ -0,0 +1,862 @@
1
+ import { useNavigator, StatefulActionIcon, createAudioDefaultPlugin, usePositionStorage, NavigatorProvider, StatefulDockingWrapper, useReaderHeaderBase, StatefulBackLink, thorium_web_reader_header_default, StatefulCollapsibleActionsBar, thorium_web_overflow_default } from './chunk-LP3JFZ4A.mjs';
2
+ import { useAudioNavigator, useDocumentTitle, useAudioSettingsCache } from './chunk-A3FZBEUL.mjs';
3
+ import { useAppSelector, useAppDispatch, setTocEntry, setAdjacentTimelineItems, setSleepTimerOnFragmentEnd, setRemotePlaybackState, setStatus, setSeekableRanges, setSeeking, setStalled, setSleepTimerOnTrackEnd, setTrackReady, setPublicationStart, setPublicationEnd, debounce, setLoading } from './chunk-EZG6SBSO.mjs';
4
+ import { findTocItemByHref } from './chunk-TEZB4ULX.mjs';
5
+ import { useAudioPreferences, proxyUrl } from './chunk-GPWW5OML.mjs';
6
+ import { useI18n } from './chunk-6EHFW43Y.mjs';
7
+ import { resolveAudioContentProtectionConfig } from './chunk-DTPO3J2C.mjs';
8
+ import { ThActionsBar, ThAudioProgress, usePlugins, ThPluginRegistry, ThPluginProvider } from './chunk-DETZMFZ7.mjs';
9
+ import { useCallback, useState, useMemo, useLayoutEffect, useRef, useEffect, Fragment as Fragment$1 } from 'react';
10
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
11
+ import { Link, Locator, LocatorLocations } from '@readium/shared';
12
+ import { I18nProvider } from 'react-aria';
13
+ import classNames from 'classnames';
14
+
15
+ var SvgPause = (props) => /* @__PURE__ */ jsx("svg", { xmlns: "http://www.w3.org/2000/svg", height: "24px", viewBox: "0 -960 960 960", width: "24px", fill: "inherit", ...props, children: /* @__PURE__ */ jsx("path", { d: "M560-200v-560h160v560H560Zm-320 0v-560h160v560H240Z" }) });
16
+ var pause_default = SvgPause;
17
+ var SvgPlayArrow = (props) => /* @__PURE__ */ jsx("svg", { xmlns: "http://www.w3.org/2000/svg", height: "24px", viewBox: "0 -960 960 960", width: "24px", fill: "inherit", ...props, children: /* @__PURE__ */ jsx("path", { d: "M320-200v-560l440 280-440 280Z" }) });
18
+ var play_arrow_default = SvgPlayArrow;
19
+
20
+ // src/components/Audio/controls/assets/styles/thorium-web.audioPlayback.module.css
21
+ var thorium_web_audioPlayback_default = {
22
+ audioControls: "thorium_web_audioPlayback_audioControls",
23
+ audioPreviousButton: "thorium_web_audioPlayback_audioPreviousButton",
24
+ audioNextButton: "thorium_web_audioPlayback_audioNextButton",
25
+ audioSkipBackwardButton: "thorium_web_audioPlayback_audioSkipBackwardButton",
26
+ audioSkipForwardButton: "thorium_web_audioPlayback_audioSkipForwardButton",
27
+ audioPlayPauseButton: "thorium_web_audioPlayback_audioPlayPauseButton"
28
+ };
29
+ var StatefulPlayPauseButton = ({ isDisabled }) => {
30
+ const { t } = useI18n();
31
+ const { play, pause } = useNavigator().media;
32
+ const isPlaying = useAppSelector((state) => state.player.status === "playing");
33
+ const handlePress = useCallback(() => {
34
+ if (isPlaying) {
35
+ pause();
36
+ } else {
37
+ play();
38
+ }
39
+ }, [isPlaying, play, pause]);
40
+ return /* @__PURE__ */ jsx(
41
+ StatefulActionIcon,
42
+ {
43
+ onPress: handlePress,
44
+ isDisabled,
45
+ "aria-label": isPlaying ? t("reader.playback.actions.pause") : t("reader.playback.actions.play"),
46
+ tooltipLabel: isPlaying ? t("reader.playback.actions.pause") : t("reader.playback.actions.play"),
47
+ className: thorium_web_audioPlayback_default.audioPlayPauseButton,
48
+ children: isPlaying ? /* @__PURE__ */ jsx(pause_default, { "aria-hidden": "true", focusable: "false" }) : /* @__PURE__ */ jsx(play_arrow_default, { "aria-hidden": "true", focusable: "false" })
49
+ }
50
+ );
51
+ };
52
+ var SvgSkipPrevious = (props) => /* @__PURE__ */ jsx("svg", { xmlns: "http://www.w3.org/2000/svg", height: "24px", viewBox: "0 -960 960 960", width: "24px", fill: "inherit", ...props, children: /* @__PURE__ */ jsx("path", { d: "M220-240v-480h80v480h-80Zm520 0L380-480l360-240v480Zm-80-240Zm0 90v-180l-136 90 136 90Z" }) });
53
+ var skip_previous_default = SvgSkipPrevious;
54
+
55
+ // src/components/Audio/controls/hooks/useAdjacentTocItems.ts
56
+ var flattenTocTree = (items) => {
57
+ const result = [];
58
+ for (const item of items) {
59
+ result.push(item);
60
+ if (item.children) result.push(...flattenTocTree(item.children));
61
+ }
62
+ return result;
63
+ };
64
+ var useAdjacentTocItems = () => {
65
+ const tocTree = useAppSelector((state) => state.publication.unstableTimeline?.toc?.tree);
66
+ const tocCurrentEntry = useAppSelector((state) => state.publication.unstableTimeline?.toc?.currentEntry);
67
+ if (!tocTree || !tocCurrentEntry) return { previous: null, next: null };
68
+ const flat = flattenTocTree(tocTree);
69
+ const index = flat.findIndex((item) => item.href === tocCurrentEntry.href);
70
+ if (index < 0) return { previous: null, next: null };
71
+ return {
72
+ previous: index > 0 ? flat[index - 1] : null,
73
+ next: index < flat.length - 1 ? flat[index + 1] : null
74
+ };
75
+ };
76
+ var StatefulPreviousButton = ({ isDisabled }) => {
77
+ const { t } = useI18n();
78
+ const { preferences } = useAudioPreferences();
79
+ const { goBackward, goLink } = useNavigator().media;
80
+ const atStart = useAppSelector((state) => state.publication.atPublicationStart);
81
+ const previousTimelineItem = useAppSelector((state) => state.publication.adjacentTimelineItems.previous);
82
+ const { previous: previousTocItem } = useAdjacentTocItems();
83
+ const affordance = preferences.affordances.previous;
84
+ const isTimeline = affordance === "timeline" /* timeline */;
85
+ const isToc = affordance === "toc" /* toc */;
86
+ const previousItem = isToc ? previousTocItem : previousTimelineItem;
87
+ const label = (isTimeline || isToc) && previousItem?.title ? previousItem.title : t("reader.actions.goToPreviousResource.descriptive");
88
+ const handlePress = () => isTimeline || isToc ? previousItem && goLink(new Link({ href: previousItem.href }), false, () => {
89
+ }) : goBackward(false, () => {
90
+ });
91
+ return /* @__PURE__ */ jsx(
92
+ StatefulActionIcon,
93
+ {
94
+ onPress: handlePress,
95
+ isDisabled: isDisabled || (isTimeline || isToc ? !previousItem : atStart),
96
+ "aria-label": label,
97
+ tooltipLabel: label,
98
+ className: thorium_web_audioPlayback_default.audioPreviousButton,
99
+ children: /* @__PURE__ */ jsx(skip_previous_default, { "aria-hidden": "true", focusable: "false" })
100
+ }
101
+ );
102
+ };
103
+ var SvgSkipNext = (props) => /* @__PURE__ */ jsx("svg", { xmlns: "http://www.w3.org/2000/svg", height: "24px", viewBox: "0 -960 960 960", width: "24px", fill: "inherit", ...props, children: /* @__PURE__ */ jsx("path", { d: "M660-240v-480h80v480h-80Zm-440 0v-480l360 240-360 240Zm80-240Zm0 90 136-90-136-90v180Z" }) });
104
+ var skip_next_default = SvgSkipNext;
105
+ var StatefulNextButton = ({ isDisabled }) => {
106
+ const { t } = useI18n();
107
+ const { preferences } = useAudioPreferences();
108
+ const { goForward, goLink } = useNavigator().media;
109
+ const atEnd = useAppSelector((state) => state.publication.atPublicationEnd);
110
+ const nextTimelineItem = useAppSelector((state) => state.publication.adjacentTimelineItems.next);
111
+ const { next: nextTocItem } = useAdjacentTocItems();
112
+ const affordance = preferences.affordances.next;
113
+ const isTimeline = affordance === "timeline" /* timeline */;
114
+ const isToc = affordance === "toc" /* toc */;
115
+ const nextItem = isToc ? nextTocItem : nextTimelineItem;
116
+ const label = (isTimeline || isToc) && nextItem?.title ? nextItem.title : t("reader.actions.goToNextResource.descriptive");
117
+ const handlePress = () => isTimeline || isToc ? nextItem && goLink(new Link({ href: nextItem.href }), false, () => {
118
+ }) : goForward(false, () => {
119
+ });
120
+ return /* @__PURE__ */ jsx(
121
+ StatefulActionIcon,
122
+ {
123
+ onPress: handlePress,
124
+ isDisabled: isDisabled || (isTimeline || isToc ? !nextItem : atEnd),
125
+ "aria-label": label,
126
+ tooltipLabel: label,
127
+ className: thorium_web_audioPlayback_default.audioNextButton,
128
+ children: /* @__PURE__ */ jsx(skip_next_default, { "aria-hidden": "true", focusable: "false" })
129
+ }
130
+ );
131
+ };
132
+ var SvgReplay = (props) => /* @__PURE__ */ jsx("svg", { xmlns: "http://www.w3.org/2000/svg", height: "24px", viewBox: "0 -960 960 960", width: "24px", fill: "inherit", ...props, children: /* @__PURE__ */ jsx("path", { d: "M347.39-126.77q-61.85-26.77-107.85-72.77-46-46-72.77-107.85Q140-369.23 140-440h60q0 117 81.5 198.5T480-160q117 0 198.5-81.5T760-440q0-117-81.5-198.5T480-720h-10.62l63.54 63.54-42.15 43.38-136.92-137.3 137.69-137.31 42.15 43.38L469.38-780H480q70.77 0 132.61 26.77 61.85 26.77 107.85 72.77 46 46 72.77 107.85Q820-510.77 820-440q0 70.77-26.77 132.61-26.77 61.85-72.77 107.85-46 46-107.85 72.77Q550.77-100 480-100q-70.77 0-132.61-26.77Z" }) });
133
+ var replay_default = SvgReplay;
134
+ var SvgReplay5 = (props) => /* @__PURE__ */ jsx("svg", { xmlns: "http://www.w3.org/2000/svg", height: "24px", viewBox: "0 -960 960 960", width: "24px", fill: "inherit", ...props, children: /* @__PURE__ */ jsx("path", { d: "M347.39-126.77q-61.85-26.77-107.85-72.77-46-46-72.77-107.83Q140-369.2 140-440h60q0 117 81.5 198.5T480-160q117 0 198.5-81.5T760-440q0-117-81.5-198.5T480-720h-10.62l63.54 63.54-42.15 43.38-136.92-137.3 137.69-137.31 42.15 43.38L469.38-780H480q70.8 0 132.63 26.77t107.83 72.77q46 46 72.77 107.82Q820-510.81 820-440.02t-26.77 132.63q-26.77 61.85-72.77 107.85-46 46-107.82 72.77Q550.81-100 480.02-100t-132.63-26.77Zm38.76-199.38v-47.7h120v-48.46h-120v-131.54h167.7v47.7h-120v48.46H520q14.38 0 24.12 9.73 9.73 9.73 9.73 24.11V-360q0 14.38-9.73 24.12-9.74 9.73-24.12 9.73H386.15Z" }) });
135
+ var replay_5_default = SvgReplay5;
136
+ var SvgReplay10 = (props) => /* @__PURE__ */ jsx("svg", { xmlns: "http://www.w3.org/2000/svg", height: "24px", viewBox: "0 -960 960 960", width: "24px", fill: "inherit", ...props, children: /* @__PURE__ */ jsx("path", { d: "M347.39-126.77q-61.85-26.77-107.85-72.77-46-46-72.77-107.85Q140-369.23 140-440h60q0 117 81.5 198.5T480-160q117 0 198.5-81.5T760-440q0-117-81.5-198.5T480-720h-10.62l63.54 63.54-42.15 43.38-136.92-137.3 137.69-137.31 42.15 43.38L469.38-780H480q70.77 0 132.61 26.77 61.85 26.77 107.85 72.77 46 46 72.77 107.85Q820-510.77 820-440q0 70.77-26.77 132.61-26.77 61.85-72.77 107.85-46 46-107.85 72.77Q550.77-100 480-100q-70.77 0-132.61-26.77Zm21.07-199.38v-180h-57.69v-47.7h105.38v227.7h-47.69Zm135.39 0q-17 0-28.5-11.5t-11.5-28.5v-147.7q0-17 11.5-28.5t28.5-11.5h75.38q17 0 28.5 11.5t11.5 28.5v147.7q0 17-11.5 28.5t-28.5 11.5h-75.38Zm12.3-47.7h50.77q2.31 0 3.47-1.15 1.15-1.15 1.15-3.46v-123.08q0-2.31-1.15-3.46-1.16-1.15-3.47-1.15h-50.77q-2.3 0-3.46 1.15-1.15 1.15-1.15 3.46v123.08q0 2.31 1.15 3.46 1.16 1.15 3.46 1.15Z" }) });
137
+ var replay_10_default = SvgReplay10;
138
+ var SvgReplay30 = (props) => /* @__PURE__ */ jsx("svg", { xmlns: "http://www.w3.org/2000/svg", height: "24px", viewBox: "0 -960 960 960", width: "24px", fill: "inherit", ...props, children: /* @__PURE__ */ jsx("path", { d: "M347.39-126.77q-61.85-26.77-107.85-72.77-46-46-72.77-107.85Q140-369.23 140-440h60q0 117 81.5 198.5T480-160q117 0 198.5-81.5T760-440q0-117-81.5-198.5T480-720h-10.62l63.54 63.54-42.15 43.38-136.92-137.3 137.69-137.31 42.15 43.38L469.38-780H480q70.77 0 132.61 26.77 61.85 26.77 107.85 72.77 46 46 72.77 107.85Q820-510.77 820-440q0 70.77-26.77 132.61-26.77 61.85-72.77 107.85-46 46-107.85 72.77Q550.77-100 480-100q-70.77 0-132.61-26.77Zm-46.62-199.38v-47.7h107.69v-48.46h-71.54v-35.38h71.54v-48.46H300.77v-47.7h121.54q14.69 0 24.27 9.58 9.57 9.58 9.57 24.27v160q0 14.69-9.57 24.27-9.58 9.58-24.27 9.58H300.77Zm243.08 0q-17 0-28.5-11.5t-11.5-28.5v-147.7q0-17 11.5-28.5t28.5-11.5h75.38q17 0 28.5 11.5t11.5 28.5v147.7q0 17-11.5 28.5t-28.5 11.5h-75.38Zm12.3-47.7h50.77q2.31 0 3.47-1.15 1.15-1.15 1.15-3.46v-123.08q0-2.31-1.15-3.46-1.16-1.15-3.47-1.15h-50.77q-2.3 0-3.46 1.15-1.15 1.15-1.15 3.46v123.08q0 2.31 1.15 3.46 1.16 1.15 3.46 1.15Z" }) });
139
+ var replay_30_default = SvgReplay30;
140
+ var replayIconMap = {
141
+ 5: replay_5_default,
142
+ 10: replay_10_default,
143
+ 30: replay_30_default
144
+ };
145
+ var StatefulSkipBackwardButton = ({ isDisabled }) => {
146
+ const { t } = useI18n();
147
+ const { skipBackward } = useNavigator().media;
148
+ const skipBackwardInterval = useAppSelector((state) => state.audioSettings.skipBackwardInterval);
149
+ const Icon = replayIconMap[skipBackwardInterval] ?? replay_default;
150
+ return /* @__PURE__ */ jsx(
151
+ StatefulActionIcon,
152
+ {
153
+ onPress: skipBackward,
154
+ isDisabled,
155
+ "aria-label": t("reader.playback.actions.skipBackward.descriptive"),
156
+ tooltipLabel: t("reader.playback.actions.skipBackward.descriptive"),
157
+ className: thorium_web_audioPlayback_default.audioSkipBackwardButton,
158
+ children: /* @__PURE__ */ jsx(Icon, { "aria-hidden": "true", focusable: "false" })
159
+ }
160
+ );
161
+ };
162
+ var SvgForwardMedia = (props) => /* @__PURE__ */ jsx("svg", { xmlns: "http://www.w3.org/2000/svg", height: "24px", viewBox: "0 -960 960 960", width: "24px", fill: "inherit", ...props, children: /* @__PURE__ */ jsx("path", { d: "M347.39-126.77q-61.85-26.77-107.85-72.77-46-46-72.77-107.85Q140-369.23 140-440q0-70.77 26.77-132.61 26.77-61.85 72.77-107.85 46-46 107.85-72.77Q409.23-780 480-780h10.62l-64.31-64.31 42.15-43.38 137.69 137.31-136.92 137.3-42.15-43.38L490.62-720H480q-117 0-198.5 81.5T200-440q0 117 81.5 198.5T480-160q117 0 198.5-81.5T760-440h60q0 70.77-26.77 132.61-26.77 61.85-72.77 107.85-46 46-107.85 72.77Q550.77-100 480-100q-70.77 0-132.61-26.77Z" }) });
163
+ var forward_media_default = SvgForwardMedia;
164
+ var SvgForward5 = (props) => /* @__PURE__ */ jsx("svg", { xmlns: "http://www.w3.org/2000/svg", height: "24px", viewBox: "0 -960 960 960", width: "24px", fill: "inherit", ...props, children: /* @__PURE__ */ jsx("path", { d: "M347.39-126.77q-61.85-26.77-107.85-72.77-46-46-72.77-107.82Q140-369.19 140-439.98t26.77-132.63q26.77-61.85 72.77-107.85 46-46 107.83-72.77Q409.2-780 480-780h10.62l-64.31-64.31 42.15-43.38 137.69 137.31-136.92 137.3-42.15-43.38L490.62-720H480q-117 0-198.5 81.5T200-440q0 117 81.5 198.5T480-160q117 0 198.5-81.5T760-440h60q0 70.8-26.77 132.63t-72.77 107.83q-46 46-107.82 72.77Q550.81-100 480.02-100t-132.63-26.77Zm38.76-199.38v-47.7h120v-48.46h-120v-131.54h167.7v47.7h-120v48.46H520q14.38 0 24.12 9.73 9.73 9.73 9.73 24.11V-360q0 14.38-9.73 24.12-9.74 9.73-24.12 9.73H386.15Z" }) });
165
+ var forward_5_default = SvgForward5;
166
+ var SvgForward10 = (props) => /* @__PURE__ */ jsx("svg", { xmlns: "http://www.w3.org/2000/svg", height: "24px", viewBox: "0 -960 960 960", width: "24px", fill: "inherit", ...props, children: /* @__PURE__ */ jsx("path", { d: "M368.46-326.15v-180h-57.69v-47.7h105.38v227.7h-47.69Zm135.39 0q-17 0-28.5-11.5t-11.5-28.5v-147.7q0-17 11.5-28.5t28.5-11.5h75.38q17 0 28.5 11.5t11.5 28.5v147.7q0 17-11.5 28.5t-28.5 11.5h-75.38Zm12.3-47.7h50.77q2.31 0 3.47-1.15 1.15-1.15 1.15-3.46v-123.08q0-2.31-1.15-3.46-1.16-1.15-3.47-1.15h-50.77q-2.3 0-3.46 1.15-1.15 1.15-1.15 3.46v123.08q0 2.31 1.15 3.46 1.16 1.15 3.46 1.15ZM347.39-126.77q-61.85-26.77-107.85-72.77-46-46-72.77-107.85Q140-369.23 140-440q0-70.77 26.77-132.61 26.77-61.85 72.77-107.85 46-46 107.85-72.77Q409.23-780 480-780h10.62l-64.31-64.31 42.15-43.38 137.69 137.31-136.92 137.3-42.15-43.38L490.62-720H480q-117 0-198.5 81.5T200-440q0 117 81.5 198.5T480-160q117 0 198.5-81.5T760-440h60q0 70.77-26.77 132.61-26.77 61.85-72.77 107.85-46 46-107.85 72.77Q550.77-100 480-100q-70.77 0-132.61-26.77Z" }) });
167
+ var forward_10_default = SvgForward10;
168
+ var SvgForward30 = (props) => /* @__PURE__ */ jsx("svg", { xmlns: "http://www.w3.org/2000/svg", height: "24px", viewBox: "0 -960 960 960", width: "24px", fill: "inherit", ...props, children: /* @__PURE__ */ jsx("path", { d: "M300.77-326.15v-47.7h107.69v-48.46h-71.54v-35.38h71.54v-48.46H300.77v-47.7h121.54q14.69 0 24.27 9.58 9.57 9.58 9.57 24.27v160q0 14.69-9.57 24.27-9.58 9.58-24.27 9.58H300.77Zm243.08 0q-17 0-28.5-11.5t-11.5-28.5v-147.7q0-17 11.5-28.5t28.5-11.5h75.38q17 0 28.5 11.5t11.5 28.5v147.7q0 17-11.5 28.5t-28.5 11.5h-75.38Zm12.3-47.7h50.77q2.31 0 3.47-1.15 1.15-1.15 1.15-3.46v-123.08q0-2.31-1.15-3.46-1.16-1.15-3.47-1.15h-50.77q-2.3 0-3.46 1.15-1.15 1.15-1.15 3.46v123.08q0 2.31 1.15 3.46 1.16 1.15 3.46 1.15ZM347.39-126.77q-61.85-26.77-107.85-72.77-46-46-72.77-107.85Q140-369.23 140-440q0-70.77 26.77-132.61 26.77-61.85 72.77-107.85 46-46 107.85-72.77Q409.23-780 480-780h10.62l-64.31-64.31 42.15-43.38 137.69 137.31-136.92 137.3-42.15-43.38L490.62-720H480q-117 0-198.5 81.5T200-440q0 117 81.5 198.5T480-160q117 0 198.5-81.5T760-440h60q0 70.77-26.77 132.61-26.77 61.85-72.77 107.85-46 46-107.85 72.77Q550.77-100 480-100q-70.77 0-132.61-26.77Z" }) });
169
+ var forward_30_default = SvgForward30;
170
+ var forwardIconMap = {
171
+ 5: forward_5_default,
172
+ 10: forward_10_default,
173
+ 30: forward_30_default
174
+ };
175
+ var StatefulSkipForwardButton = ({ isDisabled }) => {
176
+ const { t } = useI18n();
177
+ const { skipForward } = useNavigator().media;
178
+ const skipForwardInterval = useAppSelector((state) => state.audioSettings.skipForwardInterval);
179
+ const Icon = forwardIconMap[skipForwardInterval] ?? forward_media_default;
180
+ return /* @__PURE__ */ jsx(
181
+ StatefulActionIcon,
182
+ {
183
+ onPress: skipForward,
184
+ isDisabled,
185
+ "aria-label": t("reader.playback.actions.skipForward.descriptive"),
186
+ tooltipLabel: t("reader.playback.actions.skipForward.descriptive"),
187
+ className: thorium_web_audioPlayback_default.audioSkipForwardButton,
188
+ children: /* @__PURE__ */ jsx(Icon, { "aria-hidden": "true", focusable: "false" })
189
+ }
190
+ );
191
+ };
192
+ var StatefulAudioPlaybackControls = () => {
193
+ const { t } = useI18n();
194
+ const isTrackReady = useAppSelector((state) => state.player.isTrackReady);
195
+ const isStalled = useAppSelector((state) => state.player.isStalled);
196
+ return /* @__PURE__ */ jsxs(ThActionsBar, { className: thorium_web_audioPlayback_default.audioControls, "aria-label": t("audio.player.controls"), dir: "ltr", children: [
197
+ /* @__PURE__ */ jsx(StatefulPreviousButton, { isDisabled: !isTrackReady || isStalled }),
198
+ /* @__PURE__ */ jsx(StatefulSkipBackwardButton, { isDisabled: !isTrackReady || isStalled }),
199
+ /* @__PURE__ */ jsx(StatefulPlayPauseButton, { isDisabled: !isTrackReady || isStalled }),
200
+ /* @__PURE__ */ jsx(StatefulSkipForwardButton, { isDisabled: !isTrackReady || isStalled }),
201
+ /* @__PURE__ */ jsx(StatefulNextButton, { isDisabled: !isTrackReady || isStalled })
202
+ ] });
203
+ };
204
+
205
+ // src/components/Audio/controls/assets/styles/thorium-web.audioProgressBar.module.css
206
+ var thorium_web_audioProgressBar_default = {
207
+ wrapper: "thorium_web_audioProgressBar_wrapper",
208
+ current: "thorium_web_audioProgressBar_current",
209
+ slider: "thorium_web_audioProgressBar_slider",
210
+ track: "thorium_web_audioProgressBar_track",
211
+ thumb: "thorium_web_audioProgressBar_thumb",
212
+ seekableRange: "thorium_web_audioProgressBar_seekableRange",
213
+ elapsed: "thorium_web_audioProgressBar_elapsed",
214
+ remaining: "thorium_web_audioProgressBar_remaining",
215
+ tick: "thorium_web_audioProgressBar_tick",
216
+ tooltip: "thorium_web_audioProgressBar_tooltip"
217
+ };
218
+ var StatefulAudioProgressBar = () => {
219
+ const { t } = useI18n();
220
+ const { preferences } = useAudioPreferences();
221
+ const tocEntry = useAppSelector((state) => state.publication.unstableTimeline?.toc?.currentEntry);
222
+ const currentChapter = tocEntry?.title;
223
+ const isStalled = useAppSelector((state) => state.player.isStalled);
224
+ const isTrackReady = useAppSelector((state) => state.player.isTrackReady);
225
+ const seekableRanges = useAppSelector((state) => state.player.seekableRanges);
226
+ const playbackRate = useAppSelector((state) => state.audioSettings.playbackRate);
227
+ const { currentTime, duration, seek, currentLocator, timeline } = useNavigator().media;
228
+ const current = currentTime();
229
+ const total = duration();
230
+ const [hoverLabel, setHoverLabel] = useState(void 0);
231
+ const handleSeek = useCallback((time) => {
232
+ seek(time);
233
+ }, [seek]);
234
+ const handleHoverProgression = useCallback((progression) => {
235
+ if (progression === null) {
236
+ setHoverLabel(void 0);
237
+ return;
238
+ }
239
+ const locator = currentLocator();
240
+ const tl = timeline();
241
+ if (!locator || !tl) return;
242
+ const item = tl.itemAtProgression(locator.href, progression, total);
243
+ setHoverLabel(item?.title);
244
+ }, [currentLocator, timeline, total]);
245
+ const parseTimestamp = (href) => {
246
+ const match = href.match(/#t=(\d+(?:\.\d+)?)$/);
247
+ return match ? parseFloat(match[1]) : 0;
248
+ };
249
+ const segments = useMemo(() => {
250
+ const locator = currentLocator();
251
+ const tl = timeline();
252
+ if (!locator || !tl || preferences.theming.layout.progressBar?.variant !== "segmented" /* segmented */) return [];
253
+ const segments2 = tl.segmentsForHref(locator.href);
254
+ if (!segments2 || !Array.isArray(segments2)) return [];
255
+ return segments2.map((segment) => {
256
+ const referenceHref = segment.references?.[0] || "";
257
+ const timestamp = parseTimestamp(referenceHref);
258
+ const percentage = total > 0 ? timestamp / total * 100 : 0;
259
+ return {
260
+ title: segment.title,
261
+ timestamp,
262
+ percentage
263
+ };
264
+ });
265
+ }, [currentLocator, timeline, total, preferences.theming.layout.progressBar?.variant]);
266
+ return /* @__PURE__ */ jsx(
267
+ ThAudioProgress,
268
+ {
269
+ currentTime: current,
270
+ duration: total,
271
+ playbackRate,
272
+ onSeek: handleSeek,
273
+ currentChapter: currentChapter || "\u200B",
274
+ isDisabled: !isTrackReady || isStalled,
275
+ seekableRanges,
276
+ hoverLabel,
277
+ onHoverProgression: handleHoverProgression,
278
+ segments,
279
+ compounds: {
280
+ wrapper: {
281
+ className: thorium_web_audioProgressBar_default.wrapper,
282
+ onKeyDown: (e) => {
283
+ if (e.key === "Escape") document.activeElement?.blur();
284
+ }
285
+ },
286
+ current: {
287
+ className: thorium_web_audioProgressBar_default.current
288
+ },
289
+ slider: {
290
+ className: thorium_web_audioProgressBar_default.slider,
291
+ "aria-label": t("audio.player.progress")
292
+ },
293
+ track: {
294
+ className: thorium_web_audioProgressBar_default.track
295
+ },
296
+ thumb: {
297
+ className: thorium_web_audioProgressBar_default.thumb
298
+ },
299
+ elapsedTime: {
300
+ className: thorium_web_audioProgressBar_default.elapsed
301
+ },
302
+ remainingTime: {
303
+ className: thorium_web_audioProgressBar_default.remaining
304
+ },
305
+ seekableRange: {
306
+ className: thorium_web_audioProgressBar_default.seekableRange
307
+ },
308
+ fragmentTick: {
309
+ className: thorium_web_audioProgressBar_default.tick
310
+ },
311
+ tooltip: {
312
+ className: thorium_web_audioProgressBar_default.tooltip,
313
+ offset: preferences.theming.icon.tooltipOffset
314
+ }
315
+ }
316
+ }
317
+ );
318
+ };
319
+
320
+ // src/components/Audio/actions/assets/styles/thorium-web.audioActions.module.css
321
+ var thorium_web_audioActions_default = {
322
+ wrapper: "thorium_web_audioActions_wrapper"};
323
+ var AudioActionPair = ({ action }) => {
324
+ const triggerRef = useRef(null);
325
+ const { Trigger, Target } = action;
326
+ return /* @__PURE__ */ jsxs(Fragment$1, { children: [
327
+ /* @__PURE__ */ jsx(Trigger, { ref: triggerRef, variant: "iconButton" /* button */ }),
328
+ Target && /* @__PURE__ */ jsx(Target, { triggerRef, placement: "top" })
329
+ ] });
330
+ };
331
+ var StatefulAudioMediaActions = () => {
332
+ const { t } = useI18n();
333
+ const { preferences } = useAudioPreferences();
334
+ const { primaryAudioActionsMap } = usePlugins();
335
+ const displayOrder = preferences.actions.primary.displayOrder;
336
+ return /* @__PURE__ */ jsx(ThActionsBar, { className: thorium_web_audioActions_default.wrapper, "aria-label": t("audio.player.mediaActions"), children: displayOrder.map((key) => {
337
+ const action = primaryAudioActionsMap[key];
338
+ if (!action) return null;
339
+ return /* @__PURE__ */ jsx(AudioActionPair, { action }, key);
340
+ }) });
341
+ };
342
+
343
+ // src/components/Audio/assets/styles/thorium-web.audio.app.module.css
344
+ var thorium_web_audio_app_default = {
345
+ main: "thorium_web_audio_app_main",
346
+ shell: "thorium_web_audio_app_shell",
347
+ topBar: "thorium_web_audio_app_topBar"
348
+ };
349
+
350
+ // src/components/Audio/assets/styles/thorium-web.audioPlayer.module.css
351
+ var thorium_web_audioPlayer_default = {
352
+ audioPlayerWrapper: "thorium_web_audioPlayer_audioPlayerWrapper",
353
+ audioPlayerWrapperExpanded: "thorium_web_audioPlayer_audioPlayerWrapperExpanded",
354
+ audioPlayerExpandedStart: "thorium_web_audioPlayer_audioPlayerExpandedStart",
355
+ audioPlayerExpandedEnd: "thorium_web_audioPlayer_audioPlayerExpandedEnd",
356
+ coverMetadataGroup: "thorium_web_audioPlayer_coverMetadataGroup"
357
+ };
358
+ var StatefulPlayerHeader = ({
359
+ actionKeys,
360
+ actionsOrder
361
+ }) => {
362
+ const {
363
+ headerRef,
364
+ listActionItems,
365
+ t
366
+ } = useReaderHeaderBase(actionKeys);
367
+ const { preferences } = useAudioPreferences();
368
+ return /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsxs(
369
+ "div",
370
+ {
371
+ ref: headerRef,
372
+ className: classNames(thorium_web_audio_app_default.topBar, thorium_web_reader_header_default.header),
373
+ children: [
374
+ preferences.theming.header?.backLink && /* @__PURE__ */ jsx(StatefulBackLink, { className: thorium_web_reader_header_default.backlinkWrapper }),
375
+ /* @__PURE__ */ jsx(
376
+ StatefulCollapsibleActionsBar,
377
+ {
378
+ id: "reader-header-overflowMenu",
379
+ items: listActionItems(),
380
+ prefs: { ...preferences.actions.secondary, displayOrder: actionsOrder },
381
+ className: thorium_web_reader_header_default.actionsWrapper,
382
+ "aria-label": t("reader.app.header.actions"),
383
+ overflowMenuClassName: thorium_web_overflow_default.hint
384
+ }
385
+ )
386
+ ]
387
+ }
388
+ ) });
389
+ };
390
+
391
+ // src/components/Audio/assets/styles/thorium-web.audioCover.module.css
392
+ var thorium_web_audioCover_default = {
393
+ audioCoverSection: "thorium_web_audioCover_audioCoverSection",
394
+ audioCoverImage: "thorium_web_audioCover_audioCoverImage",
395
+ audioCoverPlaceholder: "thorium_web_audioCover_audioCoverPlaceholder",
396
+ audioCoverSyncOverlay: "thorium_web_audioCover_audioCoverSyncOverlay",
397
+ audioCoverSyncIcon: "thorium_web_audioCover_audioCoverSyncIcon"};
398
+ var SvgMusicNote = (props) => /* @__PURE__ */ jsx("svg", { xmlns: "http://www.w3.org/2000/svg", height: "24px", viewBox: "0 -960 960 960", width: "24px", fill: "inherit", ...props, children: /* @__PURE__ */ jsx("path", { d: "M287-167q-47-47-47-113t47-113q47-47 113-47 23 0 42.5 5.5T480-418v-422h240v160H560v400q0 66-47 113t-113 47q-66 0-113-47Z" }) });
399
+ var music_note_default = SvgMusicNote;
400
+ var SvgSync = (props) => /* @__PURE__ */ jsx("svg", { xmlns: "http://www.w3.org/2000/svg", height: "24px", viewBox: "0 -960 960 960", width: "24px", fill: "inherit", ...props, children: /* @__PURE__ */ jsx("path", { d: "M160-160v-80h110l-16-14q-52-46-73-105t-21-119q0-111 66.5-197.5T400-790v84q-72 26-116 88.5T240-478q0 45 17 87.5t53 78.5l10 10v-98h80v240H160Zm400-10v-84q72-26 116-88.5T720-482q0-45-17-87.5T650-648l-10-10v98h-80v-240h240v80H690l16 14q49 49 71.5 106.5T800-482q0 111-66.5 197.5T560-170Z" }) });
401
+ var sync_default = SvgSync;
402
+ function StatefulAudioCover({ ref, coverUrl, title }) {
403
+ const { t } = useI18n();
404
+ const isTrackReady = useAppSelector((state) => state.player.isTrackReady);
405
+ const isStalled = useAppSelector((state) => state.player.isStalled);
406
+ const showSyncOverlay = !isTrackReady || isStalled;
407
+ return /* @__PURE__ */ jsxs("figure", { ref, className: thorium_web_audioCover_default.audioCoverSection, children: [
408
+ coverUrl ? /* @__PURE__ */ jsx(
409
+ "img",
410
+ {
411
+ src: proxyUrl(coverUrl),
412
+ alt: title || t("audio.player.coverAlt"),
413
+ className: thorium_web_audioCover_default.audioCoverImage,
414
+ crossOrigin: "anonymous"
415
+ }
416
+ ) : /* @__PURE__ */ jsx("div", { className: thorium_web_audioCover_default.audioCoverPlaceholder, children: showSyncOverlay ? /* @__PURE__ */ jsx(sync_default, { className: thorium_web_audioCover_default.audioCoverSyncIcon, "aria-hidden": "true" }) : /* @__PURE__ */ jsx(music_note_default, {}) }),
417
+ coverUrl && showSyncOverlay && /* @__PURE__ */ jsx("div", { className: thorium_web_audioCover_default.audioCoverSyncOverlay, "aria-hidden": "true", children: /* @__PURE__ */ jsx(sync_default, { className: thorium_web_audioCover_default.audioCoverSyncIcon }) })
418
+ ] });
419
+ }
420
+
421
+ // src/components/Audio/assets/styles/thorium-web.audioMetadata.module.css
422
+ var thorium_web_audioMetadata_default = {
423
+ audioMetadata: "thorium_web_audioMetadata_audioMetadata",
424
+ audioMetadataTitle: "thorium_web_audioMetadata_audioMetadataTitle",
425
+ audioMetadataSubtitle: "thorium_web_audioMetadata_audioMetadataSubtitle",
426
+ audioMetadataAuthors: "thorium_web_audioMetadata_audioMetadataAuthors"
427
+ };
428
+ function StatefulAudioMetadata({ publication }) {
429
+ const { preferences } = useAudioPreferences();
430
+ const { metadata } = publication;
431
+ const title = metadata.title.getTranslation("en");
432
+ const subtitle = metadata.subtitle?.getTranslation("en");
433
+ const authors = metadata.authors?.items.map((a) => a.name.getTranslation("en"));
434
+ const metadataOrder = preferences.theming.layout.publicationMetadata.order;
435
+ const renderMetadataComponents = () => {
436
+ return metadataOrder.map((component) => {
437
+ switch (component) {
438
+ case "title" /* title */:
439
+ return /* @__PURE__ */ jsx("h1", { className: thorium_web_audioMetadata_default.audioMetadataTitle, children: title }, "title");
440
+ case "titleWithSubtitle" /* titleWithSubtitle */:
441
+ return /* @__PURE__ */ jsxs("hgroup", { children: [
442
+ /* @__PURE__ */ jsx("h1", { className: thorium_web_audioMetadata_default.audioMetadataTitle, children: title }),
443
+ subtitle && /* @__PURE__ */ jsx("p", { className: thorium_web_audioMetadata_default.audioMetadataSubtitle, children: subtitle })
444
+ ] }, "title-with-subtitle");
445
+ case "subtitleWithTitle" /* subtitleWithTitle */:
446
+ return /* @__PURE__ */ jsxs("hgroup", { children: [
447
+ subtitle && /* @__PURE__ */ jsx("p", { className: thorium_web_audioMetadata_default.audioMetadataSubtitle, children: subtitle }),
448
+ /* @__PURE__ */ jsx("h1", { className: thorium_web_audioMetadata_default.audioMetadataTitle, children: title })
449
+ ] }, "subtitle-with-title");
450
+ case "authors" /* authors */:
451
+ return authors && authors.length > 0 ? /* @__PURE__ */ jsx("p", { className: thorium_web_audioMetadata_default.audioMetadataAuthors, children: authors.join(", ") }, "authors") : null;
452
+ default:
453
+ return null;
454
+ }
455
+ }).filter(Boolean);
456
+ };
457
+ return /* @__PURE__ */ jsx("header", { className: thorium_web_audioMetadata_default.audioMetadata, children: renderMetadataComponents() });
458
+ }
459
+ var useAudioStatelessCache = (volume, playbackRate, preservePitch, skipBackwardInterval, skipForwardInterval, skipInterval, pollInterval, autoPlay, enableMediaSession, sleepTimerOnTrackEnd, sleepTimerOnFragmentEnd, adjacentTimelineItems) => {
460
+ const settingsCache = useAudioSettingsCache(
461
+ volume,
462
+ playbackRate,
463
+ preservePitch,
464
+ skipBackwardInterval,
465
+ skipForwardInterval,
466
+ skipInterval,
467
+ pollInterval,
468
+ autoPlay,
469
+ enableMediaSession
470
+ );
471
+ const cache = useRef({
472
+ settings: settingsCache.current.settings,
473
+ sleepTimerOnTrackEnd,
474
+ sleepTimerOnFragmentEnd,
475
+ adjacentTimelineItems
476
+ });
477
+ cache.current.settings = settingsCache.current.settings;
478
+ cache.current.sleepTimerOnTrackEnd = sleepTimerOnTrackEnd;
479
+ cache.current.sleepTimerOnFragmentEnd = sleepTimerOnFragmentEnd;
480
+ cache.current.adjacentTimelineItems = adjacentTimelineItems;
481
+ return cache;
482
+ };
483
+ var useAudioPreferencesConfig = ({
484
+ settings,
485
+ preferences
486
+ }) => {
487
+ const audioPreferences = useMemo(() => {
488
+ const isSkipIntervalMode = "skipInterval" /* skipInterval */ in preferences.settings.keys;
489
+ return {
490
+ volume: settings.volume,
491
+ playbackRate: settings.playbackRate,
492
+ preservePitch: settings.preservePitch,
493
+ skipBackwardInterval: isSkipIntervalMode ? settings.skipInterval : settings.skipBackwardInterval,
494
+ skipForwardInterval: isSkipIntervalMode ? settings.skipInterval : settings.skipForwardInterval,
495
+ pollInterval: settings.pollInterval,
496
+ autoPlay: settings.autoPlay,
497
+ enableMediaSession: settings.enableMediaSession
498
+ };
499
+ }, [settings, preferences.settings.keys]);
500
+ const audioDefaults = useMemo(() => {
501
+ return {
502
+ volume: 1,
503
+ playbackRate: 1,
504
+ preservePitch: true,
505
+ skipBackwardInterval: 10,
506
+ skipForwardInterval: 10,
507
+ pollInterval: 1e3,
508
+ autoPlay: false,
509
+ enableMediaSession: true
510
+ };
511
+ }, []);
512
+ return { audioPreferences, audioDefaults };
513
+ };
514
+
515
+ // src/components/Audio/Hooks/useAudioPlayerInit.ts
516
+ var useAudioPlayerInit = ({
517
+ publication,
518
+ initialPosition,
519
+ listeners,
520
+ preferences,
521
+ cache,
522
+ contentProtectionConfig,
523
+ onNavigatorReady,
524
+ onNavigatorLoaded,
525
+ onCleanup
526
+ }) => {
527
+ const [navigatorReady, setNavigatorReady] = useState(false);
528
+ const { audioPreferences, audioDefaults } = useAudioPreferencesConfig({
529
+ settings: cache.current.settings,
530
+ preferences
531
+ });
532
+ const handleCleanup = useCallback(() => {
533
+ onCleanup?.();
534
+ }, [onCleanup]);
535
+ const { AudioNavigatorLoad, AudioNavigatorDestroy } = useAudioNavigator();
536
+ const isNavigatorLoadedAudio = useRef(false);
537
+ useEffect(() => {
538
+ if (!publication || isNavigatorLoadedAudio.current) return;
539
+ const config = {
540
+ publication,
541
+ listeners,
542
+ initialPosition: initialPosition ? new Locator({
543
+ ...initialPosition,
544
+ locations: initialPosition.locations ? new LocatorLocations(initialPosition.locations) : void 0
545
+ }) : void 0,
546
+ preferences: audioPreferences,
547
+ defaults: audioDefaults,
548
+ contentProtection: contentProtectionConfig
549
+ };
550
+ isNavigatorLoadedAudio.current = true;
551
+ onNavigatorReady?.();
552
+ AudioNavigatorLoad(config, () => {
553
+ setNavigatorReady(true);
554
+ onNavigatorLoaded?.();
555
+ });
556
+ return () => {
557
+ if (isNavigatorLoadedAudio.current) {
558
+ setNavigatorReady(false);
559
+ AudioNavigatorDestroy(() => {
560
+ isNavigatorLoadedAudio.current = false;
561
+ handleCleanup();
562
+ });
563
+ }
564
+ };
565
+ }, []);
566
+ return {
567
+ navigatorReady
568
+ };
569
+ };
570
+
571
+ // src/helpers/browser.ts
572
+ var isWebKit = typeof navigator !== "undefined" && /webkit/i.test(navigator.userAgent) && !/chrome/i.test(navigator.userAgent);
573
+ var StatefulPlayer = ({
574
+ publication,
575
+ localDataKey,
576
+ plugins,
577
+ positionStorage,
578
+ coverUrl
579
+ }) => {
580
+ const [pluginsRegistered, setPluginsRegistered] = useState(false);
581
+ useLayoutEffect(() => {
582
+ if (plugins && plugins.length > 0) {
583
+ plugins.forEach((plugin) => {
584
+ ThPluginRegistry.register(plugin);
585
+ });
586
+ } else {
587
+ ThPluginRegistry.register(createAudioDefaultPlugin());
588
+ }
589
+ setPluginsRegistered(true);
590
+ }, [plugins]);
591
+ if (!pluginsRegistered) {
592
+ return null;
593
+ }
594
+ return /* @__PURE__ */ jsx(ThPluginProvider, { children: /* @__PURE__ */ jsx(StatefulPlayerInner, { publication, localDataKey, positionStorage, coverUrl }) });
595
+ };
596
+ var StatefulPlayerInner = ({ publication, localDataKey, positionStorage, coverUrl }) => {
597
+ const { preferences } = useAudioPreferences();
598
+ const { t } = useI18n();
599
+ const wrapperRef = useRef(null);
600
+ const coverSectionRef = useRef(null);
601
+ const compactMinHeight = useRef(0);
602
+ const [isExpanded, setIsExpanded] = useState(false);
603
+ const sleepOnTrackEnd = useAppSelector((state) => state.player.sleepTimer.onTrackEnd);
604
+ const sleepOnFragmentEnd = useAppSelector((state) => state.player.sleepTimer.onFragmentEnd);
605
+ const adjacentTimelineItems = useAppSelector((state) => state.publication.adjacentTimelineItems);
606
+ const volume = useAppSelector((state) => state.audioSettings.volume);
607
+ const playbackRate = useAppSelector((state) => state.audioSettings.playbackRate);
608
+ const preservePitch = useAppSelector((state) => state.audioSettings.preservePitch);
609
+ const skipBackwardInterval = useAppSelector((state) => state.audioSettings.skipBackwardInterval);
610
+ const skipForwardInterval = useAppSelector((state) => state.audioSettings.skipForwardInterval);
611
+ const skipInterval = useAppSelector((state) => state.audioSettings.skipInterval);
612
+ const pollInterval = useAppSelector((state) => state.audioSettings.pollInterval);
613
+ const autoPlay = useAppSelector((state) => state.audioSettings.autoPlay);
614
+ const enableMediaSession = useAppSelector((state) => state.audioSettings.enableMediaSession);
615
+ const cache = useAudioStatelessCache(
616
+ volume,
617
+ playbackRate,
618
+ preservePitch,
619
+ skipBackwardInterval,
620
+ skipForwardInterval,
621
+ skipInterval,
622
+ pollInterval,
623
+ autoPlay,
624
+ enableMediaSession,
625
+ sleepOnTrackEnd,
626
+ sleepOnFragmentEnd,
627
+ adjacentTimelineItems
628
+ );
629
+ const dispatch = useAppDispatch();
630
+ const audioNavigator = useAudioNavigator();
631
+ const { canGoBackward, canGoForward, submitPreferences, pause, isPlaying } = audioNavigator;
632
+ const { setLocalData, getLocalData } = usePositionStorage(localDataKey, positionStorage);
633
+ const documentTitle = publication?.metadata?.title?.getTranslation("en");
634
+ useDocumentTitle(documentTitle);
635
+ const tocTree = useAppSelector((state) => state.publication.unstableTimeline?.toc?.tree);
636
+ const tocTreeRef = useRef(void 0);
637
+ useEffect(() => {
638
+ tocTreeRef.current = tocTree;
639
+ }, [tocTree]);
640
+ const handleTimelineNavigation = useCallback((item) => {
641
+ const tl = publication.timeline;
642
+ const link = tl.linkFor(item);
643
+ if (link) {
644
+ const matched = findTocItemByHref(tocTreeRef.current || [], link.href);
645
+ dispatch(setTocEntry(matched || null));
646
+ }
647
+ const { previous, next } = tl.adjacentTo(item);
648
+ dispatch(setAdjacentTimelineItems({
649
+ previous: previous ? { title: previous.title, href: tl.linkFor(previous)?.href ?? "" } : null,
650
+ next: next ? { title: next.title, href: tl.linkFor(next)?.href ?? "" } : null
651
+ }));
652
+ return { previous, next };
653
+ }, [dispatch, publication]);
654
+ const isFragmentAffordance = useCallback((affordance) => {
655
+ return affordance === "timeline" || affordance === "toc";
656
+ }, []);
657
+ const handleSleepTimerEndOfFragment = useCallback((isTransitionToNext) => {
658
+ if (!cache.current.sleepTimerOnFragmentEnd || !isTransitionToNext) return;
659
+ const nextAffordance = preferences.affordances.next;
660
+ if (isFragmentAffordance(nextAffordance)) {
661
+ pause();
662
+ dispatch(setSleepTimerOnFragmentEnd(false));
663
+ }
664
+ }, [cache, preferences.affordances.next, isFragmentAffordance, pause, dispatch]);
665
+ const handleContinuousPlay = useCallback((isTransitionToNext) => {
666
+ if (!cache.current.settings.autoPlay && isTransitionToNext) {
667
+ if (isFragmentAffordance(preferences.affordances.next)) {
668
+ pause();
669
+ }
670
+ }
671
+ }, [cache, preferences.affordances.next, isFragmentAffordance, pause]);
672
+ const listeners = useMemo(() => ({
673
+ timelineItemChanged: (item) => {
674
+ if (!item) {
675
+ dispatch(setTocEntry(null));
676
+ dispatch(setAdjacentTimelineItems({ previous: null, next: null }));
677
+ return;
678
+ }
679
+ const previousNextItem = cache.current.adjacentTimelineItems.next;
680
+ const currentItemHref = publication.timeline.linkFor(item)?.href ?? "";
681
+ handleTimelineNavigation(item);
682
+ const isTransitionToNext = previousNextItem !== null && previousNextItem.href === currentItemHref;
683
+ handleSleepTimerEndOfFragment(isTransitionToNext);
684
+ handleContinuousPlay(isTransitionToNext);
685
+ },
686
+ positionChanged: (locator) => {
687
+ setLocalData(locator);
688
+ if (canGoBackward()) {
689
+ dispatch(setPublicationStart(false));
690
+ } else {
691
+ dispatch(setPublicationStart(true));
692
+ }
693
+ if (canGoForward()) {
694
+ dispatch(setPublicationEnd(false));
695
+ } else {
696
+ dispatch(setPublicationEnd(true));
697
+ }
698
+ },
699
+ trackLoaded: () => {
700
+ dispatch(setTrackReady(true));
701
+ dispatch(setStalled(false));
702
+ dispatch(setStatus(isPlaying() ? "playing" : "paused"));
703
+ },
704
+ trackEnded: () => {
705
+ if (cache.current.sleepTimerOnTrackEnd) {
706
+ submitPreferences({ autoPlay: false });
707
+ }
708
+ if (cache.current.sleepTimerOnFragmentEnd) {
709
+ submitPreferences({ autoPlay: false });
710
+ dispatch(setSleepTimerOnFragmentEnd(false));
711
+ }
712
+ },
713
+ metadataLoaded: () => {
714
+ },
715
+ play: () => {
716
+ if (cache.current.sleepTimerOnTrackEnd) {
717
+ submitPreferences({ autoPlay: cache.current.settings.autoPlay });
718
+ dispatch(setSleepTimerOnTrackEnd(false));
719
+ }
720
+ dispatch(setStatus("playing"));
721
+ },
722
+ pause: () => {
723
+ dispatch(setStatus("paused"));
724
+ },
725
+ stalled: (isStalled) => {
726
+ dispatch(setStalled(isStalled));
727
+ },
728
+ seeking: (isSeeking) => {
729
+ dispatch(setSeeking(isSeeking));
730
+ },
731
+ seekable: (timeRanges) => {
732
+ const ranges = [];
733
+ for (let i = 0; i < timeRanges.length; i++) {
734
+ ranges.push({ start: timeRanges.start(i), end: timeRanges.end(i) });
735
+ }
736
+ dispatch(setSeekableRanges(ranges));
737
+ },
738
+ error: (error, locator) => {
739
+ console.error("[AudioNavigator] playback error", error, locator);
740
+ dispatch(setStatus("paused"));
741
+ },
742
+ remotePlaybackStateChanged: (state) => {
743
+ if (isWebKit) return;
744
+ dispatch(setRemotePlaybackState(state));
745
+ },
746
+ contentProtection: (_type, _detail) => {
747
+ },
748
+ peripheral: (_data) => {
749
+ },
750
+ contextMenu: (_data) => {
751
+ }
752
+ }), [setLocalData, canGoBackward, canGoForward, isPlaying, dispatch, cache, submitPreferences, publication, handleTimelineNavigation, handleSleepTimerEndOfFragment, handleContinuousPlay]);
753
+ const initialPosition = useMemo(() => getLocalData(), [getLocalData]);
754
+ useAudioPlayerInit({
755
+ publication,
756
+ initialPosition,
757
+ listeners,
758
+ preferences,
759
+ cache,
760
+ contentProtectionConfig: resolveAudioContentProtectionConfig(preferences.contentProtection, t),
761
+ onNavigatorLoaded: () => dispatch(setLoading(false))
762
+ });
763
+ const { compact, expanded } = preferences.theming.layout;
764
+ const renderPlayerComponent = useCallback((component) => {
765
+ switch (component) {
766
+ case "cover" /* cover */:
767
+ return /* @__PURE__ */ jsx(StatefulAudioCover, { ref: coverSectionRef, coverUrl, title: publication?.metadata?.title?.getTranslation("en") }, component);
768
+ case "metadata" /* metadata */:
769
+ return publication ? /* @__PURE__ */ jsx(StatefulAudioMetadata, { publication }, component) : null;
770
+ case "playbackControls" /* playbackControls */:
771
+ return /* @__PURE__ */ jsx(StatefulAudioPlaybackControls, {}, component);
772
+ case "progressBar" /* progressBar */:
773
+ return /* @__PURE__ */ jsx(StatefulAudioProgressBar, {}, component);
774
+ case "mediaActions" /* mediaActions */:
775
+ return /* @__PURE__ */ jsx(StatefulAudioMediaActions, {}, component);
776
+ }
777
+ }, [coverUrl, publication]);
778
+ const renderCompactComponents = useCallback(() => {
779
+ const coverIdx = compact.order.indexOf("cover" /* cover */);
780
+ const metaIdx = compact.order.indexOf("metadata" /* metadata */);
781
+ const adjacent = coverIdx !== -1 && metaIdx !== -1 && Math.abs(coverIdx - metaIdx) === 1;
782
+ if (!adjacent) {
783
+ return compact.order.map(renderPlayerComponent);
784
+ }
785
+ const groupStart = Math.min(coverIdx, metaIdx);
786
+ const nodes = [];
787
+ for (let i = 0; i < compact.order.length; i++) {
788
+ if (i === groupStart) {
789
+ nodes.push(
790
+ /* @__PURE__ */ jsxs("div", { className: thorium_web_audioPlayer_default.coverMetadataGroup, children: [
791
+ renderPlayerComponent(compact.order[i]),
792
+ renderPlayerComponent(compact.order[i + 1])
793
+ ] }, "cover-metadata-group")
794
+ );
795
+ i++;
796
+ } else {
797
+ nodes.push(renderPlayerComponent(compact.order[i]));
798
+ }
799
+ }
800
+ return nodes;
801
+ }, [compact.order, renderPlayerComponent]);
802
+ useEffect(() => {
803
+ const el = wrapperRef.current;
804
+ if (!el) return;
805
+ const check = debounce(() => {
806
+ if (!isExpanded) {
807
+ const overflow = el.scrollHeight - el.clientHeight;
808
+ if (overflow > 0) {
809
+ const coverEl = coverSectionRef.current;
810
+ if (coverEl) {
811
+ const minHeight = parseFloat(getComputedStyle(coverEl).minHeight) || 0;
812
+ const newMaxHeight = coverEl.clientHeight - overflow;
813
+ if (newMaxHeight >= minHeight) {
814
+ el.style.setProperty("--th-layout-constraints-cover", `${newMaxHeight}px`);
815
+ return;
816
+ }
817
+ }
818
+ el.style.removeProperty("--th-layout-constraints-cover");
819
+ compactMinHeight.current = el.scrollHeight;
820
+ setIsExpanded(true);
821
+ } else {
822
+ el.style.removeProperty("--th-layout-constraints-cover");
823
+ }
824
+ } else {
825
+ if (el.clientHeight > compactMinHeight.current) {
826
+ setIsExpanded(false);
827
+ }
828
+ }
829
+ }, 100);
830
+ const observer = new ResizeObserver(check);
831
+ observer.observe(el);
832
+ return () => {
833
+ check.clear();
834
+ observer.disconnect();
835
+ };
836
+ }, [isExpanded]);
837
+ return /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsx(I18nProvider, { locale: preferences.locale, children: /* @__PURE__ */ jsx(NavigatorProvider, { mediaNavigator: audioNavigator, children: /* @__PURE__ */ jsx("main", { className: thorium_web_audio_app_default.main, children: /* @__PURE__ */ jsx(StatefulDockingWrapper, { children: /* @__PURE__ */ jsxs("div", { className: thorium_web_audio_app_default.shell, children: [
838
+ /* @__PURE__ */ jsx(
839
+ StatefulPlayerHeader,
840
+ {
841
+ actionKeys: preferences.actions.secondary.displayOrder,
842
+ actionsOrder: preferences.actions.secondary.displayOrder
843
+ }
844
+ ),
845
+ /* @__PURE__ */ jsx(
846
+ "article",
847
+ {
848
+ ref: wrapperRef,
849
+ className: isExpanded ? thorium_web_audioPlayer_default.audioPlayerWrapperExpanded : thorium_web_audioPlayer_default.audioPlayerWrapper,
850
+ "aria-label": t("reader.app.publicationWrapper"),
851
+ children: isExpanded ? /* @__PURE__ */ jsxs(Fragment, { children: [
852
+ /* @__PURE__ */ jsx("div", { className: thorium_web_audioPlayer_default.audioPlayerExpandedStart, children: expanded.start.map(renderPlayerComponent) }),
853
+ /* @__PURE__ */ jsx("div", { className: thorium_web_audioPlayer_default.audioPlayerExpandedEnd, children: expanded.end.map(renderPlayerComponent) })
854
+ ] }) : renderCompactComponents()
855
+ }
856
+ )
857
+ ] }) }) }) }) }) });
858
+ };
859
+
860
+ export { StatefulAudioMediaActions, StatefulAudioPlaybackControls, StatefulAudioProgressBar, StatefulNextButton, StatefulPlayPauseButton, StatefulPlayer, StatefulPreviousButton, StatefulSkipBackwardButton, StatefulSkipForwardButton };
861
+ //# sourceMappingURL=chunk-SAUOY37Q.mjs.map
862
+ //# sourceMappingURL=chunk-SAUOY37Q.mjs.map