@readme/markdown 11.12.1 → 11.13.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.
@@ -59,10 +59,19 @@ function Anchor(props: Props) {
59
59
  const { children, href = '', target = '', title = '', ...attrs } = props;
60
60
  const baseUrl: string = useContext(BaseUrlContext);
61
61
 
62
+ // Unwrap any nested anchor elements that GFM's autolinker may have created.
63
+ // This prevents invalid nested <a> tags when the Anchor's text content looks like a URL.
64
+ const unwrappedChildren = React.Children.map(children, child => {
65
+ if (React.isValidElement(child) && child.type === 'a') {
66
+ return child.props.children;
67
+ }
68
+ return child;
69
+ });
70
+
62
71
  return (
63
72
  // eslint-disable-next-line react/jsx-props-no-spreading
64
73
  <a {...attrs} href={getHref(href, baseUrl)} target={target} title={title} {...docLink(href)}>
65
- {children}
74
+ {unwrappedChildren}
66
75
  </a>
67
76
  );
68
77
  }
@@ -61,7 +61,8 @@ const Code = (props: CodeProps) => {
61
61
  const copyButtons = useContext(CodeOptsContext) || props.copyButtons;
62
62
  const isHydrated = useHydrated();
63
63
 
64
- const language = isHydrated ? canonicalLanguage(lang) : '';
64
+ const language = canonicalLanguage(lang);
65
+ const isMermaid = language === 'mermaid';
65
66
 
66
67
  const codeRef = createRef<HTMLElement>();
67
68
 
@@ -78,7 +79,7 @@ const Code = (props: CodeProps) => {
78
79
  ? syntaxHighlighter(code, language, codeOpts, { mdx: true })
79
80
  : code;
80
81
 
81
- if (language === 'mermaid') {
82
+ if (isHydrated && isMermaid) {
82
83
  return code;
83
84
  }
84
85
 
@@ -4,6 +4,7 @@ import syntaxHighlighterUtils from '@readme/syntax-highlighter/utils';
4
4
  import React, { useContext, useEffect } from 'react';
5
5
 
6
6
  import ThemeContext from '../../contexts/Theme';
7
+ import useHydrated from '../../hooks/useHydrated';
7
8
 
8
9
  let mermaid: Mermaid;
9
10
 
@@ -16,11 +17,26 @@ interface Props {
16
17
  const CodeTabs = (props: Props) => {
17
18
  const { children } = props;
18
19
  const theme = useContext(ThemeContext);
19
- const hasMermaid = !Array.isArray(children) && children.props?.children.props.lang === 'mermaid';
20
+ const isHydrated = useHydrated();
20
21
 
21
- // render Mermaid diagram
22
+ // Handle both array (from rehype-react in rendering mdxish) and single element (MDX/JSX runtime) cases
23
+ // The children here is the individual code block objects
24
+ const childrenArray = Array.isArray(children) ? children : [children];
25
+
26
+ // The structure varies depending on rendering context:
27
+ // - When rendered via rehype-react: pre.props.children is an array where the first element is the Code component
28
+ // - When rendered via MDX/JSX runtime: pre.props.children is directly the Code component
29
+ const getCodeComponent = (pre: JSX.Element) => {
30
+ return Array.isArray(pre?.props?.children) ? pre.props.children[0] : pre?.props?.children;
31
+ };
32
+
33
+ const containAtLeastOneMermaid = childrenArray.some(pre => getCodeComponent(pre)?.props?.lang === 'mermaid');
34
+
35
+ // Render Mermaid diagram
22
36
  useEffect(() => {
23
- if (typeof window !== 'undefined' && hasMermaid) {
37
+ // Ensure we only render mermaids when frontend is hydrated to avoid hydration errors
38
+ // because mermaid mutates the DOM before react hydrates
39
+ if (typeof window !== 'undefined' && containAtLeastOneMermaid && isHydrated) {
24
40
  import('mermaid').then(module => {
25
41
  mermaid = module.default;
26
42
  mermaid.initialize({
@@ -32,7 +48,7 @@ const CodeTabs = (props: Props) => {
32
48
  });
33
49
  });
34
50
  }
35
- }, [hasMermaid, theme]);
51
+ }, [containAtLeastOneMermaid, theme, isHydrated]);
36
52
 
37
53
  function handleClick({ target }, index: number) {
38
54
  const $wrap = target.parentElement.parentElement;
@@ -46,22 +62,25 @@ const CodeTabs = (props: Props) => {
46
62
  target.classList.add('CodeTabs_active');
47
63
  }
48
64
 
49
- // render single Mermaid diagram
50
- if (hasMermaid) {
51
- const value = children.props.children.props.value;
52
- return <pre className="mermaid-render mermaid_single">{value}</pre>;
65
+ // We want to render single mermaid diagrams without the code tabs UI
66
+ if (childrenArray.length === 1) {
67
+ const codeComponent = getCodeComponent(childrenArray[0]);
68
+ if (codeComponent?.props?.lang === 'mermaid') {
69
+ const value = codeComponent?.props?.value;
70
+ return <pre className="mermaid-render mermaid_single">{value}</pre>;
71
+ }
53
72
  }
54
73
 
55
74
  return (
56
75
  <div className={`CodeTabs CodeTabs_initial theme-${theme}`}>
57
76
  <div className="CodeTabs-toolbar">
58
- {(Array.isArray(children) ? children : [children]).map((pre, i) => {
77
+ {childrenArray.map((pre, i) => {
59
78
  // the first or only child should be our Code component
60
- const codeComponent = Array.isArray(pre.props?.children)
79
+ const tabCodeComponent = Array.isArray(pre.props?.children)
61
80
  ? pre.props.children[0]
62
81
  : pre.props?.children;
63
- const lang = codeComponent?.props?.lang;
64
- const meta = codeComponent?.props?.meta;
82
+ const lang = tabCodeComponent?.props?.lang;
83
+ const meta = tabCodeComponent?.props?.meta;
65
84
 
66
85
  /* istanbul ignore next */
67
86
  return (
package/dist/index.d.ts CHANGED
@@ -6,7 +6,7 @@ declare const utils: {
6
6
  getHref: typeof getHref;
7
7
  calloutIcons: {};
8
8
  };
9
- export { compile, exports, hast, run, mdast, mdastV6, mdx, mdxish, mdxishTags, migrate, mix, plain, renderMdxish, remarkPlugins, stripComments, tags, } from './lib';
9
+ export { compile, exports, hast, run, mdast, mdastV6, mdx, mdxish, mdxishAstProcessor, mdxishMdastToMd, mdxishTags, migrate, mix, plain, renderMdxish, remarkPlugins, stripComments, tags, } from './lib';
10
10
  export { default as Owlmoji } from './lib/owlmoji';
11
11
  export { Components, utils };
12
12
  export { tailwindCompiler } from './utils/tailwind-compiler';
@@ -7,7 +7,7 @@ export { default as mdast } from './mdast';
7
7
  export { default as mdastV6 } from './mdastV6';
8
8
  export { default as mdx } from './mdx';
9
9
  export { default as mix } from './mix';
10
- export { default as mdxish } from './mdxish';
10
+ export { default as mdxish, mdxishAstProcessor, mdxishMdastToMd } from './mdxish';
11
11
  export type { MdxishOpts } from './mdxish';
12
12
  export { default as migrate } from './migrate';
13
13
  export { default as plain } from './plain';
@@ -1,13 +1,27 @@
1
1
  import type { CustomComponents } from '../types';
2
2
  import type { Root } from 'hast';
3
+ import type { Root as MdastRoot } from 'mdast';
3
4
  import { type JSXContext } from '../processor/transform/mdxish/preprocess-jsx-expressions';
4
5
  export interface MdxishOpts {
5
6
  components?: CustomComponents;
6
7
  jsxContext?: JSXContext;
7
8
  useTailwind?: boolean;
8
9
  }
10
+ export declare function mdxishAstProcessor(mdContent: string, opts?: MdxishOpts): {
11
+ processor: import("unified").Processor<MdastRoot, import("unist").Node, import("unist").Node, undefined, undefined>;
12
+ /**
13
+ * @todo we need to return this transformed content for now
14
+ * but ultimately need to properly tokenize our special markdown syntax
15
+ * into hast nodes instead of relying on transformed content
16
+ */
17
+ parserReadyContent: string;
18
+ };
9
19
  /**
10
- * Process markdown content with MDX syntax support.
20
+ * Converts an Mdast to a Markdown string.
21
+ */
22
+ export declare function mdxishMdastToMd(mdast: MdastRoot): string;
23
+ /**
24
+ * Processes markdown content with MDX syntax support and returns a HAST.
11
25
  * Detects and renders custom component tags from the components hash.
12
26
  *
13
27
  * @see {@link https://github.com/readmeio/rmdx/blob/main/docs/mdxish-flow.md}
package/dist/main.js CHANGED
@@ -11366,6 +11366,8 @@ __webpack_require__.d(__webpack_exports__, {
11366
11366
  mdastV6: () => (/* reexport */ lib_mdastV6),
11367
11367
  mdx: () => (/* reexport */ lib_mdx),
11368
11368
  mdxish: () => (/* reexport */ lib_mdxish),
11369
+ mdxishAstProcessor: () => (/* reexport */ mdxishAstProcessor),
11370
+ mdxishMdastToMd: () => (/* reexport */ mdxishMdastToMd),
11369
11371
  mdxishTags: () => (/* reexport */ mdxishTags),
11370
11372
  migrate: () => (/* reexport */ lib_migrate),
11371
11373
  mix: () => (/* reexport */ lib_mix),
@@ -11513,9 +11515,17 @@ function docLink(href) {
11513
11515
  function Anchor(props) {
11514
11516
  const { children, href = '', target = '', title = '', ...attrs } = props;
11515
11517
  const baseUrl = (0,external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_.useContext)(BaseUrl);
11518
+ // Unwrap any nested anchor elements that GFM's autolinker may have created.
11519
+ // This prevents invalid nested <a> tags when the Anchor's text content looks like a URL.
11520
+ const unwrappedChildren = external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default().Children.map(children, child => {
11521
+ if (external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default().isValidElement(child) && child.type === 'a') {
11522
+ return child.props.children;
11523
+ }
11524
+ return child;
11525
+ });
11516
11526
  return (
11517
11527
  // eslint-disable-next-line react/jsx-props-no-spreading
11518
- external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default().createElement("a", { ...attrs, href: getHref(href, baseUrl), target: target, title: title, ...docLink(href) }, children));
11528
+ external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default().createElement("a", { ...attrs, href: getHref(href, baseUrl), target: target, title: title, ...docLink(href) }, unwrappedChildren));
11519
11529
  }
11520
11530
  /* harmony default export */ const components_Anchor = (Anchor);
11521
11531
 
@@ -11653,7 +11663,8 @@ const Code = (props) => {
11653
11663
  const theme = (0,external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_.useContext)(Theme);
11654
11664
  const copyButtons = (0,external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_.useContext)(CodeOpts) || props.copyButtons;
11655
11665
  const isHydrated = useHydrated();
11656
- const language = isHydrated ? canonicalLanguage(lang) : '';
11666
+ const language = canonicalLanguage(lang);
11667
+ const isMermaid = language === 'mermaid';
11657
11668
  const codeRef = (0,external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_.createRef)();
11658
11669
  const codeOpts = {
11659
11670
  inline: !lang,
@@ -11664,7 +11675,7 @@ const Code = (props) => {
11664
11675
  const highlightedCode = syntaxHighlighter && typeof syntaxHighlighter === 'function' && code && isHydrated
11665
11676
  ? syntaxHighlighter(code, language, codeOpts, { mdx: true })
11666
11677
  : code;
11667
- if (language === 'mermaid') {
11678
+ if (isHydrated && isMermaid) {
11668
11679
  return code;
11669
11680
  }
11670
11681
  return (external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default().createElement((external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default()).Fragment, null,
@@ -11680,15 +11691,28 @@ var dist_utils_default = /*#__PURE__*/__webpack_require__.n(dist_utils);
11680
11691
 
11681
11692
 
11682
11693
 
11694
+
11683
11695
  let mermaid;
11684
11696
  const { uppercase } = (dist_utils_default());
11685
11697
  const CodeTabs = (props) => {
11686
11698
  const { children } = props;
11687
11699
  const theme = (0,external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_.useContext)(Theme);
11688
- const hasMermaid = !Array.isArray(children) && children.props?.children.props.lang === 'mermaid';
11689
- // render Mermaid diagram
11700
+ const isHydrated = useHydrated();
11701
+ // Handle both array (from rehype-react in rendering mdxish) and single element (MDX/JSX runtime) cases
11702
+ // The children here is the individual code block objects
11703
+ const childrenArray = Array.isArray(children) ? children : [children];
11704
+ // The structure varies depending on rendering context:
11705
+ // - When rendered via rehype-react: pre.props.children is an array where the first element is the Code component
11706
+ // - When rendered via MDX/JSX runtime: pre.props.children is directly the Code component
11707
+ const getCodeComponent = (pre) => {
11708
+ return Array.isArray(pre?.props?.children) ? pre.props.children[0] : pre?.props?.children;
11709
+ };
11710
+ const containAtLeastOneMermaid = childrenArray.some(pre => getCodeComponent(pre)?.props?.lang === 'mermaid');
11711
+ // Render Mermaid diagram
11690
11712
  (0,external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_.useEffect)(() => {
11691
- if (typeof window !== 'undefined' && hasMermaid) {
11713
+ // Ensure we only render mermaids when frontend is hydrated to avoid hydration errors
11714
+ // because mermaid mutates the DOM before react hydrates
11715
+ if (typeof window !== 'undefined' && containAtLeastOneMermaid && isHydrated) {
11692
11716
  Promise.resolve(/* import() */).then(__webpack_require__.t.bind(__webpack_require__, 1387, 23)).then(module => {
11693
11717
  mermaid = module.default;
11694
11718
  mermaid.initialize({
@@ -11700,7 +11724,7 @@ const CodeTabs = (props) => {
11700
11724
  });
11701
11725
  });
11702
11726
  }
11703
- }, [hasMermaid, theme]);
11727
+ }, [containAtLeastOneMermaid, theme, isHydrated]);
11704
11728
  function handleClick({ target }, index) {
11705
11729
  const $wrap = target.parentElement.parentElement;
11706
11730
  const $open = [].slice.call($wrap.querySelectorAll('.CodeTabs_active'));
@@ -11710,19 +11734,22 @@ const CodeTabs = (props) => {
11710
11734
  codeblocks[index].classList.add('CodeTabs_active');
11711
11735
  target.classList.add('CodeTabs_active');
11712
11736
  }
11713
- // render single Mermaid diagram
11714
- if (hasMermaid) {
11715
- const value = children.props.children.props.value;
11716
- return external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default().createElement("pre", { className: "mermaid-render mermaid_single" }, value);
11737
+ // We want to render single mermaid diagrams without the code tabs UI
11738
+ if (childrenArray.length === 1) {
11739
+ const codeComponent = getCodeComponent(childrenArray[0]);
11740
+ if (codeComponent?.props?.lang === 'mermaid') {
11741
+ const value = codeComponent?.props?.value;
11742
+ return external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default().createElement("pre", { className: "mermaid-render mermaid_single" }, value);
11743
+ }
11717
11744
  }
11718
11745
  return (external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default().createElement("div", { className: `CodeTabs CodeTabs_initial theme-${theme}` },
11719
- external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default().createElement("div", { className: "CodeTabs-toolbar" }, (Array.isArray(children) ? children : [children]).map((pre, i) => {
11746
+ external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default().createElement("div", { className: "CodeTabs-toolbar" }, childrenArray.map((pre, i) => {
11720
11747
  // the first or only child should be our Code component
11721
- const codeComponent = Array.isArray(pre.props?.children)
11748
+ const tabCodeComponent = Array.isArray(pre.props?.children)
11722
11749
  ? pre.props.children[0]
11723
11750
  : pre.props?.children;
11724
- const lang = codeComponent?.props?.lang;
11725
- const meta = codeComponent?.props?.meta;
11751
+ const lang = tabCodeComponent?.props?.lang;
11752
+ const meta = tabCodeComponent?.props?.meta;
11726
11753
  /* istanbul ignore next */
11727
11754
  return (external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default().createElement("button", { key: i, onClick: e => handleClick(e, i), type: "button", value: lang }, meta || `${!lang ? 'Text' : uppercase(lang)}`));
11728
11755
  })),
@@ -71214,10 +71241,20 @@ const coerceJsxToMd = ({ components = {}, html = false } = {}) => (node, index,
71214
71241
  hProperties.url = hProperties.href;
71215
71242
  delete hProperties.href;
71216
71243
  }
71244
+ // Unwrap any autolinked children to prevent nested links.
71245
+ // GFM's autolink feature can convert URL-like text inside Anchor children
71246
+ // into link nodes, which would create invalid nested links when Anchor
71247
+ // is converted back to a link node.
71248
+ const children = node.children.flatMap(child => {
71249
+ if (child.type === 'link') {
71250
+ return child.children;
71251
+ }
71252
+ return child;
71253
+ });
71217
71254
  // @ts-expect-error we don't have a mechanism to enforce the URL attribute type right now
71218
71255
  const mdNode = {
71219
71256
  ...hProperties,
71220
- children: node.children,
71257
+ children,
71221
71258
  type: types[node.name],
71222
71259
  position: node.position,
71223
71260
  };
@@ -86506,16 +86543,17 @@ const tocHastToMdx = (toc, components) => {
86506
86543
 
86507
86544
 
86508
86545
 
86509
- const { codeTabsTransformer: compile_codeTabsTransformer, ...transforms } = defaultTransforms;
86510
86546
  const sanitizeSchema = cjs_default()(defaultSchema, {
86511
86547
  protocols: ['doc', 'ref', 'blog', 'changelog', 'page'],
86512
86548
  });
86513
86549
  const compile_compile = (text, { components = {}, missingComponents, copyButtons, useTailwind, ...opts } = {}) => {
86550
+ // Destructure at runtime to avoid circular dependency issues
86551
+ const { codeTabsTransformer, ...transforms } = defaultTransforms;
86514
86552
  const remarkPlugins = [
86515
86553
  remarkFrontmatter,
86516
86554
  remarkGfm,
86517
86555
  ...Object.values(transforms),
86518
- [compile_codeTabsTransformer, { copyButtons }],
86556
+ [codeTabsTransformer, { copyButtons }],
86519
86557
  [
86520
86558
  handle_missing_components,
86521
86559
  { components, missingComponents: ['ignore', 'throw'].includes(missingComponents) ? missingComponents : 'ignore' },
@@ -93793,8 +93831,6 @@ const mdxishHtmlBlocks = () => tree => {
93793
93831
  * Taken from the v6 branch
93794
93832
  */
93795
93833
  const RGXP = /^\s*\[block:([^\]]*)\]([^]+?)\[\/block\]/;
93796
- /** Parses markdown in table cells */
93797
- const cellParser = unified().use(remarkParse).use(remarkGfm);
93798
93834
  /**
93799
93835
  * Wraps a node in a "pinned" container if sidebar: true is set in the JSON.
93800
93836
  * Pinned blocks are displayed in a sidebar/floating position in the UI.
@@ -93828,11 +93864,13 @@ const imgWidthBySize = new Proxy(imgSizeValues, {
93828
93864
  const textToInline = (text) => [{ type: 'text', value: text }];
93829
93865
  // Simple text to block nodes (wraps in paragraph)
93830
93866
  const textToBlock = (text) => [{ children: textToInline(text), type: 'paragraph' }];
93867
+ /** Parses markdown and html to markdown nodes */
93868
+ const contentParser = unified().use(remarkParse).use(remarkGfm);
93831
93869
  // Table cells may contain html or markdown content, so we need to parse it accordingly instead of keeping it as raw text
93832
- const parseInline = (text) => {
93870
+ const parseTableCell = (text) => {
93833
93871
  if (!text.trim())
93834
93872
  return [{ type: 'text', value: '' }];
93835
- const tree = cellParser.runSync(cellParser.parse(text));
93873
+ const tree = contentParser.runSync(contentParser.parse(text));
93836
93874
  // If there are multiple block-level nodes, keep them as-is to preserve the document structure and spacing
93837
93875
  if (tree.children.length > 1) {
93838
93876
  return tree.children;
@@ -93841,6 +93879,13 @@ const parseInline = (text) => {
93841
93879
  // This unwraps the extra p node that might appear & wrapping the content
93842
93880
  n.type === 'paragraph' && 'children' in n ? n.children : [n]);
93843
93881
  };
93882
+ // Parse markdown/HTML into block-level nodes (preserves paragraphs, headings, lists, etc.)
93883
+ const parseBlock = (text) => {
93884
+ if (!text.trim())
93885
+ return [{ type: 'paragraph', children: [{ type: 'text', value: '' }] }];
93886
+ const tree = contentParser.runSync(contentParser.parse(text));
93887
+ return tree.children;
93888
+ };
93844
93889
  /**
93845
93890
  * Parse a magic block string and return MDAST nodes.
93846
93891
  *
@@ -93919,7 +93964,7 @@ function parseMagicBlock(raw, options = {}) {
93919
93964
  data: {
93920
93965
  hProperties: {
93921
93966
  ...(imgData.align && { align: imgData.align }),
93922
- className: imgData.border ? 'border' : '',
93967
+ ...(imgData.border && { border: imgData.border.toString() }),
93923
93968
  ...(imgData.sizing && { width: imgWidthBySize[imgData.sizing] }),
93924
93969
  },
93925
93970
  },
@@ -93958,8 +94003,9 @@ function parseMagicBlock(raw, options = {}) {
93958
94003
  const [icon, theme] = Array.isArray(resolvedType) ? resolvedType : ['👍', 'default'];
93959
94004
  if (!(calloutJson.title || calloutJson.body))
93960
94005
  return [];
93961
- const titleBlocks = textToBlock(calloutJson.title || '');
93962
- const bodyBlocks = textToBlock(calloutJson.body || '');
94006
+ // Parses html & markdown content
94007
+ const titleBlocks = parseBlock(calloutJson.title || '');
94008
+ const bodyBlocks = parseBlock(calloutJson.body || '');
93963
94009
  const children = [];
93964
94010
  if (titleBlocks.length > 0 && titleBlocks[0].type === 'paragraph') {
93965
94011
  const firstTitle = titleBlocks[0];
@@ -94013,7 +94059,7 @@ function parseMagicBlock(raw, options = {}) {
94013
94059
  return mapped;
94014
94060
  }, []);
94015
94061
  // In compatibility mode, wrap cell content in paragraphs; otherwise inline text
94016
- const tokenizeCell = compatibilityMode ? textToBlock : parseInline;
94062
+ const tokenizeCell = compatibilityMode ? textToBlock : parseTableCell;
94017
94063
  const children = Array.from({ length: rows + 1 }, (_, y) => ({
94018
94064
  children: Array.from({ length: cols }, (__, x) => ({
94019
94065
  children: sparseData[y]?.[x] ? tokenizeCell(sparseData[y][x]) : [{ type: 'text', value: '' }],
@@ -94147,6 +94193,38 @@ const magicBlockRestorer = ({ blocks }) => tree => {
94147
94193
  };
94148
94194
  /* harmony default export */ const mdxish_magic_blocks = (magicBlockRestorer);
94149
94195
 
94196
+ ;// ./processor/transform/mdxish/mdxish-mermaid.ts
94197
+
94198
+ /**
94199
+ * Rehype plugin for mdxish pipeline to add mermaid-render className to mermaid code blocks.
94200
+ * The mermaid-render class is used to identify the mermaid diagrams elements for the
94201
+ * mermaid library to transform. See components/CodeTabs/index.tsx for context
94202
+ */
94203
+ const mdxishMermaidTransformer = () => (tree) => {
94204
+ visit(tree, 'element', (node) => {
94205
+ if (node.tagName !== 'pre' || node.children.length !== 1)
94206
+ return;
94207
+ const [child] = node.children;
94208
+ if (child.type === 'element' &&
94209
+ child.tagName === 'code' &&
94210
+ child.properties?.lang === 'mermaid') {
94211
+ // Combine existing className with the new mermaid-render class
94212
+ const existingClassName = node.properties?.className;
94213
+ const classNameArray = Array.isArray(existingClassName)
94214
+ ? existingClassName.filter(c => typeof c === 'string' || typeof c === 'number')
94215
+ : existingClassName && (typeof existingClassName === 'string' || typeof existingClassName === 'number')
94216
+ ? [existingClassName]
94217
+ : [];
94218
+ node.properties = {
94219
+ ...node.properties,
94220
+ className: ['mermaid-render', ...classNameArray],
94221
+ };
94222
+ }
94223
+ });
94224
+ return tree;
94225
+ };
94226
+ /* harmony default export */ const mdxish_mermaid = (mdxishMermaidTransformer);
94227
+
94150
94228
  ;// ./lib/constants.ts
94151
94229
  /**
94152
94230
  * Pattern to match component tags (PascalCase or snake_case)
@@ -94593,18 +94671,15 @@ function loadComponents() {
94593
94671
 
94594
94672
 
94595
94673
 
94674
+
94675
+
94676
+
94596
94677
 
94597
94678
 
94598
94679
 
94599
94680
 
94600
94681
  const defaultTransformers = [callouts, code_tabs, gemoji_, transform_embeds];
94601
- /**
94602
- * Process markdown content with MDX syntax support.
94603
- * Detects and renders custom component tags from the components hash.
94604
- *
94605
- * @see {@link https://github.com/readmeio/rmdx/blob/main/docs/mdxish-flow.md}
94606
- */
94607
- function mdxish(mdContent, opts = {}) {
94682
+ function mdxishAstProcessor(mdContent, opts = {}) {
94608
94683
  const { components: userComponents = {}, jsxContext = {}, useTailwind } = opts;
94609
94684
  const components = {
94610
94685
  ...loadComponents(),
@@ -94639,11 +94714,46 @@ function mdxish(mdContent, opts = {}) {
94639
94714
  .use(evaluate_expressions, { context: jsxContext }) // Evaluate MDX expressions using jsxContext
94640
94715
  .use(variables_text) // Parse {user.*} patterns from text (can't rely on remarkMdx)
94641
94716
  .use(useTailwind ? transform_tailwind : undefined, { components: tempComponentsMap })
94642
- .use(remarkGfm)
94717
+ .use(remarkGfm);
94718
+ return {
94719
+ processor,
94720
+ /**
94721
+ * @todo we need to return this transformed content for now
94722
+ * but ultimately need to properly tokenize our special markdown syntax
94723
+ * into hast nodes instead of relying on transformed content
94724
+ */
94725
+ parserReadyContent,
94726
+ };
94727
+ }
94728
+ /**
94729
+ * Converts an Mdast to a Markdown string.
94730
+ */
94731
+ function mdxishMdastToMd(mdast) {
94732
+ const md = unified().use(remarkGfm).use(processor_compile).use(remarkStringify, {
94733
+ bullet: '-',
94734
+ emphasis: '_',
94735
+ }).stringify(mdast);
94736
+ return md;
94737
+ }
94738
+ /**
94739
+ * Processes markdown content with MDX syntax support and returns a HAST.
94740
+ * Detects and renders custom component tags from the components hash.
94741
+ *
94742
+ * @see {@link https://github.com/readmeio/rmdx/blob/main/docs/mdxish-flow.md}
94743
+ */
94744
+ function mdxish(mdContent, opts = {}) {
94745
+ const { components: userComponents = {} } = opts;
94746
+ const components = {
94747
+ ...loadComponents(),
94748
+ ...userComponents,
94749
+ };
94750
+ const { processor, parserReadyContent } = mdxishAstProcessor(mdContent, opts);
94751
+ processor
94643
94752
  .use(remarkRehype, { allowDangerousHtml: true, handlers: mdxComponentHandlers })
94644
94753
  .use(preserveBooleanProperties) // RehypeRaw converts boolean properties to empty strings
94645
94754
  .use(rehypeRaw, { passThrough: ['html-block'] })
94646
94755
  .use(restoreBooleanProperties)
94756
+ .use(mdxish_mermaid) // Add mermaid-render className to pre wrappers
94647
94757
  .use(rehypeSlug)
94648
94758
  .use(rehypeMdxishComponents, {
94649
94759
  components,