import { Accessor, createContext, createEffect, createMemo, createSignal, For, JSX, Match, Show, Switch, useContext } from "solid-js"; import { selectable, SelectionProvider, useSelection } from "~/features/selectable"; import { type RowNode, type GroupNode, type Node, createDataSet, toSorted, toGrouped } from './dataset'; import css from './table.module.css'; selectable export type Column = { id: keyof T, label: string, readonly groupBy?: (rows: RowNode[]) => Node[], }; const TableContext = createContext<{ readonly columns: Accessor[]>, readonly selectionMode: Accessor, readonly groupBy: Accessor, readonly sort: Accessor<{ by: string, reversed?: boolean } | undefined>, readonly cellRenderers: Accessor JSX.Element>>, }>(); const useTable = () => useContext(TableContext)! function defaultGroupingFunction(groupBy: keyof T) { return (nodes: RowNode[]): Node[] => Object.entries(Object.groupBy>(nodes, r => r.value[groupBy])) .map>(([key, nodes]) => ({ kind: 'group', key, groupedBy: groupBy, nodes: nodes! })); } export enum SelectionMode { None, Single, Multiple } type TableProps> = { class?: string, rows: T[], columns: Column[], groupBy?: keyof T, sort?: { by: keyof T, reversed?: boolean, }, selectionMode?: SelectionMode, children?: { [K in keyof T]?: (cell: { value: T[K] }) => JSX.Element }, }; export function Table>(props: TableProps) { const [selection, setSelection] = createSignal([]); const columns = createMemo[]>(() => props.columns ?? []); const selectionMode = createMemo(() => props.selectionMode ?? SelectionMode.None); const groupBy = createMemo(() => props.groupBy as string | undefined); const sort = createMemo(() => props.sort as any); const cellRenderers = createMemo(() => props.children ?? {}); return ; }; type InnerTableProps> = { class?: string, rows: T[] }; function InnerTable>(props: InnerTableProps) { const table = useTable(); const selectable = createMemo(() => table.selectionMode() !== SelectionMode.None); const columnCount = createMemo(() => table.columns().length + (selectable() ? 0 : -1)); const nodes = createMemo[]>(() => { const columns = table.columns(); const groupBy = table.groupBy(); const sort = table.sort(); let kaas = createDataSet(props.rows); if (sort) { kaas = toSorted(kaas, { by: sort.by, reversed: sort.reversed ?? false, with: (a, b) => a < b ? -1 : a > b ? 1 : 0 }) } if (groupBy) { kaas = toGrouped(kaas, { by: groupBy, with: columns.find(({ id }) => id === groupBy)?.groupBy ?? defaultGroupingFunction(groupBy) }); } console.log(kaas); const rows = props.rows; if (sort) { rows.sort((a, b) => a[sort.by] < b[sort.by] ? -1 : a[sort.by] > b[sort.by] ? 1 : 0); if (sort.reversed === true) { rows.reverse(); } } const nodes = Object.entries(rows).map>(([i, row]) => ({ kind: 'row', key: i, value: row })); if (groupBy === undefined) { return nodes; } const groupingFunction = columns.find(({ id }) => id === groupBy)?.groupBy ?? defaultGroupingFunction(groupBy); return groupingFunction(nodes); }); return
{ node => }
}; function Head>(props: {}) { const table = useTable(); const context = useSelection(); return
0 && context.selection().length === context.length()} indeterminate={context.selection().length !== 0 && context.selection().length !== context.length()} on:input={(e: InputEvent) => e.target.checked ? context.selectAll() : context.clear()} />
{ column => {column.label} }
; }; function Node>(props: { node: Node, depth: number, groupedBy?: keyof T }) { return { row => } { group => } ; } function Row>(props: { key: string, value: T, depth: number, groupedBy?: keyof T }) { const table = useTable(); const context = useSelection(); const values = createMemo(() => Object.entries(props.value)); const isSelected = context.isSelected(props.key); return
context.select([props.key])} on:pointerdown={e => e.stopPropagation()} />
{ ([k, v]) =>
{table.cellRenderers()[k]?.({ value: v }) ?? v}
}
; }; function Group>(props: { key: string, groupedBy: keyof T, nodes: Node[], depth: number }) { const table = useTable(); const gridColumn = createMemo(() => { const groupedBy = props.groupedBy; const columns = table.columns(); const selectable = table.selectionMode() !== SelectionMode.None; return columns.findIndex(({ id }) => id === groupedBy) + (selectable ? 2 : 1); }); return
{props.key} { node => }
; };