@surrealdb/ui 1.2.12 → 1.2.14
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/.claude/launch.json +17 -0
- package/.oxfmtrc.json +27 -0
- package/.oxlintrc.json +23 -0
- package/.zed/settings.json +34 -34
- package/AGENTS.md +25 -19
- package/CLAUDE.md +111 -0
- package/README.md +15 -10
- package/dist/icons.d.ts +4 -0
- package/dist/icons.js +91 -89
- package/dist/icons.js.map +1 -1
- package/dist/ui.css +1 -1
- package/dist/ui.d.ts +259 -1
- package/dist/ui.js +9807 -12265
- package/dist/ui.js.map +1 -1
- package/doc/code-style.md +264 -0
- package/doc/release.md +102 -0
- package/doc/stacker-plan.md +219 -0
- package/package.json +120 -116
- package/release-notes.md +0 -0
- package/res/_mixins.scss +15 -11
- package/tests/_setup/e2e-helpers.tsx +85 -85
- package/tests/_setup/portable-stories.ts +11 -10
- package/tests/e2e/MarkdownEditor/content-blocks.test.tsx +140 -139
- package/tests/e2e/MarkdownEditor/edits.test.tsx +101 -100
- package/tests/e2e/MarkdownEditor/heading-fold.test.tsx +35 -34
- package/tests/e2e/MarkdownEditor/hybrid-widgets.test.tsx +178 -177
- package/tests/e2e/MarkdownEditor/image-on-image.test.tsx +50 -49
- package/tests/e2e/MarkdownEditor/jsx-block-content.test.tsx +195 -194
- package/tests/e2e/MarkdownEditor/jsx-highlight.test.tsx +47 -46
- package/tests/e2e/MarkdownEditor/jsx-inline-badges.test.tsx +35 -34
- package/tests/e2e/MarkdownEditor/jsx-inline-click.test.tsx +39 -38
- package/tests/e2e/MarkdownEditor/jsx-selection.test.tsx +28 -27
- package/tests/e2e/MarkdownEditor/link-placeholder.test.tsx +49 -48
- package/tests/e2e/MarkdownEditor/media-align.test.tsx +40 -39
- package/tests/e2e/MarkdownEditor/media-edit.test.tsx +49 -48
- package/tests/e2e/MarkdownEditor/media-sizing.test.tsx +108 -107
- package/tests/e2e/MarkdownEditor/modes.test.tsx +79 -78
- package/tests/e2e/MarkdownEditor/onimage-parity.test.tsx +29 -28
- package/tests/e2e/MarkdownEditor/regressions.test.tsx +194 -193
- package/tests/e2e/MarkdownEditor/slash-commands.test.tsx +81 -80
- package/tests/e2e/MarkdownEditor/table-click.test.tsx +36 -35
- package/tests/e2e/MarkdownEditor/table-controls.test.tsx +44 -43
- package/tests/e2e/MarkdownEditor/table-format.test.tsx +28 -27
- package/tests/e2e/MarkdownEditor/undo-redo.test.tsx +22 -21
- package/tests/e2e/MarkdownViewer/parity.test.tsx +144 -143
- package/tests/e2e/MarkdownViewer/render.test.tsx +20 -19
- package/tests/e2e/Stacker/stacker.test.tsx +304 -0
- package/tests/unit/Editor/helpers.test.ts +26 -26
- package/tests/unit/MarkdownConformance/error-isolation.test.tsx +26 -25
- package/tests/unit/MarkdownConformance/indentation.test.tsx +20 -19
- package/tests/unit/MarkdownConformance/inline-code-fuzz.test.tsx +255 -0
- package/tests/unit/MarkdownConformance/jsx-attributes.test.tsx +39 -38
- package/tests/unit/MarkdownConformance/jsx-fuzz.test.tsx +122 -122
- package/tests/unit/MarkdownConformance/links.test.tsx +78 -54
- package/tests/unit/MarkdownConformance/render-helpers.tsx +60 -60
- package/tests/unit/MarkdownEditor/code-info.test.ts +58 -58
- package/tests/unit/MarkdownEditor/decorations.test.ts +423 -421
- package/tests/unit/MarkdownEditor/editor-ready.test.ts +22 -22
- package/tests/unit/MarkdownEditor/html-descriptors.test.ts +70 -70
- package/tests/unit/MarkdownEditor/indented-fence.test.ts +80 -80
- package/tests/unit/MarkdownEditor/jsx-attr-scan.test.ts +87 -87
- package/tests/unit/MarkdownEditor/jsx-block-widget.test.ts +51 -51
- package/tests/unit/MarkdownEditor/jsx-tag-grammar.test.ts +63 -63
- package/tests/unit/MarkdownEditor/list-indent.test.ts +67 -67
- package/tests/unit/MarkdownEditor/slash-commands.test.ts +150 -150
- package/tests/unit/MarkdownEditor/table-format.test.ts +67 -67
- package/tests/unit/MarkdownEditor/table.test.ts +96 -96
- package/tests/unit/MarkdownEditor/triggers.test.ts +167 -167
- package/tests/unit/MarkdownEditor/widget-store.test.ts +90 -90
- package/tests/unit/MarkdownViewer/callout.test.tsx +42 -42
- package/tests/unit/MarkdownViewer/code-highlight.test.tsx +41 -41
- package/tests/unit/MarkdownViewer/code-title.test.tsx +45 -45
- package/tests/unit/MarkdownViewer/features.test.tsx +129 -129
- package/tests/unit/MarkdownViewer/headings.test.tsx +28 -28
- package/tests/unit/MarkdownViewer/indented-jsx-children.test.tsx +53 -53
- package/tests/unit/MarkdownViewer/jsx-block-nesting.test.tsx +137 -137
- package/tests/unit/MarkdownViewer/jsx.test.tsx +188 -188
- package/tests/unit/MarkdownViewer/list-bullets.test.tsx +31 -31
- package/tests/unit/MarkdownViewer/list-code.test.tsx +45 -45
- package/tests/unit/MarkdownViewer/preserve-newlines.test.tsx +109 -109
- package/tests/unit/MarkdownViewer/read-time.test.ts +13 -13
- package/tests/unit/MarkdownViewer/renderers.test.tsx +75 -75
- package/tests/unit/MarkdownViewer/runnable.test.tsx +51 -51
- package/tests/unit/MarkdownViewer/ssr.test.tsx +56 -55
- package/tests/unit/MarkdownViewer/syntax-highlighting.test.tsx +43 -42
- package/tests/unit/MarkdownViewer/tabs-fenced-code.test.tsx +120 -120
- package/tests/unit/MarkdownViewer/tabs.test.tsx +83 -82
- package/tests/unit/Stacker/drag.test.ts +21 -0
- package/tests/unit/Stacker/helpers.test.ts +105 -0
- package/tests/unit/Stacker/reducer.test.ts +107 -0
- package/tools/duplicate-vector-mappings.json +141 -141
- package/tools/glass-export-overrides.json +6 -6
- package/tools/icon-parser.ts +41 -40
- package/tools/integration-gradient-exports.json +55 -55
- package/tools/picto-compare.ts +32 -32
- package/tools/picto-merge-urls.ts +19 -19
- package/tools/picto-sync.ts +543 -543
- package/tools/picto-verify-gradients.ts +50 -50
- package/tools/vector-export-nodes.json +975 -975
|
@@ -7,41 +7,41 @@ import { renderToString } from "react-dom/server";
|
|
|
7
7
|
import { beforeAll, describe, expect, it } from "vitest";
|
|
8
8
|
|
|
9
9
|
beforeAll(() => {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
10
|
+
if (typeof window !== "undefined" && typeof window.matchMedia !== "function") {
|
|
11
|
+
Object.defineProperty(window, "matchMedia", {
|
|
12
|
+
writable: true,
|
|
13
|
+
value: (query: string) => ({
|
|
14
|
+
matches: false,
|
|
15
|
+
media: query,
|
|
16
|
+
onchange: null,
|
|
17
|
+
addListener: () => {},
|
|
18
|
+
removeListener: () => {},
|
|
19
|
+
addEventListener: () => {},
|
|
20
|
+
removeEventListener: () => {},
|
|
21
|
+
dispatchEvent: () => false,
|
|
22
|
+
}),
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
25
|
});
|
|
26
26
|
|
|
27
27
|
function shell(node: ReactElement): string {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
28
|
+
return renderToString(
|
|
29
|
+
<MantineProvider
|
|
30
|
+
theme={MANTINE_THEME}
|
|
31
|
+
cssVariablesResolver={v8CssVariablesResolver}
|
|
32
|
+
forceColorScheme="dark"
|
|
33
|
+
>
|
|
34
|
+
{node}
|
|
35
|
+
</MantineProvider>,
|
|
36
|
+
);
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
function TwoColumn({ children }: { children?: ReactNode }): ReactElement {
|
|
40
|
-
|
|
40
|
+
return <div data-testid="two-column">{children}</div>;
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
function ColBox({ children }: { children?: ReactNode }): ReactElement {
|
|
44
|
-
|
|
44
|
+
return <div data-testid="col-box">{children}</div>;
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
const LAYOUT = `<TwoColumn>
|
|
@@ -51,93 +51,93 @@ const LAYOUT = `<TwoColumn>
|
|
|
51
51
|
</TwoColumn>`;
|
|
52
52
|
|
|
53
53
|
describe("MarkdownViewer / custom component preserveNewlines", () => {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
54
|
+
it("does not inject <br /> between block children (they render as blocks)", () => {
|
|
55
|
+
const components: MarkdownComponents = {
|
|
56
|
+
TwoColumn: { component: TwoColumn, block: true },
|
|
57
|
+
ColBox: { component: ColBox, block: true },
|
|
58
|
+
};
|
|
59
|
+
const html = shell(
|
|
60
|
+
<MarkdownViewer
|
|
61
|
+
content={LAYOUT}
|
|
62
|
+
components={components}
|
|
63
|
+
/>,
|
|
64
|
+
);
|
|
65
65
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
66
|
+
// Three boxes still render, in order.
|
|
67
|
+
expect(html.match(/data-testid="col-box"/g)?.length).toBe(3);
|
|
68
|
+
// Block-level children are carved out and rendered as their own blocks:
|
|
69
|
+
// the newlines that merely separate them must NOT become <br /> elements.
|
|
70
|
+
// A stray <br /> here would also be counted as an extra child by
|
|
71
|
+
// introspecting parents (e.g. <Tabs> reading each <TabItem>), so the two
|
|
72
|
+
// behaviours are unified — `preserveNewlines` governs prose line breaks
|
|
73
|
+
// (see the prose test below), not gaps between block children.
|
|
74
|
+
const inner = html.slice(
|
|
75
|
+
html.indexOf('data-testid="two-column"'),
|
|
76
|
+
html.lastIndexOf("</div>"),
|
|
77
|
+
);
|
|
78
|
+
expect(inner).not.toMatch(/<br\s*\/?>/);
|
|
79
|
+
});
|
|
80
80
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
81
|
+
it("omits <br /> between block children when preserveNewlines is false", () => {
|
|
82
|
+
const components: MarkdownComponents = {
|
|
83
|
+
TwoColumn: { component: TwoColumn, block: true, preserveNewlines: false },
|
|
84
|
+
ColBox: { component: ColBox, block: true },
|
|
85
|
+
};
|
|
86
|
+
const html = shell(
|
|
87
|
+
<MarkdownViewer
|
|
88
|
+
content={LAYOUT}
|
|
89
|
+
components={components}
|
|
90
|
+
/>,
|
|
91
|
+
);
|
|
92
92
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
93
|
+
// All three boxes still render.
|
|
94
|
+
expect(html.match(/data-testid="col-box"/g)?.length).toBe(3);
|
|
95
|
+
// The TwoColumn wrapper is present.
|
|
96
|
+
expect(html).toContain('data-testid="two-column"');
|
|
97
97
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
98
|
+
// No stray line breaks injected between the child blocks.
|
|
99
|
+
const inner = html.slice(
|
|
100
|
+
html.indexOf('data-testid="two-column"'),
|
|
101
|
+
html.lastIndexOf("</div>"),
|
|
102
|
+
);
|
|
103
|
+
expect(inner).not.toMatch(/<br\s*\/?>/);
|
|
104
|
+
});
|
|
105
105
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
106
|
+
it("still preserves newlines for prose components by default", () => {
|
|
107
|
+
function Prose({ children }: { children?: ReactNode }): ReactElement {
|
|
108
|
+
return <section data-testid="prose">{children}</section>;
|
|
109
|
+
}
|
|
110
|
+
const components: MarkdownComponents = {
|
|
111
|
+
Prose: { component: Prose, block: true },
|
|
112
|
+
};
|
|
113
|
+
const html = shell(
|
|
114
|
+
<MarkdownViewer
|
|
115
|
+
content={"<Prose>\nLine one\nLine two\n</Prose>"}
|
|
116
|
+
components={components}
|
|
117
|
+
/>,
|
|
118
|
+
);
|
|
119
|
+
expect(html).toContain("Line one");
|
|
120
|
+
expect(html).toContain("Line two");
|
|
121
|
+
// Multi-line prose keeps its line break.
|
|
122
|
+
expect(html).toMatch(/<br\s*\/?>/);
|
|
123
|
+
});
|
|
124
124
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
125
|
+
it("disabling preserveNewlines collapses multi-line text to a single run", () => {
|
|
126
|
+
function Prose({ children }: { children?: ReactNode }): ReactElement {
|
|
127
|
+
return <section data-testid="prose">{children}</section>;
|
|
128
|
+
}
|
|
129
|
+
const components: MarkdownComponents = {
|
|
130
|
+
Prose: { component: Prose, block: true, preserveNewlines: false },
|
|
131
|
+
};
|
|
132
|
+
const html = shell(
|
|
133
|
+
<MarkdownViewer
|
|
134
|
+
content={"<Prose>\nLine one\nLine two\n</Prose>"}
|
|
135
|
+
components={components}
|
|
136
|
+
/>,
|
|
137
|
+
);
|
|
138
|
+
expect(html).toContain("Line one");
|
|
139
|
+
expect(html).toContain("Line two");
|
|
140
|
+
const inner = html.slice(html.indexOf('data-testid="prose"'));
|
|
141
|
+
expect(inner).not.toMatch(/<br\s*\/?>/);
|
|
142
|
+
});
|
|
143
143
|
});
|
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
estimateMarkdownReadTimeMinutes,
|
|
3
|
+
formatMarkdownReadTime,
|
|
4
|
+
markdownToPlainText,
|
|
5
5
|
} from "@src/lib/markdown/read-time";
|
|
6
6
|
import { describe, expect, it } from "vitest";
|
|
7
7
|
|
|
8
8
|
describe("markdown read time", () => {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
it("strips markdown syntax for word counting", () => {
|
|
10
|
+
expect(markdownToPlainText("# Title\n\n[link](https://example.com)")).toBe("Title link");
|
|
11
|
+
});
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
it("estimates at least one minute", () => {
|
|
14
|
+
expect(estimateMarkdownReadTimeMinutes("")).toBe(1);
|
|
15
|
+
});
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
17
|
+
it("formats a read-time label", () => {
|
|
18
|
+
const words = Array.from({ length: 400 }, () => "word").join(" ");
|
|
19
|
+
expect(formatMarkdownReadTime(words)).toBe("2 min read");
|
|
20
|
+
});
|
|
21
21
|
});
|
|
@@ -6,90 +6,90 @@ import { renderToString } from "react-dom/server";
|
|
|
6
6
|
import { beforeAll, describe, expect, it } from "vitest";
|
|
7
7
|
|
|
8
8
|
beforeAll(() => {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
9
|
+
if (typeof window !== "undefined" && typeof window.matchMedia !== "function") {
|
|
10
|
+
Object.defineProperty(window, "matchMedia", {
|
|
11
|
+
writable: true,
|
|
12
|
+
value: (query: string) => ({
|
|
13
|
+
matches: false,
|
|
14
|
+
media: query,
|
|
15
|
+
onchange: null,
|
|
16
|
+
addListener: () => {},
|
|
17
|
+
removeListener: () => {},
|
|
18
|
+
addEventListener: () => {},
|
|
19
|
+
removeEventListener: () => {},
|
|
20
|
+
dispatchEvent: () => false,
|
|
21
|
+
}),
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
24
|
});
|
|
25
25
|
|
|
26
26
|
function shell(node: ReactElement): string {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
27
|
+
return renderToString(
|
|
28
|
+
<MantineProvider
|
|
29
|
+
theme={MANTINE_THEME}
|
|
30
|
+
cssVariablesResolver={v8CssVariablesResolver}
|
|
31
|
+
forceColorScheme="dark"
|
|
32
|
+
>
|
|
33
|
+
{node}
|
|
34
|
+
</MantineProvider>,
|
|
35
|
+
);
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
describe("MarkdownViewer / MarkdownViewerRenderers", () => {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
39
|
+
it("uses heading renderer override", () => {
|
|
40
|
+
const html = shell(
|
|
41
|
+
<MarkdownViewer
|
|
42
|
+
content="## Section title"
|
|
43
|
+
renderers={{
|
|
44
|
+
heading: () => <span data-custom-heading>HEADING_MARKER</span>,
|
|
45
|
+
}}
|
|
46
|
+
/>,
|
|
47
|
+
);
|
|
48
|
+
expect(html).toContain("HEADING_MARKER");
|
|
49
|
+
expect(html).not.toContain("Section title");
|
|
50
|
+
});
|
|
51
51
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
52
|
+
it("uses link renderer override", () => {
|
|
53
|
+
const html = shell(
|
|
54
|
+
<MarkdownViewer
|
|
55
|
+
content="[Example](https://example.com)"
|
|
56
|
+
renderers={{
|
|
57
|
+
link: () => <span data-custom-link>LINK_MARKER</span>,
|
|
58
|
+
}}
|
|
59
|
+
/>,
|
|
60
|
+
);
|
|
61
|
+
expect(html).toContain("LINK_MARKER");
|
|
62
|
+
expect(html).not.toContain("Example");
|
|
63
|
+
expect(html).not.toContain("https://example.com");
|
|
64
|
+
});
|
|
65
65
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
66
|
+
it("uses table renderer override without the scroll wrapper", () => {
|
|
67
|
+
const html = shell(
|
|
68
|
+
<MarkdownViewer
|
|
69
|
+
content={`| A | B |
|
|
70
70
|
| - | - |
|
|
71
71
|
| 1 | 2 |`}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
72
|
+
renderers={{
|
|
73
|
+
table: () => <span data-custom-table>TABLE_MARKER</span>,
|
|
74
|
+
}}
|
|
75
|
+
/>,
|
|
76
|
+
);
|
|
77
|
+
expect(html).toContain("TABLE_MARKER");
|
|
78
|
+
expect(html).not.toContain("<table");
|
|
79
|
+
expect(html).not.toContain("mantine-TableScrollContainer-scrollContainer");
|
|
80
|
+
});
|
|
81
81
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
82
|
+
it("uses image renderer override", () => {
|
|
83
|
+
const html = shell(
|
|
84
|
+
<MarkdownViewer
|
|
85
|
+
content=''
|
|
86
|
+
renderers={{
|
|
87
|
+
image: () => <span data-custom-image>IMAGE_MARKER</span>,
|
|
88
|
+
}}
|
|
89
|
+
/>,
|
|
90
|
+
);
|
|
91
|
+
expect(html).toContain("IMAGE_MARKER");
|
|
92
|
+
expect(html).not.toContain("Alt text");
|
|
93
|
+
expect(html).not.toContain("https://example.com/image.png");
|
|
94
|
+
});
|
|
95
95
|
});
|
|
@@ -6,64 +6,64 @@ import { renderToString } from "react-dom/server";
|
|
|
6
6
|
import { beforeAll, describe, expect, it } from "vitest";
|
|
7
7
|
|
|
8
8
|
beforeAll(() => {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
9
|
+
if (typeof window !== "undefined" && typeof window.matchMedia !== "function") {
|
|
10
|
+
Object.defineProperty(window, "matchMedia", {
|
|
11
|
+
writable: true,
|
|
12
|
+
value: (query: string) => ({
|
|
13
|
+
matches: false,
|
|
14
|
+
media: query,
|
|
15
|
+
onchange: null,
|
|
16
|
+
addListener: () => {},
|
|
17
|
+
removeListener: () => {},
|
|
18
|
+
addEventListener: () => {},
|
|
19
|
+
removeEventListener: () => {},
|
|
20
|
+
dispatchEvent: () => false,
|
|
21
|
+
}),
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
24
|
});
|
|
25
25
|
|
|
26
26
|
function shell(node: ReactElement): string {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
27
|
+
return renderToString(
|
|
28
|
+
<MantineProvider
|
|
29
|
+
theme={MANTINE_THEME}
|
|
30
|
+
cssVariablesResolver={v8CssVariablesResolver}
|
|
31
|
+
forceColorScheme="dark"
|
|
32
|
+
>
|
|
33
|
+
{node}
|
|
34
|
+
</MantineProvider>,
|
|
35
|
+
);
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
describe("MarkdownViewer / runnable code", () => {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
39
|
+
it("renders RunnableCodeBlock when fenced info includes runnable", () => {
|
|
40
|
+
const html = shell(
|
|
41
|
+
<MarkdownViewer content={'```surql runnable="SELECT 1"\nRETURN 1;\n```'} />,
|
|
42
|
+
);
|
|
43
|
+
expect(html).toContain("Run Query");
|
|
44
|
+
});
|
|
45
45
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
46
|
+
it("renders RunnableCodeBlock for a loose runnable flag with no value", () => {
|
|
47
|
+
const html = shell(<MarkdownViewer content={"```surql runnable\nRETURN 1;\n```"} />);
|
|
48
|
+
expect(html).toContain("Run Query");
|
|
49
|
+
});
|
|
50
50
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
51
|
+
it("does not render RunnableCodeBlock for plain fenced code", () => {
|
|
52
|
+
const html = shell(<MarkdownViewer content={"```surql\nRETURN 1;\n```"} />);
|
|
53
|
+
expect(html).not.toContain("Run Query");
|
|
54
|
+
});
|
|
55
55
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
56
|
+
it("preserves runnable attribute casing through the render pipeline", () => {
|
|
57
|
+
const html = shell(
|
|
58
|
+
<MarkdownViewer
|
|
59
|
+
content={'```surql runnable="SELECT 1"\nRETURN 1;\n```'}
|
|
60
|
+
codeRenderers={{}}
|
|
61
|
+
renderers={{
|
|
62
|
+
code: ({ runnable }) => <span data-runnable={runnable}>{runnable}</span>,
|
|
63
|
+
}}
|
|
64
|
+
/>,
|
|
65
|
+
);
|
|
66
|
+
expect(html).toContain("SELECT 1");
|
|
67
|
+
expect(html).not.toContain("select 1");
|
|
68
|
+
});
|
|
69
69
|
});
|