@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
@@ -1,119 +1,119 @@
1
1
  import {
2
- gfmTableAddColumn,
3
- gfmTableAddRow,
4
- gfmTableRemoveColumn,
5
- gfmTableRemoveRow,
6
- locateGfmTableCells,
7
- parseGfmTable,
8
- serialiseGfmTable,
9
- type TableModel,
2
+ gfmTableAddColumn,
3
+ gfmTableAddRow,
4
+ gfmTableRemoveColumn,
5
+ gfmTableRemoveRow,
6
+ locateGfmTableCells,
7
+ parseGfmTable,
8
+ serialiseGfmTable,
9
+ type TableModel,
10
10
  } from "@src/lib/markdown/tree/gfm-table";
11
11
  import { describe, expect, it } from "vitest";
12
12
 
13
13
  describe("GFM table", () => {
14
- it("parses simple GFM tables", () => {
15
- const source = "| a | b |\n| - | - |\n| 1 | 2 |";
16
- const model = parseGfmTable(source);
17
- expect(model).not.toBeNull();
18
- expect(model?.headers).toEqual(["a", "b"]);
19
- expect(model?.rows).toEqual([["1", "2"]]);
20
- });
14
+ it("parses simple GFM tables", () => {
15
+ const source = "| a | b |\n| - | - |\n| 1 | 2 |";
16
+ const model = parseGfmTable(source);
17
+ expect(model).not.toBeNull();
18
+ expect(model?.headers).toEqual(["a", "b"]);
19
+ expect(model?.rows).toEqual([["1", "2"]]);
20
+ });
21
21
 
22
- it("respects alignment markers", () => {
23
- const source = "| a | b | c |\n| :- | :-: | -: |\n| 1 | 2 | 3 |";
24
- const model = parseGfmTable(source);
25
- expect(model?.alignments).toEqual(["left", "center", "right"]);
26
- });
22
+ it("respects alignment markers", () => {
23
+ const source = "| a | b | c |\n| :- | :-: | -: |\n| 1 | 2 | 3 |";
24
+ const model = parseGfmTable(source);
25
+ expect(model?.alignments).toEqual(["left", "center", "right"]);
26
+ });
27
27
 
28
- it("round trips a table preserving content", () => {
29
- const source = "| Name | Score |\n| :--- | ----: |\n| Ari | 12 |\n| Nova | 8 |";
30
- const model = parseGfmTable(source);
31
- if (!model) throw new Error("expected parse");
32
- const serialised = serialiseGfmTable(model);
28
+ it("round trips a table preserving content", () => {
29
+ const source = "| Name | Score |\n| :--- | ----: |\n| Ari | 12 |\n| Nova | 8 |";
30
+ const model = parseGfmTable(source);
31
+ if (!model) throw new Error("expected parse");
32
+ const serialised = serialiseGfmTable(model);
33
33
 
34
- const reparsed = parseGfmTable(serialised);
35
- expect(reparsed).not.toBeNull();
36
- expect(reparsed?.headers).toEqual(model.headers);
37
- expect(reparsed?.alignments).toEqual(model.alignments);
38
- expect(reparsed?.rows).toEqual(model.rows);
39
- });
34
+ const reparsed = parseGfmTable(serialised);
35
+ expect(reparsed).not.toBeNull();
36
+ expect(reparsed?.headers).toEqual(model.headers);
37
+ expect(reparsed?.alignments).toEqual(model.alignments);
38
+ expect(reparsed?.rows).toEqual(model.rows);
39
+ });
40
40
 
41
- it("returns null for non-table input", () => {
42
- expect(parseGfmTable("just a paragraph")).toBeNull();
43
- });
41
+ it("returns null for non-table input", () => {
42
+ expect(parseGfmTable("just a paragraph")).toBeNull();
43
+ });
44
44
  });
45
45
 
