Merge pull request #581 from mirumee/feature/update-message-manager

update message manager
This commit is contained in:
AlicjaSzu 2020-07-03 18:26:40 +02:00 committed by GitHub
commit 7204687d80
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 803 additions and 119 deletions

View file

@ -0,0 +1,5 @@
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="16" cy="16" r="16" fill="#F5FAFB"/>
<rect x="10.2726" y="9.00024" width="17.9987" height="1.79987" transform="rotate(45 10.2726 9.00024)" fill="#FE6D76"/>
<rect x="23" y="10.2727" width="17.9987" height="1.79987" transform="rotate(135 23 10.2727)" fill="#FE6D76"/>
</svg>

After

Width:  |  Height:  |  Size: 380 B

View file

@ -0,0 +1,3 @@
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M16 32C24.8366 32 32 24.8366 32 16C32 7.16344 24.8366 0 16 0C7.16344 0 0 7.16344 0 16C0 24.8366 7.16344 32 16 32ZM15 20V8H17V20H15ZM15 24V22H17V24H15Z" fill="#CAD8DF"/>
</svg>

After

Width:  |  Height:  |  Size: 321 B

View file

@ -0,0 +1,4 @@
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="16" cy="16" r="16" fill="#F5FAFB"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M23.9167 10.306L12.5417 23L7 16.0699L8.48477 14.8326L12.611 20.0641L22.4919 9L23.9167 10.306Z" fill="#60DAA0"/>
</svg>

After

Width:  |  Height:  |  Size: 312 B

View file

@ -0,0 +1,5 @@
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="16" cy="16" r="16" fill="#F5FAFB"/>
<rect x="10.2726" y="9.00024" width="17.9987" height="1.79987" transform="rotate(45 10.2726 9.00024)" fill="#D98E1D"/>
<rect x="23" y="10.2727" width="17.9987" height="1.79987" transform="rotate(135 23 10.2727)" fill="#D98E1D"/>
</svg>

After

Width:  |  Height:  |  Size: 380 B

View file

