@readme/markdown 15.2.1 → 15.4.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/README.md CHANGED
@@ -99,6 +99,7 @@ Extends [`CompileOptions`](https://mdxjs.com/packages/mdx/#compileoptions)
99
99
  - **`safeMode`** (`boolean`, optional)—extract script tags from `HTMLBlock`s
100
100
  - **`components`** (`Record<string, string>`, optional)—an object of tag names to mdx.
101
101
  - **`copyButtons`** (`Boolean`, optional) — add a copy button to code blocks
102
+ - **`hardBreaks`** (`boolean`, optional)—render every newline as a `<br>`. `mdxish` defaults to `true`
102
103
 
103
104
  ### `RunOpts`
104
105
 
@@ -14,9 +14,11 @@ const traverse = (node: Node, callback: (element: Node) => void) => {
14
14
  interface Props {
15
15
  children: React.ReactNode;
16
16
  darkModeDataAttribute?: string | null;
17
+ /** See the matching param on `tailwindCompiler` in `utils/tailwind-compiler.ts`. */
18
+ darkModeRootSelector?: string | null;
17
19
  }
18
20
 
19
- const TailwindStyle = ({ children, darkModeDataAttribute }: Props) => {
21
+ const TailwindStyle = ({ children, darkModeDataAttribute, darkModeRootSelector }: Props) => {
20
22
  const [stylesheet, setStylesheet] = useState('');
21
23
  const classesSet = useRef(new Set<string>());
22
24
  const ref = useRef<HTMLStyleElement>(null);
@@ -43,6 +45,7 @@ const TailwindStyle = ({ children, darkModeDataAttribute }: Props) => {
43
45
  const sheet = await tailwindCompiler(classes, {
44
46
  prefix: `.${tailwindPrefix}`,
45
47
  darkModeDataAttribute,
48
+ darkModeRootSelector,
46
49
  });
47
50
  /* @note: don't insert an empty stylesheet */
48
51
  if (sheet.css.match(/^@layer utilities;/m)) return;
@@ -51,7 +54,7 @@ const TailwindStyle = ({ children, darkModeDataAttribute }: Props) => {
51
54
  };
52
55
 
53
56
  run();
54
- }, [classes, darkModeDataAttribute]);
57
+ }, [classes, darkModeDataAttribute, darkModeRootSelector]);
55
58
 
56
59
  /*
57
60
  * @note: execute once on load
@@ -2,6 +2,8 @@ import React from 'react';
2
2
  interface Props {
3
3
  children: React.ReactNode;
4
4
  darkModeDataAttribute?: string | null;
5
+ /** See the matching param on `tailwindCompiler` in `utils/tailwind-compiler.ts`. */
6
+ darkModeRootSelector?: string | null;
5
7
  }
6
- declare const TailwindStyle: ({ children, darkModeDataAttribute }: Props) => React.JSX.Element;
8
+ declare const TailwindStyle: ({ children, darkModeDataAttribute, darkModeRootSelector }: Props) => React.JSX.Element;
7
9
  export default TailwindStyle;
@@ -3,6 +3,15 @@ import type { Root } from 'hast';
3
3
  import type { Root as MdastRoot } from 'mdast';
