Merge pull request #1968 from Shopify/csb-css-animation

[ContextualSaveBar] Replace RTG
This commit is contained in:
Andrew Musgrave
2019-08-14 16:37:42 -04:00
committed by GitHub
6 changed files with 113 additions and 47 deletions

View File

@@ -114,24 +114,6 @@ $skip-vertical-offset: rem(10px);
width: 100%;
}
.ContextualSaveBar-enter {
opacity: 0;
}
.ContextualSaveBar-enterActive {
opacity: 1;
transition: opacity duration() easing(out);
}
.ContextualSaveBar-exit {
opacity: 1;
}
.ContextualSaveBar-exitActive {
opacity: 0;
transition: opacity duration() easing(out);
}
.Main {
flex: 1;
display: flex;

View File

@@ -20,7 +20,13 @@ import {
ToastID,
ToastPropsWithID,
} from '../../utilities/frame';
import {ToastManager, Loading, ContextualSaveBar} from './components';
import {
ToastManager,
Loading,
ContextualSaveBar,
CSSAnimation,
AnimationType,
} from './components';
import styles from './Frame.scss';
@@ -72,7 +78,6 @@ class Frame extends React.PureComponent<CombinedProps, State> {
private contextualSaveBar: ContextualSaveBarProps | null;
private globalRibbonContainer: HTMLDivElement | null = null;
private navigationNode = createRef<HTMLDivElement>();
private contextualSaveBarNode = createRef<HTMLDivElement>();
private skipToMainContentTargetNode = React.createRef<HTMLAnchorElement>();
componentDidMount() {
@@ -161,23 +166,13 @@ class Frame extends React.PureComponent<CombinedProps, State> {
) : null;
const contextualSaveBarMarkup = (
<CSSTransition
findDOMNode={this.findContextualSaveBarNode}
appear
exit
<CSSAnimation
in={showContextualSaveBar}
timeout={300}
classNames={contextualSaveBarTransitionClasses}
mountOnEnter
unmountOnExit
className={styles.ContextualSaveBar}
type={AnimationType.Fade}
>
<div
className={styles.ContextualSaveBar}
ref={this.contextualSaveBarNode}
>
<ContextualSaveBar {...this.contextualSaveBar} />
</div>
</CSSTransition>
<ContextualSaveBar {...this.contextualSaveBar} />
</CSSAnimation>
);
const topBarMarkup = topBar ? (
@@ -402,10 +397,6 @@ class Frame extends React.PureComponent<CombinedProps, State> {
private findNavigationNode = () => {
return this.navigationNode.current;
};
private findContextualSaveBarNode = () => {
return this.contextualSaveBarNode.current;
};
}
const navTransitionClasses = {
@@ -416,14 +407,6 @@ const navTransitionClasses = {
exitActive: classNames(styles['Navigation-exitActive']),
};
const contextualSaveBarTransitionClasses = {
enter: classNames(styles['ContextualSaveBar-enter']),
enterActive: classNames(styles['ContextualSaveBar-enterActive']),
enterDone: classNames(styles['ContextualSaveBar-enterActive']),
exit: classNames(styles['ContextualSaveBar-exit']),
exitActive: classNames(styles['ContextualSaveBar-exitActive']),
};
function isMobileView() {
return navigationBarCollapsed().matches;
}

View File

@@ -0,0 +1,11 @@
@import '../../../../styles/common';
.startFade {
opacity: 0;
will-change: opacity;
transition: opacity duration(slow) easing(out);
}
.endFade {
opacity: 1;
}

View File

@@ -0,0 +1,88 @@
import React, {useRef, useState, useEffect} from 'react';
import {classNames, variationName} from '../../../../utilities/css';
import styles from './CSSAnimation.scss';
export enum AnimationType {
Fade = 'fade',
}
export interface Props {
in: boolean;
className: string;
type: AnimationType;
children?: React.ReactNode;
}
enum TransitionStatus {
Entering = 'entering',
Entered = 'entered',
Exiting = 'exiting',
Exited = 'exited',
}
export default function Collapsible({
in: inProp,
className,
type,
children,
}: Props) {
const [transitionStatus, setTransitionStatus] = useState(
inProp ? TransitionStatus.Entering : TransitionStatus.Exited,
);
const isMounted = useRef(false);
const node = useRef<HTMLDivElement>(null);
useEffect(
() => {
if (!isMounted.current) return;
transitionStatus === TransitionStatus.Entering &&
changeTransitionStatus(TransitionStatus.Entered);
},
[transitionStatus],
);
useEffect(
() => {
if (!isMounted.current) return;
inProp && changeTransitionStatus(TransitionStatus.Entering);
!inProp && changeTransitionStatus(TransitionStatus.Exiting);
},
[inProp],
);
useEffect(() => {
isMounted.current = true;
}, []);
const wrapperClassName = classNames(
className,
styles[variationName('start', type)],
inProp && styles[variationName('end', type)],
);
const content =
transitionStatus === TransitionStatus.Exited && !inProp ? null : children;
return (
<div
className={wrapperClassName}
ref={node}
onTransitionEnd={handleTransitionEnd}
>
{content}
</div>
);
function handleTransitionEnd() {
transitionStatus === TransitionStatus.Exiting &&
changeTransitionStatus(TransitionStatus.Exited);
}
function changeTransitionStatus(transitionStatus: TransitionStatus) {
setTransitionStatus(transitionStatus);
// Forcing a reflow to enable the animation
if (transitionStatus === TransitionStatus.Entering)
node.current && node.current.getBoundingClientRect();
}
}

View File

@@ -0,0 +1 @@
export {default, AnimationType} from './CSSAnimation';

View File

@@ -9,3 +9,4 @@ export {
} from './ToastManager';
export {default as Loading, Props as LoadingProps} from './Loading';
export {default as ContextualSaveBar} from './ContextualSaveBar';
export {default as CSSAnimation, AnimationType} from './CSSAnimation';