46
46
  describe("locateGfmTableCells", () => {
47
- it("locates the content start offset of each cell", () => {
48
- const source = "| a | b |\n| - | - |\n| 1 | 2 |";
49
- const cells = locateGfmTableCells(source);
50
- expect(cells).not.toBeNull();
51
- // Header content starts: 'a' at 2, 'b' at 6.
52
- expect(cells?.headerOffsets).toEqual([2, 6]);
53
- expect(source[cells?.headerOffsets[0] ?? -1]).toBe("a");
54
- expect(source[cells?.headerOffsets[1] ?? -1]).toBe("b");
55
- // Body row content starts: '1' and '2'.
56
- expect(source[cells?.rowOffsets[0]?.[0] ?? -1]).toBe("1");
57
- expect(source[cells?.rowOffsets[0]?.[1] ?? -1]).toBe("2");
58
- });
47
+ it("locates the content start offset of each cell", () => {
48
+ const source = "| a | b |\n| - | - |\n| 1 | 2 |";
49
+ const cells = locateGfmTableCells(source);
50
+ expect(cells).not.toBeNull();
51
+ // Header content starts: 'a' at 2, 'b' at 6.
52
+ expect(cells?.headerOffsets).toEqual([2, 6]);
53
+ expect(source[cells?.headerOffsets[0] ?? -1]).toBe("a");
54
+ expect(source[cells?.headerOffsets[1] ?? -1]).toBe("b");
55
+ // Body row content starts: '1' and '2'.
56
+ expect(source[cells?.rowOffsets[0]?.[0] ?? -1]).toBe("1");
57
+ expect(source[cells?.rowOffsets[0]?.[1] ?? -1]).toBe("2");
58
+ });
59
59
 
60
- it("handles ragged padding and missing outer pipes", () => {
61
- const source = "Name | Score\n--- | ---\nAri | 12";
62
- const cells = locateGfmTableCells(source);
63
- expect(cells).not.toBeNull();
64
- expect(source.slice(cells?.headerOffsets[0] ?? 0, (cells?.headerOffsets[0] ?? 0) + 4)).toBe(
65
- "Name",
66
- );
67
- expect(source.slice(cells?.headerOffsets[1] ?? 0, (cells?.headerOffsets[1] ?? 0) + 5)).toBe(
68
- "Score",
69
- );
70
- expect(source[cells?.rowOffsets[0]?.[1] ?? -1]).toBe("1");
71
- });
60
+ it("handles ragged padding and missing outer pipes", () => {
61
+ const source = "Name | Score\n--- | ---\nAri | 12";
62
+ const cells = locateGfmTableCells(source);
63
+ expect(cells).not.toBeNull();
64
+ expect(source.slice(cells?.headerOffsets[0] ?? 0, (cells?.headerOffsets[0] ?? 0) + 4)).toBe(
65
+ "Name",
66
+ );
67
+ expect(source.slice(cells?.headerOffsets[1] ?? 0, (cells?.headerOffsets[1] ?? 0) + 5)).toBe(
68
+ "Score",
69
+ );
70
+ expect(source[cells?.rowOffsets[0]?.[1] ?? -1]).toBe("1");
71
+ });
72
72
 
73
- it("returns null for non-table input", () => {
74
- expect(locateGfmTableCells("just a paragraph")).toBeNull();
75
- });
73
+ it("returns null for non-table input", () => {
74
+ expect(locateGfmTableCells("just a paragraph")).toBeNull();
75
+ });
76
76
  });
77
77
 
