@agent-native/toolkit 0.4.10 → 0.5.0

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 (143) hide show
  1. package/README.md +17 -6
  2. package/dist/collab-ui/agent-identity.d.ts +9 -0
  3. package/dist/collab-ui/agent-identity.d.ts.map +1 -0
  4. package/dist/collab-ui/agent-identity.js +9 -0
  5. package/dist/collab-ui/agent-identity.js.map +1 -0
  6. package/dist/collab-ui/index.d.ts +2 -0
  7. package/dist/collab-ui/index.d.ts.map +1 -1
  8. package/dist/collab-ui/index.js +2 -0
  9. package/dist/collab-ui/index.js.map +1 -1
  10. package/dist/collab-ui/lead-client.d.ts +3 -0
  11. package/dist/collab-ui/lead-client.d.ts.map +1 -0
  12. package/dist/collab-ui/lead-client.js +29 -0
  13. package/dist/collab-ui/lead-client.js.map +1 -0
  14. package/dist/context-ui/ContextMeter.d.ts +10 -0
  15. package/dist/context-ui/ContextMeter.d.ts.map +1 -0
  16. package/dist/context-ui/ContextMeter.js +20 -0
  17. package/dist/context-ui/ContextMeter.js.map +1 -0
  18. package/dist/context-ui/ContextSegmentRow.d.ts +14 -0
  19. package/dist/context-ui/ContextSegmentRow.d.ts.map +1 -0
  20. package/dist/context-ui/ContextSegmentRow.js +25 -0
  21. package/dist/context-ui/ContextSegmentRow.js.map +1 -0
  22. package/dist/context-ui/ContextTreemap.d.ts +7 -0
  23. package/dist/context-ui/ContextTreemap.d.ts.map +1 -0
  24. package/dist/context-ui/ContextTreemap.js +55 -0
  25. package/dist/context-ui/ContextTreemap.js.map +1 -0
  26. package/dist/context-ui/ContextXRayPanel.d.ts +13 -0
  27. package/dist/context-ui/ContextXRayPanel.d.ts.map +1 -0
  28. package/dist/context-ui/ContextXRayPanel.js +120 -0
  29. package/dist/context-ui/ContextXRayPanel.js.map +1 -0
  30. package/dist/context-ui/format.d.ts +6 -0
  31. package/dist/context-ui/format.d.ts.map +1 -0
  32. package/dist/context-ui/format.js +58 -0
  33. package/dist/context-ui/format.js.map +1 -0
  34. package/dist/context-ui/index.d.ts +7 -0
  35. package/dist/context-ui/index.d.ts.map +1 -0
  36. package/dist/context-ui/index.js +6 -0
  37. package/dist/context-ui/index.js.map +1 -0
  38. package/dist/context-ui/types.d.ts +39 -0
  39. package/dist/context-ui/types.d.ts.map +1 -0
  40. package/dist/context-ui/types.js +2 -0
  41. package/dist/context-ui/types.js.map +1 -0
  42. package/dist/design-tweaks/index.d.ts +2 -0
  43. package/dist/design-tweaks/index.d.ts.map +1 -0
  44. package/dist/design-tweaks/index.js +2 -0
  45. package/dist/design-tweaks/index.js.map +1 -0
  46. package/dist/design-tweaks/visual-style-controls.d.ts +90 -0
  47. package/dist/design-tweaks/visual-style-controls.d.ts.map +1 -0
  48. package/dist/design-tweaks/visual-style-controls.js +499 -0
  49. package/dist/design-tweaks/visual-style-controls.js.map +1 -0
  50. package/dist/editor/BubbleToolbar.d.ts +37 -0
  51. package/dist/editor/BubbleToolbar.d.ts.map +1 -0
  52. package/dist/editor/BubbleToolbar.js +171 -0
  53. package/dist/editor/BubbleToolbar.js.map +1 -0
  54. package/dist/editor/CodeBlockNode.d.ts +49 -0
  55. package/dist/editor/CodeBlockNode.d.ts.map +1 -0
  56. package/dist/editor/CodeBlockNode.js +127 -0
  57. package/dist/editor/CodeBlockNode.js.map +1 -0
  58. package/dist/editor/DragHandle.d.ts +97 -0
  59. package/dist/editor/DragHandle.d.ts.map +1 -0
  60. package/dist/editor/DragHandle.js +1066 -0
  61. package/dist/editor/DragHandle.js.map +1 -0
  62. package/dist/editor/DragHandle.spec.d.ts +2 -0
  63. package/dist/editor/DragHandle.spec.d.ts.map +1 -0
  64. package/dist/editor/DragHandle.spec.js +407 -0
  65. package/dist/editor/DragHandle.spec.js.map +1 -0
  66. package/dist/editor/ImageExtension.d.ts +63 -0
  67. package/dist/editor/ImageExtension.d.ts.map +1 -0
  68. package/dist/editor/ImageExtension.js +243 -0
  69. package/dist/editor/ImageExtension.js.map +1 -0
  70. package/dist/editor/ImageExtension.roundtrip.spec.d.ts +2 -0
  71. package/dist/editor/ImageExtension.roundtrip.spec.d.ts.map +1 -0
  72. package/dist/editor/ImageExtension.roundtrip.spec.js +103 -0
  73. package/dist/editor/ImageExtension.roundtrip.spec.js.map +1 -0
  74. package/dist/editor/RichMarkdownEditor.collab.spec.d.ts +2 -0
  75. package/dist/editor/RichMarkdownEditor.collab.spec.d.ts.map +1 -0
  76. package/dist/editor/RichMarkdownEditor.collab.spec.js +65 -0
  77. package/dist/editor/RichMarkdownEditor.collab.spec.js.map +1 -0
  78. package/dist/editor/RichMarkdownEditor.d.ts +52 -0
  79. package/dist/editor/RichMarkdownEditor.d.ts.map +1 -0
  80. package/dist/editor/RichMarkdownEditor.js +38 -0
  81. package/dist/editor/RichMarkdownEditor.js.map +1 -0
  82. package/dist/editor/RichMarkdownEditor.roundtrip.spec.d.ts +2 -0
  83. package/dist/editor/RichMarkdownEditor.roundtrip.spec.d.ts.map +1 -0
  84. package/dist/editor/RichMarkdownEditor.roundtrip.spec.js +186 -0
  85. package/dist/editor/RichMarkdownEditor.roundtrip.spec.js.map +1 -0
  86. package/dist/editor/RunId.d.ts +28 -0
  87. package/dist/editor/RunId.d.ts.map +1 -0
  88. package/dist/editor/RunId.js +60 -0
  89. package/dist/editor/RunId.js.map +1 -0
  90. package/dist/editor/SharedRichEditor.d.ts +110 -0
  91. package/dist/editor/SharedRichEditor.d.ts.map +1 -0
  92. package/dist/editor/SharedRichEditor.js +144 -0
  93. package/dist/editor/SharedRichEditor.js.map +1 -0
  94. package/dist/editor/SlashCommandMenu.d.ts +41 -0
  95. package/dist/editor/SlashCommandMenu.d.ts.map +1 -0
  96. package/dist/editor/SlashCommandMenu.js +221 -0
  97. package/dist/editor/SlashCommandMenu.js.map +1 -0
  98. package/dist/editor/disableHistory.spec.d.ts +2 -0
  99. package/dist/editor/disableHistory.spec.d.ts.map +1 -0
  100. package/dist/editor/disableHistory.spec.js +73 -0
  101. package/dist/editor/disableHistory.spec.js.map +1 -0
  102. package/dist/editor/extensions.d.ts +178 -0
  103. package/dist/editor/extensions.d.ts.map +1 -0
  104. package/dist/editor/extensions.js +224 -0
  105. package/dist/editor/extensions.js.map +1 -0
  106. package/dist/editor/gfmDoc.d.ts +24 -0
  107. package/dist/editor/gfmDoc.d.ts.map +1 -0
  108. package/dist/editor/gfmDoc.js +83 -0
  109. package/dist/editor/gfmDoc.js.map +1 -0
  110. package/dist/editor/gfmDoc.spec.d.ts +2 -0
  111. package/dist/editor/gfmDoc.spec.d.ts.map +1 -0
  112. package/dist/editor/gfmDoc.spec.js +194 -0
  113. package/dist/editor/gfmDoc.spec.js.map +1 -0
  114. package/dist/editor/index.d.ts +13 -0
  115. package/dist/editor/index.d.ts.map +1 -0
  116. package/dist/editor/index.js +13 -0
  117. package/dist/editor/index.js.map +1 -0
  118. package/dist/editor/structuralReorderUndo.spec.d.ts +2 -0
  119. package/dist/editor/structuralReorderUndo.spec.d.ts.map +1 -0
  120. package/dist/editor/structuralReorderUndo.spec.js +120 -0
  121. package/dist/editor/structuralReorderUndo.spec.js.map +1 -0
  122. package/dist/editor/surgical-apply.d.ts +66 -0
  123. package/dist/editor/surgical-apply.d.ts.map +1 -0
  124. package/dist/editor/surgical-apply.js +147 -0
  125. package/dist/editor/surgical-apply.js.map +1 -0
  126. package/dist/editor/surgical-apply.spec.d.ts +2 -0
  127. package/dist/editor/surgical-apply.spec.d.ts.map +1 -0
  128. package/dist/editor/surgical-apply.spec.js +257 -0
  129. package/dist/editor/surgical-apply.spec.js.map +1 -0
  130. package/dist/editor/useCollabReconcile.concurrent.spec.d.ts +2 -0
  131. package/dist/editor/useCollabReconcile.concurrent.spec.d.ts.map +1 -0
  132. package/dist/editor/useCollabReconcile.concurrent.spec.js +329 -0
  133. package/dist/editor/useCollabReconcile.concurrent.spec.js.map +1 -0
  134. package/dist/editor/useCollabReconcile.d.ts +110 -0
  135. package/dist/editor/useCollabReconcile.d.ts.map +1 -0
  136. package/dist/editor/useCollabReconcile.idempotent.spec.d.ts +2 -0
  137. package/dist/editor/useCollabReconcile.idempotent.spec.d.ts.map +1 -0
  138. package/dist/editor/useCollabReconcile.idempotent.spec.js +248 -0
  139. package/dist/editor/useCollabReconcile.idempotent.spec.js.map +1 -0
  140. package/dist/editor/useCollabReconcile.js +440 -0
  141. package/dist/editor/useCollabReconcile.js.map +1 -0
  142. package/dist/editor.css +510 -0
  143. package/package.json +63 -9
