@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
@@ -12,44 +12,44 @@ import { afterEach, describe, expect, it } from "vitest";
12
12
  const views: EditorView[] = [];
13
13
 
14
14
  afterEach(() => {
15
- for (const v of views.splice(0)) v.destroy();
15
+ for (const v of views.splice(0)) v.destroy();
16
16
  });
17
17
 
18
18
  /** Build a focused, preview-mode editor with the caret at `cursor`. */
19
19
  function preview(doc: string, cursor: number): EditorView {
20
- const state = EditorState.create({
21
- doc,
22
- extensions: [
23
- createMarkdownLanguage({ extensions: [Callout] }),
24
- markdownModeField,
25
- markdownDecorations({ widgetStore: createWidgetStore() }),
26
- ],
27
- });
28
- const parent = document.createElement("div");
29
- document.body.appendChild(parent);
30
- const view = new EditorView({ state, parent });
31
- views.push(view);
32
- view.dispatch({ effects: setMarkdownMode.of("preview") });
33
- view.focus();
34
- view.dispatch({ effects: setMarkdownEditorFocused.of(true) });
35
- view.dispatch({ selection: EditorSelection.cursor(cursor) });
36
- return view;
20
+ const state = EditorState.create({
21
+ doc,
22
+ extensions: [
23
+ createMarkdownLanguage({ extensions: [Callout] }),
24
+ markdownModeField,
25
+ markdownDecorations({ widgetStore: createWidgetStore() }),
26
+ ],
27
+ });
28
+ const parent = document.createElement("div");
29
+ document.body.appendChild(parent);
30
+ const view = new EditorView({ state, parent });
31
+ views.push(view);
32
+ view.dispatch({ effects: setMarkdownMode.of("preview") });
33
+ view.focus();
34
+ view.dispatch({ effects: setMarkdownEditorFocused.of(true) });
35
+ view.dispatch({ selection: EditorSelection.cursor(cursor) });
36
+ return view;
37
37
  }
38
38
 
39
39
  function jsxBlockRanges(view: EditorView): Array<{ from: number; to: number }> {
40
- const out: Array<{ from: number; to: number }> = [];
41
- for (const set of (view as unknown as { docView: { decorations: DecorationSet[] } }).docView
42
- .decorations) {
43
- const cursor = set.iter();
44
- while (cursor.value) {
45
- const widget = (cursor.value.spec as { widget?: Decoration }).widget;
46
- if (widget instanceof JsxBlockWidget) {
47
- out.push({ from: cursor.from, to: cursor.to });
48
- }
49
- cursor.next();
50
- }
51
- }
52
- return out;
40
+ const out: Array<{ from: number; to: number }> = [];
41
+ for (const set of (view as unknown as { docView: { decorations: DecorationSet[] } }).docView
42
+ .decorations) {
43
+ const cursor = set.iter();
44
+ while (cursor.value) {
45
+ const widget = (cursor.value.spec as { widget?: Decoration }).widget;
46
+ if (widget instanceof JsxBlockWidget) {
47
+ out.push({ from: cursor.from, to: cursor.to });
48
+ }
49
+ cursor.next();
50
+ }
51
+ }
52
+ return out;
53
53
  }
54
54
 
