From f66161568cf7c5742f83a2f2e062b93eff261311 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johan=20R=C3=B8ed?= Date: Wed, 23 Sep 2026 00:35:03 +0200 Subject: [PATCH 1/3] Let the plugins take a column whose Cell asks for args The cell args sit in the args of `Cell`, so they are contravariant: a column that carries them does not fit a `Column` parameter. The plugin helpers still asked for that, so a table with such a Cell could use no plugin at all. The args are inferred, so an app could not work around it. The helpers, the plugin methods they call and `meta.forColumn` now take the column meta, the table meta and the cell args, the way `columnsFor` already does. One internal constraint keeps `any` for the cell args, where it stands for a column of any table. Cowritten by Claude --- .../plugins-with-cell-args.test.ts | 75 +++++++++++++++++++ table/src/plugins/-private/base.ts | 51 ++++++++++--- .../src/plugins/column-reordering/helpers.ts | 65 ++++++++++++---- table/src/plugins/column-resizing/helpers.ts | 45 ++++++++--- .../src/plugins/column-visibility/helpers.ts | 38 ++++++++-- table/src/plugins/data-sorting/helpers.ts | 73 ++++++++++++++---- table/src/plugins/data-sorting/plugin.ts | 21 +++++- table/src/plugins/sticky-columns/helpers.ts | 27 +++++-- 8 files changed, 326 insertions(+), 69 deletions(-) create mode 100644 table/src/-private/-type-tests/plugins-with-cell-args.test.ts diff --git a/table/src/-private/-type-tests/plugins-with-cell-args.test.ts b/table/src/-private/-type-tests/plugins-with-cell-args.test.ts new file mode 100644 index 0000000..e8b6984 --- /dev/null +++ b/table/src/-private/-type-tests/plugins-with-cell-args.test.ts @@ -0,0 +1,75 @@ +import { expectTypeOf } from 'expect-type'; + +import { headlessTable } from '../../index.ts'; +import { + moveLeft, + moveRight, + orderedColumnsFor, +} from '../../plugins/column-reordering/index.ts'; +import { isResizable } from '../../plugins/column-resizing/index.ts'; +import { + hide, + isVisible, + show, +} from '../../plugins/column-visibility/index.ts'; +import { isAscending, sort } from '../../plugins/data-sorting/index.ts'; +import { isSticky } from '../../plugins/sticky-columns/index.ts'; +import { columns, meta } from '../../plugins/index.ts'; +import { ColumnVisibility } from '../../plugins/column-visibility/index.ts'; + +import type { CellContext, Column } from '../../index.ts'; +import type { ComponentLike } from '@glint/template'; + +interface Person { + name: string; +} +declare const people: Person[]; + +///////////////////////////////////////////// +// The plugins take a column whose Cell asks for args. +// The args sit in the args of `Cell`, so a column carrying them +// does not fit a `Column` parameter on its own. +declare const GroupedCell: ComponentLike< + CellContext & { groupBy: 'day' | 'week' } +>; + +const table = headlessTable( + {}, + { + columns: () => [ + { key: 'name', Cell: GroupedCell, meta: { align: 'left' } }, + ], + data: () => people, + }, +); + +const column = table.columns[0]!; + +expectTypeOf(isVisible(column)).toEqualTypeOf(); +expectTypeOf(isAscending(column)).toEqualTypeOf(); +expectTypeOf(isResizable(column)).toEqualTypeOf(); +expectTypeOf(isSticky(column)).toEqualTypeOf(); +hide(column); +show(column); +sort(column); +moveLeft(column); +moveRight(column); +meta.forColumn(column, ColumnVisibility); + +// the column list helpers keep the args, and the meta with them +expectTypeOf(columns.for(table)[0]!.meta?.align).toEqualTypeOf< + 'left' | undefined +>(); +expectTypeOf(orderedColumnsFor(table)[0]!.meta?.align).toEqualTypeOf< + 'left' | undefined +>(); + +// Code of your own that reads a column takes the args as a parameter. +// `Column` alone cannot accept it: the args are in the args of `Cell`, +// so a column that requires them is not a column that does not. +function takesAnyColumn( + column: Column, +) { + return column.key; +} +takesAnyColumn(column); diff --git a/table/src/plugins/-private/base.ts b/table/src/plugins/-private/base.ts index e0dec7a..4ef12b6 100644 --- a/table/src/plugins/-private/base.ts +++ b/table/src/plugins/-private/base.ts @@ -164,10 +164,13 @@ export const preferences = { * (though, if other plugins can guess how the underlying plugin access * works, they can access this data, too. No security guaranteed) */ - forColumn

