@readium/navigator 2.2.0 → 2.2.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 (48) hide show
  1. package/dist/index.js +1886 -1321
  2. package/dist/index.umd.cjs +218 -17
  3. package/package.json +1 -1
  4. package/src/css/Properties.ts +47 -0
  5. package/src/css/index.ts +1 -0
  6. package/src/epub/css/Properties.ts +10 -48
  7. package/src/epub/preferences/EpubDefaults.ts +1 -1
  8. package/src/epub/preferences/EpubPreferences.ts +1 -1
  9. package/src/epub/preferences/EpubPreferencesEditor.ts +30 -23
  10. package/src/index.ts +2 -1
  11. package/src/preferences/Types.ts +40 -0
  12. package/src/{epub/preferences → preferences}/guards.ts +5 -6
  13. package/src/preferences/index.ts +2 -1
  14. package/src/webpub/WebPubBlobBuilder.ts +26 -4
  15. package/src/webpub/WebPubFrameManager.ts +16 -0
  16. package/src/webpub/WebPubFramePoolManager.ts +49 -2
  17. package/src/webpub/WebPubNavigator.ts +87 -10
  18. package/src/webpub/css/Properties.ts +71 -0
  19. package/src/webpub/css/WebPubCSS.ts +42 -0
  20. package/src/webpub/css/WebPubStylesheet.ts +204 -0
  21. package/src/webpub/css/index.ts +3 -0
  22. package/src/webpub/index.ts +3 -1
  23. package/src/webpub/preferences/WebPubDefaults.ts +61 -0
  24. package/src/webpub/preferences/WebPubPreferences.ts +88 -0
  25. package/src/webpub/preferences/WebPubPreferencesEditor.ts +193 -0
  26. package/src/webpub/preferences/WebPubSettings.ts +88 -0
  27. package/src/webpub/preferences/index.ts +4 -0
  28. package/types/src/css/Properties.d.ts +20 -0
  29. package/types/src/css/index.d.ts +1 -0
  30. package/types/src/epub/css/Properties.d.ts +1 -21
  31. package/types/src/index.d.ts +1 -0
  32. package/types/src/preferences/Types.d.ts +8 -0
  33. package/types/src/preferences/guards.d.ts +9 -0
  34. package/types/src/preferences/index.d.ts +1 -0
  35. package/types/src/webpub/WebPubBlobBuilder.d.ts +5 -1
  36. package/types/src/webpub/WebPubFrameManager.d.ts +4 -0
  37. package/types/src/webpub/WebPubFramePoolManager.d.ts +8 -1
  38. package/types/src/webpub/WebPubNavigator.d.ts +23 -3
  39. package/types/src/webpub/css/Properties.d.ts +36 -0
  40. package/types/src/webpub/css/WebPubCSS.d.ts +10 -0
  41. package/types/src/webpub/css/WebPubStylesheet.d.ts +1 -0
  42. package/types/src/webpub/css/index.d.ts +3 -0
  43. package/types/src/webpub/index.d.ts +2 -0
  44. package/types/src/webpub/preferences/WebPubDefaults.d.ts +32 -0
  45. package/types/src/webpub/preferences/WebPubPreferences.d.ts +36 -0
  46. package/types/src/webpub/preferences/WebPubPreferencesEditor.d.ts +27 -0
  47. package/types/src/webpub/preferences/WebPubSettings.d.ts +35 -0
  48. package/types/src/webpub/preferences/index.d.ts +4 -0
@@ -1,9 +1,22 @@
1
1
  import { Link, Locator, Publication, ReadingProgression, LocatorLocations } from "@readium/shared";
2
2
  import { VisualNavigator, VisualNavigatorViewport, ProgressionRange } from "../Navigator";
3
+ import { Configurable } from "../preferences/Configurable";
3
4
  import { WebPubFramePoolManager } from "./WebPubFramePoolManager";
4
5
  import { BasicTextSelection, CommsEventKey, FrameClickEvent, ModuleLibrary, ModuleName, WebPubModules } from "@readium/navigator-html-injectables";
