react-native-marked 7.1.0 → 8.0.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 +72 -0
- package/dist/commonjs/hooks/useMarkdownWithComponents.js +74 -0
- package/dist/commonjs/hooks/useMarkdownWithComponents.js.map +1 -0
- package/dist/commonjs/index.js +14 -0
- package/dist/commonjs/index.js.map +1 -1
- package/dist/commonjs/lib/Parser.js +5 -5
- package/dist/commonjs/lib/Parser.js.map +1 -1
- package/dist/commonjs/lib/ReactComponentRegistry.js +30 -0
- package/dist/commonjs/lib/ReactComponentRegistry.js.map +1 -0
- package/dist/commonjs/lib/ReactComponentTokenizer.js +106 -0
- package/dist/commonjs/lib/ReactComponentTokenizer.js.map +1 -0
- package/dist/commonjs/lib/Renderer.js +6 -5
- package/dist/commonjs/lib/Renderer.js.map +1 -1
- package/dist/commonjs/utils/svg.js +2 -2
- package/dist/commonjs/utils/svg.js.map +1 -1
- package/dist/module/hooks/useMarkdownWithComponents.js +66 -0
- package/dist/module/hooks/useMarkdownWithComponents.js.map +1 -0
- package/dist/module/index.js +3 -1
- package/dist/module/index.js.map +1 -1
- package/dist/module/lib/Parser.js +5 -5
- package/dist/module/lib/Parser.js.map +1 -1
- package/dist/module/lib/ReactComponentRegistry.js +23 -0
- package/dist/module/lib/ReactComponentRegistry.js.map +1 -0
- package/dist/module/lib/ReactComponentTokenizer.js +100 -0
- package/dist/module/lib/ReactComponentTokenizer.js.map +1 -0
- package/dist/module/lib/Renderer.js +6 -5
- package/dist/module/lib/Renderer.js.map +1 -1
- package/dist/module/utils/svg.js +2 -2
- package/dist/module/utils/svg.js.map +1 -1
- package/dist/typescript/hooks/useMarkdownWithComponents.d.ts +7 -0
- package/dist/typescript/hooks/useMarkdownWithComponents.d.ts.map +1 -0
- package/dist/typescript/index.d.ts +5 -2
- package/dist/typescript/index.d.ts.map +1 -1
- package/dist/typescript/lib/Parser.d.ts.map +1 -1
- package/dist/typescript/lib/ReactComponentRegistry.d.ts +22 -0
- package/dist/typescript/lib/ReactComponentRegistry.d.ts.map +1 -0
- package/dist/typescript/lib/ReactComponentTokenizer.d.ts +15 -0
- package/dist/typescript/lib/ReactComponentTokenizer.d.ts.map +1 -0
- package/dist/typescript/lib/Renderer.d.ts +3 -3
- package/dist/typescript/lib/Renderer.d.ts.map +1 -1
- package/dist/typescript/lib/types.d.ts +3 -3
- package/dist/typescript/lib/types.d.ts.map +1 -1
- package/package.json +18 -18
- package/src/hooks/useMarkdownWithComponents.tsx +89 -0
- package/src/index.ts +13 -1
- package/src/lib/Parser.tsx +6 -4
- package/src/lib/ReactComponentRegistry.tsx +52 -0
- package/src/lib/ReactComponentTokenizer.ts +149 -0
- package/src/lib/Renderer.tsx +11 -3
- package/src/lib/types.ts +8 -1
- package/src/utils/svg.ts +2 -2
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
import React, { useMemo } from "react";
|
|
3
|
+
import { useReactComponentRegistry } from "../lib/ReactComponentRegistry";
|
|
4
|
+
import type { ReactComponentToken } from "../lib/ReactComponentTokenizer";
|
|
5
|
+
import {
|
|
6
|
+
isReactComponentToken,
|
|
7
|
+
ReactComponentTokenizer,
|
|
8
|
+
} from "../lib/ReactComponentTokenizer";
|
|
9
|
+
import Renderer from "../lib/Renderer";
|
|
10
|
+
import type { RendererInterface } from "../lib/types";
|
|
11
|
+
import type { useMarkdownHookOptions } from "./useMarkdown";
|
|
12
|
+
import useMarkdown from "./useMarkdown";
|
|
13
|
+
|
|
14
|
+
export interface useMarkdownWithComponentsOptions
|
|
15
|
+
extends Omit<useMarkdownHookOptions, "tokenizer"> {}
|
|
16
|
+
|
|
17
|
+
interface ComponentData {
|
|
18
|
+
token: ReactComponentToken;
|
|
19
|
+
id: string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function useMarkdownWithComponents(
|
|
23
|
+
value: string,
|
|
24
|
+
options?: useMarkdownWithComponentsOptions,
|
|
25
|
+
): ReactNode[] {
|
|
26
|
+
const registry = useReactComponentRegistry();
|
|
27
|
+
|
|
28
|
+
const { tokenizer, componentMap } = useMemo(() => {
|
|
29
|
+
const map = new Map<string, ComponentData>();
|
|
30
|
+
|
|
31
|
+
const customTokenizer = new ReactComponentTokenizer();
|
|
32
|
+
const originalHtml = customTokenizer.html.bind(customTokenizer);
|
|
33
|
+
|
|
34
|
+
let componentCounter = 0;
|
|
35
|
+
|
|
36
|
+
customTokenizer.html = (src: string) => {
|
|
37
|
+
const token = originalHtml(src);
|
|
38
|
+
if (token && isReactComponentToken(token)) {
|
|
39
|
+
const id = `${token.componentName}-${componentCounter++}`;
|
|
40
|
+
map.set(token.raw, { token, id });
|
|
41
|
+
}
|
|
42
|
+
return token;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
return { tokenizer: customTokenizer, componentMap: map };
|
|
46
|
+
}, []);
|
|
47
|
+
|
|
48
|
+
const baseRenderer = useMemo(
|
|
49
|
+
() => options?.renderer ?? new Renderer(),
|
|
50
|
+
[options?.renderer],
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
const renderer = useMemo<RendererInterface>(() => {
|
|
54
|
+
const wrappedRenderer = Object.create(baseRenderer) as typeof baseRenderer;
|
|
55
|
+
|
|
56
|
+
wrappedRenderer.html = (text: string | ReactNode[], styles): ReactNode => {
|
|
57
|
+
if (typeof text === "string") {
|
|
58
|
+
const data = componentMap.get(text);
|
|
59
|
+
if (data) {
|
|
60
|
+
if (registry?.hasComponent(data.token.componentName)) {
|
|
61
|
+
const Component = registry.getComponent(data.token.componentName);
|
|
62
|
+
if (Component) {
|
|
63
|
+
return (
|
|
64
|
+
<Component key={data.id} props={data.token.componentProps}>
|
|
65
|
+
{data.token.componentChildren || undefined}
|
|
66
|
+
</Component>
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return baseRenderer.html(text, styles);
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
return wrappedRenderer;
|
|
78
|
+
}, [baseRenderer, componentMap, registry]);
|
|
79
|
+
|
|
80
|
+
const elements = useMarkdown(value, {
|
|
81
|
+
...options,
|
|
82
|
+
tokenizer,
|
|
83
|
+
renderer,
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
return elements;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export default useMarkdownWithComponents;
|
package/src/index.ts
CHANGED
|
@@ -5,7 +5,10 @@ import {
|
|
|
5
5
|
marked,
|
|
6
6
|
} from "marked";
|
|
7
7
|
import useMarkdown, { type useMarkdownHookOptions } from "./hooks/useMarkdown";
|
|
8
|
+
import useMarkdownWithComponents from "./hooks/useMarkdownWithComponents";
|
|
8
9
|
import Markdown from "./lib/Markdown";
|
|
10
|
+
import type { ReactComponentRegistry } from "./lib/ReactComponentRegistry";
|
|
11
|
+
import { ReactComponentRegistryProvider } from "./lib/ReactComponentRegistry";
|
|
9
12
|
import Renderer from "./lib/Renderer";
|
|
10
13
|
import type {
|
|
11
14
|
MarkdownProps,
|
|
@@ -24,8 +27,17 @@ export type {
|
|
|
24
27
|
useMarkdownHookOptions,
|
|
25
28
|
Token,
|
|
26
29
|
Tokens,
|
|
30
|
+
ReactComponentRegistry,
|
|
27
31
|
};
|
|
28
32
|
|
|
29
|
-
export {
|
|
33
|
+
export {
|
|
34
|
+
useMarkdown,
|
|
35
|
+
useMarkdownWithComponents,
|
|
36
|
+
MarkedLexer,
|
|
37
|
+
Renderer,
|
|
38
|
+
MarkedTokenizer,
|
|
39
|
+
MarkedHooks,
|
|
40
|
+
ReactComponentRegistryProvider,
|
|
41
|
+
};
|
|
30
42
|
|
|
31
43
|
export default Markdown;
|
package/src/lib/Parser.tsx
CHANGED
|
@@ -82,7 +82,7 @@ class Parser {
|
|
|
82
82
|
return this.renderer.hr(this.styles.hr);
|
|
83
83
|
}
|
|
84
84
|
case "list": {
|
|
85
|
-
let startIndex = Number.parseInt(token.start.toString());
|
|
85
|
+
let startIndex = Number.parseInt(token.start.toString(), 10);
|
|
86
86
|
if (Number.isNaN(startIndex)) {
|
|
87
87
|
startIndex = 1;
|
|
88
88
|
}
|
|
@@ -139,17 +139,18 @@ class Parser {
|
|
|
139
139
|
const href = getValidURL(this.baseUrl, token.href);
|
|
140
140
|
|
|
141
141
|
if (this.hasDuplicateTextChildToken(token)) {
|
|
142
|
-
return this.renderer.link(token.text, href, linkStyle);
|
|
142
|
+
return this.renderer.link(token.text, href, linkStyle, token.title);
|
|
143
143
|
}
|
|
144
144
|
|
|
145
145
|
const children = this._parse(token.tokens, linkStyle);
|
|
146
|
-
return this.renderer.link(children, href, linkStyle);
|
|
146
|
+
return this.renderer.link(children, href, linkStyle, token.title);
|
|
147
147
|
}
|
|
148
148
|
case "image": {
|
|
149
149
|
return this.renderer.image(
|
|
150
150
|
token.href,
|
|
151
|
-
token.text
|
|
151
|
+
token.text,
|
|
152
152
|
this.styles.image,
|
|
153
|
+
token.title,
|
|
153
154
|
);
|
|
154
155
|
}
|
|
155
156
|
case "strong": {
|
|
@@ -277,6 +278,7 @@ class Parser {
|
|
|
277
278
|
imageToken.href,
|
|
278
279
|
imageToken.text ?? imageToken.title ?? "",
|
|
279
280
|
this.styles.image,
|
|
281
|
+
imageToken.title,
|
|
280
282
|
),
|
|
281
283
|
);
|
|
282
284
|
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
import React, { createContext, useContext, useMemo } from "react";
|
|
3
|
+
import type { ReactComponentProps } from "./ReactComponentTokenizer";
|
|
4
|
+
|
|
5
|
+
export interface ReactComponentRendererProps {
|
|
6
|
+
props: ReactComponentProps;
|
|
7
|
+
children?: ReactNode;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export type ReactComponentRenderer = (
|
|
11
|
+
props: ReactComponentRendererProps,
|
|
12
|
+
) => ReactNode;
|
|
13
|
+
|
|
14
|
+
export type ReactComponentRegistry = Record<string, ReactComponentRenderer>;
|
|
15
|
+
|
|
16
|
+
interface ReactComponentRegistryContextValue {
|
|
17
|
+
components: ReactComponentRegistry;
|
|
18
|
+
getComponent: (name: string) => ReactComponentRenderer | undefined;
|
|
19
|
+
hasComponent: (name: string) => boolean;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const ReactComponentRegistryContext =
|
|
23
|
+
createContext<ReactComponentRegistryContextValue | null>(null);
|
|
24
|
+
|
|
25
|
+
interface ReactComponentRegistryProviderProps {
|
|
26
|
+
components: ReactComponentRegistry;
|
|
27
|
+
children: ReactNode;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function ReactComponentRegistryProvider({
|
|
31
|
+
components,
|
|
32
|
+
children,
|
|
33
|
+
}: ReactComponentRegistryProviderProps) {
|
|
34
|
+
const contextValue = useMemo<ReactComponentRegistryContextValue>(
|
|
35
|
+
() => ({
|
|
36
|
+
components,
|
|
37
|
+
getComponent: (name: string) => components[name],
|
|
38
|
+
hasComponent: (name: string) => name in components,
|
|
39
|
+
}),
|
|
40
|
+
[components],
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
return (
|
|
44
|
+
<ReactComponentRegistryContext.Provider value={contextValue}>
|
|
45
|
+
{children}
|
|
46
|
+
</ReactComponentRegistryContext.Provider>
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function useReactComponentRegistry(): ReactComponentRegistryContextValue | null {
|
|
51
|
+
return useContext(ReactComponentRegistryContext);
|
|
52
|
+
}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import type { Tokens } from "marked";
|
|
2
|
+
import { Tokenizer } from "marked";
|
|
3
|
+
|
|
4
|
+
const SELF_CLOSING_REGEX = /^<([A-Z][a-zA-Z0-9]*)([^>]*?)\s*\/>/;
|
|
5
|
+
const OPENING_TAG_REGEX = /^<([A-Z][a-zA-Z0-9]*)([^>]*)>/;
|
|
6
|
+
const PROP_REGEX = /(\w+)(?:=(?:"([^"]*)"|'([^']*)'|\{([^}]*)\}))?/g;
|
|
7
|
+
|
|
8
|
+
export type ReactComponentProps = Record<string, string | boolean | number>;
|
|
9
|
+
|
|
10
|
+
export interface ReactComponentToken extends Tokens.HTML {
|
|
11
|
+
componentName: string;
|
|
12
|
+
componentProps: ReactComponentProps;
|
|
13
|
+
componentChildren: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function parseProps(propsString: string): ReactComponentProps {
|
|
17
|
+
const props: ReactComponentProps = {};
|
|
18
|
+
if (!propsString) return props;
|
|
19
|
+
|
|
20
|
+
let match: RegExpExecArray | null;
|
|
21
|
+
|
|
22
|
+
match = PROP_REGEX.exec(propsString);
|
|
23
|
+
while (match !== null) {
|
|
24
|
+
const [, propName, doubleQuoted, singleQuoted, braced] = match;
|
|
25
|
+
if (propName) {
|
|
26
|
+
if (doubleQuoted !== undefined) {
|
|
27
|
+
props[propName] = doubleQuoted;
|
|
28
|
+
} else if (singleQuoted !== undefined) {
|
|
29
|
+
props[propName] = singleQuoted;
|
|
30
|
+
} else if (braced !== undefined) {
|
|
31
|
+
const trimmed = braced.trim();
|
|
32
|
+
if (trimmed === "true") {
|
|
33
|
+
props[propName] = true;
|
|
34
|
+
} else if (trimmed === "false") {
|
|
35
|
+
props[propName] = false;
|
|
36
|
+
} else if (!Number.isNaN(Number(trimmed))) {
|
|
37
|
+
props[propName] = Number(trimmed);
|
|
38
|
+
} else {
|
|
39
|
+
props[propName] = trimmed;
|
|
40
|
+
}
|
|
41
|
+
} else {
|
|
42
|
+
props[propName] = true;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
match = PROP_REGEX.exec(propsString);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
PROP_REGEX.lastIndex = 0;
|
|
49
|
+
return props;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function findClosingTag(
|
|
53
|
+
src: string,
|
|
54
|
+
componentName: string,
|
|
55
|
+
startIndex: number,
|
|
56
|
+
): { endIndex: number; children: string } | null {
|
|
57
|
+
const openingTag = new RegExp(`<${componentName}(?:\\s[^>]*)?>`, "g");
|
|
58
|
+
const closingTag = `</${componentName}>`;
|
|
59
|
+
|
|
60
|
+
let depth = 1;
|
|
61
|
+
let currentIndex = startIndex;
|
|
62
|
+
|
|
63
|
+
while (depth > 0 && currentIndex < src.length) {
|
|
64
|
+
const closingIndex = src.indexOf(closingTag, currentIndex);
|
|
65
|
+
if (closingIndex === -1) return null;
|
|
66
|
+
|
|
67
|
+
openingTag.lastIndex = currentIndex;
|
|
68
|
+
let nestedMatch: RegExpExecArray | null;
|
|
69
|
+
nestedMatch = openingTag.exec(src);
|
|
70
|
+
while (nestedMatch !== null && nestedMatch.index < closingIndex) {
|
|
71
|
+
depth++;
|
|
72
|
+
nestedMatch = openingTag.exec(src);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
depth--;
|
|
76
|
+
if (depth === 0) {
|
|
77
|
+
return {
|
|
78
|
+
endIndex: closingIndex + closingTag.length,
|
|
79
|
+
children: src.slice(startIndex, closingIndex),
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
currentIndex = closingIndex + closingTag.length;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export class ReactComponentTokenizer extends Tokenizer {
|
|
89
|
+
override html(src: string): Tokens.HTML | undefined {
|
|
90
|
+
const selfClosingMatch = SELF_CLOSING_REGEX.exec(src);
|
|
91
|
+
if (selfClosingMatch) {
|
|
92
|
+
const [raw, componentName, propsString] = selfClosingMatch;
|
|
93
|
+
return this.createReactComponentToken(
|
|
94
|
+
raw,
|
|
95
|
+
componentName ?? "",
|
|
96
|
+
propsString ?? "",
|
|
97
|
+
"",
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const openingMatch = OPENING_TAG_REGEX.exec(src);
|
|
102
|
+
if (openingMatch) {
|
|
103
|
+
const [openingTag, componentName, propsString] = openingMatch;
|
|
104
|
+
const result = findClosingTag(
|
|
105
|
+
src,
|
|
106
|
+
componentName ?? "",
|
|
107
|
+
openingTag?.length ?? 0,
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
if (result) {
|
|
111
|
+
const raw = src.slice(0, result.endIndex);
|
|
112
|
+
return this.createReactComponentToken(
|
|
113
|
+
raw,
|
|
114
|
+
componentName ?? "",
|
|
115
|
+
propsString ?? "",
|
|
116
|
+
result.children,
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return super.html(src);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
private createReactComponentToken(
|
|
125
|
+
raw: string,
|
|
126
|
+
componentName: string,
|
|
127
|
+
propsString: string,
|
|
128
|
+
children: string,
|
|
129
|
+
): ReactComponentToken {
|
|
130
|
+
return {
|
|
131
|
+
type: "html",
|
|
132
|
+
raw,
|
|
133
|
+
text: raw,
|
|
134
|
+
block: true,
|
|
135
|
+
pre: false,
|
|
136
|
+
componentName,
|
|
137
|
+
componentProps: parseProps(propsString),
|
|
138
|
+
componentChildren: children.trim(),
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
export function isReactComponentToken(
|
|
144
|
+
token: Tokens.HTML,
|
|
145
|
+
): token is ReactComponentToken {
|
|
146
|
+
return "componentName" in token && typeof token.componentName === "string";
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
export default ReactComponentTokenizer;
|
package/src/lib/Renderer.tsx
CHANGED
|
@@ -97,12 +97,14 @@ class Renderer implements RendererInterface {
|
|
|
97
97
|
children: string | ReactNode[],
|
|
98
98
|
href: string,
|
|
99
99
|
styles?: TextStyle,
|
|
100
|
+
title?: string,
|
|
100
101
|
): ReactNode {
|
|
101
102
|
return (
|
|
102
103
|
<Text
|
|
103
104
|
selectable
|
|
104
105
|
accessibilityRole="link"
|
|
105
106
|
accessibilityHint="Opens in a new window"
|
|
107
|
+
accessibilityLabel={title || "Link"}
|
|
106
108
|
key={this.getKey()}
|
|
107
109
|
onPress={onLinkPress(href)}
|
|
108
110
|
style={styles}
|
|
@@ -112,12 +114,17 @@ class Renderer implements RendererInterface {
|
|
|
112
114
|
);
|
|
113
115
|
}
|
|
114
116
|
|
|
115
|
-
image(
|
|
117
|
+
image(
|
|
118
|
+
uri: string,
|
|
119
|
+
alt?: string,
|
|
120
|
+
style?: ImageStyle,
|
|
121
|
+
title?: string,
|
|
122
|
+
): ReactNode {
|
|
116
123
|
const key = this.getKey();
|
|
117
124
|
if (uri.endsWith(".svg")) {
|
|
118
125
|
return <MDSvg uri={uri} key={key} />;
|
|
119
126
|
}
|
|
120
|
-
return <MDImage key={key} uri={uri} alt={alt} style={style} />;
|
|
127
|
+
return <MDImage key={key} uri={uri} alt={alt || title} style={style} />;
|
|
121
128
|
}
|
|
122
129
|
|
|
123
130
|
strong(children: string | ReactNode[], styles?: TextStyle): ReactNode {
|
|
@@ -153,8 +160,9 @@ class Renderer implements RendererInterface {
|
|
|
153
160
|
imageUrl: string,
|
|
154
161
|
alt?: string,
|
|
155
162
|
style?: ImageStyle,
|
|
163
|
+
title?: string,
|
|
156
164
|
): ReactNode {
|
|
157
|
-
const imageNode = this.image(imageUrl, alt, style);
|
|
165
|
+
const imageNode = this.image(imageUrl, alt, style, title);
|
|
158
166
|
return (
|
|
159
167
|
<TouchableHighlight
|
|
160
168
|
accessibilityRole="link"
|
package/src/lib/types.ts
CHANGED
|
@@ -55,8 +55,14 @@ export interface RendererInterface {
|
|
|
55
55
|
children: string | ReactNode[],
|
|
56
56
|
href: string,
|
|
57
57
|
styles?: TextStyle,
|
|
58
|
+
title?: string,
|
|
59
|
+
): ReactNode;
|
|
60
|
+
image(
|
|
61
|
+
uri: string,
|
|
62
|
+
alt?: string,
|
|
63
|
+
style?: ImageStyle,
|
|
64
|
+
title?: string,
|
|
58
65
|
): ReactNode;
|
|
59
|
-
image(uri: string, alt?: string, style?: ImageStyle): ReactNode;
|
|
60
66
|
strong(children: string | ReactNode[], styles?: TextStyle): ReactNode;
|
|
61
67
|
em(children: string | ReactNode[], styles?: TextStyle): ReactNode;
|
|
62
68
|
codespan(text: string, styles?: TextStyle): ReactNode;
|
|
@@ -69,6 +75,7 @@ export interface RendererInterface {
|
|
|
69
75
|
imageUrl: string,
|
|
70
76
|
alt?: string,
|
|
71
77
|
style?: ImageStyle,
|
|
78
|
+
title?: string | null,
|
|
72
79
|
): ReactNode;
|
|
73
80
|
table(
|
|
74
81
|
header: ReactNode[][],
|
package/src/utils/svg.ts
CHANGED
|
@@ -7,8 +7,8 @@ export const getSvgDimensions = (svg: string) => {
|
|
|
7
7
|
const rootChild = parsed.children[0] as ElementNode;
|
|
8
8
|
|
|
9
9
|
return {
|
|
10
|
-
width: Number.parseInt(String(rootChild.properties?.width ?? "0")),
|
|
11
|
-
height: Number.parseInt(String(rootChild.properties?.height ?? "0")),
|
|
10
|
+
width: Number.parseInt(String(rootChild.properties?.width ?? "0"), 10),
|
|
11
|
+
height: Number.parseInt(String(rootChild.properties?.height ?? "0"), 10),
|
|
12
12
|
viewBox: String(rootChild.properties?.viewBox ?? ""),
|
|
13
13
|
};
|
|
14
14
|
};
|