, Data = unknown>( - column: Column, - klass: Class

, - ) { + forColumn< + P extends BasePlugin, + Data = unknown, + ColumnMeta = unknown, + Meta = unknown, + CellArgs = unknown, + >(column: Column, klass: Class

) { return { /** * delete an entry on the underlying `Map` used for this column-plugin pair @@ -574,8 +577,14 @@ export const meta = { * * Note that this requires the column instance to exist on the table. */ - forColumn

, Data = unknown>( - column: Column, + forColumn< + P extends BasePlugin, + Data = unknown, + ColumnMeta = unknown, + Meta = unknown, + CellArgs = unknown, + >( + column: Column, klass: Class

, ): ColumnMetaFor> { const columnMeta = column.table[COLUMN_META_KEY]; @@ -685,8 +694,14 @@ export const meta = { * * For example, multiple column-focused plugins may care about width or visibility */ - forColumn( - column: Column, + forColumn< + FeatureName extends string, + Data = unknown, + ColumnMeta = unknown, + Meta = unknown, + CellArgs = unknown, + >( + column: Column, featureName: FeatureName, ): ColumnFeatures[FeatureName] { const { plugins } = column.table; @@ -792,8 +807,14 @@ export const options = { return fn() ?? {}; }, - forColumn

, Data = unknown>( - column: Column, + forColumn< + P extends BasePlugin, + Data = unknown, + ColumnMeta = unknown, + Meta = unknown, + CellArgs = unknown, + >( + column: Column, klass: Class

, ): Partial>> { const tuple = column.config.pluginOptions?.find( @@ -819,13 +840,19 @@ function getPluginInstance( mapKey: Class, factory: () => Instance, ): Instance; -function getPluginInstance | Row, Instance>( +function getPluginInstance< + RootKey extends Column | Row, + Instance, +>( map: WeakMap, Instance>>, rootKey: RootKey, mapKey: Class, factory: () => Instance, ): Instance; -function getPluginInstance | Row, Instance>( +function getPluginInstance< + RootKey extends Column | Row, + Instance, +>( ...args: | [FactoryMap, Class, () => Instance] | [ diff --git a/table/src/plugins/column-reordering/helpers.ts b/table/src/plugins/column-reordering/helpers.ts index da9d675..caa078a 100644 --- a/table/src/plugins/column-reordering/helpers.ts +++ b/table/src/plugins/column-reordering/helpers.ts @@ -8,21 +8,38 @@ import type { Column, Table } from '../../index.ts'; * Move the column one position to the left. * If the column is first, nothing will happen. */ -export const moveLeft = (column: Column): void => - meta.forColumn(column, ColumnReordering).moveLeft(); +export const moveLeft = < + DataType = unknown, + ColumnMeta = unknown, + Meta = unknown, + CellArgs = unknown, +>( + column: Column, +): void => meta.forColumn(column, ColumnReordering).moveLeft(); /** * Move the column one position to the right. * If the column is last, nothing will happen. */ -export const moveRight = (column: Column): void => - meta.forColumn(column, ColumnReordering).moveRight(); +export const moveRight = < + DataType = unknown, + ColumnMeta = unknown, + Meta = unknown, + CellArgs = unknown, +>( + column: Column, +): void => meta.forColumn(column, ColumnReordering).moveRight(); /** * Override all column positions at once. */ -export const setColumnOrder = ( - table: Table, +export const setColumnOrder = < + DataType = unknown, + ColumnMeta = unknown, + Meta = unknown, + CellArgs = unknown, +>( + table: Table, order: ColumnOrder, ): void => { // Note: The meta.forTable API doesn't preserve the DataType generic from the table parameter. @@ -37,23 +54,38 @@ export const setColumnOrder = ( /** * Ask if the column cannot move to the left */ -export const cannotMoveLeft = ( - column: Column, +export const cannotMoveLeft = < + DataType = unknown, + ColumnMeta = unknown, + Meta = unknown, + CellArgs = unknown, +>( + column: Column, ): boolean => meta.forColumn(column, ColumnReordering).cannotMoveLeft; /** * Ask if the column cannot move to the right */ -export const cannotMoveRight = ( - column: Column, +export const cannotMoveRight = < + DataType = unknown, + ColumnMeta = unknown, + Meta = unknown, + CellArgs = unknown, +>( + column: Column, ): boolean => meta.forColumn(column, ColumnReordering).cannotMoveRight; /** * Ask if the column can move to the left * (If your plugin doesn't expose `canMoveLeft`, use `!cannotMoveLeft`.) */ -export const canMoveLeft = ( - column: Column, +export const canMoveLeft = < + DataType = unknown, + ColumnMeta = unknown, + Meta = unknown, + CellArgs = unknown, +>( + column: Column, ): boolean => // Prefer this if available: // meta.forColumn(column, ColumnReordering).canMoveLeft @@ -63,8 +95,13 @@ export const canMoveLeft = ( * Ask if the column can move to the right * (If your plugin doesn't expose `canMoveRight`, use `!cannotMoveRight`.) */ -export const canMoveRight = ( - column: Column, +export const canMoveRight = < + DataType = unknown, + ColumnMeta = unknown, + Meta = unknown, + CellArgs = unknown, +>( + column: Column, ): boolean => // Prefer this if available: // meta.forColumn(column, ColumnReordering).canMoveRight diff --git a/table/src/plugins/column-resizing/helpers.ts b/table/src/plugins/column-resizing/helpers.ts index 9876612..8f74d10 100644 --- a/table/src/plugins/column-resizing/helpers.ts +++ b/table/src/plugins/column-resizing/helpers.ts @@ -9,8 +9,13 @@ import type { Column } from '../../index.ts'; * Is the column resizable? * This checks if resizing is enabled for this specific column, */ -export const isResizable = ( - column: Column, +export const isResizable = < + DataType = unknown, + ColumnMeta = unknown, + Meta = unknown, + CellArgs = unknown, +>( + column: Column, ): boolean => meta.forColumn(column, ColumnResizing).isResizable; /** @@ -23,15 +28,25 @@ export const isResizable = ( * be marked as isResizing, because this is a user-scoped question: * "Is the user directly resizing this column?" */ -export const isResizing = ( - column: Column, +export const isResizing = < + DataType = unknown, + ColumnMeta = unknown, + Meta = unknown, + CellArgs = unknown, +>( + column: Column, ): boolean => meta.forColumn(column, ColumnResizing).isResizing; /** * Does the column have room to shrink? */ -export const canShrink = ( - column: Column, +export const canShrink = < + DataType = unknown, + ColumnMeta = unknown, + Meta = unknown, + CellArgs = unknown, +>( + column: Column, ): boolean | 0 => meta.forColumn(column, ColumnResizing).canShrink; /** @@ -41,8 +56,13 @@ export const canShrink = ( * - if resizing is enabled for the whole table * - or if we're asking about the first column (resize handles may only be "between" columns) */ -export const hasResizeHandle = ( - column: Column, +export const hasResizeHandle = < + DataType = unknown, + ColumnMeta = unknown, + Meta = unknown, + CellArgs = unknown, +>( + column: Column, ): boolean => meta.forColumn(column, ColumnResizing).hasResizeHandle; /** @@ -53,8 +73,13 @@ export const hasResizeHandle = ( * * This utility is meant to be applied to the `style` attribute of a particular td-like element. */ -export const styleStringFor = ( - column: Column, +export const styleStringFor = < + DataType = unknown, + ColumnMeta = unknown, + Meta = unknown, + CellArgs = unknown, +>( + column: Column, ): ReturnType => { const columnMeta = meta.forColumn(column, ColumnResizing); diff --git a/table/src/plugins/column-visibility/helpers.ts b/table/src/plugins/column-visibility/helpers.ts index 48b0c4c..0e90f09 100644 --- a/table/src/plugins/column-visibility/helpers.ts +++ b/table/src/plugins/column-visibility/helpers.ts @@ -6,25 +6,47 @@ import type { Column } from '../../index.ts'; /** * Hide a column */ -export const hide = (column: Column): void => - meta.forColumn(column, ColumnVisibility).hide(); +export const hide = < + DataType = unknown, + ColumnMeta = unknown, + Meta = unknown, + CellArgs = unknown, +>( + column: Column, +): void => meta.forColumn(column, ColumnVisibility).hide(); /** * Show a column */ -export const show = (column: Column): void => - meta.forColumn(column, ColumnVisibility).show(); +export const show = < + DataType = unknown, + ColumnMeta = unknown, + Meta = unknown, + CellArgs = unknown, +>( + column: Column, +): void => meta.forColumn(column, ColumnVisibility).show(); /** * Ask if a column is presently supposed to be visible */ -export const isVisible = ( - column: Column, +export const isVisible = < + DataType = unknown, + ColumnMeta = unknown, + Meta = unknown, + CellArgs = unknown, +>( + column: Column, ): boolean => meta.forColumn(column, ColumnVisibility).isVisible; /** * Ask if a column is presently supposed to be hidden */ -export const isHidden = ( - column: Column, +export const isHidden = < + DataType = unknown, + ColumnMeta = unknown, + Meta = unknown, + CellArgs = unknown, +>( + column: Column, ): boolean => meta.forColumn(column, ColumnVisibility).isHidden; diff --git a/table/src/plugins/data-sorting/helpers.ts b/table/src/plugins/data-sorting/helpers.ts index 9d02036..070e862 100644 --- a/table/src/plugins/data-sorting/helpers.ts +++ b/table/src/plugins/data-sorting/helpers.ts @@ -7,36 +7,61 @@ import type { SortDirection } from './types.ts'; /** * Query a specific column's current sort direction */ -export const sortDirection = ( - column: Column, +export const sortDirection = < + DataType = unknown, + ColumnMeta = unknown, + Meta = unknown, + CellArgs = unknown, +>( + column: Column, ): SortDirection => meta.forColumn(column, Sorting).sortDirection; /** * Ask if a column is sortable */ -export const isSortable = ( - column: Column, +export const isSortable = < + DataType = unknown, + ColumnMeta = unknown, + Meta = unknown, + CellArgs = unknown, +>( + column: Column, ): boolean => meta.forColumn(column, Sorting).isSortable; /** * Ask if a column is ascending */ -export const isAscending = ( - column: Column, +export const isAscending = < + DataType = unknown, + ColumnMeta = unknown, + Meta = unknown, + CellArgs = unknown, +>( + column: Column, ): boolean => meta.forColumn(column, Sorting).isAscending; /** * Ask if a column is sorted descending */ -export const isDescending = ( - column: Column, +export const isDescending = < + DataType = unknown, + ColumnMeta = unknown, + Meta = unknown, + CellArgs = unknown, +>( + column: Column, ): boolean => meta.forColumn(column, Sorting).isDescending; /** * Ask if a column is not sorted */ -export const isUnsorted = ( - column: Column, +export const isUnsorted = < + DataType = unknown, + ColumnMeta = unknown, + Meta = unknown, + CellArgs = unknown, +>( + column: Column, ): boolean => meta.forColumn(column, Sorting).isUnsorted; /** @@ -46,19 +71,35 @@ export const isUnsorted = ( * Ascending => None => Descending * ⬑ ---------- <= ---------- ↲ */ -export const sort = (column: Column): void => - meta.forTable(column.table, Sorting).handleSort(column); +export const sort = < + DataType = unknown, + ColumnMeta = unknown, + Meta = unknown, + CellArgs = unknown, +>( + column: Column, +): void => meta.forTable(column.table, Sorting).handleSort(column); /** * Toggle a column between descending and not unsorted states */ -export const sortDescending = ( - column: Column, +export const sortDescending = < + DataType = unknown, + ColumnMeta = unknown, + Meta = unknown, + CellArgs = unknown, +>( + column: Column, ): void => meta.forTable(column.table, Sorting).toggleDescending(column); /** * Toggle a column between ascending and not unsorted states */ -export const sortAscending = ( - column: Column, +export const sortAscending = < + DataType = unknown, + ColumnMeta = unknown, + Meta = unknown, + CellArgs = unknown, +>( + column: Column, ): void => meta.forTable(column.table, Sorting).toggleAscending(column); diff --git a/table/src/plugins/data-sorting/plugin.ts b/table/src/plugins/data-sorting/plugin.ts index fb17ed2..447750c 100644 --- a/table/src/plugins/data-sorting/plugin.ts +++ b/table/src/plugins/data-sorting/plugin.ts @@ -160,7 +160,12 @@ export class TableMeta { } @action - handleSort(column: Column): void { + handleSort< + DataType = unknown, + ColumnMeta = unknown, + Meta = unknown, + CellArgs = unknown, + >(column: Column): void { const columnMeta = meta.forColumn(column, Sorting); if (!columnMeta.sortProperty) { @@ -187,7 +192,12 @@ export class TableMeta { } @action - toggleAscending(column: Column): void { + toggleAscending< + DataType = unknown, + ColumnMeta = unknown, + Meta = unknown, + CellArgs = unknown, + >(column: Column): void { const columnMeta = meta.forColumn(column, Sorting); if (!columnMeta.sortProperty) { @@ -204,7 +214,12 @@ export class TableMeta { } @action - toggleDescending(column: Column): void { + toggleDescending< + DataType = unknown, + ColumnMeta = unknown, + Meta = unknown, + CellArgs = unknown, + >(column: Column): void { const columnMeta = meta.forColumn(column, Sorting); if (!columnMeta.sortProperty) { diff --git a/table/src/plugins/sticky-columns/helpers.ts b/table/src/plugins/sticky-columns/helpers.ts index 41f51b1..216c30b 100644 --- a/table/src/plugins/sticky-columns/helpers.ts +++ b/table/src/plugins/sticky-columns/helpers.ts @@ -5,12 +5,22 @@ import { StickyColumns } from './plugin.ts'; import type { Column } from '../../index.ts'; -export const isSticky = ( - column: Column, +export const isSticky = < + DataType = unknown, + ColumnMeta = unknown, + Meta = unknown, + CellArgs = unknown, +>( + column: Column, ): boolean => meta.forColumn(column, StickyColumns).isSticky; -export const styleFor = ( - column: Column, +export const styleFor = < + DataType = unknown, + ColumnMeta = unknown, + Meta = unknown, + CellArgs = unknown, +>( + column: Column, ): Partial => meta.forColumn(column, StickyColumns).style; /** @@ -24,8 +34,13 @@ export const styleFor = ( * In the mean time, we'll need to append style strings, which is more work * for consumers, but is a reasonable trade-off for now. */ -export const styleStringFor = ( - column: Column, +export const styleStringFor = < + DataType = unknown, + ColumnMeta = unknown, + Meta = unknown, + CellArgs = unknown, +>( + column: Column, ): ReturnType => { const columnMeta = meta.forColumn(column, StickyColumns); From e7694e83c615ff9136b607b02ab042d693d516ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johan=20R=C3=B8ed?= Date: Wed, 23 Sep 2026 00:45:00 +0200 Subject: [PATCH 2/3] Let an order be built from columns whose Cells ask for args `ColumnOrder` holds the columns it orders, so it needs the same parameters as the helpers. The plugin keeps one for its own table and does not read the Cells, so it holds the widest shape. Cowritten by Claude --- .../plugins-with-cell-args.test.ts | 5 ++++ .../src/plugins/column-reordering/helpers.ts | 2 +- table/src/plugins/column-reordering/plugin.ts | 26 +++++++++++++------ 3 files changed, 24 insertions(+), 9 deletions(-) diff --git a/table/src/-private/-type-tests/plugins-with-cell-args.test.ts b/table/src/-private/-type-tests/plugins-with-cell-args.test.ts index e8b6984..70f5c1f 100644 --- a/table/src/-private/-type-tests/plugins-with-cell-args.test.ts +++ b/table/src/-private/-type-tests/plugins-with-cell-args.test.ts @@ -2,9 +2,11 @@ import { expectTypeOf } from 'expect-type'; import { headlessTable } from '../../index.ts'; import { + ColumnOrder, moveLeft, moveRight, orderedColumnsFor, + setColumnOrder, } from '../../plugins/column-reordering/index.ts'; import { isResizable } from '../../plugins/column-resizing/index.ts'; import { @@ -56,6 +58,9 @@ moveLeft(column); moveRight(column); meta.forColumn(column, ColumnVisibility); +// an order is built from the columns of the table it orders +setColumnOrder(table, new ColumnOrder({ columns: () => [column] })); + // the column list helpers keep the args, and the meta with them expectTypeOf(columns.for(table)[0]!.meta?.align).toEqualTypeOf< 'left' | undefined diff --git a/table/src/plugins/column-reordering/helpers.ts b/table/src/plugins/column-reordering/helpers.ts index caa078a..fb54558 100644 --- a/table/src/plugins/column-reordering/helpers.ts +++ b/table/src/plugins/column-reordering/helpers.ts @@ -40,7 +40,7 @@ export const setColumnOrder = < CellArgs = unknown, >( table: Table, - order: ColumnOrder, + order: ColumnOrder, ): void => { // Note: The meta.forTable API doesn't preserve the DataType generic from the table parameter. // We use a type assertion here to match the expected types. diff --git a/table/src/plugins/column-reordering/plugin.ts b/table/src/plugins/column-reordering/plugin.ts index a66c44a..8c21f39 100644 --- a/table/src/plugins/column-reordering/plugin.ts +++ b/table/src/plugins/column-reordering/plugin.ts @@ -119,7 +119,12 @@ export class TableMeta { * This is also why the order of the columns is maintained via column key */ @tracked - columnOrder: ColumnOrder = new ColumnOrder({ + columnOrder: ColumnOrder = new ColumnOrder< + DataType, + any, + any, + any + >({ columns: () => this.allColumns, visibleColumns: () => this.visibleColumns, save: this.save, @@ -148,7 +153,7 @@ export class TableMeta { /** * Using a `ColumnOrder` instance, set the order of all columns */ - setOrder = (order: ColumnOrder): void => { + setOrder = (order: ColumnOrder): void => { this.columnOrder.setAll(order.map); }; @@ -159,7 +164,7 @@ export class TableMeta { @action reset(): void { preferences.forTable(this.table, ColumnReordering).delete('order'); - this.columnOrder = new ColumnOrder({ + this.columnOrder = new ColumnOrder({ columns: () => this.allColumns, visibleColumns: () => this.visibleColumns, save: this.save, @@ -223,7 +228,12 @@ export class TableMeta { * @private * Used for keeping track of and updating column order */ -export class ColumnOrder { +export class ColumnOrder< + DataType = unknown, + ColumnMeta = unknown, + Meta = unknown, + CellArgs = unknown, +> { /** * This map will be empty until we re-order something. */ @@ -243,7 +253,7 @@ export class ColumnOrder { * - Provide `visibleColumns` to indicate which are visible * - Hidden columns maintain their position when toggled */ - columns: () => Column[]; + columns: () => Column[]; /** * Optional: Record of which columns are currently visible. * When provided, moveLeft/moveRight will skip over hidden columns. @@ -515,19 +525,19 @@ export class ColumnOrder { } @cached - get orderedColumns(): Column[] { + get orderedColumns(): Column[] { const allColumns = this.args.columns(); const columnsByKey = allColumns.reduce( (keyMap, column) => { keyMap[column.key] = column; return keyMap; }, - {} as Record>, + {} as Record>, ); // Use orderedMap which is reactive to preferences const mergedOrder = this.orderedMap; - const result: Column[] = Array.from({ + const result: Column[] = Array.from({ length: allColumns.length, }); From 63f8e9954395c5778387ff60cefd5e119d207c7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johan=20R=C3=B8ed?= Date: Wed, 23 Sep 2026 00:51:14 +0200 Subject: [PATCH 3/3] Let the modifiers take a column whose Cell asks for args `table.modifiers.columnHeader` and `resizeHandle` are given a column in a template, so they meet the same wall as the helpers. The plugin column API holds the widest shape, because a plugin is handed whatever column the table has. Cowritten by Claude --- table/src/-private/interfaces/plugins.ts | 3 ++- table/src/-private/table.ts | 10 ++++++++-- table/src/plugins/column-resizing/handle.ts | 6 +++--- test-app/tests/integration/cells-test.gts | 8 ++++++++ 4 files changed, 21 insertions(+), 6 deletions(-) diff --git a/table/src/-private/interfaces/plugins.ts b/table/src/-private/interfaces/plugins.ts index 8cca8d4..eb4ad31 100644 --- a/table/src/-private/interfaces/plugins.ts +++ b/table/src/-private/interfaces/plugins.ts @@ -31,7 +31,8 @@ export type PluginSubclassInstance = PluginType & { * The data passed to a plugin's column APIs */ export interface ColumnApi { - column: Column>; + // A plugin is handed whatever column the table has, whatever its Cell asks for. + column: Column, any, any, any>; table: T; } diff --git a/table/src/-private/table.ts b/table/src/-private/table.ts index 63e0faf..562681c 100644 --- a/table/src/-private/table.ts +++ b/table/src/-private/table.ts @@ -198,7 +198,10 @@ export class Table< }>; columnHeader: FunctionBasedModifier<{ Element: HTMLElement; - Args: { Positional: [Column]; Named: EmptyObject }; + Args: { + Positional: [Column]; + Named: EmptyObject; + }; }>; row: FunctionBasedModifier<{ Element: HTMLElement; @@ -225,7 +228,10 @@ export class Table< // With curried+composed modifiers, only the plugin's headerModifier // that has tracked changes would run, leaving the other modifiers alone columnHeader: modifier( - (element: HTMLElement, [column]: [Column]): Destructor => { + ( + element: HTMLElement, + [column]: [Column], + ): Destructor => { const modifiers = this.plugins.map( (plugin) => plugin.headerCellModifier, ); diff --git a/table/src/plugins/column-resizing/handle.ts b/table/src/plugins/column-resizing/handle.ts index 5897b1c..af50b71 100644 --- a/table/src/plugins/column-resizing/handle.ts +++ b/table/src/plugins/column-resizing/handle.ts @@ -25,10 +25,10 @@ const waiter = buildWaiter('ColumnResizing#ResizeHandle'); */ class ResizeHandle extends Modifier<{ - Args: { Positional: [Column] }; + Args: { Positional: [Column] }; }> { declare dragHandle: HTMLElement; - declare column: Column; + declare column: Column; declare meta: ColumnMeta; // Pointer @@ -47,7 +47,7 @@ class ResizeHandle extends Modifier<{ token?: unknown; isSetup = false; - modify(element: Element, [column]: [Column]): void { + modify(element: Element, [column]: [Column]): void { this.column = column; this.meta = meta.forColumn(column, ColumnResizing); this.dragHandle = element as HTMLElement; diff --git a/test-app/tests/integration/cells-test.gts b/test-app/tests/integration/cells-test.gts index 0631ed2..6eeb423 100644 --- a/test-app/tests/integration/cells-test.gts +++ b/test-app/tests/integration/cells-test.gts @@ -4,6 +4,7 @@ import { module, test } from "qunit"; import { setupRenderingTest } from "ember-qunit"; import { headlessTable } from "@universal-ember/table"; +import { resizeHandle } from "@universal-ember/table/plugins/column-resizing"; import type { TOC } from "@ember/component/template-only"; import type { CellContext } from "@universal-ember/table"; @@ -77,6 +78,13 @@ module("Cells", function (hooks) { * Never rendered: these templates only exist for the type checks. */ const TypeChecks: TOC<{ Args: { table: Context["table"] } }> =