@wingleeio/mugen-markdown 0.1.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/LICENSE +21 -0
- package/README.md +183 -0
- package/dist/index.cjs +1903 -0
- package/dist/index.d.cts +498 -0
- package/dist/index.d.mts +498 -0
- package/dist/index.mjs +1861 -0
- package/package.json +79 -0
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,498 @@
|
|
|
1
|
+
import { CSSProperties, JSX, ReactElement, ReactNode } from "react";
|
|
2
|
+
import { BoxProps, Font, Font as Font$1, HStack, HStackProps, MeasurableStyle, PrimitiveComponent, SafeClassName, Text, TextProps, VStack, VStackProps, definePrimitive } from "@wingleeio/mugen";
|
|
3
|
+
import { ParserOptions } from "@incremark/core";
|
|
4
|
+
import { Blockquote, Blockquote as Blockquote$1, Code, Code as Code$1, Heading, Heading as Heading$1, Html, Html as Html$1, Image, Image as Image$1, Link, List, List as List$1, ListItem, Paragraph, Paragraph as Paragraph$1, PhrasingContent, PhrasingContent as PhrasingContent$1, Root, Root as Root$1, RootContent, RootContent as RootContent$1, Table, Table as Table$1, TableCell, TableRow, ThematicBreak, ThematicBreak as ThematicBreak$1 } from "mdast";
|
|
5
|
+
|
|
6
|
+
//#region src/parse.d.ts
|
|
7
|
+
/**
|
|
8
|
+
* Markdown parsing options — a curated subset of incremark's `ParserOptions`.
|
|
9
|
+
* `gfm` (tables, task lists, strikethrough, autolinks) is on by default because
|
|
10
|
+
* it's what people mean by "markdown" today.
|
|
11
|
+
*/
|
|
12
|
+
interface MarkdownParseOptions {
|
|
13
|
+
/** GitHub-Flavored Markdown: tables, task lists, strikethrough, autolinks. Default `true`. */
|
|
14
|
+
gfm?: boolean;
|
|
15
|
+
/** `$…$` / `$$…$$` math. Off by default (needs a math-capable component override to render). */
|
|
16
|
+
math?: ParserOptions['math'];
|
|
17
|
+
/** `:::` directive containers. Off by default. */
|
|
18
|
+
containers?: ParserOptions['containers'];
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Parse markdown into an mdast `Root` with incremark, memoized by
|
|
22
|
+
* `(source, options)` and parsed **incrementally** when the source grows.
|
|
23
|
+
*
|
|
24
|
+
* Pure and synchronous — safe to call inside mugen's measure walk. Growing the
|
|
25
|
+
* same source (a streaming row) appends only the new text to a retained parser;
|
|
26
|
+
* an unchanged source is served from the AST cache; a non-extending change parses
|
|
27
|
+
* fresh.
|
|
28
|
+
*/
|
|
29
|
+
declare function parseMarkdown(source: string, options?: MarkdownParseOptions): Root$1;
|
|
30
|
+
/** Drop the parse caches and retained parsers (tests / memory pressure). */
|
|
31
|
+
declare function clearParseCache(): void;
|
|
32
|
+
//#endregion
|
|
33
|
+
//#region src/highlight/types.d.ts
|
|
34
|
+
/**
|
|
35
|
+
* Token vocabulary for the built-in code-block highlighter. The set is small on
|
|
36
|
+
* purpose: highlighting is purely cosmetic paint layered over already-laid-out
|
|
37
|
+
* text, so a coarse classification that is cheap to compute incrementally beats
|
|
38
|
+
* a grammar-exact one that would need a real parser.
|
|
39
|
+
*/
|
|
40
|
+
type TokenType = 'keyword' | 'string' | 'comment' | 'number' | 'constant' | 'function' | 'type' | 'property' | 'operator' | 'punctuation';
|
|
41
|
+
/**
|
|
42
|
+
* One colour per token type. A value of `'currentColor'` paints that token in
|
|
43
|
+
* the block's own text colour (whatever `color` computes to on the `<code>`),
|
|
44
|
+
* which is how a token type opts out of special colouring.
|
|
45
|
+
*/
|
|
46
|
+
type CodeTokenColors = Record<TokenType, string>;
|
|
47
|
+
/**
|
|
48
|
+
* Default palette: mid-tone colours chosen to stay legible on both light and
|
|
49
|
+
* dark page backgrounds, since the default theme inherits the page colours.
|
|
50
|
+
*/
|
|
51
|
+
declare const defaultTokenColors: CodeTokenColors;
|
|
52
|
+
//#endregion
|
|
53
|
+
//#region src/theme.d.ts
|
|
54
|
+
/**
|
|
55
|
+
* The markdown theme. Every value that affects a box's height — fonts, line
|
|
56
|
+
* heights, paddings, gaps — lives here as a concrete number/family, because the
|
|
57
|
+
* dispatcher bakes them into primitive props (the measure walk only sees props,
|
|
58
|
+
* never React context). Colours and other purely-cosmetic values live here too,
|
|
59
|
+
* for one-stop styling.
|
|
60
|
+
*
|
|
61
|
+
* Fonts are given as a **family** plus sizes/weights, not as full `Font`
|
|
62
|
+
* shorthands, so the dispatcher can compose inline variants (bold inside a
|
|
63
|
+
* heading, code inside a paragraph) without you spelling out every combination.
|
|
64
|
+
* Families must be measurable — a named web font (`"Inter"`) or a canvas-safe
|
|
65
|
+
* generic (`"sans-serif"`, `"monospace"`); `"system-ui"` is rejected at measure
|
|
66
|
+
* time because its canvas metrics drift from what CSS paints.
|
|
67
|
+
*/
|
|
68
|
+
interface MarkdownTheme {
|
|
69
|
+
/** Body text family, e.g. `"Inter"` or `"sans-serif"`. */
|
|
70
|
+
fontFamily: string;
|
|
71
|
+
/** Monospace family for code, e.g. `"JetBrains Mono"` or `"monospace"`. */
|
|
72
|
+
monoFamily: string;
|
|
73
|
+
/** Body font size in px. */
|
|
74
|
+
fontSize: number;
|
|
75
|
+
/** Body line height in px. */
|
|
76
|
+
lineHeight: number;
|
|
77
|
+
/** Default text colour (any CSS colour; `"inherit"` follows the surrounding CSS). */
|
|
78
|
+
color: string;
|
|
79
|
+
/** Vertical gap between adjacent blocks, in px. */
|
|
80
|
+
blockGap: number;
|
|
81
|
+
heading: {
|
|
82
|
+
weight: number;
|
|
83
|
+
color: string; /** Font size per heading depth, in px. */
|
|
84
|
+
sizes: Record<1 | 2 | 3 | 4 | 5 | 6, number>; /** Line height per heading depth, in px. */
|
|
85
|
+
lineHeights: Record<1 | 2 | 3 | 4 | 5 | 6, number>;
|
|
86
|
+
};
|
|
87
|
+
/** Weight applied to `**strong**` text. */
|
|
88
|
+
strongWeight: number;
|
|
89
|
+
/** Whether `*emphasis*` renders italic (needs an italic face of the family). */
|
|
90
|
+
emphasisItalic: boolean;
|
|
91
|
+
link: {
|
|
92
|
+
color: string;
|
|
93
|
+
underline: boolean;
|
|
94
|
+
};
|
|
95
|
+
inlineCode: {
|
|
96
|
+
color: string;
|
|
97
|
+
background: string; /** Inline-code size as a fraction of the surrounding text size. */
|
|
98
|
+
sizeScale: number;
|
|
99
|
+
};
|
|
100
|
+
code: {
|
|
101
|
+
fontSize: number;
|
|
102
|
+
lineHeight: number;
|
|
103
|
+
padding: number;
|
|
104
|
+
background: string;
|
|
105
|
+
color: string;
|
|
106
|
+
radius: number;
|
|
107
|
+
/**
|
|
108
|
+
* Token palette for the built-in non-blocking canvas highlighter, or
|
|
109
|
+
* `false` to disable highlighting. Colours are paint-only — they can never
|
|
110
|
+
* change a block's measured height.
|
|
111
|
+
*/
|
|
112
|
+
highlight: CodeTokenColors | false;
|
|
113
|
+
};
|
|
114
|
+
blockquote: {
|
|
115
|
+
padding: number;
|
|
116
|
+
gap: number;
|
|
117
|
+
borderWidth: number;
|
|
118
|
+
borderColor: string;
|
|
119
|
+
color: string;
|
|
120
|
+
};
|
|
121
|
+
list: {
|
|
122
|
+
/** Gap between list items, in px. */gap: number; /** Width of the marker column (bullet / number), in px. */
|
|
123
|
+
indent: number;
|
|
124
|
+
markerColor: string;
|
|
125
|
+
};
|
|
126
|
+
table: {
|
|
127
|
+
/** Uniform cell padding in px (uniform so the analytic height stays exact). */cellPadding: number; /** Hairline between rows (and the outer ring) in px; 0 disables both. */
|
|
128
|
+
gap: number;
|
|
129
|
+
headerWeight: number; /** Background behind the header row. */
|
|
130
|
+
headerBackground: string; /** Hairline / outer-ring colour. */
|
|
131
|
+
borderColor: string; /** Corner radius in px (clip only — no height impact). */
|
|
132
|
+
radius: number;
|
|
133
|
+
};
|
|
134
|
+
rule: {
|
|
135
|
+
thickness: number;
|
|
136
|
+
color: string;
|
|
137
|
+
gap: number;
|
|
138
|
+
};
|
|
139
|
+
/**
|
|
140
|
+
* Images have no intrinsic measurable height, so the default `image` component
|
|
141
|
+
* renders a fixed-height box. Override the `image` component for real layout.
|
|
142
|
+
*/
|
|
143
|
+
image: {
|
|
144
|
+
placeholderHeight: number;
|
|
145
|
+
color: string;
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
type DeepPartial<T> = T extends (infer U)[] ? DeepPartial<U>[] : T extends object ? { [K in keyof T]?: DeepPartial<T[K]> } : T;
|
|
149
|
+
declare const defaultTheme: MarkdownTheme;
|
|
150
|
+
/** Merge a partial theme over the defaults into a fully-resolved theme. */
|
|
151
|
+
declare function resolveTheme(theme?: DeepPartial<MarkdownTheme>): MarkdownTheme;
|
|
152
|
+
//#endregion
|
|
153
|
+
//#region src/primitives/rich-text.d.ts
|
|
154
|
+
/**
|
|
155
|
+
* One styled span of inline text. A `RichText` is a sequence of runs that wrap
|
|
156
|
+
* together as a single flowing paragraph — the thing markdown inline content
|
|
157
|
+
* (bold, italic, code, links inside a sentence) needs and that a single-font
|
|
158
|
+
* `<Text>` can't express. Each run carries its own measurable `font`, so the
|
|
159
|
+
* mixed fonts on a line are measured exactly (via `@chenglou/pretext`'s
|
|
160
|
+
* rich-inline layout) and the painted spans use the identical fonts.
|
|
161
|
+
*/
|
|
162
|
+
interface RichTextRun {
|
|
163
|
+
/** The run's text. Ignored when `break` is set. */
|
|
164
|
+
text: string;
|
|
165
|
+
/** Measurable font for this run; falls back to the `<RichText font>` prop. */
|
|
166
|
+
font?: Font$1;
|
|
167
|
+
color?: string;
|
|
168
|
+
/** Background (e.g. inline-code chip). Cosmetic — does not affect height. */
|
|
169
|
+
background?: string;
|
|
170
|
+
/** CSS `text-decoration` (e.g. `"underline"`, `"line-through"`). Cosmetic. */
|
|
171
|
+
decoration?: string;
|
|
172
|
+
/** Render as a link with this `href` (sets the tag to `<a>` unless `as` is given). */
|
|
173
|
+
href?: string;
|
|
174
|
+
title?: string;
|
|
175
|
+
onClick?: (e: unknown) => void;
|
|
176
|
+
/** The element tag for this run. Defaults to `a` when `href` is set, else `span`. */
|
|
177
|
+
as?: keyof JSX.IntrinsicElements;
|
|
178
|
+
/** Forbid line breaks inside this run. */
|
|
179
|
+
noBreak?: boolean;
|
|
180
|
+
letterSpacing?: number;
|
|
181
|
+
className?: string;
|
|
182
|
+
/** A hard line break (renders `<br>`, forces a new line in the measure). */
|
|
183
|
+
break?: boolean;
|
|
184
|
+
}
|
|
185
|
+
interface RichTextProps<C extends string = string> {
|
|
186
|
+
/** The inline runs to flow together. */
|
|
187
|
+
runs: RichTextRun[];
|
|
188
|
+
/** Line height in px — the height of every wrapped line. Required. */
|
|
189
|
+
lineHeight: number;
|
|
190
|
+
/** Fallback font for runs that don't set their own. */
|
|
191
|
+
font?: Font$1;
|
|
192
|
+
color?: string;
|
|
193
|
+
align?: CSSProperties['textAlign'];
|
|
194
|
+
/** Inline styles, minus spacing/sizing (owned by the layout). */
|
|
195
|
+
style?: MeasurableStyle;
|
|
196
|
+
className?: SafeClassName<C>;
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* A measurable rich inline-text primitive: a paragraph of mixed-font runs that
|
|
200
|
+
* wrap as one flow. Its height is `lines × lineHeight`, where `lines` comes from
|
|
201
|
+
* pretext's rich-inline layout at the row's width — the same layout the browser
|
|
202
|
+
* performs over the rendered spans, so the analytic height matches the paint.
|
|
203
|
+
*/
|
|
204
|
+
declare const RichText: <C extends string = string>(props: RichTextProps<C>) => ReactElement;
|
|
205
|
+
/** Drop the rich-inline prepare cache (tests / memory pressure). */
|
|
206
|
+
declare function clearRichTextCache(): void;
|
|
207
|
+
//#endregion
|
|
208
|
+
//#region src/inline.d.ts
|
|
209
|
+
/**
|
|
210
|
+
* The mutable styling state threaded through the inline walk. Markdown inline
|
|
211
|
+
* marks (`**`, `*`, `` ` ``, `[]()`) nest, so we carry the composed format down
|
|
212
|
+
* and emit a styled run at each text leaf. Fonts are composed here — a `<strong>`
|
|
213
|
+
* inside a heading produces one bold run at the heading's size — which is what
|
|
214
|
+
* lets the rich-inline measurement see every mixed font exactly.
|
|
215
|
+
*/
|
|
216
|
+
interface InlineFormat {
|
|
217
|
+
family: string;
|
|
218
|
+
monoFamily: string;
|
|
219
|
+
size: number;
|
|
220
|
+
weight: number;
|
|
221
|
+
italic: boolean;
|
|
222
|
+
mono: boolean;
|
|
223
|
+
underline: boolean;
|
|
224
|
+
strike: boolean;
|
|
225
|
+
color?: string;
|
|
226
|
+
background?: string;
|
|
227
|
+
href?: string;
|
|
228
|
+
}
|
|
229
|
+
/** A base format for body text at a given size/weight/colour. */
|
|
230
|
+
declare function baseFormat(theme: MarkdownTheme, opts?: {
|
|
231
|
+
size?: number;
|
|
232
|
+
weight?: number;
|
|
233
|
+
color?: string;
|
|
234
|
+
}): InlineFormat;
|
|
235
|
+
/** Compose a measurable `Font` shorthand from a format. */
|
|
236
|
+
declare function composeFont(fmt: InlineFormat): Font$1;
|
|
237
|
+
/**
|
|
238
|
+
* Flatten phrasing content into styled runs. Recursive over the inline marks;
|
|
239
|
+
* the result feeds a single `<RichText>` so the whole paragraph wraps as one
|
|
240
|
+
* flow and measures exactly.
|
|
241
|
+
*/
|
|
242
|
+
declare function flattenInline(nodes: readonly PhrasingContent$1[], fmt: InlineFormat, theme: MarkdownTheme, out: RichTextRun[]): void;
|
|
243
|
+
//#endregion
|
|
244
|
+
//#region src/types.d.ts
|
|
245
|
+
/** Options for building a body/heading inline-text (`RichText`) element. */
|
|
246
|
+
interface InlineTextOptions {
|
|
247
|
+
/** Font size in px (defaults to the theme body size). */
|
|
248
|
+
size?: number;
|
|
249
|
+
/** Font weight (defaults to 400). */
|
|
250
|
+
weight?: number;
|
|
251
|
+
/** Line height in px (defaults to the theme body line height). */
|
|
252
|
+
lineHeight?: number;
|
|
253
|
+
color?: string;
|
|
254
|
+
align?: CSSProperties['textAlign'];
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* The context threaded to every markdown component. It carries the resolved
|
|
258
|
+
* theme and the helpers a component needs to recurse — all of which return
|
|
259
|
+
* **mugen primitives**, so whatever a component builds with them stays
|
|
260
|
+
* measurable by mugen's tree walker.
|
|
261
|
+
*/
|
|
262
|
+
interface MarkdownRenderContext {
|
|
263
|
+
/** The fully-resolved theme. */
|
|
264
|
+
readonly theme: MarkdownTheme;
|
|
265
|
+
/** The resolved component set (defaults merged with user overrides). */
|
|
266
|
+
readonly components: ResolvedMarkdownComponents;
|
|
267
|
+
/** Render a list of block nodes as a vertically-stacked subtree (gap defaults to `theme.blockGap`). */
|
|
268
|
+
renderBlocks(nodes: readonly RootContent$1[], gap?: number): ReactNode;
|
|
269
|
+
/** Render a single block node, dispatching to its component. */
|
|
270
|
+
renderBlock(node: RootContent$1, key?: string | number): ReactNode;
|
|
271
|
+
/** The default inner rendering for a node (inline `RichText`, or rendered child blocks). */
|
|
272
|
+
renderChildren(node: RootContent$1): ReactNode;
|
|
273
|
+
/** Flatten phrasing content into styled `RichText` runs at an optional base format. */
|
|
274
|
+
inlineRuns(nodes: readonly PhrasingContent$1[], base?: Partial<InlineFormat>): RichTextRun[];
|
|
275
|
+
/** Build a `RichText` element from phrasing content (the inline pipeline). */
|
|
276
|
+
inlineText(nodes: readonly PhrasingContent$1[], opts?: InlineTextOptions): ReactNode;
|
|
277
|
+
/**
|
|
278
|
+
* Memoize a rendered element by its `node`'s content, so streaming re-renders
|
|
279
|
+
* reuse it (React then bails out). `variant` distinguishes renderings of the
|
|
280
|
+
* same node that differ by sibling context — e.g. a list item's index/marker
|
|
281
|
+
* or a table cell's column. Use it in custom `list`/`table` components so their
|
|
282
|
+
* already-finished items/cells don't re-render while a later one streams in.
|
|
283
|
+
*/
|
|
284
|
+
memo(node: object, variant: string, build: () => ReactNode): ReactNode;
|
|
285
|
+
}
|
|
286
|
+
/**
|
|
287
|
+
* Props every markdown component receives. `node` is the typed mdast node,
|
|
288
|
+
* `children` is what the default component would render inside (so an override
|
|
289
|
+
* can wrap it), and `ctx` exposes the recursion + theme helpers.
|
|
290
|
+
*/
|
|
291
|
+
interface MarkdownComponentProps<N> {
|
|
292
|
+
node: N;
|
|
293
|
+
children: ReactNode;
|
|
294
|
+
ctx: MarkdownRenderContext;
|
|
295
|
+
}
|
|
296
|
+
/**
|
|
297
|
+
* A markdown component. It must return mugen primitives (or hook-free
|
|
298
|
+
* compositions of them) so mugen's walker can measure the row — use the
|
|
299
|
+
* primitives re-exported from this package and the `ctx` helpers.
|
|
300
|
+
*/
|
|
301
|
+
type MarkdownComponent<N> = (props: MarkdownComponentProps<N>) => ReactNode;
|
|
302
|
+
/**
|
|
303
|
+
* The overridable block-level components, keyed by mdast node type and typed to
|
|
304
|
+
* the matching node. Inline marks (bold, italic, code, links) are styled through
|
|
305
|
+
* the {@link MarkdownTheme} rather than as components, because inline content
|
|
306
|
+
* must collapse into a single wrapping flow to be measured exactly.
|
|
307
|
+
*/
|
|
308
|
+
interface MarkdownComponents {
|
|
309
|
+
paragraph?: MarkdownComponent<Paragraph$1>;
|
|
310
|
+
heading?: MarkdownComponent<Heading$1>;
|
|
311
|
+
thematicBreak?: MarkdownComponent<ThematicBreak$1>;
|
|
312
|
+
blockquote?: MarkdownComponent<Blockquote$1>;
|
|
313
|
+
list?: MarkdownComponent<List$1>;
|
|
314
|
+
code?: MarkdownComponent<Code$1>;
|
|
315
|
+
table?: MarkdownComponent<Table$1>;
|
|
316
|
+
image?: MarkdownComponent<Image$1>;
|
|
317
|
+
html?: MarkdownComponent<Html$1>;
|
|
318
|
+
}
|
|
319
|
+
type ResolvedMarkdownComponents = Required<MarkdownComponents>;
|
|
320
|
+
/**
|
|
321
|
+
* Identity helper for authoring a typed component set with full inference and
|
|
322
|
+
* `node` narrowing per key:
|
|
323
|
+
*
|
|
324
|
+
* ```tsx
|
|
325
|
+
* const components = defineMarkdownComponents({
|
|
326
|
+
* heading: ({ node, children }) => // node is Heading, node.depth is 1..6
|
|
327
|
+
* <VStack>{children}</VStack>,
|
|
328
|
+
* });
|
|
329
|
+
* ```
|
|
330
|
+
*/
|
|
331
|
+
declare function defineMarkdownComponents(components: MarkdownComponents): MarkdownComponents;
|
|
332
|
+
//#endregion
|
|
333
|
+
//#region src/components.d.ts
|
|
334
|
+
declare const defaultComponents: ResolvedMarkdownComponents;
|
|
335
|
+
//#endregion
|
|
336
|
+
//#region src/render.d.ts
|
|
337
|
+
interface RenderMarkdownOptions {
|
|
338
|
+
/** Theme overrides (deep-merged over the defaults). */
|
|
339
|
+
theme?: DeepPartial<MarkdownTheme>;
|
|
340
|
+
/** Block-component overrides. */
|
|
341
|
+
components?: MarkdownComponents;
|
|
342
|
+
/** Parser options (gfm, math, containers). */
|
|
343
|
+
parserOptions?: MarkdownParseOptions;
|
|
344
|
+
}
|
|
345
|
+
/**
|
|
346
|
+
* Parse `source` and render it into a tree of mugen primitives. The result is
|
|
347
|
+
* pure and hook-free, so it can be returned straight from a `<MugenVList>`
|
|
348
|
+
* `render` and measured by the walker. Memoization of parsing/theme/components
|
|
349
|
+
* keeps the measure and render passes cheap.
|
|
350
|
+
*/
|
|
351
|
+
declare function renderMarkdown(source: string, options?: RenderMarkdownOptions): ReactNode;
|
|
352
|
+
//#endregion
|
|
353
|
+
//#region src/markdown.d.ts
|
|
354
|
+
interface MarkdownProps extends RenderMarkdownOptions {
|
|
355
|
+
/** The markdown source to render. */
|
|
356
|
+
source: string;
|
|
357
|
+
}
|
|
358
|
+
/**
|
|
359
|
+
* Render markdown as a tree of mugen primitives.
|
|
360
|
+
*
|
|
361
|
+
* `<Markdown>` is a **pure, hook-free** component: it parses `source` with
|
|
362
|
+
* incremark and maps the AST to mugen primitives, producing the identical tree
|
|
363
|
+
* in mugen's measure walk and in React's render. Drop it straight into a
|
|
364
|
+
* `<MugenVList>` `render` and every row — on- or off-screen — gets an exact,
|
|
365
|
+
* analytic height.
|
|
366
|
+
*
|
|
367
|
+
* ```tsx
|
|
368
|
+
* <MugenVList
|
|
369
|
+
* instance={list}
|
|
370
|
+
* getKey={(m) => m.id}
|
|
371
|
+
* render={(m) => <Markdown source={m.body} />}
|
|
372
|
+
* />
|
|
373
|
+
* ```
|
|
374
|
+
*
|
|
375
|
+
* Extend it with typed, per-node `components` (built from the same primitives)
|
|
376
|
+
* and a deep-partial `theme`.
|
|
377
|
+
*/
|
|
378
|
+
declare function Markdown(props: MarkdownProps): ReactNode;
|
|
379
|
+
declare namespace Markdown {
|
|
380
|
+
var displayName: string;
|
|
381
|
+
}
|
|
382
|
+
//#endregion
|
|
383
|
+
//#region src/primitives/code-block.d.ts
|
|
384
|
+
/**
|
|
385
|
+
* A fenced code block. Code does not wrap — long lines scroll horizontally — so
|
|
386
|
+
* its height is simply `lineCount × lineHeight + 2 × padding`, independent of the
|
|
387
|
+
* row width. That makes it trivially and exactly measurable.
|
|
388
|
+
*
|
|
389
|
+
* Syntax highlighting is layered on as pure paint, never layout: the `<code>`
|
|
390
|
+
* text renders immediately (plain, selectable, accessible), the language is
|
|
391
|
+
* tokenized off the critical path in time-sliced chunks, and token colours are
|
|
392
|
+
* painted onto canvas tiles overlaying the text — at which point the DOM text
|
|
393
|
+
* turns `color: transparent` in the same frame. Highlighting therefore can't
|
|
394
|
+
* block first paint and can't ever change the measured height.
|
|
395
|
+
*/
|
|
396
|
+
interface CodeBlockProps<C extends string = string> {
|
|
397
|
+
/** Raw code text. Newlines determine the line count. */
|
|
398
|
+
value: string;
|
|
399
|
+
/** Info-string language, if any (drives the built-in highlighter / labels). */
|
|
400
|
+
lang?: string;
|
|
401
|
+
/** Monospace font. Required. */
|
|
402
|
+
font: Font$1;
|
|
403
|
+
/** Line height in px. Required. */
|
|
404
|
+
lineHeight: number;
|
|
405
|
+
/** Uniform padding in px (chrome counted in the height). */
|
|
406
|
+
padding?: number;
|
|
407
|
+
background?: string;
|
|
408
|
+
color?: string;
|
|
409
|
+
radius?: number;
|
|
410
|
+
/**
|
|
411
|
+
* Token-colour overrides for the built-in canvas highlighter, or `false` to
|
|
412
|
+
* disable it. Defaults to {@link defaultTokenColors}; only languages with a
|
|
413
|
+
* registered profile are highlighted either way.
|
|
414
|
+
*/
|
|
415
|
+
highlight?: Partial<CodeTokenColors> | false;
|
|
416
|
+
style?: MeasurableStyle;
|
|
417
|
+
className?: SafeClassName<C>;
|
|
418
|
+
}
|
|
419
|
+
/** A measurable fenced-code primitive (no wrapping; height from line count). */
|
|
420
|
+
declare const CodeBlock: <C extends string = string>(props: CodeBlockProps<C>) => ReactElement;
|
|
421
|
+
//#endregion
|
|
422
|
+
//#region src/primitives/table-block.d.ts
|
|
423
|
+
/**
|
|
424
|
+
* A GFM table that *looks* like a table and is still exactly measurable.
|
|
425
|
+
*
|
|
426
|
+
* Every row shares one set of column widths, proportional to each column's
|
|
427
|
+
* max-content width across all rows (floored so a tiny column stays
|
|
428
|
+
* readable). Cells paint as `flex: ratio ratio 0` — with basis 0, flexbox
|
|
429
|
+
* resolves each column to `width × ratio / Σratios`, which is the same
|
|
430
|
+
* arithmetic the measure runs, so the heights agree at any width and the
|
|
431
|
+
* columns align across rows.
|
|
432
|
+
*
|
|
433
|
+
* Chrome is height-neutral by construction: row hairlines are real
|
|
434
|
+
* `divider`-px elements (counted in the height), while the outer ring is an
|
|
435
|
+
* inset box-shadow and the corner radius is pure overflow clipping — neither
|
|
436
|
+
* consumes width or height the walker can't see.
|
|
437
|
+
*/
|
|
438
|
+
interface TableBlockProps<C extends string = string> {
|
|
439
|
+
/** Cell content per row, header row first. Rows may be ragged. */
|
|
440
|
+
rows: ReactNode[][];
|
|
441
|
+
/** Uniform cell padding in px (counted in the height). */
|
|
442
|
+
cellPadding: number;
|
|
443
|
+
/** Hairline between rows and the outer ring, in px. 0 disables both. */
|
|
444
|
+
divider: number;
|
|
445
|
+
/** Hairline / ring colour. */
|
|
446
|
+
borderColor: string;
|
|
447
|
+
/** Background behind the header row. */
|
|
448
|
+
headerBackground: string;
|
|
449
|
+
/** Corner radius in px (clip only — no height impact). */
|
|
450
|
+
radius: number;
|
|
451
|
+
style?: MeasurableStyle;
|
|
452
|
+
className?: SafeClassName<C>;
|
|
453
|
+
}
|
|
454
|
+
/** A measurable GFM-table primitive with aligned, content-proportional columns. */
|
|
455
|
+
declare const TableBlock: <C extends string = string>(props: TableBlockProps<C>) => ReactElement;
|
|
456
|
+
//#endregion
|
|
457
|
+
//#region src/highlight/languages.d.ts
|
|
458
|
+
/**
|
|
459
|
+
* Language profiles for the built-in tokenizer. A profile is a small data
|
|
460
|
+
* description — comment markers, string delimiters, keyword sets, and a few
|
|
461
|
+
* classification heuristics — interpreted by one shared scanner, so adding a
|
|
462
|
+
* language is a handful of lines rather than a grammar.
|
|
463
|
+
*/
|
|
464
|
+
interface LanguageProfile {
|
|
465
|
+
/** Markers that comment to end-of-line (`//`, `#`, `--`). */
|
|
466
|
+
lineComments: readonly string[];
|
|
467
|
+
/** Open/close pairs that may span lines (C-style block comments, `<!-- … -->`). */
|
|
468
|
+
blockComments: readonly (readonly [string, string])[];
|
|
469
|
+
/** Single-char string delimiters; an unclosed one ends at end-of-line. */
|
|
470
|
+
quotes: readonly string[];
|
|
471
|
+
/** String delimiters that carry across lines (`` ` ``, `'''`, `"""`). */
|
|
472
|
+
multilineQuotes: readonly string[];
|
|
473
|
+
keywords: ReadonlySet<string>;
|
|
474
|
+
constants: ReadonlySet<string>;
|
|
475
|
+
/** Colour Capitalised identifiers as types. */
|
|
476
|
+
capitalTypes: boolean;
|
|
477
|
+
/** Extra identifier characters beyond `[A-Za-z0-9_$]` (e.g. `-` for CSS). */
|
|
478
|
+
identExtra: string;
|
|
479
|
+
/** Lower-case words before keyword/constant lookup (SQL, Dockerfile). */
|
|
480
|
+
caseInsensitive?: boolean;
|
|
481
|
+
/** A string immediately followed by `:` is a property key (JSON). */
|
|
482
|
+
stringKeys?: boolean;
|
|
483
|
+
/** An identifier immediately followed by `:` is a property key. */
|
|
484
|
+
colonProps?: boolean;
|
|
485
|
+
/** An identifier followed by `=` (not `==`) is a property/attribute name. */
|
|
486
|
+
eqProps?: boolean;
|
|
487
|
+
/** An identifier right after `<` or `</` is a tag name (HTML/XML). */
|
|
488
|
+
tags?: boolean;
|
|
489
|
+
}
|
|
490
|
+
/**
|
|
491
|
+
* Register a profile under one or more fence info-string names (lower-cased).
|
|
492
|
+
* Use this to add or override languages for the built-in highlighter.
|
|
493
|
+
*/
|
|
494
|
+
declare function registerLanguage(names: string | readonly string[], p: LanguageProfile): void;
|
|
495
|
+
/** The profile for a fence language, or `null` when the language is unknown. */
|
|
496
|
+
declare function profileFor(lang: string | undefined): LanguageProfile | null;
|
|
497
|
+
//#endregion
|
|
498
|
+
export { type Blockquote, type BoxProps, type Code, CodeBlock, type CodeBlockProps, type CodeTokenColors, type DeepPartial, type Font, HStack, type HStackProps, type Heading, type Html, type Image, type InlineFormat, type InlineTextOptions, type LanguageProfile, type Link, type List, type ListItem, Markdown, type MarkdownComponent, type MarkdownComponentProps, type MarkdownComponents, type MarkdownParseOptions, type MarkdownProps, type MarkdownRenderContext, type MarkdownTheme, type Paragraph, type PhrasingContent, type PrimitiveComponent, type RenderMarkdownOptions, type ResolvedMarkdownComponents, RichText, type RichTextProps, type RichTextRun, type Root, type RootContent, type Table, TableBlock, type TableBlockProps, type TableCell, type TableRow, Text, type TextProps, type ThematicBreak, type TokenType, VStack, type VStackProps, baseFormat, clearParseCache, clearRichTextCache, composeFont, defaultComponents, defaultTheme, defaultTokenColors, defineMarkdownComponents, definePrimitive, flattenInline, parseMarkdown, profileFor, registerLanguage, renderMarkdown, resolveTheme };
|