@weng-lab/genomebrowser-ui 0.2.0 → 0.2.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.
Files changed (57) hide show
  1. package/.env.local +1 -1
  2. package/dist/TrackSelect/Dialogs/ClearDialog.d.ts +9 -0
  3. package/dist/TrackSelect/Dialogs/LimitDialog.d.ts +7 -0
  4. package/dist/TrackSelect/Dialogs/ResetDialog.d.ts +7 -0
  5. package/dist/TrackSelect/Folders/biosamples/data/human.json.d.ts +57141 -57141
  6. package/dist/TrackSelect/Folders/biosamples/data/mouse.json.d.ts +10394 -10394
  7. package/dist/TrackSelect/Folders/genes/data/human.json.d.ts +7 -7
  8. package/dist/TrackSelect/Folders/genes/data/mouse.json.d.ts +7 -7
  9. package/dist/genomebrowser-ui.es.js +736 -652
  10. package/dist/genomebrowser-ui.es.js.map +1 -1
  11. package/eslint.config.js +30 -30
  12. package/index.html +14 -14
  13. package/package.json +2 -1
  14. package/src/TrackSelect/DataGrid/DataGridWrapper.tsx +137 -137
  15. package/src/TrackSelect/DataGrid/DefaultGroupingCell.tsx +64 -64
  16. package/src/TrackSelect/Dialogs/ClearDialog.tsx +63 -0
  17. package/src/TrackSelect/Dialogs/LimitDialog.tsx +33 -0
  18. package/src/TrackSelect/Dialogs/ResetDialog.tsx +43 -0
  19. package/src/TrackSelect/FolderList/Breadcrumb.tsx +38 -38
  20. package/src/TrackSelect/FolderList/FolderCard.tsx +51 -51
  21. package/src/TrackSelect/FolderList/FolderList.tsx +47 -47
  22. package/src/TrackSelect/Folders/NEW.md +929 -929
  23. package/src/TrackSelect/Folders/biosamples/data/formatBiosamples.go +254 -254
  24. package/src/TrackSelect/Folders/biosamples/data/human.json +57141 -57141
  25. package/src/TrackSelect/Folders/biosamples/data/mouse.json +10394 -10394
  26. package/src/TrackSelect/Folders/biosamples/human.ts +17 -17
  27. package/src/TrackSelect/Folders/biosamples/mouse.ts +17 -17
  28. package/src/TrackSelect/Folders/biosamples/shared/AssayToggle.tsx +78 -78
  29. package/src/TrackSelect/Folders/biosamples/shared/BiosampleGroupingCell.tsx +146 -146
  30. package/src/TrackSelect/Folders/biosamples/shared/BiosampleTreeItem.tsx +15 -15
  31. package/src/TrackSelect/Folders/biosamples/shared/columns.tsx +165 -165
  32. package/src/TrackSelect/Folders/biosamples/shared/constants.tsx +116 -116
  33. package/src/TrackSelect/Folders/biosamples/shared/createFolder.ts +116 -116
  34. package/src/TrackSelect/Folders/biosamples/shared/treeBuilder.ts +224 -224
  35. package/src/TrackSelect/Folders/biosamples/shared/types.ts +48 -48
  36. package/src/TrackSelect/Folders/genes/data/human.json +7 -7
  37. package/src/TrackSelect/Folders/genes/data/mouse.json +7 -7
  38. package/src/TrackSelect/Folders/genes/human.ts +16 -16
  39. package/src/TrackSelect/Folders/genes/mouse.ts +16 -16
  40. package/src/TrackSelect/Folders/genes/shared/columns.tsx +42 -42
  41. package/src/TrackSelect/Folders/genes/shared/createFolder.ts +68 -68
  42. package/src/TrackSelect/Folders/genes/shared/treeBuilder.ts +45 -45
  43. package/src/TrackSelect/Folders/genes/shared/types.ts +29 -29
  44. package/src/TrackSelect/Folders/index.ts +30 -30
  45. package/src/TrackSelect/Folders/types.ts +106 -106
  46. package/src/TrackSelect/TrackSelect.tsx +82 -74
  47. package/src/TrackSelect/TreeView/CustomTreeItem.tsx +214 -214
  48. package/src/TrackSelect/TreeView/TreeViewWrapper.tsx +145 -145
  49. package/src/TrackSelect/store.ts +117 -117
  50. package/src/TrackSelect/types.ts +121 -121
  51. package/src/lib.ts +13 -13
  52. package/src/vite-env.d.ts +1 -1
  53. package/test/main.tsx +369 -369
  54. package/tsconfig.app.json +25 -25
  55. package/tsconfig.json +7 -7
  56. package/tsconfig.node.json +25 -25
  57. 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
+ });