diff --git a/docs/src/pages/demos/snackbars/ConsecutiveSnackbars.js b/docs/src/pages/demos/snackbars/ConsecutiveSnackbars.js index 53abfd8207e54a..d953f8ac4d2d8e 100644 --- a/docs/src/pages/demos/snackbars/ConsecutiveSnackbars.js +++ b/docs/src/pages/demos/snackbars/ConsecutiveSnackbars.js @@ -15,10 +15,13 @@ const styles = theme => ({ class ConsecutiveSnackbars extends React.Component { queue = []; - state = { - open: false, - messageInfo: {}, - }; + constructor(props) { + super(props); + + this.state = { + open: false, + }; + } handleClick = message => () => { this.queue.push({ @@ -57,7 +60,7 @@ class ConsecutiveSnackbars extends React.Component { render() { const { classes } = this.props; - const { messageInfo } = this.state; + const { messageInfo = {} } = this.state; return (
diff --git a/docs/src/pages/demos/snackbars/ConsecutiveSnackbars.tsx b/docs/src/pages/demos/snackbars/ConsecutiveSnackbars.tsx new file mode 100644 index 00000000000000..dfd5580f6ad668 --- /dev/null +++ b/docs/src/pages/demos/snackbars/ConsecutiveSnackbars.tsx @@ -0,0 +1,121 @@ +import React, { SyntheticEvent } from 'react'; +import PropTypes, { number } from 'prop-types'; +import { createStyles, withStyles, WithStyles, Theme } from '@material-ui/core/styles'; +import Button from '@material-ui/core/Button'; +import Snackbar from '@material-ui/core/Snackbar'; +import IconButton from '@material-ui/core/IconButton'; +import CloseIcon from '@material-ui/icons/Close'; +import { string } from 'parsimmon'; + +const styles = (theme: Theme) => + createStyles({ + close: { + padding: theme.spacing(0.5), + }, + }); + +export interface SnackbarMessage { + message: string; + key: number; +} + +export type Props = WithStyles; + +export interface State { + open: boolean; + messageInfo?: SnackbarMessage; +} + +class ConsecutiveSnackbars extends React.Component { + queue: SnackbarMessage[] = []; + + constructor(props: Props) { + super(props); + + this.state = { + open: false, + }; + } + + handleClick = (message: string) => () => { + this.queue.push({ + message, + key: new Date().getTime(), + }); + + if (this.state.open) { + // immediately begin dismissing current message + // to start showing new one + this.setState({ open: false }); + } else { + this.processQueue(); + } + }; + + processQueue = () => { + if (this.queue.length > 0) { + this.setState({ + messageInfo: this.queue.shift(), + open: true, + }); + } + }; + + handleClose = (event: SyntheticEvent | MouseEvent, reason?: string) => { + if (reason === 'clickaway') { + return; + } + this.setState({ open: false }); + }; + + handleExited = () => { + this.processQueue(); + }; + + render() { + const { classes } = this.props; + const { messageInfo = {} as SnackbarMessage } = this.state; + + return ( +
+ + + {messageInfo.message}} + action={[ + , + + + , + ]} + /> +
+ ); + } +} + +(ConsecutiveSnackbars as React.ComponentClass).propTypes = { + classes: PropTypes.object.isRequired, +} as any; + +export default withStyles(styles)(ConsecutiveSnackbars); diff --git a/docs/src/pages/demos/snackbars/CustomizedSnackbars.tsx b/docs/src/pages/demos/snackbars/CustomizedSnackbars.tsx new file mode 100644 index 00000000000000..97cb04ea8e6094 --- /dev/null +++ b/docs/src/pages/demos/snackbars/CustomizedSnackbars.tsx @@ -0,0 +1,162 @@ +import React, { SyntheticEvent } from 'react'; +import PropTypes from 'prop-types'; +import clsx from 'clsx'; +import Button from '@material-ui/core/Button'; +import CheckCircleIcon from '@material-ui/icons/CheckCircle'; +import ErrorIcon from '@material-ui/icons/Error'; +import InfoIcon from '@material-ui/icons/Info'; +import CloseIcon from '@material-ui/icons/Close'; +import green from '@material-ui/core/colors/green'; +import amber from '@material-ui/core/colors/amber'; +import IconButton from '@material-ui/core/IconButton'; +import Snackbar from '@material-ui/core/Snackbar'; +import SnackbarContent from '@material-ui/core/SnackbarContent'; +import WarningIcon from '@material-ui/icons/Warning'; +import { makeStyles, Theme } from '@material-ui/core/styles'; + +const variantIcon = { + success: CheckCircleIcon, + warning: WarningIcon, + error: ErrorIcon, + info: InfoIcon, +}; + +const useStyles1 = makeStyles((theme: Theme) => ({ + success: { + backgroundColor: green[600], + }, + error: { + backgroundColor: theme.palette.error.dark, + }, + info: { + backgroundColor: theme.palette.primary.dark, + }, + warning: { + backgroundColor: amber[700], + }, + icon: { + fontSize: 20, + }, + iconVariant: { + opacity: 0.9, + marginRight: theme.spacing(1), + }, + message: { + display: 'flex', + alignItems: 'center', + }, +})); + +export interface Props { + className?: string; + message?: string; + onClose?: () => void; + variant: keyof typeof variantIcon; +} + +function MySnackbarContentWrapper(props: Props) { + const classes = useStyles1(); + const { className, message, onClose, variant, ...other } = props; + const Icon = variantIcon[variant]; + + return ( + + + {message} + + } + action={[ + + + , + ]} + {...other} + /> + ); +} + +MySnackbarContentWrapper.propTypes = { + className: PropTypes.string, + message: PropTypes.node, + onClose: PropTypes.func, + variant: PropTypes.oneOf(['success', 'warning', 'error', 'info']).isRequired, +}; + +const useStyles2 = makeStyles((theme: Theme) => ({ + margin: { + margin: theme.spacing(1), + }, +})); + +function CustomizedSnackbars() { + const classes = useStyles2(); + const [open, setOpen] = React.useState(false); + + function handleClick() { + setOpen(true); + } + + function handleClose(event?: SyntheticEvent, reason?: string) { + if (reason === 'clickaway') { + return; + } + + setOpen(false); + } + + return ( +
+ + + + + + + + +
+ ); +} + +export default CustomizedSnackbars; diff --git a/docs/src/pages/demos/snackbars/DirectionSnackbar.js b/docs/src/pages/demos/snackbars/DirectionSnackbar.js index d1af62e229158c..c4d2027a3d5247 100644 --- a/docs/src/pages/demos/snackbars/DirectionSnackbar.js +++ b/docs/src/pages/demos/snackbars/DirectionSnackbar.js @@ -20,10 +20,13 @@ function TransitionDown(props) { } class DirectionSnackbar extends React.Component { - state = { - open: false, - Transition: null, - }; + constructor() { + super(); + + this.state = { + open: false, + }; + } handleClick = Transition => () => { this.setState({ open: true, Transition }); diff --git a/docs/src/pages/demos/snackbars/DirectionSnackbar.tsx b/docs/src/pages/demos/snackbars/DirectionSnackbar.tsx new file mode 100644 index 00000000000000..0557f16e49c899 --- /dev/null +++ b/docs/src/pages/demos/snackbars/DirectionSnackbar.tsx @@ -0,0 +1,66 @@ +import React from 'react'; +import Button from '@material-ui/core/Button'; +import Snackbar from '@material-ui/core/Snackbar'; +import Slide from '@material-ui/core/Slide'; +import { TransitionProps } from '@material-ui/core/transitions/transition'; + +function TransitionLeft(props: TransitionProps) { + return ; +} + +function TransitionUp(props: TransitionProps) { + return ; +} + +function TransitionRight(props: TransitionProps) { + return ; +} + +function TransitionDown(props: TransitionProps) { + return ; +} + +export interface State { + open: boolean; + Transition?: React.ComponentType; +} + +class DirectionSnackbar extends React.Component { + constructor() { + super(); + + this.state = { + open: false, + }; + } + + handleClick = (Transition: React.ComponentType) => () => { + this.setState({ open: true, Transition }); + }; + + handleClose = () => { + this.setState({ open: false }); + }; + + render() { + return ( +
+ + + + + I love snacks} + /> +
+ ); + } +} + +export default DirectionSnackbar; diff --git a/docs/src/pages/demos/snackbars/FabIntegrationSnackbar.tsx b/docs/src/pages/demos/snackbars/FabIntegrationSnackbar.tsx new file mode 100644 index 00000000000000..5c17dda66eba31 --- /dev/null +++ b/docs/src/pages/demos/snackbars/FabIntegrationSnackbar.tsx @@ -0,0 +1,116 @@ +import React from 'react'; +import clsx from 'clsx'; +import { makeStyles, Theme } from '@material-ui/core/styles'; +import AppBar from '@material-ui/core/AppBar'; +import Toolbar from '@material-ui/core/Toolbar'; +import IconButton from '@material-ui/core/IconButton'; +import MenuIcon from '@material-ui/icons/Menu'; +import Typography from '@material-ui/core/Typography'; +import Button from '@material-ui/core/Button'; +import Fab from '@material-ui/core/Fab'; +import AddIcon from '@material-ui/icons/Add'; +import Snackbar from '@material-ui/core/Snackbar'; + +const useStyles = makeStyles((theme: Theme) => ({ + root: { + position: 'relative', + overflow: 'hidden', + }, + appFrame: { + width: 360, + height: 360, + backgroundColor: theme.palette.background.paper, + }, + menuButton: { + marginRight: 20, + }, + button: { + marginBottom: theme.spacing(1), + }, + fab: { + position: 'absolute', + bottom: theme.spacing(2), + right: theme.spacing(2), + }, + fabMoveUp: { + transform: 'translate3d(0, -46px, 0)', + transition: theme.transitions.create('transform', { + duration: theme.transitions.duration.enteringScreen, + easing: theme.transitions.easing.easeOut, + }), + }, + fabMoveDown: { + transform: 'translate3d(0, 0, 0)', + transition: theme.transitions.create('transform', { + duration: theme.transitions.duration.leavingScreen, + easing: theme.transitions.easing.sharp, + }), + }, + snackbar: { + position: 'absolute', + }, + snackbarContent: { + width: 360, + }, +})); + +function FabIntegrationSnackbar() { + const classes = useStyles(); + const [open, setOpen] = React.useState(false); + + function handleClick() { + setOpen(true); + } + + function handleClose() { + setOpen(false); + } + + const fabClassName = clsx(classes.fab, open ? classes.fabMoveUp : classes.fabMoveDown); + + return ( +
+ +
+ + + + + + + Out of my way! + + + + + + + Archived} + action={ + + } + className={classes.snackbar} + /> +
+
+ ); +} + +export default FabIntegrationSnackbar; diff --git a/docs/src/pages/demos/snackbars/FadeSnackbar.tsx b/docs/src/pages/demos/snackbars/FadeSnackbar.tsx new file mode 100644 index 00000000000000..e9f96f662fc1c0 --- /dev/null +++ b/docs/src/pages/demos/snackbars/FadeSnackbar.tsx @@ -0,0 +1,33 @@ +import React from 'react'; +import Button from '@material-ui/core/Button'; +import Snackbar from '@material-ui/core/Snackbar'; +import Fade from '@material-ui/core/Fade'; + +function FadeSnackbar() { + const [open, setOpen] = React.useState(false); + + function handleClick() { + setOpen(true); + } + + function handleClose() { + setOpen(false); + } + + return ( +
+ + I love snacks} + /> +
+ ); +} + +export default FadeSnackbar; diff --git a/docs/src/pages/demos/snackbars/IntegrationNotistack.js b/docs/src/pages/demos/snackbars/IntegrationNotistack.js index 941cf0df5246b9..1f657aa48327f7 100644 --- a/docs/src/pages/demos/snackbars/IntegrationNotistack.js +++ b/docs/src/pages/demos/snackbars/IntegrationNotistack.js @@ -4,12 +4,16 @@ import Button from '@material-ui/core/Button'; import { SnackbarProvider, withSnackbar } from 'notistack'; class App extends React.Component { + static propTypes = { + enqueueSnackbar: PropTypes.func.isRequired, + }; + handleClick = () => { this.props.enqueueSnackbar('I love snacks.'); }; handleClickVariant = variant => () => { - // variant could be success, error, warning or info + // variant could be success, error, warning, info, or default this.props.enqueueSnackbar('This is a warning message!', { variant }); }; @@ -23,10 +27,6 @@ class App extends React.Component { } } -App.propTypes = { - enqueueSnackbar: PropTypes.func.isRequired, -}; - const MyApp = withSnackbar(App); function IntegrationNotistack() { diff --git a/docs/src/pages/demos/snackbars/IntegrationNotistack.tsx b/docs/src/pages/demos/snackbars/IntegrationNotistack.tsx new file mode 100644 index 00000000000000..914048cbb2753f --- /dev/null +++ b/docs/src/pages/demos/snackbars/IntegrationNotistack.tsx @@ -0,0 +1,40 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import Button from '@material-ui/core/Button'; +import { SnackbarProvider, VariantType, withSnackbar, withSnackbarProps } from 'notistack'; + +class App extends React.Component { + static propTypes = { + enqueueSnackbar: PropTypes.func.isRequired, + }; + + handleClick = () => { + this.props.enqueueSnackbar('I love snacks.'); + }; + + handleClickVariant = (variant: VariantType) => () => { + // variant could be success, error, warning, info, or default + this.props.enqueueSnackbar('This is a warning message!', { variant }); + }; + + render() { + return ( + + + + + ); + } +} + +const MyApp = withSnackbar(App); + +function IntegrationNotistack() { + return ( + + + + ); +} + +export default IntegrationNotistack; diff --git a/docs/src/pages/demos/snackbars/LongTextSnackbar.tsx b/docs/src/pages/demos/snackbars/LongTextSnackbar.tsx new file mode 100644 index 00000000000000..741f64005d367f --- /dev/null +++ b/docs/src/pages/demos/snackbars/LongTextSnackbar.tsx @@ -0,0 +1,56 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import Button from '@material-ui/core/Button'; +import { createStyles, withStyles, WithStyles, Theme } from '@material-ui/core/styles'; +import SnackbarContent from '@material-ui/core/SnackbarContent'; + +const action = ( + +); + +const styles = (theme: Theme) => + createStyles({ + snackbar: { + margin: theme.spacing(1), + }, + }); + +export type Props = WithStyles; + +function LongTextSnackbar(props: Props) { + const { classes } = props; + + return ( +
+ + + + +
+ ); +} + +LongTextSnackbar.propTypes = { + classes: PropTypes.object.isRequired, +} as any; + +export default withStyles(styles)(LongTextSnackbar); diff --git a/docs/src/pages/demos/snackbars/PositionedSnackbar.js b/docs/src/pages/demos/snackbars/PositionedSnackbar.js index 2ef54d46b36f3a..278d64f1adab01 100644 --- a/docs/src/pages/demos/snackbars/PositionedSnackbar.js +++ b/docs/src/pages/demos/snackbars/PositionedSnackbar.js @@ -8,6 +8,7 @@ function PositionedSnackbar() { vertical: 'top', horizontal: 'center', }); + const { vertical, horizontal, open } = state; const handleClick = newState => () => { diff --git a/docs/src/pages/demos/snackbars/PositionedSnackbar.tsx b/docs/src/pages/demos/snackbars/PositionedSnackbar.tsx new file mode 100644 index 00000000000000..ad93e21eb5467d --- /dev/null +++ b/docs/src/pages/demos/snackbars/PositionedSnackbar.tsx @@ -0,0 +1,50 @@ +import React from 'react'; +import Button from '@material-ui/core/Button'; +import Snackbar, { SnackbarOrigin } from '@material-ui/core/Snackbar'; + +export interface State extends SnackbarOrigin { + open: boolean; +} + +function PositionedSnackbar() { + const [state, setState] = React.useState({ + open: false, + vertical: 'top', + horizontal: 'center', + }); + const { vertical, horizontal, open } = state; + + const handleClick = (newState: SnackbarOrigin) => () => { + setState({ open: true, ...newState }); + }; + + function handleClose() { + setState({ ...state, open: false }); + } + + return ( +
+ + + + + + + I love snacks} + /> +
+ ); +} + +export default PositionedSnackbar; diff --git a/docs/src/pages/demos/snackbars/SimpleSnackbar.tsx b/docs/src/pages/demos/snackbars/SimpleSnackbar.tsx new file mode 100644 index 00000000000000..a71c8931369552 --- /dev/null +++ b/docs/src/pages/demos/snackbars/SimpleSnackbar.tsx @@ -0,0 +1,64 @@ +import React from 'react'; +import { makeStyles, Theme } from '@material-ui/core/styles'; +import Button from '@material-ui/core/Button'; +import Snackbar from '@material-ui/core/Snackbar'; +import IconButton from '@material-ui/core/IconButton'; +import CloseIcon from '@material-ui/icons/Close'; + +const useStyles = makeStyles((theme: Theme) => ({ + close: { + padding: theme.spacing(0.5), + }, +})); + +function SimpleSnackbar() { + const classes = useStyles(); + const [open, setOpen] = React.useState(false); + + function handleClick() { + setOpen(true); + } + + function handleClose(event: React.SyntheticEvent | React.MouseEvent, reason?: string) { + if (reason === 'clickaway') { + return; + } + + setOpen(false); + } + + return ( +
+ + Note archived} + action={[ + , + + + , + ]} + /> +
+ ); +} + +export default SimpleSnackbar;