@surrealdb/ui 1.2.11 → 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 (101) 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/assets/245b1ccaa4927818.svg +3 -0
  8. package/dist/assets/333e1fe6e67ca4a2.svg +10 -0
  9. package/dist/assets/4b0e10c655814886.svg +21 -0
  10. package/dist/assets/9932da008ea5dd32.svg +3 -0
  11. package/dist/assets/a372168d5789daa2.svg +4 -0
  12. package/dist/assets/b140e44ee4ae7e35.svg +5 -0
  13. package/dist/assets/e028075817d928e4.svg +3 -0
  14. package/dist/assets/ee1065ad5a8f7f14.svg +6 -0
  15. package/dist/ui.css +1 -1
  16. package/dist/ui.d.ts +579 -1
  17. package/dist/ui.js +11553 -8988
  18. package/dist/ui.js.map +1 -1
  19. package/doc/code-style.md +264 -0
  20. package/doc/stacker-plan.md +219 -0
  21. package/package.json +119 -115
  22. package/res/_mixins.scss +15 -11
  23. package/tests/_setup/e2e-helpers.tsx +85 -85
  24. package/tests/_setup/portable-stories.ts +11 -10
  25. package/tests/e2e/MarkdownEditor/content-blocks.test.tsx +140 -139
  26. package/tests/e2e/MarkdownEditor/edits.test.tsx +101 -100
  27. package/tests/e2e/MarkdownEditor/heading-fold.test.tsx +35 -34
  28. package/tests/e2e/MarkdownEditor/hybrid-widgets.test.tsx +178 -177
  29. package/tests/e2e/MarkdownEditor/image-on-image.test.tsx +50 -49
  30. package/tests/e2e/MarkdownEditor/jsx-block-content.test.tsx +195 -194
  31. package/tests/e2e/MarkdownEditor/jsx-highlight.test.tsx +47 -46
  32. package/tests/e2e/MarkdownEditor/jsx-inline-badges.test.tsx +35 -34
  33. package/tests/e2e/MarkdownEditor/jsx-inline-click.test.tsx +39 -38
  34. package/tests/e2e/MarkdownEditor/jsx-selection.test.tsx +28 -27
  35. package/tests/e2e/MarkdownEditor/link-placeholder.test.tsx +49 -48
  36. package/tests/e2e/MarkdownEditor/media-align.test.tsx +40 -39
  37. package/tests/e2e/MarkdownEditor/media-edit.test.tsx +49 -48
  38. package/tests/e2e/MarkdownEditor/media-sizing.test.tsx +108 -107
  39. package/tests/e2e/MarkdownEditor/modes.test.tsx +79 -78
  40. package/tests/e2e/MarkdownEditor/onimage-parity.test.tsx +29 -28
  41. package/tests/e2e/MarkdownEditor/regressions.test.tsx +194 -193
  42. package/tests/e2e/MarkdownEditor/slash-commands.test.tsx +81 -80
  43. package/tests/e2e/MarkdownEditor/table-click.test.tsx +36 -35
  44. package/tests/e2e/MarkdownEditor/table-controls.test.tsx +44 -43
  45. package/tests/e2e/MarkdownEditor/table-format.test.tsx +28 -27
  46. package/tests/e2e/MarkdownEditor/undo-redo.test.tsx +22 -21
  47. package/tests/e2e/MarkdownViewer/parity.test.tsx +144 -143
  48. package/tests/e2e/MarkdownViewer/render.test.tsx +20 -19
  49. package/tests/e2e/Stacker/stacker.test.tsx +304 -0
  50. package/tests/unit/Editor/helpers.test.ts +26 -26
  51. package/tests/unit/MarkdownConformance/error-isolation.test.tsx +26 -25
  52. package/tests/unit/MarkdownConformance/indentation.test.tsx +20 -19
  53. package/tests/unit/MarkdownConformance/inline-code-fuzz.test.tsx +255 -0
  54. package/tests/unit/MarkdownConformance/jsx-attributes.test.tsx +39 -38
  55. package/tests/unit/MarkdownConformance/jsx-fuzz.test.tsx +122 -122
  56. package/tests/unit/MarkdownConformance/links.test.tsx +78 -54
  57. package/tests/unit/MarkdownConformance/render-helpers.tsx +60 -60
  58. package/tests/unit/MarkdownEditor/code-info.test.ts +58 -58
  59. package/tests/unit/MarkdownEditor/decorations.test.ts +423 -421
  60. package/tests/unit/MarkdownEditor/editor-ready.test.ts +22 -22
  61. package/tests/unit/MarkdownEditor/html-descriptors.test.ts +70 -70
  62. package/tests/unit/MarkdownEditor/indented-fence.test.ts +80 -80
  63. package/tests/unit/MarkdownEditor/jsx-attr-scan.test.ts +87 -87
  64. package/tests/unit/MarkdownEditor/jsx-block-widget.test.ts +51 -51
  65. package/tests/unit/MarkdownEditor/jsx-tag-grammar.test.ts +63 -63
  66. package/tests/unit/MarkdownEditor/list-indent.test.ts +67 -67
  67. package/tests/unit/MarkdownEditor/slash-commands.test.ts +150 -150
  68. package/tests/unit/MarkdownEditor/table-format.test.ts +67 -67
  69. package/tests/unit/MarkdownEditor/table.test.ts +96 -96
  70. package/tests/unit/MarkdownEditor/triggers.test.ts +167 -167
  71. package/tests/unit/MarkdownEditor/widget-store.test.ts +90 -90
  72. package/tests/unit/MarkdownViewer/callout.test.tsx +42 -42
  73. package/tests/unit/MarkdownViewer/code-highlight.test.tsx +41 -41
  74. package/tests/unit/MarkdownViewer/code-title.test.tsx +45 -45
  75. package/tests/unit/MarkdownViewer/features.test.tsx +129 -129
  76. package/tests/unit/MarkdownViewer/headings.test.tsx +28 -28
  77. package/tests/unit/MarkdownViewer/indented-jsx-children.test.tsx +53 -53
  78. package/tests/unit/MarkdownViewer/jsx-block-nesting.test.tsx +137 -137
  79. package/tests/unit/MarkdownViewer/jsx.test.tsx +188 -188
  80. package/tests/unit/MarkdownViewer/list-bullets.test.tsx +31 -31
  81. package/tests/unit/MarkdownViewer/list-code.test.tsx +45 -45
  82. package/tests/unit/MarkdownViewer/preserve-newlines.test.tsx +109 -109
  83. package/tests/unit/MarkdownViewer/read-time.test.ts +13 -13
  84. package/tests/unit/MarkdownViewer/renderers.test.tsx +75 -75
  85. package/tests/unit/MarkdownViewer/runnable.test.tsx +51 -51
  86. package/tests/unit/MarkdownViewer/ssr.test.tsx +56 -55
  87. package/tests/unit/MarkdownViewer/syntax-highlighting.test.tsx +43 -42
  88. package/tests/unit/MarkdownViewer/tabs-fenced-code.test.tsx +120 -120
  89. package/tests/unit/MarkdownViewer/tabs.test.tsx +83 -82
  90. package/tests/unit/Stacker/drag.test.ts +21 -0
  91. package/tests/unit/Stacker/helpers.test.ts +105 -0
  92. package/tests/unit/Stacker/reducer.test.ts +107 -0
  93. package/tools/duplicate-vector-mappings.json +141 -141
  94. package/tools/glass-export-overrides.json +6 -6
  95. package/tools/icon-parser.ts +41 -40
  96. package/tools/integration-gradient-exports.json +55 -55
  97. package/tools/picto-compare.ts +32 -32
  98. package/tools/picto-merge-urls.ts +19 -19
  99. package/tools/picto-sync.ts +543 -543
  100. package/tools/picto-verify-gradients.ts +50 -50
  101. package/tools/vector-export-nodes.json +975 -975
