@pixerate/editor-react 0.14.0 → 0.15.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 (38) hide show
  1. package/README.md +2 -1
  2. package/dist/canvas/index.cjs +252 -119
  3. package/dist/canvas/index.cjs.map +1 -1
  4. package/dist/canvas/index.d.cts +55 -7
  5. package/dist/canvas/index.d.ts +55 -7
  6. package/dist/canvas/index.js +155 -19
  7. package/dist/canvas/index.js.map +1 -1
  8. package/dist/chunk-4ZC2WCUO.js +196 -0
  9. package/dist/chunk-4ZC2WCUO.js.map +1 -0
  10. package/dist/{chunk-TL27COKM.js → chunk-LPFZMZ3L.js} +45 -2
  11. package/dist/chunk-LPFZMZ3L.js.map +1 -0
  12. package/dist/{chunk-25S5EHH4.js → chunk-QVQYYHJ5.js} +4 -3
  13. package/dist/chunk-QVQYYHJ5.js.map +1 -0
  14. package/dist/commands/index.cjs +232 -0
  15. package/dist/commands/index.cjs.map +1 -0
  16. package/dist/commands/index.d.cts +69 -0
  17. package/dist/commands/index.d.ts +69 -0
  18. package/dist/commands/index.js +13 -0
  19. package/dist/commands/index.js.map +1 -0
  20. package/dist/image-editor/index.cjs +41 -0
  21. package/dist/image-editor/index.cjs.map +1 -1
  22. package/dist/image-editor/index.d.cts +5 -3
  23. package/dist/image-editor/index.d.ts +5 -3
  24. package/dist/image-editor/index.js +1 -1
  25. package/dist/index.cjs +535 -251
  26. package/dist/index.cjs.map +1 -1
  27. package/dist/index.d.cts +61 -22
  28. package/dist/index.d.ts +61 -22
  29. package/dist/index.js +131 -70
  30. package/dist/index.js.map +1 -1
  31. package/dist/spreadsheet/index.cjs +1 -1
  32. package/dist/spreadsheet/index.cjs.map +1 -1
  33. package/dist/spreadsheet/index.d.cts +7 -7
  34. package/dist/spreadsheet/index.d.ts +7 -7
  35. package/dist/spreadsheet/index.js +1 -1
  36. package/package.json +10 -2
  37. package/dist/chunk-25S5EHH4.js.map +0 -1
  38. package/dist/chunk-TL27COKM.js.map +0 -1
package/dist/index.js CHANGED
@@ -6,11 +6,17 @@ import {
6
6
  useFillHandle,
7
7
  useSpreadsheetClipboard,
8
8
  useSpreadsheetEditor
9
- } from "./chunk-25S5EHH4.js";
9
+ } from "./chunk-QVQYYHJ5.js";
10
10
  import {
11
11
  ImageEditor,
12
12
  useImageEditor
13
- } from "./chunk-TL27COKM.js";
13
+ } from "./chunk-LPFZMZ3L.js";
14
+ import {
15
+ CommandPalette,
16
+ useCommandPalette,
17
+ useCommandShortcuts,
18
+ useRegisterCommands
19
+ } from "./chunk-4ZC2WCUO.js";
14
20
 
15
21
  // src/hooks/usePromptEditor.ts
16
22
  import { useMemo, useEffect, useRef } from "react";