78
78
  describe("GFM table edits", () => {
79
- const base: TableModel = {
80
- headers: ["a", "b"],
81
- alignments: ["default", "default"],
82
- rows: [["1", "2"]],
83
- };
79
+ const base: TableModel = {
80
+ headers: ["a", "b"],
81
+ alignments: ["default", "default"],
82
+ rows: [["1", "2"]],
83
+ };
84
84
 
85
- it("adds an empty trailing column", () => {
86
- const next = gfmTableAddColumn(base);
87
- expect(next.headers).toEqual(["a", "b", ""]);
88
- expect(next.alignments).toHaveLength(3);
89
- expect(next.rows).toEqual([["1", "2", ""]]);
90
- });
85
+ it("adds an empty trailing column", () => {
86
+ const next = gfmTableAddColumn(base);
87
+ expect(next.headers).toEqual(["a", "b", ""]);
88
+ expect(next.alignments).toHaveLength(3);
89
+ expect(next.rows).toEqual([["1", "2", ""]]);
90
+ });
91
91
 
92
- it("removes the last column but keeps at least one", () => {
93
- const next = gfmTableRemoveColumn(base);
94
- expect(next.headers).toEqual(["a"]);
95
- expect(next.rows).toEqual([["1"]]);
96
- const single: TableModel = { headers: ["only"], alignments: ["default"], rows: [["x"]] };
97
- expect(gfmTableRemoveColumn(single)).toEqual(single);
98
- });
92
+ it("removes the last column but keeps at least one", () => {
93
+ const next = gfmTableRemoveColumn(base);
94
+ expect(next.headers).toEqual(["a"]);
95
+ expect(next.rows).toEqual([["1"]]);
96
+ const single: TableModel = { headers: ["only"], alignments: ["default"], rows: [["x"]] };
97
+ expect(gfmTableRemoveColumn(single)).toEqual(single);
98
+ });
99
99
 
100
- it("adds an empty trailing row sized to the columns", () => {
101
- const next = gfmTableAddRow(base);
102
- expect(next.rows).toEqual([
103
- ["1", "2"],
104
- ["", ""],
105
- ]);
106
- });
100
+ it("adds an empty trailing row sized to the columns", () => {
101
+ const next = gfmTableAddRow(base);
102
+ expect(next.rows).toEqual([
103
+ ["1", "2"],
104
+ ["", ""],
105
+ ]);
106
+ });
107
107
 
108
- it("removes the last row and is a no-op with no rows", () => {
109
- expect(gfmTableRemoveRow(base).rows).toEqual([]);
110
- const empty: TableModel = { headers: ["a"], alignments: ["default"], rows: [] };
111
- expect(gfmTableRemoveRow(empty)).toEqual(empty);
112
- });
108
+ it("removes the last row and is a no-op with no rows", () => {
109
+ expect(gfmTableRemoveRow(base).rows).toEqual([]);
110
+ const empty: TableModel = { headers: ["a"], alignments: ["default"], rows: [] };
111
+ expect(gfmTableRemoveRow(empty)).toEqual(empty);
112
+ });
113
113
 
114
- it("round-trips edits through serialise/parse", () => {
115
- const widened = serialiseGfmTable(gfmTableAddColumn(base));
116
- const reparsed = parseGfmTable(widened);
117
- expect(reparsed?.headers).toEqual(["a", "b", ""]);
118
- });
114
+ it("round-trips edits through serialise/parse", () => {
115
+ const widened = serialiseGfmTable(gfmTableAddColumn(base));
116
+ const reparsed = parseGfmTable(widened);
117
+ expect(reparsed?.headers).toEqual(["a", "b", ""]);
118
+ });
119
119
  });
@@ -6,30 +6,30 @@ import { createMarkdownLanguage } from "@src/lib/markdown/grammar/language";
6
6
  import { describe, expect, it } from "vitest";
7
7
 
