From 1e5e10eaddb50d6c0492ec600db5781205299252 Mon Sep 17 00:00:00 2001 From: Pavel <14926950+prichodko@users.noreply.github.com> Date: Thu, 30 Mar 2023 14:41:56 +0200 Subject: [PATCH] Message reactions, add Tabs, update Dialog and Tooltip (#361) * add Tabs component * update Tooltip styling * add reactions dialog * use IconButton and simplify ReactButton * add PressableTrigger to dialog * update css reset * update pressable type * fix text story name * update dynamic button props * add counter to TabsTrigger * fix casing in USerListProps * make Dialog.Content customizable * update dialogs --- apps/web/styles/reset.css | 1 + packages/components/.storybook/reset.css | 1 + packages/components/package.json | 1 + packages/components/src/counter/counter.tsx | 9 +- .../components/src/dialog/dialog.stories.tsx | 5 +- packages/components/src/dialog/dialog.tsx | 118 ++++++------- packages/components/src/dialog/index.tsx | 2 +- .../dynamic-button/dynamic-button.stories.tsx | 1 - .../src/dynamic-button/dynamic-button.tsx | 9 +- .../src/hooks/use-pressable-colors.tsx | 10 +- .../src/icon-button/icon-button.tsx | 5 +- .../messages/components/reaction-popover.tsx | 49 ++++-- .../messages/components/reactions-dialog.tsx | 89 ++++++++++ .../src/messages/components/reactions.tsx | 116 ++++++------- .../src/pinned-message/pinned-message.tsx | 91 +++------- .../src/react-button/react-button.stories.tsx | 54 +----- .../src/react-button/react-button.tsx | 82 +++------ .../src/sidebar-members/sidebar-members.tsx | 4 +- packages/components/src/tabs/index.tsx | 1 + packages/components/src/tabs/tabs.stories.tsx | 72 ++++++++ packages/components/src/tabs/tabs.tsx | 164 ++++++++++++++++++ packages/components/src/text/text.stories.tsx | 6 +- packages/components/src/tooltip/tooltip.tsx | 19 +- packages/components/src/types.ts | 2 +- .../components/src/user-list/user-list.tsx | 2 +- yarn.lock | 15 ++ 26 files changed, 580 insertions(+), 348 deletions(-) create mode 100644 packages/components/src/messages/components/reactions-dialog.tsx create mode 100644 packages/components/src/tabs/index.tsx create mode 100644 packages/components/src/tabs/tabs.stories.tsx create mode 100644 packages/components/src/tabs/tabs.tsx diff --git a/apps/web/styles/reset.css b/apps/web/styles/reset.css index 71df37c9..4dc13e3e 100644 --- a/apps/web/styles/reset.css +++ b/apps/web/styles/reset.css @@ -71,6 +71,7 @@ button, textarea, select { font: inherit; + all: unset; } /* 8. Avoid text overflows diff --git a/packages/components/.storybook/reset.css b/packages/components/.storybook/reset.css index c793f03b..3d5db94d 100644 --- a/packages/components/.storybook/reset.css +++ b/packages/components/.storybook/reset.css @@ -71,6 +71,7 @@ button, textarea, select { font: inherit; + all: unset; } /* 8. Avoid text overflows diff --git a/packages/components/package.json b/packages/components/package.json index b2f97890..310c3279 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -32,6 +32,7 @@ "@radix-ui/react-dialog": "^1.0.3", "@radix-ui/react-dropdown-menu": "^2.0.4", "@radix-ui/react-popover": "^1.0.5", + "@radix-ui/react-tabs": "^1.0.3", "@radix-ui/react-tooltip": "^1.0.5", "@status-im/icons": "*", "@tamagui/animations-css": "1.7.7", diff --git a/packages/components/src/counter/counter.tsx b/packages/components/src/counter/counter.tsx index 89c4d514..a5965555 100644 --- a/packages/components/src/counter/counter.tsx +++ b/packages/components/src/counter/counter.tsx @@ -17,7 +17,7 @@ const Counter = (props: Props) => { return ( - + {value > 99 ? '99+' : value} @@ -31,7 +31,7 @@ const Base = styled(View, { backgroundColor: '$primary-50', paddingHorizontal: 3, paddingVertical: 0, - borderRadius: '6px', // TODO: use tokens when fixed its definition + borderRadius: 6, // TODO: use tokens when fixed its definition height: 16, minWidth: 16, maxWidth: 28, @@ -39,6 +39,8 @@ const Base = styled(View, { justifyContent: 'center', alignItems: 'center', flexBasis: 'fit-content', + borderWidth: 1, + borderColor: 'transparent', variants: { type: { @@ -54,13 +56,12 @@ const Base = styled(View, { outline: { backgroundColor: 'transparent', borderColor: '$neutral-20', - borderWidth: '1px', }, }, }, }) -const textColor: Record, ColorTokens> = { +const textColors: Record, ColorTokens> = { default: '$white-100', secondary: '$neutral-100', outline: '$neutral-100', diff --git a/packages/components/src/dialog/dialog.stories.tsx b/packages/components/src/dialog/dialog.stories.tsx index 32117f79..b616533f 100644 --- a/packages/components/src/dialog/dialog.stories.tsx +++ b/packages/components/src/dialog/dialog.stories.tsx @@ -24,7 +24,10 @@ export const Default: Story = { render: () => ( - test + + + test + ), } diff --git a/packages/components/src/dialog/dialog.tsx b/packages/components/src/dialog/dialog.tsx index fa7b6ba9..306dda0f 100644 --- a/packages/components/src/dialog/dialog.tsx +++ b/packages/components/src/dialog/dialog.tsx @@ -1,10 +1,15 @@ -import { forwardRef } from 'react' +import { cloneElement, forwardRef } from 'react' -import { Content, Overlay, Portal, Root, Trigger } from '@radix-ui/react-dialog' -import { Stack, styled, useMedia } from 'tamagui' - -import { Sheet } from '../sheet' +import { + Close, + Content, + Overlay, + Portal, + Root, + Trigger, +} from '@radix-ui/react-dialog' +import type { DialogTriggerProps } from '@radix-ui/react-dialog' import type { Ref } from 'react' import type React from 'react' @@ -15,74 +20,61 @@ interface Props { press?: 'normal' | 'long' } -const Wrapper = styled(Stack, { - position: 'absolute', - display: 'flex', - alignItems: 'center', - justifyContent: 'center', - width: '100vw', - height: '100vh', -}) - -// const DialogTrigger = ( -// props: DialogTriggerProps & { -// press: Props['press'] -// children: React.ReactElement -// } -// ) => { -// const { children, press, onClick, type, ...triggerProps } = props -// const handler = press === 'normal' ? 'onPress' : 'onLongPress' - -// // console.log('dialog', press, onClick, { ...triggerProps, [handler]: onClick }) -// return cloneElement(children, { ref, ...triggerProps, [handler]: onClick }) -// } - -// TODO: allow customization of press duration const Dialog = (props: Props) => { - const { children, open, onOpenChange /* press = 'normal' */ } = props + const { children, open, onOpenChange, press = 'normal' } = props const [trigger, content] = children - const media = useMedia() + // const media = useMedia() - if (media.sm) { - return ( - - {trigger} - {content} - - ) - } + // if (media.sm) { + // return ( + // + // {trigger} + // {content} + // + // ) + // } return ( {/* TRIGGER */} - {trigger} + + {trigger} + {/* CONTENT */} - - - {content} - + + {content} ) } +const PressableTrigger = forwardRef(function _PressableTrigger( + props: DialogTriggerProps & { + press: Props['press'] + children: React.ReactElement + }, + ref +) { + const { children, press, onClick, ...triggerProps } = props + const handler = press === 'normal' ? 'onPress' : 'onLongPress' + + return cloneElement(children, { ref, ...triggerProps, [handler]: onClick }) +}) + interface DialogContentProps { - // title: string - // description?: string children: React.ReactNode - // action: string - // onAction: (close: VoidFunction) => void - // onCancel?: () => void + borderRadius: 8 | 12 | 16 + width: number initialFocusRef?: React.RefObject } @@ -96,25 +88,25 @@ const DialogContent = (props: DialogContentProps, ref: Ref) => { } } - const media = useMedia() + // const media = useMedia() - if (media.sm) { - return {children} - } + // if (media.sm) { + // return {children} + // } return ( {children} @@ -124,4 +116,4 @@ const DialogContent = (props: DialogContentProps, ref: Ref) => { Dialog.Content = forwardRef(DialogContent) -export { Dialog } +export { Close, Dialog } diff --git a/packages/components/src/dialog/index.tsx b/packages/components/src/dialog/index.tsx index afbb355f..ac07eb6b 100644 --- a/packages/components/src/dialog/index.tsx +++ b/packages/components/src/dialog/index.tsx @@ -1 +1 @@ -export { Dialog } from './dialog' +export { Close, Dialog } from './dialog' diff --git a/packages/components/src/dynamic-button/dynamic-button.stories.tsx b/packages/components/src/dynamic-button/dynamic-button.stories.tsx index 1080c01c..5580129d 100644 --- a/packages/components/src/dynamic-button/dynamic-button.stories.tsx +++ b/packages/components/src/dynamic-button/dynamic-button.stories.tsx @@ -6,7 +6,6 @@ import type { Meta, StoryObj } from '@storybook/react' // More on how to set up stories at: https://storybook.js.org/docs/7.0/react/writing-stories/introduction const meta: Meta = { - title: 'DynamicButton', component: DynamicButton, args: {}, argTypes: {}, diff --git a/packages/components/src/dynamic-button/dynamic-button.tsx b/packages/components/src/dynamic-button/dynamic-button.tsx index 16b535db..090feb40 100644 --- a/packages/components/src/dynamic-button/dynamic-button.tsx +++ b/packages/components/src/dynamic-button/dynamic-button.tsx @@ -6,10 +6,9 @@ import { Stack, styled } from '@tamagui/core' import { Shadow } from '../shadow' import { Text } from '../text' -import type { GetVariants } from '../types' -import type { ColorTokens, StackProps } from '@tamagui/core' +import type { GetVariants, PressableProps } from '../types' +import type { ColorTokens } from '@tamagui/core' import type { Ref } from 'react' -import type { PressableProps } from 'react-native' type Variants = GetVariants @@ -27,7 +26,7 @@ const DynamicButton = (props: Props, ref: Ref) => { return ( reacted with {'[ICON]'} - + setDialogOpen(true)} + > + + You, Mr Gandalf, Ariana Perlona + + + + and + + + + 3 more + + + + reacted with + + {createElement(icon)} + + } > - - - - - - + + ) } diff --git a/packages/components/src/pinned-message/pinned-message.tsx b/packages/components/src/pinned-message/pinned-message.tsx index 1562342e..6903be37 100644 --- a/packages/components/src/pinned-message/pinned-message.tsx +++ b/packages/components/src/pinned-message/pinned-message.tsx @@ -1,13 +1,11 @@ -import { useState } from 'react' - import { CloseIcon, PinIcon } from '@status-im/icons/20' -import { styled } from '@tamagui/core' -import { Pressable, View } from 'react-native' +import { Stack } from '@tamagui/core' +import { Pressable } from 'react-native' import { Banner } from '../banner' import { Button } from '../button' import { ContextTag } from '../context-tag' -import { Dialog } from '../dialog' +import { Close, Dialog } from '../dialog' import { Message } from '../messages' import { Text } from '../text' @@ -19,78 +17,39 @@ type Props = { const PinnedMessage = (props: Props) => { const { messages } = props - const [isDetailVisible, setIsDetailVisible] = useState(false) - return messages.length > 0 ? ( - - setIsDetailVisible(true)}> + return ( + + }> {messages[0].text} - - - ) : null + ) } export { PinnedMessage } export type { Props as PinnedMessageProps } - -const Base = styled(View, { - position: 'relative', - paddingHorizontal: 16, - paddingVertical: 16, - borderRadius: 16, - alignSelf: 'center', - alignItems: 'flex-start', - maxWidth: 480, - backgroundColor: '$neutral-5', - zIndex: 100, - - variants: { - active: { - true: { - backgroundColor: '$neutral-5', - }, - }, - pinned: { - true: { - backgroundColor: '$blue-50-opa-5', - }, - }, - } as const, -}) - -const DialogHeader = styled(View, { - alignItems: 'flex-start', - justifyContent: 'flex-start', - paddingVertical: 16, - space: 11, -}) - -const DialogContent = styled(View, { - alignItems: 'stretch', - justifyContent: 'flex-start', -}) diff --git a/packages/components/src/react-button/react-button.stories.tsx b/packages/components/src/react-button/react-button.stories.tsx index b1c6e04b..3a8658b3 100644 --- a/packages/components/src/react-button/react-button.stories.tsx +++ b/packages/components/src/react-button/react-button.stories.tsx @@ -6,62 +6,24 @@ import type { Meta, StoryObj } from '@storybook/react' // More on how to set up stories at: https://storybook.js.org/docs/7.0/react/writing-stories/introduction const meta: Meta = { - title: 'ReactButton', component: ReactButton, args: {}, argTypes: {}, render: args => ( - - - - - - + + + + + + + ), } type Story = StoryObj -export const Outline: Story = { - name: 'Outline / 40px', - args: { variant: 'outline' }, -} - -export const OutlineSelected: Story = { - name: 'Outline / 40px / selected', - args: { variant: 'outline', selected: true }, -} - -export const Outline32: Story = { - name: 'Outline / 32px', - args: { variant: 'outline', size: 32 }, -} - -export const Outline32Selected: Story = { - name: 'Outline / 32px', - args: { variant: 'outline', size: 32, selected: true }, -} - -export const Ghost: Story = { - name: 'Ghost / 40px', - args: { variant: 'ghost' }, -} - -export const GhostSelected: Story = { - name: 'Ghost / 40px / selected', - args: { variant: 'ghost', selected: true }, -} - -export const Ghost32: Story = { - name: 'Ghost / 32px', - args: { variant: 'ghost', size: 32 }, -} - -export const Ghost32Selected: Story = { - name: 'Ghost / 32px', - args: { variant: 'ghost', size: 32, selected: true }, -} +export const Default: Story = {} export default meta diff --git a/packages/components/src/react-button/react-button.tsx b/packages/components/src/react-button/react-button.tsx index 7dde9eb8..2c2ebcfe 100644 --- a/packages/components/src/react-button/react-button.tsx +++ b/packages/components/src/react-button/react-button.tsx @@ -9,18 +9,16 @@ import { ThumbsDownIcon, ThumbsUpIcon, } from '@status-im/icons/reactions' -import { Stack, styled } from '@tamagui/core' +import { styled } from '@tamagui/core' +import { Stack } from '@tamagui/web' import { Text } from '../text' -import type { GetVariants } from '../types' -import type { StackProps } from '@tamagui/core' +import type { ReactionType } from '../messages/types' +import type { PressableProps } from '../types' import type { Ref } from 'react' -import type { PressableProps } from 'react-native' -type Variants = GetVariants - -export const REACTIONS = { +export const REACTIONS_ICONS = { love: LoveIcon, laugh: LaughIcon, 'thumbs-up': ThumbsUpIcon, @@ -31,10 +29,7 @@ export const REACTIONS = { } as const type Props = PressableProps & { - icon: keyof typeof REACTIONS - variant?: Variants['variant'] - size?: Variants['size'] - // FIXME: use aria-selected + type: ReactionType selected?: boolean count?: number // FIXME: update to latest RN @@ -43,25 +38,17 @@ type Props = PressableProps & { } const ReactButton = (props: Props, ref: Ref) => { - const { - icon, - variant = 'outline', - size = 40, - count, - ...pressableProps - } = props + const { type, count, ...pressableProps } = props - const Icon = REACTIONS[icon] + const Icon = REACTIONS_ICONS[type] const selected = props.selected || props['aria-expanded'] || props['aria-selected'] return (