@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
|
@@ -3,30 +3,31 @@ import type { MarkdownComponents } from "@src/lib/markdown";
|
|
|
3
3
|
import { MarkdownEditor } from "@src/primitives/MarkdownEditor";
|
|
4
4
|
import { MANTINE_THEME } from "@src/theme/mantine";
|
|
5
5
|
import { describe, expect, it } from "vitest";
|
|
6
|
+
|
|
6
7
|
import { getEditorView, mountStory, nextFrame } from "../../_setup/e2e-helpers";
|
|
7
8
|
|
|
8
9
|
function Card({ label }: { label: string }) {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
10
|
+
return (
|
|
11
|
+
<Paper
|
|
12
|
+
withBorder
|
|
13
|
+
p="xs"
|
|
14
|
+
radius="sm"
|
|
15
|
+
mb="xs"
|
|
16
|
+
>
|
|
17
|
+
<Group gap="xs">
|
|
18
|
+
<Text size="sm">value =</Text>
|
|
19
|
+
<Text size="sm">{label}</Text>
|
|
20
|
+
</Group>
|
|
21
|
+
</Paper>
|
|
22
|
+
);
|
|
22
23
|
}
|
|
23
24
|
|
|
24
25
|
const inlineComponents: MarkdownComponents = {
|
|
25
|
-
|
|
26
|
+
Card,
|
|
26
27
|
};
|
|
27
28
|
|
|
28
29
|
const blockComponents: MarkdownComponents = {
|
|
29
|
-
|
|
30
|
+
Card: { component: Card, block: true },
|
|
30
31
|
};
|
|
31
32
|
|
|
32
33
|
const ONE_PER_LINE_DOC = `# Heading
|
|
@@ -44,199 +45,199 @@ const MANY_PER_LINE_DOC = `# Heading
|
|
|
44
45
|
`;
|
|
45
46
|
|
|
46
47
|
function renderEditor(doc: string, components: MarkdownComponents) {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
48
|
+
return (
|
|
49
|
+
<MantineProvider
|
|
50
|
+
theme={MANTINE_THEME}
|
|
51
|
+
cssVariablesResolver={v8CssVariablesResolver}
|
|
52
|
+
forceColorScheme="dark"
|
|
53
|
+
>
|
|
54
|
+
<Paper
|
|
55
|
+
p="md"
|
|
56
|
+
withBorder
|
|
57
|
+
>
|
|
58
|
+
<MarkdownEditor
|
|
59
|
+
mode="preview"
|
|
60
|
+
document={doc}
|
|
61
|
+
autoFocus={false}
|
|
62
|
+
jsxMode="render"
|
|
63
|
+
components={components}
|
|
64
|
+
/>
|
|
65
|
+
</Paper>
|
|
66
|
+
</MantineProvider>
|
|
67
|
+
);
|
|
67
68
|
}
|
|
68
69
|
|
|
69
70
|
function lineHeightsForInlineWidgets(): number[] {
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
71
|
+
const lines = Array.from(document.querySelectorAll<HTMLElement>(".cm-line"));
|
|
72
|
+
return lines
|
|
73
|
+
.filter((line) => line.querySelector('[data-md-widget="JsxInlineWidget"]'))
|
|
74
|
+
.map((line) => line.getBoundingClientRect().height);
|
|
74
75
|
}
|
|
75
76
|
|
|
76
77
|
/** Block replace widgets render between `.cm-line` rows, not inside them. */
|
|
77
78
|
function blockWidgetHostLine(widget: HTMLElement): HTMLElement | null {
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
79
|
+
let el: HTMLElement | null = widget;
|
|
80
|
+
while (el) {
|
|
81
|
+
if (el.classList.contains("cm-line")) return el;
|
|
82
|
+
el = el.parentElement;
|
|
83
|
+
}
|
|
84
|
+
return null;
|
|
84
85
|
}
|
|
85
86
|
|
|
86
87
|
async function mountPreviewEditor(doc: string, components: MarkdownComponents) {
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
88
|
+
mountStory(renderEditor(doc, components));
|
|
89
|
+
const view = await getEditorView();
|
|
90
|
+
view.contentDOM.blur();
|
|
91
|
+
await nextFrame();
|
|
92
|
+
await nextFrame();
|
|
93
|
+
return view;
|
|
93
94
|
}
|
|
94
95
|
|
|
95
96
|
describe("MarkdownEditor / inline JSX rendering block content", () => {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
97
|
+
it("does not stack cm-widgetBuffer images above and below the widget", async () => {
|
|
98
|
+
mountStory(renderEditor(ONE_PER_LINE_DOC, inlineComponents));
|
|
99
|
+
|
|
100
|
+
const view = await getEditorView();
|
|
101
|
+
view.contentDOM.blur();
|
|
102
|
+
await nextFrame();
|
|
103
|
+
await nextFrame();
|
|
104
|
+
|
|
105
|
+
const cardWidgets = document.querySelectorAll<HTMLElement>(
|
|
106
|
+
'[data-md-widget="JsxInlineWidget"]',
|
|
107
|
+
);
|
|
108
|
+
expect(cardWidgets.length).toBe(3);
|
|
109
|
+
|
|
110
|
+
const widgetHeights = Array.from(cardWidgets).map((w) => w.getBoundingClientRect().height);
|
|
111
|
+
const lineHeights = lineHeightsForInlineWidgets();
|
|
112
|
+
expect(lineHeights.length).toBe(3);
|
|
113
|
+
|
|
114
|
+
for (let i = 0; i < lineHeights.length; i++) {
|
|
115
|
+
const lineHeight = lineHeights[i] ?? 0;
|
|
116
|
+
const widgetHeight = widgetHeights[i] ?? 0;
|
|
117
|
+
expect(widgetHeight).toBeGreaterThan(0);
|
|
118
|
+
expect(lineHeight).toBeGreaterThan(0);
|
|
119
|
+
expect(lineHeight).toBeLessThan(widgetHeight + 20);
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
it("keeps multiple inline JSX widgets on the same line side-by-side", async () => {
|
|
124
|
+
mountStory(renderEditor(MANY_PER_LINE_DOC, inlineComponents));
|
|
125
|
+
|
|
126
|
+
const view = await getEditorView();
|
|
127
|
+
view.contentDOM.blur();
|
|
128
|
+
await nextFrame();
|
|
129
|
+
await nextFrame();
|
|
130
|
+
|
|
131
|
+
const cardWidgets = document.querySelectorAll<HTMLElement>(
|
|
132
|
+
'[data-md-widget="JsxInlineWidget"]',
|
|
133
|
+
);
|
|
134
|
+
expect(cardWidgets.length).toBe(3);
|
|
135
|
+
|
|
136
|
+
const rects = Array.from(cardWidgets).map((w) => w.getBoundingClientRect());
|
|
137
|
+
const firstTop = rects[0]?.top ?? 0;
|
|
138
|
+
const tolerance = 4;
|
|
139
|
+
for (const r of rects) {
|
|
140
|
+
expect(Math.abs(r.top - firstTop)).toBeLessThan(tolerance);
|
|
141
|
+
}
|
|
142
|
+
});
|
|
142
143
|
});
|
|
143
144
|
|
|
144
145
|
describe("MarkdownEditor / block JSX components", () => {
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
146
|
+
it("renders block components via JsxBlockWidget with an edit-source action", async () => {
|
|
147
|
+
await mountPreviewEditor(ONE_PER_LINE_DOC, blockComponents);
|
|
148
|
+
|
|
149
|
+
const blockWidgets = document.querySelectorAll<HTMLElement>(
|
|
150
|
+
'[data-md-widget="JsxBlockWidget"]',
|
|
151
|
+
);
|
|
152
|
+
expect(blockWidgets.length).toBe(3);
|
|
153
|
+
expect(document.querySelectorAll('[data-md-widget="JsxInlineWidget"]').length).toBe(0);
|
|
154
|
+
|
|
155
|
+
const editButtons = document.querySelectorAll<HTMLButtonElement>(
|
|
156
|
+
'[aria-label="Edit source"]',
|
|
157
|
+
);
|
|
158
|
+
expect(editButtons.length).toBeGreaterThanOrEqual(3);
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
it("renders block widgets between cm-lines, not inside a cm-line", async () => {
|
|
162
|
+
await mountPreviewEditor(ONE_PER_LINE_DOC, blockComponents);
|
|
163
|
+
|
|
164
|
+
expect(document.querySelectorAll(".jsx-block-line-host").length).toBe(0);
|
|
165
|
+
|
|
166
|
+
for (const widget of Array.from(
|
|
167
|
+
document.querySelectorAll<HTMLElement>('[data-md-widget="JsxBlockWidget"]'),
|
|
168
|
+
)) {
|
|
169
|
+
expect(blockWidgetHostLine(widget)).toBeNull();
|
|
170
|
+
const lineSibling = widget.closest(".cm-line");
|
|
171
|
+
expect(lineSibling).toBeNull();
|
|
172
|
+
}
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
it("block widgets do not get cm-widgetBuffer spacer images", async () => {
|
|
176
|
+
await mountPreviewEditor(ONE_PER_LINE_DOC, blockComponents);
|
|
177
|
+
|
|
178
|
+
for (const widget of Array.from(
|
|
179
|
+
document.querySelectorAll<HTMLElement>('[data-md-widget="JsxBlockWidget"]'),
|
|
180
|
+
)) {
|
|
181
|
+
const parent = widget.parentElement;
|
|
182
|
+
expect(parent?.querySelector("img.cm-widgetBuffer")).toBeNull();
|
|
183
|
+
}
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
it("clicking the edit-source action selects the component source range", async () => {
|
|
187
|
+
const view = await mountPreviewEditor(ONE_PER_LINE_DOC, blockComponents);
|
|
188
|
+
|
|
189
|
+
const editButton = document.querySelector<HTMLButtonElement>('[aria-label="Edit source"]');
|
|
190
|
+
expect(editButton).toBeTruthy();
|
|
191
|
+
editButton?.dispatchEvent(new MouseEvent("mousedown", { bubbles: true, cancelable: true }));
|
|
192
|
+
await nextFrame();
|
|
193
|
+
await nextFrame();
|
|
194
|
+
|
|
195
|
+
const selection = view.state.selection.main;
|
|
196
|
+
const selectedSource = view.state.sliceDoc(selection.from, selection.to);
|
|
197
|
+
expect(selectedSource.trim()).toBe('<Card label="Alpha" />');
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
it("renders block components embedded in a mixed paragraph on a dedicated row", async () => {
|
|
201
|
+
const doc = 'Intro text <Card label="Mid" /> trailing text.';
|
|
202
|
+
await mountPreviewEditor(doc, blockComponents);
|
|
203
|
+
|
|
204
|
+
const blockWidgets = document.querySelectorAll<HTMLElement>(
|
|
205
|
+
'[data-md-widget="JsxBlockWidget"]',
|
|
206
|
+
);
|
|
207
|
+
expect(blockWidgets.length).toBe(1);
|
|
208
|
+
const midWidget = blockWidgets[0];
|
|
209
|
+
expect(midWidget?.textContent).toContain("Mid");
|
|
210
|
+
expect(midWidget && blockWidgetHostLine(midWidget)).toBeNull();
|
|
211
|
+
|
|
212
|
+
const lines = Array.from(document.querySelectorAll<HTMLElement>(".cm-line"));
|
|
213
|
+
expect(lines.some((line) => line.classList.contains("jsx-block-line-host"))).toBe(false);
|
|
214
|
+
|
|
215
|
+
const introLine = lines.find((line) => line.textContent?.includes("Intro text"));
|
|
216
|
+
const trailingLine = lines.find((line) => line.textContent?.includes("trailing text"));
|
|
217
|
+
expect(introLine).toBeTruthy();
|
|
218
|
+
expect(trailingLine).toBeTruthy();
|
|
219
|
+
expect(introLine?.style.display).not.toBe("flex");
|
|
220
|
+
expect(trailingLine?.style.display).not.toBe("flex");
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
it("renders block HTML embedded in a mixed paragraph on a dedicated row", async () => {
|
|
224
|
+
const doc = "hello world `snippet` <div>test</div> foo bar";
|
|
225
|
+
await mountPreviewEditor(doc, blockComponents);
|
|
226
|
+
|
|
227
|
+
const blockWidgets = document.querySelectorAll<HTMLElement>(
|
|
228
|
+
'[data-md-widget="JsxBlockWidget"]',
|
|
229
|
+
);
|
|
230
|
+
expect(blockWidgets.length).toBe(1);
|
|
231
|
+
const divWidget = blockWidgets[0];
|
|
232
|
+
expect(divWidget?.textContent).toContain("test");
|
|
233
|
+
expect(divWidget && blockWidgetHostLine(divWidget)).toBeNull();
|
|
234
|
+
|
|
235
|
+
const lines = Array.from(document.querySelectorAll<HTMLElement>(".cm-line"));
|
|
236
|
+
const helloLine = lines.find((line) => line.textContent?.includes("hello world"));
|
|
237
|
+
const fooLine = lines.find((line) => line.textContent?.includes("foo bar"));
|
|
238
|
+
expect(helloLine).toBeTruthy();
|
|
239
|
+
expect(fooLine).toBeTruthy();
|
|
240
|
+
expect(helloLine?.classList.contains("jsx-block-line-host")).toBe(false);
|
|
241
|
+
expect(fooLine?.classList.contains("jsx-block-line-host")).toBe(false);
|
|
242
|
+
});
|
|
242
243
|
});
|
|
@@ -2,6 +2,7 @@ import { MantineProvider, Paper, v8CssVariablesResolver } from "@mantine/core";
|
|
|
2
2
|
import { MarkdownEditor } from "@src/primitives/MarkdownEditor";
|
|
3
3
|
import { MANTINE_THEME } from "@src/theme/mantine";
|
|
4
4
|
import { describe, expect, it } from "vitest";
|
|
5
|
+
|
|
5
6
|
import { getEditorView, mountStory, nextFrame } from "../../_setup/e2e-helpers";
|
|
6
7
|
|
|
7
8
|
const TAG = '<Since v={"2.0.0"} t="true" b="false" />';
|
|
@@ -12,57 +13,57 @@ const STRING_COLOR = "rgb(0, 255, 110)";
|
|
|
12
13
|
const PROPERTY_COLOR = "rgb(224, 108, 117)";
|
|
13
14
|
|
|
14
15
|
describe("MarkdownEditor / JSX attribute highlighting", () => {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
16
|
+
it("does not let the nested HTML parser mis-highlight attributes after an expression", async () => {
|
|
17
|
+
mountStory(
|
|
18
|
+
<MantineProvider
|
|
19
|
+
theme={MANTINE_THEME}
|
|
20
|
+
cssVariablesResolver={v8CssVariablesResolver}
|
|
21
|
+
forceColorScheme="dark"
|
|
22
|
+
>
|
|
23
|
+
<Paper
|
|
24
|
+
p="md"
|
|
25
|
+
withBorder
|
|
26
|
+
>
|
|
27
|
+
<MarkdownEditor
|
|
28
|
+
mode="source"
|
|
29
|
+
document={TAG}
|
|
30
|
+
autoFocus={false}
|
|
31
|
+
mih={120}
|
|
32
|
+
/>
|
|
33
|
+
</Paper>
|
|
34
|
+
</MantineProvider>,
|
|
35
|
+
);
|
|
36
|
+
await getEditorView();
|
|
37
|
+
await nextFrame();
|
|
37
38
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
39
|
+
const colors = readLineTokenColors();
|
|
40
|
+
expect(colors.v).toBe(PROPERTY_COLOR);
|
|
41
|
+
expect(colors.t).toBe(PROPERTY_COLOR);
|
|
42
|
+
expect(colors.b).toBe(PROPERTY_COLOR);
|
|
43
|
+
expect(colors.trueQuoted).toBe(STRING_COLOR);
|
|
44
|
+
expect(colors.falseQuoted).toBe(STRING_COLOR);
|
|
45
|
+
expect(colors.exprLiteral).toBe(STRING_COLOR);
|
|
46
|
+
});
|
|
46
47
|
});
|
|
47
48
|
|
|
48
49
|
function readLineTokenColors(): Record<string, string> {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
50
|
+
const line = document.querySelector(".cm-line");
|
|
51
|
+
expect(line).not.toBeNull();
|
|
52
|
+
if (!line) return {};
|
|
52
53
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
54
|
+
const out: Record<string, string> = {};
|
|
55
|
+
for (const span of Array.from(line.querySelectorAll("span"))) {
|
|
56
|
+
const text = span.textContent ?? "";
|
|
57
|
+
if (!text) continue;
|
|
58
|
+
const color = getComputedStyle(span).color;
|
|
58
59
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
60
|
+
if (text === "v") out.v = color;
|
|
61
|
+
if (text === "t") out.t = color;
|
|
62
|
+
if (text === "b") out.b = color;
|
|
63
|
+
if (text === '"2.0.0"') out.exprLiteral = color;
|
|
64
|
+
if (text === '"true"') out.trueQuoted = color;
|
|
65
|
+
if (text === '"false"') out.falseQuoted = color;
|
|
66
|
+
}
|
|
66
67
|
|
|
67
|
-
|
|
68
|
+
return out;
|
|
68
69
|
}
|
|
@@ -2,6 +2,7 @@ import { MantineProvider, Paper, v8CssVariablesResolver } from "@mantine/core";
|
|
|
2
2
|
import { MarkdownEditor } from "@src/primitives/MarkdownEditor";
|
|
3
3
|
import { MANTINE_THEME } from "@src/theme/mantine";
|
|
4
4
|
import { describe, expect, it } from "vitest";
|
|
5
|
+
|
|
5
6
|
import { getEditorView, mountStory, nextFrame } from "../../_setup/e2e-helpers";
|
|
6
7
|
|
|
7
8
|
const JSX_BADGES_DOC = `### Since
|
|
@@ -22,38 +23,38 @@ const JSX_BADGES_DOC = `### Since
|
|
|
22
23
|
`;
|
|
23
24
|
|
|
24
25
|
describe("MarkdownEditor / inline JSX badges", () => {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
26
|
+
it("renders all Since and Label components inline like the viewer", async () => {
|
|
27
|
+
mountStory(
|
|
28
|
+
<MantineProvider
|
|
29
|
+
theme={MANTINE_THEME}
|
|
30
|
+
cssVariablesResolver={v8CssVariablesResolver}
|
|
31
|
+
forceColorScheme="dark"
|
|
32
|
+
>
|
|
33
|
+
<Paper
|
|
34
|
+
p="md"
|
|
35
|
+
withBorder
|
|
36
|
+
>
|
|
37
|
+
<MarkdownEditor
|
|
38
|
+
mode="preview"
|
|
39
|
+
document={JSX_BADGES_DOC}
|
|
40
|
+
autoFocus={false}
|
|
41
|
+
jsxMode="render"
|
|
42
|
+
/>
|
|
43
|
+
</Paper>
|
|
44
|
+
</MantineProvider>,
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
const view = await getEditorView();
|
|
48
|
+
view.contentDOM.blur();
|
|
49
|
+
await nextFrame();
|
|
50
|
+
|
|
51
|
+
const badges = document.querySelectorAll(".mantine-Badge-label");
|
|
52
|
+
expect(badges.length).toBe(7);
|
|
53
|
+
expect(document.body.textContent).toContain("1.5.0");
|
|
54
|
+
expect(document.body.textContent).toContain("Required");
|
|
55
|
+
expect(document.body.textContent).toContain("Optional");
|
|
56
|
+
expect(document.body.textContent).toContain("Deprecated");
|
|
57
|
+
expect(document.querySelector(".cm-content")?.textContent).not.toContain("<Since");
|
|
58
|
+
expect(document.querySelector(".cm-content")?.textContent).not.toContain("<Label");
|
|
59
|
+
});
|
|
59
60
|
});
|