@tanstack/table-core 9.0.0-beta.69 → 9.0.0-beta.70

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (89) hide show
  1. package/dist/core/cells/constructCell.d.ts +1 -1
  2. package/dist/core/cells/coreCellsFeature.types.d.ts +1 -1
  3. package/dist/core/cells/coreCellsFeature.utils.d.ts +1 -1
  4. package/dist/core/columns/constructColumn.d.ts +1 -1
  5. package/dist/core/columns/coreColumnsFeature.types.d.ts +1 -1
  6. package/dist/core/columns/coreColumnsFeature.utils.d.ts +1 -1
  7. package/dist/core/headers/buildHeaderGroups.d.ts +1 -1
  8. package/dist/core/headers/constructHeader.d.ts +1 -1
  9. package/dist/core/headers/coreHeadersFeature.types.d.ts +1 -1
  10. package/dist/core/headers/coreHeadersFeature.utils.d.ts +1 -1
  11. package/dist/core/row-models/coreRowModelsFeature.types.d.ts +4 -4
  12. package/dist/core/row-models/coreRowModelsFeature.utils.d.ts +1 -1
  13. package/dist/core/row-models/createCoreRowModel.d.ts +1 -1
  14. package/dist/core/rows/constructRow.d.ts +1 -1
  15. package/dist/core/rows/coreRowsFeature.types.d.ts +1 -1
  16. package/dist/core/rows/coreRowsFeature.utils.d.ts +1 -1
  17. package/dist/features/cell-selection/cellSelectionFeature.js +13 -2
  18. package/dist/features/cell-selection/cellSelectionFeature.types.d.ts +9 -0
  19. package/dist/features/cell-selection/cellSelectionFeature.utils.d.ts +20 -1
  20. package/dist/features/cell-selection/cellSelectionFeature.utils.js +139 -11
  21. package/dist/features/cell-selection/cellSelectionGeometry.js +32 -1
  22. package/dist/features/cell-spanning/cellSpanningFeature.d.ts +13 -0
  23. package/dist/features/cell-spanning/cellSpanningFeature.js +47 -0
  24. package/dist/features/cell-spanning/cellSpanningFeature.types.d.ts +150 -0
  25. package/dist/features/cell-spanning/cellSpanningFeature.utils.d.ts +74 -0
  26. package/dist/features/cell-spanning/cellSpanningFeature.utils.js +262 -0
  27. package/dist/features/column-faceting/columnFacetingFeature.utils.d.ts +1 -1
  28. package/dist/features/column-faceting/createFacetedRowModel.d.ts +1 -1
  29. package/dist/features/column-filtering/columnFilteringFeature.utils.d.ts +1 -1
  30. package/dist/features/column-filtering/createFilteredRowModel.d.ts +1 -1
  31. package/dist/features/column-grouping/columnGroupingFeature.utils.d.ts +2 -2
  32. package/dist/features/column-grouping/createGroupedRowModel.d.ts +1 -1
  33. package/dist/features/column-ordering/columnOrderingFeature.utils.d.ts +1 -1
  34. package/dist/features/column-pinning/columnPinningFeature.utils.d.ts +2 -2
  35. package/dist/features/column-resizing/columnResizingFeature.utils.d.ts +1 -1
  36. package/dist/features/column-sizing/columnSizingFeature.utils.d.ts +2 -2
  37. package/dist/features/column-visibility/columnVisibilityFeature.utils.d.ts +1 -1
  38. package/dist/features/global-filtering/globalFilteringFeature.utils.d.ts +1 -1
  39. package/dist/features/row-aggregation/rowAggregationFeature.types.d.ts +1 -1
  40. package/dist/features/row-expanding/createExpandedRowModel.d.ts +1 -1
  41. package/dist/features/row-expanding/rowExpandingFeature.utils.d.ts +1 -1
  42. package/dist/features/row-pagination/createPaginatedRowModel.d.ts +1 -1
  43. package/dist/features/row-pinning/rowPinningFeature.utils.d.ts +1 -1
  44. package/dist/features/row-selection/rowSelectionFeature.utils.d.ts +1 -1
  45. package/dist/features/row-sorting/createSortedRowModel.d.ts +1 -1
  46. package/dist/features/row-sorting/rowSortingFeature.utils.d.ts +1 -1
  47. package/dist/features/stockFeatures.d.ts +2 -0
  48. package/dist/features/stockFeatures.js +2 -0
  49. package/dist/index.d.ts +24 -22
  50. package/dist/index.js +2 -1
  51. package/dist/static-functions.d.ts +3 -2
  52. package/dist/static-functions.js +3 -2
  53. package/dist/types/Cell.d.ts +3 -1
  54. package/dist/types/Column.d.ts +7 -7
  55. package/dist/types/ColumnDef.d.ts +8 -6
  56. package/dist/types/Header.d.ts +1 -1
  57. package/dist/types/Row.d.ts +4 -4
  58. package/dist/types/RowModel.d.ts +4 -4
  59. package/dist/types/Table.d.ts +15 -13
  60. package/dist/types/TableFeatures.d.ts +4 -4
  61. package/dist/types/TableOptions.d.ts +16 -14
  62. package/dist/types/TableState.d.ts +8 -8
  63. package/dist/worker/createWorkerRowModel.d.ts +1 -1
  64. package/dist/worker/rebuildRowModel.d.ts +1 -1
  65. package/package.json +1 -1
  66. package/skills/aggregation/SKILL.md +1 -1
  67. package/skills/api-not-found/SKILL.md +1 -1
  68. package/skills/cell-selection/SKILL.md +1 -1
  69. package/skills/cell-spanning/SKILL.md +162 -0
  70. package/skills/client-vs-server/SKILL.md +1 -1
  71. package/skills/column-faceting/SKILL.md +1 -1
  72. package/skills/column-filtering/SKILL.md +1 -1
  73. package/skills/column-ordering/SKILL.md +1 -1
  74. package/skills/column-pinning/SKILL.md +1 -1
  75. package/skills/column-resizing/SKILL.md +1 -1
  76. package/skills/column-sizing/SKILL.md +1 -1
  77. package/skills/column-visibility/SKILL.md +1 -1
  78. package/skills/core/SKILL.md +1 -1
  79. package/skills/custom-features/SKILL.md +1 -1
  80. package/skills/expanding/SKILL.md +1 -1
  81. package/skills/global-filtering/SKILL.md +1 -1
  82. package/skills/grouping/SKILL.md +1 -1
  83. package/skills/migrate-v8-to-v9/SKILL.md +1 -1
  84. package/skills/pagination/SKILL.md +1 -1
  85. package/skills/row-pinning/SKILL.md +1 -1
  86. package/skills/row-selection/SKILL.md +1 -1
  87. package/skills/sorting/SKILL.md +1 -1
  88. package/skills/table-features/SKILL.md +1 -1
  89. package/skills/typescript/SKILL.md +1 -1
