@pixerate/editor-react 0.17.0 → 0.18.1

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.
@@ -41,7 +41,8 @@ __export(spreadsheet_exports, {
41
41
  SpreadsheetValidationDialog: () => SpreadsheetValidationDialog,
42
42
  useFillHandle: () => useFillHandle,
43
43
  useSpreadsheetClipboard: () => useSpreadsheetClipboard,
44
- useSpreadsheetEditor: () => useSpreadsheetEditor
44
+ useSpreadsheetEditor: () => useSpreadsheetEditor,
45
+ useSpreadsheetViewport: () => useSpreadsheetViewport
45
46
  });
46
47
  module.exports = __toCommonJS(spreadsheet_exports);
47
48
 
@@ -282,8 +283,8 @@ function useSpreadsheetEditor(options = {}) {
282
283
  }
283
284
 
284
285
  // src/spreadsheet/SpreadsheetEditor.tsx
285
- var import_react8 = require("react");
286
- var import_spreadsheet7 = require("@pixerate/editor/spreadsheet");
286
+ var import_react10 = require("react");
287
+ var import_spreadsheet8 = require("@pixerate/editor/spreadsheet");
287
288
 
288
289
  // src/spreadsheet/SpreadsheetContextMenu.tsx
289
290
  var import_react2 = __toESM(require("react"), 1);
@@ -362,6 +363,7 @@ var SpreadsheetContextMenu = ({ items, x, y, onClose, onOpenPanel, ariaLabel = "
362
363
  };
363
364
 
364
365
  // src/spreadsheet/SpreadsheetGroupRow.tsx
366
+ var import_react3 = __toESM(require("react"), 1);
365
367
  var import_jsx_runtime2 = require("react/jsx-runtime");
366
368
  var formatSummary = (value) => value === null ? "\u2013" : String(value);
367
369
  var SpreadsheetGroupRow = ({
@@ -369,9 +371,14 @@ var SpreadsheetGroupRow = ({
369
371
  columns,
370
372
  groupColId,
371
373
  onToggle,
372
- trailingCell
374
+ trailingCell,
375
+ labelColumns = columns,
376
+ leadingColumns,
377
+ leftSpace = 0,
378
+ rightSpace = 0
373
379
  }) => {
374
- const labelColId = columns.some((c) => c.column.id === groupColId) ? groupColId : columns[0]?.column.id;
380
+ const labelColId = labelColumns.some((c) => c.column.id === groupColId) ? groupColId : labelColumns[0]?.column.id;
381
+ const spacer = (key) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { "aria-hidden": "true", "data-spacer": "", style: { padding: 0 } }, key);
375
382
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("tr", { className: "border-b border-border bg-muted/40 font-semibold", "data-group-key": group.key, style: { height: 28 }, children: [
376
383
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { className: "w-12 min-w-[3rem] sticky left-0 z-10 bg-muted border-r border-border text-center", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
377
384
  "button",
@@ -387,24 +394,30 @@ var SpreadsheetGroupRow = ({
387
394
  children: group.collapsed ? "\u25B8" : "\u25BE"
388
395
  }
389
396
  ) }),
390
- columns.map(({ column }) => {
397
+ columns.map(({ column }, i) => {
391
398
  const summary = group.summaries[column.id];
392
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { className: "border-r border-border px-2 py-1 truncate max-w-0 text-foreground", style: { maxWidth: 0, overflow: "hidden" }, children: column.id === labelColId ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "truncate", children: [
393
- group.label,
394
- " ",
395
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "font-normal text-muted-foreground", children: [
396
- "(",
397
- group.rowIndices.length,
398
- ")"
399
- ] })
400
- ] }) : summary !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "truncate", "data-summary": column.id, children: formatSummary(summary) }) : null }, column.id);
399
+ const before = leadingColumns !== void 0 && i === leadingColumns && leftSpace > 0 ? spacer("space:left") : null;
400
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react3.default.Fragment, { children: [
401
+ before,
402
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { className: "border-r border-border px-2 py-1 truncate max-w-0 text-foreground", style: { maxWidth: 0, overflow: "hidden" }, children: column.id === labelColId ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "truncate", children: [
403
+ group.label,
404
+ " ",
405
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "font-normal text-muted-foreground", children: [
406
+ "(",
407
+ group.rowIndices.length,
408
+ ")"
409
+ ] })
410
+ ] }) : summary !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "truncate", "data-summary": column.id, children: formatSummary(summary) }) : null })
411
+ ] }, column.id);
401
412
  }),
413
+ leadingColumns !== void 0 && leadingColumns >= columns.length && leftSpace > 0 && spacer("space:left"),
414
+ rightSpace > 0 && spacer("space:right"),
402
415
  trailingCell && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { className: "w-10 min-w-[2.5rem] bg-muted/10 border-r border-border" })
403
416
  ] });
404
417
  };
405
418
 
406
419
  // src/spreadsheet/useSpreadsheetTableInteractions.ts
407
- var import_react3 = require("react");
420
+ var import_react4 = require("react");
408
421
  var import_spreadsheet3 = require("@pixerate/editor/spreadsheet");
