Add more components, message actions & reactions (#339)
* hide sidebar on small screen * add reply component * add radix dependencies * add dropdown menu component * add popover component * add tooltip component * add react button component * add reaction popover * update chat message actions * add basic dialog and sheet components * add ref to Button component * add chat message reactions * add reply and reactions to chat message * remove console.log * add dropdown menu to topbar * add ref and support aria in IconButton * yarn.lock * add stylesheet reset to storybook * add pinned state to message * remove extraneous component * add all button variants * fix button icons * use IconButton in actions * remove erroneous character * add reply to composer + simplify * use correct button in reply
This commit is contained in:
parent
a5fdd22d51
commit
84ec492292
|
@ -88,12 +88,9 @@ function App() {
|
|||
<Messages />
|
||||
</div>
|
||||
|
||||
<Composer
|
||||
backgroundColor="$blurBackground"
|
||||
paddingBottom={56}
|
||||
isBlurred={shouldBlurBottom}
|
||||
style={{ marginTop: -112 }}
|
||||
/>
|
||||
<div id="composer">
|
||||
<Composer isBlurred={shouldBlurBottom} reply={false} />
|
||||
</div>
|
||||
</main>
|
||||
<AnimatePresence enterVariant="fromRight" exitVariant="fromLeft">
|
||||
{showMembers && (
|
||||
|
|
|
@ -17,6 +17,7 @@ body,
|
|||
}
|
||||
|
||||
#main {
|
||||
position: relative;
|
||||
display: grid;
|
||||
grid-template-rows: 56px 1fr 100px;
|
||||
height: 100vh;
|
||||
|
@ -45,7 +46,24 @@ body,
|
|||
margin-top: -56px;
|
||||
}
|
||||
|
||||
#composer {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
#members {
|
||||
width: 352px;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 768px) {
|
||||
#app {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
#sidebar {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,8 @@ import { TamaguiProvider } from '@tamagui/core'
|
|||
import { config } from '../src'
|
||||
import { Parameters, Decorator } from '@storybook/react'
|
||||
|
||||
import './reset.css'
|
||||
|
||||
export const parameters: Parameters = {
|
||||
actions: { argTypesRegex: '^on[A-Z].*' },
|
||||
controls: {
|
||||
|
|
|
@ -0,0 +1,100 @@
|
|||
/*
|
||||
1. Use a more-intuitive box-sizing model.
|
||||
*/
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:root {
|
||||
font-family: Inter, Avenir, Helvetica, Arial, sans-serif;
|
||||
font-size: 16px;
|
||||
line-height: 24px;
|
||||
font-weight: 400;
|
||||
|
||||
color-scheme: light dark;
|
||||
color: rgba(255, 255, 255, 0.87);
|
||||
background-color: #fff;
|
||||
|
||||
font-synthesis: none;
|
||||
text-rendering: optimizeLegibility;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
-webkit-text-size-adjust: 100%;
|
||||
}
|
||||
|
||||
/*
|
||||
2. Remove default margin
|
||||
*/
|
||||
* {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/*
|
||||
3. Allow percentage-based heights in the application
|
||||
*/
|
||||
html,
|
||||
body {
|
||||
height: 100vh;
|
||||
width: 100vw;
|
||||
overflow: hidden;
|
||||
overscroll-behavior-y: none; /* not working on Safari */
|
||||
}
|
||||
/*
|
||||
Typographic tweaks!
|
||||
4. Add accessible line-height
|
||||
5. Improve text rendering
|
||||
*/
|
||||
body {
|
||||
line-height: 1.5;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
padding: 0;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
/*
|
||||
6. Improve media defaults
|
||||
*/
|
||||
img,
|
||||
picture,
|
||||
video,
|
||||
canvas,
|
||||
svg {
|
||||
display: block;
|
||||
max-width: 100%;
|
||||
}
|
||||
/*
|
||||
7. Remove built-in form typography styles
|
||||
*/
|
||||
input,
|
||||
button,
|
||||
textarea,
|
||||
select {
|
||||
font: inherit;
|
||||
}
|
||||
/*
|
||||
8. Avoid text overflows
|
||||
*/
|
||||
p,
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
overflow-wrap: break-word;
|
||||
}
|
||||
/*
|
||||
9. Create a root stacking context
|
||||
*/
|
||||
#root,
|
||||
#__next {
|
||||
isolation: isolate;
|
||||
}
|
||||
|
||||
/*
|
||||
10. Remove user selection on buttons
|
||||
*/
|
||||
button {
|
||||
user-select: none;
|
||||
}
|
|
@ -22,6 +22,9 @@
|
|||
"react-native-web": "^0.18.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@radix-ui/react-dropdown-menu": "^2.0.2",
|
||||
"@radix-ui/react-popover": "^1.0.3",
|
||||
"@radix-ui/react-tooltip": "^1.0.3",
|
||||
"@status-im/icons": "*",
|
||||
"@tamagui/animations-css": "1.0.15",
|
||||
"@tamagui/animations-react-native": "1.0.15",
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
import { action } from '@storybook/addon-actions'
|
||||
import { Stack } from 'tamagui'
|
||||
|
||||
import { Button } from './button'
|
||||
|
||||
import type { Meta, StoryObj } from '@storybook/react'
|
||||
|
@ -5,18 +8,25 @@ 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<typeof Button> = {
|
||||
component: Button,
|
||||
argTypes: {},
|
||||
args: {
|
||||
onPress: action('press'),
|
||||
},
|
||||
argTypes: {
|
||||
disabled: {
|
||||
defaultValue: false,
|
||||
},
|
||||
},
|
||||
decorators: [
|
||||
Story => (
|
||||
<Stack alignItems="flex-start">
|
||||
<Story />
|
||||
</Stack>
|
||||
),
|
||||
],
|
||||
}
|
||||
|
||||
type Story = StoryObj<typeof Button>
|
||||
|
||||
// More on writing stories with args: https://storybook.js.org/docs/7.0/react/writing-stories/args
|
||||
export const Primary: Story = {
|
||||
args: {
|
||||
children: 'Click me',
|
||||
},
|
||||
}
|
||||
|
||||
const icon = (
|
||||
<svg
|
||||
width="20"
|
||||
|
@ -34,14 +44,43 @@ const icon = (
|
|||
</svg>
|
||||
)
|
||||
|
||||
// More on writing stories with args: https://storybook.js.org/docs/7.0/react/writing-stories/args
|
||||
export const Primary: Story = {
|
||||
args: {
|
||||
children: 'Click me',
|
||||
},
|
||||
}
|
||||
|
||||
export const PrimaryDisabled: Story = {
|
||||
args: {
|
||||
children: 'Click me',
|
||||
disabled: true,
|
||||
},
|
||||
}
|
||||
|
||||
export const PrimaryFullWidth: Story = {
|
||||
args: {
|
||||
children: 'Click me',
|
||||
width: 'full',
|
||||
},
|
||||
}
|
||||
|
||||
export const Primary32: Story = {
|
||||
name: 'Primary/32px',
|
||||
name: 'Primary / 32',
|
||||
args: {
|
||||
size: 32,
|
||||
children: 'Click me',
|
||||
},
|
||||
}
|
||||
|
||||
export const Primary24: Story = {
|
||||
name: 'Primary / 24',
|
||||
args: {
|
||||
size: 24,
|
||||
children: 'Click me',
|
||||
},
|
||||
}
|
||||
|
||||
export const PrimaryIconBefore: Story = {
|
||||
name: 'Primary icon before',
|
||||
args: {
|
||||
|
@ -85,4 +124,11 @@ export const Ghost: Story = {
|
|||
},
|
||||
}
|
||||
|
||||
export const Danger: Story = {
|
||||
args: {
|
||||
type: 'danger',
|
||||
children: 'Click me',
|
||||
},
|
||||
}
|
||||
|
||||
export default meta
|
||||
|
|
|
@ -1,24 +1,29 @@
|
|||
import { forwardRef } from 'react'
|
||||
|
||||
import { Stack, styled } from '@tamagui/core'
|
||||
|
||||
import { Paragraph } from '../typography'
|
||||
|
||||
import type { GetProps } from '@tamagui/core'
|
||||
// import { Pressable } from 'react-native'
|
||||
import type { Ref } from 'react'
|
||||
|
||||
const Base = styled(Stack, {
|
||||
name: 'Button',
|
||||
accessibilityRole: 'button',
|
||||
|
||||
borderRadius: 12,
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
paddingHorizontal: 16,
|
||||
paddingTop: 7,
|
||||
paddingBottom: 9,
|
||||
cursor: 'pointer',
|
||||
|
||||
alignItems: 'center',
|
||||
animation: 'fast',
|
||||
cursor: 'pointer',
|
||||
userSelect: 'none',
|
||||
animation: 'fast',
|
||||
borderWidth: 1,
|
||||
borderColor: 'transparent',
|
||||
|
||||
variants: {
|
||||
type: {
|
||||
|
@ -28,9 +33,19 @@ const Base = styled(Stack, {
|
|||
pressStyle: { backgroundColor: '$primaryHover' },
|
||||
},
|
||||
positive: {
|
||||
backgroundColor: '$success',
|
||||
hoverStyle: { backgroundColor: '$successHover' },
|
||||
pressStyle: { backgroundColor: '$successHover' },
|
||||
backgroundColor: '$success-50',
|
||||
hoverStyle: { backgroundColor: '$success-60' },
|
||||
pressStyle: { backgroundColor: '$success-50' },
|
||||
},
|
||||
grey: {
|
||||
backgroundColor: '$neutral-10',
|
||||
hoverStyle: { backgroundColor: '$neutral-20' },
|
||||
pressStyle: { backgroundColor: '$neutral-30' },
|
||||
},
|
||||
darkGrey: {
|
||||
backgroundColor: '$neutral-20',
|
||||
hoverStyle: { backgroundColor: '$neutral-30' },
|
||||
pressStyle: { backgroundColor: '$neutral-40' },
|
||||
},
|
||||
outline: {
|
||||
borderWidth: 1,
|
||||
|
@ -43,23 +58,47 @@ const Base = styled(Stack, {
|
|||
hoverStyle: { backgroundColor: '$neutral-10' },
|
||||
pressStyle: { backgroundColor: '$neutral-20' },
|
||||
},
|
||||
danger: {
|
||||
backgroundColor: '$danger',
|
||||
hoverStyle: { backgroundColor: '$danger-60' },
|
||||
pressStyle: { backgroundColor: '$danger' },
|
||||
},
|
||||
},
|
||||
|
||||
disabled: {
|
||||
true: {
|
||||
opacity: 0.3,
|
||||
cursor: 'default',
|
||||
},
|
||||
},
|
||||
|
||||
size: {
|
||||
40: {
|
||||
minHeight: 40,
|
||||
borderRadius: 12,
|
||||
paddingHorizontal: 16,
|
||||
paddingTop: 7,
|
||||
paddingBottom: 9,
|
||||
},
|
||||
32: {
|
||||
minHeight: 32,
|
||||
borderRadius: 10,
|
||||
paddingHorizontal: 16,
|
||||
paddingTop: 4,
|
||||
paddingBottom: 6,
|
||||
},
|
||||
24: {
|
||||
minHeight: 24,
|
||||
borderRadius: 8,
|
||||
paddingHorizontal: 8,
|
||||
paddingTop: 2,
|
||||
paddingBottom: 4,
|
||||
},
|
||||
},
|
||||
|
||||
iconOnly: {
|
||||
true: {
|
||||
space: 0,
|
||||
paddingHorizontal: 8,
|
||||
},
|
||||
},
|
||||
|
@ -67,11 +106,10 @@ const Base = styled(Stack, {
|
|||
})
|
||||
|
||||
const ButtonText = styled(Paragraph, {
|
||||
textAlign: 'center',
|
||||
weight: 'medium',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
space: 4,
|
||||
weight: 'medium',
|
||||
|
||||
variants: {
|
||||
type: {
|
||||
|
@ -81,12 +119,33 @@ const ButtonText = styled(Paragraph, {
|
|||
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',
|
||||
},
|
||||
32: {
|
||||
variant: 'normal',
|
||||
},
|
||||
24: {
|
||||
variant: 'smaller',
|
||||
},
|
||||
},
|
||||
} as const,
|
||||
})
|
||||
|
@ -95,19 +154,18 @@ type BaseProps = GetProps<typeof Base>
|
|||
|
||||
type Props = BaseProps & {
|
||||
children?: string
|
||||
icon?: React.ReactNode
|
||||
type?: BaseProps['type']
|
||||
size?: BaseProps['size']
|
||||
disabled?: boolean
|
||||
icon?: React.ReactNode
|
||||
iconAfter?: React.ReactNode
|
||||
onPress?: () => void
|
||||
}
|
||||
|
||||
const Button = (props: Props) => {
|
||||
const Button = (props: Props, ref: Ref<HTMLButtonElement>) => {
|
||||
const {
|
||||
type = 'primary',
|
||||
size = 40,
|
||||
children,
|
||||
onPress,
|
||||
icon,
|
||||
iconAfter,
|
||||
...rest
|
||||
|
@ -116,14 +174,8 @@ const Button = (props: Props) => {
|
|||
const iconOnly = !children && Boolean(icon)
|
||||
|
||||
return (
|
||||
<Base
|
||||
{...rest}
|
||||
type={type}
|
||||
size={size}
|
||||
iconOnly={iconOnly}
|
||||
onPress={onPress}
|
||||
>
|
||||
<ButtonText type={type}>
|
||||
<Base {...rest} ref={ref} type={type} size={size} iconOnly={iconOnly}>
|
||||
<ButtonText type={type} size={size}>
|
||||
{icon}
|
||||
{children}
|
||||
{iconAfter}
|
||||
|
@ -132,5 +184,7 @@ const Button = (props: Props) => {
|
|||
)
|
||||
}
|
||||
|
||||
export { Button }
|
||||
const _Button = forwardRef(Button)
|
||||
|
||||
export { _Button as Button }
|
||||
export type { Props as ButtonProps }
|
||||
|
|
|
@ -1 +1 @@
|
|||
export { Button } from './button'
|
||||
export { type ButtonProps, Button } from './button'
|
||||
|
|
|
@ -11,30 +11,19 @@ import { Stack, XStack, YStack } from 'tamagui'
|
|||
|
||||
import { IconButton } from '../icon-button'
|
||||
import { Input } from '../input'
|
||||
import { Reply } from '../reply'
|
||||
|
||||
import type { GetProps } from '@tamagui/core'
|
||||
import type { ViewProps } from 'react-native'
|
||||
|
||||
type BaseProps = GetProps<typeof YStack>
|
||||
|
||||
const Composer = (
|
||||
props: Omit<BaseProps, 'style'> & {
|
||||
placeholderTextColor?: BaseProps['backgroundColor']
|
||||
iconOptionsColor?: BaseProps['backgroundColor']
|
||||
isBlurred?: boolean
|
||||
style?: ViewProps['style']
|
||||
interface Props {
|
||||
isBlurred: boolean
|
||||
reply: boolean
|
||||
}
|
||||
) => {
|
||||
const { backgroundColor, isBlurred, style: styleFromProps, ...rest } = props
|
||||
const style = styleFromProps ? Object.assign(styleFromProps) : {}
|
||||
|
||||
const Composer = (props: Props) => {
|
||||
const { isBlurred, reply } = props
|
||||
|
||||
const [isFocused, setIsFocused] = useState(false)
|
||||
|
||||
const applyVariantStyles:
|
||||
| {
|
||||
blurred: boolean
|
||||
}
|
||||
| undefined = isBlurred && !isFocused ? { blurred: true } : undefined
|
||||
const iconButtonBlurred = isBlurred && !isFocused
|
||||
|
||||
return (
|
||||
<BlurView
|
||||
|
@ -42,25 +31,35 @@ const Composer = (
|
|||
style={{
|
||||
zIndex: 100,
|
||||
borderRadius: 20,
|
||||
...style,
|
||||
}}
|
||||
>
|
||||
<YStack
|
||||
animation="fast"
|
||||
backgroundColor={isFocused ? '$background' : backgroundColor}
|
||||
backgroundColor={isFocused ? '$background' : '$blurBackground'}
|
||||
shadowColor={!isBlurred || isFocused ? 'rgba(9, 16, 28, 0.08)' : 'none'}
|
||||
shadowOffset={{ width: 4, height: !isBlurred || isFocused ? 4 : 0 }}
|
||||
shadowRadius={20}
|
||||
borderTopLeftRadius={20}
|
||||
borderTopRightRadius={20}
|
||||
px={16}
|
||||
pt={8}
|
||||
width="100%"
|
||||
py={12}
|
||||
style={{
|
||||
elevation: 10,
|
||||
}}
|
||||
{...rest}
|
||||
>
|
||||
{reply && (
|
||||
<Stack paddingLeft={4} paddingBottom={4}>
|
||||
<Reply
|
||||
type="text"
|
||||
name="Alisher"
|
||||
src="https://images.unsplash.com/photo-1524638431109-93d95c968f03?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=500&ixid=MnwxfDB8MXxyYW5kb218MHx8Z2lybHx8fHx8fDE2NzM4ODQ0NzU&ixlib=rb-4.0.3&q=80&utm_campaign=api-credit&utm_medium=referral&utm_source=unsplash_source&w=500"
|
||||
onClose={() => {
|
||||
console.log('close')
|
||||
}}
|
||||
/>
|
||||
</Stack>
|
||||
)}
|
||||
|
||||
<Input
|
||||
className="composer-input"
|
||||
placeholder="Type something..."
|
||||
|
@ -70,35 +69,35 @@ const Composer = (
|
|||
onBlur={() => setIsFocused(false)}
|
||||
onFocus={() => setIsFocused(true)}
|
||||
/>
|
||||
|
||||
<XStack
|
||||
alignItems="center"
|
||||
justifyContent="space-between"
|
||||
pt={8}
|
||||
paddingTop={12}
|
||||
backgroundColor="transparent"
|
||||
>
|
||||
<Stack space={12} flexDirection="row" backgroundColor="transparent">
|
||||
<IconButton
|
||||
variant="outline"
|
||||
icon={<ImageIcon />}
|
||||
{...applyVariantStyles}
|
||||
selected
|
||||
blurred={iconButtonBlurred}
|
||||
/>
|
||||
<IconButton
|
||||
variant="outline"
|
||||
icon={<ReactionIcon />}
|
||||
{...applyVariantStyles}
|
||||
blurred={iconButtonBlurred}
|
||||
/>
|
||||
<IconButton
|
||||
variant="outline"
|
||||
icon={<FormatIcon />}
|
||||
disabled
|
||||
{...applyVariantStyles}
|
||||
blurred={iconButtonBlurred}
|
||||
/>
|
||||
</Stack>
|
||||
<IconButton
|
||||
variant="outline"
|
||||
icon={<AudioIcon />}
|
||||
{...applyVariantStyles}
|
||||
blurred={iconButtonBlurred}
|
||||
/>
|
||||
</XStack>
|
||||
</YStack>
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
import { Button } from '../button'
|
||||
import { Dialog } from './dialog'
|
||||
|
||||
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<typeof Dialog> = {
|
||||
title: 'Web/Dialog',
|
||||
// component: Sheet,
|
||||
argTypes: {},
|
||||
parameters: {
|
||||
design: {
|
||||
type: 'figma',
|
||||
url: 'https://www.figma.com/file/IBmFKgGL1B4GzqD8LQTw6n/Design-System-for-Web?node-id=611%3A36006&t=Gyy71OAckl3b2TWj-4',
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
type Story = StoryObj<typeof Dialog>
|
||||
|
||||
// More on writing stories with args: https://storybook.js.org/docs/7.0/react/writing-stories/args
|
||||
export const Default: Story = {
|
||||
args: {},
|
||||
render: () => (
|
||||
<Dialog>
|
||||
<Button>Trigger</Button>
|
||||
<Dialog.Content>test</Dialog.Content>
|
||||
</Dialog>
|
||||
),
|
||||
}
|
||||
|
||||
export default meta
|
|
@ -0,0 +1,116 @@
|
|||
import { forwardRef } from 'react'
|
||||
|
||||
import { Content, Overlay, Portal, Root, Trigger } from '@radix-ui/react-dialog'
|
||||
import { useMedia } from 'tamagui'
|
||||
|
||||
import { Sheet } from '../sheet'
|
||||
|
||||
import type { Ref } from 'react'
|
||||
import type React from 'react'
|
||||
|
||||
interface Props {
|
||||
children: [React.ReactElement, React.ReactElement]
|
||||
open?: boolean
|
||||
onOpenChange?: (open: boolean) => void
|
||||
press?: 'normal' | 'long'
|
||||
}
|
||||
|
||||
// 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 [trigger, content] = children
|
||||
|
||||
const media = useMedia()
|
||||
|
||||
if (media.sm) {
|
||||
return (
|
||||
<Sheet>
|
||||
{trigger}
|
||||
{content}
|
||||
</Sheet>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<Root open={open} onOpenChange={onOpenChange}>
|
||||
{/* TRIGGER */}
|
||||
<Trigger asChild>{trigger}</Trigger>
|
||||
|
||||
{/* CONTENT */}
|
||||
<Portal>
|
||||
<Overlay
|
||||
style={{
|
||||
position: 'fixed',
|
||||
inset: 0,
|
||||
backgroundColor: 'rgba(0,0,0,0.5)',
|
||||
}}
|
||||
/>
|
||||
{content}
|
||||
</Portal>
|
||||
</Root>
|
||||
)
|
||||
}
|
||||
|
||||
interface DialogContentProps {
|
||||
// title: string
|
||||
// description?: string
|
||||
children: React.ReactNode
|
||||
// action: string
|
||||
// onAction: (close: VoidFunction) => void
|
||||
// onCancel?: () => void
|
||||
initialFocusRef?: React.RefObject<HTMLElement>
|
||||
}
|
||||
|
||||
const DialogContent = (props: DialogContentProps, ref: Ref<HTMLDivElement>) => {
|
||||
const { children, initialFocusRef } = props
|
||||
|
||||
const handleOpenAutoFocus = (event: Event) => {
|
||||
if (initialFocusRef?.current) {
|
||||
event.preventDefault()
|
||||
initialFocusRef.current.focus()
|
||||
}
|
||||
}
|
||||
|
||||
const media = useMedia()
|
||||
|
||||
if (media.sm) {
|
||||
return <Sheet.Content>{children}</Sheet.Content>
|
||||
}
|
||||
|
||||
return (
|
||||
<Content
|
||||
ref={ref}
|
||||
onOpenAutoFocus={handleOpenAutoFocus}
|
||||
style={{
|
||||
backgroundColor: 'white',
|
||||
padding: 8,
|
||||
width: 400,
|
||||
borderRadius: 8,
|
||||
position: 'fixed',
|
||||
top: '50%',
|
||||
left: '50%',
|
||||
transform: 'translate(-50%, -50%)',
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</Content>
|
||||
)
|
||||
}
|
||||
|
||||
Dialog.Content = forwardRef(DialogContent)
|
||||
|
||||
export { Dialog }
|
|
@ -0,0 +1 @@
|
|||
export { Dialog } from './dialog'
|
|
@ -0,0 +1,85 @@
|
|||
import {
|
||||
CopyIcon,
|
||||
DeleteIcon,
|
||||
EditIcon,
|
||||
ForwardIcon,
|
||||
LinkIcon,
|
||||
PinIcon,
|
||||
ReplyIcon,
|
||||
} from '@status-im/icons/20'
|
||||
import { action } from '@storybook/addon-actions'
|
||||
|
||||
import { Button } from '../button'
|
||||
import { DropdownMenu } from './dropdown-menu'
|
||||
|
||||
import type { Meta, StoryObj } from '@storybook/react'
|
||||
|
||||
const meta: Meta<typeof DropdownMenu> = {
|
||||
title: 'Web/dropdown menu',
|
||||
component: DropdownMenu,
|
||||
argTypes: {},
|
||||
parameters: {
|
||||
design: {
|
||||
type: 'figma',
|
||||
url: 'https://www.figma.com/file/IBmFKgGL1B4GzqD8LQTw6n/Design-System-for-Web?node-id=1931%3A31188&t=rOKELbVkzya48FJE-0',
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
type Story = StoryObj<typeof DropdownMenu>
|
||||
|
||||
export const Default: Story = {
|
||||
args: {},
|
||||
|
||||
render: args => {
|
||||
return (
|
||||
<DropdownMenu {...args}>
|
||||
<Button>Open</Button>
|
||||
|
||||
<DropdownMenu.Content sideOffset={10}>
|
||||
<DropdownMenu.Item
|
||||
icon={<EditIcon />}
|
||||
label="Edit message"
|
||||
onSelect={action('edit')}
|
||||
/>
|
||||
<DropdownMenu.Item
|
||||
icon={<ReplyIcon />}
|
||||
label="Reply"
|
||||
onSelect={action('reply')}
|
||||
/>
|
||||
<DropdownMenu.Item
|
||||
icon={<CopyIcon />}
|
||||
label="Copy text"
|
||||
onSelect={action('copy')}
|
||||
/>
|
||||
<DropdownMenu.Item
|
||||
icon={<PinIcon />}
|
||||
label="Pin to the channel"
|
||||
onSelect={action('pin')}
|
||||
/>
|
||||
<DropdownMenu.Item
|
||||
icon={<ForwardIcon />}
|
||||
label="Forward"
|
||||
onSelect={action('forward')}
|
||||
/>
|
||||
<DropdownMenu.Item
|
||||
icon={<LinkIcon />}
|
||||
label="Share link to message"
|
||||
onSelect={action('share')}
|
||||
/>
|
||||
|
||||
<DropdownMenu.Separator />
|
||||
|
||||
<DropdownMenu.Item
|
||||
icon={<DeleteIcon />}
|
||||
label="Delete message"
|
||||
danger
|
||||
onSelect={action('delete')}
|
||||
/>
|
||||
</DropdownMenu.Content>
|
||||
</DropdownMenu>
|
||||
)
|
||||
},
|
||||
}
|
||||
|
||||
export default meta
|
|
@ -0,0 +1,108 @@
|
|||
import { cloneElement } from 'react'
|
||||
|
||||
import {
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem as RadixDropdownMenuItem,
|
||||
DropdownMenuSeparator,
|
||||
// Label,
|
||||
Portal,
|
||||
Root,
|
||||
Trigger,
|
||||
} from '@radix-ui/react-dropdown-menu'
|
||||
import { Stack, styled } from 'tamagui'
|
||||
|
||||
import { Paragraph } from '../typography'
|
||||
|
||||
const Content = styled(DropdownMenuContent, {
|
||||
name: 'DropdownMenuContent',
|
||||
acceptsClassName: true,
|
||||
|
||||
width: 352,
|
||||
padding: 8,
|
||||
borderRadius: 16,
|
||||
backgroundColor: '$white-100',
|
||||
|
||||
shadowRadius: 30,
|
||||
shadowOffset: '0px 8px',
|
||||
shadowColor: 'rgba(9, 16, 28, 0.12)',
|
||||
})
|
||||
|
||||
const Item = styled(RadixDropdownMenuItem, {
|
||||
name: 'DropdownMenuItem',
|
||||
acceptsClassName: true,
|
||||
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
padding: 8,
|
||||
borderRadius: 12,
|
||||
cursor: 'pointer',
|
||||
userSelect: 'none',
|
||||
|
||||
hoverStyle: {
|
||||
backgroundColor: '$neutral-5',
|
||||
},
|
||||
|
||||
pressStyle: {
|
||||
backgroundColor: '$neutral-10',
|
||||
},
|
||||
})
|
||||
|
||||
const Separator = styled(DropdownMenuSeparator, {
|
||||
name: 'DropdownMenuSeparator',
|
||||
acceptsClassName: true,
|
||||
|
||||
height: 1,
|
||||
backgroundColor: '$neutral-10',
|
||||
marginVertical: 8,
|
||||
marginLeft: -8,
|
||||
marginRight: -8,
|
||||
})
|
||||
|
||||
interface Props {
|
||||
children: [React.ReactElement, React.ReactElement]
|
||||
modal?: false
|
||||
onOpenChange?: (open: boolean) => void
|
||||
}
|
||||
|
||||
const DropdownMenu = (props: Props) => {
|
||||
const { children, onOpenChange, modal } = props
|
||||
|
||||
const [trigger, content] = children
|
||||
|
||||
return (
|
||||
<Root onOpenChange={onOpenChange} modal={modal}>
|
||||
<Trigger asChild>{trigger}</Trigger>
|
||||
<Portal>{content}</Portal>
|
||||
</Root>
|
||||
)
|
||||
}
|
||||
|
||||
interface DropdownMenuItemProps {
|
||||
icon: React.ReactElement
|
||||
label: string
|
||||
onSelect: () => void
|
||||
danger?: boolean
|
||||
}
|
||||
|
||||
const DropdownMenuItem = (props: DropdownMenuItemProps) => {
|
||||
const { icon, label, onSelect, danger } = props
|
||||
|
||||
const iconColor = danger ? '$danger-50' : '$neutral-50'
|
||||
const textColor = danger ? '$danger-50' : '$neutral-100'
|
||||
|
||||
return (
|
||||
<Item onSelect={onSelect}>
|
||||
<Stack marginRight={12}>{cloneElement(icon, { color: iconColor })}</Stack>
|
||||
<Paragraph weight="medium" color={textColor}>
|
||||
{label}
|
||||
</Paragraph>
|
||||
</Item>
|
||||
)
|
||||
}
|
||||
|
||||
DropdownMenu.Content = Content
|
||||
DropdownMenu.Item = DropdownMenuItem
|
||||
DropdownMenu.Separator = Separator
|
||||
|
||||
export { DropdownMenu }
|
||||
export type { Props as DropdownMenuProps }
|
|
@ -0,0 +1 @@
|
|||
export { DropdownMenu } from './dropdown-menu'
|
|
@ -1,8 +1,8 @@
|
|||
import { cloneElement } from 'react'
|
||||
import { cloneElement, forwardRef } from 'react'
|
||||
|
||||
import { Stack, styled } from '@tamagui/core'
|
||||
|
||||
import type React from 'react'
|
||||
import type { Ref } from 'react'
|
||||
|
||||
const Base = styled(Stack, {
|
||||
name: 'IconButton',
|
||||
|
@ -108,6 +108,9 @@ interface Props {
|
|||
disabled?: boolean
|
||||
// FIXME: enforce aria-label for accessibility
|
||||
// 'aria-label'?: string
|
||||
// FIXME: update to latest RN
|
||||
'aria-expanded'?: boolean
|
||||
'aria-selected'?: boolean
|
||||
}
|
||||
|
||||
const iconColor = {
|
||||
|
@ -165,26 +168,22 @@ const getSelectedVariant = ({
|
|||
return variant
|
||||
}
|
||||
|
||||
const IconButton = (props: Props) => {
|
||||
const {
|
||||
icon,
|
||||
selected,
|
||||
blurred,
|
||||
onPress,
|
||||
variant = 'default',
|
||||
disabled,
|
||||
} = props
|
||||
const IconButton = (props: Props, ref: Ref<HTMLButtonElement>) => {
|
||||
const { icon, blurred, variant = 'default', ...rest } = props
|
||||
|
||||
const selected =
|
||||
props.selected || props['aria-expanded'] || props['aria-selected']
|
||||
|
||||
const state = getStateForIconColor({ blurred, selected })
|
||||
const selectedVariant = getSelectedVariant({ selected, variant, blurred })
|
||||
|
||||
return (
|
||||
<Base
|
||||
{...rest}
|
||||
ref={ref}
|
||||
variant={variant}
|
||||
selected={selectedVariant}
|
||||
onPress={onPress}
|
||||
blurred={blurred ? variant : undefined}
|
||||
disabled={disabled}
|
||||
>
|
||||
{cloneElement(icon, {
|
||||
color: iconColor[variant][state],
|
||||
|
@ -194,5 +193,7 @@ const IconButton = (props: Props) => {
|
|||
)
|
||||
}
|
||||
|
||||
export { IconButton }
|
||||
const _IconButton = forwardRef(IconButton)
|
||||
|
||||
export { _IconButton as IconButton }
|
||||
export type { Props as IconButtonProps }
|
||||
|
|
|
@ -24,7 +24,7 @@ export const InputFrame = styled(
|
|||
|
||||
backgroundColor: 'transparent',
|
||||
|
||||
height: 40,
|
||||
height: 32,
|
||||
borderRadius: 12,
|
||||
|
||||
animation: 'fast',
|
||||
|
|
|
@ -1,89 +0,0 @@
|
|||
import React from 'react'
|
||||
|
||||
import { Stack, Unspaced, XStack, YStack } from 'tamagui'
|
||||
|
||||
import { Author } from '../author/author'
|
||||
import { Avatar } from '../avatar'
|
||||
import { Image } from '../image'
|
||||
import { Paragraph } from '../typography'
|
||||
import { Actions } from './components/actions'
|
||||
import { Reactions } from './components/reactions'
|
||||
|
||||
interface Props {
|
||||
text?: React.ReactNode
|
||||
images?: Array<{ url: string }>
|
||||
reactions?: []
|
||||
}
|
||||
|
||||
const ChatMessage = (props: Props) => {
|
||||
const { text, images, reactions } = props
|
||||
|
||||
const [hovered, setHovered] = React.useState(false)
|
||||
|
||||
return (
|
||||
<XStack
|
||||
space={10}
|
||||
position="relative"
|
||||
alignItems="flex-start"
|
||||
paddingHorizontal={8}
|
||||
paddingVertical={12}
|
||||
borderRadius={16}
|
||||
hoverStyle={{
|
||||
backgroundColor: '$neutral-5',
|
||||
}}
|
||||
onHoverIn={() => setHovered(true)}
|
||||
onHoverOut={() => setHovered(false)}
|
||||
>
|
||||
{hovered && (
|
||||
<Unspaced>
|
||||
<Actions
|
||||
onClick={() => {
|
||||
console.log('clicked')
|
||||
}}
|
||||
/>
|
||||
</Unspaced>
|
||||
)}
|
||||
|
||||
<Avatar
|
||||
size={32}
|
||||
src="https://images.unsplash.com/photo-1524638431109-93d95c968f03?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=500&ixid=MnwxfDB8MXxyYW5kb218MHx8Z2lybHx8fHx8fDE2NzM4ODQ0NzU&ixlib=rb-4.0.3&q=80&utm_campaign=api-credit&utm_medium=referral&utm_source=unsplash_source&w=500"
|
||||
indicator="online"
|
||||
/>
|
||||
|
||||
<YStack flex={1}>
|
||||
<Author
|
||||
name="Alisher Yakupov"
|
||||
address="zQ3...9d4Gs0"
|
||||
status="verified"
|
||||
time="09:30"
|
||||
/>
|
||||
|
||||
{text && (
|
||||
<Paragraph flexGrow={0} weight="regular" color="$neutral-100">
|
||||
{text}
|
||||
</Paragraph>
|
||||
)}
|
||||
|
||||
{images?.map(image => (
|
||||
<Stack
|
||||
key={image.url}
|
||||
marginTop={8}
|
||||
$gtMd={{
|
||||
maxWidth: 320,
|
||||
}}
|
||||
>
|
||||
<Image src={image.url} width="full" height={320} radius={12} />
|
||||
</Stack>
|
||||
))}
|
||||
|
||||
{reactions && (
|
||||
<Stack marginTop={8}>
|
||||
<Reactions />
|
||||
</Stack>
|
||||
)}
|
||||
</YStack>
|
||||
</XStack>
|
||||
)
|
||||
}
|
||||
|
||||
export { ChatMessage }
|
|
@ -1,11 +1,21 @@
|
|||
import { Actions } from './actions'
|
||||
|
||||
import type { ReactionsType } from '../types'
|
||||
import type { Meta, StoryObj } from '@storybook/react'
|
||||
|
||||
const reactions: ReactionsType = {
|
||||
love: new Set(['me', '1', '2', '3']),
|
||||
'thumbs-up': new Set(['me', '1', '2', '3']),
|
||||
'thumbs-down': new Set(['me', '1', '2', '3']),
|
||||
}
|
||||
|
||||
// More on how to set up stories at: https://storybook.js.org/docs/7.0/react/writing-stories/introduction
|
||||
const meta: Meta<typeof Actions> = {
|
||||
title: 'Messages/actions',
|
||||
component: Actions,
|
||||
args: {
|
||||
reactions,
|
||||
},
|
||||
argTypes: {},
|
||||
parameters: {
|
||||
layout: 'centered',
|
||||
|
|
|
@ -1,18 +1,47 @@
|
|||
import { AddReactionIcon, OptionsIcon, ReplyIcon } from '@status-im/icons/20'
|
||||
import { useEffect } from 'react'
|
||||
|
||||
import {
|
||||
AddReactionIcon,
|
||||
CopyIcon,
|
||||
DeleteIcon,
|
||||
EditIcon,
|
||||
ForwardIcon,
|
||||
LinkIcon,
|
||||
OptionsIcon,
|
||||
PinIcon,
|
||||
ReplyIcon,
|
||||
} from '@status-im/icons/20'
|
||||
import { Stack } from 'tamagui'
|
||||
|
||||
import { Button } from '../../button'
|
||||
import { DropdownMenu } from '../../dropdown-menu'
|
||||
import { IconButton } from '../../icon-button'
|
||||
import { ReactionPopover } from './reaction-popover'
|
||||
|
||||
import type { ReactionsType } from '../types'
|
||||
|
||||
interface Props {
|
||||
onClick: VoidFunction
|
||||
reactions: ReactionsType
|
||||
onOpenChange: (open: boolean) => void
|
||||
onReplyPress: VoidFunction
|
||||
// onEditPress: VoidFunction
|
||||
// onDeletePress: VoidFunction
|
||||
}
|
||||
export const Actions = (_props: Props) => {
|
||||
|
||||
export const Actions = (props: Props) => {
|
||||
const { reactions, onOpenChange, onReplyPress } = props
|
||||
|
||||
useEffect(() => {
|
||||
return () => onOpenChange(false)
|
||||
}, [onOpenChange])
|
||||
|
||||
return (
|
||||
<Stack
|
||||
backgroundColor="$white-100"
|
||||
borderWidth={1}
|
||||
borderColor="$neutral-10"
|
||||
borderRadius={10}
|
||||
borderRadius={12}
|
||||
padding={2}
|
||||
space={2}
|
||||
overflow="hidden"
|
||||
position="absolute"
|
||||
top={-16}
|
||||
|
@ -23,9 +52,82 @@ export const Actions = (_props: Props) => {
|
|||
shadowColor="rgba(9, 16, 28, 0.08)"
|
||||
zIndex={10}
|
||||
>
|
||||
<Button type="ghost" icon={<AddReactionIcon />} borderRadius={0} />
|
||||
<Button type="ghost" icon={<ReplyIcon />} borderRadius={0} />
|
||||
<Button type="ghost" icon={<OptionsIcon />} borderRadius={0} />
|
||||
{/* REACTION */}
|
||||
<ReactionPopover
|
||||
reactions={reactions}
|
||||
side="left"
|
||||
sideOffset={6}
|
||||
onOpenChange={onOpenChange}
|
||||
>
|
||||
<IconButton variant="outline" icon={<AddReactionIcon />} />
|
||||
</ReactionPopover>
|
||||
|
||||
{/* REPLY */}
|
||||
<IconButton
|
||||
variant="outline"
|
||||
icon={<ReplyIcon />}
|
||||
onPress={onReplyPress}
|
||||
/>
|
||||
|
||||
{/* EDIT */}
|
||||
{/* <IconButton
|
||||
variant="outline"
|
||||
icon={<EditIcon />}
|
||||
onPress={onEditPress}
|
||||
/> */}
|
||||
|
||||
{/* DELETE */}
|
||||
{/* <IconButton
|
||||
variant="outline"
|
||||
icon={<DeleteIcon />}
|
||||
onPress={onDeletePress}
|
||||
/> */}
|
||||
|
||||
{/* OPTIONS MENU */}
|
||||
<DropdownMenu modal={false} onOpenChange={onOpenChange}>
|
||||
<IconButton variant="outline" icon={<OptionsIcon />} />
|
||||
<DropdownMenu.Content align="end" sideOffset={10}>
|
||||
<DropdownMenu.Item
|
||||
icon={<EditIcon />}
|
||||
label="Edit message"
|
||||
onSelect={() => console.log('edit')}
|
||||
/>
|
||||
<DropdownMenu.Item
|
||||
icon={<ReplyIcon />}
|
||||
label="Reply"
|
||||
onSelect={() => console.log('reply')}
|
||||
/>
|
||||
<DropdownMenu.Item
|
||||
icon={<CopyIcon />}
|
||||
label="Copy text"
|
||||
onSelect={() => console.log('copy')}
|
||||
/>
|
||||
<DropdownMenu.Item
|
||||
icon={<PinIcon />}
|
||||
label="Pin to the channel"
|
||||
onSelect={() => console.log('pin')}
|
||||
/>
|
||||
<DropdownMenu.Item
|
||||
icon={<ForwardIcon />}
|
||||
label="Forward"
|
||||
onSelect={() => console.log('forward')}
|
||||
/>
|
||||
<DropdownMenu.Item
|
||||
icon={<LinkIcon />}
|
||||
label="Share link to message"
|
||||
onSelect={() => console.log('share')}
|
||||
/>
|
||||
|
||||
<DropdownMenu.Separator />
|
||||
|
||||
<DropdownMenu.Item
|
||||
icon={<DeleteIcon />}
|
||||
label="Delete message"
|
||||
danger
|
||||
onSelect={() => console.log('delete')}
|
||||
/>
|
||||
</DropdownMenu.Content>
|
||||
</DropdownMenu>
|
||||
</Stack>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
import { XStack } from 'tamagui'
|
||||
|
||||
import { Popover } from '../../popover'
|
||||
import { ReactButton } from '../../react-button'
|
||||
|
||||
import type { PopoverProps } from '../../popover'
|
||||
import type { ReactionsType } from '../types'
|
||||
|
||||
type Props = Omit<PopoverProps, 'children'> & {
|
||||
children: React.ReactElement
|
||||
reactions: ReactionsType
|
||||
onOpenChange?: PopoverProps['onOpenChange']
|
||||
}
|
||||
|
||||
export const ReactionPopover = (props: Props) => {
|
||||
const { children, reactions, onOpenChange, ...popoverProps } = props
|
||||
|
||||
return (
|
||||
<Popover {...popoverProps} onOpenChange={onOpenChange} modal={false}>
|
||||
{children}
|
||||
|
||||
<Popover.Content>
|
||||
<XStack space={2} padding={2}>
|
||||
<ReactButton
|
||||
variant="ghost"
|
||||
size={32}
|
||||
icon="love"
|
||||
selected={reactions['love']?.has('me')}
|
||||
/>
|
||||
<ReactButton
|
||||
variant="ghost"
|
||||
size={32}
|
||||
icon="thumbs-up"
|
||||
selected={reactions['thumbs-up']?.has('me')}
|
||||
/>
|
||||
<ReactButton
|
||||
variant="ghost"
|
||||
size={32}
|
||||
icon="thumbs-down"
|
||||
selected={reactions['thumbs-down']?.has('me')}
|
||||
/>
|
||||
<ReactButton
|
||||
variant="ghost"
|
||||
size={32}
|
||||
icon="laugh"
|
||||
selected={reactions.laugh?.has('me')}
|
||||
/>
|
||||
<ReactButton
|
||||
variant="ghost"
|
||||
size={32}
|
||||
icon="sad"
|
||||
selected={reactions.sad?.has('me')}
|
||||
/>
|
||||
<ReactButton
|
||||
variant="ghost"
|
||||
size={32}
|
||||
icon="angry"
|
||||
selected={reactions.angry?.has('me')}
|
||||
/>
|
||||
</XStack>
|
||||
</Popover.Content>
|
||||
</Popover>
|
||||
)
|
||||
}
|
|
@ -1,11 +1,21 @@
|
|||
import { Reactions } from './reactions'
|
||||
|
||||
import type { ReactionsType } from '../types'
|
||||
import type { Meta, StoryObj } from '@storybook/react'
|
||||
|
||||
const reactions: ReactionsType = {
|
||||
love: new Set(['me', '1', '2', '3']),
|
||||
'thumbs-up': new Set(['me', '1', '2', '3']),
|
||||
'thumbs-down': new Set(['me', '1', '2', '3']),
|
||||
}
|
||||
|
||||
// More on how to set up stories at: https://storybook.js.org/docs/7.0/react/writing-stories/introduction
|
||||
const meta: Meta<typeof Reactions> = {
|
||||
title: 'messages/reactions',
|
||||
component: Reactions,
|
||||
args: {
|
||||
reactions,
|
||||
},
|
||||
argTypes: {},
|
||||
parameters: {
|
||||
design: {
|
||||
|
|
|
@ -1,94 +1,109 @@
|
|||
import { cloneElement } from 'react'
|
||||
|
||||
import { AddReactionIcon } from '@status-im/icons/20'
|
||||
import {
|
||||
// AngryIcon,
|
||||
LaughIcon,
|
||||
LoveIcon,
|
||||
SadIcon,
|
||||
ThumbsDownIcon,
|
||||
ThumbsUpIcon,
|
||||
} from '@status-im/icons/reactions'
|
||||
import { Stack, styled } from '@tamagui/core'
|
||||
import { XStack } from 'tamagui'
|
||||
|
||||
import { Paragraph } from '../../typography'
|
||||
import { Dialog } from '../../dialog'
|
||||
import { ReactButton } from '../../react-button'
|
||||
import { Tooltip } from '../../tooltip/tooltip'
|
||||
import { UserList } from '../../user-list'
|
||||
import { ReactionPopover } from './reaction-popover'
|
||||
|
||||
import type React from 'react'
|
||||
|
||||
// import { Pressable } from 'react-native'
|
||||
|
||||
const ReactButton = styled(Stack, {
|
||||
name: 'ReactButton',
|
||||
accessibilityRole: 'button',
|
||||
|
||||
cursor: 'pointer',
|
||||
userSelect: 'none',
|
||||
borderRadius: 8,
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
space: 4,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
flexShrink: 0,
|
||||
minWidth: 36,
|
||||
height: 24,
|
||||
paddingHorizontal: 8,
|
||||
borderWidth: 1,
|
||||
borderColor: '$neutral-20',
|
||||
|
||||
hoverStyle: {
|
||||
borderColor: '$neutral-30',
|
||||
},
|
||||
|
||||
variants: {
|
||||
selected: {
|
||||
true: {
|
||||
backgroundColor: '$neutral-30',
|
||||
borderColor: '$neutral-30',
|
||||
},
|
||||
},
|
||||
} as const,
|
||||
})
|
||||
|
||||
type ReactionButtonProps = {
|
||||
icon: React.ReactElement
|
||||
count?: number
|
||||
selected?: boolean
|
||||
}
|
||||
|
||||
const ReactionButton = (props: ReactionButtonProps) => {
|
||||
const { count, selected, icon } = props
|
||||
|
||||
return (
|
||||
<ReactButton selected={selected}>
|
||||
{cloneElement(icon, { color: '$neutral-100' })}
|
||||
{count && (
|
||||
<Paragraph weight="medium" variant="smaller" whiteSpace="nowrap">
|
||||
{count}
|
||||
</Paragraph>
|
||||
)}
|
||||
</ReactButton>
|
||||
)
|
||||
}
|
||||
import type { ReactButtonProps } from '../../react-button'
|
||||
import type { ReactionsType, ReactionType } from '../types'
|
||||
|
||||
type Props = {
|
||||
reactions?: any[]
|
||||
reactions: ReactionsType
|
||||
}
|
||||
|
||||
export const Reactions = (props: Props) => {
|
||||
const { reactions } = props
|
||||
|
||||
const hasReaction = Object.values(reactions).some(value => value.size > 0)
|
||||
|
||||
if (hasReaction === false) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<XStack space={8} flexWrap="wrap">
|
||||
<ReactionButton count={1} icon={<LoveIcon />} selected />
|
||||
<ReactionButton count={10} icon={<ThumbsUpIcon />} />
|
||||
<ReactionButton count={99} icon={<ThumbsDownIcon />} />
|
||||
<ReactionButton count={100} icon={<LaughIcon />} />
|
||||
<ReactionButton count={100} icon={<SadIcon />} />
|
||||
{/* FIX TAMAGUI BUG */}
|
||||
{/* <ReactionButton count={100} icon={<AngryIcon />} /> */}
|
||||
<ReactionButton icon={<AddReactionIcon />} />
|
||||
<XStack space={6} flexWrap="wrap">
|
||||
{Object.entries(reactions).map(([type, value]) => (
|
||||
<Reaction
|
||||
key={type}
|
||||
size="compact"
|
||||
icon={type as ReactionType}
|
||||
count={value.size}
|
||||
selected={value.has('me')}
|
||||
/>
|
||||
))}
|
||||
|
||||
<ReactionPopover
|
||||
reactions={reactions}
|
||||
side="bottom"
|
||||
align="start"
|
||||
sideOffset={8}
|
||||
>
|
||||
<ReactButton size="compact" icon="add" selected={false} />
|
||||
</ReactionPopover>
|
||||
</XStack>
|
||||
)
|
||||
}
|
||||
|
||||
const Reaction = (props: ReactButtonProps) => {
|
||||
return (
|
||||
<Dialog press="long">
|
||||
<Tooltip
|
||||
side="bottom"
|
||||
sideOffset={4}
|
||||
content={
|
||||
<>
|
||||
You, Mr Gandalf, Ariana Perlona and
|
||||
<button>3 more</button> reacted with {'[ICON]'}
|
||||
</>
|
||||
}
|
||||
>
|
||||
<ReactButton {...props} />
|
||||
</Tooltip>
|
||||
|
||||
<Dialog.Content>
|
||||
<UserList
|
||||
users={[
|
||||
{
|
||||
name: 'Pedro',
|
||||
src: 'https://images.unsplash.com/photo-1570295999919-56ceb5ecca61?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1760&q=80',
|
||||
address: 'zQ3...9d4Gs0',
|
||||
indicator: 'online',
|
||||
},
|
||||
{
|
||||
name: 'Pedro',
|
||||
src: 'https://images.unsplash.com/photo-1570295999919-56ceb5ecca61?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1760&q=80',
|
||||
address: 'zQ3...9d4Gs0',
|
||||
indicator: 'online',
|
||||
},
|
||||
{
|
||||
name: 'Pedro',
|
||||
src: 'https://images.unsplash.com/photo-1570295999919-56ceb5ecca61?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1760&q=80',
|
||||
address: 'zQ3...9d4Gs0',
|
||||
indicator: 'online',
|
||||
},
|
||||
{
|
||||
name: 'Pedro',
|
||||
src: 'https://images.unsplash.com/photo-1570295999919-56ceb5ecca61?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1760&q=80',
|
||||
address: 'zQ3...9d4Gs0',
|
||||
indicator: 'online',
|
||||
},
|
||||
{
|
||||
name: 'Pedro',
|
||||
src: 'https://images.unsplash.com/photo-1570295999919-56ceb5ecca61?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1760&q=80',
|
||||
address: 'zQ3...9d4Gs0',
|
||||
indicator: 'online',
|
||||
},
|
||||
{
|
||||
name: 'Pedro',
|
||||
src: 'https://images.unsplash.com/photo-1570295999919-56ceb5ecca61?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1760&q=80',
|
||||
address: 'zQ3...9d4Gs0',
|
||||
indicator: 'online',
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</Dialog.Content>
|
||||
</Dialog>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,50 +1,82 @@
|
|||
import { ChatMessage } from './chat-message'
|
||||
import { Message } from './message'
|
||||
|
||||
export * from './chat-message'
|
||||
import type { ReactionsType } from './types'
|
||||
|
||||
export * from './message'
|
||||
|
||||
const reactions: ReactionsType = {
|
||||
love: new Set(['me', '1']),
|
||||
'thumbs-up': new Set(['3']),
|
||||
'thumbs-down': new Set(['me', '1', '2', '3']),
|
||||
}
|
||||
|
||||
export const Messages = () => {
|
||||
return (
|
||||
<>
|
||||
<ChatMessage text="fsdjkf kasldjf ksdlfjksdlfj asdklfj sdkljf" />
|
||||
<ChatMessage text="fsdjkf kasldjf ksdlfjksdlfj asdklfj sdkljf" />
|
||||
<ChatMessage text="fsdjkf kasldjf ksdlfjksdlfj asdklfj sdkljf" />
|
||||
<ChatMessage
|
||||
<Message
|
||||
text="Morbi a metus. Phasellus enim erat, vestibulum vel, aliquam a, posuere eu, velit. Nullam sapien sem, ornare ac, nonummy non, lobortis a, enim. Nunc tincidunt ante vitae massa. Duis ante orci, molestie vitae, vehicula venenatis, tincidunt ac, pede. Nulla accumsan, elit sit"
|
||||
reactions={{}}
|
||||
/>
|
||||
<Message
|
||||
text="Morbi a metus. Phasellus enim erat, vestibulum vel, aliquam a, posuere eu, velit. "
|
||||
reactions={{}}
|
||||
reply
|
||||
pinned
|
||||
/>
|
||||
<Message
|
||||
text="Morbi a metus. Phasellus enim erat, vestibulum vel, aliquam a, posuere eu, velit. "
|
||||
reactions={{}}
|
||||
/>
|
||||
<Message
|
||||
images={[
|
||||
{
|
||||
url: 'https://images.unsplash.com/photo-1673433107234-14d1a4424658?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1470&q=80',
|
||||
},
|
||||
]}
|
||||
reactions={{}}
|
||||
/>
|
||||
<ChatMessage text="fsdjkf kasldjf ksdlfjksdlfj asdklfj sdkljf" />
|
||||
<ChatMessage text="fsdjkf kasldjf ksdlfjksdlfj asdklfj sdkljf" />
|
||||
<ChatMessage
|
||||
text="fsdjkf kasldjf ksdlfjksdlfj asdklfj sdkljf"
|
||||
reactions={['123']}
|
||||
<Message
|
||||
text="Morbi a metus. Phasellus enim erat, vestibulum vel, aliquam a, posuere eu, velit. Nullam sapien sem, ornare ac, nonummy non, lobortis a, enim. Nunc tincidunt ante vitae massa. Duis ante orci, molestie vitae, vehicula venenatis, tincidunt ac, pede. Nulla accumsan, elit sit"
|
||||
reactions={reactions}
|
||||
/>
|
||||
<ChatMessage text="fsdjkf kasldjf ksdlfjksdlfj asdklfj sdkljf" />
|
||||
<ChatMessage text="fsdjkf kasldjf ksdlfjksdlfj asdklfj sdkljf" />
|
||||
<ChatMessage text="fsdjkf kasldjf ksdlfjksdlfj asdklfj sdkljf" />
|
||||
<ChatMessage
|
||||
text="fsdjkf kasldjf ksdlfjksdlfj asdklfj sdkljf"
|
||||
reactions={['123']}
|
||||
<Message
|
||||
text="Morbi a metus. Phasellus enim erat, vestibulum vel, aliquam. "
|
||||
reactions={{}}
|
||||
pinned
|
||||
/>
|
||||
<ChatMessage
|
||||
text="fsdjkf kasldjf ksdlfjksdlfj asdklfj sdkljf"
|
||||
reactions={['123']}
|
||||
<Message
|
||||
text="Morbi a metus. Phasellus enim erat, vestibulum vel, aliquam. "
|
||||
reactions={{}}
|
||||
reply
|
||||
/>
|
||||
<ChatMessage
|
||||
<Message
|
||||
text="Morbi a metus. Phasellus enim erat, vestibulum vel, aliquam. "
|
||||
reactions={{}}
|
||||
/>
|
||||
<Message
|
||||
text="Morbi a metus. Phasellus enim erat, vestibulum vel, aliquam a, posuere eu, velit. Nullam sapien sem, ornare ac, nonummy non, lobortis a, enim.sit"
|
||||
reactions={reactions}
|
||||
reply
|
||||
/>
|
||||
<Message
|
||||
text="Morbi a metus. Phasellus enim erat, vestibulum vel, aliquam a, posuere eu, velit. Nullam sapien sem, ornare ac, nonummy non, lobortis a, enim.sit"
|
||||
reactions={reactions}
|
||||
/>
|
||||
<Message
|
||||
images={[
|
||||
{
|
||||
url: 'https://images.unsplash.com/photo-1673433107234-14d1a4424658?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1470&q=80',
|
||||
},
|
||||
]}
|
||||
reactions={{}}
|
||||
/>
|
||||
<ChatMessage
|
||||
<Message
|
||||
images={[
|
||||
{
|
||||
url: 'https://images.unsplash.com/photo-1673433107234-14d1a4424658?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1470&q=80',
|
||||
},
|
||||
]}
|
||||
reactions={{}}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
|
|
|
@ -1,12 +1,25 @@
|
|||
import { ChatMessage } from './chat-message'
|
||||
import { Message } from './message'
|
||||
|
||||
import type { ReactionsType } from './types'
|
||||
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<typeof ChatMessage> = {
|
||||
// title: 'Messages',
|
||||
component: ChatMessage,
|
||||
argTypes: {},
|
||||
const meta: Meta<typeof Message> = {
|
||||
title: 'messages',
|
||||
component: Message,
|
||||
args: {
|
||||
reactions: {},
|
||||
},
|
||||
argTypes: {
|
||||
pinned: {
|
||||
type: 'boolean',
|
||||
defaultValue: false,
|
||||
},
|
||||
reply: {
|
||||
type: 'boolean',
|
||||
defaultValue: false,
|
||||
},
|
||||
},
|
||||
parameters: {
|
||||
design: {
|
||||
type: 'figma',
|
||||
|
@ -15,9 +28,13 @@ const meta: Meta<typeof ChatMessage> = {
|
|||
},
|
||||
}
|
||||
|
||||
type Story = StoryObj<typeof ChatMessage>
|
||||
type Story = StoryObj<typeof Message>
|
||||
|
||||
const reactions = ['123']
|
||||
const reactions: ReactionsType = {
|
||||
love: new Set(['me', '1', '2', '3']),
|
||||
'thumbs-up': new Set(['me', '1', '2', '3']),
|
||||
'thumbs-down': new Set(['me', '1', '2', '3']),
|
||||
}
|
||||
|
||||
// More on writing stories with args: https://storybook.js.org/docs/7.0/react/writing-stories/args
|
||||
export const Text: Story = {
|
||||
|
@ -34,6 +51,22 @@ export const TextWithReactions: Story = {
|
|||
},
|
||||
}
|
||||
|
||||
export const TextWithReply: Story = {
|
||||
name: 'Text + Reply',
|
||||
args: {
|
||||
text: 'This is a simple message.',
|
||||
reply: true,
|
||||
},
|
||||
}
|
||||
|
||||
export const TextPinned: Story = {
|
||||
name: 'Text + Pinned',
|
||||
args: {
|
||||
text: 'This is a simple message.',
|
||||
pinned: true,
|
||||
},
|
||||
}
|
||||
|
||||
export const LongText: Story = {
|
||||
name: 'Long text',
|
||||
args: {
|
|
@ -0,0 +1,127 @@
|
|||
import React from 'react'
|
||||
|
||||
import { PinIcon } from '@status-im/icons/16'
|
||||
import { Stack, Unspaced, XStack, YStack } from 'tamagui'
|
||||
|
||||
import { Author } from '../author/author'
|
||||
import { Avatar } from '../avatar'
|
||||
import { Image } from '../image'
|
||||
import { Reply } from '../reply'
|
||||
import { Paragraph } from '../typography'
|
||||
import { Actions } from './components/actions'
|
||||
import { Reactions } from './components/reactions'
|
||||
|
||||
import type { ReactionsType } from './types'
|
||||
|
||||
interface Props {
|
||||
text?: React.ReactNode
|
||||
images?: Array<{ url: string }>
|
||||
reactions: ReactionsType
|
||||
reply?: boolean
|
||||
pinned?: boolean
|
||||
}
|
||||
|
||||
const Message = (props: Props) => {
|
||||
const { text, images, reactions, reply, pinned } = props
|
||||
|
||||
const [hovered, setHovered] = React.useState(false)
|
||||
const [actionsOpen, setActionsOpen] = React.useState(false)
|
||||
|
||||
const active = actionsOpen || hovered
|
||||
// <Sheet press="long">
|
||||
|
||||
return (
|
||||
<YStack
|
||||
position="relative"
|
||||
alignItems="flex-start"
|
||||
paddingHorizontal={8}
|
||||
paddingVertical={8}
|
||||
borderRadius={16}
|
||||
backgroundColor={
|
||||
active ? '$neutral-5' : pinned ? '$blue-50-opa-5' : undefined
|
||||
}
|
||||
onMouseEnter={() => setHovered(true)}
|
||||
onMouseLeave={() => setHovered(false)}
|
||||
>
|
||||
{active && (
|
||||
<Unspaced>
|
||||
<Actions
|
||||
reactions={reactions}
|
||||
onOpenChange={setActionsOpen}
|
||||
onReplyPress={() => {
|
||||
console.log('reply')
|
||||
}}
|
||||
/>
|
||||
</Unspaced>
|
||||
)}
|
||||
|
||||
{reply && (
|
||||
<Stack paddingLeft={16} paddingBottom={12}>
|
||||
<Reply
|
||||
type="text"
|
||||
name="Alisher"
|
||||
src="https://images.unsplash.com/photo-1524638431109-93d95c968f03?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=500&ixid=MnwxfDB8MXxyYW5kb218MHx8Z2lybHx8fHx8fDE2NzM4ODQ0NzU&ixlib=rb-4.0.3&q=80&utm_campaign=api-credit&utm_medium=referral&utm_source=unsplash_source&w=500"
|
||||
/>
|
||||
</Stack>
|
||||
)}
|
||||
|
||||
{pinned && (
|
||||
<Stack
|
||||
flexDirection="row"
|
||||
alignItems="center"
|
||||
paddingLeft={40}
|
||||
paddingBottom={2}
|
||||
space={2}
|
||||
>
|
||||
<PinIcon color="$blue-50" />
|
||||
<Paragraph variant={11} weight="medium" color="$blue-50">
|
||||
Steve
|
||||
</Paragraph>
|
||||
</Stack>
|
||||
)}
|
||||
|
||||
<XStack space={10}>
|
||||
<Avatar
|
||||
size={32}
|
||||
src="https://images.unsplash.com/photo-1524638431109-93d95c968f03?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=500&ixid=MnwxfDB8MXxyYW5kb218MHx8Z2lybHx8fHx8fDE2NzM4ODQ0NzU&ixlib=rb-4.0.3&q=80&utm_campaign=api-credit&utm_medium=referral&utm_source=unsplash_source&w=500"
|
||||
indicator="online"
|
||||
/>
|
||||
|
||||
<YStack flex={1}>
|
||||
<Author
|
||||
name="Alisher Yakupov"
|
||||
address="zQ3...9d4Gs0"
|
||||
status="verified"
|
||||
time="09:30"
|
||||
/>
|
||||
|
||||
{text && (
|
||||
<Paragraph flexGrow={0} weight="regular" color="$neutral-100">
|
||||
{text}
|
||||
</Paragraph>
|
||||
)}
|
||||
|
||||
{images?.map(image => (
|
||||
<Stack
|
||||
key={image.url}
|
||||
marginTop={8}
|
||||
$gtMd={{
|
||||
maxWidth: 320,
|
||||
}}
|
||||
>
|
||||
<Image src={image.url} width="full" height={320} radius={12} />
|
||||
</Stack>
|
||||
))}
|
||||
|
||||
{reactions && (
|
||||
<Stack paddingTop={8}>
|
||||
<Reactions reactions={reactions} />
|
||||
</Stack>
|
||||
)}
|
||||
</YStack>
|
||||
</XStack>
|
||||
</YStack>
|
||||
)
|
||||
}
|
||||
|
||||
export { Message }
|
|
@ -0,0 +1,12 @@
|
|||
export type ReactionType =
|
||||
| 'love'
|
||||
| 'laugh'
|
||||
| 'thumbs-up'
|
||||
| 'thumbs-down'
|
||||
| 'sad'
|
||||
| 'angry'
|
||||
| 'add'
|
||||
|
||||
export type ReactionsType = {
|
||||
[key in ReactionType]?: Set<string>
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
export { type PopoverProps, Popover } from './popover'
|
|
@ -0,0 +1,32 @@
|
|||
import { Button } from '../button'
|
||||
import { Popover } from './popover'
|
||||
|
||||
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<typeof Popover> = {
|
||||
// title: 'Messages',
|
||||
component: Popover,
|
||||
argTypes: {},
|
||||
parameters: {
|
||||
design: {
|
||||
type: 'figma',
|
||||
url: 'https://www.figma.com/file/IBmFKgGL1B4GzqD8LQTw6n/Design-System-for-Web?node-id=611%3A36006&t=Gyy71OAckl3b2TWj-4',
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
type Story = StoryObj<typeof Popover>
|
||||
|
||||
// More on writing stories with args: https://storybook.js.org/docs/7.0/react/writing-stories/args
|
||||
export const Default: Story = {
|
||||
args: {},
|
||||
render: args => (
|
||||
<Popover {...args}>
|
||||
<Button type="primary">Trigger</Button>
|
||||
<Popover.Content>some content</Popover.Content>
|
||||
</Popover>
|
||||
),
|
||||
}
|
||||
|
||||
export default meta
|
|
@ -0,0 +1,51 @@
|
|||
import { Content, Portal, Root, Trigger } from '@radix-ui/react-popover'
|
||||
import { Stack } from 'tamagui'
|
||||
|
||||
import type { PopoverContentProps } from '@radix-ui/react-popover'
|
||||
import type { FunctionComponent } from 'react'
|
||||
|
||||
interface Props {
|
||||
children: [React.ReactElement, React.ReactElement]
|
||||
onOpenChange?: (open: boolean) => void
|
||||
modal?: false
|
||||
side?: PopoverContentProps['side']
|
||||
sideOffset?: PopoverContentProps['sideOffset']
|
||||
align?: PopoverContentProps['align']
|
||||
alignOffset?: PopoverContentProps['alignOffset']
|
||||
}
|
||||
|
||||
const Popover = (props: Props) => {
|
||||
const { children, onOpenChange, modal, ...contentProps } = props
|
||||
|
||||
const [trigger, content] = children
|
||||
|
||||
return (
|
||||
<Root onOpenChange={onOpenChange} modal={modal}>
|
||||
<Trigger asChild>{trigger}</Trigger>
|
||||
<Portal>
|
||||
<Content {...contentProps}>{content}</Content>
|
||||
</Portal>
|
||||
</Root>
|
||||
)
|
||||
}
|
||||
|
||||
const PopoverContent: FunctionComponent = props => {
|
||||
const { children } = props
|
||||
|
||||
return (
|
||||
<Stack
|
||||
backgroundColor="$white-100"
|
||||
borderRadius={12}
|
||||
shadowRadius={30}
|
||||
shadowOffset="0px 8px"
|
||||
shadowColor="rgba(9, 16, 28, 0.12)"
|
||||
>
|
||||
{children}
|
||||
</Stack>
|
||||
)
|
||||
}
|
||||
|
||||
Popover.Content = PopoverContent
|
||||
|
||||
export { Popover as Popover }
|
||||
export type { Props as PopoverProps }
|
|
@ -0,0 +1 @@
|
|||
export { type ReactButtonProps, ReactButton } from './react-button'
|
|
@ -0,0 +1,67 @@
|
|||
import { XStack } from 'tamagui'
|
||||
|
||||
import { ReactButton } from './react-button'
|
||||
|
||||
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<typeof ReactButton> = {
|
||||
title: 'ReactButton',
|
||||
component: ReactButton,
|
||||
args: {},
|
||||
argTypes: {},
|
||||
render: args => (
|
||||
<XStack space={4}>
|
||||
<ReactButton {...args} icon="laugh" />
|
||||
<ReactButton {...args} icon="love" />
|
||||
<ReactButton {...args} icon="sad" />
|
||||
<ReactButton {...args} icon="thumbs-up" />
|
||||
<ReactButton {...args} icon="thumbs-down" />
|
||||
<ReactButton {...args} icon="angry" />
|
||||
</XStack>
|
||||
),
|
||||
}
|
||||
|
||||
type Story = StoryObj<typeof ReactButton>
|
||||
|
||||
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 default meta
|
|
@ -0,0 +1,141 @@
|
|||
import { forwardRef } from 'react'
|
||||
|
||||
import { AddReactionIcon } from '@status-im/icons/20'
|
||||
import {
|
||||
AngryIcon,
|
||||
LaughIcon,
|
||||
LoveIcon,
|
||||
SadIcon,
|
||||
ThumbsDownIcon,
|
||||
ThumbsUpIcon,
|
||||
} from '@status-im/icons/reactions'
|
||||
import { Stack, styled } from '@tamagui/core'
|
||||
|
||||
import { Paragraph } from '../typography'
|
||||
|
||||
import type { GetProps } from '@tamagui/core'
|
||||
import type { Ref } from 'react'
|
||||
import type { PressableProps } from 'react-native'
|
||||
|
||||
const Button = styled(Stack, {
|
||||
name: 'ReactButton',
|
||||
accessibilityRole: 'button',
|
||||
|
||||
cursor: 'pointer',
|
||||
userSelect: 'none',
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
borderWidth: 1,
|
||||
animation: 'fast',
|
||||
space: 4,
|
||||
|
||||
variants: {
|
||||
variant: {
|
||||
outline: {
|
||||
borderColor: '$neutral-10',
|
||||
hoverStyle: { borderColor: '$neutral-30' },
|
||||
pressStyle: {
|
||||
backgroundColor: '$neutral-10',
|
||||
borderColor: '$neutral-20',
|
||||
},
|
||||
},
|
||||
|
||||
ghost: {
|
||||
borderColor: 'transparent',
|
||||
hoverStyle: { backgroundColor: '$neutral-10' },
|
||||
pressStyle: { backgroundColor: '$neutral-20' },
|
||||
},
|
||||
},
|
||||
|
||||
selected: {
|
||||
true: {
|
||||
backgroundColor: '$neutral-10',
|
||||
borderColor: '$neutral-30',
|
||||
},
|
||||
},
|
||||
|
||||
size: {
|
||||
40: {
|
||||
borderRadius: 12,
|
||||
width: 40,
|
||||
height: 40,
|
||||
},
|
||||
|
||||
32: {
|
||||
borderRadius: 10,
|
||||
width: 32,
|
||||
height: 32,
|
||||
},
|
||||
|
||||
compact: {
|
||||
borderRadius: 8,
|
||||
minWidth: 36,
|
||||
height: 24,
|
||||
paddingHorizontal: 8,
|
||||
},
|
||||
},
|
||||
} as const,
|
||||
})
|
||||
|
||||
type ButtonProps = GetProps<typeof Button>
|
||||
|
||||
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<HTMLButtonElement>) => {
|
||||
const {
|
||||
icon,
|
||||
variant = 'outline',
|
||||
size = 40,
|
||||
count,
|
||||
...pressableProps
|
||||
} = props
|
||||
|
||||
const Icon = REACTIONS[icon]
|
||||
|
||||
const selected =
|
||||
props.selected || props['aria-expanded'] || props['aria-selected']
|
||||
|
||||
return (
|
||||
<Button
|
||||
{...(pressableProps as any)}
|
||||
ref={ref}
|
||||
variant={variant}
|
||||
size={size}
|
||||
selected={selected}
|
||||
>
|
||||
<Icon color="$neutral-100" />
|
||||
{count && (
|
||||
<Paragraph weight="medium" variant="smaller" whiteSpace="nowrap">
|
||||
{count}
|
||||
</Paragraph>
|
||||
)}
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
|
||||
const _ReactButton = forwardRef(ReactButton)
|
||||
|
||||
export { _ReactButton as ReactButton }
|
||||
export type { Props as ReactButtonProps }
|
|
@ -0,0 +1 @@
|
|||
export { type ReplyProps, Reply } from './reply'
|
|
@ -0,0 +1,84 @@
|
|||
import { action } from '@storybook/addon-actions'
|
||||
|
||||
import { Reply } from './reply'
|
||||
|
||||
import type { Meta, StoryObj } from '@storybook/react'
|
||||
|
||||
const meta: Meta<typeof Reply> = {
|
||||
component: Reply,
|
||||
argTypes: {},
|
||||
args: {
|
||||
name: 'Alisher Yakupov',
|
||||
src: 'https://images.unsplash.com/photo-1570295999919-56ceb5ecca61?ixid=Mnw0MDAxMTJ8MHwxfHNlYXJjaHw0fHxhdmF0YXJ8ZW58MHx8fHwxNjc1MjU4NTkw&ixlib=rb-4.0.3',
|
||||
},
|
||||
parameters: {
|
||||
design: {
|
||||
type: 'figma',
|
||||
url: 'https://www.figma.com/file/IBmFKgGL1B4GzqD8LQTw6n/Design-System-for-Desktop%2FWeb?node-id=3173%3A55936&t=QgRAQPXVREVsrDg7-11',
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
type Story = StoryObj<typeof Reply>
|
||||
|
||||
export const Text: Story = {
|
||||
args: {
|
||||
type: 'text',
|
||||
onClose: undefined,
|
||||
},
|
||||
}
|
||||
|
||||
export const TextClose: Story = {
|
||||
name: 'Text + Close',
|
||||
args: {
|
||||
...Text.args,
|
||||
onClose: action('close'),
|
||||
},
|
||||
}
|
||||
|
||||
export const Image: Story = {
|
||||
args: {
|
||||
type: 'image',
|
||||
onClose: undefined,
|
||||
},
|
||||
}
|
||||
|
||||
export const ImageClose: Story = {
|
||||
name: 'Image + Close',
|
||||
args: {
|
||||
...Image.args,
|
||||
onClose: action('close'),
|
||||
},
|
||||
}
|
||||
|
||||
export const GIF: Story = {
|
||||
args: {
|
||||
type: 'gif',
|
||||
onClose: undefined,
|
||||
},
|
||||
}
|
||||
|
||||
export const GIFClose: Story = {
|
||||
name: 'GIF + Close',
|
||||
args: {
|
||||
...GIF.args,
|
||||
onClose: action('close'),
|
||||
},
|
||||
}
|
||||
|
||||
export const Deleted: Story = {
|
||||
args: {
|
||||
type: 'deleted',
|
||||
onClose: undefined,
|
||||
},
|
||||
}
|
||||
|
||||
export const DeletedClose: Story = {
|
||||
name: 'Deleted + Close',
|
||||
args: {
|
||||
type: 'deleted',
|
||||
onClose: action('close'),
|
||||
},
|
||||
}
|
||||
|
||||
export default meta
|
|
@ -0,0 +1,97 @@
|
|||
import { CloseIcon } from '@status-im/icons/12'
|
||||
import { SadIcon } from '@status-im/icons/16'
|
||||
import { Path, Svg } from 'react-native-svg'
|
||||
import { Stack, Unspaced, XStack } from 'tamagui'
|
||||
|
||||
import { Avatar } from '../avatar'
|
||||
import { Button } from '../button'
|
||||
import { Paragraph } from '../typography'
|
||||
|
||||
interface Props {
|
||||
type: 'text' | 'gif' | 'image' | 'deleted'
|
||||
onClose?: VoidFunction
|
||||
name: string
|
||||
src: string
|
||||
}
|
||||
|
||||
// FIXME: This should accept message or message ID and render the message accordingly
|
||||
const Reply = (props: Props) => {
|
||||
const { type, name, onClose, src } = props
|
||||
|
||||
const content =
|
||||
type !== 'deleted' ? (
|
||||
<XStack position="relative" space={4} alignItems="center" height={24}>
|
||||
<Unspaced>
|
||||
<Stack position="absolute" left={-24} top={10}>
|
||||
<Connector />
|
||||
</Stack>
|
||||
</Unspaced>
|
||||
|
||||
<Avatar size={20} src={src} />
|
||||
|
||||
<Paragraph variant="smaller" weight="semibold" color="$neutral-100">
|
||||
{name}
|
||||
</Paragraph>
|
||||
|
||||
<Paragraph variant={11} weight="regular" color="$neutral-50">
|
||||
{type === 'text' && 'What is the meaning of life? '}
|
||||
{type === 'gif' && 'GIF'}
|
||||
{type === 'image' && '5 photos'}
|
||||
</Paragraph>
|
||||
</XStack>
|
||||
) : (
|
||||
<XStack position="relative" space={4} alignItems="center" height={24}>
|
||||
<Unspaced>
|
||||
<Stack position="absolute" left={-24} top={10}>
|
||||
<Connector />
|
||||
</Stack>
|
||||
</Unspaced>
|
||||
|
||||
<SadIcon color="$neutral-50" />
|
||||
|
||||
<Paragraph variant="smaller" weight="medium" color="$neutral-50">
|
||||
Message deleted
|
||||
</Paragraph>
|
||||
</XStack>
|
||||
)
|
||||
|
||||
return (
|
||||
<XStack
|
||||
space={8}
|
||||
justifyContent="space-between"
|
||||
alignItems="center"
|
||||
paddingLeft={24}
|
||||
>
|
||||
{content}
|
||||
|
||||
{/* FIXME: This should be regular button with size 24 */}
|
||||
{onClose && (
|
||||
<Button
|
||||
type="outline"
|
||||
size={24}
|
||||
icon={<CloseIcon />}
|
||||
onPress={onClose}
|
||||
/>
|
||||
)}
|
||||
</XStack>
|
||||
)
|
||||
}
|
||||
|
||||
const Connector = () => (
|
||||
<Svg
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 16 16"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<Path
|
||||
d="M16 1V1C8.16344 1 1 8.16344 1 16V16"
|
||||
stroke="#A1ABBD"
|
||||
strokeLinecap="round"
|
||||
/>
|
||||
</Svg>
|
||||
)
|
||||
|
||||
export { Reply }
|
||||
export type { Props as ReplyProps }
|
|
@ -0,0 +1 @@
|
|||
export { Sheet } from './sheet'
|
|
@ -0,0 +1,32 @@
|
|||
import { Button } from '../button'
|
||||
import { Sheet } from './sheet'
|
||||
|
||||
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<typeof Sheet> = {
|
||||
// title: 'Messages',
|
||||
component: Sheet,
|
||||
argTypes: {},
|
||||
parameters: {
|
||||
design: {
|
||||
type: 'figma',
|
||||
url: 'https://www.figma.com/file/IBmFKgGL1B4GzqD8LQTw6n/Design-System-for-Web?node-id=611%3A36006&t=Gyy71OAckl3b2TWj-4',
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
type Story = StoryObj<typeof Sheet>
|
||||
|
||||
// More on writing stories with args: https://storybook.js.org/docs/7.0/react/writing-stories/args
|
||||
export const Default: Story = {
|
||||
args: {},
|
||||
render: args => (
|
||||
<Sheet {...args}>
|
||||
<Button>Trigger</Button>
|
||||
<Sheet.Content>hello</Sheet.Content>
|
||||
</Sheet>
|
||||
),
|
||||
}
|
||||
|
||||
export default meta
|
|
@ -0,0 +1,79 @@
|
|||
import { Content, Overlay, Portal, Root, Trigger } from '@radix-ui/react-dialog'
|
||||
|
||||
import type React from 'react'
|
||||
|
||||
interface Props {
|
||||
children: [React.ReactElement, React.ReactElement]
|
||||
open?: boolean
|
||||
onOpenChange?: (open: boolean) => void
|
||||
press?: 'normal' | 'long'
|
||||
}
|
||||
|
||||
const Sheet = (props: Props) => {
|
||||
const { children, open, onOpenChange } = props
|
||||
|
||||
const [trigger, content] = children
|
||||
|
||||
return (
|
||||
<Root open={open} onOpenChange={onOpenChange}>
|
||||
{/* TRIGGER */}
|
||||
<Trigger asChild>{trigger}</Trigger>
|
||||
|
||||
{/* CONTENT */}
|
||||
<Portal>
|
||||
<Overlay
|
||||
style={{
|
||||
position: 'fixed',
|
||||
inset: 0,
|
||||
backgroundColor: 'rgba(0,0,0,0.5)',
|
||||
}}
|
||||
/>
|
||||
{content}
|
||||
</Portal>
|
||||
</Root>
|
||||
)
|
||||
}
|
||||
|
||||
interface DialogContentProps {
|
||||
children: React.ReactNode
|
||||
initialFocusRef?: React.RefObject<HTMLElement>
|
||||
}
|
||||
|
||||
const SheetContent = (props: DialogContentProps) => {
|
||||
const { children, initialFocusRef } = props
|
||||
|
||||
const handleOpenAutoFocus = (event: Event) => {
|
||||
if (initialFocusRef?.current) {
|
||||
event.preventDefault()
|
||||
initialFocusRef.current.focus()
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Content
|
||||
onOpenAutoFocus={handleOpenAutoFocus}
|
||||
style={{
|
||||
backgroundColor: 'white',
|
||||
padding: 8,
|
||||
borderTopLeftRadius: 8,
|
||||
borderTopRightRadius: 8,
|
||||
position: 'fixed',
|
||||
bottom: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
height: '80%',
|
||||
// top: 'auto',
|
||||
// from
|
||||
// transform: 'translate3d(0,100%,0)',
|
||||
// to
|
||||
transform: 'translate3d(0,0,0)',
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</Content>
|
||||
)
|
||||
}
|
||||
|
||||
Sheet.Content = SheetContent
|
||||
|
||||
export { Sheet }
|
|
@ -0,0 +1 @@
|
|||
export { type TooltipProps, Tooltip } from './tooltip'
|
|
@ -0,0 +1,3 @@
|
|||
import type { PropsWithChildren } from 'react'
|
||||
|
||||
export const Tooltip = ({ children }: PropsWithChildren<unknown>) => children
|
|
@ -0,0 +1,30 @@
|
|||
import { Button } from '../button'
|
||||
import { Tooltip } from './tooltip'
|
||||
|
||||
import type { Meta, StoryObj } from '@storybook/react'
|
||||
|
||||
const meta: Meta<typeof Tooltip> = {
|
||||
component: Tooltip,
|
||||
argTypes: {},
|
||||
parameters: {
|
||||
design: {
|
||||
type: 'figma',
|
||||
url: 'https://www.figma.com/file/IBmFKgGL1B4GzqD8LQTw6n/Design-System-for-Web?node-id=15032%3A174184&t=PHVNitU0s0KwOi8L-0',
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
type Story = StoryObj<typeof Tooltip>
|
||||
|
||||
export const Default: Story = {
|
||||
args: {
|
||||
content: 'Sebastian Vettel reacted with a heart',
|
||||
},
|
||||
render: args => (
|
||||
<Tooltip {...args}>
|
||||
<Button type="outline">Trigger</Button>
|
||||
</Tooltip>
|
||||
),
|
||||
}
|
||||
|
||||
export default meta
|
|
@ -0,0 +1,83 @@
|
|||
import { forwardRef } from 'react'
|
||||
|
||||
import {
|
||||
Arrow,
|
||||
Content,
|
||||
Portal,
|
||||
Root,
|
||||
TooltipProvider,
|
||||
Trigger,
|
||||
} from '@radix-ui/react-tooltip'
|
||||
import { Stack } from 'tamagui'
|
||||
|
||||
import { Paragraph } from '../typography'
|
||||
|
||||
import type { TooltipContentProps } from '@radix-ui/react-tooltip'
|
||||
import type { Ref } from 'react'
|
||||
|
||||
interface Props {
|
||||
children: React.ReactElement
|
||||
content: React.ReactNode
|
||||
delayDuration?: number
|
||||
side?: TooltipContentProps['side']
|
||||
sideOffset?: TooltipContentProps['sideOffset']
|
||||
align?: TooltipContentProps['align']
|
||||
alignOffset?: TooltipContentProps['alignOffset']
|
||||
}
|
||||
|
||||
const Tooltip = (props: Props, ref: Ref<HTMLButtonElement>) => {
|
||||
const {
|
||||
children,
|
||||
content,
|
||||
delayDuration,
|
||||
side,
|
||||
sideOffset,
|
||||
align,
|
||||
alignOffset,
|
||||
...triggerProps
|
||||
} = props
|
||||
|
||||
return (
|
||||
<TooltipProvider>
|
||||
<Root delayDuration={delayDuration}>
|
||||
<Trigger {...triggerProps} ref={ref} asChild>
|
||||
{children}
|
||||
</Trigger>
|
||||
|
||||
<Portal>
|
||||
<Content
|
||||
asChild
|
||||
side={side}
|
||||
sideOffset={sideOffset}
|
||||
align={align}
|
||||
alignOffset={alignOffset}
|
||||
>
|
||||
<Stack
|
||||
backgroundColor="$neutral-95"
|
||||
paddingVertical={6}
|
||||
paddingHorizontal={12}
|
||||
borderRadius={8}
|
||||
shadowRadius={30}
|
||||
shadowOffset="0px 8px"
|
||||
shadowColor="rgba(9, 16, 28, 0.12)"
|
||||
>
|
||||
{typeof content === 'string' ? (
|
||||
<Paragraph variant="smaller" weight="medium" color="$white-100">
|
||||
{content}
|
||||
</Paragraph>
|
||||
) : (
|
||||
content
|
||||
)}
|
||||
<Arrow width={11} height={5} />
|
||||
</Stack>
|
||||
</Content>
|
||||
</Portal>
|
||||
</Root>
|
||||
</TooltipProvider>
|
||||
)
|
||||
}
|
||||
|
||||
const _Tooltip = forwardRef(Tooltip)
|
||||
|
||||
export { _Tooltip as Tooltip }
|
||||
export type { Props as TooltipProps }
|
|
@ -1,13 +1,21 @@
|
|||
import { Divider, IconButton, Paragraph } from '@status-im/components'
|
||||
import {
|
||||
ArrowLeftIcon,
|
||||
CommunitiesIcon,
|
||||
DeleteIcon,
|
||||
DownloadIcon,
|
||||
LockedIcon,
|
||||
MembersIcon,
|
||||
MutedIcon,
|
||||
OptionsIcon,
|
||||
ShareIcon,
|
||||
UpToDateIcon,
|
||||
} from '@status-im/icons/20'
|
||||
import { Stack } from '@tamagui/core'
|
||||
import { BlurView } from 'expo-blur'
|
||||
|
||||
import { DropdownMenu } from '../dropdown-menu'
|
||||
|
||||
import type { GetProps, StackProps } from '@tamagui/core'
|
||||
|
||||
type BaseProps = GetProps<typeof Stack>
|
||||
|
@ -104,7 +112,46 @@ const Topbar = (props: Props) => {
|
|||
blurred={isBlurred}
|
||||
/>
|
||||
</Stack>
|
||||
<IconButton icon={<OptionsIcon />} blurred={isBlurred} />
|
||||
<DropdownMenu>
|
||||
<IconButton icon={<OptionsIcon />} />
|
||||
|
||||
<DropdownMenu.Content align="end" sideOffset={4}>
|
||||
<DropdownMenu.Item
|
||||
icon={<CommunitiesIcon />}
|
||||
label="View channel members and details"
|
||||
onSelect={() => console.log('click')}
|
||||
/>
|
||||
<DropdownMenu.Item
|
||||
icon={<MutedIcon />}
|
||||
label="Mute channel"
|
||||
onSelect={() => console.log('click')}
|
||||
/>
|
||||
<DropdownMenu.Item
|
||||
icon={<UpToDateIcon />}
|
||||
label="Mark as read"
|
||||
onSelect={() => console.log('click')}
|
||||
/>
|
||||
<DropdownMenu.Item
|
||||
icon={<DownloadIcon />}
|
||||
label="Fetch messages"
|
||||
onSelect={() => console.log('click')}
|
||||
/>
|
||||
<DropdownMenu.Item
|
||||
icon={<ShareIcon />}
|
||||
label="Share link to the channel"
|
||||
onSelect={() => console.log('click')}
|
||||
/>
|
||||
|
||||
<DropdownMenu.Separator />
|
||||
|
||||
<DropdownMenu.Item
|
||||
icon={<DeleteIcon />}
|
||||
label="Clear history"
|
||||
onSelect={() => console.log('click')}
|
||||
danger
|
||||
/>
|
||||
</DropdownMenu.Content>
|
||||
</DropdownMenu>
|
||||
</Stack>
|
||||
</Stack>
|
||||
</BlurView>
|
||||
|
|
|
@ -23,7 +23,6 @@ export default defineConfig(({ mode }) => {
|
|||
'./src/reactions/index.ts',
|
||||
],
|
||||
fileName(format, entryName) {
|
||||
console.log('fileName > format, entryName', format, entryName)
|
||||
// const [name] = entryName.split('/')
|
||||
return `icons-${entryName}.${format}.js`
|
||||
},
|
||||
|
|
224
yarn.lock
224
yarn.lock
|
@ -3612,6 +3612,14 @@
|
|||
"@babel/runtime" "^7.13.10"
|
||||
"@radix-ui/react-primitive" "1.0.0"
|
||||
|
||||
"@radix-ui/react-arrow@1.0.1":
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-arrow/-/react-arrow-1.0.1.tgz#5246adf79e97f89e819af68da51ddcf349ecf1c4"
|
||||
integrity sha512-1yientwXqXcErDHEv8av9ZVNEBldH8L9scVR3is20lL+jOCfcJyMFZFEY5cgIrgexsq1qggSXqiEL/d/4f+QXA==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.13.10"
|
||||
"@radix-ui/react-primitive" "1.0.1"
|
||||
|
||||
"@radix-ui/react-checkbox@^0.1.5":
|
||||
version "0.1.5"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-checkbox/-/react-checkbox-0.1.5.tgz#3a6bd54ba1720c8e5c03852acf460e35dfbe9da3"
|
||||
|
@ -3665,6 +3673,17 @@
|
|||
"@radix-ui/react-primitive" "1.0.0"
|
||||
"@radix-ui/react-slot" "1.0.0"
|
||||
|
||||
"@radix-ui/react-collection@1.0.1":
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-collection/-/react-collection-1.0.1.tgz#259506f97c6703b36291826768d3c1337edd1de5"
|
||||
integrity sha512-uuiFbs+YCKjn3X1DTSx9G7BHApu4GHbi3kgiwsnFUbOKCrwejAJv4eE4Vc8C0Oaxt9T0aV4ox0WCOdx+39Xo+g==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.13.10"
|
||||
"@radix-ui/react-compose-refs" "1.0.0"
|
||||
"@radix-ui/react-context" "1.0.0"
|
||||
"@radix-ui/react-primitive" "1.0.1"
|
||||
"@radix-ui/react-slot" "1.0.1"
|
||||
|
||||
"@radix-ui/react-compose-refs@0.1.0", "@radix-ui/react-compose-refs@^0.1.0":
|
||||
version "0.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-compose-refs/-/react-compose-refs-0.1.0.tgz#cff6e780a0f73778b976acff2c2a5b6551caab95"
|
||||
|
@ -3758,6 +3777,18 @@
|
|||
"@radix-ui/react-use-callback-ref" "1.0.0"
|
||||
"@radix-ui/react-use-escape-keydown" "1.0.0"
|
||||
|
||||
"@radix-ui/react-dismissable-layer@1.0.2":
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.0.2.tgz#f04d1061bddf00b1ca304148516b9ddc62e45fb2"
|
||||
integrity sha512-WjJzMrTWROozDqLB0uRWYvj4UuXsM/2L19EmQ3Au+IJWqwvwq9Bwd+P8ivo0Deg9JDPArR1I6MbWNi1CmXsskg==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.13.10"
|
||||
"@radix-ui/primitive" "1.0.0"
|
||||
"@radix-ui/react-compose-refs" "1.0.0"
|
||||
"@radix-ui/react-primitive" "1.0.1"
|
||||
"@radix-ui/react-use-callback-ref" "1.0.0"
|
||||
"@radix-ui/react-use-escape-keydown" "1.0.2"
|
||||
|
||||
"@radix-ui/react-dropdown-menu@^0.1.6":
|
||||
version "0.1.6"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-0.1.6.tgz#3203229788cd57e552c9f19dcc7008e2b545919c"
|
||||
|
@ -3772,6 +3803,20 @@
|
|||
"@radix-ui/react-primitive" "0.1.4"
|
||||
"@radix-ui/react-use-controllable-state" "0.1.0"
|
||||
|
||||
"@radix-ui/react-dropdown-menu@^2.0.2":
|
||||
version "2.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-2.0.2.tgz#758ca7733dc79b3a6523d2d5a8d33970ec7ece1b"
|
||||
integrity sha512-r0kN0fstrSi+uAdK2GkLxnnbhqVBy/9Q4o4PvGOYipW0BldQlYBMSmZprvCNj2i2mAATx16kvzIn12GnaGjbMw==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.13.10"
|
||||
"@radix-ui/primitive" "1.0.0"
|
||||
"@radix-ui/react-compose-refs" "1.0.0"
|
||||
"@radix-ui/react-context" "1.0.0"
|
||||
"@radix-ui/react-id" "1.0.0"
|
||||
"@radix-ui/react-menu" "2.0.2"
|
||||
"@radix-ui/react-primitive" "1.0.1"
|
||||
"@radix-ui/react-use-controllable-state" "1.0.0"
|
||||
|
||||
"@radix-ui/react-focus-guards@0.1.0":
|
||||
version "0.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-focus-guards/-/react-focus-guards-0.1.0.tgz#ba3b6f902cba7826569f8edc21ff8223dece7def"
|
||||
|
@ -3779,6 +3824,13 @@
|
|||
dependencies:
|
||||
"@babel/runtime" "^7.13.10"
|
||||
|
||||
"@radix-ui/react-focus-guards@1.0.0":
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-focus-guards/-/react-focus-guards-1.0.0.tgz#339c1c69c41628c1a5e655f15f7020bf11aa01fa"
|
||||
integrity sha512-UagjDk4ijOAnGu4WMUPj9ahi7/zJJqNZ9ZAiGPp7waUWJO0O1aWXi/udPphI0IUjvrhBsZJGSN66dR2dsueLWQ==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.13.10"
|
||||
|
||||
"@radix-ui/react-focus-scope@0.1.4":
|
||||
version "0.1.4"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-focus-scope/-/react-focus-scope-0.1.4.tgz#c830724e212d42ffaaa81aee49533213d09b47df"
|
||||
|
@ -3789,6 +3841,16 @@
|
|||
"@radix-ui/react-primitive" "0.1.4"
|
||||
"@radix-ui/react-use-callback-ref" "0.1.0"
|
||||
|
||||
"@radix-ui/react-focus-scope@1.0.1":
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-focus-scope/-/react-focus-scope-1.0.1.tgz#faea8c25f537c5a5c38c50914b63722db0e7f951"
|
||||
integrity sha512-Ej2MQTit8IWJiS2uuujGUmxXjF/y5xZptIIQnyd2JHLwtV0R2j9NRVoRj/1j/gJ7e3REdaBw4Hjf4a1ImhkZcQ==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.13.10"
|
||||
"@radix-ui/react-compose-refs" "1.0.0"
|
||||
"@radix-ui/react-primitive" "1.0.1"
|
||||
"@radix-ui/react-use-callback-ref" "1.0.0"
|
||||
|
||||
"@radix-ui/react-id@0.1.5":
|
||||
version "0.1.5"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-id/-/react-id-0.1.5.tgz#010d311bedd5a2884c1e9bb6aaaa4e6cc1d1d3b8"
|
||||
|
@ -3840,6 +3902,31 @@
|
|||
aria-hidden "^1.1.1"
|
||||
react-remove-scroll "^2.4.0"
|
||||
|
||||
"@radix-ui/react-menu@2.0.2":
|
||||
version "2.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-menu/-/react-menu-2.0.2.tgz#54d4e040407962af95ff3c66612749661a504de7"
|
||||
integrity sha512-H5dtBi/k3tc45IMd2Pu+Q2PyONFlsYJ5sWUlflSs8BQRghh5GhJHLRuB1yb88VOywuzzvGkaR/HUJJ65Jf2POA==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.13.10"
|
||||
"@radix-ui/primitive" "1.0.0"
|
||||
"@radix-ui/react-collection" "1.0.1"
|
||||
"@radix-ui/react-compose-refs" "1.0.0"
|
||||
"@radix-ui/react-context" "1.0.0"
|
||||
"@radix-ui/react-direction" "1.0.0"
|
||||
"@radix-ui/react-dismissable-layer" "1.0.2"
|
||||
"@radix-ui/react-focus-guards" "1.0.0"
|
||||
"@radix-ui/react-focus-scope" "1.0.1"
|
||||
"@radix-ui/react-id" "1.0.0"
|
||||
"@radix-ui/react-popper" "1.1.0"
|
||||
"@radix-ui/react-portal" "1.0.1"
|
||||
"@radix-ui/react-presence" "1.0.0"
|
||||
"@radix-ui/react-primitive" "1.0.1"
|
||||
"@radix-ui/react-roving-focus" "1.0.2"
|
||||
"@radix-ui/react-slot" "1.0.1"
|
||||
"@radix-ui/react-use-callback-ref" "1.0.0"
|
||||
aria-hidden "^1.1.1"
|
||||
react-remove-scroll "2.5.5"
|
||||
|
||||
"@radix-ui/react-popover@^0.1.6":
|
||||
version "0.1.6"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-popover/-/react-popover-0.1.6.tgz#788e969239d9c55239678e615ab591b6b7ba5cdc"
|
||||
|
@ -3861,6 +3948,28 @@
|
|||
aria-hidden "^1.1.1"
|
||||
react-remove-scroll "^2.4.0"
|
||||
|
||||
"@radix-ui/react-popover@^1.0.3":
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-popover/-/react-popover-1.0.3.tgz#65ae2ee1fca2d7fd750308549eb8e0857c6160fe"
|
||||
integrity sha512-YwedSukfWsyJs3/yP3yXUq44k4/JBe3jqU63Z8v2i19qZZ3dsx32oma17ztgclWPNuqp3A+Xa9UiDlZHyVX8Vg==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.13.10"
|
||||
"@radix-ui/primitive" "1.0.0"
|
||||
"@radix-ui/react-compose-refs" "1.0.0"
|
||||
"@radix-ui/react-context" "1.0.0"
|
||||
"@radix-ui/react-dismissable-layer" "1.0.2"
|
||||
"@radix-ui/react-focus-guards" "1.0.0"
|
||||
"@radix-ui/react-focus-scope" "1.0.1"
|
||||
"@radix-ui/react-id" "1.0.0"
|
||||
"@radix-ui/react-popper" "1.1.0"
|
||||
"@radix-ui/react-portal" "1.0.1"
|
||||
"@radix-ui/react-presence" "1.0.0"
|
||||
"@radix-ui/react-primitive" "1.0.1"
|
||||
"@radix-ui/react-slot" "1.0.1"
|
||||
"@radix-ui/react-use-controllable-state" "1.0.0"
|
||||
aria-hidden "^1.1.1"
|
||||
react-remove-scroll "2.5.5"
|
||||
|
||||
"@radix-ui/react-popper@0.1.4":
|
||||
version "0.1.4"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-popper/-/react-popper-0.1.4.tgz#dfc055dcd7dfae6a2eff7a70d333141d15a5d029"
|
||||
|
@ -3892,6 +4001,23 @@
|
|||
"@radix-ui/react-use-size" "1.0.0"
|
||||
"@radix-ui/rect" "1.0.0"
|
||||
|
||||
"@radix-ui/react-popper@1.1.0":
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-popper/-/react-popper-1.1.0.tgz#2be7e4c0cd4581f54277ca33a981c9037d2a8e60"
|
||||
integrity sha512-07U7jpI0dZcLRAxT7L9qs6HecSoPhDSJybF7mEGHJDBDv+ZoGCvIlva0s+WxMXwJEav+ckX3hAlXBtnHmuvlCQ==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.13.10"
|
||||
"@floating-ui/react-dom" "0.7.2"
|
||||
"@radix-ui/react-arrow" "1.0.1"
|
||||
"@radix-ui/react-compose-refs" "1.0.0"
|
||||
"@radix-ui/react-context" "1.0.0"
|
||||
"@radix-ui/react-primitive" "1.0.1"
|
||||
"@radix-ui/react-use-callback-ref" "1.0.0"
|
||||
"@radix-ui/react-use-layout-effect" "1.0.0"
|
||||
"@radix-ui/react-use-rect" "1.0.0"
|
||||
"@radix-ui/react-use-size" "1.0.0"
|
||||
"@radix-ui/rect" "1.0.0"
|
||||
|
||||
"@radix-ui/react-portal@0.1.4":
|
||||
version "0.1.4"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-portal/-/react-portal-0.1.4.tgz#17bdce3d7f1a9a0b35cb5e935ab8bc562441a7d2"
|
||||
|
@ -3909,6 +4035,14 @@
|
|||
"@babel/runtime" "^7.13.10"
|
||||
"@radix-ui/react-primitive" "1.0.0"
|
||||
|
||||
"@radix-ui/react-portal@1.0.1":
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-portal/-/react-portal-1.0.1.tgz#169c5a50719c2bb0079cf4c91a27aa6d37e5dd33"
|
||||
integrity sha512-NY2vUWI5WENgAT1nfC6JS7RU5xRYBfjZVLq0HmgEN1Ezy3rk/UruMV4+Rd0F40PEaFC5SrLS1ixYvcYIQrb4Ig==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.13.10"
|
||||
"@radix-ui/react-primitive" "1.0.1"
|
||||
|
||||
"@radix-ui/react-presence@0.1.2":
|
||||
version "0.1.2"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-presence/-/react-presence-0.1.2.tgz#9f11cce3df73cf65bc348e8b76d891f0d54c1fe3"
|
||||
|
@ -3943,6 +4077,14 @@
|
|||
"@babel/runtime" "^7.13.10"
|
||||
"@radix-ui/react-slot" "1.0.0"
|
||||
|
||||
"@radix-ui/react-primitive@1.0.1":
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-primitive/-/react-primitive-1.0.1.tgz#c1ebcce283dd2f02e4fbefdaa49d1cb13dbc990a"
|
||||
integrity sha512-fHbmislWVkZaIdeF6GZxF0A/NH/3BjrGIYj+Ae6eTmTCr7EB0RQAAVEiqsXK6p3/JcRqVSBQoceZroj30Jj3XA==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.13.10"
|
||||
"@radix-ui/react-slot" "1.0.1"
|
||||
|
||||
"@radix-ui/react-roving-focus@0.1.5":
|
||||
version "0.1.5"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-roving-focus/-/react-roving-focus-0.1.5.tgz#cc48d17a36b56f253d54905b0fd60ee134cb97ee"
|
||||
|
@ -3974,6 +4116,22 @@
|
|||
"@radix-ui/react-use-callback-ref" "1.0.0"
|
||||
"@radix-ui/react-use-controllable-state" "1.0.0"
|
||||
|
||||
"@radix-ui/react-roving-focus@1.0.2":
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-roving-focus/-/react-roving-focus-1.0.2.tgz#d8ac2e3b8006697bdfc2b0eb06bef7e15b6245de"
|
||||
integrity sha512-HLK+CqD/8pN6GfJm3U+cqpqhSKYAWiOJDe+A+8MfxBnOue39QEeMa43csUn2CXCHQT0/mewh1LrrG4tfkM9DMA==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.13.10"
|
||||
"@radix-ui/primitive" "1.0.0"
|
||||
"@radix-ui/react-collection" "1.0.1"
|
||||
"@radix-ui/react-compose-refs" "1.0.0"
|
||||
"@radix-ui/react-context" "1.0.0"
|
||||
"@radix-ui/react-direction" "1.0.0"
|
||||
"@radix-ui/react-id" "1.0.0"
|
||||
"@radix-ui/react-primitive" "1.0.1"
|
||||
"@radix-ui/react-use-callback-ref" "1.0.0"
|
||||
"@radix-ui/react-use-controllable-state" "1.0.0"
|
||||
|
||||
"@radix-ui/react-separator@^0.1.4":
|
||||
version "0.1.4"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-separator/-/react-separator-0.1.4.tgz#383ad0f82b364d9982a978d752084af3598e4090"
|
||||
|
@ -3998,6 +4156,14 @@
|
|||
"@babel/runtime" "^7.13.10"
|
||||
"@radix-ui/react-compose-refs" "1.0.0"
|
||||
|
||||
"@radix-ui/react-slot@1.0.1":
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-slot/-/react-slot-1.0.1.tgz#e7868c669c974d649070e9ecbec0b367ee0b4d81"
|
||||
integrity sha512-avutXAFL1ehGvAXtPquu0YK5oz6ctS474iM3vNGQIkswrVhdrS52e3uoMQBzZhNRAIE0jBnUyXWNmSjGHhCFcw==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.13.10"
|
||||
"@radix-ui/react-compose-refs" "1.0.0"
|
||||
|
||||
"@radix-ui/react-tabs@^1.0.0":
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-tabs/-/react-tabs-1.0.0.tgz#135c67f1f2bd9ada69a3f6e38dd897d459af5fe5"
|
||||
|
@ -4073,6 +4239,25 @@
|
|||
"@radix-ui/react-use-controllable-state" "1.0.0"
|
||||
"@radix-ui/react-visually-hidden" "1.0.0"
|
||||
|
||||
"@radix-ui/react-tooltip@^1.0.3":
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-tooltip/-/react-tooltip-1.0.3.tgz#a8c7e7b2b542cdfe7e94122af79079f7de3f90ff"
|
||||
integrity sha512-cmc9qV4KpgqdXVTn1K8KN8MnuSXvw+E719pKwyvpCGrQ+0AA2qTjcIL3uxCj4jc4k3sDR36RF7R3H7N5hPybBQ==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.13.10"
|
||||
"@radix-ui/primitive" "1.0.0"
|
||||
"@radix-ui/react-compose-refs" "1.0.0"
|
||||
"@radix-ui/react-context" "1.0.0"
|
||||
"@radix-ui/react-dismissable-layer" "1.0.2"
|
||||
"@radix-ui/react-id" "1.0.0"
|
||||
"@radix-ui/react-popper" "1.1.0"
|
||||
"@radix-ui/react-portal" "1.0.1"
|
||||
"@radix-ui/react-presence" "1.0.0"
|
||||
"@radix-ui/react-primitive" "1.0.1"
|
||||
"@radix-ui/react-slot" "1.0.1"
|
||||
"@radix-ui/react-use-controllable-state" "1.0.0"
|
||||
"@radix-ui/react-visually-hidden" "1.0.1"
|
||||
|
||||
"@radix-ui/react-use-body-pointer-events@0.1.1":
|
||||
version "0.1.1"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-use-body-pointer-events/-/react-use-body-pointer-events-0.1.1.tgz#63e7fd81ca7ffd30841deb584cd2b7f460df2597"
|
||||
|
@ -4134,6 +4319,14 @@
|
|||
"@babel/runtime" "^7.13.10"
|
||||
"@radix-ui/react-use-callback-ref" "1.0.0"
|
||||
|
||||
"@radix-ui/react-use-escape-keydown@1.0.2":
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.0.2.tgz#09ab6455ab240b4f0a61faf06d4e5132c4d639f6"
|
||||
integrity sha512-DXGim3x74WgUv+iMNCF+cAo8xUHHeqvjx8zs7trKf+FkQKPQXLk2sX7Gx1ysH7Q76xCpZuxIJE7HLPxRE+Q+GA==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.13.10"
|
||||
"@radix-ui/react-use-callback-ref" "1.0.0"
|
||||
|
||||
"@radix-ui/react-use-layout-effect@0.1.0":
|
||||
version "0.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-0.1.0.tgz#ebf71bd6d2825de8f1fbb984abf2293823f0f223"
|
||||
|
@ -4202,6 +4395,14 @@
|
|||
"@babel/runtime" "^7.13.10"
|
||||
"@radix-ui/react-primitive" "1.0.0"
|
||||
|
||||
"@radix-ui/react-visually-hidden@1.0.1":
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.0.1.tgz#9a4ac4fc97ae8d72a10e727f16b3121b5f0aa469"
|
||||
integrity sha512-K1hJcCMfWfiYUibRqf3V8r5Drpyf7rh44jnrwAbdvI5iCCijilBBeyQv9SKidYNZIopMdCyR9FnIjkHxHN0FcQ==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.13.10"
|
||||
"@radix-ui/react-primitive" "1.0.1"
|
||||
|
||||
"@radix-ui/rect@0.1.1":
|
||||
version "0.1.1"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/rect/-/rect-0.1.1.tgz#95b5ba51f469bea6b1b841e2d427e17e37d38419"
|
||||
|
@ -14437,6 +14638,7 @@ node-fetch-native@^1.0.1:
|
|||
|
||||
node-fetch@2.6.7, node-fetch@^2.2.0, node-fetch@^2.6.0, node-fetch@^2.6.1, node-fetch@^2.6.7, node-fetch@^2.x.x:
|
||||
version "2.6.7"
|
||||
uid "1b5d62978f2ed07b99444f64f0df39f960a6d34d"
|
||||
resolved "https://registry.npmjs.org/@achingbrain/node-fetch/-/node-fetch-2.6.7.tgz#1b5d62978f2ed07b99444f64f0df39f960a6d34d"
|
||||
|
||||
node-forge@^1.1.0, node-forge@^1.2.1, node-forge@^1.3.1:
|
||||
|
@ -15883,6 +16085,17 @@ react-remove-scroll-bar@^2.3.3:
|
|||
react-style-singleton "^2.2.1"
|
||||
tslib "^2.0.0"
|
||||
|
||||
react-remove-scroll@2.5.5, react-remove-scroll@^2.5.5:
|
||||
version "2.5.5"
|
||||
resolved "https://registry.yarnpkg.com/react-remove-scroll/-/react-remove-scroll-2.5.5.tgz#1e31a1260df08887a8a0e46d09271b52b3a37e77"
|
||||
integrity sha512-ImKhrzJJsyXJfBZ4bzu8Bwpka14c/fQt0k+cyFp/PBhTfyDnU5hjOtM4AG/0AMyy8oKzOTR0lDgJIM7pYXI0kw==
|
||||
dependencies:
|
||||
react-remove-scroll-bar "^2.3.3"
|
||||
react-style-singleton "^2.2.1"
|
||||
tslib "^2.1.0"
|
||||
use-callback-ref "^1.3.0"
|
||||
use-sidecar "^1.1.2"
|
||||
|
||||
react-remove-scroll@^2.4.0:
|
||||
version "2.4.4"
|
||||
resolved "https://registry.yarnpkg.com/react-remove-scroll/-/react-remove-scroll-2.4.4.tgz#2dfff377cf17efc00de39dad51c143fc7a1b9e3e"
|
||||
|
@ -15894,17 +16107,6 @@ react-remove-scroll@^2.4.0:
|
|||
use-callback-ref "^1.2.3"
|
||||
use-sidecar "^1.0.1"
|
||||
|
||||
react-remove-scroll@^2.5.5:
|
||||
version "2.5.5"
|
||||
resolved "https://registry.yarnpkg.com/react-remove-scroll/-/react-remove-scroll-2.5.5.tgz#1e31a1260df08887a8a0e46d09271b52b3a37e77"
|
||||
integrity sha512-ImKhrzJJsyXJfBZ4bzu8Bwpka14c/fQt0k+cyFp/PBhTfyDnU5hjOtM4AG/0AMyy8oKzOTR0lDgJIM7pYXI0kw==
|
||||
dependencies:
|
||||
react-remove-scroll-bar "^2.3.3"
|
||||
react-style-singleton "^2.2.1"
|
||||
tslib "^2.1.0"
|
||||
use-callback-ref "^1.3.0"
|
||||
use-sidecar "^1.1.2"
|
||||
|
||||
react-router-dom@^6.3.0:
|
||||
version "6.3.0"
|
||||
resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-6.3.0.tgz#a0216da813454e521905b5fa55e0e5176123f43d"
|
||||
|
|
Loading…
Reference in New Issue