UNPKG

hightable

Version:

A dynamic windowed scrolling table component for react

149 lines (148 loc) 6.2 kB
import type { OrderBy } from '../sort.js'; import type { CustomEventTarget } from '../typedEventTarget.js'; export type Obj = Record<string, any>; export type Cells = Obj; /** * A resolved value wrapping the actual value. */ export interface ResolvedValue<T = any> { /** The actual value. Can be undefined. */ value: T; } /** * Events emitted by DataFrame instances. */ export interface DataFrameEvents { /** * Emitted when the number of rows has changed. */ numrowschange: undefined; /** * Emitted when a cell value has resolved. */ resolve: undefined; /** * Emitted when some data has been updated (e.g. a cell value). */ update: undefined; } /** * Descriptor for a single column in a DataFrame. */ export interface ColumnDescriptor<C extends Obj = Obj> { /** Column name */ name: string; /** Whether the column is sortable. Defaults to false. */ sortable?: boolean; /** Custom metadata extendable by the user */ metadata?: C; } export type Fetch = ({ rowStart, rowEnd, columns, orderBy, signal }: { rowStart: number; rowEnd: number; columns?: string[]; orderBy?: OrderBy; signal?: AbortSignal; }) => Promise<void>; /** * DataFrame is an interface for a data structure that represents a table of immutable data. * * The data can be fetched in chunks, and the table can subscribe to changes using the eventTarget. * * The methods getCell, getRowNumber, and fetch should respect the columns' `sortable` property: * - sort along the sortable columns when `orderBy` is provided, * - throw an error if a column within `orderBy` is not sortable. */ export interface DataFrame<M extends Obj = Obj, C extends Obj = Obj> { /** Number of rows in the data frame. * * Trigger a "numrowschange" event when it changes (can be implemented with a getter and a setter, emitting the event on set). * * If numRows can change, be careful to take it into account in getCell, getRowNumber and fetch implementations, * for example when validating the row parameter. */ numRows: number; /** * Descriptors for all columns in the data frame, in order. * * Includes the column name, whether it's sortable, and any custom metadata. */ columnDescriptors: ColumnDescriptor<C>[]; /** Custom metadata about the data frame */ metadata?: M; /** * If false, multiple columns can be sorted at the same time, and orderBy is treated as a list of sort criteria. * * If true, only one column can be sorted at a time, and any update to orderBy will replace the previous one. * * Defaults to false. */ exclusiveSort?: boolean; /** * Get the value of a cell at the given row and column, optionally sorted by orderBy. * * getCell does NOT initiate a fetch, it just returns resolved data. * * @param row - The row index in the data frame (0 = first row). * @param column - The column name. * @param orderBy - Optional sorting criteria. * @returns The resolved cell value (a boxed value type, so we can distinguish undefined from pending), or undefined if the value is not available yet. */ getCell({ row, column, orderBy }: { row: number; column: string; orderBy?: OrderBy; }): ResolvedValue | undefined; /** * Get the row number (index in the underlying data) for the given row index in the dataframe. * * getRowNumber does NOT initiate a fetch, it just returns resolved data. * * The result can be different from the row parameter when the dataframe is the result of a sampling operation, * a filter, a sort, or any operation that changes the order or the set of rows. In the case of a sampling operation, for example, the row number is the index in the original data. * * @param row - The row index in the data frame (0 = first row). * @param orderBy - Optional sorting criteria. * @returns The resolved row number (a boxed value type, by analogy to getCell), or undefined if the value is not available yet. */ getRowNumber({ row, orderBy }: { row: number; orderBy?: OrderBy; }): ResolvedValue<number> | undefined; /** * Fetch the required data (the required columns and the row numbers) asynchronously. * * This method is optional, as static data frames might not need to fetch any data. * * Checks if the required data (the required columns and the row numbers) is available, * and it not, it fetches it. * * The client can use an AbortController and pass its .signal, to be able to cancel with .abort() when the data is not required anymore. * The dataframe implementer can choose to ignore, de-queue, or cancel in-flight fetches. * * It rejects on the first error, which can be the signal abort (it must throw `AbortError`). * * It's responsible for dispatching the "resolve" event when data has resolved * (ie: when some new data is available synchronously with the methods `getCell` and `getRowNumber`). * It can dispatch the events multiple times if the data is fetched in chunks. * * @param rowStart - The start row index (inclusive, 0 = first row). * @param rowEnd - The end row index (exclusive). * @param columns - The list of column names to fetch. If undefined or an empty array, only the row numbers must be fetched. * @param orderBy - Optional sorting criteria. * @param signal - Optional AbortSignal to cancel the fetch. * @returns A void promise which resolves when all the data has been fetched. Note that it does not return the data. */ fetch?: Fetch; /** * Event target to subscribe to DataFrame events. * * If the DataFrame is static and does not emit events, this can be undefined. * * See DataFrameEvents for the list of events. * * To listen to events, use eventTarget.addEventListener('eventname', callback). * To emit events, use eventTarget.dispatchEvent(new CustomEvent('eventname')). */ eventTarget?: CustomEventTarget<DataFrameEvents>; }