409
422
  function gridHasFocus(grid) {
410
423
  if (!grid || typeof document === "undefined") return false;
@@ -413,12 +426,12 @@ function gridHasFocus(grid) {
413
426
  return !(active instanceof HTMLInputElement || active instanceof HTMLTextAreaElement);
414
427
  }
415
428
  function useSpreadsheetClipboard(gridRef, state, readOnly) {
416
- const stateRef = (0, import_react3.useRef)(state);
429
+ const stateRef = (0, import_react4.useRef)(state);
417
430
  stateRef.current = state;
418
- const readOnlyRef = (0, import_react3.useRef)(readOnly);
431
+ const readOnlyRef = (0, import_react4.useRef)(readOnly);
419
432
  readOnlyRef.current = readOnly;
420
- const copiedRef = (0, import_react3.useRef)(false);
421
- (0, import_react3.useEffect)(() => {
433
+ const copiedRef = (0, import_react4.useRef)(false);
434
+ (0, import_react4.useEffect)(() => {
422
435
  if (typeof document === "undefined") return;
423
436
  const handleCopy = (e) => {
424
437
  const s = stateRef.current;
@@ -441,7 +454,7 @@ function useSpreadsheetClipboard(gridRef, state, readOnly) {
441
454
  document.removeEventListener("paste", handlePaste);
442
455
  };
443
456
  }, [gridRef]);
444
- const copyShortcutFallback = (0, import_react3.useCallback)(() => {
457
+ const copyShortcutFallback = (0, import_react4.useCallback)(() => {
445
458
  copiedRef.current = false;
446
459
  setTimeout(() => {
447
460
  if (copiedRef.current) return;
@@ -453,13 +466,13 @@ function useSpreadsheetClipboard(gridRef, state, readOnly) {
453
466
  return { copyShortcutFallback };
454
467
  }
455
468
  function useFillHandle(state) {
456
- const [drag, setDrag] = (0, import_react3.useState)(null);
457
- const dragRef = (0, import_react3.useRef)(drag);
469
+ const [drag, setDrag] = (0, import_react4.useState)(null);
470
+ const dragRef = (0, import_react4.useRef)(drag);
458
471
  dragRef.current = drag;
459
- const stateRef = (0, import_react3.useRef)(state);
472
+ const stateRef = (0, import_react4.useRef)(state);
460
473
  stateRef.current = state;
461
474
  const dragging = drag !== null;
462
- (0, import_react3.useEffect)(() => {
475
+ (0, import_react4.useEffect)(() => {
463
476
  if (!dragging) return;
464
477
  const handleMouseUp = () => {
465
478
  const current = dragRef.current;
@@ -469,13 +482,13 @@ function useFillHandle(state) {
469
482
  window.addEventListener("mouseup", handleMouseUp);
470
483
  return () => window.removeEventListener("mouseup", handleMouseUp);
471
484
  }, [dragging]);
472
- const startFill = (0, import_react3.useCallback)((e) => {
485
+ const startFill = (0, import_react4.useCallback)((e) => {
473
486
  e.preventDefault();
474
487
  e.stopPropagation();
475
488
  const range = stateRef.current.selectedRange;
476
489
  if (range) setDrag({ source: (0, import_spreadsheet3.normalizeRange)(range), target: null });
477
490
  }, []);
478
- const extendFill = (0, import_react3.useCallback)((row, col) => {
491
+ const extendFill = (0, import_react4.useCallback)((row, col) => {
479
492
  const current = dragRef.current;
480
493
  if (!current) return;
481
494
  setDrag({ source: current.source, target: (0, import_spreadsheet3.computeFillTarget)(current.source, { row, col }) });
@@ -484,12 +497,12 @@ function useFillHandle(state) {
484
497
  }
485
498
 
486
499
  // src/spreadsheet/SpreadsheetValidationDialog.tsx
487
- var import_react4 = require("react");
500
+ var import_react5 = require("react");
488
501
  var import_jsx_runtime3 = require("react/jsx-runtime");
489
502
  var SpreadsheetValidationDialog = ({ prompt, onResolve }) => {
490
503
  const style = prompt.result.errorStyle ?? "stop";
491
- const firstButton = (0, import_react4.useRef)(null);
492
- (0, import_react4.useEffect)(() => {
504
+ const firstButton = (0, import_react5.useRef)(null);
505
+ (0, import_react5.useEffect)(() => {
493
506
  firstButton.current?.focus();
494
507
  }, [prompt]);
495
508
  const buttons = style === "stop" ? [
@@ -555,7 +568,7 @@ var SpreadsheetValidationDialog = ({ prompt, onResolve }) => {
555
568
  };
556
569
 
557
570
  // src/spreadsheet/SpreadsheetRulePanels.tsx
558
- var import_react5 = require("react");
571
+ var import_react6 = require("react");
559
572
  var import_spreadsheet4 = require("@pixerate/editor/spreadsheet");
560
573
  var import_jsx_runtime4 = require("react/jsx-runtime");
561
574
  var inputClass = "w-full rounded border border-border bg-background px-1.5 py-0.5 text-xs text-foreground";
@@ -609,18 +622,18 @@ function RuleSwatch({ rule }) {
609
622
  }
610
623
  var SpreadsheetConditionalFormatPanel = ({ state, onClose }) => {
611
624
  const rules = state.document.table?.conditionalFormats ?? [];
612
- const [kind, setKind] = (0, import_react5.useState)("greaterThan");
613
- const [appliesTo, setAppliesTo] = (0, import_react5.useState)(() => selectionText(state.selectedRange));
614
- const [value, setValue] = (0, import_react5.useState)("");
615
- const [value2, setValue2] = (0, import_react5.useState)("");
616
- const [text, setText] = (0, import_react5.useState)("");
617
- const [formula, setFormula] = (0, import_react5.useState)("=");
618
- const [rank, setRank] = (0, import_react5.useState)("10");
619
- const [period, setPeriod] = (0, import_react5.useState)("today");
620
- const [iconSet, setIconSet] = (0, import_react5.useState)("3TrafficLights1");
621
- const [color, setColor] = (0, import_react5.useState)("#638ec6");
622
- const [styleId, setStyleId] = (0, import_react5.useState)(import_spreadsheet4.CONDITIONAL_FORMAT_STYLE_PRESETS[0].id);
623
- const preset = (0, import_react5.useMemo)(() => import_spreadsheet4.CONDITIONAL_FORMAT_PRESETS.find((p) => p.kind === kind), [kind]);
625
+ const [kind, setKind] = (0, import_react6.useState)("greaterThan");
626
+ const [appliesTo, setAppliesTo] = (0, import_react6.useState)(() => selectionText(state.selectedRange));
627
+ const [value, setValue] = (0, import_react6.useState)("");
628
+ const [value2, setValue2] = (0, import_react6.useState)("");
629
+ const [text, setText] = (0, import_react6.useState)("");
630
+ const [formula, setFormula] = (0, import_react6.useState)("=");
631
+ const [rank, setRank] = (0, import_react6.useState)("10");
632
+ const [period, setPeriod] = (0, import_react6.useState)("today");
633
+ const [iconSet, setIconSet] = (0, import_react6.useState)("3TrafficLights1");
634
+ const [color, setColor] = (0, import_react6.useState)("#638ec6");
635
+ const [styleId, setStyleId] = (0, import_react6.useState)(import_spreadsheet4.CONDITIONAL_FORMAT_STYLE_PRESETS[0].id);
636
+ const preset = (0, import_react6.useMemo)(() => import_spreadsheet4.CONDITIONAL_FORMAT_PRESETS.find((p) => p.kind === kind), [kind]);
624
637
  const ranges = (0, import_spreadsheet4.parseRuleRanges)(appliesTo);
625
638
  const add = () => {
626
639
  if (!ranges) return;
@@ -704,15 +717,15 @@ var SpreadsheetConditionalFormatPanel = ({ state, onClose }) => {
704
717
  };
705
718
  var SpreadsheetDataValidationPanel = ({ state, onClose }) => {
706
719
  const rules = state.document.table?.dataValidations ?? [];
707
- const [type, setType] = (0, import_react5.useState)("list");
708
- const [operator, setOperator] = (0, import_react5.useState)("between");
709
- const [formula1, setFormula1] = (0, import_react5.useState)("");
710
- const [formula2, setFormula2] = (0, import_react5.useState)("");
711
- const [errorStyle, setErrorStyle] = (0, import_react5.useState)("stop");
712
- const [errorMessage, setErrorMessage] = (0, import_react5.useState)("");
713
- const [inputMessage, setInputMessage] = (0, import_react5.useState)("");
714
- const [ignoreBlank, setIgnoreBlank] = (0, import_react5.useState)(true);
715
- const [appliesTo, setAppliesTo] = (0, import_react5.useState)(() => selectionText(state.selectedRange));
720
+ const [type, setType] = (0, import_react6.useState)("list");
721
+ const [operator, setOperator] = (0, import_react6.useState)("between");
722
+ const [formula1, setFormula1] = (0, import_react6.useState)("");
723
+ const [formula2, setFormula2] = (0, import_react6.useState)("");
724
+ const [errorStyle, setErrorStyle] = (0, import_react6.useState)("stop");
725
+ const [errorMessage, setErrorMessage] = (0, import_react6.useState)("");
726
+ const [inputMessage, setInputMessage] = (0, import_react6.useState)("");
727
+ const [ignoreBlank, setIgnoreBlank] = (0, import_react6.useState)(true);
728
+ const [appliesTo, setAppliesTo] = (0, import_react6.useState)(() => selectionText(state.selectedRange));
716
729
  const ranges = (0, import_spreadsheet4.parseRuleRanges)(appliesTo);
717
730
  const usesOperator = type === "whole" || type === "decimal" || type === "date" || type === "time" || type === "textLength";
718
731
  const needsTwo = usesOperator && (operator === "between" || operator === "notBetween");
@@ -785,35 +798,99 @@ var SpreadsheetDataValidationPanel = ({ state, onClose }) => {
785
798
  ] });
786
799
  };
787
800
 
788
- // src/spreadsheet/FormulaHints.tsx
789
- var import_react6 = require("react");
801
+ // src/spreadsheet/useSpreadsheetViewport.ts
802
+ var import_react7 = require("react");
790
803
  var import_spreadsheet5 = require("@pixerate/editor/spreadsheet");
804
+ var useIsomorphicLayoutEffect = typeof window !== "undefined" ? import_react7.useLayoutEffect : import_react7.useEffect;
805
+ function useSpreadsheetViewport(scrollRef, view, options = {}) {
806
+ const metrics = (0, import_react7.useMemo)(() => (0, import_spreadsheet5.measureSpreadsheetView)(view), [view]);
807
+ const virtual = (0, import_spreadsheet5.shouldVirtualizeSpreadsheet)(view, options.virtualize ?? "auto");
808
+ const [viewport, setViewport] = (0, import_react7.useState)({ scrollTop: 0, scrollLeft: 0, width: 0, height: 0 });
809
+ const windowOptions = (0, import_react7.useMemo)(
810
+ () => ({ merges: options.merges, overscanRows: options.overscanRows, overscanColumns: options.overscanColumns }),
811
+ [options.merges, options.overscanRows, options.overscanColumns]
812
+ );
813
+ const win = (0, import_react7.useMemo)(
814
+ () => virtual ? (0, import_spreadsheet5.getSpreadsheetViewWindow)(metrics, viewport, windowOptions) : (0, import_spreadsheet5.fullSpreadsheetViewWindow)(metrics),
815
+ [virtual, metrics, viewport, windowOptions]
816
+ );
817
+ const latest = (0, import_react7.useRef)({ metrics, viewport, virtual, windowOptions });
818
+ latest.current = { metrics, viewport, virtual, windowOptions };
819
+ const readViewport = (0, import_react7.useCallback)(() => {
820
+ const el = scrollRef.current;
821
+ if (!el) return null;
822
+ return { scrollTop: el.scrollTop, scrollLeft: el.scrollLeft, width: el.clientWidth, height: el.clientHeight };
823
+ }, [scrollRef]);
824
+ const updateViewport = (0, import_react7.useCallback)((next) => {
825
+ setViewport((prev) => {
826
+ const { metrics: m, virtual: v, windowOptions: o } = latest.current;
827
+ if (!v) return prev;
828
+ const same = prev.width === next.width && prev.height === next.height && (0, import_spreadsheet5.sameSpreadsheetViewWindow)((0, import_spreadsheet5.getSpreadsheetViewWindow)(m, prev, o), (0, import_spreadsheet5.getSpreadsheetViewWindow)(m, next, o));
829
+ return same ? prev : next;
830
+ });
831
+ }, []);
832
+ const onScroll = (0, import_react7.useCallback)(() => {
833
+ const next = readViewport();
834
+ if (next) updateViewport(next);
835
+ }, [readViewport, updateViewport]);
836
+ useIsomorphicLayoutEffect(() => {
837
+ if (!virtual) return;
838
+ onScroll();
839
+ const el = scrollRef.current;
840
+ if (!el || typeof ResizeObserver === "undefined") return;
841
+ const observer = new ResizeObserver(() => onScroll());
842
+ observer.observe(el);
843
+ return () => observer.disconnect();
844
+ }, [virtual, onScroll, scrollRef]);
845
+ const activeRow = options.activeCell?.row;
846
+ const activeCol = options.activeCell?.col;
847
+ useIsomorphicLayoutEffect(() => {
848
+ if (!virtual || activeRow === void 0 || activeCol === void 0) return;
849
+ const el = scrollRef.current;
850
+ const current = latest.current.viewport;
851
+ const measured = readViewport();
852
+ const base = measured ? { ...measured, scrollTop: Math.max(measured.scrollTop, 0), scrollLeft: Math.max(measured.scrollLeft, 0) } : current;
853
+ const target = (0, import_spreadsheet5.getSpreadsheetScrollToCell)(latest.current.metrics, base, { row: activeRow, col: activeCol });
854
+ if (!target) return;
855
+ const next = { ...base, ...target };
856
+ if (el) {
857
+ if (target.scrollTop !== void 0) el.scrollTop = target.scrollTop;
858
+ if (target.scrollLeft !== void 0) el.scrollLeft = target.scrollLeft;
859
+ }
860
+ updateViewport(next);
861
+ }, [virtual, activeRow, activeCol]);
862
+ return { metrics, window: win, onScroll };
863
+ }
864
+
865
+ // src/spreadsheet/FormulaHints.tsx
866
+ var import_react8 = require("react");
867
+ var import_spreadsheet6 = require("@pixerate/editor/spreadsheet");
791
868
  var import_jsx_runtime5 = require("react/jsx-runtime");
792
869
  var FormulaHints = ({ inputRef, value, onAccept, limit = 8, names }) => {
793
- const [caret, setCaret] = (0, import_react6.useState)(null);
794
- const [focused, setFocused] = (0, import_react6.useState)(false);
795
- const [selected, setSelected] = (0, import_react6.useState)(0);
796
- const [dismissed, setDismissed] = (0, import_react6.useState)(false);
797
- const [position, setPosition] = (0, import_react6.useState)(null);
798
- const pendingCaret = (0, import_react6.useRef)(null);
799
- const hints = (0, import_react6.useMemo)(
800
- () => (0, import_spreadsheet5.getFormulaHints)(value, caret ?? value.length, { limit, names }),
870
+ const [caret, setCaret] = (0, import_react8.useState)(null);
871
+ const [focused, setFocused] = (0, import_react8.useState)(false);
872
+ const [selected, setSelected] = (0, import_react8.useState)(0);
873
+ const [dismissed, setDismissed] = (0, import_react8.useState)(false);
874
+ const [position, setPosition] = (0, import_react8.useState)(null);
875
+ const pendingCaret = (0, import_react8.useRef)(null);
876
+ const hints = (0, import_react8.useMemo)(
877
+ () => (0, import_spreadsheet6.getFormulaHints)(value, caret ?? value.length, { limit, names }),
801
878
  [value, caret, limit, names]
802
879
  );
803
880
  const suggestions = dismissed ? [] : hints.suggestions;
804
881
  const selectedIndex = Math.max(0, Math.min(selected, suggestions.length - 1));
805
882
  const visible = focused && value.trimStart().startsWith("=") && (suggestions.length > 0 || !!hints.activeCall);
806
- const latest = (0, import_react6.useRef)({ suggestions, selected: selectedIndex, value, caret, onAccept });
883
+ const latest = (0, import_react8.useRef)({ suggestions, selected: selectedIndex, value, caret, onAccept });
807
884
  latest.current = { suggestions, selected: selectedIndex, value, caret, onAccept };
808
885
  const accept = (index) => {
809
886
  const { suggestions: list, value: current, caret: at, onAccept: commit } = latest.current;
810
887
  const suggestion = list[index];
811
888
  if (!suggestion) return;
812
- const next = (0, import_spreadsheet5.applyFormulaSuggestion)(current, at ?? current.length, suggestion);
889
+ const next = (0, import_spreadsheet6.applyFormulaSuggestion)(current, at ?? current.length, suggestion);
813
890
  pendingCaret.current = next.caret;
814
891
  commit(next.value);
815
892
  };
816
- (0, import_react6.useEffect)(() => {
893
+ (0, import_react8.useEffect)(() => {
817
894
  const input = inputRef.current;
818
895
  if (!input) return;
819
896
  const syncCaret = () => setCaret(input.selectionStart ?? input.value.length);
@@ -863,7 +940,7 @@ var FormulaHints = ({ inputRef, value, onAccept, limit = 8, names }) => {
863
940
  input.removeEventListener("keydown", onKeyDown);
864
941
  };
865
942
  }, [inputRef]);
866
- (0, import_react6.useLayoutEffect)(() => {
943
+ (0, import_react8.useLayoutEffect)(() => {
867
944
  const input = inputRef.current;
868
945
  const at = pendingCaret.current;
869
946
  if (!input || at === null || input.value !== value) return;
@@ -872,7 +949,7 @@ var FormulaHints = ({ inputRef, value, onAccept, limit = 8, names }) => {
872
949
  setCaret(at);
873
950
  setSelected(0);
874
951
  }, [value, inputRef]);
875
- (0, import_react6.useLayoutEffect)(() => {
952
+ (0, import_react8.useLayoutEffect)(() => {
876
953
  const input = inputRef.current;
877
954
  if (!visible || !input) return;
878
955
  const rect = input.getBoundingClientRect();
@@ -936,16 +1013,16 @@ var FormulaHints = ({ inputRef, value, onAccept, limit = 8, names }) => {
936
1013
  };
937
1014
 
938
1015
  // src/spreadsheet/SheetTabs.tsx
939
- var import_react7 = require("react");
940
- var import_spreadsheet6 = require("@pixerate/editor/spreadsheet");
1016
+ var import_react9 = require("react");
1017
+ var import_spreadsheet7 = require("@pixerate/editor/spreadsheet");
941
1018
  var import_jsx_runtime6 = require("react/jsx-runtime");
942
1019
  var SheetTabs = ({ state, readOnly = false, className = "" }) => {
943
1020
  const { controller, sheets } = state;
944
- const [renaming, setRenaming] = (0, import_react7.useState)(null);
945
- const [error, setError] = (0, import_react7.useState)(null);
946
- const [menu, setMenu] = (0, import_react7.useState)(null);
947
- const dragFrom = (0, import_react7.useRef)(null);
948
- const [dropTarget, setDropTarget] = (0, import_react7.useState)(null);
1021
+ const [renaming, setRenaming] = (0, import_react9.useState)(null);
1022
+ const [error, setError] = (0, import_react9.useState)(null);
1023
+ const [menu, setMenu] = (0, import_react9.useState)(null);
1024
+ const dragFrom = (0, import_react9.useRef)(null);
1025
+ const [dropTarget, setDropTarget] = (0, import_react9.useState)(null);
949
1026
  const commitRename = (cancelOnError) => {
950
1027
  if (!renaming) return;
951
1028
  const sheet = sheets.find((s) => s.id === renaming.id);
@@ -1016,7 +1093,7 @@ var SheetTabs = ({ state, readOnly = false, className = "" }) => {
1016
1093
  onContextMenu: (e) => {
1017
1094
  if (readOnly) return;
1018
1095
  e.preventDefault();
1019
- setMenu({ x: e.clientX, y: e.clientY, items: (0, import_spreadsheet6.getSheetTabMenuItems)(controller, sheet.id, { onError: setError }) });
1096
+ setMenu({ x: e.clientX, y: e.clientY, items: (0, import_spreadsheet7.getSheetTabMenuItems)(controller, sheet.id, { onError: setError }) });
1020
1097
  },
1021
1098
  onDragStart: (e) => {
1022
1099
  dragFrom.current = index;
@@ -1036,7 +1113,7 @@ var SheetTabs = ({ state, readOnly = false, className = "" }) => {
1036
1113
  dragFrom.current = null;
1037
1114
  setDropTarget(null);
1038
1115
  if (from === null) return;
1039
- state.moveSheet(sheets[from].id, (0, import_spreadsheet6.sheetDropIndex)(from, index, dropAfter(e)));
1116
+ state.moveSheet(sheets[from].id, (0, import_spreadsheet7.sheetDropIndex)(from, index, dropAfter(e)));
1040
1117
  },
1041
1118
  onDragEnd: () => {
1042
1119
  dragFrom.current = null;
@@ -1092,7 +1169,7 @@ function frozenCellStyle(viewRow, viewCol) {
1092
1169
  background: "var(--background, #fff)"
1093
1170
  };
1094
1171
  }
1095
- var coordKey = (cell) => cell ? `${(0, import_spreadsheet7.indexToColName)(cell.col)}${cell.row + 1}` : "";
1172
+ var coordKey = (cell) => cell ? `${(0, import_spreadsheet8.indexToColName)(cell.col)}${cell.row + 1}` : "";
1096
1173
  function spillBorderStyle(range, row, col) {
1097
1174
  const line = "1px solid color-mix(in srgb, var(--primary, #6366f1) 60%, transparent)";
1098
1175
  return {
@@ -1107,8 +1184,8 @@ function spillBorderStyle(range, row, col) {
1107
1184
  };
1108
1185
  }
1109
1186
  function CellText({ cell, conditional }) {
1110
- const shown = (0, import_spreadsheet7.formatCellForDisplay)(cell);
1111
- const color = conditional?.color ?? (shown.color ? (0, import_spreadsheet7.numberFormatColorToCss)(shown.color) : void 0);
1187
+ const shown = (0, import_spreadsheet8.formatCellForDisplay)(cell);
1188
+ const color = conditional?.color ?? (shown.color ? (0, import_spreadsheet8.numberFormatColorToCss)(shown.color) : void 0);
1112
1189
  const decorated = !!conditional?.dataBar || !!conditional?.icon;
1113
1190
  const text = /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1114
1191
  "span",
@@ -1126,9 +1203,9 @@ function CellText({ cell, conditional }) {
1126
1203
  }
1127
1204
  );
1128
1205
  if (!conditional || !decorated) return text;
1129
- const icon = conditional.icon ? (0, import_spreadsheet7.getConditionalFormatIcon)(conditional.icon.set, conditional.icon.index) : null;
1206
+ const icon = conditional.icon ? (0, import_spreadsheet8.getConditionalFormatIcon)(conditional.icon.set, conditional.icon.index) : null;
1130
1207
  return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
1131
- conditional.dataBar && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { "aria-hidden": "true", className: "spreadsheet-data-bar", style: (0, import_spreadsheet7.getDataBarCss)(conditional.dataBar) }),
1208
+ conditional.dataBar && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { "aria-hidden": "true", className: "spreadsheet-data-bar", style: (0, import_spreadsheet8.getDataBarCss)(conditional.dataBar) }),
1132
1209
  icon ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { className: "flex items-center gap-1 min-w-0", style: { position: "relative" }, children: [
1133
1210
  /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "spreadsheet-cf-icon shrink-0", role: "img", "aria-label": icon.label, "data-icon": conditional.icon.id, style: { color: icon.color }, children: icon.glyph }),
1134
1211
  text
@@ -1142,65 +1219,94 @@ var SpreadsheetEditor = ({
1142
1219
  onAddColumnClick,
1143
1220
  onColumnHeaderClick,
1144
1221
  onColumnResize,
1145
- showSheetTabs = false
1222
+ showSheetTabs = false,
1223
+ virtualize = "auto"
1146
1224
  }) => {
1147
1225
  const defaultState = useSpreadsheetEditor();
1148
1226
  const state = externalState || defaultState;
1149
- const gridRef = (0, import_react8.useRef)(null);
1150
- const formulaBarRef = (0, import_react8.useRef)(null);
1151
- const cellInputRef = (0, import_react8.useRef)(null);
1152
- const [resizingColId, setResizingColId] = (0, import_react8.useState)(null);
1153
- const [hoveredColId, setHoveredColId] = (0, import_react8.useState)(null);
1154
- const [resizeStartX, setResizeStartX] = (0, import_react8.useState)(0);
1155
- const [resizeStartWidth, setResizeStartWidth] = (0, import_react8.useState)(0);
1227
+ const gridRef = (0, import_react10.useRef)(null);
1228
+ const scrollRef = (0, import_react10.useRef)(null);
1229
+ const formulaBarRef = (0, import_react10.useRef)(null);
1230
+ const cellInputRef = (0, import_react10.useRef)(null);
1231
+ const [resizingColId, setResizingColId] = (0, import_react10.useState)(null);
1232
+ const [hoveredColId, setHoveredColId] = (0, import_react10.useState)(null);
1233
+ const [resizeStartX, setResizeStartX] = (0, import_react10.useState)(0);
1234
+ const [resizeStartWidth, setResizeStartWidth] = (0, import_react10.useState)(0);
1156
1235
  const view = state.viewModel;
1236
+ const { window: viewWindow, onScroll: handleGridScroll } = useSpreadsheetViewport(scrollRef, view, {
1237
+ virtualize,
1238
+ merges: state.document.table?.merges,
1239
+ activeCell: state.activeCell
1240
+ });
1241
+ const columnSlots = (0, import_react10.useMemo)(() => {
1242
+ const col = (viewCol) => ({ kind: "col", viewCol });
1243
+ if (!viewWindow.virtual) return view.columns.map(col);
1244
+ const slots = view.columns.slice(0, viewWindow.frozenColumns).map(col);
1245
+ if (viewWindow.leftSpace > 0) slots.push({ kind: "space", key: "space:left", width: viewWindow.leftSpace });
1246
+ for (let i = viewWindow.colStart; i < viewWindow.colEnd; i++) slots.push(col(view.columns[i]));
1247
+ if (viewWindow.rightSpace > 0) slots.push({ kind: "space", key: "space:right", width: viewWindow.rightSpace });
1248
+ return slots;
1249
+ }, [view, viewWindow]);
1250
+ const renderedColumns = (0, import_react10.useMemo)(
1251
+ () => columnSlots.flatMap((slot) => slot.kind === "col" ? [slot.viewCol] : []),
1252
+ [columnSlots]
1253
+ );
1254
+ const rowSlots = (0, import_react10.useMemo)(() => {
1255
+ const row = (viewRow) => ({ kind: "row", viewRow });
1256
+ if (!viewWindow.virtual) return view.rows.map(row);
1257
+ const slots = view.rows.slice(0, viewWindow.frozenRows).map(row);
1258
+ if (viewWindow.topSpace > 0) slots.push({ kind: "space", key: "space:top", height: viewWindow.topSpace });
1259
+ for (let i = viewWindow.rowStart; i < viewWindow.rowEnd; i++) slots.push(row(view.rows[i]));
1260
+ if (viewWindow.bottomSpace > 0) slots.push({ kind: "space", key: "space:bottom", height: viewWindow.bottomSpace });
1261
+ return slots;
1262
+ }, [view, viewWindow]);
1157
1263
  const { copyShortcutFallback } = useSpreadsheetClipboard(gridRef, state, readOnly);
1158
1264
  const { fillTarget, startFill, extendFill } = useFillHandle(state);
1159
- const [menu, setMenu] = (0, import_react8.useState)(null);
1160
- const [panel, setPanel] = (0, import_react8.useState)(null);
1161
- const [listMenu, setListMenu] = (0, import_react8.useState)(null);
1265
+ const [menu, setMenu] = (0, import_react10.useState)(null);
1266
+ const [panel, setPanel] = (0, import_react10.useState)(null);
1267
+ const [listMenu, setListMenu] = (0, import_react10.useState)(null);
1162
1268
  const overlay = state.conditionalFormatOverlay;
1163
1269
  const filter = state.document.table?.filter;
1164
- const filteredColIds = (0, import_react8.useMemo)(
1270
+ const filteredColIds = (0, import_react10.useMemo)(
1165
1271
  () => new Set(filter?.enabled ? filter.rules.map((r) => r.colId) : []),
1166
1272
  [filter]
1167
1273
  );
1168
- const handleCellContextMenu = (0, import_react8.useCallback)((rIdx, cIdx, e) => {
1274
+ const handleCellContextMenu = (0, import_react10.useCallback)((rIdx, cIdx, e) => {
1169
1275
  if (readOnly) return;
1170
1276
  e.preventDefault();
1171
1277
  if (state.editingCell) state.commitEditing();
1172
- if (!state.selectedRange || !(0, import_spreadsheet7.rangeContains)(state.selectedRange, rIdx, cIdx)) {
1278
+ if (!state.selectedRange || !(0, import_spreadsheet8.rangeContains)(state.selectedRange, rIdx, cIdx)) {
1173
1279
  state.selectCell(rIdx, cIdx);
1174
1280
  }
1175
- setMenu({ x: e.clientX, y: e.clientY, items: (0, import_spreadsheet7.getSpreadsheetMenuItems)(state.controller, { row: rIdx, col: cIdx }) });
1281
+ setMenu({ x: e.clientX, y: e.clientY, items: (0, import_spreadsheet8.getSpreadsheetMenuItems)(state.controller, { row: rIdx, col: cIdx }) });
1176
1282
  }, [readOnly, state]);
1177
- const nameSuggestions = (0, import_react8.useMemo)(
1283
+ const nameSuggestions = (0, import_react10.useMemo)(
1178
1284
  () => state.controller.getNameSuggestions(),
1179
1285
  // eslint-disable-next-line react-hooks/exhaustive-deps
1180
1286
  [state.controller, state.document]
1181
1287
  );
1182
- const activeRawValue = (0, import_react8.useMemo)(() => {
1288
+ const activeRawValue = (0, import_react10.useMemo)(() => {
1183
1289
  if (!state.activeCell) return "";
1184
1290
  const row = state.document.rows[state.activeCell.row];
1185
1291
  const col = state.document.columns[state.activeCell.col];
1186
1292
  if (!row || !col) return "";
1187
1293
  return state.getCell(row.id, col.id).raw;
1188
1294
  }, [state.activeCell, state.document]);
1189
- const activeSpill = (0, import_react8.useMemo)(
1295
+ const activeSpill = (0, import_react10.useMemo)(
1190
1296
  () => state.activeCell ? state.controller.getSpillAt(state.activeCell.row, state.activeCell.col) : null,
1191
1297
  // eslint-disable-next-line react-hooks/exhaustive-deps
1192
1298
  [state.controller, state.activeCell, state.document]
1193
1299
  );
1194
1300
  const spillFormula = activeSpill && !activeRawValue && activeSpill.key !== coordKey(state.activeCell) ? activeSpill.formula : "";
1195
- const coordLabel = (0, import_react8.useMemo)(() => {
1301
+ const coordLabel = (0, import_react10.useMemo)(() => {
1196
1302
  if (!state.activeCell) return "--";
1197
- const colName = (0, import_spreadsheet7.indexToColName)(state.activeCell.col);
1303
+ const colName = (0, import_spreadsheet8.indexToColName)(state.activeCell.col);
1198
1304
  return `${colName}${state.activeCell.row + 1}`;
1199
1305
  }, [state.activeCell]);
1200
- const [formulaDraft, setFormulaDraft] = (0, import_react8.useState)(null);
1306
+ const [formulaDraft, setFormulaDraft] = (0, import_react10.useState)(null);
1201
1307
  const activeColumn = state.activeCell ? state.document.columns[state.activeCell.col] : void 0;
1202
1308
  const formulaBarReadOnly = readOnly || !state.activeCell || !!activeColumn?.readOnly;
1203
- (0, import_react8.useEffect)(() => {
1309
+ (0, import_react10.useEffect)(() => {
1204
1310
  setFormulaDraft(null);
1205
1311
  }, [state.activeCell?.row, state.activeCell?.col]);
1206
1312
  const commitFormulaBar = () => {
@@ -1216,19 +1322,19 @@ var SpreadsheetEditor = ({
1216
1322
  }
1217
1323
  setFormulaDraft(null);
1218
1324
  };
1219
- const handleCellClick = (0, import_react8.useCallback)((rIdx, cIdx, e) => {
1325
+ const handleCellClick = (0, import_react10.useCallback)((rIdx, cIdx, e) => {
1220
1326
  if (state.editingCell && (state.editingCell.row !== rIdx || state.editingCell.col !== cIdx)) {
1221
1327
  state.commitEditing();
1222
1328
  }
1223
1329
  state.selectCell(rIdx, cIdx, e.shiftKey);
1224
1330
  }, [state]);
1225
- const handleCellDblClick = (0, import_react8.useCallback)((rIdx, cIdx) => {
1331
+ const handleCellDblClick = (0, import_react10.useCallback)((rIdx, cIdx) => {
1226
1332
  if (readOnly) return;
1227
1333
  const col = state.document.columns[cIdx];
1228
1334
  if (col?.readOnly) return;
1229
1335
  state.startEditing(rIdx, cIdx);
1230
1336
  }, [readOnly, state]);
1231
- const handleKeyDown = (0, import_react8.useCallback)((e) => {
1337
+ const handleKeyDown = (0, import_react10.useCallback)((e) => {
1232
1338
  if (state.editingCell) {
1233
1339
  if (e.key === "Enter") {
1234
1340
  e.preventDefault();
@@ -1300,12 +1406,12 @@ var SpreadsheetEditor = ({
1300
1406
  }
1301
1407
  }
1302
1408
  }, [readOnly, state, copyShortcutFallback]);
1303
- const activeListValues = (0, import_react8.useMemo)(
1409
+ const activeListValues = (0, import_react10.useMemo)(
1304
1410
  () => state.activeCell && !readOnly ? state.controller.getValidationListValues(state.activeCell.row, state.activeCell.col) : null,
1305
1411
  // eslint-disable-next-line react-hooks/exhaustive-deps
1306
1412
  [state.controller, state.activeCell, state.document, readOnly]
1307
1413
  );
1308
- const activeRule = (0, import_react8.useMemo)(
1414
+ const activeRule = (0, import_react10.useMemo)(
1309
1415
  () => state.activeCell ? state.controller.getDataValidationAt(state.activeCell.row, state.activeCell.col) : void 0,
1310
1416
  // eslint-disable-next-line react-hooks/exhaustive-deps
1311
1417
  [state.controller, state.activeCell, state.document]
@@ -1319,7 +1425,7 @@ var SpreadsheetEditor = ({
1319
1425
  const rect = td?.getBoundingClientRect();
1320
1426
  setListMenu({ x: rect ? rect.left : 0, y: rect ? rect.bottom : 0, row, col, values });
1321
1427
  }
1322
- (0, import_react8.useEffect)(() => {
1428
+ (0, import_react10.useEffect)(() => {
1323
1429
  if (!listMenu) return;
1324
1430
  const close = (e) => {
1325
1431
  if (!e.target?.closest?.('[aria-label="Allowed values"], .spreadsheet-list-arrow')) setListMenu(null);
@@ -1342,11 +1448,11 @@ var SpreadsheetEditor = ({
1342
1448
  else gridRef.current?.focus();
1343
1449
  });
1344
1450
  };
1345
- const stateRef = (0, import_react8.useRef)(state);
1451
+ const stateRef = (0, import_react10.useRef)(state);
1346
1452
  stateRef.current = state;
1347
- const onColumnResizeRef = (0, import_react8.useRef)(onColumnResize);
1453
+ const onColumnResizeRef = (0, import_react10.useRef)(onColumnResize);
1348
1454
  onColumnResizeRef.current = onColumnResize;
1349
- (0, import_react8.useEffect)(() => {
1455
+ (0, import_react10.useEffect)(() => {
1350
1456
  if (!resizingColId) return;
1351
1457
  if (typeof document !== "undefined") {
1352
1458
  document.body.style.cursor = "col-resize";
@@ -1397,7 +1503,7 @@ var SpreadsheetEditor = ({
1397
1503
  window.removeEventListener("mouseup", handleMouseUp);
1398
1504
  };
1399
1505
  }, [resizingColId, resizeStartX, resizeStartWidth]);
1400
- const measureElementContentWidth = (0, import_react8.useCallback)((el, container) => {
1506
+ const measureElementContentWidth = (0, import_react10.useCallback)((el, container) => {
1401
1507
  if (typeof document === "undefined") return 0;
1402
1508
  let maxW = el.scrollWidth || 0;
1403
1509
  const firstChild = el.firstElementChild;
@@ -1445,7 +1551,7 @@ var SpreadsheetEditor = ({
1445
1551
  }
1446
1552
  return maxW;
1447
1553
  }, []);
1448
- const autoFitColumn = (0, import_react8.useCallback)((colId, colIndex) => {
1554
+ const autoFitColumn = (0, import_react10.useCallback)((colId, colIndex) => {
1449
1555
  const col = state.document.columns.find((c) => c.id === colId);
1450
1556
  if (!col) return;
1451
1557
  let calculatedWidth = 0;
@@ -1481,12 +1587,12 @@ var SpreadsheetEditor = ({
1481
1587
  onColumnResize(updatedCol.id, updatedCol.width || 130);
1482
1588
  }
1483
1589
  }, [state, measureElementContentWidth, onColumnResize]);
1484
- const handleResizeDblClick = (0, import_react8.useCallback)((colId, colIndex, e) => {
1590
+ const handleResizeDblClick = (0, import_react10.useCallback)((colId, colIndex, e) => {
1485
1591
  e.preventDefault();
1486
1592
  e.stopPropagation();
1487
1593
  autoFitColumn(colId, colIndex);
1488
1594
  }, [autoFitColumn]);
1489
- const handleHeaderDblClick = (0, import_react8.useCallback)((colId, colIndex, e) => {
1595
+ const handleHeaderDblClick = (0, import_react10.useCallback)((colId, colIndex, e) => {
1490
1596
  const target = e.currentTarget;
1491
1597
  if (target) {
1492
1598
  const rect = target.getBoundingClientRect();
@@ -1571,10 +1677,19 @@ var SpreadsheetEditor = ({
1571
1677
  inputMessage.inputTitle && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "mr-1 font-semibold text-foreground", children: inputMessage.inputTitle }),
1572
1678
  inputMessage.inputMessage
1573
1679
  ] }),
1574
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "relative flex-1 overflow-auto", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("table", { className: "border-collapse table-fixed w-max min-w-full", children: [
1680
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { ref: scrollRef, className: "relative flex-1 overflow-auto", onScroll: handleGridScroll, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("table", { className: "border-separate border-spacing-0 table-fixed w-max min-w-full [&>*>tr:not([data-spacer])>*]:border-b [&>*>tr>*]:border-border", children: [
1575
1681
  /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("tr", { className: "h-7 bg-muted sticky top-0 z-20 border-b border-border shadow-xs", children: [
1576
1682
  /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("th", { className: "w-12 min-w-[3rem] sticky left-0 z-30 bg-muted border-r border-border text-center text-[10px] text-muted-foreground font-medium", children: "#" }),
1577
- view.columns.map(({ column: col, index: cIdx, frozen, stickyLeft }) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
1683
+ columnSlots.map((slot) => slot.kind === "space" ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1684
+ "th",
1685
+ {
1686
+ "aria-hidden": "true",
1687
+ "data-spacer": "",
1688
+ className: "p-0",
1689
+ style: { width: slot.width, minWidth: slot.width, maxWidth: slot.width, padding: 0 }
1690
+ },
1691
+ slot.key
1692
+ ) : (({ column: col, index: cIdx, frozen, stickyLeft }) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
1578
1693
  "th",
1579
1694
  {
1580
1695
  "data-col": cIdx,
@@ -1633,7 +1748,7 @@ var SpreadsheetEditor = ({
1633
1748
  ]
1634
1749
  },
1635
1750
  col.id
1636
- )),
1751
+ ))(slot.viewCol)),
1637
1752
  onAddColumnClick && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1638
1753
  "th",
1639
1754
  {
@@ -1644,13 +1759,21 @@ var SpreadsheetEditor = ({
1644
1759
  }
1645
1760
  )
1646
1761
  ] }) }),
1647
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("tbody", { children: view.rows.map((viewRow) => {
1762
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("tbody", { children: rowSlots.map((rowSlot) => {
1763
+ if (rowSlot.kind === "space") {
1764
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("tr", { "aria-hidden": "true", "data-spacer": "", style: { height: rowSlot.height }, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("td", { colSpan: columnSlots.length + 2, style: { padding: 0, border: 0 } }) }, rowSlot.key);
1765
+ }
1766
+ const viewRow = rowSlot.viewRow;
1648
1767
  if (viewRow.kind === "group") {
1649
1768
  return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1650
1769
  SpreadsheetGroupRow,
1651
1770
  {
1652
1771
  group: viewRow.group,
1653
- columns: view.columns,
1772
+ columns: renderedColumns,
1773
+ labelColumns: view.columns,
1774
+ leadingColumns: viewWindow.virtual ? viewWindow.frozenColumns : void 0,
1775
+ leftSpace: viewWindow.leftSpace,
1776
+ rightSpace: viewWindow.rightSpace,
1654
1777
  groupColId: state.document.table?.grouping?.colId ?? "",
1655
1778
  onToggle: state.toggleGroupCollapsed,
1656
1779
  trailingCell: !!onAddColumnClick
@@ -1659,7 +1782,7 @@ var SpreadsheetEditor = ({
1659
1782
  );
1660
1783
  }
1661
1784
  const displayRowIndex = viewRow.index;
1662
- const selection = state.selectedRange ? (0, import_spreadsheet7.normalizeRange)(state.selectedRange) : null;
1785
+ const selection = state.selectedRange ? (0, import_spreadsheet8.normalizeRange)(state.selectedRange) : null;
1663
1786
  return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
1664
1787
  "tr",
1665
1788
  {
@@ -1675,7 +1798,9 @@ var SpreadsheetEditor = ({
1675
1798
  children: displayRowIndex + 1
1676
1799
  }
1677
1800
  ),
1678
- view.columns.map((viewCol) => {
1801
+ columnSlots.map((slot) => {
1802
+ if (slot.kind === "space") return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("td", { "aria-hidden": "true", "data-spacer": "", style: { padding: 0 } }, slot.key);
1803
+ const viewCol = slot.viewCol;
1679
1804
  const span = view.getCellSpan(displayRowIndex, viewCol.index);
1680
1805
  if (!span) return null;
1681
1806
  const rIdx = span.source.row;
@@ -1687,11 +1812,11 @@ var SpreadsheetEditor = ({
1687
1812
  const active = isActiveCell(rIdx, cIdx);
1688
1813
  const isEditing = state.editingCell?.row === rIdx && state.editingCell?.col === cIdx;
1689
1814
  const conditional = overlay.get(rIdx, cIdx);
1690
- const conditionalCss = (0, import_spreadsheet7.getConditionalFormatCss)(conditional);
1815
+ const conditionalCss = (0, import_spreadsheet8.getConditionalFormatCss)(conditional);
1691
1816
  const circled = state.controller.isInvalidDataCircled(rIdx, cIdx);
1692
1817
  const showListArrow = active && !isEditing && !!activeListValues;
1693
- const inFillPreview = !!fillTarget && !selected && (0, import_spreadsheet7.rangeContains)(fillTarget, displayRowIndex, viewCol.index);
1694
- const showFillHandle = !readOnly && !isEditing && !!selection && (span.merge ? (0, import_spreadsheet7.rangeContains)(span.merge, selection.endRow, selection.endCol) : selection.endRow === rIdx && selection.endCol === cIdx);
1818
+ const inFillPreview = !!fillTarget && !selected && (0, import_spreadsheet8.rangeContains)(fillTarget, displayRowIndex, viewCol.index);
1819
+ const showFillHandle = !readOnly && !isEditing && !!selection && (span.merge ? (0, import_spreadsheet8.rangeContains)(span.merge, selection.endRow, selection.endCol) : selection.endRow === rIdx && selection.endCol === cIdx);
1695
1820
  return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
1696
1821
  "td",
1697
1822
  {
@@ -1760,7 +1885,7 @@ var SpreadsheetEditor = ({
1760
1885
  children: "\u25BE"
1761
1886
  }
1762
1887
  ),
1763
- activeSpill && (0, import_spreadsheet7.rangeContains)(activeSpill.range, rIdx, cIdx) && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { "aria-hidden": "true", className: "spreadsheet-spill-border", style: spillBorderStyle(activeSpill.range, rIdx, cIdx) }),
1888
+ activeSpill && (0, import_spreadsheet8.rangeContains)(activeSpill.range, rIdx, cIdx) && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { "aria-hidden": "true", className: "spreadsheet-spill-border", style: spillBorderStyle(activeSpill.range, rIdx, cIdx) }),
1764
1889
  showFillHandle && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1765
1890
  "div",
1766
1891
  {
@@ -1858,19 +1983,19 @@ var SpreadsheetEditor = ({
1858
1983
  };
1859
1984
 
1860
1985
  // src/spreadsheet/NameManager.tsx
1861
- var import_react9 = require("react");
1862
- var import_spreadsheet8 = require("@pixerate/editor/spreadsheet");
1986
+ var import_react11 = require("react");
1987
+ var import_spreadsheet9 = require("@pixerate/editor/spreadsheet");
1863
1988
  var import_jsx_runtime8 = require("react/jsx-runtime");
1864
1989
  var EMPTY_DRAFT = { original: null, name: "", refersTo: "=", scope: "", comment: "" };
1865
1990
  var NameManager = ({ state, readOnly = false, onClose, className = "" }) => {
1866
1991
  const { controller, sheets } = state;
1867
- const rows = (0, import_react9.useMemo)(
1868
- () => (0, import_spreadsheet8.getNameManagerRows)(controller),
1992
+ const rows = (0, import_react11.useMemo)(
1993
+ () => (0, import_spreadsheet9.getNameManagerRows)(controller),
1869
1994
  // eslint-disable-next-line react-hooks/exhaustive-deps
1870
1995
  [controller, state.document, state.names]
1871
1996
  );
1872
- const [draft, setDraft] = (0, import_react9.useState)(EMPTY_DRAFT);
1873
- const [error, setError] = (0, import_react9.useState)(null);
1997
+ const [draft, setDraft] = (0, import_react11.useState)(EMPTY_DRAFT);
1998
+ const [error, setError] = (0, import_react11.useState)(null);
1874
1999
  const edit = (row) => {
1875
2000
  setError(null);
1876
2001
  setDraft({
@@ -1888,7 +2013,7 @@ var NameManager = ({ state, readOnly = false, onClose, className = "" }) => {
1888
2013
  const invalid = controller.validateDefinedName(draft.name.trim());
1889
2014
  if (invalid) throw new Error(invalid);
1890
2015
  try {
1891
- (0, import_spreadsheet8.parseFormula)(draft.refersTo.trim().startsWith("=") ? draft.refersTo.trim() : `=${draft.refersTo.trim()}`);
2016
+ (0, import_spreadsheet9.parseFormula)(draft.refersTo.trim().startsWith("=") ? draft.refersTo.trim() : `=${draft.refersTo.trim()}`);
1892
2017
  } catch (err) {
1893
2018
  throw new Error(`There's a problem with this formula: ${err?.message ?? draft.refersTo}`);
1894
2019
  }
@@ -2024,6 +2149,7 @@ var NameManager = ({ state, readOnly = false, onClose, className = "" }) => {
2024
2149
  SpreadsheetValidationDialog,
2025
2150
  useFillHandle,
2026
2151
  useSpreadsheetClipboard,
2027
- useSpreadsheetEditor
2152
+ useSpreadsheetEditor,
2153
+ useSpreadsheetViewport
2028
2154
  });
2029
2155
  //# sourceMappingURL=index.cjs.map