@@ -0,0 +1,224 @@
1
+ import Collaboration from "@tiptap/extension-collaboration";
2
+ import CollaborationCaret from "@tiptap/extension-collaboration-caret";
3
+ import Link from "@tiptap/extension-link";
4
+ import Placeholder from "@tiptap/extension-placeholder";
5
+ import { Table } from "@tiptap/extension-table";
6
+ import { TableCell } from "@tiptap/extension-table-cell";
7
+ import { TableHeader } from "@tiptap/extension-table-header";
8
+ import { TableRow } from "@tiptap/extension-table-row";
9
+ import TaskItem from "@tiptap/extension-task-item";
10
+ import TaskList from "@tiptap/extension-task-list";
11
+ import StarterKit from "@tiptap/starter-kit";
12
+ import bash from "highlight.js/lib/languages/bash";
13
+ import css from "highlight.js/lib/languages/css";
14
+ import javascript from "highlight.js/lib/languages/javascript";
15
+ import json from "highlight.js/lib/languages/json";
16
+ import markdown from "highlight.js/lib/languages/markdown";
17
+ import python from "highlight.js/lib/languages/python";
18
+ import sql from "highlight.js/lib/languages/sql";
19
+ import typescript from "highlight.js/lib/languages/typescript";
20
+ import xml from "highlight.js/lib/languages/xml";
21
+ import yaml from "highlight.js/lib/languages/yaml";
22
+ import { createLowlight } from "lowlight";
23
+ import { Markdown } from "tiptap-markdown";
24
+ /**
25
+ * Shared lowlight instance for the editor's syntax-highlighted code blocks. A
26
+ * curated grammar set (aliases like ts/tsx, js/jsx, html, sh, py, yml, md come
27
+ * for free from each grammar) keeps the editor bundle lean while matching the
28
+ * languages the read-side Shiki surfaces (`code-tabs`) support. highlight.js is
29
+ * synchronous, which is what a live ProseMirror editor needs — Shiki is async
30
+ * and only used for read-only render paths.
31
+ */
32
+ const codeLowlight = createLowlight({
33
+ bash,
34
+ css,
35
+ javascript,
36
+ json,
37
+ markdown,
38
+ python,
39
+ sql,
40
+ typescript,
41
+ xml,
42
+ yaml,
43
+ });
44
+ import { createCodeBlockNode } from "./CodeBlockNode.js";
45
+ import { createImageExtension } from "./ImageExtension.js";
46
+ /**
47
+ * tiptap-markdown configuration, keyed by dialect. This is the single source of
48
+ * truth for how each dialect parses/serializes markdown so the editor component
49
+ * and the round-trip fidelity test can never drift apart.
50
+ *
51
+ * tiptap-markdown re-serializes the whole document on every edit, so the goal
52
+ * for GFM is `serialize(parse(markdown)) === markdown` for the markdown plans
53
+ * actually contain. We deliberately keep tiptap-markdown's own defaults
54
+ * (`bulletListMarker: "-"`, `tightLists: true`, `linkify: false`,
55
+ * `breaks: false`) because those produce the most byte-stable GFM. See
56
+ * RichMarkdownEditor.roundtrip.spec.ts for the pinned corpus.
57
+ *
58
+ * NFM (Content) opts into inline HTML passthrough (`html: true`) so
59
+ * Notion-specific blocks survive a markdown round-trip; the rest mirrors the
60
+ * Content editor's existing `Markdown.configure` call.
61
+ */
62
+ export const MARKDOWN_DIALECT_CONFIG = {
63
+ gfm: {
64
+ // GFM plans are the common case and must never gain raw HTML as a second
65
+ // representation.
66
+ html: false,
67
+ // Keep tiptap-markdown's defaults that minimise first-edit normalisation
68
+ // churn (see roundtrip spec). Listed explicitly so the contract is
69
+ // self-documenting rather than relying on the package defaults.
70
+ bulletListMarker: "-",
71
+ tightLists: true,
72
+ linkify: false,
73
+ breaks: false,
74
+ transformPastedText: true,
75
+ transformCopiedText: true,
76
+ },
77
+ nfm: {
78
+ // NFM is a superset that allows inline HTML so Notion blocks round-trip.
79
+ html: true,
80
+ transformPastedText: true,
81
+ transformCopiedText: true,
82
+ },
83
+ };
84
+ const DEFAULT_FEATURES = {
85
+ tables: true,
86
+ tasks: true,
87
+ link: true,
88
+ codeBlock: true,
89
+ placeholder: true,
90
+ markdown: true,
91
+ // Off by default: only Plans opt in today. Content injects its own richer
92
+ // image node via `extraExtensions` and must not get a second `image` node.
93
+ image: false,
94
+ };
95
+ /**
96
+ * The ONE editor extension factory shared by every embedder (Plans today,
97
+ * Content next). It assembles the base Tiptap schema (StarterKit + Placeholder
98
+ * + Link + tasks + tables + code block), the dialect-keyed {@link Markdown}
99
+ * serializer, the optional Collaboration stack, and finally any app-specific
100
+ * `extraExtensions`.
101
+ *
102
+ * Ordering matters:
103
+ * 1. Base schema (StarterKit first so its nodes/marks register; `starterKit`
104
+ * overrides let an app disable replaced nodes / swap the dropcursor).
105
+ * 2. dialect-keyed Markdown serializer (suppressible via `features.markdown`
106
+ * for apps that own the whole serialize/parse pipeline, e.g. Content's NFM).
107
+ * 3. `extraExtensions` (Notion/media/etc.) — appended before Collaboration so
108
+ * apps can extend the schema and Collaboration still binds over the full
109
+ * schema.
110
+ * 4. Collaboration (+ CollaborationCaret) LAST so they bind over everything.
111
+ *
112
+ * Content (the NFM editor) drives this factory with `features.placeholder` and
113
+ * `features.markdown` off, `features.tasks/tables/link` off where it ships its
114
+ * own, a `starterKit` override disabling paragraph/blockquote/codeBlock, and all
115
+ * Notion/media/fidelity nodes + its own Markdown(NFM)/Placeholder via
116
+ * `extraExtensions` — so it shares the StarterKit base + the collab wiring while
117
+ * owning its byte-identical NFM serializer.
118
+ */
119
+ export function createSharedEditorExtensions({ dialect = "gfm",
120
+ // `preset` is accepted and forwarded for future preset-specific schema
121
+ // branches; it is currently schema-neutral.
122
+ preset: _preset = "plan", placeholder = "Type '/' for commands...", features, starterKit, markdown, extraExtensions = [], collab = null, onImageUpload = null, disableHistory = false, } = {}) {
123
+ const feat = { ...DEFAULT_FEATURES, ...(features ?? {}) };
124
+ const ydoc = collab?.ydoc ?? null;
125
+ const awareness = collab?.awareness ?? null;
126
+ const user = collab?.user ?? null;
127
+ const exts = [
128
+ StarterKit.configure({
129
+ heading: { levels: [1, 2, 3, 4] },
130
+ link: false,
131
+ // StarterKit's plain code block is always disabled; when enabled we add the
132
+ // syntax-highlighting `CodeBlockLowlight` (same `codeBlock` node) below.
133
+ codeBlock: false,
134
+ dropcursor: { color: "hsl(var(--ring))", width: 2 },
135
+ // Yjs owns undo/redo when Collaboration is active; the StarterKit history
136
+ // plugin and the CRDT cannot both track undo without corrupting state.
137
+ // `disableHistory` is the non-collab equivalent: a controlled editor whose
138
+ // host (e.g. the plan editor) owns a single app-level undo authority.
139
+ ...(ydoc || disableHistory ? { undoRedo: false } : {}),
140
+ // App overrides last so embedders can disable replaced nodes (paragraph,
141
+ // blockquote, code block) or swap the dropcursor while keeping the shared
142
+ // base + the collab undo/redo gating above.
143
+ ...(starterKit ?? {}),
144
+ }),
145
+ ];
146
+ // Notion-style syntax-highlighted code block (replaces StarterKit's plain one)
147
+ // only when the embedder opts in via `features.codeBlock`. The shared node adds
148
+ // a language picker header (Auto-detects by default) over `CodeBlockLowlight`,
149
+ // so fenced markdown still round-trips byte-identically. Content disables this
150
+ // and ships its own code node, so this affects Plans (and future opt-in apps)
151
+ // alone.
152
+ if (feat.codeBlock) {
153
+ exts.push(createCodeBlockNode({ lowlight: codeLowlight }));
154
+ }
155
+ if (feat.placeholder) {
156
+ exts.push(Placeholder.configure({
157
+ placeholder: ({ node }) => {
158
+ if (node.type.name === "heading") {
159
+ const level = node.attrs.level;
160
+ if (level === 1)
161
+ return "Heading 1";
162
+ if (level === 2)
163
+ return "Heading 2";
164
+ if (level === 3)
165
+ return "Heading 3";
166
+ return "Heading 4";
167
+ }
168
+ return placeholder;
169
+ },
170
+ showOnlyWhenEditable: true,
171
+ showOnlyCurrent: true,
172
+ }));
173
+ }
174
+ if (feat.link) {
175
+ exts.push(Link.configure({
176
+ openOnClick: false,
177
+ HTMLAttributes: { class: "an-rich-md-link" },
178
+ }));
179
+ }
180
+ if (feat.tasks) {
181
+ exts.push(TaskList.configure({
182
+ HTMLAttributes: { class: "an-rich-md-task-list" },
183
+ }), TaskItem.configure({ nested: true }));
184
+ }
185
+ if (feat.tables) {
186
+ exts.push(Table.configure({
187
+ resizable: false,
188
+ HTMLAttributes: { class: "an-rich-md-table" },
189
+ }), TableRow, TableHeader, TableCell);
190
+ }
191
+ if (feat.markdown) {
192
+ exts.push(Markdown.configure(markdown ?? MARKDOWN_DIALECT_CONFIG[dialect]));
193
+ }
194
+ // Shared block-level image node. The node is named `image`, so when
195
+ // `features.markdown` is on, tiptap-markdown serializes it through its
196
+ // built-in `defaultMarkdownSerializer.nodes.image` fallback → `![alt](src)`
197
+ // (no width-as-HTML override here, so GFM stays byte-stable and
198
+ // source-syncable). With an `onImageUpload` it accepts paste/drop uploads.
199
+ if (feat.image) {
200
+ exts.push(createImageExtension({ onImageUpload }));
201
+ }
202
+ // App-specific extensions (Notion/media/drag handles/comments). Appended
203
+ // before Collaboration so they can extend the schema and Collaboration binds
204
+ // over the full set.
205
+ if (extraExtensions.length > 0) {
206
+ exts.push(...extraExtensions);
207
+ }
208
+ // Collaborative editing via the shared Y.Doc. Markdown stays the canonical
209
+ // saved representation (onChange serializes it); the Y.Doc is transient live
210
+ // state only. Appended last so it binds over the configured schema above.
211
+ if (ydoc) {
212
+ exts.push(Collaboration.configure({ document: ydoc }));
213
+ // Live multi-user cursors. Only mounted alongside a Y.Doc so the standalone
214
+ // controlled editor (today's plan/content behavior) is untouched.
215
+ if (awareness) {
216
+ exts.push(CollaborationCaret.configure({
217
+ provider: { awareness },
218
+ user: user ?? { name: "Anonymous", color: "#999" },
219
+ }));
220
+ }
221
+ }
222
+ return exts;
223
+ }
224
+ //# sourceMappingURL=extensions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extensions.js","sourceRoot":"","sources":["../../src/editor/extensions.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ import { type JSONContent } from "@tiptap/core";
2
+ /**
3
+ * Parse a GFM markdown string into an array of top-level ProseMirror node JSON
4
+ * (paragraph / heading / list / table / code block / etc.), matching the live
5
+ * plan editor schema (`createSharedEditorExtensions({ dialect: "gfm",
6
+ * features: { image: true } })`) plus the {@link RunId} attribute.
7
+ *
8
+ * `tiptap-markdown` registers the markdown parser, so handing the raw markdown
9
+ * string to `setContent` deserializes it (the same path the live editor uses
10
+ * when it seeds `content: markdown`). Returns the doc's child nodes; an empty
11
+ * string yields a single empty paragraph.
12
+ */
13
+ export declare function gfmToProseJSON(markdown: string): JSONContent[];
14
+ /**
15
+ * Serialize an array of top-level ProseMirror node JSON into GFM markdown. The
16
+ * `runId` attribute is omitted by GFM (the {@link RunId} extension registers no
17
+ * markdown serializer), so it never leaks into the saved markdown.
18
+ *
19
+ * The nodes are wrapped in a `doc` and set on the shared editor, then the GFM
20
+ * markdown is read from the tiptap-markdown storage — the exact serializer the
21
+ * live editor persists with, so output is byte-stable with the live save path.
22
+ */
23
+ export declare function proseJSONToGfm(nodes: JSONContent[]): string;
24
+ //# sourceMappingURL=gfmDoc.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gfmDoc.d.ts","sourceRoot":"","sources":["../../src/editor/gfmDoc.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,KAAK,WAAW,EAAE,MAAM,cAAc,CAAC;AA0DxD;;;;;;;;;;GAUG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,WAAW,EAAE,CAM9D;AAED;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,WAAW,EAAE,GAAG,MAAM,CAK3D"}
@@ -0,0 +1,83 @@
1
+ import { Editor } from "@tiptap/core";
2
+ import { createSharedEditorExtensions } from "./extensions.js";
3
+ import { RunId } from "./RunId.js";
4
+ /**
5
+ * The GFM ↔ ProseMirror primitive for the plan single-doc editor.
6
+ *
7
+ * Plans keep `PlanContent.blocks[]` as the source of truth, but the editor is
8
+ * ONE ProseMirror/Tiptap document. The `doc ↔ blocks[]` serializer
9
+ * (`templates/plan/shared/plan-doc.ts`) needs to turn a `rich-text` block's GFM
10
+ * markdown into prose nodes and back. This module is that primitive.
11
+ *
12
+ * Both directions go through a SINGLE headless Tiptap {@link Editor} built from
13
+ * the exact same `createSharedEditorExtensions` config the live plan editor
14
+ * uses (`dialect: "gfm"`, `features.image: true`) plus the {@link RunId}
15
+ * extension, so the schema and the GFM serializer can never drift from the live
16
+ * editor. The instance is created lazily on first use and reused across calls.
17
+ *
18
+ * The headless editor needs a DOM (ProseMirror's `EditorView`). It works under
19
+ * `happy-dom` in vitest (see `gfmDoc.spec.ts`) and under the real browser DOM
20
+ * in production. `createElement` is used rather than mounting into the page so
21
+ * nothing is ever attached to the document.
22
+ */
23
+ let sharedEditor = null;
24
+ /**
25
+ * Lazily build (and memoize) the single headless editor. Throws if no DOM is
26
+ * available — this primitive is for the client / jsdom-style test envs only.
27
+ */
28
+ function getSharedEditor() {
29
+ if (sharedEditor)
30
+ return sharedEditor;
31
+ if (typeof document === "undefined") {
32
+ throw new Error("gfmDoc requires a DOM (document). It runs in the browser and in jsdom/happy-dom tests, not in a bare Node server context.");
33
+ }
34
+ sharedEditor = new Editor({
35
+ element: document.createElement("div"),
36
+ extensions: createSharedEditorExtensions({
37
+ dialect: "gfm",
38
+ features: { image: true },
39
+ extraExtensions: [RunId],
40
+ }),
41
+ content: "",
42
+ });
43
+ return sharedEditor;
44
+ }
45
+ /** Reads the GFM markdown out of the tiptap-markdown storage. */
46
+ function getMarkdown(editor) {
47
+ const storage = editor.storage;
48
+ return storage.markdown?.getMarkdown?.() ?? "";
49
+ }
50
+ /**
51
+ * Parse a GFM markdown string into an array of top-level ProseMirror node JSON
52
+ * (paragraph / heading / list / table / code block / etc.), matching the live
53
+ * plan editor schema (`createSharedEditorExtensions({ dialect: "gfm",
54
+ * features: { image: true } })`) plus the {@link RunId} attribute.
55
+ *
56
+ * `tiptap-markdown` registers the markdown parser, so handing the raw markdown
57
+ * string to `setContent` deserializes it (the same path the live editor uses
58
+ * when it seeds `content: markdown`). Returns the doc's child nodes; an empty
59
+ * string yields a single empty paragraph.
60
+ */
61
+ export function gfmToProseJSON(markdown) {
62
+ const editor = getSharedEditor();
63
+ // `emitUpdate: false` keeps this a pure transform with no side effects on any
64
+ // (non-existent) consumers of the headless editor's update stream.
65
+ editor.commands.setContent(markdown, { emitUpdate: false });
66
+ return editor.getJSON().content ?? [];
67
+ }
68
+ /**
69
+ * Serialize an array of top-level ProseMirror node JSON into GFM markdown. The
70
+ * `runId` attribute is omitted by GFM (the {@link RunId} extension registers no
71
+ * markdown serializer), so it never leaks into the saved markdown.
72
+ *
73
+ * The nodes are wrapped in a `doc` and set on the shared editor, then the GFM
74
+ * markdown is read from the tiptap-markdown storage — the exact serializer the
75
+ * live editor persists with, so output is byte-stable with the live save path.
76
+ */
77
+ export function proseJSONToGfm(nodes) {
78
+ const editor = getSharedEditor();
79
+ const content = nodes.length > 0 ? nodes : [{ type: "paragraph" }];
80
+ editor.commands.setContent({ type: "doc", content }, { emitUpdate: false });
81
+ return getMarkdown(editor);
82
+ }
83
+ //# sourceMappingURL=gfmDoc.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gfmDoc.js","sourceRoot":"","sources":["../../src/editor/gfmDoc.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAoB,MAAM,cAAc,CAAC;AAExD,OAAO,EAAE,4BAA4B,EAAE,MAAM,iBAAiB,CAAC;AAC/D,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAEnC;;;;;;;;;;;;;;;;;;GAkBG;AAEH,IAAI,YAAY,GAAkB,IAAI,CAAC;AAEvC;;;GAGG;AACH,SAAS,eAAe;IACtB,IAAI,YAAY;QAAE,OAAO,YAAY,CAAC;IACtC,IAAI,OAAO,QAAQ,KAAK,WAAW,EAAE,CAAC;QACpC,MAAM,IAAI,KAAK,CACb,2HAA2H,CAC5H,CAAC;IACJ,CAAC;IACD,YAAY,GAAG,IAAI,MAAM,CAAC;QACxB,OAAO,EAAE,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAC;QACtC,UAAU,EAAE,4BAA4B,CAAC;YACvC,OAAO,EAAE,KAAK;YACd,QAAQ,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE;YACzB,eAAe,EAAE,CAAC,KAAK,CAAC;SACzB,CAAC;QACF,OAAO,EAAE,EAAE;KACZ,CAAC,CAAC;IACH,OAAO,YAAY,CAAC;AACtB,CAAC;AAED,iEAAiE;AACjE,SAAS,WAAW,CAAC,MAAc;IACjC,MAAM,OAAO,GAAG,MAAM,CAAC,OAEtB,CAAC;IACF,OAAO,OAAO,CAAC,QAAQ,EAAE,WAAW,EAAE,EAAE,IAAI,EAAE,CAAC;AACjD,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,cAAc,CAAC,QAAgB;IAC7C,MAAM,MAAM,GAAG,eAAe,EAAE,CAAC;IACjC,8EAA8E;IAC9E,mEAAmE;IACnE,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAC,QAAQ,EAAE,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC,CAAC;IAC5D,OAAO,MAAM,CAAC,OAAO,EAAE,CAAC,OAAO,IAAI,EAAE,CAAC;AACxC,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,cAAc,CAAC,KAAoB;IACjD,MAAM,MAAM,GAAG,eAAe,EAAE,CAAC;IACjC,MAAM,OAAO,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC,CAAC;IACnE,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC,CAAC;IAC5E,OAAO,WAAW,CAAC,MAAM,CAAC,CAAC;AAC7B,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=gfmDoc.spec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gfmDoc.spec.d.ts","sourceRoot":"","sources":["../../src/editor/gfmDoc.spec.ts"],"names":[],"mappings":""}
@@ -0,0 +1,194 @@
1
+ // @vitest-environment happy-dom
2
+ import { describe, expect, it } from "vitest";
3
+ import { gfmToProseJSON, proseJSONToGfm } from "./gfmDoc.js";
4
+ /**
5
+ * GFM ↔ ProseMirror primitive for the plan single-doc editor.
6
+ *
7
+ * `gfmToProseJSON` / `proseJSONToGfm` go through ONE memoized headless Tiptap
8
+ * editor built from the SAME `createSharedEditorExtensions({ dialect: "gfm",
9
+ * features: { image: true } })` config the live plan editor uses, plus the
10
+ * `RunId` extension. These tests assert two things:
11
+ *
12
+ * 1. `proseJSONToGfm(gfmToProseJSON(md))` normalizes STABLY — once a corpus
13
+ * entry has been through the converter, running it through again is a
14
+ * fixed point (the live editor re-serializes the whole doc on every edit,
15
+ * so a non-stable round-trip would churn untouched prose on first edit).
16
+ * 2. `gfmToProseJSON` produces the EXPECTED top-level node types for a known
17
+ * corpus, so the bridge can rely on the shapes it walks.
18
+ *
19
+ * The headless editor needs a DOM (ProseMirror's EditorView); this file runs
20
+ * under `happy-dom` (the same env the other editor specs use), proving the
21
+ * primitive works in jsdom-style test runners as well as the browser.
22
+ */
23
+ /** First pass: md → prose → md. */
24
+ function once(markdown) {
25
+ return proseJSONToGfm(gfmToProseJSON(markdown));
26
+ }
27
+ /** Asserts the converter reaches a fixed point (re-running is a no-op). */
28
+ function expectStableRoundTrip(markdown) {
29
+ const first = once(markdown);
30
+ const second = once(first);
31
+ expect(second).toBe(first);
32
+ }
33
+ /** Top-level node types produced for a markdown string. */
34
+ function topLevelTypes(markdown) {
35
+ return gfmToProseJSON(markdown).map((node) => node.type ?? "");
36
+ }
37
+ /**
38
+ * Top-level node types with any trailing empty paragraph(s) dropped.
39
+ *
40
+ * The markdown parser appends a trailing empty `paragraph` whenever the doc
41
+ * would otherwise end in a non-paragraph block (heading / list / code / table /
42
+ * blockquote). This is a genuine ProseMirror parse artifact — the GFM
43
+ * serializer drops it again, so the round-trip stays byte-stable — and the
44
+ * plan's doc→blocks bridge skips whitespace-only runs, so it is not meaningful
45
+ * content. These assertions focus on the meaningful leading block types.
46
+ */
47
+ function meaningfulTypes(markdown) {
48
+ const types = topLevelTypes(markdown);
49
+ while (types.length > 1 &&
50
+ types[types.length - 1] === "paragraph" &&
51
+ isEmptyParagraph(gfmToProseJSON(markdown)[types.length - 1])) {
52
+ types.pop();
53
+ }
54
+ return types;
55
+ }
56
+ /** True when a paragraph node has no inline content (the trailing filler). */
57
+ function isEmptyParagraph(node) {
58
+ return node?.type === "paragraph" && (node.content ?? []).length === 0;
59
+ }
60
+ const PROSE_CORPUS = {
61
+ "heading 1": "# Heading 1",
62
+ "heading 2": "## Heading 2",
63
+ "heading 3": "### Heading 3",
64
+ paragraph: "A plain paragraph of prose.",
65
+ "bulleted list": "- One\n- Two\n- Three",
66
+ "numbered list": "1. One\n2. Two\n3. Three",
67
+ "task list": "- [ ] Todo item\n- [x] Done item",
68
+ blockquote: "> A quoted line.",
69
+ "fenced code block": "```ts\nconst x: number = 1;\n```",
70
+ "inline marks": "Text with **bold**, *italic*, `code`, and a word.",
71
+ link: "See [the docs](https://example.com/docs) for details.",
72
+ table: [
73
+ "| Name | Status |",
74
+ "| --- | --- |",
75
+ "| Alpha | Done |",
76
+ "| Beta | Open |",
77
+ "",
78
+ "Trailing paragraph so the table is not the last block.",
79
+ ].join("\n"),
80
+ "mixed body": [
81
+ "# Project Plan",
82
+ "",
83
+ "## Overview",
84
+ "",
85
+ "This plan covers the **rollout** of the new flow.",
86
+ "",
87
+ "- Step one",
88
+ "- Step two",
89
+ "",
90
+ "> A note to remember.",
91
+ "",
92
+ "```ts",
93
+ "const ready = true;",
94
+ "```",
95
+ ].join("\n"),
96
+ };
97
+ describe("gfmDoc GFM ↔ ProseMirror primitive", () => {
98
+ describe("round-trip is stable (fixed point)", () => {
99
+ for (const [name, markdown] of Object.entries(PROSE_CORPUS)) {
100
+ it(`stabilizes: ${name}`, () => {
101
+ expectStableRoundTrip(markdown);
102
+ });
103
+ }
104
+ });
105
+ describe("gfmToProseJSON produces expected node types", () => {
106
+ it("headings carry their level", () => {
107
+ expect(meaningfulTypes("# A\n\n## B\n\n### C")).toEqual([
108
+ "heading",
109
+ "heading",
110
+ "heading",
111
+ ]);
112
+ const levels = gfmToProseJSON("# A\n\n## B\n\n### C")
113
+ .filter((n) => n.type === "heading")
114
+ .map((n) => n.attrs?.level);
115
+ expect(levels).toEqual([1, 2, 3]);
116
+ });
117
+ it("paragraph", () => {
118
+ expect(meaningfulTypes("Just text.")).toEqual(["paragraph"]);
119
+ });
120
+ it("bulleted list", () => {
121
+ expect(meaningfulTypes("- a\n- b")).toEqual(["bulletList"]);
122
+ });
123
+ it("numbered list", () => {
124
+ expect(meaningfulTypes("1. a\n2. b")).toEqual(["orderedList"]);
125
+ });
126
+ it("task list", () => {
127
+ expect(meaningfulTypes("- [ ] a\n- [x] b")).toEqual(["taskList"]);
128
+ });
129
+ it("blockquote", () => {
130
+ expect(meaningfulTypes("> quoted")).toEqual(["blockquote"]);
131
+ });
132
+ it("fenced code block keeps language", () => {
133
+ const nodes = gfmToProseJSON("```ts\nconst x = 1;\n```");
134
+ const code = nodes.find((n) => n.type === "codeBlock");
135
+ expect(meaningfulTypes("```ts\nconst x = 1;\n```")).toEqual([
136
+ "codeBlock",
137
+ ]);
138
+ expect(code?.attrs?.language).toBe("ts");
139
+ });
140
+ it("GFM pipe table", () => {
141
+ expect(meaningfulTypes(["| H |", "| --- |", "| v |"].join("\n"))).toEqual(["table"]);
142
+ });
143
+ it("inline marks land on the paragraph's text", () => {
144
+ const nodes = gfmToProseJSON("Has **bold**, *italic*, `code`.");
145
+ expect(nodes).toHaveLength(1);
146
+ const para = nodes[0];
147
+ expect(para.type).toBe("paragraph");
148
+ const markTypes = new Set((para.content ?? []).flatMap((child) => (child.marks ?? []).map((m) => m.type)));
149
+ expect(markTypes.has("bold")).toBe(true);
150
+ expect(markTypes.has("italic")).toBe(true);
151
+ expect(markTypes.has("code")).toBe(true);
152
+ });
153
+ it("link mark carries the href", () => {
154
+ const nodes = gfmToProseJSON("See [docs](https://example.com).");
155
+ const para = nodes[0];
156
+ const linkMark = (para.content ?? [])
157
+ .flatMap((child) => child.marks ?? [])
158
+ .find((m) => m.type === "link");
159
+ expect(linkMark?.attrs?.href).toBe("https://example.com");
160
+ });
161
+ });
162
+ describe("runId attribute", () => {
163
+ it("is omitted from serialized GFM markdown", () => {
164
+ const nodes = gfmToProseJSON("A paragraph.");
165
+ const stamped = nodes.map((n, i) => i === 0
166
+ ? { ...n, attrs: { ...(n.attrs ?? {}), runId: "block-123" } }
167
+ : n);
168
+ const markdown = proseJSONToGfm(stamped);
169
+ expect(markdown).toBe("A paragraph.");
170
+ expect(markdown).not.toContain("block-123");
171
+ expect(markdown).not.toContain("run-id");
172
+ });
173
+ it("survives a prose → JSON → prose round-trip when set", () => {
174
+ const nodes = gfmToProseJSON("A paragraph.");
175
+ const stamped = nodes.map((n, i) => i === 0 ? { ...n, attrs: { ...(n.attrs ?? {}), runId: "block-9" } } : n);
176
+ // Serializing drops runId (GFM), but the attribute is a valid schema
177
+ // attribute on the node JSON — re-parsing markdown yields runId: null.
178
+ const reparsed = gfmToProseJSON(proseJSONToGfm(stamped));
179
+ expect(reparsed[0]?.type).toBe("paragraph");
180
+ expect(reparsed[0]?.attrs?.runId ?? null).toBeNull();
181
+ });
182
+ });
183
+ describe("edge cases", () => {
184
+ it("empty string yields a single empty paragraph", () => {
185
+ const nodes = gfmToProseJSON("");
186
+ expect(nodes).toHaveLength(1);
187
+ expect(nodes[0]?.type).toBe("paragraph");
188
+ });
189
+ it("empty node array serializes to empty markdown", () => {
190
+ expect(proseJSONToGfm([])).toBe("");
191
+ });
192
+ });
193
+ });
194
+ //# sourceMappingURL=gfmDoc.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gfmDoc.spec.js","sourceRoot":"","sources":["../../src/editor/gfmDoc.spec.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ export { createSharedEditorExtensions, MARKDOWN_DIALECT_CONFIG, type RichMarkdownDialect, type RichMarkdownEditorPreset, type RichMarkdownCollabUser, type SharedEditorCollab, type SharedEditorFeatures, type CreateSharedEditorExtensionsOptions, } from "./extensions.js";
2
+ export { useCollabReconcile, getEditorMarkdown, RICH_MARKDOWN_PROGRAMMATIC_TRANSACTION, type UseCollabReconcileOptions, type UseCollabReconcileResult, } from "./useCollabReconcile.js";
3
+ export { applyDocSurgically, defaultParseValue, diffTopLevel, type TopLevelDiff, } from "./surgical-apply.js";
4
+ export { SlashCommandMenu, DEFAULT_SLASH_COMMANDS, createImageSlashCommand, type SlashCommandItem, type SlashCommandMenuProps, } from "./SlashCommandMenu.js";
5
+ export { SharedImage, createImageExtension, pickAndInsertImage, type ImageUploadFn, type SharedImageOptions, } from "./ImageExtension.js";
6
+ export { BubbleToolbar, buildDefaultBubbleItems, type BubbleToolbarItem, type BubbleToolbarProps, } from "./BubbleToolbar.js";
7
+ export { SharedRichEditor, type SharedRichEditorProps, } from "./SharedRichEditor.js";
8
+ export { createCodeBlockNode, DEFAULT_CODE_LANGUAGES, type CodeLanguageOption, type CodeBlockClassNames, type CreateCodeBlockNodeOptions, } from "./CodeBlockNode.js";
9
+ export { RichMarkdownEditor, createRichMarkdownExtensions, type RichMarkdownEditorProps, type CreateRichMarkdownExtensionsOptions, } from "./RichMarkdownEditor.js";
10
+ export { RunId, RUN_ID_NODE_TYPES } from "./RunId.js";
11
+ export { gfmToProseJSON, proseJSONToGfm } from "./gfmDoc.js";
12
+ export { DragHandle, DEFAULT_DRAG_HANDLE_WRAPPER_SELECTOR, type DragHandleDropContext, type DragHandleDropPlacement, type DragHandleOptions, } from "./DragHandle.js";
13
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/editor/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,4BAA4B,EAC5B,uBAAuB,EACvB,KAAK,mBAAmB,EACxB,KAAK,wBAAwB,EAC7B,KAAK,sBAAsB,EAC3B,KAAK,kBAAkB,EACvB,KAAK,oBAAoB,EACzB,KAAK,mCAAmC,GACzC,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,kBAAkB,EAClB,iBAAiB,EACjB,sCAAsC,EACtC,KAAK,yBAAyB,EAC9B,KAAK,wBAAwB,GAC9B,MAAM,yBAAyB,CAAC;AACjC,OAAO,EACL,kBAAkB,EAClB,iBAAiB,EACjB,YAAY,EACZ,KAAK,YAAY,GAClB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,gBAAgB,EAChB,sBAAsB,EACtB,uBAAuB,EACvB,KAAK,gBAAgB,EACrB,KAAK,qBAAqB,GAC3B,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,WAAW,EACX,oBAAoB,EACpB,kBAAkB,EAClB,KAAK,aAAa,EAClB,KAAK,kBAAkB,GACxB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,aAAa,EACb,uBAAuB,EACvB,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,GACxB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,gBAAgB,EAChB,KAAK,qBAAqB,GAC3B,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,mBAAmB,EACnB,sBAAsB,EACtB,KAAK,kBAAkB,EACvB,KAAK,mBAAmB,EACxB,KAAK,0BAA0B,GAChC,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,kBAAkB,EAClB,4BAA4B,EAC5B,KAAK,uBAAuB,EAC5B,KAAK,mCAAmC,GACzC,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7D,OAAO,EACL,UAAU,EACV,oCAAoC,EACpC,KAAK,qBAAqB,EAC1B,KAAK,uBAAuB,EAC5B,KAAK,iBAAiB,GACvB,MAAM,iBAAiB,CAAC"}
@@ -0,0 +1,13 @@
1
+ export { createSharedEditorExtensions, MARKDOWN_DIALECT_CONFIG, } from "./extensions.js";
2
+ export { useCollabReconcile, getEditorMarkdown, RICH_MARKDOWN_PROGRAMMATIC_TRANSACTION, } from "./useCollabReconcile.js";
3
+ export { applyDocSurgically, defaultParseValue, diffTopLevel, } from "./surgical-apply.js";
4
+ export { SlashCommandMenu, DEFAULT_SLASH_COMMANDS, createImageSlashCommand, } from "./SlashCommandMenu.js";
5
+ export { SharedImage, createImageExtension, pickAndInsertImage, } from "./ImageExtension.js";
6
+ export { BubbleToolbar, buildDefaultBubbleItems, } from "./BubbleToolbar.js";
7
+ export { SharedRichEditor, } from "./SharedRichEditor.js";
8
+ export { createCodeBlockNode, DEFAULT_CODE_LANGUAGES, } from "./CodeBlockNode.js";
9
+ export { RichMarkdownEditor, createRichMarkdownExtensions, } from "./RichMarkdownEditor.js";
10
+ export { RunId, RUN_ID_NODE_TYPES } from "./RunId.js";
11
+ export { gfmToProseJSON, proseJSONToGfm } from "./gfmDoc.js";
12
+ export { DragHandle, DEFAULT_DRAG_HANDLE_WRAPPER_SELECTOR, } from "./DragHandle.js";
13
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/editor/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,4BAA4B,EAC5B,uBAAuB,GAOxB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,kBAAkB,EAClB,iBAAiB,EACjB,sCAAsC,GAGvC,MAAM,yBAAyB,CAAC;AACjC,OAAO,EACL,kBAAkB,EAClB,iBAAiB,EACjB,YAAY,GAEb,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,gBAAgB,EAChB,sBAAsB,EACtB,uBAAuB,GAGxB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,WAAW,EACX,oBAAoB,EACpB,kBAAkB,GAGnB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,aAAa,EACb,uBAAuB,GAGxB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,gBAAgB,GAEjB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,mBAAmB,EACnB,sBAAsB,GAIvB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,kBAAkB,EAClB,4BAA4B,GAG7B,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7D,OAAO,EACL,UAAU,EACV,oCAAoC,GAIrC,MAAM,iBAAiB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=structuralReorderUndo.spec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"structuralReorderUndo.spec.d.ts","sourceRoot":"","sources":["../../src/editor/structuralReorderUndo.spec.ts"],"names":[],"mappings":""}