UNPKG

@humanspeak/svelte-headless-table

Version:

A powerful, headless table library for Svelte that provides complete control over table UI while handling complex data operations like sorting, filtering, pagination, grouping, and row expansion. Build custom, accessible data tables with zero styling opin

218 lines (217 loc) 7.5 kB
/** * Base class for all column types in the table. * Provides type guards for determining the specific column type. * * @template Item - The type of data items in the table. * @template Plugins - The plugins configuration type. */ export class Column { /** The header label or render function. */ header; /** Optional footer label or render function. */ footer; /** The height of the column in header rows. */ height; /** Plugin-specific column configuration. */ plugins; /** * Creates a new Column instance. * * @param init - The column initialization options. */ constructor({ header, footer, height, plugins }) { this.header = header; this.footer = footer; this.height = height; this.plugins = plugins; } /** * Type guard to check if this column is a FlatColumn (DataColumn or DisplayColumn). * * @returns True if this is a FlatColumn. */ // TODO Workaround for https://github.com/vitejs/vite/issues/9528 isFlat() { return '__flat' in this; } /** * Type guard to check if this column is a DataColumn. * * @returns True if this is a DataColumn. */ // TODO Workaround for https://github.com/vitejs/vite/issues/9528 isData() { return '__data' in this; } /** * Type guard to check if this column is a DisplayColumn. * * @returns True if this is a DisplayColumn. */ // TODO Workaround for https://github.com/vitejs/vite/issues/9528 isDisplay() { return '__display' in this; } /** * Type guard to check if this column is a GroupColumn. * * @returns True if this is a GroupColumn. */ // TODO Workaround for https://github.com/vitejs/vite/issues/9528 isGroup() { return '__group' in this; } } /** * A column that occupies a single row in the header (not a group). * Base class for DataColumn and DisplayColumn. * * @template Item - The type of data items in the table. * @template Plugins - The plugins configuration type. * @template Id - The column ID type. */ export class FlatColumn extends Column { // TODO Workaround for https://github.com/vitejs/vite/issues/9528 __flat = true; /** The unique identifier for this column. */ id; /** * Creates a new FlatColumn instance. * * @param init - The column initialization options. */ constructor({ header, footer, plugins, id }) { super({ header, footer, plugins, height: 1 }); this.id = id ?? String(header); } } /** * A column that displays data from the table items. * Uses an accessor (key or function) to extract values from each row. * * @template Item - The type of data items in the table. * @template Plugins - The plugins configuration type. * @template Id - The column ID type. * @template Value - The type of the cell value. */ export class DataColumn extends FlatColumn { // TODO Workaround for https://github.com/vitejs/vite/issues/9528 __data = true; /** Optional custom cell renderer. */ cell; /** The property key used to access values (if using key accessor). */ accessorKey; /** The function used to extract values (if using function accessor). */ /* trunk-ignore(eslint/no-unused-vars) */ accessorFn; /** * Creates a new DataColumn instance. * * @param init - The column initialization options. * @throws Error if no id, accessor key, or header is provided. */ constructor({ header, footer, plugins, cell, accessor, id }) { super({ header, footer, plugins, id: 'Initialization not complete' }); this.cell = cell; if (accessor instanceof Function) { this.accessorFn = accessor; } else { this.accessorKey = accessor; } if (id === undefined && this.accessorKey === undefined && header === undefined) { throw new Error('A column id, string accessor, or header is required'); } const accessorKeyId = typeof this.accessorKey === 'string' ? this.accessorKey : null; this.id = (id ?? accessorKeyId ?? String(header)); } /** * Extracts the value from a data item using the configured accessor. * * @param item - The data item to extract the value from. * @returns The extracted value, or undefined if no accessor is configured. */ /* trunk-ignore(eslint/@typescript-eslint/no-explicit-any) */ getValue(item) { if (this.accessorFn !== undefined) { return this.accessorFn(item); } if (this.accessorKey !== undefined) { return item[this.accessorKey]; } return undefined; } } /** * A column for displaying non-data content like actions, checkboxes, or custom UI. * Unlike DataColumn, it doesn't extract values from the data items automatically. * * @template Item - The type of data items in the table. * @template Plugins - The plugins configuration type. * @template Id - The column ID type. */ export class DisplayColumn extends FlatColumn { // TODO Workaround for https://github.com/vitejs/vite/issues/9528 __display = true; /** The cell renderer function. */ cell; /** Optional function to provide custom data to the cell. */ data; /** * Creates a new DisplayColumn instance. * * @param init - The column initialization options. */ constructor({ header, footer, plugins, id, cell, data }) { super({ header, footer, plugins, id }); this.cell = cell; this.data = data; } } /** * A column that groups other columns under a shared header. * Creates a hierarchical header structure. * * @template Item - The type of data items in the table. * @template Plugins - The plugins configuration type. */ export class GroupColumn extends Column { // TODO Workaround for https://github.com/vitejs/vite/issues/9528 __group = true; /** The child columns contained within this group. */ columns; /** The IDs of all flat columns within this group (recursively). */ ids; /** * Creates a new GroupColumn instance. * Height is calculated as max child height + 1. * * @param init - The column initialization options. */ constructor({ header, footer, columns, plugins }) { const height = Math.max(...columns.map((c) => c.height)) + 1; super({ header, footer, height, plugins }); this.columns = columns; this.ids = getFlatColumnIds(columns); } } /** * Extracts all flat column IDs from an array of columns (including nested groups). * * @template Item - The type of data items in the table. * @template Plugins - The plugins configuration type. * @param columns - The array of columns to extract IDs from. * @returns An array of column ID strings. */ export const getFlatColumnIds = (columns) => columns.flatMap((c) => (c.isFlat() ? [c.id] : c.isGroup() ? c.ids : [])); /** * Extracts all FlatColumns from an array of columns (including nested groups). * * @template Item - The type of data items in the table. * @template Plugins - The plugins configuration type. * @param columns - The array of columns to flatten. * @returns An array of FlatColumn instances. */ export const getFlatColumns = (columns) => { return columns.flatMap((c) => (c.isFlat() ? [c] : c.isGroup() ? getFlatColumns(c.columns) : [])); };