UNPKG

@oceanbase-odc/ob-react-data-grid

Version:

Excel-like grid component built with React, with editors, keyboard navigation, copy & paste, and the like

396 lines 14.6 kB
import type { ReactElement } from 'react'; import React from 'react'; import { ConnectDropTarget, ConnectDragSource, ConnectDragPreview } from 'react-dnd'; export interface ISelectorEvent { rowIdx: number; columnIdx: number; isShiftClick?: boolean; isCtrlClick?: boolean; isUpdateIndex?: boolean; enableEditor?: boolean; mode?: RangeMode; } export type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>; export interface Column<TRow = any, TSummaryRow = unknown> { /** The name of the column. By default it will be displayed in the header cell */ name: string | ReactElement; /** A unique key to distinguish each column */ key: string; /** Column width. If not specified, it will be determined automatically based on grid width and specified widths of other columns */ width?: number | string; /** Minimum column width in px. */ minWidth?: number; /** Maximum column width in px. */ maxWidth?: number; dataType?: 'number' | 'string'; cellClass?: string | ((row: TRow, isRowCellSelected?: boolean) => string | undefined); headerCellClass?: string; summaryCellClass?: string | ((row: TSummaryRow) => string); /** Formatter to be used to render the cell content */ formatter?: React.ComponentType<FormatterProps<TRow, TSummaryRow>>; /** Formatter to be used to render the summary cell content */ summaryFormatter?: React.ComponentType<SummaryFormatterProps<TSummaryRow, TRow>>; /** Formatter to be used to render the group cell content */ groupFormatter?: React.ComponentType<GroupFormatterProps<TRow, TSummaryRow>>; /** Enables cell editing. If set and no editor property specified, then a textinput will be used as the cell editor */ editable?: boolean | ((row: TRow) => boolean); /** Determines whether column is frozen or not */ frozen?: boolean; /** Enable resizing of a column */ resizable?: boolean; /** Enable sorting of a column */ sortable?: boolean; /** Enable filter of a column */ filterable?: boolean; clickable?: boolean; /** Sets the column sort order to be descending instead of ascending the first time the column is sorted */ sortDescendingFirst?: boolean; /** Editor to be rendered when cell of column is being edited. If set, then the column is automatically set to be editable */ editor?: React.ComponentType<EditorProps<TRow, TSummaryRow>>; editorOptions?: { /** @default false */ createPortal?: boolean; /** @default false */ editOnClick?: boolean; /** Prevent default to cancel editing */ onCellKeyDown?: (event: React.KeyboardEvent<HTMLDivElement>) => void; /** Control the default cell navigation behavior while the editor is open */ onNavigation?: (event: React.KeyboardEvent<HTMLDivElement>) => boolean; }; /** Header renderer for each header cell */ headerRenderer?: React.ComponentType<HeaderRendererProps<TRow, TSummaryRow>>; /** Component to be used to filter the data of the column */ filterRenderer?: React.ComponentType<FilterRendererProps<TRow, any, TSummaryRow>>; } export interface CalculatedColumn<TRow, TSummaryRow = unknown> extends Column<TRow, TSummaryRow> { idx: number; resizable: boolean; sortable: boolean; frozen: boolean; isLastFrozenColumn: boolean; rowGroup: boolean; formatter: React.ComponentType<FormatterProps<TRow, TSummaryRow>>; } export interface ColumnMetric { width: number; left: number; } export interface Position { rowIdx: number; columnIdx: number; } export interface IRange { rowIdx: number; columnIdx: number; endRowIdx: number; endColumnIdx: number; } export declare enum RangeMode { SELECT = "SELECT", EDIT = "EDIT" } export interface FormatterProps<TRow = any, TSummaryRow = any> { rowIdx: number; column: CalculatedColumn<TRow, TSummaryRow>; row: TRow; isCellSelected: boolean; isRowSelected: boolean; onRowSelectionChange: (checked: boolean, isShiftClick: boolean, isCtrlClick: boolean) => void; onRowChange: (row: Readonly<TRow>) => void; onRowReorder?: (sourceRowIndex: number, targetRowIndex: number) => void; enableRowRecord?: boolean; } export interface SummaryFormatterProps<TSummaryRow, TRow = any> { column: CalculatedColumn<TRow, TSummaryRow>; row: TSummaryRow; } export interface GroupFormatterProps<TRow, TSummaryRow = unknown> { groupKey: unknown; column: CalculatedColumn<TRow, TSummaryRow>; childRows: readonly TRow[]; isExpanded: boolean; isCellSelected: boolean; isRowSelected: boolean; onRowSelectionChange: (checked: boolean) => void; toggleGroup: () => void; } export interface SharedEditorProps<TRow> { row?: Readonly<TRow>; rowHeight: number; editorPortalTarget: Element; onRowChange: (row: TRow, commitChanges?: boolean) => void; onClose: (commitChanges?: boolean) => void; } export interface EditorProps<TRow, TSummaryRow = unknown> extends SharedEditorProps<TRow> { rowIdx: number; column: Readonly<CalculatedColumn<TRow, TSummaryRow>>; top: number; left: number; width: number | undefined; } export interface HeaderRendererProps<TRow, TSummaryRow = unknown> { column: CalculatedColumn<TRow, TSummaryRow>; sortInfo: SortInfo; onSort?: (columnKey: string, direction: SortDirection) => void; allRowsSelected: boolean; } interface SelectedCellPropsBase { idx: number; onKeyDown: (event: React.KeyboardEvent<HTMLDivElement>) => void; } export interface EditCellProps<TRow> extends SelectedCellPropsBase { mode: 'EDIT'; editorProps: SharedEditorProps<TRow>; } export interface SelectedCellProps extends SelectedCellPropsBase { mode: 'SELECT'; onFocus: () => void; dragHandleProps?: Pick<React.HTMLAttributes<HTMLDivElement>, 'onMouseDown' | 'onDoubleClick'>; } export interface ISelectRange extends IRange { mode: RangeMode; key?: string | null; } export interface ContextMenuRenderProps<R> { row: R; rowKeyName: string; rowIdx: number; columnKey: string; selectedRange: ISelectRange; contextMenuVisible: boolean; setContextMenuVisible: React.Dispatch<React.SetStateAction<boolean>>; config?: ContextMenuConfig<R>[]; isRowSelected: boolean; isColumnSelected: boolean; } export type ContextMenuRender<R = any> = React.ComponentType<ContextMenuRenderProps<R>>; export interface ContextMenuConfig<TRow> { key: string; text: React.ReactNode; isShowRowSelected?: boolean; disabled?: boolean; children?: ContextMenuConfig<TRow>[]; onClick?: (row: TRow) => void; } export interface getContextMenuConfig<R> { (row: R, column: CalculatedColumn<R, R>): ContextMenuConfig<R>[]; } export interface CellRendererProps<TRow, TSummaryRow = unknown> extends Omit<React.HTMLAttributes<HTMLDivElement>, 'style' | 'children'> { rowIdx: number; column: CalculatedColumn<TRow, TSummaryRow>; columnIdx: number; row: TRow; isRowCellSelected: boolean; lazyStore: Map<string, any>; isModified: boolean; setMouseDown: (isDown: boolean) => void; isDraggedOver: boolean; isCellSelected: boolean; isCellFirstSelected: boolean; isRowSelected: boolean; /** * 所处的 column 是否被选中 */ isColumnSelected: boolean; drop: [ { isOver: boolean; canDrop: boolean; }, ConnectDropTarget ]; drag: [ { isDragging: boolean; }, ConnectDragSource, ConnectDragPreview ]; width: number | undefined; dragHandleProps?: Pick<React.HTMLAttributes<HTMLDivElement>, 'onMouseDown' | 'onDoubleClick'>; onRowChange: (newRow: TRow) => void; onRowReorder?: (sourceRowIndex: number, targetRowIndex: number) => void; onRowClick?: (rowIdx: number, row: TRow, column: CalculatedColumn<TRow, TSummaryRow>) => void; onGridSelect: (data: ISelectorEvent) => void; enableRowRecord?: boolean; selectedRange: ISelectRange; } export interface RowRendererProps<TRow, TSummaryRow = unknown> extends Omit<React.HTMLAttributes<HTMLDivElement>, 'style' | 'children'> { viewportColumns: readonly CalculatedColumn<TRow, TSummaryRow>[]; row: TRow; enableRowRecord?: boolean; getModifiedColumns: (row: TRow) => string[]; isAdd: boolean; isDeleted: boolean; cellRenderer?: React.ComponentType<CellRendererProps<TRow, TSummaryRow>>; rowIdx: number; draggedOverCellIdx?: number; lastFrozenColumnIndex: number; isRowSelected: boolean; isMainSelectedRow: boolean; selectedColumns: Set<string>; totalColumnWidth: number; isLastRow: boolean; isShowRowMenu?: boolean; top: number; selectedCellProps?: EditCellProps<TRow> | SelectedCellProps; lazyStore: Map<string, any>; selectedRange: ISelectRange; setMouseDown: (isDown: boolean) => void; onRowChange: (row: TRow) => void; onRowReorder?: (sourceRowIndex: number, targetRowIndex: number) => void; onRowClick?: (rowIdx: number, row: TRow, column: CalculatedColumn<TRow, TSummaryRow>) => void; rowClass?: (row: TRow) => string | undefined; setDraggedOverRowIdx?: (overRowIdx: number) => void; onGridSelect: (data: ISelectorEvent) => void; columnMetrics: Map<CalculatedColumn<TRow, TSummaryRow>, ColumnMetric>; } export interface FilterRendererProps<TRow, TFilterValue = unknown, TSummaryRow = unknown> { column: CalculatedColumn<TRow, TSummaryRow>; value: TFilterValue; onChange: (value: TFilterValue) => void; } export type Filters = Record<string, Set<any> | undefined>; export type FilterOptions = Record<string, Set<any>> | null; export interface RowsChangeData<R = any, SR = any> { modifiedRows?: R[]; newRows?: R[]; deletedRows?: R[]; indexes?: number[]; column?: CalculatedColumn<R, SR>; } export interface RowChangeType<R = any> { _created?: boolean; _deleted?: boolean; modified?: boolean; _originRow?: R; } export interface SelectRowEvent { rowIdx: number; isShiftClick: boolean; isCtrlClick: boolean; checked?: boolean; } export interface FillEvent<TRow> { columnKey: string; sourceRow: TRow; targetRows: TRow[]; } export interface PasteEvent<TRow> { sourceColumnKey: string; sourceRow: TRow; targetColumnKey: string; targetRow: TRow; } export type CellNavigationMode = 'NONE' | 'CHANGE_ROW' | 'LOOP_OVER_ROW'; export type SortDirection = 'ASC' | 'DESC' | 'NONE'; export type SortInfo = { columnKey: string; direction: SortDirection; }; export type ColSpanArgs<R, SR> = { type: 'HEADER' | 'FILTER'; } | { type: 'ROW'; row: R; } | { type: 'SUMMARY'; row: SR; }; type DefaultColumnOptions<R, SR> = Pick<Column<R, SR>, 'formatter' | 'minWidth' | 'resizable' | 'sortable'>; type SharedDivProps = Pick<React.HTMLAttributes<HTMLDivElement>, 'className' | 'style'>; export interface DataGridProps<R = any, SR = any> extends SharedDivProps, RowsChangeData<R> { /** * Grid and data Props */ /** An array of objects representing each column on the grid */ initialColumns: Column<R, SR>[]; /** A function called for each rendered row that should return a plain key/value pair object */ initialRows: R[]; /** The getter should return a unique key for each row */ rowKeyName?: string; onRowsChange?: (rows: R[]) => void; onColumnChange?: (columns: Column<R, SR>[]) => void; onSelectChange?: (selectedRowsKey: React.Key[], cellColumnsKey?: React.Key[]) => void; /** * Feature props */ defaultColumnOptions?: DefaultColumnOptions<R, SR>; onFill?: (event: FillEvent<R>) => R[]; onPaste?: (event: PasteEvent<R>) => R; onSort?: (columnKey: string, direction: SortDirection) => void; /** * Custom renderers */ rowRenderer?: React.ComponentType<RowRendererProps<R, SR>>; emptyRowsRenderer?: React.ComponentType; /** * Event props */ onCopy?: (ref: DataGridRef<R>) => void; contextMenuRender?: ContextMenuRender<R>; getContextMenuConfig?: getContextMenuConfig<R>; options?: { theme?: 'white' | 'dark'; readonly?: boolean; /** The height of each row in pixels */ rowHeight?: number; /** The height of the header row in pixels */ headerRowHeight?: number; /** The height of the header filter row in pixels */ headerFiltersHeight?: number; /** The height of each summary row in pixels */ summaryRowHeight?: number; /** 行移动 */ enableRowRecord?: boolean; enableColumnRecord?: boolean; /** Toggles whether filters row is displayed or not */ enableFilterRow?: boolean; /** Toggles whether sorters row is displayed or not */ enableSortRow?: boolean; enableFrozenRow?: boolean; enableSelect?: boolean; enableVirtualization?: boolean; enableRowTools?: boolean; enableAddRow?: boolean; enableFlushDelete?: boolean; searchKey?: string; aria?: React.AriaAttributes; cellNavigationMode?: CellNavigationMode; }; /** * Miscellaneous */ /** The node where the editor portal should mount. */ editorPortalTarget?: Element; rowClass?: (row: R) => string | undefined; /** format 粘贴数据,再应用到单元格 */ pasteFormatter?: (row: R, column: Column<R, SR>, value: any) => any; } export interface DataGridRef<R = any> { element: HTMLDivElement | null; columns: Column<R, any>[]; rows: R[]; selectedColumns: Set<string>; selectedRows: Set<string>; selectedRange: ISelectRange; enableFrozenRow: boolean; rowKeyName: string; scrollToColumn: (colIdx: number) => void; scrollToRow: (rowIdx: number, force?: boolean) => void; scrollToNextPage: () => void; scrollToPrevPage: () => void; addRows: (rows: R[]) => void; deleteRows: () => void; rowKeyGetter: (row: { [key: string]: any; }) => string; onRowReorder: (sourceRowIndex: number, targetRowIndex: number) => void; setRows: (rows: R[]) => void; selectCell: (position: Position, isShiftClick?: boolean, enableEditor?: boolean) => void; setColumns: (columns: Column<R, any>[]) => void; setCellsByRowIndex: (rowIdx: number, cells: Record<string, any>) => void; getCellsByRowIndex: (rowIdx: number) => Record<string, any>; } export {}; //# sourceMappingURL=types.d.ts.map