@tanstack/table-core 9.0.0-alpha.46 → 9.0.0-alpha.47

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.
Files changed (163) hide show
  1. package/dist/core/cells/constructCell.cjs +4 -3
  2. package/dist/core/cells/constructCell.cjs.map +1 -1
  3. package/dist/core/cells/constructCell.js +4 -3
  4. package/dist/core/cells/constructCell.js.map +1 -1
  5. package/dist/core/columns/constructColumn.cjs +6 -4
  6. package/dist/core/columns/constructColumn.cjs.map +1 -1
  7. package/dist/core/columns/constructColumn.js +6 -4
  8. package/dist/core/columns/constructColumn.js.map +1 -1
  9. package/dist/core/columns/coreColumnsFeature.utils.cjs +10 -2
  10. package/dist/core/columns/coreColumnsFeature.utils.cjs.map +1 -1
  11. package/dist/core/columns/coreColumnsFeature.utils.js +10 -2
  12. package/dist/core/columns/coreColumnsFeature.utils.js.map +1 -1
  13. package/dist/core/headers/buildHeaderGroups.cjs +27 -19
  14. package/dist/core/headers/buildHeaderGroups.cjs.map +1 -1
  15. package/dist/core/headers/buildHeaderGroups.js +27 -19
  16. package/dist/core/headers/buildHeaderGroups.js.map +1 -1
  17. package/dist/core/headers/constructHeader.cjs +4 -3
  18. package/dist/core/headers/constructHeader.cjs.map +1 -1
  19. package/dist/core/headers/constructHeader.js +4 -3
  20. package/dist/core/headers/constructHeader.js.map +1 -1
  21. package/dist/core/headers/coreHeadersFeature.cjs +1 -6
  22. package/dist/core/headers/coreHeadersFeature.cjs.map +1 -1
  23. package/dist/core/headers/coreHeadersFeature.js +2 -7
  24. package/dist/core/headers/coreHeadersFeature.js.map +1 -1
  25. package/dist/core/headers/coreHeadersFeature.utils.cjs +20 -18
  26. package/dist/core/headers/coreHeadersFeature.utils.cjs.map +1 -1
  27. package/dist/core/headers/coreHeadersFeature.utils.d.cts +1 -1
  28. package/dist/core/headers/coreHeadersFeature.utils.d.ts +1 -1
  29. package/dist/core/headers/coreHeadersFeature.utils.js +21 -19
  30. package/dist/core/headers/coreHeadersFeature.utils.js.map +1 -1
  31. package/dist/core/reactivity/coreReactivityFeature.types.d.cts +4 -0
  32. package/dist/core/reactivity/coreReactivityFeature.types.d.ts +4 -0
  33. package/dist/core/rows/constructRow.cjs +8 -6
  34. package/dist/core/rows/constructRow.cjs.map +1 -1
  35. package/dist/core/rows/constructRow.js +8 -6
  36. package/dist/core/rows/constructRow.js.map +1 -1
  37. package/dist/core/rows/coreRowsFeature.utils.cjs +9 -4
  38. package/dist/core/rows/coreRowsFeature.utils.cjs.map +1 -1
  39. package/dist/core/rows/coreRowsFeature.utils.js +9 -4
  40. package/dist/core/rows/coreRowsFeature.utils.js.map +1 -1
  41. package/dist/core/table/constructTable.cjs +9 -5
  42. package/dist/core/table/constructTable.cjs.map +1 -1
  43. package/dist/core/table/constructTable.js +9 -5
  44. package/dist/core/table/constructTable.js.map +1 -1
  45. package/dist/core/table/coreTablesFeature.utils.cjs +5 -1
  46. package/dist/core/table/coreTablesFeature.utils.cjs.map +1 -1
  47. package/dist/core/table/coreTablesFeature.utils.js +5 -1
  48. package/dist/core/table/coreTablesFeature.utils.js.map +1 -1
  49. package/dist/features/column-faceting/createFacetedMinMaxValues.cjs +8 -5
  50. package/dist/features/column-faceting/createFacetedMinMaxValues.cjs.map +1 -1
  51. package/dist/features/column-faceting/createFacetedMinMaxValues.js +8 -5
  52. package/dist/features/column-faceting/createFacetedMinMaxValues.js.map +1 -1
  53. package/dist/features/column-faceting/createFacetedRowModel.cjs +8 -3
  54. package/dist/features/column-faceting/createFacetedRowModel.cjs.map +1 -1
  55. package/dist/features/column-faceting/createFacetedRowModel.js +8 -3
  56. package/dist/features/column-faceting/createFacetedRowModel.js.map +1 -1
  57. package/dist/features/column-faceting/createFacetedUniqueValues.cjs +7 -4
  58. package/dist/features/column-faceting/createFacetedUniqueValues.cjs.map +1 -1
  59. package/dist/features/column-faceting/createFacetedUniqueValues.js +7 -4
  60. package/dist/features/column-faceting/createFacetedUniqueValues.js.map +1 -1
  61. package/dist/features/column-filtering/createFilteredRowModel.cjs +11 -5
  62. package/dist/features/column-filtering/createFilteredRowModel.cjs.map +1 -1
  63. package/dist/features/column-filtering/createFilteredRowModel.js +11 -5
  64. package/dist/features/column-filtering/createFilteredRowModel.js.map +1 -1
  65. package/dist/features/column-ordering/columnOrderingFeature.utils.cjs +16 -6
  66. package/dist/features/column-ordering/columnOrderingFeature.utils.cjs.map +1 -1
  67. package/dist/features/column-ordering/columnOrderingFeature.utils.js +16 -6
  68. package/dist/features/column-ordering/columnOrderingFeature.utils.js.map +1 -1
  69. package/dist/features/column-pinning/columnPinningFeature.utils.cjs +41 -24
  70. package/dist/features/column-pinning/columnPinningFeature.utils.cjs.map +1 -1
  71. package/dist/features/column-pinning/columnPinningFeature.utils.d.cts +5 -4
  72. package/dist/features/column-pinning/columnPinningFeature.utils.d.ts +5 -4
  73. package/dist/features/column-pinning/columnPinningFeature.utils.js +42 -25
  74. package/dist/features/column-pinning/columnPinningFeature.utils.js.map +1 -1
  75. package/dist/features/column-sizing/columnSizingFeature.cjs +28 -4
  76. package/dist/features/column-sizing/columnSizingFeature.cjs.map +1 -1
  77. package/dist/features/column-sizing/columnSizingFeature.js +28 -4
  78. package/dist/features/column-sizing/columnSizingFeature.js.map +1 -1
  79. package/dist/features/column-visibility/columnVisibilityFeature.cjs +23 -14
  80. package/dist/features/column-visibility/columnVisibilityFeature.cjs.map +1 -1
  81. package/dist/features/column-visibility/columnVisibilityFeature.js +24 -15
  82. package/dist/features/column-visibility/columnVisibilityFeature.js.map +1 -1
  83. package/dist/features/column-visibility/columnVisibilityFeature.types.d.cts +4 -0
  84. package/dist/features/column-visibility/columnVisibilityFeature.types.d.ts +4 -0
  85. package/dist/features/column-visibility/columnVisibilityFeature.utils.cjs +40 -13
  86. package/dist/features/column-visibility/columnVisibilityFeature.utils.cjs.map +1 -1
  87. package/dist/features/column-visibility/columnVisibilityFeature.utils.d.cts +12 -1
  88. package/dist/features/column-visibility/columnVisibilityFeature.utils.d.ts +12 -1
  89. package/dist/features/column-visibility/columnVisibilityFeature.utils.js +40 -14
  90. package/dist/features/column-visibility/columnVisibilityFeature.utils.js.map +1 -1
  91. package/dist/features/row-expanding/rowExpandingFeature.utils.cjs +2 -2
  92. package/dist/features/row-expanding/rowExpandingFeature.utils.cjs.map +1 -1
  93. package/dist/features/row-expanding/rowExpandingFeature.utils.js +2 -2
  94. package/dist/features/row-expanding/rowExpandingFeature.utils.js.map +1 -1
  95. package/dist/features/row-pinning/rowPinningFeature.utils.cjs +13 -7
  96. package/dist/features/row-pinning/rowPinningFeature.utils.cjs.map +1 -1
  97. package/dist/features/row-pinning/rowPinningFeature.utils.js +13 -7
  98. package/dist/features/row-pinning/rowPinningFeature.utils.js.map +1 -1
  99. package/dist/features/row-selection/rowSelectionFeature.utils.cjs +6 -3
  100. package/dist/features/row-selection/rowSelectionFeature.utils.cjs.map +1 -1
  101. package/dist/features/row-selection/rowSelectionFeature.utils.js +6 -3
  102. package/dist/features/row-selection/rowSelectionFeature.utils.js.map +1 -1
  103. package/dist/features/row-sorting/createSortedRowModel.cjs +13 -8
  104. package/dist/features/row-sorting/createSortedRowModel.cjs.map +1 -1
  105. package/dist/features/row-sorting/createSortedRowModel.js +13 -8
  106. package/dist/features/row-sorting/createSortedRowModel.js.map +1 -1
  107. package/dist/features/row-sorting/rowSortingFeature.utils.cjs +2 -2
  108. package/dist/features/row-sorting/rowSortingFeature.utils.cjs.map +1 -1
  109. package/dist/features/row-sorting/rowSortingFeature.utils.js +2 -2
  110. package/dist/features/row-sorting/rowSortingFeature.utils.js.map +1 -1
  111. package/dist/fns/aggregationFns.cjs +14 -7
  112. package/dist/fns/aggregationFns.cjs.map +1 -1
  113. package/dist/fns/aggregationFns.js +14 -8
  114. package/dist/fns/aggregationFns.js.map +1 -1
  115. package/dist/index.cjs +0 -4
  116. package/dist/index.d.cts +2 -2
  117. package/dist/index.d.ts +2 -2
  118. package/dist/index.js +2 -2
  119. package/dist/static-functions.cjs +1 -0
  120. package/dist/static-functions.d.cts +2 -2
  121. package/dist/static-functions.d.ts +2 -2
  122. package/dist/static-functions.js +2 -2
  123. package/dist/store-reactivity-bindings.cjs +1 -0
  124. package/dist/store-reactivity-bindings.cjs.map +1 -1
  125. package/dist/store-reactivity-bindings.js +1 -0
  126. package/dist/store-reactivity-bindings.js.map +1 -1
  127. package/dist/utils.cjs +18 -39
  128. package/dist/utils.cjs.map +1 -1
  129. package/dist/utils.d.cts +1 -23
  130. package/dist/utils.d.ts +1 -23
  131. package/dist/utils.js +19 -36
  132. package/dist/utils.js.map +1 -1
  133. package/package.json +1 -1
  134. package/src/core/cells/constructCell.ts +3 -2
  135. package/src/core/columns/constructColumn.ts +5 -3
  136. package/src/core/columns/coreColumnsFeature.utils.ts +6 -2
  137. package/src/core/headers/buildHeaderGroups.ts +29 -30
  138. package/src/core/headers/constructHeader.ts +3 -2
  139. package/src/core/headers/coreHeadersFeature.ts +2 -27
  140. package/src/core/headers/coreHeadersFeature.utils.ts +29 -43
  141. package/src/core/reactivity/coreReactivityFeature.types.ts +4 -0
  142. package/src/core/rows/constructRow.ts +6 -4
  143. package/src/core/rows/coreRowsFeature.utils.ts +11 -4
  144. package/src/core/table/constructTable.ts +6 -4
  145. package/src/core/table/coreTablesFeature.utils.ts +3 -1
  146. package/src/features/column-faceting/createFacetedMinMaxValues.ts +8 -10
  147. package/src/features/column-faceting/createFacetedRowModel.ts +10 -6
  148. package/src/features/column-faceting/createFacetedUniqueValues.ts +4 -3
  149. package/src/features/column-filtering/createFilteredRowModel.ts +14 -8
  150. package/src/features/column-ordering/columnOrderingFeature.utils.ts +14 -6
  151. package/src/features/column-pinning/columnPinningFeature.utils.ts +53 -37
  152. package/src/features/column-sizing/columnSizingFeature.ts +16 -0
  153. package/src/features/column-visibility/columnVisibilityFeature.ts +8 -0
  154. package/src/features/column-visibility/columnVisibilityFeature.types.ts +7 -0
  155. package/src/features/column-visibility/columnVisibilityFeature.utils.ts +50 -17
  156. package/src/features/row-expanding/rowExpandingFeature.utils.ts +2 -2
  157. package/src/features/row-pinning/rowPinningFeature.utils.ts +20 -18
  158. package/src/features/row-selection/rowSelectionFeature.utils.ts +20 -19
  159. package/src/features/row-sorting/createSortedRowModel.ts +16 -13
  160. package/src/features/row-sorting/rowSortingFeature.utils.ts +2 -2
  161. package/src/fns/aggregationFns.ts +20 -8
  162. package/src/store-reactivity-bindings.ts +1 -0
  163. package/src/utils.ts +19 -46
