@pixerate/editor-react 0.3.13 → 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/dist/index.d.ts CHANGED
@@ -1,10 +1,10 @@
1
1
  import * as _tiptap_core from '@tiptap/core';
2
2
  import { Editor } from '@tiptap/core';
3
3
  import * as _pixerate_editor from '@pixerate/editor';
4
- import { Template, ColorGradient, RichTextPresetOptions, SpreadsheetControllerOptions, SpreadsheetDocument, CellCoordinate, CellRange, SpreadsheetController, SpreadsheetColumn, SpreadsheetRow, SpreadsheetDataSource, CellData } from '@pixerate/editor';
5
- export { ColorGradient, RichTextPresetOptions, Template, TemplateVersion, Token, TokenType } from '@pixerate/editor';
4
+ import { Template, ColorGradient, RichTextPresetOptions, HistoryState, HistoryManager, Command, HistoryManagerOptions, SpreadsheetControllerOptions, SpreadsheetDocument, CellCoordinate, CellRange, SpreadsheetController, SpreadsheetColumn, SpreadsheetRow, SpreadsheetDataSource, CellData } from '@pixerate/editor';
5
+ export { ColorGradient, Command, DirtyTracker, DirtyTrackerOptions, HistoryManager, HistoryManagerOptions, HistoryState, RichTextPresetOptions, Template, TemplateVersion, Token, TokenType, createDirtyTracker, createHistoryManager, defaultIsEqual } from '@pixerate/editor';
6
6
  import { UseEditorOptions, EditorContentProps as EditorContentProps$1 } from '@tiptap/react';
7
- import * as React from 'react';
7
+ import * as React$1 from 'react';
8
8
  import React__default from 'react';
9
9
  import { BubbleMenuPluginProps } from '@tiptap/extension-bubble-menu';
10
10
 