@ -1420,6 +1420,18 @@
"context": "weight", "context": "weight",
"string": "{value} {unit}" "string": "{value} {unit}"
}, },
"src_dot_components_dot_messages_dot_1219076963": {
"context": "snackbar expand",
"string": "Expand"
},
"src_dot_components_dot_messages_dot_2473863536": {
"context": "snackbar button undo",
"string": "Undo"
},
"src_dot_components_dot_messages_dot_3444275093": {
"context": "snackbar collapse",
"string": "Collapse"
},
"src_dot_configuration": { "src_dot_configuration": {
"context": "configuration section name", "context": "configuration section name",
"string": "Configuration" "string": "Configuration"

View file

@ -0,0 +1,12 @@
import React from "react";
import { useStyles } from "./styles";
const Container = ({ children }) => {
const classes = useStyles({});
return (
!!children.length && <div className={classes.container}>{children}</div>
);
};
export default Container;

View file

@ -1,117 +1,155 @@
import Button from "@material-ui/core/Button"; import Button from "@material-ui/core/Button";
import IconButton from "@material-ui/core/IconButton"; import IconButton from "@material-ui/core/IconButton";
import Snackbar from "@material-ui/core/Snackbar"; import SnackbarContent from "@material-ui/core/SnackbarContent";
import Typography from "@material-ui/core/Typography"; import Typography from "@material-ui/core/Typography";
import CloseIcon from "@material-ui/icons/Close"; import CloseIcon from "@material-ui/icons/Close";
import React from "react"; import classNames from "classnames";
import React, { useState } from "react";
import { FormattedMessage } from "react-intl";
import { IMessage, MessageContext } from "./"; import { INotification } from "./";
import { useStyles } from "./styles";
interface Message extends IMessage { export interface IMessageManagerProps extends INotification {
key: string; onMouseEnter?: () => void;
} onMouseLeave?: () => void;
interface MessageManagerState {
message: Message;
opened: boolean;
} }
export class MessageManager extends React.Component<{}, MessageManagerState> { export const MessageManagerTemplate: React.FC<IMessageManagerProps> = props => {
state: MessageManagerState = { const {
message: { key: "0", onUndo: undefined, text: "" }, close,
opened: false onMouseEnter,
}; onMouseLeave,
queue = []; message: { actionBtn, expandText, status = "info", title, text, onUndo },
timeout
} = props;
handleClose = (_, reason) => { const [expand, setExpand] = useState(false);
if (reason === "clickaway") {
return;
}
this.setState({ opened: false });
};
handleExited = () => { const classes = useStyles({});
this.processQueue(); const id = props.id.toString();
};
pushMessage = (message: IMessage) => {
this.queue.push({
key: new Date().getTime(),
...message
});
if (this.state.opened) {
this.setState({ opened: false });
} else {
this.processQueue();
}
};
processQueue = () => {
if (this.queue.length > 0) {
this.setState({
message: this.queue.shift(),
opened: true
});
}
};
render() {
const { autohide = 3000, title, text, key, onUndo } = this.state.message;
return ( return (
<> <div
<Snackbar key={props.id}
key={key} className={classes.snackbarContainer}
anchorOrigin={{ onMouseEnter={onMouseEnter}
horizontal: "right", onMouseLeave={onMouseLeave}
vertical: "top" >
}} <SnackbarContent
open={this.state.opened} id={id}
autoHideDuration={autohide} key={id}
onClose={this.handleClose} aria-describedby={`message-id-${id}`}
onExited={this.handleExited} className={classNames(classes.snackbar, {
ContentProps={{ [classes.info]: status === "info",
"aria-describedby": "message-id" [classes.error]: status === "error",
}} [classes.success]: status === "success",
[classes.warning]: status === "warning"
})}
message={ message={
<span id="message-id" data-test="notification"> <span id={`message-id-${id}`} data-test="notification">
{title && ( {title && (
<Typography variant="h5" style={{ marginBottom: "1rem" }}> <Typography variant="h5" style={{ fontWeight: "bold" }}>
{title} {title}
</Typography> </Typography>
)} )}
<Typography
className={status === "info" ? classes.textInfo : classes.text}
>
{text} {text}
</Typography>
</span> </span>
} }
title={title}
action={[ action={[
!!onUndo ? ( !!expandText ? (
<Button <div
key="undo" key="expanded"
color="secondary" className={classNames(classes.expandedContainer, {
size="small" [classes.expandedContainerInfo]: status === "info"
onClick={this.handleClose as any} })}
data-test="button-undo"
> >
UNDO <div
</Button> className={classNames(
classes.expandedContainerContent,
expand ? classes.expandedText : classes.hiddenText
)}
>
<p>{expandText}</p>
</div>
<button
className={classNames(classes.expandBtn, {
[classes.expandBtnInfo]: status === "info"
})}
onClick={() => {
setExpand(expand => !expand);
}}
>
{!expand ? (
<FormattedMessage
defaultMessage="Expand"
description="snackbar expand"
/>
) : (
<FormattedMessage
defaultMessage="Collapse"
description="snackbar collapse"
/>
)}
</button>
</div>
) : ( ) : (
undefined undefined
), ),
<div key="actions" className={classes.actionContainer}>
{!!onUndo && (
<Button
key="undo"
color="default"
size="small"
onClick={close}
data-test="button-undo"
>
<FormattedMessage
defaultMessage="Undo"
description="snackbar button undo"
/>
</Button>
)}
{!!actionBtn && (
<Button
key="action"
color="default"
size="small"
onClick={actionBtn.action}
data-test="button-action"
>
{actionBtn.label}
</Button>
)}
</div>,
<IconButton <IconButton
key="close" key="close"
aria-label="Close" aria-label="Close"
color="inherit" color="inherit"
onClick={this.handleClose as any} onClick={close}
className={classNames(classes.closeBtn, {
[classes.closeBtnInfo]: status === "info"
})}
> >
<CloseIcon /> <CloseIcon />
</IconButton> </IconButton>,
<div className={classes.progressBarContainer} key="progressBar">
<div
className={classNames(classes.progressBar, {
[classes.progressBarSuccess]: status === "success",
[classes.progressBarWarning]: status === "warning",
[classes.progressBarError]: status === "error"
})}
style={{ ["--animationTime" as any]: `${timeout}ms` }}
/>
</div>
]} ]}
/> />
<MessageContext.Provider value={this.pushMessage}> </div>
{this.props.children}
</MessageContext.Provider>
</>
); );
} };
}
export default MessageManager;

View file

@ -0,0 +1,130 @@
import React, { useCallback, useEffect, useRef, useState } from "react";
import { createPortal } from "react-dom";
import { TransitionGroup } from "react-transition-group";
import {
INotification,
ITimer,
MessageContext,
MessageManagerTemplate
} from ".";
import Container from "./Container";
import Transition from "./Transition";
const MessageManagerProvider = ({ children }) => {
const root = useRef(null);
const timersArr = useRef<ITimer[]>([]);
const [notifications, setNotifications] = useState<INotification[]>([]);
useEffect(() => {
root.current = document.createElement("div");
root.current.id = "__message-manager__";
document.body.appendChild(root.current);
const timersArrRef = timersArr.current;
return () => {
timersArrRef.forEach(timer => clearTimeout(timer.timeoutId));
if (root.current) {
document.body.removeChild(root.current);
}
};
}, []);
const timerCallback = (notification: INotification) => {
remove(notification.id);
timersArr.current = timersArr.current.filter(
timer => timer.id !== notification.id
);
};
const remove = useCallback(notificationId => {
setNotifications(currentNotifications =>
currentNotifications.filter(n => n.id !== notificationId)
);
}, []);
const show = useCallback((message = {}, timeout = 3000) => {
const id = Date.now();
const notification = {
close: () => remove(id),
id,
message,
timeout
};
if (timeout !== null) {
const timeoutId = window.setTimeout(() => {
timerCallback(notification);
}, timeout);
timersArr.current.push({
id: notification.id,
notification,
remaining: timeout,
start: new Date().getTime(),
timeoutId
});
}
setNotifications(state => [notification, ...state]);
return notification;
}, []);
const getCurrentTimer = (notification: INotification) => {
const currentTimerIndex = timersArr.current.findIndex(
timer => timer.id === notification.id
);
return timersArr.current[currentTimerIndex];
};
const pauseTimer = (notification: INotification) => {
const currentTimer = getCurrentTimer(notification);
if (currentTimer) {
currentTimer.remaining =
currentTimer.remaining - (new Date().getTime() - currentTimer.start);
window.clearTimeout(currentTimer.timeoutId);
}
};
const resumeTimer = (notification: INotification) => {
const currentTimer = getCurrentTimer(notification);
if (currentTimer) {
currentTimer.start = new Date().getTime();
currentTimer.timeoutId = window.setTimeout(
() => timerCallback(notification),
currentTimer.remaining
);
}
};
return (
<MessageContext.Provider value={{ remove, show }}>
{children}
{root.current &&
createPortal(
<TransitionGroup
appear
options={{ position: "top right" }}
component={Container}
>
{!!notifications.length &&
notifications.map(notification => (
<Transition key={notification.id}>
<MessageManagerTemplate
{...notification}
{...(!!notification.timeout
? {
onMouseEnter: () => pauseTimer(notification),
onMouseLeave: () => resumeTimer(notification)
}
: {})}
/>
</Transition>
))}
</TransitionGroup>,
root.current
)}
</MessageContext.Provider>
);
};
export default MessageManagerProvider;

View file

@ -0,0 +1,31 @@
import React from "react";
import { Transition as MessageManagerTransition } from "react-transition-group";
const duration = 250;
const defaultStyle = {
opacity: 0,
transition: `opacity ${duration}ms ease`
};
const transitionStyles = {
entered: { opacity: 1 },
entering: { opacity: 0 }
};
const Transition = ({ children, ...props }) => (
<MessageManagerTransition {...props} timeout={duration}>
{state => (
<div
style={{
...defaultStyle,
...transitionStyles[state]
}}
>
{children}
</div>
)}
</MessageManagerTransition>
);
export default Transition;

View file

@ -1,13 +1,48 @@
import { createContext } from "react"; import { createContext } from "react";
export type Status = "success" | "error" | "info" | "warning";
export interface IMessage { export interface IMessage {
actionBtn?: {
label: string;
action: () => void;
};
autohide?: number; autohide?: number;
expandText?: string;
title?: string; title?: string;
text: string; text: string;
onUndo?: () => void; onUndo?: () => void;
status?: Status;
} }
export interface INotification {
id: number;
message: IMessage;
timeout: number;
close: () => void;
}
export interface ITimer {
id: number;
notification: INotification;
remaining: number;
start: number;
timeoutId: number;
}
export const types = {
ERROR: "error",
INFO: "info",
SUCCESS: "success",
WARNING: "warning"
};
export interface INotificationContext {
show: (message: IMessage, timeout?: number | null) => void;
remove: (notification: INotification) => void;
}
export type IMessageContext = (message: IMessage) => void; export type IMessageContext = (message: IMessage) => void;
export const MessageContext = createContext<IMessageContext>(undefined); export const MessageContext = createContext<INotificationContext>(null);
export * from "./MessageManager"; export * from "./MessageManager";
export default MessageContext.Consumer; export * from "./MessageManagerProvider";
export { default } from "./MessageManagerProvider";

View file

@ -0,0 +1,213 @@
import errorIcon from "@assets/images/error-icon.svg";
import infoIcon from "@assets/images/info-icon.svg";
import successIcon from "@assets/images/success-icon.svg";
import warningIcon from "@assets/images/warning-icon.svg";
import { makeStyles } from "@material-ui/core/styles";
import { darken } from "@material-ui/core/styles/colorManipulator";
const successColor = "#60DAA0";
const warningColor = "#FFB84E";
const infoColor = "#CAD8DF";
const errorColor = "#FE6E76";
export const useStyles = makeStyles(
theme => ({
"@keyframes bar": {
from: { transform: "translateX(-100%)" },
to: { transform: "translateX(0)" }
},
actionContainer: {
marginLeft: -8
},
closeBtn: {
"& svg": {
maxHeight: 18,
maxWidth: 18
},
color: "#fff",
padding: 10,
position: "absolute",
right: 5,
top: 7
},
closeBtnInfo: {
color: theme.palette.text.primary
},
container: {
display: "grid",
gridTemplateRows: "repeat(auto-fill, minmax(90px, 1fr))",
justifyContent: "end",
left: 0,
pointerEvents: "none",
position: "fixed",
top: 0,
width: "100%",
zIndex: 1200
},
error: {
"& > div": {
"& button span": {
color: "#fff"
}
},
"& > div:first-child": {
"&:before": {
backgroundImage: `url(${errorIcon})`
}
},
backgroundColor: errorColor,
color: "#fff"
},
expandBtn: {
"&:before": {
borderLeft: "4px solid transparent",
borderRight: "4px solid transparent",
borderTop: "8px solid #fff",
content: "''",
display: "block",
height: 0,
position: "absolute",
right: 0,
top: "50%",
transform: "translateY(-50%)",
width: 0
},
background: "transparent",
border: "none",
color: "#fff",
cursor: "pointer",
fontSize: theme.spacing(2),
outline: "none",
padding: 0,
paddingRight: 15,
position: "relative"
},
expandBtnInfo: {
"&:before": {
borderTop: `8px solid ${theme.palette.text.primary}`
},
color: theme.palette.text.primary
},
expandedContainer: {
"& p": {
margin: theme.spacing(1, 0)
},
color: "#fff",
marginBottom: 5
},
expandedContainerContent: {
overflow: "hidden",
transition: "max-height .6s ease"
},
expandedContainerInfo: {
color: theme.palette.text.secondary
},
expandedText: {
maxHeight: 500
},
hiddenText: {
maxHeight: 0
},
info: {
"& > div:first-child": {
"&:before": {
backgroundImage: `url(${infoIcon})`
}
}
},
progressBar: {
animation: `$bar var(--animationTime) ease both`,
backgroundColor: infoColor,
height: 8,
transform: "translateX(-100%)",
width: "100%"
},
progressBarContainer: {
borderRadius: "0 0 4px 4px",
bottom: 0,
left: 0,
overflow: "hidden",
position: "absolute",
width: "calc(100%)"
},
progressBarError: {
backgroundColor: darken(errorColor, 0.2)
},
progressBarSuccess: {
backgroundColor: darken(successColor, 0.2)
},
progressBarWarning: {
backgroundColor: darken(warningColor, 0.2)
},
snackbar: {
"& > div": {
paddingLeft: 60
},
"& > div:first-child": {
"&:before": {
backgroundRepeat: "no-repeat",
backgroundSize: "contain",
content: "''",
display: "block",
height: 32,
left: 15,
position: "absolute",
top: 13,
width: 32
},
paddingTop: 16,
position: "relative"
},
"&:hover": {
"& [class*='progressBar']": {
animationPlayState: "paused"
}
},
borderRadius: 4,
paddingBottom: 15,
paddingLeft: 5,
paddingRight: 45,
position: "relative"
},
snackbarContainer: {
borderRadius: 4,
display: "block",
margin: theme.spacing(2, 2, 0, 2),
maxWidth: 450,
pointerEvents: "all",
position: "relative"
},
success: {
"& > div:first-child": {
"&:before": {
backgroundImage: `url(${successIcon})`
}
},
"& button span": {
color: "#fff"
},
backgroundColor: successColor,
color: "#fff"
},
text: {
color: "#fff",
paddingTop: 5
},
textInfo: {
paddingTop: 5
},
warning: {
"& > div:first-child": {
"&:before": {
backgroundImage: `url(${warningIcon})`
}
},
"& button span": {
color: "#fff"
},
backgroundColor: warningColor,
color: "#fff"
}
}),
{ name: "MessageManager" }
);

View file

@ -1,9 +1,16 @@
import { IMessage } from "@saleor/components/messages";
import { IMessageContext, MessageContext } from "@saleor/components/messages"; import { IMessageContext, MessageContext } from "@saleor/components/messages";
import { useContext } from "react"; import { useContext } from "react";
export type UseNotifierResult = IMessageContext; export type UseNotifierResult = IMessageContext;
function useNotifier(): UseNotifierResult { function useNotifier(): UseNotifierResult {
const notify = useContext(MessageContext); const notificationContext = useContext(MessageContext);
const notify = (options: IMessage) => {
const timeout = options.status === "error" ? null : options.autohide;
notificationContext.show(options, timeout);
};
return notify; return notify;
} }
export default useNotifier; export default useNotifier;

View file

@ -28,7 +28,7 @@ import CollectionSection from "./collections";
import AppLayout from "./components/AppLayout"; import AppLayout from "./components/AppLayout";
import { DateProvider } from "./components/Date"; import { DateProvider } from "./components/Date";
import { LocaleProvider } from "./components/Locale"; import { LocaleProvider } from "./components/Locale";
import { MessageManager } from "./components/messages"; import MessageManagerProvider from "./components/messages";
import { ShopProvider } from "./components/Shop"; import { ShopProvider } from "./components/Shop";
import ThemeProvider from "./components/Theme"; import ThemeProvider from "./components/Theme";
import { WindowTitle } from "./components/WindowTitle"; import { WindowTitle } from "./components/WindowTitle";
@ -135,7 +135,7 @@ const App: React.FC = () => {
<ThemeProvider isDefaultDark={isDark}> <ThemeProvider isDefaultDark={isDark}>
<DateProvider> <DateProvider>
<LocaleProvider> <LocaleProvider>
<MessageManager> <MessageManagerProvider>
<BackgroundTasksProvider> <BackgroundTasksProvider>
<AppStateProvider> <AppStateProvider>
<ShopProvider> <ShopProvider>
@ -143,7 +143,7 @@ const App: React.FC = () => {
</ShopProvider> </ShopProvider>
</AppStateProvider> </AppStateProvider>
</BackgroundTasksProvider> </BackgroundTasksProvider>
</MessageManager> </MessageManagerProvider>
</LocaleProvider> </LocaleProvider>
</DateProvider> </DateProvider>
</ThemeProvider> </ThemeProvider>

View file

@ -3,7 +3,7 @@ import React from "react";
import { IntlProvider } from "react-intl"; import { IntlProvider } from "react-intl";
import { Provider as DateProvider } from "../components/Date/DateContext"; import { Provider as DateProvider } from "../components/Date/DateContext";
import { MessageManager } from "../components/messages"; import MessageManagerProvider from "../components/messages";
import ThemeProvider from "../components/Theme"; import ThemeProvider from "../components/Theme";
import { TimezoneProvider } from "../components/Timezone"; import { TimezoneProvider } from "../components/Timezone";
@ -18,7 +18,7 @@ export const Decorator = storyFn => (
<DateProvider value={+new Date("2018-08-07T14:30:44+00:00")}> <DateProvider value={+new Date("2018-08-07T14:30:44+00:00")}>
<TimezoneProvider value="America/New_York"> <TimezoneProvider value="America/New_York">
<ThemeProvider isDefaultDark={false}> <ThemeProvider isDefaultDark={false}>
<MessageManager> <MessageManagerProvider>
<div <div
style={{ style={{
padding: 24 padding: 24
@ -26,7 +26,7 @@ export const Decorator = storyFn => (
> >
{storyFn()} {storyFn()}
</div> </div>
</MessageManager> </MessageManagerProvider>
</ThemeProvider> </ThemeProvider>
</TimezoneProvider> </TimezoneProvider>
</DateProvider> </DateProvider>

View file

@ -2612,6 +2612,118 @@ exports[`Storyshots Generics / Global messages default 1`] = `
</div> </div>
`; `;
exports[`Storyshots Generics / Global messages with action 1`] = `
<div
style="padding:24px"
>
<div
class="MuiPaper-root-id MuiPaper-elevation0-id MuiCard-root-id MuiPaper-rounded-id"
style="margin:auto;overflow:visible;position:relative;width:400px"
>
<div
class="MuiCardContent-root-id"
>
<button
class="MuiButtonBase-root-id MuiButton-root-id MuiButton-contained-id MuiButton-containedPrimary-id"
style="display:block;margin:auto"
tabindex="0"
type="button"
>
<span
class="MuiButton-label-id"
>
Push message
</span>
</button>
</div>
</div>
</div>
`;
exports[`Storyshots Generics / Global messages with error status 1`] = `
<div
style="padding:24px"
>
<div
class="MuiPaper-root-id MuiPaper-elevation0-id MuiCard-root-id MuiPaper-rounded-id"
style="margin:auto;overflow:visible;position:relative;width:400px"
>
<div
class="MuiCardContent-root-id"
>
<button
class="MuiButtonBase-root-id MuiButton-root-id MuiButton-contained-id MuiButton-containedPrimary-id"
style="display:block;margin:auto"
tabindex="0"
type="button"
>
<span
class="MuiButton-label-id"
>
Push message
</span>
</button>
</div>
</div>
</div>
`;
exports[`Storyshots Generics / Global messages with expandText 1`] = `
<div
style="padding:24px"
>
<div
class="MuiPaper-root-id MuiPaper-elevation0-id MuiCard-root-id MuiPaper-rounded-id"
style="margin:auto;overflow:visible;position:relative;width:400px"
>
<div
class="MuiCardContent-root-id"
>
<button
class="MuiButtonBase-root-id MuiButton-root-id MuiButton-contained-id MuiButton-containedPrimary-id"
style="display:block;margin:auto"
tabindex="0"
type="button"
>
<span
class="MuiButton-label-id"
>
Push message
</span>
</button>
</div>
</div>
</div>
`;
exports[`Storyshots Generics / Global messages with success status 1`] = `
<div
style="padding:24px"
>
<div
class="MuiPaper-root-id MuiPaper-elevation0-id MuiCard-root-id MuiPaper-rounded-id"
style="margin:auto;overflow:visible;position:relative;width:400px"
>
<div
class="MuiCardContent-root-id"
>
<button
class="MuiButtonBase-root-id MuiButton-root-id MuiButton-contained-id MuiButton-containedPrimary-id"
style="display:block;margin:auto"
tabindex="0"
type="button"
>
<span
class="MuiButton-label-id"
>
Push message
</span>
</button>
</div>
</div>
</div>
`;
exports[`Storyshots Generics / Global messages with undo action 1`] = ` exports[`Storyshots Generics / Global messages with undo action 1`] = `
<div <div
style="padding:24px" style="padding:24px"
@ -2640,6 +2752,34 @@ exports[`Storyshots Generics / Global messages with undo action 1`] = `
</div> </div>
`; `;
exports[`Storyshots Generics / Global messages with warning status 1`] = `
<div
style="padding:24px"
>
<div
class="MuiPaper-root-id MuiPaper-elevation0-id MuiCard-root-id MuiPaper-rounded-id"
style="margin:auto;overflow:visible;position:relative;width:400px"
>
<div
class="MuiCardContent-root-id"
>
<button
class="MuiButtonBase-root-id MuiButton-root-id MuiButton-contained-id MuiButton-containedPrimary-id"
style="display:block;margin:auto"
tabindex="0"
type="button"
>
<span
class="MuiButton-label-id"
>
Push message
</span>
</button>
</div>
</div>
</div>
`;
exports[`Storyshots Generics / Link with choices default 1`] = ` exports[`Storyshots Generics / Link with choices default 1`] = `
<div <div
style="padding:24px" style="padding:24px"

View file

@ -1,4 +1,5 @@
import Button from "@material-ui/core/Button"; import Button from "@material-ui/core/Button";
import { IMessage } from "@saleor/components/messages";
import useNotifier from "@saleor/hooks/useNotifier"; import useNotifier from "@saleor/hooks/useNotifier";
import { storiesOf } from "@storybook/react"; import { storiesOf } from "@storybook/react";
import React from "react"; import React from "react";
@ -6,10 +7,18 @@ import React from "react";
import CardDecorator from "../../CardDecorator"; import CardDecorator from "../../CardDecorator";
import Decorator from "../../Decorator"; import Decorator from "../../Decorator";
interface StoryProps { const props = {
undo: boolean; text: "This is message",
} title: "Title"
const Story: React.FC<StoryProps> = ({ undo }) => { };
const Story: React.FC<IMessage> = ({
actionBtn,
expandText,
onUndo,
status,
title,
text
}) => {
const pushMessage = useNotifier(); const pushMessage = useNotifier();
return ( return (
@ -18,8 +27,12 @@ const Story: React.FC<StoryProps> = ({ undo }) => {
variant="contained" variant="contained"
onClick={() => onClick={() =>
pushMessage({ pushMessage({
onUndo: undo ? () => undefined : undefined, actionBtn,
text: "This is message" expandText,
onUndo: onUndo ? () => undefined : undefined,
status,
text,
title
}) })
} }
style={{ display: "block", margin: "auto" }} style={{ display: "block", margin: "auto" }}
@ -32,5 +45,39 @@ const Story: React.FC<StoryProps> = ({ undo }) => {
storiesOf("Generics / Global messages", module) storiesOf("Generics / Global messages", module)
.addDecorator(CardDecorator) .addDecorator(CardDecorator)
.addDecorator(Decorator) .addDecorator(Decorator)
.add("default", () => <Story undo={false} />) .add("default", () => <Story {...props} />)
.add("with undo action", () => <Story undo={true} />); .add("with undo action", () => <Story onUndo={() => undefined} {...props} />)
.add("with expandText", () => (
<Story expandText={"Some expanded text"} {...props} />
))
.add("with action", () => (
<Story
actionBtn={{ action: () => undefined, label: "Action" }}
{...props}
/>
))
.add("with success status", () => (
<Story
{...props}
actionBtn={{ action: () => undefined, label: "Action" }}
status="success"
title="Success!"
/>
))
.add("with error status", () => (
<Story
{...props}
actionBtn={{ action: () => undefined, label: "Action" }}
expandText={"Some expanded text"}
status="error"
title="Error"
/>
))
.add("with warning status", () => (
<Story
{...props}
expandText={"Some expanded text"}
status="warning"
title="Warning"
/>
));

View file

@ -343,7 +343,10 @@ export default (colors: IThemeColors): Theme =>
color: colors.font.default color: colors.font.default
} }
}, },
alignSelf: "baseline" display: "block",
paddingBottom: 10,
paddingLeft: 0,
paddingRight: 45
}, },
message: { message: {
fontSize: 16 fontSize: 16
@ -353,8 +356,7 @@ export default (colors: IThemeColors): Theme =>
boxShadow: boxShadow:
"0 6px 10px 0px rgba(0, 0, 0, 0.15), 0 1px 18px 0px rgba(0, 0, 0, 0.12), 0 3px 5px -1px rgba(0, 0, 0, 0.10)", "0 6px 10px 0px rgba(0, 0, 0, 0.15), 0 1px 18px 0px rgba(0, 0, 0, 0.12), 0 3px 5px -1px rgba(0, 0, 0, 0.10)",
color: colors.font.default, color: colors.font.default,
display: "grid", display: "block",
gridTemplateColumns: "1fr 56px",
maxWidth: 480 maxWidth: 480
} }
}, },