Skip to content

Commit

Permalink
Resizable snackbars - Fixed sudden transitions (#168)
Browse files Browse the repository at this point in the history
* Remove renderVariants property from index.d.ts

* Fixed sudden transitions
  • Loading branch information
vyushin authored and iamhosseindhv committed Sep 22, 2019
1 parent c42289e commit f5d8732
Show file tree
Hide file tree
Showing 7 changed files with 87 additions and 109 deletions.
39 changes: 14 additions & 25 deletions src/SnackbarContainer.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { SNACKBAR_INDENTS } from './utils/constants';

const styles = theme => ({
root: {
boxSizing: 'border-box',
display: 'flex',
maxHeight: '100%',
maxWidth: '100%',
Expand All @@ -15,36 +16,24 @@ const styles = theme => ({
height: 'auto',
width: 'auto',
minWidth: 288,
transition: theme.transitions.create(['padding']),
transition: theme.transitions.create(['top', 'right', 'bottom', 'left'], { easing: 'ease' }),
[theme.breakpoints.down('sm')]: {
width: '100%',
paddingLeft: '0 !important',
paddingRight: '0 !important',
},
},
reverseColumns: { flexDirection: 'column-reverse' },

topPadding: { paddingTop: SNACKBAR_INDENTS.default.view },
topDensePadding: { paddingTop: SNACKBAR_INDENTS.dense.view },

bottomPadding: { paddingBottom: SNACKBAR_INDENTS.default.view },
bottomDensePadding: { paddingBottom: SNACKBAR_INDENTS.dense.view },

leftPadding: { paddingLeft: SNACKBAR_INDENTS.default.view },
leftDensePadding: { paddingLeft: SNACKBAR_INDENTS.dense.view },

rightPadding: { paddingRight: SNACKBAR_INDENTS.default.view },
rightDensePadding: { paddingRight: SNACKBAR_INDENTS.dense.view },

top: { top: 0 },
bottom: { bottom: 0 },
left: { left: 0 },
right: { right: 0 },
top: { top: SNACKBAR_INDENTS.default.container },
topDense: { top: SNACKBAR_INDENTS.dense.container },
bottom: { bottom: (SNACKBAR_INDENTS.default.container - SNACKBAR_INDENTS.default.snackbar) },
bottomDense: { bottom: (SNACKBAR_INDENTS.dense.container - SNACKBAR_INDENTS.dense.snackbar) },
left: { left: SNACKBAR_INDENTS.default.container },
leftDense: { left: SNACKBAR_INDENTS.dense.container },
right: { right: SNACKBAR_INDENTS.default.container },
rightDense: { right: SNACKBAR_INDENTS.dense.container },
center: {
[theme.breakpoints.up('md')]: {
left: '50%',
transform: 'translateX(-50%)',
},
left: '50%',
transform: 'translateX(-50%)',
},
});

Expand All @@ -55,8 +44,8 @@ const SnackbarContainer = React.memo((props) => {
classes.root,
classes[anchorOrigin.vertical],
classes[anchorOrigin.horizontal],
classes[`${anchorOrigin.vertical}${dense ? 'Dense' : ''}Padding`],
classes[`${anchorOrigin.horizontal}${dense ? 'Dense' : ''}Padding`],
classes[`${anchorOrigin.vertical}${dense ? 'Dense' : ''}`],
classes[`${anchorOrigin.horizontal}${dense ? 'Dense' : ''}`],
{ [classes.reverseColumns]: anchorOrigin.vertical === 'bottom' },
);

Expand Down
77 changes: 46 additions & 31 deletions src/SnackbarItem/SnackbarItem.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,20 @@ import classNames from 'classnames';
import PropTypes from 'prop-types';
import { withStyles } from '@material-ui/core/styles';
import Snackbar from '@material-ui/core/Snackbar';
import Collapse from '@material-ui/core/Collapse';
import SnackbarContent from '@material-ui/core/SnackbarContent';
import { capitalise, getTransitionDirection, getSnackbarClasses } from './SnackbarItem.util';
import { capitalise, getTransitionDirection, getSnackbarClasses, getCollapseClasses } from './SnackbarItem.util';
import styles from './SnackbarItem.styles';


class SnackbarItem extends Component {
constructor(props) {
super(props);
this.state = {
collapsed: true,
};
}

handleClose = key => (event, reason) => {
const { onClose, snack: { onClose: singleOnClose } } = this.props;
if (reason === 'clickaway') return;
Expand Down Expand Up @@ -68,38 +76,45 @@ class SnackbarItem extends Component {
}

return (
<Snackbar
TransitionProps={{
direction: getTransitionDirection(anchorOrigin),
}}
{...other}
{...singleSnackProps}
anchorOrigin={anchorOrigin}
open={snack.open}
classes={getSnackbarClasses(classes, anchorOrigin, dense)}
onClose={this.handleClose(key)}
<Collapse
unmountOnExit
in={this.state.collapsed}
onExited={this.handleExited(key)}
classes={getCollapseClasses(classes, dense)}
>
{snackChildren || (
<SnackbarContent
className={classNames(
classes.base,
classes[`variant${capitalise(variant)}`],
(!hideIconVariant && icon) ? classes.lessPadding : null,
className,
)}
{...contentProps}
aria-describedby={ariaDescribedby}
message={(
<span id={ariaDescribedby} className={classes.message}>
{!hideIconVariant ? icon : null}
{snack.message}
</span>
)}
action={finalAction}
/>
)}
</Snackbar>
<Snackbar
TransitionProps={{
direction: getTransitionDirection(anchorOrigin),
onExited: () => this.setState(({ collapsed }) => ({ collapsed: !collapsed })),
}}
{...other}
{...singleSnackProps}
anchorOrigin={anchorOrigin}
open={snack.open}
classes={getSnackbarClasses(classes)}
onClose={this.handleClose(key)}
>
{snackChildren || (
<SnackbarContent
className={classNames(
classes.base,
classes[`variant${capitalise(variant)}`],
(!hideIconVariant && icon) ? classes.lessPadding : null,
className,
)}
{...contentProps}
aria-describedby={ariaDescribedby}
message={(
<span id={ariaDescribedby} className={classes.message}>
{!hideIconVariant ? icon : null}
{snack.message}
</span>
)}
action={finalAction}
/>
)}
</Snackbar>
</Collapse>
);
}
}
Expand Down
40 changes: 8 additions & 32 deletions src/SnackbarItem/SnackbarItem.styles.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,7 @@
import green from '@material-ui/core/colors/green';
import amber from '@material-ui/core/colors/amber';
import { muiClasses } from './SnackbarItem.util';
import { TRANSITION_DELAY, TRANSITION_DOWN_DURATION, SNACKBAR_INDENTS } from '../utils/constants';

export const transitionStyles = {
WebKitTransition: `all ${TRANSITION_DOWN_DURATION}ms`,
MozTransition: `all ${TRANSITION_DOWN_DURATION}ms`,
msTransition: `all ${TRANSITION_DOWN_DURATION}ms`,
OTransition: `all ${TRANSITION_DOWN_DURATION}ms`,
transition: `all ${TRANSITION_DOWN_DURATION * 5}ms`,
transitionDelay: `${TRANSITION_DELAY}ms`,
};
import { SNACKBAR_INDENTS } from '../utils/constants';

const styles = theme => ({
...muiClasses,
Expand Down Expand Up @@ -46,31 +37,16 @@ const styles = theme => ({
right: 0,
bottom: 0,
left: 0,
// ...transitionStyles,
'&:nth-last-child(1n+2)': {
marginBottom: SNACKBAR_INDENTS.default.snackbar,
},
},
wrappedRootReverseFirstChild: {
'&:nth-last-child(1n+2)': {
marginBottom: 0,
},
'&:nth-child(1n+2)': {
marginBottom: SNACKBAR_INDENTS.default.snackbar,
},
collapseContainer: {
transition: theme.transitions.create(['height'], { easing: 'ease' }),
},
wrappedRootDense: {
'&:nth-last-child(1n+2)': {
marginBottom: SNACKBAR_INDENTS.dense.snackbar,
},
collapseWrapped: {
marginBottom: SNACKBAR_INDENTS.default.snackbar,
transition: theme.transitions.create(['margin-bottom'], { easing: 'ease' }),
},
wrappedRootReverseFirstChildDense: {
'&:nth-last-child(1n+2)': {
marginBottom: 0,
},
'&:nth-child(1n+2)': {
marginBottom: SNACKBAR_INDENTS.dense.snackbar,
},
collapseWrappedDense: {
marginBottom: SNACKBAR_INDENTS.dense.snackbar,
},
});

Expand Down
20 changes: 14 additions & 6 deletions src/SnackbarItem/SnackbarItem.util.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export const getTransitionDirection = (anchorOrigin) => {
* @param {boolean} dense
* @return {object}
*/
export const getSnackbarClasses = (classes, anchOrigin, dense) => {
export const getSnackbarClasses = (classes) => {
// filter classes object and return keys that are allowed in material-ui snackbar classes prop
const snackbarMuiClasses = Object.keys(classes)
.filter(key => muiClasses[key] !== undefined)
Expand All @@ -42,14 +42,22 @@ export const getSnackbarClasses = (classes, anchOrigin, dense) => {
[key]: classes[key],
}), {});

const rootClasses = classNames(snackbarMuiClasses.root, classes.wrappedRoot, {
[classes.wrappedRootDense]: dense,
[classes.wrappedRootReverseFirstChild]: anchOrigin.vertical === 'bottom',
[classes.wrappedRootReverseFirstChildDense]: dense && anchOrigin.vertical === 'bottom',
});
const rootClasses = classNames(snackbarMuiClasses.root, classes.wrappedRoot);

return {
...snackbarMuiClasses,
root: rootClasses,
};
};

export const getCollapseClasses = (classes, dense) => {

const rootClasses = classNames(classes.collapseWrapped, {
[classes.collapseWrappedDense]: dense,
});

return {
container: classes.collapseContainer,
wrapper: rootClasses,
};
};
9 changes: 3 additions & 6 deletions src/SnackbarProvider.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React, { Component } from 'react';
import PropTypes from 'prop-types';
import Slide from '@material-ui/core/Slide';
import SnackbarContext from './SnackbarContext';
import { TRANSITION_DELAY, TRANSITION_DOWN_DURATION, MESSAGES, iconVariant, originKeyExtractor } from './utils/constants';
import { MESSAGES, iconVariant, originKeyExtractor } from './utils/constants';
import SnackbarItem from './SnackbarItem';
import SnackbarContainer from './SnackbarContainer';
import warning from './utils/warning';
Expand Down Expand Up @@ -158,12 +158,9 @@ class SnackbarProvider extends Component {
* @param {object} event - The event source of the callback
*/
handleExitedSnack = (event, key) => {
const enterDelay = TRANSITION_DELAY + TRANSITION_DOWN_DURATION + 40;
this.setState(
({ snacks }) => ({
snacks: snacks.filter(item => item.key !== key),
}),
() => setTimeout(this.handleDisplaySnack, enterDelay),
({ snacks }) => ({ snacks: snacks.filter(item => item.key !== key) }),
() => this.handleDisplaySnack(),
);

if (this.props.onExited) this.props.onExited(event, key);
Expand Down
3 changes: 0 additions & 3 deletions src/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ type ClassNameMap<ClassKey extends string = string> = Record<ClassKey, string>;

export type VariantType = 'default' | 'error' | 'success' | 'warning' | 'info';

export type RenderVariants = 'default'| 'wrapped';

export interface OptionsObject extends Omit<SnackbarProps, 'open' | 'message' | 'classes'> {
key?: string | number;
variant?: VariantType;
Expand Down Expand Up @@ -42,7 +40,6 @@ export interface SnackbarProviderProps extends Omit<SnackbarProps, 'open' | 'mes
preventDuplicate?: boolean;
dense?: boolean;
action?: SnackbarContentProps['action'] | ((key: OptionsObject['key']) => React.ReactNode);
renderVariant?: RenderVariants;
}

export const SnackbarProvider: React.ComponentType<SnackbarProviderProps>;
8 changes: 2 additions & 6 deletions src/utils/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,17 +48,13 @@ export const iconVariant = {
info: <InfoIcon style={iconStyles} />,
};

export const TRANSITION_DELAY = 150;

export const TRANSITION_DOWN_DURATION = 200;

export const MESSAGES = {
NO_PERSIST_ALL: 'WARNING - notistack: Reached maxSnack while all enqueued snackbars have \'persist\' flag. Notistack will dismiss the oldest snackbar anyway to allow other ones in the queue to be presented.',
};

export const SNACKBAR_INDENTS = {
default: { view: 20, snackbar: 12 },
dense: { view: 0, snackbar: 4 },
default: { view: 20, snackbar: 12, container: 12 },
dense: { view: 0, snackbar: 4, container: 4 },
};

export const originKeyExtractor = anchor => `${anchor.vertical}-${anchor.horizontal}`;

0 comments on commit f5d8732

Please sign in to comment.