react-native-readium 4.0.1 → 5.0.0-rc.0
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/README.md +93 -9
- package/android/build.gradle +32 -29
- package/android/gradle.properties +3 -3
- package/android/src/main/java/com/reactnativereadium/ReadiumView.kt +88 -28
- package/android/src/main/java/com/reactnativereadium/ReadiumViewManager.kt +20 -19
- package/android/src/main/java/com/reactnativereadium/reader/BaseReaderFragment.kt +27 -6
- package/android/src/main/java/com/reactnativereadium/reader/EpubReaderFragment.kt +53 -69
- package/android/src/main/java/com/reactnativereadium/reader/PositionLabelManager.kt +132 -0
- package/android/src/main/java/com/reactnativereadium/reader/ReaderService.kt +64 -65
- package/android/src/main/java/com/reactnativereadium/reader/ReaderViewModel.kt +6 -85
- package/android/src/main/java/com/reactnativereadium/reader/VisualReaderFragment.kt +32 -2
- package/android/src/main/java/com/reactnativereadium/utils/FragmentFactory.kt +2 -3
- package/android/src/main/java/com/reactnativereadium/utils/JsonExtensions.kt +61 -0
- package/android/src/main/java/com/reactnativereadium/utils/MetadataNormalizer.kt +183 -0
- package/android/src/main/java/com/reactnativereadium/utils/NormalizedMetadata.kt +179 -0
- package/android/src/main/java/com/reactnativereadium/utils/extensions/InputStream.kt +0 -9
- package/ios/App/AppModule.swift +3 -9
- package/ios/Common/Toolkit/Extensions/Locator.swift +1 -1
- package/ios/Data/Bookmark.swift +1 -1
- package/ios/Reader/Common/ReaderViewController.swift +118 -21
- package/ios/Reader/EPUB/AssociatedColors.swift +1 -1
- package/ios/Reader/EPUB/EPUBHTTPServer.swift +13 -0
- package/ios/Reader/EPUB/EPUBModule.swift +1 -1
- package/ios/Reader/EPUB/EPUBViewController.swift +3 -4
- package/ios/Reader/ReaderFormatModule.swift +1 -1
- package/ios/Reader/ReaderModule.swift +1 -1
- package/ios/Reader/ReaderService.swift +70 -35
- package/ios/ReadiumView.swift +62 -25
- package/ios/ReadiumViewManager.m +1 -1
- package/lib/src/ReadiumViewNativeComponent.d.ts +19 -0
- package/lib/src/ReadiumViewNativeComponent.js +10 -0
- package/lib/src/components/BaseReadiumView.d.ts +1 -2
- package/lib/src/components/BaseReadiumView.js +3 -7
- package/lib/src/components/ReadiumView.js +15 -15
- package/lib/src/components/ReadiumView.web.js +100 -21
- package/lib/src/interfaces/BaseReadiumViewProps.d.ts +2 -1
- package/lib/src/interfaces/Preferences.d.ts +3 -2
- package/lib/src/interfaces/PublicationMetadata.d.ts +114 -0
- package/lib/src/interfaces/PublicationMetadata.js +1 -0
- package/lib/src/interfaces/PublicationReady.d.ts +15 -0
- package/lib/src/interfaces/PublicationReady.js +1 -0
- package/lib/src/interfaces/index.d.ts +2 -0
- package/lib/src/interfaces/index.js +2 -0
- package/lib/src/utils/index.d.ts +0 -1
- package/lib/src/utils/index.js +0 -1
- package/lib/web/hooks/index.d.ts +3 -2
- package/lib/web/hooks/index.js +3 -2
- package/lib/web/hooks/useLocationObserver.d.ts +2 -1
- package/lib/web/hooks/useLocationObserver.js +18 -11
- package/lib/web/hooks/useNavigator.d.ts +12 -0
- package/lib/web/hooks/useNavigator.js +87 -0
- package/lib/web/hooks/usePositionLabel.d.ts +9 -0
- package/lib/web/hooks/usePositionLabel.js +33 -0
- package/lib/web/hooks/usePreferencesObserver.d.ts +2 -0
- package/lib/web/hooks/usePreferencesObserver.js +54 -0
- package/lib/web/utils/manifestFetcher.d.ts +8 -0
- package/lib/web/utils/manifestFetcher.js +28 -0
- package/lib/web/utils/manifestNormalizer.d.ts +8 -0
- package/lib/web/utils/manifestNormalizer.js +70 -0
- package/lib/web/utils/metadataNormalizer.d.ts +53 -0
- package/lib/web/utils/metadataNormalizer.js +220 -0
- package/lib/web/utils/navigatorListeners.d.ts +6 -0
- package/lib/web/utils/navigatorListeners.js +50 -0
- package/lib/web/utils/publicationUtils.d.ts +15 -0
- package/lib/web/utils/publicationUtils.js +39 -0
- package/package.json +24 -14
- package/react-native-readium.podspec +7 -5
- package/src/ReadiumViewNativeComponent.ts +35 -0
- package/src/components/BaseReadiumView.tsx +3 -10
- package/src/components/ReadiumView.tsx +15 -15
- package/src/components/ReadiumView.web.tsx +120 -27
- package/src/interfaces/BaseReadiumViewProps.ts +2 -1
- package/src/interfaces/Preferences.ts +3 -2
- package/src/interfaces/PublicationMetadata.ts +141 -0
- package/src/interfaces/PublicationReady.ts +18 -0
- package/src/interfaces/index.ts +2 -0
- package/src/utils/index.ts +0 -1
- package/web/hooks/index.ts +3 -2
- package/web/hooks/useLocationObserver.ts +24 -11
- package/web/hooks/useNavigator.ts +146 -0
- package/web/hooks/usePositionLabel.ts +51 -0
- package/web/hooks/usePreferencesObserver.ts +69 -0
- package/web/utils/manifestFetcher.ts +38 -0
- package/web/utils/manifestNormalizer.ts +74 -0
- package/web/utils/metadataNormalizer.ts +238 -0
- package/web/utils/navigatorListeners.ts +60 -0
- package/web/utils/publicationUtils.ts +47 -0
- package/android/src/main/java/com/reactnativereadium/search/SearchFragment.kt +0 -100
- package/android/src/main/java/com/reactnativereadium/search/SearchPagingSource.kt +0 -44
- package/android/src/main/java/com/reactnativereadium/search/SearchResultAdapter.kt +0 -68
- package/android/src/main/java/com/reactnativereadium/utils/R2DispatcherActivity.kt +0 -45
- package/android/src/main/java/com/reactnativereadium/utils/SectionDecoration.kt +0 -98
- package/android/src/main/java/com/reactnativereadium/utils/SingleClickListener.kt +0 -32
- package/android/src/main/java/com/reactnativereadium/utils/extensions/Bitmap.kt +0 -23
- package/android/src/main/java/com/reactnativereadium/utils/extensions/Context.kt +0 -16
- package/android/src/main/java/com/reactnativereadium/utils/extensions/File.kt +0 -22
- package/android/src/main/java/com/reactnativereadium/utils/extensions/Link.kt +0 -6
- package/android/src/main/java/com/reactnativereadium/utils/extensions/Metadata.kt +0 -6
- package/android/src/main/java/com/reactnativereadium/utils/extensions/URL.kt +0 -29
- package/android/src/main/java/com/reactnativereadium/utils/extensions/Uri.kt +0 -17
- package/android/src/main/res/layout/fragment_search.xml +0 -39
- package/android/src/main/res/layout/item_recycle_search.xml +0 -14
- package/ios/Common/EPUBPreferences.swift +0 -8
- package/ios/Common/Paths.swift +0 -52
- package/ios/Common/Publication.swift +0 -15
- package/ios/Common/Toolkit/Extensions/HTTPClient.swift +0 -65
- package/ios/Common/Toolkit/Extensions/UIImage.swift +0 -12
- package/ios/Common/Toolkit/Extensions/UIViewController.swift +0 -19
- package/ios/Common/Toolkit/ScreenOrientation.swift +0 -13
- package/lib/src/utils/createFragment.d.ts +0 -1
- package/lib/src/utils/createFragment.js +0 -10
- package/lib/web/hooks/useReaderRef.d.ts +0 -3
- package/lib/web/hooks/useReaderRef.js +0 -85
- package/lib/web/hooks/useSettingsObserver.d.ts +0 -2
- package/lib/web/hooks/useSettingsObserver.js +0 -44
- package/src/utils/createFragment.ts +0 -15
- package/web/hooks/useReaderRef.ts +0 -109
- package/web/hooks/useSettingsObserver.ts +0 -61
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Normalizes a Readium manifest object to ensure compatibility with the navigator.
|
|
3
|
+
* Handles various inconsistencies in manifest formats:
|
|
4
|
+
* - Converts string properties to arrays where required
|
|
5
|
+
* - Normalizes date formats to ISO 8601
|
|
6
|
+
* - Ensures required properties exist
|
|
7
|
+
*/
|
|
8
|
+
export declare function normalizeManifest(manifest: any): any;
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Normalizes a Readium manifest object to ensure compatibility with the navigator.
|
|
3
|
+
* Handles various inconsistencies in manifest formats:
|
|
4
|
+
* - Converts string properties to arrays where required
|
|
5
|
+
* - Normalizes date formats to ISO 8601
|
|
6
|
+
* - Ensures required properties exist
|
|
7
|
+
*/
|
|
8
|
+
export function normalizeManifest(manifest) {
|
|
9
|
+
const responseObj = manifest;
|
|
10
|
+
const metadata = responseObj.metadata;
|
|
11
|
+
// Normalize root-level properties
|
|
12
|
+
if (typeof responseObj.conformsTo === 'string') {
|
|
13
|
+
responseObj.conformsTo = [responseObj.conformsTo];
|
|
14
|
+
}
|
|
15
|
+
if (typeof metadata?.conformsTo === 'string') {
|
|
16
|
+
metadata.conformsTo = [metadata.conformsTo];
|
|
17
|
+
}
|
|
18
|
+
if (typeof metadata?.accessMode === 'string') {
|
|
19
|
+
metadata.accessMode = [metadata.accessMode];
|
|
20
|
+
}
|
|
21
|
+
if (typeof metadata?.accessibilityFeature === 'string') {
|
|
22
|
+
metadata.accessibilityFeature = [metadata.accessibilityFeature];
|
|
23
|
+
}
|
|
24
|
+
if (typeof metadata?.accessibilityHazard === 'string') {
|
|
25
|
+
metadata.accessibilityHazard = [metadata.accessibilityHazard];
|
|
26
|
+
}
|
|
27
|
+
// Normalize nested accessibility properties
|
|
28
|
+
const accessibility = metadata?.accessibility;
|
|
29
|
+
if (accessibility) {
|
|
30
|
+
if (typeof accessibility.conformsTo === 'string') {
|
|
31
|
+
accessibility.conformsTo = [accessibility.conformsTo];
|
|
32
|
+
}
|
|
33
|
+
if (typeof accessibility.accessMode === 'string') {
|
|
34
|
+
accessibility.accessMode = [accessibility.accessMode];
|
|
35
|
+
}
|
|
36
|
+
if (typeof accessibility.feature === 'string') {
|
|
37
|
+
accessibility.feature = [accessibility.feature];
|
|
38
|
+
}
|
|
39
|
+
if (typeof accessibility.hazard === 'string') {
|
|
40
|
+
accessibility.hazard = [accessibility.hazard];
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
// Normalize date formats
|
|
44
|
+
// Some manifests use JavaScript Date.toString() format instead of ISO 8601
|
|
45
|
+
if (metadata?.modified && typeof metadata.modified === 'string') {
|
|
46
|
+
const date = new Date(metadata.modified);
|
|
47
|
+
if (!isNaN(date.getTime())) {
|
|
48
|
+
metadata.modified = date.toISOString();
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
if (metadata?.published && typeof metadata.published === 'string') {
|
|
52
|
+
const date = new Date(metadata.published);
|
|
53
|
+
if (!isNaN(date.getTime())) {
|
|
54
|
+
metadata.published = date.toISOString();
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
// Ensure links property exists (required by RWPM spec)
|
|
58
|
+
// Some manifests may have landmarks instead of links
|
|
59
|
+
if (!responseObj.links) {
|
|
60
|
+
// If landmarks exist, convert them to links
|
|
61
|
+
if (responseObj.landmarks && Array.isArray(responseObj.landmarks)) {
|
|
62
|
+
responseObj.links = responseObj.landmarks;
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
// Otherwise create an empty links array
|
|
66
|
+
responseObj.links = [];
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return responseObj;
|
|
70
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Normalizes metadata to ensure consistent structure per RWPM spec.
|
|
3
|
+
*
|
|
4
|
+
* This normalizer is library-agnostic and based on the stable RWPM specification,
|
|
5
|
+
* ensuring it works regardless of how the underlying Readium library serializes data.
|
|
6
|
+
*
|
|
7
|
+
* https://readium.org/webpub-manifest/
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Normalizes a localized string per RWPM spec.
|
|
11
|
+
*
|
|
12
|
+
* Per RWPM spec, a localized string can be:
|
|
13
|
+
* 1. Plain string: "Moby-Dick"
|
|
14
|
+
* 2. Language map: {"en": "Moby-Dick", "fr": "Moby Dick"}
|
|
15
|
+
*
|
|
16
|
+
* Priority for language selection:
|
|
17
|
+
* 1. "undefined" or "und" (default/undetermined language)
|
|
18
|
+
* 2. "en" (English fallback)
|
|
19
|
+
* 3. First available language
|
|
20
|
+
*
|
|
21
|
+
* https://readium.org/webpub-manifest/contexts/default/
|
|
22
|
+
*/
|
|
23
|
+
export declare function normalizeLocalizedString(value: any): string;
|
|
24
|
+
/**
|
|
25
|
+
* Normalizes contributors per RWPM spec.
|
|
26
|
+
*
|
|
27
|
+
* Per RWPM spec, a contributor can be:
|
|
28
|
+
* 1. Plain string: "Herman Melville"
|
|
29
|
+
* 2. Object: {"name": "Herman Melville", "sortAs": "Melville, Herman"}
|
|
30
|
+
*
|
|
31
|
+
* The Web library uses a Contributors class with an "items" property.
|
|
32
|
+
*
|
|
33
|
+
* https://readium.org/webpub-manifest/schema/contributor-object.schema.json
|
|
34
|
+
*/
|
|
35
|
+
export declare function normalizeContributors(value: any): any[] | undefined;
|
|
36
|
+
/**
|
|
37
|
+
* Normalizes subjects per RWPM spec.
|
|
38
|
+
*
|
|
39
|
+
* Subject names can be LocalizedStrings.
|
|
40
|
+
* The Web library uses a Subjects class with an "items" property.
|
|
41
|
+
*
|
|
42
|
+
* https://readium.org/webpub-manifest/schema/subject.schema.json
|
|
43
|
+
*/
|
|
44
|
+
export declare function normalizeSubjects(value: any): any[] | undefined;
|
|
45
|
+
/**
|
|
46
|
+
* Normalizes the entire metadata object per RWPM spec.
|
|
47
|
+
*
|
|
48
|
+
* This function is library-agnostic and based on the stable RWPM specification,
|
|
49
|
+
* ensuring it works regardless of how the underlying Readium library serializes data.
|
|
50
|
+
*
|
|
51
|
+
* https://readium.org/webpub-manifest/
|
|
52
|
+
*/
|
|
53
|
+
export declare function normalizeMetadata(metadata: any): any;
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Normalizes metadata to ensure consistent structure per RWPM spec.
|
|
3
|
+
*
|
|
4
|
+
* This normalizer is library-agnostic and based on the stable RWPM specification,
|
|
5
|
+
* ensuring it works regardless of how the underlying Readium library serializes data.
|
|
6
|
+
*
|
|
7
|
+
* https://readium.org/webpub-manifest/
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Normalizes a localized string per RWPM spec.
|
|
11
|
+
*
|
|
12
|
+
* Per RWPM spec, a localized string can be:
|
|
13
|
+
* 1. Plain string: "Moby-Dick"
|
|
14
|
+
* 2. Language map: {"en": "Moby-Dick", "fr": "Moby Dick"}
|
|
15
|
+
*
|
|
16
|
+
* Priority for language selection:
|
|
17
|
+
* 1. "undefined" or "und" (default/undetermined language)
|
|
18
|
+
* 2. "en" (English fallback)
|
|
19
|
+
* 3. First available language
|
|
20
|
+
*
|
|
21
|
+
* https://readium.org/webpub-manifest/contexts/default/
|
|
22
|
+
*/
|
|
23
|
+
export function normalizeLocalizedString(value) {
|
|
24
|
+
if (!value)
|
|
25
|
+
return '';
|
|
26
|
+
// Format 1: Plain string (spec-compliant shorthand)
|
|
27
|
+
if (typeof value === 'string')
|
|
28
|
+
return value;
|
|
29
|
+
// Format 2: Language map (spec-compliant full form)
|
|
30
|
+
if (typeof value === 'object') {
|
|
31
|
+
// Check if it's a LocalizedString instance with translations property
|
|
32
|
+
if (value.translations) {
|
|
33
|
+
const translations = value.translations;
|
|
34
|
+
return (translations['undefined'] ||
|
|
35
|
+
translations['und'] ||
|
|
36
|
+
translations['en'] ||
|
|
37
|
+
Object.values(translations)[0] ||
|
|
38
|
+
'');
|
|
39
|
+
}
|
|
40
|
+
// Check if it's already a plain language map object
|
|
41
|
+
return (value['undefined'] ||
|
|
42
|
+
value['und'] ||
|
|
43
|
+
value['en'] ||
|
|
44
|
+
Object.values(value)[0] ||
|
|
45
|
+
'');
|
|
46
|
+
}
|
|
47
|
+
return '';
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Normalizes contributors per RWPM spec.
|
|
51
|
+
*
|
|
52
|
+
* Per RWPM spec, a contributor can be:
|
|
53
|
+
* 1. Plain string: "Herman Melville"
|
|
54
|
+
* 2. Object: {"name": "Herman Melville", "sortAs": "Melville, Herman"}
|
|
55
|
+
*
|
|
56
|
+
* The Web library uses a Contributors class with an "items" property.
|
|
57
|
+
*
|
|
58
|
+
* https://readium.org/webpub-manifest/schema/contributor-object.schema.json
|
|
59
|
+
*/
|
|
60
|
+
export function normalizeContributors(value) {
|
|
61
|
+
if (!value)
|
|
62
|
+
return undefined;
|
|
63
|
+
// Handle TypeScript library's Contributors class format (has .items property)
|
|
64
|
+
const items = value.items || value;
|
|
65
|
+
if (!Array.isArray(items))
|
|
66
|
+
return undefined;
|
|
67
|
+
return items
|
|
68
|
+
.map((contributor) => {
|
|
69
|
+
// Format 1: Plain string
|
|
70
|
+
if (typeof contributor === 'string') {
|
|
71
|
+
return { name: contributor };
|
|
72
|
+
}
|
|
73
|
+
// Format 2: Object with potentially localized fields
|
|
74
|
+
const normalized = {
|
|
75
|
+
name: normalizeLocalizedString(contributor.name),
|
|
76
|
+
};
|
|
77
|
+
if (contributor.sortAs) {
|
|
78
|
+
normalized.sortAs = normalizeLocalizedString(contributor.sortAs);
|
|
79
|
+
}
|
|
80
|
+
if (contributor.identifier) {
|
|
81
|
+
normalized.identifier = contributor.identifier;
|
|
82
|
+
}
|
|
83
|
+
if (contributor.role) {
|
|
84
|
+
normalized.role = contributor.role;
|
|
85
|
+
}
|
|
86
|
+
if (contributor.position !== undefined) {
|
|
87
|
+
normalized.position = contributor.position;
|
|
88
|
+
}
|
|
89
|
+
return normalized;
|
|
90
|
+
})
|
|
91
|
+
.filter((c) => c.name); // Remove contributors without names
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Normalizes subjects per RWPM spec.
|
|
95
|
+
*
|
|
96
|
+
* Subject names can be LocalizedStrings.
|
|
97
|
+
* The Web library uses a Subjects class with an "items" property.
|
|
98
|
+
*
|
|
99
|
+
* https://readium.org/webpub-manifest/schema/subject.schema.json
|
|
100
|
+
*/
|
|
101
|
+
export function normalizeSubjects(value) {
|
|
102
|
+
if (!value)
|
|
103
|
+
return undefined;
|
|
104
|
+
// Handle Subjects class format (has .items property)
|
|
105
|
+
const items = value.items || value;
|
|
106
|
+
if (!Array.isArray(items))
|
|
107
|
+
return undefined;
|
|
108
|
+
return items
|
|
109
|
+
.map((subject) => {
|
|
110
|
+
// Format 1: Plain string
|
|
111
|
+
if (typeof subject === 'string') {
|
|
112
|
+
return { name: subject };
|
|
113
|
+
}
|
|
114
|
+
// Format 2: Object
|
|
115
|
+
const normalized = {
|
|
116
|
+
name: normalizeLocalizedString(subject.name),
|
|
117
|
+
};
|
|
118
|
+
if (subject.sortAs) {
|
|
119
|
+
normalized.sortAs = normalizeLocalizedString(subject.sortAs);
|
|
120
|
+
}
|
|
121
|
+
if (subject.code) {
|
|
122
|
+
normalized.code = subject.code;
|
|
123
|
+
}
|
|
124
|
+
if (subject.scheme) {
|
|
125
|
+
normalized.scheme = subject.scheme;
|
|
126
|
+
}
|
|
127
|
+
return normalized;
|
|
128
|
+
})
|
|
129
|
+
.filter((s) => s.name);
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Normalizes the entire metadata object per RWPM spec.
|
|
133
|
+
*
|
|
134
|
+
* This function is library-agnostic and based on the stable RWPM specification,
|
|
135
|
+
* ensuring it works regardless of how the underlying Readium library serializes data.
|
|
136
|
+
*
|
|
137
|
+
* https://readium.org/webpub-manifest/
|
|
138
|
+
*/
|
|
139
|
+
export function normalizeMetadata(metadata) {
|
|
140
|
+
const normalized = {
|
|
141
|
+
// Title is required
|
|
142
|
+
title: normalizeLocalizedString(metadata.title),
|
|
143
|
+
};
|
|
144
|
+
// Optional localized string fields
|
|
145
|
+
if (metadata.subtitle) {
|
|
146
|
+
normalized.subtitle = normalizeLocalizedString(metadata.subtitle);
|
|
147
|
+
}
|
|
148
|
+
if (metadata.sortAs) {
|
|
149
|
+
normalized.sortAs = normalizeLocalizedString(metadata.sortAs);
|
|
150
|
+
}
|
|
151
|
+
// Direct copy fields
|
|
152
|
+
if (metadata.identifier)
|
|
153
|
+
normalized.identifier = metadata.identifier;
|
|
154
|
+
if (metadata.conformsTo)
|
|
155
|
+
normalized.conformsTo = metadata.conformsTo;
|
|
156
|
+
if (metadata.description)
|
|
157
|
+
normalized.description = metadata.description;
|
|
158
|
+
if (metadata.readingProgression)
|
|
159
|
+
normalized.readingProgression = metadata.readingProgression;
|
|
160
|
+
if (metadata.layout)
|
|
161
|
+
normalized.layout = metadata.layout;
|
|
162
|
+
if (metadata.duration)
|
|
163
|
+
normalized.duration = metadata.duration;
|
|
164
|
+
if (metadata.numberOfPages)
|
|
165
|
+
normalized.numberOfPages = metadata.numberOfPages;
|
|
166
|
+
// Date fields - convert to ISO strings
|
|
167
|
+
if (metadata.modified) {
|
|
168
|
+
normalized.modified =
|
|
169
|
+
metadata.modified instanceof Date
|
|
170
|
+
? metadata.modified.toISOString()
|
|
171
|
+
: metadata.modified;
|
|
172
|
+
}
|
|
173
|
+
if (metadata.published) {
|
|
174
|
+
normalized.published =
|
|
175
|
+
metadata.published instanceof Date
|
|
176
|
+
? metadata.published.toISOString()
|
|
177
|
+
: metadata.published;
|
|
178
|
+
}
|
|
179
|
+
// Languages (Web uses plural 'languages', our interface uses singular 'language')
|
|
180
|
+
if (metadata.languages) {
|
|
181
|
+
normalized.language = metadata.languages;
|
|
182
|
+
}
|
|
183
|
+
// Normalize all contributor types (Web uses plural names, our interface uses singular)
|
|
184
|
+
if (metadata.authors)
|
|
185
|
+
normalized.author = normalizeContributors(metadata.authors);
|
|
186
|
+
if (metadata.translators)
|
|
187
|
+
normalized.translator = normalizeContributors(metadata.translators);
|
|
188
|
+
if (metadata.editors)
|
|
189
|
+
normalized.editor = normalizeContributors(metadata.editors);
|
|
190
|
+
if (metadata.artists)
|
|
191
|
+
normalized.artist = normalizeContributors(metadata.artists);
|
|
192
|
+
if (metadata.illustrators)
|
|
193
|
+
normalized.illustrator = normalizeContributors(metadata.illustrators);
|
|
194
|
+
if (metadata.letterers)
|
|
195
|
+
normalized.letterer = normalizeContributors(metadata.letterers);
|
|
196
|
+
if (metadata.pencilers)
|
|
197
|
+
normalized.penciler = normalizeContributors(metadata.pencilers);
|
|
198
|
+
if (metadata.colorists)
|
|
199
|
+
normalized.colorist = normalizeContributors(metadata.colorists);
|
|
200
|
+
if (metadata.inkers)
|
|
201
|
+
normalized.inker = normalizeContributors(metadata.inkers);
|
|
202
|
+
if (metadata.narrators)
|
|
203
|
+
normalized.narrator = normalizeContributors(metadata.narrators);
|
|
204
|
+
if (metadata.contributors)
|
|
205
|
+
normalized.contributor = normalizeContributors(metadata.contributors);
|
|
206
|
+
if (metadata.publishers)
|
|
207
|
+
normalized.publisher = normalizeContributors(metadata.publishers);
|
|
208
|
+
if (metadata.imprints)
|
|
209
|
+
normalized.imprint = normalizeContributors(metadata.imprints);
|
|
210
|
+
// Normalize subjects
|
|
211
|
+
if (metadata.subjects) {
|
|
212
|
+
normalized.subject = normalizeSubjects(metadata.subjects);
|
|
213
|
+
}
|
|
214
|
+
// Copy complex objects as-is
|
|
215
|
+
if (metadata.belongsTo)
|
|
216
|
+
normalized.belongsTo = metadata.belongsTo;
|
|
217
|
+
if (metadata.accessibility)
|
|
218
|
+
normalized.accessibility = metadata.accessibility;
|
|
219
|
+
return normalized;
|
|
220
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { EpubNavigatorListeners } from '@readium/navigator';
|
|
2
|
+
import { Locator } from '@readium/shared';
|
|
3
|
+
/**
|
|
4
|
+
* Creates navigator listeners for handling navigation events
|
|
5
|
+
*/
|
|
6
|
+
export declare function createNavigatorListeners(onLocationChangeWithTotalProgression: (locator: Locator) => void, onPositionChange?: (position: number | null) => void): EpubNavigatorListeners;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Creates navigator listeners for handling navigation events
|
|
3
|
+
*/
|
|
4
|
+
export function createNavigatorListeners(onLocationChangeWithTotalProgression, onPositionChange) {
|
|
5
|
+
return {
|
|
6
|
+
frameLoaded: function (_wnd) {
|
|
7
|
+
// noop
|
|
8
|
+
},
|
|
9
|
+
positionChanged: function (_locator) {
|
|
10
|
+
onLocationChangeWithTotalProgression(_locator);
|
|
11
|
+
if (onPositionChange) {
|
|
12
|
+
onPositionChange(_locator.locations?.position || null);
|
|
13
|
+
}
|
|
14
|
+
window.focus();
|
|
15
|
+
},
|
|
16
|
+
tap: function (_e) {
|
|
17
|
+
return false;
|
|
18
|
+
},
|
|
19
|
+
click: function (_e) {
|
|
20
|
+
return false;
|
|
21
|
+
},
|
|
22
|
+
zoom: function (_scale) {
|
|
23
|
+
// noop
|
|
24
|
+
},
|
|
25
|
+
miscPointer: function (_amount) {
|
|
26
|
+
// noop
|
|
27
|
+
},
|
|
28
|
+
scroll: function (_amount) {
|
|
29
|
+
// noop
|
|
30
|
+
},
|
|
31
|
+
customEvent: function (_key, _data) { },
|
|
32
|
+
handleLocator: function (locator) {
|
|
33
|
+
const href = locator.href;
|
|
34
|
+
if (href.startsWith('http://') ||
|
|
35
|
+
href.startsWith('https://') ||
|
|
36
|
+
href.startsWith('mailto:') ||
|
|
37
|
+
href.startsWith('tel:')) {
|
|
38
|
+
if (confirm(`Open "${href}" ?`))
|
|
39
|
+
window.open(href, '_blank');
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
console.warn('Unhandled locator', locator);
|
|
43
|
+
}
|
|
44
|
+
return false;
|
|
45
|
+
},
|
|
46
|
+
textSelected: function (_selection) {
|
|
47
|
+
// noop
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Locator, Manifest, Publication } from '@readium/shared';
|
|
2
|
+
/**
|
|
3
|
+
* Normalizes a publication URL to ensure it ends with /
|
|
4
|
+
* If URL ends with manifest.json, extracts the base directory
|
|
5
|
+
*/
|
|
6
|
+
export declare function normalizePublicationURL(url: string): string;
|
|
7
|
+
/**
|
|
8
|
+
* Creates positions array from publication reading order
|
|
9
|
+
* NOTE: The published npm packages (v2.2.5) require positions to be passed explicitly
|
|
10
|
+
*/
|
|
11
|
+
export declare function createPositions(publication: Publication): Locator[];
|
|
12
|
+
/**
|
|
13
|
+
* Extracts table of contents items from manifest
|
|
14
|
+
*/
|
|
15
|
+
export declare function extractTableOfContents(manifest: Manifest): any[];
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { Locator, LocatorLocations, } from '@readium/shared';
|
|
2
|
+
/**
|
|
3
|
+
* Normalizes a publication URL to ensure it ends with /
|
|
4
|
+
* If URL ends with manifest.json, extracts the base directory
|
|
5
|
+
*/
|
|
6
|
+
export function normalizePublicationURL(url) {
|
|
7
|
+
if (url.endsWith('manifest.json')) {
|
|
8
|
+
return url.substring(0, url.lastIndexOf('/') + 1);
|
|
9
|
+
}
|
|
10
|
+
return url.endsWith('/') ? url : `${url}/`;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Creates positions array from publication reading order
|
|
14
|
+
* NOTE: The published npm packages (v2.2.5) require positions to be passed explicitly
|
|
15
|
+
*/
|
|
16
|
+
export function createPositions(publication) {
|
|
17
|
+
return publication.readingOrder.items.map((link, idx) => {
|
|
18
|
+
const position = idx + 1;
|
|
19
|
+
return new Locator({
|
|
20
|
+
href: link.href,
|
|
21
|
+
type: link.type,
|
|
22
|
+
title: link.title,
|
|
23
|
+
locations: new LocatorLocations({
|
|
24
|
+
position: position,
|
|
25
|
+
progression: 0,
|
|
26
|
+
totalProgression: idx / publication.readingOrder.items.length,
|
|
27
|
+
}),
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Extracts table of contents items from manifest
|
|
33
|
+
*/
|
|
34
|
+
export function extractTableOfContents(manifest) {
|
|
35
|
+
return Array.isArray(manifest.toc)
|
|
36
|
+
? manifest.toc
|
|
37
|
+
: // @ts-ignore
|
|
38
|
+
manifest.toc.items || [];
|
|
39
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-readium",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "5.0.0-rc.0",
|
|
4
4
|
"description": "A react-native wrapper for https://readium.org/",
|
|
5
5
|
"main": "lib/src/index",
|
|
6
6
|
"types": "lib/src/index.d.ts",
|
|
@@ -21,6 +21,9 @@
|
|
|
21
21
|
"!**/__fixtures__",
|
|
22
22
|
"!**/__mocks__"
|
|
23
23
|
],
|
|
24
|
+
"workspaces": [
|
|
25
|
+
"apps/*"
|
|
26
|
+
],
|
|
24
27
|
"scripts": {
|
|
25
28
|
"test": "jest",
|
|
26
29
|
"typescript": "tsc --noEmit",
|
|
@@ -28,8 +31,9 @@
|
|
|
28
31
|
"lint:fix": "eslint ./src --fix",
|
|
29
32
|
"prepare": "rimraf lib && tsc",
|
|
30
33
|
"release": "release-it",
|
|
31
|
-
"example": "yarn
|
|
32
|
-
"
|
|
34
|
+
"example": "yarn workspace example-native",
|
|
35
|
+
"example:nextjs": "yarn workspace example-nextjs",
|
|
36
|
+
"pods": "cd apps/example-native && pod-install --quiet",
|
|
33
37
|
"bootstrap": "yarn example && yarn && yarn pods",
|
|
34
38
|
"version": "yarn changelog && git add CHANGELOG.md",
|
|
35
39
|
"postversion": "npm run publish:git && npm run publish:npm",
|
|
@@ -61,27 +65,27 @@
|
|
|
61
65
|
"devDependencies": {
|
|
62
66
|
"@commitlint/config-conventional": "^17.0.2",
|
|
63
67
|
"@evilmartians/lefthook": "^1.5.0",
|
|
64
|
-
"@react-native/eslint-config": "
|
|
68
|
+
"@react-native/eslint-config": "0.83.0",
|
|
65
69
|
"@release-it/conventional-changelog": "^5.0.0",
|
|
66
|
-
"@types/jest": "^29.5.
|
|
67
|
-
"@types/react": "^
|
|
70
|
+
"@types/jest": "^29.5.13",
|
|
71
|
+
"@types/react": "^19.2.0",
|
|
68
72
|
"commitlint": "^17.0.2",
|
|
69
73
|
"conventional-changelog-cli": "^2.2.2",
|
|
70
74
|
"del-cli": "^5.1.0",
|
|
71
|
-
"eslint": "^8.
|
|
75
|
+
"eslint": "^8.19.0",
|
|
72
76
|
"eslint-config-prettier": "^9.0.0",
|
|
73
77
|
"eslint-plugin-prettier": "^5.0.1",
|
|
74
78
|
"husky": "^6.0.0",
|
|
75
|
-
"jest": "^29.
|
|
79
|
+
"jest": "^29.6.3",
|
|
76
80
|
"pod-install": "^0.1.0",
|
|
77
|
-
"prettier": "
|
|
78
|
-
"react": "
|
|
79
|
-
"react-native": "0.
|
|
81
|
+
"prettier": "2.8.8",
|
|
82
|
+
"react": "19.0.0",
|
|
83
|
+
"react-native": "0.83.1",
|
|
80
84
|
"react-native-builder-bob": "^0.23.2",
|
|
81
85
|
"release-it": "^15.0.0",
|
|
82
86
|
"rimraf": "^5.0.7",
|
|
83
87
|
"turbo": "^1.10.7",
|
|
84
|
-
"typescript": "^5.
|
|
88
|
+
"typescript": "^5.8.3"
|
|
85
89
|
},
|
|
86
90
|
"peerDependencies": {
|
|
87
91
|
"react": "*",
|
|
@@ -122,6 +126,9 @@
|
|
|
122
126
|
"@react-native",
|
|
123
127
|
"prettier"
|
|
124
128
|
],
|
|
129
|
+
"plugins": [
|
|
130
|
+
"prettier"
|
|
131
|
+
],
|
|
125
132
|
"rules": {
|
|
126
133
|
"prettier/prettier": [
|
|
127
134
|
"error",
|
|
@@ -147,11 +154,14 @@
|
|
|
147
154
|
"useTabs": false
|
|
148
155
|
},
|
|
149
156
|
"dependencies": {
|
|
150
|
-
"@
|
|
157
|
+
"@readium/css": "^2.0.0-beta.24",
|
|
158
|
+
"@readium/navigator": "^2.2.5",
|
|
159
|
+
"@readium/navigator-html-injectables": "^2.2.2",
|
|
160
|
+
"@readium/shared": "^2.1.2",
|
|
151
161
|
"use-deep-compare": "^1.1.0"
|
|
152
162
|
},
|
|
153
163
|
"engines": {
|
|
154
|
-
"node": ">=
|
|
164
|
+
"node": ">=20"
|
|
155
165
|
},
|
|
156
166
|
"packageManager": "yarn@3.6.4",
|
|
157
167
|
"stableVersion": "1.2.1"
|
|
@@ -18,10 +18,12 @@ Pod::Spec.new do |s|
|
|
|
18
18
|
|
|
19
19
|
s.swift_version = "5.0"
|
|
20
20
|
|
|
21
|
+
s.dependency 'ReadiumShared', '~> 3.5.0'
|
|
22
|
+
s.dependency 'ReadiumStreamer', '~> 3.5.0'
|
|
23
|
+
s.dependency 'ReadiumNavigator','~> 3.5.0'
|
|
24
|
+
s.dependency 'ReadiumAdapterGCDWebServer', '~> 3.5.0'
|
|
25
|
+
s.dependency 'ReadiumInternal'
|
|
26
|
+
|
|
21
27
|
s.dependency "React-Core"
|
|
22
|
-
|
|
23
|
-
s.dependency "R2Streamer"
|
|
24
|
-
s.dependency "R2Navigator"
|
|
25
|
-
s.dependency "GCDWebServer"
|
|
26
|
-
s.dependency "ReadiumAdapterGCDWebServer"
|
|
28
|
+
|
|
27
29
|
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { HostComponent, ViewProps } from 'react-native';
|
|
2
|
+
import type { DirectEventHandler } from 'react-native/Libraries/Types/CodegenTypes';
|
|
3
|
+
// eslint-disable-next-line @react-native/no-deep-imports
|
|
4
|
+
import codegenNativeComponent from 'react-native/Libraries/Utilities/codegenNativeComponent';
|
|
5
|
+
// eslint-disable-next-line @react-native/no-deep-imports
|
|
6
|
+
import codegenNativeCommands from 'react-native/Libraries/Utilities/codegenNativeCommands';
|
|
7
|
+
import type { File } from './interfaces/File';
|
|
8
|
+
import type { Locator } from './interfaces/Locator';
|
|
9
|
+
import type { PublicationReadyEvent } from './interfaces/PublicationReady';
|
|
10
|
+
|
|
11
|
+
// Event types for native events
|
|
12
|
+
type OnLocationChangeEvent = Readonly<Locator>;
|
|
13
|
+
type OnPublicationReadyEvent = Readonly<PublicationReadyEvent>;
|
|
14
|
+
|
|
15
|
+
// Native component props interface
|
|
16
|
+
export interface NativeProps extends ViewProps {
|
|
17
|
+
file: File;
|
|
18
|
+
preferences?: string;
|
|
19
|
+
onLocationChange?: DirectEventHandler<OnLocationChangeEvent>;
|
|
20
|
+
onPublicationReady?: DirectEventHandler<OnPublicationReadyEvent>;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Native commands interface
|
|
24
|
+
export interface NativeCommands {
|
|
25
|
+
create: (viewRef: React.ElementRef<HostComponent<NativeProps>>) => void;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Generate the native component
|
|
29
|
+
export const ReadiumViewNativeComponent =
|
|
30
|
+
codegenNativeComponent<NativeProps>('ReadiumView');
|
|
31
|
+
|
|
32
|
+
// Generate the commands
|
|
33
|
+
export const Commands = codegenNativeCommands<NativeCommands>({
|
|
34
|
+
supportedCommands: ['create'],
|
|
35
|
+
});
|
|
@@ -1,11 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ReadiumViewNativeComponent } from '../ReadiumViewNativeComponent';
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
export const BaseReadiumView =
|
|
7
|
-
UIManager.getViewManagerConfig(COMPONENT_NAME) != null
|
|
8
|
-
? requireNativeComponent<BaseReadiumViewProps>(COMPONENT_NAME)
|
|
9
|
-
: () => {
|
|
10
|
-
throw new Error(LINKING_ERROR);
|
|
11
|
-
};
|
|
3
|
+
// Re-export the native component for backwards compatibility
|
|
4
|
+
export const BaseReadiumView = ReadiumViewNativeComponent;
|