@@ -60,6 +60,99 @@ interface UseRichEditorProps extends UseEditorOptions {
60
60
  */
61
61
  declare function useEditor(options?: UseRichEditorProps): _tiptap_core.Editor | null;
62
62
 
63
+ interface UseNavigationGuardOptions {
64
+ /** Whether the current form or editor has unsaved changes */
65
+ isDirty: boolean;
66
+ /** Whether guarding is enabled (defaults to true) */
67
+ enabled?: boolean;
68
+ /** Custom navigation function (e.g. router.push from next/navigation or react-router) */
69
+ onNavigate?: (url: string) => void;
70
+ /** Optional callback fired when an internal navigation attempt is intercepted */
71
+ onBlocked?: (url: string) => void;
72
+ }
73
+ interface UseNavigationGuardReturn {
74
+ /** Whether the unsaved changes confirmation dialog should be displayed */
75
+ showConfirm: boolean;
76
+ /** Setter to manually control the dialog visibility */
77
+ setShowConfirm: (show: boolean) => void;
78
+ /** The target URL that the user attempted to navigate to */
79
+ pendingUrl: string | null;
80
+ /** Proceeds with the blocked navigation and closes the dialog */
81
+ confirmLeave: () => void;
82
+ /** Cancels the navigation attempt and keeps the user on the current page */
83
+ cancelLeave: () => void;
84
+ }
85
+ /**
86
+ * Hook to guard against navigation when there are unsaved changes.
87
+ * Intercepts both external unloads (tab closing/refreshing) and internal link clicks.
88
+ */
89
+ declare function useNavigationGuard({ isDirty, enabled, onNavigate, onBlocked, }: UseNavigationGuardOptions): UseNavigationGuardReturn;
90
+
91
+ interface UseDismissGuardOptions {
92
+ /** Whether there are unsaved changes */
93
+ isDirty: boolean;
94
+ /** Whether the dismissal guard is enabled (defaults to true) */
95
+ enabled?: boolean;
96
+ /** Callback fired when dismissal is confirmed or when clean dismissal occurs */
97
+ onDismiss?: () => void;
98
+ }
99
+ interface UseDismissGuardReturn {
100
+ /** Whether the discard confirmation modal should be shown */
101
+ showConfirm: boolean;
102
+ /** Manually update confirmation modal visibility */
103
+ setShowConfirm: (show: boolean) => void;
104
+ /** Request dismissal - checks isDirty and shows confirm or executes onDismiss */
105
+ requestDismiss: () => void;
106
+ /** Confirm discarding changes and dismiss */
107
+ confirmDismiss: () => void;
108
+ /** Cancel discarding and resume editing */
109
+ cancelDismiss: () => void;
110
+ /** Helper keydown handler intercepting Escape key */
111
+ handleKeyDown: (event: React.KeyboardEvent | KeyboardEvent) => boolean;
112
+ }
113
+ /**
114
+ * Hook to guard against closing or exiting an editor/dialog with uncommitted changes.
115
+ */
116
+ declare function useDismissGuard({ isDirty, enabled, onDismiss, }: UseDismissGuardOptions): UseDismissGuardReturn;
117
+
118
+ interface UseHistoryResult extends HistoryState {
119
+ manager: HistoryManager;
120
+ undo: () => boolean;
121
+ redo: () => boolean;
122
+ clear: () => void;
123
+ execute: (command: Command) => void;
124
+ executeMerged: (command: Command, options?: {
125
+ windowMs?: number;
126
+ }) => void;
127
+ batch: (name: string, fn: () => void) => void;
128
+ }
129
+ /**
130
+ * React hook that subscribes to a HistoryManager instance.
131
+ * Accepts an existing HistoryManager or config options to create an instance.
132
+ */
133
+ declare function useHistory(managerOrOptions?: HistoryManager | HistoryManagerOptions): UseHistoryResult;
134
+
135
+ interface HistoryShortcutsOptions {
136
+ /**
137
+ * Whether the keyboard shortcuts are enabled. Defaults to true.
138
+ */
139
+ enabled?: boolean;
140
+ /**
141
+ * Target element or window to listen on. Defaults to window.
142
+ */
143
+ target?: Window | HTMLElement | null;
144
+ /**
145
+ * When true (default), shortcuts will not trigger if an <input>, <textarea>,
146
+ * or [contenteditable] element is currently active / focused.
147
+ */
148
+ ignoreEditableElements?: boolean;
149
+ }
150
+ /**
151
+ * Attaches keyboard listeners for Undo (Mod+Z) and Redo (Mod+Shift+Z / Mod+Y).
152
+ * Automatically guards against active text inputs and contenteditable editors.
153
+ */
154
+ declare function useHistoryShortcuts(manager: HistoryManager, options?: HistoryShortcutsOptions): void;
155
+
63
156
  interface EditorContentProps extends EditorContentProps$1 {
64
157
  className?: string;
65
158
  }
@@ -100,7 +193,7 @@ declare function useSpreadsheetEditor(options?: SpreadsheetControllerOptions): {
100
193
  selectedRange: CellRange | null;
101
194
  editingCell: CellCoordinate | null;
102
195
  draftValue: string;
103
- setDraftValue: React.Dispatch<React.SetStateAction<string>>;
196
+ setDraftValue: React$1.Dispatch<React$1.SetStateAction<string>>;
104
197
  controller: SpreadsheetController;
105
198
  getCell: (rowId: string, colId: string) => _pixerate_editor.CellData;
106
199
  setCellValue: (rowId: string, colId: string, raw: string) => void;
@@ -141,4 +234,4 @@ interface SpreadsheetEditorProps {
141
234
  }
142
235
  declare const SpreadsheetEditor: React__default.FC<SpreadsheetEditorProps>;
143
236
 
144
- export { BubbleMenu, type BubbleMenuProps, EditorContent, type EditorContentProps, SpreadsheetEditor, type SpreadsheetEditorProps, TemplateRenderer, type TemplateRendererProps, type UsePromptEditorProps, type UseRichEditorProps, useEditor, usePromptEditor, useSpreadsheetEditor };
237
+ export { BubbleMenu, type BubbleMenuProps, EditorContent, type EditorContentProps, type HistoryShortcutsOptions, SpreadsheetEditor, type SpreadsheetEditorProps, TemplateRenderer, type TemplateRendererProps, type UseDismissGuardOptions, type UseDismissGuardReturn, type UseHistoryResult, type UseNavigationGuardOptions, type UseNavigationGuardReturn, type UsePromptEditorProps, type UseRichEditorProps, useDismissGuard, useEditor, useHistory, useHistoryShortcuts, useNavigationGuard, usePromptEditor, useSpreadsheetEditor };
package/dist/index.js CHANGED
@@ -227,6 +227,226 @@ function useEditor2(options = {}) {
227
227
  });
228
228
  }
