@weng-lab/genomebrowser-ui 0.2.1 → 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 +729 -645
  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
package/eslint.config.js CHANGED
@@ -1,30 +1,30 @@
1
- // For more info, see https://github.com/storybookjs/eslint-plugin-storybook#configuration-flat-config-format
2
- import storybook from "eslint-plugin-storybook";
3
-
4
- import js from "@eslint/js";
5
- import globals from "globals";
6
- import reactHooks from "eslint-plugin-react-hooks";
7
- import reactRefresh from "eslint-plugin-react-refresh";
8
- import tseslint from "typescript-eslint";
9
-
10
- export default tseslint.config(
11
- { ignores: ["dist"] },
12
- {
13
- extends: [js.configs.recommended, ...tseslint.configs.recommended],
14
- files: ["**/*.{ts,tsx}"],
15
- languageOptions: {
16
- ecmaVersion: 2020,
17
- globals: globals.browser,
18
- },
19
- plugins: {
20
- "react-hooks": reactHooks,
21
- "react-refresh": reactRefresh,
22
- },
23
- rules: {
24
- ...reactHooks.configs.recommended.rules,
25
- "@typescript-eslint/no-explicit-any": "warn",
26
- "react-refresh/only-export-components": ["warn", { allowConstantExport: true }],
27
- },
28
- },
29
- storybook.configs["flat/recommended"]
30
- );
1
+ // For more info, see https://github.com/storybookjs/eslint-plugin-storybook#configuration-flat-config-format
2
+ import storybook from "eslint-plugin-storybook";
3
+
4
+ import js from "@eslint/js";
5
+ import globals from "globals";
6
+ import reactHooks from "eslint-plugin-react-hooks";
7
+ import reactRefresh from "eslint-plugin-react-refresh";
8
+ import tseslint from "typescript-eslint";
9
+
10
+ export default tseslint.config(
11
+ { ignores: ["dist"] },
12
+ {
13
+ extends: [js.configs.recommended, ...tseslint.configs.recommended],
14
+ files: ["**/*.{ts,tsx}"],
15
+ languageOptions: {
16
+ ecmaVersion: 2020,
17
+ globals: globals.browser,
18
+ },
19
+ plugins: {
20
+ "react-hooks": reactHooks,
21
+ "react-refresh": reactRefresh,
22
+ },
23
+ rules: {
24
+ ...reactHooks.configs.recommended.rules,
25
+ "@typescript-eslint/no-explicit-any": "warn",
26
+ "react-refresh/only-export-components": ["warn", { allowConstantExport: true }],
27
+ },
28
+ },
29
+ storybook.configs["flat/recommended"]
30
+ );
package/index.html CHANGED
@@ -1,14 +1,14 @@
1
- <!doctype html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="UTF-8" />
5
- <link rel="icon" type="image/svg+xml" href="/vite.svg" />
6
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
- <title>Genomebrowser-UI Test Page</title>
8
- </head>
9
- <body>
10
- <div id="root"></div>
11
- <script src="https://unpkg.com/react-scan/dist/auto.global.js"></script>
12
- <script type="module" src="/test/main.tsx"></script>
13
- </body>
14
- </html>
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <link rel="icon" type="image/svg+xml" href="/vite.svg" />
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
+ <title>Genomebrowser-UI Test Page</title>
8
+ </head>
9
+ <body>
10
+ <div id="root"></div>
11
+ <script src="https://unpkg.com/react-scan/dist/auto.global.js"></script>
12
+ <script type="module" src="/test/main.tsx"></script>
13
+ </body>
14
+ </html>
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@weng-lab/genomebrowser-ui",
3
3
  "private": false,
4
- "version": "0.2.1",
4
+ "version": "0.2.2",
5
5
  "license": "MIT",
6
6
  "type": "module",
