@readium/navigator 2.2.0 → 2.2.2

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 +1912 -1330
  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 +103 -11
  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 +199 -0
  26. package/src/webpub/preferences/WebPubSettings.ts +90 -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 +30 -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 +28 -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,23 @@
1
- import { Link, Locator, Publication, ReadingProgression, LocatorLocations } from "@readium/shared";
1
+ import { Feature, 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";
7
+ import { WebPubFrameManager } from "./WebPubFrameManager";
8
+
6
9
  import { ManagerEventKey } from "../epub/EpubNavigator";
10
+ import { WebPubCSS } from "./css/WebPubCSS";
11
+ import { WebUserProperties } from "./css/Properties";
12
+ import { IWebPubPreferences, WebPubPreferences } from "./preferences/WebPubPreferences";
13
+ import { IWebPubDefaults, WebPubDefaults } from "./preferences/WebPubDefaults";
14
+ import { WebPubSettings } from "./preferences/WebPubSettings";
15
+ import { IPreferencesEditor } from "../preferences/PreferencesEditor";
16
+ import { WebPubPreferencesEditor } from "./preferences/WebPubPreferencesEditor";
17
+ export interface WebPubNavigatorConfiguration {
18
+ preferences: IWebPubPreferences;
19
+ defaults: IWebPubDefaults;
20
+ }
7
21
 
8
22
  export interface WebPubNavigatorListeners {
9
23
  frameLoaded: (wnd: Window) => void;
@@ -27,27 +41,43 @@ const defaultListeners = (listeners: WebPubNavigatorListeners): WebPubNavigatorL
27
41
  customEvent: listeners.customEvent || (() => {}),
28
42
  handleLocator: listeners.handleLocator || (() => false),
29
43
  textSelected: listeners.textSelected || (() => {})
30
- });
44
+ })
31
45
 
32
- class WebPubNavigator extends VisualNavigator {
46
+ export class WebPubNavigator extends VisualNavigator implements Configurable<WebPubSettings, WebPubPreferences> {
33
47
  private readonly pub: Publication;
34
48
  private readonly container: HTMLElement;
35
49
  private readonly listeners: WebPubNavigatorListeners;
36
- private framePool: WebPubFramePoolManager;
50
+ private framePool!: WebPubFramePoolManager;
37
51
  private currentIndex: number = 0;
38
52
  private currentLocation: Locator;
53
+
54
+ private _preferences: WebPubPreferences;
55
+ private _defaults: WebPubDefaults;
56
+ private _settings: WebPubSettings;
57
+ private _css: WebPubCSS;
58
+ private _preferencesEditor: WebPubPreferencesEditor | null = null;
59
+
39
60
  private webViewport: VisualNavigatorViewport = {
40
61
  readingOrder: [],
41
62
  progressions: new Map(),
42
63
  positions: null
43
64
  };
44
65
 
45
- constructor(container: HTMLElement, pub: Publication, listeners: WebPubNavigatorListeners, initialPosition: Locator | undefined = undefined) {
66
+ constructor(container: HTMLElement, pub: Publication, listeners: WebPubNavigatorListeners, initialPosition: Locator | undefined = undefined, configuration: WebPubNavigatorConfiguration = { preferences: {}, defaults: {} }) {
46
67
  super();
47
68
  this.pub = pub;
48
69
  this.container = container;
49
70
  this.listeners = defaultListeners(listeners);
50
- this.framePool = new WebPubFramePoolManager(this.container);
71
+
72
+ // Initialize preference system
73
+ this._preferences = new WebPubPreferences(configuration.preferences);
74
+ this._defaults = new WebPubDefaults(configuration.defaults);
75
+ this._settings = new WebPubSettings(this._preferences, this._defaults, this.hasDisplayTransformability);
76
+ this._css = new WebPubCSS({
77
+ userProperties: new WebUserProperties({ zoom: this._settings.zoom })
78
+ });
79
+
80
+ // Initialize current location
51
81
  if (initialPosition && typeof initialPosition.copyWithLocations === 'function') {
52
82
  this.currentLocation = initialPosition;
53
83
  // Update currentIndex to match the initial position
@@ -60,13 +90,75 @@ class WebPubNavigator extends VisualNavigator {
60
90
  }
61
91
  }
62
92
 
63
- async load(): Promise<void> {
64
- await this.framePool.update(this.pub, this.currentLocation, this.determineModules());
93
+ public async load() {
94
+ await this.updateCSS(false);
95
+ const cssProperties = this.compileCSSProperties(this._css);
96
+ this.framePool = new WebPubFramePoolManager(this.container, cssProperties);
65
97
 
66
- this.attachListener();
98
+ await this.apply();
99
+ }
67
100
 
68
- // Notify listeners of initial position
69
- this.listeners.positionChanged(this.currentLocation);
101
+ // Configurable interface implementation
102
+ public get settings(): Readonly<WebPubSettings> {
103
+ return Object.freeze({ ...this._settings });
104
+ }
105
+
106
+ public get preferencesEditor(): IPreferencesEditor {
107
+ if (this._preferencesEditor === null) {
108
+ this._preferencesEditor = new WebPubPreferencesEditor(this._preferences, this.settings, this.pub.metadata);
109
+ }
110
+ return this._preferencesEditor;
111
+ }
112
+
113
+ public async submitPreferences(preferences: WebPubPreferences) {
114
+ this._preferences = this._preferences.merging(preferences) as WebPubPreferences;
115
+ await this.applyPreferences();
116
+ }
117
+
118
+ private async applyPreferences() {
119
+ this._settings = new WebPubSettings(this._preferences, this._defaults, this.hasDisplayTransformability);
120
+
121
+ if (this._preferencesEditor !== null) {
122
+ this._preferencesEditor = new WebPubPreferencesEditor(this._preferences, this.settings, this.pub.metadata);
123
+ }
124
+
125
+ // Apply preferences using CSS system like EPUB
126
+ await this.updateCSS(true);
127
+ }
128
+
129
+ private async updateCSS(commit: boolean) {
130
+ this._css.update(this._settings);
131
+
132
+ if (commit) await this.commitCSS(this._css);
133
+ };
134
+
135
+ private compileCSSProperties(css: WebPubCSS) {
136
+ const properties: { [key: string]: string } = {};
137
+
138
+ for (const [key, value] of Object.entries(css.userProperties.toCSSProperties())) {
139
+ properties[key] = value;
140
+ }
141
+
142
+ return properties;
143
+ }
144
+
145
+ private async commitCSS(css: WebPubCSS) {
146
+ const properties = this.compileCSSProperties(css);
147
+ this.framePool.setCSSProperties(properties);
148
+ }
149
+
150
+ /**
151
+ * Exposed to the public to compensate for lack of implemented readium conveniences
152
+ * TODO remove when settings management is incorporated
153
+ */
154
+ public get _cframes(): (WebPubFrameManager | undefined)[] {
155
+ return this.framePool.currentFrames;
156
+ }
157
+
158
+ private get hasDisplayTransformability(): boolean {
159
+ return this.pub.metadata?.accessibility?.feature?.some(
160
+ f => f.value === Feature.DISPLAY_TRANSFORMABILITY.value
161
+ ) ?? false;
70
162
  }
71
163
 
72
164
  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
+ }