@tanstack/table-core 9.0.0-beta.5 → 9.0.0-beta.7
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.
- package/dist/features/row-sorting/rowSortingFeature.utils.cjs +8 -5
- package/dist/features/row-sorting/rowSortingFeature.utils.cjs.map +1 -1
- package/dist/features/row-sorting/rowSortingFeature.utils.js +8 -5
- package/dist/features/row-sorting/rowSortingFeature.utils.js.map +1 -1
- package/dist/fns/sortFns.cjs +18 -6
- package/dist/fns/sortFns.cjs.map +1 -1
- package/dist/fns/sortFns.js +18 -6
- package/dist/fns/sortFns.js.map +1 -1
- package/package.json +1 -1
- package/src/features/row-sorting/rowSortingFeature.utils.ts +8 -6
- package/src/fns/sortFns.ts +33 -10
|
@@ -60,19 +60,22 @@ function table_resetSorting(table, defaultState) {
|
|
|
60
60
|
*/
|
|
61
61
|
function column_getAutoSortFn(column) {
|
|
62
62
|
const sortFns = column.table._rowModelFns.sortFns;
|
|
63
|
-
let sortFn;
|
|
64
63
|
const firstRows = column.table.getFilteredRowModel().flatRows.slice(0, 10);
|
|
65
64
|
let isString = false;
|
|
66
65
|
for (let i = 0; i < firstRows.length; i++) {
|
|
67
66
|
const value = firstRows[i].getValue(column.id);
|
|
68
|
-
if (Object.prototype.toString.call(value) === "[object Date]")
|
|
67
|
+
if (Object.prototype.toString.call(value) === "[object Date]") {
|
|
68
|
+
if (sortFns === null || sortFns === void 0 ? void 0 : sortFns.datetime) return sortFns.datetime;
|
|
69
|
+
}
|
|
69
70
|
if (typeof value === "string") {
|
|
70
71
|
isString = true;
|
|
71
|
-
if (value.split(require_sortFns.reSplitAlphaNumeric).length > 1)
|
|
72
|
+
if (value.split(require_sortFns.reSplitAlphaNumeric).length > 1) {
|
|
73
|
+
if (sortFns === null || sortFns === void 0 ? void 0 : sortFns.alphanumeric) return sortFns.alphanumeric;
|
|
74
|
+
}
|
|
72
75
|
}
|
|
73
76
|
}
|
|
74
|
-
if (isString)
|
|
75
|
-
return
|
|
77
|
+
if (isString) return (sortFns === null || sortFns === void 0 ? void 0 : sortFns.text) ?? require_sortFns.sortFn_basic;
|
|
78
|
+
return require_sortFns.sortFn_basic;
|
|
76
79
|
}
|
|
77
80
|
/**
|
|
78
81
|
* Chooses the default first sort direction from the first filtered row value.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rowSortingFeature.utils.cjs","names":["cloneState","reSplitAlphaNumeric","sortFn_basic","isFunction"],"sources":["../../../src/features/row-sorting/rowSortingFeature.utils.ts"],"sourcesContent":["import { reSplitAlphaNumeric, sortFn_basic } from '../../fns/sortFns'\nimport { cloneState, isFunction } from '../../utils'\nimport type { CellData, RowData, Updater } from '../../types/type-utils'\nimport type { TableFeatures } from '../../types/TableFeatures'\nimport type { Table_Internal } from '../../types/Table'\nimport type { Column_Internal } from '../../types/Column'\nimport type {\n SortDirection,\n SortFn,\n SortingState,\n} from './rowSortingFeature.types'\n\n// State Utils\n\n/**\n * Creates the default sorting state.\n *\n * The feature default is an empty array, meaning no columns are sorted. Reset\n * APIs use this value when `defaultState` is `true`.\n *\n * @example\n * ```ts\n * const sorting = getDefaultSortingState()\n * ```\n */\nexport function getDefaultSortingState(): SortingState {\n return []\n}\n\n/**\n * Routes a sorting updater through the table's sorting change handler.\n *\n * The updater may be a next `SortingState` array or a function of the previous\n * sorting state, matching the instance `table.setSorting` behavior.\n *\n * @example\n * ```ts\n * table_setSorting(table, (old) => [...old, { id: 'age', desc: true }])\n * ```\n */\nexport function table_setSorting<\n TFeatures extends TableFeatures,\n TData extends RowData,\n>(table: Table_Internal<TFeatures, TData>, updater: Updater<SortingState>) {\n table.options.onSortingChange?.(updater)\n}\n\n/**\n * Resets `sorting` to the configured initial state or feature default.\n *\n * With no argument, the reset clones `table.initialState.sorting` when it\n * exists. Passing `true` ignores initial state and resets to `[]`.\n *\n * @example\n * ```ts\n * table_resetSorting(table)\n * table_resetSorting(table, true)\n * ```\n */\nexport function table_resetSorting<\n TFeatures extends TableFeatures,\n TData extends RowData,\n>(table: Table_Internal<TFeatures, TData>, defaultState?: boolean) {\n table_setSorting(\n table,\n defaultState ? [] : cloneState(table.initialState.sorting ?? []),\n )\n}\n\n// Column Utils\n\n/**\n * Chooses a built-in sorting function from sampled filtered row values.\n *\n * Date-like values use `datetime`, mixed text/numeric strings use\n * `alphanumeric`, plain strings use `text`, and unknown values fall back to\n * `basic`.\n *\n * @example\n * ```ts\n * const sortFn = column_getAutoSortFn(column)\n * ```\n */\nexport function column_getAutoSortFn<\n TFeatures extends TableFeatures,\n TData extends RowData,\n TValue extends CellData = CellData,\n>(column: Column_Internal<TFeatures, TData, TValue>): SortFn<TFeatures, TData> {\n const sortFns: Record<string, SortFn<TFeatures, TData>> | undefined =\n column.table._rowModelFns.sortFns\n\n let sortFn: SortFn<TFeatures, TData> | undefined\n\n const firstRows = column.table.getFilteredRowModel().flatRows.slice(0, 10)\n\n let isString = false\n\n for (let i = 0; i < firstRows.length; i++) {\n const value = firstRows[i]!.getValue(column.id)\n\n if (Object.prototype.toString.call(value) === '[object Date]') {\n sortFn = sortFns?.datetime\n }\n\n if (typeof value === 'string') {\n isString = true\n\n if (value.split(reSplitAlphaNumeric).length > 1) {\n sortFn = sortFns?.alphanumeric\n }\n }\n }\n\n if (isString) {\n sortFn = sortFns?.text\n }\n\n return sortFn ?? sortFn_basic\n}\n\n/**\n * Chooses the default first sort direction from the first filtered row value.\n *\n * String columns start ascending so alphabetical order is natural; other value\n * types start descending.\n *\n * @example\n * ```ts\n * const direction = column_getAutoSortDir(column)\n * ```\n */\nexport function column_getAutoSortDir<\n TFeatures extends TableFeatures,\n TData extends RowData,\n TValue extends CellData = CellData,\n>(column: Column_Internal<TFeatures, TData, TValue>) {\n const firstRow = column.table.getFilteredRowModel().flatRows[0]\n\n const value = firstRow ? firstRow.getValue(column.id) : undefined\n\n if (typeof value === 'string') {\n return 'asc'\n }\n\n return 'desc'\n}\n\n/**\n * Resolves the sorting function configured for a column.\n *\n * Function-valued `columnDef.sortFn` is returned directly, `'auto'` delegates\n * to `column_getAutoSortFn`, and string values are looked up in the table's\n * sorting function registry before falling back to `basic`.\n *\n * @example\n * ```ts\n * const sortFn = column_getSortFn(column)\n * ```\n */\nexport function column_getSortFn<\n TFeatures extends TableFeatures,\n TData extends RowData,\n TValue extends CellData = CellData,\n>(column: Column_Internal<TFeatures, TData, TValue>): SortFn<TFeatures, TData> {\n const sortFns: Record<string, SortFn<TFeatures, TData>> | undefined =\n column.table._rowModelFns.sortFns\n\n return isFunction(column.columnDef.sortFn)\n ? column.columnDef.sortFn\n : column.columnDef.sortFn === 'auto'\n ? column_getAutoSortFn(column)\n : (sortFns?.[column.columnDef.sortFn as string] ?? sortFn_basic)\n}\n\n/**\n * Applies the next sorting state for this column.\n *\n * The toggle can add, replace, flip, or remove this column's sort entry. Multi\n * sorting respects `enableMultiSort`, `maxMultiSortColCount`, and the `multi`\n * argument.\n *\n * @example\n * ```ts\n * column_toggleSorting(column, undefined, true)\n * ```\n */\nexport function column_toggleSorting<\n TFeatures extends TableFeatures,\n TData extends RowData,\n TValue extends CellData = CellData,\n>(\n column: Column_Internal<TFeatures, TData, TValue>,\n desc?: boolean,\n multi?: boolean,\n) {\n // if (column.columns.length) {\n // column.columns.forEach((c, i) => {\n // if (c.id) {\n // table.toggleColumnSorting(c.id, undefined, multi || !!i)\n // }\n // })\n // return\n // }\n\n // this needs to be outside of table.setSorting to be in sync with rerender\n const nextSortingOrder = column_getNextSortingOrder(column)\n const hasManualValue = typeof desc !== 'undefined'\n\n table_setSorting(column.table, (old) => {\n // Find any existing sorting for this column\n const existingSorting = old.find((d) => d.id === column.id)\n const existingIndex = old.findIndex((d) => d.id === column.id)\n\n let newSorting: SortingState = []\n\n // What should we do with this sort action?\n let sortAction: 'add' | 'remove' | 'toggle' | 'replace'\n const nextDesc = hasManualValue ? desc : nextSortingOrder === 'desc'\n\n // Multi-mode\n if (old.length && column_getCanMultiSort(column) && multi) {\n if (existingSorting) {\n sortAction = 'toggle'\n } else {\n sortAction = 'add'\n }\n } else {\n // Normal mode\n if (old.length && existingIndex !== old.length - 1) {\n sortAction = 'replace'\n } else if (existingSorting) {\n sortAction = 'toggle'\n } else {\n sortAction = 'replace'\n }\n }\n\n // Handle toggle states that will remove the sorting\n if (sortAction === 'toggle') {\n // If we are \"actually\" toggling (not a manual set value), should we remove the sorting?\n if (!hasManualValue) {\n // Is our intention to remove?\n if (!nextSortingOrder) {\n sortAction = 'remove'\n }\n }\n }\n\n if (sortAction === 'add') {\n newSorting = [\n ...old,\n {\n id: column.id,\n desc: nextDesc,\n },\n ]\n // Take latest n columns\n newSorting.splice(\n 0,\n newSorting.length -\n (column.table.options.maxMultiSortColCount ??\n Number.MAX_SAFE_INTEGER),\n )\n } else if (sortAction === 'toggle') {\n // This flips (or sets) the\n newSorting = old.map((d) => {\n if (d.id === column.id) {\n return {\n ...d,\n desc: nextDesc,\n }\n }\n return d\n })\n } else if (sortAction === 'remove') {\n newSorting = old.filter((d) => d.id !== column.id)\n } else {\n newSorting = [\n {\n id: column.id,\n desc: nextDesc,\n },\n ]\n }\n\n return newSorting\n })\n}\n\n/**\n * Resolves the first direction used when this column begins sorting.\n *\n * Column-level `sortDescFirst` wins, then table-level `sortDescFirst`, then the\n * auto direction inferred from sampled values.\n *\n * @example\n * ```ts\n * const firstDirection = column_getFirstSortDir(column)\n * ```\n */\nexport function column_getFirstSortDir<\n TFeatures extends TableFeatures,\n TData extends RowData,\n TValue extends CellData = CellData,\n>(column: Column_Internal<TFeatures, TData, TValue>) {\n const sortDescFirst =\n column.columnDef.sortDescFirst ??\n column.table.options.sortDescFirst ??\n column_getAutoSortDir(column) === 'desc'\n return sortDescFirst ? 'desc' : 'asc'\n}\n\n/**\n * Resolves the next sort order for this column's toggle cycle.\n *\n * The cycle starts with the first sort direction, flips between `asc` and\n * `desc`, and can return `false` when sorting removal is enabled.\n *\n * @example\n * ```ts\n * const nextOrder = column_getNextSortingOrder(column)\n * ```\n */\nexport function column_getNextSortingOrder<\n TFeatures extends TableFeatures,\n TData extends RowData,\n TValue extends CellData = CellData,\n>(column: Column_Internal<TFeatures, TData, TValue>, multi?: boolean) {\n const firstSortDirection = column_getFirstSortDir(column)\n const isSorted = column_getIsSorted(column)\n\n if (!isSorted) {\n return firstSortDirection\n }\n\n if (\n isSorted !== firstSortDirection &&\n (column.table.options.enableSortingRemoval ?? true) && // If enableSortRemove, enable in general\n (multi ? (column.table.options.enableMultiRemove ?? true) : true) // If multi, don't allow if enableMultiRemove))\n ) {\n return false\n }\n return isSorted === 'desc' ? 'asc' : 'desc'\n}\n\n/**\n * Checks whether this accessor column can participate in sorting.\n *\n * The column must have an accessor and sorting must be enabled by both the\n * column definition and table options.\n *\n * @example\n * ```ts\n * const canSort = column_getCanSort(column)\n * ```\n */\nexport function column_getCanSort<\n TFeatures extends TableFeatures,\n TData extends RowData,\n TValue extends CellData = CellData,\n>(column: Column_Internal<TFeatures, TData, TValue>) {\n return (\n (column.columnDef.enableSorting ?? true) &&\n (column.table.options.enableSorting ?? true) &&\n !!column.accessorFn\n )\n}\n\n/**\n * Checks whether this column can be added to a multi-sort state.\n *\n * Column-level `enableMultiSort` wins over table-level `enableMultiSort`; if\n * neither is set, accessor columns can multi-sort by default.\n *\n * @example\n * ```ts\n * const canMultiSort = column_getCanMultiSort(column)\n * ```\n */\nexport function column_getCanMultiSort<\n TFeatures extends TableFeatures,\n TData extends RowData,\n TValue extends CellData = CellData,\n>(column: Column_Internal<TFeatures, TData, TValue>): boolean {\n return (\n column.columnDef.enableMultiSort ??\n column.table.options.enableMultiSort ??\n !!column.accessorFn\n )\n}\n\n/**\n * Reads this column's current sort direction.\n *\n * The result is `false` when the column is not sorted, otherwise `'asc'` or\n * `'desc'` based on the column's entry in `state.sorting`.\n *\n * @example\n * ```ts\n * const direction = column_getIsSorted(column)\n * ```\n */\nexport function column_getIsSorted<\n TFeatures extends TableFeatures,\n TData extends RowData,\n TValue extends CellData = CellData,\n>(column: Column_Internal<TFeatures, TData, TValue>): false | SortDirection {\n const columnSort = column.table.atoms.sorting\n ?.get()\n ?.find((d) => d.id === column.id)\n return !columnSort ? false : columnSort.desc ? 'desc' : 'asc'\n}\n\n/**\n * Finds this column's position in the ordered `state.sorting` array.\n *\n * The result is `-1` when the column is not sorted.\n *\n * @example\n * ```ts\n * const index = column_getSortIndex(column)\n * ```\n */\nexport function column_getSortIndex<\n TFeatures extends TableFeatures,\n TData extends RowData,\n TValue extends CellData = CellData,\n>(column: Column_Internal<TFeatures, TData, TValue>): number {\n return (\n column.table.atoms.sorting?.get()?.findIndex((d) => d.id === column.id) ??\n -1\n )\n}\n\n/**\n * Removes this column from the sorting state.\n *\n * Other sorted columns are preserved, including their relative order.\n *\n * @example\n * ```ts\n * column_clearSorting(column)\n * ```\n */\nexport function column_clearSorting<\n TFeatures extends TableFeatures,\n TData extends RowData,\n TValue extends CellData = CellData,\n>(column: Column_Internal<TFeatures, TData, TValue>) {\n // clear sorting for just 1 column\n table_setSorting(column.table, (old) =>\n old.length ? old.filter((d) => d.id !== column.id) : [],\n )\n}\n\n/**\n * Creates a header event handler that toggles this column's sorting.\n *\n * The handler ignores events when the column cannot sort, persists React-style\n * synthetic events when present, and asks `options.isMultiSortEvent` whether\n * the event should add to a multi-sort.\n *\n * @example\n * ```ts\n * const onClick = column_getToggleSortingHandler(column)\n * ```\n */\nexport function column_getToggleSortingHandler<\n TFeatures extends TableFeatures,\n TData extends RowData,\n TValue extends CellData = CellData,\n>(column: Column_Internal<TFeatures, TData, TValue>) {\n const canSort = column_getCanSort(column)\n\n return (e: unknown) => {\n if (!canSort) return\n ;(e as any).persist?.()\n column_toggleSorting(\n column,\n\n undefined,\n column_getCanMultiSort(column)\n ? column.table.options.isMultiSortEvent?.(e)\n : false,\n )\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"rowSortingFeature.utils.cjs","names":["cloneState","reSplitAlphaNumeric","sortFn_basic","isFunction"],"sources":["../../../src/features/row-sorting/rowSortingFeature.utils.ts"],"sourcesContent":["import { reSplitAlphaNumeric, sortFn_basic } from '../../fns/sortFns'\nimport { cloneState, isFunction } from '../../utils'\nimport type { CellData, RowData, Updater } from '../../types/type-utils'\nimport type { TableFeatures } from '../../types/TableFeatures'\nimport type { Table_Internal } from '../../types/Table'\nimport type { Column_Internal } from '../../types/Column'\nimport type {\n SortDirection,\n SortFn,\n SortingState,\n} from './rowSortingFeature.types'\n\n// State Utils\n\n/**\n * Creates the default sorting state.\n *\n * The feature default is an empty array, meaning no columns are sorted. Reset\n * APIs use this value when `defaultState` is `true`.\n *\n * @example\n * ```ts\n * const sorting = getDefaultSortingState()\n * ```\n */\nexport function getDefaultSortingState(): SortingState {\n return []\n}\n\n/**\n * Routes a sorting updater through the table's sorting change handler.\n *\n * The updater may be a next `SortingState` array or a function of the previous\n * sorting state, matching the instance `table.setSorting` behavior.\n *\n * @example\n * ```ts\n * table_setSorting(table, (old) => [...old, { id: 'age', desc: true }])\n * ```\n */\nexport function table_setSorting<\n TFeatures extends TableFeatures,\n TData extends RowData,\n>(table: Table_Internal<TFeatures, TData>, updater: Updater<SortingState>) {\n table.options.onSortingChange?.(updater)\n}\n\n/**\n * Resets `sorting` to the configured initial state or feature default.\n *\n * With no argument, the reset clones `table.initialState.sorting` when it\n * exists. Passing `true` ignores initial state and resets to `[]`.\n *\n * @example\n * ```ts\n * table_resetSorting(table)\n * table_resetSorting(table, true)\n * ```\n */\nexport function table_resetSorting<\n TFeatures extends TableFeatures,\n TData extends RowData,\n>(table: Table_Internal<TFeatures, TData>, defaultState?: boolean) {\n table_setSorting(\n table,\n defaultState ? [] : cloneState(table.initialState.sorting ?? []),\n )\n}\n\n// Column Utils\n\n/**\n * Chooses a built-in sorting function from sampled filtered row values.\n *\n * Date-like values use `datetime`, mixed text/numeric strings use\n * `alphanumeric`, plain strings use `text`, and unknown values fall back to\n * `basic`.\n *\n * @example\n * ```ts\n * const sortFn = column_getAutoSortFn(column)\n * ```\n */\nexport function column_getAutoSortFn<\n TFeatures extends TableFeatures,\n TData extends RowData,\n TValue extends CellData = CellData,\n>(column: Column_Internal<TFeatures, TData, TValue>): SortFn<TFeatures, TData> {\n const sortFns: Record<string, SortFn<TFeatures, TData>> | undefined =\n column.table._rowModelFns.sortFns\n\n const firstRows = column.table.getFilteredRowModel().flatRows.slice(0, 10)\n\n let isString = false\n\n for (let i = 0; i < firstRows.length; i++) {\n const value = firstRows[i]!.getValue(column.id)\n\n if (Object.prototype.toString.call(value) === '[object Date]') {\n if (sortFns?.datetime) {\n return sortFns.datetime\n }\n }\n\n if (typeof value === 'string') {\n isString = true\n\n if (value.split(reSplitAlphaNumeric).length > 1) {\n if (sortFns?.alphanumeric) {\n return sortFns.alphanumeric\n }\n }\n }\n }\n\n if (isString) {\n return sortFns?.text ?? sortFn_basic\n }\n\n return sortFn_basic\n}\n\n/**\n * Chooses the default first sort direction from the first filtered row value.\n *\n * String columns start ascending so alphabetical order is natural; other value\n * types start descending.\n *\n * @example\n * ```ts\n * const direction = column_getAutoSortDir(column)\n * ```\n */\nexport function column_getAutoSortDir<\n TFeatures extends TableFeatures,\n TData extends RowData,\n TValue extends CellData = CellData,\n>(column: Column_Internal<TFeatures, TData, TValue>) {\n const firstRow = column.table.getFilteredRowModel().flatRows[0]\n\n const value = firstRow ? firstRow.getValue(column.id) : undefined\n\n if (typeof value === 'string') {\n return 'asc'\n }\n\n return 'desc'\n}\n\n/**\n * Resolves the sorting function configured for a column.\n *\n * Function-valued `columnDef.sortFn` is returned directly, `'auto'` delegates\n * to `column_getAutoSortFn`, and string values are looked up in the table's\n * sorting function registry before falling back to `basic`.\n *\n * @example\n * ```ts\n * const sortFn = column_getSortFn(column)\n * ```\n */\nexport function column_getSortFn<\n TFeatures extends TableFeatures,\n TData extends RowData,\n TValue extends CellData = CellData,\n>(column: Column_Internal<TFeatures, TData, TValue>): SortFn<TFeatures, TData> {\n const sortFns: Record<string, SortFn<TFeatures, TData>> | undefined =\n column.table._rowModelFns.sortFns\n\n return isFunction(column.columnDef.sortFn)\n ? column.columnDef.sortFn\n : column.columnDef.sortFn === 'auto'\n ? column_getAutoSortFn(column)\n : (sortFns?.[column.columnDef.sortFn as string] ?? sortFn_basic)\n}\n\n/**\n * Applies the next sorting state for this column.\n *\n * The toggle can add, replace, flip, or remove this column's sort entry. Multi\n * sorting respects `enableMultiSort`, `maxMultiSortColCount`, and the `multi`\n * argument.\n *\n * @example\n * ```ts\n * column_toggleSorting(column, undefined, true)\n * ```\n */\nexport function column_toggleSorting<\n TFeatures extends TableFeatures,\n TData extends RowData,\n TValue extends CellData = CellData,\n>(\n column: Column_Internal<TFeatures, TData, TValue>,\n desc?: boolean,\n multi?: boolean,\n) {\n // if (column.columns.length) {\n // column.columns.forEach((c, i) => {\n // if (c.id) {\n // table.toggleColumnSorting(c.id, undefined, multi || !!i)\n // }\n // })\n // return\n // }\n\n // this needs to be outside of table.setSorting to be in sync with rerender\n const nextSortingOrder = column_getNextSortingOrder(column)\n const hasManualValue = typeof desc !== 'undefined'\n\n table_setSorting(column.table, (old) => {\n // Find any existing sorting for this column\n const existingSorting = old.find((d) => d.id === column.id)\n const existingIndex = old.findIndex((d) => d.id === column.id)\n\n let newSorting: SortingState = []\n\n // What should we do with this sort action?\n let sortAction: 'add' | 'remove' | 'toggle' | 'replace'\n const nextDesc = hasManualValue ? desc : nextSortingOrder === 'desc'\n\n // Multi-mode\n if (old.length && column_getCanMultiSort(column) && multi) {\n if (existingSorting) {\n sortAction = 'toggle'\n } else {\n sortAction = 'add'\n }\n } else {\n // Normal mode\n if (old.length && existingIndex !== old.length - 1) {\n sortAction = 'replace'\n } else if (existingSorting) {\n sortAction = 'toggle'\n } else {\n sortAction = 'replace'\n }\n }\n\n // Handle toggle states that will remove the sorting\n if (sortAction === 'toggle') {\n // If we are \"actually\" toggling (not a manual set value), should we remove the sorting?\n if (!hasManualValue) {\n // Is our intention to remove?\n if (!nextSortingOrder) {\n sortAction = 'remove'\n }\n }\n }\n\n if (sortAction === 'add') {\n newSorting = [\n ...old,\n {\n id: column.id,\n desc: nextDesc,\n },\n ]\n // Take latest n columns\n newSorting.splice(\n 0,\n newSorting.length -\n (column.table.options.maxMultiSortColCount ??\n Number.MAX_SAFE_INTEGER),\n )\n } else if (sortAction === 'toggle') {\n // This flips (or sets) the\n newSorting = old.map((d) => {\n if (d.id === column.id) {\n return {\n ...d,\n desc: nextDesc,\n }\n }\n return d\n })\n } else if (sortAction === 'remove') {\n newSorting = old.filter((d) => d.id !== column.id)\n } else {\n newSorting = [\n {\n id: column.id,\n desc: nextDesc,\n },\n ]\n }\n\n return newSorting\n })\n}\n\n/**\n * Resolves the first direction used when this column begins sorting.\n *\n * Column-level `sortDescFirst` wins, then table-level `sortDescFirst`, then the\n * auto direction inferred from sampled values.\n *\n * @example\n * ```ts\n * const firstDirection = column_getFirstSortDir(column)\n * ```\n */\nexport function column_getFirstSortDir<\n TFeatures extends TableFeatures,\n TData extends RowData,\n TValue extends CellData = CellData,\n>(column: Column_Internal<TFeatures, TData, TValue>) {\n const sortDescFirst =\n column.columnDef.sortDescFirst ??\n column.table.options.sortDescFirst ??\n column_getAutoSortDir(column) === 'desc'\n return sortDescFirst ? 'desc' : 'asc'\n}\n\n/**\n * Resolves the next sort order for this column's toggle cycle.\n *\n * The cycle starts with the first sort direction, flips between `asc` and\n * `desc`, and can return `false` when sorting removal is enabled.\n *\n * @example\n * ```ts\n * const nextOrder = column_getNextSortingOrder(column)\n * ```\n */\nexport function column_getNextSortingOrder<\n TFeatures extends TableFeatures,\n TData extends RowData,\n TValue extends CellData = CellData,\n>(column: Column_Internal<TFeatures, TData, TValue>, multi?: boolean) {\n const firstSortDirection = column_getFirstSortDir(column)\n const isSorted = column_getIsSorted(column)\n\n if (!isSorted) {\n return firstSortDirection\n }\n\n if (\n isSorted !== firstSortDirection &&\n (column.table.options.enableSortingRemoval ?? true) && // If enableSortRemove, enable in general\n (multi ? (column.table.options.enableMultiRemove ?? true) : true) // If multi, don't allow if enableMultiRemove))\n ) {\n return false\n }\n return isSorted === 'desc' ? 'asc' : 'desc'\n}\n\n/**\n * Checks whether this accessor column can participate in sorting.\n *\n * The column must have an accessor and sorting must be enabled by both the\n * column definition and table options.\n *\n * @example\n * ```ts\n * const canSort = column_getCanSort(column)\n * ```\n */\nexport function column_getCanSort<\n TFeatures extends TableFeatures,\n TData extends RowData,\n TValue extends CellData = CellData,\n>(column: Column_Internal<TFeatures, TData, TValue>) {\n return (\n (column.columnDef.enableSorting ?? true) &&\n (column.table.options.enableSorting ?? true) &&\n !!column.accessorFn\n )\n}\n\n/**\n * Checks whether this column can be added to a multi-sort state.\n *\n * Column-level `enableMultiSort` wins over table-level `enableMultiSort`; if\n * neither is set, accessor columns can multi-sort by default.\n *\n * @example\n * ```ts\n * const canMultiSort = column_getCanMultiSort(column)\n * ```\n */\nexport function column_getCanMultiSort<\n TFeatures extends TableFeatures,\n TData extends RowData,\n TValue extends CellData = CellData,\n>(column: Column_Internal<TFeatures, TData, TValue>): boolean {\n return (\n column.columnDef.enableMultiSort ??\n column.table.options.enableMultiSort ??\n !!column.accessorFn\n )\n}\n\n/**\n * Reads this column's current sort direction.\n *\n * The result is `false` when the column is not sorted, otherwise `'asc'` or\n * `'desc'` based on the column's entry in `state.sorting`.\n *\n * @example\n * ```ts\n * const direction = column_getIsSorted(column)\n * ```\n */\nexport function column_getIsSorted<\n TFeatures extends TableFeatures,\n TData extends RowData,\n TValue extends CellData = CellData,\n>(column: Column_Internal<TFeatures, TData, TValue>): false | SortDirection {\n const columnSort = column.table.atoms.sorting\n ?.get()\n ?.find((d) => d.id === column.id)\n return !columnSort ? false : columnSort.desc ? 'desc' : 'asc'\n}\n\n/**\n * Finds this column's position in the ordered `state.sorting` array.\n *\n * The result is `-1` when the column is not sorted.\n *\n * @example\n * ```ts\n * const index = column_getSortIndex(column)\n * ```\n */\nexport function column_getSortIndex<\n TFeatures extends TableFeatures,\n TData extends RowData,\n TValue extends CellData = CellData,\n>(column: Column_Internal<TFeatures, TData, TValue>): number {\n return (\n column.table.atoms.sorting?.get()?.findIndex((d) => d.id === column.id) ??\n -1\n )\n}\n\n/**\n * Removes this column from the sorting state.\n *\n * Other sorted columns are preserved, including their relative order.\n *\n * @example\n * ```ts\n * column_clearSorting(column)\n * ```\n */\nexport function column_clearSorting<\n TFeatures extends TableFeatures,\n TData extends RowData,\n TValue extends CellData = CellData,\n>(column: Column_Internal<TFeatures, TData, TValue>) {\n // clear sorting for just 1 column\n table_setSorting(column.table, (old) =>\n old.length ? old.filter((d) => d.id !== column.id) : [],\n )\n}\n\n/**\n * Creates a header event handler that toggles this column's sorting.\n *\n * The handler ignores events when the column cannot sort, persists React-style\n * synthetic events when present, and asks `options.isMultiSortEvent` whether\n * the event should add to a multi-sort.\n *\n * @example\n * ```ts\n * const onClick = column_getToggleSortingHandler(column)\n * ```\n */\nexport function column_getToggleSortingHandler<\n TFeatures extends TableFeatures,\n TData extends RowData,\n TValue extends CellData = CellData,\n>(column: Column_Internal<TFeatures, TData, TValue>) {\n const canSort = column_getCanSort(column)\n\n return (e: unknown) => {\n if (!canSort) return\n ;(e as any).persist?.()\n column_toggleSorting(\n column,\n\n undefined,\n column_getCanMultiSort(column)\n ? column.table.options.isMultiSortEvent?.(e)\n : false,\n )\n }\n}\n"],"mappings":"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"}
|
|
@@ -60,19 +60,22 @@ function table_resetSorting(table, defaultState) {
|
|
|
60
60
|
*/
|
|
61
61
|
function column_getAutoSortFn(column) {
|
|
62
62
|
const sortFns = column.table._rowModelFns.sortFns;
|
|
63
|
-
let sortFn;
|
|
64
63
|
const firstRows = column.table.getFilteredRowModel().flatRows.slice(0, 10);
|
|
65
64
|
let isString = false;
|
|
66
65
|
for (let i = 0; i < firstRows.length; i++) {
|
|
67
66
|
const value = firstRows[i].getValue(column.id);
|
|
68
|
-
if (Object.prototype.toString.call(value) === "[object Date]")
|
|
67
|
+
if (Object.prototype.toString.call(value) === "[object Date]") {
|
|
68
|
+
if (sortFns === null || sortFns === void 0 ? void 0 : sortFns.datetime) return sortFns.datetime;
|
|
69
|
+
}
|
|
69
70
|
if (typeof value === "string") {
|
|
70
71
|
isString = true;
|
|
71
|
-
if (value.split(reSplitAlphaNumeric).length > 1)
|
|
72
|
+
if (value.split(reSplitAlphaNumeric).length > 1) {
|
|
73
|
+
if (sortFns === null || sortFns === void 0 ? void 0 : sortFns.alphanumeric) return sortFns.alphanumeric;
|
|
74
|
+
}
|
|
72
75
|
}
|
|
73
76
|
}
|
|
74
|
-
if (isString)
|
|
75
|
-
return
|
|
77
|
+
if (isString) return (sortFns === null || sortFns === void 0 ? void 0 : sortFns.text) ?? sortFn_basic;
|
|
78
|
+
return sortFn_basic;
|
|
76
79
|
}
|
|
77
80
|
/**
|
|
78
81
|
* Chooses the default first sort direction from the first filtered row value.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rowSortingFeature.utils.js","names":[],"sources":["../../../src/features/row-sorting/rowSortingFeature.utils.ts"],"sourcesContent":["import { reSplitAlphaNumeric, sortFn_basic } from '../../fns/sortFns'\nimport { cloneState, isFunction } from '../../utils'\nimport type { CellData, RowData, Updater } from '../../types/type-utils'\nimport type { TableFeatures } from '../../types/TableFeatures'\nimport type { Table_Internal } from '../../types/Table'\nimport type { Column_Internal } from '../../types/Column'\nimport type {\n SortDirection,\n SortFn,\n SortingState,\n} from './rowSortingFeature.types'\n\n// State Utils\n\n/**\n * Creates the default sorting state.\n *\n * The feature default is an empty array, meaning no columns are sorted. Reset\n * APIs use this value when `defaultState` is `true`.\n *\n * @example\n * ```ts\n * const sorting = getDefaultSortingState()\n * ```\n */\nexport function getDefaultSortingState(): SortingState {\n return []\n}\n\n/**\n * Routes a sorting updater through the table's sorting change handler.\n *\n * The updater may be a next `SortingState` array or a function of the previous\n * sorting state, matching the instance `table.setSorting` behavior.\n *\n * @example\n * ```ts\n * table_setSorting(table, (old) => [...old, { id: 'age', desc: true }])\n * ```\n */\nexport function table_setSorting<\n TFeatures extends TableFeatures,\n TData extends RowData,\n>(table: Table_Internal<TFeatures, TData>, updater: Updater<SortingState>) {\n table.options.onSortingChange?.(updater)\n}\n\n/**\n * Resets `sorting` to the configured initial state or feature default.\n *\n * With no argument, the reset clones `table.initialState.sorting` when it\n * exists. Passing `true` ignores initial state and resets to `[]`.\n *\n * @example\n * ```ts\n * table_resetSorting(table)\n * table_resetSorting(table, true)\n * ```\n */\nexport function table_resetSorting<\n TFeatures extends TableFeatures,\n TData extends RowData,\n>(table: Table_Internal<TFeatures, TData>, defaultState?: boolean) {\n table_setSorting(\n table,\n defaultState ? [] : cloneState(table.initialState.sorting ?? []),\n )\n}\n\n// Column Utils\n\n/**\n * Chooses a built-in sorting function from sampled filtered row values.\n *\n * Date-like values use `datetime`, mixed text/numeric strings use\n * `alphanumeric`, plain strings use `text`, and unknown values fall back to\n * `basic`.\n *\n * @example\n * ```ts\n * const sortFn = column_getAutoSortFn(column)\n * ```\n */\nexport function column_getAutoSortFn<\n TFeatures extends TableFeatures,\n TData extends RowData,\n TValue extends CellData = CellData,\n>(column: Column_Internal<TFeatures, TData, TValue>): SortFn<TFeatures, TData> {\n const sortFns: Record<string, SortFn<TFeatures, TData>> | undefined =\n column.table._rowModelFns.sortFns\n\n let sortFn: SortFn<TFeatures, TData> | undefined\n\n const firstRows = column.table.getFilteredRowModel().flatRows.slice(0, 10)\n\n let isString = false\n\n for (let i = 0; i < firstRows.length; i++) {\n const value = firstRows[i]!.getValue(column.id)\n\n if (Object.prototype.toString.call(value) === '[object Date]') {\n sortFn = sortFns?.datetime\n }\n\n if (typeof value === 'string') {\n isString = true\n\n if (value.split(reSplitAlphaNumeric).length > 1) {\n sortFn = sortFns?.alphanumeric\n }\n }\n }\n\n if (isString) {\n sortFn = sortFns?.text\n }\n\n return sortFn ?? sortFn_basic\n}\n\n/**\n * Chooses the default first sort direction from the first filtered row value.\n *\n * String columns start ascending so alphabetical order is natural; other value\n * types start descending.\n *\n * @example\n * ```ts\n * const direction = column_getAutoSortDir(column)\n * ```\n */\nexport function column_getAutoSortDir<\n TFeatures extends TableFeatures,\n TData extends RowData,\n TValue extends CellData = CellData,\n>(column: Column_Internal<TFeatures, TData, TValue>) {\n const firstRow = column.table.getFilteredRowModel().flatRows[0]\n\n const value = firstRow ? firstRow.getValue(column.id) : undefined\n\n if (typeof value === 'string') {\n return 'asc'\n }\n\n return 'desc'\n}\n\n/**\n * Resolves the sorting function configured for a column.\n *\n * Function-valued `columnDef.sortFn` is returned directly, `'auto'` delegates\n * to `column_getAutoSortFn`, and string values are looked up in the table's\n * sorting function registry before falling back to `basic`.\n *\n * @example\n * ```ts\n * const sortFn = column_getSortFn(column)\n * ```\n */\nexport function column_getSortFn<\n TFeatures extends TableFeatures,\n TData extends RowData,\n TValue extends CellData = CellData,\n>(column: Column_Internal<TFeatures, TData, TValue>): SortFn<TFeatures, TData> {\n const sortFns: Record<string, SortFn<TFeatures, TData>> | undefined =\n column.table._rowModelFns.sortFns\n\n return isFunction(column.columnDef.sortFn)\n ? column.columnDef.sortFn\n : column.columnDef.sortFn === 'auto'\n ? column_getAutoSortFn(column)\n : (sortFns?.[column.columnDef.sortFn as string] ?? sortFn_basic)\n}\n\n/**\n * Applies the next sorting state for this column.\n *\n * The toggle can add, replace, flip, or remove this column's sort entry. Multi\n * sorting respects `enableMultiSort`, `maxMultiSortColCount`, and the `multi`\n * argument.\n *\n * @example\n * ```ts\n * column_toggleSorting(column, undefined, true)\n * ```\n */\nexport function column_toggleSorting<\n TFeatures extends TableFeatures,\n TData extends RowData,\n TValue extends CellData = CellData,\n>(\n column: Column_Internal<TFeatures, TData, TValue>,\n desc?: boolean,\n multi?: boolean,\n) {\n // if (column.columns.length) {\n // column.columns.forEach((c, i) => {\n // if (c.id) {\n // table.toggleColumnSorting(c.id, undefined, multi || !!i)\n // }\n // })\n // return\n // }\n\n // this needs to be outside of table.setSorting to be in sync with rerender\n const nextSortingOrder = column_getNextSortingOrder(column)\n const hasManualValue = typeof desc !== 'undefined'\n\n table_setSorting(column.table, (old) => {\n // Find any existing sorting for this column\n const existingSorting = old.find((d) => d.id === column.id)\n const existingIndex = old.findIndex((d) => d.id === column.id)\n\n let newSorting: SortingState = []\n\n // What should we do with this sort action?\n let sortAction: 'add' | 'remove' | 'toggle' | 'replace'\n const nextDesc = hasManualValue ? desc : nextSortingOrder === 'desc'\n\n // Multi-mode\n if (old.length && column_getCanMultiSort(column) && multi) {\n if (existingSorting) {\n sortAction = 'toggle'\n } else {\n sortAction = 'add'\n }\n } else {\n // Normal mode\n if (old.length && existingIndex !== old.length - 1) {\n sortAction = 'replace'\n } else if (existingSorting) {\n sortAction = 'toggle'\n } else {\n sortAction = 'replace'\n }\n }\n\n // Handle toggle states that will remove the sorting\n if (sortAction === 'toggle') {\n // If we are \"actually\" toggling (not a manual set value), should we remove the sorting?\n if (!hasManualValue) {\n // Is our intention to remove?\n if (!nextSortingOrder) {\n sortAction = 'remove'\n }\n }\n }\n\n if (sortAction === 'add') {\n newSorting = [\n ...old,\n {\n id: column.id,\n desc: nextDesc,\n },\n ]\n // Take latest n columns\n newSorting.splice(\n 0,\n newSorting.length -\n (column.table.options.maxMultiSortColCount ??\n Number.MAX_SAFE_INTEGER),\n )\n } else if (sortAction === 'toggle') {\n // This flips (or sets) the\n newSorting = old.map((d) => {\n if (d.id === column.id) {\n return {\n ...d,\n desc: nextDesc,\n }\n }\n return d\n })\n } else if (sortAction === 'remove') {\n newSorting = old.filter((d) => d.id !== column.id)\n } else {\n newSorting = [\n {\n id: column.id,\n desc: nextDesc,\n },\n ]\n }\n\n return newSorting\n })\n}\n\n/**\n * Resolves the first direction used when this column begins sorting.\n *\n * Column-level `sortDescFirst` wins, then table-level `sortDescFirst`, then the\n * auto direction inferred from sampled values.\n *\n * @example\n * ```ts\n * const firstDirection = column_getFirstSortDir(column)\n * ```\n */\nexport function column_getFirstSortDir<\n TFeatures extends TableFeatures,\n TData extends RowData,\n TValue extends CellData = CellData,\n>(column: Column_Internal<TFeatures, TData, TValue>) {\n const sortDescFirst =\n column.columnDef.sortDescFirst ??\n column.table.options.sortDescFirst ??\n column_getAutoSortDir(column) === 'desc'\n return sortDescFirst ? 'desc' : 'asc'\n}\n\n/**\n * Resolves the next sort order for this column's toggle cycle.\n *\n * The cycle starts with the first sort direction, flips between `asc` and\n * `desc`, and can return `false` when sorting removal is enabled.\n *\n * @example\n * ```ts\n * const nextOrder = column_getNextSortingOrder(column)\n * ```\n */\nexport function column_getNextSortingOrder<\n TFeatures extends TableFeatures,\n TData extends RowData,\n TValue extends CellData = CellData,\n>(column: Column_Internal<TFeatures, TData, TValue>, multi?: boolean) {\n const firstSortDirection = column_getFirstSortDir(column)\n const isSorted = column_getIsSorted(column)\n\n if (!isSorted) {\n return firstSortDirection\n }\n\n if (\n isSorted !== firstSortDirection &&\n (column.table.options.enableSortingRemoval ?? true) && // If enableSortRemove, enable in general\n (multi ? (column.table.options.enableMultiRemove ?? true) : true) // If multi, don't allow if enableMultiRemove))\n ) {\n return false\n }\n return isSorted === 'desc' ? 'asc' : 'desc'\n}\n\n/**\n * Checks whether this accessor column can participate in sorting.\n *\n * The column must have an accessor and sorting must be enabled by both the\n * column definition and table options.\n *\n * @example\n * ```ts\n * const canSort = column_getCanSort(column)\n * ```\n */\nexport function column_getCanSort<\n TFeatures extends TableFeatures,\n TData extends RowData,\n TValue extends CellData = CellData,\n>(column: Column_Internal<TFeatures, TData, TValue>) {\n return (\n (column.columnDef.enableSorting ?? true) &&\n (column.table.options.enableSorting ?? true) &&\n !!column.accessorFn\n )\n}\n\n/**\n * Checks whether this column can be added to a multi-sort state.\n *\n * Column-level `enableMultiSort` wins over table-level `enableMultiSort`; if\n * neither is set, accessor columns can multi-sort by default.\n *\n * @example\n * ```ts\n * const canMultiSort = column_getCanMultiSort(column)\n * ```\n */\nexport function column_getCanMultiSort<\n TFeatures extends TableFeatures,\n TData extends RowData,\n TValue extends CellData = CellData,\n>(column: Column_Internal<TFeatures, TData, TValue>): boolean {\n return (\n column.columnDef.enableMultiSort ??\n column.table.options.enableMultiSort ??\n !!column.accessorFn\n )\n}\n\n/**\n * Reads this column's current sort direction.\n *\n * The result is `false` when the column is not sorted, otherwise `'asc'` or\n * `'desc'` based on the column's entry in `state.sorting`.\n *\n * @example\n * ```ts\n * const direction = column_getIsSorted(column)\n * ```\n */\nexport function column_getIsSorted<\n TFeatures extends TableFeatures,\n TData extends RowData,\n TValue extends CellData = CellData,\n>(column: Column_Internal<TFeatures, TData, TValue>): false | SortDirection {\n const columnSort = column.table.atoms.sorting\n ?.get()\n ?.find((d) => d.id === column.id)\n return !columnSort ? false : columnSort.desc ? 'desc' : 'asc'\n}\n\n/**\n * Finds this column's position in the ordered `state.sorting` array.\n *\n * The result is `-1` when the column is not sorted.\n *\n * @example\n * ```ts\n * const index = column_getSortIndex(column)\n * ```\n */\nexport function column_getSortIndex<\n TFeatures extends TableFeatures,\n TData extends RowData,\n TValue extends CellData = CellData,\n>(column: Column_Internal<TFeatures, TData, TValue>): number {\n return (\n column.table.atoms.sorting?.get()?.findIndex((d) => d.id === column.id) ??\n -1\n )\n}\n\n/**\n * Removes this column from the sorting state.\n *\n * Other sorted columns are preserved, including their relative order.\n *\n * @example\n * ```ts\n * column_clearSorting(column)\n * ```\n */\nexport function column_clearSorting<\n TFeatures extends TableFeatures,\n TData extends RowData,\n TValue extends CellData = CellData,\n>(column: Column_Internal<TFeatures, TData, TValue>) {\n // clear sorting for just 1 column\n table_setSorting(column.table, (old) =>\n old.length ? old.filter((d) => d.id !== column.id) : [],\n )\n}\n\n/**\n * Creates a header event handler that toggles this column's sorting.\n *\n * The handler ignores events when the column cannot sort, persists React-style\n * synthetic events when present, and asks `options.isMultiSortEvent` whether\n * the event should add to a multi-sort.\n *\n * @example\n * ```ts\n * const onClick = column_getToggleSortingHandler(column)\n * ```\n */\nexport function column_getToggleSortingHandler<\n TFeatures extends TableFeatures,\n TData extends RowData,\n TValue extends CellData = CellData,\n>(column: Column_Internal<TFeatures, TData, TValue>) {\n const canSort = column_getCanSort(column)\n\n return (e: unknown) => {\n if (!canSort) return\n ;(e as any).persist?.()\n column_toggleSorting(\n column,\n\n undefined,\n column_getCanMultiSort(column)\n ? column.table.options.isMultiSortEvent?.(e)\n : false,\n )\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"rowSortingFeature.utils.js","names":[],"sources":["../../../src/features/row-sorting/rowSortingFeature.utils.ts"],"sourcesContent":["import { reSplitAlphaNumeric, sortFn_basic } from '../../fns/sortFns'\nimport { cloneState, isFunction } from '../../utils'\nimport type { CellData, RowData, Updater } from '../../types/type-utils'\nimport type { TableFeatures } from '../../types/TableFeatures'\nimport type { Table_Internal } from '../../types/Table'\nimport type { Column_Internal } from '../../types/Column'\nimport type {\n SortDirection,\n SortFn,\n SortingState,\n} from './rowSortingFeature.types'\n\n// State Utils\n\n/**\n * Creates the default sorting state.\n *\n * The feature default is an empty array, meaning no columns are sorted. Reset\n * APIs use this value when `defaultState` is `true`.\n *\n * @example\n * ```ts\n * const sorting = getDefaultSortingState()\n * ```\n */\nexport function getDefaultSortingState(): SortingState {\n return []\n}\n\n/**\n * Routes a sorting updater through the table's sorting change handler.\n *\n * The updater may be a next `SortingState` array or a function of the previous\n * sorting state, matching the instance `table.setSorting` behavior.\n *\n * @example\n * ```ts\n * table_setSorting(table, (old) => [...old, { id: 'age', desc: true }])\n * ```\n */\nexport function table_setSorting<\n TFeatures extends TableFeatures,\n TData extends RowData,\n>(table: Table_Internal<TFeatures, TData>, updater: Updater<SortingState>) {\n table.options.onSortingChange?.(updater)\n}\n\n/**\n * Resets `sorting` to the configured initial state or feature default.\n *\n * With no argument, the reset clones `table.initialState.sorting` when it\n * exists. Passing `true` ignores initial state and resets to `[]`.\n *\n * @example\n * ```ts\n * table_resetSorting(table)\n * table_resetSorting(table, true)\n * ```\n */\nexport function table_resetSorting<\n TFeatures extends TableFeatures,\n TData extends RowData,\n>(table: Table_Internal<TFeatures, TData>, defaultState?: boolean) {\n table_setSorting(\n table,\n defaultState ? [] : cloneState(table.initialState.sorting ?? []),\n )\n}\n\n// Column Utils\n\n/**\n * Chooses a built-in sorting function from sampled filtered row values.\n *\n * Date-like values use `datetime`, mixed text/numeric strings use\n * `alphanumeric`, plain strings use `text`, and unknown values fall back to\n * `basic`.\n *\n * @example\n * ```ts\n * const sortFn = column_getAutoSortFn(column)\n * ```\n */\nexport function column_getAutoSortFn<\n TFeatures extends TableFeatures,\n TData extends RowData,\n TValue extends CellData = CellData,\n>(column: Column_Internal<TFeatures, TData, TValue>): SortFn<TFeatures, TData> {\n const sortFns: Record<string, SortFn<TFeatures, TData>> | undefined =\n column.table._rowModelFns.sortFns\n\n const firstRows = column.table.getFilteredRowModel().flatRows.slice(0, 10)\n\n let isString = false\n\n for (let i = 0; i < firstRows.length; i++) {\n const value = firstRows[i]!.getValue(column.id)\n\n if (Object.prototype.toString.call(value) === '[object Date]') {\n if (sortFns?.datetime) {\n return sortFns.datetime\n }\n }\n\n if (typeof value === 'string') {\n isString = true\n\n if (value.split(reSplitAlphaNumeric).length > 1) {\n if (sortFns?.alphanumeric) {\n return sortFns.alphanumeric\n }\n }\n }\n }\n\n if (isString) {\n return sortFns?.text ?? sortFn_basic\n }\n\n return sortFn_basic\n}\n\n/**\n * Chooses the default first sort direction from the first filtered row value.\n *\n * String columns start ascending so alphabetical order is natural; other value\n * types start descending.\n *\n * @example\n * ```ts\n * const direction = column_getAutoSortDir(column)\n * ```\n */\nexport function column_getAutoSortDir<\n TFeatures extends TableFeatures,\n TData extends RowData,\n TValue extends CellData = CellData,\n>(column: Column_Internal<TFeatures, TData, TValue>) {\n const firstRow = column.table.getFilteredRowModel().flatRows[0]\n\n const value = firstRow ? firstRow.getValue(column.id) : undefined\n\n if (typeof value === 'string') {\n return 'asc'\n }\n\n return 'desc'\n}\n\n/**\n * Resolves the sorting function configured for a column.\n *\n * Function-valued `columnDef.sortFn` is returned directly, `'auto'` delegates\n * to `column_getAutoSortFn`, and string values are looked up in the table's\n * sorting function registry before falling back to `basic`.\n *\n * @example\n * ```ts\n * const sortFn = column_getSortFn(column)\n * ```\n */\nexport function column_getSortFn<\n TFeatures extends TableFeatures,\n TData extends RowData,\n TValue extends CellData = CellData,\n>(column: Column_Internal<TFeatures, TData, TValue>): SortFn<TFeatures, TData> {\n const sortFns: Record<string, SortFn<TFeatures, TData>> | undefined =\n column.table._rowModelFns.sortFns\n\n return isFunction(column.columnDef.sortFn)\n ? column.columnDef.sortFn\n : column.columnDef.sortFn === 'auto'\n ? column_getAutoSortFn(column)\n : (sortFns?.[column.columnDef.sortFn as string] ?? sortFn_basic)\n}\n\n/**\n * Applies the next sorting state for this column.\n *\n * The toggle can add, replace, flip, or remove this column's sort entry. Multi\n * sorting respects `enableMultiSort`, `maxMultiSortColCount`, and the `multi`\n * argument.\n *\n * @example\n * ```ts\n * column_toggleSorting(column, undefined, true)\n * ```\n */\nexport function column_toggleSorting<\n TFeatures extends TableFeatures,\n TData extends RowData,\n TValue extends CellData = CellData,\n>(\n column: Column_Internal<TFeatures, TData, TValue>,\n desc?: boolean,\n multi?: boolean,\n) {\n // if (column.columns.length) {\n // column.columns.forEach((c, i) => {\n // if (c.id) {\n // table.toggleColumnSorting(c.id, undefined, multi || !!i)\n // }\n // })\n // return\n // }\n\n // this needs to be outside of table.setSorting to be in sync with rerender\n const nextSortingOrder = column_getNextSortingOrder(column)\n const hasManualValue = typeof desc !== 'undefined'\n\n table_setSorting(column.table, (old) => {\n // Find any existing sorting for this column\n const existingSorting = old.find((d) => d.id === column.id)\n const existingIndex = old.findIndex((d) => d.id === column.id)\n\n let newSorting: SortingState = []\n\n // What should we do with this sort action?\n let sortAction: 'add' | 'remove' | 'toggle' | 'replace'\n const nextDesc = hasManualValue ? desc : nextSortingOrder === 'desc'\n\n // Multi-mode\n if (old.length && column_getCanMultiSort(column) && multi) {\n if (existingSorting) {\n sortAction = 'toggle'\n } else {\n sortAction = 'add'\n }\n } else {\n // Normal mode\n if (old.length && existingIndex !== old.length - 1) {\n sortAction = 'replace'\n } else if (existingSorting) {\n sortAction = 'toggle'\n } else {\n sortAction = 'replace'\n }\n }\n\n // Handle toggle states that will remove the sorting\n if (sortAction === 'toggle') {\n // If we are \"actually\" toggling (not a manual set value), should we remove the sorting?\n if (!hasManualValue) {\n // Is our intention to remove?\n if (!nextSortingOrder) {\n sortAction = 'remove'\n }\n }\n }\n\n if (sortAction === 'add') {\n newSorting = [\n ...old,\n {\n id: column.id,\n desc: nextDesc,\n },\n ]\n // Take latest n columns\n newSorting.splice(\n 0,\n newSorting.length -\n (column.table.options.maxMultiSortColCount ??\n Number.MAX_SAFE_INTEGER),\n )\n } else if (sortAction === 'toggle') {\n // This flips (or sets) the\n newSorting = old.map((d) => {\n if (d.id === column.id) {\n return {\n ...d,\n desc: nextDesc,\n }\n }\n return d\n })\n } else if (sortAction === 'remove') {\n newSorting = old.filter((d) => d.id !== column.id)\n } else {\n newSorting = [\n {\n id: column.id,\n desc: nextDesc,\n },\n ]\n }\n\n return newSorting\n })\n}\n\n/**\n * Resolves the first direction used when this column begins sorting.\n *\n * Column-level `sortDescFirst` wins, then table-level `sortDescFirst`, then the\n * auto direction inferred from sampled values.\n *\n * @example\n * ```ts\n * const firstDirection = column_getFirstSortDir(column)\n * ```\n */\nexport function column_getFirstSortDir<\n TFeatures extends TableFeatures,\n TData extends RowData,\n TValue extends CellData = CellData,\n>(column: Column_Internal<TFeatures, TData, TValue>) {\n const sortDescFirst =\n column.columnDef.sortDescFirst ??\n column.table.options.sortDescFirst ??\n column_getAutoSortDir(column) === 'desc'\n return sortDescFirst ? 'desc' : 'asc'\n}\n\n/**\n * Resolves the next sort order for this column's toggle cycle.\n *\n * The cycle starts with the first sort direction, flips between `asc` and\n * `desc`, and can return `false` when sorting removal is enabled.\n *\n * @example\n * ```ts\n * const nextOrder = column_getNextSortingOrder(column)\n * ```\n */\nexport function column_getNextSortingOrder<\n TFeatures extends TableFeatures,\n TData extends RowData,\n TValue extends CellData = CellData,\n>(column: Column_Internal<TFeatures, TData, TValue>, multi?: boolean) {\n const firstSortDirection = column_getFirstSortDir(column)\n const isSorted = column_getIsSorted(column)\n\n if (!isSorted) {\n return firstSortDirection\n }\n\n if (\n isSorted !== firstSortDirection &&\n (column.table.options.enableSortingRemoval ?? true) && // If enableSortRemove, enable in general\n (multi ? (column.table.options.enableMultiRemove ?? true) : true) // If multi, don't allow if enableMultiRemove))\n ) {\n return false\n }\n return isSorted === 'desc' ? 'asc' : 'desc'\n}\n\n/**\n * Checks whether this accessor column can participate in sorting.\n *\n * The column must have an accessor and sorting must be enabled by both the\n * column definition and table options.\n *\n * @example\n * ```ts\n * const canSort = column_getCanSort(column)\n * ```\n */\nexport function column_getCanSort<\n TFeatures extends TableFeatures,\n TData extends RowData,\n TValue extends CellData = CellData,\n>(column: Column_Internal<TFeatures, TData, TValue>) {\n return (\n (column.columnDef.enableSorting ?? true) &&\n (column.table.options.enableSorting ?? true) &&\n !!column.accessorFn\n )\n}\n\n/**\n * Checks whether this column can be added to a multi-sort state.\n *\n * Column-level `enableMultiSort` wins over table-level `enableMultiSort`; if\n * neither is set, accessor columns can multi-sort by default.\n *\n * @example\n * ```ts\n * const canMultiSort = column_getCanMultiSort(column)\n * ```\n */\nexport function column_getCanMultiSort<\n TFeatures extends TableFeatures,\n TData extends RowData,\n TValue extends CellData = CellData,\n>(column: Column_Internal<TFeatures, TData, TValue>): boolean {\n return (\n column.columnDef.enableMultiSort ??\n column.table.options.enableMultiSort ??\n !!column.accessorFn\n )\n}\n\n/**\n * Reads this column's current sort direction.\n *\n * The result is `false` when the column is not sorted, otherwise `'asc'` or\n * `'desc'` based on the column's entry in `state.sorting`.\n *\n * @example\n * ```ts\n * const direction = column_getIsSorted(column)\n * ```\n */\nexport function column_getIsSorted<\n TFeatures extends TableFeatures,\n TData extends RowData,\n TValue extends CellData = CellData,\n>(column: Column_Internal<TFeatures, TData, TValue>): false | SortDirection {\n const columnSort = column.table.atoms.sorting\n ?.get()\n ?.find((d) => d.id === column.id)\n return !columnSort ? false : columnSort.desc ? 'desc' : 'asc'\n}\n\n/**\n * Finds this column's position in the ordered `state.sorting` array.\n *\n * The result is `-1` when the column is not sorted.\n *\n * @example\n * ```ts\n * const index = column_getSortIndex(column)\n * ```\n */\nexport function column_getSortIndex<\n TFeatures extends TableFeatures,\n TData extends RowData,\n TValue extends CellData = CellData,\n>(column: Column_Internal<TFeatures, TData, TValue>): number {\n return (\n column.table.atoms.sorting?.get()?.findIndex((d) => d.id === column.id) ??\n -1\n )\n}\n\n/**\n * Removes this column from the sorting state.\n *\n * Other sorted columns are preserved, including their relative order.\n *\n * @example\n * ```ts\n * column_clearSorting(column)\n * ```\n */\nexport function column_clearSorting<\n TFeatures extends TableFeatures,\n TData extends RowData,\n TValue extends CellData = CellData,\n>(column: Column_Internal<TFeatures, TData, TValue>) {\n // clear sorting for just 1 column\n table_setSorting(column.table, (old) =>\n old.length ? old.filter((d) => d.id !== column.id) : [],\n )\n}\n\n/**\n * Creates a header event handler that toggles this column's sorting.\n *\n * The handler ignores events when the column cannot sort, persists React-style\n * synthetic events when present, and asks `options.isMultiSortEvent` whether\n * the event should add to a multi-sort.\n *\n * @example\n * ```ts\n * const onClick = column_getToggleSortingHandler(column)\n * ```\n */\nexport function column_getToggleSortingHandler<\n TFeatures extends TableFeatures,\n TData extends RowData,\n TValue extends CellData = CellData,\n>(column: Column_Internal<TFeatures, TData, TValue>) {\n const canSort = column_getCanSort(column)\n\n return (e: unknown) => {\n if (!canSort) return\n ;(e as any).persist?.()\n column_toggleSorting(\n column,\n\n undefined,\n column_getCanMultiSort(column)\n ? column.table.options.isMultiSortEvent?.(e)\n : false,\n )\n }\n}\n"],"mappings":"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"}
|
package/dist/fns/sortFns.cjs
CHANGED
|
@@ -69,28 +69,40 @@ function toString(a) {
|
|
|
69
69
|
return "";
|
|
70
70
|
}
|
|
71
71
|
function compareAlphanumeric(aStr, bStr) {
|
|
72
|
-
const a = aStr.split(reSplitAlphaNumeric)
|
|
73
|
-
const b = bStr.split(reSplitAlphaNumeric)
|
|
72
|
+
const a = aStr.split(reSplitAlphaNumeric);
|
|
73
|
+
const b = bStr.split(reSplitAlphaNumeric);
|
|
74
74
|
let ai = 0;
|
|
75
75
|
let bi = 0;
|
|
76
76
|
const aLen = a.length;
|
|
77
77
|
const bLen = b.length;
|
|
78
78
|
while (ai < aLen && bi < bLen) {
|
|
79
|
+
if (!a[ai]) {
|
|
80
|
+
ai++;
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
if (!b[bi]) {
|
|
84
|
+
bi++;
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
79
87
|
const aa = a[ai++];
|
|
80
88
|
const bb = b[bi++];
|
|
81
89
|
const an = parseInt(aa, 10);
|
|
82
90
|
const bn = parseInt(bb, 10);
|
|
83
|
-
const
|
|
84
|
-
|
|
91
|
+
const aIsNaN = isNaN(an);
|
|
92
|
+
const bIsNaN = isNaN(bn);
|
|
93
|
+
if (aIsNaN && bIsNaN) {
|
|
85
94
|
if (aa > bb) return 1;
|
|
86
95
|
if (bb > aa) return -1;
|
|
87
96
|
continue;
|
|
88
97
|
}
|
|
89
|
-
if (
|
|
98
|
+
if (aIsNaN || bIsNaN) return aIsNaN ? -1 : 1;
|
|
90
99
|
if (an > bn) return 1;
|
|
91
100
|
if (bn > an) return -1;
|
|
92
101
|
}
|
|
93
|
-
|
|
102
|
+
let remaining = 0;
|
|
103
|
+
for (; ai < aLen; ai++) if (a[ai]) remaining++;
|
|
104
|
+
for (; bi < bLen; bi++) if (b[bi]) remaining--;
|
|
105
|
+
return remaining;
|
|
94
106
|
}
|
|
95
107
|
/**
|
|
96
108
|
* The built-in sorting function registry.
|
package/dist/fns/sortFns.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sortFns.cjs","names":[],"sources":["../../src/fns/sortFns.ts"],"sourcesContent":["import type { RowData } from '../types/type-utils'\nimport type { TableFeatures } from '../types/TableFeatures'\nimport type { Row } from '../types/Row'\n\n/**\n * Regular expression used to split mixed text and numeric chunks.\n *\n * The alphanumeric sort functions use these chunks for natural sorting of\n * strings like `item2` before `item10`.\n */\nexport const reSplitAlphaNumeric = /([0-9]+)/gm\n\n/**\n * Sorts rows with the built-in alphanumeric strategy.\n *\n * This comparator returns ascending-order results; descending order is applied by the sorting row model.\n */\nexport const sortFn_alphanumeric = <\n TFeatures extends TableFeatures,\n TData extends RowData,\n>(\n rowA: Row<TFeatures, TData>,\n rowB: Row<TFeatures, TData>,\n columnId: string,\n) => {\n return compareAlphanumeric(\n toString(rowA.getValue(columnId)).toLowerCase(),\n toString(rowB.getValue(columnId)).toLowerCase(),\n )\n}\n\n/**\n * Sorts rows with the built-in alphanumeric case sensitive strategy.\n *\n * This comparator returns ascending-order results; descending order is applied by the sorting row model.\n */\nexport const sortFn_alphanumericCaseSensitive = <\n TFeatures extends TableFeatures,\n TData extends RowData,\n>(\n rowA: Row<TFeatures, TData>,\n rowB: Row<TFeatures, TData>,\n columnId: string,\n) => {\n return compareAlphanumeric(\n toString(rowA.getValue(columnId)),\n toString(rowB.getValue(columnId)),\n )\n}\n\n// The text filter is more basic (less numeric support)\n// but is much faster\n/**\n * Sorts rows with the built-in text strategy.\n *\n * This comparator returns ascending-order results; descending order is applied by the sorting row model.\n */\nexport const sortFn_text = <\n TFeatures extends TableFeatures,\n TData extends RowData,\n>(\n rowA: Row<TFeatures, TData>,\n rowB: Row<TFeatures, TData>,\n columnId: string,\n) => {\n return compareBasic(\n toString(rowA.getValue(columnId)).toLowerCase(),\n toString(rowB.getValue(columnId)).toLowerCase(),\n )\n}\n\n// The text filter is more basic (less numeric support)\n// but is much faster\n/**\n * Sorts rows with the built-in text case sensitive strategy.\n *\n * This comparator returns ascending-order results; descending order is applied by the sorting row model.\n */\nexport const sortFn_textCaseSensitive = <\n TFeatures extends TableFeatures,\n TData extends RowData,\n>(\n rowA: Row<TFeatures, TData>,\n rowB: Row<TFeatures, TData>,\n columnId: string,\n) => {\n return compareBasic(\n toString(rowA.getValue(columnId)),\n toString(rowB.getValue(columnId)),\n )\n}\n\n/**\n * Sorts rows with the built-in datetime strategy.\n *\n * This comparator returns ascending-order results; descending order is applied by the sorting row model.\n */\nexport const sortFn_datetime = <\n TFeatures extends TableFeatures,\n TData extends RowData,\n>(\n rowA: Row<TFeatures, TData>,\n rowB: Row<TFeatures, TData>,\n columnId: string,\n) => {\n const a: number | string = rowA.getValue(columnId)\n const b: number | string = rowB.getValue(columnId)\n\n // Can handle nullish values\n // Use > and < because == (and ===) doesn't work with\n // Date objects (would require calling getTime()).\n return a > b ? 1 : a < b ? -1 : 0\n}\n\n/**\n * Sorts rows with the built-in basic strategy.\n *\n * This comparator returns ascending-order results; descending order is applied by the sorting row model.\n */\nexport const sortFn_basic = <\n TFeatures extends TableFeatures,\n TData extends RowData,\n>(\n rowA: Row<TFeatures, TData>,\n rowB: Row<TFeatures, TData>,\n columnId: string,\n) => {\n return compareBasic(rowA.getValue(columnId), rowB.getValue(columnId))\n}\n\n// Utils\n\nfunction compareBasic(a: any, b: any) {\n return a === b ? 0 : a > b ? 1 : -1\n}\n\nfunction toString(a: any) {\n if (typeof a === 'number') {\n if (isNaN(a) || a === Infinity || a === -Infinity) {\n return ''\n }\n return String(a)\n }\n if (typeof a === 'string') {\n return a\n }\n return ''\n}\n\n// Mixed sorting is slow, but very inclusive of many edge cases.\n// It handles numbers, mixed alphanumeric combinations, and even\n// null, undefined, and Infinity\nfunction compareAlphanumeric(aStr: string, bStr: string) {\n
|
|
1
|
+
{"version":3,"file":"sortFns.cjs","names":[],"sources":["../../src/fns/sortFns.ts"],"sourcesContent":["import type { RowData } from '../types/type-utils'\nimport type { TableFeatures } from '../types/TableFeatures'\nimport type { Row } from '../types/Row'\n\n/**\n * Regular expression used to split mixed text and numeric chunks.\n *\n * The alphanumeric sort functions use these chunks for natural sorting of\n * strings like `item2` before `item10`.\n */\nexport const reSplitAlphaNumeric = /([0-9]+)/gm\n\n/**\n * Sorts rows with the built-in alphanumeric strategy.\n *\n * This comparator returns ascending-order results; descending order is applied by the sorting row model.\n */\nexport const sortFn_alphanumeric = <\n TFeatures extends TableFeatures,\n TData extends RowData,\n>(\n rowA: Row<TFeatures, TData>,\n rowB: Row<TFeatures, TData>,\n columnId: string,\n) => {\n return compareAlphanumeric(\n toString(rowA.getValue(columnId)).toLowerCase(),\n toString(rowB.getValue(columnId)).toLowerCase(),\n )\n}\n\n/**\n * Sorts rows with the built-in alphanumeric case sensitive strategy.\n *\n * This comparator returns ascending-order results; descending order is applied by the sorting row model.\n */\nexport const sortFn_alphanumericCaseSensitive = <\n TFeatures extends TableFeatures,\n TData extends RowData,\n>(\n rowA: Row<TFeatures, TData>,\n rowB: Row<TFeatures, TData>,\n columnId: string,\n) => {\n return compareAlphanumeric(\n toString(rowA.getValue(columnId)),\n toString(rowB.getValue(columnId)),\n )\n}\n\n// The text filter is more basic (less numeric support)\n// but is much faster\n/**\n * Sorts rows with the built-in text strategy.\n *\n * This comparator returns ascending-order results; descending order is applied by the sorting row model.\n */\nexport const sortFn_text = <\n TFeatures extends TableFeatures,\n TData extends RowData,\n>(\n rowA: Row<TFeatures, TData>,\n rowB: Row<TFeatures, TData>,\n columnId: string,\n) => {\n return compareBasic(\n toString(rowA.getValue(columnId)).toLowerCase(),\n toString(rowB.getValue(columnId)).toLowerCase(),\n )\n}\n\n// The text filter is more basic (less numeric support)\n// but is much faster\n/**\n * Sorts rows with the built-in text case sensitive strategy.\n *\n * This comparator returns ascending-order results; descending order is applied by the sorting row model.\n */\nexport const sortFn_textCaseSensitive = <\n TFeatures extends TableFeatures,\n TData extends RowData,\n>(\n rowA: Row<TFeatures, TData>,\n rowB: Row<TFeatures, TData>,\n columnId: string,\n) => {\n return compareBasic(\n toString(rowA.getValue(columnId)),\n toString(rowB.getValue(columnId)),\n )\n}\n\n/**\n * Sorts rows with the built-in datetime strategy.\n *\n * This comparator returns ascending-order results; descending order is applied by the sorting row model.\n */\nexport const sortFn_datetime = <\n TFeatures extends TableFeatures,\n TData extends RowData,\n>(\n rowA: Row<TFeatures, TData>,\n rowB: Row<TFeatures, TData>,\n columnId: string,\n) => {\n const a: number | string = rowA.getValue(columnId)\n const b: number | string = rowB.getValue(columnId)\n\n // Can handle nullish values\n // Use > and < because == (and ===) doesn't work with\n // Date objects (would require calling getTime()).\n return a > b ? 1 : a < b ? -1 : 0\n}\n\n/**\n * Sorts rows with the built-in basic strategy.\n *\n * This comparator returns ascending-order results; descending order is applied by the sorting row model.\n */\nexport const sortFn_basic = <\n TFeatures extends TableFeatures,\n TData extends RowData,\n>(\n rowA: Row<TFeatures, TData>,\n rowB: Row<TFeatures, TData>,\n columnId: string,\n) => {\n return compareBasic(rowA.getValue(columnId), rowB.getValue(columnId))\n}\n\n// Utils\n\nfunction compareBasic(a: any, b: any) {\n return a === b ? 0 : a > b ? 1 : -1\n}\n\nfunction toString(a: any) {\n if (typeof a === 'number') {\n if (isNaN(a) || a === Infinity || a === -Infinity) {\n return ''\n }\n return String(a)\n }\n if (typeof a === 'string') {\n return a\n }\n return ''\n}\n\n// Mixed sorting is slow, but very inclusive of many edge cases.\n// It handles numbers, mixed alphanumeric combinations, and even\n// null, undefined, and Infinity\nfunction compareAlphanumeric(aStr: string, bStr: string) {\n const a = aStr.split(reSplitAlphaNumeric)\n const b = bStr.split(reSplitAlphaNumeric)\n\n let ai = 0\n let bi = 0\n const aLen = a.length\n const bLen = b.length\n\n while (ai < aLen && bi < bLen) {\n // Skip the empty boundary chunks that .filter(Boolean) used to remove\n if (!a[ai]) {\n ai++\n continue\n }\n if (!b[bi]) {\n bi++\n continue\n }\n\n const aa = a[ai++]!\n const bb = b[bi++]!\n\n // Chunks are either all-digit (parseInt always succeeds) or digit-free\n // (parseInt is always NaN), so NaN-ness fully classifies each chunk\n const an = parseInt(aa, 10)\n const bn = parseInt(bb, 10)\n\n const aIsNaN = isNaN(an)\n const bIsNaN = isNaN(bn)\n\n // Both are string\n if (aIsNaN && bIsNaN) {\n if (aa > bb) {\n return 1\n }\n if (bb > aa) {\n return -1\n }\n continue\n }\n\n // One is a string, one is a number — the string chunk sorts first\n if (aIsNaN || bIsNaN) {\n return aIsNaN ? -1 : 1\n }\n\n // Both are numbers\n if (an > bn) {\n return 1\n }\n if (bn > an) {\n return -1\n }\n }\n\n // One side is exhausted — compare the counts of remaining non-empty chunks\n let remaining = 0\n for (; ai < aLen; ai++) {\n if (a[ai]) {\n remaining++\n }\n }\n for (; bi < bLen; bi++) {\n if (b[bi]) {\n remaining--\n }\n }\n return remaining\n}\n\n// Exports\n\n/**\n * The built-in sorting function registry.\n *\n * Pass this object to sorted row model creation or extend it with custom sorting functions.\n */\nexport const sortFns = {\n alphanumeric: sortFn_alphanumeric,\n alphanumericCaseSensitive: sortFn_alphanumericCaseSensitive,\n basic: sortFn_basic,\n datetime: sortFn_datetime,\n text: sortFn_text,\n textCaseSensitive: sortFn_textCaseSensitive,\n}\n\nexport type BuiltInSortFn = keyof typeof sortFns\n"],"mappings":";;;;;;;;AAUA,MAAa,sBAAsB;;;;;;AAOnC,MAAa,uBAIX,MACA,MACA,aACG;CACH,OAAO,oBACL,SAAS,KAAK,SAAS,QAAQ,CAAC,CAAC,CAAC,YAAY,GAC9C,SAAS,KAAK,SAAS,QAAQ,CAAC,CAAC,CAAC,YAAY,CAChD;AACF;;;;;;AAOA,MAAa,oCAIX,MACA,MACA,aACG;CACH,OAAO,oBACL,SAAS,KAAK,SAAS,QAAQ,CAAC,GAChC,SAAS,KAAK,SAAS,QAAQ,CAAC,CAClC;AACF;;;;;;AASA,MAAa,eAIX,MACA,MACA,aACG;CACH,OAAO,aACL,SAAS,KAAK,SAAS,QAAQ,CAAC,CAAC,CAAC,YAAY,GAC9C,SAAS,KAAK,SAAS,QAAQ,CAAC,CAAC,CAAC,YAAY,CAChD;AACF;;;;;;AASA,MAAa,4BAIX,MACA,MACA,aACG;CACH,OAAO,aACL,SAAS,KAAK,SAAS,QAAQ,CAAC,GAChC,SAAS,KAAK,SAAS,QAAQ,CAAC,CAClC;AACF;;;;;;AAOA,MAAa,mBAIX,MACA,MACA,aACG;CACH,MAAM,IAAqB,KAAK,SAAS,QAAQ;CACjD,MAAM,IAAqB,KAAK,SAAS,QAAQ;CAKjD,OAAO,IAAI,IAAI,IAAI,IAAI,IAAI,KAAK;AAClC;;;;;;AAOA,MAAa,gBAIX,MACA,MACA,aACG;CACH,OAAO,aAAa,KAAK,SAAS,QAAQ,GAAG,KAAK,SAAS,QAAQ,CAAC;AACtE;AAIA,SAAS,aAAa,GAAQ,GAAQ;CACpC,OAAO,MAAM,IAAI,IAAI,IAAI,IAAI,IAAI;AACnC;AAEA,SAAS,SAAS,GAAQ;CACxB,IAAI,OAAO,MAAM,UAAU;EACzB,IAAI,MAAM,CAAC,KAAK,MAAM,YAAY,MAAM,WACtC,OAAO;EAET,OAAO,OAAO,CAAC;CACjB;CACA,IAAI,OAAO,MAAM,UACf,OAAO;CAET,OAAO;AACT;AAKA,SAAS,oBAAoB,MAAc,MAAc;CACvD,MAAM,IAAI,KAAK,MAAM,mBAAmB;CACxC,MAAM,IAAI,KAAK,MAAM,mBAAmB;CAExC,IAAI,KAAK;CACT,IAAI,KAAK;CACT,MAAM,OAAO,EAAE;CACf,MAAM,OAAO,EAAE;CAEf,OAAO,KAAK,QAAQ,KAAK,MAAM;EAE7B,IAAI,CAAC,EAAE,KAAK;GACV;GACA;EACF;EACA,IAAI,CAAC,EAAE,KAAK;GACV;GACA;EACF;EAEA,MAAM,KAAK,EAAE;EACb,MAAM,KAAK,EAAE;EAIb,MAAM,KAAK,SAAS,IAAI,EAAE;EAC1B,MAAM,KAAK,SAAS,IAAI,EAAE;EAE1B,MAAM,SAAS,MAAM,EAAE;EACvB,MAAM,SAAS,MAAM,EAAE;EAGvB,IAAI,UAAU,QAAQ;GACpB,IAAI,KAAK,IACP,OAAO;GAET,IAAI,KAAK,IACP,OAAO;GAET;EACF;EAGA,IAAI,UAAU,QACZ,OAAO,SAAS,KAAK;EAIvB,IAAI,KAAK,IACP,OAAO;EAET,IAAI,KAAK,IACP,OAAO;CAEX;CAGA,IAAI,YAAY;CAChB,OAAO,KAAK,MAAM,MAChB,IAAI,EAAE,KACJ;CAGJ,OAAO,KAAK,MAAM,MAChB,IAAI,EAAE,KACJ;CAGJ,OAAO;AACT;;;;;;AASA,MAAa,UAAU;CACrB,cAAc;CACd,2BAA2B;CAC3B,OAAO;CACP,UAAU;CACV,MAAM;CACN,mBAAmB;AACrB"}
|
package/dist/fns/sortFns.js
CHANGED
|
@@ -68,28 +68,40 @@ function toString(a) {
|
|
|
68
68
|
return "";
|
|
69
69
|
}
|
|
70
70
|
function compareAlphanumeric(aStr, bStr) {
|
|
71
|
-
const a = aStr.split(reSplitAlphaNumeric)
|
|
72
|
-
const b = bStr.split(reSplitAlphaNumeric)
|
|
71
|
+
const a = aStr.split(reSplitAlphaNumeric);
|
|
72
|
+
const b = bStr.split(reSplitAlphaNumeric);
|
|
73
73
|
let ai = 0;
|
|
74
74
|
let bi = 0;
|
|
75
75
|
const aLen = a.length;
|
|
76
76
|
const bLen = b.length;
|
|
77
77
|
while (ai < aLen && bi < bLen) {
|
|
78
|
+
if (!a[ai]) {
|
|
79
|
+
ai++;
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
if (!b[bi]) {
|
|
83
|
+
bi++;
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
78
86
|
const aa = a[ai++];
|
|
79
87
|
const bb = b[bi++];
|
|
80
88
|
const an = parseInt(aa, 10);
|
|
81
89
|
const bn = parseInt(bb, 10);
|
|
82
|
-
const
|
|
83
|
-
|
|
90
|
+
const aIsNaN = isNaN(an);
|
|
91
|
+
const bIsNaN = isNaN(bn);
|
|
92
|
+
if (aIsNaN && bIsNaN) {
|
|
84
93
|
if (aa > bb) return 1;
|
|
85
94
|
if (bb > aa) return -1;
|
|
86
95
|
continue;
|
|
87
96
|
}
|
|
88
|
-
if (
|
|
97
|
+
if (aIsNaN || bIsNaN) return aIsNaN ? -1 : 1;
|
|
89
98
|
if (an > bn) return 1;
|
|
90
99
|
if (bn > an) return -1;
|
|
91
100
|
}
|
|
92
|
-
|
|
101
|
+
let remaining = 0;
|
|
102
|
+
for (; ai < aLen; ai++) if (a[ai]) remaining++;
|
|
103
|
+
for (; bi < bLen; bi++) if (b[bi]) remaining--;
|
|
104
|
+
return remaining;
|
|
93
105
|
}
|
|
94
106
|
/**
|
|
95
107
|
* The built-in sorting function registry.
|
package/dist/fns/sortFns.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sortFns.js","names":[],"sources":["../../src/fns/sortFns.ts"],"sourcesContent":["import type { RowData } from '../types/type-utils'\nimport type { TableFeatures } from '../types/TableFeatures'\nimport type { Row } from '../types/Row'\n\n/**\n * Regular expression used to split mixed text and numeric chunks.\n *\n * The alphanumeric sort functions use these chunks for natural sorting of\n * strings like `item2` before `item10`.\n */\nexport const reSplitAlphaNumeric = /([0-9]+)/gm\n\n/**\n * Sorts rows with the built-in alphanumeric strategy.\n *\n * This comparator returns ascending-order results; descending order is applied by the sorting row model.\n */\nexport const sortFn_alphanumeric = <\n TFeatures extends TableFeatures,\n TData extends RowData,\n>(\n rowA: Row<TFeatures, TData>,\n rowB: Row<TFeatures, TData>,\n columnId: string,\n) => {\n return compareAlphanumeric(\n toString(rowA.getValue(columnId)).toLowerCase(),\n toString(rowB.getValue(columnId)).toLowerCase(),\n )\n}\n\n/**\n * Sorts rows with the built-in alphanumeric case sensitive strategy.\n *\n * This comparator returns ascending-order results; descending order is applied by the sorting row model.\n */\nexport const sortFn_alphanumericCaseSensitive = <\n TFeatures extends TableFeatures,\n TData extends RowData,\n>(\n rowA: Row<TFeatures, TData>,\n rowB: Row<TFeatures, TData>,\n columnId: string,\n) => {\n return compareAlphanumeric(\n toString(rowA.getValue(columnId)),\n toString(rowB.getValue(columnId)),\n )\n}\n\n// The text filter is more basic (less numeric support)\n// but is much faster\n/**\n * Sorts rows with the built-in text strategy.\n *\n * This comparator returns ascending-order results; descending order is applied by the sorting row model.\n */\nexport const sortFn_text = <\n TFeatures extends TableFeatures,\n TData extends RowData,\n>(\n rowA: Row<TFeatures, TData>,\n rowB: Row<TFeatures, TData>,\n columnId: string,\n) => {\n return compareBasic(\n toString(rowA.getValue(columnId)).toLowerCase(),\n toString(rowB.getValue(columnId)).toLowerCase(),\n )\n}\n\n// The text filter is more basic (less numeric support)\n// but is much faster\n/**\n * Sorts rows with the built-in text case sensitive strategy.\n *\n * This comparator returns ascending-order results; descending order is applied by the sorting row model.\n */\nexport const sortFn_textCaseSensitive = <\n TFeatures extends TableFeatures,\n TData extends RowData,\n>(\n rowA: Row<TFeatures, TData>,\n rowB: Row<TFeatures, TData>,\n columnId: string,\n) => {\n return compareBasic(\n toString(rowA.getValue(columnId)),\n toString(rowB.getValue(columnId)),\n )\n}\n\n/**\n * Sorts rows with the built-in datetime strategy.\n *\n * This comparator returns ascending-order results; descending order is applied by the sorting row model.\n */\nexport const sortFn_datetime = <\n TFeatures extends TableFeatures,\n TData extends RowData,\n>(\n rowA: Row<TFeatures, TData>,\n rowB: Row<TFeatures, TData>,\n columnId: string,\n) => {\n const a: number | string = rowA.getValue(columnId)\n const b: number | string = rowB.getValue(columnId)\n\n // Can handle nullish values\n // Use > and < because == (and ===) doesn't work with\n // Date objects (would require calling getTime()).\n return a > b ? 1 : a < b ? -1 : 0\n}\n\n/**\n * Sorts rows with the built-in basic strategy.\n *\n * This comparator returns ascending-order results; descending order is applied by the sorting row model.\n */\nexport const sortFn_basic = <\n TFeatures extends TableFeatures,\n TData extends RowData,\n>(\n rowA: Row<TFeatures, TData>,\n rowB: Row<TFeatures, TData>,\n columnId: string,\n) => {\n return compareBasic(rowA.getValue(columnId), rowB.getValue(columnId))\n}\n\n// Utils\n\nfunction compareBasic(a: any, b: any) {\n return a === b ? 0 : a > b ? 1 : -1\n}\n\nfunction toString(a: any) {\n if (typeof a === 'number') {\n if (isNaN(a) || a === Infinity || a === -Infinity) {\n return ''\n }\n return String(a)\n }\n if (typeof a === 'string') {\n return a\n }\n return ''\n}\n\n// Mixed sorting is slow, but very inclusive of many edge cases.\n// It handles numbers, mixed alphanumeric combinations, and even\n// null, undefined, and Infinity\nfunction compareAlphanumeric(aStr: string, bStr: string) {\n
|
|
1
|
+
{"version":3,"file":"sortFns.js","names":[],"sources":["../../src/fns/sortFns.ts"],"sourcesContent":["import type { RowData } from '../types/type-utils'\nimport type { TableFeatures } from '../types/TableFeatures'\nimport type { Row } from '../types/Row'\n\n/**\n * Regular expression used to split mixed text and numeric chunks.\n *\n * The alphanumeric sort functions use these chunks for natural sorting of\n * strings like `item2` before `item10`.\n */\nexport const reSplitAlphaNumeric = /([0-9]+)/gm\n\n/**\n * Sorts rows with the built-in alphanumeric strategy.\n *\n * This comparator returns ascending-order results; descending order is applied by the sorting row model.\n */\nexport const sortFn_alphanumeric = <\n TFeatures extends TableFeatures,\n TData extends RowData,\n>(\n rowA: Row<TFeatures, TData>,\n rowB: Row<TFeatures, TData>,\n columnId: string,\n) => {\n return compareAlphanumeric(\n toString(rowA.getValue(columnId)).toLowerCase(),\n toString(rowB.getValue(columnId)).toLowerCase(),\n )\n}\n\n/**\n * Sorts rows with the built-in alphanumeric case sensitive strategy.\n *\n * This comparator returns ascending-order results; descending order is applied by the sorting row model.\n */\nexport const sortFn_alphanumericCaseSensitive = <\n TFeatures extends TableFeatures,\n TData extends RowData,\n>(\n rowA: Row<TFeatures, TData>,\n rowB: Row<TFeatures, TData>,\n columnId: string,\n) => {\n return compareAlphanumeric(\n toString(rowA.getValue(columnId)),\n toString(rowB.getValue(columnId)),\n )\n}\n\n// The text filter is more basic (less numeric support)\n// but is much faster\n/**\n * Sorts rows with the built-in text strategy.\n *\n * This comparator returns ascending-order results; descending order is applied by the sorting row model.\n */\nexport const sortFn_text = <\n TFeatures extends TableFeatures,\n TData extends RowData,\n>(\n rowA: Row<TFeatures, TData>,\n rowB: Row<TFeatures, TData>,\n columnId: string,\n) => {\n return compareBasic(\n toString(rowA.getValue(columnId)).toLowerCase(),\n toString(rowB.getValue(columnId)).toLowerCase(),\n )\n}\n\n// The text filter is more basic (less numeric support)\n// but is much faster\n/**\n * Sorts rows with the built-in text case sensitive strategy.\n *\n * This comparator returns ascending-order results; descending order is applied by the sorting row model.\n */\nexport const sortFn_textCaseSensitive = <\n TFeatures extends TableFeatures,\n TData extends RowData,\n>(\n rowA: Row<TFeatures, TData>,\n rowB: Row<TFeatures, TData>,\n columnId: string,\n) => {\n return compareBasic(\n toString(rowA.getValue(columnId)),\n toString(rowB.getValue(columnId)),\n )\n}\n\n/**\n * Sorts rows with the built-in datetime strategy.\n *\n * This comparator returns ascending-order results; descending order is applied by the sorting row model.\n */\nexport const sortFn_datetime = <\n TFeatures extends TableFeatures,\n TData extends RowData,\n>(\n rowA: Row<TFeatures, TData>,\n rowB: Row<TFeatures, TData>,\n columnId: string,\n) => {\n const a: number | string = rowA.getValue(columnId)\n const b: number | string = rowB.getValue(columnId)\n\n // Can handle nullish values\n // Use > and < because == (and ===) doesn't work with\n // Date objects (would require calling getTime()).\n return a > b ? 1 : a < b ? -1 : 0\n}\n\n/**\n * Sorts rows with the built-in basic strategy.\n *\n * This comparator returns ascending-order results; descending order is applied by the sorting row model.\n */\nexport const sortFn_basic = <\n TFeatures extends TableFeatures,\n TData extends RowData,\n>(\n rowA: Row<TFeatures, TData>,\n rowB: Row<TFeatures, TData>,\n columnId: string,\n) => {\n return compareBasic(rowA.getValue(columnId), rowB.getValue(columnId))\n}\n\n// Utils\n\nfunction compareBasic(a: any, b: any) {\n return a === b ? 0 : a > b ? 1 : -1\n}\n\nfunction toString(a: any) {\n if (typeof a === 'number') {\n if (isNaN(a) || a === Infinity || a === -Infinity) {\n return ''\n }\n return String(a)\n }\n if (typeof a === 'string') {\n return a\n }\n return ''\n}\n\n// Mixed sorting is slow, but very inclusive of many edge cases.\n// It handles numbers, mixed alphanumeric combinations, and even\n// null, undefined, and Infinity\nfunction compareAlphanumeric(aStr: string, bStr: string) {\n const a = aStr.split(reSplitAlphaNumeric)\n const b = bStr.split(reSplitAlphaNumeric)\n\n let ai = 0\n let bi = 0\n const aLen = a.length\n const bLen = b.length\n\n while (ai < aLen && bi < bLen) {\n // Skip the empty boundary chunks that .filter(Boolean) used to remove\n if (!a[ai]) {\n ai++\n continue\n }\n if (!b[bi]) {\n bi++\n continue\n }\n\n const aa = a[ai++]!\n const bb = b[bi++]!\n\n // Chunks are either all-digit (parseInt always succeeds) or digit-free\n // (parseInt is always NaN), so NaN-ness fully classifies each chunk\n const an = parseInt(aa, 10)\n const bn = parseInt(bb, 10)\n\n const aIsNaN = isNaN(an)\n const bIsNaN = isNaN(bn)\n\n // Both are string\n if (aIsNaN && bIsNaN) {\n if (aa > bb) {\n return 1\n }\n if (bb > aa) {\n return -1\n }\n continue\n }\n\n // One is a string, one is a number — the string chunk sorts first\n if (aIsNaN || bIsNaN) {\n return aIsNaN ? -1 : 1\n }\n\n // Both are numbers\n if (an > bn) {\n return 1\n }\n if (bn > an) {\n return -1\n }\n }\n\n // One side is exhausted — compare the counts of remaining non-empty chunks\n let remaining = 0\n for (; ai < aLen; ai++) {\n if (a[ai]) {\n remaining++\n }\n }\n for (; bi < bLen; bi++) {\n if (b[bi]) {\n remaining--\n }\n }\n return remaining\n}\n\n// Exports\n\n/**\n * The built-in sorting function registry.\n *\n * Pass this object to sorted row model creation or extend it with custom sorting functions.\n */\nexport const sortFns = {\n alphanumeric: sortFn_alphanumeric,\n alphanumericCaseSensitive: sortFn_alphanumericCaseSensitive,\n basic: sortFn_basic,\n datetime: sortFn_datetime,\n text: sortFn_text,\n textCaseSensitive: sortFn_textCaseSensitive,\n}\n\nexport type BuiltInSortFn = keyof typeof sortFns\n"],"mappings":";;;;;;;AAUA,MAAa,sBAAsB;;;;;;AAOnC,MAAa,uBAIX,MACA,MACA,aACG;CACH,OAAO,oBACL,SAAS,KAAK,SAAS,QAAQ,CAAC,CAAC,CAAC,YAAY,GAC9C,SAAS,KAAK,SAAS,QAAQ,CAAC,CAAC,CAAC,YAAY,CAChD;AACF;;;;;;AAOA,MAAa,oCAIX,MACA,MACA,aACG;CACH,OAAO,oBACL,SAAS,KAAK,SAAS,QAAQ,CAAC,GAChC,SAAS,KAAK,SAAS,QAAQ,CAAC,CAClC;AACF;;;;;;AASA,MAAa,eAIX,MACA,MACA,aACG;CACH,OAAO,aACL,SAAS,KAAK,SAAS,QAAQ,CAAC,CAAC,CAAC,YAAY,GAC9C,SAAS,KAAK,SAAS,QAAQ,CAAC,CAAC,CAAC,YAAY,CAChD;AACF;;;;;;AASA,MAAa,4BAIX,MACA,MACA,aACG;CACH,OAAO,aACL,SAAS,KAAK,SAAS,QAAQ,CAAC,GAChC,SAAS,KAAK,SAAS,QAAQ,CAAC,CAClC;AACF;;;;;;AAOA,MAAa,mBAIX,MACA,MACA,aACG;CACH,MAAM,IAAqB,KAAK,SAAS,QAAQ;CACjD,MAAM,IAAqB,KAAK,SAAS,QAAQ;CAKjD,OAAO,IAAI,IAAI,IAAI,IAAI,IAAI,KAAK;AAClC;;;;;;AAOA,MAAa,gBAIX,MACA,MACA,aACG;CACH,OAAO,aAAa,KAAK,SAAS,QAAQ,GAAG,KAAK,SAAS,QAAQ,CAAC;AACtE;AAIA,SAAS,aAAa,GAAQ,GAAQ;CACpC,OAAO,MAAM,IAAI,IAAI,IAAI,IAAI,IAAI;AACnC;AAEA,SAAS,SAAS,GAAQ;CACxB,IAAI,OAAO,MAAM,UAAU;EACzB,IAAI,MAAM,CAAC,KAAK,MAAM,YAAY,MAAM,WACtC,OAAO;EAET,OAAO,OAAO,CAAC;CACjB;CACA,IAAI,OAAO,MAAM,UACf,OAAO;CAET,OAAO;AACT;AAKA,SAAS,oBAAoB,MAAc,MAAc;CACvD,MAAM,IAAI,KAAK,MAAM,mBAAmB;CACxC,MAAM,IAAI,KAAK,MAAM,mBAAmB;CAExC,IAAI,KAAK;CACT,IAAI,KAAK;CACT,MAAM,OAAO,EAAE;CACf,MAAM,OAAO,EAAE;CAEf,OAAO,KAAK,QAAQ,KAAK,MAAM;EAE7B,IAAI,CAAC,EAAE,KAAK;GACV;GACA;EACF;EACA,IAAI,CAAC,EAAE,KAAK;GACV;GACA;EACF;EAEA,MAAM,KAAK,EAAE;EACb,MAAM,KAAK,EAAE;EAIb,MAAM,KAAK,SAAS,IAAI,EAAE;EAC1B,MAAM,KAAK,SAAS,IAAI,EAAE;EAE1B,MAAM,SAAS,MAAM,EAAE;EACvB,MAAM,SAAS,MAAM,EAAE;EAGvB,IAAI,UAAU,QAAQ;GACpB,IAAI,KAAK,IACP,OAAO;GAET,IAAI,KAAK,IACP,OAAO;GAET;EACF;EAGA,IAAI,UAAU,QACZ,OAAO,SAAS,KAAK;EAIvB,IAAI,KAAK,IACP,OAAO;EAET,IAAI,KAAK,IACP,OAAO;CAEX;CAGA,IAAI,YAAY;CAChB,OAAO,KAAK,MAAM,MAChB,IAAI,EAAE,KACJ;CAGJ,OAAO,KAAK,MAAM,MAChB,IAAI,EAAE,KACJ;CAGJ,OAAO;AACT;;;;;;AASA,MAAa,UAAU;CACrB,cAAc;CACd,2BAA2B;CAC3B,OAAO;CACP,UAAU;CACV,MAAM;CACN,mBAAmB;AACrB"}
|
package/package.json
CHANGED
|
@@ -89,8 +89,6 @@ export function column_getAutoSortFn<
|
|
|
89
89
|
const sortFns: Record<string, SortFn<TFeatures, TData>> | undefined =
|
|
90
90
|
column.table._rowModelFns.sortFns
|
|
91
91
|
|
|
92
|
-
let sortFn: SortFn<TFeatures, TData> | undefined
|
|
93
|
-
|
|
94
92
|
const firstRows = column.table.getFilteredRowModel().flatRows.slice(0, 10)
|
|
95
93
|
|
|
96
94
|
let isString = false
|
|
@@ -99,23 +97,27 @@ export function column_getAutoSortFn<
|
|
|
99
97
|
const value = firstRows[i]!.getValue(column.id)
|
|
100
98
|
|
|
101
99
|
if (Object.prototype.toString.call(value) === '[object Date]') {
|
|
102
|
-
|
|
100
|
+
if (sortFns?.datetime) {
|
|
101
|
+
return sortFns.datetime
|
|
102
|
+
}
|
|
103
103
|
}
|
|
104
104
|
|
|
105
105
|
if (typeof value === 'string') {
|
|
106
106
|
isString = true
|
|
107
107
|
|
|
108
108
|
if (value.split(reSplitAlphaNumeric).length > 1) {
|
|
109
|
-
|
|
109
|
+
if (sortFns?.alphanumeric) {
|
|
110
|
+
return sortFns.alphanumeric
|
|
111
|
+
}
|
|
110
112
|
}
|
|
111
113
|
}
|
|
112
114
|
}
|
|
113
115
|
|
|
114
116
|
if (isString) {
|
|
115
|
-
|
|
117
|
+
return sortFns?.text ?? sortFn_basic
|
|
116
118
|
}
|
|
117
119
|
|
|
118
|
-
return
|
|
120
|
+
return sortFn_basic
|
|
119
121
|
}
|
|
120
122
|
|
|
121
123
|
/**
|
package/src/fns/sortFns.ts
CHANGED
|
@@ -151,10 +151,8 @@ function toString(a: any) {
|
|
|
151
151
|
// It handles numbers, mixed alphanumeric combinations, and even
|
|
152
152
|
// null, undefined, and Infinity
|
|
153
153
|
function compareAlphanumeric(aStr: string, bStr: string) {
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
const a = aStr.split(reSplitAlphaNumeric).filter(Boolean)
|
|
157
|
-
const b = bStr.split(reSplitAlphaNumeric).filter(Boolean)
|
|
154
|
+
const a = aStr.split(reSplitAlphaNumeric)
|
|
155
|
+
const b = bStr.split(reSplitAlphaNumeric)
|
|
158
156
|
|
|
159
157
|
let ai = 0
|
|
160
158
|
let bi = 0
|
|
@@ -162,16 +160,29 @@ function compareAlphanumeric(aStr: string, bStr: string) {
|
|
|
162
160
|
const bLen = b.length
|
|
163
161
|
|
|
164
162
|
while (ai < aLen && bi < bLen) {
|
|
163
|
+
// Skip the empty boundary chunks that .filter(Boolean) used to remove
|
|
164
|
+
if (!a[ai]) {
|
|
165
|
+
ai++
|
|
166
|
+
continue
|
|
167
|
+
}
|
|
168
|
+
if (!b[bi]) {
|
|
169
|
+
bi++
|
|
170
|
+
continue
|
|
171
|
+
}
|
|
172
|
+
|
|
165
173
|
const aa = a[ai++]!
|
|
166
174
|
const bb = b[bi++]!
|
|
167
175
|
|
|
176
|
+
// Chunks are either all-digit (parseInt always succeeds) or digit-free
|
|
177
|
+
// (parseInt is always NaN), so NaN-ness fully classifies each chunk
|
|
168
178
|
const an = parseInt(aa, 10)
|
|
169
179
|
const bn = parseInt(bb, 10)
|
|
170
180
|
|
|
171
|
-
const
|
|
181
|
+
const aIsNaN = isNaN(an)
|
|
182
|
+
const bIsNaN = isNaN(bn)
|
|
172
183
|
|
|
173
184
|
// Both are string
|
|
174
|
-
if (
|
|
185
|
+
if (aIsNaN && bIsNaN) {
|
|
175
186
|
if (aa > bb) {
|
|
176
187
|
return 1
|
|
177
188
|
}
|
|
@@ -181,9 +192,9 @@ function compareAlphanumeric(aStr: string, bStr: string) {
|
|
|
181
192
|
continue
|
|
182
193
|
}
|
|
183
194
|
|
|
184
|
-
// One is a string, one is a number
|
|
185
|
-
if (
|
|
186
|
-
return
|
|
195
|
+
// One is a string, one is a number — the string chunk sorts first
|
|
196
|
+
if (aIsNaN || bIsNaN) {
|
|
197
|
+
return aIsNaN ? -1 : 1
|
|
187
198
|
}
|
|
188
199
|
|
|
189
200
|
// Both are numbers
|
|
@@ -195,7 +206,19 @@ function compareAlphanumeric(aStr: string, bStr: string) {
|
|
|
195
206
|
}
|
|
196
207
|
}
|
|
197
208
|
|
|
198
|
-
|
|
209
|
+
// One side is exhausted — compare the counts of remaining non-empty chunks
|
|
210
|
+
let remaining = 0
|
|
211
|
+
for (; ai < aLen; ai++) {
|
|
212
|
+
if (a[ai]) {
|
|
213
|
+
remaining++
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
for (; bi < bLen; bi++) {
|
|
217
|
+
if (b[bi]) {
|
|
218
|
+
remaining--
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
return remaining
|
|
199
222
|
}
|
|
200
223
|
|
|
201
224
|
// Exports
|