diff --git a/CHANGELOG.md b/CHANGELOG.md index 2bef8d4..4a7543c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,8 +22,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ```ts const columns: ColumnConfiguration[] = [ - { key: 'id', headerText: 'User ID', type: 'number', filter: true, sort: true }, - { key: 'name', filter: true, sort: true }, + { key: 'id', headerText: 'User ID', type: 'number', filterable: true, sortable: true }, + { key: 'name', filterable: true, sortable: true }, ]; ``` @@ -35,17 +35,22 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 key="id" header-text="User ID" type="number" - .filter=${true} - .sort=${true} + filterable + sortable > ``` +- **BREAKING:** Column `sort` and `filter` properties have been replaced with separate boolean and configuration properties: + - `sort` → `sortable` (boolean) + `sortingCaseSensitive` (boolean) + `sortConfiguration` (object with `comparer` option) + - `filter` → `filterable` (boolean) + `filteringCaseSensitive` (boolean) + +- **BREAKING:** Removed `ColumnFilterConfiguration` type. Use `filteringCaseSensitive` boolean property directly on the column. - **BREAKING:** Renamed `GridSortConfiguration` type to `GridLiteSortingOptions`. - **BREAKING:** Renamed `IgcGridLite.sortConfiguration` property to `sortingOptions`. - **BREAKING:** Renamed `IgcGridLite.sortExpressions` property to `sortingExpressions`. diff --git a/demo/demo.ts b/demo/demo.ts index ac905f0..646893b 100644 --- a/demo/demo.ts +++ b/demo/demo.ts @@ -106,12 +106,19 @@ const themeChoose = html` `; const columns: ColumnConfiguration[] = [ - { key: 'id', headerText: 'User ID', resizable: true, type: 'number', filter: true, sort: true }, + { + key: 'id', + headerText: 'User ID', + resizable: true, + type: 'number', + filterable: true, + sortable: true, + }, { key: 'name', cellTemplate: (params) => html``, - filter: true, - sort: true, + filterable: true, + sortable: true, }, { key: 'avatar', @@ -124,8 +131,8 @@ const columns: ColumnConfiguration[] = [ { key: 'satisfaction', type: 'number', - sort: true, - filter: true, + sortable: true, + filterable: true, cellTemplate: (params) => html`[] = [ (choice) => html`${choice}`, )}`, - sort: { + sortable: true, + sortConfiguration: { comparer: (a, b) => choices.indexOf(a) - choices.indexOf(b), }, }, @@ -157,8 +165,8 @@ const columns: ColumnConfiguration[] = [ { key: 'subscribed', type: 'boolean', - sort: true, - filter: true, + sortable: true, + filterable: true, cellTemplate: (params) => html` { (col) => col.key === 'name', )!; - column.filter = !column.filter; + column.filterable = !column.filterable; }; render( @@ -214,8 +222,9 @@ render( .headerText=${col.headerText} ?hidden=${col.hidden} ?resizable=${col.resizable} - .sort=${col.sort} - .filter=${col.filter} + ?sortable=${col.sortable} + .sortConfiguration=${col.sortConfiguration} + ?filterable=${col.filterable} .cellTemplate=${col.cellTemplate} .headerTemplate=${col.headerTemplate as any} >`, diff --git a/src/components/column.ts b/src/components/column.ts index beb05a2..8afdf8b 100644 --- a/src/components/column.ts +++ b/src/components/column.ts @@ -6,7 +6,6 @@ import { registerComponent } from '../internal/register.js'; import { GRID_COLUMN_TAG } from '../internal/tags.js'; import type { BaseColumnConfiguration, - ColumnFilterConfiguration, ColumnSortConfiguration, IgcCellContext, IgcHeaderContext, @@ -62,13 +61,25 @@ export class IgcGridLiteColumn @property({ type: Boolean }) public resizable = false; - /** Sort configuration for the column. */ - @property({ attribute: false }) - public sort?: ColumnSortConfiguration | boolean = false; + /** Indicates whether the column is sortable. */ + @property({ type: Boolean }) + public sortable = false; + + /** Whether sort operations will be case sensitive. */ + @property({ type: Boolean, attribute: 'sorting-case-sensitive' }) + public sortingCaseSensitive = false; - /** Filter configuration for the column. */ + /** Sort configuration for the column (e.g., custom comparer). */ @property({ attribute: false }) - public filter?: ColumnFilterConfiguration | boolean = false; + public sortConfiguration?: ColumnSortConfiguration; + + /** Indicates whether the column is filterable. */ + @property({ type: Boolean }) + public filterable = false; + + /** Whether filter operations will be case sensitive. */ + @property({ type: Boolean, attribute: 'filtering-case-sensitive' }) + public filteringCaseSensitive = false; /** Custom header template for the column. */ @property({ attribute: false }) diff --git a/src/components/filter-row.ts b/src/components/filter-row.ts index 08c766c..47e822b 100644 --- a/src/components/filter-row.ts +++ b/src/components/filter-row.ts @@ -377,7 +377,7 @@ export default class IgcFilterRow extends LitElement { ? nothing : html`
- ${column.filter ? this.renderFilterState(column) : nothing} + ${column.filterable ? this.renderFilterState(column) : nothing}
` ); diff --git a/src/components/grid.ts b/src/components/grid.ts index 0d3544e..82e277a 100644 --- a/src/components/grid.ts +++ b/src/components/grid.ts @@ -476,7 +476,7 @@ export class IgcGridLite extends EventEmitterBase column.filter) + this._stateController.columns.some((column) => column.filterable) ? html`` : nothing )}`; diff --git a/src/components/header.ts b/src/components/header.ts index b02ba0f..73d54fb 100644 --- a/src/components/header.ts +++ b/src/components/header.ts @@ -36,7 +36,7 @@ export default class IgcGridLiteHeader extends LitElement { } protected get isSortable() { - return Boolean(this.column.sort); + return Boolean(this.column.sortable); } protected get resizeController() { diff --git a/src/controllers/filter.ts b/src/controllers/filter.ts index 3b9c7a9..92b174f 100644 --- a/src/controllers/filter.ts +++ b/src/controllers/filter.ts @@ -71,7 +71,7 @@ export class FilterController implements ReactiveController { } public setActiveColumn(column?: ColumnConfiguration) { - if (column?.filter && this.filterRow?.active) { + if (column?.filterable && this.filterRow?.active) { this.filterRow.column = column; this.filterRow.expression = this.getDefaultExpression(column); this.host.requestUpdate(); @@ -79,8 +79,7 @@ export class FilterController implements ReactiveController { } public getDefaultExpression(column: ColumnConfiguration) { - const caseSensitive = - typeof column.filter === 'boolean' ? false : Boolean(column.filter?.caseSensitive); + const caseSensitive = Boolean(column.filteringCaseSensitive); const operands = getFilterOperandsFor(column); const keys = Object.keys(operands) as Keys[]; diff --git a/src/controllers/sort.ts b/src/controllers/sort.ts index ac8b353..38bd7fc 100644 --- a/src/controllers/sort.ts +++ b/src/controllers/sort.ts @@ -1,11 +1,6 @@ import type { ReactiveController } from 'lit'; import { PIPELINE } from '../internal/constants.js'; -import type { - ColumnConfiguration, - ColumnSortConfiguration, - GridHost, - Keys, -} from '../internal/types.js'; +import type { ColumnConfiguration, GridHost, Keys } from '../internal/types.js'; import { asArray } from '../internal/utils.js'; import type { SortingDirection, SortingExpression, SortState } from '../operations/sort/types.js'; @@ -24,29 +19,29 @@ export class SortController implements ReactiveController { return true; } - #resolveSortOptions(options?: boolean | ColumnSortConfiguration) { + #resolveSortOptions(column?: ColumnConfiguration) { const expr: Pick, 'caseSensitive' | 'comparer'> = { caseSensitive: false, comparer: undefined, }; - if (!options || typeof options === 'boolean') { + if (!column) { return expr as Partial>; } return Object.assign(expr, { - caseSensitive: options.caseSensitive, - comparer: options.comparer, + caseSensitive: column.sortingCaseSensitive, + comparer: column.sortConfiguration?.comparer, }) as Partial>; } #createDefaultExpression(key: Keys) { - const options = this.host.getColumn(key)?.sort; + const column = this.host.getColumn(key); return { key, direction: 'ascending', - ...this.#resolveSortOptions(options), + ...this.#resolveSortOptions(column), } as SortingExpression; } @@ -93,18 +88,18 @@ export class SortController implements ReactiveController { this.#emitSortedEvent(expression); } - public prepareExpression({ key, sort: options }: ColumnConfiguration): SortingExpression { - if (this.state.has(key)) { - const expr = this.state.get(key)!; + public prepareExpression(column: ColumnConfiguration): SortingExpression { + if (this.state.has(column.key)) { + const expr = this.state.get(column.key)!; return Object.assign(expr, { direction: this.#orderBy(expr.direction), - ...this.#resolveSortOptions(options), + ...this.#resolveSortOptions(column), }); } // Initial state - return this.#createDefaultExpression(key); + return this.#createDefaultExpression(column.key); } public reset(key?: Keys) { diff --git a/src/index.ts b/src/index.ts index 49a9ece..b71f6fd 100644 --- a/src/index.ts +++ b/src/index.ts @@ -11,7 +11,6 @@ export type { BaseIgcCellContext, BasePropertyType, ColumnConfiguration, - ColumnFilterConfiguration, ColumnSortConfiguration, DataPipelineConfiguration, DataPipelineHook, diff --git a/src/internal/constants.ts b/src/internal/constants.ts index 31ea84c..57f0ca9 100644 --- a/src/internal/constants.ts +++ b/src/internal/constants.ts @@ -18,8 +18,8 @@ export const DEFAULT_COLUMN_CONFIG = Object.freeze>({ type: 'string', resizable: false, hidden: false, - sort: false, - filter: false, + sortable: false, + filterable: false, }); export const NAVIGATION_STATE: Map> = new Map([ ['previous', SENTINEL_NODE], diff --git a/src/internal/types.ts b/src/internal/types.ts index 740834a..77bd044 100644 --- a/src/internal/types.ts +++ b/src/internal/types.ts @@ -42,10 +42,6 @@ export interface GridLiteSortingOptions { * Extended sort configuration for a column. */ export interface BaseColumnSortConfiguration = Keys> { - /** - * Whether the sort operations will be case sensitive. - */ - caseSensitive?: boolean; /** * Custom comparer function for sort operations for this column. */ @@ -59,16 +55,6 @@ export type ColumnSortConfiguration = Keys> = K extends ? BaseColumnSortConfiguration : never; -/** - * Extended filter configuration for a column. - */ -export interface ColumnFilterConfiguration { - /** - * Whether the filter operations will be case sensitive. - */ - caseSensitive?: boolean; -} - /** Configuration object for grid columns. */ export interface BaseColumnConfiguration = Keys> { /** @@ -110,13 +96,25 @@ export interface BaseColumnConfiguration = K */ resizable?: boolean; /** - * Whether the column can be sorted or not. + * Whether the column can be sorted. */ - sort?: ColumnSortConfiguration | boolean; + sortable?: boolean; /** - * Whether filter operation can be applied on the column or not. + * Whether the sort operations will be case sensitive. + */ + sortingCaseSensitive?: boolean; + /** + * Sort configuration options for the column (e.g., custom comparer). + */ + sortConfiguration?: ColumnSortConfiguration; + /** + * Whether the column can be filtered. + */ + filterable?: boolean; + /** + * Whether the filter operations will be case sensitive. */ - filter?: ColumnFilterConfiguration | boolean; + filteringCaseSensitive?: boolean; /** * Header template callback. */ diff --git a/src/internal/utils.ts b/src/internal/utils.ts index 0cea36d..d0befea 100644 --- a/src/internal/utils.ts +++ b/src/internal/utils.ts @@ -73,8 +73,11 @@ export function createColumnConfiguration( width: config.width, hidden: config.hidden ?? false, resizable: config.resizable ?? false, - sort: config.sort ?? false, - filter: config.filter ?? false, + sortable: config.sortable ?? false, + sortingCaseSensitive: config.sortingCaseSensitive ?? false, + sortConfiguration: config.sortConfiguration, + filterable: config.filterable ?? false, + filteringCaseSensitive: config.filteringCaseSensitive ?? false, headerTemplate: config.headerTemplate, cellTemplate: config.cellTemplate, } as ColumnConfiguration; diff --git a/test/data-operation/filter-ui.test.ts b/test/data-operation/filter-ui.test.ts index fb60915..6fe9397 100644 --- a/test/data-operation/filter-ui.test.ts +++ b/test/data-operation/filter-ui.test.ts @@ -11,12 +11,12 @@ class FilterFixture extends GridTestFixture { public override updateConfig(): void { this.columnConfig = this.columnConfig.map((config) => ({ ...config, - filter: true, + filterable: true, })); } public get filterableColumns() { - return this.grid.columns.filter((each) => each.filter); + return this.grid.columns.filter((each) => each.filterable); } public get activeChips() { @@ -109,7 +109,7 @@ describe('Grid UI filter', () => { describe('Default UI state', () => { it('Default state for no filterable columns', async () => { - await TDD.updateColumns(TDD.columnConfig.map((each) => ({ ...each, filter: false }))); + await TDD.updateColumns(TDD.columnConfig.map((each) => ({ ...each, filterable: false }))); expect(TDD.filterRow.element).to.not.exist; }); @@ -121,10 +121,10 @@ describe('Grid UI filter', () => { it('Correct number of UI elements', async () => { expect(TDD.filterableColumns).lengthOf(TDD.filterRow.inactiveStateChips.length); - await TDD.updateColumns({ key: 'name', filter: false }); + await TDD.updateColumns({ key: 'name', filterable: false }); expect(TDD.filterableColumns).lengthOf(TDD.filterRow.inactiveStateChips.length); - await TDD.updateColumns({ key: 'name', filter: true }); + await TDD.updateColumns({ key: 'name', filterable: true }); expect(TDD.filterableColumns).lengthOf(TDD.filterRow.inactiveStateChips.length); }); @@ -156,7 +156,7 @@ describe('Grid UI filter', () => { }); it('Does not change header style when clicking on a non-filterable column', async () => { - await TDD.updateColumns({ key: 'active', filter: false }); + await TDD.updateColumns({ key: 'active', filterable: false }); await TDD.activateFilterRow('name'); await TDD.clickHeader('active'); @@ -266,7 +266,11 @@ describe('Grid UI filter', () => { }); it('String column, single filter [case sensitive]', async () => { - await TDD.updateColumns({ key: 'name', filter: { caseSensitive: true } }); + await TDD.updateColumns({ + key: 'name', + filterable: true, + filteringCaseSensitive: true, + }); await TDD.activateFilterRow('name'); await TDD.filterByInput('a'); @@ -280,7 +284,7 @@ describe('Grid UI filter', () => { }); it('Number column, single filter [correct type]', async () => { - await TDD.updateColumns({ key: 'id', type: 'number', filter: true }); + await TDD.updateColumns({ key: 'id', type: 'number', filterable: true }); await TDD.activateFilterRow('id'); await TDD.filterByInput('3'); @@ -370,14 +374,22 @@ describe('Grid UI filter', () => { describe('API', () => { it('Honors column configuration parameters', async () => { - await TDD.updateColumns({ key: 'name', filter: { caseSensitive: true } }); + await TDD.updateColumns({ + key: 'name', + filterable: true, + filteringCaseSensitive: true, + }); await TDD.filter({ key: 'name', condition: 'contains', searchTerm: 'D' }); expect(TDD.grid.totalItems).to.equal(1); }); it('Honors overwriting column configuration parameters', async () => { - await TDD.updateColumns({ key: 'name', filter: { caseSensitive: true } }); + await TDD.updateColumns({ + key: 'name', + filterable: true, + filteringCaseSensitive: true, + }); await TDD.filter({ key: 'name', condition: 'contains', diff --git a/test/data-operation/sort-ui.test.ts b/test/data-operation/sort-ui.test.ts index 0c705dd..3f35cb7 100644 --- a/test/data-operation/sort-ui.test.ts +++ b/test/data-operation/sort-ui.test.ts @@ -7,7 +7,7 @@ import data, { importanceComparer } from '../utils/test-data.js'; class SortFixture extends GridTestFixture { public override updateConfig(): void { - this.columnConfig = this.columnConfig.map((config) => ({ ...config, sort: true })); + this.columnConfig = this.columnConfig.map((config) => ({ ...config, sortable: true })); } public sortDOMExists(key: Keys) { @@ -74,7 +74,7 @@ describe('Grid UI sort', () => { }); it('Non-sortable columns have no sort DOM', async () => { - await TDD.updateColumns({ key: 'id', sort: false }); + await TDD.updateColumns({ key: 'id', sortable: false }); TDD.sortDOMDoesNotExist('id'); }); @@ -254,7 +254,7 @@ describe('Grid UI sort', () => { }); it('Sort works on non-sortable columns', async () => { - await TDD.updateColumns({ key: 'id', sort: false }); + await TDD.updateColumns({ key: 'id', sortable: false }); await TDD.sort({ key: 'id', direction: 'descending' }); expect(TDD.rows.first.data.id).to.equal(8); diff --git a/test/grid.properties.test.ts b/test/grid.properties.test.ts index fbb8904..eb63e53 100644 --- a/test/grid.properties.test.ts +++ b/test/grid.properties.test.ts @@ -26,8 +26,8 @@ class InitialDataStateFixture extends GridTestFixture { (col) => html` { (col) => html`