@edrlab/thorium-web 1.4.1 → 1.5.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 (87) hide show
  1. package/dist/{ThPreferencesAdapter-_5AePKHa.d.mts → ThPreferencesAdapter-B3a-f5v-.d.mts} +22 -17
  2. package/dist/{ThSettingsWrapper-B_9klYXH.d.mts → ThSettingsWrapper-DtzcwzYX.d.mts} +4 -4
  3. package/dist/{actions-CuRRM3rp.d.mts → actions-C33UN3Ji.d.mts} +14 -3
  4. package/dist/{actionsReducer-VFR42qgL.d.mts → actionsReducer-Bzcj3wk3.d.mts} +1 -1
  5. package/dist/{chunk-SZAVAQ6S.mjs → chunk-2B3HE57E.mjs} +42 -52
  6. package/dist/chunk-2B3HE57E.mjs.map +1 -0
  7. package/dist/{chunk-SI4FBFHM.mjs → chunk-3ITHCTDL.mjs} +157 -108
  8. package/dist/chunk-3ITHCTDL.mjs.map +1 -0
  9. package/dist/{chunk-OD75GC5N.mjs → chunk-3VB756GR.mjs} +89 -51
  10. package/dist/chunk-3VB756GR.mjs.map +1 -0
  11. package/dist/{chunk-ETLIGONP.mjs → chunk-AXX4U2FW.mjs} +25 -133
  12. package/dist/chunk-AXX4U2FW.mjs.map +1 -0
  13. package/dist/{chunk-WF2UOYO7.mjs → chunk-CCHCCVSF.mjs} +3 -3
  14. package/dist/{chunk-WF2UOYO7.mjs.map → chunk-CCHCCVSF.mjs.map} +1 -1
  15. package/dist/{chunk-RBEPH5E5.mjs → chunk-J6XDICU2.mjs} +80 -50
  16. package/dist/chunk-J6XDICU2.mjs.map +1 -0
  17. package/dist/chunk-KQ3KS5O5.mjs +37 -0
  18. package/dist/chunk-KQ3KS5O5.mjs.map +1 -0
  19. package/dist/{chunk-DQDOOTCE.mjs → chunk-KT2QY5QU.mjs} +3 -3
  20. package/dist/{chunk-DQDOOTCE.mjs.map → chunk-KT2QY5QU.mjs.map} +1 -1
  21. package/dist/{chunk-KGSFTRCH.mjs → chunk-KXOIN35D.mjs} +45 -117
  22. package/dist/chunk-KXOIN35D.mjs.map +1 -0
  23. package/dist/{chunk-E2JEGVVE.mjs → chunk-MTH2RF6V.mjs} +45 -12
  24. package/dist/chunk-MTH2RF6V.mjs.map +1 -0
  25. package/dist/{chunk-MSHUPSBI.mjs → chunk-THOJRBVD.mjs} +337 -90
  26. package/dist/chunk-THOJRBVD.mjs.map +1 -0
  27. package/dist/{chunk-VENFFPK2.mjs → chunk-VYSDLACR.mjs} +2 -2
  28. package/dist/{chunk-VENFFPK2.mjs.map → chunk-VYSDLACR.mjs.map} +1 -1
  29. package/dist/chunk-X63WSMOH.mjs +57 -0
  30. package/dist/chunk-X63WSMOH.mjs.map +1 -0
  31. package/dist/{chunk-YEVLT3AV.mjs → chunk-YE5QOQUT.mjs} +3 -3
  32. package/dist/{chunk-YEVLT3AV.mjs.map → chunk-YE5QOQUT.mjs.map} +1 -1
  33. package/dist/components/Audio/index.css +10 -0
  34. package/dist/components/Audio/index.css.map +1 -1
  35. package/dist/components/Audio/index.d.mts +12 -11
  36. package/dist/components/Audio/index.mjs +13 -12
  37. package/dist/components/Epub/index.css +10 -0
  38. package/dist/components/Epub/index.css.map +1 -1
  39. package/dist/components/Epub/index.d.mts +12 -11
  40. package/dist/components/Epub/index.mjs +14 -13
  41. package/dist/components/Misc/index.mjs +4 -4
  42. package/dist/components/Reader/index.css +10 -0
  43. package/dist/components/Reader/index.css.map +1 -1
  44. package/dist/components/Reader/index.d.mts +11 -10
  45. package/dist/components/Reader/index.mjs +21 -20
  46. package/dist/components/Reader/index.mjs.map +1 -1
  47. package/dist/components/WebPub/index.css +10 -0
  48. package/dist/components/WebPub/index.css.map +1 -1
  49. package/dist/components/WebPub/index.d.mts +12 -11
  50. package/dist/components/WebPub/index.mjs +14 -13
  51. package/dist/core/Components/index.d.mts +10 -25
  52. package/dist/core/Components/index.mjs +1 -1
  53. package/dist/core/Helpers/index.d.mts +1 -1
  54. package/dist/core/Helpers/index.mjs +3 -2
  55. package/dist/core/Hooks/index.d.mts +14 -7
  56. package/dist/core/Hooks/index.mjs +2 -1
  57. package/dist/i18n/index.mjs +2 -2
  58. package/dist/keyboardUtilities-BCP3UcLb.d.mts +30 -0
  59. package/dist/lib/index.d.mts +9 -8
  60. package/dist/lib/index.mjs +3 -2
  61. package/dist/locales/da/thorium-shared.json +217 -10
  62. package/dist/locales/he/thorium-shared.json +8 -0
  63. package/dist/locales/he/thorium-web.json +9 -0
  64. package/dist/locales/it/thorium-shared.json +2 -2
  65. package/dist/locales/it/thorium-web.json +24 -2
  66. package/dist/locales/lt/thorium-shared.json +85 -1
  67. package/dist/locales/sv/thorium-shared.json +5 -5
  68. package/dist/locales/sv/thorium-web.json +22 -0
  69. package/dist/preferences/index.d.mts +16 -23
  70. package/dist/preferences/index.mjs +4 -3
  71. package/dist/{settingsReducer-VqBhLq50.d.mts → settingsReducer-Pp9aoiiC.d.mts} +1 -1
  72. package/dist/{useAudioNavigator-CWXyNWq1.d.mts → useAudioNavigator-9RuOpLGB.d.mts} +8 -5
  73. package/dist/{useContrast-Cbso7N1l.d.mts → useContrast-Bl08zDTU.d.mts} +2 -7
  74. package/dist/{usePreferences-9ZvbcbLW.d.mts → usePreferences-Cy7-JN2x.d.mts} +4 -8
  75. package/dist/{useReaderTransitions-0hKGCvMm.d.mts → useReaderTransitions-CpgrXS5g.d.mts} +50 -23
  76. package/package.json +7 -7
  77. package/dist/chunk-44PEO3DS.mjs +0 -121
  78. package/dist/chunk-44PEO3DS.mjs.map +0 -1
  79. package/dist/chunk-E2JEGVVE.mjs.map +0 -1
  80. package/dist/chunk-ETLIGONP.mjs.map +0 -1
  81. package/dist/chunk-KGSFTRCH.mjs.map +0 -1
  82. package/dist/chunk-MSHUPSBI.mjs.map +0 -1
  83. package/dist/chunk-OD75GC5N.mjs.map +0 -1
  84. package/dist/chunk-RBEPH5E5.mjs.map +0 -1
  85. package/dist/chunk-SI4FBFHM.mjs.map +0 -1
  86. package/dist/chunk-SZAVAQ6S.mjs.map +0 -1
  87. package/dist/keyboardUtilities-BWAyLS_D.d.mts +0 -56
