Skip to content

Commit

Permalink
Fix side panel exit animation (#350)
Browse files Browse the repository at this point in the history
Co-authored-by: Adam Skoufis <askoufis@users.noreply.github.com>
  • Loading branch information
felixhabib and askoufis committed May 10, 2024
1 parent 0502218 commit a0724d2
Show file tree
Hide file tree
Showing 7 changed files with 119 additions and 47 deletions.
5 changes: 5 additions & 0 deletions .changeset/beige-tips-swim.md
@@ -0,0 +1,5 @@
---
'playroom': patch
---

Fixes a bug in the side panel exit animation that was causing the contents to vanish abruptly
4 changes: 2 additions & 2 deletions cypress/e2e/snippets.cy.js
Expand Up @@ -72,7 +72,7 @@ describe('Snippets', () => {
assertSnippetsListIsVisible();
assertCodePaneLineCount(8);
filterSnippets('{esc}');
assertCodePaneLineCount(1);
assertCodePaneLineCount(1, { wait: 500 });
typeCode(`${isMac() ? '{cmd}' : '{ctrl}'}k`);
assertSnippetsListIsVisible();
assertCodePaneLineCount(8);
Expand All @@ -89,7 +89,7 @@ describe('Snippets', () => {
// Close without persisting
filterSnippets('{esc}');
assertCodePaneContains('<div>Initial <span>code</span></div>');
assertCodePaneLineCount(1);
assertCodePaneLineCount(1, { wait: 500 });

// Re-open and persist
typeCode(`${isMac() ? '{cmd}' : '{ctrl}'}k`);
Expand Down
7 changes: 6 additions & 1 deletion cypress/support/utils.js
Expand Up @@ -149,10 +149,15 @@ export const assertCodePaneContains = (text) => {
});
};

export const assertCodePaneLineCount = (lines) => {
export const assertCodePaneLineCount = (lines, { wait } = {}) => {
getCodeEditor().within(() =>
cy.get('.CodeMirror-line').should('have.length', lines)
);

// Wait after check to ensure original focus is restored
if (typeof wait === 'number') {
cy.wait(wait);
}
};

export const assertFramesMatch = (matches) =>
Expand Down
2 changes: 2 additions & 0 deletions package.json
Expand Up @@ -98,6 +98,7 @@
"re-resizable": "^6.9.9",
"react-docgen-typescript": "^2.2.2",
"react-helmet": "^6.1.0",
"react-transition-group": "^4.4.5",
"react-use": "^17.4.0",
"read-pkg-up": "^7.0.1",
"scope-eval": "^1.0.0",
Expand All @@ -114,6 +115,7 @@
"@octokit/rest": "^19.0.5",
"@types/jest": "^29.2.4",
"@types/react-helmet": "^6.1.6",
"@types/react-transition-group": "^4.4.10",
"concurrently": "^7.6.0",
"cypress": "^13.6.6",
"eslint": "^8.44.0",
Expand Down
33 changes: 33 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

48 changes: 35 additions & 13 deletions src/Playroom/Toolbar/Toolbar.css.ts
Expand Up @@ -90,26 +90,48 @@ export const buttons = style([
export const panel = style([
sprinkles({
position: 'relative',
display: 'flex',
overflow: 'auto',
transition: 'slow',
pointerEvents: 'auto',
}),
{
width: toolbarOpenSize,
backgroundColor: colorPaletteVars.background.surface,
borderLeft: `${toolbarBorderThickness} solid ${colorPaletteVars.border.standard}`,
selectors: {
[`${root}:not(${isOpen}) &`]: {
transform: `translateX(${calc(`${toolbarOpenSize}px`).multiply(0.3)})`,
opacity: 0,
pointerEvents: 'none',
},
},
},
]);

export const preference = sprinkles({
position: 'absolute',
inset: 0,
});
export const transitionStyles = {
enter: style({
opacity: 0,
transform: `translateX(30%)`,
}),
enterActive: style([
sprinkles({
transition: 'slow',
}),
{
opacity: 1,
transform: `translateX(0)`,
},
]),
enterDone: style({
opacity: 1,
transform: `translateX(0)`,
}),
exit: style({
opacity: 1,
}),
exitActive: style([
sprinkles({
transition: 'slow',
}),
{
opacity: 0,
transform: `translateX(30%)`,
},
]),
exitDone: style({
opacity: 0,
transform: `translateX(30%)`,
}),
};
67 changes: 36 additions & 31 deletions src/Playroom/Toolbar/Toolbar.tsx
@@ -1,4 +1,4 @@
import { useContext, useState, useCallback } from 'react';
import { useContext, useState, useCallback, useEffect } from 'react';
import { useTimeoutFn } from 'react-use';
import classnames from 'classnames';
import type { PlayroomProps } from '../Playroom';
Expand All @@ -17,13 +17,16 @@ import SettingsPanel from '../SettingsPanel/SettingsPanel';
import SettingsIcon from '../icons/SettingsIcon';
import { isMac } from '../../utils/formatting';

import { CSSTransition } from 'react-transition-group';

interface Props {
themes: PlayroomProps['themes'];
widths: PlayroomProps['widths'];
snippets: PlayroomProps['snippets'];
}

export const toolbarItemCount = 5;
const ANIMATION_TIMEOUT = 300;

export default ({ themes: allThemes, widths: allWidths, snippets }: Props) => {
const [
Expand Down Expand Up @@ -58,6 +61,15 @@ export default ({ themes: allThemes, widths: allWidths, snippets }: Props) => {
const isSettingsOpen = activeToolbarPanel === 'settings';
const isPreviewOpen = activeToolbarPanel === 'preview';

const [lastActivePanel, setLastActivePanel] =
useState<typeof activeToolbarPanel>(undefined);

useEffect(() => {
if (activeToolbarPanel) {
setLastActivePanel(activeToolbarPanel);
}
}, [activeToolbarPanel]);

const hasSnippets = snippets && snippets.length > 0;
const hasFilteredFrames =
visibleThemes.length > 0 || visibleWidths.length > 0;
Expand Down Expand Up @@ -148,13 +160,16 @@ export default ({ themes: allThemes, widths: allWidths, snippets }: Props) => {
</ToolbarItem>
</div>
</div>

<div className={styles.panel}>
{isSnippetsOpen && (
<div
hidden={isSnippetsOpen ? undefined : true}
className={styles.preference}
>
<CSSTransition
in={isOpen}
timeout={ANIMATION_TIMEOUT}
classNames={styles.transitionStyles}
mountOnEnter
unmountOnExit
onExited={() => setLastActivePanel(undefined)}
>
<div className={styles.panel} id="custom-id">
{lastActivePanel === 'snippets' && (
<Snippets
snippets={snippets}
onHighlight={(snippet) => {
Expand All @@ -174,32 +189,22 @@ export default ({ themes: allThemes, widths: allWidths, snippets }: Props) => {
}
}}
/>
</div>
)}
<div
hidden={isFramesOpen ? undefined : true}
className={styles.preference}
>
<FramesPanel
availableWidths={allWidths}
availableThemes={allThemes}
/>
</div>
)}

<div
hidden={isPreviewOpen ? undefined : true}
className={styles.preference}
>
<PreviewPanel themes={allThemes} visibleThemes={visibleThemes} />
</div>
{lastActivePanel === 'frames' && (
<FramesPanel
availableWidths={allWidths}
availableThemes={allThemes}
/>
)}

<div
hidden={isSettingsOpen ? undefined : true}
className={styles.preference}
>
<SettingsPanel />
{lastActivePanel === 'preview' && (
<PreviewPanel themes={allThemes} visibleThemes={visibleThemes} />
)}

{lastActivePanel === 'settings' && <SettingsPanel />}
</div>
</div>
</CSSTransition>
</div>
</div>
);
Expand Down

0 comments on commit a0724d2

Please sign in to comment.