Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

react-konva-grid

Package Overview
Dependencies
Maintainers
1
Versions
146
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

react-konva-grid - npm Package Compare versions

Comparing version 2.6.3 to 2.6.4

16

dist/Grid.d.ts

@@ -51,2 +51,6 @@ import React, { Key } from "react";

/**
* Currently active cell
*/
activeCell?: CellInterface;
/**
* Background of selection

@@ -66,3 +70,3 @@ */

*/
selections?: AreaProps[];
selections?: SelectionArea[];
/**

@@ -136,2 +140,6 @@ * Array of merged cells

};
export declare type OptionalScrollCoords = {
scrollTop?: number;
scrollLeft?: number;
};
export interface ScrollState extends ScrollCoords {

@@ -147,2 +155,6 @@ isScrolling: boolean;

export declare type ItemSizer = (index: number) => number;
export interface SelectionArea {
bounds: AreaProps;
inProgress?: boolean;
}
export interface AreaProps {

@@ -203,3 +215,3 @@ top: number;

getCellOffsetFromCoords: (coords: CellInterface) => CellPosition;
scrollToItem: (coords: CellInterface) => void;
scrollToItem: (coords: OptionalCellInterface) => void;
focus: () => void;

@@ -206,0 +218,0 @@ resizeColumns: (indexes: number[]) => void;

175

dist/Grid.js

@@ -53,3 +53,3 @@ "use strict";

const defaultSelectionRenderer = (props) => {
return utils_1.createBox(Object.assign(Object.assign({}, props), { strokeWidth: 2, strokeBoxWidth: 0 }));
return utils_1.createBox(Object.assign({ strokeWidth: 1, strokeBoxWidth: 0 }, props));
};

@@ -62,3 +62,3 @@ const RESET_SCROLL_EVENTS_DEBOUNCE_INTERVAL = 150;

const Grid = react_1.memo(react_1.forwardRef((props, forwardedRef) => {
const { width: containerWidth = 800, height: containerHeight = 600, estimatedColumnWidth, estimatedRowHeight, rowHeight = defaultRowHeight, columnWidth = defaultColumnWidth, rowCount = 0, columnCount = 0, scrollbarSize = 13, onScroll, showScrollbar = true, selectionBackgroundColor = "rgb(14, 101, 235, 0.1)", selectionBorderColor = "#1a73e8", selectionStrokeWidth = 2, selections = [], frozenRows = 0, frozenColumns = 0, itemRenderer = Cell_1.CellRenderer, mergedCells = [], snap = false, scrollThrottleTimeout = 100, onViewChange, selectionRenderer = defaultSelectionRenderer, onBeforeRenderRow, showFrozenShadow = true, shadowSettings = defaultShadowSettings, borderStyles = [], children, stageProps } = props, rest = __rest(props, ["width", "height", "estimatedColumnWidth", "estimatedRowHeight", "rowHeight", "columnWidth", "rowCount", "columnCount", "scrollbarSize", "onScroll", "showScrollbar", "selectionBackgroundColor", "selectionBorderColor", "selectionStrokeWidth", "selections", "frozenRows", "frozenColumns", "itemRenderer", "mergedCells", "snap", "scrollThrottleTimeout", "onViewChange", "selectionRenderer", "onBeforeRenderRow", "showFrozenShadow", "shadowSettings", "borderStyles", "children", "stageProps"]);
const { width: containerWidth = 800, height: containerHeight = 600, estimatedColumnWidth, estimatedRowHeight, rowHeight = defaultRowHeight, columnWidth = defaultColumnWidth, rowCount = 0, columnCount = 0, scrollbarSize = 13, onScroll, showScrollbar = true, selectionBackgroundColor = "rgb(14, 101, 235, 0.1)", selectionBorderColor = "#1a73e8", selectionStrokeWidth = 2, activeCell, selections = [], frozenRows = 0, frozenColumns = 0, itemRenderer = Cell_1.CellRenderer, mergedCells = [], snap = false, scrollThrottleTimeout = 100, onViewChange, selectionRenderer = defaultSelectionRenderer, onBeforeRenderRow, showFrozenShadow = true, shadowSettings = defaultShadowSettings, borderStyles = [], children, stageProps } = props, rest = __rest(props, ["width", "height", "estimatedColumnWidth", "estimatedRowHeight", "rowHeight", "columnWidth", "rowCount", "columnCount", "scrollbarSize", "onScroll", "showScrollbar", "selectionBackgroundColor", "selectionBorderColor", "selectionStrokeWidth", "activeCell", "selections", "frozenRows", "frozenColumns", "itemRenderer", "mergedCells", "snap", "scrollThrottleTimeout", "onViewChange", "selectionRenderer", "onBeforeRenderRow", "showFrozenShadow", "shadowSettings", "borderStyles", "children", "stageProps"]);
tiny_invariant_1.default(!(children && typeof children !== "function"), "Children should be a function");

@@ -303,5 +303,5 @@ /* Expose some methods in ref */

