From 6474b39bacab9acca41f69ea10be0ff5dbb1da21 Mon Sep 17 00:00:00 2001
From: Pavel <14926950+prichodko@users.noreply.github.com>
Date: Wed, 22 Mar 2023 10:39:42 +0100
Subject: [PATCH] Replies, buttons, add shadow (#353)
* improve primary button
* create shadow component
* add all avatar variants
* update reply
* update button prop
* add usePressableColors hook
* update icon button component
* update messages actions
* update composer
* add inverted variant to Shadow component
* update Message component
* fix prop name
* add user-select none to web app
* fix avatar shape
* fix button icon color
* fix icon button token name
* fix icon button selected prop name
* change accordion item prop name
* set default indicator variant
* fix button prop
* export helper types
* refactor accordion props
* buttons only extend PressableProps
* improve typing of variants in component props
* add tmp workaround for pressable props
* remove new line
* make GetVariants helper nonnullable
* fix image aspectRatio
* fix avatar indicator
* fix icon button props
* add todo
---
apps/mobile/App.tsx | 2 +-
apps/web/styles/app.css | 1 +
.../src/accordion/accordion.stories.tsx | 4 +-
.../components/src/accordion/accordion.tsx | 23 +-
.../src/accordion/accordionItem.tsx | 13 +-
.../components/src/avatar/avatar.stories.tsx | 42 ++-
packages/components/src/avatar/avatar.tsx | 331 +++++++++---------
.../components/src/button/button.stories.tsx | 23 +-
packages/components/src/button/button.tsx | 186 +++++-----
packages/components/src/composer/composer.tsx | 39 +--
.../src/hooks/use-pressable-colors.tsx | 69 ++++
.../src/icon-button/icon-button.stories.tsx | 30 ++
.../src/icon-button/icon-button.tsx | 314 ++++++++---------
packages/components/src/image/image.tsx | 64 ++--
.../src/messages/components/actions.tsx | 40 +--
packages/components/src/messages/message.tsx | 26 +-
.../src/popover/popover.stories.tsx | 2 +-
.../src/react-button/react-button.tsx | 125 +++----
packages/components/src/reply/reply.tsx | 7 +-
packages/components/src/shadow/index.tsx | 1 +
.../components/src/shadow/shadow.stories.tsx | 61 ++++
packages/components/src/shadow/shadow.tsx | 97 +++++
packages/components/src/sidebar/mock-data.tsx | 8 +-
packages/components/src/sidebar/sidebar.tsx | 11 +-
.../src/tooltip/tooltip.stories.tsx | 2 +-
packages/components/src/topbar/topbar.tsx | 4 +-
packages/components/src/types.ts | 35 ++
27 files changed, 923 insertions(+), 637 deletions(-)
create mode 100644 packages/components/src/hooks/use-pressable-colors.tsx
create mode 100644 packages/components/src/shadow/index.tsx
create mode 100644 packages/components/src/shadow/shadow.stories.tsx
create mode 100644 packages/components/src/shadow/shadow.tsx
create mode 100644 packages/components/src/types.ts
diff --git a/apps/mobile/App.tsx b/apps/mobile/App.tsx
index 0cb834b6..bc147ae2 100644
--- a/apps/mobile/App.tsx
+++ b/apps/mobile/App.tsx
@@ -124,9 +124,9 @@ export default function App() {
>
Rarible
)}
diff --git a/apps/web/styles/app.css b/apps/web/styles/app.css
index d944a747..882669c6 100644
--- a/apps/web/styles/app.css
+++ b/apps/web/styles/app.css
@@ -3,6 +3,7 @@ body,
#root {
height: 100%;
overscroll-behavior: none;
+ user-select: none;
}
*::selection {
diff --git a/packages/components/src/accordion/accordion.stories.tsx b/packages/components/src/accordion/accordion.stories.tsx
index 8d75f3d5..c1afb90d 100644
--- a/packages/components/src/accordion/accordion.stories.tsx
+++ b/packages/components/src/accordion/accordion.stories.tsx
@@ -8,7 +8,7 @@ const meta: Meta = {
component: Accordion,
argTypes: {},
args: {
- numberOfNewMessages: 3,
+ unreadCount: 3,
title: 'Welcome',
},
parameters: {
@@ -27,7 +27,7 @@ export const Default: Story = {
<>
diff --git a/packages/components/src/accordion/accordion.tsx b/packages/components/src/accordion/accordion.tsx
index 1517e21d..bf476fe4 100644
--- a/packages/components/src/accordion/accordion.tsx
+++ b/packages/components/src/accordion/accordion.tsx
@@ -6,24 +6,18 @@ import { AnimatePresence } from 'tamagui'
import { Label, Paragraph } from '../typography'
-import type { GetProps } from '@tamagui/core'
-
-type BaseProps = GetProps
-
type Props = {
children: React.ReactElement[] | React.ReactElement
initialExpanded: boolean
title: string
- numberOfNewMessages?: number
-} & BaseProps
+ unreadCount?: number
+}
+
+const Accordion = (props: Props) => {
+ const { children, initialExpanded, title, unreadCount } = props
-const Accordion = ({
- children,
- initialExpanded,
- title,
- numberOfNewMessages,
-}: Props) => {
const [isExpanded, setIsExpanded] = useState(initialExpanded)
+
return (
@@ -68,7 +63,7 @@ const Accordion = ({
- {!isExpanded && numberOfNewMessages && (
+ {!isExpanded && unreadCount !== 0 && (
diff --git a/packages/components/src/accordion/accordionItem.tsx b/packages/components/src/accordion/accordionItem.tsx
index 4144a1ca..8ea57a6f 100644
--- a/packages/components/src/accordion/accordionItem.tsx
+++ b/packages/components/src/accordion/accordionItem.tsx
@@ -6,10 +6,9 @@ import { Label, Paragraph } from '../typography'
import type { Channel } from '../sidebar/mock-data'
type Props = {
- isSelected?: boolean
+ selected?: boolean
onPress?: () => void
channel: Channel
- mb?: number
}
const textColor = {
@@ -20,8 +19,9 @@ const textColor = {
}
const AccordionItem = (props: Props) => {
- const { channel, isSelected, onPress, mb } = props
- const { emoji, title, channelStatus = 'normal', numberOfMessages } = channel
+ const { channel, selected, onPress } = props
+
+ const { emoji, title, channelStatus = 'normal', unreadCount } = channel
return (
{
},
},
]}
- backgroundColor={isSelected ? '$primary-50-opa-10' : 'transparent'}
+ backgroundColor={selected ? '$primary-50-opa-10' : 'transparent'}
hoverStyle={{
backgroundColor: '$primary-50-opa-5',
}}
@@ -51,7 +51,6 @@ const AccordionItem = (props: Props) => {
flexDirection="row"
cursor="pointer"
onPress={onPress}
- mb={mb}
>
{
alignItems="center"
>
diff --git a/packages/components/src/avatar/avatar.stories.tsx b/packages/components/src/avatar/avatar.stories.tsx
index f641b777..bf3c65a6 100644
--- a/packages/components/src/avatar/avatar.stories.tsx
+++ b/packages/components/src/avatar/avatar.stories.tsx
@@ -18,12 +18,28 @@ export const Default: Story = {
src: 'https://images.unsplash.com/photo-1518020382113-a7e8fc38eac9?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=500&h=500&q=80',
},
render: args => (
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
),
}
@@ -31,14 +47,18 @@ export const Default: Story = {
export const Rounded: Story = {
args: {
src: 'https://images.unsplash.com/photo-1518020382113-a7e8fc38eac9?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=500&h=500&q=80',
+ shape: 'rounded',
},
render: args => (
-
-
-
-
-
+
+
+
+
+
+
+
+
),
}
diff --git a/packages/components/src/avatar/avatar.tsx b/packages/components/src/avatar/avatar.tsx
index 87fc2f33..5cb8fa4c 100644
--- a/packages/components/src/avatar/avatar.tsx
+++ b/packages/components/src/avatar/avatar.tsx
@@ -4,160 +4,28 @@ import { Stack, styled, Text, Unspaced } from '@tamagui/core'
import { Image } from '../image'
-import type { GetProps } from '@tamagui/core'
+import type { GetStyledVariants } from '@tamagui/core'
-// import { Button as RNButton } from 'react-native'
+type Variants = GetStyledVariants
-// setupReactNative({ Button: RNButton })
-
-// import type { GetProps} from '@tamagui/core';
-
-const Base = styled(Stack, {
- name: 'Avatar',
-
- display: 'flex',
- position: 'relative',
- backgroundColor: '$white-100',
- justifyContent: 'center',
- alignItems: 'center',
-
- variants: {
- size: {
- 80: {
- width: 80,
- height: 80,
- borderRadius: 80 / 2,
- },
- 56: {
- width: 56,
- height: 56,
- borderRadius: 56 / 2,
- },
- 52: {
- width: 52,
- height: 52,
- borderRadius: 52 / 2,
- },
- 48: {
- width: 48,
- height: 48,
- borderRadius: 48 / 2,
- },
- 32: {
- width: 32,
- height: 32,
- borderRadius: 32 / 2,
- },
- 20: {
- width: 20,
- height: 20,
- borderRadius: 20 / 2,
- },
- },
-
- shape: {
- circle: {},
- rounded: {
- borderRadius: 16,
- },
- },
- withOutline: {
- true: {
- borderWidth: 2,
- borderColor: '$white-100',
- },
- },
- } as const,
-})
-
-const Indicator = styled(Stack, {
- name: 'Indicator',
-
- position: 'absolute',
- bottom: 2,
- right: 2,
- zIndex: 2,
-
- borderWidth: 2,
- borderColor: '$white-100',
-
- variants: {
- size: {
- 80: {
- width: 10,
- height: 10,
- borderRadius: 10 / 2,
- },
- 56: {
- width: 10,
- height: 10,
- borderRadius: 10 / 2,
- },
- // FIXME: use catch all variant
- 52: {
- width: 12,
- height: 12,
- borderRadius: 12 / 2,
- },
- 48: {
- width: 10,
- height: 10,
- borderRadius: 10 / 2,
- right: 0,
- bottom: 0,
- },
- 32: {
- width: 10,
- height: 10,
- borderRadius: 10 / 2,
- right: 0,
- bottom: 0,
- },
- 20: {
- width: 10,
- height: 10,
- borderRadius: 10 / 2,
- right: 0,
- bottom: 0,
- },
- },
-
- state: {
- online: {
- backgroundColor: '$success-50',
- },
- offline: {
- backgroundColor: '$neutral-40',
- },
- },
-
- shape: {
- circle: {},
- rounded: {
- borderRadius: 16,
- },
- },
- } as const,
-})
-
-const Fallback = styled(Text, {
- name: 'AvatarFallback',
-})
-
-type BaseProps = GetProps
-
-interface Props {
+type Props = {
src: string
- size: NonNullable
- indicator?: 'online' | 'offline'
- shape?: 'circle' | 'rounded'
- withOutline?: boolean
+ size: 80 | 56 | 48 | 32 | 28 | 24 | 20 | 16
+ shape?: Variants['shape']
+ outline?: Variants['outline']
+ indicator?: GetStyledVariants['state']
}
type ImageLoadingStatus = 'idle' | 'loading' | 'loaded' | 'error'
const Avatar = (props: Props) => {
- const { src, size, shape = 'circle', withOutline, indicator } = props
+ const {
+ src,
+ size,
+ shape = 'circle',
+ outline = false,
+ indicator = 'none',
+ } = props
const [status, setStatus] = useState('idle')
@@ -166,36 +34,163 @@ const Avatar = (props: Props) => {
}, [src])
return (
-
- {indicator && (
+
+ {indicator !== 'none' && (
)}
+
+ setStatus('loaded')}
+ onError={() => setStatus('error')}
+ />
- setStatus('loaded')}
- onError={() => setStatus('error')}
- />
-
- {status === 'error' && (
-
- PP
-
- )}
+ {status === 'error' && (
+
+ PP
+
+ )}
+
)
}
export { Avatar }
export type { Props as AvatarProps }
+
+const Base = styled(Stack, {
+ name: 'Avatar',
+
+ position: 'relative',
+ justifyContent: 'center',
+ alignItems: 'center',
+
+ variants: {
+ // defined in Avatar props
+ size: {
+ '...': (size: number) => {
+ return {
+ width: size,
+ height: size,
+ }
+ },
+ },
+
+ shape: {
+ circle: {
+ borderRadius: 80, // big enough to cover all sizes
+ },
+ rounded: {
+ borderRadius: 16,
+ },
+ },
+
+ outline: {
+ true: {
+ borderWidth: 2,
+ borderColor: '$white-100',
+ },
+ },
+ } as const,
+})
+
+const Shape = styled(Stack, {
+ name: 'AvatarShape',
+
+ width: '100%',
+ height: '100%',
+ backgroundColor: '$white-100',
+ overflow: 'hidden',
+
+ variants: {
+ shape: {
+ circle: {
+ borderRadius: 80, // big enough to cover all sizes
+ },
+ rounded: {
+ borderRadius: 16,
+ },
+ },
+ },
+})
+
+const Indicator = styled(Stack, {
+ name: 'AvatarIndicator',
+
+ position: 'absolute',
+ zIndex: 2,
+ borderWidth: 2,
+ borderColor: '$white-100',
+ borderRadius: 10,
+
+ variants: {
+ size: {
+ 80: {
+ width: 16,
+ height: 16,
+ bottom: 4,
+ right: 4,
+ },
+ 56: {
+ width: 12,
+ height: 12,
+ bottom: 2,
+ right: 2,
+ },
+ 48: {
+ width: 12,
+ height: 12,
+ right: 0,
+ bottom: 0,
+ },
+ 32: {
+ width: 12,
+ height: 12,
+ right: -2,
+ bottom: -2,
+ },
+ 28: {
+ width: 12,
+ height: 12,
+ right: -2,
+ bottom: -2,
+ },
+ 24: {
+ width: 12,
+ height: 12,
+ right: -2,
+ bottom: -2,
+ },
+ 20: {
+ display: 'none',
+ },
+ 16: {
+ display: 'none',
+ },
+ },
+
+ state: {
+ none: {},
+ online: {
+ backgroundColor: '$success-50',
+ },
+ offline: {
+ backgroundColor: '$neutral-40',
+ },
+ },
+ } as const,
+})
+
+const Fallback = styled(Text, {
+ name: 'AvatarFallback',
+})
diff --git a/packages/components/src/button/button.stories.tsx b/packages/components/src/button/button.stories.tsx
index 91b93de8..28f29962 100644
--- a/packages/components/src/button/button.stories.tsx
+++ b/packages/components/src/button/button.stories.tsx
@@ -58,13 +58,6 @@ export const PrimaryDisabled: Story = {
},
}
-export const PrimaryFullWidth: Story = {
- args: {
- children: 'Click me',
- width: 'full',
- },
-}
-
export const Primary32: Story = {
name: 'Primary / 32',
args: {
@@ -103,30 +96,38 @@ export const PrimaryIconOnly: Story = {
},
}
+export const PrimaryIconOnlyCirlce: Story = {
+ name: 'Primary/Icon only/Circle',
+ args: {
+ icon,
+ shape: 'circle',
+ },
+}
+
export const Success: Story = {
args: {
- type: 'positive',
+ variant: 'positive',
children: 'Click me',
},
}
export const Outline: Story = {
args: {
- type: 'outline',
+ variant: 'outline',
children: 'Click me',
},
}
export const Ghost: Story = {
args: {
- type: 'ghost',
+ variant: 'ghost',
children: 'Click me',
},
}
export const Danger: Story = {
args: {
- type: 'danger',
+ variant: 'danger',
children: 'Click me',
},
}
diff --git a/packages/components/src/button/button.tsx b/packages/components/src/button/button.tsx
index a84a7442..b38c718b 100644
--- a/packages/components/src/button/button.tsx
+++ b/packages/components/src/button/button.tsx
@@ -1,12 +1,73 @@
-import { forwardRef } from 'react'
+import { cloneElement, forwardRef } from 'react'
import { Stack, styled } from '@tamagui/core'
import { Paragraph } from '../typography'
-import type { GetProps } from '@tamagui/core'
+import type { GetVariants, MapVariant, PressableProps } from '../types'
+import type { StackProps } from '@tamagui/core'
import type { Ref } from 'react'
+type Variants = GetVariants
+
+type Props = PressableProps & {
+ variant?: Variants['variant']
+ size?: Variants['size']
+ shape?: 'default' | 'circle'
+ children?: string
+ icon?: React.ReactElement
+ iconAfter?: React.ReactElement
+ disabled?: boolean
+}
+
+const textColors: MapVariant = {
+ primary: '$white-100',
+ positive: '$white-100',
+ grey: '$neutral-100',
+ darkGrey: '$neutral-100',
+ outline: '$neutral-100',
+ ghost: '$neutral-100',
+ danger: '$white-100',
+}
+
+const Button = (props: Props, ref: Ref) => {
+ const {
+ variant = 'primary',
+ shape = 'default',
+ size = 40,
+ icon = null,
+ iconAfter = null,
+ children,
+ ...buttonProps
+ } = props
+
+ // TODO: provider aria-label if button has only icon
+ const iconOnly = !children && Boolean(icon)
+ const textColor = textColors[variant]
+
+ return (
+
+ {icon ? cloneElement(icon, { color: textColor }) : null}
+
+ {children}
+
+ {iconAfter ? cloneElement(iconAfter, { color: textColor }) : null}
+
+ )
+}
+
+const _Button = forwardRef(Button)
+
+export { _Button as Button }
+export type { Props as ButtonProps }
+
const Base = styled(Stack, {
tag: 'button',
name: 'Button',
@@ -16,26 +77,24 @@ const Base = styled(Stack, {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
- paddingHorizontal: 16,
- paddingTop: 7,
- paddingBottom: 9,
-
cursor: 'pointer',
userSelect: 'none',
- animation: 'fast',
borderWidth: 1,
borderColor: 'transparent',
+ animation: 'fast',
variants: {
- type: {
+ variant: {
primary: {
- backgroundColor: '$primary',
- hoverStyle: { backgroundColor: '$primaryHover' },
- pressStyle: { backgroundColor: '$primaryHover' },
+ backgroundColor: '$primary-50',
+ hoverStyle: { backgroundColor: '$primary-60' },
+ // TODO: update background color
+ pressStyle: { backgroundColor: '$primary-50' },
},
positive: {
backgroundColor: '$success-50',
hoverStyle: { backgroundColor: '$success-60' },
+ // TODO: update background color
pressStyle: { backgroundColor: '$success-50' },
},
grey: {
@@ -51,7 +110,7 @@ const Base = styled(Stack, {
outline: {
borderWidth: 1,
borderColor: '$neutral-30',
- hoverStyle: { borderColor: '$neutral-30' },
+ hoverStyle: { borderColor: '$neutral-40' },
pressStyle: { borderColor: '$neutral-50' },
},
ghost: {
@@ -62,6 +121,7 @@ const Base = styled(Stack, {
danger: {
backgroundColor: '$danger',
hoverStyle: { backgroundColor: '$danger-60' },
+ // TODO: update background color
pressStyle: { backgroundColor: '$danger' },
},
},
@@ -75,32 +135,41 @@ const Base = styled(Stack, {
size: {
40: {
- minHeight: 40,
- borderRadius: 12,
+ height: 40,
paddingHorizontal: 16,
- paddingTop: 7,
- paddingBottom: 9,
+ gap: 4,
},
32: {
- minHeight: 32,
- borderRadius: 10,
- paddingHorizontal: 16,
- paddingTop: 4,
- paddingBottom: 6,
+ height: 32,
+ paddingHorizontal: 12,
+ gap: 4,
},
24: {
- minHeight: 24,
- borderRadius: 8,
+ height: 24,
paddingHorizontal: 8,
- paddingTop: 2,
- paddingBottom: 4,
+ },
+ },
+
+ radius: {
+ full: {
+ borderRadius: 40,
+ },
+ 40: {
+ borderRadius: 12,
+ },
+ 32: {
+ borderRadius: 10,
+ },
+ 24: {
+ borderRadius: 8,
},
},
iconOnly: {
true: {
- space: 0,
- paddingHorizontal: 8,
+ gap: 0,
+ padding: 0,
+ aspectRatio: 1,
},
},
} as const,
@@ -113,30 +182,6 @@ const ButtonText = styled(Paragraph, {
weight: 'medium',
variants: {
- type: {
- primary: {
- color: '$white-100',
- },
- positive: {
- color: '$white-100',
- },
- grey: {
- color: '$neutral-100',
- },
- darkGrey: {
- color: '$neutral-100',
- },
- outline: {
- color: '$neutral-100',
- },
- ghost: {
- color: '$neutral-100',
- },
- danger: {
- color: '$white-100',
- },
- },
-
size: {
40: {
variant: 'normal',
@@ -150,42 +195,3 @@ const ButtonText = styled(Paragraph, {
},
} as const,
})
-
-type BaseProps = GetProps
-
-type Props = BaseProps & {
- children?: string
- type?: BaseProps['type']
- size?: BaseProps['size']
- disabled?: boolean
- icon?: React.ReactNode
- iconAfter?: React.ReactNode
-}
-
-const Button = (props: Props, ref: Ref) => {
- const {
- type = 'primary',
- size = 40,
- children,
- icon,
- iconAfter,
- ...rest
- } = props
-
- const iconOnly = !children && Boolean(icon)
-
- return (
-
-
- {icon}
- {children}
- {iconAfter}
-
-
- )
-}
-
-const _Button = forwardRef(Button)
-
-export { _Button as Button }
-export type { Props as ButtonProps }
diff --git a/packages/components/src/composer/composer.tsx b/packages/components/src/composer/composer.tsx
index c06b7593..9e52862c 100644
--- a/packages/components/src/composer/composer.tsx
+++ b/packages/components/src/composer/composer.tsx
@@ -10,7 +10,7 @@ import {
ReactionIcon,
} from '@status-im/icons/20'
import { BlurView } from 'expo-blur'
-import { AnimatePresence, Stack, XStack, YStack } from 'tamagui'
+import { AnimatePresence, Stack, XStack } from 'tamagui'
import { Button } from '../button'
import { IconButton } from '../icon-button'
@@ -18,6 +18,7 @@ import { Image } from '../image'
import { Input } from '../input'
import { useChatDispatch, useChatState } from '../provider'
import { Reply } from '../reply'
+import { Shadow } from '../shadow'
interface Props {
blur?: boolean
@@ -43,6 +44,8 @@ const Composer = (props: Props) => {
const chatState = useChatState()
const chatDispatch = useChatDispatch()
+ const showSendButton = text !== '' || imagesData.length > 0
+
return (
{
width: '100%',
}}
>
-
{chatState?.type === 'reply' && (
@@ -169,42 +168,38 @@ const Composer = (props: Props) => {
variant="outline"
icon={}
disabled={isImageUploadDisabled}
- blurred={iconButtonBlurred}
+ blur={iconButtonBlurred}
/>
}
- blurred={iconButtonBlurred}
+ blur={iconButtonBlurred}
/>
}
disabled
- blurred={iconButtonBlurred}
+ blur={iconButtonBlurred}
/>
- {text || imagesData.length > 0 ? (
- // TODO fix styles for circular button. Also the color is different from the design and we have layout shift because of the size.
+ {showSendButton ? (
}
- height={32}
size={32}
- width={32}
- borderRadius={32}
- justifyContent="center"
- alignItems="center"
- type="positive"
/>
) : (
- }
- blurred={iconButtonBlurred}
+ size={32}
+ // blurred={iconButtonBlurred}
/>
)}
-
+
)
}
diff --git a/packages/components/src/hooks/use-pressable-colors.tsx b/packages/components/src/hooks/use-pressable-colors.tsx
new file mode 100644
index 00000000..25130207
--- /dev/null
+++ b/packages/components/src/hooks/use-pressable-colors.tsx
@@ -0,0 +1,69 @@
+import { useState } from 'react'
+
+import type { PressableProps } from '../types'
+import type { ColorTokens } from 'tamagui'
+
+type Config = {
+ default: ColorTokens
+ hover: ColorTokens
+ press: ColorTokens
+ active: ColorTokens
+}
+
+type Return = {
+ color: ColorTokens
+ pressableProps: Pick<
+ PressableProps,
+ 'onHoverIn' | 'onHoverOut' | 'onPressIn' | 'onPressOut'
+ >
+}
+
+export const usePressableColors = (
+ styles: Config,
+ props: Partial & {
+ 'aria-expanded'?: boolean
+ 'aria-selected'?: boolean
+ selected?: boolean
+ }
+): Return => {
+ const [hovered, setHovered] = useState(false)
+ const [pressed, setPressed] = useState(false)
+
+ /**
+ * Order of precedence:
+ * 1. active
+ * 2. press
+ * 3. hover
+ * 4. default
+ */
+ const key =
+ props['aria-expanded'] || props['aria-selected']
+ ? 'active'
+ : pressed
+ ? 'press'
+ : hovered
+ ? 'hover'
+ : 'default'
+
+ return {
+ color: styles[key],
+ pressableProps: {
+ onHoverIn: event => {
+ props.onHoverIn?.(event)
+ setHovered(true)
+ },
+ onHoverOut: event => {
+ props.onHoverOut?.(event)
+ setHovered(false)
+ },
+ onPressIn: event => {
+ props.onPressIn?.(event)
+ setPressed(true)
+ },
+ onPressOut: event => {
+ props.onPressOut?.(event)
+ setPressed(false)
+ },
+ } as const,
+ }
+}
diff --git a/packages/components/src/icon-button/icon-button.stories.tsx b/packages/components/src/icon-button/icon-button.stories.tsx
index 1244e78d..9fd704c8 100644
--- a/packages/components/src/icon-button/icon-button.stories.tsx
+++ b/packages/components/src/icon-button/icon-button.stories.tsx
@@ -1,4 +1,5 @@
import { OptionsIcon } from '@status-im/icons/20'
+import { Stack } from 'tamagui'
import { IconButton } from './icon-button'
@@ -8,6 +9,12 @@ import type { Meta, StoryObj } from '@storybook/react'
const meta: Meta = {
component: IconButton,
argTypes: {},
+ parameters: {
+ design: {
+ type: 'figma',
+ url: 'https://www.figma.com/file/IBmFKgGL1B4GzqD8LQTw6n/Design-System-for-Desktop%2FWeb?node-id=10466-128996&t=GxddSvW99WvZQY0A-11',
+ },
+ },
}
type Story = StoryObj
@@ -17,6 +24,29 @@ export const Default: Story = {
args: {
icon: ,
},
+ render: args => {
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ )
+ },
}
export default meta
diff --git a/packages/components/src/icon-button/icon-button.tsx b/packages/components/src/icon-button/icon-button.tsx
index 86dc78f2..0f5da85c 100644
--- a/packages/components/src/icon-button/icon-button.tsx
+++ b/packages/components/src/icon-button/icon-button.tsx
@@ -1,110 +1,20 @@
import { cloneElement, forwardRef } from 'react'
-import { Stack, styled } from '@tamagui/core'
+import { Stack, styled } from 'tamagui'
+import { usePressableColors } from '../hooks/use-pressable-colors'
+
+import type { GetVariants, PressableProps } from '../types'
+import type { StackProps } from '@tamagui/core'
import type { Ref } from 'react'
-const Base = styled(Stack, {
- name: 'IconButton',
- accessibilityRole: 'button',
+type Variants = GetVariants
- cursor: 'pointer',
- userSelect: 'none',
- borderRadius: 10,
- display: 'flex',
- alignItems: 'center',
- justifyContent: 'center',
- animation: 'fast',
-
- width: 30,
- height: 30,
- borderWidth: 1,
- padding: 4,
-
- variants: {
- variant: {
- default: {
- backgroundColor: '$iconButtonBackground',
- borderColor: 'transparent',
-
- hoverStyle: {
- backgroundColor: '$iconButtonBackgroundHover',
- },
-
- pressStyle: {
- backgroundColor: '$iconButtonBackgroundHover',
- },
- },
- outline: {
- backgroundColor: 'transparent',
- borderColor: '$iconButtonOutlineBorder',
-
- hoverStyle: {
- borderColor: '$iconButtonOutlineBorderHover',
- },
-
- pressStyle: {
- borderColor: '$iconButtonOutlineBorderHover',
- },
- },
- },
- blurred: {
- default: {
- backgroundColor: '$iconButtonBackgroundBlurred',
-
- hoverStyle: {
- backgroundColor: '$iconButtonBackgroundBlurredHover',
- },
-
- pressStyle: {
- backgroundColor: 'iconButtonBackgroundBlurredHover',
- },
- },
- outline: {
- borderColor: '$iconButtonOutlineBorderBlurred',
-
- hoverStyle: {
- borderColor: '$iconButtonOutlineBorderBlurredHover',
- },
-
- pressStyle: {
- borderColor: '$iconButtonOutlineBorderBlurredHover',
- },
- },
- },
- selected: {
- default: {
- backgroundColor: '$iconButtonBackgroundSelected',
- borderColor: '$iconButtonBorderSelected',
- },
- defaultWithBlur: {
- backgroundColor: '$iconButtonBackgroundBlurredSelected',
- borderColor: '$iconButtonBorderBlurredSelected',
- },
- outline: {
- backgroundColor: '$iconButtonOutlineBackgroundSelected',
- borderColor: '$iconButtonOutlineBorderSelected',
- },
- outlineWithBlur: {
- backgroundColor: '$iconButtonOutBackgroundBlurredSelected',
- borderColor: '$iconButtonOutlineBorderBlurredSelected',
- },
- },
- disabled: {
- true: {
- opacity: 0.3,
- cursor: 'default',
- },
- },
- } as const,
-})
-
-interface Props {
+type Props = PressableProps & {
icon: React.ReactElement
- onPress?: () => void
+ variant?: Variants['variant']
selected?: boolean
- blurred?: boolean
- variant?: 'default' | 'outline'
+ blur?: boolean
disabled?: boolean
// FIXME: enforce aria-label for accessibility
// 'aria-label'?: string
@@ -113,80 +23,34 @@ interface Props {
'aria-selected'?: boolean
}
-const iconColor = {
- default: {
- default: '$iconButtonColor',
- defaultBlurred: '$iconButtonColorBlurred',
- selected: '$iconButtonColorSelected',
- selectedBlurred: '$iconButtonColorBlurred',
- },
- outline: {
- default: '$iconButtonColorOutline',
- defaultBlurred: '$iconButtonColorOutlineBlurred',
- selected: '$iconButtonColorOutlineSelected',
- selectedBlurred: '$iconButtonColorOutlineBlurred',
- },
-}
-
-const getStateForIconColor = ({
- blurred,
- selected,
-}: {
- blurred?: boolean
- selected?: boolean
-}) => {
- if (!selected && blurred) {
- return 'defaultBlurred'
- }
- if (selected && blurred) {
- return 'selectedBlurred'
- }
- if (selected && !blurred) {
- return 'selected'
- }
- return 'default'
-}
-
-const getSelectedVariant = ({
- selected,
- blurred,
- variant,
-}: {
- selected?: boolean
- blurred?: boolean
- variant?: 'default' | 'outline'
-}) => {
- if (!selected) {
- return undefined
- }
- if (blurred && variant === 'default') {
- return 'defaultWithBlur'
- }
- if (blurred && variant === 'outline') {
- return 'outlineWithBlur'
- }
- return variant
-}
-
const IconButton = (props: Props, ref: Ref) => {
- const { icon, blurred, variant = 'default', ...rest } = props
+ const { icon, blur, variant = 'default', ...buttonProps } = props
+
+ const { pressableProps, color } = usePressableColors(
+ {
+ default: blur ? '$neutral-80-opa-70' : '$neutral-50',
+ hover: blur ? '$neutral-80-opa-70' : '$neutral-50',
+ press: '$neutral-100',
+ active: '$neutral-100',
+ },
+ props
+ )
const selected =
props.selected || props['aria-expanded'] || props['aria-selected']
- const state = getStateForIconColor({ blurred, selected })
- const selectedVariant = getSelectedVariant({ selected, variant, blurred })
-
return (
{cloneElement(icon, {
- color: iconColor[variant][state],
+ color,
size: 20,
})}
@@ -197,3 +61,127 @@ const _IconButton = forwardRef(IconButton)
export { _IconButton as IconButton }
export type { Props as IconButtonProps }
+
+const Base = styled(Stack, {
+ name: 'IconButton',
+ tag: 'button',
+ accessibilityRole: 'button',
+
+ cursor: 'pointer',
+ userSelect: 'none',
+ borderRadius: 10,
+ display: 'flex',
+ alignItems: 'center',
+ justifyContent: 'center',
+ padding: 4,
+ width: 32,
+ height: 32,
+ borderWidth: 1,
+ borderColor: 'transparent',
+ animation: 'fast',
+
+ variants: {
+ variant: {
+ default: {
+ backgroundColor: '$neutral-10',
+ borderColor: 'transparent',
+ hoverStyle: { backgroundColor: '$neutral-20' },
+ pressStyle: {
+ backgroundColor: '$neutral-20',
+ borderColor: '$neutral-30',
+ },
+ },
+
+ outline: {
+ backgroundColor: 'transparent',
+ borderColor: '$neutral-20',
+ hoverStyle: { borderColor: '$neutral-30' },
+ pressStyle: {
+ borderColor: '$neutral-20',
+ backgroundColor: '$neutral-10',
+ },
+ },
+
+ ghost: {
+ backgroundColor: 'transparent',
+ hoverStyle: { backgroundColor: '$neutral-10' },
+ pressStyle: {
+ backgroundColor: '$neutral-10',
+ borderColor: '$neutral-20',
+ },
+ },
+ },
+
+ active: {
+ default: {
+ backgroundColor: '$neutral-20',
+ borderColor: '$neutral-30',
+ },
+
+ outline: {
+ borderColor: '$neutral-20',
+ backgroundColor: '$neutral-10',
+ },
+
+ ghost: {
+ backgroundColor: '$neutral-10',
+ borderColor: '$neutral-20',
+ },
+ },
+
+ variantBlur: {
+ default: {
+ backgroundColor: '$neutral-80-opa-5',
+ borderColor: 'transparent',
+ hoverStyle: { backgroundColor: '$neutral-80-opa-10' },
+ pressStyle: {
+ backgroundColor: '$neutral-80-opa-10',
+ borderColor: '$neutral-80-opa-5',
+ },
+ },
+
+ outline: {
+ backgroundColor: 'transparent',
+ borderColor: '$neutral-80-opa-10',
+ hoverStyle: { borderColor: '$neutral-80-opa-20' },
+ pressStyle: {
+ borderColor: '$neutral-80-opa-10',
+ backgroundColor: '$neutral-80-opa-5',
+ },
+ },
+
+ ghost: {
+ backgroundColor: 'transparent',
+ hoverStyle: { backgroundColor: '$neutral-80-opa-5' },
+ pressStyle: {
+ backgroundColor: '$neutral-80-opa-5',
+ borderColor: '$neutral-80-opa-10',
+ },
+ },
+ },
+
+ activeBlur: {
+ default: {
+ backgroundColor: '$neutral-80-opa-10',
+ borderColor: '$neutral-80-opa-5',
+ },
+
+ outline: {
+ borderColor: '$neutral-80-opa-10',
+ backgroundColor: '$neutral-80-opa-5',
+ },
+
+ ghost: {
+ backgroundColor: '$neutral-80-opa-5',
+ borderColor: '$neutral-80-opa-10',
+ },
+ },
+
+ disabled: {
+ true: {
+ opacity: 0.3,
+ cursor: 'default',
+ },
+ },
+ } as const,
+})
diff --git a/packages/components/src/image/image.tsx b/packages/components/src/image/image.tsx
index e86683c4..b1541339 100644
--- a/packages/components/src/image/image.tsx
+++ b/packages/components/src/image/image.tsx
@@ -3,48 +3,24 @@ import { forwardRef } from 'react'
import { setupReactNative, styled } from '@tamagui/core'
import { Image as RNImage } from 'react-native'
-import type { GetProps } from '@tamagui/core'
+import type { GetProps, GetVariants } from '../types'
import type { Ref } from 'react'
-import type { ImagePropsBase as RNImageProps } from 'react-native'
setupReactNative({
Image: RNImage,
})
-const Base = styled(RNImage, {
- name: 'Image',
- position: 'relative',
- zIndex: 1,
- source: {
- uri: '',
- },
+type Variants = GetVariants
- variants: {
- radius: {
- 12: {
- borderRadius: 12,
- },
- full: {
- borderRadius: 9999,
- },
- },
- },
-})
-
-type ImageProps = GetProps
-
-interface Props {
+type Props = GetProps & {
src: string
width: number | 'full'
height?: number
- aspectRatio?: ImageProps['aspectRatio']
- radius?: ImageProps['radius']
- onLoad?: RNImageProps['onLoad']
- onError?: RNImageProps['onError']
+ radius?: Variants['radius']
}
const Image = (props: Props, ref: Ref) => {
- const { src, aspectRatio, radius, ...rest } = props
+ const { src, radius = 'none', aspectRatio, ...imageProps } = props
const width = props.width === 'full' ? '100%' : props.width
const height = aspectRatio ? undefined : props.height
@@ -56,19 +32,39 @@ const Image = (props: Props, ref: Ref) => {
return (
)
}
-// TODO?: this was used in @tamagui/image package. Why?
-// focusableInputHOC(Image)
-const _Image = Base.extractable(forwardRef(Image))
+const _Image = forwardRef(Image)
export { _Image as Image }
+export type { Props as ImageProps }
+
+const Base = styled(RNImage, {
+ name: 'Image',
+ position: 'relative',
+ zIndex: 1,
+ source: {
+ uri: '',
+ },
+
+ variants: {
+ radius: {
+ none: {},
+ 12: {
+ borderRadius: 12,
+ },
+ full: {
+ borderRadius: 9999,
+ },
+ },
+ },
+})
diff --git a/packages/components/src/messages/components/actions.tsx b/packages/components/src/messages/components/actions.tsx
index 1e4a37e7..a5cb8342 100644
--- a/packages/components/src/messages/components/actions.tsx
+++ b/packages/components/src/messages/components/actions.tsx
@@ -11,10 +11,10 @@ import {
PinIcon,
ReplyIcon,
} from '@status-im/icons/20'
-import { Stack } from 'tamagui'
import { DropdownMenu } from '../../dropdown-menu'
import { IconButton } from '../../icon-button'
+import { Shadow } from '../../shadow'
import { ReactionPopover } from './reaction-popover'
import type { ReactionsType } from '../types'
@@ -35,21 +35,19 @@ export const Actions = (props: Props) => {
}, [onOpenChange])
return (
-
{/* REACTION */}
@@ -59,29 +57,25 @@ export const Actions = (props: Props) => {
sideOffset={6}
onOpenChange={onOpenChange}
>
- } />
+ } />
{/* REPLY */}
- }
- onPress={onReplyPress}
- />
+ } onPress={onReplyPress} />
{/* EDIT */}
- } onPress={onEditPress} />
+ } onPress={onEditPress} />
{/* DELETE */}
{/* }
onPress={onDeletePress}
/> */}
{/* OPTIONS MENU */}
- } />
+ } />
}
@@ -124,6 +118,6 @@ export const Actions = (props: Props) => {
/>
-
+
)
}
diff --git a/packages/components/src/messages/message.tsx b/packages/components/src/messages/message.tsx
index b0659e9b..552c01f7 100644
--- a/packages/components/src/messages/message.tsx
+++ b/packages/components/src/messages/message.tsx
@@ -1,10 +1,9 @@
import { useState } from 'react'
import { PinIcon } from '@status-im/icons/16'
-import { View } from 'react-native'
import { Stack, styled, Unspaced, XStack, YStack } from 'tamagui'
-import { Author } from '../author/author'
+import { Author } from '../author'
import { Avatar } from '../avatar'
import { Image } from '../image'
import { useChatDispatch } from '../provider'
@@ -23,7 +22,7 @@ interface Props {
pinned?: boolean
}
-const Wrapper = styled(View, {
+const Base = styled(Stack, {
position: 'relative',
paddingHorizontal: 8,
paddingVertical: 8,
@@ -36,6 +35,7 @@ const Wrapper = styled(View, {
backgroundColor: '$neutral-5',
},
},
+
pinned: {
true: {
backgroundColor: '$blue-50-opa-5',
@@ -48,15 +48,16 @@ const Message = (props: Props) => {
const { text, images, reactions, reply, pinned } = props
const [hovered, setHovered] = useState(false)
- const [actionsOpen, setActionsOpen] = useState(false)
+ const [showActions, setShowActions] = useState(false)
- const active = actionsOpen || hovered
+ const active = showActions || hovered
+ const hasReactions = Object.keys(reactions).length > 0
//
const dispatch = useChatDispatch()
return (
- setHovered(true)}
onHoverOut={() => setHovered(false)}
@@ -65,7 +66,7 @@ const Message = (props: Props) => {
dispatch({ type: 'reply', messageId: '1' })}
onEditPress={() => dispatch({ type: 'edit', messageId: '1' })}
/>
@@ -113,7 +114,12 @@ const Message = (props: Props) => {
/>
{text && (
-
+
{text}
)}
@@ -130,14 +136,14 @@ const Message = (props: Props) => {
))}
- {reactions && (
+ {hasReactions && (
)}
-
+
)
}
diff --git a/packages/components/src/popover/popover.stories.tsx b/packages/components/src/popover/popover.stories.tsx
index 003018e5..26f792da 100644
--- a/packages/components/src/popover/popover.stories.tsx
+++ b/packages/components/src/popover/popover.stories.tsx
@@ -23,7 +23,7 @@ export const Default: Story = {
args: {},
render: args => (
-
+
some content
),
diff --git a/packages/components/src/react-button/react-button.tsx b/packages/components/src/react-button/react-button.tsx
index 57636abf..3f456da8 100644
--- a/packages/components/src/react-button/react-button.tsx
+++ b/packages/components/src/react-button/react-button.tsx
@@ -13,10 +13,72 @@ import { Stack, styled } from '@tamagui/core'
import { Paragraph } from '../typography'
-import type { GetProps } from '@tamagui/core'
+import type { GetVariants } from '../types'
+import type { StackProps } from '@tamagui/core'
import type { Ref } from 'react'
import type { PressableProps } from 'react-native'
+type Variants = GetVariants
+
+export const REACTIONS = {
+ love: LoveIcon,
+ laugh: LaughIcon,
+ 'thumbs-up': ThumbsUpIcon,
+ 'thumbs-down': ThumbsDownIcon,
+ sad: SadIcon,
+ angry: AngryIcon,
+ add: AddReactionIcon,
+} as const
+
+type Props = PressableProps & {
+ icon: keyof typeof REACTIONS
+ variant?: Variants['variant']
+ size?: Variants['size']
+ // FIXME: use aria-selected
+ selected?: boolean
+ count?: number
+ // FIXME: update to latest RN
+ 'aria-expanded'?: boolean
+ 'aria-selected'?: boolean
+}
+
+const ReactButton = (props: Props, ref: Ref) => {
+ const {
+ icon,
+ variant = 'outline',
+ size = 40,
+ count,
+ ...pressableProps
+ } = props
+
+ const Icon = REACTIONS[icon]
+
+ const selected =
+ props.selected || props['aria-expanded'] || props['aria-selected']
+
+ return (
+
+ )
+}
+
+const _ReactButton = forwardRef(ReactButton)
+
+export { _ReactButton as ReactButton }
+export type { Props as ReactButtonProps }
+
const Button = styled(Stack, {
name: 'ReactButton',
accessibilityRole: 'button',
@@ -78,64 +140,3 @@ const Button = styled(Stack, {
},
} as const,
})
-
-type ButtonProps = GetProps
-
-export const REACTIONS = {
- love: LoveIcon,
- laugh: LaughIcon,
- 'thumbs-up': ThumbsUpIcon,
- 'thumbs-down': ThumbsDownIcon,
- sad: SadIcon,
- angry: AngryIcon,
- add: AddReactionIcon,
-} as const
-
-interface Props extends PressableProps {
- icon: keyof typeof REACTIONS
- variant?: ButtonProps['variant']
- size?: ButtonProps['size']
- // FIXME: use aria-selected
- selected?: boolean
- count?: number
- // FIXME: update to latest RN
- 'aria-expanded'?: boolean
- 'aria-selected'?: boolean
-}
-
-const ReactButton = (props: Props, ref: Ref) => {
- const {
- icon,
- variant = 'outline',
- size = 40,
- count,
- ...pressableProps
- } = props
-
- const Icon = REACTIONS[icon]
-
- const selected =
- props.selected || props['aria-expanded'] || props['aria-selected']
-
- return (
-
- )
-}
-
-const _ReactButton = forwardRef(ReactButton)
-
-export { _ReactButton as ReactButton }
-export type { Props as ReactButtonProps }
diff --git a/packages/components/src/reply/reply.tsx b/packages/components/src/reply/reply.tsx
index 5f88d45f..867b89c5 100644
--- a/packages/components/src/reply/reply.tsx
+++ b/packages/components/src/reply/reply.tsx
@@ -27,7 +27,7 @@ const Reply = (props: Props) => {
-
+
{name}
@@ -64,12 +64,11 @@ const Reply = (props: Props) => {
>
{content}
- {/* FIXME: This should be regular button with size 24 */}
{onClose && (
}
+ variant="outline"
+ size={24}
onPress={onClose}
/>
)}
diff --git a/packages/components/src/shadow/index.tsx b/packages/components/src/shadow/index.tsx
new file mode 100644
index 00000000..fd721c3c
--- /dev/null
+++ b/packages/components/src/shadow/index.tsx
@@ -0,0 +1 @@
+export { Shadow, type ShadowProps } from './shadow'
diff --git a/packages/components/src/shadow/shadow.stories.tsx b/packages/components/src/shadow/shadow.stories.tsx
new file mode 100644
index 00000000..af40ade8
--- /dev/null
+++ b/packages/components/src/shadow/shadow.stories.tsx
@@ -0,0 +1,61 @@
+import { Stack } from 'tamagui'
+
+import { Shadow } from './shadow'
+
+import type { Meta, StoryObj } from '@storybook/react'
+
+const meta: Meta = {
+ component: Shadow,
+ argTypes: {},
+ args: {},
+ parameters: {
+ design: {
+ type: 'figma',
+ url: 'https://www.figma.com/file/v98g9ZiaSHYUdKWrbFg9eM/Foundations?node-id=624-752&t=ppNe6QC4ntgNciqw-11',
+ },
+ },
+}
+
+export default meta
+
+type Story = StoryObj
+
+export const Default: Story = {
+ args: {},
+ render: () => (
+
+
+
+
+
+
+ ),
+}
diff --git a/packages/components/src/shadow/shadow.tsx b/packages/components/src/shadow/shadow.tsx
new file mode 100644
index 00000000..00d946fa
--- /dev/null
+++ b/packages/components/src/shadow/shadow.tsx
@@ -0,0 +1,97 @@
+import { forwardRef } from 'react'
+
+import { Stack, styled } from 'tamagui'
+
+import type { GetVariants } from '../types'
+import type { StackProps } from '@tamagui/core'
+import type { Ref } from 'react'
+import type { View } from 'react-native'
+
+type Variants = GetVariants
+
+type Props = StackProps & {
+ variant?: Variants['variant']
+ inverted?: boolean
+}
+
+const Shadow = (props: Props, ref: Ref) => {
+ const { variant = '$1', inverted = false, ...stackProps } = props
+
+ return (
+
+ )
+}
+
+const _Shadow = forwardRef(Shadow)
+
+export { _Shadow as Shadow }
+export type { Props as ShadowProps }
+
+const Base = styled(Stack, {
+ variants: {
+ variant: {
+ $1: {
+ // box-shadow: 0px 2px 20px 0px hsla(218, 51%, 7%, 0.04);
+ shadowOffset: { width: 0, height: 2 },
+ shadowRadius: 20,
+ shadowColor: 'hsla(218, 51%, 7%, 0.04)',
+ },
+ $2: {
+ // box-shadow: 0px 4px 20px 0px hsla(218, 51%, 7%, 0.08);
+ shadowOffset: { width: 0, height: 4 },
+ shadowRadius: 20,
+ shadowColor: 'hsla(218, 51%, 7%, 0.08)',
+ },
+ $3: {
+ // box-shadow: 0px 8px 30px 0px hsla(218, 51%, 7%, 0.12);
+ shadowOffset: { width: 0, height: 8 },
+ shadowRadius: 30,
+ shadowColor: 'hsla(218, 51%, 7%, 0.12)',
+ },
+ $4: {
+ // box-shadow: 0px 12px 56px 0px hsla(218, 51%, 7%, 0.16);
+ shadowOffset: { width: 0, height: 12 },
+ shadowRadius: 56,
+ shadowColor: 'hsla(218, 51%, 7%, 0.16)',
+ },
+ none: {},
+ },
+
+ inverted: {
+ $1: {
+ // box-shadow: 0px -2px 20px 0px hsla(218, 51%, 7%, 0.04);
+ shadowOffset: { width: 0, height: -2 },
+ shadowRadius: 20,
+ shadowColor: 'hsla(218, 51%, 7%, 0.04)',
+ },
+ $2: {
+ // box-shadow: 0px -4px 20px 0px hsla(218, 51%, 7%, 0.08);
+ shadowOffset: { width: 0, height: -4 },
+ shadowRadius: 20,
+ shadowColor: 'hsla(218, 51%, 7%, 0.08)',
+ },
+ $3: {
+ // box-shadow: 0px -8px 30px 0px hsla(218, 51%, 7%, 0.12);
+ shadowOffset: { width: 0, height: -8 },
+ shadowRadius: 30,
+ shadowColor: 'hsla(218, 51%, 7%, 0.12)',
+ },
+ $4: {
+ // box-shadow: 0px 12px 56px 0px hsla(218, 51%, 7%, 0.16);
+ shadowOffset: { width: 0, height: 12 },
+ shadowRadius: 56,
+ shadowColor: 'hsla(218, 51%, 7%, 0.16)',
+ },
+ none: {},
+ },
+ } as const,
+
+ defaultVariants: {
+ variant: '$1',
+ },
+})
diff --git a/packages/components/src/sidebar/mock-data.tsx b/packages/components/src/sidebar/mock-data.tsx
index 6bd3fefb..6a34cc51 100644
--- a/packages/components/src/sidebar/mock-data.tsx
+++ b/packages/components/src/sidebar/mock-data.tsx
@@ -4,7 +4,7 @@ export interface Channel {
description: string
emoji: string
channelStatus?: 'muted' | 'normal' | 'withMessages' | 'withMentions'
- numberOfMessages?: number
+ unreadCount?: number
}
export interface ChannelGroup {
@@ -49,7 +49,7 @@ export const CHANNEL_GROUPS: ChannelGroup[] = [
emoji: randomEmoji(),
description: 'Share random funny stuff with the community. Play nice.',
channelStatus: 'withMentions',
- numberOfMessages: 3,
+ unreadCount: 3,
},
],
},
@@ -68,7 +68,7 @@ export const CHANNEL_GROUPS: ChannelGroup[] = [
id: 'jobs',
title: '# jobs',
channelStatus: 'withMentions',
- numberOfMessages: 3,
+ unreadCount: 3,
emoji: randomEmoji(),
description: 'Share random funny stuff with the community. Play nice.',
},
@@ -76,7 +76,7 @@ export const CHANNEL_GROUPS: ChannelGroup[] = [
id: 'events',
title: '# events',
channelStatus: 'withMentions',
- numberOfMessages: 2,
+ unreadCount: 2,
emoji: randomEmoji(),
description: 'Share random funny stuff with the community. Play nice.',
},
diff --git a/packages/components/src/sidebar/sidebar.tsx b/packages/components/src/sidebar/sidebar.tsx
index cc98c5ee..405de6b8 100644
--- a/packages/components/src/sidebar/sidebar.tsx
+++ b/packages/components/src/sidebar/sidebar.tsx
@@ -53,7 +53,7 @@ const Sidebar = (props: Props) => {
@@ -72,18 +72,15 @@ const Sidebar = (props: Props) => {
key={group.id}
initialExpanded={group.id === 'welcome'}
title={group.title}
- numberOfNewMessages={group.unreadCount}
+ unreadCount={group.unreadCount}
>
- {group.channels.map((channel, index) => {
- const isLastChannelOfTheList = index === group.channels.length - 1
-
+ {group.channels.map(channel => {
return (
onChannelPress(channel.id)}
- mb={isLastChannelOfTheList ? 8 : 0}
/>
)
})}
diff --git a/packages/components/src/tooltip/tooltip.stories.tsx b/packages/components/src/tooltip/tooltip.stories.tsx
index 97e02370..5af103ea 100644
--- a/packages/components/src/tooltip/tooltip.stories.tsx
+++ b/packages/components/src/tooltip/tooltip.stories.tsx
@@ -22,7 +22,7 @@ export const Default: Story = {
},
render: args => (
-
+
),
}
diff --git a/packages/components/src/topbar/topbar.tsx b/packages/components/src/topbar/topbar.tsx
index 6a0b6349..b07e8b9c 100644
--- a/packages/components/src/topbar/topbar.tsx
+++ b/packages/components/src/topbar/topbar.tsx
@@ -51,7 +51,7 @@ const Topbar = (props: Props) => {
}
onPress={() => goBack?.()}
- blurred={blur}
+ blur={blur}
/>
@@ -100,7 +100,7 @@ const Topbar = (props: Props) => {
icon={}
selected={membersVisisble}
onPress={onMembersPress}
- blurred={blur}
+ blur={blur}
/>
diff --git a/packages/components/src/types.ts b/packages/components/src/types.ts
new file mode 100644
index 00000000..06346eaa
--- /dev/null
+++ b/packages/components/src/types.ts
@@ -0,0 +1,35 @@
+import type {
+ ColorTokens,
+ GetBaseProps,
+ GetProps,
+ GetStyledVariants,
+ TamaguiComponent,
+} from '@tamagui/core'
+import type { PressableProps as NativePressableProps } from 'react-native'
+
+type PressableProps = {
+ onHoverIn?: Exclude
+ onHoverOut?: NativePressableProps['onHoverOut']
+ onPress?: NativePressableProps['onPress']
+ onPressIn?: NativePressableProps['onPressIn']
+ onPressOut?: NativePressableProps['onPressOut']
+ onLongPress?: NativePressableProps['onLongPress']
+ delayHoverIn?: NativePressableProps['delayHoverIn']
+ delayHoverOut?: NativePressableProps['delayHoverOut']
+ delayLongPress?: NativePressableProps['delayLongPress']
+ disabled?: NativePressableProps['disabled']
+}
+
+export type MapVariant<
+ C extends TamaguiComponent,
+ K extends keyof GetStyledVariants,
+ V extends GetStyledVariants = GetStyledVariants
+> = {
+ [key in V[K] & string]: ColorTokens
+}
+
+export type GetVariants = Required<
+ GetStyledVariants
+>
+
+export type { GetBaseProps, GetProps, PressableProps }