@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.node.js CHANGED
@@ -24834,9 +24834,10 @@ const LightboxPortal = ({ children }) => {
24834
24834
  return (0,external_react_dom_namespaceObject.createPortal)(children, document.body);
24835
24835
  };
24836
24836
  const Image = (Props) => {
24837
- const { align = '', alt = '', border: borderProp = false, caption, className = '', height = 'auto', src, title = '', width = 'auto', lazy = true, children, } = Props;
24838
- // Normalize border: MDXish passes {false} as the string "false", not a boolean
24837
+ const { align = '', alt = '', border: borderProp = false, caption, className = '', framed: framedProp = false, height = 'auto', src, title = '', width = 'auto', lazy = true, children, } = Props;
24838
+ // Normalize border/framed: MDXish passes {false} as the string "false", not a boolean
24839
24839
  const border = borderProp === true || borderProp === 'true';
24840
+ const framed = framedProp === true || framedProp === 'true';
24840
24841
  const [lightbox, setLightbox] = external_react_.useState(false);
24841
24842
  if (className === 'emoji') {
24842
24843
  return external_react_.createElement("img", { alt: alt, height: height, loading: lazy ? 'lazy' : 'eager', src: src, title: title, width: width });
@@ -24865,7 +24866,10 @@ const Image = (Props) => {
24865
24866
  return;
24866
24867
  setLightbox(!lightbox);
24867
24868
  };
24868
- const imgElement = (external_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 }));
24869
+ // Framed images center the <img> itself; outer wrapper handles left/right alignment via text-align.
24870
+ const imgElement = (external_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 }));
24871
+ const closedLightbox = (ariaLabel, content) => (external_react_.createElement("span", { "aria-label": ariaLabel, className: "img lightbox closed", onClick: toggle, onKeyDown: handleKeyDown, role: 'button', tabIndex: 0 },
24872
+ external_react_.createElement("span", { className: "lightbox-inner" }, content)));
24869
24873
  const lightboxOverlay = lightbox ? (external_react_.createElement(LightboxPortal, null,
24870
24874
  external_react_.createElement("div", { className: "markdown-body" },
24871
24875
  external_react_.createElement("span", { "aria-label": alt || 'Collapse image', className: "img lightbox open", onClick: toggle, onKeyDown: handleKeyDown, role: 'button', tabIndex: 0 },
@@ -24874,17 +24878,27 @@ const Image = (Props) => {
24874
24878
  (children || caption) && external_react_.createElement("figcaption", null, children || caption))),
24875
24879
  external_react_.createElement("button", { "aria-label": "Minimize image", className: "lightbox-close", onClick: toggle, type: "button" },
24876
24880
  external_react_.createElement("i", { "aria-hidden": "true", className: "fa-solid fa-xmark" }))))) : null;
24881
+ if (framed) {
24882
+ const frameClass = `img-frame img-frame-${align || 'center'}`;
24883
+ if (children || caption) {
24884
+ return (external_react_.createElement("figure", { className: frameClass },
24885
+ closedLightbox(alt || 'Expand image', imgElement),
24886
+ lightboxOverlay,
24887
+ external_react_.createElement("figcaption", null, children || caption)));
24888
+ }
24889
+ return (external_react_.createElement("div", { className: frameClass },
24890
+ closedLightbox(alt || 'Expand image', imgElement),
24891
+ lightboxOverlay));
24892
+ }
24877
24893
  if (children || caption) {
24878
24894
  return (external_react_.createElement("figure", null,
24879
- external_react_.createElement("span", { "aria-label": alt, className: "img lightbox closed", onClick: toggle, onKeyDown: handleKeyDown, role: 'button', tabIndex: 0 },
24880
- external_react_.createElement("span", { className: "lightbox-inner" },
24881
- imgElement,
24882
- external_react_.createElement("figcaption", null, children || caption))),
24895
+ closedLightbox(alt || 'Expand image', external_react_.createElement(external_react_.Fragment, null,
24896
+ imgElement,
24897
+ external_react_.createElement("figcaption", null, children || caption))),
24883
24898
  lightboxOverlay));
24884
24899
  }