@@ -1,7 +1,7 @@
1
1
  import { CellData, RowData } from "../../types/type-utils.js";
2
- import { Table } from "../../types/Table.js";
3
2
  import { Column } from "../../types/Column.js";
4
3
  import { Row } from "../../types/Row.js";
4
+ import { Table } from "../../types/Table.js";
5
5
  import { Cell } from "../../types/Cell.js";
6
6
  import { TableFeatures } from "../../types/TableFeatures.js";
7
7
  //#region src/core/cells/constructCell.d.ts
@@ -1,7 +1,7 @@
1
1
  import { CellData, Getter, RowData } from "../../types/type-utils.js";
2
- import { Table } from "../../types/Table.js";
3
2
  import { Column } from "../../types/Column.js";
4
3
  import { Row } from "../../types/Row.js";
4
+ import { Table } from "../../types/Table.js";
5
5
  import { Cell } from "../../types/Cell.js";
6
6
  import { TableFeatures } from "../../types/TableFeatures.js";
7
7
  //#region src/core/cells/coreCellsFeature.types.d.ts
@@ -1,7 +1,7 @@
1
1
  import { CellData, NoInfer, RowData } from "../../types/type-utils.js";
2
- import { Table } from "../../types/Table.js";
3
2
  import { Column } from "../../types/Column.js";
4
3
  import { Row } from "../../types/Row.js";
4
+ import { Table } from "../../types/Table.js";
5
5
  import { Cell } from "../../types/Cell.js";
6
6
  import { TableFeatures } from "../../types/TableFeatures.js";
7
7
  import "../../index.js";
@@ -1,7 +1,7 @@
1
1
  import { CellData, RowData } from "../../types/type-utils.js";
2
2
  import { ColumnDef } from "../../types/ColumnDef.js";
3
- import { Table } from "../../types/Table.js";
4
3
  import { Column } from "../../types/Column.js";
4
+ import { Table } from "../../types/Table.js";
5
5
  import { TableFeatures } from "../../types/TableFeatures.js";
6
6
  //#region src/core/columns/constructColumn.d.ts