@@ -1,24 +1,136 @@
1
- import { makeBreakpointsMap, isKeyboardTriggered, isActiveElement } from './chunk-VENFFPK2.mjs';
2
- import { useFullscreen, useLocalStorage, useEpubNavigator } from './chunk-SZAVAQ6S.mjs';
3
- import { setFullscreen, setReaderProfile, setPositionsList, setTocTree, setScriptMode, setRTL, setFXL, setHasDisplayTransformability, setActionOpen, dockAction, setHovering, setSettingsContainer, debounce, setColumnCount, initialWebPubSettingsState, initialSettingsState, setWebPubFontFamily, setFontFamily, setWebPubFontWeight, setFontWeight, setWebPubHyphens, setHyphens, setScroll, setWebPubLetterSpacing, setLetterSpacing, setWebPubLineHeight, setLineHeight, setWebPubParagraphIndent, setParagraphIndent, setWebPubParagraphSpacing, setParagraphSpacing, setWebPubWordSpacing, setWordSpacing, setWebPubSpacingPreset, setWebPubPublisherStyles, setSpacingPreset, setPublisherStyles, setWebPubTextAlign, setTextAlign, setWebPubTextNormalization, setTextNormalization, setWebPubLigatures, setLigatures, setWebPubNoRuby, setNoRuby, setTheme, setWebPubZoom, setFontSize, setSkipBackwardInterval, setSkipForwardInterval, setSkipInterval, setAutoPlay, toggleActionOpen, setVolume, setPlaybackRate, setSleepTimerRemainingSeconds, setSleepTimerOnTrackEnd, setSleepTimerOnFragmentEnd, setRemotePlaybackState, ThReduxPreferencesAdapter, ThReduxGlobalPreferencesAdapter, setImmersive, setOverflow, setUserNavigated, setTocEntry, collapseDockPanel, expandDockPanel, activateDockPanel, deactivateDockPanel, setDockPanelWidth } from './chunk-YEVLT3AV.mjs';
1
+ import { makeBreakpointsMap, isKeyboardTriggered, isActiveElement } from './chunk-VYSDLACR.mjs';
2
+ import { useFullscreen, useLocalStorage, useEpubNavigator } from './chunk-2B3HE57E.mjs';
3
+ import { ErrorHandler } from './chunk-RRDEPGBK.mjs';
4
+ import { useI18n } from './chunk-2NCN2AG2.mjs';
5
+ import { setFullscreen, setReaderProfile, setPositionsList, setTocTree, setScriptMode, setRTL, setFXL, setHasDisplayTransformability, setActionOpen, dockAction, setHovering, setSettingsContainer, debounce, setColumnCount, initialWebPubSettingsState, initialSettingsState, setWebPubFontFamily, setFontFamily, setWebPubFontWeight, setFontWeight, setWebPubHyphens, setHyphens, setScroll, setWebPubLetterSpacing, setLetterSpacing, setWebPubLineHeight, setLineHeight, setWebPubParagraphIndent, setParagraphIndent, setWebPubParagraphSpacing, setParagraphSpacing, setWebPubWordSpacing, setWordSpacing, setWebPubSpacingPreset, setWebPubPublisherStyles, setSpacingPreset, setPublisherStyles, setWebPubTextAlign, setTextAlign, setWebPubTextNormalization, setTextNormalization, setWebPubLigatures, setLigatures, setWebPubNoRuby, setNoRuby, setTheme, setWebPubZoom, setFontSize, setSkipBackwardInterval, setSkipForwardInterval, setSkipInterval, setAutoPlay, toggleActionOpen, setVolume, setPlaybackRate, setSleepTimerRemainingSeconds, setSleepTimerOnTrackEnd, setSleepTimerOnFragmentEnd, setRemotePlaybackState, ThReduxPreferencesAdapter, ThReduxGlobalPreferencesAdapter, setImmersive, setOverflow, setUserNavigated, setTocEntry, collapseDockPanel, expandDockPanel, activateDockPanel, deactivateDockPanel, setDockPanelWidth } from './chunk-YE5QOQUT.mjs';
4
6
  import { buildTocTree, findTocItemById } from './chunk-TEZB4ULX.mjs';
5
- import { useSharedPreferences, useActionsPreferences, prefixString, ThDockingTypes, ThSheetTypes, useAudioPreferences, usePreferences, useFilteredPreferenceKeys, defaultSpacingSettingsSubpanel, defaultSpacingSettingsMain, defaultTextSettingsSubpanel, defaultTextSettingsMain, ThTextSettingsKeys, ThSpacingSettingsKeys, buildThemeObject, defaultAudioSkipBackwardInterval, defaultAudioSkipForwardInterval, defaultAudioSkipInterval, defaultPreferences, ThPreferencesProvider, ThGlobalPreferencesProvider } from './chunk-OD75GC5N.mjs';
7
+ import { useSharedPreferences, useActionsPreferences, prefixString, ThDockingTypes, ThSheetTypes, useAudioPreferences, usePreferences, useFilteredPreferenceKeys, defaultSpacingSettingsSubpanel, defaultSpacingSettingsMain, defaultTextSettingsSubpanel, defaultTextSettingsMain, ThTextSettingsKeys, ThSpacingSettingsKeys, buildThemeObject, defaultAudioSkipBackwardInterval, defaultAudioSkipForwardInterval, defaultAudioSkipInterval, defaultPreferences, ThPreferencesProvider, ThGlobalPreferencesProvider } from './chunk-3VB756GR.mjs';
6
8
  import { useAppDispatch, useAppSelector } from './chunk-A575ZW4A.mjs';
7
- import { isIOSish, buildShortcut, metaKeys } from './chunk-44PEO3DS.mjs';
8
- import { ErrorHandler } from './chunk-RRDEPGBK.mjs';
9
- import { ThMenuItem, ThActionButton, ThMenu, ThCollapsibleActionsBar, ThPopover, ThContainerHeader, ThNavigationButton, ThContainerBody, ThModal, ThBottomSheet, ThCloseButton, ThDockedPanel, useFirstFocusable, ThTypedComponentRenderer, useActions, useActionComponentStatus, ThForm, ThFormNumberField, usePlugins, ThSettingsWrapper, ThRadioGroup, ThDropdown, ThSwitch, ThNumberField, ThSlider, ThSliderWithPresets, ThLink, ThLibrary, ThHome, ThBackArrow, ThFormSearchField } from './chunk-ETLIGONP.mjs';
9
+ import { metaKeys } from './chunk-X63WSMOH.mjs';
10
+ import { isIOSish } from './chunk-KQ3KS5O5.mjs';
11
+ import { ThMenuItem, ThActionButton, ThMenu, ThCollapsibleActionsBar, ThPopover, ThContainerHeader, ThNavigationButton, ThContainerBody, ThModal, ThBottomSheet, ThCloseButton, ThDockedPanel, useFirstFocusable, ThTypedComponentRenderer, useActions, ThForm, ThFormNumberField, ThSettingsWrapper, ThRadioGroup, ThDropdown, ThSwitch, ThNumberField, ThSlider, ThSliderWithPresets, ThLink, ThLibrary, ThHome, ThBackArrow, ThFormSearchField } from './chunk-AXX4U2FW.mjs';
10
12
  import { usePrevious } from './chunk-YZ73DHRU.mjs';
11
- import { useI18n } from './chunk-2NCN2AG2.mjs';
12
- import { Text, Popover, Dialog, ListBox, ListBoxItem, Radio, Button, Keyboard, Toolbar, useFilter, Tree, TreeItem, TreeItemContent, Collection } from 'react-aria-components';
13
+ import React23, { createContext, useContext, useState, useEffect, useMemo, useCallback, useRef } from 'react';
13
14
  import { jsx, Fragment, jsxs } from 'react/jsx-runtime';
15
+ import { Text, Popover, Dialog, ListBox, ListBoxItem, Radio, Button, Keyboard, Toolbar, useFilter, Tree, TreeItem, TreeItemContent, Collection } from 'react-aria-components';
14
16
  import { useObjectRef, useNumberFormatter, FocusScope, useLocale, useFocusWithin } from 'react-aria';
15
17
  import classNames4 from 'classnames';
16
- import React22, { createContext, useCallback, useRef, useMemo, useContext, useState, useEffect } from 'react';
17
18
  import { Link, HttpFetcher, Manifest, Publication, ReadingProgression, Layout, Feature, Profile } from '@readium/shared';
18
- import { getScriptMode, TextAlignment } from '@readium/navigator';
19
+ import { getScriptMode, lineHeightRangeConfig, TextAlignment } from '@readium/navigator';
20
+ import i18nData from '@readium/css/css/vars/i18n.json';
19
21
  import { useStore } from 'react-redux';
20
22
  import { PanelGroup, Panel, PanelResizeHandle } from 'react-resizable-panels';
21
23
 
