@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.node.js CHANGED
@@ -24471,6 +24471,8 @@ const GlossaryContext = (0,external_react_.createContext)([]);
24471
24471
 
24472
24472
  const Glossary = ({ children, term: termProp, terms }) => {
24473
24473
  const term = (Array.isArray(children) ? children[0] : children) || termProp;
24474
+ if (!term)
24475
+ return null;
24474
24476
  const foundTerm = terms.find(i => term.toLowerCase() === i?.term?.toLowerCase());
24475
24477
  if (!foundTerm)
24476
24478
  return external_react_default().createElement("span", null, term);
@@ -24664,13 +24666,91 @@ const Table = (props) => {
24664
24666
 
24665
24667
  ;// ./components/TableOfContents/index.tsx
24666
24668
 
24667
- function TableOfContents({ children, heading = 'Table of Contents' }) {
24668
- return (external_react_default().createElement("nav", { "aria-label": "Table of contents", role: "navigation" },
24669
+ /**
24670
+ * Build link map and decode the hash to get the id and weird chars
24671
+ */
24672
+ function buildLinkMap(nav) {
24673
+ const map = new Map();
24674
+ Array.from(nav.querySelectorAll('a')).forEach(link => {
24675
+ const id = decodeURIComponent(link.hash.slice(1));
24676
+ if (!id)
24677
+ return;
24678
+ const list = map.get(id);
24679
+ if (list)
24680
+ list.push(link);
24681
+ else
24682
+ map.set(id, [link]);
24683
+ });
24684
+ return map;
24685
+ }
24686
+ /**
24687
+ * Watches headings in the viewport and toggles `active` on the
24688
+ * corresponding TOC links so the reader always knows where they are.
24689
+ */
24690
+ function useScrollHighlight(navRef) {
24691
+ const [linkCount, setLinkCount] = (0,external_react_.useState)(0);
24692
+ (0,external_react_.useEffect)(() => {
24693
+ const nav = navRef.current;
24694
+ if (!nav)
24695
+ return;
24696
+ const count = nav.querySelectorAll('a[href^="#"]').length;
24697
+ setLinkCount(count);
24698
+ }, [navRef]);
24699
+ (0,external_react_.useEffect)(() => {
24700
+ const nav = navRef.current;
24701
+ if (!nav || typeof IntersectionObserver === 'undefined' || linkCount === 0)
24702
+ return undefined;
24703
+ const linkMap = buildLinkMap(nav);
24704
+ if (linkMap.size === 0)
24705
+ return undefined;
24706
+ const headings = [...linkMap.keys()]
24707
+ .map(id => document.getElementById(id))
24708
+ .filter((el) => el !== null);
24709
+ if (headings.length === 0)
24710
+ return undefined;
24711
+ let activeId = null;
24712
+ const visible = new Set();
24713
+ const activate = (id) => {
24714
+ if (id === activeId)
24715
+ return;
24716
+ if (activeId)
24717
+ linkMap.get(activeId)?.forEach(a => a.classList.remove('active'));
24718
+ activeId = id;
24719
+ // set active states + border pos/size
24720
+ if (id) {
24721
+ const links = linkMap.get(id);
24722
+ links?.forEach(a => a.classList.add('active'));
24723
+ const link = links?.[0];
24724
+ if (link) {
24725
+ const navRect = nav.getBoundingClientRect();
24726
+ const linkRect = link.getBoundingClientRect();
24727
+ nav.style.setProperty('--ToC-border-active-height', `${linkRect.height}px`);
24728
+ nav.style.setProperty('--ToC-border-active-top', `${linkRect.top - navRect.top}px`);
24729
+ }
24730
+ }
24731
+ };
24732
+ const observer = new IntersectionObserver(entries => {
24733
+ entries.forEach(e => {
24734
+ if (e.isIntersecting)
24735
+ visible.add(e.target.id);
24736
+ else
24737
+ visible.delete(e.target.id);
24738
+ });
24739
+ // Highlight the topmost visible heading; if none are visible,
24740
+ // keep the last active one so the user still has context.
24741
+ const topmost = headings.find(el => visible.has(el.id));
24742
+ if (topmost)
24743
+ activate(topmost.id);
24744
+ }, { rootMargin: '0px 0px -60% 0px', threshold: 0 });
24745
+ headings.forEach(el => { observer.observe(el); });
24746
+ return () => { observer.disconnect(); };
24747
+ }, [navRef, linkCount]);
24748
+ }
24749
+ function TableOfContents({ children }) {
24750
+ const navRef = (0,external_react_.useRef)(null);
24751
+ useScrollHighlight(navRef);
24752
+ return (external_react_default().createElement("nav", { ref: navRef, "aria-label": "Table of contents", className: "rm-ToC" },
24669
24753
  external_react_default().createElement("ul", { className: "toc-list" },
24670
- external_react_default().createElement("li", null,
24671
- external_react_default().createElement("a", { className: "tocHeader", href: "#" },
24672
- external_react_default().createElement("i", { className: "icon icon-text-align-left" }),
24673
- heading)),
24674
24754
  external_react_default().createElement("li", { className: "toc-children" }, children))));
24675
24755
  }
24676
24756
  /* harmony default export */ const components_TableOfContents = (TableOfContents);
@@ -24938,19 +25018,10 @@ const TailwindStyle = ({ children, darkModeDataAttribute }) => {
24938
25018
  records.forEach(record => {
24939
25019
  if (record.type === 'childList') {
24940
25020
  record.addedNodes.forEach(node => {
24941
- if (!(node instanceof HTMLElement))
25021
+ if (!(node instanceof HTMLElement) || !node.classList.contains(tailwindPrefix))
24942
25022
  return;
24943
- // Check the added node itself
24944
- if (node.classList.contains(tailwindPrefix)) {
24945
- traverse(node, addClasses);
24946
- shouldUpdate = true;
24947
- }
24948
- // Also check descendants — React may insert a parent node
24949
- // whose children contain TailwindRoot elements
24950
- node.querySelectorAll(`.${tailwindPrefix}`).forEach(child => {
24951
- traverse(child, addClasses);
24952
- shouldUpdate = true;
24953
- });
25023
+ traverse(node, addClasses);
25024
+ shouldUpdate = true;
24954
25025
  });
24955
25026
  }
24956
25027
  else if (record.type === 'attributes') {
@@ -73183,6 +73254,10 @@ const plain = (node, opts = {}) => {
73183
73254
  };
73184
73255
  /* harmony default export */ const lib_plain = (plain);
73185
73256
 
73257
+ ;// ./processor/compile/gemoji.ts
73258
+ const gemoji = (node) => `:${node.name}:`;
73259
+ /* harmony default export */ const compile_gemoji = (gemoji);
73260
+
73186
73261
  ;// ./processor/compile/variable.ts
73187
73262
  const variable = (node) => `{user.${node.data?.hProperties?.name || ''}}`;
73188
73263
  /* harmony default export */ const compile_variable = (variable);
@@ -73233,6 +73308,7 @@ const extractText = (node) => {
73233
73308
 
73234
73309
 
73235
73310
 
73311
+
73236
73312
  const titleParser = unified().use(remarkParse).use(remarkGfm);
73237
73313
  // The title paragraph may contain custom AST nodes that `toMarkdown` doesn't
73238
73314
  // natively understand
@@ -73240,8 +73316,8 @@ const toMarkdownExtensions = [
73240
73316
  gfmToMarkdown(),
73241
73317
  // For mdx variable syntaxes (e.g., {user.name})
73242
73318
  mdxExpressionToMarkdown(),
73243
- // Important: This is required and would crash the parser if there's no variable node handler
73244
- { handlers: { [NodeTypes.variable]: compile_variable } },
73319
+ // Important: This is required and would crash the parser if there's no variable and gemoji node handler
73320
+ { handlers: { [NodeTypes.variable]: compile_variable, [NodeTypes.emoji]: compile_gemoji } },
73245
73321
  ];
73246
73322
  const callouts_regex = `^(${emoji_regex().source}|⚠)(\\s+|$)`;
73247
73323
  const findFirst = (node) => {
@@ -73636,7 +73712,7 @@ const embedTransformer = () => {
73636
73712
  *
73637
73713
  * @type {Array<Gemoji>}
73638
73714
  */
73639
- const gemoji = [
73715
+ const gemoji_gemoji = [
73640
73716
  {
73641
73717
  emoji: '😀',
73642
73718
  names: ['grinning'],
@@ -90579,7 +90655,7 @@ class Owlmoji {
90579
90655
  return null;
90580
90656
  };
90581
90657
  static nameToEmoji = nameToEmoji;
90582
- static owlmoji = gemoji.concat(owlmoji);
90658
+ static owlmoji = gemoji_gemoji.concat(owlmoji);
90583
90659
  }
90584
90660
 
90585
90661
  ;// ./processor/transform/gemoji+.ts
@@ -91489,6 +91565,316 @@ const mdxToHast = () => tree => {
91489
91565
  };
91490
91566
  /* harmony default export */ const mdx_to_hast = (mdxToHast);
91491
91567
 
91568
+ ;// ./lib/mdast-util/gemoji/index.ts
91569
+
91570
+
91571
+ function exitGemoji(token) {
91572
+ const name = this.sliceSerialize(token).slice(1, -1); // strip surrounding colons
91573
+ switch (Owlmoji.kind(name)) {
91574
+ case 'gemoji': {
91575
+ this.enter({ type: NodeTypes.emoji, value: Owlmoji.nameToEmoji[name], name }, token);
91576
+ this.exit(token);
91577
+ break;
91578
+ }
91579
+ case 'fontawesome': {
91580
+ this.enter({
91581
+ type: NodeTypes.i,
91582
+ value: name,
91583
+ data: { hName: 'i', hProperties: { className: ['fa-regular', name] } },
91584
+ }, token);
91585
+ this.exit(token);
91586
+ break;
91587
+ }
91588
+ case 'owlmoji': {
91589
+ this.enter({
91590
+ type: NodeTypes.emoji,
91591
+ value: `:${name}:`,
91592
+ name,
91593
+ data: {
91594
+ hName: 'img',
91595
+ hProperties: {
91596
+ src: `/public/img/emojis/${name}.png`,
91597
+ alt: `:${name}:`,
91598
+ title: `:${name}:`,
91599
+ className: 'emoji',
91600
+ align: 'absmiddle',
91601
+ height: '20',
91602
+ width: '20',
91603
+ },
91604
+ },
91605
+ }, token);
91606
+ this.exit(token);
91607
+ break;
91608
+ }
91609
+ default: {
91610
+ // Unknown shortcode, emit as literal text `:name:`
91611
+ this.enter({ type: 'text', value: `:${name}:` }, token);
91612
+ this.exit(token);
91613
+ break;
91614
+ }
91615
+ }
91616
+ }
91617
+ function gemojiFromMarkdown() {
91618
+ return {
91619
+ exit: {
91620
+ gemoji: exitGemoji,
91621
+ },
91622
+ };
91623
+ }
91624
+
91625
+ ;// ./node_modules/micromark-util-symbol/lib/codes.js
91626
+ /**
91627
+ * Character codes.
91628
+ *
91629
+ * This module is compiled away!
91630
+ *
91631
+ * micromark works based on character codes.
91632
+ * This module contains constants for the ASCII block and the replacement
91633
+ * character.
91634
+ * A couple of them are handled in a special way, such as the line endings
91635
+ * (CR, LF, and CR+LF, commonly known as end-of-line: EOLs), the tab (horizontal
91636
+ * tab) and its expansion based on what column it’s at (virtual space),
91637
+ * and the end-of-file (eof) character.
91638
+ * As values are preprocessed before handling them, the actual characters LF,
91639
+ * CR, HT, and NUL (which is present as the replacement character), are
91640
+ * guaranteed to not exist.
91641
+ *
91642
+ * Unicode basic latin block.
91643
+ */
91644
+ const codes = /** @type {const} */ ({
91645
+ carriageReturn: -5,
91646
+ lineFeed: -4,
91647
+ carriageReturnLineFeed: -3,
91648
+ horizontalTab: -2,
91649
+ virtualSpace: -1,
91650
+ eof: null,
91651
+ nul: 0,
91652
+ soh: 1,
91653
+ stx: 2,
91654
+ etx: 3,
91655
+ eot: 4,
91656
+ enq: 5,
91657
+ ack: 6,
91658
+ bel: 7,
91659
+ bs: 8,
91660
+ ht: 9, // `\t`
91661
+ lf: 10, // `\n`
91662
+ vt: 11, // `\v`
91663
+ ff: 12, // `\f`
91664
+ cr: 13, // `\r`
91665
+ so: 14,
91666
+ si: 15,
91667
+ dle: 16,
91668
+ dc1: 17,
91669
+ dc2: 18,
91670
+ dc3: 19,
91671
+ dc4: 20,
91672
+ nak: 21,
91673
+ syn: 22,
91674
+ etb: 23,
91675
+ can: 24,
91676
+ em: 25,
91677
+ sub: 26,
91678
+ esc: 27,
91679
+ fs: 28,
91680
+ gs: 29,
91681
+ rs: 30,
91682
+ us: 31,
91683
+ space: 32,
91684
+ exclamationMark: 33, // `!`
91685
+ quotationMark: 34, // `"`
91686
+ numberSign: 35, // `#`
91687
+ dollarSign: 36, // `$`
91688
+ percentSign: 37, // `%`
91689
+ ampersand: 38, // `&`
91690
+ apostrophe: 39, // `'`
91691
+ leftParenthesis: 40, // `(`
91692
+ rightParenthesis: 41, // `)`
91693
+ asterisk: 42, // `*`
91694
+ plusSign: 43, // `+`
91695
+ comma: 44, // `,`
91696
+ dash: 45, // `-`
91697
+ dot: 46, // `.`
91698
+ slash: 47, // `/`
91699
+ digit0: 48, // `0`
91700
+ digit1: 49, // `1`
91701
+ digit2: 50, // `2`
91702
+ digit3: 51, // `3`
91703
+ digit4: 52, // `4`
91704
+ digit5: 53, // `5`
91705
+ digit6: 54, // `6`
91706
+ digit7: 55, // `7`
91707
+ digit8: 56, // `8`
91708
+ digit9: 57, // `9`
91709
+ colon: 58, // `:`
91710
+ semicolon: 59, // `;`
91711
+ lessThan: 60, // `<`
91712
+ equalsTo: 61, // `=`
91713
+ greaterThan: 62, // `>`
91714
+ questionMark: 63, // `?`
91715
+ atSign: 64, // `@`
91716
+ uppercaseA: 65, // `A`
91717
+ uppercaseB: 66, // `B`
91718
+ uppercaseC: 67, // `C`
91719
+ uppercaseD: 68, // `D`
91720
+ uppercaseE: 69, // `E`
91721
+ uppercaseF: 70, // `F`
91722
+ uppercaseG: 71, // `G`
91723
+ uppercaseH: 72, // `H`
91724
+ uppercaseI: 73, // `I`
91725
+ uppercaseJ: 74, // `J`
91726
+ uppercaseK: 75, // `K`
91727
+ uppercaseL: 76, // `L`
91728
+ uppercaseM: 77, // `M`
91729
+ uppercaseN: 78, // `N`
91730
+ uppercaseO: 79, // `O`
91731
+ uppercaseP: 80, // `P`
91732
+ uppercaseQ: 81, // `Q`
91733
+ uppercaseR: 82, // `R`
91734
+ uppercaseS: 83, // `S`
91735
+ uppercaseT: 84, // `T`
91736
+ uppercaseU: 85, // `U`
91737
+ uppercaseV: 86, // `V`
91738
+ uppercaseW: 87, // `W`
91739
+ uppercaseX: 88, // `X`
91740
+ uppercaseY: 89, // `Y`
91741
+ uppercaseZ: 90, // `Z`
91742
+ leftSquareBracket: 91, // `[`
91743
+ backslash: 92, // `\`
91744
+ rightSquareBracket: 93, // `]`
91745
+ caret: 94, // `^`
91746
+ underscore: 95, // `_`
91747
+ graveAccent: 96, // `` ` ``
91748
+ lowercaseA: 97, // `a`
91749
+ lowercaseB: 98, // `b`
91750
+ lowercaseC: 99, // `c`
91751
+ lowercaseD: 100, // `d`
91752
+ lowercaseE: 101, // `e`
91753
+ lowercaseF: 102, // `f`
91754
+ lowercaseG: 103, // `g`
91755
+ lowercaseH: 104, // `h`
91756
+ lowercaseI: 105, // `i`
91757
+ lowercaseJ: 106, // `j`
91758
+ lowercaseK: 107, // `k`
91759
+ lowercaseL: 108, // `l`
91760
+ lowercaseM: 109, // `m`
91761
+ lowercaseN: 110, // `n`
91762
+ lowercaseO: 111, // `o`
91763
+ lowercaseP: 112, // `p`
91764
+ lowercaseQ: 113, // `q`
91765
+ lowercaseR: 114, // `r`
91766
+ lowercaseS: 115, // `s`
91767
+ lowercaseT: 116, // `t`
91768
+ lowercaseU: 117, // `u`
91769
+ lowercaseV: 118, // `v`
91770
+ lowercaseW: 119, // `w`
91771
+ lowercaseX: 120, // `x`
91772
+ lowercaseY: 121, // `y`
91773
+ lowercaseZ: 122, // `z`
91774
+ leftCurlyBrace: 123, // `{`
91775
+ verticalBar: 124, // `|`
91776
+ rightCurlyBrace: 125, // `}`
91777
+ tilde: 126, // `~`
91778
+ del: 127,
91779
+ // Unicode Specials block.
91780
+ byteOrderMarker: 65_279,
91781
+ // Unicode Specials block.
91782
+ replacementCharacter: 65_533 // `�`
91783
+ })
91784
+
91785
+ ;// ./lib/micromark/gemoji/syntax.ts
91786
+
91787
+ // Matches the name pattern from the original regex: \+1 or [-\w]+
91788
+ // see https://github.com/readmeio/markdown/blob/489a71e19b34f640595ce81e988dad631045186f/processor/transform/gemoji%2B.ts#L9
91789
+ function isNameChar(code) {
91790
+ if (code === null)
91791
+ return false;
91792
+ return ((code >= codes.lowercaseA && code <= codes.lowercaseZ) ||
91793
+ (code >= codes.uppercaseA && code <= codes.uppercaseZ) ||
91794
+ (code >= codes.digit0 && code <= codes.digit9) ||
91795
+ code === codes.dash ||
91796
+ code === codes.underscore);
91797
+ }
91798
+ const gemojiConstruct = {
91799
+ name: 'gemoji',
91800
+ tokenize,
91801
+ };
91802
+ function tokenize(effects, ok, nok) {
91803
+ let hasName = false;
91804
+ // Entry point — expect opening `:`
91805
+ const start = (code) => {
91806
+ if (code !== codes.colon)
91807
+ return nok(code);
91808
+ effects.enter('gemoji');
91809
+ effects.enter('gemojiMarker');
91810
+ effects.consume(code); // :
91811
+ effects.exit('gemojiMarker');
91812
+ effects.enter('gemojiName');
91813
+ return nameStart;
91814
+ };
91815
+ // First char after `:`, branch on `+` for :+1:, otherwise start normal name
91816
+ const nameStart = (code) => {
91817
+ if (code === codes.plusSign) {
91818
+ effects.consume(code); // +
91819
+ return plusOne;
91820
+ }
91821
+ if (isNameChar(code)) {
91822
+ hasName = true;
91823
+ effects.consume(code);
91824
+ return name;
91825
+ }
91826
+ // Not a valid shortcode start (e.g. `::`, `: `, `:<`)
91827
+ return nok(code);
91828
+ };
91829
+ // After `+`, only `1` is valid (for :+1:), anything else rejects
91830
+ // this is a special case for :+1: 👍 since + isnt a normal name character
91831
+ const plusOne = (code) => {
91832
+ if (code === codes.digit1) {
91833
+ hasName = true;
91834
+ effects.consume(code); // 1
91835
+ return nameEnd;
91836
+ }
91837
+ return nok(code);
91838
+ };
91839
+ // Consume name characters until we hit closing `:` or an invalid char
91840
+ const name = (code) => {
91841
+ if (code === codes.colon) {
91842
+ if (!hasName)
91843
+ return nok(code);
91844
+ return nameEnd(code);
91845
+ }
91846
+ if (isNameChar(code)) {
91847
+ effects.consume(code);
91848
+ return name;
91849
+ }
91850
+ // Invalid character in name (space, newline, special char) — reject
91851
+ return nok(code);
91852
+ };
91853
+ // Expect closing `:`
91854
+ const nameEnd = (code) => {
91855
+ if (code !== codes.colon)
91856
+ return nok(code);
91857
+ effects.exit('gemojiName');
91858
+ effects.enter('gemojiMarker');
91859
+ effects.consume(code); // :
91860
+ effects.exit('gemojiMarker');
91861
+ effects.exit('gemoji');
91862
+ return ok;
91863
+ };
91864
+ return start;
91865
+ }
91866
+ function syntax_gemoji() {
91867
+ return {
91868
+ text: { [codes.colon]: gemojiConstruct },
91869
+ };
91870
+ }
91871
+
91872
+ ;// ./lib/micromark/gemoji/index.ts
91873
+ /**
91874
+ * Micromark extension for :emoji: inline syntax.
91875
+ */
91876
+
91877
+
91492
91878
  ;// ./processor/transform/mdxish/normalize-malformed-md-syntax.ts
91493
91879
 
91494
91880
  // Marker patterns for multi-node emphasis detection
@@ -91845,6 +92231,7 @@ const normalizeEmphasisAST = () => (tree) => {
91845
92231
 
91846
92232
 
91847
92233
 
92234
+
91848
92235
  const isTableCell = (node) => isMDXElement(node) && ['th', 'td'].includes(node.name);
91849
92236
  const tableTypes = {
91850
92237
  tr: 'tableRow',
@@ -91852,10 +92239,12 @@ const tableTypes = {
91852
92239
  td: 'tableCell',
91853
92240
  };
91854
92241
  const tableNodeProcessor = unified()
92242
+ .data('micromarkExtensions', [syntax_gemoji()])
92243
+ .data('fromMarkdownExtensions', [gemojiFromMarkdown()])
91855
92244
  .use(remarkParse)
91856
92245
  .use(remarkMdx)
91857
92246
  .use(normalize_malformed_md_syntax)
91858
- .use([[callouts, { isMdxish: true }], gemoji_, code_tabs])
92247
+ .use([[callouts, { isMdxish: true }], code_tabs])
91859
92248
  .use(remarkGfm);
91860
92249
  /**
91861
92250
  * Check if children are only text nodes that might contain markdown
@@ -92728,7 +93117,6 @@ const mdxishTransformers = [
92728
93117
  [callouts, { isMdxish: true }],
92729
93118
  code_tabs,
92730
93119
  transform_images,
92731
- gemoji_,
92732
93120
  ];
92733
93121
  /* harmony default export */ const transform = (Object.values(defaultTransforms));
92734
93122
 
@@ -112510,10 +112898,6 @@ const embed_embed = (node) => {
112510
112898
  };
112511
112899
  /* harmony default export */ const compile_embed = (embed_embed);
112512
112900
 
112513
- ;// ./processor/compile/gemoji.ts
112514
- const gemoji_gemoji = (node) => `:${node.name}:`;
112515
- /* harmony default export */ const compile_gemoji = (gemoji_gemoji);
112516
-
112517
112901
  ;// ./processor/compile/html-block.ts
112518
112902
 
112519
112903
  const htmlBlock = (node) => {
@@ -114496,6 +114880,86 @@ const mdxComponentHandlers = {
114496
114880
  [NodeTypes.htmlBlock]: htmlBlockHandler,
114497
114881
  };
114498
114882
 
114883
+ ;// ./processor/transform/mdxish/close-self-closing-html-tags.ts
114884
+
114885
+ /**
114886
+ * HTML void elements that are legitimately self-closing per the HTML spec.
114887
+ * These should NOT be transformed.
114888
+ *
114889
+ * @see https://html.spec.whatwg.org/multipage/syntax.html#void-elements
114890
+ */
114891
+ const HTML_VOID_ELEMENTS = new Set([
114892
+ 'area',
114893
+ 'base',
114894
+ 'br',
114895
+ 'col',
114896
+ 'embed',
114897
+ 'hr',
114898
+ 'img',
114899
+ 'input',
114900
+ 'link',
114901
+ 'meta',
114902
+ 'param',
114903
+ 'source',
114904
+ 'track',
114905
+ 'wbr',
114906
+ ]);
114907
+ /**
114908
+ * Matches self-closing HTML tags: `<tagname/>` or `<tagname attr="val" />`
114909
+ *
114910
+ * Captures:
114911
+ * 1 - tag name (lowercase letters, digits, hyphens)
114912
+ * 2 - attributes (everything between tag name and `/>`)
114913
+ *
114914
+ * The attribute portion skips over quoted strings (`"..."` and `'...'`) so that
114915
+ * a `/>` inside an attribute value (e.g. `title="use /> here"`) does not cause
114916
+ * a premature match.
114917
+ *
114918
+ * Only matches lowercase tag names to avoid interfering with PascalCase
114919
+ * JSX custom components (e.g. `<MyComponent />`), which are handled
114920
+ * separately by mdxish-component-blocks.
114921
+ */
114922
+ const SELF_CLOSING_TAG_RE = /<([a-z][a-z0-9-]*)((?:\s+(?:[^>"']*(?:"[^"]*"|'[^']*'))*[^>"']*)?)?\s*\/>/g;
114923
+ /**
114924
+ * String-level preprocessor that converts self-closing non-void HTML tags
114925
+ * into explicitly closed tags.
114926
+ *
114927
+ * Problem: `rehype-raw` (via parse5) follows the HTML spec where the `/` in
114928
+ * `<i />` is ignored for non-void elements. This causes `<i />` to be parsed
114929
+ * as an opening `<i>` tag, which then wraps all subsequent content.
114930
+ *
114931
+ * Solution: Transform `<i />` → `<i></i>` before parsing, so rehype-raw
114932
+ * sees a properly closed element.
114933
+ *
114934
+ * This preprocessor:
114935
+ * - Skips void elements (`<br />`, `<hr />`, `<img />`, etc.)
114936
+ * - Skips PascalCase tags (custom components handled elsewhere)
114937
+ * - Protects code blocks from transformation
114938
+ *
114939
+ * @example
114940
+ * closeSelfClosingHtmlTags('<i/> text') // '<i></i> text'
114941
+ * closeSelfClosingHtmlTags('<br />') // '<br />' (void, untouched)
114942
+ * closeSelfClosingHtmlTags('<MyComp />') // '<MyComp />' (PascalCase, untouched)
114943
+ * closeSelfClosingHtmlTags('<i class="icon" />') // '<i class="icon"></i>'
114944
+ */
114945
+ function closeSelfClosingHtmlTags(content) {
114946
+ const { protectedContent, protectedCode } = protectCodeBlocks(content);
114947
+ const result = protectedContent.replace(SELF_CLOSING_TAG_RE, (match, tagName, attrs) => {
114948
+ // Skip void elements (legitimately self-closing)
114949
+ if (HTML_VOID_ELEMENTS.has(tagName)) {
114950
+ return match;
114951
+ }
114952
+ // Skip tags with hyphens — these are custom elements (web components)
114953
+ // and should not be rewritten (e.g. <my-component />)
114954
+ if (tagName.includes('-')) {
114955
+ return match;
114956
+ }
114957
+ const attributes = attrs?.trim() ? ` ${attrs.trim()}` : '';
114958
+ return `<${tagName}${attributes}></${tagName}>`;
114959
+ });
114960
+ return restoreCodeBlocks(result, protectedCode);
114961
+ }
114962
+
114499
114963
  ;// ./processor/transform/mdxish/evaluate-expressions.ts
114500
114964
 
114501
114965
 
@@ -114785,166 +115249,6 @@ function legacyVariableFromMarkdown() {
114785
115249
  };
114786
115250
  }
114787
115251
 
114788
- ;// ./node_modules/micromark-util-symbol/lib/codes.js
114789
- /**
114790
- * Character codes.
114791
- *
114792
- * This module is compiled away!
114793
- *
114794
- * micromark works based on character codes.
114795
- * This module contains constants for the ASCII block and the replacement
114796
- * character.
114797
- * A couple of them are handled in a special way, such as the line endings
114798
- * (CR, LF, and CR+LF, commonly known as end-of-line: EOLs), the tab (horizontal
114799
- * tab) and its expansion based on what column it’s at (virtual space),
114800
- * and the end-of-file (eof) character.
114801
- * As values are preprocessed before handling them, the actual characters LF,
114802
- * CR, HT, and NUL (which is present as the replacement character), are
114803
- * guaranteed to not exist.
114804
- *
114805
- * Unicode basic latin block.
114806
- */
114807
- const codes = /** @type {const} */ ({
114808
- carriageReturn: -5,
114809
- lineFeed: -4,
114810
- carriageReturnLineFeed: -3,
114811
- horizontalTab: -2,
114812
- virtualSpace: -1,
114813
- eof: null,
114814
- nul: 0,
114815
- soh: 1,
114816
- stx: 2,
114817
- etx: 3,
114818
- eot: 4,
114819
- enq: 5,
114820
- ack: 6,
114821
- bel: 7,
114822
- bs: 8,
114823
- ht: 9, // `\t`
114824
- lf: 10, // `\n`
114825
- vt: 11, // `\v`
114826
- ff: 12, // `\f`
114827
- cr: 13, // `\r`
114828
- so: 14,
114829
- si: 15,
114830
- dle: 16,
114831
- dc1: 17,
114832
- dc2: 18,
114833
- dc3: 19,
114834
- dc4: 20,
114835
- nak: 21,
114836
- syn: 22,
114837
- etb: 23,
114838
- can: 24,
114839
- em: 25,
114840
- sub: 26,
114841
- esc: 27,
114842
- fs: 28,
114843
- gs: 29,
114844
- rs: 30,
114845
- us: 31,
114846
- space: 32,
114847
- exclamationMark: 33, // `!`
114848
- quotationMark: 34, // `"`
114849
- numberSign: 35, // `#`
114850
- dollarSign: 36, // `$`
114851
- percentSign: 37, // `%`
114852
- ampersand: 38, // `&`
114853
- apostrophe: 39, // `'`
114854
- leftParenthesis: 40, // `(`
114855
- rightParenthesis: 41, // `)`
114856
- asterisk: 42, // `*`
114857
- plusSign: 43, // `+`
114858
- comma: 44, // `,`
114859
- dash: 45, // `-`
114860
- dot: 46, // `.`
114861
- slash: 47, // `/`
114862
- digit0: 48, // `0`
114863
- digit1: 49, // `1`
114864
- digit2: 50, // `2`
114865
- digit3: 51, // `3`
114866
- digit4: 52, // `4`
114867
- digit5: 53, // `5`
114868
- digit6: 54, // `6`
114869
- digit7: 55, // `7`
114870
- digit8: 56, // `8`
114871
- digit9: 57, // `9`
114872
- colon: 58, // `:`
114873
- semicolon: 59, // `;`
114874
- lessThan: 60, // `<`
114875
- equalsTo: 61, // `=`
114876
- greaterThan: 62, // `>`
114877
- questionMark: 63, // `?`
114878
- atSign: 64, // `@`
114879
- uppercaseA: 65, // `A`
114880
- uppercaseB: 66, // `B`
114881
- uppercaseC: 67, // `C`
114882
- uppercaseD: 68, // `D`
114883
- uppercaseE: 69, // `E`
114884
- uppercaseF: 70, // `F`
114885
- uppercaseG: 71, // `G`
114886
- uppercaseH: 72, // `H`
114887
- uppercaseI: 73, // `I`
114888
- uppercaseJ: 74, // `J`
114889
- uppercaseK: 75, // `K`
114890
- uppercaseL: 76, // `L`
114891
- uppercaseM: 77, // `M`
114892
- uppercaseN: 78, // `N`
114893
- uppercaseO: 79, // `O`
114894
- uppercaseP: 80, // `P`
114895
- uppercaseQ: 81, // `Q`
114896
- uppercaseR: 82, // `R`
114897
- uppercaseS: 83, // `S`
114898
- uppercaseT: 84, // `T`
114899
- uppercaseU: 85, // `U`
114900
- uppercaseV: 86, // `V`
114901
- uppercaseW: 87, // `W`
114902
- uppercaseX: 88, // `X`
114903
- uppercaseY: 89, // `Y`
114904
- uppercaseZ: 90, // `Z`
114905
- leftSquareBracket: 91, // `[`
114906
- backslash: 92, // `\`
114907
- rightSquareBracket: 93, // `]`
114908
- caret: 94, // `^`
114909
- underscore: 95, // `_`
114910
- graveAccent: 96, // `` ` ``
114911
- lowercaseA: 97, // `a`
114912
- lowercaseB: 98, // `b`
114913
- lowercaseC: 99, // `c`
114914
- lowercaseD: 100, // `d`
114915
- lowercaseE: 101, // `e`
114916
- lowercaseF: 102, // `f`
114917
- lowercaseG: 103, // `g`
114918
- lowercaseH: 104, // `h`
114919
- lowercaseI: 105, // `i`
114920
- lowercaseJ: 106, // `j`
114921
- lowercaseK: 107, // `k`
114922
- lowercaseL: 108, // `l`
114923
- lowercaseM: 109, // `m`
114924
- lowercaseN: 110, // `n`
114925
- lowercaseO: 111, // `o`
114926
- lowercaseP: 112, // `p`
114927
- lowercaseQ: 113, // `q`
114928
- lowercaseR: 114, // `r`
114929
- lowercaseS: 115, // `s`
114930
- lowercaseT: 116, // `t`
114931
- lowercaseU: 117, // `u`
114932
- lowercaseV: 118, // `v`
114933
- lowercaseW: 119, // `w`
114934
- lowercaseX: 120, // `x`
114935
- lowercaseY: 121, // `y`
114936
- lowercaseZ: 122, // `z`
114937
- leftCurlyBrace: 123, // `{`
114938
- verticalBar: 124, // `|`
114939
- rightCurlyBrace: 125, // `}`
114940
- tilde: 126, // `~`
114941
- del: 127,
114942
- // Unicode Specials block.
114943
- byteOrderMarker: 65_279,
114944
- // Unicode Specials block.
114945
- replacementCharacter: 65_533 // `�`
114946
- })
114947
-
114948
115252
  ;// ./lib/micromark/legacy-variable/syntax.ts
114949
115253
 
114950
115254
 
@@ -114956,9 +115260,9 @@ function isAllowedValueChar(code) {
114956
115260
  }
114957
115261
  const legacyVariableConstruct = {
114958
115262
  name: 'legacyVariable',
114959
- tokenize,
115263
+ tokenize: syntax_tokenize,
114960
115264
  };
114961
- function tokenize(effects, ok, nok) {
115265
+ function syntax_tokenize(effects, ok, nok) {
114962
115266
  let hasValue = false;
114963
115267
  const start = (code) => {
114964
115268
  if (code !== codes.lessThan)
@@ -116097,6 +116401,8 @@ const EMPTY_CODE_PLACEHOLDER = {
116097
116401
 
116098
116402
 
116099
116403
 
116404
+
116405
+
116100
116406
 
116101
116407
 
116102
116408
 
@@ -116139,8 +116445,8 @@ const preprocessBody = (text) => {
116139
116445
  };
116140
116446
  /** Markdown parser */
116141
116447
  const contentParser = unified()
116142
- .data('micromarkExtensions', [legacyVariable(), looseHtmlEntity()])
116143
- .data('fromMarkdownExtensions', [legacyVariableFromMarkdown(), emptyTaskListItemFromMarkdown(), looseHtmlEntityFromMarkdown()])
116448
+ .data('micromarkExtensions', [syntax_gemoji(), legacyVariable(), looseHtmlEntity()])
116449
+ .data('fromMarkdownExtensions', [gemojiFromMarkdown(), legacyVariableFromMarkdown(), emptyTaskListItemFromMarkdown(), looseHtmlEntityFromMarkdown()])
116144
116450
  .use(remarkParse)
116145
116451
  .use(remarkBreaks)
116146
116452
  .use(remarkGfm)
@@ -116153,8 +116459,8 @@ const contentParser = unified()
116153
116459
  * such as `<ul><li>https://a</li>\n</ul>` due to subtokenizing recursion for URLs
116154
116460
  */
116155
116461
  const markdownToHtml = unified()
116156
- .data('micromarkExtensions', [gfmStrikethrough(), legacyVariable(), looseHtmlEntity()])
116157
- .data('fromMarkdownExtensions', [gfmStrikethroughFromMarkdown(), legacyVariableFromMarkdown(), emptyTaskListItemFromMarkdown(), looseHtmlEntityFromMarkdown()])
116462
+ .data('micromarkExtensions', [gfmStrikethrough(), syntax_gemoji(), legacyVariable(), looseHtmlEntity()])
116463
+ .data('fromMarkdownExtensions', [gfmStrikethroughFromMarkdown(), gemojiFromMarkdown(), legacyVariableFromMarkdown(), emptyTaskListItemFromMarkdown(), looseHtmlEntityFromMarkdown()])
116158
116464
  .use(remarkParse)
116159
116465
  .use(normalize_malformed_md_syntax)
116160
116466
  .use(remarkRehype)
@@ -116295,6 +116601,7 @@ const parseBlock = (text) => {
116295
116601
  */
116296
116602
  const apiHeaderTitleParser = unified()
116297
116603
  .data('micromarkExtensions', [
116604
+ syntax_gemoji(),
116298
116605
  legacyVariable(),
116299
116606
  looseHtmlEntity(),
116300
116607
  {
@@ -116308,7 +116615,7 @@ const apiHeaderTitleParser = unified()
116308
116615
  },
116309
116616
  },
116310
116617
  ])
116311
- .data('fromMarkdownExtensions', [legacyVariableFromMarkdown(), looseHtmlEntityFromMarkdown()])
116618
+ .data('fromMarkdownExtensions', [gemojiFromMarkdown(), legacyVariableFromMarkdown(), looseHtmlEntityFromMarkdown()])
116312
116619
  .use(remarkParse)
116313
116620
  .use(remarkGfm);
116314
116621
  const parseApiHeaderTitle = (text) => {
@@ -117422,6 +117729,179 @@ function mdxish_jsx_to_mdast_extractText(nodes) {
117422
117729
  })
117423
117730
  .join('');
117424
117731
  }
117732
+ const FIGURE_OPEN_REGEX = /^<figure(\s[^>]*)?>$/;
117733
+ const FIGURE_CLOSE_REGEX = /^\s*<\/figure>\s*$/;
117734
+ const FIGURE_COMPLETE_REGEX = /^<figure(\s[^>]*)?>[\s\S]*<\/figure>\s*$/;
117735
+ const FIGCAPTION_REGEX = /<figcaption>(.*?)<\/figcaption>/s;
117736
+ const FIGCAPTION_OPEN_REGEX = /^<figcaption>$/;
117737
+ const FIGCAPTION_CLOSE_REGEX = /^<\/figcaption>$/;
117738
+ /**
117739
+ * Extracts an image or image-block from a node. If the node itself is an image/image-block,
117740
+ * it is returned directly. If the node is a paragraph, its children are searched for one.
117741
+ * This is needed because standalone markdown images (`![](url)`) may be wrapped in a
117742
+ * paragraph node by the parser, or already transformed to image-block by imageTransformer.
117743
+ */
117744
+ function findImageInNode(node) {
117745
+ if (node.type === 'image' || node.type === NodeTypes.imageBlock)
117746
+ return node;
117747
+ if (node.type === 'paragraph') {
117748
+ return node.children.find(child => child.type === 'image' || child.type === NodeTypes.imageBlock);
117749
+ }
117750
+ return undefined;
117751
+ }
117752
+ /**
117753
+ * Parses a complete `<figure>` HTML string into image URL, alt text, and optional caption.
117754
+ * Returns undefined if the HTML doesn't contain a recognizable image.
117755
+ */
117756
+ function parseCompleteFigure(html) {
117757
+ const imageMatch = /!\[([^\]]*)\]\(([^)]+)\)/.exec(html);
117758
+ if (!imageMatch)
117759
+ return undefined;
117760
+ const captionMatch = FIGCAPTION_REGEX.exec(html);
117761
+ return {
117762
+ alt: imageMatch[1],
117763
+ caption: captionMatch?.[1],
117764
+ url: imageMatch[2],
117765
+ };
117766
+ }
117767
+ /**
117768
+ * Builds a FigureNode containing an image and optional figcaption from parsed figure data.
117769
+ */
117770
+ function buildFigureNode(imageNode, captionText, position) {
117771
+ const figureChildren = [imageNode];
117772
+ if (captionText) {
117773
+ figureChildren.push({
117774
+ children: [{ type: 'text', value: captionText }],
117775
+ data: { hName: 'figcaption' },
117776
+ type: 'figcaption',
117777
+ });
117778
+ }
117779
+ return {
117780
+ children: figureChildren,
117781
+ data: { hName: 'figure' },
117782
+ position,
117783
+ type: 'figure',
117784
+ };
117785
+ }
117786
+ /**
117787
+ * Scans siblings starting at `startIndex` within a parent's children looking for the
117788
+ * figcaption text and </figure> closing tag. Handles three fragmentation patterns:
117789
+ *
117790
+ * 1. Combined: `<figcaption>Hello</figcaption>\n</figure>` in one html node
117791
+ * 2. Separate: `<figcaption>Hello</figcaption>` then `</figure>` as sibling html nodes
117792
+ * 3. Split (table cells): `<figcaption>` + text(Hello) + `</figcaption>` + `</figure>` as siblings
117793
+ */
117794
+ function scanForFigcaptionAndClose(children, startIndex) {
117795
+ let captionText;
117796
+ let endIndex = startIndex - 1;
117797
+ let foundClose = false;
117798
+ for (let j = startIndex; j < children.length; j += 1) {
117799
+ const sibling = children[j];
117800
+ const htmlValue = sibling.type === 'html' ? sibling.value : undefined;
117801
+ if (htmlValue === undefined && sibling.type !== 'text')
117802
+ break;
117803
+ // Standalone </figure>
117804
+ if (htmlValue && FIGURE_CLOSE_REGEX.test(htmlValue)) {
117805
+ endIndex = j;
117806
+ foundClose = true;
117807
+ break;
117808
+ }
117809
+ // Combined <figcaption>...</figcaption> in one node (possibly with </figure>)
117810
+ if (htmlValue) {
117811
+ const figcaptionMatch = FIGCAPTION_REGEX.exec(htmlValue);
117812
+ if (figcaptionMatch) {
117813
+ captionText = figcaptionMatch[1];
117814
+ if (FIGURE_CLOSE_REGEX.test(htmlValue.replace(FIGCAPTION_REGEX, ''))) {
117815
+ endIndex = j;
117816
+ foundClose = true;
117817
+ break;
117818
+ }
117819
+ const nextSibling = children[j + 1];
117820
+ if (nextSibling?.type === 'html' && FIGURE_CLOSE_REGEX.test(nextSibling.value)) {
117821
+ endIndex = j + 1;
117822
+ foundClose = true;
117823
+ break;
117824
+ }
117825
+ }
117826
+ }
117827
+ // Split figcaption: <figcaption> + text + </figcaption> as separate nodes (table cells)
117828
+ if (htmlValue && FIGCAPTION_OPEN_REGEX.test(htmlValue)) {
117829
+ const textNode = children[j + 1];
117830
+ const closeCaption = children[j + 2];
117831
+ if (textNode?.type === 'text' &&
117832
+ closeCaption?.type === 'html' &&
117833
+ FIGCAPTION_CLOSE_REGEX.test(closeCaption.value)) {
117834
+ captionText = textNode.value;
117835
+ const closeFigure = children[j + 3];
117836
+ if (closeFigure?.type === 'html' && FIGURE_CLOSE_REGEX.test(closeFigure.value)) {
117837
+ endIndex = j + 3;
117838
+ foundClose = true;
117839
+ break;
117840
+ }
117841
+ }
117842
+ }
117843
+ }
117844
+ return { captionText, endIndex, foundClose };
117845
+ }
117846
+ /**
117847
+ * Reconstruct fragmented or complete HTML <figure> elements into figure MDAST nodes.
117848
+ *
117849
+ * Handles three html-based cases (the JSX case is handled by transformFigure in COMPONENT_MAP):
117850
+ * 1. Complete: A single html node containing the full `<figure>...<figcaption>...</figure>` block
117851
+ * (e.g. inside callouts where blockquote parsing keeps it together).
117852
+ * 2. Fragmented siblings: `terminateHtmlFlowBlocks` splits `<figure>` into separate sibling
117853
+ * nodes (open tag, image, figcaption, close tag).
117854
+ * 3. Split tags (GFM table cells): Each tag becomes its own html node with text nodes between them.
117855
+ *
117856
+ * Runs on all parent nodes so it works inside callouts, tables, and at root level.
117857
+ */
117858
+ function reassembleHtmlFigures(tree) {
117859
+ // Case 1: Handle complete <figure> blocks in a single html node (e.g. inside callouts)
117860
+ visit(tree, 'html', (node, index, parent) => {
117861
+ if (!parent || index === undefined)
117862
+ return;
117863
+ if (!FIGURE_COMPLETE_REGEX.test(node.value.trim()))
117864
+ return;
117865
+ const parsed = parseCompleteFigure(node.value);
117866
+ if (!parsed)
117867
+ return;
117868
+ const imageNode = {
117869
+ type: 'image',
117870
+ url: parsed.url,
117871
+ alt: parsed.alt,
117872
+ };
117873
+ const figureNode = buildFigureNode(imageNode, parsed.caption, node.position);
117874
+ parent.children.splice(index, 1, figureNode);
117875
+ });
117876
+ // Case 2 & 3: Handle fragmented <figure> blocks split across sibling nodes
117877
+ const processChildren = (parent) => {
117878
+ const children = parent.children;
117879
+ let i = 0;
117880
+ while (i < children.length) {
117881
+ const node = children[i];
117882
+ const nextNode = children[i + 1];
117883
+ const imageNode = nextNode ? findImageInNode(nextNode) : undefined;
117884
+ if (node.type === 'html' &&
117885
+ FIGURE_OPEN_REGEX.test(node.value.trim()) &&
117886
+ imageNode) {
117887
+ const { captionText, endIndex, foundClose } = scanForFigcaptionAndClose(children, i + 2);
117888
+ if (foundClose) {
117889
+ const figureNode = buildFigureNode(imageNode, captionText, node.position);
117890
+ parent.children.splice(i, endIndex - i + 1, figureNode);
117891
+ }
117892
+ }
117893
+ i += 1;
117894
+ }
117895
+ };
117896
+ // Process all parent nodes (root, callouts, blockquotes, table cells, list items)
117897
+ visit(tree, (node) => {
117898
+ if ('children' in node)
117899
+ processChildren(node);
117900
+ });
117901
+ }
117902
+ /**
117903
+ * Transforms an inline `<Anchor>` JSX element into a readme-anchor MDAST node.
117904
+ */
117425
117905
  const transformAnchor = (jsx) => {
117426
117906
  const attrs = getAttrs(jsx);
117427
117907
  const { href = '', label, target, title } = attrs;
@@ -117440,6 +117920,10 @@ const transformAnchor = (jsx) => {
117440
117920
  position: jsx.position,
117441
117921
  };
117442
117922
  };
117923
+ /**
117924
+ * Transforms an `<Image />` JSX element into an image-block MDAST node.
117925
+ * Normalizes attributes (align, border, width→sizing) and parses caption markdown into children.
117926
+ */
117443
117927
  const transformImage = (jsx) => {
117444
117928
  const attrs = getAttrs(jsx);
117445
117929
  const { align, alt = '', border, caption, className, height, lazy, src = '', title = '', width } = attrs;
@@ -117479,6 +117963,9 @@ const transformImage = (jsx) => {
117479
117963
  position: jsx.position,
117480
117964
  };
117481
117965
  };
117966
+ /**
117967
+ * Transforms a `<Callout>` JSX element into an rdme-callout MDAST node.
117968
+ */
117482
117969
  const transformCallout = (jsx) => {
117483
117970
  const attrs = getAttrs(jsx);
117484
117971
  const { empty = false, icon = '', theme = '' } = attrs;
@@ -117496,6 +117983,9 @@ const transformCallout = (jsx) => {
117496
117983
  position: jsx.position,
117497
117984
  };
117498
117985
  };
117986
+ /**
117987
+ * Transforms an `<Embed />` JSX element into an embed-block MDAST node.
117988
+ */
117499
117989
  const transformEmbed = (jsx) => {
117500
117990
  const attrs = getAttrs(jsx);
117501
117991
  const { favicon, height, href, html, iframe, image, providerName, providerUrl, provider, title = '', typeOfEmbed, url = '', width, } = attrs;
@@ -117524,6 +118014,9 @@ const transformEmbed = (jsx) => {
117524
118014
  position: jsx.position,
117525
118015
  };
117526
118016
  };
118017
+ /**
118018
+ * Transforms a `<Recipe />` JSX element into a recipe MDAST node.
118019
+ */
117527
118020
  const transformRecipe = (jsx) => {
117528
118021
  const attrs = getAttrs(jsx);
117529
118022
  const { backgroundColor = '', emoji = '', id = '', link = '', slug = '', title = '' } = attrs;
@@ -117660,21 +118153,44 @@ const transformTable = (jsx) => {
117660
118153
  children: rows,
117661
118154
  };
117662
118155
  };
118156
+ /**
118157
+ * Transforms a `<figure>` JSX element into a FigureNode.
118158
+ * Inside JSX tables with blank lines, the parser treats `<figure>` as an mdxJsxFlowElement
118159
+ * containing a paragraph with the image and a `<figcaption>` mdxJsxTextElement as children.
118160
+ */
118161
+ const transformFigure = (jsx) => {
118162
+ let imageNode;
118163
+ let captionText;
118164
+ visit(jsx, (child) => {
118165
+ if (!imageNode && (child.type === 'image' || child.type === NodeTypes.imageBlock)) {
118166
+ imageNode = child;
118167
+ }
118168
+ if (!captionText && child.type === 'mdxJsxTextElement' && child.name === 'figcaption') {
118169
+ captionText = mdxish_jsx_to_mdast_extractText(child.children);
118170
+ }
118171
+ });
118172
+ if (!imageNode)
118173
+ return null;
118174
+ return buildFigureNode(imageNode, captionText, jsx.position);
118175
+ };
117663
118176
  const COMPONENT_MAP = {
117664
118177
  Callout: transformCallout,
117665
118178
  Embed: transformEmbed,
117666
118179
  Image: transformImage,
118180
+ figure: transformFigure,
117667
118181
  Recipe: transformRecipe,
117668
118182
  Table: transformTable,
117669
118183
  };
117670
118184
  /**
117671
- * Transform mdxJsxFlowElement nodes and magic block nodes into proper MDAST node types.
118185
+ * Transform mdxJsxFlowElement nodes, magic block nodes, and HTML figure elements
118186
+ * into proper MDAST node types.
117672
118187
  *
117673
118188
  * This transformer runs after mdxishComponentBlocks and converts:
117674
- * - JSX component elements (Image, Callout, Embed, Recipe) into their corresponding MDAST types
118189
+ * - JSX component elements (Image, Callout, Embed, Recipe, figure) into their corresponding MDAST types
117675
118190
  * - Magic block image nodes (type: 'image') into image-block
117676
118191
  * - Magic block embed nodes (type: 'embed') into embed-block
117677
- * - Figure nodes (magic blocks with captions) into flat image-block with caption string
118192
+ * - Fragmented HTML <figure> blocks (from terminateHtmlFlowBlocks) back into figure nodes
118193
+ * - Figure nodes (from magic blocks, HTML, or JSX) into flat image-block with caption string
117678
118194
  * - Normalizes all image-block attrs (border, align, sizing, caption) to a consistent shape
117679
118195
  *
117680
118196
  * This is controlled by the `newEditorTypes` flag to maintain backwards compatibility.
@@ -117721,6 +118237,9 @@ const mdxishJsxToMdast = () => tree => {
117721
118237
  parent.children[index] = newNode;
117722
118238
  return SKIP;
117723
118239
  });
118240
+ // Reassembling fragmented HTML <figure> blocks into proper figure/figcaption nodes
118241
+ // this will then later be transformed into image-block nodes by imageTransformer
118242
+ reassembleHtmlFigures(tree);
117724
118243
  // Flatten figure nodes (magic blocks with captions) into image-block nodes
117725
118244
  const isFigure = (node) => node.type === 'figure';
117726
118245
  visit(tree, isFigure, (node, index, parent) => {
@@ -117973,6 +118492,7 @@ function restoreSnakeCase(placeholderName, mapping) {
117973
118492
  ;// ./processor/transform/mdxish/mdxish-tables-to-jsx.ts
117974
118493
 
117975
118494
 
118495
+ const SELF_CLOSING_JSX_REGEX = /^\s*<[A-Z][^>]*\/>\s*$/;
117976
118496
  const mdxish_tables_to_jsx_alignToStyle = (align) => {
117977
118497
  if (!align || align === 'left')
117978
118498
  return null;
@@ -117999,7 +118519,7 @@ const mdxishTablesToJsx = () => tree => {
117999
118519
  visit(tree, (node) => ['table', 'tableau'].includes(node.type), (table, index, parent) => {
118000
118520
  let hasFlowContent = false;
118001
118521
  visit(table, mdxish_tables_to_jsx_isTableCell, (cell) => {
118002
- if (cell.children.length === 0)
118522
+ if (hasFlowContent || cell.children.length === 0)
118003
118523
  return;
118004
118524
  const content = cell.children.length === 1 && cell.children[0].type === 'paragraph'
118005
118525
  ? cell.children[0].children[0]
@@ -118010,17 +118530,21 @@ const mdxishTablesToJsx = () => tree => {
118010
118530
  breakParent.children.splice(breakIndex, 1, { type: 'text', value: '\n' });
118011
118531
  });
118012
118532
  if (!(phrasing(content) || content.type === 'plain') && content.type !== 'escape') {
118013
- if (content.type === 'html')
118014
- return;
118015
- hasFlowContent = true;
118016
- return EXIT;
118017
- }
118018
- visit(cell, mdxish_tables_to_jsx_isLiteral, (node) => {
118019
- if (node.value.match(/\n/)) {
118533
+ // Plain HTML (e.g. <div>Hello</div>) is skipped here — it stays in GFM cells fine.
118534
+ // But self-closing JSX components (e.g. <Image src="..." caption="..." />) serialize
118535
+ // with newlines that break GFM cells, so they must trigger JSX <Table> serialization.
118536
+ const isPlainHtml = content.type === 'html' && !SELF_CLOSING_JSX_REGEX.test(content.value);
118537
+ if (!isPlainHtml) {
118020
118538
  hasFlowContent = true;
118021
- return EXIT;
118022
118539
  }
118023
- });
118540
+ }
118541
+ if (!hasFlowContent) {
118542
+ visit(cell, mdxish_tables_to_jsx_isLiteral, (node) => {
118543
+ if (node.value.match(/\n/)) {
118544
+ hasFlowContent = true;
118545
+ }
118546
+ });
118547
+ }
118024
118548
  });
118025
118549
  if (!hasFlowContent) {
118026
118550
  table.type = 'table';
@@ -120260,13 +120784,14 @@ function loadComponents() {
120260
120784
 
120261
120785
 
120262
120786
 
120787
+
120788
+
120263
120789
 
120264
120790
 
120265
120791
 
120266
120792
  const defaultTransformers = [
120267
120793
  [callouts, { isMdxish: true }],
120268
120794
  code_tabs,
120269
- gemoji_,
120270
120795
  transform_embeds,
120271
120796
  ];
120272
120797
  /**
@@ -120276,13 +120801,15 @@ const defaultTransformers = [
120276
120801
  * Runs a series of string-level transformations before micromark/remark parsing:
120277
120802
  * 1. Normalize malformed table separator syntax (e.g., `|: ---` → `| :---`)
120278
120803
  * 2. Terminate HTML flow blocks so subsequent content isn't swallowed
120279
- * 3. Evaluate JSX expressions in attributes (unless safeMode)
120280
- * 4. Replace snake_case component names with parser-safe placeholders
120804
+ * 3. Close invalid "self-closing" HTML tags (e.g., `<i />` → `<i></i>`)
120805
+ * 4. Evaluate JSX expressions in attributes (unless safeMode)
120806
+ * 5. Replace snake_case component names with parser-safe placeholders
120281
120807
  */
120282
120808
  function preprocessContent(content, opts) {
120283
120809
  const { safeMode, jsxContext, knownComponents } = opts;
120284
120810
  let result = normalizeTableSeparator(content);
120285
120811
  result = terminateHtmlFlowBlocks(result);
120812
+ result = closeSelfClosingHtmlTags(result);
120286
120813
  result = safeMode ? result : preprocessJSXExpressions(result, jsxContext);
120287
120814
  return processSnakeCaseComponent(result, { knownComponents });
120288
120815
  }
@@ -120312,12 +120839,13 @@ function mdxishAstProcessor(mdContent, opts = {}) {
120312
120839
  };
120313
120840
  const processor = unified()
120314
120841
  .data('micromarkExtensions', safeMode
120315
- ? [jsxTable(), magicBlock(), legacyVariable(), looseHtmlEntity()]
120316
- : [jsxTable(), magicBlock(), mdxExprTextOnly, legacyVariable(), looseHtmlEntity()])
120842
+ ? [jsxTable(), magicBlock(), syntax_gemoji(), legacyVariable(), looseHtmlEntity()]
120843
+ : [jsxTable(), magicBlock(), syntax_gemoji(), mdxExprTextOnly, legacyVariable(), looseHtmlEntity()])
120317
120844
  .data('fromMarkdownExtensions', safeMode
120318
120845
  ? [
120319
120846
  jsxTableFromMarkdown(),
120320
120847
  magicBlockFromMarkdown(),
120848
+ gemojiFromMarkdown(),
120321
120849
  legacyVariableFromMarkdown(),
120322
120850
  emptyTaskListItemFromMarkdown(),
120323
120851
  looseHtmlEntityFromMarkdown(),
@@ -120325,6 +120853,7 @@ function mdxishAstProcessor(mdContent, opts = {}) {
120325
120853
  : [
120326
120854
  jsxTableFromMarkdown(),
120327
120855
  magicBlockFromMarkdown(),
120856
+ gemojiFromMarkdown(),
120328
120857
  mdxExpressionFromMarkdown(),
120329
120858
  legacyVariableFromMarkdown(),
120330
120859
  emptyTaskListItemFromMarkdown(),
@@ -120683,7 +121212,7 @@ function createTocComponent(tocHast) {
120683
121212
  components: { p: (external_react_default()).Fragment },
120684
121213
  });
120685
121214
  const tocReactElement = tocProcessor.stringify(tocHast);
120686
- const TocComponent = (props) => tocReactElement ? (external_react_default().createElement(components_TableOfContents, { heading: props.heading }, tocReactElement)) : null;
121215
+ const TocComponent = () => tocReactElement ? (external_react_default().createElement(components_TableOfContents, null, tocReactElement)) : null;
120687
121216
  TocComponent.displayName = 'Toc';
120688
121217
  return TocComponent;
120689
121218
  }
@@ -120849,7 +121378,7 @@ const run_run = (string, _opts = {}) => {
120849
121378
  default: (props) => (external_react_default().createElement(contexts, { baseUrl: baseUrl, copyButtons: copyButtons, terms: terms, theme: theme, variables: variables },
120850
121379
  external_react_default().createElement(Content, { ...props }))),
120851
121380
  toc,
120852
- Toc: (props) => Toc ? (external_react_default().createElement(components_TableOfContents, { heading: props.heading },
121381
+ Toc: () => Toc ? (external_react_default().createElement(components_TableOfContents, null,
120853
121382
  external_react_default().createElement(Toc, null))) : null,
120854
121383
  stylesheet,
120855
121384
  ...exports,