@ai-react-markdown/core 1.4.3 → 1.4.5
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 +90 -54
- package/dist/index.cjs +2185 -2080
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +86 -58
- package/dist/index.d.ts +86 -58
- package/dist/index.js +586 -480
- package/dist/index.js.map +1 -1
- package/dist/typography/all.css +34 -29
- package/dist/typography/all.css.map +1 -1
- package/dist/typography/default.css +34 -29
- package/dist/typography/default.css.map +1 -1
- package/package.json +11 -3
package/README.md
CHANGED
|
@@ -49,6 +49,14 @@ For LaTeX math rendering, include the KaTeX stylesheet:
|
|
|
49
49
|
import 'katex/dist/katex.min.css';
|
|
50
50
|
```
|
|
51
51
|
|
|
52
|
+
`katex` is declared as an **optional peer dependency**. It ships transitively via `rehype-katex`, so hoisted installers (npm, yarn classic, default pnpm) resolve the import automatically. Strict-isolation installers (yarn PnP, `pnpm --node-linker=isolated`) need it installed explicitly:
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
npm install katex
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Skip the install only if you have no `import 'katex/…'` calls in your app and don't render math.
|
|
59
|
+
|
|
52
60
|
For the built-in default typography, include the typography CSS:
|
|
53
61
|
|
|
54
62
|
```tsx
|
|
@@ -81,23 +89,23 @@ function StreamingChat({ content, isStreaming }: { content: string; isStreaming:
|
|
|
81
89
|
|
|
82
90
|
### `AIMarkdownProps<TConfig, TRenderData>`
|
|
83
91
|
|
|
84
|
-
| Prop | Type | Default | Description
|
|
85
|
-
| ---------------------- | -------------------------------- | ------------------------------- |
|
|
86
|
-
| `content` | `string` | **(required)** | Raw markdown content to render.
|
|
87
|
-
| `streaming` | `boolean` | `false` | Whether content is actively being streamed (e.g. from an LLM).
|
|
88
|
-
| `fontSize` | `number \| string` | `'0.9375rem'` | Base font size. Numbers are treated as pixels.
|
|
89
|
-
| `variant` | `AIMarkdownVariant` | `'default'` | Typography variant name.
|
|
90
|
-
| `colorScheme` | `AIMarkdownColorScheme` | `'light'` | Color scheme name (`'light'`, `'dark'`, or custom).
|
|
91
|
-
| `config` | `PartialDeep<TConfig>` | `undefined` | Partial render config, deep-merged with defaults.
|
|
92
|
-
| `defaultConfig` | `TConfig` | `defaultAIMarkdownRenderConfig` | Base config to merge against. Sub-packages can pass extended defaults.
|
|
93
|
-
| `metadata` | `TRenderData` | `undefined` | Arbitrary data passed to custom components via a dedicated context.
|
|
94
|
-
| `contentPreprocessors` | `AIMDContentPreprocessor[]` | `[]` | Additional preprocessors run after the built-in LaTeX preprocessor.
|
|
95
|
-
| `customComponents` | `AIMarkdownCustomComponents` | `undefined` | `react-markdown` component overrides for specific HTML elements.
|
|
96
|
-
| `Typography` | `AIMarkdownTypographyComponent` | `DefaultTypography` | Typography wrapper component.
|
|
97
|
-
| `ExtraStyles` | `AIMarkdownExtraStylesComponent` | `undefined` | Optional extra style wrapper rendered between typography and content.
|
|
92
|
+
| Prop | Type | Default | Description |
|
|
93
|
+
| ---------------------- | -------------------------------- | ------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
94
|
+
| `content` | `string` | **(required)** | Raw markdown content to render. |
|
|
95
|
+
| `streaming` | `boolean` | `false` | Whether content is actively being streamed (e.g. from an LLM). |
|
|
96
|
+
| `fontSize` | `number \| string` | `'0.9375rem'` | Base font size. Numbers are treated as pixels. |
|
|
97
|
+
| `variant` | `AIMarkdownVariant` | `'default'` | Typography variant name. |
|
|
98
|
+
| `colorScheme` | `AIMarkdownColorScheme` | `'light'` | Color scheme name (`'light'`, `'dark'`, or custom). |
|
|
99
|
+
| `config` | `PartialDeep<TConfig>` | `undefined` | Partial render config, deep-merged with defaults. |
|
|
100
|
+
| `defaultConfig` | `TConfig` | `defaultAIMarkdownRenderConfig` | Base config to merge against. Sub-packages can pass extended defaults. |
|
|
101
|
+
| `metadata` | `TRenderData` | `undefined` | Arbitrary data passed to custom components via a dedicated context. |
|
|
102
|
+
| `contentPreprocessors` | `AIMDContentPreprocessor[]` | `[]` | Additional preprocessors run after the built-in LaTeX preprocessor. |
|
|
103
|
+
| `customComponents` | `AIMarkdownCustomComponents` | `undefined` | `react-markdown` component overrides for specific HTML elements. |
|
|
104
|
+
| `Typography` | `AIMarkdownTypographyComponent` | `DefaultTypography` | Typography wrapper component. |
|
|
105
|
+
| `ExtraStyles` | `AIMarkdownExtraStylesComponent` | `undefined` | Optional extra style wrapper rendered between typography and content. |
|
|
98
106
|
| `documentId` | `string` | auto via `useId()` | Stable id for the _logical markdown document_ this `<AIMarkdown>` is rendering. Used as the id namespace for clobberable attributes (`id`, hash hrefs) so two documents on the same page do not cross-link (footnote `[^1]` in message A won't scroll to `[^1]` in message B). When one document is split into chunks rendered by multiple `<AIMarkdown>` instances, pass the SAME `documentId` to every chunk so prefixes align. The value is passed through `encodeURIComponent` before being injected into HTML attributes, so any string is safe (React's `useId()` output, your own opaque ids, user-supplied UUIDs). Long ids (>16 chars, e.g. UUIDs) are hashed via MurmurHash3 to a short Base62 form **inside the rendered `id="…"`/`href="#…"` prefix only** to keep HTML compact; `state.documentId` itself and registry keying via `useDocumentRegistry` stay raw, so deep linking and any consumer code reading `documentId` are unaffected. |
|
|
99
|
-
| `urlTransform` | `UrlTransform \| null` | `defaultUrlTransform` | Override the URL allowlist applied to `href`, `src`, and similar attributes. The default mirrors GitHub: `http`, `https`, `irc`, `ircs`, `mailto`, `xmpp`. Pass a function defined at module scope (or memoized) to permit additional schemes — see [Custom URL Schemes and Sanitization](#custom-url-schemes-and-sanitization).
|
|
100
|
-
| `sanitizeSchema` | `SanitizeSchema` | library default | Override the `rehype-sanitize` schema. Build with [`extendSanitizeSchema`](#custom-url-schemes-and-sanitization) so the library's cross-chunk tag and KaTeX className allowlists survive — hand-rolling silently drops them.
|
|
107
|
+
| `urlTransform` | `UrlTransform \| null` | `defaultUrlTransform` | Override the URL allowlist applied to `href`, `src`, and similar attributes. The default mirrors GitHub: `http`, `https`, `irc`, `ircs`, `mailto`, `xmpp`. Pass a function defined at module scope (or memoized) to permit additional schemes — see [Custom URL Schemes and Sanitization](#custom-url-schemes-and-sanitization). |
|
|
108
|
+
| `sanitizeSchema` | `SanitizeSchema` | library default | Override the `rehype-sanitize` schema. Build with [`extendSanitizeSchema`](#custom-url-schemes-and-sanitization) so the library's cross-chunk tag and KaTeX className allowlists survive — hand-rolling silently drops them. |
|
|
101
109
|
|
|
102
110
|
## Configuration
|
|
103
111
|
|
|
@@ -202,25 +210,23 @@ By default `<AIMarkdown>` only renders links and images whose URLs use the stand
|
|
|
202
210
|
|
|
203
211
|
Sanitization runs in **two independent gates** (defense in depth):
|
|
204
212
|
|
|
205
|
-
1. **`urlTransform`** — runs first, on every URL-bearing attribute, and rewrites disallowed URLs to `''`.
|
|
206
|
-
2. **`rehype-sanitize` schema** — runs second, and drops the
|
|
213
|
+
1. **`urlTransform`** — runs first, on every URL-bearing attribute, and rewrites disallowed URLs to `''`. Called per-attribute with the attribute name (`'href'` / `'src'` / …) so key-aware transforms can discriminate (e.g. allow a scheme on `href` but not on `src` to block tracker pixels).
|
|
214
|
+
2. **`rehype-sanitize` schema** — runs second, and drops the URL when the protocol is not in the schema's per-attribute allowlist (`protocols.href`, `protocols.src`, `protocols.cite`).
|
|
207
215
|
|
|
208
216
|
For a private scheme to render, **both gates must permit it**. Allowing only one is the most common pitfall.
|
|
209
217
|
|
|
218
|
+
**Cross-chunk symmetry.** When `<AIMarkdown>` instances are wrapped in `<AIMarkdownDocuments>`, link/image references resolved across chunks (chunk A defines `[evil]: …`, chunk B writes `[click][evil]`) go through both gates as well — the same `urlTransform` and `sanitizeSchema` you pass to `<AIMarkdown>` apply at render time. The per-attribute key (`'href'` vs `'src'`) is honored: a key-aware policy that permits a scheme on `<a>` but not `<img>` will produce identical behavior whether the reference is in-chunk or cross-chunk.
|
|
219
|
+
|
|
210
220
|
### Allowing a Custom Scheme
|
|
211
221
|
|
|
212
222
|
Define both gates at module scope so their reference identity is stable across renders (this keeps the per-block memo cache warm):
|
|
213
223
|
|
|
214
224
|
```tsx
|
|
215
|
-
import AIMarkdown, {
|
|
216
|
-
defaultUrlTransform,
|
|
217
|
-
extendSanitizeSchema,
|
|
218
|
-
} from '@ai-react-markdown/core';
|
|
225
|
+
import AIMarkdown, { defaultUrlTransform, extendSanitizeSchema } from '@ai-react-markdown/core';
|
|
219
226
|
|
|
220
227
|
// Gate 1: compose with the default so https/mailto/etc. still work.
|
|
221
228
|
const ALLOWED = /^myapp:/i;
|
|
222
|
-
const URL_TRANSFORM = (url, key, node) =>
|
|
223
|
-
ALLOWED.test(url) ? url : defaultUrlTransform(url, key, node);
|
|
229
|
+
const URL_TRANSFORM = (url, key, node) => (ALLOWED.test(url) ? url : defaultUrlTransform(url, key, node));
|
|
224
230
|
|
|
225
231
|
// Gate 2: extend the library schema so it permits the scheme on href + src.
|
|
226
232
|
const SCHEMA = extendSanitizeSchema((s) => {
|
|
@@ -229,13 +235,7 @@ const SCHEMA = extendSanitizeSchema((s) => {
|
|
|
229
235
|
});
|
|
230
236
|
|
|
231
237
|
function App() {
|
|
232
|
-
return
|
|
233
|
-
<AIMarkdown
|
|
234
|
-
content={markdown}
|
|
235
|
-
urlTransform={URL_TRANSFORM}
|
|
236
|
-
sanitizeSchema={SCHEMA}
|
|
237
|
-
/>
|
|
238
|
-
);
|
|
238
|
+
return <AIMarkdown content={markdown} urlTransform={URL_TRANSFORM} sanitizeSchema={SCHEMA} />;
|
|
239
239
|
}
|
|
240
240
|
```
|
|
241
241
|
|
|
@@ -245,8 +245,8 @@ Hands you a deep clone of the library's default sanitize schema. Mutate it freel
|
|
|
245
245
|
|
|
246
246
|
```tsx
|
|
247
247
|
const SCHEMA = extendSanitizeSchema((s) => {
|
|
248
|
-
s.tagNames.push('my-widget');
|
|
249
|
-
s.protocols.href.push('myapp');
|
|
248
|
+
s.tagNames.push('my-widget'); // add a tag
|
|
249
|
+
s.protocols.href.push('myapp'); // permit a protocol
|
|
250
250
|
s.attributes['my-widget'] = ['data-id', 'data-mode']; // allow attributes
|
|
251
251
|
// No `return` needed — mutate-only is fine.
|
|
252
252
|
});
|
|
@@ -260,36 +260,45 @@ const SCHEMA = extendSanitizeSchema((s) => {
|
|
|
260
260
|
|
|
261
261
|
### Reference Stability and the Cache
|
|
262
262
|
|
|
263
|
-
Both `urlTransform` and `sanitizeSchema`
|
|
263
|
+
Both `urlTransform` and `sanitizeSchema` participate in the per-block memo cache, but they are stabilized **asymmetrically**:
|
|
264
|
+
|
|
265
|
+
- **`urlTransform`** is tracked by identity only. A new function reference every render flushes the cache. Callers MUST supply a stable reference (module scope or `useMemo`).
|
|
266
|
+
- **`sanitizeSchema`** is tracked by identity AND additionally stabilized internally via a deep-equal safety net (`useStableValue`). An inline-but-deep-equal schema still works, just with a one-time deep compare on each render — cheaper than a cache flush but not free.
|
|
267
|
+
|
|
268
|
+
Why the asymmetry: function identity can't be deep-compared (two closures with identical bodies are always non-equal), so for `urlTransform` only the call-site can produce a stable reference. `sanitizeSchema` is plain data, so a deep compare is meaningful and serves as a guardrail for callers who forget the module-scope rule.
|
|
264
269
|
|
|
265
270
|
```tsx
|
|
266
|
-
// 🚫 Anti-pattern —
|
|
271
|
+
// 🚫 Anti-pattern — `urlTransform` is recreated every render and discards
|
|
272
|
+
// the entire markdown cache. `sanitizeSchema` would too without the
|
|
273
|
+
// internal deep-equal safety net, but you still pay the deep-compare cost.
|
|
267
274
|
<AIMarkdown
|
|
268
275
|
urlTransform={(url, k, n) => /* … */}
|
|
269
276
|
sanitizeSchema={extendSanitizeSchema((s) => /* … */)}
|
|
270
277
|
/>
|
|
278
|
+
|
|
279
|
+
// ✅ Stable — both refs are minted once at module scope.
|
|
280
|
+
const URL_TRANSFORM = (url, k, n) => /* … */;
|
|
281
|
+
const SCHEMA = extendSanitizeSchema((s) => /* … */);
|
|
282
|
+
<AIMarkdown urlTransform={URL_TRANSFORM} sanitizeSchema={SCHEMA} />
|
|
271
283
|
```
|
|
272
284
|
|
|
273
|
-
|
|
285
|
+
In development the library will `console.warn` after detecting 3+ identity flips on either prop. The warning is dead-code-eliminated in production builds. Define both values at module scope, or memoize with `useMemo` if they depend on state.
|
|
274
286
|
|
|
275
287
|
### Regex Escaping for `+` / `-` / `.` in Scheme Names
|
|
276
288
|
|
|
277
289
|
Per RFC 3986 scheme names may contain `+`, `-`, and `.` — all regex metacharacters. Write `/^web\+app:/i`, **not** `/^web+app:/i` (the latter would match `we`, `wee`, `weee`, …, silently broadening the allowlist).
|
|
278
290
|
|
|
279
|
-
###
|
|
291
|
+
### Inspecting the Default Schema
|
|
280
292
|
|
|
281
|
-
|
|
293
|
+
`extendSanitizeSchema` hands the modifier a deep clone of the library default. That makes the helper itself the cleanest introspection path — no separate export of the singleton is needed:
|
|
282
294
|
|
|
283
295
|
```tsx
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
...sanitizeSchema, // ← required to keep cross-chunk + math invariants
|
|
288
|
-
// your overrides here
|
|
289
|
-
};
|
|
296
|
+
extendSanitizeSchema((s) => {
|
|
297
|
+
console.log('default sanitize schema:', s);
|
|
298
|
+
});
|
|
290
299
|
```
|
|
291
300
|
|
|
292
|
-
|
|
301
|
+
Why no direct `sanitizeSchema` export? Because the obvious extension pattern — `{ ...sanitizeSchema, … }` — is a shallow spread. Nested arrays (`protocols.href`, `attributes.a`, `ancestors.*`, …) stay aliased to the singleton; a subsequent `.protocols.href.push(...)` mutates it, and the change leaks into every other `<AIMarkdown>` in your app that doesn't override `sanitizeSchema`. `extendSanitizeSchema` always works on a deep clone, so this class of bug is impossible by construction.
|
|
293
302
|
|
|
294
303
|
### API Stability of `UrlTransform` and `SanitizeSchema`
|
|
295
304
|
|
|
@@ -316,15 +325,15 @@ function CustomCodeBlock({ children }: PropsWithChildren) {
|
|
|
316
325
|
|
|
317
326
|
**Returns** `AIMarkdownRenderState<TConfig>`:
|
|
318
327
|
|
|
319
|
-
| Field | Type | Description
|
|
320
|
-
| --------------- | ----------------------- |
|
|
321
|
-
| `streaming` | `boolean` | Whether content is being streamed.
|
|
322
|
-
| `fontSize` | `string` | Resolved CSS font-size value.
|
|
323
|
-
| `variant` | `AIMarkdownVariant` | Active typography variant.
|
|
324
|
-
| `colorScheme` | `AIMarkdownColorScheme` | Active color scheme.
|
|
325
|
-
| `documentId` | `string` | Stable id for the logical markdown document — caller-supplied or auto-generated via `useId()`.
|
|
328
|
+
| Field | Type | Description |
|
|
329
|
+
| --------------- | ----------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
330
|
+
| `streaming` | `boolean` | Whether content is being streamed. |
|
|
331
|
+
| `fontSize` | `string` | Resolved CSS font-size value. |
|
|
332
|
+
| `variant` | `AIMarkdownVariant` | Active typography variant. |
|
|
333
|
+
| `colorScheme` | `AIMarkdownColorScheme` | Active color scheme. |
|
|
334
|
+
| `documentId` | `string` | Stable id for the logical markdown document — caller-supplied or auto-generated via `useId()`. |
|
|
326
335
|
| `clobberPrefix` | `string` | URI-safe id prefix derived from `documentId` (with MurmurHash3 → Base62 shortening applied for >16-char ids), used by every clobberable HTML attribute (`id=…` / `href="#…"`). Read this from the render state rather than recomputing locally when writing components that emit anchors — the prefix's exact byte form is not part of the stability contract and may shift across versions. |
|
|
327
|
-
| `config` | `TConfig` | Active render configuration (merged with defaults).
|
|
336
|
+
| `config` | `TConfig` | Active render configuration (merged with defaults). |
|
|
328
337
|
|
|
329
338
|
### `useAIMarkdownMetadata<TMetadata>()`
|
|
330
339
|
|
|
@@ -382,6 +391,32 @@ Import the corresponding CSS to activate styles:
|
|
|
382
391
|
import '@ai-react-markdown/core/typography/default.css';
|
|
383
392
|
```
|
|
384
393
|
|
|
394
|
+
#### Customization tokens
|
|
395
|
+
|
|
396
|
+
All `default`-variant styles are driven by CSS custom properties declared on `.aim-typography-root.default`. Spacing, font-size, and heading tokens are **anchored to `--aim-font-size-root`** (injected by the renderer from the `fontSize` prop), so changing `fontSize` proportionally scales every dimension. To customize, override any token in your own stylesheet:
|
|
397
|
+
|
|
398
|
+
```css
|
|
399
|
+
.aim-typography-root.default {
|
|
400
|
+
--aim-spacing-md: calc(var(--aim-font-size-root) * 1.2); /* roomier paragraphs */
|
|
401
|
+
--aim-h1-font-size: calc(var(--aim-font-size-root) * 2.5); /* bigger H1 */
|
|
402
|
+
--aim-font-weight-strong: 600; /* lighter headings + th */
|
|
403
|
+
--aim-color-anchor: #ff6b6b; /* red links */
|
|
404
|
+
}
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
| Group | Tokens | Notes |
|
|
408
|
+
| ------------- | ------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
409
|
+
| Spacing | `--aim-spacing-{xs,sm,md,lg,xl}` | `calc(var(--aim-font-size-root) * k)` where `k ∈ {0.625, 0.75, 1, 1.25, 1.5}` |
|
|
410
|
+
| Font size | `--aim-font-size-{xs,sm,md,lg,xl}` | `k ∈ {0.75, 0.875, 1, 1.125, 1.25}` |
|
|
411
|
+
| Heading sizes | `--aim-h{1..6}-font-size` | Multipliers mirror Mantine's heading scale (`{2.125, 1.625, 1.375, 1.125, 1, 0.875}`) |
|
|
412
|
+
| Heading meta | `--aim-h{1..6}-line-height`, `--aim-h{1..6}-font-weight` | line-heights are unitless; weights default to `var(--aim-font-weight-strong)` |
|
|
413
|
+
| Weight | `--aim-font-weight-strong` | Shared by all headings and `<th>`. Default `700`. |
|
|
414
|
+
| KaTeX | `--aim-katex-font-size` | Defaults to `var(--aim-font-size-root)`, so formulas stay at the component-root size regardless of parent context (blockquote, heading). Override to `1em` if you want parent-relative. |
|
|
415
|
+
| Misc | `--aim-line-height`, `--aim-radius-sm`, `--aim-font-family-{monospace,headings}` | Unitless / rem / font-stack constants. |
|
|
416
|
+
| Color (light) | `--aim-color-{text,dimmed,anchor,border,code-bg,code-text,blockquote-bg,mark-bg,mark-text}` | Declared on `.aim-typography-root.light`; dark variants on `.aim-typography-root.dark`. |
|
|
417
|
+
|
|
418
|
+
> **Stability contract:** the _names_ and _roles_ of these tokens follow semver. The exact default _values_ (multipliers, colors) may shift under minor bumps as the visual design evolves — override the token if you need a specific value to be locked.
|
|
419
|
+
|
|
385
420
|
### Custom Typography Component
|
|
386
421
|
|
|
387
422
|
Replace the typography wrapper by passing a custom component. The `style` prop carries CSS custom properties injected by the core renderer — **merge it onto your root element** so that descendant CSS can reference these variables:
|
|
@@ -410,6 +445,8 @@ The core renderer injects the following CSS custom properties via the Typography
|
|
|
410
445
|
|
|
411
446
|
**Why `--aim-font-size-root`?** Markdown content frequently nests elements that use relative `em` units — blockquotes, lists, code blocks. Each nesting level compounds the effective size: a `0.875em` code span inside a `1.125em` blockquote resolves to `0.984em` of the parent, not `0.875em` of the root. This variable provides a stable, absolute reference that inner CSS rules can use to opt out of compounding when a fixed size is needed.
|
|
412
447
|
|
|
448
|
+
The built-in `default` variant already consumes this variable — all of its spacing, font-size, and heading tokens are defined as `calc(var(--aim-font-size-root) * k)`, so changing the `fontSize` prop on `<AIMarkdown>` proportionally scales every rendered dimension. See [Customization tokens](#customization-tokens) above for the full surface.
|
|
449
|
+
|
|
413
450
|
### Extra Styles Wrapper
|
|
414
451
|
|
|
415
452
|
The `ExtraStyles` prop accepts a component rendered between the typography wrapper and the markdown content. Useful for injecting additional CSS scope or theme providers:
|
|
@@ -575,7 +612,6 @@ The metadata and render state providers are deliberately separated so that metad
|
|
|
575
612
|
- `AIMarkdownRenderDisplayOptimizeAbility`
|
|
576
613
|
- `defaultAIMarkdownRenderConfig`
|
|
577
614
|
- `defaultUrlTransform` -- the library's built-in URL-allowlist transform; compose with this when supplying a custom `urlTransform`
|
|
578
|
-
- `sanitizeSchema` -- the library's built-in `rehype-sanitize` schema; spread this when hand-rolling a custom schema (or use `extendSanitizeSchema` instead)
|
|
579
615
|
|
|
580
616
|
### Helpers
|
|
581
617
|
|