Refactor DeesTable component: modularize data handling and styles
- Moved column computation and data retrieval logic to a new data.ts file for better separation of concerns. - Created a styles.ts file to encapsulate all CSS styles related to the DeesTable component. - Updated the DeesTable class to utilize the new data handling functions and styles. - Introduced selection and filtering features, allowing for single and multi-row selection. - Enhanced rendering logic to accommodate selection checkboxes and filtering capabilities. - Re-exported types from types.ts for better type management and clarity.
This commit is contained in:
78
ts_web/elements/dees-table/data.ts
Normal file
78
ts_web/elements/dees-table/data.ts
Normal file
@@ -0,0 +1,78 @@
|
||||
import type { Column, TDisplayFunction } from './types.js';
|
||||
|
||||
export function computeColumnsFromDisplayFunction<T>(
|
||||
displayFunction: TDisplayFunction<T>,
|
||||
data: T[]
|
||||
): Column<T>[] {
|
||||
if (!data || data.length === 0) return [];
|
||||
const firstTransformedItem = displayFunction(data[0]);
|
||||
const keys: string[] = Object.keys(firstTransformedItem);
|
||||
return keys.map((key) => ({
|
||||
key,
|
||||
header: key,
|
||||
value: (row: T) => displayFunction(row)[key],
|
||||
}));
|
||||
}
|
||||
|
||||
export function computeEffectiveColumns<T>(
|
||||
columns: Column<T>[] | undefined,
|
||||
augmentFromDisplayFunction: boolean,
|
||||
displayFunction: TDisplayFunction<T>,
|
||||
data: T[]
|
||||
): Column<T>[] {
|
||||
const base = (columns || []).slice();
|
||||
if (!augmentFromDisplayFunction) return base;
|
||||
const fromDisplay = computeColumnsFromDisplayFunction(displayFunction, data);
|
||||
const existingKeys = new Set(base.map((c) => String(c.key)));
|
||||
for (const col of fromDisplay) {
|
||||
if (!existingKeys.has(String(col.key))) {
|
||||
base.push(col);
|
||||
}
|
||||
}
|
||||
return base;
|
||||
}
|
||||
|
||||
export function getCellValue<T>(row: T, col: Column<T>, displayFunction?: TDisplayFunction<T>): any {
|
||||
return col.value ? col.value(row) : (row as any)[col.key as any];
|
||||
}
|
||||
|
||||
export function getViewData<T>(
|
||||
data: T[],
|
||||
effectiveColumns: Column<T>[],
|
||||
sortKey?: string,
|
||||
sortDir?: 'asc' | 'desc' | null,
|
||||
filterText?: string
|
||||
): T[] {
|
||||
let arr = data.slice();
|
||||
const ft = (filterText || '').trim().toLowerCase();
|
||||
if (ft) {
|
||||
arr = arr.filter((row) => {
|
||||
for (const col of effectiveColumns) {
|
||||
if (col.hidden) continue;
|
||||
const val = getCellValue(row, col);
|
||||
const s = String(val ?? '').toLowerCase();
|
||||
if (s.includes(ft)) return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
if (!sortKey || !sortDir) return arr;
|
||||
const col = effectiveColumns.find((c) => String(c.key) === sortKey);
|
||||
if (!col) return arr;
|
||||
const dir = sortDir === 'asc' ? 1 : -1;
|
||||
arr.sort((a, b) => {
|
||||
const va = getCellValue(a, col);
|
||||
const vb = getCellValue(b, col);
|
||||
if (va == null && vb == null) return 0;
|
||||
if (va == null) return -1 * dir;
|
||||
if (vb == null) return 1 * dir;
|
||||
if (typeof va === 'number' && typeof vb === 'number') return (va - vb) * dir;
|
||||
const sa = String(va).toLowerCase();
|
||||
const sb = String(vb).toLowerCase();
|
||||
if (sa < sb) return -1 * dir;
|
||||
if (sa > sb) return 1 * dir;
|
||||
return 0;
|
||||
});
|
||||
return arr;
|
||||
}
|
||||
|
Reference in New Issue
Block a user