if (showScrollbar) {
if (horizontalScrollRef.current)
if (horizontalScrollRef.current && scrollLeft !== void 0)
horizontalScrollRef.current.scrollLeft = scrollLeft;
if (verticalScrollRef.current)
if (verticalScrollRef.current && scrollTop !== void 0)
verticalScrollRef.current.scrollTop = scrollTop;

@@ -322,15 +322,17 @@ }

});
const newScrollLeft = helpers_1.getOffsetForColumnAndAlignment({
index: columnIndex,
containerHeight,
containerWidth,
columnCount,
columnWidth,
rowCount,
rowHeight,
scrollOffset: scrollLeft,
instanceProps: instanceProps.current,
scrollbarSize,
frozenOffset: frozenColumnOffset,
});
const newScrollLeft = columnIndex
? helpers_1.getOffsetForColumnAndAlignment({
index: columnIndex,
containerHeight,
containerWidth,
columnCount,
columnWidth,
rowCount,
rowHeight,
scrollOffset: scrollLeft,
instanceProps: instanceProps.current,
scrollbarSize,
frozenOffset: frozenColumnOffset,
})
: void 0;
const frozenRowOffset = helpers_1.getRowOffset({

@@ -342,15 +344,17 @@ index: frozenRows,

});
const newScrollTop = helpers_1.getOffsetForRowAndAlignment({
index: rowIndex,
containerHeight,
containerWidth,
columnCount,
columnWidth,
rowCount,
rowHeight,
scrollOffset: scrollTop,
instanceProps: instanceProps.current,
scrollbarSize,
frozenOffset: frozenRowOffset,
});
const newScrollTop = rowIndex
? helpers_1.getOffsetForRowAndAlignment({
index: rowIndex,
containerHeight,
containerWidth,
columnCount,
columnWidth,
rowCount,
rowHeight,
scrollOffset: scrollTop,
instanceProps: instanceProps.current,
scrollbarSize,
frozenOffset: frozenRowOffset,
})
: void 0;
scrollTo({

@@ -683,2 +687,47 @@ scrollLeft: newScrollLeft,

}
const activeCellSelection = [];
if (activeCell) {
const { rowIndex, columnIndex } = activeCell;
const bounds = getCellBounds(activeCell);
const { top, left, right, bottom } = bounds;
const actualBottom = Math.min(rowStopIndex, bottom);
const actualRight = Math.min(columnStopIndex, right);
const y = helpers_1.getRowOffset({
index: top,
rowHeight,
columnWidth,
instanceProps: instanceProps.current,
});
const height = helpers_1.getRowOffset({
index: actualBottom,
rowHeight,
columnWidth,
instanceProps: instanceProps.current,
}) -
y +
helpers_1.getRowHeight(actualBottom, instanceProps.current);
const x = helpers_1.getColumnOffset({
index: left,
rowHeight,
columnWidth,
instanceProps: instanceProps.current,
});
const width = helpers_1.getColumnOffset({
index: actualRight,
rowHeight,
columnWidth,
instanceProps: instanceProps.current,
}) -
x +
helpers_1.getColumnWidth(actualRight, instanceProps.current);
activeCellSelection.push(selectionRenderer({
stroke: selectionBorderColor,
strokeWidth: 2,
fill: selectionBackgroundColor,
x: x,
y: y,
width: width,
height: height,
}));
}
/**

@@ -695,3 +744,4 @@ * Convert selections to area

for (let i = 0; i < selections.length; i++) {
const { top, left, right, bottom } = selections[i];
const { bounds, inProgress } = selections[i];
const { top, left, right, bottom } = bounds;
const selectionBounds = { x: 0, y: 0, width: 0, height: 0 };

@@ -703,2 +753,6 @@ const actualBottom = Math.min(rowStopIndex, bottom);

const isIntersectionFrozen = top < frozenRows && left < frozenColumns;
const styles = {
stroke: inProgress ? "transparent" : selectionBorderColor,
fill: selectionBackgroundColor,
};
selectionBounds.y = helpers_1.getRowOffset({

@@ -741,14 +795,5 @@ index: top,

}));
selectionAreasFrozenColumns.push(selectionRenderer({
key: i,
stroke: selectionBorderColor,
fill: selectionBackgroundColor,
x: selectionBounds.x,
y: selectionBounds.y,
width: frozenColumnSelectionWidth,
height: selectionBounds.height,
strokeRightWidth: frozenColumnSelectionWidth === selectionBounds.width
selectionAreasFrozenColumns.push(selectionRenderer(Object.assign(Object.assign({}, styles), { key: i, x: selectionBounds.x, y: selectionBounds.y, width: frozenColumnSelectionWidth, height: selectionBounds.height, strokeRightWidth: frozenColumnSelectionWidth === selectionBounds.width
? selectionStrokeWidth
: 0,
}));
: 0 })));
}

@@ -762,14 +807,5 @@ if (isTopBoundFrozen) {

}));
selectionAreasFrozenRows.push(selectionRenderer({
key: i,
stroke: selectionBorderColor,
fill: selectionBackgroundColor,
x: selectionBounds.x,
y: selectionBounds.y,
width: selectionBounds.width,
height: frozenRowSelectionHeight,
strokeBottomWidth: frozenRowSelectionHeight === selectionBounds.height
selectionAreasFrozenRows.push(selectionRenderer(Object.assign(Object.assign({}, styles), { key: i, x: selectionBounds.x, y: selectionBounds.y, width: selectionBounds.width, height: frozenRowSelectionHeight, strokeBottomWidth: frozenRowSelectionHeight === selectionBounds.height
? selectionStrokeWidth
: 0,
}));
: 0 })));
}

@@ -789,27 +825,9 @@ if (isIntersectionFrozen) {

}));
selectionAreasIntersection.push(selectionRenderer({
key: i,
stroke: selectionBorderColor,
fill: selectionBackgroundColor,
x: selectionBounds.x,
y: selectionBounds.y,
width: frozenIntersectionSelectionWidth,
height: frozenIntersectionSelectionHeight,
strokeBottomWidth: frozenIntersectionSelectionHeight === selectionBounds.height
selectionAreasIntersection.push(selectionRenderer(Object.assign(Object.assign({}, styles), { key: i, x: selectionBounds.x, y: selectionBounds.y, width: frozenIntersectionSelectionWidth, height: frozenIntersectionSelectionHeight, strokeBottomWidth: frozenIntersectionSelectionHeight === selectionBounds.height
? selectionStrokeWidth
: 0,
strokeRightWidth: frozenIntersectionSelectionWidth === selectionBounds.width
: 0, strokeRightWidth: frozenIntersectionSelectionWidth === selectionBounds.width
? selectionStrokeWidth
: 0,
}));
: 0 })));
}
selectionAreas.push(selectionRenderer({
key: i,
stroke: selectionBorderColor,
fill: selectionBackgroundColor,
x: selectionBounds.x,
y: selectionBounds.y,
width: selectionBounds.width,
height: selectionBounds.height,
}));
selectionAreas.push(selectionRenderer(Object.assign(Object.assign({}, styles), { key: i, x: selectionBounds.x, y: selectionBounds.y, width: selectionBounds.width, height: selectionBounds.height })));
}

@@ -883,3 +901,5 @@ /**

});
return { rowIndex, columnIndex };
/* To be compatible with merged cells */
const bounds = getCellBounds({ rowIndex, columnIndex });
return { rowIndex: bounds.top, columnIndex: bounds.left };
}, [scrollLeft, scrollTop, rowCount, columnCount]);

