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}
<Button onClick={onCancel} sx={{ ml: 2 }}>
<Button onClick={onCancel} sx={{ marginLeft: 2 }}>
Cancel
</Button>
</Box>

View File

@ -264,7 +264,10 @@ export const ChangeRequestOverview: FC = () => {
}
show={
<Button
sx={{ ml: 2 }}
sx={{
marginLeft: theme =>
theme.spacing(2),
}}
variant="outlined"
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';
interface IAnimateOnMountProps {
mounted: boolean;
enter: string;
start: string;
leave?: string;
container?: string;
style?: React.CSSProperties;
enter: CSSProperties;
start: CSSProperties;
leave?: CSSProperties;
onStart?: () => void;
onEnd?: () => void;
}
@ -17,14 +15,12 @@ const AnimateOnMount: FC<IAnimateOnMountProps> = ({
enter,
start,
leave,
container,
children,
style,
onStart,
onEnd,
}) => {
const [show, setShow] = useState(mounted);
const [styles, setStyles] = useState('');
const [styles, setStyles] = useState<CSSProperties>({});
const mountedRef = useRef<null | boolean>(null);
useEffect(() => {
@ -39,7 +35,7 @@ const AnimateOnMount: FC<IAnimateOnMountProps> = ({
if (!leave) {
setShow(false);
}
setStyles(leave || '');
setStyles(leave || {});
}
}
}, [mounted, enter, onStart, leave]);
@ -56,11 +52,8 @@ const AnimateOnMount: FC<IAnimateOnMountProps> = ({
condition={show}
show={
<div
className={`${start} ${styles} ${
container ? container : ''
}`}
onTransitionEnd={onTransitionEnd}
style={{ ...style }}
style={{ ...start, ...styles }}
>
{children}
</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 { 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 classnames from 'classnames';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import { useStyles } from './Search.styles';
import { SearchSuggestions } from './SearchSuggestions/SearchSuggestions';
import { IGetSearchContextOutput } from 'hooks/useSearch';
import { useKeyboardShortcut } from 'hooks/useKeyboardShortcut';
import { useAsyncDebounce } from 'react-table';
interface ISearchProps {
initialValue?: string;
@ -21,6 +19,43 @@ interface ISearchProps {
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 = ({
initialValue = '',
onChange,
@ -33,7 +68,6 @@ export const Search = ({
debounceTime = 200,
}: ISearchProps) => {
const ref = useRef<HTMLInputElement>();
const { classes: styles } = useStyles();
const [showSuggestions, setShowSuggestions] = useState(false);
const [value, setValue] = useState(initialValue);
@ -62,23 +96,17 @@ export const Search = ({
const placeholder = `${customPlaceholder ?? 'Search'} (${hotkey})`;
return (
<div className={styles.container} style={containerStyles}>
<div
className={classnames(
styles.search,
className,
'search-container'
)}
>
<StyledContainer style={containerStyles}>
<StyledSearch className={className}>
<SearchIcon
className={classnames(styles.searchIcon, 'search-icon')}
sx={{
mr: 1,
color: theme => theme.palette.inactiveIcon,
}}
/>
<InputBase
<StyledInputBase
inputRef={ref}
placeholder={placeholder}
classes={{
root: classnames(styles.inputRoot, 'input-container'),
}}
inputProps={{ 'aria-label': placeholder }}
value={value}
onChange={e => onSearchChange(e.target.value)}
@ -86,12 +114,7 @@ export const Search = ({
onBlur={() => setShowSuggestions(false)}
disabled={disabled}
/>
<div
className={classnames(
styles.clearContainer,
'clear-container'
)}
>
<Box sx={{ width: theme => theme.spacing(4) }}>
<ConditionallyRender
condition={Boolean(value)}
show={
@ -102,20 +125,21 @@ export const Search = ({
onSearchChange('');
ref.current?.focus();
}}
sx={{ padding: theme => theme.spacing(1) }}
>
<Close className={styles.clearIcon} />
<StyledClose />
</IconButton>
</Tooltip>
}
/>
</div>
</div>
</Box>
</StyledSearch>
<ConditionallyRender
condition={Boolean(hasFilters) && showSuggestions}
show={
<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,
AccordionSummary,
Button,
styled,
Typography,
} from '@mui/material';
import { ConstraintAccordionList } from '../ConstraintAccordion/ConstraintAccordionList/ConstraintAccordionList';
import { ConditionallyRender } from '../ConditionallyRender/ConditionallyRender';
import { useStyles } from './SegmentItem.styles';
import { ConstraintAccordionList } from 'component/common/ConstraintAccordion/ConstraintAccordionList/ConstraintAccordionList';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
interface ISegmentItemProps {
segment: Partial<ISegment>;
@ -20,36 +20,52 @@ interface ISegmentItemProps {
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> = ({
segment,
isExpanded,
headerContent,
constraintList,
}) => {
const { classes } = useStyles();
const [isOpen, setIsOpen] = useState(isExpanded || false);
return (
<Accordion
expanded={isOpen}
className={classes.accordion}
classes={{
root: classes.accordionRoot,
expanded: classes.accordionExpanded,
}}
>
<AccordionSummary
id={`segment-accordion-${segment.id}`}
className={classes.summary}
>
<StyledAccordion expanded={isOpen}>
<StyledAccordionSummary id={`segment-accordion-${segment.id}`}>
<DonutLarge color="secondary" sx={{ mr: 1 }} />
Segment:
<Link
to={`/segments/edit/${segment.id}`}
className={classes.link}
>
<span>Segment:</span>
<StyledLink to={`/segments/edit/${segment.id}`}>
{segment.name}
</Link>
</StyledLink>
<ConditionallyRender
condition={Boolean(headerContent)}
show={headerContent}
@ -61,13 +77,18 @@ export const SegmentItem: VFC<ISegmentItemProps> = ({
size="small"
variant="outlined"
onClick={() => setIsOpen(value => !value)}
className={classes.previewButton}
sx={{
my: 0,
ml: 'auto',
fontSize: theme =>
theme.typography.body2.fontSize,
}}
>
{isOpen ? 'Close preview' : 'Preview'}
</Button>
}
/>
</AccordionSummary>
</StyledAccordionSummary>
<AccordionDetails sx={{ pt: 0 }}>
<ConditionallyRender
condition={Boolean(constraintList)}
@ -90,6 +111,6 @@ export const SegmentItem: VFC<ISegmentItemProps> = ({
}
/>
</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 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 { useMemo } from 'react';
interface IStaleDataNotification {
refresh: () => void;
@ -18,12 +22,12 @@ export const StaleDataNotification = ({
data,
cache,
}: IStaleDataNotification) => {
const { classes: themeStyles } = useThemeStyles();
const theme = useTheme();
const isExtraSmallScreen = useMediaQuery(theme.breakpoints.down('sm'));
const getStyles = () => {
const style = useMemo(() => {
const base = {
...fadeInBottomStartWithoutFixed,
padding: `${theme.spacing(3)} ${theme.spacing(4)}`,
boxShadow: theme.boxShadows.elevated,
borderRadius: theme.shape.borderRadiusLarge,
@ -41,15 +45,10 @@ export const StaleDataNotification = ({
};
}
return base;
};
}, [theme, isExtraSmallScreen]);
return (
<AnimateOnMount
mounted={show}
start={themeStyles.fadeInBottomStartWithoutFixed}
enter={themeStyles.fadeInBottomEnter}
style={getStyles()}
>
<AnimateOnMount mounted={show} start={style} enter={fadeInBottomEnter}>
<Typography variant="h5" sx={{ my: 2, mb: 2 }}>
Your data is stale
</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 { DragIndicator } from '@mui/icons-material';
import { styled, IconButton, Box } from '@mui/material';
import classNames from 'classnames';
import { IFeatureStrategy } from 'interfaces/strategy';
import {
getFeatureStrategyIcon,
@ -9,7 +8,6 @@ import {
} from 'utils/strategyNames';
import StringTruncator from 'component/common/StringTruncator/StringTruncator';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import { useStyles } from './StrategyItemContainer.styles';
import { PlaygroundStrategySchema } from 'openapi';
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> = ({
strategy,
onDragStart,
@ -49,7 +68,6 @@ export const StrategyItemContainer: FC<IStrategyItemContainerProps> = ({
orderNumber,
style = {},
}) => {
const { classes: styles } = useStyles();
const Icon = getFeatureStrategyIcon(strategy.name);
return (
@ -58,12 +76,8 @@ export const StrategyItemContainer: FC<IStrategyItemContainerProps> = ({
condition={orderNumber !== undefined}
show={<StyledIndexLabel>{orderNumber}</StyledIndexLabel>}
/>
<Box className={styles.container} style={{ ...style }}>
<div
className={classNames(styles.header, {
[styles.headerDraggable]: Boolean(onDragStart),
})}
>
<StyledContainer style={style}>
<StyledHeader draggable={Boolean(onDragStart)}>
<ConditionallyRender
condition={Boolean(onDragStart)}
show={() => (
@ -83,16 +97,36 @@ export const StrategyItemContainer: FC<IStrategyItemContainerProps> = ({
</DragIcon>
)}
/>
<Icon className={styles.icon} />
<Icon
sx={{
fill: theme => theme.palette.inactiveIcon,
}}
/>
<StringTruncator
maxWidth="150"
maxLength={15}
text={formatStrategyName(strategy.name)}
/>
<div className={styles.actions}>{actions}</div>
</div>
<div className={styles.body}>{children}</div>
<Box
sx={{
marginLeft: 'auto',
display: 'flex',
minHeight: theme => theme.spacing(6),
alignItems: 'center',
}}
>
{actions}
</Box>
</StyledHeader>
<Box
sx={{
p: 2,
justifyItems: 'center',
}}
>
{children}
</Box>
</StyledContainer>
</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 classnames from 'classnames';
import { Tabs, Tab, Paper } from '@mui/material';
import { useStyles } from 'component/common/TabNav/TabNav/TabNav.styles';
import { TabPanel } from 'component/common/TabNav/TabPanel/TabPanel';
interface ITabNavProps {
@ -15,13 +13,13 @@ interface ITabData {
label: string;
component: ReactNode;
}
export const TabNav = ({
tabData,
className = '',
navClass = '',
startingTab = 0,
}: ITabNavProps) => {
const { classes: styles } = useStyles();
const [activeTab, setActiveTab] = useState(startingTab);
const renderTabs = () =>
tabData.map((tab, index) => (
@ -30,7 +28,11 @@ export const TabNav = ({
label={tab.label}
id={`tab-${index}`}
aria-controls={`tabpanel-${index}`}
className={styles.tab}
sx={{
minWidth: {
lg: 160,
},
}}
/>
));
@ -44,8 +46,14 @@ export const TabNav = ({
return (
<>
<Paper
className={classnames(styles.tabNav, navClass)}
className={navClass}
elevation={0}
sx={{
backgroundColor: theme => theme.palette.background.paper,
borderBottom: '1px solid',
borderBottomColor: theme => theme.palette.grey[300],
borderRadius: 0,
}}
>
<Tabs
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 => ({
header: {
export const StyledTableCell = styled(TableCell, {
shouldForwardProp: prop =>
prop !== 'isFlex' && prop !== 'isSortable' && prop !== 'isFlexGrow',
})<{
isFlex?: boolean;
isSortable?: boolean;
isFlexGrow?: boolean;
}>(({ theme, isFlex, isSortable, isFlexGrow }) => ({
position: 'relative',
fontWeight: theme.fontWeight.medium,
},
flex: {
fontWeight: theme.typography.fontWeightRegular,
...(isFlex && {
justifyContent: 'stretch',
alignItems: 'center',
display: 'flex',
@ -13,11 +18,8 @@ export const useStyles = makeStyles()(theme => ({
'& > *': {
flexGrow: 1,
},
},
flexGrow: {
flexGrow: 1,
},
sortable: {
}),
...(isSortable && {
padding: 0,
'&:hover, &:focus': {
backgroundColor: theme.palette.tableHeaderHover,
@ -25,8 +27,15 @@ export const useStyles = makeStyles()(theme => ({
color: 'inherit',
},
},
},
sortButton: {
}),
...(isFlexGrow && {
flexGrow: 1,
}),
}));
export const StyledButton = styled('button', {
shouldForwardProp: prop => prop !== 'isSorted',
})<{ isSorted?: boolean }>(({ theme, isSorted }) => ({
all: 'unset',
whiteSpace: 'nowrap',
width: '100%',
@ -41,11 +50,12 @@ export const useStyles = makeStyles()(theme => ({
display: 'flex',
boxSizing: 'inherit',
cursor: 'pointer',
},
sortedButton: {
fontWeight: theme.fontWeight.bold,
},
label: {
...(isSorted && {
fontWeight: theme.typography.fontWeightBold,
}),
}));
export const StyledLabel = styled('span')(({ theme }) => ({
display: 'flex',
flexDirection: 'column',
flexShrink: 1,
@ -58,27 +68,17 @@ export const useStyles = makeStyles()(theme => ({
visibility: 'hidden',
overflow: 'hidden',
},
},
alignLeft: {
justifyContent: 'flex-start',
textAlign: 'left',
},
alignRight: {
justifyContent: 'flex-end',
textAlign: 'right',
},
alignCenter: {
justifyContent: 'center',
textAlign: 'center',
},
hiddenMeasurementLayer: {
}));
export const StyledHiddenMeasurementLayer = styled('span')(({ theme }) => ({
padding: theme.spacing(2),
visibility: 'hidden',
display: 'flex',
alignItems: 'center',
width: '100%',
},
visibleAbsoluteLayer: {
}));
export const StyledVisibleAbsoluteLayer = styled('span')(({ theme }) => ({
padding: theme.spacing(2),
position: 'absolute',
display: 'flex',
@ -95,5 +95,4 @@ export const useStyles = makeStyles()(theme => ({
overflowX: 'hidden',
overflowY: 'visible',
},
},
}));

View File

@ -7,11 +7,16 @@ import {
useRef,
useState,
} from 'react';
import { TableCell, Tooltip } from '@mui/material';
import classnames from 'classnames';
import { Tooltip } from '@mui/material';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import { useStyles } from './CellSortable.styles';
import { AnnouncerContext } from 'component/common/Announcer/AnnouncerContext/AnnouncerContext';
import {
StyledButton,
StyledHiddenMeasurementLayer,
StyledLabel,
StyledTableCell,
StyledVisibleAbsoluteLayer,
} from './CellSortable.styles';
import { SortArrow } from './SortArrow/SortArrow';
interface ICellSortableProps {
@ -45,7 +50,6 @@ export const CellSortable: FC<ICellSortableProps> = ({
const { setAnnouncement } = useContext(AnnouncerContext);
const [title, setTitle] = useState('');
const ref = useRef<HTMLSpanElement>(null);
const { classes: styles } = useStyles();
const ariaSort = isSorted
? isDescending
@ -62,18 +66,27 @@ export const CellSortable: FC<ICellSortableProps> = ({
);
};
const alignClass = useMemo(() => {
const alignStyle = useMemo(() => {
switch (align) {
case 'left':
return styles.alignLeft;
return {
justifyContent: 'flex-start',
textAlign: 'left',
} as const;
case 'center':
return styles.alignCenter;
return {
justifyContent: 'center',
textAlign: 'center',
} as const;
case 'right':
return styles.alignRight;
return {
justifyContent: 'flex-end',
textAlign: 'right',
} as const;
default:
return undefined;
}
}, [align, styles]);
}, [align]);
useEffect(() => {
const updateTitle = () => {
@ -93,55 +106,36 @@ export const CellSortable: FC<ICellSortableProps> = ({
}, [setTitle, ariaTitle]); // eslint-disable-line react-hooks/exhaustive-deps
return (
<TableCell
<StyledTableCell
component="th"
aria-sort={ariaSort}
className={classnames(
styles.header,
isSortable && styles.sortable,
isFlex && styles.flex,
isFlexGrow && styles.flexGrow
)}
style={{ width, minWidth, maxWidth }}
isFlex={isFlex}
isFlexGrow={isFlexGrow}
isSortable={isSortable}
>
<ConditionallyRender
condition={isSortable}
show={
<Tooltip title={title} arrow>
<button
<StyledButton
isSorted={isSorted}
type="button"
className={classnames(
isSorted && styles.sortedButton,
styles.sortButton,
alignClass
)}
onClick={onSortClick}
>
<span
className={classnames(
styles.hiddenMeasurementLayer,
alignClass
)}
<StyledHiddenMeasurementLayer
style={alignStyle}
aria-hidden
>
<span
className={styles.label}
tabIndex={-1}
data-text={children}
>
<StyledLabel tabIndex={-1} data-text={children}>
{children}
</span>
</StyledLabel>
<SortArrow
isSorted={isSorted}
isDesc={isDescending}
/>
</span>
<span
className={classnames(
styles.visibleAbsoluteLayer,
alignClass
)}
>
</StyledHiddenMeasurementLayer>
<StyledVisibleAbsoluteLayer style={alignStyle}>
<span ref={ref} tabIndex={-1}>
<span>{children}</span>
</span>
@ -150,12 +144,12 @@ export const CellSortable: FC<ICellSortableProps> = ({
isDesc={isDescending}
className="sort-arrow"
/>
</span>
</button>
</StyledVisibleAbsoluteLayer>
</StyledButton>
</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,
} from '@mui/icons-material';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import { useStyles } from './SortArrow.styles';
import classnames from 'classnames';
import { Theme } from '@mui/material';
interface ISortArrowProps {
isSorted?: boolean;
@ -14,14 +14,19 @@ interface ISortArrowProps {
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> = ({
isSorted: sorted,
isDesc: desc = false,
className,
}) => {
const { classes: styles } = useStyles();
return (
}) => (
<ConditionallyRender
condition={Boolean(sorted)}
show={
@ -29,21 +34,21 @@ export const SortArrow: VFC<ISortArrowProps> = ({
condition={Boolean(desc)}
show={
<KeyboardArrowDown
className={classnames(
styles.icon,
styles.sorted,
className
)}
sx={theme => ({
...iconStyle(theme),
color: theme.palette.tableHeaderColor,
})}
className={className}
fontSize="inherit"
/>
}
elseShow={
<KeyboardArrowUp
className={classnames(
styles.icon,
styles.sorted,
className
)}
sx={theme => ({
...iconStyle(theme),
color: theme.palette.tableHeaderColor,
})}
className={className}
fontSize="inherit"
/>
}
@ -51,10 +56,12 @@ export const SortArrow: VFC<ISortArrowProps> = ({
}
elseShow={
<UnfoldMoreOutlined
className={classnames(styles.icon, className, 'hover-only')}
sx={theme => ({
...iconStyle(theme),
})}
className={classnames(className, 'hover-only')}
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 { TableHead, TableRow } from '@mui/material';
import { styled, TableHead, TableRow } from '@mui/material';
import { HeaderGroup } from 'react-table';
import { useStyles } from './SortableTableHeader.styles';
import { CellSortable } from './CellSortable/CellSortable';
interface ISortableTableHeaderProps {
@ -10,20 +9,31 @@ interface ISortableTableHeaderProps {
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> = ({
headerGroups,
className,
flex,
}) => {
const { classes: styles } = useStyles();
return (
}) => (
<TableHead className={className}>
{headerGroups.map(headerGroup => (
<TableRow
{...headerGroup.getHeaderGroupProps()}
className={styles.tableHeader}
>
<StyledTableRow {...headerGroup.getHeaderGroupProps()}>
{headerGroup.headers.map((column: HeaderGroup) => {
const content = column.render('Header');
@ -54,8 +64,7 @@ export const SortableTableHeader: VFC<ISortableTableHeaderProps> = ({
</CellSortable>
);
})}
</TableRow>
</StyledTableRow>
))}
</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 classnames from 'classnames';
import { Table as MUITable, TableProps } from '@mui/material';
import { useStyles } from './Table.styles';
export const Table: FC<
TableProps & {
rowHeight?: 'auto' | 'dense' | 'standard' | 'compact' | number;
}
> = ({ rowHeight = 'auto', className, ...props }) => {
const { classes } = useStyles({ rowHeight });
return (
<MUITable className={classnames(classes.table, className)} {...props} />
);
};
> = ({ rowHeight = 'auto', ...props }) => (
<MUITable
sx={{
position: 'relative',
'& 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 classnames from 'classnames';
import { TableCell as MUITableCell, TableCellProps } from '@mui/material';
import { useStyles } from './TableCell.styles';
import {
styled,
TableCell as MUITableCell,
TableCellProps,
} from '@mui/material';
const StyledTableCell = styled(MUITableCell)(({ theme }) => ({
padding: 0,
}));
export const TableCell: FC<TableCellProps> = forwardRef(
({ className, ...props }, ref: ForwardedRef<unknown>) => {
const { classes: styles } = useStyles();
return (
<MUITableCell
className={classnames(styles.tableCell, className)}
{...props}
ref={ref}
/>
);
}
({ className, ...props }, ref: ForwardedRef<unknown>) => (
<StyledTableCell {...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 { Box } from '@mui/material';
import { useStyles } from 'component/common/Table/TablePlaceholder/TablePlaceholder.styles';
export const TablePlaceholder: FC = ({ children }) => {
const { classes: styles } = useStyles();
return <Box className={styles.emptyStateListItem}>{children}</Box>;
};
export const TablePlaceholder: FC = ({ children }) => (
<Box
sx={{
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 {
SortableTableHeader,
Table,
TableCell,
TableBody,
TableRow,
TableCell,
} from 'component/common/Table';
import { useVirtualizedRange } from 'hooks/useVirtualizedRange';
import { useStyles } from './VirtualizedTable.styles';
import { HeaderGroup, Row } from 'react-table';
interface IVirtualizedTableProps {
@ -34,7 +33,6 @@ export const VirtualizedTable: VFC<IVirtualizedTableProps> = ({
rows,
prepareRow,
}) => {
const { classes } = useStyles();
const theme = useTheme();
const rowHeight = useMemo(
() => rowHeightOverride || theme.shape.tableRowHeight,
@ -56,7 +54,28 @@ export const VirtualizedTable: VFC<IVirtualizedTableProps> = ({
style={{ height: tableHeight }}
>
<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) => {
const top =
index * rowHeight + theme.shape.tableRowHeightCompact;
@ -73,10 +92,10 @@ export const VirtualizedTable: VFC<IVirtualizedTableProps> = ({
return (
<TableRow
hover
{...row.getRowProps()}
{...row.getRowProps({
style: { display: 'flex', top },
})}
key={row.id}
className={classes.row}
style={{ display: 'flex', top }}
>
{row.cells.map(cell => (
<TableCell
@ -87,7 +106,6 @@ export const VirtualizedTable: VFC<IVirtualizedTableProps> = ({
: undefined,
},
})}
className={classes.cell}
>
{cell.render('Cell')}
</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 { useStyles } from './ActionCell.styles';
const ActionCellDivider: VFC = () => {
const { classes } = useStyles();
return (
<Divider
className={classes.divider}
orientation="vertical"
variant="middle"
/>
);
};
const StyledContainer = styled(Box)(({ theme }) => ({
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
padding: theme.spacing(0, 1.5),
}));
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 & {
Divider: typeof ActionCellDivider;
} = ({ children }) => {
const { classes } = useStyles();
return <Box className={classes.container}>{children}</Box>;
return <StyledContainer>{children}</StyledContainer>;
};
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 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 { useStyles } from './FeatureSeenCell.styles';
function shortenUnitName(unit?: string): string {
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 {
value?: string | Date | null;
}
@ -59,21 +76,16 @@ const Wrapper: FC<{ unit?: string; tooltip: string }> = ({
tooltip,
children,
}) => {
const { classes: styles } = useStyles();
const getColor = useFeatureColor();
return (
<div className={styles.container}>
<StyledContainer>
<Tooltip title={tooltip} arrow describeChild>
<div
className={styles.box}
style={{ background: getColor(unit) }}
data-loading
>
<StyledBox style={{ background: getColor(unit) }} data-loading>
{children}
</div>
</StyledBox>
</Tooltip>
</div>
</StyledContainer>
);
};

View File

@ -1,15 +1,21 @@
import { VFC } from 'react';
import { Tooltip } from '@mui/material';
import { styled, Tooltip } from '@mui/material';
import { getFeatureTypeIcons } from 'utils/getFeatureTypeIcons';
import useFeatureTypes from 'hooks/api/getters/useFeatureTypes/useFeatureTypes';
import { useStyles } from './FeatureTypeCell.styles';
interface IFeatureTypeProps {
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 }) => {
const { classes: styles } = useStyles();
const { featureTypes } = useFeatureTypes();
const IconComponent = getFeatureTypeIcons(value);
@ -20,10 +26,10 @@ export const FeatureTypeCell: VFC<IFeatureTypeProps> = ({ value }) => {
const title = `This is a "${typeName || value}" toggle`;
return (
<div className={styles.container}>
<StyledContainer>
<Tooltip arrow title={title} describeChild>
<IconComponent data-loading className={styles.icon} />
<IconComponent data-loading />
</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 { Highlighter } from 'component/common/Highlighter/Highlighter';
import { useSearchHighlightContext } from 'component/common/Table/SearchHighlightContext/SearchHighlightContext';
import { Box, Typography } from '@mui/material';
import { useStyles } from './HighlightCell.styles';
import { Box, styled } from '@mui/material';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
interface IHighlightCellProps {
@ -10,17 +9,43 @@ interface IHighlightCellProps {
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> = ({
value,
subtitle,
}) => {
const { searchQuery } = useSearchHighlightContext();
const { classes } = useStyles();
return (
<Box className={classes.container}>
<span
className={classes.title}
<StyledContainer>
<StyledTitle
style={{
WebkitLineClamp: Boolean(subtitle) ? 1 : 2,
lineClamp: Boolean(subtitle) ? 1 : 2,
@ -28,21 +53,17 @@ export const HighlightCell: VFC<IHighlightCellProps> = ({
data-loading
>
<Highlighter search={searchQuery}>{value}</Highlighter>
</span>
</StyledTitle>
<ConditionallyRender
condition={Boolean(subtitle)}
show={() => (
<Typography
component="span"
className={classes.subtitle}
data-loading
>
<StyledSubtitle data-loading>
<Highlighter search={searchQuery}>
{subtitle}
</Highlighter>
</Typography>
</StyledSubtitle>
)}
/>
</Box>
</StyledContainer>
);
};

View File

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

View File

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

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 { useContext, useEffect } from 'react';
import { useThemeStyles } from 'themes/themeStyles';
import { useContext, useEffect, useMemo } from 'react';
import {
fadeInBottomEnter,
fadeInBottomLeave,
fadeInBottomStartWithoutFixed,
} from 'themes/themeStyles';
import UIContext from 'contexts/UIContext';
import { useStyles } from './ToastRenderer.styles';
import AnimateOnMount from '../AnimateOnMount/AnimateOnMount';
import Toast from './Toast/Toast';
import { IToast } from 'interfaces/toast';
const ToastRenderer = () => {
const { toastData, setToast } = useContext(UIContext);
const { classes: themeStyles } = useThemeStyles();
const { classes: styles } = useStyles();
const hide = () => {
setToast((prev: IToast) => ({ ...prev, show: false }));
@ -28,14 +29,28 @@ const ToastRenderer = () => {
/* eslint-disable-next-line */
}, [toastData?.show]);
const animations = useMemo(
() => ({
start: {
...fadeInBottomStartWithoutFixed,
right: 0,
left: 0,
margin: '0 auto',
maxWidth: '450px',
},
enter: fadeInBottomEnter,
leave: fadeInBottomLeave,
}),
[]
);
return (
<Portal>
<AnimateOnMount
mounted={Boolean(toastData?.show)}
start={themeStyles.fadeInBottomStartWithoutFixed}
enter={themeStyles.fadeInBottomEnter}
leave={themeStyles.fadeInBottomLeave}
container={styles.toastWrapper}
start={animations.start}
enter={animations.enter}
leave={animations.leave}
>
<Toast {...toastData} />
</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 { Button, IconButton, Tooltip } from '@mui/material';
import classnames from 'classnames';
import { useContext, useMemo, useState } from 'react';
import { Box, Button, IconButton, Tooltip, useTheme } from '@mui/material';
import CloseIcon from '@mui/icons-material/Close';
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 { 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 {
PNPS_FEEDBACK_ID,
@ -24,10 +27,18 @@ export const FeedbackNPS = ({ openUrl }: IFeedbackNPSProps) => {
const { createFeedback, updateFeedback } = useAuthFeedbackApi();
const { feedback } = useAuthFeedback();
const [answeredNotNow, setAnsweredNotNow] = useState(false);
const { classes: styles } = useStyles();
const { classes: themeStyles } = useThemeStyles();
const theme = useTheme();
const feedbackId = PNPS_FEEDBACK_ID;
const animations = useMemo(
() => ({
start: { ...fadeInTopStart(theme), zIndex: theme.zIndex.tooltip },
enter: fadeInTopEnter,
leave: fadeInTopLeave,
}),
[theme]
);
const onConfirm = async () => {
try {
await createFeedback({ feedbackId });
@ -61,28 +72,53 @@ export const FeedbackNPS = ({ openUrl }: IFeedbackNPSProps) => {
return (
<AnimateOnMount
mounted={showFeedback}
start={themeStyles.fadeInTopStart}
enter={themeStyles.fadeInTopEnter}
leave={themeStyles.fadeInTopLeave}
container={styles.animateContainer}
start={animations.start}
enter={animations.enter}
leave={animations.leave}
>
<div className={styles.feedback}>
<div
className={classnames(
styles.container,
themeStyles.contentSpacingY
)}
<Box
sx={{
borderRadius: '12.5px',
backgroundColor: theme.palette.background.paper,
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>
<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)}
size="large"
>
<CloseIcon />
</IconButton>
</Tooltip>
<Logo className={styles.logo} />
<Logo
style={{
width: '25px',
height: '25px',
}}
/>
<ConditionallyRender
condition={answeredNotNow}
show={
@ -99,7 +135,7 @@ export const FeedbackNPS = ({ openUrl }: IFeedbackNPSProps) => {
}
/>
<div>
<Box>
<ConditionallyRender
condition={answeredNotNow}
show={
@ -120,7 +156,10 @@ export const FeedbackNPS = ({ openUrl }: IFeedbackNPSProps) => {
Yes, no problem
</Button>
<Button
className={styles.cancel}
sx={{
marginLeft: theme =>
theme.spacing(2),
}}
onClick={() => setAnsweredNotNow(true)}
>
Not now
@ -128,9 +167,9 @@ export const FeedbackNPS = ({ openUrl }: IFeedbackNPSProps) => {
</>
}
/>
</div>
</div>
</div>
</Box>
</Box>
</Box>
</AnimateOnMount>
);
};

View File

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

View File

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

View File

@ -1,5 +1,6 @@
import { makeStyles } from 'tss-react/mui';
import { Theme } from '@mui/material';
import { CSSProperties } from 'react';
export const focusable = (theme: Theme) => ({
'&:focus-visible': {
@ -51,6 +52,54 @@ export const defaultBorderRadius = (theme: Theme) => ({
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
* @deprecated
@ -117,53 +166,6 @@ export const useThemeStyles = makeStyles()(theme => ({
fontWeight: 'bold',
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: {
fontSize: theme.fontSizes.smallBody,
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 LocationOnIcon from '@mui/icons-material/LocationOn';
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) {
case 'default':
return PowerSettingsNewIcon;