@weng-lab/genomebrowser-ui 0.2.2 → 0.2.3

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 (54) hide show
  1. package/.env.local +1 -1
  2. package/dist/TrackSelect/Folders/biosamples/data/human.json.d.ts +57141 -57141
  3. package/dist/TrackSelect/Folders/biosamples/data/mouse.json.d.ts +10394 -10394
  4. package/dist/TrackSelect/Folders/genes/data/human.json.d.ts +7 -7
  5. package/dist/TrackSelect/Folders/genes/data/mouse.json.d.ts +7 -7
  6. package/dist/genomebrowser-ui.es.js +9 -5
  7. package/dist/genomebrowser-ui.es.js.map +1 -1
  8. package/eslint.config.js +30 -30
  9. package/index.html +14 -14
  10. package/package.json +1 -1
  11. package/src/TrackSelect/DataGrid/DataGridWrapper.tsx +137 -137
  12. package/src/TrackSelect/DataGrid/DefaultGroupingCell.tsx +64 -64
  13. package/src/TrackSelect/Dialogs/ClearDialog.tsx +63 -63
  14. package/src/TrackSelect/Dialogs/LimitDialog.tsx +33 -33
  15. package/src/TrackSelect/Dialogs/ResetDialog.tsx +43 -43
  16. package/src/TrackSelect/FolderList/Breadcrumb.tsx +38 -38
  17. package/src/TrackSelect/FolderList/FolderCard.tsx +51 -51
  18. package/src/TrackSelect/FolderList/FolderList.tsx +47 -47
  19. package/src/TrackSelect/Folders/NEW.md +929 -929
  20. package/src/TrackSelect/Folders/biosamples/data/formatBiosamples.go +254 -254
  21. package/src/TrackSelect/Folders/biosamples/data/human.json +57141 -57141
  22. package/src/TrackSelect/Folders/biosamples/data/mouse.json +10394 -10394
  23. package/src/TrackSelect/Folders/biosamples/human.ts +17 -17
  24. package/src/TrackSelect/Folders/biosamples/mouse.ts +17 -17
  25. package/src/TrackSelect/Folders/biosamples/shared/AssayToggle.tsx +78 -78
  26. package/src/TrackSelect/Folders/biosamples/shared/BiosampleGroupingCell.tsx +146 -146
  27. package/src/TrackSelect/Folders/biosamples/shared/BiosampleTreeItem.tsx +15 -15
  28. package/src/TrackSelect/Folders/biosamples/shared/columns.tsx +165 -165
  29. package/src/TrackSelect/Folders/biosamples/shared/constants.tsx +116 -116
  30. package/src/TrackSelect/Folders/biosamples/shared/createFolder.ts +116 -116
  31. package/src/TrackSelect/Folders/biosamples/shared/treeBuilder.ts +224 -224
  32. package/src/TrackSelect/Folders/biosamples/shared/types.ts +48 -48
  33. package/src/TrackSelect/Folders/genes/data/human.json +7 -7
  34. package/src/TrackSelect/Folders/genes/data/mouse.json +7 -7
  35. package/src/TrackSelect/Folders/genes/human.ts +16 -16
  36. package/src/TrackSelect/Folders/genes/mouse.ts +16 -16
  37. package/src/TrackSelect/Folders/genes/shared/columns.tsx +42 -42
  38. package/src/TrackSelect/Folders/genes/shared/createFolder.ts +68 -68
  39. package/src/TrackSelect/Folders/genes/shared/treeBuilder.ts +45 -45
  40. package/src/TrackSelect/Folders/genes/shared/types.ts +29 -29
  41. package/src/TrackSelect/Folders/index.ts +30 -30
  42. package/src/TrackSelect/Folders/types.ts +106 -106
  43. package/src/TrackSelect/TrackSelect.tsx +11 -7
  44. package/src/TrackSelect/TreeView/CustomTreeItem.tsx +214 -214
  45. package/src/TrackSelect/TreeView/TreeViewWrapper.tsx +145 -145
  46. package/src/TrackSelect/store.ts +117 -117
  47. package/src/TrackSelect/types.ts +121 -121
  48. package/src/lib.ts +13 -13
  49. package/src/vite-env.d.ts +1 -1
  50. package/test/main.tsx +369 -369
  51. package/tsconfig.app.json +25 -25
  52. package/tsconfig.json +7 -7
  53. package/tsconfig.node.json +25 -25
  54. package/vite.config.ts +66 -66
