@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 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,3 @@
1
+ export type { HyperJumpMarkdownViewerAPI, HyperJumpMarkdownViewerProps, } from "./markdown-viewer";
2
+ export { MarkdownRenderer } from "./markdown-viewer";
3
+ //# sourceMappingURL=index.d.ts.map
@@ -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.2",
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",