@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.
Files changed (93) hide show
  1. package/.claude/launch.json +17 -0
  2. package/.oxfmtrc.json +27 -0
  3. package/.oxlintrc.json +23 -0
  4. package/.zed/settings.json +34 -34
  5. package/AGENTS.md +21 -19
  6. package/README.md +15 -10
  7. package/dist/ui.css +1 -1
  8. package/dist/ui.d.ts +234 -1
  9. package/dist/ui.js +8217 -7329
  10. package/dist/ui.js.map +1 -1
  11. package/doc/code-style.md +264 -0
  12. package/doc/stacker-plan.md +219 -0
  13. package/package.json +119 -116
  14. package/res/_mixins.scss +15 -11
  15. package/tests/_setup/e2e-helpers.tsx +85 -85
  16. package/tests/_setup/portable-stories.ts +11 -10
  17. package/tests/e2e/MarkdownEditor/content-blocks.test.tsx +140 -139
  18. package/tests/e2e/MarkdownEditor/edits.test.tsx +101 -100
  19. package/tests/e2e/MarkdownEditor/heading-fold.test.tsx +35 -34
  20. package/tests/e2e/MarkdownEditor/hybrid-widgets.test.tsx +178 -177
  21. package/tests/e2e/MarkdownEditor/image-on-image.test.tsx +50 -49
  22. package/tests/e2e/MarkdownEditor/jsx-block-content.test.tsx +195 -194
  23. package/tests/e2e/MarkdownEditor/jsx-highlight.test.tsx +47 -46
  24. package/tests/e2e/MarkdownEditor/jsx-inline-badges.test.tsx +35 -34
  25. package/tests/e2e/MarkdownEditor/jsx-inline-click.test.tsx +39 -38
  26. package/tests/e2e/MarkdownEditor/jsx-selection.test.tsx +28 -27
  27. package/tests/e2e/MarkdownEditor/link-placeholder.test.tsx +49 -48
  28. package/tests/e2e/MarkdownEditor/media-align.test.tsx +40 -39
  29. package/tests/e2e/MarkdownEditor/media-edit.test.tsx +49 -48
  30. package/tests/e2e/MarkdownEditor/media-sizing.test.tsx +108 -107
  31. package/tests/e2e/MarkdownEditor/modes.test.tsx +79 -78
  32. package/tests/e2e/MarkdownEditor/onimage-parity.test.tsx +29 -28
  33. package/tests/e2e/MarkdownEditor/regressions.test.tsx +194 -193
  34. package/tests/e2e/MarkdownEditor/slash-commands.test.tsx +81 -80
  35. package/tests/e2e/MarkdownEditor/table-click.test.tsx +36 -35
  36. package/tests/e2e/MarkdownEditor/table-controls.test.tsx +44 -43
  37. package/tests/e2e/MarkdownEditor/table-format.test.tsx +28 -27
  38. package/tests/e2e/MarkdownEditor/undo-redo.test.tsx +22 -21
  39. package/tests/e2e/MarkdownViewer/parity.test.tsx +144 -143
  40. package/tests/e2e/MarkdownViewer/render.test.tsx +20 -19
  41. package/tests/e2e/Stacker/stacker.test.tsx +304 -0
  42. package/tests/unit/Editor/helpers.test.ts +26 -26
  43. package/tests/unit/MarkdownConformance/error-isolation.test.tsx +26 -25
  44. package/tests/unit/MarkdownConformance/indentation.test.tsx +20 -19
  45. package/tests/unit/MarkdownConformance/inline-code-fuzz.test.tsx +255 -0
  46. package/tests/unit/MarkdownConformance/jsx-attributes.test.tsx +39 -38
  47. package/tests/unit/MarkdownConformance/jsx-fuzz.test.tsx +122 -122
  48. package/tests/unit/MarkdownConformance/links.test.tsx +78 -54
  49. package/tests/unit/MarkdownConformance/render-helpers.tsx +60 -60
  50. package/tests/unit/MarkdownEditor/code-info.test.ts +58 -58
  51. package/tests/unit/MarkdownEditor/decorations.test.ts +423 -421
  52. package/tests/unit/MarkdownEditor/editor-ready.test.ts +22 -22
  53. package/tests/unit/MarkdownEditor/html-descriptors.test.ts +70 -70
  54. package/tests/unit/MarkdownEditor/indented-fence.test.ts +80 -80
  55. package/tests/unit/MarkdownEditor/jsx-attr-scan.test.ts +87 -87
  56. package/tests/unit/MarkdownEditor/jsx-block-widget.test.ts +51 -51
  57. package/tests/unit/MarkdownEditor/jsx-tag-grammar.test.ts +63 -63
  58. package/tests/unit/MarkdownEditor/list-indent.test.ts +67 -67
  59. package/tests/unit/MarkdownEditor/slash-commands.test.ts +150 -150
  60. package/tests/unit/MarkdownEditor/table-format.test.ts +67 -67
  61. package/tests/unit/MarkdownEditor/table.test.ts +96 -96
  62. package/tests/unit/MarkdownEditor/triggers.test.ts +167 -167
  63. package/tests/unit/MarkdownEditor/widget-store.test.ts +90 -90
  64. package/tests/unit/MarkdownViewer/callout.test.tsx +42 -42
  65. package/tests/unit/MarkdownViewer/code-highlight.test.tsx +41 -41
  66. package/tests/unit/MarkdownViewer/code-title.test.tsx +45 -45
  67. package/tests/unit/MarkdownViewer/features.test.tsx +129 -129
  68. package/tests/unit/MarkdownViewer/headings.test.tsx +28 -28
  69. package/tests/unit/MarkdownViewer/indented-jsx-children.test.tsx +53 -53
  70. package/tests/unit/MarkdownViewer/jsx-block-nesting.test.tsx +137 -137
  71. package/tests/unit/MarkdownViewer/jsx.test.tsx +188 -188
  72. package/tests/unit/MarkdownViewer/list-bullets.test.tsx +31 -31
  73. package/tests/unit/MarkdownViewer/list-code.test.tsx +45 -45
  74. package/tests/unit/MarkdownViewer/preserve-newlines.test.tsx +109 -109
  75. package/tests/unit/MarkdownViewer/read-time.test.ts +13 -13
  76. package/tests/unit/MarkdownViewer/renderers.test.tsx +75 -75
  77. package/tests/unit/MarkdownViewer/runnable.test.tsx +51 -51
  78. package/tests/unit/MarkdownViewer/ssr.test.tsx +56 -55
  79. package/tests/unit/MarkdownViewer/syntax-highlighting.test.tsx +43 -42
  80. package/tests/unit/MarkdownViewer/tabs-fenced-code.test.tsx +120 -120
  81. package/tests/unit/MarkdownViewer/tabs.test.tsx +83 -82
  82. package/tests/unit/Stacker/drag.test.ts +21 -0
  83. package/tests/unit/Stacker/helpers.test.ts +105 -0
  84. package/tests/unit/Stacker/reducer.test.ts +107 -0
  85. package/tools/duplicate-vector-mappings.json +141 -141
  86. package/tools/glass-export-overrides.json +6 -6
  87. package/tools/icon-parser.ts +41 -40
  88. package/tools/integration-gradient-exports.json +55 -55
  89. package/tools/picto-compare.ts +32 -32
  90. package/tools/picto-merge-urls.ts +19 -19
  91. package/tools/picto-sync.ts +543 -543
  92. package/tools/picto-verify-gradients.ts +50 -50
  93. package/tools/vector-export-nodes.json +975 -975