@@ -936,3 +956,4 @@ const borderStylesCells = react_1.useMemo(() => {

borderStylesCells,
selectionAreas),
selectionAreas,
activeCellSelection),
frozenColumnShadow,

@@ -939,0 +960,0 @@ frozenRowShadow,

import React from "react";
import { CellInterface, ScrollCoords, CellPosition, GridRef, AreaProps } from "../Grid";
import { CellInterface, ScrollCoords, CellPosition, GridRef, SelectionArea } from "../Grid";
import { KeyCodes } from "./../types";

@@ -11,4 +11,5 @@ export interface UseEditableOptions {

onSubmit?: (value: string, coords: CellInterface, nextCoords?: CellInterface) => void;
onDelete: (selections: AreaProps[]) => void;
selections: AreaProps[];
onDelete?: (activeCell: CellInterface, selections: SelectionArea[]) => void;
selections: SelectionArea[];
activeCell: CellInterface | null;
onBeforeEdit?: (coords: CellInterface) => boolean;

@@ -34,3 +35,3 @@ }

*/
declare const useEditable: ({ getEditor, gridRef, getValue, onChange, onSubmit, onCancel, onDelete, selections, onBeforeEdit, }: UseEditableOptions) => EditableResults;
declare const useEditable: ({ getEditor, gridRef, getValue, onChange, onSubmit, onCancel, onDelete, selections, activeCell, onBeforeEdit, }: UseEditableOptions) => EditableResults;
export default useEditable;

