Smartable/src/Smartable/Row.tsx
Madeorsk 519facc608
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
Add columns filters system and default StringFilter dans NumberFilter.
2024-07-28 14:18:17 +02:00

134 lines
3 KiB
TypeScript

import React, {useContext} from "react";
import {AutoColumnContextProvider, ColumnContext, ColumnKey} from "./Column";
import {CellDefinition, CellInstance, CellLoader} from "./Cell";
import {Smartable, useTable} from "./Smartable";
import { Promisable} from "@kernelui/core";
import {CurrentRowData} from "./AsyncManager";
/**
* Smartable row cells.
*/
export type RowCells<CK extends ColumnKey, T = any> = Record<CK, Promisable<CellDefinition<T>>>;
/**
* Smartable row data.
*/
export interface RowData<CK extends ColumnKey, T = any>
{
/**
* Cells definition.
*/
cells: RowCells<CK, T>;
/**
* Rendered row element.
*/
element?: React.ReactElement;
/**
* Rendered row cell element.
*/
cellElement?: React.ReactElement;
}
/**
* Smartable row definition.
*/
export type RowDefinition<CK extends ColumnKey> = RowCells<CK>|RowData<CK>;
/**
* Normalize row definition to row data.
*/
export function normalizeRowDefinition<CK extends ColumnKey>(rowDefinition: RowDefinition<CK>): RowData<CK>
{
if (!("cells" in rowDefinition) || !Object.values(rowDefinition?.cells).some((cellData: Promisable<CellDefinition>) => (
cellData instanceof Promise || ("data" in cellData)
))) { // If the row definition doesn't form a RowData object (= it is a RowCell object), converting it.
rowDefinition = {
cells: rowDefinition as RowCells<CK>,
};
}
// Return changed row definition, or just keep the default one if it matched RowData.
return rowDefinition;
}
/**
* Table row context data.
*/
export interface RowContextData<CK extends ColumnKey, T = any> extends CurrentRowData<CK, T>
{
}
const RowContext = React.createContext<RowContextData<ColumnKey>>(undefined);
/**
* Hook to get current row data.
*/
export function useRow<CK extends ColumnKey, T = any>(smartable?: Smartable<CK>): RowContextData<CK, T>
{
return useContext(RowContext);
}
/**
* Default row component.
*/
export function Row()
{
return (
<tr>
<RowCells />
</tr>
);
}
export function RowCells()
{
// Get row data.
const row = useRow();
// Get table data.
const {columns} = useTable();
return (
Object.keys(columns).map((columnKey) => (
<AutoColumnContextProvider key={columnKey} columnKey={columnKey}>
{ // Show current cell.
row.cells?.[columnKey]
? <CellInstance cell={row.cells?.[columnKey]} />
: <CellLoader />
}
</AutoColumnContextProvider>
))
);
}
/**
* Row instance component.
*/
export function RowInstance<CK extends ColumnKey>({row}: { row: CurrentRowData<CK> })
{
// Get table row element.
const {rowElement} = useTable();
return (
<RowContext.Provider value={row}>
{ // Trying to render row-specific element, then table-specific element, then default element.
row.element ?? rowElement ?? <Row />
}
</RowContext.Provider>
);
}
/**
* Animated row loader.
*/
export function RowLoader()
{
// Get table columns to get their count.
const {columns} = useTable();
return (
<tr><td colSpan={Object.keys(columns).length} className={"generic loader"}></td></tr>
)
}