@@ -7,205 +7,205 @@ import { renderToString } from "react-dom/server";
7
7
  import { beforeAll, describe, expect, it } from "vitest";
8
8
 
9
9
  beforeAll(() => {
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
- }
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
- return renderToString(
29
- <MantineProvider
30
- theme={MANTINE_THEME}
31
- cssVariablesResolver={v8CssVariablesResolver}
32
- forceColorScheme="dark"
33
- >
34
- {node}
35
- </MantineProvider>,
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
  describe("MarkdownViewer / JSX and HTML", () => {
40
- it("renders a JSX component when jsxMode is render", () => {
41
- const html = shell(<MarkdownViewer content={'<Since v="2.0.0" />'} />);
42
- expect(html).toContain("2.0.0");
43
- expect(html).not.toContain("<Since");
44
- });
45
-
46
- it("shows graceful fallback when jsxMode is graceful and component is missing", () => {
47
- const html = shell(
48
- <MarkdownViewer
49
- content="<UnknownComponent />"
50
- jsxMode="graceful"
51
- />,
52
- );
53
- expect(html).toContain("unsupported JSX");
54
- });
55
-
56
- it("parses JSON attribute values on JSX components", () => {
57
- function ValueEcho({ value }: { value: unknown }) {
58
- return <span data-value={JSON.stringify(value)} />;
59
- }
60
-
61
- const html = shell(
62
- <MarkdownViewer
63
- content={"<ValueEcho value={42} />"}
64
- jsxMode="render"
65
- components={{ ValueEcho }}
66
- />,
67
- );
68
- expect(html).toContain("data-value");
69
- expect(html).toContain("42");
70
- });
71
-
72
- it("leaves inline brace text as plain text", () => {
73
- const html = shell(<MarkdownViewer content="Count: {count}" />);
74
- expect(html).toContain("{count}");
75
- });
76
-
77
- it("renders details/summary HTML blocks", () => {
78
- const html = shell(
79
- <MarkdownViewer
80
- content={`<details>
40
+ it("renders a JSX component when jsxMode is render", () => {
41
+ const html = shell(<MarkdownViewer content={'<Since v="2.0.0" />'} />);
42
+ expect(html).toContain("2.0.0");
43
+ expect(html).not.toContain("<Since");
44
+ });
45
+
46
+ it("shows graceful fallback when jsxMode is graceful and component is missing", () => {
47
+ const html = shell(
48
+ <MarkdownViewer
49
+ content="<UnknownComponent />"
50
+ jsxMode="graceful"
51
+ />,
52
+ );
53
+ expect(html).toContain("unsupported JSX");
54
+ });
55
+
56
+ it("parses JSON attribute values on JSX components", () => {
57
+ function ValueEcho({ value }: { value: unknown }) {
58
+ return <span data-value={JSON.stringify(value)} />;
59
+ }
60
+
61
+ const html = shell(
62
+ <MarkdownViewer
63
+ content={"<ValueEcho value={42} />"}
64
+ jsxMode="render"
65
+ components={{ ValueEcho }}
66
+ />,
67
+ );
68
+ expect(html).toContain("data-value");
69
+ expect(html).toContain("42");
70
+ });
71
+
72
+ it("leaves inline brace text as plain text", () => {
73
+ const html = shell(<MarkdownViewer content="Count: {count}" />);
74
+ expect(html).toContain("{count}");
75
+ });
76
+
77
+ it("renders details/summary HTML blocks", () => {
78
+ const html = shell(
79
+ <MarkdownViewer
80
+ content={`<details>
81
81
  <summary>Toggle</summary>
82
82
 
83
83
  Hidden **bold** text
84
84
 
85
85
  </details>`}
86
- jsxMode="render"
87
- />,
88
- );
89
- expect(html).toContain("Toggle");
90
- expect(html).toContain("bold");
91
- });
92
-
93
- it("extractHeadings returns h2 and h3 slugs", () => {
94
- const source = "## Section\n\n### Sub\n";
95
- const tree = parseMarkdownTree(source);
96
- const headings = extractHeadings(tree, markdownSourceFromString(source));
97
- expect(headings).toHaveLength(2);
98
- expect(headings[0]?.text).toBe("Section");
99
- expect(headings[1]?.text).toBe("Sub");
100
- });
101
-
102
- it("onResolveMedia rewrites image src", () => {
103
- const html = shell(
104
- <MarkdownViewer
105
- content='<img src="@ui/pictoAI" />'
106
- jsxMode="render"
107
- onResolveMedia={(node) => ({ ...node, src: "https://example.com/resolved.png" })}
108
- />,
109
- );
110
- expect(html).toContain("https://example.com/resolved.png");
111
- });
112
-
113
- it("renders inline paired HTML anchor without duplicating link text", () => {
114
- const html = shell(
115
- <MarkdownViewer content={'Visit <a href="https://example.com">link text</a> here.'} />,
116
- );
117
- const matches = html.match(/link text/g) ?? [];
118
- expect(matches).toHaveLength(1);
119
- });
120
-
121
- it("throws when jsxMode is throw and a JSX component is unsupported", () => {
122
- expect(() =>
123
- shell(
124
- <MarkdownViewer
125
- content="<Foo />"
126
- jsxMode="throw"
127
- />,
128
- ),
129
- ).toThrow(/Unsupported JSX component <Foo \/>/);
130
- });
131
-
132
- it("omits unsupported JSX when jsxMode is omit", () => {
133
- const html = shell(
134
- <MarkdownViewer
135
- content="<Unknown />"
136
- jsxMode="omit"
137
- />,
138
- );
139
- expect(html).not.toContain("unsupported");
140
- expect(html).not.toContain("Unsupported JSX");
141
- });
142
-
143
- it("adds heading id and autolink anchor by default", () => {
144
- const html = shell(<MarkdownViewer content="## Hello" />);
145
- expect(html).toMatch(/id="hello"/);
146
- expect(html).toContain('href="#hello"');
147
- });
148
-
149
- it("renders the same output when tree and source are passed via tree prop", () => {
150
- const content = "# Tree prop\n\nParagraph body.";
151
- const tree = parseMarkdownTree(content);
152
- const source = markdownSourceFromString(content);
153
- const fromTree = shell(<MarkdownViewer tree={{ tree, source }} />);
154
- const fromContent = shell(<MarkdownViewer content={content} />);
155
- expect(fromTree).toBe(fromContent);
156
- });
157
-
158
- it("uses paragraph renderer override when provided", () => {
159
- const html = shell(
160
- <MarkdownViewer
161
- content="Custom paragraph."
162
- renderers={{
163
- paragraph: () => <span data-custom-paragraph>PARAGRAPH_MARKER</span>,
164
- }}
165
- />,
166
- );
167
- expect(html).toContain("PARAGRAPH_MARKER");
168
- expect(html).not.toContain("Custom paragraph.");
169
- });
170
-
171
- it("renders multi-line paragraph JSX tags", () => {
172
- const html = shell(<MarkdownViewer content={'<Since\n v="2.0.0"\n/>'} />);
173
- expect(html).toContain("2.0.0");
174
- expect(html).not.toContain("<Since");
175
- });
176
-
177
- it("renders multiple JSX components on one line", () => {
178
- const html = shell(
179
- <MarkdownViewer content={'<Label label="Required" /><Label label="Optional" />'} />,
180
- );
181
- expect(html.match(/mantine-Badge-label/g)?.length).toBe(2);
182
- expect(html).toContain("Required");
183
- expect(html).toContain("Optional");
184
- });
185
-
186
- it("renders inline HTML on separate source lines with line breaks", () => {
187
- const html = shell(
188
- <MarkdownViewer
189
- content={`<span>foo</span> <span>bar</span>
86
+ jsxMode="render"
87
+ />,
88
+ );
89
+ expect(html).toContain("Toggle");
90
+ expect(html).toContain("bold");
91
+ });
92
+
93
+ it("extractHeadings returns h2 and h3 slugs", () => {
94
+ const source = "## Section\n\n### Sub\n";
95
+ const tree = parseMarkdownTree(source);
96
+ const headings = extractHeadings(tree, markdownSourceFromString(source));
97
+ expect(headings).toHaveLength(2);
98
+ expect(headings[0]?.text).toBe("Section");
99
+ expect(headings[1]?.text).toBe("Sub");
100
+ });
101
+
102
+ it("onResolveMedia rewrites image src", () => {
103
+ const html = shell(
104
+ <MarkdownViewer
105
+ content='<img src="@ui/pictoAI" />'
106
+ jsxMode="render"
107
+ onResolveMedia={(node) => ({ ...node, src: "https://example.com/resolved.png" })}
108
+ />,
109
+ );
110
+ expect(html).toContain("https://example.com/resolved.png");
111
+ });
112
+
113
+ it("renders inline paired HTML anchor without duplicating link text", () => {
114
+ const html = shell(
115
+ <MarkdownViewer content={'Visit <a href="https://example.com">link text</a> here.'} />,
116
+ );
117
+ const matches = html.match(/link text/g) ?? [];
118
+ expect(matches).toHaveLength(1);
119
+ });
120
+
121
+ it("throws when jsxMode is throw and a JSX component is unsupported", () => {
122
+ expect(() =>
123
+ shell(
124
+ <MarkdownViewer
125
+ content="<Foo />"
126
+ jsxMode="throw"
127
+ />,
128
+ ),
129
+ ).toThrow(/Unsupported JSX component <Foo \/>/);
130
+ });
131
+
132
+ it("omits unsupported JSX when jsxMode is omit", () => {
133
+ const html = shell(
134
+ <MarkdownViewer
135
+ content="<Unknown />"
136
+ jsxMode="omit"
137
+ />,
138
+ );
139
+ expect(html).not.toContain("unsupported");
140
+ expect(html).not.toContain("Unsupported JSX");
141
+ });
142
+
143
+ it("adds heading id and autolink anchor by default", () => {
144
+ const html = shell(<MarkdownViewer content="## Hello" />);
145
+ expect(html).toMatch(/id="hello"/);
146
+ expect(html).toContain('href="#hello"');
147
+ });
148
+
149
+ it("renders the same output when tree and source are passed via tree prop", () => {
150
+ const content = "# Tree prop\n\nParagraph body.";
151
+ const tree = parseMarkdownTree(content);
152
+ const source = markdownSourceFromString(content);
153
+ const fromTree = shell(<MarkdownViewer tree={{ tree, source }} />);
154
+ const fromContent = shell(<MarkdownViewer content={content} />);
155
+ expect(fromTree).toBe(fromContent);
156
+ });
157
+
158
+ it("uses paragraph renderer override when provided", () => {
159
+ const html = shell(
160
+ <MarkdownViewer
161
+ content="Custom paragraph."
162
+ renderers={{
163
+ paragraph: () => <span data-custom-paragraph>PARAGRAPH_MARKER</span>,
164
+ }}
165
+ />,
166
+ );
167
+ expect(html).toContain("PARAGRAPH_MARKER");
168
+ expect(html).not.toContain("Custom paragraph.");
169
+ });
170
+
171
+ it("renders multi-line paragraph JSX tags", () => {
172
+ const html = shell(<MarkdownViewer content={'<Since\n v="2.0.0"\n/>'} />);
173
+ expect(html).toContain("2.0.0");
174
+ expect(html).not.toContain("<Since");
175
+ });
176
+
177
+ it("renders multiple JSX components on one line", () => {
178
+ const html = shell(
179
+ <MarkdownViewer content={'<Label label="Required" /><Label label="Optional" />'} />,
180
+ );
181
+ expect(html.match(/mantine-Badge-label/g)?.length).toBe(2);
182
+ expect(html).toContain("Required");
183
+ expect(html).toContain("Optional");
184
+ });
185
+
186
+ it("renders inline HTML on separate source lines with line breaks", () => {
187
+ const html = shell(
188
+ <MarkdownViewer
189
+ content={`<span>foo</span> <span>bar</span>
190
190
  <span>hello</span>
191
191
  <span>world</span>`}
192
- />,
193
- );
194
- expect(html).toContain("foo");
195
- expect(html).toContain("bar");
196
- expect(html).toContain("hello");
197
- expect(html).toContain("world");
198
- expect(html.match(/<br\s*\/?>/g)?.length).toBe(2);
199
- });
200
-
201
- it("renders jsx-only paragraphs on separate lines as separate p elements", () => {
202
- const html = shell(
203
- <MarkdownViewer
204
- content={'<Since v="1.5.0" />\n\n<Since v="2.0.0" prefix="Available since" />'}
205
- />,
206
- );
207
- expect(html.match(/mantine-Badge-label/g)?.length).toBe(2);
208
- const paragraphs = html.match(/<p[^>]*>[\s\S]*?<\/p>/g) ?? [];
209
- expect(paragraphs.length).toBeGreaterThanOrEqual(2);
210
- });
192
+ />,
193
+ );
194
+ expect(html).toContain("foo");
195
+ expect(html).toContain("bar");
196
+ expect(html).toContain("hello");
197
+ expect(html).toContain("world");
198
+ expect(html.match(/<br\s*\/?>/g)?.length).toBe(2);
199
+ });
200
+
201
+ it("renders jsx-only paragraphs on separate lines as separate p elements", () => {
202
+ const html = shell(
203
+ <MarkdownViewer
204
+ content={'<Since v="1.5.0" />\n\n<Since v="2.0.0" prefix="Available since" />'}
205
+ />,
206
+ );
207
+ expect(html.match(/mantine-Badge-label/g)?.length).toBe(2);
208
+ const paragraphs = html.match(/<p[^>]*>[\s\S]*?<\/p>/g) ?? [];
209
+ expect(paragraphs.length).toBeGreaterThanOrEqual(2);
210
+ });
211
211
  });
