@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.mjs CHANGED
@@ -125,13 +125,21 @@ https://github.com/nodeca/pako/blob/main/LICENSE\r
125
125
  }\r
126
126
  };\r
127
127
  \r
128
- window.addEventListener('error', (event) => {\r
129
- reportError(event.error || event.message, 'window.error');\r
130
- });\r
131
- \r
132
- window.addEventListener('unhandledrejection', (event) => {\r
133
- reportError(event.reason, 'unhandledrejection');\r
134
- });\r
128
+ const shouldIgnoreError = (error) => {
129
+ const message = error && error.message ? error.message : String(error || '');
130
+ return message.includes('ResizeObserver loop');
131
+ };
132
+
133
+ window.addEventListener('error', (event) => {
134
+ const error = event.error || event.message;
135
+ if (shouldIgnoreError(error)) return;
136
+ reportError(error, 'window.error');
137
+ });
138
+
139
+ window.addEventListener('unhandledrejection', (event) => {
140
+ if (shouldIgnoreError(event.reason)) return;
141
+ reportError(event.reason, 'unhandledrejection');
142
+ });
135
143
  \r
136
144
  const clearViewer = () => {\r
137
145
  while (viewer.firstChild) {\r
@@ -394,8 +402,12 @@ https://github.com/nodeca/pako/blob/main/LICENSE\r
394
402
  });\r
395
403
  \r
396
404
  const getPageIndex = (dest) => {\r
397
- if (currentType !== 'epub') return null;\r
405
+ if (!dest) return null;\r
398
406
  if (typeof dest === 'string') return getSpineIndexByHref(dest);\r
407
+ if (typeof dest !== 'object') return null;\r
408
+ if (dest.kind === 'href') return getSpineIndexByHref(dest.value);\r
409
+ if (dest.kind === 'pageIndex') return dest.value;\r
410
+ if (dest.kind === 'pageNumber') return Math.max(0, dest.value - 1);\r
399
411
  return null;\r
400
412
  };\r
401
413
  \r
