UNPKG

react-spreadsheet

Version:

Simple, customizable yet performant spreadsheet for React

432 lines (417 loc) 18.3 kB
import * as React from 'react'; import FormulaParser, { FormulaParserConfig } from 'fast-formula-parser'; /** A cell coordinates in the spreadsheet */ type Point = { /** The cell's column */ column: number; /** The cell's row */ row: number; }; /** * Interface for ranges between two points */ /** Range between two points. Creates a normalized range between two given points */ declare class PointRange { /** The top-left point */ start: Point; /** The bottom-right point */ end: Point; constructor(source: Point, target: Point); /** Iterates through all the existing points in given range */ [Symbol.iterator](): Iterator<Point>; /** Returns the size (rows x columns) of the given range */ size(): number; /** Returns whether given point exists in given range */ has(point: Point): boolean; /** Limits given masked range with given mask */ mask(mask: PointRange): PointRange; /** Returns whether given range is equal to this range */ equals(range: PointRange): boolean; } /** A two-dimensional array of given type T in rows and columns */ type Matrix<T> = Array<Array<T | undefined>>; /** * 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 */ declare function createEmpty<T>(rows: number, columns: number): Matrix<T>; /** Selection from a spreadsheet */ declare abstract class Selection { /** Get concrete range of the selection in the given data */ abstract toRange(data: Matrix<unknown>): PointRange | null; /** Normalize the selection according to the given data */ abstract normalizeTo(data: Matrix<unknown>): this; /** Determines whether the given row is entirely selected in given selection */ abstract hasEntireRow(row: number): boolean; /** Determines whether the given column is entirely selected in given selection */ abstract hasEntireColumn(column: number): boolean; /** Get the number of selected points according to given data */ abstract size(data: Matrix<unknown>): number; /** Determines whether the given point is within the selection */ abstract has(data: Matrix<unknown>, point: Point): boolean; /** Determines whether the given selection is equal to this selection */ abstract equals(selection: Selection): boolean; } /** Selection of no cells */ declare class EmptySelection extends Selection { toRange(data: Matrix<unknown>): PointRange | null; normalizeTo(data: Matrix<unknown>): this; hasEntireRow(row: number): boolean; hasEntireColumn(column: number): boolean; size(): number; has(): boolean; equals(selection: Selection): boolean; } /** Selection of a range of cells */ declare class RangeSelection extends Selection { range: PointRange; constructor(range: PointRange); toRange(data: Matrix<unknown>): PointRange | null; normalizeTo(data: Matrix<unknown>): this; hasEntireRow(row: number): boolean; hasEntireColumn(column: number): boolean; size(data: Matrix<unknown>): number; has(data: Matrix<unknown>, point: Point): boolean; equals(selection: Selection): boolean; } /** Selection of an entire part of the spreadsheet */ declare abstract class EntireSelection extends Selection { } /** Selection of the entire worksheet */ declare class EntireWorksheetSelection extends EntireSelection { toRange(data: Matrix<unknown>): PointRange; normalizeTo(data: Matrix<unknown>): this; hasEntireColumn(column: number): boolean; hasEntireRow(row: number): boolean; size(data: Matrix<unknown>): number; has(data: Matrix<unknown>, point: Point): boolean; equals(selection: Selection): boolean; } /** Selection of an entire axis in the spreadsheet */ declare abstract class EntireAxisSelection extends EntireSelection { /** Selection start index, integer */ readonly start: number; /** Selection end index, integer */ readonly end: number; /** * @param start - row index where the selection starts, integer * @param end - row index where the selection ends, integer * @throws {@link InvalidIndexError} */ constructor(start: number, end: number); equals(selection: Selection): boolean; } /** Selection of entire rows in the spreadsheet */ declare class EntireRowsSelection extends EntireAxisSelection { toRange(data: Matrix<unknown>): PointRange; normalizeTo(data: Matrix<unknown>): this; hasEntireRow(row: number): boolean; hasEntireColumn(column: number): boolean; size(data: Matrix<unknown>): number; has(data: Matrix<unknown>, point: Point): boolean; } /** Selection of entire columns in the spreadsheet */ declare class EntireColumnsSelection extends EntireAxisSelection { toRange(data: Matrix<unknown>): PointRange; normalizeTo(data: Matrix<unknown>): this; hasEntireRow(row: number): boolean; hasEntireColumn(column: number): boolean; size(data: Matrix<unknown>): number; has(data: Matrix<unknown>, point: Point): boolean; } /** Error thrown when passing a non-index value where an index value is expected */ declare class InvalidIndexError extends Error { constructor(name: string); } /** * Immutable Set like interface of points */ declare class PointSet { private set; private constructor(); /** Creates a new PointSet instance from an array-like or iterable object */ static from(points: Iterable<Point>): PointSet; /** Returns a boolean asserting whether an point is present with the given value in the Set object or not */ has(point: Point): boolean; /** Returns the number of points in a PointSet object */ get size(): number; /** Add the given point to given set */ add(point: Point): PointSet; /** Remove the given point from the given set */ delete(point: Point): PointSet; /** Returns a new PointSet with points common to the set and other */ difference(other: PointSet): PointSet; /** Returns a new PointSet with all points in both sets */ union(other: PointSet): PointSet; /** Creates an iterator of points in the set */ [Symbol.iterator](): Iterator<Point>; } /** * Immutable directed graph of points, where each point can have multiple * edges to other points. */ declare class PointGraph { private forwards; private constructor(); /** Creates a new PointGraph instance from an array-like or iterable object */ static from(pairs: Iterable<[Point, PointSet]>): PointGraph; set(node: Point, edges: PointSet): PointGraph; get(node: Point): PointSet; getBackwards(node: Point): PointSet; getBackwardsRecursive(node: Point, visited?: PointSet): PointSet; /** Determine whether the graph has a circular dependency, starting from given start point */ hasCircularDependency(startPoint: Point): boolean; [Symbol.iterator](): Iterator<[Point, PointSet]>; /** Get the points in the graph in a breadth-first order */ traverseBFSBackwards(): Generator<Point>; } declare class Model<Cell extends CellBase> { readonly data: Matrix<Cell>; readonly evaluatedData: Matrix<Cell>; readonly referenceGraph: PointGraph; readonly createFormulaParser: CreateFormulaParser; constructor(createFormulaParser: CreateFormulaParser, data: Matrix<Cell>, referenceGraph?: PointGraph, evaluatedData?: Matrix<Cell>); } declare function createFormulaParser(data: Matrix<CellBase>, config?: Omit<FormulaParserConfig, "onCell" | "onRange">): FormulaParser; /** The base type of cell data in Spreadsheet */ type CellBase<Value = any> = { /** Whether the cell should not be editable */ readOnly?: boolean; /** Class to be given for the cell element */ className?: string; /** The value of the cell */ value: Value; /** Custom component to render when the cell is edited, if not defined would default to the component defined for the Spreadsheet */ DataEditor?: DataEditorComponent<CellBase<Value>>; /** Custom component to render when the cell is viewed, if not defined would default to the component defined for the Spreadsheet */ DataViewer?: DataViewerComponent<CellBase<Value>>; }; /** * A cell with it's coordinates * @deprecated the component does not use cell descriptors anymore. Instead it passes cell point and cell value explicitly. */ type CellDescriptor<Cell> = { /** The cell's data */ data: Cell | undefined; } & Point; /** The spreadsheet's write mode */ type Mode = "view" | "edit"; /** Dimensions of an element */ type Dimensions = { /** The element's width in pixels */ width: number; /** The element's height in pixels */ height: number; /** The distance of the element from it's container top border in pixels */ top: number; /** The distance of the element from it's container left border in pixels */ left: number; }; type CellChange<Cell extends CellBase = CellBase> = { prevCell: Cell | null; nextCell: Cell | null; }; /** Type of Spreadsheet Cell component props */ type CellComponentProps<Cell extends CellBase = CellBase> = { /** The row of the cell */ row: number; /** The column of the cell */ column: number; /** The DataViewer component to be used by the cell */ DataViewer: DataViewerComponent<Cell>; /** Whether the cell is selected */ selected: boolean; /** Whether the cell is active */ active: boolean; /** Whether the cell is copied */ copied: boolean; /** Whether the user is dragging */ dragging: boolean; /** The mode of the cell */ mode: Mode; /** The data of the cell */ data: Cell | undefined; /** The evaluated data of the cell */ evaluatedData: Cell | undefined; /** Select the cell at the given point */ select: (point: Point) => void; /** Activate the cell at the given point */ activate: (point: Point) => void; /** Set the dimensions of the cell at the given point with the given dimensions */ setCellDimensions: (point: Point, dimensions: Dimensions) => void; /** Set data of the cell */ setCellData: (cell: Cell) => void; }; /** Type of the Spreadsheet Cell component */ type CellComponent<Cell extends CellBase = CellBase> = React.ComponentType<CellComponentProps<Cell>>; type DataComponentProps<Cell extends CellBase> = { /** The rendered cell by the component */ cell: Cell | undefined; } & Point; /** Type of the Spreadsheet DataViewer component props */ type DataViewerProps<Cell extends CellBase = CellBase> = DataComponentProps<Cell> & { /** Set data of the cell */ setCellData: (cell: Cell) => void; evaluatedCell: Cell | undefined; }; /** Type of the Spreadsheet DataViewer component */ type DataViewerComponent<Cell extends CellBase = CellBase> = React.ComponentType<DataViewerProps<Cell>>; /** Type of the Spreadsheet DataEditor component props */ type DataEditorProps<Cell extends CellBase = CellBase> = DataComponentProps<Cell> & { /** Callback to be called when the cell's value is changed */ onChange: (cell: Cell) => void; /** Callback to be called when edit mode should be exited */ exitEditMode: () => void; }; /** Type of the Spreadsheet DataEditor component */ type DataEditorComponent<Cell extends CellBase = CellBase> = React.ComponentType<DataEditorProps<Cell>>; /** Type of the Spreadsheet Table component props */ type TableProps = React.PropsWithChildren<{ /** Numebr of columns the table should render */ columns: number; /** Whether column indicators are hidden */ hideColumnIndicators?: boolean | null; }>; /** Type of the Spreadsheet Table component */ type TableComponent = React.ComponentType<TableProps>; /** Type of the Spreadsheet Row component props */ type RowProps = React.PropsWithChildren<{ /** The row index of the table */ row: number; }>; /** Type of the Row component */ type RowComponent = React.ComponentType<RowProps>; /** Type of the Spreadsheet HeaderRow component props */ type HeaderRowProps = React.PropsWithChildren<{}>; /** Type of the HeaderRow component */ type HeaderRowComponent = React.ComponentType<HeaderRowProps>; /** Type of the Spreadsheet RowIndicator component props */ type RowIndicatorProps = { /** The row the indicator indicates */ row: number; /** A custom label for the indicator as provided in rowLabels */ label?: React.ReactNode | null; /** Whether the entire row is selected */ selected: boolean; /** Callback to be called when the row is selected */ onSelect: (row: number, extend: boolean) => void; }; /** Type of the RowIndicator component */ type RowIndicatorComponent = React.ComponentType<RowIndicatorProps>; /** Type of the Spreadsheet ColumnIndicator component props */ type ColumnIndicatorProps = { /** The column the indicator indicates */ column: number; /** A custom label for the indicator as provided in columnLabels */ label?: React.ReactNode | null; /** Whether the entire column in selected */ selected: boolean; /** Callback to be called when the column is selected */ onSelect: (column: number, extend: boolean) => void; }; /** Type of the ColumnIndicator component */ type ColumnIndicatorComponent = React.ComponentType<ColumnIndicatorProps>; /** Type of the Spreadsheet CornerIndicator component props */ type CornerIndicatorProps = { /** Whether the entire table is selected */ selected: boolean; /** Callback to select the entire table */ onSelect: () => void; }; /** Type of the CornerIndicator component */ type CornerIndicatorComponent = React.ComponentType<CornerIndicatorProps>; type CreateFormulaParser = (data: Matrix<CellBase>) => FormulaParser; /** The Spreadsheet component props */ type Props<CellType extends CellBase> = { /** The spreadsheet's data */ data: Matrix<CellType>; /** Class name to be added to the spreadsheet's root element */ className?: string; /** * Use dark colors that complement dark mode * @defaultValue `false` */ darkMode?: boolean; /** * Function used to create the formula parser (instance of * "fast-formula-parser") used by the Spreadsheet by getting the spreadsheet's * data. * @defaultValue function which creates a formula parser bound to the * Spreadsheet's data. * @see `createFormulaParser` * @see https://www.npmjs.com/package/fast-formula-parser */ createFormulaParser?: CreateFormulaParser; /** * Labels to use in column indicators. * @defaultValue alphabetical labels. */ columnLabels?: string[]; /** * Labels to use in row indicators. * @defaultValue row index labels. */ rowLabels?: string[]; /** * If set to true, hides the row indicators of the spreadsheet. * @defaultValue `false`. */ hideRowIndicators?: boolean; /** * If set to true, hides the column indicators of the spreadsheet. * @defaultValue `false`. */ hideColumnIndicators?: boolean; /** The selected cells in the worksheet. */ selected?: Selection; /** Component rendered above each column. */ ColumnIndicator?: ColumnIndicatorComponent; /** Component rendered in the corner of row and column indicators. */ CornerIndicator?: CornerIndicatorComponent; /** Component rendered next to each row. */ RowIndicator?: RowIndicatorComponent; /** The Spreadsheet's table component. */ Table?: TableComponent; /** The Spreadsheet's row component. */ Row?: RowComponent; /** The spreadsheet's header row component */ HeaderRow?: HeaderRowComponent; /** The Spreadsheet's cell component. */ Cell?: CellComponent<CellType>; /** Component rendered for cells in view mode. */ DataViewer?: DataViewerComponent<CellType>; /** Component rendered for cells in edit mode. */ DataEditor?: DataEditorComponent<CellType>; /** Callback called on key down inside the spreadsheet. */ onKeyDown?: (event: React.KeyboardEvent) => void; /** Callback called when the Spreadsheet's data changes. */ onChange?: (data: Matrix<CellType>) => void; /** Callback called when the Spreadsheet's edit mode changes. */ onModeChange?: (mode: Mode) => void; /** Callback called when the Spreadsheet's selection changes. */ onSelect?: (selected: Selection) => void; /** Callback called when Spreadsheet's active cell changes. */ onActivate?: (active: Point) => void; /** Callback called when the Spreadsheet loses focus */ onBlur?: () => void; onCellCommit?: (prevCell: null | CellType, nextCell: null | CellType, coords: null | Point) => void; /** Callback called when the Spreadsheet's evaluated data changes. */ onEvaluatedDataChange?: (data: Matrix<CellType>) => void; }; /** * The Spreadsheet Ref Type */ type SpreadsheetRef = { /** * Pass the desired point as a prop to specify which one should be activated. */ activate: (point: Point) => void; }; declare const _default: React.ForwardRefExoticComponent<Props<CellBase<any>> & React.RefAttributes<unknown>>; /** The default Spreadsheet DataEditor component */ declare const DataEditor: React.FC<DataEditorProps>; /** The default Spreadsheet DataViewer component */ declare const DataViewer: <Cell extends CellBase<Value>, Value>({ cell, evaluatedCell, }: DataViewerProps<Cell>) => React.ReactElement; export { CellBase, CellChange, CellComponent, CellComponentProps, CellDescriptor, ColumnIndicatorComponent, ColumnIndicatorProps, CornerIndicatorComponent, CornerIndicatorProps, DataEditor, DataEditorComponent, DataEditorProps, DataViewer, DataViewerComponent, DataViewerProps, Dimensions, EmptySelection, EntireAxisSelection, EntireColumnsSelection, EntireRowsSelection, EntireSelection, EntireWorksheetSelection, HeaderRowComponent, HeaderRowProps, InvalidIndexError, Matrix, Mode, Model, Point, PointRange, Props, RangeSelection, RowComponent, RowIndicatorComponent, RowIndicatorProps, RowProps, Selection, _default as Spreadsheet, SpreadsheetRef, TableComponent, TableProps, createEmpty as createEmptyMatrix, createFormulaParser, _default as default };