@@ -89,4 +89,4 @@ "use strict";

*/
const useEditable = ({ getEditor = getDefaultEditor, gridRef, getValue, onChange, onSubmit, onCancel, onDelete, selections = [], onBeforeEdit, }) => {
const [activeCell, setActiveCell] = react_1.useState(null);
const useEditable = ({ getEditor = getDefaultEditor, gridRef, getValue, onChange, onSubmit, onCancel, onDelete, selections = [], activeCell, onBeforeEdit, }) => {
const [isEditorShown, setShowEditor] = react_1.useState(false);
const [value, setValue] = react_1.useState("");

@@ -99,2 +99,3 @@ const [position, setPosition] = react_1.useState({

});
const currentActiveCellRef = react_1.useRef(null);
const [scrollPosition, setScrollPosition] = react_1.useState({

@@ -104,2 +105,7 @@ scrollLeft: 0,

});
const showEditor = () => setShowEditor(true);
const hideEditor = () => {
setShowEditor(false);
currentActiveCellRef.current = null;
};
const makeEditable = (coords, initialValue) => {

@@ -111,4 +117,5 @@ if (!gridRef.current)

return;
currentActiveCellRef.current = coords;
const pos = gridRef.current.getCellOffsetFromCoords(coords);
setActiveCell(coords);
showEditor();
setValue(initialValue || getValue(coords) || "");

@@ -137,10 +144,13 @@ setPosition(pos);

e.nativeEvent.ctrlKey ||
e.nativeEvent.shiftKey)
e.nativeEvent.shiftKey ||
e.nativeEvent.metaKey)
return;
/* If user has not made any selection yet */
if (!selections.length)
if (!activeCell)
return;
const { top: rowIndex, left: columnIndex } = selections[0];
const { rowIndex, columnIndex } = activeCell;
if (keyCode === types_1.KeyCodes.Delete || keyCode === types_1.KeyCodes.BackSpace) {
return onDelete(selections);
// TODO: onbefore delete
onDelete && onDelete(activeCell, selections);
return;
}

@@ -151,3 +161,3 @@ const initialValue = keyCode === types_1.KeyCodes.Enter // Enter key

makeEditable({ rowIndex, columnIndex }, initialValue);
}, [selections]);
}, [selections, activeCell]);
/* Save the value */

@@ -167,3 +177,4 @@ const handleSubmit = react_1.useCallback((sourceKey) => {

onSubmit && onSubmit(value, activeCell, nextActiveCell);
setActiveCell(null);
/* Show editor */
hideEditor();
/* Keep the focus */

@@ -180,21 +191,30 @@ gridRef.current.focus();

const handleHide = react_1.useCallback((e) => {
setActiveCell(null);
hideEditor();
onCancel && onCancel();
/* Keep the focus back in the grid */
gridRef.current.focus();
}, [activeCell]);
}, []);
const handleScroll = react_1.useCallback((scrollPos) => {
setScrollPosition(scrollPos);
}, []);
/* Update value onBlur */
const handleBlur = react_1.useCallback(() => {
if (!activeCell)
const handleBlur = react_1.useCallback((e) => {
if (!currentActiveCellRef.current)
return;
onSubmit && onSubmit(value, activeCell);
setActiveCell(null);
}, [value, activeCell]);
/**
* Event callstack
* mouseDown => sets the activeCell
* onBlur => reads the new activeCell, which is wrong.
* Thats the reason by storing the active cell in Ref internally
*/
onSubmit && onSubmit(value, currentActiveCellRef.current);
hideEditor();
}, [value]);
/* Editor */
const Editor = react_1.useMemo(() => getEditor(activeCell), [activeCell]);
const editorComponent = activeCell ? (react_1.default.createElement(Editor, { value: value, onChange: handleChange, onSubmit: handleSubmit, onBlur: handleBlur, onEscape: handleHide, position: position, scrollPosition: scrollPosition })) : null;
const editorComponent = isEditorShown ? (react_1.default.createElement(Editor, { value: value, onChange: handleChange, onSubmit: handleSubmit, onBlur: handleBlur, onEscape: handleHide, position: position, scrollPosition: scrollPosition })) : null;
return {
editorComponent,
onDoubleClick: handleDoubleClick,
onScroll: setScrollPosition,
onScroll: handleScroll,
onKeyDown: handleKeyDown,

@@ -201,0 +221,0 @@ };

