@weng-lab/genomebrowser-ui 0.4.1 → 0.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@weng-lab/genomebrowser-ui",
3
3
  "private": false,
4
- "version": "0.4.1",
4
+ "version": "0.4.2",
5
5
  "license": "MIT",
6
6
  "type": "module",
7
7
  "publishConfig": {
@@ -23,7 +23,7 @@
23
23
  "@mui/x-data-grid-premium": "^8.19.0",
24
24
  "react": "^19.0.0",
25
25
  "react-dom": "^19.0.0",
26
- "@weng-lab/genomebrowser": "1.8.5"
26
+ "@weng-lab/genomebrowser": "1.8.6"
27
27
  },
28
28
  "devDependencies": {
29
29
  "@eslint/js": "^9.34.0",
@@ -6,10 +6,11 @@ import {
6
6
  GridColDef,
7
7
  GridColumnVisibilityModel,
8
8
  GridRenderCellParams,
9
+ GridRowId,
9
10
  GridRowSelectionModel,
10
11
  useGridApiRef,
11
12
  } from "@mui/x-data-grid-premium";
12
- import { useEffect, useMemo, useState } from "react";
13
+ import { useCallback, useEffect, useMemo, useState } from "react";
13
14
  import { DataGridProps } from "../types";
14
15
  import { DefaultGroupingCell } from "./DefaultGroupingCell";
15
16
 
@@ -19,6 +20,25 @@ const autosizeOptions: GridAutosizeOptions = {
19
20
  outliersFactor: 1.5,
20
21
  };
21
22
 
23
+ const areSetsEqual = <T,>(a: Set<T>, b: Set<T>) => {
24
+ if (a.size !== b.size) {
25
+ return false;
26
+ }
27
+
28
+ for (const value of a) {
29
+ if (!b.has(value)) {
30
+ return false;
31
+ }
32
+ }
33
+
34
+ return true;
35
+ };
36
+
37
+ const areSelectionModelsEqual = (
38
+ a: GridRowSelectionModel,
39
+ b: GridRowSelectionModel,
40
+ ) => a.type === b.type && areSetsEqual(a.ids, b.ids);
41
+
22
42
  export function DataGridWrapper(props: DataGridProps) {
23
43
  const {
24
44
  columns,
@@ -34,6 +54,60 @@ export function DataGridWrapper(props: DataGridProps) {
34
54
 
35
55
  const apiRef = useGridApiRef();
36
56
 
57
+ const rowIdSet = useMemo(
58
+ () => new Set(rows.map((row: { id: string }) => row.id)),
59
+ [rows],
60
+ );
61
+
62
+ const filterToLeafIds = useCallback(
63
+ (ids: Set<GridRowId>) =>
64
+ new Set([...ids].map(String).filter((id) => rowIdSet.has(id))),
65
+ [rowIdSet],
66
+ );
67
+
68
+ const getPropagatedSelectionModel = useCallback(
69
+ (ids: Set<GridRowId>) => {
70
+ const selectionModel: GridRowSelectionModel = {
71
+ type: "include",
72
+ ids,
73
+ };
74
+
75
+ return apiRef.current.getPropagatedRowSelectionModel
76
+ ? apiRef.current.getPropagatedRowSelectionModel(selectionModel)
77
+ : selectionModel;
78
+ },
79
+ [apiRef],
80
+ );
81
+
82
+ const [rowSelectionModel, setRowSelectionModel] =
83
+ useState<GridRowSelectionModel>(() => ({
84
+ type: "include",
85
+ ids: new Set(selectedIds),
86
+ }));
87
+
88
+ useEffect(() => {
89
+ const currentLeafIds = filterToLeafIds(rowSelectionModel.ids);
90
+ if (areSetsEqual(currentLeafIds, selectedIds)) {
91
+ return;
92
+ }
93
+
94
+ const nextSelectionModel = getPropagatedSelectionModel(
95
+ new Set(selectedIds),
96
+ );
97
+
98
+ setRowSelectionModel((currentSelectionModel) =>
99
+ areSelectionModelsEqual(currentSelectionModel, nextSelectionModel)
100
+ ? currentSelectionModel
101
+ : nextSelectionModel,
102
+ );
103
+ }, [
104
+ filterToLeafIds,
105
+ getPropagatedSelectionModel,
106
+ groupingModel,
107
+ rowSelectionModel.ids,
108
+ selectedIds,
109
+ ]);
110
+
37
111
  useEffect(() => {
38
112
  if (apiRef.current && apiRef.current.autosizeColumns) {
39
113
  apiRef.current.autosizeColumns(autosizeOptions);
@@ -106,15 +180,25 @@ export function DataGridWrapper(props: DataGridProps) {
106
180
  columnVisibilityModel={columnVisibilityModel}
107
181
  onColumnVisibilityModelChange={setColumnVisibilityModel}
108
182
  onRowSelectionModelChange={(selection: GridRowSelectionModel) => {
109
- const ids = selection.ids ?? new Set<string>();
110
- onSelectionChange(new Set([...ids].map(String)));
183
+ const nextSelectionModel = getPropagatedSelectionModel(
184
+ selection.ids,
185
+ );
186
+
187
+ setRowSelectionModel((currentSelectionModel) =>
188
+ areSelectionModelsEqual(currentSelectionModel, nextSelectionModel)
189
+ ? currentSelectionModel
190
+ : nextSelectionModel,
191
+ );
192
+
193
+ const leafIds = filterToLeafIds(nextSelectionModel.ids);
194
+
195
+ if (!areSetsEqual(leafIds, selectedIds)) {
196
+ onSelectionChange(leafIds);
197
+ }
111
198
  }}
112
- rowSelectionPropagation={{ descendants: true, parents: false }}
199
+ rowSelectionPropagation={{ descendants: true, parents: true }}
113
200
  disableRowGrouping={false}
114
- rowSelectionModel={{
115
- type: "include",
116
- ids: selectedIds,
117
- }}
201
+ rowSelectionModel={rowSelectionModel}
118
202
  slotProps={{
119
203
  filterPanel: {
120
204
  filterFormProps: {