@@ -7,43 +7,43 @@ import { renderToString } from "react-dom/server";
7
7
  import { describe, expect, it } from "vitest";
8
8
 
9
9
  function shell(node: ReactElement): string {
10
- return renderToString(
11
- <MantineProvider
12
- theme={MANTINE_THEME}
13
- cssVariablesResolver={v8CssVariablesResolver}
14
- forceColorScheme="dark"
15
- >
16
- {node}
17
- </MantineProvider>,
18
- );
10
+ return renderToString(
11
+ <MantineProvider
12
+ theme={MANTINE_THEME}
13
+ cssVariablesResolver={v8CssVariablesResolver}
14
+ forceColorScheme="dark"
15
+ >
16
+ {node}
17
+ </MantineProvider>,
18
+ );
19
19
  }
20
20
 
21
21
  describe("unorderedBulletForDepth", () => {
22
- it("cycles through bullet, circle, square by depth", () => {
23
- expect(unorderedBulletForDepth(0)).toBe("•");
24
- expect(unorderedBulletForDepth(1)).toBe("◦");
25
- expect(unorderedBulletForDepth(2)).toBe("▪");
26
- });
22
+ it("cycles through bullet, circle, square by depth", () => {
23
+ expect(unorderedBulletForDepth(0)).toBe("•");
24
+ expect(unorderedBulletForDepth(1)).toBe("◦");
25
+ expect(unorderedBulletForDepth(2)).toBe("▪");
26
+ });
27
27
 
28
- it("repeats the sequence for deeper nesting", () => {
29
- expect(unorderedBulletForDepth(3)).toBe("•");
30
- expect(unorderedBulletForDepth(4)).toBe("◦");
31
- expect(unorderedBulletForDepth(5)).toBe("▪");
32
- });
28
+ it("repeats the sequence for deeper nesting", () => {
29
+ expect(unorderedBulletForDepth(3)).toBe("•");
30
+ expect(unorderedBulletForDepth(4)).toBe("◦");
31
+ expect(unorderedBulletForDepth(5)).toBe("▪");
32
+ });
33
33
  });
