Skip to content

Commit 5d69d31

Browse files
committed
fix: prevent animation on mount
1 parent ab55841 commit 5d69d31

2 files changed

Lines changed: 51 additions & 40 deletions

File tree

docs/stories/04-components/Drawer.stories.tsx

Lines changed: 5 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import * as React from 'react';
22

33
import { Meta, StoryObj } from '@storybook/react-vite';
4-
import { Button, Drawer, Field, Flex, Typography } from '@strapi/design-system';
4+
import { Button, Drawer, Field, Flex } from '@strapi/design-system';
55
import { outdent } from 'outdent';
66

77
interface DrawerArgs
@@ -96,34 +96,10 @@ const meta: Meta<DrawerArgs> = {
9696
<Drawer.Title>Drawer title</Drawer.Title>
9797
</Drawer.Header>
9898
<Drawer.Body>
99-
<Typography>
100-
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla molestie odio dui. Cras egestas ultrices
101-
pulvinar. Cras in pellentesque neque. Vestibulum imperdiet ex vitae felis lobortis, sed facilisis ligula
102-
laoreet. Proin iaculis molestie felis. Curabitur ultrices turpis nec rutrum facilisis. Suspendisse in
103-
ligula in est euismod feugiat. Proin vestibulum eros massa, et accumsan justo interdum dictum. Vestibulum
104-
sed varius urna. Ut pellentesque fermentum sodales. Suspendisse venenatis eros vitae lorem rutrum tempus.
105-
Suspendisse diam erat, semper gravida finibus et, tincidunt a erat. Curabitur placerat imperdiet urna, sit
106-
amet aliquet lorem rutrum sit amet. Aliquam et molestie nisl. Quisque at nisl et eros sollicitudin blandit
107-
bibendum ac augue. Quisque nec facilisis tortor. Nulla ex urna, scelerisque ultricies leo eget, iaculis
108-
laoreet ipsum. Suspendisse potenti. Sed eget porttitor lectus. Nullam in ipsum vel enim facilisis gravida.
109-
Duis posuere porttitor erat eu maximus. Morbi viverra tempus ante. Phasellus gravida ligula vel elit
110-
lacinia, ut finibus urna interdum. In cursus rhoncus accumsan. Cras at mattis massa. Mauris tempor ipsum
111-
quam. Integer augue eros, accumsan in ante nec, tincidunt ultrices nisl. Integer ut enim enim. Vivamus
112-
posuere metus et nibh pharetra, at bibendum dolor porttitor. Fusce iaculis eleifend lectus, ut rutrum
113-
sapien auctor et. In vitae risus lacus. Quisque ex mauris, venenatis vel nisi in, dictum suscipit tortor.
114-
Aliquam non justo cursus, dictum libero eget, viverra velit. Sed velit nisi, rutrum ut tempor et, ornare
115-
sit amet risus. Mauris ornare eleifend justo et viverra. Morbi feugiat nulla vitae sodales auctor. Donec
116-
laoreet quam nibh, vel mattis ligula venenatis et. Ut vel tempor eros. Suspendisse at est scelerisque,
117-
rutrum mi non, congue enim. Ut laoreet feugiat ante non lobortis. Vivamus convallis libero condimentum
118-
nisl pellentesque, quis feugiat nunc suscipit. Maecenas laoreet dui nec nisi placerat tincidunt. Integer
119-
elementum, mauris eu suscipit rutrum, lectus sapien porttitor odio, a egestas velit nibh in eros.
120-
Vestibulum eu quam eu lorem bibendum maximus. Sed ac commodo sapien. Suspendisse congue lacus id finibus
121-
auctor. Cras eu placerat leo. Pellentesque ut elit bibendum, auctor massa eget, mollis lacus. In porttitor
122-
semper ante, sed gravida metus porta id. In scelerisque neque non laoreet faucibus. Aenean molestie
123-
pellentesque leo quis pharetra. Nam sit amet dictum lacus. Fusce eget condimentum justo. Integer lacus
124-
lectus, sagittis non ultrices sit amet, hendrerit ac mi. Quisque non laoreet erat. Mauris nec nulla erat.
125-
Suspendisse potenti.
126-
</Typography>
99+
<Field.Root name="example">
100+
<Field.Label>Example field</Field.Label>
101+
<Field.Input placeholder="Type something…" />
102+
</Field.Root>
127103
</Drawer.Body>
128104
<Drawer.Footer>
129105
<Drawer.Close>

packages/design-system/src/components/Drawer/Drawer.tsx

Lines changed: 46 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ interface DrawerContextValue {
8888
onOpenChange: (open: boolean) => void;
8989
headerVisible: boolean;
9090
overlayVisible: boolean;
91+
wasFirstOpen: boolean;
9192
}
9293

9394
const [DrawerProvider, useDrawer] = createContext<DrawerContextValue | null>('Drawer', null);
@@ -127,6 +128,13 @@ const Root = React.forwardRef<HTMLDivElement, RootProps>(
127128
[setOpen, onOpenChange],
128129
);
129130

131+
// Used to skip the animation on component mount when the drawer is closed but the header is visible.
132+
const [wasFirstOpen, setWasFirstOpen] = React.useState(false);
133+
134+
React.useEffect(() => {
135+
if (open) setWasFirstOpen(true);
136+
}, [open]);
137+
130138
const dialogOpen = headerVisible ? true : open ?? false;
131139
const isOpen = open ?? false;
132140
const modal = !!(isOpen && overlayVisible);
@@ -138,6 +146,7 @@ const Root = React.forwardRef<HTMLDivElement, RootProps>(
138146
onOpenChange={handleOpenChange}
139147
headerVisible={headerVisible}
140148
overlayVisible={overlayVisible}
149+
wasFirstOpen={wasFirstOpen}
141150
>
142151
<Dialog.Root {...props} open={dialogOpen} onOpenChange={handleOpenChange} modal={modal}>
143152
{children}
@@ -564,7 +573,7 @@ const Body = React.forwardRef<BodyElement, BodyProps>(({ children, ...restProps
564573
if (!expandable) return content;
565574

566575
return (
567-
<ExpandableSection $open={open} $flex>
576+
<ExpandableSection open={open} flex>
568577
{content}
569578
</ExpandableSection>
570579
);
@@ -620,30 +629,56 @@ const Footer = React.forwardRef<FooterElement, FooterProps>((props, forwardedRef
620629

621630
if (!expandable) return content;
622631

623-
return (
624-
<ExpandableSection $open={open} $flex={false}>
625-
{content}
626-
</ExpandableSection>
627-
);
632+
return <ExpandableSection open={open}>{content}</ExpandableSection>;
628633
});
629634

630635
const Foot = styled<FlexComponent<'footer'>>(Flex)`
631636
border-top: solid 1px ${(props) => props.theme.colors.neutral150};
632637
flex-shrink: 0;
633638
`;
634639

635-
const ExpandableSection = styled.div<{ $open: boolean; $flex?: boolean }>`
640+
const ExpandableSection = ({
641+
open,
642+
flex = false,
643+
children,
644+
}: {
645+
open: boolean;
646+
flex?: boolean;
647+
children: React.ReactNode;
648+
}) => {
649+
const drawer = useDrawer('Drawer.ExpandableSection');
650+
const wasFirstOpen = drawer?.wasFirstOpen ?? false;
651+
652+
// Before the first opening, the animation should be skipped to prevent it from happening on component mount.
653+
const skipAnimation = !wasFirstOpen && !open;
654+
655+
return (
656+
<ExpandableSectionImpl $open={open} $flex={flex} $skipAnimation={skipAnimation}>
657+
{children}
658+
</ExpandableSectionImpl>
659+
);
660+
};
661+
662+
const ExpandableSectionImpl = styled.div<{
663+
$open: boolean;
664+
$flex?: boolean;
665+
$skipAnimation?: boolean;
666+
}>`
636667
overflow: hidden;
637668
display: flex;
638669
flex-direction: column;
639670
${(props) => (props.$flex ? 'flex: 1; min-height: 0;' : 'flex-shrink: 0;')}
640671
max-height: ${(props) => (props.$open ? '100vh' : '0')};
672+
opacity: ${(props) => (props.$open ? 1 : 0)};
641673
642674
@media (prefers-reduced-motion: no-preference) {
643-
animation: ${({ $open }) => ($open ? OPEN_DRAWER_ANIMATION : CLOSE_DRAWER_ANIMATION)}
644-
${({ $open, theme }) =>
645-
$open ? theme.motion.timings[CLOSING_ANIMATION_DURATION] : theme.motion.timings[OPENING_ANIMATION_DURATION]}
646-
${(p) => p.theme.motion.easings.authenticMotion};
675+
${({ $skipAnimation, $open, theme }) =>
676+
!$skipAnimation &&
677+
css`
678+
animation: ${$open ? OPEN_DRAWER_ANIMATION : CLOSE_DRAWER_ANIMATION}
679+
${$open ? theme.motion.timings[OPENING_ANIMATION_DURATION] : theme.motion.timings[CLOSING_ANIMATION_DURATION]}
680+
${theme.motion.easings.authenticMotion};
681+
`}
647682
}
648683
`;
649684

0 commit comments

Comments
 (0)