8
8
  function createView(doc: string, cursor?: number | { anchor: number; head: number }): EditorView {
9
- const state = EditorState.create({
10
- doc,
11
- extensions: [
12
- createMarkdownLanguage({ extensions: [Callout] }),
13
- markdownSnippetHandler,
14
- markdownPairKeymap,
15
- ],
16
- selection:
17
- typeof cursor === "number"
18
- ? EditorSelection.cursor(cursor)
19
- : cursor
20
- ? EditorSelection.range(cursor.anchor, cursor.head)
21
- : undefined,
22
- });
23
-
24
- const parent = document.createElement("div");
25
- document.body.appendChild(parent);
26
-
27
- return new EditorView({ state, parent });
9
+ const state = EditorState.create({
10
+ doc,
11
+ extensions: [
12
+ createMarkdownLanguage({ extensions: [Callout] }),
13
+ markdownSnippetHandler,
14
+ markdownPairKeymap,
15
+ ],
16
+ selection:
17
+ typeof cursor === "number"
18
+ ? EditorSelection.cursor(cursor)
19
+ : cursor
20
+ ? EditorSelection.range(cursor.anchor, cursor.head)
21
+ : undefined,
22
+ });
23
+
24
+ const parent = document.createElement("div");
25
+ document.body.appendChild(parent);
26
+
27
+ return new EditorView({ state, parent });
28
28
  }
29
29
 
30
30
  /** Dispatch a Backspace through the registered key handlers. */
31
31
  function backspace(view: EditorView): boolean {
32
- return runScopeHandlers(view, new KeyboardEvent("keydown", { key: "Backspace" }), "editor");
32
+ return runScopeHandlers(view, new KeyboardEvent("keydown", { key: "Backspace" }), "editor");
33
33
  }
34
34
 
35
35
  /**
@@ -39,206 +39,206 @@ function backspace(view: EditorView): boolean {
39
39
  * normal keystroke.
40
40
  */
41
41
  function type(view: EditorView, text: string): void {
42
- const main = view.state.selection.main;
43
- const handlers = view.state.facet(EditorView.inputHandler);
44
- const buildTransaction = () => view.state.update(view.state.replaceSelection(text));
45
- for (const handler of handlers) {
46
- if (handler(view, main.from, main.to, text, buildTransaction)) {
47
- return;
48
- }
49
- }
50
- view.dispatch(buildTransaction());
42
+ const main = view.state.selection.main;
43
+ const handlers = view.state.facet(EditorView.inputHandler);
44
+ const buildTransaction = () => view.state.update(view.state.replaceSelection(text));
45
+ for (const handler of handlers) {
46
+ if (handler(view, main.from, main.to, text, buildTransaction)) {
47
+ return;
48
+ }
49
+ }
50
+ view.dispatch(buildTransaction());
51
51
  }
52
52
 
