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 GestureMode, type GetModel, type Selection } from './Selection'; 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[]; createEmptySelection?: (getModel: GetModel) => Selection; movedColumns?: readonly MoveOperation[]; movedRows?: readonly MoveOperation[]; onError?: (e: Error) => void; /** @deprecated Use onSelectionChange instead. */ onSelectionChanged?: (ranges: readonly GridRange[]) => void; onSelectionChange?: (selection: Selection) => 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[]; selection: Selection; lastSelection: Selection; gestureMode: GestureMode | null; /** * @deprecated Use `selection` instead. Kept for backward compat with consumers * that read `grid.state.selectedRanges` directly. */ selectedRanges: 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; }; /** Selection-related slice of `GridState`. Returned by gesture entry points. */ export type GridSelectionState = Pick; /** * 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; onSelectionChange: (_selection: Selection) => 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; createEmptySelection: (getModel: GetModel) => Selection; }; 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; private renderState; private drawListeners; 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; /** Sets the selection directly, bypassing mouse/keyboard gesture state. */ setSelection(selection: Selection): void; /** Gets the current selection */ getSelection(): Selection; /** @deprecated Use getSelection() instead */ getSelectedRanges(): readonly GridRange[]; /** * Queries the current grid model. * @returns The current GridModel instance. */ getModel(): GridModel; /** * Extend + commit a gesture at `cursor` and return the resulting partial * state. Shared by mouse click-and-release and keyboard commits. * * @param selection Pre-gesture selection to fold against. Cursor landing * reads its extended (pre-commit) form so `KeyedSelection`'s overlay is * still available. * @param cursor Gesture target cell. * @param mode Modifier-derived gesture mode. * @param opts.moveCursor Snap the cursor to `cursor` (default true). * Pass false for keyboard extend / maximize / add so the cursor stays put. * @param opts.allowDeselect Whether committing on top of the same * single-row / single-cell selection should deselect (mouse affordance, * default true). Keyboard callers pass false so arrowing onto an * already-selected cell just moves the cursor. * @param opts.settle Whether the commit should finalize (deselect check, * hole-punch, consolidation). Mouse-down passes false so a drag can grow * the last range before mouse-up finalizes. */ private applyGestureAt; /** * Start a mouse-driven selection gesture at `cursor` with the given * modifier-derived `mode`. Extends the selection per `mode` semantics * and commits immediately so a click without drag settles the state. */ handleMouseSelectStart(cursor: { row: GridRangeIndex; column: GridRangeIndex; }, mode: GestureMode): void; /** * Extend the current mouse selection gesture to `cursor`. Transient * overlay only; the settled commit runs on `handleMouseSelectEnd`. */ handleMouseSelectDrag(cursor: { row: GridRangeIndex; column: GridRangeIndex; }): void; /** Settle the current mouse selection gesture. Called on mouse-up. */ handleMouseSelectEnd(): void; /** * Apply a keyboard-driven selection gesture at `cursor` with `mode`, then * optionally scroll the viewport to bring the cursor into view. Shared * entry point for arrow keys, Home/End, and page-key movements. * * Only `replace` moves the cursor to `cursor`; extend/maximize/add * preserve the existing cursor and update `selectionEnd` only. This * matches long-standing Shift+Arrow semantics where the cursor stays put * as the selection grows. */ handleKeySelectAt(cursor: { row: GridRangeIndex; column: GridRangeIndex; }, mode: GestureMode, opts?: { keepCursorInView?: boolean; }): void; /** * Listen for the grid finishing a draw of its canvas. Called immediately with * the most recent draw if the grid has already drawn. * @param listener Called with the state that was drawn * @returns A function to stop listening */ private registerDrawListener; /** * Advance the cursor in `direction` through the current selection. Used * by Tab/Enter — cycles within the selected ranges when there are * multiple, wraps at grid edges when there is only a single cell. * When the resulting cursor falls outside the current selection (e.g. * from an initial empty state), installs a fresh single-cell selection. */ handleKeyAdvanceCursor(direction: SELECTION_DIRECTION): void; /** * Page-move gesture. `direction` is +1 (page-down) or -1 (page-up). Reads * viewport metrics to compute the target cell, applies the gesture without * auto-scrolling, then pins the viewport top so the cursor lands where it * was on screen before. */ private handleKeyPage; handleKeyPageUp(mode: GestureMode): void; handleKeyPageDown(mode: GestureMode): void; /** * Move the cursor to a cell without touching the selection. */ handleKeyMoveCursor(column: VisibleIndex, row: VisibleIndex): void; setFocusRow(focusedRow: number): void; /** * Set the selection to the entire grid */ selectAll(): 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