@pixerate/editor-react 0.10.1 → 0.10.2

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.cjs CHANGED
@@ -645,36 +645,32 @@ var import_editor7 = require("@pixerate/editor");
645
645
  var import_react11 = require("react");
646
646
  var import_editor5 = require("@pixerate/editor");
647
647
  function useSpreadsheetEditor(options = {}) {
648
- const [doc, setDoc] = (0, import_react11.useState)(() => ({
649
- id: options.document?.id || `sheet_${Date.now()}`,
650
- name: options.document?.name || "Sheet 1",
651
- columns: options.document?.columns || [],
652
- rows: options.document?.rows || [],
653
- cells: options.document?.cells || {},
654
- createdAt: options.document?.createdAt || Date.now(),
655
- updatedAt: options.document?.updatedAt || Date.now()
656
- }));
657
- const [activeCell, setActiveCell] = (0, import_react11.useState)(null);
658
- const [selectedRange, setSelectedRange] = (0, import_react11.useState)(null);
659
- const [editingCell, setEditingCell] = (0, import_react11.useState)(null);
660
- const [draftValue, setDraftValue] = (0, import_react11.useState)("");
661
- const controller = (0, import_react11.useMemo)(() => {
662
- return new import_editor5.SpreadsheetController({
648
+ const optionsRef = (0, import_react11.useRef)(options);
649
+ optionsRef.current = options;
650
+ const settersRef = (0, import_react11.useRef)({});
651
+ const [controller] = (0, import_react11.useState)(
652
+ () => new import_editor5.SpreadsheetController({
663
653
  ...options,
664
654
  onDocumentChange: (updated) => {
665
- setDoc({ ...updated });
666
- options.onDocumentChange?.(updated);
655
+ settersRef.current.setDoc?.({ ...updated });
656
+ optionsRef.current.onDocumentChange?.(updated);
667
657
  },
668
658
  onSelectionChange: (active, range) => {
669
- setActiveCell(active);
670
- setSelectedRange(range);
671
- options.onSelectionChange?.(active, range);
659
+ settersRef.current.setActiveCell?.(active);
660
+ settersRef.current.setSelectedRange?.(range);
661
+ optionsRef.current.onSelectionChange?.(active, range);
672
662
  },
673
663
  onCellCommit: (rowId, colId, raw, value) => {
674
- options.onCellCommit?.(rowId, colId, raw, value);
664
+ optionsRef.current.onCellCommit?.(rowId, colId, raw, value);
675
665
  }
676
- });
677
- }, []);
666
+ })
667
+ );
668
+ const [doc, setDoc] = (0, import_react11.useState)(() => ({ ...controller.document }));
669
+ const [activeCell, setActiveCell] = (0, import_react11.useState)(controller.activeCell);
670
+ const [selectedRange, setSelectedRange] = (0, import_react11.useState)(controller.selectedRange);
671
+ const [editingCell, setEditingCell] = (0, import_react11.useState)(null);
672
+ const [draftValue, setDraftValue] = (0, import_react11.useState)("");
673
+ settersRef.current = { setDoc, setActiveCell, setSelectedRange };
678
674
  const setCellValue = (0, import_react11.useCallback)((rowId, colId, raw) => {
679
675
  controller.setCellValue(rowId, colId, raw);
680
676
  setDoc({ ...controller.document });
@@ -792,7 +788,7 @@ function useSpreadsheetEditor(options = {}) {
792
788
  registerDataSource,
793
789
  setPrimaryDataSource,
794
790
  recalculateAll,
795
- exportToTsv: () => controller.exportToTsv(),
791
+ exportToTsv: (range) => controller.exportToTsv(range),
796
792
  importFromTsv: (data) => {
797
793
  controller.importFromTsv(data);
798
794
  setDoc({ ...controller.document });
@@ -833,6 +829,25 @@ var SpreadsheetEditor = ({
833
829
  const colName = (0, import_editor6.indexToColName)(state.activeCell.col);
834
830
  return `${colName}${state.activeCell.row + 1}`;
835
831
  }, [state.activeCell]);
832
+ const [formulaDraft, setFormulaDraft] = (0, import_react12.useState)(null);
833
+ const activeColumn = state.activeCell ? state.document.columns[state.activeCell.col] : void 0;
834
+ const formulaBarReadOnly = readOnly || !state.activeCell || !!activeColumn?.readOnly;
835
+ (0, import_react12.useEffect)(() => {
836
+ setFormulaDraft(null);
837
+ }, [state.activeCell?.row, state.activeCell?.col]);
838
+ const commitFormulaBar = () => {
839
+ if (state.editingCell) {
840
+ state.commitEditing();
841
+ return;
842
+ }
843
+ if (formulaDraft === null || !state.activeCell) return;
844
+ const row = state.document.rows[state.activeCell.row];
845
+ const col = state.document.columns[state.activeCell.col];
846
+ if (row && col && !formulaBarReadOnly && formulaDraft !== activeRawValue) {
847
+ state.setCellValue(row.id, col.id, formulaDraft);
848
+ }
849
+ setFormulaDraft(null);
850
+ };
836
851
  const handleCellClick = (0, import_react12.useCallback)((rIdx, cIdx, e) => {
837
852
  if (state.editingCell && (state.editingCell.row !== rIdx || state.editingCell.col !== cIdx)) {
838
853
  state.commitEditing();
@@ -891,16 +906,19 @@ var SpreadsheetEditor = ({
891
906
  e.preventDefault();
892
907
  state.setCellValue(row.id, col.id, "");
893
908
  }
894
- } else if ((e.metaKey || e.ctrlKey) && e.key === "z") {
909
+ } else if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === "z") {
895
910
  e.preventDefault();
896
911
  if (e.shiftKey) {
897
912
  state.redo();
898
913
  } else {
899
914
  state.undo();
900
915
  }
901
- } else if ((e.metaKey || e.ctrlKey) && e.key === "c") {
916
+ } else if (e.ctrlKey && !e.metaKey && e.key.toLowerCase() === "y") {
902
917
  e.preventDefault();
903
- const tsv = state.exportToTsv();
918
+ state.redo();
919
+ } else if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === "c") {
920
+ e.preventDefault();
921
+ const tsv = state.exportToTsv(state.selectedRange);
904
922
  navigator.clipboard?.writeText(tsv);
905
923
  } else if (!readOnly && e.key.length === 1 && !e.ctrlKey && !e.metaKey && !e.altKey) {
906
924
  const col = state.document.columns[state.activeCell.col];
@@ -909,6 +927,10 @@ var SpreadsheetEditor = ({
909
927
  }
910
928
  }
911
929
  }, [readOnly, state]);
930
+ const stateRef = (0, import_react12.useRef)(state);
931
+ stateRef.current = state;
932
+ const onColumnResizeRef = (0, import_react12.useRef)(onColumnResize);
933
+ onColumnResizeRef.current = onColumnResize;
912
934
  (0, import_react12.useEffect)(() => {
913
935
  if (!resizingColId) return;
914
936
  if (typeof document !== "undefined") {
@@ -927,7 +949,7 @@ var SpreadsheetEditor = ({
927
949
  if (rafId === null) {
928
950
  rafId = requestAnimationFrame(() => {
929
951
  rafId = null;
930
- state.setColumnWidth(resizingColId, pendingWidth);
952
+ stateRef.current.setColumnWidth(resizingColId, pendingWidth);
931
953
  });
932
954
  }
933
955
  };
@@ -937,11 +959,8 @@ var SpreadsheetEditor = ({
937
959
  rafId = null;
938
960
  }
939
961
  if (hasDragged) {
940
- state.setColumnWidth(resizingColId, pendingWidth);
941
- const col = state.document.columns.find((c) => c.id === resizingColId);
942
- if (col && onColumnResize) {
943
- onColumnResize(col.id, col.width || pendingWidth);
944
- }
962
+ stateRef.current.setColumnWidth(resizingColId, pendingWidth);
963
+ onColumnResizeRef.current?.(resizingColId, pendingWidth);
945
964
  }
946
965
  setResizingColId(null);
947
966
  if (typeof document !== "undefined") {
@@ -962,7 +981,7 @@ var SpreadsheetEditor = ({
962
981
  window.removeEventListener("mousemove", handleMouseMove);
963
982
  window.removeEventListener("mouseup", handleMouseUp);
964
983
  };
965
- }, [resizingColId, resizeStartX, resizeStartWidth, state, onColumnResize]);
984
+ }, [resizingColId, resizeStartX, resizeStartWidth]);
966
985
  const measureElementContentWidth = (0, import_react12.useCallback)((el, container) => {
967
986
  if (typeof document === "undefined") return 0;
968
987
  let maxW = el.scrollWidth || 0;
@@ -1094,25 +1113,29 @@ var SpreadsheetEditor = ({
1094
1113
  type: "text",
1095
1114
  className: "flex-1 bg-transparent px-2 py-0.5 outline-none font-sans text-xs text-foreground placeholder:text-muted-foreground/60 focus:bg-background focus:ring-1 focus:ring-primary rounded",
1096
1115
  placeholder: "Enter a value or formula (e.g. =SUM(A1:A5))",
1097
- value: state.editingCell ? state.draftValue : activeRawValue,
1116
+ "aria-label": "Formula bar",
1117
+ readOnly: formulaBarReadOnly,
1118
+ value: state.editingCell ? state.draftValue : formulaDraft ?? activeRawValue,
1119
+ onFocus: () => {
1120
+ if (!state.editingCell) setFormulaDraft(activeRawValue);
1121
+ },
1098
1122
  onChange: (e) => {
1099
- if (state.activeCell) {
1123
+ if (state.editingCell) {
1100
1124
  state.setDraftValue(e.target.value);
1125
+ } else if (state.activeCell) {
1126
+ setFormulaDraft(e.target.value);
1101
1127
  }
1102
1128
  },
1129
+ onBlur: () => commitFormulaBar(),
1103
1130
  onKeyDown: (e) => {
1131
+ e.stopPropagation();
1104
1132
  if (e.key === "Enter") {
1105
1133
  e.preventDefault();
1106
- if (state.activeCell) {
1107
- const row = state.document.rows[state.activeCell.row];
1108
- const col = state.document.columns[state.activeCell.col];
1109
- if (row && col) {
1110
- state.setCellValue(row.id, col.id, e.target.value);
1111
- }
1112
- }
1134
+ commitFormulaBar();
1113
1135
  } else if (e.key === "Escape") {
1114
1136
  e.preventDefault();
1115
- state.cancelEditing();
1137
+ setFormulaDraft(null);
1138
+ if (state.editingCell) state.cancelEditing();
1116
1139
  }
1117
1140
  }
1118
1141
  }