import type { UniComponent } from '../../../_common/components/uni-component/uni-component.js'; import type { TType } from '../../logical/typesystem.js'; import type { DataViewColumnManager, DataViewManager, } from '../data-view-manager.js'; type JSON = | null | number | string | boolean | JSON[] | { [k: string]: JSON; }; export interface CellRenderProps< Data extends NonNullable = NonNullable, Value = unknown, > { view: DataViewManager; column: DataViewColumnManager; rowId: string; isEditing: boolean; selectCurrentCell: (editing: boolean) => void; } export interface DataViewCellLifeCycle { beforeEnterEditMode(): boolean; onEnterEditMode(): void; onExitEditMode(): void; focusCell(): boolean; blurCell(): boolean; forceUpdate(): void; } export type DataViewCellComponent< Data extends NonNullable = NonNullable, Value = unknown, > = UniComponent, DataViewCellLifeCycle>; export type CellRenderer< Data extends NonNullable = NonNullable, Value = unknown, > = { view: DataViewCellComponent; edit?: DataViewCellComponent; }; type ColumnOps< Data extends NonNullable = NonNullable, Value = unknown, > = { name: string; defaultData: () => Data; type: (data: Data) => TType; formatValue?: (value: unknown, colData: Data) => Value; cellToString: (data: Value, colData: Data) => string; cellFromString: ( data: string, colData: Data ) => { value: unknown; data?: Record }; cellToJson: (data: Value, colData: Data) => JSON; addGroup?: (text: string, oldData: Data) => Data; }; type ConvertFunction = ( column: GetColumnDataFromConfig, cells: (GetCellDataFromConfig | undefined)[] ) => { column: GetColumnDataFromConfig; cells: (GetCellDataFromConfig | undefined)[]; }; declare global { // eslint-disable-next-line @typescript-eslint/no-empty-interface export interface ColumnConfigMap {} } export class ColumnConfigManager { // eslint-disable-next-line @typescript-eslint/no-explicit-any private map = new Map>(); getColumn( type: Type ): ColumnConfigMap[Type]; getColumn(type: string): ColumnConfig; getColumn(type: string): ColumnConfig { const column = this.map.get(type); if (!column) { throw new Error(`${type} is not exist`); } return column; } register = Record>( type: string, ops: ColumnOps ) { const config = new ColumnConfig(type, ops); this.map.set(type, config); return config; } } export type GetColumnDataFromConfig = // eslint-disable-next-line @typescript-eslint/no-explicit-any T extends ColumnConfig ? R : never; export type GetCellDataFromConfig = // eslint-disable-next-line @typescript-eslint/no-explicit-any T extends ColumnConfig ? R : never; export class ColumnConfig< T extends NonNullable = NonNullable, CellData = unknown, > { convertMap = new Map(); constructor( public readonly type: string, public ops: ColumnOps ) {} create( name: string, data?: T ): { type: string; name: string; data: T; } { return { type: this.type, name, data: data ?? this.ops.defaultData(), }; } defaultData() { return this.ops.defaultData(); } createWithId( id: string, name: string, data?: T ): { type: string; name: string; data: T; id: string; } { return { id, type: this.type, name, data: data ?? this.ops.defaultData(), }; } dataType(data: T) { return this.ops.type(data); } toString(cellData: CellData, colData: T): string { return this.ops.cellToString(cellData, colData); } toJson(cellData: CellData, colData: T): JSON { return this.ops.cellToJson(cellData, colData); } formatValue(cellData: CellData, colData: T): CellData | undefined { return cellData === undefined ? undefined : this.ops.formatValue?.(cellData, colData) ?? cellData; } fromString(cellData: string, colData: T) { return this.ops.cellFromString(cellData, colData); } convertCell(to: string, column: Record, cells: unknown[]) { return this.convertMap.get(to)?.(column, cells); } registerConvert( to: ToCellName, // @ts-expect-error convert: ConvertFunction ) { this.convertMap.set(to, convert); } get name() { return this.ops.name; } } export const columnManager = new ColumnConfigManager();