@@ -406,7 +412,7 @@ function useDismissGuard({
406
412
  }
407
413
 
408
414
  // src/hooks/useHistory.ts
409
- import { useSyncExternalStore, useRef as useRef4, useCallback as useCallback3 } from "react";
415
+ import { useSyncExternalStore, useRef as useRef4, useCallback as useCallback3, useMemo as useMemo2 } from "react";
410
416
  import {
411
417
  HistoryManager,
412
418
  createHistoryManager
@@ -428,6 +434,7 @@ function useHistory(managerOrOptions) {
428
434
  () => manager.getState(),
429
435
  () => manager.getState()
430
436
  );
437
+ const entries = useMemo2(() => manager.getEntries(), [manager, state]);
431
438
  const undo = useCallback3(() => manager.undo(), [manager]);
432
439
  const redo = useCallback3(() => manager.redo(), [manager]);
433
440
  const clear = useCallback3(() => manager.clear(), [manager]);
@@ -443,60 +450,105 @@ function useHistory(managerOrOptions) {
443
450
  (name, fn) => manager.batch(name, fn),
444
451
  [manager]
445
452
  );
453
+ const goTo = useCallback3((index) => manager.goTo(index), [manager]);
454
+ const mark = useCallback3(() => manager.mark(), [manager]);
455
+ const revertTo = useCallback3(
456
+ (m) => manager.revertTo(m),
457
+ [manager]
458
+ );
459
+ const beginGesture = useCallback3(
460
+ (key) => manager.beginGesture(key),
461
+ [manager]
462
+ );
463
+ const endGesture = useCallback3(() => manager.endGesture(), [manager]);
446
464
  return {
447
465
  ...state,
448
466
  manager,
467
+ entries,
449
468
  undo,
450
469
  redo,
451
470
  clear,
452
471
  execute,
453
472
  executeMerged,
454
- batch
473
+ batch,
474
+ goTo,
475
+ mark,
476
+ revertTo,
477
+ beginGesture,
478
+ endGesture
455
479
  };
456
480
  }
457
481
 
482
+ // src/hooks/useHistoryDirty.ts
483
+ import { useCallback as useCallback4, useEffect as useEffect3, useRef as useRef5, useState as useState3, useSyncExternalStore as useSyncExternalStore2 } from "react";
484
+ import {
485
+ DirtyTracker,
486
+ bindDirtyToHistory
487
+ } from "@pixerate/editor";
488
+ function useHistoryDirty(options) {
489
+ const getValueRef = useRef5(options.getValue);
490
+ getValueRef.current = options.getValue;
491
+ const [tracker] = useState3(
492
+ () => options.tracker ?? new DirtyTracker(options.getValue(), {
493
+ isEqual: options.isEqual,
494
+ normalize: options.normalize
495
+ })
496
+ );
497
+ const bindingRef = useRef5(null);
498
+ useEffect3(() => {
499
+ const binding = bindDirtyToHistory({
500
+ history: options.history,
501
+ getValue: () => getValueRef.current(),
502
+ tracker
503
+ });
504
+ bindingRef.current = binding;
505
+ return () => {
506
+ binding.destroy();
507
+ if (bindingRef.current === binding) bindingRef.current = null;
508
+ };
509
+ }, [options.history, tracker]);
510
+ const isDirty = useSyncExternalStore2(
511
+ useCallback4((onChange) => tracker.subscribe(onChange), [tracker]),
512
+ () => tracker.dirty,
513
+ () => tracker.dirty
514
+ );
515
+ const markClean = useCallback4(
516
+ () => tracker.markClean(getValueRef.current()),
517
+ [tracker]
518
+ );
519
+ const suppress = useCallback4(
520
+ (fn) => bindingRef.current ? bindingRef.current.suppress(fn) : tracker.suppress(fn),
521
+ [tracker]
522
+ );
523
+ const refresh = useCallback4(
524
+ () => tracker.update(getValueRef.current()),
525
+ [tracker]
526
+ );
527
+ return { isDirty, markClean, suppress, refresh, tracker };
528
+ }
529
+
458
530
  // src/hooks/useHistoryShortcuts.ts
459
- import { useEffect as useEffect3 } from "react";
531
+ import { useEffect as useEffect4 } from "react";
532
+ import { matchHistoryShortcut } from "@pixerate/editor/commands";
460
533
  function useHistoryShortcuts(manager, options = {}) {
461
534
  const {
462
535
  enabled = true,
463
536
  target,
464
537
  ignoreEditableElements = true
465
538
  } = options;
466
- useEffect3(() => {
539
+ useEffect4(() => {
467
540
  if (!enabled) return;
468
541
  const eventTarget = target ?? (typeof window !== "undefined" ? window : null);
469
542
  if (!eventTarget) return;
470
543
  const handleKeyDown = (event) => {
471
544
  const e = event;
472
- const isMac = typeof navigator !== "undefined" && /Mac|iPod|iPhone|iPad/.test(navigator.platform || navigator.userAgent);
473
- const modifier = isMac ? e.metaKey : e.ctrlKey;
474
- if (!modifier) return;
475
- if (ignoreEditableElements && typeof document !== "undefined") {
476
- const targetEl = e.target || document.activeElement;
477
- if (targetEl && targetEl.tagName) {
478
- const tagName = targetEl.tagName.toLowerCase();
479
- const isInput = tagName === "input" || tagName === "textarea";
480
- const isContentEditable = targetEl.isContentEditable || targetEl.getAttribute?.("contenteditable") === "true";
481
- if (isInput || isContentEditable) {
482
- return;
483
- }
484
- }
485
- }
486
- const key = e.key.toLowerCase();
487
- if (key === "z" && !e.shiftKey) {
488
- if (manager.getState().canUndo) {
489
- e.preventDefault();
490
- manager.undo();
491
- }
492
- return;
493
- }
494
- const isRedoKey = key === "z" && e.shiftKey || !isMac && key === "y" && !e.shiftKey;
495
- if (isRedoKey) {
496
- if (manager.getState().canRedo) {
497
- e.preventDefault();
498
- manager.redo();
499
- }
545
+ const action = matchHistoryShortcut(e, { allowInEditable: !ignoreEditableElements });
546
+ if (action === "undo" && manager.getState().canUndo) {
547
+ e.preventDefault();
548
+ manager.undo();
549
+ } else if (action === "redo" && manager.getState().canRedo) {
550
+ e.preventDefault();
551
+ manager.redo();
500
552
  }
501
553
  };
502
554
  eventTarget.addEventListener("keydown", handleKeyDown);
@@ -507,24 +559,24 @@ function useHistoryShortcuts(manager, options = {}) {
507
559
  }
508
560
 
509
561
  // src/hooks/useFileImport.ts
510
- import { useEffect as useEffect4, useMemo as useMemo2, useRef as useRef5, useSyncExternalStore as useSyncExternalStore2 } from "react";
562
+ import { useEffect as useEffect5, useMemo as useMemo3, useRef as useRef6, useSyncExternalStore as useSyncExternalStore3 } from "react";
511
563
  import {
512
564
  FileImportController
513
565
  } from "@pixerate/editor";
514
566
  function useFileImport(editor, options = {}) {
515
- const editorRef = useRef5(editor);
567
+ const editorRef = useRef6(editor);
516
568
  editorRef.current = editor;
517
- const controller = useMemo2(
569
+ const controller = useMemo3(
518
570
  () => new FileImportController(() => {
519
571
  const current = editorRef.current;
520
572
  return current && !current.isDestroyed ? current : null;
521
573
  }, options),
522
574
  []
523
575
  );
524
- useEffect4(() => {
576
+ useEffect5(() => {
525
577
  controller.setOptions(options);
526
578
  });
527
- const state = useSyncExternalStore2(controller.subscribe, controller.getState, controller.getState);
579
+ const state = useSyncExternalStore3(controller.subscribe, controller.getState, controller.getState);
528
580
  return {
529
581
  ...state,
530
582
  accept: controller.accept,
@@ -534,9 +586,9 @@ function useFileImport(editor, options = {}) {
534
586
  }
535
587
 
536
588
  // src/hooks/useAgentToolProvider.ts
537
- import { useEffect as useEffect5 } from "react";
589
+ import { useEffect as useEffect6 } from "react";
538
590
  function useAgentToolProvider(registry, provider) {
539
- useEffect5(() => {
591
+ useEffect6(() => {
540
592
  if (!registry || !provider) return;
541
593
  return registry.register(provider);
542
594
  }, [registry, provider]);
@@ -556,7 +608,7 @@ var EditorContent = ({
556
608
  };
557
609
 
558
610
  // src/components/BubbleMenu.tsx
559
- import { useEffect as useEffect6, useRef as useRef6, useState as useState3 } from "react";
611
+ import { useEffect as useEffect7, useRef as useRef7, useState as useState4 } from "react";
560
612
  import { createPortal } from "react-dom";
561
613
  import {
562
614
  BubbleMenuPlugin
@@ -570,12 +622,12 @@ var BubbleMenu = ({
570
622
  pluginKey = "bubbleMenu",
571
623
  updateDelay
572
624
  }) => {
573
- const menuEl = useRef6(null);
574
- const [mounted, setMounted] = useState3(false);
625
+ const menuEl = useRef7(null);
626
+ const [mounted, setMounted] = useState4(false);
575
627
  if (!menuEl.current && typeof document !== "undefined") {
576
628
  menuEl.current = document.createElement("div");
577
629
  }
578
- useEffect6(() => {
630
+ useEffect7(() => {
579
631
  if (!editor || !menuEl.current || editor.isDestroyed) {
580
632
  return;
581
633
  }
@@ -606,7 +658,7 @@ var BubbleMenu = ({
606
658
  };
607
659
 
608
660
  // src/components/TemplateRenderer.tsx
609
- import { useMemo as useMemo3 } from "react";
661
+ import { useMemo as useMemo4 } from "react";
610
662
  import {
611
663
  evaluatePromptTokens,
612
664
  resolveTemplates
@@ -624,11 +676,11 @@ var TemplateRenderer = ({
624
676
  onTemplateClick,
625
677
  onVariableClick
626
678
  }) => {
627
- const displayText = useMemo3(() => {
679
+ const displayText = useMemo4(() => {
628
680
  if (!resolve || templates.length === 0) return content;
629
681
  return resolveTemplates(content, templates, { bindings });
630
682
  }, [content, templates, resolve, bindings]);
631
- const tokens = useMemo3(() => {
683
+ const tokens = useMemo4(() => {
632
684
  return evaluatePromptTokens(displayText, values);
633
685
  }, [displayText, values]);
634
686
  return /* @__PURE__ */ jsx2("div", { className, children: tokens.map((token, index) => {
@@ -717,7 +769,7 @@ var TemplateRenderer = ({
717
769
  };
718
770
 
719
771
  // src/components/VariableForm.tsx
720
- import { useId, useMemo as useMemo4, useState as useState4 } from "react";
772
+ import { useId, useMemo as useMemo5, useState as useState5 } from "react";
721
773
  import {
722
774
  compactVariableValues,
723
775
  getVariableFormFields
@@ -733,11 +785,11 @@ var VariableForm = ({
733
785
  className = "flex flex-col gap-3 text-sm"
734
786
  }) => {
735
787
  const idPrefix = useId();
736
- const [internal, setInternal] = useState4(
788
+ const [internal, setInternal] = useState5(
737
789
  () => defaultValues ?? {}
738
790
  );
739
791
  const entered = values ?? internal;
740
- const fields = useMemo4(
792
+ const fields = useMemo5(
741
793
  () => getVariableFormFields(content, { templates, bindings }),
742
794
  [content, templates, bindings]
743
795
  );
@@ -805,11 +857,11 @@ var VariableForm = ({
805
857
  };
806
858
 
807
859
  // src/hooks/useOutline.ts
808
- import { useMemo as useMemo5, useSyncExternalStore as useSyncExternalStore3 } from "react";
860
+ import { useMemo as useMemo6, useSyncExternalStore as useSyncExternalStore4 } from "react";
809
861
  import { createOutlineStore } from "@pixerate/editor";
810
862
  function useOutline(editor) {
811
- const store = useMemo5(() => createOutlineStore(editor), [editor]);
812
- return useSyncExternalStore3(store.subscribe, store.getSnapshot, store.getSnapshot);
863
+ const store = useMemo6(() => createOutlineStore(editor), [editor]);
864
+ return useSyncExternalStore4(store.subscribe, store.getSnapshot, store.getSnapshot);
813
865
  }
814
866
 
815
867
  // src/components/OutlinePanel.tsx
@@ -855,15 +907,17 @@ var OutlinePanel = ({
855
907
 
856
908
  // src/index.ts
857
909
  import {
858
- DirtyTracker,
910
+ DirtyTracker as DirtyTracker2,
859
911
  createDirtyTracker,
860
912
  defaultIsEqual,
861
913
  HistoryManager as HistoryManager2,
862
- createHistoryManager as createHistoryManager2
914
+ createHistoryManager as createHistoryManager2,
915
+ bindDirtyToHistory as bindDirtyToHistory2,
916
+ withoutDirty
863
917
  } from "@pixerate/editor";
864
918
 
865
919
  // src/slots.tsx
866
- import { createContext, useContext, useMemo as useMemo6 } from "react";
920
+ import { createContext, useContext, useMemo as useMemo7 } from "react";
867
921
  import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
868
922
  var defaultSlots = {
869
923
  Button: (props) => /* @__PURE__ */ jsx5(
@@ -887,7 +941,7 @@ var defaultSlots = {
887
941
  };
888
942
  var EditorSlotsContext = createContext(defaultSlots);
889
943
  function EditorSlotsProvider({ slots, children }) {
890
- const mergedSlots = useMemo6(() => ({ ...defaultSlots, ...slots }), [slots]);
944
+ const mergedSlots = useMemo7(() => ({ ...defaultSlots, ...slots }), [slots]);
891
945
  return /* @__PURE__ */ jsx5(EditorSlotsContext.Provider, { value: mergedSlots, children });
892
946
  }
893
947
  function useEditorSlots() {
@@ -895,7 +949,7 @@ function useEditorSlots() {
895
949
  }
896
950
 
897
951
  // src/review/useReview.ts
898
- import { useCallback as useCallback4, useMemo as useMemo7, useSyncExternalStore as useSyncExternalStore4 } from "react";
952
+ import { useCallback as useCallback5, useMemo as useMemo8, useSyncExternalStore as useSyncExternalStore5 } from "react";
899
953
  import {
900
954
  getCommentStore,
901
955
  getTrackChangesStore
@@ -917,23 +971,23 @@ function isCommentStore(value) {
917
971
  }
918
972
  function useComments(source) {
919
973
  const store = isCommentStore(source) ? source : getCommentStore(source);
920
- const subscribe = useCallback4(
974
+ const subscribe = useCallback5(
921
975
  (onChange) => store ? store.subscribe(() => onChange()) : noopUnsubscribe,
922
976
  [store]
923
977
  );
924
978
  const getSnapshot = () => store?.getSnapshot() ?? EMPTY_COMMENTS;
925
- const snapshot = useSyncExternalStore4(subscribe, getSnapshot, getSnapshot);
926
- return useMemo7(() => ({ ...snapshot, store }), [snapshot, store]);
979
+ const snapshot = useSyncExternalStore5(subscribe, getSnapshot, getSnapshot);
980
+ return useMemo8(() => ({ ...snapshot, store }), [snapshot, store]);
927
981
  }
928
982
  function useTrackChanges(editor) {
929
983
  const store = getTrackChangesStore(editor ?? null);
930
- const subscribe = useCallback4(
984
+ const subscribe = useCallback5(
931
985
  (onChange) => store ? store.subscribe(() => onChange()) : noopUnsubscribe,
932
986
  [store]
933
987
  );
934
988
  const getSnapshot = () => store?.getSnapshot() ?? EMPTY_TRACK_CHANGES;
935
- const snapshot = useSyncExternalStore4(subscribe, getSnapshot, getSnapshot);
936
- return useMemo7(() => {
989
+ const snapshot = useSyncExternalStore5(subscribe, getSnapshot, getSnapshot);
990
+ return useMemo8(() => {
937
991
  const run = (fn) => () => {
938
992
  if (editor && !editor.isDestroyed) fn(editor);
939
993
  };
@@ -953,7 +1007,7 @@ function useTrackChanges(editor) {
953
1007
  }
954
1008
 
955
1009
  // src/review/CommentsPanel.tsx
956
- import { useState as useState5 } from "react";
1010
+ import { useState as useState6 } from "react";
957
1011
  import {
958
1012
  formatReviewTime,
959
1013
  getCommentAuthor
@@ -972,7 +1026,7 @@ var CommentsPanel = ({
972
1026
  emptyMessage = "No comments yet. Select text and add a comment."
973
1027
  }) => {
974
1028
  const { threads, activeThreadId, store } = useComments(storeProp ?? editor);
975
- const [showResolved, setShowResolved] = useState5(showResolvedInitial);
1029
+ const [showResolved, setShowResolved] = useState6(showResolvedInitial);
976
1030
  const author = authorProp ?? getCommentAuthor(editor) ?? { id: "anonymous", name: "Anonymous" };
977
1031
  const visible = threads.filter((t) => showResolved || !t.resolved);
978
1032
  const resolvedCount = threads.filter((t) => t.resolved).length;
@@ -1016,7 +1070,7 @@ var CommentThreadCard = ({
1016
1070
  author,
1017
1071
  formatTime
1018
1072
  }) => {
1019
- const [draft, setDraft] = useState5("");
1073
+ const [draft, setDraft] = useState6("");
1020
1074
  const isDraft = thread.body === "";
1021
1075
  const quote = thread.anchor?.quote ?? thread.lastQuote ?? "";
1022
1076
  const live = editor && !editor.isDestroyed ? editor : null;
@@ -1230,9 +1284,10 @@ var CommentButton = ({
1230
1284
  );
1231
1285
  export {
1232
1286
  BubbleMenu,
1287
+ CommandPalette,
1233
1288
  CommentButton,
1234
1289
  CommentsPanel,
1235
- DirtyTracker,
1290
+ DirtyTracker2 as DirtyTracker,
1236
1291
  EditorContent,
1237
1292
  EditorSlotsProvider,
1238
1293
  FormulaHints,
@@ -1245,10 +1300,13 @@ export {
1245
1300
  SpreadsheetGroupRow,
1246
1301
  TemplateRenderer,
1247
1302
  VariableForm,
1303
+ bindDirtyToHistory2 as bindDirtyToHistory,
1248
1304
  createDirtyTracker,
1249
1305
  createHistoryManager2 as createHistoryManager,
1250
1306
  defaultIsEqual,
1251
1307
  useAgentToolProvider,
1308
+ useCommandPalette,
1309
+ useCommandShortcuts,
1252
1310
  useComments,
1253
1311
  useDismissGuard,
1254
1312
  useEditor2 as useEditor,
@@ -1256,13 +1314,16 @@ export {
1256
1314
  useFileImport,
1257
1315
  useFillHandle,
1258
1316
  useHistory,
1317
+ useHistoryDirty,
1259
1318
  useHistoryShortcuts,
1260
1319
  useImageEditor,
1261
1320
  useNavigationGuard,
1262
1321
  useOutline,
1263
1322
  usePromptEditor,
1323
+ useRegisterCommands,
1264
1324
  useSpreadsheetClipboard,
1265
1325
  useSpreadsheetEditor,
1266
- useTrackChanges
1326
+ useTrackChanges,
1327
+ withoutDirty
1267
1328
  };
1268
1329
  //# sourceMappingURL=index.js.map