Latest repo

This commit is contained in:
Marc
2025-06-02 16:42:16 +00:00
parent 53ddf1a329
commit cde5fae175
27907 changed files with 3875388 additions and 1 deletions

8
node_modules/react-markdown/index.d.ts generated vendored Normal file
View File

@@ -0,0 +1,8 @@
export type AllowElement = import("./lib/index.js").AllowElement;
export type Components = import("./lib/index.js").Components;
export type ExtraProps = import("./lib/index.js").ExtraProps;
export type HooksOptions = import("./lib/index.js").HooksOptions;
export type Options = import("./lib/index.js").Options;
export type UrlTransform = import("./lib/index.js").UrlTransform;
export { MarkdownAsync, MarkdownHooks, Markdown as default, defaultUrlTransform } from "./lib/index.js";
//# sourceMappingURL=index.d.ts.map

1
node_modules/react-markdown/index.d.ts.map generated vendored Normal file
View File

@@ -0,0 +1 @@
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["index.js"],"names":[],"mappings":"2BACa,OAAO,gBAAgB,EAAE,YAAY;yBACrC,OAAO,gBAAgB,EAAE,UAAU;yBACnC,OAAO,gBAAgB,EAAE,UAAU;2BACnC,OAAO,gBAAgB,EAAE,YAAY;sBACrC,OAAO,gBAAgB,EAAE,OAAO;2BAChC,OAAO,gBAAgB,EAAE,YAAY"}

15
node_modules/react-markdown/index.js generated vendored Normal file
View File

@@ -0,0 +1,15 @@
/**
* @typedef {import('./lib/index.js').AllowElement} AllowElement
* @typedef {import('./lib/index.js').Components} Components
* @typedef {import('./lib/index.js').ExtraProps} ExtraProps
* @typedef {import('./lib/index.js').HooksOptions} HooksOptions
* @typedef {import('./lib/index.js').Options} Options
* @typedef {import('./lib/index.js').UrlTransform} UrlTransform
*/
export {
MarkdownAsync,
MarkdownHooks,
Markdown as default,
defaultUrlTransform
} from './lib/index.js'

166
node_modules/react-markdown/lib/index.d.ts generated vendored Normal file
View File

@@ -0,0 +1,166 @@
/**
* Component to render markdown.
*
* This is a synchronous component.
* When using async plugins,
* see {@linkcode MarkdownAsync} or {@linkcode MarkdownHooks}.
*
* @param {Readonly<Options>} options
* Props.
* @returns {ReactElement}
* React element.
*/
export function Markdown(options: Readonly<Options>): ReactElement;
/**
* Component to render markdown with support for async plugins
* through async/await.
*
* Components returning promises are supported on the server.
* For async support on the client,
* see {@linkcode MarkdownHooks}.
*
* @param {Readonly<Options>} options
* Props.
* @returns {Promise<ReactElement>}
* Promise to a React element.
*/
export function MarkdownAsync(options: Readonly<Options>): Promise<ReactElement>;
/**
* Component to render markdown with support for async plugins through hooks.
*
* This uses `useEffect` and `useState` hooks.
* Hooks run on the client and do not immediately render something.
* For async support on the server,
* see {@linkcode MarkdownAsync}.
*
* @param {Readonly<HooksOptions>} options
* Props.
* @returns {ReactNode}
* React node.
*/
export function MarkdownHooks(options: Readonly<HooksOptions>): ReactNode;
/**
* Make a URL safe.
*
* @satisfies {UrlTransform}
* @param {string} value
* URL.
* @returns {string}
* Safe URL.
*/
export function defaultUrlTransform(value: string): string;
/**
* Filter elements.
*/
export type AllowElement = (element: Readonly<Element>, index: number, parent: Readonly<Parents> | undefined) => boolean | null | undefined;
/**
* Extra fields we pass.
*/
export type ExtraProps = {
/**
* passed when `passNode` is on.
*/
node?: Element | undefined;
};
/**
* Map tag names to components.
*/
export type Components = { [Key in keyof JSX.IntrinsicElements]?: ComponentType<JSX.IntrinsicElements[Key] & ExtraProps> | keyof JSX.IntrinsicElements; };
/**
* Deprecation.
*/
export type Deprecation = {
/**
* Old field.
*/
from: string;
/**
* ID in readme.
*/
id: string;
/**
* New field.
*/
to?: keyof Options;
};
/**
* Configuration.
*/
export type Options = {
/**
* Filter elements (optional);
* `allowedElements` / `disallowedElements` is used first.
*/
allowElement?: AllowElement | null | undefined;
/**
* Tag names to allow (default: all tag names);
* cannot combine w/ `disallowedElements`.
*/
allowedElements?: ReadonlyArray<string> | null | undefined;
/**
* Markdown.
*/
children?: string | null | undefined;
/**
* Map tag names to components.
*/
components?: Components | null | undefined;
/**
* Tag names to disallow (default: `[]`);
* cannot combine w/ `allowedElements`.
*/
disallowedElements?: ReadonlyArray<string> | null | undefined;
/**
* List of rehype plugins to use.
*/
rehypePlugins?: PluggableList | null | undefined;
/**
* List of remark plugins to use.
*/
remarkPlugins?: PluggableList | null | undefined;
/**
* Options to pass through to `remark-rehype`.
*/
remarkRehypeOptions?: Readonly<RemarkRehypeOptions> | null | undefined;
/**
* Ignore HTML in markdown completely (default: `false`).
*/
skipHtml?: boolean | null | undefined;
/**
* Extract (unwrap) whats in disallowed elements (default: `false`);
* normally when say `strong` is not allowed, it and its children are dropped,
* with `unwrapDisallowed` the element itself is replaced by its children.
*/
unwrapDisallowed?: boolean | null | undefined;
/**
* Change URLs (default: `defaultUrlTransform`)
*/
urlTransform?: UrlTransform | null | undefined;
};
/**
* Configuration specifically for {@linkcode MarkdownHooks}.
*/
export type HooksOptionsOnly = {
/**
* Content to render while the processor processing the markdown (optional).
*/
fallback?: ReactNode | null | undefined;
};
/**
* Configuration for {@linkcode MarkdownHooks};
* extends the regular {@linkcode Options} with a `fallback` prop.
*/
export type HooksOptions = Options & HooksOptionsOnly;
/**
* Transform all URLs.
*/
export type UrlTransform = (url: string, key: string, node: Readonly<Element>) => string | null | undefined;
import type { ReactElement } from 'react';
import type { ReactNode } from 'react';
import type { Element } from 'hast';
import type { Parents } from 'hast';
import type { JSX } from 'react';
import type { ComponentType } from 'react';
import type { PluggableList } from 'unified';
import type { Options as RemarkRehypeOptions } from 'remark-rehype';
//# sourceMappingURL=index.d.ts.map

