@papyrus-sdk/ui-react-native 0.1.2 → 0.1.4
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/dist/index.d.mts +21 -2
- package/dist/index.d.ts +21 -2
- package/dist/index.js +208 -19
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +214 -19
- package/dist/index.mjs.map +1 -1
- package/package.json +4 -4
- package/runtime/index.html +31 -19
- package/runtime/runtime.js +29 -11
package/dist/index.d.mts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { DocumentEngine } from '@papyrus-sdk/types';
|
|
2
|
+
import { DocumentEngine, DocumentSource, DocumentType } from '@papyrus-sdk/types';
|
|
3
3
|
import { PapyrusPageViewProps } from '@papyrus-sdk/engine-native';
|
|
4
|
+
import { StyleProp, ViewStyle } from 'react-native';
|
|
4
5
|
|
|
5
6
|
interface ViewerProps {
|
|
6
7
|
engine: DocumentEngine;
|
|
@@ -43,4 +44,22 @@ interface SettingsSheetProps {
|
|
|
43
44
|
}
|
|
44
45
|
declare const SettingsSheet: React.FC<SettingsSheetProps>;
|
|
45
46
|
|
|
46
|
-
|
|
47
|
+
type CoverPreviewProps = {
|
|
48
|
+
source: DocumentSource;
|
|
49
|
+
type?: DocumentType;
|
|
50
|
+
pageIndex?: number;
|
|
51
|
+
visible?: boolean;
|
|
52
|
+
keepAlive?: boolean;
|
|
53
|
+
allowInteraction?: boolean;
|
|
54
|
+
renderScale?: number;
|
|
55
|
+
showLoading?: boolean;
|
|
56
|
+
loadingIndicator?: React.ReactNode;
|
|
57
|
+
placeholder?: React.ReactNode;
|
|
58
|
+
style?: StyleProp<ViewStyle>;
|
|
59
|
+
onLoadStart?: () => void;
|
|
60
|
+
onLoadEnd?: () => void;
|
|
61
|
+
onError?: (error: Error) => void;
|
|
62
|
+
};
|
|
63
|
+
declare const CoverPreview: React.FC<CoverPreviewProps>;
|
|
64
|
+
|
|
65
|
+
export { AnnotationEditor, BottomBar, CoverPreview, PageRenderer, RightSheet, SettingsSheet, ToolDock, Topbar, Viewer };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { DocumentEngine } from '@papyrus-sdk/types';
|
|
2
|
+
import { DocumentEngine, DocumentSource, DocumentType } from '@papyrus-sdk/types';
|
|
3
3
|
import { PapyrusPageViewProps } from '@papyrus-sdk/engine-native';
|
|
4
|
+
import { StyleProp, ViewStyle } from 'react-native';
|
|
4
5
|
|
|
5
6
|
interface ViewerProps {
|
|
6
7
|
engine: DocumentEngine;
|
|
@@ -43,4 +44,22 @@ interface SettingsSheetProps {
|
|
|
43
44
|
}
|
|
44
45
|
declare const SettingsSheet: React.FC<SettingsSheetProps>;
|
|
45
46
|
|
|
46
|
-
|
|
47
|
+
type CoverPreviewProps = {
|
|
48
|
+
source: DocumentSource;
|
|
49
|
+
type?: DocumentType;
|
|
50
|
+
pageIndex?: number;
|
|
51
|
+
visible?: boolean;
|
|
52
|
+
keepAlive?: boolean;
|
|
53
|
+
allowInteraction?: boolean;
|
|
54
|
+
renderScale?: number;
|
|
55
|
+
showLoading?: boolean;
|
|
56
|
+
loadingIndicator?: React.ReactNode;
|
|
57
|
+
placeholder?: React.ReactNode;
|
|
58
|
+
style?: StyleProp<ViewStyle>;
|
|
59
|
+
onLoadStart?: () => void;
|
|
60
|
+
onLoadEnd?: () => void;
|
|
61
|
+
onError?: (error: Error) => void;
|
|
62
|
+
};
|
|
63
|
+
declare const CoverPreview: React.FC<CoverPreviewProps>;
|
|
64
|
+
|
|
65
|
+
export { AnnotationEditor, BottomBar, CoverPreview, PageRenderer, RightSheet, SettingsSheet, ToolDock, Topbar, Viewer };
|
package/dist/index.js
CHANGED
|
@@ -151,13 +151,21 @@ https://github.com/nodeca/pako/blob/main/LICENSE\r
|
|
|
151
151
|
}\r
|
|
152
152
|
};\r
|
|
153
153
|
\r
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
154
|
+
const shouldIgnoreError = (error) => {
|
|
155
|
+
const message = error && error.message ? error.message : String(error || '');
|
|
156
|
+
return message.includes('ResizeObserver loop');
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
window.addEventListener('error', (event) => {
|
|
160
|
+
const error = event.error || event.message;
|
|
161
|
+
if (shouldIgnoreError(error)) return;
|
|
162
|
+
reportError(error, 'window.error');
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
window.addEventListener('unhandledrejection', (event) => {
|
|
166
|
+
if (shouldIgnoreError(event.reason)) return;
|
|
167
|
+
reportError(event.reason, 'unhandledrejection');
|
|
168
|
+
});
|
|
161
169
|
\r
|
|
162
170
|
const clearViewer = () => {\r
|
|
163
171
|
while (viewer.firstChild) {\r
|
|
@@ -420,8 +428,12 @@ https://github.com/nodeca/pako/blob/main/LICENSE\r
|
|
|
420
428
|
});\r
|
|
421
429
|
\r
|
|
422
430
|
const getPageIndex = (dest) => {\r
|
|
423
|
-
if (
|
|
431
|
+
if (!dest) return null;\r
|
|
424
432
|
if (typeof dest === 'string') return getSpineIndexByHref(dest);\r
|
|
433
|
+
if (typeof dest !== 'object') return null;\r
|
|
434
|
+
if (dest.kind === 'href') return getSpineIndexByHref(dest.value);\r
|
|
435
|
+
if (dest.kind === 'pageIndex') return dest.value;\r
|
|
436
|
+
if (dest.kind === 'pageNumber') return Math.max(0, dest.value - 1);\r
|
|
425
437
|
return null;\r
|
|
426
438
|
};\r
|
|
427
439
|
\r
|
|
@@ -548,6 +560,9 @@ https://github.com/nodeca/pako/blob/main/LICENSE\r
|
|
|
548
560
|
if (raw && typeof raw === 'object' && raw.kind && raw.id) {
|
|
549
561
|
message = raw;
|
|
550
562
|
} else if (typeof raw === 'string') {
|
|
563
|
+
if (raw.startsWith('setImmediate$')) {
|
|
564
|
+
return;
|
|
565
|
+
}
|
|
551
566
|
const trimmed = raw.trim();
|
|
552
567
|
if (!trimmed || (!trimmed.startsWith('{') && !trimmed.startsWith('['))) {
|
|
553
568
|
return;
|
|
@@ -555,18 +570,15 @@ https://github.com/nodeca/pako/blob/main/LICENSE\r
|
|
|
555
570
|
try {
|
|
556
571
|
message = JSON.parse(trimmed);
|
|
557
572
|
} catch (err) {
|
|
558
|
-
sendEvent('RUNTIME_ERROR', {
|
|
559
|
-
message: 'Failed to parse message'
|
|
560
|
-
context: 'runtime.onMessage'
|
|
561
|
-
stack: err && err.stack ? err.stack : null
|
|
562
|
-
preview: trimmed.slice(0, 200)
|
|
563
|
-
})
|
|
564
|
-
return
|
|
565
|
-
}
|
|
573
|
+
sendEvent('RUNTIME_ERROR', {\r
|
|
574
|
+
message: 'Failed to parse message',\r
|
|
575
|
+
context: 'runtime.onMessage',\r
|
|
576
|
+
stack: err && err.stack ? err.stack : null,\r
|
|
577
|
+
preview: trimmed.slice(0, 200),\r
|
|
578
|
+
});\r
|
|
579
|
+
return;\r
|
|
580
|
+
}\r
|
|
566
581
|
} else {
|
|
567
|
-
sendEvent('RUNTIME_LOG', {
|
|
568
|
-
message: \`Ignoring message of type \${typeof raw}\`,
|
|
569
|
-
});
|
|
570
582
|
return;
|
|
571
583
|
}
|
|
572
584
|
\r
|
|
@@ -593,6 +605,7 @@ var index_exports = {};
|
|
|
593
605
|
__export(index_exports, {
|
|
594
606
|
AnnotationEditor: () => AnnotationEditor_default,
|
|
595
607
|
BottomBar: () => BottomBar_default,
|
|
608
|
+
CoverPreview: () => CoverPreview_default,
|
|
596
609
|
PageRenderer: () => PageRenderer_default,
|
|
597
610
|
RightSheet: () => RightSheet_default,
|
|
598
611
|
SettingsSheet: () => SettingsSheet_default,
|
|
@@ -3623,10 +3636,186 @@ var styles9 = import_react_native9.StyleSheet.create({
|
|
|
3623
3636
|
}
|
|
3624
3637
|
});
|
|
3625
3638
|
var SettingsSheet_default = SettingsSheet;
|
|
3639
|
+
|
|
3640
|
+
// components/CoverPreview.tsx
|
|
3641
|
+
var import_react7 = require("react");
|
|
3642
|
+
var import_react_native10 = require("react-native");
|
|
3643
|
+
var import_engine_native3 = require("@papyrus-sdk/engine-native");
|
|
3644
|
+
var import_jsx_runtime11 = require("react/jsx-runtime");
|
|
3645
|
+
var parseDataUri = (value) => {
|
|
3646
|
+
const match = /^data:([^;,]+)?(;base64)?,/.exec(value);
|
|
3647
|
+
if (!match) return null;
|
|
3648
|
+
return { mime: match[1] ?? "" };
|
|
3649
|
+
};
|
|
3650
|
+
var inferDocumentType = (source, explicitType) => {
|
|
3651
|
+
if (explicitType) return explicitType;
|
|
3652
|
+
if (typeof source === "string") {
|
|
3653
|
+
const dataUri = parseDataUri(source);
|
|
3654
|
+
if (dataUri?.mime) {
|
|
3655
|
+
const mime = dataUri.mime.toLowerCase();
|
|
3656
|
+
if (mime.includes("epub")) return "epub";
|
|
3657
|
+
if (mime.includes("text")) return "text";
|
|
3658
|
+
if (mime.includes("pdf")) return "pdf";
|
|
3659
|
+
}
|
|
3660
|
+
const clean = source.split("?")[0].split("#")[0];
|
|
3661
|
+
const ext = clean.includes(".") ? clean.split(".").pop()?.toLowerCase() : void 0;
|
|
3662
|
+
if (ext === "epub") return "epub";
|
|
3663
|
+
if (ext === "txt") return "text";
|
|
3664
|
+
if (ext === "pdf") return "pdf";
|
|
3665
|
+
return "pdf";
|
|
3666
|
+
}
|
|
3667
|
+
if (typeof source === "object" && source !== null && "uri" in source) {
|
|
3668
|
+
const clean = source.uri.split("?")[0].split("#")[0];
|
|
3669
|
+
const ext = clean.includes(".") ? clean.split(".").pop()?.toLowerCase() : void 0;
|
|
3670
|
+
if (ext === "epub") return "epub";
|
|
3671
|
+
if (ext === "txt") return "text";
|
|
3672
|
+
if (ext === "pdf") return "pdf";
|
|
3673
|
+
}
|
|
3674
|
+
return "pdf";
|
|
3675
|
+
};
|
|
3676
|
+
var CoverPreview = ({
|
|
3677
|
+
source,
|
|
3678
|
+
type,
|
|
3679
|
+
pageIndex = 0,
|
|
3680
|
+
visible = true,
|
|
3681
|
+
keepAlive = false,
|
|
3682
|
+
allowInteraction = false,
|
|
3683
|
+
renderScale = 2,
|
|
3684
|
+
showLoading = true,
|
|
3685
|
+
loadingIndicator,
|
|
3686
|
+
placeholder,
|
|
3687
|
+
style,
|
|
3688
|
+
onLoadStart,
|
|
3689
|
+
onLoadEnd,
|
|
3690
|
+
onError
|
|
3691
|
+
}) => {
|
|
3692
|
+
const [engine, setEngine] = (0, import_react7.useState)(null);
|
|
3693
|
+
const [layoutReady, setLayoutReady] = (0, import_react7.useState)(false);
|
|
3694
|
+
const [loaded, setLoaded] = (0, import_react7.useState)(false);
|
|
3695
|
+
const [loading, setLoading] = (0, import_react7.useState)(false);
|
|
3696
|
+
const [error, setError] = (0, import_react7.useState)(null);
|
|
3697
|
+
const viewRef = (0, import_react7.useRef)(null);
|
|
3698
|
+
const resolvedType = (0, import_react7.useMemo)(() => inferDocumentType(source, type), [source, type]);
|
|
3699
|
+
const isPdf = resolvedType === "pdf";
|
|
3700
|
+
const hasNativePageView = Boolean(import_react_native10.UIManager.getViewManagerConfig?.("PapyrusPageView"));
|
|
3701
|
+
const canRender = !isPdf || hasNativePageView;
|
|
3702
|
+
const shouldRender = Boolean(visible);
|
|
3703
|
+
(0, import_react7.useEffect)(() => {
|
|
3704
|
+
if (!shouldRender) {
|
|
3705
|
+
if (!keepAlive) {
|
|
3706
|
+
setEngine(null);
|
|
3707
|
+
setLoaded(false);
|
|
3708
|
+
setError(null);
|
|
3709
|
+
}
|
|
3710
|
+
return;
|
|
3711
|
+
}
|
|
3712
|
+
if (!engine && canRender) {
|
|
3713
|
+
setEngine(new import_engine_native3.MobileDocumentEngine());
|
|
3714
|
+
}
|
|
3715
|
+
}, [shouldRender, keepAlive, engine, canRender]);
|
|
3716
|
+
(0, import_react7.useEffect)(() => {
|
|
3717
|
+
if (!engine || !shouldRender || !canRender) return;
|
|
3718
|
+
let active = true;
|
|
3719
|
+
setLoading(true);
|
|
3720
|
+
setLoaded(false);
|
|
3721
|
+
setError(null);
|
|
3722
|
+
onLoadStart?.();
|
|
3723
|
+
const loadInput = type ? { type, source } : source;
|
|
3724
|
+
engine.load(loadInput).then(() => {
|
|
3725
|
+
if (!active) return;
|
|
3726
|
+
if (!isPdf && pageIndex > 0) {
|
|
3727
|
+
engine.goToPage(pageIndex + 1);
|
|
3728
|
+
}
|
|
3729
|
+
setLoaded(true);
|
|
3730
|
+
setLoading(false);
|
|
3731
|
+
onLoadEnd?.();
|
|
3732
|
+
}).catch((err) => {
|
|
3733
|
+
if (!active) return;
|
|
3734
|
+
const errorValue = err instanceof Error ? err : new Error("[Papyrus] Failed to load document");
|
|
3735
|
+
setError(errorValue);
|
|
3736
|
+
setLoading(false);
|
|
3737
|
+
onError?.(errorValue);
|
|
3738
|
+
});
|
|
3739
|
+
return () => {
|
|
3740
|
+
active = false;
|
|
3741
|
+
};
|
|
3742
|
+
}, [engine, shouldRender, canRender, source, type, pageIndex, isPdf, onLoadStart, onLoadEnd, onError]);
|
|
3743
|
+
(0, import_react7.useEffect)(() => {
|
|
3744
|
+
if (!engine || !isPdf || !loaded || !layoutReady || !shouldRender || !canRender) return;
|
|
3745
|
+
const viewTag = (0, import_react_native10.findNodeHandle)(viewRef.current);
|
|
3746
|
+
if (!viewTag) return;
|
|
3747
|
+
engine.renderPage(pageIndex, viewTag, renderScale);
|
|
3748
|
+
}, [engine, isPdf, loaded, layoutReady, shouldRender, canRender, pageIndex, renderScale]);
|
|
3749
|
+
(0, import_react7.useEffect)(() => {
|
|
3750
|
+
return () => {
|
|
3751
|
+
engine?.destroy();
|
|
3752
|
+
};
|
|
3753
|
+
}, [engine]);
|
|
3754
|
+
const handleLayout = (event) => {
|
|
3755
|
+
const { width, height } = event.nativeEvent.layout;
|
|
3756
|
+
if (width > 0 && height > 0) {
|
|
3757
|
+
setLayoutReady(true);
|
|
3758
|
+
}
|
|
3759
|
+
};
|
|
3760
|
+
if (!shouldRender || !canRender) {
|
|
3761
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react_native10.View, { style: [styles10.container, style], children: placeholder ?? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react_native10.View, { style: styles10.placeholder, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react_native10.Text, { style: styles10.placeholderText, children: "Preview" }) }) });
|
|
3762
|
+
}
|
|
3763
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_react_native10.View, { style: [styles10.container, style], onLayout: handleLayout, children: [
|
|
3764
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react_native10.View, { style: styles10.previewFrame, pointerEvents: allowInteraction ? "auto" : "none", children: isPdf ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_engine_native3.PapyrusPageView, { ref: viewRef, style: styles10.pageView }) : engine && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(WebViewViewer_default, { engine }) }),
|
|
3765
|
+
showLoading && loading && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react_native10.View, { pointerEvents: "none", style: styles10.loadingOverlay, children: loadingIndicator ?? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react_native10.ActivityIndicator, { size: "small", color: "#2563eb" }) }),
|
|
3766
|
+
error && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react_native10.View, { pointerEvents: "none", style: styles10.errorOverlay, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react_native10.Text, { style: styles10.errorText, children: "Preview unavailable" }) })
|
|
3767
|
+
] });
|
|
3768
|
+
};
|
|
3769
|
+
var styles10 = import_react_native10.StyleSheet.create({
|
|
3770
|
+
container: {
|
|
3771
|
+
backgroundColor: "#f8fafc",
|
|
3772
|
+
borderRadius: 12,
|
|
3773
|
+
overflow: "hidden"
|
|
3774
|
+
},
|
|
3775
|
+
previewFrame: {
|
|
3776
|
+
flex: 1,
|
|
3777
|
+
backgroundColor: "#ffffff"
|
|
3778
|
+
},
|
|
3779
|
+
pageView: {
|
|
3780
|
+
width: "100%",
|
|
3781
|
+
height: "100%",
|
|
3782
|
+
backgroundColor: "transparent"
|
|
3783
|
+
},
|
|
3784
|
+
loadingOverlay: {
|
|
3785
|
+
...import_react_native10.StyleSheet.absoluteFillObject,
|
|
3786
|
+
alignItems: "center",
|
|
3787
|
+
justifyContent: "center",
|
|
3788
|
+
backgroundColor: "rgba(15, 23, 42, 0.15)"
|
|
3789
|
+
},
|
|
3790
|
+
errorOverlay: {
|
|
3791
|
+
...import_react_native10.StyleSheet.absoluteFillObject,
|
|
3792
|
+
alignItems: "center",
|
|
3793
|
+
justifyContent: "center",
|
|
3794
|
+
backgroundColor: "rgba(15, 23, 42, 0.4)"
|
|
3795
|
+
},
|
|
3796
|
+
errorText: {
|
|
3797
|
+
fontSize: 12,
|
|
3798
|
+
fontWeight: "600",
|
|
3799
|
+
color: "#f8fafc"
|
|
3800
|
+
},
|
|
3801
|
+
placeholder: {
|
|
3802
|
+
flex: 1,
|
|
3803
|
+
alignItems: "center",
|
|
3804
|
+
justifyContent: "center",
|
|
3805
|
+
backgroundColor: "#e2e8f0"
|
|
3806
|
+
},
|
|
3807
|
+
placeholderText: {
|
|
3808
|
+
fontSize: 12,
|
|
3809
|
+
fontWeight: "600",
|
|
3810
|
+
color: "#475569"
|
|
3811
|
+
}
|
|
3812
|
+
});
|
|
3813
|
+
var CoverPreview_default = CoverPreview;
|
|
3626
3814
|
// Annotate the CommonJS export names for ESM import in node:
|
|
3627
3815
|
0 && (module.exports = {
|
|
3628
3816
|
AnnotationEditor,
|
|
3629
3817
|
BottomBar,
|
|
3818
|
+
CoverPreview,
|
|
3630
3819
|
PageRenderer,
|
|
3631
3820
|
RightSheet,
|
|
3632
3821
|
SettingsSheet,
|