@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,41 +7,41 @@ 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
  function TwoColumn({ children }: { children?: ReactNode }): ReactElement {
40
- return <div data-testid="two-column">{children}</div>;
40
+ return <div data-testid="two-column">{children}</div>;
41
41
  }
42
42
 
43
43
  function ColBox({ children }: { children?: ReactNode }): ReactElement {
44
- return <div data-testid="col-box">{children}</div>;
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
- 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
- );
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
- // 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
- });
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
- 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
- );
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
- // 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"');
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
- // 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
- });
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
- 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
- });
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
- 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
- });
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
- estimateMarkdownReadTimeMinutes,
3
- formatMarkdownReadTime,
4
- markdownToPlainText,
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
- it("strips markdown syntax for word counting", () => {
10
- expect(markdownToPlainText("# Title\n\n[link](https://example.com)")).toBe("Title link");
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
- it("estimates at least one minute", () => {
14
- expect(estimateMarkdownReadTimeMinutes("")).toBe(1);
15
- });
13
+ it("estimates at least one minute", () => {
14
+ expect(estimateMarkdownReadTimeMinutes("")).toBe(1);
15
+ });
16
16
 
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
- });
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
- 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
  describe("MarkdownViewer / MarkdownViewerRenderers", () => {
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
- });
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
- 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
- });
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
- it("uses table renderer override without the scroll wrapper", () => {
67
- const html = shell(
68
- <MarkdownViewer
69
- content={`| A | B |
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
- 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
- });
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
- it("uses image renderer override", () => {
83
- const html = shell(
84
- <MarkdownViewer
85
- content='![Alt text](https://example.com/image.png "Title")'
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
- });
82
+ it("uses image renderer override", () => {
83
+ const html = shell(
84
+ <MarkdownViewer
85
+ content='![Alt text](https://example.com/image.png "Title")'
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
- 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
  describe("MarkdownViewer / runnable code", () => {
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
- });
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
- 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
- });
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
- 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
- });
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
- 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
- });
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
  });