@weng-lab/genomebrowser-ui 0.3.6 → 0.4.0-beta.1

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 (91) hide show
  1. package/.env.local +1 -1
  2. package/dist/TrackSelect/Folders/biosamples/shared/BiosampleViewSelector.d.ts +7 -0
  3. package/dist/TrackSelect/Folders/biosamples/shared/createFolder.d.ts +1 -13
  4. package/dist/TrackSelect/Folders/biosamples/shared/toTrack.d.ts +20 -0
  5. package/dist/TrackSelect/Folders/biosamples/shared/types.d.ts +4 -13
  6. package/dist/TrackSelect/Folders/genes/shared/columns.d.ts +2 -2
  7. package/dist/TrackSelect/Folders/genes/shared/createFolder.d.ts +1 -3
  8. package/dist/TrackSelect/Folders/genes/shared/toTrack.d.ts +18 -0
  9. package/dist/TrackSelect/Folders/genes/shared/types.d.ts +2 -0
  10. package/dist/TrackSelect/Folders/index.d.ts +6 -12
  11. package/dist/TrackSelect/Folders/mohd/data/human.json.d.ts +2948 -0
  12. package/dist/TrackSelect/Folders/mohd/human.d.ts +1 -0
  13. package/dist/TrackSelect/Folders/mohd/shared/MohdGroupingCell.d.ts +2 -0
  14. package/dist/TrackSelect/Folders/mohd/shared/MohdTreeItem.d.ts +3 -0
  15. package/dist/TrackSelect/Folders/mohd/shared/MohdViewSelector.d.ts +7 -0
  16. package/dist/TrackSelect/Folders/mohd/shared/columns.d.ts +5 -0
  17. package/dist/TrackSelect/Folders/mohd/shared/config.d.ts +42 -0
  18. package/dist/TrackSelect/Folders/mohd/shared/createFolder.d.ts +9 -0
  19. package/dist/TrackSelect/Folders/mohd/shared/toTrack.d.ts +9 -0
  20. package/dist/TrackSelect/Folders/mohd/shared/types.d.ts +40 -0
  21. package/dist/TrackSelect/Folders/other-tracks/shared/toTrack.d.ts +5 -0
  22. package/dist/TrackSelect/Folders/other-tracks/shared/types.d.ts +1 -0
  23. package/dist/TrackSelect/Folders/types.d.ts +23 -55
  24. package/dist/TrackSelect/TrackSelect.d.ts +10 -7
  25. package/dist/TrackSelect/TreeView/TreeViewWrapper.d.ts +1 -1
  26. package/dist/TrackSelect/buildSelectedTree.d.ts +15 -0
  27. package/dist/TrackSelect/managedTracks.d.ts +13 -0
  28. package/dist/TrackSelect/resolveFolderView.d.ts +2 -0
  29. package/dist/TrackSelect/trackContext.d.ts +5 -0
  30. package/dist/TrackSelect/types.d.ts +12 -33
  31. package/dist/genomebrowser-ui.es.js +2231 -1732
  32. package/dist/genomebrowser-ui.es.js.map +1 -1
  33. package/dist/lib.d.ts +4 -4
  34. package/dist/muiLicense.d.ts +1 -0
  35. package/package.json +6 -3
  36. package/src/TrackSelect/Dialogs/ClearDialog.tsx +3 -8
  37. package/src/TrackSelect/Dialogs/ResetDialog.tsx +5 -4
  38. package/src/TrackSelect/FolderList/FolderCard.tsx +1 -1
  39. package/src/TrackSelect/Folders/biosamples/shared/BiosampleViewSelector.tsx +33 -0
  40. package/src/TrackSelect/Folders/biosamples/shared/createFolder.ts +39 -58
  41. package/src/TrackSelect/Folders/biosamples/shared/toTrack.ts +138 -0
  42. package/src/TrackSelect/Folders/biosamples/shared/types.ts +4 -16
  43. package/src/TrackSelect/Folders/genes/shared/columns.tsx +2 -2
  44. package/src/TrackSelect/Folders/genes/shared/createFolder.ts +11 -31
  45. package/src/TrackSelect/Folders/genes/shared/toTrack.ts +59 -0
  46. package/src/TrackSelect/Folders/genes/shared/types.ts +2 -0
  47. package/src/TrackSelect/Folders/index.ts +14 -17
  48. package/src/TrackSelect/Folders/mohd/data/human.json +2945 -0
  49. package/src/TrackSelect/Folders/mohd/human.ts +10 -0
  50. package/src/TrackSelect/Folders/mohd/shared/MohdGroupingCell.tsx +68 -0
  51. package/src/TrackSelect/Folders/mohd/shared/MohdTreeItem.tsx +17 -0
  52. package/src/TrackSelect/Folders/mohd/shared/MohdViewSelector.tsx +33 -0
  53. package/src/TrackSelect/Folders/mohd/shared/columns.tsx +79 -0
  54. package/src/TrackSelect/Folders/mohd/shared/config.tsx +71 -0
  55. package/src/TrackSelect/Folders/mohd/shared/createFolder.ts +144 -0
  56. package/src/TrackSelect/Folders/mohd/shared/toTrack.ts +164 -0
  57. package/src/TrackSelect/Folders/mohd/shared/types.ts +46 -0
  58. package/src/TrackSelect/Folders/other-tracks/shared/createFolder.ts +13 -14
  59. package/src/TrackSelect/Folders/other-tracks/shared/toTrack.ts +17 -0
  60. package/src/TrackSelect/Folders/other-tracks/shared/types.ts +1 -0
  61. package/src/TrackSelect/Folders/types.ts +26 -69
  62. package/src/TrackSelect/TrackSelect.tsx +301 -257
  63. package/src/TrackSelect/TreeView/CustomTreeItem.tsx +9 -9
  64. package/src/TrackSelect/TreeView/TreeViewWrapper.tsx +84 -6
  65. package/src/TrackSelect/buildSelectedTree.ts +145 -0
  66. package/src/TrackSelect/managedTracks.ts +92 -0
  67. package/src/TrackSelect/resolveFolderView.ts +20 -0
  68. package/src/TrackSelect/trackContext.ts +9 -0
  69. package/src/TrackSelect/types.ts +14 -39
  70. package/src/lib.ts +13 -7
  71. package/src/muiLicense.ts +9 -0
  72. package/src/vite-env.d.ts +9 -0
  73. package/test/TrackSelect.test.tsx +435 -0
  74. package/test/main.tsx +36 -352
  75. package/test/mocks/logo-test.tsx +11 -0
  76. package/test/mohdDisplay.test.tsx +45 -0
  77. package/test/startup.test.ts +206 -0
  78. package/test/trackSelectState.test.ts +176 -0
  79. package/vite.config.ts +1 -0
  80. package/vitest.config.ts +20 -0
  81. package/dist/TrackSelect/Folders/biosamples/shared/AssayToggle.d.ts +0 -18
  82. package/dist/TrackSelect/Folders/biosamples/shared/treeBuilder.d.ts +0 -28
  83. package/dist/TrackSelect/Folders/genes/shared/treeBuilder.d.ts +0 -13
  84. package/dist/TrackSelect/Folders/other-tracks/shared/treeBuilder.d.ts +0 -4
  85. package/dist/TrackSelect/store.d.ts +0 -4
  86. package/src/TrackSelect/Folders/NEW.md +0 -929
  87. package/src/TrackSelect/Folders/biosamples/shared/AssayToggle.tsx +0 -78
  88. package/src/TrackSelect/Folders/biosamples/shared/treeBuilder.ts +0 -224
  89. package/src/TrackSelect/Folders/genes/shared/treeBuilder.ts +0 -45
  90. package/src/TrackSelect/Folders/other-tracks/shared/treeBuilder.ts +0 -34
  91. package/src/TrackSelect/store.ts +0 -117
