@papyrus-sdk/ui-react-native 0.1.3 → 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 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
- export { AnnotationEditor, BottomBar, PageRenderer, RightSheet, SettingsSheet, ToolDock, Topbar, Viewer };
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
- export { AnnotationEditor, BottomBar, PageRenderer, RightSheet, SettingsSheet, ToolDock, Topbar, Viewer };
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
@@ -605,6 +605,7 @@ var index_exports = {};
605
605
  __export(index_exports, {
606
606
  AnnotationEditor: () => AnnotationEditor_default,
607
607
  BottomBar: () => BottomBar_default,
608
+ CoverPreview: () => CoverPreview_default,
608
609
  PageRenderer: () => PageRenderer_default,
609
610
  RightSheet: () => RightSheet_default,
610
611
  SettingsSheet: () => SettingsSheet_default,
@@ -3635,10 +3636,186 @@ var styles9 = import_react_native9.StyleSheet.create({
3635
3636
  }
3636
3637
  });
3637
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;
3638
3814
  // Annotate the CommonJS export names for ESM import in node:
3639
3815
  0 && (module.exports = {
3640
3816
  AnnotationEditor,
3641
3817
  BottomBar,
3818
+ CoverPreview,
3642
3819
  PageRenderer,
3643
3820
  RightSheet,
3644
3821
  SettingsSheet,