4
4
  export interface MdxishOpts {
5
5
  components?: CustomComponents;
6
+ /**
7
+ * Whether a single newline (\n) renders as a `<br>`. Defaults to `true`, matching legacy rdmd.
8
+ * Turn it off for CommonMark semantics, where only a blank line breaks — what content
9
+ * soft-wrapped to a line-length limit (OpenAPI descriptions, linted markdown) expects.
10
+ *
11
+ * Only applies to `mdxish()`; `mdxishAstProcessor` never hard-breaks its MDAST.
12
+ * There's no use for it right now but it can be revisited if needed.
13
+ */
14
+ hardBreaks?: boolean;
6
15
  newEditorTypes?: boolean;
7
16
  /**
8
17
  * When enabled, the pipeline ignores all expression syntax `{...}`.
package/dist/main.js CHANGED
@@ -12675,7 +12675,7 @@ async function loadStylesheet(id, base) {
12675
12675
  async function loadModule() {
12676
12676
  throw new Error('The browser build does not support plugins or config files.');
12677
12677
  }
12678
- async function createCompiler({ darkModeDataAttribute }) {
12678
+ async function createCompiler({ darkModeDataAttribute, darkModeRootSelector, }) {
12679
12679
  let css = `
12680
12680
  @layer theme, base, components, utilities;
12681
12681
 
@@ -12683,9 +12683,12 @@ async function createCompiler({ darkModeDataAttribute }) {
12683
12683
  @import "tailwindcss/utilities.css" layer(utilities);
12684
12684
  `;
12685
12685
  if (darkModeDataAttribute) {
12686
+ // Anchors `dark:` to `darkModeRootSelector`'s own attribute instead of any ancestor's,
12687
+ // when supplied — see the `darkModeRootSelector` param doc below for why there's no default.
12688
+ const root = darkModeRootSelector || '';
12686
12689
  css += `
12687
12690
 
12688
- @custom-variant dark (&:where([${darkModeDataAttribute}=dark], [${darkModeDataAttribute}=dark] *));`;
12691
+ @custom-variant dark (&:where(${root}[${darkModeDataAttribute}=dark], ${root}[${darkModeDataAttribute}=dark] *));`;
12689
12692
  }
12690
12693
  return Hu(css, {
12691
12694
  base: '/',
@@ -12693,8 +12696,8 @@ async function createCompiler({ darkModeDataAttribute }) {
12693
12696
  loadModule,
12694
12697
  });
12695
12698
  }
12696
- async function tailwindCompiler(classes, { prefix, darkModeDataAttribute }) {
12697
- const compiler = await createCompiler({ darkModeDataAttribute });
12699
+ async function tailwindCompiler(classes, { prefix, darkModeDataAttribute, darkModeRootSelector, }) {
12700
+ const compiler = await createCompiler({ darkModeDataAttribute, darkModeRootSelector });
12698
12701
  const css = compiler.build(Array.from(classes));
12699
12702
  return lib_postcss([postcss_prefix_selector_default()({ prefix })]).process(css, { from: undefined });
12700
12703
  }
@@ -12709,7 +12712,7 @@ const traverse = (node, callback) => {
12709
12712
  traverse(child, callback);
12710
12713
  });
12711
12714
  };
12712
- const TailwindStyle = ({ children, darkModeDataAttribute }) => {
12715
+ const TailwindStyle = ({ children, darkModeDataAttribute, darkModeRootSelector }) => {
12713
12716
  const [stylesheet, setStylesheet] = (0,external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_.useState)('');
12714
12717
  const classesSet = (0,external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_.useRef)(new Set());
12715
12718
  const ref = (0,external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_.useRef)(null);
@@ -12733,6 +12736,7 @@ const TailwindStyle = ({ children, darkModeDataAttribute }) => {
12733
12736
  const sheet = await tailwindCompiler(classes, {
12734
12737
  prefix: `.${tailwindPrefix}`,
12735
12738
  darkModeDataAttribute,
12739
+ darkModeRootSelector,
12736
12740
  });
12737
12741
  /* @note: don't insert an empty stylesheet */
12738
12742
  if (sheet.css.match(/^@layer utilities;/m))
@@ -12740,7 +12744,7 @@ const TailwindStyle = ({ children, darkModeDataAttribute }) => {
12740
12744
  setStylesheet(sheet.css);
12741
12745
  };
12742
12746
  run();
12743
- }, [classes, darkModeDataAttribute]);
12747
+ }, [classes, darkModeDataAttribute, darkModeRootSelector]);
12744
12748
  /*
12745
12749
  * @note: execute once on load
12746
12750
  */