@@ -30,19 +30,19 @@ const TreeItemRoot = styled("li")(({ theme }) => ({
30
30
  }),
31
31
  }));
32
32
 
33
- const TreeItemLabelText = styled(Typography)({
34
- color: "black",
33
+ const TreeItemLabelText = styled(Typography)(({ theme }) => ({
34
+ color: theme.palette.text.primary,
35
35
  fontFamily: "inherit",
36
36
  overflow: "hidden",
37
37
  textOverflow: "ellipsis",
38
38
  whiteSpace: "nowrap",
39
- });
39
+ }));
40
40
 
41
41
  function CustomLabel({
42
42
  icon: Icon,
43
43
  children,
44
- isAssayItem,
45
- assayName,
44
+ isHighlightedItem,
45
+ highlightName,
46
46
  renderIcon,
47
47
  ...other
48
48
  }: CustomLabelProps) {
@@ -78,8 +78,8 @@ function CustomLabel({
78
78
  alignItems="center"
79
79
  sx={{ minWidth: 0, overflow: "hidden", flex: 1 }}
80
80
  >
81
- {assayName && renderIcon && (
82
- <Box sx={{ flexShrink: 0 }}>{renderIcon(assayName)}</Box>
81
+ {isHighlightedItem && highlightName && renderIcon && (
82
+ <Box sx={{ flexShrink: 0 }}>{renderIcon(highlightName)}</Box>
83
83
  )}
84
84
  <Tooltip title={labelText} enterDelay={500} placement="top">
85
85
  <TreeItemLabelText fontWeight={fontWeight} variant={variant}>
@@ -199,8 +199,8 @@ export const CustomTreeItem = React.forwardRef(function CustomTreeItem(
199
199
  icon
200
200
  ),
201
201
  expandable: (status.expandable && status.expanded).toString(),
202
- isAssayItem: item.isAssayItem,
203
- assayName: item.assayName,
202
+ isHighlightedItem: item.isHighlightedItem,
203
+ highlightName: item.highlightName,
204
204
  id: item.id,
205
205
  renderIcon,
206
206
  })}
@@ -1,14 +1,29 @@
1
1
  import { Avatar, Box, Paper, Typography } from "@mui/material";
2
2
  import { RichTreeView, TreeViewBaseItem } from "@mui/x-tree-view";
3
- import { useEffect, useMemo, useState } from "react";
3
+ import { useTreeItemModel } from "@mui/x-tree-view/hooks";
4
+ import React, { useEffect, useMemo, useState } from "react";
5
+ import { buildSelectedTree } from "../buildSelectedTree";
4
6
  import {
5
7
  CustomTreeItemProps,
6
8
  ExtendedTreeItemProps,
7
- FolderTreeConfig,
8
9
  TreeViewWrapperProps,
9
10
  } from "../types";
11
+ import { resolveFolderView } from "../resolveFolderView";
10
12
  import { CustomTreeItem } from "./CustomTreeItem";
11
13
 
14
+ const attachFolderId = (
15
+ items: TreeViewBaseItem<ExtendedTreeItemProps>[],
16
+ folderId: string,
17
+ ): TreeViewBaseItem<ExtendedTreeItemProps>[] => {
18
+ return items.map((item) => ({
19
+ ...item,
20
+ folderId,
21
+ children: item.children
22
+ ? attachFolderId(item.children, folderId)
23
+ : undefined,
24
+ }));
25
+ };
26
+
12
27
  function getAllExpandableItemIds(
13
28
  items: TreeViewBaseItem<ExtendedTreeItemProps>[],
14
29
  ): string[] {
@@ -24,11 +39,17 @@ function getAllExpandableItemIds(
24
39
 
25
40
  function FolderTree({
26
41
  items,
42
+ LeafTreeItemComponent,
27
43
  TreeItemComponent,
28
44
  onRemove,
29
45
  }: {
30
- items: FolderTreeConfig["items"];
31
- TreeItemComponent: FolderTreeConfig["TreeItemComponent"];
46
+ items: TreeViewBaseItem<ExtendedTreeItemProps>[];
47
+ LeafTreeItemComponent?: React.ForwardRefExoticComponent<
48
+ CustomTreeItemProps & React.RefAttributes<HTMLLIElement>
49
+ >;
50
+ TreeItemComponent?: React.ForwardRefExoticComponent<
51
+ CustomTreeItemProps & React.RefAttributes<HTMLLIElement>
52
+ >;
32
53
  onRemove: (item: TreeViewBaseItem<ExtendedTreeItemProps>) => void;
33
54
  }) {
34
55
  const allExpandableIds = useMemo(
@@ -54,7 +75,27 @@ function FolderTree({
54
75
  onRemove(item);
55
76
  };
56
77
 
57
- const TreeItem = TreeItemComponent ?? CustomTreeItem;
78
+ const TreeItem = useMemo(
79
+ () =>
80
+ TreeItemComponent || LeafTreeItemComponent
81
+ ? React.forwardRef<HTMLLIElement, CustomTreeItemProps>(
82
+ function TreeItem(props, ref) {
83
+ const item = useTreeItemModel<ExtendedTreeItemProps>(
84
+ props.itemId,
85
+ );
86
+ const Component =
87
+ item?.kind === "leaf"
88
+ ? (LeafTreeItemComponent ??
89
+ TreeItemComponent ??
90
+ CustomTreeItem)
91
+ : (TreeItemComponent ?? CustomTreeItem);
92
+
93
+ return <Component {...props} ref={ref} />;
94
+ },
95
+ )
96
+ : CustomTreeItem,
97
+ [LeafTreeItemComponent, TreeItemComponent],
98
+ );
58
99
 
59
100
  return (
60
101
  <RichTreeView
@@ -80,10 +121,46 @@ function FolderTree({
80
121
  }
81
122
 
82
123
  export function TreeViewWrapper({
83
- folderTrees,
124
+ folders,
125
+ selectedByFolder,
126
+ activeViewIdByFolder,
84
127
  selectedCount,
85
128
  onRemove,
86
129
  }: TreeViewWrapperProps) {
130
+ const folderTrees = useMemo(
131
+ () =>
132
+ folders.flatMap((folder) => {
133
+ const folderSelectedIds = selectedByFolder.get(folder.id);
134
+ if (!folderSelectedIds || folderSelectedIds.size === 0) {
135
+ return [];
136
+ }
137
+
138
+ const activeView = resolveFolderView(folder, activeViewIdByFolder);
139
+ const selectedRows = folder.rows.filter((row) =>
140
+ folderSelectedIds.has(row.id),
141
+ );
142
+
143
+ return [
144
+ {
145
+ folderId: folder.id,
146
+ items: attachFolderId(
147
+ buildSelectedTree({
148
+ folderId: folder.id,
149
+ rootLabel: folder.label,
150
+ selectedRows,
151
+ groupingModel: activeView.groupingModel,
152
+ leafField: activeView.leafField,
153
+ }),
154
+ folder.id,
155
+ ),
156
+ TreeItemComponent: folder.TreeItemComponent,
157
+ LeafTreeItemComponent: folder.LeafTreeItemComponent,
158
+ },
159
+ ];
160
+ }),
161
+ [activeViewIdByFolder, folders, selectedByFolder],
162
+ );
163
+
87
164
  return (
88
165
  <Paper
89
166
  sx={{
@@ -131,6 +208,7 @@ export function TreeViewWrapper({
131
208
  <FolderTree
132
209
  key={folderTree.folderId}
133
210
  items={folderTree.items}
211
+ LeafTreeItemComponent={folderTree.LeafTreeItemComponent}
134
212
  TreeItemComponent={folderTree.TreeItemComponent}
135
213
  onRemove={onRemove}
136
214
  />
@@ -0,0 +1,145 @@
1
+ import { TreeViewBaseItem } from "@mui/x-tree-view";
2
+ import { ExtendedTreeItemProps } from "./types";
3
+
4
+ type TreeRow = {
5
+ id: string;
6
+ [key: string]: unknown;
7
+ };
8
+
9
+ type BuildSelectedTreeOptions = {
10
+ folderId: string;
11
+ rootLabel: string;
12
+ selectedRows: TreeRow[];
13
+ groupingModel: string[];
14
+ leafField: string;
15
+ };
16
+
17
+ const toLabel = (value: unknown, fallback: string) => {
18
+ if (value === null || value === undefined || value === "") {
19
+ return fallback;
20
+ }
21
+
22
+ return String(value);
23
+ };
24
+
25
+ const isHighlightedField = (field: string) => {
26
+ return field === "assay" || field === "ome";
27
+ };
28
+
29
+ const createRootNode = (
30
+ folderId: string,
31
+ rootLabel: string,
32
+ ): TreeViewBaseItem<ExtendedTreeItemProps> => ({
33
+ id: `${folderId}::root`,
34
+ kind: "root",
35
+ label: rootLabel,
36
+ icon: "folder",
37
+ children: [],
38
+ allExpAccessions: [],
39
+ });
40
+
41
+ const createLeafNode = (
42
+ row: TreeRow,
43
+ leafField: string,
44
+ ): TreeViewBaseItem<ExtendedTreeItemProps> => {
45
+ const value = row[leafField];
46
+ const label = toLabel(value, row.id);
47
+
48
+ return {
49
+ id: row.id,
50
+ kind: "leaf",
51
+ field: leafField,
52
+ value: label,
53
+ rowId: row.id,
54
+ label,
55
+ icon: "removeable",
56
+ highlightName: isHighlightedField(leafField) ? label : undefined,
57
+ isHighlightedItem: isHighlightedField(leafField),
58
+ children: [],
59
+ allExpAccessions: [row.id],
60
+ };
61
+ };
62
+
63
+ const appendGroupedRows = (
64
+ parent: TreeViewBaseItem<ExtendedTreeItemProps>,
65
+ rows: TreeRow[],
66
+ groupingModel: string[],
67
+ depth: number,
68
+ folderId: string,
69
+ leafField: string,
70
+ path: string[],
71
+ ) => {
72
+ if (depth >= groupingModel.length) {
73
+ rows.forEach((row) => {
74
+ const leafNode = createLeafNode(row, leafField);
75
+ parent.children!.push(leafNode);
76
+ parent.allExpAccessions!.push(row.id);
77
+ });
78
+ return;
79
+ }
80
+
81
+ const field = groupingModel[depth];
82
+ const groupedRows = new Map<string, TreeRow[]>();
83
+
84
+ rows.forEach((row) => {
85
+ const value = toLabel(row[field], row.id);
86
+ const groupRows = groupedRows.get(value);
87
+ if (groupRows) {
88
+ groupRows.push(row);
89
+ return;
90
+ }
91
+
92
+ groupedRows.set(value, [row]);
93
+ });
94
+
95
+ groupedRows.forEach((groupRows, value) => {
96
+ const nodeId = `${folderId}::${[...path, `${field}=${encodeURIComponent(value)}`].join("::")}`;
97
+ const groupNode: TreeViewBaseItem<ExtendedTreeItemProps> = {
98
+ id: nodeId,
99
+ kind: "group",
100
+ field,
101
+ value,
102
+ label: value,
103
+ icon: "removeable",
104
+ highlightName: isHighlightedField(field) ? value : undefined,
105
+ isHighlightedItem: isHighlightedField(field),
106
+ children: [],
107
+ allExpAccessions: [],
108
+ };
109
+
110
+ appendGroupedRows(
111
+ groupNode,
112
+ groupRows,
113
+ groupingModel,
114
+ depth + 1,
115
+ folderId,
116
+ leafField,
117
+ [...path, `${field}=${encodeURIComponent(value)}`],
118
+ );
119
+
120
+ parent.children!.push(groupNode);
121
+ parent.allExpAccessions!.push(...groupNode.allExpAccessions!);
122
+ });
123
+ };
124
+
125
+ export const buildSelectedTree = ({
126
+ folderId,
127
+ rootLabel,
128
+ selectedRows,
129
+ groupingModel,
130
+ leafField,
131
+ }: BuildSelectedTreeOptions): TreeViewBaseItem<ExtendedTreeItemProps>[] => {
132
+ const root = createRootNode(folderId, rootLabel);
133
+
134
+ appendGroupedRows(
135
+ root,
136
+ selectedRows,
137
+ groupingModel,
138
+ 0,
139
+ folderId,
140
+ leafField,
141
+ [],
142
+ );
143
+
144
+ return [root];
145
+ };
@@ -0,0 +1,92 @@
1
+ import { Track } from "@weng-lab/genomebrowser";
2
+ import { Assembly, FolderDefinition } from "./Folders/types";
3
+ import type { TrackSelectTrackContext } from "./trackContext";
4
+
5
+ const buildManagedTrack = ({
6
+ assembly,
7
+ folder,
8
+ id,
9
+ trackContext,
10
+ }: {
11
+ assembly: Assembly;
12
+ folder: FolderDefinition;
13
+ id: string;
14
+ trackContext?: TrackSelectTrackContext;
15
+ }) => {
16
+ const row = folder.rows.find((candidate) => candidate.id === id);
17
+ if (!row) {
18
+ return null;
19
+ }
20
+
21
+ const track = folder.createTrack(row, { assembly, trackContext });
22
+ if (!track) {
23
+ return null;
24
+ }
25
+
26
+ return track;
27
+ };
28
+
29
+ export const diffManagedTracks = ({
30
+ assembly,
31
+ currentTracks,
32
+ folders,
33
+ selectedByFolder,
34
+ trackContext,
35
+ }: {
36
+ assembly: Assembly;
37
+ currentTracks: Track[];
38
+ folders: FolderDefinition[];
39
+ selectedByFolder: Map<string, Set<string>>;
40
+ trackContext?: TrackSelectTrackContext;
41
+ }) => {
42
+ const nextManagedIds = new Set<string>();
43
+ const currentManagedIds = new Set<string>();
44
+ const idsToRemove: string[] = [];
45
+ const tracksToAdd: Track[] = [];
46
+
47
+ currentTracks.forEach((track) => {
48
+ if (folders.some((folder) => track.id.startsWith(`${folder.id}/`))) {
49
+ currentManagedIds.add(track.id);
50
+ }
51
+ });
52
+
53
+ folders.forEach((folder) => {
54
+ const selectedIds = selectedByFolder.get(folder.id) ?? new Set<string>();
55
+
56
+ selectedIds.forEach((id) => {
57
+ nextManagedIds.add(id);
58
+ });
59
+ });
60
+
61
+ currentManagedIds.forEach((id) => {
62
+ if (!nextManagedIds.has(id)) {
63
+ idsToRemove.push(id);
64
+ }
65
+ });
66
+
67
+ folders.forEach((folder) => {
68
+ const selectedIds = selectedByFolder.get(folder.id) ?? new Set<string>();
69
+
70
+ selectedIds.forEach((id) => {
71
+ if (currentManagedIds.has(id)) {
72
+ return;
73
+ }
74
+
75
+ const track = buildManagedTrack({
76
+ assembly,
77
+ folder,
78
+ id,
79
+ trackContext,
80
+ });
81
+
82
+ if (track) {
83
+ tracksToAdd.push(track);
84
+ }
85
+ });
86
+ });
87
+
88
+ return {
89
+ idsToRemove,
90
+ tracksToAdd,
91
+ };
92
+ };
@@ -0,0 +1,20 @@
1
+ import { FolderDefinition, FolderView } from "./Folders/types";
2
+
3
+ export const resolveFolderView = (
4
+ folder: FolderDefinition,
5
+ activeViewIdByFolder: Map<string, string>,
6
+ ): FolderView => {
7
+ const activeViewId = activeViewIdByFolder.get(folder.id);
8
+ const activeView = folder.views?.find((view) => view.id === activeViewId);
9
+
10
+ return (
11
+ activeView ??
12
+ folder.views?.[0] ?? {
13
+ id: "default",
14
+ label: folder.label,
15
+ columns: folder.columns,
16
+ groupingModel: folder.groupingModel,
17
+ leafField: folder.leafField,
18
+ }
19
+ );
20
+ };
@@ -0,0 +1,9 @@
1
+ import type { BiosampleTrackContext } from "./Folders/biosamples/shared/toTrack";
2
+ import type { GeneTrackContext } from "./Folders/genes/shared/toTrack";
3
+ import type { MohdTrackContext } from "./Folders/mohd/shared/toTrack";
4
+ import type { OtherTracksTrackContext } from "./Folders/other-tracks/shared/toTrack";
5
+
6
+ export type TrackSelectTrackContext = GeneTrackContext &
7
+ BiosampleTrackContext &
8
+ MohdTrackContext &
9
+ OtherTracksTrackContext;
@@ -7,6 +7,7 @@ import {
7
7
  } from "@mui/x-data-grid-premium";
8
8
  import { ReactElement, ReactNode } from "react";
9
9
  import { SvgIconOwnProps } from "@mui/material";
10
+ import { FolderDefinition } from "./Folders/types";
10
11
 
11
12
  /**
12
13
  * Custom Tree Props for RichTreeView Panel
@@ -15,12 +16,13 @@ export type ExtendedTreeItemProps = {
15
16
  id: string;
16
17
  label: string;
17
18
  icon: string;
19
+ kind?: "root" | "group" | "leaf";
20
+ field?: string;
21
+ value?: string;
22
+ rowId?: string;
18
23
  folderId?: string;
19
- isAssayItem?: boolean;
20
- /**
21
- * The assay name for leaf nodes (experiment accession items)
22
- */
23
- assayName?: string;
24
+ isHighlightedItem?: boolean;
25
+ highlightName?: string;
24
26
  /**
25
27
  * list of all the experimentAccession values in the children/grandchildren of the item, or the accession of the item itself
26
28
  * this is used in updating the rowSelectionModel when removing items from the Tree View panel
@@ -28,22 +30,10 @@ export type ExtendedTreeItemProps = {
28
30
  allExpAccessions?: string[];
29
31
  };
30
32
 
31
- /**
32
- * Configuration for a single folder's tree in the TreeViewWrapper.
33
- * Each folder gets its own tree with its own TreeItemComponent.
34
- */
35
- export type FolderTreeConfig = {
36
- folderId: string;
37
- items: TreeViewBaseItem<ExtendedTreeItemProps>[];
38
- /** Optional custom TreeItem component for this folder */
39
- TreeItemComponent?: React.ForwardRefExoticComponent<
40
- CustomTreeItemProps & React.RefAttributes<HTMLLIElement>
41
- >;
42
- };
43
-
44
33
  export type TreeViewWrapperProps = {
45
- /** Array of folder tree configurations, one per folder with selections */
46
- folderTrees: FolderTreeConfig[];
34
+ folders: FolderDefinition[];
35
+ selectedByFolder: Map<string, Set<string>>;
36
+ activeViewIdByFolder: Map<string, string>;
47
37
  selectedCount: number;
48
38
  onRemove: (item: TreeViewBaseItem<ExtendedTreeItemProps>) => void;
49
39
  };
@@ -51,35 +41,20 @@ export type TreeViewWrapperProps = {
51
41
  export interface CustomLabelProps {
52
42
  id: string;
53
43
  children: React.ReactNode;
54
- isAssayItem?: boolean;
55
- assayName?: string;
44
+ isHighlightedItem?: boolean;
45
+ highlightName?: string;
56
46
  icon?: React.ElementType | React.ReactElement | ReactNode;
57
- /** Optional function to render custom icons for assay items */
58
47
  renderIcon?: (name: string) => ReactNode;
59
48
  }
60
49
 
61
50
  export interface CustomTreeItemProps
62
- extends Omit<UseTreeItemParameters, "rootRef">,
51
+ extends
52
+ Omit<UseTreeItemParameters, "rootRef">,
63
53
  Omit<React.HTMLAttributes<HTMLLIElement>, "onFocus"> {
64
54
  onRemove?: (item: TreeViewBaseItem<ExtendedTreeItemProps>) => void;
65
- /** Optional function to render custom icons for assay items */
66
55
  renderIcon?: (name: string) => ReactNode;
67
56
  }
68
57
 
69
- /**
70
- * Types for useSelectionStore to keep track of selected DataGrid rows/tracks
71
- */
72
- export type SelectionState = {
73
- selectedByFolder: Map<string, Set<string>>;
74
- activeFolderId: string;
75
- };
76
-
77
- export type SelectionAction = {
78
- clear: (folderId?: string) => void;
79
- setActiveFolder: (folderId: string) => void;
80
- setSelection: (folderId: string, ids: Set<string>) => void;
81
- };
82
-
83
58
  /**
84
59
  * DataGrid Props
85
60
  */
package/src/lib.ts CHANGED
@@ -1,19 +1,25 @@
1
- import TrackSelect, { type TrackSelectProps } from "./TrackSelect/TrackSelect";
2
- export { TrackSelect, TrackSelectProps };
1
+ import "./muiLicense";
3
2
 
4
- import {
5
- createSelectionStore,
6
- type SelectionStoreInstance,
7
- } from "./TrackSelect/store.ts";
8
- export { createSelectionStore, SelectionStoreInstance };
3
+ import TrackSelect, {
4
+ type InitialSelectedIdsByAssembly,
5
+ type TrackSelectProps,
6
+ } from "./TrackSelect/TrackSelect";
7
+ export { TrackSelect, TrackSelectProps };
8
+ export type { TrackSelectTrackContext } from "./TrackSelect/trackContext";
9
+ export type { InitialSelectedIdsByAssembly };
9
10
 
10
11
  import { foldersByAssembly } from "./TrackSelect/Folders/index.ts";
11
12
  export { foldersByAssembly };
12
13
 
13
14
  export type {
14
15
  BiosampleRowInfo,
16
+ BiosampleTrackContext,
15
17
  GeneRowInfo,
18
+ GeneTrackContext,
19
+ MohdRowInfo,
20
+ MohdTrackContext,
16
21
  OtherTrackInfo,
22
+ OtherTracksTrackContext,
17
23
  } from "./TrackSelect/Folders";
18
24
 
19
25
  import { tfPeaksTrack } from "./TrackSelect/Custom/TfPeaks.tsx";
@@ -0,0 +1,9 @@
1
+ import { LicenseInfo } from "@mui/x-license";
2
+
3
+ const muiLicenseKey =
4
+ import.meta.env.NEXT_PUBLIC_MUI_X_LICENSE_KEY ??
5
+ import.meta.env.VITE_MUI_X_LICENSE_KEY;
6
+
7
+ if (muiLicenseKey) {
8
+ LicenseInfo.setLicenseKey(muiLicenseKey);
9
+ }
package/src/vite-env.d.ts CHANGED
@@ -1 +1,10 @@
1
1
  /// <reference types="vite/client" />
2
+
3
+ interface ImportMetaEnv {
4
+ readonly NEXT_PUBLIC_MUI_X_LICENSE_KEY?: string;
5
+ readonly VITE_MUI_X_LICENSE_KEY?: string;
6
+ }
7
+
8
+ interface ImportMeta {
9
+ readonly env: ImportMetaEnv;
10
+ }