@willwang-io/react-djot 0.1.5 → 0.1.6

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/dist/index.js CHANGED
@@ -6,27 +6,6 @@ import { jsx } from 'react/jsx-runtime';
6
6
  function isParentNode(node) {
7
7
  return Array.isArray(node.children);
8
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, footnoteState) {
22
- return children.map(
23
- (child, index) => renderNode(child, {
24
- components,
25
- footnoteState,
26
- key: index
27
- })
28
- );
29
- }
30
9
  function collectFootnoteReferences(nodes, indexByLabel, order) {
31
10
  for (const node of nodes) {
32
11
  if (node.tag === "footnote_reference") {
@@ -48,12 +27,26 @@ function createFootnoteState(node) {
48
27
  const order = [];
49
28
  collectFootnoteReferences(node.children, indexByLabel, order);
50
29
  return {
30
+ autoReferencesByLabel: node.autoReferences ?? {},
51
31
  firstRefIdByLabel: /* @__PURE__ */ new Map(),
52
32
  indexByLabel,
53
33
  order,
34
+ referencesByLabel: node.references ?? {},
54
35
  refCountByLabel: /* @__PURE__ */ new Map()
55
36
  };
56
37
  }
38
+ function resolveReferenceNode(node, footnoteState) {
39
+ if (!node.reference || !footnoteState) {
40
+ return void 0;
41
+ }
42
+ return footnoteState.referencesByLabel[node.reference] ?? footnoteState.autoReferencesByLabel[node.reference];
43
+ }
44
+ function resolveReferenceDestination(node, footnoteState) {
45
+ if (node.destination) {
46
+ return node.destination;
47
+ }
48
+ return resolveReferenceNode(node, footnoteState)?.destination;
49
+ }
57
50
  function ensureFootnoteIndex(label, footnoteState) {
58
51
  const existing = footnoteState.indexByLabel.get(label);
59
52
  if (existing) {
@@ -78,6 +71,11 @@ function appendBacklink(nodes, backlink) {
78
71
  next.push(backlink);
79
72
  return next;
80
73
  }
74
+
75
+ // src/renderNode.utils.ts
76
+ function isParentNode2(node) {
77
+ return Array.isArray(node.children);
78
+ }
81
79
  function toSmartPunctuation(type, fallback) {
82
80
  switch (type) {
83
81
  case "left_double_quote":
@@ -108,7 +106,15 @@ function toAltText(nodes) {
108
106
  case "inline_math":
109
107
  case "display_math":
110
108
  case "code_block":
111
- output += node.text;
109
+ case "raw_block":
110
+ case "raw_inline":
111
+ case "symb":
112
+ case "url":
113
+ case "email":
114
+ output += node.tag === "symb" ? `:${node.alias}:` : node.text;
115
+ break;
116
+ case "non_breaking_space":
117
+ output += "\xA0";
112
118
  break;
113
119
  case "smart_punctuation":
114
120
  output += toSmartPunctuation(node.type, node.text);
@@ -128,7 +134,7 @@ function toAltText(nodes) {
128
134
  output += "\n";
129
135
  break;
130
136
  default:
131
- if (isParentNode(node)) {
137
+ if (isParentNode2(node)) {
132
138
  output += toAltText(node.children);
133
139
  }
134
140
  break;
@@ -168,6 +174,45 @@ function toDomPropsFromAttributes(attributes) {
168
174
  }
169
175
  return props;
170
176
  }
177
+ function toDomPropsFromNode(node) {
178
+ return {
179
+ ...toDomPropsFromAttributes(node.autoAttributes),
180
+ ...toDomPropsFromAttributes(node.attributes)
181
+ };
182
+ }
183
+ function joinClassNames(...values) {
184
+ const classes = values.filter((value) => Boolean(value && value.length > 0));
185
+ return classes.length > 0 ? classes.join(" ") : void 0;
186
+ }
187
+ function toStyleObject(value) {
188
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
189
+ return void 0;
190
+ }
191
+ return value;
192
+ }
193
+ function mergeDomProps(node, extra = {}) {
194
+ const nodeProps = toDomPropsFromNode(node);
195
+ const merged = {
196
+ ...extra,
197
+ ...nodeProps
198
+ };
199
+ const className = joinClassNames(
200
+ typeof extra.className === "string" ? extra.className : void 0,
201
+ typeof nodeProps.className === "string" ? nodeProps.className : void 0
202
+ );
203
+ if (className) {
204
+ merged.className = className;
205
+ }
206
+ const extraStyle = toStyleObject(extra.style);
207
+ const nodeStyle = toStyleObject(nodeProps.style);
208
+ if (extraStyle || nodeStyle) {
209
+ merged.style = {
210
+ ...extraStyle ?? {},
211
+ ...nodeStyle ?? {}
212
+ };
213
+ }
214
+ return merged;
215
+ }
171
216
  function textAlignForCell(align) {
172
217
  if (align === "left") {
173
218
  return "left";
@@ -180,6 +225,289 @@ function textAlignForCell(align) {
180
225
  }
181
226
  return void 0;
182
227
  }
228
+ function toOrderedListType(style) {
229
+ if (!style || /1/.test(style)) {
230
+ return void 0;
231
+ }
232
+ const type = style.replace(/[().]/g, "");
233
+ return type.length > 0 ? type : void 0;
234
+ }
235
+
236
+ // src/renderNode.rawHtml.tsx
237
+ var RAW_HTML_ATTR_PATTERN = /([^\s"'=<>`/]+)(?:\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s"'=<>`]+)))?/g;
238
+ var RAW_HTML_TOKEN_PATTERN = /<!--[\s\S]*?-->|<\/?[A-Za-z][^>]*>|[^<]+|</g;
239
+ var RAW_HTML_BLOCKED_TAGS = /* @__PURE__ */ new Set([
240
+ "base",
241
+ "embed",
242
+ "form",
243
+ "iframe",
244
+ "meta",
245
+ "object",
246
+ "script"
247
+ ]);
248
+ var RAW_HTML_BOOLEAN_ATTRS = /* @__PURE__ */ new Set([
249
+ "allowfullscreen",
250
+ "async",
251
+ "autofocus",
252
+ "autoplay",
253
+ "checked",
254
+ "controls",
255
+ "default",
256
+ "defer",
257
+ "disabled",
258
+ "hidden",
259
+ "loop",
260
+ "multiple",
261
+ "muted",
262
+ "novalidate",
263
+ "open",
264
+ "playsinline",
265
+ "readonly",
266
+ "required",
267
+ "reversed",
268
+ "selected"
269
+ ]);
270
+ var RAW_HTML_UNSAFE_PROTOCOL = /^\s*(?:javascript:|vbscript:|data:)/i;
271
+ var RAW_HTML_URL_ATTRS = /* @__PURE__ */ new Set([
272
+ "action",
273
+ "formaction",
274
+ "href",
275
+ "poster",
276
+ "src",
277
+ "xlink:href"
278
+ ]);
279
+ var RAW_HTML_VOID_TAGS = /* @__PURE__ */ new Set([
280
+ "area",
281
+ "base",
282
+ "br",
283
+ "col",
284
+ "embed",
285
+ "hr",
286
+ "img",
287
+ "input",
288
+ "link",
289
+ "meta",
290
+ "param",
291
+ "source",
292
+ "track",
293
+ "wbr"
294
+ ]);
295
+ function decodeHtmlEntities(value) {
296
+ return value.replace(/&(#x?[0-9a-fA-F]+|[a-zA-Z]+);/g, (_match, entity) => {
297
+ if (entity.startsWith("#x") || entity.startsWith("#X")) {
298
+ const codePoint = Number.parseInt(entity.slice(2), 16);
299
+ if (!Number.isNaN(codePoint)) {
300
+ return String.fromCodePoint(codePoint);
301
+ }
302
+ return _match;
303
+ }
304
+ if (entity.startsWith("#")) {
305
+ const codePoint = Number.parseInt(entity.slice(1), 10);
306
+ if (!Number.isNaN(codePoint)) {
307
+ return String.fromCodePoint(codePoint);
308
+ }
309
+ return _match;
310
+ }
311
+ switch (entity) {
312
+ case "amp":
313
+ return "&";
314
+ case "apos":
315
+ return "'";
316
+ case "gt":
317
+ return ">";
318
+ case "lt":
319
+ return "<";
320
+ case "nbsp":
321
+ return "\xA0";
322
+ case "quot":
323
+ return '"';
324
+ default:
325
+ return _match;
326
+ }
327
+ });
328
+ }
329
+ function parseRawHtmlAttributes(source) {
330
+ const attributes = [];
331
+ for (const match of source.matchAll(RAW_HTML_ATTR_PATTERN)) {
332
+ const name = match[1]?.toLowerCase();
333
+ if (!name) {
334
+ continue;
335
+ }
336
+ const rawValue = match[2] ?? match[3] ?? match[4] ?? "";
337
+ const value = decodeHtmlEntities(rawValue);
338
+ attributes.push({ name, value });
339
+ }
340
+ return attributes;
341
+ }
342
+ function parseRawHtmlFragment(source) {
343
+ const root = {
344
+ attributes: [],
345
+ children: [],
346
+ tagName: "#root",
347
+ type: "element"
348
+ };
349
+ const stack = [root];
350
+ for (const match of source.matchAll(RAW_HTML_TOKEN_PATTERN)) {
351
+ const token = match[0];
352
+ if (token.startsWith("<!--")) {
353
+ continue;
354
+ }
355
+ if (token === "<") {
356
+ stack[stack.length - 1]?.children.push({ text: "<", type: "text" });
357
+ continue;
358
+ }
359
+ const closingTag = /^<\/\s*([A-Za-z][\w:-]*)\s*>$/.exec(token);
360
+ if (closingTag) {
361
+ const closingTagName = closingTag[1];
362
+ if (!closingTagName) {
363
+ continue;
364
+ }
365
+ const tagName = closingTagName.toLowerCase();
366
+ for (let index = stack.length - 1; index > 0; index -= 1) {
367
+ if (stack[index]?.tagName === tagName) {
368
+ stack.length = index;
369
+ break;
370
+ }
371
+ }
372
+ continue;
373
+ }
374
+ const openingTag = /^<\s*([A-Za-z][\w:-]*)([\s\S]*?)>$/.exec(token);
375
+ if (openingTag) {
376
+ const openingTagName = openingTag[1];
377
+ if (!openingTagName) {
378
+ continue;
379
+ }
380
+ const tagName = openingTagName.toLowerCase();
381
+ const rawAttributes = openingTag[2] ?? "";
382
+ const selfClosing = /\/\s*$/.test(rawAttributes) || RAW_HTML_VOID_TAGS.has(tagName);
383
+ const attrSource = selfClosing ? rawAttributes.replace(/\/\s*$/, "") : rawAttributes;
384
+ const element = {
385
+ attributes: parseRawHtmlAttributes(attrSource),
386
+ children: [],
387
+ tagName,
388
+ type: "element"
389
+ };
390
+ stack[stack.length - 1]?.children.push(element);
391
+ if (!selfClosing) {
392
+ stack.push(element);
393
+ }
394
+ continue;
395
+ }
396
+ stack[stack.length - 1]?.children.push({
397
+ text: decodeHtmlEntities(token),
398
+ type: "text"
399
+ });
400
+ }
401
+ return root.children;
402
+ }
403
+ function toCamelCaseCssProperty(name) {
404
+ return name.trim().replace(/^-+/, "").replace(/-([a-z])/g, (_, letter) => letter.toUpperCase());
405
+ }
406
+ function parseStyleAttribute(value) {
407
+ const style = {};
408
+ for (const declaration of value.split(";")) {
409
+ const separatorIndex = declaration.indexOf(":");
410
+ if (separatorIndex === -1) {
411
+ continue;
412
+ }
413
+ const property = toCamelCaseCssProperty(declaration.slice(0, separatorIndex));
414
+ const propertyValue = declaration.slice(separatorIndex + 1).trim();
415
+ if (!property || !propertyValue) {
416
+ continue;
417
+ }
418
+ style[property] = propertyValue;
419
+ }
420
+ if (Object.keys(style).length === 0) {
421
+ return void 0;
422
+ }
423
+ return style;
424
+ }
425
+ function toRawHtmlDomProps(attributes) {
426
+ const props = {};
427
+ for (const { name, value } of attributes) {
428
+ if (name.startsWith("on")) {
429
+ continue;
430
+ }
431
+ if (RAW_HTML_URL_ATTRS.has(name) && RAW_HTML_UNSAFE_PROTOCOL.test(value)) {
432
+ continue;
433
+ }
434
+ if (name === "class") {
435
+ props.className = value;
436
+ continue;
437
+ }
438
+ if (name === "for") {
439
+ props.htmlFor = value;
440
+ continue;
441
+ }
442
+ if (name === "style") {
443
+ const style = parseStyleAttribute(value);
444
+ if (style) {
445
+ props.style = style;
446
+ }
447
+ continue;
448
+ }
449
+ if (RAW_HTML_BOOLEAN_ATTRS.has(name) && value.length === 0) {
450
+ props[name] = true;
451
+ continue;
452
+ }
453
+ props[name] = value;
454
+ }
455
+ return props;
456
+ }
457
+ function renderRawHtmlNode(node, key) {
458
+ if (node.type === "text") {
459
+ return node.text;
460
+ }
461
+ if (RAW_HTML_BLOCKED_TAGS.has(node.tagName)) {
462
+ return null;
463
+ }
464
+ const children = renderRawHtmlNodes(node.children, key);
465
+ return createElement(
466
+ node.tagName,
467
+ withKey(toRawHtmlDomProps(node.attributes), key),
468
+ children.length > 0 ? children : void 0
469
+ );
470
+ }
471
+ function renderRawHtmlNodes(nodes, keyPrefix) {
472
+ const rendered = [];
473
+ for (const [index, node] of nodes.entries()) {
474
+ const next = renderRawHtmlNode(node, `${keyPrefix}-${index}`);
475
+ if (next !== null) {
476
+ rendered.push(next);
477
+ }
478
+ }
479
+ return rendered;
480
+ }
481
+ function rawHtmlChildren(value, keyPrefix) {
482
+ return renderRawHtmlNodes(parseRawHtmlFragment(value), keyPrefix);
483
+ }
484
+
485
+ // src/renderNode.tsx
486
+ function isParentNode3(node) {
487
+ return Array.isArray(node.children);
488
+ }
489
+ function isSoftBreakNode(node) {
490
+ return node.tag === "soft_break" || node.tag === "softbreak";
491
+ }
492
+ function isHardBreakNode(node) {
493
+ return node.tag === "hard_break" || node.tag === "hardbreak";
494
+ }
495
+ function pickComponent(components, primary, alias) {
496
+ if (!components) {
497
+ return void 0;
498
+ }
499
+ return components[primary] ?? (alias ? components[alias] : void 0);
500
+ }
501
+ function renderChildren(children, components, footnoteState, listTight) {
502
+ return children.map(
503
+ (child, index) => renderNode(child, {
504
+ components,
505
+ footnoteState,
506
+ key: index,
507
+ listTight
508
+ })
509
+ );
510
+ }
183
511
  function renderWithOverride(override, fallback, domProps, customProps, key, children) {
184
512
  const Component = override ?? fallback;
185
513
  const props = typeof Component === "string" ? withKey(domProps, key) : withKey(
@@ -198,39 +526,33 @@ function renderDoc(node, components, key) {
198
526
  const allChildren = endnotes ? [...children, endnotes] : children;
199
527
  const Component = pickComponent(components, "doc");
200
528
  if (Component) {
529
+ const domProps = mergeDomProps(node);
201
530
  if (typeof Component === "string") {
202
- return createElement(Component, withKey({}, key), allChildren);
531
+ return createElement(Component, withKey(domProps, key), allChildren);
203
532
  }
204
- return createElement(Component, withKey({ node }, key), allChildren);
533
+ return createElement(Component, withKey({ ...domProps, node }, key), allChildren);
205
534
  }
206
535
  return createElement(Fragment, withKey({}, key), allChildren);
207
536
  }
208
537
  function renderSection(node, components, footnoteState, key) {
209
538
  const children = renderChildren(node.children, components, footnoteState);
210
- const Component = pickComponent(components, "section");
211
- if (Component) {
212
- if (typeof Component === "string") {
213
- return createElement(Component, withKey({}, key), children);
214
- }
215
- return createElement(
216
- Component,
217
- withKey(
218
- {
219
- node
220
- },
221
- key
222
- ),
223
- children
224
- );
225
- }
226
- return createElement(Fragment, withKey({}, key), children);
539
+ return renderWithOverride(
540
+ pickComponent(components, "section"),
541
+ "section",
542
+ mergeDomProps(node),
543
+ {
544
+ node
545
+ },
546
+ key,
547
+ children
548
+ );
227
549
  }
228
550
  function renderDiv(node, components, footnoteState, key) {
229
551
  const children = renderChildren(node.children, components, footnoteState);
230
552
  return renderWithOverride(
231
553
  pickComponent(components, "div"),
232
554
  "div",
233
- toDomPropsFromAttributes(node.attributes),
555
+ mergeDomProps(node),
234
556
  {
235
557
  node
236
558
  },
@@ -239,11 +561,44 @@ function renderDiv(node, components, footnoteState, key) {
239
561
  );
240
562
  }
241
563
  function renderTable(node, components, footnoteState, key) {
242
- const children = renderChildren(node.children, components, footnoteState);
564
+ const captionChildren = [];
565
+ const headRows = [];
566
+ const bodyRows = [];
567
+ const otherChildren = [];
568
+ for (const [index, child] of node.children.entries()) {
569
+ const rendered = renderNode(child, {
570
+ components,
571
+ footnoteState,
572
+ key: index
573
+ });
574
+ if (child.tag === "caption") {
575
+ captionChildren.push(rendered);
576
+ continue;
577
+ }
578
+ if (child.tag === "row") {
579
+ if (child.head && bodyRows.length === 0) {
580
+ headRows.push(rendered);
581
+ } else {
582
+ bodyRows.push(rendered);
583
+ }
584
+ continue;
585
+ }
586
+ otherChildren.push(rendered);
587
+ }
588
+ const children = [...captionChildren];
589
+ if (headRows.length > 0) {
590
+ children.push(createElement("thead", { key: "thead" }, headRows));
591
+ }
592
+ if (bodyRows.length > 0) {
593
+ children.push(createElement("tbody", { key: "tbody" }, bodyRows));
594
+ }
595
+ if (otherChildren.length > 0) {
596
+ children.push(...otherChildren);
597
+ }
243
598
  return renderWithOverride(
244
599
  pickComponent(components, "table"),
245
600
  "table",
246
- toDomPropsFromAttributes(node.attributes),
601
+ mergeDomProps(node),
247
602
  {
248
603
  node
249
604
  },
@@ -260,7 +615,7 @@ function renderCaption(node, components, footnoteState, key) {
260
615
  return renderWithOverride(
261
616
  Component,
262
617
  "caption",
263
- toDomPropsFromAttributes(node.attributes),
618
+ mergeDomProps(node),
264
619
  {
265
620
  node
266
621
  },
@@ -273,7 +628,7 @@ function renderRow(node, components, footnoteState, key) {
273
628
  return renderWithOverride(
274
629
  pickComponent(components, "row"),
275
630
  "tr",
276
- toDomPropsFromAttributes(node.attributes),
631
+ mergeDomProps(node),
277
632
  {
278
633
  head: node.head,
279
634
  node
@@ -285,10 +640,9 @@ function renderRow(node, components, footnoteState, key) {
285
640
  function renderCell(node, components, footnoteState, key) {
286
641
  const children = renderChildren(node.children, components, footnoteState);
287
642
  const textAlign = textAlignForCell(node.align);
288
- const domProps = {
289
- ...toDomPropsFromAttributes(node.attributes),
643
+ const domProps = mergeDomProps(node, {
290
644
  style: textAlign ? { textAlign } : void 0
291
- };
645
+ });
292
646
  return renderWithOverride(
293
647
  pickComponent(components, "cell"),
294
648
  node.head ? "th" : "td",
@@ -308,7 +662,7 @@ function renderHeading(node, components, footnoteState, key) {
308
662
  return renderWithOverride(
309
663
  pickComponent(components, "heading"),
310
664
  `h${level}`,
311
- {},
665
+ mergeDomProps(node),
312
666
  {
313
667
  level,
314
668
  node
@@ -322,7 +676,7 @@ function renderMark(node, components, footnoteState, key, primary, alias) {
322
676
  return renderWithOverride(
323
677
  pickComponent(components, primary, alias),
324
678
  "mark",
325
- {},
679
+ mergeDomProps(node),
326
680
  {
327
681
  node
328
682
  },
@@ -335,7 +689,7 @@ function renderSuperscript(node, components, footnoteState, key, primary, alias)
335
689
  return renderWithOverride(
336
690
  pickComponent(components, primary, alias),
337
691
  "sup",
338
- {},
692
+ mergeDomProps(node),
339
693
  {
340
694
  node
341
695
  },
@@ -348,7 +702,7 @@ function renderSubscript(node, components, footnoteState, key) {
348
702
  return renderWithOverride(
349
703
  pickComponent(components, "subscript"),
350
704
  "sub",
351
- {},
705
+ mergeDomProps(node),
352
706
  {
353
707
  node
354
708
  },
@@ -361,7 +715,7 @@ function renderInsert(node, components, footnoteState, key) {
361
715
  return renderWithOverride(
362
716
  pickComponent(components, "insert"),
363
717
  "ins",
364
- {},
718
+ mergeDomProps(node),
365
719
  {
366
720
  node
367
721
  },
@@ -374,7 +728,7 @@ function renderDelete(node, components, footnoteState, key) {
374
728
  return renderWithOverride(
375
729
  pickComponent(components, "delete"),
376
730
  "del",
377
- {},
731
+ mergeDomProps(node),
378
732
  {
379
733
  node
380
734
  },
@@ -398,11 +752,11 @@ function renderFootnoteReference(node, components, footnoteState, key) {
398
752
  return renderWithOverride(
399
753
  pickComponent(components, "footnote_reference"),
400
754
  "a",
401
- {
755
+ mergeDomProps(node, {
402
756
  href,
403
757
  id,
404
758
  role: "doc-noteref"
405
- },
759
+ }),
406
760
  {
407
761
  index,
408
762
  label,
@@ -436,10 +790,10 @@ function renderEndnotes(node, components, footnoteState) {
436
790
  return renderWithOverride(
437
791
  pickComponent(components, "footnote"),
438
792
  "li",
439
- {
793
+ mergeDomProps(footnoteNode, {
440
794
  id: `fn${index}`,
441
795
  key: label
442
- },
796
+ }),
443
797
  {
444
798
  index,
445
799
  label,
@@ -468,16 +822,18 @@ function renderEndnotes(node, components, footnoteState) {
468
822
  function renderQuoted(node, components, footnoteState, key, primary, alias, openQuote, closeQuote) {
469
823
  const children = renderChildren(node.children, components, footnoteState);
470
824
  const Component = pickComponent(components, primary, alias);
825
+ const domProps = mergeDomProps(node);
471
826
  if (!Component) {
472
827
  return createElement(Fragment, withKey({}, key), openQuote, children, closeQuote);
473
828
  }
474
829
  if (typeof Component === "string") {
475
- return createElement(Component, withKey({}, key), openQuote, children, closeQuote);
830
+ return createElement(Component, withKey(domProps, key), openQuote, children, closeQuote);
476
831
  }
477
832
  return createElement(
478
833
  Component,
479
834
  withKey(
480
835
  {
836
+ ...domProps,
481
837
  node
482
838
  },
483
839
  key
@@ -490,16 +846,18 @@ function renderQuoted(node, components, footnoteState, key, primary, alias, open
490
846
  function renderSmartPunctuation(node, components, key) {
491
847
  const value = toSmartPunctuation(node.type, node.text);
492
848
  const Component = pickComponent(components, "smart_punctuation");
849
+ const domProps = mergeDomProps(node);
493
850
  if (!Component) {
494
851
  return value;
495
852
  }
496
853
  if (typeof Component === "string") {
497
- return createElement(Component, withKey({}, key), value);
854
+ return createElement(Component, withKey(domProps, key), value);
498
855
  }
499
856
  return createElement(
500
857
  Component,
501
858
  withKey(
502
859
  {
860
+ ...domProps,
503
861
  kind: node.type,
504
862
  node,
505
863
  value
@@ -514,9 +872,9 @@ function renderInlineMath(node, components, key) {
514
872
  return renderWithOverride(
515
873
  pickComponent(components, "inline_math"),
516
874
  "span",
517
- {
875
+ mergeDomProps(node, {
518
876
  className: "math inline"
519
- },
877
+ }),
520
878
  {
521
879
  node,
522
880
  value
@@ -530,9 +888,9 @@ function renderDisplayMath(node, components, key) {
530
888
  return renderWithOverride(
531
889
  pickComponent(components, "display_math"),
532
890
  "span",
533
- {
891
+ mergeDomProps(node, {
534
892
  className: "math display"
535
- },
893
+ }),
536
894
  {
537
895
  node,
538
896
  value
@@ -546,7 +904,7 @@ function renderCode(node, components, key, primary, alias) {
546
904
  return renderWithOverride(
547
905
  pickComponent(components, primary, alias),
548
906
  "code",
549
- {},
907
+ mergeDomProps(node),
550
908
  {
551
909
  node,
552
910
  value
@@ -568,7 +926,7 @@ function renderCodeBlock(node, components, key) {
568
926
  return renderWithOverride(
569
927
  pickComponent(components, "code_block"),
570
928
  "pre",
571
- {},
929
+ mergeDomProps(node),
572
930
  {
573
931
  language,
574
932
  node,
@@ -578,15 +936,136 @@ function renderCodeBlock(node, components, key) {
578
936
  fallbackChildren
579
937
  );
580
938
  }
581
- function renderLink(node, components, footnoteState, key) {
582
- const children = renderChildren(node.children, components, footnoteState);
583
- const href = node.destination;
939
+ function renderRawBlock(node, components, key) {
940
+ const format = node.format;
941
+ const value = node.text;
942
+ const htmlChildren = format === "html" ? rawHtmlChildren(value, `raw-block-${String(key ?? "node")}`) : void 0;
943
+ const Component = pickComponent(components, "raw_block");
944
+ const domProps = mergeDomProps(node);
945
+ if (!Component) {
946
+ if (format !== "html") {
947
+ return null;
948
+ }
949
+ return createElement(Fragment, withKey({}, key), htmlChildren);
950
+ }
951
+ if (typeof Component === "string") {
952
+ return createElement(Component, withKey(domProps, key), htmlChildren ?? value);
953
+ }
954
+ return createElement(
955
+ Component,
956
+ withKey(
957
+ {
958
+ ...domProps,
959
+ format,
960
+ node,
961
+ value
962
+ },
963
+ key
964
+ ),
965
+ htmlChildren ?? value
966
+ );
967
+ }
968
+ function renderRawInline(node, components, key) {
969
+ const format = node.format;
970
+ const value = node.text;
971
+ const htmlChildren = format === "html" ? rawHtmlChildren(value, `raw-inline-${String(key ?? "node")}`) : void 0;
972
+ const Component = pickComponent(components, "raw_inline");
973
+ const domProps = mergeDomProps(node);
974
+ if (!Component) {
975
+ if (format !== "html") {
976
+ return null;
977
+ }
978
+ return createElement(Fragment, withKey({}, key), htmlChildren);
979
+ }
980
+ if (typeof Component === "string") {
981
+ return createElement(Component, withKey(domProps, key), htmlChildren ?? value);
982
+ }
983
+ return createElement(
984
+ Component,
985
+ withKey(
986
+ {
987
+ ...domProps,
988
+ format,
989
+ node,
990
+ value
991
+ },
992
+ key
993
+ ),
994
+ htmlChildren ?? value
995
+ );
996
+ }
997
+ function renderUrl(node, components, key) {
998
+ const value = node.text;
999
+ const href = value;
584
1000
  return renderWithOverride(
585
- pickComponent(components, "link"),
1001
+ pickComponent(components, "url"),
586
1002
  "a",
1003
+ mergeDomProps(node, {
1004
+ href
1005
+ }),
587
1006
  {
1007
+ href,
1008
+ node,
1009
+ value
1010
+ },
1011
+ key,
1012
+ value
1013
+ );
1014
+ }
1015
+ function renderEmail(node, components, key) {
1016
+ const value = node.text;
1017
+ const href = `mailto:${value}`;
1018
+ return renderWithOverride(
1019
+ pickComponent(components, "email"),
1020
+ "a",
1021
+ mergeDomProps(node, {
588
1022
  href
1023
+ }),
1024
+ {
1025
+ href,
1026
+ node,
1027
+ value
589
1028
  },
1029
+ key,
1030
+ value
1031
+ );
1032
+ }
1033
+ function renderSymb(node, components, key) {
1034
+ const alias = node.alias;
1035
+ const value = `:${alias}:`;
1036
+ const Component = pickComponent(components, "symb");
1037
+ if (!Component) {
1038
+ return value;
1039
+ }
1040
+ if (typeof Component === "string") {
1041
+ return createElement(Component, withKey(mergeDomProps(node), key), value);
1042
+ }
1043
+ return createElement(
1044
+ Component,
1045
+ withKey(
1046
+ {
1047
+ ...mergeDomProps(node),
1048
+ alias,
1049
+ node,
1050
+ value
1051
+ },
1052
+ key
1053
+ ),
1054
+ value
1055
+ );
1056
+ }
1057
+ function renderLink(node, components, footnoteState, key) {
1058
+ const children = renderChildren(node.children, components, footnoteState);
1059
+ const referenceNode = resolveReferenceNode(node, footnoteState);
1060
+ const referenceProps = referenceNode ? toDomPropsFromNode(referenceNode) : {};
1061
+ const href = resolveReferenceDestination(node, footnoteState);
1062
+ return renderWithOverride(
1063
+ pickComponent(components, "link"),
1064
+ "a",
1065
+ mergeDomProps(node, {
1066
+ href,
1067
+ ...referenceProps
1068
+ }),
590
1069
  {
591
1070
  node
592
1071
  },
@@ -594,16 +1073,19 @@ function renderLink(node, components, footnoteState, key) {
594
1073
  children
595
1074
  );
596
1075
  }
597
- function renderImage(node, components, key) {
1076
+ function renderImage(node, components, footnoteState, key) {
598
1077
  const alt = toAltText(node.children) || void 0;
599
- const src = node.destination;
1078
+ const referenceNode = resolveReferenceNode(node, footnoteState);
1079
+ const referenceProps = referenceNode ? toDomPropsFromNode(referenceNode) : {};
1080
+ const src = resolveReferenceDestination(node, footnoteState);
600
1081
  return renderWithOverride(
601
1082
  pickComponent(components, "image"),
602
1083
  "img",
603
- {
1084
+ mergeDomProps(node, {
604
1085
  alt,
605
- src
606
- },
1086
+ src,
1087
+ ...referenceProps
1088
+ }),
607
1089
  {
608
1090
  alt,
609
1091
  node
@@ -612,27 +1094,164 @@ function renderImage(node, components, key) {
612
1094
  );
613
1095
  }
614
1096
  function renderOrderedList(node, components, footnoteState, key) {
615
- const children = renderChildren(node.children, components, footnoteState);
1097
+ const tight = node.tight ?? false;
1098
+ const children = renderChildren(node.children, components, footnoteState, tight);
1099
+ const start = node.start !== void 0 && node.start !== 1 ? node.start : void 0;
1100
+ const type = toOrderedListType(node.style);
616
1101
  return renderWithOverride(
617
1102
  pickComponent(components, "ordered_list"),
618
1103
  "ol",
1104
+ mergeDomProps(node, {
1105
+ start,
1106
+ type
1107
+ }),
1108
+ {
1109
+ node,
1110
+ start,
1111
+ tight
1112
+ },
1113
+ key,
1114
+ children
1115
+ );
1116
+ }
1117
+ function renderDefinitionList(node, components, footnoteState, key) {
1118
+ const children = renderChildren(node.children, components, footnoteState);
1119
+ return renderWithOverride(
1120
+ pickComponent(components, "definition_list"),
1121
+ "dl",
1122
+ mergeDomProps(node),
619
1123
  {
620
- start: node.start
1124
+ node
621
1125
  },
1126
+ key,
1127
+ children
1128
+ );
1129
+ }
1130
+ function renderDefinitionListItem(node, components, footnoteState, key) {
1131
+ const children = renderChildren(node.children, components, footnoteState);
1132
+ const Component = pickComponent(components, "definition_list_item");
1133
+ const domProps = mergeDomProps(node);
1134
+ if (Component) {
1135
+ if (typeof Component === "string") {
1136
+ return createElement(Component, withKey(domProps, key), children);
1137
+ }
1138
+ return createElement(
1139
+ Component,
1140
+ withKey(
1141
+ {
1142
+ ...domProps,
1143
+ node
1144
+ },
1145
+ key
1146
+ ),
1147
+ children
1148
+ );
1149
+ }
1150
+ return createElement(Fragment, withKey({}, key), children);
1151
+ }
1152
+ function renderBulletList(node, components, footnoteState, key) {
1153
+ const tight = node.tight ?? false;
1154
+ const children = renderChildren(node.children, components, footnoteState, tight);
1155
+ return renderWithOverride(
1156
+ pickComponent(components, "bullet_list"),
1157
+ "ul",
1158
+ mergeDomProps(node),
622
1159
  {
623
1160
  node,
624
- start: node.start
1161
+ tight
1162
+ },
1163
+ key,
1164
+ children
1165
+ );
1166
+ }
1167
+ function renderListItem(node, components, footnoteState, listTight, key) {
1168
+ const override = pickComponent(components, "list_item");
1169
+ if (override) {
1170
+ const domProps = mergeDomProps(node);
1171
+ const contentChildren2 = renderChildren(node.children, components, footnoteState);
1172
+ if (typeof override === "string") {
1173
+ return createElement(override, withKey(domProps, key), contentChildren2);
1174
+ }
1175
+ return createElement(
1176
+ override,
1177
+ withKey({ ...domProps, node, tight: listTight }, key),
1178
+ contentChildren2
1179
+ );
1180
+ }
1181
+ const firstChild = node.children[0];
1182
+ const inlineSource = listTight === true && node.children.length === 1 && firstChild?.tag === "para" ? firstChild.children : node.children;
1183
+ const contentChildren = renderChildren(inlineSource, components, footnoteState);
1184
+ return createElement("li", withKey(mergeDomProps(node), key), contentChildren);
1185
+ }
1186
+ function renderTerm(node, components, footnoteState, key) {
1187
+ const children = renderChildren(node.children, components, footnoteState);
1188
+ return renderWithOverride(
1189
+ pickComponent(components, "term"),
1190
+ "dt",
1191
+ mergeDomProps(node),
1192
+ {
1193
+ node
625
1194
  },
626
1195
  key,
627
1196
  children
628
1197
  );
629
1198
  }
1199
+ function renderDefinition(node, components, footnoteState, key) {
1200
+ const children = renderChildren(node.children, components, footnoteState);
1201
+ return renderWithOverride(
1202
+ pickComponent(components, "definition"),
1203
+ "dd",
1204
+ mergeDomProps(node),
1205
+ {
1206
+ node
1207
+ },
1208
+ key,
1209
+ children
1210
+ );
1211
+ }
1212
+ function renderTaskList(node, components, footnoteState, key) {
1213
+ const tight = node.tight ?? false;
1214
+ const children = renderChildren(node.children, components, footnoteState, tight);
1215
+ return renderWithOverride(
1216
+ pickComponent(components, "task_list"),
1217
+ "ul",
1218
+ mergeDomProps(node, { className: "task-list" }),
1219
+ { node, tight },
1220
+ key,
1221
+ children
1222
+ );
1223
+ }
1224
+ function renderTaskListItem(node, components, footnoteState, listTight, key) {
1225
+ const override = pickComponent(components, "task_list_item");
1226
+ if (override) {
1227
+ const domProps = mergeDomProps(node);
1228
+ const contentChildren2 = renderChildren(node.children, components, footnoteState);
1229
+ if (typeof override === "string") {
1230
+ return createElement(override, withKey(domProps, key), contentChildren2);
1231
+ }
1232
+ return createElement(
1233
+ override,
1234
+ withKey({ ...domProps, node, checkbox: node.checkbox, tight: listTight }, key),
1235
+ contentChildren2
1236
+ );
1237
+ }
1238
+ const firstChild = node.children[0];
1239
+ const inlineSource = listTight === true && node.children.length === 1 && firstChild?.tag === "para" ? firstChild.children : node.children;
1240
+ const contentChildren = renderChildren(inlineSource, components, footnoteState);
1241
+ const checkboxEl = createElement("input", {
1242
+ key: "checkbox",
1243
+ type: "checkbox",
1244
+ disabled: true,
1245
+ checked: node.checkbox === "checked"
1246
+ });
1247
+ return createElement("li", withKey(mergeDomProps(node), key), [checkboxEl, contentChildren]);
1248
+ }
630
1249
  function renderBlockQuote(node, components, footnoteState, key, primary, alias) {
631
1250
  const children = renderChildren(node.children, components, footnoteState);
632
1251
  return renderWithOverride(
633
1252
  pickComponent(components, primary, alias),
634
1253
  "blockquote",
635
- {},
1254
+ mergeDomProps(node),
636
1255
  {
637
1256
  node
638
1257
  },
@@ -643,16 +1262,49 @@ function renderBlockQuote(node, components, footnoteState, key, primary, alias)
643
1262
  function renderStr(node, components, key) {
644
1263
  const value = node.text;
645
1264
  const Component = pickComponent(components, "str");
1265
+ const domProps = mergeDomProps(node);
1266
+ const hasNodeDomProps = Object.keys(domProps).length > 0;
1267
+ if (!Component) {
1268
+ if (hasNodeDomProps) {
1269
+ return createElement("span", withKey(domProps, key), value);
1270
+ }
1271
+ return value;
1272
+ }
1273
+ if (typeof Component === "string") {
1274
+ return createElement(Component, withKey(domProps, key), value);
1275
+ }
1276
+ return createElement(
1277
+ Component,
1278
+ withKey(
1279
+ {
1280
+ ...domProps,
1281
+ node,
1282
+ value
1283
+ },
1284
+ key
1285
+ ),
1286
+ value
1287
+ );
1288
+ }
1289
+ function renderNonBreakingSpace(node, components, key) {
1290
+ const value = "\xA0";
1291
+ const Component = pickComponent(components, "non_breaking_space");
1292
+ const domProps = mergeDomProps(node);
1293
+ const hasNodeDomProps = Object.keys(domProps).length > 0;
646
1294
  if (!Component) {
1295
+ if (hasNodeDomProps) {
1296
+ return createElement("span", withKey(domProps, key), value);
1297
+ }
647
1298
  return value;
648
1299
  }
649
1300
  if (typeof Component === "string") {
650
- return createElement(Component, withKey({}, key), value);
1301
+ return createElement(Component, withKey(domProps, key), value);
651
1302
  }
652
1303
  return createElement(
653
1304
  Component,
654
1305
  withKey(
655
1306
  {
1307
+ ...domProps,
656
1308
  node,
657
1309
  value
658
1310
  },
@@ -663,16 +1315,18 @@ function renderStr(node, components, key) {
663
1315
  }
664
1316
  function renderSoftBreak(node, components, key) {
665
1317
  const Component = pickComponent(components, "soft_break", "softbreak");
1318
+ const domProps = mergeDomProps(node);
666
1319
  if (!Component) {
667
1320
  return "\n";
668
1321
  }
669
1322
  if (typeof Component === "string") {
670
- return createElement(Component, withKey({}, key), "\n");
1323
+ return createElement(Component, withKey(domProps, key), "\n");
671
1324
  }
672
1325
  return createElement(
673
1326
  Component,
674
1327
  withKey(
675
1328
  {
1329
+ ...domProps,
676
1330
  node
677
1331
  },
678
1332
  key
@@ -684,7 +1338,7 @@ function renderHardBreak(node, components, key) {
684
1338
  return renderWithOverride(
685
1339
  pickComponent(components, "hard_break", "hardbreak"),
686
1340
  "br",
687
- {},
1341
+ mergeDomProps(node),
688
1342
  {
689
1343
  node
690
1344
  },
@@ -692,8 +1346,8 @@ function renderHardBreak(node, components, key) {
692
1346
  );
693
1347
  }
694
1348
  function renderNode(node, options = {}) {
695
- const { components, footnoteState, key } = options;
696
- const children = isParentNode(node) ? renderChildren(node.children, components, footnoteState) : void 0;
1349
+ const { components, footnoteState, key, listTight } = options;
1350
+ const children = isParentNode3(node) ? renderChildren(node.children, components, footnoteState, listTight) : void 0;
697
1351
  switch (node.tag) {
698
1352
  case "doc":
699
1353
  return renderDoc(node, components, key);
@@ -713,7 +1367,7 @@ function renderNode(node, options = {}) {
713
1367
  return renderWithOverride(
714
1368
  pickComponent(components, "para"),
715
1369
  "p",
716
- {},
1370
+ mergeDomProps(node),
717
1371
  {
718
1372
  node
719
1373
  },
@@ -726,7 +1380,7 @@ function renderNode(node, options = {}) {
726
1380
  return renderWithOverride(
727
1381
  pickComponent(components, "emph"),
728
1382
  "em",
729
- {},
1383
+ mergeDomProps(node),
730
1384
  {
731
1385
  node
732
1386
  },
@@ -737,7 +1391,7 @@ function renderNode(node, options = {}) {
737
1391
  return renderWithOverride(
738
1392
  pickComponent(components, "strong"),
739
1393
  "strong",
740
- {},
1394
+ mergeDomProps(node),
741
1395
  {
742
1396
  node
743
1397
  },
@@ -758,13 +1412,24 @@ function renderNode(node, options = {}) {
758
1412
  return renderInsert(node, components, footnoteState, key);
759
1413
  case "delete":
760
1414
  return renderDelete(node, components, footnoteState, key);
1415
+ case "span":
1416
+ return renderWithOverride(
1417
+ pickComponent(components, "span"),
1418
+ "span",
1419
+ mergeDomProps(node),
1420
+ {
1421
+ node
1422
+ },
1423
+ key,
1424
+ children
1425
+ );
761
1426
  case "footnote_reference":
762
1427
  return renderFootnoteReference(node, components, footnoteState, key);
763
1428
  case "footnote":
764
1429
  return renderWithOverride(
765
1430
  pickComponent(components, "footnote"),
766
1431
  "li",
767
- {},
1432
+ mergeDomProps(node),
768
1433
  {
769
1434
  index: 0,
770
1435
  label: node.label,
@@ -797,6 +1462,8 @@ function renderNode(node, options = {}) {
797
1462
  );
798
1463
  case "smart_punctuation":
799
1464
  return renderSmartPunctuation(node, components, key);
1465
+ case "symb":
1466
+ return renderSymb(node, components, key);
800
1467
  case "inline_math":
801
1468
  return renderInlineMath(node, components, key);
802
1469
  case "display_math":
@@ -807,34 +1474,36 @@ function renderNode(node, options = {}) {
807
1474
  return renderCode(node, components, key, "verbatim", "code");
808
1475
  case "code_block":
809
1476
  return renderCodeBlock(node, components, key);
1477
+ case "raw_block":
1478
+ return renderRawBlock(node, components, key);
1479
+ case "raw_inline":
1480
+ return renderRawInline(node, components, key);
1481
+ case "url":
1482
+ return renderUrl(node, components, key);
1483
+ case "email":
1484
+ return renderEmail(node, components, key);
810
1485
  case "link":
811
1486
  return renderLink(node, components, footnoteState, key);
812
1487
  case "image":
813
- return renderImage(node, components, key);
1488
+ return renderImage(node, components, footnoteState, key);
814
1489
  case "bullet_list":
815
- return renderWithOverride(
816
- pickComponent(components, "bullet_list"),
817
- "ul",
818
- {},
819
- {
820
- node
821
- },
822
- key,
823
- children
824
- );
1490
+ return renderBulletList(node, components, footnoteState, key);
825
1491
  case "ordered_list":
826
1492
  return renderOrderedList(node, components, footnoteState, key);
827
1493
  case "list_item":
828
- return renderWithOverride(
829
- pickComponent(components, "list_item"),
830
- "li",
831
- {},
832
- {
833
- node
834
- },
835
- key,
836
- children
837
- );
1494
+ return renderListItem(node, components, footnoteState, listTight, key);
1495
+ case "definition_list":
1496
+ return renderDefinitionList(node, components, footnoteState, key);
1497
+ case "definition_list_item":
1498
+ return renderDefinitionListItem(node, components, footnoteState, key);
1499
+ case "term":
1500
+ return renderTerm(node, components, footnoteState, key);
1501
+ case "definition":
1502
+ return renderDefinition(node, components, footnoteState, key);
1503
+ case "task_list":
1504
+ return renderTaskList(node, components, footnoteState, key);
1505
+ case "task_list_item":
1506
+ return renderTaskListItem(node, components, footnoteState, listTight, key);
838
1507
  case "blockquote":
839
1508
  return renderBlockQuote(node, components, footnoteState, key, "blockquote", "block_quote");
840
1509
  case "block_quote":
@@ -843,7 +1512,7 @@ function renderNode(node, options = {}) {
843
1512
  return renderWithOverride(
844
1513
  pickComponent(components, "thematic_break"),
845
1514
  "hr",
846
- {},
1515
+ mergeDomProps(node),
847
1516
  {
848
1517
  node
849
1518
  },
@@ -851,6 +1520,8 @@ function renderNode(node, options = {}) {
851
1520
  );
852
1521
  case "str":
853
1522
  return renderStr(node, components, key);
1523
+ case "non_breaking_space":
1524
+ return renderNonBreakingSpace(node, components, key);
854
1525
  default:
855
1526
  if (isSoftBreakNode(node)) {
856
1527
  return renderSoftBreak(node, components, key);
@@ -861,16 +1532,50 @@ function renderNode(node, options = {}) {
861
1532
  return null;
862
1533
  }
863
1534
  }
864
- function Djot({ children, components }) {
865
- const source = children ?? "";
1535
+ var COMPILE_CACHE_LIMIT = 100;
1536
+ var compileCache = /* @__PURE__ */ new Map();
1537
+ function getCachedAst(source) {
1538
+ const cached = compileCache.get(source);
1539
+ if (!cached) {
1540
+ return void 0;
1541
+ }
1542
+ compileCache.delete(source);
1543
+ compileCache.set(source, cached);
1544
+ return cached;
1545
+ }
1546
+ function setCachedAst(source, ast) {
1547
+ compileCache.set(source, ast);
1548
+ if (compileCache.size > COMPILE_CACHE_LIMIT) {
1549
+ const oldestSource = compileCache.keys().next().value;
1550
+ if (oldestSource !== void 0) {
1551
+ compileCache.delete(oldestSource);
1552
+ }
1553
+ }
1554
+ return ast;
1555
+ }
1556
+ function compileDjot(source) {
1557
+ const cached = getCachedAst(source);
1558
+ if (cached) {
1559
+ return cached;
1560
+ }
1561
+ const ast = parse(source);
1562
+ return setCachedAst(source, ast);
1563
+ }
1564
+ function Djot(props) {
1565
+ const { components } = props;
1566
+ const astFromProps = props.ast;
1567
+ if (astFromProps !== void 0) {
1568
+ return /* @__PURE__ */ jsx(Fragment, { children: renderNode(astFromProps, { components }) });
1569
+ }
1570
+ const source = props.children ?? "";
866
1571
  if (source.length === 0) {
867
1572
  return null;
868
1573
  }
869
- const ast = parse(source);
1574
+ const ast = compileDjot(source);
870
1575
  return /* @__PURE__ */ jsx(Fragment, { children: renderNode(ast, { components }) });
871
1576
  }
872
1577
  var Djot_default = Djot;
873
1578
 
874
- export { Djot, Djot_default as default, renderNode };
1579
+ export { Djot, compileDjot, Djot_default as default, renderNode };
875
1580
  //# sourceMappingURL=index.js.map
876
1581
  //# sourceMappingURL=index.js.map