import React from "react";
import { AreaProps, CellInterface, GridRef } from "./../Grid";
import { SelectionArea, CellInterface, GridRef } from "./../Grid";
export interface UseSelectionOptions {
gridRef?: React.MutableRefObject<GridRef>;
initialSelections?: AreaProps[];
initialSelections?: SelectionArea[];
columnCount?: number;

@@ -10,4 +10,6 @@ rowCount?: number;

export interface SelectionResults {
activeCell: CellInterface | null;
newSelection: (coords: CellInterface) => void;
selections: AreaProps[];
setActiveCell: (coords: CellInterface | null) => void;
selections: SelectionArea[];
onMouseDown: (e: React.MouseEvent<HTMLDivElement>) => void;

@@ -14,0 +16,0 @@ onMouseMove: (e: React.MouseEvent<HTMLDivElement>) => void;

@@ -5,2 +5,6 @@ "use strict";

const types_1 = require("./../types");
const initialActiveCell = {
rowIndex: 3,
columnIndex: 3,
};
/**

@@ -12,2 +16,3 @@ * useSelection hook to enable selection in datagrid

const { gridRef, initialSelections = [], columnCount = 0, rowCount = 0 } = options || {};
const [activeCell, setActiveCell] = react_1.useState(initialActiveCell);
const [selections, setSelections] = react_1.useState(initialSelections);

@@ -18,9 +23,10 @@ const selectionStart = react_1.useRef();

/* New selection */
const newSelection = (coords) => {
selectionStart.current = coords;
selectionEnd.current = coords;
const selection = selectionFromStartEnd(coords, coords);
if (!selection)
const newSelection = (start, end = start) => {
selectionStart.current = start;
selectionEnd.current = end;
const bounds = selectionFromStartEnd(start, end);
if (!bounds)
return;
setSelections([selection]);
setActiveCell({ rowIndex: bounds.top, columnIndex: bounds.left });
setSelections([]);
};

@@ -41,10 +47,25 @@ /* selection object from start, end */

/* Modify current selection */
const modifySelection = (coords) => {
const modifySelection = (coords, setInProgress) => {
if (!selectionStart.current)
return;
selectionEnd.current = coords;
const selection = selectionFromStartEnd(selectionStart.current, coords);
if (!selection)
const bounds = selectionFromStartEnd(selectionStart.current, coords);
if (!bounds)
return;
setSelections([selection]);
/**
* 1. Multiple selections on mousedown/mousemove
* 2. Move the activeCell to newly selection. Done by appendSelection
*/
setSelections((prevSelection) => {
const len = prevSelection.length;
if (!len) {
return [{ bounds, inProgress: setInProgress ? true : false }];
}
return prevSelection.map((sel, i) => {
if (len - 1 === i) {
return Object.assign(Object.assign({}, sel), { bounds, inProgress: setInProgress ? true : false });
}
return sel;
});
});
};

@@ -55,6 +76,7 @@ /* Adds a new selection, CMD key */

selectionEnd.current = coords;
const selection = selectionFromStartEnd(coords, coords);
if (!selection)
const bounds = selectionFromStartEnd(coords, coords);
if (!bounds)
return;
setSelections((prev) => [...prev, selection]);
setActiveCell({ rowIndex: bounds.top, columnIndex: bounds.left });
setSelections((prev) => [...prev, { bounds }]);
};

@@ -97,4 +119,10 @@ /**

const { rowIndex, columnIndex } = gridRef.current.getCellCoordsFromOffset(e.clientX, e.clientY);
modifySelection({ rowIndex, columnIndex });
}, [isSelectionMode]);
/**
* If the user is moving across the Active Cell, lets not add it to selection
*/
if ((activeCell === null || activeCell === void 0 ? void 0 : activeCell.rowIndex) === rowIndex &&
(activeCell === null || activeCell === void 0 ? void 0 : activeCell.columnIndex) === columnIndex)
return;
modifySelection({ rowIndex, columnIndex }, true);
}, [activeCell]);
/**

@@ -106,2 +134,12 @@ * Mouse up handler

isSelectionMode.current = false;
/* Update last selection */
setSelections((prevSelection) => {
const len = prevSelection.length;
return prevSelection.map((sel, i) => {
if (len - 1 === i) {
return Object.assign(Object.assign({}, sel), { inProgress: false });
}
return sel;
});
});
}, []);

