@readme/markdown 14.11.0 → 14.11.1

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
@@ -95943,6 +95943,18 @@ const tableTags = new Set([
95943
95943
  'th',
95944
95944
  'td',
95945
95945
  ]);
95946
+ /**
95947
+ * Replaces every paragraph node with its inline children. Used where paragraphs
95948
+ * are parser artifacts (remarkMdx wrapping inline JSX), not real content.
95949
+ */
95950
+ const unwrapParagraphNodes = (children) => {
95951
+ return children.flatMap(child => {
95952
+ if (child.type === 'paragraph' && 'children' in child && Array.isArray(child.children)) {
95953
+ return child.children;
95954
+ }
95955
+ return [child];
95956
+ });
95957
+ };
95946
95958
  /**
95947
95959
  * If the cell has exactly one paragraph child, unwrap it so its inline children sit
95948
95960
  * directly under the cell (matches GFM table cell shape and avoids stray `<p>` wrappers).
@@ -95954,12 +95966,7 @@ const unwrapSoleParagraph = (children) => {
95954
95966
  const paragraphCount = children.filter(c => c.type === 'paragraph').length;
95955
95967
  if (paragraphCount !== 1)
95956
95968
  return children;
95957
- return children.flatMap(child => {
95958
- if (child.type === 'paragraph' && 'children' in child && Array.isArray(child.children)) {
95959
- return child.children;
95960
- }
95961
- return [child];
95962
- });
95969
+ return unwrapParagraphNodes(children);
95963
95970
  };
95964
95971
  /**
95965
95972
  * Splice each text into `html` at its offset. Inserts at the same offset
@@ -96309,6 +96316,23 @@ const RUNTIME_COMPONENT_TAGS = new Set(['Variable', 'variable', 'html-block', 'r
96309
96316
  * Uses the html-tags package, converted to a Set<string> for efficient lookups.
96310
96317
  */
96311
96318
  const STANDARD_HTML_TAGS = new Set(html_tags_namespaceObject);
