@pixerate/editor-react 0.3.13 → 0.4.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.js CHANGED
@@ -227,6 +227,127 @@ 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
+
230
351
  // src/components/EditorContent.tsx
231
352
  import {
232
353
  EditorContent as TipTapEditorContent
@@ -241,7 +362,7 @@ var EditorContent = ({
241
362
  };
242
363
 
243
364
  // src/components/BubbleMenu.tsx
244
- import { useEffect as useEffect2, useRef as useRef2, useState } from "react";
365
+ import { useEffect as useEffect3, useRef as useRef4, useState as useState3 } from "react";
245
366
  import { createPortal } from "react-dom";
246
367
  import {
247
368
  BubbleMenuPlugin
@@ -255,12 +376,12 @@ var BubbleMenu = ({
255
376
  pluginKey = "bubbleMenu",
256
377
  updateDelay
257
378
  }) => {
258
- const menuEl = useRef2(null);
259
- const [mounted, setMounted] = useState(false);
379
+ const menuEl = useRef4(null);
380
+ const [mounted, setMounted] = useState3(false);
260
381
  if (!menuEl.current && typeof document !== "undefined") {
261
382
  menuEl.current = document.createElement("div");
262
383
  }
263
- useEffect2(() => {
384
+ useEffect3(() => {
264
385
  if (!editor || !menuEl.current || editor.isDestroyed) {
265
386
  return;
266
387
  }
@@ -362,13 +483,20 @@ var TemplateRenderer = ({
362
483
  }) });
363
484
  };
364
485
 
486
+ // src/index.ts
487
+ import {
488
+ DirtyTracker,
489
+ createDirtyTracker,
490
+ defaultIsEqual
491
+ } from "@pixerate/editor";
492
+
365
493
  // src/spreadsheet/useSpreadsheetEditor.ts
366
- import { useState as useState2, useMemo as useMemo3, useCallback } from "react";
494
+ import { useState as useState4, useMemo as useMemo3, useCallback as useCallback3 } from "react";
367
495
  import {
368
496
  SpreadsheetController
369
497
  } from "@pixerate/editor";
370
498
  function useSpreadsheetEditor(options = {}) {
371
- const [doc, setDoc] = useState2(() => ({
499
+ const [doc, setDoc] = useState4(() => ({
372
500
  id: options.document?.id || `sheet_${Date.now()}`,
373
501
  name: options.document?.name || "Sheet 1",
374
502
  columns: options.document?.columns || [],
@@ -377,10 +505,10 @@ function useSpreadsheetEditor(options = {}) {
377
505
  createdAt: options.document?.createdAt || Date.now(),
378
506
  updatedAt: options.document?.updatedAt || Date.now()
379
507
  }));
380
- const [activeCell, setActiveCell] = useState2(null);
381
- const [selectedRange, setSelectedRange] = useState2(null);
382
- const [editingCell, setEditingCell] = useState2(null);
383
- const [draftValue, setDraftValue] = useState2("");
508
+ const [activeCell, setActiveCell] = useState4(null);
509
+ const [selectedRange, setSelectedRange] = useState4(null);
510
+ const [editingCell, setEditingCell] = useState4(null);
511
+ const [draftValue, setDraftValue] = useState4("");
384
512
  const controller = useMemo3(() => {
385
513
  return new SpreadsheetController({
386
514
  ...options,
@@ -398,82 +526,82 @@ function useSpreadsheetEditor(options = {}) {
398
526
  }
399
527
  });
400
528
  }, []);
401
- const setCellValue = useCallback((rowId, colId, raw) => {
529
+ const setCellValue = useCallback3((rowId, colId, raw) => {
402
530
  controller.setCellValue(rowId, colId, raw);
403
531
  setDoc({ ...controller.document });
404
532
  }, [controller]);
405
- const selectCell = useCallback((row, col, extendSelection = false) => {
533
+ const selectCell = useCallback3((row, col, extendSelection = false) => {
406
534
  controller.selectCell(row, col, extendSelection);
407
535
  setActiveCell(controller.activeCell);
408
536
  setSelectedRange(controller.selectedRange);
409
537
  }, [controller]);
410
- const selectRange = useCallback((range) => {
538
+ const selectRange = useCallback3((range) => {
411
539
  controller.selectRange(range);
412
540
  setSelectedRange(controller.selectedRange);
413
541
  }, [controller]);
414
- const startEditing = useCallback((row, col, initialVal) => {
542
+ const startEditing = useCallback3((row, col, initialVal) => {
415
543
  controller.startEditing(row, col, initialVal);
416
544
  setActiveCell(controller.activeCell);
417
545
  setEditingCell(controller.editingCell);
418
546
  setDraftValue(controller.draftValue);
419
547
  }, [controller]);
420
- const commitEditing = useCallback((val) => {
548
+ const commitEditing = useCallback3((val) => {
421
549
  controller.commitEditing(val);
422
550
  setEditingCell(null);
423
551
  setDraftValue("");
424
552
  setDoc({ ...controller.document });
425
553
  }, [controller]);
426
- const cancelEditing = useCallback(() => {
554
+ const cancelEditing = useCallback3(() => {
427
555
  controller.cancelEditing();
428
556
  setEditingCell(null);
429
557
  setDraftValue("");
430
558
  }, [controller]);
431
- const moveCursor = useCallback((dir, extend = false) => {
559
+ const moveCursor = useCallback3((dir, extend = false) => {
432
560
  controller.moveCursor(dir, extend);
433
561
  setActiveCell(controller.activeCell);
434
562
  setSelectedRange(controller.selectedRange);
435
563
  }, [controller]);
436
- const insertColumn = useCallback((index, config) => {
564
+ const insertColumn = useCallback3((index, config) => {
437
565
  controller.insertColumn(index, config);
438
566
  setDoc({ ...controller.document });
439
567
  }, [controller]);
440
- const deleteColumn = useCallback((colId) => {
568
+ const deleteColumn = useCallback3((colId) => {
441
569
  controller.deleteColumn(colId);
442
570
  setDoc({ ...controller.document });
443
571
  }, [controller]);
444
- const insertRow = useCallback((index, config) => {
572
+ const insertRow = useCallback3((index, config) => {
445
573
  controller.insertRow(index, config);
446
574
  setDoc({ ...controller.document });
447
575
  }, [controller]);
448
- const deleteRow = useCallback((rowId) => {
576
+ const deleteRow = useCallback3((rowId) => {
449
577
  controller.deleteRow(rowId);
450
578
  setDoc({ ...controller.document });
451
579
  }, [controller]);
452
- const setColumnWidth = useCallback((colId, width) => {
580
+ const setColumnWidth = useCallback3((colId, width) => {
453
581
  controller.setColumnWidth(colId, width);
454
582
  setDoc({ ...controller.document });
455
583
  }, [controller]);
456
- const autoFitColumnWidth = useCallback((colId, customWidth) => {
584
+ const autoFitColumnWidth = useCallback3((colId, customWidth) => {
457
585
  controller.autoFitColumnWidth(colId, customWidth);
458
586
  setDoc({ ...controller.document });
459
587
  }, [controller]);
460
- const registerDataSource = useCallback((ds) => {
588
+ const registerDataSource = useCallback3((ds) => {
461
589
  controller.registerDataSource(ds);
462
590
  setDoc({ ...controller.document });
463
591
  }, [controller]);
464
- const setPrimaryDataSource = useCallback((id) => {
592
+ const setPrimaryDataSource = useCallback3((id) => {
465
593
  controller.setPrimaryDataSource(id);
466
594
  setDoc({ ...controller.document });
467
595
  }, [controller]);
468
- const recalculateAll = useCallback(() => {
596
+ const recalculateAll = useCallback3(() => {
469
597
  controller.recalculateAll();
470
598
  setDoc({ ...controller.document });
471
599
  }, [controller]);
472
- const undo = useCallback(() => {
600
+ const undo = useCallback3(() => {
473
601
  controller.undo();
474
602
  setDoc({ ...controller.document });
475
603
  }, [controller]);
476
- const redo = useCallback(() => {
604
+ const redo = useCallback3(() => {
477
605
  controller.redo();
478
606
  setDoc({ ...controller.document });
479
607
  }, [controller]);
@@ -526,7 +654,7 @@ function useSpreadsheetEditor(options = {}) {
526
654
  }
527
655
 
528
656
  // src/spreadsheet/SpreadsheetEditor.tsx
529
- import { useRef as useRef3, useState as useState3, useMemo as useMemo4, useEffect as useEffect3, useCallback as useCallback2 } from "react";
657
+ import { useRef as useRef5, useState as useState5, useMemo as useMemo4, useEffect as useEffect4, useCallback as useCallback4 } from "react";
530
658
  import {
531
659
  indexToColName
532
660
  } from "@pixerate/editor";
@@ -541,11 +669,11 @@ var SpreadsheetEditor = ({
541
669
  }) => {
542
670
  const defaultState = useSpreadsheetEditor();
543
671
  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);
672
+ const gridRef = useRef5(null);
673
+ const [resizingColId, setResizingColId] = useState5(null);
674
+ const [hoveredColId, setHoveredColId] = useState5(null);
675
+ const [resizeStartX, setResizeStartX] = useState5(0);
676
+ const [resizeStartWidth, setResizeStartWidth] = useState5(0);
549
677
  const activeRawValue = useMemo4(() => {
550
678
  if (!state.activeCell) return "";
551
679
  const row = state.document.rows[state.activeCell.row];
@@ -558,19 +686,19 @@ var SpreadsheetEditor = ({
558
686
  const colName = indexToColName(state.activeCell.col);
559
687
  return `${colName}${state.activeCell.row + 1}`;
560
688
  }, [state.activeCell]);
561
- const handleCellClick = useCallback2((rIdx, cIdx, e) => {
689
+ const handleCellClick = useCallback4((rIdx, cIdx, e) => {
562
690
  if (state.editingCell && (state.editingCell.row !== rIdx || state.editingCell.col !== cIdx)) {
563
691
  state.commitEditing();
564
692
  }
565
693
  state.selectCell(rIdx, cIdx, e.shiftKey);
566
694
  }, [state]);
567
- const handleCellDblClick = useCallback2((rIdx, cIdx) => {
695
+ const handleCellDblClick = useCallback4((rIdx, cIdx) => {
568
696
  if (readOnly) return;
569
697
  const col = state.document.columns[cIdx];
570
698
  if (col?.readOnly) return;
571
699
  state.startEditing(rIdx, cIdx);
572
700
  }, [readOnly, state]);
573
- const handleKeyDown = useCallback2((e) => {
701
+ const handleKeyDown = useCallback4((e) => {
574
702
  if (state.editingCell) {
575
703
  if (e.key === "Enter") {
576
704
  e.preventDefault();
@@ -634,7 +762,7 @@ var SpreadsheetEditor = ({
634
762
  }
635
763
  }
636
764
  }, [readOnly, state]);
637
- useEffect3(() => {
765
+ useEffect4(() => {
638
766
  if (!resizingColId) return;
639
767
  if (typeof document !== "undefined") {
640
768
  document.body.style.cursor = "col-resize";
@@ -688,7 +816,7 @@ var SpreadsheetEditor = ({
688
816
  window.removeEventListener("mouseup", handleMouseUp);
689
817
  };
690
818
  }, [resizingColId, resizeStartX, resizeStartWidth, state, onColumnResize]);
691
- const measureElementContentWidth = useCallback2((el, container) => {
819
+ const measureElementContentWidth = useCallback4((el, container) => {
692
820
  if (typeof document === "undefined") return 0;
693
821
  let maxW = el.scrollWidth || 0;
694
822
  const firstChild = el.firstElementChild;
@@ -736,7 +864,7 @@ var SpreadsheetEditor = ({
736
864
  }
737
865
  return maxW;
738
866
  }, []);
739
- const autoFitColumn = useCallback2((colId, colIndex) => {
867
+ const autoFitColumn = useCallback4((colId, colIndex) => {
740
868
  const col = state.document.columns.find((c) => c.id === colId);
741
869
  if (!col) return;
742
870
  let calculatedWidth = 0;
@@ -773,12 +901,12 @@ var SpreadsheetEditor = ({
773
901
  onColumnResize(updatedCol.id, updatedCol.width || 130);
774
902
  }
775
903
  }, [state, measureElementContentWidth, onColumnResize]);
776
- const handleResizeDblClick = useCallback2((colId, colIndex, e) => {
904
+ const handleResizeDblClick = useCallback4((colId, colIndex, e) => {
777
905
  e.preventDefault();
778
906
  e.stopPropagation();
779
907
  autoFitColumn(colId, colIndex);
780
908
  }, [autoFitColumn]);
781
- const handleHeaderDblClick = useCallback2((colId, colIndex, e) => {
909
+ const handleHeaderDblClick = useCallback4((colId, colIndex, e) => {
782
910
  const target = e.currentTarget;
783
911
  if (target) {
784
912
  const rect = target.getBoundingClientRect();
@@ -963,10 +1091,15 @@ var SpreadsheetEditor = ({
963
1091
  };
964
1092
  export {
965
1093
  BubbleMenu,
1094
+ DirtyTracker,
966
1095
  EditorContent,
967
1096
  SpreadsheetEditor,
968
1097
  TemplateRenderer,
1098
+ createDirtyTracker,
1099
+ defaultIsEqual,
1100
+ useDismissGuard,
969
1101
  useEditor2 as useEditor,
1102
+ useNavigationGuard,
970
1103
  usePromptEditor,
971
1104
  useSpreadsheetEditor
972
1105
  };