@@ -1,17 +1,17 @@
1
- import { createBiosampleFolder } from "./shared/createFolder";
2
- import humanData from "./data/human.json";
3
- import { BiosampleDataFile } from "./shared/types";
4
-
5
- /**
6
- * Human biosamples folder configuration for GRCh38 assembly.
7
- *
8
- * Contains epigenomic data (DNase, ATAC, H3K4me3, H3K27ac, CTCF, cCRE, RNA-seq, ChromHMM)
9
- * from human tissue samples, primary cells, cell lines, and organoids.
10
- */
11
- export const humanBiosamplesFolder = createBiosampleFolder({
12
- id: "human-biosamples",
13
- label: "Human Biosamples",
14
- description:
15
- "Epigenomic data from human tissue samples, primary cells, cell lines, and organoids.",
16
- data: humanData as BiosampleDataFile,
17
- });
1
+ import { createBiosampleFolder } from "./shared/createFolder";
2
+ import humanData from "./data/human.json";
3
+ import { BiosampleDataFile } from "./shared/types";
4
+
5
+ /**
6
+ * Human biosamples folder configuration for GRCh38 assembly.
7
+ *
8
+ * Contains epigenomic data (DNase, ATAC, H3K4me3, H3K27ac, CTCF, cCRE, RNA-seq, ChromHMM)
9
+ * from human tissue samples, primary cells, cell lines, and organoids.
10
+ */
11
+ export const humanBiosamplesFolder = createBiosampleFolder({
12
+ id: "human-biosamples",
13
+ label: "Human Biosamples",
14
+ description:
15
+ "Epigenomic data from human tissue samples, primary cells, cell lines, and organoids.",
16
+ data: humanData as BiosampleDataFile,
17
+ });
@@ -1,17 +1,17 @@
1
- import { createBiosampleFolder } from "./shared/createFolder";
2
- import mouseData from "./data/mouse.json";
3
- import { BiosampleDataFile } from "./shared/types";
4
-
5
- /**
6
- * Mouse biosamples folder configuration for mm10 assembly.
7
- *
8
- * Contains epigenomic data (DNase, ATAC, H3K4me3, H3K27ac, CTCF, cCRE, RNA-seq, ChromHMM)
9
- * from mouse tissue samples, primary cells, cell lines, and organoids.
10
- */
11
- export const mouseBiosamplesFolder = createBiosampleFolder({
12
- id: "mouse-biosamples",
13
- label: "Mouse Biosamples",
14
- description:
15
- "Epigenomic data from mouse tissue samples, primary cells, cell lines, and organoids.",
16
- data: mouseData as BiosampleDataFile,
17
- });
1
+ import { createBiosampleFolder } from "./shared/createFolder";
2
+ import mouseData from "./data/mouse.json";
3
+ import { BiosampleDataFile } from "./shared/types";
4
+
5
+ /**
6
+ * Mouse biosamples folder configuration for mm10 assembly.
7
+ *
8
+ * Contains epigenomic data (DNase, ATAC, H3K4me3, H3K27ac, CTCF, cCRE, RNA-seq, ChromHMM)
9
+ * from mouse tissue samples, primary cells, cell lines, and organoids.
10
+ */
11
+ export const mouseBiosamplesFolder = createBiosampleFolder({
12
+ id: "mouse-biosamples",
13
+ label: "Mouse Biosamples",
14
+ description:
15
+ "Epigenomic data from mouse tissue samples, primary cells, cell lines, and organoids.",
16
+ data: mouseData as BiosampleDataFile,
17
+ });
@@ -1,78 +1,78 @@
1
- import { FormControlLabel, Switch } from "@mui/material";
2
- import { FolderRuntimeConfig } from "../../types";
3
- import {
4
- defaultColumns,
5
- defaultGroupingModel,
6
- defaultLeafField,
7
- sortedByAssayColumns,
8
- sortedByAssayGroupingModel,
9
- sortedByAssayLeafField,
10
- } from "./columns";
11
- import { buildTreeView, buildSortedAssayTreeView } from "./treeBuilder";
12
-
13
- export interface AssayToggleProps {
14
- updateConfig: (partial: Partial<FolderRuntimeConfig>) => void;
15
- folderId: string;
16
- label: string;
17
- config: FolderRuntimeConfig;
18
- }
19
-
20
- /**
21
- * Biosample-specific toolbar component that toggles between
22
- * sample-grouped and assay-grouped views.
23
- *
24
- * When toggled, it updates the folder's runtime config to switch:
25
- * - columns: Different column definitions for each view
26
- * - groupingModel: ["ontology", "displayName"] vs ["assay", "ontology"]
27
- * - leafField: "assay" vs "displayName"
28
- * - buildTree: Different tree builder function
29
- */
30
- export function AssayToggle({
31
- updateConfig,
32
- folderId,
33
- label,
34
- config,
35
- }: AssayToggleProps) {
36
- // Derive toggle state from current config's leafField
37
- const sortedByAssay = config.leafField === sortedByAssayLeafField;
38
-
39
- const handleToggle = () => {
40
- const newValue = !sortedByAssay;
41
-
42
- if (newValue) {
43
- // Switch to assay-grouped view
44
- updateConfig({
45
- columns: sortedByAssayColumns,
46
- groupingModel: sortedByAssayGroupingModel,
47
- leafField: sortedByAssayLeafField,
48
- buildTree: (selectedIds, rowById) =>
49
- buildSortedAssayTreeView(selectedIds, rowById, label, folderId),
50
- });
51
- } else {
52
- // Switch back to default (sample-grouped) view
53
- updateConfig({
54
- columns: defaultColumns,
55
- groupingModel: defaultGroupingModel,
56
- leafField: defaultLeafField,
57
- buildTree: (selectedIds, rowById) =>
58
- buildTreeView(selectedIds, rowById, label, folderId),
59
- });
60
- }
61
- };
62
-
63
- return (
64
- <FormControlLabel
65
- sx={{ display: "flex", justifyContent: "flex-end" }}
66
- value="Sort by assay"
67
- control={
68
- <Switch
69
- color="primary"
70
- checked={sortedByAssay}
71
- onChange={handleToggle}
72
- />
73
- }
74
- label="Sort by assay"
75
- labelPlacement="end"
76
- />
77
- );
78
- }
1
+ import { FormControlLabel, Switch } from "@mui/material";
2
+ import { FolderRuntimeConfig } from "../../types";
3
+ import {
4
+ defaultColumns,
5
+ defaultGroupingModel,
6
+ defaultLeafField,
7
+ sortedByAssayColumns,
8
+ sortedByAssayGroupingModel,
9
+ sortedByAssayLeafField,
10
+ } from "./columns";
11
+ import { buildTreeView, buildSortedAssayTreeView } from "./treeBuilder";
12
+
13
+ export interface AssayToggleProps {
14
+ updateConfig: (partial: Partial<FolderRuntimeConfig>) => void;
15
+ folderId: string;
16
+ label: string;
17
+ config: FolderRuntimeConfig;
18
+ }
19
+
20
+ /**
21
+ * Biosample-specific toolbar component that toggles between
22
+ * sample-grouped and assay-grouped views.
23
+ *
24
+ * When toggled, it updates the folder's runtime config to switch:
25
+ * - columns: Different column definitions for each view
26
+ * - groupingModel: ["ontology", "displayName"] vs ["assay", "ontology"]
27
+ * - leafField: "assay" vs "displayName"
28
+ * - buildTree: Different tree builder function
29
+ */
30
+ export function AssayToggle({
31
+ updateConfig,
32
+ folderId,
33
+ label,
34
+ config,
35
+ }: AssayToggleProps) {
36
+ // Derive toggle state from current config's leafField
37
+ const sortedByAssay = config.leafField === sortedByAssayLeafField;
38
+
39
+ const handleToggle = () => {
40
+ const newValue = !sortedByAssay;
41
+
42
+ if (newValue) {
43
+ // Switch to assay-grouped view
44
+ updateConfig({
45
+ columns: sortedByAssayColumns,
46
+ groupingModel: sortedByAssayGroupingModel,
47
+ leafField: sortedByAssayLeafField,
48
+ buildTree: (selectedIds, rowById) =>
49
+ buildSortedAssayTreeView(selectedIds, rowById, label, folderId),
50
+ });
51
+ } else {
52
+ // Switch back to default (sample-grouped) view
53
+ updateConfig({
54
+ columns: defaultColumns,
55
+ groupingModel: defaultGroupingModel,
56
+ leafField: defaultLeafField,
57
+ buildTree: (selectedIds, rowById) =>
58
+ buildTreeView(selectedIds, rowById, label, folderId),
59
+ });
60
+ }
61
+ };
62
+
63
+ return (
64
+ <FormControlLabel
65
+ sx={{ display: "flex", justifyContent: "flex-end" }}
66
+ value="Sort by assay"
67
+ control={
68
+ <Switch
69
+ color="primary"
70
+ checked={sortedByAssay}
71
+ onChange={handleToggle}
72
+ />
73
+ }
74
+ label="Sort by assay"
75
+ labelPlacement="end"
76
+ />
77
+ );
78
+ }
@@ -1,146 +1,146 @@
1
- import { Stack, Tooltip, Box, IconButton } from "@mui/material";
2
- import {
3
- GridRenderCellParams,
4
- useGridApiContext,
5
- GridGroupNode,
6
- } from "@mui/x-data-grid-premium";
7
- import { assayTypes, AssayIcon } from "./constants";
8
- import ChevronRightIcon from "@mui/icons-material/ChevronRight";
9
- import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
10
-
11
- /**
12
- * Biosample-specific grouping cell that renders AssayIcon for assay groups/values.
13
- * Handles expand/collapse, truncation, and tooltips.
14
- */
15
- export default function BiosampleGroupingCell(params: GridRenderCellParams) {
16
- const apiRef = useGridApiContext();
17
- const isGroup = params.rowNode.type === "group";
18
- const groupNode = params.rowNode as GridGroupNode;
19
- const isExpanded = isGroup ? groupNode.childrenExpanded : false;
20
- const groupingField = isGroup ? groupNode.groupingField : null;
21
- const depth = params.rowNode.depth ?? 0;
22
-
23
- const handleExpandClick = (e: React.MouseEvent) => {
24
- e.stopPropagation();
25
- apiRef.current.setRowChildrenExpansion(params.id, !isExpanded);
26
- };
27
-
28
- // Render content based on grouping field
29
- const renderContent = () => {
30
- const value = String(params.value ?? "");
31
-
32
- // For assay groups, show the colored icon
33
- if (isGroup && groupingField === "assay") {
34
- return (
35
- <Stack
36
- direction="row"
37
- spacing={1}
38
- alignItems="center"
39
- sx={{ flex: 1, overflow: "hidden" }}
40
- >
41
- {AssayIcon(value)}
42
- <Tooltip title={value} placement="top-start" enterDelay={500}>
43
- <Box
44
- sx={{
45
- overflow: "hidden",
46
- textOverflow: "ellipsis",
47
- whiteSpace: "nowrap",
48
- fontWeight: "bold",
49
- }}
50
- >
51
- {params.formattedValue}
52
- </Box>
53
- </Tooltip>
54
- </Stack>
55
- );
56
- }
57
-
58
- // For other groups (ontology, displayName), show bold text
59
- if (isGroup) {
60
- return (
61
- <Tooltip title={value} placement="top-start" enterDelay={500}>
62
- <Box
63
- sx={{
64
- overflow: "hidden",
65
- textOverflow: "ellipsis",
66
- whiteSpace: "nowrap",
67
- flex: 1,
68
- fontWeight: "bold",
69
- }}
70
- >
71
- {params.formattedValue}
72
- </Box>
73
- </Tooltip>
74
- );
75
- }
76
-
77
- // For leaf rows - check if it's an assay value
78
- const isAssayValue = assayTypes
79
- .map((a) => a.toLowerCase())
80
- .includes(value.toLowerCase());
81
-
82
- if (isAssayValue) {
83
- return (
84
- <Stack
85
- direction="row"
86
- spacing={1}
87
- alignItems="center"
88
- sx={{ flex: 1, overflow: "hidden" }}
89
- >
90
- {AssayIcon(value)}
91
- <Tooltip title={value} placement="top-start" enterDelay={500}>
92
- <Box
93
- sx={{
94
- overflow: "hidden",
95
- textOverflow: "ellipsis",
96
- whiteSpace: "nowrap",
97
- }}
98
- >
99
- {params.formattedValue}
100
- </Box>
101
- </Tooltip>
102
- </Stack>
103
- );
104
- }
105
-
106
- return (
107
- <Tooltip title={value} placement="top-start" enterDelay={500}>
108
- <Box
109
- sx={{
110
- overflow: "hidden",
111
- textOverflow: "ellipsis",
112
- whiteSpace: "nowrap",
113
- flex: 1,
114
- }}
115
- >
116
- {params.formattedValue}
117
- </Box>
118
- </Tooltip>
119
- );
120
- };
121
-
122
- // Indent based on depth (2 units per level)
123
- const indentLevel = depth * 2;
124
-
125
- return (
126
- <Box
127
- sx={{
128
- display: "flex",
129
- alignItems: "center",
130
- width: "100%",
131
- ml: indentLevel,
132
- }}
133
- >
134
- {isGroup && (
135
- <IconButton size="small" onClick={handleExpandClick} sx={{ mr: 0.5 }}>
136
- {isExpanded ? (
137
- <ExpandMoreIcon fontSize="small" />
138
- ) : (
139
- <ChevronRightIcon fontSize="small" />
140
- )}
141
- </IconButton>
142
- )}
143
- {renderContent()}
144
- </Box>
145
- );
146
- }
1
+ import { Stack, Tooltip, Box, IconButton } from "@mui/material";
2
+ import {
3
+ GridRenderCellParams,
4
+ useGridApiContext,
5
+ GridGroupNode,
6
+ } from "@mui/x-data-grid-premium";
7
+ import { assayTypes, AssayIcon } from "./constants";
8
+ import ChevronRightIcon from "@mui/icons-material/ChevronRight";
9
+ import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
10
+
11
+ /**
12
+ * Biosample-specific grouping cell that renders AssayIcon for assay groups/values.
13
+ * Handles expand/collapse, truncation, and tooltips.
14
+ */
15
+ export default function BiosampleGroupingCell(params: GridRenderCellParams) {
16
+ const apiRef = useGridApiContext();
17
+ const isGroup = params.rowNode.type === "group";
18
+ const groupNode = params.rowNode as GridGroupNode;
19
+ const isExpanded = isGroup ? groupNode.childrenExpanded : false;
20
+ const groupingField = isGroup ? groupNode.groupingField : null;
21
+ const depth = params.rowNode.depth ?? 0;
22
+
23
+ const handleExpandClick = (e: React.MouseEvent) => {
24
+ e.stopPropagation();
25
+ apiRef.current.setRowChildrenExpansion(params.id, !isExpanded);
26
+ };
27
+
28
+ // Render content based on grouping field
29
+ const renderContent = () => {
30
+ const value = String(params.value ?? "");
31
+
32
+ // For assay groups, show the colored icon
33
+ if (isGroup && groupingField === "assay") {
34
+ return (
35
+ <Stack
36
+ direction="row"
37
+ spacing={1}
38
+ alignItems="center"
39
+ sx={{ flex: 1, overflow: "hidden" }}
40
+ >
41
+ {AssayIcon(value)}
42
+ <Tooltip title={value} placement="top-start" enterDelay={500}>
43
+ <Box
44
+ sx={{
45
+ overflow: "hidden",
46
+ textOverflow: "ellipsis",
47
+ whiteSpace: "nowrap",
48
+ fontWeight: "bold",
49
+ }}
50
+ >
51
+ {params.formattedValue}
52
+ </Box>
53
+ </Tooltip>
54
+ </Stack>
55
+ );
56
+ }
57
+
58
+ // For other groups (ontology, displayName), show bold text
59
+ if (isGroup) {
60
+ return (
61
+ <Tooltip title={value} placement="top-start" enterDelay={500}>
62
+ <Box
63
+ sx={{
64
+ overflow: "hidden",
65
+ textOverflow: "ellipsis",
66
+ whiteSpace: "nowrap",
67
+ flex: 1,
68
+ fontWeight: "bold",
69
+ }}
70
+ >
71
+ {params.formattedValue}
72
+ </Box>
73
+ </Tooltip>
74
+ );
75
+ }
76
+
77
+ // For leaf rows - check if it's an assay value
78
+ const isAssayValue = assayTypes
79
+ .map((a) => a.toLowerCase())
80
+ .includes(value.toLowerCase());
81
+
82
+ if (isAssayValue) {
83
+ return (
84
+ <Stack
85
+ direction="row"
86
+ spacing={1}
87
+ alignItems="center"
88
+ sx={{ flex: 1, overflow: "hidden" }}
89
+ >
90
+ {AssayIcon(value)}
91
+ <Tooltip title={value} placement="top-start" enterDelay={500}>
92
+ <Box
93
+ sx={{
94
+ overflow: "hidden",
95
+ textOverflow: "ellipsis",
96
+ whiteSpace: "nowrap",
97
+ }}
98
+ >
99
+ {params.formattedValue}
100
+ </Box>
101
+ </Tooltip>
102
+ </Stack>
103
+ );
104
+ }
105
+
106
+ return (
107
+ <Tooltip title={value} placement="top-start" enterDelay={500}>
108
+ <Box
109
+ sx={{
110
+ overflow: "hidden",
111
+ textOverflow: "ellipsis",
112
+ whiteSpace: "nowrap",
113
+ flex: 1,
114
+ }}
115
+ >
116
+ {params.formattedValue}
117
+ </Box>
118
+ </Tooltip>
119
+ );
120
+ };
121
+
122
+ // Indent based on depth (2 units per level)
123
+ const indentLevel = depth * 2;
124
+
125
+ return (
126
+ <Box
127
+ sx={{
128
+ display: "flex",
129
+ alignItems: "center",
130
+ width: "100%",
131
+ ml: indentLevel,
132
+ }}
133
+ >
134
+ {isGroup && (
135
+ <IconButton size="small" onClick={handleExpandClick} sx={{ mr: 0.5 }}>
136
+ {isExpanded ? (
137
+ <ExpandMoreIcon fontSize="small" />
138
+ ) : (
139
+ <ChevronRightIcon fontSize="small" />
140
+ )}
141
+ </IconButton>
142
+ )}
143
+ {renderContent()}
144
+ </Box>
145
+ );
146
+ }
@@ -1,15 +1,15 @@
1
- import React from "react";
2
- import { CustomTreeItem } from "../../../TreeView/CustomTreeItem";
3
- import { CustomTreeItemProps } from "../../../types";
4
- import { AssayIcon } from "./constants";
5
-
6
- /**
7
- * Biosample-specific TreeItem that renders AssayIcon for assay items.
8
- * Wraps the generic CustomTreeItem with the AssayIcon renderer.
9
- */
10
- export const BiosampleTreeItem = React.forwardRef<
11
- HTMLLIElement,
12
- CustomTreeItemProps
13
- >(function BiosampleTreeItem(props, ref) {
14
- return <CustomTreeItem {...props} ref={ref} renderIcon={AssayIcon} />;
15
- });
1
+ import React from "react";
2
+ import { CustomTreeItem } from "../../../TreeView/CustomTreeItem";
3
+ import { CustomTreeItemProps } from "../../../types";
4
+ import { AssayIcon } from "./constants";
5
+
6
+ /**
7
+ * Biosample-specific TreeItem that renders AssayIcon for assay items.
8
+ * Wraps the generic CustomTreeItem with the AssayIcon renderer.
9
+ */
10
+ export const BiosampleTreeItem = React.forwardRef<
11
+ HTMLLIElement,
12
+ CustomTreeItemProps
13
+ >(function BiosampleTreeItem(props, ref) {
14
+ return <CustomTreeItem {...props} ref={ref} renderIcon={AssayIcon} />;
15
+ });