diff --git a/package.json b/package.json index 76a29175..6fe478c7 100644 --- a/package.json +++ b/package.json @@ -3,9 +3,13 @@ "version": "0.1.0", "private": true, "dependencies": { - "@material-ui/core": "^4.10.2", - "@material-ui/lab": "^4.0.0-alpha.56", + "@emotion/react": "^11.11.4", + "@emotion/styled": "^11.11.5", + "@mui/lab": "^5.0.0-alpha.176", + "@mui/material": "^5.16.7", + "@mui/styles": "^5.16.7", "@sentry/react": "^5.24.2", + "@tanstack/react-table": "^8.21.3", "@testing-library/jest-dom": "^5.11.0", "@testing-library/react": "^10.4.5", "@testing-library/user-event": "^7.1.2", @@ -17,13 +21,17 @@ "@types/react-dom": "^17.0.26", "@types/react-map-gl": "^5.2.7", "@types/react-router-dom": "^5.3.3", - "@types/react-swipeable-views": "^0.13.0", "@types/react-window": "^1.8.2", "@types/webfontloader": "^1.6.32", "airtable": "^0.10.1", + "clsx": "^1.1.1", + "filefy": "^0.1.10", + "history": "^5.0.0", "jest-canvas-mock": "^2.2.0", + "jspdf": "^2.1.0", + "jspdf-autotable": "^3.5.13", + "mapbox-gl": "^1.11.1", "match-sorter": "^4.2.0", - "material-table": "1.68.1", "react": "^17.0.2", "react-device-detect": "^1.17.0", "react-dom": "^17.0.2", @@ -35,7 +43,6 @@ "react-query-devtools": "^2.6.3", "react-router-dom": "^5.2.0", "react-share": "^4.2.1", - "react-swipeable-views": "^0.13.9", "react-transition-group": "^4.4.1", "react-window": "^1.8.5", "simple-statistics": "^7.3.2", @@ -86,15 +93,6 @@ "last 1 safari version" ] }, - "peerDependencies": { - "@material-ui/styles": "^4.10.0", - "clsx": "^1.1.1", - "filefy": "^0.1.10", - "history": "^5.0.0", - "jspdf": "^2.1.0", - "jspdf-autotable": "^3.5.13", - "mapbox-gl": "^1.11.1" - }, "husky": { "hooks": { "pre-commit": "lint-staged" diff --git a/src/components/AppWrap.tsx b/src/components/AppWrap.tsx index 9d5c90c9..17677ad3 100644 --- a/src/components/AppWrap.tsx +++ b/src/components/AppWrap.tsx @@ -1,7 +1,9 @@ import React, { FC, useState } from 'react' -import { createStyles, makeStyles, Theme } from '@material-ui/core/styles' +import { Theme } from '@mui/material/styles' +import createStyles from '@mui/styles/createStyles' +import makeStyles from '@mui/styles/makeStyles' import { InteractiveMap } from 'react-map-gl' -import { Hidden } from '@material-ui/core' +import { Hidden } from '@mui/material' import { panelWidths } from 'components/panels/config' import { PanelWrap, usePanelState, ShowPanelBtn } from 'components/panels' @@ -45,7 +47,7 @@ const useStyles = makeStyles((theme: Theme) => [theme.breakpoints.up('xl')]: { left: (props: Style) => (props.open ? panelWidths.midLarge : 0), }, - [theme.breakpoints.down('sm')]: { + [theme.breakpoints.down('md')]: { top: PANEL_TITLE_BAR_HT_MOBILE, width: '100%', bottom: (props: Style) => diff --git a/src/components/about/AboutPageView.tsx b/src/components/about/AboutPageView.tsx index 88ac403f..d4ef2d5a 100644 --- a/src/components/about/AboutPageView.tsx +++ b/src/components/about/AboutPageView.tsx @@ -1,6 +1,9 @@ import React, { FC } from 'react' import { useQuery } from 'react-query' -import { createStyles, makeStyles, Theme } from '@material-ui/core/styles' +import { Theme } from '@mui/material/styles' + +import createStyles from '@mui/styles/createStyles' +import makeStyles from '@mui/styles/makeStyles' import { LoadingIndicator } from 'components/generic/modals' import { AboutPageProps, WpApiPageResponse } from './types' @@ -19,7 +22,7 @@ const useStyles = makeStyles((theme: Theme) => boxShadow: theme.shadows[8], // Prevent screenshots from getting lost in Paper bg if same color: // outline: 'solid 1px hsl(0deg 0% 40%)', - [theme.breakpoints.down('xs')]: { + [theme.breakpoints.down('sm')]: { margin: '0.5rem 0', }, }, diff --git a/src/components/about/FeedbackForm.tsx b/src/components/about/FeedbackForm.tsx index 791de7b0..bbb74ba5 100644 --- a/src/components/about/FeedbackForm.tsx +++ b/src/components/about/FeedbackForm.tsx @@ -1,5 +1,8 @@ import React, { FC } from 'react' -import { makeStyles, Theme, createStyles } from '@material-ui/core/styles' +import { Theme } from '@mui/material/styles' + +import makeStyles from '@mui/styles/makeStyles' +import createStyles from '@mui/styles/createStyles' const useStyles = makeStyles((theme: Theme) => createStyles({ diff --git a/src/components/about/FeedbackModal.tsx b/src/components/about/FeedbackModal.tsx index a59f3722..814e2fce 100644 --- a/src/components/about/FeedbackModal.tsx +++ b/src/components/about/FeedbackModal.tsx @@ -1,5 +1,8 @@ import React, { FC } from 'react' -import { createStyles, makeStyles, Theme } from '@material-ui/core/styles' +import { Theme } from '@mui/material/styles' + +import createStyles from '@mui/styles/createStyles' +import makeStyles from '@mui/styles/makeStyles' import { SimpleDialog } from 'components/generic/modals' import { FeedbackForm } from 'components/about' diff --git a/src/components/about/FeedbackToggle.tsx b/src/components/about/FeedbackToggle.tsx index c09d3b15..4ce6b2db 100644 --- a/src/components/about/FeedbackToggle.tsx +++ b/src/components/about/FeedbackToggle.tsx @@ -1,6 +1,8 @@ import React, { FC, useState } from 'react' -import { createStyles, makeStyles, Theme } from '@material-ui/core/styles' -import { Button } from '@material-ui/core' +import { Theme } from '@mui/material/styles' +import createStyles from '@mui/styles/createStyles' +import makeStyles from '@mui/styles/makeStyles' +import { Button } from '@mui/material' import { FeedbackModal } from 'components/about' import { Explanation, UItextFromAirtable } from 'components/generic' diff --git a/src/components/about/WaysToHelp.tsx b/src/components/about/WaysToHelp.tsx index 50591597..0146328e 100644 --- a/src/components/about/WaysToHelp.tsx +++ b/src/components/about/WaysToHelp.tsx @@ -1,5 +1,8 @@ import React, { FC } from 'react' -import { makeStyles, Theme, createStyles } from '@material-ui/core/styles' +import { Theme } from '@mui/material/styles' + +import makeStyles from '@mui/styles/makeStyles' +import createStyles from '@mui/styles/createStyles' import { BasicExploreIntro } from 'components/explore' import { UItextFromAirtable } from 'components/generic' diff --git a/src/components/about/WelcomeDialog.tsx b/src/components/about/WelcomeDialog.tsx index 11d3b565..50f572ca 100644 --- a/src/components/about/WelcomeDialog.tsx +++ b/src/components/about/WelcomeDialog.tsx @@ -1,12 +1,14 @@ import React, { FC, useState } from 'react' -import { createStyles, makeStyles, Theme } from '@material-ui/core/styles' +import { Theme } from '@mui/material/styles' +import createStyles from '@mui/styles/createStyles' +import makeStyles from '@mui/styles/makeStyles' import { Dialog, DialogContent, DialogTitle, Typography, Backdrop, -} from '@material-ui/core' +} from '@mui/material' import { MarkdownWithRouteLinks, useUItext, Logo } from 'components/generic' import { WelcomeFooter } from './WelcomeFooter' @@ -20,7 +22,7 @@ const useStyles = makeStyles((theme: Theme) => display: 'flex', justifyContent: 'center', paddingTop: '1rem', - [theme.breakpoints.down('xs')]: { + [theme.breakpoints.down('sm')]: { padding: '1rem 0.75rem 0.75rem', }, }, @@ -42,7 +44,7 @@ const useStyles = makeStyles((theme: Theme) => fontSize: '1rem', paddingTop: '1.5rem', paddingBottom: '1.5rem', - [theme.breakpoints.down('xs')]: { + [theme.breakpoints.down('sm')]: { paddingLeft: '1.25rem', paddingRight: '1.25rem', '& p': { @@ -56,10 +58,10 @@ const useStyles = makeStyles((theme: Theme) => marginLeft: theme.spacing(3), marginRight: theme.spacing(3), }, - [theme.breakpoints.down('xs')]: { + [theme.breakpoints.down('sm')]: { marginBottom: 0, marginTop: 0, - maxHeight: `calc(100% - ${theme.spacing(4)}px)`, + maxHeight: `calc(100% - ${theme.spacing(4)})`, }, }, }) @@ -112,14 +114,13 @@ export const WelcomeDialog: FC = () => { open={open} onClose={handleClose} disableEscapeKeyDown - disableBackdropClick aria-labelledby="welcome-dialog-title" aria-describedby="welcome-dialog-description" maxWidth="sm" BackdropProps={{ classes: { root: backdrop } }} PaperProps={{ classes: { root: paper }, elevation: 24 }} > - + diff --git a/src/components/about/WelcomeFooter.tsx b/src/components/about/WelcomeFooter.tsx index 75912b4f..152e5527 100644 --- a/src/components/about/WelcomeFooter.tsx +++ b/src/components/about/WelcomeFooter.tsx @@ -1,12 +1,14 @@ import React, { FC, useState } from 'react' -import { createStyles, makeStyles, Theme } from '@material-ui/core/styles' +import { Theme } from '@mui/material/styles' +import createStyles from '@mui/styles/createStyles' +import makeStyles from '@mui/styles/makeStyles' import { Button, Checkbox, DialogActions, FormControlLabel, Typography, -} from '@material-ui/core' +} from '@mui/material' import { HIDE_WELCOME_LOCAL_STG_KEY } from './config' diff --git a/src/components/config/theme.ts b/src/components/config/theme.ts index 1c7f633d..b43af828 100644 --- a/src/components/config/theme.ts +++ b/src/components/config/theme.ts @@ -1,8 +1,9 @@ import { - createMuiTheme, + createTheme, responsiveFontSizes, - fade, -} from '@material-ui/core/styles' + alpha, + adaptV4Theme, +} from '@mui/material/styles' // Always have a hard time finding the Typography variant docs for some reason: // https://material-ui.com/components/typography/#component @@ -59,94 +60,80 @@ const headings = { // track, "just" need to wire it up w/state and responsive fonts and all the // other shtuff: `export function customTheme(type: PaletteType)` -// Easy access to theme properties when used in `createMuiTheme` overrides -// CRED: https://stackoverflow.com/a/57127040/1048518 -const customTheme = createMuiTheme({ - palette: { - type: 'dark', - primary: { - light: '#62aca0', - main: '#379587', - dark: '#286a61', - contrastText: '#fff', +const baseTheme = createTheme( + adaptV4Theme({ + palette: { + mode: 'dark', + primary: { + light: '#62aca0', + main: '#379587', + dark: '#286a61', + contrastText: '#fff', + }, + secondary: { + light: '#55a9c1', + main: '#207d96', + dark: '#2d6777', + contrastText: '#fff', + }, }, - secondary: { - light: '#55a9c1', - main: '#207d96', - dark: '#2d6777', - contrastText: '#fff', + typography: { + fontFamily: BODY_FONTS, + fontSize: 16, + ...headings, }, - }, - typography: { - fontFamily: BODY_FONTS, - fontSize: 16, - ...headings, - }, -}) - -// Global overrides of MUI components that need to be re-styled often. More -// examples available at: -// https://github.com/Covid-Self-report-Tool/cov-self-report-frontend/blob/4523287b5c2a4f0dea1fe918b985aa6b6ca1efc6/src/theme.ts + }) +) -// Global overrides of MUI components that need to be re-styled often -customTheme.overrides = { - MuiFormHelperText: { - root: { - fontSize: '0.65rem', - }, - contained: { - marginLeft: '0.75rem', - marginRight: 0, - }, - }, - MuiInput: { - root: { - fontSize: customTheme.typography.body2.fontSize, // default inputs: huge - }, - underline: { - // Bottom line of focused input boxes, including table column filters - '&.Mui-focused:after': { - borderBottomColor: customTheme.palette.secondary.main, +const customTheme = createTheme(baseTheme, { + components: { + MuiFormHelperText: { + styleOverrides: { + root: { fontSize: '0.65rem' }, + contained: { marginLeft: '0.75rem', marginRight: 0 }, }, }, - }, - MuiInputAdornment: { - root: { - color: customTheme.palette.text.secondary, - }, - }, - MuiDialog: { - // Outside boundary of all dialogs - paper: { - margin: 12, + MuiInput: { + styleOverrides: { + root: { fontSize: baseTheme.typography.body2.fontSize }, + underline: { + '&.Mui-focused:after': { + borderBottomColor: baseTheme.palette.secondary.main, + }, + }, + }, }, - }, - MuiButton: { - root: { - textTransform: 'none', + MuiInputAdornment: { + styleOverrides: { + root: { color: baseTheme.palette.text.secondary }, + }, }, - textSecondary: { - color: customTheme.palette.secondary.light, + MuiDialog: { + styleOverrides: { + paper: { margin: 12 }, + }, }, - // Outlined secondary buttons use the default of `palette.secondary.main`, - // which is too hard to see against dark paper backgrounds - outlinedSecondary: { - color: customTheme.palette.secondary.light, - border: `1px solid ${fade(customTheme.palette.secondary.light, 0.5)}`, + MuiButton: { + styleOverrides: { + root: { textTransform: 'none' }, + textSecondary: { color: baseTheme.palette.secondary.light }, + outlinedSecondary: { + color: baseTheme.palette.secondary.light, + border: `1px solid ${alpha(baseTheme.palette.secondary.light, 0.5)}`, + }, + }, }, - }, - MuiLink: { - root: { - color: customTheme.palette.secondary.light, + MuiLink: { + styleOverrides: { + root: { color: baseTheme.palette.secondary.light }, + }, }, - }, - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - MuiAutocomplete: { - root: { - marginBottom: '1rem', + MuiAutocomplete: { + styleOverrides: { + root: { marginBottom: '1rem' }, + }, }, }, -} +}) export const theme = responsiveFontSizes(customTheme) diff --git a/src/components/context/ProvidersWrap.tsx b/src/components/context/ProvidersWrap.tsx index 46587fa7..ab6f31ec 100644 --- a/src/components/context/ProvidersWrap.tsx +++ b/src/components/context/ProvidersWrap.tsx @@ -1,6 +1,10 @@ import React, { FC } from 'react' -import { CssBaseline } from '@material-ui/core' -import { ThemeProvider } from '@material-ui/styles' +import { CssBaseline } from '@mui/material' +import { + Theme, + ThemeProvider, + StyledEngineProvider, +} from '@mui/material/styles' import '../style.css' @@ -8,6 +12,11 @@ import { GlobalProvider } from './GlobalContext' import { SymbAndLabelProvider } from './SymbAndLabelContext' import { theme } from '../config/theme' +declare module '@mui/styles/defaultTheme' { + // eslint-disable-next-line @typescript-eslint/no-empty-interface + interface DefaultTheme extends Theme {} +} + // Everything the app needs except Routes. This makes it testable and reusable // (e.g. ) export const ProvidersWrap: FC = ({ children }) => { @@ -16,10 +25,12 @@ export const ProvidersWrap: FC = ({ children }) => { // https://medium.com/heuristics/react-dark-mode-switch-in-material-ui-dashboard-82fcf1cded66 return ( - - - {children} - + + + + {children} + + ) } diff --git a/src/components/details/Chips.tsx b/src/components/details/Chips.tsx index 9eb564f0..ee5ef234 100644 --- a/src/components/details/Chips.tsx +++ b/src/components/details/Chips.tsx @@ -1,8 +1,10 @@ import React, { FC } from 'react' import { isMobile } from 'react-device-detect' import { Link as RouterLink } from 'react-router-dom' -import { createStyles, makeStyles, Theme } from '@material-ui/core/styles' -import { Paper } from '@material-ui/core' +import { Theme } from '@mui/material/styles' +import createStyles from '@mui/styles/createStyles' +import makeStyles from '@mui/styles/makeStyles' +import { Paper } from '@mui/material' import * as Types from './types' diff --git a/src/components/details/DetailedIntro.tsx b/src/components/details/DetailedIntro.tsx index 417a6742..bd0c8c54 100644 --- a/src/components/details/DetailedIntro.tsx +++ b/src/components/details/DetailedIntro.tsx @@ -1,7 +1,9 @@ import React, { FC, useState } from 'react' -import { createStyles, makeStyles, Theme } from '@material-ui/core/styles' +import { Theme } from '@mui/material/styles' +import createStyles from '@mui/styles/createStyles' +import makeStyles from '@mui/styles/makeStyles' import { Route, Switch } from 'react-router-dom' -import { Grow } from '@material-ui/core' +import { Grow } from '@mui/material' import { Media } from 'components/media' import { MoreLikeThis } from 'components/details' diff --git a/src/components/details/DetailsPanel.tsx b/src/components/details/DetailsPanel.tsx index 7926127d..90920372 100644 --- a/src/components/details/DetailsPanel.tsx +++ b/src/components/details/DetailsPanel.tsx @@ -1,6 +1,6 @@ import React, { FC } from 'react' import { Switch, Route } from 'react-router-dom' -import { Typography } from '@material-ui/core' +import { Typography } from '@mui/material' import { RecordDescription } from 'components/results' import { DetailedIntro, LangOrEndoIntro } from 'components/details' diff --git a/src/components/details/EndoImageWrap.tsx b/src/components/details/EndoImageWrap.tsx index f57eaac7..dafbe691 100644 --- a/src/components/details/EndoImageWrap.tsx +++ b/src/components/details/EndoImageWrap.tsx @@ -1,5 +1,6 @@ import React, { FC } from 'react' -import { createStyles, makeStyles } from '@material-ui/core/styles' +import createStyles from '@mui/styles/createStyles' +import makeStyles from '@mui/styles/makeStyles' type EndoImageComponent = { url: string diff --git a/src/components/details/LocationLink.tsx b/src/components/details/LocationLink.tsx index 046a76ac..3f5e02aa 100644 --- a/src/components/details/LocationLink.tsx +++ b/src/components/details/LocationLink.tsx @@ -1,7 +1,9 @@ import React, { FC } from 'react' import { Link as RouterLink } from 'react-router-dom' -import { createStyles, makeStyles, Theme } from '@material-ui/core/styles' -import { Button, Popover } from '@material-ui/core' +import { Theme } from '@mui/material/styles' +import createStyles from '@mui/styles/createStyles' +import makeStyles from '@mui/styles/makeStyles' +import { Button, Popover } from '@mui/material' import { BiMapPin } from 'react-icons/bi' import { NeighborhoodList } from 'components/details' diff --git a/src/components/details/MoreLikeThis.tsx b/src/components/details/MoreLikeThis.tsx index 1ba14bf3..3535f7bd 100644 --- a/src/components/details/MoreLikeThis.tsx +++ b/src/components/details/MoreLikeThis.tsx @@ -1,5 +1,7 @@ import React, { FC } from 'react' -import { createStyles, makeStyles, Theme } from '@material-ui/core/styles' +import { Theme } from '@mui/material/styles' +import createStyles from '@mui/styles/createStyles' +import makeStyles from '@mui/styles/makeStyles' import { IoIosPeople } from 'react-icons/io' import { routes } from 'components/config/api' diff --git a/src/components/details/NeighborhoodList.tsx b/src/components/details/NeighborhoodList.tsx index d9891cd6..a0b0fd46 100644 --- a/src/components/details/NeighborhoodList.tsx +++ b/src/components/details/NeighborhoodList.tsx @@ -1,7 +1,9 @@ import React, { FC } from 'react' import { Link as RouterLink, Route, Switch } from 'react-router-dom' -import { createStyles, makeStyles, Theme } from '@material-ui/core/styles' -import { Typography, Link } from '@material-ui/core' +import { Theme } from '@mui/material/styles' +import createStyles from '@mui/styles/createStyles' +import makeStyles from '@mui/styles/makeStyles' +import { Typography, Link } from '@mui/material' import { BiMapPin } from 'react-icons/bi' import { CustomCard, CardListWrap } from 'components/explore' diff --git a/src/components/details/RandomLinkBtn.tsx b/src/components/details/RandomLinkBtn.tsx index ccccc76a..d266fc0e 100644 --- a/src/components/details/RandomLinkBtn.tsx +++ b/src/components/details/RandomLinkBtn.tsx @@ -1,6 +1,6 @@ import React, { FC, useContext } from 'react' import { Link as RouterLink } from 'react-router-dom' -import { Button } from '@material-ui/core' +import { Button } from '@mui/material' import { FaRandom } from 'react-icons/fa' import { GlobalContext } from 'components/context' diff --git a/src/components/details/styles.ts b/src/components/details/styles.ts index e60db6aa..9825a9d4 100644 --- a/src/components/details/styles.ts +++ b/src/components/details/styles.ts @@ -1,4 +1,7 @@ -import { createStyles, makeStyles, Theme } from '@material-ui/core/styles' +import { Theme } from '@mui/material/styles' + +import createStyles from '@mui/styles/createStyles' +import makeStyles from '@mui/styles/makeStyles' export const useStyles = makeStyles((theme: Theme) => createStyles({ diff --git a/src/components/explore/BasicExploreIntro.tsx b/src/components/explore/BasicExploreIntro.tsx index 670382b2..6db70114 100644 --- a/src/components/explore/BasicExploreIntro.tsx +++ b/src/components/explore/BasicExploreIntro.tsx @@ -1,7 +1,9 @@ import React, { FC } from 'react' import { Route } from 'react-router-dom' -import { createStyles, makeStyles, Theme } from '@material-ui/core/styles' -import { Grow, Typography } from '@material-ui/core' +import { Theme } from '@mui/material/styles' +import createStyles from '@mui/styles/createStyles' +import makeStyles from '@mui/styles/makeStyles' +import { Grow, Typography } from '@mui/material' import { FiltersWarning } from 'components/home/FiltersWarning' import { Explanation } from 'components/generic' diff --git a/src/components/explore/Breadcrumbs.tsx b/src/components/explore/Breadcrumbs.tsx index c665e4a7..60e8b91f 100644 --- a/src/components/explore/Breadcrumbs.tsx +++ b/src/components/explore/Breadcrumbs.tsx @@ -1,6 +1,8 @@ import React, { FC } from 'react' -import { makeStyles, Theme, createStyles } from '@material-ui/core/styles' -import { Link } from '@material-ui/core' +import { Theme } from '@mui/material/styles' +import makeStyles from '@mui/styles/makeStyles' +import createStyles from '@mui/styles/createStyles' +import { Link } from '@mui/material' import { useLocation, Link as RouterLink, @@ -17,7 +19,7 @@ const useStyles = makeStyles((theme: Theme) => alignItems: 'center', display: 'flex', overflow: 'hidden', - [theme.breakpoints.down('sm')]: { + [theme.breakpoints.down('md')]: { overflowX: 'auto', // Easter egg: scroll sideways on small screens }, '& > :last-child': { diff --git a/src/components/explore/CardList.tsx b/src/components/explore/CardList.tsx index ee049fef..7306f2c5 100644 --- a/src/components/explore/CardList.tsx +++ b/src/components/explore/CardList.tsx @@ -1,6 +1,9 @@ import React, { FC } from 'react' import { useParams, useRouteMatch } from 'react-router-dom' -import { createStyles, makeStyles, Theme } from '@material-ui/core/styles' +import { Theme } from '@mui/material/styles' + +import createStyles from '@mui/styles/createStyles' +import makeStyles from '@mui/styles/makeStyles' import { ColoredCircle } from 'components/generic/icons-and-swatches' import { RouteMatch, TonsWithAddl } from './types' diff --git a/src/components/explore/CensusPopover.tsx b/src/components/explore/CensusPopover.tsx index 450fd1a3..862fc92d 100644 --- a/src/components/explore/CensusPopover.tsx +++ b/src/components/explore/CensusPopover.tsx @@ -1,7 +1,9 @@ import React, { FC, useState } from 'react' import { Link as RouterLink } from 'react-router-dom' -import { makeStyles, createStyles, Theme } from '@material-ui/core/styles' -import { Typography, Popover, Button } from '@material-ui/core' +import { Theme } from '@mui/material/styles' +import makeStyles from '@mui/styles/makeStyles' +import createStyles from '@mui/styles/createStyles' +import { Typography, Popover, Button } from '@mui/material' import { FaClipboardList } from 'react-icons/fa' import { MdLayersClear, MdLayers } from 'react-icons/md' diff --git a/src/components/explore/ClearSelectionBtn.tsx b/src/components/explore/ClearSelectionBtn.tsx index 7cf353ba..ecf468fc 100644 --- a/src/components/explore/ClearSelectionBtn.tsx +++ b/src/components/explore/ClearSelectionBtn.tsx @@ -1,6 +1,6 @@ import React, { FC } from 'react' import { Link as RouterLink } from 'react-router-dom' -import { Button } from '@material-ui/core' +import { Button } from '@mui/material' import { IoIosCloseCircleOutline } from 'react-icons/io' import { routes } from 'components/config/api' diff --git a/src/components/explore/CustomCard.tsx b/src/components/explore/CustomCard.tsx index 4d2e6dcb..cb9f77b2 100644 --- a/src/components/explore/CustomCard.tsx +++ b/src/components/explore/CustomCard.tsx @@ -1,8 +1,10 @@ import React, { FC } from 'react' import { isMobile } from 'react-device-detect' import { Link } from 'react-router-dom' -import { createStyles, makeStyles, Theme } from '@material-ui/core/styles' -import { Grow, Card, Typography } from '@material-ui/core' +import { Theme } from '@mui/material/styles' +import createStyles from '@mui/styles/createStyles' +import makeStyles from '@mui/styles/makeStyles' +import { Grow, Card, Typography } from '@mui/material' import { CustomCardProps } from './types' import * as utils from './utils' diff --git a/src/components/explore/LayerToggle.tsx b/src/components/explore/LayerToggle.tsx index 57f8172a..457413b3 100644 --- a/src/components/explore/LayerToggle.tsx +++ b/src/components/explore/LayerToggle.tsx @@ -1,6 +1,8 @@ import React, { FC } from 'react' -import { createStyles, makeStyles, Theme } from '@material-ui/core/styles' -import { FormControlLabel, Switch } from '@material-ui/core' +import { Theme } from '@mui/material/styles' +import createStyles from '@mui/styles/createStyles' +import makeStyles from '@mui/styles/makeStyles' +import { FormControlLabel, Switch } from '@mui/material' import { useMapToolsState, useMapToolsDispatch } from 'components/context' @@ -26,7 +28,7 @@ const useStyles = makeStyles((theme: Theme) => // wowww overkill, but it fits... hideOnMobile: { whiteSpace: 'pre', - [theme.breakpoints.down('xs')]: { + [theme.breakpoints.down('sm')]: { display: 'none', }, }, diff --git a/src/components/explore/NeighborhoodsInstance.tsx b/src/components/explore/NeighborhoodsInstance.tsx index dd3e22ce..73381472 100644 --- a/src/components/explore/NeighborhoodsInstance.tsx +++ b/src/components/explore/NeighborhoodsInstance.tsx @@ -1,7 +1,9 @@ import React, { FC, useState } from 'react' import { useParams, useRouteMatch } from 'react-router-dom' -import { createStyles, makeStyles, Theme } from '@material-ui/core/styles' -import { Button } from '@material-ui/core' +import { Theme } from '@mui/material/styles' +import createStyles from '@mui/styles/createStyles' +import makeStyles from '@mui/styles/makeStyles' +import { Button } from '@mui/material' import { FiShare } from 'react-icons/fi' import { BasicExploreIntro } from 'components/panels' @@ -58,7 +60,7 @@ const useStyles = makeStyles((theme: Theme) => }, '& .MuiButton-textSizeSmall': { fontSize: '0.85rem', - [theme.breakpoints.down('sm')]: { + [theme.breakpoints.down('md')]: { minWidth: 'auto', }, }, @@ -66,7 +68,7 @@ const useStyles = makeStyles((theme: Theme) => // wowww overkill, but it fits... hideOnMobile: { whiteSpace: 'pre', - [theme.breakpoints.down('sm')]: { + [theme.breakpoints.down('md')]: { display: 'none', }, }, diff --git a/src/components/explore/PanelIntroTitleSubtitle.tsx b/src/components/explore/PanelIntroTitleSubtitle.tsx index b7424298..8d474d1e 100644 --- a/src/components/explore/PanelIntroTitleSubtitle.tsx +++ b/src/components/explore/PanelIntroTitleSubtitle.tsx @@ -1,6 +1,8 @@ import React, { FC } from 'react' -import { createStyles, makeStyles, Theme } from '@material-ui/core/styles' -import { Typography } from '@material-ui/core' +import { Theme } from '@mui/material/styles' +import createStyles from '@mui/styles/createStyles' +import makeStyles from '@mui/styles/makeStyles' +import { Typography } from '@mui/material' const useStyles = makeStyles((theme: Theme) => createStyles({ diff --git a/src/components/explore/StatsAndMeta.tsx b/src/components/explore/StatsAndMeta.tsx index 3b68d086..411769b4 100644 --- a/src/components/explore/StatsAndMeta.tsx +++ b/src/components/explore/StatsAndMeta.tsx @@ -1,5 +1,8 @@ import React, { FC } from 'react' -import { makeStyles, createStyles, Theme } from '@material-ui/core/styles' +import { Theme } from '@mui/material/styles' + +import makeStyles from '@mui/styles/makeStyles' +import createStyles from '@mui/styles/createStyles' import { StatsAndMetaProps } from 'components/explore/types' diff --git a/src/components/generic/BackToTopBtn.tsx b/src/components/generic/BackToTopBtn.tsx index 77446845..e645a31c 100644 --- a/src/components/generic/BackToTopBtn.tsx +++ b/src/components/generic/BackToTopBtn.tsx @@ -1,12 +1,7 @@ import React, { FC } from 'react' -import { - createStyles, - makeStyles, - Theme, - Fab, - fade, - Zoom, -} from '@material-ui/core' +import { Theme, Fab, alpha, Zoom } from '@mui/material' +import createStyles from '@mui/styles/createStyles' +import makeStyles from '@mui/styles/makeStyles' import { FaArrowCircleUp } from 'react-icons/fa' import { BOTTOM_NAV_HEIGHT } from 'components/nav/config' @@ -21,7 +16,7 @@ const useStyles = makeStyles((theme: Theme) => position: 'absolute', bottom: BOTTOM_NAV_HEIGHT + 8, right: '1.25rem', - [theme.breakpoints.down('sm')]: { + [theme.breakpoints.down('md')]: { bottom: '1rem', right: '1rem', }, @@ -30,7 +25,7 @@ const useStyles = makeStyles((theme: Theme) => width: 36, height: 36, minHeight: 36, - backgroundColor: fade(theme.palette.secondary.main, 0.75), + backgroundColor: alpha(theme.palette.secondary.main, 0.75), }, }) ) diff --git a/src/components/generic/Explanation.tsx b/src/components/generic/Explanation.tsx index d4847e3d..fb841659 100644 --- a/src/components/generic/Explanation.tsx +++ b/src/components/generic/Explanation.tsx @@ -1,6 +1,8 @@ import React, { FC } from 'react' -import { createStyles, makeStyles, Theme } from '@material-ui/core/styles' -import { Typography } from '@material-ui/core' +import { Theme } from '@mui/material/styles' +import createStyles from '@mui/styles/createStyles' +import makeStyles from '@mui/styles/makeStyles' +import { Typography } from '@mui/material' const useStyles = makeStyles((theme: Theme) => createStyles({ diff --git a/src/components/generic/FancyHorizRule.tsx b/src/components/generic/FancyHorizRule.tsx index a51db29d..e14134c8 100644 --- a/src/components/generic/FancyHorizRule.tsx +++ b/src/components/generic/FancyHorizRule.tsx @@ -1,5 +1,8 @@ import React, { FC } from 'react' -import { createStyles, makeStyles, Theme } from '@material-ui/core/styles' +import { Theme } from '@mui/material/styles' + +import createStyles from '@mui/styles/createStyles' +import makeStyles from '@mui/styles/makeStyles' const useStyles = makeStyles((theme: Theme) => createStyles({ diff --git a/src/components/generic/Logo.tsx b/src/components/generic/Logo.tsx index 1998d70c..df3e12c9 100644 --- a/src/components/generic/Logo.tsx +++ b/src/components/generic/Logo.tsx @@ -1,5 +1,7 @@ import React, { FC } from 'react' -import { createStyles, makeStyles, Theme } from '@material-ui/core/styles' +import { Theme } from '@mui/material/styles' +import createStyles from '@mui/styles/createStyles' +import makeStyles from '@mui/styles/makeStyles' import ProjectLogo from '../../img/logo.svg?react' type LogoProps = { diff --git a/src/components/generic/MarkdownWithRouteLinks.tsx b/src/components/generic/MarkdownWithRouteLinks.tsx index 02ac11ca..b7d63050 100644 --- a/src/components/generic/MarkdownWithRouteLinks.tsx +++ b/src/components/generic/MarkdownWithRouteLinks.tsx @@ -1,7 +1,7 @@ import React, { FC } from 'react' import ReactMarkdown from 'react-markdown' import { Link as RouterLink } from 'react-router-dom' -import { Link } from '@material-ui/core' +import { Link } from '@mui/material' import { LinkRenderer, MarkdownRootElemType } from './types' diff --git a/src/components/generic/ReadMore.tsx b/src/components/generic/ReadMore.tsx index a61b137e..a55c12a4 100644 --- a/src/components/generic/ReadMore.tsx +++ b/src/components/generic/ReadMore.tsx @@ -1,7 +1,9 @@ import React, { FC, useState } from 'react' import { isMobile } from 'react-device-detect' -import { createStyles, makeStyles, Theme } from '@material-ui/core/styles' -import { Button } from '@material-ui/core' +import { Theme } from '@mui/material/styles' +import createStyles from '@mui/styles/createStyles' +import makeStyles from '@mui/styles/makeStyles' +import { Button } from '@mui/material' import { ToggleableSection, MarkdownWithRouteLinks } from 'components/generic' diff --git a/src/components/generic/ShareButtons.tsx b/src/components/generic/ShareButtons.tsx index bed3d5bc..d318d7f4 100644 --- a/src/components/generic/ShareButtons.tsx +++ b/src/components/generic/ShareButtons.tsx @@ -1,7 +1,7 @@ // CRED: for the majority of this file: // https://github.com/Covid-Self-report-Tool/cov-self-report-frontend/blob/master/src/components/ShareButtons.tsx import React, { FC } from 'react' -import { Grid, GridSpacing } from '@material-ui/core' +import { Grid, GridSpacing } from '@mui/material' import { EmailIcon, EmailShareButton, @@ -47,7 +47,7 @@ export const ShareButtons: FC = (props) => { return ( createStyles({ diff --git a/src/components/generic/ToggleWithHelper.tsx b/src/components/generic/ToggleWithHelper.tsx index 68e836b3..08f5477c 100644 --- a/src/components/generic/ToggleWithHelper.tsx +++ b/src/components/generic/ToggleWithHelper.tsx @@ -1,6 +1,8 @@ import React, { FC } from 'react' -import { createStyles, makeStyles, Theme } from '@material-ui/core/styles' -import { FormControlLabel, Switch } from '@material-ui/core' +import { Theme } from '@mui/material/styles' +import createStyles from '@mui/styles/createStyles' +import makeStyles from '@mui/styles/makeStyles' +import { FormControlLabel, Switch } from '@mui/material' import { ToggleWithHelperProps } from './types' import { SubtleText } from './SubtleText' diff --git a/src/components/generic/ToggleableSection.tsx b/src/components/generic/ToggleableSection.tsx index 52f8b58c..a21ce963 100644 --- a/src/components/generic/ToggleableSection.tsx +++ b/src/components/generic/ToggleableSection.tsx @@ -1,5 +1,6 @@ import React, { FC } from 'react' -import { createStyles, makeStyles } from '@material-ui/core/styles' +import createStyles from '@mui/styles/createStyles' +import makeStyles from '@mui/styles/makeStyles' type ToggleableProps = { show: boolean diff --git a/src/components/generic/hooks.ts b/src/components/generic/hooks.ts index fc1b1fc5..a1dbdf97 100644 --- a/src/components/generic/hooks.ts +++ b/src/components/generic/hooks.ts @@ -1,5 +1,5 @@ import { useRef, useState, useCallback, useEffect } from 'react' -import { useTheme } from '@material-ui/core/styles' +import { useTheme } from '@mui/material/styles' import { useAirtable } from 'components/explore/hooks' import { useLocation, useRouteMatch } from 'react-router-dom' import { routes } from 'components/config' diff --git a/src/components/generic/modals/DialogCloseBtn.tsx b/src/components/generic/modals/DialogCloseBtn.tsx index 3283c340..2da97557 100644 --- a/src/components/generic/modals/DialogCloseBtn.tsx +++ b/src/components/generic/modals/DialogCloseBtn.tsx @@ -1,6 +1,8 @@ import React, { FC } from 'react' -import { createStyles, makeStyles, Theme } from '@material-ui/core/styles' -import { IconButton } from '@material-ui/core' +import { Theme } from '@mui/material/styles' +import createStyles from '@mui/styles/createStyles' +import makeStyles from '@mui/styles/makeStyles' +import { IconButton } from '@mui/material' import { MdClose } from 'react-icons/md' const useStyles = makeStyles((theme: Theme) => @@ -34,6 +36,7 @@ export const DialogCloseBtn: FC = (props) => { onClick={onClose} className={classes.closeBtnRoot} title={tooltip} + size="large" > diff --git a/src/components/generic/modals/LoadingBackdrop.tsx b/src/components/generic/modals/LoadingBackdrop.tsx index 35c494ab..02577751 100644 --- a/src/components/generic/modals/LoadingBackdrop.tsx +++ b/src/components/generic/modals/LoadingBackdrop.tsx @@ -1,6 +1,8 @@ import React, { FC } from 'react' -import { makeStyles, createStyles, Theme } from '@material-ui/core/styles' -import { Backdrop, CircularProgress, Typography } from '@material-ui/core' +import { Theme } from '@mui/material/styles' +import makeStyles from '@mui/styles/makeStyles' +import createStyles from '@mui/styles/createStyles' +import { Backdrop, CircularProgress, Typography } from '@mui/material' type LoadingBackdrop = { centerOnScreen?: boolean diff --git a/src/components/generic/modals/LoadingIndicator.tsx b/src/components/generic/modals/LoadingIndicator.tsx index b7d86452..43881476 100644 --- a/src/components/generic/modals/LoadingIndicator.tsx +++ b/src/components/generic/modals/LoadingIndicator.tsx @@ -1,6 +1,8 @@ import React, { FC } from 'react' -import { createStyles, makeStyles, Theme } from '@material-ui/core/styles' -import { Typography, CircularProgress, LinearProgress } from '@material-ui/core' +import { Theme } from '@mui/material/styles' +import createStyles from '@mui/styles/createStyles' +import makeStyles from '@mui/styles/makeStyles' +import { Typography, CircularProgress, LinearProgress } from '@mui/material' type LoadingProps = { omitText?: boolean diff --git a/src/components/generic/modals/LoadingTextOnElem.tsx b/src/components/generic/modals/LoadingTextOnElem.tsx index 1859cd3a..19894aa5 100644 --- a/src/components/generic/modals/LoadingTextOnElem.tsx +++ b/src/components/generic/modals/LoadingTextOnElem.tsx @@ -1,6 +1,8 @@ import React, { FC } from 'react' -import { makeStyles, createStyles, Theme } from '@material-ui/core/styles' -import { CircularProgress, Typography } from '@material-ui/core' +import { Theme } from '@mui/material/styles' +import makeStyles from '@mui/styles/makeStyles' +import createStyles from '@mui/styles/createStyles' +import { CircularProgress, Typography } from '@mui/material' const useStyles = makeStyles((theme: Theme) => createStyles({ diff --git a/src/components/generic/modals/SimpleDialog.tsx b/src/components/generic/modals/SimpleDialog.tsx index a96dd70b..e9e29a2f 100644 --- a/src/components/generic/modals/SimpleDialog.tsx +++ b/src/components/generic/modals/SimpleDialog.tsx @@ -1,16 +1,13 @@ import React, { FC } from 'react' -import { - createStyles, - makeStyles, - useTheme, - Theme, -} from '@material-ui/core/styles' +import { useTheme, Theme } from '@mui/material/styles' +import createStyles from '@mui/styles/createStyles' +import makeStyles from '@mui/styles/makeStyles' import { Dialog, DialogContent, DialogProps, useMediaQuery, -} from '@material-ui/core' +} from '@mui/material' import { DialogCloseBtn } from './DialogCloseBtn' import { SlideUp } from './SlideUp' @@ -19,7 +16,7 @@ const useStyles = makeStyles((theme: Theme) => createStyles({ dialogContent: { padding: theme.spacing(3), - [theme.breakpoints.down('sm')]: { + [theme.breakpoints.down('md')]: { padding: '2rem 1rem', // make media btns fit }, }, diff --git a/src/components/generic/modals/SlideUp.tsx b/src/components/generic/modals/SlideUp.tsx index efb53127..df7e5af3 100644 --- a/src/components/generic/modals/SlideUp.tsx +++ b/src/components/generic/modals/SlideUp.tsx @@ -1,11 +1,10 @@ import React from 'react' -import { Slide } from '@material-ui/core' -import { TransitionProps } from '@material-ui/core/transitions' +import { Slide } from '@mui/material' +import { TransitionProps } from '@mui/material/transitions' export const SlideUp = React.forwardRef(function Transition( - // Don't care, came straight from the MUI example - // eslint-disable-next-line react/require-default-props, @typescript-eslint/no-explicit-any - props: TransitionProps & { children?: React.ReactElement }, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + props: TransitionProps & { children: React.ReactElement }, ref: React.Ref ) { return diff --git a/src/components/home/ClearFiltersBtn.tsx b/src/components/home/ClearFiltersBtn.tsx index fc5fb2b4..e3be4a85 100644 --- a/src/components/home/ClearFiltersBtn.tsx +++ b/src/components/home/ClearFiltersBtn.tsx @@ -1,5 +1,5 @@ import React, { FC } from 'react' -import { Button } from '@material-ui/core' +import { Button } from '@mui/material' import { IoMdCloseCircle } from 'react-icons/io' type ClearFiltersComponent = { diff --git a/src/components/home/FiltersWarning.tsx b/src/components/home/FiltersWarning.tsx index 34a29e50..037002f3 100644 --- a/src/components/home/FiltersWarning.tsx +++ b/src/components/home/FiltersWarning.tsx @@ -1,7 +1,9 @@ import React, { FC, useContext } from 'react' import { Link as RouterLink } from 'react-router-dom' -import { createStyles, makeStyles, Theme } from '@material-ui/core/styles' -import { Button, Link } from '@material-ui/core' +import { Theme } from '@mui/material/styles' +import createStyles from '@mui/styles/createStyles' +import makeStyles from '@mui/styles/makeStyles' +import { Button, Link } from '@mui/material' import { GlobalContext } from 'components/context' import { Explanation } from 'components/generic' diff --git a/src/components/home/ListboxComponent.tsx b/src/components/home/ListboxComponent.tsx index 1865ab8a..578ca179 100644 --- a/src/components/home/ListboxComponent.tsx +++ b/src/components/home/ListboxComponent.tsx @@ -1,5 +1,5 @@ import React from 'react' -import { ListSubheader } from '@material-ui/core' +import { ListSubheader } from '@mui/material' import { VariableSizeList, ListChildComponentProps } from 'react-window' import { useResetCache } from './utils' diff --git a/src/components/home/OmniboxResult.tsx b/src/components/home/OmniboxResult.tsx index 0e00119e..c2a33c4f 100644 --- a/src/components/home/OmniboxResult.tsx +++ b/src/components/home/OmniboxResult.tsx @@ -1,6 +1,8 @@ import React, { FC } from 'react' -import { createStyles, makeStyles, Theme } from '@material-ui/core/styles' -import { Typography, Box } from '@material-ui/core' +import { Theme } from '@mui/material/styles' +import createStyles from '@mui/styles/createStyles' +import makeStyles from '@mui/styles/makeStyles' +import { Typography, Box } from '@mui/material' import { PreppedAutocompleteGroup } from './types' diff --git a/src/components/home/SearchByOmnibox.tsx b/src/components/home/SearchByOmnibox.tsx index bc4d9c33..b2a20034 100644 --- a/src/components/home/SearchByOmnibox.tsx +++ b/src/components/home/SearchByOmnibox.tsx @@ -1,9 +1,11 @@ import React, { FC } from 'react' import { useHistory } from 'react-router-dom' import matchSorter from 'match-sorter' -import Autocomplete from '@material-ui/lab/Autocomplete' -import { TextField, InputAdornment } from '@material-ui/core' -import { makeStyles, Theme, createStyles } from '@material-ui/core/styles' +import Autocomplete from '@mui/material/Autocomplete' +import { TextField, InputAdornment } from '@mui/material' +import { Theme } from '@mui/material/styles' +import makeStyles from '@mui/styles/makeStyles' +import createStyles from '@mui/styles/createStyles' import { MdClose } from 'react-icons/md' import { GoSearch } from 'react-icons/go' @@ -43,7 +45,7 @@ const useStyles = makeStyles((theme: Theme) => }, // Group headings '& .MuiListSubheader-root': { - borderBottom: `1px solid ${theme.palette.text.hint}`, + borderBottom: `1px solid ${theme.palette.text.disabled}`, color: theme.palette.text.primary, fontFamily: theme.typography.h1.fontFamily, fontSize: '1.25rem', @@ -109,7 +111,7 @@ export const SearchByOmnibox: FC = (props) => { } + clearIcon={} // Thought this helped to resolve iOS zoom issue but the cause seems to be // when font size is smaller than the page default. // blurOnSelect="touch" @@ -122,7 +124,11 @@ export const SearchByOmnibox: FC = (props) => { disabled={isLoading || problemo} loadingText={loadingText} // does nothing renderGroup={renderGroup} - renderOption={(option) => } + renderOption={(liProps, option) => ( +
  • + +
  • + )} size="small" popupIcon={null} color="secondary" diff --git a/src/components/home/utils.tsx b/src/components/home/utils.tsx index bd50fc55..433d3f13 100644 --- a/src/components/home/utils.tsx +++ b/src/components/home/utils.tsx @@ -1,8 +1,8 @@ import React from 'react' import { Link as RouterLink } from 'react-router-dom' import { VariableSizeList } from 'react-window' -import { AutocompleteRenderGroupParams } from '@material-ui/lab/Autocomplete' -import ListSubheader from '@material-ui/core/ListSubheader' +import { AutocompleteRenderGroupParams } from '@mui/material/Autocomplete' +import ListSubheader from '@mui/material/ListSubheader' import { LangLevelSchema } from 'components/context/types' import { PreppedAutocompleteGroup } from './types' diff --git a/src/components/legend/LangPointsToggle.tsx b/src/components/legend/LangPointsToggle.tsx index 56e7a409..c14e4321 100644 --- a/src/components/legend/LangPointsToggle.tsx +++ b/src/components/legend/LangPointsToggle.tsx @@ -1,7 +1,10 @@ // TODO: rename file to something logical; mv it and all children to ../local import React, { FC } from 'react' -import { FormControlLabel, Switch } from '@material-ui/core' -import { createStyles, makeStyles, Theme } from '@material-ui/core/styles' +import { FormControlLabel, Switch } from '@mui/material' +import { Theme } from '@mui/material/styles' + +import createStyles from '@mui/styles/createStyles' +import makeStyles from '@mui/styles/makeStyles' import { useLabelAndSymbDispatch, @@ -29,7 +32,7 @@ const useStyles = makeStyles((theme: Theme) => }, smallerText: { fontSize: '0.75rem', - [theme.breakpoints.down('sm')]: { + [theme.breakpoints.down('md')]: { fontSize: '0.65rem', }, }, diff --git a/src/components/legend/LayerLabelSelect.tsx b/src/components/legend/LayerLabelSelect.tsx index 3f537b11..85661298 100644 --- a/src/components/legend/LayerLabelSelect.tsx +++ b/src/components/legend/LayerLabelSelect.tsx @@ -1,5 +1,5 @@ import React, { FC } from 'react' -import { TextField } from '@material-ui/core' +import { TextField } from '@mui/material' import { useSymbAndLabelState, diff --git a/src/components/legend/LayerSymbSelect.tsx b/src/components/legend/LayerSymbSelect.tsx index 5f36ac67..828c51e4 100644 --- a/src/components/legend/LayerSymbSelect.tsx +++ b/src/components/legend/LayerSymbSelect.tsx @@ -1,5 +1,5 @@ import React, { FC } from 'react' -import { TextField } from '@material-ui/core' +import { TextField } from '@mui/material' import { useSymbAndLabelState, diff --git a/src/components/legend/Legend.tsx b/src/components/legend/Legend.tsx index 41e0962a..cdb9b8ea 100644 --- a/src/components/legend/Legend.tsx +++ b/src/components/legend/Legend.tsx @@ -1,7 +1,9 @@ import React, { FC } from 'react' import { Link as RouterLink } from 'react-router-dom' -import { createStyles, makeStyles, Theme } from '@material-ui/core/styles' -import { Typography } from '@material-ui/core' +import { Theme } from '@mui/material/styles' +import createStyles from '@mui/styles/createStyles' +import makeStyles from '@mui/styles/makeStyles' +import { Typography } from '@mui/material' import { LegendSwatch } from 'components/legend' import { Explanation, SubtleText } from 'components/generic' diff --git a/src/components/legend/LegendPanel.tsx b/src/components/legend/LegendPanel.tsx index 5b0ef846..d2419184 100644 --- a/src/components/legend/LegendPanel.tsx +++ b/src/components/legend/LegendPanel.tsx @@ -1,6 +1,8 @@ import React, { FC } from 'react' -import { createStyles, makeStyles, Theme } from '@material-ui/core/styles' -import { Typography } from '@material-ui/core' +import { Theme } from '@mui/material/styles' +import createStyles from '@mui/styles/createStyles' +import makeStyles from '@mui/styles/makeStyles' +import { Typography } from '@mui/material' import { LayerSymbSelect, diff --git a/src/components/legend/LegendSwatch.tsx b/src/components/legend/LegendSwatch.tsx index eb287c08..7cdb1deb 100644 --- a/src/components/legend/LegendSwatch.tsx +++ b/src/components/legend/LegendSwatch.tsx @@ -1,6 +1,8 @@ import React, { FC } from 'react' -import { createStyles, makeStyles, Theme } from '@material-ui/core/styles' -import { Typography, Box } from '@material-ui/core' +import { Theme } from '@mui/material/styles' +import createStyles from '@mui/styles/createStyles' +import makeStyles from '@mui/styles/makeStyles' +import { Typography, Box } from '@mui/material' import * as Types from './types' diff --git a/src/components/legend/WorldRegionMap.tsx b/src/components/legend/WorldRegionMap.tsx index ce2eb0a9..7c9410a4 100644 --- a/src/components/legend/WorldRegionMap.tsx +++ b/src/components/legend/WorldRegionMap.tsx @@ -1,6 +1,9 @@ import React, { FC, useState } from 'react' -import { Button } from '@material-ui/core' -import { createStyles, makeStyles, Theme } from '@material-ui/core/styles' +import { Button } from '@mui/material' +import { Theme } from '@mui/material/styles' + +import createStyles from '@mui/styles/createStyles' +import makeStyles from '@mui/styles/makeStyles' import { ToggleableSection, Explanation } from 'components/generic' diff --git a/src/components/legend/config.ts b/src/components/legend/config.ts index 8441b0ff..e8f83a9c 100644 --- a/src/components/legend/config.ts +++ b/src/components/legend/config.ts @@ -1,4 +1,4 @@ -import { OutlinedTextFieldProps } from '@material-ui/core' +import { OutlinedTextFieldProps } from '@mui/material' import { InstanceLevelSchema } from 'components/context/types' import { AtSymbFields } from './types' diff --git a/src/components/local/CensusAutoZoomToggle.tsx b/src/components/local/CensusAutoZoomToggle.tsx index 3d4be75d..d55171b8 100644 --- a/src/components/local/CensusAutoZoomToggle.tsx +++ b/src/components/local/CensusAutoZoomToggle.tsx @@ -1,5 +1,5 @@ import React, { FC } from 'react' -import { Switch } from '@material-ui/core' +import { Switch } from '@mui/material' import { CustomFormControl } from 'components/legend' import { useMapToolsDispatch, useMapToolsState } from 'components/context' diff --git a/src/components/local/CensusFieldSelect.tsx b/src/components/local/CensusFieldSelect.tsx index 3f7e298a..7fe9ad92 100644 --- a/src/components/local/CensusFieldSelect.tsx +++ b/src/components/local/CensusFieldSelect.tsx @@ -1,10 +1,12 @@ import React, { FC } from 'react' import { useHistory } from 'react-router-dom' -import { createStyles, makeStyles, Theme } from '@material-ui/core/styles' -import { TextField, Typography, ListSubheader } from '@material-ui/core' +import { Theme } from '@mui/material/styles' +import createStyles from '@mui/styles/createStyles' +import makeStyles from '@mui/styles/makeStyles' +import { TextField, Typography, ListSubheader } from '@mui/material' import Autocomplete, { AutocompleteRenderGroupParams, -} from '@material-ui/lab/Autocomplete' +} from '@mui/material/Autocomplete' import { useMapToolsDispatch, useMapToolsState } from 'components/context' import { UItextFromAirtable, useUItext } from 'components/generic' @@ -42,7 +44,7 @@ const useStyles = makeStyles((theme: Theme) => }, listbox: { paddingTop: 0, - [theme.breakpoints.down('sm')]: { + [theme.breakpoints.down('md')]: { maxHeight: 225, // maybe helps prevent unwanted upward-opening menu? }, }, diff --git a/src/components/local/CensusTogglesWrap.tsx b/src/components/local/CensusTogglesWrap.tsx index d35beea9..cfa0d67d 100644 --- a/src/components/local/CensusTogglesWrap.tsx +++ b/src/components/local/CensusTogglesWrap.tsx @@ -1,5 +1,8 @@ import React, { FC } from 'react' -import { makeStyles, Theme, createStyles } from '@material-ui/core/styles' +import { Theme } from '@mui/material/styles' + +import makeStyles from '@mui/styles/makeStyles' +import createStyles from '@mui/styles/createStyles' import { AllLangDataToggle } from 'components/legend' import { CensusAutoZoomToggle } from './CensusAutoZoomToggle' @@ -14,7 +17,7 @@ const useStyles = makeStyles((theme: Theme) => marginBottom: '0.75rem', paddingBottom: '0.5rem', borderBottom: `solid 1px ${theme.palette.divider}`, - [theme.breakpoints.down('sm')]: { + [theme.breakpoints.down('md')]: { gridColumnGap: 2, }, }, diff --git a/src/components/local/LegendGradient.tsx b/src/components/local/LegendGradient.tsx index d1eb980c..2c964bdf 100644 --- a/src/components/local/LegendGradient.tsx +++ b/src/components/local/LegendGradient.tsx @@ -1,5 +1,8 @@ import React, { FC } from 'react' -import { makeStyles, Theme, createStyles } from '@material-ui/core/styles' +import { Theme } from '@mui/material/styles' + +import makeStyles from '@mui/styles/makeStyles' +import createStyles from '@mui/styles/createStyles' import { useMapToolsState } from 'components/context' import { LegendBarProps, LegendMarkersProps } from './types' diff --git a/src/components/map/BaseLayerToggles.tsx b/src/components/map/BaseLayerToggles.tsx index cbcaa56b..ddce5872 100644 --- a/src/components/map/BaseLayerToggles.tsx +++ b/src/components/map/BaseLayerToggles.tsx @@ -1,7 +1,9 @@ import React, { FC } from 'react' import { isMobile } from 'react-device-detect' -import { createStyles, makeStyles, Theme } from '@material-ui/core/styles' -import { ToggleButton, ToggleButtonGroup } from '@material-ui/lab' +import { Theme } from '@mui/material/styles' +import createStyles from '@mui/styles/createStyles' +import makeStyles from '@mui/styles/makeStyles' +import { ToggleButton, ToggleButtonGroup } from '@mui/material' import { FiSun, FiMoon } from 'react-icons/fi' import { RiEyeCloseLine } from 'react-icons/ri' @@ -82,7 +84,6 @@ export const BaseLayerToggles: FC = (props) => { > diff --git a/src/components/map/GeocodeMarker.tsx b/src/components/map/GeocodeMarker.tsx index 08153dfb..282cddef 100644 --- a/src/components/map/GeocodeMarker.tsx +++ b/src/components/map/GeocodeMarker.tsx @@ -1,7 +1,9 @@ import React, { FC } from 'react' import { Marker } from 'react-map-gl' -import { createStyles, makeStyles, Theme } from '@material-ui/core/styles' -import { Typography } from '@material-ui/core' +import { Theme } from '@mui/material/styles' +import createStyles from '@mui/styles/createStyles' +import makeStyles from '@mui/styles/makeStyles' +import { Typography } from '@mui/material' import * as MapTypes from './types' diff --git a/src/components/map/GeocoderPopout.tsx b/src/components/map/GeocoderPopout.tsx index c003f790..0e3e8e74 100644 --- a/src/components/map/GeocoderPopout.tsx +++ b/src/components/map/GeocoderPopout.tsx @@ -2,7 +2,10 @@ import React, { FC, useRef } from 'react' import { Map } from 'mapbox-gl' import Geocoder from 'react-map-gl-geocoder' -import { createStyles, makeStyles, Theme } from '@material-ui/core' +import { Theme } from '@mui/material' + +import createStyles from '@mui/styles/createStyles' +import makeStyles from '@mui/styles/makeStyles' import 'react-map-gl-geocoder/dist/mapbox-gl-geocoder.css' diff --git a/src/components/map/MapCtrlBtns.tsx b/src/components/map/MapCtrlBtns.tsx index dfba9b05..5094c3de 100644 --- a/src/components/map/MapCtrlBtns.tsx +++ b/src/components/map/MapCtrlBtns.tsx @@ -1,6 +1,8 @@ import React, { FC, useState } from 'react' -import { makeStyles, createStyles, Theme } from '@material-ui/core/styles' -import { SpeedDial, SpeedDialAction } from '@material-ui/lab' +import { Theme } from '@mui/material/styles' +import makeStyles from '@mui/styles/makeStyles' +import createStyles from '@mui/styles/createStyles' +import { SpeedDial, SpeedDialAction } from '@mui/material' import { MdYoutubeSearchedFor } from 'react-icons/md' import { FiLayers } from 'react-icons/fi' import { FaSearchPlus, FaSearchMinus } from 'react-icons/fa' @@ -14,7 +16,7 @@ const useStyles = makeStyles((theme: Theme) => '& svg': { fontSize: '1.25rem', }, - [theme.breakpoints.down('sm')]: { + [theme.breakpoints.down('md')]: { position: 'absolute', right: '0.5rem', top: -4, // deals w/padding on btn root diff --git a/src/components/map/MapOptionsMenu.tsx b/src/components/map/MapOptionsMenu.tsx index ae1eceb6..3211bdc1 100644 --- a/src/components/map/MapOptionsMenu.tsx +++ b/src/components/map/MapOptionsMenu.tsx @@ -1,7 +1,9 @@ import React, { FC } from 'react' import { Link as RouterLink } from 'react-router-dom' -import { makeStyles, createStyles, Theme } from '@material-ui/core/styles' -import { Button, Popover, Typography } from '@material-ui/core' +import { Theme } from '@mui/material/styles' +import makeStyles from '@mui/styles/makeStyles' +import createStyles from '@mui/styles/createStyles' +import { Button, Popover, Typography } from '@mui/material' import { DialogCloseBtn } from 'components/generic/modals' import { useMapToolsState, useMapToolsDispatch } from 'components/context' diff --git a/src/components/map/MapPopup.tsx b/src/components/map/MapPopup.tsx index bccedafb..0aa15c45 100644 --- a/src/components/map/MapPopup.tsx +++ b/src/components/map/MapPopup.tsx @@ -1,8 +1,10 @@ import React, { FC } from 'react' import { Route, useParams, Switch } from 'react-router-dom' import { Popup } from 'react-map-gl' -import { createStyles, makeStyles, Theme } from '@material-ui/core/styles' -import { Typography } from '@material-ui/core' +import { Theme } from '@mui/material/styles' +import createStyles from '@mui/styles/createStyles' +import makeStyles from '@mui/styles/makeStyles' +import { Typography } from '@mui/material' import { InstanceLevelSchema, useMapToolsState } from 'components/context' import { useAirtable } from 'components/explore/hooks' @@ -26,7 +28,7 @@ const useStyles = makeStyles((theme: Theme) => wordWrap: 'break-word', '& .mapboxgl-popup-content': { // Leave room for "x" close button - padding: `${theme.spacing(1)}px ${theme.spacing(3)}px`, + padding: `${theme.spacing(1)} ${theme.spacing(3)}`, }, '& .mapboxgl-popup-close-button': { fontSize: '1.25rem', diff --git a/src/components/media/Media.tsx b/src/components/media/Media.tsx index cbbe6986..5c1c466b 100644 --- a/src/components/media/Media.tsx +++ b/src/components/media/Media.tsx @@ -1,7 +1,9 @@ import React, { FC, useState } from 'react' import { useHistory, useRouteMatch } from 'react-router-dom' -import { createStyles, makeStyles, Theme } from '@material-ui/core/styles' -import { Button } from '@material-ui/core' +import { Theme } from '@mui/material/styles' +import createStyles from '@mui/styles/createStyles' +import makeStyles from '@mui/styles/makeStyles' +import { Button } from '@mui/material' import { FiVideo, FiShare } from 'react-icons/fi' import { AiOutlineSound } from 'react-icons/ai' import { IoIosCloseCircleOutline } from 'react-icons/io' diff --git a/src/components/media/MediaModal.tsx b/src/components/media/MediaModal.tsx index 256569c6..d14ab864 100644 --- a/src/components/media/MediaModal.tsx +++ b/src/components/media/MediaModal.tsx @@ -1,13 +1,10 @@ import React, { FC } from 'react' import * as Sentry from '@sentry/react' import { useQuery, QueryCache, ReactQueryCacheProvider } from 'react-query' -import { createStyles, makeStyles, Theme } from '@material-ui/core/styles' -import { - Container, - Button, - Typography, - CircularProgress, -} from '@material-ui/core' +import { Theme } from '@mui/material/styles' +import createStyles from '@mui/styles/createStyles' +import makeStyles from '@mui/styles/makeStyles' +import { Container, Button, Typography, CircularProgress } from '@mui/material' import { SimpleDialog } from 'components/generic/modals' import { MediaModalProps, ModalContentProps, APIresponse } from './types' @@ -31,7 +28,7 @@ const useStyles = makeStyles((theme: Theme) => dialogContent: { marginTop: '1rem', marginBottom: '1rem', - [theme.breakpoints.down('sm')]: { + [theme.breakpoints.down('md')]: { padding: 0, }, }, diff --git a/src/components/nav/AboutLinkAsIcon.tsx b/src/components/nav/AboutLinkAsIcon.tsx index 67659edf..e3f138d9 100644 --- a/src/components/nav/AboutLinkAsIcon.tsx +++ b/src/components/nav/AboutLinkAsIcon.tsx @@ -1,6 +1,6 @@ import React, { FC } from 'react' import { useHistory } from 'react-router-dom' -import { IconButton } from '@material-ui/core' +import { IconButton } from '@mui/material' import { GoInfo } from 'react-icons/go' type ListItemLinkProps = { @@ -21,6 +21,7 @@ export const AboutLinkAsIcon: FC = ({ className={muiClass} edge="end" onClick={() => history.push(to)} + size="large" > diff --git a/src/components/nav/BottomNav.tsx b/src/components/nav/BottomNav.tsx index 8b0c13d7..ce42a848 100644 --- a/src/components/nav/BottomNav.tsx +++ b/src/components/nav/BottomNav.tsx @@ -1,13 +1,10 @@ import React, { FC, useEffect, useState } from 'react' import { isMobile } from 'react-device-detect' import { NavLink, useLocation } from 'react-router-dom' -import { - createStyles, - makeStyles, - Theme, - lighten, -} from '@material-ui/core/styles' -import { BottomNavigation, BottomNavigationAction } from '@material-ui/core' +import { Theme, lighten } from '@mui/material/styles' +import createStyles from '@mui/styles/createStyles' +import makeStyles from '@mui/styles/makeStyles' +import { BottomNavigation, BottomNavigationAction } from '@mui/material' import { usePanelState, usePanelDispatch } from 'components/panels' import { routes } from 'components/config/api' @@ -33,7 +30,7 @@ radial-gradient(ellipse at bottom, ${theme.palette.primary.dark}, transparent)` width: '100%', position: 'absolute', bottom: 0, - [theme.breakpoints.down('md')]: { + [theme.breakpoints.down('lg')]: { boxShadow: '0px -5px 5px 0px rgba(0,0,0,0.1)', borderRadius: 0, height: BOTTOM_NAV_HEIGHT_MOBILE, @@ -65,7 +62,7 @@ radial-gradient(ellipse at bottom, ${theme.palette.primary.dark}, transparent)` }, wrapper: { fontSize: '0.85rem', - [theme.breakpoints.down('sm')]: { + [theme.breakpoints.down('md')]: { fontSize: '0.75rem', }, }, @@ -73,7 +70,7 @@ radial-gradient(ellipse at bottom, ${theme.palette.primary.dark}, transparent)` '& .Mui-selected': { fontSize: 'inherit', // from the wrapper class }, - [theme.breakpoints.down('sm')]: { + [theme.breakpoints.down('md')]: { fontSize: '0.75rem', }, }, @@ -96,7 +93,7 @@ const initialSubRoutes = { export const BottomNav: FC = (props) => { const { pathname } = useLocation() const classes = useStyles() - const { bottomNavActionRoot, selected, label, wrapper } = classes + const { bottomNavActionRoot, selected } = classes const { panelOpen } = usePanelState() const panelDispatch = usePanelDispatch() const [subRoutePath, setSubRoutePath] = useState( @@ -152,7 +149,7 @@ export const BottomNav: FC = (props) => { // @ts-ignore const handleClick = ( to: string, - e?: React.MouseEventHandler + e?: React.MouseEvent ) => { // Avoid route changes if we just want to open/close the panel if (pathname.includes(to)) { @@ -183,10 +180,10 @@ export const BottomNav: FC = (props) => { value={subRouteStateKey} to={to} showLabel - classes={{ root: bottomNavActionRoot, selected, label, wrapper }} + classes={{ root: bottomNavActionRoot, selected }} // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore - onClick={(e: React.MouseEventHandler) => { + onClick={(e) => { handleClick(to, e) }} /> diff --git a/src/components/nav/Nav.tsx b/src/components/nav/Nav.tsx index 90e87d9a..bfac7a1f 100644 --- a/src/components/nav/Nav.tsx +++ b/src/components/nav/Nav.tsx @@ -1,6 +1,8 @@ import React, { FC } from 'react' import { Link as RouterLink } from 'react-router-dom' -import { createStyles, makeStyles, Theme } from '@material-ui/core/styles' +import { Theme } from '@mui/material/styles' +import createStyles from '@mui/styles/createStyles' +import makeStyles from '@mui/styles/makeStyles' import { Divider, Link, @@ -8,7 +10,7 @@ import { ListItem, ListItemIcon, ListItemText, -} from '@material-ui/core' +} from '@mui/material' import { routes, icons } from 'components/config' import { UItextFromAirtable } from 'components/generic' diff --git a/src/components/nav/OffCanvasNav.tsx b/src/components/nav/OffCanvasNav.tsx index 7a261923..9e341050 100644 --- a/src/components/nav/OffCanvasNav.tsx +++ b/src/components/nav/OffCanvasNav.tsx @@ -1,6 +1,8 @@ import React, { FC, useState } from 'react' -import { createStyles, makeStyles, Theme } from '@material-ui/core/styles' -import { Drawer } from '@material-ui/core' +import { Theme } from '@mui/material/styles' +import createStyles from '@mui/styles/createStyles' +import makeStyles from '@mui/styles/makeStyles' +import { Drawer } from '@mui/material' import { Nav } from 'components/nav' import { SimpleDialog } from 'components/generic/modals' diff --git a/src/components/nav/Settings.tsx b/src/components/nav/Settings.tsx index c305e74a..4cdb05cc 100644 --- a/src/components/nav/Settings.tsx +++ b/src/components/nav/Settings.tsx @@ -1,6 +1,8 @@ import React, { FC, useState } from 'react' -import { createStyles, makeStyles, Theme } from '@material-ui/core/styles' -import { FormControlLabel, Switch, Typography } from '@material-ui/core' +import { Theme } from '@mui/material/styles' +import createStyles from '@mui/styles/createStyles' +import makeStyles from '@mui/styles/makeStyles' +import { FormControlLabel, Switch, Typography } from '@mui/material' import { FiShare } from 'react-icons/fi' import { GoGear } from 'react-icons/go' diff --git a/src/components/nav/TopBar.test.tsx b/src/components/nav/TopBar.test.tsx index 34624c3f..3a0cebca 100644 --- a/src/components/nav/TopBar.test.tsx +++ b/src/components/nav/TopBar.test.tsx @@ -7,9 +7,9 @@ import { TopBar } from 'components/nav' // Hoist helper functions (but not vars) to reuse between test cases const renderTopBar = () => ( // Only needed because there are components - + ( - + ) ) describe('Formerly testing off-canvas behavhior', () => { diff --git a/src/components/nav/TopBar.tsx b/src/components/nav/TopBar.tsx index 3dcc49a2..7a5156ac 100644 --- a/src/components/nav/TopBar.tsx +++ b/src/components/nav/TopBar.tsx @@ -1,5 +1,7 @@ import React, { FC } from 'react' -import { createStyles, makeStyles, Theme } from '@material-ui/core/styles' +import { Theme } from '@mui/material/styles' +import createStyles from '@mui/styles/createStyles' +import makeStyles from '@mui/styles/makeStyles' import { Link as RouteLink } from 'react-router-dom' import { routes } from 'components/config/api' @@ -25,7 +27,7 @@ const useStyles = makeStyles((theme: Theme) => [theme.breakpoints.up('xl')]: { top: '0.75rem', }, - [theme.breakpoints.down('sm')]: { + [theme.breakpoints.down('md')]: { display: 'none', }, }, diff --git a/src/components/panels/NavItemWithBadge.tsx b/src/components/panels/NavItemWithBadge.tsx index 665ff292..b4f450f7 100644 --- a/src/components/panels/NavItemWithBadge.tsx +++ b/src/components/panels/NavItemWithBadge.tsx @@ -1,6 +1,8 @@ import React, { FC, useContext } from 'react' -import { createStyles, makeStyles, Theme } from '@material-ui/core/styles' -import { Badge } from '@material-ui/core' +import { Theme } from '@mui/material/styles' +import createStyles from '@mui/styles/createStyles' +import makeStyles from '@mui/styles/makeStyles' +import { Badge } from '@mui/material' import { GlobalContext } from 'components/context' @@ -24,7 +26,7 @@ export const NavItemWithBadge: FC = (props) => { classes={{ dot: classes.badgeRoot }} badgeContent="" color="secondary" - overlap="circle" + overlap="circular" anchorOrigin={{ vertical: 'top', horizontal: 'left' }} invisible={state.langFeatsLenCache === state.langFeatures.length} > diff --git a/src/components/panels/PanelCloseBtn.tsx b/src/components/panels/PanelCloseBtn.tsx index f3220fa1..7baac9cc 100644 --- a/src/components/panels/PanelCloseBtn.tsx +++ b/src/components/panels/PanelCloseBtn.tsx @@ -1,6 +1,8 @@ import React, { FC } from 'react' -import { createStyles, makeStyles, Theme } from '@material-ui/core/styles' -import { IconButton, Tooltip } from '@material-ui/core' +import { Theme } from '@mui/material/styles' +import createStyles from '@mui/styles/createStyles' +import makeStyles from '@mui/styles/makeStyles' +import { IconButton, Tooltip } from '@mui/material' import { CgClose } from 'react-icons/cg' import { usePanelDispatch } from 'components/panels' diff --git a/src/components/panels/PanelHeading.tsx b/src/components/panels/PanelHeading.tsx index 70142000..ca9a2c44 100644 --- a/src/components/panels/PanelHeading.tsx +++ b/src/components/panels/PanelHeading.tsx @@ -1,6 +1,8 @@ import React, { FC } from 'react' -import { createStyles, makeStyles, Theme } from '@material-ui/core/styles' -import { Typography } from '@material-ui/core' +import { Theme } from '@mui/material/styles' +import createStyles from '@mui/styles/createStyles' +import makeStyles from '@mui/styles/makeStyles' +import { Typography } from '@mui/material' type PanelHeadingProps = { text: string diff --git a/src/components/panels/PanelTitleBar.tsx b/src/components/panels/PanelTitleBar.tsx index 87a29100..bf52f776 100644 --- a/src/components/panels/PanelTitleBar.tsx +++ b/src/components/panels/PanelTitleBar.tsx @@ -1,6 +1,8 @@ import React, { FC, useState } from 'react' import { useLocation, Route, Switch } from 'react-router-dom' -import { makeStyles, Theme, createStyles } from '@material-ui/core/styles' +import { Theme } from '@mui/material/styles' +import makeStyles from '@mui/styles/makeStyles' +import createStyles from '@mui/styles/createStyles' import { Popover, AppBar, @@ -8,7 +10,7 @@ import { IconButton, Toolbar, Tooltip, -} from '@material-ui/core' +} from '@mui/material' import { HiOutlineSearch } from 'react-icons/hi' import { PanelCloseBtn } from 'components/panels' @@ -27,7 +29,7 @@ const useStyles = makeStyles((theme: Theme) => top: 0, width: '100%', boxShadow: theme.shadows[12], - [theme.breakpoints.down('sm')]: { + [theme.breakpoints.down('md')]: { boxShadow: '0px 11px 10px 0px rgb(0 0 0 / 18%), 0px 24px 38px 3px rgb(0 0 0 / 12%), 0px 9px 46px 8px rgb(0 0 0 / 10%)', }, @@ -122,7 +124,7 @@ export const PanelTitleBar: FC = (props) => { {mapRef && } - + diff --git a/src/components/panels/PanelTitleRoutes.tsx b/src/components/panels/PanelTitleRoutes.tsx index 65cc8b37..afb1a264 100644 --- a/src/components/panels/PanelTitleRoutes.tsx +++ b/src/components/panels/PanelTitleRoutes.tsx @@ -1,7 +1,9 @@ import React, { FC } from 'react' import { Route, Switch, Link as RouterLink } from 'react-router-dom' -import { makeStyles, Theme, createStyles } from '@material-ui/core/styles' -import { IconButton, Typography, Tooltip, Hidden } from '@material-ui/core' +import { Theme } from '@mui/material/styles' +import makeStyles from '@mui/styles/makeStyles' +import createStyles from '@mui/styles/createStyles' +import { IconButton, Typography, Tooltip, Hidden } from '@mui/material' import { icons } from 'components/config' import { routes } from 'components/config/api' @@ -19,7 +21,7 @@ const useStyles = makeStyles((theme: Theme) => alignItems: 'center', display: 'flex', '& > svg': { - color: theme.palette.text.hint, + color: theme.palette.text.disabled, marginRight: 6, }, }, @@ -87,7 +89,7 @@ export const PanelTitleRoutes: FC<{ panelTitle: string }> = (props) => {
    - + diff --git a/src/components/panels/PanelWrap.tsx b/src/components/panels/PanelWrap.tsx index 5e24e93c..953edf53 100644 --- a/src/components/panels/PanelWrap.tsx +++ b/src/components/panels/PanelWrap.tsx @@ -1,7 +1,9 @@ import React, { FC, useRef } from 'react' import { Route, Switch, useLocation } from 'react-router-dom' -import { createStyles, makeStyles, Theme } from '@material-ui/core/styles' -import { Hidden } from '@material-ui/core' +import { Theme } from '@mui/material/styles' +import createStyles from '@mui/styles/createStyles' +import makeStyles from '@mui/styles/makeStyles' +import { Hidden } from '@mui/material' import { SearchTabs, @@ -47,7 +49,7 @@ const useStyles = makeStyles((theme: Theme) => [theme.breakpoints.up('xl')]: { width: panelWidths.midLarge, }, - [theme.breakpoints.down('sm')]: { + [theme.breakpoints.down('md')]: { width: '100%', borderTop: `solid 6px ${theme.palette.primary.dark}`, bottom: BOTTOM_NAV_HEIGHT_MOBILE, @@ -75,7 +77,7 @@ const useStyles = makeStyles((theme: Theme) => [theme.breakpoints.up('md')]: { padding: '1.5rem 1.25rem', }, - [theme.breakpoints.down('sm')]: { + [theme.breakpoints.down('md')]: { bottom: 0, top: 0, opacity: (props: Style) => (props.open ? 1 : 0), @@ -90,8 +92,6 @@ const useStyles = makeStyles((theme: Theme) => }) ) -// WISHLIST: consider swipeable views for moving between panels: -// https://react-swipeable-views.com/demos/demos/ export const PanelWrap: FC = (props) => { const { mapRef } = props const { panelOpen } = usePanelState() @@ -105,7 +105,7 @@ export const PanelWrap: FC = (props) => { return (
    - + @@ -131,7 +131,7 @@ export const PanelWrap: FC = (props) => {
    - +
    diff --git a/src/components/panels/SearchTabs.tsx b/src/components/panels/SearchTabs.tsx index 42ec2761..f1aca0a1 100755 --- a/src/components/panels/SearchTabs.tsx +++ b/src/components/panels/SearchTabs.tsx @@ -1,14 +1,9 @@ import React, { FC, useState } from 'react' -import SwipeableViews from 'react-swipeable-views' -import AppBar from '@material-ui/core/AppBar' -import { - createStyles, - makeStyles, - Tab, - Tabs, - Theme, - useTheme, -} from '@material-ui/core' +import AppBar from '@mui/material/AppBar' +import { Tab, Tabs, Theme } from '@mui/material' + +import createStyles from '@mui/styles/createStyles' +import makeStyles from '@mui/styles/makeStyles' import { SearchByOmnibox } from 'components/home/SearchByOmnibox' import { GeocoderPopout } from 'components/map' @@ -63,7 +58,6 @@ const QuickFlex: FC<{ uiTextID: UItextTableID }> = (props) => { export const SearchTabs: FC = (props) => { const { mapRef } = props const classes = useStyles() - const theme = useTheme() const [value, setValue] = useState(0) const handleChange = ( @@ -73,10 +67,6 @@ export const SearchTabs: FC = (props) => { setValue(newValue) } - const handleChangeIndex = (index: number) => { - setValue(index) - } - const TabAppBar = ( = (props) => { ) const TabMeat = ( - + <> @@ -119,7 +105,7 @@ export const SearchTabs: FC = (props) => { - + ) return ( diff --git a/src/components/panels/ShowPanelBtn.tsx b/src/components/panels/ShowPanelBtn.tsx index 51c9ed43..4ae594c7 100644 --- a/src/components/panels/ShowPanelBtn.tsx +++ b/src/components/panels/ShowPanelBtn.tsx @@ -1,7 +1,9 @@ import React, { FC } from 'react' -import { makeStyles, Theme, createStyles } from '@material-ui/core/styles' +import { Theme } from '@mui/material/styles' +import makeStyles from '@mui/styles/makeStyles' +import createStyles from '@mui/styles/createStyles' import { usePanelDispatch } from 'components/panels' -import { Tooltip, Zoom, Fab } from '@material-ui/core' +import { Tooltip, Zoom, Fab } from '@mui/material' import { MdKeyboardArrowRight } from 'react-icons/md' const useStyles = makeStyles((theme: Theme) => @@ -11,13 +13,11 @@ const useStyles = makeStyles((theme: Theme) => top: '1rem', left: '1rem', zIndex: 1, - [theme.breakpoints.down('sm')]: { + fontSize: '1.5rem', + [theme.breakpoints.down('md')]: { display: 'none', // TODO: think it through }, }, - label: { - fontSize: '1.5rem', - }, }) ) @@ -38,8 +38,8 @@ export const ShowPanelBtn: FC<{ panelOpen: boolean }> = (props) => { size="small" aria-label="panel open" color="secondary" - variant="round" - classes={{ root: classes.root, label: classes.label }} + variant="circular" + classes={{ root: classes.root }} onClick={handleClick} > diff --git a/src/components/panels/SplitCrumbs.tsx b/src/components/panels/SplitCrumbs.tsx index 74540b3d..e789f065 100644 --- a/src/components/panels/SplitCrumbs.tsx +++ b/src/components/panels/SplitCrumbs.tsx @@ -1,8 +1,10 @@ // TODO: rename file and component to "BackBtn" import React, { FC, useEffect } from 'react' import { Link as RouterLink, useLocation } from 'react-router-dom' -import { makeStyles, Theme, createStyles } from '@material-ui/core/styles' -import { IconButton, Popover, Tooltip } from '@material-ui/core' +import { Theme } from '@mui/material/styles' +import makeStyles from '@mui/styles/makeStyles' +import createStyles from '@mui/styles/createStyles' +import { IconButton, Popover, Tooltip } from '@mui/material' import { AiOutlineUnorderedList } from 'react-icons/ai' import { BsArrow90DegUp } from 'react-icons/bs' diff --git a/src/components/panels/TabPanel.tsx b/src/components/panels/TabPanel.tsx index af2550ca..f7cc180c 100644 --- a/src/components/panels/TabPanel.tsx +++ b/src/components/panels/TabPanel.tsx @@ -1,5 +1,8 @@ import React, { FC } from 'react' -import { createStyles, makeStyles, Theme } from '@material-ui/core' +import { Theme } from '@mui/material' + +import createStyles from '@mui/styles/createStyles' +import makeStyles from '@mui/styles/makeStyles' import { TabPanelProps } from './types' @@ -10,7 +13,7 @@ const useStyles = makeStyles((theme: Theme) => { root: { padding: '1rem', borderBottom: `solid 1px ${palette.divider}`, - [theme.breakpoints.down('sm')]: { + [theme.breakpoints.down('md')]: { padding: '0.75rem 0.5rem', }, }, diff --git a/src/components/panels/TimelineCrumbs.tsx b/src/components/panels/TimelineCrumbs.tsx index 6b5c1327..0657dfca 100644 --- a/src/components/panels/TimelineCrumbs.tsx +++ b/src/components/panels/TimelineCrumbs.tsx @@ -1,6 +1,8 @@ import React, { FC } from 'react' import { Link as RouterLink, Route, Switch } from 'react-router-dom' -import { makeStyles, Theme, createStyles } from '@material-ui/core/styles' +import { Theme } from '@mui/material/styles' +import makeStyles from '@mui/styles/makeStyles' +import createStyles from '@mui/styles/createStyles' import { Timeline, TimelineItem, @@ -8,7 +10,7 @@ import { TimelineConnector, TimelineContent, TimelineDot, -} from '@material-ui/lab' +} from '@mui/lab' import { RouteableTableNames } from 'components/context/types' import { icons } from 'components/config' @@ -59,7 +61,7 @@ export const TimelineCrumbs: FC = (props) => { {panelIcon} diff --git a/src/components/results/Cells.tsx b/src/components/results/Cells.tsx index b302ac23..82805cec 100644 --- a/src/components/results/Cells.tsx +++ b/src/components/results/Cells.tsx @@ -1,16 +1,13 @@ import React, { FC } from 'react' -import { - makeStyles, - createStyles, - useTheme, - Theme, -} from '@material-ui/core/styles' +import { useTheme, Theme } from '@mui/material/styles' +import makeStyles from '@mui/styles/makeStyles' +import createStyles from '@mui/styles/createStyles' import { MdCheck } from 'react-icons/md' import { GoCircleSlash } from 'react-icons/go' import { LegendSwatch } from 'components/legend' import { InstanceLevelSchema } from 'components/context/types' -import { CellProps, MediaColumnCellProps } from './types' +import { LangCellContext } from './types' const useStyles = makeStyles((theme: Theme) => createStyles({ @@ -20,9 +17,13 @@ const useStyles = makeStyles((theme: Theme) => }) ) -export const MediaColumnCell: FC = (props) => { +export const MediaColumnCell: FC<{ + info: LangCellContext + columnName: keyof InstanceLevelSchema +}> = (props) => { const classes = useStyles() - const { data, columnName } = props + const { info, columnName } = props + const data = info.row.original return (
    @@ -31,32 +32,32 @@ export const MediaColumnCell: FC = (props) => { ) } -export const GlobalSpeakers: FC = (props) => { +export const GlobalSpeakers: FC<{ info: LangCellContext }> = (props) => { const classes = useStyles() - const { data } = props + const { info } = props + const data = info.row.original if (!data['Global Speaker Total']) return null return ( - // Right-aligned number w/left-aligned column heading was requested
    {data['Global Speaker Total'].toLocaleString()}
    ) } -export const CommStatus: FC = (props) => { +export const CommStatus: FC<{ info: LangCellContext }> = (props) => { const classes = useStyles() - const { data } = props + const { info } = props + const data = info.row.original return
    {data.Status}
    } -export const CommSize: FC<{ - data: InstanceLevelSchema -}> = (props) => { +export const CommSize: FC<{ info: LangCellContext }> = (props) => { const theme = useTheme() - const { data } = props + const { info } = props + const data = info.row.original const { Size, sizeColor } = data return ( @@ -75,8 +76,9 @@ export const CommSize: FC<{ ) } -export const WorldRegion: FC = (props) => { - const { data } = props +export const WorldRegion: FC<{ info: LangCellContext }> = (props) => { + const { info } = props + const data = info.row.original return ( alignItems: 'center', display: 'grid', gridColumnGap: theme.spacing(1), - gridTemplateColumns: `${theme.spacing(3)}px auto`, + gridTemplateColumns: `${theme.spacing(3)} auto`, gridTemplateRows: 'auto', lineHeight: 1, // proper vertical align (all good except super-long Congo) '& + li': { diff --git a/src/components/results/EndoImageModal.tsx b/src/components/results/EndoImageModal.tsx index 9e0a2758..3a64ba3d 100644 --- a/src/components/results/EndoImageModal.tsx +++ b/src/components/results/EndoImageModal.tsx @@ -1,6 +1,8 @@ import React, { FC, useState } from 'react' -import { createStyles, makeStyles, Theme } from '@material-ui/core/styles' -import { Button, Typography } from '@material-ui/core' +import { Theme } from '@mui/material/styles' +import createStyles from '@mui/styles/createStyles' +import makeStyles from '@mui/styles/makeStyles' +import { Button, Typography } from '@mui/material' import { SimpleDialog } from 'components/generic/modals' import { correctDropboxURL } from '../../utils' @@ -23,7 +25,7 @@ const useStyles = makeStyles((theme: Theme) => }, // Smaller than the default so that it is not as large as table modal endoModalPaper: { - margin: `${theme.spacing(4)}px ${theme.spacing(3)}px`, + margin: `${theme.spacing(4)} ${theme.spacing(3)}`, }, image: { height: 'auto', diff --git a/src/components/results/LocalColumnTitle.tsx b/src/components/results/LocalColumnTitle.tsx index c6944a44..5fb20ecd 100644 --- a/src/components/results/LocalColumnTitle.tsx +++ b/src/components/results/LocalColumnTitle.tsx @@ -1,13 +1,22 @@ import React, { FC } from 'react' +import { Theme } from '@mui/material/styles' +import createStyles from '@mui/styles/createStyles' +import makeStyles from '@mui/styles/makeStyles' import { BiMapPin } from 'react-icons/bi' -import { useStyles } from './ResultsToolbar' - -// TODO: could be a better icon: MdPersonPinCircle +const useLocalIndicatorStyles = makeStyles((theme: Theme) => + createStyles({ + localIndicator: { + display: 'flex', + alignItems: 'center', + '& svg': { color: theme.palette.secondary.light, marginRight: 4 }, + }, + }) +) export const LocalColumnTitle: FC<{ text: string }> = (props) => { const { text } = props - const classes = useStyles() + const classes = useLocalIndicatorStyles() return (
    diff --git a/src/components/results/MediaColumnFilter.tsx b/src/components/results/MediaColumnFilter.tsx index aeceb7bf..930e1260 100644 --- a/src/components/results/MediaColumnFilter.tsx +++ b/src/components/results/MediaColumnFilter.tsx @@ -1,47 +1,41 @@ import React, { FC } from 'react' -import { createStyles, makeStyles, Theme } from '@material-ui/core/styles' -import { FormControlLabel, Checkbox } from '@material-ui/core' - -import * as Types from './types' - -const CHECK_STRING = 'http' - -const useStyles = makeStyles((theme: Theme) => - createStyles({ - root: { - color: theme.palette.secondary.main, - marginLeft: 2, // shaaaaky - }, - }) -) - -// CRED: (partial anyway): -// https://github.com/mbrn/material-table/issues/671#issuecomment-651743451 -export const MediaColumnFilter: FC = (props) => { - const classes = useStyles() - const { columnDef, onFilterChanged } = props - const { tableData, field } = columnDef - const { filterValue } = tableData - const checked = filterValue === CHECK_STRING - const inputElemName = `${field?.replace(/\s/g, '-').toLowerCase()}-filter` - - // REFACTOR: useMemo maybe? This gets run for EVERY record, and it's the same - const handleChange = (e: React.ChangeEvent) => { - onFilterChanged(tableData.id, e.target.checked ? CHECK_STRING : '') +import { Checkbox } from '@mui/material' +import { Column } from '@tanstack/react-table' + +import { InstanceLevelSchema } from 'components/context/types' +import { LangFilterFn } from './types' + +const CHECK_VALUE = 'http' + +// TanStack column filter that matches rows whose value contains "http" +// (used for the Audio/Video URL columns). +export const mediaUrlFilterFn: LangFilterFn = (row, columnId, filterValue) => { + if (!filterValue) return true + + const value = row.getValue(columnId) + + if (!value) return false + if (typeof value === 'string') return value.includes(CHECK_VALUE) + if (Array.isArray(value)) { + return value.some((v) => typeof v === 'string' && v.includes(CHECK_VALUE)) } + return false +} + +export const MediaColumnFilter: FC<{ + column: Column +}> = ({ column }) => { + const checked = (column.getFilterValue() as boolean) || false + return ( - - } - label="" + column.setFilterValue(e.target.checked || undefined)} + sx={{ padding: 0.5 }} /> ) } diff --git a/src/components/results/RecordDescription.tsx b/src/components/results/RecordDescription.tsx index 9667cd36..85fa1c85 100644 --- a/src/components/results/RecordDescription.tsx +++ b/src/components/results/RecordDescription.tsx @@ -1,6 +1,8 @@ import React, { FC } from 'react' -import { createStyles, makeStyles, Theme } from '@material-ui/core/styles' -import { Typography } from '@material-ui/core' +import { Theme } from '@mui/material/styles' +import createStyles from '@mui/styles/createStyles' +import makeStyles from '@mui/styles/makeStyles' +import { Typography } from '@mui/material' import { MarkdownWithRouteLinks } from 'components/generic' import { isAlpha } from '../../utils' diff --git a/src/components/results/ResultsModal.tsx b/src/components/results/ResultsModal.tsx index 6190fe5f..000f01d8 100644 --- a/src/components/results/ResultsModal.tsx +++ b/src/components/results/ResultsModal.tsx @@ -1,6 +1,6 @@ import React, { FC, useContext, useEffect, useState } from 'react' import { useHistory, useLocation, useRouteMatch } from 'react-router-dom' -import { Dialog } from '@material-ui/core' +import { Dialog } from '@mui/material' import { DialogCloseBtn, SlideUp } from 'components/generic/modals' import { InstanceLevelSchema, GlobalContext } from 'components/context' diff --git a/src/components/results/ResultsTable.tsx b/src/components/results/ResultsTable.tsx index 8e629c39..4a27df0d 100644 --- a/src/components/results/ResultsTable.tsx +++ b/src/components/results/ResultsTable.tsx @@ -1,183 +1,423 @@ /* eslint-disable react/display-name */ -import React, { FC, useState } from 'react' +import React, { FC, useMemo, useRef, useState } from 'react' import { Route, useHistory } from 'react-router-dom' -import MaterialTable from 'material-table' +import { + Box, + MenuItem, + Select, + Table, + TableBody, + TableCell, + TableContainer, + TableHead, + TableRow, + TableSortLabel, + TextField, +} from '@mui/material' +import { Theme } from '@mui/material/styles' +import createStyles from '@mui/styles/createStyles' +import makeStyles from '@mui/styles/makeStyles' +import { + ColumnFiltersState, + ColumnOrderState, + SortingState, + VisibilityState, + flexRender, + getCoreRowModel, + getFilteredRowModel, + getPaginationRowModel, + getSortedRowModel, + useReactTable, +} from '@tanstack/react-table' import { routes } from 'components/config/api' -import { InstanceLevelSchema } from 'components/context' +import { InstanceLevelSchema } from 'components/context/types' import { DetailsModal } from './DetailsModal' -import { FILTER_CLASS } from './utils' import { ResultsToolbar } from './ResultsToolbar' -import { icons, options, columns as columnConfig, localization } from './config' -import { - ResultsTableProps, - ColumnWithTableData, - MuiTableWithLangs, -} from './types' +import { columns as columnConfig, initialColumnVisibility } from './config' +import { MediaColumnFilter } from './MediaColumnFilter' +import { LangColumnMeta, ResultsTableProps } from './types' + +const useStyles = makeStyles((theme: Theme) => + createStyles({ + container: { + display: 'flex', + flexDirection: 'column', + height: '100%', + width: '100%', + }, + tableScroll: { + flex: 1, + overflow: 'auto', + }, + table: { + borderCollapse: 'separate', + tableLayout: 'auto', + '& th, & td': { + verticalAlign: 'top', + }, + }, + headerRow: { + backgroundColor: theme.palette.background.paper, + }, + filterRow: { + backgroundColor: theme.palette.background.paper, + '& th': { + paddingTop: 4, + paddingBottom: 4, + }, + }, + bodyRow: { + cursor: 'pointer', + '&:hover': { backgroundColor: theme.palette.action.hover }, + }, + actionsCell: { + paddingLeft: 4, + paddingRight: 4, + width: 56, + }, + pagination: { + alignItems: 'center', + borderTop: `1px solid ${theme.palette.divider}`, + display: 'flex', + flexWrap: 'wrap', + gap: '0.75rem', + justifyContent: 'flex-end', + padding: '0.5rem 1rem', + }, + paginationBtn: { + background: 'transparent', + border: `1px solid ${theme.palette.divider}`, + borderRadius: 4, + color: theme.palette.text.primary, + cursor: 'pointer', + padding: '0.25rem 0.6rem', + '&:disabled': { + cursor: 'not-allowed', + opacity: 0.4, + }, + }, + }) +) + +const PAGE_SIZE_OPTIONS = [10, 20, 50] export const ResultsTable: FC = (props) => { const { data: tableData } = props + const classes = useStyles() const history = useHistory() - const tableRef = React.useRef(null) + const containerRef = useRef(null) const [clearBtnEnabled, setClearBtnEnabled] = useState(false) + const [globalFilter, setGlobalFilter] = useState('') + const [columnFilters, setColumnFilters] = useState([]) + const [sorting, setSorting] = useState([]) + const [columnVisibility, setColumnVisibility] = useState( + initialColumnVisibility + ) + const [columnOrder, setColumnOrder] = useState([]) - // Filter changes, etc. keep the table at its current vertical scroll, often - // at the bottom, which is super annoying. - function scrollToTop() { - if (!tableRef || !tableRef.current) return + const columns = useMemo(() => columnConfig, []) - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore // nooooooo thanks - const divRef = tableRef.current.tableContainerDiv + const table = useReactTable({ + data: tableData, + columns, + state: { + globalFilter, + columnFilters, + sorting, + columnVisibility, + columnOrder, + }, + onGlobalFilterChange: (updater) => { + setGlobalFilter( + typeof updater === 'function' ? updater(globalFilter) : updater + ) + setClearBtnEnabled(true) + }, + onColumnFiltersChange: (updater) => { + setColumnFilters((old) => + typeof updater === 'function' ? updater(old) : updater + ) + setClearBtnEnabled(true) + }, + onSortingChange: setSorting, + onColumnVisibilityChange: setColumnVisibility, + onColumnOrderChange: setColumnOrder, + getCoreRowModel: getCoreRowModel(), + getFilteredRowModel: getFilteredRowModel(), + getSortedRowModel: getSortedRowModel(), + getPaginationRowModel: getPaginationRowModel(), + initialState: { + pagination: { pageSize: 20 }, + }, + }) - if (divRef && divRef.current) divRef.current.scrollIntoView(true) + const scrollToTop = () => { + containerRef.current?.scrollTo({ top: 0 }) } - // REFACTOR: get this monster into utils or events or something - const onRowClick = ( - event: React.MouseEvent, - rowData: InstanceLevelSchema - ): void => { - if (!tableRef || !tableRef.current || !event || !rowData) return - - const self = tableRef.current - const { dataManager } = self - const { columns } = dataManager.getRenderState() - const path = event.nativeEvent.composedPath() // cross-platform - - const tdElem = path.find((elem) => { - const asElement = elem as HTMLTableCellElement + const visibleRows: InstanceLevelSchema[] = table + .getFilteredRowModel() + .rows.map((r) => r.original) - return asElement.nodeName === 'TD' - }) as HTMLTableCellElement - - // Events like closing the Endo img dialog will trigger the click but - // lack a TD element - if (!tdElem) return + // Static config filtered down to only currently-visible columns. Used for + // CSV/PDF export so hidden columns don't leak into downloads. + const visibleColumnConfig = columns.filter( + (col) => + columnVisibility[ + (col.id ?? (col as { accessorKey?: string }).accessorKey) as string + ] !== false + ) - const colIndex = tdElem.cellIndex - const { field } = columns[colIndex] + const resetFilters = () => { + setGlobalFilter('') + setColumnFilters([]) + setClearBtnEnabled(false) + scrollToTop() + } - // Show feature in map - if (field === 'id') { - history.push(`/Explore/Language/${rowData.Language}/${rowData.id}`) + const onCellClick = ( + field: string, + row: InstanceLevelSchema, + event: React.MouseEvent + ): void => { + if (field === 'actions-id') { + history.push(`/Explore/Language/${row.Language}/${row.id}`) return } - // Don't set filter for image-only Endonyms - if (field === 'Endonym' && rowData['Font Image Alt']) return - - // Has nothing to do with County, just need it for full-screen view - if (field === 'County') { - history.push(`${routes.data}/${rowData.id}`) // open Details modal + if (field === 'actions-county') { + history.push(`${routes.data}/${row.id}`) return } - // Support multi-line value clicks, e.g. Country, Additional Neighborhoods - const elemWithFilter = path.find((elem) => { - const asElement = elem as HTMLElement + if (field === 'Endonym' && row['Font Image Alt']) return - return asElement.classList?.contains(FILTER_CLASS) - }) as HTMLElement + event.stopPropagation() + } - // Clicking a country flag cell above or below the content results in no - // element match, but we can't use the row value because it's an array and - // the table is expecting a string, and we can't convert it to string - // because then there won't be a match if there is a newline. 😠 - if (!elemWithFilter && Array.isArray(rowData[field])) return + return ( + + + + + { + const headerDef = column.columnDef.header + const label = typeof headerDef === 'string' ? headerDef : column.id - // Safari will preserve newlines w/o `trim` - const newFilterVal = elemWithFilter?.innerText.trim() || rowData[field] + return { + id: column.id, + label, + isVisible: column.getIsVisible(), + canHide: column.getCanHide(), + toggle: () => column.toggleVisibility(), + } + })} + /> + + + + {table.getHeaderGroups().map((headerGroup) => ( + + {headerGroup.headers.map((header) => { + const sortable = header.column.getCanSort() + const sortDir = header.column.getIsSorted() + const isActions = header.column.id.startsWith('actions-') - const newlyFiltered = columns.map((column: ColumnWithTableData, i) => { - let filterValue + return ( + + {sortable ? ( + + {flexRender( + header.column.columnDef.header, + header.getContext() + )} + + ) : ( + flexRender( + header.column.columnDef.header, + header.getContext() + ) + )} + + ) + })} + + ))} + {/* Per-column filter row, à la material-table */} + + {table.getVisibleLeafColumns().map((column) => { + const meta = column.columnDef.meta as LangColumnMeta | undefined + const canFilter = column.getCanFilter() && !meta?.unfilterable - if (colIndex !== i) filterValue = column.tableData.filterValue - // Lookup filter types have array values - else if (column.lookup) filterValue = [newFilterVal] - else filterValue = newFilterVal + if (!canFilter) { + return + } - return { - ...column, - tableData: { ...column.tableData, filterValue }, - } - }) + if (meta?.mediaFilter) { + return ( + + + + ) + } - columns.forEach((col: ColumnWithTableData, i: number) => { - dataManager.changeFilterValue(i, newlyFiltered[i].tableData.filterValue) - }) + if (meta?.lookup) { + const value = (column.getFilterValue() as string) || '' - self.setState({ ...dataManager.getRenderState(), columns: newlyFiltered }) + return ( + + + + ) + } - setClearBtnEnabled(true) - scrollToTop() - } + const value = (column.getFilterValue() as string) || '' - return ( - <> - - - - { - import('./exporting' /* webpackChunkName: "exporting" */) - .then(({ exportCsv }) => exportCsv(defs, data)) - .catch(() => { - throw new Error( - '😱 Uh oh! Could not import the exporting utility' + return ( + + + column.setFilterValue(e.target.value || undefined) + } + /> + ) - }) - }, - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - exportPdf: (defs, data) => { - import('./exporting' /* webpackChunkName: "exporting" */) - .then(({ exportPdf }) => exportPdf(defs, data)) - .catch(() => { - throw new Error( - '😱 Uh oh! Could not import the exporting utility' - ) - }) - }, - }} - columns={columnConfig} - localization={localization} - data={tableData} - onChangeRowsPerPage={() => scrollToTop()} - onChangePage={() => scrollToTop()} - onSearchChange={() => scrollToTop()} - onRowClick={(event, rowData): void => { - if (!tableRef || !tableRef.current || !event || !rowData) return - - onRowClick(event, rowData) - }} - components={{ - Toolbar: (toolbarProps) => ( - - ), - }} - // Works but laggy: - onFilterChange={() => { - setClearBtnEnabled(true) - scrollToTop() - }} - // CANNOT get this to work without setting the focus to the clear btn - // onSearchChange={(search) => setClearBtnEnabled(true)} - /> - + })} + + + + {table.getRowModel().rows.map((row) => ( + + {row.getVisibleCells().map((cell) => { + const isActions = cell.column.id.startsWith('actions-') + + return ( + + onCellClick(cell.column.id, row.original, e) + } + className={isActions ? classes.actionsCell : undefined} + > + {flexRender( + cell.column.columnDef.cell, + cell.getContext() + )} + + ) + })} + + ))} + {table.getRowModel().rows.length === 0 && ( + + + No communities found. Try fewer criteria or click "Clear + filters" to reset the table. + + + )} + +
    +
    +
    + + Rows per page:  + + + + {(() => { + const total = table.getFilteredRowModel().rows.length + + if (total === 0) return '0–0 of 0' + + const { pageIndex, pageSize } = table.getState().pagination + const start = pageIndex * pageSize + 1 + const end = Math.min((pageIndex + 1) * pageSize, total) + + return `${start}–${end} of ${total}` + })()} + + + +
    +
    ) } diff --git a/src/components/results/ResultsTitle.tsx b/src/components/results/ResultsTitle.tsx index 94ab8fcb..b48a41b5 100644 --- a/src/components/results/ResultsTitle.tsx +++ b/src/components/results/ResultsTitle.tsx @@ -1,8 +1,10 @@ /* eslint-disable operator-linebreak */ /* eslint-disable react/display-name */ import React, { FC } from 'react' -import { createStyles, makeStyles, Theme } from '@material-ui/core/styles' -import { Typography } from '@material-ui/core' +import { Theme } from '@mui/material/styles' +import createStyles from '@mui/styles/createStyles' +import makeStyles from '@mui/styles/makeStyles' +import { Typography } from '@mui/material' import { BsTable } from 'react-icons/bs' const useStyles = makeStyles((theme: Theme) => @@ -11,7 +13,7 @@ const useStyles = makeStyles((theme: Theme) => gridArea: 'title', display: 'flex', alignItems: 'center', - [theme.breakpoints.down('sm')]: { + [theme.breakpoints.down('md')]: { '& .MuiFormControl-root': { paddingLeft: 8 }, }, }, diff --git a/src/components/results/ResultsToolbar.tsx b/src/components/results/ResultsToolbar.tsx index 1f78c4e6..a6a749f4 100644 --- a/src/components/results/ResultsToolbar.tsx +++ b/src/components/results/ResultsToolbar.tsx @@ -1,10 +1,21 @@ -import React, { FC, useContext, useEffect } from 'react' +import React, { FC, useContext, useEffect, useState } from 'react' import { useHistory } from 'react-router-dom' -import { createStyles, makeStyles, Theme } from '@material-ui/core/styles' -import { MTableToolbar } from 'material-table' -import { Button } from '@material-ui/core' +import { Theme } from '@mui/material/styles' +import createStyles from '@mui/styles/createStyles' +import makeStyles from '@mui/styles/makeStyles' +import { + Button, + Checkbox, + FormControlLabel, + InputAdornment, + Menu, + MenuItem, + TextField, +} from '@mui/material' import { BiMapPin } from 'react-icons/bi' -import { FaMap } from 'react-icons/fa' +import { FaMap, FaFileCsv, FaFilePdf } from 'react-icons/fa' +import { GoSearch } from 'react-icons/go' +import { MdViewColumn } from 'react-icons/md' import { RiFilterOffFill } from 'react-icons/ri' import { GlobalContext } from 'components/context' @@ -13,65 +24,39 @@ import { PopoverWithUItext } from 'components/generic' import { ResultsTitle } from './ResultsTitle' import * as Types from './types' +import { exportCsv, exportPdf } from './exporting' import { whittleLangFeats } from './utils' -const TOOLBAR_ID = 'custom-toolbar' - -// TODO: get this monster into styles file export const useStyles = makeStyles((theme: Theme) => createStyles({ resultsToolbarRoot: { padding: '0.5em 0.75em', - // outline: 'solid blue 5px', borderBottom: `solid ${theme.palette.divider} 2px`, - position: 'sticky', - top: 0, backgroundColor: theme.palette.background.paper, - zIndex: 11, // keeps it above header row display: 'grid', alignItems: 'center', gridColumnGap: '0.75em', - gridRowGap: '0.15em', + gridRowGap: '0.4em', gridTemplateAreas: `"title searchAndActions" "buttons buttons" + "exports exports" "local local"`, gridTemplateColumns: 'auto 1fr', - gridTemplateRows: 'auto auto auto', - // marginBottom: '0.25em', // STUPID SPACER SO RIDICULOUS - '& .MuiIconButton-root': { padding: 4 }, // huuuge by default - [theme.breakpoints.up('sm')]: { - gridTemplateColumns: 'auto auto', - justifyContent: 'center', - gridColumnGap: '1em', - }, + '& .MuiIconButton-root': { padding: 4 }, [theme.breakpoints.up('md')]: { - gridTemplateAreas: `"title buttons local searchAndActions"`, - gridTemplateColumns: 'auto auto auto 1fr', + gridTemplateAreas: `"title buttons exports local searchAndActions"`, + gridTemplateColumns: 'auto auto auto auto 1fr', gridTemplateRows: 'auto', - justifyContent: 'flex-start', - padding: '1em 1em 0', - height: 100, // ugghhhhh + padding: '0.75em 1em', }, }, - // TODO: move the stupid searchbar onto its own line searchAndActions: { display: 'flex', gridArea: 'searchAndActions', - '& .MuiToolbar-root': { paddingLeft: 0 }, - // Can't seem to access these any other way except maybe overriding the - // entire component, and definitely not via `MTable` classes since they - // are mutated in the build. - '& .MuiToolbar-root > :nth-child(2)': { display: 'none' }, // spacer - '& .MuiToolbar-root > :last-child': { flexShrink: 0 }, // actions wrap - [theme.breakpoints.only('xs')]: { - '& .MuiToolbar-root': { paddingRight: 0 }, - '& .MuiInputBase-root.MuiInput-root': { maxWidth: 135 }, // so FRAGILE - }, + alignItems: 'center', [theme.breakpoints.up('md')]: { justifyContent: 'flex-end', - marginRight: 8, }, - // outline: 'solid red 1px', }, localIndicator: { display: 'flex', @@ -84,80 +69,59 @@ export const useStyles = makeStyles((theme: Theme) => fontSize: '0.75em', gridArea: 'local', justifyContent: 'center', - marginTop: '0.4em', textAlign: 'center', - // outline: 'solid gold 1px', '& svg': { fontSize: '1.2em' }, - [theme.breakpoints.up('md')]: { marginTop: 0, justifySelf: 'flex-end' }, + [theme.breakpoints.up('md')]: { justifySelf: 'flex-end' }, }, toolbarBtns: { alignItems: 'center', - display: 'grid', + display: 'flex', + flexWrap: 'wrap', + gap: '0.5rem', gridArea: 'buttons', - gridColumnGap: '0.5rem', - gridTemplateColumns: 'auto auto auto', justifyContent: 'center', - // outline: 'solid green 1px', - [theme.breakpoints.only('xs')]: { - gridColumnGap: '0.25rem', - }, + }, + exportBtns: { + alignItems: 'center', + display: 'flex', + gap: '0.5rem', + gridArea: 'exports', + justifyContent: 'center', }, }) ) export const ResultsToolbar: FC = (props) => { - const { tableRef, clearBtnEnabled, setClearBtnEnabled, scrollToTop } = props + const { + clearBtnEnabled, + setClearBtnEnabled, + scrollToTop, + visibleRows, + globalFilter, + setGlobalFilter, + resetFilters, + rowCount, + columns, + columnToggles, + } = props const { state, dispatch } = useContext(GlobalContext) const classes = useStyles() const history = useHistory() - const noResults = tableRef.current && !tableRef.current.state.data.length + const noResults = rowCount === 0 - // CRED: 🎉 - // https://github.com/mbrn/material-table/issues/1132#issuecomment-549591832 function clearFiltersBtnClick(physicalClick?: boolean): void { - if (!tableRef || !tableRef.current) return - - const self = tableRef.current - const { dataManager } = self - const { columns } = dataManager.getRenderState() - - // CRED: for TS: https://stackoverflow.com/a/46204035/1048518 - const shame: HTMLElement = document.querySelector( - `#${TOOLBAR_ID} button[aria-label="Clear Search"]` - ) as HTMLElement - - if (shame) shame.click() - // else { // TODO: sentry: element not found... } - - const cleared = columns.map((column: Types.ColumnWithTableData) => ({ - ...column, - tableData: { ...column.tableData, filterValue: undefined }, - })) - - columns.forEach((col: Types.ColumnWithTableData, i: number) => { - dataManager.changeFilterValue(i, undefined) - }) - - self.setState({ ...dataManager.getRenderState(), columns: cleared }) - - setClearBtnEnabled(false) - scrollToTop() + resetFilters() if (!physicalClick) { - dispatch({ - type: 'CLEAR_FILTERS', - payload: 0, - }) - + dispatch({ type: 'CLEAR_FILTERS', payload: 0 }) dispatch({ type: 'SET_LANG_LAYER_FEATURES', - payload: whittleLangFeats(dataManager.data), + payload: whittleLangFeats(visibleRows), }) } } useEffect((): void => { - // TODO: fix, obviously: if (state.clearFilters === 555) { clearFiltersBtnClick() } @@ -165,32 +129,42 @@ export const ResultsToolbar: FC = (props) => { }, [state.clearFilters]) function mapFilterBtnClick(): void { - const currentData = tableRef?.current.state.data - - if (!currentData) return - dispatch({ type: 'SET_LANG_LAYER_FEATURES', - payload: whittleLangFeats(currentData), + payload: whittleLangFeats(visibleRows), }) - // Let the map know it's okay to re-render (as opposed to on first load) dispatch({ type: 'SET_FILTER_HAS_RUN' }) - const gangsAllHere = state.langFeatsLenCache === currentData.length + const gangsAllHere = state.langFeatsLenCache === visibleRows.length dispatch({ type: 'CLEAR_FILTERS', payload: gangsAllHere ? 0 : 1 }) - history.push(routes.home) // TODO: ideally, go back + history.push(routes.home) } return (
    -
    - - {/* TODO: restore */} - {/* Showing {langFeatures.length} of {langFeatures.length} communities. */} +
    + { + setGlobalFilter(e.target.value) + setClearBtnEnabled(true) + scrollToTop() + }} + InputProps={{ + startAdornment: ( + + + + ), + }} + />
    +
    +
    + + +
    Local community data
    ) } + +const ColumnVisibilityMenu: FC<{ toggles: Types.ColumnToggle[] }> = (props) => { + const { toggles } = props + const [anchorEl, setAnchorEl] = useState(null) + + return ( + <> + + setAnchorEl(null)} + > + {toggles + .filter((t) => t.canHide) + .map((t) => ( + t.toggle()} + sx={{ paddingY: 0 }} + > + e.preventDefault()} + control={ + + } + label={t.label} + /> + + ))} + + + ) +} diff --git a/src/components/results/config.tsx b/src/components/results/config.tsx index ffd1da2b..b76c8f27 100644 --- a/src/components/results/config.tsx +++ b/src/components/results/config.tsx @@ -1,28 +1,14 @@ /* eslint-disable react/display-name */ import React from 'react' -import { Icons, Localization } from 'material-table' -import { FaFilter } from 'react-icons/fa' -import { - MdArrowUpward, - MdCheck, - MdChevronLeft, - MdChevronRight, - MdClear, - MdFileDownload, - MdFirstPage, - MdLastPage, - MdSearch, - MdViewColumn, - MdRemove, -} from 'react-icons/md' +import { createColumnHelper } from '@tanstack/react-table' -import { Statuses } from 'components/context/types' +import { InstanceLevelSchema, Statuses } from 'components/context/types' import * as Types from './types' import * as utils from './utils' import * as Cells from './Cells' -import { MediaColumnFilter } from './MediaColumnFilter' +import { mediaUrlFilterFn } from './MediaColumnFilter' import { LocalColumnTitle } from './LocalColumnTitle' const COMM_STATUS_LOOKUP = { @@ -35,15 +21,13 @@ const COMM_STATUS_LOOKUP = { [key in Statuses]: Statuses } -// TODO: pass this as fn arg instead of importing in export util export const tableExportMeta = { pageTitle: 'Languages of New York City', filename: 'nyc-language-data', fullDatasetURL: 'https://airtable.com/shrqQo5FJHvhKtffs', } -// TODO: Enum?? -const SIZE_MAP = { +const SIZE_MAP: { [key: string]: number } = { Smallest: 1, Small: 2, Medium: 3, @@ -59,276 +43,122 @@ const COMM_SIZES = { Largest: 'Largest', } -export const localization: Localization = { - body: { - emptyDataSourceMessage: - 'No communities found. Try fewer criteria or click the "Clear filters" button to reset the table.', - }, - header: { - actions: '', - }, - toolbar: { - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore // in newer version of material-table, which has laggy bug... - exportCSVName: 'Download as CSV', - exportPDFName: 'Download as PDF', - searchPlaceholder: 'Search...', - }, -} - -// Table options for the component -export const options = { - columnsButton: true, - doubleHorizontalScroll: false, - draggable: true, // kinda clunky - exportAllData: true, // misleading, it actually exports all FILTERED data - exportButton: true, // enable it in the toolbar - filtering: true, - grouping: false, // kinda clunky - isLoading: true, - maxBodyHeight: '100%', - minBodyHeight: '100%', - pageSize: 20, - pageSizeOptions: [10, 20, 50], - searchFieldAlignment: 'left', - showTitle: false, - thirdSortClick: false, - // TODO: rm unused, or keep for reference - // actionsCellStyle: {}, // semi-useful but ended up with `!important` anyway - // actionsColumnIndex: 0, - // fixedColumns: { left: 2, right: 0 }, // awful in so many ways - // headerStyle: { position: 'sticky', top: 0 }, - // filterCellStyle: { backgroundColor: 'yellow' }, // works - // filterRowStyle: { backgroundColor: 'red' }, // works, but sticky 2 tricky! - // padding: 'dense', // dense leads to choppier inconsistent row height - // rowStyle: { backgroundColor: 'turquoise' }, // works - // searchFieldVariant: 'outlined', // meh, too big - // searchFieldStyle: {}, // the actual text inside search box - // tableLayout: 'fixed', // can set widths, but `fixed` = for bad Actions col -} as Types.TableOptions - -export const icons = { - Check: MdCheck, - DetailPanel: MdChevronRight, - Export: MdFileDownload, - Filter: FaFilter, - FirstPage: MdFirstPage, - LastPage: MdLastPage, - NextPage: MdChevronRight, - PreviousPage: MdChevronLeft, - ResetSearch: MdClear, - Search: MdSearch, - SortArrow: MdArrowUpward, - ThirdStateCheck: MdRemove, - ViewColumn: MdViewColumn, -} as Icons - -const commonColProps = { - editable: 'never', - searchable: true, - // cellStyle: {}, -} - -const hiddenCols = [ - { - title: 'Glottocode', - field: 'Glottocode', - ...commonColProps, - hidden: true, - }, - { - title: 'ISO 639-3', - field: 'ISO 639-3', - ...commonColProps, - hidden: true, - }, - { - title: 'Additional Neighborhoods', - field: 'Additional Neighborhoods', - ...commonColProps, - hidden: true, - }, +const ch = createColumnHelper() + +export const columns: Types.ColumnList = [ + ch.display({ + id: 'actions-id', + header: '', + size: 56, + enableSorting: false, + enableColumnFilter: false, + enableHiding: false, + cell: utils.renderIDcolumn, + meta: { excludeFromExport: true, unfilterable: true }, + }), + ch.display({ + id: 'actions-county', + header: '', + size: 56, + enableSorting: false, + enableColumnFilter: false, + enableHiding: false, + cell: utils.renderDescripCol, + meta: { excludeFromExport: true, unfilterable: true }, + }), + ch.accessor('Language', { + header: 'Language', + cell: (info) => (info.getValue() as React.ReactNode) ?? '', + meta: { exportTitle: 'Language' }, + }), + ch.accessor('Endonym', { + header: 'Endonym', + cell: utils.renderEndoColumn, + meta: { exportTitle: 'Endonym' }, + }), + ch.accessor('World Region', { + header: 'World Region', + cell: (info) => , + meta: { exportTitle: 'World Region' }, + }), + ch.accessor( + (row) => (Array.isArray(row.Country) ? row.Country.join(', ') : ''), + { + id: 'Country', + header: 'Country', + cell: utils.renderCountryColumn, + meta: { exportTitle: 'Country' }, + } + ), + ch.accessor('Global Speaker Total', { + header: 'Global Speakers', + cell: (info) => , + enableColumnFilter: false, + sortingFn: 'basic', + meta: { exportTitle: 'Global Speakers', unfilterable: true }, + }), + ch.accessor('Language Family', { + header: 'Language Family', + cell: (info) => (info.getValue() as React.ReactNode) ?? '', + meta: { exportTitle: 'Language Family' }, + }), + ch.accessor('Video', { + header: 'Video', + cell: (info) => , + enableSorting: false, + filterFn: mediaUrlFilterFn, + meta: { exportTitle: 'Video', mediaFilter: true, excludeFromExport: true }, + }), + ch.accessor('Audio', { + header: 'Audio', + cell: (info) => , + enableSorting: false, + filterFn: mediaUrlFilterFn, + meta: { exportTitle: 'Audio', mediaFilter: true, excludeFromExport: true }, + }), + ch.accessor('Primary Location', { + header: () => , + cell: (info) => (info.getValue() as React.ReactNode) ?? '', + meta: { exportTitle: 'Location' }, + }), + ch.accessor('Size', { + header: () => , + cell: (info) => , + sortingFn: (a, b) => { + const va = SIZE_MAP[a.original.Size as string] || 0 + const vb = SIZE_MAP[b.original.Size as string] || 0 + + if (va === vb) return 0 + + return va > vb ? 1 : -1 + }, + meta: { exportTitle: 'Size', lookup: COMM_SIZES }, + }), + ch.accessor('Status', { + header: () => , + cell: (info) => , + meta: { exportTitle: 'Status', lookup: COMM_STATUS_LOOKUP }, + }), + ch.accessor('Glottocode', { + header: 'Glottocode', + cell: (info) => (info.getValue() as React.ReactNode) ?? '', + meta: { exportTitle: 'Glottocode' }, + }), + ch.accessor('ISO 639-3', { + header: 'ISO 639-3', + cell: (info) => (info.getValue() as React.ReactNode) ?? '', + meta: { exportTitle: 'ISO 639-3' }, + }), + ch.accessor('Additional Neighborhoods', { + header: 'Additional Neighborhoods', + cell: (info) => (info.getValue() as React.ReactNode) ?? '', + meta: { exportTitle: 'Additional Neighborhoods' }, + }), ] -// NOTE: did not want to attempt to deal with any of the multi-option cols like -// Size or Status in terms of filter-col-via-cell-click behavior, or the -// boolean-ish Video column. Wishlist... - -// First and second column values are just buttons -const stickyColStyle = { - position: 'sticky', - zIndex: 250, - backgroundColor: '#424242', // "paper" BG. Can't access theme from here 😞 +// Hide the columns that were `hidden: true` in the material-table config. +export const initialColumnVisibility: { [key: string]: boolean } = { + Glottocode: false, + 'ISO 639-3': false, + 'Additional Neighborhoods': false, } - -const firstColStyle = { - ...stickyColStyle, - left: 0, -} - -const secondColStyle = { - ...stickyColStyle, - left: 42, - paddingLeft: 0, - boxShadow: '5px 0px 8px 0px rgba(0,0,0,0.08)', -} - -// "View in map" and details modal can't use `hidden`, but without a title they -// show up as blanks in the column toggle/reorder menu. Handy workaround. -const hidden = { - color: 'transparent', - fontSize: 0, -} - -// 25px : 200char = decent ratio -export const columns = [ - { - title: 'View in map', - field: 'id', - ...commonColProps, - filtering: false, - export: false, - render: utils.renderIDcolumn, - cellStyle: firstColStyle, - headerStyle: { ...firstColStyle, ...hidden }, - filterCellStyle: firstColStyle, - }, - { - // It's not actully county, just a sneaky way to allow county/borough search - // AND a "view details modal" icon. Two birds, one stone. - title: 'County', - field: 'County', - ...commonColProps, - sorting: false, - filtering: false, - export: false, - render: utils.renderDescripCol, - cellStyle: secondColStyle, - headerStyle: { ...firstColStyle, ...hidden }, - filterCellStyle: secondColStyle, - }, - { - // Average: 9.3, Longest: 31 - title: 'Language', - field: 'Language', - ...commonColProps, - defaultSort: 'asc', - cellStyle: { paddingLeft: '1.25rem' }, // give room to 2nd col shadow - headerStyle: { paddingLeft: '1.25rem' }, // give room to 2nd col shadow - filterCellStyle: { paddingLeft: '1.25rem' }, // give room to 2nd col shadow - }, - { - // Average: 8.5, Longest: 26, Longest full: Anashinaabemowin - title: 'Endonym', - field: 'Endonym', - ...commonColProps, - render: utils.renderEndoColumn, - }, - { - // Average: 13, Longest: 25 (thanks AUS & NZ...) - title: 'World Region', - field: 'World Region', - ...commonColProps, - // TODO: instead of open-search filters, custom `filterComponent` with this: - // https://material-ui.com/components/autocomplete/#checkboxes - render: (data) => , - headerStyle: { - paddingRight: 25, // enough for `Southeastern Asia` cells to not wrap - whiteSpace: 'nowrap', - }, - }, - { - // Average: 8.5, Longest: 35 (w/o big Congos: Average: 8, Longest: 24) - // ...plus emoji flag and margin - // TODO: for Country selection: - // https://material-ui.com/components/autocomplete/#country-select - title: 'Country', - field: 'Country', - ...commonColProps, - render: utils.renderCountryColumn, - headerStyle: { - paddingRight: 30, // enough for `South Africa` cells to not wrap - }, - }, - { - // Longest: 20 - title: 'Global Speakers', // the only abbrev so far - field: 'Global Speaker Total', - ...commonColProps, - // customSort: utils.sortNeighbs, // TODO: blanks last - render: (data) => , - searchable: false, - filtering: false, - disableClick: true, - type: 'numeric', - // Right-aligned number w/left-aligned column heading was requested - headerStyle: { - whiteSpace: 'nowrap', - paddingRight: 0, - flexDirection: 'row', - }, - }, - { - // Average: 10, Longest: 23 but preserve hyphenated Athabaskan-Eyak-Tlingit - title: 'Language Family', - field: 'Language Family', - ...commonColProps, - headerStyle: { whiteSpace: 'nowrap' }, - }, - { - title: 'Video', - field: 'Video', - ...commonColProps, - export: false, - filterComponent: MediaColumnFilter, - headerStyle: { whiteSpace: 'nowrap' }, - render: (data) => , - searchable: false, - disableClick: true, - }, - { - title: 'Audio', - field: 'Audio', - ...commonColProps, - export: false, - filterComponent: MediaColumnFilter, - headerStyle: { whiteSpace: 'nowrap' }, - render: (data) => , - searchable: false, - disableClick: true, - }, - { - // Average: 12, Longest: 26 - title: , - field: 'Primary Location', - ...commonColProps, - }, - { - // Longest: 14 - title: , - field: 'Size', - ...commonColProps, - align: 'left', - lookup: COMM_SIZES, - customSort: (a, b) => { - if (SIZE_MAP[a.Size] === SIZE_MAP[b.Size]) return 0 - if (SIZE_MAP[a.Size] > SIZE_MAP[b.Size]) return 1 - - return -1 - }, - render: (data) => , - searchable: false, - headerStyle: { - paddingRight: 25, // "Smallest" is ironically the longest - }, - }, - { - title: , - field: 'Status', - ...commonColProps, - searchable: false, - render: (data) => , - lookup: COMM_STATUS_LOOKUP, - }, - ...hiddenCols, -] as Types.ColumnsConfig[] diff --git a/src/components/results/exporting.ts b/src/components/results/exporting.ts index d0321eb2..821bd642 100644 Binary files a/src/components/results/exporting.ts and b/src/components/results/exporting.ts differ diff --git a/src/components/results/styles.ts b/src/components/results/styles.ts index 402110a3..22cd602b 100644 --- a/src/components/results/styles.ts +++ b/src/components/results/styles.ts @@ -1,4 +1,7 @@ -import { createStyles, makeStyles, Theme } from '@material-ui/core/styles' +import { Theme } from '@mui/material/styles' + +import createStyles from '@mui/styles/createStyles' +import makeStyles from '@mui/styles/makeStyles' const footerCell = '.MuiTableCell-footer' const footerWrap = '.MuiPaper-root > .MuiTable-root' @@ -7,7 +10,7 @@ const headCell = '.MuiTableCell-head' export const useStyles = makeStyles((theme: Theme) => createStyles({ resultsModalRoot: { - [theme.breakpoints.down('sm')]: { + [theme.breakpoints.down('md')]: { '& .MuiTableFooter-root .MuiIconButton-root': { padding: 4, // waaaaayy too much default padding, can't see on mobile }, @@ -30,7 +33,7 @@ export const useStyles = makeStyles((theme: Theme) => backgroundColor: theme.palette.background.paper, }, // e.g. the Filter icon at beginning of column filters - '& .MuiInputAdornment-root': { color: theme.palette.text.hint }, + '& .MuiInputAdornment-root': { color: theme.palette.text.disabled }, [`& ${headCell}`]: { backgroundColor: 'inherit', color: theme.palette.secondary.light, @@ -71,9 +74,9 @@ export const useStyles = makeStyles((theme: Theme) => }, // Squeeze a bit more room out of the dialog resultsModalPaper: { - height: `calc(100% - ${theme.spacing(2)}px)`, + height: `calc(100% - ${theme.spacing(2)})`, maxHeight: '100%', - [theme.breakpoints.down('sm')]: { + [theme.breakpoints.down('md')]: { height: '100%', margin: 0, }, diff --git a/src/components/results/types.ts b/src/components/results/types.ts index b2639c82..614ee6ec 100644 --- a/src/components/results/types.ts +++ b/src/components/results/types.ts @@ -1,76 +1,68 @@ -import MaterialTable, { - Options, - Column, - MaterialTableProps, -} from 'material-table' +import { CellContext, ColumnDef, FilterFn, Row } from '@tanstack/react-table' import { InstanceLevelSchema } from 'components/context/types' import { AirtableError } from 'components/explore/types' -type ColumnWithField = Column & { - field: keyof InstanceLevelSchema - title: string +export type LangColumnMeta = { + // Human-readable column title for export (PDF/CSV) and filter labels. + exportTitle?: string | React.ReactElement + // If true, exclude from CSV/PDF export. + excludeFromExport?: boolean + // Predefined value set, used to render a select dropdown filter. + lookup?: { [key: string]: string } + // Render a "has media" checkbox filter instead of the default text input. + mediaFilter?: boolean + // Hide the per-column filter input. + unfilterable?: boolean } -export type ColumnList = ColumnWithField[] -export type InitialData = InstanceLevelSchema[] - -// The JSON file with {"name":"code"} country key/val pairs -export type CountryCodes = { [key: string]: string } -export type ColumnWithTableData = { tableData: TableData } & ColumnsConfig -export type ResultsTableProps = { data: InstanceLevelSchema[] } -export type TableOptions = Options - // eslint-disable-next-line @typescript-eslint/no-explicit-any -export type TableData = { id: number | string; filterValue: any } - -export type FilterComponentProps = { - columnDef: { - tableData: TableData - } & Column - onFilterChanged: (rowId: number | string, value: string) => void +export type LangColumn = ColumnDef & { + meta?: LangColumnMeta } -export type ColumnsConfig = Column & { - title: keyof InstanceLevelSchema - field: keyof InstanceLevelSchema +export type ColumnList = LangColumn[] +export type InitialData = InstanceLevelSchema[] + +// Used by exporting.ts after filtering out export-excluded columns. +export type ExportableColumn = LangColumn & { + accessorKey: keyof InstanceLevelSchema + header: string | React.ReactElement } +export type CountryCodes = { [key: string]: string } +export type ResultsTableProps = { data: InstanceLevelSchema[] } + export type UseLocation = { state: null | { selFeatID?: number - // TODO: scroll tops: - // scrollTops?: { - // [key in RouteLocation]?: string - // } } pathname: string } -// `dataManager` prop definitely exists but is not evidently part of the TS -export type MuiTableWithLangs = MaterialTable & { - dataManager: { - data: InstanceLevelSchema[] - // eslint-disable-next-line @typescript-eslint/no-explicit-any - changeFilterValue: (col: number, val: any) => void - changeSearchText: (text: string) => void - getRenderState: () => Omit< - MaterialTableProps, - 'columns' - > & { - columns: ColumnWithTableData[] - query: { - searchText: string - } - } - } +export type LangCellContext = CellContext +export type LangRow = Row +export type LangFilterFn = FilterFn + +export type ColumnToggle = { + id: string + label: string + isVisible: boolean + canHide: boolean + toggle: () => void } -export type ResultsToolbarProps = MaterialTableProps & { +export type ResultsToolbarProps = { scrollToTop: () => void - tableRef: React.RefObject clearBtnEnabled: boolean setClearBtnEnabled: React.Dispatch + visibleRows: InstanceLevelSchema[] + globalFilter: string + setGlobalFilter: (v: string) => void + resetFilters: () => void + rowCount: number + columns: ColumnList + columnToggles: ColumnToggle[] } export type CountryListItemWithFlagProps = { diff --git a/src/components/results/utils.tsx b/src/components/results/utils.tsx index 56c519a1..68000cef 100644 --- a/src/components/results/utils.tsx +++ b/src/components/results/utils.tsx @@ -1,24 +1,29 @@ import React from 'react' -import { IconButton } from '@material-ui/core' +import { IconButton } from '@mui/material' import { GoFile } from 'react-icons/go' import { FaMapMarkedAlt } from 'react-icons/fa' import { InstanceLevelSchema, InternalWithLang } from 'components/context/types' import { CountryListItemWithFlag } from './CountryListItemWithFlag' import { EndoImageModal } from './EndoImageModal' +import { LangCellContext } from './types' export const FILTER_CLASS = 'for-filter' export function renderCountryColumn( - data: InstanceLevelSchema + info: LangCellContext ): string | React.ReactNode { + const data = info.row.original + + if (!Array.isArray(data.Country) || data.Country.length === 0) return '' + return (
      {data.Country.map((countryWithFlag, i) => ( ))} @@ -27,10 +32,12 @@ export function renderCountryColumn( } export function renderEndoColumn( - data: InstanceLevelSchema + info: LangCellContext ): string | React.ReactNode { + const data = info.row.original + if (!data['Font Image Alt']) { - return data.Endonym + return data.Endonym ?? '' } return ( @@ -41,7 +48,6 @@ export function renderEndoColumn( ) } -// This is a misleading name since it's now "County", but it does the same thing export function renderDescripCol(): string | React.ReactNode { return ( @@ -64,6 +70,5 @@ export const whittleLangFeats = ( data.map((row) => { const { id, Latitude, Longitude, Language } = row - // Language needed for "No community selected" due to new routes setup return { id, Latitude, Longitude, Language } }) diff --git a/src/components/style-guide/DemoBreadcrumbs.tsx b/src/components/style-guide/DemoBreadcrumbs.tsx index 48eb1b18..446f3918 100644 --- a/src/components/style-guide/DemoBreadcrumbs.tsx +++ b/src/components/style-guide/DemoBreadcrumbs.tsx @@ -1,12 +1,14 @@ import React, { FC } from 'react' import { Link as RouteLink } from 'react-router-dom' -import { Theme, createStyles, makeStyles } from '@material-ui/core/styles' -import { Breadcrumbs, Typography, Link } from '@material-ui/core' +import { Theme } from '@mui/material/styles' +import createStyles from '@mui/styles/createStyles' +import makeStyles from '@mui/styles/makeStyles' +import { Breadcrumbs, Typography, Link } from '@mui/material' const useStyles = makeStyles((theme: Theme) => createStyles({ root: { - borderBottomColor: theme.palette.text.hint, + borderBottomColor: theme.palette.text.disabled, borderBottomStyle: 'dashed', borderBottomWidth: 1, marginTop: theme.spacing(4), diff --git a/src/components/style-guide/DemoBtns.tsx b/src/components/style-guide/DemoBtns.tsx index b41df510..a738a34e 100644 --- a/src/components/style-guide/DemoBtns.tsx +++ b/src/components/style-guide/DemoBtns.tsx @@ -1,12 +1,14 @@ import React, { FC } from 'react' -import { makeStyles, createStyles, Theme } from '@material-ui/core/styles' +import { Theme } from '@mui/material/styles' +import makeStyles from '@mui/styles/makeStyles' +import createStyles from '@mui/styles/createStyles' import { Button, ButtonGroup, IconButton, Paper, Typography, -} from '@material-ui/core' +} from '@mui/material' import { MdDelete } from 'react-icons/md' import { DemoSplitBtn } from 'components/style-guide' @@ -124,13 +126,13 @@ export const DemoBtns: FC = () => { - + - + - +
    @@ -150,7 +152,7 @@ export const DemoBtns: FC = () => { > Text first -