@@ -113,6 +151,11 @@ /**

*/
const keyNavigate = (direction, modify) => {
if (!selectionEnd.current || !gridRef)
const keyNavigate = react_1.useCallback((direction, modify) => {
if (!selectionStart.current ||
!selectionEnd.current ||
!gridRef ||
!activeCell)
return;
var { rowIndex, columnIndex } = selectionEnd.current;
var { rowIndex, columnIndex } = modify
? selectionEnd.current
: activeCell;
const isMergedCell = gridRef === null || gridRef === void 0 ? void 0 : gridRef.current.isMergedCell({

@@ -145,2 +188,7 @@ rowIndex,

}
const scrollToCell = modify
? selectionEnd.current.rowIndex === rowIndex
? { columnIndex }
: { rowIndex }
: { rowIndex, columnIndex };
if (modify) {

@@ -153,22 +201,71 @@ modifySelection({ rowIndex, columnIndex });

/* Keep the item in view */
gridRef.current.scrollToItem({ rowIndex, columnIndex });
gridRef.current.scrollToItem(scrollToCell);
}, [activeCell]);
// ⌘A or ⌘+Shift+Space
const selectAll = () => {
selectionStart.current = { rowIndex: 0, columnIndex: 0 };
modifySelection({ rowIndex: rowCount - 1, columnIndex: columnCount - 1 });
};
// Shift+Space
const selectColumn = () => {
if (!selectionEnd.current || !selectionStart.current)
return;
selectionStart.current = {
rowIndex: 0,
columnIndex: selectionStart.current.columnIndex,
};
modifySelection({
rowIndex: rowCount - 1,
columnIndex: selectionEnd.current.columnIndex,
});
};
// Shift+Space
const selectRow = () => {
if (!selectionEnd.current || !selectionStart.current)
return;
selectionStart.current = {
rowIndex: selectionStart.current.rowIndex,
columnIndex: 0,
};
modifySelection({
rowIndex: selectionEnd.current.rowIndex,
columnIndex: columnCount - 1,
});
};
const handleKeyDown = react_1.useCallback((e) => {
const modify = e.nativeEvent.shiftKey;
const isShiftKey = e.nativeEvent.shiftKey;
const isMetaKey = e.nativeEvent.ctrlKey || e.nativeEvent.metaKey;
switch (e.nativeEvent.which) {
case types_1.KeyCodes.Right:
keyNavigate(types_1.Direction.Right, modify);
keyNavigate(types_1.Direction.Right, isShiftKey);
break;
case types_1.KeyCodes.Left:
keyNavigate(types_1.Direction.Left, modify);
keyNavigate(types_1.Direction.Left, isShiftKey);
break;
// Up
case types_1.KeyCodes.Up:
keyNavigate(types_1.Direction.Up, modify);
keyNavigate(types_1.Direction.Up, isShiftKey);
break;
case types_1.KeyCodes.Down:
keyNavigate(types_1.Direction.Down, modify);
keyNavigate(types_1.Direction.Down, isShiftKey);
break;
case types_1.KeyCodes.A:
// Select All
if (isMetaKey) {
selectAll();
}
break;
case types_1.KeyCodes.SPACE:
if (isMetaKey && isShiftKey) {
selectAll();
}
else if (isMetaKey) {
selectColumn();
}
else if (isShiftKey) {
selectRow();
}
break;
case types_1.KeyCodes.Tab:
if (modify) {
if (isShiftKey) {
keyNavigate(types_1.Direction.Left);

@@ -182,4 +279,5 @@ }

}
}, [rowCount, columnCount]);
}, [rowCount, columnCount, activeCell]);
return {
activeCell,
selections,

@@ -191,2 +289,3 @@ onMouseDown: handleMouseDown,

newSelection,
setActiveCell,
};

@@ -193,0 +292,0 @@ };

@@ -11,3 +11,5 @@ export declare enum KeyCodes {

BackSpace = 8,
Enter = 13
Enter = 13,
A = 65,
SPACE = 32
}

@@ -14,0 +16,0 @@ export declare enum Direction {

@@ -16,2 +16,4 @@ "use strict";

KeyCodes[KeyCodes["Enter"] = 13] = "Enter";
KeyCodes[KeyCodes["A"] = 65] = "A";
KeyCodes[KeyCodes["SPACE"] = 32] = "SPACE";
})(KeyCodes = exports.KeyCodes || (exports.KeyCodes = {}));

@@ -18,0 +20,0 @@ var Direction;

