Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix card flip animation showing back-face in chrome #228

Merged
merged 12 commits into from
Oct 14, 2021
1 change: 0 additions & 1 deletion packages/code-studio/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@
"prop-types": "^15.7.2",
"react": "^16.14.0",
"react-beautiful-dnd": "^13.0.0",
"react-card-flip": "^0.7.2",
"react-dom": "^16.14.0",
"react-markdown": "^6.0.2",
"react-redux": "^7.2.4",
Expand Down
2 changes: 1 addition & 1 deletion packages/components/scss/bootstrap_overrides.scss
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ $enable-print-styles: false; //I don't think anyone should expect to "print" thi
$transition: 0.15s;
$transition-mid: 0.2s;
$transition-long: 0.3s;
$transition-slow: 1s;
$transition-slow: 0.6s;

//form-validation icon, uses vsIssues icon encoded here as svg
$form-feedback-icon-invalid-color: theme-color('danger');
Expand Down
7 changes: 7 additions & 0 deletions packages/components/src/BaseStyleSheet.scss
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,13 @@ button:focus {
min-width: 7rem;
}

span.btn-disabled-wrapper {
.btn.disabled,
.btn:disabled {
pointer-events: none;
}
}

.btn-link {
min-width: unset;
padding: $spacer-1;
Expand Down
16 changes: 14 additions & 2 deletions packages/components/src/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
typeof tooltip === 'string' ? <Tooltip>{tooltip}</Tooltip> : tooltip;
}

return (
const button = (
<button
ref={ref}
// eslint-disable-next-line react/button-has-type
Expand All @@ -133,9 +133,21 @@ const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
>
{icon && iconElem}
{children}
{tooltip && tooltipElem}
{tooltip && !disabled && tooltipElem}
</button>
);

// disabled buttons tooltips need a wrapped element to receive pointer events
// https://jakearchibald.com/2017/events-and-disabled-form-fields/

return disabled ? (
<span className="btn-disabled-wrapper">
{button}
{tooltip && tooltipElem}
</span>
) : (
button
);
}
);

Expand Down
50 changes: 50 additions & 0 deletions packages/components/src/CardFlip.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
@import '../scss/custom.scss';

.card-flip {
&--show-front,
&--show-back {
display: grid;
height: 100%;
width: 100%;
isolation: isolate;
perspective: 1000px;
}

&--front,
&--back {
grid-area: 1/1/2/2;
transform-style: flat;
backface-visibility: hidden;
transition: transform $transition-slow ease-in-out;
overflow: hidden;
}

&--show-back {
.card-flip--front {
transform: rotateY(180deg);
}
.card-flip--back {
transform: rotateY(0);
}
}

&--show-front {
.card-flip--front {
transform: rotateY(0);
}
.card-flip--back {
transform: rotateY(-180deg);
}
}

&--is-flipping {
// this is applied to body during transitions
// so that the perspective transform doesn't cause overflow
overflow: hidden;
.card-flip--show-front,
.card-flip--show-back {
// increase z-index while flipping so perspective appears above everything
z-index: $zindex-popover;
}
}
}
71 changes: 71 additions & 0 deletions packages/components/src/CardFlip.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import React, { useCallback, useEffect, useRef } from 'react';
import classNames from 'classnames';
import './CardFlip.scss';

type CardFlipProps = {
isFlipped: boolean;
children: [React.ReactNode, React.ReactNode];
className?: string;
};

/**
* Card flip component, switches between a front and back face being visible.
* Has logic to handle oveflow on body, caused by perspective transforms
* and moves z-index to top during transition.
* @param isFlipped true shows second child, false shows first child
* @param children Expects exactly two children
* @returns
*/
dsmmcken marked this conversation as resolved.
Show resolved Hide resolved
const CardFlip = ({
className,
isFlipped,
children,
}: CardFlipProps): JSX.Element => {
const getComponent = (key: 0 | 1) => {
if (children.length !== 2) {
throw new Error(
'Component ReactCardFlip requires 2 children to function'
dsmmcken marked this conversation as resolved.
Show resolved Hide resolved
);
}
return children[key];
};

const front = useRef<HTMLDivElement>(null);

const transitionStart = useCallback(event => {
if (event.target === event.currentTarget) {
document.body.classList.add('card-flip--is-flipping');
}
}, []);

const transitionEnd = useCallback(event => {
if (event.target === event.currentTarget) {
document.body.classList.remove('card-flip--is-flipping');
}
}, []);

useEffect(() => {
if (!front.current) throw Error('ref undefined');
front.current.addEventListener('transitionstart', transitionStart);
}, [transitionStart]);

return (
<div
className={classNames(className, {
'card-flip--show-front': isFlipped,
'card-flip--show-back': !isFlipped,
})}
>
<div className="card-flip--back">{getComponent(0)}</div>
<div
ref={front}
className="card-flip--front"
onTransitionEnd={transitionEnd}
>
{getComponent(1)}
</div>
</div>
);
};

export default CardFlip;
1 change: 1 addition & 0 deletions packages/components/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export { default as BasicModal } from './BasicModal';
export { default as Button } from './Button';
export { default as ButtonGroup } from './ButtonGroup';
export { default as ButtonOld } from './ButtonOld';
export { default as CardFlip } from './CardFlip';
export * from './context-actions';
export { default as Collapse } from './Collapse';
export { default as Checkbox } from './Checkbox';
Expand Down
Loading