Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions navigator/CHANGELOG.MD
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,18 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [2.2.4] - 2025-11-06

### Added

- Added the handling of iOS and iPadOS patches to the WebPub Preferences API

### Changed

- Updated ReadiumCSS to `v2.0.0-beta.22`
- Switched experimental WebPublication Navigator Preferences to ReadiumCSS
- Updated ligatures handling in EpubPreferencesEditor to match ReadiumCSS

## [2.2.3] - 2025-11-01

### Fixed
Expand Down
4 changes: 2 additions & 2 deletions navigator/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@readium/navigator",
"version": "2.2.3",
"version": "2.2.4",
"type": "module",
"description": "Next generation SDK for publications in Web Apps",
"author": "readium",
Expand Down Expand Up @@ -49,7 +49,7 @@
},
"devDependencies": {
"@laynezh/vite-plugin-lib-assets": "^2.1.0",
"@readium/css": "2.0.0-beta.20",
"@readium/css": "2.0.0-beta.22",
"@readium/navigator-html-injectables": "workspace:*",
"@readium/shared": "workspace:*",
"@types/path-browserify": "^1.0.3",
Expand Down
27 changes: 24 additions & 3 deletions navigator/src/epub/preferences/EpubPreferencesEditor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -256,9 +256,30 @@ export class EpubPreferencesEditor implements IPreferencesEditor {
return new BooleanPreference({
initialValue: this.preferences.ligatures,
effectiveValue: this.settings.ligatures || true,
isEffective: this.layout !== Layout.fixed
&& this.metadata?.languages?.some(lang => lang === "ar" || lang === "fa")
&& this.preferences.ligatures !== null || false,
isEffective: (() => {
// Always respect explicit null (disabled) preference
if (this.preferences.ligatures === null) {
return false;
}

// Disable for fixed layout
if (this.layout === Layout.fixed) {
return false;
}

// Check for languages/scripts that should disable ligatures
// ReadiumCSS does not apply in CJK
const primaryLang = this.metadata?.languages?.[0]?.toLowerCase();
if (primaryLang) {
// Disable for Chinese, Japanese, Korean, and Traditional Mongolian (mn-Mong)
if (["zh", "ja", "ko", "mn-mong"].some(lang => primaryLang.startsWith(lang))) {
return false;
}
}

// Enable by default
return true;
})(),
onChange: (newValue: boolean | null | undefined) => {
this.updatePreference("ligatures", newValue || null);
}
Expand Down
25 changes: 17 additions & 8 deletions navigator/src/webpub/WebPubBlobBuilder.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,35 @@
import { Link, Publication } from "@readium/shared";
import { webPubStylesheet } from "./css/WebPubStylesheet";

// Utilities (matching FrameBlobBuilder pattern)
// Readium CSS imports
// The "?inline" query is to prevent some bundlers from injecting these into the page (e.g. vite)
// @ts-ignore
import readiumCSSWebPub from "@readium/css/css/dist/webPub/ReadiumCSS-webPub.css?inline";

// Utilities
const blobify = (source: string, type: string) => URL.createObjectURL(new Blob([source], { type }));
const stripJS = (source: string) => source.replace(/\/\/.*/g, "").replace(/\/\*[\s\S]*?\*\//g, "").replace(/\n/g, "").replace(/\s+/g, " ");
const stripCSS = (source: string) => source.replace(/\/\*(?:(?!\*\/)[\s\S])*\*\/|[\r\n\t]+/g, '').replace(/ {2,}/g, ' ')
// Fully resolve absolute local URLs created by bundlers since it's going into a blob
.replace(/url\((?!(https?:)?\/\/)("?)\/([^\)]+)/g, `url($2${window.location.origin}/$3`);
const scriptify = (doc: Document, source: string) => {
const s = doc.createElement("script");
s.dataset.readium = "true";
s.src = source.startsWith("blob:") ? source : blobify(source, "text/javascript");
return s;
}
const styleify = (doc: Document, source: string) => {
const s = doc.createElement("style");
const s = doc.createElement("link");
s.dataset.readium = "true";
s.textContent = source;
s.rel = "stylesheet";
s.type = "text/css";
s.href = source.startsWith("blob:") ? source : blobify(source, "text/css");
return s;
}

type CacheFunction = () => string;
const resourceBlobCache = new Map<string, string>();
const cached = (key: string, cacher: CacheFunction) => {
if (resourceBlobCache.has(key)) return resourceBlobCache.get(key)!;
if(resourceBlobCache.has(key)) return resourceBlobCache.get(key)!;
const value = cacher();
resourceBlobCache.set(key, value);
return value;
Expand Down Expand Up @@ -103,9 +112,9 @@ export class WebPubBlobBuilder {
private finalizeDOM(doc: Document, base: string | undefined, mediaType: any, txt?: string, cssProperties?: { [key: string]: string }): string {
if(!doc) return "";

// Add WebPubCSS stylesheet at end of head (like EPUB ReadiumCSS-after)
const webPubStyle = styleify(doc, webPubStylesheet);
doc.head.appendChild(webPubStyle);
// ReadiumCSS WebPub
doc.head.appendChild(styleify(doc, cached("ReadiumCSS-webpub", () => blobify(stripCSS(readiumCSSWebPub), "text/css"))));

if (cssProperties) {
this.setProperties(cssProperties, doc);
}
Expand Down
8 changes: 8 additions & 0 deletions navigator/src/webpub/css/Properties.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ export interface IWebUserProperties {
bodyHyphens?: BodyHyphens | null;
fontFamily?: string | null;
fontWeight?: number | null;
iOSPatch?: boolean | null;
iPadOSPatch?: boolean | null;
letterSpacing?: number | null;
ligatures?: Ligatures | null;
lineHeight?: number | null;
Expand All @@ -22,6 +24,8 @@ export class WebUserProperties extends Properties {
bodyHyphens: BodyHyphens | null;
fontFamily: string | null;
fontWeight: number | null;
iOSPatch: boolean | null;
iPadOSPatch: boolean | null;
letterSpacing: number | null;
ligatures: Ligatures | null;
lineHeight: number | null;
Expand All @@ -38,6 +42,8 @@ export class WebUserProperties extends Properties {
this.bodyHyphens = props.bodyHyphens ?? null;
this.fontFamily = props.fontFamily ?? null;
this.fontWeight = props.fontWeight ?? null;
this.iOSPatch = props.iOSPatch ?? null;
this.iPadOSPatch = props.iPadOSPatch ?? null;
this.letterSpacing = props.letterSpacing ?? null;
this.ligatures = props.ligatures ?? null;
this.lineHeight = props.lineHeight ?? null;
Expand All @@ -56,6 +62,8 @@ export class WebUserProperties extends Properties {
if (this.bodyHyphens) cssProperties["--USER__bodyHyphens"] = this.bodyHyphens;
if (this.fontFamily) cssProperties["--USER__fontFamily"] = this.fontFamily;
if (this.fontWeight != null) cssProperties["--USER__fontWeight"] = this.toUnitless(this.fontWeight);
if (this.iOSPatch) cssProperties["--USER__iOSPatch"] = this.toFlag("iOSPatch");
if (this.iPadOSPatch) cssProperties["--USER__iPadOSPatch"] = this.toFlag("iPadOSPatch");
if (this.letterSpacing != null) cssProperties["--USER__letterSpacing"] = this.toRem(this.letterSpacing);
if (this.ligatures) cssProperties["--USER__ligatures"] = this.ligatures;
if (this.lineHeight != null) cssProperties["--USER__lineHeight"] = this.toUnitless(this.lineHeight);
Expand Down
2 changes: 2 additions & 0 deletions navigator/src/webpub/css/WebPubCSS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ export class WebPubCSS {
: "none",
fontFamily: settings.fontFamily,
fontWeight: settings.fontWeight,
iOSPatch: settings.iOSPatch,
iPadOSPatch: settings.iPadOSPatch,
letterSpacing: settings.letterSpacing,
ligatures: typeof settings.ligatures !== "boolean"
? null
Expand Down
205 changes: 0 additions & 205 deletions navigator/src/webpub/css/WebPubStylesheet.ts

This file was deleted.

3 changes: 1 addition & 2 deletions navigator/src/webpub/css/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
export * from "./Properties";
export * from "./WebPubCSS";
export * from "./WebPubStylesheet";
export * from "./WebPubCSS";
Loading