1
node_modules/react-markdown/lib/index.d.ts.map generated vendored Normal file
View File

@@ -0,0 +1 @@
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["index.js"],"names":[],"mappings":"AAkKA;;;;;;;;;;;GAWG;AACH,kCALW,QAAQ,CAAC,OAAO,CAAC,GAEf,YAAY,CAOxB;AAED;;;;;;;;;;;;GAYG;AACH,uCALW,QAAQ,CAAC,OAAO,CAAC,GAEf,OAAO,CAAC,YAAY,CAAC,CAQjC;AAED;;;;;;;;;;;;GAYG;AACH,uCALW,QAAQ,CAAC,YAAY,CAAC,GAEpB,SAAS,CAyCrB;AAgKD;;;;;;;;GAQG;AACH,2CALW,MAAM,GAEJ,MAAM,CA0BlB;;;;qCA/aU,QAAQ,CAAC,OAAO,CAAC,SAEjB,MAAM,UAEN,QAAQ,CAAC,OAAO,CAAC,GAAG,SAAS,KAE3B,OAAO,GAAG,IAAI,GAAG,SAAS;;;;;;;;WAOzB,OAAO,GAAG,SAAS;;;;;yBAKpB,GACP,GAAG,IAAI,MAAM,qBAAqB,CAAC,CAAC,EAAE,cAAc,qBAAqB,CAAC,GAAG,CAAC,GAAG,UAAU,CAAC,GAAG,MAAM,qBAAqB,GAC5H;;;;;;;;UAOU,MAAM;;;;QAEN,MAAM;;;;SAEN,MAAM,OAAO;;;;;;;;;;mBAOb,YAAY,GAAG,IAAI,GAAG,SAAS;;;;;sBAG/B,aAAa,CAAC,MAAM,CAAC,GAAG,IAAI,GAAG,SAAS;;;;eAGxC,MAAM,GAAG,IAAI,GAAG,SAAS;;;;iBAEzB,UAAU,GAAG,IAAI,GAAG,SAAS;;;;;yBAE7B,aAAa,CAAC,MAAM,CAAC,GAAG,IAAI,GAAG,SAAS;;;;oBAGxC,aAAa,GAAG,IAAI,GAAG,SAAS;;;;oBAEhC,aAAa,GAAG,IAAI,GAAG,SAAS;;;;0BAEhC,QAAQ,CAAC,mBAAmB,CAAC,GAAG,IAAI,GAAG,SAAS;;;;eAEhD,OAAO,GAAG,IAAI,GAAG,SAAS;;;;;;uBAE1B,OAAO,GAAG,IAAI,GAAG,SAAS;;;;mBAI1B,YAAY,GAAG,IAAI,GAAG,SAAS;;;;;;;;;eAO/B,SAAS,GAAG,IAAI,GAAG,SAAS;;;;;;2BAK7B,OAAO,GAAG,gBAAgB;;;;iCAQ5B,MAAM,OAEN,MAAM,QAEN,QAAQ,CAAC,OAAO,CAAC,KAEf,MAAM,GAAG,IAAI,GAAG,SAAS;kCAlGwB,OAAO;+BAAP,OAAO;6BAFrB,MAAM;6BAAN,MAAM;yBAEQ,OAAO;mCAAP,OAAO;mCAG1B,SAAS;oDAFH,eAAe"}

444
node_modules/react-markdown/lib/index.js generated vendored Normal file
View File

