@timlassiter11/yatl 0.3.22 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/events.ts","../src/utils.ts","../src/yatl-table.ts","../src/yatl-table.styles.ts"],"sourcesContent":["export * from './events';\nexport * from './types';\nexport * from './yatl-table';\n","import { SortOrder } from './types';\nimport { NestedKeyOf } from './utils';\n\nexport class YatlEvent<T = unknown> extends CustomEvent<T> {\n constructor(name: string, detail: T, options: EventInit = {}) {\n super(name, {\n bubbles: true,\n composed: true,\n cancelable: false,\n ...options,\n detail,\n });\n }\n}\n\nexport class YatlRowClickEvent<T> extends YatlEvent<{\n row: T;\n index: number;\n field: NestedKeyOf<T>;\n originalEvent: MouseEvent;\n}> {\n public static readonly EVENT_NAME = 'yatl-row-click';\n\n constructor(\n row: T,\n index: number,\n field: NestedKeyOf<T>,\n originalEvent: MouseEvent,\n ) {\n super(YatlRowClickEvent.EVENT_NAME, {\n row,\n index,\n field,\n originalEvent,\n });\n }\n}\n\nexport class YatlChangeEvent<T> extends YatlEvent<{ data: T[] }> {\n public static readonly EVENT_NAME = 'yatl-change';\n\n constructor(data: T[]) {\n super(YatlChangeEvent.EVENT_NAME, { data });\n }\n}\n\nexport class YatlSortEvent<T> extends YatlEvent<{\n field: NestedKeyOf<T>;\n order: SortOrder | null;\n}> {\n public static readonly EVENT_NAME = 'yatl-sort';\n\n constructor(field: NestedKeyOf<T>, order: SortOrder | null) {\n super(\n YatlSortEvent.EVENT_NAME,\n {\n field,\n order,\n },\n {\n cancelable: true,\n },\n );\n }\n}\n\nexport class YatlColumnToggleEvent<T> extends YatlEvent<{\n field: NestedKeyOf<T>;\n visible: boolean;\n}> {\n public static readonly EVENT_NAME = 'yatl-column-toggle';\n\n constructor(field: NestedKeyOf<T>, visible: boolean) {\n super(\n YatlColumnToggleEvent.EVENT_NAME,\n {\n field,\n visible,\n },\n {\n cancelable: true,\n },\n );\n }\n}\n\nexport class YatlColumnResizeEvent<T> extends YatlEvent<{\n field: NestedKeyOf<T>;\n width: number;\n}> {\n public static readonly EVENT_NAME = 'yatl-column-resize';\n\n constructor(field: NestedKeyOf<T>, width: number) {\n super(YatlColumnResizeEvent.EVENT_NAME, {\n field,\n width,\n });\n }\n}\n\nexport class YatlColumnReorderEvent<T> extends YatlEvent<{\n draggedColumn: NestedKeyOf<T>;\n droppedColumn: NestedKeyOf<T>;\n order: NestedKeyOf<T>[];\n}> {\n public static readonly EVENT_NAME = 'yatl-column-reorder';\n\n constructor(\n draggedColumn: NestedKeyOf<T>,\n droppedColumn: NestedKeyOf<T>,\n order: NestedKeyOf<T>[],\n ) {\n super(\n YatlColumnReorderEvent.EVENT_NAME,\n {\n draggedColumn,\n droppedColumn,\n order,\n },\n {\n cancelable: true,\n },\n );\n }\n}\n\nexport class YatlSearchEvent extends YatlEvent<{ query: string }> {\n public static readonly EVENT_NAME = 'yatl-search';\n\n constructor(query: string) {\n super(YatlSearchEvent.EVENT_NAME, { query });\n }\n}\n","import { html, TemplateResult } from 'lit';\nimport { ColumnState, Compareable } from './types';\n\nexport type NestedKeyOf<ObjectType> = ObjectType extends object\n ? {\n [Key in keyof ObjectType & (string | number)]: NonNullable<\n // Use NonNullable to include optional properties\n ObjectType[Key]\n > extends unknown[]\n ? `${Key}`\n : NonNullable<ObjectType[Key]> extends object\n ? // Recurse with the non-nullable type\n `${Key}` | `${Key}.${NestedKeyOf<NonNullable<ObjectType[Key]>>}`\n : `${Key}`;\n }[keyof ObjectType & (string | number)]\n : never;\n\n/*\n * Converts a string to a human-readable format.\n * - Replaces underscores with spaces\n * - Inserts spaces before uppercase letters (for camelCase)\n * - Capitalizes the first letter of each word\n *\n * @param {string} str - The input string to convert.\n * @returns {string} - The converted human-readable string.\n */\nexport const toHumanReadable = (str: string) => {\n return (\n str\n // Replace underscores with spaces\n .replace(/_/g, ' ')\n // Insert spaces before uppercase letters (for camelCase)\n .replace(/([a-z])([A-Z])/g, '$1 $2')\n // Capitalize the first letter of each word\n .replace(/\\b\\w/g, char => char.toUpperCase())\n );\n};\n\nexport const createRegexTokenizer = (exp: string = '\\\\S+') => {\n const regex = new RegExp(`\"[^\"]*\"|${exp}`, 'g');\n\n return (value: string) => {\n // Find all matches, which will include the quotes\n const matches = value.match(regex) || [];\n\n // Clean up the results by removing the surrounding quotes\n return matches.map(token => {\n token = token.toLocaleLowerCase().trim();\n if (token.startsWith('\"') && token.endsWith('\"')) {\n return { value: token.slice(1, -1), quoted: true };\n }\n return { value: token, quoted: false };\n });\n };\n};\n\nexport const whitespaceTokenizer = createRegexTokenizer();\n\n// Source - https://stackoverflow.com/a\n// Posted by Emma\n// Retrieved 2026-01-26, License - CC BY-SA 4.0\nexport function isStringRecord(obj: unknown): obj is Record<string, unknown> {\n if (typeof obj !== 'object') return false;\n\n if (Array.isArray(obj)) return false;\n\n if (Object.getOwnPropertySymbols(obj).length > 0) return false;\n\n return true;\n}\n\nfunction isValidKey<K extends string>(\n key: string,\n obj: Record<K, unknown>,\n): key is K {\n return key in obj;\n}\n\n/**\n * Get a value from an object based on a path.\n * @param obj - The object to get the value from\n * @param path - The path of the value\n * @returns The value found at the given path\n */\nexport function getNestedValue(obj: object, path: string): unknown {\n const keys = path.split('.');\n\n let current = obj;\n\n for (const key of keys) {\n if (current && isValidKey(key, current)) {\n current = current[key];\n } else {\n return undefined; // Or handle the error as needed\n }\n }\n\n return current;\n}\n\nexport function findColumn<T extends { field: string }>(\n field: string,\n columns: T[],\n) {\n return columns.find(c => c.field === field);\n}\n\n/**\n * Highlights sections of a string based on index ranges.\n * @param text - The original string to render.\n * @param ranges - An array of [start, end] tuples representing matches.\n * @returns A Lit TemplateResult with <mark> tags, or the original string if no ranges exist.\n */\nexport function highlightText(\n text: string,\n ranges: [number, number][],\n): TemplateResult | string {\n if (!text || !ranges || ranges.length === 0) {\n return text;\n }\n\n // 1. Sort ranges by start position to process linearly\n const sortedRanges = [...ranges].sort((a, b) => a[0] - b[0]);\n\n // 2. Merge overlapping ranges\n // Example: [[0, 5], [2, 6]] becomes [[0, 6]]\n const mergedRanges: [number, number][] = [];\n let currentRange = sortedRanges[0];\n\n for (let i = 1; i < sortedRanges.length; i++) {\n const nextRange = sortedRanges[i];\n\n if (nextRange[0] < currentRange[1]) {\n // Overlap detected: Extend the current end if needed\n currentRange[1] = Math.max(currentRange[1], nextRange[1]);\n } else {\n // No overlap: Push current and start a new one\n mergedRanges.push(currentRange);\n currentRange = nextRange;\n }\n }\n mergedRanges.push(currentRange);\n\n // 3. Slice the string\n const result: (string | TemplateResult)[] = [];\n let lastIndex = 0;\n\n for (const [start, end] of mergedRanges) {\n // Clamp values to prevent out-of-bounds errors\n const safeStart = Math.max(0, Math.min(start, text.length));\n const safeEnd = Math.max(0, Math.min(end, text.length));\n\n // Append non-highlighted text before the match\n if (safeStart > lastIndex) {\n result.push(text.slice(lastIndex, safeStart));\n }\n\n // Append highlighted text\n // We use the 'mark' tag, but you can change this to a span with a class\n result.push(\n html`<mark class=\"highlight\">${text.slice(safeStart, safeEnd)}</mark>`,\n );\n\n lastIndex = safeEnd;\n }\n\n // 4. Append any remaining text after the last match\n if (lastIndex < text.length) {\n result.push(text.slice(lastIndex));\n }\n\n return html`${result}`;\n}\n\nexport function widthsToGridTemplates(\n widths: Array<number | null>,\n defaultWidth = '1fr',\n) {\n return widths.map(width => (width ? `${width}px` : defaultWidth));\n}\n\nexport function didSortStateChange<T>(\n newState: ColumnState<T>[],\n oldState?: ColumnState<T>[],\n) {\n // If it is undefined it means this is the first render.\n if (!oldState) {\n return true;\n }\n\n const allKeys = new Set([\n ...oldState.map(s => s.field),\n ...newState.map(s => s.field),\n ]) as Set<NestedKeyOf<T>>;\n\n for (const key of allKeys) {\n const oldSort = findColumn(key, oldState)?.sortState;\n const newSort = findColumn(key, newState)?.sortState;\n\n if (\n oldSort?.order !== newSort?.order ||\n oldSort?.priority !== newSort?.priority\n ) {\n return true;\n }\n }\n return false;\n}\n\nexport function isCompareable(value: unknown): value is Compareable {\n return (\n typeof value === 'string' ||\n typeof value === 'number' ||\n typeof value === 'boolean' ||\n value instanceof Date\n );\n}\n","import type {\n ColumnFilterCallback,\n ColumnOptions,\n ColumnState,\n Compareable,\n FilterCallback,\n Filters,\n QueryToken,\n RestorableColumnState,\n RestorableTableState,\n RowPartsCallback,\n SortOrder,\n StorageOptions,\n TableState,\n TokenizerCallback,\n} from './types';\n\nimport {\n createRegexTokenizer,\n didSortStateChange,\n findColumn,\n getNestedValue,\n highlightText,\n isCompareable,\n NestedKeyOf,\n toHumanReadable,\n whitespaceTokenizer,\n widthsToGridTemplates,\n} from './utils';\n\nimport { html, LitElement, nothing, PropertyValues, TemplateResult } from 'lit';\nimport { customElement, property, query, state } from 'lit/decorators.js';\nimport { classMap } from 'lit/directives/class-map.js';\nimport { ifDefined } from 'lit/directives/if-defined.js';\nimport { repeat } from 'lit/directives/repeat.js';\nimport { styleMap } from 'lit/directives/style-map.js';\n\nimport '@lit-labs/virtualizer';\n\nimport styles from './yatl-table.styles';\nimport { LitVirtualizer } from '@lit-labs/virtualizer';\nimport {\n YatlChangeEvent,\n YatlColumnReorderEvent,\n YatlColumnResizeEvent,\n YatlColumnToggleEvent as YatlColumnToggleEvent,\n YatlRowClickEvent,\n YatlSearchEvent,\n YatlSortEvent,\n} from './events';\n\n// #region --- Constants ---\n\n// Debounce between state saves\nconst STATE_SAVE_DEBOUNCE = 1000;\n\nconst DEFAULT_STORAGE_OPTIONS: Partial<StorageOptions> = {\n storage: 'local',\n saveColumnSortOrders: true,\n saveColumnVisibility: true,\n saveColumnWidths: true,\n saveColumnOrder: true,\n};\n\n// Properties that should trigger a save\nconst SAVE_TRIGGERS = new Set<keyof YatlTable<object>>([\n 'searchQuery',\n 'filters',\n // Covers column order\n 'columns',\n // Covers sort, visibility, and width\n 'columnStates',\n 'storageOptions',\n]);\n\nconst MATCH_WEIGHTS = {\n EXACT: 100,\n PREFIX: 50,\n SUBSTRING: 10,\n};\n\n// #endregion\n\n/**\n * Represents a dynamic and interactive table with features like sorting, searching, filtering,\n * column resizing, column rearranging, and virtual scrolling.\n */\n@customElement('yatl-table')\nexport class YatlTable<T extends object> extends LitElement {\n public static override styles = [styles];\n\n @query('.table')\n private tableElement!: HTMLElement;\n @query('lit-virtualizer')\n private virtualizer?: LitVirtualizer;\n\n // #region --- State Data ---\n\n // Property data\n private _enableSearchTokenization = false;\n private _enableSearchScoring = false;\n private _columns: ColumnOptions<T>[] = [];\n private _columnStates: ColumnState<T>[] = [];\n private _storageOptions: StorageOptions | null = null;\n private _data: T[] = [];\n private _searchQuery = '';\n private _searchIncludedFields: NestedKeyOf<T>[] = [];\n private _searchTokenizer: TokenizerCallback = whitespaceTokenizer;\n private _filters: Filters<T> | FilterCallback<T> | null = null;\n\n @state()\n private _filteredData: T[] = [];\n\n // Flag if we have already restored the state or not.\n private hasRestoredState = false;\n\n // save state debounce timer\n private saveTimer = 0;\n\n // Flags set when something changes that\n // requires the filter or sort logic to re-run.\n private filterDirty = false;\n private sortDirty = false;\n\n // The last time the data was updated.\n // For displaying in the footer only.\n private dataLastUpdate: Date | null = null;\n\n // Maps rows to their metadata\n private rowMetadata = new WeakMap<T, RowMetadata>();\n // List of tokens created from the current query\n private queryTokens: QueryToken[] | null = null;\n // Column resize state\n private resizeState: {\n active: boolean;\n startX: number;\n startWidth: number;\n columnIndex: number;\n columnField: NestedKeyOf<T>;\n currentWidths: string[];\n } | null = null;\n\n // Column drag & drop state\n private dragColumn: NestedKeyOf<T> | null = null;\n\n // #endregion\n\n // #region --- Properties ---\n\n /**\n * Enables virtual scrolling for the table.\n * When enabled, only the visible rows are rendered to the DOM, significantly improving\n * performance for large datasets (1000+ rows).\n * @default false\n */\n @property({ type: Boolean, attribute: 'enable-virtual-scroll' })\n public enableVirtualScroll = false;\n\n /**\n * When enabled, text matching the current search query will be wrapped in `<mark>` tags.\n * This applies to all visible cells that contain the search term.\n * This does NOT apply to content rendered by the user such as the ColumnOptions.render callback.\n * @default true\n */\n @property({ type: Boolean, attribute: 'enable-search-highlight' })\n public enableSearchHighlight = true;\n\n /**\n * Enables tokenized search behavior.\n * When enabled, the search query is split into individual tokens using the\n * `searchTokenizer` function (defaults to splitting on whitespace).\n * A row is considered a match if **ANY** of the tokens appear in the searchable fields.\n * @default false\n */\n @property({ type: Boolean, attribute: 'enable-search-tokenization' })\n public get enableSearchTokenization() {\n return this._enableSearchTokenization;\n }\n\n public set enableSearchTokenization(enable) {\n if (this._enableSearchTokenization === enable) {\n return;\n }\n\n const oldValue = this._enableSearchTokenization;\n this._enableSearchTokenization = enable;\n this.updateInternalQuery();\n this.filterDirty = true;\n this.requestUpdate('enableSearchTokenization', oldValue);\n }\n\n /**\n * Enables weighted relevance scoring for search results.\n * When enabled, exact matches and prefix matches are ranked higher than substring matches.\n * Rows are sorted by their relevance score descending.\n * @default false\n */\n @property({ type: Boolean, attribute: 'enable-search-scoring' })\n public get enableSearchScoring() {\n return this._enableSearchScoring;\n }\n\n public set enableSearchScoring(enable) {\n if (this._enableSearchScoring === enable) {\n return;\n }\n\n const oldValue = this._enableSearchScoring;\n this._enableSearchScoring = enable;\n this.filterDirty = true;\n this.requestUpdate('enableSearchScoring', oldValue);\n }\n\n /**\n * Allows users to reorder columns by dragging and dropping headers.\n * @default true\n */\n @property({ type: Boolean, attribute: 'enable-column-reorder' })\n public enableColumnReorder = true;\n\n /**\n * Shows the built-in footer row which displays the current record count.\n * The footer content can be customized using the `slot=\"footer\"` element.\n * @default false\n */\n @property({ type: Boolean, attribute: 'enable-footer' })\n public enableFooter = false;\n\n /**\n * The string to display in a cell when the data value is `null` or `undefined`.\n * @default \"-\"\n */\n @property({ type: String, attribute: 'null-value-placeholder' })\n public nullValuePlaceholder = '-';\n\n /**\n * The message displayed when the `data` array is empty.\n * @default \"No records to display\"\n */\n @property({ type: String, attribute: 'empty-message' })\n public emptyMessage = 'No records to display';\n\n /**\n * The message displayed when `data` exists but the current search/filter\n * results in zero visible rows.\n * @default \"No matching records found\"\n */\n @property({ type: String, attribute: 'no-results-message' })\n public noResultsMessage = 'No matching records found';\n\n /**\n * The definitions for the columns to be rendered.\n * This defines the field mapping, titles, sortability, and other static options.\n */\n @property({ attribute: false })\n public get columns() {\n return this._columns;\n }\n\n public set columns(columns) {\n if (this._columns === columns) {\n return;\n }\n\n const oldValue = this._columns;\n this._columns = columns;\n this.createColumnStates();\n this.filterDirty = true;\n this.requestUpdate('columns', oldValue);\n }\n\n /**\n * The current dynamic state of the columns (width, visibility, sort order).\n * This property is updated automatically when users interact with the table.\n */\n @property({ attribute: false })\n public get columnStates(): ColumnState<T>[] {\n return this._columnStates.map(state => ({\n ...state,\n sortState: state.sortState ? { ...state.sortState } : undefined,\n }));\n }\n\n public set columnStates(states) {\n if (this._columnStates === states) {\n return;\n }\n\n const oldValue = this._columnStates;\n this._columnStates = states;\n\n if (didSortStateChange(this._columnStates, oldValue)) {\n this.sortDirty = true;\n }\n\n this.requestUpdate('columnStates', oldValue);\n }\n\n /**\n * The current text string used to filter the table data.\n * Setting this property triggers a new search and render cycle.\n */\n @property({ type: String, attribute: 'search-query' })\n public get searchQuery() {\n return this._searchQuery;\n }\n\n public set searchQuery(query) {\n if (this._searchQuery === query) {\n return;\n }\n\n const oldValue = this._searchQuery;\n this._searchQuery = query;\n this.updateInternalQuery();\n this.filterDirty = true;\n this.requestUpdate('searchQuery', oldValue);\n }\n\n /**\n * A list of extra data fields to include in the search index, even if they are not\n * displayed as visible columns. Useful for searching by ID, hidden keywords, or tags.\n */\n @property({ type: Array, attribute: 'search-included-fields' })\n public get searchIncludedFields() {\n return this._searchIncludedFields;\n }\n\n public set searchIncludedFields(fields) {\n if (this._searchIncludedFields === fields) {\n return;\n }\n\n const oldValue = this._searchIncludedFields;\n this._searchIncludedFields = fields;\n this.filterDirty = true;\n this.requestUpdate('searchIncludedFields', oldValue);\n }\n\n /**\n * A function that splits the search query into tokens.\n * Only used if `enableSearchTokenization` is true.\n * @default whitespaceTokenizer\n */\n @property({ attribute: false })\n public get searchTokenizer() {\n return this._searchTokenizer;\n }\n\n public set searchTokenizer(tokenizer) {\n if (this._searchTokenizer === tokenizer) {\n return;\n }\n\n const oldValue = this._searchTokenizer;\n this._searchTokenizer = tokenizer;\n this.filterDirty = true;\n this.requestUpdate('searchTokenizer', oldValue);\n }\n\n /**\n * An optional set of criteria to filter the visible rows.\n * This runs **before** the global search query is applied.\n * * You can provide:\n * 1. A **Partial Object**: matches rows where specific keys equal specific values (AND logic).\n * 2. A **Callback Function**: returns `true` to keep the row, `false` to hide it.\n * * @example\n * // 1. Object Syntax (Simple Exact Match)\n * // Shows rows where status is 'active' AND role is 'admin'\n * table.filters = { status: 'active', role: 'admin' };\n * * @example\n * // 2. Callback Syntax (Complex Logic)\n * // Shows rows where age is over 21 OR they are a VIP\n * table.filters = (row) => row.age > 21 || row.isVip;\n */\n @property({ attribute: false })\n public get filters() {\n return this._filters;\n }\n\n public set filters(filters) {\n if (this._filters === filters) {\n return;\n }\n\n const oldValue = this._filters;\n this._filters = filters;\n this.filterDirty = true;\n this.requestUpdate('filters', oldValue);\n }\n\n /**\n * A callback function to conditionally apply CSS parts to table rows.\n */\n @property({ attribute: false })\n public rowParts: RowPartsCallback<T> | null = null;\n\n /**\n * Configuration options for automatically saving and restoring table state\n * (column width, order, visibility, etc.) to browser storage.\n */\n @property({ type: Object, attribute: 'storage-options' })\n public get storageOptions() {\n return this._storageOptions;\n }\n\n public set storageOptions(options) {\n if (this._storageOptions === options) {\n return;\n }\n\n const oldValue = this._storageOptions;\n this._storageOptions = options;\n if (!this.hasRestoredState) {\n this.loadStateFromStorage();\n }\n this.requestUpdate('storageOptions', oldValue);\n }\n\n /**\n * The array of data objects to be displayed.\n * Objects must satisfy the `WeakKey` constraint (objects only, no primitives).\n */\n @property({ attribute: false })\n public get data() {\n return this._data;\n }\n\n public set data(value: T[]) {\n const oldValue = this._data;\n this._data = value;\n this.dataLastUpdate = new Date();\n this.createMetadata();\n this.filterDirty = true;\n this.requestUpdate('data', oldValue);\n }\n\n get filteredData() {\n if (this.filterDirty) {\n this.filterRows();\n } else if (this.sortDirty) {\n this.sortRows();\n }\n\n this.filterDirty = false;\n this.sortDirty = false;\n\n return [...this._filteredData];\n }\n\n // #endregion\n\n // #region --- Public Methods ---\n\n /**\n * Gets a copy of the current state of the table.\n */\n public getState(): TableState<T> {\n const states = this.columnStates;\n return {\n searchQuery: this.searchQuery,\n filters: this.filters,\n columnOrder: this.columns.map(column => column.field),\n columns: this.columns.map(column => {\n const columnState = findColumn(column.field, states);\n return {\n field: column.field,\n visible: columnState?.visible ?? true,\n sortState: columnState?.sortState,\n width: columnState?.width,\n };\n }),\n };\n }\n\n /**\n * Restores the table to the provided state.\n * @param state - The state to restore the table to.\n */\n public restoreState(state: RestorableTableState<T>) {\n if ('searchQuery' in state && state.searchQuery !== undefined) {\n this.searchQuery = state.searchQuery;\n }\n\n if ('filters' in state && state.filters !== undefined) {\n this.filters = state.filters;\n }\n\n if ('columnOrder' in state && state.columnOrder !== undefined) {\n this.setColumnOrder(state.columnOrder);\n }\n\n if ('columns' in state && state.columns !== undefined) {\n const newColumnStates: ColumnState<T>[] = [];\n\n for (const newState of state.columns) {\n // We don't check if this is a valid column becuase we\n // could be restoring the state before the columns are loaded.\n const currentState = findColumn(newState.field, this._columnStates) ?? {\n field: newState.field,\n visible: true,\n };\n\n newColumnStates.push(currentState);\n\n if (!newState) {\n continue;\n }\n\n if ('visible' in newState && newState.visible !== undefined) {\n currentState.visible = newState.visible;\n }\n\n if ('sortState' in newState && newState.sortState !== undefined) {\n currentState.sortState = newState.sortState;\n }\n\n if ('width' in newState && newState.width !== undefined) {\n currentState.width = newState.width;\n }\n }\n this.columnStates = newColumnStates;\n }\n }\n\n /**\n * Sorts the table by a specified column and order.\n * If `order` is `null`, the sort on this column is removed.\n * @param field - The field name of the column to sort by.\n * @param order - The sort order: 'asc', 'desc', or `null` to remove sorting for this column.\n * @param clear - Clear all other sorting\n */\n public sort(\n field: NestedKeyOf<T>,\n order: SortOrder | null,\n clear: boolean = true,\n ) {\n // Get a copy of the current column states.\n const columnStates = this.columnStates;\n const state = findColumn(field, columnStates);\n if (!state) {\n throw new Error(`Cannot get options for non-existent column \"${field}\"`);\n }\n\n if (order === state.sortState?.order) {\n return;\n }\n\n if (!this.dispatchEvent(new YatlSortEvent(field, order))) {\n return;\n }\n\n // Column was unsorted, give it a new priority\n if (order && !state.sortState) {\n // Create a list of current sort priorities\n const priorities = columnStates\n .map(col => col.sortState?.priority)\n .filter(priority => priority !== undefined);\n\n const maxPriority = this.columns.length + 1;\n const priority = Math.min(maxPriority, ...priorities) - 1;\n state.sortState = { order, priority };\n } else if (order && state.sortState) {\n // Column was sorted, just updated the order\n state.sortState.order = order;\n } else {\n state.sortState = null;\n }\n\n // Clear all other sorting\n if (clear) {\n for (const state of columnStates) {\n if (state.field !== field) {\n state.sortState = null;\n }\n }\n }\n\n this.columnStates = columnStates;\n }\n\n /**\n * Sets the visibility of a specified column.\n * @param field - The field name of the column.\n * @param visible - `true` to show the column, `false` to hide it.\n */\n public setColumnVisibility(field: NestedKeyOf<T>, visible: boolean) {\n const columnStates = this.columnStates;\n const state = findColumn(field, columnStates);\n if (!state) {\n throw new Error(`Cannot get options for non-existent column \"${field}\"`);\n }\n\n if (state.visible === visible) {\n return;\n }\n\n if (!this.dispatchEvent(new YatlColumnToggleEvent(field, visible))) {\n return;\n }\n\n state.visible = visible;\n this.columnStates = columnStates;\n }\n\n /**\n * Toggles the visibility of hte specified column\n * @param field - The field name of the column to toggle.\n */\n public toggleColumnVisibility(field: NestedKeyOf<T>) {\n const state = findColumn(field, this._columnStates);\n // If state is null here becuase the column doesn't exist\n // setColumnVisibility will throw an error. We don't need to.\n this.setColumnVisibility(field, !state);\n }\n\n /**\n * Shows the specified column\n * @param field - The field name of the column to show.\n */\n public showColumn(field: NestedKeyOf<T>) {\n this.setColumnVisibility(field, true);\n }\n\n /**\n * Hides the specified column\n * @param field - The field name of the column to hide.\n */\n public hideColumn(field: NestedKeyOf<T>) {\n this.setColumnVisibility(field, false);\n }\n\n /**\n * Export the current visible table data to a CSV file.\n * @param filename - The name of the file to save.\n * @param all - If `true`, exports all original data (ignoring filters). If `false` (default), exports only the currently visible (filtered and sorted) rows.\n */\n public export(filename: string, all = false) {\n const data = all ? this.data : this.filteredData;\n const rows = [...data.values()];\n\n const columnData = this.columnData;\n\n const csvHeaders = columnData\n .filter(col => all || col.state?.visible)\n .map(col => `\"${col.options.title}\"`)\n .join(',');\n\n const csvRows = rows\n .map(row => {\n const list: string[] = [];\n for (const col of columnData) {\n let value = getNestedValue(row, col.field);\n if (all || col.state.visible) {\n if (typeof col.options.valueFormatter === 'function') {\n value = col.options.valueFormatter(value, row);\n }\n\n value = String(value).replace('\"', '\"\"');\n list.push(`\"${value}\"`);\n }\n }\n return list.join(',');\n })\n .join('\\n');\n\n const csvContent = csvHeaders + '\\n' + csvRows;\n const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8,' });\n const a = document.createElement('a');\n a.style.display = 'none';\n a.href = URL.createObjectURL(blob);\n a.download = `${filename}.csv`;\n document.body.append(a);\n a.click();\n a.remove();\n }\n\n public scrollToRow(row: T) {\n const index = this.data.findIndex(v => v === row);\n if (typeof index === 'number') {\n return this.scrollToOriginalIndex(index);\n } else {\n throw new Error('Row not in table');\n }\n }\n\n /**\n * Scrolls the table to bring the row at the specified original index into view.\n * @param index - The original index of the row (from the initial dataset).\n */\n public scrollToOriginalIndex(index: number) {\n const rowData = this.data[index];\n if (rowData) {\n const filteredIndex = this.filteredData.indexOf(rowData);\n if (filteredIndex >= 0) {\n return this.scrollToFilteredIndex(filteredIndex);\n } else {\n throw new Error('Cannot scroll to filtered out row');\n }\n } else {\n throw new RangeError(`Row index ${index} out of range`);\n }\n }\n\n public async scrollToFilteredIndex(index: number) {\n // FIXME: Scrolling to an index using lit-virtualizer is buggy.\n // It usually stops short of the requested index.\n // The amount it stops short seems to be proportinal to how far away the index is.\n // Scrolling without VS works but since I use sticky headers, it seems to be one row off.\n\n const rowData = this.filteredData[index];\n if (!rowData) {\n throw new RangeError(`Row index ${index} out of range`);\n }\n\n await this.updateComplete;\n\n // TODO: Should I check if virtual scroll is enabled\n // or just rely on the appropriate elements existing?\n if (this.virtualizer) {\n this.virtualizer.element(index)?.scrollIntoView({\n block: 'start',\n behavior: 'instant',\n });\n } else {\n const row = this.tableElement.querySelector(\n `.row[data-filtered-index=\"${index}\"]`,\n );\n row?.scrollIntoView({\n block: 'start',\n behavior: 'smooth',\n });\n }\n }\n\n public async scrollToPx(px: number) {\n // FIXME: This doesn't work with lit-virtualizer at all.\n\n await this.updateComplete;\n\n if (this.virtualizer) {\n this.virtualizer.scrollTop = px;\n } else {\n this.tableElement.scrollTop = px;\n }\n }\n\n /**\n * Sets the display order of the columns in the table.\n *\n * @param fields - An array of field names representing the new order of columns. Columns not included in the array will be placed at the end.\n * @throws {TypeError} If `fields` is not an array.\n */\n public setColumnOrder(fields: NestedKeyOf<T>[]) {\n const newColumns: ColumnOptions<T>[] = [];\n for (const field of fields) {\n const col = findColumn(field, this.columns);\n if (col) {\n newColumns.push(col);\n }\n }\n\n for (const col of this.columns) {\n if (!findColumn(col.field, newColumns)) {\n newColumns.push(col);\n }\n }\n\n this.columns = [...newColumns];\n }\n\n /**\n * Finds the first row\n * @param field\n * @param value\n * @returns\n */\n public findRow(field: NestedKeyOf<T>, value: unknown) {\n return this.data.find(row => {\n const rowValue = getNestedValue(row, field);\n return rowValue === value;\n });\n }\n\n /**\n * Finds the original index of the first row where the specified field matches the given value.\n * This searches through the original, unfiltered dataset.\n * @param field - The field name within the row data to search.\n * @param value - The value to match against the field's content.\n * @returns The original index of the found row, or -1 if no match is found.\n * @example\n * ```ts\n * const index = dataTable.indexOf('id', 12345);\n * if (index >= 0) {\n * dataTable.updateRow({description: \"Updated description\"}, index);\n * }\n * ```\n */\n public findRowIndex(field: NestedKeyOf<T>, value: unknown) {\n const row = this.findRow(field, value);\n if (row) {\n return this.rowMetadata.get(row)!.index;\n }\n return -1;\n }\n\n /**\n * Updates the data of a row at a specific original index.\n * @param index - The original index of the row to update.\n * @param data - An object containing the new data to assign to the row. Existing fields will be updated, and new fields will be added.\n *\n * @example\n * ```ts\n * const index = dataTable.indexOf('id', 12345);\n * if (index >= 0) {\n * dataTable.updateRow(index, {description: \"Updated description\"});\n * }\n * ```\n */\n public updateRow(index: number, data: Partial<T>) {\n const current_row = this.data[index];\n if (current_row) {\n Object.assign(current_row, data);\n this.requestUpdate('data');\n }\n }\n\n /**\n * Deletes a row at a specific original index from the table.\n * @param index - The original index of the row to delete.\n */\n public deleteRow(index: number) {\n this.data = this.data.toSpliced(index, 1);\n }\n\n // #endregion\n\n // #region --- Render Methods ---\n\n protected renderColumnSortIcon(\n column: ColumnOptions<T>,\n state: ColumnState<T>,\n ) {\n return column.sortable\n ? html`<div\n part=\"header-sort-icon\"\n class=${classMap({\n 'sort-icon': true,\n ascending: state.sortState?.order === 'asc',\n descending: state.sortState?.order === 'desc',\n })}\n ></div>`\n : nothing;\n }\n\n protected renderColumnResizer(\n column: ColumnOptions<T>,\n _state: ColumnState<T>,\n ) {\n return column.resizable\n ? html`<div\n part=\"header-resizer\"\n class=\"resizer\"\n @click=${(event: MouseEvent) => event.stopPropagation()}\n @mousedown=${(event: MouseEvent) =>\n this.handleResizeMouseDown(event, column.field)}\n ></div>`\n : nothing;\n }\n\n protected renderHeaderCell(column: ColumnOptions<T>) {\n const state = findColumn(column.field, this._columnStates)!;\n if (state.visible == false) {\n return nothing;\n }\n\n return html`\n <div\n part=\"cell header-cell\"\n class=${classMap({\n cell: true,\n sortable: column.sortable ?? false,\n })}\n draggable=${ifDefined(this.enableColumnReorder ? true : undefined)}\n data-field=${column.field}\n @dragstart=${(event: DragEvent) =>\n this.handleDragColumnStart(event, column.field)}\n @dragenter=${this.handleDragColumnEnter}\n @dragleave=${this.handleDragColumnLeave}\n @dragover=${this.handleDragColumnOver}\n @drop=${(event: DragEvent) =>\n this.handleDragColumnDrop(event, column.field)}\n @dragend=${this.handleDragColumnEnd}\n @click=${(event: MouseEvent) => this.handleHeaderClicked(event, column)}\n >\n <div class=\"header-content\">\n <span class=\"header-title truncate\" part=\"header-title\">\n ${column.title ?? toHumanReadable(column.field)}\n </span>\n ${this.renderColumnSortIcon(column, state)}\n </div>\n ${this.renderColumnResizer(column, state)}\n <div part=\"drop-indicator\" class=\"drop-indicator\"></div>\n </div>\n `;\n }\n\n protected renderHeader() {\n return html`\n <div part=\"header\" class=\"header row\">\n ${this.columns.map(column => this.renderHeaderCell(column))}\n </div>\n `;\n }\n\n protected renderCellContents(\n value: unknown,\n column: ColumnOptions<T>,\n row: T,\n ) {\n if (column.cellRenderer) {\n return column.cellRenderer(value, column.field, row);\n }\n\n if (value == null) {\n return this.nullValuePlaceholder;\n }\n\n const indices = this.rowMetadata.get(row)!.highlightIndices;\n\n return this.enableSearchHighlight && indices\n ? highlightText(String(value), indices[column.field])\n : value;\n }\n\n protected renderCell(column: ColumnOptions<T>, row: T) {\n const state = findColumn(column.field, this._columnStates);\n if (state?.visible == false) {\n return nothing;\n }\n\n let value = getNestedValue(row, column.field);\n // Get the user parts from the raw value\n // before we call the value formatter.\n let userParts = column.cellParts?.call(this, value, column.field, row);\n if (Array.isArray(userParts)) {\n userParts = userParts.join(' ');\n }\n\n if (typeof column.valueFormatter === 'function') {\n value = column.valueFormatter(value, row);\n }\n\n return html`\n <div\n part=\"cell body-cell cell-${column.field} ${userParts}\"\n data-field=${column.field}\n class=\"cell\"\n title=${ifDefined(value ? String(value) : undefined)}\n @click=${(event: MouseEvent) =>\n this.handleCellClick(event, row, column.field)}\n >\n <span class=\"truncate\">\n ${this.renderCellContents(value, column, row)}\n </span>\n </div>\n `;\n }\n\n protected renderRow(row: T, index: number) {\n const metadata = this.rowMetadata.get(row)!;\n let userParts = this.rowParts?.(row) ?? '';\n if (Array.isArray(userParts)) {\n userParts = userParts.join(' ');\n }\n\n return html`\n <div\n part=${'row ' + userParts}\n class=\"row\"\n data-index=${metadata.index}\n data-filtered-index=${index}\n >\n ${this.columns.map(column => this.renderCell(column, row))}\n </div>\n `;\n }\n\n protected renderBody() {\n if (this.columnWidths.length === 0) {\n return html`\n <div part=\"message\" class=\"message\">No visible columns.</div>\n `;\n }\n\n if (this.data.length === 0) {\n return html`<div part=\"message\" class=\"message\">\n ${this.emptyMessage}\n </div>`;\n }\n if (this.filteredData.length === 0) {\n return html`<div part=\"message\" class=\"message\">\n ${this.noResultsMessage}\n </div>`;\n }\n\n if (this.enableVirtualScroll) {\n return html`\n <lit-virtualizer\n .items=${this.filteredData}\n .renderItem=${(item: T, index: number) =>\n this.renderRow(item, index) as TemplateResult}\n ></lit-virtualizer>\n `;\n }\n\n return html`\n ${repeat(\n this.filteredData,\n item => this.rowMetadata.get(item)!.index,\n (item, index) => this.renderRow(item, index),\n )}\n `;\n }\n\n protected renderFooter() {\n if (!this.enableFooter) {\n return nothing;\n }\n\n const total = this.data.length;\n const filtered = this.filteredData.length;\n\n const fmt = new Intl.NumberFormat(undefined);\n const totalStr = fmt.format(total);\n const filteredStr = fmt.format(filtered);\n\n const rowCountText =\n total !== filtered\n ? `Showing ${filteredStr} of ${totalStr} records`\n : `Total records: ${totalStr}`;\n\n const formatter = Intl.DateTimeFormat(undefined, {\n dateStyle: 'short',\n timeStyle: 'short',\n });\n const lastUpdateText = this.dataLastUpdate\n ? formatter.format(this.dataLastUpdate)\n : 'Never';\n\n return html`\n <div part=\"footer\" class=\"footer\">\n <slot name=\"footer\">\n <span part=\"row-count\">${rowCountText}</span>\n <span part=\"timestamp\">${lastUpdateText}</span>\n </slot>\n </div>\n `;\n }\n\n protected override render() {\n const gridTemplate = widthsToGridTemplates(this.columnWidths).join(' ');\n\n return html`\n <div\n part=\"table\"\n class=\"table\"\n style=${styleMap({ '--grid-template': gridTemplate })}\n >\n ${this.renderHeader()} ${this.renderBody()} ${this.renderFooter()}\n </div>\n `;\n }\n\n // #endregion\n\n // #region --- Lifecycle Methods ---\n\n protected override updated(changedProperties: PropertyValues<YatlTable<T>>) {\n super.updated(changedProperties);\n\n if (!this.storageOptions?.key) return;\n const shouldSave = Array.from(changedProperties.keys()).some(prop =>\n SAVE_TRIGGERS.has(prop as keyof YatlTable<T>),\n );\n\n if (shouldSave) {\n this.scheduleSave();\n }\n }\n\n public override disconnectedCallback(): void {\n super.disconnectedCallback();\n window.addEventListener('mousemove', this.handleResizeMouseMove);\n window.addEventListener('mouseup', this.handleResizeMouseUp);\n }\n\n // #endregion\n\n // #region --- Filter Methods ---\n\n /**\n * Calculates a relevance score for a given query against a target string.\n *\n * This function implements a tiered matching strategy:\n * 1. **Exact Match**: The query exactly matches the target. This yields the highest score.\n * 2. **Prefix Match**: The target starts with the query. This is the next most relevant.\n * 3. **Substring Match**: The target contains the query somewhere. This is the least relevant.\n *\n * The final score is weighted and adjusted by the length difference between the query and the target\n * to ensure that more specific matches (e.g., \"apple\" vs \"application\" for the query \"apple\") rank higher.\n *\n * @param query The search term (e.g., \"app\").\n * @param target The string to be searched (e.g., \"Apple\" or \"Application\").\n * @returns A numerical score representing the relevance of the match. Higher is better. Returns 0 if no match is found.\n */\n private calculateSearchScore(query: string, target: string): SearchResult {\n const results: SearchResult = { score: 0, ranges: [] };\n\n if (!query || !target) {\n return results;\n }\n\n let baseScore = 0;\n let matchTypeWeight = 0;\n\n if (target === query) {\n matchTypeWeight = MATCH_WEIGHTS.EXACT;\n baseScore = query.length;\n results.ranges.push([0, target.length]);\n } else if (target.startsWith(query)) {\n matchTypeWeight = MATCH_WEIGHTS.PREFIX;\n baseScore = query.length;\n results.ranges.push([0, query.length]);\n } else {\n const index = target.indexOf(query);\n if (index !== -1) {\n matchTypeWeight = MATCH_WEIGHTS.SUBSTRING;\n baseScore = query.length;\n\n let cursor = index;\n while (cursor !== -1) {\n results.ranges.push([cursor, cursor + query.length]);\n cursor = target.indexOf(query, cursor + 1);\n }\n } else {\n return results;\n }\n }\n\n // Reward matches where the query length is close to the target length.\n const lengthDifference = target.length - query.length;\n const specificityBonus = 1 / (1 + lengthDifference);\n\n // The final score is a combination of the match type's importance,\n // the base score from the query length, and the specificity bonus.\n results.score = baseScore * matchTypeWeight * specificityBonus;\n return results;\n }\n\n private searchField(\n query: QueryToken,\n value: string,\n tokens?: string[],\n ): SearchResult {\n const result: SearchResult = { score: 0, ranges: [] };\n\n const addRangesFromValue = (searchTerm: string) => {\n let idx = value.indexOf(searchTerm);\n while (idx !== -1) {\n result.ranges.push([idx, idx + searchTerm.length]);\n idx = value.indexOf(searchTerm, idx + 1);\n }\n };\n\n // Handle Quoted/Untokenized (Direct Search)\n if (query.quoted || !tokens) {\n if (!this.enableSearchScoring) {\n // Simple boolean match\n if (value.includes(query.value)) {\n result.score = 1;\n addRangesFromValue(query.value);\n }\n } else {\n // Scored match\n const calculation = this.calculateSearchScore(query.value, value);\n result.score = calculation.score;\n result.ranges = calculation.ranges;\n }\n return result;\n }\n\n // Handle Tokenized Search\n // We search the tokens to check for validity/scoring,\n // but we map back to the 'value' for highlighting.\n if (!this.enableSearchScoring) {\n const isMatch = tokens.some(token => token.includes(query.value));\n if (isMatch) {\n result.score = 1;\n addRangesFromValue(query.value);\n }\n return result;\n }\n\n // Complex Scored Token Search\n // We sum the scores of all matching tokens\n for (const token of tokens) {\n const calculation = this.calculateSearchScore(query.value, token);\n if (calculation.score > 0) {\n result.score += calculation.score;\n // If a token matched, find that query in the main string\n addRangesFromValue(query.value);\n }\n }\n\n return result;\n }\n\n private filterField(\n value: unknown,\n filter: unknown,\n filterFunction: ColumnFilterCallback | null = null,\n ): boolean {\n if (Array.isArray(filter)) {\n if (filter.length === 0) {\n return true;\n }\n // If it's an array, we will use an OR filter.\n // If any filters in the array match, keep it.\n return filter.some(element =>\n this.filterField(value, element, filterFunction),\n );\n }\n\n if (Array.isArray(value)) {\n if (value.length === 0) {\n return false;\n }\n return value.some(element =>\n this.filterField(element, filter, filterFunction),\n );\n }\n\n if (typeof filterFunction === 'function') {\n return filterFunction(value, filter);\n }\n\n if (filter instanceof RegExp) {\n return filter.test(String(value));\n }\n\n return filter === value;\n }\n\n private filterRow(row: T, index: number): boolean {\n if (!this.filters) {\n return true;\n }\n\n if (typeof this.filters === 'function') {\n return this.filters(row, index);\n }\n\n for (const field in this.filters) {\n const filter = getNestedValue(this.filters, field);\n const value = getNestedValue(row, field);\n if (typeof filter === 'function') {\n if (!filter(value)) {\n return false;\n }\n } else {\n const col = findColumn(field, this.columns);\n const filterCallback = col ? col.filter : undefined;\n if (!this.filterField(value, filter, filterCallback)) {\n return false;\n }\n }\n }\n return true;\n }\n\n private filterRows() {\n const searchableFields = [...this.columnData.values()]\n .filter(col => col.options.searchable)\n .map(c => c.field);\n\n const fields = [...searchableFields, ...this.searchIncludedFields];\n\n this._filteredData = this.data.filter((row, index) => {\n const metadata = this.rowMetadata.get(row)!;\n metadata.searchScore = 0;\n metadata.highlightIndices = {};\n // Filter takes precedence over search.\n if (!this.filterRow(row, index)) {\n return false;\n }\n\n if (!this.queryTokens) {\n return true;\n }\n\n for (const field of fields) {\n const originalValue = getNestedValue(row, field);\n const compareValue = metadata.searchValues[field];\n const columnTokens = metadata.searchTokens[field];\n\n if (\n typeof originalValue !== 'string' ||\n typeof compareValue !== 'string'\n ) {\n continue;\n }\n\n const fieldResults: SearchResult = { score: 0, ranges: [] };\n for (const token of this.queryTokens) {\n const results = this.searchField(token, compareValue, columnTokens);\n fieldResults.score += results.score;\n fieldResults.ranges.push(...results.ranges);\n }\n\n if (fieldResults.score > 0) {\n metadata.searchScore += fieldResults.score;\n metadata.highlightIndices[field] = fieldResults.ranges;\n }\n }\n\n return metadata.searchScore > 0;\n });\n\n this.filterDirty = false;\n\n this.sortRows();\n this.dispatchEvent(new YatlChangeEvent(this.data));\n }\n\n // #endregion\n\n // #region --- Sort Methods ---\n\n private compareRows(a: T, b: T, field: NestedKeyOf<T>): number {\n let aValue, bValue;\n\n const columnData = findColumn(field, this.columnData)!;\n\n if (!columnData.state.sortState) {\n return 0;\n }\n\n const aMetadata = this.rowMetadata.get(a)!;\n const bMetadata = this.rowMetadata.get(b)!;\n\n if (columnData.state.sortState?.order === 'asc') {\n aValue = aMetadata.sortValues[columnData.field];\n bValue = bMetadata.sortValues[columnData.field];\n } else {\n aValue = bMetadata.sortValues[columnData.field];\n bValue = aMetadata.sortValues[columnData.field];\n }\n\n if (typeof columnData.options.sorter === 'function') {\n const ret = columnData.options.sorter(aValue, bValue);\n if (ret !== 0) return ret;\n }\n\n const aIsNull = aValue == null;\n const bIsNull = bValue == null;\n\n if (aIsNull && !bIsNull) return -1;\n if (bIsNull && !aIsNull) return 1;\n\n if (aValue < bValue) return -1;\n if (aValue > bValue) return 1;\n return 0;\n }\n\n private sortRows() {\n if (this.filterDirty) {\n this.filterRows();\n return;\n }\n\n const sortedColumns = this.columnData\n // Filter to visible columns with active sort states\n .filter(col => col.state.visible && col.state.sortState)\n // Sort our columns by their sort priority.\n // This is how sorting by multiple columns is handled.\n .sort(\n (a, b) => b.state.sortState!.priority - a.state.sortState!.priority,\n );\n\n this._filteredData = this._filteredData.toSorted((a, b) => {\n const aMetadata = this.rowMetadata.get(a)!;\n const bMetadata = this.rowMetadata.get(b)!;\n\n // Try to sort by search score if we're using scoring and there is a query.\n if (this.enableSearchScoring && this.queryTokens) {\n const aValue = aMetadata.searchScore || 0;\n const bValue = bMetadata.searchScore || 0;\n if (aValue > bValue) return -1;\n if (aValue < bValue) return 1;\n }\n\n for (const col of sortedColumns) {\n const comp = this.compareRows(a, b, col.field);\n if (comp !== 0) {\n return comp;\n }\n }\n\n // Always fall back to the index column\n return aMetadata.index - bMetadata.index;\n });\n this.sortDirty = false;\n }\n\n // #endregion\n\n // #region --- State Methods ---\n\n private createColumnStates() {\n this.columnStates = this.columns.map(column => {\n const previousState = findColumn(column.field, this._columnStates);\n return {\n field: column.field,\n visible: previousState?.visible ?? true,\n sortState: previousState?.sortState,\n width: previousState?.width,\n };\n });\n }\n\n private createMetadata() {\n this.rowMetadata = new WeakMap();\n\n let index = 0;\n for (const row of this.data) {\n // Add the index\n const metadata: RowMetadata = {\n index: index++,\n searchTokens: {},\n searchValues: {},\n sortValues: {},\n };\n this.rowMetadata.set(row, metadata);\n\n for (const column of this.columns) {\n const value = getNestedValue(row, column.field);\n\n // Cache precomputed values for sorting\n if (typeof column.sortValue === 'function') {\n metadata.sortValues[column.field] = column.sortValue(value);\n } else if (typeof value === 'string') {\n metadata.sortValues[column.field] = value.toLocaleLowerCase();\n } else if (isCompareable(value)) {\n metadata.sortValues[column.field] = value;\n } else {\n metadata.sortValues[column.field] = String(value);\n }\n\n // Cache precomputed lower-case values for search\n if (typeof value === 'string') {\n metadata.searchValues[column.field] = value.toLocaleLowerCase();\n }\n\n // Tokenize any searchable columns\n if (column.searchable && column.tokenize && value) {\n const tokenizer = column.searchTokenizer ?? this.searchTokenizer;\n metadata.searchTokens[column.field] = tokenizer(String(value)).map(\n token => token.value,\n );\n }\n }\n\n // Add any extra search fields\n for (const field of this.searchIncludedFields) {\n const value = getNestedValue(row, field);\n // Cache precomputed lower-case values for search\n if (typeof value === 'string') {\n metadata.searchValues[field] = value.toLocaleLowerCase();\n }\n }\n }\n }\n\n private updateInternalQuery() {\n if (this.searchQuery.length === 0) {\n this.queryTokens = null;\n return;\n }\n\n this.queryTokens = [\n { value: this.searchQuery.toLocaleLowerCase(), quoted: true },\n ];\n\n if (this.enableSearchTokenization) {\n this.queryTokens.push(...this.searchTokenizer(this.searchQuery));\n }\n }\n\n // #endregion\n\n // #region --- Utilities ---\n\n private get columnData() {\n return this.columns.map(column => ({\n field: column.field,\n options: column,\n state: findColumn(column.field, this._columnStates) ?? {\n field: column.field,\n visible: true,\n },\n }));\n }\n\n private get columnWidths() {\n // Search through the user defined columns (not the states just in case)\n // Filter out any hidden columns (columns with no state are considered visible)\n return this.columns\n .map(col => findColumn(col.field, this._columnStates))\n .filter(state => (state ? state.visible : true))\n .map(state => state?.width ?? null);\n }\n\n private scheduleSave() {\n window.clearTimeout(this.saveTimer);\n\n this.saveTimer = window.setTimeout(() => {\n this.saveStateToStorage();\n }, STATE_SAVE_DEBOUNCE);\n }\n\n // #endregion\n\n // #region --- Storage Methods ---\n\n private saveStateToStorage() {\n if (!this.storageOptions) {\n return;\n }\n\n const options = { ...DEFAULT_STORAGE_OPTIONS, ...this.storageOptions };\n const savedTableState: RestorableTableState<T> = {\n columns: [],\n };\n const tableState = this.getState();\n\n if (options.saveColumnOrder) {\n savedTableState.columnOrder = tableState.columnOrder;\n }\n\n for (const columnState of tableState.columns) {\n const savedColumnState: RestorableColumnState<T> = {\n field: columnState.field,\n };\n\n if (options.saveColumnSortOrders) {\n savedColumnState.sortState = columnState.sortState;\n }\n\n if (options.saveColumnVisibility) {\n savedColumnState.visible = columnState.visible;\n }\n\n if (options.saveColumnWidths) {\n savedColumnState.width = columnState.width;\n }\n\n savedTableState.columns?.push(savedColumnState);\n }\n\n const storage =\n options.storage === 'session' ? sessionStorage : localStorage;\n try {\n storage.setItem(options.key, JSON.stringify(savedTableState));\n } catch (error) {\n console.warn('Failed to save table state', error);\n }\n }\n\n private loadStateFromStorage() {\n if (!this.storageOptions) {\n return;\n }\n\n const options = { ...DEFAULT_STORAGE_OPTIONS, ...this.storageOptions };\n const json = localStorage.getItem(options.key);\n if (!json) {\n return;\n }\n\n try {\n const savedTableState = JSON.parse(json) as RestorableTableState<T>;\n const tableStateToRestore: RestorableTableState<T> = {};\n\n if (options.saveColumnOrder) {\n tableStateToRestore.columnOrder = savedTableState.columnOrder;\n }\n\n if (savedTableState.columns) {\n tableStateToRestore.columns = [];\n for (const savedColumnState of savedTableState.columns) {\n const columnStateToRestore: RestorableColumnState<T> = {\n field: savedColumnState.field,\n };\n\n if (options.saveColumnVisibility) {\n columnStateToRestore.visible = savedColumnState.visible;\n }\n\n if (options.saveColumnWidths) {\n columnStateToRestore.width = savedColumnState.width;\n }\n\n if (options.saveColumnSortOrders) {\n columnStateToRestore.sortState = savedColumnState.sortState;\n }\n tableStateToRestore.columns.push(columnStateToRestore);\n }\n }\n\n this.restoreState(tableStateToRestore);\n this.hasRestoredState = true;\n } catch (error) {\n console.error('Failed to restore DataTable state:', error);\n }\n }\n\n // #endregion\n\n // #region --- Event Handlers ---\n\n private handleHeaderClicked = (\n event: MouseEvent,\n column: ColumnOptions<T>,\n ) => {\n const target = event.target as HTMLElement;\n if (!column.sortable || target.classList.contains('resizer')) {\n return;\n }\n\n const multiSort = event.shiftKey;\n const state = findColumn(column.field, this._columnStates);\n\n if (!state?.sortState) {\n this.sort(column.field, 'asc', !multiSort);\n } else if (state.sortState.order === 'asc') {\n this.sort(column.field, 'desc', !multiSort);\n } else if (state.sortState.order) {\n this.sort(column.field, null, !multiSort);\n }\n };\n\n private handleCellClick = (\n event: MouseEvent,\n row: T,\n field: NestedKeyOf<T>,\n ) => {\n // Ignore events if the user is highlighting text\n if (window.getSelection()?.toString()) return;\n\n const rowIndex = this.rowMetadata.get(row)!.index;\n this.dispatchEvent(new YatlRowClickEvent(row, rowIndex, field, event));\n };\n\n private handleResizeMouseDown(event: MouseEvent, field: NestedKeyOf<T>) {\n event.preventDefault();\n event.stopPropagation();\n\n const target = event.target as HTMLElement;\n const header = target.closest('.cell');\n if (!header) {\n return;\n }\n\n const columnIndex = this.columns.findIndex(col => col.field === field);\n if (columnIndex < 0) {\n return;\n }\n\n // Freeze the current widths as soon as the users starts resizing\n this.tableElement\n .querySelectorAll<HTMLElement>('.header .cell')\n .forEach(element => {\n const field = element.dataset.field;\n if (field) {\n const state = findColumn(field, this._columnStates);\n if (state) {\n state.width = element.getBoundingClientRect().width;\n }\n }\n });\n\n this.resizeState = {\n active: true,\n startX: event.pageX,\n startWidth: header.getBoundingClientRect().width,\n columnIndex: columnIndex,\n columnField: field,\n currentWidths: widthsToGridTemplates(this.columnWidths),\n };\n\n this.tableElement.style.setProperty(\n '--grid-template',\n this.resizeState.currentWidths.join(' '),\n );\n\n window.addEventListener('mousemove', this.handleResizeMouseMove);\n window.addEventListener('mouseup', this.handleResizeMouseUp);\n document.body.style.cursor = 'col-resize';\n }\n\n private handleResizeMouseMove = (event: MouseEvent) => {\n if (!this.resizeState?.active) return;\n\n requestAnimationFrame(() => {\n if (!this.resizeState?.active) return;\n\n const deltaX = event.pageX - this.resizeState.startX;\n const newWidth = Math.max(50, this.resizeState.startWidth + deltaX);\n this.resizeState.currentWidths[this.resizeState.columnIndex] =\n `${newWidth}px`;\n this.tableElement.style.setProperty(\n '--grid-template',\n this.resizeState.currentWidths.join(' '),\n );\n });\n };\n\n private handleResizeMouseUp = (_event: MouseEvent) => {\n window.removeEventListener('mousemove', this.handleResizeMouseMove);\n window.removeEventListener('mouseup', this.handleResizeMouseUp);\n document.body.style.cursor = '';\n\n if (this.resizeState?.active) {\n // Calculate the final width based on the DOM's current style\n const finalWidth = parseFloat(\n this.resizeState.currentWidths[this.resizeState.columnIndex],\n );\n const columnStates = this.columnStates;\n const state = findColumn(this.resizeState.columnField, columnStates)!;\n state.width = finalWidth;\n // We need to trigger a lifecycle update\n // to force any logic from updating the width.\n // Right now this is just the save state logic.\n this.columnStates = columnStates;\n\n this.dispatchEvent(new YatlColumnResizeEvent(state.field, state.width));\n }\n\n this.resizeState = null;\n };\n\n private handleDragColumnStart = (event: DragEvent, field: NestedKeyOf<T>) => {\n const target = event.target as HTMLElement;\n console.log('Starting drag event');\n console.log(target);\n\n if (target?.classList.contains('resizer')) {\n event.preventDefault();\n return;\n }\n\n if (event.dataTransfer) {\n event.dataTransfer.effectAllowed = 'move';\n event.dataTransfer.setData('text/plain', field);\n this.dragColumn = field;\n }\n };\n\n private handleDragColumnEnter = (event: DragEvent) => {\n const cell = event.currentTarget as HTMLElement;\n cell.querySelector('.drop-indicator')?.classList.add('active');\n };\n\n private handleDragColumnLeave = (event: DragEvent) => {\n const cell = event.currentTarget as HTMLElement;\n const enteringElement = event.relatedTarget as Node;\n\n if (cell.contains(enteringElement)) {\n return;\n }\n\n cell.querySelector('.drop-indicator')?.classList.remove('active');\n };\n\n private handleDragColumnOver = (event: DragEvent) => {\n event.preventDefault();\n if (event.dataTransfer) {\n event.dataTransfer.dropEffect = 'move';\n }\n };\n\n private handleDragColumnDrop = (event: DragEvent, field: NestedKeyOf<T>) => {\n if (!this.dragColumn || this.dragColumn === field) {\n return;\n }\n\n event.preventDefault();\n event.stopPropagation();\n\n const columns = [...this.columns];\n const dragIndex = columns.findIndex(col => col.field === this.dragColumn);\n const dropIndex = columns.findIndex(col => col.field === field);\n\n if (dragIndex > -1 && dropIndex > -1) {\n const [draggedColumn] = columns.splice(dragIndex, 1);\n const droppedColumn = findColumn(field, this.columns);\n if (!droppedColumn) return;\n\n columns.splice(dropIndex, 0, draggedColumn);\n const newColumnOrder = columns.map(col => col.field);\n const reorderEvent = new YatlColumnReorderEvent(\n draggedColumn.field,\n droppedColumn.field,\n newColumnOrder,\n );\n if (!this.dispatchEvent(reorderEvent)) {\n return;\n }\n\n this.setColumnOrder(newColumnOrder);\n }\n };\n\n private handleDragColumnEnd = () => {\n this.dragColumn = null;\n // Clean up just in case\n this.tableElement\n .querySelectorAll('.drop-indicator.active')\n .forEach(element => element.classList.remove('active'));\n };\n\n // #endregion\n\n // #region --- Event Target ---\n\n public override addEventListener<K extends keyof EventMap<T>>(\n type: K,\n listener: (this: EventMap<T>, ev: EventMap<T>[K]) => void,\n options?: boolean | AddEventListenerOptions,\n ): void;\n\n public override addEventListener(\n type: string,\n listener: EventListenerOrEventListenerObject,\n options?: boolean | AddEventListenerOptions,\n ): void;\n\n public override addEventListener(\n type: string,\n listener: unknown,\n options?: boolean | AddEventListenerOptions,\n ) {\n super.addEventListener(\n type,\n listener as EventListenerOrEventListenerObject,\n options,\n );\n }\n\n public override removeEventListener<K extends keyof EventMap<T>>(\n type: K,\n listener: EventListenerOrEventListenerObject,\n options?: boolean | EventListenerOptions,\n ): void;\n\n public override removeEventListener(\n type: string,\n listener: EventListenerOrEventListenerObject,\n options?: boolean | EventListenerOptions,\n ): void {\n super.removeEventListener(type, listener, options);\n }\n\n public override dispatchEvent<K extends keyof EventMap<T>>(\n event: EventMap<T>[K],\n ): boolean {\n return super.dispatchEvent(event);\n }\n\n // #endregion\n}\n\ninterface RowMetadata {\n index: number;\n searchScore?: number;\n /** Precomputed search tokens */\n searchTokens: Record<string, string[]>;\n /** Precomputed search values */\n searchValues: Record<string, string>;\n /** Precomputed sort values */\n sortValues: Record<string, Compareable>;\n highlightIndices?: Record<string, [number, number][]>;\n}\n\ninterface SearchResult {\n score: number;\n ranges: [number, number][]; // Array of [start, end] tuples\n}\n\n/**\n * Defines the mapping between event names and their detail object types.\n */\ninterface EventMap<T> {\n 'yatl-row-click': YatlRowClickEvent<T>;\n 'yatl-change': YatlChangeEvent<T>;\n 'yatl-sort': YatlSortEvent<T>;\n 'yatl-column-toggle': YatlColumnToggleEvent<T>;\n 'yatl-column-resize': YatlColumnResizeEvent<T>;\n 'yatl-column-reorder': YatlColumnReorderEvent<T>;\n 'yatl-search': YatlSearchEvent;\n}\n\nexport { createRegexTokenizer, findColumn, whitespaceTokenizer };\n","import { css } from 'lit';\n\nexport default css`\n /* Style declarations */\n :host {\n /* Typography */\n --yatl-font-family: var(\n --yatl-table-font,\n -apple-system,\n BlinkMacSystemFont,\n 'Segoe UI',\n Roboto,\n Helvetica,\n Arial,\n sans-serif,\n 'Apple Color Emoji',\n 'Segoe UI Emoji'\n );\n --yatl-font-size: var(--yatl-table-font-size, 0.875rem);\n --yatl-line-height: var(--yatl-table-line-height, 1.25rem);\n\n /* Spacing */\n --yatl-cell-padding: var(--yatl-table-cell-padding, 10px 16px);\n --yatl-header-padding: var(--yatl-table-header-padding, 12px 16px);\n\n /* Colors */\n --yatl-bg: var(--yatl-table-bg, #ffffff);\n --yatl-text: var(--yatl-table-text, #0f172a);\n --yatl-text-muted: var(--yatl-table-text-muted, #64748b);\n --yatl-border-color: var(--yatl-table-border-color, #e2e8f0);\n\n --yatl-header-bg: var(--yatl-table-header-bg, #f8fafc);\n --yatl-header-text: var(--yatl-table-header-text, #475569);\n\n --yatl-row-hover-bg: var(--yatl-table-row-hover-bg, #f1f5f9);\n --yatl-row-selected-bg: var(--yatl-table-row-selected-bg, #e0f2fe);\n\n /* Resize grab handle width */\n --yatl-resizer-width: 10px;\n /* z-index for the header */\n --header-z-index: 2;\n /* Drop target background color */\n --header-drop-color: rgba(255, 255, 255, 0.1);\n\n font-family: var(--yatl-font-family);\n font-size: var(--yatl-font-size);\n color: var(--yatl-text);\n }\n\n :host(.dark) {\n --yatl-table-bg: #1e293b;\n --yatl-table-text: #f1f5f9;\n --yatl-table-text-muted: #94a3b8;\n --yatl-table-border-color: #334155;\n\n --yatl-table-header-bg: #0f172a;\n --yatl-table-header-text: #cbd5e1;\n\n --yatl-table-row-hover-bg: #334155;\n --yatl-table-row-selected-bg: #1e3a8a;\n }\n\n @media (prefers-color-scheme: dark) {\n :host {\n --yatl-bg: var(--yatl-table-bg, #1e293b);\n --yatl-text: var(--yatl-table-text, #f1f5f9);\n --yatl-text-muted: var(--yatl-table-text-muted, #94a3b8);\n --yatl-border-color: var(--yatl-table-border-color, #334155);\n\n --yatl-header-bg: var(--yatl-table-header-bg, #0f172a);\n --yatl-header-text: var(--yatl-table-header-text, #cbd5e1);\n\n --yatl-row-hover-bg: var(--yatl-table-row-hover-bg, #334155);\n --yatl-row-selected-bg: var(--yatl-table-row-selected-bg, #1e3a8a);\n }\n }\n\n :host {\n font-family: system-ui, sans-serif;\n }\n\n .table {\n background-color: var(--yatl-bg);\n border: 1px solid var(--yatl-border-color);\n border-radius: 6px;\n }\n\n .header.row {\n background-color: var(--yatl-header-bg);\n border-bottom: 1px solid var(--yatl-border-color);\n font-weight: 600;\n color: var(--yatl-header-text);\n }\n\n .row {\n background-color: var(--yatl-bg);\n border-bottom: 1px solid var(--yatl-border-color);\n transition: background-color 50ms;\n position: relative;\n }\n\n .row:last-child {\n border-bottom: none;\n }\n\n .header .cell::after,\n .row:not(.header)::after {\n content: '';\n position: absolute;\n inset: 0;\n pointer-events: none;\n background-color: transparent;\n transition: background-color 50ms;\n z-index: 1;\n }\n\n .header .cell:hover::after,\n .row:not(.header):hover::after {\n background-color: rgba(0, 0, 0, 0.2);\n }\n\n .cell {\n align-items: center;\n padding: var(--yatl-cell-padding);\n }\n\n .header .cell {\n padding: var(--yatl-header-padding);\n }\n\n .footer {\n padding: 8px 12px;\n background-color: var(--yatl-header-bg);\n border-top: 1px solid var(--yatl-border-color);\n color: var(--yatl-text-muted);\n font-size: 0.8em;\n }\n\n .resizer::after {\n height: 60%;\n width: 1px;\n background-color: color-mix(in srgb, currentColor 30%, transparent);\n transition: background-color 0.2s;\n }\n\n .resizer:hover::after {\n background-color: currentColor;\n width: 2px;\n }\n\n .drop-indicator {\n background: rgba(0, 0, 0, 0.4);\n }\n\n .message {\n font-size: large;\n }\n\n /* Layout stuff\n * Most of this is functional and needed\n * for the table to work properly. \n * Modify with caution!\n */\n :host {\n display: block;\n height: 100%;\n width: 100%;\n }\n\n .table {\n display: flex;\n flex-direction: column;\n height: 100%;\n width: 100%;\n min-height: 0;\n overflow: auto;\n box-sizing: border-box;\n }\n\n .header {\n z-index: var(--header-z-index);\n flex-shrink: 0;\n position: sticky;\n top: 0;\n }\n\n .header-content {\n position: relative;\n width: 100%;\n display: flex;\n flex-direction: row;\n align-items: baseline;\n gap: 0.5rem;\n }\n\n .sort-icon {\n position: relative;\n width: 1ch;\n align-self: stretch;\n padding: 0;\n overflow: hidden;\n flex-shrink: 0;\n }\n\n .sort-icon::after {\n content: '';\n position: absolute;\n }\n\n .sort-icon.descending::after {\n content: '\\\\2191';\n }\n\n .sort-icon.ascending::after {\n content: '\\\\2193';\n }\n\n .resizer {\n position: absolute;\n top: 0;\n bottom: 0;\n right: 0;\n width: var(--yatl-resizer-width);\n cursor: col-resize;\n display: flex;\n justify-content: center;\n align-items: center;\n }\n\n .resizer::after {\n content: '';\n display: block;\n }\n\n .drop-indicator {\n display: none;\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n pointer-events: none;\n z-index: calc(var(--header-z-index) + 1);\n }\n\n .drop-indicator.active {\n display: block;\n }\n\n .sortable {\n cursor: pointer;\n }\n\n /* Footer */\n .footer {\n display: flex;\n align-items: center;\n justify-content: space-between;\n flex-shrink: 0;\n\n position: sticky;\n bottom: 0;\n z-index: var(--header-z-index);\n }\n\n /* Generic table parts */\n .row {\n display: grid;\n grid-template-columns: var(--grid-template);\n min-width: 100%;\n width: fit-content;\n }\n\n .cell {\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n position: relative;\n display: flex;\n align-items: center;\n }\n\n .message {\n width: 100%;\n height: 100%;\n text-align: center;\n pointer-events: none;\n display: flex;\n align-items: center;\n justify-content: center;\n }\n\n .truncate {\n display: block;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n`;\n"],"mappings":"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","names":["query","import_lit","import_lit","state","query","priority","field"]}