53
53
  describe("markdownSnippetHandler", () => {
54
- it("expands triple backtick into a fenced code block with caret on the empty content line", () => {
55
- const view = createView("``", 2);
56
- type(view, "`");
54
+ it("expands triple backtick into a fenced code block with caret on the empty content line", () => {
55
+ const view = createView("``", 2);
56
+ type(view, "`");
57
57
 
58
- expect(view.state.doc.toString()).toBe("```\n\n```");
59
- expect(view.state.selection.main.empty).toBe(true);
60
- // Caret on the empty middle line, after "```\n".
61
- expect(view.state.selection.main.from).toBe(4);
58
+ expect(view.state.doc.toString()).toBe("```\n\n```");
59
+ expect(view.state.selection.main.empty).toBe(true);
60
+ // Caret on the empty middle line, after "```\n".
61
+ expect(view.state.selection.main.from).toBe(4);
62
62
 
63
- view.destroy();
64
- });
63
+ view.destroy();
64
+ });
65
65
 
66
- it("preserves leading indent when expanding a fence inside a nested context", () => {
67
- const view = createView(" ``", 4);
68
- type(view, "`");
66
+ it("preserves leading indent when expanding a fence inside a nested context", () => {
67
+ const view = createView(" ``", 4);
68
+ type(view, "`");
69
69
 
70
- expect(view.state.doc.toString()).toBe(" ```\n \n ```");
71
- // Caret on the indented content line.
72
- expect(view.state.selection.main.from).toBe(8);
70
+ expect(view.state.doc.toString()).toBe(" ```\n \n ```");
71
+ // Caret on the indented content line.
72
+ expect(view.state.selection.main.from).toBe(8);
73
73
 
74
- view.destroy();
75
- });
74
+ view.destroy();
75
+ });
76
76
 
77
- it("expands a triple backtick typed one keystroke at a time", () => {
78
- const view = createView("", 0);
79
- type(view, "`");
80
- type(view, "`");
81
- type(view, "`");
77
+ it("expands a triple backtick typed one keystroke at a time", () => {
78
+ const view = createView("", 0);
79
+ type(view, "`");
80
+ type(view, "`");
81
+ type(view, "`");
82
82
 
83
- expect(view.state.doc.toString()).toBe("```\n\n```");
84
- expect(view.state.selection.main.from).toBe(4);
83
+ expect(view.state.doc.toString()).toBe("```\n\n```");
84
+ expect(view.state.selection.main.from).toBe(4);
85
85
 
86
- view.destroy();
87
- });
86
+ view.destroy();
87
+ });
88
88
 
89
- it("does not expand a fence from a single backtick after text", () => {
90
- const view = createView("abc", 3);
91
- type(view, "`");
89
+ it("does not expand a fence from a single backtick after text", () => {
90
+ const view = createView("abc", 3);
91
+ type(view, "`");
92
92
 
93
- // A lone backtick must auto-pair, never clobber the preceding text.
94
- expect(view.state.doc.toString()).toBe("abc``");
95
- expect(view.state.selection.main.from).toBe(4);
93
+ // A lone backtick must auto-pair, never clobber the preceding text.
94
+ expect(view.state.doc.toString()).toBe("abc``");
95
+ expect(view.state.selection.main.from).toBe(4);
96
96
 
97
- view.destroy();
98
- });
97
+ view.destroy();
98
+ });
99
99
 
100
- it("does not expand a fence when the backticks are not at the line start", () => {
101
- const view = createView("x ``", 4);
102
- type(view, "`");
100
+ it("does not expand a fence when the backticks are not at the line start", () => {
101
+ const view = createView("x ``", 4);
102
+ type(view, "`");
103
103
 
104
- expect(view.state.doc.toString()).toBe("x ```");
104
+ expect(view.state.doc.toString()).toBe("x ```");
105
105
 
106
- view.destroy();
107
- });
106
+ view.destroy();
107
+ });
108
108
 
109
- it("does not expand a fence when there is content after the cursor on the same line", () => {
110
- const view = createView("``rest", 2);
111
- type(view, "`");
109
+ it("does not expand a fence when there is content after the cursor on the same line", () => {
110
+ const view = createView("``rest", 2);
111
+ type(view, "`");
112
112
 
113
- expect(view.state.doc.toString()).toBe("```rest");
113
+ expect(view.state.doc.toString()).toBe("```rest");
114
114
 
115
- view.destroy();
116
- });
115
+ view.destroy();
116
+ });
117
117
 
118
- it("does not expand a fence when typing inside an existing fenced code block", () => {
119
- const view = createView("```js\nlet x``\n```", 13);
120
- type(view, "`");
118
+ it("does not expand a fence when typing inside an existing fenced code block", () => {
119
+ const view = createView("```js\nlet x``\n```", 13);
120
+ type(view, "`");
121
121
 
122
- expect(view.state.doc.toString()).toBe("```js\nlet x```\n```");
122
+ expect(view.state.doc.toString()).toBe("```js\nlet x```\n```");
123
123
 
124
- view.destroy();
125
- });
124
+ view.destroy();
125
+ });
126
126
 
127
- it("wraps a non-empty selection with backticks", () => {
128
- const view = createView("hello world", { anchor: 0, head: 5 });
129
- type(view, "`");
127
+ it("wraps a non-empty selection with backticks", () => {
128
+ const view = createView("hello world", { anchor: 0, head: 5 });
129
+ type(view, "`");
130
130
 
131
- expect(view.state.doc.toString()).toBe("`hello` world");
132
- expect(view.state.selection.main.from).toBe(1);
133
- expect(view.state.selection.main.to).toBe(6);
131
+ expect(view.state.doc.toString()).toBe("`hello` world");
132
+ expect(view.state.selection.main.from).toBe(1);
133
+ expect(view.state.selection.main.to).toBe(6);
134
134
 
135
- view.destroy();
136
- });
135
+ view.destroy();
136
+ });
137
137
 
138
- it("wraps a selection with asterisks for italic and again for bold", () => {
139
- const view = createView("hello world", { anchor: 0, head: 5 });
140
- type(view, "*");
141
- expect(view.state.doc.toString()).toBe("*hello* world");
138
+ it("wraps a selection with asterisks for italic and again for bold", () => {
139
+ const view = createView("hello world", { anchor: 0, head: 5 });
140
+ type(view, "*");
141
+ expect(view.state.doc.toString()).toBe("*hello* world");
142
142
 
143
- type(view, "*");
144
- expect(view.state.doc.toString()).toBe("**hello** world");
143
+ type(view, "*");
144
+ expect(view.state.doc.toString()).toBe("**hello** world");
145
145
 
146
- view.destroy();
147
- });
146
+ view.destroy();
147
+ });
148
148
 
149
- it("wraps a selection with tildes for strikethrough", () => {
150
- const view = createView("hello world", { anchor: 0, head: 5 });
151
- type(view, "~");
152
- type(view, "~");
149
+ it("wraps a selection with tildes for strikethrough", () => {
150
+ const view = createView("hello world", { anchor: 0, head: 5 });
151
+ type(view, "~");
152
+ type(view, "~");
153
153
 
154
- expect(view.state.doc.toString()).toBe("~~hello~~ world");
154
+ expect(view.state.doc.toString()).toBe("~~hello~~ world");
155
155
 
156
- view.destroy();
157
- });
156
+ view.destroy();
157
+ });
158
158
 
159
- it("wraps a selection as a markdown link with caret between the parens", () => {
160
- const view = createView("hello world", { anchor: 0, head: 5 });
161
- type(view, "[");
159
+ it("wraps a selection as a markdown link with caret between the parens", () => {
160
+ const view = createView("hello world", { anchor: 0, head: 5 });
161
+ type(view, "[");
162
162
 
163
- expect(view.state.doc.toString()).toBe("[hello]() world");
164
- expect(view.state.selection.main.empty).toBe(true);
165
- expect(view.state.selection.main.from).toBe(8);
163
+ expect(view.state.doc.toString()).toBe("[hello]() world");
164
+ expect(view.state.selection.main.empty).toBe(true);
165
+ expect(view.state.selection.main.from).toBe(8);
166
166
 
167
- view.destroy();
168
- });
167
+ view.destroy();
168
+ });
169
169
 
170
- it("does not wrap when the selection is inside a fenced code block", () => {
171
- const view = createView("```js\nlet x = 1\n```", { anchor: 6, head: 11 });
172
- type(view, "*");
170
+ it("does not wrap when the selection is inside a fenced code block", () => {
171
+ const view = createView("```js\nlet x = 1\n```", { anchor: 6, head: 11 });
172
+ type(view, "*");
173
173
 
174
- const doc = view.state.doc.toString();
175
- expect(doc).not.toContain("*let x *");
176
- expect(doc).not.toContain("*let x ");
174
+ const doc = view.state.doc.toString();
175
+ expect(doc).not.toContain("*let x *");
176
+ expect(doc).not.toContain("*let x ");
177
177
 
178
- view.destroy();
179
- });
178
+ view.destroy();
179
+ });
180
180
 
181
- it("auto-pairs a lone backtick for inline code", () => {
182
- const view = createView("run ", 4);
183
- type(view, "`");
181
+ it("auto-pairs a lone backtick for inline code", () => {
182
+ const view = createView("run ", 4);
183
+ type(view, "`");
184
184
 
185
- expect(view.state.doc.toString()).toBe("run ``");
186
- expect(view.state.selection.main.from).toBe(5);
185
+ expect(view.state.doc.toString()).toBe("run ``");
186
+ expect(view.state.selection.main.from).toBe(5);
187
187
 
188
- view.destroy();
189
- });
188
+ view.destroy();
189
+ });
190
190
 
191
- it("auto-pairs and steps over brackets", () => {
192
- const view = createView("", 0);
193
- type(view, "(");
194
- expect(view.state.doc.toString()).toBe("()");
195
- expect(view.state.selection.main.from).toBe(1);
191
+ it("auto-pairs and steps over brackets", () => {
192
+ const view = createView("", 0);
193
+ type(view, "(");
194
+ expect(view.state.doc.toString()).toBe("()");
195
+ expect(view.state.selection.main.from).toBe(1);
196
196
 
197
- type(view, ")");
198
- expect(view.state.doc.toString()).toBe("()");
199
- expect(view.state.selection.main.from).toBe(2);
197
+ type(view, ")");
198
+ expect(view.state.doc.toString()).toBe("()");
199
+ expect(view.state.selection.main.from).toBe(2);
200
200
 
201
- view.destroy();
202
- });
201
+ view.destroy();
202
+ });
203
203
 
204
- it("does not double a closing bracket that was not auto-paired", () => {
205
- const view = createView("foo", 3);
206
- type(view, ")");
204
+ it("does not double a closing bracket that was not auto-paired", () => {
205
+ const view = createView("foo", 3);
206
+ type(view, ")");
207
207
 
208
- expect(view.state.doc.toString()).toBe("foo)");
208
+ expect(view.state.doc.toString()).toBe("foo)");
209
209
 
210
- view.destroy();
211
- });
210
+ view.destroy();
211
+ });
212
212
 
213
- it("suppresses emphasis auto-pairing directly in front of a word", () => {
214
- const view = createView("word", 0);
215
- type(view, "*");
213
+ it("suppresses emphasis auto-pairing directly in front of a word", () => {
214
+ const view = createView("word", 0);
215
+ type(view, "*");
216
216
 
217
- expect(view.state.doc.toString()).toBe("*word");
218
- expect(view.state.selection.main.from).toBe(1);
217
+ expect(view.state.doc.toString()).toBe("*word");
218
+ expect(view.state.selection.main.from).toBe(1);
219
219
 
220
- view.destroy();
221
- });
220
+ view.destroy();
221
+ });
222
222
 
223
- it("deletes an empty auto-inserted pair with a single backspace", () => {
224
- const view = createView("", 0);
225
- type(view, "(");
226
- expect(view.state.doc.toString()).toBe("()");
223
+ it("deletes an empty auto-inserted pair with a single backspace", () => {
224
+ const view = createView("", 0);
225
+ type(view, "(");
226
+ expect(view.state.doc.toString()).toBe("()");
227
227
 
228
- backspace(view);
229
- expect(view.state.doc.toString()).toBe("");
230
- expect(view.state.selection.main.from).toBe(0);
228
+ backspace(view);
229
+ expect(view.state.doc.toString()).toBe("");
230
+ expect(view.state.selection.main.from).toBe(0);
231
231
 
232
- view.destroy();
233
- });
232
+ view.destroy();
233
+ });
234
234
 
235
- it("leaves a non-empty pair to the default backspace", () => {
236
- const view = createView("(x)", 2);
237
- // The pair handler declines (no empty pair around the caret), so the
238
- // default backspace binding is left to run.
239
- expect(backspace(view)).toBe(false);
240
- expect(view.state.doc.toString()).toBe("(x)");
235
+ it("leaves a non-empty pair to the default backspace", () => {
236
+ const view = createView("(x)", 2);
237
+ // The pair handler declines (no empty pair around the caret), so the
238
+ // default backspace binding is left to run.
239
+ expect(backspace(view)).toBe(false);
240
+ expect(view.state.doc.toString()).toBe("(x)");
241
241
 
242
- view.destroy();
243
- });
242
+ view.destroy();
243
+ });
244
244
  });