@@ -0,0 +1,444 @@
/**
* @import {Element, Nodes, Parents, Root} from 'hast'
* @import {Root as MdastRoot} from 'mdast'
* @import {ComponentType, JSX, ReactElement, ReactNode} from 'react'
* @import {Options as RemarkRehypeOptions} from 'remark-rehype'
* @import {BuildVisitor} from 'unist-util-visit'
* @import {PluggableList, Processor} from 'unified'
*/
/**
* @callback AllowElement
* Filter elements.
* @param {Readonly<Element>} element
* Element to check.
* @param {number} index
* Index of `element` in `parent`.
* @param {Readonly<Parents> | undefined} parent
* Parent of `element`.
* @returns {boolean | null | undefined}
* Whether to allow `element` (default: `false`).
*/
/**
* @typedef ExtraProps
* Extra fields we pass.
* @property {Element | undefined} [node]
* passed when `passNode` is on.
*/
/**
* @typedef {{
* [Key in keyof JSX.IntrinsicElements]?: ComponentType<JSX.IntrinsicElements[Key] & ExtraProps> | keyof JSX.IntrinsicElements
* }} Components
* Map tag names to components.
*/
/**
* @typedef Deprecation
* Deprecation.
* @property {string} from
* Old field.
* @property {string} id
* ID in readme.
* @property {keyof Options} [to]
* New field.
*/
/**
* @typedef Options
* Configuration.
* @property {AllowElement | null | undefined} [allowElement]
* Filter elements (optional);
* `allowedElements` / `disallowedElements` is used first.
* @property {ReadonlyArray<string> | null | undefined} [allowedElements]
* Tag names to allow (default: all tag names);
* cannot combine w/ `disallowedElements`.
* @property {string | null | undefined} [children]
* Markdown.
* @property {Components | null | undefined} [components]
* Map tag names to components.
* @property {ReadonlyArray<string> | null | undefined} [disallowedElements]
* Tag names to disallow (default: `[]`);
* cannot combine w/ `allowedElements`.
* @property {PluggableList | null | undefined} [rehypePlugins]
* List of rehype plugins to use.
* @property {PluggableList | null | undefined} [remarkPlugins]
* List of remark plugins to use.
* @property {Readonly<RemarkRehypeOptions> | null | undefined} [remarkRehypeOptions]
* Options to pass through to `remark-rehype`.
* @property {boolean | null | undefined} [skipHtml=false]
* Ignore HTML in markdown completely (default: `false`).
* @property {boolean | null | undefined} [unwrapDisallowed=false]
* Extract (unwrap) whats in disallowed elements (default: `false`);
* normally when say `strong` is not allowed, it and its children are dropped,
* with `unwrapDisallowed` the element itself is replaced by its children.
* @property {UrlTransform | null | undefined} [urlTransform]
* Change URLs (default: `defaultUrlTransform`)
*/
/**
* @typedef HooksOptionsOnly
* Configuration specifically for {@linkcode MarkdownHooks}.
* @property {ReactNode | null | undefined} [fallback]
* Content to render while the processor processing the markdown (optional).
*/
/**
* @typedef {Options & HooksOptionsOnly} HooksOptions
* Configuration for {@linkcode MarkdownHooks};
* extends the regular {@linkcode Options} with a `fallback` prop.
*/
/**
* @callback UrlTransform
* Transform all URLs.
* @param {string} url
* URL.
* @param {string} key
* Property name (example: `'href'`).
* @param {Readonly<Element>} node
* Node.
* @returns {string | null | undefined}
* Transformed URL (optional).
*/
import {unreachable} from 'devlop'
import {toJsxRuntime} from 'hast-util-to-jsx-runtime'
import {urlAttributes} from 'html-url-attributes'
import {Fragment, jsx, jsxs} from 'react/jsx-runtime'
import {useEffect, useState} from 'react'
import remarkParse from 'remark-parse'
import remarkRehype from 'remark-rehype'
import {unified} from 'unified'
import {visit} from 'unist-util-visit'
import {VFile} from 'vfile'
const changelog =
'https://github.com/remarkjs/react-markdown/blob/main/changelog.md'
/** @type {PluggableList} */
const emptyPlugins = []
/** @type {Readonly<RemarkRehypeOptions>} */
const emptyRemarkRehypeOptions = {allowDangerousHtml: true}
const safeProtocol = /^(https?|ircs?|mailto|xmpp)$/i
// Mutable because we `delete` any time its used and a message is sent.
/** @type {ReadonlyArray<Readonly<Deprecation>>} */
const deprecations = [
{from: 'astPlugins', id: 'remove-buggy-html-in-markdown-parser'},
{from: 'allowDangerousHtml', id: 'remove-buggy-html-in-markdown-parser'},
{
from: 'allowNode',
id: 'replace-allownode-allowedtypes-and-disallowedtypes',
to: 'allowElement'
},
{
from: 'allowedTypes',
id: 'replace-allownode-allowedtypes-and-disallowedtypes',
to: 'allowedElements'
},
{from: 'className', id: 'remove-classname'},
{
from: 'disallowedTypes',
id: 'replace-allownode-allowedtypes-and-disallowedtypes',
to: 'disallowedElements'
},
{from: 'escapeHtml', id: 'remove-buggy-html-in-markdown-parser'},
{from: 'includeElementIndex', id: '#remove-includeelementindex'},
{
from: 'includeNodeIndex',
id: 'change-includenodeindex-to-includeelementindex'
},
{from: 'linkTarget', id: 'remove-linktarget'},
{from: 'plugins', id: 'change-plugins-to-remarkplugins', to: 'remarkPlugins'},
{from: 'rawSourcePos', id: '#remove-rawsourcepos'},
{from: 'renderers', id: 'change-renderers-to-components', to: 'components'},
{from: 'source', id: 'change-source-to-children', to: 'children'},
{from: 'sourcePos', id: '#remove-sourcepos'},
{from: 'transformImageUri', id: '#add-urltransform', to: 'urlTransform'},
{from: 'transformLinkUri', id: '#add-urltransform', to: 'urlTransform'}
]
/**
* Component to render markdown.
*
* This is a synchronous component.
* When using async plugins,
* see {@linkcode MarkdownAsync} or {@linkcode MarkdownHooks}.
*
* @param {Readonly<Options>} options
* Props.
* @returns {ReactElement}
* React element.
*/
export function Markdown(options) {
const processor = createProcessor(options)
const file = createFile(options)
return post(processor.runSync(processor.parse(file), file), options)
}
/**
* Component to render markdown with support for async plugins
* through async/await.
*
* Components returning promises are supported on the server.
* For async support on the client,
* see {@linkcode MarkdownHooks}.
*
* @param {Readonly<Options>} options
* Props.
* @returns {Promise<ReactElement>}
* Promise to a React element.
*/
export async function MarkdownAsync(options) {
const processor = createProcessor(options)
const file = createFile(options)
const tree = await processor.run(processor.parse(file), file)
return post(tree, options)
}
/**
* Component to render markdown with support for async plugins through hooks.
*
* This uses `useEffect` and `useState` hooks.
* Hooks run on the client and do not immediately render something.
* For async support on the server,
* see {@linkcode MarkdownAsync}.
*
* @param {Readonly<HooksOptions>} options
* Props.
* @returns {ReactNode}
* React node.
*/
export function MarkdownHooks(options) {
const processor = createProcessor(options)
const [error, setError] = useState(
/** @type {Error | undefined} */ (undefined)
)
const [tree, setTree] = useState(/** @type {Root | undefined} */ (undefined))
useEffect(
function () {
let cancelled = false
const file = createFile(options)
processor.run(processor.parse(file), file, function (error, tree) {
if (!cancelled) {
setError(error)
setTree(tree)
}
})
/**
* @returns {undefined}
* Nothing.
*/
return function () {
cancelled = true
}
},
[
options.children,
options.rehypePlugins,
options.remarkPlugins,
options.remarkRehypeOptions
]
)
if (error) throw error
return tree ? post(tree, options) : options.fallback
}
/**
* Set up the `unified` processor.
*
* @param {Readonly<Options>} options
* Props.
* @returns {Processor<MdastRoot, MdastRoot, Root, undefined, undefined>}
* Result.
*/
function createProcessor(options) {
const rehypePlugins = options.rehypePlugins || emptyPlugins
const remarkPlugins = options.remarkPlugins || emptyPlugins
const remarkRehypeOptions = options.remarkRehypeOptions
? {...options.remarkRehypeOptions, ...emptyRemarkRehypeOptions}
: emptyRemarkRehypeOptions
const processor = unified()
.use(remarkParse)
.use(remarkPlugins)
.use(remarkRehype, remarkRehypeOptions)
.use(rehypePlugins)
return processor
}
/**
* Set up the virtual file.
*
* @param {Readonly<Options>} options
* Props.
* @returns {VFile}
* Result.
*/
function createFile(options) {
const children = options.children || ''
const file = new VFile()
if (typeof children === 'string') {
file.value = children
} else {
unreachable(
'Unexpected value `' +
children +
'` for `children` prop, expected `string`'
)
}
return file
}
/**
* Process the result from unified some more.
*
* @param {Nodes} tree
* Tree.
* @param {Readonly<Options>} options
* Props.
* @returns {ReactElement}
* React element.
*/
function post(tree, options) {
const allowedElements = options.allowedElements
const allowElement = options.allowElement
const components = options.components
const disallowedElements = options.disallowedElements
const skipHtml = options.skipHtml
const unwrapDisallowed = options.unwrapDisallowed
const urlTransform = options.urlTransform || defaultUrlTransform
for (const deprecation of deprecations) {
if (Object.hasOwn(options, deprecation.from)) {
unreachable(
'Unexpected `' +
deprecation.from +
'` prop, ' +
(deprecation.to
? 'use `' + deprecation.to + '` instead'
: 'remove it') +
' (see <' +
changelog +
'#' +
deprecation.id +
'> for more info)'
)
}
}
if (allowedElements && disallowedElements) {
unreachable(
'Unexpected combined `allowedElements` and `disallowedElements`, expected one or the other'
)
}
visit(tree, transform)
return toJsxRuntime(tree, {
Fragment,
components,
ignoreInvalidStyle: true,
jsx,
jsxs,
passKeys: true,
passNode: true
})
/** @type {BuildVisitor<Root>} */
function transform(node, index, parent) {
if (node.type === 'raw' && parent && typeof index === 'number') {
if (skipHtml) {
parent.children.splice(index, 1)
} else {
parent.children[index] = {type: 'text', value: node.value}
}
return index
}
if (node.type === 'element') {
/** @type {string} */
let key
for (key in urlAttributes) {
if (
Object.hasOwn(urlAttributes, key) &&
Object.hasOwn(node.properties, key)
) {
const value = node.properties[key]
const test = urlAttributes[key]
if (test === null || test.includes(node.tagName)) {
node.properties[key] = urlTransform(String(value || ''), key, node)
}
}
}
}
if (node.type === 'element') {
let remove = allowedElements
? !allowedElements.includes(node.tagName)
: disallowedElements
? disallowedElements.includes(node.tagName)
: false
if (!remove && allowElement && typeof index === 'number') {
remove = !allowElement(node, index, parent)
}
if (remove && parent && typeof index === 'number') {
if (unwrapDisallowed && node.children) {
parent.children.splice(index, 1, ...node.children)
} else {
parent.children.splice(index, 1)
}
return index
}
}
}
}
/**
* Make a URL safe.
*
* @satisfies {UrlTransform}
* @param {string} value
* URL.
* @returns {string}
* Safe URL.
*/
export function defaultUrlTransform(value) {
// Same as:
// <https://github.com/micromark/micromark/blob/929275e/packages/micromark-util-sanitize-uri/dev/index.js#L34>
// But without the `encode` part.
const colon = value.indexOf(':')
const questionMark = value.indexOf('?')
const numberSign = value.indexOf('#')
const slash = value.indexOf('/')
if (
// If there is no protocol, its relative.
colon === -1 ||
// If the first colon is after a `?`, `#`, or `/`, its not a protocol.
(slash !== -1 && colon > slash) ||
(questionMark !== -1 && colon > questionMark) ||
(numberSign !== -1 && colon > numberSign) ||
// It is a protocol, it should be allowed.
safeProtocol.test(value.slice(0, colon))
) {
return value
}
return ''
}

