@surrealdb/ui 1.2.12 → 1.2.13
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 +21 -19
- package/README.md +15 -10
- package/dist/ui.css +1 -1
- package/dist/ui.d.ts +234 -1
- package/dist/ui.js +8217 -7329
- package/dist/ui.js.map +1 -1
- package/doc/code-style.md +264 -0
- package/doc/stacker-plan.md +219 -0
- package/package.json +119 -116
- 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
|
@@ -2,104 +2,104 @@ import { createWidgetStore } from "@src/lib/markdown/editor/widgets/store";
|
|
|
2
2
|
import { describe, expect, it } from "vitest";
|
|
3
3
|
|
|
4
4
|
describe("createWidgetStore", () => {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
5
|
+
it("unregisterHost removes only the portal whose host identity matches registration", () => {
|
|
6
|
+
const store = createWidgetStore();
|
|
7
|
+
const host214 = document.createElement("span");
|
|
8
|
+
const host227 = document.createElement("span");
|
|
9
|
+
store.register({
|
|
10
|
+
portalKey: 1,
|
|
11
|
+
id: "list-bullet:214",
|
|
12
|
+
host: host214,
|
|
13
|
+
render: () => null,
|
|
14
|
+
});
|
|
15
|
+
store.register({
|
|
16
|
+
portalKey: 2,
|
|
17
|
+
id: "list-bullet:227",
|
|
18
|
+
host: host227,
|
|
19
|
+
render: () => null,
|
|
20
|
+
});
|
|
21
|
+
expect(store.getSnapshot()).toHaveLength(2);
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
expect(store.hasPortalKey(1)).toBe(true);
|
|
24
|
+
expect(store.hasPortalKey(99)).toBe(false);
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
26
|
+
store.unregisterHost(host214);
|
|
27
|
+
expect(store.getSnapshot()).toHaveLength(1);
|
|
28
|
+
expect(store.getSnapshot()[0]?.id).toBe("list-bullet:227");
|
|
29
29
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
30
|
+
store.unregisterHost(host227);
|
|
31
|
+
expect(store.getSnapshot()).toHaveLength(0);
|
|
32
|
+
});
|
|
33
33
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
34
|
+
it("same logical id on two hosts keeps two portals until each host unregisters", () => {
|
|
35
|
+
const store = createWidgetStore();
|
|
36
|
+
const hostA = document.createElement("span");
|
|
37
|
+
const hostB = document.createElement("span");
|
|
38
|
+
store.register({
|
|
39
|
+
portalKey: 10,
|
|
40
|
+
id: "list-bullet:214",
|
|
41
|
+
host: hostA,
|
|
42
|
+
render: () => null,
|
|
43
|
+
});
|
|
44
|
+
store.register({
|
|
45
|
+
portalKey: 11,
|
|
46
|
+
id: "list-bullet:214",
|
|
47
|
+
host: hostB,
|
|
48
|
+
render: () => null,
|
|
49
|
+
});
|
|
50
|
+
expect(store.getSnapshot()).toHaveLength(2);
|
|
51
51
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
52
|
+
store.unregisterHost(hostA);
|
|
53
|
+
expect(store.getSnapshot()).toHaveLength(1);
|
|
54
|
+
expect(store.getSnapshot()[0]?.host).toBe(hostB);
|
|
55
55
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
56
|
+
store.unregisterHost(hostB);
|
|
57
|
+
expect(store.getSnapshot()).toHaveLength(0);
|
|
58
|
+
});
|
|
59
59
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
60
|
+
it("re-registering the same host evicts the previous portalKey (one portal per host)", () => {
|
|
61
|
+
const store = createWidgetStore();
|
|
62
|
+
const host = document.createElement("span");
|
|
63
|
+
store.register({
|
|
64
|
+
portalKey: 1,
|
|
65
|
+
id: "checkbox:2-5",
|
|
66
|
+
host,
|
|
67
|
+
render: () => null,
|
|
68
|
+
});
|
|
69
|
+
expect(store.getSnapshot()).toHaveLength(1);
|
|
70
70
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
71
|
+
store.register({
|
|
72
|
+
portalKey: 2,
|
|
73
|
+
id: "checkbox:2-5",
|
|
74
|
+
host,
|
|
75
|
+
render: () => null,
|
|
76
|
+
});
|
|
77
|
+
expect(store.getSnapshot()).toHaveLength(1);
|
|
78
|
+
expect(store.getSnapshot()[0]?.portalKey).toBe(2);
|
|
79
|
+
expect(store.hasPortalKey(1)).toBe(false);
|
|
80
|
+
expect(store.hasPortalKey(2)).toBe(true);
|
|
81
|
+
});
|
|
82
82
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
83
|
+
it("unregisterHost with expectedPortalKey skips when a newer registration owns the host", () => {
|
|
84
|
+
const store = createWidgetStore();
|
|
85
|
+
const host = document.createElement("span");
|
|
86
|
+
store.register({
|
|
87
|
+
portalKey: 10,
|
|
88
|
+
id: "checkbox:2-5",
|
|
89
|
+
host,
|
|
90
|
+
render: () => null,
|
|
91
|
+
});
|
|
92
|
+
store.register({
|
|
93
|
+
portalKey: 11,
|
|
94
|
+
id: "checkbox:2-5",
|
|
95
|
+
host,
|
|
96
|
+
render: () => null,
|
|
97
|
+
});
|
|
98
|
+
store.unregisterHost(host, 10);
|
|
99
|
+
expect(store.getSnapshot()).toHaveLength(1);
|
|
100
|
+
expect(store.getSnapshot()[0]?.portalKey).toBe(11);
|
|
101
101
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
102
|
+
store.unregisterHost(host, 11);
|
|
103
|
+
expect(store.getSnapshot()).toHaveLength(0);
|
|
104
|
+
});
|
|
105
105
|
});
|
|
@@ -6,55 +6,55 @@ 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 / callouts", () => {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
39
|
+
it("renders the title and body without a leading <br> between them", () => {
|
|
40
|
+
const html = shell(
|
|
41
|
+
<MarkdownViewer
|
|
42
|
+
content={"> [!NOTE]\n> Sandbox data is **not persistent**: it is reset later."}
|
|
43
|
+
/>,
|
|
44
|
+
);
|
|
45
45
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
46
|
+
expect(html).toContain("Note");
|
|
47
|
+
expect(html).toContain("Sandbox data is");
|
|
48
|
+
expect(html).toContain("not persistent");
|
|
49
49
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
50
|
+
// The body paragraph must not open with a stray line break.
|
|
51
|
+
expect(html).not.toMatch(/<p[^>]*><br\s*\/?>/);
|
|
52
|
+
});
|
|
53
53
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
54
|
+
it("supports the title and body on adjacent lines", () => {
|
|
55
|
+
const html = shell(<MarkdownViewer content={"> [!WARNING]\n> Be careful here."} />);
|
|
56
|
+
expect(html).toContain("Warning");
|
|
57
|
+
expect(html).toContain("Be careful here.");
|
|
58
|
+
expect(html).not.toMatch(/<p[^>]*><br\s*\/?>/);
|
|
59
|
+
});
|
|
60
60
|
});
|
|
@@ -6,33 +6,33 @@ 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
|
// Dark-scheme syntax colors (see src/syntax/theme.ts).
|
|
@@ -40,22 +40,22 @@ const STRING_COLOR = "#00ff6e";
|
|
|
40
40
|
const PROPERTY_COLOR = "#e06c75";
|
|
41
41
|
|
|
42
42
|
describe("MarkdownViewer / code syntax highlighting", () => {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
43
|
+
it("highlights object keys as property names (not bare identifiers)", () => {
|
|
44
|
+
const code = ["{", ' "monthly_sales": "DEFINE TABLE monthly_sales TYPE NORMAL"', "}"].join(
|
|
45
|
+
"\n",
|
|
46
|
+
);
|
|
47
|
+
const html = shell(<MarkdownViewer content={`\`\`\`json\n${code}\n\`\`\``} />);
|
|
48
|
+
expect(html).toContain(PROPERTY_COLOR);
|
|
49
|
+
expect(html).toContain(STRING_COLOR);
|
|
50
|
+
});
|
|
51
51
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
52
|
+
it("keeps a multi-line string token highlighted as one string across lines", () => {
|
|
53
|
+
const code = ["const q = `DEFINE TABLE wishlist", "SCHEMAFULL PERMISSIONS NONE`;"].join(
|
|
54
|
+
"\n",
|
|
55
|
+
);
|
|
56
|
+
const html = shell(<MarkdownViewer content={`\`\`\`js\n${code}\n\`\`\``} />);
|
|
57
|
+
// Continuation line content must be inside a string-colored span — proof
|
|
58
|
+
// the whole block was parsed once rather than line by line.
|
|
59
|
+
expect(html).toMatch(new RegExp(`color:${STRING_COLOR}[^>]*>SCHEMAFULL PERMISSIONS NONE`));
|
|
60
|
+
});
|
|
61
61
|
});
|
|
@@ -6,57 +6,57 @@ 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 / code title", () => {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
39
|
+
it("renders a title attribute as a caption above the code block", () => {
|
|
40
|
+
const html = shell(
|
|
41
|
+
<MarkdownViewer content={'```ts title="Example file"\nconst x = 1;\n```'} />,
|
|
42
|
+
);
|
|
43
|
+
expect(html).toContain("Example file");
|
|
44
|
+
});
|
|
45
45
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
46
|
+
it("omits the caption when no title is present", () => {
|
|
47
|
+
const html = shell(<MarkdownViewer content={"```ts\nconst x = 1;\n```"} />);
|
|
48
|
+
expect(html).not.toContain("code-block-caption");
|
|
49
|
+
});
|
|
50
50
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
51
|
+
it("passes the title through the code renderer override", () => {
|
|
52
|
+
const html = shell(
|
|
53
|
+
<MarkdownViewer
|
|
54
|
+
content={'```ts title="From override"\nconst x = 1;\n```'}
|
|
55
|
+
renderers={{
|
|
56
|
+
code: ({ title }) => <span data-title={title}>{title}</span>,
|
|
57
|
+
}}
|
|
58
|
+
/>,
|
|
59
|
+
);
|
|
60
|
+
expect(html).toContain("From override");
|
|
61
|
+
});
|
|
62
62
|
});
|