{
"name": "react-konva-grid",
"description": "Declarative React Canvas Grid primitive for Data table, Pivot table, Excel Worksheets",
"version": "2.6.3",
"version": "2.6.4",
"main": "dist/index.js",

@@ -6,0 +6,0 @@ "license": "MIT",

import React, { useState, useCallback, useRef } from "react";
import { AreaProps, CellInterface, GridRef } from "./../Grid";
import { SelectionArea, AreaProps, CellInterface, GridRef } from "./../Grid";
import { KeyCodes, Direction } from "./../types";

@@ -7,3 +7,3 @@

gridRef?: React.MutableRefObject<GridRef>;
initialSelections?: AreaProps[];
initialSelections?: SelectionArea[];
columnCount?: number;

@@ -14,4 +14,6 @@ rowCount?: number;

export interface SelectionResults {
activeCell: CellInterface | null;
newSelection: (coords: CellInterface) => void;
selections: AreaProps[];
setActiveCell: (coords: CellInterface | null) => void;
selections: SelectionArea[];
onMouseDown: (e: React.MouseEvent<HTMLDivElement>) => void;

@@ -23,2 +25,7 @@ onMouseMove: (e: React.MouseEvent<HTMLDivElement>) => void;

const initialActiveCell = {
rowIndex: 3,
columnIndex: 3,
};
/**

@@ -31,3 +38,8 @@ * useSelection hook to enable selection in datagrid

options || {};
const [selections, setSelections] = useState<AreaProps[]>(initialSelections);
const [activeCell, setActiveCell] = useState<CellInterface | null>(
initialActiveCell
);
const [selections, setSelections] = useState<SelectionArea[]>(
initialSelections
);
const selectionStart = useRef<CellInterface>();

@@ -38,8 +50,9 @@ const selectionEnd = useRef<CellInterface>();

/* New selection */
const newSelection = (coords: CellInterface) => {
selectionStart.current = coords;
selectionEnd.current = coords;
const selection = selectionFromStartEnd(coords, coords);
if (!selection) return;
setSelections([selection]);
const newSelection = (start: CellInterface, end: CellInterface = start) => {
selectionStart.current = start;
selectionEnd.current = end;
const bounds = selectionFromStartEnd(start, end);
if (!bounds) return;
setActiveCell({ rowIndex: bounds.top, columnIndex: bounds.left });
setSelections([]);
};

@@ -61,8 +74,28 @@

/* Modify current selection */
const modifySelection = (coords: CellInterface) => {
const modifySelection = (coords: CellInterface, setInProgress?: boolean) => {
if (!selectionStart.current) return;
selectionEnd.current = coords;
const selection = selectionFromStartEnd(selectionStart.current, coords);
if (!selection) return;
setSelections([selection]);
const bounds = selectionFromStartEnd(selectionStart.current, coords);
if (!bounds) return;
/**
* 1. Multiple selections on mousedown/mousemove
* 2. Move the activeCell to newly selection. Done by appendSelection
*/
setSelections((prevSelection) => {
const len = prevSelection.length;
if (!len) {
return [{ bounds, inProgress: setInProgress ? true : false }];
}
return prevSelection.map((sel, i) => {
if (len - 1 === i) {
return {
...sel,
bounds,
inProgress: setInProgress ? true : false,
};
}
return sel;
});
});
};

@@ -74,5 +107,6 @@

selectionEnd.current = coords;
const selection = selectionFromStartEnd(coords, coords);
if (!selection) return;
setSelections((prev) => [...prev, selection]);
const bounds = selectionFromStartEnd(coords, coords);
if (!bounds) return;
setActiveCell({ rowIndex: bounds.top, columnIndex: bounds.left });
setSelections((prev) => [...prev, { bounds }]);
};

@@ -130,5 +164,14 @@

modifySelection({ rowIndex, columnIndex });
/**
* If the user is moving across the Active Cell, lets not add it to selection
*/
if (
activeCell?.rowIndex === rowIndex &&
activeCell?.columnIndex === columnIndex
)
return;
modifySelection({ rowIndex, columnIndex }, true);
},
[isSelectionMode]
[activeCell]
);

@@ -141,2 +184,16 @@ /**

isSelectionMode.current = false;
/* Update last selection */
setSelections((prevSelection) => {
const len = prevSelection.length;
return prevSelection.map((sel, i) => {
if (len - 1 === i) {
return {
...sel,
inProgress: false,
};
}
return sel;
});
});
}, []);

@@ -149,54 +206,104 @@

