-
Notifications
You must be signed in to change notification settings - Fork 146
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
6cf035f
commit 9f39a33
Showing
11 changed files
with
208 additions
and
32 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,29 +1,58 @@ | ||
import { AnimatePresence, motion } from 'framer-motion'; | ||
import BaseBox from '~components/Box/BaseBox'; | ||
import { AnimatePresence, m as motion } from 'framer-motion'; | ||
import React from 'react'; | ||
import styled from 'styled-components'; | ||
import { useStagger } from '~components/Stagger/StaggerProvider'; | ||
import type { BaseMotionProps } from './types'; | ||
|
||
const MotionBox = motion(BaseBox); | ||
// Creating empty styled component so that the final component supports `as` prop | ||
const StyledDiv = styled.div``; | ||
const MotionDiv = motion(StyledDiv); | ||
|
||
export const BaseMotionBox = ({ | ||
const useAnimationVariables = ({ | ||
variant, | ||
isInsideStaggerContainer, | ||
}: { | ||
variant: BaseMotionProps['variant']; | ||
isInsideStaggerContainer: boolean; | ||
}) => { | ||
const animationVariables = React.useMemo(() => { | ||
// When component is rendered inside stagger, we remove the initial, animate, exit props | ||
// otherwise they override the stagger behaviour and stagger does not work | ||
return isInsideStaggerContainer | ||
? {} | ||
: { | ||
initial: variant === 'in' || variant === 'inout' ? 'initial' : undefined, | ||
animate: 'animate', | ||
exit: variant === 'out' || variant === 'inout' ? 'exit' : undefined, | ||
}; | ||
}, [variant, isInsideStaggerContainer]); | ||
|
||
return animationVariables; | ||
}; | ||
|
||
const BaseMotionBox = ({ | ||
children, | ||
motionVariants, | ||
isVisible = true, | ||
variant, | ||
variant = 'inout', | ||
}: BaseMotionProps) => { | ||
const { isInsideStaggerContainer } = useStagger(); | ||
const animationVariables = useAnimationVariables({ variant, isInsideStaggerContainer }); | ||
|
||
return ( | ||
<AnimatePresence> | ||
{isVisible ? ( | ||
<MotionBox | ||
<MotionDiv | ||
// kinda hack to build it as enhancer component | ||
as={children.type} | ||
variants={motionVariants} | ||
initial={variant === 'in' || variant === 'inout' ? 'initial' : undefined} | ||
animate="animate" | ||
exit={variant === 'out' || variant === 'inout' ? 'exit' : undefined} | ||
{...animationVariables} | ||
// We pass the props of children and not pass the children itself since the `as` prop already renders the children and we don't want to re-render it inside | ||
{...children.props} | ||
/> | ||
) : null} | ||
</AnimatePresence> | ||
); | ||
}; | ||
|
||
export { MotionDiv, BaseMotionBox }; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,23 +1,30 @@ | ||
import { BaseMotionBox } from '~components/BaseMotion'; | ||
import type { BaseEntryExitMotionProps, BaseMotionBoxVariants } from '~components/BaseMotion'; | ||
import type { BaseEntryExitMotionProps, MotionVariantsType } from '~components/BaseMotion'; | ||
|
||
export type MoveProps = BaseEntryExitMotionProps; | ||
|
||
export const Move = ({ children }: MoveProps) => { | ||
const moveVariants: BaseMotionBoxVariants = { | ||
export const Move = ({ children, variant = 'inout', isVisible }: MoveProps) => { | ||
const moveVariants: MotionVariantsType = { | ||
initial: { | ||
opacity: 0, | ||
y: '-10px', | ||
transform: 'translateY(20px)', | ||
}, | ||
animate: { | ||
opacity: 1, | ||
y: '0px', | ||
transform: 'translateY(0px)', | ||
}, | ||
exit: { | ||
opacity: 0, | ||
y: '-10px', | ||
transform: 'translateY(20px)', | ||
}, | ||
}; | ||
|
||
return <BaseMotionBox motionVariants={moveVariants} children={children} />; | ||
return ( | ||
<BaseMotionBox | ||
motionVariants={moveVariants} | ||
children={children} | ||
variant={variant} | ||
isVisible={isVisible} | ||
/> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
import React from 'react'; | ||
import type { Meta, StoryFn } from '@storybook/react'; | ||
import { Title } from '@storybook/addon-docs'; | ||
import { Stagger } from './'; | ||
import type { StaggerProps } from './'; | ||
import { Sandbox } from '~utils/storybook/Sandbox'; | ||
import StoryPageWrapper from '~utils/storybook/StoryPageWrapper'; | ||
import { Button } from '~components/Button'; | ||
import { Box } from '~components/Box'; | ||
import { InternalCardExample } from '../Card/Card.stories'; | ||
import { Fade } from '~components/Fade'; | ||
import { Move } from '~components/Move'; | ||
|
||
const Page = (): React.ReactElement => { | ||
return ( | ||
<StoryPageWrapper | ||
componentName="Stagger" | ||
componentDescription="Stagger Motion Component (TODO)" | ||
figmaURL="https://www.figma.com/proto/jubmQL9Z8V7881ayUD95ps/Blade-DSL?type=design&node-id=74864-85897&t=CvaYT53LNc4OYVKa-1&scaling=min-zoom&page-id=21689%3A381614&mode=design" | ||
> | ||
<Title>Usage</Title> | ||
<Sandbox> | ||
{` | ||
const todo = 'todo'; | ||
`} | ||
</Sandbox> | ||
</StoryPageWrapper> | ||
); | ||
}; | ||
|
||
export default { | ||
title: 'Motion/Stagger', | ||
component: Stagger, | ||
tags: ['autodocs'], | ||
parameters: { | ||
docs: { | ||
page: Page, | ||
}, | ||
}, | ||
} as Meta<StaggerProps>; | ||
|
||
const StaggerTemplate: StoryFn<typeof Stagger> = (args) => { | ||
const [isVisible, setIsVisible] = React.useState(true); | ||
return ( | ||
<Box minHeight="350px"> | ||
<Button marginBottom="spacing.4" onClick={() => setIsVisible(!isVisible)}> | ||
Toggle Stagger | ||
</Button> | ||
<Stagger {...args} isVisible={isVisible}> | ||
{args.children} | ||
</Stagger> | ||
</Box> | ||
); | ||
}; | ||
|
||
export const Default = StaggerTemplate.bind({}); | ||
Default.args = { | ||
children: ( | ||
<Box display="flex" flexDirection="row" gap="spacing.4"> | ||
<Fade> | ||
<InternalCardExample /> | ||
</Fade> | ||
<Fade> | ||
<InternalCardExample /> | ||
</Fade> | ||
<Fade> | ||
<InternalCardExample /> | ||
</Fade> | ||
</Box> | ||
), | ||
}; | ||
|
||
export const MoveStagger = StaggerTemplate.bind({}); | ||
MoveStagger.args = { | ||
children: ( | ||
<Box display="flex" flexDirection="row" gap="spacing.4"> | ||
<Move> | ||
<InternalCardExample /> | ||
</Move> | ||
<Move> | ||
<InternalCardExample /> | ||
</Move> | ||
<Move> | ||
<InternalCardExample /> | ||
</Move> | ||
</Box> | ||
), | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
import { MotionDiv } from '~components/BaseMotion'; | ||
import type { BaseEntryExitMotionProps, MotionVariantsType } from '~components/BaseMotion'; | ||
import { AnimatePresence } from 'framer-motion'; | ||
import { StaggerContext } from './StaggerProvider'; | ||
|
||
export type StaggerProps = BaseEntryExitMotionProps & { | ||
children: React.ReactElement[] | React.ReactElement; | ||
}; | ||
|
||
export const Stagger = ({ children, isVisible, variant = 'inout' }: StaggerProps) => { | ||
const staggerVariants: MotionVariantsType = { | ||
initial: {}, | ||
animate: { | ||
transition: { | ||
staggerChildren: 0.1, | ||
}, | ||
}, | ||
exit: { | ||
transition: { | ||
staggerChildren: 0.1, | ||
}, | ||
}, | ||
}; | ||
|
||
return ( | ||
<StaggerContext.Provider value={{ isInsideStaggerContainer: true }}> | ||
<AnimatePresence> | ||
{isVisible ? ( | ||
<MotionDiv initial="initial" animate="animate" exit="exit" variants={staggerVariants}> | ||
{children} | ||
</MotionDiv> | ||
) : null} | ||
</AnimatePresence> | ||
</StaggerContext.Provider> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
import React from 'react'; | ||
|
||
const StaggerContext = React.createContext({ isInsideStaggerContainer: false }); | ||
|
||
const useStagger = () => { | ||
const staggerContextValue = React.useContext(StaggerContext); | ||
return staggerContextValue; | ||
}; | ||
|
||
export { useStagger, StaggerContext }; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
export { Stagger } from './Stagger'; | ||
export type { StaggerProps } from './Stagger'; |