@agent-native/toolkit 0.4.9 → 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/collab-ui/types.d.ts.map +1 -1
- package/dist/collab-ui/types.js +11 -2
- package/dist/collab-ui/types.js.map +1 -1
- package/dist/collab-ui/types.spec.d.ts +2 -0
- package/dist/collab-ui/types.spec.d.ts.map +1 -0
- package/dist/collab-ui/types.spec.js +15 -0
- package/dist/collab-ui/types.spec.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,186 @@
|
|
|
1
|
+
// @vitest-environment happy-dom
|
|
2
|
+
import { Editor } from "@tiptap/core";
|
|
3
|
+
import { describe, expect, it } from "vitest";
|
|
4
|
+
import { createRichMarkdownExtensions } from "./RichMarkdownEditor.js";
|
|
5
|
+
/**
|
|
6
|
+
* Round-trip fidelity for the Plan rich-text editor.
|
|
7
|
+
*
|
|
8
|
+
* tiptap-markdown re-serializes the ENTIRE document on every edit. If
|
|
9
|
+
* `serialize(parse(markdown)) !== markdown` for the markdown that plans
|
|
10
|
+
* actually contain, then the FIRST edit of an existing block emits a fully
|
|
11
|
+
* normalized version of text the user never touched — a noisy one-time git
|
|
12
|
+
* diff plus an update-rich-text write that rewrites untouched prose.
|
|
13
|
+
*
|
|
14
|
+
* This suite mounts an `Editor` from the SAME extension factory the component
|
|
15
|
+
* uses ({@link createRichMarkdownExtensions}) so the test and the component can
|
|
16
|
+
* never disagree about the dialect, then pins the round-trip output for a
|
|
17
|
+
* representative plan corpus. Cases fall into two buckets:
|
|
18
|
+
*
|
|
19
|
+
* - byte-stable: `roundTrip(x) === x`. Asserted via `expectStable`.
|
|
20
|
+
* - pinned-lossy: tiptap-markdown 0.9.0 normalizes the input in a way that
|
|
21
|
+
* CANNOT be removed through the public `Markdown.configure` surface
|
|
22
|
+
* (the relevant internals — prosemirror-markdown's `em` serializer and the
|
|
23
|
+
* non-exported `MarkdownTightLists` extension — are not configurable). We
|
|
24
|
+
* are forbidden from reformatting/post-processing stored markdown to chase
|
|
25
|
+
* stability, so these are pinned to their ACTUAL normalized output via
|
|
26
|
+
* `expectNormalizesTo`. That keeps each normalization visible and
|
|
27
|
+
* regression-guarded instead of silently churning.
|
|
28
|
+
*
|
|
29
|
+
* The only lever we are allowed to pull is the tiptap-markdown
|
|
30
|
+
* `Markdown.configure` options in the shared factory. The current config
|
|
31
|
+
* (`bulletListMarker: "-"`, `tightLists: true`, `linkify: false`,
|
|
32
|
+
* `breaks: false`) already minimizes normalization for everything below; the
|
|
33
|
+
* remaining lossy cases are inherent to the library at this version.
|
|
34
|
+
*/
|
|
35
|
+
function roundTrip(markdown) {
|
|
36
|
+
const editor = new Editor({
|
|
37
|
+
element: document.createElement("div"),
|
|
38
|
+
extensions: createRichMarkdownExtensions({ dialect: "gfm" }),
|
|
39
|
+
content: markdown,
|
|
40
|
+
});
|
|
41
|
+
try {
|
|
42
|
+
const storage = editor.storage;
|
|
43
|
+
return storage.markdown?.getMarkdown?.() ?? "";
|
|
44
|
+
}
|
|
45
|
+
finally {
|
|
46
|
+
editor.destroy();
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
/** Asserts the markdown survives parse→serialize unchanged (byte-stable). */
|
|
50
|
+
function expectStable(markdown) {
|
|
51
|
+
expect(roundTrip(markdown)).toBe(markdown);
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Asserts an inherently-lossy case serializes to a KNOWN normalized form.
|
|
55
|
+
* Pins the normalization so it stays visible and regression-guarded; also
|
|
56
|
+
* guards that the case is genuinely lossy (otherwise it belongs in the
|
|
57
|
+
* byte-stable bucket).
|
|
58
|
+
*/
|
|
59
|
+
function expectNormalizesTo(input, normalized) {
|
|
60
|
+
expect(roundTrip(input)).toBe(normalized);
|
|
61
|
+
expect(normalized).not.toBe(input);
|
|
62
|
+
}
|
|
63
|
+
describe("RichMarkdownEditor markdown round-trip", () => {
|
|
64
|
+
describe("byte-stable cases", () => {
|
|
65
|
+
it("headings H1-H4 (ATX)", () => {
|
|
66
|
+
expectStable("# Heading 1");
|
|
67
|
+
expectStable("## Heading 2");
|
|
68
|
+
expectStable("### Heading 3");
|
|
69
|
+
expectStable("#### Heading 4");
|
|
70
|
+
});
|
|
71
|
+
it("paragraphs", () => {
|
|
72
|
+
expectStable("A single plain paragraph.");
|
|
73
|
+
expectStable("First paragraph.\n\nSecond paragraph.");
|
|
74
|
+
});
|
|
75
|
+
it("bold and inline code marks", () => {
|
|
76
|
+
expectStable("Text with **bold** words.");
|
|
77
|
+
expectStable("Text with `inline code` words.");
|
|
78
|
+
expectStable("Mixed **bold** and `code` together.");
|
|
79
|
+
});
|
|
80
|
+
it("bulleted list (tight)", () => {
|
|
81
|
+
expectStable("- One\n- Two\n- Three");
|
|
82
|
+
});
|
|
83
|
+
it("numbered list (tight)", () => {
|
|
84
|
+
expectStable("1. One\n2. Two\n3. Three");
|
|
85
|
+
});
|
|
86
|
+
it("nested bulleted list", () => {
|
|
87
|
+
expectStable("- One\n - Nested A\n - Nested B\n- Two");
|
|
88
|
+
});
|
|
89
|
+
it("a single task item", () => {
|
|
90
|
+
expectStable("- [ ] Todo item");
|
|
91
|
+
expectStable("- [x] Done item");
|
|
92
|
+
});
|
|
93
|
+
it("blockquote", () => {
|
|
94
|
+
expectStable("> A quoted line.");
|
|
95
|
+
});
|
|
96
|
+
it("fenced code block with a language", () => {
|
|
97
|
+
expectStable("```ts\nconst x: number = 1;\n```");
|
|
98
|
+
});
|
|
99
|
+
it("links", () => {
|
|
100
|
+
expectStable("See [the docs](https://example.com/docs) for details.");
|
|
101
|
+
});
|
|
102
|
+
it("horizontal rule", () => {
|
|
103
|
+
expectStable("Above.\n\n---\n\nBelow.");
|
|
104
|
+
});
|
|
105
|
+
it("GFM pipe table when followed by more content", () => {
|
|
106
|
+
// A table in the middle of a body (the common case in a plan) is stable.
|
|
107
|
+
// The trailing-newline normalization only happens when a table is the
|
|
108
|
+
// very last block — see pinned-lossy cases below.
|
|
109
|
+
expectStable([
|
|
110
|
+
"Intro paragraph.",
|
|
111
|
+
"",
|
|
112
|
+
"| Name | Status |",
|
|
113
|
+
"| --- | --- |",
|
|
114
|
+
"| Alpha | Done |",
|
|
115
|
+
"| Beta | Open |",
|
|
116
|
+
"",
|
|
117
|
+
"Closing paragraph.",
|
|
118
|
+
].join("\n"));
|
|
119
|
+
});
|
|
120
|
+
it("a representative mixed plan body (no italics, table not last)", () => {
|
|
121
|
+
expectStable([
|
|
122
|
+
"# Project Plan",
|
|
123
|
+
"",
|
|
124
|
+
"## Overview",
|
|
125
|
+
"",
|
|
126
|
+
"This plan covers the **rollout** of the new flow.",
|
|
127
|
+
"",
|
|
128
|
+
"## Notes",
|
|
129
|
+
"",
|
|
130
|
+
"See [the brief](https://example.com/brief) and run `pnpm test`.",
|
|
131
|
+
"",
|
|
132
|
+
"```ts",
|
|
133
|
+
"const ready = true;",
|
|
134
|
+
"```",
|
|
135
|
+
].join("\n"));
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
describe("pinned-lossy cases (inherent to tiptap-markdown 0.9.0)", () => {
|
|
139
|
+
it("italic: underscore markers normalize to asterisks", () => {
|
|
140
|
+
// tiptap-markdown serializes the italic mark via prosemirror-markdown's
|
|
141
|
+
// `defaultMarkdownSerializer.marks.em`, which hardcodes `*` open/close.
|
|
142
|
+
// There is NO `Markdown.configure` option for the emphasis marker
|
|
143
|
+
// (`bulletListMarker` only controls bullet lists), so `_x_` always
|
|
144
|
+
// re-emits as `*x*`. Asterisk-delimited italics are already stable.
|
|
145
|
+
expectNormalizesTo("Text with _italic_ words.", "Text with *italic* words.");
|
|
146
|
+
expectStable("Text with *italic* words.");
|
|
147
|
+
});
|
|
148
|
+
it("multi-item task lists serialize loose (blank line between items)", () => {
|
|
149
|
+
// tiptap-markdown's tight-list support (MarkdownTightLists) only
|
|
150
|
+
// registers the `tight` attribute for `bulletList`/`orderedList`, never
|
|
151
|
+
// `taskList`, and that extension is not exported for reconfiguration.
|
|
152
|
+
// So task lists with 2+ items always gain a blank line between items.
|
|
153
|
+
// A single task item (above) stays stable.
|
|
154
|
+
expectNormalizesTo("- [ ] Todo item\n- [x] Done item", "- [ ] Todo item\n\n- [x] Done item");
|
|
155
|
+
});
|
|
156
|
+
it("nested task list also serializes loose", () => {
|
|
157
|
+
expectNormalizesTo("- [ ] parent\n - [x] child", "- [ ] parent\n\n - [x] child");
|
|
158
|
+
});
|
|
159
|
+
it("a table as the LAST block gains a trailing newline", () => {
|
|
160
|
+
// When a pipe table is the final block in the document the serializer
|
|
161
|
+
// appends a trailing "\n". (Mid-body tables — see byte-stable cases —
|
|
162
|
+
// do not.) Not removable via public config.
|
|
163
|
+
expectNormalizesTo([
|
|
164
|
+
"| Name | Status |",
|
|
165
|
+
"| --- | --- |",
|
|
166
|
+
"| Alpha | Done |",
|
|
167
|
+
"| Beta | Open |",
|
|
168
|
+
].join("\n"), [
|
|
169
|
+
"| Name | Status |",
|
|
170
|
+
"| --- | --- |",
|
|
171
|
+
"| Alpha | Done |",
|
|
172
|
+
"| Beta | Open |",
|
|
173
|
+
"",
|
|
174
|
+
].join("\n"));
|
|
175
|
+
});
|
|
176
|
+
});
|
|
177
|
+
describe("intentional normalizations (desired, GFM-canonical)", () => {
|
|
178
|
+
it("`*` bullet markers normalize to `-` per bulletListMarker config", () => {
|
|
179
|
+
// We deliberately keep bulletListMarker: "-" so all bullets converge on
|
|
180
|
+
// the GFM-canonical dash. `*`/`+` bullets becoming `-` is intended.
|
|
181
|
+
expectNormalizesTo("* One\n* Two", "- One\n- Two");
|
|
182
|
+
expectNormalizesTo("+ One\n+ Two", "- One\n- Two");
|
|
183
|
+
});
|
|
184
|
+
});
|
|
185
|
+
});
|
|
186
|
+
//# sourceMappingURL=RichMarkdownEditor.roundtrip.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RichMarkdownEditor.roundtrip.spec.js","sourceRoot":"","sources":["../../src/editor/RichMarkdownEditor.roundtrip.spec.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { Extension } from "@tiptap/core";
|
|
2
|
+
/**
|
|
3
|
+
* Node types that carry the optional `runId` attribute.
|
|
4
|
+
*
|
|
5
|
+
* These are exactly the top-level block nodes a plan's `rich-text` block can
|
|
6
|
+
* serialize to. The plan's `doc ↔ blocks[]` bridge stamps `runId` onto the
|
|
7
|
+
* FIRST node of each rich-text run so a re-parse can map the run back to its
|
|
8
|
+
* originating block id (stable ids across edits). Atom/structured blocks live
|
|
9
|
+
* in their own `planBlock` node and do not need this attribute.
|
|
10
|
+
*/
|
|
11
|
+
export declare const RUN_ID_NODE_TYPES: readonly ["paragraph", "heading", "bulletList", "orderedList", "taskList", "blockquote", "codeBlock"];
|
|
12
|
+
/**
|
|
13
|
+
* Tiptap extension that adds a GLOBAL `runId` attribute (default `null`) to the
|
|
14
|
+
* block node types in {@link RUN_ID_NODE_TYPES}.
|
|
15
|
+
*
|
|
16
|
+
* - `renderHTML` emits `data-run-id` only when the attribute is set, so the
|
|
17
|
+
* live editor's DOM carries the id for the doc↔blocks bridge.
|
|
18
|
+
* - `parseHTML` reads `data-run-id` back so a paste / re-parse preserves it.
|
|
19
|
+
* - Markdown serialization deliberately IGNORES `runId`: GFM never emits it.
|
|
20
|
+
* `tiptap-markdown` drops attributes it has no serializer for, so we simply
|
|
21
|
+
* don't register a markdown serializer here — the attribute is invisible to
|
|
22
|
+
* the GFM round-trip and only lives in the ProseMirror JSON / DOM.
|
|
23
|
+
*
|
|
24
|
+
* Used by BOTH the headless `gfmDoc` editor and the live plan editor so the
|
|
25
|
+
* schema is identical on both sides of the bridge.
|
|
26
|
+
*/
|
|
27
|
+
export declare const RunId: Extension<any, any>;
|
|
28
|
+
//# sourceMappingURL=RunId.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RunId.d.ts","sourceRoot":"","sources":["../../src/editor/RunId.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEzC;;;;;;;;GAQG;AACH,eAAO,MAAM,iBAAiB,YAC5B,WAAW,EACX,SAAS,EACT,YAAY,EACZ,aAAa,EACb,UAAU,EACV,YAAY,EACZ,WAAW,CACH,CAAC;AAEX;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,KAAK,qBAwBhB,CAAC"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { Extension } from "@tiptap/core";
|
|
2
|
+
/**
|
|
3
|
+
* Node types that carry the optional `runId` attribute.
|
|
4
|
+
*
|
|
5
|
+
* These are exactly the top-level block nodes a plan's `rich-text` block can
|
|
6
|
+
* serialize to. The plan's `doc ↔ blocks[]` bridge stamps `runId` onto the
|
|
7
|
+
* FIRST node of each rich-text run so a re-parse can map the run back to its
|
|
8
|
+
* originating block id (stable ids across edits). Atom/structured blocks live
|
|
9
|
+
* in their own `planBlock` node and do not need this attribute.
|
|
10
|
+
*/
|
|
11
|
+
export const RUN_ID_NODE_TYPES = [
|
|
12
|
+
"paragraph",
|
|
13
|
+
"heading",
|
|
14
|
+
"bulletList",
|
|
15
|
+
"orderedList",
|
|
16
|
+
"taskList",
|
|
17
|
+
"blockquote",
|
|
18
|
+
"codeBlock",
|
|
19
|
+
];
|
|
20
|
+
/**
|
|
21
|
+
* Tiptap extension that adds a GLOBAL `runId` attribute (default `null`) to the
|
|
22
|
+
* block node types in {@link RUN_ID_NODE_TYPES}.
|
|
23
|
+
*
|
|
24
|
+
* - `renderHTML` emits `data-run-id` only when the attribute is set, so the
|
|
25
|
+
* live editor's DOM carries the id for the doc↔blocks bridge.
|
|
26
|
+
* - `parseHTML` reads `data-run-id` back so a paste / re-parse preserves it.
|
|
27
|
+
* - Markdown serialization deliberately IGNORES `runId`: GFM never emits it.
|
|
28
|
+
* `tiptap-markdown` drops attributes it has no serializer for, so we simply
|
|
29
|
+
* don't register a markdown serializer here — the attribute is invisible to
|
|
30
|
+
* the GFM round-trip and only lives in the ProseMirror JSON / DOM.
|
|
31
|
+
*
|
|
32
|
+
* Used by BOTH the headless `gfmDoc` editor and the live plan editor so the
|
|
33
|
+
* schema is identical on both sides of the bridge.
|
|
34
|
+
*/
|
|
35
|
+
export const RunId = Extension.create({
|
|
36
|
+
name: "runId",
|
|
37
|
+
addGlobalAttributes() {
|
|
38
|
+
return [
|
|
39
|
+
{
|
|
40
|
+
types: [...RUN_ID_NODE_TYPES],
|
|
41
|
+
attributes: {
|
|
42
|
+
runId: {
|
|
43
|
+
default: null,
|
|
44
|
+
// Read the id off the rendered DOM so paste / re-parse round-trips.
|
|
45
|
+
parseHTML: (element) => element.getAttribute("data-run-id"),
|
|
46
|
+
// Only emit the attribute when set; an unset (null) runId adds
|
|
47
|
+
// nothing to the DOM so untouched nodes stay clean.
|
|
48
|
+
renderHTML: (attributes) => {
|
|
49
|
+
const runId = attributes.runId;
|
|
50
|
+
if (!runId)
|
|
51
|
+
return {};
|
|
52
|
+
return { "data-run-id": runId };
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
];
|
|
58
|
+
},
|
|
59
|
+
});
|
|
60
|
+
//# sourceMappingURL=RunId.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RunId.js","sourceRoot":"","sources":["../../src/editor/RunId.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEzC;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG;IAC/B,WAAW;IACX,SAAS;IACT,YAAY;IACZ,aAAa;IACb,UAAU;IACV,YAAY;IACZ,WAAW;CACH,CAAC;AAEX;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,MAAM,KAAK,GAAG,SAAS,CAAC,MAAM,CAAC;IACpC,IAAI,EAAE,OAAO;IAEb,mBAAmB;QACjB,OAAO;YACL;gBACE,KAAK,EAAE,CAAC,GAAG,iBAAiB,CAAC;gBAC7B,UAAU,EAAE;oBACV,KAAK,EAAE;wBACL,OAAO,EAAE,IAAI;wBACb,oEAAoE;wBACpE,SAAS,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,YAAY,CAAC,aAAa,CAAC;wBAC3D,+DAA+D;wBAC/D,oDAAoD;wBACpD,UAAU,EAAE,CAAC,UAAU,EAAE,EAAE;4BACzB,MAAM,KAAK,GAAI,UAAwC,CAAC,KAAK,CAAC;4BAC9D,IAAI,CAAC,KAAK;gCAAE,OAAO,EAAE,CAAC;4BACtB,OAAO,EAAE,aAAa,EAAE,KAAK,EAAE,CAAC;wBAClC,CAAC;qBACF;iBACF;aACF;SACF,CAAC;IACJ,CAAC;CACF,CAAC,CAAC"}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import type { Extension, Node, Mark } from "@tiptap/core";
|
|
2
|
+
import type { Awareness } from "y-protocols/awareness";
|
|
3
|
+
import type { Doc as YDoc } from "yjs";
|
|
4
|
+
import { type BubbleToolbarItem } from "./BubbleToolbar.js";
|
|
5
|
+
import { type RichMarkdownDialect, type RichMarkdownEditorPreset, type RichMarkdownCollabUser, type SharedEditorFeatures } from "./extensions.js";
|
|
6
|
+
import type { ImageUploadFn } from "./ImageExtension.js";
|
|
7
|
+
import { type SlashCommandItem } from "./SlashCommandMenu.js";
|
|
8
|
+
import { type UseCollabReconcileOptions } from "./useCollabReconcile.js";
|
|
9
|
+
export interface SharedRichEditorProps {
|
|
10
|
+
value: string;
|
|
11
|
+
onChange: (markdown: string) => void;
|
|
12
|
+
onBlur?: () => void;
|
|
13
|
+
contentUpdatedAt?: string | null;
|
|
14
|
+
editable?: boolean;
|
|
15
|
+
dialect?: RichMarkdownDialect;
|
|
16
|
+
preset?: RichMarkdownEditorPreset;
|
|
17
|
+
/** Toggle individual base extensions (tables/tasks/link/codeBlock/image). */
|
|
18
|
+
features?: SharedEditorFeatures;
|
|
19
|
+
/**
|
|
20
|
+
* Injectable image uploader for the shared image block. Used only when
|
|
21
|
+
* `features.image` is on. Pass `uploadEditorImage` (the framework
|
|
22
|
+
* `upload-image` action) for a real uploading image block.
|
|
23
|
+
*/
|
|
24
|
+
onImageUpload?: ImageUploadFn | null;
|
|
25
|
+
/**
|
|
26
|
+
* App-specific extensions (Notion nodes, media, drag handles, comment
|
|
27
|
+
* anchors, …) appended after the shared base schema.
|
|
28
|
+
*/
|
|
29
|
+
extraExtensions?: Array<Extension | Node | Mark>;
|
|
30
|
+
placeholder?: string;
|
|
31
|
+
className?: string;
|
|
32
|
+
editorClassName?: string;
|
|
33
|
+
ariaLabel?: string;
|
|
34
|
+
interactive?: boolean;
|
|
35
|
+
/**
|
|
36
|
+
* Yjs document for real-time multi-user editing. When provided, prose is
|
|
37
|
+
* authored against the shared Y.Doc and mirrored back to `value` as markdown
|
|
38
|
+
* (still the source of truth). When omitted, the editor is a plain controlled
|
|
39
|
+
* `value`/`onChange` editor — the existing, non-collaborative behavior.
|
|
40
|
+
*/
|
|
41
|
+
ydoc?: YDoc | null;
|
|
42
|
+
/** True after the collab provider has loaded persisted Y.Doc state. */
|
|
43
|
+
collabSynced?: boolean;
|
|
44
|
+
/** Shared awareness instance for live cursors/presence. */
|
|
45
|
+
awareness?: Awareness | null;
|
|
46
|
+
/** Current user info for the collaborative cursor label. */
|
|
47
|
+
user?: RichMarkdownCollabUser | null;
|
|
48
|
+
/**
|
|
49
|
+
* Disable StarterKit's built-in undo/redo for a controlled (non-collab)
|
|
50
|
+
* editor whose host owns its own undo authority (see
|
|
51
|
+
* {@link CreateSharedEditorExtensionsOptions.disableHistory}). Ignored when a
|
|
52
|
+
* `ydoc` is present (Yjs always owns history then). Default `false`, so every
|
|
53
|
+
* existing embedder is unchanged.
|
|
54
|
+
*/
|
|
55
|
+
disableHistory?: boolean;
|
|
56
|
+
/** Override the slash-menu block command list. */
|
|
57
|
+
slashItems?: SlashCommandItem[];
|
|
58
|
+
/** Override the bubble-toolbar item builder. */
|
|
59
|
+
buildBubbleItems?: (editor: import("@tiptap/react").Editor, toggleLink: () => void) => BubbleToolbarItem[];
|
|
60
|
+
/**
|
|
61
|
+
* Override how the editor's content is read into the canonical `value`.
|
|
62
|
+
* Defaults to the tiptap-markdown storage reader. Apps with a custom on-disk
|
|
63
|
+
* format (Content's NFM, the plan's `blocks[]` JSON) pass their serializer so
|
|
64
|
+
* seed/reconcile/onChange all speak the same value space.
|
|
65
|
+
*/
|
|
66
|
+
getMarkdown?: (editor: import("@tiptap/react").Editor) => string;
|
|
67
|
+
/** Override how the canonical `value` is applied into the editor (seed + reconcile). */
|
|
68
|
+
setContent?: (editor: import("@tiptap/react").Editor, value: string, options: {
|
|
69
|
+
emitUpdate?: boolean;
|
|
70
|
+
addToHistory?: boolean;
|
|
71
|
+
}) => void;
|
|
72
|
+
/**
|
|
73
|
+
* Optional parser for surgical reconcile. Custom value formats that already
|
|
74
|
+
* handle surgical writes inside `setContent` can pass `false` so the default
|
|
75
|
+
* markdown parser never treats their source bytes as literal markdown.
|
|
76
|
+
*/
|
|
77
|
+
parseValue?: UseCollabReconcileOptions["parseValue"];
|
|
78
|
+
/** Canonicalize `value` for the echo / already-in-sync equality checks. */
|
|
79
|
+
normalizeValue?: (value: string) => string;
|
|
80
|
+
/** Override the empty-doc seed predicate (see {@link useCollabReconcile}). */
|
|
81
|
+
shouldSeed?: (info: {
|
|
82
|
+
value: string;
|
|
83
|
+
currentMarkdown: string;
|
|
84
|
+
fragmentLength: number;
|
|
85
|
+
}) => boolean;
|
|
86
|
+
/** Initial "applied" watermark (see {@link useCollabReconcile}). */
|
|
87
|
+
initialAppliedUpdatedAt?: string | null;
|
|
88
|
+
/** Extra class on the editor wrapper (e.g. a drag-handle `wrapperSelector` hook). */
|
|
89
|
+
wrapperClassName?: string;
|
|
90
|
+
/**
|
|
91
|
+
* Fires once the editor instance exists. Lets a host capture the root
|
|
92
|
+
* `editor.view` — e.g. to repaint the WHOLE document after a structural block
|
|
93
|
+
* move (a column emptied and its container dissolved) that a surgical
|
|
94
|
+
* per-region patch can't express, since the change is in the root doc itself.
|
|
95
|
+
*/
|
|
96
|
+
onEditorReady?: (editor: import("@tiptap/react").Editor) => void;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* The single shared rich markdown editor surface. Combines
|
|
100
|
+
* {@link createSharedEditorExtensions} (schema + dialect-keyed markdown +
|
|
101
|
+
* optional collab + app extras), {@link useCollabReconcile} (seed / reconcile /
|
|
102
|
+
* lead-client logic), and the shared {@link SlashCommandMenu} +
|
|
103
|
+
* {@link BubbleToolbar}.
|
|
104
|
+
*
|
|
105
|
+
* With no `ydoc` it is a controlled `value`/`onChange` single-user editor.
|
|
106
|
+
* With a `ydoc` it binds the framework collaboration stack; markdown stays the
|
|
107
|
+
* canonical saved representation while the Y.Doc is transient live state.
|
|
108
|
+
*/
|
|
109
|
+
export declare function SharedRichEditor({ value, onChange, onBlur, contentUpdatedAt, editable, dialect, preset, features, onImageUpload, extraExtensions, placeholder, className, editorClassName, ariaLabel, interactive, ydoc, collabSynced, awareness, user, disableHistory, slashItems, buildBubbleItems, getMarkdown, setContent, parseValue, normalizeValue, shouldSeed, initialAppliedUpdatedAt, wrapperClassName, onEditorReady, }: SharedRichEditorProps): import("react").JSX.Element;
|
|
110
|
+
//# sourceMappingURL=SharedRichEditor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SharedRichEditor.d.ts","sourceRoot":"","sources":["../../src/editor/SharedRichEditor.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { EditorContent, useEditor } from "@tiptap/react";
|
|
3
|
+
import { useEffect, useMemo, useRef } from "react";
|
|
4
|
+
import { cn } from "../utils.js";
|
|
5
|
+
import { BubbleToolbar } from "./BubbleToolbar.js";
|
|
6
|
+
import { createSharedEditorExtensions, } from "./extensions.js";
|
|
7
|
+
import { SlashCommandMenu } from "./SlashCommandMenu.js";
|
|
8
|
+
import { useCollabReconcile, getEditorMarkdown, } from "./useCollabReconcile.js";
|
|
9
|
+
/**
|
|
10
|
+
* The single shared rich markdown editor surface. Combines
|
|
11
|
+
* {@link createSharedEditorExtensions} (schema + dialect-keyed markdown +
|
|
12
|
+
* optional collab + app extras), {@link useCollabReconcile} (seed / reconcile /
|
|
13
|
+
* lead-client logic), and the shared {@link SlashCommandMenu} +
|
|
14
|
+
* {@link BubbleToolbar}.
|
|
15
|
+
*
|
|
16
|
+
* With no `ydoc` it is a controlled `value`/`onChange` single-user editor.
|
|
17
|
+
* With a `ydoc` it binds the framework collaboration stack; markdown stays the
|
|
18
|
+
* canonical saved representation while the Y.Doc is transient live state.
|
|
19
|
+
*/
|
|
20
|
+
export function SharedRichEditor({ value, onChange, onBlur, contentUpdatedAt, editable = true, dialect = "gfm", preset = "plan", features, onImageUpload = null, extraExtensions, placeholder = "Type '/' for commands...", className, editorClassName, ariaLabel, interactive = editable, ydoc = null, collabSynced = true, awareness = null, user = null, disableHistory = false, slashItems, buildBubbleItems, getMarkdown, setContent, parseValue, normalizeValue, shouldSeed, initialAppliedUpdatedAt, wrapperClassName, onEditorReady, }) {
|
|
21
|
+
const readMarkdown = getMarkdown ?? getEditorMarkdown;
|
|
22
|
+
const onChangeRef = useRef(onChange);
|
|
23
|
+
const onBlurRef = useRef(onBlur);
|
|
24
|
+
onChangeRef.current = onChange;
|
|
25
|
+
onBlurRef.current = onBlur;
|
|
26
|
+
const extensions = useMemo(() => createSharedEditorExtensions({
|
|
27
|
+
dialect,
|
|
28
|
+
preset,
|
|
29
|
+
placeholder,
|
|
30
|
+
features,
|
|
31
|
+
extraExtensions,
|
|
32
|
+
onImageUpload,
|
|
33
|
+
collab: ydoc ? { ydoc, awareness, user } : null,
|
|
34
|
+
disableHistory,
|
|
35
|
+
}),
|
|
36
|
+
// `preset` is retained in the dependency list so future preset-specific
|
|
37
|
+
// schema branches re-create the editor; it is currently schema-neutral. The
|
|
38
|
+
// collab inputs are identity-stable per block (one Y.Doc per docId), so they
|
|
39
|
+
// only change on a genuine doc switch — exactly when the editor must
|
|
40
|
+
// re-create to rebind Collaboration.
|
|
41
|
+
[
|
|
42
|
+
dialect,
|
|
43
|
+
placeholder,
|
|
44
|
+
preset,
|
|
45
|
+
features,
|
|
46
|
+
extraExtensions,
|
|
47
|
+
onImageUpload,
|
|
48
|
+
ydoc,
|
|
49
|
+
awareness,
|
|
50
|
+
user?.name,
|
|
51
|
+
user?.email,
|
|
52
|
+
user?.color,
|
|
53
|
+
disableHistory,
|
|
54
|
+
]);
|
|
55
|
+
const collab = !!ydoc;
|
|
56
|
+
// The collab hook needs the editor, but useEditor's `onUpdate` needs the
|
|
57
|
+
// hook's guards. Break the cycle with a ref: `onUpdate` reads the guards
|
|
58
|
+
// through `guardsRef`, which is populated right after the hook runs below.
|
|
59
|
+
// `onUpdate` only ever fires after the editor exists, by which point the ref
|
|
60
|
+
// holds the real guards.
|
|
61
|
+
const guardsRef = useRef(null);
|
|
62
|
+
const editor = useEditor({
|
|
63
|
+
extensions,
|
|
64
|
+
// With Collaboration active the prose is owned by the shared Y.XmlFragment.
|
|
65
|
+
// Seeding `content` here too would make the editor initialize from BOTH the
|
|
66
|
+
// prop and the Y.Doc, firing a spurious initial update that could autosave a
|
|
67
|
+
// stale value over newer SQL. The lead-client seed effect populates an empty
|
|
68
|
+
// doc instead. Non-collab editors keep initializing from `value`.
|
|
69
|
+
// With Collaboration the Y.Doc owns the prose (seeded by the lead client).
|
|
70
|
+
// With a custom `setContent` the reconcile seeds the editor too (the raw
|
|
71
|
+
// `value` is not directly settable content — e.g. the plan's blocks JSON),
|
|
72
|
+
// so only the plain markdown path seeds from `value` here.
|
|
73
|
+
content: collab || setContent ? null : value,
|
|
74
|
+
editable,
|
|
75
|
+
editorProps: {
|
|
76
|
+
attributes: {
|
|
77
|
+
class: cn("an-rich-md-prose", editorClassName),
|
|
78
|
+
...(ariaLabel ? { role: "textbox", "aria-label": ariaLabel } : {}),
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
onUpdate: ({ editor, transaction }) => {
|
|
82
|
+
const guards = guardsRef.current;
|
|
83
|
+
if (!guards || guards.shouldIgnoreUpdate(transaction))
|
|
84
|
+
return;
|
|
85
|
+
try {
|
|
86
|
+
const markdown = readMarkdown(editor);
|
|
87
|
+
if (!guards.registerEmitted(markdown))
|
|
88
|
+
return;
|
|
89
|
+
queueMicrotask(() => onChangeRef.current(markdown));
|
|
90
|
+
}
|
|
91
|
+
catch (error) {
|
|
92
|
+
console.error("Markdown serialization error:", error);
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
onBlur: () => {
|
|
96
|
+
onBlurRef.current?.();
|
|
97
|
+
},
|
|
98
|
+
// Recreate the editor when the shared Y.Doc identity changes — including
|
|
99
|
+
// null → doc. Extensions are baked in at creation, so a ydoc that arrives
|
|
100
|
+
// AFTER the first mount (fresh page load: the session/user resolves after
|
|
101
|
+
// the editor mounts) would otherwise never bind Collaboration: the editor
|
|
102
|
+
// looks fine but produces no Yjs updates and never receives peers' edits.
|
|
103
|
+
}, [ydoc]);
|
|
104
|
+
const collabState = useCollabReconcile({
|
|
105
|
+
editor,
|
|
106
|
+
ydoc,
|
|
107
|
+
collabSynced,
|
|
108
|
+
awareness,
|
|
109
|
+
value,
|
|
110
|
+
contentUpdatedAt,
|
|
111
|
+
editable,
|
|
112
|
+
getMarkdown: readMarkdown,
|
|
113
|
+
setContent,
|
|
114
|
+
parseValue,
|
|
115
|
+
normalizeValue,
|
|
116
|
+
shouldSeed,
|
|
117
|
+
initialAppliedUpdatedAt,
|
|
118
|
+
});
|
|
119
|
+
guardsRef.current = collabState;
|
|
120
|
+
useEffect(() => {
|
|
121
|
+
if (!editor || editor.isDestroyed)
|
|
122
|
+
return;
|
|
123
|
+
editor.setEditable(editable);
|
|
124
|
+
}, [editable, editor]);
|
|
125
|
+
useEffect(() => {
|
|
126
|
+
if (editor)
|
|
127
|
+
onEditorReady?.(editor);
|
|
128
|
+
}, [editor, onEditorReady]);
|
|
129
|
+
useEffect(() => () => editor?.destroy(), [editor]);
|
|
130
|
+
const handleWrapperClick = (event) => {
|
|
131
|
+
if (!editable || !editor || editor.isDestroyed)
|
|
132
|
+
return;
|
|
133
|
+
const target = event.target;
|
|
134
|
+
if (target.classList.contains("an-rich-md-wrapper") ||
|
|
135
|
+
target.classList.contains("an-rich-md-clickable")) {
|
|
136
|
+
editor.chain().focus("end").run();
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
if (!editor) {
|
|
140
|
+
return (_jsx("div", { className: cn("an-rich-md-wrapper an-rich-md-loading", className), "data-plan-interactive": interactive ? true : undefined }));
|
|
141
|
+
}
|
|
142
|
+
return (_jsxs("div", { className: cn("an-rich-md-wrapper an-rich-md-clickable", !editable && "an-rich-md-wrapper--readonly", wrapperClassName, className), onClick: handleWrapperClick, "data-plan-interactive": interactive ? true : undefined, children: [editable ? (_jsx(BubbleToolbar, { editor: editor, buildItems: buildBubbleItems })) : null, editable ? (_jsx(SlashCommandMenu, { editor: editor, items: slashItems })) : null, _jsx(EditorContent, { editor: editor })] }));
|
|
143
|
+
}
|
|
144
|
+
//# sourceMappingURL=SharedRichEditor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SharedRichEditor.js","sourceRoot":"","sources":["../../src/editor/SharedRichEditor.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { Editor } from "@tiptap/react";
|
|
2
|
+
import { type ImageUploadFn } from "./ImageExtension.js";
|
|
3
|
+
/** A single slash-menu block command. Apps can extend the default list. */
|
|
4
|
+
export interface SlashCommandItem {
|
|
5
|
+
title: string;
|
|
6
|
+
description: string;
|
|
7
|
+
/**
|
|
8
|
+
* Optional hidden search text. Use this for raw block types and aliases that
|
|
9
|
+
* should match slash queries without making the visible description verbose.
|
|
10
|
+
*/
|
|
11
|
+
searchText?: string;
|
|
12
|
+
/** Short text glyph shown in the menu (T, H1, tbl, …). */
|
|
13
|
+
icon: string;
|
|
14
|
+
action: (editor: Editor) => void;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* The default block commands — Plan's current set. Apps pass their own `items`
|
|
18
|
+
* (typically `[...DEFAULT_SLASH_COMMANDS, ...extra]`) to extend it.
|
|
19
|
+
*/
|
|
20
|
+
export declare const DEFAULT_SLASH_COMMANDS: SlashCommandItem[];
|
|
21
|
+
/**
|
|
22
|
+
* Build the `/image` slash command for the shared image block. Requires the
|
|
23
|
+
* editor to mount the shared image extension (`features.image`) and an
|
|
24
|
+
* {@link ImageUploadFn}; the command opens a native file picker and uploads +
|
|
25
|
+
* inserts the chosen image(s). Add it to the list an app passes to
|
|
26
|
+
* {@link SlashCommandMenu} (e.g. `[...DEFAULT_SLASH_COMMANDS, createImageSlashCommand(upload)]`).
|
|
27
|
+
*/
|
|
28
|
+
export declare function createImageSlashCommand(upload: ImageUploadFn): SlashCommandItem;
|
|
29
|
+
export interface SlashCommandMenuProps {
|
|
30
|
+
editor: Editor;
|
|
31
|
+
/** Block command list. Defaults to {@link DEFAULT_SLASH_COMMANDS}. */
|
|
32
|
+
items?: SlashCommandItem[];
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* The shared "/" block-insert menu. Detects a `/query` at the caret, filters the
|
|
36
|
+
* provided command list, and renders a fixed-position picker with keyboard
|
|
37
|
+
* navigation. Extracted from the inline plan menu so apps share one
|
|
38
|
+
* implementation and only swap the command list.
|
|
39
|
+
*/
|
|
40
|
+
export declare function SlashCommandMenu({ editor, items, }: SlashCommandMenuProps): import("react").JSX.Element | null;
|
|
41
|
+
//# sourceMappingURL=SlashCommandMenu.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SlashCommandMenu.d.ts","sourceRoot":"","sources":["../../src/editor/SlashCommandMenu.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAW5C,OAAO,EAAsB,KAAK,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAE7E,2EAA2E;AAC3E,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,0DAA0D;IAC1D,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;CAClC;AAED;;;GAGG;AACH,eAAO,MAAM,sBAAsB,EAAE,gBAAgB,EA2EpD,CAAC;AAEF;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,aAAa,GACpB,gBAAgB,CAOlB;AAED,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,MAAM,CAAC;IACf,sEAAsE;IACtE,KAAK,CAAC,EAAE,gBAAgB,EAAE,CAAC;CAC5B;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,EAC/B,MAAM,EACN,KAA8B,GAC/B,EAAE,qBAAqB,sCAwKvB"}
|