229
229
 
230
+ // src/hooks/useNavigationGuard.ts
231
+ import { useState, useEffect as useEffect2, useCallback, useRef as useRef2 } from "react";
232
+ function useNavigationGuard({
233
+ isDirty,
234
+ enabled = true,
235
+ onNavigate,
236
+ onBlocked
237
+ }) {
238
+ const [showConfirm, setShowConfirm] = useState(false);
239
+ const [pendingUrl, setPendingUrl] = useState(null);
240
+ const onNavigateRef = useRef2(onNavigate);
241
+ onNavigateRef.current = onNavigate;
242
+ const onBlockedRef = useRef2(onBlocked);
243
+ onBlockedRef.current = onBlocked;
244
+ useEffect2(() => {
245
+ if (typeof window === "undefined") return;
246
+ if (!enabled || !isDirty) return;
247
+ const handleBeforeUnload = (e) => {
248
+ e.preventDefault();
249
+ e.returnValue = "";
250
+ };
251
+ window.addEventListener("beforeunload", handleBeforeUnload);
252
+ return () => {
253
+ window.removeEventListener("beforeunload", handleBeforeUnload);
254
+ };
255
+ }, [enabled, isDirty]);
256
+ useEffect2(() => {
257
+ if (typeof document === "undefined" || typeof window === "undefined")
258
+ return;
259
+ if (!enabled || !isDirty) return;
260
+ const handleClick = (e) => {
261
+ const target = e.target;
262
+ const anchor = target?.closest?.("a");
263
+ if (!anchor) return;
264
+ if (anchor.target === "_blank") return;
265
+ const isInternal = anchor.host === window.location.host;
266
+ if (!isInternal) return;
267
+ if (anchor.pathname === window.location.pathname && anchor.search === window.location.search) {
268
+ return;
269
+ }
270
+ e.preventDefault();
271
+ e.stopPropagation();
272
+ const href = anchor.href;
273
+ setPendingUrl(href);
274
+ setShowConfirm(true);
275
+ onBlockedRef.current?.(href);
276
+ };
277
+ document.addEventListener("click", handleClick, { capture: true });
278
+ return () => {
279
+ document.removeEventListener("click", handleClick, { capture: true });
280
+ };
281
+ }, [enabled, isDirty]);
282
+ const confirmLeave = useCallback(() => {
283
+ setShowConfirm(false);
284
+ if (pendingUrl) {
285
+ if (onNavigateRef.current) {
286
+ onNavigateRef.current(pendingUrl);
287
+ } else if (typeof window !== "undefined") {
288
+ window.location.href = pendingUrl;
289
+ }
290
+ }
291
+ }, [pendingUrl]);
292
+ const cancelLeave = useCallback(() => {
293
+ setShowConfirm(false);
294
+ setPendingUrl(null);
295
+ }, []);
296
+ return {
297
+ showConfirm,
298
+ setShowConfirm,
299
+ pendingUrl,
300
+ confirmLeave,
301
+ cancelLeave
302
+ };
303
+ }
304
+
305
+ // src/hooks/useDismissGuard.ts
306
+ import { useState as useState2, useCallback as useCallback2, useRef as useRef3 } from "react";
307
+ function useDismissGuard({
308
+ isDirty,
309
+ enabled = true,
310
+ onDismiss
311
+ }) {
312
+ const [showConfirm, setShowConfirm] = useState2(false);
313
+ const onDismissRef = useRef3(onDismiss);
314
+ onDismissRef.current = onDismiss;
315
+ const requestDismiss = useCallback2(() => {
316
+ if (enabled && isDirty) {
317
+ setShowConfirm(true);
318
+ } else {
319
+ onDismissRef.current?.();
320
+ }
321
+ }, [enabled, isDirty]);
322
+ const confirmDismiss = useCallback2(() => {
323
+ setShowConfirm(false);
324
+ onDismissRef.current?.();
325
+ }, []);
326
+ const cancelDismiss = useCallback2(() => {
327
+ setShowConfirm(false);
328
+ }, []);
329
+ const handleKeyDown = useCallback2(
330
+ (event) => {
331
+ if (event.key === "Escape") {
332
+ if (event.defaultPrevented) return false;
333
+ event.preventDefault();
334
+ requestDismiss();
335
+ return true;
336
+ }
337
+ return false;
338
+ },
339
+ [requestDismiss]
340
+ );
341
+ return {
342
+ showConfirm,
343
+ setShowConfirm,
344
+ requestDismiss,
345
+ confirmDismiss,
346
+ cancelDismiss,
347
+ handleKeyDown
348
+ };
349
+ }
350
+
351
+ // src/hooks/useHistory.ts
352
+ import { useSyncExternalStore, useMemo as useMemo2, useCallback as useCallback3 } from "react";
353
+ import {
354
+ HistoryManager,
355
+ createHistoryManager
356
+ } from "@pixerate/editor";
357
+ function useHistory(managerOrOptions) {
358
+ const manager = useMemo2(() => {
359
+ if (managerOrOptions instanceof HistoryManager) {
360
+ return managerOrOptions;
361
+ }
362
+ return createHistoryManager(managerOrOptions);
363
+ }, [managerOrOptions]);
364
+ const state = useSyncExternalStore(
365
+ useCallback3(
366
+ (onStoreChange) => manager.subscribe(onStoreChange),
367
+ [manager]
368
+ ),
369
+ () => manager.getState(),
370
+ () => manager.getState()
371
+ );
372
+ const undo = useCallback3(() => manager.undo(), [manager]);
373
+ const redo = useCallback3(() => manager.redo(), [manager]);
374
+ const clear = useCallback3(() => manager.clear(), [manager]);
375
+ const execute = useCallback3(
376
+ (cmd) => manager.execute(cmd),
377
+ [manager]
378
+ );
379
+ const executeMerged = useCallback3(
380
+ (cmd, opts) => manager.executeMerged(cmd, opts),
381
+ [manager]
382
+ );
383
+ const batch = useCallback3(
384
+ (name, fn) => manager.batch(name, fn),
385
+ [manager]
386
+ );
387
+ return {
388
+ ...state,
389
+ manager,
390
+ undo,
391
+ redo,
392
+ clear,
393
+ execute,
394
+ executeMerged,
395
+ batch
396
+ };
397
+ }
398
+
399
+ // src/hooks/useHistoryShortcuts.ts
400
+ import { useEffect as useEffect3 } from "react";
401
+ function useHistoryShortcuts(manager, options = {}) {
402
+ const {
403
+ enabled = true,
404
+ target,
405
+ ignoreEditableElements = true
406
+ } = options;
407
+ useEffect3(() => {
408
+ if (!enabled) return;
409
+ const eventTarget = target ?? (typeof window !== "undefined" ? window : null);
410
+ if (!eventTarget) return;
411
+ const handleKeyDown = (event) => {
412
+ const e = event;
413
+ const isMac = typeof navigator !== "undefined" && /Mac|iPod|iPhone|iPad/.test(navigator.platform || navigator.userAgent);
414
+ const modifier = isMac ? e.metaKey : e.ctrlKey;
415
+ if (!modifier) return;
416
+ if (ignoreEditableElements && typeof document !== "undefined") {
417
+ const targetEl = e.target || document.activeElement;
418
+ if (targetEl && targetEl.tagName) {
419
+ const tagName = targetEl.tagName.toLowerCase();
420
+ const isInput = tagName === "input" || tagName === "textarea";
421
+ const isContentEditable = targetEl.isContentEditable || targetEl.getAttribute?.("contenteditable") === "true";
422
+ if (isInput || isContentEditable) {
423
+ return;
424
+ }
425
+ }
426
+ }
427
+ const key = e.key.toLowerCase();
428
+ if (key === "z" && !e.shiftKey) {
429
+ if (manager.getState().canUndo) {
430
+ e.preventDefault();
431
+ manager.undo();
432
+ }
433
+ return;
434
+ }
435
+ const isRedoKey = key === "z" && e.shiftKey || !isMac && key === "y" && !e.shiftKey;
436
+ if (isRedoKey) {
437
+ if (manager.getState().canRedo) {
438
+ e.preventDefault();
439
+ manager.redo();
440
+ }
441
+ }
442
+ };
443
+ eventTarget.addEventListener("keydown", handleKeyDown);
444
+ return () => {
445
+ eventTarget.removeEventListener("keydown", handleKeyDown);
446
+ };
447
+ }, [manager, enabled, target, ignoreEditableElements]);
448
+ }
449
+
230
450
  // src/components/EditorContent.tsx
