@willwang-io/react-djot 0.1.1
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 +140 -0
- package/dist/index.cjs +371 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +127 -0
- package/dist/index.d.ts +127 -0
- package/dist/index.js +365 -0
- package/dist/index.js.map +1 -0
- package/package.json +58 -0
package/README.md
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
# react-djot
|
|
2
|
+
|
|
3
|
+
`react-djot` renders [Djot](https://djot.net/) into React elements with a
|
|
4
|
+
`react-markdown`-style API.
|
|
5
|
+
|
|
6
|
+
The design goal is familiarity: if you know `react-markdown`, you should feel
|
|
7
|
+
at home with `react-djot`.
|
|
8
|
+
|
|
9
|
+
## Features
|
|
10
|
+
|
|
11
|
+
- React 18+ support
|
|
12
|
+
- `components` override map for per-node rendering control
|
|
13
|
+
- No `dangerouslySetInnerHTML`
|
|
14
|
+
- React Server Component friendly main path (no hooks)
|
|
15
|
+
- TypeScript-first API
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm install react-djot
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Peer dependencies:
|
|
24
|
+
|
|
25
|
+
- `react`
|
|
26
|
+
- `react-dom`
|
|
27
|
+
- `@djot/djot`
|
|
28
|
+
|
|
29
|
+
## Quick Start
|
|
30
|
+
|
|
31
|
+
```tsx
|
|
32
|
+
import { Djot } from "react-djot";
|
|
33
|
+
|
|
34
|
+
export function Example() {
|
|
35
|
+
return <Djot>{"# Hello\n\nThis is *Djot*."}</Djot>;
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## API
|
|
40
|
+
|
|
41
|
+
### `<Djot />`
|
|
42
|
+
|
|
43
|
+
```tsx
|
|
44
|
+
import { Djot } from "react-djot";
|
|
45
|
+
|
|
46
|
+
<Djot
|
|
47
|
+
children={"# Title"}
|
|
48
|
+
components={
|
|
49
|
+
{
|
|
50
|
+
/* overrides */
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
/>;
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Props:
|
|
57
|
+
|
|
58
|
+
- `children?: string | null | undefined`
|
|
59
|
+
- Djot source text to parse and render.
|
|
60
|
+
- `components?: DjotComponents`
|
|
61
|
+
- Optional map of node-tag keys to React components.
|
|
62
|
+
|
|
63
|
+
### `components` overrides
|
|
64
|
+
|
|
65
|
+
The override pattern mirrors `react-markdown`: provide a component per node
|
|
66
|
+
type key.
|
|
67
|
+
|
|
68
|
+
```tsx
|
|
69
|
+
import { Djot } from "react-djot";
|
|
70
|
+
import type { DjotComponents } from "react-djot";
|
|
71
|
+
|
|
72
|
+
const components: DjotComponents = {
|
|
73
|
+
para: ({ node, children, ...props }) => (
|
|
74
|
+
<p className="lead" {...props}>
|
|
75
|
+
{children}
|
|
76
|
+
</p>
|
|
77
|
+
),
|
|
78
|
+
heading: ({ level, node, children, ...props }) => {
|
|
79
|
+
const Tag = `h${Math.min(Math.max(level, 1), 6)}` as const;
|
|
80
|
+
return (
|
|
81
|
+
<Tag {...props} data-level={level}>
|
|
82
|
+
{children}
|
|
83
|
+
</Tag>
|
|
84
|
+
);
|
|
85
|
+
},
|
|
86
|
+
link: ({ node, href, children, ...props }) => (
|
|
87
|
+
<a {...props} href={href} rel="noreferrer" target="_blank">
|
|
88
|
+
{children}
|
|
89
|
+
</a>
|
|
90
|
+
)
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
export function Example() {
|
|
94
|
+
return <Djot components={components}>{"## Custom\n\n[Go](https://example.com)"}</Djot>;
|
|
95
|
+
}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### Supported node keys (current core set)
|
|
99
|
+
|
|
100
|
+
- `doc`
|
|
101
|
+
- `para`
|
|
102
|
+
- `heading`
|
|
103
|
+
- `emph`
|
|
104
|
+
- `strong`
|
|
105
|
+
- `code`
|
|
106
|
+
- `code_block`
|
|
107
|
+
- `link`
|
|
108
|
+
- `image`
|
|
109
|
+
- `bullet_list`
|
|
110
|
+
- `ordered_list`
|
|
111
|
+
- `list_item`
|
|
112
|
+
- `blockquote`
|
|
113
|
+
- `thematic_break`
|
|
114
|
+
- `str`
|
|
115
|
+
- `soft_break` and `softbreak`
|
|
116
|
+
- `hard_break` and `hardbreak`
|
|
117
|
+
|
|
118
|
+
## Rendering Guarantees
|
|
119
|
+
|
|
120
|
+
- Parses Djot via `@djot/djot` `parse()`
|
|
121
|
+
- Walks the AST recursively and creates React elements directly
|
|
122
|
+
- Does not use `dangerouslySetInnerHTML`
|
|
123
|
+
|
|
124
|
+
## React Server Components
|
|
125
|
+
|
|
126
|
+
`<Djot />` has no hooks in the main render path, so it can be used in Server
|
|
127
|
+
Components.
|
|
128
|
+
|
|
129
|
+
## Development
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
npm run build
|
|
133
|
+
npm run typecheck
|
|
134
|
+
npm run lint
|
|
135
|
+
npm test
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
## License
|
|
139
|
+
|
|
140
|
+
MIT
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,371 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
var djot = require('@djot/djot');
|
|
6
|
+
var react = require('react');
|
|
7
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
8
|
+
|
|
9
|
+
// src/Djot.tsx
|
|
10
|
+
function isParentNode(node) {
|
|
11
|
+
return Array.isArray(node.children);
|
|
12
|
+
}
|
|
13
|
+
function isSoftBreakNode(node) {
|
|
14
|
+
return node.tag === "soft_break" || node.tag === "softbreak";
|
|
15
|
+
}
|
|
16
|
+
function isHardBreakNode(node) {
|
|
17
|
+
return node.tag === "hard_break" || node.tag === "hardbreak";
|
|
18
|
+
}
|
|
19
|
+
function pickComponent(components, primary, alias) {
|
|
20
|
+
if (!components) {
|
|
21
|
+
return void 0;
|
|
22
|
+
}
|
|
23
|
+
return components[primary] ?? (alias ? components[alias] : void 0);
|
|
24
|
+
}
|
|
25
|
+
function renderChildren(children, components) {
|
|
26
|
+
return children.map(
|
|
27
|
+
(child, index) => renderNode(child, {
|
|
28
|
+
components,
|
|
29
|
+
key: index
|
|
30
|
+
})
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
function toAltText(nodes) {
|
|
34
|
+
let output = "";
|
|
35
|
+
for (const node of nodes) {
|
|
36
|
+
switch (node.tag) {
|
|
37
|
+
case "str":
|
|
38
|
+
case "code":
|
|
39
|
+
case "code_block":
|
|
40
|
+
output += node.text;
|
|
41
|
+
break;
|
|
42
|
+
case "soft_break":
|
|
43
|
+
case "softbreak":
|
|
44
|
+
output += " ";
|
|
45
|
+
break;
|
|
46
|
+
case "hard_break":
|
|
47
|
+
case "hardbreak":
|
|
48
|
+
output += "\n";
|
|
49
|
+
break;
|
|
50
|
+
default:
|
|
51
|
+
if (isParentNode(node)) {
|
|
52
|
+
output += toAltText(node.children);
|
|
53
|
+
}
|
|
54
|
+
break;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return output.trim();
|
|
58
|
+
}
|
|
59
|
+
function clampHeadingLevel(level) {
|
|
60
|
+
if (level <= 1) {
|
|
61
|
+
return 1;
|
|
62
|
+
}
|
|
63
|
+
if (level >= 6) {
|
|
64
|
+
return 6;
|
|
65
|
+
}
|
|
66
|
+
return level;
|
|
67
|
+
}
|
|
68
|
+
function withKey(props, key) {
|
|
69
|
+
if (key === void 0) {
|
|
70
|
+
return props;
|
|
71
|
+
}
|
|
72
|
+
return {
|
|
73
|
+
...props,
|
|
74
|
+
key
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
function renderWithOverride(override, fallback, domProps, customProps, key, children) {
|
|
78
|
+
const Component = override ?? fallback;
|
|
79
|
+
const props = typeof Component === "string" ? withKey(domProps, key) : withKey(
|
|
80
|
+
{
|
|
81
|
+
...domProps,
|
|
82
|
+
...customProps
|
|
83
|
+
},
|
|
84
|
+
key
|
|
85
|
+
);
|
|
86
|
+
return react.createElement(Component, props, children);
|
|
87
|
+
}
|
|
88
|
+
function renderDoc(node, components, key) {
|
|
89
|
+
const children = renderChildren(node.children, components);
|
|
90
|
+
const Component = pickComponent(components, "doc");
|
|
91
|
+
if (Component) {
|
|
92
|
+
if (typeof Component === "string") {
|
|
93
|
+
return react.createElement(Component, withKey({}, key), children);
|
|
94
|
+
}
|
|
95
|
+
return react.createElement(Component, withKey({ node }, key), children);
|
|
96
|
+
}
|
|
97
|
+
return react.createElement(react.Fragment, withKey({}, key), children);
|
|
98
|
+
}
|
|
99
|
+
function renderHeading(node, components, key) {
|
|
100
|
+
const level = clampHeadingLevel(node.level);
|
|
101
|
+
const children = renderChildren(node.children, components);
|
|
102
|
+
return renderWithOverride(
|
|
103
|
+
pickComponent(components, "heading"),
|
|
104
|
+
`h${level}`,
|
|
105
|
+
{},
|
|
106
|
+
{
|
|
107
|
+
level,
|
|
108
|
+
node
|
|
109
|
+
},
|
|
110
|
+
key,
|
|
111
|
+
children
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
function renderCode(node, components, key) {
|
|
115
|
+
const value = node.text;
|
|
116
|
+
return renderWithOverride(
|
|
117
|
+
pickComponent(components, "code"),
|
|
118
|
+
"code",
|
|
119
|
+
{},
|
|
120
|
+
{
|
|
121
|
+
node,
|
|
122
|
+
value
|
|
123
|
+
},
|
|
124
|
+
key,
|
|
125
|
+
value
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
function renderCodeBlock(node, components, key) {
|
|
129
|
+
const value = node.text;
|
|
130
|
+
const language = node.lang;
|
|
131
|
+
const fallbackChildren = react.createElement(
|
|
132
|
+
"code",
|
|
133
|
+
{
|
|
134
|
+
className: language ? `language-${language}` : void 0
|
|
135
|
+
},
|
|
136
|
+
value
|
|
137
|
+
);
|
|
138
|
+
return renderWithOverride(
|
|
139
|
+
pickComponent(components, "code_block"),
|
|
140
|
+
"pre",
|
|
141
|
+
{},
|
|
142
|
+
{
|
|
143
|
+
language,
|
|
144
|
+
node,
|
|
145
|
+
value
|
|
146
|
+
},
|
|
147
|
+
key,
|
|
148
|
+
fallbackChildren
|
|
149
|
+
);
|
|
150
|
+
}
|
|
151
|
+
function renderLink(node, components, key) {
|
|
152
|
+
const children = renderChildren(node.children, components);
|
|
153
|
+
const href = node.destination;
|
|
154
|
+
return renderWithOverride(
|
|
155
|
+
pickComponent(components, "link"),
|
|
156
|
+
"a",
|
|
157
|
+
{
|
|
158
|
+
href
|
|
159
|
+
},
|
|
160
|
+
{
|
|
161
|
+
node
|
|
162
|
+
},
|
|
163
|
+
key,
|
|
164
|
+
children
|
|
165
|
+
);
|
|
166
|
+
}
|
|
167
|
+
function renderImage(node, components, key) {
|
|
168
|
+
const alt = toAltText(node.children) || void 0;
|
|
169
|
+
const src = node.destination;
|
|
170
|
+
return renderWithOverride(
|
|
171
|
+
pickComponent(components, "image"),
|
|
172
|
+
"img",
|
|
173
|
+
{
|
|
174
|
+
alt,
|
|
175
|
+
src
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
alt,
|
|
179
|
+
node
|
|
180
|
+
},
|
|
181
|
+
key
|
|
182
|
+
);
|
|
183
|
+
}
|
|
184
|
+
function renderOrderedList(node, components, key) {
|
|
185
|
+
const children = renderChildren(node.children, components);
|
|
186
|
+
return renderWithOverride(
|
|
187
|
+
pickComponent(components, "ordered_list"),
|
|
188
|
+
"ol",
|
|
189
|
+
{
|
|
190
|
+
start: node.start
|
|
191
|
+
},
|
|
192
|
+
{
|
|
193
|
+
node,
|
|
194
|
+
start: node.start
|
|
195
|
+
},
|
|
196
|
+
key,
|
|
197
|
+
children
|
|
198
|
+
);
|
|
199
|
+
}
|
|
200
|
+
function renderStr(node, components, key) {
|
|
201
|
+
const value = node.text;
|
|
202
|
+
const Component = pickComponent(components, "str");
|
|
203
|
+
if (!Component) {
|
|
204
|
+
return value;
|
|
205
|
+
}
|
|
206
|
+
if (typeof Component === "string") {
|
|
207
|
+
return react.createElement(Component, withKey({}, key), value);
|
|
208
|
+
}
|
|
209
|
+
return react.createElement(
|
|
210
|
+
Component,
|
|
211
|
+
withKey(
|
|
212
|
+
{
|
|
213
|
+
node,
|
|
214
|
+
value
|
|
215
|
+
},
|
|
216
|
+
key
|
|
217
|
+
),
|
|
218
|
+
value
|
|
219
|
+
);
|
|
220
|
+
}
|
|
221
|
+
function renderSoftBreak(node, components, key) {
|
|
222
|
+
const Component = pickComponent(components, "soft_break", "softbreak");
|
|
223
|
+
if (!Component) {
|
|
224
|
+
return "\n";
|
|
225
|
+
}
|
|
226
|
+
if (typeof Component === "string") {
|
|
227
|
+
return react.createElement(Component, withKey({}, key), "\n");
|
|
228
|
+
}
|
|
229
|
+
return react.createElement(
|
|
230
|
+
Component,
|
|
231
|
+
withKey(
|
|
232
|
+
{
|
|
233
|
+
node
|
|
234
|
+
},
|
|
235
|
+
key
|
|
236
|
+
),
|
|
237
|
+
"\n"
|
|
238
|
+
);
|
|
239
|
+
}
|
|
240
|
+
function renderHardBreak(node, components, key) {
|
|
241
|
+
return renderWithOverride(
|
|
242
|
+
pickComponent(components, "hard_break", "hardbreak"),
|
|
243
|
+
"br",
|
|
244
|
+
{},
|
|
245
|
+
{
|
|
246
|
+
node
|
|
247
|
+
},
|
|
248
|
+
key
|
|
249
|
+
);
|
|
250
|
+
}
|
|
251
|
+
function renderNode(node, options = {}) {
|
|
252
|
+
const { components, key } = options;
|
|
253
|
+
const children = isParentNode(node) ? renderChildren(node.children, components) : void 0;
|
|
254
|
+
switch (node.tag) {
|
|
255
|
+
case "doc":
|
|
256
|
+
return renderDoc(node, components, key);
|
|
257
|
+
case "para":
|
|
258
|
+
return renderWithOverride(
|
|
259
|
+
pickComponent(components, "para"),
|
|
260
|
+
"p",
|
|
261
|
+
{},
|
|
262
|
+
{
|
|
263
|
+
node
|
|
264
|
+
},
|
|
265
|
+
key,
|
|
266
|
+
children
|
|
267
|
+
);
|
|
268
|
+
case "heading":
|
|
269
|
+
return renderHeading(node, components, key);
|
|
270
|
+
case "emph":
|
|
271
|
+
return renderWithOverride(
|
|
272
|
+
pickComponent(components, "emph"),
|
|
273
|
+
"em",
|
|
274
|
+
{},
|
|
275
|
+
{
|
|
276
|
+
node
|
|
277
|
+
},
|
|
278
|
+
key,
|
|
279
|
+
children
|
|
280
|
+
);
|
|
281
|
+
case "strong":
|
|
282
|
+
return renderWithOverride(
|
|
283
|
+
pickComponent(components, "strong"),
|
|
284
|
+
"strong",
|
|
285
|
+
{},
|
|
286
|
+
{
|
|
287
|
+
node
|
|
288
|
+
},
|
|
289
|
+
key,
|
|
290
|
+
children
|
|
291
|
+
);
|
|
292
|
+
case "code":
|
|
293
|
+
return renderCode(node, components, key);
|
|
294
|
+
case "code_block":
|
|
295
|
+
return renderCodeBlock(node, components, key);
|
|
296
|
+
case "link":
|
|
297
|
+
return renderLink(node, components, key);
|
|
298
|
+
case "image":
|
|
299
|
+
return renderImage(node, components, key);
|
|
300
|
+
case "bullet_list":
|
|
301
|
+
return renderWithOverride(
|
|
302
|
+
pickComponent(components, "bullet_list"),
|
|
303
|
+
"ul",
|
|
304
|
+
{},
|
|
305
|
+
{
|
|
306
|
+
node
|
|
307
|
+
},
|
|
308
|
+
key,
|
|
309
|
+
children
|
|
310
|
+
);
|
|
311
|
+
case "ordered_list":
|
|
312
|
+
return renderOrderedList(node, components, key);
|
|
313
|
+
case "list_item":
|
|
314
|
+
return renderWithOverride(
|
|
315
|
+
pickComponent(components, "list_item"),
|
|
316
|
+
"li",
|
|
317
|
+
{},
|
|
318
|
+
{
|
|
319
|
+
node
|
|
320
|
+
},
|
|
321
|
+
key,
|
|
322
|
+
children
|
|
323
|
+
);
|
|
324
|
+
case "blockquote":
|
|
325
|
+
return renderWithOverride(
|
|
326
|
+
pickComponent(components, "blockquote"),
|
|
327
|
+
"blockquote",
|
|
328
|
+
{},
|
|
329
|
+
{
|
|
330
|
+
node
|
|
331
|
+
},
|
|
332
|
+
key,
|
|
333
|
+
children
|
|
334
|
+
);
|
|
335
|
+
case "thematic_break":
|
|
336
|
+
return renderWithOverride(
|
|
337
|
+
pickComponent(components, "thematic_break"),
|
|
338
|
+
"hr",
|
|
339
|
+
{},
|
|
340
|
+
{
|
|
341
|
+
node
|
|
342
|
+
},
|
|
343
|
+
key
|
|
344
|
+
);
|
|
345
|
+
case "str":
|
|
346
|
+
return renderStr(node, components, key);
|
|
347
|
+
default:
|
|
348
|
+
if (isSoftBreakNode(node)) {
|
|
349
|
+
return renderSoftBreak(node, components, key);
|
|
350
|
+
}
|
|
351
|
+
if (isHardBreakNode(node)) {
|
|
352
|
+
return renderHardBreak(node, components, key);
|
|
353
|
+
}
|
|
354
|
+
return null;
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
function Djot({ children, components }) {
|
|
358
|
+
const source = children ?? "";
|
|
359
|
+
if (source.length === 0) {
|
|
360
|
+
return null;
|
|
361
|
+
}
|
|
362
|
+
const ast = djot.parse(source);
|
|
363
|
+
return /* @__PURE__ */ jsxRuntime.jsx(react.Fragment, { children: renderNode(ast, { components }) });
|
|
364
|
+
}
|
|
365
|
+
var Djot_default = Djot;
|
|
366
|
+
|
|
367
|
+
exports.Djot = Djot;
|
|
368
|
+
exports.default = Djot_default;
|
|
369
|
+
exports.renderNode = renderNode;
|
|
370
|
+
//# sourceMappingURL=index.cjs.map
|
|
371
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/renderNode.tsx","../src/Djot.tsx"],"names":["createElement","Fragment","parse","jsx"],"mappings":"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","file":"index.cjs","sourcesContent":["import { createElement, Fragment } from \"react\";\nimport type React from \"react\";\nimport type {\n DjotBaseNode,\n DjotCodeBlockNode,\n DjotCodeNode,\n DjotComponentPropsMap,\n DjotComponents,\n DjotDocNode,\n DjotHardBreakNode,\n DjotHeadingNode,\n DjotImageNode,\n DjotLinkNode,\n DjotNode,\n DjotOrderedListNode,\n DjotParentNode,\n DjotSoftBreakNode,\n DjotStrNode\n} from \"./types\";\n\nexport interface RenderNodeOptions {\n components?: DjotComponents | undefined;\n key?: React.Key;\n}\n\ntype ComponentKey = keyof DjotComponentPropsMap;\n\nfunction isParentNode(node: DjotBaseNode): node is DjotParentNode {\n return Array.isArray((node as DjotParentNode).children);\n}\n\nfunction isSoftBreakNode(node: DjotNode): node is DjotSoftBreakNode {\n return node.tag === \"soft_break\" || node.tag === \"softbreak\";\n}\n\nfunction isHardBreakNode(node: DjotNode): node is DjotHardBreakNode {\n return node.tag === \"hard_break\" || node.tag === \"hardbreak\";\n}\n\nfunction pickComponent(\n components: DjotComponents | undefined,\n primary: ComponentKey,\n alias?: ComponentKey\n): React.ElementType | undefined {\n if (!components) {\n return undefined;\n }\n\n return (components[primary] ?? (alias ? components[alias] : undefined)) as\n | React.ElementType\n | undefined;\n}\n\nfunction renderChildren(children: DjotNode[], components?: DjotComponents): React.ReactNode[] {\n return children.map((child, index) =>\n renderNode(child, {\n components,\n key: index\n })\n );\n}\n\nfunction toAltText(nodes: DjotNode[]): string {\n let output = \"\";\n\n for (const node of nodes) {\n switch (node.tag) {\n case \"str\":\n case \"code\":\n case \"code_block\":\n output += node.text;\n break;\n case \"soft_break\":\n case \"softbreak\":\n output += \" \";\n break;\n case \"hard_break\":\n case \"hardbreak\":\n output += \"\\n\";\n break;\n default:\n if (isParentNode(node)) {\n output += toAltText(node.children);\n }\n break;\n }\n }\n\n return output.trim();\n}\n\nfunction clampHeadingLevel(level: number): 1 | 2 | 3 | 4 | 5 | 6 {\n if (level <= 1) {\n return 1;\n }\n\n if (level >= 6) {\n return 6;\n }\n\n return level as 1 | 2 | 3 | 4 | 5 | 6;\n}\n\nfunction withKey<T extends Record<string, unknown>>(props: T, key?: React.Key): T & { key?: React.Key } {\n if (key === undefined) {\n return props;\n }\n\n return {\n ...props,\n key\n };\n}\n\nfunction renderWithOverride(\n override: React.ElementType | undefined,\n fallback: React.ElementType,\n domProps: Record<string, unknown>,\n customProps: Record<string, unknown>,\n key?: React.Key,\n children?: React.ReactNode\n): React.ReactNode {\n const Component = override ?? fallback;\n const props =\n typeof Component === \"string\"\n ? withKey(domProps, key)\n : withKey(\n {\n ...domProps,\n ...customProps\n },\n key\n );\n\n return createElement(Component, props, children);\n}\n\nfunction renderDoc(\n node: DjotDocNode,\n components: DjotComponents | undefined,\n key?: React.Key\n): React.ReactNode {\n const children = renderChildren(node.children, components);\n const Component = pickComponent(components, \"doc\");\n\n if (Component) {\n if (typeof Component === \"string\") {\n return createElement(Component, withKey({}, key), children);\n }\n\n return createElement(Component, withKey({ node }, key), children);\n }\n\n return createElement(Fragment, withKey({}, key), children);\n}\n\nfunction renderHeading(\n node: DjotHeadingNode,\n components: DjotComponents | undefined,\n key?: React.Key\n): React.ReactNode {\n const level = clampHeadingLevel(node.level);\n const children = renderChildren(node.children, components);\n return renderWithOverride(\n pickComponent(components, \"heading\"),\n `h${level}`,\n {},\n {\n level,\n node\n },\n key,\n children\n );\n}\n\nfunction renderCode(\n node: DjotCodeNode,\n components: DjotComponents | undefined,\n key?: React.Key\n): React.ReactNode {\n const value = node.text;\n return renderWithOverride(\n pickComponent(components, \"code\"),\n \"code\",\n {},\n {\n node,\n value\n },\n key,\n value\n );\n}\n\nfunction renderCodeBlock(\n node: DjotCodeBlockNode,\n components: DjotComponents | undefined,\n key?: React.Key\n): React.ReactNode {\n const value = node.text;\n const language = node.lang;\n const fallbackChildren = createElement(\n \"code\",\n {\n className: language ? `language-${language}` : undefined\n },\n value\n );\n\n return renderWithOverride(\n pickComponent(components, \"code_block\"),\n \"pre\",\n {},\n {\n language,\n node,\n value\n },\n key,\n fallbackChildren\n );\n}\n\nfunction renderLink(\n node: DjotLinkNode,\n components: DjotComponents | undefined,\n key?: React.Key\n): React.ReactNode {\n const children = renderChildren(node.children, components);\n const href = node.destination;\n return renderWithOverride(\n pickComponent(components, \"link\"),\n \"a\",\n {\n href\n },\n {\n node\n },\n key,\n children\n );\n}\n\nfunction renderImage(\n node: DjotImageNode,\n components: DjotComponents | undefined,\n key?: React.Key\n): React.ReactNode {\n const alt = toAltText(node.children) || undefined;\n const src = node.destination;\n return renderWithOverride(\n pickComponent(components, \"image\"),\n \"img\",\n {\n alt,\n src\n },\n {\n alt,\n node\n },\n key\n );\n}\n\nfunction renderOrderedList(\n node: DjotOrderedListNode,\n components: DjotComponents | undefined,\n key?: React.Key\n): React.ReactNode {\n const children = renderChildren(node.children, components);\n return renderWithOverride(\n pickComponent(components, \"ordered_list\"),\n \"ol\",\n {\n start: node.start\n },\n {\n node,\n start: node.start\n },\n key,\n children\n );\n}\n\nfunction renderStr(\n node: DjotStrNode,\n components: DjotComponents | undefined,\n key?: React.Key\n): React.ReactNode {\n const value = node.text;\n const Component = pickComponent(components, \"str\");\n\n if (!Component) {\n return value;\n }\n\n if (typeof Component === \"string\") {\n return createElement(Component, withKey({}, key), value);\n }\n\n return createElement(\n Component,\n withKey(\n {\n node,\n value\n },\n key\n ),\n value\n );\n}\n\nfunction renderSoftBreak(\n node: DjotSoftBreakNode,\n components: DjotComponents | undefined,\n key?: React.Key\n): React.ReactNode {\n const Component = pickComponent(components, \"soft_break\", \"softbreak\");\n\n if (!Component) {\n return \"\\n\";\n }\n\n if (typeof Component === \"string\") {\n return createElement(Component, withKey({}, key), \"\\n\");\n }\n\n return createElement(\n Component,\n withKey(\n {\n node\n },\n key\n ),\n \"\\n\"\n );\n}\n\nfunction renderHardBreak(\n node: DjotHardBreakNode,\n components: DjotComponents | undefined,\n key?: React.Key\n): React.ReactNode {\n return renderWithOverride(\n pickComponent(components, \"hard_break\", \"hardbreak\"),\n \"br\",\n {},\n {\n node\n },\n key\n );\n}\n\nexport function renderNode(node: DjotNode, options: RenderNodeOptions = {}): React.ReactNode {\n const { components, key } = options;\n const children = isParentNode(node) ? renderChildren(node.children, components) : undefined;\n\n switch (node.tag) {\n case \"doc\":\n return renderDoc(node, components, key);\n case \"para\":\n return renderWithOverride(\n pickComponent(components, \"para\"),\n \"p\",\n {},\n {\n node\n },\n key,\n children\n );\n case \"heading\":\n return renderHeading(node, components, key);\n case \"emph\":\n return renderWithOverride(\n pickComponent(components, \"emph\"),\n \"em\",\n {},\n {\n node\n },\n key,\n children\n );\n case \"strong\":\n return renderWithOverride(\n pickComponent(components, \"strong\"),\n \"strong\",\n {},\n {\n node\n },\n key,\n children\n );\n case \"code\":\n return renderCode(node, components, key);\n case \"code_block\":\n return renderCodeBlock(node, components, key);\n case \"link\":\n return renderLink(node, components, key);\n case \"image\":\n return renderImage(node, components, key);\n case \"bullet_list\":\n return renderWithOverride(\n pickComponent(components, \"bullet_list\"),\n \"ul\",\n {},\n {\n node\n },\n key,\n children\n );\n case \"ordered_list\":\n return renderOrderedList(node, components, key);\n case \"list_item\":\n return renderWithOverride(\n pickComponent(components, \"list_item\"),\n \"li\",\n {},\n {\n node\n },\n key,\n children\n );\n case \"blockquote\":\n return renderWithOverride(\n pickComponent(components, \"blockquote\"),\n \"blockquote\",\n {},\n {\n node\n },\n key,\n children\n );\n case \"thematic_break\":\n return renderWithOverride(\n pickComponent(components, \"thematic_break\"),\n \"hr\",\n {},\n {\n node\n },\n key\n );\n case \"str\":\n return renderStr(node, components, key);\n default:\n if (isSoftBreakNode(node)) {\n return renderSoftBreak(node, components, key);\n }\n\n if (isHardBreakNode(node)) {\n return renderHardBreak(node, components, key);\n }\n\n return null;\n }\n}\n","import { parse } from \"@djot/djot\";\nimport { Fragment } from \"react\";\nimport type React from \"react\";\nimport { renderNode } from \"./renderNode\";\nimport type { DjotNode, DjotProps } from \"./types\";\n\nexport function Djot({ children, components }: DjotProps): React.ReactElement | null {\n const source = children ?? \"\";\n\n if (source.length === 0) {\n return null;\n }\n\n const ast = parse(source) as DjotNode;\n return <Fragment>{renderNode(ast, { components })}</Fragment>;\n}\n\nexport default Djot;\n"]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
type DjotAttributes = Record<string, string>;
|
|
4
|
+
interface DjotBaseNode {
|
|
5
|
+
attributes?: DjotAttributes;
|
|
6
|
+
tag: string;
|
|
7
|
+
}
|
|
8
|
+
interface DjotParentNode extends DjotBaseNode {
|
|
9
|
+
children: DjotNode[];
|
|
10
|
+
}
|
|
11
|
+
interface DjotDocNode extends DjotParentNode {
|
|
12
|
+
tag: "doc";
|
|
13
|
+
}
|
|
14
|
+
interface DjotParaNode extends DjotParentNode {
|
|
15
|
+
tag: "para";
|
|
16
|
+
}
|
|
17
|
+
interface DjotHeadingNode extends DjotParentNode {
|
|
18
|
+
level: number;
|
|
19
|
+
tag: "heading";
|
|
20
|
+
}
|
|
21
|
+
interface DjotEmphNode extends DjotParentNode {
|
|
22
|
+
tag: "emph";
|
|
23
|
+
}
|
|
24
|
+
interface DjotStrongNode extends DjotParentNode {
|
|
25
|
+
tag: "strong";
|
|
26
|
+
}
|
|
27
|
+
interface DjotCodeNode extends DjotBaseNode {
|
|
28
|
+
tag: "code";
|
|
29
|
+
text: string;
|
|
30
|
+
}
|
|
31
|
+
interface DjotCodeBlockNode extends DjotBaseNode {
|
|
32
|
+
lang?: string;
|
|
33
|
+
tag: "code_block";
|
|
34
|
+
text: string;
|
|
35
|
+
}
|
|
36
|
+
interface DjotLinkNode extends DjotParentNode {
|
|
37
|
+
destination: string;
|
|
38
|
+
tag: "link";
|
|
39
|
+
}
|
|
40
|
+
interface DjotImageNode extends DjotParentNode {
|
|
41
|
+
destination: string;
|
|
42
|
+
tag: "image";
|
|
43
|
+
}
|
|
44
|
+
interface DjotBulletListNode extends DjotParentNode {
|
|
45
|
+
tag: "bullet_list";
|
|
46
|
+
}
|
|
47
|
+
interface DjotOrderedListNode extends DjotParentNode {
|
|
48
|
+
start?: number;
|
|
49
|
+
tag: "ordered_list";
|
|
50
|
+
}
|
|
51
|
+
interface DjotListItemNode extends DjotParentNode {
|
|
52
|
+
tag: "list_item";
|
|
53
|
+
}
|
|
54
|
+
interface DjotBlockquoteNode extends DjotParentNode {
|
|
55
|
+
tag: "blockquote";
|
|
56
|
+
}
|
|
57
|
+
interface DjotThematicBreakNode extends DjotBaseNode {
|
|
58
|
+
tag: "thematic_break";
|
|
59
|
+
}
|
|
60
|
+
interface DjotStrNode extends DjotBaseNode {
|
|
61
|
+
tag: "str";
|
|
62
|
+
text: string;
|
|
63
|
+
}
|
|
64
|
+
interface DjotSoftBreakNode extends DjotBaseNode {
|
|
65
|
+
tag: "soft_break" | "softbreak";
|
|
66
|
+
}
|
|
67
|
+
interface DjotHardBreakNode extends DjotBaseNode {
|
|
68
|
+
tag: "hard_break" | "hardbreak";
|
|
69
|
+
}
|
|
70
|
+
type DjotNode = DjotDocNode | DjotParaNode | DjotHeadingNode | DjotEmphNode | DjotStrongNode | DjotCodeNode | DjotCodeBlockNode | DjotLinkNode | DjotImageNode | DjotBulletListNode | DjotOrderedListNode | DjotListItemNode | DjotBlockquoteNode | DjotThematicBreakNode | DjotStrNode | DjotSoftBreakNode | DjotHardBreakNode;
|
|
71
|
+
type DjotNodeTag = DjotNode["tag"];
|
|
72
|
+
type DjotNodeByTag<Tag extends DjotNodeTag> = Extract<DjotNode, {
|
|
73
|
+
tag: Tag;
|
|
74
|
+
}>;
|
|
75
|
+
interface DjotNodePropsBase<Tag extends DjotNodeTag> {
|
|
76
|
+
children?: React.ReactNode;
|
|
77
|
+
node: DjotNodeByTag<Tag>;
|
|
78
|
+
}
|
|
79
|
+
interface DjotComponentPropsMap {
|
|
80
|
+
doc: DjotNodePropsBase<"doc">;
|
|
81
|
+
para: React.HTMLAttributes<HTMLParagraphElement> & DjotNodePropsBase<"para">;
|
|
82
|
+
heading: React.HTMLAttributes<HTMLHeadingElement> & DjotNodePropsBase<"heading"> & {
|
|
83
|
+
level: number;
|
|
84
|
+
};
|
|
85
|
+
emph: React.HTMLAttributes<HTMLElement> & DjotNodePropsBase<"emph">;
|
|
86
|
+
strong: React.HTMLAttributes<HTMLElement> & DjotNodePropsBase<"strong">;
|
|
87
|
+
code: React.HTMLAttributes<HTMLElement> & DjotNodePropsBase<"code"> & {
|
|
88
|
+
value: string;
|
|
89
|
+
};
|
|
90
|
+
code_block: React.HTMLAttributes<HTMLPreElement> & DjotNodePropsBase<"code_block"> & {
|
|
91
|
+
language?: string;
|
|
92
|
+
value: string;
|
|
93
|
+
};
|
|
94
|
+
link: React.AnchorHTMLAttributes<HTMLAnchorElement> & DjotNodePropsBase<"link">;
|
|
95
|
+
image: React.ImgHTMLAttributes<HTMLImageElement> & DjotNodePropsBase<"image"> & {
|
|
96
|
+
alt?: string;
|
|
97
|
+
};
|
|
98
|
+
bullet_list: React.HTMLAttributes<HTMLUListElement> & DjotNodePropsBase<"bullet_list">;
|
|
99
|
+
ordered_list: React.OlHTMLAttributes<HTMLOListElement> & DjotNodePropsBase<"ordered_list">;
|
|
100
|
+
list_item: React.LiHTMLAttributes<HTMLLIElement> & DjotNodePropsBase<"list_item">;
|
|
101
|
+
blockquote: React.BlockquoteHTMLAttributes<HTMLQuoteElement> & DjotNodePropsBase<"blockquote">;
|
|
102
|
+
thematic_break: React.HTMLAttributes<HTMLHRElement> & DjotNodePropsBase<"thematic_break">;
|
|
103
|
+
str: DjotNodePropsBase<"str"> & {
|
|
104
|
+
value: string;
|
|
105
|
+
};
|
|
106
|
+
soft_break: DjotNodePropsBase<"soft_break">;
|
|
107
|
+
softbreak: DjotNodePropsBase<"softbreak">;
|
|
108
|
+
hard_break: DjotNodePropsBase<"hard_break">;
|
|
109
|
+
hardbreak: DjotNodePropsBase<"hardbreak">;
|
|
110
|
+
}
|
|
111
|
+
type DjotComponents = Partial<{
|
|
112
|
+
[K in keyof DjotComponentPropsMap]: React.ElementType<DjotComponentPropsMap[K]>;
|
|
113
|
+
}>;
|
|
114
|
+
interface DjotProps {
|
|
115
|
+
children?: string | null | undefined;
|
|
116
|
+
components?: DjotComponents | undefined;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
declare function Djot({ children, components }: DjotProps): React.ReactElement | null;
|
|
120
|
+
|
|
121
|
+
interface RenderNodeOptions {
|
|
122
|
+
components?: DjotComponents | undefined;
|
|
123
|
+
key?: React.Key;
|
|
124
|
+
}
|
|
125
|
+
declare function renderNode(node: DjotNode, options?: RenderNodeOptions): React.ReactNode;
|
|
126
|
+
|
|
127
|
+
export { Djot, type DjotComponentPropsMap, type DjotComponents, type DjotNode, type DjotNodeByTag, type DjotNodeTag, type DjotProps, Djot as default, renderNode };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
type DjotAttributes = Record<string, string>;
|
|
4
|
+
interface DjotBaseNode {
|
|
5
|
+
attributes?: DjotAttributes;
|
|
6
|
+
tag: string;
|
|
7
|
+
}
|
|
8
|
+
interface DjotParentNode extends DjotBaseNode {
|
|
9
|
+
children: DjotNode[];
|
|
10
|
+
}
|
|
11
|
+
interface DjotDocNode extends DjotParentNode {
|
|
12
|
+
tag: "doc";
|
|
13
|
+
}
|
|
14
|
+
interface DjotParaNode extends DjotParentNode {
|
|
15
|
+
tag: "para";
|
|
16
|
+
}
|
|
17
|
+
interface DjotHeadingNode extends DjotParentNode {
|
|
18
|
+
level: number;
|
|
19
|
+
tag: "heading";
|
|
20
|
+
}
|
|
21
|
+
interface DjotEmphNode extends DjotParentNode {
|
|
22
|
+
tag: "emph";
|
|
23
|
+
}
|
|
24
|
+
interface DjotStrongNode extends DjotParentNode {
|
|
25
|
+
tag: "strong";
|
|
26
|
+
}
|
|
27
|
+
interface DjotCodeNode extends DjotBaseNode {
|
|
28
|
+
tag: "code";
|
|
29
|
+
text: string;
|
|
30
|
+
}
|
|
31
|
+
interface DjotCodeBlockNode extends DjotBaseNode {
|
|
32
|
+
lang?: string;
|
|
33
|
+
tag: "code_block";
|
|
34
|
+
text: string;
|
|
35
|
+
}
|
|
36
|
+
interface DjotLinkNode extends DjotParentNode {
|
|
37
|
+
destination: string;
|
|
38
|
+
tag: "link";
|
|
39
|
+
}
|
|
40
|
+
interface DjotImageNode extends DjotParentNode {
|
|
41
|
+
destination: string;
|
|
42
|
+
tag: "image";
|
|
43
|
+
}
|
|
44
|
+
interface DjotBulletListNode extends DjotParentNode {
|
|
45
|
+
tag: "bullet_list";
|
|
46
|
+
}
|
|
47
|
+
interface DjotOrderedListNode extends DjotParentNode {
|
|
48
|
+
start?: number;
|
|
49
|
+
tag: "ordered_list";
|
|
50
|
+
}
|
|
51
|
+
interface DjotListItemNode extends DjotParentNode {
|
|
52
|
+
tag: "list_item";
|
|
53
|
+
}
|
|
54
|
+
interface DjotBlockquoteNode extends DjotParentNode {
|
|
55
|
+
tag: "blockquote";
|
|
56
|
+
}
|
|
57
|
+
interface DjotThematicBreakNode extends DjotBaseNode {
|
|
58
|
+
tag: "thematic_break";
|
|
59
|
+
}
|
|
60
|
+
interface DjotStrNode extends DjotBaseNode {
|
|
61
|
+
tag: "str";
|
|
62
|
+
text: string;
|
|
63
|
+
}
|
|
64
|
+
interface DjotSoftBreakNode extends DjotBaseNode {
|
|
65
|
+
tag: "soft_break" | "softbreak";
|
|
66
|
+
}
|
|
67
|
+
interface DjotHardBreakNode extends DjotBaseNode {
|
|
68
|
+
tag: "hard_break" | "hardbreak";
|
|
69
|
+
}
|
|
70
|
+
type DjotNode = DjotDocNode | DjotParaNode | DjotHeadingNode | DjotEmphNode | DjotStrongNode | DjotCodeNode | DjotCodeBlockNode | DjotLinkNode | DjotImageNode | DjotBulletListNode | DjotOrderedListNode | DjotListItemNode | DjotBlockquoteNode | DjotThematicBreakNode | DjotStrNode | DjotSoftBreakNode | DjotHardBreakNode;
|
|
71
|
+
type DjotNodeTag = DjotNode["tag"];
|
|
72
|
+
type DjotNodeByTag<Tag extends DjotNodeTag> = Extract<DjotNode, {
|
|
73
|
+
tag: Tag;
|
|
74
|
+
}>;
|
|
75
|
+
interface DjotNodePropsBase<Tag extends DjotNodeTag> {
|
|
76
|
+
children?: React.ReactNode;
|
|
77
|
+
node: DjotNodeByTag<Tag>;
|
|
78
|
+
}
|
|
79
|
+
interface DjotComponentPropsMap {
|
|
80
|
+
doc: DjotNodePropsBase<"doc">;
|
|
81
|
+
para: React.HTMLAttributes<HTMLParagraphElement> & DjotNodePropsBase<"para">;
|
|
82
|
+
heading: React.HTMLAttributes<HTMLHeadingElement> & DjotNodePropsBase<"heading"> & {
|
|
83
|
+
level: number;
|
|
84
|
+
};
|
|
85
|
+
emph: React.HTMLAttributes<HTMLElement> & DjotNodePropsBase<"emph">;
|
|
86
|
+
strong: React.HTMLAttributes<HTMLElement> & DjotNodePropsBase<"strong">;
|
|
87
|
+
code: React.HTMLAttributes<HTMLElement> & DjotNodePropsBase<"code"> & {
|
|
88
|
+
value: string;
|
|
89
|
+
};
|
|
90
|
+
code_block: React.HTMLAttributes<HTMLPreElement> & DjotNodePropsBase<"code_block"> & {
|
|
91
|
+
language?: string;
|
|
92
|
+
value: string;
|
|
93
|
+
};
|
|
94
|
+
link: React.AnchorHTMLAttributes<HTMLAnchorElement> & DjotNodePropsBase<"link">;
|
|
95
|
+
image: React.ImgHTMLAttributes<HTMLImageElement> & DjotNodePropsBase<"image"> & {
|
|
96
|
+
alt?: string;
|
|
97
|
+
};
|
|
98
|
+
bullet_list: React.HTMLAttributes<HTMLUListElement> & DjotNodePropsBase<"bullet_list">;
|
|
99
|
+
ordered_list: React.OlHTMLAttributes<HTMLOListElement> & DjotNodePropsBase<"ordered_list">;
|
|
100
|
+
list_item: React.LiHTMLAttributes<HTMLLIElement> & DjotNodePropsBase<"list_item">;
|
|
101
|
+
blockquote: React.BlockquoteHTMLAttributes<HTMLQuoteElement> & DjotNodePropsBase<"blockquote">;
|
|
102
|
+
thematic_break: React.HTMLAttributes<HTMLHRElement> & DjotNodePropsBase<"thematic_break">;
|
|
103
|
+
str: DjotNodePropsBase<"str"> & {
|
|
104
|
+
value: string;
|
|
105
|
+
};
|
|
106
|
+
soft_break: DjotNodePropsBase<"soft_break">;
|
|
107
|
+
softbreak: DjotNodePropsBase<"softbreak">;
|
|
108
|
+
hard_break: DjotNodePropsBase<"hard_break">;
|
|
109
|
+
hardbreak: DjotNodePropsBase<"hardbreak">;
|
|
110
|
+
}
|
|
111
|
+
type DjotComponents = Partial<{
|
|
112
|
+
[K in keyof DjotComponentPropsMap]: React.ElementType<DjotComponentPropsMap[K]>;
|
|
113
|
+
}>;
|
|
114
|
+
interface DjotProps {
|
|
115
|
+
children?: string | null | undefined;
|
|
116
|
+
components?: DjotComponents | undefined;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
declare function Djot({ children, components }: DjotProps): React.ReactElement | null;
|
|
120
|
+
|
|
121
|
+
interface RenderNodeOptions {
|
|
122
|
+
components?: DjotComponents | undefined;
|
|
123
|
+
key?: React.Key;
|
|
124
|
+
}
|
|
125
|
+
declare function renderNode(node: DjotNode, options?: RenderNodeOptions): React.ReactNode;
|
|
126
|
+
|
|
127
|
+
export { Djot, type DjotComponentPropsMap, type DjotComponents, type DjotNode, type DjotNodeByTag, type DjotNodeTag, type DjotProps, Djot as default, renderNode };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,365 @@
|
|
|
1
|
+
import { parse } from '@djot/djot';
|
|
2
|
+
import { Fragment, createElement } from 'react';
|
|
3
|
+
import { jsx } from 'react/jsx-runtime';
|
|
4
|
+
|
|
5
|
+
// src/Djot.tsx
|
|
6
|
+
function isParentNode(node) {
|
|
7
|
+
return Array.isArray(node.children);
|
|
8
|
+
}
|
|
9
|
+
function isSoftBreakNode(node) {
|
|
10
|
+
return node.tag === "soft_break" || node.tag === "softbreak";
|
|
11
|
+
}
|
|
12
|
+
function isHardBreakNode(node) {
|
|
13
|
+
return node.tag === "hard_break" || node.tag === "hardbreak";
|
|
14
|
+
}
|
|
15
|
+
function pickComponent(components, primary, alias) {
|
|
16
|
+
if (!components) {
|
|
17
|
+
return void 0;
|
|
18
|
+
}
|
|
19
|
+
return components[primary] ?? (alias ? components[alias] : void 0);
|
|
20
|
+
}
|
|
21
|
+
function renderChildren(children, components) {
|
|
22
|
+
return children.map(
|
|
23
|
+
(child, index) => renderNode(child, {
|
|
24
|
+
components,
|
|
25
|
+
key: index
|
|
26
|
+
})
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
function toAltText(nodes) {
|
|
30
|
+
let output = "";
|
|
31
|
+
for (const node of nodes) {
|
|
32
|
+
switch (node.tag) {
|
|
33
|
+
case "str":
|
|
34
|
+
case "code":
|
|
35
|
+
case "code_block":
|
|
36
|
+
output += node.text;
|
|
37
|
+
break;
|
|
38
|
+
case "soft_break":
|
|
39
|
+
case "softbreak":
|
|
40
|
+
output += " ";
|
|
41
|
+
break;
|
|
42
|
+
case "hard_break":
|
|
43
|
+
case "hardbreak":
|
|
44
|
+
output += "\n";
|
|
45
|
+
break;
|
|
46
|
+
default:
|
|
47
|
+
if (isParentNode(node)) {
|
|
48
|
+
output += toAltText(node.children);
|
|
49
|
+
}
|
|
50
|
+
break;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return output.trim();
|
|
54
|
+
}
|
|
55
|
+
function clampHeadingLevel(level) {
|
|
56
|
+
if (level <= 1) {
|
|
57
|
+
return 1;
|
|
58
|
+
}
|
|
59
|
+
if (level >= 6) {
|
|
60
|
+
return 6;
|
|
61
|
+
}
|
|
62
|
+
return level;
|
|
63
|
+
}
|
|
64
|
+
function withKey(props, key) {
|
|
65
|
+
if (key === void 0) {
|
|
66
|
+
return props;
|
|
67
|
+
}
|
|
68
|
+
return {
|
|
69
|
+
...props,
|
|
70
|
+
key
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
function renderWithOverride(override, fallback, domProps, customProps, key, children) {
|
|
74
|
+
const Component = override ?? fallback;
|
|
75
|
+
const props = typeof Component === "string" ? withKey(domProps, key) : withKey(
|
|
76
|
+
{
|
|
77
|
+
...domProps,
|
|
78
|
+
...customProps
|
|
79
|
+
},
|
|
80
|
+
key
|
|
81
|
+
);
|
|
82
|
+
return createElement(Component, props, children);
|
|
83
|
+
}
|
|
84
|
+
function renderDoc(node, components, key) {
|
|
85
|
+
const children = renderChildren(node.children, components);
|
|
86
|
+
const Component = pickComponent(components, "doc");
|
|
87
|
+
if (Component) {
|
|
88
|
+
if (typeof Component === "string") {
|
|
89
|
+
return createElement(Component, withKey({}, key), children);
|
|
90
|
+
}
|
|
91
|
+
return createElement(Component, withKey({ node }, key), children);
|
|
92
|
+
}
|
|
93
|
+
return createElement(Fragment, withKey({}, key), children);
|
|
94
|
+
}
|
|
95
|
+
function renderHeading(node, components, key) {
|
|
96
|
+
const level = clampHeadingLevel(node.level);
|
|
97
|
+
const children = renderChildren(node.children, components);
|
|
98
|
+
return renderWithOverride(
|
|
99
|
+
pickComponent(components, "heading"),
|
|
100
|
+
`h${level}`,
|
|
101
|
+
{},
|
|
102
|
+
{
|
|
103
|
+
level,
|
|
104
|
+
node
|
|
105
|
+
},
|
|
106
|
+
key,
|
|
107
|
+
children
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
function renderCode(node, components, key) {
|
|
111
|
+
const value = node.text;
|
|
112
|
+
return renderWithOverride(
|
|
113
|
+
pickComponent(components, "code"),
|
|
114
|
+
"code",
|
|
115
|
+
{},
|
|
116
|
+
{
|
|
117
|
+
node,
|
|
118
|
+
value
|
|
119
|
+
},
|
|
120
|
+
key,
|
|
121
|
+
value
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
function renderCodeBlock(node, components, key) {
|
|
125
|
+
const value = node.text;
|
|
126
|
+
const language = node.lang;
|
|
127
|
+
const fallbackChildren = createElement(
|
|
128
|
+
"code",
|
|
129
|
+
{
|
|
130
|
+
className: language ? `language-${language}` : void 0
|
|
131
|
+
},
|
|
132
|
+
value
|
|
133
|
+
);
|
|
134
|
+
return renderWithOverride(
|
|
135
|
+
pickComponent(components, "code_block"),
|
|
136
|
+
"pre",
|
|
137
|
+
{},
|
|
138
|
+
{
|
|
139
|
+
language,
|
|
140
|
+
node,
|
|
141
|
+
value
|
|
142
|
+
},
|
|
143
|
+
key,
|
|
144
|
+
fallbackChildren
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
function renderLink(node, components, key) {
|
|
148
|
+
const children = renderChildren(node.children, components);
|
|
149
|
+
const href = node.destination;
|
|
150
|
+
return renderWithOverride(
|
|
151
|
+
pickComponent(components, "link"),
|
|
152
|
+
"a",
|
|
153
|
+
{
|
|
154
|
+
href
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
node
|
|
158
|
+
},
|
|
159
|
+
key,
|
|
160
|
+
children
|
|
161
|
+
);
|
|
162
|
+
}
|
|
163
|
+
function renderImage(node, components, key) {
|
|
164
|
+
const alt = toAltText(node.children) || void 0;
|
|
165
|
+
const src = node.destination;
|
|
166
|
+
return renderWithOverride(
|
|
167
|
+
pickComponent(components, "image"),
|
|
168
|
+
"img",
|
|
169
|
+
{
|
|
170
|
+
alt,
|
|
171
|
+
src
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
alt,
|
|
175
|
+
node
|
|
176
|
+
},
|
|
177
|
+
key
|
|
178
|
+
);
|
|
179
|
+
}
|
|
180
|
+
function renderOrderedList(node, components, key) {
|
|
181
|
+
const children = renderChildren(node.children, components);
|
|
182
|
+
return renderWithOverride(
|
|
183
|
+
pickComponent(components, "ordered_list"),
|
|
184
|
+
"ol",
|
|
185
|
+
{
|
|
186
|
+
start: node.start
|
|
187
|
+
},
|
|
188
|
+
{
|
|
189
|
+
node,
|
|
190
|
+
start: node.start
|
|
191
|
+
},
|
|
192
|
+
key,
|
|
193
|
+
children
|
|
194
|
+
);
|
|
195
|
+
}
|
|
196
|
+
function renderStr(node, components, key) {
|
|
197
|
+
const value = node.text;
|
|
198
|
+
const Component = pickComponent(components, "str");
|
|
199
|
+
if (!Component) {
|
|
200
|
+
return value;
|
|
201
|
+
}
|
|
202
|
+
if (typeof Component === "string") {
|
|
203
|
+
return createElement(Component, withKey({}, key), value);
|
|
204
|
+
}
|
|
205
|
+
return createElement(
|
|
206
|
+
Component,
|
|
207
|
+
withKey(
|
|
208
|
+
{
|
|
209
|
+
node,
|
|
210
|
+
value
|
|
211
|
+
},
|
|
212
|
+
key
|
|
213
|
+
),
|
|
214
|
+
value
|
|
215
|
+
);
|
|
216
|
+
}
|
|
217
|
+
function renderSoftBreak(node, components, key) {
|
|
218
|
+
const Component = pickComponent(components, "soft_break", "softbreak");
|
|
219
|
+
if (!Component) {
|
|
220
|
+
return "\n";
|
|
221
|
+
}
|
|
222
|
+
if (typeof Component === "string") {
|
|
223
|
+
return createElement(Component, withKey({}, key), "\n");
|
|
224
|
+
}
|
|
225
|
+
return createElement(
|
|
226
|
+
Component,
|
|
227
|
+
withKey(
|
|
228
|
+
{
|
|
229
|
+
node
|
|
230
|
+
},
|
|
231
|
+
key
|
|
232
|
+
),
|
|
233
|
+
"\n"
|
|
234
|
+
);
|
|
235
|
+
}
|
|
236
|
+
function renderHardBreak(node, components, key) {
|
|
237
|
+
return renderWithOverride(
|
|
238
|
+
pickComponent(components, "hard_break", "hardbreak"),
|
|
239
|
+
"br",
|
|
240
|
+
{},
|
|
241
|
+
{
|
|
242
|
+
node
|
|
243
|
+
},
|
|
244
|
+
key
|
|
245
|
+
);
|
|
246
|
+
}
|
|
247
|
+
function renderNode(node, options = {}) {
|
|
248
|
+
const { components, key } = options;
|
|
249
|
+
const children = isParentNode(node) ? renderChildren(node.children, components) : void 0;
|
|
250
|
+
switch (node.tag) {
|
|
251
|
+
case "doc":
|
|
252
|
+
return renderDoc(node, components, key);
|
|
253
|
+
case "para":
|
|
254
|
+
return renderWithOverride(
|
|
255
|
+
pickComponent(components, "para"),
|
|
256
|
+
"p",
|
|
257
|
+
{},
|
|
258
|
+
{
|
|
259
|
+
node
|
|
260
|
+
},
|
|
261
|
+
key,
|
|
262
|
+
children
|
|
263
|
+
);
|
|
264
|
+
case "heading":
|
|
265
|
+
return renderHeading(node, components, key);
|
|
266
|
+
case "emph":
|
|
267
|
+
return renderWithOverride(
|
|
268
|
+
pickComponent(components, "emph"),
|
|
269
|
+
"em",
|
|
270
|
+
{},
|
|
271
|
+
{
|
|
272
|
+
node
|
|
273
|
+
},
|
|
274
|
+
key,
|
|
275
|
+
children
|
|
276
|
+
);
|
|
277
|
+
case "strong":
|
|
278
|
+
return renderWithOverride(
|
|
279
|
+
pickComponent(components, "strong"),
|
|
280
|
+
"strong",
|
|
281
|
+
{},
|
|
282
|
+
{
|
|
283
|
+
node
|
|
284
|
+
},
|
|
285
|
+
key,
|
|
286
|
+
children
|
|
287
|
+
);
|
|
288
|
+
case "code":
|
|
289
|
+
return renderCode(node, components, key);
|
|
290
|
+
case "code_block":
|
|
291
|
+
return renderCodeBlock(node, components, key);
|
|
292
|
+
case "link":
|
|
293
|
+
return renderLink(node, components, key);
|
|
294
|
+
case "image":
|
|
295
|
+
return renderImage(node, components, key);
|
|
296
|
+
case "bullet_list":
|
|
297
|
+
return renderWithOverride(
|
|
298
|
+
pickComponent(components, "bullet_list"),
|
|
299
|
+
"ul",
|
|
300
|
+
{},
|
|
301
|
+
{
|
|
302
|
+
node
|
|
303
|
+
},
|
|
304
|
+
key,
|
|
305
|
+
children
|
|
306
|
+
);
|
|
307
|
+
case "ordered_list":
|
|
308
|
+
return renderOrderedList(node, components, key);
|
|
309
|
+
case "list_item":
|
|
310
|
+
return renderWithOverride(
|
|
311
|
+
pickComponent(components, "list_item"),
|
|
312
|
+
"li",
|
|
313
|
+
{},
|
|
314
|
+
{
|
|
315
|
+
node
|
|
316
|
+
},
|
|
317
|
+
key,
|
|
318
|
+
children
|
|
319
|
+
);
|
|
320
|
+
case "blockquote":
|
|
321
|
+
return renderWithOverride(
|
|
322
|
+
pickComponent(components, "blockquote"),
|
|
323
|
+
"blockquote",
|
|
324
|
+
{},
|
|
325
|
+
{
|
|
326
|
+
node
|
|
327
|
+
},
|
|
328
|
+
key,
|
|
329
|
+
children
|
|
330
|
+
);
|
|
331
|
+
case "thematic_break":
|
|
332
|
+
return renderWithOverride(
|
|
333
|
+
pickComponent(components, "thematic_break"),
|
|
334
|
+
"hr",
|
|
335
|
+
{},
|
|
336
|
+
{
|
|
337
|
+
node
|
|
338
|
+
},
|
|
339
|
+
key
|
|
340
|
+
);
|
|
341
|
+
case "str":
|
|
342
|
+
return renderStr(node, components, key);
|
|
343
|
+
default:
|
|
344
|
+
if (isSoftBreakNode(node)) {
|
|
345
|
+
return renderSoftBreak(node, components, key);
|
|
346
|
+
}
|
|
347
|
+
if (isHardBreakNode(node)) {
|
|
348
|
+
return renderHardBreak(node, components, key);
|
|
349
|
+
}
|
|
350
|
+
return null;
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
function Djot({ children, components }) {
|
|
354
|
+
const source = children ?? "";
|
|
355
|
+
if (source.length === 0) {
|
|
356
|
+
return null;
|
|
357
|
+
}
|
|
358
|
+
const ast = parse(source);
|
|
359
|
+
return /* @__PURE__ */ jsx(Fragment, { children: renderNode(ast, { components }) });
|
|
360
|
+
}
|
|
361
|
+
var Djot_default = Djot;
|
|
362
|
+
|
|
363
|
+
export { Djot, Djot_default as default, renderNode };
|
|
364
|
+
//# sourceMappingURL=index.js.map
|
|
365
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/renderNode.tsx","../src/Djot.tsx"],"names":["Fragment"],"mappings":"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","file":"index.js","sourcesContent":["import { createElement, Fragment } from \"react\";\nimport type React from \"react\";\nimport type {\n DjotBaseNode,\n DjotCodeBlockNode,\n DjotCodeNode,\n DjotComponentPropsMap,\n DjotComponents,\n DjotDocNode,\n DjotHardBreakNode,\n DjotHeadingNode,\n DjotImageNode,\n DjotLinkNode,\n DjotNode,\n DjotOrderedListNode,\n DjotParentNode,\n DjotSoftBreakNode,\n DjotStrNode\n} from \"./types\";\n\nexport interface RenderNodeOptions {\n components?: DjotComponents | undefined;\n key?: React.Key;\n}\n\ntype ComponentKey = keyof DjotComponentPropsMap;\n\nfunction isParentNode(node: DjotBaseNode): node is DjotParentNode {\n return Array.isArray((node as DjotParentNode).children);\n}\n\nfunction isSoftBreakNode(node: DjotNode): node is DjotSoftBreakNode {\n return node.tag === \"soft_break\" || node.tag === \"softbreak\";\n}\n\nfunction isHardBreakNode(node: DjotNode): node is DjotHardBreakNode {\n return node.tag === \"hard_break\" || node.tag === \"hardbreak\";\n}\n\nfunction pickComponent(\n components: DjotComponents | undefined,\n primary: ComponentKey,\n alias?: ComponentKey\n): React.ElementType | undefined {\n if (!components) {\n return undefined;\n }\n\n return (components[primary] ?? (alias ? components[alias] : undefined)) as\n | React.ElementType\n | undefined;\n}\n\nfunction renderChildren(children: DjotNode[], components?: DjotComponents): React.ReactNode[] {\n return children.map((child, index) =>\n renderNode(child, {\n components,\n key: index\n })\n );\n}\n\nfunction toAltText(nodes: DjotNode[]): string {\n let output = \"\";\n\n for (const node of nodes) {\n switch (node.tag) {\n case \"str\":\n case \"code\":\n case \"code_block\":\n output += node.text;\n break;\n case \"soft_break\":\n case \"softbreak\":\n output += \" \";\n break;\n case \"hard_break\":\n case \"hardbreak\":\n output += \"\\n\";\n break;\n default:\n if (isParentNode(node)) {\n output += toAltText(node.children);\n }\n break;\n }\n }\n\n return output.trim();\n}\n\nfunction clampHeadingLevel(level: number): 1 | 2 | 3 | 4 | 5 | 6 {\n if (level <= 1) {\n return 1;\n }\n\n if (level >= 6) {\n return 6;\n }\n\n return level as 1 | 2 | 3 | 4 | 5 | 6;\n}\n\nfunction withKey<T extends Record<string, unknown>>(props: T, key?: React.Key): T & { key?: React.Key } {\n if (key === undefined) {\n return props;\n }\n\n return {\n ...props,\n key\n };\n}\n\nfunction renderWithOverride(\n override: React.ElementType | undefined,\n fallback: React.ElementType,\n domProps: Record<string, unknown>,\n customProps: Record<string, unknown>,\n key?: React.Key,\n children?: React.ReactNode\n): React.ReactNode {\n const Component = override ?? fallback;\n const props =\n typeof Component === \"string\"\n ? withKey(domProps, key)\n : withKey(\n {\n ...domProps,\n ...customProps\n },\n key\n );\n\n return createElement(Component, props, children);\n}\n\nfunction renderDoc(\n node: DjotDocNode,\n components: DjotComponents | undefined,\n key?: React.Key\n): React.ReactNode {\n const children = renderChildren(node.children, components);\n const Component = pickComponent(components, \"doc\");\n\n if (Component) {\n if (typeof Component === \"string\") {\n return createElement(Component, withKey({}, key), children);\n }\n\n return createElement(Component, withKey({ node }, key), children);\n }\n\n return createElement(Fragment, withKey({}, key), children);\n}\n\nfunction renderHeading(\n node: DjotHeadingNode,\n components: DjotComponents | undefined,\n key?: React.Key\n): React.ReactNode {\n const level = clampHeadingLevel(node.level);\n const children = renderChildren(node.children, components);\n return renderWithOverride(\n pickComponent(components, \"heading\"),\n `h${level}`,\n {},\n {\n level,\n node\n },\n key,\n children\n );\n}\n\nfunction renderCode(\n node: DjotCodeNode,\n components: DjotComponents | undefined,\n key?: React.Key\n): React.ReactNode {\n const value = node.text;\n return renderWithOverride(\n pickComponent(components, \"code\"),\n \"code\",\n {},\n {\n node,\n value\n },\n key,\n value\n );\n}\n\nfunction renderCodeBlock(\n node: DjotCodeBlockNode,\n components: DjotComponents | undefined,\n key?: React.Key\n): React.ReactNode {\n const value = node.text;\n const language = node.lang;\n const fallbackChildren = createElement(\n \"code\",\n {\n className: language ? `language-${language}` : undefined\n },\n value\n );\n\n return renderWithOverride(\n pickComponent(components, \"code_block\"),\n \"pre\",\n {},\n {\n language,\n node,\n value\n },\n key,\n fallbackChildren\n );\n}\n\nfunction renderLink(\n node: DjotLinkNode,\n components: DjotComponents | undefined,\n key?: React.Key\n): React.ReactNode {\n const children = renderChildren(node.children, components);\n const href = node.destination;\n return renderWithOverride(\n pickComponent(components, \"link\"),\n \"a\",\n {\n href\n },\n {\n node\n },\n key,\n children\n );\n}\n\nfunction renderImage(\n node: DjotImageNode,\n components: DjotComponents | undefined,\n key?: React.Key\n): React.ReactNode {\n const alt = toAltText(node.children) || undefined;\n const src = node.destination;\n return renderWithOverride(\n pickComponent(components, \"image\"),\n \"img\",\n {\n alt,\n src\n },\n {\n alt,\n node\n },\n key\n );\n}\n\nfunction renderOrderedList(\n node: DjotOrderedListNode,\n components: DjotComponents | undefined,\n key?: React.Key\n): React.ReactNode {\n const children = renderChildren(node.children, components);\n return renderWithOverride(\n pickComponent(components, \"ordered_list\"),\n \"ol\",\n {\n start: node.start\n },\n {\n node,\n start: node.start\n },\n key,\n children\n );\n}\n\nfunction renderStr(\n node: DjotStrNode,\n components: DjotComponents | undefined,\n key?: React.Key\n): React.ReactNode {\n const value = node.text;\n const Component = pickComponent(components, \"str\");\n\n if (!Component) {\n return value;\n }\n\n if (typeof Component === \"string\") {\n return createElement(Component, withKey({}, key), value);\n }\n\n return createElement(\n Component,\n withKey(\n {\n node,\n value\n },\n key\n ),\n value\n );\n}\n\nfunction renderSoftBreak(\n node: DjotSoftBreakNode,\n components: DjotComponents | undefined,\n key?: React.Key\n): React.ReactNode {\n const Component = pickComponent(components, \"soft_break\", \"softbreak\");\n\n if (!Component) {\n return \"\\n\";\n }\n\n if (typeof Component === \"string\") {\n return createElement(Component, withKey({}, key), \"\\n\");\n }\n\n return createElement(\n Component,\n withKey(\n {\n node\n },\n key\n ),\n \"\\n\"\n );\n}\n\nfunction renderHardBreak(\n node: DjotHardBreakNode,\n components: DjotComponents | undefined,\n key?: React.Key\n): React.ReactNode {\n return renderWithOverride(\n pickComponent(components, \"hard_break\", \"hardbreak\"),\n \"br\",\n {},\n {\n node\n },\n key\n );\n}\n\nexport function renderNode(node: DjotNode, options: RenderNodeOptions = {}): React.ReactNode {\n const { components, key } = options;\n const children = isParentNode(node) ? renderChildren(node.children, components) : undefined;\n\n switch (node.tag) {\n case \"doc\":\n return renderDoc(node, components, key);\n case \"para\":\n return renderWithOverride(\n pickComponent(components, \"para\"),\n \"p\",\n {},\n {\n node\n },\n key,\n children\n );\n case \"heading\":\n return renderHeading(node, components, key);\n case \"emph\":\n return renderWithOverride(\n pickComponent(components, \"emph\"),\n \"em\",\n {},\n {\n node\n },\n key,\n children\n );\n case \"strong\":\n return renderWithOverride(\n pickComponent(components, \"strong\"),\n \"strong\",\n {},\n {\n node\n },\n key,\n children\n );\n case \"code\":\n return renderCode(node, components, key);\n case \"code_block\":\n return renderCodeBlock(node, components, key);\n case \"link\":\n return renderLink(node, components, key);\n case \"image\":\n return renderImage(node, components, key);\n case \"bullet_list\":\n return renderWithOverride(\n pickComponent(components, \"bullet_list\"),\n \"ul\",\n {},\n {\n node\n },\n key,\n children\n );\n case \"ordered_list\":\n return renderOrderedList(node, components, key);\n case \"list_item\":\n return renderWithOverride(\n pickComponent(components, \"list_item\"),\n \"li\",\n {},\n {\n node\n },\n key,\n children\n );\n case \"blockquote\":\n return renderWithOverride(\n pickComponent(components, \"blockquote\"),\n \"blockquote\",\n {},\n {\n node\n },\n key,\n children\n );\n case \"thematic_break\":\n return renderWithOverride(\n pickComponent(components, \"thematic_break\"),\n \"hr\",\n {},\n {\n node\n },\n key\n );\n case \"str\":\n return renderStr(node, components, key);\n default:\n if (isSoftBreakNode(node)) {\n return renderSoftBreak(node, components, key);\n }\n\n if (isHardBreakNode(node)) {\n return renderHardBreak(node, components, key);\n }\n\n return null;\n }\n}\n","import { parse } from \"@djot/djot\";\nimport { Fragment } from \"react\";\nimport type React from \"react\";\nimport { renderNode } from \"./renderNode\";\nimport type { DjotNode, DjotProps } from \"./types\";\n\nexport function Djot({ children, components }: DjotProps): React.ReactElement | null {\n const source = children ?? \"\";\n\n if (source.length === 0) {\n return null;\n }\n\n const ast = parse(source) as DjotNode;\n return <Fragment>{renderNode(ast, { components })}</Fragment>;\n}\n\nexport default Djot;\n"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@willwang-io/react-djot",
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "Render Djot to React with a react-markdown style component override API.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "./dist/index.cjs",
|
|
8
|
+
"module": "./dist/index.js",
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"exports": {
|
|
11
|
+
".": {
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"import": "./dist/index.js",
|
|
14
|
+
"require": "./dist/index.cjs"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"dist"
|
|
19
|
+
],
|
|
20
|
+
"sideEffects": false,
|
|
21
|
+
"engines": {
|
|
22
|
+
"node": ">=18"
|
|
23
|
+
},
|
|
24
|
+
"scripts": {
|
|
25
|
+
"build": "tsup",
|
|
26
|
+
"dev": "tsup --watch",
|
|
27
|
+
"typecheck": "tsc --noEmit",
|
|
28
|
+
"test": "vitest run",
|
|
29
|
+
"test:watch": "vitest",
|
|
30
|
+
"lint": "eslint . --ext .ts,.tsx",
|
|
31
|
+
"format": "prettier . --write",
|
|
32
|
+
"format:check": "prettier . --check"
|
|
33
|
+
},
|
|
34
|
+
"peerDependencies": {
|
|
35
|
+
"@djot/djot": "^0.3.0",
|
|
36
|
+
"react": ">=18",
|
|
37
|
+
"react-dom": ">=18"
|
|
38
|
+
},
|
|
39
|
+
"devDependencies": {
|
|
40
|
+
"@djot/djot": "^0.3.0",
|
|
41
|
+
"@types/node": "^24.0.0",
|
|
42
|
+
"@types/react": "^18.3.0",
|
|
43
|
+
"@types/react-dom": "^18.3.0",
|
|
44
|
+
"@typescript-eslint/eslint-plugin": "^8.0.0",
|
|
45
|
+
"@typescript-eslint/parser": "^8.0.0",
|
|
46
|
+
"eslint": "^8.57.0",
|
|
47
|
+
"eslint-config-prettier": "^9.1.0",
|
|
48
|
+
"prettier": "^3.3.0",
|
|
49
|
+
"react": "^18.3.1",
|
|
50
|
+
"react-dom": "^18.3.1",
|
|
51
|
+
"tsup": "^8.2.0",
|
|
52
|
+
"typescript": "^5.6.0",
|
|
53
|
+
"vitest": "^2.1.0"
|
|
54
|
+
},
|
|
55
|
+
"publishConfig": {
|
|
56
|
+
"access": "public"
|
|
57
|
+
}
|
|
58
|
+
}
|