*/
const keyNavigate = (direction: Direction, modify?: boolean) => {
if (!selectionEnd.current || !gridRef) return;
var { rowIndex, columnIndex } = selectionEnd.current;
const isMergedCell = gridRef?.current.isMergedCell({
rowIndex,
columnIndex,
});
const keyNavigate = useCallback(
(direction: Direction, modify?: boolean) => {
if (
!selectionStart.current ||
!selectionEnd.current ||
!gridRef ||
!activeCell
)
return;
var { rowIndex, columnIndex } = modify
? selectionEnd.current
: activeCell;
const isMergedCell = gridRef?.current.isMergedCell({
rowIndex,
columnIndex,
});
const bounds = gridRef.current.getCellBounds({ rowIndex, columnIndex });
const bounds = gridRef.current.getCellBounds({ rowIndex, columnIndex });
switch (direction) {
case Direction.Up:
if (isMergedCell) rowIndex = bounds.top;
rowIndex = Math.max(rowIndex - 1, 0);
break;
switch (direction) {
case Direction.Up:
if (isMergedCell) rowIndex = bounds.top;
rowIndex = Math.max(rowIndex - 1, 0);
break;
case Direction.Down:
if (isMergedCell) rowIndex = bounds.bottom;
rowIndex = Math.min(rowIndex + 1, rowCount - 1);
break;
case Direction.Down:
if (isMergedCell) rowIndex = bounds.bottom;
rowIndex = Math.min(rowIndex + 1, rowCount - 1);
break;
case Direction.Left:
if (isMergedCell) columnIndex = bounds.left;
columnIndex = Math.max(columnIndex - 1, 0);
break;
case Direction.Left:
if (isMergedCell) columnIndex = bounds.left;
columnIndex = Math.max(columnIndex - 1, 0);
break;
case Direction.Right:
if (isMergedCell) columnIndex = bounds.right;
columnIndex = Math.min(columnIndex + 1, columnCount - 1);
break;
}
case Direction.Right:
if (isMergedCell) columnIndex = bounds.right;
columnIndex = Math.min(columnIndex + 1, columnCount - 1);
break;
}
if (modify) {
modifySelection({ rowIndex, columnIndex });
} else {
newSelection({ rowIndex, columnIndex });
}
const scrollToCell = modify
? selectionEnd.current.rowIndex === rowIndex
? { columnIndex }
: { rowIndex }
: { rowIndex, columnIndex };
/* Keep the item in view */
gridRef.current.scrollToItem({ rowIndex, columnIndex });
if (modify) {
modifySelection({ rowIndex, columnIndex });
} else {
newSelection({ rowIndex, columnIndex });
}
/* Keep the item in view */
gridRef.current.scrollToItem(scrollToCell);
},
[activeCell]
);
// ⌘A or ⌘+Shift+Space
const selectAll = () => {
selectionStart.current = { rowIndex: 0, columnIndex: 0 };
modifySelection({ rowIndex: rowCount - 1, columnIndex: columnCount - 1 });
};
// Shift+Space
const selectColumn = () => {
if (!selectionEnd.current || !selectionStart.current) return;
selectionStart.current = {
rowIndex: 0,
columnIndex: selectionStart.current.columnIndex,
};
modifySelection({
rowIndex: rowCount - 1,
columnIndex: selectionEnd.current.columnIndex,
});
};
// Shift+Space
const selectRow = () => {
if (!selectionEnd.current || !selectionStart.current) return;
selectionStart.current = {
rowIndex: selectionStart.current.rowIndex,
columnIndex: 0,
};
modifySelection({
rowIndex: selectionEnd.current.rowIndex,
columnIndex: columnCount - 1,
});
};
const handleKeyDown = useCallback(
(e: React.KeyboardEvent) => {
const modify = e.nativeEvent.shiftKey;
const isShiftKey = e.nativeEvent.shiftKey;
const isMetaKey = e.nativeEvent.ctrlKey || e.nativeEvent.metaKey;
switch (e.nativeEvent.which) {
case KeyCodes.Right:
keyNavigate(Direction.Right, modify);
keyNavigate(Direction.Right, isShiftKey);
break;
case KeyCodes.Left:
keyNavigate(Direction.Left, modify);
keyNavigate(Direction.Left, isShiftKey);
break;

@@ -206,11 +313,28 @@

case KeyCodes.Up:
keyNavigate(Direction.Up, modify);
keyNavigate(Direction.Up, isShiftKey);
break;
case KeyCodes.Down:
keyNavigate(Direction.Down, modify);
keyNavigate(Direction.Down, isShiftKey);
break;
case KeyCodes.A:
// Select All
if (isMetaKey) {
selectAll();
}
break;
case KeyCodes.SPACE:
if (isMetaKey && isShiftKey) {
selectAll();
} else if (isMetaKey) {
selectColumn();
} else if (isShiftKey) {
selectRow();
}
break;
case KeyCodes.Tab:
if (modify) {
if (isShiftKey) {
keyNavigate(Direction.Left);

@@ -224,6 +348,7 @@ } else {

},
[rowCount, columnCount]
[rowCount, columnCount, activeCell]
);
return {
activeCell,
selections,

@@ -235,2 +360,3 @@ onMouseDown: handleMouseDown,

newSelection,
setActiveCell,
};

@@ -237,0 +363,0 @@ };

@@ -12,2 +12,4 @@ export enum KeyCodes {

Enter = 13,
A = 65,
SPACE = 32,
}

@@ -14,0 +16,0 @@

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc