@tanstack/table-core 9.0.0-beta.33 → 9.0.0-beta.35
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/core/rows/coreRowsFeature.cjs +4 -1
- package/dist/core/rows/coreRowsFeature.cjs.map +1 -1
- package/dist/core/rows/coreRowsFeature.js +4 -1
- package/dist/core/rows/coreRowsFeature.js.map +1 -1
- package/dist/core/rows/coreRowsFeature.types.d.cts +2 -0
- package/dist/core/rows/coreRowsFeature.types.d.ts +2 -0
- package/dist/core/rows/coreRowsFeature.utils.cjs +11 -1
- package/dist/core/rows/coreRowsFeature.utils.cjs.map +1 -1
- package/dist/core/rows/coreRowsFeature.utils.js +11 -1
- package/dist/core/rows/coreRowsFeature.utils.js.map +1 -1
- package/dist/features/column-ordering/columnOrderingFeature.cjs +12 -11
- package/dist/features/column-ordering/columnOrderingFeature.cjs.map +1 -1
- package/dist/features/column-ordering/columnOrderingFeature.js +13 -12
- package/dist/features/column-ordering/columnOrderingFeature.js.map +1 -1
- package/dist/features/column-ordering/columnOrderingFeature.types.d.cts +26 -1
- package/dist/features/column-ordering/columnOrderingFeature.types.d.ts +26 -1
- package/dist/features/column-ordering/columnOrderingFeature.utils.cjs +26 -1
- package/dist/features/column-ordering/columnOrderingFeature.utils.cjs.map +1 -1
- package/dist/features/column-ordering/columnOrderingFeature.utils.d.cts +14 -2
- package/dist/features/column-ordering/columnOrderingFeature.utils.d.ts +14 -2
- package/dist/features/column-ordering/columnOrderingFeature.utils.js +27 -3
- package/dist/features/column-ordering/columnOrderingFeature.utils.js.map +1 -1
- package/dist/features/column-pinning/columnPinningFeature.utils.cjs +10 -6
- package/dist/features/column-pinning/columnPinningFeature.utils.cjs.map +1 -1
- package/dist/features/column-pinning/columnPinningFeature.utils.js +10 -6
- package/dist/features/column-pinning/columnPinningFeature.utils.js.map +1 -1
- package/dist/features/row-selection/rowSelectionFeature.utils.cjs +1 -1
- package/dist/features/row-selection/rowSelectionFeature.utils.cjs.map +1 -1
- package/dist/features/row-selection/rowSelectionFeature.utils.js +2 -2
- package/dist/features/row-selection/rowSelectionFeature.utils.js.map +1 -1
- package/dist/features/row-sorting/createSortedRowModel.cjs +17 -7
- package/dist/features/row-sorting/createSortedRowModel.cjs.map +1 -1
- package/dist/features/row-sorting/createSortedRowModel.js +18 -8
- package/dist/features/row-sorting/createSortedRowModel.js.map +1 -1
- package/dist/features/row-sorting/rowSortingFeature.utils.cjs +1 -1
- package/dist/features/row-sorting/rowSortingFeature.utils.cjs.map +1 -1
- package/dist/features/row-sorting/rowSortingFeature.utils.js +1 -1
- package/dist/features/row-sorting/rowSortingFeature.utils.js.map +1 -1
- package/dist/index.cjs +1 -0
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +2 -2
- package/dist/static-functions.cjs +1 -0
- package/dist/static-functions.d.cts +2 -2
- package/dist/static-functions.d.ts +2 -2
- package/dist/static-functions.js +2 -2
- package/dist/utils.cjs +15 -0
- package/dist/utils.cjs.map +1 -1
- package/dist/utils.d.cts +7 -1
- package/dist/utils.d.ts +7 -1
- package/dist/utils.js +15 -1
- package/dist/utils.js.map +1 -1
- package/package.json +1 -1
- package/src/core/rows/coreRowsFeature.ts +1 -0
- package/src/core/rows/coreRowsFeature.types.ts +5 -0
- package/src/core/rows/coreRowsFeature.utils.ts +13 -1
- package/src/features/column-ordering/columnOrderingFeature.ts +12 -8
- package/src/features/column-ordering/columnOrderingFeature.types.ts +26 -0
- package/src/features/column-ordering/columnOrderingFeature.utils.ts +56 -5
- package/src/features/column-pinning/columnPinningFeature.utils.ts +24 -10
- package/src/features/row-selection/rowSelectionFeature.utils.ts +2 -1
- package/src/features/row-sorting/createSortedRowModel.ts +31 -10
- package/src/features/row-sorting/rowSortingFeature.utils.ts +2 -10
- package/src/utils.ts +22 -0
package/dist/utils.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.js","names":[],"sources":["../src/utils.ts"],"sourcesContent":["import type { Table_Internal } from './types/Table'\nimport type { NoInfer, RowData, Updater } from './types/type-utils'\nimport type { TableFeatures } from './types/TableFeatures'\nimport type { TableState, TableState_All } from './types/TableState'\n\n/**\n * Applies a TanStack updater to a value.\n *\n * If the updater is a function it is called with the previous value; otherwise the updater value is returned directly.\n */\nexport function functionalUpdate<T>(updater: Updater<T>, input: T): T {\n return typeof updater === 'function'\n ? (updater as (i: T) => T)(input)\n : updater\n}\n\n/**\n * Clones table state values while preserving non-plain objects.\n *\n * Plain objects and arrays are copied recursively so state updates can avoid mutating existing references.\n */\nexport function cloneState<T>(value: T): T {\n if (Array.isArray(value)) {\n return value.map(cloneState) as T\n }\n\n if (value && typeof value === 'object') {\n const proto = Object.getPrototypeOf(value)\n\n if (proto !== Object.prototype && proto !== null) {\n return value\n }\n\n const copy: Record<string, unknown> = proto === null ? makeObjectMap() : {}\n const keys = Object.keys(value)\n\n for (let i = 0; i < keys.length; i++) {\n const key = keys[i]!\n Object.defineProperty(copy, key, {\n configurable: true,\n enumerable: true,\n value: cloneState((value as Record<string, unknown>)[key]),\n writable: true,\n })\n }\n\n return copy as T\n }\n\n return value\n}\n\n/**\n * Creates an object intended only for string-keyed dictionary lookups.\n *\n * The null prototype keeps user-controlled ids such as `__proto__` and\n * `hasOwnProperty` as plain data keys.\n */\nexport function makeObjectMap<TValue = unknown>(): Record<string, TValue> {\n return Object.create(null) as Record<string, TValue>\n}\n\n/**\n * Checks whether an object owns a key, including null-prototype dictionaries.\n */\nexport function hasOwn(obj: object, key: PropertyKey): boolean {\n return Object.prototype.hasOwnProperty.call(obj, key)\n}\n\n/**\n * Creates a table state updater for a single state slice.\n *\n * The updater writes through the table base atom for the slice and supports both value and functional updater forms.\n */\nexport function makeStateUpdater<\n TFeatures extends TableFeatures,\n K extends (string & {}) | keyof TableState_All | keyof TableState<TFeatures>,\n>(\n key: K,\n // Minimal structural shape so any table view (public `Table`,\n // `Table_Internal`, or a custom plugin table) can be passed without forcing\n // the compiler to relate the full table types.\n instance: {\n readonly options: { readonly atoms?: object | undefined }\n readonly baseAtoms: object\n },\n) {\n return (updater: Updater<TableState<any>[K & keyof TableState<any>]>) => {\n const externalAtom = (instance.options as any).atoms?.[key]\n const targetAtom = externalAtom ?? (instance.baseAtoms as any)[key]\n targetAtom.set((old: any) => functionalUpdate(updater, old))\n }\n}\n\ntype AnyFunction = (...args: any) => any\n\n/**\n * Returns whether a value is a function.\n */\nexport function isFunction<T extends AnyFunction>(d: any): d is T {\n return d instanceof Function\n}\n\n/**\n * Flattens a tree of nodes by recursively reading child nodes.\n *\n * The original nodes are preserved in depth-first order.\n */\nexport function flattenBy<TNode>(\n arr: Array<TNode>,\n getChildren: (item: TNode) => Array<TNode>,\n) {\n const flat: Array<TNode> = []\n\n const recurse = (subArr: Array<TNode>) => {\n subArr.forEach((item) => {\n flat.push(item)\n const children = getChildren(item)\n if (children.length) {\n recurse(children)\n }\n })\n }\n\n recurse(arr)\n\n return flat\n}\n\ninterface MemoOptions<TDeps extends ReadonlyArray<any>, TDepArgs, TResult> {\n fn: (...args: NoInfer<TDeps>) => TResult\n memoDeps?: (depArgs?: TDepArgs) => [...TDeps] | undefined\n onAfterCompare?: (depsChanged: boolean) => void\n onAfterUpdate?: (result: TResult) => void\n onBeforeCompare?: () => void\n onBeforeUpdate?: () => void\n}\n\n/**\n * Creates a dependency-tracked memoized function for table internals.\n *\n * The memo recomputes only when its dependency tuple changes and can emit debug timing information.\n */\nexport const memo = <TDeps extends ReadonlyArray<any>, TDepArgs, TResult>({\n fn,\n memoDeps,\n onAfterCompare,\n onAfterUpdate,\n onBeforeCompare,\n onBeforeUpdate,\n}: MemoOptions<TDeps, TDepArgs, TResult>): ((\n depArgs?: TDepArgs,\n) => TResult) => {\n let deps: Array<any> | undefined = []\n let result: TResult | undefined\n\n const memoizedFn = (depArgs?: TDepArgs): TResult => {\n onBeforeCompare?.()\n const newDeps = memoDeps?.(depArgs)\n let depsChanged = !newDeps || newDeps.length !== deps?.length\n if (!depsChanged && newDeps) {\n for (let i = 0; i < newDeps.length; i++) {\n if (newDeps[i] !== deps![i]) {\n depsChanged = true\n break\n }\n }\n }\n onAfterCompare?.(depsChanged)\n\n if (!depsChanged) {\n return result!\n }\n\n deps = newDeps\n\n onBeforeUpdate?.()\n result = fn(...(newDeps ?? ([] as any)))\n onAfterUpdate?.(result)\n\n return result\n }\n\n return memoizedFn\n}\n\ninterface TableMemoOptions<\n TFeatures extends TableFeatures,\n TDeps extends ReadonlyArray<any>,\n TDepArgs,\n TResult,\n> extends MemoOptions<TDeps, TDepArgs, TResult> {\n feature?: keyof TFeatures & string\n fnName: string\n objectId?: string\n onAfterUpdate?: () => void\n table: Table_Internal<TFeatures, any>\n}\n\nconst pad = (str: number | string, num: number) => {\n str = String(str)\n while (str.length < num) {\n str = ' ' + str\n }\n return str\n}\n\n/**\n * Creates a table-aware memoized function.\n *\n * This wraps `memo` with table debug options and feature metadata so row models and derived APIs can share consistent diagnostics.\n */\nexport function tableMemo<\n TFeatures extends TableFeatures,\n TDeps extends ReadonlyArray<any>,\n TDepArgs,\n TResult,\n>({\n feature,\n fnName,\n objectId,\n onAfterUpdate,\n table,\n ...memoOptions\n}: TableMemoOptions<TFeatures, TDeps, TDepArgs, TResult>) {\n let beforeCompareTime: number\n let afterCompareTime: number\n let startCalcTime: number\n let endCalcTime: number\n let runCount = 0\n let debug: boolean | undefined\n let debugCache: boolean | undefined\n\n if (process.env.NODE_ENV === 'development') {\n const { debugCache: _debugCache, debugAll } = table.options\n debugCache = _debugCache\n const { parentName } = getFunctionNameInfo(fnName, '.')\n\n const debugByParent =\n // @ts-expect-error\n table.options[\n `debug${(parentName != 'table' ? parentName + 's' : parentName).replace(\n parentName,\n parentName.charAt(0).toUpperCase() + parentName.slice(1),\n )}`\n ]\n const debugByFeature = feature\n ? // @ts-expect-error\n table.options[\n `debug${feature.charAt(0).toUpperCase() + feature.slice(1)}`\n ]\n : false\n\n debug = debugAll || debugByParent || debugByFeature\n }\n\n function logTime(time: number, depsChanged: boolean) {\n const runType =\n runCount === 0\n ? '(1st run)'\n : depsChanged\n ? '(rerun #' + runCount + ')'\n : '(cache)'\n runCount++\n\n console.groupCollapsed(\n `%c⏱ ${pad(`${time.toFixed(1)} ms`, 12)} %c${runType}%c ${fnName}%c ${objectId ? `(${fnName.split('.')[0]}Id: ${objectId})` : ''}`,\n `font-size: .6rem; font-weight: bold; ${\n depsChanged\n ? `color: hsl(\n ${Math.max(0, Math.min(120 - Math.log10(time) * 60, 120))}deg 100% 31%);`\n : ''\n } `,\n `color: ${runCount < 2 ? '#FF00FF' : '#FF1493'}`,\n 'color: #666',\n 'color: #87CEEB',\n )\n console.info({\n feature,\n state: table.store.state,\n deps: memoOptions.memoDeps?.toString(),\n })\n console.trace()\n console.groupEnd()\n }\n\n const onAfterUpdateHandler = () => {\n if (!onAfterUpdate) {\n return\n }\n\n const { schedule, untrack } = table._reactivity\n schedule(() => untrack(() => onAfterUpdate()))\n }\n\n const debugOptions =\n process.env.NODE_ENV === 'development'\n ? {\n onBeforeCompare: () => {\n if (debugCache) {\n beforeCompareTime = performance.now()\n }\n },\n onAfterCompare: (depsChanged: boolean) => {\n if (debugCache) {\n afterCompareTime = performance.now()\n const compareTime =\n Math.round((afterCompareTime - beforeCompareTime) * 100) / 100\n if (!depsChanged) {\n logTime(compareTime, depsChanged)\n }\n }\n },\n onBeforeUpdate: () => {\n if (debug) {\n startCalcTime = performance.now()\n }\n },\n onAfterUpdate: () => {\n if (debug) {\n endCalcTime = performance.now()\n const executionTime =\n Math.round((endCalcTime - startCalcTime) * 100) / 100\n logTime(executionTime, true)\n }\n onAfterUpdateHandler()\n },\n }\n : {\n onAfterUpdate: () => {\n onAfterUpdateHandler()\n },\n }\n\n return memo({\n ...memoOptions,\n ...debugOptions,\n })\n}\n\nexport interface API<TDeps extends ReadonlyArray<any>, TDepArgs> {\n fn: (...args: any) => any\n memoDeps?: (depArgs?: any) => [...any] | undefined\n}\n\nexport type APIObject<TDeps extends ReadonlyArray<any>, TDepArgs> = Record<\n string,\n API<TDeps, TDepArgs>\n>\n\n/**\n * Assumes that a function name is in the format of `parentName_fnKey` and returns the `fnKey` and `fnName` in the format of `parentName.fnKey`.\n */\nexport function getFunctionNameInfo(\n staticFnName: string,\n splitBy: '_' | '.' = '_',\n) {\n const [parentName, fnKey] = staticFnName.split(splitBy)\n const fnName = `${parentName}.${fnKey}`\n return { fnKey, fnName, parentName } as {\n fnKey: string\n fnName: string\n parentName: string\n }\n}\n\n/**\n * Assigns Table API methods directly to the table instance.\n * Unlike row/cell/column/header, the table is a singleton so methods are assigned directly.\n */\nexport function assignTableAPIs<\n TFeatures extends TableFeatures,\n TData extends RowData,\n TDeps extends ReadonlyArray<any>,\n TDepArgs,\n>(\n feature: keyof TFeatures & string,\n table: Table_Internal<TFeatures, TData>,\n apis: APIObject<TDeps, NoInfer<TDepArgs>>,\n): void {\n for (const [staticFnName, { fn, memoDeps }] of Object.entries(apis)) {\n const { fnKey, fnName } = getFunctionNameInfo(staticFnName)\n\n ;(table as Record<string, any>)[fnKey] = memoDeps\n ? tableMemo({\n memoDeps,\n fn,\n fnName,\n table,\n feature,\n })\n : fn\n }\n}\n\nexport interface PrototypeAPI<TDeps extends ReadonlyArray<any>, TDepArgs> {\n fn: (self: any, ...args: any) => any\n memoDeps?: (self: any, depArgs?: any) => [...any] | undefined\n}\n\nexport type PrototypeAPIObject<\n TDeps extends ReadonlyArray<any>,\n TDepArgs,\n> = Record<string, PrototypeAPI<TDeps, TDepArgs>>\n\n/**\n * Assigns API methods to a prototype object for memory-efficient method sharing.\n * All instances created with this prototype will share the same method references.\n *\n * For memoized methods, the memo state is lazily created and stored on each instance.\n * This provides the best of both worlds: shared method code + per-instance caching.\n */\nexport function assignPrototypeAPIs<\n TFeatures extends TableFeatures,\n TData extends RowData,\n TDeps extends ReadonlyArray<any>,\n TDepArgs,\n>(\n feature: keyof TFeatures & string,\n prototype: Record<string, any>,\n table: Table_Internal<TFeatures, TData>,\n apis: PrototypeAPIObject<TDeps, NoInfer<TDepArgs>>,\n): void {\n for (const [staticFnName, { fn, memoDeps }] of Object.entries(apis)) {\n const { fnKey, fnName } = getFunctionNameInfo(staticFnName)\n\n if (memoDeps) {\n // For memoized methods, create a function that lazily initializes\n // the memo on first access and stores it on the instance\n const memoKey = `_memo_${fnKey}`\n\n prototype[fnKey] = function (this: any, ...args: Array<any>) {\n // Lazily create memo on first access for this instance\n if (!this[memoKey]) {\n const self = this\n this[memoKey] = tableMemo({\n memoDeps: (depArgs) => memoDeps(self, depArgs),\n fn: (...deps) => fn(self, ...deps),\n fnName,\n objectId: self.id,\n table,\n feature,\n })\n }\n return this[memoKey](...args)\n }\n } else {\n // Non-memoized methods just call the static function with `this`\n prototype[fnKey] = function (this: any, ...args: Array<any>) {\n return fn(this, ...args)\n }\n }\n }\n}\n\n/**\n * Looks to run the memoized function with the builder pattern on the object if it exists, otherwise fallback to the static method passed in.\n */\nexport function callMemoOrStaticFn<\n TObject extends Record<string, any>,\n TArgs extends Array<any>,\n TReturn,\n>(\n obj: TObject,\n fnKey: string,\n staticFn: (obj: TObject, ...args: TArgs) => TReturn,\n ...args: TArgs\n): TReturn {\n return (\n (obj[fnKey] as Function | undefined)?.(...args) ?? staticFn(obj, ...args)\n )\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"utils.js","names":[],"sources":["../src/utils.ts"],"sourcesContent":["import type { Table_Internal } from './types/Table'\nimport type { NoInfer, RowData, Updater } from './types/type-utils'\nimport type { TableFeatures } from './types/TableFeatures'\nimport type { TableState, TableState_All } from './types/TableState'\n\n/**\n * Applies a TanStack updater to a value.\n *\n * If the updater is a function it is called with the previous value; otherwise the updater value is returned directly.\n */\nexport function functionalUpdate<T>(updater: Updater<T>, input: T): T {\n return typeof updater === 'function'\n ? (updater as (i: T) => T)(input)\n : updater\n}\n\n/**\n * Clones table state values while preserving non-plain objects.\n *\n * Plain objects and arrays are copied recursively so state updates can avoid mutating existing references.\n */\nexport function cloneState<T>(value: T): T {\n if (Array.isArray(value)) {\n return value.map(cloneState) as T\n }\n\n if (value && typeof value === 'object') {\n const proto = Object.getPrototypeOf(value)\n\n if (proto !== Object.prototype && proto !== null) {\n return value\n }\n\n const copy: Record<string, unknown> = proto === null ? makeObjectMap() : {}\n const keys = Object.keys(value)\n\n for (let i = 0; i < keys.length; i++) {\n const key = keys[i]!\n Object.defineProperty(copy, key, {\n configurable: true,\n enumerable: true,\n value: cloneState((value as Record<string, unknown>)[key]),\n writable: true,\n })\n }\n\n return copy as T\n }\n\n return value\n}\n\n/**\n * Copies prototype-instance own properties without carrying over lazy memo\n * closures or the per-row cell cache, both of which are bound to the source\n * instance (cached cells reference the source row).\n */\nexport function copyInstancePropertiesWithoutMemos<\n TTarget extends Record<string, any>,\n TSource extends Record<string, any>,\n>(target: TTarget, source: TSource): TTarget & TSource {\n const keys = Object.keys(source)\n const targetRecord = target as Record<string, any>\n\n for (let i = 0; i < keys.length; i++) {\n const key = keys[i]!\n if (!key.startsWith('_memo_') && key !== '_cellsCache') {\n targetRecord[key] = source[key]\n }\n }\n\n return target as TTarget & TSource\n}\n\n/**\n * Creates an object intended only for string-keyed dictionary lookups.\n *\n * The null prototype keeps user-controlled ids such as `__proto__` and\n * `hasOwnProperty` as plain data keys.\n */\nexport function makeObjectMap<TValue = unknown>(): Record<string, TValue> {\n return Object.create(null) as Record<string, TValue>\n}\n\n/**\n * Checks whether an object owns a key, including null-prototype dictionaries.\n */\nexport function hasOwn(obj: object, key: PropertyKey): boolean {\n return Object.prototype.hasOwnProperty.call(obj, key)\n}\n\n/**\n * Creates a table state updater for a single state slice.\n *\n * The updater writes through the table base atom for the slice and supports both value and functional updater forms.\n */\nexport function makeStateUpdater<\n TFeatures extends TableFeatures,\n K extends (string & {}) | keyof TableState_All | keyof TableState<TFeatures>,\n>(\n key: K,\n // Minimal structural shape so any table view (public `Table`,\n // `Table_Internal`, or a custom plugin table) can be passed without forcing\n // the compiler to relate the full table types.\n instance: {\n readonly options: { readonly atoms?: object | undefined }\n readonly baseAtoms: object\n },\n) {\n return (updater: Updater<TableState<any>[K & keyof TableState<any>]>) => {\n const externalAtom = (instance.options as any).atoms?.[key]\n const targetAtom = externalAtom ?? (instance.baseAtoms as any)[key]\n targetAtom.set((old: any) => functionalUpdate(updater, old))\n }\n}\n\ntype AnyFunction = (...args: any) => any\n\n/**\n * Returns whether a value is a function.\n */\nexport function isFunction<T extends AnyFunction>(d: any): d is T {\n return d instanceof Function\n}\n\n/**\n * Flattens a tree of nodes by recursively reading child nodes.\n *\n * The original nodes are preserved in depth-first order.\n */\nexport function flattenBy<TNode>(\n arr: Array<TNode>,\n getChildren: (item: TNode) => Array<TNode>,\n) {\n const flat: Array<TNode> = []\n\n const recurse = (subArr: Array<TNode>) => {\n subArr.forEach((item) => {\n flat.push(item)\n const children = getChildren(item)\n if (children.length) {\n recurse(children)\n }\n })\n }\n\n recurse(arr)\n\n return flat\n}\n\ninterface MemoOptions<TDeps extends ReadonlyArray<any>, TDepArgs, TResult> {\n fn: (...args: NoInfer<TDeps>) => TResult\n memoDeps?: (depArgs?: TDepArgs) => [...TDeps] | undefined\n onAfterCompare?: (depsChanged: boolean) => void\n onAfterUpdate?: (result: TResult) => void\n onBeforeCompare?: () => void\n onBeforeUpdate?: () => void\n}\n\n/**\n * Creates a dependency-tracked memoized function for table internals.\n *\n * The memo recomputes only when its dependency tuple changes and can emit debug timing information.\n */\nexport const memo = <TDeps extends ReadonlyArray<any>, TDepArgs, TResult>({\n fn,\n memoDeps,\n onAfterCompare,\n onAfterUpdate,\n onBeforeCompare,\n onBeforeUpdate,\n}: MemoOptions<TDeps, TDepArgs, TResult>): ((\n depArgs?: TDepArgs,\n) => TResult) => {\n let deps: Array<any> | undefined = []\n let result: TResult | undefined\n\n const memoizedFn = (depArgs?: TDepArgs): TResult => {\n onBeforeCompare?.()\n const newDeps = memoDeps?.(depArgs)\n let depsChanged = !newDeps || newDeps.length !== deps?.length\n if (!depsChanged && newDeps) {\n for (let i = 0; i < newDeps.length; i++) {\n if (newDeps[i] !== deps![i]) {\n depsChanged = true\n break\n }\n }\n }\n onAfterCompare?.(depsChanged)\n\n if (!depsChanged) {\n return result!\n }\n\n deps = newDeps\n\n onBeforeUpdate?.()\n result = fn(...(newDeps ?? ([] as any)))\n onAfterUpdate?.(result)\n\n return result\n }\n\n return memoizedFn\n}\n\ninterface TableMemoOptions<\n TFeatures extends TableFeatures,\n TDeps extends ReadonlyArray<any>,\n TDepArgs,\n TResult,\n> extends MemoOptions<TDeps, TDepArgs, TResult> {\n feature?: keyof TFeatures & string\n fnName: string\n objectId?: string\n onAfterUpdate?: () => void\n table: Table_Internal<TFeatures, any>\n}\n\nconst pad = (str: number | string, num: number) => {\n str = String(str)\n while (str.length < num) {\n str = ' ' + str\n }\n return str\n}\n\n/**\n * Creates a table-aware memoized function.\n *\n * This wraps `memo` with table debug options and feature metadata so row models and derived APIs can share consistent diagnostics.\n */\nexport function tableMemo<\n TFeatures extends TableFeatures,\n TDeps extends ReadonlyArray<any>,\n TDepArgs,\n TResult,\n>({\n feature,\n fnName,\n objectId,\n onAfterUpdate,\n table,\n ...memoOptions\n}: TableMemoOptions<TFeatures, TDeps, TDepArgs, TResult>) {\n let beforeCompareTime: number\n let afterCompareTime: number\n let startCalcTime: number\n let endCalcTime: number\n let runCount = 0\n let debug: boolean | undefined\n let debugCache: boolean | undefined\n\n if (process.env.NODE_ENV === 'development') {\n const { debugCache: _debugCache, debugAll } = table.options\n debugCache = _debugCache\n const { parentName } = getFunctionNameInfo(fnName, '.')\n\n const debugByParent =\n // @ts-expect-error\n table.options[\n `debug${(parentName != 'table' ? parentName + 's' : parentName).replace(\n parentName,\n parentName.charAt(0).toUpperCase() + parentName.slice(1),\n )}`\n ]\n const debugByFeature = feature\n ? // @ts-expect-error\n table.options[\n `debug${feature.charAt(0).toUpperCase() + feature.slice(1)}`\n ]\n : false\n\n debug = debugAll || debugByParent || debugByFeature\n }\n\n function logTime(time: number, depsChanged: boolean) {\n const runType =\n runCount === 0\n ? '(1st run)'\n : depsChanged\n ? '(rerun #' + runCount + ')'\n : '(cache)'\n runCount++\n\n console.groupCollapsed(\n `%c⏱ ${pad(`${time.toFixed(1)} ms`, 12)} %c${runType}%c ${fnName}%c ${objectId ? `(${fnName.split('.')[0]}Id: ${objectId})` : ''}`,\n `font-size: .6rem; font-weight: bold; ${\n depsChanged\n ? `color: hsl(\n ${Math.max(0, Math.min(120 - Math.log10(time) * 60, 120))}deg 100% 31%);`\n : ''\n } `,\n `color: ${runCount < 2 ? '#FF00FF' : '#FF1493'}`,\n 'color: #666',\n 'color: #87CEEB',\n )\n console.info({\n feature,\n state: table.store.state,\n deps: memoOptions.memoDeps?.toString(),\n })\n console.trace()\n console.groupEnd()\n }\n\n const onAfterUpdateHandler = () => {\n if (!onAfterUpdate) {\n return\n }\n\n const { schedule, untrack } = table._reactivity\n schedule(() => untrack(() => onAfterUpdate()))\n }\n\n const debugOptions =\n process.env.NODE_ENV === 'development'\n ? {\n onBeforeCompare: () => {\n if (debugCache) {\n beforeCompareTime = performance.now()\n }\n },\n onAfterCompare: (depsChanged: boolean) => {\n if (debugCache) {\n afterCompareTime = performance.now()\n const compareTime =\n Math.round((afterCompareTime - beforeCompareTime) * 100) / 100\n if (!depsChanged) {\n logTime(compareTime, depsChanged)\n }\n }\n },\n onBeforeUpdate: () => {\n if (debug) {\n startCalcTime = performance.now()\n }\n },\n onAfterUpdate: () => {\n if (debug) {\n endCalcTime = performance.now()\n const executionTime =\n Math.round((endCalcTime - startCalcTime) * 100) / 100\n logTime(executionTime, true)\n }\n onAfterUpdateHandler()\n },\n }\n : {\n onAfterUpdate: () => {\n onAfterUpdateHandler()\n },\n }\n\n return memo({\n ...memoOptions,\n ...debugOptions,\n })\n}\n\nexport interface API<TDeps extends ReadonlyArray<any>, TDepArgs> {\n fn: (...args: any) => any\n memoDeps?: (depArgs?: any) => [...any] | undefined\n}\n\nexport type APIObject<TDeps extends ReadonlyArray<any>, TDepArgs> = Record<\n string,\n API<TDeps, TDepArgs>\n>\n\n/**\n * Assumes that a function name is in the format of `parentName_fnKey` and returns the `fnKey` and `fnName` in the format of `parentName.fnKey`.\n */\nexport function getFunctionNameInfo(\n staticFnName: string,\n splitBy: '_' | '.' = '_',\n) {\n const [parentName, fnKey] = staticFnName.split(splitBy)\n const fnName = `${parentName}.${fnKey}`\n return { fnKey, fnName, parentName } as {\n fnKey: string\n fnName: string\n parentName: string\n }\n}\n\n/**\n * Assigns Table API methods directly to the table instance.\n * Unlike row/cell/column/header, the table is a singleton so methods are assigned directly.\n */\nexport function assignTableAPIs<\n TFeatures extends TableFeatures,\n TData extends RowData,\n TDeps extends ReadonlyArray<any>,\n TDepArgs,\n>(\n feature: keyof TFeatures & string,\n table: Table_Internal<TFeatures, TData>,\n apis: APIObject<TDeps, NoInfer<TDepArgs>>,\n): void {\n for (const [staticFnName, { fn, memoDeps }] of Object.entries(apis)) {\n const { fnKey, fnName } = getFunctionNameInfo(staticFnName)\n\n ;(table as Record<string, any>)[fnKey] = memoDeps\n ? tableMemo({\n memoDeps,\n fn,\n fnName,\n table,\n feature,\n })\n : fn\n }\n}\n\nexport interface PrototypeAPI<TDeps extends ReadonlyArray<any>, TDepArgs> {\n fn: (self: any, ...args: any) => any\n memoDeps?: (self: any, depArgs?: any) => [...any] | undefined\n}\n\nexport type PrototypeAPIObject<\n TDeps extends ReadonlyArray<any>,\n TDepArgs,\n> = Record<string, PrototypeAPI<TDeps, TDepArgs>>\n\n/**\n * Assigns API methods to a prototype object for memory-efficient method sharing.\n * All instances created with this prototype will share the same method references.\n *\n * For memoized methods, the memo state is lazily created and stored on each instance.\n * This provides the best of both worlds: shared method code + per-instance caching.\n */\nexport function assignPrototypeAPIs<\n TFeatures extends TableFeatures,\n TData extends RowData,\n TDeps extends ReadonlyArray<any>,\n TDepArgs,\n>(\n feature: keyof TFeatures & string,\n prototype: Record<string, any>,\n table: Table_Internal<TFeatures, TData>,\n apis: PrototypeAPIObject<TDeps, NoInfer<TDepArgs>>,\n): void {\n for (const [staticFnName, { fn, memoDeps }] of Object.entries(apis)) {\n const { fnKey, fnName } = getFunctionNameInfo(staticFnName)\n\n if (memoDeps) {\n // For memoized methods, create a function that lazily initializes\n // the memo on first access and stores it on the instance\n const memoKey = `_memo_${fnKey}`\n\n prototype[fnKey] = function (this: any, ...args: Array<any>) {\n // Lazily create memo on first access for this instance\n if (!this[memoKey]) {\n const self = this\n this[memoKey] = tableMemo({\n memoDeps: (depArgs) => memoDeps(self, depArgs),\n fn: (...deps) => fn(self, ...deps),\n fnName,\n objectId: self.id,\n table,\n feature,\n })\n }\n return this[memoKey](...args)\n }\n } else {\n // Non-memoized methods just call the static function with `this`\n prototype[fnKey] = function (this: any, ...args: Array<any>) {\n return fn(this, ...args)\n }\n }\n }\n}\n\n/**\n * Looks to run the memoized function with the builder pattern on the object if it exists, otherwise fallback to the static method passed in.\n */\nexport function callMemoOrStaticFn<\n TObject extends Record<string, any>,\n TArgs extends Array<any>,\n TReturn,\n>(\n obj: TObject,\n fnKey: string,\n staticFn: (obj: TObject, ...args: TArgs) => TReturn,\n ...args: TArgs\n): TReturn {\n return (\n (obj[fnKey] as Function | undefined)?.(...args) ?? staticFn(obj, ...args)\n )\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -3,11 +3,16 @@ import type { RowData } from '../../types/type-utils'
|
|
|
3
3
|
import type { TableFeatures } from '../../types/TableFeatures'
|
|
4
4
|
import type { Row } from '../../types/Row'
|
|
5
5
|
import type { Cell } from '../../types/Cell'
|
|
6
|
+
import type { Column } from '../../types/Column'
|
|
6
7
|
|
|
7
8
|
export interface Row_CoreProperties<
|
|
8
9
|
in out TFeatures extends TableFeatures,
|
|
9
10
|
in out TData extends RowData,
|
|
10
11
|
> {
|
|
12
|
+
_cellsCache?: WeakMap<
|
|
13
|
+
Column<TFeatures, TData, unknown>,
|
|
14
|
+
Cell<TFeatures, TData, unknown>
|
|
15
|
+
>
|
|
11
16
|
_uniqueValuesCache: Record<string, unknown>
|
|
12
17
|
_valuesCache: Record<string, unknown>
|
|
13
18
|
/**
|
|
@@ -169,11 +169,23 @@ export function row_getAllCells<
|
|
|
169
169
|
TData extends RowData,
|
|
170
170
|
>(row: Row<TFeatures, TData>): Array<Cell<TFeatures, TData, unknown>> {
|
|
171
171
|
const columns = row.table.getAllLeafColumns()
|
|
172
|
+
// WeakMap so cells keyed by replaced column instances can be collected;
|
|
173
|
+
// rows are memoized on data only and outlive column generations
|
|
174
|
+
let cache = row._cellsCache
|
|
175
|
+
if (!cache) {
|
|
176
|
+
cache = row._cellsCache = new WeakMap()
|
|
177
|
+
}
|
|
172
178
|
const cells: Array<Cell<TFeatures, TData, unknown>> = new Array(
|
|
173
179
|
columns.length,
|
|
174
180
|
)
|
|
175
181
|
for (let i = 0; i < columns.length; i++) {
|
|
176
|
-
|
|
182
|
+
const column = columns[i]!
|
|
183
|
+
let cell = cache.get(column)
|
|
184
|
+
if (!cell) {
|
|
185
|
+
cell = constructCell(column, row, row.table)
|
|
186
|
+
cache.set(column, cell)
|
|
187
|
+
}
|
|
188
|
+
cells[i] = cell
|
|
177
189
|
}
|
|
178
190
|
return cells
|
|
179
191
|
}
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
column_getIsFirstColumn,
|
|
9
9
|
column_getIsLastColumn,
|
|
10
10
|
getDefaultColumnOrderState,
|
|
11
|
+
table_getColumnIndexes,
|
|
11
12
|
table_getOrderColumnsFn,
|
|
12
13
|
table_resetColumnOrder,
|
|
13
14
|
table_setColumnOrder,
|
|
@@ -35,14 +36,6 @@ export const columnOrderingFeature: TableFeature = {
|
|
|
35
36
|
assignPrototypeAPIs('columnOrderingFeature', prototype, table, {
|
|
36
37
|
column_getIndex: {
|
|
37
38
|
fn: (column, position) => column_getIndex(column, position),
|
|
38
|
-
memoDeps: (column, position) => [
|
|
39
|
-
position,
|
|
40
|
-
column.table.atoms.columnOrder?.get(),
|
|
41
|
-
column.table.atoms.columnPinning?.get(),
|
|
42
|
-
column.table.atoms.grouping?.get(),
|
|
43
|
-
column.table.atoms.columnVisibility?.get(),
|
|
44
|
-
column.table.options.groupedColumnMode,
|
|
45
|
-
],
|
|
46
39
|
},
|
|
47
40
|
column_getIsFirstColumn: {
|
|
48
41
|
fn: (column, position) => column_getIsFirstColumn(column, position),
|
|
@@ -55,6 +48,17 @@ export const columnOrderingFeature: TableFeature = {
|
|
|
55
48
|
|
|
56
49
|
constructTableAPIs: (table) => {
|
|
57
50
|
assignTableAPIs('columnOrderingFeature', table, {
|
|
51
|
+
table_getColumnIndexes: {
|
|
52
|
+
fn: () => table_getColumnIndexes(table),
|
|
53
|
+
memoDeps: () => [
|
|
54
|
+
table.options.columns,
|
|
55
|
+
table.atoms.columnOrder?.get(),
|
|
56
|
+
table.atoms.columnPinning?.get(),
|
|
57
|
+
table.atoms.columnVisibility?.get(),
|
|
58
|
+
table.atoms.grouping?.get(),
|
|
59
|
+
table.options.groupedColumnMode,
|
|
60
|
+
],
|
|
61
|
+
},
|
|
58
62
|
table_setColumnOrder: {
|
|
59
63
|
fn: (updater) => table_setColumnOrder(table, updater),
|
|
60
64
|
},
|
|
@@ -4,6 +4,25 @@ import type { ColumnPinningPosition } from '../column-pinning/columnPinningFeatu
|
|
|
4
4
|
|
|
5
5
|
export type ColumnOrderState = Array<string>
|
|
6
6
|
|
|
7
|
+
export interface ColumnIndexes {
|
|
8
|
+
/**
|
|
9
|
+
* Maps each visible leaf column id to its index in the full visible column list.
|
|
10
|
+
*/
|
|
11
|
+
all: Record<string, number>
|
|
12
|
+
/**
|
|
13
|
+
* Maps each unpinned visible leaf column id to its index within the center region.
|
|
14
|
+
*/
|
|
15
|
+
center: Record<string, number>
|
|
16
|
+
/**
|
|
17
|
+
* Maps each left-pinned visible leaf column id to its index within the left region.
|
|
18
|
+
*/
|
|
19
|
+
left: Record<string, number>
|
|
20
|
+
/**
|
|
21
|
+
* Maps each right-pinned visible leaf column id to its index within the right region.
|
|
22
|
+
*/
|
|
23
|
+
right: Record<string, number>
|
|
24
|
+
}
|
|
25
|
+
|
|
7
26
|
export interface TableState_ColumnOrdering {
|
|
8
27
|
columnOrder: ColumnOrderState
|
|
9
28
|
}
|
|
@@ -47,6 +66,13 @@ export interface Table_ColumnOrdering<
|
|
|
47
66
|
in out TFeatures extends TableFeatures,
|
|
48
67
|
in out TData extends RowData,
|
|
49
68
|
> {
|
|
69
|
+
/**
|
|
70
|
+
* Builds column-id to index records for each visible pinning region.
|
|
71
|
+
*
|
|
72
|
+
* This is the memoized source that `column.getIndex` reads from; most apps
|
|
73
|
+
* will not need to call it directly.
|
|
74
|
+
*/
|
|
75
|
+
getColumnIndexes: () => ColumnIndexes
|
|
50
76
|
/**
|
|
51
77
|
* Resets `columnOrder` to `initialState.columnOrder`.
|
|
52
78
|
*
|
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
import { table_getPinnedVisibleLeafColumns } from '../column-pinning/columnPinningFeature.utils'
|
|
2
|
-
import { cloneState } from '../../utils'
|
|
2
|
+
import { callMemoOrStaticFn, cloneState, makeObjectMap } from '../../utils'
|
|
3
3
|
import type { GroupingState } from '../column-grouping/columnGroupingFeature.types'
|
|
4
4
|
import type { CellData, RowData, Updater } from '../../types/type-utils'
|
|
5
5
|
import type { TableFeatures } from '../../types/TableFeatures'
|
|
6
6
|
import type { Table_Internal } from '../../types/Table'
|
|
7
|
-
import type { Column_Internal } from '../../types/Column'
|
|
7
|
+
import type { Column, Column_Internal } from '../../types/Column'
|
|
8
8
|
import type { ColumnPinningPosition } from '../column-pinning/columnPinningFeature.types'
|
|
9
|
-
import type {
|
|
9
|
+
import type {
|
|
10
|
+
ColumnIndexes,
|
|
11
|
+
ColumnOrderState,
|
|
12
|
+
} from './columnOrderingFeature.types'
|
|
10
13
|
|
|
11
14
|
/**
|
|
12
15
|
* Creates the default column order state.
|
|
@@ -23,6 +26,42 @@ export function getDefaultColumnOrderState(): ColumnOrderState {
|
|
|
23
26
|
return []
|
|
24
27
|
}
|
|
25
28
|
|
|
29
|
+
/**
|
|
30
|
+
* Builds column-id to index records for each visible pinning region.
|
|
31
|
+
*
|
|
32
|
+
* All four regions are built in one pass so a single memo entry serves every
|
|
33
|
+
* `column_getIndex` lookup without per-column scans.
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```ts
|
|
37
|
+
* const indexes = table_getColumnIndexes(table)
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
export function table_getColumnIndexes<
|
|
41
|
+
TFeatures extends TableFeatures,
|
|
42
|
+
TData extends RowData,
|
|
43
|
+
>(table: Table_Internal<TFeatures, TData>): ColumnIndexes {
|
|
44
|
+
const buildIndexes = (
|
|
45
|
+
columns: ReadonlyArray<
|
|
46
|
+
| Column<TFeatures, TData, unknown>
|
|
47
|
+
| Column_Internal<TFeatures, TData, unknown>
|
|
48
|
+
>,
|
|
49
|
+
): Record<string, number> => {
|
|
50
|
+
const indexes = makeObjectMap<number>()
|
|
51
|
+
for (let i = 0; i < columns.length; i++) {
|
|
52
|
+
indexes[columns[i]!.id] = i
|
|
53
|
+
}
|
|
54
|
+
return indexes
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return {
|
|
58
|
+
all: buildIndexes(table_getPinnedVisibleLeafColumns(table)),
|
|
59
|
+
center: buildIndexes(table_getPinnedVisibleLeafColumns(table, 'center')),
|
|
60
|
+
left: buildIndexes(table_getPinnedVisibleLeafColumns(table, 'left')),
|
|
61
|
+
right: buildIndexes(table_getPinnedVisibleLeafColumns(table, 'right')),
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
26
65
|
/**
|
|
27
66
|
* Finds this column's index within a visible pinning region.
|
|
28
67
|
*
|
|
@@ -42,8 +81,20 @@ export function column_getIndex<
|
|
|
42
81
|
column: Column_Internal<TFeatures, TData, TValue>,
|
|
43
82
|
position?: ColumnPinningPosition | 'center',
|
|
44
83
|
) {
|
|
45
|
-
const
|
|
46
|
-
|
|
84
|
+
const indexes = callMemoOrStaticFn(
|
|
85
|
+
column.table,
|
|
86
|
+
'getColumnIndexes',
|
|
87
|
+
table_getColumnIndexes,
|
|
88
|
+
)
|
|
89
|
+
const key =
|
|
90
|
+
position === 'left'
|
|
91
|
+
? 'left'
|
|
92
|
+
: position === 'right'
|
|
93
|
+
? 'right'
|
|
94
|
+
: position === 'center'
|
|
95
|
+
? 'center'
|
|
96
|
+
: 'all'
|
|
97
|
+
return indexes[key][column.id] ?? -1
|
|
47
98
|
}
|
|
48
99
|
|
|
49
100
|
/**
|
|
@@ -139,15 +139,22 @@ export function column_getIsPinned<
|
|
|
139
139
|
>(
|
|
140
140
|
column: Column_Internal<TFeatures, TData, TValue>,
|
|
141
141
|
): ColumnPinningPosition | false {
|
|
142
|
-
const
|
|
142
|
+
const leafColumns = column.getLeafColumns()
|
|
143
143
|
|
|
144
144
|
const { left, right } =
|
|
145
145
|
column.table.atoms.columnPinning?.get() ?? getDefaultColumnPinningState()
|
|
146
146
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
147
|
+
for (let i = 0; i < leafColumns.length; i++) {
|
|
148
|
+
if (left.includes(leafColumns[i]!.id)) {
|
|
149
|
+
return 'left'
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
for (let i = 0; i < leafColumns.length; i++) {
|
|
153
|
+
if (right.includes(leafColumns[i]!.id)) {
|
|
154
|
+
return 'right'
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
return false
|
|
151
158
|
}
|
|
152
159
|
|
|
153
160
|
/**
|
|
@@ -197,6 +204,9 @@ export function row_getCenterVisibleCells<
|
|
|
197
204
|
)
|
|
198
205
|
const { left, right } =
|
|
199
206
|
row.table.atoms.columnPinning?.get() ?? getDefaultColumnPinningState()
|
|
207
|
+
if (!left.length && !right.length) {
|
|
208
|
+
return allCells
|
|
209
|
+
}
|
|
200
210
|
const leftAndRight: Array<string> = [...left, ...right]
|
|
201
211
|
return allCells.filter((d) => !leftAndRight.includes(d.column.id))
|
|
202
212
|
}
|
|
@@ -441,11 +451,12 @@ export function table_getCenterHeaderGroups<
|
|
|
441
451
|
)
|
|
442
452
|
const { left, right } =
|
|
443
453
|
table.atoms.columnPinning?.get() ?? getDefaultColumnPinningState()
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
454
|
+
if (left.length || right.length) {
|
|
455
|
+
const leftAndRight: Array<string> = [...left, ...right]
|
|
456
|
+
leafColumns = leafColumns.filter(
|
|
457
|
+
(column) => !leftAndRight.includes(column.id),
|
|
458
|
+
)
|
|
459
|
+
}
|
|
449
460
|
return buildHeaderGroups(allColumns, leafColumns, table, 'center')
|
|
450
461
|
}
|
|
451
462
|
|
|
@@ -741,6 +752,9 @@ export function table_getCenterLeafColumns<
|
|
|
741
752
|
>(table: Table_Internal<TFeatures, TData>) {
|
|
742
753
|
const { left, right } =
|
|
743
754
|
table.atoms.columnPinning?.get() ?? getDefaultColumnPinningState()
|
|
755
|
+
if (!left.length && !right.length) {
|
|
756
|
+
return table.getAllLeafColumns()
|
|
757
|
+
}
|
|
744
758
|
const leftAndRight: Array<string> = [...left, ...right]
|
|
745
759
|
return table.getAllLeafColumns().filter((d) => !leftAndRight.includes(d.id))
|
|
746
760
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
callMemoOrStaticFn,
|
|
3
3
|
cloneState,
|
|
4
|
+
copyInstancePropertiesWithoutMemos,
|
|
4
5
|
hasOwn,
|
|
5
6
|
makeObjectMap,
|
|
6
7
|
} from '../../utils'
|
|
@@ -738,7 +739,7 @@ export function selectRowsFn<
|
|
|
738
739
|
if (isSelected) {
|
|
739
740
|
// Preserve prototype chain so methods like getValue() remain accessible
|
|
740
741
|
const cloned = Object.create(Object.getPrototypeOf(row))
|
|
741
|
-
|
|
742
|
+
copyInstancePropertiesWithoutMemos(cloned, row)
|
|
742
743
|
cloned.subRows = newSubRows
|
|
743
744
|
result.push(cloned)
|
|
744
745
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { tableMemo } from '../../utils'
|
|
1
|
+
import { copyInstancePropertiesWithoutMemos, tableMemo } from '../../utils'
|
|
2
2
|
import { table_autoResetPageIndex } from '../row-pagination/rowPaginationFeature.utils'
|
|
3
3
|
import { column_getCanSort, column_getSortFn } from './rowSortingFeature.utils'
|
|
4
4
|
import type { Column_Internal } from '../../types/Column'
|
|
@@ -56,6 +56,10 @@ function _createSortedRowModel<
|
|
|
56
56
|
return column ? column_getCanSort(column) : false
|
|
57
57
|
})
|
|
58
58
|
|
|
59
|
+
if (!availableSorting.length) {
|
|
60
|
+
return preSortedRowModel
|
|
61
|
+
}
|
|
62
|
+
|
|
59
63
|
const resolvedSorting: Array<{
|
|
60
64
|
id: string
|
|
61
65
|
desc?: boolean
|
|
@@ -132,32 +136,49 @@ function _createSortedRowModel<
|
|
|
132
136
|
return rowA.index - rowB.index
|
|
133
137
|
}
|
|
134
138
|
|
|
135
|
-
const sortData = (
|
|
139
|
+
const sortData = (
|
|
140
|
+
rows: Array<Row<TFeatures, TData>>,
|
|
141
|
+
): {
|
|
142
|
+
rows: Array<Row<TFeatures, TData>>
|
|
143
|
+
changed: boolean
|
|
144
|
+
} => {
|
|
136
145
|
const sortedData = rows.slice()
|
|
137
146
|
|
|
138
147
|
sortedData.sort(compareRows)
|
|
148
|
+
let changed = false
|
|
139
149
|
|
|
140
150
|
// If there are sub-rows, sort them. Clone only rows that need mutation
|
|
141
151
|
// (i.e. have subRows) so we don't corrupt the source row model.
|
|
142
152
|
for (let i = 0; i < sortedData.length; i++) {
|
|
143
153
|
const row = sortedData[i]!
|
|
154
|
+
if (row !== rows[i]) {
|
|
155
|
+
changed = true
|
|
156
|
+
}
|
|
157
|
+
|
|
144
158
|
if (row.subRows.length) {
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
159
|
+
const sortedSubRows = sortData(row.subRows)
|
|
160
|
+
|
|
161
|
+
if (sortedSubRows.changed) {
|
|
162
|
+
// Preserve prototype chain so methods like getValue() remain accessible
|
|
163
|
+
const cloned = Object.create(Object.getPrototypeOf(row))
|
|
164
|
+
copyInstancePropertiesWithoutMemos(cloned, row)
|
|
165
|
+
cloned.subRows = sortedSubRows.rows
|
|
166
|
+
sortedData[i] = cloned
|
|
167
|
+
sortedFlatRows.push(cloned)
|
|
168
|
+
changed = true
|
|
169
|
+
} else {
|
|
170
|
+
sortedFlatRows.push(row)
|
|
171
|
+
}
|
|
151
172
|
} else {
|
|
152
173
|
sortedFlatRows.push(row)
|
|
153
174
|
}
|
|
154
175
|
}
|
|
155
176
|
|
|
156
|
-
return sortedData
|
|
177
|
+
return { rows: sortedData, changed }
|
|
157
178
|
}
|
|
158
179
|
|
|
159
180
|
return {
|
|
160
|
-
rows: sortData(preSortedRowModel.rows),
|
|
181
|
+
rows: sortData(preSortedRowModel.rows).rows,
|
|
161
182
|
flatRows: sortedFlatRows,
|
|
162
183
|
rowsById: preSortedRowModel.rowsById,
|
|
163
184
|
}
|
|
@@ -195,23 +195,15 @@ export function column_toggleSorting<
|
|
|
195
195
|
desc?: boolean,
|
|
196
196
|
multi?: boolean,
|
|
197
197
|
) {
|
|
198
|
-
// if (column.columns.length) {
|
|
199
|
-
// column.columns.forEach((c, i) => {
|
|
200
|
-
// if (c.id) {
|
|
201
|
-
// table.toggleColumnSorting(c.id, undefined, multi || !!i)
|
|
202
|
-
// }
|
|
203
|
-
// })
|
|
204
|
-
// return
|
|
205
|
-
// }
|
|
206
|
-
|
|
207
198
|
// this needs to be outside of table.setSorting to be in sync with rerender
|
|
208
199
|
const nextSortingOrder = column_getNextSortingOrder(column)
|
|
209
200
|
const hasManualValue = typeof desc !== 'undefined'
|
|
210
201
|
|
|
211
202
|
table_setSorting(column.table, (old) => {
|
|
212
203
|
// Find any existing sorting for this column
|
|
213
|
-
const existingSorting = old.find((d) => d.id === column.id)
|
|
214
204
|
const existingIndex = old.findIndex((d) => d.id === column.id)
|
|
205
|
+
const existingSorting =
|
|
206
|
+
existingIndex === -1 ? undefined : old[existingIndex]
|
|
215
207
|
|
|
216
208
|
let newSorting: SortingState = []
|
|
217
209
|
|
package/src/utils.ts
CHANGED
|
@@ -50,6 +50,28 @@ export function cloneState<T>(value: T): T {
|
|
|
50
50
|
return value
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
+
/**
|
|
54
|
+
* Copies prototype-instance own properties without carrying over lazy memo
|
|
55
|
+
* closures or the per-row cell cache, both of which are bound to the source
|
|
56
|
+
* instance (cached cells reference the source row).
|
|
57
|
+
*/
|
|
58
|
+
export function copyInstancePropertiesWithoutMemos<
|
|
59
|
+
TTarget extends Record<string, any>,
|
|
60
|
+
TSource extends Record<string, any>,
|
|
61
|
+
>(target: TTarget, source: TSource): TTarget & TSource {
|
|
62
|
+
const keys = Object.keys(source)
|
|
63
|
+
const targetRecord = target as Record<string, any>
|
|
64
|
+
|
|
65
|
+
for (let i = 0; i < keys.length; i++) {
|
|
66
|
+
const key = keys[i]!
|
|
67
|
+
if (!key.startsWith('_memo_') && key !== '_cellsCache') {
|
|
68
|
+
targetRecord[key] = source[key]
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return target as TTarget & TSource
|
|
73
|
+
}
|
|
74
|
+
|
|
53
75
|
/**
|
|
54
76
|
* Creates an object intended only for string-keyed dictionary lookups.
|
|
55
77
|
*
|