@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
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { Root } from 'mdast';
|
|
2
|
+
import type { Plugin } from 'unified';
|
|
3
|
+
/**
|
|
4
|
+
* Evaluate the JSX expression wrapping a `<style>` tag's contents (typically a template
|
|
5
|
+
* literal, e.g. `<style>{\`.foo { color: red; }\`}</style>`) so the tag ends up holding plain
|
|
6
|
+
* CSS text instead of the literal `{`...`}` wrapper — which the browser treats as invalid CSS
|
|
7
|
+
* and drops the entire stylesheet for.
|
|
8
|
+
*
|
|
9
|
+
* `<style>` is one of CommonMark's "raw text" HTML elements (along with script/pre/textarea):
|
|
10
|
+
* its contents are captured verbatim as a single `html` mdast node with no inner tokenization,
|
|
11
|
+
* so this expression never reaches the mdxFlowExpression tokenizer or `evaluateExpressions` —
|
|
12
|
+
* it has to be matched and evaluated directly against the raw node's string value.
|
|
13
|
+
*
|
|
14
|
+
* Must run after `evaluateExports` (needs `file.data.mdxishScope`) and before `remarkRehype`
|
|
15
|
+
* turns `html` mdast nodes into raw hast strings. Skipped in safeMode.
|
|
16
|
+
*/
|
|
17
|
+
declare const evaluateStyleBlockExpressions: Plugin<[], Root>;
|
|
18
|
+
export default evaluateStyleBlockExpressions;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* True for a value that should be serialized as a style object rather than passed through
|
|
3
|
+
* as an already-CSS string. React elements are excluded since they're valid objects too.
|
|
4
|
+
*/
|
|
5
|
+
export declare const isPlainObject: (value: unknown) => value is Record<string, unknown>;
|
|
6
|
+
/**
|
|
7
|
+
* Serialize a React-style inline style object (`{ color: "red", fontSize: 12 }`) into a
|
|
8
|
+
* CSS declaration string (`color:red;font-size:12px`), the shape hast/HTML expects for a
|
|
9
|
+
* `style` attribute. Empty (`undefined`/`null`/`''`) entries are dropped.
|
|
10
|
+
*/
|
|
11
|
+
export declare const styleObjectToCssText: (style: Record<string, unknown>) => string;
|
|
@@ -9,6 +9,11 @@ export interface RepairResult {
|
|
|
9
9
|
value: string;
|
|
10
10
|
}
|
|
11
11
|
export declare const tableTags: Set<string>;
|
|
12
|
+
/**
|
|
13
|
+
* Replaces every paragraph node with its inline children. Used where paragraphs
|
|
14
|
+
* are parser artifacts (remarkMdx wrapping inline JSX), not real content.
|
|
15
|
+
*/
|
|
16
|
+
export declare const unwrapParagraphNodes: (children: Node[]) => Node[];
|
|
12
17
|
/**
|
|
13
18
|
* If the cell has exactly one paragraph child, unwrap it so its inline children sit
|
|
14
19
|
* directly under the cell (matches GFM table cell shape and avoids stray `<p>` wrappers).
|
|
@@ -92021,6 +92021,34 @@ function useScrollHighlight(navRef) {
|
|
|
92021
92021
|
return scrollParent.scrollHeight > scrollParent.clientHeight
|
|
92022
92022
|
&& scrollParent.scrollTop + scrollParent.clientHeight >= scrollParent.scrollHeight - SCROLL_BOTTOM_TOLERANCE;
|
|
92023
92023
|
};
|
|
92024
|
+
/**
|
|
92025
|
+
* Keeps the active link visible within the TOC's own scroll container —
|
|
92026
|
+
* the same result as `scrollIntoView({ block: 'nearest' })`, but scoped to
|
|
92027
|
+
* a single scroller. `scrollIntoView` adjusts *every* scrollable ancestor,
|
|
92028
|
+
* and starting a scroll on the page's content scroller cancels any
|
|
92029
|
+
* in-flight smooth scroll there — e.g. the hub's scroll-to-top reset when
|
|
92030
|
+
* navigating between pages (CX-3667).
|
|
92031
|
+
*/
|
|
92032
|
+
const scrollTOCLinkIntoView = (link) => {
|
|
92033
|
+
const tocScroller = TableOfContents_getScrollParent(link);
|
|
92034
|
+
// Without a TOC-local scroll area, the link's nearest scrollable
|
|
92035
|
+
// ancestor is the window (`getScrollParent`'s fallback) or the scroller
|
|
92036
|
+
// holding the page content — never auto-scroll those just to reveal a
|
|
92037
|
+
// TOC link.
|
|
92038
|
+
if (!(tocScroller instanceof HTMLElement) || tocScroller.contains(headings[0]))
|
|
92039
|
+
return;
|
|
92040
|
+
const scrollerRect = tocScroller.getBoundingClientRect();
|
|
92041
|
+
const linkRect = link.getBoundingClientRect();
|
|
92042
|
+
if (linkRect.top < scrollerRect.top) {
|
|
92043
|
+
tocScroller.scrollTo?.({ top: tocScroller.scrollTop + (linkRect.top - scrollerRect.top), behavior: 'smooth' });
|
|
92044
|
+
}
|
|
92045
|
+
else if (linkRect.bottom > scrollerRect.bottom) {
|
|
92046
|
+
tocScroller.scrollTo?.({
|
|
92047
|
+
top: tocScroller.scrollTop + (linkRect.bottom - scrollerRect.bottom),
|
|
92048
|
+
behavior: 'smooth',
|
|
92049
|
+
});
|
|
92050
|
+
}
|
|
92051
|
+
};
|
|
92024
92052
|
const activate = (id) => {
|
|
92025
92053
|
if (id === activeId)
|
|
92026
92054
|
return;
|
|
@@ -92037,7 +92065,7 @@ function useScrollHighlight(navRef) {
|
|
|
92037
92065
|
const linkRect = link.getBoundingClientRect();
|
|
92038
92066
|
nav.style.setProperty('--ToC-border-active-height', `${linkRect.height}px`);
|
|
92039
92067
|
nav.style.setProperty('--ToC-border-active-top', `${linkRect.top - navRect.top}px`);
|
|
92040
|
-
link
|
|
92068
|
+
scrollTOCLinkIntoView(link);
|
|
92041
92069
|
}
|
|
92042
92070
|
}
|
|
92043
92071
|
};
|
|
@@ -95894,6 +95922,18 @@ const tableTags = new Set([
|
|
|
95894
95922
|
'th',
|
|
95895
95923
|
'td',
|
|
95896
95924
|
]);
|
|
95925
|
+
/**
|
|
95926
|
+
* Replaces every paragraph node with its inline children. Used where paragraphs
|
|
95927
|
+
* are parser artifacts (remarkMdx wrapping inline JSX), not real content.
|
|
95928
|
+
*/
|
|
95929
|
+
const unwrapParagraphNodes = (children) => {
|
|
95930
|
+
return children.flatMap(child => {
|
|
95931
|
+
if (child.type === 'paragraph' && 'children' in child && Array.isArray(child.children)) {
|
|
95932
|
+
return child.children;
|
|
95933
|
+
}
|
|
95934
|
+
return [child];
|
|
95935
|
+
});
|
|
95936
|
+
};
|
|
95897
95937
|
/**
|
|
95898
95938
|
* If the cell has exactly one paragraph child, unwrap it so its inline children sit
|
|
95899
95939
|
* directly under the cell (matches GFM table cell shape and avoids stray `<p>` wrappers).
|
|
@@ -95905,12 +95945,7 @@ const unwrapSoleParagraph = (children) => {
|
|
|
95905
95945
|
const paragraphCount = children.filter(c => c.type === 'paragraph').length;
|
|
95906
95946
|
if (paragraphCount !== 1)
|
|
95907
95947
|
return children;
|
|
95908
|
-
return children
|
|
95909
|
-
if (child.type === 'paragraph' && 'children' in child && Array.isArray(child.children)) {
|
|
95910
|
-
return child.children;
|
|
95911
|
-
}
|
|
95912
|
-
return [child];
|
|
95913
|
-
});
|
|
95948
|
+
return unwrapParagraphNodes(children);
|
|
95914
95949
|
};
|
|
95915
95950
|
/**
|
|
95916
95951
|
* Splice each text into `html` at its offset. Inserts at the same offset
|
|
@@ -96260,6 +96295,23 @@ const RUNTIME_COMPONENT_TAGS = new Set(['Variable', 'variable', 'html-block', 'r
|
|
|
96260
96295
|
* Uses the html-tags package, converted to a Set<string> for efficient lookups.
|
|
96261
96296
|
*/
|
|
96262
96297
|
const STANDARD_HTML_TAGS = new Set(html_tags_namespaceObject);
|
|
96298
|
+
/**
|
|
96299
|
+
* Table structural tags. Blank lines inside these carry deliberate meaning for
|
|
96300
|
+
* `mdxishTables` (e.g. splitting cell content into paragraphs, or deciding
|
|
96301
|
+
* whether a table stays plain HTML vs a JSX `<Table>`), so transforms that
|
|
96302
|
+
* neutralize or claim across blank lines must leave them alone.
|
|
96303
|
+
*/
|
|
96304
|
+
const HTML_TABLE_STRUCTURE_TAGS = new Set([
|
|
96305
|
+
'table',
|
|
96306
|
+
'thead',
|
|
96307
|
+
'tbody',
|
|
96308
|
+
'tfoot',
|
|
96309
|
+
'tr',
|
|
96310
|
+
'td',
|
|
96311
|
+
'th',
|
|
96312
|
+
'caption',
|
|
96313
|
+
'colgroup',
|
|
96314
|
+
]);
|
|
96263
96315
|
/**
|
|
96264
96316
|
* HTML void elements — elements that have no closing tag and no children.
|
|
96265
96317
|
*
|
|
@@ -96571,18 +96623,17 @@ const processTableNode = (node, index, parent, documentPosition) => {
|
|
|
96571
96623
|
// same line as content becomes mdxJsxTextElement inside a paragraph).
|
|
96572
96624
|
// Unwrap these so <td>/<th> sit directly under <tr>, and strip
|
|
96573
96625
|
// whitespace-only text nodes to avoid rendering empty <p>/<br>.
|
|
96574
|
-
const
|
|
96575
|
-
.flatMap(child => {
|
|
96576
|
-
if (child.type === 'paragraph' && 'children' in child && Array.isArray(child.children)) {
|
|
96577
|
-
return child.children;
|
|
96578
|
-
}
|
|
96579
|
-
return [child];
|
|
96580
|
-
})
|
|
96581
|
-
.filter(child => !(child.type === 'text' && 'value' in child && typeof child.value === 'string' && !child.value.trim()));
|
|
96626
|
+
const removeWhitespaceOnlyTextNodes = (children) => children.filter(child => !(child.type === 'text' && 'value' in child && typeof child.value === 'string' && !child.value.trim()));
|
|
96582
96627
|
lib_visit(node, utils_isMDXElement, (el) => {
|
|
96583
|
-
if ('children' in el
|
|
96584
|
-
|
|
96585
|
-
|
|
96628
|
+
if (!('children' in el) || !Array.isArray(el.children))
|
|
96629
|
+
return;
|
|
96630
|
+
// Filtering transformers
|
|
96631
|
+
// A cell only unwraps a sole paragraph: multiple paragraphs are real
|
|
96632
|
+
// blank-line-separated content that must stay separated
|
|
96633
|
+
const unwrapped = isTableCell(el)
|
|
96634
|
+
? unwrapSoleParagraph(el.children)
|
|
96635
|
+
: unwrapParagraphNodes(el.children);
|
|
96636
|
+
el.children = removeWhitespaceOnlyTextNodes(unwrapped);
|
|
96586
96637
|
});
|
|
96587
96638
|
parent.children[index] = {
|
|
96588
96639
|
...node,
|
|
@@ -119552,15 +119603,26 @@ const types_types = /** @type {const} */ ({
|
|
|
119552
119603
|
|
|
119553
119604
|
|
|
119554
119605
|
|
|
119606
|
+
|
|
119555
119607
|
// Raw tags (type-1: pre/script/style/textarea) and block tags (type-6: div,
|
|
119556
119608
|
// section, …) always start a block, so they stay flow even with trailing
|
|
119557
119609
|
// content. Other lowercase tags (i, span, …) follow the type-7 rule and only
|
|
119558
119610
|
// stay flow when nothing trails the close tag.
|
|
119559
119611
|
const htmlFlowTagNames = new Set([...htmlRawNames, ...htmlBlockNames]);
|
|
119612
|
+
// Lowercase type-6 block tags claimable in flow even without a `{…}` attribute, so
|
|
119613
|
+
// blank lines between nested JSX siblings don't fragment the block. Excludes table
|
|
119614
|
+
// tags (mdxishTables owns their blank lines) and voids (never close).
|
|
119615
|
+
const plainBlockClaimTagNames = new Set([...htmlBlockNames].filter(tag => !HTML_TABLE_STRUCTURE_TAGS.has(tag) && !HTML_VOID_ELEMENTS.has(tag)));
|
|
119560
119616
|
const syntax_nonLazyContinuationStart = {
|
|
119561
119617
|
tokenize: syntax_tokenizeNonLazyContinuationStart,
|
|
119562
119618
|
partial: true,
|
|
119563
119619
|
};
|
|
119620
|
+
// Lookahead for `plainClaimLineStart`: is this line markup-only, or a paragraph
|
|
119621
|
+
// that merely starts with a tag? Run via `effects.check` so it never consumes.
|
|
119622
|
+
const markupOnlyContinuation = {
|
|
119623
|
+
tokenize: tokenizeMarkupOnlyContinuation,
|
|
119624
|
+
partial: true,
|
|
119625
|
+
};
|
|
119564
119626
|
function resolveToMdxComponent(events) {
|
|
119565
119627
|
let index = events.length;
|
|
119566
119628
|
while (index > 0) {
|
|
@@ -119615,6 +119677,10 @@ function createTokenize(mode) {
|
|
|
119615
119677
|
// (INLINE_COMPONENT_TAGS — Anchor, Glossary), also brace-gated.
|
|
119616
119678
|
let isLowercaseTag = false;
|
|
119617
119679
|
let sawBraceAttr = false;
|
|
119680
|
+
// A plain lowercase block tag claimed without a `{…}` attribute, gated by
|
|
119681
|
+
// `plainClaimLineStart`: after a blank line it may only continue on a tag line.
|
|
119682
|
+
let isPlainBlockClaim = false;
|
|
119683
|
+
let pendingBlankLine = false;
|
|
119618
119684
|
// Code span tracking
|
|
119619
119685
|
let codeSpanOpenSize = 0;
|
|
119620
119686
|
let codeSpanCloseSize = 0;
|
|
@@ -119848,8 +119914,13 @@ function createTokenize(mode) {
|
|
|
119848
119914
|
}
|
|
119849
119915
|
// End of opening tag
|
|
119850
119916
|
if (code === codes.greaterThan) {
|
|
119851
|
-
if (requiresBraceAttr && !sawBraceAttr)
|
|
119852
|
-
|
|
119917
|
+
if (requiresBraceAttr && !sawBraceAttr) {
|
|
119918
|
+
// Plain lowercase block tags stay claimable in flow, gated per line by
|
|
119919
|
+
// `plainClaimLineStart`; everything else falls through to CommonMark.
|
|
119920
|
+
if (!isFlow || !plainBlockClaimTagNames.has(tagName))
|
|
119921
|
+
return nok(code);
|
|
119922
|
+
isPlainBlockClaim = true;
|
|
119923
|
+
}
|
|
119853
119924
|
effects.consume(code);
|
|
119854
119925
|
onOpenerLine = isFlow;
|
|
119855
119926
|
return body;
|
|
@@ -119999,6 +120070,7 @@ function createTokenize(mode) {
|
|
|
119999
120070
|
if (atLineStart && codeSpanOpenSize >= 3) {
|
|
120000
120071
|
fenceChar = codes.graveAccent;
|
|
120001
120072
|
fenceLength = codeSpanOpenSize;
|
|
120073
|
+
atLineStart = false;
|
|
120002
120074
|
return inFencedCode(code);
|
|
120003
120075
|
}
|
|
120004
120076
|
return inCodeSpan(code);
|
|
@@ -120146,8 +120218,14 @@ function createTokenize(mode) {
|
|
|
120146
120218
|
effects.consume(code);
|
|
120147
120219
|
return nestedOpenTagName;
|
|
120148
120220
|
}
|
|
120149
|
-
//
|
|
120150
|
-
|
|
120221
|
+
// Same-name opener followed by a tag-end char bumps depth. A line ending
|
|
120222
|
+
// counts too: Prettier puts a newline right after the name (`<div\n …\n>`).
|
|
120223
|
+
if (closingTagName === tagName &&
|
|
120224
|
+
(code === codes.greaterThan ||
|
|
120225
|
+
code === codes.slash ||
|
|
120226
|
+
code === codes.space ||
|
|
120227
|
+
code === codes.horizontalTab ||
|
|
120228
|
+
markdownLineEnding(code))) {
|
|
120151
120229
|
depth += 1;
|
|
120152
120230
|
}
|
|
120153
120231
|
atLineStart = false;
|
|
@@ -120236,6 +120314,10 @@ function createTokenize(mode) {
|
|
|
120236
120314
|
}
|
|
120237
120315
|
function bodyContinuationBefore(code) {
|
|
120238
120316
|
if (code === null || markdownLineEnding(code)) {
|
|
120317
|
+
// Empty line: outside any `{…}` expression this is CommonMark's html-block
|
|
120318
|
+
// terminator, so a plain block claim must pass the guard below to continue.
|
|
120319
|
+
if (isPlainBlockClaim && braceDepth === 0)
|
|
120320
|
+
pendingBlankLine = true;
|
|
120239
120321
|
return bodyContinuationStart(code);
|
|
120240
120322
|
}
|
|
120241
120323
|
effects.enter('mdxComponentData');
|
|
@@ -120247,19 +120329,52 @@ function createTokenize(mode) {
|
|
|
120247
120329
|
return inBodyBraceString(code);
|
|
120248
120330
|
return inBodyBraceExpr(code);
|
|
120249
120331
|
}
|
|
120250
|
-
|
|
120251
|
-
|
|
120332
|
+
if (isPlainBlockClaim)
|
|
120333
|
+
return plainClaimLineStart(code);
|
|
120334
|
+
return bodyLineStart(code);
|
|
120335
|
+
}
|
|
120336
|
+
// Dispatch a non-blank continuation line: fenced code at line start, else body.
|
|
120337
|
+
function bodyLineStart(code) {
|
|
120338
|
+
if (atLineStart && code === codes.tilde)
|
|
120252
120339
|
return bodyAfterLineStart(code);
|
|
120253
|
-
}
|
|
120254
|
-
// Detect backtick fences at line start
|
|
120255
120340
|
if (atLineStart && code === codes.graveAccent) {
|
|
120256
120341
|
codeSpanOpenSize = 0;
|
|
120257
|
-
atLineStart
|
|
120342
|
+
// Leave `atLineStart` set — `countOpenTicks` needs it to tell a fence from an
|
|
120343
|
+
// inline code span once the run of backticks is fully counted; it's cleared once
|
|
120344
|
+
// that fence-vs-span decision has actually been made.
|
|
120258
120345
|
return countOpenTicks(code);
|
|
120259
120346
|
}
|
|
120260
120347
|
atLineStart = false;
|
|
120261
120348
|
return body(code);
|
|
120262
120349
|
}
|
|
120350
|
+
// Line-start gate for plain block claims. After a blank line the block may only
|
|
120351
|
+
// continue on a tag line (`<…`); any markdown island (`**bold**`, `[block:…]`, a
|
|
120352
|
+
// fence) refuses so CommonMark html-flow reparses it exactly as it does today.
|
|
120353
|
+
function plainClaimLineStart(code) {
|
|
120354
|
+
// Leading whitespace only → treat as a blank line, matching CommonMark.
|
|
120355
|
+
if (code === codes.space || code === codes.horizontalTab) {
|
|
120356
|
+
effects.consume(code);
|
|
120357
|
+
return plainClaimLineStart;
|
|
120358
|
+
}
|
|
120359
|
+
if (code === null || markdownLineEnding(code)) {
|
|
120360
|
+
pendingBlankLine = true;
|
|
120361
|
+
effects.exit('mdxComponentData');
|
|
120362
|
+
return bodyContinuationStart(code);
|
|
120363
|
+
}
|
|
120364
|
+
// Across a blank line the block only continues onto a markup-only line; a
|
|
120365
|
+
// paragraph that merely starts with a tag must fall back so its markdown
|
|
120366
|
+
// parses and rehype-raw re-nests it into the wrapper.
|
|
120367
|
+
if (pendingBlankLine) {
|
|
120368
|
+
if (code !== codes.lessThan)
|
|
120369
|
+
return nok(code);
|
|
120370
|
+
return effects.check(markupOnlyContinuation, plainClaimContinue, nok)(code);
|
|
120371
|
+
}
|
|
120372
|
+
return bodyLineStart(code);
|
|
120373
|
+
}
|
|
120374
|
+
function plainClaimContinue(code) {
|
|
120375
|
+
pendingBlankLine = false;
|
|
120376
|
+
return bodyLineStart(code);
|
|
120377
|
+
}
|
|
120263
120378
|
// ── Shared lazy continuation failure ───────────────────────────────────
|
|
120264
120379
|
function continuationAfter(code) {
|
|
120265
120380
|
if (code === null) {
|
|
@@ -120290,6 +120405,46 @@ function syntax_tokenizeNonLazyContinuationStart(effects, ok, nok) {
|
|
|
120290
120405
|
return ok(code);
|
|
120291
120406
|
}
|
|
120292
120407
|
}
|
|
120408
|
+
// A markup-only line opens with a tag (`<x`/`</x`) and ends (ignoring trailing
|
|
120409
|
+
// spaces) at a `>`. That distinguishes a structural continuation like
|
|
120410
|
+
// `<span>b</span></div>` from a paragraph like `<b>Note:</b> read *this*`.
|
|
120411
|
+
function tokenizeMarkupOnlyContinuation(effects, ok, nok) {
|
|
120412
|
+
let lastNonSpace = null;
|
|
120413
|
+
return start;
|
|
120414
|
+
function start(code) {
|
|
120415
|
+
// Caller guarantees we are at `<` at the (already de-indented) line start.
|
|
120416
|
+
effects.enter(types_types.data);
|
|
120417
|
+
effects.consume(code);
|
|
120418
|
+
return afterLessThan;
|
|
120419
|
+
}
|
|
120420
|
+
function afterLessThan(code) {
|
|
120421
|
+
if (code === codes.slash) {
|
|
120422
|
+
effects.consume(code);
|
|
120423
|
+
return afterSlash;
|
|
120424
|
+
}
|
|
120425
|
+
return afterSlash(code);
|
|
120426
|
+
}
|
|
120427
|
+
// The `<` (or `</`) must introduce a real tag, not a stray `<` in prose.
|
|
120428
|
+
function afterSlash(code) {
|
|
120429
|
+
if (asciiAlpha(code)) {
|
|
120430
|
+
lastNonSpace = code;
|
|
120431
|
+
effects.consume(code);
|
|
120432
|
+
return scanToLineEnd;
|
|
120433
|
+
}
|
|
120434
|
+
effects.exit(types_types.data);
|
|
120435
|
+
return nok(code);
|
|
120436
|
+
}
|
|
120437
|
+
function scanToLineEnd(code) {
|
|
120438
|
+
if (code === null || markdownLineEnding(code)) {
|
|
120439
|
+
effects.exit(types_types.data);
|
|
120440
|
+
return lastNonSpace === codes.greaterThan ? ok(code) : nok(code);
|
|
120441
|
+
}
|
|
120442
|
+
if (!markdownSpace(code))
|
|
120443
|
+
lastNonSpace = code;
|
|
120444
|
+
effects.consume(code);
|
|
120445
|
+
return scanToLineEnd;
|
|
120446
|
+
}
|
|
120447
|
+
}
|
|
120293
120448
|
/**
|
|
120294
120449
|
* Micromark extension that tokenizes MDX-like components.
|
|
120295
120450
|
*
|
|
@@ -120536,6 +120691,8 @@ const mdxishInlineMdxComponents = () => tree => {
|
|
|
120536
120691
|
|
|
120537
120692
|
|
|
120538
120693
|
|
|
120694
|
+
/** Matches a JSX attribute expression (e.g. `key={i}`) anywhere in a string. */
|
|
120695
|
+
const NESTED_ATTR_EXPRESSION_RE = /[\w-]+\s*=\s*\{/;
|
|
120539
120696
|
/**
|
|
120540
120697
|
* Reduce leading whitespace on all lines just enough to prevent
|
|
120541
120698
|
* remark from treating indented content as code blocks (4+ spaces).
|
|
@@ -120695,10 +120852,16 @@ const mdx_blocks_mdxishMdxComponentBlocks = (opts = {}) => (tree, file) => {
|
|
|
120695
120852
|
// inline, which is how ReadMe's custom components are modeled).
|
|
120696
120853
|
if (!isPascal && parent.type === 'paragraph')
|
|
120697
120854
|
return;
|
|
120698
|
-
// Lowercase HTML tags are
|
|
120699
|
-
//
|
|
120855
|
+
// Lowercase HTML tags are eligible when they (or a descendant tag in their
|
|
120856
|
+
// content, e.g. a `.map()` body returning JSX with `key={i}`) carry a
|
|
120857
|
+
// JSX-expression attribute. Without this, a wrapper `<div>` with only plain
|
|
120858
|
+
// attributes (or none) swallows its whole nested block — including any
|
|
120859
|
+
// `style={{...}}`/`.map()` JSX inside it — as literal HTML text, which
|
|
120860
|
+
// rehype-raw's parse5 pass then garbles (it has no notion of JS expressions).
|
|
120861
|
+
// Plain HTML with no expressions anywhere stays as an html node so
|
|
120700
120862
|
// rehype-raw handles it as normal.
|
|
120701
|
-
|
|
120863
|
+
const hasNestedExpressionAttr = !selfClosing && NESTED_ATTR_EXPRESSION_RE.test(contentAfterTag);
|
|
120864
|
+
if (!isPascal && !hasExpressionAttr(attributes) && !hasNestedExpressionAttr)
|
|
120702
120865
|
return;
|
|
120703
120866
|
const closingTagStr = `</${tag}>`;
|
|
120704
120867
|
// Case 1: Self-closing tag
|
|
@@ -121135,15 +121298,17 @@ const evalExpression = (expression, scope) => {
|
|
|
121135
121298
|
|
|
121136
121299
|
|
|
121137
121300
|
|
|
121301
|
+
/** True for an array containing at least one React element, e.g. the result of `.map()` returning JSX. */
|
|
121302
|
+
const isRenderableElementArray = (value) => Array.isArray(value) && value.some((external_react_default()).isValidElement);
|
|
121138
121303
|
/** Given the type of the expression result, create the corresponding mdast node. */
|
|
121139
121304
|
const createEvaluatedNode = (result, position) => {
|
|
121140
121305
|
if (result === null || result === undefined) {
|
|
121141
121306
|
return { type: 'text', value: '', position };
|
|
121142
121307
|
}
|
|
121143
|
-
else if (external_react_default().isValidElement(result)) {
|
|
121144
|
-
// Convert react elements to
|
|
121145
|
-
// This must come before the object check as
|
|
121146
|
-
return { type: 'html', value: (0,server_node/* renderToStaticMarkup */.qV)(result), position };
|
|
121308
|
+
else if (external_react_default().isValidElement(result) || isRenderableElementArray(result)) {
|
|
121309
|
+
// Convert react elements (or arrays of them, e.g. `.map()` returning JSX) to their HTML
|
|
121310
|
+
// representation. This must come before the object check as both are a subset of it.
|
|
121311
|
+
return { type: 'html', value: (0,server_node/* renderToStaticMarkup */.qV)(external_react_default().createElement((external_react_default()).Fragment, null, result)), position };
|
|
121147
121312
|
}
|
|
121148
121313
|
else if (typeof result === 'object') {
|
|
121149
121314
|
return { type: 'text', value: JSON.stringify(result), position };
|
|
@@ -121183,6 +121348,47 @@ const evaluateExpressions = () => (tree, file) => {
|
|
|
121183
121348
|
};
|
|
121184
121349
|
/* harmony default export */ const evaluate_expressions = (evaluateExpressions);
|
|
121185
121350
|
|
|
121351
|
+
;// ./processor/transform/mdxish/evaluate-style-block-expressions.ts
|
|
121352
|
+
|
|
121353
|
+
|
|
121354
|
+
|
|
121355
|
+
// Matches a standalone `<style ...>{ <expr> }</style>` block — the JSX shape MDX evaluates
|
|
121356
|
+
// (typically a template-literal-wrapped CSS string) but which mdxish otherwise leaves as
|
|
121357
|
+
// literal, invalid-CSS text (see CX-3646).
|
|
121358
|
+
const STYLE_EXPRESSION_RE = /^(<style\b[^>]*>)\s*\{([\s\S]*)\}\s*(<\/style>)$/i;
|
|
121359
|
+
/**
|
|
121360
|
+
* Evaluate the JSX expression wrapping a `<style>` tag's contents (typically a template
|
|
121361
|
+
* literal, e.g. `<style>{\`.foo { color: red; }\`}</style>`) so the tag ends up holding plain
|
|
121362
|
+
* CSS text instead of the literal `{`...`}` wrapper — which the browser treats as invalid CSS
|
|
121363
|
+
* and drops the entire stylesheet for.
|
|
121364
|
+
*
|
|
121365
|
+
* `<style>` is one of CommonMark's "raw text" HTML elements (along with script/pre/textarea):
|
|
121366
|
+
* its contents are captured verbatim as a single `html` mdast node with no inner tokenization,
|
|
121367
|
+
* so this expression never reaches the mdxFlowExpression tokenizer or `evaluateExpressions` —
|
|
121368
|
+
* it has to be matched and evaluated directly against the raw node's string value.
|
|
121369
|
+
*
|
|
121370
|
+
* Must run after `evaluateExports` (needs `file.data.mdxishScope`) and before `remarkRehype`
|
|
121371
|
+
* turns `html` mdast nodes into raw hast strings. Skipped in safeMode.
|
|
121372
|
+
*/
|
|
121373
|
+
const evaluateStyleBlockExpressions = () => (tree, file) => {
|
|
121374
|
+
const scope = { ...file.data.mdxishScope, React: (external_react_default()) };
|
|
121375
|
+
lib_visit(tree, 'html', (node) => {
|
|
121376
|
+
const match = node.value.trim().match(STYLE_EXPRESSION_RE);
|
|
121377
|
+
if (!match)
|
|
121378
|
+
return;
|
|
121379
|
+
const [, openTag, expression, closeTag] = match;
|
|
121380
|
+
try {
|
|
121381
|
+
const css = evalExpression(expression, scope);
|
|
121382
|
+
node.value = `${openTag}${String(css)}${closeTag}`;
|
|
121383
|
+
}
|
|
121384
|
+
catch {
|
|
121385
|
+
// Evaluation failed — leave the node untouched so it round-trips as literal text.
|
|
121386
|
+
}
|
|
121387
|
+
});
|
|
121388
|
+
return tree;
|
|
121389
|
+
};
|
|
121390
|
+
/* harmony default export */ const evaluate_style_block_expressions = (evaluateStyleBlockExpressions);
|
|
121391
|
+
|
|
121186
121392
|
;// ./processor/transform/mdxish/heading-slugs.ts
|
|
121187
121393
|
|
|
121188
121394
|
|
|
@@ -124459,10 +124665,84 @@ function removeJSXComments(content) {
|
|
|
124459
124665
|
return content.replace(JSX_COMMENT_REGEX, '');
|
|
124460
124666
|
}
|
|
124461
124667
|
|
|
124668
|
+
;// ./processor/transform/mdxish/style-object-to-css.ts
|
|
124669
|
+
|
|
124670
|
+
/**
|
|
124671
|
+
* CSS properties React treats as unitless — a bare number stays as-is instead of
|
|
124672
|
+
* getting `px` appended. Mirrors React DOM's `isUnitlessNumber` whitelist.
|
|
124673
|
+
* @see https://github.com/facebook/react/blob/main/packages/react-dom-bindings/src/shared/CSSProperty.js
|
|
124674
|
+
*/
|
|
124675
|
+
const UNITLESS_CSS_PROPERTIES = new Set([
|
|
124676
|
+
'animationIterationCount',
|
|
124677
|
+
'aspectRatio',
|
|
124678
|
+
'borderImageOutset',
|
|
124679
|
+
'borderImageSlice',
|
|
124680
|
+
'borderImageWidth',
|
|
124681
|
+
'boxFlex',
|
|
124682
|
+
'boxFlexGroup',
|
|
124683
|
+
'boxOrdinalGroup',
|
|
124684
|
+
'columnCount',
|
|
124685
|
+
'columns',
|
|
124686
|
+
'flex',
|
|
124687
|
+
'flexGrow',
|
|
124688
|
+
'flexPositive',
|
|
124689
|
+
'flexShrink',
|
|
124690
|
+
'flexNegative',
|
|
124691
|
+
'flexOrder',
|
|
124692
|
+
'gridArea',
|
|
124693
|
+
'gridRow',
|
|
124694
|
+
'gridRowEnd',
|
|
124695
|
+
'gridRowSpan',
|
|
124696
|
+
'gridRowStart',
|
|
124697
|
+
'gridColumn',
|
|
124698
|
+
'gridColumnEnd',
|
|
124699
|
+
'gridColumnSpan',
|
|
124700
|
+
'gridColumnStart',
|
|
124701
|
+
'fontWeight',
|
|
124702
|
+
'lineClamp',
|
|
124703
|
+
'lineHeight',
|
|
124704
|
+
'opacity',
|
|
124705
|
+
'order',
|
|
124706
|
+
'orphans',
|
|
124707
|
+
'tabSize',
|
|
124708
|
+
'widows',
|
|
124709
|
+
'zIndex',
|
|
124710
|
+
'zoom',
|
|
124711
|
+
'fillOpacity',
|
|
124712
|
+
'floodOpacity',
|
|
124713
|
+
'stopOpacity',
|
|
124714
|
+
'strokeDasharray',
|
|
124715
|
+
'strokeDashoffset',
|
|
124716
|
+
'strokeMiterlimit',
|
|
124717
|
+
'strokeOpacity',
|
|
124718
|
+
'strokeWidth',
|
|
124719
|
+
]);
|
|
124720
|
+
/** Convert a camelCase (or CSS custom property) key into its kebab-case CSS name. */
|
|
124721
|
+
const cssPropertyName = (key) => (key.startsWith('--') ? key : key.replace(/[A-Z]/g, m => `-${m.toLowerCase()}`));
|
|
124722
|
+
/** React appends `px` to non-zero numeric values, except unitless and custom properties. */
|
|
124723
|
+
const cssPropertyValue = (key, value) => typeof value === 'number' && value !== 0 && !key.startsWith('--') && !UNITLESS_CSS_PROPERTIES.has(key)
|
|
124724
|
+
? `${value}px`
|
|
124725
|
+
: `${value}`;
|
|
124726
|
+
/**
|
|
124727
|
+
* True for a value that should be serialized as a style object rather than passed through
|
|
124728
|
+
* as an already-CSS string. React elements are excluded since they're valid objects too.
|
|
124729
|
+
*/
|
|
124730
|
+
const style_object_to_css_isPlainObject = (value) => typeof value === 'object' && value !== null && !Array.isArray(value) && !external_react_default().isValidElement(value);
|
|
124731
|
+
/**
|
|
124732
|
+
* Serialize a React-style inline style object (`{ color: "red", fontSize: 12 }`) into a
|
|
124733
|
+
* CSS declaration string (`color:red;font-size:12px`), the shape hast/HTML expects for a
|
|
124734
|
+
* `style` attribute. Empty (`undefined`/`null`/`''`) entries are dropped.
|
|
124735
|
+
*/
|
|
124736
|
+
const styleObjectToCssText = (style) => Object.entries(style)
|
|
124737
|
+
.filter(([, value]) => value !== undefined && value !== null && value !== '')
|
|
124738
|
+
.map(([key, value]) => `${cssPropertyName(key)}:${cssPropertyValue(key, value)}`)
|
|
124739
|
+
.join(';');
|
|
124740
|
+
|
|
124462
124741
|
;// ./processor/transform/mdxish/resolve-deferred-attribute-expression-props.ts
|
|
124463
124742
|
|
|
124464
124743
|
|
|
124465
124744
|
|
|
124745
|
+
|
|
124466
124746
|
/**
|
|
124467
124747
|
* Resolve attribute expressions that `mdxJsxElementHandler` deferred.
|
|
124468
124748
|
*
|
|
@@ -124484,7 +124764,10 @@ const resolveDeferredAttributeExpressionProps = () => (tree, file) => {
|
|
|
124484
124764
|
const properties = node.properties;
|
|
124485
124765
|
Object.entries(deferredExpressions).forEach(([name, source]) => {
|
|
124486
124766
|
try {
|
|
124487
|
-
|
|
124767
|
+
const result = evalExpression(source, scope);
|
|
124768
|
+
// hast/HTML `style` is a plain CSS string; a `style={{...}}` expression evaluates to
|
|
124769
|
+
// a JS object, which must be serialized or it renders as the literal "[object Object]".
|
|
124770
|
+
properties[name] = name === 'style' && style_object_to_css_isPlainObject(result) ? styleObjectToCssText(result) : result;
|
|
124488
124771
|
}
|
|
124489
124772
|
catch {
|
|
124490
124773
|
// Evaluation failed — fall back to the raw expression source so the attribute
|
|
@@ -124804,13 +125087,13 @@ function normalizeTableSeparator(content) {
|
|
|
124804
125087
|
;// ./processor/transform/mdxish/terminate-html-flow-blocks.ts
|
|
124805
125088
|
|
|
124806
125089
|
|
|
125090
|
+
|
|
124807
125091
|
const STANDALONE_HTML_LINE_REGEX = /^(<[a-z][^<>]*>|<\/[a-z][^<>]*>)+\s*$/;
|
|
124808
125092
|
const HTML_LINE_WITH_CONTENT_REGEX = /^<[a-z][^<>]*>.*<\/[a-z][^<>]*>(?:[^<]*)$/;
|
|
124809
|
-
const terminate_html_flow_blocks_TABLE_STRUCTURE_TAGS = ['table', 'thead', 'tbody', 'tfoot', 'tr', 'td', 'th', 'caption', 'colgroup'];
|
|
124810
125093
|
// Tags whose contents must be preserved as is, inserting a blank line after the
|
|
124811
125094
|
// opener corrupts the payload.
|
|
124812
125095
|
// htmlRawNames here refer to <pre>, <textarea>, <script>, <style>
|
|
124813
|
-
const RAW_CONTENT_TAGS = [...htmlRawNames, ...
|
|
125096
|
+
const RAW_CONTENT_TAGS = [...htmlRawNames, ...HTML_TABLE_STRUCTURE_TAGS];
|
|
124814
125097
|
// The `(?=[\s/>])` lookahead avoids false matches on lookalike names like `<script-foo>`.
|
|
124815
125098
|
const RAW_CONTENT_TAG_MATCHERS = RAW_CONTENT_TAGS.map(tag => ({
|
|
124816
125099
|
open: new RegExp(`<${tag}(?=[\\s/>])[^>]*?(?<!/)>`, 'gi'),
|
|
@@ -125608,6 +125891,7 @@ function loadComponents() {
|
|
|
125608
125891
|
|
|
125609
125892
|
|
|
125610
125893
|
|
|
125894
|
+
|
|
125611
125895
|
|
|
125612
125896
|
|
|
125613
125897
|
const defaultTransformers = [
|
|
@@ -125758,6 +126042,7 @@ function mdxish_mdxish(mdContent, opts = {}) {
|
|
|
125758
126042
|
.use(safeMode ? undefined : evaluate_exports) // Evaluate `export const/function` and stash scope on file.data.mdxishScope
|
|
125759
126043
|
.use(remarkBreaks) // Must precede evaluateExpressions to avoid splitting the \n in an evaluated template literal into a <br> node
|
|
125760
126044
|
.use(safeMode ? undefined : evaluate_expressions) // Evaluate self-contained MDX expressions (e.g. `{1+1}`)
|
|
126045
|
+
.use(safeMode ? undefined : evaluate_style_block_expressions) // Evaluate `<style>{`...`}</style>` template literals into plain CSS
|
|
125761
126046
|
.use(variables_code, { variables }) // Resolve <<...>> and {user.*} inside code and inline code nodes
|
|
125762
126047
|
.use(lib_remarkRehype, { allowDangerousHtml: true, handlers: mdxComponentHandlers })
|
|
125763
126048
|
.use(preserveBooleanProperties) // RehypeRaw converts boolean properties to empty strings
|