@pixerate/editor 0.234.0 → 0.236.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 (45) hide show
  1. package/dist/agent/index.cjs +286 -27
  2. package/dist/agent/index.d.cts +1 -0
  3. package/dist/agent/index.d.ts +1 -0
  4. package/dist/agent/index.js +261 -2
  5. package/dist/agent/reviewTools.d.cts +16 -0
  6. package/dist/agent/reviewTools.d.ts +16 -0
  7. package/dist/animation-editor/controller.d.cts +25 -0
  8. package/dist/animation-editor/controller.d.ts +25 -0
  9. package/dist/animation-editor/index.cjs +159 -50
  10. package/dist/animation-editor/index.d.cts +1 -0
  11. package/dist/animation-editor/index.d.ts +1 -0
  12. package/dist/animation-editor/index.js +115 -6
  13. package/dist/animation-editor/layers.d.cts +2 -0
  14. package/dist/animation-editor/layers.d.ts +2 -0
  15. package/dist/animation-editor/sequence.d.cts +33 -0
  16. package/dist/animation-editor/sequence.d.ts +33 -0
  17. package/dist/{chunk-PI2UYMZY.js → chunk-FSLKBQU7.js} +269 -15
  18. package/dist/{chunk-I277KJLQ.js → chunk-G3RUKJ5C.js} +105 -1
  19. package/dist/{chunk-6RZVFYGJ.cjs → chunk-JWCKJNDR.cjs} +105 -1
  20. package/dist/{chunk-3MO3ZS7E.js → chunk-PHYOZK3B.js} +59 -311
  21. package/dist/{chunk-CZBRY4SW.cjs → chunk-WPWHT4Z6.cjs} +122 -374
  22. package/dist/{chunk-O7QXVGMP.cjs → chunk-WV5WTOC6.cjs} +295 -41
  23. package/dist/effects/index.cjs +19 -11
  24. package/dist/effects/index.d.cts +1 -0
  25. package/dist/effects/index.d.ts +1 -0
  26. package/dist/effects/index.js +9 -1
  27. package/dist/effects/template-tools.d.cts +25 -0
  28. package/dist/effects/template-tools.d.ts +25 -0
  29. package/dist/effects/templates.d.cts +30 -1
  30. package/dist/effects/templates.d.ts +30 -1
  31. package/dist/extensions/index.cjs +6 -6
  32. package/dist/extensions/index.js +10 -10
  33. package/dist/index.cjs +11 -11
  34. package/dist/index.js +10 -10
  35. package/dist/video-editor/controller.d.cts +26 -0
  36. package/dist/video-editor/controller.d.ts +26 -0
  37. package/dist/video-editor/index.cjs +187 -42
  38. package/dist/video-editor/index.d.cts +1 -0
  39. package/dist/video-editor/index.d.ts +1 -0
  40. package/dist/video-editor/index.js +145 -0
  41. package/dist/video-editor/sequence.d.cts +38 -0
  42. package/dist/video-editor/sequence.d.ts +38 -0
  43. package/package.json +1 -1
  44. package/skills/pixerate-rich-text/SKILL.md +28 -1
  45. package/skills/pixerate-rich-text-revise/SKILL.md +8 -1
@@ -1,9 +1,3 @@
1
- import {
2
- effectLayerInput,
3
- effectLayerOffered,
4
- effectLayerRole,
5
- effectSubjectKind
6
- } from "../chunk-I277KJLQ.js";
7
1
  import {
8
2
  createVectorMorph
9
3
  } from "../chunk-YMREOA67.js";
@@ -15,6 +9,14 @@ import {
15
9
  namedWithSuggestion,
16
10
  suggestName
17
11
  } from "../chunk-EUKY4KFX.js";
