@readme/markdown 13.7.3 → 13.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/main.js CHANGED
@@ -11873,6 +11873,8 @@ const GlossaryContext = (0,external_amd_react_commonjs_react_commonjs2_react_roo
11873
11873
 
11874
11874
  const Glossary = ({ children, term: termProp, terms }) => {
11875
11875
  const term = (Array.isArray(children) ? children[0] : children) || termProp;
11876
+ if (!term)
11877
+ return null;
11876
11878
  const foundTerm = terms.find(i => term.toLowerCase() === i?.term?.toLowerCase());
11877
11879
  if (!foundTerm)
11878
11880
  return external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default().createElement("span", null, term);
@@ -12068,13 +12070,91 @@ const Table = (props) => {
12068
12070
 
12069
12071
  ;// ./components/TableOfContents/index.tsx
12070
12072
 
12071
- function TableOfContents({ children, heading = 'Table of Contents' }) {
12072
- return (external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default().createElement("nav", { "aria-label": "Table of contents", role: "navigation" },
12073
+ /**
12074
+ * Build link map and decode the hash to get the id and weird chars
12075
+ */
12076
+ function buildLinkMap(nav) {
12077
+ const map = new Map();
12078
+ Array.from(nav.querySelectorAll('a')).forEach(link => {
12079
+ const id = decodeURIComponent(link.hash.slice(1));
12080
+ if (!id)
12081
+ return;
12082
+ const list = map.get(id);
12083
+ if (list)
12084
+ list.push(link);
12085
+ else
12086
+ map.set(id, [link]);
12087
+ });
12088
+ return map;
12089
+ }
12090
+ /**
12091
+ * Watches headings in the viewport and toggles `active` on the
12092
+ * corresponding TOC links so the reader always knows where they are.
12093
+ */
12094
+ function useScrollHighlight(navRef) {
12095
+ const [linkCount, setLinkCount] = (0,external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_.useState)(0);
12096
+ (0,external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_.useEffect)(() => {
12097
+ const nav = navRef.current;
12098
+ if (!nav)
12099
+ return;
12100
+ const count = nav.querySelectorAll('a[href^="#"]').length;
12101
+ setLinkCount(count);
12102
+ }, [navRef]);
12103
+ (0,external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_.useEffect)(() => {
12104
+ const nav = navRef.current;
12105
+ if (!nav || typeof IntersectionObserver === 'undefined' || linkCount === 0)
12106
+ return undefined;
12107
+ const linkMap = buildLinkMap(nav);
12108
+ if (linkMap.size === 0)
12109
+ return undefined;
12110
+ const headings = [...linkMap.keys()]
12111
+ .map(id => document.getElementById(id))
12112
+ .filter((el) => el !== null);
12113
+ if (headings.length === 0)
12114
+ return undefined;
12115
+ let activeId = null;
12116
+ const visible = new Set();
12117
+ const activate = (id) => {
12118
+ if (id === activeId)
12119
+ return;
12120
+ if (activeId)
12121
+ linkMap.get(activeId)?.forEach(a => a.classList.remove('active'));
12122
+ activeId = id;
12123
+ // set active states + border pos/size
12124
+ if (id) {
12125
+ const links = linkMap.get(id);
12126
+ links?.forEach(a => a.classList.add('active'));
12127
+ const link = links?.[0];
12128
+ if (link) {
12129
+ const navRect = nav.getBoundingClientRect();
12130
+ const linkRect = link.getBoundingClientRect();
12131
+ nav.style.setProperty('--ToC-border-active-height', `${linkRect.height}px`);
12132
+ nav.style.setProperty('--ToC-border-active-top', `${linkRect.top - navRect.top}px`);
12133
+ }
12134
+ }
12135
+ };
12136
+ const observer = new IntersectionObserver(entries => {
12137
+ entries.forEach(e => {
12138
+ if (e.isIntersecting)
12139
+ visible.add(e.target.id);
12140
+ else
12141
+ visible.delete(e.target.id);
12142
+ });
12143
+ // Highlight the topmost visible heading; if none are visible,
12144
+ // keep the last active one so the user still has context.
12145
+ const topmost = headings.find(el => visible.has(el.id));
12146
+ if (topmost)
12147
+ activate(topmost.id);
12148
+ }, { rootMargin: '0px 0px -60% 0px', threshold: 0 });
12149
+ headings.forEach(el => { observer.observe(el); });
12150
+ return () => { observer.disconnect(); };
12151
+ }, [navRef, linkCount]);
12152
+ }
12153
+ function TableOfContents({ children }) {
12154
+ const navRef = (0,external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_.useRef)(null);
12155
+ useScrollHighlight(navRef);
12156
+ return (external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default().createElement("nav", { ref: navRef, "aria-label": "Table of contents", className: "rm-ToC" },
12073
12157
  external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default().createElement("ul", { className: "toc-list" },
12074
- external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default().createElement("li", null,
12075
- external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default().createElement("a", { className: "tocHeader", href: "#" },
12076
- external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default().createElement("i", { className: "icon icon-text-align-left" }),
12077
- heading)),
12078
12158
  external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default().createElement("li", { className: "toc-children" }, children))));
12079
12159
  }
12080
12160
  /* harmony default export */ const components_TableOfContents = (TableOfContents);
@@ -12342,19 +12422,10 @@ const TailwindStyle = ({ children, darkModeDataAttribute }) => {
12342
12422
  records.forEach(record => {
12343
12423
  if (record.type === 'childList') {
12344
12424
  record.addedNodes.forEach(node => {
12345
- if (!(node instanceof HTMLElement))
12425
+ if (!(node instanceof HTMLElement) || !node.classList.contains(tailwindPrefix))
12346
12426
  return;
12347
- // Check the added node itself
12348
- if (node.classList.contains(tailwindPrefix)) {
12349
- traverse(node, addClasses);
12350
- shouldUpdate = true;
12351
- }
12352
- // Also check descendants — React may insert a parent node
12353
- // whose children contain TailwindRoot elements
12354
- node.querySelectorAll(`.${tailwindPrefix}`).forEach(child => {
12355
- traverse(child, addClasses);
12356
- shouldUpdate = true;
12357
- });
12427
+ traverse(node, addClasses);
12428
+ shouldUpdate = true;
12358
12429
  });
12359
12430
  }
12360
12431
  else if (record.type === 'attributes') {
@@ -52989,6 +53060,10 @@ const plain = (node, opts = {}) => {
52989
53060
  };
52990
53061
  /* harmony default export */ const lib_plain = (plain);
52991
53062
 
53063
+ ;// ./processor/compile/gemoji.ts
53064
+ const gemoji = (node) => `:${node.name}:`;
53065
+ /* harmony default export */ const compile_gemoji = (gemoji);
53066
+
52992
53067
  ;// ./processor/compile/variable.ts
52993
53068
  const variable = (node) => `{user.${node.data?.hProperties?.name || ''}}`;
52994
53069
  /* harmony default export */ const compile_variable = (variable);
@@ -53039,6 +53114,7 @@ const extractText = (node) => {
53039
53114
 
53040
53115
 
53041
53116
 
53117
+
53042
53118
  const titleParser = unified().use(remarkParse).use(remarkGfm);
53043
53119
  // The title paragraph may contain custom AST nodes that `toMarkdown` doesn't
53044
53120
  // natively understand
@@ -53046,8 +53122,8 @@ const toMarkdownExtensions = [
53046
53122
  gfmToMarkdown(),
53047
53123
  // For mdx variable syntaxes (e.g., {user.name})
53048
53124
  mdxExpressionToMarkdown(),
53049
- // Important: This is required and would crash the parser if there's no variable node handler
53050
- { handlers: { [NodeTypes.variable]: compile_variable } },
53125
+ // Important: This is required and would crash the parser if there's no variable and gemoji node handler
53126
+ { handlers: { [NodeTypes.variable]: compile_variable, [NodeTypes.emoji]: compile_gemoji } },
53051
53127
  ];
53052
53128
  const callouts_regex = `^(${emoji_regex().source}|⚠)(\\s+|$)`;
53053
53129
  const findFirst = (node) => {
@@ -53442,7 +53518,7 @@ const embedTransformer = () => {
53442
53518
  *
53443
53519
  * @type {Array<Gemoji>}
53444
53520
  */
53445
- const gemoji = [
53521
+ const gemoji_gemoji = [
53446
53522
  {
53447
53523
  emoji: '😀',
53448
53524
  names: ['grinning'],
@@ -70385,7 +70461,7 @@ class Owlmoji {
70385
70461
  return null;
70386
70462
  };
70387
70463
  static nameToEmoji = nameToEmoji;
70388
- static owlmoji = gemoji.concat(owlmoji);
70464
+ static owlmoji = gemoji_gemoji.concat(owlmoji);
70389
70465
  }
70390
70466
 
70391
70467
  ;// ./processor/transform/gemoji+.ts
@@ -71295,6 +71371,316 @@ const mdxToHast = () => tree => {
71295
71371
  };
71296
71372
  /* harmony default export */ const mdx_to_hast = (mdxToHast);
71297
71373
 
71374
+ ;// ./lib/mdast-util/gemoji/index.ts
71375
+
71376
+
71377
+ function exitGemoji(token) {
71378
+ const name = this.sliceSerialize(token).slice(1, -1); // strip surrounding colons
71379
+ switch (Owlmoji.kind(name)) {
71380
+ case 'gemoji': {
71381
+ this.enter({ type: NodeTypes.emoji, value: Owlmoji.nameToEmoji[name], name }, token);
71382
+ this.exit(token);
71383
+ break;
71384
+ }
71385
+ case 'fontawesome': {
71386
+ this.enter({
71387
+ type: NodeTypes.i,
71388
+ value: name,
71389
+ data: { hName: 'i', hProperties: { className: ['fa-regular', name] } },
71390
+ }, token);
71391
+ this.exit(token);
71392
+ break;
71393
+ }
71394
+ case 'owlmoji': {
71395
+ this.enter({
71396
+ type: NodeTypes.emoji,
71397
+ value: `:${name}:`,
71398
+ name,
71399
+ data: {
71400
+ hName: 'img',
71401
+ hProperties: {
71402
+ src: `/public/img/emojis/${name}.png`,
71403
+ alt: `:${name}:`,
71404
+ title: `:${name}:`,
71405
+ className: 'emoji',
71406
+ align: 'absmiddle',
71407
+ height: '20',
71408
+ width: '20',
71409
+ },
71410
+ },
71411
+ }, token);
71412
+ this.exit(token);
71413
+ break;
71414
+ }
71415
+ default: {
71416
+ // Unknown shortcode, emit as literal text `:name:`
71417
+ this.enter({ type: 'text', value: `:${name}:` }, token);
71418
+ this.exit(token);
71419
+ break;
71420
+ }
71421
+ }
71422
+ }
71423
+ function gemojiFromMarkdown() {
71424
+ return {
71425
+ exit: {
71426
+ gemoji: exitGemoji,
71427
+ },
71428
+ };
71429
+ }
71430
+
71431
+ ;// ./node_modules/micromark-util-symbol/lib/codes.js
71432
+ /**
71433
+ * Character codes.
71434
+ *
71435
+ * This module is compiled away!
71436
+ *
71437
+ * micromark works based on character codes.
71438
+ * This module contains constants for the ASCII block and the replacement
71439
+ * character.
71440
+ * A couple of them are handled in a special way, such as the line endings
71441
+ * (CR, LF, and CR+LF, commonly known as end-of-line: EOLs), the tab (horizontal
71442
+ * tab) and its expansion based on what column it’s at (virtual space),
71443
+ * and the end-of-file (eof) character.
71444
+ * As values are preprocessed before handling them, the actual characters LF,
71445
+ * CR, HT, and NUL (which is present as the replacement character), are
71446
+ * guaranteed to not exist.
71447
+ *
71448
+ * Unicode basic latin block.
71449
+ */
71450
+ const codes = /** @type {const} */ ({
71451
+ carriageReturn: -5,
71452
+ lineFeed: -4,
71453
+ carriageReturnLineFeed: -3,
71454
+ horizontalTab: -2,
71455
+ virtualSpace: -1,
71456
+ eof: null,
71457
+ nul: 0,
71458
+ soh: 1,
71459
+ stx: 2,
71460
+ etx: 3,
71461
+ eot: 4,
71462
+ enq: 5,
71463
+ ack: 6,
71464
+ bel: 7,
71465
+ bs: 8,
71466
+ ht: 9, // `\t`
71467
+ lf: 10, // `\n`
71468
+ vt: 11, // `\v`
71469
+ ff: 12, // `\f`
71470
+ cr: 13, // `\r`
71471
+ so: 14,
71472
+ si: 15,
71473
+ dle: 16,
71474
+ dc1: 17,
71475
+ dc2: 18,
71476
+ dc3: 19,
71477
+ dc4: 20,
71478
+ nak: 21,
71479
+ syn: 22,
71480
+ etb: 23,
71481
+ can: 24,
71482
+ em: 25,
71483
+ sub: 26,
71484
+ esc: 27,
71485
+ fs: 28,
71486
+ gs: 29,
71487
+ rs: 30,
71488
+ us: 31,
71489
+ space: 32,
71490
+ exclamationMark: 33, // `!`
71491
+ quotationMark: 34, // `"`
71492
+ numberSign: 35, // `#`
71493
+ dollarSign: 36, // `$`
71494
+ percentSign: 37, // `%`
71495
+ ampersand: 38, // `&`
71496
+ apostrophe: 39, // `'`
71497
+ leftParenthesis: 40, // `(`
71498
+ rightParenthesis: 41, // `)`
71499
+ asterisk: 42, // `*`
71500
+ plusSign: 43, // `+`
71501
+ comma: 44, // `,`
71502
+ dash: 45, // `-`
71503
+ dot: 46, // `.`
71504
+ slash: 47, // `/`
71505
+ digit0: 48, // `0`
71506
+ digit1: 49, // `1`
71507
+ digit2: 50, // `2`
71508
+ digit3: 51, // `3`
71509
+ digit4: 52, // `4`
71510
+ digit5: 53, // `5`
71511
+ digit6: 54, // `6`
71512
+ digit7: 55, // `7`
71513
+ digit8: 56, // `8`
71514
+ digit9: 57, // `9`
71515
+ colon: 58, // `:`
71516
+ semicolon: 59, // `;`
71517
+ lessThan: 60, // `<`
71518
+ equalsTo: 61, // `=`
71519
+ greaterThan: 62, // `>`
71520
+ questionMark: 63, // `?`
71521
+ atSign: 64, // `@`
71522
+ uppercaseA: 65, // `A`
71523
+ uppercaseB: 66, // `B`
71524
+ uppercaseC: 67, // `C`
71525
+ uppercaseD: 68, // `D`
71526
+ uppercaseE: 69, // `E`
71527
+ uppercaseF: 70, // `F`
71528
+ uppercaseG: 71, // `G`
71529
+ uppercaseH: 72, // `H`
71530
+ uppercaseI: 73, // `I`
71531
+ uppercaseJ: 74, // `J`
71532
+ uppercaseK: 75, // `K`
71533
+ uppercaseL: 76, // `L`
71534
+ uppercaseM: 77, // `M`
71535
+ uppercaseN: 78, // `N`
71536
+ uppercaseO: 79, // `O`
71537
+ uppercaseP: 80, // `P`
71538
+ uppercaseQ: 81, // `Q`
71539
+ uppercaseR: 82, // `R`
71540
+ uppercaseS: 83, // `S`
71541
+ uppercaseT: 84, // `T`
71542
+ uppercaseU: 85, // `U`
71543
+ uppercaseV: 86, // `V`
71544
+ uppercaseW: 87, // `W`
71545
+ uppercaseX: 88, // `X`
71546
+ uppercaseY: 89, // `Y`
71547
+ uppercaseZ: 90, // `Z`
71548
+ leftSquareBracket: 91, // `[`
71549
+ backslash: 92, // `\`
71550
+ rightSquareBracket: 93, // `]`
71551
+ caret: 94, // `^`
71552
+ underscore: 95, // `_`
71553
+ graveAccent: 96, // `` ` ``
71554
+ lowercaseA: 97, // `a`
71555
+ lowercaseB: 98, // `b`
71556
+ lowercaseC: 99, // `c`
71557
+ lowercaseD: 100, // `d`
71558
+ lowercaseE: 101, // `e`
71559
+ lowercaseF: 102, // `f`
71560
+ lowercaseG: 103, // `g`
71561
+ lowercaseH: 104, // `h`
71562
+ lowercaseI: 105, // `i`
71563
+ lowercaseJ: 106, // `j`
71564
+ lowercaseK: 107, // `k`
71565
+ lowercaseL: 108, // `l`
71566
+ lowercaseM: 109, // `m`
71567
+ lowercaseN: 110, // `n`
71568
+ lowercaseO: 111, // `o`
71569
+ lowercaseP: 112, // `p`
71570
+ lowercaseQ: 113, // `q`
71571
+ lowercaseR: 114, // `r`
71572
+ lowercaseS: 115, // `s`
71573
+ lowercaseT: 116, // `t`
71574
+ lowercaseU: 117, // `u`
71575
+ lowercaseV: 118, // `v`
71576
+ lowercaseW: 119, // `w`
71577
+ lowercaseX: 120, // `x`
71578
+ lowercaseY: 121, // `y`
71579
+ lowercaseZ: 122, // `z`
71580
+ leftCurlyBrace: 123, // `{`
71581
+ verticalBar: 124, // `|`
71582
+ rightCurlyBrace: 125, // `}`
71583
+ tilde: 126, // `~`
71584
+ del: 127,
71585
+ // Unicode Specials block.
71586
+ byteOrderMarker: 65_279,
71587
+ // Unicode Specials block.
71588
+ replacementCharacter: 65_533 // `�`
71589
+ })
71590
+
71591
+ ;// ./lib/micromark/gemoji/syntax.ts
71592
+
71593
+ // Matches the name pattern from the original regex: \+1 or [-\w]+
71594
+ // see https://github.com/readmeio/markdown/blob/489a71e19b34f640595ce81e988dad631045186f/processor/transform/gemoji%2B.ts#L9
71595
+ function isNameChar(code) {
71596
+ if (code === null)
71597
+ return false;
71598
+ return ((code >= codes.lowercaseA && code <= codes.lowercaseZ) ||
71599
+ (code >= codes.uppercaseA && code <= codes.uppercaseZ) ||
71600
+ (code >= codes.digit0 && code <= codes.digit9) ||
71601
+ code === codes.dash ||
71602
+ code === codes.underscore);
71603
+ }
71604
+ const gemojiConstruct = {
71605
+ name: 'gemoji',
71606
+ tokenize,
71607
+ };
71608
+ function tokenize(effects, ok, nok) {
71609
+ let hasName = false;
71610
+ // Entry point — expect opening `:`
71611
+ const start = (code) => {
71612
+ if (code !== codes.colon)
71613
+ return nok(code);
71614
+ effects.enter('gemoji');
71615
+ effects.enter('gemojiMarker');
71616
+ effects.consume(code); // :
71617
+ effects.exit('gemojiMarker');
71618
+ effects.enter('gemojiName');
71619
+ return nameStart;
71620
+ };
71621
+ // First char after `:`, branch on `+` for :+1:, otherwise start normal name
71622
+ const nameStart = (code) => {
71623
+ if (code === codes.plusSign) {
71624
+ effects.consume(code); // +
71625
+ return plusOne;
71626
+ }
71627
+ if (isNameChar(code)) {
71628
+ hasName = true;
71629
+ effects.consume(code);
71630
+ return name;
71631
+ }
71632
+ // Not a valid shortcode start (e.g. `::`, `: `, `:<`)
71633
+ return nok(code);
71634
+ };
71635
+ // After `+`, only `1` is valid (for :+1:), anything else rejects
71636
+ // this is a special case for :+1: 👍 since + isnt a normal name character
71637
+ const plusOne = (code) => {
71638
+ if (code === codes.digit1) {
71639
+ hasName = true;
71640
+ effects.consume(code); // 1
71641
+ return nameEnd;
71642
+ }
71643
+ return nok(code);
71644
+ };
71645
+ // Consume name characters until we hit closing `:` or an invalid char
71646
+ const name = (code) => {
71647
+ if (code === codes.colon) {
71648
+ if (!hasName)
71649
+ return nok(code);
71650
+ return nameEnd(code);
71651
+ }
71652
+ if (isNameChar(code)) {
71653
+ effects.consume(code);
71654
+ return name;
71655
+ }
71656
+ // Invalid character in name (space, newline, special char) — reject
71657
+ return nok(code);
71658
+ };
71659
+ // Expect closing `:`
71660
+ const nameEnd = (code) => {
71661
+ if (code !== codes.colon)
71662
+ return nok(code);
71663
+ effects.exit('gemojiName');
71664
+ effects.enter('gemojiMarker');
71665
+ effects.consume(code); // :
71666
+ effects.exit('gemojiMarker');
71667
+ effects.exit('gemoji');
71668
+ return ok;
71669
+ };
71670
+ return start;
71671
+ }
71672
+ function syntax_gemoji() {
71673
+ return {
71674
+ text: { [codes.colon]: gemojiConstruct },
71675
+ };
71676
+ }
71677
+
71678
+ ;// ./lib/micromark/gemoji/index.ts
71679
+ /**
71680
+ * Micromark extension for :emoji: inline syntax.
71681
+ */
71682
+
71683
+
71298
71684
  ;// ./processor/transform/mdxish/normalize-malformed-md-syntax.ts
71299
71685
 
71300
71686
  // Marker patterns for multi-node emphasis detection
@@ -71651,6 +72037,7 @@ const normalizeEmphasisAST = () => (tree) => {
71651
72037
 
71652
72038
 
71653
72039
 
72040
+
71654
72041
  const isTableCell = (node) => isMDXElement(node) && ['th', 'td'].includes(node.name);
71655
72042
  const tableTypes = {
71656
72043
  tr: 'tableRow',
@@ -71658,10 +72045,12 @@ const tableTypes = {
71658
72045
  td: 'tableCell',
71659
72046
  };
71660
72047
  const tableNodeProcessor = unified()
72048
+ .data('micromarkExtensions', [syntax_gemoji()])
72049
+ .data('fromMarkdownExtensions', [gemojiFromMarkdown()])
71661
72050
  .use(remarkParse)
71662
72051
  .use(remarkMdx)
71663
72052
  .use(normalize_malformed_md_syntax)
71664
- .use([[callouts, { isMdxish: true }], gemoji_, code_tabs])
72053
+ .use([[callouts, { isMdxish: true }], code_tabs])
71665
72054
  .use(remarkGfm);
71666
72055
  /**
71667
72056
  * Check if children are only text nodes that might contain markdown
@@ -72534,7 +72923,6 @@ const mdxishTransformers = [
72534
72923
  [callouts, { isMdxish: true }],
72535
72924
  code_tabs,
72536
72925
  transform_images,
72537
- gemoji_,
72538
72926
  ];
72539
72927
  /* harmony default export */ const transform = (Object.values(defaultTransforms));
72540
72928
 
@@ -92316,10 +92704,6 @@ const embed_embed = (node) => {
92316
92704
  };
92317
92705
  /* harmony default export */ const compile_embed = (embed_embed);
92318
92706
 
92319
- ;// ./processor/compile/gemoji.ts
92320
- const gemoji_gemoji = (node) => `:${node.name}:`;
92321
- /* harmony default export */ const compile_gemoji = (gemoji_gemoji);
92322
-
92323
92707
  ;// ./processor/compile/html-block.ts
92324
92708
 
92325
92709
  const htmlBlock = (node) => {
@@ -94302,6 +94686,86 @@ const mdxComponentHandlers = {
94302
94686
  [NodeTypes.htmlBlock]: htmlBlockHandler,
94303
94687
  };
94304
94688
 
94689
+ ;// ./processor/transform/mdxish/close-self-closing-html-tags.ts
94690
+
94691
+ /**
94692
+ * HTML void elements that are legitimately self-closing per the HTML spec.
94693
+ * These should NOT be transformed.
94694
+ *
94695
+ * @see https://html.spec.whatwg.org/multipage/syntax.html#void-elements
94696
+ */
94697
+ const HTML_VOID_ELEMENTS = new Set([
94698
+ 'area',
94699
+ 'base',
94700
+ 'br',
94701
+ 'col',
94702
+ 'embed',
94703
+ 'hr',
94704
+ 'img',
94705
+ 'input',
94706
+ 'link',
94707
+ 'meta',
94708
+ 'param',
94709
+ 'source',
94710
+ 'track',
94711
+ 'wbr',
94712
+ ]);
94713
+ /**
94714
+ * Matches self-closing HTML tags: `<tagname/>` or `<tagname attr="val" />`
94715
+ *
94716
+ * Captures:
94717
+ * 1 - tag name (lowercase letters, digits, hyphens)
94718
+ * 2 - attributes (everything between tag name and `/>`)
94719
+ *
94720
+ * The attribute portion skips over quoted strings (`"..."` and `'...'`) so that
94721
+ * a `/>` inside an attribute value (e.g. `title="use /> here"`) does not cause
94722
+ * a premature match.
94723
+ *
94724
+ * Only matches lowercase tag names to avoid interfering with PascalCase
94725
+ * JSX custom components (e.g. `<MyComponent />`), which are handled
94726
+ * separately by mdxish-component-blocks.
94727
+ */
94728
+ const SELF_CLOSING_TAG_RE = /<([a-z][a-z0-9-]*)((?:\s+(?:[^>"']*(?:"[^"]*"|'[^']*'))*[^>"']*)?)?\s*\/>/g;
94729
+ /**
94730
+ * String-level preprocessor that converts self-closing non-void HTML tags
94731
+ * into explicitly closed tags.
94732
+ *
94733
+ * Problem: `rehype-raw` (via parse5) follows the HTML spec where the `/` in
94734
+ * `<i />` is ignored for non-void elements. This causes `<i />` to be parsed
94735
+ * as an opening `<i>` tag, which then wraps all subsequent content.
94736
+ *
94737
+ * Solution: Transform `<i />` → `<i></i>` before parsing, so rehype-raw
94738
+ * sees a properly closed element.
94739
+ *
94740
+ * This preprocessor:
94741
+ * - Skips void elements (`<br />`, `<hr />`, `<img />`, etc.)
94742
+ * - Skips PascalCase tags (custom components handled elsewhere)
94743
+ * - Protects code blocks from transformation
94744
+ *
94745
+ * @example
94746
+ * closeSelfClosingHtmlTags('<i/> text') // '<i></i> text'
94747
+ * closeSelfClosingHtmlTags('<br />') // '<br />' (void, untouched)
94748
+ * closeSelfClosingHtmlTags('<MyComp />') // '<MyComp />' (PascalCase, untouched)
94749
+ * closeSelfClosingHtmlTags('<i class="icon" />') // '<i class="icon"></i>'
94750
+ */
94751
+ function closeSelfClosingHtmlTags(content) {
94752
+ const { protectedContent, protectedCode } = protectCodeBlocks(content);
94753
+ const result = protectedContent.replace(SELF_CLOSING_TAG_RE, (match, tagName, attrs) => {
94754
+ // Skip void elements (legitimately self-closing)
94755
+ if (HTML_VOID_ELEMENTS.has(tagName)) {
94756
+ return match;
94757
+ }
94758
+ // Skip tags with hyphens — these are custom elements (web components)
94759
+ // and should not be rewritten (e.g. <my-component />)
94760
+ if (tagName.includes('-')) {
94761
+ return match;
94762
+ }
94763
+ const attributes = attrs?.trim() ? ` ${attrs.trim()}` : '';
94764
+ return `<${tagName}${attributes}></${tagName}>`;
94765
+ });
94766
+ return restoreCodeBlocks(result, protectedCode);
94767
+ }
94768
+
94305
94769
  ;// ./processor/transform/mdxish/evaluate-expressions.ts
94306
94770
 
94307
94771
 
@@ -94591,166 +95055,6 @@ function legacyVariableFromMarkdown() {
94591
95055
  };
94592
95056
  }
94593
95057
 
94594
- ;// ./node_modules/micromark-util-symbol/lib/codes.js
94595
- /**
94596
- * Character codes.
94597
- *
94598
- * This module is compiled away!
94599
- *
94600
- * micromark works based on character codes.
94601
- * This module contains constants for the ASCII block and the replacement
94602
- * character.
94603
- * A couple of them are handled in a special way, such as the line endings
94604
- * (CR, LF, and CR+LF, commonly known as end-of-line: EOLs), the tab (horizontal
94605
- * tab) and its expansion based on what column it’s at (virtual space),
94606
- * and the end-of-file (eof) character.
94607
- * As values are preprocessed before handling them, the actual characters LF,
94608
- * CR, HT, and NUL (which is present as the replacement character), are
94609
- * guaranteed to not exist.
94610
- *
94611
- * Unicode basic latin block.
94612
- */
94613
- const codes = /** @type {const} */ ({
94614
- carriageReturn: -5,
94615
- lineFeed: -4,
94616
- carriageReturnLineFeed: -3,
94617
- horizontalTab: -2,
94618
- virtualSpace: -1,
94619
- eof: null,
94620
- nul: 0,
94621
- soh: 1,
94622
- stx: 2,
94623
- etx: 3,
94624
- eot: 4,
94625
- enq: 5,
94626
- ack: 6,
94627
- bel: 7,
94628
- bs: 8,
94629
- ht: 9, // `\t`
94630
- lf: 10, // `\n`
94631
- vt: 11, // `\v`
94632
- ff: 12, // `\f`
94633
- cr: 13, // `\r`
94634
- so: 14,
94635
- si: 15,
94636
- dle: 16,
94637
- dc1: 17,
94638
- dc2: 18,
94639
- dc3: 19,
94640
- dc4: 20,
94641
- nak: 21,
94642
- syn: 22,
94643
- etb: 23,
94644
- can: 24,
94645
- em: 25,
94646
- sub: 26,
94647
- esc: 27,
94648
- fs: 28,
94649
- gs: 29,
94650
- rs: 30,
94651
- us: 31,
94652
- space: 32,
94653
- exclamationMark: 33, // `!`
94654
- quotationMark: 34, // `"`
94655
- numberSign: 35, // `#`
94656
- dollarSign: 36, // `$`
94657
- percentSign: 37, // `%`
94658
- ampersand: 38, // `&`
94659
- apostrophe: 39, // `'`
94660
- leftParenthesis: 40, // `(`
94661
- rightParenthesis: 41, // `)`
94662
- asterisk: 42, // `*`
94663
- plusSign: 43, // `+`
94664
- comma: 44, // `,`
94665
- dash: 45, // `-`
94666
- dot: 46, // `.`
94667
- slash: 47, // `/`
94668
- digit0: 48, // `0`
94669
- digit1: 49, // `1`
94670
- digit2: 50, // `2`
94671
- digit3: 51, // `3`
94672
- digit4: 52, // `4`
94673
- digit5: 53, // `5`
94674
- digit6: 54, // `6`
94675
- digit7: 55, // `7`
94676
- digit8: 56, // `8`
94677
- digit9: 57, // `9`
94678
- colon: 58, // `:`
94679
- semicolon: 59, // `;`
94680
- lessThan: 60, // `<`
94681
- equalsTo: 61, // `=`
94682
- greaterThan: 62, // `>`
94683
- questionMark: 63, // `?`
94684
- atSign: 64, // `@`
94685
- uppercaseA: 65, // `A`
94686
- uppercaseB: 66, // `B`
94687
- uppercaseC: 67, // `C`
94688
- uppercaseD: 68, // `D`
94689
- uppercaseE: 69, // `E`
94690
- uppercaseF: 70, // `F`
94691
- uppercaseG: 71, // `G`
94692
- uppercaseH: 72, // `H`
94693
- uppercaseI: 73, // `I`
94694
- uppercaseJ: 74, // `J`
94695
- uppercaseK: 75, // `K`
94696
- uppercaseL: 76, // `L`
94697
- uppercaseM: 77, // `M`
94698
- uppercaseN: 78, // `N`
94699
- uppercaseO: 79, // `O`
94700
- uppercaseP: 80, // `P`
94701
- uppercaseQ: 81, // `Q`
94702
- uppercaseR: 82, // `R`
94703
- uppercaseS: 83, // `S`
94704
- uppercaseT: 84, // `T`
94705
- uppercaseU: 85, // `U`
94706
- uppercaseV: 86, // `V`
94707
- uppercaseW: 87, // `W`
94708
- uppercaseX: 88, // `X`
94709
- uppercaseY: 89, // `Y`
94710
- uppercaseZ: 90, // `Z`
94711
- leftSquareBracket: 91, // `[`
94712
- backslash: 92, // `\`
94713
- rightSquareBracket: 93, // `]`
94714
- caret: 94, // `^`
94715
- underscore: 95, // `_`
94716
- graveAccent: 96, // `` ` ``
94717
- lowercaseA: 97, // `a`
94718
- lowercaseB: 98, // `b`
94719
- lowercaseC: 99, // `c`
94720
- lowercaseD: 100, // `d`
94721
- lowercaseE: 101, // `e`
94722
- lowercaseF: 102, // `f`
94723
- lowercaseG: 103, // `g`
94724
- lowercaseH: 104, // `h`
94725
- lowercaseI: 105, // `i`
94726
- lowercaseJ: 106, // `j`
94727
- lowercaseK: 107, // `k`
94728
- lowercaseL: 108, // `l`
94729
- lowercaseM: 109, // `m`
94730
- lowercaseN: 110, // `n`
94731
- lowercaseO: 111, // `o`
94732
- lowercaseP: 112, // `p`
94733
- lowercaseQ: 113, // `q`
94734
- lowercaseR: 114, // `r`
94735
- lowercaseS: 115, // `s`
94736
- lowercaseT: 116, // `t`
94737
- lowercaseU: 117, // `u`
94738
- lowercaseV: 118, // `v`
94739
- lowercaseW: 119, // `w`
94740
- lowercaseX: 120, // `x`
94741
- lowercaseY: 121, // `y`
94742
- lowercaseZ: 122, // `z`
94743
- leftCurlyBrace: 123, // `{`
94744
- verticalBar: 124, // `|`
94745
- rightCurlyBrace: 125, // `}`
94746
- tilde: 126, // `~`
94747
- del: 127,
94748
- // Unicode Specials block.
94749
- byteOrderMarker: 65_279,
94750
- // Unicode Specials block.
94751
- replacementCharacter: 65_533 // `�`
94752
- })
94753
-
94754
95058
  ;// ./lib/micromark/legacy-variable/syntax.ts
94755
95059
 
94756
95060
 
@@ -94762,9 +95066,9 @@ function isAllowedValueChar(code) {
94762
95066
  }
94763
95067
  const legacyVariableConstruct = {
94764
95068
  name: 'legacyVariable',
94765
- tokenize,
95069
+ tokenize: syntax_tokenize,
94766
95070
  };
94767
- function tokenize(effects, ok, nok) {
95071
+ function syntax_tokenize(effects, ok, nok) {
94768
95072
  let hasValue = false;
94769
95073
  const start = (code) => {
94770
95074
  if (code !== codes.lessThan)
@@ -95903,6 +96207,8 @@ const EMPTY_CODE_PLACEHOLDER = {
95903
96207
 
95904
96208
 
95905
96209
 
96210
+
96211
+
95906
96212
 
95907
96213
 
95908
96214
 
@@ -95945,8 +96251,8 @@ const preprocessBody = (text) => {
95945
96251
  };
95946
96252
  /** Markdown parser */
95947
96253
  const contentParser = unified()
95948
- .data('micromarkExtensions', [legacyVariable(), looseHtmlEntity()])
95949
- .data('fromMarkdownExtensions', [legacyVariableFromMarkdown(), emptyTaskListItemFromMarkdown(), looseHtmlEntityFromMarkdown()])
96254
+ .data('micromarkExtensions', [syntax_gemoji(), legacyVariable(), looseHtmlEntity()])
96255
+ .data('fromMarkdownExtensions', [gemojiFromMarkdown(), legacyVariableFromMarkdown(), emptyTaskListItemFromMarkdown(), looseHtmlEntityFromMarkdown()])
95950
96256
  .use(remarkParse)
95951
96257
  .use(remarkBreaks)
95952
96258
  .use(remarkGfm)
@@ -95959,8 +96265,8 @@ const contentParser = unified()
95959
96265
  * such as `<ul><li>https://a</li>\n</ul>` due to subtokenizing recursion for URLs
95960
96266
  */
95961
96267
  const markdownToHtml = unified()
95962
- .data('micromarkExtensions', [gfmStrikethrough(), legacyVariable(), looseHtmlEntity()])
95963
- .data('fromMarkdownExtensions', [gfmStrikethroughFromMarkdown(), legacyVariableFromMarkdown(), emptyTaskListItemFromMarkdown(), looseHtmlEntityFromMarkdown()])
96268
+ .data('micromarkExtensions', [gfmStrikethrough(), syntax_gemoji(), legacyVariable(), looseHtmlEntity()])
96269
+ .data('fromMarkdownExtensions', [gfmStrikethroughFromMarkdown(), gemojiFromMarkdown(), legacyVariableFromMarkdown(), emptyTaskListItemFromMarkdown(), looseHtmlEntityFromMarkdown()])
95964
96270
  .use(remarkParse)
95965
96271
  .use(normalize_malformed_md_syntax)
95966
96272
  .use(remarkRehype)
@@ -96101,6 +96407,7 @@ const parseBlock = (text) => {
96101
96407
  */
96102
96408
  const apiHeaderTitleParser = unified()
96103
96409
  .data('micromarkExtensions', [
96410
+ syntax_gemoji(),
96104
96411
  legacyVariable(),
96105
96412
  looseHtmlEntity(),
96106
96413
  {
@@ -96114,7 +96421,7 @@ const apiHeaderTitleParser = unified()
96114
96421
  },
96115
96422
  },
96116
96423
  ])
96117
- .data('fromMarkdownExtensions', [legacyVariableFromMarkdown(), looseHtmlEntityFromMarkdown()])
96424
+ .data('fromMarkdownExtensions', [gemojiFromMarkdown(), legacyVariableFromMarkdown(), looseHtmlEntityFromMarkdown()])
96118
96425
  .use(remarkParse)
96119
96426
  .use(remarkGfm);
96120
96427
  const parseApiHeaderTitle = (text) => {
@@ -97228,6 +97535,179 @@ function mdxish_jsx_to_mdast_extractText(nodes) {
97228
97535
  })
97229
97536
  .join('');
97230
97537
  }
97538
+ const FIGURE_OPEN_REGEX = /^<figure(\s[^>]*)?>$/;
97539
+ const FIGURE_CLOSE_REGEX = /^\s*<\/figure>\s*$/;
97540
+ const FIGURE_COMPLETE_REGEX = /^<figure(\s[^>]*)?>[\s\S]*<\/figure>\s*$/;
97541
+ const FIGCAPTION_REGEX = /<figcaption>(.*?)<\/figcaption>/s;
97542
+ const FIGCAPTION_OPEN_REGEX = /^<figcaption>$/;
97543
+ const FIGCAPTION_CLOSE_REGEX = /^<\/figcaption>$/;
97544
+ /**
97545
+ * Extracts an image or image-block from a node. If the node itself is an image/image-block,
97546
+ * it is returned directly. If the node is a paragraph, its children are searched for one.
97547
+ * This is needed because standalone markdown images (`![](url)`) may be wrapped in a
97548
+ * paragraph node by the parser, or already transformed to image-block by imageTransformer.
97549
+ */
97550
+ function findImageInNode(node) {
97551
+ if (node.type === 'image' || node.type === NodeTypes.imageBlock)
97552
+ return node;
97553
+ if (node.type === 'paragraph') {
97554
+ return node.children.find(child => child.type === 'image' || child.type === NodeTypes.imageBlock);
97555
+ }
97556
+ return undefined;
97557
+ }
97558
+ /**
97559
+ * Parses a complete `<figure>` HTML string into image URL, alt text, and optional caption.
97560
+ * Returns undefined if the HTML doesn't contain a recognizable image.
97561
+ */
97562
+ function parseCompleteFigure(html) {
97563
+ const imageMatch = /!\[([^\]]*)\]\(([^)]+)\)/.exec(html);
97564
+ if (!imageMatch)
97565
+ return undefined;
97566
+ const captionMatch = FIGCAPTION_REGEX.exec(html);
97567
+ return {
97568
+ alt: imageMatch[1],
97569
+ caption: captionMatch?.[1],
97570
+ url: imageMatch[2],
97571
+ };
97572
+ }
97573
+ /**
97574
+ * Builds a FigureNode containing an image and optional figcaption from parsed figure data.
97575
+ */
97576
+ function buildFigureNode(imageNode, captionText, position) {
97577
+ const figureChildren = [imageNode];
97578
+ if (captionText) {
97579
+ figureChildren.push({
97580
+ children: [{ type: 'text', value: captionText }],
97581
+ data: { hName: 'figcaption' },
97582
+ type: 'figcaption',
97583
+ });
97584
+ }
97585
+ return {
97586
+ children: figureChildren,
97587
+ data: { hName: 'figure' },
97588
+ position,
97589
+ type: 'figure',
97590
+ };
97591
+ }
97592
+ /**
97593
+ * Scans siblings starting at `startIndex` within a parent's children looking for the
97594
+ * figcaption text and </figure> closing tag. Handles three fragmentation patterns:
97595
+ *
97596
+ * 1. Combined: `<figcaption>Hello</figcaption>\n</figure>` in one html node
97597
+ * 2. Separate: `<figcaption>Hello</figcaption>` then `</figure>` as sibling html nodes
97598
+ * 3. Split (table cells): `<figcaption>` + text(Hello) + `</figcaption>` + `</figure>` as siblings
97599
+ */
97600
+ function scanForFigcaptionAndClose(children, startIndex) {
97601
+ let captionText;
97602
+ let endIndex = startIndex - 1;
97603
+ let foundClose = false;
97604
+ for (let j = startIndex; j < children.length; j += 1) {
97605
+ const sibling = children[j];
97606
+ const htmlValue = sibling.type === 'html' ? sibling.value : undefined;
97607
+ if (htmlValue === undefined && sibling.type !== 'text')
97608
+ break;
97609
+ // Standalone </figure>
97610
+ if (htmlValue && FIGURE_CLOSE_REGEX.test(htmlValue)) {
97611
+ endIndex = j;
97612
+ foundClose = true;
97613
+ break;
97614
+ }
97615
+ // Combined <figcaption>...</figcaption> in one node (possibly with </figure>)
97616
+ if (htmlValue) {
97617
+ const figcaptionMatch = FIGCAPTION_REGEX.exec(htmlValue);
97618
+ if (figcaptionMatch) {
97619
+ captionText = figcaptionMatch[1];
97620
+ if (FIGURE_CLOSE_REGEX.test(htmlValue.replace(FIGCAPTION_REGEX, ''))) {
97621
+ endIndex = j;
97622
+ foundClose = true;
97623
+ break;
97624
+ }
97625
+ const nextSibling = children[j + 1];
97626
+ if (nextSibling?.type === 'html' && FIGURE_CLOSE_REGEX.test(nextSibling.value)) {
97627
+ endIndex = j + 1;
97628
+ foundClose = true;
97629
+ break;
97630
+ }
97631
+ }
97632
+ }
97633
+ // Split figcaption: <figcaption> + text + </figcaption> as separate nodes (table cells)
97634
+ if (htmlValue && FIGCAPTION_OPEN_REGEX.test(htmlValue)) {
97635
+ const textNode = children[j + 1];
97636
+ const closeCaption = children[j + 2];
97637
+ if (textNode?.type === 'text' &&
97638
+ closeCaption?.type === 'html' &&
97639
+ FIGCAPTION_CLOSE_REGEX.test(closeCaption.value)) {
97640
+ captionText = textNode.value;
97641
+ const closeFigure = children[j + 3];
97642
+ if (closeFigure?.type === 'html' && FIGURE_CLOSE_REGEX.test(closeFigure.value)) {
97643
+ endIndex = j + 3;
97644
+ foundClose = true;
97645
+ break;
97646
+ }
97647
+ }
97648
+ }
97649
+ }
97650
+ return { captionText, endIndex, foundClose };
97651
+ }
97652
+ /**
97653
+ * Reconstruct fragmented or complete HTML <figure> elements into figure MDAST nodes.
97654
+ *
97655
+ * Handles three html-based cases (the JSX case is handled by transformFigure in COMPONENT_MAP):
97656
+ * 1. Complete: A single html node containing the full `<figure>...<figcaption>...</figure>` block
97657
+ * (e.g. inside callouts where blockquote parsing keeps it together).
97658
+ * 2. Fragmented siblings: `terminateHtmlFlowBlocks` splits `<figure>` into separate sibling
97659
+ * nodes (open tag, image, figcaption, close tag).
97660
+ * 3. Split tags (GFM table cells): Each tag becomes its own html node with text nodes between them.
97661
+ *
97662
+ * Runs on all parent nodes so it works inside callouts, tables, and at root level.
97663
+ */
97664
+ function reassembleHtmlFigures(tree) {
97665
+ // Case 1: Handle complete <figure> blocks in a single html node (e.g. inside callouts)
97666
+ visit(tree, 'html', (node, index, parent) => {
97667
+ if (!parent || index === undefined)
97668
+ return;
97669
+ if (!FIGURE_COMPLETE_REGEX.test(node.value.trim()))
97670
+ return;
97671
+ const parsed = parseCompleteFigure(node.value);
97672
+ if (!parsed)
97673
+ return;
97674
+ const imageNode = {
97675
+ type: 'image',
97676
+ url: parsed.url,
97677
+ alt: parsed.alt,
97678
+ };
97679
+ const figureNode = buildFigureNode(imageNode, parsed.caption, node.position);
97680
+ parent.children.splice(index, 1, figureNode);
97681
+ });
97682
+ // Case 2 & 3: Handle fragmented <figure> blocks split across sibling nodes
97683
+ const processChildren = (parent) => {
97684
+ const children = parent.children;
97685
+ let i = 0;
97686
+ while (i < children.length) {
97687
+ const node = children[i];
97688
+ const nextNode = children[i + 1];
97689
+ const imageNode = nextNode ? findImageInNode(nextNode) : undefined;
97690
+ if (node.type === 'html' &&
97691
+ FIGURE_OPEN_REGEX.test(node.value.trim()) &&
97692
+ imageNode) {
97693
+ const { captionText, endIndex, foundClose } = scanForFigcaptionAndClose(children, i + 2);
97694
+ if (foundClose) {
97695
+ const figureNode = buildFigureNode(imageNode, captionText, node.position);
97696
+ parent.children.splice(i, endIndex - i + 1, figureNode);
97697
+ }
97698
+ }
97699
+ i += 1;
97700
+ }
97701
+ };
97702
+ // Process all parent nodes (root, callouts, blockquotes, table cells, list items)
97703
+ visit(tree, (node) => {
97704
+ if ('children' in node)
97705
+ processChildren(node);
97706
+ });
97707
+ }
97708
+ /**
97709
+ * Transforms an inline `<Anchor>` JSX element into a readme-anchor MDAST node.
97710
+ */
97231
97711
  const transformAnchor = (jsx) => {
97232
97712
  const attrs = getAttrs(jsx);
97233
97713
  const { href = '', label, target, title } = attrs;
@@ -97246,6 +97726,10 @@ const transformAnchor = (jsx) => {
97246
97726
  position: jsx.position,
97247
97727
  };
97248
97728
  };
97729
+ /**
97730
+ * Transforms an `<Image />` JSX element into an image-block MDAST node.
97731
+ * Normalizes attributes (align, border, width→sizing) and parses caption markdown into children.
97732
+ */
97249
97733
  const transformImage = (jsx) => {
97250
97734
  const attrs = getAttrs(jsx);
97251
97735
  const { align, alt = '', border, caption, className, height, lazy, src = '', title = '', width } = attrs;
@@ -97285,6 +97769,9 @@ const transformImage = (jsx) => {
97285
97769
  position: jsx.position,
97286
97770
  };
97287
97771
  };
97772
+ /**
97773
+ * Transforms a `<Callout>` JSX element into an rdme-callout MDAST node.
97774
+ */
97288
97775
  const transformCallout = (jsx) => {
97289
97776
  const attrs = getAttrs(jsx);
97290
97777
  const { empty = false, icon = '', theme = '' } = attrs;
@@ -97302,6 +97789,9 @@ const transformCallout = (jsx) => {
97302
97789
  position: jsx.position,
97303
97790
  };
97304
97791
  };
97792
+ /**
97793
+ * Transforms an `<Embed />` JSX element into an embed-block MDAST node.
97794
+ */
97305
97795
  const transformEmbed = (jsx) => {
97306
97796
  const attrs = getAttrs(jsx);
97307
97797
  const { favicon, height, href, html, iframe, image, providerName, providerUrl, provider, title = '', typeOfEmbed, url = '', width, } = attrs;
@@ -97330,6 +97820,9 @@ const transformEmbed = (jsx) => {
97330
97820
  position: jsx.position,
97331
97821
  };
97332
97822
  };
97823
+ /**
97824
+ * Transforms a `<Recipe />` JSX element into a recipe MDAST node.
97825
+ */
97333
97826
  const transformRecipe = (jsx) => {
97334
97827
  const attrs = getAttrs(jsx);
97335
97828
  const { backgroundColor = '', emoji = '', id = '', link = '', slug = '', title = '' } = attrs;
@@ -97466,21 +97959,44 @@ const transformTable = (jsx) => {
97466
97959
  children: rows,
97467
97960
  };
97468
97961
  };
97962
+ /**
97963
+ * Transforms a `<figure>` JSX element into a FigureNode.
97964
+ * Inside JSX tables with blank lines, the parser treats `<figure>` as an mdxJsxFlowElement
97965
+ * containing a paragraph with the image and a `<figcaption>` mdxJsxTextElement as children.
97966
+ */
97967
+ const transformFigure = (jsx) => {
97968
+ let imageNode;
97969
+ let captionText;
97970
+ visit(jsx, (child) => {
97971
+ if (!imageNode && (child.type === 'image' || child.type === NodeTypes.imageBlock)) {
97972
+ imageNode = child;
97973
+ }
97974
+ if (!captionText && child.type === 'mdxJsxTextElement' && child.name === 'figcaption') {
97975
+ captionText = mdxish_jsx_to_mdast_extractText(child.children);
97976
+ }
97977
+ });
97978
+ if (!imageNode)
97979
+ return null;
97980
+ return buildFigureNode(imageNode, captionText, jsx.position);
97981
+ };
97469
97982
  const COMPONENT_MAP = {
97470
97983
  Callout: transformCallout,
97471
97984
  Embed: transformEmbed,
97472
97985
  Image: transformImage,
97986
+ figure: transformFigure,
97473
97987
  Recipe: transformRecipe,
97474
97988
  Table: transformTable,
97475
97989
  };
97476
97990
  /**
97477
- * Transform mdxJsxFlowElement nodes and magic block nodes into proper MDAST node types.
97991
+ * Transform mdxJsxFlowElement nodes, magic block nodes, and HTML figure elements
97992
+ * into proper MDAST node types.
97478
97993
  *
97479
97994
  * This transformer runs after mdxishComponentBlocks and converts:
97480
- * - JSX component elements (Image, Callout, Embed, Recipe) into their corresponding MDAST types
97995
+ * - JSX component elements (Image, Callout, Embed, Recipe, figure) into their corresponding MDAST types
97481
97996
  * - Magic block image nodes (type: 'image') into image-block
97482
97997
  * - Magic block embed nodes (type: 'embed') into embed-block
97483
- * - Figure nodes (magic blocks with captions) into flat image-block with caption string
97998
+ * - Fragmented HTML <figure> blocks (from terminateHtmlFlowBlocks) back into figure nodes
97999
+ * - Figure nodes (from magic blocks, HTML, or JSX) into flat image-block with caption string
97484
98000
  * - Normalizes all image-block attrs (border, align, sizing, caption) to a consistent shape
97485
98001
  *
97486
98002
  * This is controlled by the `newEditorTypes` flag to maintain backwards compatibility.
@@ -97527,6 +98043,9 @@ const mdxishJsxToMdast = () => tree => {
97527
98043
  parent.children[index] = newNode;
97528
98044
  return SKIP;
97529
98045
  });
98046
+ // Reassembling fragmented HTML <figure> blocks into proper figure/figcaption nodes
98047
+ // this will then later be transformed into image-block nodes by imageTransformer
98048
+ reassembleHtmlFigures(tree);
97530
98049
  // Flatten figure nodes (magic blocks with captions) into image-block nodes
97531
98050
  const isFigure = (node) => node.type === 'figure';
97532
98051
  visit(tree, isFigure, (node, index, parent) => {
@@ -97779,6 +98298,7 @@ function restoreSnakeCase(placeholderName, mapping) {
97779
98298
  ;// ./processor/transform/mdxish/mdxish-tables-to-jsx.ts
97780
98299
 
97781
98300
 
98301
+ const SELF_CLOSING_JSX_REGEX = /^\s*<[A-Z][^>]*\/>\s*$/;
97782
98302
  const mdxish_tables_to_jsx_alignToStyle = (align) => {
97783
98303
  if (!align || align === 'left')
97784
98304
  return null;
@@ -97805,7 +98325,7 @@ const mdxishTablesToJsx = () => tree => {
97805
98325
  visit(tree, (node) => ['table', 'tableau'].includes(node.type), (table, index, parent) => {
97806
98326
  let hasFlowContent = false;
97807
98327
  visit(table, mdxish_tables_to_jsx_isTableCell, (cell) => {
97808
- if (cell.children.length === 0)
98328
+ if (hasFlowContent || cell.children.length === 0)
97809
98329
  return;
97810
98330
  const content = cell.children.length === 1 && cell.children[0].type === 'paragraph'
97811
98331
  ? cell.children[0].children[0]
@@ -97816,17 +98336,21 @@ const mdxishTablesToJsx = () => tree => {
97816
98336
  breakParent.children.splice(breakIndex, 1, { type: 'text', value: '\n' });
97817
98337
  });
97818
98338
  if (!(phrasing(content) || content.type === 'plain') && content.type !== 'escape') {
97819
- if (content.type === 'html')
97820
- return;
97821
- hasFlowContent = true;
97822
- return EXIT;
97823
- }
97824
- visit(cell, mdxish_tables_to_jsx_isLiteral, (node) => {
97825
- if (node.value.match(/\n/)) {
98339
+ // Plain HTML (e.g. <div>Hello</div>) is skipped here — it stays in GFM cells fine.
98340
+ // But self-closing JSX components (e.g. <Image src="..." caption="..." />) serialize
98341
+ // with newlines that break GFM cells, so they must trigger JSX <Table> serialization.
98342
+ const isPlainHtml = content.type === 'html' && !SELF_CLOSING_JSX_REGEX.test(content.value);
98343
+ if (!isPlainHtml) {
97826
98344
  hasFlowContent = true;
97827
- return EXIT;
97828
98345
  }
97829
- });
98346
+ }
98347
+ if (!hasFlowContent) {
98348
+ visit(cell, mdxish_tables_to_jsx_isLiteral, (node) => {
98349
+ if (node.value.match(/\n/)) {
98350
+ hasFlowContent = true;
98351
+ }
98352
+ });
98353
+ }
97830
98354
  });
97831
98355
  if (!hasFlowContent) {
97832
98356
  table.type = 'table';
@@ -100066,13 +100590,14 @@ function loadComponents() {
100066
100590
 
100067
100591
 
100068
100592
 
100593
+
100594
+
100069
100595
 
100070
100596
 
100071
100597
 
100072
100598
  const defaultTransformers = [
100073
100599
  [callouts, { isMdxish: true }],
100074
100600
  code_tabs,
100075
- gemoji_,
100076
100601
  transform_embeds,
100077
100602
  ];
100078
100603
  /**
@@ -100082,13 +100607,15 @@ const defaultTransformers = [
100082
100607
  * Runs a series of string-level transformations before micromark/remark parsing:
100083
100608
  * 1. Normalize malformed table separator syntax (e.g., `|: ---` → `| :---`)
100084
100609
  * 2. Terminate HTML flow blocks so subsequent content isn't swallowed
100085
- * 3. Evaluate JSX expressions in attributes (unless safeMode)
100086
- * 4. Replace snake_case component names with parser-safe placeholders
100610
+ * 3. Close invalid "self-closing" HTML tags (e.g., `<i />` → `<i></i>`)
100611
+ * 4. Evaluate JSX expressions in attributes (unless safeMode)
100612
+ * 5. Replace snake_case component names with parser-safe placeholders
100087
100613
  */
100088
100614
  function preprocessContent(content, opts) {
100089
100615
  const { safeMode, jsxContext, knownComponents } = opts;
100090
100616
  let result = normalizeTableSeparator(content);
100091
100617
  result = terminateHtmlFlowBlocks(result);
100618
+ result = closeSelfClosingHtmlTags(result);
100092
100619
  result = safeMode ? result : preprocessJSXExpressions(result, jsxContext);
100093
100620
  return processSnakeCaseComponent(result, { knownComponents });
100094
100621
  }
@@ -100118,12 +100645,13 @@ function mdxishAstProcessor(mdContent, opts = {}) {
100118
100645
  };
100119
100646
  const processor = unified()
100120
100647
  .data('micromarkExtensions', safeMode
100121
- ? [jsxTable(), magicBlock(), legacyVariable(), looseHtmlEntity()]
100122
- : [jsxTable(), magicBlock(), mdxExprTextOnly, legacyVariable(), looseHtmlEntity()])
100648
+ ? [jsxTable(), magicBlock(), syntax_gemoji(), legacyVariable(), looseHtmlEntity()]
100649
+ : [jsxTable(), magicBlock(), syntax_gemoji(), mdxExprTextOnly, legacyVariable(), looseHtmlEntity()])
100123
100650
  .data('fromMarkdownExtensions', safeMode
100124
100651
  ? [
100125
100652
  jsxTableFromMarkdown(),
100126
100653
  magicBlockFromMarkdown(),
100654
+ gemojiFromMarkdown(),
100127
100655
  legacyVariableFromMarkdown(),
100128
100656
  emptyTaskListItemFromMarkdown(),
100129
100657
  looseHtmlEntityFromMarkdown(),
@@ -100131,6 +100659,7 @@ function mdxishAstProcessor(mdContent, opts = {}) {
100131
100659
  : [
100132
100660
  jsxTableFromMarkdown(),
100133
100661
  magicBlockFromMarkdown(),
100662
+ gemojiFromMarkdown(),
100134
100663
  mdxExpressionFromMarkdown(),
100135
100664
  legacyVariableFromMarkdown(),
100136
100665
  emptyTaskListItemFromMarkdown(),
@@ -100489,7 +101018,7 @@ function createTocComponent(tocHast) {
100489
101018
  components: { p: (external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default()).Fragment },
100490
101019
  });
100491
101020
  const tocReactElement = tocProcessor.stringify(tocHast);
100492
- const TocComponent = (props) => tocReactElement ? (external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default().createElement(components_TableOfContents, { heading: props.heading }, tocReactElement)) : null;
101021
+ const TocComponent = () => tocReactElement ? (external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default().createElement(components_TableOfContents, null, tocReactElement)) : null;
100493
101022
  TocComponent.displayName = 'Toc';
100494
101023
  return TocComponent;
100495
101024
  }
@@ -100655,7 +101184,7 @@ const run_run = (string, _opts = {}) => {
100655
101184
  default: (props) => (external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default().createElement(contexts, { baseUrl: baseUrl, copyButtons: copyButtons, terms: terms, theme: theme, variables: variables },
100656
101185
  external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default().createElement(Content, { ...props }))),
100657
101186
  toc,
100658
- Toc: (props) => Toc ? (external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default().createElement(components_TableOfContents, { heading: props.heading },
101187
+ Toc: () => Toc ? (external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default().createElement(components_TableOfContents, null,
100659
101188
  external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default().createElement(Toc, null))) : null,
100660
101189
  stylesheet,
100661
101190
  ...exports,