@@ -7,33 +7,33 @@ 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
  /**
@@ -42,40 +42,40 @@ function shell(node: ReactElement): string {
42
42
  * `renderToString` assert the full parsed structure of all tab bodies.
43
43
  */
44
44
  function EagerGroup({ children }: { children?: ReactNode }): ReactElement {
45
- const items = Children.toArray(children).filter(isValidElement);
46
- return (
47
- <div data-eager-group>
48
- <div
49
- data-labels={items.map((el) => (el.props as { label?: string }).label).join("|")}
50
- />
51
- {items.map((el, i) => (
52
- <section
53
- data-panel={i}
54
- key={(el.props as { label?: string }).label ?? i}
55
- >
56
- {(el.props as { children?: ReactNode }).children}
57
- </section>
58
- ))}
59
- </div>
60
- );
45
+ const items = Children.toArray(children).filter(isValidElement);
46
+ return (
47
+ <div data-eager-group>
48
+ <div
49
+ data-labels={items.map((el) => (el.props as { label?: string }).label).join("|")}
50
+ />
51
+ {items.map((el, i) => (
52
+ <section
53
+ data-panel={i}
54
+ key={(el.props as { label?: string }).label ?? i}
55
+ >
56
+ {(el.props as { children?: ReactNode }).children}
57
+ </section>
58
+ ))}
59
+ </div>
60
+ );
61
61
  }