21
node_modules/react-markdown/license generated vendored Normal file
View File

@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) Espen Hovlandsdal
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

169
node_modules/react-markdown/package.json generated vendored Normal file
View File

@@ -0,0 +1,169 @@
{
"author": "Espen Hovlandsdal <espen@hovlandsdal.com>",
"bugs": "https://github.com/remarkjs/react-markdown/issues",
"contributors": [
"Alexander Wallin <office@alexanderwallin.com>",
"Alexander Wong <admin@alexander-wong.com>",
"André Staltz <andre@staltz.com>",
"Angus MacIsaac <angus.macisaac@busbud.com>",
"Beau Roberts <beau.roberts@autodesk.com>",
"Charlie Chen <doveccl@live.com>",
"Christian Murphy <christian.murphy.42@gmail.com>",
"Christoph Werner <christoph@codepunkt.de>",
"Danny <dannyharding10@gmail.com>",
"Dennis S <denis.s@svsg.co>",
"Espen Hovlandsdal <espen@hovlandsdal.com>",
"Evan Hensleigh <futuraprime@gmail.com>",
"Fabian Irsara <info@fabianirsara.com>",
"Florentin Luca Rieger <florentin.rieger@gmail.com>",
"Frank <frankieali4@gmail.com>",
"Igor Kamyshev <garik.novel@gmail.com>",
"Jack Williams <jsw547@gmail.com>",
"Jakub Chrzanowski <jakub@chrzanowski.info>",
"Jeremy Moseley <jeremy@jeremymoseley.net>",
"Jesse Pinho <jesse@jessepinho.com>",
"Kelvin Chan <kchan@securitycompass.com>",
"Kohei Asai <me@axross.io>",
"Linus Unnebäck <linus@folkdatorn.se>",
"Marshall Smith <marshall@radialdevgroup.com>",
"Nathan Bierema <nbierema@gmail.com>",
"Nicolas Venegas <nvenegas@atlassian.com>",
"Peng Guanwen <pg999w@outlook.com>",
"Petr Gazarov <petrgazarov@gmail.com>",
"Phil Rajchgot <tophil@outlook.com>",
"Rasmus Eneman <rasmus@eneman.eu>",
"René Kooi <renee@kooi.me>",
"Riku Rouvila <riku.rouvila@gmail.com>",
"Robin Wieruch <wrobin@gmx.net>",
"Rostyslav Melnychuk <blackswordgc@gmail.com>",
"Ted Piotrowski <tppiotrowski@gmail.com>",
"Thibaud Courtoison <do.not.press.enter@gmail.com>",
"Thomas Lindstrøm <t@hom.as>",
"Tiago Roldão <focus5.6@gmail.com>",
"Titus Wormer <tituswormer@gmail.com> (https://wooorm.com)",
"cerkiewny <mstarzycki@gmail.com>",
"evoye <rosej@gmx.net>",
"gRoberts84 <gavin@gav-roberts.co.uk>",
"mudrz <mudrz@outlook.com>",
"vanchagreen <vanchagreen@gmail.com>"
],
"dependencies": {
"@types/hast": "^3.0.0",
"@types/mdast": "^4.0.0",
"devlop": "^1.0.0",
"hast-util-to-jsx-runtime": "^2.0.0",
"html-url-attributes": "^3.0.0",
"mdast-util-to-hast": "^13.0.0",
"remark-parse": "^11.0.0",
"remark-rehype": "^11.0.0",
"unified": "^11.0.0",
"unist-util-visit": "^5.0.0",
"vfile": "^6.0.0"
},
"description": "React component to render markdown",
"devDependencies": {
"@testing-library/react": "^16.0.0",
"@types/node": "^22.0.0",
"@types/react": "^19.0.0",
"@types/react-dom": "^19.0.0",
"c8": "^10.0.0",
"concat-stream": "^2.0.0",
"esbuild": "^0.25.0",
"eslint-plugin-react": "^7.0.0",
"global-jsdom": "^26.0.0",
"prettier": "^3.0.0",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"rehype-raw": "^7.0.0",
"rehype-starry-night": "^2.0.0",
"remark-cli": "^12.0.0",
"remark-gfm": "^4.0.0",
"remark-preset-wooorm": "^11.0.0",
"remark-toc": "^9.0.0",
"type-coverage": "^2.0.0",
"typescript": "^5.0.0",
"xo": "^0.60.0"
},
"exports": "./index.js",
"files": [
"index.d.ts.map",
"index.d.ts",
"index.js",
"lib/"
],
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/unified"
},
"keywords": [
"ast",
"commonmark",
"component",
"gfm",
"markdown",
"react",
"react-component",
"remark",
"unified"
],
"license": "MIT",
"name": "react-markdown",
"peerDependencies": {
"@types/react": ">=18",
"react": ">=18"
},
"prettier": {
"bracketSpacing": false,
"singleQuote": true,
"semi": false,
"tabWidth": 2,
"trailingComma": "none",
"useTabs": false
},
"remarkConfig": {
"plugins": [
"remark-preset-wooorm",
[
"remark-lint-no-html",
false
]
]
},
"repository": "remarkjs/react-markdown",
"scripts": {
"build": "tsc --build --clean && tsc --build && type-coverage",
"format": "remark --frail --output --quiet -- . && prettier --log-level warn --write -- . && xo --fix",
"test-api": "node --conditions development --experimental-loader=./script/load-jsx.js --no-warnings test.jsx",
"test-coverage": "c8 --100 --exclude script/ --reporter lcov -- npm run test-api",
"test": "npm run build && npm run format && npm run test-coverage"
},
"sideEffects": false,
"typeCoverage": {
"atLeast": 100,
"strict": true
},
"type": "module",
"version": "10.1.0",
"xo": {
"envs": [
"shared-node-browser"
],
"extends": "plugin:react/jsx-runtime",
"overrides": [
{
"files": [
"**/*.jsx"
],
"rules": {
"no-unused-vars": "off"
}
}
],
"prettier": true,
"rules": {
"complexity": "off",
"n/file-extension-in-import": "off",
"unicorn/prevent-abbreviations": "off"
}
}
}