5
6
  import * as path from "path-browserify";
6
7
  import { ManagerEventKey } from "../epub/EpubNavigator";
8
+ import { WebPubCSS } from "./css/WebPubCSS";
9
+ import { WebUserProperties } from "./css/Properties";
10
+ import { IWebPubPreferences, WebPubPreferences } from "./preferences/WebPubPreferences";
11
+ import { IWebPubDefaults, WebPubDefaults } from "./preferences/WebPubDefaults";
12
+ import { WebPubSettings } from "./preferences/WebPubSettings";
13
+ import { IPreferencesEditor } from "../preferences/PreferencesEditor";
14
+ import { WebPubPreferencesEditor } from "./preferences/WebPubPreferencesEditor";
15
+
16
+ export interface WebPubNavigatorConfiguration {
17
+ preferences: IWebPubPreferences;
18
+ defaults: IWebPubDefaults;
19
+ }
7
20
 
8
21
  export interface WebPubNavigatorListeners {
9
22
  frameLoaded: (wnd: Window) => void;
@@ -27,27 +40,43 @@ const defaultListeners = (listeners: WebPubNavigatorListeners): WebPubNavigatorL
27
40
  customEvent: listeners.customEvent || (() => {}),
28
41
  handleLocator: listeners.handleLocator || (() => false),
29
42
  textSelected: listeners.textSelected || (() => {})
30
- });
43
+ })
31
44
 
