@pixerate/editor 0.59.0 → 0.61.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 (39) hide show
  1. package/THIRD_PARTY_NOTICES.md +2 -0
  2. package/dist/agent/index.cjs +111 -38
  3. package/dist/agent/index.cjs.map +1 -1
  4. package/dist/agent/index.d.cts +30 -2
  5. package/dist/agent/index.d.ts +30 -2
  6. package/dist/agent/index.js +96 -23
  7. package/dist/agent/index.js.map +1 -1
  8. package/dist/agent-caret-BmYhQF7L.d.cts +106 -0
  9. package/dist/agent-caret-BmYhQF7L.d.ts +106 -0
  10. package/dist/animation-editor/index.cjs +197 -82
  11. package/dist/animation-editor/index.cjs.map +1 -1
  12. package/dist/animation-editor/index.d.cts +136 -3
  13. package/dist/animation-editor/index.d.ts +136 -3
  14. package/dist/animation-editor/index.js +163 -48
  15. package/dist/animation-editor/index.js.map +1 -1
  16. package/dist/{chunk-LMUDHBWR.js → chunk-4YFMSPBU.js} +2 -2
  17. package/dist/{chunk-3I6V7PI4.cjs → chunk-7ZSU4MQZ.cjs} +45 -45
  18. package/dist/{chunk-3I6V7PI4.cjs.map → chunk-7ZSU4MQZ.cjs.map} +1 -1
  19. package/dist/{chunk-WLVZ235X.js → chunk-OK7T2LHK.js} +229 -2
  20. package/dist/chunk-OK7T2LHK.js.map +1 -0
  21. package/dist/{chunk-AHCENCU4.cjs → chunk-T4XWVPJK.cjs} +253 -26
  22. package/dist/chunk-T4XWVPJK.cjs.map +1 -0
  23. package/dist/extensions/index.cjs +27 -3
  24. package/dist/extensions/index.cjs.map +1 -1
  25. package/dist/extensions/index.d.cts +2 -1
  26. package/dist/extensions/index.d.ts +2 -1
  27. package/dist/extensions/index.js +26 -2
  28. package/dist/{index-CTCc3m3C.d.ts → index-B16wbOn_.d.ts} +1 -0
  29. package/dist/{index-BcHyG0Wq.d.cts → index-BAt14aIU.d.cts} +1 -0
  30. package/dist/index.cjs +32 -8
  31. package/dist/index.cjs.map +1 -1
  32. package/dist/index.d.cts +3 -2
  33. package/dist/index.d.ts +3 -2
  34. package/dist/index.js +26 -2
  35. package/dist/index.js.map +1 -1
  36. package/package.json +1 -1
  37. package/dist/chunk-AHCENCU4.cjs.map +0 -1
  38. package/dist/chunk-WLVZ235X.js.map +0 -1
  39. /package/dist/{chunk-LMUDHBWR.js.map → chunk-4YFMSPBU.js.map} +0 -0
@@ -51,19 +51,26 @@ import {
51
51
  validateJsonSchema
52
52
  } from "../chunk-4FX5ACVG.js";
53
53
  import {
54
+ DEFAULT_AGENT_CARET_COLOR,
55
+ DEFAULT_AGENT_CARET_NAME,
54
56
  MAX_SPARKLINE_VALUES,
55
57
  SPARKLINE_KINDS,
56
58
  TABLE_ACTIONS,
57
59
  applyReplacements,
60
+ clearAgentCaret,
58
61
  getDocumentCharts,
59
62
  getTableActionState,
60
63
  getTableState,
61
64
  isTableEnabled,
65
+ markAgentChanges,
62
66
  normalizeSparklineValues,
67
+ replaceWithTextTransaction,
63
68
  runTableAction,
64
69
  searchDocument,
65
- sparklineLabel
66
- } from "../chunk-WLVZ235X.js";
70
+ setAgentCaret,
71
+ sparklineLabel,
72
+ typeAgentText
73
+ } from "../chunk-OK7T2LHK.js";
67
74
  import {
68
75
  describeChart
69
76
  } from "../chunk-ZOH6X3VR.js";
@@ -74,8 +81,7 @@ import {
74
81
  } from "../chunk-633QC34G.js";
75
82
  import {
76
83
  getEditorMarkdown,
77
- getEditorText,
78
- plainTextToSlice
84
+ getEditorText
79
85
  } from "../chunk-UKI64KUD.js";
80
86
  import "../chunk-O5RYH2PG.js";
81
87
  import "../chunk-SWE3NPOU.js";
@@ -611,11 +617,6 @@ function createDocumentChartTools(editor) {
611
617
 
612
618
  // src/agent/providers.ts
613
619
  var toEditor = (target) => "commands" in target ? target : target.editor;
614
- function replaceWithText(editor, from, to, text) {
615
- const { state, view } = editor;
616
- const tr = /[\r\n]/.test(text) ? state.tr.replace(from, to, plainTextToSlice(text, state.schema)) : text ? state.tr.insertText(text, from, to) : state.tr.delete(from, to);
617
- view.dispatch(tr.scrollIntoView());
618
- }
619
620
  function selectionInfo(editor) {
620
621
  const { from, to } = editor.state.selection;
621
622
  return { from, to, text: editor.state.doc.textBetween(from, to, "\n") };
@@ -634,6 +635,71 @@ function textBlocks(editor) {
634
635
  });
635
636
  return blocks;
636
637
  }
