import React, { PureComponent, type ReactNode, type RefObject } from 'react'; import GridMetricCalculator, { type GridMetricState } from './GridMetricCalculator'; import type GridModel from './GridModel'; import { type GridMouseEvent, type GridMouseHandlerFunctionName } from './GridMouseHandler'; import type GridMouseHandler from './GridMouseHandler'; import { type GridTheme as GridThemeType } from './GridTheme'; import GridRange, { type GridRangeIndex, SELECTION_DIRECTION } from './GridRange'; import GridRenderer from './GridRenderer'; import { type GridPoint, type Token } from './GridUtils'; import { type GridSeparator } from './mouse-handlers'; import './Grid.scss'; import { type GridKeyHandlerFunctionName, type GridKeyboardEvent } from './KeyHandler'; import type KeyHandler from './KeyHandler'; import { type Coordinate, type ModelIndex, type MoveOperation, type VisibleIndex } from './GridMetrics'; import type GridMetrics from './GridMetrics'; import ThemeContext from './ThemeContext'; import { type DraggingColumn } from './mouse-handlers/GridColumnMoveMouseHandler'; import { type EditingCell, type GridRenderState, type EditingCellTextSelectionRange, type CellInputRendererRegistry } from './GridRendererTypes'; export type GridProps = typeof Grid.defaultProps & { children?: ReactNode; canvasOptions?: CanvasRenderingContext2DSettings; isStickyBottom?: boolean; isStickyRight?: boolean; isStuckToBottom?: boolean; isStuckToRight?: boolean; metricCalculator?: GridMetricCalculator; model: GridModel; keyHandlers?: readonly KeyHandler[]; mouseHandlers?: readonly GridMouseHandler[]; movedColumns?: readonly MoveOperation[]; movedRows?: readonly MoveOperation[]; onError?: (e: Error) => void; onSelectionChanged?: (ranges: readonly GridRange[]) => void; onMovedColumnsChanged?: (movedColumns: readonly MoveOperation[]) => void; onMovedRowsChanged?: (movedRows: readonly MoveOperation[]) => void; onMoveColumnComplete?: (movedColumns: readonly MoveOperation[]) => void; onMoveRowComplete?: (movedRows: readonly MoveOperation[]) => void; onViewChanged?: (metrics: GridMetrics) => void; onTokenClicked?: (token: Token) => void; renderer?: GridRenderer; /** * Registry of cell input renderer functions keyed by column restriction type. * Grid looks up columnRestrictions[0].type at render time and falls back to * its built-in CellInputField when there is no match. */ cellInputRendererRegistry?: CellInputRendererRegistry; stateOverride?: Record; theme?: Partial; }; export type GridState = { top: VisibleIndex; left: VisibleIndex; topOffset: number; leftOffset: number; draggingColumn: DraggingColumn | null; draggingRow: VisibleIndex | null; draggingRowOffset: number | null; draggingColumnSeparator: GridSeparator | null; draggingRowSeparator: GridSeparator | null; isDraggingHorizontalScrollBar: boolean; isDraggingVerticalScrollBar: boolean; isDragging: boolean; mouseX: number | null; mouseY: number | null; movedColumns: readonly MoveOperation[]; movedRows: readonly MoveOperation[]; cursorRow: VisibleIndex | null; cursorColumn: VisibleIndex | null; selectionStartRow: VisibleIndex | null; selectionStartColumn: VisibleIndex | null; selectionEndRow: VisibleIndex | null; selectionEndColumn: VisibleIndex | null; selectedRanges: readonly GridRange[]; lastSelectedRanges: readonly GridRange[]; cursor: string | null; editingCell: EditingCell | null; isStuckToBottom: boolean; isStuckToRight: boolean; /** * Errors thrown during a render animation frame. * These are not caught by the grid panel, * so we need to throw them in componentDidUpdate */ renderError?: unknown; /** What revision the grid is drawing. Automatically increments when a forceUpdate is called. */ updateRevision: number; }; /** * High performance, extendible, themeable grid component. * Architectured to be fast and handle billions of rows/columns by default. * The base model does not provide support for sorting, filtering, etc. * To get that functionality, extend GridModel/GridRenderer, and add onClick/onContextMenu handlers to implement your own sort. * * Extend GridModel with your own data model to provide the data for the grid. * Extend GridTheme to change the appearance if the grid. See GridTheme for all the settable values. * Extend GridMetricCalculator to provide different metrics for the grid, such as column sizing, header sizing, etc. * Extend GridRenderer to have complete control over the rendering process. Can override just one method such as drawColumnHeader, or override the whole drawCanvas process. * * Add an onViewChanged callback to page in/out data as user moves around the grid * Can also add onClick and onContextMenu handlers to add custom functionality and menus. */ declare class Grid extends PureComponent { static contextType: React.Context>; context: React.ContextType; static defaultProps: { canvasOptions: CanvasRenderingContext2DSettings; isStickyBottom: boolean; isStickyRight: boolean; isStuckToBottom: boolean; isStuckToRight: boolean; keyHandlers: readonly KeyHandler[]; mouseHandlers: readonly GridMouseHandler[]; movedColumns: readonly MoveOperation[]; movedRows: readonly MoveOperation[]; onError: () => void; onSelectionChanged: () => void; onMovedColumnsChanged: (moveOperations: readonly MoveOperation[]) => void; onMoveColumnComplete: () => void; onMovedRowsChanged: () => void; onMoveRowComplete: () => void; onViewChanged: (metrics: GridMetrics) => void; onTokenClicked: (token: Token) => void; cellInputRendererRegistry: CellInputRendererRegistry; stateOverride: Record; theme: Partial; }; static pixelsPerLine: number; static dragTimeout: number; static getTheme: (contextTheme: Partial, userTheme: Partial) => { allowColumnResize: boolean; allowRowResize: boolean; autoSelectRow: boolean; autoSelectColumn: boolean; autoSizeColumns: boolean; autoSizeRows: boolean; backgroundColor: import("./GridTheme").GridColor; textColor: import("./GridTheme").GridColor; hyperlinkColor: import("./GridTheme").GridColor; black: import("./GridTheme").GridColor; white: import("./GridTheme").GridColor; cellHorizontalPadding: number; headerHorizontalPadding: number; font: import("./GridTheme").GridFont; gridColumnColor: import("./GridTheme").NullableGridColor; gridRowColor: import("./GridTheme").NullableGridColor; headerBackgroundColor: import("./GridTheme").GridColor; headerSeparatorColor: import("./GridTheme").GridColor; headerSeparatorHoverColor: import("./GridTheme").GridColor; headerSeparatorHandleSize: number; headerHiddenSeparatorSize: number; headerHiddenSeparatorHoverColor: import("./GridTheme").GridColor; headerColor: import("./GridTheme").GridColor; headerFont: import("./GridTheme").GridFont; columnHoverBackgroundColor: import("./GridTheme").NullableGridColor; selectedColumnHoverBackgroundColor: import("./GridTheme").NullableGridColor; rowHoverBackgroundColor: import("./GridTheme").NullableGridColor; selectedRowHoverBackgroundColor: import("./GridTheme").NullableGridColor; rowBackgroundColors: import("./GridTheme").GridColorWay; minScrollHandleSize: number; scrollBarBackgroundColor: import("./GridTheme").GridColor; scrollBarHoverBackgroundColor: import("./GridTheme").GridColor; scrollBarCasingColor: import("./GridTheme").GridColor; scrollBarCornerColor: import("./GridTheme").GridColor; scrollBarColor: import("./GridTheme").GridColor; scrollBarHoverColor: import("./GridTheme").GridColor; scrollBarActiveColor: import("./GridTheme").GridColor; scrollBarSize: number; scrollBarHoverSize: number; scrollBarCasingWidth: number; scrollSnapToColumn: boolean; scrollSnapToRow: boolean; scrollBarSelectionTick: boolean; scrollBarSelectionTickColor: import("./GridTheme").NullableGridColor; scrollBarActiveSelectionTickColor: import("./GridTheme").NullableGridColor; activeCellSelectionBorderWidth: number; selectionColor: import("./GridTheme").GridColor; selectionOutlineColor: import("./GridTheme").GridColor; selectionOutlineCasingColor: import("./GridTheme").GridColor; shadowBlur: number; shadowColor: import("./GridTheme").GridColor; shadowAlpha: number; maxDepth: number; treeDepthIndent: number; treeHorizontalPadding: number; treeLineColor: import("./GridTheme").GridColor; treeMarkerColor: import("./GridTheme").GridColor; treeMarkerHoverColor: import("./GridTheme").GridColor; rowHeight: number; columnWidth: number; minRowHeight: number; minColumnWidth: number; maxColumnWidth: number; columnHeaderHeight: number; rowHeaderWidth: number; rowFooterWidth: number; headerResizeSnapThreshold: number; headerResizeHiddenSnapThreshold: number; allowColumnReorder: boolean; allowRowReorder: boolean; reorderOffset: number; floatingGridColumnColor: import("./GridTheme").NullableGridColor; floatingGridRowColor: import("./GridTheme").NullableGridColor; floatingRowBackgroundColors: import("./GridTheme").GridColorWay; floatingDividerOuterColor: import("./GridTheme").GridColor; floatingDividerInnerColor: import("./GridTheme").GridColor; zeroLineColor: import("./GridTheme").GridColor; positiveBarColor: import("./GridTheme").GridColor; negativeBarColor: import("./GridTheme").GridColor; markerBarColor: import("./GridTheme").GridColor; dataBarHorizontalPadding: number; }; /** * On some devices there may be different scaling required for high DPI. Get the scale required for the canvas. * @param context The canvas context * @returns The scale to use */ static getScale(context: CanvasRenderingContext2D): number; /** * Get the class name from the cursor provided * @param cursor The grid cursor to use * @returns Class name with the grid-cursor prefix or null if no cursor provided */ static getCursorClassName(cursor: string | null): string | null; renderer: GridRenderer; metricCalculator: GridMetricCalculator; canvas: HTMLCanvasElement | null; canvasContext: CanvasRenderingContext2D | null; canvasWrapper: RefObject; resizeObserver: ResizeObserver; animationFrame: number | null; prevMetrics: GridMetrics | null; metrics: GridMetrics | null; renderState: GridRenderState; documentCursor: string | null; hasAddedBlockEvents: boolean; dragTimer: ReturnType | null; keyHandlers: readonly KeyHandler[]; mouseHandlers: readonly GridMouseHandler[]; constructor(props: GridProps); componentDidMount(): void; componentDidUpdate(prevProps: GridProps, prevState: GridState): void; componentWillUnmount(): void; getTheme(): GridThemeType; getGridPointFromEvent(event: GridMouseEvent): GridPoint; getGridPointFromXY(x: Coordinate, y: Coordinate): GridPoint; getMetricState(state?: Readonly): GridMetricState; getCachedKeyHandlers: (keyHandlers: readonly KeyHandler[]) => KeyHandler[]; getKeyHandlers(): readonly KeyHandler[]; getCachedMouseHandlers: (mouseHandlers: readonly GridMouseHandler[]) => readonly GridMouseHandler[]; getMouseHandlers(): readonly GridMouseHandler[]; /** * Translate from the provided visible index to the model index * @param columnIndex The column index to get the model for * @returns The model index */ getModelColumn(columnIndex: VisibleIndex): ModelIndex; /** * Translate from the provided visible index to the model index * @param rowIndex The row index to get the model for * @returns The model index */ getModelRow(rowIndex: VisibleIndex): ModelIndex; /** * Toggle a row between expanded and collapsed states * @param row The row to toggle expansion for * @param expandDescendants True if nested rows should be expanded, false otherwise */ toggleRowExpanded(row: VisibleIndex, expandDescendants?: boolean): void; getStickyScrollPosition(isStickyBottom: boolean, isStickyRight: boolean): { top: VisibleIndex; left: VisibleIndex; }; /** * Allows the selected ranges to be set programatically * Will update the cursor and selection start/end based on the new ranges * @param gridRanges The new selected ranges to set */ setSelectedRanges(gridRanges: readonly GridRange[]): void; initContext(): void; requestUpdateCanvas(): void; /** * Updates the canvas, metrics, and render state, then draws the canvas. */ updateCanvas(): void; private updateCanvasScale; updateScrollBounds(): void; /** * Compares the current metrics with the previous metrics to see if we need to scroll when it is stuck to the bottom or the right */ needToUpdateScroll(): boolean; updateMetrics(state?: Readonly): GridMetrics; /** * Check if the selection state has changed, and call the onSelectionChanged callback if they have * @param prevState The previous grid state */ checkSelectionChange(prevState: GridState): void; /** * Validate the current selection, and reset if it is invalid * @returns True if the selection is valid, false if the selection was invalid and has been reset */ validateSelection(): boolean; /** * Clears all selected ranges */ clearSelectedRanges(): void; /** Clears all but the last selected range */ trimSelectedRanges(): void; /** Gets the selected ranges */ getSelectedRanges(): readonly GridRange[]; /** * Begin a selection operation at the provided location * @param column Column where the selection is beginning * @param row Row where the selection is beginning */ beginSelection(column: GridRangeIndex, row: GridRangeIndex): void; /** * Moves the selection to the cell specified * @param column The column index to move the cursor to * @param row The row index to move the cursor to * @param extendSelection Whether to extend the current selection (eg. holding Shift) * @param maximizePreviousRange When true, maximize/add to the previous range only, ignoring where the selection was started. */ moveSelection(column: GridRangeIndex, row: GridRangeIndex, extendSelection?: boolean, maximizePreviousRange?: boolean): void; /** * Commits the last selected range to the selected ranges. * First checks if the last range is completely contained within another range, and if it * is then it blows those ranges apart. * Then it consolidates all the selected ranges, reducing them. */ commitSelection(): void; setFocusRow(focusedRow: number): void; /** * Set the selection to the entire grid */ selectAll(): void; /** * Move the cursor in relation to the current cursor position * @param deltaColumn Number of columns to move the cursor * @param deltaRow Number of rows to move the cursor * @param extendSelection True if the current selection should be extended, false to start a new selection */ moveCursor(deltaColumn: number, deltaRow: number, extendSelection: boolean): void; /** * Move the cursor in the provided selection direction * @param direction The direction to move the cursor in */ moveCursorInDirection(direction?: SELECTION_DIRECTION): void; /** * Move a cursor to the specified position in the grid. * @param column The column index to move the cursor to * @param row The row index to move the cursor to * @param extendSelection Whether to extend the current selection (eg. holding Shift) * @param keepCursorInView Whether to move the viewport so that the cursor is in view * @param maximizePreviousRange With this and `extendSelection` true, it will maximize/add to the previous range only, ignoring where the selection was started */ moveCursorToPosition(column: GridRangeIndex, row: GridRangeIndex, extendSelection?: boolean, keepCursorInView?: boolean, maximizePreviousRange?: boolean): void; /** * Moves the view to make the specified cell visible * * @param column The column index to bring into view * @param row The row index to bring into view */ moveViewToCell(column: GridRangeIndex, row: GridRangeIndex): void; /** * Checks the `top` and `left` properties that are set and updates the isStuckToBottom/Right properties * Should be called when user interaction occurs * @param viewState New state properties to set. * @param forceUpdate Whether to force an update. */ setViewState(viewState: Partial, forceUpdate?: boolean): void; /** * Start editing the data at the given index * * @param column The visible column index to start editing * @param row The visible row index to start editing * @param isQuickEdit If this is a quick edit (the arrow keys can commit) * @param selectionRange The tuple [start,end] text selection range of the value to select when editing * @param value The value to start with in the edit field. Leave undefined to use the current value. */ startEditing(column: VisibleIndex, row: VisibleIndex, isQuickEdit?: boolean, selectionRange?: EditingCellTextSelectionRange, value?: string): void; /** * Check if a value is valid for a specific cell * @param column Column index of the cell to check * @param row Row index of the cell to check * @param value Value to check * @returns True if the value is valid for the provided cell, false otherwise */ isValidForCell(column: VisibleIndex, row: VisibleIndex, value: string): boolean; /** * Paste a value with the current selection * It first needs to validate that the pasted table is valid for the given selection. * Also may update selection if single cells are selected and a table is pasted. * @param value Table or a string that is being pasted */ pasteValue(value: string[][] | string): Promise; /** * Set a value to a specific cell. If the value is not valid for that cell, do not set it * @param column Column index to set the value for * @param row Row index to set the value for * @param value Value to set at that cell * @returns true If the value was valid and attempted to be set, false is it was not valid */ setValueForCell(column: VisibleIndex, row: VisibleIndex, value: string): boolean; /** * Set a value on all the ranges provided * @param ranges Ranges to set * @param value The value to set on all the ranges */ setValueForRanges(ranges: readonly GridRange[], value: string): void; /** * Check if a given cell is within the current selection * @param row Row to check * @param column Column to check * @returns True if the cell is in the current selection, false otherwise */ isSelected(row: VisibleIndex, column: VisibleIndex): boolean; addDocumentCursor(cursor?: string | null): void; removeDocumentCursor(): void; startDragTimer(event: React.MouseEvent): void; stopDragTimer(): void; /** * Draw the grid with the metrics provided * When scrolling you've have to re-draw the whole canvas. As a consequence, all these drawing methods * must be very quick. */ private drawCanvas; /** * Set focus to this grid element */ focus(): void; /** * Check if this grid is currently focused * @returns True if the active element is this grid */ isFocused(): boolean; /** * Handle a mouse click event. Pass the event to the registered mouse handlers until one handles it. * Focuses the grid after the click. * @param event The mouse event */ handleClick(event: React.MouseEvent): void; /** * Handle a mouse context menu event. Pass the event to the registered mouse handlers until one handles it. * @param event The mouse event triggering the context menu */ handleContextMenu(event: React.MouseEvent): void; /** * Notify all of the keyboard handlers for this grid of a keyboard event. * @param functionName The name of the function in the keyboard handler to call * @param event The keyboard event to notify */ notifyKeyboardHandlers(functionName: GridKeyHandlerFunctionName, event: GridKeyboardEvent): void; handleKeyDown(event: GridKeyboardEvent): void; handleKeyUp(event: GridKeyboardEvent): void; /** * Notify all of the mouse handlers for this grid of a mouse event. * @param functionName The name of the function in the mouse handler to call * @param event The mouse event to notify * @param updateCoordinates Whether to update the mouse coordinates * @param addCursorToDocument Whether to add a cursor overlay or not (for dragging) */ notifyMouseHandlers(functionName: GridMouseHandlerFunctionName, event: GridMouseEvent, updateCoordinates?: boolean, addCursorToDocument?: boolean): void; handleMouseDown(event: React.MouseEvent): void; handleDoubleClick(event: React.MouseEvent): void; handleMouseMove(event: React.MouseEvent): void; handleMouseLeave(event: React.MouseEvent): void; handleMouseDrag(event: MouseEvent): void; handleMouseUp(event: MouseEvent): void; handleResize(): void; forceUpdate(callback?: (() => void) | undefined): void; handleWheel(event: WheelEvent): void; /** * Handle cancelling the cell edit action */ handleEditCellCancel(): void; /** * Handle a change in the value in an editing cell * @param value New value set */ handleEditCellChange(value: string): void; /** * Commit an edit for the currently editing cell * @param value Value that was committed * @param options Options for committing */ handleEditCellCommit(value: string, { direction, fillRange, }?: { direction?: SELECTION_DIRECTION | null; fillRange?: boolean; }): void; renderInputField(): ReactNode; /** * Gets the render state * @returns The render state */ updateRenderState(): GridRenderState; render(): ReactNode; } export default Grid; //# sourceMappingURL=Grid.d.ts.map