@@ -75799,6 +75803,7 @@ var allCSS2RNProps = __webpack_unused_export__ = flatten([allProps, CSS2RNProps]
75799
75803
 
75800
75804
 
75801
75805
 
75806
+
75802
75807
  /**
75803
75808
  * Extract word boundaries from camelCase strings (e.g., "borderWidth" -> ["border", "width"])
75804
75809
  */
@@ -75878,10 +75883,43 @@ const CUSTOM_PROP_BOUNDARIES = [
75878
75883
  */
75879
75884
  const RUNTIME_COMPONENT_TAGS = new Set(['Variable', 'variable', 'html-block', 'rdme-pin']);
75880
75885
  /**
75881
- * Standard HTML tags that should never be treated as custom components.
75882
- * Uses the html-tags package, converted to a Set<string> for efficient lookups.
75886
+ * Elements that are not actually standard HTML tags, or those that we intentionally
75887
+ * don't want to treat as one & is mute to check with. These include:
75888
+ * - SVG/MathML descendants
75889
+ * - Namespaced foreign content
75890
+ * - `image`, which the HTML tree builder rewrites to `img`
75891
+ * Most of these are bundled in parse5's `TAG_NAMES` set, but we can also add a few more.
75883
75892
  */
75884
- const STANDARD_HTML_TAGS = new Set(html_tags_namespaceObject);
75893
+ const NON_STANDARD_TAGS = new Set([
75894
+ 'annotation-xml',
75895
+ 'desc',
75896
+ 'foreignObject',
75897
+ 'image',
75898
+ 'malignmark',
75899
+ 'mglyph',
75900
+ 'mi',
75901
+ 'mn',
75902
+ 'mo',
75903
+ 'ms',
75904
+ 'mtext',
75905
+ ]);
75906
+ /**
75907
+ * Standard HTML tags list.
75908
+ * A use case of this is to differentiate custom components tag vs standard HTML tags.
75909
+ *
75910
+ * Unioned from:
75911
+ * - `html-tags`: All modern spec HTML elements
75912
+ * - parse5's `TAG_NAMES`: Elements the HTML tree-construction algorithm has to special-case
75913
+ * This includes obsolete tags that are still rendered by browsers.
75914
+ * - NON_STANDARD_TAGS: We've had to filter because currently parse5's `TAG_NAMES` set over-enumerates
75915
+ * tags that are not actually standard HTML tags. It also allows custom tags to be filtered out.
75916
+ */
75917
+ const STANDARD_HTML_TAGS = new Set([
75918
+ ...html_tags_namespaceObject,
75919
+ ...Object.values(TAG_NAMES),
75920
+ 'acronym', // Obselete tag not included either of the above sources. Add here if we have missed any.
75921
+ 'blink',
75922
+ ].filter(tag => !NON_STANDARD_TAGS.has(tag)));
75885
75923
  /**
75886
75924
  * Table structural tags. Blank lines inside these carry deliberate meaning for
75887
75925
  * `mdxishTables` (e.g. splitting cell content into paragraphs, or deciding
@@ -105351,8 +105389,11 @@ var variable_default = /*#__PURE__*/__webpack_require__.n(variable_);
105351
105389
  const HTML_TAG_RE = /<\/?([a-zA-Z][a-zA-Z0-9-]*)((?:[^>"']*(?:"[^"]*"|'[^']*'))*[^>"']*)>/g;
105352
105390
  /** Matches an HTML element from its opening tag to the matching closing tag. */
105353
105391
  const HTML_ELEMENT_BLOCK_RE = /<([a-zA-Z][a-zA-Z0-9-]*)[\s>][\s\S]*?<\/\1>/g;
105392
+ const NEWLINE_RE = /\n/g;
105354
105393
  /** Matches a newline with surrounding horizontal whitespace. */
105355
105394
  const NEWLINE_WITH_WHITESPACE_RE = /[^\S\n]*\n[^\S\n]*/g;
105395
+ /** Matches a run of two or more newlines (a blank line) with surrounding horizontal whitespace. */
105396
+ const BLANK_LINE_RE = /[^\S\n]*\n(?:[^\S\n]*\n)+[^\S\n]*/g;
105356
105397
  /** Matches a closing block-level tag followed by non-tag text or by a newline then non-blank content. */
105357
105398
  const CLOSE_BLOCK_TAG_BOUNDARY_RE = /<\/([a-zA-Z][a-zA-Z0-9-]*)>\s*(?:(?!<)(\S)|\n([^\n]))/g;
105358
105399
  /** Strips HTML open/close tags. Used to detect non-tag inner text content. */
@@ -105422,7 +105463,6 @@ const EMPTY_CODE_PLACEHOLDER = {
105422
105463
 
105423
105464
 
105424
105465
 
105425
-
105426
105466
  /**
105427
105467
  * Wraps a node in a "pinned" container if sidebar: true is set.
105428
105468
  */
@@ -105457,16 +105497,13 @@ const textToBlock = (text) => [{ children: textToInline(text), type: 'paragraph'
105457
105497
  */
105458
105498
  const ensureLeadingBreaks = (text) => text.replace(/^\n+/, match => '<br>'.repeat(match.length));
105459
105499
  /** Preprocesses magic block body content before parsing. */
105460
- const preprocessBody = (text) => {
105461
- return ensureLeadingBreaks(text);
105462
- };
105500
+ const preprocessBody = (text, hardBreaks) => (hardBreaks ? ensureLeadingBreaks(text) : text);
105463
105501
  const bodyExtensions = mdxishExtensions(FEATURES.magicBlockBody);
105464
105502
  /** Markdown parser */
105465
105503
  const contentParser = unified()
105466
105504
  .data('micromarkExtensions', bodyExtensions.micromarkExtensions)
105467
105505
  .data('fromMarkdownExtensions', bodyExtensions.fromMarkdownExtensions)
105468
105506
  .use(remarkParse)
105469
- .use(hard_breaks)
105470
105507
  .use(remarkGfm)
105471
105508
  .use(normalize_malformed_md_syntax);
105472
105509
  /**
@@ -105563,17 +105600,21 @@ const processMarkdownInHtmlString = (html) => {
105563
105600
  /**
105564
105601
  * Separate a closing block-level tag from the content that follows it.
105565
105602
  *
105566
- * Each \n in the original text becomes a <br> tag to preserve spacing, then a
105567
- * blank line (\n\n) is appended so CommonMark ends the HTML block and parses
105568
- * the following content as markdown.
105603
+ * A blank line (\n\n) is appended so CommonMark ends the HTML block and parses the
105604
+ * following content as markdown; with hard breaks each \n also becomes a <br> to keep its spacing.
105569
105605
  */
105570
- const separateBlockTagFromContent = (match, tag, inlineChar, nextLineChar) => {
105606
+ const separateBlockTagFromContent = (hardBreaks, match, tag, inlineChar, nextLineChar) => {
105571
105607
  if (!BLOCK_LEVEL_TAGS.has(tag.toLowerCase()))
105572
105608
  return match;
105573
- const newlineCount = (match.match(/\n/g) ?? []).length;
105609
+ const newlineCount = hardBreaks ? (match.match(NEWLINE_RE) ?? []).length : 0;
105574
105610
  const breaks = '<br>'.repeat(newlineCount);
105575
105611
  return `</${tag}>${breaks}\n\n${inlineChar || nextLineChar}`;
105576
105612
  };
105613
+ /**
105614
+ * Newlines inside an HTML block become <br> so CommonMark doesn't end the block on a blank
105615
+ * line. Without hard breaks only blank lines break, but they still have to be replaced.
105616
+ */
105617
+ const collapseHtmlBlockNewlines = (html, hardBreaks) => html.replace(hardBreaks ? NEWLINE_WITH_WHITESPACE_RE : BLANK_LINE_RE, '<br>');
105577
105618
  /** Escape a leading (possibly indented) `-`/`*`/`+` so cells don't become bullet lists. */
105578
105619
  const escapeLeadingListMarkers = (text) => text.replace(/^([ \t]*)([-*+])(?=[ \t]|$)/gm, '$1\\$2');
105579
105620
  /**
@@ -105581,15 +105622,13 @@ const escapeLeadingListMarkers = (text) => text.replace(/^([ \t]*)([-*+])(?=[ \t
105581
105622
  * so `<ul><li>_text_</li></ul>` won't convert underscores to emphasis.
105582
105623
  * We parse first, then visit html nodes and process their text content.
105583
105624
  */
105584
- const parseTableCell = (text) => {
105625
+ const parseTableCell = (text, hardBreaks) => {
105585
105626
  if (!text.trim())
105586
105627
  return [{ type: 'text', value: '' }];
105587
- // Convert \n (and surrounding whitespace) to <br> inside HTML blocks so
105588
- // CommonMark doesn't split them on blank lines.
105589
105628
  const escaped = processBackslashEscapes(text);
105590
105629
  const normalized = escaped
105591
- .replace(HTML_ELEMENT_BLOCK_RE, match => match.replace(NEWLINE_WITH_WHITESPACE_RE, '<br>'))
105592
- .replace(CLOSE_BLOCK_TAG_BOUNDARY_RE, separateBlockTagFromContent);
105630
+ .replace(HTML_ELEMENT_BLOCK_RE, match => collapseHtmlBlockNewlines(match, hardBreaks))
105631
+ .replace(CLOSE_BLOCK_TAG_BOUNDARY_RE, (match, tag, inlineChar, nextLineChar) => separateBlockTagFromContent(hardBreaks, match, tag, inlineChar, nextLineChar));
105593
105632
  const processed = escapeLeadingListMarkers(normalized);
105594
105633
  const tree = contentParser.runSync(contentParser.parse(processed));
105595
105634
  // Process markdown inside HTML blocks that have non-tag inner text (e.g. `<div>**x**`
@@ -105638,7 +105677,7 @@ const parseApiHeaderTitle = (text) => {
105638
105677
  * Transform a magicBlock node into final MDAST nodes.
105639
105678
  */
105640
105679
  function transformMagicBlock(blockType, data, rawValue, options = {}) {
105641
- const { compatibilityMode = false, safeMode = false } = options;
105680
+ const { compatibilityMode = false, hardBreaks = true, safeMode = false } = options;
105642
105681
  // Handle empty data by returning placeholder nodes for known block types
105643
105682
  // This allows the editor to show appropriate placeholder UI instead of nothing
105644
105683
  if (Object.keys(data).length < 1) {
@@ -105777,7 +105816,7 @@ function transformMagicBlock(blockType, data, rawValue, options = {}) {
105777
105816
  });
105778
105817
  }
105779
105818
  if (hasBody) {
105780
- const bodyBlocks = parseBlock(preprocessBody(calloutJson.body || ''));
105819
+ const bodyBlocks = parseBlock(preprocessBody(calloutJson.body || '', hardBreaks));
105781
105820
  children.push(...bodyBlocks);
105782
105821
  }
105783
105822
  const calloutElement = {
@@ -105809,12 +105848,12 @@ function transformMagicBlock(blockType, data, rawValue, options = {}) {
105809
105848
  mapped[rowIndex][colIndex] = v;
105810
105849
  return mapped;
105811
105850
  }, []);
105812
- const tokenizeCell = compatibilityMode
105813
- ? textToBlock
105814
- : parseTableCell;
105851
+ const tokenizeCell = compatibilityMode ? textToBlock : (text) => parseTableCell(text, hardBreaks);
105815
105852
  const tableChildren = Array.from({ length: rows + 1 }, (_, y) => ({
105816
105853
  children: Array.from({ length: cols }, (__, x) => ({
105817
- children: sparseData[y]?.[x] ? tokenizeCell(preprocessBody(sparseData[y][x])) : [{ type: 'text', value: '' }],
105854
+ children: sparseData[y]?.[x]
105855
+ ? tokenizeCell(preprocessBody(sparseData[y][x], hardBreaks))
105856
+ : [{ type: 'text', value: '' }],
105818
105857
  type: y === 0 ? 'tableHead' : 'tableCell',
105819
105858
  })),
105820
105859
  type: 'tableRow',
@@ -107690,7 +107729,7 @@ function preprocessContent(content, opts) {
107690
107729
  return processSnakeCaseComponent(result, { knownComponents });
107691
107730
  }
107692
107731
  function mdxishAstProcessor(mdContent, opts = {}) {
107693
- const { components: userComponents = {}, newEditorTypes = false, safeMode = false, useTailwind } = opts;
107732
+ const { components: userComponents = {}, hardBreaks: enableHardBreaks = true, newEditorTypes = false, safeMode = false, useTailwind, } = opts;
107694
107733
  const components = {
107695
107734
  ...loadComponents(),
107696
107735
  ...userComponents,
@@ -107719,7 +107758,7 @@ function mdxishAstProcessor(mdContent, opts = {}) {
107719
107758
  // The next few transformers must appear after mdxishMdxComponentBlocks
107720
107759
  // so nodes produced by the inline re-parse of component bodies
107721
107760
  // (e.g. code/image/embed inside <Tabs>) get visited too
107722
- .use(magic_block_transformer)
107761
+ .use(magic_block_transformer, { hardBreaks: enableHardBreaks })
107723
107762
  .use(transform_images, { isMdxish: true })
107724
107763
  .use(defaultTransformers)
107725
107764
  .use(newEditorTypes ? inline_mdx_blocks : undefined) // Merge inline html components (e.g. <Anchor>) into MDAST nodes
@@ -107776,7 +107815,7 @@ function mdxishMdastToMd(mdast) {
107776
107815
  * @see .claude/context/MDXish/Processor Overview.md
107777
107816
  */
107778
107817
  function mdxish(mdContent, opts = {}) {
107779
- const { components: userComponents = {}, safeMode = false, variables } = opts;
107818
+ const { components: userComponents = {}, hardBreaks: enableHardBreaks = true, safeMode = false, variables } = opts;
107780
107819
  const components = {
107781
107820
  ...loadComponents(),
107782
107821
  ...userComponents,
@@ -107788,7 +107827,7 @@ function mdxish(mdContent, opts = {}) {
107788
107827
  const { processor, parserReadyContent } = mdxishAstProcessor(contentWithoutComments, opts);
107789
107828
  processor
107790
107829
  .use(safeMode ? undefined : evaluate_exports) // Evaluate `export const/function` and stash scope on file.data.mdxishScope
107791
- .use(hard_breaks) // Must precede evaluateExpressions to avoid splitting the \n in an evaluated template literal into a <br> node
107830
+ .use(enableHardBreaks ? hard_breaks : undefined) // Must precede evaluateExpressions to avoid splitting the \n in an evaluated template literal into a <br> node
107792
107831
  .use(safeMode ? undefined : evaluate_expressions) // Evaluate self-contained MDX expressions (e.g. `{1+1}`)
107793
107832
  .use(safeMode ? undefined : evaluate_style_block_expressions) // Evaluate `<style>{`...`}</style>` template literals into plain CSS
107794
107833
  .use(variables_code, { variables }) // Resolve <<...>> and {user.*} inside code and inline code nodes
package/dist/main.node.js CHANGED
@@ -25260,7 +25260,7 @@ async function loadStylesheet(id, base) {
25260
25260
  async function loadModule() {
25261
25261
  throw new Error('The browser build does not support plugins or config files.');
25262
25262
  }
25263
- async function createCompiler({ darkModeDataAttribute }) {
25263
+ async function createCompiler({ darkModeDataAttribute, darkModeRootSelector, }) {
25264
25264
  let css = `
25265
25265
  @layer theme, base, components, utilities;
25266
25266
 
@@ -25268,9 +25268,12 @@ async function createCompiler({ darkModeDataAttribute }) {
25268
25268
  @import "tailwindcss/utilities.css" layer(utilities);
25269
25269
  `;
25270
25270
  if (darkModeDataAttribute) {
25271
+ // Anchors `dark:` to `darkModeRootSelector`'s own attribute instead of any ancestor's,
25272
+ // when supplied — see the `darkModeRootSelector` param doc below for why there's no default.
25273
+ const root = darkModeRootSelector || '';
25271
25274
  css += `
25272
25275
 
25273
- @custom-variant dark (&:where([${darkModeDataAttribute}=dark], [${darkModeDataAttribute}=dark] *));`;
25276
+ @custom-variant dark (&:where(${root}[${darkModeDataAttribute}=dark], ${root}[${darkModeDataAttribute}=dark] *));`;
25274
25277
  }
25275
25278
  return Hu(css, {
25276
25279
  base: '/',
@@ -25278,8 +25281,8 @@ async function createCompiler({ darkModeDataAttribute }) {
25278
25281
  loadModule,
25279
25282
  });
25280
25283
  }
25281
- async function tailwindCompiler(classes, { prefix, darkModeDataAttribute }) {
25282
- const compiler = await createCompiler({ darkModeDataAttribute });
25284
+ async function tailwindCompiler(classes, { prefix, darkModeDataAttribute, darkModeRootSelector, }) {
25285
+ const compiler = await createCompiler({ darkModeDataAttribute, darkModeRootSelector });
25283
25286
  const css = compiler.build(Array.from(classes));
25284
25287
  return lib_postcss([postcss_prefix_selector_default()({ prefix })]).process(css, { from: undefined });
25285
25288
  }
@@ -25294,7 +25297,7 @@ const traverse = (node, callback) => {
25294
25297
  traverse(child, callback);
25295
25298
  });
25296
25299
  };
25297
- const TailwindStyle = ({ children, darkModeDataAttribute }) => {
25300
+ const TailwindStyle = ({ children, darkModeDataAttribute, darkModeRootSelector }) => {
25298
25301
  const [stylesheet, setStylesheet] = (0,external_react_.useState)('');
25299
25302
  const classesSet = (0,external_react_.useRef)(new Set());
25300
25303
  const ref = (0,external_react_.useRef)(null);
@@ -25318,6 +25321,7 @@ const TailwindStyle = ({ children, darkModeDataAttribute }) => {
25318
25321
  const sheet = await tailwindCompiler(classes, {
25319
25322
  prefix: `.${tailwindPrefix}`,
25320
25323
  darkModeDataAttribute,
25324
+ darkModeRootSelector,
25321
25325
  });
25322
25326
  /* @note: don't insert an empty stylesheet */
25323
25327
  if (sheet.css.match(/^@layer utilities;/m))
@@ -25325,7 +25329,7 @@ const TailwindStyle = ({ children, darkModeDataAttribute }) => {
25325
25329
  setStylesheet(sheet.css);
25326
25330
  };
25327
25331
  run();
25328
- }, [classes, darkModeDataAttribute]);
25332
+ }, [classes, darkModeDataAttribute, darkModeRootSelector]);
25329
25333
  /*
25330
25334
  * @note: execute once on load
25331
25335
  */
@@ -95982,6 +95986,7 @@ var allCSS2RNProps = __webpack_unused_export__ = flatten([allProps, CSS2RNProps]
95982
95986
 
95983
95987
 
95984
95988
 
95989
+
95985
95990
  /**
95986
95991
  * Extract word boundaries from camelCase strings (e.g., "borderWidth" -> ["border", "width"])
95987
95992
  */
@@ -96061,10 +96066,43 @@ const CUSTOM_PROP_BOUNDARIES = [
96061
96066
  */
96062
96067
  const RUNTIME_COMPONENT_TAGS = new Set(['Variable', 'variable', 'html-block', 'rdme-pin']);
96063
96068
  /**
96064
- * Standard HTML tags that should never be treated as custom components.
96065
- * Uses the html-tags package, converted to a Set<string> for efficient lookups.
96069
+ * Elements that are not actually standard HTML tags, or those that we intentionally
96070
+ * don't want to treat as one & is mute to check with. These include:
96071
+ * - SVG/MathML descendants
96072
+ * - Namespaced foreign content
96073
+ * - `image`, which the HTML tree builder rewrites to `img`
96074
+ * Most of these are bundled in parse5's `TAG_NAMES` set, but we can also add a few more.
96066
96075
  */
96067
- const STANDARD_HTML_TAGS = new Set(html_tags_namespaceObject);
96076
+ const NON_STANDARD_TAGS = new Set([
96077
+ 'annotation-xml',
96078
+ 'desc',
96079
+ 'foreignObject',
96080
+ 'image',
96081
+ 'malignmark',
96082
+ 'mglyph',
96083
+ 'mi',
96084
+ 'mn',
96085
+ 'mo',
96086
+ 'ms',
96087
+ 'mtext',
96088
+ ]);
96089
+ /**
96090
+ * Standard HTML tags list.
96091
+ * A use case of this is to differentiate custom components tag vs standard HTML tags.
96092
+ *
96093
+ * Unioned from:
96094
+ * - `html-tags`: All modern spec HTML elements
96095
+ * - parse5's `TAG_NAMES`: Elements the HTML tree-construction algorithm has to special-case
96096
+ * This includes obsolete tags that are still rendered by browsers.
96097
+ * - NON_STANDARD_TAGS: We've had to filter because currently parse5's `TAG_NAMES` set over-enumerates
96098
+ * tags that are not actually standard HTML tags. It also allows custom tags to be filtered out.
96099
+ */
96100
+ const STANDARD_HTML_TAGS = new Set([
96101
+ ...html_tags_namespaceObject,
96102
+ ...Object.values(TAG_NAMES),
96103
+ 'acronym', // Obselete tag not included either of the above sources. Add here if we have missed any.
96104
+ 'blink',
96105
+ ].filter(tag => !NON_STANDARD_TAGS.has(tag)));
96068
96106
  /**
96069
96107
  * Table structural tags. Blank lines inside these carry deliberate meaning for
96070
96108
  * `mdxishTables` (e.g. splitting cell content into paragraphs, or deciding
@@ -125534,8 +125572,11 @@ var variable_dist_default = /*#__PURE__*/__webpack_require__.n(variable_dist);
125534
125572
  const HTML_TAG_RE = /<\/?([a-zA-Z][a-zA-Z0-9-]*)((?:[^>"']*(?:"[^"]*"|'[^']*'))*[^>"']*)>/g;
125535
125573
  /** Matches an HTML element from its opening tag to the matching closing tag. */
125536
125574
  const HTML_ELEMENT_BLOCK_RE = /<([a-zA-Z][a-zA-Z0-9-]*)[\s>][\s\S]*?<\/\1>/g;
125575
+ const NEWLINE_RE = /\n/g;
125537
125576
  /** Matches a newline with surrounding horizontal whitespace. */
125538
125577
  const NEWLINE_WITH_WHITESPACE_RE = /[^\S\n]*\n[^\S\n]*/g;
125578
+ /** Matches a run of two or more newlines (a blank line) with surrounding horizontal whitespace. */
125579
+ const BLANK_LINE_RE = /[^\S\n]*\n(?:[^\S\n]*\n)+[^\S\n]*/g;
125539
125580
  /** Matches a closing block-level tag followed by non-tag text or by a newline then non-blank content. */
125540
125581
  const CLOSE_BLOCK_TAG_BOUNDARY_RE = /<\/([a-zA-Z][a-zA-Z0-9-]*)>\s*(?:(?!<)(\S)|\n([^\n]))/g;
125541
125582
  /** Strips HTML open/close tags. Used to detect non-tag inner text content. */
@@ -125605,7 +125646,6 @@ const EMPTY_CODE_PLACEHOLDER = {
125605
125646
 
125606
125647
 
125607
125648
 
125608
-
125609
125649
  /**
125610
125650
  * Wraps a node in a "pinned" container if sidebar: true is set.
125611
125651
  */
@@ -125640,16 +125680,13 @@ const textToBlock = (text) => [{ children: textToInline(text), type: 'paragraph'
125640
125680
  */
125641
125681
  const ensureLeadingBreaks = (text) => text.replace(/^\n+/, match => '<br>'.repeat(match.length));
125642
125682
  /** Preprocesses magic block body content before parsing. */
125643
- const preprocessBody = (text) => {
125644
- return ensureLeadingBreaks(text);
125645
- };
125683
+ const preprocessBody = (text, hardBreaks) => (hardBreaks ? ensureLeadingBreaks(text) : text);
125646
125684
  const bodyExtensions = mdxishExtensions(FEATURES.magicBlockBody);
125647
125685
  /** Markdown parser */
125648
125686
  const contentParser = unified()
125649
125687
  .data('micromarkExtensions', bodyExtensions.micromarkExtensions)
125650
125688
  .data('fromMarkdownExtensions', bodyExtensions.fromMarkdownExtensions)
125651
125689
  .use(remarkParse)
125652
- .use(hard_breaks)
125653
125690
  .use(remarkGfm)
125654
125691
  .use(normalize_malformed_md_syntax);
125655
125692
  /**
@@ -125746,17 +125783,21 @@ const processMarkdownInHtmlString = (html) => {
125746
125783
  /**
125747
125784
  * Separate a closing block-level tag from the content that follows it.
125748
125785
  *
125749
- * Each \n in the original text becomes a <br> tag to preserve spacing, then a
125750
- * blank line (\n\n) is appended so CommonMark ends the HTML block and parses
125751
- * the following content as markdown.
125786
+ * A blank line (\n\n) is appended so CommonMark ends the HTML block and parses the
125787
+ * following content as markdown; with hard breaks each \n also becomes a <br> to keep its spacing.
125752
125788
  */
125753
- const separateBlockTagFromContent = (match, tag, inlineChar, nextLineChar) => {
125789
+ const separateBlockTagFromContent = (hardBreaks, match, tag, inlineChar, nextLineChar) => {
125754
125790
  if (!BLOCK_LEVEL_TAGS.has(tag.toLowerCase()))
125755
125791
  return match;
125756
- const newlineCount = (match.match(/\n/g) ?? []).length;
125792
+ const newlineCount = hardBreaks ? (match.match(NEWLINE_RE) ?? []).length : 0;
125757
125793
  const breaks = '<br>'.repeat(newlineCount);
125758
125794
  return `</${tag}>${breaks}\n\n${inlineChar || nextLineChar}`;
125759
125795
  };
125796
+ /**
125797
+ * Newlines inside an HTML block become <br> so CommonMark doesn't end the block on a blank
125798
+ * line. Without hard breaks only blank lines break, but they still have to be replaced.
125799
+ */
125800
+ const collapseHtmlBlockNewlines = (html, hardBreaks) => html.replace(hardBreaks ? NEWLINE_WITH_WHITESPACE_RE : BLANK_LINE_RE, '<br>');
125760
125801
  /** Escape a leading (possibly indented) `-`/`*`/`+` so cells don't become bullet lists. */
125761
125802
  const escapeLeadingListMarkers = (text) => text.replace(/^([ \t]*)([-*+])(?=[ \t]|$)/gm, '$1\\$2');
125762
125803
  /**
@@ -125764,15 +125805,13 @@ const escapeLeadingListMarkers = (text) => text.replace(/^([ \t]*)([-*+])(?=[ \t
125764
125805
  * so `<ul><li>_text_</li></ul>` won't convert underscores to emphasis.
125765
125806
  * We parse first, then visit html nodes and process their text content.
125766
125807
  */
125767
- const parseTableCell = (text) => {
125808
+ const parseTableCell = (text, hardBreaks) => {
125768
125809
  if (!text.trim())
125769
125810
  return [{ type: 'text', value: '' }];
125770
- // Convert \n (and surrounding whitespace) to <br> inside HTML blocks so
125771
- // CommonMark doesn't split them on blank lines.
125772
125811
  const escaped = processBackslashEscapes(text);
125773
125812
  const normalized = escaped
125774
- .replace(HTML_ELEMENT_BLOCK_RE, match => match.replace(NEWLINE_WITH_WHITESPACE_RE, '<br>'))
125775
- .replace(CLOSE_BLOCK_TAG_BOUNDARY_RE, separateBlockTagFromContent);
125813
+ .replace(HTML_ELEMENT_BLOCK_RE, match => collapseHtmlBlockNewlines(match, hardBreaks))
125814
+ .replace(CLOSE_BLOCK_TAG_BOUNDARY_RE, (match, tag, inlineChar, nextLineChar) => separateBlockTagFromContent(hardBreaks, match, tag, inlineChar, nextLineChar));
125776
125815
  const processed = escapeLeadingListMarkers(normalized);
125777
125816
  const tree = contentParser.runSync(contentParser.parse(processed));
125778
125817
  // Process markdown inside HTML blocks that have non-tag inner text (e.g. `<div>**x**`
@@ -125821,7 +125860,7 @@ const parseApiHeaderTitle = (text) => {
125821
125860
  * Transform a magicBlock node into final MDAST nodes.
125822
125861
  */
125823
125862
  function transformMagicBlock(blockType, data, rawValue, options = {}) {
125824
- const { compatibilityMode = false, safeMode = false } = options;
125863
+ const { compatibilityMode = false, hardBreaks = true, safeMode = false } = options;
125825
125864
  // Handle empty data by returning placeholder nodes for known block types
125826
125865
  // This allows the editor to show appropriate placeholder UI instead of nothing
125827
125866
  if (Object.keys(data).length < 1) {
@@ -125960,7 +125999,7 @@ function transformMagicBlock(blockType, data, rawValue, options = {}) {
125960
125999
  });
125961
126000
  }
125962
126001
  if (hasBody) {
125963
- const bodyBlocks = parseBlock(preprocessBody(calloutJson.body || ''));
126002
+ const bodyBlocks = parseBlock(preprocessBody(calloutJson.body || '', hardBreaks));
125964
126003
  children.push(...bodyBlocks);
125965
126004
  }
125966
126005
  const calloutElement = {
@@ -125992,12 +126031,12 @@ function transformMagicBlock(blockType, data, rawValue, options = {}) {
125992
126031
  mapped[rowIndex][colIndex] = v;
125993
126032
  return mapped;
125994
126033
  }, []);
125995
- const tokenizeCell = compatibilityMode
125996
- ? textToBlock
125997
- : parseTableCell;
126034
+ const tokenizeCell = compatibilityMode ? textToBlock : (text) => parseTableCell(text, hardBreaks);
125998
126035
  const tableChildren = Array.from({ length: rows + 1 }, (_, y) => ({
125999
126036
  children: Array.from({ length: cols }, (__, x) => ({
126000
- children: sparseData[y]?.[x] ? tokenizeCell(preprocessBody(sparseData[y][x])) : [{ type: 'text', value: '' }],
126037
+ children: sparseData[y]?.[x]
126038
+ ? tokenizeCell(preprocessBody(sparseData[y][x], hardBreaks))
126039
+ : [{ type: 'text', value: '' }],
126001
126040
  type: y === 0 ? 'tableHead' : 'tableCell',
126002
126041
  })),
126003
126042
  type: 'tableRow',
@@ -127873,7 +127912,7 @@ function preprocessContent(content, opts) {
127873
127912
  return processSnakeCaseComponent(result, { knownComponents });
127874
127913
  }
127875
127914
  function mdxishAstProcessor(mdContent, opts = {}) {
127876
- const { components: userComponents = {}, newEditorTypes = false, safeMode = false, useTailwind } = opts;
127915
+ const { components: userComponents = {}, hardBreaks: enableHardBreaks = true, newEditorTypes = false, safeMode = false, useTailwind, } = opts;
127877
127916
  const components = {
127878
127917
  ...loadComponents(),
127879
127918
  ...userComponents,
@@ -127902,7 +127941,7 @@ function mdxishAstProcessor(mdContent, opts = {}) {
127902
127941
  // The next few transformers must appear after mdxishMdxComponentBlocks
127903
127942
  // so nodes produced by the inline re-parse of component bodies
127904
127943
  // (e.g. code/image/embed inside <Tabs>) get visited too
127905
- .use(magic_block_transformer)
127944
+ .use(magic_block_transformer, { hardBreaks: enableHardBreaks })
127906
127945
  .use(transform_images, { isMdxish: true })
127907
127946
  .use(defaultTransformers)
127908
127947
  .use(newEditorTypes ? inline_mdx_blocks : undefined) // Merge inline html components (e.g. <Anchor>) into MDAST nodes
@@ -127959,7 +127998,7 @@ function mdxishMdastToMd(mdast) {
127959
127998
  * @see .claude/context/MDXish/Processor Overview.md
127960
127999
  */
127961
128000
  function mdxish(mdContent, opts = {}) {
127962
- const { components: userComponents = {}, safeMode = false, variables } = opts;
128001
+ const { components: userComponents = {}, hardBreaks: enableHardBreaks = true, safeMode = false, variables } = opts;
127963
128002
  const components = {
127964
128003
  ...loadComponents(),
127965
128004
  ...userComponents,
@@ -127971,7 +128010,7 @@ function mdxish(mdContent, opts = {}) {
127971
128010
  const { processor, parserReadyContent } = mdxishAstProcessor(contentWithoutComments, opts);
127972
128011
  processor
127973
128012
  .use(safeMode ? undefined : evaluate_exports) // Evaluate `export const/function` and stash scope on file.data.mdxishScope
127974
- .use(hard_breaks) // Must precede evaluateExpressions to avoid splitting the \n in an evaluated template literal into a <br> node
128013
+ .use(enableHardBreaks ? hard_breaks : undefined) // Must precede evaluateExpressions to avoid splitting the \n in an evaluated template literal into a <br> node
127975
128014
  .use(safeMode ? undefined : evaluate_expressions) // Evaluate self-contained MDX expressions (e.g. `{1+1}`)
127976
128015
  .use(safeMode ? undefined : evaluate_style_block_expressions) // Evaluate `<style>{`...`}</style>` template literals into plain CSS
127977
128016
  .use(variables_code, { variables }) // Resolve <<...>> and {user.*} inside code and inline code nodes