638
+ function createTextPresence(editor, providerId, option) {
639
+ const config = option === false ? null : option === true || option === void 0 ? {} : option;
640
+ const caret = {
641
+ id: config?.id ?? providerId,
642
+ name: config?.name ?? DEFAULT_AGENT_CARET_NAME,
643
+ color: config?.color ?? DEFAULT_AGENT_CARET_COLOR
644
+ };
645
+ const typing = !config?.typing ? null : config.typing === true ? {} : config.typing;
646
+ const idleMs = config?.idleMs ?? 12e3;
647
+ const changedMs = config?.changedMs ?? 1500;
648
+ let idleTimer;
649
+ let tintTimer;
650
+ const live = () => {
651
+ const ed = editor();
652
+ return config && ed && !ed.isDestroyed ? ed : null;
653
+ };
654
+ const touch = () => {
655
+ clearTimeout(idleTimer);
656
+ if (idleMs > 0) idleTimer = setTimeout(() => live() && clearAgentCaret(live(), caret.id), idleMs);
657
+ };
658
+ const tint = (ed, ranges) => {
659
+ clearTimeout(tintTimer);
660
+ markAgentChanges(ed, caret.id, ranges);
661
+ if (changedMs > 0 && ranges.length) tintTimer = setTimeout(() => live() && markAgentChanges(live(), caret.id, []), changedMs);
662
+ };
663
+ return {
664
+ /** Puts the caret at `head`, selecting from `anchor`. */
665
+ show(anchor, head = anchor) {
666
+ const ed = live();
667
+ if (!ed) return;
668
+ setAgentCaret(ed, { ...caret, from: anchor, to: head });
669
+ touch();
670
+ },
671
+ /** Shows the caret after ranges just changed by a tool, tinting them. */
672
+ changed(ranges) {
673
+ const ed = live();
674
+ if (!ed || !ranges.length) return;
675
+ const last = ranges[ranges.length - 1];
676
+ setAgentCaret(ed, { ...caret, from: last.to });
677
+ tint(ed, ranges);
678
+ touch();
679
+ },
680
+ /** Replaces `from..to` with literal text, typed out when typing is on. Returns the inserted range. */
681
+ async write(ed, from, to, text, signal) {
682
+ if (live() && typing) {
683
+ clearTimeout(tintTimer);
684
+ const range2 = await typeAgentText(ed, { ...typing, from, to, text, caret, signal });
685
+ if (changedMs > 0) tintTimer = setTimeout(() => live() && markAgentChanges(live(), caret.id, []), changedMs);
686
+ touch();
687
+ return range2;
688
+ }
689
+ const tr = replaceWithTextTransaction(ed.state, from, to, text);
690
+ const end = tr.mapping.map(to, 1);
691
+ const range = { from: Math.min(tr.mapping.map(from, -1), end), to: end };
692
+ ed.view.dispatch(tr.scrollIntoView());
693
+ if (range.from < range.to) this.changed([range]);
694
+ else this.show(range.to);
695
+ return range;
696
+ },
697
+ dispose() {
698
+ clearTimeout(idleTimer);
699
+ clearTimeout(tintTimer);
700
+ }
701
+ };
702
+ }
637
703
  var FIND_SCHEMA_PROPERTIES = {
638
704
  matchCase: { type: "boolean", description: "Case-sensitive match (default false)." },
639
705
  wholeWord: { type: "boolean", description: "Match whole words only (default false)." },
@@ -656,6 +722,7 @@ function findMatches(editor, query, args, replacement) {
656
722
  function createRichTextToolProvider(target, options) {
657
723
  const editor = () => toEditor(target);
658
724
  const charts = createDocumentChartTools(editor);
725
+ const presence = createTextPresence(editor, options.id, options.presence);
659
726
  const getText = {
660
727
  name: "get_text",
661
728
  title: "Get document text",
@@ -697,7 +764,7 @@ function createRichTextToolProvider(target, options) {
697
764
  const insertText = {
698
765
  name: "insert_text",
699
766
  title: "Insert text",
700
- description: "Inserts literal text (newlines start new paragraphs) at a document position, or at the cursor when `at` is omitted.",
767
+ description: "Inserts literal text (newlines start new paragraphs) at a document position, or at the cursor when `at` is omitted. Returns the inserted `range` {from, to}.",
701
768
  inputSchema: {
702
769
  type: "object",
703
770
  properties: {
@@ -714,15 +781,15 @@ function createRichTextToolProvider(target, options) {
714
781
  idempotentHint: false,
715
782
  openWorldHint: false
716
783
  },
717
- handler: ({ text, at }) => {
784
+ handler: async ({ text, at }, { signal }) => {
718
785
  const ed = editor();
719
786
  const size = ed.state.doc.content.size;
720
787
  if (at !== void 0 && at > size) {
721
788
  throw new Error(`Position ${at} is outside the document (size ${size}).`);
722
789
  }
723
790
  const { from, to } = ed.state.selection;
724
- replaceWithText(ed, at ?? from, at ?? to, text);
725
- return { inserted: text.length, selection: selectionInfo(ed) };
791
+ const range = await presence.write(ed, at ?? from, at ?? to, text, signal);
792
+ return { inserted: text.length, range, selection: selectionInfo(ed) };
726
793
  }
727
794
  };
728
795
  const findText = {
@@ -750,6 +817,7 @@ function createRichTextToolProvider(target, options) {
750
817
  const ed = editor();
751
818
  const { doc } = ed.state;
752
819
  const { matches, truncated } = findMatches(ed, query, flags);
820
+ if (matches.length) presence.show(matches[0].from, matches[0].to);
753
821
  return {
754
822
  total: matches.length,
755
823
  truncated: truncated || matches.length > maxResults,
@@ -803,10 +871,12 @@ function createRichTextToolProvider(target, options) {
803
871
  const tr = ed.state.tr;
804
872
  const ends = applyReplacements(tr, chosen);
805
873
  ed.view.dispatch(tr.scrollIntoView());
874
+ const ranges = chosen.map((m, i) => ({ from: tr.mapping.map(m.from, -1), to: ends[i] }));
875
+ presence.changed(ranges.filter((r) => r.from < r.to));
806
876
  return {
807
877
  replaced: chosen.length,
808
878
  total: matches.length,
809
- ranges: chosen.map((m, i) => ({ from: tr.mapping.map(m.from, -1), to: ends[i] })),
879
+ ranges,
810
880
  selection: selectionInfo(ed)
811
881
  };
812
882
  }
@@ -814,7 +884,7 @@ function createRichTextToolProvider(target, options) {
814
884
  const replaceRange = {
815
885
  name: "replace_range",
816
886
  title: "Replace a range",
817
- description: "Replaces the content between two document positions (from get_text `blocks` or find_text) with literal text. from === to inserts; an empty text deletes.",
887
+ description: "Replaces the content between two document positions (from get_text `blocks` or find_text) with literal text. from === to inserts; an empty text deletes. Returns the new text's `range` {from, to}.",
818
888
  inputSchema: {
819
889
  type: "object",
820
890
  properties: {
@@ -832,11 +902,11 @@ function createRichTextToolProvider(target, options) {
832
902
  idempotentHint: false,
833
903
  openWorldHint: false
834
904
  },
835
- handler: ({ from, to, text }) => {
905
+ handler: async ({ from, to, text }, { signal }) => {
836
906
  const ed = editor();
837
907
  checkRange(ed, from, to);
838
- replaceWithText(ed, from, to, text);
839
- return { replaced: { from, to }, selection: selectionInfo(ed), size: ed.state.doc.content.size };
908
+ const range = await presence.write(ed, from, to, text, signal);
909
+ return { replaced: { from, to }, range, selection: selectionInfo(ed), size: ed.state.doc.content.size };
840
910
  }
841
911
  };
842
912
  const setSelection = {
@@ -864,13 +934,15 @@ function createRichTextToolProvider(target, options) {
864
934
  checkRange(ed, from, to);
865
935
  const { doc } = ed.state;
866
936
  ed.view.dispatch(ed.state.tr.setSelection(TextSelection.between(doc.resolve(from), doc.resolve(to))));
867
- return { selection: selectionInfo(ed) };
937
+ const selection = selectionInfo(ed);
938
+ presence.show(selection.from, selection.to);
939
+ return { selection };
868
940
  }
869
941
  };
870
942
  const replaceSelection = {
871
943
  name: "replace_selection",
872
944
  title: "Replace selection",
873
- description: "Replaces the selected content with literal text (an empty string deletes the selection).",
945
+ description: "Replaces the selected content with literal text (an empty string deletes the selection). Returns the new text's `range` {from, to}.",
874
946
  inputSchema: {
875
947
  type: "object",
876
948
  properties: { text: { type: "string", description: "Replacement text." } },
@@ -884,11 +956,11 @@ function createRichTextToolProvider(target, options) {
884
956
  idempotentHint: false,
885
957
  openWorldHint: false
886
958
  },
887
- handler: ({ text }) => {
959
+ handler: async ({ text }, { signal }) => {
888
960
  const ed = editor();
889
961
  const { from, to } = ed.state.selection;
890
- replaceWithText(ed, from, to, text);
891
- return { replaced: { from, to }, selection: selectionInfo(ed) };
962
+ const range = await presence.write(ed, from, to, text, signal);
963
+ return { replaced: { from, to }, range, selection: selectionInfo(ed) };
892
964
  }
893
965
  };
894
966
  const editTable = {
@@ -956,6 +1028,7 @@ function createRichTextToolProvider(target, options) {
956
1028
  return () => {
957
1029
  ed.off("update", notify);
958
1030
  ed.off("destroy", notify);
1031
+ presence.dispose();
959
1032
  };
960
1033
  }
961
1034
  };