@hypercard-ai/hyper-jump 1.0.2 → 1.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/README.md +39 -4
- package/dist/markdown/index.css +137 -0
- package/dist/markdown/index.css.map +1 -0
- package/dist/markdown/index.d.ts +3 -0
- package/dist/markdown/index.d.ts.map +1 -0
- package/dist/markdown/index.js +73 -0
- package/dist/markdown/index.js.map +1 -0
- package/dist/markdown/markdown-viewer.d.ts +7 -0
- package/dist/markdown/markdown-viewer.d.ts.map +1 -0
- package/package.json +13 -2
package/README.md
CHANGED
|
@@ -10,7 +10,7 @@ Renderers are opt-in — only bundle what you use.
|
|
|
10
10
|
|
|
11
11
|
## Features
|
|
12
12
|
|
|
13
|
-
- **Pluggable renderers** — import only the file types you need (PDF, video, and more coming soon)
|
|
13
|
+
- **Pluggable renderers** — import only the file types you need (PDF, video, markdown, and more coming soon)
|
|
14
14
|
- Virtualized rendering via `react-window` for smooth viewing of large PDFs
|
|
15
15
|
- Unified `jump()` API for instant navigation to cited content across all file types
|
|
16
16
|
- Zoom controls with preset levels and automatic fit-to-width
|
|
@@ -23,6 +23,9 @@ Renderers are opt-in — only bundle what you use.
|
|
|
23
23
|
# Core + PDF renderer
|
|
24
24
|
npm install @hypercard-ai/hyper-jump react-pdf react-window
|
|
25
25
|
|
|
26
|
+
# Core + Markdown renderer
|
|
27
|
+
npm install @hypercard-ai/hyper-jump react-markdown
|
|
28
|
+
|
|
26
29
|
# Core + Video renderer (no extra dependencies needed)
|
|
27
30
|
npm install @hypercard-ai/hyper-jump
|
|
28
31
|
```
|
|
@@ -47,7 +50,7 @@ function App() {
|
|
|
47
50
|
|
|
48
51
|
### Open at a specific position
|
|
49
52
|
|
|
50
|
-
Pass `initialPosition` to start at a specific location when the file loads. The meaning depends on the renderer — page index for PDF, seconds for video:
|
|
53
|
+
Pass `initialPosition` to start at a specific location when the file loads. The meaning depends on the renderer — page index for PDF, seconds for video, pixel offset for markdown:
|
|
51
54
|
|
|
52
55
|
```tsx
|
|
53
56
|
// PDF: open at page 4 (0-indexed)
|
|
@@ -55,6 +58,9 @@ Pass `initialPosition` to start at a specific location when the file loads. The
|
|
|
55
58
|
|
|
56
59
|
// Video: start at 30 seconds
|
|
57
60
|
<HyperJumpViewer url="/clip.mp4" renderers={[VideoRenderer]} initialPosition={30} />
|
|
61
|
+
|
|
62
|
+
// Markdown: start at 200px scroll offset
|
|
63
|
+
<HyperJumpViewer url="/doc.md" renderers={[MarkdownRenderer]} initialPosition={200} />
|
|
58
64
|
```
|
|
59
65
|
|
|
60
66
|
### Jump to a position imperatively
|
|
@@ -96,7 +102,7 @@ The core component. It detects the file type from the URL extension (or an expli
|
|
|
96
102
|
| `renderers` | `FileRenderer[]` | Yes | Renderers the viewer can use (first match wins) |
|
|
97
103
|
| `type` | `string` | No | Explicit file type override (e.g. `"pdf"`). If omitted, detected from URL extension |
|
|
98
104
|
| `ref` | `Ref<HyperJumpAPI>` | No | Forwarded to the active renderer for the `jump()` API |
|
|
99
|
-
| `initialPosition` | `number` | No | Position to start at when the file loads (page index for PDF, seconds for video) |
|
|
105
|
+
| `initialPosition` | `number` | No | Position to start at when the file loads (page index for PDF, seconds for video, pixel offset for markdown) |
|
|
100
106
|
| `onPositionChange` | `(position: number) => void` | No | Called when the current position changes |
|
|
101
107
|
| `rendererProps` | `T` | No | Additional props forwarded to the matched renderer (generic, typed per renderer) |
|
|
102
108
|
|
|
@@ -106,7 +112,7 @@ All renderers expose the same imperative API:
|
|
|
106
112
|
|
|
107
113
|
| Method | Description |
|
|
108
114
|
| --- | --- |
|
|
109
|
-
| `jump(position: number)` | Jump to a position. Page index for PDF (0-indexed, clamped), seconds for video. |
|
|
115
|
+
| `jump(position: number)` | Jump to a position. Page index for PDF (0-indexed, clamped), seconds for video, pixel offset for markdown. |
|
|
110
116
|
|
|
111
117
|
### PDF Renderer
|
|
112
118
|
|
|
@@ -118,6 +124,26 @@ Imported from `@hypercard-ai/hyper-jump/pdf`. Requires `react-pdf` and `react-wi
|
|
|
118
124
|
| --- | --- | --- | --- |
|
|
119
125
|
| `scrollBehavior` | `"auto" \| "instant" \| "smooth"` | No | Scroll behavior when navigating between pages (default: `"instant"`) |
|
|
120
126
|
|
|
127
|
+
### Markdown Renderer
|
|
128
|
+
|
|
129
|
+
Imported from `@hypercard-ai/hyper-jump/markdown`. Requires `react-markdown` as a peer dependency. Fetches the markdown file from the URL and renders it with GitHub-flavored styling.
|
|
130
|
+
|
|
131
|
+
```tsx
|
|
132
|
+
import { HyperJumpViewer } from "@hypercard-ai/hyper-jump";
|
|
133
|
+
import { MarkdownRenderer } from "@hypercard-ai/hyper-jump/markdown";
|
|
134
|
+
import "@hypercard-ai/hyper-jump/styles.css";
|
|
135
|
+
import "@hypercard-ai/hyper-jump/markdown/styles.css";
|
|
136
|
+
|
|
137
|
+
function App() {
|
|
138
|
+
return (
|
|
139
|
+
<HyperJumpViewer
|
|
140
|
+
url="/path/to/document.md"
|
|
141
|
+
renderers={[MarkdownRenderer]}
|
|
142
|
+
/>
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
```
|
|
146
|
+
|
|
121
147
|
### Video Renderer
|
|
122
148
|
|
|
123
149
|
Imported from `@hypercard-ai/hyper-jump/video`. Uses the native HTML `<video>` element — no extra dependencies required.
|
|
@@ -165,6 +191,14 @@ function App() {
|
|
|
165
191
|
| `HyperJumpPdfViewerProps` | Type | Full props for the PDF renderer |
|
|
166
192
|
| `ScrollBehavior` | Type | Scroll behavior union type |
|
|
167
193
|
|
|
194
|
+
#### `@hypercard-ai/hyper-jump/markdown`
|
|
195
|
+
|
|
196
|
+
| Export | Type | Description |
|
|
197
|
+
| --- | --- | --- |
|
|
198
|
+
| `MarkdownRenderer` | `FileRenderer` | Renderer descriptor for markdown files |
|
|
199
|
+
| `HyperJumpMarkdownViewerAPI` | Type | Alias for `HyperJumpAPI` |
|
|
200
|
+
| `HyperJumpMarkdownViewerProps` | Type | Full props for the markdown renderer |
|
|
201
|
+
|
|
168
202
|
#### `@hypercard-ai/hyper-jump/video`
|
|
169
203
|
|
|
170
204
|
| Export | Type | Description |
|
|
@@ -196,6 +230,7 @@ const MyVideoRenderer: FileRenderer = {
|
|
|
196
230
|
- React 19+
|
|
197
231
|
- react-pdf 10+ (when using `PdfRenderer`)
|
|
198
232
|
- react-window 2+ (when using `PdfRenderer`)
|
|
233
|
+
- react-markdown 9+ (when using `MarkdownRenderer`)
|
|
199
234
|
|
|
200
235
|
## Development
|
|
201
236
|
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
/* src/markdown/markdown-viewer.css */
|
|
2
|
+
.hj-markdown {
|
|
3
|
+
height: 100%;
|
|
4
|
+
width: 100%;
|
|
5
|
+
overflow-y: auto;
|
|
6
|
+
padding: 24px 32px;
|
|
7
|
+
box-sizing: border-box;
|
|
8
|
+
font-family:
|
|
9
|
+
-apple-system,
|
|
10
|
+
BlinkMacSystemFont,
|
|
11
|
+
"Segoe UI",
|
|
12
|
+
Helvetica,
|
|
13
|
+
Arial,
|
|
14
|
+
sans-serif;
|
|
15
|
+
font-size: 16px;
|
|
16
|
+
line-height: 1.6;
|
|
17
|
+
color: #1f2328;
|
|
18
|
+
word-wrap: break-word;
|
|
19
|
+
}
|
|
20
|
+
.hj-markdown--loading,
|
|
21
|
+
.hj-markdown--error {
|
|
22
|
+
display: flex;
|
|
23
|
+
align-items: center;
|
|
24
|
+
justify-content: center;
|
|
25
|
+
}
|
|
26
|
+
.hj-markdown h1,
|
|
27
|
+
.hj-markdown h2,
|
|
28
|
+
.hj-markdown h3,
|
|
29
|
+
.hj-markdown h4,
|
|
30
|
+
.hj-markdown h5,
|
|
31
|
+
.hj-markdown h6 {
|
|
32
|
+
margin-top: 24px;
|
|
33
|
+
margin-bottom: 16px;
|
|
34
|
+
font-weight: 600;
|
|
35
|
+
line-height: 1.25;
|
|
36
|
+
}
|
|
37
|
+
.hj-markdown h1 {
|
|
38
|
+
font-size: 2em;
|
|
39
|
+
padding-bottom: 0.3em;
|
|
40
|
+
border-bottom: 1px solid #d1d9e0;
|
|
41
|
+
}
|
|
42
|
+
.hj-markdown h2 {
|
|
43
|
+
font-size: 1.5em;
|
|
44
|
+
padding-bottom: 0.3em;
|
|
45
|
+
border-bottom: 1px solid #d1d9e0;
|
|
46
|
+
}
|
|
47
|
+
.hj-markdown h3 {
|
|
48
|
+
font-size: 1.25em;
|
|
49
|
+
}
|
|
50
|
+
.hj-markdown p {
|
|
51
|
+
margin-top: 0;
|
|
52
|
+
margin-bottom: 16px;
|
|
53
|
+
}
|
|
54
|
+
.hj-markdown a {
|
|
55
|
+
color: #0969da;
|
|
56
|
+
text-decoration: none;
|
|
57
|
+
}
|
|
58
|
+
.hj-markdown a:hover {
|
|
59
|
+
text-decoration: underline;
|
|
60
|
+
}
|
|
61
|
+
.hj-markdown code {
|
|
62
|
+
padding: 0.2em 0.4em;
|
|
63
|
+
margin: 0;
|
|
64
|
+
font-size: 85%;
|
|
65
|
+
background-color: rgba(175, 184, 193, 0.2);
|
|
66
|
+
border-radius: 6px;
|
|
67
|
+
font-family:
|
|
68
|
+
ui-monospace,
|
|
69
|
+
SFMono-Regular,
|
|
70
|
+
"SF Mono",
|
|
71
|
+
Menlo,
|
|
72
|
+
Consolas,
|
|
73
|
+
"Liberation Mono",
|
|
74
|
+
monospace;
|
|
75
|
+
}
|
|
76
|
+
.hj-markdown pre {
|
|
77
|
+
padding: 16px;
|
|
78
|
+
overflow: auto;
|
|
79
|
+
font-size: 85%;
|
|
80
|
+
line-height: 1.45;
|
|
81
|
+
background-color: #f6f8fa;
|
|
82
|
+
border-radius: 6px;
|
|
83
|
+
margin-bottom: 16px;
|
|
84
|
+
}
|
|
85
|
+
.hj-markdown pre code {
|
|
86
|
+
padding: 0;
|
|
87
|
+
background-color: transparent;
|
|
88
|
+
border-radius: 0;
|
|
89
|
+
font-size: 100%;
|
|
90
|
+
}
|
|
91
|
+
.hj-markdown blockquote {
|
|
92
|
+
padding: 0 1em;
|
|
93
|
+
color: #656d76;
|
|
94
|
+
border-left: 0.25em solid #d1d9e0;
|
|
95
|
+
margin: 0 0 16px 0;
|
|
96
|
+
}
|
|
97
|
+
.hj-markdown ul,
|
|
98
|
+
.hj-markdown ol {
|
|
99
|
+
padding-left: 2em;
|
|
100
|
+
margin-top: 0;
|
|
101
|
+
margin-bottom: 16px;
|
|
102
|
+
}
|
|
103
|
+
.hj-markdown li + li {
|
|
104
|
+
margin-top: 0.25em;
|
|
105
|
+
}
|
|
106
|
+
.hj-markdown hr {
|
|
107
|
+
height: 0.25em;
|
|
108
|
+
padding: 0;
|
|
109
|
+
margin: 24px 0;
|
|
110
|
+
background-color: #d1d9e0;
|
|
111
|
+
border: 0;
|
|
112
|
+
}
|
|
113
|
+
.hj-markdown img {
|
|
114
|
+
max-width: 100%;
|
|
115
|
+
height: auto;
|
|
116
|
+
}
|
|
117
|
+
.hj-markdown table {
|
|
118
|
+
border-spacing: 0;
|
|
119
|
+
border-collapse: collapse;
|
|
120
|
+
margin-bottom: 16px;
|
|
121
|
+
width: max-content;
|
|
122
|
+
max-width: 100%;
|
|
123
|
+
overflow: auto;
|
|
124
|
+
}
|
|
125
|
+
.hj-markdown table th,
|
|
126
|
+
.hj-markdown table td {
|
|
127
|
+
padding: 6px 13px;
|
|
128
|
+
border: 1px solid #d1d9e0;
|
|
129
|
+
}
|
|
130
|
+
.hj-markdown table th {
|
|
131
|
+
font-weight: 600;
|
|
132
|
+
background-color: #f6f8fa;
|
|
133
|
+
}
|
|
134
|
+
.hj-markdown table tr:nth-child(2n) {
|
|
135
|
+
background-color: #f6f8fa;
|
|
136
|
+
}
|
|
137
|
+
/*# sourceMappingURL=index.css.map */
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/markdown/markdown-viewer.css"],"sourcesContent":[".hj-markdown {\n\theight: 100%;\n\twidth: 100%;\n\toverflow-y: auto;\n\tpadding: 24px 32px;\n\tbox-sizing: border-box;\n\tfont-family:\n\t\t-apple-system, BlinkMacSystemFont, \"Segoe UI\", Helvetica, Arial, sans-serif;\n\tfont-size: 16px;\n\tline-height: 1.6;\n\tcolor: #1f2328;\n\tword-wrap: break-word;\n}\n\n.hj-markdown--loading,\n.hj-markdown--error {\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n}\n\n.hj-markdown h1,\n.hj-markdown h2,\n.hj-markdown h3,\n.hj-markdown h4,\n.hj-markdown h5,\n.hj-markdown h6 {\n\tmargin-top: 24px;\n\tmargin-bottom: 16px;\n\tfont-weight: 600;\n\tline-height: 1.25;\n}\n\n.hj-markdown h1 {\n\tfont-size: 2em;\n\tpadding-bottom: 0.3em;\n\tborder-bottom: 1px solid #d1d9e0;\n}\n\n.hj-markdown h2 {\n\tfont-size: 1.5em;\n\tpadding-bottom: 0.3em;\n\tborder-bottom: 1px solid #d1d9e0;\n}\n\n.hj-markdown h3 {\n\tfont-size: 1.25em;\n}\n\n.hj-markdown p {\n\tmargin-top: 0;\n\tmargin-bottom: 16px;\n}\n\n.hj-markdown a {\n\tcolor: #0969da;\n\ttext-decoration: none;\n}\n\n.hj-markdown a:hover {\n\ttext-decoration: underline;\n}\n\n.hj-markdown code {\n\tpadding: 0.2em 0.4em;\n\tmargin: 0;\n\tfont-size: 85%;\n\tbackground-color: rgba(175, 184, 193, 0.2);\n\tborder-radius: 6px;\n\tfont-family:\n\t\tui-monospace, SFMono-Regular, \"SF Mono\", Menlo, Consolas, \"Liberation Mono\",\n\t\tmonospace;\n}\n\n.hj-markdown pre {\n\tpadding: 16px;\n\toverflow: auto;\n\tfont-size: 85%;\n\tline-height: 1.45;\n\tbackground-color: #f6f8fa;\n\tborder-radius: 6px;\n\tmargin-bottom: 16px;\n}\n\n.hj-markdown pre code {\n\tpadding: 0;\n\tbackground-color: transparent;\n\tborder-radius: 0;\n\tfont-size: 100%;\n}\n\n.hj-markdown blockquote {\n\tpadding: 0 1em;\n\tcolor: #656d76;\n\tborder-left: 0.25em solid #d1d9e0;\n\tmargin: 0 0 16px 0;\n}\n\n.hj-markdown ul,\n.hj-markdown ol {\n\tpadding-left: 2em;\n\tmargin-top: 0;\n\tmargin-bottom: 16px;\n}\n\n.hj-markdown li + li {\n\tmargin-top: 0.25em;\n}\n\n.hj-markdown hr {\n\theight: 0.25em;\n\tpadding: 0;\n\tmargin: 24px 0;\n\tbackground-color: #d1d9e0;\n\tborder: 0;\n}\n\n.hj-markdown img {\n\tmax-width: 100%;\n\theight: auto;\n}\n\n.hj-markdown table {\n\tborder-spacing: 0;\n\tborder-collapse: collapse;\n\tmargin-bottom: 16px;\n\twidth: max-content;\n\tmax-width: 100%;\n\toverflow: auto;\n}\n\n.hj-markdown table th,\n.hj-markdown table td {\n\tpadding: 6px 13px;\n\tborder: 1px solid #d1d9e0;\n}\n\n.hj-markdown table th {\n\tfont-weight: 600;\n\tbackground-color: #f6f8fa;\n}\n\n.hj-markdown table tr:nth-child(2n) {\n\tbackground-color: #f6f8fa;\n}\n"],"mappings":";AAAA,CAAC;AACA,UAAQ;AACR,SAAO;AACP,cAAY;AACZ,WAAS,KAAK;AACd,cAAY;AACZ;AAAA,IACC,aAAa;AAAA,IAAE,kBAAkB;AAAA,IAAE,UAAU;AAAA,IAAE,SAAS;AAAA,IAAE,KAAK;AAAA,IAAE;AAClE,aAAW;AACX,eAAa;AACb,SAAO;AACP,aAAW;AACZ;AAEA,CAAC;AACD,CAAC;AACA,WAAS;AACT,eAAa;AACb,mBAAiB;AAClB;AAEA,CArBC,YAqBY;AACb,CAtBC,YAsBY;AACb,CAvBC,YAuBY;AACb,CAxBC,YAwBY;AACb,CAzBC,YAyBY;AACb,CA1BC,YA0BY;AACZ,cAAY;AACZ,iBAAe;AACf,eAAa;AACb,eAAa;AACd;AAEA,CAjCC,YAiCY;AACZ,aAAW;AACX,kBAAgB;AAChB,iBAAe,IAAI,MAAM;AAC1B;AAEA,CAvCC,YAuCY;AACZ,aAAW;AACX,kBAAgB;AAChB,iBAAe,IAAI,MAAM;AAC1B;AAEA,CA7CC,YA6CY;AACZ,aAAW;AACZ;AAEA,CAjDC,YAiDY;AACZ,cAAY;AACZ,iBAAe;AAChB;AAEA,CAtDC,YAsDY;AACZ,SAAO;AACP,mBAAiB;AAClB;AAEA,CA3DC,YA2DY,CAAC;AACb,mBAAiB;AAClB;AAEA,CA/DC,YA+DY;AACZ,WAAS,MAAM;AACf,UAAQ;AACR,aAAW;AACX,oBAAkB,KAAK,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE;AACtC,iBAAe;AACf;AAAA,IACC,YAAY;AAAA,IAAE,cAAc;AAAA,IAAE,SAAS;AAAA,IAAE,KAAK;AAAA,IAAE,QAAQ;AAAA,IAAE,iBAAiB;AAAA,IAC3E;AACF;AAEA,CA1EC,YA0EY;AACZ,WAAS;AACT,YAAU;AACV,aAAW;AACX,eAAa;AACb,oBAAkB;AAClB,iBAAe;AACf,iBAAe;AAChB;AAEA,CApFC,YAoFY,IAAI;AAChB,WAAS;AACT,oBAAkB;AAClB,iBAAe;AACf,aAAW;AACZ;AAEA,CA3FC,YA2FY;AACZ,WAAS,EAAE;AACX,SAAO;AACP,eAAa,OAAO,MAAM;AAC1B,UAAQ,EAAE,EAAE,KAAK;AAClB;AAEA,CAlGC,YAkGY;AACb,CAnGC,YAmGY;AACZ,gBAAc;AACd,cAAY;AACZ,iBAAe;AAChB;AAEA,CAzGC,YAyGY,GAAG,EAAE;AACjB,cAAY;AACb;AAEA,CA7GC,YA6GY;AACZ,UAAQ;AACR,WAAS;AACT,UAAQ,KAAK;AACb,oBAAkB;AAClB,UAAQ;AACT;AAEA,CArHC,YAqHY;AACZ,aAAW;AACX,UAAQ;AACT;AAEA,CA1HC,YA0HY;AACZ,kBAAgB;AAChB,mBAAiB;AACjB,iBAAe;AACf,SAAO;AACP,aAAW;AACX,YAAU;AACX;AAEA,CAnIC,YAmIY,MAAM;AACnB,CApIC,YAoIY,MAAM;AAClB,WAAS,IAAI;AACb,UAAQ,IAAI,MAAM;AACnB;AAEA,CAzIC,YAyIY,MAAM;AAClB,eAAa;AACb,oBAAkB;AACnB;AAEA,CA9IC,YA8IY,MAAM,EAAE;AACpB,oBAAkB;AACnB;","names":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/markdown/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACX,0BAA0B,EAC1B,4BAA4B,GAC5B,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
// src/markdown/markdown-viewer.tsx
|
|
2
|
+
import {
|
|
3
|
+
forwardRef,
|
|
4
|
+
useCallback,
|
|
5
|
+
useEffect,
|
|
6
|
+
useImperativeHandle,
|
|
7
|
+
useRef,
|
|
8
|
+
useState
|
|
9
|
+
} from "react";
|
|
10
|
+
import Markdown from "react-markdown";
|
|
11
|
+
import { jsx } from "react/jsx-runtime";
|
|
12
|
+
var MarkdownViewerComponent = forwardRef(function MarkdownViewerComponent2(props, ref) {
|
|
13
|
+
const { url, initialPosition, onPositionChange } = props;
|
|
14
|
+
const containerRef = useRef(null);
|
|
15
|
+
const hasAppliedInitialPosition = useRef(false);
|
|
16
|
+
const [content, setContent] = useState(null);
|
|
17
|
+
const [error, setError] = useState(null);
|
|
18
|
+
useImperativeHandle(
|
|
19
|
+
ref,
|
|
20
|
+
() => ({
|
|
21
|
+
jump: (position) => {
|
|
22
|
+
if (containerRef.current) {
|
|
23
|
+
containerRef.current.scrollTop = position;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}),
|
|
27
|
+
[]
|
|
28
|
+
);
|
|
29
|
+
useEffect(() => {
|
|
30
|
+
let cancelled = false;
|
|
31
|
+
setContent(null);
|
|
32
|
+
setError(null);
|
|
33
|
+
hasAppliedInitialPosition.current = false;
|
|
34
|
+
fetch(url).then((res) => {
|
|
35
|
+
if (!res.ok) throw new Error(`Failed to fetch: ${res.status}`);
|
|
36
|
+
return res.text();
|
|
37
|
+
}).then((text) => {
|
|
38
|
+
if (!cancelled) setContent(text);
|
|
39
|
+
}).catch((err) => {
|
|
40
|
+
if (!cancelled) setError(err.message);
|
|
41
|
+
});
|
|
42
|
+
return () => {
|
|
43
|
+
cancelled = true;
|
|
44
|
+
};
|
|
45
|
+
}, [url]);
|
|
46
|
+
useEffect(() => {
|
|
47
|
+
if (!hasAppliedInitialPosition.current && initialPosition !== void 0 && content !== null && containerRef.current) {
|
|
48
|
+
hasAppliedInitialPosition.current = true;
|
|
49
|
+
containerRef.current.scrollTop = initialPosition;
|
|
50
|
+
}
|
|
51
|
+
}, [initialPosition, content]);
|
|
52
|
+
const handleScroll = useCallback(() => {
|
|
53
|
+
if (containerRef.current) {
|
|
54
|
+
onPositionChange?.(containerRef.current.scrollTop);
|
|
55
|
+
}
|
|
56
|
+
}, [onPositionChange]);
|
|
57
|
+
if (error) {
|
|
58
|
+
return /* @__PURE__ */ jsx("div", { className: "hj-markdown hj-markdown--error", children: error });
|
|
59
|
+
}
|
|
60
|
+
if (content === null) {
|
|
61
|
+
return /* @__PURE__ */ jsx("div", { className: "hj-markdown hj-markdown--loading", children: "Loading\u2026" });
|
|
62
|
+
}
|
|
63
|
+
return /* @__PURE__ */ jsx("div", { className: "hj-markdown", ref: containerRef, onScroll: handleScroll, children: /* @__PURE__ */ jsx(Markdown, { children: content }) });
|
|
64
|
+
});
|
|
65
|
+
var MarkdownRenderer = {
|
|
66
|
+
type: "markdown",
|
|
67
|
+
extensions: ["md", "markdown"],
|
|
68
|
+
Component: MarkdownViewerComponent
|
|
69
|
+
};
|
|
70
|
+
export {
|
|
71
|
+
MarkdownRenderer
|
|
72
|
+
};
|
|
73
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/markdown/markdown-viewer.tsx"],"sourcesContent":["import {\n\tforwardRef,\n\tuseCallback,\n\tuseEffect,\n\tuseImperativeHandle,\n\tuseRef,\n\tuseState,\n} from \"react\";\nimport Markdown from \"react-markdown\";\nimport type { FileRenderer, HyperJumpAPI, RendererProps } from \"../lib/types\";\nimport \"./markdown-viewer.css\";\n\nexport type HyperJumpMarkdownViewerAPI = HyperJumpAPI;\n\nexport interface HyperJumpMarkdownViewerProps extends RendererProps {}\n\nconst MarkdownViewerComponent = forwardRef<\n\tHyperJumpMarkdownViewerAPI,\n\tHyperJumpMarkdownViewerProps\n>(function MarkdownViewerComponent(props, ref) {\n\tconst { url, initialPosition, onPositionChange } = props;\n\tconst containerRef = useRef<HTMLDivElement>(null);\n\tconst hasAppliedInitialPosition = useRef(false);\n\tconst [content, setContent] = useState<string | null>(null);\n\tconst [error, setError] = useState<string | null>(null);\n\n\tuseImperativeHandle(\n\t\tref,\n\t\t() => ({\n\t\t\tjump: (position: number) => {\n\t\t\t\tif (containerRef.current) {\n\t\t\t\t\tcontainerRef.current.scrollTop = position;\n\t\t\t\t}\n\t\t\t},\n\t\t}),\n\t\t[],\n\t);\n\n\tuseEffect(() => {\n\t\tlet cancelled = false;\n\t\tsetContent(null);\n\t\tsetError(null);\n\t\thasAppliedInitialPosition.current = false;\n\n\t\tfetch(url)\n\t\t\t.then((res) => {\n\t\t\t\tif (!res.ok) throw new Error(`Failed to fetch: ${res.status}`);\n\t\t\t\treturn res.text();\n\t\t\t})\n\t\t\t.then((text) => {\n\t\t\t\tif (!cancelled) setContent(text);\n\t\t\t})\n\t\t\t.catch((err) => {\n\t\t\t\tif (!cancelled) setError(err.message);\n\t\t\t});\n\n\t\treturn () => {\n\t\t\tcancelled = true;\n\t\t};\n\t}, [url]);\n\n\tuseEffect(() => {\n\t\tif (\n\t\t\t!hasAppliedInitialPosition.current &&\n\t\t\tinitialPosition !== undefined &&\n\t\t\tcontent !== null &&\n\t\t\tcontainerRef.current\n\t\t) {\n\t\t\thasAppliedInitialPosition.current = true;\n\t\t\tcontainerRef.current.scrollTop = initialPosition;\n\t\t}\n\t}, [initialPosition, content]);\n\n\tconst handleScroll = useCallback(() => {\n\t\tif (containerRef.current) {\n\t\t\tonPositionChange?.(containerRef.current.scrollTop);\n\t\t}\n\t}, [onPositionChange]);\n\n\tif (error) {\n\t\treturn <div className=\"hj-markdown hj-markdown--error\">{error}</div>;\n\t}\n\n\tif (content === null) {\n\t\treturn <div className=\"hj-markdown hj-markdown--loading\">Loading…</div>;\n\t}\n\n\treturn (\n\t\t<div className=\"hj-markdown\" ref={containerRef} onScroll={handleScroll}>\n\t\t\t<Markdown>{content}</Markdown>\n\t\t</div>\n\t);\n});\n\nexport const MarkdownRenderer: FileRenderer = {\n\ttype: \"markdown\",\n\textensions: [\"md\", \"markdown\"],\n\tComponent: MarkdownViewerComponent as React.ComponentType<\n\t\tRendererProps & Record<string, unknown>\n\t>,\n};\n"],"mappings":";AAAA;AAAA,EACC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACM;AACP,OAAO,cAAc;AAwEZ;AAhET,IAAM,0BAA0B,WAG9B,SAASA,yBAAwB,OAAO,KAAK;AAC9C,QAAM,EAAE,KAAK,iBAAiB,iBAAiB,IAAI;AACnD,QAAM,eAAe,OAAuB,IAAI;AAChD,QAAM,4BAA4B,OAAO,KAAK;AAC9C,QAAM,CAAC,SAAS,UAAU,IAAI,SAAwB,IAAI;AAC1D,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAwB,IAAI;AAEtD;AAAA,IACC;AAAA,IACA,OAAO;AAAA,MACN,MAAM,CAAC,aAAqB;AAC3B,YAAI,aAAa,SAAS;AACzB,uBAAa,QAAQ,YAAY;AAAA,QAClC;AAAA,MACD;AAAA,IACD;AAAA,IACA,CAAC;AAAA,EACF;AAEA,YAAU,MAAM;AACf,QAAI,YAAY;AAChB,eAAW,IAAI;AACf,aAAS,IAAI;AACb,8BAA0B,UAAU;AAEpC,UAAM,GAAG,EACP,KAAK,CAAC,QAAQ;AACd,UAAI,CAAC,IAAI,GAAI,OAAM,IAAI,MAAM,oBAAoB,IAAI,MAAM,EAAE;AAC7D,aAAO,IAAI,KAAK;AAAA,IACjB,CAAC,EACA,KAAK,CAAC,SAAS;AACf,UAAI,CAAC,UAAW,YAAW,IAAI;AAAA,IAChC,CAAC,EACA,MAAM,CAAC,QAAQ;AACf,UAAI,CAAC,UAAW,UAAS,IAAI,OAAO;AAAA,IACrC,CAAC;AAEF,WAAO,MAAM;AACZ,kBAAY;AAAA,IACb;AAAA,EACD,GAAG,CAAC,GAAG,CAAC;AAER,YAAU,MAAM;AACf,QACC,CAAC,0BAA0B,WAC3B,oBAAoB,UACpB,YAAY,QACZ,aAAa,SACZ;AACD,gCAA0B,UAAU;AACpC,mBAAa,QAAQ,YAAY;AAAA,IAClC;AAAA,EACD,GAAG,CAAC,iBAAiB,OAAO,CAAC;AAE7B,QAAM,eAAe,YAAY,MAAM;AACtC,QAAI,aAAa,SAAS;AACzB,yBAAmB,aAAa,QAAQ,SAAS;AAAA,IAClD;AAAA,EACD,GAAG,CAAC,gBAAgB,CAAC;AAErB,MAAI,OAAO;AACV,WAAO,oBAAC,SAAI,WAAU,kCAAkC,iBAAM;AAAA,EAC/D;AAEA,MAAI,YAAY,MAAM;AACrB,WAAO,oBAAC,SAAI,WAAU,oCAAmC,2BAAQ;AAAA,EAClE;AAEA,SACC,oBAAC,SAAI,WAAU,eAAc,KAAK,cAAc,UAAU,cACzD,8BAAC,YAAU,mBAAQ,GACpB;AAEF,CAAC;AAEM,IAAM,mBAAiC;AAAA,EAC7C,MAAM;AAAA,EACN,YAAY,CAAC,MAAM,UAAU;AAAA,EAC7B,WAAW;AAGZ;","names":["MarkdownViewerComponent"]}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { FileRenderer, HyperJumpAPI, RendererProps } from "../lib/types";
|
|
2
|
+
import "./markdown-viewer.css";
|
|
3
|
+
export type HyperJumpMarkdownViewerAPI = HyperJumpAPI;
|
|
4
|
+
export interface HyperJumpMarkdownViewerProps extends RendererProps {
|
|
5
|
+
}
|
|
6
|
+
export declare const MarkdownRenderer: FileRenderer;
|
|
7
|
+
//# sourceMappingURL=markdown-viewer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"markdown-viewer.d.ts","sourceRoot":"","sources":["../../src/markdown/markdown-viewer.tsx"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC9E,OAAO,uBAAuB,CAAC;AAE/B,MAAM,MAAM,0BAA0B,GAAG,YAAY,CAAC;AAEtD,MAAM,WAAW,4BAA6B,SAAQ,aAAa;CAAG;AAgFtE,eAAO,MAAM,gBAAgB,EAAE,YAM9B,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hypercard-ai/hyper-jump",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "Document viewer built for RAG",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "HyperCard AI",
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
"url": "https://github.com/hypercard-ai/hyper-jump/issues"
|
|
14
14
|
},
|
|
15
15
|
"keywords": [
|
|
16
|
+
"markdown",
|
|
16
17
|
"pdf",
|
|
17
18
|
"video",
|
|
18
19
|
"viewer",
|
|
@@ -38,7 +39,12 @@
|
|
|
38
39
|
"types": "./dist/video/index.d.ts",
|
|
39
40
|
"default": "./dist/video/index.js"
|
|
40
41
|
},
|
|
41
|
-
"./video/styles.css": "./dist/video/index.css"
|
|
42
|
+
"./video/styles.css": "./dist/video/index.css",
|
|
43
|
+
"./markdown": {
|
|
44
|
+
"types": "./dist/markdown/index.d.ts",
|
|
45
|
+
"default": "./dist/markdown/index.js"
|
|
46
|
+
},
|
|
47
|
+
"./markdown/styles.css": "./dist/markdown/index.css"
|
|
42
48
|
},
|
|
43
49
|
"files": [
|
|
44
50
|
"dist",
|
|
@@ -67,12 +73,16 @@
|
|
|
67
73
|
"react": ">=19.0.0",
|
|
68
74
|
"react-dom": ">=19.0.0",
|
|
69
75
|
"react-pdf": ">=10.0.0",
|
|
76
|
+
"react-markdown": ">=9.0.0",
|
|
70
77
|
"react-window": ">=2.0.0"
|
|
71
78
|
},
|
|
72
79
|
"peerDependenciesMeta": {
|
|
73
80
|
"react-pdf": {
|
|
74
81
|
"optional": true
|
|
75
82
|
},
|
|
83
|
+
"react-markdown": {
|
|
84
|
+
"optional": true
|
|
85
|
+
},
|
|
76
86
|
"react-window": {
|
|
77
87
|
"optional": true
|
|
78
88
|
}
|
|
@@ -88,6 +98,7 @@
|
|
|
88
98
|
"jsdom": "^28.0.0",
|
|
89
99
|
"react": "^19.2.4",
|
|
90
100
|
"react-dom": "^19.2.4",
|
|
101
|
+
"react-markdown": "^9.0.0",
|
|
91
102
|
"react-pdf": "10.3.0",
|
|
92
103
|
"react-window": "^2.2.7",
|
|
93
104
|
"storybook": "^10.2.8",
|