@readium/navigator 2.2.4 → 2.2.5

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@readium/navigator",
3
- "version": "2.2.4",
3
+ "version": "2.2.5",
4
4
  "type": "module",
5
5
  "description": "Next generation SDK for publications in Web Apps",
6
6
  "author": "readium",
@@ -49,16 +49,16 @@
49
49
  },
50
50
  "devDependencies": {
51
51
  "@laynezh/vite-plugin-lib-assets": "^2.1.0",
52
- "@readium/css": "2.0.0-beta.22",
52
+ "@readium/css": "2.0.0-beta.24",
53
53
  "@readium/navigator-html-injectables": "workspace:*",
54
54
  "@readium/shared": "workspace:*",
55
55
  "@types/path-browserify": "^1.0.3",
56
56
  "css-selector-generator": "^3.6.9",
57
57
  "path-browserify": "^1.0.1",
58
58
  "tslib": "^2.8.1",
59
- "typescript": "^5.9.2",
59
+ "typescript": "^5.9.3",
60
60
  "typescript-plugin-css-modules": "^5.2.0",
61
61
  "user-agent-data-types": "^0.4.2",
62
- "vite": "^7.1.5"
62
+ "vite": "^7.2.4"
63
63
  }
64
64
  }
@@ -1,4 +1,4 @@
1
- import { TextAlignment } from "../../preferences/Types";
1
+ import { ExperimentKey, experiments, TextAlignment } from "../../preferences/Types";
2
2
  import {
3
3
  BodyHyphens,
4
4
  BoxSizing,
@@ -214,6 +214,7 @@ export interface IRSProperties {
214
214
  textColor?: string | null;
215
215
  typeScale?: TypeScale | null;
216
216
  visitedColor?: string | null;
217
+ experiments?: Array<ExperimentKey> | null;
217
218
  }
218
219
 
219
220
  export class RSProperties extends Properties {
@@ -258,6 +259,7 @@ export class RSProperties extends Properties {
258
259
  textColor: string | null;
259
260
  typeScale: TypeScale | null;
260
261
  visitedColor: string | null;
262
+ experiments: Array<ExperimentKey> | null;
261
263
 
262
264
  constructor(props: IRSProperties) {
263
265
  super();
@@ -302,6 +304,7 @@ export class RSProperties extends Properties {
302
304
  this.textColor = props.textColor ?? null;
303
305
  this.typeScale = props.typeScale ?? null;
304
306
  this.visitedColor = props.visitedColor ?? null;
307
+ this.experiments = props.experiments ?? null;
305
308
  }
306
309
 
307
310
  toCSSProperties(): { [key: string]: string; } {
@@ -349,6 +352,12 @@ export class RSProperties extends Properties {
349
352
  if (this.typeScale) cssProperties["--RS__typeScale"] = this.toUnitless(this.typeScale);
350
353
  if (this.visitedColor) cssProperties["--RS__visitedColor"] = this.visitedColor;
351
354
 
355
+ if (this.experiments) {
356
+ this.experiments.forEach((exp) => {
357
+ cssProperties["--RS__" + exp] = experiments[exp].value;
358
+ });
359
+ };
360
+
352
361
  return cssProperties;
353
362
  }
354
363
  }
@@ -54,6 +54,9 @@ export class ReadiumCSS {
54
54
  if (settings.scrollPaddingTop !== this.rsProperties.scrollPaddingTop)
55
55
  this.rsProperties.scrollPaddingTop = settings.scrollPaddingTop;
56
56
 
57
+ if (settings.experiments !== this.rsProperties.experiments)
58
+ this.rsProperties.experiments = settings.experiments;
59
+
57
60
  // This has to be updated before pagination
58
61
  // otherwise the metrics won’t be correct for line length
59
62
  this.lineLengths.update({
@@ -50,7 +50,10 @@ const cssSelectorGenerator = (doc: Document) => scriptify(doc, cached("css-selec
50
50
 
51
51
  // Note: we aren't blocking some of the events right now to try and be as nonintrusive as possible.
52
52
  // For a more comprehensive implementation, see https://github.com/hackademix/noscript/blob/3a83c0e4a506f175e38b0342dad50cdca3eae836/src/content/syncFetchPolicy.js#L142
53
+ // The snippet of code at the beginning of this source is an attempt at defence against JS using persistent storage
53
54
  const rBefore = (doc: Document) => scriptify(doc, cached("JS-Before", () => blobify(stripJS(`
55
+ const noop=()=>{},emptyObj={},emptyPromise=()=>Promise.resolve(void 0),fakeStorage={getItem:noop,setItem:noop,removeItem:noop,clear:noop,key:noop,length:0};["localStorage","sessionStorage"].forEach((e=>Object.defineProperty(window,e,{get:()=>fakeStorage,configurable:!0}))),Object.defineProperty(document,"cookie",{get:()=>"",set:noop,configurable:!0}),Object.defineProperty(window,"indexedDB",{get:()=>{},configurable:!0}),Object.defineProperty(window,"caches",{get:()=>emptyObj,configurable:!0}),Object.defineProperty(navigator,"storage",{get:()=>({persist:emptyPromise,persisted:emptyPromise,estimate:()=>Promise.resolve({quota:0,usage:0})}),configurable:!0}),Object.defineProperty(navigator,"serviceWorker",{get:()=>({register:emptyPromise,getRegistration:emptyPromise,ready:emptyPromise()}),configurable:!0});
56
+
54
57
  window._readium_blockedEvents = [];
55
58
  window._readium_blockEvents = true;
56
59
  window._readium_eventBlocker = (e) => {
@@ -78,6 +81,24 @@ const rAfter = (doc: Document) => scriptify(doc, cached("JS-After", () => blobif
78
81
  });`
79
82
  ), "text/javascript")));
80
83
 
84
+ const csp = (domains: string[]) => {
85
+ const d = domains.join(" ");
86
+ return [
87
+ // 'self' is useless because the document is loaded from a blob: URL
88
+ `upgrade-insecure-requests`,
89
+ `default-src ${d} blob:`,
90
+ `connect-src 'none'`, // No fetches to anywhere. TODO: change?
91
+ `script-src ${d} blob: 'unsafe-inline'`, // JS scripts
92
+ `style-src ${d} blob: 'unsafe-inline'`, // CSS styles
93
+ `img-src ${d} blob: data:`, // Images
94
+ `font-src ${d} blob: data:`, // Fonts
95
+ `object-src ${d} blob:`, // Despite not being recommended, still necessary in EPUBs for <object>
96
+ `child-src ${d}`, // <iframe>, web workers
97
+ `form-action 'none'`, // No form submissions
98
+ //`report-uri ?`,
99
+ ].join("; ");
100
+ };
101
+
81
102
  export default class FrameBlobBuider {
82
103
  private readonly item: Link;
83
104
  private readonly burl: string;
@@ -93,7 +114,7 @@ export default class FrameBlobBuider {
93
114
 
94
115
  public async build(fxl = false): Promise<string> {
95
116
  if(!this.item.mediaType.isHTML) {
96
- if(this.item.mediaType.isBitmap) {
117
+ if(this.item.mediaType.isBitmap || this.item.mediaType.equals(MediaType.SVG)) {
97
118
  return this.buildImageFrame();
98
119
  } else
99
120
  throw Error("Unsupported frame mediatype " + this.item.mediaType.string);
@@ -115,7 +136,7 @@ export default class FrameBlobBuider {
115
136
  const details = perror.querySelector("div");
116
137
  throw new Error(`Failed parsing item ${this.item.href}: ${details?.textContent || perror.textContent}`);
117
138
  }
118
- return this.finalizeDOM(doc, this.burl, this.item.mediaType, fxl, this.cssProperties);
139
+ return this.finalizeDOM(doc, this.pub.baseURL, this.burl, this.item.mediaType, fxl, this.cssProperties);
119
140
  }
120
141
 
121
142
  private buildImageFrame(): string {
@@ -126,7 +147,7 @@ export default class FrameBlobBuider {
126
147
  simg.alt = this.item.title || "";
127
148
  simg.decoding = "async";
128
149
  doc.body.appendChild(simg);
129
- return this.finalizeDOM(doc, this.burl, this.item.mediaType, true);
150
+ return this.finalizeDOM(doc, this.pub.baseURL, this.burl, this.item.mediaType, true);
130
151
  }
131
152
 
132
153
  // Has JS that may have side-effects when the document is loaded, without any user interaction
@@ -159,7 +180,7 @@ export default class FrameBlobBuider {
159
180
  }
160
181
  }
161
182
 
162
- private finalizeDOM(doc: Document, base: string | undefined, mediaType: MediaType, fxl = false, cssProperties?: { [key: string]: string }): string {
183
+ private finalizeDOM(doc: Document, root: string | undefined, base: string | undefined, mediaType: MediaType, fxl = false, cssProperties?: { [key: string]: string }): string {
163
184
  if(!doc) return "";
164
185
 
165
186
  // Inject styles
@@ -233,8 +254,8 @@ export default class FrameBlobBuider {
233
254
  ) {
234
255
  document.documentElement.dir = this.pub.metadata.effectiveReadingProgression;
235
256
  } */
236
-
237
- if(base !== undefined) {
257
+
258
+ if (base !== undefined) {
238
259
  // Set all URL bases. Very convenient!
239
260
  const b = doc.createElement("base");
240
261
  b.href = base;
@@ -244,17 +265,24 @@ export default class FrameBlobBuider {
244
265
 
245
266
  // Inject script to prevent in-publication scripts from executing until we want them to
246
267
  const hasExecutable = this.hasExecutable(doc);
247
- if(hasExecutable) doc.head.firstChild!.before(rBefore(doc));
268
+ if (hasExecutable) doc.head.firstChild!.before(rBefore(doc));
248
269
  doc.head.firstChild!.before(cssSelectorGenerator(doc)); // CSS selector utility
249
- if(hasExecutable) doc.head.appendChild(rAfter(doc)); // Another execution prevention script
270
+ if (hasExecutable) doc.head.appendChild(rAfter(doc)); // Another execution prevention script
271
+
272
+ // Add CSP
273
+ const meta = doc.createElement("meta");
274
+ meta.httpEquiv = "Content-Security-Policy";
275
+ meta.content = csp(root ? [root] : []);
276
+ meta.dataset.readium = "true";
277
+ doc.head.firstChild!.before(meta);
250
278
 
251
279
 
252
280
  // Make blob from doc
253
281
  return URL.createObjectURL(
254
282
  new Blob([new XMLSerializer().serializeToString(doc)], {
255
- type: mediaType.isHTML
256
- ? mediaType.string
257
- : "application/xhtml+xml", // Fallback to XHTML
283
+ type: mediaType.isHTML
284
+ ? mediaType.string
285
+ : "application/xhtml+xml", // Fallback to XHTML
258
286
  })
259
287
  );
260
288
  }
@@ -16,6 +16,7 @@ export class FrameManager {
16
16
 
17
17
  constructor(source: string) {
18
18
  this.frame = document.createElement("iframe");
19
+ this.frame.sandbox.value = "allow-same-origin allow-scripts";
19
20
  this.frame.classList.add("readium-navigator-iframe");
20
21
  this.frame.style.visibility = "hidden";
21
22
  this.frame.style.setProperty("aria-hidden", "true");
@@ -23,6 +23,7 @@ export class FXLFrameManager {
23
23
  this.peripherals = peripherals;
24
24
  this.debugHref = debugHref;
25
25
  this.frame = document.createElement("iframe");
26
+ this.frame.sandbox.value = "allow-same-origin allow-scripts";
26
27
  this.frame.classList.add("readium-navigator-iframe");
27
28
  this.frame.classList.add("blank");
28
29
  this.frame.scrolling = "no";
@@ -1,4 +1,5 @@
1
1
  import {
2
+ ExperimentKey,
2
3
  fontSizeRangeConfig,
3
4
  fontWeightRangeConfig,
4
5
  fontWidthRangeConfig,
@@ -8,13 +9,14 @@ import {
8
9
  import {
9
10
  ensureBoolean,
10
11
  ensureEnumValue,
12
+ ensureExperiment,
11
13
  ensureFilter,
12
14
  ensureLessThanOrEqual,
13
15
  ensureMoreThanOrEqual,
14
16
  ensureNonNegative,
15
17
  ensureString,
16
18
  ensureValueInRange,
17
- withFallback
19
+ withFallback
18
20
  } from "../../preferences/guards";
19
21
 
20
22
  import { sMLWithRequest } from "../../helpers";
@@ -59,7 +61,8 @@ export interface IEpubDefaults {
59
61
  textColor?: string | null,
60
62
  textNormalization?: boolean | null,
61
63
  visitedColor?: string | null,
62
- wordSpacing?: number | null
64
+ wordSpacing?: number | null,
65
+ experiments?: Array<ExperimentKey> | null
63
66
  }
64
67
 
65
68
  export class EpubDefaults {
@@ -103,6 +106,7 @@ export class EpubDefaults {
103
106
  textNormalization: boolean | null;
104
107
  visitedColor: string | null;
105
108
  wordSpacing: number | null;
109
+ experiments: Array<ExperimentKey> | null;
106
110
 
107
111
  constructor(defaults: IEpubDefaults) {
108
112
  this.backgroundColor = ensureString(defaults.backgroundColor) || null;
@@ -153,5 +157,7 @@ export class EpubDefaults {
153
157
  this.optimalLineLength = ensureNonNegative(defaults.optimalLineLength) || 65;
154
158
  this.maximalLineLength = withFallback(ensureMoreThanOrEqual(defaults.maximalLineLength, this.optimalLineLength), 80);
155
159
  this.minimalLineLength = withFallback(ensureLessThanOrEqual(defaults.minimalLineLength, this.optimalLineLength), 40);
160
+
161
+ this.experiments = ensureExperiment(defaults.experiments) || null;
156
162
  }
157
163
  }
@@ -1,5 +1,5 @@
1
1
  import { ConfigurableSettings } from "../../preferences/Configurable";
2
- import { TextAlignment } from "../../preferences/Types";
2
+ import { ExperimentKey, TextAlignment } from "../../preferences/Types";
3
3
  import { EpubDefaults } from "./EpubDefaults";
4
4
  import { EpubPreferences } from "./EpubPreferences";
5
5
 
@@ -45,7 +45,8 @@ export interface IEpubSettings {
45
45
  textColor?: string | null,
46
46
  textNormalization?: boolean | null,
47
47
  visitedColor?: string | null,
48
- wordSpacing?: number | null
48
+ wordSpacing?: number | null,
49
+ experiments?: Array<ExperimentKey> | null
49
50
  }
50
51
 
51
52
  export class EpubSettings implements ConfigurableSettings {
@@ -89,6 +90,7 @@ export class EpubSettings implements ConfigurableSettings {
89
90
  textNormalization: boolean | null;
90
91
  visitedColor: string | null;
91
92
  wordSpacing: number | null;
93
+ experiments: Array<ExperimentKey> | null;
92
94
 
93
95
  constructor(preferences: EpubPreferences, defaults: EpubDefaults) {
94
96
  this.backgroundColor = preferences.backgroundColor || defaults.backgroundColor || null;
@@ -229,5 +231,7 @@ export class EpubSettings implements ConfigurableSettings {
229
231
  : defaults.wordSpacing !== undefined
230
232
  ? defaults.wordSpacing
231
233
  : null;
234
+
235
+ this.experiments = defaults.experiments || null;
232
236
  }
233
237
  }
@@ -1,3 +1,9 @@
1
+ import RCSSExperiments from "@readium/css/css/vars/experiments.json";
2
+
3
+ export type ExperimentKey = keyof typeof RCSSExperiments;
4
+
5
+ export const experiments = RCSSExperiments;
6
+
1
7
  export enum TextAlignment {
2
8
  start = "start",
3
9
  left = "left",
@@ -1,3 +1,5 @@
1
+ import { ExperimentKey, experiments } from './Types';
2
+
1
3
  export function ensureLessThanOrEqual<T extends number | null | undefined>(value: T, compareTo: T): T | undefined {
2
4
  if (value === undefined || value === null) {
3
5
  return value;
@@ -83,3 +85,13 @@ export function ensureValueInRange(value: number | null | undefined, range: [num
83
85
  export function withFallback<T>(value: T | null | undefined, defaultValue: T | null): T | null {
84
86
  return value === undefined ? defaultValue : value;
85
87
  }
88
+
89
+ export function ensureExperiment(experimentsInput: ExperimentKey[] | null | undefined): ExperimentKey[] | null | undefined {
90
+ if (experimentsInput === undefined) {
91
+ return undefined;
92
+ }
93
+ if (experimentsInput === null) {
94
+ return null;
95
+ }
96
+ return experimentsInput.filter(exp => exp in experiments);
97
+ }
@@ -8,12 +8,13 @@ import { WebPubFrameManager } from "./WebPubFrameManager";
8
8
 
9
9
  import { ManagerEventKey } from "../epub/EpubNavigator";
10
10
  import { WebPubCSS } from "./css/WebPubCSS";
11
- import { WebUserProperties } from "./css/Properties";
11
+ import { WebUserProperties, WebRSProperties } from "./css/Properties";
12
12
  import { IWebPubPreferences, WebPubPreferences } from "./preferences/WebPubPreferences";
13
13
  import { IWebPubDefaults, WebPubDefaults } from "./preferences/WebPubDefaults";
14
14
  import { WebPubSettings } from "./preferences/WebPubSettings";
15
15
  import { IPreferencesEditor } from "../preferences/PreferencesEditor";
16
16
  import { WebPubPreferencesEditor } from "./preferences/WebPubPreferencesEditor";
17
+
17
18
  export interface WebPubNavigatorConfiguration {
18
19
  preferences: IWebPubPreferences;
19
20
  defaults: IWebPubDefaults;
@@ -74,6 +75,7 @@ export class WebPubNavigator extends VisualNavigator implements Configurable<Web
74
75
  this._defaults = new WebPubDefaults(configuration.defaults);
75
76
  this._settings = new WebPubSettings(this._preferences, this._defaults, this.hasDisplayTransformability);
76
77
  this._css = new WebPubCSS({
78
+ rsProperties: new WebRSProperties({ experiments: this._settings.experiments || null }),
77
79
  userProperties: new WebUserProperties({ zoom: this._settings.zoom })
78
80
  });
79
81
 
@@ -135,6 +137,12 @@ export class WebPubNavigator extends VisualNavigator implements Configurable<Web
135
137
  private compileCSSProperties(css: WebPubCSS) {
136
138
  const properties: { [key: string]: string } = {};
137
139
 
140
+ // Include RS properties (i.e. experiments)
141
+ for (const [key, value] of Object.entries(css.rsProperties.toCSSProperties())) {
142
+ properties[key] = value;
143
+ }
144
+
145
+ // Include user properties
138
146
  for (const [key, value] of Object.entries(css.userProperties.toCSSProperties())) {
139
147
  properties[key] = value;
140
148
  }
@@ -1,4 +1,4 @@
1
- import { TextAlignment } from "../../preferences/Types";
1
+ import { ExperimentKey, experiments, TextAlignment } from "../../preferences/Types";
2
2
  import { BodyHyphens, Ligatures, Properties } from "../../css/Properties";
3
3
 
4
4
  export interface IWebUserProperties {
@@ -77,3 +77,28 @@ export class WebUserProperties extends Properties {
77
77
  return cssProperties;
78
78
  }
79
79
  }
80
+
81
+ export interface IWebRSProperties {
82
+ experiments: Array<ExperimentKey> | null;
83
+ }
84
+
85
+ export class WebRSProperties extends Properties {
86
+ experiments: Array<ExperimentKey> | null;
87
+
88
+ constructor(props: IWebRSProperties) {
89
+ super();
90
+ this.experiments = props.experiments ?? null;
91
+ }
92
+
93
+ toCSSProperties() {
94
+ const cssProperties: { [key: string]: string } = {};
95
+
96
+ if (this.experiments) {
97
+ this.experiments.forEach((exp) => {
98
+ cssProperties["--RS__" + exp] = experiments[exp].value;
99
+ });
100
+ };
101
+
102
+ return cssProperties;
103
+ }
104
+ }
@@ -1,18 +1,25 @@
1
1
  import { WebPubSettings } from "../preferences/WebPubSettings";
2
- import { IWebUserProperties, WebUserProperties } from "./Properties";
2
+ import { IWebUserProperties, WebRSProperties, WebUserProperties } from "./Properties";
3
3
 
4
4
  export interface IWebPubCSS {
5
+ rsProperties: WebRSProperties;
5
6
  userProperties: WebUserProperties;
6
7
  }
7
8
 
8
9
  export class WebPubCSS {
10
+ rsProperties: WebRSProperties;
9
11
  userProperties: WebUserProperties;
10
12
 
11
13
  constructor(props: IWebPubCSS) {
14
+ this.rsProperties = props.rsProperties;
12
15
  this.userProperties = props.userProperties;
13
16
  }
14
17
 
15
18
  update(settings: WebPubSettings) {
19
+ if (settings.experiments) {
20
+ this.rsProperties.experiments = settings.experiments;
21
+ }
22
+
16
23
  const updated: IWebUserProperties = {
17
24
  a11yNormalize: settings.textNormalization,
18
25
  bodyHyphens: typeof settings.hyphens !== "boolean"
@@ -1,4 +1,5 @@
1
1
  import {
2
+ ExperimentKey,
2
3
  fontWeightRangeConfig,
3
4
  TextAlignment,
4
5
  zoomRangeConfig
@@ -9,7 +10,8 @@ import {
9
10
  ensureEnumValue,
10
11
  ensureNonNegative,
11
12
  ensureValueInRange,
12
- ensureString
13
+ ensureString,
14
+ ensureExperiment
13
15
  } from "../../preferences/guards";
14
16
 
15
17
  import { sMLWithRequest } from "../../helpers";
@@ -29,7 +31,8 @@ export interface IWebPubDefaults {
29
31
  textAlign?: TextAlignment | null,
30
32
  textNormalization?: boolean | null,
31
33
  wordSpacing?: number | null,
32
- zoom?: number | null
34
+ zoom?: number | null,
35
+ experiments?: Array<ExperimentKey> | null,
33
36
  }
34
37
 
35
38
  export class WebPubDefaults {
@@ -48,6 +51,7 @@ export class WebPubDefaults {
48
51
  textNormalization: boolean | null;
49
52
  wordSpacing: number | null;
50
53
  zoom: number;
54
+ experiments: Array<ExperimentKey> | null;
51
55
 
52
56
  constructor(defaults: IWebPubDefaults) {
53
57
  this.fontFamily = ensureString(defaults.fontFamily) || null;
@@ -69,5 +73,6 @@ export class WebPubDefaults {
69
73
  this.textNormalization = ensureBoolean(defaults.textNormalization) ?? false;
70
74
  this.wordSpacing = ensureNonNegative(defaults.wordSpacing) || null;
71
75
  this.zoom = ensureValueInRange(defaults.zoom, zoomRangeConfig.range) || 1;
76
+ this.experiments = ensureExperiment(defaults.experiments) ?? null;
72
77
  }
73
78
  }
@@ -1,5 +1,5 @@
1
1
  import { ConfigurableSettings } from "../../preferences/Configurable";
2
- import { TextAlignment } from "../../preferences/Types";
2
+ import { ExperimentKey, TextAlignment } from "../../preferences/Types";
3
3
  import { WebPubDefaults } from "./WebPubDefaults";
4
4
  import { WebPubPreferences } from "./WebPubPreferences";
5
5
 
@@ -20,7 +20,8 @@ export interface IWebPubSettings {
20
20
  textAlign?: TextAlignment | null,
21
21
  textNormalization?: boolean | null,
22
22
  wordSpacing?: number | null,
23
- zoom?: number | null;
23
+ zoom?: number | null,
24
+ experiments?: Array<ExperimentKey> | null,
24
25
  }
25
26
 
26
27
  export class WebPubSettings implements ConfigurableSettings {
@@ -39,6 +40,7 @@ export class WebPubSettings implements ConfigurableSettings {
39
40
  textNormalization: boolean | null = null;
40
41
  wordSpacing: number | null = null;
41
42
  zoom: number | null;
43
+ experiments: Array<ExperimentKey> | null;
42
44
 
43
45
  constructor(preferences: WebPubPreferences, defaults: WebPubDefaults, hasDisplayTransformability: boolean) {
44
46
  if (hasDisplayTransformability) {
@@ -103,5 +105,7 @@ export class WebPubSettings implements ConfigurableSettings {
103
105
  : defaults.zoom !== undefined
104
106
  ? defaults.zoom
105
107
  : null;
108
+
109
+ this.experiments = defaults.experiments || null;
106
110
  }
107
111
  }
@@ -1,4 +1,4 @@
1
- import { TextAlignment } from "../../preferences/Types";
1
+ import { ExperimentKey, TextAlignment } from "../../preferences/Types";
2
2
  import { BodyHyphens, BoxSizing, FontOpticalSizing, FontWidth, Ligatures, Properties, TypeScale, View } from "../../css/Properties";
3
3
  export interface IUserProperties {
4
4
  advancedSettings?: boolean | null;
@@ -113,6 +113,7 @@ export interface IRSProperties {
113
113
  textColor?: string | null;
114
114
  typeScale?: TypeScale | null;
115
115
  visitedColor?: string | null;
116
+ experiments?: Array<ExperimentKey> | null;
116
117
  }
117
118
  export declare class RSProperties extends Properties {
118
119
  backgroundColor: string | null;
@@ -154,6 +155,7 @@ export declare class RSProperties extends Properties {
154
155
  textColor: string | null;
155
156
  typeScale: TypeScale | null;
156
157
  visitedColor: string | null;
158
+ experiments: Array<ExperimentKey> | null;
157
159
  constructor(props: IRSProperties);
158
160
  toCSSProperties(): {
159
161
  [key: string]: string;
@@ -1,4 +1,4 @@
1
- import { TextAlignment } from "../../preferences/Types";
1
+ import { ExperimentKey, TextAlignment } from "../../preferences/Types";
2
2
  export interface IEpubDefaults {
3
3
  backgroundColor?: string | null;
4
4
  blendFilter?: boolean | null;
@@ -38,6 +38,7 @@ export interface IEpubDefaults {
38
38
  textNormalization?: boolean | null;
39
39
  visitedColor?: string | null;
40
40
  wordSpacing?: number | null;
41
+ experiments?: Array<ExperimentKey> | null;
41
42
  }
42
43
  export declare class EpubDefaults {
43
44
  backgroundColor: string | null;
@@ -78,5 +79,6 @@ export declare class EpubDefaults {
78
79
  textNormalization: boolean | null;
79
80
  visitedColor: string | null;
80
81
  wordSpacing: number | null;
82
+ experiments: Array<ExperimentKey> | null;
81
83
  constructor(defaults: IEpubDefaults);
82
84
  }
@@ -1,5 +1,5 @@
1
1
  import { ConfigurableSettings } from "../../preferences/Configurable";
2
- import { TextAlignment } from "../../preferences/Types";
2
+ import { ExperimentKey, TextAlignment } from "../../preferences/Types";
3
3
  import { EpubDefaults } from "./EpubDefaults";
4
4
  import { EpubPreferences } from "./EpubPreferences";
5
5
  export interface IEpubSettings {
@@ -41,6 +41,7 @@ export interface IEpubSettings {
41
41
  textNormalization?: boolean | null;
42
42
  visitedColor?: string | null;
43
43
  wordSpacing?: number | null;
44
+ experiments?: Array<ExperimentKey> | null;
44
45
  }
45
46
  export declare class EpubSettings implements ConfigurableSettings {
46
47
  backgroundColor: string | null;
@@ -81,5 +82,6 @@ export declare class EpubSettings implements ConfigurableSettings {
81
82
  textNormalization: boolean | null;
82
83
  visitedColor: string | null;
83
84
  wordSpacing: number | null;
85
+ experiments: Array<ExperimentKey> | null;
84
86
  constructor(preferences: EpubPreferences, defaults: EpubDefaults);
85
87
  }
@@ -1,3 +1,17 @@
1
+ import RCSSExperiments from "@readium/css/css/vars/experiments.json";
2
+ export type ExperimentKey = keyof typeof RCSSExperiments;
3
+ export declare const experiments: {
4
+ experimentalHeaderFiltering: {
5
+ description: string;
6
+ scope: string;
7
+ value: string;
8
+ };
9
+ experimentalZoom: {
10
+ description: string;
11
+ scope: string;
12
+ value: string;
13
+ };
14
+ };
1
15
  export declare enum TextAlignment {
2
16
  start = "start",
3
17
  left = "left",
@@ -1,3 +1,4 @@
1
+ import { ExperimentKey } from './Types';
1
2
  export declare function ensureLessThanOrEqual<T extends number | null | undefined>(value: T, compareTo: T): T | undefined;
2
3
  export declare function ensureMoreThanOrEqual<T extends number | null | undefined>(value: T, compareTo: T): T | undefined;
3
4
  export declare function ensureString(value: string | null | undefined): string | null | undefined;
@@ -7,3 +8,4 @@ export declare function ensureFilter(filter: boolean | number | null | undefined
7
8
  export declare function ensureNonNegative(value: number | null | undefined): number | null | undefined;
8
9
  export declare function ensureValueInRange(value: number | null | undefined, range: [number, number]): number | null | undefined;
9
10
  export declare function withFallback<T>(value: T | null | undefined, defaultValue: T | null): T | null;
11
+ export declare function ensureExperiment(experimentsInput: ExperimentKey[] | null | undefined): ExperimentKey[] | null | undefined;
@@ -1,4 +1,4 @@
1
- import { TextAlignment } from "../../preferences/Types";
1
+ import { ExperimentKey, TextAlignment } from "../../preferences/Types";
2
2
  import { BodyHyphens, Ligatures, Properties } from "../../css/Properties";
3
3
  export interface IWebUserProperties {
4
4
  a11yNormalize?: boolean | null;
@@ -38,3 +38,13 @@ export declare class WebUserProperties extends Properties {
38
38
  [key: string]: string;
39
39
  };
40
40
  }
41
+ export interface IWebRSProperties {
42
+ experiments: Array<ExperimentKey> | null;
43
+ }
44
+ export declare class WebRSProperties extends Properties {
45
+ experiments: Array<ExperimentKey> | null;
46
+ constructor(props: IWebRSProperties);
47
+ toCSSProperties(): {
48
+ [key: string]: string;
49
+ };
50
+ }
@@ -1,9 +1,11 @@
1
1
  import { WebPubSettings } from "../preferences/WebPubSettings";
2
- import { WebUserProperties } from "./Properties";
2
+ import { WebRSProperties, WebUserProperties } from "./Properties";
3
3
  export interface IWebPubCSS {
4
+ rsProperties: WebRSProperties;
4
5
  userProperties: WebUserProperties;
5
6
  }
6
7
  export declare class WebPubCSS {
8
+ rsProperties: WebRSProperties;
7
9
  userProperties: WebUserProperties;
8
10
  constructor(props: IWebPubCSS);
9
11
  update(settings: WebPubSettings): void;
@@ -1,4 +1,4 @@
1
- import { TextAlignment } from "../../preferences/Types";
1
+ import { ExperimentKey, TextAlignment } from "../../preferences/Types";
2
2
  export interface IWebPubDefaults {
3
3
  fontFamily?: string | null;
4
4
  fontWeight?: number | null;
@@ -15,6 +15,7 @@ export interface IWebPubDefaults {
15
15
  textNormalization?: boolean | null;
16
16
  wordSpacing?: number | null;
17
17
  zoom?: number | null;
18
+ experiments?: Array<ExperimentKey> | null;
18
19
  }
19
20
  export declare class WebPubDefaults {
20
21
  fontFamily: string | null;
@@ -32,5 +33,6 @@ export declare class WebPubDefaults {
32
33
  textNormalization: boolean | null;
33
34
  wordSpacing: number | null;
34
35
  zoom: number;
36
+ experiments: Array<ExperimentKey> | null;
35
37
  constructor(defaults: IWebPubDefaults);
36
38
  }