7
7
  /**
@@ -1,7 +1,7 @@
1
1
  import { CellData, RowData } from "../../types/type-utils.js";
2
2
  import { AccessorFn, ColumnDef } from "../../types/ColumnDef.js";
3
- import { Table } from "../../types/Table.js";
4
3
  import { Column } from "../../types/Column.js";
4
+ import { Table } from "../../types/Table.js";
5
5
  import { TableFeatures } from "../../types/TableFeatures.js";
6
6
  //#region src/core/columns/coreColumnsFeature.types.d.ts
7
7
  interface Column_CoreProperties<in out TFeatures extends TableFeatures, in out TData extends RowData, TValue extends CellData = CellData> {
@@ -1,7 +1,7 @@
1
1
  import { CellData, RowData } from "../../types/type-utils.js";
2
2
  import { ColumnDef } from "../../types/ColumnDef.js";
3
- import { Table } from "../../types/Table.js";
4
3
  import { Column } from "../../types/Column.js";
4
+ import { Table } from "../../types/Table.js";
5
5
  import { TableFeatures } from "../../types/TableFeatures.js";
6
6
  //#region src/core/columns/coreColumnsFeature.utils.d.ts
7
7
  /**
@@ -1,7 +1,7 @@
1
1
  import { CellData, RowData } from "../../types/type-utils.js";
2
2
  import { HeaderGroup } from "../../types/HeaderGroup.js";
3
- import { Table } from "../../types/Table.js";
4
3
  import { Column } from "../../types/Column.js";
4
+ import { Table } from "../../types/Table.js";
5
5
  import { TableFeatures } from "../../types/TableFeatures.js";
6
6
  //#region src/core/headers/buildHeaderGroups.d.ts
7
7
  /**
@@ -1,7 +1,7 @@
1
1
  import { CellData, RowData } from "../../types/type-utils.js";
2
2
  import { Header } from "../../types/Header.js";
3
- import { Table } from "../../types/Table.js";
4
3
  import { Column } from "../../types/Column.js";
4
+ import { Table } from "../../types/Table.js";
5
5
  import { TableFeatures } from "../../types/TableFeatures.js";
6
6
  //#region src/core/headers/constructHeader.d.ts
7
7
  /**
@@ -1,8 +1,8 @@
1
1
  import { CellData, RowData } from "../../types/type-utils.js";
2
2
  import { HeaderGroup } from "../../types/HeaderGroup.js";
3
3
  import { Header } from "../../types/Header.js";
4
- import { Table } from "../../types/Table.js";
5
4
  import { Column } from "../../types/Column.js";
5
+ import { Table } from "../../types/Table.js";
6
6
  import { TableFeatures } from "../../types/TableFeatures.js";
7
7
  //#region src/core/headers/coreHeadersFeature.types.d.ts
8
8
  interface Table_Headers<in out TFeatures extends TableFeatures, in out TData extends RowData> {
@@ -1,8 +1,8 @@
1
1
  import { RowData } from "../../types/type-utils.js";
2
2
  import { HeaderGroup } from "../../types/HeaderGroup.js";
3
3
  import { Header } from "../../types/Header.js";
4
- import { Table } from "../../types/Table.js";
5
4
  import { Column } from "../../types/Column.js";
5
+ import { Table } from "../../types/Table.js";
6
6
  import { TableFeatures } from "../../types/TableFeatures.js";
7
7
  import "../../index.js";
8
8
  //#region src/core/headers/coreHeadersFeature.utils.d.ts
@@ -1,11 +1,11 @@
1
1
  import { RowData } from "../../types/type-utils.js";
2
- import { Table_RowModels_Faceted } from "../../features/column-faceting/columnFacetingFeature.types.js";
3
- import { Table_RowModels_Expanded } from "../../features/row-expanding/rowExpandingFeature.types.js";
4
- import { Table_RowModels_Paginated } from "../../features/row-pagination/rowPaginationFeature.types.js";
5
2
  import { Table_RowModels_Sorted } from "../../features/row-sorting/rowSortingFeature.types.js";
3
+ import { Table_RowModels_Grouped } from "../../features/column-grouping/columnGroupingFeature.types.js";
4
+ import { Table_RowModels_Expanded } from "../../features/row-expanding/rowExpandingFeature.types.js";
6
5
  import { Row } from "../../types/Row.js";
7
6
  import { Table_RowModels_Filtered } from "../../features/column-filtering/columnFilteringFeature.types.js";
8
- import { Table_RowModels_Grouped } from "../../features/column-grouping/columnGroupingFeature.types.js";
7
+ import { Table_RowModels_Paginated } from "../../features/row-pagination/rowPaginationFeature.types.js";
8
+ import { Table_RowModels_Faceted } from "../../features/column-faceting/columnFacetingFeature.types.js";
9
9
  import { TableFeatures } from "../../types/TableFeatures.js";
10
10
  //#region src/core/row-models/coreRowModelsFeature.types.d.ts
11
11
  interface RowModel<in out TFeatures extends TableFeatures, in out TData extends RowData> {
@@ -1,6 +1,6 @@
1
1
  import { RowData } from "../../types/type-utils.js";
2
- import { Table } from "../../types/Table.js";
3
2
  import { RowModel } from "./coreRowModelsFeature.types.js";
3
+ import { Table } from "../../types/Table.js";
4
4
  import { TableFeatures } from "../../types/TableFeatures.js";
5
5
  //#region src/core/row-models/coreRowModelsFeature.utils.d.ts
6
6
  /**
@@ -1,6 +1,6 @@
1
1
  import { RowData } from "../../types/type-utils.js";
2
- import { Table } from "../../types/Table.js";
3
2
  import { RowModel } from "./coreRowModelsFeature.types.js";
3
+ import { Table } from "../../types/Table.js";
4
4
  import { TableFeatures } from "../../types/TableFeatures.js";
5
5
  //#region src/core/row-models/createCoreRowModel.d.ts
6
6
  /**
@@ -1,6 +1,6 @@
1
1
  import { RowData } from "../../types/type-utils.js";
2
- import { Table } from "../../types/Table.js";
3
2
  import { Row } from "../../types/Row.js";
3
+ import { Table } from "../../types/Table.js";
4
4
  import { TableFeatures } from "../../types/TableFeatures.js";
5
5
  //#region src/core/rows/constructRow.d.ts
6
6
  /**
@@ -1,7 +1,7 @@
1
1
  import { RowData } from "../../types/type-utils.js";
2
- import { Table } from "../../types/Table.js";
3
2
  import { Column } from "../../types/Column.js";
4
3
  import { Row } from "../../types/Row.js";
4
+ import { Table } from "../../types/Table.js";
5
5
  import { Cell } from "../../types/Cell.js";
6
6
  import { TableFeatures } from "../../types/TableFeatures.js";
7
7
  //#region src/core/rows/coreRowsFeature.types.d.ts
@@ -1,6 +1,6 @@
1
1
  import { RowData } from "../../types/type-utils.js";
2
- import { Table } from "../../types/Table.js";
3
2
  import { Row } from "../../types/Row.js";
3
+ import { Table } from "../../types/Table.js";
4
4
  import { Cell } from "../../types/Cell.js";
5
5
  import { TableFeatures } from "../../types/TableFeatures.js";
6
6
  //#region src/core/rows/coreRowsFeature.utils.d.ts
@@ -1,5 +1,5 @@
1
1
  import { assignPrototypeAPIs, assignTableAPIs, callMemoOrStaticFn, makeStateUpdater } from "../../utils.js";
2
- import { cell_getCanSelect, cell_getIsFocused, cell_getIsSelected, cell_getSelectionEdges, cell_getSelectionExtendHandler, cell_getSelectionStartHandler, cell_getTabIndex, getDefaultCellSelectionState, table_autoResetCellSelection, table_extendCellSelection, table_getCellSelectionBounds, table_getCellSelectionColumnIds, table_getCellSelectionColumnIndexes, table_getCellSelectionRowIds, table_getFocusedCell, table_getSelectedCellCount, table_getSelectedCellIds, table_getSelectedCellRangesData, table_moveCellSelection, table_resetCellSelection, table_selectAllCells, table_selectCellRange, table_setCellSelection, table_setFocusedCell } from "./cellSelectionFeature.utils.js";
2
+ import { cell_getCanSelect, cell_getIsFocused, cell_getIsSelected, cell_getSelectionEdges, cell_getSelectionExtendHandler, cell_getSelectionStartHandler, cell_getTabIndex, getDefaultCellSelectionState, table_autoResetCellSelection, table_extendCellSelection, table_getCellSelectionBounds, table_getCellSelectionColumnIds, table_getCellSelectionColumnIndexes, table_getCellSelectionMergeBounds, table_getCellSelectionRowIds, table_getFocusedCell, table_getSelectedCellCount, table_getSelectedCellIds, table_getSelectedCellRangesData, table_moveCellSelection, table_resetCellSelection, table_selectAllCells, table_selectCellRange, table_setCellSelection, table_setFocusedCell } from "./cellSelectionFeature.utils.js";
3
3
 
4
4
  //#region src/features/cell-selection/cellSelectionFeature.ts
5
5
  /**
@@ -63,12 +63,21 @@ const cellSelectionFeature = {
63
63
  table.options.groupedColumnMode
64
64
  ]
65
65
  },
66
+ table_getCellSelectionMergeBounds: {
67
+ fn: () => table_getCellSelectionMergeBounds(table),
68
+ memoDeps: () => [
69
+ table.getCellSpanIndex?.(),
70
+ table.getRowsInDisplayOrder(),
71
+ callMemoOrStaticFn(table, "getCellSelectionColumnIndexes", table_getCellSelectionColumnIndexes)
72
+ ]
73
+ },
66
74
  table_getCellSelectionBounds: {
67
75
  fn: () => table_getCellSelectionBounds(table),
68
76
  memoDeps: () => [
69
77
  table.atoms.cellSelection?.get(),
70
78
  table.getRowsInDisplayOrder(),
71
- callMemoOrStaticFn(table, "getCellSelectionColumnIndexes", table_getCellSelectionColumnIndexes)
79
+ callMemoOrStaticFn(table, "getCellSelectionColumnIndexes", table_getCellSelectionColumnIndexes),
80
+ callMemoOrStaticFn(table, "getCellSelectionMergeBounds", table_getCellSelectionMergeBounds)
72
81
  ]
73
82
  },
74
83
  table_selectCellRange: { fn: (range, opts) => table_selectCellRange(table, range, opts) },
@@ -81,6 +90,7 @@ const cellSelectionFeature = {
81
90
  fn: () => table_getSelectedCellIds(table),
82
91
  memoDeps: () => [
83
92
  callMemoOrStaticFn(table, "getCellSelectionBounds", table_getCellSelectionBounds),
93
+ callMemoOrStaticFn(table, "getCellSelectionMergeBounds", table_getCellSelectionMergeBounds),
84
94
  table.getRowsInDisplayOrder(),
85
95
  table.options.enableCellSelection
86
96
  ]
@@ -97,6 +107,7 @@ const cellSelectionFeature = {
97
107
  fn: () => table_getSelectedCellCount(table),
98
108
  memoDeps: () => [
99
109
  callMemoOrStaticFn(table, "getCellSelectionBounds", table_getCellSelectionBounds),
110
+ callMemoOrStaticFn(table, "getCellSelectionMergeBounds", table_getCellSelectionMergeBounds),
100
111
  table.getRowsInDisplayOrder(),
101
112
  table.options.enableCellSelection
102
113
  ]
@@ -211,6 +211,15 @@ interface Table_CellSelection<in out TFeatures extends TableFeatures, in out TDa
211
211
  * corners no longer resolve are omitted.
212
212
  */