24
+ // src/components/Plugins/PluginRegistry.ts
25
+ var pluginsStore = [];
26
+ var PluginRegistryClass = class {
27
+ register(plugin) {
28
+ const existingPluginIndex = pluginsStore.findIndex((p) => p.id === plugin.id);
29
+ if (existingPluginIndex >= 0) {
30
+ pluginsStore[existingPluginIndex] = plugin;
31
+ } else {
32
+ pluginsStore.push(plugin);
33
+ }
34
+ }
35
+ unregister(pluginId) {
36
+ const filteredPlugins = pluginsStore.filter((plugin) => plugin.id !== pluginId);
37
+ pluginsStore.length = 0;
38
+ pluginsStore.push(...filteredPlugins);
39
+ }
40
+ getPlugins() {
41
+ return [...pluginsStore];
42
+ }
43
+ getComponentMaps() {
44
+ const actionsComponentsMap = {};
45
+ const settingsComponentsMap = {};
46
+ const primaryAudioActionsMap = {};
47
+ [...pluginsStore].reverse().forEach((plugin) => {
48
+ if (plugin.components.actions) {
49
+ Object.entries(plugin.components.actions).forEach(([key, component]) => {
50
+ actionsComponentsMap[key] = component;
51
+ });
52
+ }
53
+ if (plugin.components.settings) {
54
+ Object.entries(plugin.components.settings).forEach(([key, component]) => {
55
+ settingsComponentsMap[key] = component;
56
+ });
57
+ }
58
+ if (plugin.components.primaryAudioActions) {
59
+ Object.entries(plugin.components.primaryAudioActions).forEach(([key, component]) => {
60
+ primaryAudioActionsMap[key] = component;
61
+ });
62
+ }
63
+ });
64
+ return {
65
+ actionsComponentsMap,
66
+ settingsComponentsMap,
67
+ primaryAudioActionsMap
68
+ };
69
+ }
70
+ };
71
+ var ThPluginRegistry = new PluginRegistryClass();
72
+ var ThPluginContext = createContext({
73
+ actionsComponentsMap: {},
74
+ settingsComponentsMap: {},
75
+ textSettingsComponentsMap: {},
76
+ spacingSettingsComponentsMap: {},
77
+ primaryAudioActionsMap: {},
78
+ registerPlugin: ThPluginRegistry.register.bind(ThPluginRegistry),
79
+ unregisterPlugin: ThPluginRegistry.unregister.bind(ThPluginRegistry)
80
+ });
81
+ var usePlugins = () => useContext(ThPluginContext);
82
+ var ThPluginProvider = ({ children }) => {
83
+ const [componentMaps, setComponentMaps] = useState(() => {
84
+ const maps = ThPluginRegistry.getComponentMaps();
85
+ return {
86
+ ...maps,
87
+ textSettingsComponentsMap: getTypedSettingsComponents(maps.settingsComponentsMap, "text"),
88
+ spacingSettingsComponentsMap: getTypedSettingsComponents(maps.settingsComponentsMap, "spacing")
89
+ };
90
+ });
91
+ function getTypedSettingsComponents(componentsMap, type) {
92
+ return Object.entries(componentsMap).filter(([_, component]) => component.type === type).reduce((acc, [key, component]) => {
93
+ acc[key] = component;
94
+ return acc;
95
+ }, {});
96
+ }
97
+ useEffect(() => {
98
+ const updateComponentMaps = () => {
99
+ const maps = ThPluginRegistry.getComponentMaps();
100
+ setComponentMaps({
101
+ ...maps,
102
+ textSettingsComponentsMap: getTypedSettingsComponents(maps.settingsComponentsMap, "text"),
103
+ spacingSettingsComponentsMap: getTypedSettingsComponents(maps.settingsComponentsMap, "spacing")
104
+ });
105
+ };
106
+ updateComponentMaps();
107
+ }, []);
108
+ const registerPlugin = (plugin) => {
109
+ ThPluginRegistry.register(plugin);
110
+ };
111
+ const unregisterPlugin = (pluginId) => {
112
+ ThPluginRegistry.unregister(pluginId);
113
+ };
114
+ const value = {
115
+ ...componentMaps,
116
+ registerPlugin,
117
+ unregisterPlugin
118
+ };
119
+ return /* @__PURE__ */ jsx(ThPluginContext.Provider, { value, children });
120
+ };
121
+
122
+ // src/components/Actions/hooks/useActionComponentStatus.ts
123
+ var useActionComponentStatus = (options) => {
124
+ const { actionKey, orderArray, additionalCondition } = options;
125
+ const { actionsComponentsMap, primaryAudioActionsMap } = usePlugins();
126
+ return useMemo(() => {
127
+ const isComponentRegistered = !!actionsComponentsMap?.[actionKey] || !!primaryAudioActionsMap?.[actionKey];
128
+ const isInOrder = orderArray ? orderArray.includes(actionKey) : true;
129
+ const isComponentAvailable = isComponentRegistered && isInOrder && (additionalCondition ?? true);
130
+ return { isComponentRegistered, isInOrder, isComponentAvailable };
131
+ }, [actionKey, orderArray, additionalCondition, actionsComponentsMap, primaryAudioActionsMap]);
132
+ };
133
+
22
134
  // src/components/Actions/assets/styles/thorium-web.overflow.module.css