55
55
  const TABS = `<Tabs syncKey="demo">
@@ -67,26 +67,26 @@ Beta para one.
67
67
  const TABS_WITH_PROSE = `Intro line.\n\n${TABS}`;
68
68
 
69
69
  describe("MarkdownEditor / JSX block widget", () => {
70
- it("renders a multi-paragraph Tabs block as a single widget when the caret is outside", () => {
71
- const view = preview(TABS_WITH_PROSE, 0); // caret in the intro line
72
- const ranges = jsxBlockRanges(view);
73
- expect(ranges).toHaveLength(1);
74
- // Covers the whole <Tabs>…</Tabs> span, not a fragment of it.
75
- const tabsStart = TABS_WITH_PROSE.indexOf("<Tabs");
76
- expect(ranges[0]?.from).toBe(tabsStart);
77
- expect(ranges[0]?.to).toBe(TABS_WITH_PROSE.length);
78
- });
70
+ it("renders a multi-paragraph Tabs block as a single widget when the caret is outside", () => {
71
+ const view = preview(TABS_WITH_PROSE, 0); // caret in the intro line
72
+ const ranges = jsxBlockRanges(view);
73
+ expect(ranges).toHaveLength(1);
74
+ // Covers the whole <Tabs>…</Tabs> span, not a fragment of it.
75
+ const tabsStart = TABS_WITH_PROSE.indexOf("<Tabs");
76
+ expect(ranges[0]?.from).toBe(tabsStart);
77
+ expect(ranges[0]?.to).toBe(TABS_WITH_PROSE.length);
78
+ });
79
79
 
80
- it("reveals the entire block as source (no partial widgets) when the caret is inside", () => {
81
- // Caret inside the first tab's content.
82
- const inside = TABS_WITH_PROSE.indexOf("Alpha para one.") + 3;
83
- const view = preview(TABS_WITH_PROSE, inside);
84
- expect(jsxBlockRanges(view)).toHaveLength(0);
85
- });
80
+ it("reveals the entire block as source (no partial widgets) when the caret is inside", () => {
81
+ // Caret inside the first tab's content.
82
+ const inside = TABS_WITH_PROSE.indexOf("Alpha para one.") + 3;
83
+ const view = preview(TABS_WITH_PROSE, inside);
84
+ expect(jsxBlockRanges(view)).toHaveLength(0);
85
+ });
86
86
 
87
- it("keeps nested TabItem tags raw when the caret is on the closing tag line", () => {
88
- const onClose = TABS_WITH_PROSE.indexOf("</Tabs>") + 1;
89
- const view = preview(TABS_WITH_PROSE, onClose);
90
- expect(jsxBlockRanges(view)).toHaveLength(0);
91
- });
87
+ it("keeps nested TabItem tags raw when the caret is on the closing tag line", () => {
88
+ const onClose = TABS_WITH_PROSE.indexOf("</Tabs>") + 1;
89
+ const view = preview(TABS_WITH_PROSE, onClose);
90
+ expect(jsxBlockRanges(view)).toHaveLength(0);
91
+ });
92
92
  });
@@ -1,88 +1,88 @@
1
1
  import {
2
- JSX_ATTR_NAME_NODE,
3
- JSX_ATTR_STRING_NODE,
4
- JSX_EXPRESSION_CONTENT_NODE,
5
- JSX_EXPRESSION_MARK_NODE,
2
+ JSX_ATTR_NAME_NODE,
3
+ JSX_ATTR_STRING_NODE,
4
+ JSX_EXPRESSION_CONTENT_NODE,
5
+ JSX_EXPRESSION_MARK_NODE,
6
6
  } from "@src/lib/markdown/grammar/jsx-tag";
7
7
  import { createMarkdownLanguage } from "@src/lib/markdown/grammar/language";
8
8
  import { describe, expect, it } from "vitest";
9
9
 
10
10
  function parse(text: string) {
11
- const support = createMarkdownLanguage({ addKeymap: false, pasteURLAsLink: false });
12
- return support.language.parser.parse(text);
11
+ const support = createMarkdownLanguage({ addKeymap: false, pasteURLAsLink: false });
12
+ return support.language.parser.parse(text);
13
13
  }
14
14
 
15
15
  function nodeNames(text: string): string[] {
16
- const tree = parse(text);
17
- const names: string[] = [];
18
- tree.iterate({
19
- enter: (n) => {
20
- names.push(n.name);
21
- },
22
- });
23
- return names;
16
+ const tree = parse(text);
17
+ const names: string[] = [];
18
+ tree.iterate({
19
+ enter: (n) => {
20
+ names.push(n.name);
21
+ },
22
+ });
23
+ return names;
24
24
  }
25
25
 
26
26
  function htmlTagSpan(text: string): { from: number; to: number } | null {
27
- const tree = parse(text);
28
- let span: { from: number; to: number } | null = null;
29
- tree.iterate({
30
- enter: (n) => {
31
- if (n.name === "HTMLTag") span = { from: n.from, to: n.to };
32
- },
33
- });
34
- return span;
27
+ const tree = parse(text);
28
+ let span: { from: number; to: number } | null = null;
29
+ tree.iterate({
30
+ enter: (n) => {
31
+ if (n.name === "HTMLTag") span = { from: n.from, to: n.to };
32
+ },
33
+ });
34
+ return span;
35
35
  }
36
36
 
37
37
  describe("JsxTag grammar extension", () => {
38
- it("keeps plain quoted attributes on the built-in HTMLTag parser", () => {
39
- expect(nodeNames('<Since v="1" />')).toEqual(["Document", "Paragraph", "HTMLTag"]);
40
- expect(nodeNames('<Since v="1" />')).not.toContain(JSX_EXPRESSION_CONTENT_NODE);
41
- });
38
+ it("keeps plain quoted attributes on the built-in HTMLTag parser", () => {
39
+ expect(nodeNames('<Since v="1" />')).toEqual(["Document", "Paragraph", "HTMLTag"]);
40
+ expect(nodeNames('<Since v="1" />')).not.toContain(JSX_EXPRESSION_CONTENT_NODE);
41
+ });
42
42
 
43
- it("parses a full HTMLTag when the attribute value is a JSX expression", () => {
44
- const text = '<Component prop={"a"} />';
45
- expect(htmlTagSpan(text)).toEqual({ from: 0, to: text.length });
46
- expect(nodeNames(text)).toContain(JSX_EXPRESSION_CONTENT_NODE);
47
- expect(nodeNames(text)).toContain(JSX_EXPRESSION_MARK_NODE);
48
- });
43
+ it("parses a full HTMLTag when the attribute value is a JSX expression", () => {
44
+ const text = '<Component prop={"a"} />';
45
+ expect(htmlTagSpan(text)).toEqual({ from: 0, to: text.length });
46
+ expect(nodeNames(text)).toContain(JSX_EXPRESSION_CONTENT_NODE);
47
+ expect(nodeNames(text)).toContain(JSX_EXPRESSION_MARK_NODE);
48
+ });
49
49
 
50
- it("does not truncate at > inside a JSX expression", () => {
51
- const text = "<Component prop={foo > bar} />";
52
- expect(htmlTagSpan(text)).toEqual({ from: 0, to: text.length });
53
- });
50
+ it("does not truncate at > inside a JSX expression", () => {
51
+ const text = "<Component prop={foo > bar} />";
52
+ expect(htmlTagSpan(text)).toEqual({ from: 0, to: text.length });
53
+ });
54
54
 
55
- it("parses multiple JSX tags on one line", () => {
56
- const text = '<Tabs defaultValue={"a"}><TabItem label={x} /></Tabs>';
57
- const tree = parse(text);
58
- const tags: string[] = [];
59
- tree.iterate({
60
- enter: (n) => {
61
- if (n.name === "HTMLTag") tags.push(text.slice(n.from, n.to));
62
- },
63
- });
64
- expect(tags).toEqual(['<Tabs defaultValue={"a"}>', "<TabItem label={x} />", "</Tabs>"]);
65
- });
55
+ it("parses multiple JSX tags on one line", () => {
56
+ const text = '<Tabs defaultValue={"a"}><TabItem label={x} /></Tabs>';
57
+ const tree = parse(text);
58
+ const tags: string[] = [];
59
+ tree.iterate({
60
+ enter: (n) => {
61
+ if (n.name === "HTMLTag") tags.push(text.slice(n.from, n.to));
62
+ },
63
+ });
64
+ expect(tags).toEqual(['<Tabs defaultValue={"a"}>', "<TabItem label={x} />", "</Tabs>"]);
65
+ });
66
66
 
67
- it("highlights quoted attributes that follow a JSX expression", () => {
68
- const text = '<Since v={"2.0.0"} t="true" b="false" />';
69
- expect(htmlTagSpan(text)).toEqual({ from: 0, to: text.length });
67
+ it("highlights quoted attributes that follow a JSX expression", () => {
68
+ const text = '<Since v={"2.0.0"} t="true" b="false" />';
69
+ expect(htmlTagSpan(text)).toEqual({ from: 0, to: text.length });
70
70
 
71
- const tree = parse(text);
72
- const names = collectNodes(tree, text, JSX_ATTR_NAME_NODE);
73
- const strings = collectNodes(tree, text, JSX_ATTR_STRING_NODE);
71
+ const tree = parse(text);
72
+ const names = collectNodes(tree, text, JSX_ATTR_NAME_NODE);
73
+ const strings = collectNodes(tree, text, JSX_ATTR_STRING_NODE);
74
74
 
75
- expect(names).toEqual(["v", "t", "b"]);
76
- expect(strings).toEqual(['"true"', '"false"']);
77
- });
75
+ expect(names).toEqual(["v", "t", "b"]);
76
+ expect(strings).toEqual(['"true"', '"false"']);
77
+ });
78
78
  });
79
79
 
80
80
  function collectNodes(tree: ReturnType<typeof parse>, text: string, name: string): string[] {
81
- const out: string[] = [];
82
- tree.iterate({
83
- enter: (n) => {
84
- if (n.name === name) out.push(text.slice(n.from, n.to));
85
- },
86
- });
87
- return out;
81
+ const out: string[] = [];
82
+ tree.iterate({
83
+ enter: (n) => {
84
+ if (n.name === name) out.push(text.slice(n.from, n.to));
85
+ },
86
+ });
87
+ return out;
88
88
  }
@@ -8,88 +8,88 @@ import { afterEach, describe, expect, it } from "vitest";
8
8
  let view: EditorView;
9
9
 
10
10
  afterEach(() => {
11
- view?.destroy();
11
+ view?.destroy();
12
12
  });
13
13
 
14
14
  function createView(doc: string, cursor: number): EditorView {
15
- const state = EditorState.create({
16
- doc,
17
- selection: EditorSelection.cursor(cursor),
18
- extensions: [createMarkdownLanguage({ extensions: [Callout] })],
19
- });
20
- const parent = document.createElement("div");
21
- document.body.appendChild(parent);
22
- view = new EditorView({ state, parent });
23
- return view;
15
+ const state = EditorState.create({
16
+ doc,
17
+ selection: EditorSelection.cursor(cursor),
18
+ extensions: [createMarkdownLanguage({ extensions: [Callout] })],
19
+ });
20
+ const parent = document.createElement("div");
21
+ document.body.appendChild(parent);
22
+ view = new EditorView({ state, parent });
23
+ return view;
24
24
  }
25
25
 
26
26
  /** Index just after the marker + space of the line containing `needle`. */
27
27
  function cursorInItem(doc: string, needle: string): number {
28
- return doc.indexOf(needle) + 1;
28
+ return doc.indexOf(needle) + 1;
29
29
  }
30
30
 
31
31
  describe("indentMarkdownList", () => {
32
- it("indents an item under its preceding sibling", () => {
33
- const doc = "- one\n- two";
34
- const v = createView(doc, cursorInItem(doc, "two"));
35
- const handled = indentMarkdownList(v, false);
36
- expect(handled).toBe(true);
37
- expect(v.state.doc.toString()).toBe("- one\n - two");
38
- });
32
+ it("indents an item under its preceding sibling", () => {
33
+ const doc = "- one\n- two";
34
+ const v = createView(doc, cursorInItem(doc, "two"));
35
+ const handled = indentMarkdownList(v, false);
36
+ expect(handled).toBe(true);
37
+ expect(v.state.doc.toString()).toBe("- one\n - two");
38
+ });
39
39
 
40
- it("consumes Tab but does not change the first item (no preceding sibling)", () => {
41
- const doc = "- one\n- two";
42
- const v = createView(doc, cursorInItem(doc, "one"));
43
- const handled = indentMarkdownList(v, false);
44
- expect(handled).toBe(true);
45
- expect(v.state.doc.toString()).toBe(doc);
46
- });
40
+ it("consumes Tab but does not change the first item (no preceding sibling)", () => {
41
+ const doc = "- one\n- two";
42
+ const v = createView(doc, cursorInItem(doc, "one"));
43
+ const handled = indentMarkdownList(v, false);
44
+ expect(handled).toBe(true);
45
+ expect(v.state.doc.toString()).toBe(doc);
46
+ });
47
47
 
48
- it("outdents a nested item to its parent level", () => {
49
- const doc = "- one\n - two";
50
- const v = createView(doc, cursorInItem(doc, "two"));
51
- const handled = indentMarkdownList(v, true);
52
- expect(handled).toBe(true);
53
- expect(v.state.doc.toString()).toBe("- one\n- two");
54
- });
48
+ it("outdents a nested item to its parent level", () => {
49
+ const doc = "- one\n - two";
50
+ const v = createView(doc, cursorInItem(doc, "two"));
51
+ const handled = indentMarkdownList(v, true);
52
+ expect(handled).toBe(true);
53
+ expect(v.state.doc.toString()).toBe("- one\n- two");
54
+ });
55
55
 
56
- it("consumes Shift-Tab but does not outdent a top-level item", () => {
57
- const doc = "- one\n- two";
58
- const v = createView(doc, cursorInItem(doc, "two"));
59
- const handled = indentMarkdownList(v, true);
60
- expect(handled).toBe(true);
61
- expect(v.state.doc.toString()).toBe(doc);
62
- });
56
+ it("consumes Shift-Tab but does not outdent a top-level item", () => {
57
+ const doc = "- one\n- two";
58
+ const v = createView(doc, cursorInItem(doc, "two"));
59
+ const handled = indentMarkdownList(v, true);
60
+ expect(handled).toBe(true);
61
+ expect(v.state.doc.toString()).toBe(doc);
62
+ });
63
63
 
64
- it("returns false outside a list", () => {
65
- const doc = "just a paragraph";
66
- const v = createView(doc, 4);
67
- expect(indentMarkdownList(v, false)).toBe(false);
68
- expect(indentMarkdownList(v, true)).toBe(false);
69
- });
64
+ it("returns false outside a list", () => {
65
+ const doc = "just a paragraph";
66
+ const v = createView(doc, 4);
67
+ expect(indentMarkdownList(v, false)).toBe(false);
68
+ expect(indentMarkdownList(v, true)).toBe(false);
69
+ });
70
70
 
71
- it("indents ordered list items by the marker width", () => {
72
- const doc = "1. one\n2. two";
73
- const v = createView(doc, cursorInItem(doc, "two"));
74
- const handled = indentMarkdownList(v, false);
75
- expect(handled).toBe(true);
76
- expect(v.state.doc.toString()).toBe("1. one\n 2. two");
77
- });
71
+ it("indents ordered list items by the marker width", () => {
72
+ const doc = "1. one\n2. two";
73
+ const v = createView(doc, cursorInItem(doc, "two"));
74
+ const handled = indentMarkdownList(v, false);
75
+ expect(handled).toBe(true);
76
+ expect(v.state.doc.toString()).toBe("1. one\n 2. two");
77
+ });
78
78
 
79
- it("indents an item together with its nested children", () => {
80
- const doc = "- one\n- two\n - child";
81
- const v = createView(doc, cursorInItem(doc, "two"));
82
- const handled = indentMarkdownList(v, false);
83
- expect(handled).toBe(true);
84
- expect(v.state.doc.toString()).toBe("- one\n - two\n - child");
85
- });
79
+ it("indents an item together with its nested children", () => {
80
+ const doc = "- one\n- two\n - child";
81
+ const v = createView(doc, cursorInItem(doc, "two"));
82
+ const handled = indentMarkdownList(v, false);
83
+ expect(handled).toBe(true);
84
+ expect(v.state.doc.toString()).toBe("- one\n - two\n - child");
85
+ });
86
86
 
87
- it("keeps the cursor with the indented text", () => {
88
- const doc = "- one\n- two";
89
- const start = doc.indexOf("two");
90
- const v = createView(doc, start);
91
- indentMarkdownList(v, false);
92
- // Two spaces inserted before the line shift the cursor right by two.
93
- expect(v.state.selection.main.head).toBe(start + 2);
94
- });
87
+ it("keeps the cursor with the indented text", () => {
88
+ const doc = "- one\n- two";
89
+ const start = doc.indexOf("two");
90
+ const v = createView(doc, start);
91
+ indentMarkdownList(v, false);
92
+ // Two spaces inserted before the line shift the cursor right by two.
93
+ expect(v.state.selection.main.head).toBe(start + 2);
94
+ });
95
95
  });