213
213
  getCellSelectionBounds: () => Array<CellSelectionBounds>;
214
+ /**
215
+ * Returns the merged-cell rectangles of the rendered rows in selection's
216
+ * display-order index space, or an empty array when `cellSpanningFeature`
217
+ * is not registered.
218
+ *
219
+ * Selection rectangles expand to fully enclose these, so a merged cell is
220
+ * always entirely selected or entirely unselected.
221
+ */
222
+ getCellSelectionMergeBounds: () => Array<CellSelectionBounds>;
214
223
  /**
215
224
  * Returns the ids of all columns intersected by the selection.
216
225
  */
@@ -68,6 +68,25 @@ declare function table_autoResetCellSelection<TFeatures extends TableFeatures, T
68
68
  * ```
69
69
  */
70
70
  declare function table_getCellSelectionColumnIndexes<TFeatures extends TableFeatures, TData extends RowData>(table: Table<TFeatures, TData>): Record<string, number>;
71
+ /**
72
+ * Resolves the merged-cell rectangles of the rendered rows into selection's
73
+ * own index space.
74
+ *
75
+ * The span index positions rows by their paginated render order while
76
+ * selection positions them by pre-paginated display order, so each merge is
77
+ * mapped through `row.getDisplayIndex()`. A merge whose rows do not map to a
78
+ * contiguous display range is skipped defensively; it then behaves like
79
+ * unmerged cells instead of corrupting the geometry.
80
+ *
81
+ * Returns an empty array when `cellSpanningFeature` is not registered, which
82
+ * keeps every selection code path identical to the span-unaware behavior.
83
+ *
84
+ * @example
85
+ * ```ts
86
+ * const merges = table_getCellSelectionMergeBounds(table)
87
+ * ```
88
+ */
89
+ declare function table_getCellSelectionMergeBounds<TFeatures extends TableFeatures, TData extends RowData>(table: Table<TFeatures, TData>): Array<CellSelectionBounds>;
71
90
  /**
72
91
  * Resolves ordered range operations into disjoint, positive display-order
73
92
  * index rectangles.
@@ -284,4 +303,4 @@ declare function cell_getSelectionStartHandler<TFeatures extends TableFeatures,
284
303
  */
285
304
  declare function cell_getSelectionExtendHandler<TFeatures extends TableFeatures, TData extends RowData, TValue extends CellData = CellData>(cell: Cell<TFeatures, TData, TValue>): (_e: unknown) => void;
286
305
  //#endregion
287
- export { cell_getCanSelect, cell_getIsFocused, cell_getIsSelected, cell_getSelectionEdges, cell_getSelectionExtendHandler, cell_getSelectionStartHandler, cell_getTabIndex, getDefaultCellSelectionState, table_autoResetCellSelection, table_extendCellSelection, table_getCellSelectionBounds, table_getCellSelectionColumnIds, table_getCellSelectionColumnIndexes, table_getCellSelectionRowIds, table_getFocusedCell, table_getSelectedCellCount, table_getSelectedCellIds, table_getSelectedCellRangesData, table_moveCellSelection, table_resetCellSelection, table_selectAllCells, table_selectCellRange, table_setCellSelection, table_setFocusedCell };
306
+ export { cell_getCanSelect, cell_getIsFocused, cell_getIsSelected, cell_getSelectionEdges, cell_getSelectionExtendHandler, cell_getSelectionStartHandler, cell_getTabIndex, getDefaultCellSelectionState, table_autoResetCellSelection, table_extendCellSelection, table_getCellSelectionBounds, table_getCellSelectionColumnIds, table_getCellSelectionColumnIndexes, table_getCellSelectionMergeBounds, table_getCellSelectionRowIds, table_getFocusedCell, table_getSelectedCellCount, table_getSelectedCellIds, table_getSelectedCellRangesData, table_moveCellSelection, table_resetCellSelection, table_selectAllCells, table_selectCellRange, table_setCellSelection, table_setFocusedCell };
@@ -1,6 +1,6 @@
1
1
  import { callMemoOrStaticFn, cloneState, makeObjectMap } from "../../utils.js";
2
2
  import { table_getVisibleLeafColumns } from "../column-visibility/columnVisibilityFeature.utils.js";
3
- import { applyCellSelectionBoundsOperations } from "./cellSelectionGeometry.js";
3
+ import { applyCellSelectionBoundsOperations, expandCellSelectionBounds } from "./cellSelectionGeometry.js";
4
4
 
5
5
  //#region src/features/cell-selection/cellSelectionFeature.utils.ts
6
6
  /**
@@ -122,6 +122,87 @@ function table_getCellSelectionColumnIndexes(table) {
122
122
  for (let i = 0; i < columns.length; i++) indexes[columns[i].id] = i;
123
123
  return indexes;
124
124
  }
125
+ const EMPTY_MERGE_BOUNDS = [];
126
+ function probeCellSpanIndex(table) {
127
+ return table.getCellSpanIndex?.();
128
+ }
129
+ /**
130
+ * Resolves the merged-cell rectangles of the rendered rows into selection's
131
+ * own index space.
132
+ *
133
+ * The span index positions rows by their paginated render order while
134
+ * selection positions them by pre-paginated display order, so each merge is
135
+ * mapped through `row.getDisplayIndex()`. A merge whose rows do not map to a
136
+ * contiguous display range is skipped defensively; it then behaves like
137
+ * unmerged cells instead of corrupting the geometry.
138
+ *
139
+ * Returns an empty array when `cellSpanningFeature` is not registered, which
140
+ * keeps every selection code path identical to the span-unaware behavior.
141
+ *
142
+ * @example
143
+ * ```ts
144
+ * const merges = table_getCellSelectionMergeBounds(table)
145
+ * ```
146
+ */
147
+ function table_getCellSelectionMergeBounds(table) {
148
+ const spanIndex = probeCellSpanIndex(table);
149
+ if (!spanIndex) return EMPTY_MERGE_BOUNDS;
150
+ const columnIndexes = callMemoOrStaticFn(table, "getCellSelectionColumnIndexes", table_getCellSelectionColumnIndexes);
151
+ const merges = [];
152
+ for (const columnId in spanIndex.rowSpans) {
153
+ const columnIndex = columnIndexes[columnId];
154
+ if (columnIndex === void 0) continue;
155
+ const spans = spanIndex.rowSpans[columnId];
156
+ const spanColumnIndex = spanIndex.columnIndexes[columnId];
157
+ for (let r = 0; r < spans.length; r++) {
158
+ const span = spans[r];
159
+ if (span <= 1) continue;
160
+ const startRow = spanIndex.rows[r].getDisplayIndex();
161
+ const endRow = spanIndex.rows[r + span - 1].getDisplayIndex();
162
+ if (startRow < 0 || endRow - startRow !== span - 1) continue;
163
+ const colSpan = spanColumnIndex === void 0 ? 1 : Math.max(spanIndex.colSpans[r]?.[spanColumnIndex] ?? 1, 1);
164
+ merges.push({
165
+ minRowIndex: startRow,
166
+ maxRowIndex: endRow,
167
+ minColumnIndex: columnIndex,
168
+ maxColumnIndex: columnIndex + colSpan - 1
169
+ });
170
+ }
171
+ }
172
+ if (spanIndex.colSpans.length) {
173
+ const columnIdBySpanIndex = [];
174
+ for (const columnId in spanIndex.columnIndexes) columnIdBySpanIndex[spanIndex.columnIndexes[columnId]] = columnId;
175
+ for (let r = 0; r < spanIndex.colSpans.length; r++) {
176
+ const rowColSpans = spanIndex.colSpans[r];
177
+ if (!rowColSpans) continue;
178
+ const displayRow = spanIndex.rows[r]?.getDisplayIndex() ?? -1;
179
+ if (displayRow < 0) continue;
180
+ for (let c = 0; c < rowColSpans.length; c++) {
181
+ const span = rowColSpans[c];
182
+ if (span <= 1) continue;
183
+ const columnId = columnIdBySpanIndex[c];
184
+ if (columnId === void 0) continue;
185
+ const vertical = spanIndex.rowSpans[columnId];
186
+ if (vertical && vertical[r] !== 1) continue;
187
+ const columnIndex = columnIndexes[columnId];
188
+ if (columnIndex === void 0) continue;
189
+ merges.push({
190
+ minRowIndex: displayRow,
191
+ maxRowIndex: displayRow,
192
+ minColumnIndex: columnIndex,
193
+ maxColumnIndex: columnIndex + span - 1
194
+ });
195
+ }
196
+ }
197
+ }
198
+ return merges;
199
+ }
200
+ function findMergeBoundsAt(merges, rowIndex, columnIndex) {
201
+ for (let i = 0; i < merges.length; i++) {
202
+ const merge = merges[i];
203
+ if (rowIndex >= merge.minRowIndex && rowIndex <= merge.maxRowIndex && columnIndex >= merge.minColumnIndex && columnIndex <= merge.maxColumnIndex) return merge;
204
+ }
205
+ }
125
206
  /**
126
207
  * Resolves a row id to its display-order index, or `-1` when it no longer
127
208
  * identifies a row in the current order.
@@ -172,6 +253,15 @@ function table_getCellSelectionBounds(table) {
172
253
  operation: range.operation ?? "include"
173
254
  });
174
255
  }
256
+ const merges = callMemoOrStaticFn(table, "getCellSelectionMergeBounds", table_getCellSelectionMergeBounds);
257
+ if (merges.length) for (let i = 0; i < operations.length; i++) {
258
+ const operation = operations[i];
259
+ const expanded = expandCellSelectionBounds(operation, merges);
260
+ operation.minRowIndex = expanded.minRowIndex;
261
+ operation.maxRowIndex = expanded.maxRowIndex;
262
+ operation.minColumnIndex = expanded.minColumnIndex;
263
+ operation.maxColumnIndex = expanded.maxColumnIndex;
264
+ }
175
265
  return applyCellSelectionBoundsOperations(operations);
176
266
  }
177
267
  /**
@@ -290,12 +380,24 @@ function cell_getSelectionEdges(cell) {
290
380
  if (!position) return none;
291
381
  const { bounds, rowIndex, columnIndex } = position;
292
382
  if (!isWithinBounds(bounds, rowIndex, columnIndex)) return none;
293
- return {
383
+ const merges = callMemoOrStaticFn(cell.table, "getCellSelectionMergeBounds", table_getCellSelectionMergeBounds);
384
+ const merge = merges.length ? findMergeBoundsAt(merges, rowIndex, columnIndex) : void 0;
385
+ if (!merge) return {
294
386
  top: !isWithinBounds(bounds, rowIndex - 1, columnIndex),
295
387
  right: !isWithinBounds(bounds, rowIndex, columnIndex + 1),
296
388
  bottom: !isWithinBounds(bounds, rowIndex + 1, columnIndex),
297
389
  left: !isWithinBounds(bounds, rowIndex, columnIndex - 1)
298
390
  };
391
+ return {
392
+ top: isStripOutside(bounds, merge.minRowIndex - 1, merge.minColumnIndex, merge.maxColumnIndex, true),
393
+ right: isStripOutside(bounds, merge.maxColumnIndex + 1, merge.minRowIndex, merge.maxRowIndex, false),
394
+ bottom: isStripOutside(bounds, merge.maxRowIndex + 1, merge.minColumnIndex, merge.maxColumnIndex, true),
395
+ left: isStripOutside(bounds, merge.minColumnIndex - 1, merge.minRowIndex, merge.maxRowIndex, false)
396
+ };
397
+ }
398
+ function isStripOutside(bounds, fixedIndex, from, to, fixedIsRow) {
399
+ for (let i = from; i <= to; i++) if (!isWithinBounds(bounds, fixedIsRow ? fixedIndex : i, fixedIsRow ? i : fixedIndex)) return true;
400
+ return false;
299
401
  }
300
402
  /**
301
403
  * Returns the active cell, i.e. the anchor of the most recent operation.
@@ -417,11 +519,23 @@ function stepCoordinate(table, rowId, columnId, direction) {
417
519
  const rowIndex = resolveRowIndex(table, rows, rowId);
418
520
  const columnIndex = columns.findIndex((column) => column.id === columnId);
419
521
  if (rowIndex < 0 || columnIndex < 0) return null;
420
- const nextRowIndex = rowIndex + rowDelta;
522
+ const merges = callMemoOrStaticFn(table, "getCellSelectionMergeBounds", table_getCellSelectionMergeBounds);
523
+ let fromRowIndex = rowIndex;
524
+ let fromColumnIndex = columnIndex;
525
+ if (merges.length) {
526
+ const startMerge = findMergeBoundsAt(merges, rowIndex, columnIndex);
527
+ if (startMerge) {
528
+ if (rowDelta > 0) fromRowIndex = startMerge.maxRowIndex;
529
+ if (rowDelta < 0) fromRowIndex = startMerge.minRowIndex;
530
+ if (columnDelta > 0) fromColumnIndex = startMerge.maxColumnIndex;
531
+ if (columnDelta < 0) fromColumnIndex = startMerge.minColumnIndex;
532
+ }
533
+ }
534
+ const nextRowIndex = fromRowIndex + rowDelta;
421
535
  if (nextRowIndex < 0 || nextRowIndex >= rows.length) return null;
422
536
  const selectableColumnIds = new Set(getSelectableColumns(table).map((column) => column.id));
423
537
  if (!selectableColumnIds.size) return null;
424
- let nextColumnIndex = columnIndex;
538
+ let nextColumnIndex = fromColumnIndex;
425
539
  if (columnDelta) do
426
540
  nextColumnIndex += columnDelta;
427
541
  while (nextColumnIndex >= 0 && nextColumnIndex < columns.length && !selectableColumnIds.has(columns[nextColumnIndex].id));
@@ -438,9 +552,21 @@ function stepCoordinate(table, rowId, columnId, direction) {
438
552
  }
439
553
  }
440
554
  if (nextColumnIndex < 0 || nextColumnIndex >= columns.length || !selectableColumnIds.has(columns[nextColumnIndex].id)) return null;
555
+ let landingRowIndex = nextRowIndex;
556
+ let landingColumnIndex = nextColumnIndex;
557
+ if (merges.length) {
558
+ const landingMerge = findMergeBoundsAt(merges, nextRowIndex, nextColumnIndex);
559
+ if (landingMerge) {
560
+ landingRowIndex = landingMerge.minRowIndex;
561
+ landingColumnIndex = landingMerge.minColumnIndex;
562
+ }
563
+ }
564
+ const landingRow = rows[landingRowIndex];
565
+ const landingColumn = columns[landingColumnIndex];
566
+ if (!landingRow || !landingColumn) return null;
441
567
  return {
442
- rowId: rows[nextRowIndex].id,
443
- columnId: columns[nextColumnIndex].id
568
+ rowId: landingRow.id,
569
+ columnId: landingColumn.id
444
570
  };
445
571
  }
446
572
  /**
@@ -502,7 +628,7 @@ function table_extendCellSelection(table, direction) {
502
628
  * Every expansion API shares this so the per-cell enable predicate is applied
503
629
  * in exactly one place.
504
630
  */
505
- function forEachSelectedCell(table, visit) {
631
+ function forEachSelectedCell(table, visit, skipCovered = false) {
506
632
  const bounds = callMemoOrStaticFn(table, "getCellSelectionBounds", table_getCellSelectionBounds);
507
633
  if (!bounds.length) return;
508
634
  const rows = table.getRowsInDisplayOrder();
@@ -519,6 +645,7 @@ function forEachSelectedCell(table, visit) {
519
645
  const cell = cellsByColumnId[column.id];
520
646
  if (!cell) continue;
521
647
  if (!callMemoOrStaticFn(cell, "getCanSelect", cell_getCanSelect)) continue;
648
+ if (skipCovered && cell.getIsCovered?.()) continue;
522
649
  visit(cell, i, rowIndex - bound.minRowIndex, columnIndex - bound.minColumnIndex);
523
650
  }
524
651
  }
@@ -542,7 +669,7 @@ function table_getSelectedCellIds(table) {
542
669
  if (seen.has(cell.id)) return;
543
670
  seen.add(cell.id);
544
671
  ids.push(cell.id);
545
- });
672
+ }, true);
546
673
  return ids;
547
674
  }
548
675
  /**
@@ -580,9 +707,10 @@ function table_getSelectedCellCount(table) {
580
707
  if (table.options.enableCellSelection === false) return 0;
581
708
  const bounds = callMemoOrStaticFn(table, "getCellSelectionBounds", table_getCellSelectionBounds);
582
709
  if (!bounds.length) return 0;
583
- if (typeof table.options.enableCellSelection === "function") {
710
+ const merges = callMemoOrStaticFn(table, "getCellSelectionMergeBounds", table_getCellSelectionMergeBounds);
711
+ if (typeof table.options.enableCellSelection === "function" || merges.length) {
584
712
  const ids = /* @__PURE__ */ new Set();
585
- forEachSelectedCell(table, (cell) => ids.add(cell.id));
713
+ forEachSelectedCell(table, (cell) => ids.add(cell.id), true);
586
714
  return ids.size;
587
715
  }
588
716
  const columns = getDisplayOrderedColumns(table);
@@ -742,4 +870,4 @@ function cell_getSelectionExtendHandler(cell) {
742
870
  }
743
871
 
744
872
  //#endregion
745
- export { cell_getCanSelect, cell_getIsFocused, cell_getIsSelected, cell_getSelectionEdges, cell_getSelectionExtendHandler, cell_getSelectionStartHandler, cell_getTabIndex, getDefaultCellSelectionState, table_autoResetCellSelection, table_extendCellSelection, table_getCellSelectionBounds, table_getCellSelectionColumnIds, table_getCellSelectionColumnIndexes, table_getCellSelectionRowIds, table_getFocusedCell, table_getSelectedCellCount, table_getSelectedCellIds, table_getSelectedCellRangesData, table_moveCellSelection, table_resetCellSelection, table_selectAllCells, table_selectCellRange, table_setCellSelection, table_setFocusedCell };
873
+ export { cell_getCanSelect, cell_getIsFocused, cell_getIsSelected, cell_getSelectionEdges, cell_getSelectionExtendHandler, cell_getSelectionStartHandler, cell_getTabIndex, getDefaultCellSelectionState, table_autoResetCellSelection, table_extendCellSelection, table_getCellSelectionBounds, table_getCellSelectionColumnIds, table_getCellSelectionColumnIndexes, table_getCellSelectionMergeBounds, table_getCellSelectionRowIds, table_getFocusedCell, table_getSelectedCellCount, table_getSelectedCellIds, table_getSelectedCellRangesData, table_moveCellSelection, table_resetCellSelection, table_selectAllCells, table_selectCellRange, table_setCellSelection, table_setFocusedCell };
@@ -71,6 +71,37 @@ function addCellSelectionBounds(selected, included) {
71
71
  }
72
72
  return mergeAdjacentCellSelectionBounds([...selected, ...fragments]);
73
73
  }
74
+ /**
75
+ * Grows a rectangle until it fully contains every merged-cell rectangle it
76
+ * touches.
77
+ *
78
+ * Merged cells make plain rectangles insufficient: a selection that clips part
79
+ * of a merge must cover the whole merge, and covering it can bring the
80
+ * rectangle into contact with further merges, so the expansion runs to a fixed
81
+ * point. The loop is bounded by the merge count, since each pass that changes
82
+ * the rectangle consumes at least one merge.
83
+ */
84
+ function expandCellSelectionBounds(bounds, merges) {
85
+ let expanded = bounds;
86
+ let changed = true;
87
+ while (changed) {
88
+ changed = false;
89
+ for (const merge of merges) {
90
+ if (!intersectCellSelectionBounds(expanded, merge)) continue;
91
+ const union = {
92
+ minRowIndex: Math.min(expanded.minRowIndex, merge.minRowIndex),
93
+ maxRowIndex: Math.max(expanded.maxRowIndex, merge.maxRowIndex),
94
+ minColumnIndex: Math.min(expanded.minColumnIndex, merge.minColumnIndex),
95
+ maxColumnIndex: Math.max(expanded.maxColumnIndex, merge.maxColumnIndex)
96
+ };
97
+ if (union.minRowIndex !== expanded.minRowIndex || union.maxRowIndex !== expanded.maxRowIndex || union.minColumnIndex !== expanded.minColumnIndex || union.maxColumnIndex !== expanded.maxColumnIndex) {
98
+ expanded = union;
99
+ changed = true;
100
+ }
101
+ }
102
+ }
103
+ return expanded;
104
+ }
74
105
  function applyCellSelectionBoundsOperations(operations) {
75
106
  let selected = [];
76
107
  for (const operation of operations) {
@@ -87,4 +118,4 @@ function applyCellSelectionBoundsOperations(operations) {
87
118
  }
88
119
 
89
120
  //#endregion
90
- export { addCellSelectionBounds, applyCellSelectionBoundsOperations, intersectCellSelectionBounds, mergeAdjacentCellSelectionBounds, subtractCellSelectionBounds };
121
+ export { addCellSelectionBounds, applyCellSelectionBoundsOperations, expandCellSelectionBounds, intersectCellSelectionBounds, mergeAdjacentCellSelectionBounds, subtractCellSelectionBounds };
@@ -0,0 +1,13 @@
1
+ import { TableFeature } from "../../types/TableFeatures.js";
2
+ //#region src/features/cell-spanning/cellSpanningFeature.d.ts
3
+ /**
4
+ * Feature that merges adjacent cells that share a value into row-spanning
5
+ * cells, and lets a column def declare column-spanning cells per row.
6
+ *
7
+ * Stateless: spans are always derived from the rows that are currently
8
+ * rendered, so there is nothing to persist and nothing to configure beyond the
9
+ * column defs.
10
+ */
11
+ declare const cellSpanningFeature: TableFeature;
12
+ //#endregion
13
+ export { cellSpanningFeature };
@@ -0,0 +1,47 @@
1
+ import { assignPrototypeAPIs, assignTableAPIs } from "../../utils.js";
2
+ import { cell_getColSpan, cell_getIsCovered, cell_getRowSpan, table_getCellSpanIndex } from "./cellSpanningFeature.utils.js";
3
+
4
+ //#region src/features/cell-spanning/cellSpanningFeature.ts
5
+ /**
6
+ * Feature that merges adjacent cells that share a value into row-spanning
7
+ * cells, and lets a column def declare column-spanning cells per row.
8
+ *
9
+ * Stateless: spans are always derived from the rows that are currently
10
+ * rendered, so there is nothing to persist and nothing to configure beyond the
11
+ * column defs.
12
+ */
13
+ const cellSpanningFeature = {
14
+ getDefaultTableOptions: () => {
15
+ return { enableCellSpanning: true };
16
+ },
17
+ initRowInstanceData: (row) => {
18
+ row._cellSpanRowIndex = -1;
19
+ },
20
+ assignCellPrototype: (prototype, table) => {
21
+ assignPrototypeAPIs("cellSpanningFeature", prototype, table, {
22
+ cell_getColSpan: { fn: (cell) => cell_getColSpan(cell) },
23
+ cell_getIsCovered: { fn: (cell) => cell_getIsCovered(cell) },
24
+ cell_getRowSpan: { fn: (cell) => cell_getRowSpan(cell) }
25
+ });
26
+ },
27
+ constructTableAPIs: (table) => {
28
+ assignTableAPIs("cellSpanningFeature", table, { table_getCellSpanIndex: {
29
+ fn: () => table_getCellSpanIndex(table),
30
+ memoDeps: () => [
31
+ table.getRowModel().rows,
32
+ table.atoms.rowPinning?.get(),
33
+ table.options.keepPinnedRows,
34
+ table.atoms.columnVisibility?.get(),
35
+ table.atoms.columnOrder?.get(),
36
+ table.atoms.columnPinning?.get(),
37
+ table.atoms.grouping?.get(),
38
+ table.options.columns,
39
+ table.options.groupedColumnMode,
40
+ table.options.enableCellSpanning
41
+ ]
42
+ } });
43
+ }
44
+ };
45
+
46
+ //#endregion
47
+ export { cellSpanningFeature };