@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
@@ -1,11 +1,7 @@
1
- import { propsToCSSVars } from './chunk-XVSFXHYB.mjs';
2
- import { useBreakpoints, useForcedColors, useMonochrome, useReducedMotion, useReducedTransparency } from './chunk-GFSLVQIG.mjs';
3
- import { useColorScheme, useContrast } from './chunk-NQ2ZSGCX.mjs';
4
1
  import { isSupportedLocale, supportedLocales } from './chunk-B3WDMWCT.mjs';
5
2
  import fontStacks from '@readium/css/css/vars/fontStacks.json';
6
3
  import ReadiumCSSColors from '@readium/css/css/vars/colors.json';
7
- import { createContext, useMemo, useState, useCallback, useEffect, useContext, useRef } from 'react';
8
- import { jsx } from 'react/jsx-runtime';
4
+ import { createContext, useContext } from 'react';
9
5
 
10
6
  // src/preferences/models/actions.ts
11
7
  var ThActionsKeys = /* @__PURE__ */ ((ThActionsKeys3) => {
@@ -30,6 +26,8 @@ var ThDockingTypes = /* @__PURE__ */ ((ThDockingTypes2) => {
30
26
  })(ThDockingTypes || {});
31
27
  var ThSheetTypes = /* @__PURE__ */ ((ThSheetTypes3) => {
32
28
  ThSheetTypes3["popover"] = "popover";
29
+ ThSheetTypes3["compactPopover"] = "compactPopover";
30
+ ThSheetTypes3["modal"] = "modal";
33
31
  ThSheetTypes3["fullscreen"] = "fullscreen";
34
32
  ThSheetTypes3["dockedStart"] = "docked start";
35
33
  ThSheetTypes3["dockedEnd"] = "docked end";
@@ -108,123 +106,307 @@ var defaultJumpToPositionAction = {
108
106
  }
109
107
  };
110
108
 
111
- // src/preferences/helpers/buildThemeObject.ts
112
- var buildThemeObject = ({
113
- theme,
114
- themeKeys,
115
- systemThemes,
116
- colorScheme
117
- }) => {
118
- if (!theme) {
119
- return {};
120
- }
121
- if (theme === "auto" && colorScheme && systemThemes) {
122
- theme = colorScheme === "dark" /* dark */ ? systemThemes.dark : systemThemes.light;
123
- }
124
- let themeProps = {};
125
- const themeToken = themeKeys[theme];
126
- if (themeToken) {
127
- themeProps = {
128
- backgroundColor: themeToken.background,
129
- textColor: themeToken.text,
130
- linkColor: themeToken.link,
131
- selectionBackgroundColor: themeToken.select,
132
- selectionTextColor: themeToken.onSelect,
133
- visitedColor: themeToken.visited
134
- };
135
- } else {
136
- console.warn(`Theme key "${String(theme)}" not found in themeKeys.`);
137
- themeProps = {
138
- backgroundColor: null,
139
- textColor: null,
140
- linkColor: null,
141
- selectionBackgroundColor: null,
142
- selectionTextColor: null,
143
- visitedColor: null
144
- };
109
+ // src/preferences/models/settings.ts
110
+ var ThSettingsKeys = /* @__PURE__ */ ((ThSettingsKeys2) => {
111
+ ThSettingsKeys2["columns"] = "columns";
112
+ ThSettingsKeys2["fontFamily"] = "fontFamily";
113
+ ThSettingsKeys2["fontWeight"] = "fontWeight";
114
+ ThSettingsKeys2["hyphens"] = "hyphens";
115
+ ThSettingsKeys2["layout"] = "layout";
116
+ ThSettingsKeys2["letterSpacing"] = "letterSpacing";
117
+ ThSettingsKeys2["lineHeight"] = "lineHeight";
118
+ ThSettingsKeys2["paragraphIndent"] = "paragraphIndent";
119
+ ThSettingsKeys2["paragraphSpacing"] = "paragraphSpacing";
120
+ ThSettingsKeys2["publisherStyles"] = "publisherStyles";
121
+ ThSettingsKeys2["spacingGroup"] = "spacingGroup";
122
+ ThSettingsKeys2["spacingPresets"] = "spacingPresets";
123
+ ThSettingsKeys2["textAlign"] = "textAlign";
124
+ ThSettingsKeys2["textGroup"] = "textGroup";
125
+ ThSettingsKeys2["textNormalize"] = "textNormalize";
126
+ ThSettingsKeys2["theme"] = "theme";
127
+ ThSettingsKeys2["wordSpacing"] = "wordSpacing";
128
+ ThSettingsKeys2["zoom"] = "zoom";
129
+ return ThSettingsKeys2;
130
+ })(ThSettingsKeys || {});
131
+ var ThTextSettingsKeys = /* @__PURE__ */ ((ThTextSettingsKeys3) => {
132
+ ThTextSettingsKeys3["fontFamily"] = "fontFamily";
133
+ ThTextSettingsKeys3["fontWeight"] = "fontWeight";
134
+ ThTextSettingsKeys3["hyphens"] = "hyphens";
135
+ ThTextSettingsKeys3["textAlign"] = "textAlign";
136
+ ThTextSettingsKeys3["textNormalize"] = "textNormalize";
137
+ return ThTextSettingsKeys3;
138
+ })(ThTextSettingsKeys || {});
139
+ var ThSpacingSettingsKeys = /* @__PURE__ */ ((ThSpacingSettingsKeys3) => {
140
+ ThSpacingSettingsKeys3["letterSpacing"] = "letterSpacing";
141
+ ThSpacingSettingsKeys3["lineHeight"] = "lineHeight";
142
+ ThSpacingSettingsKeys3["paragraphIndent"] = "paragraphIndent";
143
+ ThSpacingSettingsKeys3["paragraphSpacing"] = "paragraphSpacing";
144
+ ThSpacingSettingsKeys3["publisherStyles"] = "publisherStyles";
145
+ ThSpacingSettingsKeys3["spacingPresets"] = "spacingPresets";
146
+ ThSpacingSettingsKeys3["wordSpacing"] = "wordSpacing";
147
+ return ThSpacingSettingsKeys3;
148
+ })(ThSpacingSettingsKeys || {});
149
+ var ThSettingsContainerKeys = /* @__PURE__ */ ((ThSettingsContainerKeys2) => {
150
+ ThSettingsContainerKeys2["initial"] = "initial";
151
+ ThSettingsContainerKeys2["text"] = "text";
152
+ ThSettingsContainerKeys2["spacing"] = "spacing";
153
+ return ThSettingsContainerKeys2;
154
+ })(ThSettingsContainerKeys || {});
155
+ var ThSettingsRangeVariant = /* @__PURE__ */ ((ThSettingsRangeVariant2) => {
156
+ ThSettingsRangeVariant2["slider"] = "slider";
157
+ ThSettingsRangeVariant2["incrementedSlider"] = "incrementedSlider";
158
+ ThSettingsRangeVariant2["numberField"] = "numberField";
159
+ ThSettingsRangeVariant2["sliderWithPresets"] = "sliderWithPresets";
160
+ ThSettingsRangeVariant2["presetsGroup"] = "presetsGroup";
161
+ return ThSettingsRangeVariant2;
162
+ })(ThSettingsRangeVariant || {});
163
+ var ThSettingsRangePlaceholder = /* @__PURE__ */ ((ThSettingsRangePlaceholder2) => {
164
+ ThSettingsRangePlaceholder2["range"] = "range";
165
+ ThSettingsRangePlaceholder2["none"] = "none";
166
+ return ThSettingsRangePlaceholder2;
167
+ })(ThSettingsRangePlaceholder || {});
168
+ var ThSpacingPresetKeys = /* @__PURE__ */ ((ThSpacingPresetKeys3) => {
169
+ ThSpacingPresetKeys3["publisher"] = "publisher";
170
+ ThSpacingPresetKeys3["tight"] = "tight";
171
+ ThSpacingPresetKeys3["balanced"] = "balanced";
172
+ ThSpacingPresetKeys3["loose"] = "loose";
173
+ ThSpacingPresetKeys3["accessible"] = "accessible";
174
+ ThSpacingPresetKeys3["custom"] = "custom";
175
+ return ThSpacingPresetKeys3;
176
+ })(ThSpacingPresetKeys || {});
177
+ var ThLayoutOptions = /* @__PURE__ */ ((ThLayoutOptions2) => {
178
+ ThLayoutOptions2["scroll"] = "scroll_option";
179
+ ThLayoutOptions2["paginated"] = "page_option";
180
+ return ThLayoutOptions2;
181
+ })(ThLayoutOptions || {});
182
+ var ThTextAlignOptions = /* @__PURE__ */ ((ThTextAlignOptions2) => {
183
+ ThTextAlignOptions2["publisher"] = "publisher";
184
+ ThTextAlignOptions2["start"] = "start";
185
+ ThTextAlignOptions2["justify"] = "justify";
186
+ return ThTextAlignOptions2;
187
+ })(ThTextAlignOptions || {});
188
+ var ThLineHeightOptions = /* @__PURE__ */ ((ThLineHeightOptions3) => {
189
+ ThLineHeightOptions3["publisher"] = "publisher";
190
+ ThLineHeightOptions3["small"] = "small";
191
+ ThLineHeightOptions3["medium"] = "medium";
192
+ ThLineHeightOptions3["large"] = "large";
193
+ return ThLineHeightOptions3;
194
+ })(ThLineHeightOptions || {});
195
+ var defaultTextSettingsMain = ["fontFamily" /* fontFamily */];
196
+ var defaultTextSettingsSubpanel = [
197
+ "fontFamily" /* fontFamily */,
198
+ "textAlign" /* textAlign */,
199
+ "hyphens" /* hyphens */,
200
+ "fontWeight" /* fontWeight */,
201
+ "textNormalize" /* textNormalize */
202
+ ];
203
+ var defaultSpacingSettingsMain = [
204
+ "spacingPresets" /* spacingPresets */
205
+ ];
206
+ var defaultSpacingSettingsSubpanel = [
207
+ "spacingPresets" /* spacingPresets */,
208
+ "lineHeight" /* lineHeight */,
209
+ "paragraphSpacing" /* paragraphSpacing */,
210
+ "paragraphIndent" /* paragraphIndent */,
211
+ "wordSpacing" /* wordSpacing */,
212
+ "letterSpacing" /* letterSpacing */
213
+ ];
214
+ var defaultSpacingPresetsOrder = [
215
+ "publisher" /* publisher */,
216
+ "accessible" /* accessible */,
217
+ "custom" /* custom */,
218
+ "tight" /* tight */,
219
+ "balanced" /* balanced */,
220
+ "loose" /* loose */
221
+ ];
222
+ var defaultParagraphSpacing = {
223
+ variant: "numberField" /* numberField */,
224
+ placeholder: "range" /* range */,
225
+ range: [0, 3],
226
+ step: 0.25
227
+ };
228
+ var defaultParagraphIndent = {
229
+ variant: "numberField" /* numberField */,
230
+ placeholder: "range" /* range */,
231
+ range: [0, 2],
232
+ step: 0.25
233
+ };
234
+ var defaultWordSpacing = {
235
+ variant: "numberField" /* numberField */,
236
+ placeholder: "range" /* range */,
237
+ range: [0, 1],
238
+ step: 0.1
239
+ };
240
+ var defaultLetterSpacing = {
241
+ variant: "numberField" /* numberField */,
242
+ placeholder: "range" /* range */,
243
+ range: [0, 0.5],
244
+ step: 0.05
245
+ };
246
+ var defaultLineHeights = {
247
+ ["small" /* small */]: 1.35,
248
+ ["medium" /* medium */]: 1.5,
249
+ ["large" /* large */]: 1.75
250
+ };
251
+ var defaultZoom = {
252
+ variant: "numberField" /* numberField */,
253
+ placeholder: "range" /* range */,
254
+ range: [0.7, 4],
255
+ step: 0.05
256
+ };
257
+ var defaultSpacingPresets = {
258
+ ["tight" /* tight */]: {
259
+ ["lineHeight" /* lineHeight */]: "small" /* small */,
260
+ ["paragraphSpacing" /* paragraphSpacing */]: 0.25,
261
+ ["paragraphIndent" /* paragraphIndent */]: 1
262
+ },
263
+ ["balanced" /* balanced */]: {
264
+ ["lineHeight" /* lineHeight */]: "medium" /* medium */,
265
+ ["paragraphSpacing" /* paragraphSpacing */]: 1,
266
+ ["paragraphIndent" /* paragraphIndent */]: 1
267
+ },
268
+ ["loose" /* loose */]: {
269
+ ["lineHeight" /* lineHeight */]: "large" /* large */,
270
+ ["paragraphSpacing" /* paragraphSpacing */]: 1.5,
271
+ ["paragraphIndent" /* paragraphIndent */]: 1
272
+ },
273
+ ["accessible" /* accessible */]: {
274
+ ["lineHeight" /* lineHeight */]: "large" /* large */,
275
+ ["paragraphSpacing" /* paragraphSpacing */]: 2.5,
276
+ ["paragraphIndent" /* paragraphIndent */]: 1,
277
+ ["letterSpacing" /* letterSpacing */]: 0.1,
278
+ ["wordSpacing" /* wordSpacing */]: 0.3
145
279
  }
146
- return themeProps;
147
280
  };
148
281
 
149
- // src/preferences/helpers/fontPref/bunnyFonts.ts
150
- var DEFAULT_FALLBACK = "sans-serif";
151
- var createDefinitionsFromBunnyFonts = (params) => {
152
- const { cssUrl, options } = params;
153
- const { fallbacks, order, labels } = options || {};
154
- const processedUrl = cssUrl.includes("@import") ? cssUrl.match(/@import\s+url\(['"]?([^'")]+)['"]?\)/i)?.[1] || cssUrl : cssUrl.includes("href=") ? cssUrl.match(/href=["']([^"']+)["']/)?.[1] || cssUrl : cssUrl;
155
- const url = new URL(processedUrl);
156
- if (!url.hostname.includes("fonts.bunny.net")) {
157
- throw new Error("Invalid Bunny Fonts URL");
158
- }
159
- const familyParam = url.searchParams.get("family");
160
- if (!familyParam) {
161
- throw new Error("No family parameter found in Bunny Fonts URL");
162
- }
163
- const fontEntries = familyParam.split("|").map((familyStr) => {
164
- const [familyName, weightsStr = ""] = familyStr.split(":");
165
- if (!familyName) {
166
- throw new Error(`Invalid font family format: ${familyStr}`);
282
+ // src/preferences/models/audio.ts
283
+ var ThAudioActionKeys = /* @__PURE__ */ ((ThAudioActionKeys2) => {
284
+ ThAudioActionKeys2["toc"] = "audio.toc";
285
+ ThAudioActionKeys2["volume"] = "audio.volume";
286
+ ThAudioActionKeys2["playbackRate"] = "audio.playbackRate";
287
+ ThAudioActionKeys2["sleepTimer"] = "audio.sleepTimer";
288
+ ThAudioActionKeys2["remotePlayback"] = "audio.remotePlayback";
289
+ return ThAudioActionKeys2;
290
+ })(ThAudioActionKeys || {});
291
+ var ThAudioKeys = /* @__PURE__ */ ((ThAudioKeys2) => {
292
+ ThAudioKeys2["theme"] = "theme";
293
+ ThAudioKeys2["volume"] = "volume";
294
+ ThAudioKeys2["playbackRate"] = "playbackRate";
295
+ ThAudioKeys2["skipBackwardInterval"] = "skipBackwardInterval";
296
+ ThAudioKeys2["skipForwardInterval"] = "skipForwardInterval";
297
+ ThAudioKeys2["skipInterval"] = "skipInterval";
298
+ ThAudioKeys2["autoPlay"] = "autoPlay";
299
+ ThAudioKeys2["sleepTimer"] = "sleepTimer";
300
+ return ThAudioKeys2;
301
+ })(ThAudioKeys || {});
302
+ var ThSettingsTimerVariant = /* @__PURE__ */ ((ThSettingsTimerVariant2) => {
303
+ ThSettingsTimerVariant2["presetList"] = "presetList";
304
+ ThSettingsTimerVariant2["durationField"] = "durationField";
305
+ return ThSettingsTimerVariant2;
306
+ })(ThSettingsTimerVariant || {});
307
+ var defaultAudioVolume = {
308
+ variant: "slider" /* slider */,
309
+ range: [0, 1],
310
+ step: 0.1,
311
+ placeholder: "range" /* range */
312
+ };
313
+ var defaultAudioPlaybackRate = {
314
+ variant: "sliderWithPresets" /* sliderWithPresets */,
315
+ range: [0.5, 4],
316
+ step: 0.05,
317
+ placeholder: "range" /* range */,
318
+ presets: [0.75, 1, 1.25, 1.5, 1.75, 2]
319
+ };
320
+ var defaultAudioSkipBackwardInterval = {
321
+ variant: "presetsGroup" /* presetsGroup */,
322
+ range: [5, 60],
323
+ step: 5,
324
+ placeholder: "range" /* range */,
325
+ presets: [5, 10, 30]
326
+ };
327
+ var defaultAudioSkipForwardInterval = {
328
+ variant: "presetsGroup" /* presetsGroup */,
329
+ range: [5, 60],
330
+ step: 5,
331
+ placeholder: "range" /* range */,
332
+ presets: [5, 10, 30]
333
+ };
334
+ var defaultAudioSkipInterval = {
335
+ variant: "presetsGroup" /* presetsGroup */,
336
+ range: [5, 60],
337
+ step: 5,
338
+ placeholder: "range" /* range */,
339
+ presets: [5, 10, 30]
340
+ };
341
+ var defaultAudioSleepTimer = {
342
+ variant: "durationField" /* durationField */,
343
+ maxHours: 23
344
+ };
345
+ var defaultAudioSleepTimerPresetList = {
346
+ variant: "presetList" /* presetList */,
347
+ presets: [15, 30, 45, 60, 90, "endOfFragment", "endOfResource"]
348
+ };
349
+ var defaultAudioVolumeAction = {
350
+ visibility: "always" /* always */,
351
+ shortcut: null,
352
+ sheet: {
353
+ defaultSheet: "compactPopover" /* compactPopover */,
354
+ breakpoints: {}
355
+ },
356
+ docked: { dockable: "none" /* none */ }
357
+ };
358
+ var defaultAudioPlaybackRateAction = {
359
+ visibility: "always" /* always */,
360
+ shortcut: null,
361
+ sheet: {
362
+ defaultSheet: "compactPopover" /* compactPopover */,
363
+ breakpoints: { ["compact" /* compact */]: "bottomSheet" /* bottomSheet */ }
364
+ },
365
+ snapped: {
366
+ minHeight: "content-height"
367
+ },
368
+ docked: { dockable: "none" /* none */ }
369
+ };
370
+ var defaultAudioSleepTimerAction = {
371
+ visibility: "partially" /* partially */,
372
+ shortcut: null,
373
+ sheet: {
374
+ defaultSheet: "modal" /* modal */,
375
+ breakpoints: {
376
+ ["compact" /* compact */]: "bottomSheet" /* bottomSheet */,
377
+ ["medium" /* medium */]: "bottomSheet" /* bottomSheet */
167
378
  }
168
- const weightStyles = /* @__PURE__ */ new Map();
169
- if (weightsStr) {
170
- weightsStr.split(",").forEach((weightStr) => {
171
- const isItalic = weightStr.endsWith("i");
172
- const weightValue = parseInt(isItalic ? weightStr.slice(0, -1) : weightStr, 10);
173
- if (!isNaN(weightValue)) {
174
- if (!weightStyles.has(weightValue)) {
175
- weightStyles.set(weightValue, /* @__PURE__ */ new Set());
176
- }
177
- weightStyles.get(weightValue)?.add(isItalic ? "italic" : "normal");
178
- }
179
- });
379
+ },
380
+ snapped: {
381
+ minHeight: "content-height"
382
+ },
383
+ docked: { dockable: "none" /* none */ }
384
+ };
385
+ var defaultAudioRemotePlaybackAction = {
386
+ visibility: "always" /* always */,
387
+ shortcut: null
388
+ };
389
+ var defaultAudioTocAction = {
390
+ visibility: "partially" /* partially */,
391
+ shortcut: null,
392
+ sheet: {
393
+ defaultSheet: "modal" /* modal */,
394
+ breakpoints: {
395
+ ["compact" /* compact */]: "fullscreen" /* fullscreen */,
396
+ ["medium" /* medium */]: "fullscreen" /* fullscreen */
180
397
  }
181
- const weights = Array.from(weightStyles.keys()).sort((a, b) => a - b);
182
- const hasItalic = Array.from(weightStyles.values()).some((styles2) => styles2.has("italic"));
183
- const styles = hasItalic ? ["normal", "italic"] : ["normal"];
184
- const fontId = familyName;
185
- const familyDisplayName = familyName.split("-").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
186
- return [
187
- fontId,
188
- {
189
- id: fontId,
190
- name: familyDisplayName,
191
- ...labels?.[fontId] && { label: labels[fontId] },
192
- source: {
193
- type: "custom",
194
- provider: "bunny"
195
- },
196
- spec: {
197
- family: familyDisplayName,
198
- fallbacks: fallbacks?.[fontId] || [DEFAULT_FALLBACK],
199
- weights: {
200
- type: "static",
201
- values: weights.length ? weights : [400]
202
- },
203
- styles
204
- }
205
- }
206
- ];
207
- });
208
- const result = Object.fromEntries(fontEntries);
209
- if (order && order.length > 0) {
210
- const orderedResult = {};
211
- order.forEach((fontId) => {
212
- if (result[fontId]) {
213
- orderedResult[fontId] = result[fontId];
214
- }
215
- });
216
- Object.entries(result).forEach(([fontId, definition]) => {
217
- if (!orderedResult[fontId]) {
218
- orderedResult[fontId] = definition;
219
- }
220
- });
221
- return orderedResult;
398
+ },
399
+ docked: {
400
+ dockable: "both" /* both */,
401
+ dragIndicator: false,
402
+ width: 360,
403
+ minWidth: 320,
404
+ maxWidth: 450
222
405
  }
223
- return result;
224
406
  };
225
407
 
226
408
  // src/preferences/helpers/fontPref/googleFonts.ts
227
- var DEFAULT_FALLBACK2 = "sans-serif";
409
+ var DEFAULT_FALLBACK = "sans-serif";
228
410
  var DEFAULT_WIDTH_STEP = 20;
229
411
  var DEFAULT_WEIGHT_STEP = 20;
230
412
  var createDefinitionsFromGoogleFonts = (params) => {
@@ -322,7 +504,7 @@ var createDefinitionsFromGoogleFonts = (params) => {
322
504
  source: { type: "custom", provider: "google" },
323
505
  spec: {
324
506
  family: family.name,
325
- fallbacks: fallbacks?.[fontId] || [DEFAULT_FALLBACK2],
507
+ fallbacks: fallbacks?.[fontId] || [DEFAULT_FALLBACK],
326
508
  weights: family.weights,
327
509
  styles: family.styles,
328
510
  ...family.widths && { widths: family.widths },
@@ -384,7 +566,31 @@ var createDefinitionFromStaticFonts = (params) => {
384
566
  };
385
567
  };
386
568
 
387
- // src/preferences/models/fonts.ts
569
+ // src/preferences/helpers/validateObjectKeys.ts
570
+ var validateObjectKeys = (orderArrays, keysObj, context, specialCase, fallback) => {
571
+ const allOrders = new Set(
572
+ orderArrays.flatMap((arr) => {
573
+ if (!specialCase) return arr;
574
+ return arr.filter((k) => {
575
+ if (Array.isArray(specialCase)) {
576
+ return !specialCase.includes(k);
577
+ } else {
578
+ return k !== specialCase;
579
+ }
580
+ });
581
+ })
582
+ );
583
+ const availableKeys = Object.keys(keysObj);
584
+ allOrders.forEach((key) => {
585
+ if (!availableKeys.includes(key)) {
586
+ if (fallback) keysObj[key] = fallback;
587
+ console.warn(
588
+ `Key "${key}" in ${context} order arrays not found in ${context}.keys.${fallback ? `
589
+ Using fallback: ${JSON.stringify(fallback)}` : ""}`
590
+ );
591
+ }
592
+ });
593
+ };
388
594
  var readiumCSSFontCollection = {
389
595
  oldStyle: {
390
596
  id: "oldStyle",
@@ -532,16 +738,44 @@ var resolveContentProtectionConfig = (contentProtection, t) => {
532
738
  protectCopy: contentProtection.protectCopy,
533
739
  disableContextMenu: contentProtection.disableContextMenu,
534
740
  disableDragAndDrop: contentProtection.disableDragAndDrop,
535
- protectPrinting: contentProtection.protectPrinting ? {
536
- disable: contentProtection.protectPrinting.disable,
741
+ protectPrinting: contentProtection.protectPrinting?.disable ? {
742
+ disable: true,
537
743
  watermark: resolvedWatermark
538
744
  } : void 0,
539
745
  disableSelectAll: contentProtection.disableSelectAll,
540
746
  disableSave: contentProtection.disableSave,
541
747
  monitorDevTools: contentProtection.monitorDevTools
748
+ // TODO: When we implement it in non-audio navigators, uncomment
749
+ // disableRemotePlayback: contentProtection.disableRemotePlayback
542
750
  };
543
751
  return resolved;
544
752
  };
753
+ var resolveAudioContentProtectionConfig = (contentProtection, t) => {
754
+ if (!contentProtection) return void 0;
755
+ let resolvedWatermark;
756
+ if (contentProtection.protectPrinting?.watermark) {
757
+ if (typeof contentProtection.protectPrinting.watermark === "object" && "key" in contentProtection.protectPrinting.watermark) {
758
+ resolvedWatermark = t(contentProtection.protectPrinting.watermark.key, {
759
+ defaultValue: contentProtection.protectPrinting.watermark.fallback
760
+ });
761
+ } else if (typeof contentProtection.protectPrinting.watermark === "string") {
762
+ resolvedWatermark = t(contentProtection.protectPrinting.watermark);
763
+ }
764
+ }
765
+ return {
766
+ protectCopy: contentProtection.protectCopy,
767
+ disableContextMenu: contentProtection.disableContextMenu,
768
+ disableDragAndDrop: contentProtection.disableDragAndDrop,
769
+ protectPrinting: contentProtection.protectPrinting?.disable ? {
770
+ disable: true,
771
+ watermark: resolvedWatermark
772
+ } : void 0,
773
+ disableSelectAll: contentProtection.disableSelectAll,
774
+ disableSave: contentProtection.disableSave,
775
+ monitorDevTools: contentProtection.monitorDevTools,
776
+ disableRemotePlayback: contentProtection.disableRemotePlayback
777
+ };
778
+ };
545
779
  var defaultContentProtectionConfig = {
546
780
  protectCopy: false,
547
781
  disableContextMenu: false,
@@ -554,187 +788,30 @@ var defaultContentProtectionConfig = {
554
788
  disableSave: false,
555
789
  monitorDevTools: false
556
790
  };
557
- var devContentProtectionConfig = {
791
+ var defaultAudioContentProtectionConfig = {
558
792
  protectCopy: false,
559
793
  disableContextMenu: false,
560
794
  disableDragAndDrop: false,
561
795
  protectPrinting: {
562
- disable: false
796
+ disable: false,
797
+ watermark: "reader.app.printingDisabled"
563
798
  },
564
799
  disableSelectAll: false,
565
800
  disableSave: false,
566
- monitorDevTools: false
567
- };
568
-
569
- // src/preferences/models/settings.ts
570
- var ThSettingsKeys = /* @__PURE__ */ ((ThSettingsKeys2) => {
571
- ThSettingsKeys2["columns"] = "columns";
572
- ThSettingsKeys2["fontFamily"] = "fontFamily";
573
- ThSettingsKeys2["fontWeight"] = "fontWeight";
574
- ThSettingsKeys2["hyphens"] = "hyphens";
575
- ThSettingsKeys2["layout"] = "layout";
576
- ThSettingsKeys2["letterSpacing"] = "letterSpacing";
577
- ThSettingsKeys2["lineHeight"] = "lineHeight";
578
- ThSettingsKeys2["paragraphIndent"] = "paragraphIndent";
579
- ThSettingsKeys2["paragraphSpacing"] = "paragraphSpacing";
580
- ThSettingsKeys2["publisherStyles"] = "publisherStyles";
581
- ThSettingsKeys2["spacingGroup"] = "spacingGroup";
582
- ThSettingsKeys2["spacingPresets"] = "spacingPresets";
583
- ThSettingsKeys2["textAlign"] = "textAlign";
584
- ThSettingsKeys2["textGroup"] = "textGroup";
585
- ThSettingsKeys2["textNormalize"] = "textNormalize";
586
- ThSettingsKeys2["theme"] = "theme";
587
- ThSettingsKeys2["wordSpacing"] = "wordSpacing";
588
- ThSettingsKeys2["zoom"] = "zoom";
589
- return ThSettingsKeys2;
590
- })(ThSettingsKeys || {});
591
- var ThTextSettingsKeys = /* @__PURE__ */ ((ThTextSettingsKeys3) => {
592
- ThTextSettingsKeys3["fontFamily"] = "fontFamily";
593
- ThTextSettingsKeys3["fontWeight"] = "fontWeight";
594
- ThTextSettingsKeys3["hyphens"] = "hyphens";
595
- ThTextSettingsKeys3["textAlign"] = "textAlign";
596
- ThTextSettingsKeys3["textNormalize"] = "textNormalize";
597
- return ThTextSettingsKeys3;
598
- })(ThTextSettingsKeys || {});
599
- var ThSpacingSettingsKeys = /* @__PURE__ */ ((ThSpacingSettingsKeys3) => {
600
- ThSpacingSettingsKeys3["letterSpacing"] = "letterSpacing";
601
- ThSpacingSettingsKeys3["lineHeight"] = "lineHeight";
602
- ThSpacingSettingsKeys3["paragraphIndent"] = "paragraphIndent";
603
- ThSpacingSettingsKeys3["paragraphSpacing"] = "paragraphSpacing";
604
- ThSpacingSettingsKeys3["publisherStyles"] = "publisherStyles";
605
- ThSpacingSettingsKeys3["spacingPresets"] = "spacingPresets";
606
- ThSpacingSettingsKeys3["wordSpacing"] = "wordSpacing";
607
- return ThSpacingSettingsKeys3;
608
- })(ThSpacingSettingsKeys || {});
609
- var ThSettingsContainerKeys = /* @__PURE__ */ ((ThSettingsContainerKeys2) => {
610
- ThSettingsContainerKeys2["initial"] = "initial";
611
- ThSettingsContainerKeys2["text"] = "text";
612
- ThSettingsContainerKeys2["spacing"] = "spacing";
613
- return ThSettingsContainerKeys2;
614
- })(ThSettingsContainerKeys || {});
615
- var ThSettingsRangeVariant = /* @__PURE__ */ ((ThSettingsRangeVariant2) => {
616
- ThSettingsRangeVariant2["slider"] = "slider";
617
- ThSettingsRangeVariant2["incrementedSlider"] = "incrementedSlider";
618
- ThSettingsRangeVariant2["numberField"] = "numberField";
619
- return ThSettingsRangeVariant2;
620
- })(ThSettingsRangeVariant || {});
621
- var ThSettingsRangePlaceholder = /* @__PURE__ */ ((ThSettingsRangePlaceholder2) => {
622
- ThSettingsRangePlaceholder2["range"] = "range";
623
- ThSettingsRangePlaceholder2["none"] = "none";
624
- return ThSettingsRangePlaceholder2;
625
- })(ThSettingsRangePlaceholder || {});
626
- var ThSpacingPresetKeys = /* @__PURE__ */ ((ThSpacingPresetKeys4) => {
627
- ThSpacingPresetKeys4["publisher"] = "publisher";
628
- ThSpacingPresetKeys4["tight"] = "tight";
629
- ThSpacingPresetKeys4["balanced"] = "balanced";
630
- ThSpacingPresetKeys4["loose"] = "loose";
631
- ThSpacingPresetKeys4["accessible"] = "accessible";
632
- ThSpacingPresetKeys4["custom"] = "custom";
633
- return ThSpacingPresetKeys4;
634
- })(ThSpacingPresetKeys || {});
635
- var ThLayoutOptions = /* @__PURE__ */ ((ThLayoutOptions2) => {
636
- ThLayoutOptions2["scroll"] = "scroll_option";
637
- ThLayoutOptions2["paginated"] = "page_option";
638
- return ThLayoutOptions2;
639
- })(ThLayoutOptions || {});
640
- var ThTextAlignOptions = /* @__PURE__ */ ((ThTextAlignOptions2) => {
641
- ThTextAlignOptions2["publisher"] = "publisher";
642
- ThTextAlignOptions2["start"] = "start";
643
- ThTextAlignOptions2["justify"] = "justify";
644
- return ThTextAlignOptions2;
645
- })(ThTextAlignOptions || {});
646
- var ThLineHeightOptions = /* @__PURE__ */ ((ThLineHeightOptions3) => {
647
- ThLineHeightOptions3["publisher"] = "publisher";
648
- ThLineHeightOptions3["small"] = "small";
649
- ThLineHeightOptions3["medium"] = "medium";
650
- ThLineHeightOptions3["large"] = "large";
651
- return ThLineHeightOptions3;
652
- })(ThLineHeightOptions || {});
653
- var defaultTextSettingsMain = ["fontFamily" /* fontFamily */];
654
- var defaultTextSettingsSubpanel = [
655
- "fontFamily" /* fontFamily */,
656
- "textAlign" /* textAlign */,
657
- "hyphens" /* hyphens */,
658
- "fontWeight" /* fontWeight */,
659
- "textNormalize" /* textNormalize */
660
- ];
661
- var defaultSpacingSettingsMain = [
662
- "spacingPresets" /* spacingPresets */
663
- ];
664
- var defaultSpacingSettingsSubpanel = [
665
- "spacingPresets" /* spacingPresets */,
666
- "lineHeight" /* lineHeight */,
667
- "paragraphSpacing" /* paragraphSpacing */,
668
- "paragraphIndent" /* paragraphIndent */,
669
- "wordSpacing" /* wordSpacing */,
670
- "letterSpacing" /* letterSpacing */
671
- ];
672
- var defaultSpacingPresetsOrder = [
673
- "publisher" /* publisher */,
674
- "accessible" /* accessible */,
675
- "custom" /* custom */,
676
- "tight" /* tight */,
677
- "balanced" /* balanced */,
678
- "loose" /* loose */
679
- ];
680
- var defaultParagraphSpacing = {
681
- variant: "numberField" /* numberField */,
682
- placeholder: "range" /* range */,
683
- range: [0, 3],
684
- step: 0.25
801
+ monitorDevTools: false,
802
+ disableRemotePlayback: false
685
803
  };
686
- var defaultParagraphIndent = {
687
- variant: "numberField" /* numberField */,
688
- placeholder: "range" /* range */,
689
- range: [0, 2],
690
- step: 0.25
691
- };
692
- var defaultWordSpacing = {
693
- variant: "numberField" /* numberField */,
694
- placeholder: "range" /* range */,
695
- range: [0, 1],
696
- step: 0.1
697
- };
698
- var defaultLetterSpacing = {
699
- variant: "numberField" /* numberField */,
700
- placeholder: "range" /* range */,
701
- range: [0, 0.5],
702
- step: 0.05
703
- };
704
- var defaultLineHeights = {
705
- ["small" /* small */]: 1.3,
706
- ["medium" /* medium */]: 1.5,
707
- ["large" /* large */]: 1.75
708
- };
709
- var defaultZoom = {
710
- variant: "numberField" /* numberField */,
711
- placeholder: "range" /* range */,
712
- range: [0.7, 4],
713
- step: 0.05
714
- };
715
- var defaultSpacingPresets = {
716
- ["tight" /* tight */]: {
717
- ["lineHeight" /* lineHeight */]: "small" /* small */,
718
- ["paragraphSpacing" /* paragraphSpacing */]: 0,
719
- ["paragraphIndent" /* paragraphIndent */]: 1
720
- },
721
- ["balanced" /* balanced */]: {
722
- ["lineHeight" /* lineHeight */]: "medium" /* medium */,
723
- ["paragraphSpacing" /* paragraphSpacing */]: 0.75,
724
- ["paragraphIndent" /* paragraphIndent */]: 0
725
- },
726
- ["loose" /* loose */]: {
727
- ["lineHeight" /* lineHeight */]: "large" /* large */,
728
- ["paragraphSpacing" /* paragraphSpacing */]: 1.75,
729
- ["paragraphIndent" /* paragraphIndent */]: 0
804
+ var devContentProtectionConfig = {
805
+ protectCopy: false,
806
+ disableContextMenu: false,
807
+ disableDragAndDrop: false,
808
+ protectPrinting: {
809
+ disable: false
730
810
  },
731
- ["accessible" /* accessible */]: {
732
- ["lineHeight" /* lineHeight */]: "large" /* large */,
733
- ["paragraphSpacing" /* paragraphSpacing */]: 2.5,
734
- ["paragraphIndent" /* paragraphIndent */]: 0,
735
- ["letterSpacing" /* letterSpacing */]: 0.1,
736
- ["wordSpacing" /* wordSpacing */]: 0.3
737
- }
811
+ disableSelectAll: false,
812
+ disableSave: false,
813
+ monitorDevTools: false,
814
+ disableRemotePlayback: false
738
815
  };
739
816
  var ThThemeKeys = /* @__PURE__ */ ((ThThemeKeys3) => {
740
817
  ThThemeKeys3["light"] = "light";
@@ -849,20 +926,260 @@ var contrast2Theme = {
849
926
  elevate: "0px 0px 2px #808080",
850
927
  immerse: "0.4"
851
928
  };
852
- var contrast3Theme = {
853
- background: "#c5e7cd",
854
- text: "#000000",
855
- link: "#0000EE",
856
- visited: "#551A8B",
857
- subdue: "#8c8c8c",
858
- disable: "#8c8c8c",
859
- hover: "#6fc383",
860
- onHover: "#000000",
861
- select: "#b4d8fe",
862
- onSelect: "inherit",
863
- focus: "#004099",
864
- elevate: "0px 0px 2px #8c8c8c",
865
- immerse: "0.45"
929
+ var contrast3Theme = {
930
+ background: "#c5e7cd",
931
+ text: "#000000",
932
+ link: "#0000EE",
933
+ visited: "#551A8B",
934
+ subdue: "#8c8c8c",
935
+ disable: "#8c8c8c",
936
+ hover: "#6fc383",
937
+ onHover: "#000000",
938
+ select: "#b4d8fe",
939
+ onSelect: "inherit",
940
+ focus: "#004099",
941
+ elevate: "0px 0px 2px #8c8c8c",
942
+ immerse: "0.45"
943
+ };
944
+
945
+ // src/preferences/audioPreferences.ts
946
+ var ThAudioAffordance = /* @__PURE__ */ ((ThAudioAffordance2) => {
947
+ ThAudioAffordance2["timeline"] = "timeline";
948
+ ThAudioAffordance2["readingOrder"] = "readingOrder";
949
+ ThAudioAffordance2["toc"] = "toc";
950
+ return ThAudioAffordance2;
951
+ })(ThAudioAffordance || {});
952
+ var validateRangePresets = (pref, context) => {
953
+ if (pref.variant !== "sliderWithPresets" /* sliderWithPresets */ || !pref.presets?.length) return;
954
+ const [min, max] = [Math.min(...pref.range), Math.max(...pref.range)];
955
+ const step = pref.step;
956
+ const tolerance = step * 1e-9;
957
+ const invalid = pref.presets.filter((p) => {
958
+ if (p < min || p > max) return true;
959
+ const offset = (p - min) / step;
960
+ return Math.abs(offset - Math.round(offset)) > tolerance;
961
+ });
962
+ if (invalid.length > 0) {
963
+ console.warn(
964
+ `${context}: presets [${invalid.join(", ")}] are not reachable with range=[${min}, ${max}] and step=${step}.`
965
+ );
966
+ }
967
+ };
968
+ var createAudioPreferences = (params) => {
969
+ if (params.actions?.secondary) {
970
+ validateObjectKeys(
971
+ [params.actions.secondary.displayOrder],
972
+ params.actions.secondary.keys,
973
+ "actions.secondary"
974
+ );
975
+ }
976
+ if (params.settings?.order) {
977
+ const order = params.settings.order;
978
+ const hasSkipInterval = order.includes("skipInterval" /* skipInterval */);
979
+ const hasSplitIntervals = order.includes("skipBackwardInterval" /* skipBackwardInterval */) || order.includes("skipForwardInterval" /* skipForwardInterval */);
980
+ if (hasSkipInterval && hasSplitIntervals) {
981
+ console.warn(
982
+ `settings.order contains both "${"skipInterval" /* skipInterval */}" and split interval keys. Use one or the other.`
983
+ );
984
+ }
985
+ }
986
+ if (params.theming?.themes) {
987
+ validateObjectKeys(
988
+ [params.theming.themes.audioOrder],
989
+ params.theming.themes.keys,
990
+ "theming.themes",
991
+ "auto"
992
+ );
993
+ }
994
+ if (params.theming?.layout?.publicationMetadata?.order) {
995
+ const order = params.theming.layout.publicationMetadata.order;
996
+ const titleVariants = [
997
+ "title" /* title */,
998
+ "titleWithSubtitle" /* titleWithSubtitle */,
999
+ "subtitleWithTitle" /* subtitleWithTitle */
1000
+ ];
1001
+ const titleVariantsInOrder = order.filter((c) => titleVariants.includes(c));
1002
+ if (titleVariantsInOrder.length > 1) {
1003
+ console.warn(
1004
+ `publicationMetadata.order contains multiple title variants [${titleVariantsInOrder.join(", ")}]. Using first one only.`
1005
+ );
1006
+ const firstTitleIndex = order.findIndex((c) => titleVariants.includes(c));
1007
+ params.theming.layout.publicationMetadata.order = order.filter((component, index) => {
1008
+ if (component === "authors" /* authors */) return true;
1009
+ return index === firstTitleIndex;
1010
+ });
1011
+ }
1012
+ }
1013
+ Object.entries(params.settings?.keys ?? {}).forEach(([key, pref]) => {
1014
+ if (pref && typeof pref === "object" && "variant" in pref) {
1015
+ validateRangePresets(pref, `settings.keys.${key}`);
1016
+ }
1017
+ });
1018
+ return params;
1019
+ };
1020
+
1021
+ // src/preferences/defaultAudioPreferences.ts
1022
+ var defaultAudioPreferences = createAudioPreferences({
1023
+ theming: {
1024
+ header: {
1025
+ backLink: {
1026
+ variant: "arrow" /* arrow */,
1027
+ visibility: "partially",
1028
+ href: "/"
1029
+ }
1030
+ },
1031
+ icon: {
1032
+ size: 24,
1033
+ tooltipOffset: 10
1034
+ },
1035
+ layout: {
1036
+ compact: {
1037
+ order: [
1038
+ "cover" /* cover */,
1039
+ "metadata" /* metadata */,
1040
+ "playbackControls" /* playbackControls */,
1041
+ "progressBar" /* progressBar */,
1042
+ "mediaActions" /* mediaActions */
1043
+ ]
1044
+ },
1045
+ expanded: {
1046
+ start: [
1047
+ "cover" /* cover */,
1048
+ "metadata" /* metadata */
1049
+ ],
1050
+ end: [
1051
+ "playbackControls" /* playbackControls */,
1052
+ "progressBar" /* progressBar */,
1053
+ "mediaActions" /* mediaActions */
1054
+ ]
1055
+ },
1056
+ publicationMetadata: {
1057
+ order: [
1058
+ "titleWithSubtitle" /* titleWithSubtitle */
1059
+ ]
1060
+ },
1061
+ radius: 5,
1062
+ spacing: 20,
1063
+ progressBar: {
1064
+ variant: "segmented" /* segmented */
1065
+ },
1066
+ defaults: {
1067
+ dockingWidth: 340,
1068
+ scrim: "rgba(0, 0, 0, 0.2)"
1069
+ },
1070
+ constraints: {
1071
+ ["bottomSheet" /* bottomSheet */]: 600,
1072
+ ["popover" /* popover */]: 600,
1073
+ ["modal" /* modal */]: 600,
1074
+ cover: 300
1075
+ }
1076
+ },
1077
+ breakpoints: {
1078
+ ["compact" /* compact */]: 600,
1079
+ ["medium" /* medium */]: 840,
1080
+ ["expanded" /* expanded */]: 1200,
1081
+ ["large" /* large */]: 1600,
1082
+ ["xLarge" /* xLarge */]: null
1083
+ },
1084
+ themes: {
1085
+ audioOrder: [
1086
+ "auto",
1087
+ "light" /* light */,
1088
+ "dark" /* dark */
1089
+ ],
1090
+ systemThemes: {
1091
+ light: "light" /* light */,
1092
+ dark: "dark" /* dark */
1093
+ },
1094
+ keys: {
1095
+ ["light" /* light */]: lightTheme,
1096
+ ["dark" /* dark */]: darkTheme
1097
+ }
1098
+ }
1099
+ },
1100
+ actions: {
1101
+ primary: {
1102
+ displayOrder: [
1103
+ "audio.volume" /* volume */,
1104
+ "audio.playbackRate" /* playbackRate */,
1105
+ "audio.toc" /* toc */,
1106
+ "audio.sleepTimer" /* sleepTimer */
1107
+ ],
1108
+ keys: {
1109
+ ["audio.volume" /* volume */]: defaultAudioVolumeAction,
1110
+ ["audio.playbackRate" /* playbackRate */]: defaultAudioPlaybackRateAction,
1111
+ ["audio.toc" /* toc */]: defaultAudioTocAction,
1112
+ ["audio.sleepTimer" /* sleepTimer */]: defaultAudioSleepTimerAction
1113
+ }
1114
+ },
1115
+ secondary: {
1116
+ displayOrder: [
1117
+ "audio.remotePlayback" /* remotePlayback */,
1118
+ "settings" /* settings */
1119
+ ],
1120
+ collapse: {
1121
+ ["compact" /* compact */]: 2,
1122
+ ["medium" /* medium */]: 3
1123
+ },
1124
+ keys: {
1125
+ ["audio.remotePlayback" /* remotePlayback */]: defaultAudioRemotePlaybackAction,
1126
+ ["settings" /* settings */]: defaultSettingsAction
1127
+ }
1128
+ }
1129
+ },
1130
+ settings: {
1131
+ order: [
1132
+ "theme" /* theme */,
1133
+ "skipBackwardInterval" /* skipBackwardInterval */,
1134
+ "skipForwardInterval" /* skipForwardInterval */,
1135
+ "autoPlay" /* autoPlay */
1136
+ ],
1137
+ keys: {
1138
+ ["volume" /* volume */]: defaultAudioVolume,
1139
+ ["playbackRate" /* playbackRate */]: defaultAudioPlaybackRate,
1140
+ ["skipBackwardInterval" /* skipBackwardInterval */]: defaultAudioSkipBackwardInterval,
1141
+ ["skipForwardInterval" /* skipForwardInterval */]: defaultAudioSkipForwardInterval,
1142
+ ["sleepTimer" /* sleepTimer */]: defaultAudioSleepTimer
1143
+ }
1144
+ },
1145
+ contentProtection: defaultAudioContentProtectionConfig,
1146
+ affordances: {
1147
+ previous: "toc" /* toc */,
1148
+ next: "toc" /* toc */
1149
+ },
1150
+ shortcuts: {
1151
+ representation: "symbol" /* symbol */,
1152
+ joiner: "+"
1153
+ },
1154
+ docking: {
1155
+ displayOrder: [
1156
+ "dockingTransient" /* transient */,
1157
+ "dockingStart" /* start */,
1158
+ "dockingEnd" /* end */
1159
+ ],
1160
+ // Only toc is dockable; others have dockable:none so dock panels are TOC-only
1161
+ // Matches EPUB config: no docking on compact/medium (mobile/tablet portrait)
1162
+ dock: {
1163
+ ["compact" /* compact */]: "none" /* none */,
1164
+ ["medium" /* medium */]: "none" /* none */,
1165
+ ["expanded" /* expanded */]: "start" /* start */,
1166
+ ["large" /* large */]: "both" /* both */,
1167
+ ["xLarge" /* xLarge */]: "both" /* both */
1168
+ },
1169
+ collapse: true,
1170
+ keys: {
1171
+ ["dockingStart" /* start */]: { visibility: "overflow" /* overflow */, shortcut: null },
1172
+ ["dockingEnd" /* end */]: { visibility: "overflow" /* overflow */, shortcut: null },
1173
+ ["dockingTransient" /* transient */]: { visibility: "overflow" /* overflow */, shortcut: null }
1174
+ }
1175
+ }
1176
+ });
1177
+ var ThAudioPreferencesContext = createContext(null);
1178
+ var defaultAudioPreferencesContextValue = {
1179
+ preferences: defaultAudioPreferences,
1180
+ updatePreferences: () => {
1181
+ throw new Error("updatePreferences must be used within a ThAudioPreferencesProvider");
1182
+ }
866
1183
  };
867
1184
 
868
1185
  // src/preferences/preferences.ts
@@ -874,29 +1191,13 @@ var createPreferences = (params) => {
874
1191
  params.locale = void 0;
875
1192
  }
876
1193
  }
877
- const validateObjectKeys = (orderArrays, keysObj, context, specialCase, fallback) => {
878
- const allOrders = new Set(
879
- orderArrays.flatMap((arr) => {
880
- if (!specialCase) return arr;
881
- return arr.filter((k) => {
882
- if (Array.isArray(specialCase)) {
883
- return !specialCase.includes(k);
884
- } else {
885
- return k !== specialCase;
886
- }
887
- });
888
- })
889
- );
890
- const availableKeys = Object.keys(keysObj);
891
- allOrders.forEach((key) => {
892
- if (!availableKeys.includes(key)) {
893
- console.warn(`Key "${key}" in ${context} order arrays not found in ${context}.keys.${""}`);
894
- }
895
- });
896
- };
897
1194
  if (params.actions) {
898
1195
  validateObjectKeys(
899
- [params.actions.reflowOrder, params.actions.fxlOrder, params.actions.webPubOrder],
1196
+ [
1197
+ params.actions.reflowOrder,
1198
+ params.actions.fxlOrder,
1199
+ params.actions.webPubOrder
1200
+ ],
900
1201
  params.actions.keys,
901
1202
  "actions"
902
1203
  );
@@ -1004,6 +1305,25 @@ var createPreferences = (params) => {
1004
1305
  }
1005
1306
  });
1006
1307
  }
1308
+ const validateRangePresets2 = (pref, context) => {
1309
+ if (pref.variant !== "sliderWithPresets" /* sliderWithPresets */ || !pref.presets?.length) return;
1310
+ const [min, max] = [Math.min(...pref.range), Math.max(...pref.range)];
1311
+ const step = pref.step;
1312
+ const tolerance = step * 1e-9;
1313
+ const invalid = pref.presets.filter((p) => {
1314
+ if (p < min || p > max) return true;
1315
+ const offset = (p - min) / step;
1316
+ return Math.abs(offset - Math.round(offset)) > tolerance;
1317
+ });
1318
+ if (invalid.length > 0) {
1319
+ console.warn(`${context}: presets [${invalid.join(", ")}] are not reachable with range=[${min}, ${max}] and step=${step}.`);
1320
+ }
1321
+ };
1322
+ Object.entries(params.settings?.keys ?? {}).forEach(([key, pref]) => {
1323
+ if (pref && typeof pref === "object" && "variant" in pref) {
1324
+ validateRangePresets2(pref, `settings.keys.${key}`);
1325
+ }
1326
+ });
1007
1327
  return params;
1008
1328
  };
1009
1329
 
@@ -1165,8 +1485,12 @@ var defaultPreferences = createPreferences({
1165
1485
  // Max-width of all bottom sheets
1166
1486
  ["popover" /* popover */]: 600,
1167
1487
  // Max-width of all popover sheets
1168
- pagination: 1024
1488
+ ["modal" /* modal */]: 600,
1489
+ // Max-width of all modal sheets
1490
+ pagination: 1024,
1169
1491
  // Max-width of pagination component
1492
+ dropdown: 250
1493
+ // Max-height of main UI dropdowns
1170
1494
  }
1171
1495
  },
1172
1496
  breakpoints: {
@@ -1367,8 +1691,6 @@ var defaultPreferences = createPreferences({
1367
1691
  }
1368
1692
  }
1369
1693
  });
1370
-
1371
- // src/preferences/ThPreferencesContext.ts
1372
1694
  var ThPreferencesContext = createContext(null);
1373
1695
  var defaultPreferencesContextValue = {
1374
1696
  preferences: defaultPreferences,
@@ -1376,611 +1698,35 @@ var defaultPreferencesContextValue = {
1376
1698
  throw new Error("updatePreferences must be used within a ThPreferencesProvider with an adapter");
1377
1699
  }
1378
1700
  };
1379
-
1380
- // src/preferences/adapters/ThMemoryPreferencesAdapter.ts
1381
- var ThMemoryPreferencesAdapter = class {
1382
- currentPreferences;
1383
- listeners = /* @__PURE__ */ new Set();
1384
- constructor(initialPreferences) {
1385
- this.currentPreferences = { ...initialPreferences };
1386
- }
1387
- getPreferences() {
1388
- return { ...this.currentPreferences };
1389
- }
1390
- setPreferences(prefs) {
1391
- this.currentPreferences = { ...prefs };
1392
- this.notifyListeners(this.currentPreferences);
1393
- }
1394
- subscribe(listener) {
1395
- this.listeners.add(listener);
1396
- }
1397
- unsubscribe(listener) {
1398
- this.listeners.delete(listener);
1399
- }
1400
- notifyListeners(prefs) {
1401
- this.listeners.forEach((listener) => listener({ ...prefs }));
1402
- }
1403
- };
1404
- var ThDirectionSetter = ({
1405
- direction,
1406
- children
1407
- }) => {
1408
- useEffect(() => {
1409
- if (direction) document.documentElement.dir = direction;
1410
- }, [direction]);
1411
- return children;
1412
- };
1413
- function ThPreferencesProvider({
1414
- adapter,
1415
- initialPreferences,
1416
- devMode,
1417
- children
1418
- }) {
1419
- const effectiveAdapter = useMemo(() => {
1420
- let fallbackPreferences = defaultPreferencesContextValue.preferences;
1421
- if (devMode && !initialPreferences) {
1422
- fallbackPreferences = {
1423
- ...fallbackPreferences,
1424
- contentProtection: devContentProtectionConfig
1425
- };
1426
- }
1427
- return adapter || new ThMemoryPreferencesAdapter(
1428
- initialPreferences || fallbackPreferences
1429
- );
1430
- }, [adapter, initialPreferences, devMode]);
1431
- const [preferences, setPreferences] = useState(
1432
- (() => {
1433
- let fallbackPreferences = defaultPreferencesContextValue.preferences;
1434
- if (devMode && !initialPreferences) {
1435
- fallbackPreferences = {
1436
- ...fallbackPreferences,
1437
- contentProtection: devContentProtectionConfig
1438
- };
1439
- }
1440
- return initialPreferences || fallbackPreferences;
1441
- })()
1442
- );
1443
- const handlePreferenceChange = useCallback((newPrefs) => {
1444
- setPreferences((prev) => {
1445
- return JSON.stringify(prev) === JSON.stringify(newPrefs) ? prev : newPrefs;
1446
- });
1447
- }, []);
1448
- useEffect(() => {
1449
- effectiveAdapter.subscribe(handlePreferenceChange);
1450
- return () => {
1451
- effectiveAdapter.unsubscribe(handlePreferenceChange);
1452
- };
1453
- }, [effectiveAdapter, handlePreferenceChange]);
1454
- const contextValue = useMemo(() => ({
1455
- preferences,
1456
- updatePreferences: (newPrefs) => {
1457
- effectiveAdapter.setPreferences(newPrefs);
1458
- }
1459
- }), [preferences, effectiveAdapter]);
1460
- return /* @__PURE__ */ jsx(ThPreferencesContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsx(ThDirectionSetter, { direction: preferences.direction, children }) });
1461
- }
1462
-
1463
- // src/preferences/services/createBunnyFontResources.ts
1464
- var buildBunnyFontsUrl = ({
1465
- family,
1466
- weights,
1467
- styles = ["normal"]
1468
- }) => {
1469
- if (weights.type !== "static") {
1470
- throw new Error("Bunny Fonts only supports static fonts");
1471
- }
1472
- const weightValues = weights.values;
1473
- const variants = /* @__PURE__ */ new Set();
1474
- for (const weight of weightValues) {
1475
- variants.add(weight.toString());
1476
- if (styles.includes("italic")) {
1477
- variants.add(`${weight}i`);
1478
- }
1479
- }
1480
- const variantList = Array.from(variants).sort();
1481
- const familyParam = family.replace(/ /g, "-").toLowerCase();
1482
- const variantParam = variantList.join(",");
1483
- return `https://fonts.bunny.net/css?family=${familyParam}:${variantParam}`;
1484
- };
1485
- var createBunnyFontResources = (font) => {
1486
- if (font.source.type !== "custom" || font.source.provider !== "bunny" || font.spec.weights.type !== "static") {
1487
- return null;
1488
- }
1489
- const { family, weights, styles } = font.spec;
1490
- const url = buildBunnyFontsUrl({
1491
- family,
1492
- weights,
1493
- styles
1494
- });
1495
- return {
1496
- as: "link",
1497
- rel: "stylesheet",
1498
- url
1499
- };
1500
- };
1501
-
1502
- // src/preferences/services/createGoogleFontResources.ts
1503
- var buildGoogleFontsV2Url = ({
1504
- family,
1505
- weights,
1506
- styles = ["normal"],
1507
- widths,
1508
- display = "block",
1509
- text
1510
- }) => {
1511
- if (text) {
1512
- return `https://fonts.googleapis.com/css2?family=${family.replace(/ /g, "+")}&text=${encodeURIComponent(text)}`;
1513
- }
1514
- const hasItalic = styles.includes("italic");
1515
- const hasWidth = !!widths;
1516
- const weightValues = weights.type === "static" ? weights.values.join(",") : `${weights.min}..${weights.max}`;
1517
- const widthValues = hasWidth && widths ? `${widths.min}..${widths.max}` : void 0;
1518
- const familyParam = family.replace(/ /g, "+");
1519
- let axesParam;
1520
- if (hasItalic && hasWidth) {
1521
- const variants = [
1522
- `0,${widthValues},${weightValues}`,
1523
- // normal
1524
- `1,${widthValues},${weightValues}`
1525
- // italic
1526
- ];
1527
- axesParam = `:ital,wdth,wght@${variants.join(";")}`;
1528
- } else if (hasItalic) {
1529
- const variants = [
1530
- `0,${weightValues}`,
1531
- // normal
1532
- `1,${weightValues}`
1533
- // italic
1534
- ];
1535
- axesParam = `:ital,wght@${variants.join(";")}`;
1536
- } else if (hasWidth) {
1537
- axesParam = `:wdth,wght@${widthValues},${weightValues}`;
1538
- } else {
1539
- axesParam = `:wght@${weightValues}`;
1540
- }
1541
- const displayParam = display ? `&display=${display}` : "";
1542
- return `https://fonts.googleapis.com/css2?family=${familyParam}${axesParam}${displayParam}`;
1543
- };
1544
- var createGoogleFontResources = (font, text) => {
1545
- if (font.source.type !== "custom" || font.source.provider !== "google") {
1546
- return null;
1547
- }
1548
- const { family, weights, display, styles, widths } = font.spec;
1549
- const url = buildGoogleFontsV2Url({
1550
- family,
1551
- weights,
1552
- display,
1553
- styles,
1554
- widths,
1555
- text
1556
- });
1557
- return {
1558
- as: "link",
1559
- rel: "stylesheet",
1560
- url
1561
- };
1562
- };
1563
-
1564
- // src/preferences/services/createLocalFontResources.ts
1565
- var getFontFormat = (path) => {
1566
- const ext = path.split(".").pop()?.toLowerCase();
1567
- switch (ext) {
1568
- case "woff":
1569
- return "woff";
1570
- case "woff2":
1571
- return "woff2";
1572
- case "ttf":
1573
- return "truetype";
1574
- case "otf":
1575
- return "opentype";
1576
- case "eot":
1577
- return "embedded-opentype";
1578
- case "svg":
1579
- return "svg";
1580
- default:
1581
- return "woff2";
1582
- }
1583
- };
1584
- var createLocalFontResources = (font) => {
1585
- if (font.source.type !== "custom" || font.source.provider !== "local") {
1586
- return null;
1587
- }
1588
- const { family, weights, display, widths } = font.spec;
1589
- const fontFiles = font.source.files || [];
1590
- const cssContent = fontFiles.map((fontFile) => {
1591
- const format = getFontFormat(fontFile.path);
1592
- const fontUrl = new URL(fontFile.path, window.location.origin).toString();
1593
- const isVariable = font.source.type === "custom" && font.source.provider === "local" && "variant" in font.source && font.source.variant === "variable";
1594
- const rules = [
1595
- `@font-face {`,
1596
- ` font-family: "${family}";`,
1597
- ` src: url("${fontUrl}") format("${format}");`
1598
- ];
1599
- if (isVariable && weights.type === "variable") {
1600
- rules.push(` font-weight: ${weights.min} ${weights.max};`);
1601
- } else if ("weight" in fontFile) {
1602
- rules.push(` font-weight: ${fontFile.weight};`);
1603
- }
1604
- if ("style" in fontFile) {
1605
- rules.push(` font-style: ${fontFile.style};`);
1606
- }
1607
- if (isVariable && widths) {
1608
- rules.push(` font-stretch: ${widths.min}% ${widths.max}%;`);
1609
- }
1610
- if (display) {
1611
- rules.push(` font-display: ${display};`);
1612
- } else {
1613
- rules.push(` font-display: block;`);
1614
- }
1615
- return rules.join("\n") + "\n}";
1616
- }).filter(Boolean).join("\n\n");
1617
- const blob = new Blob([cssContent], { type: "text/css" });
1618
- return {
1619
- as: "link",
1620
- rel: "stylesheet",
1621
- blob
1622
- };
1623
- };
1624
-
1625
- // src/preferences/services/fonts.ts
1626
- var createFontService = (fontFamilyPref) => {
1627
- const allSupportedLanguages = [];
1628
- const parsedFonts = /* @__PURE__ */ new Map();
1629
- const bunnyFonts = /* @__PURE__ */ new Map();
1630
- const googleFonts = /* @__PURE__ */ new Map();
1631
- const localFonts = /* @__PURE__ */ new Map();
1632
- const resolveFontLanguage = (bcp47Tag, direction = "ltr") => {
1633
- if (!bcp47Tag) return "default";
1634
- if (allSupportedLanguages.includes(bcp47Tag)) {
1635
- return bcp47Tag;
1636
- }
1637
- const parts = bcp47Tag.split(/[-_]/);
1638
- const language = parts[0].toLowerCase();
1639
- const scriptOrRegion = parts[1]?.toLowerCase();
1640
- if (scriptOrRegion) {
1641
- const langScriptOrRegion = `${language}-${scriptOrRegion}`;
1642
- if (allSupportedLanguages.includes(langScriptOrRegion)) {
1643
- return langScriptOrRegion;
1644
- }
1645
- }
1646
- if (language === "ja" && !scriptOrRegion) {
1647
- if (direction === "rtl" && allSupportedLanguages.includes("ja-v")) {
1648
- return "ja-v";
1649
- }
1650
- if (allSupportedLanguages.includes("ja")) {
1651
- return "ja";
1652
- }
1653
- }
1654
- const shouldFilter = language === "mn" && (scriptOrRegion === "mong" || scriptOrRegion === "cyrl") || language === "zh" && (scriptOrRegion === "hant" || scriptOrRegion === "tw" || scriptOrRegion === "hk");
1655
- if (!shouldFilter && allSupportedLanguages.includes(language)) {
1656
- return language;
1657
- }
1658
- return "default";
1659
- };
1660
- Object.entries(fontFamilyPref).forEach(([collectionName, collectionData]) => {
1661
- const fontCollection = "fonts" in collectionData ? collectionData.fonts : collectionData;
1662
- if ("supportedLanguages" in collectionData) {
1663
- const reducedLanguages = collectionData.supportedLanguages.map((lang) => {
1664
- const parts = lang.split(/[-_]/);
1665
- const language = parts[0].toLowerCase();
1666
- const scriptOrRegion = parts[1]?.toLowerCase();
1667
- return scriptOrRegion ? `${language}-${scriptOrRegion}` : language;
1668
- });
1669
- allSupportedLanguages.push(...reducedLanguages);
1670
- }
1671
- bunnyFonts.set(collectionName, []);
1672
- googleFonts.set(collectionName, []);
1673
- localFonts.set(collectionName, []);
1674
- const collectionBunnyFonts = bunnyFonts.get(collectionName);
1675
- const collectionGoogleFonts = googleFonts.get(collectionName);
1676
- const collectionLocalFonts = localFonts.get(collectionName);
1677
- Object.entries(fontCollection).forEach(([id, font]) => {
1678
- const fontFamily = font.spec.family;
1679
- let fontStack = fontFamily;
1680
- if (font.source.type === "custom") {
1681
- switch (font.source.provider) {
1682
- case "bunny":
1683
- collectionBunnyFonts.push(font);
1684
- break;
1685
- case "google":
1686
- collectionGoogleFonts.push(font);
1687
- break;
1688
- case "local":
1689
- collectionLocalFonts.push(font);
1690
- break;
1691
- }
1692
- }
1693
- const wrapIfNeeded = (name) => {
1694
- const trimmed = name.trim();
1695
- if (!trimmed) return "";
1696
- if (trimmed.includes(" ") && !/^['"].*['"]$/.test(trimmed)) {
1697
- return `"${trimmed}"`;
1698
- }
1699
- return trimmed;
1700
- };
1701
- const wrappedFontFamily = wrapIfNeeded(fontFamily);
1702
- if (font.spec.fallbacks?.length) {
1703
- const uniqueFallbacks = [...new Set(
1704
- font.spec.fallbacks.filter((fallback) => fallback.toLowerCase() !== fontFamily.toLowerCase()).map(wrapIfNeeded)
1705
- )];
1706
- if (uniqueFallbacks.length > 0) {
1707
- fontStack = [wrappedFontFamily, ...uniqueFallbacks].join(", ");
1708
- }
1709
- }
1710
- parsedFonts.set(id, {
1711
- fontStack: fontStack || wrappedFontFamily,
1712
- fontFamily: wrappedFontFamily,
1713
- weights: font.spec.weights || null,
1714
- widths: font.spec.widths || null
1715
- });
1716
- });
1717
- });
1718
- const defaultBunnyFonts = bunnyFonts.get("default") || [];
1719
- const defaultGoogleFonts = googleFonts.get("default") || [];
1720
- const defaultLocalFonts = localFonts.get("default") || [];
1721
- const processFonts = (bunnyFontsList, googleFontsList, localFontsList, optimize = false) => {
1722
- const result = {
1723
- allowedDomains: [],
1724
- prepend: [],
1725
- append: []
1726
- };
1727
- const bunnyResources = bunnyFontsList.map((font) => createBunnyFontResources(font)).filter((resource) => resource !== null);
1728
- if (bunnyResources.length > 0) {
1729
- result.allowedDomains.push(
1730
- "https://fonts.bunny.net"
1731
- );
1732
- result.prepend.push(
1733
- {
1734
- as: "link",
1735
- rel: "preconnect",
1736
- url: "https://fonts.bunny.net"
1737
- }
1738
- );
1739
- result.append.push(...bunnyResources);
1740
- }
1741
- const googleResources = googleFontsList.map((font) => createGoogleFontResources(font, optimize ? font.name : void 0)).filter((resource) => resource !== null);
1742
- if (googleResources.length > 0) {
1743
- result.allowedDomains.push(
1744
- "https://fonts.googleapis.com",
1745
- "https://fonts.gstatic.com"
1746
- );
1747
- result.prepend.push(
1748
- {
1749
- as: "link",
1750
- rel: "preconnect",
1751
- url: "https://fonts.googleapis.com"
1752
- },
1753
- {
1754
- as: "link",
1755
- rel: "preconnect",
1756
- url: "https://fonts.gstatic.com",
1757
- attributes: { crossOrigin: "anonymous" }
1758
- }
1759
- );
1760
- result.append.push(...googleResources);
1761
- }
1762
- const localResources = localFontsList.map(createLocalFontResources).filter((resource) => resource !== null);
1763
- if (localResources.length > 0) {
1764
- result.allowedDomains.push(window.location.origin);
1765
- result.append.push(...localResources);
1766
- }
1767
- return result.append.length > 0 ? result : null;
1768
- };
1769
- const getInjectables = (options, optimize = false) => {
1770
- if (options && "key" in options) {
1771
- const { key } = options;
1772
- if (!key || !(key in fontFamilyPref)) {
1773
- return null;
1774
- }
1775
- return processFonts(bunnyFonts.get(key) || [], googleFonts.get(key) || [], localFonts.get(key) || [], optimize);
1776
- }
1777
- if (options && "language" in options) {
1778
- const { language: publicationLanguage } = options;
1779
- for (const [collectionName, collectionData] of Object.entries(fontFamilyPref)) {
1780
- if (collectionName === "default") continue;
1781
- const supportedLangs = "supportedLanguages" in collectionData ? collectionData.supportedLanguages : null;
1782
- if (supportedLangs && Array.isArray(supportedLangs) && publicationLanguage && supportedLangs.includes(publicationLanguage)) {
1783
- return processFonts(bunnyFonts.get(collectionName) || [], googleFonts.get(collectionName) || [], localFonts.get(collectionName) || [], optimize);
1784
- }
1785
- }
1786
- }
1787
- return processFonts(defaultBunnyFonts, defaultGoogleFonts, defaultLocalFonts, optimize);
1788
- };
1789
- const getFontMetadata = (fontId) => {
1790
- const parsed = parsedFonts.get(fontId);
1791
- return parsed || { fontStack: null, fontFamily: null, weights: null, widths: null };
1792
- };
1793
- const getFontCollection = (options) => {
1794
- if (options && "key" in options) {
1795
- const { key } = options;
1796
- if (!key || !(key in fontFamilyPref)) {
1797
- return fontFamilyPref.default;
1798
- }
1799
- if (key === "default") {
1800
- return fontFamilyPref.default;
1801
- }
1802
- const prefRecord = fontFamilyPref;
1803
- const collection = prefRecord[key];
1804
- if (collection && "fonts" in collection) {
1805
- return collection.fonts;
1806
- }
1807
- return fontFamilyPref.default;
1808
- }
1809
- if (options && "language" in options) {
1810
- const { language: publicationLanguage } = options;
1811
- for (const [collectionName, collectionData] of Object.entries(fontFamilyPref)) {
1812
- if (collectionName === "default") continue;
1813
- const collection = "fonts" in collectionData ? collectionData : { fonts: collectionData };
1814
- const supportedLangs = "supportedLanguages" in collection ? collection.supportedLanguages : null;
1815
- if (supportedLangs?.includes(publicationLanguage)) {
1816
- return collection.fonts;
1817
- }
1818
- }
1819
- return fontFamilyPref.default;
1820
- }
1821
- return fontFamilyPref.default;
1822
- };
1823
- return {
1824
- getInjectables,
1825
- getFontMetadata,
1826
- getFontCollection,
1827
- resolveFontLanguage
1828
- };
1829
- };
1830
-
1831
- // src/preferences/hooks/usePreferences.ts
1832
- function usePreferences() {
1833
- const context = useContext(ThPreferencesContext);
1834
- if (!context) {
1835
- throw new Error("usePreferences must be used within a ThPreferencesProvider");
1836
- }
1837
- const fontService = createFontService(context.preferences.settings.keys.fontFamily);
1838
- return {
1839
- preferences: context.preferences,
1840
- updatePreferences: context.updatePreferences,
1841
- getFontInjectables: (options, optimize) => {
1842
- return fontService.getInjectables(options, optimize);
1843
- },
1844
- getFontsList: (options) => {
1845
- return fontService.getFontCollection(options);
1846
- },
1847
- getFontMetadata: (fontId) => {
1848
- return fontService.getFontMetadata(fontId);
1849
- },
1850
- resolveFontLanguage: (bcp47Tag, direction) => {
1851
- return fontService.resolveFontLanguage(bcp47Tag, direction);
1852
- }
1853
- };
1854
- }
1855
-
1856
- // src/preferences/hooks/usePreferenceKeys.ts
1857
- var usePreferenceKeys = () => {
1858
- const { preferences } = usePreferences();
1859
- const reflowActionKeys = preferences.actions.reflowOrder;
1860
- const fxlActionKeys = preferences.actions.fxlOrder;
1861
- const webPubActionKeys = preferences.actions.webPubOrder;
1862
- const reflowThemeKeys = preferences.theming.themes.reflowOrder;
1863
- const fxlThemeKeys = preferences.theming.themes.fxlOrder;
1864
- const reflowSettingsKeys = preferences.settings.reflowOrder;
1865
- const fxlSettingsKeys = preferences.settings.fxlOrder;
1866
- const webPubSettingsKeys = preferences.settings.webPubOrder;
1867
- const mainTextSettingsKeys = preferences.settings.text?.main ?? defaultTextSettingsMain;
1868
- const subPanelTextSettingsKeys = preferences.settings.text?.subPanel ?? defaultTextSettingsSubpanel;
1869
- const mainSpacingSettingsKeys = preferences.settings.spacing?.main ?? defaultSpacingSettingsMain;
1870
- const subPanelSpacingSettingsKeys = preferences.settings.spacing?.subPanel ?? defaultSpacingSettingsSubpanel;
1871
- const reflowSpacingPresetKeys = preferences.settings.spacing?.presets?.reflowOrder ?? defaultSpacingPresetsOrder;
1872
- const fxlSpacingPresetKeys = [];
1873
- const webPubSpacingPresetKeys = preferences.settings.spacing?.presets?.webPubOrder ?? defaultSpacingPresetsOrder;
1701
+ var useSharedPreferences = () => {
1702
+ const audioCtx = useContext(ThAudioPreferencesContext);
1703
+ const readerCtx = useContext(ThPreferencesContext);
1704
+ const ctx = audioCtx ?? readerCtx;
1705
+ if (!ctx) throw new Error("useSharedPreferences must be used within a ThPreferencesProvider or ThAudioPreferencesProvider");
1706
+ const prefs = ctx.preferences;
1874
1707
  return {
1875
- reflowActionKeys,
1876
- fxlActionKeys,
1877
- webPubActionKeys,
1878
- reflowThemeKeys,
1879
- fxlThemeKeys,
1880
- reflowSettingsKeys,
1881
- fxlSettingsKeys,
1882
- webPubSettingsKeys,
1883
- mainTextSettingsKeys,
1884
- subPanelTextSettingsKeys,
1885
- mainSpacingSettingsKeys,
1886
- subPanelSpacingSettingsKeys,
1887
- reflowSpacingPresetKeys,
1888
- fxlSpacingPresetKeys,
1889
- webPubSpacingPresetKeys
1890
- };
1891
- };
1892
-
1893
- // src/core/Helpers/prefixString.ts
1894
- var PREFIXES = {
1895
- short: "th",
1896
- full: "thorium_web"
1897
- };
1898
- var prefixString = (str, variant = "short") => {
1899
- return `${PREFIXES[variant]}-${str}`;
1900
- };
1901
-
1902
- // src/preferences/hooks/useTheming.ts
1903
- var useTheming = ({
1904
- theme,
1905
- systemKeys,
1906
- themeKeys,
1907
- breakpointsMap,
1908
- initProps,
1909
- onBreakpointChange,
1910
- onColorSchemeChange,
1911
- onContrastChange,
1912
- onForcedColorsChange,
1913
- onMonochromeChange,
1914
- onReducedMotionChange,
1915
- onReducedTransparencyChange
1916
- }) => {
1917
- const breakpoints = useBreakpoints(breakpointsMap, onBreakpointChange);
1918
- const colorScheme = useColorScheme(onColorSchemeChange);
1919
- const colorSchemeRef = useRef(colorScheme);
1920
- const contrast = useContrast(onContrastChange);
1921
- const forcedColors = useForcedColors(onForcedColorsChange);
1922
- const monochrome = useMonochrome(onMonochromeChange);
1923
- const reducedMotion = useReducedMotion(onReducedMotionChange);
1924
- const reducedTransparency = useReducedTransparency(onReducedTransparencyChange);
1925
- const updateThemeColorMetaTag = useCallback((color) => {
1926
- if (typeof document === "undefined") return;
1927
- let metaTag = document.querySelector("meta[name='theme-color']");
1928
- if (!metaTag) {
1929
- metaTag = document.createElement("meta");
1930
- metaTag.setAttribute("name", "theme-color");
1931
- document.head.appendChild(metaTag);
1932
- }
1933
- metaTag.setAttribute("content", color);
1934
- }, []);
1935
- const inferThemeAuto = useCallback(() => {
1936
- return colorSchemeRef.current === "dark" /* dark */ ? systemKeys?.dark : systemKeys?.light;
1937
- }, [systemKeys]);
1938
- const initThemingCustomProps = useCallback(() => {
1939
- for (let p in initProps) {
1940
- document.documentElement.style.setProperty(p, initProps[p]);
1941
- }
1942
- }, [initProps]);
1943
- const setThemeCustomProps = useCallback((t) => {
1944
- if (!t) {
1945
- return;
1946
- }
1947
- if (t === "auto") {
1948
- const autoTheme = inferThemeAuto();
1949
- if (!autoTheme) {
1950
- return;
1951
- }
1952
- t = autoTheme;
1953
- }
1954
- const themeTokens = themeKeys[t];
1955
- if (!themeTokens) {
1956
- return;
1957
- }
1958
- const props = propsToCSSVars(themeTokens, { prefix: prefixString("theme") });
1959
- for (let p in props) {
1960
- document.documentElement.style.setProperty(p, props[p]);
1708
+ direction: prefs.direction,
1709
+ locale: prefs.locale,
1710
+ shortcuts: prefs.shortcuts,
1711
+ docking: prefs.docking,
1712
+ theming: {
1713
+ icon: prefs.theming.icon,
1714
+ header: prefs.theming.header ? { backLink: prefs.theming.header.backLink } : void 0,
1715
+ themes: {
1716
+ systemThemes: prefs.theming.themes.systemThemes,
1717
+ keys: prefs.theming.themes.keys,
1718
+ audioOrder: audioCtx?.preferences.theming.themes.audioOrder,
1719
+ reflowOrder: readerCtx?.preferences.theming.themes.reflowOrder,
1720
+ fxlOrder: readerCtx?.preferences.theming.themes.fxlOrder
1721
+ },
1722
+ layout: {
1723
+ defaults: prefs.theming.layout.defaults
1724
+ },
1725
+ breakpoints: prefs.theming.breakpoints
1961
1726
  }
1962
- updateThemeColorMetaTag(themeTokens.background);
1963
- }, [inferThemeAuto, updateThemeColorMetaTag, themeKeys]);
1964
- useEffect(() => {
1965
- initThemingCustomProps();
1966
- }, [initThemingCustomProps]);
1967
- useEffect(() => {
1968
- colorSchemeRef.current = colorScheme;
1969
- setThemeCustomProps(theme);
1970
- }, [setThemeCustomProps, theme, colorScheme]);
1971
- return {
1972
- inferThemeAuto,
1973
- theme,
1974
- breakpoints,
1975
- colorScheme,
1976
- contrast,
1977
- forcedColors,
1978
- monochrome,
1979
- reducedMotion,
1980
- reducedTransparency
1981
1727
  };
1982
1728
  };
1983
1729
 
1984
- export { ThActionsKeys, ThDockingKeys, ThDockingTypes, ThLayoutOptions, ThLineHeightOptions, ThMemoryPreferencesAdapter, ThPreferencesContext, ThPreferencesProvider, ThSettingsContainerKeys, ThSettingsKeys, ThSettingsRangePlaceholder, ThSettingsRangeVariant, ThSheetHeaderVariant, ThSheetTypes, ThSpacingPresetKeys, ThSpacingSettingsKeys, ThTextAlignOptions, ThTextSettingsKeys, ThThemeKeys, buildThemeObject, contrast1Theme, contrast2Theme, contrast3Theme, createDefinitionFromStaticFonts, createDefinitionsFromBunnyFonts, createDefinitionsFromGoogleFonts, createPreferences, darkTheme, defaultActionKeysObject, defaultContentProtectionConfig, defaultFontCollection, defaultFullscreenAction, defaultJumpToPositionAction, defaultLetterSpacing, defaultLineHeights, defaultParagraphIndent, defaultParagraphSpacing, defaultPreferences, defaultPreferencesContextValue, defaultSettingsAction, defaultSpacingPresets, defaultSpacingPresetsOrder, defaultSpacingSettingsMain, defaultSpacingSettingsSubpanel, defaultTextSettingsMain, defaultTextSettingsSubpanel, defaultTocAction, defaultWordSpacing, defaultZoom, devContentProtectionConfig, lightTheme, paperTheme, prefixString, readiumCSSFontCollection, resolveContentProtectionConfig, sepiaTheme, tamilCollection, usePreferenceKeys, usePreferences, useTheming };
1985
- //# sourceMappingURL=chunk-7NEQAW7J.mjs.map
1986
- //# sourceMappingURL=chunk-7NEQAW7J.mjs.map
1730
+ export { ThActionsKeys, ThAudioActionKeys, ThAudioAffordance, ThAudioKeys, ThAudioPreferencesContext, ThDockingKeys, ThDockingTypes, ThLayoutOptions, ThLineHeightOptions, ThPreferencesContext, ThSettingsContainerKeys, ThSettingsKeys, ThSettingsRangePlaceholder, ThSettingsRangeVariant, ThSettingsTimerVariant, ThSheetHeaderVariant, ThSheetTypes, ThSpacingPresetKeys, ThSpacingSettingsKeys, ThTextAlignOptions, ThTextSettingsKeys, ThThemeKeys, contrast1Theme, contrast2Theme, contrast3Theme, createAudioPreferences, createDefinitionFromStaticFonts, createDefinitionsFromGoogleFonts, createPreferences, darkTheme, defaultActionKeysObject, defaultAudioContentProtectionConfig, defaultAudioPlaybackRate, defaultAudioPlaybackRateAction, defaultAudioPreferences, defaultAudioPreferencesContextValue, defaultAudioRemotePlaybackAction, defaultAudioSkipBackwardInterval, defaultAudioSkipForwardInterval, defaultAudioSkipInterval, defaultAudioSleepTimer, defaultAudioSleepTimerAction, defaultAudioSleepTimerPresetList, defaultAudioTocAction, defaultAudioVolume, defaultAudioVolumeAction, defaultContentProtectionConfig, defaultFontCollection, defaultFullscreenAction, defaultJumpToPositionAction, defaultLetterSpacing, defaultLineHeights, defaultParagraphIndent, defaultParagraphSpacing, defaultPreferences, defaultPreferencesContextValue, defaultSettingsAction, defaultSpacingPresets, defaultSpacingPresetsOrder, defaultSpacingSettingsMain, defaultSpacingSettingsSubpanel, defaultTextSettingsMain, defaultTextSettingsSubpanel, defaultTocAction, defaultWordSpacing, defaultZoom, devContentProtectionConfig, lightTheme, paperTheme, readiumCSSFontCollection, resolveAudioContentProtectionConfig, resolveContentProtectionConfig, sepiaTheme, tamilCollection, useSharedPreferences, validateObjectKeys };
1731
+ //# sourceMappingURL=chunk-DTPO3J2C.mjs.map
1732
+ //# sourceMappingURL=chunk-DTPO3J2C.mjs.map