62
62
 
63
63
  function EagerItem({ children }: { children?: ReactNode }): ReactElement {
64
- return <>{children}</>;
64
+ return <>{children}</>;
65
65
  }
66
66
 
67
67
  const EAGER_COMPONENTS: MarkdownComponents = {
68
- Tabs: { component: EagerGroup, block: true },
69
- TabItem: { component: EagerItem, block: true },
68
+ Tabs: { component: EagerGroup, block: true },
69
+ TabItem: { component: EagerItem, block: true },
70
70
  };
71
71
 
72
72
  function stripTags(html: string): string {
73
- return html.replace(/<[^>]+>/g, "");
73
+ return html.replace(/<[^>]+>/g, "");
74
74
  }
75
75
 
76
76
  describe("MarkdownViewer / JSX block nesting", () => {
77
- it("pairs a Tabs block into exactly its authored TabItems (no synthetic tabs)", () => {
78
- const content = `<Tabs syncKey="demo">
77
+ it("pairs a Tabs block into exactly its authored TabItems (no synthetic tabs)", () => {
78
+ const content = `<Tabs syncKey="demo">
79
79
  <TabItem label="Create an instance">
80
80
  \tSurrealDB Cloud allows you to connect.
81
81
 
@@ -89,24 +89,24 @@ describe("MarkdownViewer / JSX block nesting", () => {
89
89
  \tSince SurrealDB Cloud is closely integrated.
90
90
  </TabItem>
91
91
  </Tabs>`;
92
- const html = shell(<MarkdownViewer content={content} />);
93
-
94
- // Exactly two tab buttons with the authored labels — no paragraphs
95
- // leaking out as extra "Tab N" children.
96
- const tabButtons = html.match(/mantine-Tabs-tab\b/g) ?? [];
97
- expect(tabButtons).toHaveLength(2);
98
- const labels = [...html.matchAll(/mantine-Tabs-tabLabel">([^<]*)</g)].map((m) => m[1]);
99
- expect(labels).toEqual(["Create an instance", "Connect to your instance"]);
100
-
101
- // The active tab renders its full multi-paragraph markdown body.
102
- const text = stripTags(html);
103
- expect(text).toContain("SurrealDB Cloud allows you to connect.");
104
- expect(text).toContain("1. Create Instance.");
105
- expect(text).toContain("When creating an instance");
106
- });
107
-
108
- it("renders full multi-paragraph markdown for every TabItem (via eager group)", () => {
109
- const content = `<Tabs syncKey="demo">
92
+ const html = shell(<MarkdownViewer content={content} />);
93
+
94
+ // Exactly two tab buttons with the authored labels — no paragraphs
95
+ // leaking out as extra "Tab N" children.
96
+ const tabButtons = html.match(/mantine-Tabs-tab\b/g) ?? [];
97
+ expect(tabButtons).toHaveLength(2);
98
+ const labels = [...html.matchAll(/mantine-Tabs-tabLabel">([^<]*)</g)].map((m) => m[1]);
99
+ expect(labels).toEqual(["Create an instance", "Connect to your instance"]);
100
+
101
+ // The active tab renders its full multi-paragraph markdown body.
102
+ const text = stripTags(html);
103
+ expect(text).toContain("SurrealDB Cloud allows you to connect.");
104
+ expect(text).toContain("1. Create Instance.");
105
+ expect(text).toContain("When creating an instance");
106
+ });
107
+
108
+ it("renders full multi-paragraph markdown for every TabItem (via eager group)", () => {
109
+ const content = `<Tabs syncKey="demo">
110
110
  <TabItem label="Create an instance">
111
111
  \tSurrealDB Cloud allows you to connect.
112
112
 
@@ -122,30 +122,30 @@ describe("MarkdownViewer / JSX block nesting", () => {
122
122
  \tSince SurrealDB Cloud is closely integrated.
123
123
  </TabItem>
124
124
  </Tabs>`;
125
- const html = shell(
126
- <MarkdownViewer
127
- content={content}
128
- components={EAGER_COMPONENTS}
129
- />,
130
- );
131
-
132
- expect(html).toContain('data-labels="Create an instance|Connect to your instance"');
133
- expect(html).not.toContain("Tab 2");
134
-
135
- // Both panels rendered, in order, with all their paragraphs.
136
- const text = stripTags(html);
137
- expect(text).toContain("SurrealDB Cloud allows you to connect.");
138
- expect(text).toContain("1. Create Instance.");
139
- expect(text).toContain("When creating an instance");
140
- expect(text).toContain("You can connect via Surrealist");
141
- expect(text).toContain("closely integrated");
142
- // Links inside both tabs survive.
143
- expect(html).toContain('href="/docs/x"');
144
- expect(html).toContain('href="/docs/y"');
145
- });
146
-
147
- it("renders a single-paragraph Tabs block (regression)", () => {
148
- const content = `<Tabs syncKey="s">
125
+ const html = shell(
126
+ <MarkdownViewer
127
+ content={content}
128
+ components={EAGER_COMPONENTS}
129
+ />,
130
+ );
131
+
132
+ expect(html).toContain('data-labels="Create an instance|Connect to your instance"');
133
+ expect(html).not.toContain("Tab 2");
134
+
135
+ // Both panels rendered, in order, with all their paragraphs.
136
+ const text = stripTags(html);
137
+ expect(text).toContain("SurrealDB Cloud allows you to connect.");
138
+ expect(text).toContain("1. Create Instance.");
139
+ expect(text).toContain("When creating an instance");
140
+ expect(text).toContain("You can connect via Surrealist");
141
+ expect(text).toContain("closely integrated");
142
+ // Links inside both tabs survive.
143
+ expect(html).toContain('href="/docs/x"');
144
+ expect(html).toContain('href="/docs/y"');
145
+ });
146
+
147
+ it("renders a single-paragraph Tabs block (regression)", () => {
148
+ const content = `<Tabs syncKey="s">
149
149
  <TabItem label="First">
150
150
  Alpha content.
151
151
  </TabItem>
@@ -153,21 +153,21 @@ Alpha content.
153
153
  Beta content.
154
154
  </TabItem>
155
155
  </Tabs>`;
156
- const html = shell(
157
- <MarkdownViewer
158
- content={content}
159
- components={EAGER_COMPONENTS}
160
- />,
161
- );
162
- expect(html).toContain('data-labels="First|Second"');
163
- expect(html).not.toContain("Tab 2");
164
- const text = stripTags(html);
165
- expect(text).toContain("Alpha content.");
166
- expect(text).toContain("Beta content.");
167
- });
168
-
169
- it("renders block content around a Tabs block", () => {
170
- const content = `# Heading
156
+ const html = shell(
157
+ <MarkdownViewer
158
+ content={content}
159
+ components={EAGER_COMPONENTS}
160
+ />,
161
+ );
162
+ expect(html).toContain('data-labels="First|Second"');
163
+ expect(html).not.toContain("Tab 2");
164
+ const text = stripTags(html);
165
+ expect(text).toContain("Alpha content.");
166
+ expect(text).toContain("Beta content.");
167
+ });
168
+
169
+ it("renders block content around a Tabs block", () => {
170
+ const content = `# Heading
171
171
 
172
172
  Intro paragraph.
173
173
 
@@ -181,23 +181,23 @@ Second tab.
181
181
  </Tabs>
182
182
 
183
183
  Outro paragraph.`;
184
- const html = shell(
185
- <MarkdownViewer
186
- content={content}
187
- components={EAGER_COMPONENTS}
188
- />,
189
- );
190
- const text = stripTags(html);
191
- expect(text).toContain("Heading");
192
- expect(text).toContain("Intro paragraph.");
193
- expect(text).toContain("Outro paragraph.");
194
- expect(html).toContain('data-labels="One|Two"');
195
- expect(text).toContain("First tab.");
196
- expect(text).toContain("Second tab.");
197
- });
198
-
199
- it("renders nested block components (Tabs inside a TabItem)", () => {
200
- const content = `<Tabs syncKey="outer">
184
+ const html = shell(
185
+ <MarkdownViewer
186
+ content={content}
187
+ components={EAGER_COMPONENTS}
188
+ />,
189
+ );
190
+ const text = stripTags(html);
191
+ expect(text).toContain("Heading");
192
+ expect(text).toContain("Intro paragraph.");
193
+ expect(text).toContain("Outro paragraph.");
194
+ expect(html).toContain('data-labels="One|Two"');
195
+ expect(text).toContain("First tab.");
196
+ expect(text).toContain("Second tab.");
197
+ });
198
+
199
+ it("renders nested block components (Tabs inside a TabItem)", () => {
200
+ const content = `<Tabs syncKey="outer">
201
201
  <TabItem label="Outer A">
202
202
  Outer A body.
203
203
 
@@ -214,21 +214,21 @@ Inner Y body.
214
214
  Outer B body.
215
215
  </TabItem>
216
216
  </Tabs>`;
217
- const html = shell(
218
- <MarkdownViewer
219
- content={content}
220
- components={EAGER_COMPONENTS}
221
- />,
222
- );
223
- // Outer group has exactly the two authored tabs.
224
- expect(html).toContain('data-labels="Outer A|Outer B"');
225
- // Inner group nested inside Outer A has its own two tabs.
226
- expect(html).toContain('data-labels="Inner X|Inner Y"');
227
- expect(html).not.toContain("Tab 2");
228
- const text = stripTags(html);
229
- expect(text).toContain("Outer A body.");
230
- expect(text).toContain("Outer B body.");
231
- expect(text).toContain("Inner X body.");
232
- expect(text).toContain("Inner Y body.");
233
- });
217
+ const html = shell(
218
+ <MarkdownViewer
219
+ content={content}
220
+ components={EAGER_COMPONENTS}
221
+ />,
222
+ );
223
+ // Outer group has exactly the two authored tabs.
224
+ expect(html).toContain('data-labels="Outer A|Outer B"');
225
+ // Inner group nested inside Outer A has its own two tabs.
226
+ expect(html).toContain('data-labels="Inner X|Inner Y"');
227
+ expect(html).not.toContain("Tab 2");
228
+ const text = stripTags(html);
229
+ expect(text).toContain("Outer A body.");
230
+ expect(text).toContain("Outer B body.");
231
+ expect(text).toContain("Inner X body.");
232
+ expect(text).toContain("Inner Y body.");
233
+ });
234
234
  });