24885
24900
  return (external_react_.createElement(external_react_.Fragment, null,
24886
- external_react_.createElement("span", { "aria-label": "Expand image", className: "img lightbox closed", onClick: toggle, onKeyDown: handleKeyDown, role: 'button', tabIndex: 0 },
24887
- external_react_.createElement("span", { className: "lightbox-inner" }, imgElement)),
24901
+ closedLightbox('Expand image', imgElement),
24888
24902
  lightboxOverlay));
24889
24903
  };
24890
24904
  /* harmony default export */ const components_Image = (Image);
@@ -25122,12 +25136,14 @@ const Tab = ({ children }) => {
25122
25136
  };
25123
25137
  const Tabs = ({ children }) => {
25124
25138
  const [activeTab, setActiveTab] = (0,external_react_.useState)(0);
25139
+ // React passes `children` as a single element when there's only one child, so normalize.
25140
+ const tabs = external_react_default().Children.toArray(children);
25125
25141
  return (external_react_default().createElement("div", { className: "TabGroup" },
25126
25142
  external_react_default().createElement("header", null,
25127
- external_react_default().createElement("nav", { className: "TabGroup-nav" }, children?.map((tab, index) => (external_react_default().createElement("button", { key: tab.props.title, className: `TabGroup-tab${activeTab === index ? '_active' : ''}`, onClick: () => setActiveTab(index) },
25143
+ external_react_default().createElement("nav", { className: "TabGroup-nav" }, tabs.map((tab, index) => (external_react_default().createElement("button", { key: tab.props.title, className: `TabGroup-tab${activeTab === index ? '_active' : ''}`, onClick: () => setActiveTab(index) },
25128
25144
  tab.props.icon && (external_react_default().createElement("i", { className: `TabGroup-icon fa-duotone fa-solid ${tab.props.icon}`, style: { color: `${tab.props.iconColor}` } })),
25129
25145
  tab.props.title))))),
25130
- external_react_default().createElement("section", null, children && children[activeTab])));
25146
+ external_react_default().createElement("section", null, tabs[activeTab])));
25131
25147
  };
25132
25148
  /* harmony default export */ const components_Tabs = (Tabs);
25133
25149
 
@@ -95806,13 +95822,14 @@ const applyInserts = (html, inserts) => {
95806
95822
  const sorted = [...inserts].sort((a, b) => a.offset - b.offset);
95807
95823
  let out = '';
95808
95824
  let cursor = 0;
95809
- sorted.forEach(({ offset, text }) => {
95825
+ sorted.forEach(({ offset, text, consumes = 0 }) => {
95810
95826
  const clamped = Math.min(Math.max(offset, cursor), html.length);
95811
95827
  if (clamped > cursor) {
95812
95828
  out += html.slice(cursor, clamped);
95813
95829
  cursor = clamped;
95814
95830
  }
95815
95831
  out += text;
95832
+ cursor = Math.min(cursor + consumes, html.length);
95816
95833
  });
95817
95834
  return { value: out + html.slice(cursor), inserts: sorted };
95818
95835
  };
@@ -95924,9 +95941,10 @@ const buildOffsetMapper = (inserts) => {
95924
95941
  // Pre-compute each insert's start in repaired-space.
95925
95942
  let acc = 0;
95926
95943
  const segments = inserts.map(ins => {
95944
+ const consumes = ins.consumes ?? 0;
95927
95945
  const repairedStart = ins.offset + acc;
95928
- acc += ins.text.length;
95929
- return { origOffset: ins.offset, len: ins.text.length, repairedStart };
95946
+ acc += ins.text.length - consumes;
95947
+ return { origOffset: ins.offset, consumes, len: ins.text.length, repairedStart };
95930
95948
  });
95931
95949
  return (repaired) => {
95932
95950
  // Offsets inside an insert's synthetic span have no original counterpart;
@@ -95934,7 +95952,7 @@ const buildOffsetMapper = (inserts) => {
95934
95952
  const hit = segments.find(seg => seg.repairedStart < repaired && repaired < seg.repairedStart + seg.len);
95935
95953
  if (hit)
95936
95954
  return hit.origOffset;
95937
- const shift = segments.reduce((acc2, seg) => (seg.repairedStart < repaired ? acc2 + seg.len : acc2), 0);
95955
+ const shift = segments.reduce((acc2, seg) => (seg.repairedStart < repaired ? acc2 + seg.len - seg.consumes : acc2), 0);
95938
95956
  return repaired - shift;
95939
95957
  };
95940
95958
  };
@@ -96113,6 +96131,43 @@ const HTML_VOID_ELEMENTS = new Set([
96113
96131
 
96114
96132
 
96115
96133
  const isStandardHtmlTag = (name) => STANDARD_HTML_TAGS.has(name.toLowerCase());
96134
+ // Intentionally simpler than htmlparser2: `[^>]*` does not honor `>` inside
96135
+ // quoted attribute values. That's acceptable here because the main walker
96136
+ // (htmlparser2) handles attribute parsing; this scan only needs to locate
96137
+ // orphan closers, which can't appear inside an attribute value anyway.
96138
+ const HTML_TAG_TOKEN_RE = /<(\/)?([a-zA-Z][a-zA-Z0-9-]*)\b[^>]*>/g;
96139
+ /**
96140
+ * htmlparser2 silently drops closing tags that have no matching opener
96141
+ * (e.g. the trailing `</li>` in `<ul><li>x</ul></li>`), leaving them in the
96142
+ * source makes mdxjs choke on the dangling closer. Scan the masked
96143
+ * source for `</name>` tokens that don't pair with any prior unmatched
96144
+ * `<name>` and return their spans so the caller can drop them.
96145
+ */
96146
+ const findOrphanClosers = (html) => {
96147
+ const masked = maskNonTagRegions(html);
96148
+ const stack = [];
96149
+ const orphans = [];
96150
+ HTML_TAG_TOKEN_RE.lastIndex = 0;
96151
+ let match;
96152
+ while ((match = HTML_TAG_TOKEN_RE.exec(masked)) !== null) {
96153
+ const name = match[2].toLowerCase();
96154
+ // Non-HTML names and void elements are handled by the main walker.
96155
+ // eslint-disable-next-line no-continue
96156
+ if (!isStandardHtmlTag(name) || HTML_VOID_ELEMENTS.has(name))
96157
+ continue;
96158
+ if (match[1] === '/') {
96159
+ const idx = stack.lastIndexOf(name);
96160
+ if (idx === -1)
96161
+ orphans.push({ offset: match.index, length: match[0].length });
96162
+ else
96163
+ stack.length = idx;
96164
+ }
96165
+ else if (!match[0].endsWith('/>')) {
96166
+ stack.push(name);
96167
+ }
96168
+ }
96169
+ return orphans;
96170
+ };
96116
96171
  /**
96117
96172
  * MDX requires a JSX inline tag and its closer to live on the same line — not
96118
96173
  * just the same paragraph. (`<td>\nArray <object>\n</object></td>` still
@@ -96169,6 +96224,7 @@ const repairUnclosedTags = (html) => {
96169
96224
  inserts.push({ offset: findOffsetToPlaceCloser(html, openTag.end, start), text: `</${name}>` });
96170
96225
  },
96171
96226
  });
96227
+ findOrphanClosers(html).forEach(({ offset, length }) => inserts.push({ offset, text: '', consumes: length }));
96172
96228
  return applyInserts(html, inserts);
96173
96229
  };
96174
96230
 
@@ -118598,6 +118654,12 @@ function parseTextChildren(node, processMarkdown, components) {
118598
118654
  node.children = node.children.flatMap(child => {
118599
118655
  if (child.type !== 'text' || !child.value.trim())
118600
118656
  return [child];
118657
+ // Store multiline template-literal children (e.g. {`...\n...`}) as a bare string prop
118658
+ // via node.properties.children so hast-to-hyperscript doesn't wrap them in an array.
118659
+ if (child.value.includes('\n')) {
118660
+ node.properties = { ...node.properties, children: child.value };
118661
+ return [];
118662
+ }
118601
118663
  const hast = processMarkdown(child.value.trim());
118602
118664
  const children = (hast.children ?? []).filter(isElementContentNode);
118603
118665
  // For inline components, preserve plain text instead of wrapping in <p>
@@ -120749,6 +120811,123 @@ function createTokenize(mode) {
120749
120811
  const isSameCaseAsTag = (code) => isLowercaseTag
120750
120812
  ? code >= codes.lowercaseA && code <= codes.lowercaseZ
120751
120813
  : code >= codes.uppercaseA && code <= codes.uppercaseZ;
120814
+ // Shared brace-expression state machine. The two call sites differ only in where
120815
+ // to continue after a line ending and where to return when braceDepth reaches zero.
120816
+ function createBraceExprStates(continuationStart, afterBraceClose) {
120817
+ function braceExpr(code) {
120818
+ if (code === null)
120819
+ return nok(code);
120820
+ if (markdownLineEnding(code)) {
120821
+ if (!isFlow)
120822
+ return nok(code);
120823
+ effects.exit('mdxComponentData');
120824
+ return continuationStart(code);
120825
+ }
120826
+ if (code === codes.quotationMark || code === codes.apostrophe) {
120827
+ quoteChar = code;
120828
+ effects.consume(code);
120829
+ return braceString;
120830
+ }
120831
+ if (code === codes.graveAccent) {
120832
+ inTemplateLit = true;
120833
+ effects.consume(code);
120834
+ return braceTemplateLiteral;
120835
+ }
120836
+ if (code === codes.leftCurlyBrace) {
120837
+ braceDepth += 1;
120838
+ effects.consume(code);
120839
+ return braceExpr;
120840
+ }
120841
+ if (code === codes.rightCurlyBrace) {
120842
+ braceDepth -= 1;
120843
+ effects.consume(code);
120844
+ if (templateStack.length > 0 && braceDepth === templateStack[templateStack.length - 1]) {
120845
+ templateStack.pop();
120846
+ inTemplateLit = true;
120847
+ return braceTemplateLiteral;
120848
+ }
120849
+ if (braceDepth === 0) {
120850
+ return afterBraceClose;
120851
+ }
120852
+ return braceExpr;
120853
+ }
120854
+ effects.consume(code);
120855
+ return braceExpr;
120856
+ }
120857
+ function braceString(code) {
120858
+ if (code === null)
120859
+ return nok(code);
120860
+ if (markdownLineEnding(code)) {
120861
+ if (!isFlow)
120862
+ return nok(code);
120863
+ effects.exit('mdxComponentData');
120864
+ return continuationStart(code);
120865
+ }
120866
+ if (code === codes.backslash) {
120867
+ effects.consume(code);
120868
+ return braceStringEscape;
120869
+ }
120870
+ if (code === quoteChar) {
120871
+ effects.consume(code);
120872
+ quoteChar = null;
120873
+ return braceExpr;
120874
+ }
120875
+ effects.consume(code);
120876
+ return braceString;
120877
+ }
120878
+ function braceStringEscape(code) {
120879
+ if (code === null || markdownLineEnding(code)) {
120880
+ return braceString(code);
120881
+ }
120882
+ effects.consume(code);
120883
+ return braceString;
120884
+ }
120885
+ function braceTemplateLiteral(code) {
120886
+ if (code === null)
120887
+ return nok(code);
120888
+ if (markdownLineEnding(code)) {
120889
+ if (!isFlow)
120890
+ return nok(code);
120891
+ effects.exit('mdxComponentData');
120892
+ return continuationStart(code);
120893
+ }
120894
+ if (code === codes.graveAccent) {
120895
+ inTemplateLit = false;
120896
+ effects.consume(code);
120897
+ return braceExpr;
120898
+ }
120899
+ if (code === codes.backslash) {
120900
+ effects.consume(code);
120901
+ return braceTemplateLiteralEscape;
120902
+ }
120903
+ if (code === codes.dollarSign) {
120904
+ effects.consume(code);
120905
+ return braceTemplateLiteralDollar;
120906
+ }
120907
+ effects.consume(code);
120908
+ return braceTemplateLiteral;
120909
+ }
120910
+ function braceTemplateLiteralEscape(code) {
120911
+ if (code === null || markdownLineEnding(code)) {
120912
+ return braceTemplateLiteral(code);
120913
+ }
120914
+ effects.consume(code);
120915
+ return braceTemplateLiteral;
120916
+ }
120917
+ function braceTemplateLiteralDollar(code) {
120918
+ if (code === codes.leftCurlyBrace) {
120919
+ templateStack.push(braceDepth);
120920
+ braceDepth += 1;
120921
+ inTemplateLit = false;
120922
+ effects.consume(code);
120923
+ return braceExpr;
120924
+ }
120925
+ return braceTemplateLiteral(code);
120926
+ }
120927
+ return { braceExpr, braceString, braceTemplateLiteral };
120928
+ }
120929
+ const { braceExpr: inBraceExpr, braceString: inBraceString, braceTemplateLiteral: inBraceTemplateLiteral, } = createBraceExprStates(openTagContinuationStart, afterOpenTagName);
120930
+ const { braceExpr: inBodyBraceExpr, braceString: inBodyBraceString, braceTemplateLiteral: inBodyBraceTemplateLiteral, } = createBraceExprStates(bodyContinuationStart, body);
120752
120931
  return start;
120753
120932
  // ── Start ──────────────────────────────────────────────────────────────
120754
120933
  function start(code) {
@@ -120871,126 +121050,6 @@ function createTokenize(mode) {
120871
121050
  effects.consume(code);
120872
121051
  return inQuotedAttr;
120873
121052
  }
120874
- function inBraceExpr(code) {
120875
- if (code === null)
120876
- return nok(code);
120877
- if (markdownLineEnding(code)) {
120878
- if (!isFlow)
120879
- return nok(code);
120880
- effects.exit('mdxComponentData');
120881
- return openTagContinuationStart(code);
120882
- }
120883
- // Handle strings inside braces
120884
- if (code === codes.quotationMark || code === codes.apostrophe) {
120885
- quoteChar = code;
120886
- effects.consume(code);
120887
- return inBraceString;
120888
- }
120889
- // Handle template literals inside braces
120890
- if (code === codes.graveAccent) {
120891
- inTemplateLit = true;
120892
- effects.consume(code);
120893
- return inBraceTemplateLiteral;
120894
- }
120895
- if (code === codes.leftCurlyBrace) {
120896
- braceDepth += 1;
120897
- effects.consume(code);
120898
- return inBraceExpr;
120899
- }
120900
- if (code === codes.rightCurlyBrace) {
120901
- braceDepth -= 1;
120902
- effects.consume(code);
120903
- // Check if this } closes a ${...} interpolation
120904
- if (templateStack.length > 0 && braceDepth === templateStack[templateStack.length - 1]) {
120905
- templateStack.pop();
120906
- inTemplateLit = true; // back inside the template literal
120907
- return inBraceTemplateLiteral;
120908
- }
120909
- if (braceDepth === 0) {
120910
- return afterOpenTagName;
120911
- }
120912
- return inBraceExpr;
120913
- }
120914
- effects.consume(code);
120915
- return inBraceExpr;
120916
- }
120917
- function inBraceString(code) {
120918
- if (code === null)
120919
- return nok(code);
120920
- if (markdownLineEnding(code)) {
120921
- if (!isFlow)
120922
- return nok(code);
120923
- effects.exit('mdxComponentData');
120924
- return openTagContinuationStart(code);
120925
- }
120926
- if (code === codes.backslash) {
120927
- effects.consume(code);
120928
- return inBraceStringEscape;
120929
- }
120930
- if (code === quoteChar) {
120931
- effects.consume(code);
120932
- quoteChar = null;
120933
- return inBraceExpr;
120934
- }
120935
- effects.consume(code);
120936
- return inBraceString;
120937
- }
120938
- function inBraceStringEscape(code) {
120939
- if (code === null || markdownLineEnding(code)) {
120940
- return inBraceString(code);
120941
- }
120942
- effects.consume(code);
120943
- return inBraceString;
120944
- }
120945
- // ── Template literal handling inside brace expressions ─────────────────
120946
- function inBraceTemplateLiteral(code) {
120947
- if (code === null)
120948
- return nok(code);
120949
- if (markdownLineEnding(code)) {
120950
- if (!isFlow)
120951
- return nok(code);
120952
- effects.exit('mdxComponentData');
120953
- return openTagContinuationStart(code);
120954
- }
120955
- // Closing backtick ends the template literal
120956
- if (code === codes.graveAccent) {
120957
- inTemplateLit = false;
120958
- effects.consume(code);
120959
- return inBraceExpr;
120960
- }
120961
- // Backslash escape (e.g., \` or \$)
120962
- if (code === codes.backslash) {
120963
- effects.consume(code);
120964
- return inBraceTemplateLiteralEscape;
120965
- }
120966
- // ${ starts an interpolation
120967
- if (code === codes.dollarSign) {
120968
- effects.consume(code);
120969
- return inBraceTemplateLiteralDollar;
120970
- }
120971
- effects.consume(code);
120972
- return inBraceTemplateLiteral;
120973
- }
120974
- function inBraceTemplateLiteralEscape(code) {
120975
- if (code === null || markdownLineEnding(code)) {
120976
- return inBraceTemplateLiteral(code);
120977
- }
120978
- effects.consume(code);
120979
- return inBraceTemplateLiteral;
120980
- }
120981
- function inBraceTemplateLiteralDollar(code) {
120982
- if (code === codes.leftCurlyBrace) {
120983
- // Enter ${...} interpolation. Save current braceDepth so we know
120984
- // when the matching } returns us to this template literal.
120985
- templateStack.push(braceDepth);
120986
- braceDepth += 1;
120987
- inTemplateLit = false; // now inside interpolation expression
120988
- effects.consume(code);
120989
- return inBraceExpr;
120990
- }
120991
- // Just a $ not followed by { — back to template literal
120992
- return inBraceTemplateLiteral(code);
120993
- }
120994
121053
  function selfCloseGt(code) {
120995
121054
  if (code === codes.greaterThan) {
120996
121055
  effects.consume(code);
@@ -121060,6 +121119,15 @@ function createTokenize(mode) {
121060
121119
  codeSpanOpenSize = 0;
121061
121120
  return countOpenTicks(code);
121062
121121
  }
121122
+ // JSX expression child — track braces/template literals so the closing
121123
+ // backtick of `{`...`}` is not misread as a code span opener
121124
+ if (code === codes.leftCurlyBrace) {
121125
+ braceDepth = 1;
121126
+ inTemplateLit = false;
121127
+ effects.consume(code);
121128
+ atLineStart = false;
121129
+ return inBodyBraceExpr;
121130
+ }
121063
121131
  effects.consume(code);
121064
121132
  atLineStart = false;
121065
121133
  return body;
@@ -121300,6 +121368,14 @@ function createTokenize(mode) {
121300
121368
  return bodyContinuationStart(code);
121301
121369
  }
121302
121370
  effects.enter('mdxComponentData');
121371
+ // Resume inside a body brace expression if a line ending interrupted one
121372
+ if (braceDepth > 0) {
121373
+ if (inTemplateLit)
121374
+ return inBodyBraceTemplateLiteral(code);
121375
+ if (quoteChar !== null)
121376
+ return inBodyBraceString(code);
121377
+ return inBodyBraceExpr(code);
121378
+ }
121303
121379
  // Detect tilde fences at line start
121304
121380
  if (atLineStart && code === codes.tilde) {
121305
121381
  return bodyAfterLineStart(code);
@@ -121402,7 +121478,8 @@ const buildInlineMdProcessor = (safeMode) => {
121402
121478
  // Since evaluating expressions can be dangerous, do so only when safeMode is off
121403
121479
  if (!safeMode) {
121404
121480
  const mdxExprExt = mdxExpression({ allowEmpty: true });
121405
- micromarkExts.push({ text: mdxExprExt.text });
121481
+ // We include both flow and text extensions to support both single-line and multi-line expressions
121482
+ micromarkExts.push({ flow: mdxExprExt.flow, text: mdxExprExt.text });
121406
121483
  fromMarkdownExts.push(mdxExpressionFromMarkdown());
121407
121484
  }
121408
121485
  return unified()
@@ -122060,7 +122137,7 @@ const createEvaluatedNode = (result, position) => {
122060
122137
  else if (typeof result === 'object') {
122061
122138
  return { type: 'text', value: JSON.stringify(result), position };
122062
122139
  }
122063
- return { type: 'text', value: String(result).replace(/\s+/g, ' ').trim(), position };
122140
+ return { type: 'text', value: String(result), position };
122064
122141
  };
122065
122142
  /**
122066
122143
  * AST transformer to evaluate MDX expressions.
@@ -123770,7 +123847,7 @@ const transformAnchor = (jsx) => {
123770
123847
  */
123771
123848
  const transformImage = (jsx) => {
123772
123849
  const attrs = getAttrs(jsx);
123773
- const { align, alt = '', border, caption, className, height, lazy, src = '', title = '', width } = attrs;
123850
+ const { align, alt = '', border, caption, className, framed, height, lazy, src = '', title = '', width } = attrs;
123774
123851
  const validAlign = toImageAlign(align);
123775
123852
  const sizing = width !== undefined ? String(width) : undefined;
123776
123853
  const hProperties = {
@@ -123781,6 +123858,7 @@ const transformImage = (jsx) => {
123781
123858
  ...(border !== undefined && { border: toBool(border) }),
123782
123859
  ...(caption && { caption }),
123783
123860
  ...(className && { className }),
123861
+ ...(framed !== undefined && { framed: toBool(framed) }),
123784
123862
  ...(height !== undefined && { height: String(height) }),
123785
123863
  ...(lazy !== undefined && { lazy: toBool(lazy) }),
123786
123864
  ...(sizing && { sizing }),
@@ -123794,6 +123872,7 @@ const transformImage = (jsx) => {
123794
123872
  caption,
123795
123873
  children: caption ? lib_mdast(caption).children : [],
123796
123874
  className,
123875
+ framed: toBool(framed),
123797
123876
  height: height !== undefined ? String(height) : undefined,
123798
123877
  lazy: toBool(lazy),
123799
123878
  sizing,
@@ -124162,6 +124241,14 @@ const mdxishJsxToMdast = () => tree => {
124162
124241
  else if (node.border !== undefined) {
124163
124242
  node.border = toBool(node.border);
124164
124243
  }
124244
+ if (hProps.framed !== undefined) {
124245
+ const val = toBool(hProps.framed);
124246
+ node.framed = val;
124247
+ hProps.framed = val;
124248
+ }
124249
+ else if (node.framed !== undefined) {
124250
+ node.framed = toBool(node.framed);
124251
+ }
124165
124252
  // Validate align
124166
124253
  const validAlign = toImageAlign(hProps.align) || toImageAlign(node.align);
124167
124254
  node.align = validAlign;
@@ -124616,11 +124703,30 @@ function normalizeTableSeparator(content) {
124616
124703
 
124617
124704
  ;// ./processor/transform/mdxish/terminate-html-flow-blocks.ts
124618
124705
 
124706
+
124619
124707
  const STANDALONE_HTML_LINE_REGEX = /^(<[a-z][^<>]*>|<\/[a-z][^<>]*>)+\s*$/;
124620
124708
  const HTML_LINE_WITH_CONTENT_REGEX = /^<[a-z][^<>]*>.*<\/[a-z][^<>]*>(?:[^<]*)$/;
124709
+ const terminate_html_flow_blocks_TABLE_STRUCTURE_TAGS = ['table', 'thead', 'tbody', 'tfoot', 'tr', 'td', 'th', 'caption', 'colgroup'];
124710
+ // Tags whose contents must be preserved as is, inserting a blank line after the
124711
+ // opener corrupts the payload.
124712
+ // htmlRawNames here refer to <pre>, <textarea>, <script>, <style>
124713
+ const RAW_CONTENT_TAGS = [...htmlRawNames, ...terminate_html_flow_blocks_TABLE_STRUCTURE_TAGS];
124714
+ // The `(?=[\s/>])` lookahead avoids false matches on lookalike names like `<script-foo>`.
124715
+ const RAW_CONTENT_TAG_MATCHERS = RAW_CONTENT_TAGS.map(tag => ({
124716
+ open: new RegExp(`<${tag}(?=[\\s/>])[^>]*?(?<!/)>`, 'gi'),
124717
+ close: new RegExp(`</${tag}(?=[\\s>])[^>]*>`, 'gi'),
124718
+ }));
124621
124719
  function isLineHtml(line) {
124622
124720
  return STANDALONE_HTML_LINE_REGEX.test(line) || HTML_LINE_WITH_CONTENT_REGEX.test(line);
124623
124721
  }
124722
+ // True if any RAW_CONTENT_TAGS opener on this line is not closed on the same line.
124723
+ function hasUnclosedRawContentOpener(line) {
124724
+ return RAW_CONTENT_TAG_MATCHERS.some(({ open, close }) => {
124725
+ const opens = (line.match(open) ?? []).length;
124726
+ const closes = (line.match(close) ?? []).length;
124727
+ return opens > closes;
124728
+ });
124729
+ }
124624
124730
  /**
124625
124731
  * Preprocessor to terminate HTML flow blocks.
124626
124732
  *
@@ -124631,15 +124737,16 @@ function isLineHtml(line) {
124631
124737
  *
124632
124738
  * @link https://spec.commonmark.org/0.29/#html-blocks
124633
124739
  *
124634
- * This preprocessor inserts a blank line after standalone HTML lines when the
124635
- * next line is non-blank and not an HTML construct (because they still might be part of the HTML flow),
124636
- * ensuring micromark's HTML flow tokenizer terminates and subsequent content is parsed independently.
124740
+ * This preprocessor inserts a blank line after standalone HTML lines when the next
124741
+ * line is non-blank and not an HTML construct, ensuring micromark's HTML flow
124742
+ * tokenizer terminates and subsequent content is parsed independently.
124637
124743
  *
124638
124744
  * Conditions:
124639
- * 1. Only targets non-indented lines with lowercase tag names. Uppercase tags
124640
- * (e.g., `<Table>`, `<MyComponent>`) are JSX custom components and don't
124641
- * trigger CommonMark HTML blocks, so they are left untouched.
124642
- * 2. Lines inside protected blocks (e.g., code blocks) should be left untouched.
124745
+ * 1. Only non-indented lines with lowercase tag names are considered. Uppercase tags
124746
+ * (e.g. `<Table>`, `<MyComponent>`) are JSX custom components and don't trigger
124747
+ * CommonMark HTML blocks.
124748
+ * 2. Lines inside protected blocks (e.g. fenced code) are left untouched.
124749
+ * 3. Lines with an unclosed RAW_CONTENT_TAGS opener are exempted.
124643
124750
  */
124644
124751
  function terminateHtmlFlowBlocks(content) {
124645
124752
  const { protectedContent, protectedCode } = protectCodeBlocks(content);
@@ -124654,7 +124761,7 @@ function terminateHtmlFlowBlocks(content) {
124654
124761
  }
124655
124762
  const isCurrentLineHtml = isLineHtml(lines[i]);
124656
124763
  const isNextLineHtml = isLineHtml(lines[i + 1]);
124657
- if (isCurrentLineHtml && !isNextLineHtml) {
124764
+ if (isCurrentLineHtml && !isNextLineHtml && !hasUnclosedRawContentOpener(lines[i])) {
124658
124765
  result.push('');
124659
124766
  }
124660
124767
  }
@@ -125472,8 +125579,8 @@ function mdxish(mdContent, opts = {}) {
125472
125579
  const { processor, parserReadyContent } = mdxishAstProcessor(contentWithoutComments, opts);
125473
125580
  processor
125474
125581
  .use(safeMode ? undefined : evaluate_exports) // Evaluate `export const/function` and stash scope on file.data.mdxishScope
125582
+ .use(remarkBreaks) // Must precede evaluateExpressions to avoid splitting the \n in an evaluated template literal into a <br> node
125475
125583
  .use(safeMode ? undefined : evaluate_expressions) // Evaluate self-contained MDX expressions (e.g. `{1+1}`)
125476
- .use(remarkBreaks)
125477
125584
  .use(variables_code, { variables }) // Resolve <<...>> and {user.*} inside code and inline code nodes
125478
125585
  .use(remarkRehype, { allowDangerousHtml: true, handlers: mdxComponentHandlers })
125479
125586
  .use(preserveBooleanProperties) // RehypeRaw converts boolean properties to empty strings
@@ -125725,7 +125832,10 @@ function exportComponentsForRehype(components) {
125725
125832
  function createElementPreservingHastProps(type, props, ...children) {
125726
125833
  if (props?.node?.properties) {
125727
125834
  const { node, ...rest } = props;
125728
- return external_react_default().createElement(type, { ...rest, ...node.properties }, ...children);
125835
+ const mergedProps = { ...rest, ...node.properties };
125836
+ // Strip undefined so positional args don't shadow node.properties.children
125837
+ const definedChildren = children.filter(c => c !== undefined);
125838
+ return external_react_default().createElement(type, mergedProps, ...definedChildren);
125729
125839
  }
125730
125840
  return external_react_default().createElement(type, props, ...children);
125731
125841
  }