7
7
  "publishConfig": {
@@ -33,6 +33,7 @@
33
33
  "eslint": "^9.34.0",
34
34
  "eslint-plugin-react-hooks": "^5.2.0",
35
35
  "eslint-plugin-react-refresh": "^0.4.20",
36
+ "typescript": "^5.7.3",
36
37
  "typescript-eslint": "^8.42.0",
37
38
  "vite": "^6.3.5",
38
39
  "vite-plugin-dts": "^4.5.4"
@@ -1,137 +1,137 @@
1
- import { Box, Paper } from "@mui/material";
2
- import {
3
- DataGridPremium,
4
- FilterColumnsArgs,
5
- GridAutosizeOptions,
6
- GridColDef,
7
- GridColumnVisibilityModel,
8
- useGridApiRef,
9
- } from "@mui/x-data-grid-premium";
10
- import { useEffect, useMemo, useState } from "react";
11
- import { DataGridProps } from "../types";
12
- import { DefaultGroupingCell } from "./DefaultGroupingCell";
13
-
14
- const autosizeOptions: GridAutosizeOptions = {
15
- expand: true,
16
- includeHeaders: true,
17
- outliersFactor: 1.5,
18
- };
19
-
20
- export function DataGridWrapper(props: DataGridProps) {
21
- const {
22
- columns,
23
- groupingModel,
24
- leafField,
25
- onSelectionChange,
26
- rows,
27
- selectedIds,
28
- GroupingCellComponent,
29
- } = props;
30
-
31
- const GroupingCell = GroupingCellComponent ?? DefaultGroupingCell;
32
-
33
- const apiRef = useGridApiRef();
34
-
35
- useEffect(() => {
36
- if (apiRef.current && apiRef.current.autosizeColumns) {
37
- apiRef.current.autosizeColumns(autosizeOptions);
38
- }
39
- }, [columns, groupingModel, leafField]);
40
-
41
- const baseVisibility = useMemo(() => {
42
- const visibility: GridColumnVisibilityModel = {
43
- id: false,
44
- };
45
-
46
- // Only hide leafField if we have grouping (it shows in grouping column)
47
- if (groupingModel.length > 0) {
48
- visibility[leafField] = false;
49
- }
50
-
51
- groupingModel.forEach((field) => {
52
- visibility[field] = false;
53
- });
54
-
55
- return visibility;
56
- }, [groupingModel, leafField]);
57
-
58
- const [columnVisibilityModel, setColumnVisibilityModel] =
59
- useState<GridColumnVisibilityModel>(baseVisibility);
60
-
61
- useEffect(() => {
62
- setColumnVisibilityModel(baseVisibility);
63
- }, [baseVisibility]);
64
-
65
- // functions to customize the column and filter panel in the toolbar
66
- const filterColumns = ({ columns }: FilterColumnsArgs) => {
67
- return columns
68
- .filter((column) => column.type !== "custom")
69
- .map((column) => column.field);
70
- };
71
-
72
- const getTogglableColumns = (columns: GridColDef[]) => {
73
- return columns
74
- .filter((column) => column.type !== "custom")
75
- .map((column) => column.field);
76
- };
77
-
78
- return (
79
- <Paper sx={{ width: "100%" }}>
80
- <Box
81
- sx={{
82
- height: 500,
83
- width: "100%",
84
- overflow: "auto",
85
- }}
86
- >
87
- <DataGridPremium
88
- apiRef={apiRef}
89
- rows={rows}
90
- columns={columns}
91
- getRowId={(row) => row.id}
92
- autosizeOptions={autosizeOptions}
93
- rowGroupingModel={groupingModel}
94
- groupingColDef={{
95
- leafField,
96
- display: "flex",
97
- minWidth: 300,
98
- maxWidth: 500,
99
- flex: 2,
100
- renderCell: (params) => <GroupingCell {...params} />,
101
- }}
102
- columnVisibilityModel={columnVisibilityModel}
103
- onColumnVisibilityModelChange={setColumnVisibilityModel}
104
- onRowSelectionModelChange={(selection) => {
105
- const ids = (selection as any)?.ids ?? new Set<string>();
106
- onSelectionChange(new Set(ids));
107
- }}
108
- rowSelectionPropagation={{ descendants: true, parents: false }}
109
- disableRowGrouping={false}
110
- rowSelectionModel={{
111
- type: "include",
112
- ids: selectedIds,
113
- }}
114
- slotProps={{
115
- filterPanel: {
116
- filterFormProps: {
117
- filterColumns,
118
- },
119
- },
120
- columnsManagement: {
121
- getTogglableColumns,
122
- },
123
- }}
124
- keepNonExistentRowsSelected
125
- showToolbar
126
- disableAggregation
127
- disableRowSelectionExcludeModel
128
- disablePivoting
129
- checkboxSelection
130
- autosizeOnMount
131
- pagination
132
- hideFooterSelectedRowCount
133
- />
134
- </Box>
135
- </Paper>
136
- );
137
- }
1
+ import { Box, Paper } from "@mui/material";
2
+ import {
3
+ DataGridPremium,
4
+ FilterColumnsArgs,
5
+ GridAutosizeOptions,
6
+ GridColDef,
7
+ GridColumnVisibilityModel,
8
+ useGridApiRef,
9
+ } from "@mui/x-data-grid-premium";
10
+ import { useEffect, useMemo, useState } from "react";
11
+ import { DataGridProps } from "../types";
12
+ import { DefaultGroupingCell } from "./DefaultGroupingCell";
13
+
14
+ const autosizeOptions: GridAutosizeOptions = {
15
+ expand: true,
16
+ includeHeaders: true,
17
+ outliersFactor: 1.5,
18
+ };
19
+
20
+ export function DataGridWrapper(props: DataGridProps) {
21
+ const {
22
+ columns,
23
+ groupingModel,
24
+ leafField,
25
+ onSelectionChange,
26
+ rows,
27
+ selectedIds,
28
+ GroupingCellComponent,
29
+ } = props;
30
+
31
+ const GroupingCell = GroupingCellComponent ?? DefaultGroupingCell;
32
+
33
+ const apiRef = useGridApiRef();
34
+
35
+ useEffect(() => {
36
+ if (apiRef.current && apiRef.current.autosizeColumns) {
37
+ apiRef.current.autosizeColumns(autosizeOptions);
38
+ }
39
+ }, [columns, groupingModel, leafField]);
40
+
41
+ const baseVisibility = useMemo(() => {
42
+ const visibility: GridColumnVisibilityModel = {
43
+ id: false,
44
+ };
45
+
46
+ // Only hide leafField if we have grouping (it shows in grouping column)
47
+ if (groupingModel.length > 0) {
48
+ visibility[leafField] = false;
49
+ }
50
+
51
+ groupingModel.forEach((field) => {
52
+ visibility[field] = false;
53
+ });
54
+
55
+ return visibility;
56
+ }, [groupingModel, leafField]);
57
+
58
+ const [columnVisibilityModel, setColumnVisibilityModel] =
59
+ useState<GridColumnVisibilityModel>(baseVisibility);
60
+
61
+ useEffect(() => {
62
+ setColumnVisibilityModel(baseVisibility);
63
+ }, [baseVisibility]);
64
+
65
+ // functions to customize the column and filter panel in the toolbar
66
+ const filterColumns = ({ columns }: FilterColumnsArgs) => {
67
+ return columns
68
+ .filter((column) => column.type !== "custom")
69
+ .map((column) => column.field);
70
+ };
71
+
72
+ const getTogglableColumns = (columns: GridColDef[]) => {
73
+ return columns
74
+ .filter((column) => column.type !== "custom")
75
+ .map((column) => column.field);
76
+ };
77
+
78
+ return (
79
+ <Paper sx={{ width: "100%" }}>
80
+ <Box
81
+ sx={{
82
+ height: 500,
83
+ width: "100%",
84
+ overflow: "auto",
85
+ }}
86
+ >
87
+ <DataGridPremium
88
+ apiRef={apiRef}
89
+ rows={rows}
90
+ columns={columns}
91
+ getRowId={(row) => row.id}
92
+ autosizeOptions={autosizeOptions}
93
+ rowGroupingModel={groupingModel}
94
+ groupingColDef={{
95
+ leafField,
96
+ display: "flex",
97
+ minWidth: 300,
98
+ maxWidth: 500,
99
+ flex: 2,
100
+ renderCell: (params) => <GroupingCell {...params} />,
101
+ }}
102
+ columnVisibilityModel={columnVisibilityModel}
103
+ onColumnVisibilityModelChange={setColumnVisibilityModel}
104
+ onRowSelectionModelChange={(selection) => {
105
+ const ids = (selection as any)?.ids ?? new Set<string>();
106
+ onSelectionChange(new Set(ids));
107
+ }}
108
+ rowSelectionPropagation={{ descendants: true, parents: false }}
109
+ disableRowGrouping={false}
110
+ rowSelectionModel={{
111
+ type: "include",
112
+ ids: selectedIds,
113
+ }}
114
+ slotProps={{
115
+ filterPanel: {
116
+ filterFormProps: {
117
+ filterColumns,
118
+ },
119
+ },
120
+ columnsManagement: {
121
+ getTogglableColumns,
122
+ },
123
+ }}
124
+ keepNonExistentRowsSelected
125
+ showToolbar
126
+ disableAggregation
127
+ disableRowSelectionExcludeModel
128
+ disablePivoting
129
+ checkboxSelection
130
+ autosizeOnMount
131
+ pagination
132
+ hideFooterSelectedRowCount
133
+ />
134
+ </Box>
135
+ </Paper>
136
+ );
137
+ }
@@ -1,64 +1,64 @@
1
- import { Tooltip, Box, IconButton } from "@mui/material";
2
- import {
3
- GridRenderCellParams,
4
- useGridApiContext,
5
- GridGroupNode,
6
- } from "@mui/x-data-grid-premium";
7
- import ChevronRightIcon from "@mui/icons-material/ChevronRight";
8
- import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
9
-
10
- /**
11
- * Default grouping cell that handles expand/collapse, truncation, and tooltips.
12
- * This is a generic implementation without any folder-specific logic.
13
- */
14
- export function DefaultGroupingCell(params: GridRenderCellParams) {
15
- const apiRef = useGridApiContext();
16
- const isGroup = params.rowNode.type === "group";
17
- const groupNode = params.rowNode as GridGroupNode;
18
- const isExpanded = isGroup ? groupNode.childrenExpanded : false;
19
- const depth = params.rowNode.depth ?? 0;
20
-
21
- const handleExpandClick = (e: React.MouseEvent) => {
22
- e.stopPropagation();
23
- apiRef.current.setRowChildrenExpansion(params.id, !isExpanded);
24
- };
25
-
26
- const value = String(params.value ?? "");
27
-
28
- // Indent based on depth (2 units per level)
29
- const indentLevel = depth * 2;
30
-
31
- return (
32
- <Box
33
- sx={{
34
- display: "flex",
35
- alignItems: "center",
36
- width: "100%",
37
- ml: indentLevel,
38
- }}
39
- >
40
- {isGroup && (
41
- <IconButton size="small" onClick={handleExpandClick} sx={{ mr: 0.5 }}>
42
- {isExpanded ? (
43
- <ExpandMoreIcon fontSize="small" />
44
- ) : (
45
- <ChevronRightIcon fontSize="small" />
46
- )}
47
- </IconButton>
48
- )}
49
- <Tooltip title={value} placement="top-start" enterDelay={500}>
50
- <Box
51
- sx={{
52
- overflow: "hidden",
53
- textOverflow: "ellipsis",
54
- whiteSpace: "nowrap",
55
- flex: 1,
56
- fontWeight: isGroup ? "bold" : undefined,
57
- }}
58
- >
59
- {params.formattedValue}
60
- </Box>
61
- </Tooltip>
62
- </Box>
63
- );
64
- }
1
+ import { Tooltip, Box, IconButton } from "@mui/material";
2
+ import {
3
+ GridRenderCellParams,
4
+ useGridApiContext,
5
+ GridGroupNode,
6
+ } from "@mui/x-data-grid-premium";
7
+ import ChevronRightIcon from "@mui/icons-material/ChevronRight";
8
+ import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
9
+
10
+ /**
11
+ * Default grouping cell that handles expand/collapse, truncation, and tooltips.
12
+ * This is a generic implementation without any folder-specific logic.
13
+ */
14
+ export function DefaultGroupingCell(params: GridRenderCellParams) {
15
+ const apiRef = useGridApiContext();
16
+ const isGroup = params.rowNode.type === "group";
17
+ const groupNode = params.rowNode as GridGroupNode;
18
+ const isExpanded = isGroup ? groupNode.childrenExpanded : false;
19
+ const depth = params.rowNode.depth ?? 0;
20
+
21
+ const handleExpandClick = (e: React.MouseEvent) => {
22
+ e.stopPropagation();
23
+ apiRef.current.setRowChildrenExpansion(params.id, !isExpanded);
24
+ };
25
+
26
+ const value = String(params.value ?? "");
27
+
28
+ // Indent based on depth (2 units per level)
29
+ const indentLevel = depth * 2;
30
+
31
+ return (
32
+ <Box
33
+ sx={{
34
+ display: "flex",
35
+ alignItems: "center",
36
+ width: "100%",
37
+ ml: indentLevel,
38
+ }}
39
+ >
40
+ {isGroup && (
41
+ <IconButton size="small" onClick={handleExpandClick} sx={{ mr: 0.5 }}>
42
+ {isExpanded ? (
43
+ <ExpandMoreIcon fontSize="small" />
44
+ ) : (
45
+ <ChevronRightIcon fontSize="small" />
46
+ )}
47
+ </IconButton>
48
+ )}
49
+ <Tooltip title={value} placement="top-start" enterDelay={500}>
50
+ <Box
51
+ sx={{
52
+ overflow: "hidden",
53
+ textOverflow: "ellipsis",
54
+ whiteSpace: "nowrap",
55
+ flex: 1,
56
+ fontWeight: isGroup ? "bold" : undefined,
57
+ }}
58
+ >
59
+ {params.formattedValue}
60
+ </Box>
61
+ </Tooltip>
62
+ </Box>
63
+ );
64
+ }
@@ -0,0 +1,63 @@
1
+ import {
2
+ Button,
3
+ Dialog,
4
+ DialogActions,
5
+ DialogContent,
6
+ DialogContentText,
7
+ DialogTitle,
8
+ } from "@mui/material";
9
+
10
+ interface ClearDialogProps {
11
+ open: boolean;
12
+ onClose: () => void;
13
+ onConfirm: () => void;
14
+ folderLabel: string;
15
+ clearAll: boolean;
16
+ }
17
+
18
+ export function ClearDialog({
19
+ open,
20
+ onClose,
21
+ onConfirm,
22
+ folderLabel,
23
+ clearAll,
24
+ }: ClearDialogProps) {
25
+ return (
26
+ <Dialog open={open} onClose={onClose}>
27
+ <DialogTitle
28
+ sx={{
29
+ bgcolor: "#0c184a",
30
+ color: "white",
31
+ fontWeight: "bold",
32
+ }}
33
+ >
34
+ {clearAll ? "Clear All Folders" : `Clear ${folderLabel}`}
35
+ </DialogTitle>
36
+ <DialogContent sx={{ mt: 2 }}>
37
+ <DialogContentText>
38
+ {clearAll ? (
39
+ "Are you sure you want to clear all selections?"
40
+ ) : (
41
+ <>
42
+ Are you sure you want to clear the selection for{" "}
43
+ <strong>{folderLabel}</strong>?
44
+ </>
45
+ )}
46
+ </DialogContentText>
47
+ </DialogContent>
48
+ <DialogActions sx={{ justifyContent: "center", gap: 2, pb: 2 }}>
49
+ <Button
50
+ variant="contained"
51
+ color="primary"
52
+ onClick={onClose}
53
+ autoFocus
54
+ >
55
+ Cancel
56
+ </Button>
57
+ <Button variant="outlined" color="secondary" onClick={onConfirm}>
58
+ Clear
59
+ </Button>
60
+ </DialogActions>
61
+ </Dialog>
62
+ );
63
+ }
@@ -0,0 +1,33 @@
1
+ import {
2
+ Button,
3
+ Dialog,
4
+ DialogActions,
5
+ DialogContent,
6
+ DialogContentText,
7
+ DialogTitle,
8
+ } from "@mui/material";
9
+
10
+ interface LimitDialogProps {
11
+ open: boolean;
12
+ onClose: () => void;
13
+ maxTracks: number;
14
+ }
15
+
16
+ export function LimitDialog({ open, onClose, maxTracks }: LimitDialogProps) {
17
+ return (
18
+ <Dialog open={open} onClose={onClose}>
19
+ <DialogTitle>Track Limit Reached</DialogTitle>
20
+ <DialogContent>
21
+ <DialogContentText>
22
+ You can select up to {maxTracks} tracks at a time. Please remove a
23
+ track before adding another.
24
+ </DialogContentText>
25
+ </DialogContent>
26
+ <DialogActions>
27
+ <Button onClick={onClose} autoFocus>
28
+ OK
29
+ </Button>
30
+ </DialogActions>
31
+ </Dialog>
32
+ );
33
+ }
@@ -0,0 +1,43 @@
1
+ import {
2
+ Button,
3
+ Dialog,
4
+ DialogActions,
5
+ DialogContent,
6
+ DialogContentText,
7
+ DialogTitle,
8
+ } from "@mui/material";
9
+
10
+ interface ResetDialogProps {
11
+ open: boolean;
12
+ onClose: () => void;
13
+ onConfirm: () => void;
14
+ }
15
+
16
+ export function ResetDialog({ open, onClose, onConfirm }: ResetDialogProps) {
17
+ return (
18
+ <Dialog open={open} onClose={onClose}>
19
+ <DialogTitle
20
+ sx={{
21
+ bgcolor: "#0c184a",
22
+ color: "white",
23
+ fontWeight: "bold",
24
+ }}
25
+ >
26
+ Reset to Default
27
+ </DialogTitle>
28
+ <DialogContent sx={{ mt: 2 }}>
29
+ <DialogContentText>
30
+ Are you sure you want to reset all selections to the default?
31
+ </DialogContentText>
32
+ </DialogContent>
33
+ <DialogActions sx={{ justifyContent: "center", gap: 2, pb: 2 }}>
34
+ <Button variant="contained" color="primary" onClick={onClose} autoFocus>
35
+ Cancel
36
+ </Button>
37
+ <Button variant="outlined" color="secondary" onClick={onConfirm}>
38
+ Reset
39
+ </Button>
40
+ </DialogActions>
41
+ </Dialog>
42
+ );
43
+ }