react-spreadsheet
Version:
Simple, customizable yet performant spreadsheet for React
1,328 lines (1,304 loc) • 117 kB
JavaScript
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
var React = require('react');
var classNames = require('classnames');
var FormulaParser = require('fast-formula-parser');
var useContextSelector = require('use-context-selector');
function _interopNamespaceDefault(e) {
var n = Object.create(null);
if (e) {
Object.keys(e).forEach(function (k) {
if (k !== 'default') {
var d = Object.getOwnPropertyDescriptor(e, k);
Object.defineProperty(n, k, d.get ? d : {
enumerable: true,
get: function () { return e[k]; }
});
}
});
}
n.default = e;
return Object.freeze(n);
}
var React__namespace = /*#__PURE__*/_interopNamespaceDefault(React);
/******************************************************************************
Copyright (c) Microsoft Corporation.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
***************************************************************************** */
/* global Reflect, Promise */
var extendStatics = function(d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
return extendStatics(d, b);
};
function __extends(d, b) {
if (typeof b !== "function" && b !== null)
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
}
var __assign = function() {
__assign = Object.assign || function __assign(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
function __generator(thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (g && (g = 0, op[0] && (_ = 0)), _) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
}
function __values(o) {
var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
if (m) return m.call(o);
if (o && typeof o.length === "number") return {
next: function () {
if (o && i >= o.length) o = void 0;
return { value: o && o[i++], done: !o };
}
};
throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
}
function __read(o, n) {
var m = typeof Symbol === "function" && o[Symbol.iterator];
if (!m) return o;
var i = m.call(o), r, ar = [], e;
try {
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
}
catch (error) { e = { error: error }; }
finally {
try {
if (r && !r.done && (m = i["return"])) m.call(i);
}
finally { if (e) throw e.error; }
}
return ar;
}
function __spreadArray(to, from, pack) {
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
if (ar || !(i in from)) {
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
ar[i] = from[i];
}
}
return to.concat(ar || Array.prototype.slice.call(from));
}
var SET_DATA = "SET_DATA";
var SET_CREATE_FORMULA_PARSER = "SET_CREATE_FORMULA_PARSER";
var SELECT_ENTIRE_ROW = "SELECT_ENTIRE_ROW";
var SELECT_ENTIRE_COLUMN = "SELECT_ENTIRE_COLUMN";
var SELECT_ENTIRE_WORKSHEET = "SELECT_ENTIRE_WORKSHEET";
var SET_SELECTION = "SET_SELECTION";
var SELECT = "SELECT";
var ACTIVATE = "ACTIVATE";
var SET_CELL_DATA = "SET_CELL_DATA";
var SET_CELL_DIMENSIONS = "SET_CELL_DIMENSIONS";
var COPY = "COPY";
var CUT = "CUT";
var PASTE = "PASTE";
var EDIT = "EDIT";
var VIEW = "VIEW";
var CLEAR = "CLEAR";
var BLUR = "BLUR";
var KEY_PRESS = "KEY_PRESS";
var KEY_DOWN = "KEY_DOWN";
var DRAG_START = "DRAG_START";
var DRAG_END = "DRAG_END";
var COMMIT = "COMMIT";
function setData(data) {
return {
type: SET_DATA,
payload: { data: data },
};
}
function setCreateFormulaParser(createFormulaParser) {
return {
type: SET_CREATE_FORMULA_PARSER,
payload: { createFormulaParser: createFormulaParser },
};
}
function selectEntireRow(row, extend) {
return {
type: SELECT_ENTIRE_ROW,
payload: { row: row, extend: extend },
};
}
function selectEntireColumn(column, extend) {
return {
type: SELECT_ENTIRE_COLUMN,
payload: { column: column, extend: extend },
};
}
function selectEntireWorksheet() {
return { type: SELECT_ENTIRE_WORKSHEET };
}
function setSelection(selection) {
return { type: SET_SELECTION, payload: { selection: selection } };
}
function select(point) {
return {
type: SELECT,
payload: { point: point },
};
}
function activate(point) {
return {
type: ACTIVATE,
payload: { point: point },
};
}
function setCellData(active, data) {
return {
type: SET_CELL_DATA,
payload: { active: active, data: data },
};
}
function setCellDimensions(point, dimensions) {
return {
type: SET_CELL_DIMENSIONS,
payload: { point: point, dimensions: dimensions },
};
}
function paste(data) {
return {
type: PASTE,
payload: { data: data },
};
}
function keyPress(event) {
return {
type: KEY_PRESS,
payload: { event: event },
};
}
function keyDown(event) {
return {
type: KEY_DOWN,
payload: { event: event },
};
}
function dragStart() {
return { type: DRAG_START };
}
function dragEnd() {
return { type: DRAG_END };
}
function commit$1(changes) {
return {
type: COMMIT,
payload: { changes: changes },
};
}
function copy() {
return { type: COPY };
}
function cut() {
return { type: CUT };
}
function edit$1() {
return { type: EDIT };
}
function view$1() {
return { type: VIEW };
}
function blur$1() {
return { type: BLUR };
}
/**
* Creates an empty matrix with given rows and columns
* @param rows - integer, the amount of rows the matrix should have
* @param columns - integer, the amount of columns the matrix should have
* @returns an empty matrix with given rows and columns
*/
function createEmpty(rows, columns) {
var matrix = Array(rows);
for (var i = 0; i < rows; i++) {
matrix[i] = Array(columns);
}
return matrix;
}
/** Gets the value at row and column of matrix. */
function get(point, matrix) {
var columns = matrix[point.row];
if (columns === undefined) {
return undefined;
}
return columns[point.column];
}
/** Creates a slice of matrix from startPoint up to, but not including, endPoint. */
function slice(startPoint, endPoint, matrix) {
var sliced = [];
var columns = endPoint.column - startPoint.column;
for (var row = startPoint.row; row <= endPoint.row; row++) {
var slicedRow = row - startPoint.row;
sliced[slicedRow] = sliced[slicedRow] || Array(columns);
for (var column = startPoint.column; column <= endPoint.column; column++) {
sliced[slicedRow][column - startPoint.column] = get({ row: row, column: column }, matrix);
}
}
return sliced;
}
/** Sets the value at row and column of matrix. If a row doesn't exist, it's created. */
function set(point, value, matrix) {
var nextMatrix = __spreadArray([], __read(matrix), false);
// Synchronize first row length
var firstRow = matrix[0];
var nextFirstRow = firstRow ? __spreadArray([], __read(firstRow), false) : [];
if (nextFirstRow.length - 1 < point.column) {
nextFirstRow[point.column] = undefined;
nextMatrix[0] = nextFirstRow;
}
var nextRow = matrix[point.row] ? __spreadArray([], __read(matrix[point.row]), false) : [];
nextRow[point.column] = value;
nextMatrix[point.row] = nextRow;
return nextMatrix;
}
/** Like Matrix.set() but mutates the matrix */
function mutableSet(point, value, matrix) {
var firstRow = matrix[0];
if (!firstRow) {
firstRow = [];
matrix[0] = firstRow;
}
if (!(point.row in matrix)) {
matrix[point.row] = [];
}
// Synchronize first row length
if (!(point.column in firstRow)) {
firstRow[point.column] = undefined;
}
matrix[point.row][point.column] = value;
}
/** Removes the coordinate of matrix */
function unset(point, matrix) {
if (!has(point, matrix)) {
return matrix;
}
var nextMatrix = __spreadArray([], __read(matrix), false);
var nextRow = __spreadArray([], __read(matrix[point.row]), false);
// Avoid deleting to preserve first row length
nextRow[point.column] = undefined;
nextMatrix[point.row] = nextRow;
return nextMatrix;
}
/** Creates an array of values by running each element in collection thru iteratee. */
function map(func, matrix) {
var e_1, _a;
var newMatrix = [];
try {
for (var _b = __values(entries(matrix)), _c = _b.next(); !_c.done; _c = _b.next()) {
var _d = __read(_c.value, 2), point = _d[0], value = _d[1];
mutableSet(point, func(value, point), newMatrix);
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
try {
if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
}
finally { if (e_1) throw e_1.error; }
}
return newMatrix;
}
/** Create an iterator over the cells in the matrix */
function entries(matrix) {
var _a, _b, _c, row, values, _d, _e, _f, column, value, point, e_2_1, e_3_1;
var e_3, _g, e_2, _h;
return __generator(this, function (_j) {
switch (_j.label) {
case 0:
_j.trys.push([0, 11, 12, 13]);
_a = __values(matrix.entries()), _b = _a.next();
_j.label = 1;
case 1:
if (!!_b.done) return [3 /*break*/, 10];
_c = __read(_b.value, 2), row = _c[0], values = _c[1];
_j.label = 2;
case 2:
_j.trys.push([2, 7, 8, 9]);
_d = (e_2 = void 0, __values(values.entries())), _e = _d.next();
_j.label = 3;
case 3:
if (!!_e.done) return [3 /*break*/, 6];
_f = __read(_e.value, 2), column = _f[0], value = _f[1];
point = { row: row, column: column };
return [4 /*yield*/, [point, value]];
case 4:
_j.sent();
_j.label = 5;
case 5:
_e = _d.next();
return [3 /*break*/, 3];
case 6: return [3 /*break*/, 9];
case 7:
e_2_1 = _j.sent();
e_2 = { error: e_2_1 };
return [3 /*break*/, 9];
case 8:
try {
if (_e && !_e.done && (_h = _d.return)) _h.call(_d);
}
finally { if (e_2) throw e_2.error; }
return [7 /*endfinally*/];
case 9:
_b = _a.next();
return [3 /*break*/, 1];
case 10: return [3 /*break*/, 13];
case 11:
e_3_1 = _j.sent();
e_3 = { error: e_3_1 };
return [3 /*break*/, 13];
case 12:
try {
if (_b && !_b.done && (_g = _a.return)) _g.call(_a);
}
finally { if (e_3) throw e_3.error; }
return [7 /*endfinally*/];
case 13: return [2 /*return*/];
}
});
}
/**
* Converts all elements in row into a string separated by horizontalSeparator and each row string
* to string separated by verticalSeparator
*/
function join(matrix, horizontalSeparator, verticalSeparator) {
if (horizontalSeparator === void 0) { horizontalSeparator = "\t"; }
if (verticalSeparator === void 0) { verticalSeparator = "\n"; }
var joined = "";
var _a = getSize(matrix), rows = _a.rows, columns = _a.columns;
for (var row = 0; row < rows; row++) {
if (row) {
joined += verticalSeparator;
}
for (var column = 0; column < columns; column++) {
if (column) {
joined += horizontalSeparator;
}
if (matrix[row] && column in matrix[row]) {
joined += String(matrix[row][column]);
}
}
}
return joined;
}
/**
* Parses a CSV separated by a horizontalSeparator and verticalSeparator into a
* Matrix using a transform function
*/
function split(csv, transform, horizontalSeparator, verticalSeparator) {
if (horizontalSeparator === void 0) { horizontalSeparator = "\t"; }
if (verticalSeparator === void 0) { verticalSeparator = /\r\n|\n|\r/; }
// Temporarily replace line breaks inside quotes
var replaced = csv.replace(/"([^"]*?)"/g, function (match, p1) {
return p1.replace(/\n/g, "\\n");
});
return replaced.split(verticalSeparator).map(function (row) {
return row
.split(horizontalSeparator)
.map(function (line) {
// Restore original line breaks in each line
return line.replace(/\\n/g, "\n");
})
.map(transform);
});
}
/** Returns whether the point exists in the matrix or not. */
function has(point, matrix) {
var firstRow = matrix[0];
return (firstRow &&
// validation
point.row >= 0 &&
point.column >= 0 &&
Number.isInteger(point.row) &&
Number.isInteger(point.column) &&
// first row length is in sync with other rows
point.column < firstRow.length &&
point.row < matrix.length);
}
/** Gets the count of rows and columns of given matrix */
function getSize(matrix) {
return {
columns: getColumnsCount(matrix),
rows: getRowsCount(matrix),
};
}
/** Gets the count of rows of given matrix */
function getRowsCount(matrix) {
return matrix.length;
}
/** Gets the count of columns of given matrix */
function getColumnsCount(matrix) {
var firstRow = matrix[0];
return firstRow ? firstRow.length : 0;
}
/**
* Pads matrix with empty columns to match given total columns
* @param matrix - matrix to pad
* @param size - minimum size of the matrix after padding.
* @returns the updated matrix
*/
function pad(matrix, size) {
var _a = getSize(matrix), rows = _a.rows, columns = _a.columns;
if (rows >= size.rows && columns >= size.columns) {
// Optimization, no padding required.
return matrix;
}
var resultSize = {
rows: size.rows > rows ? size.rows : rows,
columns: size.columns > columns ? size.columns : columns,
};
var padded = __spreadArray([], __read(matrix), false);
if (resultSize.columns > columns) {
var padColumns_1 = resultSize.columns - columns;
padded = padded.map(function (row) { return __spreadArray(__spreadArray([], __read(row), false), __read(Array(padColumns_1).fill(undefined)), false); });
}
if (resultSize.rows > rows) {
var padRows_1 = resultSize.rows - rows;
var emptyRow = Array(resultSize.columns).fill(undefined);
padded = __spreadArray(__spreadArray([], __read(padded), false), __read(Array(padRows_1).fill(emptyRow)), false);
}
return padded;
}
/**
* Flattens a matrix values to an array
* @param matrix - the matrix to flatten values from
* @param transform - optional transform function to apply to each value in the
* matrix
* @returns an array of the values from matrix, transformed if a transform
* function is passed
*/
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
function toArray(matrix, transform) {
var array = [];
for (var row = 0; row < matrix.length; row++) {
for (var column = 0; column < matrix[row].length; column++) {
var value = matrix[row][column];
array.push(transform ? transform(value, { row: row, column: column }) : value);
}
}
return array;
}
/** Returns the maximum point in the matrix */
function maxPoint(matrix) {
var size = getSize(matrix);
return { row: size.rows - 1, column: size.columns - 1 };
}
/**
* Interface for ranges between two points
*/
/** Range between two points. Creates a normalized range between two given points */
var PointRange = /** @class */ (function () {
function PointRange(source, target) {
this.start = {
row: Math.min(source.row, target.row),
column: Math.min(source.column, target.column),
};
this.end = {
row: Math.max(source.row, target.row),
column: Math.max(source.column, target.column),
};
}
/** Iterates through all the existing points in given range */
PointRange.prototype[Symbol.iterator] = function () {
var row, column;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
row = this.start.row;
_a.label = 1;
case 1:
if (!(row <= this.end.row)) return [3 /*break*/, 6];
column = this.start.column;
_a.label = 2;
case 2:
if (!(column <= this.end.column)) return [3 /*break*/, 5];
return [4 /*yield*/, { row: row, column: column }];
case 3:
_a.sent();
_a.label = 4;
case 4:
column++;
return [3 /*break*/, 2];
case 5:
row++;
return [3 /*break*/, 1];
case 6: return [2 /*return*/];
}
});
};
/** Returns the size (rows x columns) of the given range */
PointRange.prototype.size = function () {
var rows = this.end.row + 1 - this.start.row;
var columns = this.end.column + 1 - this.start.column;
return rows * columns;
};
/** Returns whether given point exists in given range */
PointRange.prototype.has = function (point) {
return (point.row >= this.start.row &&
point.column >= this.start.column &&
point.row <= this.end.row &&
point.column <= this.end.column);
};
/** Limits given masked range with given mask */
PointRange.prototype.mask = function (mask) {
return new PointRange({
row: mask.start.row > this.start.row ? mask.start.row : this.start.row,
column: mask.start.column > this.start.column
? mask.start.column
: this.start.column,
}, {
row: mask.end.row < this.end.row ? mask.end.row : this.end.row,
column: mask.end.column < this.end.column ? mask.end.column : this.end.column,
});
};
/** Returns whether given range is equal to this range */
PointRange.prototype.equals = function (range) {
return (this.start.row === range.start.row &&
this.start.column === range.start.column &&
this.end.row === range.end.row &&
this.end.column === range.end.column);
};
return PointRange;
}());
/** Return whether two given points are the equal */
function isEqual(source, target) {
return source.column === target.column && source.row === target.row;
}
/** The origin point in matrices */
var ORIGIN = { row: 0, column: 0 };
/** Selection from a spreadsheet */
var Selection = /** @class */ (function () {
function Selection() {
}
return Selection;
}());
/** Selection of no cells */
var EmptySelection = /** @class */ (function (_super) {
__extends(EmptySelection, _super);
function EmptySelection() {
return _super !== null && _super.apply(this, arguments) || this;
}
EmptySelection.prototype.toRange = function (data) {
return null;
};
EmptySelection.prototype.normalizeTo = function (data) {
return this;
};
EmptySelection.prototype.hasEntireRow = function (row) {
return false;
};
EmptySelection.prototype.hasEntireColumn = function (column) {
return false;
};
EmptySelection.prototype.size = function () {
return 0;
};
EmptySelection.prototype.has = function () {
return false;
};
EmptySelection.prototype.equals = function (selection) {
return selection instanceof EmptySelection;
};
return EmptySelection;
}(Selection));
/** Selection of a range of cells */
var RangeSelection = /** @class */ (function (_super) {
__extends(RangeSelection, _super);
function RangeSelection(range) {
var _this = _super.call(this) || this;
_this.range = range;
return _this;
}
RangeSelection.prototype.toRange = function (data) {
return this.range;
};
RangeSelection.prototype.normalizeTo = function (data) {
var dataRange = getMatrixRange(data);
var nextSelection = new RangeSelection(this.range.mask(dataRange));
// @ts-expect-error
return nextSelection;
};
RangeSelection.prototype.hasEntireRow = function (row) {
return false;
};
RangeSelection.prototype.hasEntireColumn = function (column) {
return false;
};
RangeSelection.prototype.size = function (data) {
var range = this.toRange(data);
return range ? range.size() : 0;
};
RangeSelection.prototype.has = function (data, point) {
var range = this.toRange(data);
return range !== null && range.has(point);
};
RangeSelection.prototype.equals = function (selection) {
return (selection instanceof RangeSelection && this.range.equals(selection.range));
};
return RangeSelection;
}(Selection));
/** Selection of an entire part of the spreadsheet */
var EntireSelection = /** @class */ (function (_super) {
__extends(EntireSelection, _super);
function EntireSelection() {
return _super !== null && _super.apply(this, arguments) || this;
}
return EntireSelection;
}(Selection));
/** Selection of the entire worksheet */
var EntireWorksheetSelection = /** @class */ (function (_super) {
__extends(EntireWorksheetSelection, _super);
function EntireWorksheetSelection() {
return _super !== null && _super.apply(this, arguments) || this;
}
EntireWorksheetSelection.prototype.toRange = function (data) {
return getMatrixRange(data);
};
EntireWorksheetSelection.prototype.normalizeTo = function (data) {
return this;
};
EntireWorksheetSelection.prototype.hasEntireColumn = function (column) {
return true;
};
EntireWorksheetSelection.prototype.hasEntireRow = function (row) {
return true;
};
EntireWorksheetSelection.prototype.size = function (data) {
return getColumnsCount(data) * getRowsCount(data);
};
EntireWorksheetSelection.prototype.has = function (data, point) {
return true;
};
EntireWorksheetSelection.prototype.equals = function (selection) {
return selection instanceof EntireWorksheetSelection;
};
return EntireWorksheetSelection;
}(EntireSelection));
/** Selection of an entire axis in the spreadsheet */
var EntireAxisSelection = /** @class */ (function (_super) {
__extends(EntireAxisSelection, _super);
/**
* @param start - row index where the selection starts, integer
* @param end - row index where the selection ends, integer
* @throws {@link InvalidIndexError}
*/
function EntireAxisSelection(start, end) {
var _this = this;
if (!isIndex(start)) {
throw new InvalidIndexError("start");
}
if (!isIndex(end)) {
throw new InvalidIndexError("end");
}
_this = _super.call(this) || this;
_this.start = Math.min(start, end);
_this.end = Math.max(start, end);
return _this;
}
EntireAxisSelection.prototype.equals = function (selection) {
return (selection instanceof EntireAxisSelection &&
this.constructor === selection.constructor &&
this.start === selection.start &&
this.end === selection.end);
};
return EntireAxisSelection;
}(EntireSelection));
/** Selection of entire rows in the spreadsheet */
var EntireRowsSelection = /** @class */ (function (_super) {
__extends(EntireRowsSelection, _super);
function EntireRowsSelection() {
return _super !== null && _super.apply(this, arguments) || this;
}
EntireRowsSelection.prototype.toRange = function (data) {
var max = maxPoint(data);
return new PointRange({ row: this.start, column: 0 }, { row: this.end, column: max.column });
};
EntireRowsSelection.prototype.normalizeTo = function (data) {
var count = getRowsCount(data);
var nextSelection = new EntireRowsSelection(Math.max(this.start, 0), Math.min(this.end, count - 1));
// @ts-expect-error
return nextSelection;
};
EntireRowsSelection.prototype.hasEntireRow = function (row) {
return row >= this.start && row <= this.end;
};
EntireRowsSelection.prototype.hasEntireColumn = function (column) {
return false;
};
EntireRowsSelection.prototype.size = function (data) {
var rows = this.end - this.start + 1;
return rows * getColumnsCount(data);
};
EntireRowsSelection.prototype.has = function (data, point) {
return point.row >= this.start && point.row <= this.end;
};
return EntireRowsSelection;
}(EntireAxisSelection));
/** Selection of entire columns in the spreadsheet */
var EntireColumnsSelection = /** @class */ (function (_super) {
__extends(EntireColumnsSelection, _super);
function EntireColumnsSelection() {
return _super !== null && _super.apply(this, arguments) || this;
}
EntireColumnsSelection.prototype.toRange = function (data) {
var max = maxPoint(data);
return new PointRange({ row: 0, column: this.start }, { row: max.row, column: this.end });
};
EntireColumnsSelection.prototype.normalizeTo = function (data) {
var count = getColumnsCount(data);
var nextSelection = new EntireColumnsSelection(Math.max(this.start, 0), Math.min(this.end, count - 1));
// @ts-expect-error
return nextSelection;
};
EntireColumnsSelection.prototype.hasEntireRow = function (row) {
return false;
};
EntireColumnsSelection.prototype.hasEntireColumn = function (column) {
return column >= this.start && column <= this.end;
};
EntireColumnsSelection.prototype.size = function (data) {
var columns = this.end - this.start + 1;
return columns * getRowsCount(data);
};
EntireColumnsSelection.prototype.has = function (data, point) {
return point.column >= this.start && point.column <= this.end;
};
return EntireColumnsSelection;
}(EntireAxisSelection));
/** Get the point range of given matrix */
function getMatrixRange(data) {
var maxPoint$1 = maxPoint(data);
return new PointRange(ORIGIN, maxPoint$1);
}
/** Determines whether the given value is a valid index */
function isIndex(value) {
return Number.isInteger(value) && value >= 0;
}
/** Error thrown when passing a non-index value where an index value is expected */
var InvalidIndexError = /** @class */ (function (_super) {
__extends(InvalidIndexError, _super);
function InvalidIndexError(name) {
return _super.call(this, "".concat(name, " is not a valid index. It must be 0 or a positive integer")) || this;
}
return InvalidIndexError;
}(Error));
var PLAIN_TEXT_MIME = "text/plain";
var FOCUS_WITHIN_SELECTOR = ":focus-within";
/** Move the cursor of given input element to the input's end */
function moveCursorToEnd(el) {
el.selectionStart = el.selectionEnd = el.value.length;
}
/**
* Creates an array of numbers (positive and/or negative) progressing from start up to, but not including, end. A step of -1 is used if a negative start is specified without an end or step. If end is not specified, it's set to start with start then set to 0.
* @param end - an integer number specifying at which position to stop (not included).
* @param start - An integer number specifying at which position to start.
* @param step - An integer number specifying the incrementation
*/
function range(end, start, step) {
if (start === void 0) { start = 0; }
if (step === void 0) { step = 1; }
var array = [];
if (Math.sign(end - start) === -1) {
for (var element = start; element > end; element -= step) {
array.push(element);
}
return array;
}
for (var element = start; element < end; element += step) {
array.push(element);
}
return array;
}
/** Return whether given point is active */
function isActive(active, point) {
return Boolean(active && isEqual(point, active));
}
/** Get the offset values of given element */
function getOffsetRect(element) {
return {
width: element.offsetWidth,
height: element.offsetHeight,
left: element.offsetLeft,
top: element.offsetTop,
};
}
/** Write given data to clipboard with given event */
function writeTextToClipboard(event, data) {
var _a;
(_a = event.clipboardData) === null || _a === void 0 ? void 0 : _a.setData(PLAIN_TEXT_MIME, data);
}
/** Read text from given clipboard event */
function readTextFromClipboard(event) {
// @ts-ignore
if (window.clipboardData && window.clipboardData.getData) {
// @ts-ignore
return window.clipboardData.getData("Text");
}
if (event.clipboardData && event.clipboardData.getData) {
return event.clipboardData.getData(PLAIN_TEXT_MIME);
}
return "";
}
/** Get the dimensions of cell at point from state */
function getCellDimensions(point, rowDimensions, columnDimensions) {
var cellRowDimensions = rowDimensions && rowDimensions[point.row];
var cellColumnDimensions = columnDimensions && columnDimensions[point.column];
return (cellRowDimensions &&
cellColumnDimensions && __assign(__assign({}, cellRowDimensions), cellColumnDimensions));
}
/** Get the dimensions of a range of cells */
function getRangeDimensions(rowDimensions, columnDimensions, range) {
var startDimensions = getCellDimensions(range.start, rowDimensions, columnDimensions);
var endDimensions = getCellDimensions(range.end, rowDimensions, columnDimensions);
return (startDimensions &&
endDimensions && {
width: endDimensions.left + endDimensions.width - startDimensions.left,
height: endDimensions.top + endDimensions.height - startDimensions.top,
top: startDimensions.top,
left: startDimensions.left,
});
}
/** Get the dimensions of selected */
function getSelectedDimensions(rowDimensions, columnDimensions, data, selected) {
var range = selected.toRange(data);
return range
? getRangeDimensions(rowDimensions, columnDimensions, range)
: undefined;
}
/** Get given data as CSV */
function getCSV(data) {
var valueMatrix = map(function (cell) { return (cell === null || cell === void 0 ? void 0 : cell.value) || ""; }, data);
return join(valueMatrix);
}
/**
* Calculate the rows and columns counts of a spreadsheet
* @param data - the spreadsheet's data
* @param rowLabels - the spreadsheet's row labels (if defined)
* @param columnLabels - the spreadsheet's column labels (if defined)
* @returns the rows and columns counts of a spreadsheet
*/
function calculateSpreadsheetSize(data, rowLabels, columnLabels) {
var _a = getSize(data), columns = _a.columns, rows = _a.rows;
return {
rows: rowLabels ? Math.max(rows, rowLabels.length) : rows,
columns: columnLabels ? Math.max(columns, columnLabels.length) : columns,
};
}
/** Should spreadsheet handle clipboard event */
function shouldHandleClipboardEvent(root, mode) {
return root !== null && mode === "view" && isFocusedWithin(root);
}
function isFocusedWithin(element) {
return element.matches(FOCUS_WITHIN_SELECTOR);
}
function hasLineBreaker(value) {
return typeof value === "string" && value.includes("\n");
}
function toString(point) {
return "".concat(point.row, ",").concat(point.column);
}
function fromString(point) {
var _a = __read(point.split(","), 2), row = _a[0], column = _a[1];
return { row: Number(row), column: Number(column) };
}
/**
* Immutable Set like interface of points
*/
var PointSet = /** @class */ (function () {
function PointSet(set) {
this.set = set;
}
/** Creates a new PointSet instance from an array-like or iterable object */
PointSet.from = function (points) {
var e_1, _a;
var set = new Set();
try {
for (var points_1 = __values(points), points_1_1 = points_1.next(); !points_1_1.done; points_1_1 = points_1.next()) {
var point = points_1_1.value;
set.add(toString(point));
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
try {
if (points_1_1 && !points_1_1.done && (_a = points_1.return)) _a.call(points_1);
}
finally { if (e_1) throw e_1.error; }
}
return new PointSet(set);
};
/** Returns a boolean asserting whether an point is present with the given value in the Set object or not */
PointSet.prototype.has = function (point) {
return this.set.has(toString(point));
};
Object.defineProperty(PointSet.prototype, "size", {
/** Returns the number of points in a PointSet object */
get: function () {
return this.set.size;
},
enumerable: false,
configurable: true
});
/** Add the given point to given set */
PointSet.prototype.add = function (point) {
var newSet = new Set(this.set);
newSet.add(toString(point));
return new PointSet(newSet);
};
/** Remove the given point from the given set */
PointSet.prototype.delete = function (point) {
var newSet = new Set(this.set);
if (!newSet.delete(toString(point))) {
return this;
}
return new PointSet(newSet);
};
/** Returns a new PointSet with points common to the set and other */
PointSet.prototype.difference = function (other) {
var e_2, _a;
var newSet = this;
try {
for (var other_1 = __values(other), other_1_1 = other_1.next(); !other_1_1.done; other_1_1 = other_1.next()) {
var point = other_1_1.value;
newSet = newSet.delete(point);
}
}
catch (e_2_1) { e_2 = { error: e_2_1 }; }
finally {
try {
if (other_1_1 && !other_1_1.done && (_a = other_1.return)) _a.call(other_1);
}
finally { if (e_2) throw e_2.error; }
}
return newSet;
};
/** Returns a new PointSet with all points in both sets */
PointSet.prototype.union = function (other) {
var e_3, _a;
var newSet = this;
try {
for (var other_2 = __values(other), other_2_1 = other_2.next(); !other_2_1.done; other_2_1 = other_2.next()) {
var point = other_2_1.value;
newSet = newSet.add(point);
}
}
catch (e_3_1) { e_3 = { error: e_3_1 }; }
finally {
try {
if (other_2_1 && !other_2_1.done && (_a = other_2.return)) _a.call(other_2);
}
finally { if (e_3) throw e_3.error; }
}
return newSet;
};
/** Creates an iterator of points in the set */
PointSet.prototype[Symbol.iterator] = function () {
var _a, _b, value, e_4_1;
var e_4, _c;
return __generator(this, function (_d) {
switch (_d.label) {
case 0:
_d.trys.push([0, 5, 6, 7]);
_a = __values(this.set), _b = _a.next();
_d.label = 1;
case 1:
if (!!_b.done) return [3 /*break*/, 4];
value = _b.value;
return [4 /*yield*/, fromString(value)];
case 2:
_d.sent();
_d.label = 3;
case 3:
_b = _a.next();
return [3 /*break*/, 1];
case 4: return [3 /*break*/, 7];
case 5:
e_4_1 = _d.sent();
e_4 = { error: e_4_1 };
return [3 /*break*/, 7];
case 6:
try {
if (_b && !_b.done && (_c = _a.return)) _c.call(_a);
}
finally { if (e_4) throw e_4.error; }
return [7 /*endfinally*/];
case 7: return [2 /*return*/];
}
});
};
return PointSet;
}());
var FORMULA_VALUE_PREFIX = "=";
/** Returns whether given value is a formula */
function isFormulaValue(value) {
return (typeof value === "string" &&
value.startsWith(FORMULA_VALUE_PREFIX) &&
value.length > 1);
}
/** Extracts formula from value */
function extractFormula(value) {
return value.slice(1);
}
function createFormulaParser(data, config) {
return new FormulaParser(__assign(__assign({}, config), { onCell: function (ref) {
var point = {
row: ref.row - 1,
column: ref.col - 1,
};
var cell = get(point, data);
if (!isNaN(cell === null || cell === void 0 ? void 0 : cell.value))
return Number(cell === null || cell === void 0 ? void 0 : cell.value);
return cell === null || cell === void 0 ? void 0 : cell.value;
}, onRange: function (ref) {
var size = getSize(data);
var start = {
row: ref.from.row - 1,
column: ref.from.col - 1,
};
var end = {
row: Math.min(ref.to.row - 1, size.rows - 1),
column: Math.min(ref.to.col - 1, size.columns - 1),
};
var dataSlice = slice(start, end, data);
return toArray(dataSlice, function (cell) {
if (!isNaN(cell === null || cell === void 0 ? void 0 : cell.value))
return Number(cell === null || cell === void 0 ? void 0 : cell.value);
return cell === null || cell === void 0 ? void 0 : cell.value;
});
} }));
}
var depParser = new FormulaParser.DepParser();
/**
* For given formula returns the cell references
* @param formula - formula to get references for
*/
function getReferences(formula, point, data) {
var _a = getSize(data), rows = _a.rows, columns = _a.columns;
try {
var dependencies = depParser.parse(formula, convertPointToCellRef(point));
var references = PointSet.from(dependencies.flatMap(function (reference) {
var isRange = "from" in reference;
if (isRange) {
var from = reference.from, to = reference.to;
var normalizedFrom = {
row: from.row - 1,
column: from.col - 1,
};
var normalizedTo = {
row: Math.min(to.row - 1, rows - 1),
column: Math.min(to.col - 1, columns - 1),
};
var range = new PointRange(normalizedFrom, normalizedTo);
return Array.from(range);
}
return { row: reference.row - 1, column: reference.col - 1 };
}));
return references;
}
catch (error) {
if (error instanceof FormulaParser.FormulaError) {
return PointSet.from([]);
}
else {
throw error;
}
}
}
function evaluate(formula, point, formulaParser) {
try {
var position = convertPointToCellRef(point);
var returned = formulaParser.parse(formula, position);
return returned instanceof FormulaParser.FormulaError ? returned.toString() : returned;
}
catch (error) {
if (error instanceof FormulaParser.FormulaError) {
return error.toString();
}
throw error;
}
}
function convertPointToCellRef(point) {
return {
row: point.row + 1,
col: point.column + 1,
// TODO: fill once we support multiple sheets
sheet: "Sheet1",
};
}
/**
* Immutable directed graph of points, where each point can have multiple
* edges to other points.
*/
var PointGraph = /** @class */ (function () {
function PointGraph(forwards) {
if (forwards === void 0) { forwards = new Map(); }
this.forwards = forwards;
}
/** Creates a new PointGraph instance from an array-like or iterable object */
PointGraph.from = function (pairs) {
var e_1, _a;
var forwards = new Map();
try {
for (var pairs_1 = __values(pairs), pairs_1_1 = pairs_1.next(); !pairs_1_1.done; pairs_1_1 = pairs_1.next()) {
var _b = __read(pairs_1_1.value, 2), node = _b[0], edges = _b[1];
forwards.set(toString(node), edges);
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
try {
if (pairs_1_1 && !pairs_1_1.done && (_a = pairs_1.return)) _a.call(pairs_1);
}
finally { if (e_1) throw e_1.error; }
}
return new PointGraph(forwards);
};
PointGraph.prototype.set = function (node, edges) {
var newGraph = new PointGraph(new Map(this.forwards));
if (edges.size === 0) {
newGraph.forwards.delete(toString(node));
return newGraph;
}
newGraph.forwards.set(toString(node), edges);
return newGraph;
};
PointGraph.prototype.get = function (node) {
return this.forwards.get(toString(node)) || PointSet.from([]);
};
PointGraph.prototype.getBackwards = function (node) {
var e_2, _a;
var result = PointSet.from([]);
try {
for (var _b = __values(this.forwards), _c = _b.next(); !_c.done; _c = _b.next()) {
var _d = __read(_c.value, 2), key = _d[0], value = _d[1];
if (value.has(node)) {
result = result.add(fromString(key));
}
}
}
catch (e_2_1) { e_2 = { error: e_2_1 }; }
finally {
try {
if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
}
finally { if (e_2) throw e_2.error; }
}
return result;
};
PointGraph.prototype.getBackwardsRecursive = function (node, visited) {
var e_3, _a;
if (visited === void 0) { visited = PointSet.from([]); }
var result = this.getBackwards(node);
var newVisited = visited;
try {
for (var result_1 = __values(result), result_1_1 = result_1.next(); !result_1_1.done; result_1_1 = result_1.next()) {
var point = result_1_1.value;
if (newVisited.has(point)) {
continue;
}
newVisited = newVisited.add(point);
result = result.union(this.getBackwardsRecursive(point, newVisited));
}
}
catch (e_3_1) { e_3 = { error: e_3_1 }; }
finally {
try {
if (result_1_1 && !result_1_1.done && (_a = result_1.return)) _a.call(result_1);
}
finally { if (e_3) throw e_3.error; }
}
return result;
};
/** Determine whether the graph has a circular dependency, starting from given start point */
PointGraph.prototype.hasCircularDependency = function (startPoint) {
var e_4, _a;
var visited = PointSet.from([]);
var stack = [startPoint];
while (stack.length > 0) {
var current = stack.pop();
if (!current) {
continue;
}
if (visited.has(current)) {
return true;
}
visited = visited.add(current);
var dependents = this.get(current);
if (!dependents) {
continue;
}
try {
for (var dependents_1 = (e_4 = void 0, __values(dependents)), dependents_1_1 = dependents_1.next(); !dependents_1_1.done; dependents_1_1 = dependents_1.next()) {
var dependent = dependents_1_1.value;
stack.push(dependent);
}
}
catch (e_4_1) { e_4 = { error: e_4_1 }; }
finally {
try {
if (dependents_1_1 && !dependents_1_1.done && (_a = dependents_1.return)) _a.call(dependents_1);
}
finally { if (e_4) throw e_4.error; }
}
}
return false;
};
PointGraph.prototype[Symbol.iterator] = function () {
var visitedHashes, _a, _b, _c, key, values, point, values_1, values_1_1, value, hash, e_5_1, e_6_1;
var e_6, _d, e_5, _e;
return __generator(this, function (_f) {
switch (_f.label) {
case 0:
visitedHashes = new Set();
_f.label = 1;
case 1:
_f.trys.push([1, 13, 14, 15]);
_a = __values(this.forwards), _b = _a.next();
_f.label = 2;
case 2:
if (!!_b.done) return [3 /*break*/, 12];
_c = __read(_b.value, 2), key = _c[0], values = _c[1];
point = fromString(key);
visitedHashes.add(key);
return [4 /*yield*/, [point, values]];
case 3:
_f.sent();
_f.la