-
Notifications
You must be signed in to change notification settings - Fork 0
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
e5cccdd
commit 7789780
Showing
427 changed files
with
73,031 additions
and
4,683 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 |
---|---|---|
@@ -0,0 +1,98 @@ | ||
import type { SizeTokens } from 'tamagui' | ||
import { Avatar, Paragraph, Tooltip, View, styled, withStaticProperties } from 'tamagui' | ||
|
||
const items = ['Developer', 'User', 'Athlete', 'User', 'Designer'] | ||
|
||
/** ------ EXAMPLE ------ */ | ||
export function AvatarsTooltip() { | ||
return ( | ||
<View gap="$6"> | ||
<View flexDirection="row"> | ||
{items.map((item, index) => ( | ||
<View | ||
marginLeft={index !== 0 ? '$-2' : undefined} | ||
key={item} | ||
hoverStyle={{ | ||
zIndex: 1, | ||
scale: 1.05, | ||
}} | ||
animation="bouncy" | ||
cursor="pointer" | ||
> | ||
<AvatarTip offset={5} placement="bottom" restMs={0} delay={0}> | ||
<AvatarTip.Trigger> | ||
<Item size="$4" imageUrl={`/avatars/300.jpeg`} /> | ||
</AvatarTip.Trigger> | ||
<AvatarTip.Content elevation={2} transformOrigin="center top"> | ||
<AvatarTip.Arrow /> | ||
<Paragraph size="$2" lineHeight="$1"> | ||
{item} | ||
</Paragraph> | ||
</AvatarTip.Content> | ||
</AvatarTip> | ||
</View> | ||
))} | ||
</View> | ||
<View flexDirection="row"> | ||
{items.map((item, index) => ( | ||
<View | ||
marginLeft={index !== 0 ? '$-4' : undefined} | ||
key={item} | ||
hoverStyle={{ | ||
zIndex: 1, | ||
scale: 1.05, | ||
}} | ||
animation="bouncy" | ||
cursor="pointer" | ||
> | ||
<AvatarTip offset={5} placement="bottom" delay={0}> | ||
<AvatarTip.Trigger> | ||
<Item size="$6" imageUrl={`/avatars/300.jpeg`} /> | ||
</AvatarTip.Trigger> | ||
<AvatarTip.Content elevation={2} transformOrigin="center top"> | ||
<AvatarTip.Arrow /> | ||
<Paragraph size="$2" lineHeight="$1"> | ||
{item} | ||
</Paragraph> | ||
</AvatarTip.Content> | ||
</AvatarTip> | ||
</View> | ||
))} | ||
</View> | ||
</View> | ||
) | ||
} | ||
|
||
AvatarsTooltip.fileName = 'AvatarsTooltip' | ||
|
||
function Item({ imageUrl, size }: { imageUrl: string; size: SizeTokens }) { | ||
return ( | ||
<Avatar borderWidth="$1" borderColor="$color1" circular size={size}> | ||
<Avatar.Image src={imageUrl} /> | ||
<Avatar.Fallback backgroundColor="$background" /> | ||
</Avatar> | ||
) | ||
} | ||
|
||
const AvatarTooltipContent = styled(Tooltip.Content, { | ||
enterStyle: { x: 0, y: -5, opacity: 0, scale: 0.9 }, | ||
exitStyle: { x: 0, y: -5, opacity: 0, scale: 0.9 }, | ||
scale: 1, | ||
x: 0, | ||
y: 0, | ||
opacity: 1, | ||
animation: [ | ||
'100ms', | ||
{ | ||
y: { | ||
overshootClamping: true, | ||
}, | ||
}, | ||
], | ||
}) | ||
|
||
const AvatarTip = withStaticProperties(Tooltip, { | ||
Trigger: Tooltip.Trigger, | ||
Content: AvatarTooltipContent, | ||
Arrow: Tooltip.Arrow, | ||
}) |
137 changes: 137 additions & 0 deletions
137
assets/bento-bundle/animation/avatars/AvatarsTooltipFancy.tsx
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,137 @@ | ||
import { useEffect, useRef, useState } from 'react' | ||
import type { SizeTokens, TamaguiElement } from 'tamagui' | ||
import { | ||
Avatar, | ||
Paragraph, | ||
Tooltip, | ||
View, | ||
isWeb, | ||
styled, | ||
withStaticProperties, | ||
} from 'tamagui' | ||
|
||
const items = ['Developer', 'User', 'Athlete', 'User', 'Designer'] | ||
|
||
/** ------ EXAMPLE ------ */ | ||
export function AvatarsTooltipFancy() { | ||
return ( | ||
<View gap="$6"> | ||
<View flexDirection="row"> | ||
{items.map((item, index) => ( | ||
<Item item={item} index={index} key={item} /> | ||
))} | ||
</View> | ||
</View> | ||
) | ||
} | ||
|
||
AvatarsTooltipFancy.fileName = 'AvatarsTooltipFancy' | ||
|
||
function Item(props: { item: string; index: number }) { | ||
const { item, index } = props | ||
const [innerRef, setInnerRef] = useState<TamaguiElement | null>(null) | ||
const [outerRef, setOuterRef] = useState<TamaguiElement | null>(null) | ||
const [position, setPosition] = useState({ degree: '0deg', x: 0 }) | ||
|
||
useCircleInteraction(innerRef, outerRef, ({ degree, x }) => { | ||
setPosition({ degree, x }) | ||
}) | ||
|
||
return ( | ||
<View | ||
marginLeft={index !== 0 ? '$-4' : undefined} | ||
zIndex={index} | ||
key={item} | ||
cursor="pointer" | ||
> | ||
<AvatarTip offset={5} placement="top" delay={0}> | ||
<AvatarTip.Trigger> | ||
<Avatar | ||
ref={setInnerRef} | ||
borderWidth="$1" | ||
borderColor="$color1" | ||
circular | ||
size="$6" | ||
> | ||
<Avatar.Image src={`/avatars/300.jpeg`} /> | ||
<Avatar.Fallback backgroundColor="$background" /> | ||
</Avatar> | ||
</AvatarTip.Trigger> | ||
<AvatarTip.Content | ||
ref={setOuterRef} | ||
elevation={8} | ||
x={position.x / 2} | ||
rotate={position.degree} | ||
transformOrigin="center bottom" | ||
> | ||
<Paragraph size="$2" lineHeight="$1" paddingHorizontal="$2"> | ||
{item} | ||
</Paragraph> | ||
</AvatarTip.Content> | ||
</AvatarTip> | ||
</View> | ||
) | ||
} | ||
|
||
const AvatarTooltipContent = styled(Tooltip.Content, { | ||
enterStyle: { x: 0, y: 15, opacity: 0, scale: 0.9 }, | ||
exitStyle: { x: 0, y: 15, opacity: 0, scale: 0.9 }, | ||
scale: 1, | ||
x: 0, | ||
y: 0, | ||
opacity: 1, | ||
animation: [ | ||
'bouncy', | ||
{ | ||
opacity: { | ||
overshootClamping: true, | ||
}, | ||
}, | ||
], | ||
}) | ||
|
||
const AvatarTip = withStaticProperties(Tooltip, { | ||
Trigger: Tooltip.Trigger, | ||
Content: AvatarTooltipContent, | ||
Arrow: Tooltip.Arrow, | ||
}) | ||
|
||
function useCircleInteraction( | ||
innerRef: any, | ||
outerRef: any, | ||
callback: (arg0: { degree: string; x: number }) => void | ||
) { | ||
if (!isWeb) return | ||
useEffect(() => { | ||
function handleMouseMove(event: MouseEvent) { | ||
const innerRect = innerRef.getBoundingClientRect() | ||
const circleCenterX = innerRect.left + innerRect.width / 2 | ||
const circleWidth = innerRect.width | ||
|
||
const relativeX = event.clientX - circleCenterX | ||
|
||
let degree = (relativeX / (circleWidth / 2)) * -15 | ||
|
||
if (degree > 15) { | ||
degree = 15 | ||
} else if (degree < -15) { | ||
degree = -15 | ||
} | ||
|
||
degree /= 2 | ||
|
||
if (typeof callback === 'function') { | ||
callback({ degree: degree + 'deg', x: -relativeX }) | ||
} | ||
} | ||
if (innerRef && outerRef) { | ||
innerRef.addEventListener('mousemove', handleMouseMove) | ||
} | ||
|
||
return () => { | ||
if (innerRef && outerRef) { | ||
innerRef.removeEventListener('mousemove', handleMouseMove) | ||
} | ||
} | ||
}, [innerRef, callback]) | ||
} |
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 * from './AvatarsTooltip' | ||
export * from './AvatarsTooltipFancy' |
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,78 @@ | ||
import { useEffect, useState } from 'react' | ||
import { AnimatePresence, Button, Spinner, Theme, View } from 'tamagui' | ||
|
||
/** ------ EXAMPLE ------ */ | ||
export function ButtonLoading() { | ||
return ( | ||
<View | ||
flexDirection="row" | ||
gap="$4" | ||
flexWrap="wrap" | ||
alignItems="center" | ||
justifyContent="center" | ||
maxWidth={400} | ||
> | ||
<ButtonLoadingExample /> | ||
<Theme name="blue"> | ||
<ButtonLoadingExample /> | ||
</Theme> | ||
<Theme name="purple"> | ||
<ButtonLoadingExample /> | ||
</Theme> | ||
<Theme name="pink"> | ||
<ButtonLoadingExample /> | ||
</Theme> | ||
<Theme name="red"> | ||
<ButtonLoadingExample /> | ||
</Theme> | ||
<Theme name="orange"> | ||
<ButtonLoadingExample /> | ||
</Theme> | ||
<Theme name="yellow"> | ||
<ButtonLoadingExample /> | ||
</Theme> | ||
<Theme name="green"> | ||
<ButtonLoadingExample /> | ||
</Theme> | ||
</View> | ||
) | ||
} | ||
|
||
function ButtonLoadingExample() { | ||
const [loading, setLoading] = useState(true) | ||
useEffect(() => { | ||
// toggle loading state after every 1 second | ||
const interval = setInterval(() => { | ||
setLoading(!loading) | ||
}, 3000) | ||
return () => clearInterval(interval as NodeJS.Timeout) | ||
}) | ||
return ( | ||
<Button onPress={() => setLoading(!loading)} size="$5"> | ||
<View | ||
animation="bouncy" | ||
flexDirection="row" | ||
x={loading ? 0 : -15} | ||
gap="$3" | ||
alignItems="center" | ||
justifyContent="center" | ||
> | ||
<Button.Icon> | ||
<Spinner | ||
animation="slow" | ||
enterStyle={{ | ||
scale: 0, | ||
}} | ||
exitStyle={{ | ||
scale: 0, | ||
}} | ||
opacity={loading ? 1 : 0} | ||
/> | ||
</Button.Icon> | ||
<Button.Text>Click</Button.Text> | ||
</View> | ||
</Button> | ||
) | ||
} | ||
|
||
ButtonLoading.fileName = 'ButtonLoading' |
Oops, something went wrong.