Cb 3587 migrate snackbars to css modules (#1842)

* CB-3587 add css modules, remove reshadow styles from snackbars

* CB-3587 fix notification cross button style

---------

Co-authored-by: mr-anton-t <42037741+mr-anton-t@users.noreply.github.com>
This commit is contained in:
Tatiana Fokina
2023-07-27 17:34:39 +03:00
committed by GitHub
co-authored by mr-anton-t
parent 664864d478
commit 45c201c465
10 changed files with 159 additions and 144 deletions
@@ -0,0 +1,30 @@
.notificationBody {
display: flex;
flex-direction: column;
flex: 1;
& .bodyTextBlock {
margin-top: 8px;
padding-right: 24px;
& .message {
font-size: 16px;
opacity: 0.8;
overflow: auto;
max-height: 200px;
margin-bottom: 8px;
word-break: break-word;
white-space: pre-line;
}
}
}
.textBlockTitle {
composes: theme-typography--headline6 from global;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
line-height: 1.55rem;
font-weight: 700;
margin: 0;
padding: 0;
margin-bottom: 8px;
}
@@ -5,40 +5,9 @@
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
*/
import styled, { css } from 'reshadow';
const SNACKBAR_BODY_STYLES = css`
notification-body {
display: flex;
flex-direction: column;
flex: 1;
& body-text-block {
margin-top: 8px;
padding-right: 24px;
& message {
font-size: 16px;
opacity: 0.8;
overflow: auto;
max-height: 200px;
margin-bottom: 8px;
word-break: break-word;
white-space: pre-line;
}
}
}
text-block-title {
composes: theme-typography--headline6 from global;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
line-height: 1.55rem;
font-weight: 700;
margin: 0;
padding: 0;
margin-bottom: 8px;
}
`;
import { s } from '../../s';
import { useS } from '../../useS';
import style from './SnackbarBody.m.css';
interface Props {
title: string;
@@ -46,14 +15,17 @@ interface Props {
}
export const SnackbarBody: React.FC<React.PropsWithChildren<Props>> = function SnackbarBody({ title, className, children }) {
return styled(SNACKBAR_BODY_STYLES)(
<notification-body as="div" className={className}>
<body-text-block as="div">
<text-block-title title={title} as="h2">
const styles = useS(style);
return (
<div data-testid="notification-body" className={s(styles, { notificationBody: true }, className)}>
<div data-testid="body-text-block" className={styles.bodyTextBlock}>
<h2 data-testid="text-block-title" title={title} className={styles.textBlockTitle}>
{title}
</text-block-title>
<message as="div">{children}</message>
</body-text-block>
</notification-body>,
</h2>
<div data-testid="message" className={styles.message}>
{children}
</div>
</div>
</div>
);
};
@@ -0,0 +1,6 @@
.notificationContent {
display: flex;
flex-direction: column;
flex: 1;
overflow: hidden;
}
@@ -5,25 +5,19 @@
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
*/
import styled, { css } from 'reshadow';
const SNACKBAR_CONTENT_STYLES = css`
notification-content {
display: flex;
flex-direction: column;
flex: 1;
overflow: hidden;
}
`;
import { s } from '../../s';
import { useS } from '../../useS';
import style from './SnackbarContent.m.css';
interface Props {
className?: string;
}
export const SnackbarContent: React.FC<React.PropsWithChildren<Props>> = function SnackbarContent({ children, className }) {
return styled(SNACKBAR_CONTENT_STYLES)(
<notification-content as="div" className={className}>
const styles = useS(style);
return (
<div data-testid="notification-content" className={s(styles, { notificationContent: true }, className)}>
{children}
</notification-content>,
</div>
);
};
@@ -0,0 +1,18 @@
.notificationFooter {
display: flex;
align-items: flex-end;
justify-content: space-between;
}
.footerTime {
composes: theme-typography--caption from global;
opacity: 0.7;
}
.actions:empty {
display: none;
}
.actions > *:not(:first-child) {
margin-left: 16px;
}
@@ -5,25 +5,9 @@
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
*/
import styled, { css } from 'reshadow';
const SNACKBAR_FOOTER_STYLES = css`
notification-footer {
display: flex;
align-items: flex-end;
justify-content: space-between;
}
footer-time {
composes: theme-typography--caption from global;
opacity: 0.7;
}
actions:empty {
display: none;
}
actions > *:not(:first-child) {
margin-left: 16px;
}
`;
import { s } from '../../s';
import { useS } from '../../useS';
import style from './SnackbarFooter.m.css';
interface Props {
timestamp: number;
@@ -31,12 +15,17 @@ interface Props {
}
export const SnackbarFooter: React.FC<React.PropsWithChildren<Props>> = function SnackbarFooter({ timestamp, className, children }) {
const styles = useS(style);
const timeStringFromTimestamp = new Date(timestamp).toLocaleTimeString();
return styled(SNACKBAR_FOOTER_STYLES)(
<notification-footer as="div" className={className}>
<footer-time as="span">{timeStringFromTimestamp}</footer-time>
<actions as="div">{children}</actions>
</notification-footer>,
return (
<div data-testid="notification-footer" className={s(styles, { notificationFooter: true }, className)}>
<span data-testid="footer-time" className={styles.footerTime}>
{timeStringFromTimestamp}
</span>
<div data-testid="actions" className={styles.actions}>
{children}
</div>
</div>
);
};
@@ -0,0 +1,11 @@
.notificationMark {
padding-right: 12px;
}
.loaderContainer {
padding-right: 12px;
& .loader {
width: 40px;
height: 40px;
}
}
@@ -5,25 +5,13 @@
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
*/
import styled, { css } from 'reshadow';
import { ENotificationType } from '@cloudbeaver/core-events';
import { Loader } from '../../Loader/Loader';
import { s } from '../../s';
import { useS } from '../../useS';
import { NotificationMark } from '../NotificationMark';
const SNACKBAR_STATUS_STYLES = css`
NotificationMark {
padding-right: 12px;
}
loader-container {
padding-right: 12px;
& Loader {
width: 40px;
height: 40px;
}
}
`;
import style from './SnackbarStatus.m.css';
interface SnackbarStatusProps {
status: ENotificationType;
@@ -31,13 +19,12 @@ interface SnackbarStatusProps {
}
export const SnackbarStatus: React.FC<SnackbarStatusProps> = function SnackbarStatus({ status, className }) {
return styled(SNACKBAR_STATUS_STYLES)(
status === ENotificationType.Loading ? (
<loader-container className={className}>
<Loader fullSize hideMessage />
</loader-container>
) : (
<NotificationMark className={className} type={status} />
),
const styles = useS(style);
return status === ENotificationType.Loading ? (
<div data-testid="loader-container" className={s(styles, { loaderContainer: true }, className)}>
<Loader className={styles.loader} fullSize hideMessage />
</div>
) : (
<NotificationMark className={s(styles, { notificationMark: true }, className)} type={status} />
);
};
@@ -0,0 +1,40 @@
.notification {
composes: theme-background-surface theme-text-on-surface theme-elevation-z5 from global;
position: relative;
display: flex;
box-sizing: border-box;
overflow: hidden;
width: 500px;
margin-bottom: 16px;
margin-left: 16px;
padding: 16px 16px;
line-height: 1.5;
opacity: 0;
border-radius: var(--theme-group-element-radius);
transition: opacity 0.3s ease-in-out, transform 0.5s ease-in-out;
transform: translateX(-100%);
&.mounted {
transform: translateX(0);
opacity: 1;
}
&.closing {
opacity: 0;
}
}
.iconButton {
position: absolute;
&.large {
top: 8px;
right: 8px;
height: 22px;
width: 22px;
}
&:hover {
opacity: 0.7;
}
}
@@ -6,46 +6,11 @@
* you may not use this file except in compliance with the License.
*/
import { useEffect, useState } from 'react';
import styled, { css, use } from 'reshadow';
import { IconButton } from '../../IconButton';
const SNACKBAR_WRAPPER_STYLES = css`
notification {
composes: theme-background-surface theme-text-on-surface theme-elevation-z5 from global;
position: relative;
display: flex;
box-sizing: border-box;
overflow: hidden;
width: 500px;
margin-bottom: 16px;
margin-left: 16px;
padding: 16px 16px;
line-height: 1.5;
opacity: 0;
border-radius: var(--theme-group-element-radius);
transition: opacity 0.3s ease-in-out, transform 0.5s ease-in-out;
transform: translateX(-100%);
&[use|mounted] {
transform: translateX(0);
opacity: 1;
}
&[use|closing] {
opacity: 0;
}
}
IconButton {
position: absolute;
top: 8px;
right: 8px;
height: 22px;
width: 22px;
&:hover {
opacity: 0.7;
}
}
`;
import { s } from '../../s';
import { useS } from '../../useS';
import style from './SnackbarWrapper.m.css';
interface Props {
closing?: boolean;
@@ -61,16 +26,19 @@ export const SnackbarWrapper: React.FC<React.PropsWithChildren<Props>> = functio
children,
className,
}) {
const styles = useS(style);
const [mounted, setMounted] = useState(false);
useEffect(() => {
setMounted(true);
}, []);
return styled(SNACKBAR_WRAPPER_STYLES)(
<notification as="div" className={className} {...use({ mounted, closing })}>
return (
<div data-testid="notification" className={s(styles, { notification: true, mounted, closing }, className)}>
{children}
{!persistent && onClose && <IconButton name="cross" viewBox="0 0 16 16" onClick={onClose} />}
</notification>,
{!persistent && onClose && (
<IconButton name="cross" viewBox="0 0 16 16" className={s(styles, { iconButton: true, large: true })} onClick={onClose} />
)}
</div>
);
};