@readme/markdown 14.11.0 → 14.11.2

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
@@ -25110,6 +25110,34 @@ function useScrollHighlight(navRef) {
25110
25110
  return scrollParent.scrollHeight > scrollParent.clientHeight
25111
25111
  && scrollParent.scrollTop + scrollParent.clientHeight >= scrollParent.scrollHeight - SCROLL_BOTTOM_TOLERANCE;
25112
25112
  };
25113
+ /**
25114
+ * Keeps the active link visible within the TOC's own scroll container —
25115
+ * the same result as `scrollIntoView({ block: 'nearest' })`, but scoped to
25116
+ * a single scroller. `scrollIntoView` adjusts *every* scrollable ancestor,
25117
+ * and starting a scroll on the page's content scroller cancels any
25118
+ * in-flight smooth scroll there — e.g. the hub's scroll-to-top reset when
25119
+ * navigating between pages (CX-3667).
25120
+ */
25121
+ const scrollTOCLinkIntoView = (link) => {
25122
+ const tocScroller = TableOfContents_getScrollParent(link);
25123
+ // Without a TOC-local scroll area, the link's nearest scrollable
25124
+ // ancestor is the window (`getScrollParent`'s fallback) or the scroller
25125
+ // holding the page content — never auto-scroll those just to reveal a
25126
+ // TOC link.
25127
+ if (!(tocScroller instanceof HTMLElement) || tocScroller.contains(headings[0]))
25128
+ return;
25129
+ const scrollerRect = tocScroller.getBoundingClientRect();
25130
+ const linkRect = link.getBoundingClientRect();
25131
+ if (linkRect.top < scrollerRect.top) {
25132
+ tocScroller.scrollTo?.({ top: tocScroller.scrollTop + (linkRect.top - scrollerRect.top), behavior: 'smooth' });
25133
+ }
25134
+ else if (linkRect.bottom > scrollerRect.bottom) {
25135
+ tocScroller.scrollTo?.({
25136
+ top: tocScroller.scrollTop + (linkRect.bottom - scrollerRect.bottom),
25137
+ behavior: 'smooth',
25138
+ });
25139
+ }
25140
+ };
25113
25141
  const activate = (id) => {
25114
25142
  if (id === activeId)
25115
25143
  return;
@@ -25126,7 +25154,7 @@ function useScrollHighlight(navRef) {
25126
25154
  const linkRect = link.getBoundingClientRect();
25127
25155
  nav.style.setProperty('--ToC-border-active-height', `${linkRect.height}px`);
25128
25156
  nav.style.setProperty('--ToC-border-active-top', `${linkRect.top - navRect.top}px`);
25129
- link.scrollIntoView?.({ block: 'nearest', behavior: 'smooth' });
25157
+ scrollTOCLinkIntoView(link);
25130
25158
  }
25131
25159
  }
25132
25160
  };
@@ -95943,6 +95971,18 @@ const tableTags = new Set([
95943
95971
  'th',
95944
95972
  'td',
95945
95973
  ]);
95974
+ /**
95975
+ * Replaces every paragraph node with its inline children. Used where paragraphs
95976
+ * are parser artifacts (remarkMdx wrapping inline JSX), not real content.
95977
+ */
95978
+ const unwrapParagraphNodes = (children) => {
95979
+ return children.flatMap(child => {
95980
+ if (child.type === 'paragraph' && 'children' in child && Array.isArray(child.children)) {
95981
+ return child.children;
95982
+ }
95983
+ return [child];
95984
+ });
95985
+ };
95946
95986
  /**
95947
95987
  * If the cell has exactly one paragraph child, unwrap it so its inline children sit
95948
95988
  * directly under the cell (matches GFM table cell shape and avoids stray `<p>` wrappers).
@@ -95954,12 +95994,7 @@ const unwrapSoleParagraph = (children) => {
95954
95994
  const paragraphCount = children.filter(c => c.type === 'paragraph').length;
95955
95995
  if (paragraphCount !== 1)
95956
95996
  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
- });
95997
+ return unwrapParagraphNodes(children);
95963
95998
  };
95964
95999
  /**
95965
96000
  * Splice each text into `html` at its offset. Inserts at the same offset
@@ -96309,6 +96344,23 @@ const RUNTIME_COMPONENT_TAGS = new Set(['Variable', 'variable', 'html-block', 'r
96309
96344
  * Uses the html-tags package, converted to a Set<string> for efficient lookups.
96310
96345
  */
