Columns
ColumnFilterType, FilterComponentProps, IntervalInputProps, GridColumnDef and 7 more: generated from the source of active-grid.
Exported by @workspace/. Generated from the package source; part of the index of every export.
Functions, hooks and constants#
The same narrowing for the other accessor: does this definition compute its value from the row, and if so with which function?
Symmetrical to has and needed for the same reason. A definition read back from an array is the union, and a caller that wants to invoke the accessor has to establish that there is one; the alternative is an assertion that keeps compiling after the field moves.
<TData, TValue>(column: GridColumnDef<TData, TValue>) => column is GridAccessorFnColumnDef<TData, TValue>The one narrowing for the union above: does this definition read its value by naming a row field, and if so what is that field called?
Reading accessor off a column definition is a real need — hydration prunes a persisted sort against it, the column-type presets key on it. The alternative, a local column as {accessor, is an assertion in a position where a test is available, and it silently keeps working when the field is renamed. This is the test.
It returns the narrowed type rather than a boolean so that the caller reads the field off a definition the compiler agrees has one.
<TData, TValue>(column: GridColumnDef<TData, TValue>) => column is GridAccessorKeyColumnDef<TData, TValue>Types#
type ColumnFilterType =
'text' | 'number' | 'date' | 'select' | 'boolean' | 'interval';Props passed to a custom filter component registered via meta.. The component receives the column instance for reading/writing filter state, and an optional placeholder string derived from the column header.
interface FilterComponentProps {
column: Column;
placeholder?: string;
}Props for a custom boundary-input inside the built-in interval filter (meta.). The interval filter owns the mode toggle, the popover and the apply/clear plumbing; this component owns only the entry of the two numeric bounds. from/to are plain numbers (or null when unset); the implementation reports new bounds via on. This is the seam where a host plugs in a domain-specific entry (a year picker, a price range) without the grid knowing what the numbers mean.
interface IntervalInputProps {
from: number | null;
to: number | null;
onChange: (next: {from: number | null; to: number | null}) => void;
placeholder?: string;
}A column definition.
## It is a union, and that is what makes it a contract
Three kinds, and an invalid definition matches none of them. One consequence for whoever READS a definition back: accessor is not reachable on the union, because two of the three kinds do not have it. Narrow with has rather than asserting the field into existence.
## The one widening in this contract
TValue defaults to any. This is the only place in the public column contract where that type appears, it is named here, and it is a deliberate position rather than a convenience.
The reason is the ARRAY ANNOTATION. Grid is how a column set is declared, and one such array holds columns whose values are a string, a number and nothing at all. A definition that knows its own value type — everything create builds, and everything written as Grid — reaches that array through cell, header and footer, whose contexts carry the value type in a callback PARAMETER. Under strict a parameter is checked contravariantly, so a definition over string is not a definition over unknown, and the array would refuse every column that knows what it holds: with unknown in this position the helper's own output cannot enter an annotated array at all.
What the widening does NOT touch: the metadata key space stays closed, a metadata value of the wrong type is still refused, a key naming no field of the row is still refused, a nested entry is still a definition, and a primitive is still not a column. Those are the negative fixtures in kernel/, and they are asserted against this default rather than against a stricter instantiation.
Naming TValue explicitly gives the strict contract for a single column: Grid refuses a renderer shaped for a number. The widening is the DEFAULT, not the type.
type GridColumnDef<TData, TValue = any> =
| GridAccessorKeyColumnDef<TData, TValue>
| GridAccessorFnColumnDef<TData, TValue>
| GridGroupColumnDef<TData, TValue>;interface GridColumnDefaults<TData = DefaultRowData, TValue = unknown> {
size?: number;
minSize?: number;
maxSize?: number;
enableSorting?: boolean;
enableResizing?: boolean;
enablePinning?: boolean;
enableHiding?: boolean;
meta?: Partial<GridColumnMeta<TData, TValue>>;
}Per-column meta configuration. Fields are grouped by purpose; each group is delimited by a section-marker comment. Categories:
1. Display & alignment — label, header/cell alignment, classNames. 2. Filtering — filterType, customFilter, operator config, filterOptions, date-filter config. 3. Editing — editable, editType, validate, editOptions, valueParser. 4. Aggregation — aggregationFn, aggregationLabel. 5. Cell formatting & tooltips — statusTones, valueFormatter, cellClassRules, tooltips, truncate, wrap. 6. Layout — colSpan, resize/pin, autoSize, flex, responsivePriority, locked. 7. Header customization — headerMenu, headerRenderer, suppressHeaderMenuButton. 8. System — isSystemColumn, suppressFilterIcon, internal _ fields.
A callback that is handed the row's record (TData) is asked about the cells of records only. A row grouping generated stands for no record, so on it such a callback is not asked, and the grid does what it does without one: no edit, no class or style from it, no tooltip from it, no span.
interface GridColumnMeta<TData, TValue> {
label?: string;
headerAlign?: 'left' | 'center' | 'right';
cellAlign?: 'left' | 'center' | 'right';
headerClassName?: string;
cellClassName?: string | ((value: TValue, row: TData) => string | undefined);
headerClass?: (context: HeaderContext<TData, TValue>) => string;
filterType?: ColumnFilterType;
customFilter?: React.ComponentType<FilterComponentProps>;
intervalInput?: React.ComponentType<IntervalInputProps>;
filterOptions?: {label: string; value: string}[];
emptyValueKey?: string;
allowedOperators?: FilterOperator[];
operatorPreset?: BuiltInOperatorPreset | (string & {});
defaultFilterOperator?: FilterOperator;
filterSearchable?: boolean;
filterShowSelectAll?: boolean;
booleanFilterLabels?: {
all?: string;
true?: string;
false?: string;
};
booleanFilterVariant?: 'text' | 'icon';
dateFilterPresets?: DateFilterPreset[] | false;
dateFilterMode?: 'single' | 'range' | 'both';
dateFilterMinDate?: string | Date;
dateFilterMaxDate?: string | Date;
suppressFilterIcon?: boolean;
editable?: boolean | ((row: TData) => boolean);
editType?: ColumnEditType;
validate?: (
value: unknown,
row: TData,
) => string | undefined | Promise<string | undefined>;
editOptions?: {label: string; value: string}[];
valueParser?: (value: string) => unknown;
aggregationFn?: 'sum' | 'avg' | 'count' | 'min' | 'max';
aggregationLabel?: string;
statusTones?: Partial<Record<string, GridStatusTone>>;
semanticType?: 'currency' | 'number' | 'percent' | 'date' | 'dateTime';
datePreset?: DatePreset;
currencyCode?: string;
currencyKey?: string;
currencyDecimals?: number;
numberFormat?: NumberFormat;
percentSource?: 'fraction' | 'percentage-points';
percentPreset?: PercentFormat;
truncate?: boolean;
textDirection?: GridTextDirection;
valueFormatter?: (value: TValue, data: TData) => React.ReactNode;
exportValue?: (value: TValue, data: TData) => unknown;
cellClassRules?: Record<string, (value: TValue, row: TData) => boolean>;
cellStyle?: (value: TValue, row: TData) => React.CSSProperties | undefined;
headerTooltip?: string;
tooltipField?: keyof TData;
tooltipValueGetter?: (value: TValue, row: TData) => string;
showTooltipOnTruncate?: boolean;
wrapText?: boolean;
autoHeight?: boolean;
colSpan?: number | ((row: TData) => number);
enableResizing?: boolean;
autoSizeMaxBodyWidth?: number;
enablePinning?: boolean;
flex?: number;
suppressSizeToFit?: boolean;
locked?: boolean;
responsivePriority?: number;
headerMenu?: GridHeaderMenuConfig;
suppressHeaderMenuButton?: boolean;
headerRenderer?: (props: HeaderRendererProps) => React.ReactNode;
isSystemColumn?: boolean;
_hasCustomCell?: boolean;
_serverFilterCapability?: import('../utils/capability-contract').GridServerFilterCapability;
}type GridColumnTypes<TData = DefaultRowData> = Record<
string,
Partial<GridColumnDef<TData>>
>;Props passed to a custom meta.. Provides everything needed to render sort indicators, filter icons, resize handles, and menu buttons inside a fully custom header cell layout.
interface HeaderRendererProps {
label: React.ReactNode;
isSortable: boolean;
sortDirection: 'asc' | 'desc' | false;
sortIndex: number;
isMultiSort: boolean;
onToggleSort?: (event: unknown) => void;
isFiltered: boolean;
canResize: boolean;
sortIndicator: React.ReactNode;
menuElement: React.ReactNode;
resizeHandle: React.ReactNode;
}The five generic status tones a status cell draws with (meta., <Status).
UI semantics, not domain semantics: the grid does not know what LAPSED or PENDING_ means; the column maps each domain value onto a tone. There is deliberately no pending tone: waiting without attention needed is neutral, waiting that needs attention is warning. Each tone paints with the --grid- tokens, which a host maps onto its own status colours.
type GridStatusTone =
'neutral' | 'info' | 'success' | 'warning' | 'danger';