23
135
  var thorium_web_overflow_default = {
24
136
  hint: "thorium_web_overflow_hint",
@@ -28,40 +140,47 @@ var thorium_web_overflow_default = {
28
140
  menuItemLabel: "thorium_web_overflow_menuItemLabel",
29
141
  menuItemShortcut: "thorium_web_overflow_menuItemShortcut"
30
142
  };
31
- var UnstableStatefulShortcut = ({
143
+ var DIGIT_OFFSET = 48;
144
+ var F_KEY_OFFSET = 112;
145
+ var resolveKeyLabel = (keyCode, label, t) => {
146
+ if (label !== void 0) {
147
+ if (typeof label === "string") return label;
148
+ return t(label.key, { defaultValue: label.fallback });
149
+ }
150
+ if (keyCode >= 65 && keyCode <= 90) return String.fromCharCode(keyCode);
151
+ if (keyCode >= DIGIT_OFFSET && keyCode <= 57) return String.fromCharCode(keyCode);
152
+ if (keyCode >= F_KEY_OFFSET && keyCode <= 123) return `F${keyCode - F_KEY_OFFSET + 1}`;
153
+ return "";
154
+ };
155
+ var pickCombo = (keyCombos, platformModifier) => {
156
+ if (keyCombos.length === 1) return keyCombos[0];
157
+ const wantsCtrl = platformModifier.modifier === "ctrlKey";
158
+ const preferred = keyCombos.find((c) => wantsCtrl ? c.ctrl : c.meta);
159
+ return preferred ?? keyCombos[0];
160
+ };
161
+ var StatefulShortcut = ({
32
162
  className,
33
- rawForm,
163
+ combo,
34
164
  representation,
35
165
  joiner
36
166
  }) => {
37
167
  const { shortcuts } = useSharedPreferences();
38
168
  const platformModifier = useAppSelector((state) => state.reader.platformModifier);
39
- representation = representation ? representation : shortcuts.representation || "symbol" /* symbol */;
40
- joiner = joiner ? joiner : shortcuts.joiner || " + ";
41
- const shortcutObj = buildShortcut(rawForm);
42
- if (shortcutObj) {
43
- let shortcutRepresentation = [];
44
- for (const prop in shortcutObj.modifiers) {
45
- if (shortcutObj.modifiers[prop]) {
46
- if (prop === "platformKey") {
47
- shortcutRepresentation.push(platformModifier[representation]);
48
- } else {
49
- const metaKey = metaKeys[prop];
50
- shortcutRepresentation.push(metaKey[representation]);
51
- }
52
- }
53
- }
54
- if (shortcutObj.char) {
55
- shortcutRepresentation.push(shortcutObj.char);
56
- }
57
- if (shortcutRepresentation.length > 0) {
58
- const displayShortcut = shortcutRepresentation.join(joiner);
59
- return /* @__PURE__ */ jsx(Keyboard, { className, children: displayShortcut });
60
- } else {
61
- return /* @__PURE__ */ jsx(Fragment, {});
62
- }
63
- }
64
- return /* @__PURE__ */ jsx(Fragment, {});
169
+ const { t } = useI18n();
170
+ const rep = representation ?? shortcuts.representation ?? "symbol" /* symbol */;
171
+ const sep = joiner ?? shortcuts.joiner ?? " + ";
172
+ const { keyCombos, label } = combo;
173
+ if (!keyCombos.length) return /* @__PURE__ */ jsx(Fragment, {});
174
+ const chosen = pickCombo(keyCombos, platformModifier);
175
+ const parts = [];
176
+ if (chosen.ctrl) parts.push(metaKeys.ctrlKey[rep]);
177
+ if (chosen.alt) parts.push(metaKeys.altKey[rep]);
178
+ if (chosen.shift) parts.push(metaKeys.shiftKey[rep]);
179
+ if (chosen.meta) parts.push(metaKeys.metaKey[rep]);
180
+ const keyLabel = resolveKeyLabel(chosen.keyCode, label, t);
181
+ if (keyLabel) parts.push(keyLabel);
182
+ if (!parts.length) return /* @__PURE__ */ jsx(Fragment, {});
183
+ return /* @__PURE__ */ jsx(Keyboard, { className, children: parts.join(sep) });
65
184
  };
66
185
  var StatefulOverflowMenuItem = ({
67
186
  id,
@@ -70,6 +189,7 @@ var StatefulOverflowMenuItem = ({
70
189
  shortcut = void 0,
71
190
  ...props
72
191
  }) => {
192
+ const { shortcuts } = useSharedPreferences();
73
193
  const menuItemLabelId = `${id}-label`;
74
194
  return /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsxs(
75
195
  ThMenuItem,
@@ -90,11 +210,11 @@ var StatefulOverflowMenuItem = ({
90
210
  children: label
91
211
  }
92
212
  ),
93
- shortcut && /* @__PURE__ */ jsx(
94
- UnstableStatefulShortcut,
213
+ shortcut && shortcuts.displayIn?.includes("menuItem") && /* @__PURE__ */ jsx(
214
+ StatefulShortcut,
95
215
  {
96
216
  className: thorium_web_overflow_default.menuItemShortcut,
97
- rawForm: shortcut
217
+ combo: shortcut
98
218
  }
99
219
  )
100
220
  ]
@@ -109,6 +229,7 @@ var thorium_web_button_default = {
109
229
  closeButton: "thorium_web_button_closeButton",
110
230
  backButton: "thorium_web_button_backButton",
111
231
  tooltip: "thorium_web_button_tooltip",
232
+ tooltipShortcut: "thorium_web_button_tooltipShortcut",
112
233
  alwaysVisible: "thorium_web_button_alwaysVisible",
113
234
  partiallyVisible: "thorium_web_button_partiallyVisible",
114
235
  iconCompSm: "thorium_web_button_iconCompSm",
@@ -120,10 +241,11 @@ var StatefulActionIcon = ({
120
241
  visibility,
121
242
  placement,
122
243
  tooltipLabel,
244
+ shortcut,
123
245
  children,
124
246
  ...props
125
247
  }) => {
126
- const { theming } = useSharedPreferences();
248
+ const { theming, shortcuts } = useSharedPreferences();
127
249
  const triggerRef = useObjectRef(externalRef ?? null);
128
250
  const dispatch = useAppDispatch();
129
251
  const handleClassNameFromState = () => {
@@ -169,7 +291,10 @@ var StatefulActionIcon = ({
169
291
  placement,
170
292
  offset: theming.icon.tooltipOffset || 0
171
293
  },
172
- label: tooltipLabel
294
+ label: /* @__PURE__ */ jsxs(Fragment, { children: [
295
+ tooltipLabel,
296
+ shortcut && shortcuts.displayIn?.includes("tooltip") && /* @__PURE__ */ jsx(StatefulShortcut, { className: thorium_web_button_default.tooltipShortcut, combo: shortcut })
297
+ ] })
173
298
  } : void 0,
174
299
  ...Object.fromEntries(Object.entries(props).filter(([key]) => key !== "className")),
175
300
  children
@@ -194,7 +319,7 @@ var StatefulFullscreenTrigger = ({ variant }) => {
194
319
  fs.handleFullscreen();
195
320
  dispatch(setHovering(false));
196
321
  };
197
- if (!document.fullscreenEnabled || isIOSish()) return null;
322
+ if (!fs.isSupported) return null;
198
323
  return /* @__PURE__ */ jsx(Fragment, { children: variant && variant === "menuItem" /* menu */ ? /* @__PURE__ */ jsx(
199
324
  StatefulOverflowMenuItem,
200
325
  {
@@ -212,6 +337,7 @@ var StatefulFullscreenTrigger = ({ variant }) => {
212
337
  "aria-label": label,
213
338
  placement: "bottom",
214
339
  tooltipLabel: t("reader.fullscreen.tooltip"),
340
+ shortcut: preferences.actionsKeys["fullscreen" /* fullscreen */].shortcut,
215
341
  onPress: handlePress,
216
342
  children: /* @__PURE__ */ jsx(Icon, { "aria-hidden": "true", focusable: "false" })
217
343
  }
@@ -964,10 +1090,11 @@ var StatefulPopoverSheet = ({
964
1090
  }
965
1091
  }, [isOpen]);
966
1092
  useWebkitPatch(!!isOpen);
967
- if (React22.Children.toArray(children).length > 0) {
1093
+ if (React23.Children.toArray(children).length > 0) {
968
1094
  return /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsxs(
969
1095
  ThPopover,
970
1096
  {
1097
+ id,
971
1098
  ref: popoverRef,
972
1099
  triggerRef,
973
1100
  focusOptions: {
@@ -1073,10 +1200,11 @@ var StatefulModalBase = ({
1073
1200
  }
1074
1201
  }, [isOpen]);
1075
1202
  useWebkitPatch(!!isOpen);
1076
- if (React22.Children.toArray(children).length > 0) {
1203
+ if (React23.Children.toArray(children).length > 0) {
1077
1204
  return /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsxs(
1078
1205
  ThModal,
1079
1206
  {
1207
+ id,
1080
1208
  ref: sheetRef,
1081
1209
  focusOptions: {
1082
1210
  withinRef: focusWithinRef ?? sheetBodyRef,
@@ -1332,7 +1460,7 @@ var StatefulBottomSheet = ({
1332
1460
  return "default";
1333
1461
  }
1334
1462
  };
1335
- if (React22.Children.toArray(children).length > 0) {
1463
+ if (React23.Children.toArray(children).length > 0) {
1336
1464
  return /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsxs(
1337
1465
  ThBottomSheet,
1338
1466
  {
@@ -1370,6 +1498,7 @@ var StatefulBottomSheet = ({
1370
1498
  prefersReducedMotion,
1371
1499
  compounds: {
1372
1500
  container: {
1501
+ id,
1373
1502
  className: classNames4(thorium_web_sheets_default.draggable, detentClassName),
1374
1503
  ref: sheetContainerRef,
1375
1504
  style: {
@@ -1483,10 +1612,11 @@ var StatefulDockedSheet = ({
1483
1612
  return direction === "ltr" /* ltr */ ? thorium_web_sheets_default.dockedRightBorder : thorium_web_sheets_default.dockedLeftBorder;
1484
1613
  }
1485
1614
  }, [flow, direction]);
1486
- if (React22.Children.toArray(children).length > 0) {
1615
+ if (React23.Children.toArray(children).length > 0) {
1487
1616
  return /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsxs(
1488
1617
  ThDockedPanel,
1489
1618
  {
1619
+ id,
1490
1620
  ref: dockedSheetRef,
1491
1621
  isOpen,
1492
1622
  portal: dockPortal,
@@ -1553,6 +1683,7 @@ var StatefulDockedSheet = ({
1553
1683
  }
1554
1684
  };
1555
1685
  var StatefulCompactPopoverSheet = ({
1686
+ id,
1556
1687
  triggerRef,
1557
1688
  heading,
1558
1689
  className,
@@ -1582,7 +1713,7 @@ var StatefulCompactPopoverSheet = ({
1582
1713
  updateState: resetFocus
1583
1714
  });
1584
1715
  useWebkitPatch(!!isOpen);
1585
- if (React22.Children.toArray(children).length > 0) {
1716
+ if (React23.Children.toArray(children).length > 0) {
1586
1717
  return /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsx(
1587
1718
  Popover,
1588
1719
  {
@@ -1596,6 +1727,7 @@ var StatefulCompactPopoverSheet = ({
1596
1727
  children: /* @__PURE__ */ jsx(
1597
1728
  Dialog,
1598
1729
  {
1730
+ id,
1599
1731
  "aria-label": heading,
1600
1732
  className: thorium_web_sheets_default.dialog,
1601
1733
  children: /* @__PURE__ */ jsx(
@@ -2052,6 +2184,7 @@ var StatefulJumpToPositionTrigger = ({ variant }) => {
2052
2184
  "aria-label": t("reader.actions.goToPosition.descriptive"),
2053
2185
  placement: "bottom",
2054
2186
  tooltipLabel: t("reader.actions.goToPosition.compact"),
2187
+ shortcut: preferences.actionsKeys["jumpToPosition" /* jumpToPosition */].shortcut,
2055
2188
  onPress: () => setOpen(!actionState?.isOpen),
2056
2189
  children: /* @__PURE__ */ jsx(pin_drop_default, { "aria-hidden": "true", focusable: "false" })
2057
2190
  }
@@ -2480,6 +2613,7 @@ var StatefulSettingsTrigger = ({ variant }) => {
2480
2613
  "aria-label": isAudio ? t("reader.playback.preferences.audio.title") : t("reader.preferences.title"),
2481
2614
  placement: "bottom",
2482
2615
  tooltipLabel: isAudio ? t("reader.playback.preferences.audio.title") : t("reader.preferences.title"),
2616
+ shortcut: preferences.actionsKeys["settings" /* settings */].shortcut,
2483
2617
  onPress: () => setOpen(!actionState?.isOpen),
2484
2618
  children: isAudio ? /* @__PURE__ */ jsx(instant_mix_default, { "aria-hidden": "true", focusable: "false" }) : /* @__PURE__ */ jsx(match_case_default, { "aria-hidden": "true", focusable: "false" })
2485
2619
  }
@@ -2766,6 +2900,7 @@ var StatefulTocTrigger = ({ variant }) => {
2766
2900
  "aria-label": t("reader.tableOfContents.title"),
2767
2901
  placement: "bottom",
2768
2902
  tooltipLabel: t("reader.tableOfContents.title"),
2903
+ shortcut: preferences.actionsKeys["toc" /* toc */].shortcut,
2769
2904
  onPress: () => setOpen(!actionState?.isOpen),
2770
2905
  children: /* @__PURE__ */ jsx(toc_default, { "aria-hidden": "true", focusable: "false" })
2771
2906
  }
@@ -2804,7 +2939,7 @@ var useGridNavigation = ({
2804
2939
  onFocus
2805
2940
  }) => {
2806
2941
  const visibleColumns = useGridTemplate(containerRef, "columns");
2807
- const onKeyDown = React22.useCallback((e) => {
2942
+ const onKeyDown = React23.useCallback((e) => {
2808
2943
  const columns = visibleColumns || 1;
2809
2944
  if (columns <= 1 || !items.current?.length) return;
2810
2945
  const currentIdx = items.current.findIndex((val) => {
@@ -3052,7 +3187,7 @@ var StatefulDropdown = ({
3052
3187
  className: thorium_web_reader_settings_default.label,
3053
3188
  ...compounds?.label || {}
3054
3189
  },
3055
- ...React22.isValidElement(compounds?.button) ? { button: compounds.button } : {
3190
+ ...React23.isValidElement(compounds?.button) ? { button: compounds.button } : {
3056
3191
  button: {
3057
3192
  className: thorium_web_reader_settings_default.dropdownButton,
3058
3193
  ...compounds?.button || {}
@@ -3063,7 +3198,7 @@ var StatefulDropdown = ({
3063
3198
  placement: "bottom",
3064
3199
  ...compounds?.popover || {}
3065
3200
  },
3066
- ...React22.isValidElement(compounds?.listbox) ? { listbox: compounds.listbox } : {
3201
+ ...React23.isValidElement(compounds?.listbox) ? { listbox: compounds.listbox } : {
3067
3202
  listbox: {
3068
3203
  className: thorium_web_reader_settings_default.dropdownListbox,
3069
3204
  ...compounds?.listbox || {}
@@ -3858,14 +3993,55 @@ var StatefulLetterSpacing = ({ standalone = true }) => {
3858
3993
  }
3859
3994
  ) });
3860
3995
  };
3996
+ var ORDERED_LINE_HEIGHT_OPTIONS = ["small" /* small */, "medium" /* medium */, "large" /* large */];
3997
+ function spreadValues(values, globalMin, globalMax) {
3998
+ const n = values.length;
3999
+ if (n <= 1) return values;
4000
+ const indexed = values.map((v, i) => ({ v, i })).sort((a, b) => a.v - b.v);
4001
+ if (indexed.every((item, i) => i === 0 || item.v !== indexed[i - 1].v)) return values;
4002
+ const lo = indexed[0].v === indexed[n - 1].v ? globalMin : indexed[0].v;
4003
+ const hi = indexed[0].v === indexed[n - 1].v ? globalMax : indexed[n - 1].v;
4004
+ const step = (hi - lo) / (n - 1);
4005
+ const result = new Array(n);
4006
+ for (let i = 0; i < n; i++) result[indexed[i].i] = lo + i * step;
4007
+ return result;
4008
+ }
4009
+ var getLineHeightCompensation = (language) => {
4010
+ const data = i18nData;
4011
+ if (data[language]?.lineHeightCompensation !== void 0) return data[language].lineHeightCompensation;
4012
+ const stripped = language.split("-").slice(0, -1).join("-");
4013
+ if (stripped && data[stripped]?.lineHeightCompensation !== void 0) return data[stripped].lineHeightCompensation;
4014
+ return data.latin?.lineHeightCompensation ?? 1;
4015
+ };
3861
4016
  var useLineHeight = () => {
3862
4017
  const { preferences } = usePreferences();
3863
- return useMemo(() => ({
3864
- ["publisher" /* publisher */]: null,
3865
- ["small" /* small */]: preferences.settings.keys["lineHeight" /* lineHeight */].keys["small" /* small */],
3866
- ["medium" /* medium */]: preferences.settings.keys["lineHeight" /* lineHeight */].keys["medium" /* medium */],
3867
- ["large" /* large */]: preferences.settings.keys["lineHeight" /* lineHeight */].keys["large" /* large */]
3868
- }), [preferences.settings.keys]);
4018
+ const fontLanguage = useAppSelector((state) => state.publication.fontLanguage);
4019
+ return useMemo(() => {
4020
+ const keys = preferences.settings.keys["lineHeight" /* lineHeight */].keys;
4021
+ const factor = getLineHeightCompensation(fontLanguage);
4022
+ const values = {
4023
+ ["publisher" /* publisher */]: null,
4024
+ ["small" /* small */]: keys["small" /* small */],
4025
+ ["medium" /* medium */]: keys["medium" /* medium */],
4026
+ ["large" /* large */]: keys["large" /* large */]
4027
+ };
4028
+ const compensate = (v) => v !== null ? v * factor : null;
4029
+ const compensatedValues = {
4030
+ ["publisher" /* publisher */]: null,
4031
+ ["small" /* small */]: compensate(values["small" /* small */]),
4032
+ ["medium" /* medium */]: compensate(values["medium" /* medium */]),
4033
+ ["large" /* large */]: compensate(values["large" /* large */])
4034
+ };
4035
+ const [minRange, maxRange] = lineHeightRangeConfig.range;
4036
+ const clamp = (v) => v === null ? minRange : Math.min(Math.max(v, minRange), maxRange);
4037
+ const ordered = ORDERED_LINE_HEIGHT_OPTIONS;
4038
+ const clamped = ordered.map((key) => clamp(compensatedValues[key]));
4039
+ const processed = spreadValues(clamped, minRange, maxRange);
4040
+ const processedValues = Object.fromEntries(
4041
+ ordered.map((key, i) => [key, processed[i]])
4042
+ );
4043
+ return { values, compensatedValues, processedValues, compensate };
4044
+ }, [preferences.settings.keys, fontLanguage]);
3869
4045
  };
3870
4046
  var SvgBook = (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: "M240-80q-33 0-56.5-23.5T160-160v-640q0-33 23.5-56.5T240-880h480q33 0 56.5 23.5T800-800v640q0 33-23.5 56.5T720-80H240Zm0-80h480v-640h-80v280l-100-60-100 60v-280H240v640Zm0 0v-640 640Zm200-360 100-60 100 60-100-60-100 60Z" }) });
3871
4047
  var book_default = SvgBook;
@@ -3881,20 +4057,18 @@ var StatefulLineHeight = ({ standalone = true }) => {
3881
4057
  const profile = useAppSelector((state) => state.reader.profile);
3882
4058
  const isWebPub = profile === "webPub";
3883
4059
  const publisherStyles = useReaderSetting("publisherStyles");
3884
- const { getSetting, submitPreferences, preferencesEditor } = useNavigator().visual;
4060
+ const { getSetting, submitPreferences } = useNavigator().visual;
3885
4061
  const prefKey = SETTINGS_KEY_TO_PREFERENCE["lineHeight" /* lineHeight */];
3886
4062
  const { getEffectiveSpacingValue, setLineHeight: setLineHeight2 } = useSpacingPresets();
3887
4063
  const lineHeight = getEffectiveSpacingValue("lineHeight" /* lineHeight */);
3888
- const lineHeightOptions = useLineHeight();
3889
- const lineHeightNumericValues = useMemo(
3890
- () => Object.values(lineHeightOptions).filter((v) => v !== null),
3891
- [lineHeightOptions]
3892
- );
3893
- const { presets: effectivePresets } = useEffectiveRange(
3894
- [Math.min(...lineHeightNumericValues), Math.max(...lineHeightNumericValues)],
3895
- preferencesEditor?.lineHeight?.supportedRange,
3896
- lineHeightNumericValues
3897
- );
4064
+ const { processedValues } = useLineHeight();
4065
+ const processedPresets = useMemo(() => {
4066
+ const result = /* @__PURE__ */ new Map();
4067
+ result.set("small" /* small */, processedValues["small" /* small */]);
4068
+ result.set("medium" /* medium */, processedValues["medium" /* medium */]);
4069
+ result.set("large" /* large */, processedValues["large" /* large */]);
4070
+ return result;
4071
+ }, [processedValues]);
3898
4072
  const items = useMemo(() => {
3899
4073
  const baseItems = [
3900
4074
  {
@@ -3915,10 +4089,7 @@ var StatefulLineHeight = ({ standalone = true }) => {
3915
4089
  label: t("reader.preferences.lineHeight.large"),
3916
4090
  value: "large" /* large */
3917
4091
  }
3918
- ].filter((item) => {
3919
- const v = lineHeightOptions[item.id];
3920
- return effectivePresets === void 0 || effectivePresets.includes(v);
3921
- });
4092
+ ].filter((item) => processedPresets.has(item.id));
3922
4093
  if (preferences.settings.keys["lineHeight" /* lineHeight */].allowUnset !== false) {
3923
4094
  baseItems.unshift({
3924
4095
  id: "publisher" /* publisher */,
@@ -3928,16 +4099,16 @@ var StatefulLineHeight = ({ standalone = true }) => {
3928
4099
  });
3929
4100
  }
3930
4101
  return baseItems;
3931
- }, [preferences.settings.keys, lineHeightOptions, effectivePresets, t]);
4102
+ }, [preferences.settings.keys, processedPresets, t]);
3932
4103
  const updatePreference = useCallback(async (value) => {
3933
- const computedValue = value === "publisher" /* publisher */ ? null : lineHeightOptions[value];
4104
+ const submitValue = value === "publisher" /* publisher */ ? null : processedPresets.get(value) ?? null;
3934
4105
  await submitPreferences({
3935
- [prefKey]: computedValue
4106
+ [prefKey]: submitValue
3936
4107
  });
3937
- const currentLineHeight = getSetting(prefKey);
3938
- const currentDisplayLineHeightOption = Object.entries(lineHeightOptions).find(([_key, value2]) => value2 === currentLineHeight)?.[0];
4108
+ const storedLineHeight = getSetting(prefKey);
4109
+ const currentDisplayLineHeightOption = [...processedPresets.entries()].find(([, v]) => v === storedLineHeight)?.[0];
3939
4110
  setLineHeight2(currentDisplayLineHeightOption);
3940
- }, [prefKey, submitPreferences, getSetting, setLineHeight2, lineHeightOptions]);
4111
+ }, [prefKey, submitPreferences, getSetting, setLineHeight2, processedPresets]);
3941
4112
  return /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsx(
3942
4113
  StatefulRadioGroup,
3943
4114
  {
@@ -4113,7 +4284,7 @@ var StatefulPublisherStyles = ({ standalone = true }) => {
4113
4284
  const paragraphSpacing = getEffectiveSpacingValue("paragraphSpacing" /* paragraphSpacing */);
4114
4285
  const letterSpacing = getEffectiveSpacingValue("letterSpacing" /* letterSpacing */);
4115
4286
  const wordSpacing = getEffectiveSpacingValue("wordSpacing" /* wordSpacing */);
4116
- const lineHeightOptions = useLineHeight();
4287
+ const { compensatedValues: lineHeightOptions } = useLineHeight();
4117
4288
  const { submitPreferences } = useNavigator().visual;
4118
4289
  const lineHeightPrefKey = SETTINGS_KEY_TO_PREFERENCE["lineHeight" /* lineHeight */];
4119
4290
  const paragraphIndentPrefKey = SETTINGS_KEY_TO_PREFERENCE["paragraphIndent" /* paragraphIndent */];
@@ -4206,7 +4377,7 @@ var StatefulSpacingPresets = ({ standalone }) => {
4206
4377
  const paragraphIndentPrefKey = SETTINGS_KEY_TO_PREFERENCE["paragraphIndent" /* paragraphIndent */];
4207
4378
  const paragraphSpacingPrefKey = SETTINGS_KEY_TO_PREFERENCE["paragraphSpacing" /* paragraphSpacing */];
4208
4379
  const wordSpacingPrefKey = SETTINGS_KEY_TO_PREFERENCE["wordSpacing" /* wordSpacing */];
4209
- const lineHeightOptions = useLineHeight();
4380
+ const { values: lineHeightOptions, compensate: compensateLineHeight } = useLineHeight();
4210
4381
  const { getPresetValues } = useSpacingPresets();
4211
4382
  const publicationType = isWebPub ? "webpub" : isFXL ? "fxl" : "reflow";
4212
4383
  const { isComponentUsed: isLetterSpacingUsed } = useSettingsComponentStatus({
@@ -4240,7 +4411,7 @@ var StatefulSpacingPresets = ({ standalone }) => {
4240
4411
  ["wordSpacing" /* wordSpacing */]: presetValues?.["wordSpacing" /* wordSpacing */] ?? null
4241
4412
  };
4242
4413
  const lineHeightValue = reduxValues["lineHeight" /* lineHeight */];
4243
- const lineHeightValueNumber = lineHeightValue && lineHeightValue !== "publisher" /* publisher */ ? lineHeightOptions[lineHeightValue] : null;
4414
+ const lineHeightValueNumber = lineHeightValue && lineHeightValue !== "publisher" /* publisher */ ? compensateLineHeight(lineHeightOptions[lineHeightValue]) : null;
4244
4415
  const preferencesToSubmit = {};
4245
4416
  if (isLetterSpacingUsed) {
4246
4417
  preferencesToSubmit[letterSpacingPrefKey] = reduxValues["letterSpacing" /* letterSpacing */];
@@ -4269,7 +4440,7 @@ var StatefulSpacingPresets = ({ standalone }) => {
4269
4440
  values: reduxValues
4270
4441
  }));
4271
4442
  }
4272
- }, [isWebPub, dispatch, submitPreferences, getPresetValues, lineHeightOptions, letterSpacingPrefKey, lineHeightPrefKey, paragraphIndentPrefKey, paragraphSpacingPrefKey, wordSpacingPrefKey, isLetterSpacingUsed, isLineHeightUsed, isParagraphIndentUsed, isParagraphSpacingUsed, isWordSpacingUsed]);
4443
+ }, [isWebPub, dispatch, submitPreferences, getPresetValues, lineHeightOptions, compensateLineHeight, letterSpacingPrefKey, lineHeightPrefKey, paragraphIndentPrefKey, paragraphSpacingPrefKey, wordSpacingPrefKey, isLetterSpacingUsed, isLineHeightUsed, isParagraphIndentUsed, isParagraphSpacingUsed, isWordSpacingUsed]);
4273
4444
  const spacingKeys = useMemo(() => {
4274
4445
  const baseKeys = isWebPub ? webPubSpacingPresetKeys : isFXL ? fxlSpacingPresetKeys : reflowSpacingPresetKeys;
4275
4446
  const subPanelKeys = subPanelSpacingSettingsKeys || [];
@@ -4750,7 +4921,7 @@ var createDefaultPlugin = () => {
4750
4921
  id: "core",
4751
4922
  name: "Core Components",
4752
4923
  description: "Default components for Thorium Web Epub StatefulReader",
4753
- version: "1.4.0",
4924
+ version: "1.5.1",
4754
4925
  components: {
4755
4926
  actions: {
4756
4927
  ["fullscreen" /* fullscreen */]: {
@@ -5344,6 +5515,8 @@ var StatefulAudioVolumeTrigger = ({ ref }) => {
5344
5515
  const { t } = useI18n();
5345
5516
  const profile = useAppSelector((state) => state.reader.profile);
5346
5517
  const { preferences } = useAudioPreferences();
5518
+ const { actionsKeys } = useActionsPreferences();
5519
+ const shortcut = actionsKeys["audio.volume" /* volume */]?.shortcut;
5347
5520
  const { preferencesEditor } = useNavigator().media;
5348
5521
  const volume = useAppSelector((state) => state.audioSettings.volume);
5349
5522
  const isTrackReady = useAppSelector((state) => state.player.isTrackReady);
@@ -5365,6 +5538,7 @@ var StatefulAudioVolumeTrigger = ({ ref }) => {
5365
5538
  {
5366
5539
  ref,
5367
5540
  tooltipLabel: t("reader.playback.preferences.audio.volume"),
5541
+ shortcut,
5368
5542
  placement: "top",
5369
5543
  onPress: () => {
5370
5544
  if (profile) {
@@ -5448,6 +5622,8 @@ var thorium_web_playbackRate_default = {
5448
5622
  var StatefulAudioPlaybackRateTrigger = ({ ref }) => {
5449
5623
  const { t } = useI18n();
5450
5624
  const profile = useAppSelector((state) => state.reader.profile);
5625
+ const { actionsKeys } = useActionsPreferences();
5626
+ const shortcut = actionsKeys["audio.playbackRate" /* playbackRate */]?.shortcut;
5451
5627
  const playbackRate = useAppSelector((state) => state.audioSettings.playbackRate);
5452
5628
  const isTrackReady = useAppSelector((state) => state.player.isTrackReady);
5453
5629
  const isStalled = useAppSelector((state) => state.player.isStalled);
@@ -5458,6 +5634,7 @@ var StatefulAudioPlaybackRateTrigger = ({ ref }) => {
5458
5634
  {
5459
5635
  ref,
5460
5636
  tooltipLabel: t("reader.playback.preferences.playbackRate.descriptive"),
5637
+ shortcut,
5461
5638
  placement: "top",
5462
5639
  onPress: () => {
5463
5640
  if (profile) {
@@ -5563,6 +5740,8 @@ var thorium_web_audioToc_default = {
5563
5740
  var StatefulAudioTocTrigger = ({ ref }) => {
5564
5741
  const { t } = useI18n();
5565
5742
  const profile = useAppSelector((state) => state.reader.profile);
5743
+ const { actionsKeys } = useActionsPreferences();
5744
+ const shortcut = actionsKeys["audio.toc" /* toc */]?.shortcut;
5566
5745
  const isTrackReady = useAppSelector((state) => state.player.isTrackReady);
5567
5746
  const isStalled = useAppSelector((state) => state.player.isStalled);
5568
5747
  const isDisabled = !isTrackReady || isStalled;
@@ -5572,6 +5751,7 @@ var StatefulAudioTocTrigger = ({ ref }) => {
5572
5751
  {
5573
5752
  ref,
5574
5753
  tooltipLabel: t("reader.tableOfContents.title"),
5754
+ shortcut,
5575
5755
  placement: "top",
5576
5756
  onPress: () => {
5577
5757
  if (profile) {
@@ -5691,6 +5871,8 @@ var thorium_web_sleepTimer_default = {
5691
5871
  var StatefulAudioSleepTimerTrigger = ({ ref }) => {
5692
5872
  const { t } = useI18n();
5693
5873
  const profile = useAppSelector((state) => state.reader.profile);
5874
+ const { actionsKeys } = useActionsPreferences();
5875
+ const shortcut = actionsKeys["audio.sleepTimer" /* sleepTimer */]?.shortcut;
5694
5876
  const remainingSeconds = useAppSelector((state) => state.player.sleepTimer.remainingSeconds);
5695
5877
  const onTrackEnd = useAppSelector((state) => state.player.sleepTimer.onTrackEnd);
5696
5878
  const onFragmentEnd = useAppSelector((state) => state.player.sleepTimer.onFragmentEnd);
@@ -5713,6 +5895,7 @@ var StatefulAudioSleepTimerTrigger = ({ ref }) => {
5713
5895
  {
5714
5896
  ref,
5715
5897
  tooltipLabel: t("reader.playback.preferences.sleepTimer.descriptive"),
5898
+ shortcut,
5716
5899
  placement: "top",
5717
5900
  onPress: () => {
5718
5901
  if (profile) {
@@ -6014,7 +6197,7 @@ var createAudioDefaultPlugin = () => {
6014
6197
  id: "audio-core",
6015
6198
  name: "Audio Core Components",
6016
6199
  description: "Default components for Thorium Web Audio StatefulReader",
6017
- version: "1.4.0",
6200
+ version: "1.5.1",
6018
6201
  components: {
6019
6202
  actions: {
6020
6203
  ["settings" /* settings */]: {
@@ -6385,6 +6568,70 @@ var StatefulDockingWrapper = ({
6385
6568
  }
6386
6569
  };
6387
6570
 
6571
+ // src/helpers/peripherals.ts
6572
+ var NavPeripheralType = {
6573
+ progressForward: "th_nav_progress_forward",
6574
+ progressBackward: "th_nav_progress_backward",
6575
+ moveRight: "th_nav_move_right",
6576
+ moveLeft: "th_nav_move_left",
6577
+ moveUp: "th_nav_move_up",
6578
+ moveDown: "th_nav_move_down",
6579
+ moveHome: "th_nav_move_home",
6580
+ moveEnd: "th_nav_move_end",
6581
+ zoomIn: "th_nav_zoom_in",
6582
+ zoomOut: "th_nav_zoom_out"
6583
+ };
6584
+ var ZOOM_IN_KEY_COMBOS = [
6585
+ { keyCode: 187, ctrl: true },
6586
+ { keyCode: 61, ctrl: true },
6587
+ { keyCode: 107, ctrl: true },
6588
+ { keyCode: 187, meta: true },
6589
+ { keyCode: 61, meta: true },
6590
+ { keyCode: 107, meta: true }
6591
+ ];
6592
+ var ZOOM_OUT_KEY_COMBOS = [
6593
+ { keyCode: 189, ctrl: true },
6594
+ { keyCode: 173, ctrl: true },
6595
+ { keyCode: 109, ctrl: true },
6596
+ { keyCode: 189, meta: true },
6597
+ { keyCode: 173, meta: true },
6598
+ { keyCode: 109, meta: true }
6599
+ ];
6600
+ var ACTION_PERIPHERAL_PREFIX = "th_action_";
6601
+ var toActionPeripheralType = (key) => `${ACTION_PERIPHERAL_PREFIX}${key}`;
6602
+ var fromActionPeripheralType = (type) => type.startsWith(ACTION_PERIPHERAL_PREFIX) ? type.slice(ACTION_PERIPHERAL_PREFIX.length) : null;
6603
+ var DOCKING_PERIPHERAL_PREFIX = "th_docking_";
6604
+ var toDockingPeripheralType = (key) => `${DOCKING_PERIPHERAL_PREFIX}${key}`;
6605
+ var fromDockingPeripheralType = (type) => type.startsWith(DOCKING_PERIPHERAL_PREFIX) ? type.slice(DOCKING_PERIPHERAL_PREFIX.length) : null;
6606
+ var useFocusedDockableKey = () => {
6607
+ const { actionsKeys } = useActionsPreferences();
6608
+ return useCallback((dockingKey) => {
6609
+ const active = document.activeElement;
6610
+ if (!active) return null;
6611
+ const checkKey = (key) => {
6612
+ const dockable = actionsKeys[key]?.docked?.dockable;
6613
+ if (!dockable || dockable === "none" /* none */) return false;
6614
+ return dockingKey === "dockingTransient" /* transient */ || dockingKey === "dockingStart" /* start */ && (dockable === "start" /* start */ || dockable === "both" /* both */) || dockingKey === "dockingEnd" /* end */ && (dockable === "end" /* end */ || dockable === "both" /* both */);
6615
+ };
6616
+ let el = active;
6617
+ while (el) {
6618
+ const id = el.getAttribute("id");
6619
+ if (id) {
6620
+ if (checkKey(id)) return id;
6621
+ const keyFromId = Object.keys(actionsKeys).find((k) => id.startsWith(`${k}-`));
6622
+ if (keyFromId && checkKey(keyFromId)) return keyFromId;
6623
+ }
6624
+ const dataKey = el.getAttribute("data-key");
6625
+ if (dataKey) {
6626
+ const key = dataKey.slice(dataKey.lastIndexOf("-") + 1);
6627
+ if (key && checkKey(key)) return key;
6628
+ }
6629
+ el = el.parentElement;
6630
+ }
6631
+ return null;
6632
+ }, [actionsKeys]);
6633
+ };
6634
+
6388
6635
  // src/components/assets/styles/thorium-web.reader.header.module.css
6389
6636
  var thorium_web_reader_header_default = {
6390
6637
  header: "thorium_web_reader_header_header",
@@ -6468,7 +6715,7 @@ var StatefulBackLink = ({
6468
6715
  for (const { name, value } of Array.from(svgElement.attributes)) {
6469
6716
  attributes[name] = value;
6470
6717
  }
6471
- contentNode = React22.createElement("svg", {
6718
+ contentNode = React23.createElement("svg", {
6472
6719
  ...attributes,
6473
6720
  "aria-hidden": "true",
6474
6721
  focusable: "false",
@@ -6572,6 +6819,6 @@ var useReaderHeaderBase = (actionKeys) => {
6572
6819
  };
6573
6820
  };
6574
6821
 
6575
- export { NavigatorProvider, StatefulActionIcon, StatefulAudioAutoPlay, StatefulAudioPlaybackRateContainer, StatefulAudioPlaybackRateTrigger, StatefulAudioRemotePlaybackTrigger, StatefulAudioSettingsContainer, StatefulAudioSkipBackwardInterval, StatefulAudioSkipForwardInterval, StatefulAudioSkipInterval, StatefulAudioSleepTimerContainer, StatefulAudioSleepTimerTrigger, StatefulAudioTocContainer, StatefulAudioTocTrigger, StatefulAudioVolumeContainer, StatefulAudioVolumeTrigger, StatefulBackLink, StatefulBottomSheet, StatefulCollapsibleActionsBar, StatefulColumns, StatefulCompactPopoverSheet, StatefulDockedSheet, StatefulDockingWrapper, StatefulDropdown, StatefulFontFamily, StatefulFullScreenSheet, StatefulFullscreenTrigger, StatefulGlobalPreferencesProvider, StatefulGroupWrapper, StatefulHyphens, StatefulJumpToPositionContainer, StatefulJumpToPositionTrigger, StatefulLayout, StatefulLetterSpacing, StatefulLigatures, StatefulLineHeight, StatefulModalBase, StatefulModalSheet, StatefulNoRuby, StatefulNumberField, StatefulOverflowMenu, StatefulOverflowMenuItem, StatefulParagraphIndent, StatefulParagraphSpacing, StatefulPopoverSheet, StatefulPreferencesProvider, StatefulPublisherStyles, StatefulRadioGroup, StatefulSettingsTrigger, StatefulSettingsWrapper, StatefulSheetWrapper, StatefulSlider, StatefulSliderWithPresets, StatefulSpacingGroup, StatefulSpacingGroupContainer, StatefulSpacingPresets, StatefulSwitch, StatefulTextAlign, StatefulTextGroup, StatefulTextGroupContainer, StatefulTextNormalize, StatefulTheme, StatefulTocContainer, StatefulTocTrigger, StatefulVisualSettingsContainer, StatefulWordSpacing, StatefulZoom, UnstableStatefulFontWeight, createAudioDefaultPlugin, createDefaultPlugin, thorium_web_button_default, thorium_web_overflow_default, thorium_web_reader_app_default, thorium_web_reader_header_default, useDocking, useEffectiveRange, useGridNavigation, useGridTemplate, useIsScroll, useLineHeight, useNavigator, usePlaceholder, usePositionStorage, usePublication, useReaderHeaderBase, useReaderSetting, useReaderTransitions, useSettingsComponentStatus, useSpacingPresets };
6576
- //# sourceMappingURL=chunk-MSHUPSBI.mjs.map
6577
- //# sourceMappingURL=chunk-MSHUPSBI.mjs.map
6822
+ export { NavPeripheralType, NavigatorProvider, ORDERED_LINE_HEIGHT_OPTIONS, StatefulActionIcon, StatefulAudioAutoPlay, StatefulAudioPlaybackRateContainer, StatefulAudioPlaybackRateTrigger, StatefulAudioRemotePlaybackTrigger, StatefulAudioSettingsContainer, StatefulAudioSkipBackwardInterval, StatefulAudioSkipForwardInterval, StatefulAudioSkipInterval, StatefulAudioSleepTimerContainer, StatefulAudioSleepTimerTrigger, StatefulAudioTocContainer, StatefulAudioTocTrigger, StatefulAudioVolumeContainer, StatefulAudioVolumeTrigger, StatefulBackLink, StatefulBottomSheet, StatefulCollapsibleActionsBar, StatefulColumns, StatefulCompactPopoverSheet, StatefulDockedSheet, StatefulDockingWrapper, StatefulDropdown, StatefulFontFamily, StatefulFullScreenSheet, StatefulFullscreenTrigger, StatefulGlobalPreferencesProvider, StatefulGroupWrapper, StatefulHyphens, StatefulJumpToPositionContainer, StatefulJumpToPositionTrigger, StatefulLayout, StatefulLetterSpacing, StatefulLigatures, StatefulLineHeight, StatefulModalBase, StatefulModalSheet, StatefulNoRuby, StatefulNumberField, StatefulOverflowMenu, StatefulOverflowMenuItem, StatefulParagraphIndent, StatefulParagraphSpacing, StatefulPopoverSheet, StatefulPreferencesProvider, StatefulPublisherStyles, StatefulRadioGroup, StatefulSettingsTrigger, StatefulSettingsWrapper, StatefulSheetWrapper, StatefulSlider, StatefulSliderWithPresets, StatefulSpacingGroup, StatefulSpacingGroupContainer, StatefulSpacingPresets, StatefulSwitch, StatefulTextAlign, StatefulTextGroup, StatefulTextGroupContainer, StatefulTextNormalize, StatefulTheme, StatefulTocContainer, StatefulTocTrigger, StatefulVisualSettingsContainer, StatefulWordSpacing, StatefulZoom, ThPluginProvider, ThPluginRegistry, UnstableStatefulFontWeight, ZOOM_IN_KEY_COMBOS, ZOOM_OUT_KEY_COMBOS, createAudioDefaultPlugin, createDefaultPlugin, fromActionPeripheralType, fromDockingPeripheralType, thorium_web_button_default, thorium_web_overflow_default, thorium_web_reader_app_default, thorium_web_reader_header_default, toActionPeripheralType, toDockingPeripheralType, useActionComponentStatus, useDocking, useEffectiveRange, useFocusedDockableKey, useGridNavigation, useGridTemplate, useIsScroll, useLineHeight, useNavigator, usePlaceholder, usePlugins, usePositionStorage, usePublication, useReaderHeaderBase, useReaderSetting, useReaderTransitions, useSettingsComponentStatus, useSpacingPresets };
6823
+ //# sourceMappingURL=chunk-THOJRBVD.mjs.map
6824
+ //# sourceMappingURL=chunk-THOJRBVD.mjs.map