@@ -522,6 +534,9 @@ https://github.com/nodeca/pako/blob/main/LICENSE\r
522
534
  if (raw && typeof raw === 'object' && raw.kind && raw.id) {
523
535
  message = raw;
524
536
  } else if (typeof raw === 'string') {
537
+ if (raw.startsWith('setImmediate$')) {
538
+ return;
539
+ }
525
540
  const trimmed = raw.trim();
526
541
  if (!trimmed || (!trimmed.startsWith('{') && !trimmed.startsWith('['))) {
527
542
  return;
@@ -529,18 +544,15 @@ https://github.com/nodeca/pako/blob/main/LICENSE\r
529
544
  try {
530
545
  message = JSON.parse(trimmed);
531
546
  } catch (err) {
532
- sendEvent('RUNTIME_ERROR', {
533
- message: 'Failed to parse message',
534
- context: 'runtime.onMessage',
535
- stack: err && err.stack ? err.stack : null,
536
- preview: trimmed.slice(0, 200),
537
- });
538
- return;
539
- }
547
+ sendEvent('RUNTIME_ERROR', {\r
548
+ message: 'Failed to parse message',\r
549
+ context: 'runtime.onMessage',\r
550
+ stack: err && err.stack ? err.stack : null,\r
551
+ preview: trimmed.slice(0, 200),\r
552
+ });\r
553
+ return;\r
554
+ }\r
540
555
  } else {
541
- sendEvent('RUNTIME_LOG', {
542
- message: \`Ignoring message of type \${typeof raw}\`,
543
- });
544
556
  return;
545
557
  }
546
558
  \r
@@ -3606,9 +3618,192 @@ var styles9 = StyleSheet9.create({
3606
3618
  }
3607
3619
  });
3608
3620
  var SettingsSheet_default = SettingsSheet;
3621
+
3622
+ // components/CoverPreview.tsx
3623
+ import { useEffect as useEffect7, useMemo as useMemo5, useRef as useRef5, useState as useState5 } from "react";
3624
+ import {
3625
+ ActivityIndicator as ActivityIndicator2,
3626
+ StyleSheet as StyleSheet10,
3627
+ Text as Text7,
3628
+ UIManager as UIManager2,
3629
+ View as View10,
3630
+ findNodeHandle as findNodeHandle3
3631
+ } from "react-native";
3632
+ import { MobileDocumentEngine, PapyrusPageView as PapyrusPageView3 } from "@papyrus-sdk/engine-native";
3633
+ import { jsx as jsx11, jsxs as jsxs11 } from "react/jsx-runtime";
3634
+ var parseDataUri = (value) => {
3635
+ const match = /^data:([^;,]+)?(;base64)?,/.exec(value);
3636
+ if (!match) return null;
3637
+ return { mime: match[1] ?? "" };
3638
+ };
3639
+ var inferDocumentType = (source, explicitType) => {
3640
+ if (explicitType) return explicitType;
3641
+ if (typeof source === "string") {
3642
+ const dataUri = parseDataUri(source);
3643
+ if (dataUri?.mime) {
3644
+ const mime = dataUri.mime.toLowerCase();
3645
+ if (mime.includes("epub")) return "epub";
3646
+ if (mime.includes("text")) return "text";
3647
+ if (mime.includes("pdf")) return "pdf";
3648
+ }
3649
+ const clean = source.split("?")[0].split("#")[0];
3650
+ const ext = clean.includes(".") ? clean.split(".").pop()?.toLowerCase() : void 0;
3651
+ if (ext === "epub") return "epub";
3652
+ if (ext === "txt") return "text";
3653
+ if (ext === "pdf") return "pdf";
3654
+ return "pdf";
3655
+ }
3656
+ if (typeof source === "object" && source !== null && "uri" in source) {
3657
+ const clean = source.uri.split("?")[0].split("#")[0];
3658
+ const ext = clean.includes(".") ? clean.split(".").pop()?.toLowerCase() : void 0;
3659
+ if (ext === "epub") return "epub";
3660
+ if (ext === "txt") return "text";
3661
+ if (ext === "pdf") return "pdf";
3662
+ }
3663
+ return "pdf";
3664
+ };
3665
+ var CoverPreview = ({
3666
+ source,
3667
+ type,
3668
+ pageIndex = 0,
3669
+ visible = true,
3670
+ keepAlive = false,
3671
+ allowInteraction = false,
3672
+ renderScale = 2,
3673
+ showLoading = true,
3674
+ loadingIndicator,
3675
+ placeholder,
3676
+ style,
3677
+ onLoadStart,
3678
+ onLoadEnd,
3679
+ onError
3680
+ }) => {
3681
+ const [engine, setEngine] = useState5(null);
3682
+ const [layoutReady, setLayoutReady] = useState5(false);
3683
+ const [loaded, setLoaded] = useState5(false);
3684
+ const [loading, setLoading] = useState5(false);
3685
+ const [error, setError] = useState5(null);
3686
+ const viewRef = useRef5(null);
3687
+ const resolvedType = useMemo5(() => inferDocumentType(source, type), [source, type]);
3688
+ const isPdf = resolvedType === "pdf";
3689
+ const hasNativePageView = Boolean(UIManager2.getViewManagerConfig?.("PapyrusPageView"));
3690
+ const canRender = !isPdf || hasNativePageView;
3691
+ const shouldRender = Boolean(visible);
3692
+ useEffect7(() => {
3693
+ if (!shouldRender) {
3694
+ if (!keepAlive) {
3695
+ setEngine(null);
3696
+ setLoaded(false);
3697
+ setError(null);
3698
+ }
3699
+ return;
3700
+ }
3701
+ if (!engine && canRender) {
3702
+ setEngine(new MobileDocumentEngine());
3703
+ }
3704
+ }, [shouldRender, keepAlive, engine, canRender]);
3705
+ useEffect7(() => {
3706
+ if (!engine || !shouldRender || !canRender) return;
3707
+ let active = true;
3708
+ setLoading(true);
3709
+ setLoaded(false);
3710
+ setError(null);
3711
+ onLoadStart?.();
3712
+ const loadInput = type ? { type, source } : source;
3713
+ engine.load(loadInput).then(() => {
3714
+ if (!active) return;
3715
+ if (!isPdf && pageIndex > 0) {
3716
+ engine.goToPage(pageIndex + 1);
3717
+ }
3718
+ setLoaded(true);
3719
+ setLoading(false);
3720
+ onLoadEnd?.();
3721
+ }).catch((err) => {
3722
+ if (!active) return;
3723
+ const errorValue = err instanceof Error ? err : new Error("[Papyrus] Failed to load document");
3724
+ setError(errorValue);
3725
+ setLoading(false);
3726
+ onError?.(errorValue);
3727
+ });
3728
+ return () => {
3729
+ active = false;
3730
+ };
3731
+ }, [engine, shouldRender, canRender, source, type, pageIndex, isPdf, onLoadStart, onLoadEnd, onError]);
3732
+ useEffect7(() => {
3733
+ if (!engine || !isPdf || !loaded || !layoutReady || !shouldRender || !canRender) return;
3734
+ const viewTag = findNodeHandle3(viewRef.current);
3735
+ if (!viewTag) return;
3736
+ engine.renderPage(pageIndex, viewTag, renderScale);
3737
+ }, [engine, isPdf, loaded, layoutReady, shouldRender, canRender, pageIndex, renderScale]);
3738
+ useEffect7(() => {
3739
+ return () => {
3740
+ engine?.destroy();
3741
+ };
3742
+ }, [engine]);
3743
+ const handleLayout = (event) => {
3744
+ const { width, height } = event.nativeEvent.layout;
3745
+ if (width > 0 && height > 0) {
3746
+ setLayoutReady(true);
3747
+ }
3748
+ };
3749
+ if (!shouldRender || !canRender) {
3750
+ return /* @__PURE__ */ jsx11(View10, { style: [styles10.container, style], children: placeholder ?? /* @__PURE__ */ jsx11(View10, { style: styles10.placeholder, children: /* @__PURE__ */ jsx11(Text7, { style: styles10.placeholderText, children: "Preview" }) }) });
3751
+ }
3752
+ return /* @__PURE__ */ jsxs11(View10, { style: [styles10.container, style], onLayout: handleLayout, children: [
3753
+ /* @__PURE__ */ jsx11(View10, { style: styles10.previewFrame, pointerEvents: allowInteraction ? "auto" : "none", children: isPdf ? /* @__PURE__ */ jsx11(PapyrusPageView3, { ref: viewRef, style: styles10.pageView }) : engine && /* @__PURE__ */ jsx11(WebViewViewer_default, { engine }) }),
3754
+ showLoading && loading && /* @__PURE__ */ jsx11(View10, { pointerEvents: "none", style: styles10.loadingOverlay, children: loadingIndicator ?? /* @__PURE__ */ jsx11(ActivityIndicator2, { size: "small", color: "#2563eb" }) }),
3755
+ error && /* @__PURE__ */ jsx11(View10, { pointerEvents: "none", style: styles10.errorOverlay, children: /* @__PURE__ */ jsx11(Text7, { style: styles10.errorText, children: "Preview unavailable" }) })
3756
+ ] });
3757
+ };
3758
+ var styles10 = StyleSheet10.create({
3759
+ container: {
3760
+ backgroundColor: "#f8fafc",
3761
+ borderRadius: 12,
3762
+ overflow: "hidden"
3763
+ },
3764
+ previewFrame: {
3765
+ flex: 1,
3766
+ backgroundColor: "#ffffff"
3767
+ },
3768
+ pageView: {
3769
+ width: "100%",
3770
+ height: "100%",
3771
+ backgroundColor: "transparent"
3772
+ },
3773
+ loadingOverlay: {
3774
+ ...StyleSheet10.absoluteFillObject,
3775
+ alignItems: "center",
3776
+ justifyContent: "center",
3777
+ backgroundColor: "rgba(15, 23, 42, 0.15)"
3778
+ },
3779
+ errorOverlay: {
3780
+ ...StyleSheet10.absoluteFillObject,
3781
+ alignItems: "center",
3782
+ justifyContent: "center",
3783
+ backgroundColor: "rgba(15, 23, 42, 0.4)"
3784
+ },
3785
+ errorText: {
3786
+ fontSize: 12,
3787
+ fontWeight: "600",
3788
+ color: "#f8fafc"
3789
+ },
3790
+ placeholder: {
3791
+ flex: 1,
3792
+ alignItems: "center",
3793
+ justifyContent: "center",
3794
+ backgroundColor: "#e2e8f0"
3795
+ },
3796
+ placeholderText: {
3797
+ fontSize: 12,
3798
+ fontWeight: "600",
3799
+ color: "#475569"
3800
+ }
3801
+ });
3802
+ var CoverPreview_default = CoverPreview;
3609
3803
  export {
3610
3804
  AnnotationEditor_default as AnnotationEditor,
3611
3805
  BottomBar_default as BottomBar,
3806
+ CoverPreview_default as CoverPreview,
3612
3807
  PageRenderer_default as PageRenderer,
3613
3808
  RightSheet_default as RightSheet,
3614
3809
  SettingsSheet_default as SettingsSheet,