34
34
 
35
35
  describe("MarkdownViewer / nested list bullets", () => {
36
- it("renders distinct glyphs per nesting level", () => {
37
- const content = ["- top", " - second", " - third"].join("\n");
38
- const html = shell(<MarkdownViewer content={content} />);
39
- expect(html).toContain("•");
40
- expect(html).toContain("◦");
41
- expect(html).toContain("▪");
42
- });
36
+ it("renders distinct glyphs per nesting level", () => {
37
+ const content = ["- top", " - second", " - third"].join("\n");
38
+ const html = shell(<MarkdownViewer content={content} />);
39
+ expect(html).toContain("•");
40
+ expect(html).toContain("◦");
41
+ expect(html).toContain("▪");
42
+ });
43
43
 
44
- it("keeps ordered list markers as numbers regardless of depth", () => {
45
- const content = ["1. top", " 1. nested"].join("\n");
46
- const html = shell(<MarkdownViewer content={content} />);
47
- expect(html).not.toContain("◦");
48
- });
44
+ it("keeps ordered list markers as numbers regardless of depth", () => {
45
+ const content = ["1. top", " 1. nested"].join("\n");
46
+ const html = shell(<MarkdownViewer content={content} />);
47
+ expect(html).not.toContain("◦");
48
+ });
49
49
  });