12
+ import {
13
+ effectLayerInput,
14
+ effectLayerOffered,
15
+ effectLayerRole,
16
+ effectSubjectKind,
17
+ effectTemplateTools,
18
+ fillEffectTemplate
19
+ } from "../chunk-G3RUKJ5C.js";
18
20
  import {
19
21
  IDENTITY_MATRIX,
20
22
  applyMatrix,
@@ -1802,7 +1804,10 @@ var MotionLayersEngine = class {
1802
1804
  this.reset();
1803
1805
  this.listeners.clear();
1804
1806
  }
1807
+ /** Goes up each time pictures come in or are cleared, so a view that caches frames knows to draw again. */
1808
+ revision = 0;
1805
1809
  notify() {
1810
+ this.revision++;
1806
1811
  this.listeners.forEach((l) => l());
1807
1812
  }
1808
1813
  size(b) {
@@ -4484,6 +4489,57 @@ async function checkMotionShotLayers(scene, provider) {
4484
4489
  return issues;
4485
4490
  }
4486
4491
 
4492
+ // src/animation-editor/sequence.ts
4493
+ var fresh = (used, base) => {
4494
+ const clean = base.replace(/[^\w.-]+/g, "-").replace(/^[^A-Za-z_]+/, "") || "item";
4495
+ if (!used.has(clean)) return used.add(clean), clean;
4496
+ for (let i = 2; ; i++) if (!used.has(`${clean}-${i}`)) return used.add(`${clean}-${i}`), `${clean}-${i}`;
4497
+ };
4498
+ function motionShotsFromSequence(sequence, options = {}) {
4499
+ const sx = (options.width ?? sequence.stage.width) / sequence.stage.width;
4500
+ const sy = (options.height ?? sequence.stage.height) / sequence.stage.height;
4501
+ const scale = (r) => ({ x: r.x * sx, y: r.y * sy, width: r.width * sx, height: r.height * sy });
4502
+ const full = { x: 0, y: 0, width: sequence.stage.width * sx, height: sequence.stage.height * sy };
4503
+ const shotIds = new Set(options.shotIds ?? []);
4504
+ const layerIds = new Set(options.layerIds ?? []);
4505
+ const notes = [];
4506
+ const provider = options.provider ? { provider: options.provider } : {};
4507
+ const shots = sequence.shots.map((s, i) => {
4508
+ const id = fresh(shotIds, `shot${i + 1}`);
4509
+ const framing = s.camera?.framing ? scale(s.camera.framing) : void 0;
4510
+ const view = framing ?? full;
4511
+ const layers = [];
4512
+ for (const layer of s.layers) {
4513
+ if (layer.subject && "video" in layer.subject) {
4514
+ notes.push(`Shot ${i + 1}: a layer plays a video, which an animation cannot; it was left out (the video editor plays it).`);
4515
+ continue;
4516
+ }
4517
+ const { id: given, rect, subject, ...rest } = layer;
4518
+ layers.push({ ...rest, id: fresh(layerIds, given ?? "layer"), ...subject ? { subject } : {}, ...rect ? { rect: scale(rect) } : {}, ...layer.effect ? provider : {} });
4519
+ }
4520
+ if (s.title) layers.push({ id: fresh(layerIds, `${id}-title`), subject: { text: s.title }, role: "overlay", rect: { x: view.x + view.width * 0.1, y: view.y + view.height * 0.38, width: view.width * 0.8, height: view.height * 0.24 } });
4521
+ if (s.caption) layers.push({ id: fresh(layerIds, `${id}-caption`), subject: { text: s.caption }, role: "overlay", rect: { x: view.x + view.width * 0.1, y: view.y + view.height * 0.8, width: view.width * 0.8, height: view.height * 0.1 } });
4522
+ const camera = framing || s.camera?.in !== void 0 || s.camera?.during !== void 0 ? { ...framing ?? {}, ...s.camera?.in !== void 0 ? { in: s.camera.in } : {}, ...s.camera?.during !== void 0 ? { during: s.camera.during } : {} } : void 0;
4523
+ return {
4524
+ id,
4525
+ label: s.title ?? s.caption ?? `Shot ${i + 1}`,
4526
+ ...camera ? { camera } : {},
4527
+ run: [],
4528
+ hold: s.hold,
4529
+ ...layers.length ? { layers } : {},
4530
+ ...i > 0 && s.transition ? { transition: { ...s.transition, ...provider } } : {}
4531
+ };
4532
+ });
4533
+ return { shots, notes };
4534
+ }
4535
+ function motionSceneFromSequence(sequence, options = {}) {
4536
+ const { shots, notes } = motionShotsFromSequence(sequence, options);
4537
+ return {
4538
+ scene: { version: 1, name: sequence.name, ...sequence.title ? { description: sequence.title } : {}, artwork: { width: sequence.stage.width, height: sequence.stage.height, background: options.background ?? "#000000", nodes: [] }, shots },
4539
+ notes
4540
+ };
4541
+ }
4542
+
4487
4543
  // src/animation-editor/effects.ts
4488
4544
  var sourceOf = (c) => c.source;
4489
4545
  function motionSceneEffects(scene) {
@@ -4667,6 +4723,7 @@ var AnimationEditorController = class {
4667
4723
  redoLabel: h.redoName,
4668
4724
  revision: this.revision,
4669
4725
  effectsProvider: this.effects.provider,
4726
+ layerPictures: this.layers.revision,
4670
4727
  recording: this.recording ? {
4671
4728
  shot: this.recording.options.id,
4672
4729
  at: this.recording.options.at,
@@ -5175,6 +5232,42 @@ var AnimationEditorController = class {
5175
5232
  if (!r.ok) return r;
5176
5233
  return this.layerResult(shot, void 0);
5177
5234
  }
5235
+ /**
5236
+ * Fills a provider sequence template and loads it: `replace` (default) makes a new scene the
5237
+ * size of the template's stage from its shots; `append` adds its shots after the current ones,
5238
+ * scaled to the artwork. Values are checked first and every problem is refused at once. One
5239
+ * undo step. Returns the new shot and layer ids, slots left open and notes.
5240
+ */
5241
+ async fillTemplate(template, values = {}, options = {}) {
5242
+ const reason = this.readOnlyReason();
5243
+ if (reason) return this.refuse(reason);
5244
+ const mode = options.mode ?? "replace";
5245
+ let filled;
5246
+ try {
5247
+ filled = await fillEffectTemplate(this.effects.provider, template, values, options.name ? { name: options.name } : {});
5248
+ } catch (error) {
5249
+ if (isEffectError(error) || error instanceof Error) return this.refuse(error.message);
5250
+ throw error;
5251
+ }
5252
+ const provider = this.effects.provider.id;
5253
+ const label = `Template ${filled.template.name}`;
5254
+ let shots;
5255
+ let notes;
5256
+ let r;
5257
+ if (mode === "replace") {
5258
+ const made = motionSceneFromSequence(filled.sequence, { provider });
5259
+ shots = made.scene.shots;
5260
+ notes = made.notes;
5261
+ r = this.apply({ op: "replace_scene", scene: made.scene }, label);
5262
+ } else {
5263
+ const made = motionShotsFromSequence(filled.sequence, { provider, width: this.scene.artwork.width, height: this.scene.artwork.height, shotIds: this.scene.shots.map((s) => s.id), layerIds: this.scene.shots.flatMap((s) => (s.layers ?? []).map((l) => l.id)) });
5264
+ shots = made.shots;
5265
+ notes = made.notes;
5266
+ r = this.apply({ op: "insert_shots", shots: made.shots }, label);
5267
+ }
5268
+ if (!r.ok) return r;
5269
+ return { ok: true, template, mode, shots: shots.map((s) => s.id), layers: shots.flatMap((s) => (s.layers ?? []).map((l) => l.id)), openSlots: filled.openSlots, notes: [...filled.notes, ...notes] };
5270
+ }
5178
5271
  // ---------------------------------------------------------------------------------------
5179
5272
  // Recording
5180
5273
  // ---------------------------------------------------------------------------------------
@@ -7087,6 +7180,20 @@ function createAnimationEffectsToolProvider(controller, options = {}) {
7087
7180
  extraTools: (ctx) => [
7088
7181
  ...animationCameraMoveTools(controller, ctx),
7089
7182
  ...animationShotLayerTools(controller, ctx),
7183
+ ...effectTemplateTools(
7184
+ {
7185
+ provider: () => controller.effectsProvider,
7186
+ fillDetails: "mode replace (default) makes a new scene from the template's shots, the size of its stage; mode append adds its shots after the current ones, scaled to the artwork. Each shot keeps its framing and camera moves, its layers and its transition; its title and caption become overlay word layers. Returns { template, mode, shots (new shot ids), layers (new layer ids), openSlots, notes }. Check the result with render_animation_frame.",
7187
+ fillOptions: { mode: { type: "string", enum: ["replace", "append"], description: "replace (default): a new scene from the template; append: its shots after the current ones." } },
7188
+ fill: async (template, values, options2) => {
7189
+ const r = await controller.fillTemplate(template, values, { name: options2.name, mode: options2.mode });
7190
+ if (!r.ok) throw new Error(r.error);
7191
+ const { ok: _ok, ...rest } = r;
7192
+ return rest;
7193
+ }
7194
+ },
7195
+ ctx
7196
+ ),
7090
7197
  {
7091
7198
  name: "add_vector_effect",
7092
7199
  title: "Add a vector effect",
@@ -7296,6 +7403,7 @@ export {
7296
7403
  motionRevealPadding,
7297
7404
  motionRulerTicks,
7298
7405
  motionSceneEffects,
7406
+ motionSceneFromSequence,
7299
7407
  motionSceneHasLayers,
7300
7408
  motionSceneShapeProblems,
7301
7409
  motionSceneToJson,
@@ -7304,6 +7412,7 @@ export {
7304
7412
  motionShotCueTime,
7305
7413
  motionShotLayersInfo,
7306
7414
  motionShotTimeScale,
7415
+ motionShotsFromSequence,
7307
7416
  motionStageSvg,
7308
7417
  motionTakeProblems,
7309
7418
  motionTakeShot,
@@ -144,6 +144,8 @@ export declare class MotionLayersEngine implements MotionLayerPictures {
144
144
  /** Forgets every picture and failure (a new provider, or the host changed). */
145
145
  reset(): void;
146
146
  dispose(): void;
147
+ /** Goes up each time pictures come in or are cleared, so a view that caches frames knows to draw again. */
148
+ revision: number;
147
149
  private notify;
148
150
  private size;
149
151
  private snap;
@@ -144,6 +144,8 @@ export declare class MotionLayersEngine implements MotionLayerPictures {
144
144
  /** Forgets every picture and failure (a new provider, or the host changed). */
145
145
  reset(): void;
146
146
  dispose(): void;
147
+ /** Goes up each time pictures come in or are cleared, so a view that caches frames knows to draw again. */
148
+ revision: number;
147
149
  private notify;
148
150
  private size;
149
151
  private snap;
@@ -0,0 +1,33 @@
1
+ /**
2
+ * An effects provider's `EffectSequence` (what a sequence template fills to) as animation shots:
3
+ * each shot keeps its framing and camera moves, its layers and its transition. Its title and
4
+ * caption become overlay word layers placed in the shot's framing. Rects and framings are scaled
5
+ * from the sequence's stage to the artwork.
6
+ */
7
+ import type { EffectSequence } from '../effects/types.cjs';
8
+ import type { MotionScene, MotionShot } from './types.cjs';
9
+ export interface MotionShotsFromSequence {
10
+ shots: MotionShot[];
11
+ /** What could not be carried over, in sentences. */
12
+ notes: string[];
13
+ }
14
+ export interface MotionSequenceOptions {
15
+ /** The artwork size the shots are for (default the sequence's stage). */
16
+ width?: number;
17
+ height?: number;
18
+ /** Shot ids already used (new ones avoid them). */
19
+ shotIds?: Iterable<string>;
20
+ /** Layer ids already used (new ones avoid them). */
21
+ layerIds?: Iterable<string>;
22
+ /** The provider the sequence's effects come from, saved on layers and transitions. */
23
+ provider?: string;
24
+ }
25
+ /** The shots of a sequence, sized for the artwork (see the module comment). */
26
+ export declare function motionShotsFromSequence(sequence: EffectSequence, options?: MotionSequenceOptions): MotionShotsFromSequence;
27
+ /** A new scene from a sequence: an empty artwork the size of its stage, and its shots. */
28
+ export declare function motionSceneFromSequence(sequence: EffectSequence, options?: Pick<MotionSequenceOptions, 'provider'> & {
29
+ background?: string;
30
+ }): {
31
+ scene: MotionScene;
32
+ notes: string[];
33
+ };
@@ -0,0 +1,33 @@
1
+ /**
2
+ * An effects provider's `EffectSequence` (what a sequence template fills to) as animation shots:
3
+ * each shot keeps its framing and camera moves, its layers and its transition. Its title and
4
+ * caption become overlay word layers placed in the shot's framing. Rects and framings are scaled
5
+ * from the sequence's stage to the artwork.
6
+ */
7
+ import type { EffectSequence } from '../effects/types.js';
8
+ import type { MotionScene, MotionShot } from './types.js';
9
+ export interface MotionShotsFromSequence {
10
+ shots: MotionShot[];
11
+ /** What could not be carried over, in sentences. */
12
+ notes: string[];
13
+ }
14
+ export interface MotionSequenceOptions {
15
+ /** The artwork size the shots are for (default the sequence's stage). */
16
+ width?: number;
17
+ height?: number;
18
+ /** Shot ids already used (new ones avoid them). */
19
+ shotIds?: Iterable<string>;
20
+ /** Layer ids already used (new ones avoid them). */
21
+ layerIds?: Iterable<string>;
22
+ /** The provider the sequence's effects come from, saved on layers and transitions. */
23
+ provider?: string;
24
+ }
25
+ /** The shots of a sequence, sized for the artwork (see the module comment). */
26
+ export declare function motionShotsFromSequence(sequence: EffectSequence, options?: MotionSequenceOptions): MotionShotsFromSequence;
27
+ /** A new scene from a sequence: an empty artwork the size of its stage, and its shots. */
28
+ export declare function motionSceneFromSequence(sequence: EffectSequence, options?: Pick<MotionSequenceOptions, 'provider'> & {
29
+ background?: string;
30
+ }): {
31
+ scene: MotionScene;
32
+ notes: string[];
33
+ };
@@ -17,21 +17,267 @@ import {
17
17
  plainTextToSlice
18
18
  } from "./chunk-2INPJDNY.js";
19
19
  import {
20
+ CommentStore,
20
21
  TRACK_CHANGES_SKIP_META,
22
+ createReviewId,
21
23
  isTrackChangesEnabled,
22
24
  safeMergeAttributes
23
25
  } from "./chunk-6IN474P4.js";
24
26
 
27
+ // src/extensions/comments.ts
28
+ import { Mark } from "@tiptap/core";
29
+ import { Plugin, PluginKey, TextSelection } from "@tiptap/pm/state";
30
+ import { Decoration, DecorationSet } from "@tiptap/pm/view";
31
+ var commentsPluginKey = new PluginKey("comments");
32
+ var COMMENT_MARK_NAME = "comment";
33
+ function findCommentRanges(doc) {
34
+ const result = /* @__PURE__ */ new Map();
35
+ doc.descendants((node, pos) => {
36
+ if (!node.isInline) return;
37
+ node.marks.forEach((mark) => {
38
+ if (mark.type.name !== COMMENT_MARK_NAME) return;
39
+ const id = mark.attrs.commentId;
40
+ if (!id) return;
41
+ const ranges = result.get(id) ?? [];
42
+ const last = ranges[ranges.length - 1];
43
+ const end = pos + node.nodeSize;
44
+ if (last && last.to === pos) {
45
+ last.to = end;
46
+ } else {
47
+ ranges.push({ from: pos, to: end });
48
+ }
49
+ result.set(id, ranges);
50
+ });
51
+ });
52
+ return result;
53
+ }
54
+ function getCommentAnchors(doc) {
55
+ const anchors = /* @__PURE__ */ new Map();
56
+ findCommentRanges(doc).forEach((ranges, id) => {
57
+ const from = ranges[0].from;
58
+ const to = ranges[ranges.length - 1].to;
59
+ anchors.set(id, {
60
+ from,
61
+ to,
62
+ quote: ranges.map((r) => doc.textBetween(r.from, r.to, " ", " ")).join(" ")
63
+ });
64
+ });
65
+ return anchors;
66
+ }
67
+ function getCommentIdsAt(state, pos = state.selection.from) {
68
+ const $pos = state.doc.resolve(pos);
69
+ const marks = [
70
+ ...$pos.nodeAfter?.marks ?? [],
71
+ ...$pos.nodeBefore?.marks ?? []
72
+ ];
73
+ const ids = [];
74
+ marks.forEach((m) => {
75
+ if (m.type.name === COMMENT_MARK_NAME && m.attrs.commentId && !ids.includes(m.attrs.commentId)) {
76
+ ids.push(m.attrs.commentId);
77
+ }
78
+ });
79
+ return ids;
80
+ }
81
+ function getCommentStore(editor) {
82
+ return editor?.storage?.[COMMENT_MARK_NAME]?.store ?? null;
83
+ }
84
+ function resolveAuthor(author) {
85
+ return typeof author === "function" ? author() : author;
86
+ }
87
+ var Comments = Mark.create({
88
+ name: COMMENT_MARK_NAME,
89
+ // Typing at the edge of a comment does not extend it.
90
+ inclusive: false,
91
+ // Allow several comment marks (different threads) on the same text.
92
+ excludes: "",
93
+ addOptions() {
94
+ return {
95
+ store: null,
96
+ author: { id: "anonymous", name: "Anonymous" },
97
+ HTMLAttributes: {},
98
+ commentClass: "pixerate-comment bg-amber-100 border-b-2 border-amber-400 dark:bg-amber-500/20 cursor-pointer",
99
+ activeClass: "pixerate-comment-active bg-amber-200 dark:bg-amber-500/40",
100
+ resolvedClass: "",
101
+ activateOnSelection: true
102
+ };
103
+ },
104
+ addStorage() {
105
+ return {
106
+ store: this.options.store ?? new CommentStore(),
107
+ // tiptap-markdown: comments are not part of the exported markdown.
108
+ markdown: { serialize: { open: "", close: "" }, parse: {} }
109
+ };
110
+ },
111
+ addAttributes() {
112
+ return {
113
+ commentId: {
114
+ default: null,
115
+ parseHTML: (el) => el.getAttribute("data-comment-id"),
116
+ renderHTML: (attrs) => attrs.commentId ? { "data-comment-id": attrs.commentId } : {}
117
+ }
118
+ };
119
+ },
120
+ parseHTML() {
121
+ return [{ tag: "span[data-comment-id]" }];
122
+ },
123
+ renderHTML({ HTMLAttributes }) {
124
+ return ["span", safeMergeAttributes(this.options.HTMLAttributes, HTMLAttributes), 0];
125
+ },
126
+ addCommands() {
127
+ const store = () => this.storage.store;
128
+ return {
129
+ addComment: (options = {}) => ({ state, tr, dispatch }) => {
130
+ const { from, to, empty } = state.selection;
131
+ if (empty) return false;
132
+ if (dispatch) {
133
+ const id = options.id ?? createReviewId("comment");
134
+ tr.addMark(from, to, this.type.create({ commentId: id }));
135
+ tr.setMeta(commentsPluginKey, "refresh");
136
+ store().createThread({
137
+ id,
138
+ body: options.body ?? "",
139
+ author: options.author ?? resolveAuthor(this.options.author),
140
+ anchor: { from, to, quote: state.doc.textBetween(from, to, " ", " ") }
141
+ });
142
+ store().setActiveThread(id);
143
+ }
144
+ return true;
145
+ },
146
+ resolveComment: (id, resolved = true) => ({ tr, dispatch }) => {
147
+ if (!store().getThread(id)) return false;
148
+ if (dispatch) {
149
+ store().resolveThread(id, resolved, resolveAuthor(this.options.author));
150
+ tr.setMeta(commentsPluginKey, "refresh");
151
+ }
152
+ return true;
153
+ },
154
+ deleteComment: (id) => ({ state, tr, dispatch }) => {
155
+ const ranges = findCommentRanges(state.doc).get(id) ?? [];
156
+ if (ranges.length === 0 && !store().getThread(id)) return false;
157
+ if (dispatch) {
158
+ ranges.forEach(({ from, to }) => {
159
+ state.doc.nodesBetween(from, to, (node, pos) => {
160
+ const mark = node.marks.find(
161
+ (m) => m.type === this.type && m.attrs.commentId === id
162
+ );
163
+ if (mark) {
164
+ tr.removeMark(Math.max(pos, from), Math.min(pos + node.nodeSize, to), mark);
165
+ }
166
+ });
167
+ });
168
+ tr.setMeta(commentsPluginKey, "refresh");
169
+ store().deleteThread(id);
170
+ }
171
+ return true;
172
+ },
173
+ setActiveComment: (id) => ({ tr, dispatch }) => {
174
+ if (id !== null && !store().getThread(id)) return false;
175
+ if (dispatch) {
176
+ store().setActiveThread(id);
177
+ tr.setMeta(commentsPluginKey, "refresh");
178
+ }
179
+ return true;
180
+ },
181
+ focusComment: (id) => ({ state, tr, dispatch }) => {
182
+ const ranges = findCommentRanges(state.doc).get(id);
183
+ if (!ranges || ranges.length === 0) return false;
184
+ if (dispatch) {
185
+ const from = ranges[0].from;
186
+ const to = ranges[ranges.length - 1].to;
187
+ tr.setSelection(TextSelection.create(tr.doc, from, to)).scrollIntoView();
188
+ store().setActiveThread(id);
189
+ tr.setMeta(commentsPluginKey, "refresh");
190
+ }
191
+ return true;
192
+ }
193
+ };
194
+ },
195
+ addProseMirrorPlugins() {
196
+ const store = this.storage.store;
197
+ const options = this.options;
198
+ let cache = null;
199
+ const buildDecorations2 = (doc) => {
200
+ const snapshot = store.getSnapshot();
201
+ if (cache && cache.doc === doc && cache.snapshot === snapshot) return cache.set;
202
+ const decorations = [];
203
+ findCommentRanges(doc).forEach((ranges, id) => {
204
+ const thread = store.getThread(id);
205
+ const resolved = thread?.resolved ?? false;
206
+ const active = snapshot.activeThreadId === id;
207
+ const cls = [
208
+ resolved ? options.resolvedClass : options.commentClass,
209
+ active ? options.activeClass : ""
210
+ ].filter(Boolean).join(" ");
211
+ if (!cls) return;
212
+ ranges.forEach(({ from, to }) => {
213
+ decorations.push(Decoration.inline(from, to, { class: cls }));
214
+ });
215
+ });
216
+ const set = DecorationSet.create(doc, decorations);
217
+ cache = { doc, snapshot, set };
218
+ return set;
219
+ };
220
+ return [
221
+ new Plugin({
222
+ key: commentsPluginKey,
223
+ props: {
224
+ decorations: (state) => buildDecorations2(state.doc)
225
+ },
226
+ view: (view) => {
227
+ let destroyed = false;
228
+ let scheduled = false;
229
+ const sync = () => store.syncAnchors(getCommentAnchors(view.state.doc));
230
+ sync();
231
+ const unsubscribe = store.subscribe(() => {
232
+ if (scheduled) return;
233
+ scheduled = true;
234
+ queueMicrotask(() => {
235
+ scheduled = false;
236
+ if (destroyed) return;
237
+ sync();
238
+ if (cache?.snapshot !== store.getSnapshot()) {
239
+ view.dispatch(
240
+ view.state.tr.setMeta(commentsPluginKey, "refresh").setMeta("addToHistory", false)
241
+ );
242
+ }
243
+ });
244
+ });
245
+ return {
246
+ update(view2, prevState) {
247
+ if (!prevState.doc.eq(view2.state.doc)) sync();
248
+ if (options.activateOnSelection && !prevState.selection.eq(view2.state.selection)) {
249
+ const ids = getCommentIdsAt(view2.state);
250
+ const active = store.getSnapshot().activeThreadId;
251
+ if (!active || !ids.includes(active)) {
252
+ store.setActiveThread(ids[0] ?? null);
253
+ }
254
+ }
255
+ },
256
+ destroy() {
257
+ destroyed = true;
258
+ unsubscribe();
259
+ }
260
+ };
261
+ }
262
+ })
263
+ ];
264
+ }
265
+ });
266
+ function getCommentAuthor(editor) {
267
+ const ext = editor?.extensionManager?.extensions.find((e) => e.name === COMMENT_MARK_NAME);
268
+ return ext ? resolveAuthor(ext.options.author) : null;
269
+ }
270
+
25
271
  // src/extensions/table/nesting.ts
26
272
  import { Fragment, Slice } from "@tiptap/pm/model";
27
- import { Plugin, PluginKey, Selection } from "@tiptap/pm/state";
273
+ import { Plugin as Plugin2, PluginKey as PluginKey2, Selection } from "@tiptap/pm/state";
28
274
  import {
29
275
  CellSelection,
30
276
  __pastedCells,
31
277
  handlePaste as handleTablePaste
32
278
  } from "@tiptap/pm/tables";
33
279
  var ALLOW_NESTED_TABLES_META = "allowNestedTables";
34
- var tableNestingPluginKey = new PluginKey("tableNesting");
280
+ var tableNestingPluginKey = new PluginKey2("tableNesting");
35
281
  var roleOf = (node) => node.type.spec.tableRole;
36
282
  var isTableNode = (node) => roleOf(node) === "table";
37
283
  function outermostTableDepth($pos) {
@@ -171,7 +417,7 @@ var skip = (tr) => !tr.docChanged || tr.getMeta(ALLOW_NESTED_TABLES_META) === tr
171
417
  // (nested) table back so the deletion can be reviewed.
172
418
  !!tr.getMeta("appendedTransaction") || replacesDocument(tr);
173
419
  function createTableNestingPlugin() {
174
- return new Plugin({
420
+ return new Plugin2({
175
421
  key: tableNestingPluginKey,
176
422
  props: {
177
423
  handlePaste: (view, event, slice) => handleTablePasteWithoutNesting(view, event, slice)
@@ -1334,7 +1580,7 @@ function createChartNodeView(mount, renderStatic) {
1334
1580
 
1335
1581
  // src/extensions/chart/chart-node.ts
1336
1582
  import { Node } from "@tiptap/core";
1337
- import { Plugin as Plugin2, PluginKey as PluginKey2 } from "@tiptap/pm/state";
1583
+ import { Plugin as Plugin3, PluginKey as PluginKey3 } from "@tiptap/pm/state";
1338
1584
 
1339
1585
  // src/extensions/document-structure/utils.ts
1340
1586
  import { createDocument } from "@tiptap/core";
@@ -1419,7 +1665,7 @@ function syncInitialContent(editor, sync) {
1419
1665
  var STRUCTURE_PRIORITY = 45;
1420
1666
 
1421
1667
  // src/extensions/chart/chart-node.ts
1422
- var chartPluginKey = new PluginKey2("chartNode");
1668
+ var chartPluginKey = new PluginKey3("chartNode");
1423
1669
  function getDocumentCharts(doc, typeName = "chart") {
1424
1670
  const charts = [];
1425
1671
  doc.descendants((node, pos) => {
@@ -1614,7 +1860,7 @@ var Chart = Node.create({
1614
1860
  const { name } = this;
1615
1861
  const { generateId } = this.options;
1616
1862
  return [
1617
- new Plugin2({
1863
+ new Plugin3({
1618
1864
  key: chartPluginKey,
1619
1865
  appendTransaction: (transactions, _oldState, newState) => {
1620
1866
  if (!transactions.some((tr) => tr.docChanged)) return null;
@@ -2007,11 +2253,11 @@ function createTableStore(editor) {
2007
2253
  // src/extensions/agent-caret.ts
2008
2254
  import { Extension } from "@tiptap/core";
2009
2255
  import { closeHistory } from "@tiptap/pm/history";
2010
- import { Plugin as Plugin3, PluginKey as PluginKey3 } from "@tiptap/pm/state";
2011
- import { Decoration, DecorationSet } from "@tiptap/pm/view";
2256
+ import { Plugin as Plugin4, PluginKey as PluginKey4 } from "@tiptap/pm/state";
2257
+ import { Decoration as Decoration2, DecorationSet as DecorationSet2 } from "@tiptap/pm/view";
2012
2258
  var DEFAULT_AGENT_CARET_COLOR = "#8b5cf6";
2013
2259
  var DEFAULT_AGENT_CARET_NAME = "Agent";
2014
- var agentCaretPluginKey = new PluginKey3("agentCaret");
2260
+ var agentCaretPluginKey = new PluginKey4("agentCaret");
2015
2261
  var clamp = (pos, size) => Math.max(0, Math.min(size, Math.round(pos)));
2016
2262
  function caretWidget(caret) {
2017
2263
  return (view) => {
@@ -2036,7 +2282,7 @@ function buildDecorations(state, carets) {
2036
2282
  for (const caret of carets) {
2037
2283
  for (const range of caret.changed) {
2038
2284
  decorations.push(
2039
- Decoration.inline(range.from, range.to, {
2285
+ Decoration2.inline(range.from, range.to, {
2040
2286
  class: "pe-agent-changed",
2041
2287
  "data-agent-id": caret.id,
2042
2288
  style: `background-color:${tint(caret.color, 18)};`
@@ -2047,7 +2293,7 @@ function buildDecorations(state, carets) {
2047
2293
  const to = Math.max(caret.anchor, caret.head);
2048
2294
  if (from < to) {
2049
2295
  decorations.push(
2050
- Decoration.inline(from, to, {
2296
+ Decoration2.inline(from, to, {
2051
2297
  class: "pe-agent-selection",
2052
2298
  "data-agent-id": caret.id,
2053
2299
  style: `background-color:${tint(caret.color, 28)};`
@@ -2055,20 +2301,20 @@ function buildDecorations(state, carets) {
2055
2301
  );
2056
2302
  }
2057
2303
  decorations.push(
2058
- Decoration.widget(caret.head, caretWidget(caret), {
2304
+ Decoration2.widget(caret.head, caretWidget(caret), {
2059
2305
  key: `agent-caret:${caret.id}:${caret.name}:${caret.color}`,
2060
2306
  side: 10,
2061
2307
  ignoreSelection: true
2062
2308
  })
2063
2309
  );
2064
2310
  }
2065
- return DecorationSet.create(state.doc, decorations);
2311
+ return DecorationSet2.create(state.doc, decorations);
2066
2312
  }
2067
2313
  function createAgentCaretPlugin() {
2068
- return new Plugin3({
2314
+ return new Plugin4({
2069
2315
  key: agentCaretPluginKey,
2070
2316
  state: {
2071
- init: (_, state) => ({ carets: [], spans: {}, decorations: DecorationSet.create(state.doc, []) }),
2317
+ init: (_, state) => ({ carets: [], spans: {}, decorations: DecorationSet2.create(state.doc, []) }),
2072
2318
  apply(tr, value, _old, state) {
2073
2319
  const meta = tr.getMeta(agentCaretPluginKey);
2074
2320
  if (!tr.docChanged && !meta) return value;
@@ -2217,6 +2463,14 @@ async function typeAgentText(editor, options) {
2217
2463
  }
2218
2464
 
2219
2465
  export {
2466
+ commentsPluginKey,
2467
+ COMMENT_MARK_NAME,
2468
+ findCommentRanges,
2469
+ getCommentAnchors,
2470
+ getCommentIdsAt,
2471
+ getCommentStore,
2472
+ Comments,
2473
+ getCommentAuthor,
2220
2474
  ALLOW_NESTED_TABLES_META,
2221
2475
  tableNestingPluginKey,
2222
2476
  outermostTableDepth,