package/dist/utils.js CHANGED
@@ -18,16 +18,16 @@ function cloneState(value) {
18
18
  const proto = Object.getPrototypeOf(value);
19
19
  if (proto !== Object.prototype && proto !== null) return value;
20
20
  const copy = {};
21
- for (const key of Object.keys(value)) copy[key] = cloneState(value[key]);
21
+ const keys = Object.keys(value);
22
+ for (let i = 0; i < keys.length; i++) {
23
+ const key = keys[i];
24
+ copy[key] = cloneState(value[key]);
25
+ }
22
26
  return copy;
23
27
  }
24
28
  return value;
25
29
  }
26
30
  /**
27
- * A no-operation function used as a safe default callback.
28
- */
29
- function noop() {}
30
- /**
31
31
  * Creates a table state updater for a single state slice.
32
32
  *
33
33
  * The updater writes through the table base atom for the slice and supports both value and functional updater forms.
@@ -45,12 +45,6 @@ function isFunction(d) {
45
45
  return d instanceof Function;
46
46
  }
47
47
  /**
48
- * Returns whether a value is an array containing only numbers.
49
- */
50
- function isNumberArray(d) {
51
- return Array.isArray(d) && d.every((val) => typeof val === "number");
52
- }
53
- /**
54
48
  * Flattens a tree of nodes by recursively reading child nodes.
55
49
  *
56
50
  * The original nodes are preserved in depth-first order.
@@ -68,25 +62,6 @@ function flattenBy(arr, getChildren) {
68
62
  return flat;
69
63
  }
70
64
  /**
71
- * Symbol used to attach internal memo metadata to wrapped functions.
72
- *
73
- * This is exported so diagnostics can recognize memoized functions without
74
- * depending on a string property name.
75
- */
76
- const $internalMemoFnMeta = Symbol("memoFnMeta");
77
- /**
78
- * @internal
79
- */
80
- function setMemoFnMeta(fn, meta) {
81
- Object.defineProperty(fn, $internalMemoFnMeta, { value: meta });
82
- }
83
- /**
84
- * @internal
85
- */
86
- function getMemoFnMeta(fn) {
87
- return (typeof fn === "function" && fn[$internalMemoFnMeta]) ?? null;
88
- }
89
- /**
90
65
  * Creates a dependency-tracked memoized function for table internals.
91
66
  *
92
67
  * The memo recomputes only when its dependency tuple changes and can emit debug timing information.
@@ -97,7 +72,13 @@ const memo = ({ fn, memoDeps, onAfterCompare, onAfterUpdate, onBeforeCompare, on
97
72
  const memoizedFn = (depArgs) => {
98
73
  onBeforeCompare === null || onBeforeCompare === void 0 || onBeforeCompare();
99
74
  const newDeps = memoDeps === null || memoDeps === void 0 ? void 0 : memoDeps(depArgs);
100
- const depsChanged = !newDeps || newDeps.length !== (deps === null || deps === void 0 ? void 0 : deps.length) || newDeps.some((dep, index) => (deps === null || deps === void 0 ? void 0 : deps[index]) !== dep);
75
+ let depsChanged = !newDeps || newDeps.length !== (deps === null || deps === void 0 ? void 0 : deps.length);
76
+ if (!depsChanged && newDeps) {
77
+ for (let i = 0; i < newDeps.length; i++) if (newDeps[i] !== deps[i]) {
78
+ depsChanged = true;
79
+ break;
80
+ }
81
+ }
101
82
  onAfterCompare === null || onAfterCompare === void 0 || onAfterCompare(depsChanged);
102
83
  if (!depsChanged) return result;
103
84
  deps = newDeps;
@@ -106,7 +87,6 @@ const memo = ({ fn, memoDeps, onAfterCompare, onAfterUpdate, onBeforeCompare, on
106
87
  onAfterUpdate === null || onAfterUpdate === void 0 || onAfterUpdate(result);
107
88
  return result;
108
89
  };
109
- setMemoFnMeta(memoizedFn, { originalArgsLength: fn.length });
110
90
  return memoizedFn;
111
91
  };
112
92
  const pad = (str, num) => {
@@ -147,6 +127,10 @@ function tableMemo({ feature, fnName, objectId, onAfterUpdate, table, ...memoOpt
147
127
  console.trace();
148
128
  console.groupEnd();
149
129
  }
130
+ const onAfterUpdateHandler = () => {
131
+ const { schedule, untrack } = table._reactivity;
132
+ schedule(() => untrack(() => onAfterUpdate === null || onAfterUpdate === void 0 ? void 0 : onAfterUpdate()));
133
+ };
150
134
  const debugOptions = process.env.NODE_ENV === "development" ? {
151
135
  onBeforeCompare: () => {
152
136
  if (debugCache) beforeCompareTime = performance.now();
@@ -166,10 +150,10 @@ function tableMemo({ feature, fnName, objectId, onAfterUpdate, table, ...memoOpt
166
150
  endCalcTime = performance.now();
167
151
  logTime(Math.round((endCalcTime - startCalcTime) * 100) / 100, true);
168
152
  }
169
- queueMicrotask(() => onAfterUpdate === null || onAfterUpdate === void 0 ? void 0 : onAfterUpdate());
153
+ onAfterUpdateHandler();
170
154
  }
171
155
  } : { onAfterUpdate: () => {
172
- queueMicrotask(() => onAfterUpdate === null || onAfterUpdate === void 0 ? void 0 : onAfterUpdate());
156
+ onAfterUpdateHandler();
173
157
  } };
174
158
  return memo({
175
159
  ...memoOptions,
@@ -232,7 +216,6 @@ function assignPrototypeAPIs(feature, prototype, table, apis) {
232
216
  } else prototype[fnKey] = function(...args) {
233
217
  return fn(this, ...args);
234
218
  };
235
- setMemoFnMeta(prototype[fnKey], { originalArgsLength: fn.length });
236
219
  }
237
220
  }
238
221
  /**
@@ -244,5 +227,5 @@ function callMemoOrStaticFn(obj, fnKey, staticFn, ...args) {
244
227
  }
245
228
 
246
229
  //#endregion
247
- export { $internalMemoFnMeta, assignPrototypeAPIs, assignTableAPIs, callMemoOrStaticFn, cloneState, flattenBy, functionalUpdate, getFunctionNameInfo, getMemoFnMeta, isFunction, isNumberArray, makeStateUpdater, memo, noop, tableMemo };
230
+ export { assignPrototypeAPIs, assignTableAPIs, callMemoOrStaticFn, cloneState, flattenBy, functionalUpdate, getFunctionNameInfo, isFunction, makeStateUpdater, memo, tableMemo };
248
231
  //# sourceMappingURL=utils.js.map
package/dist/utils.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"utils.js","names":[],"sources":["../src/utils.ts"],"sourcesContent":["import type { Table, 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> = {}\n\n for (const key of Object.keys(value)) {\n copy[key] = cloneState((value as Record<string, unknown>)[key])\n }\n\n return copy as T\n }\n\n return value\n}\n\n/**\n * A no-operation function used as a safe default callback.\n */\nexport function noop() {}\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>(key: K, instance: Table<TFeatures, any>) {\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 * Returns whether a value is an array containing only numbers.\n */\nexport function isNumberArray(d: any): d is Array<number> {\n return Array.isArray(d) && d.every((val) => typeof val === 'number')\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\n/**\n * Symbol used to attach internal memo metadata to wrapped functions.\n *\n * This is exported so diagnostics can recognize memoized functions without\n * depending on a string property name.\n */\nexport const $internalMemoFnMeta = Symbol('memoFnMeta')\nexport type MemoFnMeta = { originalArgsLength?: number }\n\n/**\n * @internal\n */\nfunction setMemoFnMeta(fn: Function, meta: MemoFnMeta) {\n Object.defineProperty(fn, $internalMemoFnMeta, { value: meta })\n}\n\n/**\n * @internal\n */\nexport function getMemoFnMeta(fn: any): MemoFnMeta | null {\n return (typeof fn === 'function' && fn[$internalMemoFnMeta]) ?? null\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 const depsChanged =\n !newDeps ||\n newDeps.length !== deps?.length ||\n newDeps.some((dep: any, index: number) => deps?.[index] !== dep)\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 setMemoFnMeta(memoizedFn, { originalArgsLength: fn.length })\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 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 queueMicrotask(() => onAfterUpdate?.())\n },\n }\n : {\n onAfterUpdate: () => {\n queueMicrotask(() => onAfterUpdate?.())\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 setMemoFnMeta(prototype[fnKey], { originalArgsLength: fn.length })\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 TStaticFn extends AnyFunction,\n>(\n obj: TObject,\n fnKey: string,\n staticFn: TStaticFn,\n ...args: Parameters<TStaticFn> extends [any, ...infer Rest] ? Rest : never\n): ReturnType<TStaticFn> {\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, 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> = {}\n const keys = Object.keys(value)\n\n for (let i = 0; i < keys.length; i++) {\n const key = keys[i]!\n copy[key] = cloneState((value as Record<string, unknown>)[key])\n }\n\n return copy as T\n }\n\n return value\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>(key: K, instance: Table<TFeatures, any>) {\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 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 TStaticFn extends AnyFunction,\n>(\n obj: TObject,\n fnKey: string,\n staticFn: TStaticFn,\n ...args: Parameters<TStaticFn> extends [any, ...infer Rest] ? Rest : never\n): ReturnType<TStaticFn> {\n return (\n (obj[fnKey] as Function | undefined)?.(...args) ?? staticFn(obj, ...args)\n )\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tanstack/table-core",
3
- "version": "9.0.0-alpha.46",
3
+ "version": "9.0.0-alpha.47",
4
4
  "description": "Headless UI for building powerful tables & datagrids for TS/JS.",
5
5
  "author": "Tanner Linsley",
6
6
  "license": "MIT",
@@ -16,8 +16,9 @@ function getCellPrototype<
16
16
  >(table: Table_Internal<TFeatures, TData>): object {
17
17
  if (!table._cellPrototype) {
18
18
  table._cellPrototype = { table }
19
- for (const feature of Object.values(table._features)) {
20
- feature.assignCellPrototype?.(table._cellPrototype, table)
19
+ const features = Object.values(table._features)
20
+ for (let i = 0; i < features.length; i++) {
21
+ features[i]!.assignCellPrototype?.(table._cellPrototype, table)
21
22
  }
22
23
  }
23
24
  return table._cellPrototype
@@ -20,8 +20,9 @@ function getColumnPrototype<
20
20
  >(table: Table_Internal<TFeatures, TData>): object {
21
21
  if (!table._columnPrototype) {
22
22
  table._columnPrototype = { table }
23
- for (const feature of Object.values(table._features)) {
24
- feature.assignColumnPrototype?.(table._columnPrototype, table)
23
+ const features = Object.values(table._features)
24
+ for (let i = 0; i < features.length; i++) {
25
+ features[i]!.assignColumnPrototype?.(table._columnPrototype, table)
25
26
  }
26
27
  }
27
28
  return table._columnPrototype
@@ -69,7 +70,8 @@ export function constructColumn<
69
70
  accessorFn = (originalRow: TData) => {
70
71
  let result = originalRow as Record<string, any> | undefined
71
72
 
72
- for (const key of keys) {
73
+ for (let i = 0; i < keys.length; i++) {
74
+ const key = keys[i]!
73
75
  result = result?.[key]
74
76
  if (process.env.NODE_ENV === 'development' && result === undefined) {
75
77
  console.warn(
@@ -179,7 +179,9 @@ export function table_getAllFlatColumnsById<
179
179
  table: Table_Internal<TFeatures, TData>,
180
180
  ): Record<string, Column<TFeatures, TData, unknown>> {
181
181
  const result: Record<string, Column<TFeatures, TData, unknown>> = {}
182
- for (const column of table.getAllFlatColumns()) {
182
+ const flatColumns = table.getAllFlatColumns()
183
+ for (let i = 0; i < flatColumns.length; i++) {
184
+ const column = flatColumns[i]!
183
185
  result[column.id] = column
184
186
  }
185
187
  return result
@@ -228,7 +230,9 @@ export function table_getAllLeafColumnsById<
228
230
  table: Table_Internal<TFeatures, TData>,
229
231
  ): Record<string, Column<TFeatures, TData, unknown>> {
230
232
  const result: Record<string, Column<TFeatures, TData, unknown>> = {}
231
- for (const column of table.getAllLeafColumns()) {
233
+ const leafColumns = table.getAllLeafColumns()
234
+ for (let i = 0; i < leafColumns.length; i++) {
235
+ const column = leafColumns[i]!
232
236
  result[column.id] = column
233
237
  }
234
238
  return result
@@ -37,15 +37,14 @@ export function buildHeaderGroups<
37
37
  ) => {
38
38
  maxDepth = Math.max(maxDepth, depth)
39
39
 
40
- columns
41
- .filter((column) =>
42
- callMemoOrStaticFn(column, 'getIsVisible', column_getIsVisible),
43
- )
44
- .forEach((column) => {
40
+ for (let i = 0; i < columns.length; i++) {
41
+ const column = columns[i]!
42
+ if (callMemoOrStaticFn(column, 'getIsVisible', column_getIsVisible)) {
45
43
  if (column.columns.length) {
46
44
  findMaxDepth(column.columns, depth + 1)
47
45
  }
48
- }, 0)
46
+ }
47
+ }
49
48
  }
50
49
 
51
50
  findMaxDepth(allColumns)
@@ -136,43 +135,43 @@ export function buildHeaderGroups<
136
135
 
137
136
  headerGroups.reverse()
138
137
 
139
- // headerGroups = headerGroups.filter(headerGroup => {
140
- // return !headerGroup.headers.every(header => header.isPlaceholder)
141
- // })
142
-
143
138
  const recurseHeadersForSpans = (
144
139
  headers: Array<Header<TFeatures, TData, TValue>>,
145
140
  ): Array<{ colSpan: number; rowSpan: number }> => {
146
- const filteredHeaders = headers.filter((header) =>
147
- callMemoOrStaticFn(header.column, 'getIsVisible', column_getIsVisible),
148
- )
141
+ const results: Array<{ colSpan: number; rowSpan: number }> = []
142
+
143
+ for (let i = 0; i < headers.length; i++) {
144
+ const header = headers[i]!
145
+ if (
146
+ !callMemoOrStaticFn(header.column, 'getIsVisible', column_getIsVisible)
147
+ ) {
148
+ continue
149
+ }
149
150
 
150
- return filteredHeaders.map((header) => {
151
151
  let colSpan = 0
152
- let rowSpan = 0
153
- let childRowSpans = [0]
152
+ let minChildRowSpan = Infinity
154
153
 
155
154
  if (header.subHeaders.length) {
156
- childRowSpans = []
157
-
158
- recurseHeadersForSpans(header.subHeaders).forEach(
159
- ({ colSpan: childColSpan, rowSpan: childRowSpan }) => {
160
- colSpan += childColSpan
161
- childRowSpans.push(childRowSpan)
162
- },
163
- )
155
+ const childSpans = recurseHeadersForSpans(header.subHeaders)
156
+ for (let j = 0; j < childSpans.length; j++) {
157
+ const child = childSpans[j]!
158
+ colSpan += child.colSpan
159
+ if (child.rowSpan < minChildRowSpan) {
160
+ minChildRowSpan = child.rowSpan
161
+ }
162
+ }
164
163
  } else {
165
164
  colSpan = 1
165
+ minChildRowSpan = 0
166
166
  }
167
167
 
168
- const minChildRowSpan = Math.min(...childRowSpans)
169
- rowSpan = rowSpan + minChildRowSpan
170
-
171
168
  header.colSpan = colSpan
172
- header.rowSpan = rowSpan
169
+ header.rowSpan = minChildRowSpan
173
170
 
174
- return { colSpan, rowSpan }
175
- })
171
+ results.push({ colSpan, rowSpan: header.rowSpan })
172
+ }
173
+
174
+ return results
176
175
  }
177
176
 
178
177
  recurseHeadersForSpans(
@@ -15,8 +15,9 @@ function getHeaderPrototype<
15
15
  >(table: Table_Internal<TFeatures, TData>): object {
16
16
  if (!table._headerPrototype) {
17
17
  table._headerPrototype = { table }
18
- for (const feature of Object.values(table._features)) {
19
- feature.assignHeaderPrototype?.(table._headerPrototype, table)
18
+ const features = Object.values(table._features)
19
+ for (let i = 0; i < features.length; i++) {
20
+ features[i]!.assignHeaderPrototype?.(table._headerPrototype, table)
20
21
  }
21
22
  }
22
23
  return table._headerPrototype
@@ -1,13 +1,4 @@
1
- import {
2
- assignPrototypeAPIs,
3
- assignTableAPIs,
4
- callMemoOrStaticFn,
5
- } from '../../utils'
6
- import {
7
- table_getCenterHeaderGroups,
8
- table_getLeftHeaderGroups,
9
- table_getRightHeaderGroups,
10
- } from '../../features/column-pinning/columnPinningFeature.utils'
1
+ import { assignPrototypeAPIs, assignTableAPIs } from '../../utils'
11
2
  import {
12
3
  header_getContext,
13
4
  header_getLeafHeaders,
@@ -74,23 +65,7 @@ export function constructCoreHeadersFeature<
74
65
  },
75
66
  table_getLeafHeaders: {
76
67
  fn: () => table_getLeafHeaders(table),
77
- memoDeps: () => [
78
- callMemoOrStaticFn(
79
- table,
80
- 'getLeftHeaderGroups',
81
- table_getLeftHeaderGroups,
82
- ),
83
- callMemoOrStaticFn(
84
- table,
85
- 'getCenterHeaderGroups',
86
- table_getCenterHeaderGroups,
87
- ),
88
- callMemoOrStaticFn(
89
- table,
90
- 'getRightHeaderGroups',
91
- table_getRightHeaderGroups,
92
- ),
93
- ],
68
+ memoDeps: () => [table.getHeaderGroups()],
94
69
  },
95
70
  })
96
71
  },
@@ -1,9 +1,4 @@
1
- import {
2
- getDefaultColumnPinningState,
3
- table_getCenterHeaderGroups,
4
- table_getLeftHeaderGroups,
5
- table_getRightHeaderGroups,
6
- } from '../../features/column-pinning/columnPinningFeature.utils'
1
+ import { getDefaultColumnPinningState } from '../../features/column-pinning/columnPinningFeature.utils'
7
2
  import {
8
3
  column_getIsVisible,
9
4
  table_getVisibleLeafColumns,
@@ -90,11 +85,17 @@ export function table_getHeaderGroups<
90
85
  'getVisibleLeafColumns',
91
86
  table_getVisibleLeafColumns,
92
87
  ) as Array<Column<TFeatures, TData, unknown>>
88
+
89
+ // Fast path: no columns are pinned — skip per-side lookups, partition, and spread.
90
+ if (!left.length && !right.length) {
91
+ return buildHeaderGroups(allColumns, leafColumns, table)
92
+ }
93
+
93
94
  const leafColumnsById = table.getAllLeafColumnsById()
94
95
 
95
96
  const leftColumns: typeof leafColumns = []
96
- for (const columnId of left) {
97
- const column = leafColumnsById[columnId]
97
+ for (let i = 0; i < left.length; i++) {
98
+ const column = leafColumnsById[left[i]!]
98
99
  if (
99
100
  column &&
100
101
  callMemoOrStaticFn(column, 'getIsVisible', column_getIsVisible)
@@ -104,8 +105,8 @@ export function table_getHeaderGroups<
104
105
  }
105
106
 
106
107
  const rightColumns: typeof leafColumns = []
107
- for (const columnId of right) {
108
- const column = leafColumnsById[columnId]
108
+ for (let i = 0; i < right.length; i++) {
109
+ const column = leafColumnsById[right[i]!]
109
110
  if (
110
111
  column &&
111
112
  callMemoOrStaticFn(column, 'getIsVisible', column_getIsVisible)
@@ -118,13 +119,11 @@ export function table_getHeaderGroups<
118
119
  (column) => !left.includes(column.id) && !right.includes(column.id),
119
120
  )
120
121
 
121
- const headerGroups = buildHeaderGroups(
122
+ return buildHeaderGroups(
122
123
  allColumns,
123
124
  [...leftColumns, ...centerColumns, ...rightColumns],
124
125
  table,
125
126
  )
126
-
127
- return headerGroups
128
127
  }
129
128
 
130
129
  /**
@@ -160,11 +159,14 @@ export function table_getFlatHeaders<
160
159
  TData extends RowData,
161
160
  >(table: Table_Internal<TFeatures, TData>) {
162
161
  const headerGroups = table.getHeaderGroups()
163
- return headerGroups
164
- .map((headerGroup) => {
165
- return headerGroup.headers
166
- })
167
- .flat()
162
+ const result: Array<Header<TFeatures, TData, unknown>> = []
163
+ for (let i = 0; i < headerGroups.length; i++) {
164
+ const headers = headerGroups[i]!.headers
165
+ for (let j = 0; j < headers.length; j++) {
166
+ result.push(headers[j]!)
167
+ }
168
+ }
169
+ return result
168
170
  }
169
171
 
170
172
  /**
@@ -181,29 +183,13 @@ export function table_getLeafHeaders<
181
183
  TFeatures extends TableFeatures,
182
184
  TData extends RowData,
183
185
  >(table: Table_Internal<TFeatures, TData>) {
184
- const left = callMemoOrStaticFn(
185
- table,
186
- 'getLeftHeaderGroups',
187
- table_getLeftHeaderGroups,
188
- )
189
- const center = callMemoOrStaticFn(
190
- table,
191
- 'getCenterHeaderGroups',
192
- table_getCenterHeaderGroups,
193
- )
194
- const right = callMemoOrStaticFn(
195
- table,
196
- 'getRightHeaderGroups',
197
- table_getRightHeaderGroups,
198
- )
199
-
200
- return [
201
- ...(left[0]?.headers ?? []),
202
- ...(center[0]?.headers ?? []),
203
- ...(right[0]?.headers ?? []),
204
- ]
205
- .map((header) => {
206
- return header.getLeafHeaders()
207
- })
208
- .flat()
186
+ const topHeaders = table.getHeaderGroups()[0]?.headers ?? []
187
+ const result: Array<Header<TFeatures, TData, unknown>> = []
188
+ for (let i = 0; i < topHeaders.length; i++) {
189
+ const leafHeaders = topHeaders[i]!.getLeafHeaders()
190
+ for (let j = 0; j < leafHeaders.length; j++) {
191
+ result.push(leafHeaders[j]!)
192
+ }
193
+ }
194
+ return result
209
195
  }
@@ -38,4 +38,8 @@ export interface TableReactivityBindings {
38
38
  * Batches reactive updates to avoid intermediate recomputation.
39
39
  */
40
40
  batch: (fn: () => void) => void
41
+ /**
42
+ * Schedules a function to run. This is used to defer updates after the current call stack (render, etc.) has finished
43
+ */
44
+ schedule: (fn: () => void) => void
41
45
  }
@@ -14,8 +14,9 @@ function getRowPrototype<
14
14
  >(table: Table_Internal<TFeatures, TData>): object {
15
15
  if (!table._rowPrototype) {
16
16
  table._rowPrototype = { table }
17
- for (const feature of Object.values(table._features)) {
18
- feature.assignRowPrototype?.(table._rowPrototype, table)
17
+ const features = Object.values(table._features)
18
+ for (let i = 0; i < features.length; i++) {
19
+ features[i]!.assignRowPrototype?.(table._rowPrototype, table)
19
20
  }
20
21
  }
21
22
  return table._rowPrototype
@@ -56,8 +57,9 @@ export const constructRow = <
56
57
  row.subRows = subRows ?? []
57
58
 
58
59
  // Initialize instance-specific data (e.g., caches) for features that need it
59
- for (const feature of Object.values(table._features)) {
60
- feature.initRowInstanceData?.(row)
60
+ const features = Object.values(table._features)
61
+ for (let i = 0; i < features.length; i++) {
62
+ features[i]!.initRowInstanceData?.(row)
61
63
  }
62
64
 
63
65
  return row as Row<TFeatures, TData>
@@ -164,9 +164,14 @@ export function row_getAllCells<
164
164
  TFeatures extends TableFeatures,
165
165
  TData extends RowData,
166
166
  >(row: Row<TFeatures, TData>): Array<Cell<TFeatures, TData, unknown>> {
167
- return row.table.getAllLeafColumns().map((column) => {
168
- return constructCell(column, row, row.table)
169
- })
167
+ const columns = row.table.getAllLeafColumns()
168
+ const cells: Array<Cell<TFeatures, TData, unknown>> = new Array(
169
+ columns.length,
170
+ )
171
+ for (let i = 0; i < columns.length; i++) {
172
+ cells[i] = constructCell(columns[i]!, row, row.table)
173
+ }
174
+ return cells
170
175
  }
171
176
 
172
177
  /**
@@ -184,7 +189,9 @@ export function row_getAllCellsByColumnId<
184
189
  TData extends RowData,
185
190
  >(row: Row<TFeatures, TData>) {
186
191
  const result: Record<string, Cell<TFeatures, TData, unknown>> = {}
187
- for (const cell of row.getAllCells()) {
192
+ const cells = row.getAllCells()
193
+ for (let i = 0; i < cells.length; i++) {
194
+ const cell = cells[i]!
188
195
  result[cell.column.id] = cell
189
196
  }
190
197
  return result
@@ -79,7 +79,8 @@ export function constructTable<
79
79
  string & keyof TableState<TFeatures>
80
80
  >
81
81
 
82
- for (const key of stateKeys) {
82
+ for (let i = 0; i < stateKeys.length; i++) {
83
+ const key = stateKeys[i]!
83
84
  // create writable base atom
84
85
  table.baseAtoms[key] = _reactivity.createWritableAtom(
85
86
  table.initialState[key],
@@ -107,7 +108,8 @@ export function constructTable<
107
108
  _reactivity.createReadonlyAtom(
108
109
  () => {
109
110
  const snapshot = {} as TableState<TFeatures>
110
- for (const key of stateKeys) {
111
+ for (let i = 0; i < stateKeys.length; i++) {
112
+ const key = stateKeys[i]!
111
113
  snapshot[key] = table.atoms[key].get()
112
114
  }
113
115
  return snapshot
@@ -136,8 +138,8 @@ export function constructTable<
136
138
  )
137
139
  }
138
140
 
139
- for (const feature of featuresList) {
140
- feature.constructTableAPIs?.(table)
141
+ for (let i = 0; i < featuresList.length; i++) {
142
+ featuresList[i]!.constructTableAPIs?.(table)
141
143
  }
142
144
 
143
145
  return table
@@ -56,7 +56,9 @@ export function table_reset<
56
56
  >(table: Table_Internal<TFeatures, TData>): void {
57
57
  const snap = cloneState(table.initialState)
58
58
  table._reactivity.batch(() => {
59
- for (const key of Object.keys(snap) as Array<keyof typeof snap>) {
59
+ const keys = Object.keys(snap) as Array<keyof typeof snap>
60
+ for (let i = 0; i < keys.length; i++) {
61
+ const key = keys[i]!
60
62
  ;(table.baseAtoms as any)[key].set(snap[key] as any)
61
63
  }
62
64
  })