@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.
- package/README.md +17 -6
- package/dist/collab-ui/agent-identity.d.ts +9 -0
- package/dist/collab-ui/agent-identity.d.ts.map +1 -0
- package/dist/collab-ui/agent-identity.js +9 -0
- package/dist/collab-ui/agent-identity.js.map +1 -0
- package/dist/collab-ui/index.d.ts +2 -0
- package/dist/collab-ui/index.d.ts.map +1 -1
- package/dist/collab-ui/index.js +2 -0
- package/dist/collab-ui/index.js.map +1 -1
- package/dist/collab-ui/lead-client.d.ts +3 -0
- package/dist/collab-ui/lead-client.d.ts.map +1 -0
- package/dist/collab-ui/lead-client.js +29 -0
- package/dist/collab-ui/lead-client.js.map +1 -0
- package/dist/context-ui/ContextMeter.d.ts +10 -0
- package/dist/context-ui/ContextMeter.d.ts.map +1 -0
- package/dist/context-ui/ContextMeter.js +20 -0
- package/dist/context-ui/ContextMeter.js.map +1 -0
- package/dist/context-ui/ContextSegmentRow.d.ts +14 -0
- package/dist/context-ui/ContextSegmentRow.d.ts.map +1 -0
- package/dist/context-ui/ContextSegmentRow.js +25 -0
- package/dist/context-ui/ContextSegmentRow.js.map +1 -0
- package/dist/context-ui/ContextTreemap.d.ts +7 -0
- package/dist/context-ui/ContextTreemap.d.ts.map +1 -0
- package/dist/context-ui/ContextTreemap.js +55 -0
- package/dist/context-ui/ContextTreemap.js.map +1 -0
- package/dist/context-ui/ContextXRayPanel.d.ts +13 -0
- package/dist/context-ui/ContextXRayPanel.d.ts.map +1 -0
- package/dist/context-ui/ContextXRayPanel.js +120 -0
- package/dist/context-ui/ContextXRayPanel.js.map +1 -0
- package/dist/context-ui/format.d.ts +6 -0
- package/dist/context-ui/format.d.ts.map +1 -0
- package/dist/context-ui/format.js +58 -0
- package/dist/context-ui/format.js.map +1 -0
- package/dist/context-ui/index.d.ts +7 -0
- package/dist/context-ui/index.d.ts.map +1 -0
- package/dist/context-ui/index.js +6 -0
- package/dist/context-ui/index.js.map +1 -0
- package/dist/context-ui/types.d.ts +39 -0
- package/dist/context-ui/types.d.ts.map +1 -0
- package/dist/context-ui/types.js +2 -0
- package/dist/context-ui/types.js.map +1 -0
- package/dist/design-tweaks/index.d.ts +2 -0
- package/dist/design-tweaks/index.d.ts.map +1 -0
- package/dist/design-tweaks/index.js +2 -0
- package/dist/design-tweaks/index.js.map +1 -0
- package/dist/design-tweaks/visual-style-controls.d.ts +90 -0
- package/dist/design-tweaks/visual-style-controls.d.ts.map +1 -0
- package/dist/design-tweaks/visual-style-controls.js +499 -0
- package/dist/design-tweaks/visual-style-controls.js.map +1 -0
- package/dist/editor/BubbleToolbar.d.ts +37 -0
- package/dist/editor/BubbleToolbar.d.ts.map +1 -0
- package/dist/editor/BubbleToolbar.js +171 -0
- package/dist/editor/BubbleToolbar.js.map +1 -0
- package/dist/editor/CodeBlockNode.d.ts +49 -0
- package/dist/editor/CodeBlockNode.d.ts.map +1 -0
- package/dist/editor/CodeBlockNode.js +127 -0
- package/dist/editor/CodeBlockNode.js.map +1 -0
- package/dist/editor/DragHandle.d.ts +97 -0
- package/dist/editor/DragHandle.d.ts.map +1 -0
- package/dist/editor/DragHandle.js +1066 -0
- package/dist/editor/DragHandle.js.map +1 -0
- package/dist/editor/DragHandle.spec.d.ts +2 -0
- package/dist/editor/DragHandle.spec.d.ts.map +1 -0
- package/dist/editor/DragHandle.spec.js +407 -0
- package/dist/editor/DragHandle.spec.js.map +1 -0
- package/dist/editor/ImageExtension.d.ts +63 -0
- package/dist/editor/ImageExtension.d.ts.map +1 -0
- package/dist/editor/ImageExtension.js +243 -0
- package/dist/editor/ImageExtension.js.map +1 -0
- package/dist/editor/ImageExtension.roundtrip.spec.d.ts +2 -0
- package/dist/editor/ImageExtension.roundtrip.spec.d.ts.map +1 -0
- package/dist/editor/ImageExtension.roundtrip.spec.js +103 -0
- package/dist/editor/ImageExtension.roundtrip.spec.js.map +1 -0
- package/dist/editor/RichMarkdownEditor.collab.spec.d.ts +2 -0
- package/dist/editor/RichMarkdownEditor.collab.spec.d.ts.map +1 -0
- package/dist/editor/RichMarkdownEditor.collab.spec.js +65 -0
- package/dist/editor/RichMarkdownEditor.collab.spec.js.map +1 -0
- package/dist/editor/RichMarkdownEditor.d.ts +52 -0
- package/dist/editor/RichMarkdownEditor.d.ts.map +1 -0
- package/dist/editor/RichMarkdownEditor.js +38 -0
- package/dist/editor/RichMarkdownEditor.js.map +1 -0
- package/dist/editor/RichMarkdownEditor.roundtrip.spec.d.ts +2 -0
- package/dist/editor/RichMarkdownEditor.roundtrip.spec.d.ts.map +1 -0
- package/dist/editor/RichMarkdownEditor.roundtrip.spec.js +186 -0
- package/dist/editor/RichMarkdownEditor.roundtrip.spec.js.map +1 -0
- package/dist/editor/RunId.d.ts +28 -0
- package/dist/editor/RunId.d.ts.map +1 -0
- package/dist/editor/RunId.js +60 -0
- package/dist/editor/RunId.js.map +1 -0
- package/dist/editor/SharedRichEditor.d.ts +110 -0
- package/dist/editor/SharedRichEditor.d.ts.map +1 -0
- package/dist/editor/SharedRichEditor.js +144 -0
- package/dist/editor/SharedRichEditor.js.map +1 -0
- package/dist/editor/SlashCommandMenu.d.ts +41 -0
- package/dist/editor/SlashCommandMenu.d.ts.map +1 -0
- package/dist/editor/SlashCommandMenu.js +221 -0
- package/dist/editor/SlashCommandMenu.js.map +1 -0
- package/dist/editor/disableHistory.spec.d.ts +2 -0
- package/dist/editor/disableHistory.spec.d.ts.map +1 -0
- package/dist/editor/disableHistory.spec.js +73 -0
- package/dist/editor/disableHistory.spec.js.map +1 -0
- package/dist/editor/extensions.d.ts +178 -0
- package/dist/editor/extensions.d.ts.map +1 -0
- package/dist/editor/extensions.js +224 -0
- package/dist/editor/extensions.js.map +1 -0
- package/dist/editor/gfmDoc.d.ts +24 -0
- package/dist/editor/gfmDoc.d.ts.map +1 -0
- package/dist/editor/gfmDoc.js +83 -0
- package/dist/editor/gfmDoc.js.map +1 -0
- package/dist/editor/gfmDoc.spec.d.ts +2 -0
- package/dist/editor/gfmDoc.spec.d.ts.map +1 -0
- package/dist/editor/gfmDoc.spec.js +194 -0
- package/dist/editor/gfmDoc.spec.js.map +1 -0
- package/dist/editor/index.d.ts +13 -0
- package/dist/editor/index.d.ts.map +1 -0
- package/dist/editor/index.js +13 -0
- package/dist/editor/index.js.map +1 -0
- package/dist/editor/structuralReorderUndo.spec.d.ts +2 -0
- package/dist/editor/structuralReorderUndo.spec.d.ts.map +1 -0
- package/dist/editor/structuralReorderUndo.spec.js +120 -0
- package/dist/editor/structuralReorderUndo.spec.js.map +1 -0
- package/dist/editor/surgical-apply.d.ts +66 -0
- package/dist/editor/surgical-apply.d.ts.map +1 -0
- package/dist/editor/surgical-apply.js +147 -0
- package/dist/editor/surgical-apply.js.map +1 -0
- package/dist/editor/surgical-apply.spec.d.ts +2 -0
- package/dist/editor/surgical-apply.spec.d.ts.map +1 -0
- package/dist/editor/surgical-apply.spec.js +257 -0
- package/dist/editor/surgical-apply.spec.js.map +1 -0
- package/dist/editor/useCollabReconcile.concurrent.spec.d.ts +2 -0
- package/dist/editor/useCollabReconcile.concurrent.spec.d.ts.map +1 -0
- package/dist/editor/useCollabReconcile.concurrent.spec.js +329 -0
- package/dist/editor/useCollabReconcile.concurrent.spec.js.map +1 -0
- package/dist/editor/useCollabReconcile.d.ts +110 -0
- package/dist/editor/useCollabReconcile.d.ts.map +1 -0
- package/dist/editor/useCollabReconcile.idempotent.spec.d.ts +2 -0
- package/dist/editor/useCollabReconcile.idempotent.spec.d.ts.map +1 -0
- package/dist/editor/useCollabReconcile.idempotent.spec.js +248 -0
- package/dist/editor/useCollabReconcile.idempotent.spec.js.map +1 -0
- package/dist/editor/useCollabReconcile.js +440 -0
- package/dist/editor/useCollabReconcile.js.map +1 -0
- package/dist/editor.css +510 -0
- 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 → ``
|
|
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 @@
|
|
|
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 @@
|
|
|
1
|
+
{"version":3,"file":"structuralReorderUndo.spec.d.ts","sourceRoot":"","sources":["../../src/editor/structuralReorderUndo.spec.ts"],"names":[],"mappings":""}
|