96319
+ /**
96320
+ * Table structural tags. Blank lines inside these carry deliberate meaning for
96321
+ * `mdxishTables` (e.g. splitting cell content into paragraphs, or deciding
96322
+ * whether a table stays plain HTML vs a JSX `<Table>`), so transforms that
96323
+ * neutralize or claim across blank lines must leave them alone.
96324
+ */
96325
+ const HTML_TABLE_STRUCTURE_TAGS = new Set([
96326
+ 'table',
96327
+ 'thead',
96328
+ 'tbody',
96329
+ 'tfoot',
96330
+ 'tr',
96331
+ 'td',
96332
+ 'th',
96333
+ 'caption',
96334
+ 'colgroup',
96335
+ ]);
96312
96336
  /**
96313
96337
  * HTML void elements — elements that have no closing tag and no children.
96314
96338
  *
@@ -96620,18 +96644,17 @@ const processTableNode = (node, index, parent, documentPosition) => {
96620
96644
  // same line as content becomes mdxJsxTextElement inside a paragraph).
96621
96645
  // Unwrap these so <td>/<th> sit directly under <tr>, and strip
96622
96646
  // whitespace-only text nodes to avoid rendering empty <p>/<br>.
96623
- const cleanChildren = (children) => children
96624
- .flatMap(child => {
96625
- if (child.type === 'paragraph' && 'children' in child && Array.isArray(child.children)) {
96626
- return child.children;
96627
- }
96628
- return [child];
96629
- })
96630
- .filter(child => !(child.type === 'text' && 'value' in child && typeof child.value === 'string' && !child.value.trim()));
96647
+ const removeWhitespaceOnlyTextNodes = (children) => children.filter(child => !(child.type === 'text' && 'value' in child && typeof child.value === 'string' && !child.value.trim()));
96631
96648
  visit(node, isMDXElement, (el) => {
96632
- if ('children' in el && Array.isArray(el.children)) {
96633
- el.children = cleanChildren(el.children);
96634
- }
96649
+ if (!('children' in el) || !Array.isArray(el.children))
96650
+ return;
96651
+ // Filtering transformers
96652
+ // A cell only unwraps a sole paragraph: multiple paragraphs are real
96653
+ // blank-line-separated content that must stay separated
96654
+ const unwrapped = isTableCell(el)
96655
+ ? unwrapSoleParagraph(el.children)
96656
+ : unwrapParagraphNodes(el.children);
96657
+ el.children = removeWhitespaceOnlyTextNodes(unwrapped);
96635
96658
  });
96636
96659
  parent.children[index] = {
96637
96660
  ...node,
@@ -121021,15 +121044,26 @@ const types_types = /** @type {const} */ ({
121021
121044
 
121022
121045
 
121023
121046
 
121047
+
121024
121048
  // Raw tags (type-1: pre/script/style/textarea) and block tags (type-6: div,
121025
121049
  // section, …) always start a block, so they stay flow even with trailing
121026
121050
  // content. Other lowercase tags (i, span, …) follow the type-7 rule and only
121027
121051
  // stay flow when nothing trails the close tag.
121028
121052
  const htmlFlowTagNames = new Set([...htmlRawNames, ...htmlBlockNames]);
121053
+ // Lowercase type-6 block tags claimable in flow even without a `{…}` attribute, so
121054
+ // blank lines between nested JSX siblings don't fragment the block. Excludes table
121055
+ // tags (mdxishTables owns their blank lines) and voids (never close).
121056
+ const plainBlockClaimTagNames = new Set([...htmlBlockNames].filter(tag => !HTML_TABLE_STRUCTURE_TAGS.has(tag) && !HTML_VOID_ELEMENTS.has(tag)));
121029
121057
  const syntax_nonLazyContinuationStart = {
121030
121058
  tokenize: syntax_tokenizeNonLazyContinuationStart,
121031
121059
  partial: true,
121032
121060
  };
121061
+ // Lookahead for `plainClaimLineStart`: is this line markup-only, or a paragraph
121062
+ // that merely starts with a tag? Run via `effects.check` so it never consumes.
121063
+ const markupOnlyContinuation = {
121064
+ tokenize: tokenizeMarkupOnlyContinuation,
121065
+ partial: true,
121066
+ };
121033
121067
  function resolveToMdxComponent(events) {
121034
121068
  let index = events.length;
121035
121069
  while (index > 0) {
@@ -121084,6 +121118,10 @@ function createTokenize(mode) {
121084
121118
  // (INLINE_COMPONENT_TAGS — Anchor, Glossary), also brace-gated.
121085
121119
  let isLowercaseTag = false;
121086
121120
  let sawBraceAttr = false;
121121
+ // A plain lowercase block tag claimed without a `{…}` attribute, gated by
121122
+ // `plainClaimLineStart`: after a blank line it may only continue on a tag line.
121123
+ let isPlainBlockClaim = false;
121124
+ let pendingBlankLine = false;
121087
121125
  // Code span tracking
121088
121126
  let codeSpanOpenSize = 0;
121089
121127
  let codeSpanCloseSize = 0;
@@ -121317,8 +121355,13 @@ function createTokenize(mode) {
121317
121355
  }
121318
121356
  // End of opening tag
121319
121357
  if (code === codes.greaterThan) {
121320
- if (requiresBraceAttr && !sawBraceAttr)
121321
- return nok(code);
121358
+ if (requiresBraceAttr && !sawBraceAttr) {
121359
+ // Plain lowercase block tags stay claimable in flow, gated per line by
121360
+ // `plainClaimLineStart`; everything else falls through to CommonMark.
121361
+ if (!isFlow || !plainBlockClaimTagNames.has(tagName))
121362
+ return nok(code);
121363
+ isPlainBlockClaim = true;
121364
+ }
121322
121365
  effects.consume(code);
121323
121366
  onOpenerLine = isFlow;
121324
121367
  return body;
@@ -121468,6 +121511,7 @@ function createTokenize(mode) {
121468
121511
  if (atLineStart && codeSpanOpenSize >= 3) {
121469
121512
  fenceChar = codes.graveAccent;
121470
121513
  fenceLength = codeSpanOpenSize;
121514
+ atLineStart = false;
121471
121515
  return inFencedCode(code);
121472
121516
  }
121473
121517
  return inCodeSpan(code);
@@ -121615,8 +121659,14 @@ function createTokenize(mode) {
121615
121659
  effects.consume(code);
121616
121660
  return nestedOpenTagName;
121617
121661
  }
121618
- // Only increment depth for same-name tags that are followed by valid tag-end chars
121619
- if (closingTagName === tagName && (code === codes.greaterThan || code === codes.slash || code === codes.space || code === codes.horizontalTab)) {
121662
+ // Same-name opener followed by a tag-end char bumps depth. A line ending
121663
+ // counts too: Prettier puts a newline right after the name (`<div\n …\n>`).
121664
+ if (closingTagName === tagName &&
121665
+ (code === codes.greaterThan ||
121666
+ code === codes.slash ||
121667
+ code === codes.space ||
121668
+ code === codes.horizontalTab ||
121669
+ markdownLineEnding(code))) {
121620
121670
  depth += 1;
121621
121671
  }
121622
121672
  atLineStart = false;
@@ -121705,6 +121755,10 @@ function createTokenize(mode) {
121705
121755
  }
121706
121756
  function bodyContinuationBefore(code) {
121707
121757
  if (code === null || markdownLineEnding(code)) {
121758
+ // Empty line: outside any `{…}` expression this is CommonMark's html-block
121759
+ // terminator, so a plain block claim must pass the guard below to continue.
121760
+ if (isPlainBlockClaim && braceDepth === 0)
121761
+ pendingBlankLine = true;
121708
121762
  return bodyContinuationStart(code);
121709
121763
  }
121710
121764
  effects.enter('mdxComponentData');
@@ -121716,19 +121770,52 @@ function createTokenize(mode) {
121716
121770
  return inBodyBraceString(code);
121717
121771
  return inBodyBraceExpr(code);
121718
121772
  }
121719
- // Detect tilde fences at line start
121720
- if (atLineStart && code === codes.tilde) {
121773
+ if (isPlainBlockClaim)
121774
+ return plainClaimLineStart(code);
121775
+ return bodyLineStart(code);
121776
+ }
121777
+ // Dispatch a non-blank continuation line: fenced code at line start, else body.
121778
+ function bodyLineStart(code) {
121779
+ if (atLineStart && code === codes.tilde)
121721
121780
  return bodyAfterLineStart(code);
121722
- }
121723
- // Detect backtick fences at line start
121724
121781
  if (atLineStart && code === codes.graveAccent) {
121725
121782
  codeSpanOpenSize = 0;
121726
- atLineStart = false;
121783
+ // Leave `atLineStart` set — `countOpenTicks` needs it to tell a fence from an
121784
+ // inline code span once the run of backticks is fully counted; it's cleared once
121785
+ // that fence-vs-span decision has actually been made.
121727
121786
  return countOpenTicks(code);
121728
121787
  }
121729
121788
  atLineStart = false;
121730
121789
  return body(code);
121731
121790
  }
121791
+ // Line-start gate for plain block claims. After a blank line the block may only
121792
+ // continue on a tag line (`<…`); any markdown island (`**bold**`, `[block:…]`, a
121793
+ // fence) refuses so CommonMark html-flow reparses it exactly as it does today.
121794
+ function plainClaimLineStart(code) {
121795
+ // Leading whitespace only → treat as a blank line, matching CommonMark.
121796
+ if (code === codes.space || code === codes.horizontalTab) {
121797
+ effects.consume(code);
121798
+ return plainClaimLineStart;
121799
+ }
121800
+ if (code === null || markdownLineEnding(code)) {
121801
+ pendingBlankLine = true;
121802
+ effects.exit('mdxComponentData');
121803
+ return bodyContinuationStart(code);
121804
+ }
121805
+ // Across a blank line the block only continues onto a markup-only line; a
121806
+ // paragraph that merely starts with a tag must fall back so its markdown
121807
+ // parses and rehype-raw re-nests it into the wrapper.
121808
+ if (pendingBlankLine) {
121809
+ if (code !== codes.lessThan)
121810
+ return nok(code);
121811
+ return effects.check(markupOnlyContinuation, plainClaimContinue, nok)(code);
121812
+ }
121813
+ return bodyLineStart(code);
121814
+ }
121815
+ function plainClaimContinue(code) {
121816
+ pendingBlankLine = false;
121817
+ return bodyLineStart(code);
121818
+ }
121732
121819
  // ── Shared lazy continuation failure ───────────────────────────────────
121733
121820
  function continuationAfter(code) {
121734
121821
  if (code === null) {
@@ -121759,6 +121846,46 @@ function syntax_tokenizeNonLazyContinuationStart(effects, ok, nok) {
121759
121846
  return ok(code);
121760
121847
  }
121761
121848
  }
121849
+ // A markup-only line opens with a tag (`<x`/`</x`) and ends (ignoring trailing
121850
+ // spaces) at a `>`. That distinguishes a structural continuation like
121851
+ // `<span>b</span></div>` from a paragraph like `<b>Note:</b> read *this*`.
121852
+ function tokenizeMarkupOnlyContinuation(effects, ok, nok) {
121853
+ let lastNonSpace = null;
121854
+ return start;
121855
+ function start(code) {
121856
+ // Caller guarantees we are at `<` at the (already de-indented) line start.
121857
+ effects.enter(types_types.data);
121858
+ effects.consume(code);
121859
+ return afterLessThan;
121860
+ }
121861
+ function afterLessThan(code) {
121862
+ if (code === codes.slash) {
121863
+ effects.consume(code);
121864
+ return afterSlash;
121865
+ }
121866
+ return afterSlash(code);
121867
+ }
121868
+ // The `<` (or `</`) must introduce a real tag, not a stray `<` in prose.
121869
+ function afterSlash(code) {
121870
+ if (asciiAlpha(code)) {
121871
+ lastNonSpace = code;
121872
+ effects.consume(code);
121873
+ return scanToLineEnd;
121874
+ }
121875
+ effects.exit(types_types.data);
121876
+ return nok(code);
121877
+ }
121878
+ function scanToLineEnd(code) {
121879
+ if (code === null || markdownLineEnding(code)) {
121880
+ effects.exit(types_types.data);
121881
+ return lastNonSpace === codes.greaterThan ? ok(code) : nok(code);
121882
+ }
121883
+ if (!markdownSpace(code))
121884
+ lastNonSpace = code;
121885
+ effects.consume(code);
121886
+ return scanToLineEnd;
121887
+ }
121888
+ }
121762
121889
  /**
121763
121890
  * Micromark extension that tokenizes MDX-like components.
121764
121891
  *
@@ -122005,6 +122132,8 @@ const mdxishInlineMdxComponents = () => tree => {
122005
122132
 
122006
122133
 
122007
122134
 
122135
+ /** Matches a JSX attribute expression (e.g. `key={i}`) anywhere in a string. */
122136
+ const NESTED_ATTR_EXPRESSION_RE = /[\w-]+\s*=\s*\{/;
122008
122137
  /**
122009
122138
  * Reduce leading whitespace on all lines just enough to prevent
122010
122139
  * remark from treating indented content as code blocks (4+ spaces).
@@ -122164,10 +122293,16 @@ const mdxishMdxComponentBlocks = (opts = {}) => (tree, file) => {
122164
122293
  // inline, which is how ReadMe's custom components are modeled).
122165
122294
  if (!isPascal && parent.type === 'paragraph')
122166
122295
  return;
122167
- // Lowercase HTML tags are only eligible when the tokenizer claimed them
122168
- // for JSX-expression attributes. Plain HTML should stay as html nodes so
122296
+ // Lowercase HTML tags are eligible when they (or a descendant tag in their
122297
+ // content, e.g. a `.map()` body returning JSX with `key={i}`) carry a
122298
+ // JSX-expression attribute. Without this, a wrapper `<div>` with only plain
122299
+ // attributes (or none) swallows its whole nested block — including any
122300
+ // `style={{...}}`/`.map()` JSX inside it — as literal HTML text, which
122301
+ // rehype-raw's parse5 pass then garbles (it has no notion of JS expressions).
122302
+ // Plain HTML with no expressions anywhere stays as an html node so
122169
122303
  // rehype-raw handles it as normal.
122170
- if (!isPascal && !hasExpressionAttr(attributes))
122304
+ const hasNestedExpressionAttr = !selfClosing && NESTED_ATTR_EXPRESSION_RE.test(contentAfterTag);
122305
+ if (!isPascal && !hasExpressionAttr(attributes) && !hasNestedExpressionAttr)
122171
122306
  return;
122172
122307
  const closingTagStr = `</${tag}>`;
122173
122308
  // Case 1: Self-closing tag
@@ -122606,15 +122741,17 @@ const evalExpression = (expression, scope) => {
122606
122741
 
122607
122742
 
122608
122743
 
122744
+ /** True for an array containing at least one React element, e.g. the result of `.map()` returning JSX. */
122745
+ const isRenderableElementArray = (value) => Array.isArray(value) && value.some((external_react_default()).isValidElement);
122609
122746
  /** Given the type of the expression result, create the corresponding mdast node. */
122610
122747
  const createEvaluatedNode = (result, position) => {
122611
122748
  if (result === null || result === undefined) {
122612
122749
  return { type: 'text', value: '', position };
122613
122750
  }
122614
- else if (external_react_default().isValidElement(result)) {
122615
- // Convert react elements to its HTML representation
122616
- // This must come before the object check as this is a subset of it
122617
- return { type: 'html', value: (0,server_node/* renderToStaticMarkup */.qV)(result), position };
122751
+ else if (external_react_default().isValidElement(result) || isRenderableElementArray(result)) {
122752
+ // Convert react elements (or arrays of them, e.g. `.map()` returning JSX) to their HTML
122753
+ // representation. This must come before the object check as both are a subset of it.
122754
+ return { type: 'html', value: (0,server_node/* renderToStaticMarkup */.qV)(external_react_default().createElement((external_react_default()).Fragment, null, result)), position };
122618
122755
  }
122619
122756
  else if (typeof result === 'object') {
122620
122757
  return { type: 'text', value: JSON.stringify(result), position };
@@ -122654,6 +122791,47 @@ const evaluateExpressions = () => (tree, file) => {
122654
122791
  };
122655
122792
  /* harmony default export */ const evaluate_expressions = (evaluateExpressions);
122656
122793
 
122794
+ ;// ./processor/transform/mdxish/evaluate-style-block-expressions.ts
122795
+
122796
+
122797
+
122798
+ // Matches a standalone `<style ...>{ <expr> }</style>` block — the JSX shape MDX evaluates
122799
+ // (typically a template-literal-wrapped CSS string) but which mdxish otherwise leaves as
122800
+ // literal, invalid-CSS text (see CX-3646).
122801
+ const STYLE_EXPRESSION_RE = /^(<style\b[^>]*>)\s*\{([\s\S]*)\}\s*(<\/style>)$/i;
122802
+ /**
122803
+ * Evaluate the JSX expression wrapping a `<style>` tag's contents (typically a template
122804
+ * literal, e.g. `<style>{\`.foo { color: red; }\`}</style>`) so the tag ends up holding plain
122805
+ * CSS text instead of the literal `{`...`}` wrapper — which the browser treats as invalid CSS
122806
+ * and drops the entire stylesheet for.
122807
+ *
122808
+ * `<style>` is one of CommonMark's "raw text" HTML elements (along with script/pre/textarea):
122809
+ * its contents are captured verbatim as a single `html` mdast node with no inner tokenization,
122810
+ * so this expression never reaches the mdxFlowExpression tokenizer or `evaluateExpressions` —
122811
+ * it has to be matched and evaluated directly against the raw node's string value.
122812
+ *
122813
+ * Must run after `evaluateExports` (needs `file.data.mdxishScope`) and before `remarkRehype`
122814
+ * turns `html` mdast nodes into raw hast strings. Skipped in safeMode.
122815
+ */
122816
+ const evaluateStyleBlockExpressions = () => (tree, file) => {
122817
+ const scope = { ...file.data.mdxishScope, React: (external_react_default()) };
122818
+ visit(tree, 'html', (node) => {
122819
+ const match = node.value.trim().match(STYLE_EXPRESSION_RE);
122820
+ if (!match)
122821
+ return;
122822
+ const [, openTag, expression, closeTag] = match;
122823
+ try {
122824
+ const css = evalExpression(expression, scope);
122825
+ node.value = `${openTag}${String(css)}${closeTag}`;
122826
+ }
122827
+ catch {
122828
+ // Evaluation failed — leave the node untouched so it round-trips as literal text.
122829
+ }
122830
+ });
122831
+ return tree;
122832
+ };
122833
+ /* harmony default export */ const evaluate_style_block_expressions = (evaluateStyleBlockExpressions);
122834
+
122657
122835
  ;// ./processor/transform/mdxish/heading-slugs.ts
122658
122836
 
122659
122837
 
@@ -124510,10 +124688,84 @@ function removeJSXComments(content) {
124510
124688
  return content.replace(JSX_COMMENT_REGEX, '');
124511
124689
  }
124512
124690
 
124691
+ ;// ./processor/transform/mdxish/style-object-to-css.ts
124692
+
124693
+ /**
124694
+ * CSS properties React treats as unitless — a bare number stays as-is instead of
124695
+ * getting `px` appended. Mirrors React DOM's `isUnitlessNumber` whitelist.
124696
+ * @see https://github.com/facebook/react/blob/main/packages/react-dom-bindings/src/shared/CSSProperty.js
124697
+ */
124698
+ const UNITLESS_CSS_PROPERTIES = new Set([
124699
+ 'animationIterationCount',
124700
+ 'aspectRatio',
124701
+ 'borderImageOutset',
124702
+ 'borderImageSlice',
124703
+ 'borderImageWidth',
124704
+ 'boxFlex',
124705
+ 'boxFlexGroup',
124706
+ 'boxOrdinalGroup',
124707
+ 'columnCount',
124708
+ 'columns',
124709
+ 'flex',
124710
+ 'flexGrow',
124711
+ 'flexPositive',
124712
+ 'flexShrink',
124713
+ 'flexNegative',
124714
+ 'flexOrder',
124715
+ 'gridArea',
124716
+ 'gridRow',
124717
+ 'gridRowEnd',
124718
+ 'gridRowSpan',
124719
+ 'gridRowStart',
124720
+ 'gridColumn',
124721
+ 'gridColumnEnd',
124722
+ 'gridColumnSpan',
124723
+ 'gridColumnStart',
124724
+ 'fontWeight',
124725
+ 'lineClamp',
124726
+ 'lineHeight',
124727
+ 'opacity',
124728
+ 'order',
124729
+ 'orphans',
124730
+ 'tabSize',
124731
+ 'widows',
124732
+ 'zIndex',
124733
+ 'zoom',
124734
+ 'fillOpacity',
124735
+ 'floodOpacity',
124736
+ 'stopOpacity',
124737
+ 'strokeDasharray',
124738
+ 'strokeDashoffset',
124739
+ 'strokeMiterlimit',
124740
+ 'strokeOpacity',
124741
+ 'strokeWidth',
124742
+ ]);
124743
+ /** Convert a camelCase (or CSS custom property) key into its kebab-case CSS name. */
124744
+ const cssPropertyName = (key) => (key.startsWith('--') ? key : key.replace(/[A-Z]/g, m => `-${m.toLowerCase()}`));
124745
+ /** React appends `px` to non-zero numeric values, except unitless and custom properties. */
124746
+ const cssPropertyValue = (key, value) => typeof value === 'number' && value !== 0 && !key.startsWith('--') && !UNITLESS_CSS_PROPERTIES.has(key)
124747
+ ? `${value}px`
124748
+ : `${value}`;
124749
+ /**
124750
+ * True for a value that should be serialized as a style object rather than passed through
124751
+ * as an already-CSS string. React elements are excluded since they're valid objects too.
124752
+ */
124753
+ const style_object_to_css_isPlainObject = (value) => typeof value === 'object' && value !== null && !Array.isArray(value) && !external_react_default().isValidElement(value);
124754
+ /**
124755
+ * Serialize a React-style inline style object (`{ color: "red", fontSize: 12 }`) into a
124756
+ * CSS declaration string (`color:red;font-size:12px`), the shape hast/HTML expects for a
124757
+ * `style` attribute. Empty (`undefined`/`null`/`''`) entries are dropped.
124758
+ */
124759
+ const styleObjectToCssText = (style) => Object.entries(style)
124760
+ .filter(([, value]) => value !== undefined && value !== null && value !== '')
124761
+ .map(([key, value]) => `${cssPropertyName(key)}:${cssPropertyValue(key, value)}`)
124762
+ .join(';');
124763
+
124513
124764
  ;// ./processor/transform/mdxish/resolve-deferred-attribute-expression-props.ts
124514
124765
 
124515
124766
 
124516
124767
 
124768
+
124517
124769
  /**
124518
124770
  * Resolve attribute expressions that `mdxJsxElementHandler` deferred.
124519
124771
  *
@@ -124535,7 +124787,10 @@ const resolveDeferredAttributeExpressionProps = () => (tree, file) => {
124535
124787
  const properties = node.properties;
124536
124788
  Object.entries(deferredExpressions).forEach(([name, source]) => {
124537
124789
  try {
124538
- properties[name] = evalExpression(source, scope);
124790
+ const result = evalExpression(source, scope);
124791
+ // hast/HTML `style` is a plain CSS string; a `style={{...}}` expression evaluates to
124792
+ // a JS object, which must be serialized or it renders as the literal "[object Object]".
124793
+ properties[name] = name === 'style' && style_object_to_css_isPlainObject(result) ? styleObjectToCssText(result) : result;
124539
124794
  }
124540
124795
  catch {
124541
124796
  // Evaluation failed — fall back to the raw expression source so the attribute
@@ -124855,13 +125110,13 @@ function normalizeTableSeparator(content) {
124855
125110
  ;// ./processor/transform/mdxish/terminate-html-flow-blocks.ts
124856
125111
 
124857
125112
 
125113
+
124858
125114
  const STANDALONE_HTML_LINE_REGEX = /^(<[a-z][^<>]*>|<\/[a-z][^<>]*>)+\s*$/;
124859
125115
  const HTML_LINE_WITH_CONTENT_REGEX = /^<[a-z][^<>]*>.*<\/[a-z][^<>]*>(?:[^<]*)$/;
124860
- const terminate_html_flow_blocks_TABLE_STRUCTURE_TAGS = ['table', 'thead', 'tbody', 'tfoot', 'tr', 'td', 'th', 'caption', 'colgroup'];
124861
125116
  // Tags whose contents must be preserved as is, inserting a blank line after the
124862
125117
  // opener corrupts the payload.
124863
125118
  // htmlRawNames here refer to <pre>, <textarea>, <script>, <style>
124864
- const RAW_CONTENT_TAGS = [...htmlRawNames, ...terminate_html_flow_blocks_TABLE_STRUCTURE_TAGS];
125119
+ const RAW_CONTENT_TAGS = [...htmlRawNames, ...HTML_TABLE_STRUCTURE_TAGS];
124865
125120
  // The `(?=[\s/>])` lookahead avoids false matches on lookalike names like `<script-foo>`.
124866
125121
  const RAW_CONTENT_TAG_MATCHERS = RAW_CONTENT_TAGS.map(tag => ({
124867
125122
  open: new RegExp(`<${tag}(?=[\\s/>])[^>]*?(?<!/)>`, 'gi'),
@@ -125659,6 +125914,7 @@ function loadComponents() {
125659
125914
 
125660
125915
 
125661
125916
 
125917
+
125662
125918
 
125663
125919
 
125664
125920
  const defaultTransformers = [
@@ -125809,6 +126065,7 @@ function mdxish(mdContent, opts = {}) {
125809
126065
  .use(safeMode ? undefined : evaluate_exports) // Evaluate `export const/function` and stash scope on file.data.mdxishScope
125810
126066
  .use(remarkBreaks) // Must precede evaluateExpressions to avoid splitting the \n in an evaluated template literal into a <br> node
125811
126067
  .use(safeMode ? undefined : evaluate_expressions) // Evaluate self-contained MDX expressions (e.g. `{1+1}`)
126068
+ .use(safeMode ? undefined : evaluate_style_block_expressions) // Evaluate `<style>{`...`}</style>` template literals into plain CSS
125812
126069
  .use(variables_code, { variables }) // Resolve <<...>> and {user.*} inside code and inline code nodes
125813
126070
  .use(remarkRehype, { allowDangerousHtml: true, handlers: mdxComponentHandlers })
125814
126071
  .use(preserveBooleanProperties) // RehypeRaw converts boolean properties to empty strings