@readme/markdown 14.3.0 → 14.4.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
@@ -12208,9 +12208,10 @@ const LightboxPortal = ({ children }) => {
12208
12208
  return (0,external_amd_react_dom_commonjs2_react_dom_commonjs_react_dom_root_ReactDOM_umd_react_dom_.createPortal)(children, document.body);
12209
12209
  };
12210
12210
  const Image = (Props) => {
12211
- const { align = '', alt = '', border: borderProp = false, caption, className = '', height = 'auto', src, title = '', width = 'auto', lazy = true, children, } = Props;
12212
- // Normalize border: MDXish passes {false} as the string "false", not a boolean
12211
+ const { align = '', alt = '', border: borderProp = false, caption, className = '', framed: framedProp = false, height = 'auto', src, title = '', width = 'auto', lazy = true, children, } = Props;
12212
+ // Normalize border/framed: MDXish passes {false} as the string "false", not a boolean
12213
12213
  const border = borderProp === true || borderProp === 'true';
12214
+ const framed = framedProp === true || framedProp === 'true';
12214
12215
  const [lightbox, setLightbox] = external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_.useState(false);
12215
12216
  if (className === 'emoji') {
12216
12217
  return external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_.createElement("img", { alt: alt, height: height, loading: lazy ? 'lazy' : 'eager', src: src, title: title, width: width });
@@ -12239,7 +12240,10 @@ const Image = (Props) => {
12239
12240
  return;
12240
12241
  setLightbox(!lightbox);
12241
12242
  };
12242
- const imgElement = (external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_.createElement("img", { alt: alt, className: `img ${caption || children ? 'img-align-center' : align ? `img-align-${align}` : ''} ${border ? 'border' : ''}`, height: height, loading: lazy ? 'lazy' : 'eager', src: src, title: title, width: width }));
12243
+ // Framed images center the <img> itself; outer wrapper handles left/right alignment via text-align.
12244
+ const imgElement = (external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_.createElement("img", { alt: alt, className: `img ${caption || children || framed ? 'img-align-center' : align ? `img-align-${align}` : ''} ${border ? 'border' : ''}`, height: height, loading: lazy ? 'lazy' : 'eager', src: src, title: title, width: width }));
12245
+ const closedLightbox = (ariaLabel, content) => (external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_.createElement("span", { "aria-label": ariaLabel, className: "img lightbox closed", onClick: toggle, onKeyDown: handleKeyDown, role: 'button', tabIndex: 0 },
12246
+ external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_.createElement("span", { className: "lightbox-inner" }, content)));
12243
12247
  const lightboxOverlay = lightbox ? (external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_.createElement(LightboxPortal, null,
12244
12248
  external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_.createElement("div", { className: "markdown-body" },
12245
12249
  external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_.createElement("span", { "aria-label": alt || 'Collapse image', className: "img lightbox open", onClick: toggle, onKeyDown: handleKeyDown, role: 'button', tabIndex: 0 },
@@ -12248,17 +12252,27 @@ const Image = (Props) => {
12248
12252
  (children || caption) && external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_.createElement("figcaption", null, children || caption))),
12249
12253
  external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_.createElement("button", { "aria-label": "Minimize image", className: "lightbox-close", onClick: toggle, type: "button" },
12250
12254
  external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_.createElement("i", { "aria-hidden": "true", className: "fa-solid fa-xmark" }))))) : null;
12255
+ if (framed) {
12256
+ const frameClass = `img-frame img-frame-${align || 'center'}`;
12257
+ if (children || caption) {
12258
+ return (external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_.createElement("figure", { className: frameClass },
12259
+ closedLightbox(alt || 'Expand image', imgElement),
12260
+ lightboxOverlay,
12261
+ external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_.createElement("figcaption", null, children || caption)));
12262
+ }
12263
+ return (external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_.createElement("div", { className: frameClass },
12264
+ closedLightbox(alt || 'Expand image', imgElement),
12265
+ lightboxOverlay));
12266
+ }
12251
12267
  if (children || caption) {
12252
12268
  return (external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_.createElement("figure", null,
12253
- external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_.createElement("span", { "aria-label": alt, className: "img lightbox closed", onClick: toggle, onKeyDown: handleKeyDown, role: 'button', tabIndex: 0 },
12254
- external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_.createElement("span", { className: "lightbox-inner" },
12255
- imgElement,
12256
- external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_.createElement("figcaption", null, children || caption))),
12269
+ closedLightbox(alt || 'Expand image', external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_.createElement(external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_.Fragment, null,
12270
+ imgElement,
12271
+ external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_.createElement("figcaption", null, children || caption))),
12257
12272
  lightboxOverlay));
12258
12273
  }
12259
12274
  return (external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_.createElement(external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_.Fragment, null,
12260
- external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_.createElement("span", { "aria-label": "Expand image", className: "img lightbox closed", onClick: toggle, onKeyDown: handleKeyDown, role: 'button', tabIndex: 0 },
12261
- external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_.createElement("span", { className: "lightbox-inner" }, imgElement)),
12275
+ closedLightbox('Expand image', imgElement),
12262
12276
  lightboxOverlay));
12263
12277
  };
12264
12278
  /* harmony default export */ const components_Image = (Image);
@@ -12496,12 +12510,14 @@ const Tab = ({ children }) => {
12496
12510
  };
12497
12511
  const Tabs = ({ children }) => {
12498
12512
  const [activeTab, setActiveTab] = (0,external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_.useState)(0);
12513
+ // React passes `children` as a single element when there's only one child, so normalize.
12514
+ const tabs = external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default().Children.toArray(children);
12499
12515
  return (external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default().createElement("div", { className: "TabGroup" },
12500
12516
  external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default().createElement("header", null,
12501
- external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default().createElement("nav", { className: "TabGroup-nav" }, children?.map((tab, index) => (external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default().createElement("button", { key: tab.props.title, className: `TabGroup-tab${activeTab === index ? '_active' : ''}`, onClick: () => setActiveTab(index) },
12517
+ external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default().createElement("nav", { className: "TabGroup-nav" }, tabs.map((tab, index) => (external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default().createElement("button", { key: tab.props.title, className: `TabGroup-tab${activeTab === index ? '_active' : ''}`, onClick: () => setActiveTab(index) },
12502
12518
  tab.props.icon && (external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default().createElement("i", { className: `TabGroup-icon fa-duotone fa-solid ${tab.props.icon}`, style: { color: `${tab.props.iconColor}` } })),
12503
12519
  tab.props.title))))),
12504
- external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default().createElement("section", null, children && children[activeTab])));
12520
+ external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default().createElement("section", null, tabs[activeTab])));
12505
12521
  };
12506
12522
  /* harmony default export */ const components_Tabs = (Tabs);
12507
12523
 
@@ -75582,13 +75598,14 @@ const applyInserts = (html, inserts) => {
75582
75598
  const sorted = [...inserts].sort((a, b) => a.offset - b.offset);
75583
75599
  let out = '';
75584
75600
  let cursor = 0;
75585
- sorted.forEach(({ offset, text }) => {
75601
+ sorted.forEach(({ offset, text, consumes = 0 }) => {
75586
75602
  const clamped = Math.min(Math.max(offset, cursor), html.length);
75587
75603
  if (clamped > cursor) {
75588
75604
  out += html.slice(cursor, clamped);
75589
75605
  cursor = clamped;
75590
75606
  }
75591
75607
  out += text;
75608
+ cursor = Math.min(cursor + consumes, html.length);
75592
75609
  });
75593
75610
  return { value: out + html.slice(cursor), inserts: sorted };
75594
75611
  };
@@ -75700,9 +75717,10 @@ const buildOffsetMapper = (inserts) => {
75700
75717
  // Pre-compute each insert's start in repaired-space.
75701
75718
  let acc = 0;
75702
75719
  const segments = inserts.map(ins => {
75720
+ const consumes = ins.consumes ?? 0;
75703
75721
  const repairedStart = ins.offset + acc;
75704
- acc += ins.text.length;
75705
- return { origOffset: ins.offset, len: ins.text.length, repairedStart };
75722
+ acc += ins.text.length - consumes;
75723
+ return { origOffset: ins.offset, consumes, len: ins.text.length, repairedStart };
75706
75724
  });
75707
75725
  return (repaired) => {
75708
75726
  // Offsets inside an insert's synthetic span have no original counterpart;
@@ -75710,7 +75728,7 @@ const buildOffsetMapper = (inserts) => {
75710
75728
  const hit = segments.find(seg => seg.repairedStart < repaired && repaired < seg.repairedStart + seg.len);
75711
75729
  if (hit)
75712
75730
  return hit.origOffset;
75713
- const shift = segments.reduce((acc2, seg) => (seg.repairedStart < repaired ? acc2 + seg.len : acc2), 0);
75731
+ const shift = segments.reduce((acc2, seg) => (seg.repairedStart < repaired ? acc2 + seg.len - seg.consumes : acc2), 0);
75714
75732
  return repaired - shift;
75715
75733
  };
75716
75734
  };
@@ -75889,6 +75907,43 @@ const HTML_VOID_ELEMENTS = new Set([
75889
75907
 
75890
75908
 
75891
75909
  const isStandardHtmlTag = (name) => STANDARD_HTML_TAGS.has(name.toLowerCase());
75910
+ // Intentionally simpler than htmlparser2: `[^>]*` does not honor `>` inside
75911
+ // quoted attribute values. That's acceptable here because the main walker
75912
+ // (htmlparser2) handles attribute parsing; this scan only needs to locate
75913
+ // orphan closers, which can't appear inside an attribute value anyway.
75914
+ const HTML_TAG_TOKEN_RE = /<(\/)?([a-zA-Z][a-zA-Z0-9-]*)\b[^>]*>/g;
75915
+ /**
75916
+ * htmlparser2 silently drops closing tags that have no matching opener
75917
+ * (e.g. the trailing `</li>` in `<ul><li>x</ul></li>`), leaving them in the
75918
+ * source makes mdxjs choke on the dangling closer. Scan the masked
75919
+ * source for `</name>` tokens that don't pair with any prior unmatched
75920
+ * `<name>` and return their spans so the caller can drop them.
75921
+ */
75922
+ const findOrphanClosers = (html) => {
75923
+ const masked = maskNonTagRegions(html);
75924
+ const stack = [];
75925
+ const orphans = [];
75926
+ HTML_TAG_TOKEN_RE.lastIndex = 0;
75927
+ let match;
75928
+ while ((match = HTML_TAG_TOKEN_RE.exec(masked)) !== null) {
75929
+ const name = match[2].toLowerCase();
75930
+ // Non-HTML names and void elements are handled by the main walker.
75931
+ // eslint-disable-next-line no-continue
75932
+ if (!isStandardHtmlTag(name) || HTML_VOID_ELEMENTS.has(name))
75933
+ continue;
75934
+ if (match[1] === '/') {
75935
+ const idx = stack.lastIndexOf(name);
75936
+ if (idx === -1)
75937
+ orphans.push({ offset: match.index, length: match[0].length });
75938
+ else
75939
+ stack.length = idx;
75940
+ }
75941
+ else if (!match[0].endsWith('/>')) {
75942
+ stack.push(name);
75943
+ }
75944
+ }
75945
+ return orphans;
75946
+ };
75892
75947
  /**
75893
75948
  * MDX requires a JSX inline tag and its closer to live on the same line — not
75894
75949
  * just the same paragraph. (`<td>\nArray <object>\n</object></td>` still
@@ -75945,6 +76000,7 @@ const repairUnclosedTags = (html) => {
75945
76000
  inserts.push({ offset: findOffsetToPlaceCloser(html, openTag.end, start), text: `</${name}>` });
75946
76001
  },
75947
76002
  });
76003
+ findOrphanClosers(html).forEach(({ offset, length }) => inserts.push({ offset, text: '', consumes: length }));
75948
76004
  return applyInserts(html, inserts);
75949
76005
  };
75950
76006
 
@@ -98374,6 +98430,12 @@ function parseTextChildren(node, processMarkdown, components) {
98374
98430
  node.children = node.children.flatMap(child => {
98375
98431
  if (child.type !== 'text' || !child.value.trim())
98376
98432
  return [child];
98433
+ // Store multiline template-literal children (e.g. {`...\n...`}) as a bare string prop
98434
+ // via node.properties.children so hast-to-hyperscript doesn't wrap them in an array.
98435
+ if (child.value.includes('\n')) {
98436
+ node.properties = { ...node.properties, children: child.value };
98437
+ return [];
98438
+ }
98377
98439
  const hast = processMarkdown(child.value.trim());
98378
98440
  const children = (hast.children ?? []).filter(isElementContentNode);
98379
98441
  // For inline components, preserve plain text instead of wrapping in <p>
@@ -100525,6 +100587,123 @@ function createTokenize(mode) {
100525
100587
  const isSameCaseAsTag = (code) => isLowercaseTag
100526
100588
  ? code >= codes.lowercaseA && code <= codes.lowercaseZ
100527
100589
  : code >= codes.uppercaseA && code <= codes.uppercaseZ;
100590
+ // Shared brace-expression state machine. The two call sites differ only in where
100591
+ // to continue after a line ending and where to return when braceDepth reaches zero.
100592
+ function createBraceExprStates(continuationStart, afterBraceClose) {
100593
+ function braceExpr(code) {
100594
+ if (code === null)
100595
+ return nok(code);
100596
+ if (markdownLineEnding(code)) {
100597
+ if (!isFlow)
100598
+ return nok(code);
100599
+ effects.exit('mdxComponentData');
100600
+ return continuationStart(code);
100601
+ }
100602
+ if (code === codes.quotationMark || code === codes.apostrophe) {
100603
+ quoteChar = code;
100604
+ effects.consume(code);
100605
+ return braceString;
100606
+ }
100607
+ if (code === codes.graveAccent) {
100608
+ inTemplateLit = true;
100609
+ effects.consume(code);
100610
+ return braceTemplateLiteral;
100611
+ }
100612
+ if (code === codes.leftCurlyBrace) {
100613
+ braceDepth += 1;
100614
+ effects.consume(code);
100615
+ return braceExpr;
100616
+ }
100617
+ if (code === codes.rightCurlyBrace) {
100618
+ braceDepth -= 1;
100619
+ effects.consume(code);
100620
+ if (templateStack.length > 0 && braceDepth === templateStack[templateStack.length - 1]) {
100621
+ templateStack.pop();
100622
+ inTemplateLit = true;
100623
+ return braceTemplateLiteral;
100624
+ }
100625
+ if (braceDepth === 0) {
100626
+ return afterBraceClose;
100627
+ }
100628
+ return braceExpr;
100629
+ }
100630
+ effects.consume(code);
100631
+ return braceExpr;
100632
+ }
100633
+ function braceString(code) {
100634
+ if (code === null)
100635
+ return nok(code);
100636
+ if (markdownLineEnding(code)) {
100637
+ if (!isFlow)
100638
+ return nok(code);
100639
+ effects.exit('mdxComponentData');
100640
+ return continuationStart(code);
100641
+ }
100642
+ if (code === codes.backslash) {
100643
+ effects.consume(code);
100644
+ return braceStringEscape;
100645
+ }
100646
+ if (code === quoteChar) {
100647
+ effects.consume(code);
100648
+ quoteChar = null;
100649
+ return braceExpr;
100650
+ }
100651
+ effects.consume(code);
100652
+ return braceString;
100653
+ }
100654
+ function braceStringEscape(code) {
100655
+ if (code === null || markdownLineEnding(code)) {
100656
+ return braceString(code);
100657
+ }
100658
+ effects.consume(code);
100659
+ return braceString;
100660
+ }
100661
+ function braceTemplateLiteral(code) {
100662
+ if (code === null)
100663
+ return nok(code);
100664
+ if (markdownLineEnding(code)) {
100665
+ if (!isFlow)
100666
+ return nok(code);
100667
+ effects.exit('mdxComponentData');
100668
+ return continuationStart(code);
100669
+ }
100670
+ if (code === codes.graveAccent) {
100671
+ inTemplateLit = false;
100672
+ effects.consume(code);
100673
+ return braceExpr;
100674
+ }
100675
+ if (code === codes.backslash) {
100676
+ effects.consume(code);
100677
+ return braceTemplateLiteralEscape;
100678
+ }
100679
+ if (code === codes.dollarSign) {
100680
+ effects.consume(code);
100681
+ return braceTemplateLiteralDollar;
100682
+ }
100683
+ effects.consume(code);
100684
+ return braceTemplateLiteral;
100685
+ }
100686
+ function braceTemplateLiteralEscape(code) {
100687
+ if (code === null || markdownLineEnding(code)) {
100688
+ return braceTemplateLiteral(code);
100689
+ }
100690
+ effects.consume(code);
100691
+ return braceTemplateLiteral;
100692
+ }
100693
+ function braceTemplateLiteralDollar(code) {
100694
+ if (code === codes.leftCurlyBrace) {
100695
+ templateStack.push(braceDepth);
100696
+ braceDepth += 1;
100697
+ inTemplateLit = false;
100698
+ effects.consume(code);
100699
+ return braceExpr;
100700
+ }
100701
+ return braceTemplateLiteral(code);
100702
+ }
100703
+ return { braceExpr, braceString, braceTemplateLiteral };
100704
+ }
100705
+ const { braceExpr: inBraceExpr, braceString: inBraceString, braceTemplateLiteral: inBraceTemplateLiteral, } = createBraceExprStates(openTagContinuationStart, afterOpenTagName);
100706
+ const { braceExpr: inBodyBraceExpr, braceString: inBodyBraceString, braceTemplateLiteral: inBodyBraceTemplateLiteral, } = createBraceExprStates(bodyContinuationStart, body);
100528
100707
  return start;
100529
100708
  // ── Start ──────────────────────────────────────────────────────────────
100530
100709
  function start(code) {
@@ -100647,126 +100826,6 @@ function createTokenize(mode) {
100647
100826
  effects.consume(code);
100648
100827
  return inQuotedAttr;
100649
100828
  }
100650
- function inBraceExpr(code) {
100651
- if (code === null)
100652
- return nok(code);
100653
- if (markdownLineEnding(code)) {
100654
- if (!isFlow)
100655
- return nok(code);
100656
- effects.exit('mdxComponentData');
100657
- return openTagContinuationStart(code);
100658
- }
100659
- // Handle strings inside braces
100660
- if (code === codes.quotationMark || code === codes.apostrophe) {
100661
- quoteChar = code;
100662
- effects.consume(code);
100663
- return inBraceString;
100664
- }
100665
- // Handle template literals inside braces
100666
- if (code === codes.graveAccent) {
100667
- inTemplateLit = true;
100668
- effects.consume(code);
100669
- return inBraceTemplateLiteral;
100670
- }
100671
- if (code === codes.leftCurlyBrace) {
100672
- braceDepth += 1;
100673
- effects.consume(code);
100674
- return inBraceExpr;
100675
- }
100676
- if (code === codes.rightCurlyBrace) {
100677
- braceDepth -= 1;
100678
- effects.consume(code);
100679
- // Check if this } closes a ${...} interpolation
100680
- if (templateStack.length > 0 && braceDepth === templateStack[templateStack.length - 1]) {
100681
- templateStack.pop();
100682
- inTemplateLit = true; // back inside the template literal
100683
- return inBraceTemplateLiteral;
100684
- }
100685
- if (braceDepth === 0) {
100686
- return afterOpenTagName;
100687
- }
100688
- return inBraceExpr;
100689
- }
100690
- effects.consume(code);
100691
- return inBraceExpr;
100692
- }
100693
- function inBraceString(code) {
100694
- if (code === null)
100695
- return nok(code);
100696
- if (markdownLineEnding(code)) {
100697
- if (!isFlow)
100698
- return nok(code);
100699
- effects.exit('mdxComponentData');
100700
- return openTagContinuationStart(code);
100701
- }
100702
- if (code === codes.backslash) {
100703
- effects.consume(code);
100704
- return inBraceStringEscape;
100705
- }
100706
- if (code === quoteChar) {
100707
- effects.consume(code);
100708
- quoteChar = null;
100709
- return inBraceExpr;
100710
- }
100711
- effects.consume(code);
100712
- return inBraceString;
100713
- }
100714
- function inBraceStringEscape(code) {
100715
- if (code === null || markdownLineEnding(code)) {
100716
- return inBraceString(code);
100717
- }
100718
- effects.consume(code);
100719
- return inBraceString;
100720
- }
100721
- // ── Template literal handling inside brace expressions ─────────────────
100722
- function inBraceTemplateLiteral(code) {
100723
- if (code === null)
100724
- return nok(code);
100725
- if (markdownLineEnding(code)) {
100726
- if (!isFlow)
100727
- return nok(code);
100728
- effects.exit('mdxComponentData');
100729
- return openTagContinuationStart(code);
100730
- }
100731
- // Closing backtick ends the template literal
100732
- if (code === codes.graveAccent) {
100733
- inTemplateLit = false;
100734
- effects.consume(code);
100735
- return inBraceExpr;
100736
- }
100737
- // Backslash escape (e.g., \` or \$)
100738
- if (code === codes.backslash) {
100739
- effects.consume(code);
100740
- return inBraceTemplateLiteralEscape;
100741
- }
100742
- // ${ starts an interpolation
100743
- if (code === codes.dollarSign) {
100744
- effects.consume(code);
100745
- return inBraceTemplateLiteralDollar;
100746
- }
100747
- effects.consume(code);
100748
- return inBraceTemplateLiteral;
100749
- }
100750
- function inBraceTemplateLiteralEscape(code) {
100751
- if (code === null || markdownLineEnding(code)) {
100752
- return inBraceTemplateLiteral(code);
100753
- }
100754
- effects.consume(code);
100755
- return inBraceTemplateLiteral;
100756
- }
100757
- function inBraceTemplateLiteralDollar(code) {
100758
- if (code === codes.leftCurlyBrace) {
100759
- // Enter ${...} interpolation. Save current braceDepth so we know
100760
- // when the matching } returns us to this template literal.
100761
- templateStack.push(braceDepth);
100762
- braceDepth += 1;
100763
- inTemplateLit = false; // now inside interpolation expression
100764
- effects.consume(code);
100765
- return inBraceExpr;
100766
- }
100767
- // Just a $ not followed by { — back to template literal
100768
- return inBraceTemplateLiteral(code);
100769
- }
100770
100829
  function selfCloseGt(code) {
100771
100830
  if (code === codes.greaterThan) {
100772
100831
  effects.consume(code);
@@ -100836,6 +100895,15 @@ function createTokenize(mode) {
100836
100895
  codeSpanOpenSize = 0;
100837
100896
  return countOpenTicks(code);
100838
100897
  }
100898
+ // JSX expression child — track braces/template literals so the closing
100899
+ // backtick of `{`...`}` is not misread as a code span opener
100900
+ if (code === codes.leftCurlyBrace) {
100901
+ braceDepth = 1;
100902
+ inTemplateLit = false;
100903
+ effects.consume(code);
100904
+ atLineStart = false;
100905
+ return inBodyBraceExpr;
100906
+ }
100839
100907
  effects.consume(code);
100840
100908
  atLineStart = false;
100841
100909
  return body;
@@ -101076,6 +101144,14 @@ function createTokenize(mode) {
101076
101144
  return bodyContinuationStart(code);
101077
101145
  }
101078
101146
  effects.enter('mdxComponentData');
101147
+ // Resume inside a body brace expression if a line ending interrupted one
101148
+ if (braceDepth > 0) {
101149
+ if (inTemplateLit)
101150
+ return inBodyBraceTemplateLiteral(code);
101151
+ if (quoteChar !== null)
101152
+ return inBodyBraceString(code);
101153
+ return inBodyBraceExpr(code);
101154
+ }
101079
101155
  // Detect tilde fences at line start
101080
101156
  if (atLineStart && code === codes.tilde) {
101081
101157
  return bodyAfterLineStart(code);
@@ -101178,7 +101254,8 @@ const buildInlineMdProcessor = (safeMode) => {
101178
101254
  // Since evaluating expressions can be dangerous, do so only when safeMode is off
101179
101255
  if (!safeMode) {
101180
101256
  const mdxExprExt = mdxExpression({ allowEmpty: true });
101181
- micromarkExts.push({ text: mdxExprExt.text });
101257
+ // We include both flow and text extensions to support both single-line and multi-line expressions
101258
+ micromarkExts.push({ flow: mdxExprExt.flow, text: mdxExprExt.text });
101182
101259
  fromMarkdownExts.push(mdxExpressionFromMarkdown());
101183
101260
  }
101184
101261
  return unified()
@@ -101836,7 +101913,7 @@ const createEvaluatedNode = (result, position) => {
101836
101913
  else if (typeof result === 'object') {
101837
101914
  return { type: 'text', value: JSON.stringify(result), position };
101838
101915
  }
101839
- return { type: 'text', value: String(result).replace(/\s+/g, ' ').trim(), position };
101916
+ return { type: 'text', value: String(result), position };
101840
101917
  };
101841
101918
  /**
101842
101919
  * AST transformer to evaluate MDX expressions.
@@ -103546,7 +103623,7 @@ const transformAnchor = (jsx) => {
103546
103623
  */
103547
103624
  const transformImage = (jsx) => {
103548
103625
  const attrs = getAttrs(jsx);
103549
- const { align, alt = '', border, caption, className, height, lazy, src = '', title = '', width } = attrs;
103626
+ const { align, alt = '', border, caption, className, framed, height, lazy, src = '', title = '', width } = attrs;
103550
103627
  const validAlign = toImageAlign(align);
103551
103628
  const sizing = width !== undefined ? String(width) : undefined;
103552
103629
  const hProperties = {
@@ -103557,6 +103634,7 @@ const transformImage = (jsx) => {
103557
103634
  ...(border !== undefined && { border: toBool(border) }),
103558
103635
  ...(caption && { caption }),
103559
103636
  ...(className && { className }),
103637
+ ...(framed !== undefined && { framed: toBool(framed) }),
103560
103638
  ...(height !== undefined && { height: String(height) }),
103561
103639
  ...(lazy !== undefined && { lazy: toBool(lazy) }),
103562
103640
  ...(sizing && { sizing }),
@@ -103570,6 +103648,7 @@ const transformImage = (jsx) => {
103570
103648
  caption,
103571
103649
  children: caption ? lib_mdast(caption).children : [],
103572
103650
  className,
103651
+ framed: toBool(framed),
103573
103652
  height: height !== undefined ? String(height) : undefined,
103574
103653
  lazy: toBool(lazy),
103575
103654
  sizing,
@@ -103938,6 +104017,14 @@ const mdxishJsxToMdast = () => tree => {
103938
104017
  else if (node.border !== undefined) {
103939
104018
  node.border = toBool(node.border);
103940
104019
  }
104020
+ if (hProps.framed !== undefined) {
104021
+ const val = toBool(hProps.framed);
104022
+ node.framed = val;
104023
+ hProps.framed = val;
104024
+ }
104025
+ else if (node.framed !== undefined) {
104026
+ node.framed = toBool(node.framed);
104027
+ }
103941
104028
  // Validate align
103942
104029
  const validAlign = toImageAlign(hProps.align) || toImageAlign(node.align);
103943
104030
  node.align = validAlign;
@@ -104392,11 +104479,30 @@ function normalizeTableSeparator(content) {
104392
104479
 
104393
104480
  ;// ./processor/transform/mdxish/terminate-html-flow-blocks.ts
104394
104481
 
104482
+
104395
104483
  const STANDALONE_HTML_LINE_REGEX = /^(<[a-z][^<>]*>|<\/[a-z][^<>]*>)+\s*$/;
104396
104484
  const HTML_LINE_WITH_CONTENT_REGEX = /^<[a-z][^<>]*>.*<\/[a-z][^<>]*>(?:[^<]*)$/;
104485
+ const terminate_html_flow_blocks_TABLE_STRUCTURE_TAGS = ['table', 'thead', 'tbody', 'tfoot', 'tr', 'td', 'th', 'caption', 'colgroup'];
104486
+ // Tags whose contents must be preserved as is, inserting a blank line after the
104487
+ // opener corrupts the payload.
104488
+ // htmlRawNames here refer to <pre>, <textarea>, <script>, <style>
104489
+ const RAW_CONTENT_TAGS = [...htmlRawNames, ...terminate_html_flow_blocks_TABLE_STRUCTURE_TAGS];
104490
+ // The `(?=[\s/>])` lookahead avoids false matches on lookalike names like `<script-foo>`.
104491
+ const RAW_CONTENT_TAG_MATCHERS = RAW_CONTENT_TAGS.map(tag => ({
104492
+ open: new RegExp(`<${tag}(?=[\\s/>])[^>]*?(?<!/)>`, 'gi'),
104493
+ close: new RegExp(`</${tag}(?=[\\s>])[^>]*>`, 'gi'),
104494
+ }));
104397
104495
  function isLineHtml(line) {
104398
104496
  return STANDALONE_HTML_LINE_REGEX.test(line) || HTML_LINE_WITH_CONTENT_REGEX.test(line);
104399
104497
  }
104498
+ // True if any RAW_CONTENT_TAGS opener on this line is not closed on the same line.
104499
+ function hasUnclosedRawContentOpener(line) {
104500
+ return RAW_CONTENT_TAG_MATCHERS.some(({ open, close }) => {
104501
+ const opens = (line.match(open) ?? []).length;
104502
+ const closes = (line.match(close) ?? []).length;
104503
+ return opens > closes;
104504
+ });
104505
+ }
104400
104506
  /**
104401
104507
  * Preprocessor to terminate HTML flow blocks.
104402
104508
  *
@@ -104407,15 +104513,16 @@ function isLineHtml(line) {
104407
104513
  *
104408
104514
  * @link https://spec.commonmark.org/0.29/#html-blocks
104409
104515
  *
104410
- * This preprocessor inserts a blank line after standalone HTML lines when the
104411
- * next line is non-blank and not an HTML construct (because they still might be part of the HTML flow),
104412
- * ensuring micromark's HTML flow tokenizer terminates and subsequent content is parsed independently.
104516
+ * This preprocessor inserts a blank line after standalone HTML lines when the next
104517
+ * line is non-blank and not an HTML construct, ensuring micromark's HTML flow
104518
+ * tokenizer terminates and subsequent content is parsed independently.
104413
104519
  *
104414
104520
  * Conditions:
104415
- * 1. Only targets non-indented lines with lowercase tag names. Uppercase tags
104416
- * (e.g., `<Table>`, `<MyComponent>`) are JSX custom components and don't
104417
- * trigger CommonMark HTML blocks, so they are left untouched.
104418
- * 2. Lines inside protected blocks (e.g., code blocks) should be left untouched.
104521
+ * 1. Only non-indented lines with lowercase tag names are considered. Uppercase tags
104522
+ * (e.g. `<Table>`, `<MyComponent>`) are JSX custom components and don't trigger
104523
+ * CommonMark HTML blocks.
104524
+ * 2. Lines inside protected blocks (e.g. fenced code) are left untouched.
104525
+ * 3. Lines with an unclosed RAW_CONTENT_TAGS opener are exempted.
104419
104526
  */
104420
104527
  function terminateHtmlFlowBlocks(content) {
104421
104528
  const { protectedContent, protectedCode } = protectCodeBlocks(content);
@@ -104430,7 +104537,7 @@ function terminateHtmlFlowBlocks(content) {
104430
104537
  }
104431
104538
  const isCurrentLineHtml = isLineHtml(lines[i]);
104432
104539
  const isNextLineHtml = isLineHtml(lines[i + 1]);
104433
- if (isCurrentLineHtml && !isNextLineHtml) {
104540
+ if (isCurrentLineHtml && !isNextLineHtml && !hasUnclosedRawContentOpener(lines[i])) {
104434
104541
  result.push('');
104435
104542
  }
104436
104543
  }
@@ -105248,8 +105355,8 @@ function mdxish(mdContent, opts = {}) {
105248
105355
  const { processor, parserReadyContent } = mdxishAstProcessor(contentWithoutComments, opts);
105249
105356
  processor
105250
105357
  .use(safeMode ? undefined : evaluate_exports) // Evaluate `export const/function` and stash scope on file.data.mdxishScope
105358
+ .use(remarkBreaks) // Must precede evaluateExpressions to avoid splitting the \n in an evaluated template literal into a <br> node
105251
105359
  .use(safeMode ? undefined : evaluate_expressions) // Evaluate self-contained MDX expressions (e.g. `{1+1}`)
105252
- .use(remarkBreaks)
105253
105360
  .use(variables_code, { variables }) // Resolve <<...>> and {user.*} inside code and inline code nodes
105254
105361
  .use(remarkRehype, { allowDangerousHtml: true, handlers: mdxComponentHandlers })
105255
105362
  .use(preserveBooleanProperties) // RehypeRaw converts boolean properties to empty strings
@@ -105501,7 +105608,10 @@ function exportComponentsForRehype(components) {
105501
105608
  function createElementPreservingHastProps(type, props, ...children) {
105502
105609
  if (props?.node?.properties) {
105503
105610
  const { node, ...rest } = props;
105504
- return external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default().createElement(type, { ...rest, ...node.properties }, ...children);
105611
+ const mergedProps = { ...rest, ...node.properties };
105612
+ // Strip undefined so positional args don't shadow node.properties.children
105613
+ const definedChildren = children.filter(c => c !== undefined);
105614
+ return external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default().createElement(type, mergedProps, ...definedChildren);
105505
105615
  }
105506
105616
  return external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default().createElement(type, props, ...children);
105507
105617
  }