@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 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
@@ -151,13 +151,21 @@ https://github.com/nodeca/pako/blob/main/LICENSE\r
151
151
  }\r
152
152
  };\r
153
153
  \r
154
- window.addEventListener('error', (event) => {\r
155
- reportError(event.error || event.message, 'window.error');\r
156
- });\r
157
- \r
158
- window.addEventListener('unhandledrejection', (event) => {\r
159
- reportError(event.reason, 'unhandledrejection');\r
160
- });\r
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 (currentType !== 'epub') return null;\r
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,