96311
96346
  const STANDARD_HTML_TAGS = new Set(html_tags_namespaceObject);
96347
+ /**
96348
+ * Table structural tags. Blank lines inside these carry deliberate meaning for
96349
+ * `mdxishTables` (e.g. splitting cell content into paragraphs, or deciding
96350
+ * whether a table stays plain HTML vs a JSX `<Table>`), so transforms that
96351
+ * neutralize or claim across blank lines must leave them alone.
96352
+ */
96353
+ const HTML_TABLE_STRUCTURE_TAGS = new Set([
96354
+ 'table',
96355
+ 'thead',
96356
+ 'tbody',
96357
+ 'tfoot',
96358
+ 'tr',
96359
+ 'td',
96360
+ 'th',
96361
+ 'caption',
96362
+ 'colgroup',
96363
+ ]);
96312
96364
  /**
96313
96365
  * HTML void elements — elements that have no closing tag and no children.
96314
96366
  *
@@ -96620,18 +96672,17 @@ const processTableNode = (node, index, parent, documentPosition) => {
96620
96672
  // same line as content becomes mdxJsxTextElement inside a paragraph).
96621
96673
  // Unwrap these so <td>/<th> sit directly under <tr>, and strip
96622
96674
  // 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()));
96675
+ const removeWhitespaceOnlyTextNodes = (children) => children.filter(child => !(child.type === 'text' && 'value' in child && typeof child.value === 'string' && !child.value.trim()));
96631
96676
  visit(node, isMDXElement, (el) => {
96632
- if ('children' in el && Array.isArray(el.children)) {
96633
- el.children = cleanChildren(el.children);
96634
- }
96677
+ if (!('children' in el) || !Array.isArray(el.children))
96678
+ return;
96679
+ // Filtering transformers
96680
+ // A cell only unwraps a sole paragraph: multiple paragraphs are real
96681
+ // blank-line-separated content that must stay separated
96682
+ const unwrapped = isTableCell(el)
96683
+ ? unwrapSoleParagraph(el.children)
96684
+ : unwrapParagraphNodes(el.children);
96685
+ el.children = removeWhitespaceOnlyTextNodes(unwrapped);
96635
96686
  });
96636
96687
  parent.children[index] = {
96637
96688
  ...node,
@@ -121021,15 +121072,26 @@ const types_types = /** @type {const} */ ({
121021
121072
 
121022
121073
 
121023
121074
 
121075
+
121024
121076
  // Raw tags (type-1: pre/script/style/textarea) and block tags (type-6: div,
121025
121077
  // section, …) always start a block, so they stay flow even with trailing
121026
121078
  // content. Other lowercase tags (i, span, …) follow the type-7 rule and only
121027
121079
  // stay flow when nothing trails the close tag.
121028
121080
  const htmlFlowTagNames = new Set([...htmlRawNames, ...htmlBlockNames]);
121081
+ // Lowercase type-6 block tags claimable in flow even without a `{…}` attribute, so
121082
+ // blank lines between nested JSX siblings don't fragment the block. Excludes table
121083
+ // tags (mdxishTables owns their blank lines) and voids (never close).
121084
+ const plainBlockClaimTagNames = new Set([...htmlBlockNames].filter(tag => !HTML_TABLE_STRUCTURE_TAGS.has(tag) && !HTML_VOID_ELEMENTS.has(tag)));
121029
121085
  const syntax_nonLazyContinuationStart = {
121030
121086
  tokenize: syntax_tokenizeNonLazyContinuationStart,
121031
121087
  partial: true,
121032
121088
  };
121089
+ // Lookahead for `plainClaimLineStart`: is this line markup-only, or a paragraph
121090
+ // that merely starts with a tag? Run via `effects.check` so it never consumes.
121091
+ const markupOnlyContinuation = {
121092
+ tokenize: tokenizeMarkupOnlyContinuation,
121093
+ partial: true,
121094
+ };
121033
121095
  function resolveToMdxComponent(events) {
121034
121096
  let index = events.length;
121035
121097
  while (index > 0) {
@@ -121084,6 +121146,10 @@ function createTokenize(mode) {
121084
121146
  // (INLINE_COMPONENT_TAGS — Anchor, Glossary), also brace-gated.
121085
121147
  let isLowercaseTag = false;
121086
121148
  let sawBraceAttr = false;
121149
+ // A plain lowercase block tag claimed without a `{…}` attribute, gated by
121150
+ // `plainClaimLineStart`: after a blank line it may only continue on a tag line.
121151
+ let isPlainBlockClaim = false;
121152
+ let pendingBlankLine = false;
121087
121153
  // Code span tracking
121088
121154
  let codeSpanOpenSize = 0;
121089
121155
  let codeSpanCloseSize = 0;
@@ -121317,8 +121383,13 @@ function createTokenize(mode) {
121317
121383
  }
121318
121384
  // End of opening tag
121319
121385
  if (code === codes.greaterThan) {
121320
- if (requiresBraceAttr && !sawBraceAttr)
121321
- return nok(code);
121386
+ if (requiresBraceAttr && !sawBraceAttr) {
121387
+ // Plain lowercase block tags stay claimable in flow, gated per line by
121388
+ // `plainClaimLineStart`; everything else falls through to CommonMark.
121389
+ if (!isFlow || !plainBlockClaimTagNames.has(tagName))
121390
+ return nok(code);
121391
+ isPlainBlockClaim = true;
121392
+ }
121322
121393
  effects.consume(code);
121323
121394
  onOpenerLine = isFlow;
121324
121395
  return body;
@@ -121468,6 +121539,7 @@ function createTokenize(mode) {
121468
121539
  if (atLineStart && codeSpanOpenSize >= 3) {
121469
121540
  fenceChar = codes.graveAccent;
121470
121541
  fenceLength = codeSpanOpenSize;
121542
+ atLineStart = false;
121471
121543
  return inFencedCode(code);
121472
121544
  }
121473
121545
  return inCodeSpan(code);
@@ -121615,8 +121687,14 @@ function createTokenize(mode) {
121615
121687
  effects.consume(code);
121616
121688
  return nestedOpenTagName;
121617
121689
  }
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)) {
121690
+ // Same-name opener followed by a tag-end char bumps depth. A line ending
121691
+ // counts too: Prettier puts a newline right after the name (`<div\n …\n>`).
121692
+ if (closingTagName === tagName &&
121693
+ (code === codes.greaterThan ||
121694
+ code === codes.slash ||
121695
+ code === codes.space ||
121696
+ code === codes.horizontalTab ||
121697
+ markdownLineEnding(code))) {
121620
121698
  depth += 1;
121621
121699
  }
121622
121700
  atLineStart = false;
@@ -121705,6 +121783,10 @@ function createTokenize(mode) {
121705
121783
  }
121706
121784
  function bodyContinuationBefore(code) {
121707
121785
  if (code === null || markdownLineEnding(code)) {
121786
+ // Empty line: outside any `{…}` expression this is CommonMark's html-block
121787
+ // terminator, so a plain block claim must pass the guard below to continue.
121788
+ if (isPlainBlockClaim && braceDepth === 0)
121789
+ pendingBlankLine = true;
121708
121790
  return bodyContinuationStart(code);
121709
121791
  }
121710
121792
  effects.enter('mdxComponentData');
@@ -121716,19 +121798,52 @@ function createTokenize(mode) {
121716
121798
  return inBodyBraceString(code);
121717
121799
  return inBodyBraceExpr(code);
121718
121800
  }
121719
- // Detect tilde fences at line start
121720
- if (atLineStart && code === codes.tilde) {
121801
+ if (isPlainBlockClaim)
121802
+ return plainClaimLineStart(code);
121803
+ return bodyLineStart(code);
121804
+ }
121805
+ // Dispatch a non-blank continuation line: fenced code at line start, else body.
121806
+ function bodyLineStart(code) {
121807
+ if (atLineStart && code === codes.tilde)
121721
121808
  return bodyAfterLineStart(code);
121722
- }
121723
- // Detect backtick fences at line start
121724
121809
  if (atLineStart && code === codes.graveAccent) {
121725
121810
  codeSpanOpenSize = 0;
121726
- atLineStart = false;
121811
+ // Leave `atLineStart` set — `countOpenTicks` needs it to tell a fence from an
121812
+ // inline code span once the run of backticks is fully counted; it's cleared once
121813
+ // that fence-vs-span decision has actually been made.
121727
121814
  return countOpenTicks(code);
121728
121815
  }
121729
121816
  atLineStart = false;
121730
121817
  return body(code);
121731
121818
  }
121819
+ // Line-start gate for plain block claims. After a blank line the block may only
121820
+ // continue on a tag line (`<…`); any markdown island (`**bold**`, `[block:…]`, a
121821
+ // fence) refuses so CommonMark html-flow reparses it exactly as it does today.
121822
+ function plainClaimLineStart(code) {
121823
+ // Leading whitespace only → treat as a blank line, matching CommonMark.
121824
+ if (code === codes.space || code === codes.horizontalTab) {
121825
+ effects.consume(code);
121826
+ return plainClaimLineStart;
121827
+ }
121828
+ if (code === null || markdownLineEnding(code)) {
121829
+ pendingBlankLine = true;
121830
+ effects.exit('mdxComponentData');
121831
+ return bodyContinuationStart(code);
121832
+ }
121833
+ // Across a blank line the block only continues onto a markup-only line; a
121834
+ // paragraph that merely starts with a tag must fall back so its markdown
121835
+ // parses and rehype-raw re-nests it into the wrapper.
121836
+ if (pendingBlankLine) {
121837
+ if (code !== codes.lessThan)
121838
+ return nok(code);
121839
+ return effects.check(markupOnlyContinuation, plainClaimContinue, nok)(code);
121840
+ }
121841
+ return bodyLineStart(code);
121842
+ }
121843
+ function plainClaimContinue(code) {
121844
+ pendingBlankLine = false;
121845
+ return bodyLineStart(code);
121846
+ }
121732
121847
  // ── Shared lazy continuation failure ───────────────────────────────────
121733
121848
  function continuationAfter(code) {
121734
121849
  if (code === null) {
@@ -121759,6 +121874,46 @@ function syntax_tokenizeNonLazyContinuationStart(effects, ok, nok) {
121759
121874
  return ok(code);
121760
121875
  }
121761
121876
  }
121877
+ // A markup-only line opens with a tag (`<x`/`</x`) and ends (ignoring trailing
121878
+ // spaces) at a `>`. That distinguishes a structural continuation like
121879
+ // `<span>b</span></div>` from a paragraph like `<b>Note:</b> read *this*`.
121880
+ function tokenizeMarkupOnlyContinuation(effects, ok, nok) {
121881
+ let lastNonSpace = null;
121882
+ return start;
121883
+ function start(code) {
121884
+ // Caller guarantees we are at `<` at the (already de-indented) line start.
121885
+ effects.enter(types_types.data);
121886
+ effects.consume(code);
121887
+ return afterLessThan;
121888
+ }
121889
+ function afterLessThan(code) {
121890
+ if (code === codes.slash) {
121891
+ effects.consume(code);
121892
+ return afterSlash;
121893
+ }
121894
+ return afterSlash(code);
121895
+ }
121896
+ // The `<` (or `</`) must introduce a real tag, not a stray `<` in prose.
121897
+ function afterSlash(code) {
121898
+ if (asciiAlpha(code)) {
121899
+ lastNonSpace = code;
121900
+ effects.consume(code);
121901
+ return scanToLineEnd;
121902
+ }
121903
+ effects.exit(types_types.data);
121904
+ return nok(code);
121905
+ }
121906
+ function scanToLineEnd(code) {
121907
+ if (code === null || markdownLineEnding(code)) {
121908
+ effects.exit(types_types.data);
121909
+ return lastNonSpace === codes.greaterThan ? ok(code) : nok(code);
121910
+ }
121911
+ if (!markdownSpace(code))
121912
+ lastNonSpace = code;
121913
+ effects.consume(code);
121914
+ return scanToLineEnd;
121915
+ }
121916
+ }
121762
121917
  /**
121763
121918
  * Micromark extension that tokenizes MDX-like components.
121764
121919
  *
@@ -122005,6 +122160,8 @@ const mdxishInlineMdxComponents = () => tree => {
122005
122160
 
122006
122161
 
122007
122162
 
122163
+ /** Matches a JSX attribute expression (e.g. `key={i}`) anywhere in a string. */
122164
+ const NESTED_ATTR_EXPRESSION_RE = /[\w-]+\s*=\s*\{/;
122008
122165
  /**
122009
122166
  * Reduce leading whitespace on all lines just enough to prevent
122010
122167
  * remark from treating indented content as code blocks (4+ spaces).
@@ -122164,10 +122321,16 @@ const mdxishMdxComponentBlocks = (opts = {}) => (tree, file) => {
122164
122321
  // inline, which is how ReadMe's custom components are modeled).
122165
122322
  if (!isPascal && parent.type === 'paragraph')
122166
122323
  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
122324
+ // Lowercase HTML tags are eligible when they (or a descendant tag in their
122325
+ // content, e.g. a `.map()` body returning JSX with `key={i}`) carry a
122326
+ // JSX-expression attribute. Without this, a wrapper `<div>` with only plain
122327
+ // attributes (or none) swallows its whole nested block — including any
122328
+ // `style={{...}}`/`.map()` JSX inside it — as literal HTML text, which
122329
+ // rehype-raw's parse5 pass then garbles (it has no notion of JS expressions).
122330
+ // Plain HTML with no expressions anywhere stays as an html node so
122169
122331
  // rehype-raw handles it as normal.
122170
- if (!isPascal && !hasExpressionAttr(attributes))
122332
+ const hasNestedExpressionAttr = !selfClosing && NESTED_ATTR_EXPRESSION_RE.test(contentAfterTag);
122333
+ if (!isPascal && !hasExpressionAttr(attributes) && !hasNestedExpressionAttr)
122171
122334
  return;
122172
122335
  const closingTagStr = `</${tag}>`;
122173
122336
  // Case 1: Self-closing tag
@@ -122606,15 +122769,17 @@ const evalExpression = (expression, scope) => {
122606
122769
 
122607
122770
 
122608
122771
 
122772
+ /** True for an array containing at least one React element, e.g. the result of `.map()` returning JSX. */
122773
+ const isRenderableElementArray = (value) => Array.isArray(value) && value.some((external_react_default()).isValidElement);
122609
122774
  /** Given the type of the expression result, create the corresponding mdast node. */
122610
122775
  const createEvaluatedNode = (result, position) => {
122611
122776
  if (result === null || result === undefined) {
122612
122777
  return { type: 'text', value: '', position };
122613
122778
  }
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 };
122779
+ else if (external_react_default().isValidElement(result) || isRenderableElementArray(result)) {
122780
+ // Convert react elements (or arrays of them, e.g. `.map()` returning JSX) to their HTML
122781
+ // representation. This must come before the object check as both are a subset of it.
122782
+ return { type: 'html', value: (0,server_node/* renderToStaticMarkup */.qV)(external_react_default().createElement((external_react_default()).Fragment, null, result)), position };
122618
122783
  }
122619
122784
  else if (typeof result === 'object') {
122620
122785
  return { type: 'text', value: JSON.stringify(result), position };
@@ -122654,6 +122819,47 @@ const evaluateExpressions = () => (tree, file) => {
122654
122819
  };
122655
122820
  /* harmony default export */ const evaluate_expressions = (evaluateExpressions);
122656
122821
 
122822
+ ;// ./processor/transform/mdxish/evaluate-style-block-expressions.ts
122823
+
122824
+
122825
+
122826
+ // Matches a standalone `<style ...>{ <expr> }</style>` block — the JSX shape MDX evaluates
122827
+ // (typically a template-literal-wrapped CSS string) but which mdxish otherwise leaves as
122828
+ // literal, invalid-CSS text (see CX-3646).
122829
+ const STYLE_EXPRESSION_RE = /^(<style\b[^>]*>)\s*\{([\s\S]*)\}\s*(<\/style>)$/i;
122830
+ /**
122831
+ * Evaluate the JSX expression wrapping a `<style>` tag's contents (typically a template
122832
+ * literal, e.g. `<style>{\`.foo { color: red; }\`}</style>`) so the tag ends up holding plain
122833
+ * CSS text instead of the literal `{`...`}` wrapper — which the browser treats as invalid CSS
122834
+ * and drops the entire stylesheet for.
122835
+ *
122836
+ * `<style>` is one of CommonMark's "raw text" HTML elements (along with script/pre/textarea):
122837
+ * its contents are captured verbatim as a single `html` mdast node with no inner tokenization,
122838
+ * so this expression never reaches the mdxFlowExpression tokenizer or `evaluateExpressions` —
122839
+ * it has to be matched and evaluated directly against the raw node's string value.
122840
+ *
122841
+ * Must run after `evaluateExports` (needs `file.data.mdxishScope`) and before `remarkRehype`
122842
+ * turns `html` mdast nodes into raw hast strings. Skipped in safeMode.
122843
+ */
122844
+ const evaluateStyleBlockExpressions = () => (tree, file) => {
122845
+ const scope = { ...file.data.mdxishScope, React: (external_react_default()) };
122846
+ visit(tree, 'html', (node) => {
122847
+ const match = node.value.trim().match(STYLE_EXPRESSION_RE);
122848
+ if (!match)
122849
+ return;
122850
+ const [, openTag, expression, closeTag] = match;
122851
+ try {
122852
+ const css = evalExpression(expression, scope);
122853
+ node.value = `${openTag}${String(css)}${closeTag}`;
122854
+ }
122855
+ catch {
122856
+ // Evaluation failed — leave the node untouched so it round-trips as literal text.
122857
+ }
122858
+ });
122859
+ return tree;
122860
+ };
122861
+ /* harmony default export */ const evaluate_style_block_expressions = (evaluateStyleBlockExpressions);
122862
+
122657
122863
  ;// ./processor/transform/mdxish/heading-slugs.ts
122658
122864
 
122659
122865
 
@@ -124510,10 +124716,84 @@ function removeJSXComments(content) {
124510
124716
  return content.replace(JSX_COMMENT_REGEX, '');
124511
124717
  }
124512
124718
 
124719
+ ;// ./processor/transform/mdxish/style-object-to-css.ts
124720
+
124721
+ /**
124722
+ * CSS properties React treats as unitless — a bare number stays as-is instead of
124723
+ * getting `px` appended. Mirrors React DOM's `isUnitlessNumber` whitelist.
124724
+ * @see https://github.com/facebook/react/blob/main/packages/react-dom-bindings/src/shared/CSSProperty.js
124725
+ */
124726
+ const UNITLESS_CSS_PROPERTIES = new Set([
124727
+ 'animationIterationCount',
124728
+ 'aspectRatio',
124729
+ 'borderImageOutset',
124730
+ 'borderImageSlice',
124731
+ 'borderImageWidth',
124732
+ 'boxFlex',
124733
+ 'boxFlexGroup',
124734
+ 'boxOrdinalGroup',
124735
+ 'columnCount',
124736
+ 'columns',
124737
+ 'flex',
124738
+ 'flexGrow',
124739
+ 'flexPositive',
124740
+ 'flexShrink',
124741
+ 'flexNegative',
124742
+ 'flexOrder',
124743
+ 'gridArea',
124744
+ 'gridRow',
124745
+ 'gridRowEnd',
124746
+ 'gridRowSpan',
124747
+ 'gridRowStart',
124748
+ 'gridColumn',
124749
+ 'gridColumnEnd',
124750
+ 'gridColumnSpan',
124751
+ 'gridColumnStart',
124752
+ 'fontWeight',
124753
+ 'lineClamp',
124754
+ 'lineHeight',
124755
+ 'opacity',
124756
+ 'order',
124757
+ 'orphans',
124758
+ 'tabSize',
124759
+ 'widows',
124760
+ 'zIndex',
124761
+ 'zoom',
124762
+ 'fillOpacity',
124763
+ 'floodOpacity',
124764
+ 'stopOpacity',
124765
+ 'strokeDasharray',
124766
+ 'strokeDashoffset',
124767
+ 'strokeMiterlimit',
124768
+ 'strokeOpacity',
124769
+ 'strokeWidth',
124770
+ ]);
124771
+ /** Convert a camelCase (or CSS custom property) key into its kebab-case CSS name. */
124772
+ const cssPropertyName = (key) => (key.startsWith('--') ? key : key.replace(/[A-Z]/g, m => `-${m.toLowerCase()}`));
124773
+ /** React appends `px` to non-zero numeric values, except unitless and custom properties. */
124774
+ const cssPropertyValue = (key, value) => typeof value === 'number' && value !== 0 && !key.startsWith('--') && !UNITLESS_CSS_PROPERTIES.has(key)
124775
+ ? `${value}px`
124776
+ : `${value}`;
124777
+ /**
124778
+ * True for a value that should be serialized as a style object rather than passed through
124779
+ * as an already-CSS string. React elements are excluded since they're valid objects too.
124780
+ */
124781
+ const style_object_to_css_isPlainObject = (value) => typeof value === 'object' && value !== null && !Array.isArray(value) && !external_react_default().isValidElement(value);
124782
+ /**
124783
+ * Serialize a React-style inline style object (`{ color: "red", fontSize: 12 }`) into a
124784
+ * CSS declaration string (`color:red;font-size:12px`), the shape hast/HTML expects for a
124785
+ * `style` attribute. Empty (`undefined`/`null`/`''`) entries are dropped.
124786
+ */
124787
+ const styleObjectToCssText = (style) => Object.entries(style)
124788
+ .filter(([, value]) => value !== undefined && value !== null && value !== '')
124789
+ .map(([key, value]) => `${cssPropertyName(key)}:${cssPropertyValue(key, value)}`)
124790
+ .join(';');
124791
+
124513
124792
  ;// ./processor/transform/mdxish/resolve-deferred-attribute-expression-props.ts
124514
124793
 
124515
124794
 
124516
124795
 
124796
+
124517
124797
  /**
124518
124798
  * Resolve attribute expressions that `mdxJsxElementHandler` deferred.
124519
124799
  *
@@ -124535,7 +124815,10 @@ const resolveDeferredAttributeExpressionProps = () => (tree, file) => {
124535
124815
  const properties = node.properties;
124536
124816
  Object.entries(deferredExpressions).forEach(([name, source]) => {
124537
124817
  try {
124538
- properties[name] = evalExpression(source, scope);
124818
+ const result = evalExpression(source, scope);
124819
+ // hast/HTML `style` is a plain CSS string; a `style={{...}}` expression evaluates to
124820
+ // a JS object, which must be serialized or it renders as the literal "[object Object]".
124821
+ properties[name] = name === 'style' && style_object_to_css_isPlainObject(result) ? styleObjectToCssText(result) : result;
124539
124822
  }
124540
124823
  catch {
124541
124824
  // Evaluation failed — fall back to the raw expression source so the attribute
@@ -124855,13 +125138,13 @@ function normalizeTableSeparator(content) {
124855
125138
  ;// ./processor/transform/mdxish/terminate-html-flow-blocks.ts
124856
125139
 
124857
125140
 
125141
+
124858
125142
  const STANDALONE_HTML_LINE_REGEX = /^(<[a-z][^<>]*>|<\/[a-z][^<>]*>)+\s*$/;
124859
125143
  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
125144
  // Tags whose contents must be preserved as is, inserting a blank line after the
124862
125145
  // opener corrupts the payload.
124863
125146
  // htmlRawNames here refer to <pre>, <textarea>, <script>, <style>
124864
- const RAW_CONTENT_TAGS = [...htmlRawNames, ...terminate_html_flow_blocks_TABLE_STRUCTURE_TAGS];
125147
+ const RAW_CONTENT_TAGS = [...htmlRawNames, ...HTML_TABLE_STRUCTURE_TAGS];
124865
125148
  // The `(?=[\s/>])` lookahead avoids false matches on lookalike names like `<script-foo>`.
124866
125149
  const RAW_CONTENT_TAG_MATCHERS = RAW_CONTENT_TAGS.map(tag => ({
124867
125150
  open: new RegExp(`<${tag}(?=[\\s/>])[^>]*?(?<!/)>`, 'gi'),
@@ -125659,6 +125942,7 @@ function loadComponents() {
125659
125942
 
125660
125943
 
125661
125944
 
125945
+
125662
125946
 
125663
125947
 
125664
125948
  const defaultTransformers = [
@@ -125809,6 +126093,7 @@ function mdxish(mdContent, opts = {}) {
125809
126093
  .use(safeMode ? undefined : evaluate_exports) // Evaluate `export const/function` and stash scope on file.data.mdxishScope
125810
126094
  .use(remarkBreaks) // Must precede evaluateExpressions to avoid splitting the \n in an evaluated template literal into a <br> node
125811
126095
  .use(safeMode ? undefined : evaluate_expressions) // Evaluate self-contained MDX expressions (e.g. `{1+1}`)
126096
+ .use(safeMode ? undefined : evaluate_style_block_expressions) // Evaluate `<style>{`...`}</style>` template literals into plain CSS
125812
126097
  .use(variables_code, { variables }) // Resolve <<...>> and {user.*} inside code and inline code nodes
125813
126098
  .use(remarkRehype, { allowDangerousHtml: true, handlers: mdxComponentHandlers })
125814
126099
  .use(preserveBooleanProperties) // RehypeRaw converts boolean properties to empty strings