@lapismd/mira 0.0.3 → 0.0.5

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 (203) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/extensions/index.d.ts +7 -0
  3. package/dist/extensions/index.d.ts.map +1 -1
  4. package/dist/preview/editable-markdown-preview/editable-markdown-surface.svelte +20 -9
  5. package/dist/preview/editable-markdown-preview/editable-markdown-surface.svelte.d.ts.map +1 -1
  6. package/dist/preview/editable-markdown-preview/editing-session.d.ts +13 -0
  7. package/dist/preview/editable-markdown-preview/editing-session.d.ts.map +1 -0
  8. package/dist/preview/editable-markdown-preview/editing-session.js +50 -0
  9. package/dist/preview/editable-markdown-preview/editor-surface.svelte +13 -4
  10. package/dist/preview/editable-markdown-preview/editor-surface.svelte.d.ts +1 -0
  11. package/dist/preview/editable-markdown-preview/editor-surface.svelte.d.ts.map +1 -1
  12. package/dist/preview/editable-markdown-preview/serialized-writer.d.ts +5 -1
  13. package/dist/preview/editable-markdown-preview/serialized-writer.d.ts.map +1 -1
  14. package/dist/preview/editable-markdown-preview/serialized-writer.js +29 -0
  15. package/dist/preview/editable-markdown-preview.svelte +8 -6
  16. package/dist/preview/editable-markdown-preview.svelte.d.ts.map +1 -1
  17. package/package.json +6 -3
  18. package/dist/core/code-mirror.test.d.ts +0 -2
  19. package/dist/core/code-mirror.test.d.ts.map +0 -1
  20. package/dist/core/code-mirror.test.js +0 -68
  21. package/dist/core/images.test.d.ts +0 -2
  22. package/dist/core/images.test.d.ts.map +0 -1
  23. package/dist/core/images.test.js +0 -109
  24. package/dist/core/index.test.d.ts +0 -2
  25. package/dist/core/index.test.d.ts.map +0 -1
  26. package/dist/core/index.test.js +0 -11
  27. package/dist/core/markdown-actions.test.d.ts +0 -2
  28. package/dist/core/markdown-actions.test.d.ts.map +0 -1
  29. package/dist/core/markdown-actions.test.js +0 -182
  30. package/dist/extensions/doodle-dividers.test.d.ts +0 -2
  31. package/dist/extensions/doodle-dividers.test.d.ts.map +0 -1
  32. package/dist/extensions/doodle-dividers.test.js +0 -296
  33. package/dist/extensions/index.test.d.ts +0 -2
  34. package/dist/extensions/index.test.d.ts.map +0 -1
  35. package/dist/extensions/index.test.js +0 -283
  36. package/dist/index.test.d.ts +0 -2
  37. package/dist/index.test.d.ts.map +0 -1
  38. package/dist/index.test.js +0 -64
  39. package/dist/internal/appearance-context.test.d.ts +0 -2
  40. package/dist/internal/appearance-context.test.d.ts.map +0 -1
  41. package/dist/internal/appearance-context.test.js +0 -31
  42. package/dist/internal/codemirror/base/index.test.d.ts +0 -2
  43. package/dist/internal/codemirror/base/index.test.d.ts.map +0 -1
  44. package/dist/internal/codemirror/base/index.test.js +0 -303
  45. package/dist/internal/codemirror/base/search.test.d.ts +0 -2
  46. package/dist/internal/codemirror/base/search.test.d.ts.map +0 -1
  47. package/dist/internal/codemirror/base/search.test.js +0 -155
  48. package/dist/internal/codemirror/base/selection-toolbar.test.d.ts +0 -2
  49. package/dist/internal/codemirror/base/selection-toolbar.test.d.ts.map +0 -1
  50. package/dist/internal/codemirror/base/selection-toolbar.test.js +0 -149
  51. package/dist/internal/codemirror/markdown/authoring.test.d.ts +0 -2
  52. package/dist/internal/codemirror/markdown/authoring.test.d.ts.map +0 -1
  53. package/dist/internal/codemirror/markdown/authoring.test.js +0 -222
  54. package/dist/internal/codemirror/markdown/index.test.d.ts +0 -2
  55. package/dist/internal/codemirror/markdown/index.test.d.ts.map +0 -1
  56. package/dist/internal/codemirror/markdown/index.test.js +0 -158
  57. package/dist/internal/codemirror/markdown/showcase-fixture.test.d.ts +0 -2
  58. package/dist/internal/codemirror/markdown/showcase-fixture.test.d.ts.map +0 -1
  59. package/dist/internal/codemirror/markdown/showcase-fixture.test.js +0 -50
  60. package/dist/internal/codemirror/rich/block-controls.test.d.ts +0 -2
  61. package/dist/internal/codemirror/rich/block-controls.test.d.ts.map +0 -1
  62. package/dist/internal/codemirror/rich/block-controls.test.js +0 -401
  63. package/dist/internal/codemirror/rich/block-ranges.test.d.ts +0 -2
  64. package/dist/internal/codemirror/rich/block-ranges.test.d.ts.map +0 -1
  65. package/dist/internal/codemirror/rich/block-ranges.test.js +0 -310
  66. package/dist/internal/codemirror/rich/block-toolbar.test.d.ts +0 -2
  67. package/dist/internal/codemirror/rich/block-toolbar.test.d.ts.map +0 -1
  68. package/dist/internal/codemirror/rich/block-toolbar.test.js +0 -178
  69. package/dist/internal/codemirror/rich/decorations/fold-indicators.test.d.ts +0 -2
  70. package/dist/internal/codemirror/rich/decorations/fold-indicators.test.d.ts.map +0 -1
  71. package/dist/internal/codemirror/rich/decorations/fold-indicators.test.js +0 -8
  72. package/dist/internal/codemirror/rich/index.test.d.ts +0 -2
  73. package/dist/internal/codemirror/rich/index.test.d.ts.map +0 -1
  74. package/dist/internal/codemirror/rich/index.test.js +0 -607
  75. package/dist/internal/codemirror/rich/utils/code-block-lines.test.d.ts +0 -2
  76. package/dist/internal/codemirror/rich/utils/code-block-lines.test.d.ts.map +0 -1
  77. package/dist/internal/codemirror/rich/utils/code-block-lines.test.js +0 -82
  78. package/dist/internal/codemirror/rich/utils/fenced-code.test.d.ts +0 -2
  79. package/dist/internal/codemirror/rich/utils/fenced-code.test.d.ts.map +0 -1
  80. package/dist/internal/codemirror/rich/utils/fenced-code.test.js +0 -12
  81. package/dist/internal/codemirror/rich/utils/headings.test.d.ts +0 -2
  82. package/dist/internal/codemirror/rich/utils/headings.test.d.ts.map +0 -1
  83. package/dist/internal/codemirror/rich/utils/headings.test.js +0 -27
  84. package/dist/internal/codemirror/rich/utils/height-estimates.test.d.ts +0 -2
  85. package/dist/internal/codemirror/rich/utils/height-estimates.test.d.ts.map +0 -1
  86. package/dist/internal/codemirror/rich/utils/height-estimates.test.js +0 -10
  87. package/dist/internal/codemirror/rich/utils/images.test.d.ts +0 -2
  88. package/dist/internal/codemirror/rich/utils/images.test.d.ts.map +0 -1
  89. package/dist/internal/codemirror/rich/utils/images.test.js +0 -37
  90. package/dist/internal/codemirror/rich/utils/indent.test.d.ts +0 -2
  91. package/dist/internal/codemirror/rich/utils/indent.test.d.ts.map +0 -1
  92. package/dist/internal/codemirror/rich/utils/indent.test.js +0 -169
  93. package/dist/internal/codemirror/rich/utils/inline-math.test.d.ts +0 -2
  94. package/dist/internal/codemirror/rich/utils/inline-math.test.d.ts.map +0 -1
  95. package/dist/internal/codemirror/rich/utils/inline-math.test.js +0 -15
  96. package/dist/internal/codemirror/rich/utils/links.test.d.ts +0 -2
  97. package/dist/internal/codemirror/rich/utils/links.test.d.ts.map +0 -1
  98. package/dist/internal/codemirror/rich/utils/links.test.js +0 -28
  99. package/dist/internal/codemirror/rich/utils/list-callouts.test.d.ts +0 -2
  100. package/dist/internal/codemirror/rich/utils/list-callouts.test.d.ts.map +0 -1
  101. package/dist/internal/codemirror/rich/utils/list-callouts.test.js +0 -47
  102. package/dist/internal/codemirror/rich/utils/measured-indent.test.d.ts +0 -2
  103. package/dist/internal/codemirror/rich/utils/measured-indent.test.d.ts.map +0 -1
  104. package/dist/internal/codemirror/rich/utils/measured-indent.test.js +0 -102
  105. package/dist/internal/codemirror/rich/utils/ranges.test.d.ts +0 -2
  106. package/dist/internal/codemirror/rich/utils/ranges.test.d.ts.map +0 -1
  107. package/dist/internal/codemirror/rich/utils/ranges.test.js +0 -22
  108. package/dist/internal/codemirror/rich/utils/tasks.test.d.ts +0 -2
  109. package/dist/internal/codemirror/rich/utils/tasks.test.d.ts.map +0 -1
  110. package/dist/internal/codemirror/rich/utils/tasks.test.js +0 -57
  111. package/dist/internal/task-states.test.d.ts +0 -2
  112. package/dist/internal/task-states.test.d.ts.map +0 -1
  113. package/dist/internal/task-states.test.js +0 -36
  114. package/dist/mira-code-editor.test.d.ts +0 -2
  115. package/dist/mira-code-editor.test.d.ts.map +0 -1
  116. package/dist/mira-code-editor.test.js +0 -93
  117. package/dist/mode-position.test.d.ts +0 -2
  118. package/dist/mode-position.test.d.ts.map +0 -1
  119. package/dist/mode-position.test.js +0 -60
  120. package/dist/preview/code-language.test.d.ts +0 -2
  121. package/dist/preview/code-language.test.d.ts.map +0 -1
  122. package/dist/preview/code-language.test.js +0 -12
  123. package/dist/preview/components/icon.test.d.ts +0 -2
  124. package/dist/preview/components/icon.test.d.ts.map +0 -1
  125. package/dist/preview/components/icon.test.js +0 -20
  126. package/dist/preview/editable-markdown-preview/behavior.test.d.ts +0 -2
  127. package/dist/preview/editable-markdown-preview/behavior.test.d.ts.map +0 -1
  128. package/dist/preview/editable-markdown-preview/behavior.test.js +0 -36
  129. package/dist/preview/editable-markdown-preview/serialized-writer.test.d.ts +0 -2
  130. package/dist/preview/editable-markdown-preview/serialized-writer.test.d.ts.map +0 -1
  131. package/dist/preview/editable-markdown-preview/serialized-writer.test.js +0 -59
  132. package/dist/preview/embed-target.test.d.ts +0 -2
  133. package/dist/preview/embed-target.test.d.ts.map +0 -1
  134. package/dist/preview/embed-target.test.js +0 -78
  135. package/dist/preview/frontmatter/frontmatter.test.d.ts +0 -2
  136. package/dist/preview/frontmatter/frontmatter.test.d.ts.map +0 -1
  137. package/dist/preview/frontmatter/frontmatter.test.js +0 -190
  138. package/dist/preview/frontmatter/suggestions.test.d.ts +0 -2
  139. package/dist/preview/frontmatter/suggestions.test.d.ts.map +0 -1
  140. package/dist/preview/frontmatter/suggestions.test.js +0 -45
  141. package/dist/preview/outline.test.d.ts +0 -2
  142. package/dist/preview/outline.test.d.ts.map +0 -1
  143. package/dist/preview/outline.test.js +0 -98
  144. package/dist/preview/portable-surfaces.test.d.ts +0 -2
  145. package/dist/preview/portable-surfaces.test.d.ts.map +0 -1
  146. package/dist/preview/portable-surfaces.test.js +0 -513
  147. package/dist/preview/preview.test.d.ts +0 -2
  148. package/dist/preview/preview.test.d.ts.map +0 -1
  149. package/dist/preview/preview.test.js +0 -154
  150. package/dist/preview/remark/callouts.test.d.ts +0 -2
  151. package/dist/preview/remark/callouts.test.d.ts.map +0 -1
  152. package/dist/preview/remark/callouts.test.js +0 -23
  153. package/dist/preview/remark/custom-checklists.test.d.ts +0 -2
  154. package/dist/preview/remark/custom-checklists.test.d.ts.map +0 -1
  155. package/dist/preview/remark/custom-checklists.test.js +0 -51
  156. package/dist/preview/remark/links.test.d.ts +0 -2
  157. package/dist/preview/remark/links.test.d.ts.map +0 -1
  158. package/dist/preview/remark/links.test.js +0 -62
  159. package/dist/preview/remark/parity.test.d.ts +0 -2
  160. package/dist/preview/remark/parity.test.d.ts.map +0 -1
  161. package/dist/preview/remark/parity.test.js +0 -105
  162. package/dist/preview/styles/frontmatter-properties.test.d.ts +0 -2
  163. package/dist/preview/styles/frontmatter-properties.test.d.ts.map +0 -1
  164. package/dist/preview/styles/frontmatter-properties.test.js +0 -57
  165. package/dist/preview/styles/source-mode.test.d.ts +0 -2
  166. package/dist/preview/styles/source-mode.test.d.ts.map +0 -1
  167. package/dist/preview/styles/source-mode.test.js +0 -28
  168. package/dist/tables/extension.test.d.ts +0 -2
  169. package/dist/tables/extension.test.d.ts.map +0 -1
  170. package/dist/tables/extension.test.js +0 -100
  171. package/dist/tables/grid-editor-column.test.d.ts +0 -2
  172. package/dist/tables/grid-editor-column.test.d.ts.map +0 -1
  173. package/dist/tables/grid-editor-column.test.js +0 -27
  174. package/dist/tables/grid-table.test.d.ts +0 -2
  175. package/dist/tables/grid-table.test.d.ts.map +0 -1
  176. package/dist/tables/grid-table.test.js +0 -140
  177. package/dist/tables/index.test.d.ts +0 -2
  178. package/dist/tables/index.test.d.ts.map +0 -1
  179. package/dist/tables/index.test.js +0 -7
  180. package/dist/tables/inline-editor-extensions.test.d.ts +0 -2
  181. package/dist/tables/inline-editor-extensions.test.d.ts.map +0 -1
  182. package/dist/tables/inline-editor-extensions.test.js +0 -23
  183. package/dist/tables/pipe-table.test.d.ts +0 -2
  184. package/dist/tables/pipe-table.test.d.ts.map +0 -1
  185. package/dist/tables/pipe-table.test.js +0 -13
  186. package/dist/tables/table-node.test.d.ts +0 -2
  187. package/dist/tables/table-node.test.d.ts.map +0 -1
  188. package/dist/tables/table-node.test.js +0 -167
  189. package/dist/tables/widgets/source-button.test.d.ts +0 -2
  190. package/dist/tables/widgets/source-button.test.d.ts.map +0 -1
  191. package/dist/tables/widgets/source-button.test.js +0 -11
  192. package/dist/themes/theme-contract.test.d.ts +0 -2
  193. package/dist/themes/theme-contract.test.d.ts.map +0 -1
  194. package/dist/themes/theme-contract.test.js +0 -88
  195. package/dist/ui/index.test.d.ts +0 -2
  196. package/dist/ui/index.test.d.ts.map +0 -1
  197. package/dist/ui/index.test.js +0 -7
  198. package/dist/ui/styles.test.d.ts +0 -2
  199. package/dist/ui/styles.test.d.ts.map +0 -1
  200. package/dist/ui/styles.test.js +0 -26
  201. package/dist/ui/table-dnd/table-dnd-utils.test.d.ts +0 -2
  202. package/dist/ui/table-dnd/table-dnd-utils.test.d.ts.map +0 -1
  203. package/dist/ui/table-dnd/table-dnd-utils.test.js +0 -46
