@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
|
@@ -4,46 +4,47 @@ import { MANTINE_THEME } from "@src/theme/mantine";
|
|
|
4
4
|
import type { ReactElement } from "react";
|
|
5
5
|
import { renderToString } from "react-dom/server";
|
|
6
6
|
import { beforeAll, describe, expect, it } from "vitest";
|
|
7
|
+
|
|
7
8
|
import { md, mdViewer } from "../../_setup/markdown-classes";
|
|
8
9
|
|
|
9
10
|
// Mantine's `useComputedColorScheme` reaches for `window.matchMedia` even
|
|
10
11
|
// during a `renderToString` pass; stub it so the SSR test can exercise the
|
|
11
12
|
// full viewer pipeline (including `MarkdownCodeLines`).
|
|
12
13
|
beforeAll(() => {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
14
|
+
if (typeof window !== "undefined" && typeof window.matchMedia !== "function") {
|
|
15
|
+
Object.defineProperty(window, "matchMedia", {
|
|
16
|
+
writable: true,
|
|
17
|
+
value: (query: string) => ({
|
|
18
|
+
matches: false,
|
|
19
|
+
media: query,
|
|
20
|
+
onchange: null,
|
|
21
|
+
addListener: () => {},
|
|
22
|
+
removeListener: () => {},
|
|
23
|
+
addEventListener: () => {},
|
|
24
|
+
removeEventListener: () => {},
|
|
25
|
+
dispatchEvent: () => false,
|
|
26
|
+
}),
|
|
27
|
+
});
|
|
28
|
+
}
|
|
28
29
|
});
|
|
29
30
|
|
|
30
31
|
function shell(node: ReactElement): string {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
32
|
+
return renderToString(
|
|
33
|
+
<MantineProvider
|
|
34
|
+
theme={MANTINE_THEME}
|
|
35
|
+
cssVariablesResolver={v8CssVariablesResolver}
|
|
36
|
+
forceColorScheme="dark"
|
|
37
|
+
>
|
|
38
|
+
{node}
|
|
39
|
+
</MantineProvider>,
|
|
40
|
+
);
|
|
40
41
|
}
|
|
41
42
|
|
|
42
43
|
describe("MarkdownViewer / SSR", () => {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
44
|
+
it("renders to a static HTML string with semantic markdown structure", () => {
|
|
45
|
+
const html = shell(
|
|
46
|
+
<MarkdownViewer
|
|
47
|
+
content={`# Title
|
|
47
48
|
|
|
48
49
|
Body with **bold**, *italic* and [a link](https://surrealdb.com).
|
|
49
50
|
|
|
@@ -57,37 +58,37 @@ Body with **bold**, *italic* and [a link](https://surrealdb.com).
|
|
|
57
58
|
return true;
|
|
58
59
|
\`\`\`
|
|
59
60
|
`}
|
|
60
|
-
|
|
61
|
-
|
|
61
|
+
/>,
|
|
62
|
+
);
|
|
62
63
|
|
|
63
|
-
|
|
64
|
-
|
|
64
|
+
// Wrapper.
|
|
65
|
+
expect(html).toContain(mdViewer.viewerRoot);
|
|
65
66
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
67
|
+
// Semantic heading.
|
|
68
|
+
expect(html).toContain(md.h1);
|
|
69
|
+
expect(html).toMatch(/id="title"/);
|
|
70
|
+
expect(html).toContain("Title");
|
|
70
71
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
72
|
+
// Paragraph and inline marks (paragraph uses bare <p> without module class).
|
|
73
|
+
expect(html).toMatch(/<p[^>]*>Body with/);
|
|
74
|
+
expect(html).toContain(md.strong);
|
|
75
|
+
expect(html).toContain("bold</strong>");
|
|
76
|
+
expect(html).toContain(md.emphasis);
|
|
77
|
+
expect(html).toContain(md.link);
|
|
77
78
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
79
|
+
// Semantic lists.
|
|
80
|
+
expect(html).toContain(md.list);
|
|
81
|
+
expect(html).toContain("<li");
|
|
81
82
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
83
|
+
// Semantic code block.
|
|
84
|
+
expect(html).toContain(md.codeBlock);
|
|
85
|
+
expect(html).toContain("<code");
|
|
86
|
+
expect(html).toContain("</code></pre>");
|
|
86
87
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
88
|
+
// Raw markdown markers must not leak through.
|
|
89
|
+
expect(html).not.toContain("**bold**");
|
|
90
|
+
expect(html).not.toContain("*italic*");
|
|
91
|
+
expect(html).not.toContain("## ");
|
|
92
|
+
expect(html).not.toMatch(/<p[^>]*>#/);
|
|
93
|
+
});
|
|
93
94
|
});
|
|
@@ -4,43 +4,44 @@ import { MANTINE_THEME } from "@src/theme/mantine";
|
|
|
4
4
|
import type { ReactElement } from "react";
|
|
5
5
|
import { renderToString } from "react-dom/server";
|
|
6
6
|
import { beforeAll, describe, expect, it } from "vitest";
|
|
7
|
+
|
|
7
8
|
import { md } from "../../_setup/markdown-classes";
|
|
8
9
|
|
|
9
10
|
beforeAll(() => {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
11
|
+
if (typeof window !== "undefined" && typeof window.matchMedia !== "function") {
|
|
12
|
+
Object.defineProperty(window, "matchMedia", {
|
|
13
|
+
writable: true,
|
|
14
|
+
value: (query: string) => ({
|
|
15
|
+
matches: false,
|
|
16
|
+
media: query,
|
|
17
|
+
onchange: null,
|
|
18
|
+
addListener: () => {},
|
|
19
|
+
removeListener: () => {},
|
|
20
|
+
addEventListener: () => {},
|
|
21
|
+
removeEventListener: () => {},
|
|
22
|
+
dispatchEvent: () => false,
|
|
23
|
+
}),
|
|
24
|
+
});
|
|
25
|
+
}
|
|
25
26
|
});
|
|
26
27
|
|
|
27
28
|
function shell(node: ReactElement): string {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
29
|
+
return renderToString(
|
|
30
|
+
<MantineProvider
|
|
31
|
+
theme={MANTINE_THEME}
|
|
32
|
+
cssVariablesResolver={v8CssVariablesResolver}
|
|
33
|
+
forceColorScheme="dark"
|
|
34
|
+
>
|
|
35
|
+
{node}
|
|
36
|
+
</MantineProvider>,
|
|
37
|
+
);
|
|
37
38
|
}
|
|
38
39
|
|
|
39
40
|
describe("MarkdownViewer / syntax highlighting", () => {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
41
|
+
it("highlights bash and sh fenced blocks", () => {
|
|
42
|
+
const html = shell(
|
|
43
|
+
<MarkdownViewer
|
|
44
|
+
content={`\`\`\`bash
|
|
44
45
|
cd project
|
|
45
46
|
\`\`\`
|
|
46
47
|
|
|
@@ -48,26 +49,26 @@ cd project
|
|
|
48
49
|
export FOO=bar
|
|
49
50
|
\`\`\`
|
|
50
51
|
`}
|
|
51
|
-
|
|
52
|
-
|
|
52
|
+
/>,
|
|
53
|
+
);
|
|
53
54
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
55
|
+
expect(html).toContain(md.codeBlock);
|
|
56
|
+
expect(html).toMatch(/style="color:#ffd000"/);
|
|
57
|
+
});
|
|
57
58
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
59
|
+
it("highlights json fenced blocks", () => {
|
|
60
|
+
const html = shell(
|
|
61
|
+
<MarkdownViewer
|
|
62
|
+
content={`\`\`\`json
|
|
62
63
|
{
|
|
63
64
|
"name": "example"
|
|
64
65
|
}
|
|
65
66
|
\`\`\`
|
|
66
67
|
`}
|
|
67
|
-
|
|
68
|
-
|
|
68
|
+
/>,
|
|
69
|
+
);
|
|
69
70
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
71
|
+
expect(html).toContain(md.codeBlock);
|
|
72
|
+
expect(html).toMatch(/style="color:#00ff6e"/);
|
|
73
|
+
});
|
|
73
74
|
});
|
|
@@ -6,37 +6,37 @@ 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
|
function labels(html: string): string[] {
|
|
39
|
-
|
|
39
|
+
return [...html.matchAll(/mantine-Tabs-tabLabel">([^<]*)</g)].map((m) => m[1] ?? "");
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
// Tab items whose fenced code sits directly under the tag (no blank-line
|
|
@@ -81,116 +81,116 @@ const INDENTED = `<Tabs groupId="package-manager">
|
|
|
81
81
|
</Tabs>`;
|
|
82
82
|
|
|
83
83
|
describe("MarkdownViewer / Tabs with fenced code", () => {
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
84
|
+
for (const [name, content] of [
|
|
85
|
+
["flush", FLUSH],
|
|
86
|
+
["indented", INDENTED],
|
|
87
|
+
] as const) {
|
|
88
|
+
it(`${name}: renders both tabs, both labels, and highlighted code`, () => {
|
|
89
|
+
const html = shell(<MarkdownViewer content={content} />);
|
|
90
|
+
const text = html.replace(/<[^>]+>/g, "");
|
|
91
|
+
|
|
92
|
+
// Both tab buttons are present, in order.
|
|
93
|
+
expect(labels(html)).toEqual(["ESM", "CommonJS"]);
|
|
94
|
+
// The fenced code is rendered as a real (highlighted) code block
|
|
95
|
+
// whose tokens survive in the markup.
|
|
96
|
+
expect(html).toContain('data-language="ts"');
|
|
97
|
+
expect(html).toContain("Surreal");
|
|
98
|
+
expect(html).toContain("surrealdb");
|
|
99
|
+
// Tags and fences are not leaked as visible plain text.
|
|
100
|
+
expect(text).not.toContain("</TabItem>");
|
|
101
|
+
expect(text).not.toContain("<TabItem");
|
|
102
|
+
expect(text).not.toContain("```");
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
105
|
});
|
|
106
106
|
|
|
107
107
|
// A tab item whose content mixes prose paragraphs, blank lines, and a fenced
|
|
108
108
|
// code block — all indented under the tags. `bl` builds the blank separator
|
|
109
109
|
// lines, optionally carrying the structural tab (some editors keep it).
|
|
110
110
|
function mixedItem(bl: "" | "\t"): string {
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
111
|
+
return [
|
|
112
|
+
"<Tabs>",
|
|
113
|
+
'\t<TabItem value="esm" label="ESM">',
|
|
114
|
+
bl,
|
|
115
|
+
"\tTest",
|
|
116
|
+
bl,
|
|
117
|
+
"\t```ts",
|
|
118
|
+
"\timport { Surreal } from 'surrealdb';",
|
|
119
|
+
bl,
|
|
120
|
+
"\t// Create a new Surreal instance",
|
|
121
|
+
"\tconst db = new Surreal();",
|
|
122
|
+
"\t```",
|
|
123
|
+
bl,
|
|
124
|
+
"\ttest2",
|
|
125
|
+
bl,
|
|
126
|
+
"\t</TabItem>",
|
|
127
|
+
"</Tabs>",
|
|
128
|
+
].join("\n");
|
|
129
129
|
}
|
|
130
130
|
|
|
131
131
|
// Mirrors docs' in-memory.mdx: an indented tab item whose runaway fence used to
|
|
132
132
|
// swallow the following flush <Tabs> block whole.
|
|
133
133
|
const TWO_TAB_BLOCKS = [
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
134
|
+
"<Tabs>",
|
|
135
|
+
'\t<TabItem value="esm" label="ESM">',
|
|
136
|
+
"",
|
|
137
|
+
"\tTest",
|
|
138
|
+
"",
|
|
139
|
+
"\t```ts",
|
|
140
|
+
"\timport { Surreal } from 'surrealdb';",
|
|
141
|
+
"\t```",
|
|
142
|
+
"",
|
|
143
|
+
"\t</TabItem>",
|
|
144
|
+
"</Tabs>",
|
|
145
|
+
"",
|
|
146
|
+
"<Tabs>",
|
|
147
|
+
"",
|
|
148
|
+
'<TabItem label="SurrealDB 3.x">',
|
|
149
|
+
"",
|
|
150
|
+
"```bash",
|
|
151
|
+
"surreal start mem",
|
|
152
|
+
"```",
|
|
153
|
+
"",
|
|
154
|
+
"</TabItem>",
|
|
155
|
+
"</Tabs>",
|
|
156
156
|
].join("\n");
|
|
157
157
|
|
|
158
158
|
describe("MarkdownViewer / two adjacent Tabs blocks", () => {
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
159
|
+
it("renders both blocks independently without one swallowing the next", () => {
|
|
160
|
+
const html = shell(<MarkdownViewer content={TWO_TAB_BLOCKS} />);
|
|
161
|
+
const text = html.replace(/<[^>]+>/g, " ").replace(/\s+/g, " ");
|
|
162
|
+
|
|
163
|
+
// Both tab blocks produced their own labelled tab.
|
|
164
|
+
expect(labels(html)).toEqual(["ESM", "SurrealDB 3.x"]);
|
|
165
|
+
// Content from both blocks is present…
|
|
166
|
+
expect(html).toContain("surrealdb");
|
|
167
|
+
expect(text).toContain("surreal start mem");
|
|
168
|
+
// …and nothing leaked as raw tags or fences.
|
|
169
|
+
expect(text).not.toContain("TabItem");
|
|
170
|
+
expect(text).not.toContain("Tabs");
|
|
171
|
+
expect(text).not.toContain("```");
|
|
172
|
+
});
|
|
173
173
|
});
|
|
174
174
|
|
|
175
175
|
describe("MarkdownViewer / Tabs with mixed indented content", () => {
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
176
|
+
for (const blank of ["", "\t"] as const) {
|
|
177
|
+
const label = blank === "" ? "empty blank lines" : "tab-filled blank lines";
|
|
178
|
+
it(`renders prose + code + prose inside an indented tab item (${label})`, () => {
|
|
179
|
+
const html = shell(<MarkdownViewer content={mixedItem(blank)} />);
|
|
180
|
+
const text = html.replace(/<[^>]+>/g, " ").replace(/\s+/g, " ");
|
|
181
|
+
|
|
182
|
+
expect(labels(html)).toEqual(["ESM"]);
|
|
183
|
+
// Prose before and after the code block renders as prose.
|
|
184
|
+
expect(text).toContain("Test");
|
|
185
|
+
expect(text).toContain("test2");
|
|
186
|
+
// The code renders as a highlighted code block, not leaked prose.
|
|
187
|
+
expect(html).toContain('data-language="ts"');
|
|
188
|
+
expect(html).toContain("surrealdb");
|
|
189
|
+
// Nothing is swallowed: tags and fences never surface as text.
|
|
190
|
+
expect(text).not.toContain("TabItem");
|
|
191
|
+
expect(text).not.toContain("```");
|
|
192
|
+
// The code content must not appear as an indented (tab-prefixed) blob.
|
|
193
|
+
expect(text).not.toContain("\timport");
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
196
|
});
|