@readme/markdown 15.4.0 → 15.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/components/Accordion/index.tsx +5 -1
- package/components/Tabs/index.tsx +9 -1
- package/dist/hooks/useRestartAnimatedImages/index.d.ts +14 -0
- package/dist/lib/utils/mdxish/mdxish-expression.d.ts +7 -0
- package/dist/lib/utils/mdxish/mdxish-get-component-name.d.ts +2 -0
- package/dist/main.js +233 -215
- package/dist/main.node.js +233 -215
- package/dist/main.node.js.map +1 -1
- package/dist/processor/compile/list-item.d.ts +2 -2
- package/dist/processor/compile/table-cell-block-markers.d.ts +11 -0
- package/dist/processor/compile/text.d.ts +3 -2
- package/dist/processor/transform/mdxish/evaluate-expressions.d.ts +11 -5
- package/dist/render-fixture.node.js +233 -215
- package/dist/render-fixture.node.js.map +1 -1
- package/package.json +1 -1
- package/dist/processor/transform/mdxish/components/self-closing-blocks.d.ts +0 -21
- package/dist/processor/transform/mdxish/components/snake-case-components.d.ts +0 -28
- package/dist/processor/transform/mdxish/restore-snake-case-component-name.d.ts +0 -12
package/dist/main.js
CHANGED
|
@@ -11423,7 +11423,7 @@ module.exports = function () {
|
|
|
11423
11423
|
|
|
11424
11424
|
/***/ },
|
|
11425
11425
|
|
|
11426
|
-
/***/
|
|
11426
|
+
/***/ 912
|
|
11427
11427
|
(module, __webpack_exports__, __webpack_require__) {
|
|
11428
11428
|
|
|
11429
11429
|
"use strict";
|
|
@@ -11564,6 +11564,63 @@ __webpack_require__.d(util_types_namespaceObject, {
|
|
|
11564
11564
|
// EXTERNAL MODULE: external {"amd":"react","commonjs":"react","commonjs2":"react","root":"React","umd":"react"}
|
|
11565
11565
|
var external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_ = __webpack_require__(1307);
|
|
11566
11566
|
var external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default = /*#__PURE__*/__webpack_require__.n(external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_);
|
|
11567
|
+
;// ./hooks/useRestartAnimatedImages/index.tsx
|
|
11568
|
+
|
|
11569
|
+
/**
|
|
11570
|
+
* GIF is the one extension that implies animation. `.webp` and `.png` (the extension an APNG
|
|
11571
|
+
* ships under) are overwhelmingly static, so matching them would reload far more images than
|
|
11572
|
+
* it rewinds; telling those apart needs the bytes, not the URL.
|
|
11573
|
+
*/
|
|
11574
|
+
const ANIMATED_IMAGE_SRC = /\.gif(\?|#|$)/i;
|
|
11575
|
+
const restartAnimatedImages = (root) => {
|
|
11576
|
+
root?.querySelectorAll('img').forEach(img => {
|
|
11577
|
+
if (!ANIMATED_IMAGE_SRC.test(img.src))
|
|
11578
|
+
return;
|
|
11579
|
+
const { src } = img;
|
|
11580
|
+
// There's no seek API for animated images; reassigning `src` is the only reset
|
|
11581
|
+
img.src = '';
|
|
11582
|
+
img.src = src;
|
|
11583
|
+
});
|
|
11584
|
+
};
|
|
11585
|
+
const useRestartAfterFirstPaint = (revealKey, restart) => {
|
|
11586
|
+
const isFirstRender = (0,external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_.useRef)(true);
|
|
11587
|
+
const latestRestart = (0,external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_.useRef)(restart);
|
|
11588
|
+
latestRestart.current = restart;
|
|
11589
|
+
(0,external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_.useEffect)(() => {
|
|
11590
|
+
if (isFirstRender.current) {
|
|
11591
|
+
isFirstRender.current = false;
|
|
11592
|
+
return;
|
|
11593
|
+
}
|
|
11594
|
+
latestRestart.current();
|
|
11595
|
+
}, [revealKey]);
|
|
11596
|
+
};
|
|
11597
|
+
/**
|
|
11598
|
+
* Restarts GIF playback inside the panel that just became active.
|
|
11599
|
+
*
|
|
11600
|
+
* Tabs keep every panel mounted, so an <img> is never re-created and a GIF is
|
|
11601
|
+
* shown mid-loop (or frozen on its last frame) when its tab is re-selected.
|
|
11602
|
+
*
|
|
11603
|
+
* @returns a ref to attach to each panel element, indexed by tab.
|
|
11604
|
+
*/
|
|
11605
|
+
function useRestartAnimatedImages(activeIndex) {
|
|
11606
|
+
const panelRefs = (0,external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_.useRef)([]);
|
|
11607
|
+
useRestartAfterFirstPaint(activeIndex, () => restartAnimatedImages(panelRefs.current[activeIndex]));
|
|
11608
|
+
return panelRefs;
|
|
11609
|
+
}
|
|
11610
|
+
/**
|
|
11611
|
+
* Restarts GIF playback inside an element that has just been revealed after being hidden —
|
|
11612
|
+
* a collapsed <details>, whose images have been animating out of sight since page load.
|
|
11613
|
+
*/
|
|
11614
|
+
function useRestartAnimatedImagesOnReveal(isRevealed) {
|
|
11615
|
+
const contentRef = (0,external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_.useRef)(null);
|
|
11616
|
+
useRestartAfterFirstPaint(isRevealed, () => {
|
|
11617
|
+
// Rewinding content the reader just hid would be wasted work
|
|
11618
|
+
if (isRevealed)
|
|
11619
|
+
restartAnimatedImages(contentRef.current);
|
|
11620
|
+
});
|
|
11621
|
+
return contentRef;
|
|
11622
|
+
}
|
|
11623
|
+
|
|
11567
11624
|
;// ./components/Icon/index.tsx
|
|
11568
11625
|
|
|
11569
11626
|
/** @see https://docs-v5.fontawesome.com/web/reference-icons */
|
|
@@ -11588,14 +11645,16 @@ const Icon = ({ className, faClassName, icon, iconColor }) => {
|
|
|
11588
11645
|
|
|
11589
11646
|
|
|
11590
11647
|
|
|
11648
|
+
|
|
11591
11649
|
const Accordion = ({ children, icon, iconColor, title }) => {
|
|
11592
11650
|
const [isOpen, setIsOpen] = (0,external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_.useState)(false);
|
|
11651
|
+
const contentRef = useRestartAnimatedImagesOnReveal(isOpen);
|
|
11593
11652
|
return (external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default().createElement("details", { className: "Accordion", onToggle: () => setIsOpen(!isOpen) },
|
|
11594
11653
|
external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default().createElement("summary", { className: "Accordion-title" },
|
|
11595
11654
|
external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default().createElement("i", { className: `Accordion-toggleIcon${isOpen ? '_opened' : ''} fa fa-regular fa-chevron-right` }),
|
|
11596
11655
|
icon && external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default().createElement(components_Icon, { className: "Accordion-icon", icon: icon, iconColor: iconColor }),
|
|
11597
11656
|
title),
|
|
11598
|
-
external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default().createElement("div", { className: "Accordion-content" }, children)));
|
|
11657
|
+
external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default().createElement("div", { ref: contentRef, className: "Accordion-content" }, children)));
|
|
11599
11658
|
};
|
|
11600
11659
|
/* harmony default export */ const components_Accordion = (Accordion);
|
|
11601
11660
|
|
|
@@ -12495,11 +12554,13 @@ function TableOfContents({ children }) {
|
|
|
12495
12554
|
|
|
12496
12555
|
|
|
12497
12556
|
|
|
12557
|
+
|
|
12498
12558
|
const Tab = ({ children }) => {
|
|
12499
12559
|
return external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default().createElement("div", { className: "TabContent" }, children);
|
|
12500
12560
|
};
|
|
12501
12561
|
const Tabs = ({ children }) => {
|
|
12502
12562
|
const [activeTab, setActiveTab] = (0,external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_.useState)(0);
|
|
12563
|
+
const panelRefs = useRestartAnimatedImages(activeTab);
|
|
12503
12564
|
// React passes `children` as a single element when there's only one child, so normalize.
|
|
12504
12565
|
const tabs = external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default().Children.toArray(children);
|
|
12505
12566
|
return (external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default().createElement("div", { className: "TabGroup" },
|
|
@@ -12507,7 +12568,9 @@ const Tabs = ({ children }) => {
|
|
|
12507
12568
|
external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default().createElement("nav", { className: "TabGroup-nav" }, tabs.map((tab, index) => (external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default().createElement("button", { key: tab.key, className: `TabGroup-tab${activeTab === index ? '_active' : ''}`, onClick: () => setActiveTab(index) },
|
|
12508
12569
|
tab.props.icon && (external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default().createElement(components_Icon, { className: "TabGroup-icon", icon: tab.props.icon, iconColor: tab.props.iconColor })),
|
|
12509
12570
|
tab.props.title))))),
|
|
12510
|
-
external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default().createElement("section", null, tabs.map((tab, index) => (external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default().createElement("div", { key: tab.key,
|
|
12571
|
+
external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default().createElement("section", null, tabs.map((tab, index) => (external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default().createElement("div", { key: tab.key, ref: el => {
|
|
12572
|
+
panelRefs.current[index] = el;
|
|
12573
|
+
}, hidden: index !== activeTab }, tab))))));
|
|
12511
12574
|
};
|
|
12512
12575
|
/* harmony default export */ const components_Tabs = (Tabs);
|
|
12513
12576
|
|
|
@@ -76390,6 +76453,10 @@ function syntax_createTokenize(mode) {
|
|
|
76390
76453
|
effects.consume(code);
|
|
76391
76454
|
return inBraceExpr;
|
|
76392
76455
|
}
|
|
76456
|
+
// A raw `<` can't sit in an opening tag (quotes/braces are handled above);
|
|
76457
|
+
// bailing bounds each attempt to the next `<` instead of rescanning the line.
|
|
76458
|
+
if (code === codes.lessThan)
|
|
76459
|
+
return nok(code);
|
|
76393
76460
|
effects.consume(code);
|
|
76394
76461
|
return afterOpenTagName;
|
|
76395
76462
|
}
|
|
@@ -101596,7 +101663,7 @@ const listMarkerRegex = /^(?:[*+-]|\d+[.)])(?:([\r\n]| {1,3})|$)/;
|
|
|
101596
101663
|
* with their checkbox intact (for example, `- [ ]`) instead of dropping it
|
|
101597
101664
|
* We can add more adjustments if needed
|
|
101598
101665
|
*/
|
|
101599
|
-
const compile_list_item_listItem = (node, parent, state, info) => {
|
|
101666
|
+
const compile_list_item_listItem = ((node, parent, state, info) => {
|
|
101600
101667
|
const head = node.children[0];
|
|
101601
101668
|
const isCheckbox = typeof node.checked === 'boolean' && head && head.type === 'paragraph';
|
|
101602
101669
|
if (!isCheckbox) {
|
|
@@ -101620,15 +101687,47 @@ const compile_list_item_listItem = (node, parent, state, info) => {
|
|
|
101620
101687
|
return `${marker}${actualSeparator}${checkbox}`;
|
|
101621
101688
|
});
|
|
101622
101689
|
return value;
|
|
101623
|
-
};
|
|
101690
|
+
});
|
|
101624
101691
|
/* harmony default export */ const list_item = (compile_list_item_listItem);
|
|
101625
101692
|
|
|
101626
101693
|
;// ./processor/compile/plain.ts
|
|
101627
101694
|
const plain_plain = (node) => node.value;
|
|
101628
101695
|
/* harmony default export */ const compile_plain = (plain_plain);
|
|
101629
101696
|
|
|
101697
|
+
;// ./processor/compile/table-cell-block-markers.ts
|
|
101698
|
+
const CELL_START_BLOCK_MARKER = /^(?:[-+](?=\s|$)|#{1,6}(?=\s|$)|>)/;
|
|
101699
|
+
const BR_HTML = /^\s*<br\s*\/?>\s*$/i;
|
|
101700
|
+
const isLineBreak = (node) => {
|
|
101701
|
+
if (node.type === 'break')
|
|
101702
|
+
return true;
|
|
101703
|
+
if (node.type === 'html')
|
|
101704
|
+
return BR_HTML.test(node.value);
|
|
101705
|
+
return node.type === 'mdxJsxTextElement' && 'name' in node && node.name?.toLowerCase() === 'br';
|
|
101706
|
+
};
|
|
101707
|
+
const followsLineBreak = (node, parent) => {
|
|
101708
|
+
const siblings = (parent?.children ?? []);
|
|
101709
|
+
const previous = siblings[siblings.indexOf(node) - 1];
|
|
101710
|
+
return !!previous && isLineBreak(previous);
|
|
101711
|
+
};
|
|
101712
|
+
/**
|
|
101713
|
+
* Re-escapes a leading block marker (`-`, `+`, `#`, `>`) at the start of a table cell, or
|
|
101714
|
+
* after a `<br />` within one.
|
|
101715
|
+
*
|
|
101716
|
+
* A cell is serialized mid-line, so the `atBreak` patterns that escape these characters
|
|
101717
|
+
* never fire and an author's `| \- one |` round trips to `| - one |` (RM-17203). Cells are
|
|
101718
|
+
* serialized as `containerPhrasing(cell, { before: '|' })`, so `|` marks the cell start.
|
|
101719
|
+
*/
|
|
101720
|
+
const escapeCellStartBlockMarker = (serialized, node, parent, state, info) => {
|
|
101721
|
+
if (serialized.startsWith('\\') || !CELL_START_BLOCK_MARKER.test(serialized))
|
|
101722
|
+
return serialized;
|
|
101723
|
+
if (!state.stack.includes('tableCell') || !(info.before === '|' || followsLineBreak(node, parent)))
|
|
101724
|
+
return serialized;
|
|
101725
|
+
return `\\${serialized}`;
|
|
101726
|
+
};
|
|
101727
|
+
|
|
101630
101728
|
;// ./processor/compile/text.ts
|
|
101631
101729
|
|
|
101730
|
+
|
|
101632
101731
|
// A `_` flanked by word characters can never open or close emphasis under
|
|
101633
101732
|
// CommonMark's flanking rules, so the escape mdast-util-to-markdown adds to
|
|
101634
101733
|
// intraword underscores is unnecessary and only produces noisy `\_` diffs.
|
|
@@ -101636,9 +101735,10 @@ const plain_plain = (node) => node.value;
|
|
|
101636
101735
|
const INTRAWORD_UNDERSCORE_ESCAPE = /(?<=[\p{L}\p{N}_])\\_(?=[\p{L}\p{N}_]|\\_)/gu;
|
|
101637
101736
|
const compile_text_text = (node, parent, state, info) => {
|
|
101638
101737
|
const serialized = handle.text(node, parent, state, info);
|
|
101639
|
-
return serialized
|
|
101738
|
+
return escapeCellStartBlockMarker(serialized, node, parent, state, info);
|
|
101640
101739
|
};
|
|
101641
|
-
|
|
101740
|
+
const mdxishText = (node, parent, state, info) => compile_text_text(node, parent, state, info).replace(INTRAWORD_UNDERSCORE_ESCAPE, '_');
|
|
101741
|
+
/* harmony default export */ const compile_text = (mdxishText);
|
|
101642
101742
|
|
|
101643
101743
|
;// ./processor/compile/index.ts
|
|
101644
101744
|
|
|
@@ -101670,6 +101770,7 @@ function compilers(mdxish = false) {
|
|
|
101670
101770
|
html: compile_compatibility,
|
|
101671
101771
|
i: compile_compatibility,
|
|
101672
101772
|
plain: compile_plain,
|
|
101773
|
+
text: compile_text_text,
|
|
101673
101774
|
yaml: compile_compatibility,
|
|
101674
101775
|
// needed only for mdxish
|
|
101675
101776
|
...(mdxish && { list: compile_list }),
|
|
@@ -103738,13 +103839,14 @@ function restoreCodeBlocks(content, protectedCode) {
|
|
|
103738
103839
|
*
|
|
103739
103840
|
* The attribute portion skips over quoted strings (`"..."` and `'...'`) so that
|
|
103740
103841
|
* a `/>` inside an attribute value (e.g. `title="use /> here"`) does not cause
|
|
103741
|
-
* a premature match
|
|
103842
|
+
* a premature match, and stops at an unquoted `<` so a stray `<x` in prose
|
|
103843
|
+
* doesn't scan to the end of the document (quadratic).
|
|
103742
103844
|
*
|
|
103743
103845
|
* Only matches lowercase tag names to avoid interfering with PascalCase
|
|
103744
103846
|
* JSX custom components (e.g. `<MyComponent />`), which are handled
|
|
103745
103847
|
* separately by components/mdx-blocks.
|
|
103746
103848
|
*/
|
|
103747
|
-
const SELF_CLOSING_TAG_RE = /<([a-z][a-z0-9-]*)((?:\s+(?:[
|
|
103849
|
+
const SELF_CLOSING_TAG_RE = /<([a-z][a-z0-9-]*)((?:\s+(?:[^<>"']*(?:"[^"]*"|'[^']*'))*[^<>"']*)?)?\s*\/>/g;
|
|
103748
103850
|
/**
|
|
103749
103851
|
* String-level preprocessor that converts self-closing non-void HTML tags
|
|
103750
103852
|
* into explicitly closed tags.
|
|
@@ -104409,8 +104511,9 @@ function terminateHtmlFlowBlocks(content) {
|
|
|
104409
104511
|
|
|
104410
104512
|
|
|
104411
104513
|
|
|
104412
|
-
// Matches a JSX attribute expression (e.g. `key={i}`) anywhere in a string.
|
|
104413
|
-
|
|
104514
|
+
// Matches a JSX attribute expression (e.g. `key={i}`) anywhere in a string. One name
|
|
104515
|
+
// char suffices for existence — `[\w-]+` backtracked quadratically over huge attributes.
|
|
104516
|
+
const NESTED_ATTR_EXPRESSION_RE = /[\w-]\s*=\s*\{/;
|
|
104414
104517
|
// Name shape mirrors `componentTagPattern`; the lookbehind skips the inner tag
|
|
104415
104518
|
// of a legacy `<<VARIABLE>>`.
|
|
104416
104519
|
const NESTED_COMPONENT_TAG_RE = /(?<!<)<([A-Z][A-Za-z0-9_]*)[\s/>]/g;
|
|
@@ -104709,150 +104812,6 @@ const mdxishMdxComponentBlocks = (opts = {}) => (tree, file) => {
|
|
|
104709
104812
|
};
|
|
104710
104813
|
/* harmony default export */ const mdx_blocks = (mdxishMdxComponentBlocks);
|
|
104711
104814
|
|
|
104712
|
-
;// ./processor/transform/mdxish/components/self-closing-blocks.ts
|
|
104713
|
-
|
|
104714
|
-
|
|
104715
|
-
/**
|
|
104716
|
-
* Tags to process as self-closing blocks.
|
|
104717
|
-
* These components use simple string attributes (no JSX expressions like `data={[...]}`).
|
|
104718
|
-
* Components with JSX expression attributes should NOT be added here as parseAttributes
|
|
104719
|
-
* cannot handle them correctly.
|
|
104720
|
-
*/
|
|
104721
|
-
const SELF_CLOSING_BLOCK_TAGS = new Set(['Embed', 'Recipe']);
|
|
104722
|
-
// Regex to match self-closing PascalCase tags (handles multi-line)
|
|
104723
|
-
const selfClosingTagPattern = /^<([A-Z][A-Za-z0-9_]*)([\s\S]*?)\/>$/;
|
|
104724
|
-
/**
|
|
104725
|
-
* Try to convert a paragraph node containing a self-closing JSX component into an mdxJsxFlowElement.
|
|
104726
|
-
* Returns the new node if conversion succeeded, or null if the node doesn't match.
|
|
104727
|
-
*/
|
|
104728
|
-
const tryConvertToMdxNode = (node) => {
|
|
104729
|
-
if (node.children.length !== 1)
|
|
104730
|
-
return null;
|
|
104731
|
-
const child = node.children[0];
|
|
104732
|
-
if (child.type !== 'html')
|
|
104733
|
-
return null;
|
|
104734
|
-
const value = child.value?.trim();
|
|
104735
|
-
if (!value)
|
|
104736
|
-
return null;
|
|
104737
|
-
const match = value.match(selfClosingTagPattern);
|
|
104738
|
-
if (!match)
|
|
104739
|
-
return null;
|
|
104740
|
-
const [, tag, attrString] = match;
|
|
104741
|
-
if (!SELF_CLOSING_BLOCK_TAGS.has(tag))
|
|
104742
|
-
return null;
|
|
104743
|
-
return {
|
|
104744
|
-
type: 'mdxJsxFlowElement',
|
|
104745
|
-
name: tag,
|
|
104746
|
-
attributes: parseAttributes(attrString),
|
|
104747
|
-
children: [],
|
|
104748
|
-
position: node.position,
|
|
104749
|
-
};
|
|
104750
|
-
};
|
|
104751
|
-
/**
|
|
104752
|
-
* Transform paragraph-wrapped self-closing JSX components into mdxJsxFlowElement nodes.
|
|
104753
|
-
*
|
|
104754
|
-
* CommonMark wraps multi-line JSX in paragraphs when the opening tag isn't complete
|
|
104755
|
-
* on one line. This plugin detects these structures and unwraps them for components
|
|
104756
|
-
* in the SELF_CLOSING_BLOCK_TAGS allowlist.
|
|
104757
|
-
*
|
|
104758
|
-
* Input structure:
|
|
104759
|
-
* ```
|
|
104760
|
-
* paragraph > html: "<Embed\n typeOfEmbed=\"youtube\"\n/>"
|
|
104761
|
-
* ```
|
|
104762
|
-
*
|
|
104763
|
-
* Output structure:
|
|
104764
|
-
* ```
|
|
104765
|
-
* mdxJsxFlowElement: { name: "Embed", attributes: [...], children: [] }
|
|
104766
|
-
* ```
|
|
104767
|
-
*/
|
|
104768
|
-
const mdxishSelfClosingBlocks = () => tree => {
|
|
104769
|
-
visit(tree, 'paragraph', (node, index, parent) => {
|
|
104770
|
-
if (index === undefined || !parent)
|
|
104771
|
-
return;
|
|
104772
|
-
const mdxNode = tryConvertToMdxNode(node);
|
|
104773
|
-
if (mdxNode) {
|
|
104774
|
-
parent.children.splice(index, 1, mdxNode);
|
|
104775
|
-
}
|
|
104776
|
-
});
|
|
104777
|
-
};
|
|
104778
|
-
/* harmony default export */ const self_closing_blocks = (mdxishSelfClosingBlocks);
|
|
104779
|
-
|
|
104780
|
-
;// ./processor/transform/mdxish/components/snake-case-components.ts
|
|
104781
|
-
|
|
104782
|
-
|
|
104783
|
-
/**
|
|
104784
|
-
* Replaces snake_case component names with valid HTML placeholders.
|
|
104785
|
-
* Required because remark-parse rejects tags with underscores.
|
|
104786
|
-
* Example: `<Snake_case />` → `<MDXishSnakeCase0 />`
|
|
104787
|
-
*
|
|
104788
|
-
* Code blocks and inline code are protected and will not be transformed.
|
|
104789
|
-
*
|
|
104790
|
-
* @param content - The markdown content to process
|
|
104791
|
-
* @param options - Options including knownComponents to filter by
|
|
104792
|
-
*/
|
|
104793
|
-
function processSnakeCaseComponent(content, options = {}) {
|
|
104794
|
-
const { knownComponents } = options;
|
|
104795
|
-
// Early exit if no potential snake_case components
|
|
104796
|
-
if (!/[A-Z][A-Za-z0-9]*_[A-Za-z0-9_]*/.test(content)) {
|
|
104797
|
-
return { content, mapping: {} };
|
|
104798
|
-
}
|
|
104799
|
-
// Step 1: Extract code blocks to protect them from transformation
|
|
104800
|
-
const { protectedCode, protectedContent } = protectCodeBlocks(content);
|
|
104801
|
-
// Find the highest existing placeholder number to avoid collisions
|
|
104802
|
-
// e.g., if content has <MDXishSnakeCase0 />, start counter from 1
|
|
104803
|
-
const placeholderPattern = /MDXishSnakeCase(\d+)/g;
|
|
104804
|
-
let startCounter = 0;
|
|
104805
|
-
let placeholderMatch;
|
|
104806
|
-
while ((placeholderMatch = placeholderPattern.exec(content)) !== null) {
|
|
104807
|
-
const num = parseInt(placeholderMatch[1], 10);
|
|
104808
|
-
if (num >= startCounter) {
|
|
104809
|
-
startCounter = num + 1;
|
|
104810
|
-
}
|
|
104811
|
-
}
|
|
104812
|
-
const mapping = {};
|
|
104813
|
-
const reverseMap = new Map();
|
|
104814
|
-
let counter = startCounter;
|
|
104815
|
-
// Step 2: Transform snake_case components in non-code content
|
|
104816
|
-
const processedContent = protectedContent.replace(componentTagPattern, (match, tagName, attrs, selfClosing) => {
|
|
104817
|
-
if (!tagName.includes('_')) {
|
|
104818
|
-
return match;
|
|
104819
|
-
}
|
|
104820
|
-
const isClosing = tagName.startsWith('/');
|
|
104821
|
-
const cleanTagName = isClosing ? tagName.slice(1) : tagName;
|
|
104822
|
-
// Only transform if it's a known component (or if no filter is provided)
|
|
104823
|
-
if (knownComponents && !knownComponents.has(cleanTagName)) {
|
|
104824
|
-
return match;
|
|
104825
|
-
}
|
|
104826
|
-
let placeholder = reverseMap.get(cleanTagName);
|
|
104827
|
-
if (!placeholder) {
|
|
104828
|
-
// eslint-disable-next-line no-plusplus
|
|
104829
|
-
placeholder = `MDXishSnakeCase${counter++}`;
|
|
104830
|
-
mapping[placeholder] = cleanTagName;
|
|
104831
|
-
reverseMap.set(cleanTagName, placeholder);
|
|
104832
|
-
}
|
|
104833
|
-
const processedTagName = isClosing ? `/${placeholder}` : placeholder;
|
|
104834
|
-
return `<${processedTagName}${attrs}${selfClosing}>`;
|
|
104835
|
-
});
|
|
104836
|
-
// Step 3: Restore code blocks (untouched)
|
|
104837
|
-
const finalContent = restoreCodeBlocks(processedContent, protectedCode);
|
|
104838
|
-
return {
|
|
104839
|
-
content: finalContent,
|
|
104840
|
-
mapping,
|
|
104841
|
-
};
|
|
104842
|
-
}
|
|
104843
|
-
/**
|
|
104844
|
-
* Restores placeholder name to original snake_case name.
|
|
104845
|
-
* Uses case-insensitive matching since HTML parsers normalize to lowercase.
|
|
104846
|
-
*/
|
|
104847
|
-
function restoreSnakeCase(placeholderName, mapping) {
|
|
104848
|
-
if (mapping[placeholderName]) {
|
|
104849
|
-
return mapping[placeholderName];
|
|
104850
|
-
}
|
|
104851
|
-
const lowerName = placeholderName.toLowerCase();
|
|
104852
|
-
const matchingKey = Object.keys(mapping).find(key => key.toLowerCase() === lowerName);
|
|
104853
|
-
return matchingKey ? mapping[matchingKey] : placeholderName;
|
|
104854
|
-
}
|
|
104855
|
-
|
|
104856
104815
|
;// ./processor/transform/mdxish/resolve-esm-imports.ts
|
|
104857
104816
|
|
|
104858
104817
|
// We provide React as a default module so that components can use hooks
|
|
@@ -105037,6 +104996,54 @@ const containsJsxNode = (value) => {
|
|
|
105037
104996
|
return true;
|
|
105038
104997
|
return Object.values(value).some(containsJsxNode);
|
|
105039
104998
|
};
|
|
104999
|
+
/** Read the component name off a JSX element name node (`Foo`, `Foo.Bar`, `foo:Bar`). */
|
|
105000
|
+
const jsxElementName = (name) => {
|
|
105001
|
+
if (name === null || typeof name !== 'object')
|
|
105002
|
+
return undefined;
|
|
105003
|
+
const node = name;
|
|
105004
|
+
if (node.type === 'JSXIdentifier')
|
|
105005
|
+
return typeof node.name === 'string' ? node.name : undefined;
|
|
105006
|
+
// `<Foo.Bar/>` and `<foo:Bar/>` resolve through their leftmost part.
|
|
105007
|
+
if (node.type === 'JSXMemberExpression')
|
|
105008
|
+
return jsxElementName(node.object);
|
|
105009
|
+
if (node.type === 'JSXNamespacedName')
|
|
105010
|
+
return jsxElementName(node.namespace);
|
|
105011
|
+
return undefined;
|
|
105012
|
+
};
|
|
105013
|
+
/**
|
|
105014
|
+
* Collect the capitalized names an expression uses as JSX tags. Parsed rather than pattern
|
|
105015
|
+
* matched: `{count < Max ? <Foo/> : <Bar/>}` puts a capitalized name straight after a `<` without
|
|
105016
|
+
* it being a tag, and only the parser can tell the two apart. Unparseable input yields nothing —
|
|
105017
|
+
* evaluation is about to throw on it anyway.
|
|
105018
|
+
*/
|
|
105019
|
+
const jsxComponentNames = (expression) => {
|
|
105020
|
+
let program;
|
|
105021
|
+
try {
|
|
105022
|
+
program = parseExpression(expression);
|
|
105023
|
+
}
|
|
105024
|
+
catch {
|
|
105025
|
+
return [];
|
|
105026
|
+
}
|
|
105027
|
+
const names = new Set();
|
|
105028
|
+
const walk = (value) => {
|
|
105029
|
+
if (Array.isArray(value)) {
|
|
105030
|
+
value.forEach(walk);
|
|
105031
|
+
return;
|
|
105032
|
+
}
|
|
105033
|
+
if (value === null || typeof value !== 'object')
|
|
105034
|
+
return;
|
|
105035
|
+
const node = value;
|
|
105036
|
+
if (node.type === 'JSXOpeningElement') {
|
|
105037
|
+
const name = jsxElementName(node.name);
|
|
105038
|
+
// Lowercase tags compile to a string type, never a variable reference.
|
|
105039
|
+
if (name && /^[A-Z]/.test(name))
|
|
105040
|
+
names.add(name);
|
|
105041
|
+
}
|
|
105042
|
+
Object.values(node).forEach(walk);
|
|
105043
|
+
};
|
|
105044
|
+
walk(program);
|
|
105045
|
+
return Array.from(names);
|
|
105046
|
+
};
|
|
105040
105047
|
/** Convert a program's JSX into `React.createElement` calls and evaluate it. `scope` must provide `React`. */
|
|
105041
105048
|
const evalJsxProgram = (program, scope) => {
|
|
105042
105049
|
buildJsx(program, { runtime: 'classic', pragma: 'React.createElement', pragmaFrag: 'React.Fragment' });
|
|
@@ -105242,6 +105249,28 @@ function reactElementToHast(node) {
|
|
|
105242
105249
|
|
|
105243
105250
|
|
|
105244
105251
|
|
|
105252
|
+
|
|
105253
|
+
|
|
105254
|
+
|
|
105255
|
+
|
|
105256
|
+
/**
|
|
105257
|
+
* Bind the components a given expression actually uses as tags. Scoped per expression on purpose:
|
|
105258
|
+
* binding the whole hash would shadow same-named globals (a `math` component would break
|
|
105259
|
+
* `{Math.max(1, 2)}`) and pad `evaluate`'s `new Function` parameter list. Resolution defers to
|
|
105260
|
+
* `getComponentName` so an expression and a plain tag always reach the same component.
|
|
105261
|
+
*/
|
|
105262
|
+
const componentScope = (expression, components) => {
|
|
105263
|
+
const scope = {};
|
|
105264
|
+
jsxComponentNames(expression).forEach(name => {
|
|
105265
|
+
// `getComponentName` normalizes the tag, never the key, so it can't match `<MyBlock/>` to a
|
|
105266
|
+
// `my_block` entry; compare the key's PascalCase form for that direction.
|
|
105267
|
+
const tagName = getComponentName(name, components) ?? Object.keys(components).find(k => toPascalCase(k) === name);
|
|
105268
|
+
if (!tagName)
|
|
105269
|
+
return;
|
|
105270
|
+
scope[name] = (props) => external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default().createElement(tagName, props);
|
|
105271
|
+
});
|
|
105272
|
+
return scope;
|
|
105273
|
+
};
|
|
105245
105274
|
/**
|
|
105246
105275
|
* We divide the result of an expression into two categories:
|
|
105247
105276
|
* 1. Renderable values: HTML, JSX, e.g. .map() returning JSX
|
|
@@ -105252,6 +105281,17 @@ const isRenderable = (value) => {
|
|
|
105252
105281
|
return true;
|
|
105253
105282
|
return Array.isArray(value) && value.some(isRenderable);
|
|
105254
105283
|
};
|
|
105284
|
+
/**
|
|
105285
|
+
* Whether an expression evaluated to block-level content. Components count as block-level
|
|
105286
|
+
* unless they're on the inline list, matching the assumption the rest of the component
|
|
105287
|
+
* pipeline makes.
|
|
105288
|
+
*/
|
|
105289
|
+
const isBlockResult = (children) => children.some(child => {
|
|
105290
|
+
if (child.type !== 'element' && child.type !== 'mdx-jsx')
|
|
105291
|
+
return false;
|
|
105292
|
+
const { tagName } = child;
|
|
105293
|
+
return !STANDARD_HTML_TAGS.has(tagName.toLowerCase()) && !INLINE_COMPONENT_TAGS.has(tagName);
|
|
105294
|
+
});
|
|
105255
105295
|
/** Turn a non-renderable evaluation result into a text node. */
|
|
105256
105296
|
const createTextNode = (result, position) => {
|
|
105257
105297
|
if (result === null || result === undefined)
|
|
@@ -105263,13 +105303,22 @@ const createTextNode = (result, position) => {
|
|
|
105263
105303
|
/**
|
|
105264
105304
|
* AST transformer to evaluate MDX expressions.
|
|
105265
105305
|
* Replaces mdxFlowExpression and mdxTextExpression nodes with their evaluated values.
|
|
105266
|
-
* Self-contained expressions resolve directly (e.g. `{1+1}`); expressions that
|
|
105267
|
-
*
|
|
105268
|
-
* earlier `export const/function` (collected onto
|
|
105269
|
-
* Anything else falls through to the error branch and is kept as
|
|
105270
|
-
|
|
105271
|
-
|
|
105272
|
-
|
|
105306
|
+
* Self-contained expressions resolve directly (e.g. `{1+1}`); expressions that reference
|
|
105307
|
+
* identifiers can resolve if those identifiers are a custom component, the `user` variables
|
|
105308
|
+
* object, or were introduced by an earlier `export const/function` (collected onto
|
|
105309
|
+
* `file.data.mdxishScope`). Anything else falls through to the error branch and is kept as
|
|
105310
|
+
* literal `{...}` text.
|
|
105311
|
+
*/
|
|
105312
|
+
const evaluateExpressions = ({ components, variables } = {}) => (tree, file) => {
|
|
105313
|
+
const baseScope = {
|
|
105314
|
+
// `User` matches the fallback the MDX path binds in `run.tsx`. Only when variables were
|
|
105315
|
+
// supplied: the proxy never throws, so an unconditional bind would resolve `user.*` on
|
|
105316
|
+
// surfaces that render without them instead of leaving literal text.
|
|
105317
|
+
...(variables ? { user: user(variables) } : {}),
|
|
105318
|
+
// In-document exports win, matching `renderMdxish`.
|
|
105319
|
+
...file.data.mdxishScope,
|
|
105320
|
+
React: (external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default()),
|
|
105321
|
+
};
|
|
105273
105322
|
visit(tree, ['mdxFlowExpression', 'mdxTextExpression'], (node, index, parent) => {
|
|
105274
105323
|
if (!parent || index === null || index === undefined)
|
|
105275
105324
|
return;
|
|
@@ -105279,6 +105328,7 @@ const evaluateExpressions = () => (tree, file) => {
|
|
|
105279
105328
|
if (!expression)
|
|
105280
105329
|
return;
|
|
105281
105330
|
try {
|
|
105331
|
+
const scope = { ...componentScope(expression, components ?? {}), ...baseScope };
|
|
105282
105332
|
const result = evalExpression(expression, scope);
|
|
105283
105333
|
if (isRenderable(result)) {
|
|
105284
105334
|
// Stash hast built straight from the React tree; `mdxExpressionHandler` emits it and it
|
|
@@ -105299,6 +105349,22 @@ const evaluateExpressions = () => (tree, file) => {
|
|
|
105299
105349
|
parent.children.splice(index, 1, { type: 'text', value: `{${processed}}`, position });
|
|
105300
105350
|
}
|
|
105301
105351
|
});
|
|
105352
|
+
// A text expression is parsed inside a paragraph, but its result can be block content: a
|
|
105353
|
+
// `<Tabs>` renders a `<div>`, and a browser closes the `<p>` before it, so the DOM it builds
|
|
105354
|
+
// no longer matches what was rendered and hydration fails. Lift the expression out when
|
|
105355
|
+
// that's all the paragraph holds.
|
|
105356
|
+
visit(tree, 'paragraph', (node, index, parent) => {
|
|
105357
|
+
if (!parent || index === null || index === undefined)
|
|
105358
|
+
return;
|
|
105359
|
+
const meaningful = node.children.filter(child => !(child.type === 'text' && !child.value.trim()));
|
|
105360
|
+
const [only] = meaningful;
|
|
105361
|
+
if (meaningful.length !== 1 || only.type !== 'mdxTextExpression')
|
|
105362
|
+
return;
|
|
105363
|
+
const hChildren = only.data?.hChildren;
|
|
105364
|
+
if (!hChildren || !isBlockResult(hChildren))
|
|
105365
|
+
return;
|
|
105366
|
+
parent.children.splice(index, 1, only);
|
|
105367
|
+
});
|
|
105302
105368
|
return tree;
|
|
105303
105369
|
};
|
|
105304
105370
|
/* harmony default export */ const evaluate_expressions = (evaluateExpressions);
|
|
@@ -107106,45 +107172,6 @@ const resolveDeferredAttributeExpressionProps = () => (tree, file) => {
|
|
|
107106
107172
|
};
|
|
107107
107173
|
/* harmony default export */ const resolve_deferred_attribute_expression_props = (resolveDeferredAttributeExpressionProps);
|
|
107108
107174
|
|
|
107109
|
-
;// ./processor/transform/mdxish/restore-snake-case-component-name.ts
|
|
107110
|
-
|
|
107111
|
-
|
|
107112
|
-
/**
|
|
107113
|
-
* Restores snake_case component names from placeholders after parsing.
|
|
107114
|
-
* Runs after mdxishComponentBlocks converts HTML nodes to mdxJsxFlowElement.
|
|
107115
|
-
*/
|
|
107116
|
-
const restoreSnakeCaseComponentNames = (options) => {
|
|
107117
|
-
const { mapping } = options;
|
|
107118
|
-
return tree => {
|
|
107119
|
-
if (!mapping || Object.keys(mapping).length === 0) {
|
|
107120
|
-
return tree;
|
|
107121
|
-
}
|
|
107122
|
-
visit(tree, 'mdxJsxFlowElement', (node) => {
|
|
107123
|
-
if (node.name) {
|
|
107124
|
-
node.name = restoreSnakeCase(node.name, mapping);
|
|
107125
|
-
}
|
|
107126
|
-
});
|
|
107127
|
-
// Pre-compile regex patterns for better performance
|
|
107128
|
-
const regexPatterns = Object.entries(mapping).map(([placeholder, original]) => ({
|
|
107129
|
-
regex: new RegExp(`(<\\/?)(${placeholder})(\\s|\\/?>)`, 'gi'),
|
|
107130
|
-
original,
|
|
107131
|
-
}));
|
|
107132
|
-
visit(tree, 'html', (node) => {
|
|
107133
|
-
if (node.value) {
|
|
107134
|
-
let newValue = node.value;
|
|
107135
|
-
regexPatterns.forEach(({ regex, original }) => {
|
|
107136
|
-
newValue = newValue.replace(regex, `$1${original}$3`);
|
|
107137
|
-
});
|
|
107138
|
-
if (newValue !== node.value) {
|
|
107139
|
-
node.value = newValue;
|
|
107140
|
-
}
|
|
107141
|
-
}
|
|
107142
|
-
});
|
|
107143
|
-
return tree;
|
|
107144
|
-
};
|
|
107145
|
-
};
|
|
107146
|
-
/* harmony default export */ const restore_snake_case_component_name = (restoreSnakeCaseComponentNames);
|
|
107147
|
-
|
|
107148
107175
|
;// ./processor/transform/mdxish/retain-boolean-attributes.ts
|
|
107149
107176
|
|
|
107150
107177
|
// Private Use Area character (U+E000) which is extremely unlikely to appear in real content.
|
|
@@ -107686,9 +107713,6 @@ function loadComponents() {
|
|
|
107686
107713
|
|
|
107687
107714
|
|
|
107688
107715
|
|
|
107689
|
-
|
|
107690
|
-
|
|
107691
|
-
|
|
107692
107716
|
|
|
107693
107717
|
|
|
107694
107718
|
|
|
@@ -107710,10 +107734,8 @@ const defaultTransformers = [
|
|
|
107710
107734
|
* 5. Terminate HTML flow blocks so subsequent content isn't swallowed
|
|
107711
107735
|
* 6. Close invalid "self-closing" HTML tags (e.g., `<i />` → `<i></i>`)
|
|
107712
107736
|
* 7. Normalize compact ATX headings (e.g., `#Heading` → `# Heading`)
|
|
107713
|
-
* 8. Replace snake_case component names with parser-safe placeholders
|
|
107714
107737
|
*/
|
|
107715
|
-
function preprocessContent(content
|
|
107716
|
-
const { knownComponents } = opts;
|
|
107738
|
+
function preprocessContent(content) {
|
|
107717
107739
|
// Runs first so `jsxTable` sees a literal `</table>` (and the HTML-line
|
|
107718
107740
|
// classification in `terminateHtmlFlowBlocks` is accurate)
|
|
107719
107741
|
let result = normalizeClosingTagWhitespace(content);
|
|
@@ -107726,7 +107748,7 @@ function preprocessContent(content, opts) {
|
|
|
107726
107748
|
result = terminateHtmlFlowBlocks(result);
|
|
107727
107749
|
result = closeSelfClosingHtmlTags(result);
|
|
107728
107750
|
result = normalizeCompactHeadings(result);
|
|
107729
|
-
return
|
|
107751
|
+
return result;
|
|
107730
107752
|
}
|
|
107731
107753
|
function mdxishAstProcessor(mdContent, opts = {}) {
|
|
107732
107754
|
const { components: userComponents = {}, hardBreaks: enableHardBreaks = true, newEditorTypes = false, safeMode = false, useTailwind, } = opts;
|
|
@@ -107734,9 +107756,7 @@ function mdxishAstProcessor(mdContent, opts = {}) {
|
|
|
107734
107756
|
...loadComponents(),
|
|
107735
107757
|
...userComponents,
|
|
107736
107758
|
};
|
|
107737
|
-
|
|
107738
|
-
const knownComponents = new Set(Object.keys(components));
|
|
107739
|
-
const { content: parserReadyContent, mapping: snakeCaseMapping } = preprocessContent(mdContent, { knownComponents });
|
|
107759
|
+
const parserReadyContent = preprocessContent(mdContent);
|
|
107740
107760
|
// Create string map for tailwind transformer
|
|
107741
107761
|
const tempComponentsMap = Object.entries(components).reduce((acc, [key, value]) => {
|
|
107742
107762
|
acc[key] = String(value);
|
|
@@ -107749,10 +107769,8 @@ function mdxishAstProcessor(mdContent, opts = {}) {
|
|
|
107749
107769
|
.use(remarkParse)
|
|
107750
107770
|
.use(remarkFrontmatter)
|
|
107751
107771
|
.use(normalize_malformed_md_syntax)
|
|
107752
|
-
.use(self_closing_blocks)
|
|
107753
107772
|
.use(mdx_blocks, { safeMode })
|
|
107754
107773
|
.use(inline_html, { safeMode })
|
|
107755
|
-
.use(restore_snake_case_component_name, { mapping: snakeCaseMapping })
|
|
107756
107774
|
.use(mdxish_tables)
|
|
107757
107775
|
.use(mdxish_html_blocks) // Convert every <HTMLBlock> shape → html-block
|
|
107758
107776
|
// The next few transformers must appear after mdxishMdxComponentBlocks
|
|
@@ -107828,7 +107846,7 @@ function mdxish(mdContent, opts = {}) {
|
|
|
107828
107846
|
processor
|
|
107829
107847
|
.use(safeMode ? undefined : evaluate_exports) // Evaluate `export const/function` and stash scope on file.data.mdxishScope
|
|
107830
107848
|
.use(enableHardBreaks ? hard_breaks : undefined) // Must precede evaluateExpressions to avoid splitting the \n in an evaluated template literal into a <br> node
|
|
107831
|
-
.use(safeMode ? undefined : evaluate_expressions) // Evaluate self-contained MDX expressions (e.g. `{1+1}`)
|
|
107849
|
+
.use(safeMode ? undefined : evaluate_expressions, { components, variables }) // Evaluate self-contained MDX expressions (e.g. `{1+1}`)
|
|
107832
107850
|
.use(safeMode ? undefined : evaluate_style_block_expressions) // Evaluate `<style>{`...`}</style>` template literals into plain CSS
|
|
107833
107851
|
.use(variables_code, { variables }) // Resolve <<...>> and {user.*} inside code and inline code nodes
|
|
107834
107852
|
.use(remarkRehype, { allowDangerousHtml: true, handlers: mdxComponentHandlers })
|
|
@@ -108815,7 +108833,7 @@ module.exports = /*#__PURE__*/JSON.parse('{"*":["about","acceptCharset","accessK
|
|
|
108815
108833
|
/******/ // startup
|
|
108816
108834
|
/******/ // Load entry module and return exports
|
|
108817
108835
|
/******/ // This entry module used 'module' so it can't be inlined
|
|
108818
|
-
/******/ let __webpack_exports__ = __webpack_require__(
|
|
108836
|
+
/******/ let __webpack_exports__ = __webpack_require__(912);
|
|
108819
108837
|
/******/
|
|
108820
108838
|
/******/ return __webpack_exports__;
|
|
108821
108839
|
/******/ })()
|