@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/components/TableOfContents/index.tsx +29 -1
- package/dist/main.js +322 -37
- package/dist/main.node.js +322 -37
- package/dist/main.node.js.map +1 -1
- package/dist/processor/transform/mdxish/evaluate-style-block-expressions.d.ts +18 -0
- package/dist/processor/transform/mdxish/style-object-to-css.d.ts +11 -0
- package/dist/processor/transform/mdxish/tables/utils.d.ts +5 -0
- package/dist/render-fixture.node.js +322 -37
- package/dist/render-fixture.node.js.map +1 -1
- package/dist/utils/common-html-words.d.ts +7 -0
- package/package.json +1 -1
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
|
|
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
|
|
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
|
|
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
|
|
96633
|
-
|
|
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
|
-
|
|
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
|
-
//
|
|
121619
|
-
|
|
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
|
-
|
|
121720
|
-
|
|
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
|
|
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
|
|
122168
|
-
//
|
|
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
|
-
|
|
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
|
|
122616
|
-
// This must come before the object check as
|
|
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
|
-
|
|
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, ...
|
|
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
|