@@ -6,60 +6,60 @@ import { renderToString } from "react-dom/server";
6
6
  import { beforeAll, describe, expect, it } from "vitest";
7
7
 
8
8
  beforeAll(() => {
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
- }
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
- return renderToString(
28
- <MantineProvider
29
- theme={MANTINE_THEME}
30
- cssVariablesResolver={v8CssVariablesResolver}
31
- forceColorScheme="dark"
32
- >
33
- {node}
34
- </MantineProvider>,
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
  // Syntax highlighting splits a line into per-token spans, so assert on single
39
39
  // identifier tokens that survive tokenisation rather than whole expressions.
40
40
  describe("MarkdownViewer / code inside lists", () => {
41
- it("renders a fenced code block nested in a list item", () => {
42
- const content = ["- Item with code:", " ```js", " alphaVar;", " ```"].join("\n");
43
- const html = shell(<MarkdownViewer content={content} />);
44
- expect(html).toContain("alphaVar");
45
- });
41
+ it("renders a fenced code block nested in a list item", () => {
42
+ const content = ["- Item with code:", " ```js", " alphaVar;", " ```"].join("\n");
43
+ const html = shell(<MarkdownViewer content={content} />);
44
+ expect(html).toContain("alphaVar");
45
+ });
46
46
 
47
- it("renders multiple code lines nested in a list item", () => {
48
- const content = ["- Item:", " ```js", " alphaVar;", " betaVar;", " ```"].join("\n");
49
- const html = shell(<MarkdownViewer content={content} />);
50
- expect(html).toContain("alphaVar");
51
- expect(html).toContain("betaVar");
52
- });
47
+ it("renders multiple code lines nested in a list item", () => {
48
+ const content = ["- Item:", " ```js", " alphaVar;", " betaVar;", " ```"].join("\n");
49
+ const html = shell(<MarkdownViewer content={content} />);
50
+ expect(html).toContain("alphaVar");
51
+ expect(html).toContain("betaVar");
52
+ });
53
53
 
54
- it("renders a code block that is the first child of a list item", () => {
55
- const content = ["- ```ts", " codeFirstVar;", " ```"].join("\n");
56
- const html = shell(<MarkdownViewer content={content} />);
57
- expect(html).toContain("codeFirstVar");
58
- });
54
+ it("renders a code block that is the first child of a list item", () => {
55
+ const content = ["- ```ts", " codeFirstVar;", " ```"].join("\n");
56
+ const html = shell(<MarkdownViewer content={content} />);
57
+ expect(html).toContain("codeFirstVar");
58
+ });
59
59
 
60
- it("renders a fenced code block inside a task list item", () => {
61
- const content = ["- [ ] Task with code", " ```js", " taskCodeVar;", " ```"].join("\n");
62
- const html = shell(<MarkdownViewer content={content} />);
63
- expect(html).toContain("taskCodeVar");
64
- });
60
+ it("renders a fenced code block inside a task list item", () => {
61
+ const content = ["- [ ] Task with code", " ```js", " taskCodeVar;", " ```"].join("\n");
62
+ const html = shell(<MarkdownViewer content={content} />);
63
+ expect(html).toContain("taskCodeVar");
64
+ });
65
65
  });