231
451
  import {
232
452
  EditorContent as TipTapEditorContent
@@ -241,7 +461,7 @@ var EditorContent = ({
241
461
  };
242
462
 
243
463
  // src/components/BubbleMenu.tsx
244
- import { useEffect as useEffect2, useRef as useRef2, useState } from "react";
464
+ import { useEffect as useEffect4, useRef as useRef4, useState as useState3 } from "react";
245
465
  import { createPortal } from "react-dom";
246
466
  import {
247
467
  BubbleMenuPlugin
@@ -255,12 +475,12 @@ var BubbleMenu = ({
255
475
  pluginKey = "bubbleMenu",
256
476
  updateDelay
257
477
  }) => {
258
- const menuEl = useRef2(null);
259
- const [mounted, setMounted] = useState(false);
478
+ const menuEl = useRef4(null);
479
+ const [mounted, setMounted] = useState3(false);
260
480
  if (!menuEl.current && typeof document !== "undefined") {
261
481
  menuEl.current = document.createElement("div");
262
482
  }
263
- useEffect2(() => {
483
+ useEffect4(() => {
264
484
  if (!editor || !menuEl.current || editor.isDestroyed) {
265
485
  return;
266
486
  }
@@ -291,7 +511,7 @@ var BubbleMenu = ({
291
511
  };
292
512
 
293
513
  // src/components/TemplateRenderer.tsx
294
- import { useMemo as useMemo2 } from "react";
514
+ import { useMemo as useMemo3 } from "react";
295
515
  import {
296
516
  tokenizePrompt,
297
517
  resolveTemplates
@@ -306,11 +526,11 @@ var TemplateRenderer = ({
306
526
  onTemplateClick,
307
527
  onVariableClick
308
528
  }) => {
309
- const displayText = useMemo2(() => {
529
+ const displayText = useMemo3(() => {
310
530
  if (!resolve || templates.length === 0) return content;
311
531
  return resolveTemplates(content, templates);
312
532
  }, [content, templates, resolve]);
313
- const tokens = useMemo2(() => {
533
+ const tokens = useMemo3(() => {
314
534
  return tokenizePrompt(displayText);
315
535
  }, [displayText]);
316
536
  return /* @__PURE__ */ jsx2("div", { className, children: tokens.map((token, index) => {
@@ -362,13 +582,22 @@ var TemplateRenderer = ({
362
582
  }) });
363
583
  };
364
584
 
585
+ // src/index.ts
586
+ import {
587
+ DirtyTracker,
588
+ createDirtyTracker,
589
+ defaultIsEqual,
590
+ HistoryManager as HistoryManager2,
591
+ createHistoryManager as createHistoryManager2
592
+ } from "@pixerate/editor";
593
+
365
594
  // src/spreadsheet/useSpreadsheetEditor.ts
366
- import { useState as useState2, useMemo as useMemo3, useCallback } from "react";
595
+ import { useState as useState4, useMemo as useMemo4, useCallback as useCallback4 } from "react";
367
596
  import {
368
597
  SpreadsheetController
369
598
  } from "@pixerate/editor";
370
599
  function useSpreadsheetEditor(options = {}) {
371
- const [doc, setDoc] = useState2(() => ({
600
+ const [doc, setDoc] = useState4(() => ({
372
601
  id: options.document?.id || `sheet_${Date.now()}`,
373
602
  name: options.document?.name || "Sheet 1",
374
603
  columns: options.document?.columns || [],
@@ -377,11 +606,11 @@ function useSpreadsheetEditor(options = {}) {
377
606
  createdAt: options.document?.createdAt || Date.now(),
378
607
  updatedAt: options.document?.updatedAt || Date.now()
379
608
  }));
380
- const [activeCell, setActiveCell] = useState2(null);
381
- const [selectedRange, setSelectedRange] = useState2(null);
382
- const [editingCell, setEditingCell] = useState2(null);
383
- const [draftValue, setDraftValue] = useState2("");
384
- const controller = useMemo3(() => {
609
+ const [activeCell, setActiveCell] = useState4(null);
610
+ const [selectedRange, setSelectedRange] = useState4(null);
611
+ const [editingCell, setEditingCell] = useState4(null);
612
+ const [draftValue, setDraftValue] = useState4("");
613
+ const controller = useMemo4(() => {
385
614
  return new SpreadsheetController({
386
615
  ...options,
387
616
  onDocumentChange: (updated) => {
@@ -398,82 +627,82 @@ function useSpreadsheetEditor(options = {}) {
398
627
  }
399
628
  });
400
629
  }, []);
401
- const setCellValue = useCallback((rowId, colId, raw) => {
630
+ const setCellValue = useCallback4((rowId, colId, raw) => {
402
631
  controller.setCellValue(rowId, colId, raw);
403
632
  setDoc({ ...controller.document });
404
633
  }, [controller]);
405
- const selectCell = useCallback((row, col, extendSelection = false) => {
634
+ const selectCell = useCallback4((row, col, extendSelection = false) => {
406
635
  controller.selectCell(row, col, extendSelection);
407
636
  setActiveCell(controller.activeCell);
408
637
  setSelectedRange(controller.selectedRange);
409
638
  }, [controller]);
410
- const selectRange = useCallback((range) => {
639
+ const selectRange = useCallback4((range) => {
411
640
  controller.selectRange(range);
412
641
  setSelectedRange(controller.selectedRange);
413
642
  }, [controller]);
414
- const startEditing = useCallback((row, col, initialVal) => {
643
+ const startEditing = useCallback4((row, col, initialVal) => {
415
644
  controller.startEditing(row, col, initialVal);
416
645
  setActiveCell(controller.activeCell);
417
646
  setEditingCell(controller.editingCell);
418
647
  setDraftValue(controller.draftValue);
419
648
  }, [controller]);
420
- const commitEditing = useCallback((val) => {
649
+ const commitEditing = useCallback4((val) => {
421
650
  controller.commitEditing(val);
422
651
  setEditingCell(null);
423
652
  setDraftValue("");
424
653
  setDoc({ ...controller.document });
425
654
  }, [controller]);
426
- const cancelEditing = useCallback(() => {
655
+ const cancelEditing = useCallback4(() => {
427
656
  controller.cancelEditing();
428
657
  setEditingCell(null);
429
658
  setDraftValue("");
430
659
  }, [controller]);
431
- const moveCursor = useCallback((dir, extend = false) => {
660
+ const moveCursor = useCallback4((dir, extend = false) => {
432
661
  controller.moveCursor(dir, extend);
433
662
  setActiveCell(controller.activeCell);
434
663
  setSelectedRange(controller.selectedRange);
435
664
  }, [controller]);
436
- const insertColumn = useCallback((index, config) => {
665
+ const insertColumn = useCallback4((index, config) => {
437
666
  controller.insertColumn(index, config);
438
667
  setDoc({ ...controller.document });
439
668
  }, [controller]);
440
- const deleteColumn = useCallback((colId) => {
669
+ const deleteColumn = useCallback4((colId) => {
441
670
  controller.deleteColumn(colId);
442
671
  setDoc({ ...controller.document });
443
672
  }, [controller]);
444
- const insertRow = useCallback((index, config) => {
673
+ const insertRow = useCallback4((index, config) => {
445
674
  controller.insertRow(index, config);
446
675
  setDoc({ ...controller.document });
447
676
  }, [controller]);
448
- const deleteRow = useCallback((rowId) => {
677
+ const deleteRow = useCallback4((rowId) => {
449
678
  controller.deleteRow(rowId);
450
679
  setDoc({ ...controller.document });
451
680
  }, [controller]);
452
- const setColumnWidth = useCallback((colId, width) => {
681
+ const setColumnWidth = useCallback4((colId, width) => {
453
682
  controller.setColumnWidth(colId, width);
454
683
  setDoc({ ...controller.document });
455
684
  }, [controller]);
456
- const autoFitColumnWidth = useCallback((colId, customWidth) => {
685
+ const autoFitColumnWidth = useCallback4((colId, customWidth) => {
457
686
  controller.autoFitColumnWidth(colId, customWidth);
458
687
  setDoc({ ...controller.document });
459
688
  }, [controller]);
460
- const registerDataSource = useCallback((ds) => {
689
+ const registerDataSource = useCallback4((ds) => {
461
690
  controller.registerDataSource(ds);
462
691
  setDoc({ ...controller.document });
463
692
  }, [controller]);
464
- const setPrimaryDataSource = useCallback((id) => {
693
+ const setPrimaryDataSource = useCallback4((id) => {
465
694
  controller.setPrimaryDataSource(id);
466
695
  setDoc({ ...controller.document });
467
696
  }, [controller]);
468
- const recalculateAll = useCallback(() => {
697
+ const recalculateAll = useCallback4(() => {
469
698
  controller.recalculateAll();
470
699
  setDoc({ ...controller.document });
471
700
  }, [controller]);
472
- const undo = useCallback(() => {
701
+ const undo = useCallback4(() => {
473
702
  controller.undo();
474
703
  setDoc({ ...controller.document });
475
704
  }, [controller]);
476
- const redo = useCallback(() => {
705
+ const redo = useCallback4(() => {
477
706
  controller.redo();
478
707
  setDoc({ ...controller.document });
479
708
  }, [controller]);
@@ -526,7 +755,7 @@ function useSpreadsheetEditor(options = {}) {
526
755
  }
527
756
 
528
757
  // src/spreadsheet/SpreadsheetEditor.tsx
529
- import { useRef as useRef3, useState as useState3, useMemo as useMemo4, useEffect as useEffect3, useCallback as useCallback2 } from "react";
758
+ import { useRef as useRef5, useState as useState5, useMemo as useMemo5, useEffect as useEffect5, useCallback as useCallback5 } from "react";
530
759
  import {
531
760
  indexToColName
532
761
  } from "@pixerate/editor";
@@ -541,36 +770,36 @@ var SpreadsheetEditor = ({
541
770
  }) => {
542
771
  const defaultState = useSpreadsheetEditor();
543
772
  const state = externalState || defaultState;
544
- const gridRef = useRef3(null);
545
- const [resizingColId, setResizingColId] = useState3(null);
546
- const [hoveredColId, setHoveredColId] = useState3(null);
547
- const [resizeStartX, setResizeStartX] = useState3(0);
548
- const [resizeStartWidth, setResizeStartWidth] = useState3(0);
549
- const activeRawValue = useMemo4(() => {
773
+ const gridRef = useRef5(null);
774
+ const [resizingColId, setResizingColId] = useState5(null);
775
+ const [hoveredColId, setHoveredColId] = useState5(null);
776
+ const [resizeStartX, setResizeStartX] = useState5(0);
777
+ const [resizeStartWidth, setResizeStartWidth] = useState5(0);
778
+ const activeRawValue = useMemo5(() => {
550
779
  if (!state.activeCell) return "";
551
780
  const row = state.document.rows[state.activeCell.row];
552
781
  const col = state.document.columns[state.activeCell.col];
553
782
  if (!row || !col) return "";
554
783
  return state.getCell(row.id, col.id).raw;
555
784
  }, [state.activeCell, state.document]);
556
- const coordLabel = useMemo4(() => {
785
+ const coordLabel = useMemo5(() => {
557
786
  if (!state.activeCell) return "--";
558
787
  const colName = indexToColName(state.activeCell.col);
559
788
  return `${colName}${state.activeCell.row + 1}`;
560
789
  }, [state.activeCell]);
561
- const handleCellClick = useCallback2((rIdx, cIdx, e) => {
790
+ const handleCellClick = useCallback5((rIdx, cIdx, e) => {
562
791
  if (state.editingCell && (state.editingCell.row !== rIdx || state.editingCell.col !== cIdx)) {
563
792
  state.commitEditing();
564
793
  }
565
794
  state.selectCell(rIdx, cIdx, e.shiftKey);
566
795
  }, [state]);
567
- const handleCellDblClick = useCallback2((rIdx, cIdx) => {
796
+ const handleCellDblClick = useCallback5((rIdx, cIdx) => {
568
797
  if (readOnly) return;
569
798
  const col = state.document.columns[cIdx];
570
799
  if (col?.readOnly) return;
571
800
  state.startEditing(rIdx, cIdx);
572
801
  }, [readOnly, state]);
573
- const handleKeyDown = useCallback2((e) => {
802
+ const handleKeyDown = useCallback5((e) => {
574
803
  if (state.editingCell) {
575
804
  if (e.key === "Enter") {
576
805
  e.preventDefault();
@@ -634,7 +863,7 @@ var SpreadsheetEditor = ({
634
863
  }
635
864
  }
636
865
  }, [readOnly, state]);
637
- useEffect3(() => {
866
+ useEffect5(() => {
638
867
  if (!resizingColId) return;
639
868
  if (typeof document !== "undefined") {
640
869
  document.body.style.cursor = "col-resize";
@@ -688,7 +917,7 @@ var SpreadsheetEditor = ({
688
917
  window.removeEventListener("mouseup", handleMouseUp);
689
918
  };
690
919
  }, [resizingColId, resizeStartX, resizeStartWidth, state, onColumnResize]);
691
- const measureElementContentWidth = useCallback2((el, container) => {
920
+ const measureElementContentWidth = useCallback5((el, container) => {
692
921
  if (typeof document === "undefined") return 0;
693
922
  let maxW = el.scrollWidth || 0;
694
923
  const firstChild = el.firstElementChild;
@@ -736,7 +965,7 @@ var SpreadsheetEditor = ({
736
965
  }
737
966
  return maxW;
738
967
  }, []);
739
- const autoFitColumn = useCallback2((colId, colIndex) => {
968
+ const autoFitColumn = useCallback5((colId, colIndex) => {
740
969
  const col = state.document.columns.find((c) => c.id === colId);
741
970
  if (!col) return;
742
971
  let calculatedWidth = 0;
@@ -773,12 +1002,12 @@ var SpreadsheetEditor = ({
773
1002
  onColumnResize(updatedCol.id, updatedCol.width || 130);
774
1003
  }
775
1004
  }, [state, measureElementContentWidth, onColumnResize]);
776
- const handleResizeDblClick = useCallback2((colId, colIndex, e) => {
1005
+ const handleResizeDblClick = useCallback5((colId, colIndex, e) => {
777
1006
  e.preventDefault();
778
1007
  e.stopPropagation();
779
1008
  autoFitColumn(colId, colIndex);
780
1009
  }, [autoFitColumn]);
781
- const handleHeaderDblClick = useCallback2((colId, colIndex, e) => {
1010
+ const handleHeaderDblClick = useCallback5((colId, colIndex, e) => {
782
1011
  const target = e.currentTarget;
783
1012
  if (target) {
784
1013
  const rect = target.getBoundingClientRect();
@@ -963,10 +1192,19 @@ var SpreadsheetEditor = ({
963
1192
  };
964
1193
  export {
965
1194
  BubbleMenu,
1195
+ DirtyTracker,
966
1196
  EditorContent,
1197
+ HistoryManager2 as HistoryManager,
967
1198
  SpreadsheetEditor,
968
1199
  TemplateRenderer,
1200
+ createDirtyTracker,
1201
+ createHistoryManager2 as createHistoryManager,
1202
+ defaultIsEqual,
1203
+ useDismissGuard,
969
1204
  useEditor2 as useEditor,
1205
+ useHistory,
1206
+ useHistoryShortcuts,
1207
+ useNavigationGuard,
970
1208
  usePromptEditor,
971
1209
  useSpreadsheetEditor
972
1210
  };