@draftbase/renderer 0.1.1 → 0.1.2
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 +34 -3
- package/dist/MDXContent.js +2 -1
- package/dist/MDXErrorBoundary.d.ts +17 -0
- package/dist/MDXErrorBoundary.js +18 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/styles.css +6 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
**Framework-agnostic MDX renderer for [Draftbase](https://draftbase.co)** — the MDX-based headless CMS for React developers.
|
|
6
6
|
|
|
7
7
|
[](https://www.npmjs.com/package/@draftbase/renderer)
|
|
8
|
-
[](https://github.com/draftbase-co/renderer)
|
|
9
9
|
|
|
10
10
|
</div>
|
|
11
11
|
|
|
@@ -72,6 +72,16 @@ function Entry({ source }: { source: string }) {
|
|
|
72
72
|
}
|
|
73
73
|
```
|
|
74
74
|
|
|
75
|
+
`compiled.ok` only catches MDX _syntax_ errors. If the source references a JSX component you didn't pass in `components` (e.g. `<Callout>` without a `Callout` implementation), React throws while rendering `<Content>` — wrap it in the exported `MDXErrorBoundary` (React only, not React Native's non-DOM tree unless you supply an `errorTag`-equivalent fallback) to log it to the console and fail soft instead of crashing the page. `MDXContent` (the Next.js RSC helper above) already does this for you automatically.
|
|
76
|
+
|
|
77
|
+
```tsx
|
|
78
|
+
import { MDXErrorBoundary } from "@draftbase/renderer";
|
|
79
|
+
|
|
80
|
+
<MDXErrorBoundary fallback={<Text>{source}</Text>}>
|
|
81
|
+
<Content components={{ p: Text, h1: Text /* ... */ }} />
|
|
82
|
+
</MDXErrorBoundary>;
|
|
83
|
+
```
|
|
84
|
+
|
|
75
85
|
Extended markdown (tables, strikethrough, task lists, autolinks) is supported out of the box via `remark-gfm`.
|
|
76
86
|
|
|
77
87
|
## Astro
|
|
@@ -192,6 +202,27 @@ import { Callout, ImageBlock } from "@/components/content";
|
|
|
192
202
|
|
|
193
203
|
Any standard markdown element (`h1`, `table`, `a`, ...) can also be overridden the same way, by key — **required** on non-DOM renderers like React Native, which have no intrinsic `div`/`p`/`a`/`img` tags.
|
|
194
204
|
|
|
205
|
+
### Entry links
|
|
206
|
+
|
|
207
|
+
The Draftbase editor can insert `<EntryLink id="...">Link text</EntryLink>` into rich text to link to another entry. It's a plain JSX component like any other — no special renderer support for the tag itself — so you must supply an `EntryLink` implementation the same way as `Callout`/`ImageBlock`. If `EntryLink` isn't supplied and the source contains one, rendering throws (same as any missing custom component).
|
|
208
|
+
|
|
209
|
+
To route `id` correctly per content type, fetch the entry with `include=1` (via `@draftbase/sdk`) — the response includes an `entryLinks` map keyed by every `EntryLink` id found in that entry's richText fields, each with its `templateId`:
|
|
210
|
+
|
|
211
|
+
```tsx
|
|
212
|
+
const entry = await client.entries.get(entryId, undefined, 1);
|
|
213
|
+
// entry.entryLinks = { "64f1a2b3c4d5e6f7a8b9c0d1": { id, templateId, title, status } }
|
|
214
|
+
|
|
215
|
+
const ROUTE_BY_TEMPLATE: Record<string, string> = { blogPost: "/blog", product: "/products" };
|
|
216
|
+
|
|
217
|
+
function EntryLink({ id, children }: { id: string; children: React.ReactNode }) {
|
|
218
|
+
const link = entry.entryLinks?.[id];
|
|
219
|
+
const base = ROUTE_BY_TEMPLATE[link?.templateId ?? ""] ?? "/entries";
|
|
220
|
+
return <a href={`${base}/${id}`}>{children}</a>;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
<MDXContent source={entry.fields.body} components={{ EntryLink }} />;
|
|
224
|
+
```
|
|
225
|
+
|
|
195
226
|
## Styling
|
|
196
227
|
|
|
197
228
|
`@draftbase/renderer/styles.css` wraps output in a `.db-content` class with slim, sensible defaults (typography, tables, code blocks). Web-only, opt-in:
|
|
@@ -234,8 +265,8 @@ React (Next.js App Router/RSC, plain client React, React Native, Remix, Astro is
|
|
|
234
265
|
## Links
|
|
235
266
|
|
|
236
267
|
- [npm](https://www.npmjs.com/package/@draftbase/renderer)
|
|
237
|
-
- [Source
|
|
238
|
-
- [Issues](https://github.com/draftbase-co/
|
|
268
|
+
- [Source](https://github.com/draftbase-co/renderer)
|
|
269
|
+
- [Issues](https://github.com/draftbase-co/renderer/issues)
|
|
239
270
|
- [`@draftbase/sdk`](https://www.npmjs.com/package/@draftbase/sdk) — fetches the content this package renders
|
|
240
271
|
- [draftbase.co](https://draftbase.co) — product site
|
|
241
272
|
- [Framework support](https://draftbase.co/frameworks) — per-framework rendering guide this README is based on
|
package/dist/MDXContent.js
CHANGED
|
@@ -2,6 +2,7 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
2
2
|
import * as runtime from "react/jsx-runtime";
|
|
3
3
|
import { compileMDXCore } from "./core.js";
|
|
4
4
|
import { wrapperClassName } from "./wrapperClassName.js";
|
|
5
|
+
import { MDXErrorBoundary } from "./MDXErrorBoundary.js";
|
|
5
6
|
/**
|
|
6
7
|
* Compiles raw MDX/markdown into a renderable React component — no DOM assumptions,
|
|
7
8
|
* safe to call from a React Native loader, a client-side effect, or a Next.js Server
|
|
@@ -27,5 +28,5 @@ export async function MDXContent({ source, components, unstyled, className, wrap
|
|
|
27
28
|
return (_jsx(Wrapper, { className: wrapperClass, children: _jsx(ErrorTag, { children: source }) }));
|
|
28
29
|
}
|
|
29
30
|
const { Content } = compiled;
|
|
30
|
-
return (_jsx(Wrapper, { className: wrapperClass, children: _jsx(Content, { components: components }) }));
|
|
31
|
+
return (_jsx(Wrapper, { className: wrapperClass, children: _jsx(MDXErrorBoundary, { fallback: _jsx(ErrorTag, { children: source }), children: _jsx(Content, { components: components }) }) }));
|
|
31
32
|
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Component, type ReactNode } from "react";
|
|
2
|
+
interface MDXErrorBoundaryProps {
|
|
3
|
+
children: ReactNode;
|
|
4
|
+
fallback: ReactNode;
|
|
5
|
+
}
|
|
6
|
+
interface MDXErrorBoundaryState {
|
|
7
|
+
hasError: boolean;
|
|
8
|
+
}
|
|
9
|
+
export declare class MDXErrorBoundary extends Component<MDXErrorBoundaryProps, MDXErrorBoundaryState> {
|
|
10
|
+
state: MDXErrorBoundaryState;
|
|
11
|
+
static getDerivedStateFromError(): {
|
|
12
|
+
hasError: boolean;
|
|
13
|
+
};
|
|
14
|
+
componentDidCatch(error: unknown): void;
|
|
15
|
+
render(): ReactNode;
|
|
16
|
+
}
|
|
17
|
+
export {};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { Component } from "react";
|
|
3
|
+
// Catches render-time errors from compiled MDX content — most commonly a JSX component
|
|
4
|
+
// referenced in the source (e.g. `<Callout>`, `<EntryLink>`) that wasn't supplied in
|
|
5
|
+
// `components`. Without this, that throws "Element type is invalid" and crashes the whole
|
|
6
|
+
// page instead of just the content block.
|
|
7
|
+
export class MDXErrorBoundary extends Component {
|
|
8
|
+
state = { hasError: false };
|
|
9
|
+
static getDerivedStateFromError() {
|
|
10
|
+
return { hasError: true };
|
|
11
|
+
}
|
|
12
|
+
componentDidCatch(error) {
|
|
13
|
+
console.error("MDX content failed to render", error);
|
|
14
|
+
}
|
|
15
|
+
render() {
|
|
16
|
+
return this.state.hasError ? this.props.fallback : this.props.children;
|
|
17
|
+
}
|
|
18
|
+
}
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
package/dist/styles.css
CHANGED
|
@@ -25,6 +25,12 @@
|
|
|
25
25
|
line-height: 1.25;
|
|
26
26
|
margin: 1.5em 0 0.5em;
|
|
27
27
|
color: inherit;
|
|
28
|
+
scroll-margin-top: 96px;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/* Highlights a footnote/citation anchor when the URL hash lands on it, e.g. #fn-1. */
|
|
32
|
+
.db-content :target {
|
|
33
|
+
background: var(--accent-subtle, rgba(127, 127, 127, 0.15));
|
|
28
34
|
}
|
|
29
35
|
|
|
30
36
|
.db-content h1 {
|