1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-04-24 01:18:01 +02:00

refactor: styles batch 3 (#2821)

This commit is contained in:
Tymoteusz Czech 2023-01-11 17:44:21 +01:00 committed by GitHub
parent be1762d33f
commit ddb9d11039
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
51 changed files with 895 additions and 1144 deletions

View File

@ -137,7 +137,7 @@ const ProjectRoleForm: FC<IProjectRoleForm> = ({
}} }}
> >
{children} {children}
<Button onClick={onCancel} sx={{ ml: 2 }}> <Button onClick={onCancel} sx={{ marginLeft: 2 }}>
Cancel Cancel
</Button> </Button>
</Box> </Box>

View File

@ -264,7 +264,10 @@ export const ChangeRequestOverview: FC = () => {
} }
show={ show={
<Button <Button
sx={{ ml: 2 }} sx={{
marginLeft: theme =>
theme.spacing(2),
}}
variant="outlined" variant="outlined"
onClick={onCancel} onClick={onCancel}
> >

View File

@ -1,13 +1,11 @@
import React, { useEffect, useState, useRef, FC } from 'react'; import React, { CSSProperties, useEffect, useState, useRef, FC } from 'react';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
interface IAnimateOnMountProps { interface IAnimateOnMountProps {
mounted: boolean; mounted: boolean;
enter: string; enter: CSSProperties;
start: string; start: CSSProperties;
leave?: string; leave?: CSSProperties;
container?: string;
style?: React.CSSProperties;
onStart?: () => void; onStart?: () => void;
onEnd?: () => void; onEnd?: () => void;
} }
@ -17,14 +15,12 @@ const AnimateOnMount: FC<IAnimateOnMountProps> = ({
enter, enter,
start, start,
leave, leave,
container,
children, children,
style,
onStart, onStart,
onEnd, onEnd,
}) => { }) => {
const [show, setShow] = useState(mounted); const [show, setShow] = useState(mounted);
const [styles, setStyles] = useState(''); const [styles, setStyles] = useState<CSSProperties>({});
const mountedRef = useRef<null | boolean>(null); const mountedRef = useRef<null | boolean>(null);
useEffect(() => { useEffect(() => {
@ -39,7 +35,7 @@ const AnimateOnMount: FC<IAnimateOnMountProps> = ({
if (!leave) { if (!leave) {
setShow(false); setShow(false);
} }
setStyles(leave || ''); setStyles(leave || {});
} }
} }
}, [mounted, enter, onStart, leave]); }, [mounted, enter, onStart, leave]);
@ -56,11 +52,8 @@ const AnimateOnMount: FC<IAnimateOnMountProps> = ({
condition={show} condition={show}
show={ show={
<div <div
className={`${start} ${styles} ${
container ? container : ''
}`}
onTransitionEnd={onTransitionEnd} onTransitionEnd={onTransitionEnd}
style={{ ...style }} style={{ ...start, ...styles }}
> >
{children} {children}
</div> </div>

View File

@ -1,47 +0,0 @@
import { makeStyles } from 'tss-react/mui';
export const useStyles = makeStyles()(theme => ({
container: {
display: 'flex',
flexGrow: 1,
alignItems: 'center',
position: 'relative',
backgroundColor: theme.palette.background.paper,
maxWidth: '400px',
[theme.breakpoints.down('md')]: {
marginTop: theme.spacing(1),
maxWidth: '100%',
},
},
search: {
display: 'flex',
alignItems: 'center',
backgroundColor: theme.palette.background.paper,
border: `1px solid ${theme.palette.grey[500]}`,
borderRadius: theme.shape.borderRadiusExtraLarge,
padding: '3px 5px 3px 12px',
width: '100%',
zIndex: 3,
'&.search-container:focus-within': {
borderColor: theme.palette.primary.light,
boxShadow: theme.boxShadows.main,
},
},
searchIcon: {
marginRight: 8,
color: theme.palette.inactiveIcon,
},
clearContainer: {
width: '30px',
'& > button': {
padding: '7px',
},
},
clearIcon: {
color: theme.palette.grey[700],
fontSize: '18px',
},
inputRoot: {
width: '100%',
},
}));

View File

@ -1,13 +1,11 @@
import React, { useRef, useState } from 'react'; import React, { useRef, useState } from 'react';
import { IconButton, InputBase, Tooltip } from '@mui/material'; import { useAsyncDebounce } from 'react-table';
import { Box, IconButton, InputBase, styled, Tooltip } from '@mui/material';
import { Search as SearchIcon, Close } from '@mui/icons-material'; import { Search as SearchIcon, Close } from '@mui/icons-material';
import classnames from 'classnames';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import { useStyles } from './Search.styles';
import { SearchSuggestions } from './SearchSuggestions/SearchSuggestions'; import { SearchSuggestions } from './SearchSuggestions/SearchSuggestions';
import { IGetSearchContextOutput } from 'hooks/useSearch'; import { IGetSearchContextOutput } from 'hooks/useSearch';
import { useKeyboardShortcut } from 'hooks/useKeyboardShortcut'; import { useKeyboardShortcut } from 'hooks/useKeyboardShortcut';
import { useAsyncDebounce } from 'react-table';
interface ISearchProps { interface ISearchProps {
initialValue?: string; initialValue?: string;
@ -21,6 +19,43 @@ interface ISearchProps {
debounceTime?: number; debounceTime?: number;
} }
const StyledContainer = styled('div')(({ theme }) => ({
display: 'flex',
flexGrow: 1,
alignItems: 'center',
position: 'relative',
backgroundColor: theme.palette.background.paper,
maxWidth: '400px',
[theme.breakpoints.down('md')]: {
marginTop: theme.spacing(1),
maxWidth: '100%',
},
}));
const StyledSearch = styled('div')(({ theme }) => ({
display: 'flex',
alignItems: 'center',
backgroundColor: theme.palette.background.paper,
border: `1px solid ${theme.palette.neutral.border}`,
borderRadius: theme.shape.borderRadiusExtraLarge,
padding: '3px 5px 3px 12px',
width: '100%',
zIndex: 3,
'&:focus-within': {
borderColor: theme.palette.primary.light,
boxShadow: theme.boxShadows.main,
},
}));
const StyledInputBase = styled(InputBase)(({ theme }) => ({
width: '100%',
}));
const StyledClose = styled(Close)(({ theme }) => ({
color: theme.palette.neutral.main,
fontSize: theme.typography.body1.fontSize,
}));
export const Search = ({ export const Search = ({
initialValue = '', initialValue = '',
onChange, onChange,
@ -33,7 +68,6 @@ export const Search = ({
debounceTime = 200, debounceTime = 200,
}: ISearchProps) => { }: ISearchProps) => {
const ref = useRef<HTMLInputElement>(); const ref = useRef<HTMLInputElement>();
const { classes: styles } = useStyles();
const [showSuggestions, setShowSuggestions] = useState(false); const [showSuggestions, setShowSuggestions] = useState(false);
const [value, setValue] = useState(initialValue); const [value, setValue] = useState(initialValue);
@ -62,23 +96,17 @@ export const Search = ({
const placeholder = `${customPlaceholder ?? 'Search'} (${hotkey})`; const placeholder = `${customPlaceholder ?? 'Search'} (${hotkey})`;
return ( return (
<div className={styles.container} style={containerStyles}> <StyledContainer style={containerStyles}>
<div <StyledSearch className={className}>
className={classnames(
styles.search,
className,
'search-container'
)}
>
<SearchIcon <SearchIcon
className={classnames(styles.searchIcon, 'search-icon')} sx={{
mr: 1,
color: theme => theme.palette.inactiveIcon,
}}
/> />
<InputBase <StyledInputBase
inputRef={ref} inputRef={ref}
placeholder={placeholder} placeholder={placeholder}
classes={{
root: classnames(styles.inputRoot, 'input-container'),
}}
inputProps={{ 'aria-label': placeholder }} inputProps={{ 'aria-label': placeholder }}
value={value} value={value}
onChange={e => onSearchChange(e.target.value)} onChange={e => onSearchChange(e.target.value)}
@ -86,12 +114,7 @@ export const Search = ({
onBlur={() => setShowSuggestions(false)} onBlur={() => setShowSuggestions(false)}
disabled={disabled} disabled={disabled}
/> />
<div <Box sx={{ width: theme => theme.spacing(4) }}>
className={classnames(
styles.clearContainer,
'clear-container'
)}
>
<ConditionallyRender <ConditionallyRender
condition={Boolean(value)} condition={Boolean(value)}
show={ show={
@ -102,20 +125,21 @@ export const Search = ({
onSearchChange(''); onSearchChange('');
ref.current?.focus(); ref.current?.focus();
}} }}
sx={{ padding: theme => theme.spacing(1) }}
> >
<Close className={styles.clearIcon} /> <StyledClose />
</IconButton> </IconButton>
</Tooltip> </Tooltip>
} }
/> />
</div> </Box>
</div> </StyledSearch>
<ConditionallyRender <ConditionallyRender
condition={Boolean(hasFilters) && showSuggestions} condition={Boolean(hasFilters) && showSuggestions}
show={ show={
<SearchSuggestions getSearchContext={getSearchContext!} /> <SearchSuggestions getSearchContext={getSearchContext!} />
} }
/> />
</div> </StyledContainer>
); );
}; };

View File

@ -1,78 +0,0 @@
import React, { useState, VFC } from 'react';
import classnames from 'classnames';
import { debounce } from 'debounce';
import { InputBase, Chip } from '@mui/material';
import SearchIcon from '@mui/icons-material/Search';
import { useStyles } from 'component/common/SearchField/styles';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
interface ISearchFieldProps {
updateValue: (value: string) => void;
initialValue?: string;
className?: string;
showValueChip?: boolean;
}
/**
* @deprecated use `Search` instead.
*/
export const SearchField: VFC<ISearchFieldProps> = ({
updateValue,
initialValue = '',
className = '',
showValueChip,
}) => {
const { classes: styles } = useStyles();
const [localValue, setLocalValue] = useState(initialValue);
const debounceUpdateValue = debounce(updateValue, 500);
const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
event.preventDefault();
const value = event.target.value || '';
setLocalValue(value);
debounceUpdateValue(value);
};
const handleKeyPress = (event: React.KeyboardEvent) => {
if (event.key === 'Enter') {
updateValue(localValue);
}
};
const updateNow = () => {
updateValue(localValue);
};
const onDelete = () => {
setLocalValue('');
updateValue('');
};
return (
<form className={styles.container} role="search">
<div className={classnames(styles.search, className)}>
<SearchIcon className={styles.searchIcon} />
<InputBase
placeholder="Search..."
classes={{ root: styles.inputRoot }}
inputProps={{ 'aria-label': 'search' }}
value={localValue}
onChange={handleChange}
onBlur={updateNow}
onKeyPress={handleKeyPress}
type="search"
/>
</div>
<ConditionallyRender
condition={Boolean(showValueChip && localValue)}
show={
<Chip
label={localValue}
onDelete={onDelete}
title="Clear search query"
/>
}
/>
</form>
);
};

View File

@ -1,28 +0,0 @@
import { makeStyles } from 'tss-react/mui';
export const useStyles = makeStyles()(theme => ({
container: {
display: 'flex',
alignItems: 'center',
flexWrap: 'wrap',
gap: '1rem',
},
search: {
display: 'flex',
alignItems: 'center',
backgroundColor: theme.palette.background.default,
borderRadius: theme.shape.borderRadiusExtraLarge,
padding: '0.25rem 0.5rem',
maxWidth: '450px',
[theme.breakpoints.down('sm')]: {
width: '100%',
},
},
searchIcon: {
marginRight: 8,
color: theme.palette.inactiveIcon,
},
inputRoot: {
width: '100%',
},
}));

View File

@ -1,48 +0,0 @@
import { makeStyles } from 'tss-react/mui';
export const useStyles = makeStyles()(theme => ({
container: {
width: '100%',
padding: theme.spacing(2, 3),
display: 'flex',
alignItems: 'center',
justifyContent: 'flex-start',
fontSize: theme.fontSizes.smallBody,
border: `1px solid ${theme.palette.dividerAlternative}`,
position: 'relative',
borderRadius: '5px',
},
link: {
textDecoration: 'none',
marginLeft: theme.spacing(1),
'&:hover': {
textDecoration: 'underline',
},
},
accordion: {
border: `1px solid ${theme.palette.dividerAlternative}`,
borderRadius: theme.shape.borderRadiusMedium,
backgroundColor: '#fff',
boxShadow: 'none',
margin: 0,
},
accordionRoot: {
transition: 'all 0.1s ease',
'&:before': {
opacity: '0 !important',
},
},
accordionExpanded: {
backgroundColor: theme.palette.neutral.light,
},
previewButton: {
paddingTop: 0,
paddingBottom: 0,
marginLeft: 'auto',
fontSize: theme.fontSizes.smallBody,
},
summary: {
fontSize: theme.fontSizes.smallBody,
margin: theme.spacing(0.5, 0),
},
}));

View File

@ -7,11 +7,11 @@ import {
AccordionDetails, AccordionDetails,
AccordionSummary, AccordionSummary,
Button, Button,
styled,
Typography, Typography,
} from '@mui/material'; } from '@mui/material';
import { ConstraintAccordionList } from '../ConstraintAccordion/ConstraintAccordionList/ConstraintAccordionList'; import { ConstraintAccordionList } from 'component/common/ConstraintAccordion/ConstraintAccordionList/ConstraintAccordionList';
import { ConditionallyRender } from '../ConditionallyRender/ConditionallyRender'; import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import { useStyles } from './SegmentItem.styles';
interface ISegmentItemProps { interface ISegmentItemProps {
segment: Partial<ISegment>; segment: Partial<ISegment>;
@ -20,36 +20,52 @@ interface ISegmentItemProps {
headerContent?: JSX.Element; headerContent?: JSX.Element;
} }
const StyledAccordion = styled(Accordion)(({ theme }) => ({
border: `1px solid ${theme.palette.dividerAlternative}`,
borderRadius: theme.shape.borderRadiusMedium,
backgroundColor: theme.palette.background.paper,
boxShadow: 'none',
margin: 0,
transition: 'all 0.1s ease',
'&:before': {
opacity: '0 !important',
},
'&.Mui-expanded': { backgroundColor: theme.palette.neutral.light },
}));
const StyledAccordionSummary = styled(AccordionSummary)(({ theme }) => ({
margin: theme.spacing(0, 0.5),
fontSize: theme.typography.body2.fontSize,
'.MuiAccordionSummary-content': {
display: 'flex',
alignItems: 'center',
},
}));
const StyledLink = styled(Link)(({ theme }) => ({
textDecoration: 'none',
marginLeft: theme.spacing(1),
'&:hover': {
textDecoration: 'underline',
},
}));
export const SegmentItem: VFC<ISegmentItemProps> = ({ export const SegmentItem: VFC<ISegmentItemProps> = ({
segment, segment,
isExpanded, isExpanded,
headerContent, headerContent,
constraintList, constraintList,
}) => { }) => {
const { classes } = useStyles();
const [isOpen, setIsOpen] = useState(isExpanded || false); const [isOpen, setIsOpen] = useState(isExpanded || false);
return ( return (
<Accordion <StyledAccordion expanded={isOpen}>
expanded={isOpen} <StyledAccordionSummary id={`segment-accordion-${segment.id}`}>
className={classes.accordion}
classes={{
root: classes.accordionRoot,
expanded: classes.accordionExpanded,
}}
>
<AccordionSummary
id={`segment-accordion-${segment.id}`}
className={classes.summary}
>
<DonutLarge color="secondary" sx={{ mr: 1 }} /> <DonutLarge color="secondary" sx={{ mr: 1 }} />
Segment: <span>Segment:</span>
<Link <StyledLink to={`/segments/edit/${segment.id}`}>
to={`/segments/edit/${segment.id}`}
className={classes.link}
>
{segment.name} {segment.name}
</Link> </StyledLink>
<ConditionallyRender <ConditionallyRender
condition={Boolean(headerContent)} condition={Boolean(headerContent)}
show={headerContent} show={headerContent}
@ -61,13 +77,18 @@ export const SegmentItem: VFC<ISegmentItemProps> = ({
size="small" size="small"
variant="outlined" variant="outlined"
onClick={() => setIsOpen(value => !value)} onClick={() => setIsOpen(value => !value)}
className={classes.previewButton} sx={{
my: 0,
ml: 'auto',
fontSize: theme =>
theme.typography.body2.fontSize,
}}
> >
{isOpen ? 'Close preview' : 'Preview'} {isOpen ? 'Close preview' : 'Preview'}
</Button> </Button>
} }
/> />
</AccordionSummary> </StyledAccordionSummary>
<AccordionDetails sx={{ pt: 0 }}> <AccordionDetails sx={{ pt: 0 }}>
<ConditionallyRender <ConditionallyRender
condition={Boolean(constraintList)} condition={Boolean(constraintList)}
@ -90,6 +111,6 @@ export const SegmentItem: VFC<ISegmentItemProps> = ({
} }
/> />
</AccordionDetails> </AccordionDetails>
</Accordion> </StyledAccordion>
); );
}; };

View File

@ -1,33 +0,0 @@
import { makeStyles } from 'tss-react/mui';
export const useStyles = makeStyles()(theme => ({
link: {
position: 'fixed',
overflow: 'hidden',
zIndex: 1000,
top: '1.125rem',
left: '1.125rem',
padding: '0.5rem 1rem',
whiteSpace: 'nowrap',
textDecoration: 'none',
background: theme.palette.primary.dark,
color: theme.palette.primary.contrastText,
borderRadius: theme.shape.borderRadius,
fontSize: theme.fontSizes.smallBody,
[theme.breakpoints.down(960)]: {
top: '0.8rem',
left: '0.8rem',
},
'&:not(:focus):not(:active)': {
clip: 'rect(0 0 0 0)',
clipPath: 'inset(50%)',
zIndex: -1,
width: 1,
height: 1,
margin: -1,
padding: 0,
},
},
}));

View File

@ -1,12 +0,0 @@
import { SKIP_NAV_TARGET_ID } from 'component/common/SkipNav/SkipNavTarget';
import { useStyles } from 'component/common/SkipNav/SkipNavLink.styles';
export const SkipNavLink = () => {
const { classes: styles } = useStyles();
return (
<a href={`#${SKIP_NAV_TARGET_ID}`} className={styles.link}>
Skip to content <span aria-hidden>&darr;</span>
</a>
);
};

View File

@ -0,0 +1,38 @@
import { SKIP_NAV_TARGET_ID } from 'component/common/SkipNavLink/SkipNavTarget';
import { styled } from '@mui/material';
const StyledLink = styled('a')(({ theme }) => ({
position: 'fixed',
overflow: 'hidden',
zIndex: 1000,
top: theme.spacing(2.25),
left: theme.spacing(2.25),
padding: theme.spacing(1, 2),
whiteSpace: 'nowrap',
textDecoration: 'none',
background: theme.palette.primary.dark,
color: theme.palette.primary.contrastText,
borderRadius: theme.shape.borderRadius,
fontSize: theme.fontSizes.smallBody,
[theme.breakpoints.down(960)]: {
top: '0.8rem',
left: '0.8rem',
},
'&:not(:focus):not(:active)': {
clip: 'rect(0 0 0 0)',
clipPath: 'inset(50%)',
zIndex: -1,
width: 1,
height: 1,
margin: -1,
padding: 0,
},
}));
export const SkipNavLink = () => (
<StyledLink href={`#${SKIP_NAV_TARGET_ID}`}>
Skip to content <span aria-hidden>&darr;</span>
</StyledLink>
);

View File

@ -1,7 +1,11 @@
import { Typography, Button, useTheme, useMediaQuery } from '@mui/material'; import { Typography, Button, useTheme, useMediaQuery } from '@mui/material';
import EventDiff from 'component/events/EventDiff/EventDiff'; import EventDiff from 'component/events/EventDiff/EventDiff';
import { useThemeStyles } from 'themes/themeStyles'; import {
fadeInBottomEnter,
fadeInBottomStartWithoutFixed,
} from 'themes/themeStyles';
import AnimateOnMount from 'component/common/AnimateOnMount/AnimateOnMount'; import AnimateOnMount from 'component/common/AnimateOnMount/AnimateOnMount';
import { useMemo } from 'react';
interface IStaleDataNotification { interface IStaleDataNotification {
refresh: () => void; refresh: () => void;
@ -18,12 +22,12 @@ export const StaleDataNotification = ({
data, data,
cache, cache,
}: IStaleDataNotification) => { }: IStaleDataNotification) => {
const { classes: themeStyles } = useThemeStyles();
const theme = useTheme(); const theme = useTheme();
const isExtraSmallScreen = useMediaQuery(theme.breakpoints.down('sm')); const isExtraSmallScreen = useMediaQuery(theme.breakpoints.down('sm'));
const getStyles = () => { const style = useMemo(() => {
const base = { const base = {
...fadeInBottomStartWithoutFixed,
padding: `${theme.spacing(3)} ${theme.spacing(4)}`, padding: `${theme.spacing(3)} ${theme.spacing(4)}`,
boxShadow: theme.boxShadows.elevated, boxShadow: theme.boxShadows.elevated,
borderRadius: theme.shape.borderRadiusLarge, borderRadius: theme.shape.borderRadiusLarge,
@ -41,15 +45,10 @@ export const StaleDataNotification = ({
}; };
} }
return base; return base;
}; }, [theme, isExtraSmallScreen]);
return ( return (
<AnimateOnMount <AnimateOnMount mounted={show} start={style} enter={fadeInBottomEnter}>
mounted={show}
start={themeStyles.fadeInBottomStartWithoutFixed}
enter={themeStyles.fadeInBottomEnter}
style={getStyles()}
>
<Typography variant="h5" sx={{ my: 2, mb: 2 }}> <Typography variant="h5" sx={{ my: 2, mb: 2 }}>
Your data is stale Your data is stale
</Typography> </Typography>

View File

@ -1,39 +0,0 @@
import { makeStyles } from 'tss-react/mui';
export const useStyles = makeStyles()(theme => ({
container: {
borderRadius: theme.shape.borderRadiusMedium,
border: `1px solid ${theme.palette.divider}`,
'& + &': {
marginTop: theme.spacing(2),
},
background: theme.palette.background.paper,
},
header: {
padding: theme.spacing(0.5, 2),
display: 'flex',
gap: theme.spacing(1),
alignItems: 'center',
borderBottom: `1px solid ${theme.palette.divider}`,
fontWeight: theme.typography.fontWeightMedium,
},
headerDraggable: {
paddingLeft: theme.spacing(1),
},
icon: {
fill: theme.palette.inactiveIcon,
},
actions: {
marginLeft: 'auto',
display: 'flex',
minHeight: theme.spacing(6),
alignItems: 'center',
},
resultChip: {
marginLeft: 'auto',
},
body: {
padding: theme.spacing(2),
justifyItems: 'center',
},
}));

View File

@ -1,7 +1,6 @@
import { DragEventHandler, FC, ReactNode } from 'react'; import { DragEventHandler, FC, ReactNode } from 'react';
import { DragIndicator } from '@mui/icons-material'; import { DragIndicator } from '@mui/icons-material';
import { styled, IconButton, Box } from '@mui/material'; import { styled, IconButton, Box } from '@mui/material';
import classNames from 'classnames';
import { IFeatureStrategy } from 'interfaces/strategy'; import { IFeatureStrategy } from 'interfaces/strategy';
import { import {
getFeatureStrategyIcon, getFeatureStrategyIcon,
@ -9,7 +8,6 @@ import {
} from 'utils/strategyNames'; } from 'utils/strategyNames';
import StringTruncator from 'component/common/StringTruncator/StringTruncator'; import StringTruncator from 'component/common/StringTruncator/StringTruncator';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import { useStyles } from './StrategyItemContainer.styles';
import { PlaygroundStrategySchema } from 'openapi'; import { PlaygroundStrategySchema } from 'openapi';
interface IStrategyItemContainerProps { interface IStrategyItemContainerProps {
@ -40,6 +38,27 @@ const StyledIndexLabel = styled('div')(({ theme }) => ({
}, },
})); }));
const StyledContainer = styled(Box)(({ theme }) => ({
borderRadius: theme.shape.borderRadiusMedium,
border: `1px solid ${theme.palette.divider}`,
'& + &': {
marginTop: theme.spacing(2),
},
background: theme.palette.background.paper,
}));
const StyledHeader = styled('div', {
shouldForwardProp: prop => prop !== 'draggable',
})(({ theme, draggable }) => ({
padding: theme.spacing(0.5, 2),
display: 'flex',
gap: theme.spacing(1),
alignItems: 'center',
borderBottom: `1px solid ${theme.palette.divider}`,
fontWeight: theme.typography.fontWeightMedium,
paddingLeft: draggable ? theme.spacing(1) : theme.spacing(2),
}));
export const StrategyItemContainer: FC<IStrategyItemContainerProps> = ({ export const StrategyItemContainer: FC<IStrategyItemContainerProps> = ({
strategy, strategy,
onDragStart, onDragStart,
@ -49,7 +68,6 @@ export const StrategyItemContainer: FC<IStrategyItemContainerProps> = ({
orderNumber, orderNumber,
style = {}, style = {},
}) => { }) => {
const { classes: styles } = useStyles();
const Icon = getFeatureStrategyIcon(strategy.name); const Icon = getFeatureStrategyIcon(strategy.name);
return ( return (
@ -58,12 +76,8 @@ export const StrategyItemContainer: FC<IStrategyItemContainerProps> = ({
condition={orderNumber !== undefined} condition={orderNumber !== undefined}
show={<StyledIndexLabel>{orderNumber}</StyledIndexLabel>} show={<StyledIndexLabel>{orderNumber}</StyledIndexLabel>}
/> />
<Box className={styles.container} style={{ ...style }}> <StyledContainer style={style}>
<div <StyledHeader draggable={Boolean(onDragStart)}>
className={classNames(styles.header, {
[styles.headerDraggable]: Boolean(onDragStart),
})}
>
<ConditionallyRender <ConditionallyRender
condition={Boolean(onDragStart)} condition={Boolean(onDragStart)}
show={() => ( show={() => (
@ -83,16 +97,36 @@ export const StrategyItemContainer: FC<IStrategyItemContainerProps> = ({
</DragIcon> </DragIcon>
)} )}
/> />
<Icon className={styles.icon} /> <Icon
sx={{
fill: theme => theme.palette.inactiveIcon,
}}
/>
<StringTruncator <StringTruncator
maxWidth="150" maxWidth="150"
maxLength={15} maxLength={15}
text={formatStrategyName(strategy.name)} text={formatStrategyName(strategy.name)}
/> />
<div className={styles.actions}>{actions}</div> <Box
</div> sx={{
<div className={styles.body}>{children}</div> marginLeft: 'auto',
</Box> display: 'flex',
minHeight: theme => theme.spacing(6),
alignItems: 'center',
}}
>
{actions}
</Box>
</StyledHeader>
<Box
sx={{
p: 2,
justifyItems: 'center',
}}
>
{children}
</Box>
</StyledContainer>
</Box> </Box>
); );
}; };

View File

@ -1,15 +0,0 @@
import { makeStyles } from 'tss-react/mui';
export const useStyles = makeStyles()(theme => ({
tabNav: {
backgroundColor: theme.palette.background.paper,
borderBottom: '1px solid',
borderBottomColor: theme.palette.grey[300],
borderRadius: 0,
},
tab: {
[theme.breakpoints.up('lg')]: {
minWidth: 160,
},
},
}));

View File

@ -1,7 +1,5 @@
import React, { useState, ReactNode } from 'react'; import React, { useState, ReactNode } from 'react';
import classnames from 'classnames';
import { Tabs, Tab, Paper } from '@mui/material'; import { Tabs, Tab, Paper } from '@mui/material';
import { useStyles } from 'component/common/TabNav/TabNav/TabNav.styles';
import { TabPanel } from 'component/common/TabNav/TabPanel/TabPanel'; import { TabPanel } from 'component/common/TabNav/TabPanel/TabPanel';
interface ITabNavProps { interface ITabNavProps {
@ -15,13 +13,13 @@ interface ITabData {
label: string; label: string;
component: ReactNode; component: ReactNode;
} }
export const TabNav = ({ export const TabNav = ({
tabData, tabData,
className = '', className = '',
navClass = '', navClass = '',
startingTab = 0, startingTab = 0,
}: ITabNavProps) => { }: ITabNavProps) => {
const { classes: styles } = useStyles();
const [activeTab, setActiveTab] = useState(startingTab); const [activeTab, setActiveTab] = useState(startingTab);
const renderTabs = () => const renderTabs = () =>
tabData.map((tab, index) => ( tabData.map((tab, index) => (
@ -30,7 +28,11 @@ export const TabNav = ({
label={tab.label} label={tab.label}
id={`tab-${index}`} id={`tab-${index}`}
aria-controls={`tabpanel-${index}`} aria-controls={`tabpanel-${index}`}
className={styles.tab} sx={{
minWidth: {
lg: 160,
},
}}
/> />
)); ));
@ -44,8 +46,14 @@ export const TabNav = ({
return ( return (
<> <>
<Paper <Paper
className={classnames(styles.tabNav, navClass)} className={navClass}
elevation={0} elevation={0}
sx={{
backgroundColor: theme => theme.palette.background.paper,
borderBottom: '1px solid',
borderBottomColor: theme => theme.palette.grey[300],
borderRadius: 0,
}}
> >
<Tabs <Tabs
value={activeTab} value={activeTab}

View File

@ -1,11 +1,16 @@
import { makeStyles } from 'tss-react/mui'; import { styled, TableCell } from '@mui/material';
export const useStyles = makeStyles()(theme => ({ export const StyledTableCell = styled(TableCell, {
header: { shouldForwardProp: prop =>
position: 'relative', prop !== 'isFlex' && prop !== 'isSortable' && prop !== 'isFlexGrow',
fontWeight: theme.fontWeight.medium, })<{
}, isFlex?: boolean;
flex: { isSortable?: boolean;
isFlexGrow?: boolean;
}>(({ theme, isFlex, isSortable, isFlexGrow }) => ({
position: 'relative',
fontWeight: theme.typography.fontWeightRegular,
...(isFlex && {
justifyContent: 'stretch', justifyContent: 'stretch',
alignItems: 'center', alignItems: 'center',
display: 'flex', display: 'flex',
@ -13,11 +18,8 @@ export const useStyles = makeStyles()(theme => ({
'& > *': { '& > *': {
flexGrow: 1, flexGrow: 1,
}, },
}, }),
flexGrow: { ...(isSortable && {
flexGrow: 1,
},
sortable: {
padding: 0, padding: 0,
'&:hover, &:focus': { '&:hover, &:focus': {
backgroundColor: theme.palette.tableHeaderHover, backgroundColor: theme.palette.tableHeaderHover,
@ -25,75 +27,72 @@ export const useStyles = makeStyles()(theme => ({
color: 'inherit', color: 'inherit',
}, },
}, },
}, }),
sortButton: { ...(isFlexGrow && {
all: 'unset', flexGrow: 1,
whiteSpace: 'nowrap', }),
width: '100%', }));
position: 'relative',
zIndex: 1, export const StyledButton = styled('button', {
':hover, :focus, &:focus-visible, &:active': { shouldForwardProp: prop => prop !== 'isSorted',
outline: 'revert', })<{ isSorted?: boolean }>(({ theme, isSorted }) => ({
'.hover-only': { all: 'unset',
display: 'inline-block', whiteSpace: 'nowrap',
}, width: '100%',
}, position: 'relative',
display: 'flex', zIndex: 1,
boxSizing: 'inherit', ':hover, :focus, &:focus-visible, &:active': {
cursor: 'pointer', outline: 'revert',
},
sortedButton: {
fontWeight: theme.fontWeight.bold,
},
label: {
display: 'flex',
flexDirection: 'column',
flexShrink: 1,
minWidth: 0,
'::after': {
fontWeight: 'bold',
display: 'inline-block',
height: 0,
content: 'attr(data-text)',
visibility: 'hidden',
overflow: 'hidden',
},
},
alignLeft: {
justifyContent: 'flex-start',
textAlign: 'left',
},
alignRight: {
justifyContent: 'flex-end',
textAlign: 'right',
},
alignCenter: {
justifyContent: 'center',
textAlign: 'center',
},
hiddenMeasurementLayer: {
padding: theme.spacing(2),
visibility: 'hidden',
display: 'flex',
alignItems: 'center',
width: '100%',
},
visibleAbsoluteLayer: {
padding: theme.spacing(2),
position: 'absolute',
display: 'flex',
alignItems: 'center',
width: '100%',
height: '100%',
'.hover-only': { '.hover-only': {
display: 'none', display: 'inline-block',
},
'& > span': {
minWidth: 0,
whiteSpace: 'nowrap',
textOverflow: 'ellipsis',
overflowX: 'hidden',
overflowY: 'visible',
}, },
}, },
display: 'flex',
boxSizing: 'inherit',
cursor: 'pointer',
...(isSorted && {
fontWeight: theme.typography.fontWeightBold,
}),
}));
export const StyledLabel = styled('span')(({ theme }) => ({
display: 'flex',
flexDirection: 'column',
flexShrink: 1,
minWidth: 0,
'::after': {
fontWeight: 'bold',
display: 'inline-block',
height: 0,
content: 'attr(data-text)',
visibility: 'hidden',
overflow: 'hidden',
},
}));
export const StyledHiddenMeasurementLayer = styled('span')(({ theme }) => ({
padding: theme.spacing(2),
visibility: 'hidden',
display: 'flex',
alignItems: 'center',
width: '100%',
}));
export const StyledVisibleAbsoluteLayer = styled('span')(({ theme }) => ({
padding: theme.spacing(2),
position: 'absolute',
display: 'flex',
alignItems: 'center',
width: '100%',
height: '100%',
'.hover-only': {
display: 'none',
},
'& > span': {
minWidth: 0,
whiteSpace: 'nowrap',
textOverflow: 'ellipsis',
overflowX: 'hidden',
overflowY: 'visible',
},
})); }));

View File

@ -7,11 +7,16 @@ import {
useRef, useRef,
useState, useState,
} from 'react'; } from 'react';
import { TableCell, Tooltip } from '@mui/material'; import { Tooltip } from '@mui/material';
import classnames from 'classnames';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import { useStyles } from './CellSortable.styles';
import { AnnouncerContext } from 'component/common/Announcer/AnnouncerContext/AnnouncerContext'; import { AnnouncerContext } from 'component/common/Announcer/AnnouncerContext/AnnouncerContext';
import {
StyledButton,
StyledHiddenMeasurementLayer,
StyledLabel,
StyledTableCell,
StyledVisibleAbsoluteLayer,
} from './CellSortable.styles';
import { SortArrow } from './SortArrow/SortArrow'; import { SortArrow } from './SortArrow/SortArrow';
interface ICellSortableProps { interface ICellSortableProps {
@ -45,7 +50,6 @@ export const CellSortable: FC<ICellSortableProps> = ({
const { setAnnouncement } = useContext(AnnouncerContext); const { setAnnouncement } = useContext(AnnouncerContext);
const [title, setTitle] = useState(''); const [title, setTitle] = useState('');
const ref = useRef<HTMLSpanElement>(null); const ref = useRef<HTMLSpanElement>(null);
const { classes: styles } = useStyles();
const ariaSort = isSorted const ariaSort = isSorted
? isDescending ? isDescending
@ -62,18 +66,27 @@ export const CellSortable: FC<ICellSortableProps> = ({
); );
}; };
const alignClass = useMemo(() => { const alignStyle = useMemo(() => {
switch (align) { switch (align) {
case 'left': case 'left':
return styles.alignLeft; return {
justifyContent: 'flex-start',
textAlign: 'left',
} as const;
case 'center': case 'center':
return styles.alignCenter; return {
justifyContent: 'center',
textAlign: 'center',
} as const;
case 'right': case 'right':
return styles.alignRight; return {
justifyContent: 'flex-end',
textAlign: 'right',
} as const;
default: default:
return undefined; return undefined;
} }
}, [align, styles]); }, [align]);
useEffect(() => { useEffect(() => {
const updateTitle = () => { const updateTitle = () => {
@ -93,55 +106,36 @@ export const CellSortable: FC<ICellSortableProps> = ({
}, [setTitle, ariaTitle]); // eslint-disable-line react-hooks/exhaustive-deps }, [setTitle, ariaTitle]); // eslint-disable-line react-hooks/exhaustive-deps
return ( return (
<TableCell <StyledTableCell
component="th" component="th"
aria-sort={ariaSort} aria-sort={ariaSort}
className={classnames(
styles.header,
isSortable && styles.sortable,
isFlex && styles.flex,
isFlexGrow && styles.flexGrow
)}
style={{ width, minWidth, maxWidth }} style={{ width, minWidth, maxWidth }}
isFlex={isFlex}
isFlexGrow={isFlexGrow}
isSortable={isSortable}
> >
<ConditionallyRender <ConditionallyRender
condition={isSortable} condition={isSortable}
show={ show={
<Tooltip title={title} arrow> <Tooltip title={title} arrow>
<button <StyledButton
isSorted={isSorted}
type="button" type="button"
className={classnames(
isSorted && styles.sortedButton,
styles.sortButton,
alignClass
)}
onClick={onSortClick} onClick={onSortClick}
> >
<span <StyledHiddenMeasurementLayer
className={classnames( style={alignStyle}
styles.hiddenMeasurementLayer,
alignClass
)}
aria-hidden aria-hidden
> >
<span <StyledLabel tabIndex={-1} data-text={children}>
className={styles.label}
tabIndex={-1}
data-text={children}
>
{children} {children}
</span> </StyledLabel>
<SortArrow <SortArrow
isSorted={isSorted} isSorted={isSorted}
isDesc={isDescending} isDesc={isDescending}
/> />
</span> </StyledHiddenMeasurementLayer>
<span <StyledVisibleAbsoluteLayer style={alignStyle}>
className={classnames(
styles.visibleAbsoluteLayer,
alignClass
)}
>
<span ref={ref} tabIndex={-1}> <span ref={ref} tabIndex={-1}>
<span>{children}</span> <span>{children}</span>
</span> </span>
@ -150,12 +144,12 @@ export const CellSortable: FC<ICellSortableProps> = ({
isDesc={isDescending} isDesc={isDescending}
className="sort-arrow" className="sort-arrow"
/> />
</span> </StyledVisibleAbsoluteLayer>
</button> </StyledButton>
</Tooltip> </Tooltip>
} }
elseShow={<div className={alignClass}>{children}</div>} elseShow={<div style={alignStyle}>{children}</div>}
/> />
</TableCell> </StyledTableCell>
); );
}; };

View File

@ -1,14 +0,0 @@
import { makeStyles } from 'tss-react/mui';
export const useStyles = makeStyles()(theme => ({
icon: {
marginLeft: theme.spacing(0.25),
marginRight: theme.spacing(-0.5),
color: theme.palette.grey[700],
fontSize: theme.fontSizes.mainHeader,
verticalAlign: 'middle',
},
sorted: {
color: theme.palette.grey[900],
},
}));

View File

@ -5,8 +5,8 @@ import {
UnfoldMoreOutlined, UnfoldMoreOutlined,
} from '@mui/icons-material'; } from '@mui/icons-material';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import { useStyles } from './SortArrow.styles';
import classnames from 'classnames'; import classnames from 'classnames';
import { Theme } from '@mui/material';
interface ISortArrowProps { interface ISortArrowProps {
isSorted?: boolean; isSorted?: boolean;
@ -14,47 +14,54 @@ interface ISortArrowProps {
className?: string; className?: string;
} }
const iconStyle = (theme: Theme) => ({
marginLeft: theme.spacing(0.25),
marginRight: theme.spacing(-0.5),
color: theme.palette.neutral.main,
fontSize: theme.fontSizes.mainHeader,
verticalAlign: 'middle',
});
export const SortArrow: VFC<ISortArrowProps> = ({ export const SortArrow: VFC<ISortArrowProps> = ({
isSorted: sorted, isSorted: sorted,
isDesc: desc = false, isDesc: desc = false,
className, className,
}) => { }) => (
const { classes: styles } = useStyles(); <ConditionallyRender
condition={Boolean(sorted)}
return ( show={
<ConditionallyRender <ConditionallyRender
condition={Boolean(sorted)} condition={Boolean(desc)}
show={ show={
<ConditionallyRender <KeyboardArrowDown
condition={Boolean(desc)} sx={theme => ({
show={ ...iconStyle(theme),
<KeyboardArrowDown color: theme.palette.tableHeaderColor,
className={classnames( })}
styles.icon, className={className}
styles.sorted, fontSize="inherit"
className />
)} }
fontSize="inherit" elseShow={
/> <KeyboardArrowUp
} sx={theme => ({
elseShow={ ...iconStyle(theme),
<KeyboardArrowUp color: theme.palette.tableHeaderColor,
className={classnames( })}
styles.icon, className={className}
styles.sorted, fontSize="inherit"
className />
)} }
fontSize="inherit" />
/> }
} elseShow={
/> <UnfoldMoreOutlined
} sx={theme => ({
elseShow={ ...iconStyle(theme),
<UnfoldMoreOutlined })}
className={classnames(styles.icon, className, 'hover-only')} className={classnames(className, 'hover-only')}
fontSize="inherit" fontSize="inherit"
/> />
} }
/> />
); );
};

View File

@ -1,20 +0,0 @@
import { makeStyles } from 'tss-react/mui';
export const useStyles = makeStyles()(theme => ({
tableHeader: {
'& > th': {
height: theme.shape.tableRowHeightCompact,
border: 0,
backgroundColor: theme.palette.tableHeaderBackground,
color: theme.palette.tableHeaderColor,
'&:first-of-type': {
borderTopLeftRadius: theme.shape.borderRadiusMedium,
borderBottomLeftRadius: theme.shape.borderRadiusMedium,
},
'&:last-of-type': {
borderTopRightRadius: theme.shape.borderRadiusMedium,
borderBottomRightRadius: theme.shape.borderRadiusMedium,
},
},
},
}));

View File

@ -1,7 +1,6 @@
import { VFC } from 'react'; import { VFC } from 'react';
import { TableHead, TableRow } from '@mui/material'; import { styled, TableHead, TableRow } from '@mui/material';
import { HeaderGroup } from 'react-table'; import { HeaderGroup } from 'react-table';
import { useStyles } from './SortableTableHeader.styles';
import { CellSortable } from './CellSortable/CellSortable'; import { CellSortable } from './CellSortable/CellSortable';
interface ISortableTableHeaderProps { interface ISortableTableHeaderProps {
@ -10,52 +9,62 @@ interface ISortableTableHeaderProps {
flex?: boolean; flex?: boolean;
} }
const StyledTableRow = styled(TableRow)(({ theme }) => ({
'& > th': {
height: theme.shape.tableRowHeightCompact,
border: 0,
backgroundColor: theme.palette.tableHeaderBackground,
color: theme.palette.tableHeaderColor,
'&:first-of-type': {
borderTopLeftRadius: theme.shape.borderRadiusMedium,
borderBottomLeftRadius: theme.shape.borderRadiusMedium,
},
'&:last-of-type': {
borderTopRightRadius: theme.shape.borderRadiusMedium,
borderBottomRightRadius: theme.shape.borderRadiusMedium,
},
},
}));
export const SortableTableHeader: VFC<ISortableTableHeaderProps> = ({ export const SortableTableHeader: VFC<ISortableTableHeaderProps> = ({
headerGroups, headerGroups,
className, className,
flex, flex,
}) => { }) => (
const { classes: styles } = useStyles(); <TableHead className={className}>
{headerGroups.map(headerGroup => (
<StyledTableRow {...headerGroup.getHeaderGroupProps()}>
{headerGroup.headers.map((column: HeaderGroup) => {
const content = column.render('Header');
return ( return (
<TableHead className={className}> <CellSortable
{headerGroups.map(headerGroup => ( {...column.getHeaderProps(
<TableRow column.canSort
{...headerGroup.getHeaderGroupProps()} ? column.getSortByToggleProps()
className={styles.tableHeader} : undefined
> )}
{headerGroup.headers.map((column: HeaderGroup) => { ariaTitle={
const content = column.render('Header'); typeof content === 'string'
? content
return ( : undefined
<CellSortable }
{...column.getHeaderProps( isSortable={Boolean(column.canSort)}
column.canSort isSorted={column.isSorted}
? column.getSortByToggleProps() isDescending={column.isSortedDesc}
: undefined maxWidth={column.maxWidth}
)} minWidth={column.minWidth}
ariaTitle={ width={column.width}
typeof content === 'string' isFlex={flex}
? content isFlexGrow={Boolean(column.minWidth)}
: undefined // @ts-expect-error -- check after `react-table` v8
} align={column.align}
isSortable={Boolean(column.canSort)} >
isSorted={column.isSorted} {content}
isDescending={column.isSortedDesc} </CellSortable>
maxWidth={column.maxWidth} );
minWidth={column.minWidth} })}
width={column.width} </StyledTableRow>
isFlex={flex} ))}
isFlexGrow={Boolean(column.minWidth)} </TableHead>
// @ts-expect-error -- check after `react-table` v8 );
align={column.align}
>
{content}
</CellSortable>
);
})}
</TableRow>
))}
</TableHead>
);
};

View File

@ -1,19 +0,0 @@
import { makeStyles } from 'tss-react/mui';
export const useStyles = makeStyles<{
rowHeight: 'auto' | 'standard' | 'dense' | 'compact' | number;
}>()((theme, { rowHeight }) => ({
table: {
position: 'relative',
'& tbody tr': {
height:
{
auto: 'auto',
standard: theme.shape.tableRowHeight,
compact: theme.shape.tableRowHeightCompact,
dense: theme.shape.tableRowHeightDense,
}[rowHeight] ?? rowHeight,
},
},
}));

View File

@ -1,16 +1,24 @@
import { FC } from 'react'; import { FC } from 'react';
import classnames from 'classnames';
import { Table as MUITable, TableProps } from '@mui/material'; import { Table as MUITable, TableProps } from '@mui/material';
import { useStyles } from './Table.styles';
export const Table: FC< export const Table: FC<
TableProps & { TableProps & {
rowHeight?: 'auto' | 'dense' | 'standard' | 'compact' | number; rowHeight?: 'auto' | 'dense' | 'standard' | 'compact' | number;
} }
> = ({ rowHeight = 'auto', className, ...props }) => { > = ({ rowHeight = 'auto', ...props }) => (
const { classes } = useStyles({ rowHeight }); <MUITable
sx={{
return ( position: 'relative',
<MUITable className={classnames(classes.table, className)} {...props} /> '& tbody tr': {
); height: theme =>
}; ({
auto: 'auto',
standard: theme.shape.tableRowHeight,
compact: theme.shape.tableRowHeightCompact,
dense: theme.shape.tableRowHeightDense,
}[rowHeight] ?? rowHeight),
},
}}
{...props}
/>
);

View File

@ -1,7 +0,0 @@
import { makeStyles } from 'tss-react/mui';
export const useStyles = makeStyles()(theme => ({
tableCell: {
padding: 0,
},
}));

View File

@ -1,18 +1,16 @@
import { FC, ForwardedRef, forwardRef } from 'react'; import { FC, ForwardedRef, forwardRef } from 'react';
import classnames from 'classnames'; import {
import { TableCell as MUITableCell, TableCellProps } from '@mui/material'; styled,
import { useStyles } from './TableCell.styles'; TableCell as MUITableCell,
TableCellProps,
} from '@mui/material';
const StyledTableCell = styled(MUITableCell)(({ theme }) => ({
padding: 0,
}));
export const TableCell: FC<TableCellProps> = forwardRef( export const TableCell: FC<TableCellProps> = forwardRef(
({ className, ...props }, ref: ForwardedRef<unknown>) => { ({ className, ...props }, ref: ForwardedRef<unknown>) => (
const { classes: styles } = useStyles(); <StyledTableCell {...props} ref={ref} />
)
return (
<MUITableCell
className={classnames(styles.tableCell, className)}
{...props}
ref={ref}
/>
);
}
); );

View File

@ -1,14 +0,0 @@
import { makeStyles } from 'tss-react/mui';
export const useStyles = makeStyles()(theme => ({
emptyStateListItem: {
border: `2px dashed ${theme.palette.neutral.light}`,
padding: '0.8rem',
textAlign: 'center',
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
marginTop: theme.spacing(2),
width: '100%',
},
}));

View File

@ -1,9 +1,19 @@
import { FC } from 'react'; import { FC } from 'react';
import { Box } from '@mui/material'; import { Box } from '@mui/material';
import { useStyles } from 'component/common/Table/TablePlaceholder/TablePlaceholder.styles';
export const TablePlaceholder: FC = ({ children }) => { export const TablePlaceholder: FC = ({ children }) => (
const { classes: styles } = useStyles(); <Box
sx={{
return <Box className={styles.emptyStateListItem}>{children}</Box>; border: theme => `2px dashed ${theme.palette.neutral.light}`,
}; p: 1.6,
textAlign: 'center',
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
mt: 2,
width: '100%',
}}
>
{children}
</Box>
);

View File

@ -1,21 +0,0 @@
import { makeStyles } from 'tss-react/mui';
export const useStyles = makeStyles()(() => ({
row: {
position: 'absolute',
width: '100%',
'&:hover': {
'.show-row-hover': {
opacity: 1,
},
},
},
cell: {
alignItems: 'center',
display: 'flex',
flexShrink: 0,
'& > *': {
flexGrow: 1,
},
},
}));

View File

@ -3,12 +3,11 @@ import { useTheme } from '@mui/material';
import { import {
SortableTableHeader, SortableTableHeader,
Table, Table,
TableCell,
TableBody, TableBody,
TableRow, TableRow,
TableCell,
} from 'component/common/Table'; } from 'component/common/Table';
import { useVirtualizedRange } from 'hooks/useVirtualizedRange'; import { useVirtualizedRange } from 'hooks/useVirtualizedRange';
import { useStyles } from './VirtualizedTable.styles';
import { HeaderGroup, Row } from 'react-table'; import { HeaderGroup, Row } from 'react-table';
interface IVirtualizedTableProps { interface IVirtualizedTableProps {
@ -34,7 +33,6 @@ export const VirtualizedTable: VFC<IVirtualizedTableProps> = ({
rows, rows,
prepareRow, prepareRow,
}) => { }) => {
const { classes } = useStyles();
const theme = useTheme(); const theme = useTheme();
const rowHeight = useMemo( const rowHeight = useMemo(
() => rowHeightOverride || theme.shape.tableRowHeight, () => rowHeightOverride || theme.shape.tableRowHeight,
@ -56,7 +54,28 @@ export const VirtualizedTable: VFC<IVirtualizedTableProps> = ({
style={{ height: tableHeight }} style={{ height: tableHeight }}
> >
<SortableTableHeader headerGroups={headerGroups} flex /> <SortableTableHeader headerGroups={headerGroups} flex />
<TableBody role="rowgroup"> <TableBody
role="rowgroup"
sx={{
'& tr': {
position: 'absolute',
width: '100%',
'&:hover': {
'.show-row-hover': {
opacity: 1,
},
},
},
'& tr td': {
alignItems: 'center',
display: 'flex',
flexShrink: 0,
'& > *': {
flexGrow: 1,
},
},
}}
>
{rows.map((row, index) => { {rows.map((row, index) => {
const top = const top =
index * rowHeight + theme.shape.tableRowHeightCompact; index * rowHeight + theme.shape.tableRowHeightCompact;
@ -73,10 +92,10 @@ export const VirtualizedTable: VFC<IVirtualizedTableProps> = ({
return ( return (
<TableRow <TableRow
hover hover
{...row.getRowProps()} {...row.getRowProps({
style: { display: 'flex', top },
})}
key={row.id} key={row.id}
className={classes.row}
style={{ display: 'flex', top }}
> >
{row.cells.map(cell => ( {row.cells.map(cell => (
<TableCell <TableCell
@ -87,7 +106,6 @@ export const VirtualizedTable: VFC<IVirtualizedTableProps> = ({
: undefined, : undefined,
}, },
})} })}
className={classes.cell}
> >
{cell.render('Cell')} {cell.render('Cell')}
</TableCell> </TableCell>

View File

@ -1,15 +0,0 @@
import { makeStyles } from 'tss-react/mui';
export const useStyles = makeStyles()(theme => ({
container: {
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
padding: theme.spacing(0, 1.5),
},
divider: {
borderColor: theme.palette.dividerAlternative,
height: theme.spacing(3),
margin: theme.spacing(0, 2),
},
}));

View File

@ -1,24 +1,27 @@
import { Box, Divider } from '@mui/material'; import { Box, Divider, styled } from '@mui/material';
import { FC, VFC } from 'react'; import { FC, VFC } from 'react';
import { useStyles } from './ActionCell.styles';
const ActionCellDivider: VFC = () => { const StyledContainer = styled(Box)(({ theme }) => ({
const { classes } = useStyles(); display: 'flex',
return ( justifyContent: 'center',
<Divider alignItems: 'center',
className={classes.divider} padding: theme.spacing(0, 1.5),
orientation="vertical" }));
variant="middle"
/> const StyledDivider = styled(Divider)(({ theme }) => ({
); borderColor: theme.palette.dividerAlternative,
}; height: theme.spacing(3),
margin: theme.spacing(0, 2),
}));
const ActionCellDivider: VFC = () => (
<StyledDivider orientation="vertical" variant="middle" />
);
const ActionCellComponent: FC & { const ActionCellComponent: FC & {
Divider: typeof ActionCellDivider; Divider: typeof ActionCellDivider;
} = ({ children }) => { } = ({ children }) => {
const { classes } = useStyles(); return <StyledContainer>{children}</StyledContainer>;
return <Box className={classes.container}>{children}</Box>;
}; };
ActionCellComponent.Divider = ActionCellDivider; ActionCellComponent.Divider = ActionCellDivider;

View File

@ -1,20 +0,0 @@
import { makeStyles } from 'tss-react/mui';
export const useStyles = makeStyles()(theme => ({
container: {
display: 'flex',
padding: theme.spacing(1.5),
},
box: {
width: '38px',
height: '38px',
background: 'gray',
borderRadius: '4px',
textAlign: 'center',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
fontSize: theme.fontSizes.smallerBody,
margin: '0 auto',
},
}));

View File

@ -1,8 +1,7 @@
import React, { FC, VFC } from 'react'; import React, { FC, VFC } from 'react';
import TimeAgo from 'react-timeago'; import TimeAgo from 'react-timeago';
import { Tooltip, useTheme } from '@mui/material'; import { styled, Tooltip, useTheme } from '@mui/material';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import { useStyles } from './FeatureSeenCell.styles';
function shortenUnitName(unit?: string): string { function shortenUnitName(unit?: string): string {
switch (unit) { switch (unit) {
@ -50,6 +49,24 @@ const useFeatureColor = () => {
}; };
}; };
const StyledContainer = styled('div')(({ theme }) => ({
display: 'flex',
padding: theme.spacing(1.5),
}));
const StyledBox = styled('div')(({ theme }) => ({
width: '38px',
height: '38px',
background: theme.palette.background.paper,
borderRadius: `${theme.shape.borderRadius}px`,
textAlign: 'center',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
fontSize: theme.typography.body2.fontSize,
margin: '0 auto',
}));
interface IFeatureSeenCellProps { interface IFeatureSeenCellProps {
value?: string | Date | null; value?: string | Date | null;
} }
@ -59,21 +76,16 @@ const Wrapper: FC<{ unit?: string; tooltip: string }> = ({
tooltip, tooltip,
children, children,
}) => { }) => {
const { classes: styles } = useStyles();
const getColor = useFeatureColor(); const getColor = useFeatureColor();
return ( return (
<div className={styles.container}> <StyledContainer>
<Tooltip title={tooltip} arrow describeChild> <Tooltip title={tooltip} arrow describeChild>
<div <StyledBox style={{ background: getColor(unit) }} data-loading>
className={styles.box}
style={{ background: getColor(unit) }}
data-loading
>
{children} {children}
</div> </StyledBox>
</Tooltip> </Tooltip>
</div> </StyledContainer>
); );
}; };

View File

@ -1,15 +1,21 @@
import { VFC } from 'react'; import { VFC } from 'react';
import { Tooltip } from '@mui/material'; import { styled, Tooltip } from '@mui/material';
import { getFeatureTypeIcons } from 'utils/getFeatureTypeIcons'; import { getFeatureTypeIcons } from 'utils/getFeatureTypeIcons';
import useFeatureTypes from 'hooks/api/getters/useFeatureTypes/useFeatureTypes'; import useFeatureTypes from 'hooks/api/getters/useFeatureTypes/useFeatureTypes';
import { useStyles } from './FeatureTypeCell.styles';
interface IFeatureTypeProps { interface IFeatureTypeProps {
value?: string; value?: string;
} }
const StyledContainer = styled('div')(({ theme }) => ({
padding: theme.spacing(1.5),
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
color: theme.palette.text.disabled,
}));
export const FeatureTypeCell: VFC<IFeatureTypeProps> = ({ value }) => { export const FeatureTypeCell: VFC<IFeatureTypeProps> = ({ value }) => {
const { classes: styles } = useStyles();
const { featureTypes } = useFeatureTypes(); const { featureTypes } = useFeatureTypes();
const IconComponent = getFeatureTypeIcons(value); const IconComponent = getFeatureTypeIcons(value);
@ -20,10 +26,10 @@ export const FeatureTypeCell: VFC<IFeatureTypeProps> = ({ value }) => {
const title = `This is a "${typeName || value}" toggle`; const title = `This is a "${typeName || value}" toggle`;
return ( return (
<div className={styles.container}> <StyledContainer>
<Tooltip arrow title={title} describeChild> <Tooltip arrow title={title} describeChild>
<IconComponent data-loading className={styles.icon} /> <IconComponent data-loading />
</Tooltip> </Tooltip>
</div> </StyledContainer>
); );
}; };

View File

@ -1,29 +0,0 @@
import { makeStyles } from 'tss-react/mui';
export const useStyles = makeStyles()(theme => ({
container: {
display: 'flex',
flexDirection: 'column',
justifyContent: 'center',
wordBreak: 'break-word',
padding: theme.spacing(1, 2),
},
title: {
overflow: 'hidden',
textOverflow: 'ellipsis',
display: '-webkit-box',
WebkitBoxOrient: 'vertical',
WebkitLineClamp: '1',
lineClamp: '1',
},
subtitle: {
color: theme.palette.text.secondary,
overflow: 'hidden',
textOverflow: 'ellipsis',
fontSize: 'inherit',
WebkitLineClamp: '1',
lineClamp: '1',
display: '-webkit-box',
WebkitBoxOrient: 'vertical',
},
}));

View File

@ -1,8 +1,7 @@
import { VFC } from 'react'; import { VFC } from 'react';
import { Highlighter } from 'component/common/Highlighter/Highlighter'; import { Highlighter } from 'component/common/Highlighter/Highlighter';
import { useSearchHighlightContext } from 'component/common/Table/SearchHighlightContext/SearchHighlightContext'; import { useSearchHighlightContext } from 'component/common/Table/SearchHighlightContext/SearchHighlightContext';
import { Box, Typography } from '@mui/material'; import { Box, styled } from '@mui/material';
import { useStyles } from './HighlightCell.styles';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
interface IHighlightCellProps { interface IHighlightCellProps {
@ -10,17 +9,43 @@ interface IHighlightCellProps {
subtitle?: string; subtitle?: string;
} }
const StyledContainer = styled(Box)(({ theme }) => ({
display: 'flex',
flexDirection: 'column',
justifyContent: 'center',
wordBreak: 'break-word',
padding: theme.spacing(1, 2),
}));
const StyledTitle = styled('span')(({ theme }) => ({
overflow: 'hidden',
textOverflow: 'ellipsis',
display: '-webkit-box',
WebkitBoxOrient: 'vertical',
WebkitLineClamp: '1',
lineClamp: '1',
}));
const StyledSubtitle = styled('span')(({ theme }) => ({
color: theme.palette.text.secondary,
overflow: 'hidden',
textOverflow: 'ellipsis',
fontSize: 'inherit',
WebkitLineClamp: '1',
lineClamp: '1',
display: '-webkit-box',
WebkitBoxOrient: 'vertical',
}));
export const HighlightCell: VFC<IHighlightCellProps> = ({ export const HighlightCell: VFC<IHighlightCellProps> = ({
value, value,
subtitle, subtitle,
}) => { }) => {
const { searchQuery } = useSearchHighlightContext(); const { searchQuery } = useSearchHighlightContext();
const { classes } = useStyles();
return ( return (
<Box className={classes.container}> <StyledContainer>
<span <StyledTitle
className={classes.title}
style={{ style={{
WebkitLineClamp: Boolean(subtitle) ? 1 : 2, WebkitLineClamp: Boolean(subtitle) ? 1 : 2,
lineClamp: Boolean(subtitle) ? 1 : 2, lineClamp: Boolean(subtitle) ? 1 : 2,
@ -28,21 +53,17 @@ export const HighlightCell: VFC<IHighlightCellProps> = ({
data-loading data-loading
> >
<Highlighter search={searchQuery}>{value}</Highlighter> <Highlighter search={searchQuery}>{value}</Highlighter>
</span> </StyledTitle>
<ConditionallyRender <ConditionallyRender
condition={Boolean(subtitle)} condition={Boolean(subtitle)}
show={() => ( show={() => (
<Typography <StyledSubtitle data-loading>
component="span"
className={classes.subtitle}
data-loading
>
<Highlighter search={searchQuery}> <Highlighter search={searchQuery}>
{subtitle} {subtitle}
</Highlighter> </Highlighter>
</Typography> </StyledSubtitle>
)} )}
/> />
</Box> </StyledContainer>
); );
}; };

View File

@ -1,44 +1,53 @@
import { makeStyles } from 'tss-react/mui'; import { Link, styled, Theme } from '@mui/material';
import { ComponentType } from 'react';
export const useStyles = makeStyles()(theme => ({ export const wrapperStyles = (theme: Theme) => ({
wrapper: { paddingTop: theme.spacing(1.5),
paddingTop: theme.spacing(1.5), paddingBottom: theme.spacing(1.5),
paddingBottom: theme.spacing(1.5), paddingLeft: theme.spacing(2),
paddingLeft: theme.spacing(2), paddingRight: theme.spacing(2),
paddingRight: theme.spacing(2), display: 'flex',
display: 'flex', alignItems: 'center',
alignItems: 'center', minHeight: '62px',
minHeight: '62px', });
},
link: { export const StyledWrapper = styled('div')(({ theme }) => wrapperStyles(theme));
'&:hover, &:focus': {
textDecoration: 'none', export const StyledLink = styled(Link)<{
'& > div > span:first-of-type': { component?: ComponentType<any>;
textDecoration: 'underline', to?: string;
}, }>(({ theme }) => ({
...wrapperStyles(theme),
'&:hover, &:focus': {
textDecoration: 'none',
'& > div > span:first-of-type': {
textDecoration: 'underline',
}, },
}, },
container: { }));
display: 'flex',
flexDirection: 'column', export const StyledContainer = styled('div')(({ theme }) => ({
justifyContent: 'center', display: 'flex',
wordBreak: 'break-all', flexDirection: 'column',
}, justifyContent: 'center',
title: { wordBreak: 'break-all',
overflow: 'hidden', }));
textOverflow: 'ellipsis',
display: '-webkit-box', export const StyledTitle = styled('span')(({ theme }) => ({
WebkitBoxOrient: 'vertical', overflow: 'hidden',
}, textOverflow: 'ellipsis',
description: { display: '-webkit-box',
color: theme.palette.text.secondary, WebkitBoxOrient: 'vertical',
textDecoration: 'none', }));
fontSize: 'inherit',
WebkitLineClamp: 1, export const StyledDescription = styled('span')(({ theme }) => ({
lineClamp: 1, color: theme.palette.text.secondary,
overflow: 'hidden', textDecoration: 'none',
textOverflow: 'ellipsis', fontSize: 'inherit',
display: '-webkit-box', WebkitLineClamp: 1,
WebkitBoxOrient: 'vertical', lineClamp: 1,
}, overflow: 'hidden',
textOverflow: 'ellipsis',
display: '-webkit-box',
WebkitBoxOrient: 'vertical',
})); }));

View File

@ -1,11 +1,16 @@
import { FC } from 'react'; import { ComponentType, FC } from 'react';
import { Link, Typography } from '@mui/material'; import { Link, styled, Typography } from '@mui/material';
import { Link as RouterLink } from 'react-router-dom'; import { Link as RouterLink } from 'react-router-dom';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import { useStyles } from './LinkCell.styles';
import { Highlighter } from 'component/common/Highlighter/Highlighter'; import { Highlighter } from 'component/common/Highlighter/Highlighter';
import { useSearchHighlightContext } from 'component/common/Table/SearchHighlightContext/SearchHighlightContext'; import { useSearchHighlightContext } from 'component/common/Table/SearchHighlightContext/SearchHighlightContext';
import classnames from 'classnames'; import {
StyledWrapper,
StyledLink,
StyledContainer,
StyledTitle,
StyledDescription,
} from './LinkCell.styles';
interface ILinkCellProps { interface ILinkCellProps {
title?: string; title?: string;
@ -21,14 +26,12 @@ export const LinkCell: FC<ILinkCellProps> = ({
subtitle, subtitle,
children, children,
}) => { }) => {
const { classes: styles } = useStyles();
const { searchQuery } = useSearchHighlightContext(); const { searchQuery } = useSearchHighlightContext();
const content = ( const content = (
<div className={styles.container}> <StyledContainer>
<span <StyledTitle
data-loading data-loading
className={styles.title}
style={{ style={{
WebkitLineClamp: Boolean(subtitle) ? 1 : 2, WebkitLineClamp: Boolean(subtitle) ? 1 : 2,
lineClamp: Boolean(subtitle) ? 1 : 2, lineClamp: Boolean(subtitle) ? 1 : 2,
@ -36,44 +39,31 @@ export const LinkCell: FC<ILinkCellProps> = ({
> >
<Highlighter search={searchQuery}>{title}</Highlighter> <Highlighter search={searchQuery}>{title}</Highlighter>
{children} {children}
</span> </StyledTitle>
<ConditionallyRender <ConditionallyRender
condition={Boolean(subtitle)} condition={Boolean(subtitle)}
show={ show={
<> <>
<Typography <StyledDescription data-loading>
className={styles.description}
component="span"
data-loading
>
<Highlighter search={searchQuery}> <Highlighter search={searchQuery}>
{subtitle} {subtitle}
</Highlighter> </Highlighter>
</Typography> </StyledDescription>
</> </>
} }
/> />
</div> </StyledContainer>
); );
return to ? ( return to ? (
<Link <StyledLink component={RouterLink} to={to} underline="hover">
component={RouterLink}
to={to}
underline="hover"
className={classnames(styles.wrapper, styles.link)}
>
{content} {content}
</Link> </StyledLink>
) : onClick ? ( ) : onClick ? (
<Link <StyledLink onClick={onClick} underline="hover">
onClick={onClick}
underline="hover"
className={classnames(styles.wrapper, styles.link)}
>
{content} {content}
</Link> </StyledLink>
) : ( ) : (
<span className={styles.wrapper}>{content}</span> <StyledWrapper>{content}</StyledWrapper>
); );
}; };

View File

@ -1,17 +0,0 @@
import { makeStyles } from 'tss-react/mui';
export const useStyles = makeStyles<{ lineClamp?: number }>()(
(theme, { lineClamp }) => ({
wrapper: {
padding: theme.spacing(1, 2),
display: '-webkit-box',
overflow: lineClamp ? 'hidden' : 'auto',
WebkitLineClamp: lineClamp ? lineClamp : 'none',
WebkitBoxOrient: 'vertical',
wordBreak: 'break-all',
[theme.breakpoints.down('sm')]: {
wordBreak: 'normal',
},
},
})
);

View File

@ -1,6 +1,5 @@
import { FC } from 'react'; import { FC } from 'react';
import { Box, SxProps, Theme } from '@mui/material'; import { Box, styled, SxProps, Theme } from '@mui/material';
import { useStyles } from './TextCell.styles';
interface ITextCellProps { interface ITextCellProps {
value?: string | null; value?: string | null;
@ -9,20 +8,30 @@ interface ITextCellProps {
sx?: SxProps<Theme>; sx?: SxProps<Theme>;
} }
const StyledWrapper = styled(Box, {
shouldForwardProp: prop => prop !== 'lineClamp',
})<{ lineClamp?: number }>(({ theme, lineClamp }) => ({
padding: theme.spacing(1, 2),
display: '-webkit-box',
overflow: lineClamp ? 'hidden' : 'auto',
WebkitLineClamp: lineClamp ? lineClamp : 'none',
WebkitBoxOrient: 'vertical',
wordBreak: 'break-all',
[theme.breakpoints.down('sm')]: {
wordBreak: 'normal',
},
}));
export const TextCell: FC<ITextCellProps> = ({ export const TextCell: FC<ITextCellProps> = ({
value, value,
children, children,
lineClamp, lineClamp,
sx, sx,
'data-testid': testid, 'data-testid': testid,
}) => { }) => (
const { classes } = useStyles({ lineClamp }); <StyledWrapper lineClamp={lineClamp} sx={sx}>
<span data-loading="true" data-testid={testid}>
return ( {children ?? value}
<Box className={classes.wrapper} sx={sx}> </span>
<span data-loading="true" data-testid={testid}> </StyledWrapper>
{children ?? value} );
</span>
</Box>
);
};

View File

@ -1,10 +0,0 @@
import { makeStyles } from 'tss-react/mui';
export const useStyles = makeStyles()(theme => ({
toastWrapper: {
right: 0,
left: 0,
margin: '0 auto',
maxWidth: '450px',
},
}));

View File

@ -1,16 +1,17 @@
import { Portal } from '@mui/material'; import { Portal } from '@mui/material';
import { useContext, useEffect } from 'react'; import { useContext, useEffect, useMemo } from 'react';
import { useThemeStyles } from 'themes/themeStyles'; import {
fadeInBottomEnter,
fadeInBottomLeave,
fadeInBottomStartWithoutFixed,
} from 'themes/themeStyles';
import UIContext from 'contexts/UIContext'; import UIContext from 'contexts/UIContext';
import { useStyles } from './ToastRenderer.styles';
import AnimateOnMount from '../AnimateOnMount/AnimateOnMount'; import AnimateOnMount from '../AnimateOnMount/AnimateOnMount';
import Toast from './Toast/Toast'; import Toast from './Toast/Toast';
import { IToast } from 'interfaces/toast'; import { IToast } from 'interfaces/toast';
const ToastRenderer = () => { const ToastRenderer = () => {
const { toastData, setToast } = useContext(UIContext); const { toastData, setToast } = useContext(UIContext);
const { classes: themeStyles } = useThemeStyles();
const { classes: styles } = useStyles();
const hide = () => { const hide = () => {
setToast((prev: IToast) => ({ ...prev, show: false })); setToast((prev: IToast) => ({ ...prev, show: false }));
@ -28,14 +29,28 @@ const ToastRenderer = () => {
/* eslint-disable-next-line */ /* eslint-disable-next-line */
}, [toastData?.show]); }, [toastData?.show]);
const animations = useMemo(
() => ({
start: {
...fadeInBottomStartWithoutFixed,
right: 0,
left: 0,
margin: '0 auto',
maxWidth: '450px',
},
enter: fadeInBottomEnter,
leave: fadeInBottomLeave,
}),
[]
);
return ( return (
<Portal> <Portal>
<AnimateOnMount <AnimateOnMount
mounted={Boolean(toastData?.show)} mounted={Boolean(toastData?.show)}
start={themeStyles.fadeInBottomStartWithoutFixed} start={animations.start}
enter={themeStyles.fadeInBottomEnter} enter={animations.enter}
leave={themeStyles.fadeInBottomLeave} leave={animations.leave}
container={styles.toastWrapper}
> >
<Toast {...toastData} /> <Toast {...toastData} />
</AnimateOnMount> </AnimateOnMount>

View File

@ -1,37 +0,0 @@
import { makeStyles } from 'tss-react/mui';
export const useStyles = makeStyles()(theme => ({
feedback: {
borderRadius: '12.5px',
backgroundColor: theme.palette.background.paper,
zIndex: 9999,
boxShadow: '2px 2px 4px 4px rgba(143,143,143, 0.25)',
padding: '1.5rem',
maxWidth: '400px',
},
animateContainer: {
zIndex: 9999,
},
container: {
display: 'flex',
flexDirection: 'column',
position: 'relative',
},
close: {
position: 'absolute',
right: '-38px',
top: '-47px',
backgroundColor: theme.palette.background.paper,
boxShadow: '2px 2px 4px 4px rgba(143,143,143, 0.25)',
['&:hover']: {
backgroundColor: '#fff',
},
},
logo: {
width: '25px',
height: '25px',
},
cancel: {
marginLeft: '1rem',
},
}));

View File

@ -1,12 +1,15 @@
import { useContext, useState } from 'react'; import { useContext, useMemo, useState } from 'react';
import { Button, IconButton, Tooltip } from '@mui/material'; import { Box, Button, IconButton, Tooltip, useTheme } from '@mui/material';
import classnames from 'classnames';
import CloseIcon from '@mui/icons-material/Close'; import CloseIcon from '@mui/icons-material/Close';
import { ReactComponent as Logo } from 'assets/icons/logoPlain.svg'; import { ReactComponent as Logo } from 'assets/icons/logoPlain.svg';
import { useStyles } from 'component/feedback/FeedbackNPS/FeedbackNPS.styles';
import AnimateOnMount from 'component/common/AnimateOnMount/AnimateOnMount'; import AnimateOnMount from 'component/common/AnimateOnMount/AnimateOnMount';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import { useThemeStyles } from 'themes/themeStyles'; import {
contentSpacingY,
fadeInTopEnter,
fadeInTopLeave,
fadeInTopStart,
} from 'themes/themeStyles';
import UIContext from 'contexts/UIContext'; import UIContext from 'contexts/UIContext';
import { import {
PNPS_FEEDBACK_ID, PNPS_FEEDBACK_ID,
@ -24,10 +27,18 @@ export const FeedbackNPS = ({ openUrl }: IFeedbackNPSProps) => {
const { createFeedback, updateFeedback } = useAuthFeedbackApi(); const { createFeedback, updateFeedback } = useAuthFeedbackApi();
const { feedback } = useAuthFeedback(); const { feedback } = useAuthFeedback();
const [answeredNotNow, setAnsweredNotNow] = useState(false); const [answeredNotNow, setAnsweredNotNow] = useState(false);
const { classes: styles } = useStyles(); const theme = useTheme();
const { classes: themeStyles } = useThemeStyles();
const feedbackId = PNPS_FEEDBACK_ID; const feedbackId = PNPS_FEEDBACK_ID;
const animations = useMemo(
() => ({
start: { ...fadeInTopStart(theme), zIndex: theme.zIndex.tooltip },
enter: fadeInTopEnter,
leave: fadeInTopLeave,
}),
[theme]
);
const onConfirm = async () => { const onConfirm = async () => {
try { try {
await createFeedback({ feedbackId }); await createFeedback({ feedbackId });
@ -61,28 +72,53 @@ export const FeedbackNPS = ({ openUrl }: IFeedbackNPSProps) => {
return ( return (
<AnimateOnMount <AnimateOnMount
mounted={showFeedback} mounted={showFeedback}
start={themeStyles.fadeInTopStart} start={animations.start}
enter={themeStyles.fadeInTopEnter} enter={animations.enter}
leave={themeStyles.fadeInTopLeave} leave={animations.leave}
container={styles.animateContainer}
> >
<div className={styles.feedback}> <Box
<div sx={{
className={classnames( borderRadius: '12.5px',
styles.container, backgroundColor: theme.palette.background.paper,
themeStyles.contentSpacingY zIndex: 9999,
)} boxShadow: '2px 2px 4px 4px rgba(143,143,143, 0.25)',
padding: theme.spacing(3),
maxWidth: '400px',
}}
>
<Box
sx={{
display: 'flex',
flexDirection: 'column',
position: 'relative',
...contentSpacingY(theme),
}}
> >
<Tooltip title="Close" arrow> <Tooltip title="Close" arrow>
<IconButton <IconButton
className={styles.close} sx={{
position: 'absolute',
right: '-38px',
top: '-47px',
backgroundColor: theme.palette.background.paper,
boxShadow:
'2px 2px 4px 4px rgba(143,143,143, 0.25)',
'&:hover': {
backgroundColor: '#fff',
},
}}
onClick={() => setShowFeedback(false)} onClick={() => setShowFeedback(false)}
size="large" size="large"
> >
<CloseIcon /> <CloseIcon />
</IconButton> </IconButton>
</Tooltip> </Tooltip>
<Logo className={styles.logo} /> <Logo
style={{
width: '25px',
height: '25px',
}}
/>
<ConditionallyRender <ConditionallyRender
condition={answeredNotNow} condition={answeredNotNow}
show={ show={
@ -99,7 +135,7 @@ export const FeedbackNPS = ({ openUrl }: IFeedbackNPSProps) => {
} }
/> />
<div> <Box>
<ConditionallyRender <ConditionallyRender
condition={answeredNotNow} condition={answeredNotNow}
show={ show={
@ -120,7 +156,10 @@ export const FeedbackNPS = ({ openUrl }: IFeedbackNPSProps) => {
Yes, no problem Yes, no problem
</Button> </Button>
<Button <Button
className={styles.cancel} sx={{
marginLeft: theme =>
theme.spacing(2),
}}
onClick={() => setAnsweredNotNow(true)} onClick={() => setAnsweredNotNow(true)}
> >
Not now Not now
@ -128,9 +167,9 @@ export const FeedbackNPS = ({ openUrl }: IFeedbackNPSProps) => {
</> </>
} }
/> />
</div> </Box>
</div> </Box>
</div> </Box>
</AnimateOnMount> </AnimateOnMount>
); );
}; };

View File

@ -6,8 +6,8 @@ import Proclamation from 'component/common/Proclamation/Proclamation';
import BreadcrumbNav from 'component/common/BreadcrumbNav/BreadcrumbNav'; import BreadcrumbNav from 'component/common/BreadcrumbNav/BreadcrumbNav';
import textureImage from 'assets/img/texture.png'; import textureImage from 'assets/img/texture.png';
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig'; import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
import { SkipNavLink } from 'component/common/SkipNav/SkipNavLink'; import { SkipNavLink } from 'component/common/SkipNavLink/SkipNavLink';
import { SkipNavTarget } from 'component/common/SkipNav/SkipNavTarget'; import { SkipNavTarget } from 'component/common/SkipNavLink/SkipNavTarget';
import { formatAssetPath } from 'utils/formatPath'; import { formatAssetPath } from 'utils/formatPath';
import { useOptionalPathParam } from 'hooks/useOptionalPathParam'; import { useOptionalPathParam } from 'hooks/useOptionalPathParam';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';

View File

@ -32,14 +32,14 @@ exports[`renders an empty list correctly 1`] = `
className="css-j2179i" className="css-j2179i"
> >
<div <div
className="css-1oozr04-container" className="css-uds21r"
> >
<div <div
className="css-1xjrf9m-search search-container" className="css-19ebc6o"
> >
<svg <svg
aria-hidden={true} aria-hidden={true}
className="MuiSvgIcon-root MuiSvgIcon-fontSizeMedium search-icon css-1kyy7n4-MuiSvgIcon-root-searchIcon" className="MuiSvgIcon-root MuiSvgIcon-fontSizeMedium css-1dfm5ba-MuiSvgIcon-root"
data-testid="SearchIcon" data-testid="SearchIcon"
focusable="false" focusable="false"
viewBox="0 0 24 24" viewBox="0 0 24 24"
@ -49,7 +49,7 @@ exports[`renders an empty list correctly 1`] = `
/> />
</svg> </svg>
<div <div
className="MuiInputBase-root input-container MuiInputBase-colorPrimary css-tubodl-MuiInputBase-root-inputRoot" className="MuiInputBase-root MuiInputBase-colorPrimary css-1vp7ju7-MuiInputBase-root"
onClick={[Function]} onClick={[Function]}
> >
<input <input
@ -65,7 +65,7 @@ exports[`renders an empty list correctly 1`] = `
/> />
</div> </div>
<div <div
className="css-llttyo-clearContainer clear-container" className="MuiBox-root css-1ty7gog"
/> />
</div> </div>
</div> </div>
@ -112,7 +112,7 @@ exports[`renders an empty list correctly 1`] = `
className="body css-ccg7sp-bodyContainer" className="body css-ccg7sp-bodyContainer"
> >
<table <table
className="MuiTable-root css-1h6dscb-MuiTable-root-table" className="MuiTable-root css-1repbac-MuiTable-root"
role="table" role="table"
> >
<thead <thead
@ -120,11 +120,11 @@ exports[`renders an empty list correctly 1`] = `
role={null} role={null}
> >
<tr <tr
className="MuiTableRow-root MuiTableRow-head css-1gnoged-MuiTableRow-root-tableHeader" className="MuiTableRow-root MuiTableRow-head css-1b9hsk7-MuiTableRow-root"
role="row" role="row"
> >
<th <th
className="MuiTableCell-root MuiTableCell-head MuiTableCell-sizeMedium css-b9leyc-MuiTableCell-root-header" className="MuiTableCell-root MuiTableCell-head MuiTableCell-sizeMedium css-uzyimr-MuiTableCell-root"
scope="col" scope="col"
style={ style={
{ {
@ -140,7 +140,7 @@ exports[`renders an empty list correctly 1`] = `
</th> </th>
<th <th
aria-sort="ascending" aria-sort="ascending"
className="MuiTableCell-root MuiTableCell-head MuiTableCell-sizeMedium css-masipn-MuiTableCell-root-header-sortable" className="MuiTableCell-root MuiTableCell-head MuiTableCell-sizeMedium css-1ts7or6-MuiTableCell-root"
scope="col" scope="col"
style={ style={
{ {
@ -153,7 +153,7 @@ exports[`renders an empty list correctly 1`] = `
<button <button
aria-label="" aria-label=""
aria-labelledby={null} aria-labelledby={null}
className="css-14l86a5-sortedButton css-1inbba3-sortButton" className=" css-1xwc11x"
data-mui-internal-clone-element={true} data-mui-internal-clone-element={true}
onBlur={[Function]} onBlur={[Function]}
onClick={[Function]} onClick={[Function]}
@ -166,10 +166,10 @@ exports[`renders an empty list correctly 1`] = `
> >
<span <span
aria-hidden={true} aria-hidden={true}
className="css-r8z9jm-hiddenMeasurementLayer" className="css-15yxmxx"
> >
<span <span
className="css-1j5tskk-label" className="css-1w3kvnb"
data-text="Name" data-text="Name"
tabIndex={-1} tabIndex={-1}
> >
@ -177,7 +177,7 @@ exports[`renders an empty list correctly 1`] = `
</span> </span>
<svg <svg
aria-hidden={true} aria-hidden={true}
className="MuiSvgIcon-root MuiSvgIcon-fontSizeInherit css-1ekkz6x-MuiSvgIcon-root-icon-sorted" className="MuiSvgIcon-root MuiSvgIcon-fontSizeInherit css-57xzpo-MuiSvgIcon-root"
data-testid="KeyboardArrowUpIcon" data-testid="KeyboardArrowUpIcon"
focusable="false" focusable="false"
viewBox="0 0 24 24" viewBox="0 0 24 24"
@ -188,7 +188,7 @@ exports[`renders an empty list correctly 1`] = `
</svg> </svg>
</span> </span>
<span <span
className="css-bqel7i-visibleAbsoluteLayer" className="css-y8b3t8"
> >
<span <span
tabIndex={-1} tabIndex={-1}
@ -199,7 +199,7 @@ exports[`renders an empty list correctly 1`] = `
</span> </span>
<svg <svg
aria-hidden={true} aria-hidden={true}
className="MuiSvgIcon-root MuiSvgIcon-fontSizeInherit sort-arrow css-1ekkz6x-MuiSvgIcon-root-icon-sorted" className="MuiSvgIcon-root MuiSvgIcon-fontSizeInherit sort-arrow css-57xzpo-MuiSvgIcon-root"
data-testid="KeyboardArrowUpIcon" data-testid="KeyboardArrowUpIcon"
focusable="false" focusable="false"
viewBox="0 0 24 24" viewBox="0 0 24 24"
@ -212,7 +212,7 @@ exports[`renders an empty list correctly 1`] = `
</button> </button>
</th> </th>
<th <th
className="MuiTableCell-root MuiTableCell-head MuiTableCell-sizeMedium css-b9leyc-MuiTableCell-root-header" className="MuiTableCell-root MuiTableCell-head MuiTableCell-sizeMedium css-uzyimr-MuiTableCell-root"
scope="col" scope="col"
style={ style={
{ {
@ -223,7 +223,12 @@ exports[`renders an empty list correctly 1`] = `
} }
> >
<div <div
className="css-1x6va6g-alignCenter" style={
{
"justifyContent": "center",
"textAlign": "center",
}
}
> >
Actions Actions
</div> </div>
@ -240,7 +245,7 @@ exports[`renders an empty list correctly 1`] = `
> >
<td <td
aria-sort={null} aria-sort={null}
className="MuiTableCell-root MuiTableCell-body MuiTableCell-sizeMedium css-fv4mw1-MuiTableCell-root-tableCell" className="MuiTableCell-root MuiTableCell-body MuiTableCell-sizeMedium css-iiibbc-MuiTableCell-root"
role="cell" role="cell"
> >
<div <div
@ -262,17 +267,17 @@ exports[`renders an empty list correctly 1`] = `
</td> </td>
<td <td
aria-sort={null} aria-sort={null}
className="MuiTableCell-root MuiTableCell-body MuiTableCell-sizeMedium css-fv4mw1-MuiTableCell-root-tableCell" className="MuiTableCell-root MuiTableCell-body MuiTableCell-sizeMedium css-iiibbc-MuiTableCell-root"
role="cell" role="cell"
> >
<span <div
className="css-g3rrgy-wrapper" className="css-1prhjm6"
> >
<div <div
className="css-1sfnvgj-container" className="css-u8cmsa"
> >
<span <span
className="css-lcjmxf-title" className="css-697v50"
data-loading={true} data-loading={true}
style={ style={
{ {
@ -284,17 +289,17 @@ exports[`renders an empty list correctly 1`] = `
Tag type name Tag type name
</span> </span>
<span <span
className="MuiTypography-root MuiTypography-body1 css-kyf98y-MuiTypography-root-description" className="css-1121jr7"
data-loading={true} data-loading={true}
> >
Tag type description when loading Tag type description when loading
</span> </span>
</div> </div>
</span> </div>
</td> </td>
<td <td
aria-sort={null} aria-sort={null}
className="MuiTableCell-root MuiTableCell-body MuiTableCell-sizeMedium css-fv4mw1-MuiTableCell-root-tableCell" className="MuiTableCell-root MuiTableCell-body MuiTableCell-sizeMedium css-iiibbc-MuiTableCell-root"
role="cell" role="cell"
> >
<div <div
@ -410,7 +415,7 @@ exports[`renders an empty list correctly 1`] = `
> >
<td <td
aria-sort={null} aria-sort={null}
className="MuiTableCell-root MuiTableCell-body MuiTableCell-sizeMedium css-fv4mw1-MuiTableCell-root-tableCell" className="MuiTableCell-root MuiTableCell-body MuiTableCell-sizeMedium css-iiibbc-MuiTableCell-root"
role="cell" role="cell"
> >
<div <div
@ -432,17 +437,17 @@ exports[`renders an empty list correctly 1`] = `
</td> </td>
<td <td
aria-sort={null} aria-sort={null}
className="MuiTableCell-root MuiTableCell-body MuiTableCell-sizeMedium css-fv4mw1-MuiTableCell-root-tableCell" className="MuiTableCell-root MuiTableCell-body MuiTableCell-sizeMedium css-iiibbc-MuiTableCell-root"
role="cell" role="cell"
> >
<span <div
className="css-g3rrgy-wrapper" className="css-1prhjm6"
> >
<div <div
className="css-1sfnvgj-container" className="css-u8cmsa"
> >
<span <span
className="css-lcjmxf-title" className="css-697v50"
data-loading={true} data-loading={true}
style={ style={
{ {
@ -454,17 +459,17 @@ exports[`renders an empty list correctly 1`] = `
Tag type name Tag type name
</span> </span>
<span <span
className="MuiTypography-root MuiTypography-body1 css-kyf98y-MuiTypography-root-description" className="css-1121jr7"
data-loading={true} data-loading={true}
> >
Tag type description when loading Tag type description when loading
</span> </span>
</div> </div>
</span> </div>
</td> </td>
<td <td
aria-sort={null} aria-sort={null}
className="MuiTableCell-root MuiTableCell-body MuiTableCell-sizeMedium css-fv4mw1-MuiTableCell-root-tableCell" className="MuiTableCell-root MuiTableCell-body MuiTableCell-sizeMedium css-iiibbc-MuiTableCell-root"
role="cell" role="cell"
> >
<div <div
@ -580,7 +585,7 @@ exports[`renders an empty list correctly 1`] = `
> >
<td <td
aria-sort={null} aria-sort={null}
className="MuiTableCell-root MuiTableCell-body MuiTableCell-sizeMedium css-fv4mw1-MuiTableCell-root-tableCell" className="MuiTableCell-root MuiTableCell-body MuiTableCell-sizeMedium css-iiibbc-MuiTableCell-root"
role="cell" role="cell"
> >
<div <div
@ -602,17 +607,17 @@ exports[`renders an empty list correctly 1`] = `
</td> </td>
<td <td
aria-sort={null} aria-sort={null}
className="MuiTableCell-root MuiTableCell-body MuiTableCell-sizeMedium css-fv4mw1-MuiTableCell-root-tableCell" className="MuiTableCell-root MuiTableCell-body MuiTableCell-sizeMedium css-iiibbc-MuiTableCell-root"
role="cell" role="cell"
> >
<span <div
className="css-g3rrgy-wrapper" className="css-1prhjm6"
> >
<div <div
className="css-1sfnvgj-container" className="css-u8cmsa"
> >
<span <span
className="css-lcjmxf-title" className="css-697v50"
data-loading={true} data-loading={true}
style={ style={
{ {
@ -624,17 +629,17 @@ exports[`renders an empty list correctly 1`] = `
Tag type name Tag type name
</span> </span>
<span <span
className="MuiTypography-root MuiTypography-body1 css-kyf98y-MuiTypography-root-description" className="css-1121jr7"
data-loading={true} data-loading={true}
> >
Tag type description when loading Tag type description when loading
</span> </span>
</div> </div>
</span> </div>
</td> </td>
<td <td
aria-sort={null} aria-sort={null}
className="MuiTableCell-root MuiTableCell-body MuiTableCell-sizeMedium css-fv4mw1-MuiTableCell-root-tableCell" className="MuiTableCell-root MuiTableCell-body MuiTableCell-sizeMedium css-iiibbc-MuiTableCell-root"
role="cell" role="cell"
> >
<div <div
@ -750,7 +755,7 @@ exports[`renders an empty list correctly 1`] = `
> >
<td <td
aria-sort={null} aria-sort={null}
className="MuiTableCell-root MuiTableCell-body MuiTableCell-sizeMedium css-fv4mw1-MuiTableCell-root-tableCell" className="MuiTableCell-root MuiTableCell-body MuiTableCell-sizeMedium css-iiibbc-MuiTableCell-root"
role="cell" role="cell"
> >
<div <div
@ -772,17 +777,17 @@ exports[`renders an empty list correctly 1`] = `
</td> </td>
<td <td
aria-sort={null} aria-sort={null}
className="MuiTableCell-root MuiTableCell-body MuiTableCell-sizeMedium css-fv4mw1-MuiTableCell-root-tableCell" className="MuiTableCell-root MuiTableCell-body MuiTableCell-sizeMedium css-iiibbc-MuiTableCell-root"
role="cell" role="cell"
> >
<span <div
className="css-g3rrgy-wrapper" className="css-1prhjm6"
> >
<div <div
className="css-1sfnvgj-container" className="css-u8cmsa"
> >
<span <span
className="css-lcjmxf-title" className="css-697v50"
data-loading={true} data-loading={true}
style={ style={
{ {
@ -794,17 +799,17 @@ exports[`renders an empty list correctly 1`] = `
Tag type name Tag type name
</span> </span>
<span <span
className="MuiTypography-root MuiTypography-body1 css-kyf98y-MuiTypography-root-description" className="css-1121jr7"
data-loading={true} data-loading={true}
> >
Tag type description when loading Tag type description when loading
</span> </span>
</div> </div>
</span> </div>
</td> </td>
<td <td
aria-sort={null} aria-sort={null}
className="MuiTableCell-root MuiTableCell-body MuiTableCell-sizeMedium css-fv4mw1-MuiTableCell-root-tableCell" className="MuiTableCell-root MuiTableCell-body MuiTableCell-sizeMedium css-iiibbc-MuiTableCell-root"
role="cell" role="cell"
> >
<div <div
@ -920,7 +925,7 @@ exports[`renders an empty list correctly 1`] = `
> >
<td <td
aria-sort={null} aria-sort={null}
className="MuiTableCell-root MuiTableCell-body MuiTableCell-sizeMedium css-fv4mw1-MuiTableCell-root-tableCell" className="MuiTableCell-root MuiTableCell-body MuiTableCell-sizeMedium css-iiibbc-MuiTableCell-root"
role="cell" role="cell"
> >
<div <div
@ -942,17 +947,17 @@ exports[`renders an empty list correctly 1`] = `
</td> </td>
<td <td
aria-sort={null} aria-sort={null}
className="MuiTableCell-root MuiTableCell-body MuiTableCell-sizeMedium css-fv4mw1-MuiTableCell-root-tableCell" className="MuiTableCell-root MuiTableCell-body MuiTableCell-sizeMedium css-iiibbc-MuiTableCell-root"
role="cell" role="cell"
> >
<span <div
className="css-g3rrgy-wrapper" className="css-1prhjm6"
> >
<div <div
className="css-1sfnvgj-container" className="css-u8cmsa"
> >
<span <span
className="css-lcjmxf-title" className="css-697v50"
data-loading={true} data-loading={true}
style={ style={
{ {
@ -964,17 +969,17 @@ exports[`renders an empty list correctly 1`] = `
Tag type name Tag type name
</span> </span>
<span <span
className="MuiTypography-root MuiTypography-body1 css-kyf98y-MuiTypography-root-description" className="css-1121jr7"
data-loading={true} data-loading={true}
> >
Tag type description when loading Tag type description when loading
</span> </span>
</div> </div>
</span> </div>
</td> </td>
<td <td
aria-sort={null} aria-sort={null}
className="MuiTableCell-root MuiTableCell-body MuiTableCell-sizeMedium css-fv4mw1-MuiTableCell-root-tableCell" className="MuiTableCell-root MuiTableCell-body MuiTableCell-sizeMedium css-iiibbc-MuiTableCell-root"
role="cell" role="cell"
> >
<div <div

View File

@ -1,5 +1,6 @@
import { makeStyles } from 'tss-react/mui'; import { makeStyles } from 'tss-react/mui';
import { Theme } from '@mui/material'; import { Theme } from '@mui/material';
import { CSSProperties } from 'react';
export const focusable = (theme: Theme) => ({ export const focusable = (theme: Theme) => ({
'&:focus-visible': { '&:focus-visible': {
@ -51,6 +52,54 @@ export const defaultBorderRadius = (theme: Theme) => ({
borderRadius: `${theme.shape.borderRadius}px`, borderRadius: `${theme.shape.borderRadius}px`,
}); });
export const fadeInBottomStart = () => ({
opacity: '0',
position: 'fixed',
right: '40px',
bottom: '40px',
transform: 'translateY(400px)',
});
export const fadeInBottomStartWithoutFixed: CSSProperties = {
opacity: '0',
right: '40px',
bottom: '40px',
transform: 'translateY(400px)',
zIndex: 1400,
position: 'fixed',
};
export const fadeInBottomEnter: CSSProperties = {
transform: 'translateY(0)',
opacity: '1',
transition: 'transform 0.6s ease, opacity 1s ease',
};
export const fadeInBottomLeave: CSSProperties = {
transform: 'translateY(400px)',
opacity: '0',
transition: 'transform 1.25s ease, opacity 1s ease',
};
export const fadeInTopStart = (theme: Theme): CSSProperties => ({
opacity: '0',
position: 'fixed',
right: '40px',
top: '40px',
transform: 'translateY(-400px)',
[theme.breakpoints.down('sm')]: {
right: 20,
left: 10,
top: 40,
},
});
export const fadeInTopEnter: CSSProperties = {
transform: 'translateY(100px)',
opacity: '1',
transition: 'transform 0.6s ease, opacity 1s ease',
};
export const fadeInTopLeave: CSSProperties = {
transform: 'translateY(-400px)',
opacity: '0',
transition: 'transform 1.25s ease, opacity 1s ease',
};
/** /**
* Please extract styles below into MUI fragments as shown above * Please extract styles below into MUI fragments as shown above
* @deprecated * @deprecated
@ -117,53 +166,6 @@ export const useThemeStyles = makeStyles()(theme => ({
fontWeight: 'bold', fontWeight: 'bold',
marginBottom: '0.5rem', marginBottom: '0.5rem',
}, },
fadeInBottomStart: {
opacity: '0',
position: 'fixed',
right: '40px',
bottom: '40px',
transform: 'translateY(400px)',
},
fadeInBottomStartWithoutFixed: {
opacity: '0',
right: '40px',
bottom: '40px',
transform: 'translateY(400px)',
zIndex: 1400,
position: 'fixed',
},
fadeInBottomEnter: {
transform: 'translateY(0)',
opacity: '1',
transition: 'transform 0.6s ease, opacity 1s ease',
},
fadeInBottomLeave: {
transform: 'translateY(400px)',
opacity: '0',
transition: 'transform 1.25s ease, opacity 1s ease',
},
fadeInTopStart: {
opacity: '0',
position: 'fixed',
right: '40px',
top: '40px',
transform: 'translateY(-400px)',
[theme.breakpoints.down('sm')]: {
right: 20,
left: 10,
top: 40,
},
},
fadeInTopEnter: {
transform: 'translateY(100px)',
opacity: '1',
transition: 'transform 0.6s ease, opacity 1s ease',
},
fadeInTopLeave: {
transform: 'translateY(-400px)',
opacity: '0',
transition: 'transform 1.25s ease, opacity 1s ease',
},
error: { error: {
fontSize: theme.fontSizes.smallBody, fontSize: theme.fontSizes.smallBody,
color: theme.palette.error.main, color: theme.palette.error.main,

View File

@ -1,4 +1,4 @@
import { FC, ElementType } from 'react'; import { FC } from 'react';
import { SvgIcon, useTheme } from '@mui/material'; import { SvgIcon, useTheme } from '@mui/material';
import LocationOnIcon from '@mui/icons-material/LocationOn'; import LocationOnIcon from '@mui/icons-material/LocationOn';
import PeopleIcon from '@mui/icons-material/People'; import PeopleIcon from '@mui/icons-material/People';
@ -19,7 +19,7 @@ const RolloutSvgIcon: FC = props => (
/> />
); );
export const getFeatureStrategyIcon = (strategyName: string): ElementType => { export const getFeatureStrategyIcon = (strategyName: string) => {
switch (strategyName) { switch (strategyName) {
case 'default': case 'default':
return PowerSettingsNewIcon; return PowerSettingsNewIcon;