940
node_modules/react-markdown/readme.md generated vendored Normal file
View File

@@ -0,0 +1,940 @@
<!--
Notes for maintaining this document:
* update the version of the link for `commonmark-html` once in a while
-->
# react-markdown
[![Build][badge-build-image]][badge-build-url]
[![Coverage][badge-coverage-image]][badge-coverage-url]
[![Downloads][badge-downloads-image]][badge-downloads-url]
[![Size][badge-size-image]][badge-size-url]
React component to render markdown.
## Feature highlights
* [x] **[safe][section-security] by default**
(no `dangerouslySetInnerHTML` or XSS attacks)
* [x] **[components][section-components]**
(pass your own component to use instead of `<h2>` for `## hi`)
* [x] **[plugins][section-plugins]**
(many plugins you can pick and choose from)
* [x] **[compliant][section-syntax]**
(100% to CommonMark, 100% to GFM with a plugin)
## Contents
* [What is this?](#what-is-this)
* [When should I use this?](#when-should-i-use-this)
* [Install](#install)
* [Use](#use)
* [API](#api)
* [`Markdown`](#markdown)
* [`MarkdownAsync`](#markdownasync)
* [`MarkdownHooks`](#markdownhooks)
* [`defaultUrlTransform(url)`](#defaulturltransformurl)
* [`AllowElement`](#allowelement)
* [`Components`](#components)
* [`ExtraProps`](#extraprops)
* [`HooksOptions`](#hooksoptions)
* [`Options`](#options)
* [`UrlTransform`](#urltransform)
* [Examples](#examples)
* [Use a plugin](#use-a-plugin)
* [Use a plugin with options](#use-a-plugin-with-options)
* [Use custom components (syntax highlight)](#use-custom-components-syntax-highlight)
* [Use remark and rehype plugins (math)](#use-remark-and-rehype-plugins-math)
* [Plugins](#plugins)
* [Syntax](#syntax)
* [Compatibility](#compatibility)
* [Architecture](#architecture)
* [Appendix A: HTML in markdown](#appendix-a-html-in-markdown)
* [Appendix B: Components](#appendix-b-components)
* [Appendix C: line endings in markdown (and JSX)](#appendix-c-line-endings-in-markdown-and-jsx)
* [Security](#security)
* [Related](#related)
* [Contribute](#contribute)
* [License](#license)
## What is this?
This package is a [React][] component that can be given a string of markdown
that itll safely render to React elements.
You can pass plugins to change how markdown is transformed and pass components
that will be used instead of normal HTML elements.
* to learn markdown, see this [cheatsheet and tutorial][commonmark-help]
* to try out `react-markdown`, see [our demo][github-io-react-markdown]
## When should I use this?
There are other ways to use markdown in React out there so why use this one?
The three main reasons are that they often rely on `dangerouslySetInnerHTML`,
have bugs with how they handle markdown, or dont let you swap elements for
components.
`react-markdown` builds a virtual DOM, so React only replaces what changed,
from a syntax tree.
Thats supported because we use [unified][github-unified],
specifically [remark][github-remark] for markdown and [rehype][github-rehype]
for HTML,
which are popular tools to transform content with plugins.
This package focusses on making it easy for beginners to safely use markdown in
React.
When youre familiar with unified, you can use a modern hooks based alternative
[`react-remark`][github-react-remark] or [`rehype-react`][github-rehype-react]
manually.
If you instead want to use JavaScript and JSX *inside* markdown files, use
[MDX][github-mdx].
## Install
This package is [ESM only][esm].
In Node.js (version 16+), install with [npm][npm-install]:
```sh
npm install react-markdown
```
In Deno with [`esm.sh`][esmsh]:
```js
import Markdown from 'https://esm.sh/react-markdown@10'
```
In browsers with [`esm.sh`][esmsh]:
```html
<script type="module">
import Markdown from 'https://esm.sh/react-markdown@10?bundle'
</script>
```
## Use
A basic hello world:
```js
import React from 'react'
import {createRoot} from 'react-dom/client'
import Markdown from 'react-markdown'
const markdown = '# Hi, *Pluto*!'
createRoot(document.body).render(<Markdown>{markdown}</Markdown>)
```
<details>
<summary>Show equivalent JSX</summary>
```js
<h1>
Hi, <em>Pluto</em>!
</h1>
```
</details>
Here is an example that shows how to use a plugin
([`remark-gfm`][github-remark-gfm],
which adds support for footnotes, strikethrough, tables, tasklists and
URLs directly):
```js
import React from 'react'
import {createRoot} from 'react-dom/client'
import Markdown from 'react-markdown'
import remarkGfm from 'remark-gfm'
const markdown = `Just a link: www.nasa.gov.`
createRoot(document.body).render(
<Markdown remarkPlugins={[remarkGfm]}>{markdown}</Markdown>
)
```
<details>
<summary>Show equivalent JSX</summary>
```js
<p>
Just a link: <a href="http://www.nasa.gov">www.nasa.gov</a>.
</p>
```
</details>
## API
This package exports the identifiers
[`MarkdownAsync`][api-markdown-async],
[`MarkdownHooks`][api-markdown-hooks],
and
[`defaultUrlTransform`][api-default-url-transform].
The default export is [`Markdown`][api-markdown].
It also exports the additional [TypeScript][] types
[`AllowElement`][api-allow-element],
[`Components`][api-components],
[`ExtraProps`][api-extra-props],
[`HooksOptions`][api-hooks-options],
[`Options`][api-options],
and
[`UrlTransform`][api-url-transform].
### `Markdown`
Component to render markdown.
This is a synchronous component.
When using async plugins,
see [`MarkdownAsync`][api-markdown-async] or
[`MarkdownHooks`][api-markdown-hooks].
###### Parameters
* `options` ([`Options`][api-options])
— props
###### Returns
React element (`ReactElement`).
### `MarkdownAsync`
Component to render markdown with support for async plugins
through async/await.
Components returning promises are supported on the server.
For async support on the client,
see [`MarkdownHooks`][api-markdown-hooks].
###### Parameters
* `options` ([`Options`][api-options])
— props
###### Returns
Promise to a React element (`Promise<ReactElement>`).
### `MarkdownHooks`
Component to render markdown with support for async plugins through hooks.
This uses `useEffect` and `useState` hooks.
Hooks run on the client and do not immediately render something.
For async support on the server,
see [`MarkdownAsync`][api-markdown-async].
###### Parameters
* `options` ([`Options`][api-options])
— props
###### Returns
React node (`ReactNode`).
### `defaultUrlTransform(url)`
Make a URL safe.
###### Parameters
* `url` (`string`)
— URL
###### Returns
Safe URL (`string`).
### `AllowElement`
Filter elements (TypeScript type).
###### Parameters
* `node` ([`Element` from `hast`][github-hast-element])
— element to check
* `index` (`number | undefined`)
— index of `element` in `parent`
* `parent` ([`Node` from `hast`][github-hast-nodes])
— parent of `element`
###### Returns
Whether to allow `element` (`boolean`, optional).
### `Components`
Map tag names to components (TypeScript type).
###### Type
```ts
import type {ExtraProps} from 'react-markdown'
import type {ComponentProps, ElementType} from 'react'
type Components = {
[Key in Extract<ElementType, string>]?: ElementType<ComponentProps<Key> & ExtraProps>
}
```
### `ExtraProps`
Extra fields we pass to components (TypeScript type).
###### Fields
* `node` ([`Element` from `hast`][github-hast-element], optional)
— original node
### `HooksOptions`
Configuration for [`MarkdownHooks`][api-markdown-hooks] (TypeScript type);
extends the regular [`Options`][api-options] with a `fallback` prop.
###### Extends
[`Options`][api-options].
###### Fields
* `fallback` (`ReactNode`, optional)
— content to render while the processor processing the markdown
### `Options`
Configuration (TypeScript type).
###### Fields
* `allowElement` ([`AllowElement`][api-allow-element], optional)
— filter elements;
`allowedElements` / `disallowedElements` is used first
* `allowedElements` (`Array<string>`, default: all tag names)
— tag names to allow;
cannot combine w/ `disallowedElements`
* `children` (`string`, optional)
— markdown
* `components` ([`Components`][api-components], optional)
— map tag names to components
* `disallowedElements` (`Array<string>`, default: `[]`)
— tag names to disallow;
cannot combine w/ `allowedElements`
* `rehypePlugins` (`Array<Plugin>`, optional)
— list of [rehype plugins][github-rehype-plugins] to use
* `remarkPlugins` (`Array<Plugin>`, optional)
— list of [remark plugins][github-remark-plugins] to use
* `remarkRehypeOptions`
([`Options` from `remark-rehype`][github-remark-rehype-options],
optional)
— options to pass through to `remark-rehype`
* `skipHtml` (`boolean`, default: `false`)
— ignore HTML in markdown completely
* `unwrapDisallowed` (`boolean`, default: `false`)
— extract (unwrap) whats in disallowed elements;
normally when say `strong` is not allowed, it and its children are dropped,
with `unwrapDisallowed` the element itself is replaced by its children
* `urlTransform` ([`UrlTransform`][api-url-transform], default:
[`defaultUrlTransform`][api-default-url-transform])
— change URLs
### `UrlTransform`
Transform URLs (TypeScript type).
###### Parameters
* `url` (`string`)
— URL
* `key` (`string`, example: `'href'`)
— property name
* `node` ([`Element` from `hast`][github-hast-element])
— element to check
###### Returns
Transformed URL (`string`, optional).
## Examples
### Use a plugin
This example shows how to use a remark plugin.
In this case, [`remark-gfm`][github-remark-gfm],
which adds support for strikethrough, tables, tasklists and URLs directly:
```js
import React from 'react'
import {createRoot} from 'react-dom/client'
import Markdown from 'react-markdown'
import remarkGfm from 'remark-gfm'
const markdown = `A paragraph with *emphasis* and **strong importance**.
> A block quote with ~strikethrough~ and a URL: https://reactjs.org.
* Lists
* [ ] todo
* [x] done
A table:
| a | b |
| - | - |
`
createRoot(document.body).render(
<Markdown remarkPlugins={[remarkGfm]}>{markdown}</Markdown>
)
```
<details>
<summary>Show equivalent JSX</summary>
```js
<>
<p>
A paragraph with <em>emphasis</em> and <strong>strong importance</strong>.
</p>
<blockquote>
<p>
A block quote with <del>strikethrough</del> and a URL:{' '}
<a href="https://reactjs.org">https://reactjs.org</a>.
</p>
</blockquote>
<ul className="contains-task-list">
<li>Lists</li>
<li className="task-list-item">
<input type="checkbox" disabled /> todo
</li>
<li className="task-list-item">
<input type="checkbox" disabled checked /> done
</li>
</ul>
<p>A table:</p>
<table>
<thead>
<tr>
<th>a</th>
<th>b</th>
</tr>
</thead>
</table>
</>
```
</details>
### Use a plugin with options
This example shows how to use a plugin and give it options.
To do that, use an array with the plugin at the first place, and the options
second.
[`remark-gfm`][github-remark-gfm] has an option to allow only double tildes for
strikethrough:
```js
import React from 'react'
import {createRoot} from 'react-dom/client'
import Markdown from 'react-markdown'
import remarkGfm from 'remark-gfm'
const markdown = 'This ~is not~ strikethrough, but ~~this is~~!'
createRoot(document.body).render(
<Markdown remarkPlugins={[[remarkGfm, {singleTilde: false}]]}>
{markdown}
</Markdown>
)
```
<details>
<summary>Show equivalent JSX</summary>
```js
<p>
This ~is not~ strikethrough, but <del>this is</del>!
</p>
```
</details>
### Use custom components (syntax highlight)
This example shows how you can overwrite the normal handling of an element by
passing a component.
In this case, we apply syntax highlighting with the seriously super amazing
[`react-syntax-highlighter`][github-react-syntax-highlighter] by
[**@conorhastings**][github-conorhastings]:
<!-- To do: currently broken on actual ESM; lets find an alternative? -->
```js
import React from 'react'
import {createRoot} from 'react-dom/client'
import Markdown from 'react-markdown'
import {Prism as SyntaxHighlighter} from 'react-syntax-highlighter'
import {dark} from 'react-syntax-highlighter/dist/esm/styles/prism'
// Did you know you can use tildes instead of backticks for code in markdown? ✨
const markdown = `Here is some JavaScript code:
~~~js
console.log('It works!')
~~~
`
createRoot(document.body).render(
<Markdown
children={markdown}
components={{
code(props) {
const {children, className, node, ...rest} = props
const match = /language-(\w+)/.exec(className || '')
return match ? (
<SyntaxHighlighter
{...rest}
PreTag="div"
children={String(children).replace(/\n$/, '')}
language={match[1]}
style={dark}
/>
) : (
<code {...rest} className={className}>
{children}
</code>
)
}
}}
/>
)
```
<details>
<summary>Show equivalent JSX</summary>
```js
<>
<p>Here is some JavaScript code:</p>
<pre>
<SyntaxHighlighter language="js" style={dark} PreTag="div" children="console.log('It works!')" />
</pre>
</>
```
</details>
### Use remark and rehype plugins (math)
This example shows how a syntax extension
(through [`remark-math`][github-remark-math])
is used to support math in markdown, and a transform plugin
([`rehype-katex`][github-rehype-katex]) to render that math.
```js
import React from 'react'
import {createRoot} from 'react-dom/client'
import Markdown from 'react-markdown'
import rehypeKatex from 'rehype-katex'
import remarkMath from 'remark-math'
import 'katex/dist/katex.min.css' // `rehype-katex` does not import the CSS for you
const markdown = `The lift coefficient ($C_L$) is a dimensionless coefficient.`
createRoot(document.body).render(
<Markdown remarkPlugins={[remarkMath]} rehypePlugins={[rehypeKatex]}>
{markdown}
</Markdown>
)
```
<details>
<summary>Show equivalent JSX</summary>
```js
<p>
The lift coefficient (
<span className="katex">
<span className="katex-mathml">
<math xmlns="http://www.w3.org/1998/Math/MathML">{/* … */}</math>
</span>
<span className="katex-html" aria-hidden="true">
{/* … */}
</span>
</span>
) is a dimensionless coefficient.
</p>
```
</details>
## Plugins
We use [unified][github-unified],
specifically [remark][github-remark] for markdown and
[rehype][github-rehype] for HTML,
which are tools to transform content with plugins.
Here are three good ways to find plugins:
* [`awesome-remark`][github-awesome-remark] and
[`awesome-rehype`][github-awesome-rehype]
— selection of the most awesome projects
* [List of remark plugins][github-remark-plugins] and
[list of rehype plugins][github-rehype-plugins]
— list of all plugins
* [`remark-plugin`][github-topic-remark-plugin] and
[`rehype-plugin`][github-topic-rehype-plugin] topics
— any tagged repo on GitHub
## Syntax
`react-markdown` follows CommonMark, which standardizes the differences between
markdown implementations, by default.
Some syntax extensions are supported through plugins.
We use [`micromark`][github-micromark] under the hood for our parsing.
See its documentation for more information on markdown, CommonMark, and
extensions.
## Compatibility
Projects maintained by the unified collective are compatible with maintained
versions of Node.js.
When we cut a new major release, we drop support for unmaintained versions of
Node.
This means we try to keep the current release line, `react-markdown@10`,
compatible with Node.js 16.
They work in all modern browsers (essentially: everything not IE 11).
You can use a bundler (such as esbuild, webpack, or Rollup) to use this package
in your project, and use its options (or plugins) to add support for legacy
browsers.
## Architecture
<pre><code> react-markdown
+----------------------------------------------------------------------------------------------------------------+
| |
| +----------+ +----------------+ +---------------+ +----------------+ +------------+ |
| | | | | | | | | | | |
<a href="https://commonmark.org">markdown</a>-+->+ <a href="https://github.com/remarkjs/remark">remark</a> +-<a href="https://github.com/syntax-tree/mdast">mdast</a>->+ <a href="https://github.com/remarkjs/remark/blob/main/doc/plugins.md">remark plugins</a> +-<a href="https://github.com/syntax-tree/mdast">mdast</a>->+ <a href="https://github.com/remarkjs/remark-rehype">remark-rehype</a> +-<a href="https://github.com/syntax-tree/hast">hast</a>->+ <a href="https://github.com/rehypejs/rehype/blob/main/doc/plugins.md">rehype plugins</a> +-<a href="https://github.com/syntax-tree/hast">hast</a>->+ <a href="#appendix-b-components">components</a> +-+->react elements
| | | | | | | | | | | |
| +----------+ +----------------+ +---------------+ +----------------+ +------------+ |
| |
+----------------------------------------------------------------------------------------------------------------+
</code></pre>
To understand what this project does, its important to first understand what
unified does: please read through the [`unifiedjs/unified`][github-unified]
readme
(the part until you hit the API section is required reading).
`react-markdown` is a unified pipeline — wrapped so that most folks dont need
to directly interact with unified.
The processor goes through these steps:
* parse markdown to mdast (markdown syntax tree)
* transform through remark (markdown ecosystem)
* transform mdast to hast (HTML syntax tree)
* transform through rehype (HTML ecosystem)
* render hast to React with components
## Appendix A: HTML in markdown
`react-markdown` typically escapes HTML (or ignores it, with `skipHtml`)
because it is dangerous and defeats the purpose of this library.
However, if you are in a trusted environment (you trust the markdown), and
can spare the bundle size (±60kb minzipped), then you can use
[`rehype-raw`][github-rehype-raw]:
```js
import React from 'react'
import {createRoot} from 'react-dom/client'
import Markdown from 'react-markdown'
import rehypeRaw from 'rehype-raw'
const markdown = `<div class="note">
Some *emphasis* and <strong>strong</strong>!
</div>`
createRoot(document.body).render(
<Markdown rehypePlugins={[rehypeRaw]}>{markdown}</Markdown>
)
```
<details>
<summary>Show equivalent JSX</summary>
```js
<div className="note">
<p>
Some <em>emphasis</em> and <strong>strong</strong>!
</p>
</div>
```
</details>
**Note**: HTML in markdown is still bound by how [HTML works in
CommonMark][commonmark-html].
Make sure to use blank lines around block-level HTML that again contains
markdown!
## Appendix B: Components
You can also change the things that come from markdown:
```js
<Markdown
components={{
// Map `h1` (`# heading`) to use `h2`s.
h1: 'h2',
// Rewrite `em`s (`*like so*`) to `i` with a red foreground color.
em(props) {
const {node, ...rest} = props
return <i style={{color: 'red'}} {...rest} />
}
}}
/>
```
The keys in components are HTML equivalents for the things you write with
markdown (such as `h1` for `# heading`).
Normally, in markdown, those are: `a`, `blockquote`, `br`, `code`, `em`, `h1`,
`h2`, `h3`, `h4`, `h5`, `h6`, `hr`, `img`, `li`, `ol`, `p`, `pre`, `strong`, and
`ul`.
With [`remark-gfm`][github-remark-gfm],
you can also use `del`, `input`, `table`, `tbody`, `td`, `th`, `thead`, and `tr`.
Other remark or rehype plugins that add support for new constructs will also
work with `react-markdown`.
The props that are passed are what you probably would expect: an `a` (link) will
get `href` (and `title`) props, and `img` (image) an `src`, `alt` and `title`,
etc.
Every component will receive a `node`.
This is the original [`Element` from `hast`][github-hast-element] element being
turned into a React element.
## Appendix C: line endings in markdown (and JSX)
You might have trouble with how line endings work in markdown and JSX.
We recommend the following, which solves all line ending problems:
```js
// If you write actual markdown in your code, put your markdown in a variable;
// **do not indent markdown**:
const markdown = `
# This is perfect!
`
// Pass the value as an expression as an only child:
const result = <Markdown>{markdown}</Markdown>
```
👆 That works.
Read on for what doesnt and why that is.
You might try to write markdown directly in your JSX and find that it **does
not** work:
```js
<Markdown>
# Hi
This is **not** a paragraph.
</Markdown>
```
The is because in JSX the whitespace (including line endings) is collapsed to
a single space.
So the above example is equivalent to:
```js
<Markdown> # Hi This is **not** a paragraph. </Markdown>
```
Instead, to pass markdown to `Markdown`, you can use an expression:
with a template literal:
```js
<Markdown>{`
# Hi
This is a paragraph.
`}</Markdown>
```
Template literals have another potential problem, because they keep whitespace
(including indentation) inside them.
That means that the following **does not** turn into a heading:
```js
<Markdown>{`
# This is **not** a heading, its an indented code block
`}</Markdown>
```
## Security
Use of `react-markdown` is secure by default.
Overwriting `urlTransform` to something insecure will open you up to XSS
vectors.
Furthermore, the `remarkPlugins`, `rehypePlugins`, and `components` you use may
be insecure.
To make sure the content is completely safe, even after what plugins do,
use [`rehype-sanitize`][github-rehype-sanitize].
It lets you define your own schema of what is and isnt allowed.
## Related
* [`MDX`][github-mdx]
— JSX *in* markdown
* [`remark-gfm`][github-remark-gfm]
— add support for GitHub flavored markdown support
* [`react-remark`][github-react-remark]
— hook based alternative
* [`rehype-react`][github-rehype-react]
— turn HTML into React elements
## Contribute
See [`contributing.md`][health-contributing] in [`remarkjs/.github`][health]
for ways to get started.
See [`support.md`][health-support] for ways to get help.
This project has a [code of conduct][health-coc].
By interacting with this repository, organization, or community you agree to
abide by its terms.
## License
[MIT][file-license] © [Espen Hovlandsdal][author]
[api-allow-element]: #allowelement
[api-components]: #components
[api-default-url-transform]: #defaulturltransformurl
[api-extra-props]: #extraprops
[api-hooks-options]: #hooksoptions
[api-markdown]: #markdown
[api-markdown-async]: #markdownasync
[api-markdown-hooks]: #markdownhooks
[api-options]: #options
[api-url-transform]: #urltransform
[author]: https://espen.codes/
[badge-build-image]: https://github.com/remarkjs/react-markdown/workflows/main/badge.svg
[badge-build-url]: https://github.com/remarkjs/react-markdown/actions
[badge-coverage-image]: https://img.shields.io/codecov/c/github/remarkjs/react-markdown.svg
[badge-coverage-url]: https://codecov.io/github/remarkjs/react-markdown
[badge-downloads-image]: https://img.shields.io/npm/dm/react-markdown.svg
[badge-downloads-url]: https://www.npmjs.com/package/react-markdown
[badge-size-image]: https://img.shields.io/bundlejs/size/react-markdown
[badge-size-url]: https://bundlejs.com/?q=react-markdown
[commonmark-help]: https://commonmark.org/help/
[commonmark-html]: https://spec.commonmark.org/0.31.2/#html-blocks
[esm]: https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c
[esmsh]: https://esm.sh
[file-license]: license
[github-awesome-rehype]: https://github.com/rehypejs/awesome-rehype
[github-awesome-remark]: https://github.com/remarkjs/awesome-remark
[github-conorhastings]: https://github.com/conorhastings
[github-hast-element]: https://github.com/syntax-tree/hast#element
[github-hast-nodes]: https://github.com/syntax-tree/hast#nodes
[github-io-react-markdown]: https://remarkjs.github.io/react-markdown/
[github-mdx]: https://github.com/mdx-js/mdx/
[github-micromark]: https://github.com/micromark/micromark
[github-react-remark]: https://github.com/remarkjs/react-remark
[github-react-syntax-highlighter]: https://github.com/react-syntax-highlighter/react-syntax-highlighter
[github-rehype]: https://github.com/rehypejs/rehype
[github-rehype-katex]: https://github.com/remarkjs/remark-math/tree/main/packages/rehype-katex
[github-rehype-plugins]: https://github.com/rehypejs/rehype/blob/main/doc/plugins.md#list-of-plugins
[github-rehype-raw]: https://github.com/rehypejs/rehype-raw
[github-rehype-react]: https://github.com/rehypejs/rehype-react
[github-rehype-sanitize]: https://github.com/rehypejs/rehype-sanitize
[github-remark]: https://github.com/remarkjs/remark
[github-remark-gfm]: https://github.com/remarkjs/remark-gfm
[github-remark-math]: https://github.com/remarkjs/remark-math
[github-remark-plugins]: https://github.com/remarkjs/remark/blob/main/doc/plugins.md#list-of-plugins
[github-remark-rehype-options]: https://github.com/remarkjs/remark-rehype#options
[github-topic-rehype-plugin]: https://github.com/topics/rehype-plugin
[github-topic-remark-plugin]: https://github.com/topics/remark-plugin
[github-unified]: https://github.com/unifiedjs/unified
[health]: https://github.com/remarkjs/.github
[health-coc]: https://github.com/remarkjs/.github/blob/main/code-of-conduct.md
[health-contributing]: https://github.com/remarkjs/.github/blob/main/contributing.md
[health-support]: https://github.com/remarkjs/.github/blob/main/support.md
[npm-install]: https://docs.npmjs.com/cli/install
[react]: http://reactjs.org
[section-components]: #appendix-b-components
[section-plugins]: #plugins
[section-security]: #security
[section-syntax]: #syntax
[typescript]: https://www.typescriptlang.org