32
- class WebPubNavigator extends VisualNavigator {
45
+ export class WebPubNavigator extends VisualNavigator implements Configurable<WebPubSettings, WebPubPreferences> {
33
46
  private readonly pub: Publication;
34
47
  private readonly container: HTMLElement;
35
48
  private readonly listeners: WebPubNavigatorListeners;
36
- private framePool: WebPubFramePoolManager;
49
+ private framePool!: WebPubFramePoolManager;
37
50
  private currentIndex: number = 0;
38
51
  private currentLocation: Locator;
52
+
53
+ private _preferences: WebPubPreferences;
54
+ private _defaults: WebPubDefaults;
55
+ private _settings: WebPubSettings;
56
+ private _css: WebPubCSS;
57
+ private _preferencesEditor: WebPubPreferencesEditor | null = null;
58
+
39
59
  private webViewport: VisualNavigatorViewport = {
40
60
  readingOrder: [],
41
61
  progressions: new Map(),
42
62
  positions: null
43
63
  };
44
64
 
45
- constructor(container: HTMLElement, pub: Publication, listeners: WebPubNavigatorListeners, initialPosition: Locator | undefined = undefined) {
65
+ constructor(container: HTMLElement, pub: Publication, listeners: WebPubNavigatorListeners, initialPosition: Locator | undefined = undefined, configuration: WebPubNavigatorConfiguration = { preferences: {}, defaults: {} }) {
46
66
  super();
47
67
  this.pub = pub;
48
68
  this.container = container;
49
69
  this.listeners = defaultListeners(listeners);
50
- this.framePool = new WebPubFramePoolManager(this.container);
70
+
71
+ // Initialize preference system
72
+ this._preferences = new WebPubPreferences(configuration.preferences);
73
+ this._defaults = new WebPubDefaults(configuration.defaults);
74
+ this._settings = new WebPubSettings(this._preferences, this._defaults);
75
+ this._css = new WebPubCSS({
76
+ userProperties: new WebUserProperties({ zoom: this._settings.zoom })
77
+ });
78
+
79
+ // Initialize current location
51
80
  if (initialPosition && typeof initialPosition.copyWithLocations === 'function') {
52
81
  this.currentLocation = initialPosition;
53
82
  // Update currentIndex to match the initial position
@@ -60,13 +89,61 @@ class WebPubNavigator extends VisualNavigator {
60
89
  }
61
90
  }
62
91
 
63
- async load(): Promise<void> {
64
- await this.framePool.update(this.pub, this.currentLocation, this.determineModules());
92
+ public async load() {
93
+ await this.updateCSS(false);
94
+ const cssProperties = this.compileCSSProperties(this._css);
95
+ this.framePool = new WebPubFramePoolManager(this.container, cssProperties);
65
96
 
66
- this.attachListener();
97
+ await this.apply();
98
+ }
67
99
 
68
- // Notify listeners of initial position
69
- this.listeners.positionChanged(this.currentLocation);
100
+ // Configurable interface implementation
101
+ public get settings(): Readonly<WebPubSettings> {
102
+ return Object.freeze({ ...this._settings });
103
+ }
104
+
105
+ public get preferencesEditor(): IPreferencesEditor {
106
+ if (this._preferencesEditor === null) {
107
+ this._preferencesEditor = new WebPubPreferencesEditor(this._preferences, this.settings, this.pub.metadata);
108
+ }
109
+ return this._preferencesEditor;
110
+ }
111
+
112
+ public async submitPreferences(preferences: WebPubPreferences) {
113
+ this._preferences = this._preferences.merging(preferences) as WebPubPreferences;
114
+ await this.applyPreferences();
115
+ }
116
+
117
+ private async applyPreferences() {
118
+ this._settings = new WebPubSettings(this._preferences, this._defaults);
119
+
120
+ if (this._preferencesEditor !== null) {
121
+ this._preferencesEditor = new WebPubPreferencesEditor(this._preferences, this.settings, this.pub.metadata);
122
+ }
123
+
124
+ // Apply preferences using CSS system like EPUB
125
+ await this.updateCSS(true);
126
+ }
127
+
128
+ private async updateCSS(commit: boolean) {
129
+ this._css.update(this._settings);
130
+
131
+ if (commit) await this.commitCSS(this._css);
132
+ };
133
+
134
+ private compileCSSProperties(css: WebPubCSS) {
135
+ const properties: { [key: string]: string } = {};
136
+
137
+ for (const [key, value] of Object.entries(css.userProperties.toCSSProperties())) {
138
+ properties[key] = value;
139
+ }
140
+
141
+ return properties;
142
+ }
143
+
144
+ private async commitCSS(css: WebPubCSS) {
145
+ const properties = this.compileCSSProperties(css);
146
+ this.framePool.setCSSProperties(properties);
70
147
  }
71
148
 
72
149
  public eventListener(key: CommsEventKey | ManagerEventKey, data: unknown) {
@@ -0,0 +1,71 @@
1
+ import { TextAlignment } from "../../preferences/Types";
2
+ import { BodyHyphens, Ligatures, Properties } from "../../css/Properties";
3
+
4
+ export interface IWebUserProperties {
5
+ a11yNormalize?: boolean | null;
6
+ bodyHyphens?: BodyHyphens | null;
7
+ fontFamily?: string | null;
8
+ fontWeight?: number | null;
9
+ letterSpacing?: number | null;
10
+ ligatures?: Ligatures | null;
11
+ lineHeight?: number | null;
12
+ noRuby?: boolean | null;
13
+ paraIndent?: number | null;
14
+ paraSpacing?: number | null;
15
+ textAlign?: TextAlignment | null;
16
+ wordSpacing?: number | null;
17
+ zoom: number | null;
18
+ }
19
+
20
+ export class WebUserProperties extends Properties {
21
+ a11yNormalize: boolean | null;
22
+ bodyHyphens: BodyHyphens | null;
23
+ fontFamily: string | null;
24
+ fontWeight: number | null;
25
+ letterSpacing: number | null;
26
+ ligatures: Ligatures | null;
27
+ lineHeight: number | null;
28
+ noRuby: boolean | null;
29
+ paraIndent: number | null;
30
+ paraSpacing: number | null;
31
+ textAlign: TextAlignment | null;
32
+ wordSpacing: number | null;
33
+ zoom: number | null;
34
+
35
+ constructor(props: IWebUserProperties) {
36
+ super();
37
+ this.a11yNormalize = props.a11yNormalize ?? null;
38
+ this.bodyHyphens = props.bodyHyphens ?? null;
39
+ this.fontFamily = props.fontFamily ?? null;
40
+ this.fontWeight = props.fontWeight ?? null;
41
+ this.letterSpacing = props.letterSpacing ?? null;
42
+ this.ligatures = props.ligatures ?? null;
43
+ this.lineHeight = props.lineHeight ?? null;
44
+ this.noRuby = props.noRuby ?? null;
45
+ this.paraIndent = props.paraIndent ?? null;
46
+ this.paraSpacing = props.paraSpacing ?? null;
47
+ this.textAlign = props.textAlign ?? null;
48
+ this.wordSpacing = props.wordSpacing ?? null;
49
+ this.zoom = props.zoom ?? null;
50
+ }
51
+
52
+ toCSSProperties() {
53
+ const cssProperties: { [key: string]: string } = {};
54
+
55
+ if (this.a11yNormalize) cssProperties["--USER__a11yNormalize"] = this.toFlag("a11y");
56
+ if (this.bodyHyphens) cssProperties["--USER__bodyHyphens"] = this.bodyHyphens;
57
+ if (this.fontFamily) cssProperties["--USER__fontFamily"] = this.fontFamily;
58
+ if (this.fontWeight != null) cssProperties["--USER__fontWeight"] = this.toUnitless(this.fontWeight);
59
+ if (this.letterSpacing != null) cssProperties["--USER__letterSpacing"] = this.toRem(this.letterSpacing);
60
+ if (this.ligatures) cssProperties["--USER__ligatures"] = this.ligatures;
61
+ if (this.lineHeight != null) cssProperties["--USER__lineHeight"] = this.toUnitless(this.lineHeight);
62
+ if (this.noRuby) cssProperties["--USER__noRuby"] = this.toFlag("noRuby");
63
+ if (this.paraIndent != null) cssProperties["--USER__paraIndent"] = this.toRem(this.paraIndent);
64
+ if (this.paraSpacing != null) cssProperties["--USER__paraSpacing"] = this.toRem(this.paraSpacing);
65
+ if (this.textAlign) cssProperties["--USER__textAlign"] = this.textAlign;
66
+ if (this.wordSpacing != null) cssProperties["--USER__wordSpacing"] = this.toRem(this.wordSpacing);
67
+ if (this.zoom !== null) cssProperties["--USER__zoom"] = this.toPercentage(this.zoom, true);
68
+
69
+ return cssProperties;
70
+ }
71
+ }
@@ -0,0 +1,42 @@
1
+ import { WebPubSettings } from "../preferences/WebPubSettings";
2
+ import { IWebUserProperties, WebUserProperties } from "./Properties";
3
+
4
+ export interface IWebPubCSS {
5
+ userProperties: WebUserProperties;
6
+ }
7
+
8
+ export class WebPubCSS {
9
+ userProperties: WebUserProperties;
10
+
11
+ constructor(props: IWebPubCSS) {
12
+ this.userProperties = props.userProperties;
13
+ }
14
+
15
+ update(settings: WebPubSettings) {
16
+ const updated: IWebUserProperties = {
17
+ a11yNormalize: settings.textNormalization,
18
+ bodyHyphens: typeof settings.hyphens !== "boolean"
19
+ ? null
20
+ : settings.hyphens
21
+ ? "auto"
22
+ : "none",
23
+ fontFamily: settings.fontFamily,
24
+ fontWeight: settings.fontWeight,
25
+ letterSpacing: settings.letterSpacing,
26
+ ligatures: typeof settings.ligatures !== "boolean"
27
+ ? null
28
+ : settings.ligatures
29
+ ? "common-ligatures"
30
+ : "none",
31
+ lineHeight: settings.lineHeight,
32
+ noRuby: settings.noRuby,
33
+ paraIndent: settings.paragraphIndent,
34
+ paraSpacing: settings.paragraphSpacing,
35
+ textAlign: settings.textAlign,
36
+ wordSpacing: settings.wordSpacing,
37
+ zoom: settings.zoom
38
+ };
39
+
40
+ this.userProperties = new WebUserProperties(updated);
41
+ }
42
+ }
@@ -0,0 +1,204 @@
1
+ // WebPubCSS is equivalent to ReadiumCSS for WebPub
2
+
3
+ export const webPubStylesheet = `
4
+ /* FontFamily */
5
+
6
+ :root[style*="--USER__fontFamily"] {
7
+ font-family: var(--USER__fontFamily) !important;
8
+ }
9
+
10
+ :root[style*="--USER__fontFamily"] * {
11
+ font-family: revert !important;
12
+ }
13
+
14
+ /* FontWeight */
15
+
16
+ :root[style*="--USER__fontWeight"] body {
17
+ font-weight: var(--USER__fontWeight) !important;
18
+ }
19
+
20
+ /* Attempt to handle known bolds */
21
+ :root[style*="--USER__fontWeight"] b,
22
+ :root[style*="--USER__fontWeight"] strong {
23
+ font-weight: bolder;
24
+ }
25
+
26
+ /* Hyphens */
27
+
28
+ :root[style*="--USER__bodyHyphens"] {
29
+ -webkit-hyphens: var(--USER__bodyHyphens) !important;
30
+ -moz-hyphens: var(--USER__bodyHyphens) !important;
31
+ -ms-hyphens: var(--USER__bodyHyphens) !important;
32
+ -epub-hyphens: var(--USER__bodyHyphens) !important;
33
+ hyphens: var(--USER__bodyHyphens) !important;
34
+ }
35
+
36
+ :root[style*="--USER__bodyHyphens"] body,
37
+ :root[style*="--USER__bodyHyphens"] p,
38
+ :root[style*="--USER__bodyHyphens"] li,
39
+ :root[style*="--USER__bodyHyphens"] div,
40
+ :root[style*="--USER__bodyHyphens"] dd {
41
+ -webkit-hyphens: inherit;
42
+ -moz-hyphens: inherit;
43
+ -ms-hyphens: inherit;
44
+ -epub-hyphens: inherit;
45
+ hyphens: inherit;
46
+ }
47
+
48
+ /* LetterSpacing */
49
+
50
+ :root[style*="--USER__letterSpacing"] h1,
51
+ :root[style*="--USER__letterSpacing"] h2,
52
+ :root[style*="--USER__letterSpacing"] h3,
53
+ :root[style*="--USER__letterSpacing"] h4,
54
+ :root[style*="--USER__letterSpacing"] h5,
55
+ :root[style*="--USER__letterSpacing"] h6,
56
+ :root[style*="--USER__letterSpacing"] p,
57
+ :root[style*="--USER__letterSpacing"] li,
58
+ :root[style*="--USER__letterSpacing"] div,
59
+ :root[style*="--USER__letterSpacing"] dt,
60
+ :root[style*="--USER__letterSpacing"] dd {
61
+ letter-spacing: var(--USER__letterSpacing);
62
+ font-variant: none;
63
+ }
64
+
65
+ /* Ligatures */
66
+
67
+ :root[style*="--USER__ligatures"] {
68
+ font-variant-ligatures: var(--USER__ligatures) !important;
69
+ }
70
+
71
+ :root[style*="--USER__ligatures"] * {
72
+ font-variant-ligatures: inherit !important;
73
+ }
74
+
75
+ /* LineHeight */
76
+
77
+ :root[style*="--USER__lineHeight"] {
78
+ line-height: var(--USER__lineHeight) !important;
79
+ }
80
+
81
+ :root[style*="--USER__lineHeight"] body,
82
+ :root[style*="--USER__lineHeight"] p,
83
+ :root[style*="--USER__lineHeight"] li,
84
+ :root[style*="--USER__lineHeight"] div {
85
+ line-height: inherit;
86
+ }
87
+
88
+ /* ParagraphIndent */
89
+
90
+ :root[style*="--USER__paraIndent"] p {
91
+ text-indent: var(--USER__paraIndent) !important;
92
+ }
93
+
94
+ :root[style*="--USER__paraIndent"] p *,
95
+ :root[style*="--USER__paraIndent"] p:first-letter {
96
+ text-indent: 0 !important;
97
+ }
98
+
99
+ /* ParagraphSpacing */
100
+
101
+ :root[style*="--USER__paraSpacing"] p {
102
+ margin-block: var(--USER__paraSpacing) !important;
103
+ }
104
+
105
+ /* Ruby */
106
+
107
+ :root[style*="readium-noRuby-on"] body rt,
108
+ :root[style*="readium-noRuby-on"] body rp {
109
+ display: none;
110
+ }
111
+
112
+ /* TextAlign */
113
+
114
+ :root[style*="--USER__textAlign"] {
115
+ text-align: var(--USER__textAlign);
116
+ }
117
+
118
+ :root[style*="--USER__textAlign"] body,
119
+ :root[style*="--USER__textAlign"] p:not(blockquote p):not(figcaption p):not(hgroup p),
120
+ :root[style*="--USER__textAlign"] li,
121
+ :root[style*="--USER__textAlign"] dd {
122
+ text-align: var(--USER__textAlign) !important;
123
+ -moz-text-align-last: auto !important;
124
+ -epub-text-align-last: auto !important;
125
+ text-align-last: auto !important;
126
+ }
127
+
128
+ /* TextNormalize */
129
+
130
+ :root[style*="readium-a11y-on"] {
131
+ font-weight: normal !important;
132
+ font-style: normal !important;
133
+ }
134
+
135
+ :root[style*="readium-a11y-on"] *:not(code):not(var):not(kbd):not(samp) {
136
+ font-family: inherit !important;
137
+ font-weight: inherit !important;
138
+ font-style: inherit !important;
139
+ }
140
+
141
+ :root[style*="readium-a11y-on"] * {
142
+ text-decoration: none !important;
143
+ font-variant-caps: normal !important;
144
+ font-variant-position: normal !important;
145
+ font-variant-numeric: normal !important;
146
+ }
147
+
148
+ :root[style*="readium-a11y-on"] sup,
149
+ :root[style*="readium-a11y-on"] sub {
150
+ font-size: 1rem !important;
151
+ vertical-align: baseline !important;
152
+ }
153
+
154
+ /* Word Spacing */
155
+
156
+ :root[style*="--USER__wordSpacing"] h1,
157
+ :root[style*="--USER__wordSpacing"] h2,
158
+ :root[style*="--USER__wordSpacing"] h3,
159
+ :root[style*="--USER__wordSpacing"] h4,
160
+ :root[style*="--USER__wordSpacing"] h5,
161
+ :root[style*="--USER__wordSpacing"] h6,
162
+ :root[style*="--USER__wordSpacing"] p,
163
+ :root[style*="--USER__wordSpacing"] li,
164
+ :root[style*="--USER__wordSpacing"] div,
165
+ :root[style*="--USER__wordSpacing"] dt,
166
+ :root[style*="--USER__wordSpacing"] dd {
167
+ word-spacing: var(--USER__wordSpacing);
168
+ }
169
+
170
+ /* Zoom */
171
+
172
+ :root {
173
+ --USER__zoom: 1;
174
+ }
175
+
176
+ :root[style*="--USER__zoom"] body {
177
+ zoom: var(--USER__zoom) !important;
178
+ }
179
+
180
+ @supports selector(figure:has(> img)) {
181
+ :root[style*="--USER__zoom"] figure:has(> img),
182
+ :root[style*="--USER__zoom"] figure:has(> video),
183
+ :root[style*="--USER__zoom"] figure:has(> svg),
184
+ :root[style*="--USER__zoom"] figure:has(> canvas),
185
+ :root[style*="--USER__zoom"] figure:has(> iframe),
186
+ :root[style*="--USER__zoom"] figure:has(> audio),
187
+ :root[style*="--USER__zoom"] div:has(> img),
188
+ :root[style*="--USER__zoom"] div:has(> video),
189
+ :root[style*="--USER__zoom"] div:has(> svg),
190
+ :root[style*="--USER__zoom"] div:has(> canvas),
191
+ :root[style*="--USER__zoom"] div:has(> iframe),
192
+ :root[style*="--USER__zoom"] div:has(> audio),
193
+ :root[style*="--USER__zoom"] table {
194
+ zoom: calc(100% / var(--USER__zoom)) !important;
195
+ }
196
+
197
+ :root[style*="--USER__zoom"] figcaption,
198
+ :root[style*="--USER__zoom"] caption,
199
+ :root[style*="--USER__zoom"] td,
200
+ :root[style*="--USER__zoom"] th {
201
+ zoom: var(--USER__zoom) !important;
202
+ }
203
+ }
204
+ `;
@@ -0,0 +1,3 @@
1
+ export * from "./Properties";
2
+ export * from "./WebPubCSS";
3
+ export * from "./WebPubStylesheet";
@@ -1,4 +1,6 @@
1
1
  export * from "./WebPubNavigator";
2
2
  export * from "./WebPubBlobBuilder";
3
3
  export * from "./WebPubFrameManager";
4
- export * from "./WebPubFramePoolManager";
4
+ export * from "./WebPubFramePoolManager";
5
+ export * from "./preferences";
6
+ export * from "./css";
@@ -0,0 +1,61 @@
1
+ import {
2
+ fontWeightRangeConfig,
3
+ TextAlignment,
4
+ zoomRangeConfig
5
+ } from "../../preferences/Types";
6
+
7
+ import {
8
+ ensureBoolean,
9
+ ensureEnumValue,
10
+ ensureNonNegative,
11
+ ensureValueInRange,
12
+ ensureString
13
+ } from "../../preferences/guards";
14
+
15
+ export interface IWebPubDefaults {
16
+ fontFamily?: string | null,
17
+ fontWeight?: number | null,
18
+ hyphens?: boolean | null,
19
+ letterSpacing?: number | null,
20
+ ligatures?: boolean | null,
21
+ lineHeight?: number | null,
22
+ noRuby?: boolean | null,
23
+ paragraphIndent?: number | null,
24
+ paragraphSpacing?: number | null,
25
+ textAlign?: TextAlignment | null,
26
+ textNormalization?: boolean | null,
27
+ wordSpacing?: number | null,
28
+ zoom?: number | null
29
+ }
30
+
31
+ export class WebPubDefaults {
32
+ fontFamily: string | null;
33
+ fontWeight: number | null;
34
+ hyphens: boolean | null;
35
+ letterSpacing: number | null;
36
+ ligatures: boolean | null;
37
+ lineHeight: number | null;
38
+ noRuby: boolean | null;
39
+ paragraphIndent: number | null;
40
+ paragraphSpacing: number | null;
41
+ textAlign: TextAlignment | null;
42
+ textNormalization: boolean | null;
43
+ wordSpacing: number | null;
44
+ zoom: number;
45
+
46
+ constructor(defaults: IWebPubDefaults) {
47
+ this.fontFamily = ensureString(defaults.fontFamily) || null;
48
+ this.fontWeight = ensureValueInRange(defaults.fontWeight, fontWeightRangeConfig.range) || null;
49
+ this.hyphens = ensureBoolean(defaults.hyphens) ?? null;
50
+ this.letterSpacing = ensureNonNegative(defaults.letterSpacing) || null;
51
+ this.ligatures = ensureBoolean(defaults.ligatures) ?? null;
52
+ this.lineHeight = ensureNonNegative(defaults.lineHeight) || null;
53
+ this.noRuby = ensureBoolean(defaults.noRuby) ?? false;
54
+ this.paragraphIndent = ensureNonNegative(defaults.paragraphIndent) ?? null;
55
+ this.paragraphSpacing = ensureNonNegative(defaults.paragraphSpacing) ?? null;
56
+ this.textAlign = ensureEnumValue<TextAlignment>(defaults.textAlign, TextAlignment) || null;
57
+ this.textNormalization = ensureBoolean(defaults.textNormalization) ?? false;
58
+ this.wordSpacing = ensureNonNegative(defaults.wordSpacing) || null;
59
+ this.zoom = ensureValueInRange(defaults.zoom, zoomRangeConfig.range) || 1;
60
+ }
61
+ }
@@ -0,0 +1,88 @@
1
+ import { ConfigurablePreferences } from "../../preferences/Configurable";
2
+
3
+ import {
4
+ fontWeightRangeConfig,
5
+ TextAlignment,
6
+ zoomRangeConfig
7
+ } from "../../preferences/Types";
8
+
9
+ import {
10
+ ensureBoolean,
11
+ ensureEnumValue,
12
+ ensureNonNegative,
13
+ ensureString,
14
+ ensureValueInRange
15
+ } from "../../preferences/guards";
16
+
17
+ export interface IWebPubPreferences {
18
+ fontFamily?: string | null,
19
+ fontWeight?: number | null,
20
+ hyphens?: boolean | null,
21
+ letterSpacing?: number | null,
22
+ ligatures?: boolean | null,
23
+ lineHeight?: number | null,
24
+ noRuby?: boolean | null,
25
+ paragraphIndent?: number | null,
26
+ paragraphSpacing?: number | null,
27
+ textAlign?: TextAlignment | null,
28
+ textNormalization?: boolean | null,
29
+ wordSpacing?: number | null,
30
+ zoom?: number | null
31
+ }
32
+
33
+ export class WebPubPreferences implements ConfigurablePreferences {
34
+ fontFamily?: string | null;
35
+ fontWeight?: number | null;
36
+ hyphens?: boolean | null;
37
+ letterSpacing?: number | null;
38
+ ligatures?: boolean | null;
39
+ lineHeight?: number | null;
40
+ noRuby?: boolean | null;
41
+ paragraphIndent?: number | null;
42
+ paragraphSpacing?: number | null;
43
+ textAlign?: TextAlignment | null;
44
+ textNormalization?: boolean | null;
45
+ wordSpacing?: number | null;
46
+ zoom?: number | null;
47
+
48
+ constructor(preferences: IWebPubPreferences = {}) {
49
+ this.fontFamily = ensureString(preferences.fontFamily);
50
+ this.fontWeight = ensureValueInRange(preferences.fontWeight, fontWeightRangeConfig.range);
51
+ this.hyphens = ensureBoolean(preferences.hyphens);
52
+ this.letterSpacing = ensureNonNegative(preferences.letterSpacing);
53
+ this.ligatures = ensureBoolean(preferences.ligatures);
54
+ this.lineHeight = ensureNonNegative(preferences.lineHeight);
55
+ this.noRuby = ensureBoolean(preferences.noRuby);
56
+ this.paragraphIndent = ensureNonNegative(preferences.paragraphIndent);
57
+ this.paragraphSpacing = ensureNonNegative(preferences.paragraphSpacing);
58
+ this.textAlign = ensureEnumValue<TextAlignment>(preferences.textAlign, TextAlignment);
59
+ this.textNormalization = ensureBoolean(preferences.textNormalization);
60
+ this.wordSpacing = ensureNonNegative(preferences.wordSpacing);
61
+ this.zoom = ensureValueInRange(preferences.zoom, zoomRangeConfig.range);
62
+ }
63
+
64
+ static serialize(preferences: WebPubPreferences): string {
65
+ const { ...properties } = preferences;
66
+ return JSON.stringify(properties);
67
+ }
68
+
69
+ static deserialize(preferences: string): WebPubPreferences | null {
70
+ try {
71
+ const parsedPreferences = JSON.parse(preferences);
72
+ return new WebPubPreferences(parsedPreferences);
73
+ } catch (error) {
74
+ console.error("Failed to deserialize preferences:", error);
75
+ return null;
76
+ }
77
+ }
78
+
79
+ merging(other: ConfigurablePreferences): ConfigurablePreferences {
80
+ const merged: IWebPubPreferences = { ...this };
81
+ for (const key of Object.keys(other) as (keyof IWebPubPreferences)[]) {
82
+ if (other[key] !== undefined) {
83
+ merged[key] = other[key];
84
+ }
85
+ }
86
+ return new WebPubPreferences(merged);
87
+ }
88
+ }