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