@hypercard-ai/hyper-jump 0.1.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 HyperCard.AI
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,75 @@
1
+ # hyper-jump
2
+
3
+ [![npm version](https://img.shields.io/npm/v/@hypercard-ai/hyper-jump)](https://www.npmjs.com/package/@hypercard-ai/hyper-jump)
4
+ [![CI](https://github.com/hypercard-ai/hyper-jump/actions/workflows/ci.yml/badge.svg)](https://github.com/hypercard-ai/hyper-jump/actions/workflows/ci.yml)
5
+ [![license](https://img.shields.io/npm/l/@hypercard-ai/hyper-jump)](./LICENSE)
6
+
7
+ A React PDF viewer built for RAG (Retrieval-Augmented Generation). Originally developed as part of [HyperCard.AI](https://hypercard.ai)'s chatbot platform, hyper-jump provides fast page navigation that pairs with RAG citations to deliver an excellent document viewing experience.
8
+
9
+ ## Features
10
+
11
+ - Virtualized rendering via `react-window` for smooth viewing of large PDFs
12
+ - Jump-to-page navigation for instant access to cited content
13
+ - Zoom controls with preset levels and automatic fit-to-width
14
+ - Responsive layout that adapts to container size
15
+ - Lightweight, self-contained CSS with no external styling dependencies
16
+
17
+ ## Installation
18
+
19
+ ```bash
20
+ npm install @hypercard-ai/hyper-jump
21
+ ```
22
+
23
+ ## Usage
24
+
25
+ ```tsx
26
+ import { HyperJumpViewer } from "@hypercard-ai/hyper-jump";
27
+ import "@hypercard-ai/hyper-jump/styles.css";
28
+
29
+ function App() {
30
+ return <HyperJumpViewer url="/path/to/document.pdf" />;
31
+ }
32
+ ```
33
+
34
+ ### Jump to a specific page
35
+
36
+ Pass a zero-indexed `page` prop to scroll directly to a page:
37
+
38
+ ```tsx
39
+ <HyperJumpViewer url="/path/to/document.pdf" page={3} />
40
+ ```
41
+
42
+ ## API
43
+
44
+ ### `<HyperJumpViewer />`
45
+
46
+ | Prop | Type | Required | Description |
47
+ | ------ | -------- | -------- | ----------------------------------- |
48
+ | `url` | `string` | Yes | URL or path to the PDF file |
49
+ | `page` | `number` | No | Zero-indexed page to scroll to |
50
+
51
+ ### Exports
52
+
53
+ | Export | Type | Description |
54
+ | ----------------------- | --------- | ------------------------------------ |
55
+ | `HyperJumpViewer` | Component | The PDF viewer component |
56
+ | `HyperJumpViewerProps` | Type | Props for the viewer component |
57
+ | `ZoomConfig` | Type | Zoom configuration interface |
58
+
59
+ ## Requirements
60
+
61
+ - React 19+
62
+
63
+ ## Development
64
+
65
+ ```bash
66
+ npm install
67
+ npm run storybook # Start Storybook on port 6006
68
+ npm run test # Run tests
69
+ npm run check # Format and lint with Biome
70
+ npm run build # Build the package
71
+ ```
72
+
73
+ ## License
74
+
75
+ MIT
package/dist/index.css ADDED
@@ -0,0 +1,143 @@
1
+ /* src/styles.css */
2
+ .hj-viewer {
3
+ position: relative;
4
+ display: flex;
5
+ align-items: center;
6
+ justify-content: center;
7
+ height: 100%;
8
+ width: 100%;
9
+ overflow: hidden;
10
+ }
11
+ .hj-viewer .react-pdf__Document {
12
+ height: 100%;
13
+ width: 100%;
14
+ }
15
+ .hj-page {
16
+ display: flex;
17
+ align-items: center;
18
+ justify-content: center;
19
+ }
20
+ .hj-loading {
21
+ display: flex;
22
+ align-items: center;
23
+ justify-content: center;
24
+ background: #fff;
25
+ position: relative;
26
+ }
27
+ .hj-spinner {
28
+ width: 32px;
29
+ height: 32px;
30
+ border: 3px solid #e9ecef;
31
+ border-top-color: #228be6;
32
+ border-radius: 50%;
33
+ animation: hj-spin 0.6s linear infinite;
34
+ }
35
+ @keyframes hj-spin {
36
+ to {
37
+ transform: rotate(360deg);
38
+ }
39
+ }
40
+ .hj-error {
41
+ display: flex;
42
+ align-items: center;
43
+ justify-content: center;
44
+ background: #fff;
45
+ color: #495057;
46
+ font-size: 14px;
47
+ }
48
+ .hj-controls {
49
+ position: absolute;
50
+ bottom: 12px;
51
+ left: 12px;
52
+ right: 12px;
53
+ display: flex;
54
+ justify-content: center;
55
+ align-items: center;
56
+ z-index: 10;
57
+ }
58
+ .hj-controls-bar {
59
+ display: flex;
60
+ align-items: center;
61
+ gap: 12px;
62
+ padding: 6px 12px;
63
+ background: #fff;
64
+ border: 1px solid #dee2e6;
65
+ border-radius: 8px;
66
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1), 0 1px 2px rgba(0, 0, 0, 0.06);
67
+ }
68
+ .hj-controls-group {
69
+ display: flex;
70
+ align-items: center;
71
+ gap: 6px;
72
+ }
73
+ .hj-divider {
74
+ width: 1px;
75
+ height: 24px;
76
+ background: #dee2e6;
77
+ }
78
+ .hj-btn {
79
+ display: inline-flex;
80
+ align-items: center;
81
+ justify-content: center;
82
+ padding: 4px 12px;
83
+ font-size: 13px;
84
+ font-family: inherit;
85
+ line-height: 1.4;
86
+ border: 1px solid #dee2e6;
87
+ border-radius: 4px;
88
+ background: #fff;
89
+ color: #212529;
90
+ cursor: pointer;
91
+ user-select: none;
92
+ white-space: nowrap;
93
+ }
94
+ .hj-btn:hover:not(:disabled) {
95
+ background: #f8f9fa;
96
+ }
97
+ .hj-btn:disabled {
98
+ opacity: 0.5;
99
+ cursor: not-allowed;
100
+ }
101
+ .hj-icon-btn {
102
+ display: inline-flex;
103
+ align-items: center;
104
+ justify-content: center;
105
+ width: 28px;
106
+ height: 28px;
107
+ padding: 0;
108
+ border: 1px solid #dee2e6;
109
+ border-radius: 4px;
110
+ background: #fff;
111
+ color: #212529;
112
+ cursor: pointer;
113
+ }
114
+ .hj-icon-btn:hover:not(:disabled) {
115
+ background: #f8f9fa;
116
+ }
117
+ .hj-icon-btn:disabled {
118
+ opacity: 0.5;
119
+ cursor: not-allowed;
120
+ }
121
+ .hj-page-indicator {
122
+ font-size: 13px;
123
+ min-width: 50px;
124
+ text-align: center;
125
+ color: #212529;
126
+ user-select: none;
127
+ }
128
+ .hj-select {
129
+ font-size: 13px;
130
+ font-family: inherit;
131
+ padding: 4px 8px;
132
+ border: 1px solid #dee2e6;
133
+ border-radius: 4px;
134
+ background: #fff;
135
+ color: #212529;
136
+ cursor: pointer;
137
+ min-width: 120px;
138
+ }
139
+ .hj-select:focus {
140
+ outline: 2px solid #228be6;
141
+ outline-offset: -1px;
142
+ }
143
+ /*# sourceMappingURL=index.css.map */
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/styles.css"],"sourcesContent":["/* HyperJump PDF Viewer Styles */\n\n.hj-viewer {\n\tposition: relative;\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n\theight: 100%;\n\twidth: 100%;\n\toverflow: hidden;\n}\n\n.hj-viewer .react-pdf__Document {\n\theight: 100%;\n\twidth: 100%;\n}\n\n/* Page renderer */\n.hj-page {\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n}\n\n/* Loading page */\n.hj-loading {\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n\tbackground: #fff;\n\tposition: relative;\n}\n\n.hj-spinner {\n\twidth: 32px;\n\theight: 32px;\n\tborder: 3px solid #e9ecef;\n\tborder-top-color: #228be6;\n\tborder-radius: 50%;\n\tanimation: hj-spin 0.6s linear infinite;\n}\n\n@keyframes hj-spin {\n\tto {\n\t\ttransform: rotate(360deg);\n\t}\n}\n\n/* Error page */\n.hj-error {\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n\tbackground: #fff;\n\tcolor: #495057;\n\tfont-size: 14px;\n}\n\n/* Controls */\n.hj-controls {\n\tposition: absolute;\n\tbottom: 12px;\n\tleft: 12px;\n\tright: 12px;\n\tdisplay: flex;\n\tjustify-content: center;\n\talign-items: center;\n\tz-index: 10;\n}\n\n.hj-controls-bar {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 12px;\n\tpadding: 6px 12px;\n\tbackground: #fff;\n\tborder: 1px solid #dee2e6;\n\tborder-radius: 8px;\n\tbox-shadow:\n\t\t0 1px 3px rgba(0, 0, 0, 0.1),\n\t\t0 1px 2px rgba(0, 0, 0, 0.06);\n}\n\n.hj-controls-group {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 6px;\n}\n\n.hj-divider {\n\twidth: 1px;\n\theight: 24px;\n\tbackground: #dee2e6;\n}\n\n.hj-btn {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tjustify-content: center;\n\tpadding: 4px 12px;\n\tfont-size: 13px;\n\tfont-family: inherit;\n\tline-height: 1.4;\n\tborder: 1px solid #dee2e6;\n\tborder-radius: 4px;\n\tbackground: #fff;\n\tcolor: #212529;\n\tcursor: pointer;\n\tuser-select: none;\n\twhite-space: nowrap;\n}\n\n.hj-btn:hover:not(:disabled) {\n\tbackground: #f8f9fa;\n}\n\n.hj-btn:disabled {\n\topacity: 0.5;\n\tcursor: not-allowed;\n}\n\n.hj-icon-btn {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tjustify-content: center;\n\twidth: 28px;\n\theight: 28px;\n\tpadding: 0;\n\tborder: 1px solid #dee2e6;\n\tborder-radius: 4px;\n\tbackground: #fff;\n\tcolor: #212529;\n\tcursor: pointer;\n}\n\n.hj-icon-btn:hover:not(:disabled) {\n\tbackground: #f8f9fa;\n}\n\n.hj-icon-btn:disabled {\n\topacity: 0.5;\n\tcursor: not-allowed;\n}\n\n.hj-page-indicator {\n\tfont-size: 13px;\n\tmin-width: 50px;\n\ttext-align: center;\n\tcolor: #212529;\n\tuser-select: none;\n}\n\n.hj-select {\n\tfont-size: 13px;\n\tfont-family: inherit;\n\tpadding: 4px 8px;\n\tborder: 1px solid #dee2e6;\n\tborder-radius: 4px;\n\tbackground: #fff;\n\tcolor: #212529;\n\tcursor: pointer;\n\tmin-width: 120px;\n}\n\n.hj-select:focus {\n\toutline: 2px solid #228be6;\n\toutline-offset: -1px;\n}\n"],"mappings":";AAEA,CAAC;AACA,YAAU;AACV,WAAS;AACT,eAAa;AACb,mBAAiB;AACjB,UAAQ;AACR,SAAO;AACP,YAAU;AACX;AAEA,CAVC,UAUU,CAAC;AACX,UAAQ;AACR,SAAO;AACR;AAGA,CAAC;AACA,WAAS;AACT,eAAa;AACb,mBAAiB;AAClB;AAGA,CAAC;AACA,WAAS;AACT,eAAa;AACb,mBAAiB;AACjB,cAAY;AACZ,YAAU;AACX;AAEA,CAAC;AACA,SAAO;AACP,UAAQ;AACR,UAAQ,IAAI,MAAM;AAClB,oBAAkB;AAClB,iBAAe;AACf,aAAW,QAAQ,KAAK,OAAO;AAChC;AAEA,WAHY;AAIX;AACC,eAAW,OAAO;AACnB;AACD;AAGA,CAAC;AACA,WAAS;AACT,eAAa;AACb,mBAAiB;AACjB,cAAY;AACZ,SAAO;AACP,aAAW;AACZ;AAGA,CAAC;AACA,YAAU;AACV,UAAQ;AACR,QAAM;AACN,SAAO;AACP,WAAS;AACT,mBAAiB;AACjB,eAAa;AACb,WAAS;AACV;AAEA,CAAC;AACA,WAAS;AACT,eAAa;AACb,OAAK;AACL,WAAS,IAAI;AACb,cAAY;AACZ,UAAQ,IAAI,MAAM;AAClB,iBAAe;AACf,cACC,EAAE,IAAI,IAAI,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,IAAI,EAC5B,EAAE,IAAI,IAAI,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE;AAC1B;AAEA,CAAC;AACA,WAAS;AACT,eAAa;AACb,OAAK;AACN;AAEA,CAAC;AACA,SAAO;AACP,UAAQ;AACR,cAAY;AACb;AAEA,CAAC;AACA,WAAS;AACT,eAAa;AACb,mBAAiB;AACjB,WAAS,IAAI;AACb,aAAW;AACX,eAAa;AACb,eAAa;AACb,UAAQ,IAAI,MAAM;AAClB,iBAAe;AACf,cAAY;AACZ,SAAO;AACP,UAAQ;AACR,eAAa;AACb,eAAa;AACd;AAEA,CAjBC,MAiBM,MAAM,KAAK;AACjB,cAAY;AACb;AAEA,CArBC,MAqBM;AACN,WAAS;AACT,UAAQ;AACT;AAEA,CAAC;AACA,WAAS;AACT,eAAa;AACb,mBAAiB;AACjB,SAAO;AACP,UAAQ;AACR,WAAS;AACT,UAAQ,IAAI,MAAM;AAClB,iBAAe;AACf,cAAY;AACZ,SAAO;AACP,UAAQ;AACT;AAEA,CAdC,WAcW,MAAM,KAAK;AACtB,cAAY;AACb;AAEA,CAlBC,WAkBW;AACX,WAAS;AACT,UAAQ;AACT;AAEA,CAAC;AACA,aAAW;AACX,aAAW;AACX,cAAY;AACZ,SAAO;AACP,eAAa;AACd;AAEA,CAAC;AACA,aAAW;AACX,eAAa;AACb,WAAS,IAAI;AACb,UAAQ,IAAI,MAAM;AAClB,iBAAe;AACf,cAAY;AACZ,SAAO;AACP,UAAQ;AACR,aAAW;AACZ;AAEA,CAZC,SAYS;AACT,WAAS,IAAI,MAAM;AACnB,kBAAgB;AACjB;","names":[]}
@@ -0,0 +1,19 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+
3
+ type ZoomMode = "automatic" | "page-width" | "manual";
4
+ interface ZoomConfig {
5
+ mode: ZoomMode;
6
+ value: number;
7
+ }
8
+
9
+ interface HyperJumpViewerProps {
10
+ /** URL of the PDF file to display */
11
+ url: string;
12
+ /** Page number to jump to (0-indexed) */
13
+ page?: number;
14
+ /** Called when the visible page changes (0-indexed) */
15
+ onPageChange?: (page: number) => void;
16
+ }
17
+ declare function HyperJumpViewer(props: HyperJumpViewerProps): react_jsx_runtime.JSX.Element;
18
+
19
+ export { HyperJumpViewer, type HyperJumpViewerProps, type ZoomConfig };
package/dist/index.js ADDED
@@ -0,0 +1,318 @@
1
+ // src/viewer.tsx
2
+ import { useCallback as useCallback2, useEffect, useMemo, useRef as useRef2, useState as useState2 } from "react";
3
+ import { Document, pdfjs } from "react-pdf";
4
+ import "react-pdf/dist/Page/AnnotationLayer.css";
5
+ import "react-pdf/dist/Page/TextLayer.css";
6
+ import { List } from "react-window";
7
+
8
+ // src/controls.tsx
9
+ import { jsx, jsxs } from "react/jsx-runtime";
10
+ var ZOOM_OPTIONS = [
11
+ { label: "Auto Width", value: "automatic" },
12
+ { label: "50%", value: "0.5" },
13
+ { label: "75%", value: "0.75" },
14
+ { label: "100%", value: "1" },
15
+ { label: "125%", value: "1.25" },
16
+ { label: "150%", value: "1.5" },
17
+ { label: "200%", value: "2" },
18
+ { label: "300%", value: "3" },
19
+ { label: "400%", value: "4" }
20
+ ];
21
+ function ChevronLeft() {
22
+ return /* @__PURE__ */ jsxs(
23
+ "svg",
24
+ {
25
+ width: "16",
26
+ height: "16",
27
+ viewBox: "0 0 24 24",
28
+ fill: "none",
29
+ stroke: "currentColor",
30
+ strokeWidth: "2",
31
+ strokeLinecap: "round",
32
+ strokeLinejoin: "round",
33
+ children: [
34
+ /* @__PURE__ */ jsx("title", { children: "Previous Page" }),
35
+ /* @__PURE__ */ jsx("path", { d: "M15 18l-6-6 6-6" })
36
+ ]
37
+ }
38
+ );
39
+ }
40
+ function ChevronRight() {
41
+ return /* @__PURE__ */ jsxs(
42
+ "svg",
43
+ {
44
+ width: "16",
45
+ height: "16",
46
+ viewBox: "0 0 24 24",
47
+ fill: "none",
48
+ stroke: "currentColor",
49
+ strokeWidth: "2",
50
+ strokeLinecap: "round",
51
+ strokeLinejoin: "round",
52
+ children: [
53
+ /* @__PURE__ */ jsx("title", { children: "Next Page" }),
54
+ /* @__PURE__ */ jsx("path", { d: "M9 18l6-6-6 6" })
55
+ ]
56
+ }
57
+ );
58
+ }
59
+ function PDFViewerControls(props) {
60
+ const {
61
+ onChangeZoom,
62
+ pageIndex,
63
+ numPages,
64
+ zoomConfig,
65
+ onNextPage,
66
+ onPrevPage
67
+ } = props;
68
+ const zoomValue = zoomConfig.mode === "automatic" || zoomConfig.mode === "page-width" ? zoomConfig.mode : zoomConfig.value.toString();
69
+ return /* @__PURE__ */ jsx("div", { className: "hj-controls", children: /* @__PURE__ */ jsxs("div", { className: "hj-controls-bar", children: [
70
+ /* @__PURE__ */ jsxs("div", { className: "hj-controls-group", children: [
71
+ /* @__PURE__ */ jsx(
72
+ "button",
73
+ {
74
+ type: "button",
75
+ className: "hj-icon-btn",
76
+ onClick: onPrevPage,
77
+ disabled: pageIndex <= 0,
78
+ "aria-label": "Previous Page",
79
+ children: /* @__PURE__ */ jsx(ChevronLeft, {})
80
+ }
81
+ ),
82
+ /* @__PURE__ */ jsxs("span", { className: "hj-page-indicator", children: [
83
+ pageIndex + 1,
84
+ " / ",
85
+ numPages
86
+ ] }),
87
+ /* @__PURE__ */ jsx(
88
+ "button",
89
+ {
90
+ type: "button",
91
+ className: "hj-icon-btn",
92
+ onClick: onNextPage,
93
+ disabled: pageIndex >= numPages - 1,
94
+ "aria-label": "Next Page",
95
+ children: /* @__PURE__ */ jsx(ChevronRight, {})
96
+ }
97
+ )
98
+ ] }),
99
+ /* @__PURE__ */ jsx("div", { className: "hj-divider" }),
100
+ /* @__PURE__ */ jsx(
101
+ "select",
102
+ {
103
+ className: "hj-select",
104
+ value: zoomValue,
105
+ onChange: (e) => onChangeZoom(e.target.value),
106
+ "aria-label": "Zoom Level",
107
+ children: ZOOM_OPTIONS.map((opt) => /* @__PURE__ */ jsx("option", { value: opt.value, children: opt.label }, opt.value))
108
+ }
109
+ )
110
+ ] }) });
111
+ }
112
+
113
+ // src/constants.ts
114
+ var PAGE_HEIGHT = 842;
115
+ var PAGE_WIDTH = 595;
116
+
117
+ // src/error-page.tsx
118
+ import { jsx as jsx2 } from "react/jsx-runtime";
119
+ function PDFErrorPage() {
120
+ return /* @__PURE__ */ jsx2(
121
+ "div",
122
+ {
123
+ className: "hj-error",
124
+ style: { width: PAGE_WIDTH, height: PAGE_HEIGHT },
125
+ children: "Error loading file"
126
+ }
127
+ );
128
+ }
129
+
130
+ // src/loading-page.tsx
131
+ import { jsx as jsx3 } from "react/jsx-runtime";
132
+ function PDFLoadingPage() {
133
+ return /* @__PURE__ */ jsx3(
134
+ "div",
135
+ {
136
+ className: "hj-loading",
137
+ style: { width: PAGE_WIDTH, height: PAGE_HEIGHT },
138
+ children: /* @__PURE__ */ jsx3("div", { className: "hj-spinner" })
139
+ }
140
+ );
141
+ }
142
+
143
+ // src/renderer.tsx
144
+ import { Page } from "react-pdf";
145
+ import { jsx as jsx4 } from "react/jsx-runtime";
146
+ function PDFPageRenderer(props) {
147
+ const { index, style, scale } = props;
148
+ return /* @__PURE__ */ jsx4("div", { className: "hj-page", style, children: /* @__PURE__ */ jsx4(Page, { pageIndex: index, scale, loading: PDFLoadingPage }) });
149
+ }
150
+
151
+ // src/use-element-size.ts
152
+ import { useCallback, useRef, useState } from "react";
153
+ function useElementSize() {
154
+ const [size, setSize] = useState({ width: 0, height: 0 });
155
+ const observerRef = useRef(null);
156
+ const ref = useCallback((node) => {
157
+ if (observerRef.current) {
158
+ observerRef.current.disconnect();
159
+ observerRef.current = null;
160
+ }
161
+ if (node) {
162
+ const observer = new ResizeObserver(([entry]) => {
163
+ const { width, height } = entry.contentRect;
164
+ setSize((prev) => {
165
+ if (prev.width === width && prev.height === height) return prev;
166
+ return { width, height };
167
+ });
168
+ });
169
+ observer.observe(node);
170
+ observerRef.current = observer;
171
+ }
172
+ }, []);
173
+ return { ref, width: size.width, height: size.height };
174
+ }
175
+
176
+ // src/utils.ts
177
+ async function getPageDimensions(document, scale) {
178
+ const dims = [];
179
+ for (let i = 1; i <= document.numPages; i++) {
180
+ try {
181
+ const page = await document.getPage(i);
182
+ const viewport = page.getViewport({ scale });
183
+ const { height, width } = viewport;
184
+ dims.push({ height, width });
185
+ } catch (error) {
186
+ console.error("Failed to get page dimensions", error);
187
+ dims.push({
188
+ width: PAGE_WIDTH,
189
+ height: PAGE_HEIGHT
190
+ });
191
+ }
192
+ }
193
+ return dims;
194
+ }
195
+
196
+ // src/viewer.tsx
197
+ import { jsx as jsx5, jsxs as jsxs2 } from "react/jsx-runtime";
198
+ pdfjs.GlobalWorkerOptions.workerSrc = new URL(
199
+ "pdfjs-dist/build/pdf.worker.min.mjs",
200
+ import.meta.url
201
+ ).toString();
202
+ var PAGE_MARGIN = 12;
203
+ function HyperJumpViewer(props) {
204
+ const { url, page, onPageChange } = props;
205
+ const [document, setDocument] = useState2();
206
+ const [pageIndex, setPageIndex] = useState2(0);
207
+ const [pageDimensions, setPageDimensions] = useState2([]);
208
+ const [zoomConfig, setZoomConfig] = useState2({
209
+ mode: "automatic",
210
+ value: 1
211
+ });
212
+ const scrollPageRef = useRef2(0);
213
+ const { ref: containerRef } = useElementSize();
214
+ const listRef = useRef2(null);
215
+ const numPages = useMemo(() => {
216
+ return document?.numPages || 0;
217
+ }, [document]);
218
+ useEffect(() => {
219
+ if (document) {
220
+ getPageDimensions(document, zoomConfig.value).then((value) => {
221
+ setPageDimensions(value);
222
+ });
223
+ }
224
+ }, [document, zoomConfig]);
225
+ const scrollToPage = useCallback2((index) => {
226
+ listRef.current?.scrollToRow({ index, align: "start" });
227
+ setPageIndex(index);
228
+ }, []);
229
+ const onLoadSuccess = useCallback2((response) => {
230
+ setDocument(response);
231
+ }, []);
232
+ useEffect(() => {
233
+ if (page !== void 0 && pageDimensions.length === numPages && numPages > 0) {
234
+ scrollToPage(page);
235
+ }
236
+ }, [page, pageDimensions, numPages, scrollToPage]);
237
+ const file = useMemo(() => {
238
+ return { url };
239
+ }, [url]);
240
+ const onPrevPage = useCallback2(() => {
241
+ if (pageIndex > 0) {
242
+ const newPageIndex = pageIndex - 1;
243
+ listRef.current?.scrollToRow({ index: newPageIndex, align: "start" });
244
+ setPageIndex(newPageIndex);
245
+ }
246
+ }, [pageIndex]);
247
+ const onNextPage = useCallback2(() => {
248
+ if (pageIndex < numPages - 1) {
249
+ const newPageIndex = pageIndex + 1;
250
+ listRef.current?.scrollToRow({ index: newPageIndex, align: "start" });
251
+ setPageIndex(newPageIndex);
252
+ }
253
+ }, [pageIndex, numPages]);
254
+ const onChangeZoom = useCallback2((value) => {
255
+ if (value === "automatic") {
256
+ setZoomConfig({ mode: "automatic", value: 1 });
257
+ } else {
258
+ setZoomConfig({ mode: "manual", value: Number.parseFloat(value) });
259
+ }
260
+ }, []);
261
+ const getItemSize = useCallback2(
262
+ (index) => {
263
+ if (pageDimensions[index]) {
264
+ return pageDimensions[index].height + PAGE_MARGIN;
265
+ }
266
+ return 0;
267
+ },
268
+ [pageDimensions]
269
+ );
270
+ const onRowsRendered = useCallback2(
271
+ (visibleRows) => {
272
+ const prev = scrollPageRef.current;
273
+ scrollPageRef.current = visibleRows.startIndex;
274
+ if (visibleRows.startIndex !== prev) {
275
+ setPageIndex(visibleRows.startIndex);
276
+ onPageChange?.(visibleRows.startIndex);
277
+ }
278
+ },
279
+ [onPageChange]
280
+ );
281
+ return /* @__PURE__ */ jsxs2("div", { className: "hj-viewer", ref: containerRef, children: [
282
+ file ? /* @__PURE__ */ jsx5(
283
+ Document,
284
+ {
285
+ file,
286
+ onLoadSuccess,
287
+ error: PDFErrorPage,
288
+ loading: PDFLoadingPage,
289
+ children: pageDimensions.length > 0 && pageDimensions.length === numPages && /* @__PURE__ */ jsx5(
290
+ List,
291
+ {
292
+ listRef,
293
+ rowCount: numPages,
294
+ rowHeight: getItemSize,
295
+ onRowsRendered,
296
+ rowProps: { scale: zoomConfig.value },
297
+ rowComponent: PDFPageRenderer
298
+ }
299
+ )
300
+ }
301
+ ) : /* @__PURE__ */ jsx5(PDFLoadingPage, {}),
302
+ /* @__PURE__ */ jsx5(
303
+ PDFViewerControls,
304
+ {
305
+ pageIndex,
306
+ numPages,
307
+ onPrevPage,
308
+ onNextPage,
309
+ zoomConfig,
310
+ onChangeZoom
311
+ }
312
+ )
313
+ ] });
314
+ }
315
+ export {
316
+ HyperJumpViewer
317
+ };
318
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/viewer.tsx","../src/controls.tsx","../src/constants.ts","../src/error-page.tsx","../src/loading-page.tsx","../src/renderer.tsx","../src/use-element-size.ts","../src/utils.ts"],"sourcesContent":["import type { PDFDocumentProxy } from \"pdfjs-dist\";\nimport { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport { Document, pdfjs } from \"react-pdf\";\nimport \"react-pdf/dist/Page/AnnotationLayer.css\";\nimport \"react-pdf/dist/Page/TextLayer.css\";\nimport type { OnDocumentLoadSuccess } from \"react-pdf/dist/shared/types.js\";\nimport { List, type ListImperativeAPI } from \"react-window\";\nimport PDFViewerControls from \"./controls\";\nimport PDFErrorPage from \"./error-page\";\nimport PDFLoadingPage from \"./loading-page\";\nimport PDFPageRenderer from \"./renderer\";\nimport \"./styles.css\";\nimport type { ZoomConfig } from \"./types\";\nimport { useElementSize } from \"./use-element-size\";\nimport { getPageDimensions } from \"./utils\";\n\npdfjs.GlobalWorkerOptions.workerSrc = new URL(\n\t\"pdfjs-dist/build/pdf.worker.min.mjs\",\n\timport.meta.url,\n).toString();\n\nconst PAGE_MARGIN = 12;\n\nexport interface HyperJumpViewerProps {\n\t/** URL of the PDF file to display */\n\turl: string;\n\t/** Page number to jump to (0-indexed) */\n\tpage?: number;\n\t/** Called when the visible page changes (0-indexed) */\n\tonPageChange?: (page: number) => void;\n}\n\nexport function HyperJumpViewer(props: HyperJumpViewerProps) {\n\tconst { url, page, onPageChange } = props;\n\tconst [document, setDocument] = useState<PDFDocumentProxy>();\n\tconst [pageIndex, setPageIndex] = useState(0);\n\tconst [pageDimensions, setPageDimensions] = useState<\n\t\t{ width: number; height: number }[]\n\t>([]);\n\tconst [zoomConfig, setZoomConfig] = useState<ZoomConfig>({\n\t\tmode: \"automatic\",\n\t\tvalue: 1,\n\t});\n\tconst scrollPageRef = useRef(0);\n\n\tconst { ref: containerRef } = useElementSize();\n\tconst listRef = useRef<ListImperativeAPI>(null);\n\n\tconst numPages = useMemo(() => {\n\t\treturn document?.numPages || 0;\n\t}, [document]);\n\n\tuseEffect(() => {\n\t\tif (document) {\n\t\t\tgetPageDimensions(document, zoomConfig.value).then((value) => {\n\t\t\t\tsetPageDimensions(value);\n\t\t\t});\n\t\t}\n\t}, [document, zoomConfig]);\n\n\tconst scrollToPage = useCallback((index: number) => {\n\t\tlistRef.current?.scrollToRow({ index, align: \"start\" });\n\t\tsetPageIndex(index);\n\t}, []);\n\n\tconst onLoadSuccess: OnDocumentLoadSuccess = useCallback((response) => {\n\t\tsetDocument(response);\n\t}, []);\n\n\tuseEffect(() => {\n\t\tif (\n\t\t\tpage !== undefined &&\n\t\t\tpageDimensions.length === numPages &&\n\t\t\tnumPages > 0\n\t\t) {\n\t\t\tscrollToPage(page);\n\t\t}\n\t}, [page, pageDimensions, numPages, scrollToPage]);\n\n\tconst file = useMemo(() => {\n\t\treturn { url };\n\t}, [url]);\n\n\tconst onPrevPage = useCallback(() => {\n\t\tif (pageIndex > 0) {\n\t\t\tconst newPageIndex = pageIndex - 1;\n\t\t\tlistRef.current?.scrollToRow({ index: newPageIndex, align: \"start\" });\n\t\t\tsetPageIndex(newPageIndex);\n\t\t}\n\t}, [pageIndex]);\n\n\tconst onNextPage = useCallback(() => {\n\t\tif (pageIndex < numPages - 1) {\n\t\t\tconst newPageIndex = pageIndex + 1;\n\t\t\tlistRef.current?.scrollToRow({ index: newPageIndex, align: \"start\" });\n\t\t\tsetPageIndex(newPageIndex);\n\t\t}\n\t}, [pageIndex, numPages]);\n\n\tconst onChangeZoom = useCallback((value: string) => {\n\t\tif (value === \"automatic\") {\n\t\t\tsetZoomConfig({ mode: \"automatic\", value: 1 });\n\t\t} else {\n\t\t\tsetZoomConfig({ mode: \"manual\", value: Number.parseFloat(value) });\n\t\t}\n\t}, []);\n\n\tconst getItemSize = useCallback(\n\t\t(index: number) => {\n\t\t\tif (pageDimensions[index]) {\n\t\t\t\treturn pageDimensions[index].height + PAGE_MARGIN;\n\t\t\t}\n\t\t\treturn 0;\n\t\t},\n\t\t[pageDimensions],\n\t);\n\n\tconst onRowsRendered = useCallback(\n\t\t(visibleRows: { startIndex: number; stopIndex: number }) => {\n\t\t\tconst prev = scrollPageRef.current;\n\t\t\tscrollPageRef.current = visibleRows.startIndex;\n\t\t\tif (visibleRows.startIndex !== prev) {\n\t\t\t\tsetPageIndex(visibleRows.startIndex);\n\t\t\t\tonPageChange?.(visibleRows.startIndex);\n\t\t\t}\n\t\t},\n\t\t[onPageChange],\n\t);\n\n\treturn (\n\t\t<div className=\"hj-viewer\" ref={containerRef}>\n\t\t\t{file ? (\n\t\t\t\t<Document\n\t\t\t\t\tfile={file}\n\t\t\t\t\tonLoadSuccess={onLoadSuccess}\n\t\t\t\t\terror={PDFErrorPage}\n\t\t\t\t\tloading={PDFLoadingPage}\n\t\t\t\t>\n\t\t\t\t\t{pageDimensions.length > 0 && pageDimensions.length === numPages && (\n\t\t\t\t\t\t<List\n\t\t\t\t\t\t\tlistRef={listRef}\n\t\t\t\t\t\t\trowCount={numPages}\n\t\t\t\t\t\t\trowHeight={getItemSize}\n\t\t\t\t\t\t\tonRowsRendered={onRowsRendered}\n\t\t\t\t\t\t\trowProps={{ scale: zoomConfig.value }}\n\t\t\t\t\t\t\trowComponent={PDFPageRenderer}\n\t\t\t\t\t\t/>\n\t\t\t\t\t)}\n\t\t\t\t</Document>\n\t\t\t) : (\n\t\t\t\t<PDFLoadingPage />\n\t\t\t)}\n\t\t\t<PDFViewerControls\n\t\t\t\tpageIndex={pageIndex}\n\t\t\t\tnumPages={numPages}\n\t\t\t\tonPrevPage={onPrevPage}\n\t\t\t\tonNextPage={onNextPage}\n\t\t\t\tzoomConfig={zoomConfig}\n\t\t\t\tonChangeZoom={onChangeZoom}\n\t\t\t/>\n\t\t</div>\n\t);\n}\n","import type { ZoomConfig } from \"./types\";\n\nconst ZOOM_OPTIONS = [\n\t{ label: \"Auto Width\", value: \"automatic\" },\n\t{ label: \"50%\", value: \"0.5\" },\n\t{ label: \"75%\", value: \"0.75\" },\n\t{ label: \"100%\", value: \"1\" },\n\t{ label: \"125%\", value: \"1.25\" },\n\t{ label: \"150%\", value: \"1.5\" },\n\t{ label: \"200%\", value: \"2\" },\n\t{ label: \"300%\", value: \"3\" },\n\t{ label: \"400%\", value: \"4\" },\n];\n\ninterface IProps {\n\tonChangeZoom(value: string): void;\n\tpageIndex: number;\n\tnumPages: number;\n\tzoomConfig: ZoomConfig;\n\tonNextPage(): void;\n\tonPrevPage(): void;\n}\n\nfunction ChevronLeft() {\n\treturn (\n\t\t<svg\n\t\t\twidth=\"16\"\n\t\t\theight=\"16\"\n\t\t\tviewBox=\"0 0 24 24\"\n\t\t\tfill=\"none\"\n\t\t\tstroke=\"currentColor\"\n\t\t\tstrokeWidth=\"2\"\n\t\t\tstrokeLinecap=\"round\"\n\t\t\tstrokeLinejoin=\"round\"\n\t\t>\n\t\t\t<title>Previous Page</title>\n\t\t\t<path d=\"M15 18l-6-6 6-6\" />\n\t\t</svg>\n\t);\n}\n\nfunction ChevronRight() {\n\treturn (\n\t\t<svg\n\t\t\twidth=\"16\"\n\t\t\theight=\"16\"\n\t\t\tviewBox=\"0 0 24 24\"\n\t\t\tfill=\"none\"\n\t\t\tstroke=\"currentColor\"\n\t\t\tstrokeWidth=\"2\"\n\t\t\tstrokeLinecap=\"round\"\n\t\t\tstrokeLinejoin=\"round\"\n\t\t>\n\t\t\t<title>Next Page</title>\n\t\t\t<path d=\"M9 18l6-6-6 6\" />\n\t\t</svg>\n\t);\n}\n\nexport default function PDFViewerControls(props: IProps) {\n\tconst {\n\t\tonChangeZoom,\n\t\tpageIndex,\n\t\tnumPages,\n\t\tzoomConfig,\n\t\tonNextPage,\n\t\tonPrevPage,\n\t} = props;\n\n\tconst zoomValue =\n\t\tzoomConfig.mode === \"automatic\" || zoomConfig.mode === \"page-width\"\n\t\t\t? zoomConfig.mode\n\t\t\t: zoomConfig.value.toString();\n\n\treturn (\n\t\t<div className=\"hj-controls\">\n\t\t\t<div className=\"hj-controls-bar\">\n\t\t\t\t<div className=\"hj-controls-group\">\n\t\t\t\t\t<button\n\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\tclassName=\"hj-icon-btn\"\n\t\t\t\t\t\tonClick={onPrevPage}\n\t\t\t\t\t\tdisabled={pageIndex <= 0}\n\t\t\t\t\t\taria-label=\"Previous Page\"\n\t\t\t\t\t>\n\t\t\t\t\t\t<ChevronLeft />\n\t\t\t\t\t</button>\n\t\t\t\t\t<span className=\"hj-page-indicator\">\n\t\t\t\t\t\t{pageIndex + 1} / {numPages}\n\t\t\t\t\t</span>\n\t\t\t\t\t<button\n\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\tclassName=\"hj-icon-btn\"\n\t\t\t\t\t\tonClick={onNextPage}\n\t\t\t\t\t\tdisabled={pageIndex >= numPages - 1}\n\t\t\t\t\t\taria-label=\"Next Page\"\n\t\t\t\t\t>\n\t\t\t\t\t\t<ChevronRight />\n\t\t\t\t\t</button>\n\t\t\t\t</div>\n\t\t\t\t<div className=\"hj-divider\" />\n\t\t\t\t<select\n\t\t\t\t\tclassName=\"hj-select\"\n\t\t\t\t\tvalue={zoomValue}\n\t\t\t\t\tonChange={(e) => onChangeZoom(e.target.value)}\n\t\t\t\t\taria-label=\"Zoom Level\"\n\t\t\t\t>\n\t\t\t\t\t{ZOOM_OPTIONS.map((opt) => (\n\t\t\t\t\t\t<option key={opt.value} value={opt.value}>\n\t\t\t\t\t\t\t{opt.label}\n\t\t\t\t\t\t</option>\n\t\t\t\t\t))}\n\t\t\t\t</select>\n\t\t\t</div>\n\t\t</div>\n\t);\n}\n","export const PAGE_HEIGHT = 842;\nexport const PAGE_WIDTH = 595;\n","import { PAGE_HEIGHT, PAGE_WIDTH } from \"./constants\";\n\nexport default function PDFErrorPage() {\n\treturn (\n\t\t<div\n\t\t\tclassName=\"hj-error\"\n\t\t\tstyle={{ width: PAGE_WIDTH, height: PAGE_HEIGHT }}\n\t\t>\n\t\t\tError loading file\n\t\t</div>\n\t);\n}\n","import { PAGE_HEIGHT, PAGE_WIDTH } from \"./constants\";\n\nexport default function PDFLoadingPage() {\n\treturn (\n\t\t<div\n\t\t\tclassName=\"hj-loading\"\n\t\t\tstyle={{ width: PAGE_WIDTH, height: PAGE_HEIGHT }}\n\t\t>\n\t\t\t<div className=\"hj-spinner\" />\n\t\t</div>\n\t);\n}\n","import { Page } from \"react-pdf\";\nimport type { RowComponentProps } from \"react-window\";\nimport PDFLoadingPage from \"./loading-page\";\n\ninterface RowProps {\n\tscale: number;\n}\n\nexport default function PDFPageRenderer(props: RowComponentProps<RowProps>) {\n\tconst { index, style, scale } = props;\n\treturn (\n\t\t<div className=\"hj-page\" style={style}>\n\t\t\t<Page pageIndex={index} scale={scale} loading={PDFLoadingPage} />\n\t\t</div>\n\t);\n}\n","import { useCallback, useRef, useState } from \"react\";\n\nexport function useElementSize<T extends HTMLElement = HTMLDivElement>() {\n\tconst [size, setSize] = useState({ width: 0, height: 0 });\n\tconst observerRef = useRef<ResizeObserver | null>(null);\n\n\tconst ref = useCallback((node: T | null) => {\n\t\tif (observerRef.current) {\n\t\t\tobserverRef.current.disconnect();\n\t\t\tobserverRef.current = null;\n\t\t}\n\n\t\tif (node) {\n\t\t\tconst observer = new ResizeObserver(([entry]) => {\n\t\t\t\tconst { width, height } = entry.contentRect;\n\t\t\t\tsetSize((prev) => {\n\t\t\t\t\tif (prev.width === width && prev.height === height) return prev;\n\t\t\t\t\treturn { width, height };\n\t\t\t\t});\n\t\t\t});\n\t\t\tobserver.observe(node);\n\t\t\tobserverRef.current = observer;\n\t\t}\n\t}, []);\n\n\treturn { ref, width: size.width, height: size.height };\n}\n","import type { PDFDocumentProxy } from \"pdfjs-dist\";\nimport { PAGE_HEIGHT, PAGE_WIDTH } from \"./constants\";\n\nexport async function getPageDimensions(\n\tdocument: PDFDocumentProxy,\n\tscale: number,\n) {\n\tconst dims = [];\n\tfor (let i = 1; i <= document.numPages; i++) {\n\t\ttry {\n\t\t\tconst page = await document.getPage(i);\n\t\t\tconst viewport = page.getViewport({ scale });\n\t\t\tconst { height, width } = viewport;\n\t\t\tdims.push({ height, width });\n\t\t} catch (error) {\n\t\t\tconsole.error(\"Failed to get page dimensions\", error);\n\t\t\tdims.push({\n\t\t\t\twidth: PAGE_WIDTH,\n\t\t\t\theight: PAGE_HEIGHT,\n\t\t\t});\n\t\t}\n\t}\n\treturn dims;\n}\n"],"mappings":";AACA,SAAS,eAAAA,cAAa,WAAW,SAAS,UAAAC,SAAQ,YAAAC,iBAAgB;AAClE,SAAS,UAAU,aAAa;AAChC,OAAO;AACP,OAAO;AAEP,SAAS,YAAoC;;;ACmB3C,SAUC,KAVD;AAvBF,IAAM,eAAe;AAAA,EACpB,EAAE,OAAO,cAAc,OAAO,YAAY;AAAA,EAC1C,EAAE,OAAO,OAAO,OAAO,MAAM;AAAA,EAC7B,EAAE,OAAO,OAAO,OAAO,OAAO;AAAA,EAC9B,EAAE,OAAO,QAAQ,OAAO,IAAI;AAAA,EAC5B,EAAE,OAAO,QAAQ,OAAO,OAAO;AAAA,EAC/B,EAAE,OAAO,QAAQ,OAAO,MAAM;AAAA,EAC9B,EAAE,OAAO,QAAQ,OAAO,IAAI;AAAA,EAC5B,EAAE,OAAO,QAAQ,OAAO,IAAI;AAAA,EAC5B,EAAE,OAAO,QAAQ,OAAO,IAAI;AAC7B;AAWA,SAAS,cAAc;AACtB,SACC;AAAA,IAAC;AAAA;AAAA,MACA,OAAM;AAAA,MACN,QAAO;AAAA,MACP,SAAQ;AAAA,MACR,MAAK;AAAA,MACL,QAAO;AAAA,MACP,aAAY;AAAA,MACZ,eAAc;AAAA,MACd,gBAAe;AAAA,MAEf;AAAA,4BAAC,WAAM,2BAAa;AAAA,QACpB,oBAAC,UAAK,GAAE,mBAAkB;AAAA;AAAA;AAAA,EAC3B;AAEF;AAEA,SAAS,eAAe;AACvB,SACC;AAAA,IAAC;AAAA;AAAA,MACA,OAAM;AAAA,MACN,QAAO;AAAA,MACP,SAAQ;AAAA,MACR,MAAK;AAAA,MACL,QAAO;AAAA,MACP,aAAY;AAAA,MACZ,eAAc;AAAA,MACd,gBAAe;AAAA,MAEf;AAAA,4BAAC,WAAM,uBAAS;AAAA,QAChB,oBAAC,UAAK,GAAE,iBAAgB;AAAA;AAAA;AAAA,EACzB;AAEF;AAEe,SAAR,kBAAmC,OAAe;AACxD,QAAM;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACD,IAAI;AAEJ,QAAM,YACL,WAAW,SAAS,eAAe,WAAW,SAAS,eACpD,WAAW,OACX,WAAW,MAAM,SAAS;AAE9B,SACC,oBAAC,SAAI,WAAU,eACd,+BAAC,SAAI,WAAU,mBACd;AAAA,yBAAC,SAAI,WAAU,qBACd;AAAA;AAAA,QAAC;AAAA;AAAA,UACA,MAAK;AAAA,UACL,WAAU;AAAA,UACV,SAAS;AAAA,UACT,UAAU,aAAa;AAAA,UACvB,cAAW;AAAA,UAEX,8BAAC,eAAY;AAAA;AAAA,MACd;AAAA,MACA,qBAAC,UAAK,WAAU,qBACd;AAAA,oBAAY;AAAA,QAAE;AAAA,QAAI;AAAA,SACpB;AAAA,MACA;AAAA,QAAC;AAAA;AAAA,UACA,MAAK;AAAA,UACL,WAAU;AAAA,UACV,SAAS;AAAA,UACT,UAAU,aAAa,WAAW;AAAA,UAClC,cAAW;AAAA,UAEX,8BAAC,gBAAa;AAAA;AAAA,MACf;AAAA,OACD;AAAA,IACA,oBAAC,SAAI,WAAU,cAAa;AAAA,IAC5B;AAAA,MAAC;AAAA;AAAA,QACA,WAAU;AAAA,QACV,OAAO;AAAA,QACP,UAAU,CAAC,MAAM,aAAa,EAAE,OAAO,KAAK;AAAA,QAC5C,cAAW;AAAA,QAEV,uBAAa,IAAI,CAAC,QAClB,oBAAC,YAAuB,OAAO,IAAI,OACjC,cAAI,SADO,IAAI,KAEjB,CACA;AAAA;AAAA,IACF;AAAA,KACD,GACD;AAEF;;;ACpHO,IAAM,cAAc;AACpB,IAAM,aAAa;;;ACGxB,gBAAAC,YAAA;AAFa,SAAR,eAAgC;AACtC,SACC,gBAAAA;AAAA,IAAC;AAAA;AAAA,MACA,WAAU;AAAA,MACV,OAAO,EAAE,OAAO,YAAY,QAAQ,YAAY;AAAA,MAChD;AAAA;AAAA,EAED;AAEF;;;ACHG,gBAAAC,YAAA;AANY,SAAR,iBAAkC;AACxC,SACC,gBAAAA;AAAA,IAAC;AAAA;AAAA,MACA,WAAU;AAAA,MACV,OAAO,EAAE,OAAO,YAAY,QAAQ,YAAY;AAAA,MAEhD,0BAAAA,KAAC,SAAI,WAAU,cAAa;AAAA;AAAA,EAC7B;AAEF;;;ACXA,SAAS,YAAY;AAYlB,gBAAAC,YAAA;AAJY,SAAR,gBAAiC,OAAoC;AAC3E,QAAM,EAAE,OAAO,OAAO,MAAM,IAAI;AAChC,SACC,gBAAAA,KAAC,SAAI,WAAU,WAAU,OACxB,0BAAAA,KAAC,QAAK,WAAW,OAAO,OAAc,SAAS,gBAAgB,GAChE;AAEF;;;ACfA,SAAS,aAAa,QAAQ,gBAAgB;AAEvC,SAAS,iBAAyD;AACxE,QAAM,CAAC,MAAM,OAAO,IAAI,SAAS,EAAE,OAAO,GAAG,QAAQ,EAAE,CAAC;AACxD,QAAM,cAAc,OAA8B,IAAI;AAEtD,QAAM,MAAM,YAAY,CAAC,SAAmB;AAC3C,QAAI,YAAY,SAAS;AACxB,kBAAY,QAAQ,WAAW;AAC/B,kBAAY,UAAU;AAAA,IACvB;AAEA,QAAI,MAAM;AACT,YAAM,WAAW,IAAI,eAAe,CAAC,CAAC,KAAK,MAAM;AAChD,cAAM,EAAE,OAAO,OAAO,IAAI,MAAM;AAChC,gBAAQ,CAAC,SAAS;AACjB,cAAI,KAAK,UAAU,SAAS,KAAK,WAAW,OAAQ,QAAO;AAC3D,iBAAO,EAAE,OAAO,OAAO;AAAA,QACxB,CAAC;AAAA,MACF,CAAC;AACD,eAAS,QAAQ,IAAI;AACrB,kBAAY,UAAU;AAAA,IACvB;AAAA,EACD,GAAG,CAAC,CAAC;AAEL,SAAO,EAAE,KAAK,OAAO,KAAK,OAAO,QAAQ,KAAK,OAAO;AACtD;;;ACvBA,eAAsB,kBACrB,UACA,OACC;AACD,QAAM,OAAO,CAAC;AACd,WAAS,IAAI,GAAG,KAAK,SAAS,UAAU,KAAK;AAC5C,QAAI;AACH,YAAM,OAAO,MAAM,SAAS,QAAQ,CAAC;AACrC,YAAM,WAAW,KAAK,YAAY,EAAE,MAAM,CAAC;AAC3C,YAAM,EAAE,QAAQ,MAAM,IAAI;AAC1B,WAAK,KAAK,EAAE,QAAQ,MAAM,CAAC;AAAA,IAC5B,SAAS,OAAO;AACf,cAAQ,MAAM,iCAAiC,KAAK;AACpD,WAAK,KAAK;AAAA,QACT,OAAO;AAAA,QACP,QAAQ;AAAA,MACT,CAAC;AAAA,IACF;AAAA,EACD;AACA,SAAO;AACR;;;AP2GE,SASI,OAAAC,MATJ,QAAAC,aAAA;AAlHF,MAAM,oBAAoB,YAAY,IAAI;AAAA,EACzC;AAAA,EACA,YAAY;AACb,EAAE,SAAS;AAEX,IAAM,cAAc;AAWb,SAAS,gBAAgB,OAA6B;AAC5D,QAAM,EAAE,KAAK,MAAM,aAAa,IAAI;AACpC,QAAM,CAAC,UAAU,WAAW,IAAIC,UAA2B;AAC3D,QAAM,CAAC,WAAW,YAAY,IAAIA,UAAS,CAAC;AAC5C,QAAM,CAAC,gBAAgB,iBAAiB,IAAIA,UAE1C,CAAC,CAAC;AACJ,QAAM,CAAC,YAAY,aAAa,IAAIA,UAAqB;AAAA,IACxD,MAAM;AAAA,IACN,OAAO;AAAA,EACR,CAAC;AACD,QAAM,gBAAgBC,QAAO,CAAC;AAE9B,QAAM,EAAE,KAAK,aAAa,IAAI,eAAe;AAC7C,QAAM,UAAUA,QAA0B,IAAI;AAE9C,QAAM,WAAW,QAAQ,MAAM;AAC9B,WAAO,UAAU,YAAY;AAAA,EAC9B,GAAG,CAAC,QAAQ,CAAC;AAEb,YAAU,MAAM;AACf,QAAI,UAAU;AACb,wBAAkB,UAAU,WAAW,KAAK,EAAE,KAAK,CAAC,UAAU;AAC7D,0BAAkB,KAAK;AAAA,MACxB,CAAC;AAAA,IACF;AAAA,EACD,GAAG,CAAC,UAAU,UAAU,CAAC;AAEzB,QAAM,eAAeC,aAAY,CAAC,UAAkB;AACnD,YAAQ,SAAS,YAAY,EAAE,OAAO,OAAO,QAAQ,CAAC;AACtD,iBAAa,KAAK;AAAA,EACnB,GAAG,CAAC,CAAC;AAEL,QAAM,gBAAuCA,aAAY,CAAC,aAAa;AACtE,gBAAY,QAAQ;AAAA,EACrB,GAAG,CAAC,CAAC;AAEL,YAAU,MAAM;AACf,QACC,SAAS,UACT,eAAe,WAAW,YAC1B,WAAW,GACV;AACD,mBAAa,IAAI;AAAA,IAClB;AAAA,EACD,GAAG,CAAC,MAAM,gBAAgB,UAAU,YAAY,CAAC;AAEjD,QAAM,OAAO,QAAQ,MAAM;AAC1B,WAAO,EAAE,IAAI;AAAA,EACd,GAAG,CAAC,GAAG,CAAC;AAER,QAAM,aAAaA,aAAY,MAAM;AACpC,QAAI,YAAY,GAAG;AAClB,YAAM,eAAe,YAAY;AACjC,cAAQ,SAAS,YAAY,EAAE,OAAO,cAAc,OAAO,QAAQ,CAAC;AACpE,mBAAa,YAAY;AAAA,IAC1B;AAAA,EACD,GAAG,CAAC,SAAS,CAAC;AAEd,QAAM,aAAaA,aAAY,MAAM;AACpC,QAAI,YAAY,WAAW,GAAG;AAC7B,YAAM,eAAe,YAAY;AACjC,cAAQ,SAAS,YAAY,EAAE,OAAO,cAAc,OAAO,QAAQ,CAAC;AACpE,mBAAa,YAAY;AAAA,IAC1B;AAAA,EACD,GAAG,CAAC,WAAW,QAAQ,CAAC;AAExB,QAAM,eAAeA,aAAY,CAAC,UAAkB;AACnD,QAAI,UAAU,aAAa;AAC1B,oBAAc,EAAE,MAAM,aAAa,OAAO,EAAE,CAAC;AAAA,IAC9C,OAAO;AACN,oBAAc,EAAE,MAAM,UAAU,OAAO,OAAO,WAAW,KAAK,EAAE,CAAC;AAAA,IAClE;AAAA,EACD,GAAG,CAAC,CAAC;AAEL,QAAM,cAAcA;AAAA,IACnB,CAAC,UAAkB;AAClB,UAAI,eAAe,KAAK,GAAG;AAC1B,eAAO,eAAe,KAAK,EAAE,SAAS;AAAA,MACvC;AACA,aAAO;AAAA,IACR;AAAA,IACA,CAAC,cAAc;AAAA,EAChB;AAEA,QAAM,iBAAiBA;AAAA,IACtB,CAAC,gBAA2D;AAC3D,YAAM,OAAO,cAAc;AAC3B,oBAAc,UAAU,YAAY;AACpC,UAAI,YAAY,eAAe,MAAM;AACpC,qBAAa,YAAY,UAAU;AACnC,uBAAe,YAAY,UAAU;AAAA,MACtC;AAAA,IACD;AAAA,IACA,CAAC,YAAY;AAAA,EACd;AAEA,SACC,gBAAAH,MAAC,SAAI,WAAU,aAAY,KAAK,cAC9B;AAAA,WACA,gBAAAD;AAAA,MAAC;AAAA;AAAA,QACA;AAAA,QACA;AAAA,QACA,OAAO;AAAA,QACP,SAAS;AAAA,QAER,yBAAe,SAAS,KAAK,eAAe,WAAW,YACvD,gBAAAA;AAAA,UAAC;AAAA;AAAA,YACA;AAAA,YACA,UAAU;AAAA,YACV,WAAW;AAAA,YACX;AAAA,YACA,UAAU,EAAE,OAAO,WAAW,MAAM;AAAA,YACpC,cAAc;AAAA;AAAA,QACf;AAAA;AAAA,IAEF,IAEA,gBAAAA,KAAC,kBAAe;AAAA,IAEjB,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA;AAAA,IACD;AAAA,KACD;AAEF;","names":["useCallback","useRef","useState","jsx","jsx","jsx","jsx","jsxs","useState","useRef","useCallback"]}
package/package.json ADDED
@@ -0,0 +1,78 @@
1
+ {
2
+ "name": "@hypercard-ai/hyper-jump",
3
+ "version": "0.1.0",
4
+ "description": "Document viewer built for RAG",
5
+ "license": "MIT",
6
+ "author": "HyperCard AI",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/hypercard-ai/hyper-jump.git"
10
+ },
11
+ "homepage": "https://github.com/hypercard-ai/hyper-jump",
12
+ "bugs": {
13
+ "url": "https://github.com/hypercard-ai/hyper-jump/issues"
14
+ },
15
+ "keywords": [
16
+ "pdf",
17
+ "viewer",
18
+ "react",
19
+ "rag",
20
+ "virtualized",
21
+ "react-pdf"
22
+ ],
23
+ "type": "module",
24
+ "module": "./dist/index.js",
25
+ "types": "./dist/index.d.ts",
26
+ "exports": {
27
+ ".": {
28
+ "types": "./dist/index.d.ts",
29
+ "default": "./dist/index.js"
30
+ },
31
+ "./styles.css": "./dist/index.css"
32
+ },
33
+ "files": [
34
+ "dist",
35
+ "README.md",
36
+ "LICENSE"
37
+ ],
38
+ "sideEffects": false,
39
+ "publishConfig": {
40
+ "access": "public"
41
+ },
42
+ "scripts": {
43
+ "build": "tsup",
44
+ "dev": "tsup --watch",
45
+ "test": "vitest run",
46
+ "test:watch": "vitest",
47
+ "lint": "eslint src/",
48
+ "prepublishOnly": "npm run build",
49
+ "size": "size-limit",
50
+ "storybook": "storybook dev -p 6006",
51
+ "build-storybook": "storybook build",
52
+ "check": "npx @biomejs/biome check --write ./"
53
+ },
54
+ "peerDependencies": {
55
+ "react": ">=19.0.0",
56
+ "react-dom": ">=19.0.0"
57
+ },
58
+ "devDependencies": {
59
+ "@biomejs/biome": "2.3.15",
60
+ "@storybook/addon-docs": "^10.2.8",
61
+ "@storybook/react-vite": "^10.2.8",
62
+ "@testing-library/jest-dom": "^6.9.1",
63
+ "@testing-library/react": "^16.3.2",
64
+ "@types/react": "^19.2.14",
65
+ "@types/react-dom": "^19.2.3",
66
+ "jsdom": "^28.0.0",
67
+ "react": "^19.2.4",
68
+ "react-dom": "^19.2.4",
69
+ "storybook": "^10.2.8",
70
+ "tsup": "^8.5.1",
71
+ "typescript": "^5.9.3",
72
+ "vitest": "^4.0.18"
73
+ },
74
+ "dependencies": {
75
+ "react-pdf": "10.3.0",
76
+ "react-window": "^2.2.7"
77
+ }
78
+ }