@@ -1,310 +0,0 @@
1
- import { EditorState } from "@codemirror/state";
2
- import { EditorView } from "@codemirror/view";
3
- import { describe, expect, it } from "vitest";
4
- import { collectMarkdownBlockHandles, collectMarkdownBlockRanges, deleteMarkdownBlockRange, duplicateMarkdownBlockRange, moveMarkdownBlockHandle, moveMarkdownBlockRange, } from "./block-ranges";
5
- function state(markdown) {
6
- return EditorState.create({ doc: markdown });
7
- }
8
- function createView(markdown) {
9
- const parent = document.createElement("div");
10
- document.body.append(parent);
11
- const view = new EditorView({
12
- doc: markdown,
13
- parent,
14
- });
15
- return {
16
- view,
17
- destroy() {
18
- view.destroy();
19
- parent.remove();
20
- },
21
- };
22
- }
23
- describe("collectMarkdownBlockRanges", () => {
24
- it("collects Markdown-first block ranges across Mira block types", () => {
25
- const blocks = collectMarkdownBlockRanges(state(`---
26
- title: Demo
27
- ---
28
-
29
- # Heading
30
-
31
- Paragraph one
32
- continued.
33
-
34
- > [!note]
35
- > Callout body
36
-
37
- - item
38
- - child
39
- continuation
40
-
41
- \`\`\`mermaid
42
- graph TD;
43
- \`\`\`
44
-
45
- | A | B |
46
- | --- | --- |
47
- | 1 | 2 |
48
-
49
- +---+---+
50
- | A | B |
51
- +===+===+
52
- | C | D |
53
- +---+---+
54
-
55
- ![[image.png]]
56
-
57
- $$
58
- x=1
59
- $$
60
-
61
- <div>
62
- html
63
- </div>
64
-
65
- ---
66
-
67
- :::note
68
- directive
69
- :::
70
- `));
71
- expect(blocks.map((block) => block.kind)).toEqual([
72
- "frontmatter",
73
- "heading",
74
- "paragraph",
75
- "blockquote",
76
- "list",
77
- "code",
78
- "table",
79
- "grid-table",
80
- "embed",
81
- "math",
82
- "html",
83
- "thematic-break",
84
- "directive",
85
- ]);
86
- expect(blocks.find((block) => block.kind === "list")?.text).toContain("continuation");
87
- expect(blocks.find((block) => block.kind === "directive")?.text).toBe(":::note\ndirective\n:::");
88
- });
89
- it("treats a seeded divider comment and rule as one logical block", () => {
90
- const blocks = collectMarkdownBlockRanges(state(`Alpha
91
-
92
- <!-- mira-divider:v1:00000001 -->
93
- ---
94
-
95
- Beta`));
96
- expect(blocks.map(({ kind, startLine, endLine }) => ({
97
- kind,
98
- startLine,
99
- endLine,
100
- }))).toEqual([
101
- { kind: "paragraph", startLine: 1, endLine: 1 },
102
- { kind: "thematic-break", startLine: 3, endLine: 4 },
103
- { kind: "paragraph", startLine: 6, endLine: 6 },
104
- ]);
105
- expect(blocks[1]?.text).toBe("<!-- mira-divider:v1:00000001 -->\n---");
106
- });
107
- });
108
- describe("collectMarkdownBlockHandles", () => {
109
- it("expands heading handles to their section subtree", () => {
110
- const handles = collectMarkdownBlockHandles(state(`# One
111
-
112
- Intro
113
-
114
- ## Two
115
-
116
- Nested
117
-
118
- # Three
119
-
120
- Tail
121
- `));
122
- const one = handles.find((handle) => handle.id === "line-1");
123
- const two = handles.find((handle) => handle.id === "line-5");
124
- expect(one.role).toBe("heading-section");
125
- expect(one.headingLevel).toBe(1);
126
- expect(one.affectedRange.text).toBe("# One\n\nIntro\n\n## Two\n\nNested");
127
- expect(two.role).toBe("heading-section");
128
- expect(two.headingLevel).toBe(2);
129
- expect(two.affectedRange.text).toBe("## Two\n\nNested");
130
- });
131
- it("expands setext heading handles by heading level", () => {
132
- const handles = collectMarkdownBlockHandles(state(`Title
133
- =====
134
-
135
- Intro
136
-
137
- Next
138
- ----
139
-
140
- Nested
141
- `));
142
- const title = handles.find((handle) => handle.id === "line-1");
143
- const next = handles.find((handle) => handle.id === "line-6");
144
- expect(title.headingLevel).toBe(1);
145
- expect(title.affectedRange.text).toBe("Title\n=====\n\nIntro\n\nNext\n----\n\nNested\n");
146
- expect(next.headingLevel).toBe(2);
147
- expect(next.affectedRange.text).toBe("Next\n----\n\nNested\n");
148
- });
149
- it("creates one handle for each list item with nested affected ranges", () => {
150
- const handles = collectMarkdownBlockHandles(state(`- parent
151
- continuation
152
- - child
153
- nested
154
- - sibling
155
- `)).filter((handle) => handle.role === "list-item");
156
- expect(handles.map((handle) => handle.id)).toEqual([
157
- "list-item-1",
158
- "list-item-3",
159
- "list-item-5",
160
- ]);
161
- expect(handles[0]?.affectedRange.text).toBe("- parent\n continuation\n - child\n nested");
162
- expect(handles[1]?.parentId).toBe("list-item-1");
163
- expect(handles[1]?.affectedRange.text).toBe(" - child\n nested");
164
- expect(handles[2]?.listIndent).toBe(0);
165
- });
166
- it("records bullet, ordered, and custom task list semantics", () => {
167
- const handles = collectMarkdownBlockHandles(state(`- bullet
168
- 1. ordered
169
- * [?] custom task
170
- `)).filter((handle) => handle.role === "list-item");
171
- expect(handles.map(({ listKind, taskMarker }) => ({ listKind, taskMarker }))).toEqual([
172
- { listKind: "bullet", taskMarker: undefined },
173
- { listKind: "numbered", taskMarker: undefined },
174
- { listKind: "task", taskMarker: "?" },
175
- ]);
176
- });
177
- });
178
- describe("Markdown block mutations", () => {
179
- it("moves blocks while preserving blank-line separation", () => {
180
- const editor = createView("# One\n\nAlpha\n\nBeta\n");
181
- const blocks = collectMarkdownBlockRanges(editor.view.state);
182
- const alpha = blocks.find((block) => block.text === "Alpha");
183
- const beta = blocks.find((block) => block.text === "Beta");
184
- expect(moveMarkdownBlockRange(editor.view, beta, {
185
- block: alpha,
186
- position: "before",
187
- })).toBe(true);
188
- expect(editor.view.state.doc.toString()).toBe("# One\n\nBeta\n\nAlpha\n");
189
- editor.destroy();
190
- });
191
- it("duplicates blocks with normalized surrounding newlines", () => {
192
- const editor = createView("Alpha\n\nBeta\n");
193
- const [alpha] = collectMarkdownBlockRanges(editor.view.state);
194
- duplicateMarkdownBlockRange(editor.view, alpha);
195
- expect(editor.view.state.doc.toString()).toBe("Alpha\n\nAlpha\n\nBeta\n");
196
- editor.destroy();
197
- });
198
- it("moves and deletes a seeded divider as one authored pair", () => {
199
- const editor = createView(`Alpha
200
-
201
- <!-- mira-divider:v1:00000001 -->
202
- ---
203
-
204
- Beta
205
- `);
206
- let blocks = collectMarkdownBlockRanges(editor.view.state);
207
- const divider = blocks.find((block) => block.kind === "thematic-break");
208
- const beta = blocks.find((block) => block.text === "Beta");
209
- expect(moveMarkdownBlockRange(editor.view, divider, {
210
- block: beta,
211
- position: "after",
212
- })).toBe(true);
213
- expect(editor.view.state.doc.toString()).toBe(`Alpha
214
-
215
- Beta
216
-
217
- <!-- mira-divider:v1:00000001 -->
218
- ---
219
- `);
220
- blocks = collectMarkdownBlockRanges(editor.view.state);
221
- deleteMarkdownBlockRange(editor.view, blocks.find((block) => block.kind === "thematic-break"));
222
- expect(editor.view.state.doc.toString()).toBe("Alpha\n\nBeta\n\n");
223
- editor.destroy();
224
- });
225
- it("deletes blocks without leaving extra blank lines", () => {
226
- const editor = createView("Alpha\n\nBeta\n\nGamma\n");
227
- const beta = collectMarkdownBlockRanges(editor.view.state).find((block) => block.text === "Beta");
228
- deleteMarkdownBlockRange(editor.view, beta);
229
- expect(editor.view.state.doc.toString()).toBe("Alpha\n\nGamma\n");
230
- editor.destroy();
231
- });
232
- it("moves heading handles as whole sections", () => {
233
- const editor = createView(`# One
234
-
235
- Intro
236
-
237
- ## Two
238
-
239
- Nested
240
-
241
- # Three
242
- `);
243
- const handles = collectMarkdownBlockHandles(editor.view.state);
244
- const one = handles.find((handle) => handle.id === "line-1");
245
- const three = handles.find((handle) => handle.id === "line-9");
246
- expect(moveMarkdownBlockHandle(editor.view, one, {
247
- handle: three,
248
- position: "after",
249
- })).toBe(true);
250
- expect(editor.view.state.doc.toString()).toBe(`# Three
251
-
252
- # One
253
-
254
- Intro
255
-
256
- ## Two
257
-
258
- Nested
259
- `);
260
- editor.destroy();
261
- });
262
- it("moves list item subtrees before and after siblings without blank separators", () => {
263
- const editor = createView("- one\n- two\n - child\n- three\n");
264
- const handles = collectMarkdownBlockHandles(editor.view.state);
265
- const two = handles.find((handle) => handle.id === "list-item-2");
266
- const one = handles.find((handle) => handle.id === "list-item-1");
267
- expect(moveMarkdownBlockHandle(editor.view, two, {
268
- handle: one,
269
- position: "before",
270
- })).toBe(true);
271
- expect(editor.view.state.doc.toString()).toBe("- two\n - child\n- one\n- three\n");
272
- editor.destroy();
273
- });
274
- it("moves list items inside other list items and normalizes indentation", () => {
275
- const editor = createView("- parent\n- child\n");
276
- const handles = collectMarkdownBlockHandles(editor.view.state);
277
- const child = handles.find((handle) => handle.id === "list-item-2");
278
- const parent = handles.find((handle) => handle.id === "list-item-1");
279
- expect(moveMarkdownBlockHandle(editor.view, child, {
280
- handle: parent,
281
- position: "inside",
282
- })).toBe(true);
283
- expect(editor.view.state.doc.toString()).toBe("- parent\n - child\n");
284
- editor.destroy();
285
- });
286
- it("normalizes nested list items to top-level when moved outside lists", () => {
287
- const editor = createView("Intro\n\n- parent\n - child\n\nOutro\n");
288
- const handles = collectMarkdownBlockHandles(editor.view.state);
289
- const child = handles.find((handle) => handle.id === "list-item-4");
290
- const outro = handles.find((handle) => handle.id === "line-6");
291
- expect(moveMarkdownBlockHandle(editor.view, child, {
292
- handle: outro,
293
- position: "before",
294
- })).toBe(true);
295
- expect(editor.view.state.doc.toString()).toBe("Intro\n\n- parent\n\n- child\n\nOutro\n");
296
- editor.destroy();
297
- });
298
- it("rejects moving a handle into its own affected range", () => {
299
- const editor = createView("- parent\n - child\n- sibling\n");
300
- const handles = collectMarkdownBlockHandles(editor.view.state);
301
- const parent = handles.find((handle) => handle.id === "list-item-1");
302
- const child = handles.find((handle) => handle.id === "list-item-2");
303
- expect(moveMarkdownBlockHandle(editor.view, parent, {
304
- handle: child,
305
- position: "inside",
306
- })).toBe(false);
307
- expect(editor.view.state.doc.toString()).toBe("- parent\n - child\n- sibling\n");
308
- editor.destroy();
309
- });
310
- });
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=block-toolbar.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"block-toolbar.test.d.ts","sourceRoot":"","sources":["../../../../src/internal/codemirror/rich/block-toolbar.test.ts"],"names":[],"mappings":""}
@@ -1,178 +0,0 @@
1
- import { history, undo } from "@codemirror/commands";
2
- import { EditorView } from "@codemirror/view";
3
- import { describe, expect, it, vi } from "vitest";
4
- import { collectMarkdownBlockHandles } from "./block-ranges";
5
- import { applyBlockToolbarItem, blockPresentation, canApplyBlockToolbarItem, defaultMiraBlockToolbarItems, resolveMiraBlockControlsOptions, } from "./block-toolbar";
6
- function editor(markdown) {
7
- const parent = document.createElement("div");
8
- document.body.append(parent);
9
- const view = new EditorView({
10
- doc: markdown,
11
- extensions: [history()],
12
- parent,
13
- });
14
- return {
15
- view,
16
- destroy() {
17
- view.destroy();
18
- parent.remove();
19
- },
20
- };
21
- }
22
- function handleAt(view, line) {
23
- return collectMarkdownBlockHandles(view.state).find((handle) => handle.handleRange.startLine === line);
24
- }
25
- describe("contextual block toolbar", () => {
26
- it("keeps the existing boolean contract and enables the toolbar explicitly", () => {
27
- expect(resolveMiraBlockControlsOptions(true)).toEqual({
28
- enabled: true,
29
- toolbar: null,
30
- });
31
- expect(resolveMiraBlockControlsOptions({ enabled: true, toolbar: true })).toEqual({
32
- enabled: true,
33
- toolbar: {
34
- ariaLabel: "Change block type",
35
- items: defaultMiraBlockToolbarItems,
36
- },
37
- });
38
- expect(resolveMiraBlockControlsOptions({
39
- toolbar: {
40
- ariaLabel: "Block style",
41
- items: ["paragraph", "paragraph"],
42
- },
43
- })).toEqual({
44
- enabled: true,
45
- toolbar: { ariaLabel: "Block style", items: ["paragraph"] },
46
- });
47
- });
48
- it("resolves semantic presentations for tasks, headings, paragraphs, and rich blocks", () => {
49
- const fixture = editor(`# Heading
50
-
51
- Paragraph
52
-
53
- - [?] Task
54
-
55
- \`\`\`ts
56
- code
57
- \`\`\`
58
- `);
59
- const handles = collectMarkdownBlockHandles(fixture.view.state);
60
- expect(blockPresentation(handles[0])).toMatchObject({
61
- icon: "heading1",
62
- label: "Heading 1",
63
- type: "heading1",
64
- });
65
- expect(blockPresentation(handles[1])).toMatchObject({
66
- icon: "paragraph",
67
- type: "paragraph",
68
- });
69
- expect(blockPresentation(handles[2])).toMatchObject({
70
- icon: "task",
71
- type: "task",
72
- });
73
- expect(blockPresentation(handles[3])).toMatchObject({
74
- icon: "code",
75
- type: null,
76
- });
77
- fixture.destroy();
78
- });
79
- it("converts structural prefixes without changing content", () => {
80
- const fixture = editor("Paragraph");
81
- const handle = handleAt(fixture.view, 1);
82
- expect(applyBlockToolbarItem(fixture.view, handle, "heading2")).toBe(true);
83
- expect(fixture.view.state.doc.toString()).toBe("## Paragraph");
84
- expect(applyBlockToolbarItem(fixture.view, handleAt(fixture.view, 1), "task")).toBe(true);
85
- expect(fixture.view.state.doc.toString()).toBe("- [ ] Paragraph");
86
- expect(applyBlockToolbarItem(fixture.view, handleAt(fixture.view, 1), "numberedList")).toBe(true);
87
- expect(fixture.view.state.doc.toString()).toBe("1. Paragraph");
88
- fixture.destroy();
89
- });
90
- it.each([
91
- ["Paragraph", "heading1", "# Paragraph"],
92
- ["Paragraph", "heading3", "### Paragraph"],
93
- ["Paragraph", "bulletList", "- Paragraph"],
94
- ["Paragraph", "quote", "> Paragraph"],
95
- ["* Item", "paragraph", "Item"],
96
- ])("converts %s to %s", (markdown, item, expected) => {
97
- const fixture = editor(markdown);
98
- expect(applyBlockToolbarItem(fixture.view, handleAt(fixture.view, 1), item)).toBe(true);
99
- expect(fixture.view.state.doc.toString()).toBe(expected);
100
- fixture.destroy();
101
- });
102
- it("treats the current structural type as a no-op", () => {
103
- const fixture = editor("## Heading");
104
- expect(applyBlockToolbarItem(fixture.view, handleAt(fixture.view, 1), "heading2")).toBe(false);
105
- expect(fixture.view.state.doc.toString()).toBe("## Heading");
106
- fixture.destroy();
107
- });
108
- it("preserves indentation and outer quote ancestry", () => {
109
- const fixture = editor(" > > - [x] Nested task");
110
- let handle = handleAt(fixture.view, 1);
111
- expect(applyBlockToolbarItem(fixture.view, handle, "heading3")).toBe(true);
112
- expect(fixture.view.state.doc.toString()).toBe(" > > ### Nested task");
113
- handle = handleAt(fixture.view, 1);
114
- expect(applyBlockToolbarItem(fixture.view, handle, "paragraph")).toBe(true);
115
- expect(fixture.view.state.doc.toString()).toBe(" > > Nested task");
116
- handle = handleAt(fixture.view, 1);
117
- expect(applyBlockToolbarItem(fixture.view, handle, "paragraph")).toBe(true);
118
- expect(fixture.view.state.doc.toString()).toBe(" > Nested task");
119
- fixture.destroy();
120
- });
121
- it("normalizes setext headings and compatible list markers", () => {
122
- const setext = editor("Title\n=====");
123
- expect(applyBlockToolbarItem(setext.view, handleAt(setext.view, 1), "heading3")).toBe(true);
124
- expect(setext.view.state.doc.toString()).toBe("### Title");
125
- setext.destroy();
126
- const list = editor("+ [!] Important");
127
- expect(applyBlockToolbarItem(list.view, handleAt(list.view, 1), "bulletList")).toBe(true);
128
- expect(list.view.state.doc.toString()).toBe("- Important");
129
- list.destroy();
130
- });
131
- it("disables structural conversion for rich blocks", () => {
132
- const fixture = editor("```ts\ncode\n```");
133
- const handle = handleAt(fixture.view, 1);
134
- expect(canApplyBlockToolbarItem(handle, "paragraph")).toBe(false);
135
- expect(applyBlockToolbarItem(fixture.view, handle, "paragraph")).toBe(false);
136
- expect(fixture.view.state.doc.toString()).toBe("```ts\ncode\n```");
137
- fixture.destroy();
138
- });
139
- it("inserts a divider after a non-empty block", () => {
140
- const fixture = editor("Alpha\n\nBeta");
141
- expect(applyBlockToolbarItem(fixture.view, handleAt(fixture.view, 1), "divider")).toBe(true);
142
- expect(fixture.view.state.doc.toString()).toBe("Alpha\n\n---\n\nBeta");
143
- fixture.destroy();
144
- });
145
- it("targets a blank block boundary before invoking the image action", () => {
146
- const fixture = editor("Alpha\n\nBeta");
147
- const insertImage = vi.fn();
148
- expect(applyBlockToolbarItem(fixture.view, handleAt(fixture.view, 1), "image", {
149
- insertImage,
150
- })).toBe(true);
151
- expect(insertImage).toHaveBeenCalledOnce();
152
- expect(fixture.view.state.selection.main.head).toBe(6);
153
- expect(fixture.view.state.doc.toString()).toBe("Alpha\n\nBeta");
154
- fixture.destroy();
155
- });
156
- it("keeps conversions in one undo step", () => {
157
- const fixture = editor("Paragraph");
158
- applyBlockToolbarItem(fixture.view, handleAt(fixture.view, 1), "heading1");
159
- expect(fixture.view.state.doc.toString()).toBe("# Paragraph");
160
- expect(undo(fixture.view)).toBe(true);
161
- expect(fixture.view.state.doc.toString()).toBe("Paragraph");
162
- fixture.destroy();
163
- });
164
- it("preserves backward selection, focus, and scroll geometry", () => {
165
- const fixture = editor("Paragraph");
166
- fixture.view.dispatch({ selection: { anchor: 8, head: 2 } });
167
- fixture.view.scrollDOM.scrollTop = 12;
168
- fixture.view.scrollDOM.scrollLeft = 3;
169
- applyBlockToolbarItem(fixture.view, handleAt(fixture.view, 1), "heading1");
170
- expect(fixture.view.state.selection.main.anchor).toBe(10);
171
- expect(fixture.view.state.selection.main.head).toBe(4);
172
- expect(fixture.view.state.selection.main.anchor).toBeGreaterThan(fixture.view.state.selection.main.head);
173
- expect(fixture.view.scrollDOM.scrollTop).toBe(12);
174
- expect(fixture.view.scrollDOM.scrollLeft).toBe(3);
175
- expect(fixture.view.hasFocus).toBe(true);
176
- fixture.destroy();
177
- });
178
- });
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=fold-indicators.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"fold-indicators.test.d.ts","sourceRoot":"","sources":["../../../../../src/internal/codemirror/rich/decorations/fold-indicators.test.ts"],"names":[],"mappings":""}
@@ -1,8 +0,0 @@
1
- import { describe, expect, it } from "vitest";
2
- import { getFoldAnchor } from "./fold-indicators";
3
- describe("fold indicators", () => {
4
- it("anchors fold indicators at the first content character", () => {
5
- expect(getFoldAnchor({ from: 10, text: " ## Heading" })).toBe(12);
6
- expect(getFoldAnchor({ from: 10, text: "## Heading" })).toBe(10);
7
- });
8
- });
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=index.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.test.d.ts","sourceRoot":"","sources":["../../../../src/internal/codemirror/rich/index.test.ts"],"names":[],"mappings":""}