@changerawr/markdown 1.1.10 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +22 -13
- package/dist/astro/MarkdownRenderer.astro +31 -0
- package/dist/astro/index.d.mts +213 -0
- package/dist/astro/index.d.ts +213 -0
- package/dist/astro/index.js +2177 -0
- package/dist/astro/index.js.map +1 -0
- package/dist/astro/index.mjs +2135 -0
- package/dist/astro/index.mjs.map +1 -0
- package/dist/css/index.css +395 -33
- package/dist/index.d.mts +32 -1
- package/dist/index.d.ts +32 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs.map +1 -1
- package/dist/react/index.d.mts +133 -2
- package/dist/react/index.d.ts +133 -2
- package/dist/react/index.js +120 -15
- package/dist/react/index.js.map +1 -1
- package/dist/react/index.mjs +116 -13
- package/dist/react/index.mjs.map +1 -1
- package/dist/tailwind/index.d.mts +16 -8
- package/dist/tailwind/index.d.ts +16 -8
- package/dist/tailwind/index.js +41 -35
- package/dist/tailwind/index.js.map +1 -1
- package/dist/tailwind/index.mjs +40 -35
- package/dist/tailwind/index.mjs.map +1 -1
- package/package.json +9 -3
package/dist/react/index.d.mts
CHANGED
|
@@ -22,6 +22,37 @@ interface Extension {
|
|
|
22
22
|
parseRules: ParseRule[];
|
|
23
23
|
renderRules: RenderRule[];
|
|
24
24
|
}
|
|
25
|
+
/**
|
|
26
|
+
* Props passed to a framework component registered on a ComponentRenderRule.
|
|
27
|
+
* The `children` type is intentionally `unknown` here — each framework binding
|
|
28
|
+
* (React, Astro, etc.) narrows it to the correct type in its own module.
|
|
29
|
+
*/
|
|
30
|
+
interface ComponentTokenProps {
|
|
31
|
+
token: MarkdownToken;
|
|
32
|
+
/** Pre-rendered children (framework-specific ReactNode, Astro.slots, etc.) */
|
|
33
|
+
children?: unknown;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* A render rule that optionally carries a framework component.
|
|
37
|
+
* The `render` function is always required as a string-output fallback used by
|
|
38
|
+
* HTML / Tailwind / JSON / Astro outputs. Framework renderers (React, etc.)
|
|
39
|
+
* will prefer `component` when present.
|
|
40
|
+
*/
|
|
41
|
+
interface ComponentRenderRule extends RenderRule {
|
|
42
|
+
/**
|
|
43
|
+
* Framework component (React.ComponentType, Svelte component, etc.).
|
|
44
|
+
* Typed as `unknown` here; each framework module provides a narrowed variant.
|
|
45
|
+
*/
|
|
46
|
+
component?: unknown;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* An Extension that may carry framework components on its render rules.
|
|
50
|
+
* It is fully compatible with the base `Extension` type and can be registered
|
|
51
|
+
* with the engine like any regular extension — the engine only uses `render`.
|
|
52
|
+
*/
|
|
53
|
+
interface ComponentExtension extends Extension {
|
|
54
|
+
renderRules: ComponentRenderRule[];
|
|
55
|
+
}
|
|
25
56
|
type OutputFormat = 'html' | 'tailwind' | 'json';
|
|
26
57
|
interface RendererConfig {
|
|
27
58
|
format: OutputFormat;
|
|
@@ -61,6 +92,33 @@ interface ExtensionRegistration {
|
|
|
61
92
|
conflictingRules?: string[];
|
|
62
93
|
}
|
|
63
94
|
|
|
95
|
+
/**
|
|
96
|
+
* Props passed to a React component registered on a ReactComponentRenderRule.
|
|
97
|
+
*/
|
|
98
|
+
interface ReactComponentTokenProps {
|
|
99
|
+
token: MarkdownToken;
|
|
100
|
+
/** Rendered children as React nodes (nil when the token has no children) */
|
|
101
|
+
children?: React.ReactNode;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* A render rule that optionally carries a React component.
|
|
105
|
+
*/
|
|
106
|
+
interface ReactComponentRenderRule {
|
|
107
|
+
type: string;
|
|
108
|
+
/** React component used by the React renderer when present. */
|
|
109
|
+
component?: React.ComponentType<ReactComponentTokenProps>;
|
|
110
|
+
/** String fallback — used by HTML / Tailwind / Astro renderers. */
|
|
111
|
+
render: (token: MarkdownToken) => string;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* A ComponentExtension with React components attached to its render rules.
|
|
115
|
+
* Compatible with the base Extension interface — pass directly to createEngine().
|
|
116
|
+
*/
|
|
117
|
+
interface ReactComponentExtension {
|
|
118
|
+
name: string;
|
|
119
|
+
parseRules: ParseRule[];
|
|
120
|
+
renderRules: ReactComponentRenderRule[];
|
|
121
|
+
}
|
|
64
122
|
/**
|
|
65
123
|
* Props for the MarkdownRenderer component
|
|
66
124
|
*/
|
|
@@ -89,6 +147,12 @@ interface MarkdownRendererProps {
|
|
|
89
147
|
onError?: (error: Error) => void;
|
|
90
148
|
/** Custom extensions to register */
|
|
91
149
|
extensions?: Extension[];
|
|
150
|
+
/**
|
|
151
|
+
* Component extensions — extensions whose render rules carry React components.
|
|
152
|
+
* When provided the renderer switches from dangerouslySetInnerHTML to a React
|
|
153
|
+
* element tree, giving component-rendered tokens full React lifecycle support.
|
|
154
|
+
*/
|
|
155
|
+
componentExtensions?: ReactComponentExtension[];
|
|
92
156
|
/** Whether to sanitize HTML output */
|
|
93
157
|
sanitize?: boolean;
|
|
94
158
|
/** Allow unsafe HTML (use with caution) */
|
|
@@ -106,6 +170,8 @@ interface UseMarkdownOptions {
|
|
|
106
170
|
debug?: boolean;
|
|
107
171
|
/** Custom extensions */
|
|
108
172
|
extensions?: Extension[];
|
|
173
|
+
/** Component extensions (React-component-bearing extensions) */
|
|
174
|
+
componentExtensions?: ReactComponentExtension[];
|
|
109
175
|
/** Debounce delay in milliseconds */
|
|
110
176
|
debounceMs?: number;
|
|
111
177
|
/** Whether to memoize results */
|
|
@@ -129,6 +195,11 @@ interface UseMarkdownResult {
|
|
|
129
195
|
render: (content: string) => void;
|
|
130
196
|
/** Clear current state */
|
|
131
197
|
clear: () => void;
|
|
198
|
+
/**
|
|
199
|
+
* Render an arbitrary batch of tokens to an HTML string using the current engine.
|
|
200
|
+
* Used internally by TokenTreeRenderer to render non-component token groups.
|
|
201
|
+
*/
|
|
202
|
+
renderBatch: (tokens: MarkdownToken[]) => string;
|
|
132
203
|
}
|
|
133
204
|
/**
|
|
134
205
|
* Options for useMarkdownEngine hook
|
|
@@ -168,11 +239,37 @@ interface MarkdownDebugInfo {
|
|
|
168
239
|
* />
|
|
169
240
|
* ```
|
|
170
241
|
*/
|
|
171
|
-
declare function MarkdownRenderer({ content, className, config, format, as: Component, wrapperProps, debug, errorFallback, loading, onRender, onError, extensions, sanitize, allowUnsafeHtml, ...restProps }: MarkdownRendererProps): react_jsx_runtime.JSX.Element;
|
|
242
|
+
declare function MarkdownRenderer({ content, className, config, format, as: Component, wrapperProps, debug, errorFallback, loading, onRender, onError, extensions, componentExtensions, sanitize, allowUnsafeHtml, ...restProps }: MarkdownRendererProps): react_jsx_runtime.JSX.Element;
|
|
172
243
|
declare namespace MarkdownRenderer {
|
|
173
244
|
var displayName: string;
|
|
174
245
|
}
|
|
175
246
|
|
|
247
|
+
interface TokenTreeRendererProps {
|
|
248
|
+
tokens: MarkdownToken[];
|
|
249
|
+
/**
|
|
250
|
+
* Map from token type → the rule that carries a React component.
|
|
251
|
+
* Only rules that actually have a `component` field should be in this map.
|
|
252
|
+
*/
|
|
253
|
+
componentMap: Map<string, ReactComponentRenderRule>;
|
|
254
|
+
/**
|
|
255
|
+
* Renders a batch of tokens to an HTML string using the engine.
|
|
256
|
+
* Used for all tokens that don't have a React component attached.
|
|
257
|
+
*/
|
|
258
|
+
renderBatch: (tokens: MarkdownToken[]) => string;
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* TokenTreeRenderer — walks a token array and renders each token as either:
|
|
262
|
+
* • A React component (when the token type has a `component` registered)
|
|
263
|
+
* • A raw HTML chunk via `dangerouslySetInnerHTML` (everything else)
|
|
264
|
+
*
|
|
265
|
+
* Consecutive non-component tokens are batched into a single HTML chunk so that
|
|
266
|
+
* list-grouping and other renderer logic (which operates on slices) still works.
|
|
267
|
+
*
|
|
268
|
+
* ⚠ Limitation: list items must not be interleaved with component tokens —
|
|
269
|
+
* the list-grouping in MarkdownRenderer operates on contiguous slices.
|
|
270
|
+
*/
|
|
271
|
+
declare function TokenTreeRenderer({ tokens, componentMap, renderBatch }: TokenTreeRendererProps): React.ReactElement;
|
|
272
|
+
|
|
176
273
|
interface CacheStats {
|
|
177
274
|
size: number;
|
|
178
275
|
capacity: number;
|
|
@@ -280,5 +377,39 @@ declare function useMarkdownDebug(content: string): {
|
|
|
280
377
|
contentLength: number;
|
|
281
378
|
};
|
|
282
379
|
};
|
|
380
|
+
/**
|
|
381
|
+
* Hook for rendering markdown with React component extensions (TipTap-style).
|
|
382
|
+
*
|
|
383
|
+
* Returns the same values as `useMarkdown` plus:
|
|
384
|
+
* - `componentMap` — Map<tokenType, ReactComponentRenderRule> for TokenTreeRenderer
|
|
385
|
+
*
|
|
386
|
+
* @example
|
|
387
|
+
* ```tsx
|
|
388
|
+
* const CardExtension: ReactComponentExtension = {
|
|
389
|
+
* name: 'card',
|
|
390
|
+
* parseRules: [{ name: 'card', pattern: /:::card\n([\s\S]*?)\n:::/, render: (m) => ({ type: 'card', content: m[1] ?? '', raw: m[0] ?? '' }) }],
|
|
391
|
+
* renderRules: [{
|
|
392
|
+
* type: 'card',
|
|
393
|
+
* component: ({ token, children }) => <div className="card">{children}</div>,
|
|
394
|
+
* render: (token) => `<div class="card">${token.content}</div>`
|
|
395
|
+
* }]
|
|
396
|
+
* };
|
|
397
|
+
*
|
|
398
|
+
* const { tokens, componentMap, renderBatch } = useMarkdownComponents(content, { componentExtensions: [CardExtension] });
|
|
399
|
+
* ```
|
|
400
|
+
*/
|
|
401
|
+
declare function useMarkdownComponents(content: string, options?: UseMarkdownOptions & {
|
|
402
|
+
componentExtensions?: ReactComponentExtension[];
|
|
403
|
+
}): {
|
|
404
|
+
componentMap: Map<string, ReactComponentRenderRule>;
|
|
405
|
+
html: string;
|
|
406
|
+
tokens: MarkdownToken[];
|
|
407
|
+
isLoading: boolean;
|
|
408
|
+
error: Error | null;
|
|
409
|
+
debug: MarkdownDebugInfo | null;
|
|
410
|
+
render: (content: string) => void;
|
|
411
|
+
clear: () => void;
|
|
412
|
+
renderBatch: (tokens: MarkdownToken[]) => string;
|
|
413
|
+
};
|
|
283
414
|
|
|
284
|
-
export { type EngineConfig, type Extension, type MarkdownDebugInfo, type MarkdownEngineHookOptions, MarkdownRenderer, type MarkdownRendererProps, type MarkdownToken, type OutputFormat, type UseMarkdownOptions, type UseMarkdownResult, useMarkdown, useMarkdownDebug, useMarkdownEngine };
|
|
415
|
+
export { type ComponentExtension, type ComponentRenderRule, type ComponentTokenProps, type EngineConfig, type Extension, type MarkdownDebugInfo, type MarkdownEngineHookOptions, MarkdownRenderer, type MarkdownRendererProps, type MarkdownToken, type OutputFormat, type ReactComponentExtension, type ReactComponentRenderRule, type ReactComponentTokenProps, TokenTreeRenderer, type UseMarkdownOptions, type UseMarkdownResult, useMarkdown, useMarkdownComponents, useMarkdownDebug, useMarkdownEngine };
|
package/dist/react/index.d.ts
CHANGED
|
@@ -22,6 +22,37 @@ interface Extension {
|
|
|
22
22
|
parseRules: ParseRule[];
|
|
23
23
|
renderRules: RenderRule[];
|
|
24
24
|
}
|
|
25
|
+
/**
|
|
26
|
+
* Props passed to a framework component registered on a ComponentRenderRule.
|
|
27
|
+
* The `children` type is intentionally `unknown` here — each framework binding
|
|
28
|
+
* (React, Astro, etc.) narrows it to the correct type in its own module.
|
|
29
|
+
*/
|
|
30
|
+
interface ComponentTokenProps {
|
|
31
|
+
token: MarkdownToken;
|
|
32
|
+
/** Pre-rendered children (framework-specific ReactNode, Astro.slots, etc.) */
|
|
33
|
+
children?: unknown;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* A render rule that optionally carries a framework component.
|
|
37
|
+
* The `render` function is always required as a string-output fallback used by
|
|
38
|
+
* HTML / Tailwind / JSON / Astro outputs. Framework renderers (React, etc.)
|
|
39
|
+
* will prefer `component` when present.
|
|
40
|
+
*/
|
|
41
|
+
interface ComponentRenderRule extends RenderRule {
|
|
42
|
+
/**
|
|
43
|
+
* Framework component (React.ComponentType, Svelte component, etc.).
|
|
44
|
+
* Typed as `unknown` here; each framework module provides a narrowed variant.
|
|
45
|
+
*/
|
|
46
|
+
component?: unknown;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* An Extension that may carry framework components on its render rules.
|
|
50
|
+
* It is fully compatible with the base `Extension` type and can be registered
|
|
51
|
+
* with the engine like any regular extension — the engine only uses `render`.
|
|
52
|
+
*/
|
|
53
|
+
interface ComponentExtension extends Extension {
|
|
54
|
+
renderRules: ComponentRenderRule[];
|
|
55
|
+
}
|
|
25
56
|
type OutputFormat = 'html' | 'tailwind' | 'json';
|
|
26
57
|
interface RendererConfig {
|
|
27
58
|
format: OutputFormat;
|
|
@@ -61,6 +92,33 @@ interface ExtensionRegistration {
|
|
|
61
92
|
conflictingRules?: string[];
|
|
62
93
|
}
|
|
63
94
|
|
|
95
|
+
/**
|
|
96
|
+
* Props passed to a React component registered on a ReactComponentRenderRule.
|
|
97
|
+
*/
|
|
98
|
+
interface ReactComponentTokenProps {
|
|
99
|
+
token: MarkdownToken;
|
|
100
|
+
/** Rendered children as React nodes (nil when the token has no children) */
|
|
101
|
+
children?: React.ReactNode;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* A render rule that optionally carries a React component.
|
|
105
|
+
*/
|
|
106
|
+
interface ReactComponentRenderRule {
|
|
107
|
+
type: string;
|
|
108
|
+
/** React component used by the React renderer when present. */
|
|
109
|
+
component?: React.ComponentType<ReactComponentTokenProps>;
|
|
110
|
+
/** String fallback — used by HTML / Tailwind / Astro renderers. */
|
|
111
|
+
render: (token: MarkdownToken) => string;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* A ComponentExtension with React components attached to its render rules.
|
|
115
|
+
* Compatible with the base Extension interface — pass directly to createEngine().
|
|
116
|
+
*/
|
|
117
|
+
interface ReactComponentExtension {
|
|
118
|
+
name: string;
|
|
119
|
+
parseRules: ParseRule[];
|
|
120
|
+
renderRules: ReactComponentRenderRule[];
|
|
121
|
+
}
|
|
64
122
|
/**
|
|
65
123
|
* Props for the MarkdownRenderer component
|
|
66
124
|
*/
|
|
@@ -89,6 +147,12 @@ interface MarkdownRendererProps {
|
|
|
89
147
|
onError?: (error: Error) => void;
|
|
90
148
|
/** Custom extensions to register */
|
|
91
149
|
extensions?: Extension[];
|
|
150
|
+
/**
|
|
151
|
+
* Component extensions — extensions whose render rules carry React components.
|
|
152
|
+
* When provided the renderer switches from dangerouslySetInnerHTML to a React
|
|
153
|
+
* element tree, giving component-rendered tokens full React lifecycle support.
|
|
154
|
+
*/
|
|
155
|
+
componentExtensions?: ReactComponentExtension[];
|
|
92
156
|
/** Whether to sanitize HTML output */
|
|
93
157
|
sanitize?: boolean;
|
|
94
158
|
/** Allow unsafe HTML (use with caution) */
|
|
@@ -106,6 +170,8 @@ interface UseMarkdownOptions {
|
|
|
106
170
|
debug?: boolean;
|
|
107
171
|
/** Custom extensions */
|
|
108
172
|
extensions?: Extension[];
|
|
173
|
+
/** Component extensions (React-component-bearing extensions) */
|
|
174
|
+
componentExtensions?: ReactComponentExtension[];
|
|
109
175
|
/** Debounce delay in milliseconds */
|
|
110
176
|
debounceMs?: number;
|
|
111
177
|
/** Whether to memoize results */
|
|
@@ -129,6 +195,11 @@ interface UseMarkdownResult {
|
|
|
129
195
|
render: (content: string) => void;
|
|
130
196
|
/** Clear current state */
|
|
131
197
|
clear: () => void;
|
|
198
|
+
/**
|
|
199
|
+
* Render an arbitrary batch of tokens to an HTML string using the current engine.
|
|
200
|
+
* Used internally by TokenTreeRenderer to render non-component token groups.
|
|
201
|
+
*/
|
|
202
|
+
renderBatch: (tokens: MarkdownToken[]) => string;
|
|
132
203
|
}
|
|
133
204
|
/**
|
|
134
205
|
* Options for useMarkdownEngine hook
|
|
@@ -168,11 +239,37 @@ interface MarkdownDebugInfo {
|
|
|
168
239
|
* />
|
|
169
240
|
* ```
|
|
170
241
|
*/
|
|
171
|
-
declare function MarkdownRenderer({ content, className, config, format, as: Component, wrapperProps, debug, errorFallback, loading, onRender, onError, extensions, sanitize, allowUnsafeHtml, ...restProps }: MarkdownRendererProps): react_jsx_runtime.JSX.Element;
|
|
242
|
+
declare function MarkdownRenderer({ content, className, config, format, as: Component, wrapperProps, debug, errorFallback, loading, onRender, onError, extensions, componentExtensions, sanitize, allowUnsafeHtml, ...restProps }: MarkdownRendererProps): react_jsx_runtime.JSX.Element;
|
|
172
243
|
declare namespace MarkdownRenderer {
|
|
173
244
|
var displayName: string;
|
|
174
245
|
}
|
|
175
246
|
|
|
247
|
+
interface TokenTreeRendererProps {
|
|
248
|
+
tokens: MarkdownToken[];
|
|
249
|
+
/**
|
|
250
|
+
* Map from token type → the rule that carries a React component.
|
|
251
|
+
* Only rules that actually have a `component` field should be in this map.
|
|
252
|
+
*/
|
|
253
|
+
componentMap: Map<string, ReactComponentRenderRule>;
|
|
254
|
+
/**
|
|
255
|
+
* Renders a batch of tokens to an HTML string using the engine.
|
|
256
|
+
* Used for all tokens that don't have a React component attached.
|
|
257
|
+
*/
|
|
258
|
+
renderBatch: (tokens: MarkdownToken[]) => string;
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* TokenTreeRenderer — walks a token array and renders each token as either:
|
|
262
|
+
* • A React component (when the token type has a `component` registered)
|
|
263
|
+
* • A raw HTML chunk via `dangerouslySetInnerHTML` (everything else)
|
|
264
|
+
*
|
|
265
|
+
* Consecutive non-component tokens are batched into a single HTML chunk so that
|
|
266
|
+
* list-grouping and other renderer logic (which operates on slices) still works.
|
|
267
|
+
*
|
|
268
|
+
* ⚠ Limitation: list items must not be interleaved with component tokens —
|
|
269
|
+
* the list-grouping in MarkdownRenderer operates on contiguous slices.
|
|
270
|
+
*/
|
|
271
|
+
declare function TokenTreeRenderer({ tokens, componentMap, renderBatch }: TokenTreeRendererProps): React.ReactElement;
|
|
272
|
+
|
|
176
273
|
interface CacheStats {
|
|
177
274
|
size: number;
|
|
178
275
|
capacity: number;
|
|
@@ -280,5 +377,39 @@ declare function useMarkdownDebug(content: string): {
|
|
|
280
377
|
contentLength: number;
|
|
281
378
|
};
|
|
282
379
|
};
|
|
380
|
+
/**
|
|
381
|
+
* Hook for rendering markdown with React component extensions (TipTap-style).
|
|
382
|
+
*
|
|
383
|
+
* Returns the same values as `useMarkdown` plus:
|
|
384
|
+
* - `componentMap` — Map<tokenType, ReactComponentRenderRule> for TokenTreeRenderer
|
|
385
|
+
*
|
|
386
|
+
* @example
|
|
387
|
+
* ```tsx
|
|
388
|
+
* const CardExtension: ReactComponentExtension = {
|
|
389
|
+
* name: 'card',
|
|
390
|
+
* parseRules: [{ name: 'card', pattern: /:::card\n([\s\S]*?)\n:::/, render: (m) => ({ type: 'card', content: m[1] ?? '', raw: m[0] ?? '' }) }],
|
|
391
|
+
* renderRules: [{
|
|
392
|
+
* type: 'card',
|
|
393
|
+
* component: ({ token, children }) => <div className="card">{children}</div>,
|
|
394
|
+
* render: (token) => `<div class="card">${token.content}</div>`
|
|
395
|
+
* }]
|
|
396
|
+
* };
|
|
397
|
+
*
|
|
398
|
+
* const { tokens, componentMap, renderBatch } = useMarkdownComponents(content, { componentExtensions: [CardExtension] });
|
|
399
|
+
* ```
|
|
400
|
+
*/
|
|
401
|
+
declare function useMarkdownComponents(content: string, options?: UseMarkdownOptions & {
|
|
402
|
+
componentExtensions?: ReactComponentExtension[];
|
|
403
|
+
}): {
|
|
404
|
+
componentMap: Map<string, ReactComponentRenderRule>;
|
|
405
|
+
html: string;
|
|
406
|
+
tokens: MarkdownToken[];
|
|
407
|
+
isLoading: boolean;
|
|
408
|
+
error: Error | null;
|
|
409
|
+
debug: MarkdownDebugInfo | null;
|
|
410
|
+
render: (content: string) => void;
|
|
411
|
+
clear: () => void;
|
|
412
|
+
renderBatch: (tokens: MarkdownToken[]) => string;
|
|
413
|
+
};
|
|
283
414
|
|
|
284
|
-
export { type EngineConfig, type Extension, type MarkdownDebugInfo, type MarkdownEngineHookOptions, MarkdownRenderer, type MarkdownRendererProps, type MarkdownToken, type OutputFormat, type UseMarkdownOptions, type UseMarkdownResult, useMarkdown, useMarkdownDebug, useMarkdownEngine };
|
|
415
|
+
export { type ComponentExtension, type ComponentRenderRule, type ComponentTokenProps, type EngineConfig, type Extension, type MarkdownDebugInfo, type MarkdownEngineHookOptions, MarkdownRenderer, type MarkdownRendererProps, type MarkdownToken, type OutputFormat, type ReactComponentExtension, type ReactComponentRenderRule, type ReactComponentTokenProps, TokenTreeRenderer, type UseMarkdownOptions, type UseMarkdownResult, useMarkdown, useMarkdownComponents, useMarkdownDebug, useMarkdownEngine };
|
package/dist/react/index.js
CHANGED
|
@@ -31,7 +31,9 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
31
31
|
var index_exports = {};
|
|
32
32
|
__export(index_exports, {
|
|
33
33
|
MarkdownRenderer: () => MarkdownRenderer2,
|
|
34
|
+
TokenTreeRenderer: () => TokenTreeRenderer,
|
|
34
35
|
useMarkdown: () => useMarkdown,
|
|
36
|
+
useMarkdownComponents: () => useMarkdownComponents,
|
|
35
37
|
useMarkdownDebug: () => useMarkdownDebug,
|
|
36
38
|
useMarkdownEngine: () => useMarkdownEngine
|
|
37
39
|
});
|
|
@@ -2141,9 +2143,14 @@ function useMarkdown(initialContent = "", options = {}) {
|
|
|
2141
2143
|
newEngine.registerExtension(extension);
|
|
2142
2144
|
});
|
|
2143
2145
|
}
|
|
2146
|
+
if (options.componentExtensions) {
|
|
2147
|
+
options.componentExtensions.forEach((ext) => {
|
|
2148
|
+
newEngine.registerExtension(ext);
|
|
2149
|
+
});
|
|
2150
|
+
}
|
|
2144
2151
|
engineRef.current = newEngine;
|
|
2145
2152
|
return newEngine;
|
|
2146
|
-
}, [options.config, options.format, options.debug, options.extensions]);
|
|
2153
|
+
}, [options.config, options.format, options.debug, options.extensions, options.componentExtensions]);
|
|
2147
2154
|
const processMarkdown = (0, import_react.useCallback)((markdownContent) => {
|
|
2148
2155
|
if (!markdownContent.trim()) {
|
|
2149
2156
|
setHtml("");
|
|
@@ -2195,6 +2202,9 @@ function useMarkdown(initialContent = "", options = {}) {
|
|
|
2195
2202
|
setError(null);
|
|
2196
2203
|
setDebug(null);
|
|
2197
2204
|
}, []);
|
|
2205
|
+
const renderBatch = (0, import_react.useCallback)((batch) => {
|
|
2206
|
+
return engine.render(batch);
|
|
2207
|
+
}, [engine]);
|
|
2198
2208
|
return {
|
|
2199
2209
|
html,
|
|
2200
2210
|
tokens,
|
|
@@ -2202,7 +2212,8 @@ function useMarkdown(initialContent = "", options = {}) {
|
|
|
2202
2212
|
error,
|
|
2203
2213
|
debug,
|
|
2204
2214
|
render,
|
|
2205
|
-
clear
|
|
2215
|
+
clear,
|
|
2216
|
+
renderBatch
|
|
2206
2217
|
};
|
|
2207
2218
|
}
|
|
2208
2219
|
function useMarkdownEngine(options = {}) {
|
|
@@ -2280,9 +2291,74 @@ function useMarkdownDebug(content) {
|
|
|
2280
2291
|
}
|
|
2281
2292
|
};
|
|
2282
2293
|
}
|
|
2294
|
+
function useMarkdownComponents(content, options = {}) {
|
|
2295
|
+
const result = useMarkdown(content, options);
|
|
2296
|
+
const componentMap = (0, import_react.useMemo)(() => {
|
|
2297
|
+
const map = /* @__PURE__ */ new Map();
|
|
2298
|
+
if (options.componentExtensions) {
|
|
2299
|
+
for (const ext of options.componentExtensions) {
|
|
2300
|
+
for (const rule of ext.renderRules) {
|
|
2301
|
+
if (rule.component) {
|
|
2302
|
+
map.set(rule.type, rule);
|
|
2303
|
+
}
|
|
2304
|
+
}
|
|
2305
|
+
}
|
|
2306
|
+
}
|
|
2307
|
+
return map;
|
|
2308
|
+
}, [options.componentExtensions]);
|
|
2309
|
+
return { ...result, componentMap };
|
|
2310
|
+
}
|
|
2283
2311
|
|
|
2284
|
-
// src/react/
|
|
2312
|
+
// src/react/ComponentRenderer.tsx
|
|
2285
2313
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
2314
|
+
function TokenTreeRenderer({
|
|
2315
|
+
tokens,
|
|
2316
|
+
componentMap,
|
|
2317
|
+
renderBatch
|
|
2318
|
+
}) {
|
|
2319
|
+
const elements = [];
|
|
2320
|
+
let htmlBuffer = [];
|
|
2321
|
+
let keyCounter = 0;
|
|
2322
|
+
const flushBuffer = () => {
|
|
2323
|
+
if (htmlBuffer.length === 0) return;
|
|
2324
|
+
const html = renderBatch(htmlBuffer);
|
|
2325
|
+
elements.push(
|
|
2326
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
2327
|
+
"div",
|
|
2328
|
+
{
|
|
2329
|
+
dangerouslySetInnerHTML: { __html: html }
|
|
2330
|
+
},
|
|
2331
|
+
`html-${keyCounter++}`
|
|
2332
|
+
)
|
|
2333
|
+
);
|
|
2334
|
+
htmlBuffer = [];
|
|
2335
|
+
};
|
|
2336
|
+
for (const token of tokens) {
|
|
2337
|
+
const rule = componentMap.get(token.type);
|
|
2338
|
+
if (rule?.component) {
|
|
2339
|
+
flushBuffer();
|
|
2340
|
+
const Component = rule.component;
|
|
2341
|
+
const childElements = token.children && token.children.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
2342
|
+
TokenTreeRenderer,
|
|
2343
|
+
{
|
|
2344
|
+
tokens: token.children,
|
|
2345
|
+
componentMap,
|
|
2346
|
+
renderBatch
|
|
2347
|
+
}
|
|
2348
|
+
) : void 0;
|
|
2349
|
+
elements.push(
|
|
2350
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Component, { token, children: childElements }, `comp-${keyCounter++}`)
|
|
2351
|
+
);
|
|
2352
|
+
} else {
|
|
2353
|
+
htmlBuffer.push(token);
|
|
2354
|
+
}
|
|
2355
|
+
}
|
|
2356
|
+
flushBuffer();
|
|
2357
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: elements });
|
|
2358
|
+
}
|
|
2359
|
+
|
|
2360
|
+
// src/react/MarkdownRenderer.tsx
|
|
2361
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
2286
2362
|
function MarkdownRenderer2({
|
|
2287
2363
|
content,
|
|
2288
2364
|
className,
|
|
@@ -2296,6 +2372,7 @@ function MarkdownRenderer2({
|
|
|
2296
2372
|
onRender,
|
|
2297
2373
|
onError,
|
|
2298
2374
|
extensions,
|
|
2375
|
+
componentExtensions,
|
|
2299
2376
|
sanitize = true,
|
|
2300
2377
|
allowUnsafeHtml = false,
|
|
2301
2378
|
...restProps
|
|
@@ -2333,9 +2410,20 @@ function MarkdownRenderer2({
|
|
|
2333
2410
|
if (extensions) {
|
|
2334
2411
|
options.extensions = extensions;
|
|
2335
2412
|
}
|
|
2413
|
+
if (componentExtensions) {
|
|
2414
|
+
options.componentExtensions = componentExtensions;
|
|
2415
|
+
}
|
|
2336
2416
|
return options;
|
|
2337
|
-
}, [config, format, debug, extensions, sanitize, allowUnsafeHtml]);
|
|
2338
|
-
const
|
|
2417
|
+
}, [config, format, debug, extensions, componentExtensions, sanitize, allowUnsafeHtml]);
|
|
2418
|
+
const hasComponentExtensions = componentExtensions && componentExtensions.length > 0;
|
|
2419
|
+
const {
|
|
2420
|
+
html,
|
|
2421
|
+
tokens,
|
|
2422
|
+
isLoading,
|
|
2423
|
+
error,
|
|
2424
|
+
renderBatch,
|
|
2425
|
+
componentMap
|
|
2426
|
+
} = useMarkdownComponents(content, markdownOptions);
|
|
2339
2427
|
(0, import_react2.useEffect)(() => {
|
|
2340
2428
|
if (html && onRender) {
|
|
2341
2429
|
onRender(html, tokens);
|
|
@@ -2347,21 +2435,36 @@ function MarkdownRenderer2({
|
|
|
2347
2435
|
}
|
|
2348
2436
|
}, [error, onError]);
|
|
2349
2437
|
if (isLoading && loading) {
|
|
2350
|
-
return /* @__PURE__ */ (0,
|
|
2438
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_jsx_runtime2.Fragment, { children: loading });
|
|
2351
2439
|
}
|
|
2352
2440
|
if (error) {
|
|
2353
2441
|
if (errorFallback) {
|
|
2354
|
-
return /* @__PURE__ */ (0,
|
|
2442
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_jsx_runtime2.Fragment, { children: errorFallback(error) });
|
|
2355
2443
|
}
|
|
2356
|
-
return /* @__PURE__ */ (0,
|
|
2357
|
-
/* @__PURE__ */ (0,
|
|
2358
|
-
/* @__PURE__ */ (0,
|
|
2444
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "changerawr-error bg-red-50 border border-red-200 text-red-700 px-4 py-3 rounded", children: [
|
|
2445
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "font-medium", children: "Markdown Render Error" }),
|
|
2446
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "text-sm mt-1", children: error.message })
|
|
2359
2447
|
] });
|
|
2360
2448
|
}
|
|
2449
|
+
const wrapperClassName = className ? `${className} changerawr-markdown` : "changerawr-markdown";
|
|
2450
|
+
if (hasComponentExtensions && componentMap.size > 0) {
|
|
2451
|
+
return import_react2.default.createElement(
|
|
2452
|
+
Component,
|
|
2453
|
+
{ ...wrapperProps, ...restProps, className: wrapperClassName },
|
|
2454
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
2455
|
+
TokenTreeRenderer,
|
|
2456
|
+
{
|
|
2457
|
+
tokens,
|
|
2458
|
+
componentMap,
|
|
2459
|
+
renderBatch
|
|
2460
|
+
}
|
|
2461
|
+
)
|
|
2462
|
+
);
|
|
2463
|
+
}
|
|
2361
2464
|
const finalWrapperProps = {
|
|
2362
2465
|
...wrapperProps,
|
|
2363
2466
|
...restProps,
|
|
2364
|
-
className:
|
|
2467
|
+
className: wrapperClassName,
|
|
2365
2468
|
dangerouslySetInnerHTML: { __html: html }
|
|
2366
2469
|
};
|
|
2367
2470
|
return import_react2.default.createElement(Component, finalWrapperProps);
|
|
@@ -2383,10 +2486,10 @@ var MarkdownErrorBoundary = class extends import_react2.default.Component {
|
|
|
2383
2486
|
if (this.props.fallback) {
|
|
2384
2487
|
return this.props.fallback(this.state.error);
|
|
2385
2488
|
}
|
|
2386
|
-
return /* @__PURE__ */ (0,
|
|
2387
|
-
/* @__PURE__ */ (0,
|
|
2388
|
-
/* @__PURE__ */ (0,
|
|
2389
|
-
/* @__PURE__ */ (0,
|
|
2489
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "changerawr-error-boundary bg-red-50 border border-red-200 text-red-700 px-4 py-3 rounded", children: [
|
|
2490
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "font-medium", children: "Markdown Component Error" }),
|
|
2491
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "text-sm mt-1", children: this.state.error.message }),
|
|
2492
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
2390
2493
|
"button",
|
|
2391
2494
|
{
|
|
2392
2495
|
onClick: () => this.setState({ hasError: false, error: null }),
|
|
@@ -2402,7 +2505,9 @@ var MarkdownErrorBoundary = class extends import_react2.default.Component {
|
|
|
2402
2505
|
// Annotate the CommonJS export names for ESM import in node:
|
|
2403
2506
|
0 && (module.exports = {
|
|
2404
2507
|
MarkdownRenderer,
|
|
2508
|
+
TokenTreeRenderer,
|
|
2405
2509
|
useMarkdown,
|
|
2510
|
+
useMarkdownComponents,
|
|
2406
2511
|
useMarkdownDebug,
|
|
2407
2512
|
useMarkdownEngine
|
|
2408
2513
|
});
|