From b6b3050bad64f2b82ee08d0f59388071ddee22a1 Mon Sep 17 00:00:00 2001 From: riccardoperra Date: Fri, 31 Jul 2026 15:14:52 +0200 Subject: [PATCH 1/3] Refactor options store into atoms --- .changeset/quiet-table-devtools.md | 12 + _artifacts/domain_map.yaml | 2 +- _artifacts/skill_spec.md | 2 +- _artifacts/skill_tree.yaml | 2 +- .../reference/functions/createTableHook.md | 51 ++- .../ember/reference/functions/useTable.md | 62 +++- docs/framework/lit/guide/table-state.md | 5 +- .../reference/classes/SubscribeDirective.md | 4 +- .../lit/reference/classes/TableController.md | 35 +- .../lit/reference/functions/FlexRender-1.md | 6 +- .../reference/functions/createTableHook.md | 2 +- .../lit/reference/functions/flexRender.md | 8 +- docs/framework/lit/reference/index.md | 1 + .../interfaces/CreateTableHookResult.md | 14 +- .../reference/type-aliases/AppCellContext.md | 18 +- .../type-aliases/AppColumnDefBase.md | 2 +- .../type-aliases/AppColumnDefTemplate.md | 2 +- .../reference/type-aliases/AppColumnHelper.md | 10 +- .../type-aliases/AppDisplayColumnDef.md | 2 +- .../type-aliases/AppGroupColumnDef.md | 4 +- .../type-aliases/AppHeaderContext.md | 12 +- .../lit/reference/type-aliases/AppLitTable.md | 20 +- .../reference/type-aliases/BoundComponents.md | 2 +- .../reference/type-aliases/ComponentType.md | 2 +- .../type-aliases/CreateTableHookOptions.md | 2 +- .../reference/type-aliases/FlexRenderProps.md | 2 +- .../reference/type-aliases/LitRenderable.md | 24 ++ .../lit/reference/type-aliases/LitTable.md | 2 +- .../lit/reference/variables/subscribe.md | 2 +- .../reference/functions/FlexRender-1.md | 2 +- .../preact/reference/functions/flexRender.md | 2 +- .../preact/reference/functions/useTable.md | 2 +- .../type-aliases/AppGroupColumnDef.md | 2 +- .../reference/type-aliases/FlexRenderProps.md | 2 +- .../reference/type-aliases/PreactTable.md | 2 +- .../SubscribePropsWithSourceIdentity.md | 2 +- .../reference/index/functions/useTable.md | 2 +- .../index/type-aliases/AppGroupColumnDef.md | 2 +- .../index/type-aliases/ReactTable.md | 2 +- .../SubscribePropsWithSourceIdentity.md | 2 +- .../solid/reference/functions/createTable.md | 2 +- .../reference/functions/createTableHook.md | 2 +- .../reference/interfaces/AppCellComponent.md | 4 +- .../reference/interfaces/AppCellProps.md | 6 +- .../interfaces/AppHeaderComponent.md | 4 +- .../reference/interfaces/AppHeaderProps.md | 6 +- .../reference/interfaces/AppTableComponent.md | 4 +- .../reference/interfaces/AppTableProps.md | 4 +- .../interfaces/CreateTableHookResult.md | 14 +- .../reference/type-aliases/AppCellContext.md | 14 +- .../type-aliases/AppColumnDefBase.md | 2 +- .../type-aliases/AppColumnDefTemplate.md | 2 +- .../reference/type-aliases/AppColumnHelper.md | 10 +- .../type-aliases/AppDisplayColumnDef.md | 2 +- .../type-aliases/AppGroupColumnDef.md | 4 +- .../type-aliases/AppHeaderContext.md | 8 +- .../reference/type-aliases/AppSolidTable.md | 2 +- .../reference/type-aliases/ComponentType.md | 2 +- .../type-aliases/CreateTableHookOptions.md | 2 +- .../reference/type-aliases/SolidTable.md | 2 +- .../type-aliases/AppGroupColumnDef.md | 2 +- .../reference/functions/createTableHook.md | 2 +- .../vue/reference/functions/useTable.md | 2 +- .../type-aliases/AppGroupColumnDef.md | 2 +- .../vue/reference/type-aliases/VueTable.md | 2 +- .../vue/reference/variables/FlexRender.md | 2 +- .../index/functions/assignPrototypeAPIs.md | 14 +- .../index/functions/assignTableAPIs.md | 14 +- .../index/functions/buildHeaderGroups.md | 2 +- .../index/functions/callMemoOrStaticFn.md | 2 +- docs/reference/index/functions/cloneState.md | 2 +- .../index/functions/constructTable.md | 2 +- .../copyInstancePropertiesWithoutMemos.md | 2 +- .../index/functions/createCoreRowModel.md | 2 +- .../index/functions/createGroupedRowModel.md | 2 +- .../index/functions/createSortedRowModel.md | 2 +- docs/reference/index/functions/expandRows.md | 2 +- docs/reference/index/functions/flattenBy.md | 2 +- .../index/functions/functionalUpdate.md | 2 +- .../index/functions/getFunctionNameInfo.md | 4 +- .../index/functions/getInitialTableState.md | 2 +- docs/reference/index/functions/hasOwn.md | 2 +- docs/reference/index/functions/isFunction.md | 2 +- .../index/functions/makeObjectMap.md | 2 +- .../index/functions/makeStateUpdater.md | 2 +- docs/reference/index/functions/memo.md | 52 --- docs/reference/index/functions/tableMemo.md | 25 +- docs/reference/index/index.md | 7 +- docs/reference/index/interfaces/API.md | 58 --- docs/reference/index/interfaces/Plugins.md | 2 +- .../index/interfaces/PrototypeAPI.md | 66 ---- .../index/interfaces/TableFeature.md | 25 +- .../index/interfaces/TableFeatures.md | 2 +- .../index/interfaces/TableOptions_Core.md | 18 +- .../index/interfaces/TableOptions_Table.md | 20 +- .../index/interfaces/TableState_FeatureMap.md | 2 +- docs/reference/index/interfaces/Table_Core.md | 86 ++--- .../index/interfaces/Table_CoreProperties.md | 78 ++-- .../index/interfaces/Table_FeatureMap.md | 32 +- .../index/interfaces/Table_Internal.md | 159 ++------ .../reference/index/interfaces/Table_Table.md | 86 ++--- docs/reference/index/type-aliases/API.md | 22 ++ .../reference/index/type-aliases/APIObject.md | 16 +- .../reference/index/type-aliases/Atoms_All.md | 2 +- .../index/type-aliases/BaseAtoms_All.md | 2 +- .../index/type-aliases/ExternalAtoms_All.md | 2 +- .../index/type-aliases/PrototypeAPI.md | 22 ++ .../index/type-aliases/PrototypeAPIObject.md | 16 +- docs/reference/index/type-aliases/Table.md | 2 +- .../index/type-aliases/TableOptionAtoms.md | 38 ++ .../index/type-aliases/TableOptionsLive.md | 26 ++ .../index/variables/cellSelectionFeature.md | 2 +- .../index/variables/columnPinningFeature.md | 2 +- .../index/variables/columnSizingFeature.md | 2 +- .../index/variables/rowPinningFeature.md | 2 +- .../functions/aggregateColumnValue.md | 2 +- .../functions/cell_getIsAggregated.md | 2 +- .../functions/cell_getIsSelected.md | 2 +- .../functions/column_clearSorting.md | 2 +- .../functions/column_getAggregationFns.md | 2 +- .../functions/column_getAggregationValue.md | 2 +- .../functions/column_getAutoAggregationFn.md | 2 +- .../functions/column_getCanMultiSort.md | 2 +- .../functions/column_getCanSort.md | 2 +- .../functions/column_getFirstSortDir.md | 2 +- .../functions/column_getIsSorted.md | 2 +- .../functions/column_getNextSortingOrder.md | 2 +- .../functions/column_getSortIndex.md | 2 +- .../column_getToggleSortingHandler.md | 2 +- .../functions/formatAggregatedCellValue.md | 2 +- .../functions/getDefaultRowSelectionState.md | 2 +- .../functions/header_getContext.md | 2 +- .../functions/header_getLeafHeaders.md | 2 +- .../functions/header_getSize.md | 2 +- .../functions/header_getStart.md | 2 +- .../functions/isRowSelected.md | 2 +- .../functions/isSubRowSelected.md | 2 +- .../functions/normalizeAggregationRows.md | 2 +- .../normalizeUniqueAggregationRows.md | 2 +- .../functions/row_getAllCells.md | 2 +- .../functions/row_getAllCellsByColumnId.md | 2 +- .../functions/row_getCanMultiSelect.md | 2 +- .../functions/row_getCanSelect.md | 2 +- .../functions/row_getCanSelectSubRows.md | 2 +- .../functions/row_getDisplayIndex.md | 2 +- .../functions/row_getIsAllSubRowsSelected.md | 2 +- .../functions/row_getIsSelected.md | 2 +- .../functions/row_getIsSomeSelected.md | 2 +- .../functions/row_getLeafRows.md | 2 +- .../functions/row_getParentRow.md | 2 +- .../functions/row_getParentRows.md | 2 +- .../functions/row_getToggleSelectedHandler.md | 2 +- .../functions/row_getUniqueValues.md | 2 +- .../functions/row_getValue.md | 2 +- .../functions/row_renderValue.md | 2 +- .../functions/row_toggleSelected.md | 2 +- .../functions/selectRowsFn.md | 2 +- .../functions/table_getAllColumns.md | 2 +- .../functions/table_getAllFlatColumns.md | 2 +- .../functions/table_getAllFlatColumnsById.md | 2 +- .../functions/table_getAllLeafColumns.md | 2 +- .../functions/table_getAllLeafColumnsById.md | 2 +- .../functions/table_getCenterTotalSize.md | 2 +- .../functions/table_getColumn.md | 2 +- .../functions/table_getEndTotalSize.md | 2 +- .../table_getFilteredSelectedRowModel.md | 2 +- .../functions/table_getFlatHeaders.md | 2 +- .../functions/table_getFooterGroups.md | 2 +- .../table_getGroupedSelectedRowModel.md | 2 +- .../functions/table_getHeaderGroups.md | 2 +- .../table_getIsAllPageRowsSelected.md | 2 +- .../functions/table_getIsAllRowsSelected.md | 2 +- .../table_getIsSomePageRowsSelected.md | 2 +- .../functions/table_getIsSomeRowsSelected.md | 2 +- .../functions/table_getLeafHeaders.md | 2 +- .../functions/table_getMaxSubRowDepth.md | 2 +- .../functions/table_getPreSelectedRowModel.md | 2 +- .../functions/table_getRow.md | 2 +- .../functions/table_getRowId.md | 2 +- .../functions/table_getRowsInDisplayOrder.md | 2 +- .../functions/table_getSelectedRowIds.md | 2 +- .../functions/table_getSelectedRowModel.md | 2 +- .../functions/table_getStartTotalSize.md | 2 +- ...ble_getToggleAllPageRowsSelectedHandler.md | 2 +- .../table_getToggleAllRowsSelectedHandler.md | 2 +- .../functions/table_getTotalSize.md | 2 +- .../functions/table_mergeOptions.md | 2 +- .../functions/table_publishExternalState.md | 54 +++ .../static-functions/functions/table_reset.md | 2 +- .../functions/table_resetColumnSizing.md | 2 +- .../functions/table_resetRowSelection.md | 2 +- .../functions/table_setColumnSizing.md | 2 +- .../functions/table_setOptions.md | 16 +- .../functions/table_setRowSelection.md | 2 +- .../table_syncExternalStateToBaseAtoms.md | 28 +- .../table_toggleAllPageRowsSelected.md | 2 +- .../functions/table_toggleAllRowsSelected.md | 2 +- docs/reference/static-functions/index.md | 1 + packages/alpine-table/src/createTable.ts | 23 +- packages/alpine-table/src/reactivity.ts | 39 +- .../tests/unit/adapterCoverage.test.ts | 10 + .../src/TableDevtools.ts | 31 +- .../src/injectTanStackTableDevtools.ts | 17 +- .../angular-table-devtools/src/production.ts | 4 +- .../src/production/TableDevtools.ts | 41 +++ .../src/production/plugin.ts | 11 + packages/angular-table/src/injectTable.ts | 5 +- packages/angular-table/src/reactivity.ts | 7 +- packages/ember-table/src/reactivity.ts | 16 +- packages/ember-table/src/signal.ts | 5 +- packages/ember-table/src/use-table.ts | 147 ++++---- .../tests/integration/use-table.test.gts | 220 +++++++++++ packages/lit-table/src/TableController.ts | 28 +- packages/lit-table/src/reactivity.ts | 12 +- .../src/PreactTableDevtools.tsx | 23 +- .../preact-table-devtools/src/production.ts | 4 +- .../src/production/PreactTableDevtools.tsx | 32 ++ .../src/production/plugin.tsx | 13 + .../src/useTanStackTableDevtools.ts | 22 +- packages/preact-table/src/Subscribe.ts | 2 +- packages/preact-table/src/reactivity.ts | 7 +- packages/preact-table/src/useTable.ts | 17 +- .../tests/unit/adapterReactivity.test.tsx | 7 +- .../src/ReactTableDevtools.tsx | 24 +- .../react-table-devtools/src/production.ts | 4 +- .../src/production/ReactTableDevtools.tsx | 29 ++ .../src/production/plugin.tsx | 11 + .../src/table-devtools.d.ts | 10 + .../src/useTanStackTableDevtools.ts | 19 +- packages/react-table/src/Subscribe.ts | 2 +- packages/react-table/src/reactivity.ts | 10 +- packages/react-table/src/useTable.ts | 17 +- .../tests/adapterReactivity.test.tsx | 7 +- .../src/TableDevtools.tsx | 8 +- .../solid-table-devtools/src/production.ts | 2 +- .../src/production/TableDevtools.tsx | 8 +- .../src/useTanStackTableDevtools.ts | 15 +- packages/solid-table/src/createTable.ts | 25 +- packages/solid-table/src/createTableHook.tsx | 5 +- packages/solid-table/src/merge-options.ts | 93 +++++ packages/solid-table/src/reactivity.ts | 21 +- .../tests/unit/adapterReactivity.test.ts | 49 +++ .../solid-table/tests/unit/reactivity.test.ts | 51 +++ .../svelte-table/src/createTable.svelte.ts | 9 +- packages/svelte-table/src/merge-objects.ts | 104 ++++-- .../svelte-table/src/reactivity.svelte.ts | 84 ++--- .../tests/adapter-lifecycle.test.ts | 19 + .../tests/fixtures/ReactivityHarness.svelte | 15 +- .../svelte-table/tests/merge-objects.test.ts | 48 +++ .../skills/custom-features/SKILL.md | 2 +- .../src/core/cells/coreCellsFeature.ts | 3 +- .../src/core/columns/coreColumnsFeature.ts | 43 +-- .../src/core/headers/coreHeadersFeature.ts | 31 +- .../reactivity/coreReactivityFeature.types.ts | 27 +- .../createStableStoreReadonlyAtom.ts | 51 +++ .../core/reactivity/renderPhaseReactivity.ts | 137 ++++++- .../src/core/row-models/createCoreRowModel.ts | 67 +++- .../src/core/rows/coreRowsFeature.ts | 21 +- .../src/core/rows/coreRowsFeature.utils.ts | 3 +- .../src/core/rows/subRowsTracking.ts | 87 +++++ .../src/core/table/constructTable.ts | 99 +++-- .../src/core/table/coreTablesFeature.types.ts | 53 ++- .../src/core/table/coreTablesFeature.utils.ts | 94 ++--- .../src/core/table/tableOptionAtoms.ts | 194 ++++++++++ .../cell-selection/cellSelectionFeature.ts | 76 +--- .../cellSelectionFeature.utils.ts | 2 +- .../column-faceting/columnFacetingFeature.ts | 70 ++-- .../createFacetedMinMaxValues.ts | 39 +- .../column-faceting/createFacetedRowModel.ts | 20 +- .../createFacetedUniqueValues.ts | 39 +- .../createFilteredRowModel.ts | 5 - .../column-filtering/filterRowsUtils.ts | 5 +- .../column-grouping/createGroupedRowModel.ts | 11 +- .../column-ordering/columnOrderingFeature.ts | 25 +- .../column-pinning/columnPinningFeature.ts | 312 +++++++--------- .../column-sizing/columnSizingFeature.ts | 146 +++++--- .../columnVisibilityFeature.ts | 38 +- .../row-aggregation/rowAggregationFeature.ts | 10 +- .../row-expanding/createExpandedRowModel.ts | 6 - .../row-pagination/createPaginatedRowModel.ts | 7 - .../features/row-pinning/rowPinningFeature.ts | 78 ++-- .../row-selection/rowSelectionFeature.ts | 59 +-- .../rowSelectionFeature.utils.ts | 20 +- .../row-sorting/createSortedRowModel.ts | 7 +- .../src/store-reactivity-bindings.ts | 8 +- packages/table-core/src/types/Table.ts | 17 +- packages/table-core/src/utils.ts | 348 ++++++++---------- .../src/worker/createTableWorker.ts | 37 +- .../src/worker/createWorkerRowModel.ts | 19 +- .../row-pinning/rowPinningFeature.test.ts | 37 ++ .../row-selection/rowSelectionFeature.test.ts | 48 ++- .../unit/core/renderPhaseReactivity.test.ts | 180 +++++++++ .../tests/unit/core/rows/constructRow.test.ts | 53 +++ .../unit/core/table/tableOptionAtoms.test.ts | 211 +++++++++++ .../columnOrderingFeature.utils.test.ts | 21 ++ .../columnPinningFeature.utils.test.ts | 66 +++- .../columnResizingFeature.utils.test.ts | 104 +++--- .../columnSizingFeature.utils.test.ts | 35 +- .../rowPinningFeature.utils.test.ts | 10 +- packages/table-core/tests/unit/utils.test.ts | 282 ++++++++++++-- packages/table-devtools/src/TableDevtools.tsx | 9 +- .../src/components/ColumnsPanel.tsx | 8 +- .../src/components/FeaturesPanel.tsx | 16 +- .../src/components/OptionsPanel.tsx | 16 +- .../src/components/ResizableSplit.tsx | 24 +- .../src/components/RowsPanel.tsx | 48 +-- .../table-devtools/src/components/Shell.tsx | 5 +- .../src/components/StatePanel.tsx | 123 +++---- .../src/components/ThreeWayResizableSplit.tsx | 19 +- packages/table-devtools/src/index.ts | 2 + packages/table-devtools/src/production.ts | 2 + .../table-devtools/src/styles/use-styles.ts | 20 +- packages/table-devtools/src/tableTarget.ts | 89 ++++- packages/table-devtools/src/useTableStore.ts | 34 +- .../tests/panel-lifecycle.test.tsx | 74 ++++ packages/table-devtools/tests/styles.test.tsx | 51 +++ .../table-devtools/tests/tableTarget.test.ts | 121 ++++++ .../src/VueTableDevtools.tsx | 15 +- packages/vue-table-devtools/src/production.ts | 4 +- .../src/production/VueTableDevtools.tsx | 46 +++ .../src/production/plugin.ts | 9 + .../src/useTanStackTableDevtools.ts | 19 +- packages/vue-table/src/merge-proxy.ts | 104 +++++- packages/vue-table/src/reactivity.ts | 23 +- packages/vue-table/src/useTable.ts | 24 +- .../tests/unit/adapter-lifecycle.test.ts | 57 ++- packages/vue-table/tests/unit/signals.test.ts | 21 ++ 327 files changed, 5073 insertions(+), 2342 deletions(-) create mode 100644 .changeset/quiet-table-devtools.md create mode 100644 docs/framework/lit/reference/type-aliases/LitRenderable.md delete mode 100644 docs/reference/index/functions/memo.md delete mode 100644 docs/reference/index/interfaces/API.md delete mode 100644 docs/reference/index/interfaces/PrototypeAPI.md create mode 100644 docs/reference/index/type-aliases/API.md create mode 100644 docs/reference/index/type-aliases/PrototypeAPI.md create mode 100644 docs/reference/index/type-aliases/TableOptionAtoms.md create mode 100644 docs/reference/index/type-aliases/TableOptionsLive.md create mode 100644 docs/reference/static-functions/functions/table_publishExternalState.md create mode 100644 packages/angular-table-devtools/src/production/TableDevtools.ts create mode 100644 packages/angular-table-devtools/src/production/plugin.ts create mode 100644 packages/preact-table-devtools/src/production/PreactTableDevtools.tsx create mode 100644 packages/preact-table-devtools/src/production/plugin.tsx create mode 100644 packages/react-table-devtools/src/production/ReactTableDevtools.tsx create mode 100644 packages/react-table-devtools/src/production/plugin.tsx create mode 100644 packages/solid-table/src/merge-options.ts create mode 100644 packages/svelte-table/tests/merge-objects.test.ts create mode 100644 packages/table-core/src/core/reactivity/createStableStoreReadonlyAtom.ts create mode 100644 packages/table-core/src/core/rows/subRowsTracking.ts create mode 100644 packages/table-core/src/core/table/tableOptionAtoms.ts create mode 100644 packages/table-core/tests/unit/core/table/tableOptionAtoms.test.ts create mode 100644 packages/table-devtools/tests/panel-lifecycle.test.tsx create mode 100644 packages/table-devtools/tests/styles.test.tsx create mode 100644 packages/vue-table-devtools/src/production/VueTableDevtools.tsx create mode 100644 packages/vue-table-devtools/src/production/plugin.ts diff --git a/.changeset/quiet-table-devtools.md b/.changeset/quiet-table-devtools.md new file mode 100644 index 0000000000..68a623f6b2 --- /dev/null +++ b/.changeset/quiet-table-devtools.md @@ -0,0 +1,12 @@ +--- +'@tanstack/table-devtools': patch +'@tanstack/react-table-devtools': patch +'@tanstack/preact-table-devtools': patch +'@tanstack/solid-table-devtools': patch +'@tanstack/vue-table-devtools': patch +'@tanstack/angular-table-devtools': patch +--- + +Prevent table state updates from remounting the devtools panel, subscribe only +while the panel is open, cache generated styles by theme, and keep adapter +registration and production entrypoints reactive and stable. diff --git a/_artifacts/domain_map.yaml b/_artifacts/domain_map.yaml index af0cf867f3..9986132ac2 100644 --- a/_artifacts/domain_map.yaml +++ b/_artifacts/domain_map.yaml @@ -102,7 +102,7 @@ custom_feature_depth_contract: - 'assignPrototypeAPIs inside assignCellPrototype for shared cell methods.' - 'assignPrototypeAPIs inside assignHeaderPrototype for shared header methods.' - 'initColumnInstanceData and initRowInstanceData for per-instance mutable data rather than shared methods.' - - 'The table_/column_/row_/cell_/header_ static-name prefixes, self argument difference, optional memoDeps, and absence of per-object assign*APIs utilities.' + - 'The table_/column_/row_/cell_/header_ static-name prefixes, `{ fn }` versus `{ computed, compare? }`, prototype self argument, native dependency tracking, and absence of per-object assign*APIs utilities.' api_discovery_policy: rule: 'For exact exports, option types, state shapes, and instance APIs, inspect dist declarations (.d.ts) in the installed package before inventing an API or relying on memory.' diff --git a/_artifacts/skill_spec.md b/_artifacts/skill_spec.md index 5868132346..1f6c8b546d 100644 --- a/_artifacts/skill_spec.md +++ b/_artifacts/skill_spec.md @@ -124,7 +124,7 @@ Treat stable `data` and `columns` references as a correctness and performance in The custom-features skill must enumerate all 10 public declaration-merge FeatureMaps: table state, table options, table, column definition, column, row, cell, header, row-model functions, and cached row models. Explain that `Plugins` registers the feature key and that declarations add types only; each advertised runtime surface needs matching lifecycle wiring. -Enumerate both API utilities and every installation path: `assignTableAPIs` in `constructTableAPIs`, plus `assignPrototypeAPIs` in `assignColumnPrototype`, `assignRowPrototype`, `assignCellPrototype`, and `assignHeaderPrototype`. Include the static-name prefixes, prototype self argument, optional `memoDeps`, shared-prototype constraint, `initColumnInstanceData`/`initRowInstanceData`, and the fact that per-object `assignColumnAPIs`-style utilities do not exist. Clearly label row-model maps as advanced internal pipeline surfaces requiring explicit runtime/cache wiring. +Enumerate both API utilities and every installation path: `assignTableAPIs` in `constructTableAPIs`, plus `assignPrototypeAPIs` in `assignColumnPrototype`, `assignRowPrototype`, `assignCellPrototype`, and `assignHeaderPrototype`. Include the static-name prefixes, the `{ fn }` versus `{ computed, compare? }` descriptor shapes, the prototype computed self argument, native dependency tracking, the shared-prototype constraint, `initColumnInstanceData`/`initRowInstanceData`, and the fact that per-object `assignColumnAPIs`-style utilities do not exist. Clearly label row-model maps as advanced internal pipeline surfaces requiring explicit runtime/cache wiring. Use one annotated, authoritative feature example for the complete shape. Do not stack a minimal density example, a second FeatureMap example, a third API-installation example, and then repeat their distinction under Common Mistakes. Keep selection guidance and foot-guns as compact prose around the single example. diff --git a/_artifacts/skill_tree.yaml b/_artifacts/skill_tree.yaml index 4d96285789..e397a77bb6 100644 --- a/_artifacts/skill_tree.yaml +++ b/_artifacts/skill_tree.yaml @@ -102,7 +102,7 @@ skills: domain: foundations path: 'packages/table-core/skills/custom-features/SKILL.md' package: 'packages/table-core' - description: 'Author a TanStack Table v9 feature plugin across all 10 FeatureMaps and every table/column/row/cell/header API installation path, including prototypes, memoDeps, instance data, and advanced row-model maps, after checking built-ins and meta.' + description: 'Author a TanStack Table v9 feature plugin across all 10 FeatureMaps and every table/column/row/cell/header API installation path, including prototype and computed APIs, instance data, and advanced row-model maps, after checking built-ins and meta.' requires: ['core', 'table-features', 'typescript'] sources: - 'TanStack/table:docs/framework/react/guide/custom-features.md' diff --git a/docs/framework/ember/reference/functions/createTableHook.md b/docs/framework/ember/reference/functions/createTableHook.md index baf000d03c..2340dacd14 100644 --- a/docs/framework/ember/reference/functions/createTableHook.md +++ b/docs/framework/ember/reference/functions/createTableHook.md @@ -60,22 +60,57 @@ createAppColumnHelper: () => ColumnHelper; ### createAppTable() ```ts -createAppTable: (getTableOptions) => AppEmberTable; +createAppTable: { + (owner, getTableOptions): AppEmberTable; + (getTableOptions): AppEmberTable; +}; ``` -#### Type Parameters +#### Call Signature -##### TData +```ts +(owner, getTableOptions): AppEmberTable; +``` + +##### Type Parameters + +###### TData `TData` *extends* `RowData` -#### Parameters +##### Parameters -##### getTableOptions +###### owner + +`object` + +###### getTableOptions () => `Omit`\<`TableOptions`\<`TFeatures`, `TData`\>, `"features"`\> -#### Returns +##### Returns + +[`AppEmberTable`](../type-aliases/AppEmberTable.md)\<`TFeatures`, `TData`\> + +#### Call Signature + +```ts +(getTableOptions): AppEmberTable; +``` + +##### Type Parameters + +###### TData + +`TData` *extends* `RowData` + +##### Parameters + +###### getTableOptions + +() => `Omit`\<`TableOptions`\<`TFeatures`, `TData`\>, `"features"`\> + +##### Returns [`AppEmberTable`](../type-aliases/AppEmberTable.md)\<`TFeatures`, `TData`\> @@ -89,6 +124,6 @@ const { createAppTable, createAppColumnHelper } = createTableHook({ const columnHelper = createAppColumnHelper() const columns = columnHelper.columns([...]) -// inside a Glimmer component; options stay a thunk so tracked reads are reactive -table = createAppTable(() => ({ columns, data: this.data })) +// inside a Glimmer component; passing `this` binds cleanup to its lifecycle +table = createAppTable(this, () => ({ columns, data: this.data })) ``` diff --git a/docs/framework/ember/reference/functions/useTable.md b/docs/framework/ember/reference/functions/useTable.md index c830fcc13d..cba642ed31 100644 --- a/docs/framework/ember/reference/functions/useTable.md +++ b/docs/framework/ember/reference/functions/useTable.md @@ -5,28 +5,76 @@ title: useTable # Function: useTable() +## Call Signature + +```ts +function useTable(owner, getOptions): Table; +``` + +Defined in: packages/ember-table/declarations/use-table.d.ts:10 + +Creates an Ember-reactive table. + +Pass the containing component (or another Ember destroyable) as the first +argument to tie external-atom subscriptions to its lifecycle. The one-arg +form remains available for standalone tables that do not have an Ember +owner. + +### Type Parameters + +#### TFeatures + +`TFeatures` *extends* `TableFeatures` + +#### TData + +`TData` *extends* `RowData` + +### Parameters + +#### owner + +`object` + +#### getOptions + +() => `TableOptions`\<`TFeatures`, `TData`\> + +### Returns + +`Table`\<`TFeatures`, `TData`\> + +## Call Signature + ```ts function useTable(getOptions): Table; ``` -Defined in: packages/ember-table/declarations/use-table.d.ts:2 +Defined in: packages/ember-table/declarations/use-table.d.ts:11 + +Creates an Ember-reactive table. + +Pass the containing component (or another Ember destroyable) as the first +argument to tie external-atom subscriptions to its lifecycle. The one-arg +form remains available for standalone tables that do not have an Ember +owner. -## Type Parameters +### Type Parameters -### TFeatures +#### TFeatures `TFeatures` *extends* `TableFeatures` -### TData +#### TData `TData` *extends* `RowData` -## Parameters +### Parameters -### getOptions +#### getOptions () => `TableOptions`\<`TFeatures`, `TData`\> -## Returns +### Returns `Table`\<`TFeatures`, `TData`\> diff --git a/docs/framework/lit/guide/table-state.md b/docs/framework/lit/guide/table-state.md index 173ffbe6fe..8af534b542 100644 --- a/docs/framework/lit/guide/table-state.md +++ b/docs/framework/lit/guide/table-state.md @@ -32,9 +32,10 @@ A table instance has a few state surfaces: - `table.baseAtoms` are the internal writable atoms created from the resolved initial state. - `table.atoms` are readonly derived atoms exposed per registered state slice. - `table.store` is a readonly flat TanStack Store derived by putting all of the registered `table.atoms` together. +- `table.optionAtoms` contains stable atoms for individual resolved options, plus the readonly `snapshotVersion` atom for observing aggregate option updates. Ordinary option atoms are writable, while `table.options` is a stable readonly view backed by those atoms. - `table.state` is Lit-only selected state. It is the value returned from the selector passed as the second argument to `tableController.table(...)`. -The Lit adapter provides `litReactivity()` to the table's `coreReactivityFeature`. Readonly and writable atoms are TanStack Store atoms. `TableController` subscribes to `table.store` and `table.optionsStore`; atom or options changes flowing through those stores call `host.requestUpdate()`. +The Lit adapter provides `litReactivity()` to the table's `coreReactivityFeature`. Readonly and writable atoms are TanStack Store atoms. `TableController` stages options so table reads during a render see the current values, publishes that option commit from `hostUpdated()`, and subscribes to `table.store` to request host updates for committed state changes. ### Feature-based State @@ -88,7 +89,7 @@ const tableState = table.store.state const pagination = table.store.state.pagination ``` -These reads are current-value reads. The `TableController` handles host invalidation through its subscriptions to the table store and options store. If the UI needs to stay reactive to table state changes, use `table.state`, `table.subscribe`, or a TanStack Store subscription. +These reads are current-value reads. The `TableController` handles host invalidation through its table-store subscription. If the UI needs to stay reactive to table state changes, use `table.state`, `table.subscribe`, or a TanStack Store subscription. #### Reading Reactive State with TableController diff --git a/docs/framework/lit/reference/classes/SubscribeDirective.md b/docs/framework/lit/reference/classes/SubscribeDirective.md index cba28097d1..c9e90a36a1 100644 --- a/docs/framework/lit/reference/classes/SubscribeDirective.md +++ b/docs/framework/lit/reference/classes/SubscribeDirective.md @@ -129,7 +129,7 @@ AsyncDirective._$initialize disconnected(): void; ``` -Defined in: [packages/lit-table/src/subscribe-directive.ts:141](https://github.com/TanStack/table/blob/main/packages/lit-table/src/subscribe-directive.ts#L141) +Defined in: [packages/lit-table/src/subscribe-directive.ts:150](https://github.com/TanStack/table/blob/main/packages/lit-table/src/subscribe-directive.ts#L150) Cleans up the controller subscription when the directive is removed from the DOM. @@ -151,7 +151,7 @@ AsyncDirective.disconnected reconnected(): void; ``` -Defined in: [packages/lit-table/src/subscribe-directive.ts:146](https://github.com/TanStack/table/blob/main/packages/lit-table/src/subscribe-directive.ts#L146) +Defined in: [packages/lit-table/src/subscribe-directive.ts:155](https://github.com/TanStack/table/blob/main/packages/lit-table/src/subscribe-directive.ts#L155) Restores the controller subscription when the directive is re-attached to the DOM. diff --git a/docs/framework/lit/reference/classes/TableController.md b/docs/framework/lit/reference/classes/TableController.md index 42c62b305e..32bea4b093 100644 --- a/docs/framework/lit/reference/classes/TableController.md +++ b/docs/framework/lit/reference/classes/TableController.md @@ -5,7 +5,7 @@ title: TableController # Class: TableController\ -Defined in: [packages/lit-table/src/TableController.ts:118](https://github.com/TanStack/table/blob/main/packages/lit-table/src/TableController.ts#L118) +Defined in: [packages/lit-table/src/TableController.ts:123](https://github.com/TanStack/table/blob/main/packages/lit-table/src/TableController.ts#L123) A Lit ReactiveController for TanStack Table integration. @@ -56,7 +56,7 @@ class MyTable extends LitElement { new TableController(host): TableController; ``` -Defined in: [packages/lit-table/src/TableController.ts:132](https://github.com/TanStack/table/blob/main/packages/lit-table/src/TableController.ts#L132) +Defined in: [packages/lit-table/src/TableController.ts:145](https://github.com/TanStack/table/blob/main/packages/lit-table/src/TableController.ts#L145) #### Parameters @@ -76,7 +76,7 @@ Defined in: [packages/lit-table/src/TableController.ts:132](https://github.com/T host: ReactiveControllerHost; ``` -Defined in: [packages/lit-table/src/TableController.ts:122](https://github.com/TanStack/table/blob/main/packages/lit-table/src/TableController.ts#L122) +Defined in: [packages/lit-table/src/TableController.ts:127](https://github.com/TanStack/table/blob/main/packages/lit-table/src/TableController.ts#L127) ## Methods @@ -86,7 +86,7 @@ Defined in: [packages/lit-table/src/TableController.ts:122](https://github.com/T hostConnected(): void; ``` -Defined in: [packages/lit-table/src/TableController.ts:238](https://github.com/TanStack/table/blob/main/packages/lit-table/src/TableController.ts#L238) +Defined in: [packages/lit-table/src/TableController.ts:260](https://github.com/TanStack/table/blob/main/packages/lit-table/src/TableController.ts#L260) Called when the host is connected to the component tree. For custom element hosts, this corresponds to the `connectedCallback()` lifecycle, @@ -110,7 +110,7 @@ ReactiveController.hostConnected hostDisconnected(): void; ``` -Defined in: [packages/lit-table/src/TableController.ts:242](https://github.com/TanStack/table/blob/main/packages/lit-table/src/TableController.ts#L242) +Defined in: [packages/lit-table/src/TableController.ts:280](https://github.com/TanStack/table/blob/main/packages/lit-table/src/TableController.ts#L280) Called when the host is disconnected from the component tree. For custom element hosts, this corresponds to the `disconnectedCallback()` lifecycle, @@ -129,13 +129,36 @@ ReactiveController.hostDisconnected *** +### hostUpdated() + +```ts +hostUpdated(): void; +``` + +Defined in: [packages/lit-table/src/TableController.ts:267](https://github.com/TanStack/table/blob/main/packages/lit-table/src/TableController.ts#L267) + +Called after a host update, just before the host calls firstUpdated and +updated. It is not called in server-side rendering. + +#### Returns + +`void` + +#### Implementation of + +```ts +ReactiveController.hostUpdated +``` + +*** + ### table() ```ts table(tableOptions, selector?): LitTable; ``` -Defined in: [packages/lit-table/src/TableController.ts:152](https://github.com/TanStack/table/blob/main/packages/lit-table/src/TableController.ts#L152) +Defined in: [packages/lit-table/src/TableController.ts:165](https://github.com/TanStack/table/blob/main/packages/lit-table/src/TableController.ts#L165) Returns the Lit-backed table instance for the current render pass. diff --git a/docs/framework/lit/reference/functions/FlexRender-1.md b/docs/framework/lit/reference/functions/FlexRender-1.md index 26fe947fd8..c061ec9d2d 100644 --- a/docs/framework/lit/reference/functions/FlexRender-1.md +++ b/docs/framework/lit/reference/functions/FlexRender-1.md @@ -6,10 +6,10 @@ title: FlexRender # Function: FlexRender() ```ts -function FlexRender(props): string | TemplateResult | null; +function FlexRender(props): LitRenderable; ``` -Defined in: [packages/lit-table/src/flexRender.ts:90](https://github.com/TanStack/table/blob/main/packages/lit-table/src/flexRender.ts#L90) +Defined in: [packages/lit-table/src/flexRender.ts:101](https://github.com/TanStack/table/blob/main/packages/lit-table/src/flexRender.ts#L101) Simplified component wrapper of `flexRender`. Use this utility function to render headers, cells, or footers with custom markup. Only one prop (`cell`, `header`, or `footer`) may be passed. @@ -36,7 +36,7 @@ Only one prop (`cell`, `header`, or `footer`) may be passed. ## Returns -`string` \| `TemplateResult` \| `null` +[`LitRenderable`](../type-aliases/LitRenderable.md) ## Example diff --git a/docs/framework/lit/reference/functions/createTableHook.md b/docs/framework/lit/reference/functions/createTableHook.md index 6167c70940..3272de93ba 100644 --- a/docs/framework/lit/reference/functions/createTableHook.md +++ b/docs/framework/lit/reference/functions/createTableHook.md @@ -9,7 +9,7 @@ title: createTableHook function createTableHook(__namedParameters): CreateTableHookResult; ``` -Defined in: [packages/lit-table/src/createTableHook.ts:503](https://github.com/TanStack/table/blob/main/packages/lit-table/src/createTableHook.ts#L503) +Defined in: [packages/lit-table/src/createTableHook.ts:504](https://github.com/TanStack/table/blob/main/packages/lit-table/src/createTableHook.ts#L504) Creates a custom table hook with pre-bound components for composition. diff --git a/docs/framework/lit/reference/functions/flexRender.md b/docs/framework/lit/reference/functions/flexRender.md index cf133cdc28..883d93927f 100644 --- a/docs/framework/lit/reference/functions/flexRender.md +++ b/docs/framework/lit/reference/functions/flexRender.md @@ -6,10 +6,10 @@ title: flexRender # Function: flexRender() ```ts -function flexRender(Comp, props): string | TemplateResult | null; +function flexRender(Comp, props): LitRenderable; ``` -Defined in: [packages/lit-table/src/flexRender.ts:22](https://github.com/TanStack/table/blob/main/packages/lit-table/src/flexRender.ts#L22) +Defined in: [packages/lit-table/src/flexRender.ts:37](https://github.com/TanStack/table/blob/main/packages/lit-table/src/flexRender.ts#L37) Renders a Lit table template value with the provided context props. @@ -27,7 +27,7 @@ convenience wrapper for table cell/header/footer objects. ### Comp -`string` | `TemplateResult` | (`props`) => `string` \| `TemplateResult` | `undefined` +[`LitRenderable`](../type-aliases/LitRenderable.md) | (`props`) => [`LitRenderable`](../type-aliases/LitRenderable.md) ### props @@ -35,7 +35,7 @@ convenience wrapper for table cell/header/footer objects. ## Returns -`string` \| `TemplateResult` \| `null` +[`LitRenderable`](../type-aliases/LitRenderable.md) ## Example diff --git a/docs/framework/lit/reference/index.md b/docs/framework/lit/reference/index.md index e0cabbd6ce..5517c61193 100644 --- a/docs/framework/lit/reference/index.md +++ b/docs/framework/lit/reference/index.md @@ -28,6 +28,7 @@ title: "@tanstack/lit-table" - [ComponentType](type-aliases/ComponentType.md) - [CreateTableHookOptions](type-aliases/CreateTableHookOptions.md) - [FlexRenderProps](type-aliases/FlexRenderProps.md) +- [LitRenderable](type-aliases/LitRenderable.md) - [LitTable](type-aliases/LitTable.md) - [SelectionSource](type-aliases/SelectionSource.md) diff --git a/docs/framework/lit/reference/interfaces/CreateTableHookResult.md b/docs/framework/lit/reference/interfaces/CreateTableHookResult.md index 2c6bc65772..4aea227a2e 100644 --- a/docs/framework/lit/reference/interfaces/CreateTableHookResult.md +++ b/docs/framework/lit/reference/interfaces/CreateTableHookResult.md @@ -5,7 +5,7 @@ title: CreateTableHookResult # Interface: CreateTableHookResult\ -Defined in: [packages/lit-table/src/createTableHook.ts:358](https://github.com/TanStack/table/blob/main/packages/lit-table/src/createTableHook.ts#L358) +Defined in: [packages/lit-table/src/createTableHook.ts:359](https://github.com/TanStack/table/blob/main/packages/lit-table/src/createTableHook.ts#L359) ## Type Parameters @@ -33,7 +33,7 @@ Defined in: [packages/lit-table/src/createTableHook.ts:358](https://github.com/T appFeatures: TFeatures; ``` -Defined in: [packages/lit-table/src/createTableHook.ts:365](https://github.com/TanStack/table/blob/main/packages/lit-table/src/createTableHook.ts#L365) +Defined in: [packages/lit-table/src/createTableHook.ts:366](https://github.com/TanStack/table/blob/main/packages/lit-table/src/createTableHook.ts#L366) The features object that was passed to `createTableHook`. @@ -45,7 +45,7 @@ The features object that was passed to `createTableHook`. createAppColumnHelper: () => AppColumnHelper; ``` -Defined in: [packages/lit-table/src/createTableHook.ts:370](https://github.com/TanStack/table/blob/main/packages/lit-table/src/createTableHook.ts#L370) +Defined in: [packages/lit-table/src/createTableHook.ts:371](https://github.com/TanStack/table/blob/main/packages/lit-table/src/createTableHook.ts#L371) A column helper pre-bound to `TFeatures` and the registered components, so the cell/header/footer render props expose the bound components. @@ -68,7 +68,7 @@ the cell/header/footer render props expose the bound components. useAppTable: (host, tableOptions, selector?) => object; ``` -Defined in: [packages/lit-table/src/createTableHook.ts:381](https://github.com/TanStack/table/blob/main/packages/lit-table/src/createTableHook.ts#L381) +Defined in: [packages/lit-table/src/createTableHook.ts:382](https://github.com/TanStack/table/blob/main/packages/lit-table/src/createTableHook.ts#L382) Creates a controller-like object whose `table()` method returns a table with the `App*` wrapper functions, a bound `FlexRender`, and the registered @@ -120,7 +120,7 @@ table: () => AppLitTable(host) => ContextConsumer>, ReactiveControllerHost & HTMLElement>; ``` -Defined in: [packages/lit-table/src/createTableHook.ts:410](https://github.com/TanStack/table/blob/main/packages/lit-table/src/createTableHook.ts#L410) +Defined in: [packages/lit-table/src/createTableHook.ts:411](https://github.com/TanStack/table/blob/main/packages/lit-table/src/createTableHook.ts#L411) Reads the cell instance from a `@lit/context` `ContextConsumer`. lit never provides an extended cell through context, so this is a BARE `Cell`. @@ -149,7 +149,7 @@ provides an extended cell through context, so this is a BARE `Cell`. useHeaderContext: (host) => ContextConsumer>, ReactiveControllerHost & HTMLElement>; ``` -Defined in: [packages/lit-table/src/createTableHook.ts:420](https://github.com/TanStack/table/blob/main/packages/lit-table/src/createTableHook.ts#L420) +Defined in: [packages/lit-table/src/createTableHook.ts:421](https://github.com/TanStack/table/blob/main/packages/lit-table/src/createTableHook.ts#L421) Reads the header instance from a `@lit/context` `ContextConsumer`. lit never provides an extended header through context, so this is a BARE `Header`. @@ -178,7 +178,7 @@ provides an extended header through context, so this is a BARE `Header`. useTableContext: (host) => ContextConsumer>, ReactiveControllerHost & HTMLElement>; ``` -Defined in: [packages/lit-table/src/createTableHook.ts:400](https://github.com/TanStack/table/blob/main/packages/lit-table/src/createTableHook.ts#L400) +Defined in: [packages/lit-table/src/createTableHook.ts:401](https://github.com/TanStack/table/blob/main/packages/lit-table/src/createTableHook.ts#L401) Reads the table provided by the nearest ancestor that called `useAppTable`, via a `@lit/context` `ContextConsumer`. This is the BARE `LitTable` written diff --git a/docs/framework/lit/reference/type-aliases/AppCellContext.md b/docs/framework/lit/reference/type-aliases/AppCellContext.md index 7e013ef7fb..05e996c13c 100644 --- a/docs/framework/lit/reference/type-aliases/AppCellContext.md +++ b/docs/framework/lit/reference/type-aliases/AppCellContext.md @@ -9,7 +9,7 @@ title: AppCellContext type AppCellContext = object; ``` -Defined in: [packages/lit-table/src/createTableHook.ts:48](https://github.com/TanStack/table/blob/main/packages/lit-table/src/createTableHook.ts#L48) +Defined in: [packages/lit-table/src/createTableHook.ts:49](https://github.com/TanStack/table/blob/main/packages/lit-table/src/createTableHook.ts#L49) Enhanced CellContext with pre-bound cell components. The `cell` property includes the registered cellComponents. @@ -40,19 +40,19 @@ The `cell` property includes the registered cellComponents. cell: Cell & BoundComponents & object; ``` -Defined in: [packages/lit-table/src/createTableHook.ts:54](https://github.com/TanStack/table/blob/main/packages/lit-table/src/createTableHook.ts#L54) +Defined in: [packages/lit-table/src/createTableHook.ts:55](https://github.com/TanStack/table/blob/main/packages/lit-table/src/createTableHook.ts#L55) #### Type Declaration ##### FlexRender() ```ts -FlexRender: () => TemplateResult | string | null; +FlexRender: () => LitRenderable; ``` ###### Returns -`TemplateResult` \| `string` \| `null` +[`LitRenderable`](LitRenderable.md) *** @@ -62,7 +62,7 @@ FlexRender: () => TemplateResult | string | null; column: Column; ``` -Defined in: [packages/lit-table/src/createTableHook.ts:58](https://github.com/TanStack/table/blob/main/packages/lit-table/src/createTableHook.ts#L58) +Defined in: [packages/lit-table/src/createTableHook.ts:59](https://github.com/TanStack/table/blob/main/packages/lit-table/src/createTableHook.ts#L59) *** @@ -72,7 +72,7 @@ Defined in: [packages/lit-table/src/createTableHook.ts:58](https://github.com/Ta getValue: CellContext["getValue"]; ``` -Defined in: [packages/lit-table/src/createTableHook.ts:59](https://github.com/TanStack/table/blob/main/packages/lit-table/src/createTableHook.ts#L59) +Defined in: [packages/lit-table/src/createTableHook.ts:60](https://github.com/TanStack/table/blob/main/packages/lit-table/src/createTableHook.ts#L60) *** @@ -82,7 +82,7 @@ Defined in: [packages/lit-table/src/createTableHook.ts:59](https://github.com/Ta renderValue: CellContext["renderValue"]; ``` -Defined in: [packages/lit-table/src/createTableHook.ts:60](https://github.com/TanStack/table/blob/main/packages/lit-table/src/createTableHook.ts#L60) +Defined in: [packages/lit-table/src/createTableHook.ts:61](https://github.com/TanStack/table/blob/main/packages/lit-table/src/createTableHook.ts#L61) *** @@ -92,7 +92,7 @@ Defined in: [packages/lit-table/src/createTableHook.ts:60](https://github.com/Ta row: Row; ``` -Defined in: [packages/lit-table/src/createTableHook.ts:61](https://github.com/TanStack/table/blob/main/packages/lit-table/src/createTableHook.ts#L61) +Defined in: [packages/lit-table/src/createTableHook.ts:62](https://github.com/TanStack/table/blob/main/packages/lit-table/src/createTableHook.ts#L62) *** @@ -102,4 +102,4 @@ Defined in: [packages/lit-table/src/createTableHook.ts:61](https://github.com/Ta table: Table; ``` -Defined in: [packages/lit-table/src/createTableHook.ts:62](https://github.com/TanStack/table/blob/main/packages/lit-table/src/createTableHook.ts#L62) +Defined in: [packages/lit-table/src/createTableHook.ts:63](https://github.com/TanStack/table/blob/main/packages/lit-table/src/createTableHook.ts#L63) diff --git a/docs/framework/lit/reference/type-aliases/AppColumnDefBase.md b/docs/framework/lit/reference/type-aliases/AppColumnDefBase.md index bfc76c591c..44646f83b6 100644 --- a/docs/framework/lit/reference/type-aliases/AppColumnDefBase.md +++ b/docs/framework/lit/reference/type-aliases/AppColumnDefBase.md @@ -9,7 +9,7 @@ title: AppColumnDefBase type AppColumnDefBase = Omit, "cell" | "header" | "footer"> & object; ``` -Defined in: [packages/lit-table/src/createTableHook.ts:97](https://github.com/TanStack/table/blob/main/packages/lit-table/src/createTableHook.ts#L97) +Defined in: [packages/lit-table/src/createTableHook.ts:98](https://github.com/TanStack/table/blob/main/packages/lit-table/src/createTableHook.ts#L98) Enhanced column definition base with pre-bound components in cell/header/footer contexts. diff --git a/docs/framework/lit/reference/type-aliases/AppColumnDefTemplate.md b/docs/framework/lit/reference/type-aliases/AppColumnDefTemplate.md index 10e2a5e356..94ea5c6c65 100644 --- a/docs/framework/lit/reference/type-aliases/AppColumnDefTemplate.md +++ b/docs/framework/lit/reference/type-aliases/AppColumnDefTemplate.md @@ -9,7 +9,7 @@ title: AppColumnDefTemplate type AppColumnDefTemplate = string | (props) => any; ``` -Defined in: [packages/lit-table/src/createTableHook.ts:90](https://github.com/TanStack/table/blob/main/packages/lit-table/src/createTableHook.ts#L90) +Defined in: [packages/lit-table/src/createTableHook.ts:91](https://github.com/TanStack/table/blob/main/packages/lit-table/src/createTableHook.ts#L91) Template type for column definitions that can be a string or a function. diff --git a/docs/framework/lit/reference/type-aliases/AppColumnHelper.md b/docs/framework/lit/reference/type-aliases/AppColumnHelper.md index 267fff63b1..352dc3f684 100644 --- a/docs/framework/lit/reference/type-aliases/AppColumnHelper.md +++ b/docs/framework/lit/reference/type-aliases/AppColumnHelper.md @@ -9,7 +9,7 @@ title: AppColumnHelper type AppColumnHelper = object; ``` -Defined in: [packages/lit-table/src/createTableHook.ts:173](https://github.com/TanStack/table/blob/main/packages/lit-table/src/createTableHook.ts#L173) +Defined in: [packages/lit-table/src/createTableHook.ts:174](https://github.com/TanStack/table/blob/main/packages/lit-table/src/createTableHook.ts#L174) Enhanced column helper with pre-bound components in cell/header/footer contexts. This enables TypeScript to know about the registered components when defining columns. @@ -40,7 +40,7 @@ This enables TypeScript to know about the registered components when defining co accessor: (accessor, column) => TAccessor extends AccessorFn ? AccessorFnColumnDef : AccessorKeyColumnDef; ``` -Defined in: [packages/lit-table/src/createTableHook.ts:183](https://github.com/TanStack/table/blob/main/packages/lit-table/src/createTableHook.ts#L183) +Defined in: [packages/lit-table/src/createTableHook.ts:184](https://github.com/TanStack/table/blob/main/packages/lit-table/src/createTableHook.ts#L184) Creates a data column definition with an accessor key or function. The cell, header, and footer contexts include pre-bound components. @@ -77,7 +77,7 @@ The cell, header, and footer contexts include pre-bound components. columns: (columns) => ColumnDef[] & [...TColumns]; ``` -Defined in: [packages/lit-table/src/createTableHook.ts:214](https://github.com/TanStack/table/blob/main/packages/lit-table/src/createTableHook.ts#L214) +Defined in: [packages/lit-table/src/createTableHook.ts:215](https://github.com/TanStack/table/blob/main/packages/lit-table/src/createTableHook.ts#L215) Wraps an array of column definitions to preserve each column's individual TValue type. @@ -105,7 +105,7 @@ Wraps an array of column definitions to preserve each column's individual TValue display: (column) => DisplayColumnDef; ``` -Defined in: [packages/lit-table/src/createTableHook.ts:222](https://github.com/TanStack/table/blob/main/packages/lit-table/src/createTableHook.ts#L222) +Defined in: [packages/lit-table/src/createTableHook.ts:223](https://github.com/TanStack/table/blob/main/packages/lit-table/src/createTableHook.ts#L223) Creates a display column definition for non-data columns. The cell, header, and footer contexts include pre-bound components. @@ -128,7 +128,7 @@ The cell, header, and footer contexts include pre-bound components. group: (column) => GroupColumnDef; ``` -Defined in: [packages/lit-table/src/createTableHook.ts:235](https://github.com/TanStack/table/blob/main/packages/lit-table/src/createTableHook.ts#L235) +Defined in: [packages/lit-table/src/createTableHook.ts:236](https://github.com/TanStack/table/blob/main/packages/lit-table/src/createTableHook.ts#L236) Creates a group column definition with nested child columns. The cell, header, and footer contexts include pre-bound components. diff --git a/docs/framework/lit/reference/type-aliases/AppDisplayColumnDef.md b/docs/framework/lit/reference/type-aliases/AppDisplayColumnDef.md index 7f80e00a3a..cf84752256 100644 --- a/docs/framework/lit/reference/type-aliases/AppDisplayColumnDef.md +++ b/docs/framework/lit/reference/type-aliases/AppDisplayColumnDef.md @@ -9,7 +9,7 @@ title: AppDisplayColumnDef type AppDisplayColumnDef = Omit, "cell" | "header" | "footer"> & object; ``` -Defined in: [packages/lit-table/src/createTableHook.ts:121](https://github.com/TanStack/table/blob/main/packages/lit-table/src/createTableHook.ts#L121) +Defined in: [packages/lit-table/src/createTableHook.ts:122](https://github.com/TanStack/table/blob/main/packages/lit-table/src/createTableHook.ts#L122) Enhanced display column definition with pre-bound components. diff --git a/docs/framework/lit/reference/type-aliases/AppGroupColumnDef.md b/docs/framework/lit/reference/type-aliases/AppGroupColumnDef.md index 69c0e75c2e..70bc3f0507 100644 --- a/docs/framework/lit/reference/type-aliases/AppGroupColumnDef.md +++ b/docs/framework/lit/reference/type-aliases/AppGroupColumnDef.md @@ -9,7 +9,7 @@ title: AppGroupColumnDef type AppGroupColumnDef = Omit, "cell" | "header" | "footer" | "columns"> & object; ``` -Defined in: [packages/lit-table/src/createTableHook.ts:144](https://github.com/TanStack/table/blob/main/packages/lit-table/src/createTableHook.ts#L144) +Defined in: [packages/lit-table/src/createTableHook.ts:145](https://github.com/TanStack/table/blob/main/packages/lit-table/src/createTableHook.ts#L145) Enhanced group column definition with pre-bound components. @@ -24,7 +24,7 @@ optional cell: AppColumnDefTemplate[]; +optional columns: ReadonlyArray>; ``` ### footer? diff --git a/docs/framework/lit/reference/type-aliases/AppHeaderContext.md b/docs/framework/lit/reference/type-aliases/AppHeaderContext.md index a2da9caa18..46e6eb056b 100644 --- a/docs/framework/lit/reference/type-aliases/AppHeaderContext.md +++ b/docs/framework/lit/reference/type-aliases/AppHeaderContext.md @@ -9,7 +9,7 @@ title: AppHeaderContext type AppHeaderContext = object; ``` -Defined in: [packages/lit-table/src/createTableHook.ts:69](https://github.com/TanStack/table/blob/main/packages/lit-table/src/createTableHook.ts#L69) +Defined in: [packages/lit-table/src/createTableHook.ts:70](https://github.com/TanStack/table/blob/main/packages/lit-table/src/createTableHook.ts#L70) Enhanced HeaderContext with pre-bound header components. The `header` property includes the registered headerComponents. @@ -40,7 +40,7 @@ The `header` property includes the registered headerComponents. column: Column; ``` -Defined in: [packages/lit-table/src/createTableHook.ts:75](https://github.com/TanStack/table/blob/main/packages/lit-table/src/createTableHook.ts#L75) +Defined in: [packages/lit-table/src/createTableHook.ts:76](https://github.com/TanStack/table/blob/main/packages/lit-table/src/createTableHook.ts#L76) *** @@ -50,19 +50,19 @@ Defined in: [packages/lit-table/src/createTableHook.ts:75](https://github.com/Ta header: Header & BoundComponents & object; ``` -Defined in: [packages/lit-table/src/createTableHook.ts:76](https://github.com/TanStack/table/blob/main/packages/lit-table/src/createTableHook.ts#L76) +Defined in: [packages/lit-table/src/createTableHook.ts:77](https://github.com/TanStack/table/blob/main/packages/lit-table/src/createTableHook.ts#L77) #### Type Declaration ##### FlexRender() ```ts -FlexRender: () => TemplateResult | string | null; +FlexRender: () => LitRenderable; ``` ###### Returns -`TemplateResult` \| `string` \| `null` +[`LitRenderable`](LitRenderable.md) *** @@ -72,4 +72,4 @@ FlexRender: () => TemplateResult | string | null; table: Table; ``` -Defined in: [packages/lit-table/src/createTableHook.ts:80](https://github.com/TanStack/table/blob/main/packages/lit-table/src/createTableHook.ts#L80) +Defined in: [packages/lit-table/src/createTableHook.ts:81](https://github.com/TanStack/table/blob/main/packages/lit-table/src/createTableHook.ts#L81) diff --git a/docs/framework/lit/reference/type-aliases/AppLitTable.md b/docs/framework/lit/reference/type-aliases/AppLitTable.md index 2d74a6aa64..040021f8e1 100644 --- a/docs/framework/lit/reference/type-aliases/AppLitTable.md +++ b/docs/framework/lit/reference/type-aliases/AppLitTable.md @@ -9,7 +9,7 @@ title: AppLitTable type AppLitTable = LitTable & NoInfer & object; ``` -Defined in: [packages/lit-table/src/createTableHook.ts:288](https://github.com/TanStack/table/blob/main/packages/lit-table/src/createTableHook.ts#L288) +Defined in: [packages/lit-table/src/createTableHook.ts:289](https://github.com/TanStack/table/blob/main/packages/lit-table/src/createTableHook.ts#L289) Extended table API returned by useAppTable with all App wrapper functions @@ -18,7 +18,7 @@ Extended table API returned by useAppTable with all App wrapper functions ### AppCell() ```ts -AppCell: (cell, renderFn) => TemplateResult | string; +AppCell: (cell, renderFn) => LitRenderable; ``` Wraps a cell and provides cell context with pre-bound cellComponents. @@ -37,11 +37,11 @@ Wraps a cell and provides cell context with pre-bound cellComponents. ##### renderFn -(`cell`) => `TemplateResult` \| `string` +(`cell`) => [`LitRenderable`](LitRenderable.md) #### Returns -`TemplateResult` \| `string` +[`LitRenderable`](LitRenderable.md) #### Example @@ -52,7 +52,7 @@ ${table.AppCell(cell, (c) => html`${c.FlexRender()}`)} ### AppFooter() ```ts -AppFooter: (header, renderFn) => TemplateResult | string; +AppFooter: (header, renderFn) => LitRenderable; ``` Wraps a footer and provides header context with pre-bound headerComponents. @@ -71,11 +71,11 @@ Wraps a footer and provides header context with pre-bound headerComponents. ##### renderFn -(`header`) => `TemplateResult` \| `string` +(`header`) => [`LitRenderable`](LitRenderable.md) #### Returns -`TemplateResult` \| `string` +[`LitRenderable`](LitRenderable.md) #### Example @@ -86,7 +86,7 @@ ${table.AppFooter(footer, (f) => html`${f.FlexRender()}`)} ### AppHeader() ```ts -AppHeader: (header, renderFn) => TemplateResult | string; +AppHeader: (header, renderFn) => LitRenderable; ``` Wraps a header and provides header context with pre-bound headerComponents. @@ -105,11 +105,11 @@ Wraps a header and provides header context with pre-bound headerComponents. ##### renderFn -(`header`) => `TemplateResult` \| `string` +(`header`) => [`LitRenderable`](LitRenderable.md) #### Returns -`TemplateResult` \| `string` +[`LitRenderable`](LitRenderable.md) #### Example diff --git a/docs/framework/lit/reference/type-aliases/BoundComponents.md b/docs/framework/lit/reference/type-aliases/BoundComponents.md index 6e602b3638..07e84c5124 100644 --- a/docs/framework/lit/reference/type-aliases/BoundComponents.md +++ b/docs/framework/lit/reference/type-aliases/BoundComponents.md @@ -9,7 +9,7 @@ title: BoundComponents type BoundComponents = { [TKey in keyof TComponents]: () => ReturnType }; ``` -Defined in: [packages/lit-table/src/createTableHook.ts:34](https://github.com/TanStack/table/blob/main/packages/lit-table/src/createTableHook.ts#L34) +Defined in: [packages/lit-table/src/createTableHook.ts:35](https://github.com/TanStack/table/blob/main/packages/lit-table/src/createTableHook.ts#L35) ## Type Parameters diff --git a/docs/framework/lit/reference/type-aliases/ComponentType.md b/docs/framework/lit/reference/type-aliases/ComponentType.md index 37cb672734..8bb2f9aa9f 100644 --- a/docs/framework/lit/reference/type-aliases/ComponentType.md +++ b/docs/framework/lit/reference/type-aliases/ComponentType.md @@ -9,7 +9,7 @@ title: ComponentType type ComponentType = (props) => any; ``` -Defined in: [packages/lit-table/src/createTableHook.ts:32](https://github.com/TanStack/table/blob/main/packages/lit-table/src/createTableHook.ts#L32) +Defined in: [packages/lit-table/src/createTableHook.ts:33](https://github.com/TanStack/table/blob/main/packages/lit-table/src/createTableHook.ts#L33) ## Type Parameters diff --git a/docs/framework/lit/reference/type-aliases/CreateTableHookOptions.md b/docs/framework/lit/reference/type-aliases/CreateTableHookOptions.md index cc8073add5..d918364ed1 100644 --- a/docs/framework/lit/reference/type-aliases/CreateTableHookOptions.md +++ b/docs/framework/lit/reference/type-aliases/CreateTableHookOptions.md @@ -9,7 +9,7 @@ title: CreateTableHookOptions type CreateTableHookOptions = Omit, "columns" | "data" | "store" | "state" | "initialState"> & object; ``` -Defined in: [packages/lit-table/src/createTableHook.ts:253](https://github.com/TanStack/table/blob/main/packages/lit-table/src/createTableHook.ts#L253) +Defined in: [packages/lit-table/src/createTableHook.ts:254](https://github.com/TanStack/table/blob/main/packages/lit-table/src/createTableHook.ts#L254) Options for creating a table hook with pre-bound components and default table options. Extends all TableOptions except 'columns' | 'data' | 'store' | 'state' | 'initialState'. diff --git a/docs/framework/lit/reference/type-aliases/FlexRenderProps.md b/docs/framework/lit/reference/type-aliases/FlexRenderProps.md index 39711fc8c5..6449a0df72 100644 --- a/docs/framework/lit/reference/type-aliases/FlexRenderProps.md +++ b/docs/framework/lit/reference/type-aliases/FlexRenderProps.md @@ -24,7 +24,7 @@ type FlexRenderProps = }; ``` -Defined in: [packages/lit-table/src/flexRender.ts:56](https://github.com/TanStack/table/blob/main/packages/lit-table/src/flexRender.ts#L56) +Defined in: [packages/lit-table/src/flexRender.ts:67](https://github.com/TanStack/table/blob/main/packages/lit-table/src/flexRender.ts#L67) Simplified component wrapper of `flexRender`. Use this utility function to render headers, cells, or footers with custom markup. Only one prop (`cell`, `header`, or `footer`) may be passed. diff --git a/docs/framework/lit/reference/type-aliases/LitRenderable.md b/docs/framework/lit/reference/type-aliases/LitRenderable.md new file mode 100644 index 0000000000..f471ca81ba --- /dev/null +++ b/docs/framework/lit/reference/type-aliases/LitRenderable.md @@ -0,0 +1,24 @@ +--- +id: LitRenderable +title: LitRenderable +--- + +# Type Alias: LitRenderable + +```ts +type LitRenderable = + | TemplateResult + | DirectiveResult + | Node + | string + | number + | bigint + | boolean + | null + | undefined + | typeof nothing + | typeof noChange +| Iterable; +``` + +Defined in: [packages/lit-table/src/flexRender.ts:11](https://github.com/TanStack/table/blob/main/packages/lit-table/src/flexRender.ts#L11) diff --git a/docs/framework/lit/reference/type-aliases/LitTable.md b/docs/framework/lit/reference/type-aliases/LitTable.md index ac6715de90..64a961162f 100644 --- a/docs/framework/lit/reference/type-aliases/LitTable.md +++ b/docs/framework/lit/reference/type-aliases/LitTable.md @@ -9,7 +9,7 @@ title: LitTable type LitTable = Omit, "store"> & object; ``` -Defined in: [packages/lit-table/src/TableController.ts:21](https://github.com/TanStack/table/blob/main/packages/lit-table/src/TableController.ts#L21) +Defined in: [packages/lit-table/src/TableController.ts:26](https://github.com/TanStack/table/blob/main/packages/lit-table/src/TableController.ts#L26) The extended table type returned by the Lit adapter. Includes a `Subscribe` method for fine-grained state subscriptions diff --git a/docs/framework/lit/reference/variables/subscribe.md b/docs/framework/lit/reference/variables/subscribe.md index 72c84f206b..bc5793186e 100644 --- a/docs/framework/lit/reference/variables/subscribe.md +++ b/docs/framework/lit/reference/variables/subscribe.md @@ -12,7 +12,7 @@ const subscribe: { }; ``` -Defined in: [packages/lit-table/src/subscribe-directive.ts:182](https://github.com/TanStack/table/blob/main/packages/lit-table/src/subscribe-directive.ts#L182) +Defined in: [packages/lit-table/src/subscribe-directive.ts:194](https://github.com/TanStack/table/blob/main/packages/lit-table/src/subscribe-directive.ts#L194) A Lit directive that subscribes to a source (Store or Atom) and efficiently updates only the wrapped template diff --git a/docs/framework/preact/reference/functions/FlexRender-1.md b/docs/framework/preact/reference/functions/FlexRender-1.md index 706c45da04..7f29a39faf 100644 --- a/docs/framework/preact/reference/functions/FlexRender-1.md +++ b/docs/framework/preact/reference/functions/FlexRender-1.md @@ -9,7 +9,7 @@ title: FlexRender function FlexRender(props): ComponentChild; ``` -Defined in: [FlexRender.tsx:98](https://github.com/TanStack/table/blob/main/packages/preact-table/src/FlexRender.tsx#L98) +Defined in: [FlexRender.tsx:101](https://github.com/TanStack/table/blob/main/packages/preact-table/src/FlexRender.tsx#L101) Simplified component wrapper of `flexRender`. Use this utility component to render headers, cells, or footers with custom markup. Only one prop (`cell`, `header`, or `footer`) may be passed. diff --git a/docs/framework/preact/reference/functions/flexRender.md b/docs/framework/preact/reference/functions/flexRender.md index e4ec898268..3b1cabadbf 100644 --- a/docs/framework/preact/reference/functions/flexRender.md +++ b/docs/framework/preact/reference/functions/flexRender.md @@ -9,7 +9,7 @@ title: flexRender function flexRender(Comp, props): ComponentChild | Element; ``` -Defined in: [FlexRender.tsx:46](https://github.com/TanStack/table/blob/main/packages/preact-table/src/FlexRender.tsx#L46) +Defined in: [FlexRender.tsx:49](https://github.com/TanStack/table/blob/main/packages/preact-table/src/FlexRender.tsx#L49) If rendering headers, cells, or footers with custom markup, use flexRender instead of `cell.getValue()` or `cell.renderValue()`. diff --git a/docs/framework/preact/reference/functions/useTable.md b/docs/framework/preact/reference/functions/useTable.md index 8189a123d8..fb1d1da29d 100644 --- a/docs/framework/preact/reference/functions/useTable.md +++ b/docs/framework/preact/reference/functions/useTable.md @@ -9,7 +9,7 @@ title: useTable function useTable(tableOptions, selector?): PreactTable; ``` -Defined in: [useTable.ts:112](https://github.com/TanStack/table/blob/main/packages/preact-table/src/useTable.ts#L112) +Defined in: [useTable.ts:121](https://github.com/TanStack/table/blob/main/packages/preact-table/src/useTable.ts#L121) Creates a Preact table instance backed by TanStack Store atoms. diff --git a/docs/framework/preact/reference/type-aliases/AppGroupColumnDef.md b/docs/framework/preact/reference/type-aliases/AppGroupColumnDef.md index 837a3c58ae..69491cc742 100644 --- a/docs/framework/preact/reference/type-aliases/AppGroupColumnDef.md +++ b/docs/framework/preact/reference/type-aliases/AppGroupColumnDef.md @@ -24,7 +24,7 @@ optional cell: AppColumnDefTemplate[]; +optional columns: ReadonlyArray>; ``` ### footer? diff --git a/docs/framework/preact/reference/type-aliases/FlexRenderProps.md b/docs/framework/preact/reference/type-aliases/FlexRenderProps.md index cfb08d16a6..6d9cc3ebb6 100644 --- a/docs/framework/preact/reference/type-aliases/FlexRenderProps.md +++ b/docs/framework/preact/reference/type-aliases/FlexRenderProps.md @@ -24,7 +24,7 @@ type FlexRenderProps = }; ``` -Defined in: [FlexRender.tsx:64](https://github.com/TanStack/table/blob/main/packages/preact-table/src/FlexRender.tsx#L64) +Defined in: [FlexRender.tsx:67](https://github.com/TanStack/table/blob/main/packages/preact-table/src/FlexRender.tsx#L67) Simplified component wrapper of `flexRender`. Use this utility component to render headers, cells, or footers with custom markup. Only one prop (`cell`, `header`, or `footer`) may be passed. diff --git a/docs/framework/preact/reference/type-aliases/PreactTable.md b/docs/framework/preact/reference/type-aliases/PreactTable.md index a3c552c4ca..af6038701b 100644 --- a/docs/framework/preact/reference/type-aliases/PreactTable.md +++ b/docs/framework/preact/reference/type-aliases/PreactTable.md @@ -9,7 +9,7 @@ title: PreactTable type PreactTable = Omit, "store"> & object; ``` -Defined in: [useTable.ts:19](https://github.com/TanStack/table/blob/main/packages/preact-table/src/useTable.ts#L19) +Defined in: [useTable.ts:27](https://github.com/TanStack/table/blob/main/packages/preact-table/src/useTable.ts#L27) ## Type Declaration diff --git a/docs/framework/preact/reference/type-aliases/SubscribePropsWithSourceIdentity.md b/docs/framework/preact/reference/type-aliases/SubscribePropsWithSourceIdentity.md index 347a1565da..9c28cb587d 100644 --- a/docs/framework/preact/reference/type-aliases/SubscribePropsWithSourceIdentity.md +++ b/docs/framework/preact/reference/type-aliases/SubscribePropsWithSourceIdentity.md @@ -12,7 +12,7 @@ type SubscribePropsWithSourceIdentity = object; Defined in: [Subscribe.ts:42](https://github.com/TanStack/table/blob/main/packages/preact-table/src/Subscribe.ts#L42) Subscribe to the full value of a source (e.g. `table.atoms.rowSelection` or -`table.optionsStore`). Omitting `selector` is equivalent to the identity +`table.optionAtoms.data`). Omitting `selector` is equivalent to the identity selector — children receive `TSourceValue`. ## Type Parameters diff --git a/docs/framework/react/reference/index/functions/useTable.md b/docs/framework/react/reference/index/functions/useTable.md index 7c8a4a1bd6..2aeae10d7a 100644 --- a/docs/framework/react/reference/index/functions/useTable.md +++ b/docs/framework/react/reference/index/functions/useTable.md @@ -9,7 +9,7 @@ title: useTable function useTable(tableOptions, selector?): ReactTable; ``` -Defined in: [useTable.ts:141](https://github.com/TanStack/table/blob/main/packages/react-table/src/useTable.ts#L141) +Defined in: [useTable.ts:150](https://github.com/TanStack/table/blob/main/packages/react-table/src/useTable.ts#L150) Creates a React table instance backed by TanStack Store atoms. diff --git a/docs/framework/react/reference/index/type-aliases/AppGroupColumnDef.md b/docs/framework/react/reference/index/type-aliases/AppGroupColumnDef.md index f5b71eab3b..dbc86d42a4 100644 --- a/docs/framework/react/reference/index/type-aliases/AppGroupColumnDef.md +++ b/docs/framework/react/reference/index/type-aliases/AppGroupColumnDef.md @@ -24,7 +24,7 @@ optional cell: AppColumnDefTemplate[]; +optional columns: ReadonlyArray>; ``` ### footer? diff --git a/docs/framework/react/reference/index/type-aliases/ReactTable.md b/docs/framework/react/reference/index/type-aliases/ReactTable.md index ba687dfb15..b8b448527c 100644 --- a/docs/framework/react/reference/index/type-aliases/ReactTable.md +++ b/docs/framework/react/reference/index/type-aliases/ReactTable.md @@ -9,7 +9,7 @@ title: ReactTable type ReactTable = Omit, "store"> & object; ``` -Defined in: [useTable.ts:21](https://github.com/TanStack/table/blob/main/packages/react-table/src/useTable.ts#L21) +Defined in: [useTable.ts:29](https://github.com/TanStack/table/blob/main/packages/react-table/src/useTable.ts#L29) ## Type Declaration diff --git a/docs/framework/react/reference/index/type-aliases/SubscribePropsWithSourceIdentity.md b/docs/framework/react/reference/index/type-aliases/SubscribePropsWithSourceIdentity.md index 311890ced1..dd0b58b1f5 100644 --- a/docs/framework/react/reference/index/type-aliases/SubscribePropsWithSourceIdentity.md +++ b/docs/framework/react/reference/index/type-aliases/SubscribePropsWithSourceIdentity.md @@ -12,7 +12,7 @@ type SubscribePropsWithSourceIdentity = object; Defined in: [Subscribe.ts:44](https://github.com/TanStack/table/blob/main/packages/react-table/src/Subscribe.ts#L44) Subscribe to the full value of a source (e.g. `table.atoms.rowSelection` or -`table.optionsStore`). Omitting `selector` is equivalent to the identity +`table.optionAtoms.data`). Omitting `selector` is equivalent to the identity selector — children receive `TSourceValue`. ## Type Parameters diff --git a/docs/framework/solid/reference/functions/createTable.md b/docs/framework/solid/reference/functions/createTable.md index a1c36de618..02136dce64 100644 --- a/docs/framework/solid/reference/functions/createTable.md +++ b/docs/framework/solid/reference/functions/createTable.md @@ -9,7 +9,7 @@ title: createTable function createTable(tableOptions): SolidTable; ``` -Defined in: [createTable.ts:61](https://github.com/TanStack/table/blob/main/packages/solid-table/src/createTable.ts#L61) +Defined in: [createTable.ts:56](https://github.com/TanStack/table/blob/main/packages/solid-table/src/createTable.ts#L56) Creates a Solid table instance backed by Solid-aware TanStack Store atoms. diff --git a/docs/framework/solid/reference/functions/createTableHook.md b/docs/framework/solid/reference/functions/createTableHook.md index b98e83ae7c..0638d6f940 100644 --- a/docs/framework/solid/reference/functions/createTableHook.md +++ b/docs/framework/solid/reference/functions/createTableHook.md @@ -9,7 +9,7 @@ title: createTableHook function createTableHook(__namedParameters): CreateTableHookResult; ``` -Defined in: [createTableHook.tsx:572](https://github.com/TanStack/table/blob/main/packages/solid-table/src/createTableHook.tsx#L572) +Defined in: [createTableHook.tsx:573](https://github.com/TanStack/table/blob/main/packages/solid-table/src/createTableHook.tsx#L573) Creates a custom table hook with pre-bound components for composition. diff --git a/docs/framework/solid/reference/interfaces/AppCellComponent.md b/docs/framework/solid/reference/interfaces/AppCellComponent.md index 36c2b4f784..3e59c43cb3 100644 --- a/docs/framework/solid/reference/interfaces/AppCellComponent.md +++ b/docs/framework/solid/reference/interfaces/AppCellComponent.md @@ -5,7 +5,7 @@ title: AppCellComponent # Interface: AppCellComponent()\ -Defined in: [createTableHook.tsx:312](https://github.com/TanStack/table/blob/main/packages/solid-table/src/createTableHook.tsx#L312) +Defined in: [createTableHook.tsx:313](https://github.com/TanStack/table/blob/main/packages/solid-table/src/createTableHook.tsx#L313) Component type for AppCell - wraps a cell and provides cell context. @@ -27,7 +27,7 @@ Component type for AppCell - wraps a cell and provides cell context. AppCellComponent(props): Element; ``` -Defined in: [createTableHook.tsx:317](https://github.com/TanStack/table/blob/main/packages/solid-table/src/createTableHook.tsx#L317) +Defined in: [createTableHook.tsx:318](https://github.com/TanStack/table/blob/main/packages/solid-table/src/createTableHook.tsx#L318) Component type for AppCell - wraps a cell and provides cell context. diff --git a/docs/framework/solid/reference/interfaces/AppCellProps.md b/docs/framework/solid/reference/interfaces/AppCellProps.md index b58addcd4e..35dfe1aa6f 100644 --- a/docs/framework/solid/reference/interfaces/AppCellProps.md +++ b/docs/framework/solid/reference/interfaces/AppCellProps.md @@ -5,7 +5,7 @@ title: AppCellProps # Interface: AppCellProps\ -Defined in: [createTableHook.tsx:280](https://github.com/TanStack/table/blob/main/packages/solid-table/src/createTableHook.tsx#L280) +Defined in: [createTableHook.tsx:281](https://github.com/TanStack/table/blob/main/packages/solid-table/src/createTableHook.tsx#L281) Props for AppCell component. @@ -35,7 +35,7 @@ Props for AppCell component. cell: Cell; ``` -Defined in: [createTableHook.tsx:286](https://github.com/TanStack/table/blob/main/packages/solid-table/src/createTableHook.tsx#L286) +Defined in: [createTableHook.tsx:287](https://github.com/TanStack/table/blob/main/packages/solid-table/src/createTableHook.tsx#L287) *** @@ -45,7 +45,7 @@ Defined in: [createTableHook.tsx:286](https://github.com/TanStack/table/blob/mai children: (cell) => Element; ``` -Defined in: [createTableHook.tsx:287](https://github.com/TanStack/table/blob/main/packages/solid-table/src/createTableHook.tsx#L287) +Defined in: [createTableHook.tsx:288](https://github.com/TanStack/table/blob/main/packages/solid-table/src/createTableHook.tsx#L288) #### Parameters diff --git a/docs/framework/solid/reference/interfaces/AppHeaderComponent.md b/docs/framework/solid/reference/interfaces/AppHeaderComponent.md index 70e2e344c0..d98fe0b707 100644 --- a/docs/framework/solid/reference/interfaces/AppHeaderComponent.md +++ b/docs/framework/solid/reference/interfaces/AppHeaderComponent.md @@ -5,7 +5,7 @@ title: AppHeaderComponent # Interface: AppHeaderComponent()\ -Defined in: [createTableHook.tsx:325](https://github.com/TanStack/table/blob/main/packages/solid-table/src/createTableHook.tsx#L325) +Defined in: [createTableHook.tsx:326](https://github.com/TanStack/table/blob/main/packages/solid-table/src/createTableHook.tsx#L326) Component type for AppHeader/AppFooter - wraps a header and provides header context. @@ -27,7 +27,7 @@ Component type for AppHeader/AppFooter - wraps a header and provides header cont AppHeaderComponent(props): Element; ``` -Defined in: [createTableHook.tsx:330](https://github.com/TanStack/table/blob/main/packages/solid-table/src/createTableHook.tsx#L330) +Defined in: [createTableHook.tsx:331](https://github.com/TanStack/table/blob/main/packages/solid-table/src/createTableHook.tsx#L331) Component type for AppHeader/AppFooter - wraps a header and provides header context. diff --git a/docs/framework/solid/reference/interfaces/AppHeaderProps.md b/docs/framework/solid/reference/interfaces/AppHeaderProps.md index 248070d61c..5ed7f890d7 100644 --- a/docs/framework/solid/reference/interfaces/AppHeaderProps.md +++ b/docs/framework/solid/reference/interfaces/AppHeaderProps.md @@ -5,7 +5,7 @@ title: AppHeaderProps # Interface: AppHeaderProps\ -Defined in: [createTableHook.tsx:296](https://github.com/TanStack/table/blob/main/packages/solid-table/src/createTableHook.tsx#L296) +Defined in: [createTableHook.tsx:297](https://github.com/TanStack/table/blob/main/packages/solid-table/src/createTableHook.tsx#L297) Props for AppHeader/AppFooter component. @@ -35,7 +35,7 @@ Props for AppHeader/AppFooter component. children: (header) => Element; ``` -Defined in: [createTableHook.tsx:303](https://github.com/TanStack/table/blob/main/packages/solid-table/src/createTableHook.tsx#L303) +Defined in: [createTableHook.tsx:304](https://github.com/TanStack/table/blob/main/packages/solid-table/src/createTableHook.tsx#L304) #### Parameters @@ -55,4 +55,4 @@ Defined in: [createTableHook.tsx:303](https://github.com/TanStack/table/blob/mai header: Header; ``` -Defined in: [createTableHook.tsx:302](https://github.com/TanStack/table/blob/main/packages/solid-table/src/createTableHook.tsx#L302) +Defined in: [createTableHook.tsx:303](https://github.com/TanStack/table/blob/main/packages/solid-table/src/createTableHook.tsx#L303) diff --git a/docs/framework/solid/reference/interfaces/AppTableComponent.md b/docs/framework/solid/reference/interfaces/AppTableComponent.md index ac2f7c6e56..1e14d7e009 100644 --- a/docs/framework/solid/reference/interfaces/AppTableComponent.md +++ b/docs/framework/solid/reference/interfaces/AppTableComponent.md @@ -5,7 +5,7 @@ title: AppTableComponent # Interface: AppTableComponent()\<_TFeatures\> -Defined in: [createTableHook.tsx:338](https://github.com/TanStack/table/blob/main/packages/solid-table/src/createTableHook.tsx#L338) +Defined in: [createTableHook.tsx:339](https://github.com/TanStack/table/blob/main/packages/solid-table/src/createTableHook.tsx#L339) Component type for AppTable - root wrapper with optional Subscribe @@ -19,7 +19,7 @@ Component type for AppTable - root wrapper with optional Subscribe AppTableComponent(props): Element; ``` -Defined in: [createTableHook.tsx:339](https://github.com/TanStack/table/blob/main/packages/solid-table/src/createTableHook.tsx#L339) +Defined in: [createTableHook.tsx:340](https://github.com/TanStack/table/blob/main/packages/solid-table/src/createTableHook.tsx#L340) Component type for AppTable - root wrapper with optional Subscribe diff --git a/docs/framework/solid/reference/interfaces/AppTableProps.md b/docs/framework/solid/reference/interfaces/AppTableProps.md index 2f2714e551..d4bd747fa1 100644 --- a/docs/framework/solid/reference/interfaces/AppTableProps.md +++ b/docs/framework/solid/reference/interfaces/AppTableProps.md @@ -5,7 +5,7 @@ title: AppTableProps # Interface: AppTableProps -Defined in: [createTableHook.tsx:273](https://github.com/TanStack/table/blob/main/packages/solid-table/src/createTableHook.tsx#L273) +Defined in: [createTableHook.tsx:274](https://github.com/TanStack/table/blob/main/packages/solid-table/src/createTableHook.tsx#L274) ## Properties @@ -15,4 +15,4 @@ Defined in: [createTableHook.tsx:273](https://github.com/TanStack/table/blob/mai children: Element; ``` -Defined in: [createTableHook.tsx:274](https://github.com/TanStack/table/blob/main/packages/solid-table/src/createTableHook.tsx#L274) +Defined in: [createTableHook.tsx:275](https://github.com/TanStack/table/blob/main/packages/solid-table/src/createTableHook.tsx#L275) diff --git a/docs/framework/solid/reference/interfaces/CreateTableHookResult.md b/docs/framework/solid/reference/interfaces/CreateTableHookResult.md index 660ab4153b..9c2a0af301 100644 --- a/docs/framework/solid/reference/interfaces/CreateTableHookResult.md +++ b/docs/framework/solid/reference/interfaces/CreateTableHookResult.md @@ -5,7 +5,7 @@ title: CreateTableHookResult # Interface: CreateTableHookResult\ -Defined in: [createTableHook.tsx:406](https://github.com/TanStack/table/blob/main/packages/solid-table/src/createTableHook.tsx#L406) +Defined in: [createTableHook.tsx:407](https://github.com/TanStack/table/blob/main/packages/solid-table/src/createTableHook.tsx#L407) ## Type Parameters @@ -33,7 +33,7 @@ Defined in: [createTableHook.tsx:406](https://github.com/TanStack/table/blob/mai appFeatures: TFeatures; ``` -Defined in: [createTableHook.tsx:413](https://github.com/TanStack/table/blob/main/packages/solid-table/src/createTableHook.tsx#L413) +Defined in: [createTableHook.tsx:414](https://github.com/TanStack/table/blob/main/packages/solid-table/src/createTableHook.tsx#L414) The features object that was passed to `createTableHook`. @@ -45,7 +45,7 @@ The features object that was passed to `createTableHook`. createAppColumnHelper: () => AppColumnHelper; ``` -Defined in: [createTableHook.tsx:418](https://github.com/TanStack/table/blob/main/packages/solid-table/src/createTableHook.tsx#L418) +Defined in: [createTableHook.tsx:419](https://github.com/TanStack/table/blob/main/packages/solid-table/src/createTableHook.tsx#L419) A column helper pre-bound to `TFeatures` and the registered components, so the cell/header/footer render props expose the bound components. @@ -68,7 +68,7 @@ the cell/header/footer render props expose the bound components. createAppTable: (tableOptions) => AppSolidTable; ``` -Defined in: [createTableHook.tsx:428](https://github.com/TanStack/table/blob/main/packages/solid-table/src/createTableHook.tsx#L428) +Defined in: [createTableHook.tsx:429](https://github.com/TanStack/table/blob/main/packages/solid-table/src/createTableHook.tsx#L429) Creates a table with the `App*` wrapper components and registered `tableComponents` attached. `TData` is inferred from the `data` option. @@ -97,7 +97,7 @@ Creates a table with the `App*` wrapper components and registered useCellContext: () => Cell_Core & ExtractFeatureMapTypes & TCellComponents & object; ``` -Defined in: [createTableHook.tsx:453](https://github.com/TanStack/table/blob/main/packages/solid-table/src/createTableHook.tsx#L453) +Defined in: [createTableHook.tsx:454](https://github.com/TanStack/table/blob/main/packages/solid-table/src/createTableHook.tsx#L454) Reads the cell provided by the nearest ``, extended with your `cellComponents` and a context-bound `FlexRender`. @@ -120,7 +120,7 @@ Reads the cell provided by the nearest ``, extended with your useHeaderContext: () => Header_Core & ExtractFeatureMapTypes & THeaderComponents & object; ``` -Defined in: [createTableHook.tsx:464](https://github.com/TanStack/table/blob/main/packages/solid-table/src/createTableHook.tsx#L464) +Defined in: [createTableHook.tsx:465](https://github.com/TanStack/table/blob/main/packages/solid-table/src/createTableHook.tsx#L465) Reads the header provided by the nearest `` / ``, extended with your `headerComponents` and a @@ -144,7 +144,7 @@ context-bound `FlexRender`. useTableContext: () => AppSolidTable; ``` -Defined in: [createTableHook.tsx:442](https://github.com/TanStack/table/blob/main/packages/solid-table/src/createTableHook.tsx#L442) +Defined in: [createTableHook.tsx:443](https://github.com/TanStack/table/blob/main/packages/solid-table/src/createTableHook.tsx#L443) Reads the table provided by the nearest ``. This is the same extended instance `createAppTable` returns, so the `App*` components and your diff --git a/docs/framework/solid/reference/type-aliases/AppCellContext.md b/docs/framework/solid/reference/type-aliases/AppCellContext.md index 6d75083acc..3d5fb1e6f2 100644 --- a/docs/framework/solid/reference/type-aliases/AppCellContext.md +++ b/docs/framework/solid/reference/type-aliases/AppCellContext.md @@ -9,7 +9,7 @@ title: AppCellContext type AppCellContext = object; ``` -Defined in: [createTableHook.tsx:40](https://github.com/TanStack/table/blob/main/packages/solid-table/src/createTableHook.tsx#L40) +Defined in: [createTableHook.tsx:41](https://github.com/TanStack/table/blob/main/packages/solid-table/src/createTableHook.tsx#L41) Enhanced CellContext with pre-bound cell components. The `cell` property includes the registered cellComponents. @@ -40,7 +40,7 @@ The `cell` property includes the registered cellComponents. cell: Cell & TCellComponents & object; ``` -Defined in: [createTableHook.tsx:46](https://github.com/TanStack/table/blob/main/packages/solid-table/src/createTableHook.tsx#L46) +Defined in: [createTableHook.tsx:47](https://github.com/TanStack/table/blob/main/packages/solid-table/src/createTableHook.tsx#L47) #### Type Declaration @@ -62,7 +62,7 @@ FlexRender: () => JSXElement; column: Column; ``` -Defined in: [createTableHook.tsx:48](https://github.com/TanStack/table/blob/main/packages/solid-table/src/createTableHook.tsx#L48) +Defined in: [createTableHook.tsx:49](https://github.com/TanStack/table/blob/main/packages/solid-table/src/createTableHook.tsx#L49) *** @@ -72,7 +72,7 @@ Defined in: [createTableHook.tsx:48](https://github.com/TanStack/table/blob/main getValue: CellContext["getValue"]; ``` -Defined in: [createTableHook.tsx:49](https://github.com/TanStack/table/blob/main/packages/solid-table/src/createTableHook.tsx#L49) +Defined in: [createTableHook.tsx:50](https://github.com/TanStack/table/blob/main/packages/solid-table/src/createTableHook.tsx#L50) *** @@ -82,7 +82,7 @@ Defined in: [createTableHook.tsx:49](https://github.com/TanStack/table/blob/main renderValue: CellContext["renderValue"]; ``` -Defined in: [createTableHook.tsx:50](https://github.com/TanStack/table/blob/main/packages/solid-table/src/createTableHook.tsx#L50) +Defined in: [createTableHook.tsx:51](https://github.com/TanStack/table/blob/main/packages/solid-table/src/createTableHook.tsx#L51) *** @@ -92,7 +92,7 @@ Defined in: [createTableHook.tsx:50](https://github.com/TanStack/table/blob/main row: Row; ``` -Defined in: [createTableHook.tsx:51](https://github.com/TanStack/table/blob/main/packages/solid-table/src/createTableHook.tsx#L51) +Defined in: [createTableHook.tsx:52](https://github.com/TanStack/table/blob/main/packages/solid-table/src/createTableHook.tsx#L52) *** @@ -102,4 +102,4 @@ Defined in: [createTableHook.tsx:51](https://github.com/TanStack/table/blob/main table: Table; ``` -Defined in: [createTableHook.tsx:52](https://github.com/TanStack/table/blob/main/packages/solid-table/src/createTableHook.tsx#L52) +Defined in: [createTableHook.tsx:53](https://github.com/TanStack/table/blob/main/packages/solid-table/src/createTableHook.tsx#L53) diff --git a/docs/framework/solid/reference/type-aliases/AppColumnDefBase.md b/docs/framework/solid/reference/type-aliases/AppColumnDefBase.md index 23941c40bc..d1be49650b 100644 --- a/docs/framework/solid/reference/type-aliases/AppColumnDefBase.md +++ b/docs/framework/solid/reference/type-aliases/AppColumnDefBase.md @@ -9,7 +9,7 @@ title: AppColumnDefBase type AppColumnDefBase = Omit, "cell" | "header" | "footer"> & object; ``` -Defined in: [createTableHook.tsx:85](https://github.com/TanStack/table/blob/main/packages/solid-table/src/createTableHook.tsx#L85) +Defined in: [createTableHook.tsx:86](https://github.com/TanStack/table/blob/main/packages/solid-table/src/createTableHook.tsx#L86) Enhanced column definition base with pre-bound components in cell/header/footer contexts. diff --git a/docs/framework/solid/reference/type-aliases/AppColumnDefTemplate.md b/docs/framework/solid/reference/type-aliases/AppColumnDefTemplate.md index 6cf56656da..7988901aef 100644 --- a/docs/framework/solid/reference/type-aliases/AppColumnDefTemplate.md +++ b/docs/framework/solid/reference/type-aliases/AppColumnDefTemplate.md @@ -9,7 +9,7 @@ title: AppColumnDefTemplate type AppColumnDefTemplate = string | (props) => any; ``` -Defined in: [createTableHook.tsx:78](https://github.com/TanStack/table/blob/main/packages/solid-table/src/createTableHook.tsx#L78) +Defined in: [createTableHook.tsx:79](https://github.com/TanStack/table/blob/main/packages/solid-table/src/createTableHook.tsx#L79) Template type for column definitions that can be a string or a function. diff --git a/docs/framework/solid/reference/type-aliases/AppColumnHelper.md b/docs/framework/solid/reference/type-aliases/AppColumnHelper.md index 7a58d5c2b9..be559da935 100644 --- a/docs/framework/solid/reference/type-aliases/AppColumnHelper.md +++ b/docs/framework/solid/reference/type-aliases/AppColumnHelper.md @@ -9,7 +9,7 @@ title: AppColumnHelper type AppColumnHelper = object; ``` -Defined in: [createTableHook.tsx:161](https://github.com/TanStack/table/blob/main/packages/solid-table/src/createTableHook.tsx#L161) +Defined in: [createTableHook.tsx:162](https://github.com/TanStack/table/blob/main/packages/solid-table/src/createTableHook.tsx#L162) Enhanced column helper with pre-bound components in cell/header/footer contexts. This enables TypeScript to know about the registered components when defining columns. @@ -40,7 +40,7 @@ This enables TypeScript to know about the registered components when defining co accessor: (accessor, column) => TAccessor extends AccessorFn ? AccessorFnColumnDef : AccessorKeyColumnDef; ``` -Defined in: [createTableHook.tsx:171](https://github.com/TanStack/table/blob/main/packages/solid-table/src/createTableHook.tsx#L171) +Defined in: [createTableHook.tsx:172](https://github.com/TanStack/table/blob/main/packages/solid-table/src/createTableHook.tsx#L172) Creates a data column definition with an accessor key or function. The cell, header, and footer contexts include pre-bound components. @@ -77,7 +77,7 @@ The cell, header, and footer contexts include pre-bound components. columns: (columns) => ColumnDef[] & [...TColumns]; ``` -Defined in: [createTableHook.tsx:202](https://github.com/TanStack/table/blob/main/packages/solid-table/src/createTableHook.tsx#L202) +Defined in: [createTableHook.tsx:203](https://github.com/TanStack/table/blob/main/packages/solid-table/src/createTableHook.tsx#L203) Wraps an array of column definitions to preserve each column's individual TValue type. @@ -105,7 +105,7 @@ Wraps an array of column definitions to preserve each column's individual TValue display: (column) => DisplayColumnDef; ``` -Defined in: [createTableHook.tsx:210](https://github.com/TanStack/table/blob/main/packages/solid-table/src/createTableHook.tsx#L210) +Defined in: [createTableHook.tsx:211](https://github.com/TanStack/table/blob/main/packages/solid-table/src/createTableHook.tsx#L211) Creates a display column definition for non-data columns. The cell, header, and footer contexts include pre-bound components. @@ -128,7 +128,7 @@ The cell, header, and footer contexts include pre-bound components. group: (column) => GroupColumnDef; ``` -Defined in: [createTableHook.tsx:223](https://github.com/TanStack/table/blob/main/packages/solid-table/src/createTableHook.tsx#L223) +Defined in: [createTableHook.tsx:224](https://github.com/TanStack/table/blob/main/packages/solid-table/src/createTableHook.tsx#L224) Creates a group column definition with nested child columns. The cell, header, and footer contexts include pre-bound components. diff --git a/docs/framework/solid/reference/type-aliases/AppDisplayColumnDef.md b/docs/framework/solid/reference/type-aliases/AppDisplayColumnDef.md index 359ad0db24..262b9431d6 100644 --- a/docs/framework/solid/reference/type-aliases/AppDisplayColumnDef.md +++ b/docs/framework/solid/reference/type-aliases/AppDisplayColumnDef.md @@ -9,7 +9,7 @@ title: AppDisplayColumnDef type AppDisplayColumnDef = Omit, "cell" | "header" | "footer"> & object; ``` -Defined in: [createTableHook.tsx:109](https://github.com/TanStack/table/blob/main/packages/solid-table/src/createTableHook.tsx#L109) +Defined in: [createTableHook.tsx:110](https://github.com/TanStack/table/blob/main/packages/solid-table/src/createTableHook.tsx#L110) Enhanced display column definition with pre-bound components. diff --git a/docs/framework/solid/reference/type-aliases/AppGroupColumnDef.md b/docs/framework/solid/reference/type-aliases/AppGroupColumnDef.md index 53f9d1283f..5335c5af1a 100644 --- a/docs/framework/solid/reference/type-aliases/AppGroupColumnDef.md +++ b/docs/framework/solid/reference/type-aliases/AppGroupColumnDef.md @@ -9,7 +9,7 @@ title: AppGroupColumnDef type AppGroupColumnDef = Omit, "cell" | "header" | "footer" | "columns"> & object; ``` -Defined in: [createTableHook.tsx:132](https://github.com/TanStack/table/blob/main/packages/solid-table/src/createTableHook.tsx#L132) +Defined in: [createTableHook.tsx:133](https://github.com/TanStack/table/blob/main/packages/solid-table/src/createTableHook.tsx#L133) Enhanced group column definition with pre-bound components. @@ -24,7 +24,7 @@ optional cell: AppColumnDefTemplate[]; +optional columns: ReadonlyArray>; ``` ### footer? diff --git a/docs/framework/solid/reference/type-aliases/AppHeaderContext.md b/docs/framework/solid/reference/type-aliases/AppHeaderContext.md index 78bfb65852..63d80f7fb9 100644 --- a/docs/framework/solid/reference/type-aliases/AppHeaderContext.md +++ b/docs/framework/solid/reference/type-aliases/AppHeaderContext.md @@ -9,7 +9,7 @@ title: AppHeaderContext type AppHeaderContext = object; ``` -Defined in: [createTableHook.tsx:59](https://github.com/TanStack/table/blob/main/packages/solid-table/src/createTableHook.tsx#L59) +Defined in: [createTableHook.tsx:60](https://github.com/TanStack/table/blob/main/packages/solid-table/src/createTableHook.tsx#L60) Enhanced HeaderContext with pre-bound header components. The `header` property includes the registered headerComponents. @@ -40,7 +40,7 @@ The `header` property includes the registered headerComponents. column: Column; ``` -Defined in: [createTableHook.tsx:65](https://github.com/TanStack/table/blob/main/packages/solid-table/src/createTableHook.tsx#L65) +Defined in: [createTableHook.tsx:66](https://github.com/TanStack/table/blob/main/packages/solid-table/src/createTableHook.tsx#L66) *** @@ -50,7 +50,7 @@ Defined in: [createTableHook.tsx:65](https://github.com/TanStack/table/blob/main header: Header & THeaderComponents & object; ``` -Defined in: [createTableHook.tsx:66](https://github.com/TanStack/table/blob/main/packages/solid-table/src/createTableHook.tsx#L66) +Defined in: [createTableHook.tsx:67](https://github.com/TanStack/table/blob/main/packages/solid-table/src/createTableHook.tsx#L67) #### Type Declaration @@ -72,4 +72,4 @@ FlexRender: () => JSXElement; table: Table; ``` -Defined in: [createTableHook.tsx:68](https://github.com/TanStack/table/blob/main/packages/solid-table/src/createTableHook.tsx#L68) +Defined in: [createTableHook.tsx:69](https://github.com/TanStack/table/blob/main/packages/solid-table/src/createTableHook.tsx#L69) diff --git a/docs/framework/solid/reference/type-aliases/AppSolidTable.md b/docs/framework/solid/reference/type-aliases/AppSolidTable.md index d4248866c1..f68bf59d1e 100644 --- a/docs/framework/solid/reference/type-aliases/AppSolidTable.md +++ b/docs/framework/solid/reference/type-aliases/AppSolidTable.md @@ -9,7 +9,7 @@ title: AppSolidTable type AppSolidTable = SolidTable & NoInfer & object; ``` -Defined in: [createTableHook.tsx:345](https://github.com/TanStack/table/blob/main/packages/solid-table/src/createTableHook.tsx#L345) +Defined in: [createTableHook.tsx:346](https://github.com/TanStack/table/blob/main/packages/solid-table/src/createTableHook.tsx#L346) Extended table API returned by createAppTable with all App wrapper components diff --git a/docs/framework/solid/reference/type-aliases/ComponentType.md b/docs/framework/solid/reference/type-aliases/ComponentType.md index 21580b21f4..f1dc24b325 100644 --- a/docs/framework/solid/reference/type-aliases/ComponentType.md +++ b/docs/framework/solid/reference/type-aliases/ComponentType.md @@ -9,7 +9,7 @@ title: ComponentType type ComponentType = Component; ``` -Defined in: [createTableHook.tsx:30](https://github.com/TanStack/table/blob/main/packages/solid-table/src/createTableHook.tsx#L30) +Defined in: [createTableHook.tsx:31](https://github.com/TanStack/table/blob/main/packages/solid-table/src/createTableHook.tsx#L31) ## Type Parameters diff --git a/docs/framework/solid/reference/type-aliases/CreateTableHookOptions.md b/docs/framework/solid/reference/type-aliases/CreateTableHookOptions.md index f84ca25f1d..3e85c3355b 100644 --- a/docs/framework/solid/reference/type-aliases/CreateTableHookOptions.md +++ b/docs/framework/solid/reference/type-aliases/CreateTableHookOptions.md @@ -9,7 +9,7 @@ title: CreateTableHookOptions type CreateTableHookOptions = Omit, "columns" | "data" | "store" | "state" | "initialState"> & object; ``` -Defined in: [createTableHook.tsx:241](https://github.com/TanStack/table/blob/main/packages/solid-table/src/createTableHook.tsx#L241) +Defined in: [createTableHook.tsx:242](https://github.com/TanStack/table/blob/main/packages/solid-table/src/createTableHook.tsx#L242) Options for creating a table hook with pre-bound components and default table options. Extends all TableOptions except 'columns' | 'data' | 'store' | 'state' | 'initialState'. diff --git a/docs/framework/solid/reference/type-aliases/SolidTable.md b/docs/framework/solid/reference/type-aliases/SolidTable.md index 981d6d6fcb..ef7a08a3b4 100644 --- a/docs/framework/solid/reference/type-aliases/SolidTable.md +++ b/docs/framework/solid/reference/type-aliases/SolidTable.md @@ -9,7 +9,7 @@ title: SolidTable type SolidTable = Table & object; ``` -Defined in: [createTable.ts:19](https://github.com/TanStack/table/blob/main/packages/solid-table/src/createTable.ts#L19) +Defined in: [createTable.ts:14](https://github.com/TanStack/table/blob/main/packages/solid-table/src/createTable.ts#L14) ## Type Declaration diff --git a/docs/framework/svelte/reference/type-aliases/AppGroupColumnDef.md b/docs/framework/svelte/reference/type-aliases/AppGroupColumnDef.md index b02d54e94c..ad1becaec4 100644 --- a/docs/framework/svelte/reference/type-aliases/AppGroupColumnDef.md +++ b/docs/framework/svelte/reference/type-aliases/AppGroupColumnDef.md @@ -24,7 +24,7 @@ optional cell: AppColumnDefTemplate[]; +optional columns: ReadonlyArray>; ``` ### footer? diff --git a/docs/framework/vue/reference/functions/createTableHook.md b/docs/framework/vue/reference/functions/createTableHook.md index f833200ea9..4b02591f82 100644 --- a/docs/framework/vue/reference/functions/createTableHook.md +++ b/docs/framework/vue/reference/functions/createTableHook.md @@ -9,7 +9,7 @@ title: createTableHook function createTableHook(__namedParameters): CreateTableHookResult; ``` -Defined in: [packages/vue-table/src/createTableHook.ts:357](https://github.com/TanStack/table/blob/main/packages/vue-table/src/createTableHook.ts#L357) +Defined in: [packages/vue-table/src/createTableHook.ts:354](https://github.com/TanStack/table/blob/main/packages/vue-table/src/createTableHook.ts#L354) Creates app-scoped Vue table helpers with features, row models, and renderable component maps pre-bound. diff --git a/docs/framework/vue/reference/functions/useTable.md b/docs/framework/vue/reference/functions/useTable.md index 57c660bd7b..54b0713c34 100644 --- a/docs/framework/vue/reference/functions/useTable.md +++ b/docs/framework/vue/reference/functions/useTable.md @@ -9,7 +9,7 @@ title: useTable function useTable(tableOptions): VueTable; ``` -Defined in: [packages/vue-table/src/useTable.ts:77](https://github.com/TanStack/table/blob/main/packages/vue-table/src/useTable.ts#L77) +Defined in: [packages/vue-table/src/useTable.ts:85](https://github.com/TanStack/table/blob/main/packages/vue-table/src/useTable.ts#L85) Creates a Vue table instance backed by Vue-aware TanStack Store atoms. diff --git a/docs/framework/vue/reference/type-aliases/AppGroupColumnDef.md b/docs/framework/vue/reference/type-aliases/AppGroupColumnDef.md index a96c539039..39edad0917 100644 --- a/docs/framework/vue/reference/type-aliases/AppGroupColumnDef.md +++ b/docs/framework/vue/reference/type-aliases/AppGroupColumnDef.md @@ -22,7 +22,7 @@ optional cell: AppColumnDefTemplate[]; +optional columns: ReadonlyArray>; ``` ### footer? diff --git a/docs/framework/vue/reference/type-aliases/VueTable.md b/docs/framework/vue/reference/type-aliases/VueTable.md index afebd3fe2b..ee4645d93a 100644 --- a/docs/framework/vue/reference/type-aliases/VueTable.md +++ b/docs/framework/vue/reference/type-aliases/VueTable.md @@ -9,7 +9,7 @@ title: VueTable type VueTable = Table & object; ``` -Defined in: [packages/vue-table/src/useTable.ts:46](https://github.com/TanStack/table/blob/main/packages/vue-table/src/useTable.ts#L46) +Defined in: [packages/vue-table/src/useTable.ts:54](https://github.com/TanStack/table/blob/main/packages/vue-table/src/useTable.ts#L54) ## Type Declaration diff --git a/docs/framework/vue/reference/variables/FlexRender.md b/docs/framework/vue/reference/variables/FlexRender.md index dd6ce6f32e..ee2ebc729f 100644 --- a/docs/framework/vue/reference/variables/FlexRender.md +++ b/docs/framework/vue/reference/variables/FlexRender.md @@ -36,7 +36,7 @@ const FlexRender: DefineComponent<{ }, any>; ``` -Defined in: [packages/vue-table/src/FlexRender.ts:67](https://github.com/TanStack/table/blob/main/packages/vue-table/src/FlexRender.ts#L67) +Defined in: [packages/vue-table/src/FlexRender.ts:75](https://github.com/TanStack/table/blob/main/packages/vue-table/src/FlexRender.ts#L75) Simplified component for rendering headers, cells, or footers. diff --git a/docs/reference/index/functions/assignPrototypeAPIs.md b/docs/reference/index/functions/assignPrototypeAPIs.md index 254cb4bf22..f57eba76bc 100644 --- a/docs/reference/index/functions/assignPrototypeAPIs.md +++ b/docs/reference/index/functions/assignPrototypeAPIs.md @@ -6,14 +6,14 @@ title: assignPrototypeAPIs # Function: assignPrototypeAPIs() ```ts -function assignPrototypeAPIs( +function assignPrototypeAPIs( feature, prototype, table, apis): void; ``` -Defined in: [utils.ts:434](https://github.com/TanStack/table/blob/main/packages/table-core/src/utils.ts#L434) +Defined in: [utils.ts:404](https://github.com/TanStack/table/blob/main/packages/table-core/src/utils.ts#L404) Assigns API methods to a prototype object for memory-efficient method sharing. All instances created with this prototype will share the same method references. @@ -31,14 +31,6 @@ This provides the best of both worlds: shared method code + per-instance caching `TData` *extends* [`RowData`](../type-aliases/RowData.md) -### TDeps - -`TDeps` *extends* readonly `any`[] - -### TDepArgs - -`TDepArgs` - ## Parameters ### feature @@ -55,7 +47,7 @@ keyof `TFeatures` & `string` ### apis -[`PrototypeAPIObject`](../type-aliases/PrototypeAPIObject.md)\<`TDeps`, [`NoInfer`](../type-aliases/NoInfer.md)\<`TDepArgs`\>\> +[`PrototypeAPIObject`](../type-aliases/PrototypeAPIObject.md) ## Returns diff --git a/docs/reference/index/functions/assignTableAPIs.md b/docs/reference/index/functions/assignTableAPIs.md index 9ac2642cd1..6673bff754 100644 --- a/docs/reference/index/functions/assignTableAPIs.md +++ b/docs/reference/index/functions/assignTableAPIs.md @@ -6,13 +6,13 @@ title: assignTableAPIs # Function: assignTableAPIs() ```ts -function assignTableAPIs( +function assignTableAPIs( feature, table, apis): void; ``` -Defined in: [utils.ts:392](https://github.com/TanStack/table/blob/main/packages/table-core/src/utils.ts#L392) +Defined in: [utils.ts:359](https://github.com/TanStack/table/blob/main/packages/table-core/src/utils.ts#L359) Assigns Table API methods directly to the table instance. Unlike row/cell/column/header, the table is a singleton so methods are assigned directly. @@ -27,14 +27,6 @@ Unlike row/cell/column/header, the table is a singleton so methods are assigned `TData` *extends* [`RowData`](../type-aliases/RowData.md) -### TDeps - -`TDeps` *extends* readonly `any`[] - -### TDepArgs - -`TDepArgs` - ## Parameters ### feature @@ -47,7 +39,7 @@ keyof `TFeatures` & `string` ### apis -[`APIObject`](../type-aliases/APIObject.md)\<`TDeps`, [`NoInfer`](../type-aliases/NoInfer.md)\<`TDepArgs`\>\> +[`APIObject`](../type-aliases/APIObject.md) ## Returns diff --git a/docs/reference/index/functions/buildHeaderGroups.md b/docs/reference/index/functions/buildHeaderGroups.md index b2806b1812..1390fe78cf 100644 --- a/docs/reference/index/functions/buildHeaderGroups.md +++ b/docs/reference/index/functions/buildHeaderGroups.md @@ -13,7 +13,7 @@ function buildHeaderGroups( headerFamily?): HeaderGroup[]; ``` -Defined in: [core/headers/buildHeaderGroups.ts:16](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/headers/buildHeaderGroups.ts#L16) +Defined in: [core/headers/buildHeaderGroups.ts:211](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/headers/buildHeaderGroups.ts#L211) Builds the nested header group structure for a table. diff --git a/docs/reference/index/functions/callMemoOrStaticFn.md b/docs/reference/index/functions/callMemoOrStaticFn.md index d887ea78a8..9f1a15c5d6 100644 --- a/docs/reference/index/functions/callMemoOrStaticFn.md +++ b/docs/reference/index/functions/callMemoOrStaticFn.md @@ -13,7 +13,7 @@ function callMemoOrStaticFn( args): TReturn; ``` -Defined in: [utils.ts:480](https://github.com/TanStack/table/blob/main/packages/table-core/src/utils.ts#L480) +Defined in: [utils.ts:448](https://github.com/TanStack/table/blob/main/packages/table-core/src/utils.ts#L448) Looks to run the memoized function with the builder pattern on the object if it exists, otherwise fallback to the static method passed in. diff --git a/docs/reference/index/functions/cloneState.md b/docs/reference/index/functions/cloneState.md index d7d74767e1..59a123030b 100644 --- a/docs/reference/index/functions/cloneState.md +++ b/docs/reference/index/functions/cloneState.md @@ -9,7 +9,7 @@ title: cloneState function cloneState(value): T; ``` -Defined in: [utils.ts:22](https://github.com/TanStack/table/blob/main/packages/table-core/src/utils.ts#L22) +Defined in: [utils.ts:23](https://github.com/TanStack/table/blob/main/packages/table-core/src/utils.ts#L23) Clones table state values while preserving non-plain objects. diff --git a/docs/reference/index/functions/constructTable.md b/docs/reference/index/functions/constructTable.md index 553dc74793..23f0c65301 100644 --- a/docs/reference/index/functions/constructTable.md +++ b/docs/reference/index/functions/constructTable.md @@ -9,7 +9,7 @@ title: constructTable function constructTable(tableOptions): Table; ``` -Defined in: [core/table/constructTable.ts:32](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/constructTable.ts#L32) +Defined in: [core/table/constructTable.ts:37](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/constructTable.ts#L37) Constructs a table instance from normalized table internals. diff --git a/docs/reference/index/functions/copyInstancePropertiesWithoutMemos.md b/docs/reference/index/functions/copyInstancePropertiesWithoutMemos.md index 9cc3a2d8b1..4ecb32740f 100644 --- a/docs/reference/index/functions/copyInstancePropertiesWithoutMemos.md +++ b/docs/reference/index/functions/copyInstancePropertiesWithoutMemos.md @@ -9,7 +9,7 @@ title: copyInstancePropertiesWithoutMemos function copyInstancePropertiesWithoutMemos(target, source): TTarget & TSource; ``` -Defined in: [utils.ts:58](https://github.com/TanStack/table/blob/main/packages/table-core/src/utils.ts#L58) +Defined in: [utils.ts:59](https://github.com/TanStack/table/blob/main/packages/table-core/src/utils.ts#L59) Copies prototype-instance own properties without carrying over lazy memo closures or the per-row cell cache, both of which are bound to the source diff --git a/docs/reference/index/functions/createCoreRowModel.md b/docs/reference/index/functions/createCoreRowModel.md index 669a215a0d..183dbb261d 100644 --- a/docs/reference/index/functions/createCoreRowModel.md +++ b/docs/reference/index/functions/createCoreRowModel.md @@ -9,7 +9,7 @@ title: createCoreRowModel function createCoreRowModel(): (table) => () => RowModel; ``` -Defined in: [core/row-models/createCoreRowModel.ts:16](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/row-models/createCoreRowModel.ts#L16) +Defined in: [core/row-models/createCoreRowModel.ts:17](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/row-models/createCoreRowModel.ts#L17) Creates a memoized core row model factory. diff --git a/docs/reference/index/functions/createGroupedRowModel.md b/docs/reference/index/functions/createGroupedRowModel.md index eaad73d106..150df9c925 100644 --- a/docs/reference/index/functions/createGroupedRowModel.md +++ b/docs/reference/index/functions/createGroupedRowModel.md @@ -9,7 +9,7 @@ title: createGroupedRowModel function createGroupedRowModel(): (table) => () => RowModel; ``` -Defined in: [features/column-grouping/createGroupedRowModel.ts:26](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/column-grouping/createGroupedRowModel.ts#L26) +Defined in: [features/column-grouping/createGroupedRowModel.ts:27](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/column-grouping/createGroupedRowModel.ts#L27) Creates a memoized grouped row model factory. diff --git a/docs/reference/index/functions/createSortedRowModel.md b/docs/reference/index/functions/createSortedRowModel.md index e38afade95..78915054b8 100644 --- a/docs/reference/index/functions/createSortedRowModel.md +++ b/docs/reference/index/functions/createSortedRowModel.md @@ -9,7 +9,7 @@ title: createSortedRowModel function createSortedRowModel(): (table) => () => RowModel; ``` -Defined in: [features/row-sorting/createSortedRowModel.ts:24](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/row-sorting/createSortedRowModel.ts#L24) +Defined in: [features/row-sorting/createSortedRowModel.ts:25](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/row-sorting/createSortedRowModel.ts#L25) Creates a memoized sorted row model factory. diff --git a/docs/reference/index/functions/expandRows.md b/docs/reference/index/functions/expandRows.md index 1396582c84..7cb61fcce6 100644 --- a/docs/reference/index/functions/expandRows.md +++ b/docs/reference/index/functions/expandRows.md @@ -9,7 +9,7 @@ title: expandRows function expandRows(rowModel): RowModel; ``` -Defined in: [features/row-expanding/createExpandedRowModel.ts:62](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/row-expanding/createExpandedRowModel.ts#L62) +Defined in: [features/row-expanding/createExpandedRowModel.ts:56](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/row-expanding/createExpandedRowModel.ts#L56) Expands a row model according to the current expanded row state. diff --git a/docs/reference/index/functions/flattenBy.md b/docs/reference/index/functions/flattenBy.md index e7821f0f7b..0e1418b73b 100644 --- a/docs/reference/index/functions/flattenBy.md +++ b/docs/reference/index/functions/flattenBy.md @@ -9,7 +9,7 @@ title: flattenBy function flattenBy(arr, getChildren): TNode[]; ``` -Defined in: [utils.ts:131](https://github.com/TanStack/table/blob/main/packages/table-core/src/utils.ts#L131) +Defined in: [utils.ts:132](https://github.com/TanStack/table/blob/main/packages/table-core/src/utils.ts#L132) Flattens a tree of nodes by recursively reading child nodes. diff --git a/docs/reference/index/functions/functionalUpdate.md b/docs/reference/index/functions/functionalUpdate.md index 1904efc4ca..f52060651f 100644 --- a/docs/reference/index/functions/functionalUpdate.md +++ b/docs/reference/index/functions/functionalUpdate.md @@ -9,7 +9,7 @@ title: functionalUpdate function functionalUpdate(updater, input): T; ``` -Defined in: [utils.ts:11](https://github.com/TanStack/table/blob/main/packages/table-core/src/utils.ts#L11) +Defined in: [utils.ts:12](https://github.com/TanStack/table/blob/main/packages/table-core/src/utils.ts#L12) Applies a TanStack updater to a value. diff --git a/docs/reference/index/functions/getFunctionNameInfo.md b/docs/reference/index/functions/getFunctionNameInfo.md index 31cca62ba5..fb7dfca046 100644 --- a/docs/reference/index/functions/getFunctionNameInfo.md +++ b/docs/reference/index/functions/getFunctionNameInfo.md @@ -9,7 +9,7 @@ title: getFunctionNameInfo function getFunctionNameInfo(staticFnName, splitBy): object; ``` -Defined in: [utils.ts:375](https://github.com/TanStack/table/blob/main/packages/table-core/src/utils.ts#L375) +Defined in: [utils.ts:342](https://github.com/TanStack/table/blob/main/packages/table-core/src/utils.ts#L342) Assumes that a function name is in the format of `parentName_fnKey` and returns the `fnKey` and `fnName` in the format of `parentName.fnKey`. @@ -21,7 +21,7 @@ Assumes that a function name is in the format of `parentName_fnKey` and returns ### splitBy -`"_"` | `"."` +`"."` | `"_"` ## Returns diff --git a/docs/reference/index/functions/getInitialTableState.md b/docs/reference/index/functions/getInitialTableState.md index 8a55f27c28..43ce34ed6f 100644 --- a/docs/reference/index/functions/getInitialTableState.md +++ b/docs/reference/index/functions/getInitialTableState.md @@ -9,7 +9,7 @@ title: getInitialTableState function getInitialTableState(features, initialState): TableState; ``` -Defined in: [core/table/constructTable.ts:17](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/constructTable.ts#L17) +Defined in: [core/table/constructTable.ts:22](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/constructTable.ts#L22) Builds the initial table state from registered features and user initial state. diff --git a/docs/reference/index/functions/hasOwn.md b/docs/reference/index/functions/hasOwn.md index ea58242834..3b1043c852 100644 --- a/docs/reference/index/functions/hasOwn.md +++ b/docs/reference/index/functions/hasOwn.md @@ -9,7 +9,7 @@ title: hasOwn function hasOwn(obj, key): boolean; ``` -Defined in: [utils.ts:88](https://github.com/TanStack/table/blob/main/packages/table-core/src/utils.ts#L88) +Defined in: [utils.ts:89](https://github.com/TanStack/table/blob/main/packages/table-core/src/utils.ts#L89) Checks whether an object owns a key, including null-prototype dictionaries. diff --git a/docs/reference/index/functions/isFunction.md b/docs/reference/index/functions/isFunction.md index 730cfd7000..4df1d2f57f 100644 --- a/docs/reference/index/functions/isFunction.md +++ b/docs/reference/index/functions/isFunction.md @@ -9,7 +9,7 @@ title: isFunction function isFunction(d): d is T; ``` -Defined in: [utils.ts:122](https://github.com/TanStack/table/blob/main/packages/table-core/src/utils.ts#L122) +Defined in: [utils.ts:123](https://github.com/TanStack/table/blob/main/packages/table-core/src/utils.ts#L123) Returns whether a value is a function. diff --git a/docs/reference/index/functions/makeObjectMap.md b/docs/reference/index/functions/makeObjectMap.md index 8c7dac1846..9704cf36ca 100644 --- a/docs/reference/index/functions/makeObjectMap.md +++ b/docs/reference/index/functions/makeObjectMap.md @@ -9,7 +9,7 @@ title: makeObjectMap function makeObjectMap(): Record; ``` -Defined in: [utils.ts:81](https://github.com/TanStack/table/blob/main/packages/table-core/src/utils.ts#L81) +Defined in: [utils.ts:82](https://github.com/TanStack/table/blob/main/packages/table-core/src/utils.ts#L82) Creates an object intended only for string-keyed dictionary lookups. diff --git a/docs/reference/index/functions/makeStateUpdater.md b/docs/reference/index/functions/makeStateUpdater.md index b53ce80ad5..bf37c197b1 100644 --- a/docs/reference/index/functions/makeStateUpdater.md +++ b/docs/reference/index/functions/makeStateUpdater.md @@ -9,7 +9,7 @@ title: makeStateUpdater function makeStateUpdater(key, instance): (updater) => void; ``` -Defined in: [utils.ts:97](https://github.com/TanStack/table/blob/main/packages/table-core/src/utils.ts#L97) +Defined in: [utils.ts:98](https://github.com/TanStack/table/blob/main/packages/table-core/src/utils.ts#L98) Creates a table state updater for a single state slice. diff --git a/docs/reference/index/functions/memo.md b/docs/reference/index/functions/memo.md deleted file mode 100644 index 1737b56562..0000000000 --- a/docs/reference/index/functions/memo.md +++ /dev/null @@ -1,52 +0,0 @@ ---- -id: memo -title: memo ---- - -# Function: memo() - -```ts -function memo(__namedParameters): (depArgs?) => TResult; -``` - -Defined in: [utils.ts:166](https://github.com/TanStack/table/blob/main/packages/table-core/src/utils.ts#L166) - -Creates a dependency-tracked memoized function for table internals. - -The memo recomputes only when its dependency tuple changes and can emit debug timing information. - -## Type Parameters - -### TDeps - -`TDeps` *extends* readonly `any`[] - -### TDepArgs - -`TDepArgs` - -### TResult - -`TResult` - -## Parameters - -### \_\_namedParameters - -`MemoOptions`\<`TDeps`, `TDepArgs`, `TResult`\> - -## Returns - -```ts -(depArgs?): TResult; -``` - -### Parameters - -#### depArgs? - -`TDepArgs` - -### Returns - -`TResult` diff --git a/docs/reference/index/functions/tableMemo.md b/docs/reference/index/functions/tableMemo.md index 6f742e807b..2360f09e99 100644 --- a/docs/reference/index/functions/tableMemo.md +++ b/docs/reference/index/functions/tableMemo.md @@ -6,14 +6,15 @@ title: tableMemo # Function: tableMemo() ```ts -function tableMemo(__namedParameters): (depArgs?) => TResult; +function tableMemo(__namedParameters): () => TResult; ``` -Defined in: [utils.ts:235](https://github.com/TanStack/table/blob/main/packages/table-core/src/utils.ts#L235) +Defined in: [utils.ts:180](https://github.com/TanStack/table/blob/main/packages/table-core/src/utils.ts#L180) Creates a table-aware memoized function. -This wraps `memo` with table debug options and feature metadata so row models and derived APIs can share consistent diagnostics. +The native readonly atom is created on the first public read so eager +framework computeds cannot evaluate during incomplete table construction. ## Type Parameters @@ -21,14 +22,6 @@ This wraps `memo` with table debug options and feature metadata so row models an `TFeatures` *extends* [`TableFeatures`](../interfaces/TableFeatures.md) -### TDeps - -`TDeps` *extends* readonly `any`[] - -### TDepArgs - -`TDepArgs` - ### TResult `TResult` @@ -37,20 +30,14 @@ This wraps `memo` with table debug options and feature metadata so row models an ### \_\_namedParameters -`TableMemoOptions`\<`TFeatures`, `TDeps`, `TDepArgs`, `TResult`\> +`TableMemoOptions`\<`TFeatures`, `TResult`\> ## Returns ```ts -(depArgs?): TResult; +(): TResult; ``` -### Parameters - -#### depArgs? - -`TDepArgs` - ### Returns `TResult` diff --git a/docs/reference/index/index.md b/docs/reference/index/index.md index bab42cfd74..b2c52bbe58 100644 --- a/docs/reference/index/index.md +++ b/docs/reference/index/index.md @@ -15,7 +15,6 @@ title: index - [AggregationValueContext](interfaces/AggregationValueContext.md) - [AggregationValueOptions](interfaces/AggregationValueOptions.md) - [AggregationValueResult](interfaces/AggregationValueResult.md) -- [API](interfaces/API.md) - [CachedRowModel\_All](interfaces/CachedRowModel_All.md) - [CachedRowModel\_Core](interfaces/CachedRowModel_Core.md) - [CachedRowModel\_Expanded](interfaces/CachedRowModel_Expanded.md) @@ -97,7 +96,6 @@ title: index - [PaginationDefaultOptions](interfaces/PaginationDefaultOptions.md) - [PaginationState](interfaces/PaginationState.md) - [Plugins](interfaces/Plugins.md) -- [PrototypeAPI](interfaces/PrototypeAPI.md) - [ResolvedAggregationFn](interfaces/ResolvedAggregationFn.md) - [ResolvedColumnFilter](interfaces/ResolvedColumnFilter.md) - [Row\_ColumnFiltering](interfaces/Row_ColumnFiltering.md) @@ -212,6 +210,7 @@ title: index - [AggregationFnRef](type-aliases/AggregationFnRef.md) - [AggregationResult](type-aliases/AggregationResult.md) - [AggregationResultOf](type-aliases/AggregationResultOf.md) +- [API](type-aliases/API.md) - [APIObject](type-aliases/APIObject.md) - [Atoms](type-aliases/Atoms.md) - [Atoms\_All](type-aliases/Atoms_All.md) @@ -273,6 +272,7 @@ title: index - [OnChangeFn](type-aliases/OnChangeFn.md) - [PartialKeys](type-aliases/PartialKeys.md) - [Prettify](type-aliases/Prettify.md) +- [PrototypeAPI](type-aliases/PrototypeAPI.md) - [PrototypeAPIObject](type-aliases/PrototypeAPIObject.md) - [RequiredKeys](type-aliases/RequiredKeys.md) - [Row](type-aliases/Row.md) @@ -286,8 +286,10 @@ title: index - [StringOrTemplateHeader](type-aliases/StringOrTemplateHeader.md) - [Table](type-aliases/Table.md) - [Table\_RowModels](type-aliases/Table_RowModels.md) +- [TableOptionAtoms](type-aliases/TableOptionAtoms.md) - [TableOptions](type-aliases/TableOptions.md) - [TableOptions\_All](type-aliases/TableOptions_All.md) +- [TableOptionsLive](type-aliases/TableOptionsLive.md) - [TableState](type-aliases/TableState.md) - [TransformDataValueFn](type-aliases/TransformDataValueFn.md) - [TransformFilterValueFn](type-aliases/TransformFilterValueFn.md) @@ -401,7 +403,6 @@ title: index - [isFunction](functions/isFunction.md) - [makeObjectMap](functions/makeObjectMap.md) - [makeStateUpdater](functions/makeStateUpdater.md) -- [memo](functions/memo.md) - [metaHelper](functions/metaHelper.md) - [tableFeatures](functions/tableFeatures.md) - [tableMemo](functions/tableMemo.md) diff --git a/docs/reference/index/interfaces/API.md b/docs/reference/index/interfaces/API.md deleted file mode 100644 index 1b2b683843..0000000000 --- a/docs/reference/index/interfaces/API.md +++ /dev/null @@ -1,58 +0,0 @@ ---- -id: API -title: API ---- - -# Interface: API\<_TDeps, _TDepArgs\> - -Defined in: [utils.ts:362](https://github.com/TanStack/table/blob/main/packages/table-core/src/utils.ts#L362) - -## Type Parameters - -### _TDeps - -`_TDeps` *extends* `ReadonlyArray`\<`any`\> - -### _TDepArgs - -`_TDepArgs` - -## Properties - -### fn() - -```ts -fn: (...args) => any; -``` - -Defined in: [utils.ts:363](https://github.com/TanStack/table/blob/main/packages/table-core/src/utils.ts#L363) - -#### Parameters - -##### args - -...`any` - -#### Returns - -`any` - -*** - -### memoDeps()? - -```ts -optional memoDeps: (depArgs?) => any[] | undefined; -``` - -Defined in: [utils.ts:364](https://github.com/TanStack/table/blob/main/packages/table-core/src/utils.ts#L364) - -#### Parameters - -##### depArgs? - -`any` - -#### Returns - -`any`[] \| `undefined` diff --git a/docs/reference/index/interfaces/Plugins.md b/docs/reference/index/interfaces/Plugins.md index e5f42aeba0..e9a87e052c 100644 --- a/docs/reference/index/interfaces/Plugins.md +++ b/docs/reference/index/interfaces/Plugins.md @@ -21,4 +21,4 @@ features. workerRowModelsFeature: TableFeature; ``` -Defined in: [worker/createTableWorker.ts:23](https://github.com/TanStack/table/blob/main/packages/table-core/src/worker/createTableWorker.ts#L23) +Defined in: [worker/createTableWorker.ts:24](https://github.com/TanStack/table/blob/main/packages/table-core/src/worker/createTableWorker.ts#L24) diff --git a/docs/reference/index/interfaces/PrototypeAPI.md b/docs/reference/index/interfaces/PrototypeAPI.md deleted file mode 100644 index 1c6f7de5c7..0000000000 --- a/docs/reference/index/interfaces/PrototypeAPI.md +++ /dev/null @@ -1,66 +0,0 @@ ---- -id: PrototypeAPI -title: PrototypeAPI ---- - -# Interface: PrototypeAPI\<_TDeps, _TDepArgs\> - -Defined in: [utils.ts:417](https://github.com/TanStack/table/blob/main/packages/table-core/src/utils.ts#L417) - -## Type Parameters - -### _TDeps - -`_TDeps` *extends* `ReadonlyArray`\<`any`\> - -### _TDepArgs - -`_TDepArgs` - -## Properties - -### fn() - -```ts -fn: (self, ...args) => any; -``` - -Defined in: [utils.ts:418](https://github.com/TanStack/table/blob/main/packages/table-core/src/utils.ts#L418) - -#### Parameters - -##### self - -`any` - -##### args - -...`any` - -#### Returns - -`any` - -*** - -### memoDeps()? - -```ts -optional memoDeps: (self, depArgs?) => any[] | undefined; -``` - -Defined in: [utils.ts:419](https://github.com/TanStack/table/blob/main/packages/table-core/src/utils.ts#L419) - -#### Parameters - -##### self - -`any` - -##### depArgs? - -`any` - -#### Returns - -`any`[] \| `undefined` diff --git a/docs/reference/index/interfaces/TableFeature.md b/docs/reference/index/interfaces/TableFeature.md index b848353d04..7e98039e17 100644 --- a/docs/reference/index/interfaces/TableFeature.md +++ b/docs/reference/index/interfaces/TableFeature.md @@ -322,7 +322,7 @@ override feature defaults. optional initCellInstanceData: (cell) => void; ``` -Defined in: [types/TableFeatures.ts:449](https://github.com/TanStack/table/blob/main/packages/table-core/src/types/TableFeatures.ts#L449) +Defined in: [types/TableFeatures.ts:452](https://github.com/TanStack/table/blob/main/packages/table-core/src/types/TableFeatures.ts#L452) Initializes instance-specific data on each cell. @@ -364,7 +364,7 @@ Shared methods should be assigned via `assignCellPrototype` instead. optional initColumnInstanceData: (column) => void; ``` -Defined in: [types/TableFeatures.ts:464](https://github.com/TanStack/table/blob/main/packages/table-core/src/types/TableFeatures.ts#L464) +Defined in: [types/TableFeatures.ts:467](https://github.com/TanStack/table/blob/main/packages/table-core/src/types/TableFeatures.ts#L467) Initializes instance-specific data on each column. @@ -405,7 +405,7 @@ methods should be assigned via `assignColumnPrototype` instead. optional initHeaderGroupInstanceData: (headerGroup) => void; ``` -Defined in: [types/TableFeatures.ts:480](https://github.com/TanStack/table/blob/main/packages/table-core/src/types/TableFeatures.ts#L480) +Defined in: [types/TableFeatures.ts:483](https://github.com/TanStack/table/blob/main/packages/table-core/src/types/TableFeatures.ts#L483) Initializes instance-specific data on each header group. @@ -443,7 +443,7 @@ visibility, order, or pinning changes), so this reruns on every rebuild. optional initHeaderInstanceData: (header) => void; ``` -Defined in: [types/TableFeatures.ts:497](https://github.com/TanStack/table/blob/main/packages/table-core/src/types/TableFeatures.ts#L497) +Defined in: [types/TableFeatures.ts:500](https://github.com/TanStack/table/blob/main/packages/table-core/src/types/TableFeatures.ts#L500) Initializes instance-specific data on each header. @@ -487,7 +487,7 @@ instead. optional initRowInstanceData: (row) => void; ``` -Defined in: [types/TableFeatures.ts:512](https://github.com/TanStack/table/blob/main/packages/table-core/src/types/TableFeatures.ts#L512) +Defined in: [types/TableFeatures.ts:515](https://github.com/TanStack/table/blob/main/packages/table-core/src/types/TableFeatures.ts#L515) Initializes instance-specific data on each row. @@ -524,16 +524,19 @@ should be assigned via `assignRowPrototype` instead. optional initTableInstanceData: (table) => void; ``` -Defined in: [types/TableFeatures.ts:434](https://github.com/TanStack/table/blob/main/packages/table-core/src/types/TableFeatures.ts#L434) +Defined in: [types/TableFeatures.ts:437](https://github.com/TanStack/table/blob/main/packages/table-core/src/types/TableFeatures.ts#L437) Initializes mutable, non-reactive data owned by this feature on the table instance. This runs once during table construction after options, state atoms, and -the store are available, and before any feature's `constructTableAPIs` -hook runs. Use `constructTableAPIs` exclusively for assigning table -methods. Table resets do not rerun this hook; use -`resetTableInstanceData` to clear transient instance data instead. +the store are available. Features are processed in a single pass in +registration order, with each feature's instance data initialized just +before its own `constructTableAPIs` hook, so this hook may rely on data +and APIs of features registered earlier. Use `constructTableAPIs` +exclusively for assigning table methods. Table resets do not rerun this +hook; use `resetTableInstanceData` to clear transient instance data +instead. #### Type Parameters @@ -563,7 +566,7 @@ methods. Table resets do not rerun this hook; use optional resetTableInstanceData: (table) => void; ``` -Defined in: [types/TableFeatures.ts:525](https://github.com/TanStack/table/blob/main/packages/table-core/src/types/TableFeatures.ts#L525) +Defined in: [types/TableFeatures.ts:528](https://github.com/TanStack/table/blob/main/packages/table-core/src/types/TableFeatures.ts#L528) Resets mutable, non-reactive table-instance data owned by this feature. diff --git a/docs/reference/index/interfaces/TableFeatures.md b/docs/reference/index/interfaces/TableFeatures.md index 2c88440ad8..beb66e27de 100644 --- a/docs/reference/index/interfaces/TableFeatures.md +++ b/docs/reference/index/interfaces/TableFeatures.md @@ -745,7 +745,7 @@ When omitted, the global declaration-merged `TableMeta` interface applies. optional workerRowModelsFeature: TableFeature; ``` -Defined in: [worker/createTableWorker.ts:23](https://github.com/TanStack/table/blob/main/packages/table-core/src/worker/createTableWorker.ts#L23) +Defined in: [worker/createTableWorker.ts:24](https://github.com/TanStack/table/blob/main/packages/table-core/src/worker/createTableWorker.ts#L24) #### Inherited from diff --git a/docs/reference/index/interfaces/TableOptions_Core.md b/docs/reference/index/interfaces/TableOptions_Core.md index 47868b0456..98ae45748c 100644 --- a/docs/reference/index/interfaces/TableOptions_Core.md +++ b/docs/reference/index/interfaces/TableOptions_Core.md @@ -32,7 +32,7 @@ options are mixed in. readonly optional atoms: Partial<{ [K in string | number | symbol]: Atom[K]> }>; ``` -Defined in: [core/table/coreTablesFeature.types.ts:109](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L109) +Defined in: [core/table/coreTablesFeature.types.ts:148](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L148) Optionally, provide your own external writable atoms for individual state slices. When an atom is provided for a given slice, it takes precedence over `options.state[key]` @@ -52,7 +52,7 @@ model for app-managed table state slices. readonly optional autoResetAll: boolean; ``` -Defined in: [core/table/coreTablesFeature.types.ts:113](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L113) +Defined in: [core/table/coreTablesFeature.types.ts:152](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L152) Set this option to override any of the `autoReset...` feature options. @@ -84,7 +84,7 @@ The array of column defs to use for the table. readonly data: readonly TData[]; ``` -Defined in: [core/table/coreTablesFeature.types.ts:117](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L117) +Defined in: [core/table/coreTablesFeature.types.ts:156](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L156) The data for the table to display. When the `data` option changes reference, the table will reprocess the data. @@ -116,7 +116,7 @@ Default column options to use for all column defs supplied to the table. readonly features: TFeatures & ValidateFeatureSlots; ``` -Defined in: [core/table/coreTablesFeature.types.ts:101](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L101) +Defined in: [core/table/coreTablesFeature.types.ts:140](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L140) The feature modules registered on this table instance. @@ -214,7 +214,7 @@ getSubRows: row => row.subRows readonly optional initialState: Partial>; ``` -Defined in: [core/table/coreTablesFeature.types.ts:131](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L131) +Defined in: [core/table/coreTablesFeature.types.ts:170](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L170) Optionally provide starting values for registered table state slices. Feature reset APIs use this value by default, and many reset APIs accept @@ -233,7 +233,7 @@ object later does not reset table state, so it does not need to be stable. readonly optional key: string; ``` -Defined in: [core/table/coreTablesFeature.types.ts:124](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L124) +Defined in: [core/table/coreTablesFeature.types.ts:163](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L163) Optional key used to identify this table instance. @@ -252,7 +252,7 @@ not required unless the table is passed to devtools. readonly optional mergeOptions: (defaultOptions, options) => TableOptions; ``` -Defined in: [core/table/coreTablesFeature.types.ts:135](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L135) +Defined in: [core/table/coreTablesFeature.types.ts:174](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L174) This option is used to optionally implement the merging of table options. @@ -282,7 +282,7 @@ This option is used to optionally implement the merging of table options. readonly optional meta: ExtractTableMeta; ``` -Defined in: [core/table/coreTablesFeature.types.ts:145](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L145) +Defined in: [core/table/coreTablesFeature.types.ts:184](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L184) You can pass any object to `options.meta` and access it anywhere the `table` is available via `table.options.meta`. @@ -317,7 +317,7 @@ Value used when the desired value is not found in the data. readonly optional state: Partial>; ``` -Defined in: [core/table/coreTablesFeature.types.ts:153](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L153) +Defined in: [core/table/coreTablesFeature.types.ts:192](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L192) Optionally provide externally managed values for individual state slices. diff --git a/docs/reference/index/interfaces/TableOptions_Table.md b/docs/reference/index/interfaces/TableOptions_Table.md index 8bb8f5c2c2..8d472583c1 100644 --- a/docs/reference/index/interfaces/TableOptions_Table.md +++ b/docs/reference/index/interfaces/TableOptions_Table.md @@ -5,7 +5,7 @@ title: TableOptions_Table # Interface: TableOptions\_Table\ -Defined in: [core/table/coreTablesFeature.types.ts:88](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L88) +Defined in: [core/table/coreTablesFeature.types.ts:127](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L127) ## Extended by @@ -29,7 +29,7 @@ Defined in: [core/table/coreTablesFeature.types.ts:88](https://github.com/TanSta readonly optional atoms: Partial<{ [K in string | number | symbol]: Atom[K]> }>; ``` -Defined in: [core/table/coreTablesFeature.types.ts:109](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L109) +Defined in: [core/table/coreTablesFeature.types.ts:148](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L148) Optionally, provide your own external writable atoms for individual state slices. When an atom is provided for a given slice, it takes precedence over `options.state[key]` @@ -45,7 +45,7 @@ model for app-managed table state slices. readonly optional autoResetAll: boolean; ``` -Defined in: [core/table/coreTablesFeature.types.ts:113](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L113) +Defined in: [core/table/coreTablesFeature.types.ts:152](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L152) Set this option to override any of the `autoReset...` feature options. @@ -57,7 +57,7 @@ Set this option to override any of the `autoReset...` feature options. readonly data: readonly TData[]; ``` -Defined in: [core/table/coreTablesFeature.types.ts:117](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L117) +Defined in: [core/table/coreTablesFeature.types.ts:156](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L156) The data for the table to display. When the `data` option changes reference, the table will reprocess the data. @@ -69,7 +69,7 @@ The data for the table to display. When the `data` option changes reference, the readonly features: TFeatures & ValidateFeatureSlots; ``` -Defined in: [core/table/coreTablesFeature.types.ts:101](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L101) +Defined in: [core/table/coreTablesFeature.types.ts:140](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L140) The feature modules registered on this table instance. @@ -87,7 +87,7 @@ slots (`tableMeta`, `columnMeta`). readonly optional initialState: Partial>; ``` -Defined in: [core/table/coreTablesFeature.types.ts:131](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L131) +Defined in: [core/table/coreTablesFeature.types.ts:170](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L170) Optionally provide starting values for registered table state slices. Feature reset APIs use this value by default, and many reset APIs accept @@ -102,7 +102,7 @@ object later does not reset table state, so it does not need to be stable. readonly optional key: string; ``` -Defined in: [core/table/coreTablesFeature.types.ts:124](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L124) +Defined in: [core/table/coreTablesFeature.types.ts:163](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L163) Optional key used to identify this table instance. @@ -117,7 +117,7 @@ not required unless the table is passed to devtools. readonly optional mergeOptions: (defaultOptions, options) => TableOptions; ``` -Defined in: [core/table/coreTablesFeature.types.ts:135](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L135) +Defined in: [core/table/coreTablesFeature.types.ts:174](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L174) This option is used to optionally implement the merging of table options. @@ -143,7 +143,7 @@ This option is used to optionally implement the merging of table options. readonly optional meta: ExtractTableMeta; ``` -Defined in: [core/table/coreTablesFeature.types.ts:145](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L145) +Defined in: [core/table/coreTablesFeature.types.ts:184](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L184) You can pass any object to `options.meta` and access it anywhere the `table` is available via `table.options.meta`. @@ -158,7 +158,7 @@ Declare its type per-table via the `tableMeta` type-only slot on the readonly optional state: Partial>; ``` -Defined in: [core/table/coreTablesFeature.types.ts:153](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L153) +Defined in: [core/table/coreTablesFeature.types.ts:192](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L192) Optionally provide externally managed values for individual state slices. diff --git a/docs/reference/index/interfaces/TableState_FeatureMap.md b/docs/reference/index/interfaces/TableState_FeatureMap.md index 023c56b255..cb24a3d9e3 100644 --- a/docs/reference/index/interfaces/TableState_FeatureMap.md +++ b/docs/reference/index/interfaces/TableState_FeatureMap.md @@ -155,4 +155,4 @@ Defined in: [types/TableState.ts:31](https://github.com/TanStack/table/blob/main workerRowModelsFeature: TableState_WorkerRowModels; ``` -Defined in: [worker/createTableWorker.ts:28](https://github.com/TanStack/table/blob/main/packages/table-core/src/worker/createTableWorker.ts#L28) +Defined in: [worker/createTableWorker.ts:29](https://github.com/TanStack/table/blob/main/packages/table-core/src/worker/createTableWorker.ts#L29) diff --git a/docs/reference/index/interfaces/Table_Core.md b/docs/reference/index/interfaces/Table_Core.md index 744ad71ce9..39ed7dabde 100644 --- a/docs/reference/index/interfaces/Table_Core.md +++ b/docs/reference/index/interfaces/Table_Core.md @@ -5,7 +5,7 @@ title: Table_Core # Interface: Table\_Core\ -Defined in: [types/Table.ts:40](https://github.com/TanStack/table/blob/main/packages/table-core/src/types/Table.ts#L40) +Defined in: [types/Table.ts:41](https://github.com/TanStack/table/blob/main/packages/table-core/src/types/Table.ts#L41) The core table object that only includes the core table functionality such as column, header, row, and table APIS. No features are included. @@ -26,13 +26,13 @@ No features are included. ## Properties -### \_cellInstanceInitFns? +### \_cellInstanceInitFns ```ts -optional _cellInstanceInitFns: (cell) => void[]; +_cellInstanceInitFns: (cell) => void[]; ``` -Defined in: [core/table/coreTablesFeature.types.ts:167](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L167) +Defined in: [core/table/coreTablesFeature.types.ts:206](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L206) Cache of the `initCellInstanceData` functions for features that define one. @@ -72,7 +72,7 @@ Cache of the `initCellInstanceData` functions for features that define one. optional _cellPrototype: object; ``` -Defined in: [core/table/coreTablesFeature.types.ts:173](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L173) +Defined in: [core/table/coreTablesFeature.types.ts:210](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L210) Prototype cache for Cell objects - shared by all cells in this table @@ -82,13 +82,13 @@ Prototype cache for Cell objects - shared by all cells in this table *** -### \_columnInstanceInitFns? +### \_columnInstanceInitFns ```ts -optional _columnInstanceInitFns: (column) => void[]; +_columnInstanceInitFns: (column) => void[]; ``` -Defined in: [core/table/coreTablesFeature.types.ts:177](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L177) +Defined in: [core/table/coreTablesFeature.types.ts:214](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L214) Cache of the `initColumnInstanceData` functions for features that define one. @@ -128,7 +128,7 @@ Cache of the `initColumnInstanceData` functions for features that define one. optional _columnPrototype: object; ``` -Defined in: [core/table/coreTablesFeature.types.ts:183](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L183) +Defined in: [core/table/coreTablesFeature.types.ts:220](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L220) Prototype cache for Column objects - shared by all columns in this table @@ -144,7 +144,7 @@ Prototype cache for Column objects - shared by all columns in this table readonly _features: Partial & TFeatures; ``` -Defined in: [core/table/coreTablesFeature.types.ts:187](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L187) +Defined in: [core/table/coreTablesFeature.types.ts:224](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L224) The features that are enabled for the table. @@ -154,13 +154,13 @@ The features that are enabled for the table. *** -### \_headerGroupInstanceInitFns? +### \_headerGroupInstanceInitFns ```ts -optional _headerGroupInstanceInitFns: (headerGroup) => void[]; +_headerGroupInstanceInitFns: (headerGroup) => void[]; ``` -Defined in: [core/table/coreTablesFeature.types.ts:191](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L191) +Defined in: [core/table/coreTablesFeature.types.ts:228](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L228) Cache of the `initHeaderGroupInstanceData` functions for features that define one. @@ -190,13 +190,13 @@ Cache of the `initHeaderGroupInstanceData` functions for features that define on *** -### \_headerInstanceInitFns? +### \_headerInstanceInitFns ```ts -optional _headerInstanceInitFns: (header) => void[]; +_headerInstanceInitFns: (header) => void[]; ``` -Defined in: [core/table/coreTablesFeature.types.ts:197](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L197) +Defined in: [core/table/coreTablesFeature.types.ts:234](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L234) Cache of the `initHeaderInstanceData` functions for features that define one. @@ -236,7 +236,7 @@ Cache of the `initHeaderInstanceData` functions for features that define one. optional _headerPrototype: object; ``` -Defined in: [core/table/coreTablesFeature.types.ts:203](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L203) +Defined in: [core/table/coreTablesFeature.types.ts:240](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L240) Prototype cache for Header objects - shared by all headers in this table @@ -252,7 +252,7 @@ Prototype cache for Header objects - shared by all headers in this table readonly _reactivity: TableReactivityBindings; ``` -Defined in: [core/table/coreTablesFeature.types.ts:163](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L163) +Defined in: [core/table/coreTablesFeature.types.ts:202](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L202) Table reactivity bindings for interacting with TanStack Store. @@ -262,13 +262,13 @@ Table reactivity bindings for interacting with TanStack Store. *** -### \_rowInstanceInitFns? +### \_rowInstanceInitFns ```ts -optional _rowInstanceInitFns: (row) => void[]; +_rowInstanceInitFns: (row) => void[]; ``` -Defined in: [core/table/coreTablesFeature.types.ts:219](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L219) +Defined in: [core/table/coreTablesFeature.types.ts:256](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L256) Cache of the `initRowInstanceData` functions for features that define one. @@ -304,7 +304,7 @@ Cache of the `initRowInstanceData` functions for features that define one. readonly _rowModelFns: RowModelFns; ``` -Defined in: [core/table/coreTablesFeature.types.ts:207](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L207) +Defined in: [core/table/coreTablesFeature.types.ts:244](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L244) The row model processing functions that are used to process the data by features. @@ -320,7 +320,7 @@ The row model processing functions that are used to process the data by features readonly _rowModels: CachedRowModels; ``` -Defined in: [core/table/coreTablesFeature.types.ts:211](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L211) +Defined in: [core/table/coreTablesFeature.types.ts:248](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L248) The row models that are enabled for the table. @@ -336,7 +336,7 @@ The row models that are enabled for the table. optional _rowPrototype: object; ``` -Defined in: [core/table/coreTablesFeature.types.ts:215](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L215) +Defined in: [core/table/coreTablesFeature.types.ts:252](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L252) Prototype cache for Row objects - shared by all rows in this table @@ -352,7 +352,7 @@ Prototype cache for Row objects - shared by all rows in this table readonly atoms: Atoms; ``` -Defined in: [core/table/coreTablesFeature.types.ts:225](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L225) +Defined in: [core/table/coreTablesFeature.types.ts:262](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L262) The readonly derived atoms for each `TableState` slice. Each derives from its corresponding `baseAtom` plus, optionally, a per-slice external atom or @@ -370,7 +370,7 @@ external state value (precedence: external atom > external state > base atom). readonly baseAtoms: BaseAtoms; ``` -Defined in: [core/table/coreTablesFeature.types.ts:230](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L230) +Defined in: [core/table/coreTablesFeature.types.ts:267](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L267) The internal writable atoms for each `TableState` slice. This is the library's single write surface — all state mutations from features land here. @@ -1062,7 +1062,7 @@ Table_RowModels.getSortedRowModel readonly initialState: ExtractFeatureMapTypes; ``` -Defined in: [core/table/coreTablesFeature.types.ts:234](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L234) +Defined in: [core/table/coreTablesFeature.types.ts:271](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L271) This is the resolved initial state of the table. @@ -1072,37 +1072,39 @@ This is the resolved initial state of the table. *** -### options +### optionAtoms ```ts -readonly options: TableOptions; +readonly optionAtoms: TableOptionAtoms; ``` -Defined in: [core/table/coreTablesFeature.types.ts:238](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L238) +Defined in: [core/table/coreTablesFeature.types.ts:283](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L283) + +Stable atoms for individual resolved option values. -A read-only reference to the table's current options. +Ordinary options are writable. Construction-static options are readonly. #### Inherited from -[`Table_Table`](Table_Table.md).[`options`](Table_Table.md#options) +[`Table_Table`](Table_Table.md).[`optionAtoms`](Table_Table.md#optionatoms) *** -### optionsStore? +### options ```ts -readonly optional optionsStore: Atom>; +readonly options: TableOptionsLive; ``` -Defined in: [core/table/coreTablesFeature.types.ts:244](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L244) +Defined in: [core/table/coreTablesFeature.types.ts:277](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L277) -Writable atom for table options. Only created when `createOptionsStore` is -true on the active core reactivity bindings. Adapters that opt out keep -options as plain resolved data instead of backing them with an atom. +A stable live view of the table's current resolved options. + +Reading a property reads the matching entry in `optionAtoms`. #### Inherited from -[`Table_Table`](Table_Table.md).[`optionsStore`](Table_Table.md#optionsstore) +[`Table_Table`](Table_Table.md).[`options`](Table_Table.md#options) *** @@ -1112,7 +1114,7 @@ options as plain resolved data instead of backing them with an atom. reset: () => void; ``` -Defined in: [core/table/coreTablesFeature.types.ts:264](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L264) +Defined in: [core/table/coreTablesFeature.types.ts:303](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L303) Resets the table's internal base atoms to `table.initialState`. @@ -1137,7 +1139,7 @@ reset hooks for mutable, transient table-instance data. setOptions: (newOptions) => void; ``` -Defined in: [core/table/coreTablesFeature.types.ts:269](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L269) +Defined in: [core/table/coreTablesFeature.types.ts:308](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L308) Updates the table options by applying a value or updater to the current resolved options and then merging them through `options.mergeOptions`. @@ -1164,7 +1166,7 @@ resolved options and then merging them through `options.mergeOptions`. readonly store: ReadonlyStore>; ``` -Defined in: [core/table/coreTablesFeature.types.ts:249](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L249) +Defined in: [core/table/coreTablesFeature.types.ts:288](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L288) The readonly flat store for the table state. Derives from `table.atoms` only; never reads external state directly. diff --git a/docs/reference/index/interfaces/Table_CoreProperties.md b/docs/reference/index/interfaces/Table_CoreProperties.md index 322a1130b6..3d39f915fe 100644 --- a/docs/reference/index/interfaces/Table_CoreProperties.md +++ b/docs/reference/index/interfaces/Table_CoreProperties.md @@ -5,7 +5,7 @@ title: Table_CoreProperties # Interface: Table\_CoreProperties\ -Defined in: [core/table/coreTablesFeature.types.ts:156](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L156) +Defined in: [core/table/coreTablesFeature.types.ts:195](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L195) ## Extended by @@ -23,13 +23,13 @@ Defined in: [core/table/coreTablesFeature.types.ts:156](https://github.com/TanSt ## Properties -### \_cellInstanceInitFns? +### \_cellInstanceInitFns ```ts -optional _cellInstanceInitFns: (cell) => void[]; +_cellInstanceInitFns: (cell) => void[]; ``` -Defined in: [core/table/coreTablesFeature.types.ts:167](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L167) +Defined in: [core/table/coreTablesFeature.types.ts:206](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L206) Cache of the `initCellInstanceData` functions for features that define one. @@ -65,19 +65,19 @@ Cache of the `initCellInstanceData` functions for features that define one. optional _cellPrototype: object; ``` -Defined in: [core/table/coreTablesFeature.types.ts:173](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L173) +Defined in: [core/table/coreTablesFeature.types.ts:210](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L210) Prototype cache for Cell objects - shared by all cells in this table *** -### \_columnInstanceInitFns? +### \_columnInstanceInitFns ```ts -optional _columnInstanceInitFns: (column) => void[]; +_columnInstanceInitFns: (column) => void[]; ``` -Defined in: [core/table/coreTablesFeature.types.ts:177](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L177) +Defined in: [core/table/coreTablesFeature.types.ts:214](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L214) Cache of the `initColumnInstanceData` functions for features that define one. @@ -113,7 +113,7 @@ Cache of the `initColumnInstanceData` functions for features that define one. optional _columnPrototype: object; ``` -Defined in: [core/table/coreTablesFeature.types.ts:183](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L183) +Defined in: [core/table/coreTablesFeature.types.ts:220](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L220) Prototype cache for Column objects - shared by all columns in this table @@ -125,19 +125,19 @@ Prototype cache for Column objects - shared by all columns in this table readonly _features: Partial & TFeatures; ``` -Defined in: [core/table/coreTablesFeature.types.ts:187](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L187) +Defined in: [core/table/coreTablesFeature.types.ts:224](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L224) The features that are enabled for the table. *** -### \_headerGroupInstanceInitFns? +### \_headerGroupInstanceInitFns ```ts -optional _headerGroupInstanceInitFns: (headerGroup) => void[]; +_headerGroupInstanceInitFns: (headerGroup) => void[]; ``` -Defined in: [core/table/coreTablesFeature.types.ts:191](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L191) +Defined in: [core/table/coreTablesFeature.types.ts:228](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L228) Cache of the `initHeaderGroupInstanceData` functions for features that define one. @@ -163,13 +163,13 @@ Cache of the `initHeaderGroupInstanceData` functions for features that define on *** -### \_headerInstanceInitFns? +### \_headerInstanceInitFns ```ts -optional _headerInstanceInitFns: (header) => void[]; +_headerInstanceInitFns: (header) => void[]; ``` -Defined in: [core/table/coreTablesFeature.types.ts:197](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L197) +Defined in: [core/table/coreTablesFeature.types.ts:234](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L234) Cache of the `initHeaderInstanceData` functions for features that define one. @@ -205,7 +205,7 @@ Cache of the `initHeaderInstanceData` functions for features that define one. optional _headerPrototype: object; ``` -Defined in: [core/table/coreTablesFeature.types.ts:203](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L203) +Defined in: [core/table/coreTablesFeature.types.ts:240](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L240) Prototype cache for Header objects - shared by all headers in this table @@ -217,19 +217,19 @@ Prototype cache for Header objects - shared by all headers in this table readonly _reactivity: TableReactivityBindings; ``` -Defined in: [core/table/coreTablesFeature.types.ts:163](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L163) +Defined in: [core/table/coreTablesFeature.types.ts:202](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L202) Table reactivity bindings for interacting with TanStack Store. *** -### \_rowInstanceInitFns? +### \_rowInstanceInitFns ```ts -optional _rowInstanceInitFns: (row) => void[]; +_rowInstanceInitFns: (row) => void[]; ``` -Defined in: [core/table/coreTablesFeature.types.ts:219](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L219) +Defined in: [core/table/coreTablesFeature.types.ts:256](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L256) Cache of the `initRowInstanceData` functions for features that define one. @@ -261,7 +261,7 @@ Cache of the `initRowInstanceData` functions for features that define one. readonly _rowModelFns: RowModelFns; ``` -Defined in: [core/table/coreTablesFeature.types.ts:207](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L207) +Defined in: [core/table/coreTablesFeature.types.ts:244](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L244) The row model processing functions that are used to process the data by features. @@ -273,7 +273,7 @@ The row model processing functions that are used to process the data by features readonly _rowModels: CachedRowModels; ``` -Defined in: [core/table/coreTablesFeature.types.ts:211](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L211) +Defined in: [core/table/coreTablesFeature.types.ts:248](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L248) The row models that are enabled for the table. @@ -285,7 +285,7 @@ The row models that are enabled for the table. optional _rowPrototype: object; ``` -Defined in: [core/table/coreTablesFeature.types.ts:215](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L215) +Defined in: [core/table/coreTablesFeature.types.ts:252](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L252) Prototype cache for Row objects - shared by all rows in this table @@ -297,7 +297,7 @@ Prototype cache for Row objects - shared by all rows in this table readonly atoms: Atoms; ``` -Defined in: [core/table/coreTablesFeature.types.ts:225](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L225) +Defined in: [core/table/coreTablesFeature.types.ts:262](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L262) The readonly derived atoms for each `TableState` slice. Each derives from its corresponding `baseAtom` plus, optionally, a per-slice external atom or @@ -311,7 +311,7 @@ external state value (precedence: external atom > external state > base atom). readonly baseAtoms: BaseAtoms; ``` -Defined in: [core/table/coreTablesFeature.types.ts:230](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L230) +Defined in: [core/table/coreTablesFeature.types.ts:267](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L267) The internal writable atoms for each `TableState` slice. This is the library's single write surface — all state mutations from features land here. @@ -324,35 +324,37 @@ single write surface — all state mutations from features land here. readonly initialState: ExtractFeatureMapTypes; ``` -Defined in: [core/table/coreTablesFeature.types.ts:234](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L234) +Defined in: [core/table/coreTablesFeature.types.ts:271](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L271) This is the resolved initial state of the table. *** -### options +### optionAtoms ```ts -readonly options: TableOptions; +readonly optionAtoms: TableOptionAtoms; ``` -Defined in: [core/table/coreTablesFeature.types.ts:238](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L238) +Defined in: [core/table/coreTablesFeature.types.ts:283](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L283) -A read-only reference to the table's current options. +Stable atoms for individual resolved option values. + +Ordinary options are writable. Construction-static options are readonly. *** -### optionsStore? +### options ```ts -readonly optional optionsStore: Atom>; +readonly options: TableOptionsLive; ``` -Defined in: [core/table/coreTablesFeature.types.ts:244](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L244) +Defined in: [core/table/coreTablesFeature.types.ts:277](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L277) + +A stable live view of the table's current resolved options. -Writable atom for table options. Only created when `createOptionsStore` is -true on the active core reactivity bindings. Adapters that opt out keep -options as plain resolved data instead of backing them with an atom. +Reading a property reads the matching entry in `optionAtoms`. *** @@ -362,7 +364,7 @@ options as plain resolved data instead of backing them with an atom. readonly store: ReadonlyStore>; ``` -Defined in: [core/table/coreTablesFeature.types.ts:249](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L249) +Defined in: [core/table/coreTablesFeature.types.ts:288](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L288) The readonly flat store for the table state. Derives from `table.atoms` only; never reads external state directly. diff --git a/docs/reference/index/interfaces/Table_FeatureMap.md b/docs/reference/index/interfaces/Table_FeatureMap.md index b28da15e01..03feeeddde 100644 --- a/docs/reference/index/interfaces/Table_FeatureMap.md +++ b/docs/reference/index/interfaces/Table_FeatureMap.md @@ -5,7 +5,7 @@ title: Table_FeatureMap # Interface: Table\_FeatureMap\ -Defined in: [types/Table.ts:51](https://github.com/TanStack/table/blob/main/packages/table-core/src/types/Table.ts#L51) +Defined in: [types/Table.ts:52](https://github.com/TanStack/table/blob/main/packages/table-core/src/types/Table.ts#L52) ## Type Parameters @@ -25,7 +25,7 @@ Defined in: [types/Table.ts:51](https://github.com/TanStack/table/blob/main/pack cellSelectionFeature: Table_CellSelection; ``` -Defined in: [types/Table.ts:55](https://github.com/TanStack/table/blob/main/packages/table-core/src/types/Table.ts#L55) +Defined in: [types/Table.ts:56](https://github.com/TanStack/table/blob/main/packages/table-core/src/types/Table.ts#L56) *** @@ -35,7 +35,7 @@ Defined in: [types/Table.ts:55](https://github.com/TanStack/table/blob/main/pack columnFacetingFeature: Table_ColumnFaceting; ``` -Defined in: [types/Table.ts:56](https://github.com/TanStack/table/blob/main/packages/table-core/src/types/Table.ts#L56) +Defined in: [types/Table.ts:57](https://github.com/TanStack/table/blob/main/packages/table-core/src/types/Table.ts#L57) *** @@ -45,7 +45,7 @@ Defined in: [types/Table.ts:56](https://github.com/TanStack/table/blob/main/pack columnFilteringFeature: Table_ColumnFiltering; ``` -Defined in: [types/Table.ts:57](https://github.com/TanStack/table/blob/main/packages/table-core/src/types/Table.ts#L57) +Defined in: [types/Table.ts:58](https://github.com/TanStack/table/blob/main/packages/table-core/src/types/Table.ts#L58) *** @@ -55,7 +55,7 @@ Defined in: [types/Table.ts:57](https://github.com/TanStack/table/blob/main/pack columnGroupingFeature: Table_ColumnGrouping; ``` -Defined in: [types/Table.ts:58](https://github.com/TanStack/table/blob/main/packages/table-core/src/types/Table.ts#L58) +Defined in: [types/Table.ts:59](https://github.com/TanStack/table/blob/main/packages/table-core/src/types/Table.ts#L59) *** @@ -65,7 +65,7 @@ Defined in: [types/Table.ts:58](https://github.com/TanStack/table/blob/main/pack columnOrderingFeature: Table_ColumnOrdering; ``` -Defined in: [types/Table.ts:59](https://github.com/TanStack/table/blob/main/packages/table-core/src/types/Table.ts#L59) +Defined in: [types/Table.ts:60](https://github.com/TanStack/table/blob/main/packages/table-core/src/types/Table.ts#L60) *** @@ -75,7 +75,7 @@ Defined in: [types/Table.ts:59](https://github.com/TanStack/table/blob/main/pack columnPinningFeature: Table_ColumnPinning; ``` -Defined in: [types/Table.ts:60](https://github.com/TanStack/table/blob/main/packages/table-core/src/types/Table.ts#L60) +Defined in: [types/Table.ts:61](https://github.com/TanStack/table/blob/main/packages/table-core/src/types/Table.ts#L61) *** @@ -85,7 +85,7 @@ Defined in: [types/Table.ts:60](https://github.com/TanStack/table/blob/main/pack columnResizingFeature: Table_ColumnResizing; ``` -Defined in: [types/Table.ts:61](https://github.com/TanStack/table/blob/main/packages/table-core/src/types/Table.ts#L61) +Defined in: [types/Table.ts:62](https://github.com/TanStack/table/blob/main/packages/table-core/src/types/Table.ts#L62) *** @@ -95,7 +95,7 @@ Defined in: [types/Table.ts:61](https://github.com/TanStack/table/blob/main/pack columnSizingFeature: Table_ColumnSizing; ``` -Defined in: [types/Table.ts:62](https://github.com/TanStack/table/blob/main/packages/table-core/src/types/Table.ts#L62) +Defined in: [types/Table.ts:63](https://github.com/TanStack/table/blob/main/packages/table-core/src/types/Table.ts#L63) *** @@ -105,7 +105,7 @@ Defined in: [types/Table.ts:62](https://github.com/TanStack/table/blob/main/pack columnVisibilityFeature: Table_ColumnVisibility; ``` -Defined in: [types/Table.ts:63](https://github.com/TanStack/table/blob/main/packages/table-core/src/types/Table.ts#L63) +Defined in: [types/Table.ts:64](https://github.com/TanStack/table/blob/main/packages/table-core/src/types/Table.ts#L64) *** @@ -115,7 +115,7 @@ Defined in: [types/Table.ts:63](https://github.com/TanStack/table/blob/main/pack globalFilteringFeature: Table_GlobalFiltering; ``` -Defined in: [types/Table.ts:64](https://github.com/TanStack/table/blob/main/packages/table-core/src/types/Table.ts#L64) +Defined in: [types/Table.ts:65](https://github.com/TanStack/table/blob/main/packages/table-core/src/types/Table.ts#L65) *** @@ -125,7 +125,7 @@ Defined in: [types/Table.ts:64](https://github.com/TanStack/table/blob/main/pack rowExpandingFeature: Table_RowExpanding; ``` -Defined in: [types/Table.ts:65](https://github.com/TanStack/table/blob/main/packages/table-core/src/types/Table.ts#L65) +Defined in: [types/Table.ts:66](https://github.com/TanStack/table/blob/main/packages/table-core/src/types/Table.ts#L66) *** @@ -135,7 +135,7 @@ Defined in: [types/Table.ts:65](https://github.com/TanStack/table/blob/main/pack rowPaginationFeature: Table_RowPagination; ``` -Defined in: [types/Table.ts:66](https://github.com/TanStack/table/blob/main/packages/table-core/src/types/Table.ts#L66) +Defined in: [types/Table.ts:67](https://github.com/TanStack/table/blob/main/packages/table-core/src/types/Table.ts#L67) *** @@ -145,7 +145,7 @@ Defined in: [types/Table.ts:66](https://github.com/TanStack/table/blob/main/pack rowPinningFeature: Table_RowPinning; ``` -Defined in: [types/Table.ts:67](https://github.com/TanStack/table/blob/main/packages/table-core/src/types/Table.ts#L67) +Defined in: [types/Table.ts:68](https://github.com/TanStack/table/blob/main/packages/table-core/src/types/Table.ts#L68) *** @@ -155,7 +155,7 @@ Defined in: [types/Table.ts:67](https://github.com/TanStack/table/blob/main/pack rowSelectionFeature: Table_RowSelection; ``` -Defined in: [types/Table.ts:68](https://github.com/TanStack/table/blob/main/packages/table-core/src/types/Table.ts#L68) +Defined in: [types/Table.ts:69](https://github.com/TanStack/table/blob/main/packages/table-core/src/types/Table.ts#L69) *** @@ -165,4 +165,4 @@ Defined in: [types/Table.ts:68](https://github.com/TanStack/table/blob/main/pack rowSortingFeature: Table_RowSorting; ``` -Defined in: [types/Table.ts:69](https://github.com/TanStack/table/blob/main/packages/table-core/src/types/Table.ts#L69) +Defined in: [types/Table.ts:70](https://github.com/TanStack/table/blob/main/packages/table-core/src/types/Table.ts#L70) diff --git a/docs/reference/index/interfaces/Table_Internal.md b/docs/reference/index/interfaces/Table_Internal.md index 16398441e5..3f84659ca1 100644 --- a/docs/reference/index/interfaces/Table_Internal.md +++ b/docs/reference/index/interfaces/Table_Internal.md @@ -5,7 +5,7 @@ title: Table_Internal # Interface: Table\_Internal\ -Defined in: [types/Table.ts:96](https://github.com/TanStack/table/blob/main/packages/table-core/src/types/Table.ts#L96) +Defined in: [types/Table.ts:97](https://github.com/TanStack/table/blob/main/packages/table-core/src/types/Table.ts#L97) Internal broad table shape used by feature implementations. @@ -25,13 +25,13 @@ Internal broad table shape used by feature implementations. ## Properties -### \_cellInstanceInitFns? +### \_cellInstanceInitFns ```ts -optional _cellInstanceInitFns: (cell) => void[]; +_cellInstanceInitFns: (cell) => void[]; ``` -Defined in: [core/table/coreTablesFeature.types.ts:167](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L167) +Defined in: [core/table/coreTablesFeature.types.ts:206](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L206) Cache of the `initCellInstanceData` functions for features that define one. @@ -73,7 +73,7 @@ Omit._cellInstanceInitFns optional _cellPrototype: object; ``` -Defined in: [core/table/coreTablesFeature.types.ts:173](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L173) +Defined in: [core/table/coreTablesFeature.types.ts:210](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L210) Prototype cache for Cell objects - shared by all cells in this table @@ -83,13 +83,13 @@ Prototype cache for Cell objects - shared by all cells in this table *** -### \_columnInstanceInitFns? +### \_columnInstanceInitFns ```ts -optional _columnInstanceInitFns: (column) => void[]; +_columnInstanceInitFns: (column) => void[]; ``` -Defined in: [core/table/coreTablesFeature.types.ts:177](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L177) +Defined in: [core/table/coreTablesFeature.types.ts:214](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L214) Cache of the `initColumnInstanceData` functions for features that define one. @@ -131,7 +131,7 @@ Omit._columnInstanceInitFns optional _columnPrototype: object; ``` -Defined in: [core/table/coreTablesFeature.types.ts:183](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L183) +Defined in: [core/table/coreTablesFeature.types.ts:220](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L220) Prototype cache for Column objects - shared by all columns in this table @@ -147,7 +147,7 @@ Prototype cache for Column objects - shared by all columns in this table readonly _features: Partial & TFeatures; ``` -Defined in: [core/table/coreTablesFeature.types.ts:187](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L187) +Defined in: [core/table/coreTablesFeature.types.ts:224](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L224) The features that are enabled for the table. @@ -159,13 +159,13 @@ Omit._features *** -### \_headerGroupInstanceInitFns? +### \_headerGroupInstanceInitFns ```ts -optional _headerGroupInstanceInitFns: (headerGroup) => void[]; +_headerGroupInstanceInitFns: (headerGroup) => void[]; ``` -Defined in: [core/table/coreTablesFeature.types.ts:191](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L191) +Defined in: [core/table/coreTablesFeature.types.ts:228](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L228) Cache of the `initHeaderGroupInstanceData` functions for features that define one. @@ -197,13 +197,13 @@ Omit._headerGroupInstanceInitFns *** -### \_headerInstanceInitFns? +### \_headerInstanceInitFns ```ts -optional _headerInstanceInitFns: (header) => void[]; +_headerInstanceInitFns: (header) => void[]; ``` -Defined in: [core/table/coreTablesFeature.types.ts:197](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L197) +Defined in: [core/table/coreTablesFeature.types.ts:234](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L234) Cache of the `initHeaderInstanceData` functions for features that define one. @@ -245,7 +245,7 @@ Omit._headerInstanceInitFns optional _headerPrototype: object; ``` -Defined in: [core/table/coreTablesFeature.types.ts:203](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L203) +Defined in: [core/table/coreTablesFeature.types.ts:240](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L240) Prototype cache for Header objects - shared by all headers in this table @@ -261,7 +261,7 @@ Prototype cache for Header objects - shared by all headers in this table readonly _reactivity: TableReactivityBindings; ``` -Defined in: [core/table/coreTablesFeature.types.ts:163](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L163) +Defined in: [core/table/coreTablesFeature.types.ts:202](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L202) Table reactivity bindings for interacting with TanStack Store. @@ -271,13 +271,13 @@ Table reactivity bindings for interacting with TanStack Store. *** -### \_rowInstanceInitFns? +### \_rowInstanceInitFns ```ts -optional _rowInstanceInitFns: (row) => void[]; +_rowInstanceInitFns: (row) => void[]; ``` -Defined in: [core/table/coreTablesFeature.types.ts:219](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L219) +Defined in: [core/table/coreTablesFeature.types.ts:256](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L256) Cache of the `initRowInstanceData` functions for features that define one. @@ -315,7 +315,7 @@ Omit._rowInstanceInitFns _rowModelFns: RowModelFns_All; ``` -Defined in: [types/Table.ts:107](https://github.com/TanStack/table/blob/main/packages/table-core/src/types/Table.ts#L107) +Defined in: [types/Table.ts:108](https://github.com/TanStack/table/blob/main/packages/table-core/src/types/Table.ts#L108) *** @@ -325,7 +325,7 @@ Defined in: [types/Table.ts:107](https://github.com/TanStack/table/blob/main/pac _rowModels: CachedRowModel_All; ``` -Defined in: [types/Table.ts:106](https://github.com/TanStack/table/blob/main/packages/table-core/src/types/Table.ts#L106) +Defined in: [types/Table.ts:107](https://github.com/TanStack/table/blob/main/packages/table-core/src/types/Table.ts#L107) *** @@ -335,7 +335,7 @@ Defined in: [types/Table.ts:106](https://github.com/TanStack/table/blob/main/pac optional _rowPrototype: object; ``` -Defined in: [core/table/coreTablesFeature.types.ts:215](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L215) +Defined in: [core/table/coreTablesFeature.types.ts:252](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L252) Prototype cache for Row objects - shared by all rows in this table @@ -351,7 +351,7 @@ Prototype cache for Row objects - shared by all rows in this table atoms: Atoms & Atoms_All; ``` -Defined in: [types/Table.ts:116](https://github.com/TanStack/table/blob/main/packages/table-core/src/types/Table.ts#L116) +Defined in: [types/Table.ts:119](https://github.com/TanStack/table/blob/main/packages/table-core/src/types/Table.ts#L119) The readonly derived atoms for each `TableState` slice. Each derives from its corresponding `baseAtom` plus, optionally, a per-slice external atom or @@ -371,7 +371,7 @@ Omit.atoms baseAtoms: BaseAtoms & BaseAtoms_All; ``` -Defined in: [types/Table.ts:115](https://github.com/TanStack/table/blob/main/packages/table-core/src/types/Table.ts#L115) +Defined in: [types/Table.ts:118](https://github.com/TanStack/table/blob/main/packages/table-core/src/types/Table.ts#L118) The internal writable atoms for each `TableState` slice. This is the library's single write surface — all state mutations from features land here. @@ -1065,116 +1065,37 @@ Table_RowModels.getSortedRowModel initialState: ExtractFeatureMapTypes & TableState_All; ``` -Defined in: [types/Table.ts:114](https://github.com/TanStack/table/blob/main/packages/table-core/src/types/Table.ts#L114) +Defined in: [types/Table.ts:117](https://github.com/TanStack/table/blob/main/packages/table-core/src/types/Table.ts#L117) *** -### options - -```ts -options: object & DebugKeysFor & TableOptions_Core & Partial & TableOptions_ColumnFiltering & TableOptions_ColumnGrouping & TableOptions_ColumnOrdering & TableOptions_ColumnPinning & TableOptions_ColumnResizing & TableOptions_ColumnSizing & TableOptions_ColumnVisibility & TableOptions_GlobalFiltering & TableOptions_RowExpanding & TableOptions_RowPagination & TableOptions_RowPinning & TableOptions_RowSelection & TableOptions_RowSorting> & object; -``` - -Defined in: [types/Table.ts:108](https://github.com/TanStack/table/blob/main/packages/table-core/src/types/Table.ts#L108) - -#### Type Declaration - -##### debugAll? - -```ts -optional debugAll: boolean; -``` - -##### debugCache? - -```ts -optional debugCache: boolean; -``` - -##### debugCells? +### optionAtoms ```ts -optional debugCells: boolean; +readonly optionAtoms: TableOptionAtoms; ``` -##### debugColumns? +Defined in: [core/table/coreTablesFeature.types.ts:283](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L283) -```ts -optional debugColumns: boolean; -``` - -##### debugHeaders? - -```ts -optional debugHeaders: boolean; -``` +Stable atoms for individual resolved option values. -##### debugRows? +Ordinary options are writable. Construction-static options are readonly. -```ts -optional debugRows: boolean; -``` - -##### debugTable? - -```ts -optional debugTable: boolean; -``` - -#### Type Declaration - -##### atoms? - -```ts -optional atoms: Partial<{ - cellSelection?: Atom; - columnFilters?: Atom; - columnOrder?: Atom; - columnPinning?: Atom; - columnResizing?: Atom; - columnSizing?: Atom; - columnVisibility?: Atom; - expanded?: Atom; - globalFilter?: Atom; - grouping?: Atom; - pagination?: Atom; - rowPinning?: Atom; - rowSelection?: Atom; - sorting?: Atom; -}>; -``` - -##### initialState? - -```ts -optional initialState: TableState_All; -``` - -##### state? +#### Inherited from ```ts -optional state: TableState_All; +Omit.optionAtoms ``` *** -### optionsStore? +### options ```ts -readonly optional optionsStore: Atom>; +options: TableOptionsLive & Readonly & Partial & TableOptions_ColumnFiltering & TableOptions_ColumnGrouping & TableOptions_ColumnOrdering & TableOptions_ColumnPinning & TableOptions_ColumnResizing & TableOptions_ColumnSizing & TableOptions_ColumnVisibility & TableOptions_GlobalFiltering & TableOptions_RowExpanding & TableOptions_RowPagination & TableOptions_RowPinning & TableOptions_RowSelection & TableOptions_RowSorting> & object>; ``` -Defined in: [core/table/coreTablesFeature.types.ts:244](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L244) - -Writable atom for table options. Only created when `createOptionsStore` is -true on the active core reactivity bindings. Adapters that opt out keep -options as plain resolved data instead of backing them with an atom. - -#### Inherited from - -```ts -Omit.optionsStore -``` +Defined in: [types/Table.ts:109](https://github.com/TanStack/table/blob/main/packages/table-core/src/types/Table.ts#L109) *** @@ -1184,7 +1105,7 @@ Omit.optionsStore reset: () => void; ``` -Defined in: [core/table/coreTablesFeature.types.ts:264](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L264) +Defined in: [core/table/coreTablesFeature.types.ts:303](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L303) Resets the table's internal base atoms to `table.initialState`. @@ -1211,7 +1132,7 @@ Omit.reset setOptions: (newOptions) => void; ``` -Defined in: [core/table/coreTablesFeature.types.ts:269](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L269) +Defined in: [core/table/coreTablesFeature.types.ts:308](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L308) Updates the table options by applying a value or updater to the current resolved options and then merging them through `options.mergeOptions`. @@ -1240,4 +1161,4 @@ Omit.setOptions store: ReadonlyStore> & ReadonlyStore; ``` -Defined in: [types/Table.ts:117](https://github.com/TanStack/table/blob/main/packages/table-core/src/types/Table.ts#L117) +Defined in: [types/Table.ts:120](https://github.com/TanStack/table/blob/main/packages/table-core/src/types/Table.ts#L120) diff --git a/docs/reference/index/interfaces/Table_Table.md b/docs/reference/index/interfaces/Table_Table.md index edc13ea2c3..7a49be946a 100644 --- a/docs/reference/index/interfaces/Table_Table.md +++ b/docs/reference/index/interfaces/Table_Table.md @@ -5,7 +5,7 @@ title: Table_Table # Interface: Table\_Table\ -Defined in: [core/table/coreTablesFeature.types.ts:252](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L252) +Defined in: [core/table/coreTablesFeature.types.ts:291](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L291) ## Extends @@ -27,13 +27,13 @@ Defined in: [core/table/coreTablesFeature.types.ts:252](https://github.com/TanSt ## Properties -### \_cellInstanceInitFns? +### \_cellInstanceInitFns ```ts -optional _cellInstanceInitFns: (cell) => void[]; +_cellInstanceInitFns: (cell) => void[]; ``` -Defined in: [core/table/coreTablesFeature.types.ts:167](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L167) +Defined in: [core/table/coreTablesFeature.types.ts:206](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L206) Cache of the `initCellInstanceData` functions for features that define one. @@ -73,7 +73,7 @@ Cache of the `initCellInstanceData` functions for features that define one. optional _cellPrototype: object; ``` -Defined in: [core/table/coreTablesFeature.types.ts:173](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L173) +Defined in: [core/table/coreTablesFeature.types.ts:210](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L210) Prototype cache for Cell objects - shared by all cells in this table @@ -83,13 +83,13 @@ Prototype cache for Cell objects - shared by all cells in this table *** -### \_columnInstanceInitFns? +### \_columnInstanceInitFns ```ts -optional _columnInstanceInitFns: (column) => void[]; +_columnInstanceInitFns: (column) => void[]; ``` -Defined in: [core/table/coreTablesFeature.types.ts:177](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L177) +Defined in: [core/table/coreTablesFeature.types.ts:214](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L214) Cache of the `initColumnInstanceData` functions for features that define one. @@ -129,7 +129,7 @@ Cache of the `initColumnInstanceData` functions for features that define one. optional _columnPrototype: object; ``` -Defined in: [core/table/coreTablesFeature.types.ts:183](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L183) +Defined in: [core/table/coreTablesFeature.types.ts:220](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L220) Prototype cache for Column objects - shared by all columns in this table @@ -145,7 +145,7 @@ Prototype cache for Column objects - shared by all columns in this table readonly _features: Partial & TFeatures; ``` -Defined in: [core/table/coreTablesFeature.types.ts:187](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L187) +Defined in: [core/table/coreTablesFeature.types.ts:224](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L224) The features that are enabled for the table. @@ -155,13 +155,13 @@ The features that are enabled for the table. *** -### \_headerGroupInstanceInitFns? +### \_headerGroupInstanceInitFns ```ts -optional _headerGroupInstanceInitFns: (headerGroup) => void[]; +_headerGroupInstanceInitFns: (headerGroup) => void[]; ``` -Defined in: [core/table/coreTablesFeature.types.ts:191](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L191) +Defined in: [core/table/coreTablesFeature.types.ts:228](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L228) Cache of the `initHeaderGroupInstanceData` functions for features that define one. @@ -191,13 +191,13 @@ Cache of the `initHeaderGroupInstanceData` functions for features that define on *** -### \_headerInstanceInitFns? +### \_headerInstanceInitFns ```ts -optional _headerInstanceInitFns: (header) => void[]; +_headerInstanceInitFns: (header) => void[]; ``` -Defined in: [core/table/coreTablesFeature.types.ts:197](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L197) +Defined in: [core/table/coreTablesFeature.types.ts:234](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L234) Cache of the `initHeaderInstanceData` functions for features that define one. @@ -237,7 +237,7 @@ Cache of the `initHeaderInstanceData` functions for features that define one. optional _headerPrototype: object; ``` -Defined in: [core/table/coreTablesFeature.types.ts:203](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L203) +Defined in: [core/table/coreTablesFeature.types.ts:240](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L240) Prototype cache for Header objects - shared by all headers in this table @@ -253,7 +253,7 @@ Prototype cache for Header objects - shared by all headers in this table readonly _reactivity: TableReactivityBindings; ``` -Defined in: [core/table/coreTablesFeature.types.ts:163](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L163) +Defined in: [core/table/coreTablesFeature.types.ts:202](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L202) Table reactivity bindings for interacting with TanStack Store. @@ -263,13 +263,13 @@ Table reactivity bindings for interacting with TanStack Store. *** -### \_rowInstanceInitFns? +### \_rowInstanceInitFns ```ts -optional _rowInstanceInitFns: (row) => void[]; +_rowInstanceInitFns: (row) => void[]; ``` -Defined in: [core/table/coreTablesFeature.types.ts:219](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L219) +Defined in: [core/table/coreTablesFeature.types.ts:256](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L256) Cache of the `initRowInstanceData` functions for features that define one. @@ -305,7 +305,7 @@ Cache of the `initRowInstanceData` functions for features that define one. readonly _rowModelFns: RowModelFns; ``` -Defined in: [core/table/coreTablesFeature.types.ts:207](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L207) +Defined in: [core/table/coreTablesFeature.types.ts:244](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L244) The row model processing functions that are used to process the data by features. @@ -321,7 +321,7 @@ The row model processing functions that are used to process the data by features readonly _rowModels: CachedRowModels; ``` -Defined in: [core/table/coreTablesFeature.types.ts:211](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L211) +Defined in: [core/table/coreTablesFeature.types.ts:248](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L248) The row models that are enabled for the table. @@ -337,7 +337,7 @@ The row models that are enabled for the table. optional _rowPrototype: object; ``` -Defined in: [core/table/coreTablesFeature.types.ts:215](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L215) +Defined in: [core/table/coreTablesFeature.types.ts:252](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L252) Prototype cache for Row objects - shared by all rows in this table @@ -353,7 +353,7 @@ Prototype cache for Row objects - shared by all rows in this table readonly atoms: Atoms; ``` -Defined in: [core/table/coreTablesFeature.types.ts:225](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L225) +Defined in: [core/table/coreTablesFeature.types.ts:262](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L262) The readonly derived atoms for each `TableState` slice. Each derives from its corresponding `baseAtom` plus, optionally, a per-slice external atom or @@ -371,7 +371,7 @@ external state value (precedence: external atom > external state > base atom). readonly baseAtoms: BaseAtoms; ``` -Defined in: [core/table/coreTablesFeature.types.ts:230](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L230) +Defined in: [core/table/coreTablesFeature.types.ts:267](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L267) The internal writable atoms for each `TableState` slice. This is the library's single write surface — all state mutations from features land here. @@ -388,7 +388,7 @@ single write surface — all state mutations from features land here. readonly initialState: ExtractFeatureMapTypes; ``` -Defined in: [core/table/coreTablesFeature.types.ts:234](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L234) +Defined in: [core/table/coreTablesFeature.types.ts:271](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L271) This is the resolved initial state of the table. @@ -398,37 +398,39 @@ This is the resolved initial state of the table. *** -### options +### optionAtoms ```ts -readonly options: TableOptions; +readonly optionAtoms: TableOptionAtoms; ``` -Defined in: [core/table/coreTablesFeature.types.ts:238](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L238) +Defined in: [core/table/coreTablesFeature.types.ts:283](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L283) -A read-only reference to the table's current options. +Stable atoms for individual resolved option values. + +Ordinary options are writable. Construction-static options are readonly. #### Inherited from -[`Table_CoreProperties`](Table_CoreProperties.md).[`options`](Table_CoreProperties.md#options) +[`Table_CoreProperties`](Table_CoreProperties.md).[`optionAtoms`](Table_CoreProperties.md#optionatoms) *** -### optionsStore? +### options ```ts -readonly optional optionsStore: Atom>; +readonly options: TableOptionsLive; ``` -Defined in: [core/table/coreTablesFeature.types.ts:244](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L244) +Defined in: [core/table/coreTablesFeature.types.ts:277](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L277) + +A stable live view of the table's current resolved options. -Writable atom for table options. Only created when `createOptionsStore` is -true on the active core reactivity bindings. Adapters that opt out keep -options as plain resolved data instead of backing them with an atom. +Reading a property reads the matching entry in `optionAtoms`. #### Inherited from -[`Table_CoreProperties`](Table_CoreProperties.md).[`optionsStore`](Table_CoreProperties.md#optionsstore) +[`Table_CoreProperties`](Table_CoreProperties.md).[`options`](Table_CoreProperties.md#options) *** @@ -438,7 +440,7 @@ options as plain resolved data instead of backing them with an atom. reset: () => void; ``` -Defined in: [core/table/coreTablesFeature.types.ts:264](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L264) +Defined in: [core/table/coreTablesFeature.types.ts:303](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L303) Resets the table's internal base atoms to `table.initialState`. @@ -459,7 +461,7 @@ reset hooks for mutable, transient table-instance data. setOptions: (newOptions) => void; ``` -Defined in: [core/table/coreTablesFeature.types.ts:269](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L269) +Defined in: [core/table/coreTablesFeature.types.ts:308](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L308) Updates the table options by applying a value or updater to the current resolved options and then merging them through `options.mergeOptions`. @@ -482,7 +484,7 @@ resolved options and then merging them through `options.mergeOptions`. readonly store: ReadonlyStore>; ``` -Defined in: [core/table/coreTablesFeature.types.ts:249](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L249) +Defined in: [core/table/coreTablesFeature.types.ts:288](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L288) The readonly flat store for the table state. Derives from `table.atoms` only; never reads external state directly. diff --git a/docs/reference/index/type-aliases/API.md b/docs/reference/index/type-aliases/API.md new file mode 100644 index 0000000000..74d317a117 --- /dev/null +++ b/docs/reference/index/type-aliases/API.md @@ -0,0 +1,22 @@ +--- +id: API +title: API +--- + +# Type Alias: API + +```ts +type API = + | { + compare?: (previous, next) => boolean; + computed: () => any; + fn?: never; +} + | { + compare?: never; + computed?: never; + fn: (...args) => any; +}; +``` + +Defined in: [utils.ts:325](https://github.com/TanStack/table/blob/main/packages/table-core/src/utils.ts#L325) diff --git a/docs/reference/index/type-aliases/APIObject.md b/docs/reference/index/type-aliases/APIObject.md index f381bfcaaa..0582876ddc 100644 --- a/docs/reference/index/type-aliases/APIObject.md +++ b/docs/reference/index/type-aliases/APIObject.md @@ -3,20 +3,10 @@ id: APIObject title: APIObject --- -# Type Alias: APIObject\ +# Type Alias: APIObject ```ts -type APIObject = Record>; +type APIObject = Record; ``` -Defined in: [utils.ts:367](https://github.com/TanStack/table/blob/main/packages/table-core/src/utils.ts#L367) - -## Type Parameters - -### TDeps - -`TDeps` *extends* `ReadonlyArray`\<`any`\> - -### TDepArgs - -`TDepArgs` +Defined in: [utils.ts:337](https://github.com/TanStack/table/blob/main/packages/table-core/src/utils.ts#L337) diff --git a/docs/reference/index/type-aliases/Atoms_All.md b/docs/reference/index/type-aliases/Atoms_All.md index c965cc6dd6..a058c91dc0 100644 --- a/docs/reference/index/type-aliases/Atoms_All.md +++ b/docs/reference/index/type-aliases/Atoms_All.md @@ -9,4 +9,4 @@ title: Atoms_All type Atoms_All = { [K in keyof TableState_All]?: ReadonlyAtom }; ``` -Defined in: [core/table/coreTablesFeature.types.ts:81](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L81) +Defined in: [core/table/coreTablesFeature.types.ts:120](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L120) diff --git a/docs/reference/index/type-aliases/BaseAtoms_All.md b/docs/reference/index/type-aliases/BaseAtoms_All.md index 9bef86d951..a1ebaeb925 100644 --- a/docs/reference/index/type-aliases/BaseAtoms_All.md +++ b/docs/reference/index/type-aliases/BaseAtoms_All.md @@ -9,7 +9,7 @@ title: BaseAtoms_All type BaseAtoms_All = { [K in keyof TableState_All]?: Atom> }; ``` -Defined in: [core/table/coreTablesFeature.types.ts:78](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L78) +Defined in: [core/table/coreTablesFeature.types.ts:117](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L117) Internal "all features" flat variants of the atom types. `Table_Internal` uses these so feature code (written generically over `TFeatures`) can access diff --git a/docs/reference/index/type-aliases/ExternalAtoms_All.md b/docs/reference/index/type-aliases/ExternalAtoms_All.md index 450fc7a09c..1141246d21 100644 --- a/docs/reference/index/type-aliases/ExternalAtoms_All.md +++ b/docs/reference/index/type-aliases/ExternalAtoms_All.md @@ -9,4 +9,4 @@ title: ExternalAtoms_All type ExternalAtoms_All = Partial<{ [K in keyof TableState_All]: Atom> }>; ``` -Defined in: [core/table/coreTablesFeature.types.ts:84](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L84) +Defined in: [core/table/coreTablesFeature.types.ts:123](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L123) diff --git a/docs/reference/index/type-aliases/PrototypeAPI.md b/docs/reference/index/type-aliases/PrototypeAPI.md new file mode 100644 index 0000000000..a6cd8c7fbd --- /dev/null +++ b/docs/reference/index/type-aliases/PrototypeAPI.md @@ -0,0 +1,22 @@ +--- +id: PrototypeAPI +title: PrototypeAPI +--- + +# Type Alias: PrototypeAPI + +```ts +type PrototypeAPI = + | { + compare?: (previous, next) => boolean; + computed: (self) => any; + fn?: never; +} + | { + compare?: never; + computed?: never; + fn: (self, ...args) => any; +}; +``` + +Defined in: [utils.ts:383](https://github.com/TanStack/table/blob/main/packages/table-core/src/utils.ts#L383) diff --git a/docs/reference/index/type-aliases/PrototypeAPIObject.md b/docs/reference/index/type-aliases/PrototypeAPIObject.md index 324eebd46f..1dbd99278f 100644 --- a/docs/reference/index/type-aliases/PrototypeAPIObject.md +++ b/docs/reference/index/type-aliases/PrototypeAPIObject.md @@ -3,20 +3,10 @@ id: PrototypeAPIObject title: PrototypeAPIObject --- -# Type Alias: PrototypeAPIObject\ +# Type Alias: PrototypeAPIObject ```ts -type PrototypeAPIObject = Record>; +type PrototypeAPIObject = Record; ``` -Defined in: [utils.ts:422](https://github.com/TanStack/table/blob/main/packages/table-core/src/utils.ts#L422) - -## Type Parameters - -### TDeps - -`TDeps` *extends* `ReadonlyArray`\<`any`\> - -### TDepArgs - -`TDepArgs` +Defined in: [utils.ts:395](https://github.com/TanStack/table/blob/main/packages/table-core/src/utils.ts#L395) diff --git a/docs/reference/index/type-aliases/Table.md b/docs/reference/index/type-aliases/Table.md index 2bbfee87c3..6a1ed5e4a4 100644 --- a/docs/reference/index/type-aliases/Table.md +++ b/docs/reference/index/type-aliases/Table.md @@ -9,7 +9,7 @@ title: Table type Table = Table_Core & ExtractFeatureMapTypes>; ``` -Defined in: [types/Table.ts:75](https://github.com/TanStack/table/blob/main/packages/table-core/src/types/Table.ts#L75) +Defined in: [types/Table.ts:76](https://github.com/TanStack/table/blob/main/packages/table-core/src/types/Table.ts#L76) The table object that includes both the core table functionality and the features that are enabled via the `features` table option. diff --git a/docs/reference/index/type-aliases/TableOptionAtoms.md b/docs/reference/index/type-aliases/TableOptionAtoms.md new file mode 100644 index 0000000000..842f96422c --- /dev/null +++ b/docs/reference/index/type-aliases/TableOptionAtoms.md @@ -0,0 +1,38 @@ +--- +id: TableOptionAtoms +title: TableOptionAtoms +--- + +# Type Alias: TableOptionAtoms\ + +```ts +type TableOptionAtoms = object & { readonly [K in keyof TableOptions as K extends "snapshotVersion" ? never : K]: K extends ConstructStaticOptionKey ? ReadonlyAtom[K]> : Atom[K]> }; +``` + +Defined in: [core/table/coreTablesFeature.types.ts:77](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L77) + +One atom per currently resolved table option. + +The atom properties themselves are readonly so their identities stay +stable. Ordinary option atoms are writable; construction-static options +remain readonly. + +## Type Declaration + +### snapshotVersion + +```ts +readonly snapshotVersion: ReadonlyAtom; +``` + +Increments once after each atomic update of the resolved options. + +## Type Parameters + +### TFeatures + +`TFeatures` *extends* [`TableFeatures`](../interfaces/TableFeatures.md) + +### TData + +`TData` *extends* [`RowData`](RowData.md) diff --git a/docs/reference/index/type-aliases/TableOptionsLive.md b/docs/reference/index/type-aliases/TableOptionsLive.md new file mode 100644 index 0000000000..4f6f4de690 --- /dev/null +++ b/docs/reference/index/type-aliases/TableOptionsLive.md @@ -0,0 +1,26 @@ +--- +id: TableOptionsLive +title: TableOptionsLive +--- + +# Type Alias: TableOptionsLive\ + +```ts +type TableOptionsLive = { readonly [K in keyof TableOptions]: TableOptions[K] }; +``` + +Defined in: [core/table/coreTablesFeature.types.ts:97](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.types.ts#L97) + +The stable readonly options view exposed by `table.options`. + +Every property read is routed to the matching existing option atom. + +## Type Parameters + +### TFeatures + +`TFeatures` *extends* [`TableFeatures`](../interfaces/TableFeatures.md) + +### TData + +`TData` *extends* [`RowData`](RowData.md) diff --git a/docs/reference/index/variables/cellSelectionFeature.md b/docs/reference/index/variables/cellSelectionFeature.md index 975f8f178f..963e3f0c66 100644 --- a/docs/reference/index/variables/cellSelectionFeature.md +++ b/docs/reference/index/variables/cellSelectionFeature.md @@ -9,6 +9,6 @@ title: cellSelectionFeature const cellSelectionFeature: TableFeature; ``` -Defined in: [features/cell-selection/cellSelectionFeature.ts:38](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/cell-selection/cellSelectionFeature.ts#L38) +Defined in: [features/cell-selection/cellSelectionFeature.ts:37](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/cell-selection/cellSelectionFeature.ts#L37) Feature that adds spreadsheet-style cell range selection state and APIs. diff --git a/docs/reference/index/variables/columnPinningFeature.md b/docs/reference/index/variables/columnPinningFeature.md index 080d77d7b1..c046d128cc 100644 --- a/docs/reference/index/variables/columnPinningFeature.md +++ b/docs/reference/index/variables/columnPinningFeature.md @@ -9,7 +9,7 @@ title: columnPinningFeature const columnPinningFeature: TableFeature; ``` -Defined in: [features/column-pinning/columnPinningFeature.ts:51](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/column-pinning/columnPinningFeature.ts#L51) +Defined in: [features/column-pinning/columnPinningFeature.ts:57](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/column-pinning/columnPinningFeature.ts#L57) Feature that adds column pinning state and APIs for logical start, center, and end regions. diff --git a/docs/reference/index/variables/columnSizingFeature.md b/docs/reference/index/variables/columnSizingFeature.md index 2863ec9ac4..2467d71021 100644 --- a/docs/reference/index/variables/columnSizingFeature.md +++ b/docs/reference/index/variables/columnSizingFeature.md @@ -9,6 +9,6 @@ title: columnSizingFeature const columnSizingFeature: TableFeature; ``` -Defined in: [features/column-sizing/columnSizingFeature.ts:28](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/column-sizing/columnSizingFeature.ts#L28) +Defined in: [features/column-sizing/columnSizingFeature.ts:54](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/column-sizing/columnSizingFeature.ts#L54) Feature that adds column sizing state, defaults, and size measurement APIs. diff --git a/docs/reference/index/variables/rowPinningFeature.md b/docs/reference/index/variables/rowPinningFeature.md index 08769c84b0..8d40cbcb6f 100644 --- a/docs/reference/index/variables/rowPinningFeature.md +++ b/docs/reference/index/variables/rowPinningFeature.md @@ -9,6 +9,6 @@ title: rowPinningFeature const rowPinningFeature: TableFeature; ``` -Defined in: [features/row-pinning/rowPinningFeature.ts:24](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/row-pinning/rowPinningFeature.ts#L24) +Defined in: [features/row-pinning/rowPinningFeature.ts:29](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/row-pinning/rowPinningFeature.ts#L29) Feature that adds row pinning state and APIs for top, center, and bottom rows. diff --git a/docs/reference/static-functions/functions/aggregateColumnValue.md b/docs/reference/static-functions/functions/aggregateColumnValue.md index 37f7a9d85b..3d483d0c44 100644 --- a/docs/reference/static-functions/functions/aggregateColumnValue.md +++ b/docs/reference/static-functions/functions/aggregateColumnValue.md @@ -9,7 +9,7 @@ title: aggregateColumnValue function aggregateColumnValue(args): unknown; ``` -Defined in: [features/row-aggregation/rowAggregationFeature.utils.ts:307](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/row-aggregation/rowAggregationFeature.utils.ts#L307) +Defined in: [features/row-aggregation/rowAggregationFeature.utils.ts:337](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/row-aggregation/rowAggregationFeature.utils.ts#L337) Executes every configured aggregation over a depth-selected row frontier. diff --git a/docs/reference/static-functions/functions/cell_getIsAggregated.md b/docs/reference/static-functions/functions/cell_getIsAggregated.md index 11f960b9cb..37c50c34ab 100644 --- a/docs/reference/static-functions/functions/cell_getIsAggregated.md +++ b/docs/reference/static-functions/functions/cell_getIsAggregated.md @@ -9,7 +9,7 @@ title: cell_getIsAggregated function cell_getIsAggregated(cell): boolean; ``` -Defined in: [features/row-aggregation/rowAggregationFeature.utils.ts:450](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/row-aggregation/rowAggregationFeature.utils.ts#L450) +Defined in: [features/row-aggregation/rowAggregationFeature.utils.ts:480](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/row-aggregation/rowAggregationFeature.utils.ts#L480) Implements `cell.getIsAggregated()` for synthetic grouped rows. diff --git a/docs/reference/static-functions/functions/cell_getIsSelected.md b/docs/reference/static-functions/functions/cell_getIsSelected.md index 204ee18839..d2cb2e18c3 100644 --- a/docs/reference/static-functions/functions/cell_getIsSelected.md +++ b/docs/reference/static-functions/functions/cell_getIsSelected.md @@ -14,7 +14,7 @@ Defined in: [features/cell-selection/cellSelectionFeature.utils.ts:396](https:// Checks whether this cell falls inside any selected range. Deliberately not memoized. Registering this through `assignPrototypeAPIs` -with `memoDeps` would allocate a memo closure and dependency array per cell, +with a native computed would allocate a memo closure per cell, which costs more than the handful of integer comparisons it would save. ## Type Parameters diff --git a/docs/reference/static-functions/functions/column_clearSorting.md b/docs/reference/static-functions/functions/column_clearSorting.md index f47ab88d02..8a33162caa 100644 --- a/docs/reference/static-functions/functions/column_clearSorting.md +++ b/docs/reference/static-functions/functions/column_clearSorting.md @@ -9,7 +9,7 @@ title: column_clearSorting function column_clearSorting(column): void; ``` -Defined in: [features/row-sorting/rowSortingFeature.utils.ts:471](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/row-sorting/rowSortingFeature.utils.ts#L471) +Defined in: [features/row-sorting/rowSortingFeature.utils.ts:476](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/row-sorting/rowSortingFeature.utils.ts#L476) Removes this column from the sorting state. diff --git a/docs/reference/static-functions/functions/column_getAggregationFns.md b/docs/reference/static-functions/functions/column_getAggregationFns.md index 2974ca4a65..33d9eeb6b6 100644 --- a/docs/reference/static-functions/functions/column_getAggregationFns.md +++ b/docs/reference/static-functions/functions/column_getAggregationFns.md @@ -9,7 +9,7 @@ title: column_getAggregationFns function column_getAggregationFns(column): readonly ResolvedAggregationFn[]; ``` -Defined in: [features/row-aggregation/rowAggregationFeature.utils.ts:201](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/row-aggregation/rowAggregationFeature.utils.ts#L201) +Defined in: [features/row-aggregation/rowAggregationFeature.utils.ts:231](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/row-aggregation/rowAggregationFeature.utils.ts#L231) Resolves and validates a column's scalar or multiple aggregation option. diff --git a/docs/reference/static-functions/functions/column_getAggregationValue.md b/docs/reference/static-functions/functions/column_getAggregationValue.md index 1121ccef2f..1a14f0b3fb 100644 --- a/docs/reference/static-functions/functions/column_getAggregationValue.md +++ b/docs/reference/static-functions/functions/column_getAggregationValue.md @@ -9,7 +9,7 @@ title: column_getAggregationValue function column_getAggregationValue(column, options?): ColumnAggregationValue; ``` -Defined in: [features/row-aggregation/rowAggregationFeature.utils.ts:386](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/row-aggregation/rowAggregationFeature.utils.ts#L386) +Defined in: [features/row-aggregation/rowAggregationFeature.utils.ts:416](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/row-aggregation/rowAggregationFeature.utils.ts#L416) Implements `column.getAggregationValue(options?)` and its default cache. diff --git a/docs/reference/static-functions/functions/column_getAutoAggregationFn.md b/docs/reference/static-functions/functions/column_getAutoAggregationFn.md index ffd34f4af4..1a1646334b 100644 --- a/docs/reference/static-functions/functions/column_getAutoAggregationFn.md +++ b/docs/reference/static-functions/functions/column_getAutoAggregationFn.md @@ -11,7 +11,7 @@ function column_getAutoAggregationFn(column): | undefined; ``` -Defined in: [features/row-aggregation/rowAggregationFeature.utils.ts:159](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/row-aggregation/rowAggregationFeature.utils.ts#L159) +Defined in: [features/row-aggregation/rowAggregationFeature.utils.ts:189](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/row-aggregation/rowAggregationFeature.utils.ts#L189) Resolves the `sum` or `extent` definition inferred from the first core row. diff --git a/docs/reference/static-functions/functions/column_getCanMultiSort.md b/docs/reference/static-functions/functions/column_getCanMultiSort.md index 537236a0b0..423faaa58b 100644 --- a/docs/reference/static-functions/functions/column_getCanMultiSort.md +++ b/docs/reference/static-functions/functions/column_getCanMultiSort.md @@ -9,7 +9,7 @@ title: column_getCanMultiSort function column_getCanMultiSort(column): boolean; ``` -Defined in: [features/row-sorting/rowSortingFeature.utils.ts:406](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/row-sorting/rowSortingFeature.utils.ts#L406) +Defined in: [features/row-sorting/rowSortingFeature.utils.ts:411](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/row-sorting/rowSortingFeature.utils.ts#L411) Checks whether this column can be added to a multi-sort state. diff --git a/docs/reference/static-functions/functions/column_getCanSort.md b/docs/reference/static-functions/functions/column_getCanSort.md index 6b74553334..7e46369de3 100644 --- a/docs/reference/static-functions/functions/column_getCanSort.md +++ b/docs/reference/static-functions/functions/column_getCanSort.md @@ -9,7 +9,7 @@ title: column_getCanSort function column_getCanSort(column): boolean; ``` -Defined in: [features/row-sorting/rowSortingFeature.utils.ts:383](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/row-sorting/rowSortingFeature.utils.ts#L383) +Defined in: [features/row-sorting/rowSortingFeature.utils.ts:388](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/row-sorting/rowSortingFeature.utils.ts#L388) Checks whether this accessor column can participate in sorting. diff --git a/docs/reference/static-functions/functions/column_getFirstSortDir.md b/docs/reference/static-functions/functions/column_getFirstSortDir.md index b00c455475..2a2e59135e 100644 --- a/docs/reference/static-functions/functions/column_getFirstSortDir.md +++ b/docs/reference/static-functions/functions/column_getFirstSortDir.md @@ -9,7 +9,7 @@ title: column_getFirstSortDir function column_getFirstSortDir(column): "asc" | "desc"; ``` -Defined in: [features/row-sorting/rowSortingFeature.utils.ts:327](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/row-sorting/rowSortingFeature.utils.ts#L327) +Defined in: [features/row-sorting/rowSortingFeature.utils.ts:332](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/row-sorting/rowSortingFeature.utils.ts#L332) Resolves the first direction used when this column begins sorting. diff --git a/docs/reference/static-functions/functions/column_getIsSorted.md b/docs/reference/static-functions/functions/column_getIsSorted.md index 52f98c5829..9d306f268d 100644 --- a/docs/reference/static-functions/functions/column_getIsSorted.md +++ b/docs/reference/static-functions/functions/column_getIsSorted.md @@ -9,7 +9,7 @@ title: column_getIsSorted function column_getIsSorted(column): false | SortDirection; ``` -Defined in: [features/row-sorting/rowSortingFeature.utils.ts:429](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/row-sorting/rowSortingFeature.utils.ts#L429) +Defined in: [features/row-sorting/rowSortingFeature.utils.ts:434](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/row-sorting/rowSortingFeature.utils.ts#L434) Reads this column's current sort direction. diff --git a/docs/reference/static-functions/functions/column_getNextSortingOrder.md b/docs/reference/static-functions/functions/column_getNextSortingOrder.md index 85be91cfad..51d7c80389 100644 --- a/docs/reference/static-functions/functions/column_getNextSortingOrder.md +++ b/docs/reference/static-functions/functions/column_getNextSortingOrder.md @@ -9,7 +9,7 @@ title: column_getNextSortingOrder function column_getNextSortingOrder(column, multi?): false | "asc" | "desc"; ``` -Defined in: [features/row-sorting/rowSortingFeature.utils.ts:350](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/row-sorting/rowSortingFeature.utils.ts#L350) +Defined in: [features/row-sorting/rowSortingFeature.utils.ts:355](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/row-sorting/rowSortingFeature.utils.ts#L355) Resolves the next sort order for this column's toggle cycle. diff --git a/docs/reference/static-functions/functions/column_getSortIndex.md b/docs/reference/static-functions/functions/column_getSortIndex.md index 0470db21d7..75b706409b 100644 --- a/docs/reference/static-functions/functions/column_getSortIndex.md +++ b/docs/reference/static-functions/functions/column_getSortIndex.md @@ -9,7 +9,7 @@ title: column_getSortIndex function column_getSortIndex(column): number; ``` -Defined in: [features/row-sorting/rowSortingFeature.utils.ts:450](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/row-sorting/rowSortingFeature.utils.ts#L450) +Defined in: [features/row-sorting/rowSortingFeature.utils.ts:455](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/row-sorting/rowSortingFeature.utils.ts#L455) Finds this column's position in the ordered `state.sorting` array. diff --git a/docs/reference/static-functions/functions/column_getToggleSortingHandler.md b/docs/reference/static-functions/functions/column_getToggleSortingHandler.md index 5e5cbf5296..8d7b9474c2 100644 --- a/docs/reference/static-functions/functions/column_getToggleSortingHandler.md +++ b/docs/reference/static-functions/functions/column_getToggleSortingHandler.md @@ -9,7 +9,7 @@ title: column_getToggleSortingHandler function column_getToggleSortingHandler(column): (e) => void; ``` -Defined in: [features/row-sorting/rowSortingFeature.utils.ts:493](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/row-sorting/rowSortingFeature.utils.ts#L493) +Defined in: [features/row-sorting/rowSortingFeature.utils.ts:498](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/row-sorting/rowSortingFeature.utils.ts#L498) Creates a header event handler that toggles this column's sorting. diff --git a/docs/reference/static-functions/functions/formatAggregatedCellValue.md b/docs/reference/static-functions/functions/formatAggregatedCellValue.md index 2cfa6f6b1d..9f7fc8be77 100644 --- a/docs/reference/static-functions/functions/formatAggregatedCellValue.md +++ b/docs/reference/static-functions/functions/formatAggregatedCellValue.md @@ -9,7 +9,7 @@ title: formatAggregatedCellValue function formatAggregatedCellValue(value, option): string | null; ``` -Defined in: [features/row-aggregation/rowAggregationFeature.utils.ts:471](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/row-aggregation/rowAggregationFeature.utils.ts#L471) +Defined in: [features/row-aggregation/rowAggregationFeature.utils.ts:501](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/row-aggregation/rowAggregationFeature.utils.ts#L501) Formats the default scalar or keyed aggregated-cell representation. diff --git a/docs/reference/static-functions/functions/getDefaultRowSelectionState.md b/docs/reference/static-functions/functions/getDefaultRowSelectionState.md index 6c48067ffe..caaa1f1eb5 100644 --- a/docs/reference/static-functions/functions/getDefaultRowSelectionState.md +++ b/docs/reference/static-functions/functions/getDefaultRowSelectionState.md @@ -9,7 +9,7 @@ title: getDefaultRowSelectionState function getDefaultRowSelectionState(): RowSelectionState; ``` -Defined in: [features/row-selection/rowSelectionFeature.utils.ts:31](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/row-selection/rowSelectionFeature.utils.ts#L31) +Defined in: [features/row-selection/rowSelectionFeature.utils.ts:35](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/row-selection/rowSelectionFeature.utils.ts#L35) Creates the default row selection state. diff --git a/docs/reference/static-functions/functions/header_getContext.md b/docs/reference/static-functions/functions/header_getContext.md index af131167a8..5e301559c8 100644 --- a/docs/reference/static-functions/functions/header_getContext.md +++ b/docs/reference/static-functions/functions/header_getContext.md @@ -9,7 +9,7 @@ title: header_getContext function header_getContext(header): object; ``` -Defined in: [core/headers/coreHeadersFeature.utils.ts:54](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/headers/coreHeadersFeature.utils.ts#L54) +Defined in: [core/headers/coreHeadersFeature.utils.ts:62](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/headers/coreHeadersFeature.utils.ts#L62) Builds the render context passed to a column's `header` or `footer` template. diff --git a/docs/reference/static-functions/functions/header_getLeafHeaders.md b/docs/reference/static-functions/functions/header_getLeafHeaders.md index a7458a9c0e..bfc3efec70 100644 --- a/docs/reference/static-functions/functions/header_getLeafHeaders.md +++ b/docs/reference/static-functions/functions/header_getLeafHeaders.md @@ -9,7 +9,7 @@ title: header_getLeafHeaders function header_getLeafHeaders(header): Header[]; ``` -Defined in: [core/headers/coreHeadersFeature.utils.ts:25](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/headers/coreHeadersFeature.utils.ts#L25) +Defined in: [core/headers/coreHeadersFeature.utils.ts:40](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/headers/coreHeadersFeature.utils.ts#L40) Walks a header tree and collects all descendant leaf headers. diff --git a/docs/reference/static-functions/functions/header_getSize.md b/docs/reference/static-functions/functions/header_getSize.md index fb5d1e0111..2ceb2bc340 100644 --- a/docs/reference/static-functions/functions/header_getSize.md +++ b/docs/reference/static-functions/functions/header_getSize.md @@ -9,7 +9,7 @@ title: header_getSize function header_getSize(header): number; ``` -Defined in: [features/column-sizing/columnSizingFeature.utils.ts:269](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/column-sizing/columnSizingFeature.utils.ts#L269) +Defined in: [features/column-sizing/columnSizingFeature.utils.ts:285](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/column-sizing/columnSizingFeature.utils.ts#L285) Computes a header's rendered size from its leaf headers. diff --git a/docs/reference/static-functions/functions/header_getStart.md b/docs/reference/static-functions/functions/header_getStart.md index fdaf380548..9b81cd83af 100644 --- a/docs/reference/static-functions/functions/header_getStart.md +++ b/docs/reference/static-functions/functions/header_getStart.md @@ -9,7 +9,7 @@ title: header_getStart function header_getStart(header): number; ``` -Defined in: [features/column-sizing/columnSizingFeature.utils.ts:300](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/column-sizing/columnSizingFeature.utils.ts#L300) +Defined in: [features/column-sizing/columnSizingFeature.utils.ts:304](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/column-sizing/columnSizingFeature.utils.ts#L304) Computes a header's offset from the start of its header group. diff --git a/docs/reference/static-functions/functions/isRowSelected.md b/docs/reference/static-functions/functions/isRowSelected.md index 1a07476675..b5ec2aaa5e 100644 --- a/docs/reference/static-functions/functions/isRowSelected.md +++ b/docs/reference/static-functions/functions/isRowSelected.md @@ -9,7 +9,7 @@ title: isRowSelected function isRowSelected(row, rowSelection): boolean; ``` -Defined in: [features/row-selection/rowSelectionFeature.utils.ts:866](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/row-selection/rowSelectionFeature.utils.ts#L866) +Defined in: [features/row-selection/rowSelectionFeature.utils.ts:888](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/row-selection/rowSelectionFeature.utils.ts#L888) Returns whether a row id is selected in the current row selection state. diff --git a/docs/reference/static-functions/functions/isSubRowSelected.md b/docs/reference/static-functions/functions/isSubRowSelected.md index 2c7e3c5417..44484f9c2c 100644 --- a/docs/reference/static-functions/functions/isSubRowSelected.md +++ b/docs/reference/static-functions/functions/isSubRowSelected.md @@ -9,7 +9,7 @@ title: isSubRowSelected function isSubRowSelected(row): boolean | "some" | "all"; ``` -Defined in: [features/row-selection/rowSelectionFeature.utils.ts:883](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/row-selection/rowSelectionFeature.utils.ts#L883) +Defined in: [features/row-selection/rowSelectionFeature.utils.ts:905](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/row-selection/rowSelectionFeature.utils.ts#L905) Returns whether all, some, or none of a row's selectable descendants are selected. diff --git a/docs/reference/static-functions/functions/normalizeAggregationRows.md b/docs/reference/static-functions/functions/normalizeAggregationRows.md index 41d89599a3..8c2805d703 100644 --- a/docs/reference/static-functions/functions/normalizeAggregationRows.md +++ b/docs/reference/static-functions/functions/normalizeAggregationRows.md @@ -9,7 +9,7 @@ title: normalizeAggregationRows function normalizeAggregationRows(rows, maxDepth): Row[]; ``` -Defined in: [features/row-aggregation/rowAggregationFeature.utils.ts:66](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/row-aggregation/rowAggregationFeature.utils.ts#L66) +Defined in: [features/row-aggregation/rowAggregationFeature.utils.ts:114](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/row-aggregation/rowAggregationFeature.utils.ts#L114) Selects unique rows at a maximum relative depth in encounter order. Branches that end before the requested depth contribute their deepest row. diff --git a/docs/reference/static-functions/functions/normalizeUniqueAggregationRows.md b/docs/reference/static-functions/functions/normalizeUniqueAggregationRows.md index 572a573135..b31e423341 100644 --- a/docs/reference/static-functions/functions/normalizeUniqueAggregationRows.md +++ b/docs/reference/static-functions/functions/normalizeUniqueAggregationRows.md @@ -9,7 +9,7 @@ title: normalizeUniqueAggregationRows function normalizeUniqueAggregationRows(rows, maxDepth): readonly Row[]; ``` -Defined in: [features/row-aggregation/rowAggregationFeature.utils.ts:105](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/row-aggregation/rowAggregationFeature.utils.ts#L105) +Defined in: [features/row-aggregation/rowAggregationFeature.utils.ts:145](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/row-aggregation/rowAggregationFeature.utils.ts#L145) Frontier selection for rows that are distinct nodes of a single row tree — the row models the table builds itself. Skips `normalizeAggregationRows`' diff --git a/docs/reference/static-functions/functions/row_getAllCells.md b/docs/reference/static-functions/functions/row_getAllCells.md index f283936170..bfe970bb85 100644 --- a/docs/reference/static-functions/functions/row_getAllCells.md +++ b/docs/reference/static-functions/functions/row_getAllCells.md @@ -9,7 +9,7 @@ title: row_getAllCells function row_getAllCells(row): Cell[]; ``` -Defined in: [core/rows/coreRowsFeature.utils.ts:250](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/rows/coreRowsFeature.utils.ts#L250) +Defined in: [core/rows/coreRowsFeature.utils.ts:251](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/rows/coreRowsFeature.utils.ts#L251) Constructs one cell for each leaf column in this row. diff --git a/docs/reference/static-functions/functions/row_getAllCellsByColumnId.md b/docs/reference/static-functions/functions/row_getAllCellsByColumnId.md index db2d35d6f0..a7835d0c08 100644 --- a/docs/reference/static-functions/functions/row_getAllCellsByColumnId.md +++ b/docs/reference/static-functions/functions/row_getAllCellsByColumnId.md @@ -9,7 +9,7 @@ title: row_getAllCellsByColumnId function row_getAllCellsByColumnId(row): Record>; ``` -Defined in: [core/rows/coreRowsFeature.utils.ts:286](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/rows/coreRowsFeature.utils.ts#L286) +Defined in: [core/rows/coreRowsFeature.utils.ts:287](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/rows/coreRowsFeature.utils.ts#L287) Builds a lookup map of this row's cells keyed by column id. diff --git a/docs/reference/static-functions/functions/row_getCanMultiSelect.md b/docs/reference/static-functions/functions/row_getCanMultiSelect.md index 9a063c0da0..8ac97a046b 100644 --- a/docs/reference/static-functions/functions/row_getCanMultiSelect.md +++ b/docs/reference/static-functions/functions/row_getCanMultiSelect.md @@ -9,7 +9,7 @@ title: row_getCanMultiSelect function row_getCanMultiSelect(row): boolean; ``` -Defined in: [features/row-selection/rowSelectionFeature.utils.ts:634](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/row-selection/rowSelectionFeature.utils.ts#L634) +Defined in: [features/row-selection/rowSelectionFeature.utils.ts:638](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/row-selection/rowSelectionFeature.utils.ts#L638) Checks whether this row can be selected alongside other rows. diff --git a/docs/reference/static-functions/functions/row_getCanSelect.md b/docs/reference/static-functions/functions/row_getCanSelect.md index 569ab7a2c4..afc722c2bb 100644 --- a/docs/reference/static-functions/functions/row_getCanSelect.md +++ b/docs/reference/static-functions/functions/row_getCanSelect.md @@ -9,7 +9,7 @@ title: row_getCanSelect function row_getCanSelect(row): boolean; ``` -Defined in: [features/row-selection/rowSelectionFeature.utils.ts:588](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/row-selection/rowSelectionFeature.utils.ts#L588) +Defined in: [features/row-selection/rowSelectionFeature.utils.ts:592](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/row-selection/rowSelectionFeature.utils.ts#L592) Checks whether this row can be selected. diff --git a/docs/reference/static-functions/functions/row_getCanSelectSubRows.md b/docs/reference/static-functions/functions/row_getCanSelectSubRows.md index 45a929e4f7..982c95824c 100644 --- a/docs/reference/static-functions/functions/row_getCanSelectSubRows.md +++ b/docs/reference/static-functions/functions/row_getCanSelectSubRows.md @@ -9,7 +9,7 @@ title: row_getCanSelectSubRows function row_getCanSelectSubRows(row): boolean; ``` -Defined in: [features/row-selection/rowSelectionFeature.utils.ts:611](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/row-selection/rowSelectionFeature.utils.ts#L611) +Defined in: [features/row-selection/rowSelectionFeature.utils.ts:615](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/row-selection/rowSelectionFeature.utils.ts#L615) Checks whether selecting this row should also select its subRows. diff --git a/docs/reference/static-functions/functions/row_getDisplayIndex.md b/docs/reference/static-functions/functions/row_getDisplayIndex.md index 45779902cf..7956d512ce 100644 --- a/docs/reference/static-functions/functions/row_getDisplayIndex.md +++ b/docs/reference/static-functions/functions/row_getDisplayIndex.md @@ -9,7 +9,7 @@ title: row_getDisplayIndex function row_getDisplayIndex(row): number; ``` -Defined in: [core/rows/coreRowsFeature.utils.ts:14](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/rows/coreRowsFeature.utils.ts#L14) +Defined in: [core/rows/coreRowsFeature.utils.ts:15](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/rows/coreRowsFeature.utils.ts#L15) Returns this row's zero-based position in the current pre-pagination row model. Rows outside that model return `-1`. diff --git a/docs/reference/static-functions/functions/row_getIsAllSubRowsSelected.md b/docs/reference/static-functions/functions/row_getIsAllSubRowsSelected.md index 99bbc94068..ebef71a0d6 100644 --- a/docs/reference/static-functions/functions/row_getIsAllSubRowsSelected.md +++ b/docs/reference/static-functions/functions/row_getIsAllSubRowsSelected.md @@ -9,7 +9,7 @@ title: row_getIsAllSubRowsSelected function row_getIsAllSubRowsSelected(row): boolean; ``` -Defined in: [features/row-selection/rowSelectionFeature.utils.ts:570](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/row-selection/rowSelectionFeature.utils.ts#L570) +Defined in: [features/row-selection/rowSelectionFeature.utils.ts:574](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/row-selection/rowSelectionFeature.utils.ts#L574) Checks whether all selectable descendants are selected. diff --git a/docs/reference/static-functions/functions/row_getIsSelected.md b/docs/reference/static-functions/functions/row_getIsSelected.md index a829e0869c..d54e51bfd1 100644 --- a/docs/reference/static-functions/functions/row_getIsSelected.md +++ b/docs/reference/static-functions/functions/row_getIsSelected.md @@ -9,7 +9,7 @@ title: row_getIsSelected function row_getIsSelected(row): boolean; ``` -Defined in: [features/row-selection/rowSelectionFeature.utils.ts:535](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/row-selection/rowSelectionFeature.utils.ts#L535) +Defined in: [features/row-selection/rowSelectionFeature.utils.ts:539](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/row-selection/rowSelectionFeature.utils.ts#L539) Checks whether this row id is selected in `state.rowSelection`. diff --git a/docs/reference/static-functions/functions/row_getIsSomeSelected.md b/docs/reference/static-functions/functions/row_getIsSomeSelected.md index fa1a80d408..a01212632e 100644 --- a/docs/reference/static-functions/functions/row_getIsSomeSelected.md +++ b/docs/reference/static-functions/functions/row_getIsSomeSelected.md @@ -9,7 +9,7 @@ title: row_getIsSomeSelected function row_getIsSomeSelected(row): boolean; ``` -Defined in: [features/row-selection/rowSelectionFeature.utils.ts:553](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/row-selection/rowSelectionFeature.utils.ts#L553) +Defined in: [features/row-selection/rowSelectionFeature.utils.ts:557](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/row-selection/rowSelectionFeature.utils.ts#L557) Checks whether some, but not all, selectable descendants are selected. diff --git a/docs/reference/static-functions/functions/row_getLeafRows.md b/docs/reference/static-functions/functions/row_getLeafRows.md index 4ebccfdd82..2472036d84 100644 --- a/docs/reference/static-functions/functions/row_getLeafRows.md +++ b/docs/reference/static-functions/functions/row_getLeafRows.md @@ -9,7 +9,7 @@ title: row_getLeafRows function row_getLeafRows(row): Row[]; ``` -Defined in: [core/rows/coreRowsFeature.utils.ts:163](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/rows/coreRowsFeature.utils.ts#L163) +Defined in: [core/rows/coreRowsFeature.utils.ts:164](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/rows/coreRowsFeature.utils.ts#L164) Flattens this row's descendant tree into leaf rows. diff --git a/docs/reference/static-functions/functions/row_getParentRow.md b/docs/reference/static-functions/functions/row_getParentRow.md index 0d576071cc..656422d100 100644 --- a/docs/reference/static-functions/functions/row_getParentRow.md +++ b/docs/reference/static-functions/functions/row_getParentRow.md @@ -11,7 +11,7 @@ function row_getParentRow(row): | undefined; ``` -Defined in: [core/rows/coreRowsFeature.utils.ts:199](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/rows/coreRowsFeature.utils.ts#L199) +Defined in: [core/rows/coreRowsFeature.utils.ts:200](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/rows/coreRowsFeature.utils.ts#L200) Looks up this row's direct parent, if it has one. diff --git a/docs/reference/static-functions/functions/row_getParentRows.md b/docs/reference/static-functions/functions/row_getParentRows.md index 9508797771..8266afb58d 100644 --- a/docs/reference/static-functions/functions/row_getParentRows.md +++ b/docs/reference/static-functions/functions/row_getParentRows.md @@ -9,7 +9,7 @@ title: row_getParentRows function row_getParentRows(row): Row[]; ``` -Defined in: [core/rows/coreRowsFeature.utils.ts:223](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/rows/coreRowsFeature.utils.ts#L223) +Defined in: [core/rows/coreRowsFeature.utils.ts:224](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/rows/coreRowsFeature.utils.ts#L224) Collects this row's ancestor chain from root to direct parent. diff --git a/docs/reference/static-functions/functions/row_getToggleSelectedHandler.md b/docs/reference/static-functions/functions/row_getToggleSelectedHandler.md index 65756af575..fa5dd4a208 100644 --- a/docs/reference/static-functions/functions/row_getToggleSelectedHandler.md +++ b/docs/reference/static-functions/functions/row_getToggleSelectedHandler.md @@ -9,7 +9,7 @@ title: row_getToggleSelectedHandler function row_getToggleSelectedHandler(row, opts?): (e) => void; ``` -Defined in: [features/row-selection/rowSelectionFeature.utils.ts:660](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/row-selection/rowSelectionFeature.utils.ts#L660) +Defined in: [features/row-selection/rowSelectionFeature.utils.ts:664](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/row-selection/rowSelectionFeature.utils.ts#L664) Creates a checkbox-style handler that selects or deselects this row. diff --git a/docs/reference/static-functions/functions/row_getUniqueValues.md b/docs/reference/static-functions/functions/row_getUniqueValues.md index f9e7fa9d82..32406c9998 100644 --- a/docs/reference/static-functions/functions/row_getUniqueValues.md +++ b/docs/reference/static-functions/functions/row_getUniqueValues.md @@ -9,7 +9,7 @@ title: row_getUniqueValues function row_getUniqueValues(row, columnId): unknown; ``` -Defined in: [core/rows/coreRowsFeature.utils.ts:108](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/rows/coreRowsFeature.utils.ts#L108) +Defined in: [core/rows/coreRowsFeature.utils.ts:109](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/rows/coreRowsFeature.utils.ts#L109) Reads and caches the values used by faceting/grouping for a column. diff --git a/docs/reference/static-functions/functions/row_getValue.md b/docs/reference/static-functions/functions/row_getValue.md index e2a167117d..d8503b4851 100644 --- a/docs/reference/static-functions/functions/row_getValue.md +++ b/docs/reference/static-functions/functions/row_getValue.md @@ -9,7 +9,7 @@ title: row_getValue function row_getValue(row, columnId): unknown; ``` -Defined in: [core/rows/coreRowsFeature.utils.ts:78](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/rows/coreRowsFeature.utils.ts#L78) +Defined in: [core/rows/coreRowsFeature.utils.ts:79](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/rows/coreRowsFeature.utils.ts#L79) Reads and caches this row's value for a column. diff --git a/docs/reference/static-functions/functions/row_renderValue.md b/docs/reference/static-functions/functions/row_renderValue.md index 7ff2291498..b90b7cd53b 100644 --- a/docs/reference/static-functions/functions/row_renderValue.md +++ b/docs/reference/static-functions/functions/row_renderValue.md @@ -9,7 +9,7 @@ title: row_renderValue function row_renderValue(row, columnId): any; ``` -Defined in: [core/rows/coreRowsFeature.utils.ts:146](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/rows/coreRowsFeature.utils.ts#L146) +Defined in: [core/rows/coreRowsFeature.utils.ts:147](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/rows/coreRowsFeature.utils.ts#L147) Returns a renderable row value for a column. diff --git a/docs/reference/static-functions/functions/row_toggleSelected.md b/docs/reference/static-functions/functions/row_toggleSelected.md index b971b2c05d..55d56080ee 100644 --- a/docs/reference/static-functions/functions/row_toggleSelected.md +++ b/docs/reference/static-functions/functions/row_toggleSelected.md @@ -12,7 +12,7 @@ function row_toggleSelected( opts?): void; ``` -Defined in: [features/row-selection/rowSelectionFeature.utils.ts:502](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/row-selection/rowSelectionFeature.utils.ts#L502) +Defined in: [features/row-selection/rowSelectionFeature.utils.ts:506](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/row-selection/rowSelectionFeature.utils.ts#L506) Selects or deselects this row. diff --git a/docs/reference/static-functions/functions/selectRowsFn.md b/docs/reference/static-functions/functions/selectRowsFn.md index d509066a84..bb7edbbc47 100644 --- a/docs/reference/static-functions/functions/selectRowsFn.md +++ b/docs/reference/static-functions/functions/selectRowsFn.md @@ -9,7 +9,7 @@ title: selectRowsFn function selectRowsFn(rowModel, table): RowModel; ``` -Defined in: [features/row-selection/rowSelectionFeature.utils.ts:807](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/row-selection/rowSelectionFeature.utils.ts#L807) +Defined in: [features/row-selection/rowSelectionFeature.utils.ts:857](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/row-selection/rowSelectionFeature.utils.ts#L857) Builds a row model containing rows selected by the current row selection state. diff --git a/docs/reference/static-functions/functions/table_getAllColumns.md b/docs/reference/static-functions/functions/table_getAllColumns.md index 1948b68a8a..c5f73ea4c5 100644 --- a/docs/reference/static-functions/functions/table_getAllColumns.md +++ b/docs/reference/static-functions/functions/table_getAllColumns.md @@ -9,7 +9,7 @@ title: table_getAllColumns function table_getAllColumns(table): Column[]; ``` -Defined in: [core/columns/coreColumnsFeature.utils.ts:120](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/columns/coreColumnsFeature.utils.ts#L120) +Defined in: [core/columns/coreColumnsFeature.utils.ts:155](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/columns/coreColumnsFeature.utils.ts#L155) Normalizes `options.columns` into the table's nested column tree. diff --git a/docs/reference/static-functions/functions/table_getAllFlatColumns.md b/docs/reference/static-functions/functions/table_getAllFlatColumns.md index cba41c9224..97ff3a9a10 100644 --- a/docs/reference/static-functions/functions/table_getAllFlatColumns.md +++ b/docs/reference/static-functions/functions/table_getAllFlatColumns.md @@ -9,7 +9,7 @@ title: table_getAllFlatColumns function table_getAllFlatColumns(table): Column[]; ``` -Defined in: [core/columns/coreColumnsFeature.utils.ts:162](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/columns/coreColumnsFeature.utils.ts#L162) +Defined in: [core/columns/coreColumnsFeature.utils.ts:175](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/columns/coreColumnsFeature.utils.ts#L175) Flattens every table column, including group columns and leaf columns. diff --git a/docs/reference/static-functions/functions/table_getAllFlatColumnsById.md b/docs/reference/static-functions/functions/table_getAllFlatColumnsById.md index da8f8ddebd..6d722fb91b 100644 --- a/docs/reference/static-functions/functions/table_getAllFlatColumnsById.md +++ b/docs/reference/static-functions/functions/table_getAllFlatColumnsById.md @@ -9,7 +9,7 @@ title: table_getAllFlatColumnsById function table_getAllFlatColumnsById(table): Record>; ``` -Defined in: [core/columns/coreColumnsFeature.utils.ts:182](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/columns/coreColumnsFeature.utils.ts#L182) +Defined in: [core/columns/coreColumnsFeature.utils.ts:195](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/columns/coreColumnsFeature.utils.ts#L195) Builds an id lookup for every flat column in the table. diff --git a/docs/reference/static-functions/functions/table_getAllLeafColumns.md b/docs/reference/static-functions/functions/table_getAllLeafColumns.md index c787e828df..ceaaa9e29c 100644 --- a/docs/reference/static-functions/functions/table_getAllLeafColumns.md +++ b/docs/reference/static-functions/functions/table_getAllLeafColumns.md @@ -9,7 +9,7 @@ title: table_getAllLeafColumns function table_getAllLeafColumns(table): Column[]; ``` -Defined in: [core/columns/coreColumnsFeature.utils.ts:208](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/columns/coreColumnsFeature.utils.ts#L208) +Defined in: [core/columns/coreColumnsFeature.utils.ts:221](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/columns/coreColumnsFeature.utils.ts#L221) Collects all terminal leaf columns in their current table order. diff --git a/docs/reference/static-functions/functions/table_getAllLeafColumnsById.md b/docs/reference/static-functions/functions/table_getAllLeafColumnsById.md index 4f394e6701..d2f32eda6f 100644 --- a/docs/reference/static-functions/functions/table_getAllLeafColumnsById.md +++ b/docs/reference/static-functions/functions/table_getAllLeafColumnsById.md @@ -9,7 +9,7 @@ title: table_getAllLeafColumnsById function table_getAllLeafColumnsById(table): Record>; ``` -Defined in: [core/columns/coreColumnsFeature.utils.ts:235](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/columns/coreColumnsFeature.utils.ts#L235) +Defined in: [core/columns/coreColumnsFeature.utils.ts:248](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/columns/coreColumnsFeature.utils.ts#L248) Builds an id lookup for terminal leaf columns only. diff --git a/docs/reference/static-functions/functions/table_getCenterTotalSize.md b/docs/reference/static-functions/functions/table_getCenterTotalSize.md index 844253af9a..22f8379b99 100644 --- a/docs/reference/static-functions/functions/table_getCenterTotalSize.md +++ b/docs/reference/static-functions/functions/table_getCenterTotalSize.md @@ -9,7 +9,7 @@ title: table_getCenterTotalSize function table_getCenterTotalSize(table): number; ``` -Defined in: [features/column-sizing/columnSizingFeature.utils.ts:424](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/column-sizing/columnSizingFeature.utils.ts#L424) +Defined in: [features/column-sizing/columnSizingFeature.utils.ts:428](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/column-sizing/columnSizingFeature.utils.ts#L428) Sums the rendered size of the center, unpinned header region. diff --git a/docs/reference/static-functions/functions/table_getColumn.md b/docs/reference/static-functions/functions/table_getColumn.md index 84008f7ba7..236e91eba0 100644 --- a/docs/reference/static-functions/functions/table_getColumn.md +++ b/docs/reference/static-functions/functions/table_getColumn.md @@ -11,7 +11,7 @@ function table_getColumn(table, columnId): | undefined; ``` -Defined in: [core/columns/coreColumnsFeature.utils.ts:261](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/columns/coreColumnsFeature.utils.ts#L261) +Defined in: [core/columns/coreColumnsFeature.utils.ts:274](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/columns/coreColumnsFeature.utils.ts#L274) Looks up a column by id from the flat column map. diff --git a/docs/reference/static-functions/functions/table_getEndTotalSize.md b/docs/reference/static-functions/functions/table_getEndTotalSize.md index b677204375..021a1eefdb 100644 --- a/docs/reference/static-functions/functions/table_getEndTotalSize.md +++ b/docs/reference/static-functions/functions/table_getEndTotalSize.md @@ -9,7 +9,7 @@ title: table_getEndTotalSize function table_getEndTotalSize(table): number; ``` -Defined in: [features/column-sizing/columnSizingFeature.utils.ts:449](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/column-sizing/columnSizingFeature.utils.ts#L449) +Defined in: [features/column-sizing/columnSizingFeature.utils.ts:453](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/column-sizing/columnSizingFeature.utils.ts#L453) Sums the rendered size of the logical end pinned header region. diff --git a/docs/reference/static-functions/functions/table_getFilteredSelectedRowModel.md b/docs/reference/static-functions/functions/table_getFilteredSelectedRowModel.md index d6b450620d..c510d1a588 100644 --- a/docs/reference/static-functions/functions/table_getFilteredSelectedRowModel.md +++ b/docs/reference/static-functions/functions/table_getFilteredSelectedRowModel.md @@ -15,7 +15,7 @@ function table_getFilteredSelectedRowModel(table): }; ``` -Defined in: [features/row-selection/rowSelectionFeature.utils.ts:256](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/row-selection/rowSelectionFeature.utils.ts#L256) +Defined in: [features/row-selection/rowSelectionFeature.utils.ts:260](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/row-selection/rowSelectionFeature.utils.ts#L260) Builds a row model containing selected rows from the filtered row model. diff --git a/docs/reference/static-functions/functions/table_getFlatHeaders.md b/docs/reference/static-functions/functions/table_getFlatHeaders.md index 54d1e90cb7..9921e1bd89 100644 --- a/docs/reference/static-functions/functions/table_getFlatHeaders.md +++ b/docs/reference/static-functions/functions/table_getFlatHeaders.md @@ -9,7 +9,7 @@ title: table_getFlatHeaders function table_getFlatHeaders(table): Header[]; ``` -Defined in: [core/headers/coreHeadersFeature.utils.ts:160](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/headers/coreHeadersFeature.utils.ts#L160) +Defined in: [core/headers/coreHeadersFeature.utils.ts:168](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/headers/coreHeadersFeature.utils.ts#L168) Flattens every header from every header group into one array. diff --git a/docs/reference/static-functions/functions/table_getFooterGroups.md b/docs/reference/static-functions/functions/table_getFooterGroups.md index dc36974637..5ac22c1c7c 100644 --- a/docs/reference/static-functions/functions/table_getFooterGroups.md +++ b/docs/reference/static-functions/functions/table_getFooterGroups.md @@ -9,7 +9,7 @@ title: table_getFooterGroups function table_getFooterGroups(table): HeaderGroup[]; ``` -Defined in: [core/headers/coreHeadersFeature.utils.ts:141](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/headers/coreHeadersFeature.utils.ts#L141) +Defined in: [core/headers/coreHeadersFeature.utils.ts:149](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/headers/coreHeadersFeature.utils.ts#L149) Builds footer groups by reversing the current header groups. diff --git a/docs/reference/static-functions/functions/table_getGroupedSelectedRowModel.md b/docs/reference/static-functions/functions/table_getGroupedSelectedRowModel.md index 4f92225830..671cfd070e 100644 --- a/docs/reference/static-functions/functions/table_getGroupedSelectedRowModel.md +++ b/docs/reference/static-functions/functions/table_getGroupedSelectedRowModel.md @@ -15,7 +15,7 @@ function table_getGroupedSelectedRowModel(table): }; ``` -Defined in: [features/row-selection/rowSelectionFeature.utils.ts:290](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/row-selection/rowSelectionFeature.utils.ts#L290) +Defined in: [features/row-selection/rowSelectionFeature.utils.ts:294](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/row-selection/rowSelectionFeature.utils.ts#L294) Builds a row model containing selected rows from the grouped row model. diff --git a/docs/reference/static-functions/functions/table_getHeaderGroups.md b/docs/reference/static-functions/functions/table_getHeaderGroups.md index 835a03d284..13288adb9b 100644 --- a/docs/reference/static-functions/functions/table_getHeaderGroups.md +++ b/docs/reference/static-functions/functions/table_getHeaderGroups.md @@ -9,7 +9,7 @@ title: table_getHeaderGroups function table_getHeaderGroups(table): HeaderGroup[]; ``` -Defined in: [core/headers/coreHeadersFeature.utils.ts:77](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/headers/coreHeadersFeature.utils.ts#L77) +Defined in: [core/headers/coreHeadersFeature.utils.ts:85](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/headers/coreHeadersFeature.utils.ts#L85) Builds visible header groups for the current column tree. diff --git a/docs/reference/static-functions/functions/table_getIsAllPageRowsSelected.md b/docs/reference/static-functions/functions/table_getIsAllPageRowsSelected.md index 14f61bac64..d1c4b9be8f 100644 --- a/docs/reference/static-functions/functions/table_getIsAllPageRowsSelected.md +++ b/docs/reference/static-functions/functions/table_getIsAllPageRowsSelected.md @@ -9,7 +9,7 @@ title: table_getIsAllPageRowsSelected function table_getIsAllPageRowsSelected(table): boolean; ``` -Defined in: [features/row-selection/rowSelectionFeature.utils.ts:375](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/row-selection/rowSelectionFeature.utils.ts#L375) +Defined in: [features/row-selection/rowSelectionFeature.utils.ts:379](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/row-selection/rowSelectionFeature.utils.ts#L379) Checks whether every selectable row on the current page is selected. diff --git a/docs/reference/static-functions/functions/table_getIsAllRowsSelected.md b/docs/reference/static-functions/functions/table_getIsAllRowsSelected.md index 94407980a9..a5689b40e1 100644 --- a/docs/reference/static-functions/functions/table_getIsAllRowsSelected.md +++ b/docs/reference/static-functions/functions/table_getIsAllRowsSelected.md @@ -9,7 +9,7 @@ title: table_getIsAllRowsSelected function table_getIsAllRowsSelected(table): boolean; ``` -Defined in: [features/row-selection/rowSelectionFeature.utils.ts:341](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/row-selection/rowSelectionFeature.utils.ts#L341) +Defined in: [features/row-selection/rowSelectionFeature.utils.ts:345](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/row-selection/rowSelectionFeature.utils.ts#L345) Checks whether every selectable filtered row is selected. diff --git a/docs/reference/static-functions/functions/table_getIsSomePageRowsSelected.md b/docs/reference/static-functions/functions/table_getIsSomePageRowsSelected.md index 11b4674ed6..92467aec5e 100644 --- a/docs/reference/static-functions/functions/table_getIsSomePageRowsSelected.md +++ b/docs/reference/static-functions/functions/table_getIsSomePageRowsSelected.md @@ -9,7 +9,7 @@ title: table_getIsSomePageRowsSelected function table_getIsSomePageRowsSelected(table): boolean; ``` -Defined in: [features/row-selection/rowSelectionFeature.utils.ts:424](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/row-selection/rowSelectionFeature.utils.ts#L424) +Defined in: [features/row-selection/rowSelectionFeature.utils.ts:428](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/row-selection/rowSelectionFeature.utils.ts#L428) Checks whether the current page has a partial selection. diff --git a/docs/reference/static-functions/functions/table_getIsSomeRowsSelected.md b/docs/reference/static-functions/functions/table_getIsSomeRowsSelected.md index a1a03bad8e..e2fbedea1d 100644 --- a/docs/reference/static-functions/functions/table_getIsSomeRowsSelected.md +++ b/docs/reference/static-functions/functions/table_getIsSomeRowsSelected.md @@ -9,7 +9,7 @@ title: table_getIsSomeRowsSelected function table_getIsSomeRowsSelected(table): boolean; ``` -Defined in: [features/row-selection/rowSelectionFeature.utils.ts:406](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/row-selection/rowSelectionFeature.utils.ts#L406) +Defined in: [features/row-selection/rowSelectionFeature.utils.ts:410](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/row-selection/rowSelectionFeature.utils.ts#L410) Checks whether selection is partially applied across filtered rows. diff --git a/docs/reference/static-functions/functions/table_getLeafHeaders.md b/docs/reference/static-functions/functions/table_getLeafHeaders.md index ae4bcbcb77..3769db8731 100644 --- a/docs/reference/static-functions/functions/table_getLeafHeaders.md +++ b/docs/reference/static-functions/functions/table_getLeafHeaders.md @@ -9,7 +9,7 @@ title: table_getLeafHeaders function table_getLeafHeaders(table): Header[]; ``` -Defined in: [core/headers/coreHeadersFeature.utils.ts:186](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/headers/coreHeadersFeature.utils.ts#L186) +Defined in: [core/headers/coreHeadersFeature.utils.ts:194](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/headers/coreHeadersFeature.utils.ts#L194) Collects only the leaf headers from the current header tree. diff --git a/docs/reference/static-functions/functions/table_getMaxSubRowDepth.md b/docs/reference/static-functions/functions/table_getMaxSubRowDepth.md index 33294beb28..31567a5b61 100644 --- a/docs/reference/static-functions/functions/table_getMaxSubRowDepth.md +++ b/docs/reference/static-functions/functions/table_getMaxSubRowDepth.md @@ -9,7 +9,7 @@ title: table_getMaxSubRowDepth function table_getMaxSubRowDepth(table): number; ``` -Defined in: [core/rows/coreRowsFeature.utils.ts:174](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/rows/coreRowsFeature.utils.ts#L174) +Defined in: [core/rows/coreRowsFeature.utils.ts:175](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/rows/coreRowsFeature.utils.ts#L175) Returns the deepest structural row depth in the core row model. Root rows are depth `0`, their direct sub-rows are depth `1`, and so on. diff --git a/docs/reference/static-functions/functions/table_getPreSelectedRowModel.md b/docs/reference/static-functions/functions/table_getPreSelectedRowModel.md index 1c607f7e44..dc2ef0574c 100644 --- a/docs/reference/static-functions/functions/table_getPreSelectedRowModel.md +++ b/docs/reference/static-functions/functions/table_getPreSelectedRowModel.md @@ -9,7 +9,7 @@ title: table_getPreSelectedRowModel function table_getPreSelectedRowModel(table): RowModel; ``` -Defined in: [features/row-selection/rowSelectionFeature.utils.ts:204](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/row-selection/rowSelectionFeature.utils.ts#L204) +Defined in: [features/row-selection/rowSelectionFeature.utils.ts:208](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/row-selection/rowSelectionFeature.utils.ts#L208) Reads the row model before row selection is projected into selected rows. diff --git a/docs/reference/static-functions/functions/table_getRow.md b/docs/reference/static-functions/functions/table_getRow.md index 378ed7708c..0ac600bc6f 100644 --- a/docs/reference/static-functions/functions/table_getRow.md +++ b/docs/reference/static-functions/functions/table_getRow.md @@ -12,7 +12,7 @@ function table_getRow( searchAll?): Row; ``` -Defined in: [core/rows/coreRowsFeature.utils.ts:336](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/rows/coreRowsFeature.utils.ts#L336) +Defined in: [core/rows/coreRowsFeature.utils.ts:337](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/rows/coreRowsFeature.utils.ts#L337) Looks up a row by id from the current or full row model. diff --git a/docs/reference/static-functions/functions/table_getRowId.md b/docs/reference/static-functions/functions/table_getRowId.md index 495363bdc2..9c3b38c6d8 100644 --- a/docs/reference/static-functions/functions/table_getRowId.md +++ b/docs/reference/static-functions/functions/table_getRowId.md @@ -13,7 +13,7 @@ function table_getRowId( parent?): string; ``` -Defined in: [core/rows/coreRowsFeature.utils.ts:310](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/rows/coreRowsFeature.utils.ts#L310) +Defined in: [core/rows/coreRowsFeature.utils.ts:311](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/rows/coreRowsFeature.utils.ts#L311) Resolves the stable id for a row. diff --git a/docs/reference/static-functions/functions/table_getRowsInDisplayOrder.md b/docs/reference/static-functions/functions/table_getRowsInDisplayOrder.md index fdc93bbcde..499d400141 100644 --- a/docs/reference/static-functions/functions/table_getRowsInDisplayOrder.md +++ b/docs/reference/static-functions/functions/table_getRowsInDisplayOrder.md @@ -9,7 +9,7 @@ title: table_getRowsInDisplayOrder function table_getRowsInDisplayOrder(table): Row[]; ``` -Defined in: [core/rows/coreRowsFeature.utils.ts:32](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/rows/coreRowsFeature.utils.ts#L32) +Defined in: [core/rows/coreRowsFeature.utils.ts:33](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/rows/coreRowsFeature.utils.ts#L33) Returns the rows in the current display order after assigning their zero-based display indexes. diff --git a/docs/reference/static-functions/functions/table_getSelectedRowIds.md b/docs/reference/static-functions/functions/table_getSelectedRowIds.md index be1e8f0a50..3da4cd2f4d 100644 --- a/docs/reference/static-functions/functions/table_getSelectedRowIds.md +++ b/docs/reference/static-functions/functions/table_getSelectedRowIds.md @@ -9,7 +9,7 @@ title: table_getSelectedRowIds function table_getSelectedRowIds(table): string[]; ``` -Defined in: [features/row-selection/rowSelectionFeature.utils.ts:323](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/row-selection/rowSelectionFeature.utils.ts#L323) +Defined in: [features/row-selection/rowSelectionFeature.utils.ts:327](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/row-selection/rowSelectionFeature.utils.ts#L327) Returns the ids of all selected rows. diff --git a/docs/reference/static-functions/functions/table_getSelectedRowModel.md b/docs/reference/static-functions/functions/table_getSelectedRowModel.md index 6032ad5231..c7a243eaf7 100644 --- a/docs/reference/static-functions/functions/table_getSelectedRowModel.md +++ b/docs/reference/static-functions/functions/table_getSelectedRowModel.md @@ -15,7 +15,7 @@ function table_getSelectedRowModel(table): }; ``` -Defined in: [features/row-selection/rowSelectionFeature.utils.ts:222](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/row-selection/rowSelectionFeature.utils.ts#L222) +Defined in: [features/row-selection/rowSelectionFeature.utils.ts:226](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/row-selection/rowSelectionFeature.utils.ts#L226) Builds a row model containing selected rows from the core row model. diff --git a/docs/reference/static-functions/functions/table_getStartTotalSize.md b/docs/reference/static-functions/functions/table_getStartTotalSize.md index ff23939c93..ade24cf29b 100644 --- a/docs/reference/static-functions/functions/table_getStartTotalSize.md +++ b/docs/reference/static-functions/functions/table_getStartTotalSize.md @@ -9,7 +9,7 @@ title: table_getStartTotalSize function table_getStartTotalSize(table): number; ``` -Defined in: [features/column-sizing/columnSizingFeature.utils.ts:399](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/column-sizing/columnSizingFeature.utils.ts#L399) +Defined in: [features/column-sizing/columnSizingFeature.utils.ts:403](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/column-sizing/columnSizingFeature.utils.ts#L403) Sums the rendered size of the logical start pinned header region. diff --git a/docs/reference/static-functions/functions/table_getToggleAllPageRowsSelectedHandler.md b/docs/reference/static-functions/functions/table_getToggleAllPageRowsSelectedHandler.md index b5b2fe8fec..bc0f272cf9 100644 --- a/docs/reference/static-functions/functions/table_getToggleAllPageRowsSelectedHandler.md +++ b/docs/reference/static-functions/functions/table_getToggleAllPageRowsSelectedHandler.md @@ -9,7 +9,7 @@ title: table_getToggleAllPageRowsSelectedHandler function table_getToggleAllPageRowsSelectedHandler(table): (e) => void; ``` -Defined in: [features/row-selection/rowSelectionFeature.utils.ts:472](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/row-selection/rowSelectionFeature.utils.ts#L472) +Defined in: [features/row-selection/rowSelectionFeature.utils.ts:476](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/row-selection/rowSelectionFeature.utils.ts#L476) Creates a checkbox-style handler that selects or deselects current page rows. diff --git a/docs/reference/static-functions/functions/table_getToggleAllRowsSelectedHandler.md b/docs/reference/static-functions/functions/table_getToggleAllRowsSelectedHandler.md index 5278e63fa1..d7c63aa1d6 100644 --- a/docs/reference/static-functions/functions/table_getToggleAllRowsSelectedHandler.md +++ b/docs/reference/static-functions/functions/table_getToggleAllRowsSelectedHandler.md @@ -9,7 +9,7 @@ title: table_getToggleAllRowsSelectedHandler function table_getToggleAllRowsSelectedHandler(table): (e) => void; ``` -Defined in: [features/row-selection/rowSelectionFeature.utils.ts:449](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/row-selection/rowSelectionFeature.utils.ts#L449) +Defined in: [features/row-selection/rowSelectionFeature.utils.ts:453](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/row-selection/rowSelectionFeature.utils.ts#L453) Creates a checkbox-style handler that selects or deselects all rows. diff --git a/docs/reference/static-functions/functions/table_getTotalSize.md b/docs/reference/static-functions/functions/table_getTotalSize.md index 27413ddc98..d85f2ee5ee 100644 --- a/docs/reference/static-functions/functions/table_getTotalSize.md +++ b/docs/reference/static-functions/functions/table_getTotalSize.md @@ -9,7 +9,7 @@ title: table_getTotalSize function table_getTotalSize(table): number; ``` -Defined in: [features/column-sizing/columnSizingFeature.utils.ts:378](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/column-sizing/columnSizingFeature.utils.ts#L378) +Defined in: [features/column-sizing/columnSizingFeature.utils.ts:382](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/column-sizing/columnSizingFeature.utils.ts#L382) Sums the rendered size of the full table header row. diff --git a/docs/reference/static-functions/functions/table_mergeOptions.md b/docs/reference/static-functions/functions/table_mergeOptions.md index d5bec237d7..94f4ab6e7a 100644 --- a/docs/reference/static-functions/functions/table_mergeOptions.md +++ b/docs/reference/static-functions/functions/table_mergeOptions.md @@ -9,7 +9,7 @@ title: table_mergeOptions function table_mergeOptions(table, newOptions): TableOptions; ``` -Defined in: [core/table/coreTablesFeature.utils.ts:86](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.utils.ts#L86) +Defined in: [core/table/coreTablesFeature.utils.ts:132](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.utils.ts#L132) Merges new table options with the current resolved options. diff --git a/docs/reference/static-functions/functions/table_publishExternalState.md b/docs/reference/static-functions/functions/table_publishExternalState.md new file mode 100644 index 0000000000..d994e056a5 --- /dev/null +++ b/docs/reference/static-functions/functions/table_publishExternalState.md @@ -0,0 +1,54 @@ +--- +id: table_publishExternalState +title: table_publishExternalState +--- + +# Function: table\_publishExternalState() + +```ts +function table_publishExternalState( + table, + state, + compare, + commitToken?): void; +``` + +Defined in: [core/table/coreTablesFeature.utils.ts:70](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.utils.ts#L70) + +Publishes captured controlled state after a host framework commits. + +Render-phase adapters stage options without synchronizing base atoms, then +pass the state captured by the committed render here. The commit signal also +invalidates ownership changes when no base atom was written. + +## Type Parameters + +### TFeatures + +`TFeatures` *extends* [`TableFeatures`](../../index/interfaces/TableFeatures.md) + +### TData + +`TData` *extends* [`RowData`](../../index/type-aliases/RowData.md) + +## Parameters + +### table + +[`Table_Internal`](../../index/interfaces/Table_Internal.md)\<`TFeatures`, `TData`\> + +### state + +`Partial`\<[`TableState`](../../index/type-aliases/TableState.md)\<`TFeatures`\>\> | `null` + +### compare + +(`currentState`, `externalState`) => `boolean` + +### commitToken? + +`number` + +## Returns + +`void` diff --git a/docs/reference/static-functions/functions/table_reset.md b/docs/reference/static-functions/functions/table_reset.md index ec07464dc7..a82a796daa 100644 --- a/docs/reference/static-functions/functions/table_reset.md +++ b/docs/reference/static-functions/functions/table_reset.md @@ -9,7 +9,7 @@ title: table_reset function table_reset(table): void; ``` -Defined in: [core/table/coreTablesFeature.utils.ts:54](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.utils.ts#L54) +Defined in: [core/table/coreTablesFeature.utils.ts:100](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.utils.ts#L100) Resets all internal table base atoms to `table.initialState`, then clears transient instance data through registered feature reset hooks. diff --git a/docs/reference/static-functions/functions/table_resetColumnSizing.md b/docs/reference/static-functions/functions/table_resetColumnSizing.md index 0ac96277e3..af979c7427 100644 --- a/docs/reference/static-functions/functions/table_resetColumnSizing.md +++ b/docs/reference/static-functions/functions/table_resetColumnSizing.md @@ -9,7 +9,7 @@ title: table_resetColumnSizing function table_resetColumnSizing(table, defaultState?): void; ``` -Defined in: [features/column-sizing/columnSizingFeature.utils.ts:353](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/column-sizing/columnSizingFeature.utils.ts#L353) +Defined in: [features/column-sizing/columnSizingFeature.utils.ts:357](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/column-sizing/columnSizingFeature.utils.ts#L357) Resets `columnSizing` to the configured initial state or feature default. diff --git a/docs/reference/static-functions/functions/table_resetRowSelection.md b/docs/reference/static-functions/functions/table_resetRowSelection.md index 51e0b9ced9..3e345abe23 100644 --- a/docs/reference/static-functions/functions/table_resetRowSelection.md +++ b/docs/reference/static-functions/functions/table_resetRowSelection.md @@ -9,7 +9,7 @@ title: table_resetRowSelection function table_resetRowSelection(table, defaultState?): void; ``` -Defined in: [features/row-selection/rowSelectionFeature.utils.ts:68](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/row-selection/rowSelectionFeature.utils.ts#L68) +Defined in: [features/row-selection/rowSelectionFeature.utils.ts:72](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/row-selection/rowSelectionFeature.utils.ts#L72) Resets `rowSelection` to the configured initial state or feature default. diff --git a/docs/reference/static-functions/functions/table_setColumnSizing.md b/docs/reference/static-functions/functions/table_setColumnSizing.md index 921e2596d4..5f024f2bb0 100644 --- a/docs/reference/static-functions/functions/table_setColumnSizing.md +++ b/docs/reference/static-functions/functions/table_setColumnSizing.md @@ -9,7 +9,7 @@ title: table_setColumnSizing function table_setColumnSizing(table, updater): void; ``` -Defined in: [features/column-sizing/columnSizingFeature.utils.ts:331](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/column-sizing/columnSizingFeature.utils.ts#L331) +Defined in: [features/column-sizing/columnSizingFeature.utils.ts:335](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/column-sizing/columnSizingFeature.utils.ts#L335) Routes a committed column sizing updater through the table's sizing handler. diff --git a/docs/reference/static-functions/functions/table_setOptions.md b/docs/reference/static-functions/functions/table_setOptions.md index 4ca8ba7278..cad789f7b4 100644 --- a/docs/reference/static-functions/functions/table_setOptions.md +++ b/docs/reference/static-functions/functions/table_setOptions.md @@ -6,10 +6,13 @@ title: table_setOptions # Function: table\_setOptions() ```ts -function table_setOptions(table, updater): void; +function table_setOptions( + table, + updater, + options?): number | undefined; ``` -Defined in: [core/table/coreTablesFeature.utils.ts:152](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.utils.ts#L152) +Defined in: [core/table/coreTablesFeature.utils.ts:203](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.utils.ts#L203) Updates the table options object. @@ -36,12 +39,19 @@ immediately assigned to the table instance. [`Updater`](../../index/type-aliases/Updater.md)\<[`TableOptions`](../../index/type-aliases/TableOptions.md)\<`TFeatures`, `TData`\>\> +### options? + +#### syncExternalState? + +`boolean` + ## Returns -`void` +`number` \| `undefined` ## Example ```ts table_setOptions(table, (old) => old) +table_setOptions(table, (old) => old, { syncExternalState: false }) ``` diff --git a/docs/reference/static-functions/functions/table_setRowSelection.md b/docs/reference/static-functions/functions/table_setRowSelection.md index 3a95259cbf..3821cbcac2 100644 --- a/docs/reference/static-functions/functions/table_setRowSelection.md +++ b/docs/reference/static-functions/functions/table_setRowSelection.md @@ -9,7 +9,7 @@ title: table_setRowSelection function table_setRowSelection(table, updater): void; ``` -Defined in: [features/row-selection/rowSelectionFeature.utils.ts:46](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/row-selection/rowSelectionFeature.utils.ts#L46) +Defined in: [features/row-selection/rowSelectionFeature.utils.ts:50](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/row-selection/rowSelectionFeature.utils.ts#L50) Routes a row selection updater through the table's selection change handler. diff --git a/docs/reference/static-functions/functions/table_syncExternalStateToBaseAtoms.md b/docs/reference/static-functions/functions/table_syncExternalStateToBaseAtoms.md index c3a8961ebd..c3c307b743 100644 --- a/docs/reference/static-functions/functions/table_syncExternalStateToBaseAtoms.md +++ b/docs/reference/static-functions/functions/table_syncExternalStateToBaseAtoms.md @@ -6,15 +6,26 @@ title: table_syncExternalStateToBaseAtoms # Function: table\_syncExternalStateToBaseAtoms() ```ts -function table_syncExternalStateToBaseAtoms(table): void; +function table_syncExternalStateToBaseAtoms( + table, + capturedState?, + compare?): void; ``` -Defined in: [core/table/coreTablesFeature.utils.ts:18](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.utils.ts#L18) +Defined in: [core/table/coreTablesFeature.utils.ts:29](https://github.com/TanStack/table/blob/main/packages/table-core/src/core/table/coreTablesFeature.utils.ts#L29) Synchronizes externally controlled state slices into the table's base atoms. -This keeps legacy `options.state` values reflected in the atom graph so -derived atoms, stores, and table APIs read a consistent snapshot. +This keeps `options.state` values mirrored in the atom graph so derived +atoms, stores, and table APIs read a consistent snapshot. + +Adapters that update options during their host's render phase pass the +state snapshot captured by the committed render as `capturedState` — the +shared options object may already hold values from a newer render that +never commits. Pass `null` to publish nothing (a captured "no controlled +state"); omitting the argument reads the current `table.options.state` +instead. An optional `compare` suppresses semantically unchanged slice +writes; the default remains reference equality. ## Type Parameters @@ -32,6 +43,14 @@ derived atoms, stores, and table APIs read a consistent snapshot. [`Table_Internal`](../../index/interfaces/Table_Internal.md)\<`TFeatures`, `TData`\> +### capturedState? + +`Partial`\<[`TableState`](../../index/type-aliases/TableState.md)\<`TFeatures`\>\> | `null` + +### compare? + +(`currentState`, `externalState`) => `boolean` + ## Returns `void` @@ -40,4 +59,5 @@ derived atoms, stores, and table APIs read a consistent snapshot. ```ts table_syncExternalStateToBaseAtoms(table) +table_syncExternalStateToBaseAtoms(table, capturedState ?? null, shallow) ``` diff --git a/docs/reference/static-functions/functions/table_toggleAllPageRowsSelected.md b/docs/reference/static-functions/functions/table_toggleAllPageRowsSelected.md index d746770b17..200cedde88 100644 --- a/docs/reference/static-functions/functions/table_toggleAllPageRowsSelected.md +++ b/docs/reference/static-functions/functions/table_toggleAllPageRowsSelected.md @@ -12,7 +12,7 @@ function table_toggleAllPageRowsSelected( opts?): void; ``` -Defined in: [features/row-selection/rowSelectionFeature.utils.ts:155](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/row-selection/rowSelectionFeature.utils.ts#L155) +Defined in: [features/row-selection/rowSelectionFeature.utils.ts:159](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/row-selection/rowSelectionFeature.utils.ts#L159) Selects or deselects every selectable row on the current page. diff --git a/docs/reference/static-functions/functions/table_toggleAllRowsSelected.md b/docs/reference/static-functions/functions/table_toggleAllRowsSelected.md index 975c733b69..e82d81ac46 100644 --- a/docs/reference/static-functions/functions/table_toggleAllRowsSelected.md +++ b/docs/reference/static-functions/functions/table_toggleAllRowsSelected.md @@ -12,7 +12,7 @@ function table_toggleAllRowsSelected( opts?): void; ``` -Defined in: [features/row-selection/rowSelectionFeature.utils.ts:98](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/row-selection/rowSelectionFeature.utils.ts#L98) +Defined in: [features/row-selection/rowSelectionFeature.utils.ts:102](https://github.com/TanStack/table/blob/main/packages/table-core/src/features/row-selection/rowSelectionFeature.utils.ts#L102) Selects or deselects every selectable row before grouping. diff --git a/docs/reference/static-functions/index.md b/docs/reference/static-functions/index.md index b5ca28f5cb..930ee30025 100644 --- a/docs/reference/static-functions/index.md +++ b/docs/reference/static-functions/index.md @@ -241,6 +241,7 @@ title: static-functions - [table\_moveCellSelection](functions/table_moveCellSelection.md) - [table\_nextPage](functions/table_nextPage.md) - [table\_previousPage](functions/table_previousPage.md) +- [table\_publishExternalState](functions/table_publishExternalState.md) - [table\_reset](functions/table_reset.md) - [table\_resetCellSelection](functions/table_resetCellSelection.md) - [table\_resetColumnFilters](functions/table_resetColumnFilters.md) diff --git a/packages/alpine-table/src/createTable.ts b/packages/alpine-table/src/createTable.ts index 67b287b6c6..0f002c62c4 100644 --- a/packages/alpine-table/src/createTable.ts +++ b/packages/alpine-table/src/createTable.ts @@ -99,11 +99,11 @@ export function createTable< // inside the effect registers the dependencies, so the effect re-runs when // they change and re-applies the live values via `setOptions`. // - // `setOptions` writes to the options store, not the state store, so a `data` - // (or other option) change does not emit on `table.store` and would not bump + // `setOptions` writes option atoms, not the state store, so a `data` (or + // other option) change does not emit on `table.store` and would not bump // `_ver` on its own. We bump `_ver` here so the template re-pulls derived - // APIs like `getRowModel()`, which recompute from the new options. The effect - // never reads `_ver`, so writing it does not re-trigger this effect. + // APIs like `getRowModel()`. The effect never reads `_ver`, so writing it + // does not re-trigger this effect. let initialized = false Alpine.effect(() => { const state = tableOptions.state as Record | undefined @@ -168,6 +168,21 @@ export function createTable< } const resolvedValue = Reflect.get(target, prop, receiver) + const descriptor = Reflect.getOwnPropertyDescriptor(target, prop) + + // A Proxy must return the exact value of a non-configurable, + // non-writable data property. Core exposes options and optionAtoms this + // way, which also means callback reads preserve their source identity. + // The containing property read still tracks Alpine's version counter. + if ( + descriptor && + !descriptor.configurable && + 'value' in descriptor && + !descriptor.writable + ) { + void reactivity._ver + return resolvedValue + } if (typeof resolvedValue === 'function') { let targetWrappers = wrapperCache.get(target) diff --git a/packages/alpine-table/src/reactivity.ts b/packages/alpine-table/src/reactivity.ts index 2e94e93045..21c970250a 100644 --- a/packages/alpine-table/src/reactivity.ts +++ b/packages/alpine-table/src/reactivity.ts @@ -3,6 +3,37 @@ import type { TableAtomOptions, TableReactivityBindings, } from '@tanstack/table-core/reactivity' +import type { Observer, ReadonlyAtom } from '@tanstack/store' + +function createStableReadonlyAtom( + fn: () => T, + compare: (previous: T, next: T) => boolean, +): ReadonlyAtom { + let stableBox: { value: T } | undefined + const boxedAtom = createAtom( + () => { + const nextValue = fn() + if (!stableBox || !compare(stableBox.value, nextValue)) { + stableBox = { value: nextValue } + } + return stableBox + }, + ) + + return { + get: () => boxedAtom.get().value, + subscribe: (( + observer: Observer | ((value: T) => void), + ) => + boxedAtom.subscribe((box) => { + if (typeof observer === 'function') { + observer(box.value) + } else { + observer.next?.(box.value) + } + })) as ReadonlyAtom['subscribe'], + } +} /** * Creates the table-core reactivity bindings used by the Alpine adapter. @@ -12,7 +43,6 @@ import type { */ export function alpineReactivity(): TableReactivityBindings { return { - createOptionsStore: true, wrapExternalAtoms: false, addSubscription: () => { throw new Error( @@ -28,9 +58,10 @@ export function alpineReactivity(): TableReactivityBindings { batch, untrack: (fn) => fn(), createReadonlyAtom: (fn: () => T, options?: TableAtomOptions) => { - return createAtom(() => fn(), { - compare: options?.compare, - }) + return createStableReadonlyAtom( + fn, + options?.compare ?? Object.is, + ) }, createWritableAtom: (value: T, options?: TableAtomOptions) => { return createAtom(value, { diff --git a/packages/alpine-table/tests/unit/adapterCoverage.test.ts b/packages/alpine-table/tests/unit/adapterCoverage.test.ts index a60d460bb1..61d796d56c 100644 --- a/packages/alpine-table/tests/unit/adapterCoverage.test.ts +++ b/packages/alpine-table/tests/unit/adapterCoverage.test.ts @@ -225,11 +225,21 @@ describe('Alpine adapter reactivity', () => { }, }) + expect(table.options.onRowSelectionChange).toBe( + table.optionAtoms.onRowSelectionChange!.get(), + ) + table.toggleAllRowsSelected(true) expect(firstHandler).toHaveBeenCalledTimes(1) options.onRowSelectionChange = secondHandler await flushEffects() + + expect(table.options.onRowSelectionChange).toBe(secondHandler) + expect(table.options.onRowSelectionChange).toBe( + table.optionAtoms.onRowSelectionChange!.get(), + ) + table.toggleAllRowsSelected(false) expect(firstHandler).toHaveBeenCalledTimes(1) diff --git a/packages/angular-table-devtools/src/TableDevtools.ts b/packages/angular-table-devtools/src/TableDevtools.ts index b88c366710..0ea790a3b4 100644 --- a/packages/angular-table-devtools/src/TableDevtools.ts +++ b/packages/angular-table-devtools/src/TableDevtools.ts @@ -1,12 +1,9 @@ import { TableDevtoolsCore } from '@tanstack/table-devtools' -import { createAngularPanel } from '@tanstack/devtools-utils/angular' +import { computed, effect } from '@angular/core' import type { DevtoolsPanelProps } from '@tanstack/devtools-utils/angular' export interface TableDevtoolsAngularInit extends Partial {} -const [TableDevtoolsPanelBase, TableDevtoolsPanelNoOpBase] = - createAngularPanel(TableDevtoolsCore) - function resolvePanelProps( props?: TableDevtoolsAngularInit, ): DevtoolsPanelProps { @@ -23,12 +20,26 @@ type TableDevtoolsPanelComponent = () => ( export const TableDevtoolsPanel: TableDevtoolsPanelComponent = () => (props, host) => { - const panel = TableDevtoolsPanelBase() - return panel(() => resolvePanelProps(props()), host) + const panel = host.ownerDocument.createElement('div') + panel.style.height = '100%' + host.appendChild(panel) + + const panelProps = computed(() => resolvePanelProps(props()), { + equal: (previous, next) => + previous.theme === next.theme && + previous.devtoolsOpen === next.devtoolsOpen, + }) + const panelEffect = effect((onCleanup) => { + const instance = new TableDevtoolsCore() + void instance.mount(panel, panelProps()) + onCleanup(() => instance.unmount()) + }) + + return () => { + panelEffect.destroy() + panel.remove() + } } export const TableDevtoolsPanelNoOp: TableDevtoolsPanelComponent = - () => (_props, _host) => { - const panel = TableDevtoolsPanelNoOpBase() - return () => panel - } + () => (_props, _host) => () => {} diff --git a/packages/angular-table-devtools/src/injectTanStackTableDevtools.ts b/packages/angular-table-devtools/src/injectTanStackTableDevtools.ts index eabca429b5..e8ca71c6e0 100644 --- a/packages/angular-table-devtools/src/injectTanStackTableDevtools.ts +++ b/packages/angular-table-devtools/src/injectTanStackTableDevtools.ts @@ -1,5 +1,6 @@ -import { upsertTableDevtoolsTarget } from '@tanstack/table-devtools' +import { createTableDevtoolsRegistrationManager } from '@tanstack/table-devtools' import { + DestroyRef, Injector, assertInInjectionContext, effect, @@ -30,17 +31,15 @@ export function injectTanStackTableDevtools< injector = inject(Injector) } + const destroyRef = injector.get(DestroyRef) + const registration = createTableDevtoolsRegistrationManager() + destroyRef.onDestroy(() => registration.dispose()) + effect( - (onCleanup) => { + () => { const { table } = options() const enabledValue = enabled() - if (!enabledValue || !table) { - return - } - const cleanup = untracked(() => upsertTableDevtoolsTarget({ table })) - onCleanup(() => { - cleanup?.() - }) + untracked(() => registration.update(table, enabledValue)) }, { injector }, ) diff --git a/packages/angular-table-devtools/src/production.ts b/packages/angular-table-devtools/src/production.ts index f3e96534ef..1256c41c5a 100644 --- a/packages/angular-table-devtools/src/production.ts +++ b/packages/angular-table-devtools/src/production.ts @@ -1,5 +1,5 @@ -export { TableDevtoolsPanel } from './TableDevtools' +export { TableDevtoolsPanel } from './production/TableDevtools' export type { TableDevtoolsAngularInit } from './TableDevtools' -export { tableDevtoolsPlugin } from './plugin' +export { tableDevtoolsPlugin } from './production/plugin' export { injectTanStackTableDevtools } from './injectTanStackTableDevtools' export type { InjectTanStackTableDevtoolsOptions } from './injectTanStackTableDevtools' diff --git a/packages/angular-table-devtools/src/production/TableDevtools.ts b/packages/angular-table-devtools/src/production/TableDevtools.ts new file mode 100644 index 0000000000..c9061540c8 --- /dev/null +++ b/packages/angular-table-devtools/src/production/TableDevtools.ts @@ -0,0 +1,41 @@ +import { computed, effect } from '@angular/core' +import { TableDevtoolsCore } from '@tanstack/table-devtools/production' +import type { DevtoolsPanelProps } from '@tanstack/devtools-utils/angular' +import type { TableDevtoolsAngularInit } from '../TableDevtools' + +function resolvePanelProps( + props?: TableDevtoolsAngularInit, +): DevtoolsPanelProps { + return { + theme: props?.theme ?? 'dark', + devtoolsOpen: props?.devtoolsOpen ?? false, + } +} + +type TableDevtoolsPanelComponent = () => ( + inputs: () => TableDevtoolsAngularInit, + hostElement: HTMLElement, +) => () => void + +export const TableDevtoolsPanel: TableDevtoolsPanelComponent = + () => (props, host) => { + const panel = host.ownerDocument.createElement('div') + panel.style.height = '100%' + host.appendChild(panel) + + const panelProps = computed(() => resolvePanelProps(props()), { + equal: (previous, next) => + previous.theme === next.theme && + previous.devtoolsOpen === next.devtoolsOpen, + }) + const panelEffect = effect((onCleanup) => { + const instance = new TableDevtoolsCore() + void instance.mount(panel, panelProps()) + onCleanup(() => instance.unmount()) + }) + + return () => { + panelEffect.destroy() + panel.remove() + } + } diff --git a/packages/angular-table-devtools/src/production/plugin.ts b/packages/angular-table-devtools/src/production/plugin.ts new file mode 100644 index 0000000000..73c8683158 --- /dev/null +++ b/packages/angular-table-devtools/src/production/plugin.ts @@ -0,0 +1,11 @@ +import { createAngularPlugin } from '@tanstack/devtools-utils/angular' +import { TableDevtoolsPanel } from './TableDevtools' + +type TableDevtoolsPluginFactory = ReturnType[0] + +const [plugin] = createAngularPlugin({ + name: 'TanStack Table', + render: TableDevtoolsPanel, +}) + +export const tableDevtoolsPlugin: TableDevtoolsPluginFactory = plugin diff --git a/packages/angular-table/src/injectTable.ts b/packages/angular-table/src/injectTable.ts index 604d5dc348..485b2a97a3 100644 --- a/packages/angular-table/src/injectTable.ts +++ b/packages/angular-table/src/injectTable.ts @@ -105,11 +105,12 @@ export function injectTable< // Explicit type arguments skip generic inference from the spread object // (a type-check hot spot); the spread only adds the angular reactivity // binding to `features`. + const initialOptions = options() const table = constructTable({ - ...options(), + ...initialOptions, features: { coreReactivityFeature: angularReactivity(injector), - ...options().features, + ...initialOptions.features, }, }) diff --git a/packages/angular-table/src/reactivity.ts b/packages/angular-table/src/reactivity.ts index d35e0269ce..6b86e5245a 100644 --- a/packages/angular-table/src/reactivity.ts +++ b/packages/angular-table/src/reactivity.ts @@ -62,17 +62,14 @@ function signalToWritableAtom( /** * Creates the table-core reactivity bindings used by the Angular adapter. * - * Table state atoms are backed by TanStack Store atoms. The options store stays - * framework-native because row-model APIs read `table.options` directly during - * render. Readonly table atoms bridge Store dependency tracking into Angular - * computed signals. + * Table state and option atoms bridge table-core reads into Angular computed + * signals. */ export function angularReactivity(injector: Injector): TableReactivityBindings { const ngZone = injector.get(NgZone) const subscriptions = new Set() return { - createOptionsStore: true, wrapExternalAtoms: true, addSubscription: (subscription) => { subscriptions.add(subscription) diff --git a/packages/ember-table/src/reactivity.ts b/packages/ember-table/src/reactivity.ts index 98355b48b2..99a2a5911c 100644 --- a/packages/ember-table/src/reactivity.ts +++ b/packages/ember-table/src/reactivity.ts @@ -11,7 +11,6 @@ export function emberReactivity(): TableReactivityBindings { const subscriptions = new Set() return { - createOptionsStore: true, wrapExternalAtoms: true, // timing is not important, but the main thing is that the work does *not* @@ -20,8 +19,19 @@ export function emberReactivity(): TableReactivityBindings { batch: (fn) => fn(), untrack, // @cached - createReadonlyAtom: (fn: () => T) => { - return computed(fn) + createReadonlyAtom: (fn: () => T, options?: TableAtomOptions) => { + const compare = options?.compare ?? Object.is + let hasStableValue = false + let stableValue: T + + return computed(() => { + const nextValue = fn() + if (!hasStableValue || !compare(stableValue, nextValue)) { + stableValue = nextValue + hasStableValue = true + } + return stableValue + }) }, // @tracked createWritableAtom: (value: T, options?: TableAtomOptions) => { diff --git a/packages/ember-table/src/signal.ts b/packages/ember-table/src/signal.ts index c89373cb2a..f1c7ae275c 100644 --- a/packages/ember-table/src/signal.ts +++ b/packages/ember-table/src/signal.ts @@ -4,7 +4,10 @@ import { tracked, cached } from '@glimmer/tracking' import { untrack } from '@glimmer/validator' export function subscribeNoEffect(): Subscription { - return null as unknown as Subscription + // Glimmer invalidates computed consumers through tags rather than an + // imperative effect API. Still return a valid subscription object so the + // public ReadonlyAtom contract is safe for callers that always unsubscribe. + return { unsubscribe: () => {} } } /** diff --git a/packages/ember-table/src/use-table.ts b/packages/ember-table/src/use-table.ts index e1d02b9cc9..77123394f8 100644 --- a/packages/ember-table/src/use-table.ts +++ b/packages/ember-table/src/use-table.ts @@ -12,17 +12,10 @@ import type { } from '@tanstack/table-core' import type { Atom, ReadonlyAtom, ReadonlyStore } from '@tanstack/store' -// Internal table slots used by the pull-based options/state wiring below. +// Internal table slots used by the per-slice state wiring below. // `Table_Internal` is not exported from the table-core build, so the shape is // declared structurally here. -interface TableInternals< - TFeatures extends TableFeatures, - TData extends RowData, -> { - optionsStore?: { - get(): TableOptions - set(value: () => TableOptions): void - } +interface TableInternals { baseAtoms: Record< string, { @@ -33,6 +26,13 @@ interface TableInternals< atoms: Record } +const staticOptionKeys = new Set([ + 'atoms', + 'features', + 'initialState', + 'mergeOptions', +]) + /** * Creates an Ember-reactive table. * @@ -71,6 +71,37 @@ export function useTable< // Untracked to prevent possible "set on same computation as read" errors in Ember. const initialOptions = untrack(() => userOptions.get()) + const imperativeOptionKeys = new Set() + + const mergeOptions = ( + defaultOptions: TableOptions, + newOptions: Partial>, + ) => { + for (const key of Reflect.ownKeys(newOptions)) { + if (staticOptionKeys.has(key)) { + continue + } + + const currentHasKey = Reflect.has(defaultOptions, key) + const nextValue = Reflect.get(newOptions, key, newOptions) as unknown + const currentValue = currentHasKey + ? (Reflect.get( + defaultOptions, + key, + defaultOptions, + ) as unknown) + : undefined + + if (!currentHasKey || !Object.is(currentValue, nextValue)) { + imperativeOptionKeys.add(key) + } + } + + return { + ...defaultOptions, + ...newOptions, + } + } const table = constructTable({ ...initialOptions, @@ -78,80 +109,46 @@ export function useTable< coreReactivityFeature: reactivity, ...initialOptions.features, }, - mergeOptions: ( - defaultOptions: TableOptions, - newOptions: Partial>, - ) => ({ - ...defaultOptions, - ...newOptions, - }), - }) as Table & TableInternals + mergeOptions, + }) as Table & TableInternals + + // Keep Ember-specific getter tracking in the adapter. Core option atoms only + // store resolved values; these wrappers read the latest tracked user option + // until an imperative setOptions/optionAtoms write takes ownership. + for (const key of Reflect.ownKeys(table.optionAtoms)) { + if (key === 'snapshotVersion' || staticOptionKeys.has(key)) { + continue + } - const optionsStore = table.optionsStore! + const coreAtom = table.optionAtoms[ + key as keyof typeof table.optionAtoms + ] as Atom + const trackedAtom = { + get: () => { + if (imperativeOptionKeys.has(key)) { + return coreAtom.get() + } - const liveOptions = computed(() => { - const stored = optionsStore.get() - return { - ...stored, - ...userOptions.get(), - // stored options carry construct-time normalization (the reactivity - // feature, wrapped external atoms) that must win over the raw user - // options. - features: stored.features, - atoms: stored.atoms, + const currentOptions = userOptions.get() + return Reflect.has(currentOptions, key) + ? Reflect.get(currentOptions, key, currentOptions) + : coreAtom.get() + }, + subscribe: coreAtom.subscribe.bind(coreAtom), + set: coreAtom.set.bind(coreAtom), } - }) - - const getLiveOptions = () => liveOptions.get() - /** - * This is to get around core table not using lazy access so we need to re-wrap - * - * Similar to other reactive signal frameworks (solid, angular, svelte) - */ - Object.defineProperty(table, 'options', { - configurable: true, - enumerable: true, - get: getLiveOptions, - set: (value: TableOptions) => { - optionsStore.set(() => value) - }, - }) + Object.defineProperty(table.optionAtoms, key, { + configurable: true, + enumerable: true, + value: trackedAtom, + writable: false, + }) + } const atoms: Record> = table.atoms const stateKeys = Object.keys(table.baseAtoms) - for (const key of stateKeys) { - const baseAtom = (table.baseAtoms as Record>)[ - key - ]! - - /** - * Original atoms could cause effects for top level properties - * - * Core table should migrate to pure derived data which would boost render - * performance for both signal and non-signal frameworks. - */ - atoms[key] = reactivity.createReadonlyAtom( - () => { - const externalAtom = ( - table.options.atoms as Record> | undefined - )?.[key] - if (externalAtom) { - return externalAtom.get() - } - const stateSlice = ( - table.options.state as Record | undefined - )?.[key] - if (stateSlice !== undefined) { - return stateSlice - } - return baseAtom.get() - }, - { debugName: `table/atoms/${key}` }, - ) - } - const stateProxy: TableState = new Proxy( {}, { diff --git a/packages/ember-table/tests/integration/use-table.test.gts b/packages/ember-table/tests/integration/use-table.test.gts index cb06133665..22d34e05ba 100644 --- a/packages/ember-table/tests/integration/use-table.test.gts +++ b/packages/ember-table/tests/integration/use-table.test.gts @@ -35,6 +35,23 @@ const keysInclude = (obj: object, key: string): boolean => module('Integration | useTable', function (hooks) { setupRenderingTest(hooks) + test('option atoms return a valid subscription', function (assert) { + const table = useTable(() => ({ + data: makeData(1), + features: stockFeatures, + columns: [], + })) + + const subscription = table.optionAtoms.data.subscribe(() => {}) + + assert.strictEqual( + typeof subscription.unsubscribe, + 'function', + 'callers can always tear down the returned subscription', + ) + subscription.unsubscribe() + }) + test('can initialize with basic no columns or data', async (assert) => { class TableComponent extends Component { @tracked data = [] @@ -123,6 +140,209 @@ module('Integration | useTable', function (hooks) { .exists({ count: 1 }, 'row model re-renders when tracked data changes') }) + test('keeps the central options proxy stable and live', async (assert) => { + class TableComponent extends Component { + @tracked data = makeData(2) + + table = useTable(() => ({ + data: this.data, + features: stockFeatures, + columns: [], + })) + + savedOptions = this.table.options + + get hasSameOptionsReference() { + return this.savedOptions === this.table.options + } + + get savedOptionsDataLength() { + return this.savedOptions.data.length + } + + get optionAtomDataLength() { + return this.table.optionAtoms.data.get().length + } + + shrink = () => { + this.data = makeData(1) + } + + + } + + await render() + + assert + .dom('[data-test-options-identity]') + .hasText('same', 'the adapter leaves core’s stable options proxy intact') + assert + .dom('[data-test-saved-options]') + .hasText('2', 'a saved options reference reads the initial value') + assert + .dom('[data-test-option-atom]') + .hasText('2', 'the option atom reads the initial value') + + await click('[data-test-shrink]') + + assert + .dom('[data-test-options-identity]') + .hasText('same', 'the options proxy identity stays stable after updates') + assert + .dom('[data-test-saved-options]') + .hasText('1', 'the saved options reference remains live') + assert + .dom('[data-test-option-atom]') + .hasText('1', 'the option atom remains live') + }) + + test('imperative option writes override tracked adapter options', async (assert) => { + class TableComponent extends Component { + @tracked data = makeData(3) + + table = useTable(() => ({ + data: this.data, + features: stockFeatures, + columns: [], + })) + + get optionsDataLength() { + return this.table.options.data.length + } + + get optionAtomDataLength() { + return this.table.optionAtoms.data.get().length + } + + setThroughApi = () => { + this.table.setOptions((previous) => ({ + ...previous, + data: makeData(2), + })) + this.data = makeData(5) + } + + setThroughAtom = () => { + this.table.optionAtoms.data.set(makeData(1)) + this.data = makeData(6) + } + + + } + + await render() + + assert.dom('[data-test-options-data]').hasText('3') + assert.dom('[data-test-option-atom-data]').hasText('3') + + await click('[data-test-set-api]') + + assert + .dom('[data-test-options-data]') + .hasText('2', 'setOptions wins over a later tracked option change') + assert.dom('[data-test-option-atom-data]').hasText('2') + + await click('[data-test-set-atom]') + + assert + .dom('[data-test-options-data]') + .hasText('1', 'assignment through the option atom remains visible') + assert.dom('[data-test-option-atom-data]').hasText('1') + }) + + test('setOptions can add option keys after construction', async (assert) => { + class TableComponent extends Component { + @tracked refresh = 0 + + table = useTable(() => ({ + data: makeData(1), + features: stockFeatures, + columns: [], + })) + + get optionValue() { + void this.refresh + return String(this.table.options.debugRows) + } + + get optionAtomValue() { + void this.refresh + return String(this.table.optionAtoms.debugRows?.get()) + } + + get hasOption() { + void this.refresh + return String('debugRows' in this.table.options) + } + + addOption = () => { + this.table.setOptions((previous) => ({ + ...previous, + debugRows: true, + })) + // The key did not exist when the template first rendered, so there was + // no option atom to track yet. The host rerender makes the newly + // created atom visible. + this.refresh++ + } + + + } + + await render() + + assert.dom('[data-test-option-value]').hasText('undefined') + assert.dom('[data-test-option-atom-value]').hasText('undefined') + assert.dom('[data-test-has-option]').hasText('false') + + await click('[data-test-add-option]') + + assert + .dom('[data-test-option-value]') + .hasText('true', 'the live options proxy sees the newly supplied key') + assert + .dom('[data-test-option-atom-value]') + .hasText('true', 'setOptions creates the new option atom') + assert + .dom('[data-test-has-option]') + .hasText('true', 'reflection sees the newly supplied key') + }) + // Ember analog of angular's "in" / "Object.keys" structural tests, expressed // as rendered output since ember's table is a plain object (not a Proxy). test('exposes expected table structure', async (assert) => { diff --git a/packages/lit-table/src/TableController.ts b/packages/lit-table/src/TableController.ts index a3211e74f6..90de69bbb3 100644 --- a/packages/lit-table/src/TableController.ts +++ b/packages/lit-table/src/TableController.ts @@ -137,6 +137,7 @@ export class TableController< private _storeSubscription?: { unsubscribe: () => void } private _capturedState?: Partial> private _capturedSnapshot?: TableState + private _capturedOptionsToken?: number private _hasSelector = false private _latestSelector?: (state: TableState) => unknown private _lastSelected: unknown @@ -165,6 +166,8 @@ export class TableController< tableOptions: TableOptions, selector?: (state: TableState) => TSelected, ): LitTable { + let constructed = false + if (!this._table) { const mergedOptions: TableOptions = { ...tableOptions, @@ -192,18 +195,24 @@ export class TableController< // Set up subscriptions immediately when table is created this._setupSubscriptions() + constructed = true } // Stage current options for same-render table reads. Publication happens - // in hostUpdated() after Lit commits this render. - table_setOptions( - this._table, - (prev) => ({ - ...prev, - ...tableOptions, - }), - { syncExternalState: false }, - ) + // in hostUpdated() after Lit commits this render. Construction already + // installed this render's options, so avoid a redundant first stage: its + // commit would invalidate every render-phase memo after the values that + // produced the committed DOM were already read. + this._capturedOptionsToken = constructed + ? undefined + : table_setOptions( + this._table, + (prev) => ({ + ...prev, + ...tableOptions, + }), + { syncExternalState: false }, + ) this._capturedState = this._table.options.state const renderSnapshot = this._rootSource!.get() @@ -264,6 +273,7 @@ export class TableController< this._table, this._capturedState ?? null, shallow, + this._capturedOptionsToken, ) } diff --git a/packages/lit-table/src/reactivity.ts b/packages/lit-table/src/reactivity.ts index 0aead58a14..9ae3811f18 100644 --- a/packages/lit-table/src/reactivity.ts +++ b/packages/lit-table/src/reactivity.ts @@ -7,13 +7,11 @@ export type LitTableReactivityBindings = RenderPhaseReactivityBindings /** * Creates the table-core reactivity bindings used by the Lit adapter. * - * Lit calls `controller.table(options)` from the host's `render()`, so options - * are plain values synchronized during the update cycle — writing a reactive - * options store there would schedule a second update per interaction. The - * render-phase preset supplies the live readonly-atom facades and the `commit` - * hook; `TableController` publishes its captured controlled state from - * `hostUpdated()`. Store primitives come from `@tanstack/lit-store` so all - * atoms share one store instance with user-provided external atoms. + * Lit calls `controller.table(options)` from the host's `render()`, so option + * atoms are staged without notification during the update cycle. The + * render-phase preset supplies live option facades, cached memo atoms, and the + * commit hook; `TableController` publishes its captured state and option token + * from `hostUpdated()`. Store primitives come from `@tanstack/lit-store`. */ export function litReactivity(): LitTableReactivityBindings { return renderPhaseReactivity({ createAtom, batch }) diff --git a/packages/preact-table-devtools/src/PreactTableDevtools.tsx b/packages/preact-table-devtools/src/PreactTableDevtools.tsx index b84cae7ced..9e0f7e681b 100644 --- a/packages/preact-table-devtools/src/PreactTableDevtools.tsx +++ b/packages/preact-table-devtools/src/PreactTableDevtools.tsx @@ -1,4 +1,5 @@ import { h } from 'preact' +import { useMemo } from 'preact/hooks' import { createPreactPanel } from '@tanstack/devtools-utils/preact' import { TableDevtoolsCore } from '@tanstack/table-devtools' import type { DevtoolsPanelProps } from '@tanstack/devtools-utils/preact' @@ -22,8 +23,22 @@ function resolvePanelProps( } } -export const TableDevtoolsPanel: TableDevtoolsPanelComponent = (props) => - h(TableDevtoolsPanelBase, resolvePanelProps(props)) +export const TableDevtoolsPanel: TableDevtoolsPanelComponent = (props) => { + const theme = props?.theme + const devtoolsOpen = props?.devtoolsOpen + const panelProps = useMemo( + () => resolvePanelProps({ theme, devtoolsOpen }), + [devtoolsOpen, theme], + ) + return h(TableDevtoolsPanelBase, panelProps) +} -export const TableDevtoolsPanelNoOp: TableDevtoolsPanelComponent = (props) => - h(TableDevtoolsPanelNoOpBase, resolvePanelProps(props)) +export const TableDevtoolsPanelNoOp: TableDevtoolsPanelComponent = (props) => { + const theme = props?.theme + const devtoolsOpen = props?.devtoolsOpen + const panelProps = useMemo( + () => resolvePanelProps({ theme, devtoolsOpen }), + [devtoolsOpen, theme], + ) + return h(TableDevtoolsPanelNoOpBase, panelProps) +} diff --git a/packages/preact-table-devtools/src/production.ts b/packages/preact-table-devtools/src/production.ts index 2212d72fce..9d7e6de391 100644 --- a/packages/preact-table-devtools/src/production.ts +++ b/packages/preact-table-devtools/src/production.ts @@ -1,7 +1,7 @@ 'use client' -export { TableDevtoolsPanel } from './PreactTableDevtools' +export { TableDevtoolsPanel } from './production/PreactTableDevtools' export type { TableDevtoolsPreactInit } from './PreactTableDevtools' -export { tableDevtoolsPlugin } from './plugin' +export { tableDevtoolsPlugin } from './production/plugin' export { useTanStackTableDevtools } from './useTanStackTableDevtools' export type { UseTanStackTableDevtoolsOptions } from './useTanStackTableDevtools' diff --git a/packages/preact-table-devtools/src/production/PreactTableDevtools.tsx b/packages/preact-table-devtools/src/production/PreactTableDevtools.tsx new file mode 100644 index 0000000000..7606a20f5c --- /dev/null +++ b/packages/preact-table-devtools/src/production/PreactTableDevtools.tsx @@ -0,0 +1,32 @@ +import { h } from 'preact' +import { useMemo } from 'preact/hooks' +import { createPreactPanel } from '@tanstack/devtools-utils/preact' +import { TableDevtoolsCore } from '@tanstack/table-devtools/production' +import type { DevtoolsPanelProps } from '@tanstack/devtools-utils/preact' +import type { JSX } from 'preact' +import type { TableDevtoolsPreactInit } from '../PreactTableDevtools' + +type TableDevtoolsPanelComponent = ( + props?: TableDevtoolsPreactInit, +) => JSX.Element + +const [TableDevtoolsPanelBase] = createPreactPanel(TableDevtoolsCore) + +function resolvePanelProps( + props?: TableDevtoolsPreactInit, +): DevtoolsPanelProps { + return { + theme: props?.theme ?? 'dark', + devtoolsOpen: props?.devtoolsOpen ?? false, + } +} + +export const TableDevtoolsPanel: TableDevtoolsPanelComponent = (props) => { + const theme = props?.theme + const devtoolsOpen = props?.devtoolsOpen + const panelProps = useMemo( + () => resolvePanelProps({ theme, devtoolsOpen }), + [devtoolsOpen, theme], + ) + return h(TableDevtoolsPanelBase, panelProps) +} diff --git a/packages/preact-table-devtools/src/production/plugin.tsx b/packages/preact-table-devtools/src/production/plugin.tsx new file mode 100644 index 0000000000..a75f39c20d --- /dev/null +++ b/packages/preact-table-devtools/src/production/plugin.tsx @@ -0,0 +1,13 @@ +import { createPreactPlugin } from '@tanstack/devtools-utils/preact' +import { TableDevtoolsPanel } from './PreactTableDevtools' + +type PreactTableDevtoolsPlugin = ReturnType< + ReturnType[0] +> + +const [plugin] = createPreactPlugin({ + name: 'TanStack Table', + Component: TableDevtoolsPanel, +}) + +export const tableDevtoolsPlugin: () => PreactTableDevtoolsPlugin = plugin diff --git a/packages/preact-table-devtools/src/useTanStackTableDevtools.ts b/packages/preact-table-devtools/src/useTanStackTableDevtools.ts index 80b51f5ca4..52682f8044 100644 --- a/packages/preact-table-devtools/src/useTanStackTableDevtools.ts +++ b/packages/preact-table-devtools/src/useTanStackTableDevtools.ts @@ -1,7 +1,7 @@ 'use client' -import { useEffect } from 'preact/hooks' -import { upsertTableDevtoolsTarget } from '@tanstack/table-devtools' +import { useEffect, useRef } from 'preact/hooks' +import { createTableDevtoolsRegistrationManager } from '@tanstack/table-devtools' import type { RowData, Table, TableFeatures } from '@tanstack/table-core' export interface UseTanStackTableDevtoolsOptions { @@ -16,18 +16,18 @@ export function useTanStackTableDevtools< options?: UseTanStackTableDevtoolsOptions, ): void { const enabled = options?.enabled ?? true + const registrationRef = + useRef>() + registrationRef.current ??= createTableDevtoolsRegistrationManager() + const registration = registrationRef.current useEffect(() => { - if (!enabled || !table) { - return - } + return () => registration.dispose() + }, [registration]) - const cleanup = upsertTableDevtoolsTarget({ table }) - - return () => { - cleanup?.() - } - }, [enabled, table, table?.options.key]) + useEffect(() => { + registration.update(table, enabled) + }, [enabled, registration, table, table?.options.key]) } export function useTanStackTableDevtoolsNoOp< diff --git a/packages/preact-table/src/Subscribe.ts b/packages/preact-table/src/Subscribe.ts index c8b79480e3..1d6b27d2bc 100644 --- a/packages/preact-table/src/Subscribe.ts +++ b/packages/preact-table/src/Subscribe.ts @@ -36,7 +36,7 @@ export type SubscribePropsWithStore< /** * Subscribe to the full value of a source (e.g. `table.atoms.rowSelection` or - * `table.optionsStore`). Omitting `selector` is equivalent to the identity + * `table.optionAtoms.data`). Omitting `selector` is equivalent to the identity * selector — children receive `TSourceValue`. */ export type SubscribePropsWithSourceIdentity = { diff --git a/packages/preact-table/src/reactivity.ts b/packages/preact-table/src/reactivity.ts index 5fecc253a8..17a9e13e5f 100644 --- a/packages/preact-table/src/reactivity.ts +++ b/packages/preact-table/src/reactivity.ts @@ -7,10 +7,9 @@ export type PreactTableReactivityBindings = RenderPhaseReactivityBindings /** * Creates the table-core reactivity bindings used by the Preact adapter. * - * Preact stores table state in TanStack Store atoms and leaves options as - * plain resolved data because `useTable` synchronizes options during render. - * The render-phase preset supplies the live readonly-atom facades and the - * `commit` hook; the store primitives are passed in from + * Preact synchronizes option atoms during render without publishing them until + * commit. The render-phase preset supplies live option facades, cached memo + * atoms, and the commit hook; the store primitives come from * `@tanstack/preact-store` so all atoms share one store instance with * user-provided external atoms. */ diff --git a/packages/preact-table/src/useTable.ts b/packages/preact-table/src/useTable.ts index 957f0c6fec..9ffe190547 100644 --- a/packages/preact-table/src/useTable.ts +++ b/packages/preact-table/src/useTable.ts @@ -40,8 +40,9 @@ export type PreactTable< /** * A Preact HOC (Higher Order Component) that allows you to subscribe to the table state. * - * Pass `source` to subscribe to a single atom or store (e.g. `table.atoms.rowSelection` - * or `table.optionsStore`) instead of the full `table.store`. + * Pass `source` to subscribe to a single atom or store (e.g. + * `table.atoms.rowSelection` or `table.optionAtoms.data`) instead of the full + * `table.store`. * * @example * ({ rowSelection: state.rowSelection })}> @@ -161,7 +162,7 @@ export function useTable< // Keep options current during render without publishing them to reactive // subscribers. Readonly atoms expose the staged snapshot through live get(). - table_setOptions( + const optionCommitToken = table_setOptions( coreTable, (prev) => ({ ...prev, @@ -177,15 +178,19 @@ export function useTable< useIsomorphicLayoutEffect(() => { rootSource.markCommitted(renderSnapshot) - table_publishExternalState(coreTable, controlledState ?? null, shallow) + table_publishExternalState( + coreTable, + controlledState ?? null, + shallow, + optionCommitToken, + ) }) return useMemo( () => ({ ...table, - options: tableOptions, state, }), - [table, tableOptions, state], + [table, state], ) } diff --git a/packages/preact-table/tests/unit/adapterReactivity.test.tsx b/packages/preact-table/tests/unit/adapterReactivity.test.tsx index 74e92cb42a..a034515001 100644 --- a/packages/preact-table/tests/unit/adapterReactivity.test.tsx +++ b/packages/preact-table/tests/unit/adapterReactivity.test.tsx @@ -130,7 +130,7 @@ describe('Preact adapter reactivity and lifecycle', () => { ) }) - test('updates the paginated row model without invalidating the core row model', () => { + test('updates pagination with broad render-phase memo invalidation', () => { const data = Array.from({ length: 10 }, (_, index) => ({ id: String(index), title: `Title ${index}`, @@ -188,7 +188,10 @@ describe('Preact adapter reactivity and lifecycle', () => { expect(text('Page row IDs')).toBe('0,1,2') expect(coreRowModelCaptor).toHaveBeenCalledTimes(2) expect(rowModelCaptor).toHaveBeenCalledTimes(2) - expect(coreRowModelCaptor.mock.calls[0]![0]).toBe( + // Render-phase adapters intentionally rotate native memo atoms for any + // materially changed staged options source. Per-option revisions/read + // collectors are deliberately not part of this first implementation. + expect(coreRowModelCaptor.mock.calls[0]![0]).not.toBe( coreRowModelCaptor.mock.calls[1]![0], ) expect(rowModelCaptor.mock.calls[0]![0].rows).toHaveLength(5) diff --git a/packages/react-table-devtools/src/ReactTableDevtools.tsx b/packages/react-table-devtools/src/ReactTableDevtools.tsx index 898c95f67d..4fbd67f137 100644 --- a/packages/react-table-devtools/src/ReactTableDevtools.tsx +++ b/packages/react-table-devtools/src/ReactTableDevtools.tsx @@ -1,4 +1,4 @@ -import { createElement } from 'react' +import { createElement, useMemo } from 'react' import { createReactPanel } from '@tanstack/devtools-utils/react' import { TableDevtoolsCore } from '@tanstack/table-devtools' import type { DevtoolsPanelProps } from '@tanstack/devtools-utils/react' @@ -20,8 +20,22 @@ function resolvePanelProps(props?: TableDevtoolsReactInit): DevtoolsPanelProps { } } -export const TableDevtoolsPanel: TableDevtoolsPanelComponent = (props) => - createElement(TableDevtoolsPanelBase, resolvePanelProps(props)) +export const TableDevtoolsPanel: TableDevtoolsPanelComponent = (props) => { + const theme = props?.theme + const devtoolsOpen = props?.devtoolsOpen + const panelProps = useMemo( + () => resolvePanelProps({ theme, devtoolsOpen }), + [devtoolsOpen, theme], + ) + return createElement(TableDevtoolsPanelBase, panelProps) +} -export const TableDevtoolsPanelNoOp: TableDevtoolsPanelComponent = (props) => - createElement(TableDevtoolsPanelNoOpBase, resolvePanelProps(props)) +export const TableDevtoolsPanelNoOp: TableDevtoolsPanelComponent = (props) => { + const theme = props?.theme + const devtoolsOpen = props?.devtoolsOpen + const panelProps = useMemo( + () => resolvePanelProps({ theme, devtoolsOpen }), + [devtoolsOpen, theme], + ) + return createElement(TableDevtoolsPanelNoOpBase, panelProps) +} diff --git a/packages/react-table-devtools/src/production.ts b/packages/react-table-devtools/src/production.ts index d31f8bce12..17fbb08574 100644 --- a/packages/react-table-devtools/src/production.ts +++ b/packages/react-table-devtools/src/production.ts @@ -1,7 +1,7 @@ 'use client' -export { TableDevtoolsPanel } from './ReactTableDevtools' +export { TableDevtoolsPanel } from './production/ReactTableDevtools' export type { TableDevtoolsReactInit } from './ReactTableDevtools' -export { tableDevtoolsPlugin } from './plugin' +export { tableDevtoolsPlugin } from './production/plugin' export { useTanStackTableDevtools } from './useTanStackTableDevtools' export type { UseTanStackTableDevtoolsOptions } from './useTanStackTableDevtools' diff --git a/packages/react-table-devtools/src/production/ReactTableDevtools.tsx b/packages/react-table-devtools/src/production/ReactTableDevtools.tsx new file mode 100644 index 0000000000..5d2f4e5dd8 --- /dev/null +++ b/packages/react-table-devtools/src/production/ReactTableDevtools.tsx @@ -0,0 +1,29 @@ +import { createElement, useMemo } from 'react' +import { createReactPanel } from '@tanstack/devtools-utils/react' +import { TableDevtoolsCore } from '@tanstack/table-devtools/production' +import type { DevtoolsPanelProps } from '@tanstack/devtools-utils/react' +import type { JSX } from 'react' +import type { TableDevtoolsReactInit } from '../ReactTableDevtools' + +type TableDevtoolsPanelComponent = ( + props?: TableDevtoolsReactInit, +) => JSX.Element + +const [TableDevtoolsPanelBase] = createReactPanel(TableDevtoolsCore) + +function resolvePanelProps(props?: TableDevtoolsReactInit): DevtoolsPanelProps { + return { + theme: props?.theme ?? 'dark', + devtoolsOpen: props?.devtoolsOpen ?? false, + } +} + +export const TableDevtoolsPanel: TableDevtoolsPanelComponent = (props) => { + const theme = props?.theme + const devtoolsOpen = props?.devtoolsOpen + const panelProps = useMemo( + () => resolvePanelProps({ theme, devtoolsOpen }), + [devtoolsOpen, theme], + ) + return createElement(TableDevtoolsPanelBase, panelProps) +} diff --git a/packages/react-table-devtools/src/production/plugin.tsx b/packages/react-table-devtools/src/production/plugin.tsx new file mode 100644 index 0000000000..af649b07db --- /dev/null +++ b/packages/react-table-devtools/src/production/plugin.tsx @@ -0,0 +1,11 @@ +import { createReactPlugin } from '@tanstack/devtools-utils/react' +import { TableDevtoolsPanel } from './ReactTableDevtools' + +type TableDevtoolsPluginFactory = ReturnType[0] + +const [plugin] = createReactPlugin({ + name: 'TanStack Table', + Component: TableDevtoolsPanel, +}) + +export const tableDevtoolsPlugin: TableDevtoolsPluginFactory = plugin diff --git a/packages/react-table-devtools/src/table-devtools.d.ts b/packages/react-table-devtools/src/table-devtools.d.ts index e8b6b1d122..e8db884dc5 100644 --- a/packages/react-table-devtools/src/table-devtools.d.ts +++ b/packages/react-table-devtools/src/table-devtools.d.ts @@ -31,4 +31,14 @@ declare module '@tanstack/table-devtools' { ): (() => void) | undefined export function removeTableDevtoolsTarget(id: string): void + + export interface TableDevtoolsRegistrationManager { + update: ( + table: Table | undefined, + enabled?: boolean, + ) => void + dispose: () => void + } + + export function createTableDevtoolsRegistrationManager(): TableDevtoolsRegistrationManager } diff --git a/packages/react-table-devtools/src/useTanStackTableDevtools.ts b/packages/react-table-devtools/src/useTanStackTableDevtools.ts index fed82bad9b..1375f57be2 100644 --- a/packages/react-table-devtools/src/useTanStackTableDevtools.ts +++ b/packages/react-table-devtools/src/useTanStackTableDevtools.ts @@ -1,7 +1,7 @@ 'use client' -import { upsertTableDevtoolsTarget } from '@tanstack/table-devtools' -import { useEffect } from 'react' +import { createTableDevtoolsRegistrationManager } from '@tanstack/table-devtools' +import { useEffect, useState } from 'react' import type { RowData, Table, TableFeatures } from '@tanstack/table-core' export interface UseTanStackTableDevtoolsOptions { @@ -16,18 +16,15 @@ export function useTanStackTableDevtools< options?: UseTanStackTableDevtoolsOptions, ): void { const enabled = options?.enabled ?? true + const [registration] = useState(createTableDevtoolsRegistrationManager) useEffect(() => { - if (!enabled || !table) { - return - } + return () => registration.dispose() + }, [registration]) - const cleanup = upsertTableDevtoolsTarget({ table }) - - return () => { - cleanup?.() - } - }, [enabled, table, table?.options.key]) + useEffect(() => { + registration.update(table, enabled) + }, [enabled, registration, table, table?.options.key]) } export function useTanStackTableDevtoolsNoOp< diff --git a/packages/react-table/src/Subscribe.ts b/packages/react-table/src/Subscribe.ts index b9a9c45445..f799f838ac 100644 --- a/packages/react-table/src/Subscribe.ts +++ b/packages/react-table/src/Subscribe.ts @@ -38,7 +38,7 @@ export type SubscribePropsWithStore< /** * Subscribe to the full value of a source (e.g. `table.atoms.rowSelection` or - * `table.optionsStore`). Omitting `selector` is equivalent to the identity + * `table.optionAtoms.data`). Omitting `selector` is equivalent to the identity * selector — children receive `TSourceValue`. */ export type SubscribePropsWithSourceIdentity = { diff --git a/packages/react-table/src/reactivity.ts b/packages/react-table/src/reactivity.ts index fdc9e174df..492635220d 100644 --- a/packages/react-table/src/reactivity.ts +++ b/packages/react-table/src/reactivity.ts @@ -7,11 +7,11 @@ export type ReactTableReactivityBindings = RenderPhaseReactivityBindings /** * Creates the table-core reactivity bindings used by the React adapter. * - * React stores table state in TanStack Store atoms and leaves options as plain - * resolved data because `useTable` synchronizes options during render. The - * render-phase preset supplies the live readonly-atom facades and the `commit` - * hook; the store primitives are passed in from `@tanstack/react-store` so all - * atoms share one store instance with user-provided external atoms. + * React synchronizes option atoms during render without publishing them until + * commit. The render-phase preset supplies live option facades, cached memo + * atoms, and the commit hook; the store primitives come from + * `@tanstack/react-store` so all atoms share one store instance with + * user-provided external atoms. */ export function reactReactivity(): ReactTableReactivityBindings { return renderPhaseReactivity({ createAtom, batch }) diff --git a/packages/react-table/src/useTable.ts b/packages/react-table/src/useTable.ts index 7e4a839d6e..cee795b58e 100644 --- a/packages/react-table/src/useTable.ts +++ b/packages/react-table/src/useTable.ts @@ -44,8 +44,9 @@ export type ReactTable< * * This is useful for opting into state re-renders for specific parts of the table state. * - * Pass `source` to subscribe to a single atom or store (e.g. `table.atoms.rowSelection` - * or `table.optionsStore`) instead of the full `table.store`. + * Pass `source` to subscribe to a single atom or store (e.g. + * `table.atoms.rowSelection` or `table.optionAtoms.data`) instead of the full + * `table.store`. * * @example * ({ rowSelection: state.rowSelection })}> @@ -190,7 +191,7 @@ export function useTable< // Keep options current during render without publishing them to reactive // subscribers. Readonly atoms expose the staged snapshot through live get(). - table_setOptions( + const optionCommitToken = table_setOptions( coreTable, (prev) => ({ ...prev, @@ -211,7 +212,12 @@ export function useTable< // subscription drops the matching notification. Isolated subscribers // still receive the post-commit store update before paint. rootSource.markCommitted(renderSnapshot) - table_publishExternalState(coreTable, controlledState ?? null, shallow) + table_publishExternalState( + coreTable, + controlledState ?? null, + shallow, + optionCommitToken, + ) }) // we know this is not the most efficient way to return the table, @@ -219,9 +225,8 @@ export function useTable< return useMemo( () => ({ ...table, - options: tableOptions, state, }), - [table, tableOptions, state], + [table, state], ) } diff --git a/packages/react-table/tests/adapterReactivity.test.tsx b/packages/react-table/tests/adapterReactivity.test.tsx index 3fe4e24724..596a47c09f 100644 --- a/packages/react-table/tests/adapterReactivity.test.tsx +++ b/packages/react-table/tests/adapterReactivity.test.tsx @@ -150,7 +150,7 @@ describe('React adapter reactivity and lifecycle', () => { ) }) - test('updates the paginated row model without invalidating the core row model', () => { + test('updates pagination with broad render-phase memo invalidation', () => { const data = Array.from({ length: 10 }, (_, index) => ({ id: String(index), title: `Title ${index}`, @@ -207,7 +207,10 @@ describe('React adapter reactivity and lifecycle', () => { expect(text('Page row IDs')).toBe('0,1,2') expect(coreRowModelCaptor).toHaveBeenCalledTimes(2) expect(rowModelCaptor).toHaveBeenCalledTimes(2) - expect(coreRowModelCaptor.mock.calls[0]![0]).toBe( + // Render-phase adapters intentionally rotate native memo atoms for any + // materially changed staged options source. Per-option revisions/read + // collectors are deliberately not part of this first implementation. + expect(coreRowModelCaptor.mock.calls[0]![0]).not.toBe( coreRowModelCaptor.mock.calls[1]![0], ) expect(rowModelCaptor.mock.calls[0]![0].rows).toHaveLength(5) diff --git a/packages/solid-table-devtools/src/TableDevtools.tsx b/packages/solid-table-devtools/src/TableDevtools.tsx index 75b8f100ce..b20fea09f4 100644 --- a/packages/solid-table-devtools/src/TableDevtools.tsx +++ b/packages/solid-table-devtools/src/TableDevtools.tsx @@ -14,8 +14,12 @@ const [TableDevtoolsPanelBase, TableDevtoolsPanelNoOpBase] = function resolvePanelProps(props?: TableDevtoolsSolidInit): DevtoolsPanelProps { return { - theme: props?.theme ?? 'dark', - devtoolsOpen: props?.devtoolsOpen ?? false, + get theme() { + return props?.theme ?? 'dark' + }, + get devtoolsOpen() { + return props?.devtoolsOpen ?? false + }, } } diff --git a/packages/solid-table-devtools/src/production.ts b/packages/solid-table-devtools/src/production.ts index 010ae2139e..eddeb12413 100644 --- a/packages/solid-table-devtools/src/production.ts +++ b/packages/solid-table-devtools/src/production.ts @@ -1,4 +1,4 @@ -export { TableDevtoolsPanel } from './TableDevtools' +export { TableDevtoolsPanel } from './production/TableDevtools' export type { TableDevtoolsSolidInit } from './production/TableDevtools' diff --git a/packages/solid-table-devtools/src/production/TableDevtools.tsx b/packages/solid-table-devtools/src/production/TableDevtools.tsx index c6670acf6f..ec38ac5ae5 100644 --- a/packages/solid-table-devtools/src/production/TableDevtools.tsx +++ b/packages/solid-table-devtools/src/production/TableDevtools.tsx @@ -14,8 +14,12 @@ type TableDevtoolsPanelComponent = ( function resolvePanelProps(props?: TableDevtoolsSolidInit): DevtoolsPanelProps { return { - theme: props?.theme ?? 'dark', - devtoolsOpen: props?.devtoolsOpen ?? false, + get theme() { + return props?.theme ?? 'dark' + }, + get devtoolsOpen() { + return props?.devtoolsOpen ?? false + }, } } diff --git a/packages/solid-table-devtools/src/useTanStackTableDevtools.ts b/packages/solid-table-devtools/src/useTanStackTableDevtools.ts index 5c5fc60b40..160116b207 100644 --- a/packages/solid-table-devtools/src/useTanStackTableDevtools.ts +++ b/packages/solid-table-devtools/src/useTanStackTableDevtools.ts @@ -1,5 +1,5 @@ import { createRenderEffect, onCleanup } from 'solid-js' -import { upsertTableDevtoolsTarget } from '@tanstack/table-devtools' +import { createTableDevtoolsRegistrationManager } from '@tanstack/table-devtools' import type { RowData, Table, TableFeatures } from '@tanstack/table-core' export interface UseTanStackTableDevtoolsOptions { @@ -13,16 +13,11 @@ export function useTanStackTableDevtools< table: Table | undefined, options?: UseTanStackTableDevtoolsOptions, ): void { - createRenderEffect(() => { - if (!(options?.enabled ?? true) || !table) { - return - } - - const cleanup = upsertTableDevtoolsTarget({ table }) + const registration = createTableDevtoolsRegistrationManager() + onCleanup(() => registration.dispose()) - onCleanup(() => { - cleanup?.() - }) + createRenderEffect(() => { + registration.update(table, options?.enabled ?? true) }) } diff --git a/packages/solid-table/src/createTable.ts b/packages/solid-table/src/createTable.ts index 3a5a91c80d..1e3e0cd445 100644 --- a/packages/solid-table/src/createTable.ts +++ b/packages/solid-table/src/createTable.ts @@ -1,12 +1,7 @@ import { constructTable } from '@tanstack/table-core' -import { - createComputed, - getOwner, - mergeProps, - onCleanup, - untrack, -} from 'solid-js' +import { createComputed, getOwner, onCleanup, untrack } from 'solid-js' import { FlexRender } from './FlexRender' +import { mergeOptionSources } from './merge-options' import { solidReactivity } from './reactivity' import type { JSX } from 'solid-js' import type { @@ -65,20 +60,20 @@ export function createTable< const owner = getOwner()! const reactivity = solidReactivity(owner) - const mergedOptions = mergeProps(tableOptions, { + const mergedOptions = mergeOptionSources(tableOptions, { features: { coreReactivityFeature: reactivity, ...tableOptions.features, }, }) as any - const resolvedOptions = mergeProps( + const resolvedOptions = mergeOptionSources( { mergeOptions: ( defaultOptions: TableOptions, options: TableOptions, ) => { - return mergeProps(defaultOptions, options) + return mergeOptionSources(defaultOptions, options) }, }, mergedOptions, @@ -90,6 +85,12 @@ export function createTable< > createComputed(() => { + // Option atoms store resolved values. Touch every current option while + // tracked so a signal-backed getter re-runs this synchronization. + for (const key of Reflect.ownKeys(mergedOptions)) { + void Reflect.get(mergedOptions, key, mergedOptions) + } + const userState = tableOptions.state if (userState) { for (const key in userState) { @@ -98,9 +99,7 @@ export function createTable< } untrack(() => { - table.setOptions((prev) => { - return mergeProps(prev, mergedOptions) as TableOptions - }) + table.setOptions(() => mergedOptions as TableOptions) }) }) diff --git a/packages/solid-table/src/createTableHook.tsx b/packages/solid-table/src/createTableHook.tsx index f3f37579ce..4c0e2832c9 100644 --- a/packages/solid-table/src/createTableHook.tsx +++ b/packages/solid-table/src/createTableHook.tsx @@ -1,7 +1,8 @@ import { createColumnHelper as coreCreateColumnHelper } from '@tanstack/table-core' -import { createContext, mergeProps, useContext } from 'solid-js' +import { createContext, useContext } from 'solid-js' import { createTable } from './createTable' import { FlexRender } from './FlexRender' +import { mergeOptionSources } from './merge-options' import type { SolidTable } from './createTable' import type { Component, JSXElement } from 'solid-js' import type { @@ -816,7 +817,7 @@ export function createTableHook< THeaderComponents > { // Merge default options with provided options (provided takes precedence) - const mergedProps = mergeProps(defaultTableOptions, tableOptions) + const mergedProps = mergeOptionSources(defaultTableOptions, tableOptions) const table = createTable( mergedProps as TableOptions, ) diff --git a/packages/solid-table/src/merge-options.ts b/packages/solid-table/src/merge-options.ts new file mode 100644 index 0000000000..a791b18348 --- /dev/null +++ b/packages/solid-table/src/merge-options.ts @@ -0,0 +1,93 @@ +function getMergedPrototype(sources: Array): object | null { + let fallback: object | null = Object.prototype + + for (let i = sources.length - 1; i >= 0; i--) { + const prototype = Object.getPrototypeOf(sources[i]!) + fallback = prototype + + // Adapter-owned option fragments are ordinary objects. Prefer a custom + // user prototype when one exists in another source. + if (prototype !== Object.prototype) { + return prototype + } + } + + return fallback +} + +/** + * Lazily merges reactive Solid option sources. + * + * Unlike `mergeProps`, an explicitly present `undefined` wins over an earlier + * value. This is required for clearing optional table options. The proxy also + * keeps accessor reads live and reflects symbols and the user source's + * prototype for the core option controller. + */ +export function mergeOptionSources>( + ...sources: T +): T[number] { + const accessors = new Map unknown>() + + const read = (key: PropertyKey) => { + for (let i = sources.length - 1; i >= 0; i--) { + const source = sources[i]! + if (Reflect.has(source, key)) { + return Reflect.get(source, key, source) + } + } + } + + return new Proxy(Object.create(null), { + defineProperty() { + return false + }, + deleteProperty() { + return false + }, + get(_target, key) { + return read(key) + }, + getOwnPropertyDescriptor(_target, key) { + let descriptor: PropertyDescriptor | undefined + for (let i = sources.length - 1; i >= 0; i--) { + descriptor = Reflect.getOwnPropertyDescriptor(sources[i]!, key) + if (descriptor) break + } + if (!descriptor) return undefined + + let get = accessors.get(key) + if (!get) { + get = () => read(key) + accessors.set(key, get) + } + + return { + configurable: true, + enumerable: descriptor.enumerable ?? false, + get, + } + }, + getPrototypeOf() { + return getMergedPrototype(sources) + }, + has(_target, key) { + return sources.some((source) => Reflect.has(source, key)) + }, + ownKeys() { + const keys = new Set() + for (const source of sources) { + for (const key of Reflect.ownKeys(source)) keys.add(key) + } + return [...keys] + }, + preventExtensions() { + return false + }, + set() { + return false + }, + setPrototypeOf() { + return false + }, + }) as T[number] +} diff --git a/packages/solid-table/src/reactivity.ts b/packages/solid-table/src/reactivity.ts index c71b6b081b..f16570e05d 100644 --- a/packages/solid-table/src/reactivity.ts +++ b/packages/solid-table/src/reactivity.ts @@ -51,15 +51,12 @@ function signalToWritableAtom( /** * Creates the table-core reactivity bindings used by the Solid adapter. * - * Table state atoms are backed by TanStack Store atoms. The options store stays - * framework-native because row-model APIs read `table.options` directly during - * render. Readonly table atoms bridge Store dependency tracking into Solid memos. + * Table state and option atoms bridge table-core reads into Solid signals. */ export function solidReactivity(owner: Owner): TableReactivityBindings { const subscriptions = new Set() return { - createOptionsStore: true, wrapExternalAtoms: true, addSubscription: (subscription) => { subscriptions.add(subscription) @@ -70,10 +67,16 @@ export function solidReactivity(owner: Owner): TableReactivityBindings { }, schedule: (fn) => queueMicrotask(() => fn()), createReadonlyAtom: (fn: () => T, options?: TableAtomOptions) => { - const signal = createMemo(() => fn(), { - equals: options?.compare, - name: options?.debugName, - }) + const signal = runWithOwner(owner, () => + createMemo( + () => fn(), + undefined, + { + ...(options?.compare ? { equals: options.compare } : {}), + name: options?.debugName, + }, + ), + )! return signalToReadonlyAtom(signal, owner) }, createWritableAtom: ( @@ -81,7 +84,7 @@ export function solidReactivity(owner: Owner): TableReactivityBindings { options?: TableAtomOptions, ): Atom => { const writableSignal = createSignal(value, { - equals: options?.compare, + ...(options?.compare ? { equals: options.compare } : {}), name: options?.debugName, }) return signalToWritableAtom(writableSignal, owner) diff --git a/packages/solid-table/tests/unit/adapterReactivity.test.ts b/packages/solid-table/tests/unit/adapterReactivity.test.ts index a07f574d7b..543564e7a5 100644 --- a/packages/solid-table/tests/unit/adapterReactivity.test.ts +++ b/packages/solid-table/tests/unit/adapterReactivity.test.ts @@ -300,4 +300,53 @@ describe('Solid adapter lifecycle and option ownership', () => { dispose() }) }) + + test('an existing option can become undefined without falling back to its prior value', () => { + createRoot((dispose) => { + const [enableRowSelection, setEnableRowSelection] = createSignal< + boolean | undefined + >(false) + const [customOption, setCustomOption] = createSignal('first') + const customSymbol = Symbol('custom-option') + const prototype = { inheritedOption: 'from-prototype' } + const options = Object.create( + prototype, + Object.getOwnPropertyDescriptors({ + data: [{ id: '1', title: 'Title' }], + columns: [idColumn, titleColumn], + features: stockFeatures, + getRowId: (row: Data) => row.id, + [customSymbol]: 'symbol-value', + get enableRowSelection() { + return enableRowSelection() + }, + get customOption() { + return customOption() + }, + }), + ) + const table = createTable(options) + + expect(table.options.enableRowSelection).toBe(false) + expect(table.getRowModel().rows[0]!.getCanSelect()).toBe(false) + expect((table.options as any)[customSymbol]).toBe('symbol-value') + expect((table.options as any).customOption).toBe('first') + expect( + Object.getOwnPropertyDescriptor(table.options, 'customOption'), + ).toMatchObject({ + value: 'first', + writable: false, + }) + + setEnableRowSelection(undefined) + setCustomOption('second') + + expect(table.options.enableRowSelection).toBeUndefined() + expect(table.optionAtoms.enableRowSelection!.get()).toBeUndefined() + expect(table.getRowModel().rows[0]!.getCanSelect()).toBe(true) + expect((table.options as any).customOption).toBe('second') + + dispose() + }) + }) }) diff --git a/packages/solid-table/tests/unit/reactivity.test.ts b/packages/solid-table/tests/unit/reactivity.test.ts index a1a3233707..280e9cfb09 100644 --- a/packages/solid-table/tests/unit/reactivity.test.ts +++ b/packages/solid-table/tests/unit/reactivity.test.ts @@ -63,6 +63,57 @@ describe('solidReactivity', () => { dispose() }) }) + + test('readonly atoms pass their comparator to Solid createMemo', () => { + createRoot((dispose) => { + const owner = getOwner()! + const reactivity = solidReactivity(owner) + const count = reactivity.createWritableAtom(0) + const parity = reactivity.createReadonlyAtom( + () => ({ even: count.get() % 2 === 0 }), + { + compare: (previous, next) => previous.even === next.even, + debugName: 'parity', + }, + ) + + const initial = parity.get() + count.set(2) + expect(parity.get()).toBe(initial) + + count.set(3) + expect(parity.get()).not.toBe(initial) + dispose() + }) + }) + + test('atoms retain Solid identity equality when no comparator is provided', () => { + let dispose!: () => void + const { captor, count } = createRoot((rootDispose) => { + dispose = rootDispose + const owner = getOwner()! + const reactivity = solidReactivity(owner) + const count = reactivity.createWritableAtom(0) + const parity = reactivity.createReadonlyAtom(() => count.get() % 2, { + debugName: 'parity', + }) + const captor = vi.fn<(value: number) => void>() + + createEffect(() => captor(parity.get())) + + return { captor, count } + }) + + count.set(2) + expect(captor.mock.calls).toEqual([[0]]) + + count.set(3) + expect(captor.mock.calls).toEqual([[0], [1]]) + + count.set(3) + expect(captor.mock.calls).toEqual([[0], [1]]) + dispose() + }) }) describe('Solid table reactivity integration', () => { diff --git a/packages/svelte-table/src/createTable.svelte.ts b/packages/svelte-table/src/createTable.svelte.ts index fb9d2131bf..cfe3a9ce77 100644 --- a/packages/svelte-table/src/createTable.svelte.ts +++ b/packages/svelte-table/src/createTable.svelte.ts @@ -90,9 +90,16 @@ export function createTable< const nextOptions = flatMerge(mergedOptions) const state = nextOptions.state as Record | undefined if (state) { + const resolvedState: Record = {} for (const key in state) { - void state[key] + resolvedState[key] = state[key] } + Object.defineProperty(nextOptions, 'state', { + configurable: true, + enumerable: true, + value: resolvedState, + writable: true, + }) } untrack(() => { diff --git a/packages/svelte-table/src/merge-objects.ts b/packages/svelte-table/src/merge-objects.ts index 196dd075da..9870cddbc0 100644 --- a/packages/svelte-table/src/merge-objects.ts +++ b/packages/svelte-table/src/merge-objects.ts @@ -16,32 +16,72 @@ export function mergeObjects( source3: W, ): T & U & V & W export function mergeObjects(...sources: any): any { - const target = {} - for (let source of sources) { - if (typeof source === 'function') source = source() - if (source) { - const descriptors = Object.getOwnPropertyDescriptors(source) - for (const key in descriptors) { - if (key in target) continue - Object.defineProperty(target, key, { - enumerable: true, - get() { - for (let i = sources.length - 1; i >= 0; i--) { - let v, - s = sources[i] - if (typeof s === 'function') s = s() - // eslint-disable-next-line prefer-const - v = (s || {})[key] - if (v !== undefined) return v - } - }, - }) + const target = Object.create(getMergedPrototype(sources)) + const keys = new Set() + + for (const unresolvedSource of sources) { + const source = resolveSource(unresolvedSource) + if (source == null) continue + for (const key of Reflect.ownKeys(source)) keys.add(key) + } + + for (const key of keys) { + let enumerable = false + for (let i = sources.length - 1; i >= 0; i--) { + const source = resolveSource(sources[i]) + const descriptor = + source == null + ? undefined + : Reflect.getOwnPropertyDescriptor(source, key) + if (descriptor) { + enumerable = descriptor.enumerable ?? false + break } } + + Object.defineProperty(target, key, { + configurable: true, + enumerable, + get() { + for (let i = sources.length - 1; i >= 0; i--) { + const source = resolveSource(sources[i]) + if (source != null && Reflect.has(source, key)) { + return Reflect.get(source, key, source) + } + } + }, + }) } + return target } +function resolveSource(source: any) { + return typeof source === 'function' ? source() : source +} + +function getMergedPrototype(sources: Array): object | null { + let fallback: object | null = Object.prototype + + for (let i = sources.length - 1; i >= 0; i--) { + const source = resolveSource(sources[i]) + if ( + (typeof source !== 'object' && typeof source !== 'function') || + source === null + ) { + continue + } + + const prototype = Object.getPrototypeOf(source) + fallback = prototype + if (prototype !== Object.prototype) { + return prototype + } + } + + return fallback +} + /** * Merges objects together by eagerly resolving all values into a flat object. * @@ -50,7 +90,7 @@ export function mergeObjects(...sources: any): any { * accumulation that causes O(N) lookups when the result is repeatedly passed * back as a source in subsequent merges (e.g., inside `$effect.pre` loops). * - * Later sources take precedence; `undefined` values do not override. + * Later sources take precedence, including an explicitly present `undefined`. * * @see https://github.com/TanStack/table/issues/6235 */ @@ -64,15 +104,21 @@ export function flatMerge( source3: W, ): T & U & V & W export function flatMerge(...sources: any): any { - const result: Record = {} - for (let source of sources) { - if (typeof source === 'function') source = source() - if (!source) continue + const result = Object.create(getMergedPrototype(sources)) as Record< + PropertyKey, + unknown + > + for (const unresolvedSource of sources) { + const source = resolveSource(unresolvedSource) + if (source == null) continue for (const key of Reflect.ownKeys(source)) { - const value = (source as Record)[key] - if (value !== undefined) { - result[key as string] = value - } + const descriptor = Reflect.getOwnPropertyDescriptor(source, key) + Object.defineProperty(result, key, { + configurable: true, + enumerable: descriptor?.enumerable ?? true, + value: Reflect.get(source, key, source), + writable: true, + }) } } return result diff --git a/packages/svelte-table/src/reactivity.svelte.ts b/packages/svelte-table/src/reactivity.svelte.ts index a251a7452e..bcea1e6d66 100644 --- a/packages/svelte-table/src/reactivity.svelte.ts +++ b/packages/svelte-table/src/reactivity.svelte.ts @@ -1,4 +1,5 @@ import { untrack } from 'svelte' +import { createSubscriber } from 'svelte/reactivity' import { batch, createAtom } from '@tanstack/svelte-store' import type { TableAtomOptions, @@ -6,8 +7,6 @@ import type { } from '@tanstack/table-core/reactivity' import type { Atom, Observer, ReadonlyAtom } from '@tanstack/svelte-store' -const optionsStoreDebugName = 'table/optionsStore' - function observerToCallback( observerOrNext: Observer | ((value: T) => void), ): (value: T) => void { @@ -16,50 +15,39 @@ function observerToCallback( : (value) => observerOrNext.next?.(value) } -function subscribeToRune( - getValue: () => T, - observerOrNext: Observer | ((value: T) => void), -) { - const callback = observerToCallback(observerOrNext) - const unsubscribe = $effect.root(() => { - $effect(() => { - const value = getValue() - untrack(() => callback(value)) - }) - }) - - return { unsubscribe } -} - -function createRuneWritableAtom(initialValue: T): Atom { - let value = $state(initialValue) +function createStableReadonlyAtom( + fn: () => T, + compare: (previous: T, next: T) => boolean, +): ReadonlyAtom { + let stableBox: { value: T } | undefined + const boxedAtom = createAtom( + () => { + const nextValue = fn() + if (!stableBox || !compare(stableBox.value, nextValue)) { + stableBox = { value: nextValue } + } + return stableBox + }, + ) return { - set: (updater: T | ((prevVal: T) => T)) => { - value = - typeof updater === 'function' - ? (updater as (prevVal: T) => T)(value) - : updater - }, - get: () => value, + get: () => boxedAtom.get().value, subscribe: ((observerOrNext: Observer | ((value: T) => void)) => { - return subscribeToRune(() => value, observerOrNext) - }) as Atom['subscribe'], + const callback = observerToCallback(observerOrNext) + return boxedAtom.subscribe((box) => callback(box.value)) + }) as ReadonlyAtom['subscribe'], } } /** * Creates the table-core reactivity bindings used by the Svelte adapter. * - * Table state atoms are backed by TanStack Store atoms. The options store stays - * framework-native because row-model APIs read `table.options` directly during - * render. Readonly table atoms bridge Store dependency tracking into + * Table state and option atoms bridge Store dependency tracking into * `$derived.by`, so their `.get()` methods participate in Svelte dependency * tracking when called in templates, `$derived`, or `$effect`. */ export function svelteReactivity(): TableReactivityBindings { return { - createOptionsStore: true, wrapExternalAtoms: false, addSubscription: () => { throw new Error( @@ -73,35 +61,25 @@ export function svelteReactivity(): TableReactivityBindings { }, schedule: (fn) => queueMicrotask(() => fn()), createReadonlyAtom: (fn: () => T, _options?: TableAtomOptions) => { - const storeAtom = createAtom(() => fn(), { - compare: _options?.compare, - }) - let version = $state(0) - - $effect(() => { + const storeAtom = createStableReadonlyAtom( + fn, + _options?.compare ?? Object.is, + ) + const trackStore = createSubscriber((update) => { const subscription = storeAtom.subscribe(() => { - version += 1 + update() }) return () => subscription.unsubscribe() }) - const value = $derived.by(() => { - version - return storeAtom.get() - }) - return { get: () => { - // Both reads are load-bearing: the Store read preserves dependency - // tracking between table atoms, while touching `value` registers the - // current Svelte reactive scope with the rune-backed bridge. - const currentValue = storeAtom.get() - value - return currentValue + trackStore() + return storeAtom.get() }, subscribe: ((observerOrNext: Observer | ((value: T) => void)) => { - return subscribeToRune(() => value, observerOrNext) + return storeAtom.subscribe(observerToCallback(observerOrNext)) }) as ReadonlyAtom['subscribe'], } }, @@ -109,10 +87,6 @@ export function svelteReactivity(): TableReactivityBindings { initialValue: T, _options?: TableAtomOptions, ): Atom => { - if (_options?.debugName === optionsStoreDebugName) { - return createRuneWritableAtom(initialValue) - } - return createAtom(initialValue, { compare: _options?.compare, }) diff --git a/packages/svelte-table/tests/adapter-lifecycle.test.ts b/packages/svelte-table/tests/adapter-lifecycle.test.ts index ac6d03bae5..e28e3116fb 100644 --- a/packages/svelte-table/tests/adapter-lifecycle.test.ts +++ b/packages/svelte-table/tests/adapter-lifecycle.test.ts @@ -110,6 +110,25 @@ describe('Svelte adapter lifecycle and reactive options', () => { ]) }) + test('an existing optional top-level option can be cleared to undefined', async () => { + render(ReactivityHarness) + + expect(outputText('Row selection option')).toBe('true') + expect(outputText('First row can be selected')).toBe('true') + + await fireEvent.click( + screen.getByRole('button', { name: 'Disable row selection' }), + ) + expect(outputText('Row selection option')).toBe('false') + expect(outputText('First row can be selected')).toBe('false') + + await fireEvent.click( + screen.getByRole('button', { name: 'Clear row-selection option' }), + ) + expect(outputText('Row selection option')).toBe('undefined') + expect(outputText('First row can be selected')).toBe('true') + }) + test('table APIs use the latest rune-backed option callback', async () => { const firstHandler = vi.fn>() const secondHandler = vi.fn>() diff --git a/packages/svelte-table/tests/fixtures/ReactivityHarness.svelte b/packages/svelte-table/tests/fixtures/ReactivityHarness.svelte index 1bfc7834e4..65573aac3c 100644 --- a/packages/svelte-table/tests/fixtures/ReactivityHarness.svelte +++ b/packages/svelte-table/tests/fixtures/ReactivityHarness.svelte @@ -42,7 +42,7 @@ { id: '2', title: 'Two' }, ]) let columns = $state>>([idColumn]) - let enableRowSelection = $state(true) + let enableRowSelection = $state(true) let controlledState = $state<{ rowSelection?: RowSelectionState }>({ rowSelection: { 1: true }, }) @@ -92,6 +92,14 @@ data = [{ id: '4', title: 'Final' }] columns = [titleColumn] } + + function disableRowSelection() { + enableRowSelection = false + } + + function clearRowSelectionOption() { + enableRowSelection = undefined + } {JSON.stringify(selection)} @@ -117,9 +125,14 @@ {String(table.getRowModel().rows[0]?.getCanSelect() ?? false)} +{String(table.options.enableRowSelection)} + + diff --git a/packages/svelte-table/tests/merge-objects.test.ts b/packages/svelte-table/tests/merge-objects.test.ts new file mode 100644 index 0000000000..75c69d3d38 --- /dev/null +++ b/packages/svelte-table/tests/merge-objects.test.ts @@ -0,0 +1,48 @@ +import { describe, expect, test } from 'vitest' +import { flatMerge, mergeObjects } from '../src/merge-objects' + +describe('Svelte option source merging', () => { + test('preserves explicit undefined, symbols, accessors, and a custom prototype', () => { + const customSymbol = Symbol('custom-option') + const prototype = { inheritedOption: 'from-prototype' } + let accessorValue = 'first' + const source = Object.create(prototype) + + Object.defineProperties(source, { + optional: { + configurable: true, + enumerable: true, + value: undefined, + writable: true, + }, + customOption: { + configurable: true, + enumerable: true, + get: () => accessorValue, + }, + [customSymbol]: { + configurable: true, + enumerable: false, + value: 'symbol-value', + }, + }) + + const merged = mergeObjects({ optional: 'fallback' }, source) + + expect(merged.optional).toBeUndefined() + expect(Object.getPrototypeOf(merged)).toBe(prototype) + expect(merged[customSymbol]).toBe('symbol-value') + expect( + Object.getOwnPropertyDescriptor(merged, 'customOption')?.get, + ).toEqual(expect.any(Function)) + + accessorValue = 'second' + expect(merged.customOption).toBe('second') + + const snapshot = flatMerge({ optional: 'fallback' }, source) + expect(snapshot.optional).toBeUndefined() + expect(Object.getPrototypeOf(snapshot)).toBe(prototype) + expect(snapshot[customSymbol]).toBe('symbol-value') + expect(snapshot.customOption).toBe('second') + }) +}) diff --git a/packages/table-core/skills/custom-features/SKILL.md b/packages/table-core/skills/custom-features/SKILL.md index 80737018c4..07ec3b4c43 100644 --- a/packages/table-core/skills/custom-features/SKILL.md +++ b/packages/table-core/skills/custom-features/SKILL.md @@ -226,7 +226,7 @@ export const features = tableFeatures({ densityFeature }) - Table API `fn` receives declared arguments. Prototype API `fn` receives the current object first. - Initialize table-owned mutable data in `initTableInstanceData`, not `constructTableAPIs`; all feature data is initialized before any table API is assigned. - Clear transient table-owned data in `resetTableInstanceData`. Reset state slices through atoms/updaters, and do not expect this hook to reset externally controlled state. -- Add `memoDeps` only for a genuinely derived method. Prototype methods are shared and must not close over per-object mutable data. +- Register a zero-argument derived method as `{ computed: () => result, compare? }` and read its atoms/options inside the computation so native reactivity tracks them. Prototype computed entries receive the current object as `self`. Keep parameterized methods as `{ fn }`; shared prototype methods must not close over per-object mutable data. - There are no `assignColumnAPIs`, `assignRowAPIs`, `assignCellAPIs`, or `assignHeaderAPIs`; use `assignPrototypeAPIs` in the matching hook. - Do not mutate constructed instances ad hoc or use a feature for renderer-only callbacks that belong in meta. diff --git a/packages/table-core/src/core/cells/coreCellsFeature.ts b/packages/table-core/src/core/cells/coreCellsFeature.ts index e79384620d..8b95fe9608 100644 --- a/packages/table-core/src/core/cells/coreCellsFeature.ts +++ b/packages/table-core/src/core/cells/coreCellsFeature.ts @@ -19,8 +19,7 @@ export const coreCellsFeature: TableFeature = { fn: (cell) => cell_renderValue(cell), }, cell_getContext: { - fn: (cell) => cell_getContext(cell), - memoDeps: (cell) => [cell], + computed: (cell) => cell_getContext(cell), }, }) }, diff --git a/packages/table-core/src/core/columns/coreColumnsFeature.ts b/packages/table-core/src/core/columns/coreColumnsFeature.ts index f21a2b3bfc..69f51ad50f 100644 --- a/packages/table-core/src/core/columns/coreColumnsFeature.ts +++ b/packages/table-core/src/core/columns/coreColumnsFeature.ts @@ -19,17 +19,19 @@ export const coreColumnsFeature: TableFeature = { assignColumnPrototype: (prototype, table) => { assignPrototypeAPIs('coreColumnsFeature', prototype, table, { column_getFlatColumns: { - fn: (column) => column_getFlatColumns(column), - memoDeps: (column) => [column.table.options.columns], + computed: (column) => { + void column.table.options.columns + return column_getFlatColumns(column) + }, }, column_getLeafColumns: { - fn: (column) => column_getLeafColumns(column), - memoDeps: (column) => [ - column.table.atoms.columnOrder?.get(), - column.table.atoms.grouping?.get(), - column.table.options.columns, - column.table.options.groupedColumnMode, - ], + computed: (column) => { + void column.table.atoms.columnOrder?.get() + void column.table.atoms.grouping?.get() + void column.table.options.columns + void column.table.options.groupedColumnMode + return column_getLeafColumns(column) + }, }, }) }, @@ -37,33 +39,22 @@ export const coreColumnsFeature: TableFeature = { constructTableAPIs: (table) => { assignTableAPIs('coreColumnsFeature', table, { table_getDefaultColumnDef: { - fn: () => table_getDefaultColumnDef(table), - memoDeps: () => [table.options.defaultColumn], + computed: () => table_getDefaultColumnDef(table), }, table_getAllColumns: { - fn: () => table_getAllColumns(table), - memoDeps: () => [table.options.columns], + computed: () => table_getAllColumns(table), }, table_getAllFlatColumns: { - fn: () => table_getAllFlatColumns(table), - memoDeps: () => [table.options.columns], + computed: () => table_getAllFlatColumns(table), }, table_getAllFlatColumnsById: { - fn: () => table_getAllFlatColumnsById(table), - memoDeps: () => [table.options.columns], + computed: () => table_getAllFlatColumnsById(table), }, table_getAllLeafColumns: { - fn: () => table_getAllLeafColumns(table), - memoDeps: () => [ - table.atoms.columnOrder?.get(), - table.atoms.grouping?.get(), - table.options.columns, - table.options.groupedColumnMode, - ], + computed: () => table_getAllLeafColumns(table), }, table_getAllLeafColumnsById: { - fn: () => table_getAllLeafColumnsById(table), - memoDeps: () => [table.getAllLeafColumns()], + computed: () => table_getAllLeafColumnsById(table), }, table_getColumn: { fn: (columnId) => table_getColumn(table, columnId), diff --git a/packages/table-core/src/core/headers/coreHeadersFeature.ts b/packages/table-core/src/core/headers/coreHeadersFeature.ts index b8c7a214e4..dd1328263f 100644 --- a/packages/table-core/src/core/headers/coreHeadersFeature.ts +++ b/packages/table-core/src/core/headers/coreHeadersFeature.ts @@ -16,12 +16,16 @@ export const coreHeadersFeature: TableFeature = { assignHeaderPrototype: (prototype, table) => { assignPrototypeAPIs('coreHeadersFeature', prototype, table, { header_getLeafHeaders: { - fn: (header) => header_getLeafHeaders(header), - memoDeps: (header) => [header.column.table.options.columns], + computed: (header) => { + void header.column.table.options.columns + return header_getLeafHeaders(header) + }, }, header_getContext: { - fn: (header) => header_getContext(header), - memoDeps: (header) => [header.column.table.options.columns], + computed: (header) => { + void header.column.table.options.columns + return header_getContext(header) + }, }, }) }, @@ -29,27 +33,16 @@ export const coreHeadersFeature: TableFeature = { constructTableAPIs: (table) => { assignTableAPIs('coreHeadersFeature', table, { table_getHeaderGroups: { - fn: () => table_getHeaderGroups(table), - memoDeps: () => [ - table.options.columns, - table.atoms.columnOrder?.get(), - table.atoms.grouping?.get(), - table.atoms.columnPinning?.get(), - table.atoms.columnVisibility?.get(), - table.options.groupedColumnMode, - ], + computed: () => table_getHeaderGroups(table), }, table_getFooterGroups: { - fn: () => table_getFooterGroups(table), - memoDeps: () => [table.getHeaderGroups()], + computed: () => table_getFooterGroups(table), }, table_getFlatHeaders: { - fn: () => table_getFlatHeaders(table), - memoDeps: () => [table.getHeaderGroups()], + computed: () => table_getFlatHeaders(table), }, table_getLeafHeaders: { - fn: () => table_getLeafHeaders(table), - memoDeps: () => [table.getHeaderGroups()], + computed: () => table_getLeafHeaders(table), }, }) }, diff --git a/packages/table-core/src/core/reactivity/coreReactivityFeature.types.ts b/packages/table-core/src/core/reactivity/coreReactivityFeature.types.ts index 045d0dd90a..6d5df67dda 100644 --- a/packages/table-core/src/core/reactivity/coreReactivityFeature.types.ts +++ b/packages/table-core/src/core/reactivity/coreReactivityFeature.types.ts @@ -10,6 +10,14 @@ export interface TableAtomOptions extends AtomOptions { * A debug name for the atom, useful for debugging. */ debugName: string + /** + * Selects an internal render-phase behavior. `memo` retains native computed + * caching between reads; `staged` makes a writable value live to the current + * render while deferring its reactive publication until commit. + * + * @internal + */ + mode?: 'memo' | 'staged' } /** @@ -20,15 +28,30 @@ export interface TableAtomOptions extends AtomOptions { * scheduling primitives. */ export interface TableReactivityBindings { - createOptionsStore: boolean wrapExternalAtoms: boolean + /** + * Advances memo-mode readonly atoms to a newly staged options snapshot. + * + * Render-phase adapters return a token that must only be published after the + * corresponding host render commits. + * + * @internal + */ + stage?: () => number + /** + * Returns the token for the currently staged options snapshot without + * creating a new stage. + * + * @internal + */ + getStageToken?: () => number /** * Invalidates readonly atoms whose compute reads non-reactive inputs (plain * options). Render-phase adapters call this after publishing captured * controlled state from a host commit, including when no base atom changed, * so controlled ownership changes still reach subscribers. */ - commit?: () => void + commit?: (token?: number) => void addSubscription: (subscription: Subscription) => void /** * Creates a writable atom with an initial value. diff --git a/packages/table-core/src/core/reactivity/createStableStoreReadonlyAtom.ts b/packages/table-core/src/core/reactivity/createStableStoreReadonlyAtom.ts new file mode 100644 index 0000000000..6e6191a26c --- /dev/null +++ b/packages/table-core/src/core/reactivity/createStableStoreReadonlyAtom.ts @@ -0,0 +1,51 @@ +import type { AtomOptions, Observer, ReadonlyAtom } from '@tanstack/store' + +type StoreReadonlyAtomFactory = ( + getValue: (previous?: T) => T, + options?: AtomOptions, +) => ReadonlyAtom + +/** + * Creates a TanStack Store computed whose equality also works for `undefined`. + * + * Store uses `undefined` as its uninitialized computed snapshot, so a computed + * that legitimately returns `undefined` is otherwise reported as changed on + * every dependency invalidation. Keeping the compared value inside a stable + * box gives Store a distinct initialized snapshot without changing the public + * atom value. + */ +export function createStableStoreReadonlyAtom( + createAtom: StoreReadonlyAtomFactory, + fn: () => T, + options?: AtomOptions, +): ReadonlyAtom { + const compare = options?.compare ?? Object.is + let stableBox: { value: T } | undefined + + const boxedAtom = createAtom( + () => { + const nextValue = fn() + + if (!stableBox || !compare(stableBox.value, nextValue)) { + stableBox = { value: nextValue } + } + + return stableBox + }, + ) + + return { + get: () => boxedAtom.get().value, + subscribe: (( + observer: Observer | ((value: T) => void), + ) => { + return boxedAtom.subscribe((box) => { + if (typeof observer === 'function') { + observer(box.value) + } else { + observer.next?.(box.value) + } + }) + }) as ReadonlyAtom['subscribe'], + } +} diff --git a/packages/table-core/src/core/reactivity/renderPhaseReactivity.ts b/packages/table-core/src/core/reactivity/renderPhaseReactivity.ts index 42b30a20f7..48871ccbef 100644 --- a/packages/table-core/src/core/reactivity/renderPhaseReactivity.ts +++ b/packages/table-core/src/core/reactivity/renderPhaseReactivity.ts @@ -1,4 +1,5 @@ -import type { Atom, AtomOptions, ReadonlyAtom } from '@tanstack/store' +import { createStableStoreReadonlyAtom } from './createStableStoreReadonlyAtom' +import type { Atom, AtomOptions, Observer, ReadonlyAtom } from '@tanstack/store' import type { TableAtomOptions, TableReactivityBindings, @@ -9,7 +10,9 @@ import type { * during the host framework's render phase, with a guaranteed `commit` hook. */ export interface RenderPhaseReactivityBindings extends TableReactivityBindings { - commit: () => void + stage: () => number + getStageToken: () => number + commit: (token?: number) => void } /** @@ -40,14 +43,12 @@ export interface RenderPhaseReactivityPrimitives { * component render, where store notifications must not fire until the host * commits. * - * Readonly atoms are exposed as live facades. `get()` re-evaluates the - * resolver against the options of the render in progress — a normal computed - * cannot know that plain `options.state` changed — and caches the result - * through the configured comparator so external-store consumers (e.g. React's - * `useSyncExternalStore`) see referentially stable snapshots. `subscribe()` - * goes through a hidden computed that tracks the resolver's real atom - * dependencies plus a commit version, so subscribers are invalidated by - * actual reactive writes and by the adapter's post-commit publication. + * Regular readonly atoms are exposed as live facades. `get()` re-evaluates the + * resolver against the options of the render in progress and caches the result + * through the configured comparator. Memo-mode atoms use a native computed for + * cached table APIs. A materially changed staged options source rotates those + * computeds without notifying subscribers; `subscribe()` observes the current + * computed only after the matching host commit. * * @example * ```ts @@ -62,10 +63,14 @@ export function renderPhaseReactivity( ): RenderPhaseReactivityBindings { const { createAtom, batch } = primitives const commitAtom = createAtom(0) + let stagedVersion = 0 + let committedVersion = 0 + const publishStagedAtoms = new Set<() => void>() return { - createOptionsStore: false, wrapExternalAtoms: false, + stage: () => ++stagedVersion, + getStageToken: () => stagedVersion, addSubscription: () => { throw new Error( 'Feature not supported in current reactivity implementation', @@ -81,6 +86,42 @@ export function renderPhaseReactivity( untrack: (fn) => fn(), createReadonlyAtom: (fn: () => T, atomOptions?: TableAtomOptions) => { const compare = atomOptions?.compare ?? Object.is + + if (atomOptions?.mode === 'memo') { + let memoVersion = -1 + let memoAtom: ReadonlyAtom | undefined + + const createMemoAtom = () => + createStableStoreReadonlyAtom(createAtom, fn, { compare }) + + const getMemoAtom = () => { + if (!memoAtom || memoVersion !== stagedVersion) { + memoVersion = stagedVersion + memoAtom = createMemoAtom() + } + + return memoAtom + } + + const readMemo = () => getMemoAtom().get() + + // Staging rotates the memo used by render reads without publishing + // during render. Subscribers observe it only after the host commit. + const reactiveAtom = createStableStoreReadonlyAtom( + createAtom, + () => { + commitAtom.get() + return readMemo() + }, + { compare }, + ) + + return { + get: readMemo, + subscribe: reactiveAtom.subscribe.bind(reactiveAtom), + } + } + let hasSnapshot = false let snapshot: T @@ -95,7 +136,8 @@ export function renderPhaseReactivity( return snapshot } - const reactiveAtom = createAtom( + const reactiveAtom = createStableStoreReadonlyAtom( + createAtom, () => { commitAtom.get() return getSnapshot() @@ -109,12 +151,79 @@ export function renderPhaseReactivity( } }, createWritableAtom: (value: T, atomOptions?: TableAtomOptions) => { + if (atomOptions?.mode === 'staged') { + const compare = atomOptions.compare ?? Object.is + const publishedVersion = createAtom(0) + let currentValue = value + let dirty = false + + const publish = () => { + if (!dirty) { + return + } + + dirty = false + publishedVersion.set((version) => version + 1) + } + + publishStagedAtoms.add(publish) + + return { + get: () => { + // The value itself is live for the render in progress. Reactive + // consumers only depend on the version published by commit(). + publishedVersion.get() + return currentValue + }, + set: (updater: T | ((previous: T) => T)) => { + const nextValue = + typeof updater === 'function' + ? (updater as (previous: T) => T)(currentValue) + : updater + + if (!compare(currentValue, nextValue)) { + currentValue = nextValue + dirty = true + } + }, + subscribe: (( + observer: Observer | ((value: T) => void), + ) => { + let previous = currentValue + return publishedVersion.subscribe(() => { + const nextValue = currentValue + if (!compare(previous, nextValue)) { + previous = nextValue + if (typeof observer === 'function') { + observer(nextValue) + } else { + observer.next?.(nextValue) + } + } + }) + }) as Atom['subscribe'], + } + } + return createAtom(value, { compare: atomOptions?.compare, }) }, - commit: () => { - commitAtom.set((version) => version + 1) + commit: (token = stagedVersion) => { + // Publish only the newest staged render. Older effects and commits for a + // token that was superseded by an abandoned render must not publish the + // newer staged values under the wrong token. + if (token !== stagedVersion || token <= committedVersion) { + return + } + + committedVersion = token + batch(() => { + for (const publish of publishStagedAtoms) { + publish() + } + commitAtom.set(() => token) + }) }, } } diff --git a/packages/table-core/src/core/row-models/createCoreRowModel.ts b/packages/table-core/src/core/row-models/createCoreRowModel.ts index 99ab2d60ca..e79a057808 100644 --- a/packages/table-core/src/core/row-models/createCoreRowModel.ts +++ b/packages/table-core/src/core/row-models/createCoreRowModel.ts @@ -1,4 +1,5 @@ import { constructRow } from '../rows/constructRow' +import { row_setSubRows } from '../rows/subRowsTracking' import { makeObjectMap, tableMemo } from '../../utils' import { table_autoResetCellSelection } from '../../features/cell-selection/cellSelectionFeature.utils' import { table_autoResetPageIndex } from '../../features/row-pagination/rowPaginationFeature.utils' @@ -24,8 +25,20 @@ export function createCoreRowModel< feature: 'coreRowModelsFeature', table, fnName: 'table.getCoreRowModel', - memoDeps: () => [table.options.data], - fn: () => _createCoreRowModel(table, table.options.data), + fn: () => { + // `data` was the core row model's sole memo dependency before native + // computeds. Read that slice reactively, then take the other row + // construction callbacks from the already-installed options source. + // This preserves the established contract that a render-created but + // semantically unchanged `getRowId` callback does not rebuild every + // row, while a later data change still uses the latest callbacks. + const data = table.options.data + const { getRowId, getSubRows } = table._reactivity.untrack(() => ({ + getRowId: table.options.getRowId, + getSubRows: table.options.getSubRows, + })) + return _createCoreRowModel(table, data, getRowId, getSubRows) + }, onAfterUpdate: () => { table_autoResetPageIndex(table) // this memo recomputes only when `options.data` changes, which is @@ -40,6 +53,19 @@ function accessRows( table: Table_Internal, rowModel: RowModel, originalRows: ReadonlyArray, + getRowId: + | (( + originalRow: TData, + index: number, + parent?: Row, + ) => string) + | undefined, + getSubRows: + | (( + originalRow: TData, + index: number, + ) => ReadonlyArray | undefined) + | undefined, depth = 0, parentRow?: Row, ): Array> { @@ -50,7 +76,8 @@ function accessRows( // Make the row const row = constructRow( table, - table.getRowId(originalRow, i, parentRow), + getRowId?.(originalRow, i, parentRow) ?? + (parentRow ? `${parentRow.id}.${i}` : String(i)), originalRow, i, depth, @@ -66,17 +93,22 @@ function accessRows( rows.push(row) // Get the original subrows - if (table.options.getSubRows) { - row.originalSubRows = table.options.getSubRows(originalRow, i) + if (getSubRows) { + row.originalSubRows = getSubRows(originalRow, i) // Then recursively access them if (row.originalSubRows?.length) { - row.subRows = accessRows( - table, - rowModel, - row.originalSubRows, - depth + 1, + row_setSubRows( row, + accessRows( + table, + rowModel, + row.originalSubRows, + getRowId, + getSubRows, + depth + 1, + row, + ), ) } } @@ -91,6 +123,19 @@ function _createCoreRowModel< >( table: Table_Internal, data: ReadonlyArray, + getRowId: + | (( + originalRow: TData, + index: number, + parent?: Row, + ) => string) + | undefined, + getSubRows: + | (( + originalRow: TData, + index: number, + ) => ReadonlyArray | undefined) + | undefined, ): { rows: Array> flatRows: Array> @@ -102,7 +147,7 @@ function _createCoreRowModel< rowsById: makeObjectMap(), } - rowModel.rows = accessRows(table, rowModel, data) + rowModel.rows = accessRows(table, rowModel, data, getRowId, getSubRows) return rowModel } diff --git a/packages/table-core/src/core/rows/coreRowsFeature.ts b/packages/table-core/src/core/rows/coreRowsFeature.ts index 5c96a05522..e8e8a04d0a 100644 --- a/packages/table-core/src/core/rows/coreRowsFeature.ts +++ b/packages/table-core/src/core/rows/coreRowsFeature.ts @@ -26,16 +26,13 @@ export const coreRowsFeature: TableFeature = { fn: (row) => row_getDisplayIndex(row), }, row_getAllCellsByColumnId: { - fn: (row) => row_getAllCellsByColumnId(row), - memoDeps: (row) => [row.getAllCells()], + computed: (row) => row_getAllCellsByColumnId(row), }, row_getAllCells: { - fn: (row) => row_getAllCells(row), - memoDeps: (row) => [row.table.getAllLeafColumns()], + computed: (row) => row_getAllCells(row), }, row_getLeafRows: { - fn: (row) => row_getLeafRows(row), - memoDeps: (row) => [row.subRows], + computed: (row) => row_getLeafRows(row), }, row_getParentRow: { fn: (row) => row_getParentRow(row), @@ -57,14 +54,7 @@ export const coreRowsFeature: TableFeature = { constructTableAPIs: (table) => { assignTableAPIs('coreRowsFeature', table, { table_getRowsInDisplayOrder: { - fn: () => table_getRowsInDisplayOrder(table), - memoDeps: () => [ - table.getPrePaginatedRowModel().rows, - table.options.paginateExpandedRows, - table.options.paginateExpandedRows === false - ? table.atoms.expanded?.get() - : undefined, - ], + computed: () => table_getRowsInDisplayOrder(table), }, table_getRowId: { fn: (originalRow, index, parent) => @@ -75,8 +65,7 @@ export const coreRowsFeature: TableFeature = { table_getRow(table, id, searchAll), }, table_getMaxSubRowDepth: { - fn: () => table_getMaxSubRowDepth(table), - memoDeps: () => [table.getCoreRowModel()], + computed: () => table_getMaxSubRowDepth(table), }, }) }, diff --git a/packages/table-core/src/core/rows/coreRowsFeature.utils.ts b/packages/table-core/src/core/rows/coreRowsFeature.utils.ts index f37ce79828..d6952b7411 100644 --- a/packages/table-core/src/core/rows/coreRowsFeature.utils.ts +++ b/packages/table-core/src/core/rows/coreRowsFeature.utils.ts @@ -1,5 +1,6 @@ import { flattenBy, hasOwn, makeObjectMap } from '../../utils' import { constructCell } from '../cells/constructCell' +import { row_getTrackedSubRows } from './subRowsTracking' import type { Table_Internal } from '../../types/Table' import type { RowData } from '../../types/type-utils' import type { TableFeatures } from '../../types/TableFeatures' @@ -164,7 +165,7 @@ export function row_getLeafRows< TFeatures extends TableFeatures, TData extends RowData, >(row: Row): Array> { - return flattenBy(row.subRows, (d) => d.subRows) + return flattenBy(row_getTrackedSubRows(row), row_getTrackedSubRows) } /** diff --git a/packages/table-core/src/core/rows/subRowsTracking.ts b/packages/table-core/src/core/rows/subRowsTracking.ts new file mode 100644 index 0000000000..22ad240e91 --- /dev/null +++ b/packages/table-core/src/core/rows/subRowsTracking.ts @@ -0,0 +1,87 @@ +import type { Atom } from '@tanstack/store' +import type { Row } from '../../types/Row' +import type { RowData } from '../../types/type-utils' +import type { TableFeatures } from '../../types/TableFeatures' + +interface SubRowsTrackingState { + current: unknown + versionAtom: Atom +} + +const subRowsTracking = new WeakMap() + +/** + * Reads a row's sub-rows while making replacement of that array observable to + * table computeds. + * + * Most row APIs never need to observe `subRows` directly, so the revision atom + * and accessor are installed only when a computed such as `getLeafRows` first + * asks for a tracked read. The accessor remains enumerable and preserves the + * public mutable `subRows` property while ensuring later direct assignments + * bump the revision atom. + * + * @internal + */ +export function row_getTrackedSubRows< + TFeatures extends TableFeatures, + TData extends RowData, +>( + row: Row, +): Array> { + const tracking = subRowsTracking.get(row) + + if (!tracking) { + const createdTracking: SubRowsTrackingState = { + current: row.subRows, + versionAtom: row.table._reactivity.createWritableAtom(0, { + debugName: `row/${row.id}/subRowsVersion`, + }), + } + subRowsTracking.set(row, createdTracking) + + Object.defineProperty(row, 'subRows', { + configurable: true, + enumerable: true, + get: () => { + createdTracking.versionAtom.get() + return createdTracking.current + }, + set: (next: Array>) => { + if (createdTracking.current === next) return + createdTracking.current = next + createdTracking.versionAtom.set((version) => version + 1) + }, + }) + + createdTracking.versionAtom.get() + return createdTracking.current as Array> + } + + tracking.versionAtom.get() + return tracking.current as Array> +} + +/** + * Replaces a row's sub-row array and publishes the change when the row has + * acquired a tracked sub-row reader. + * + * @internal + */ +export function row_setSubRows< + TFeatures extends TableFeatures, + TData extends RowData, +>( + row: Row, + subRows: Array>, +): void { + const tracking = subRowsTracking.get(row) + + if (!tracking) { + row.subRows = subRows + return + } + + if (tracking.current === subRows) return + tracking.current = subRows + tracking.versionAtom.set((version) => version + 1) +} diff --git a/packages/table-core/src/core/table/constructTable.ts b/packages/table-core/src/core/table/constructTable.ts index 100bafd7e7..e22b4478c5 100644 --- a/packages/table-core/src/core/table/constructTable.ts +++ b/packages/table-core/src/core/table/constructTable.ts @@ -1,8 +1,12 @@ import { shallow } from '@tanstack/store' import { coreFeatures } from '../coreFeatures' -import { cloneState, hasOwn } from '../../utils' +import { cloneState, functionalUpdate, hasOwn } from '../../utils' import { atomToStore } from '../reactivity/coreReactivityFeature.utils' import { table_syncExternalStateToBaseAtoms } from './coreTablesFeature.utils' +import { + createTableOptionAtoms, + getTableOptionsFromAtoms, +} from './tableOptionAtoms' import type { Atom } from '@tanstack/store' import type { RowData } from '../../types/type-utils' import type { TableFeature, TableFeatures } from '../../types/TableFeatures' @@ -79,7 +83,14 @@ export function constructTable< return Object.assign(obj, feature.getDefaultTableOptions?.(table)) }, {}) as TableOptions - const mergedOptions = { ...defaultOptions, ...tableOptions } + const mergedOptions = Object.create( + Object.getPrototypeOf(tableOptions), + Object.assign( + {}, + Object.getOwnPropertyDescriptors(defaultOptions), + Object.getOwnPropertyDescriptors(tableOptions), + ), + ) as TableOptions if (_reactivity.wrapExternalAtoms && mergedOptions.atoms) { for (const [atomKey, _atom] of Object.entries(mergedOptions.atoms)) { @@ -104,24 +115,35 @@ export function constructTable< } } - if (_reactivity.createOptionsStore) { - // @ts-ignore - direct set - table.optionsStore = _reactivity.createWritableAtom< - TableOptions - >(mergedOptions, { debugName: 'table/optionsStore' }) - Object.defineProperty(table, 'options', { - configurable: true, + const optionAtoms = createTableOptionAtoms( + mergedOptions, + _reactivity, + (key, updater) => { + table.setOptions((previous) => ({ + ...previous, + [key]: functionalUpdate( + updater, + Reflect.get(previous, key, previous), + ), + })) + }, + ) + const options = getTableOptionsFromAtoms(optionAtoms) + + Object.defineProperties(table, { + optionAtoms: { + configurable: false, enumerable: true, - get() { - return table.optionsStore!.get() - }, - set(value) { - table.optionsStore!.set(() => value) // or your real update shape - }, - }) - } else { - table.options = mergedOptions - } + value: optionAtoms, + writable: false, + }, + options: { + configurable: false, + enumerable: true, + value: options, + writable: false, + }, + }) table.initialState = getInitialTableState( table._features, @@ -134,6 +156,31 @@ export function constructTable< for (let i = 0; i < stateKeys.length; i++) { const key = stateKeys[i]! + const noControlledState = {} + const externalAtomOption = _reactivity.createReadonlyAtom( + () => + ( + table.optionAtoms.atoms?.get() as + | Record> + | undefined + )?.[key], + { + debugName: `table/options/atoms/${key}`, + }, + ) + const controlledStateOption = _reactivity.createReadonlyAtom( + () => { + const controlledState = table.optionAtoms.state?.get() as + | Record + | undefined + return controlledState && hasOwn(controlledState, key) + ? controlledState[key] + : noControlledState + }, + { + debugName: `table/options/state/${key}`, + }, + ) table.baseAtoms[key] = _reactivity.createWritableAtom( table.initialState[key], { @@ -142,9 +189,7 @@ export function constructTable< ) as any ;(table.atoms as any)[key] = _reactivity.createReadonlyAtom( () => { - const options = table.options - const externalAtoms = options.atoms - const externalAtom = externalAtoms?.[key] + const externalAtom = externalAtomOption.get() // Always touch the reactive owner so controlled state still has an // invalidation source when it is published after a framework commit. const reactiveState = externalAtom @@ -156,13 +201,11 @@ export function constructTable< return reactiveState } - const controlledState = options.state as - | Record - | undefined + const controlledState = controlledStateOption.get() - return controlledState && hasOwn(controlledState, key) - ? controlledState[key] - : reactiveState + return controlledState === noControlledState + ? reactiveState + : controlledState }, { debugName: `table/atoms/${key}` }, ) diff --git a/packages/table-core/src/core/table/coreTablesFeature.types.ts b/packages/table-core/src/core/table/coreTablesFeature.types.ts index 715455cc67..1d4ecce558 100644 --- a/packages/table-core/src/core/table/coreTablesFeature.types.ts +++ b/packages/table-core/src/core/table/coreTablesFeature.types.ts @@ -65,6 +65,45 @@ export type ExternalAtoms = Partial<{ [K in keyof TableState]: Atom[K]> }> +type ConstructStaticOptionKey = 'features' | 'atoms' | 'initialState' + +/** + * One atom per currently resolved table option. + * + * The atom properties themselves are readonly so their identities stay + * stable. Ordinary option atoms are writable; construction-static options + * remain readonly. + */ +export type TableOptionAtoms< + TFeatures extends TableFeatures, + TData extends RowData, +> = { + /** Increments once after each atomic update of the resolved options. */ + readonly snapshotVersion: ReadonlyAtom +} & { + readonly [K in keyof TableOptions< + TFeatures, + TData + > as K extends 'snapshotVersion' ? never : K]: K extends ConstructStaticOptionKey + ? ReadonlyAtom[K]> + : Atom[K]> +} + +/** + * The stable readonly options view exposed by `table.options`. + * + * Every property read is routed to the matching existing option atom. + */ +export type TableOptionsLive< + TFeatures extends TableFeatures, + TData extends RowData, +> = { + readonly [K in keyof TableOptions]: TableOptions< + TFeatures, + TData + >[K] +} + /** * Internal "all features" flat variants of the atom types. `Table_Internal` * uses these so feature code (written generically over `TFeatures`) can access @@ -231,15 +270,17 @@ export interface Table_CoreProperties< */ readonly initialState: TableState /** - * A read-only reference to the table's current options. + * A stable live view of the table's current resolved options. + * + * Reading a property reads the matching entry in `optionAtoms`. */ - readonly options: TableOptions + readonly options: TableOptionsLive /** - * Writable atom for table options. Only created when `createOptionsStore` is - * true on the active core reactivity bindings. Adapters that opt out keep - * options as plain resolved data instead of backing them with an atom. + * Stable atoms for individual resolved option values. + * + * Ordinary options are writable. Construction-static options are readonly. */ - readonly optionsStore?: Atom> | undefined + readonly optionAtoms: TableOptionAtoms /** * The readonly flat store for the table state. Derives from `table.atoms` * only; never reads external state directly. diff --git a/packages/table-core/src/core/table/coreTablesFeature.utils.ts b/packages/table-core/src/core/table/coreTablesFeature.utils.ts index 73f3aea4b5..4060fbc928 100644 --- a/packages/table-core/src/core/table/coreTablesFeature.utils.ts +++ b/packages/table-core/src/core/table/coreTablesFeature.utils.ts @@ -1,4 +1,5 @@ import { cloneState, functionalUpdate } from '../../utils' +import { applyTableOptions } from './tableOptionAtoms' import type { RowData, Updater } from '../../types/type-utils' import type { TableFeatures } from '../../types/TableFeatures' import type { Table_Internal } from '../../types/Table' @@ -37,7 +38,9 @@ export function table_syncExternalStateToBaseAtoms< ) => currentState === externalState, ): void { const state = - capturedState === undefined ? table.options.state : capturedState + capturedState === undefined + ? table.options.state + : capturedState table._reactivity.batch(() => { if (state) { @@ -74,10 +77,11 @@ export function table_publishExternalState< currentState, externalState, ) => currentState === externalState, + commitToken?: number, ): void { table._reactivity.batch(() => { table_syncExternalStateToBaseAtoms(table, state, compare) - table._reactivity.commit?.() + table._reactivity.commit?.(commitToken) }) } @@ -132,51 +136,55 @@ export function table_mergeOptions< table: Table_Internal, newOptions: TableOptions, ) { - const { features, atoms, initialState } = table.options + const currentOptions = table.options + const { features, atoms, initialState } = currentOptions + const mergeOptions = currentOptions.mergeOptions // simple merge if no mergeOptions is provided - performant - if (!table.options.mergeOptions) { + if (!mergeOptions) { return { - ...table.options, + ...currentOptions, ...newOptions, features, atoms, initialState, - } + } as TableOptions } // else use the mergeOptions function and preserve getters/setters - const mergedOptions = table.options.mergeOptions( - table.options as TableOptions, - newOptions, - ) - const descriptors: PropertyDescriptorMap = { + // Give custom merge logic a descriptor-preserving snapshot. A merge + // function that mutates its first argument must not mutate the controller's + // installed source before change detection runs. + const currentOptionsSnapshot = Object.create( + Object.getPrototypeOf(currentOptions), + Object.getOwnPropertyDescriptors(currentOptions), + ) as TableOptions + const mergedOptions = mergeOptions(currentOptionsSnapshot, newOptions) + const descriptors = { ...Object.getOwnPropertyDescriptors(mergedOptions), - } - - return Object.defineProperties( - Object.create(Object.getPrototypeOf(mergedOptions)), - { - ...descriptors, - features: { - value: features, - enumerable: true, - configurable: true, - writable: true, - }, - atoms: { - value: atoms, - enumerable: true, - configurable: true, - writable: true, - }, - initialState: { - value: initialState, - enumerable: true, - configurable: true, - writable: true, - }, + features: { + value: features, + enumerable: true, + configurable: true, + writable: true, }, + atoms: { + value: atoms, + enumerable: true, + configurable: true, + writable: true, + }, + initialState: { + value: initialState, + enumerable: true, + configurable: true, + writable: true, + }, + } as Record + + return Object.create( + Object.getPrototypeOf(mergedOptions), + descriptors, ) as TableOptions } @@ -201,19 +209,21 @@ export function table_setOptions< options?: { syncExternalState?: boolean }, -): void { +): number | undefined { const newOptions = functionalUpdate( updater, table.options as TableOptions, ) const mergedOptions = table_mergeOptions(table, newOptions) - if (table.optionsStore) { - table.optionsStore.set(() => mergedOptions) - } else { - table.options = mergedOptions - } + const commitToken = applyTableOptions(table.optionAtoms, mergedOptions) if (options?.syncExternalState !== false) { - table_publishExternalState(table, mergedOptions.state ?? null) + table_publishExternalState( + table, + mergedOptions.state ?? null, + undefined, + commitToken, + ) } + return commitToken } diff --git a/packages/table-core/src/core/table/tableOptionAtoms.ts b/packages/table-core/src/core/table/tableOptionAtoms.ts new file mode 100644 index 0000000000..565a8df36b --- /dev/null +++ b/packages/table-core/src/core/table/tableOptionAtoms.ts @@ -0,0 +1,194 @@ +import type { Atom, ReadonlyAtom } from '@tanstack/store' +import type { TableReactivityBindings } from '../reactivity/coreReactivityFeature.types' +import type { RowData, Updater } from '../../types/type-utils' +import type { TableFeatures } from '../../types/TableFeatures' +import type { TableOptions } from '../../types/TableOptions' +import type { + TableOptionAtoms, + TableOptionsLive, +} from './coreTablesFeature.types' + +type OptionKey = string | symbol +type ValueBox = { value: unknown } + +interface TableOptionAtomsInternals { + readonly options: unknown + apply: (options: unknown) => number | undefined +} + +const constructStaticOptionKeys = new Set([ + 'features', + 'atoms', + 'initialState', +]) +const snapshotVersionKey = 'snapshotVersion' +const optionAtomsInternals = new WeakMap() + +/** + * Creates one stable atom for each resolved option and a readonly live view. + * + * Values are boxed so callback-valued options are never interpreted as + * computed functions or atom updaters during initialization. + */ +export function createTableOptionAtoms< + TFeatures extends TableFeatures, + TData extends RowData, +>( + initialOptions: TableOptions, + reactivity: TableReactivityBindings, + setOption: (key: OptionKey, updater: Updater) => void, +): TableOptionAtoms { + const optionAtoms = Object.create(null) as Record< + PropertyKey, + Atom | ReadonlyAtom + > + const optionsTarget = Object.create(null) as Record + const valueAtoms = new Map>() + const snapshotVersionSource = reactivity.createWritableAtom(0, { + debugName: 'table/optionAtoms/snapshotVersion', + mode: 'staged', + }) + + Object.defineProperty(optionAtoms, snapshotVersionKey, { + configurable: false, + enumerable: true, + value: { + get: () => snapshotVersionSource.get(), + subscribe: snapshotVersionSource.subscribe.bind(snapshotVersionSource), + } satisfies ReadonlyAtom, + writable: false, + }) + + const setValue = ( + key: OptionKey, + value: unknown, + ): boolean => { + if (key === snapshotVersionKey) { + throw new Error( + `Table option "${snapshotVersionKey}" is reserved by table.optionAtoms`, + ) + } + + const valueAtom = valueAtoms.get(key) + if (valueAtom) { + if (Object.is(valueAtom.get().value, value)) { + return false + } + + valueAtom.set({ value }) + return true + } + + const newValueAtom = reactivity.createWritableAtom( + { value }, + { + debugName: `table/optionAtoms/${String(key)}`, + mode: 'staged', + }, + ) + const readonlyAtom = reactivity.createReadonlyAtom( + () => newValueAtom.get().value, + { + debugName: `table/options/${String(key)}`, + }, + ) + const publicAtom = constructStaticOptionKeys.has(key) + ? readonlyAtom + : ({ + get: () => readonlyAtom.get(), + subscribe: readonlyAtom.subscribe.bind(readonlyAtom), + set: (updater: Updater) => setOption(key, updater), + } satisfies Atom) + + valueAtoms.set(key, newValueAtom) + Object.defineProperty(optionAtoms, key, { + configurable: true, + enumerable: true, + value: publicAtom, + writable: false, + }) + Object.defineProperty(optionsTarget, key, { + configurable: true, + enumerable: true, + get: () => optionAtoms[key]!.get(), + }) + + return true + } + + for (const key of Reflect.ownKeys(initialOptions)) { + setValue(key, Reflect.get(initialOptions, key, initialOptions)) + } + + const rejectMutation = () => false + const options = new Proxy(optionsTarget, { + getOwnPropertyDescriptor: (target, key) => { + const descriptor = Reflect.getOwnPropertyDescriptor(target, key) + return descriptor + ? { + configurable: true, + enumerable: true, + value: Reflect.get(target, key, target), + writable: false, + } + : undefined + }, + defineProperty: rejectMutation, + deleteProperty: rejectMutation, + preventExtensions: rejectMutation, + set: rejectMutation, + setPrototypeOf: rejectMutation, + }) as TableOptionsLive + + const apply = (nextOptions: TableOptions) => { + const nextKeys = Reflect.ownKeys(nextOptions) + let changed = false + let commitToken: number | undefined + + reactivity.batch(() => { + for (const key of nextKeys) { + changed = + setValue( + key, + Reflect.get(nextOptions, key, nextOptions), + ) || changed + } + + if (changed) { + snapshotVersionSource.set((version) => version + 1) + commitToken = reactivity.stage?.() + } else { + commitToken = reactivity.getStageToken?.() + } + }) + + return commitToken + } + + optionAtomsInternals.set(optionAtoms, { + options, + apply: apply as (options: unknown) => number | undefined, + }) + + return optionAtoms as TableOptionAtoms +} + +export function getTableOptionsFromAtoms< + TFeatures extends TableFeatures, + TData extends RowData, +>( + optionAtoms: TableOptionAtoms, +): TableOptionsLive { + return optionAtomsInternals.get(optionAtoms)! + .options as TableOptionsLive +} + +export function applyTableOptions< + TFeatures extends TableFeatures, + TData extends RowData, +>( + optionAtoms: TableOptionAtoms, + nextOptions: TableOptions, +): number | undefined { + return optionAtomsInternals.get(optionAtoms)!.apply(nextOptions) +} diff --git a/packages/table-core/src/features/cell-selection/cellSelectionFeature.ts b/packages/table-core/src/features/cell-selection/cellSelectionFeature.ts index d0d3b7a47b..71fed09077 100644 --- a/packages/table-core/src/features/cell-selection/cellSelectionFeature.ts +++ b/packages/table-core/src/features/cell-selection/cellSelectionFeature.ts @@ -1,7 +1,6 @@ import { assignPrototypeAPIs, assignTableAPIs, - callMemoOrStaticFn, makeStateUpdater, } from '../../utils' import { @@ -127,31 +126,14 @@ export const cellSelectionFeature: TableFeature = { fn: () => table_autoResetCellSelection(table), }, table_getCellSelectionColumnIndexes: { - fn: () => table_getCellSelectionColumnIndexes(table), + computed: () => table_getCellSelectionColumnIndexes(table), // Mirrors columnVisibilityFeature's own deps rather than calling - // getVisibleLeafColumns() here, so the map stays memoized even when + // getVisibleLeafColumns() directly, so the map stays reactive even when // that feature is absent and its static rebuilds on every call. // columnPinning is added because cells render in pinned order. - memoDeps: () => [ - table.atoms.columnVisibility?.get(), - table.atoms.columnOrder?.get(), - table.atoms.columnPinning?.get(), - table.atoms.grouping?.get(), - table.options.columns, - table.options.groupedColumnMode, - ], }, table_getCellSelectionBounds: { - fn: () => table_getCellSelectionBounds(table), - memoDeps: () => [ - table.atoms.cellSelection?.get(), - table.getRowsInDisplayOrder(), - callMemoOrStaticFn( - table, - 'getCellSelectionColumnIndexes', - table_getCellSelectionColumnIndexes, - ), - ], + computed: () => table_getCellSelectionBounds(table), }, table_selectCellRange: { fn: (range, opts) => table_selectCellRange(table, range, opts), @@ -172,61 +154,19 @@ export const cellSelectionFeature: TableFeature = { fn: (direction) => table_extendCellSelection(table, direction), }, table_getSelectedCellIds: { - fn: () => table_getSelectedCellIds(table), - memoDeps: () => [ - callMemoOrStaticFn( - table, - 'getCellSelectionBounds', - table_getCellSelectionBounds, - ), - table.getRowsInDisplayOrder(), - table.options.enableCellSelection, - ], + computed: () => table_getSelectedCellIds(table), }, table_getSelectedCellRangesData: { - fn: () => table_getSelectedCellRangesData(table), - memoDeps: () => [ - callMemoOrStaticFn( - table, - 'getCellSelectionBounds', - table_getCellSelectionBounds, - ), - table.getRowsInDisplayOrder(), - table.options.enableCellSelection, - ], + computed: () => table_getSelectedCellRangesData(table), }, table_getSelectedCellCount: { - fn: () => table_getSelectedCellCount(table), - memoDeps: () => [ - callMemoOrStaticFn( - table, - 'getCellSelectionBounds', - table_getCellSelectionBounds, - ), - table.getRowsInDisplayOrder(), - table.options.enableCellSelection, - ], + computed: () => table_getSelectedCellCount(table), }, table_getCellSelectionRowIds: { - fn: () => table_getCellSelectionRowIds(table), - memoDeps: () => [ - callMemoOrStaticFn( - table, - 'getCellSelectionBounds', - table_getCellSelectionBounds, - ), - table.getRowsInDisplayOrder(), - ], + computed: () => table_getCellSelectionRowIds(table), }, table_getCellSelectionColumnIds: { - fn: () => table_getCellSelectionColumnIds(table), - memoDeps: () => [ - callMemoOrStaticFn( - table, - 'getCellSelectionBounds', - table_getCellSelectionBounds, - ), - ], + computed: () => table_getCellSelectionColumnIds(table), }, }) }, diff --git a/packages/table-core/src/features/cell-selection/cellSelectionFeature.utils.ts b/packages/table-core/src/features/cell-selection/cellSelectionFeature.utils.ts index 41b2a0c897..b8635c4df1 100644 --- a/packages/table-core/src/features/cell-selection/cellSelectionFeature.utils.ts +++ b/packages/table-core/src/features/cell-selection/cellSelectionFeature.utils.ts @@ -385,7 +385,7 @@ function resolveCellPosition< * Checks whether this cell falls inside any selected range. * * Deliberately not memoized. Registering this through `assignPrototypeAPIs` - * with `memoDeps` would allocate a memo closure and dependency array per cell, + * with a native computed would allocate a memo closure per cell, * which costs more than the handful of integer comparisons it would save. * * @example diff --git a/packages/table-core/src/features/column-faceting/columnFacetingFeature.ts b/packages/table-core/src/features/column-faceting/columnFacetingFeature.ts index 193d1066dc..f22312f086 100644 --- a/packages/table-core/src/features/column-faceting/columnFacetingFeature.ts +++ b/packages/table-core/src/features/column-faceting/columnFacetingFeature.ts @@ -20,35 +20,36 @@ export const columnFacetingFeature: TableFeature = { assignColumnPrototype: (prototype, table) => { assignPrototypeAPIs('columnFacetingFeature', prototype, table, { column_getFacetedRowModel: { - memoDeps: () => [ - table.getPreFilteredRowModel().rows, - table.atoms.columnFilters?.get(), - table.atoms.globalFilter?.get(), - table.getFilteredRowModel().rows, - ], - fn: (column) => column_getFacetedRowModel(column, column.table), + computed: (column) => { + void table.getPreFilteredRowModel().rows + void table.atoms.columnFilters?.get() + void table.atoms.globalFilter?.get() + // Ensure row.columnFilters metadata is populated before faceting. + void table.getFilteredRowModel().rows + return column_getFacetedRowModel(column, column.table) + }, }, column_getFacetedMinMaxValues: { - memoDeps: (column) => [ - callMemoOrStaticFn( + computed: (column) => { + void callMemoOrStaticFn( column, 'getFacetedRowModel', column_getFacetedRowModel, column.table, - ).flatRows, - ], - fn: (column) => column_getFacetedMinMaxValues(column, column.table), + ).flatRows + return column_getFacetedMinMaxValues(column, column.table) + }, }, column_getFacetedUniqueValues: { - memoDeps: (column) => [ - callMemoOrStaticFn( + computed: (column) => { + void callMemoOrStaticFn( column, 'getFacetedRowModel', column_getFacetedRowModel, column.table, - ).flatRows, - ], - fn: (column) => column_getFacetedUniqueValues(column, column.table), + ).flatRows + return column_getFacetedUniqueValues(column, column.table) + }, }, }) }, @@ -56,33 +57,34 @@ export const columnFacetingFeature: TableFeature = { constructTableAPIs: (table) => { assignTableAPIs('columnFacetingFeature', table, { table_getGlobalFacetedRowModel: { - memoDeps: () => [ - table.getPreFilteredRowModel().rows, - table.atoms.columnFilters?.get(), - table.atoms.globalFilter?.get(), - table.getFilteredRowModel().rows, - ], - fn: () => table_getGlobalFacetedRowModel(table), + computed: () => { + void table.getPreFilteredRowModel().rows + void table.atoms.columnFilters?.get() + void table.atoms.globalFilter?.get() + // Ensure row.columnFilters metadata is populated before faceting. + void table.getFilteredRowModel().rows + return table_getGlobalFacetedRowModel(table) + }, }, table_getGlobalFacetedMinMaxValues: { - memoDeps: () => [ - callMemoOrStaticFn( + computed: () => { + void callMemoOrStaticFn( table, 'getGlobalFacetedRowModel', table_getGlobalFacetedRowModel, - ).flatRows, - ], - fn: () => table_getGlobalFacetedMinMaxValues(table), + ).flatRows + return table_getGlobalFacetedMinMaxValues(table) + }, }, table_getGlobalFacetedUniqueValues: { - memoDeps: () => [ - callMemoOrStaticFn( + computed: () => { + void callMemoOrStaticFn( table, 'getGlobalFacetedRowModel', table_getGlobalFacetedRowModel, - ).flatRows, - ], - fn: () => table_getGlobalFacetedUniqueValues(table), + ).flatRows + return table_getGlobalFacetedUniqueValues(table) + }, }, }) }, diff --git a/packages/table-core/src/features/column-faceting/createFacetedMinMaxValues.ts b/packages/table-core/src/features/column-faceting/createFacetedMinMaxValues.ts index 3582901275..6f2439aa16 100644 --- a/packages/table-core/src/features/column-faceting/createFacetedMinMaxValues.ts +++ b/packages/table-core/src/features/column-faceting/createFacetedMinMaxValues.ts @@ -25,28 +25,29 @@ export function createFacetedMinMaxValues< const table = _table as unknown as Table_Internal return tableMemo({ feature: 'columnFacetingFeature', - fn: (flatRows) => _createFacetedMinMaxValues(table, columnId, flatRows), fnName: 'table.getFacetedMinMaxValues', - memoDeps: () => { + fn: () => { + let flatRows: Array> + if (columnId === '__global__') { - return [ - callMemoOrStaticFn( - table, - 'getGlobalFacetedRowModel', - table_getGlobalFacetedRowModel, - ).flatRows, - ] - } - const column = table.getColumn(columnId) - if (!column) return [table.getPreFilteredRowModel().flatRows] - return [ - callMemoOrStaticFn( - column, - 'getFacetedRowModel', - column_getFacetedRowModel, + flatRows = callMemoOrStaticFn( table, - ).flatRows, - ] + 'getGlobalFacetedRowModel', + table_getGlobalFacetedRowModel, + ).flatRows + } else { + const column = table.getColumn(columnId) + flatRows = column + ? callMemoOrStaticFn( + column, + 'getFacetedRowModel', + column_getFacetedRowModel, + table, + ).flatRows + : table.getPreFilteredRowModel().flatRows + } + + return _createFacetedMinMaxValues(table, columnId, flatRows) }, table, }) diff --git a/packages/table-core/src/features/column-faceting/createFacetedRowModel.ts b/packages/table-core/src/features/column-faceting/createFacetedRowModel.ts index a2b55d3dc3..4d7a0e5898 100644 --- a/packages/table-core/src/features/column-faceting/createFacetedRowModel.ts +++ b/packages/table-core/src/features/column-faceting/createFacetedRowModel.ts @@ -28,20 +28,22 @@ export function createFacetedRowModel< feature: 'columnFacetingFeature', table, fnName: 'createFacetedRowModel', - memoDeps: () => [ - table.getPreFilteredRowModel(), - table.atoms.columnFilters?.get(), - table.atoms.globalFilter?.get(), - table.getFilteredRowModel(), - ], - fn: (preRowModel, columnFilters, globalFilter) => - _createFacetedRowModel( + fn: () => { + const preRowModel = table.getPreFilteredRowModel() + const columnFilters = table.atoms.columnFilters?.get() + const globalFilter = table.atoms.globalFilter?.get() + + // Filtering populates row.columnFilters metadata consumed below. + table.getFilteredRowModel() + + return _createFacetedRowModel( table, columnId, preRowModel, columnFilters, globalFilter, - ), + ) + }, }) } } diff --git a/packages/table-core/src/features/column-faceting/createFacetedUniqueValues.ts b/packages/table-core/src/features/column-faceting/createFacetedUniqueValues.ts index df8cdcd1c3..d04656f49d 100644 --- a/packages/table-core/src/features/column-faceting/createFacetedUniqueValues.ts +++ b/packages/table-core/src/features/column-faceting/createFacetedUniqueValues.ts @@ -27,28 +27,29 @@ export function createFacetedUniqueValues< feature: 'columnFacetingFeature', table, fnName: 'table.getFacetedUniqueValues', - memoDeps: () => { + fn: () => { + let flatRows: Array> + if (columnId === '__global__') { - return [ - callMemoOrStaticFn( - table, - 'getGlobalFacetedRowModel', - table_getGlobalFacetedRowModel, - ).flatRows, - ] - } - const column = table.getColumn(columnId) - if (!column) return [table.getPreFilteredRowModel().flatRows] - return [ - callMemoOrStaticFn( - column, - 'getFacetedRowModel', - column_getFacetedRowModel, + flatRows = callMemoOrStaticFn( table, - ).flatRows, - ] + 'getGlobalFacetedRowModel', + table_getGlobalFacetedRowModel, + ).flatRows + } else { + const column = table.getColumn(columnId) + flatRows = column + ? callMemoOrStaticFn( + column, + 'getFacetedRowModel', + column_getFacetedRowModel, + table, + ).flatRows + : table.getPreFilteredRowModel().flatRows + } + + return _createFacetedUniqueValues(table, columnId, flatRows) }, - fn: (flatRows) => _createFacetedUniqueValues(table, columnId, flatRows), }) } } diff --git a/packages/table-core/src/features/column-filtering/createFilteredRowModel.ts b/packages/table-core/src/features/column-filtering/createFilteredRowModel.ts index 79ed4e1bc2..455effd306 100644 --- a/packages/table-core/src/features/column-filtering/createFilteredRowModel.ts +++ b/packages/table-core/src/features/column-filtering/createFilteredRowModel.ts @@ -39,11 +39,6 @@ export function createFilteredRowModel< feature: 'columnFilteringFeature', table, fnName: 'table.getFilteredRowModel', - memoDeps: () => [ - table.getPreFilteredRowModel(), - table.atoms.columnFilters?.get(), - table.atoms.globalFilter?.get(), - ], fn: () => _createFilteredRowModel(table), onAfterUpdate: () => table_autoResetPageIndex(table), }) diff --git a/packages/table-core/src/features/column-filtering/filterRowsUtils.ts b/packages/table-core/src/features/column-filtering/filterRowsUtils.ts index e8a701a7d6..ae112243a0 100644 --- a/packages/table-core/src/features/column-filtering/filterRowsUtils.ts +++ b/packages/table-core/src/features/column-filtering/filterRowsUtils.ts @@ -1,4 +1,5 @@ import { constructRow } from '../../core/rows/constructRow' +import { row_setSubRows } from '../../core/rows/subRowsTracking' import { makeObjectMap } from '../../utils' import type { Row_ColumnFiltering } from './columnFilteringFeature.types' import type { RowModel } from '../../core/row-models/coreRowModelsFeature.types' @@ -65,7 +66,7 @@ function filterRowModelFromLeafs< newRow.columnFilters = row.columnFilters if (row.subRows.length && depth < maxDepth) { - newRow.subRows = recurseFilterRows(row.subRows, depth + 1) + row_setSubRows(newRow, recurseFilterRows(row.subRows, depth + 1)) row = newRow if (filterRow(row) && !newRow.subRows.length) { @@ -137,7 +138,7 @@ function filterRowModelFromRoot< undefined, row.parentId, ) - newRow.subRows = recurseFilterRows(row.subRows, depth + 1) + row_setSubRows(newRow, recurseFilterRows(row.subRows, depth + 1)) row = newRow } diff --git a/packages/table-core/src/features/column-grouping/createGroupedRowModel.ts b/packages/table-core/src/features/column-grouping/createGroupedRowModel.ts index a0511fb33e..ae9e1c0ddb 100644 --- a/packages/table-core/src/features/column-grouping/createGroupedRowModel.ts +++ b/packages/table-core/src/features/column-grouping/createGroupedRowModel.ts @@ -1,5 +1,6 @@ import { hasOwn, makeObjectMap, tableMemo } from '../../utils' import { constructRow } from '../../core/rows/constructRow' +import { row_setSubRows } from '../../core/rows/subRowsTracking' import { table_getColumn } from '../../core/columns/coreColumnsFeature.utils' import { table_autoResetExpanded } from '../row-expanding/rowExpandingFeature.utils' import { table_autoResetPageIndex } from '../row-pagination/rowPaginationFeature.utils' @@ -37,11 +38,6 @@ export function createGroupedRowModel< feature: 'columnGroupingFeature', table, fnName: 'table.getGroupedRowModel', - memoDeps: () => [ - table.atoms.grouping?.get(), - table.getPreGroupedRowModel(), - table.options.columns, - ], fn: () => _createGroupedRowModel(table), onAfterUpdate: () => { const grouping = table.atoms.grouping?.get() @@ -109,7 +105,10 @@ function _createGroupedRowModel< // parent group's loop or the root loop), so only descendants below // the terminal depth are pushed here. if (row.subRows.length) { - row.subRows = groupUpRecursively(row.subRows, depth + 1, row.id) + row_setSubRows( + row, + groupUpRecursively(row.subRows, depth + 1, row.id), + ) for (let i = 0; i < row.subRows.length; i++) { const subRow = row.subRows[i]! groupedFlatRows.push(subRow) diff --git a/packages/table-core/src/features/column-ordering/columnOrderingFeature.ts b/packages/table-core/src/features/column-ordering/columnOrderingFeature.ts index a279a44fc7..0ed143d206 100644 --- a/packages/table-core/src/features/column-ordering/columnOrderingFeature.ts +++ b/packages/table-core/src/features/column-ordering/columnOrderingFeature.ts @@ -49,15 +49,7 @@ export const columnOrderingFeature: TableFeature = { constructTableAPIs: (table) => { assignTableAPIs('columnOrderingFeature', table, { table_getColumnIndexes: { - fn: () => table_getColumnIndexes(table), - memoDeps: () => [ - table.options.columns, - table.atoms.columnOrder?.get(), - table.atoms.columnPinning?.get(), - table.atoms.columnVisibility?.get(), - table.atoms.grouping?.get(), - table.options.groupedColumnMode, - ], + computed: () => table_getColumnIndexes(table), }, table_setColumnOrder: { fn: (updater) => table_setColumnOrder(table, updater), @@ -66,12 +58,15 @@ export const columnOrderingFeature: TableFeature = { fn: (defaultState) => table_resetColumnOrder(table, defaultState), }, table_getOrderColumnsFn: { - fn: () => table_getOrderColumnsFn(table), - memoDeps: () => [ - table.atoms.columnOrder?.get(), - table.atoms.grouping?.get(), - table.options.groupedColumnMode, - ], + computed: () => { + // These values are consumed when the returned ordering function runs, + // but they also determine that function's behavior. Read them while + // resolving the computed so either change replaces the cached + // function, matching the former explicit memo dependency list. + void table.atoms.grouping?.get() + void table.options.groupedColumnMode + return table_getOrderColumnsFn(table) + }, }, }) }, diff --git a/packages/table-core/src/features/column-pinning/columnPinningFeature.ts b/packages/table-core/src/features/column-pinning/columnPinningFeature.ts index e02665e562..aab012b817 100644 --- a/packages/table-core/src/features/column-pinning/columnPinningFeature.ts +++ b/packages/table-core/src/features/column-pinning/columnPinningFeature.ts @@ -4,7 +4,11 @@ import { callMemoOrStaticFn, makeStateUpdater, } from '../../utils' -import { table_getVisibleLeafColumns } from '../column-visibility/columnVisibilityFeature.utils' +import { + column_getIsVisible, + row_getVisibleCellsByColumnId, +} from '../column-visibility/columnVisibilityFeature.utils' +import { buildHeaderGroups } from '../../core/headers/buildHeaderGroups' import { column_getCanPin, column_getIsPinned, @@ -12,8 +16,6 @@ import { column_pin, getDefaultColumnPinningState, row_getCenterVisibleCells, - row_getEndVisibleCells, - row_getStartVisibleCells, table_getCenterFlatHeaders, table_getCenterFooterGroups, table_getCenterHeaderGroups, @@ -22,7 +24,6 @@ import { table_getCenterVisibleLeafColumns, table_getEndFlatHeaders, table_getEndFooterGroups, - table_getEndHeaderGroups, table_getEndLeafColumns, table_getEndLeafHeaders, table_getEndVisibleLeafColumns, @@ -31,15 +32,20 @@ import { table_getPinnedVisibleLeafColumns, table_getStartFlatHeaders, table_getStartFooterGroups, - table_getStartHeaderGroups, table_getStartLeafColumns, table_getStartLeafHeaders, table_getStartVisibleLeafColumns, table_resetColumnPinning, table_setColumnPinning, } from './columnPinningFeature.utils' +import type { ReadonlyAtom } from '@tanstack/store' import type { TableFeature } from '../../types/TableFeatures' +function createLazySelector(create: () => ReadonlyAtom): () => T { + let atom: ReadonlyAtom | undefined + return () => (atom ??= create()).get() +} + /** * Feature that adds column pinning state and APIs for logical start, center, * and end regions. @@ -83,35 +89,115 @@ export const columnPinningFeature: TableFeature = { }, assignRowPrototype: (prototype, table) => { + const readStartPinning = createLazySelector(() => + table._reactivity.createReadonlyAtom( + () => table.atoms.columnPinning?.get()?.start, + { + debugName: 'table/selectors/columnPinning/start', + mode: 'memo', + }, + ), + ) + const readEndPinning = createLazySelector(() => + table._reactivity.createReadonlyAtom( + () => table.atoms.columnPinning?.get()?.end, + { + debugName: 'table/selectors/columnPinning/end', + mode: 'memo', + }, + ), + ) + assignPrototypeAPIs('columnPinningFeature', prototype, table, { row_getCenterVisibleCells: { - fn: (row) => row_getCenterVisibleCells(row), - memoDeps: (row) => [ - row.getAllCells(), - row.table.atoms.columnPinning?.get(), - row.table.atoms.columnVisibility?.get(), - ], + computed: (row) => row_getCenterVisibleCells(row), }, row_getStartVisibleCells: { - fn: (row) => row_getStartVisibleCells(row), - memoDeps: (row) => [ - row.getAllCells(), - row.table.atoms.columnPinning?.get()?.start, - row.table.atoms.columnVisibility?.get(), - ], + computed: (row) => { + const start = readStartPinning() ?? [] + if (!start.length) return [] + const cellsByColumnId = callMemoOrStaticFn( + row, + 'getVisibleCellsByColumnId', + row_getVisibleCellsByColumnId, + ) + const cells: Array<(typeof cellsByColumnId)[string]> = [] + for (let i = 0; i < start.length; i++) { + const cell = cellsByColumnId[start[i]!] + if (cell) { + ;(cell as any).position = 'start' + cells.push(cell) + } + } + return cells + }, }, row_getEndVisibleCells: { - fn: (row) => row_getEndVisibleCells(row), - memoDeps: (row) => [ - row.getAllCells(), - row.table.atoms.columnPinning?.get()?.end, - row.table.atoms.columnVisibility?.get(), - ], + computed: (row) => { + const end = readEndPinning() ?? [] + if (!end.length) return [] + const cellsByColumnId = callMemoOrStaticFn( + row, + 'getVisibleCellsByColumnId', + row_getVisibleCellsByColumnId, + ) + const cells: Array<(typeof cellsByColumnId)[string]> = [] + for (let i = 0; i < end.length; i++) { + const cell = cellsByColumnId[end[i]!] + if (cell) { + ;(cell as any).position = 'end' + cells.push(cell) + } + } + return cells + }, }, }) }, constructTableAPIs: (table) => { + const readStartPinning = createLazySelector(() => + table._reactivity.createReadonlyAtom( + () => table.atoms.columnPinning?.get()?.start, + { + debugName: 'table/selectors/columnPinning/startHeaderGroups', + mode: 'memo', + }, + ), + ) + const readEndPinning = createLazySelector(() => + table._reactivity.createReadonlyAtom( + () => table.atoms.columnPinning?.get()?.end, + { + debugName: 'table/selectors/columnPinning/endHeaderGroups', + mode: 'memo', + }, + ), + ) + const buildPinnedHeaderGroups = ( + position: 'start' | 'end', + pinnedColumnIds: ReadonlyArray, + ) => { + const allColumns = table.getAllColumns() + const leafColumnsById = table.getAllLeafColumnsById() + const orderedLeafColumns: typeof allColumns = [] + for (let i = 0; i < pinnedColumnIds.length; i++) { + const column = leafColumnsById[pinnedColumnIds[i]!] + if ( + column && + callMemoOrStaticFn(column, 'getIsVisible', column_getIsVisible) + ) { + orderedLeafColumns.push(column) + } + } + return buildHeaderGroups( + allColumns, + orderedLeafColumns, + table, + position, + ) + } + assignTableAPIs('columnPinningFeature', table, { table_setColumnPinning: { fn: (updater) => table_setColumnPinning(table, updater), @@ -124,167 +210,59 @@ export const columnPinningFeature: TableFeature = { }, // header groups table_getStartHeaderGroups: { - fn: () => table_getStartHeaderGroups(table), - memoDeps: () => [ - table.getAllColumns(), - callMemoOrStaticFn( - table, - 'getVisibleLeafColumns', - table_getVisibleLeafColumns, - ), - table.atoms.columnPinning?.get()?.start, - table.atoms.columnOrder?.get(), - ], + computed: () => { + table.atoms.columnOrder?.get() + return buildPinnedHeaderGroups('start', readStartPinning() ?? []) + }, }, table_getCenterHeaderGroups: { - fn: () => table_getCenterHeaderGroups(table), - memoDeps: () => [ - table.getAllColumns(), - callMemoOrStaticFn( - table, - 'getVisibleLeafColumns', - table_getVisibleLeafColumns, - ), - table.atoms.columnPinning?.get(), - table.atoms.columnOrder?.get(), - ], + computed: () => table_getCenterHeaderGroups(table), }, table_getEndHeaderGroups: { - fn: () => table_getEndHeaderGroups(table), - memoDeps: () => [ - table.getAllColumns(), - callMemoOrStaticFn( - table, - 'getVisibleLeafColumns', - table_getVisibleLeafColumns, - ), - table.atoms.columnPinning?.get()?.end, - table.atoms.columnOrder?.get(), - ], + computed: () => { + table.atoms.columnOrder?.get() + return buildPinnedHeaderGroups('end', readEndPinning() ?? []) + }, }, // footer groups table_getStartFooterGroups: { - fn: () => table_getStartFooterGroups(table), - memoDeps: () => [ - callMemoOrStaticFn( - table, - 'getStartHeaderGroups', - table_getStartHeaderGroups, - ), - ], + computed: () => table_getStartFooterGroups(table), }, table_getCenterFooterGroups: { - fn: () => table_getCenterFooterGroups(table), - memoDeps: () => [ - callMemoOrStaticFn( - table, - 'getCenterHeaderGroups', - table_getCenterHeaderGroups, - ), - ], + computed: () => table_getCenterFooterGroups(table), }, table_getEndFooterGroups: { - fn: () => table_getEndFooterGroups(table), - memoDeps: () => [ - callMemoOrStaticFn( - table, - 'getEndHeaderGroups', - table_getEndHeaderGroups, - ), - ], + computed: () => table_getEndFooterGroups(table), }, // flat headers table_getStartFlatHeaders: { - fn: () => table_getStartFlatHeaders(table), - memoDeps: () => [ - callMemoOrStaticFn( - table, - 'getStartHeaderGroups', - table_getStartHeaderGroups, - ), - ], + computed: () => table_getStartFlatHeaders(table), }, table_getEndFlatHeaders: { - fn: () => table_getEndFlatHeaders(table), - memoDeps: () => [ - callMemoOrStaticFn( - table, - 'getEndHeaderGroups', - table_getEndHeaderGroups, - ), - ], + computed: () => table_getEndFlatHeaders(table), }, table_getCenterFlatHeaders: { - fn: () => table_getCenterFlatHeaders(table), - memoDeps: () => [ - callMemoOrStaticFn( - table, - 'getCenterHeaderGroups', - table_getCenterHeaderGroups, - ), - ], + computed: () => table_getCenterFlatHeaders(table), }, // leaf headers table_getStartLeafHeaders: { - fn: () => table_getStartLeafHeaders(table), - memoDeps: () => [ - callMemoOrStaticFn( - table, - 'getStartHeaderGroups', - table_getStartHeaderGroups, - ), - ], + computed: () => table_getStartLeafHeaders(table), }, table_getEndLeafHeaders: { - fn: () => table_getEndLeafHeaders(table), - memoDeps: () => [ - callMemoOrStaticFn( - table, - 'getEndHeaderGroups', - table_getEndHeaderGroups, - ), - ], + computed: () => table_getEndLeafHeaders(table), }, table_getCenterLeafHeaders: { - fn: () => table_getCenterLeafHeaders(table), - memoDeps: () => [ - callMemoOrStaticFn( - table, - 'getCenterHeaderGroups', - table_getCenterHeaderGroups, - ), - ], + computed: () => table_getCenterLeafHeaders(table), }, // leaf columns table_getStartLeafColumns: { - fn: () => table_getStartLeafColumns(table), - memoDeps: () => [ - table.options.columns, - table.atoms.columnPinning?.get(), - table.atoms.columnOrder?.get(), - table.atoms.grouping?.get(), - table.options.groupedColumnMode, - ], + computed: () => table_getStartLeafColumns(table), }, table_getEndLeafColumns: { - fn: () => table_getEndLeafColumns(table), - memoDeps: () => [ - table.options.columns, - table.atoms.columnPinning?.get(), - table.atoms.columnOrder?.get(), - table.atoms.grouping?.get(), - table.options.groupedColumnMode, - ], + computed: () => table_getEndLeafColumns(table), }, table_getCenterLeafColumns: { - fn: () => table_getCenterLeafColumns(table), - memoDeps: () => [ - table.options.columns, - table.atoms.columnPinning?.get(), - table.atoms.columnOrder?.get(), - table.atoms.grouping?.get(), - table.options.groupedColumnMode, - ], + computed: () => table_getCenterLeafColumns(table), }, table_getPinnedLeafColumns: { fn: (position) => table_getPinnedLeafColumns(table, position), @@ -292,37 +270,13 @@ export const columnPinningFeature: TableFeature = { }, // visible leaf columns table_getStartVisibleLeafColumns: { - fn: () => table_getStartVisibleLeafColumns(table), - memoDeps: () => [ - table.options.columns, - table.atoms.columnPinning?.get(), - table.atoms.columnVisibility?.get(), - table.atoms.columnOrder?.get(), - table.atoms.grouping?.get(), - table.options.groupedColumnMode, - ], + computed: () => table_getStartVisibleLeafColumns(table), }, table_getCenterVisibleLeafColumns: { - fn: () => table_getCenterVisibleLeafColumns(table), - memoDeps: () => [ - table.options.columns, - table.atoms.columnPinning?.get(), - table.atoms.columnVisibility?.get(), - table.atoms.columnOrder?.get(), - table.atoms.grouping?.get(), - table.options.groupedColumnMode, - ], + computed: () => table_getCenterVisibleLeafColumns(table), }, table_getEndVisibleLeafColumns: { - fn: () => table_getEndVisibleLeafColumns(table), - memoDeps: () => [ - table.options.columns, - table.atoms.columnPinning?.get(), - table.atoms.columnVisibility?.get(), - table.atoms.columnOrder?.get(), - table.atoms.grouping?.get(), - table.options.groupedColumnMode, - ], + computed: () => table_getEndVisibleLeafColumns(table), }, table_getPinnedVisibleLeafColumns: { fn: (position) => table_getPinnedVisibleLeafColumns(table, position), diff --git a/packages/table-core/src/features/column-sizing/columnSizingFeature.ts b/packages/table-core/src/features/column-sizing/columnSizingFeature.ts index 94b7beed48..f74fc4cb86 100644 --- a/packages/table-core/src/features/column-sizing/columnSizingFeature.ts +++ b/packages/table-core/src/features/column-sizing/columnSizingFeature.ts @@ -1,11 +1,11 @@ import { assignPrototypeAPIs, assignTableAPIs, + hasOwn, makeStateUpdater, } from '../../utils' import { column_getAfter, - column_getSize, column_getStart, column_resetSize, getDefaultColumnSizingColumnDef, @@ -20,8 +20,34 @@ import { table_resetColumnSizing, table_setColumnSizing, } from './columnSizingFeature.utils' +import type { ReadonlyAtom } from '@tanstack/store' import type { TableFeature } from '../../types/TableFeatures' +function createLazySelector(create: () => ReadonlyAtom): () => T { + let atom: ReadonlyAtom | undefined + return () => (atom ??= create()).get() +} + +function resolveColumnSize( + column: { + columnDef: { + maxSize?: number + minSize?: number + size?: number + } + }, + columnSize: number | undefined, +): number { + const defaults = getDefaultColumnSizingColumnDef() + return Math.min( + Math.max( + column.columnDef.minSize ?? defaults.minSize, + columnSize ?? column.columnDef.size ?? defaults.size, + ), + column.columnDef.maxSize ?? defaults.maxSize, + ) +} + /** * Feature that adds column sizing state, defaults, and size measurement APIs. */ @@ -44,13 +70,35 @@ export const columnSizingFeature: TableFeature = { }, assignColumnPrototype: (prototype, table) => { + const sizeSelectors = new WeakMap number | undefined>() + const readColumnSize = (column: { id: string }) => { + let readSize = sizeSelectors.get(column) + if (!readSize) { + readSize = createLazySelector(() => + table._reactivity.createReadonlyAtom( + () => { + const sizing = table.atoms.columnSizing?.get() + return sizing && hasOwn(sizing, column.id) + ? sizing[column.id] + : undefined + }, + { + debugName: `table/selectors/columnSizing/${column.id}`, + mode: 'memo', + }, + ), + ) + sizeSelectors.set(column, readSize) + } + return readSize() + } + assignPrototypeAPIs('columnSizingFeature', prototype, table, { column_getSize: { - fn: (column) => column_getSize(column), - memoDeps: (column) => [ - table.options.columns, - table.atoms.columnSizing?.get()?.[column.id], // just this column's size state - ], + computed: (column) => { + void table.options.columns + return resolveColumnSize(column, readColumnSize(column)) + }, }, // O(1) lookups into the memoized table-level offsets, so no per-column // memos here @@ -67,27 +115,44 @@ export const columnSizingFeature: TableFeature = { }, assignHeaderPrototype: (prototype, table) => { + const sizeSelectors = new WeakMap number | undefined>() + const readColumnSize = (column: { id: string }) => { + let readSize = sizeSelectors.get(column) + if (!readSize) { + readSize = createLazySelector(() => + table._reactivity.createReadonlyAtom( + () => { + const sizing = table.atoms.columnSizing?.get() + return sizing && hasOwn(sizing, column.id) + ? sizing[column.id] + : undefined + }, + { + debugName: `table/selectors/headerColumnSizing/${column.id}`, + mode: 'memo', + }, + ), + ) + sizeSelectors.set(column, readSize) + } + return readSize() + } + assignPrototypeAPIs('columnSizingFeature', prototype, table, { header_getSize: { - fn: (header) => header_getSize(header), - memoDeps: (header) => [ - table.options.columns, - header.column.columns.length > 0 - ? table.atoms.columnSizing?.get() // must be all columns (sum child columns) - : table.atoms.columnSizing?.get()?.[header.column.id], // can just check it's associated column size state - ], + computed: (header) => { + void table.options.columns + if (header.column.columns.length > 0) { + return header_getSize(header) + } + return resolveColumnSize( + header.column, + readColumnSize(header.column), + ) + }, }, header_getStart: { - fn: (header) => header_getStart(header), - memoDeps: () => [ - table.options.columns, - table.atoms.columnSizing?.get(), - table.atoms.columnOrder?.get(), - table.atoms.columnPinning?.get(), - table.atoms.columnVisibility?.get(), - table.atoms.grouping?.get(), - table.options.groupedColumnMode, - ], + computed: (header) => header_getStart(header), }, }) }, @@ -95,16 +160,7 @@ export const columnSizingFeature: TableFeature = { constructTableAPIs: (table) => { assignTableAPIs('columnSizingFeature', table, { table_getColumnOffsets: { - fn: () => table_getColumnOffsets(table), - memoDeps: () => [ - table.options.columns, - table.atoms.columnSizing?.get(), - table.atoms.columnOrder?.get(), - table.atoms.columnPinning?.get(), - table.atoms.columnVisibility?.get(), - table.atoms.grouping?.get(), - table.options.groupedColumnMode, - ], + computed: () => table_getColumnOffsets(table), }, table_setColumnSizing: { fn: (updater) => table_setColumnSizing(table, updater), @@ -113,32 +169,16 @@ export const columnSizingFeature: TableFeature = { fn: (defaultState) => table_resetColumnSizing(table, defaultState), }, table_getTotalSize: { - fn: () => table_getTotalSize(table), - memoDeps: () => [ - table.atoms.columnSizing?.get(), - table.getHeaderGroups(), - ], + computed: () => table_getTotalSize(table), }, table_getStartTotalSize: { - fn: () => table_getStartTotalSize(table), - memoDeps: () => [ - table.atoms.columnSizing?.get(), - table.getHeaderGroups(), - ], + computed: () => table_getStartTotalSize(table), }, table_getCenterTotalSize: { - fn: () => table_getCenterTotalSize(table), - memoDeps: () => [ - table.atoms.columnSizing?.get(), - table.getHeaderGroups(), - ], + computed: () => table_getCenterTotalSize(table), }, table_getEndTotalSize: { - fn: () => table_getEndTotalSize(table), - memoDeps: () => [ - table.atoms.columnSizing?.get(), - table.getHeaderGroups(), - ], + computed: () => table_getEndTotalSize(table), }, }) }, diff --git a/packages/table-core/src/features/column-visibility/columnVisibilityFeature.ts b/packages/table-core/src/features/column-visibility/columnVisibilityFeature.ts index 31b6d81b7e..2f90e5c2d5 100644 --- a/packages/table-core/src/features/column-visibility/columnVisibilityFeature.ts +++ b/packages/table-core/src/features/column-visibility/columnVisibilityFeature.ts @@ -42,12 +42,7 @@ export const columnVisibilityFeature: TableFeature = { assignColumnPrototype: (prototype, table) => { assignPrototypeAPIs('columnVisibilityFeature', prototype, table, { column_getIsVisible: { - fn: (column) => column_getIsVisible(column), - memoDeps: (column) => [ - table.options.columns, - table.atoms.columnVisibility?.get(), - column.columns, - ], + computed: (column) => column_getIsVisible(column), }, column_getCanHide: { fn: (column) => column_getCanHide(column), @@ -64,19 +59,10 @@ export const columnVisibilityFeature: TableFeature = { assignRowPrototype: (prototype, table) => { assignPrototypeAPIs('columnVisibilityFeature', prototype, table, { row_getVisibleCells: { - fn: (row) => row_getVisibleCells(row), - memoDeps: (row) => [ - row.getAllCells(), - table.atoms.columnPinning?.get(), - table.atoms.columnVisibility?.get(), - ], + computed: (row) => row_getVisibleCells(row), }, row_getVisibleCellsByColumnId: { - fn: (row) => row_getVisibleCellsByColumnId(row), - memoDeps: (row) => [ - row.getAllCells(), - table.atoms.columnVisibility?.get(), - ], + computed: (row) => row_getVisibleCellsByColumnId(row), }, }) }, @@ -84,24 +70,10 @@ export const columnVisibilityFeature: TableFeature = { constructTableAPIs: (table) => { assignTableAPIs('columnVisibilityFeature', table, { table_getVisibleFlatColumns: { - fn: () => table_getVisibleFlatColumns(table), - memoDeps: () => [ - table.atoms.columnVisibility?.get(), - table.atoms.columnOrder?.get(), - table.atoms.grouping?.get(), - table.options.columns, - table.options.groupedColumnMode, - ], + computed: () => table_getVisibleFlatColumns(table), }, table_getVisibleLeafColumns: { - fn: () => table_getVisibleLeafColumns(table), - memoDeps: () => [ - table.atoms.columnVisibility?.get(), - table.atoms.columnOrder?.get(), - table.atoms.grouping?.get(), - table.options.columns, - table.options.groupedColumnMode, - ], + computed: () => table_getVisibleLeafColumns(table), }, table_setColumnVisibility: { fn: (updater) => table_setColumnVisibility(table, updater), diff --git a/packages/table-core/src/features/row-aggregation/rowAggregationFeature.ts b/packages/table-core/src/features/row-aggregation/rowAggregationFeature.ts index 3c69aba06f..0a3c270354 100644 --- a/packages/table-core/src/features/row-aggregation/rowAggregationFeature.ts +++ b/packages/table-core/src/features/row-aggregation/rowAggregationFeature.ts @@ -40,11 +40,11 @@ export const rowAggregationFeature: TableFeature = { fn: (column, options) => column_getAggregationValue(column, options), }, column_getAutoAggregationFn: { - fn: (column) => column_getAutoAggregationFn(column), - memoDeps: (column) => [ - column.table.getCoreRowModel(), - column.table._rowModelFns.aggregationFns, - ], + computed: (column) => { + void column.table.getCoreRowModel() + void column.table._rowModelFns.aggregationFns + return column_getAutoAggregationFn(column) + }, }, }) }, diff --git a/packages/table-core/src/features/row-expanding/createExpandedRowModel.ts b/packages/table-core/src/features/row-expanding/createExpandedRowModel.ts index bf3df84990..4d16b0d347 100644 --- a/packages/table-core/src/features/row-expanding/createExpandedRowModel.ts +++ b/packages/table-core/src/features/row-expanding/createExpandedRowModel.ts @@ -21,12 +21,6 @@ export function createExpandedRowModel< feature: 'rowExpandingFeature', table, fnName: 'table.getExpandedRowModel', - memoDeps: () => [ - table.atoms.expanded?.get(), - table.getPreExpandedRowModel(), - table.options.paginateExpandedRows, - table.options.manualPagination, - ], fn: () => _createExpandedRowModel(table), }) } diff --git a/packages/table-core/src/features/row-pagination/createPaginatedRowModel.ts b/packages/table-core/src/features/row-pagination/createPaginatedRowModel.ts index bd991529cf..c9463976ad 100644 --- a/packages/table-core/src/features/row-pagination/createPaginatedRowModel.ts +++ b/packages/table-core/src/features/row-pagination/createPaginatedRowModel.ts @@ -22,13 +22,6 @@ export function createPaginatedRowModel< feature: 'rowPaginationFeature', table, fnName: 'table.getPaginatedRowModel', - memoDeps: () => [ - table.getPrePaginatedRowModel(), - table.atoms.pagination?.get(), - !table.options.paginateExpandedRows - ? table.atoms.expanded?.get() - : undefined, - ], fn: () => _createPaginatedRowModel(table), }) } diff --git a/packages/table-core/src/features/row-pinning/rowPinningFeature.ts b/packages/table-core/src/features/row-pinning/rowPinningFeature.ts index cbd075e2b4..478e9705df 100644 --- a/packages/table-core/src/features/row-pinning/rowPinningFeature.ts +++ b/packages/table-core/src/features/row-pinning/rowPinningFeature.ts @@ -3,21 +3,26 @@ import { assignTableAPIs, makeStateUpdater, } from '../../utils' +import { row_getIsAllParentsExpanded } from '../row-expanding/rowExpandingFeature.utils' import { getDefaultRowPinningState, row_getCanPin, row_getIsPinned, row_getPinnedIndex, row_pin, - table_getBottomRows, table_getCenterRows, table_getIsSomeRowsPinned, - table_getTopRows, table_resetRowPinning, table_setRowPinning, } from './rowPinningFeature.utils' +import type { ReadonlyAtom } from '@tanstack/store' import type { TableFeature } from '../../types/TableFeatures' +function createLazySelector(create: () => ReadonlyAtom): () => T { + let atom: ReadonlyAtom | undefined + return () => (atom ??= create()).get() +} + /** * Feature that adds row pinning state and APIs for top, center, and bottom rows. */ @@ -47,11 +52,7 @@ export const rowPinningFeature: TableFeature = { fn: (row) => row_getIsPinned(row), }, row_getPinnedIndex: { - fn: (row) => row_getPinnedIndex(row), - memoDeps: (row) => [ - row.table.getRowModel().rows, - row.table.atoms.rowPinning?.get(), - ], + computed: (row) => row_getPinnedIndex(row), }, row_pin: { fn: (row, position, includeLeafRows, includeParentRows) => @@ -61,6 +62,51 @@ export const rowPinningFeature: TableFeature = { }, constructTableAPIs: (table) => { + const readTopPinning = createLazySelector(() => + table._reactivity.createReadonlyAtom( + () => table.atoms.rowPinning?.get()?.top, + { + debugName: 'table/selectors/rowPinning/top', + mode: 'memo', + }, + ), + ) + const readBottomPinning = createLazySelector(() => + table._reactivity.createReadonlyAtom( + () => table.atoms.rowPinning?.get()?.bottom, + { + debugName: 'table/selectors/rowPinning/bottom', + mode: 'memo', + }, + ), + ) + const getPinnedRows = ( + position: 'top' | 'bottom', + pinnedRowIds: ReadonlyArray, + ) => { + const visibleRows = table.getRowModel().rows + const keepPinnedRows = table.options.keepPinnedRows ?? true + const result: Array = [] + + for (let i = 0; i < pinnedRowIds.length; i++) { + const rowId = pinnedRowIds[i]! + let row + if (keepPinnedRows) { + const fullRow = table.getRow(rowId, true) + if (row_getIsAllParentsExpanded(fullRow)) { + row = fullRow + } + } else { + row = visibleRows.find((candidate) => candidate.id === rowId) + } + if (!row) continue + ;(row as any).position = position + result.push(row) + } + + return result + } + assignTableAPIs('rowPinningFeature', table, { table_setRowPinning: { fn: (updater) => table_setRowPinning(table, updater), @@ -72,25 +118,13 @@ export const rowPinningFeature: TableFeature = { fn: (position) => table_getIsSomeRowsPinned(table, position), }, table_getTopRows: { - fn: () => table_getTopRows(table), - memoDeps: () => [ - table.getRowModel().rows, - table.atoms.rowPinning?.get()?.top, - ], + computed: () => getPinnedRows('top', readTopPinning() ?? []), }, table_getBottomRows: { - fn: () => table_getBottomRows(table), - memoDeps: () => [ - table.getRowModel().rows, - table.atoms.rowPinning?.get()?.bottom, - ], + computed: () => getPinnedRows('bottom', readBottomPinning() ?? []), }, table_getCenterRows: { - fn: () => table_getCenterRows(table), - memoDeps: () => [ - table.getRowModel().rows, - table.atoms.rowPinning?.get(), - ], + computed: () => table_getCenterRows(table), }, }) }, diff --git a/packages/table-core/src/features/row-selection/rowSelectionFeature.ts b/packages/table-core/src/features/row-selection/rowSelectionFeature.ts index e8f4de7735..4dc82c78f6 100644 --- a/packages/table-core/src/features/row-selection/rowSelectionFeature.ts +++ b/packages/table-core/src/features/row-selection/rowSelectionFeature.ts @@ -78,20 +78,10 @@ export const rowSelectionFeature: TableFeature = { fn: (row) => row_getIsSelected(row), }, row_getIsSomeSelected: { - fn: (row) => row_getIsSomeSelected(row), - memoDeps: (row) => [ - row.subRows, - row.table.atoms.rowSelection?.get(), - row.table.options.enableRowSelection, - ], + computed: (row) => row_getIsSomeSelected(row), }, row_getIsAllSubRowsSelected: { - fn: (row) => row_getIsAllSubRowsSelected(row), - memoDeps: (row) => [ - row.subRows, - row.table.atoms.rowSelection?.get(), - row.table.options.enableRowSelection, - ], + computed: (row) => row_getIsAllSubRowsSelected(row), }, row_getCanSelect: { fn: (row) => row_getCanSelect(row), @@ -127,57 +117,28 @@ export const rowSelectionFeature: TableFeature = { fn: () => table_getPreSelectedRowModel(table), }, table_getSelectedRowModel: { - fn: () => table_getSelectedRowModel(table), - memoDeps: () => [ - table.atoms.rowSelection?.get(), - table.getCoreRowModel(), - ], + computed: () => table_getSelectedRowModel(table), }, table_getFilteredSelectedRowModel: { - fn: () => table_getFilteredSelectedRowModel(table), - memoDeps: () => [ - table.atoms.rowSelection?.get(), - table.getFilteredRowModel(), - ], + computed: () => table_getFilteredSelectedRowModel(table), }, table_getGroupedSelectedRowModel: { - fn: () => table_getGroupedSelectedRowModel(table), - memoDeps: () => [ - table.atoms.rowSelection?.get(), - table.getSortedRowModel(), - ], + computed: () => table_getGroupedSelectedRowModel(table), }, table_getSelectedRowIds: { - fn: () => table_getSelectedRowIds(table), - memoDeps: () => [table.atoms.rowSelection?.get()], + computed: () => table_getSelectedRowIds(table), }, table_getIsAllRowsSelected: { - fn: () => table_getIsAllRowsSelected(table), - memoDeps: () => [ - table.atoms.rowSelection?.get(), - table.getFilteredRowModel(), - table.options.enableRowSelection, - ], + computed: () => table_getIsAllRowsSelected(table), }, table_getIsAllPageRowsSelected: { - fn: () => table_getIsAllPageRowsSelected(table), - memoDeps: () => [ - table.atoms.rowSelection?.get(), - table.getPaginatedRowModel(), - table.options.enableRowSelection, - ], + computed: () => table_getIsAllPageRowsSelected(table), }, table_getIsSomeRowsSelected: { - fn: () => table_getIsSomeRowsSelected(table), - memoDeps: () => [table.atoms.rowSelection?.get()], + computed: () => table_getIsSomeRowsSelected(table), }, table_getIsSomePageRowsSelected: { - fn: () => table_getIsSomePageRowsSelected(table), - memoDeps: () => [ - table.atoms.rowSelection?.get(), - table.getPaginatedRowModel(), - table.options.enableRowSelection, - ], + computed: () => table_getIsSomePageRowsSelected(table), }, table_getToggleAllRowsSelectedHandler: { fn: () => table_getToggleAllRowsSelectedHandler(table), diff --git a/packages/table-core/src/features/row-selection/rowSelectionFeature.utils.ts b/packages/table-core/src/features/row-selection/rowSelectionFeature.utils.ts index a0c449799e..94fc500e12 100644 --- a/packages/table-core/src/features/row-selection/rowSelectionFeature.utils.ts +++ b/packages/table-core/src/features/row-selection/rowSelectionFeature.utils.ts @@ -5,6 +5,10 @@ import { hasOwn, makeObjectMap, } from '../../utils' +import { + row_getTrackedSubRows, + row_setSubRows, +} from '../../core/rows/subRowsTracking' import type { RowData, Updater } from '../../types/type-utils' import type { TableFeatures } from '../../types/TableFeatures' import type { RowModel } from '../../core/row-models/coreRowModelsFeature.types' @@ -807,17 +811,18 @@ function selectRowsRecursively< for (let i = 0; i < rows.length; i++) { const row = rows[i]! const isSelected = isRowSelected(row, rowSelection) + const subRows = row_getTrackedSubRows(row) if (isSelected) { selectedFlatRows.push(row) selectedRowsById[row.id] = row } - if (row.subRows.length) { + if (subRows.length) { // Always recurse — selected descendants of unselected parents must // still be collected into flatRows/rowsById. const newSubRows = selectRowsRecursively( - row.subRows, + subRows, rowSelection, selectedFlatRows, selectedRowsById, @@ -827,7 +832,7 @@ function selectRowsRecursively< // Preserve prototype chain so methods like getValue() remain accessible const cloned = Object.create(Object.getPrototypeOf(row)) copyInstancePropertiesWithoutMemos(cloned, row) - cloned.subRows = newSubRows + row_setSubRows(cloned, newSubRows) result.push(cloned) } } else if (isSelected) { @@ -901,15 +906,16 @@ export function isSubRowSelected< TFeatures extends TableFeatures, TData extends RowData, >(row: Row): boolean | 'some' | 'all' { - if (!row.subRows.length) return false + const subRows = row_getTrackedSubRows(row) + if (!subRows.length) return false const rowSelection = row.table.atoms.rowSelection?.get() ?? {} let someSelected = false let allChildrenSelected = true - for (let i = 0; i < row.subRows.length; i++) { - const subRow = row.subRows[i]! + for (let i = 0; i < subRows.length; i++) { + const subRow = subRows[i]! // Bail out early if we know both of these if (someSelected && !allChildrenSelected) { @@ -925,7 +931,7 @@ export function isSubRowSelected< } // Check row selection of nested subrows - if (subRow.subRows.length) { + if (row_getTrackedSubRows(subRow).length) { const subRowChildrenSelected = isSubRowSelected(subRow) if (subRowChildrenSelected === 'all') { someSelected = true diff --git a/packages/table-core/src/features/row-sorting/createSortedRowModel.ts b/packages/table-core/src/features/row-sorting/createSortedRowModel.ts index 2cd9a10eb3..2794a56195 100644 --- a/packages/table-core/src/features/row-sorting/createSortedRowModel.ts +++ b/packages/table-core/src/features/row-sorting/createSortedRowModel.ts @@ -1,4 +1,5 @@ import { copyInstancePropertiesWithoutMemos, tableMemo } from '../../utils' +import { row_setSubRows } from '../../core/rows/subRowsTracking' import { table_autoResetPageIndex } from '../row-pagination/rowPaginationFeature.utils' import { column_getCanSort, column_getSortFn } from './rowSortingFeature.utils' import type { Column_Internal } from '../../types/Column' @@ -31,10 +32,6 @@ export function createSortedRowModel< feature: 'rowSortingFeature', table, fnName: 'table.getSortedRowModel', - memoDeps: () => [ - table.atoms.sorting?.get(), - table.getPreSortedRowModel(), - ], fn: () => _createSortedRowModel(table), onAfterUpdate: () => table_autoResetPageIndex(table), }) @@ -166,7 +163,7 @@ function _createSortedRowModel< // Preserve prototype chain so methods like getValue() remain accessible const cloned = Object.create(Object.getPrototypeOf(row)) copyInstancePropertiesWithoutMemos(cloned, row) - cloned.subRows = sortedSubRows.rows + row_setSubRows(cloned, sortedSubRows.rows) sortedData[i] = cloned sortedFlatRows.push(cloned) changed = true diff --git a/packages/table-core/src/store-reactivity-bindings.ts b/packages/table-core/src/store-reactivity-bindings.ts index e463b87c84..8f99bea40a 100644 --- a/packages/table-core/src/store-reactivity-bindings.ts +++ b/packages/table-core/src/store-reactivity-bindings.ts @@ -1,9 +1,10 @@ import { batch, createAtom } from '@tanstack/store' +import { createStableStoreReadonlyAtom } from './core/reactivity/createStableStoreReadonlyAtom' import type { TableReactivityBindings } from './core/reactivity/coreReactivityFeature.types' /** - * TanStack Store–based reactivity for vanilla / non-framework use of `constructTable`, - * with `createOptionsStore: true` so `table.optionsStore` is available for subscriptions. + * TanStack Store–based reactivity for vanilla / non-framework use of + * `constructTable`. * * @example * ```ts @@ -18,7 +19,6 @@ import type { TableReactivityBindings } from './core/reactivity/coreReactivityFe */ export function storeReactivityBindings(): TableReactivityBindings { return { - createOptionsStore: true, wrapExternalAtoms: false, addSubscription: () => { throw new Error( @@ -34,7 +34,7 @@ export function storeReactivityBindings(): TableReactivityBindings { schedule: (fn) => queueMicrotask(fn), untrack: (fn) => fn(), createReadonlyAtom: (fn, options) => { - return createAtom(() => fn(), { + return createStableStoreReadonlyAtom(createAtom, fn, { compare: options?.compare, }) }, diff --git a/packages/table-core/src/types/Table.ts b/packages/table-core/src/types/Table.ts index a47bb20059..dff9136718 100644 --- a/packages/table-core/src/types/Table.ts +++ b/packages/table-core/src/types/Table.ts @@ -29,9 +29,10 @@ import type { BaseAtoms, BaseAtoms_All, ExternalAtoms_All, + TableOptionsLive, Table_Table, } from '../core/table/coreTablesFeature.types' -import type { DebugOptions, TableOptions_All } from './TableOptions' +import type { TableOptions_All } from './TableOptions' /** * The core table object that only includes the core table functionality such as column, header, row, and table APIS. @@ -105,12 +106,14 @@ export interface Table_Internal< Table_Headers { _rowModels: CachedRowModel_All _rowModelFns: RowModelFns_All - options: DebugOptions & - TableOptions_All & { - state?: TableState_All - initialState?: TableState_All - atoms?: ExternalAtoms_All - } + options: TableOptionsLive & + Readonly< + TableOptions_All & { + state?: TableState_All + initialState?: TableState_All + atoms?: ExternalAtoms_All + } + > initialState: TableState & TableState_All baseAtoms: BaseAtoms & BaseAtoms_All atoms: Atoms & Atoms_All diff --git a/packages/table-core/src/utils.ts b/packages/table-core/src/utils.ts index 81cd79b4f7..c18657c3a5 100755 --- a/packages/table-core/src/utils.ts +++ b/packages/table-core/src/utils.ts @@ -1,7 +1,8 @@ import type { Table_Internal } from './types/Table' -import type { NoInfer, RowData, Updater } from './types/type-utils' +import type { RowData, Updater } from './types/type-utils' import type { TableFeatures } from './types/TableFeatures' import type { TableState, TableState_All } from './types/TableState' +import type { ReadonlyAtom } from '@tanstack/store' /** * Applies a TanStack updater to a value. @@ -149,70 +150,13 @@ export function flattenBy( return flat } -interface MemoOptions, TDepArgs, TResult> { - fn: (...args: NoInfer) => TResult - memoDeps?: (depArgs?: TDepArgs) => [...TDeps] | undefined - onAfterCompare?: (depsChanged: boolean) => void - onAfterUpdate?: (result: TResult) => void - onBeforeCompare?: () => void - onBeforeUpdate?: () => void -} - -/** - * Creates a dependency-tracked memoized function for table internals. - * - * The memo recomputes only when its dependency tuple changes and can emit debug timing information. - */ -export const memo = , TDepArgs, TResult>({ - fn, - memoDeps, - onAfterCompare, - onAfterUpdate, - onBeforeCompare, - onBeforeUpdate, -}: MemoOptions): (( - depArgs?: TDepArgs, -) => TResult) => { - let deps: Array | undefined = [] - let result: TResult | undefined - - const memoizedFn = (depArgs?: TDepArgs): TResult => { - onBeforeCompare?.() - const newDeps = memoDeps?.(depArgs) - let depsChanged = !newDeps || newDeps.length !== deps?.length - if (!depsChanged && newDeps) { - for (let i = 0; i < newDeps.length; i++) { - if (newDeps[i] !== deps![i]) { - depsChanged = true - break - } - } - } - onAfterCompare?.(depsChanged) - - if (!depsChanged) { - return result! - } - - deps = newDeps - - onBeforeUpdate?.() - result = fn(...(newDeps ?? ([] as any))) - onAfterUpdate?.(result) - - return result - } - - return memoizedFn -} - interface TableMemoOptions< TFeatures extends TableFeatures, - TDeps extends ReadonlyArray, - TDepArgs, TResult, -> extends MemoOptions { +> { + compare?: (previous: TResult, next: TResult) => boolean feature?: keyof TFeatures & string + fn: () => TResult fnName: string objectId?: string onAfterUpdate?: () => void @@ -230,144 +174,167 @@ const pad = (str: number | string, num: number) => { /** * Creates a table-aware memoized function. * - * This wraps `memo` with table debug options and feature metadata so row models and derived APIs can share consistent diagnostics. + * The native readonly atom is created on the first public read so eager + * framework computeds cannot evaluate during incomplete table construction. */ export function tableMemo< TFeatures extends TableFeatures, - TDeps extends ReadonlyArray, - TDepArgs, TResult, >({ + compare, feature, + fn, fnName, objectId, onAfterUpdate, table, - ...memoOptions -}: TableMemoOptions) { - let beforeCompareTime: number - let afterCompareTime: number - let startCalcTime: number - let endCalcTime: number - let runCount = 0 - let debug: boolean | undefined - let debugCache: boolean | undefined - - if (process.env.NODE_ENV === 'development') { - const { debugAll } = table.options - const { parentName } = getFunctionNameInfo(fnName, '.') - - const debugByParent = - // @ts-expect-error - table.options[ - `debug${(parentName != 'table' ? parentName + 's' : parentName).replace( - parentName, - parentName.charAt(0).toUpperCase() + parentName.slice(1), - )}` - ] - const debugByFeature = feature - ? // @ts-expect-error - table.options[ - `debug${feature.charAt(0).toUpperCase() + feature.slice(1)}` - ] - : false - - debug = debugAll || debugByParent || debugByFeature +}: TableMemoOptions): () => TResult { + let atom: ReadonlyAtom | undefined + let evaluationCount = 0 + let hasStableResult = false + let stableResult: TResult + let debug = false + let debugCache = false + let debugInitialized = false + const isDevelopment = process.env.NODE_ENV === 'development' + + const initializeDebug = () => { + if (!isDevelopment || debugInitialized) { + return + } + debugInitialized = true + + table._reactivity.untrack(() => { + const options = table.options as unknown as Record< + PropertyKey, + unknown + > + const { parentName } = getFunctionNameInfo(fnName, '.') + const debugParent = ( + parentName !== 'table' ? `${parentName}s` : parentName + ).replace( + parentName, + parentName.charAt(0).toUpperCase() + parentName.slice(1), + ) + const debugByParent = options[`debug${debugParent}`] + const debugByFeature = feature + ? options[ + `debug${feature.charAt(0).toUpperCase() + feature.slice(1)}` + ] + : false + + debug = Boolean(options.debugAll || debugByParent || debugByFeature) + debugCache = Boolean(options.debugCache) + }) } - function logTime(time: number, depsChanged: boolean) { - const runType = - runCount === 0 + function logTime(time: number, evaluated: boolean) { + const runType = evaluated + ? evaluationCount === 1 ? '(1st run)' - : depsChanged - ? '(rerun #' + runCount + ')' - : '(cache)' - runCount++ + : `(rerun #${evaluationCount - 1})` + : '(cache)' console.groupCollapsed( `%c⏱ ${pad(`${time.toFixed(1)} ms`, 12)} %c${runType}%c ${fnName}%c ${objectId ? `(${fnName.split('.')[0]}Id: ${objectId})` : ''}`, `font-size: .6rem; font-weight: bold; ${ - depsChanged + evaluated ? `color: hsl( ${Math.max(0, Math.min(120 - Math.log10(time) * 60, 120))}deg 100% 31%);` : '' } `, - `color: ${runCount < 2 ? '#FF00FF' : '#FF1493'}`, + `color: ${evaluationCount < 2 ? '#FF00FF' : '#FF1493'}`, 'color: #666', 'color: #87CEEB', ) console.info({ feature, state: table.store.state, - deps: memoOptions.memoDeps?.toString(), }) console.trace() console.groupEnd() } - const onAfterUpdateHandler = () => { - if (!onAfterUpdate) { - return - } + const createAtom = () => { + initializeDebug() + atom = table._reactivity.createReadonlyAtom( + () => { + const startedAt = isDevelopment && debug ? performance.now() : 0 + let result: TResult + try { + const nextResult = fn() + result = + hasStableResult && compare?.(stableResult, nextResult) + ? stableResult + : nextResult + } catch (error) { + // A few native computed implementations clear their dirty flag + // even when evaluation or comparison throws. Drop this instance + // so the next public read can retry instead of returning a stale + // snapshot. + atom = undefined + throw error + } - const { schedule, untrack } = table._reactivity - schedule(() => untrack(() => onAfterUpdate())) - } + stableResult = result + hasStableResult = true + if (isDevelopment) { + evaluationCount++ + } - const debugOptions = - process.env.NODE_ENV === 'development' - ? { - onBeforeCompare: () => { - if (debugCache) { - beforeCompareTime = performance.now() - } - }, - onAfterCompare: (depsChanged: boolean) => { - if (debugCache) { - afterCompareTime = performance.now() - const compareTime = - Math.round((afterCompareTime - beforeCompareTime) * 100) / 100 - if (!depsChanged) { - logTime(compareTime, depsChanged) - } - } - }, - onBeforeUpdate: () => { - if (debug) { - startCalcTime = performance.now() - } - }, - onAfterUpdate: () => { - if (debug) { - endCalcTime = performance.now() - const executionTime = - Math.round((endCalcTime - startCalcTime) * 100) / 100 - logTime(executionTime, true) - } - onAfterUpdateHandler() - }, + if (isDevelopment && debug) { + const executionTime = + Math.round((performance.now() - startedAt) * 100) / 100 + table._reactivity.untrack(() => logTime(executionTime, true)) } - : { - onAfterUpdate: () => { - onAfterUpdateHandler() - }, + + if (onAfterUpdate) { + const { schedule, untrack } = table._reactivity + schedule(() => untrack(onAfterUpdate)) } - return memo({ - ...memoOptions, - ...debugOptions, - }) -} + return result + }, + { + debugName: fnName, + mode: 'memo', + }, + ) + return atom + } -export interface API<_TDeps extends ReadonlyArray, _TDepArgs> { - fn: (...args: any) => any - memoDeps?: (depArgs?: any) => [...any] | undefined + if (!isDevelopment) { + return () => (atom ?? createAtom()).get() + } + + return () => { + const startedAt = debugCache ? performance.now() : 0 + const beforeEvaluation = evaluationCount + const result = (atom ?? createAtom()).get() + + if (debugCache && evaluationCount === beforeEvaluation) { + const cacheTime = + Math.round((performance.now() - startedAt) * 100) / 100 + table._reactivity.untrack(() => logTime(cacheTime, false)) + } + + return result + } } -export type APIObject, TDepArgs> = Record< - string, - API -> +export type API = + | { + compare?: (previous: any, next: any) => boolean + computed: () => any + fn?: never + } + | { + compare?: never + computed?: never + fn: (...args: Array) => any + } + +export type APIObject = Record /** * Assumes that a function name is in the format of `parentName_fnKey` and returns the `fnKey` and `fnName` in the format of `parentName.fnKey`. @@ -392,37 +359,40 @@ export function getFunctionNameInfo( export function assignTableAPIs< TFeatures extends TableFeatures, TData extends RowData, - TDeps extends ReadonlyArray, - TDepArgs, >( feature: keyof TFeatures & string, table: Table_Internal, - apis: APIObject>, + apis: APIObject, ): void { - for (const [staticFnName, { fn, memoDeps }] of Object.entries(apis)) { + for (const [staticFnName, api] of Object.entries(apis)) { const { fnKey, fnName } = getFunctionNameInfo(staticFnName) - ;(table as Record)[fnKey] = memoDeps - ? tableMemo({ - memoDeps, - fn, - fnName, - table, - feature, - }) - : fn + ;(table as Record)[fnKey] = + 'computed' in api && api.computed + ? tableMemo({ + compare: api.compare, + fn: api.computed, + fnName, + table, + feature, + }) + : api.fn } } -export interface PrototypeAPI<_TDeps extends ReadonlyArray, _TDepArgs> { - fn: (self: any, ...args: any) => any - memoDeps?: (self: any, depArgs?: any) => [...any] | undefined -} +export type PrototypeAPI = + | { + compare?: (previous: any, next: any) => boolean + computed: (self: any) => any + fn?: never + } + | { + compare?: never + computed?: never + fn: (self: any, ...args: Array) => any + } -export type PrototypeAPIObject< - TDeps extends ReadonlyArray, - TDepArgs, -> = Record> +export type PrototypeAPIObject = Record /** * Assigns API methods to a prototype object for memory-efficient method sharing. @@ -434,41 +404,39 @@ export type PrototypeAPIObject< export function assignPrototypeAPIs< TFeatures extends TableFeatures, TData extends RowData, - TDeps extends ReadonlyArray, - TDepArgs, >( feature: keyof TFeatures & string, prototype: Record, table: Table_Internal, - apis: PrototypeAPIObject>, + apis: PrototypeAPIObject, ): void { - for (const [staticFnName, { fn, memoDeps }] of Object.entries(apis)) { + for (const [staticFnName, api] of Object.entries(apis)) { const { fnKey, fnName } = getFunctionNameInfo(staticFnName) - if (memoDeps) { + if ('computed' in api && api.computed) { // For memoized methods, create a function that lazily initializes // the memo on first access and stores it on the instance const memoKey = `_memo_${fnKey}` - prototype[fnKey] = function (this: any, ...args: Array) { + prototype[fnKey] = function (this: any) { // Lazily create memo on first access for this instance if (!this[memoKey]) { const self = this this[memoKey] = tableMemo({ - memoDeps: (depArgs) => memoDeps(self, depArgs), - fn: (...deps) => fn(self, ...deps), + compare: api.compare, + fn: () => api.computed(self), fnName, objectId: self.id, table, feature, }) } - return this[memoKey](...args) + return this[memoKey]() } } else { // Non-memoized methods just call the static function with `this` prototype[fnKey] = function (this: any, ...args: Array) { - return fn(this, ...args) + return api.fn(this, ...args) } } } diff --git a/packages/table-core/src/worker/createTableWorker.ts b/packages/table-core/src/worker/createTableWorker.ts index 61720ceb42..e9df2be9a6 100644 --- a/packages/table-core/src/worker/createTableWorker.ts +++ b/packages/table-core/src/worker/createTableWorker.ts @@ -13,6 +13,7 @@ import type { TableWorkerStage, TableWorkerStagePayload, } from './tableWorkerProtocol' +import type { Atom } from '@tanstack/store' // Importing anything from this module (e.g. `workerRowModelsFeature`) // registers the plugin key and its state slice with the core type maps, so @@ -71,7 +72,7 @@ export interface TableWorkerBridge { lastState: Record results: { [K in TableWorkerStage]?: TableWorkerDataPayload } /** Bumped per stage only when that stage's payload actually changed. */ - stageVersions: { [K in TableWorkerStage]?: number } + stageVersionAtoms: { [K in TableWorkerStage]?: Atom } } type AnyTable = Table_Internal @@ -156,13 +157,42 @@ export function getTableWorkerBridge( sentStageCount: 0, lastState: {}, results: {}, - stageVersions: {}, + stageVersionAtoms: {}, } tableWorker._bridges.set(table, bridge) } return bridge } +function getOrCreateStageVersionAtom( + table: AnyTable, + bridge: TableWorkerBridge, + stage: TableWorkerStage, +): Atom { + return (bridge.stageVersionAtoms[stage] ??= + table._reactivity.createWritableAtom(0, { + debugName: `table/worker/${stage}/version`, + })) +} + +/** + * Reads the version for one worker stage as a reactive dependency. + * + * The atom is lazy because only registered worker-backed stages need one. + * Unchanged worker payloads deliberately leave the version untouched, keeping + * the rebuilt row-model computed cached. + * + * @internal + */ +export function getTableWorkerStageVersion( + tableWorker: TableWorker, + table: AnyTable, + stage: TableWorkerStage, +): number { + const bridge = getTableWorkerBridge(tableWorker, table) + return getOrCreateStageVersionAtom(table, bridge, stage).get() +} + /** Shallow reference comparison; atoms return stable refs when unchanged. */ function statesEqual( a: Record | null, @@ -234,7 +264,8 @@ function handleResult( >) { if (payload.kind === 'unchanged') continue bridge.results[stage] = payload - bridge.stageVersions[stage] = (bridge.stageVersions[stage] ?? 0) + 1 + const versionAtom = getOrCreateStageVersionAtom(table, bridge, stage) + versionAtom.set((version) => version + 1) anyChanged = true if (stage === 'grouped') groupedChanged = true } diff --git a/packages/table-core/src/worker/createWorkerRowModel.ts b/packages/table-core/src/worker/createWorkerRowModel.ts index 7d2e7395de..91dbc81548 100644 --- a/packages/table-core/src/worker/createWorkerRowModel.ts +++ b/packages/table-core/src/worker/createWorkerRowModel.ts @@ -1,5 +1,9 @@ import { tableMemo } from '../utils' -import { getTableWorkerBridge, syncTableWorker } from './createTableWorker' +import { + getTableWorkerBridge, + getTableWorkerStageVersion, + syncTableWorker, +} from './createTableWorker' import { rebuildRowModel } from './rebuildRowModel' import { tableWorkerPipeline } from './tableWorkerProtocol' import type { RowModel } from '../core/row-models/coreRowModelsFeature.types' @@ -69,14 +73,13 @@ export function createWorkerRowModel( const memoized = tableMemo({ table, fnName: `table.get${capitalize(stage)}RowModel`, - // The per-stage version bumps only when this stage's payload actually - // changed, so stages the worker reported as `unchanged` skip the O(n) - // rebuild entirely (the re-render itself rides the state slice bump). - memoDeps: () => [ - table.getCoreRowModel(), - getTableWorkerBridge(tableWorker, table).stageVersions[stage], - ], fn: () => { + // The per-stage atom bumps only when this stage's payload actually + // changed, so stages the worker reported as `unchanged` skip the O(n) + // rebuild entirely (the re-render itself rides the state slice bump). + table.getCoreRowModel() + getTableWorkerStageVersion(tableWorker, table, stage) + const bridge = getTableWorkerBridge(tableWorker, table) const payload = bridge.results[stage] if (!payload) { diff --git a/packages/table-core/tests/implementation/features/row-pinning/rowPinningFeature.test.ts b/packages/table-core/tests/implementation/features/row-pinning/rowPinningFeature.test.ts index fd916d184a..091aa93393 100644 --- a/packages/table-core/tests/implementation/features/row-pinning/rowPinningFeature.test.ts +++ b/packages/table-core/tests/implementation/features/row-pinning/rowPinningFeature.test.ts @@ -191,6 +191,43 @@ describe('table methods', () => { expect(table.getTopRows()).toHaveLength(1) expect(table.getBottomRows()).toHaveLength(0) // Row 2 is not in visible rows }) + + it('keeps each pinned region cached when only its sibling changes', () => { + const table = makeTable({ + initialState: { + rowPinning: { + top: [ROW[0]], + bottom: [ROW[1]], + }, + }, + }) + const topRows = table.getTopRows() + const bottomRows = table.getBottomRows() + const initial = table.atoms.rowPinning.get() + + table.setRowPinning({ + top: initial.top, + bottom: [ROW[2]], + }) + + expect(table.getTopRows()).toBe(topRows) + + const next = table.atoms.rowPinning.get() + table.setRowPinning({ + top: [ROW[1]], + bottom: next.bottom, + }) + + expect(table.getBottomRows()).not.toBe(bottomRows) + const currentBottomRows = table.getBottomRows() + + table.setRowPinning({ + top: [ROW[0]], + bottom: table.atoms.rowPinning.get().bottom, + }) + + expect(table.getBottomRows()).toBe(currentBottomRows) + }) }) it('should handle keepPinnedRows - true', () => { diff --git a/packages/table-core/tests/implementation/features/row-selection/rowSelectionFeature.test.ts b/packages/table-core/tests/implementation/features/row-selection/rowSelectionFeature.test.ts index fec266e5cc..bce4f0174d 100644 --- a/packages/table-core/tests/implementation/features/row-selection/rowSelectionFeature.test.ts +++ b/packages/table-core/tests/implementation/features/row-selection/rowSelectionFeature.test.ts @@ -1,7 +1,6 @@ import { describe, expect, it, vi } from 'vitest' import { aggregationFns, - rowAggregationFeature, columnFilteringFeature, columnGroupingFeature, constructTable, @@ -9,6 +8,7 @@ import { createGroupedRowModel, createSortedRowModel, filterFns, + rowAggregationFeature, rowSelectionFeature, rowSortingFeature, sortFns, @@ -621,6 +621,52 @@ describe('rowSelectionFeature', () => { callsAfterFirst, ) }) + + it('invalidates recursive selection flags when subRows are replaced', () => { + const data = generateTestData(1, 2) + const table = constructTable({ + features, + data, + columns: generateColumnDefs(data), + getSubRows: (originalRow) => originalRow.subRows, + initialState: { + rowSelection: { '0.0': true }, + }, + }) + const parent = table.getRow('0') + + expect(parent.getIsSomeSelected()).toBe(true) + expect(parent.getIsAllSubRowsSelected()).toBe(false) + + parent.subRows = [parent.subRows[0]!] + + expect(parent.getIsSomeSelected()).toBe(false) + expect(parent.getIsAllSubRowsSelected()).toBe(true) + }) + + it('invalidates the selected row model when subRows are replaced', () => { + const data = generateTestData(1, 2) + const table = constructTable({ + features, + data, + columns: generateColumnDefs(data), + getSubRows: (originalRow) => originalRow.subRows, + initialState: { + rowSelection: { '0': true, '0.0': true }, + }, + }) + const parent = table.getRow('0') + const firstSelected = table.getSelectedRowModel() + + expect(firstSelected.flatRows.map((row) => row.id)).toEqual(['0', '0.0']) + + parent.subRows = [] + + const nextSelected = table.getSelectedRowModel() + expect(nextSelected).not.toBe(firstSelected) + expect(nextSelected.flatRows.map((row) => row.id)).toEqual(['0']) + expect(nextSelected.rows[0]!.subRows).toEqual([]) + }) }) describe('selected row models source the correct pipeline models', () => { diff --git a/packages/table-core/tests/unit/core/renderPhaseReactivity.test.ts b/packages/table-core/tests/unit/core/renderPhaseReactivity.test.ts index cebfc2fddb..93449550fe 100644 --- a/packages/table-core/tests/unit/core/renderPhaseReactivity.test.ts +++ b/packages/table-core/tests/unit/core/renderPhaseReactivity.test.ts @@ -40,6 +40,186 @@ afterEach(() => { }) describe('renderPhaseReactivity bindings', () => { + it('caches memo-mode reads within a render and refreshes after staging', () => { + const bindings = renderPhaseReactivity({ createAtom, batch }) + const option = bindings.createWritableAtom(1, { + debugName: 'option', + mode: 'staged', + }) + const evaluate = vi.fn(() => option.get() * 2) + const memo = bindings.createReadonlyAtom(evaluate, { + debugName: 'memo', + mode: 'memo', + }) + + expect(memo.get()).toBe(2) + expect(memo.get()).toBe(2) + expect(evaluate).toHaveBeenCalledTimes(1) + + option.set(2) + bindings.stage() + + expect(memo.get()).toBe(4) + expect(memo.get()).toBe(4) + expect(evaluate).toHaveBeenCalledTimes(2) + }) + + it('uses broad memo invalidation for a materially changed staged source', () => { + const bindings = renderPhaseReactivity({ createAtom, batch }) + const dependency = bindings.createWritableAtom(1, { + debugName: 'dependency', + mode: 'staged', + }) + const unrelated = bindings.createWritableAtom('before', { + debugName: 'unrelated', + mode: 'staged', + }) + const evaluate = vi.fn(() => ({ value: dependency.get() })) + const memo = bindings.createReadonlyAtom(evaluate, { + debugName: 'memo', + mode: 'memo', + }) + + const initial = memo.get() + + unrelated.set('after') + bindings.stage() + + expect(memo.get()).not.toBe(initial) + expect(evaluate).toHaveBeenCalledTimes(2) + }) + + it('publishes staged readonly values once for the committed token', () => { + const bindings = renderPhaseReactivity({ createAtom, batch }) + const option = bindings.createWritableAtom(1, { + debugName: 'option', + mode: 'staged', + }) + const projection = bindings.createReadonlyAtom(() => option.get(), { + debugName: 'projection', + }) + const notifications: Array = [] + const subscription = projection.subscribe((value) => { + notifications.push(value) + }) + + option.set(2) + const token = bindings.stage() + + expect(projection.get()).toBe(2) + expect(notifications).toEqual([]) + + bindings.commit(token) + bindings.commit(token) + + expect(notifications).toEqual([2]) + subscription.unsubscribe() + }) + + it('does not publish an abandoned staged value', () => { + const bindings = renderPhaseReactivity({ createAtom, batch }) + const option = bindings.createWritableAtom(1, { + debugName: 'option', + mode: 'staged', + }) + const projection = bindings.createReadonlyAtom(() => option.get(), { + debugName: 'projection', + }) + const notifications: Array = [] + const subscription = projection.subscribe((value) => { + notifications.push(value) + }) + + option.set(2) + const abandonedToken = bindings.stage() + expect(projection.get()).toBe(2) + + option.set(3) + const committedToken = bindings.stage() + expect(projection.get()).toBe(3) + + bindings.commit(committedToken) + bindings.commit(abandonedToken) + + expect(notifications).toEqual([3]) + subscription.unsubscribe() + }) + + it('does not publish newer staged values through an older commit token', () => { + const bindings = renderPhaseReactivity({ createAtom, batch }) + const option = bindings.createWritableAtom(1, { + debugName: 'option', + mode: 'staged', + }) + const projection = bindings.createReadonlyAtom(() => option.get(), { + debugName: 'projection', + }) + const notifications: Array = [] + const subscription = projection.subscribe((value) => { + notifications.push(value) + }) + + option.set(2) + const olderToken = bindings.stage() + option.set(3) + bindings.stage() + + bindings.commit(olderToken) + + expect(notifications).toEqual([]) + subscription.unsubscribe() + }) + + it('gates option atom publication and forwards the captured token', () => { + const { bindings, table, internalTable } = makeDeferredTable() + const nextData = [{ id: 'next' }] + const notifications: Array> = [] + const subscription = table.optionAtoms.data.subscribe((value) => { + notifications.push(value) + }) + const commitSpy = vi.spyOn(bindings, 'commit') + + const token = table_setOptions( + internalTable, + (options) => ({ + ...options, + data: nextData, + }), + { syncExternalState: false }, + ) + + expect(token).toEqual(expect.any(Number)) + expect(table.optionAtoms.data.get()).toBe(nextData) + expect(notifications).toEqual([]) + + table_publishExternalState(internalTable, null, undefined, token) + + expect(commitSpy).toHaveBeenCalledWith(token) + expect(notifications).toEqual([nextData]) + subscription.unsubscribe() + }) + + it('does not stage a source with unchanged option values', () => { + const { bindings, internalTable } = makeDeferredTable() + // The first merge installs construct-static undefined slots. Subsequent + // render merges with the same values should not rotate memo caches. + table_setOptions( + internalTable, + (options) => ({ ...options }), + { syncExternalState: false }, + ) + const stageSpy = vi.spyOn(bindings, 'stage') + + const token = table_setOptions( + internalTable, + (options) => ({ ...options }), + { syncExternalState: false }, + ) + + expect(token).toBe(bindings.getStageToken()) + expect(stageSpy).not.toHaveBeenCalled() + }) + it('invokes the commit hook on publish, including when nothing is published', () => { const { bindings, internalTable } = makeDeferredTable() const commitSpy = vi.spyOn(bindings, 'commit') diff --git a/packages/table-core/tests/unit/core/rows/constructRow.test.ts b/packages/table-core/tests/unit/core/rows/constructRow.test.ts index 69bef711aa..3266fdcc80 100644 --- a/packages/table-core/tests/unit/core/rows/constructRow.test.ts +++ b/packages/table-core/tests/unit/core/rows/constructRow.test.ts @@ -1,6 +1,7 @@ import { describe, expect, it } from 'vitest' import { constructTable } from '../../../../src' import { constructRow } from '../../../../src/core/rows/constructRow' +import { row_getLeafRows } from '../../../../src/core/rows/coreRowsFeature.utils' import { testFeatures } from '../../../fixtures/features' import type { Row } from '../../../../src/types/Row' @@ -90,4 +91,56 @@ describe('constructRow', () => { expect(nextLeafRows).not.toBe(firstLeafRows) expect(nextLeafRows).toEqual([leafB, leafA]) }) + + it('tracks nested subRows replacements in a readonly atom', () => { + const table = constructTable({ + features, + columns: [], + data: [], + }) + + const leafA = constructRow(table, 'leaf-a', { firstName: 'A' }, 0, 2, []) + const leafB = constructRow(table, 'leaf-b', { firstName: 'B' }, 0, 2, []) + const branch = constructRow( + table, + 'branch', + { firstName: 'Branch' }, + 0, + 1, + [leafA], + ) + const parent = constructRow( + table, + 'parent', + { firstName: 'Parent' }, + 0, + 0, + [branch], + ) + let evaluations = 0 + const leafRowsAtom = table._reactivity.createReadonlyAtom( + () => { + evaluations++ + return row_getLeafRows(parent) + }, + { debugName: 'test/nestedSubRows' }, + ) + + const firstLeafRows = leafRowsAtom.get() + expect(firstLeafRows).toEqual([branch, leafA]) + expect(leafRowsAtom.get()).toBe(firstLeafRows) + expect(evaluations).toBe(1) + + const sameSubRows = branch.subRows + branch.subRows = sameSubRows + expect(leafRowsAtom.get()).toBe(firstLeafRows) + expect(evaluations).toBe(1) + + branch.subRows = [leafB] + + const nextLeafRows = leafRowsAtom.get() + expect(nextLeafRows).not.toBe(firstLeafRows) + expect(nextLeafRows).toEqual([branch, leafB]) + expect(evaluations).toBe(2) + }) }) diff --git a/packages/table-core/tests/unit/core/table/tableOptionAtoms.test.ts b/packages/table-core/tests/unit/core/table/tableOptionAtoms.test.ts new file mode 100644 index 0000000000..61af32957b --- /dev/null +++ b/packages/table-core/tests/unit/core/table/tableOptionAtoms.test.ts @@ -0,0 +1,211 @@ +import { describe, expect, it, vi } from 'vitest' +import { constructTable } from '../../../../src' +import { testFeatures } from '../../../fixtures/features' + +function makeTable(extraOptions: Record = {}) { + return constructTable({ + features: testFeatures({}), + columns: [], + data: [], + ...extraOptions, + } as any) as any +} + +describe('table option atoms', () => { + it('types table.options readonly and ordinary option atoms writable', () => { + const table = constructTable({ + features: testFeatures({}), + columns: [], + data: [], + }) + + const assertOptionTypes = () => { + table.optionAtoms.data.set([]) + // @ts-expect-error table.options is a readonly projection + table.options.data = [] + // @ts-expect-error construction-only atoms are readonly + table.optionAtoms.features.set(testFeatures({})) + // @ts-expect-error construction-only atoms are readonly + table.optionAtoms.atoms?.set({}) + // @ts-expect-error construction-only atoms are readonly + table.optionAtoms.initialState?.set({}) + // @ts-expect-error aggregate snapshot version is readonly + table.optionAtoms.snapshotVersion.set(1) + } + + expect(assertOptionTypes).toBeTypeOf('function') + expect(table.options.data).toEqual([]) + }) + + it('keeps one readonly live options projection', () => { + const table = makeTable({ customOption: 'initial' }) + const savedOptions = table.options + const nextData = [{ id: 1 }] + + table.setOptions((previous: any) => ({ + ...previous, + customOption: 'updated', + data: nextData, + })) + + expect(table.options).toBe(savedOptions) + expect(savedOptions.customOption).toBe('updated') + expect(savedOptions.data).toBe(nextData) + expect(table.optionsStore).toBeUndefined() + }) + + it('updates writable option atoms and suppresses unrelated notifications', () => { + const table = makeTable({ customOption: 'initial' }) + const listener = vi.fn() + const subscription = table.optionAtoms.data.subscribe(listener) + const nextData = [{ id: 1 }] + + expect(table.optionAtoms.data.get()).toBe(table.options.data) + + table.optionAtoms.customOption.set('updated') + expect(table.options.customOption).toBe('updated') + expect(listener).not.toHaveBeenCalled() + + table.optionAtoms.data.set(nextData) + expect(table.options.data).toBe(nextData) + expect(listener).toHaveBeenCalledOnce() + expect(listener).toHaveBeenLastCalledWith(nextData) + + subscription.unsubscribe() + }) + + it('creates a missing atom when setOptions introduces its option', () => { + const table = makeTable() + + expect(table.optionAtoms.customOption).toBeUndefined() + expect(table.options.customOption).toBeUndefined() + + table.setOptions((previous: any) => ({ + ...previous, + customOption: 'created', + })) + + expect(table.optionAtoms.customOption.get()).toBe('created') + expect(table.options.customOption).toBe('created') + }) + + it('leaves omitted options unchanged and clears them with undefined', () => { + const table = makeTable({ + customOption: 'initial', + mergeOptions: (_current: unknown, next: unknown) => next, + }) + + table.setOptions(() => ({ data: [] })) + + expect(table.options.customOption).toBe('initial') + expect(table.optionAtoms.customOption.get()).toBe('initial') + + table.setOptions(() => ({ customOption: undefined })) + + expect(table.options.customOption).toBeUndefined() + expect(table.optionAtoms.customOption.get()).toBeUndefined() + }) + + it('keeps optionAtoms as a plain object and only proxies table.options', () => { + const symbolOption = Symbol('symbolOption') + const table = makeTable() + + table.setOptions((previous: any) => ({ + ...previous, + customOption: 'custom', + [symbolOption]: 'symbol', + })) + + expect(Object.getPrototypeOf(table.optionAtoms)).toBeNull() + expect(Reflect.ownKeys(table.options)).toEqual( + expect.arrayContaining(['customOption', symbolOption]), + ) + expect( + Object.getOwnPropertyDescriptor(table.options, 'customOption'), + ).toMatchObject({ + configurable: true, + enumerable: true, + value: 'custom', + writable: false, + }) + expect(table.options[symbolOption]).toBe('symbol') + expect(table.optionAtoms[symbolOption].get()).toBe('symbol') + }) + + it('rejects writes through table.options', () => { + const table = makeTable() + + expect(Reflect.set(table.options, 'data', [{ id: 1 }])).toBe(false) + expect(Reflect.deleteProperty(table.options, 'data')).toBe(false) + expect( + Reflect.defineProperty(table.options, 'data', { + configurable: true, + value: [{ id: 1 }], + }), + ).toBe(false) + expect(Reflect.preventExtensions(table.options)).toBe(false) + expect(Reflect.setPrototypeOf(table.options, {})).toBe(false) + expect(table.options.data).toEqual([]) + }) + + it('stores callback-valued options without invoking them', () => { + const callback = vi.fn(() => 'callback result') + const nextCallback = vi.fn(() => 'next callback result') + const table = makeTable({ callbackOption: callback }) + + expect(callback).not.toHaveBeenCalled() + expect(table.options.callbackOption).toBe(callback) + + // Function-valued atoms use the normal Atom updater contract. Wrapping + // returns the callback as a value instead of executing it as an updater. + table.optionAtoms.callbackOption.set(() => nextCallback) + + expect(table.options.callbackOption).toBe(nextCallback) + expect(callback).not.toHaveBeenCalled() + expect(nextCallback).not.toHaveBeenCalled() + }) + + it('publishes multi-option updates atomically through the binding batch', () => { + const table = makeTable({ + firstOption: 'first-before', + secondOption: 'second-before', + }) + const combined = table._reactivity.createReadonlyAtom( + () => + `${table.optionAtoms.firstOption.get()}:${table.optionAtoms.secondOption.get()}`, + { + debugName: 'table/options/combined-test', + }, + ) + const observations: Array = [] + const versions: Array = [] + const subscription = combined.subscribe((value: string) => { + observations.push(value) + }) + const versionSubscription = table.optionAtoms.snapshotVersion.subscribe( + (version: number) => { + versions.push(version) + }, + ) + + expect(table.optionAtoms.snapshotVersion.get()).toBe(0) + + table.setOptions((previous: any) => ({ + ...previous, + firstOption: 'first-after', + secondOption: 'second-after', + })) + + expect(observations).toEqual(['first-after:second-after']) + expect(table.optionAtoms.snapshotVersion.get()).toBe(1) + expect(versions).toEqual([1]) + + table.setOptions((previous: any) => ({ ...previous })) + + expect(table.optionAtoms.snapshotVersion.get()).toBe(1) + expect(versions).toEqual([1]) + + subscription.unsubscribe() + versionSubscription.unsubscribe() + }) +}) diff --git a/packages/table-core/tests/unit/features/column-ordering/columnOrderingFeature.utils.test.ts b/packages/table-core/tests/unit/features/column-ordering/columnOrderingFeature.utils.test.ts index c23ed77ce2..b09c5a816d 100644 --- a/packages/table-core/tests/unit/features/column-ordering/columnOrderingFeature.utils.test.ts +++ b/packages/table-core/tests/unit/features/column-ordering/columnOrderingFeature.utils.test.ts @@ -213,6 +213,27 @@ describe('table_resetColumnOrder', () => { }) describe('table_getOrderColumnsFn', () => { + it('recreates the memoized function when grouping behavior changes', () => { + const table = makeTable(3, { + groupedColumnMode: 'reorder', + }) + const getOrderColumnsFn = () => + (table as unknown as { getOrderColumnsFn: () => () => unknown }) + .getOrderColumnsFn() + + const initial = getOrderColumnsFn() + + table.setGrouping(['firstName']) + const afterGrouping = getOrderColumnsFn() + expect(afterGrouping).not.toBe(initial) + + table.setOptions((options) => ({ + ...options, + groupedColumnMode: 'remove', + })) + expect(getOrderColumnsFn()).not.toBe(afterGrouping) + }) + it('should return original columns when no column order is specified', () => { const table = makeTable(3) const columns = table.getAllLeafColumns() diff --git a/packages/table-core/tests/unit/features/column-pinning/columnPinningFeature.utils.test.ts b/packages/table-core/tests/unit/features/column-pinning/columnPinningFeature.utils.test.ts index 67f72ffaaf..e4e943e70a 100644 --- a/packages/table-core/tests/unit/features/column-pinning/columnPinningFeature.utils.test.ts +++ b/packages/table-core/tests/unit/features/column-pinning/columnPinningFeature.utils.test.ts @@ -13,29 +13,29 @@ import { column_pin, getDefaultColumnPinningState, row_getCenterVisibleCells, - row_getStartVisibleCells, row_getEndVisibleCells, + row_getStartVisibleCells, table_getCenterFlatHeaders, table_getCenterFooterGroups, table_getCenterHeaderGroups, table_getCenterLeafColumns, table_getCenterLeafHeaders, table_getCenterVisibleLeafColumns, + table_getEndFlatHeaders, + table_getEndFooterGroups, + table_getEndHeaderGroups, + table_getEndLeafColumns, + table_getEndLeafHeaders, + table_getEndVisibleLeafColumns, table_getIsSomeColumnsPinned, + table_getPinnedLeafColumns, + table_getPinnedVisibleLeafColumns, table_getStartFlatHeaders, table_getStartFooterGroups, table_getStartHeaderGroups, table_getStartLeafColumns, table_getStartLeafHeaders, table_getStartVisibleLeafColumns, - table_getPinnedLeafColumns, - table_getPinnedVisibleLeafColumns, - table_getEndFlatHeaders, - table_getEndFooterGroups, - table_getEndHeaderGroups, - table_getEndLeafColumns, - table_getEndLeafHeaders, - table_getEndVisibleLeafColumns, table_getVisibleLeafColumns, table_resetColumnPinning, table_setColumnPinning, @@ -501,6 +501,54 @@ describe('row_getEndVisibleCells', () => { }) }) +describe('column pinning selector boundaries', () => { + it('keeps start results cached when only end pinning changes', () => { + const table = makeTable(1, { + initialState: { + columnPinning: { + start: ['firstName'], + end: ['lastName'], + }, + }, + }) + const row = table.getRowModel().rows[0]! + const startCells = row.getStartVisibleCells() + const startHeaderGroups = table.getStartHeaderGroups() + const current = table.atoms.columnPinning.get() + + table.setColumnPinning({ + start: current.start, + end: ['age'], + }) + + expect(row.getStartVisibleCells()).toBe(startCells) + expect(table.getStartHeaderGroups()).toBe(startHeaderGroups) + }) + + it('keeps end results cached when only start pinning changes', () => { + const table = makeTable(1, { + initialState: { + columnPinning: { + start: ['firstName'], + end: ['lastName'], + }, + }, + }) + const row = table.getRowModel().rows[0]! + const endCells = row.getEndVisibleCells() + const endHeaderGroups = table.getEndHeaderGroups() + const current = table.atoms.columnPinning.get() + + table.setColumnPinning({ + start: ['age'], + end: current.end, + }) + + expect(row.getEndVisibleCells()).toBe(endCells) + expect(table.getEndHeaderGroups()).toBe(endHeaderGroups) + }) +}) + describe('table_getStartHeaderGroups', () => { it('should return header groups for start pinned columns', () => { const table = makeTable(1, { diff --git a/packages/table-core/tests/unit/features/column-resizing/columnResizingFeature.utils.test.ts b/packages/table-core/tests/unit/features/column-resizing/columnResizingFeature.utils.test.ts index 01c8ea8dfd..d3163e8f9f 100644 --- a/packages/table-core/tests/unit/features/column-resizing/columnResizingFeature.utils.test.ts +++ b/packages/table-core/tests/unit/features/column-resizing/columnResizingFeature.utils.test.ts @@ -285,7 +285,9 @@ describe('header_getResizeHandler', () => { enableColumnResizing: false, }) const onColumnResizingChange = vi.fn() - table.options.onColumnResizingChange = onColumnResizingChange + table.optionAtoms.onColumnResizingChange!.set( + () => onColumnResizingChange, + ) const header = createTestResizeHeader(table) const handler = header_getResizeHandler(header as any) @@ -297,7 +299,9 @@ describe('header_getResizeHandler', () => { it('should ignore multi-touch events', () => { const table = makeTable(1) const onColumnResizingChange = vi.fn() - table.options.onColumnResizingChange = onColumnResizingChange + table.optionAtoms.onColumnResizingChange!.set( + () => onColumnResizingChange, + ) const header = createTestResizeHeader(table) const handler = header_getResizeHandler(header as any) @@ -314,7 +318,7 @@ describe('header_getResizeHandler', () => { columnResizeMode: 'onChange', }) const onColumnSizingChange = vi.fn() - table.options.onColumnSizingChange = onColumnSizingChange + table.optionAtoms.onColumnSizingChange!.set(() => onColumnSizingChange) const header = createTestResizeHeader(table) const handler = header_getResizeHandler(header as any) @@ -336,21 +340,25 @@ describe('header_getResizeHandler', () => { }) let resizingState = getDefaultColumnResizingState() - table.options.onColumnResizingChange = (updater) => { - resizingState = - typeof updater === 'function' ? updater(resizingState) : updater - ;(table.store.state as any).columnResizing = resizingState - } + table.optionAtoms.onColumnResizingChange!.set( + () => (updater) => { + resizingState = + typeof updater === 'function' ? updater(resizingState) : updater + ;(table.store.state as any).columnResizing = resizingState + }, + ) const sizingUpdates: Array> = [] - table.options.onColumnSizingChange = (updater) => { - if (typeof updater === 'function') { - const result = updater(table.atoms.columnSizing.get()) - sizingUpdates.push(result) - } else { - sizingUpdates.push(updater) - } - } + table.optionAtoms.onColumnSizingChange!.set( + () => (updater) => { + if (typeof updater === 'function') { + const result = updater(table.atoms.columnSizing.get()) + sizingUpdates.push(result) + } else { + sizingUpdates.push(updater) + } + }, + ) const zeroSizeColumn = { ...table.getAllColumns()[0], @@ -392,12 +400,14 @@ describe('header_getResizeHandler', () => { let resizingState = getDefaultColumnResizingState() const resizingUpdates: Array = [] - table.options.onColumnResizingChange = (updater) => { - resizingState = - typeof updater === 'function' ? updater(resizingState) : updater - ;(table.store.state as any).columnResizing = resizingState - resizingUpdates.push(resizingState) - } + table.optionAtoms.onColumnResizingChange!.set( + () => (updater) => { + resizingState = + typeof updater === 'function' ? updater(resizingState) : updater + ;(table.store.state as any).columnResizing = resizingState + resizingUpdates.push(resizingState) + }, + ) const zeroSizeColumn = { ...table.getAllColumns()[0], @@ -447,7 +457,7 @@ describe('header_getResizeHandler', () => { columnResizeMode: 'onChange', }) const onColumnSizingChange = vi.fn() - table.options.onColumnSizingChange = onColumnSizingChange + table.optionAtoms.onColumnSizingChange!.set(() => onColumnSizingChange) const header = createTestResizeHeader(table) const handler = header_getResizeHandler(header as any, document) @@ -489,13 +499,15 @@ describe('header_getResizeHandler', () => { columnResizeMode: 'onChange', }) const sizingUpdates: Array> = [] - table.options.onColumnSizingChange = (updater) => { - sizingUpdates.push( - typeof updater === 'function' - ? updater(table.atoms.columnSizing.get()) - : updater, - ) - } + table.optionAtoms.onColumnSizingChange!.set( + () => (updater) => { + sizingUpdates.push( + typeof updater === 'function' + ? updater(table.atoms.columnSizing.get()) + : updater, + ) + }, + ) const header = createTestResizeHeader(table) const handler = header_getResizeHandler(header as any, document) @@ -548,13 +560,15 @@ describe('header_getResizeHandler', () => { columnResizeMode: 'onEnd', }) const sizingUpdates: Array> = [] - table.options.onColumnSizingChange = (updater) => { - sizingUpdates.push( - typeof updater === 'function' - ? updater(table.atoms.columnSizing.get()) - : updater, - ) - } + table.optionAtoms.onColumnSizingChange!.set( + () => (updater) => { + sizingUpdates.push( + typeof updater === 'function' + ? updater(table.atoms.columnSizing.get()) + : updater, + ) + }, + ) const header = createTestResizeHeader(table) const handler = header_getResizeHandler(header as any, document) @@ -610,13 +624,15 @@ describe('header_getResizeHandler', () => { columnResizeMode: 'onChange', }) const sizingUpdates: Array> = [] - table.options.onColumnSizingChange = (updater) => { - sizingUpdates.push( - typeof updater === 'function' - ? updater(table.atoms.columnSizing.get()) - : updater, - ) - } + table.optionAtoms.onColumnSizingChange!.set( + () => (updater) => { + sizingUpdates.push( + typeof updater === 'function' + ? updater(table.atoms.columnSizing.get()) + : updater, + ) + }, + ) const header = createTestResizeHeader(table) const handler = header_getResizeHandler(header as any, document) diff --git a/packages/table-core/tests/unit/features/column-sizing/columnSizingFeature.utils.test.ts b/packages/table-core/tests/unit/features/column-sizing/columnSizingFeature.utils.test.ts index f6431f34f5..0f9c724fa3 100644 --- a/packages/table-core/tests/unit/features/column-sizing/columnSizingFeature.utils.test.ts +++ b/packages/table-core/tests/unit/features/column-sizing/columnSizingFeature.utils.test.ts @@ -14,8 +14,8 @@ import { getDefaultColumnSizingState, table_getCenterTotalSize, table_getColumnOffsets, - table_getStartTotalSize, table_getEndTotalSize, + table_getStartTotalSize, table_getTotalSize, table_resetColumnSizing, table_setColumnSizing, @@ -488,6 +488,39 @@ describe('column_getSize', () => { expect(column_getSize(table.getColumn('a')!)).toBe(300) }) + + it('does not reevaluate a leaf column or header for a sibling size change', () => { + const table = makeTable({ + columns: [ + { id: 'a', accessorKey: 'a' }, + { id: 'b', accessorKey: 'b' }, + ], + }) + table.setColumnSizing({ a: 100, b: 150 }) + + const column = table.getColumn('a')! + const header = table.getHeaderGroups()[0]!.headers[0]! + let resolverReads = 0 + Object.defineProperty(column.columnDef, 'minSize', { + configurable: true, + get: () => { + resolverReads++ + return 20 + }, + }) + + expect(column.getSize()).toBe(100) + resolverReads = 0 + table.setColumnSizing({ a: 100, b: 200 }) + expect(column.getSize()).toBe(100) + expect(resolverReads).toBe(0) + + expect(header.getSize()).toBe(100) + resolverReads = 0 + table.setColumnSizing({ a: 100, b: 250 }) + expect(header.getSize()).toBe(100) + expect(resolverReads).toBe(0) + }) }) describe('column_resetSize', () => { diff --git a/packages/table-core/tests/unit/features/row-pinning/rowPinningFeature.utils.test.ts b/packages/table-core/tests/unit/features/row-pinning/rowPinningFeature.utils.test.ts index a147c18f24..f1699cd0a7 100644 --- a/packages/table-core/tests/unit/features/row-pinning/rowPinningFeature.utils.test.ts +++ b/packages/table-core/tests/unit/features/row-pinning/rowPinningFeature.utils.test.ts @@ -373,8 +373,7 @@ describe('row_getCanPin', () => { }) it('should return false when enableRowPinning is false', () => { - const table = makeTable(10) - table.options.enableRowPinning = false + const table = makeTable(10, { enableRowPinning: false }) const row = table.getRow('0') @@ -382,8 +381,7 @@ describe('row_getCanPin', () => { }) it('should return true when enableRowPinning is true', () => { - const table = makeTable(10) - table.options.enableRowPinning = true + const table = makeTable(10, { enableRowPinning: true }) const row = table.getRow('0') @@ -392,9 +390,7 @@ describe('row_getCanPin', () => { it('should use enableRowPinning function when provided', () => { const enableRowPinning = vi.fn((row) => row.id === '1') - const table = makeTable(10) - - table.options.enableRowPinning = enableRowPinning + const table = makeTable(10, { enableRowPinning }) const row0 = table.getRow('0') const row1 = table.getRow('1') diff --git a/packages/table-core/tests/unit/utils.test.ts b/packages/table-core/tests/unit/utils.test.ts index b839d48c7c..b6d67a226b 100644 --- a/packages/table-core/tests/unit/utils.test.ts +++ b/packages/table-core/tests/unit/utils.test.ts @@ -1,4 +1,5 @@ -import { describe, expect, test, vi } from 'vitest' +import { createAtom } from '@tanstack/store' +import { afterEach, describe, expect, test, vi } from 'vitest' import { callMemoOrStaticFn, cloneState, @@ -11,46 +12,273 @@ import { } from '../../src/utils' describe('tableMemo', () => { - test('does not schedule after-update work when no callback is provided', () => { - const schedule = vi.fn() + function createMemoTable( + overrides: Record = {}, + options: Record = {}, + ) { + return { + _reactivity: { + addSubscription: vi.fn(), + batch: (fn: () => void) => fn(), + createReadonlyAtom: ( + fn: () => unknown, + atomOptions?: { + compare?: (previous: unknown, next: unknown) => boolean + }, + ) => + createAtom(fn, { + compare: atomOptions?.compare, + }), + createWritableAtom: (value: unknown) => createAtom(value), + schedule: vi.fn((fn: () => void) => fn()), + untrack: (fn: () => unknown) => fn(), + wrapExternalAtoms: false, + ...overrides, + }, + options, + store: { state: {} }, + } as any + } + + afterEach(() => { + vi.restoreAllMocks() + vi.unstubAllEnvs() + }) + + test('is lazy and evaluates exactly once on the first read with an eager computed binding', () => { + const compute = vi.fn(() => 42) + const onAfterUpdate = vi.fn() + const schedule = vi.fn((fn: () => void) => fn()) + const createReadonlyAtom = vi.fn((fn: () => number) => { + const value = fn() + return { + get: () => value, + subscribe: vi.fn(), + } + }) + const table = createMemoTable({ createReadonlyAtom, schedule }) const memoized = tableMemo({ - table: { - options: {}, - _reactivity: { - schedule, - untrack: (fn: () => void) => fn(), - }, - } as any, + table, fnName: 'table.getValue', - fn: (value?: number) => value ?? 0, - memoDeps: (value?: number) => [value], + fn: compute, + onAfterUpdate, }) - expect(memoized(1)).toBe(1) - expect(memoized(2)).toBe(2) + expect(createReadonlyAtom).not.toHaveBeenCalled() + expect(compute).not.toHaveBeenCalled() expect(schedule).not.toHaveBeenCalled() + + expect(memoized()).toBe(42) + expect(createReadonlyAtom).toHaveBeenCalledOnce() + expect(compute).toHaveBeenCalledOnce() + expect(schedule).toHaveBeenCalledOnce() + expect(onAfterUpdate).toHaveBeenCalledOnce() + }) + + test('uses the native computed cache for repeated reads', () => { + const source = createAtom(1) + const compute = vi.fn(() => source.get() * 2) + const onAfterUpdate = vi.fn() + const table = createMemoTable() + const memoized = tableMemo({ + table, + fnName: 'table.getValue', + fn: compute, + onAfterUpdate, + }) + + expect(memoized()).toBe(2) + expect(memoized()).toBe(2) + expect(compute).toHaveBeenCalledOnce() + expect(onAfterUpdate).toHaveBeenCalledOnce() + }) + + test('reevaluates after a native dependency changes', () => { + const source = createAtom(1) + const compute = vi.fn(() => source.get() * 2) + const onAfterUpdate = vi.fn() + const table = createMemoTable() + const memoized = tableMemo({ + table, + fnName: 'table.getValue', + fn: compute, + onAfterUpdate, + }) + + expect(memoized()).toBe(2) + source.set(2) + expect(memoized()).toBe(4) + expect(compute).toHaveBeenCalledTimes(2) + expect(onAfterUpdate).toHaveBeenCalledTimes(2) + }) + + test('schedules after every successful evaluation even when comparison retains the previous result', () => { + const source = createAtom(1) + const compute = vi.fn(() => ({ parity: source.get() % 2 })) + const onAfterUpdate = vi.fn() + const table = createMemoTable() + const memoized = tableMemo({ + table, + fnName: 'table.getValue', + fn: compute, + compare: (previous, next) => previous.parity === next.parity, + onAfterUpdate, + }) + + const first = memoized() + source.set(3) + const second = memoized() + + expect(second).toBe(first) + expect(compute).toHaveBeenCalledTimes(2) + expect(onAfterUpdate).toHaveBeenCalledTimes(2) + }) + + test('applies the result comparator exactly once per reevaluation', () => { + const source = createAtom(1) + const compare = vi.fn( + (previous: { parity: number }, next: { parity: number }) => + previous.parity === next.parity, + ) + const table = createMemoTable() + const memoized = tableMemo({ + table, + fnName: 'table.getValue', + fn: () => ({ parity: source.get() % 2 }), + compare, + }) + + memoized() + source.set(3) + memoized() + + expect(compare).toHaveBeenCalledOnce() }) - test('schedules after-update work when a callback is provided', () => { + test('does not advance or schedule when result comparison throws', () => { + const source = createAtom(1) + const onAfterUpdate = vi.fn() const schedule = vi.fn((fn: () => void) => fn()) + const compare = vi + .fn<(previous: number, next: number) => boolean>() + .mockImplementationOnce(() => { + throw new Error('comparison failed') + }) + .mockReturnValue(false) + const table = createMemoTable({ schedule }) + const memoized = tableMemo({ + table, + fnName: 'table.getValue', + fn: () => source.get(), + compare, + onAfterUpdate, + }) + + expect(memoized()).toBe(1) + source.set(2) + expect(() => memoized()).toThrow('comparison failed') + expect(schedule).toHaveBeenCalledOnce() + expect(onAfterUpdate).toHaveBeenCalledOnce() + + expect(memoized()).toBe(2) + expect(schedule).toHaveBeenCalledTimes(2) + expect(onAfterUpdate).toHaveBeenCalledTimes(2) + }) + + test('does not advance or schedule when the computation throws', () => { + const source = createAtom(0) const onAfterUpdate = vi.fn() + const schedule = vi.fn((fn: () => void) => fn()) + const table = createMemoTable({ schedule }) + const memoized = tableMemo({ + table, + fnName: 'table.getValue', + fn: () => { + source.get() + throw new Error('no value') + }, + onAfterUpdate, + }) + + expect(() => memoized()).toThrow('no value') + expect(schedule).not.toHaveBeenCalled() + expect(onAfterUpdate).not.toHaveBeenCalled() + }) + + test('does not schedule after-update work when no callback is provided', () => { + const schedule = vi.fn() + const table = createMemoTable({ schedule }) + const memoized = tableMemo({ + table, + fnName: 'table.getValue', + fn: () => 1, + }) + + expect(memoized()).toBe(1) + expect(memoized()).toBe(1) + expect(schedule).not.toHaveBeenCalled() + }) + + test('schedules the untracked callback after returning the computed result', () => { + const scheduled: Array<() => void> = [] + const events: Array = [] + const schedule = vi.fn((fn: () => void) => { + events.push('schedule') + scheduled.push(fn) + }) + const untrack = vi.fn((fn: () => void) => { + events.push('untrack') + return fn() + }) + const onAfterUpdate = vi.fn(() => { + events.push('after') + }) + const table = createMemoTable({ schedule, untrack }) const memoized = tableMemo({ - table: { - options: {}, - _reactivity: { - schedule, - untrack: (fn: () => void) => fn(), - }, - } as any, + table, fnName: 'table.getValue', - fn: (value?: number) => value ?? 0, - memoDeps: (value?: number) => [value], + fn: () => { + events.push('compute') + return 1 + }, onAfterUpdate, }) - expect(memoized(1)).toBe(1) - expect(schedule).toHaveBeenCalledTimes(1) - expect(onAfterUpdate).toHaveBeenCalledTimes(1) + expect(memoized()).toBe(1) + events.push('returned') + expect(events).toEqual(['compute', 'schedule', 'returned']) + expect(onAfterUpdate).not.toHaveBeenCalled() + + scheduled[0]!() + expect(events).toEqual([ + 'compute', + 'schedule', + 'returned', + 'untrack', + 'after', + ]) + }) + + test('logs cache hits when debugCache is enabled', () => { + vi.stubEnv('NODE_ENV', 'development') + const groupCollapsed = vi + .spyOn(console, 'groupCollapsed') + .mockImplementation(() => {}) + vi.spyOn(console, 'info').mockImplementation(() => {}) + vi.spyOn(console, 'trace').mockImplementation(() => {}) + vi.spyOn(console, 'groupEnd').mockImplementation(() => {}) + const table = createMemoTable({}, { debugCache: true }) + const memoized = tableMemo({ + table, + fnName: 'table.getValue', + fn: () => 1, + }) + + memoized() + memoized() + + expect(groupCollapsed).toHaveBeenCalledOnce() + expect(groupCollapsed.mock.calls[0]?.[0]).toContain('(cache)') }) }) diff --git a/packages/table-devtools/src/TableDevtools.tsx b/packages/table-devtools/src/TableDevtools.tsx index a6e96ecec2..0f687b3557 100644 --- a/packages/table-devtools/src/TableDevtools.tsx +++ b/packages/table-devtools/src/TableDevtools.tsx @@ -1,3 +1,4 @@ +import { Show } from 'solid-js' import { ThemeContextProvider } from '@tanstack/devtools-ui' import { TableContextProvider } from './TableContextProvider' import { Shell } from './components/Shell' @@ -9,9 +10,11 @@ export default function TableDevtools(props: { }) { return ( - - - + + + + + ) } diff --git a/packages/table-devtools/src/components/ColumnsPanel.tsx b/packages/table-devtools/src/components/ColumnsPanel.tsx index 500e33a639..12e7b8cbcb 100644 --- a/packages/table-devtools/src/components/ColumnsPanel.tsx +++ b/packages/table-devtools/src/components/ColumnsPanel.tsx @@ -32,9 +32,9 @@ export function ColumnsPanel() { const styles = useStyles() const { table } = useTableDevtoolsContext() - const tableState = useTableStore( - () => table()?.store, - (state) => state, + const optionsVersion = useTableStore( + () => table()?.optionAtoms.snapshotVersion, + (version) => version, ) const columns = createMemo>(() => { @@ -43,7 +43,7 @@ export function ColumnsPanel() { return [] } - tableState() + optionsVersion() const tableWithColumnFns = tableInstance as unknown as { getAllFlatColumns?: () => Array diff --git a/packages/table-devtools/src/components/FeaturesPanel.tsx b/packages/table-devtools/src/components/FeaturesPanel.tsx index 6c839ff0ae..3eb73647a9 100644 --- a/packages/table-devtools/src/components/FeaturesPanel.tsx +++ b/packages/table-devtools/src/components/FeaturesPanel.tsx @@ -157,19 +157,15 @@ export function FeaturesPanel() { () => table()?.store, (state) => state, ) - const tableOptions = useTableStore( - () => { - const tableInstance = table() - return tableInstance?.optionsStore ?? tableInstance?.store - }, - () => table()?.options as unknown, + const optionsVersion = useTableStore( + () => table()?.optionAtoms.snapshotVersion, + (version) => version, ) const tableFeatures = createMemo((): Set => { const tableInstance = table() if (!tableInstance) return new Set() - tableState() return new Set(Object.keys(tableInstance._features)) }) @@ -177,8 +173,7 @@ export function FeaturesPanel() { const tableInstance = table() if (!tableInstance) return [] - tableState() - tableOptions() + optionsVersion() return Object.keys(tableInstance.options.features ?? {}).filter((key) => ROW_MODEL_FEATURE_SLOTS.includes(key), @@ -191,8 +186,7 @@ export function FeaturesPanel() { const tableInstance = table() if (!tableInstance) return [] - tableState() - tableOptions() + optionsVersion() const rowModelFns = toFnBuckets(tableInstance._rowModelFns) const optionFns = toFnBuckets(tableInstance.options) diff --git a/packages/table-devtools/src/components/OptionsPanel.tsx b/packages/table-devtools/src/components/OptionsPanel.tsx index e0753c4d0f..eff614e29f 100644 --- a/packages/table-devtools/src/components/OptionsPanel.tsx +++ b/packages/table-devtools/src/components/OptionsPanel.tsx @@ -20,17 +20,9 @@ export function OptionsPanel() { const styles = useStyles() const { table } = useTableDevtoolsContext() - const tableOptions = useTableStore( - () => { - const tableInstance = table() - return tableInstance?.optionsStore ?? tableInstance?.store - }, - () => { - const tableInstance = table() - return tableInstance - ? projectOptionsForTree(tableInstance.options) - : undefined - }, + const optionsVersion = useTableStore( + () => table()?.optionAtoms.snapshotVersion, + (version) => version, ) const options = createMemo(() => { @@ -39,7 +31,7 @@ export function OptionsPanel() { return undefined } - tableOptions() + optionsVersion() return projectOptionsForTree(tableInstance.options) }) diff --git a/packages/table-devtools/src/components/ResizableSplit.tsx b/packages/table-devtools/src/components/ResizableSplit.tsx index c8abfa661c..a19a411e0a 100644 --- a/packages/table-devtools/src/components/ResizableSplit.tsx +++ b/packages/table-devtools/src/components/ResizableSplit.tsx @@ -1,4 +1,4 @@ -import { createSignal } from 'solid-js' +import { createSignal, onCleanup } from 'solid-js' import { useStyles } from '../styles/use-styles' import type { JSX } from 'solid-js' @@ -14,14 +14,22 @@ interface ResizableSplitProps { export function ResizableSplit(props: ResizableSplitProps) { const styles = useStyles() const [leftPercent, setLeftPercent] = createSignal(DEFAULT_LEFT_PERCENT) + let cleanupDrag: (() => void) | undefined + + onCleanup(() => { + cleanupDrag?.() + }) const handleMouseDown = (e: MouseEvent) => { e.preventDefault() + cleanupDrag?.() - const onMouseMove = (moveEvent: MouseEvent) => { - const container = (e.target as HTMLElement).parentElement - if (!container) return + const container = (e.currentTarget as HTMLElement).parentElement + if (!container) return + const previousCursor = document.body.style.cursor + const previousUserSelect = document.body.style.userSelect + const onMouseMove = (moveEvent: MouseEvent) => { const rect = container.getBoundingClientRect() const x = moveEvent.clientX - rect.left const percent = Math.max( @@ -31,12 +39,14 @@ export function ResizableSplit(props: ResizableSplitProps) { setLeftPercent(percent) } - const onMouseUp = () => { + cleanupDrag = () => { document.removeEventListener('mousemove', onMouseMove) document.removeEventListener('mouseup', onMouseUp) - document.body.style.cursor = '' - document.body.style.userSelect = '' + document.body.style.cursor = previousCursor + document.body.style.userSelect = previousUserSelect + cleanupDrag = undefined } + const onMouseUp = () => cleanupDrag?.() document.addEventListener('mousemove', onMouseMove) document.addEventListener('mouseup', onMouseUp) diff --git a/packages/table-devtools/src/components/RowsPanel.tsx b/packages/table-devtools/src/components/RowsPanel.tsx index af45649ae9..873b4d0dab 100644 --- a/packages/table-devtools/src/components/RowsPanel.tsx +++ b/packages/table-devtools/src/components/RowsPanel.tsx @@ -51,12 +51,9 @@ export function RowsPanel() { () => table()?.store, (state) => state, ) - const tableOptions = useTableStore( - () => { - const tableInstance = table() - return tableInstance?.optionsStore ?? tableInstance?.store - }, - () => table()?.options as unknown, + const optionsVersion = useTableStore( + () => table()?.optionAtoms.snapshotVersion, + (version) => version, ) const [selectedRowModel, setSelectedRowModel] = @@ -66,8 +63,7 @@ export function RowsPanel() { const tableInstance = table() if (!tableInstance) return undefined - tableState() - tableOptions() + optionsVersion() const data = tableInstance.options.data as ReadonlyArray if (!Array.isArray(data)) return data @@ -79,8 +75,7 @@ export function RowsPanel() { const tableInstance = table() if (!tableInstance) return 0 - tableState() - tableOptions() + optionsVersion() const data = tableInstance.options.data as ReadonlyArray return Array.isArray(data) ? data.length : 0 @@ -91,7 +86,7 @@ export function RowsPanel() { if (!tableInstance) return [] tableState() - tableOptions() + optionsVersion() const tableWithColumnFns = tableInstance as unknown as { getVisibleLeafColumns?: () => Array @@ -221,18 +216,25 @@ export function RowsPanel() { - {(row) => ( - - {row.id} - - {(cell) => ( - - {stringifyValue(cell.getValue())} - - )} - - - )} + {(row) => { + const cells = createMemo(() => { + tableState() + return getCells(row) + }) + + return ( + + {row.id} + + {(cell) => ( + + {stringifyValue(cell.getValue())} + + )} + + + ) + }} diff --git a/packages/table-devtools/src/components/Shell.tsx b/packages/table-devtools/src/components/Shell.tsx index 3da49071db..56ecbdb32c 100644 --- a/packages/table-devtools/src/components/Shell.tsx +++ b/packages/table-devtools/src/components/Shell.tsx @@ -25,7 +25,6 @@ export function Shell() { setActiveTab, selectedTargetId, setSelectedTargetId, - table, targets, } = useTableDevtoolsContext() @@ -81,8 +80,8 @@ export function Shell() {
- - {(_table) => ( + + {(_selectedTargetId) => ( diff --git a/packages/table-devtools/src/components/StatePanel.tsx b/packages/table-devtools/src/components/StatePanel.tsx index 0095b61075..d04999af3e 100644 --- a/packages/table-devtools/src/components/StatePanel.tsx +++ b/packages/table-devtools/src/components/StatePanel.tsx @@ -6,15 +6,11 @@ import { useTableStore } from '../useTableStore' import { useStyles } from '../styles/use-styles' import { NoTableConnected } from './NoTableConnected' import { ThreeWayResizableSplit } from './ThreeWayResizableSplit' +import type { Accessor } from 'solid-js' +import type { TableDevtoolsStyles } from '../styles/use-styles' type AtomSource = 'external-atom' | 'external-state' | 'internal' -interface AtomSlice { - key: string - value: unknown - source: AtomSource -} - export function StatePanel() { const styles = useStyles() const { table } = useTableDevtoolsContext() @@ -22,75 +18,60 @@ export function StatePanel() { const [storeCopied, setStoreCopied] = createSignal(false) const [pasteError, setPasteError] = createSignal(null) - // Subscribe to both stores so the panel re-renders when either the table - // state or the options (e.g. options.atoms / options.state) change. const tableState = useTableStore( () => table()?.store, (state) => state, ) - const tableOptions = useTableStore( - () => { - const tableInstance = table() - return tableInstance?.optionsStore ?? tableInstance?.store - }, - () => table()?.options as unknown, + const optionsVersion = useTableStore( + () => table()?.optionAtoms.snapshotVersion, + (version) => version, ) const initialState = createMemo((): unknown => { const tableInstance = table() if (!tableInstance) return undefined - tableState() - tableOptions() - return tableInstance.initialState }) - const storeState = createMemo((): unknown => { + const storeState = createMemo((): Record | undefined => { const tableInstance = table() if (!tableInstance) return undefined - tableState() - tableOptions() - - return tableInstance.store.state + return (tableState() ?? tableInstance.store.get()) as Record< + string, + unknown + > }) - const atomSlices = createMemo((): Array => { + const tableOptions = createMemo | undefined>(() => { const tableInstance = table() - if (!tableInstance) return [] + if (!tableInstance) return undefined + + optionsVersion() + return tableInstance.options + }) - // Touch subscriptions so this recomputes on state or option change. - tableState() - tableOptions() + const atomKeys = createMemo(() => Object.keys(storeState() ?? {})) - const options = tableInstance.options as unknown as Record + const getAtomSource = (key: string): AtomSource => { + const options = tableOptions() ?? {} const externalAtoms = (options.atoms as Record | undefined) ?? {} const externalState = (options.state as Record | undefined) ?? {} - const storeState = tableInstance.store.state as Record - - return Object.keys(storeState).map((key) => { - const hasExternalAtom = externalAtoms[key] != null - const hasExternalState = - !hasExternalAtom && - key in externalState && - externalState[key] !== undefined - - const source: AtomSource = hasExternalAtom - ? 'external-atom' - : hasExternalState - ? 'external-state' - : 'internal' - - return { - key, - value: storeState[key], - source, - } - }) - }) + const hasExternalAtom = externalAtoms[key] != null + const hasExternalState = + !hasExternalAtom && + key in externalState && + externalState[key] !== undefined + + return hasExternalAtom + ? 'external-atom' + : hasExternalState + ? 'external-state' + : 'internal' + } const copyToClipboard = async ( value: unknown, @@ -177,8 +158,15 @@ export function StatePanel() { Reset to initialState
- - {(slice) => } + + {(key) => ( + getAtomSource(key)} + styles={styles} + value={() => storeState()?.[key]} + /> + )} } @@ -213,11 +201,14 @@ export function StatePanel() { ) } -function AtomRow(props: { slice: AtomSlice }) { - const styles = useStyles() - +function AtomRow(props: { + atomKey: string + source: Accessor + styles: Accessor + value: Accessor +}) { const badgeLabel = () => { - switch (props.slice.source) { + switch (props.source()) { case 'external-atom': return 'External Atom' case 'external-state': @@ -228,25 +219,25 @@ function AtomRow(props: { slice: AtomSlice }) { } const badgeClass = () => { - const base = styles().atomBadge - switch (props.slice.source) { + const base = props.styles().atomBadge + switch (props.source()) { case 'external-atom': - return `${base} ${styles().atomBadgeExternalAtom}` + return `${base} ${props.styles().atomBadgeExternalAtom}` case 'external-state': - return `${base} ${styles().atomBadgeExternalState}` + return `${base} ${props.styles().atomBadgeExternalState}` case 'internal': - return `${base} ${styles().atomBadgeInternal}` + return `${base} ${props.styles().atomBadgeInternal}` } } return ( -
-
- {props.slice.key} +
+
+ {props.atomKey} {badgeLabel()}
-
- +
+
) diff --git a/packages/table-devtools/src/components/ThreeWayResizableSplit.tsx b/packages/table-devtools/src/components/ThreeWayResizableSplit.tsx index 3a5803172e..098752c91b 100644 --- a/packages/table-devtools/src/components/ThreeWayResizableSplit.tsx +++ b/packages/table-devtools/src/components/ThreeWayResizableSplit.tsx @@ -1,4 +1,4 @@ -import { createSignal } from 'solid-js' +import { createSignal, onCleanup } from 'solid-js' import { useStyles } from '../styles/use-styles' import type { JSX } from 'solid-js' @@ -17,15 +17,24 @@ export function ThreeWayResizableSplit(props: ThreeWayResizableSplitProps) { const styles = useStyles() const [leftPercent, setLeftPercent] = createSignal(DEFAULT_LEFT_PERCENT) const [middlePercent, setMiddlePercent] = createSignal(DEFAULT_MIDDLE_PERCENT) + let cleanupDrag: (() => void) | undefined + + onCleanup(() => { + cleanupDrag?.() + }) const makeDragHandler = (which: 'left' | 'right'): ((e: MouseEvent) => void) => // eslint-disable-next-line solid/reactivity (e) => { e.preventDefault() + cleanupDrag?.() + const handleEl = e.currentTarget as HTMLElement const container = handleEl.parentElement if (!container) return + const previousCursor = document.body.style.cursor + const previousUserSelect = document.body.style.userSelect const startLeft = leftPercent() const startMiddle = middlePercent() @@ -56,12 +65,14 @@ export function ThreeWayResizableSplit(props: ThreeWayResizableSplitProps) { } } - const onMouseUp = () => { + cleanupDrag = () => { document.removeEventListener('mousemove', onMouseMove) document.removeEventListener('mouseup', onMouseUp) - document.body.style.cursor = '' - document.body.style.userSelect = '' + document.body.style.cursor = previousCursor + document.body.style.userSelect = previousUserSelect + cleanupDrag = undefined } + const onMouseUp = () => cleanupDrag?.() document.addEventListener('mousemove', onMouseMove) document.addEventListener('mouseup', onMouseUp) diff --git a/packages/table-devtools/src/index.ts b/packages/table-devtools/src/index.ts index 1c5d82106e..a1ff6af3e8 100644 --- a/packages/table-devtools/src/index.ts +++ b/packages/table-devtools/src/index.ts @@ -10,6 +10,7 @@ export const TableDevtoolsCore: ClassType = export type { TableDevtoolsInit } from './core' export { + createTableDevtoolsRegistrationManager, getTableDevtoolsTargets, removeTableDevtoolsTarget, setTableDevtoolsTarget, @@ -18,6 +19,7 @@ export { } from './tableTarget' export type { TableDevtoolsRegistration, + TableDevtoolsRegistrationManager, TableDevtoolsStore, TableDevtoolsTable, UpsertTableDevtoolsTargetOptions, diff --git a/packages/table-devtools/src/production.ts b/packages/table-devtools/src/production.ts index df414118c9..d39c265b89 100644 --- a/packages/table-devtools/src/production.ts +++ b/packages/table-devtools/src/production.ts @@ -4,6 +4,7 @@ export { TableDevtoolsCore } from './core' export type { TableDevtoolsInit } from './core' export { + createTableDevtoolsRegistrationManager, getTableDevtoolsTargets, removeTableDevtoolsTarget, setTableDevtoolsTarget, @@ -12,6 +13,7 @@ export { } from './tableTarget' export type { TableDevtoolsRegistration, + TableDevtoolsRegistrationManager, TableDevtoolsStore, TableDevtoolsTable, UpsertTableDevtoolsTargetOptions, diff --git a/packages/table-devtools/src/styles/use-styles.ts b/packages/table-devtools/src/styles/use-styles.ts index 2793262938..1eae90b6e2 100644 --- a/packages/table-devtools/src/styles/use-styles.ts +++ b/packages/table-devtools/src/styles/use-styles.ts @@ -1,5 +1,5 @@ import * as goober from 'goober' -import { createEffect, createSignal } from 'solid-js' +import { createMemo } from 'solid-js' import { createTheme } from '@tanstack/devtools-ui' import { tokens } from './tokens' @@ -398,11 +398,21 @@ const stylesFactory = (theme: 'light' | 'dark') => { export function useStyles() { const { theme } = createTheme() - const [styles, setStyles] = createSignal(stylesFactory(theme())) + const styles = createMemo(() => getStyles(theme())) + return styles +} + +export type TableDevtoolsStyles = ReturnType - createEffect(() => { - setStyles(stylesFactory(theme())) - }) +const stylesByTheme = new Map<'light' | 'dark', TableDevtoolsStyles>() + +function getStyles(theme: 'light' | 'dark'): TableDevtoolsStyles { + const cached = stylesByTheme.get(theme) + if (cached) { + return cached + } + const styles = stylesFactory(theme) + stylesByTheme.set(theme, styles) return styles } diff --git a/packages/table-devtools/src/tableTarget.ts b/packages/table-devtools/src/tableTarget.ts index ab6d4c4a90..b3a349bba1 100644 --- a/packages/table-devtools/src/tableTarget.ts +++ b/packages/table-devtools/src/tableTarget.ts @@ -24,7 +24,9 @@ export interface TableDevtoolsTable { state?: Record [key: string]: unknown } - optionsStore?: TableDevtoolsStore + optionAtoms: { + snapshotVersion: Readable + } reset: () => void store: TableDevtoolsStore } @@ -34,6 +36,11 @@ export interface TableDevtoolsRegistration { table: TableDevtoolsTable } +interface TableDevtoolsRegistrationEntry { + registration: TableDevtoolsRegistration + leases: Set +} + export interface UpsertTableDevtoolsTargetOptions< TFeatures extends TableFeatures, TData extends RowData, @@ -41,8 +48,16 @@ export interface UpsertTableDevtoolsTargetOptions< table: Table } +export interface TableDevtoolsRegistrationManager { + update: ( + table: Table | undefined, + enabled?: boolean, + ) => void + dispose: () => void +} + const [registrationsMap, setRegistrationsMap] = createSignal< - Map + Map >(new Map()) function getTableKey(table: TableDevtoolsTable) { @@ -63,33 +78,59 @@ export function upsertTableDevtoolsTarget< } const registrations = untrack(registrationsMap) - const existingRegistration = registrations.get(key) - - if (existingRegistration) { - if (existingRegistration.table === table) { + const existingEntry = registrations.get(key) + const lease = Symbol(key) + + if (existingEntry) { + if ( + existingEntry.registration.table === table || + existingEntry.registration.table.store === table.store + ) { + if (existingEntry.registration.table !== table) { + Object.assign(existingEntry.registration.table, table) + } + existingEntry.leases.add(lease) return () => { - removeTableDevtoolsTarget(key) + releaseTableDevtoolsTarget(key, lease) } } const nextRegistrations = new Map(registrations) nextRegistrations.set(key, { - id: key, - table, + registration: { + id: key, + table, + }, + leases: new Set([lease]), }) setRegistrationsMap(nextRegistrations) } else { const nextRegistrations = new Map(registrations) nextRegistrations.set(key, { - id: key, - table, + registration: { + id: key, + table, + }, + leases: new Set([lease]), }) setRegistrationsMap(nextRegistrations) } return () => { - removeTableDevtoolsTarget(key) + releaseTableDevtoolsTarget(key, lease) + } +} + +function releaseTableDevtoolsTarget(id: string, lease: symbol) { + const registrations = untrack(registrationsMap) + const entry = registrations.get(id) + if (!entry?.leases.delete(lease) || entry.leases.size > 0) { + return } + + const nextRegistrations = new Map(registrations) + nextRegistrations.delete(id) + setRegistrationsMap(nextRegistrations) } export function removeTableDevtoolsTarget(id: string) { @@ -105,7 +146,7 @@ export function removeTableDevtoolsTarget(id: string) { } export function getTableDevtoolsTargets(): Array { - return Array.from(registrationsMap().values()) + return Array.from(registrationsMap().values(), (entry) => entry.registration) } export function subscribeTableDevtoolsTargets(listener: Listener) { @@ -129,3 +170,25 @@ export function setTableDevtoolsTarget< upsertTableDevtoolsTarget({ table }) } + +export function createTableDevtoolsRegistrationManager(): TableDevtoolsRegistrationManager { + let cleanup: (() => void) | undefined + + return { + update: (table, enabled = true) => { + if (!enabled || !table) { + cleanup?.() + cleanup = undefined + return + } + + const previousCleanup = cleanup + cleanup = upsertTableDevtoolsTarget({ table }) + previousCleanup?.() + }, + dispose: () => { + cleanup?.() + cleanup = undefined + }, + } +} diff --git a/packages/table-devtools/src/useTableStore.ts b/packages/table-devtools/src/useTableStore.ts index 70fbfa2ec4..0dd8ffcd44 100644 --- a/packages/table-devtools/src/useTableStore.ts +++ b/packages/table-devtools/src/useTableStore.ts @@ -2,30 +2,44 @@ import { createEffect, createSignal, onCleanup } from 'solid-js' import type { Accessor } from 'solid-js' import type { Readable } from '@tanstack/solid-store' +interface UseTableStoreOptions { + equals?: false | ((previous: U | undefined, next: U | undefined) => boolean) +} + /** * Subscribes to a table store and returns a reactive signal. - * Handles both subscribe APIs: function return (store 0.8.x) and - * { unsubscribe } object return (store 0.9.x). + * Handles both function and `{ unsubscribe }` subscription results. */ export function useTableStore( storeAccessor: Accessor | null | undefined>, selector: (state: T) => U = (s) => s as unknown as U, + options?: UseTableStoreOptions, ): Accessor { - const initialValue = storeAccessor()?.get() - const [signal, setSignal] = createSignal( - initialValue ? selector(initialValue) : undefined, + const initialStore = storeAccessor() + const [signal, setSignal] = createSignal( + initialStore ? selector(initialStore.get()) : undefined, + { equals: options?.equals }, ) createEffect(() => { const store = storeAccessor() - if (!store) return + if (!store) { + setSignal(() => undefined) + return + } - const subscription = store.subscribe(() => { - setSignal(() => selector(store.get())) - }) + setSignal(() => selector(store.get())) + + const subscription = store.subscribe((snapshot) => { + setSignal(() => selector(snapshot)) + }) as unknown as { unsubscribe: () => void } | (() => void) onCleanup(() => { - subscription.unsubscribe() + if (typeof subscription === 'function') { + subscription() + } else { + subscription.unsubscribe() + } }) }) diff --git a/packages/table-devtools/tests/panel-lifecycle.test.tsx b/packages/table-devtools/tests/panel-lifecycle.test.tsx new file mode 100644 index 0000000000..04f9e0dc1e --- /dev/null +++ b/packages/table-devtools/tests/panel-lifecycle.test.tsx @@ -0,0 +1,74 @@ +import { createSignal } from 'solid-js' +import { render } from 'solid-js/web' +import { afterEach, describe, expect, it, vi } from 'vitest' +import TableDevtools from '../src/TableDevtools' +import { + getTableDevtoolsTargets, + removeTableDevtoolsTarget, + upsertTableDevtoolsTarget, +} from '../src/tableTarget' +import type { TableDevtoolsTable } from '../src/tableTarget' + +function createDevtoolsTable() { + const unsubscribe = vi.fn() + const subscribe = vi.fn(() => ({ unsubscribe })) + const table = { + _features: {}, + _rowModelFns: {}, + baseAtoms: {}, + initialState: {}, + options: { + features: {}, + key: 'users-table', + }, + optionAtoms: { + snapshotVersion: { + get: () => 0, + subscribe: () => ({ unsubscribe: () => {} }), + }, + }, + reset: vi.fn(), + store: { + get: () => ({}), + state: {}, + subscribe, + }, + } satisfies TableDevtoolsTable + + return { subscribe, table, unsubscribe } +} + +afterEach(() => { + for (const target of getTableDevtoolsTargets()) { + removeTableDevtoolsTarget(target.id) + } +}) + +describe('TableDevtools panel lifecycle', () => { + it('subscribes only while the devtools panel is open', async () => { + const { subscribe, table, unsubscribe } = createDevtoolsTable() + const cleanupTarget = upsertTableDevtoolsTarget({ + table: table as never, + }) + const [open, setOpen] = createSignal(false) + const element = document.createElement('div') + const dispose = render( + () => , + element, + ) + + await Promise.resolve() + expect(subscribe).not.toHaveBeenCalled() + + setOpen(true) + await Promise.resolve() + expect(subscribe).toHaveBeenCalledTimes(1) + + setOpen(false) + await Promise.resolve() + expect(unsubscribe).toHaveBeenCalledTimes(1) + + dispose() + cleanupTarget?.() + }) +}) diff --git a/packages/table-devtools/tests/styles.test.tsx b/packages/table-devtools/tests/styles.test.tsx new file mode 100644 index 0000000000..28dc5444f3 --- /dev/null +++ b/packages/table-devtools/tests/styles.test.tsx @@ -0,0 +1,51 @@ +import { createSignal } from 'solid-js' +import { render } from 'solid-js/web' +import { ThemeContextProvider } from '@tanstack/devtools-ui' +import { beforeEach, describe, expect, it, vi } from 'vitest' + +const { css } = vi.hoisted(() => ({ + css: vi.fn(() => 'generated-class'), +})) + +vi.mock('goober', () => ({ + css, +})) + +beforeEach(() => { + css.mockClear() +}) + +describe('useStyles', () => { + it('generates each theme once across consumers', async () => { + const { useStyles } = await import('../src/styles/use-styles') + const [theme, setTheme] = createSignal<'light' | 'dark'>('dark') + + function Consumer() { + useStyles() + useStyles() + return null + } + + const element = document.createElement('div') + const dispose = render( + () => ( + + + + ), + element, + ) + + expect(css).toHaveBeenCalledTimes(51) + + setTheme('light') + await Promise.resolve() + expect(css).toHaveBeenCalledTimes(102) + + setTheme('dark') + await Promise.resolve() + expect(css).toHaveBeenCalledTimes(102) + + dispose() + }) +}) diff --git a/packages/table-devtools/tests/tableTarget.test.ts b/packages/table-devtools/tests/tableTarget.test.ts index 0f1d1082ea..8595cae9f8 100644 --- a/packages/table-devtools/tests/tableTarget.test.ts +++ b/packages/table-devtools/tests/tableTarget.test.ts @@ -2,8 +2,10 @@ import { afterEach, describe, expect, it, vi } from 'vitest' import { constructTable, coreFeatures } from '@tanstack/table-core' import { storeReactivityBindings } from '@tanstack/table-core/store-reactivity-bindings' import { + createTableDevtoolsRegistrationManager, getTableDevtoolsTargets, removeTableDevtoolsTarget, + subscribeTableDevtoolsTargets, upsertTableDevtoolsTarget, } from '../src/tableTarget' @@ -64,6 +66,100 @@ describe('tableTarget', () => { expect(getTableDevtoolsTargets()).toEqual([]) }) + it('does not let stale cleanup remove a replacement table', () => { + const firstTable = createTable('users-table') + const nextTable = createTable('users-table') + + const cleanupFirst = upsertTableDevtoolsTarget({ table: firstTable }) + const cleanupNext = upsertTableDevtoolsTarget({ table: nextTable }) + + cleanupFirst?.() + + expect(getTableDevtoolsTargets()).toEqual([ + { + id: 'users-table', + table: nextTable, + }, + ]) + + cleanupNext?.() + expect(getTableDevtoolsTargets()).toEqual([]) + }) + + it('keeps a shared table registered until its final lease is released', () => { + const table = createTable('users-table') + + const cleanupFirst = upsertTableDevtoolsTarget({ table }) + const cleanupSecond = upsertTableDevtoolsTarget({ table }) + + cleanupFirst?.() + expect(getTableDevtoolsTargets()).toHaveLength(1) + + cleanupSecond?.() + expect(getTableDevtoolsTargets()).toEqual([]) + }) + + it('replaces a managed registration without publishing an empty registry', () => { + const manager = createTableDevtoolsRegistrationManager() + const firstTable = createTable('users-table') + const nextTable = createTable('users-table') + + manager.update(firstTable) + + const targetCounts: Array = [] + const unsubscribe = subscribeTableDevtoolsTargets((targets) => { + targetCounts.push(targets.length) + }) + + manager.update(nextTable) + + expect(targetCounts).toEqual([1, 1]) + expect(getTableDevtoolsTargets()).toEqual([ + { + id: 'users-table', + table: nextTable, + }, + ]) + + manager.dispose() + + expect(targetCounts).toEqual([1, 1, 0]) + unsubscribe() + }) + + it('updates transient wrappers without publishing a new target', () => { + const manager = createTableDevtoolsRegistrationManager() + const table = createTable('users-table') + const firstWrapper = { + ...table, + options: { + ...table.options, + debugAll: false, + }, + } + const nextWrapper = { + ...table, + options: { + ...table.options, + debugAll: true, + }, + } + + manager.update(firstWrapper) + + const listener = vi.fn() + const unsubscribe = subscribeTableDevtoolsTargets(listener) + + manager.update(nextWrapper) + + expect(listener).toHaveBeenCalledTimes(1) + expect(getTableDevtoolsTargets()[0]?.table).toBe(firstWrapper) + expect(getTableDevtoolsTargets()[0]?.table.options.debugAll).toBe(true) + + unsubscribe() + manager.dispose() + }) + it('logs and skips registration when the key is missing', () => { const consoleError = vi.spyOn(console, 'error').mockImplementation(() => {}) const table = createTable() @@ -90,6 +186,31 @@ describe('tableTarget', () => { ) }) + it('exposes a reactive resolved-options version to devtools', () => { + const table = createTable('users-table') + upsertTableDevtoolsTarget({ table }) + + const target = getTableDevtoolsTargets()[0]!.table + const snapshotVersion = target.optionAtoms.snapshotVersion + expect(snapshotVersion.get()).toBe(0) + + const versions: Array = [] + const subscription = snapshotVersion.subscribe((version) => { + versions.push(version) + }) + + table.setOptions((previous) => ({ + ...previous, + debugAll: true, + })) + + expect(snapshotVersion.get()).toBe(1) + expect(versions).toEqual([1]) + expect(target.options.debugAll).toBe(true) + + subscription.unsubscribe() + }) + it('removes keyed registrations directly', () => { const table = createTable('users-table') diff --git a/packages/vue-table-devtools/src/VueTableDevtools.tsx b/packages/vue-table-devtools/src/VueTableDevtools.tsx index ec9ba617d7..564229333e 100644 --- a/packages/vue-table-devtools/src/VueTableDevtools.tsx +++ b/packages/vue-table-devtools/src/VueTableDevtools.tsx @@ -36,16 +36,17 @@ function createPanelWrapper( name, props: ['theme', 'devtoolsOpen'], setup(props: TableDevtoolsVueInit) { - const devtoolsProps = { - theme: props.theme ?? 'dark', - devtoolsOpen: props.devtoolsOpen ?? false, - } - - return () => - h(Component, { + return () => { + const devtoolsProps = { + theme: props.theme ?? 'dark', + devtoolsOpen: props.devtoolsOpen ?? false, + } + return h(Component, { + key: `${devtoolsProps.theme}:${devtoolsProps.devtoolsOpen}`, props, devtoolsProps, }) + } }, }) as DefineComponent } diff --git a/packages/vue-table-devtools/src/production.ts b/packages/vue-table-devtools/src/production.ts index 5823644b5a..88724a9295 100644 --- a/packages/vue-table-devtools/src/production.ts +++ b/packages/vue-table-devtools/src/production.ts @@ -1,5 +1,5 @@ -export { TableDevtoolsPanel } from './VueTableDevtools' +export { TableDevtoolsPanel } from './production/VueTableDevtools' export type { TableDevtoolsVueInit } from './VueTableDevtools' -export { tableDevtoolsPlugin } from './plugin' +export { tableDevtoolsPlugin } from './production/plugin' export { useTanStackTableDevtools } from './useTanStackTableDevtools' export type { UseTanStackTableDevtoolsOptions } from './useTanStackTableDevtools' diff --git a/packages/vue-table-devtools/src/production/VueTableDevtools.tsx b/packages/vue-table-devtools/src/production/VueTableDevtools.tsx new file mode 100644 index 0000000000..d9ad422562 --- /dev/null +++ b/packages/vue-table-devtools/src/production/VueTableDevtools.tsx @@ -0,0 +1,46 @@ +import { createVuePanel } from '@tanstack/devtools-utils/vue' +import { TableDevtoolsCore } from '@tanstack/table-devtools/production' +import { defineComponent, h } from 'vue' +import type { DevtoolsPanelProps } from '@tanstack/devtools-utils/vue' +import type { DefineComponent } from 'vue' +import type { TableDevtoolsVueInit } from '../VueTableDevtools' + +class TableDevtoolsVueCore { + private readonly core = new TableDevtoolsCore() + + constructor(_props: DevtoolsPanelProps) {} + + mount(el: HTMLElement, props?: DevtoolsPanelProps) { + void this.core.mount(el, { + theme: props?.theme ?? 'dark', + devtoolsOpen: props?.devtoolsOpen ?? false, + }) + } + + unmount() { + this.core.unmount() + } +} + +const [TableDevtoolsPanelBase] = createVuePanel< + DevtoolsPanelProps, + TableDevtoolsVueCore +>(TableDevtoolsVueCore) + +export const TableDevtoolsPanel = defineComponent({ + name: 'TableDevtoolsPanel', + props: ['theme', 'devtoolsOpen'], + setup(props: TableDevtoolsVueInit) { + return () => { + const devtoolsProps = { + theme: props.theme ?? 'dark', + devtoolsOpen: props.devtoolsOpen ?? false, + } + return h(TableDevtoolsPanelBase, { + key: `${devtoolsProps.theme}:${devtoolsProps.devtoolsOpen}`, + props, + devtoolsProps, + }) + } + }, +}) as DefineComponent diff --git a/packages/vue-table-devtools/src/production/plugin.ts b/packages/vue-table-devtools/src/production/plugin.ts new file mode 100644 index 0000000000..c20a591a12 --- /dev/null +++ b/packages/vue-table-devtools/src/production/plugin.ts @@ -0,0 +1,9 @@ +import { createVuePlugin } from '@tanstack/devtools-utils/vue' +import { TableDevtoolsPanel } from './VueTableDevtools' + +const [tableDevtoolsPlugin] = createVuePlugin( + 'TanStack Table', + TableDevtoolsPanel, +) + +export { tableDevtoolsPlugin } diff --git a/packages/vue-table-devtools/src/useTanStackTableDevtools.ts b/packages/vue-table-devtools/src/useTanStackTableDevtools.ts index 23da5d8b59..feef50dbb0 100644 --- a/packages/vue-table-devtools/src/useTanStackTableDevtools.ts +++ b/packages/vue-table-devtools/src/useTanStackTableDevtools.ts @@ -1,5 +1,5 @@ -import { unref, watchEffect } from 'vue' -import { upsertTableDevtoolsTarget } from '@tanstack/table-devtools' +import { onScopeDispose, unref, watchEffect } from 'vue' +import { createTableDevtoolsRegistrationManager } from '@tanstack/table-devtools' import type { RowData, Table, TableFeatures } from '@tanstack/table-core' import type { MaybeRef } from 'vue' @@ -14,19 +14,14 @@ export function useTanStackTableDevtools< table: MaybeRef | undefined>, options?: MaybeRef, ): void { - watchEffect((onCleanup) => { + const registration = createTableDevtoolsRegistrationManager() + onScopeDispose(() => registration.dispose()) + + watchEffect(() => { const resolvedOptions = unref(options) const resolvedTable = unref(table) - if (!(resolvedOptions?.enabled ?? true) || !resolvedTable) { - return - } - - const cleanup = upsertTableDevtoolsTarget({ table: resolvedTable }) - - onCleanup(() => { - cleanup?.() - }) + registration.update(resolvedTable, resolvedOptions?.enabled ?? true) }) } diff --git a/packages/vue-table/src/merge-proxy.ts b/packages/vue-table/src/merge-proxy.ts index 94600ac185..10cf8fa79c 100644 --- a/packages/vue-table/src/merge-proxy.ts +++ b/packages/vue-table/src/merge-proxy.ts @@ -1,3 +1,5 @@ +import { isRef } from 'vue' + function trueFn() { return true } @@ -8,8 +10,10 @@ const $SOURCES = Symbol('merge-proxy-sources') // https://github.com/solidjs/solid/blob/c20ca4fd8c36bc0522fedb2c7f38a110b7ee2663/packages/solid/src/render/component.ts#L51-L118 const propTraps: ProxyHandler<{ get: (k: string | number | symbol) => any + getDescriptor: (k: string | number | symbol) => PropertyDescriptor | undefined has: (k: string | number | symbol) => boolean - keys: () => Array + keys: () => Array + prototype: () => object | null sources: Array }> = { get(_, property, receiver) { @@ -23,16 +27,21 @@ const propTraps: ProxyHandler<{ set: trueFn, deleteProperty: trueFn, getOwnPropertyDescriptor(_, property) { + const descriptor = _.getDescriptor(property) + if (!descriptor) return undefined + return { configurable: true, - enumerable: true, + enumerable: descriptor.enumerable ?? false, get() { return _.get(property) }, set: trueFn, - deleteProperty: trueFn, } }, + getPrototypeOf(_) { + return _.prototype() + }, ownKeys(_) { return _.keys() }, @@ -53,7 +62,32 @@ type MergeProxy> = UnboxIntersection< > function resolveSource(s: any) { - return s && typeof s === 'object' && 'value' in s ? s.value : s + return isRef(s) ? s.value : s +} + +function getMergedPrototype(sources: Array): object | null { + let fallback: object | null = Object.prototype + + for (let i = sources.length - 1; i >= 0; i--) { + const source = resolveSource(sources[i]) + if ( + (typeof source !== 'object' && typeof source !== 'function') || + source === null + ) { + continue + } + + const prototype = Object.getPrototypeOf(source) + fallback = prototype + + // Adapter-injected option fragments are ordinary objects. Prefer a + // meaningful user prototype when one is present in another source. + if (prototype !== Object.prototype) { + return prototype + } + } + + return fallback } export function mergeProxy>(...sources: T): MergeProxy @@ -76,21 +110,40 @@ export function mergeProxy(...sources: any): any { sources: flattenedSources, get(property: string | number | symbol) { for (let i = flattenedSources.length - 1; i >= 0; i--) { - const v = resolveSource(flattenedSources[i])[property] - if (v !== undefined) return v + const source = resolveSource(flattenedSources[i]) + if (source != null && Reflect.has(source, property)) { + return Reflect.get(source, property, source) + } + } + }, + getDescriptor(property: string | number | symbol) { + for (let i = flattenedSources.length - 1; i >= 0; i--) { + const source = resolveSource(flattenedSources[i]) + if (source == null) continue + + const descriptor = Reflect.getOwnPropertyDescriptor(source, property) + if (descriptor) return descriptor } + return undefined }, has(property: string | number | symbol) { for (let i = flattenedSources.length - 1; i >= 0; i--) { - if (property in resolveSource(flattenedSources[i])) return true + const source = resolveSource(flattenedSources[i]) + if (source != null && Reflect.has(source, property)) return true } return false }, keys() { - const keys = [] - for (const source of flattenedSources) - keys.push(...Object.keys(resolveSource(source))) - return [...Array.from(new Set(keys))] + const keys = new Set() + for (const unresolvedSource of flattenedSources) { + const source = resolveSource(unresolvedSource) + if (source == null) continue + for (const key of Reflect.ownKeys(source)) keys.add(key) + } + return [...keys] + }, + prototype() { + return getMergedPrototype(flattenedSources) }, }, propTraps, @@ -114,17 +167,36 @@ export function flatMerge( source3: W, ): T & U & V & W export function flatMerge(...sources: any): any { - const result: Record = {} + const result = Object.create(getMergedPrototype(sources)) as Record< + PropertyKey, + unknown + > - for (let source of sources) { + for (let sourceIndex = 0; sourceIndex < sources.length; sourceIndex++) { + let source = sources[sourceIndex] source = resolveSource(source) if (!source) continue for (const key of Reflect.ownKeys(source)) { - const value = (source as Record)[key] - if (value !== undefined) { - result[key] = value + const descriptor = Reflect.getOwnPropertyDescriptor(source, key) + if ( + sourceIndex === sources.length - 1 && + descriptor && + !('value' in descriptor) + ) { + Object.defineProperty(result, key, { + ...descriptor, + configurable: true, + }) + continue } + + Object.defineProperty(result, key, { + configurable: true, + enumerable: descriptor?.enumerable ?? true, + value: Reflect.get(source, key, source), + writable: true, + }) } } diff --git a/packages/vue-table/src/reactivity.ts b/packages/vue-table/src/reactivity.ts index a79bc2937a..c105698faf 100644 --- a/packages/vue-table/src/reactivity.ts +++ b/packages/vue-table/src/reactivity.ts @@ -54,16 +54,12 @@ function refToWritableAtom(source: ShallowRef): Atom { /** * Creates the table-core reactivity bindings used by the Vue adapter. * - * Table state atoms are backed by TanStack Store atoms. The options store stays - * framework-native because row-model APIs read `table.options` directly during - * render. Readonly table atoms bridge Store dependency tracking into Vue computed - * refs. + * Table state and option atoms bridge table-core reads into Vue computed refs. */ export function vueReactivity(): TableReactivityBindings { const subscriptions = new Set() return { - createOptionsStore: true, wrapExternalAtoms: true, addSubscription: (subscription) => { subscriptions.add(subscription) @@ -73,8 +69,21 @@ export function vueReactivity(): TableReactivityBindings { subscriptions.clear() }, schedule: (fn) => queueMicrotask(() => fn()), - createReadonlyAtom: (fn: () => T, _options?: TableAtomOptions) => { - return refToReadonlyAtom(computed(() => fn())) + createReadonlyAtom: (fn: () => T, options?: TableAtomOptions) => { + const compare = options?.compare ?? Object.is + let hasStableValue = false + let stableValue: T + + return refToReadonlyAtom( + computed(() => { + const nextValue = fn() + if (!hasStableValue || !compare(stableValue, nextValue)) { + stableValue = nextValue + hasStableValue = true + } + return stableValue + }), + ) }, createWritableAtom: ( value: T, diff --git a/packages/vue-table/src/useTable.ts b/packages/vue-table/src/useTable.ts index 58d7a7c622..0c126021b4 100644 --- a/packages/vue-table/src/useTable.ts +++ b/packages/vue-table/src/useTable.ts @@ -23,12 +23,20 @@ function getOptionsWithReactiveValues< TFeatures extends TableFeatures, TData extends RowData, >(options: TableOptionsWithReactiveData) { - const resolvedOptions: Record = {} - - for (const key of Object.keys(options)) { - resolvedOptions[key] = unref( - options[key as keyof TableOptionsWithReactiveData], - ) + const resolvedOptions = Object.create( + Object.getPrototypeOf(options), + ) as Record + + for (const key of Reflect.ownKeys(options)) { + const descriptor = Reflect.getOwnPropertyDescriptor(options, key) + const value = unref(Reflect.get(options, key, options)) + Object.defineProperty(resolvedOptions, key, { + configurable: true, + enumerable: descriptor?.enumerable ?? true, + get() { + return value + }, + }) } return mergeProxy(options, resolvedOptions) @@ -38,8 +46,8 @@ function getReactiveOptionDeps< TFeatures extends TableFeatures, TData extends RowData, >(options: TableOptionsWithReactiveData) { - return Object.keys(options).map((key) => - unref(options[key as keyof TableOptionsWithReactiveData]), + return Reflect.ownKeys(options).map((key) => + unref(Reflect.get(options, key, options)), ) } diff --git a/packages/vue-table/tests/unit/adapter-lifecycle.test.ts b/packages/vue-table/tests/unit/adapter-lifecycle.test.ts index e3f35a8c54..d3039d7c5d 100644 --- a/packages/vue-table/tests/unit/adapter-lifecycle.test.ts +++ b/packages/vue-table/tests/unit/adapter-lifecycle.test.ts @@ -1,5 +1,5 @@ import { describe, expect, test, vi } from 'vitest' -import { computed, effectScope, nextTick, ref, watchEffect } from 'vue' +import { computed, effectScope, isRef, nextTick, ref, watchEffect } from 'vue' import { createAtom } from '@tanstack/store' import { stockFeatures } from '@tanstack/table-core' import { useTable } from '../../src/useTable' @@ -240,4 +240,59 @@ describe('Vue adapter lifecycle and reactive options', () => { scope.stop() }) + + test('an existing ref-backed option can be cleared without leaking the Ref', async () => { + const firstHandler = vi.fn>() + const onRowSelectionChange = ref | undefined>( + firstHandler, + ) + const customOption = ref('first') + const customSymbol = Symbol('custom-option') + const prototype = { inheritedOption: 'from-prototype' } + const options = Object.create( + prototype, + Object.getOwnPropertyDescriptors({ + data: [{ id: '1', title: 'First' }], + columns, + features: stockFeatures, + getRowId: (row: Data) => row.id, + onRowSelectionChange, + value: 'custom-value', + [customSymbol]: 'symbol-value', + get customOption() { + return customOption.value + }, + }), + ) + const scope = effectScope() + const table = scope.run(() => + useTable(options), + )! + + expect(table.options.onRowSelectionChange).toBe(firstHandler) + expect(isRef(table.options.onRowSelectionChange)).toBe(false) + expect((table.options as any).value).toBe('custom-value') + expect((table.options as any)[customSymbol]).toBe('symbol-value') + expect((table.options as any).customOption).toBe('first') + expect( + Object.getOwnPropertyDescriptor(table.options, 'customOption'), + ).toMatchObject({ + value: 'first', + writable: false, + }) + + onRowSelectionChange.value = undefined + customOption.value = 'second' + await nextTick() + + expect(table.options.onRowSelectionChange).toBeUndefined() + expect(table.optionAtoms.onRowSelectionChange!.get()).toBeUndefined() + expect(isRef(table.options.onRowSelectionChange)).toBe(false) + expect((table.options as any).customOption).toBe('second') + + table.toggleAllRowsSelected(true) + expect(firstHandler).not.toHaveBeenCalled() + + scope.stop() + }) }) diff --git a/packages/vue-table/tests/unit/signals.test.ts b/packages/vue-table/tests/unit/signals.test.ts index d751381c8c..3116ba4854 100644 --- a/packages/vue-table/tests/unit/signals.test.ts +++ b/packages/vue-table/tests/unit/signals.test.ts @@ -43,4 +43,25 @@ describe('vueReactivity', () => { expect(doubled.get()).toBe(4) }) + + test('readonly atoms preserve identity through their comparator', async () => { + const reactivity = vueReactivity() + const count = reactivity.createWritableAtom(0) + const parity = reactivity.createReadonlyAtom( + () => ({ even: count.get() % 2 === 0 }), + { + compare: (previous, next) => previous.even === next.even, + debugName: 'parity', + }, + ) + + const initial = parity.get() + count.set(2) + await nextTick() + expect(parity.get()).toBe(initial) + + count.set(3) + await nextTick() + expect(parity.get()).not.toBe(initial) + }) }) From 3df127626d9a6d5bd59fdb2d900a7bc0992f59d9 Mon Sep 17 00:00:00 2001 From: riccardoperra Date: Fri, 31 Jul 2026 15:59:20 +0200 Subject: [PATCH 2/3] update --- packages/alpine-table/src/reactivity.ts | 37 +----- .../src/TableDevtools.ts | 31 ++--- .../src/injectTanStackTableDevtools.ts | 17 +-- .../angular-table-devtools/src/production.ts | 4 +- .../src/production/TableDevtools.ts | 41 ------ .../src/production/plugin.ts | 11 -- .../src/PreactTableDevtools.tsx | 23 +--- .../preact-table-devtools/src/production.ts | 4 +- .../src/production/PreactTableDevtools.tsx | 32 ----- .../src/production/plugin.tsx | 13 -- .../src/useTanStackTableDevtools.ts | 22 ++-- .../src/ReactTableDevtools.tsx | 24 +--- .../react-table-devtools/src/production.ts | 4 +- .../src/production/ReactTableDevtools.tsx | 29 ----- .../src/production/plugin.tsx | 11 -- .../src/table-devtools.d.ts | 10 -- .../src/useTanStackTableDevtools.ts | 19 +-- .../src/TableDevtools.tsx | 8 +- .../solid-table-devtools/src/production.ts | 2 +- .../src/production/TableDevtools.tsx | 8 +- .../src/useTanStackTableDevtools.ts | 15 ++- .../svelte-table/src/reactivity.svelte.ts | 30 +---- .../createStableStoreReadonlyAtom.ts | 11 +- packages/table-core/src/reactivity.ts | 1 + .../createStableStoreReadonlyAtom.test.ts | 13 ++ packages/table-devtools/src/TableDevtools.tsx | 9 +- .../src/components/ColumnsPanel.tsx | 8 +- .../src/components/FeaturesPanel.tsx | 11 +- .../src/components/OptionsPanel.tsx | 11 +- .../src/components/ResizableSplit.tsx | 24 +--- .../src/components/RowsPanel.tsx | 43 +++---- .../table-devtools/src/components/Shell.tsx | 5 +- .../src/components/StatePanel.tsx | 118 +++++++++-------- .../src/components/ThreeWayResizableSplit.tsx | 19 +-- packages/table-devtools/src/index.ts | 2 - packages/table-devtools/src/production.ts | 2 - .../table-devtools/src/styles/use-styles.ts | 20 +-- packages/table-devtools/src/tableTarget.ts | 87 ++----------- packages/table-devtools/src/useTableStore.ts | 34 ++--- .../tests/panel-lifecycle.test.tsx | 74 ----------- packages/table-devtools/tests/styles.test.tsx | 51 -------- .../table-devtools/tests/tableTarget.test.ts | 121 ------------------ .../src/VueTableDevtools.tsx | 15 +-- packages/vue-table-devtools/src/production.ts | 4 +- .../src/production/VueTableDevtools.tsx | 46 ------- .../src/production/plugin.ts | 9 -- .../src/useTanStackTableDevtools.ts | 19 ++- 47 files changed, 264 insertions(+), 888 deletions(-) delete mode 100644 packages/angular-table-devtools/src/production/TableDevtools.ts delete mode 100644 packages/angular-table-devtools/src/production/plugin.ts delete mode 100644 packages/preact-table-devtools/src/production/PreactTableDevtools.tsx delete mode 100644 packages/preact-table-devtools/src/production/plugin.tsx delete mode 100644 packages/react-table-devtools/src/production/ReactTableDevtools.tsx delete mode 100644 packages/react-table-devtools/src/production/plugin.tsx create mode 100644 packages/table-core/tests/unit/core/createStableStoreReadonlyAtom.test.ts delete mode 100644 packages/table-devtools/tests/panel-lifecycle.test.tsx delete mode 100644 packages/table-devtools/tests/styles.test.tsx delete mode 100644 packages/vue-table-devtools/src/production/VueTableDevtools.tsx delete mode 100644 packages/vue-table-devtools/src/production/plugin.ts diff --git a/packages/alpine-table/src/reactivity.ts b/packages/alpine-table/src/reactivity.ts index 21c970250a..fa2090add1 100644 --- a/packages/alpine-table/src/reactivity.ts +++ b/packages/alpine-table/src/reactivity.ts @@ -1,39 +1,9 @@ import { batch, createAtom } from '@tanstack/store' +import { createStableStoreReadonlyAtom } from '@tanstack/table-core/reactivity' import type { TableAtomOptions, TableReactivityBindings, } from '@tanstack/table-core/reactivity' -import type { Observer, ReadonlyAtom } from '@tanstack/store' - -function createStableReadonlyAtom( - fn: () => T, - compare: (previous: T, next: T) => boolean, -): ReadonlyAtom { - let stableBox: { value: T } | undefined - const boxedAtom = createAtom( - () => { - const nextValue = fn() - if (!stableBox || !compare(stableBox.value, nextValue)) { - stableBox = { value: nextValue } - } - return stableBox - }, - ) - - return { - get: () => boxedAtom.get().value, - subscribe: (( - observer: Observer | ((value: T) => void), - ) => - boxedAtom.subscribe((box) => { - if (typeof observer === 'function') { - observer(box.value) - } else { - observer.next?.(box.value) - } - })) as ReadonlyAtom['subscribe'], - } -} /** * Creates the table-core reactivity bindings used by the Alpine adapter. @@ -58,9 +28,10 @@ export function alpineReactivity(): TableReactivityBindings { batch, untrack: (fn) => fn(), createReadonlyAtom: (fn: () => T, options?: TableAtomOptions) => { - return createStableReadonlyAtom( + return createStableStoreReadonlyAtom( + createAtom, fn, - options?.compare ?? Object.is, + { compare: options?.compare }, ) }, createWritableAtom: (value: T, options?: TableAtomOptions) => { diff --git a/packages/angular-table-devtools/src/TableDevtools.ts b/packages/angular-table-devtools/src/TableDevtools.ts index 0ea790a3b4..b88c366710 100644 --- a/packages/angular-table-devtools/src/TableDevtools.ts +++ b/packages/angular-table-devtools/src/TableDevtools.ts @@ -1,9 +1,12 @@ import { TableDevtoolsCore } from '@tanstack/table-devtools' -import { computed, effect } from '@angular/core' +import { createAngularPanel } from '@tanstack/devtools-utils/angular' import type { DevtoolsPanelProps } from '@tanstack/devtools-utils/angular' export interface TableDevtoolsAngularInit extends Partial {} +const [TableDevtoolsPanelBase, TableDevtoolsPanelNoOpBase] = + createAngularPanel(TableDevtoolsCore) + function resolvePanelProps( props?: TableDevtoolsAngularInit, ): DevtoolsPanelProps { @@ -20,26 +23,12 @@ type TableDevtoolsPanelComponent = () => ( export const TableDevtoolsPanel: TableDevtoolsPanelComponent = () => (props, host) => { - const panel = host.ownerDocument.createElement('div') - panel.style.height = '100%' - host.appendChild(panel) - - const panelProps = computed(() => resolvePanelProps(props()), { - equal: (previous, next) => - previous.theme === next.theme && - previous.devtoolsOpen === next.devtoolsOpen, - }) - const panelEffect = effect((onCleanup) => { - const instance = new TableDevtoolsCore() - void instance.mount(panel, panelProps()) - onCleanup(() => instance.unmount()) - }) - - return () => { - panelEffect.destroy() - panel.remove() - } + const panel = TableDevtoolsPanelBase() + return panel(() => resolvePanelProps(props()), host) } export const TableDevtoolsPanelNoOp: TableDevtoolsPanelComponent = - () => (_props, _host) => () => {} + () => (_props, _host) => { + const panel = TableDevtoolsPanelNoOpBase() + return () => panel + } diff --git a/packages/angular-table-devtools/src/injectTanStackTableDevtools.ts b/packages/angular-table-devtools/src/injectTanStackTableDevtools.ts index e8ca71c6e0..eabca429b5 100644 --- a/packages/angular-table-devtools/src/injectTanStackTableDevtools.ts +++ b/packages/angular-table-devtools/src/injectTanStackTableDevtools.ts @@ -1,6 +1,5 @@ -import { createTableDevtoolsRegistrationManager } from '@tanstack/table-devtools' +import { upsertTableDevtoolsTarget } from '@tanstack/table-devtools' import { - DestroyRef, Injector, assertInInjectionContext, effect, @@ -31,15 +30,17 @@ export function injectTanStackTableDevtools< injector = inject(Injector) } - const destroyRef = injector.get(DestroyRef) - const registration = createTableDevtoolsRegistrationManager() - destroyRef.onDestroy(() => registration.dispose()) - effect( - () => { + (onCleanup) => { const { table } = options() const enabledValue = enabled() - untracked(() => registration.update(table, enabledValue)) + if (!enabledValue || !table) { + return + } + const cleanup = untracked(() => upsertTableDevtoolsTarget({ table })) + onCleanup(() => { + cleanup?.() + }) }, { injector }, ) diff --git a/packages/angular-table-devtools/src/production.ts b/packages/angular-table-devtools/src/production.ts index 1256c41c5a..f3e96534ef 100644 --- a/packages/angular-table-devtools/src/production.ts +++ b/packages/angular-table-devtools/src/production.ts @@ -1,5 +1,5 @@ -export { TableDevtoolsPanel } from './production/TableDevtools' +export { TableDevtoolsPanel } from './TableDevtools' export type { TableDevtoolsAngularInit } from './TableDevtools' -export { tableDevtoolsPlugin } from './production/plugin' +export { tableDevtoolsPlugin } from './plugin' export { injectTanStackTableDevtools } from './injectTanStackTableDevtools' export type { InjectTanStackTableDevtoolsOptions } from './injectTanStackTableDevtools' diff --git a/packages/angular-table-devtools/src/production/TableDevtools.ts b/packages/angular-table-devtools/src/production/TableDevtools.ts deleted file mode 100644 index c9061540c8..0000000000 --- a/packages/angular-table-devtools/src/production/TableDevtools.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { computed, effect } from '@angular/core' -import { TableDevtoolsCore } from '@tanstack/table-devtools/production' -import type { DevtoolsPanelProps } from '@tanstack/devtools-utils/angular' -import type { TableDevtoolsAngularInit } from '../TableDevtools' - -function resolvePanelProps( - props?: TableDevtoolsAngularInit, -): DevtoolsPanelProps { - return { - theme: props?.theme ?? 'dark', - devtoolsOpen: props?.devtoolsOpen ?? false, - } -} - -type TableDevtoolsPanelComponent = () => ( - inputs: () => TableDevtoolsAngularInit, - hostElement: HTMLElement, -) => () => void - -export const TableDevtoolsPanel: TableDevtoolsPanelComponent = - () => (props, host) => { - const panel = host.ownerDocument.createElement('div') - panel.style.height = '100%' - host.appendChild(panel) - - const panelProps = computed(() => resolvePanelProps(props()), { - equal: (previous, next) => - previous.theme === next.theme && - previous.devtoolsOpen === next.devtoolsOpen, - }) - const panelEffect = effect((onCleanup) => { - const instance = new TableDevtoolsCore() - void instance.mount(panel, panelProps()) - onCleanup(() => instance.unmount()) - }) - - return () => { - panelEffect.destroy() - panel.remove() - } - } diff --git a/packages/angular-table-devtools/src/production/plugin.ts b/packages/angular-table-devtools/src/production/plugin.ts deleted file mode 100644 index 73c8683158..0000000000 --- a/packages/angular-table-devtools/src/production/plugin.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { createAngularPlugin } from '@tanstack/devtools-utils/angular' -import { TableDevtoolsPanel } from './TableDevtools' - -type TableDevtoolsPluginFactory = ReturnType[0] - -const [plugin] = createAngularPlugin({ - name: 'TanStack Table', - render: TableDevtoolsPanel, -}) - -export const tableDevtoolsPlugin: TableDevtoolsPluginFactory = plugin diff --git a/packages/preact-table-devtools/src/PreactTableDevtools.tsx b/packages/preact-table-devtools/src/PreactTableDevtools.tsx index 9e0f7e681b..b84cae7ced 100644 --- a/packages/preact-table-devtools/src/PreactTableDevtools.tsx +++ b/packages/preact-table-devtools/src/PreactTableDevtools.tsx @@ -1,5 +1,4 @@ import { h } from 'preact' -import { useMemo } from 'preact/hooks' import { createPreactPanel } from '@tanstack/devtools-utils/preact' import { TableDevtoolsCore } from '@tanstack/table-devtools' import type { DevtoolsPanelProps } from '@tanstack/devtools-utils/preact' @@ -23,22 +22,8 @@ function resolvePanelProps( } } -export const TableDevtoolsPanel: TableDevtoolsPanelComponent = (props) => { - const theme = props?.theme - const devtoolsOpen = props?.devtoolsOpen - const panelProps = useMemo( - () => resolvePanelProps({ theme, devtoolsOpen }), - [devtoolsOpen, theme], - ) - return h(TableDevtoolsPanelBase, panelProps) -} +export const TableDevtoolsPanel: TableDevtoolsPanelComponent = (props) => + h(TableDevtoolsPanelBase, resolvePanelProps(props)) -export const TableDevtoolsPanelNoOp: TableDevtoolsPanelComponent = (props) => { - const theme = props?.theme - const devtoolsOpen = props?.devtoolsOpen - const panelProps = useMemo( - () => resolvePanelProps({ theme, devtoolsOpen }), - [devtoolsOpen, theme], - ) - return h(TableDevtoolsPanelNoOpBase, panelProps) -} +export const TableDevtoolsPanelNoOp: TableDevtoolsPanelComponent = (props) => + h(TableDevtoolsPanelNoOpBase, resolvePanelProps(props)) diff --git a/packages/preact-table-devtools/src/production.ts b/packages/preact-table-devtools/src/production.ts index 9d7e6de391..2212d72fce 100644 --- a/packages/preact-table-devtools/src/production.ts +++ b/packages/preact-table-devtools/src/production.ts @@ -1,7 +1,7 @@ 'use client' -export { TableDevtoolsPanel } from './production/PreactTableDevtools' +export { TableDevtoolsPanel } from './PreactTableDevtools' export type { TableDevtoolsPreactInit } from './PreactTableDevtools' -export { tableDevtoolsPlugin } from './production/plugin' +export { tableDevtoolsPlugin } from './plugin' export { useTanStackTableDevtools } from './useTanStackTableDevtools' export type { UseTanStackTableDevtoolsOptions } from './useTanStackTableDevtools' diff --git a/packages/preact-table-devtools/src/production/PreactTableDevtools.tsx b/packages/preact-table-devtools/src/production/PreactTableDevtools.tsx deleted file mode 100644 index 7606a20f5c..0000000000 --- a/packages/preact-table-devtools/src/production/PreactTableDevtools.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import { h } from 'preact' -import { useMemo } from 'preact/hooks' -import { createPreactPanel } from '@tanstack/devtools-utils/preact' -import { TableDevtoolsCore } from '@tanstack/table-devtools/production' -import type { DevtoolsPanelProps } from '@tanstack/devtools-utils/preact' -import type { JSX } from 'preact' -import type { TableDevtoolsPreactInit } from '../PreactTableDevtools' - -type TableDevtoolsPanelComponent = ( - props?: TableDevtoolsPreactInit, -) => JSX.Element - -const [TableDevtoolsPanelBase] = createPreactPanel(TableDevtoolsCore) - -function resolvePanelProps( - props?: TableDevtoolsPreactInit, -): DevtoolsPanelProps { - return { - theme: props?.theme ?? 'dark', - devtoolsOpen: props?.devtoolsOpen ?? false, - } -} - -export const TableDevtoolsPanel: TableDevtoolsPanelComponent = (props) => { - const theme = props?.theme - const devtoolsOpen = props?.devtoolsOpen - const panelProps = useMemo( - () => resolvePanelProps({ theme, devtoolsOpen }), - [devtoolsOpen, theme], - ) - return h(TableDevtoolsPanelBase, panelProps) -} diff --git a/packages/preact-table-devtools/src/production/plugin.tsx b/packages/preact-table-devtools/src/production/plugin.tsx deleted file mode 100644 index a75f39c20d..0000000000 --- a/packages/preact-table-devtools/src/production/plugin.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import { createPreactPlugin } from '@tanstack/devtools-utils/preact' -import { TableDevtoolsPanel } from './PreactTableDevtools' - -type PreactTableDevtoolsPlugin = ReturnType< - ReturnType[0] -> - -const [plugin] = createPreactPlugin({ - name: 'TanStack Table', - Component: TableDevtoolsPanel, -}) - -export const tableDevtoolsPlugin: () => PreactTableDevtoolsPlugin = plugin diff --git a/packages/preact-table-devtools/src/useTanStackTableDevtools.ts b/packages/preact-table-devtools/src/useTanStackTableDevtools.ts index 52682f8044..80b51f5ca4 100644 --- a/packages/preact-table-devtools/src/useTanStackTableDevtools.ts +++ b/packages/preact-table-devtools/src/useTanStackTableDevtools.ts @@ -1,7 +1,7 @@ 'use client' -import { useEffect, useRef } from 'preact/hooks' -import { createTableDevtoolsRegistrationManager } from '@tanstack/table-devtools' +import { useEffect } from 'preact/hooks' +import { upsertTableDevtoolsTarget } from '@tanstack/table-devtools' import type { RowData, Table, TableFeatures } from '@tanstack/table-core' export interface UseTanStackTableDevtoolsOptions { @@ -16,18 +16,18 @@ export function useTanStackTableDevtools< options?: UseTanStackTableDevtoolsOptions, ): void { const enabled = options?.enabled ?? true - const registrationRef = - useRef>() - registrationRef.current ??= createTableDevtoolsRegistrationManager() - const registration = registrationRef.current useEffect(() => { - return () => registration.dispose() - }, [registration]) + if (!enabled || !table) { + return + } - useEffect(() => { - registration.update(table, enabled) - }, [enabled, registration, table, table?.options.key]) + const cleanup = upsertTableDevtoolsTarget({ table }) + + return () => { + cleanup?.() + } + }, [enabled, table, table?.options.key]) } export function useTanStackTableDevtoolsNoOp< diff --git a/packages/react-table-devtools/src/ReactTableDevtools.tsx b/packages/react-table-devtools/src/ReactTableDevtools.tsx index 4fbd67f137..898c95f67d 100644 --- a/packages/react-table-devtools/src/ReactTableDevtools.tsx +++ b/packages/react-table-devtools/src/ReactTableDevtools.tsx @@ -1,4 +1,4 @@ -import { createElement, useMemo } from 'react' +import { createElement } from 'react' import { createReactPanel } from '@tanstack/devtools-utils/react' import { TableDevtoolsCore } from '@tanstack/table-devtools' import type { DevtoolsPanelProps } from '@tanstack/devtools-utils/react' @@ -20,22 +20,8 @@ function resolvePanelProps(props?: TableDevtoolsReactInit): DevtoolsPanelProps { } } -export const TableDevtoolsPanel: TableDevtoolsPanelComponent = (props) => { - const theme = props?.theme - const devtoolsOpen = props?.devtoolsOpen - const panelProps = useMemo( - () => resolvePanelProps({ theme, devtoolsOpen }), - [devtoolsOpen, theme], - ) - return createElement(TableDevtoolsPanelBase, panelProps) -} +export const TableDevtoolsPanel: TableDevtoolsPanelComponent = (props) => + createElement(TableDevtoolsPanelBase, resolvePanelProps(props)) -export const TableDevtoolsPanelNoOp: TableDevtoolsPanelComponent = (props) => { - const theme = props?.theme - const devtoolsOpen = props?.devtoolsOpen - const panelProps = useMemo( - () => resolvePanelProps({ theme, devtoolsOpen }), - [devtoolsOpen, theme], - ) - return createElement(TableDevtoolsPanelNoOpBase, panelProps) -} +export const TableDevtoolsPanelNoOp: TableDevtoolsPanelComponent = (props) => + createElement(TableDevtoolsPanelNoOpBase, resolvePanelProps(props)) diff --git a/packages/react-table-devtools/src/production.ts b/packages/react-table-devtools/src/production.ts index 17fbb08574..d31f8bce12 100644 --- a/packages/react-table-devtools/src/production.ts +++ b/packages/react-table-devtools/src/production.ts @@ -1,7 +1,7 @@ 'use client' -export { TableDevtoolsPanel } from './production/ReactTableDevtools' +export { TableDevtoolsPanel } from './ReactTableDevtools' export type { TableDevtoolsReactInit } from './ReactTableDevtools' -export { tableDevtoolsPlugin } from './production/plugin' +export { tableDevtoolsPlugin } from './plugin' export { useTanStackTableDevtools } from './useTanStackTableDevtools' export type { UseTanStackTableDevtoolsOptions } from './useTanStackTableDevtools' diff --git a/packages/react-table-devtools/src/production/ReactTableDevtools.tsx b/packages/react-table-devtools/src/production/ReactTableDevtools.tsx deleted file mode 100644 index 5d2f4e5dd8..0000000000 --- a/packages/react-table-devtools/src/production/ReactTableDevtools.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import { createElement, useMemo } from 'react' -import { createReactPanel } from '@tanstack/devtools-utils/react' -import { TableDevtoolsCore } from '@tanstack/table-devtools/production' -import type { DevtoolsPanelProps } from '@tanstack/devtools-utils/react' -import type { JSX } from 'react' -import type { TableDevtoolsReactInit } from '../ReactTableDevtools' - -type TableDevtoolsPanelComponent = ( - props?: TableDevtoolsReactInit, -) => JSX.Element - -const [TableDevtoolsPanelBase] = createReactPanel(TableDevtoolsCore) - -function resolvePanelProps(props?: TableDevtoolsReactInit): DevtoolsPanelProps { - return { - theme: props?.theme ?? 'dark', - devtoolsOpen: props?.devtoolsOpen ?? false, - } -} - -export const TableDevtoolsPanel: TableDevtoolsPanelComponent = (props) => { - const theme = props?.theme - const devtoolsOpen = props?.devtoolsOpen - const panelProps = useMemo( - () => resolvePanelProps({ theme, devtoolsOpen }), - [devtoolsOpen, theme], - ) - return createElement(TableDevtoolsPanelBase, panelProps) -} diff --git a/packages/react-table-devtools/src/production/plugin.tsx b/packages/react-table-devtools/src/production/plugin.tsx deleted file mode 100644 index af649b07db..0000000000 --- a/packages/react-table-devtools/src/production/plugin.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import { createReactPlugin } from '@tanstack/devtools-utils/react' -import { TableDevtoolsPanel } from './ReactTableDevtools' - -type TableDevtoolsPluginFactory = ReturnType[0] - -const [plugin] = createReactPlugin({ - name: 'TanStack Table', - Component: TableDevtoolsPanel, -}) - -export const tableDevtoolsPlugin: TableDevtoolsPluginFactory = plugin diff --git a/packages/react-table-devtools/src/table-devtools.d.ts b/packages/react-table-devtools/src/table-devtools.d.ts index e8db884dc5..e8b6b1d122 100644 --- a/packages/react-table-devtools/src/table-devtools.d.ts +++ b/packages/react-table-devtools/src/table-devtools.d.ts @@ -31,14 +31,4 @@ declare module '@tanstack/table-devtools' { ): (() => void) | undefined export function removeTableDevtoolsTarget(id: string): void - - export interface TableDevtoolsRegistrationManager { - update: ( - table: Table | undefined, - enabled?: boolean, - ) => void - dispose: () => void - } - - export function createTableDevtoolsRegistrationManager(): TableDevtoolsRegistrationManager } diff --git a/packages/react-table-devtools/src/useTanStackTableDevtools.ts b/packages/react-table-devtools/src/useTanStackTableDevtools.ts index 1375f57be2..fed82bad9b 100644 --- a/packages/react-table-devtools/src/useTanStackTableDevtools.ts +++ b/packages/react-table-devtools/src/useTanStackTableDevtools.ts @@ -1,7 +1,7 @@ 'use client' -import { createTableDevtoolsRegistrationManager } from '@tanstack/table-devtools' -import { useEffect, useState } from 'react' +import { upsertTableDevtoolsTarget } from '@tanstack/table-devtools' +import { useEffect } from 'react' import type { RowData, Table, TableFeatures } from '@tanstack/table-core' export interface UseTanStackTableDevtoolsOptions { @@ -16,15 +16,18 @@ export function useTanStackTableDevtools< options?: UseTanStackTableDevtoolsOptions, ): void { const enabled = options?.enabled ?? true - const [registration] = useState(createTableDevtoolsRegistrationManager) useEffect(() => { - return () => registration.dispose() - }, [registration]) + if (!enabled || !table) { + return + } - useEffect(() => { - registration.update(table, enabled) - }, [enabled, registration, table, table?.options.key]) + const cleanup = upsertTableDevtoolsTarget({ table }) + + return () => { + cleanup?.() + } + }, [enabled, table, table?.options.key]) } export function useTanStackTableDevtoolsNoOp< diff --git a/packages/solid-table-devtools/src/TableDevtools.tsx b/packages/solid-table-devtools/src/TableDevtools.tsx index b20fea09f4..75b8f100ce 100644 --- a/packages/solid-table-devtools/src/TableDevtools.tsx +++ b/packages/solid-table-devtools/src/TableDevtools.tsx @@ -14,12 +14,8 @@ const [TableDevtoolsPanelBase, TableDevtoolsPanelNoOpBase] = function resolvePanelProps(props?: TableDevtoolsSolidInit): DevtoolsPanelProps { return { - get theme() { - return props?.theme ?? 'dark' - }, - get devtoolsOpen() { - return props?.devtoolsOpen ?? false - }, + theme: props?.theme ?? 'dark', + devtoolsOpen: props?.devtoolsOpen ?? false, } } diff --git a/packages/solid-table-devtools/src/production.ts b/packages/solid-table-devtools/src/production.ts index eddeb12413..010ae2139e 100644 --- a/packages/solid-table-devtools/src/production.ts +++ b/packages/solid-table-devtools/src/production.ts @@ -1,4 +1,4 @@ -export { TableDevtoolsPanel } from './production/TableDevtools' +export { TableDevtoolsPanel } from './TableDevtools' export type { TableDevtoolsSolidInit } from './production/TableDevtools' diff --git a/packages/solid-table-devtools/src/production/TableDevtools.tsx b/packages/solid-table-devtools/src/production/TableDevtools.tsx index ec38ac5ae5..c6670acf6f 100644 --- a/packages/solid-table-devtools/src/production/TableDevtools.tsx +++ b/packages/solid-table-devtools/src/production/TableDevtools.tsx @@ -14,12 +14,8 @@ type TableDevtoolsPanelComponent = ( function resolvePanelProps(props?: TableDevtoolsSolidInit): DevtoolsPanelProps { return { - get theme() { - return props?.theme ?? 'dark' - }, - get devtoolsOpen() { - return props?.devtoolsOpen ?? false - }, + theme: props?.theme ?? 'dark', + devtoolsOpen: props?.devtoolsOpen ?? false, } } diff --git a/packages/solid-table-devtools/src/useTanStackTableDevtools.ts b/packages/solid-table-devtools/src/useTanStackTableDevtools.ts index 160116b207..5c5fc60b40 100644 --- a/packages/solid-table-devtools/src/useTanStackTableDevtools.ts +++ b/packages/solid-table-devtools/src/useTanStackTableDevtools.ts @@ -1,5 +1,5 @@ import { createRenderEffect, onCleanup } from 'solid-js' -import { createTableDevtoolsRegistrationManager } from '@tanstack/table-devtools' +import { upsertTableDevtoolsTarget } from '@tanstack/table-devtools' import type { RowData, Table, TableFeatures } from '@tanstack/table-core' export interface UseTanStackTableDevtoolsOptions { @@ -13,11 +13,16 @@ export function useTanStackTableDevtools< table: Table | undefined, options?: UseTanStackTableDevtoolsOptions, ): void { - const registration = createTableDevtoolsRegistrationManager() - onCleanup(() => registration.dispose()) - createRenderEffect(() => { - registration.update(table, options?.enabled ?? true) + if (!(options?.enabled ?? true) || !table) { + return + } + + const cleanup = upsertTableDevtoolsTarget({ table }) + + onCleanup(() => { + cleanup?.() + }) }) } diff --git a/packages/svelte-table/src/reactivity.svelte.ts b/packages/svelte-table/src/reactivity.svelte.ts index bcea1e6d66..766e413728 100644 --- a/packages/svelte-table/src/reactivity.svelte.ts +++ b/packages/svelte-table/src/reactivity.svelte.ts @@ -1,6 +1,7 @@ import { untrack } from 'svelte' import { createSubscriber } from 'svelte/reactivity' import { batch, createAtom } from '@tanstack/svelte-store' +import { createStableStoreReadonlyAtom } from '@tanstack/table-core/reactivity' import type { TableAtomOptions, TableReactivityBindings, @@ -15,30 +16,6 @@ function observerToCallback( : (value) => observerOrNext.next?.(value) } -function createStableReadonlyAtom( - fn: () => T, - compare: (previous: T, next: T) => boolean, -): ReadonlyAtom { - let stableBox: { value: T } | undefined - const boxedAtom = createAtom( - () => { - const nextValue = fn() - if (!stableBox || !compare(stableBox.value, nextValue)) { - stableBox = { value: nextValue } - } - return stableBox - }, - ) - - return { - get: () => boxedAtom.get().value, - subscribe: ((observerOrNext: Observer | ((value: T) => void)) => { - const callback = observerToCallback(observerOrNext) - return boxedAtom.subscribe((box) => callback(box.value)) - }) as ReadonlyAtom['subscribe'], - } -} - /** * Creates the table-core reactivity bindings used by the Svelte adapter. * @@ -61,9 +38,10 @@ export function svelteReactivity(): TableReactivityBindings { }, schedule: (fn) => queueMicrotask(() => fn()), createReadonlyAtom: (fn: () => T, _options?: TableAtomOptions) => { - const storeAtom = createStableReadonlyAtom( + const storeAtom = createStableStoreReadonlyAtom( + createAtom, fn, - _options?.compare ?? Object.is, + { compare: _options?.compare }, ) const trackStore = createSubscriber((update) => { const subscription = storeAtom.subscribe(() => { diff --git a/packages/table-core/src/core/reactivity/createStableStoreReadonlyAtom.ts b/packages/table-core/src/core/reactivity/createStableStoreReadonlyAtom.ts index 6e6191a26c..9ab518cd86 100644 --- a/packages/table-core/src/core/reactivity/createStableStoreReadonlyAtom.ts +++ b/packages/table-core/src/core/reactivity/createStableStoreReadonlyAtom.ts @@ -6,13 +6,12 @@ type StoreReadonlyAtomFactory = ( ) => ReadonlyAtom /** - * Creates a TanStack Store computed whose equality also works for `undefined`. + * Creates a TanStack Store computed that can safely return any value. * - * Store uses `undefined` as its uninitialized computed snapshot, so a computed - * that legitimately returns `undefined` is otherwise reported as changed on - * every dependency invalidation. Keeping the compared value inside a stable - * box gives Store a distinct initialized snapshot without changing the public - * atom value. + * TanStack Store treats a function passed to `createAtom` as a computed + * resolver and uses `undefined` as its uninitialized computed snapshot. + * Keeping the result inside a stable box therefore lets the computed return + * function-valued or `undefined` values while preserving result equality. */ export function createStableStoreReadonlyAtom( createAtom: StoreReadonlyAtomFactory, diff --git a/packages/table-core/src/reactivity.ts b/packages/table-core/src/reactivity.ts index ca7a98ddbe..3a34207916 100644 --- a/packages/table-core/src/reactivity.ts +++ b/packages/table-core/src/reactivity.ts @@ -1,3 +1,4 @@ export * from './core/reactivity/coreReactivityFeature.types' export * from './core/reactivity/coreReactivityFeature.utils' +export * from './core/reactivity/createStableStoreReadonlyAtom' export * from './core/reactivity/renderPhaseReactivity' diff --git a/packages/table-core/tests/unit/core/createStableStoreReadonlyAtom.test.ts b/packages/table-core/tests/unit/core/createStableStoreReadonlyAtom.test.ts new file mode 100644 index 0000000000..4d48534163 --- /dev/null +++ b/packages/table-core/tests/unit/core/createStableStoreReadonlyAtom.test.ts @@ -0,0 +1,13 @@ +import { createAtom } from '@tanstack/store' +import { describe, expect, it, vi } from 'vitest' +import { createStableStoreReadonlyAtom } from '../../../src/reactivity' + +describe('createStableStoreReadonlyAtom', () => { + it('returns a function value without invoking it as a computed resolver', () => { + const value = vi.fn() + const atom = createStableStoreReadonlyAtom(createAtom, () => value) + + expect(atom.get()).toBe(value) + expect(value).not.toHaveBeenCalled() + }) +}) diff --git a/packages/table-devtools/src/TableDevtools.tsx b/packages/table-devtools/src/TableDevtools.tsx index 0f687b3557..a6e96ecec2 100644 --- a/packages/table-devtools/src/TableDevtools.tsx +++ b/packages/table-devtools/src/TableDevtools.tsx @@ -1,4 +1,3 @@ -import { Show } from 'solid-js' import { ThemeContextProvider } from '@tanstack/devtools-ui' import { TableContextProvider } from './TableContextProvider' import { Shell } from './components/Shell' @@ -10,11 +9,9 @@ export default function TableDevtools(props: { }) { return ( - - - - - + + + ) } diff --git a/packages/table-devtools/src/components/ColumnsPanel.tsx b/packages/table-devtools/src/components/ColumnsPanel.tsx index 12e7b8cbcb..500e33a639 100644 --- a/packages/table-devtools/src/components/ColumnsPanel.tsx +++ b/packages/table-devtools/src/components/ColumnsPanel.tsx @@ -32,9 +32,9 @@ export function ColumnsPanel() { const styles = useStyles() const { table } = useTableDevtoolsContext() - const optionsVersion = useTableStore( - () => table()?.optionAtoms.snapshotVersion, - (version) => version, + const tableState = useTableStore( + () => table()?.store, + (state) => state, ) const columns = createMemo>(() => { @@ -43,7 +43,7 @@ export function ColumnsPanel() { return [] } - optionsVersion() + tableState() const tableWithColumnFns = tableInstance as unknown as { getAllFlatColumns?: () => Array diff --git a/packages/table-devtools/src/components/FeaturesPanel.tsx b/packages/table-devtools/src/components/FeaturesPanel.tsx index 3eb73647a9..b4b5076757 100644 --- a/packages/table-devtools/src/components/FeaturesPanel.tsx +++ b/packages/table-devtools/src/components/FeaturesPanel.tsx @@ -157,15 +157,16 @@ export function FeaturesPanel() { () => table()?.store, (state) => state, ) - const optionsVersion = useTableStore( + const tableOptions = useTableStore( () => table()?.optionAtoms.snapshotVersion, - (version) => version, + () => table()?.options as unknown, ) const tableFeatures = createMemo((): Set => { const tableInstance = table() if (!tableInstance) return new Set() + tableState() return new Set(Object.keys(tableInstance._features)) }) @@ -173,7 +174,8 @@ export function FeaturesPanel() { const tableInstance = table() if (!tableInstance) return [] - optionsVersion() + tableState() + tableOptions() return Object.keys(tableInstance.options.features ?? {}).filter((key) => ROW_MODEL_FEATURE_SLOTS.includes(key), @@ -186,7 +188,8 @@ export function FeaturesPanel() { const tableInstance = table() if (!tableInstance) return [] - optionsVersion() + tableState() + tableOptions() const rowModelFns = toFnBuckets(tableInstance._rowModelFns) const optionFns = toFnBuckets(tableInstance.options) diff --git a/packages/table-devtools/src/components/OptionsPanel.tsx b/packages/table-devtools/src/components/OptionsPanel.tsx index eff614e29f..08de142edc 100644 --- a/packages/table-devtools/src/components/OptionsPanel.tsx +++ b/packages/table-devtools/src/components/OptionsPanel.tsx @@ -20,9 +20,14 @@ export function OptionsPanel() { const styles = useStyles() const { table } = useTableDevtoolsContext() - const optionsVersion = useTableStore( + const tableOptions = useTableStore( () => table()?.optionAtoms.snapshotVersion, - (version) => version, + () => { + const tableInstance = table() + return tableInstance + ? projectOptionsForTree(tableInstance.options) + : undefined + }, ) const options = createMemo(() => { @@ -31,7 +36,7 @@ export function OptionsPanel() { return undefined } - optionsVersion() + tableOptions() return projectOptionsForTree(tableInstance.options) }) diff --git a/packages/table-devtools/src/components/ResizableSplit.tsx b/packages/table-devtools/src/components/ResizableSplit.tsx index a19a411e0a..c8abfa661c 100644 --- a/packages/table-devtools/src/components/ResizableSplit.tsx +++ b/packages/table-devtools/src/components/ResizableSplit.tsx @@ -1,4 +1,4 @@ -import { createSignal, onCleanup } from 'solid-js' +import { createSignal } from 'solid-js' import { useStyles } from '../styles/use-styles' import type { JSX } from 'solid-js' @@ -14,22 +14,14 @@ interface ResizableSplitProps { export function ResizableSplit(props: ResizableSplitProps) { const styles = useStyles() const [leftPercent, setLeftPercent] = createSignal(DEFAULT_LEFT_PERCENT) - let cleanupDrag: (() => void) | undefined - - onCleanup(() => { - cleanupDrag?.() - }) const handleMouseDown = (e: MouseEvent) => { e.preventDefault() - cleanupDrag?.() - - const container = (e.currentTarget as HTMLElement).parentElement - if (!container) return - const previousCursor = document.body.style.cursor - const previousUserSelect = document.body.style.userSelect const onMouseMove = (moveEvent: MouseEvent) => { + const container = (e.target as HTMLElement).parentElement + if (!container) return + const rect = container.getBoundingClientRect() const x = moveEvent.clientX - rect.left const percent = Math.max( @@ -39,14 +31,12 @@ export function ResizableSplit(props: ResizableSplitProps) { setLeftPercent(percent) } - cleanupDrag = () => { + const onMouseUp = () => { document.removeEventListener('mousemove', onMouseMove) document.removeEventListener('mouseup', onMouseUp) - document.body.style.cursor = previousCursor - document.body.style.userSelect = previousUserSelect - cleanupDrag = undefined + document.body.style.cursor = '' + document.body.style.userSelect = '' } - const onMouseUp = () => cleanupDrag?.() document.addEventListener('mousemove', onMouseMove) document.addEventListener('mouseup', onMouseUp) diff --git a/packages/table-devtools/src/components/RowsPanel.tsx b/packages/table-devtools/src/components/RowsPanel.tsx index 873b4d0dab..79a045892b 100644 --- a/packages/table-devtools/src/components/RowsPanel.tsx +++ b/packages/table-devtools/src/components/RowsPanel.tsx @@ -51,9 +51,9 @@ export function RowsPanel() { () => table()?.store, (state) => state, ) - const optionsVersion = useTableStore( + const tableOptions = useTableStore( () => table()?.optionAtoms.snapshotVersion, - (version) => version, + () => table()?.options as unknown, ) const [selectedRowModel, setSelectedRowModel] = @@ -63,7 +63,8 @@ export function RowsPanel() { const tableInstance = table() if (!tableInstance) return undefined - optionsVersion() + tableState() + tableOptions() const data = tableInstance.options.data as ReadonlyArray if (!Array.isArray(data)) return data @@ -75,7 +76,8 @@ export function RowsPanel() { const tableInstance = table() if (!tableInstance) return 0 - optionsVersion() + tableState() + tableOptions() const data = tableInstance.options.data as ReadonlyArray return Array.isArray(data) ? data.length : 0 @@ -86,7 +88,7 @@ export function RowsPanel() { if (!tableInstance) return [] tableState() - optionsVersion() + tableOptions() const tableWithColumnFns = tableInstance as unknown as { getVisibleLeafColumns?: () => Array @@ -216,25 +218,18 @@ export function RowsPanel() { - {(row) => { - const cells = createMemo(() => { - tableState() - return getCells(row) - }) - - return ( - - {row.id} - - {(cell) => ( - - {stringifyValue(cell.getValue())} - - )} - - - ) - }} + {(row) => ( + + {row.id} + + {(cell) => ( + + {stringifyValue(cell.getValue())} + + )} + + + )} diff --git a/packages/table-devtools/src/components/Shell.tsx b/packages/table-devtools/src/components/Shell.tsx index 56ecbdb32c..3da49071db 100644 --- a/packages/table-devtools/src/components/Shell.tsx +++ b/packages/table-devtools/src/components/Shell.tsx @@ -25,6 +25,7 @@ export function Shell() { setActiveTab, selectedTargetId, setSelectedTargetId, + table, targets, } = useTableDevtoolsContext() @@ -80,8 +81,8 @@ export function Shell() {
- - {(_selectedTargetId) => ( + + {(_table) => ( diff --git a/packages/table-devtools/src/components/StatePanel.tsx b/packages/table-devtools/src/components/StatePanel.tsx index d04999af3e..026d230c00 100644 --- a/packages/table-devtools/src/components/StatePanel.tsx +++ b/packages/table-devtools/src/components/StatePanel.tsx @@ -6,11 +6,15 @@ import { useTableStore } from '../useTableStore' import { useStyles } from '../styles/use-styles' import { NoTableConnected } from './NoTableConnected' import { ThreeWayResizableSplit } from './ThreeWayResizableSplit' -import type { Accessor } from 'solid-js' -import type { TableDevtoolsStyles } from '../styles/use-styles' type AtomSource = 'external-atom' | 'external-state' | 'internal' +interface AtomSlice { + key: string + value: unknown + source: AtomSource +} + export function StatePanel() { const styles = useStyles() const { table } = useTableDevtoolsContext() @@ -18,60 +22,72 @@ export function StatePanel() { const [storeCopied, setStoreCopied] = createSignal(false) const [pasteError, setPasteError] = createSignal(null) + // Subscribe to both stores so the panel re-renders when either the table + // state or the options (e.g. options.atoms / options.state) change. const tableState = useTableStore( () => table()?.store, (state) => state, ) - const optionsVersion = useTableStore( + const tableOptions = useTableStore( () => table()?.optionAtoms.snapshotVersion, - (version) => version, + () => table()?.options as unknown, ) const initialState = createMemo((): unknown => { const tableInstance = table() if (!tableInstance) return undefined + tableState() + tableOptions() + return tableInstance.initialState }) - const storeState = createMemo((): Record | undefined => { + const storeState = createMemo((): unknown => { const tableInstance = table() if (!tableInstance) return undefined - return (tableState() ?? tableInstance.store.get()) as Record< - string, - unknown - > + tableState() + tableOptions() + + return tableInstance.store.state }) - const tableOptions = createMemo | undefined>(() => { + const atomSlices = createMemo((): Array => { const tableInstance = table() - if (!tableInstance) return undefined - - optionsVersion() - return tableInstance.options - }) + if (!tableInstance) return [] - const atomKeys = createMemo(() => Object.keys(storeState() ?? {})) + // Touch subscriptions so this recomputes on state or option change. + tableState() + tableOptions() - const getAtomSource = (key: string): AtomSource => { - const options = tableOptions() ?? {} + const options = tableInstance.options as unknown as Record const externalAtoms = (options.atoms as Record | undefined) ?? {} const externalState = (options.state as Record | undefined) ?? {} - const hasExternalAtom = externalAtoms[key] != null - const hasExternalState = - !hasExternalAtom && - key in externalState && - externalState[key] !== undefined - - return hasExternalAtom - ? 'external-atom' - : hasExternalState - ? 'external-state' - : 'internal' - } + const storeState = tableInstance.store.state as Record + + return Object.keys(storeState).map((key) => { + const hasExternalAtom = externalAtoms[key] != null + const hasExternalState = + !hasExternalAtom && + key in externalState && + externalState[key] !== undefined + + const source: AtomSource = hasExternalAtom + ? 'external-atom' + : hasExternalState + ? 'external-state' + : 'internal' + + return { + key, + value: storeState[key], + source, + } + }) + }) const copyToClipboard = async ( value: unknown, @@ -158,15 +174,8 @@ export function StatePanel() { Reset to initialState
- - {(key) => ( - getAtomSource(key)} - styles={styles} - value={() => storeState()?.[key]} - /> - )} + + {(slice) => } } @@ -201,14 +210,11 @@ export function StatePanel() { ) } -function AtomRow(props: { - atomKey: string - source: Accessor - styles: Accessor - value: Accessor -}) { +function AtomRow(props: { slice: AtomSlice }) { + const styles = useStyles() + const badgeLabel = () => { - switch (props.source()) { + switch (props.slice.source) { case 'external-atom': return 'External Atom' case 'external-state': @@ -219,25 +225,25 @@ function AtomRow(props: { } const badgeClass = () => { - const base = props.styles().atomBadge - switch (props.source()) { + const base = styles().atomBadge + switch (props.slice.source) { case 'external-atom': - return `${base} ${props.styles().atomBadgeExternalAtom}` + return `${base} ${styles().atomBadgeExternalAtom}` case 'external-state': - return `${base} ${props.styles().atomBadgeExternalState}` + return `${base} ${styles().atomBadgeExternalState}` case 'internal': - return `${base} ${props.styles().atomBadgeInternal}` + return `${base} ${styles().atomBadgeInternal}` } } return ( -
-
- {props.atomKey} +
+
+ {props.slice.key} {badgeLabel()}
-
- +
+
) diff --git a/packages/table-devtools/src/components/ThreeWayResizableSplit.tsx b/packages/table-devtools/src/components/ThreeWayResizableSplit.tsx index 098752c91b..3a5803172e 100644 --- a/packages/table-devtools/src/components/ThreeWayResizableSplit.tsx +++ b/packages/table-devtools/src/components/ThreeWayResizableSplit.tsx @@ -1,4 +1,4 @@ -import { createSignal, onCleanup } from 'solid-js' +import { createSignal } from 'solid-js' import { useStyles } from '../styles/use-styles' import type { JSX } from 'solid-js' @@ -17,24 +17,15 @@ export function ThreeWayResizableSplit(props: ThreeWayResizableSplitProps) { const styles = useStyles() const [leftPercent, setLeftPercent] = createSignal(DEFAULT_LEFT_PERCENT) const [middlePercent, setMiddlePercent] = createSignal(DEFAULT_MIDDLE_PERCENT) - let cleanupDrag: (() => void) | undefined - - onCleanup(() => { - cleanupDrag?.() - }) const makeDragHandler = (which: 'left' | 'right'): ((e: MouseEvent) => void) => // eslint-disable-next-line solid/reactivity (e) => { e.preventDefault() - cleanupDrag?.() - const handleEl = e.currentTarget as HTMLElement const container = handleEl.parentElement if (!container) return - const previousCursor = document.body.style.cursor - const previousUserSelect = document.body.style.userSelect const startLeft = leftPercent() const startMiddle = middlePercent() @@ -65,14 +56,12 @@ export function ThreeWayResizableSplit(props: ThreeWayResizableSplitProps) { } } - cleanupDrag = () => { + const onMouseUp = () => { document.removeEventListener('mousemove', onMouseMove) document.removeEventListener('mouseup', onMouseUp) - document.body.style.cursor = previousCursor - document.body.style.userSelect = previousUserSelect - cleanupDrag = undefined + document.body.style.cursor = '' + document.body.style.userSelect = '' } - const onMouseUp = () => cleanupDrag?.() document.addEventListener('mousemove', onMouseMove) document.addEventListener('mouseup', onMouseUp) diff --git a/packages/table-devtools/src/index.ts b/packages/table-devtools/src/index.ts index a1ff6af3e8..1c5d82106e 100644 --- a/packages/table-devtools/src/index.ts +++ b/packages/table-devtools/src/index.ts @@ -10,7 +10,6 @@ export const TableDevtoolsCore: ClassType = export type { TableDevtoolsInit } from './core' export { - createTableDevtoolsRegistrationManager, getTableDevtoolsTargets, removeTableDevtoolsTarget, setTableDevtoolsTarget, @@ -19,7 +18,6 @@ export { } from './tableTarget' export type { TableDevtoolsRegistration, - TableDevtoolsRegistrationManager, TableDevtoolsStore, TableDevtoolsTable, UpsertTableDevtoolsTargetOptions, diff --git a/packages/table-devtools/src/production.ts b/packages/table-devtools/src/production.ts index d39c265b89..df414118c9 100644 --- a/packages/table-devtools/src/production.ts +++ b/packages/table-devtools/src/production.ts @@ -4,7 +4,6 @@ export { TableDevtoolsCore } from './core' export type { TableDevtoolsInit } from './core' export { - createTableDevtoolsRegistrationManager, getTableDevtoolsTargets, removeTableDevtoolsTarget, setTableDevtoolsTarget, @@ -13,7 +12,6 @@ export { } from './tableTarget' export type { TableDevtoolsRegistration, - TableDevtoolsRegistrationManager, TableDevtoolsStore, TableDevtoolsTable, UpsertTableDevtoolsTargetOptions, diff --git a/packages/table-devtools/src/styles/use-styles.ts b/packages/table-devtools/src/styles/use-styles.ts index 1eae90b6e2..2793262938 100644 --- a/packages/table-devtools/src/styles/use-styles.ts +++ b/packages/table-devtools/src/styles/use-styles.ts @@ -1,5 +1,5 @@ import * as goober from 'goober' -import { createMemo } from 'solid-js' +import { createEffect, createSignal } from 'solid-js' import { createTheme } from '@tanstack/devtools-ui' import { tokens } from './tokens' @@ -398,21 +398,11 @@ const stylesFactory = (theme: 'light' | 'dark') => { export function useStyles() { const { theme } = createTheme() - const styles = createMemo(() => getStyles(theme())) - return styles -} - -export type TableDevtoolsStyles = ReturnType + const [styles, setStyles] = createSignal(stylesFactory(theme())) -const stylesByTheme = new Map<'light' | 'dark', TableDevtoolsStyles>() - -function getStyles(theme: 'light' | 'dark'): TableDevtoolsStyles { - const cached = stylesByTheme.get(theme) - if (cached) { - return cached - } + createEffect(() => { + setStyles(stylesFactory(theme())) + }) - const styles = stylesFactory(theme) - stylesByTheme.set(theme, styles) return styles } diff --git a/packages/table-devtools/src/tableTarget.ts b/packages/table-devtools/src/tableTarget.ts index b3a349bba1..6a87d37803 100644 --- a/packages/table-devtools/src/tableTarget.ts +++ b/packages/table-devtools/src/tableTarget.ts @@ -25,7 +25,7 @@ export interface TableDevtoolsTable { [key: string]: unknown } optionAtoms: { - snapshotVersion: Readable + readonly snapshotVersion: Readable } reset: () => void store: TableDevtoolsStore @@ -36,11 +36,6 @@ export interface TableDevtoolsRegistration { table: TableDevtoolsTable } -interface TableDevtoolsRegistrationEntry { - registration: TableDevtoolsRegistration - leases: Set -} - export interface UpsertTableDevtoolsTargetOptions< TFeatures extends TableFeatures, TData extends RowData, @@ -48,16 +43,8 @@ export interface UpsertTableDevtoolsTargetOptions< table: Table } -export interface TableDevtoolsRegistrationManager { - update: ( - table: Table | undefined, - enabled?: boolean, - ) => void - dispose: () => void -} - const [registrationsMap, setRegistrationsMap] = createSignal< - Map + Map >(new Map()) function getTableKey(table: TableDevtoolsTable) { @@ -78,61 +65,35 @@ export function upsertTableDevtoolsTarget< } const registrations = untrack(registrationsMap) - const existingEntry = registrations.get(key) - const lease = Symbol(key) - - if (existingEntry) { - if ( - existingEntry.registration.table === table || - existingEntry.registration.table.store === table.store - ) { - if (existingEntry.registration.table !== table) { - Object.assign(existingEntry.registration.table, table) - } - existingEntry.leases.add(lease) + const existingRegistration = registrations.get(key) + + if (existingRegistration) { + if (existingRegistration.table === table) { return () => { - releaseTableDevtoolsTarget(key, lease) + removeTableDevtoolsTarget(key) } } const nextRegistrations = new Map(registrations) nextRegistrations.set(key, { - registration: { - id: key, - table, - }, - leases: new Set([lease]), + id: key, + table, }) setRegistrationsMap(nextRegistrations) } else { const nextRegistrations = new Map(registrations) nextRegistrations.set(key, { - registration: { - id: key, - table, - }, - leases: new Set([lease]), + id: key, + table, }) setRegistrationsMap(nextRegistrations) } return () => { - releaseTableDevtoolsTarget(key, lease) + removeTableDevtoolsTarget(key) } } -function releaseTableDevtoolsTarget(id: string, lease: symbol) { - const registrations = untrack(registrationsMap) - const entry = registrations.get(id) - if (!entry?.leases.delete(lease) || entry.leases.size > 0) { - return - } - - const nextRegistrations = new Map(registrations) - nextRegistrations.delete(id) - setRegistrationsMap(nextRegistrations) -} - export function removeTableDevtoolsTarget(id: string) { const registrations = untrack(registrationsMap) if (!registrations.has(id)) { @@ -146,7 +107,7 @@ export function removeTableDevtoolsTarget(id: string) { } export function getTableDevtoolsTargets(): Array { - return Array.from(registrationsMap().values(), (entry) => entry.registration) + return Array.from(registrationsMap().values()) } export function subscribeTableDevtoolsTargets(listener: Listener) { @@ -170,25 +131,3 @@ export function setTableDevtoolsTarget< upsertTableDevtoolsTarget({ table }) } - -export function createTableDevtoolsRegistrationManager(): TableDevtoolsRegistrationManager { - let cleanup: (() => void) | undefined - - return { - update: (table, enabled = true) => { - if (!enabled || !table) { - cleanup?.() - cleanup = undefined - return - } - - const previousCleanup = cleanup - cleanup = upsertTableDevtoolsTarget({ table }) - previousCleanup?.() - }, - dispose: () => { - cleanup?.() - cleanup = undefined - }, - } -} diff --git a/packages/table-devtools/src/useTableStore.ts b/packages/table-devtools/src/useTableStore.ts index 0dd8ffcd44..70fbfa2ec4 100644 --- a/packages/table-devtools/src/useTableStore.ts +++ b/packages/table-devtools/src/useTableStore.ts @@ -2,44 +2,30 @@ import { createEffect, createSignal, onCleanup } from 'solid-js' import type { Accessor } from 'solid-js' import type { Readable } from '@tanstack/solid-store' -interface UseTableStoreOptions { - equals?: false | ((previous: U | undefined, next: U | undefined) => boolean) -} - /** * Subscribes to a table store and returns a reactive signal. - * Handles both function and `{ unsubscribe }` subscription results. + * Handles both subscribe APIs: function return (store 0.8.x) and + * { unsubscribe } object return (store 0.9.x). */ export function useTableStore( storeAccessor: Accessor | null | undefined>, selector: (state: T) => U = (s) => s as unknown as U, - options?: UseTableStoreOptions, ): Accessor { - const initialStore = storeAccessor() - const [signal, setSignal] = createSignal( - initialStore ? selector(initialStore.get()) : undefined, - { equals: options?.equals }, + const initialValue = storeAccessor()?.get() + const [signal, setSignal] = createSignal( + initialValue ? selector(initialValue) : undefined, ) createEffect(() => { const store = storeAccessor() - if (!store) { - setSignal(() => undefined) - return - } + if (!store) return - setSignal(() => selector(store.get())) - - const subscription = store.subscribe((snapshot) => { - setSignal(() => selector(snapshot)) - }) as unknown as { unsubscribe: () => void } | (() => void) + const subscription = store.subscribe(() => { + setSignal(() => selector(store.get())) + }) onCleanup(() => { - if (typeof subscription === 'function') { - subscription() - } else { - subscription.unsubscribe() - } + subscription.unsubscribe() }) }) diff --git a/packages/table-devtools/tests/panel-lifecycle.test.tsx b/packages/table-devtools/tests/panel-lifecycle.test.tsx deleted file mode 100644 index 04f9e0dc1e..0000000000 --- a/packages/table-devtools/tests/panel-lifecycle.test.tsx +++ /dev/null @@ -1,74 +0,0 @@ -import { createSignal } from 'solid-js' -import { render } from 'solid-js/web' -import { afterEach, describe, expect, it, vi } from 'vitest' -import TableDevtools from '../src/TableDevtools' -import { - getTableDevtoolsTargets, - removeTableDevtoolsTarget, - upsertTableDevtoolsTarget, -} from '../src/tableTarget' -import type { TableDevtoolsTable } from '../src/tableTarget' - -function createDevtoolsTable() { - const unsubscribe = vi.fn() - const subscribe = vi.fn(() => ({ unsubscribe })) - const table = { - _features: {}, - _rowModelFns: {}, - baseAtoms: {}, - initialState: {}, - options: { - features: {}, - key: 'users-table', - }, - optionAtoms: { - snapshotVersion: { - get: () => 0, - subscribe: () => ({ unsubscribe: () => {} }), - }, - }, - reset: vi.fn(), - store: { - get: () => ({}), - state: {}, - subscribe, - }, - } satisfies TableDevtoolsTable - - return { subscribe, table, unsubscribe } -} - -afterEach(() => { - for (const target of getTableDevtoolsTargets()) { - removeTableDevtoolsTarget(target.id) - } -}) - -describe('TableDevtools panel lifecycle', () => { - it('subscribes only while the devtools panel is open', async () => { - const { subscribe, table, unsubscribe } = createDevtoolsTable() - const cleanupTarget = upsertTableDevtoolsTarget({ - table: table as never, - }) - const [open, setOpen] = createSignal(false) - const element = document.createElement('div') - const dispose = render( - () => , - element, - ) - - await Promise.resolve() - expect(subscribe).not.toHaveBeenCalled() - - setOpen(true) - await Promise.resolve() - expect(subscribe).toHaveBeenCalledTimes(1) - - setOpen(false) - await Promise.resolve() - expect(unsubscribe).toHaveBeenCalledTimes(1) - - dispose() - cleanupTarget?.() - }) -}) diff --git a/packages/table-devtools/tests/styles.test.tsx b/packages/table-devtools/tests/styles.test.tsx deleted file mode 100644 index 28dc5444f3..0000000000 --- a/packages/table-devtools/tests/styles.test.tsx +++ /dev/null @@ -1,51 +0,0 @@ -import { createSignal } from 'solid-js' -import { render } from 'solid-js/web' -import { ThemeContextProvider } from '@tanstack/devtools-ui' -import { beforeEach, describe, expect, it, vi } from 'vitest' - -const { css } = vi.hoisted(() => ({ - css: vi.fn(() => 'generated-class'), -})) - -vi.mock('goober', () => ({ - css, -})) - -beforeEach(() => { - css.mockClear() -}) - -describe('useStyles', () => { - it('generates each theme once across consumers', async () => { - const { useStyles } = await import('../src/styles/use-styles') - const [theme, setTheme] = createSignal<'light' | 'dark'>('dark') - - function Consumer() { - useStyles() - useStyles() - return null - } - - const element = document.createElement('div') - const dispose = render( - () => ( - - - - ), - element, - ) - - expect(css).toHaveBeenCalledTimes(51) - - setTheme('light') - await Promise.resolve() - expect(css).toHaveBeenCalledTimes(102) - - setTheme('dark') - await Promise.resolve() - expect(css).toHaveBeenCalledTimes(102) - - dispose() - }) -}) diff --git a/packages/table-devtools/tests/tableTarget.test.ts b/packages/table-devtools/tests/tableTarget.test.ts index 8595cae9f8..0f1d1082ea 100644 --- a/packages/table-devtools/tests/tableTarget.test.ts +++ b/packages/table-devtools/tests/tableTarget.test.ts @@ -2,10 +2,8 @@ import { afterEach, describe, expect, it, vi } from 'vitest' import { constructTable, coreFeatures } from '@tanstack/table-core' import { storeReactivityBindings } from '@tanstack/table-core/store-reactivity-bindings' import { - createTableDevtoolsRegistrationManager, getTableDevtoolsTargets, removeTableDevtoolsTarget, - subscribeTableDevtoolsTargets, upsertTableDevtoolsTarget, } from '../src/tableTarget' @@ -66,100 +64,6 @@ describe('tableTarget', () => { expect(getTableDevtoolsTargets()).toEqual([]) }) - it('does not let stale cleanup remove a replacement table', () => { - const firstTable = createTable('users-table') - const nextTable = createTable('users-table') - - const cleanupFirst = upsertTableDevtoolsTarget({ table: firstTable }) - const cleanupNext = upsertTableDevtoolsTarget({ table: nextTable }) - - cleanupFirst?.() - - expect(getTableDevtoolsTargets()).toEqual([ - { - id: 'users-table', - table: nextTable, - }, - ]) - - cleanupNext?.() - expect(getTableDevtoolsTargets()).toEqual([]) - }) - - it('keeps a shared table registered until its final lease is released', () => { - const table = createTable('users-table') - - const cleanupFirst = upsertTableDevtoolsTarget({ table }) - const cleanupSecond = upsertTableDevtoolsTarget({ table }) - - cleanupFirst?.() - expect(getTableDevtoolsTargets()).toHaveLength(1) - - cleanupSecond?.() - expect(getTableDevtoolsTargets()).toEqual([]) - }) - - it('replaces a managed registration without publishing an empty registry', () => { - const manager = createTableDevtoolsRegistrationManager() - const firstTable = createTable('users-table') - const nextTable = createTable('users-table') - - manager.update(firstTable) - - const targetCounts: Array = [] - const unsubscribe = subscribeTableDevtoolsTargets((targets) => { - targetCounts.push(targets.length) - }) - - manager.update(nextTable) - - expect(targetCounts).toEqual([1, 1]) - expect(getTableDevtoolsTargets()).toEqual([ - { - id: 'users-table', - table: nextTable, - }, - ]) - - manager.dispose() - - expect(targetCounts).toEqual([1, 1, 0]) - unsubscribe() - }) - - it('updates transient wrappers without publishing a new target', () => { - const manager = createTableDevtoolsRegistrationManager() - const table = createTable('users-table') - const firstWrapper = { - ...table, - options: { - ...table.options, - debugAll: false, - }, - } - const nextWrapper = { - ...table, - options: { - ...table.options, - debugAll: true, - }, - } - - manager.update(firstWrapper) - - const listener = vi.fn() - const unsubscribe = subscribeTableDevtoolsTargets(listener) - - manager.update(nextWrapper) - - expect(listener).toHaveBeenCalledTimes(1) - expect(getTableDevtoolsTargets()[0]?.table).toBe(firstWrapper) - expect(getTableDevtoolsTargets()[0]?.table.options.debugAll).toBe(true) - - unsubscribe() - manager.dispose() - }) - it('logs and skips registration when the key is missing', () => { const consoleError = vi.spyOn(console, 'error').mockImplementation(() => {}) const table = createTable() @@ -186,31 +90,6 @@ describe('tableTarget', () => { ) }) - it('exposes a reactive resolved-options version to devtools', () => { - const table = createTable('users-table') - upsertTableDevtoolsTarget({ table }) - - const target = getTableDevtoolsTargets()[0]!.table - const snapshotVersion = target.optionAtoms.snapshotVersion - expect(snapshotVersion.get()).toBe(0) - - const versions: Array = [] - const subscription = snapshotVersion.subscribe((version) => { - versions.push(version) - }) - - table.setOptions((previous) => ({ - ...previous, - debugAll: true, - })) - - expect(snapshotVersion.get()).toBe(1) - expect(versions).toEqual([1]) - expect(target.options.debugAll).toBe(true) - - subscription.unsubscribe() - }) - it('removes keyed registrations directly', () => { const table = createTable('users-table') diff --git a/packages/vue-table-devtools/src/VueTableDevtools.tsx b/packages/vue-table-devtools/src/VueTableDevtools.tsx index 564229333e..ec9ba617d7 100644 --- a/packages/vue-table-devtools/src/VueTableDevtools.tsx +++ b/packages/vue-table-devtools/src/VueTableDevtools.tsx @@ -36,17 +36,16 @@ function createPanelWrapper( name, props: ['theme', 'devtoolsOpen'], setup(props: TableDevtoolsVueInit) { - return () => { - const devtoolsProps = { - theme: props.theme ?? 'dark', - devtoolsOpen: props.devtoolsOpen ?? false, - } - return h(Component, { - key: `${devtoolsProps.theme}:${devtoolsProps.devtoolsOpen}`, + const devtoolsProps = { + theme: props.theme ?? 'dark', + devtoolsOpen: props.devtoolsOpen ?? false, + } + + return () => + h(Component, { props, devtoolsProps, }) - } }, }) as DefineComponent } diff --git a/packages/vue-table-devtools/src/production.ts b/packages/vue-table-devtools/src/production.ts index 88724a9295..5823644b5a 100644 --- a/packages/vue-table-devtools/src/production.ts +++ b/packages/vue-table-devtools/src/production.ts @@ -1,5 +1,5 @@ -export { TableDevtoolsPanel } from './production/VueTableDevtools' +export { TableDevtoolsPanel } from './VueTableDevtools' export type { TableDevtoolsVueInit } from './VueTableDevtools' -export { tableDevtoolsPlugin } from './production/plugin' +export { tableDevtoolsPlugin } from './plugin' export { useTanStackTableDevtools } from './useTanStackTableDevtools' export type { UseTanStackTableDevtoolsOptions } from './useTanStackTableDevtools' diff --git a/packages/vue-table-devtools/src/production/VueTableDevtools.tsx b/packages/vue-table-devtools/src/production/VueTableDevtools.tsx deleted file mode 100644 index d9ad422562..0000000000 --- a/packages/vue-table-devtools/src/production/VueTableDevtools.tsx +++ /dev/null @@ -1,46 +0,0 @@ -import { createVuePanel } from '@tanstack/devtools-utils/vue' -import { TableDevtoolsCore } from '@tanstack/table-devtools/production' -import { defineComponent, h } from 'vue' -import type { DevtoolsPanelProps } from '@tanstack/devtools-utils/vue' -import type { DefineComponent } from 'vue' -import type { TableDevtoolsVueInit } from '../VueTableDevtools' - -class TableDevtoolsVueCore { - private readonly core = new TableDevtoolsCore() - - constructor(_props: DevtoolsPanelProps) {} - - mount(el: HTMLElement, props?: DevtoolsPanelProps) { - void this.core.mount(el, { - theme: props?.theme ?? 'dark', - devtoolsOpen: props?.devtoolsOpen ?? false, - }) - } - - unmount() { - this.core.unmount() - } -} - -const [TableDevtoolsPanelBase] = createVuePanel< - DevtoolsPanelProps, - TableDevtoolsVueCore ->(TableDevtoolsVueCore) - -export const TableDevtoolsPanel = defineComponent({ - name: 'TableDevtoolsPanel', - props: ['theme', 'devtoolsOpen'], - setup(props: TableDevtoolsVueInit) { - return () => { - const devtoolsProps = { - theme: props.theme ?? 'dark', - devtoolsOpen: props.devtoolsOpen ?? false, - } - return h(TableDevtoolsPanelBase, { - key: `${devtoolsProps.theme}:${devtoolsProps.devtoolsOpen}`, - props, - devtoolsProps, - }) - } - }, -}) as DefineComponent diff --git a/packages/vue-table-devtools/src/production/plugin.ts b/packages/vue-table-devtools/src/production/plugin.ts deleted file mode 100644 index c20a591a12..0000000000 --- a/packages/vue-table-devtools/src/production/plugin.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { createVuePlugin } from '@tanstack/devtools-utils/vue' -import { TableDevtoolsPanel } from './VueTableDevtools' - -const [tableDevtoolsPlugin] = createVuePlugin( - 'TanStack Table', - TableDevtoolsPanel, -) - -export { tableDevtoolsPlugin } diff --git a/packages/vue-table-devtools/src/useTanStackTableDevtools.ts b/packages/vue-table-devtools/src/useTanStackTableDevtools.ts index feef50dbb0..23da5d8b59 100644 --- a/packages/vue-table-devtools/src/useTanStackTableDevtools.ts +++ b/packages/vue-table-devtools/src/useTanStackTableDevtools.ts @@ -1,5 +1,5 @@ -import { onScopeDispose, unref, watchEffect } from 'vue' -import { createTableDevtoolsRegistrationManager } from '@tanstack/table-devtools' +import { unref, watchEffect } from 'vue' +import { upsertTableDevtoolsTarget } from '@tanstack/table-devtools' import type { RowData, Table, TableFeatures } from '@tanstack/table-core' import type { MaybeRef } from 'vue' @@ -14,14 +14,19 @@ export function useTanStackTableDevtools< table: MaybeRef | undefined>, options?: MaybeRef, ): void { - const registration = createTableDevtoolsRegistrationManager() - onScopeDispose(() => registration.dispose()) - - watchEffect(() => { + watchEffect((onCleanup) => { const resolvedOptions = unref(options) const resolvedTable = unref(table) - registration.update(resolvedTable, resolvedOptions?.enabled ?? true) + if (!(resolvedOptions?.enabled ?? true) || !resolvedTable) { + return + } + + const cleanup = upsertTableDevtoolsTarget({ table: resolvedTable }) + + onCleanup(() => { + cleanup?.() + }) }) } From 7abe825b3fee5f4353d37f3765fd3438542f3305 Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Fri, 31 Jul 2026 14:01:05 +0000 Subject: [PATCH 3/3] ci: apply automated fixes --- packages/alpine-table/src/reactivity.ts | 8 +- packages/ember-table/src/use-table.ts | 6 +- .../tests/integration/use-table.test.gts | 12 ++- packages/solid-table/src/reactivity.ts | 12 +-- .../svelte-table/src/reactivity.svelte.ts | 8 +- .../createStableStoreReadonlyAtom.ts | 20 ++-- .../core/reactivity/renderPhaseReactivity.ts | 4 +- .../src/core/row-models/createCoreRowModel.ts | 10 +- .../src/core/rows/subRowsTracking.ts | 9 +- .../src/core/table/constructTable.ts | 5 +- .../src/core/table/coreTablesFeature.types.ts | 4 +- .../src/core/table/coreTablesFeature.utils.ts | 4 +- .../src/core/table/tableOptionAtoms.ts | 16 ++- .../column-pinning/columnPinningFeature.ts | 7 +- .../column-sizing/columnSizingFeature.ts | 5 +- packages/table-core/src/utils.ts | 22 +--- .../unit/core/renderPhaseReactivity.test.ts | 8 +- .../columnOrderingFeature.utils.test.ts | 5 +- .../columnResizingFeature.utils.test.ts | 100 ++++++++---------- 19 files changed, 100 insertions(+), 165 deletions(-) diff --git a/packages/alpine-table/src/reactivity.ts b/packages/alpine-table/src/reactivity.ts index fa2090add1..b795beed62 100644 --- a/packages/alpine-table/src/reactivity.ts +++ b/packages/alpine-table/src/reactivity.ts @@ -28,11 +28,9 @@ export function alpineReactivity(): TableReactivityBindings { batch, untrack: (fn) => fn(), createReadonlyAtom: (fn: () => T, options?: TableAtomOptions) => { - return createStableStoreReadonlyAtom( - createAtom, - fn, - { compare: options?.compare }, - ) + return createStableStoreReadonlyAtom(createAtom, fn, { + compare: options?.compare, + }) }, createWritableAtom: (value: T, options?: TableAtomOptions) => { return createAtom(value, { diff --git a/packages/ember-table/src/use-table.ts b/packages/ember-table/src/use-table.ts index 77123394f8..20c070a4c6 100644 --- a/packages/ember-table/src/use-table.ts +++ b/packages/ember-table/src/use-table.ts @@ -85,11 +85,7 @@ export function useTable< const currentHasKey = Reflect.has(defaultOptions, key) const nextValue = Reflect.get(newOptions, key, newOptions) as unknown const currentValue = currentHasKey - ? (Reflect.get( - defaultOptions, - key, - defaultOptions, - ) as unknown) + ? (Reflect.get(defaultOptions, key, defaultOptions) as unknown) : undefined if (!currentHasKey || !Object.is(currentValue, nextValue)) { diff --git a/packages/ember-table/tests/integration/use-table.test.gts b/packages/ember-table/tests/integration/use-table.test.gts index 22d34e05ba..039bb0212b 100644 --- a/packages/ember-table/tests/integration/use-table.test.gts +++ b/packages/ember-table/tests/integration/use-table.test.gts @@ -245,7 +245,11 @@ module('Integration | useTable', function (hooks) { {{this.optionAtomDataLength}} - diff --git a/packages/solid-table/src/reactivity.ts b/packages/solid-table/src/reactivity.ts index f16570e05d..b8b10fe7ed 100644 --- a/packages/solid-table/src/reactivity.ts +++ b/packages/solid-table/src/reactivity.ts @@ -68,14 +68,10 @@ export function solidReactivity(owner: Owner): TableReactivityBindings { schedule: (fn) => queueMicrotask(() => fn()), createReadonlyAtom: (fn: () => T, options?: TableAtomOptions) => { const signal = runWithOwner(owner, () => - createMemo( - () => fn(), - undefined, - { - ...(options?.compare ? { equals: options.compare } : {}), - name: options?.debugName, - }, - ), + createMemo(() => fn(), undefined, { + ...(options?.compare ? { equals: options.compare } : {}), + name: options?.debugName, + }), )! return signalToReadonlyAtom(signal, owner) }, diff --git a/packages/svelte-table/src/reactivity.svelte.ts b/packages/svelte-table/src/reactivity.svelte.ts index 766e413728..031f44d115 100644 --- a/packages/svelte-table/src/reactivity.svelte.ts +++ b/packages/svelte-table/src/reactivity.svelte.ts @@ -38,11 +38,9 @@ export function svelteReactivity(): TableReactivityBindings { }, schedule: (fn) => queueMicrotask(() => fn()), createReadonlyAtom: (fn: () => T, _options?: TableAtomOptions) => { - const storeAtom = createStableStoreReadonlyAtom( - createAtom, - fn, - { compare: _options?.compare }, - ) + const storeAtom = createStableStoreReadonlyAtom(createAtom, fn, { + compare: _options?.compare, + }) const trackStore = createSubscriber((update) => { const subscription = storeAtom.subscribe(() => { update() diff --git a/packages/table-core/src/core/reactivity/createStableStoreReadonlyAtom.ts b/packages/table-core/src/core/reactivity/createStableStoreReadonlyAtom.ts index 9ab518cd86..0f411ed804 100644 --- a/packages/table-core/src/core/reactivity/createStableStoreReadonlyAtom.ts +++ b/packages/table-core/src/core/reactivity/createStableStoreReadonlyAtom.ts @@ -21,23 +21,19 @@ export function createStableStoreReadonlyAtom( const compare = options?.compare ?? Object.is let stableBox: { value: T } | undefined - const boxedAtom = createAtom( - () => { - const nextValue = fn() + const boxedAtom = createAtom(() => { + const nextValue = fn() - if (!stableBox || !compare(stableBox.value, nextValue)) { - stableBox = { value: nextValue } - } + if (!stableBox || !compare(stableBox.value, nextValue)) { + stableBox = { value: nextValue } + } - return stableBox - }, - ) + return stableBox + }) return { get: () => boxedAtom.get().value, - subscribe: (( - observer: Observer | ((value: T) => void), - ) => { + subscribe: ((observer: Observer | ((value: T) => void)) => { return boxedAtom.subscribe((box) => { if (typeof observer === 'function') { observer(box.value) diff --git a/packages/table-core/src/core/reactivity/renderPhaseReactivity.ts b/packages/table-core/src/core/reactivity/renderPhaseReactivity.ts index 48871ccbef..ff4dc45a36 100644 --- a/packages/table-core/src/core/reactivity/renderPhaseReactivity.ts +++ b/packages/table-core/src/core/reactivity/renderPhaseReactivity.ts @@ -186,9 +186,7 @@ export function renderPhaseReactivity( dirty = true } }, - subscribe: (( - observer: Observer | ((value: T) => void), - ) => { + subscribe: ((observer: Observer | ((value: T) => void)) => { let previous = currentValue return publishedVersion.subscribe(() => { const nextValue = currentValue diff --git a/packages/table-core/src/core/row-models/createCoreRowModel.ts b/packages/table-core/src/core/row-models/createCoreRowModel.ts index e79a057808..67dd50501d 100644 --- a/packages/table-core/src/core/row-models/createCoreRowModel.ts +++ b/packages/table-core/src/core/row-models/createCoreRowModel.ts @@ -61,10 +61,7 @@ function accessRows( ) => string) | undefined, getSubRows: - | (( - originalRow: TData, - index: number, - ) => ReadonlyArray | undefined) + | ((originalRow: TData, index: number) => ReadonlyArray | undefined) | undefined, depth = 0, parentRow?: Row, @@ -131,10 +128,7 @@ function _createCoreRowModel< ) => string) | undefined, getSubRows: - | (( - originalRow: TData, - index: number, - ) => ReadonlyArray | undefined) + | ((originalRow: TData, index: number) => ReadonlyArray | undefined) | undefined, ): { rows: Array> diff --git a/packages/table-core/src/core/rows/subRowsTracking.ts b/packages/table-core/src/core/rows/subRowsTracking.ts index 22ad240e91..83fa06d3ce 100644 --- a/packages/table-core/src/core/rows/subRowsTracking.ts +++ b/packages/table-core/src/core/rows/subRowsTracking.ts @@ -25,9 +25,7 @@ const subRowsTracking = new WeakMap() export function row_getTrackedSubRows< TFeatures extends TableFeatures, TData extends RowData, ->( - row: Row, -): Array> { +>(row: Row): Array> { const tracking = subRowsTracking.get(row) if (!tracking) { @@ -70,10 +68,7 @@ export function row_getTrackedSubRows< export function row_setSubRows< TFeatures extends TableFeatures, TData extends RowData, ->( - row: Row, - subRows: Array>, -): void { +>(row: Row, subRows: Array>): void { const tracking = subRowsTracking.get(row) if (!tracking) { diff --git a/packages/table-core/src/core/table/constructTable.ts b/packages/table-core/src/core/table/constructTable.ts index e22b4478c5..70a699396f 100644 --- a/packages/table-core/src/core/table/constructTable.ts +++ b/packages/table-core/src/core/table/constructTable.ts @@ -121,10 +121,7 @@ export function constructTable< (key, updater) => { table.setOptions((previous) => ({ ...previous, - [key]: functionalUpdate( - updater, - Reflect.get(previous, key, previous), - ), + [key]: functionalUpdate(updater, Reflect.get(previous, key, previous)), })) }, ) diff --git a/packages/table-core/src/core/table/coreTablesFeature.types.ts b/packages/table-core/src/core/table/coreTablesFeature.types.ts index 1d4ecce558..cdf8b144f8 100644 --- a/packages/table-core/src/core/table/coreTablesFeature.types.ts +++ b/packages/table-core/src/core/table/coreTablesFeature.types.ts @@ -84,7 +84,9 @@ export type TableOptionAtoms< readonly [K in keyof TableOptions< TFeatures, TData - > as K extends 'snapshotVersion' ? never : K]: K extends ConstructStaticOptionKey + > as K extends 'snapshotVersion' + ? never + : K]: K extends ConstructStaticOptionKey ? ReadonlyAtom[K]> : Atom[K]> } diff --git a/packages/table-core/src/core/table/coreTablesFeature.utils.ts b/packages/table-core/src/core/table/coreTablesFeature.utils.ts index 4060fbc928..b05855af0b 100644 --- a/packages/table-core/src/core/table/coreTablesFeature.utils.ts +++ b/packages/table-core/src/core/table/coreTablesFeature.utils.ts @@ -38,9 +38,7 @@ export function table_syncExternalStateToBaseAtoms< ) => currentState === externalState, ): void { const state = - capturedState === undefined - ? table.options.state - : capturedState + capturedState === undefined ? table.options.state : capturedState table._reactivity.batch(() => { if (state) { diff --git a/packages/table-core/src/core/table/tableOptionAtoms.ts b/packages/table-core/src/core/table/tableOptionAtoms.ts index 565a8df36b..6d22ef4847 100644 --- a/packages/table-core/src/core/table/tableOptionAtoms.ts +++ b/packages/table-core/src/core/table/tableOptionAtoms.ts @@ -59,10 +59,7 @@ export function createTableOptionAtoms< writable: false, }) - const setValue = ( - key: OptionKey, - value: unknown, - ): boolean => { + const setValue = (key: OptionKey, value: unknown): boolean => { if (key === snapshotVersionKey) { throw new Error( `Table option "${snapshotVersionKey}" is reserved by table.optionAtoms`, @@ -148,10 +145,7 @@ export function createTableOptionAtoms< reactivity.batch(() => { for (const key of nextKeys) { changed = - setValue( - key, - Reflect.get(nextOptions, key, nextOptions), - ) || changed + setValue(key, Reflect.get(nextOptions, key, nextOptions)) || changed } if (changed) { @@ -179,8 +173,10 @@ export function getTableOptionsFromAtoms< >( optionAtoms: TableOptionAtoms, ): TableOptionsLive { - return optionAtomsInternals.get(optionAtoms)! - .options as TableOptionsLive + return optionAtomsInternals.get(optionAtoms)!.options as TableOptionsLive< + TFeatures, + TData + > } export function applyTableOptions< diff --git a/packages/table-core/src/features/column-pinning/columnPinningFeature.ts b/packages/table-core/src/features/column-pinning/columnPinningFeature.ts index aab012b817..2338800b83 100644 --- a/packages/table-core/src/features/column-pinning/columnPinningFeature.ts +++ b/packages/table-core/src/features/column-pinning/columnPinningFeature.ts @@ -190,12 +190,7 @@ export const columnPinningFeature: TableFeature = { orderedLeafColumns.push(column) } } - return buildHeaderGroups( - allColumns, - orderedLeafColumns, - table, - position, - ) + return buildHeaderGroups(allColumns, orderedLeafColumns, table, position) } assignTableAPIs('columnPinningFeature', table, { diff --git a/packages/table-core/src/features/column-sizing/columnSizingFeature.ts b/packages/table-core/src/features/column-sizing/columnSizingFeature.ts index f74fc4cb86..0ad8c1576f 100644 --- a/packages/table-core/src/features/column-sizing/columnSizingFeature.ts +++ b/packages/table-core/src/features/column-sizing/columnSizingFeature.ts @@ -145,10 +145,7 @@ export const columnSizingFeature: TableFeature = { if (header.column.columns.length > 0) { return header_getSize(header) } - return resolveColumnSize( - header.column, - readColumnSize(header.column), - ) + return resolveColumnSize(header.column, readColumnSize(header.column)) }, }, header_getStart: { diff --git a/packages/table-core/src/utils.ts b/packages/table-core/src/utils.ts index c18657c3a5..d4a84c99fb 100755 --- a/packages/table-core/src/utils.ts +++ b/packages/table-core/src/utils.ts @@ -150,10 +150,7 @@ export function flattenBy( return flat } -interface TableMemoOptions< - TFeatures extends TableFeatures, - TResult, -> { +interface TableMemoOptions { compare?: (previous: TResult, next: TResult) => boolean feature?: keyof TFeatures & string fn: () => TResult @@ -177,10 +174,7 @@ const pad = (str: number | string, num: number) => { * The native readonly atom is created on the first public read so eager * framework computeds cannot evaluate during incomplete table construction. */ -export function tableMemo< - TFeatures extends TableFeatures, - TResult, ->({ +export function tableMemo({ compare, feature, fn, @@ -205,10 +199,7 @@ export function tableMemo< debugInitialized = true table._reactivity.untrack(() => { - const options = table.options as unknown as Record< - PropertyKey, - unknown - > + const options = table.options as unknown as Record const { parentName } = getFunctionNameInfo(fnName, '.') const debugParent = ( parentName !== 'table' ? `${parentName}s` : parentName @@ -218,9 +209,7 @@ export function tableMemo< ) const debugByParent = options[`debug${debugParent}`] const debugByFeature = feature - ? options[ - `debug${feature.charAt(0).toUpperCase() + feature.slice(1)}` - ] + ? options[`debug${feature.charAt(0).toUpperCase() + feature.slice(1)}`] : false debug = Boolean(options.debugAll || debugByParent || debugByFeature) @@ -313,8 +302,7 @@ export function tableMemo< const result = (atom ?? createAtom()).get() if (debugCache && evaluationCount === beforeEvaluation) { - const cacheTime = - Math.round((performance.now() - startedAt) * 100) / 100 + const cacheTime = Math.round((performance.now() - startedAt) * 100) / 100 table._reactivity.untrack(() => logTime(cacheTime, false)) } diff --git a/packages/table-core/tests/unit/core/renderPhaseReactivity.test.ts b/packages/table-core/tests/unit/core/renderPhaseReactivity.test.ts index 93449550fe..205f8a6e8d 100644 --- a/packages/table-core/tests/unit/core/renderPhaseReactivity.test.ts +++ b/packages/table-core/tests/unit/core/renderPhaseReactivity.test.ts @@ -203,11 +203,9 @@ describe('renderPhaseReactivity bindings', () => { const { bindings, internalTable } = makeDeferredTable() // The first merge installs construct-static undefined slots. Subsequent // render merges with the same values should not rotate memo caches. - table_setOptions( - internalTable, - (options) => ({ ...options }), - { syncExternalState: false }, - ) + table_setOptions(internalTable, (options) => ({ ...options }), { + syncExternalState: false, + }) const stageSpy = vi.spyOn(bindings, 'stage') const token = table_setOptions( diff --git a/packages/table-core/tests/unit/features/column-ordering/columnOrderingFeature.utils.test.ts b/packages/table-core/tests/unit/features/column-ordering/columnOrderingFeature.utils.test.ts index b09c5a816d..7c2fbbe784 100644 --- a/packages/table-core/tests/unit/features/column-ordering/columnOrderingFeature.utils.test.ts +++ b/packages/table-core/tests/unit/features/column-ordering/columnOrderingFeature.utils.test.ts @@ -218,8 +218,9 @@ describe('table_getOrderColumnsFn', () => { groupedColumnMode: 'reorder', }) const getOrderColumnsFn = () => - (table as unknown as { getOrderColumnsFn: () => () => unknown }) - .getOrderColumnsFn() + ( + table as unknown as { getOrderColumnsFn: () => () => unknown } + ).getOrderColumnsFn() const initial = getOrderColumnsFn() diff --git a/packages/table-core/tests/unit/features/column-resizing/columnResizingFeature.utils.test.ts b/packages/table-core/tests/unit/features/column-resizing/columnResizingFeature.utils.test.ts index d3163e8f9f..2a244ea01c 100644 --- a/packages/table-core/tests/unit/features/column-resizing/columnResizingFeature.utils.test.ts +++ b/packages/table-core/tests/unit/features/column-resizing/columnResizingFeature.utils.test.ts @@ -285,9 +285,7 @@ describe('header_getResizeHandler', () => { enableColumnResizing: false, }) const onColumnResizingChange = vi.fn() - table.optionAtoms.onColumnResizingChange!.set( - () => onColumnResizingChange, - ) + table.optionAtoms.onColumnResizingChange!.set(() => onColumnResizingChange) const header = createTestResizeHeader(table) const handler = header_getResizeHandler(header as any) @@ -299,9 +297,7 @@ describe('header_getResizeHandler', () => { it('should ignore multi-touch events', () => { const table = makeTable(1) const onColumnResizingChange = vi.fn() - table.optionAtoms.onColumnResizingChange!.set( - () => onColumnResizingChange, - ) + table.optionAtoms.onColumnResizingChange!.set(() => onColumnResizingChange) const header = createTestResizeHeader(table) const handler = header_getResizeHandler(header as any) @@ -340,25 +336,21 @@ describe('header_getResizeHandler', () => { }) let resizingState = getDefaultColumnResizingState() - table.optionAtoms.onColumnResizingChange!.set( - () => (updater) => { - resizingState = - typeof updater === 'function' ? updater(resizingState) : updater - ;(table.store.state as any).columnResizing = resizingState - }, - ) + table.optionAtoms.onColumnResizingChange!.set(() => (updater) => { + resizingState = + typeof updater === 'function' ? updater(resizingState) : updater + ;(table.store.state as any).columnResizing = resizingState + }) const sizingUpdates: Array> = [] - table.optionAtoms.onColumnSizingChange!.set( - () => (updater) => { - if (typeof updater === 'function') { - const result = updater(table.atoms.columnSizing.get()) - sizingUpdates.push(result) - } else { - sizingUpdates.push(updater) - } - }, - ) + table.optionAtoms.onColumnSizingChange!.set(() => (updater) => { + if (typeof updater === 'function') { + const result = updater(table.atoms.columnSizing.get()) + sizingUpdates.push(result) + } else { + sizingUpdates.push(updater) + } + }) const zeroSizeColumn = { ...table.getAllColumns()[0], @@ -400,14 +392,12 @@ describe('header_getResizeHandler', () => { let resizingState = getDefaultColumnResizingState() const resizingUpdates: Array = [] - table.optionAtoms.onColumnResizingChange!.set( - () => (updater) => { - resizingState = - typeof updater === 'function' ? updater(resizingState) : updater - ;(table.store.state as any).columnResizing = resizingState - resizingUpdates.push(resizingState) - }, - ) + table.optionAtoms.onColumnResizingChange!.set(() => (updater) => { + resizingState = + typeof updater === 'function' ? updater(resizingState) : updater + ;(table.store.state as any).columnResizing = resizingState + resizingUpdates.push(resizingState) + }) const zeroSizeColumn = { ...table.getAllColumns()[0], @@ -499,15 +489,13 @@ describe('header_getResizeHandler', () => { columnResizeMode: 'onChange', }) const sizingUpdates: Array> = [] - table.optionAtoms.onColumnSizingChange!.set( - () => (updater) => { - sizingUpdates.push( - typeof updater === 'function' - ? updater(table.atoms.columnSizing.get()) - : updater, - ) - }, - ) + table.optionAtoms.onColumnSizingChange!.set(() => (updater) => { + sizingUpdates.push( + typeof updater === 'function' + ? updater(table.atoms.columnSizing.get()) + : updater, + ) + }) const header = createTestResizeHeader(table) const handler = header_getResizeHandler(header as any, document) @@ -560,15 +548,13 @@ describe('header_getResizeHandler', () => { columnResizeMode: 'onEnd', }) const sizingUpdates: Array> = [] - table.optionAtoms.onColumnSizingChange!.set( - () => (updater) => { - sizingUpdates.push( - typeof updater === 'function' - ? updater(table.atoms.columnSizing.get()) - : updater, - ) - }, - ) + table.optionAtoms.onColumnSizingChange!.set(() => (updater) => { + sizingUpdates.push( + typeof updater === 'function' + ? updater(table.atoms.columnSizing.get()) + : updater, + ) + }) const header = createTestResizeHeader(table) const handler = header_getResizeHandler(header as any, document) @@ -624,15 +610,13 @@ describe('header_getResizeHandler', () => { columnResizeMode: 'onChange', }) const sizingUpdates: Array> = [] - table.optionAtoms.onColumnSizingChange!.set( - () => (updater) => { - sizingUpdates.push( - typeof updater === 'function' - ? updater(table.atoms.columnSizing.get()) - : updater, - ) - }, - ) + table.optionAtoms.onColumnSizingChange!.set(() => (updater) => { + sizingUpdates.push( + typeof updater === 'function' + ? updater(table.atoms.columnSizing.get()) + : updater, + ) + }) const header = createTestResizeHeader(table) const handler = header_getResizeHandler(header as any, document)