add Step (#463)
* u tabs * u stories * a steps * f tabs * a changeset * u tabs * e step
This commit is contained in:
parent
6c24833a91
commit
762a698be2
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
'@status-im/components': minor
|
||||||
|
---
|
||||||
|
|
||||||
|
add Step and Tabs with Step
|
|
@ -22,6 +22,7 @@ export * from './provider'
|
||||||
export * from './shadow'
|
export * from './shadow'
|
||||||
export * from './shortcut'
|
export * from './shortcut'
|
||||||
export * from './skeleton'
|
export * from './skeleton'
|
||||||
|
export * from './step'
|
||||||
export * from './tabs'
|
export * from './tabs'
|
||||||
export * from './tag'
|
export * from './tag'
|
||||||
export * from './text'
|
export * from './text'
|
||||||
|
|
|
@ -68,6 +68,7 @@ export const ReactionsDialog = (props: Props) => {
|
||||||
const Icon = REACTIONS_ICONS[reaction as keyof ReactionsType]
|
const Icon = REACTIONS_ICONS[reaction as keyof ReactionsType]
|
||||||
return (
|
return (
|
||||||
<Tabs.Trigger
|
<Tabs.Trigger
|
||||||
|
type="icon"
|
||||||
key={reaction}
|
key={reaction}
|
||||||
value={reaction}
|
value={reaction}
|
||||||
icon={<Icon size={20} />}
|
icon={<Icon size={20} />}
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
export { Step, type StepProps } from './step'
|
|
@ -0,0 +1,78 @@
|
||||||
|
import { Stack } from '@tamagui/core'
|
||||||
|
|
||||||
|
import { Step } from './step'
|
||||||
|
|
||||||
|
import type { StepProps } from './step'
|
||||||
|
import type { Meta, StoryObj } from '@storybook/react'
|
||||||
|
|
||||||
|
const meta: Meta<typeof Step> = {
|
||||||
|
title: 'Components/Step',
|
||||||
|
component: Step,
|
||||||
|
argTypes: {
|
||||||
|
value: {
|
||||||
|
control: {
|
||||||
|
type: 'number',
|
||||||
|
min: 0,
|
||||||
|
max: 1000,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
type: {
|
||||||
|
control: 'select',
|
||||||
|
options: ['neutral', 'complete', 'active'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
parameters: {
|
||||||
|
design: {
|
||||||
|
type: 'figma',
|
||||||
|
url: 'https://www.figma.com/file/IBmFKgGL1B4GzqD8LQTw6n/Design-System-for-Desktop%2FWeb?type=design&node-id=18126-5278&mode=design&t=QNu79iGJYnhdNqOn-4',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
type Story = StoryObj<StepProps>
|
||||||
|
|
||||||
|
export const Neutral: Story = {
|
||||||
|
args: {
|
||||||
|
value: 1,
|
||||||
|
type: 'neutral',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export const Complete: Story = {
|
||||||
|
args: {
|
||||||
|
value: 1,
|
||||||
|
type: 'complete',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export const Active: Story = {
|
||||||
|
args: {
|
||||||
|
value: 1,
|
||||||
|
type: 'active',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export const AllVariants: Story = {
|
||||||
|
args: {},
|
||||||
|
render: () => (
|
||||||
|
<Stack space flexDirection="row">
|
||||||
|
<Stack space>
|
||||||
|
<Step type="neutral" value={1} />
|
||||||
|
<Step type="neutral" value={10} />
|
||||||
|
<Step type="neutral" value={999} />
|
||||||
|
</Stack>
|
||||||
|
<Stack space>
|
||||||
|
<Step type="complete" value={1} />
|
||||||
|
<Step type="complete" value={10} />
|
||||||
|
<Step type="complete" value={999} />
|
||||||
|
</Stack>
|
||||||
|
<Stack space>
|
||||||
|
<Step type="active" value={1} />
|
||||||
|
<Step type="active" value={10} />
|
||||||
|
<Step type="active" value={999} />
|
||||||
|
</Stack>
|
||||||
|
</Stack>
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
export default meta
|
|
@ -0,0 +1,74 @@
|
||||||
|
import { Stack, styled } from '@tamagui/core'
|
||||||
|
|
||||||
|
import { Text } from '../text'
|
||||||
|
|
||||||
|
import type { ColorTokens } from '@tamagui/core'
|
||||||
|
|
||||||
|
// todo?: rename netural to default
|
||||||
|
export type StepVariants = 'neutral' | 'complete' | 'active'
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
value: number
|
||||||
|
type?: StepVariants
|
||||||
|
}
|
||||||
|
|
||||||
|
const Step = (props: Props) => {
|
||||||
|
const { value, type = 'neutral' } = props
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Base>
|
||||||
|
<Content type={type}>
|
||||||
|
<Text size={11} weight="medium" color={textColors[type]}>
|
||||||
|
{value}
|
||||||
|
</Text>
|
||||||
|
</Content>
|
||||||
|
</Base>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export { Step }
|
||||||
|
export type { Props as StepProps }
|
||||||
|
|
||||||
|
const Base = styled(Stack, {
|
||||||
|
padding: 2,
|
||||||
|
display: 'inline-flex',
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center',
|
||||||
|
flexBasis: 'fit-content',
|
||||||
|
})
|
||||||
|
|
||||||
|
const Content = styled(Stack, {
|
||||||
|
backgroundColor: '$white-100',
|
||||||
|
paddingHorizontal: 3,
|
||||||
|
paddingVertical: 0,
|
||||||
|
borderRadius: '$6',
|
||||||
|
minHeight: 18,
|
||||||
|
maxHeight: 18,
|
||||||
|
minWidth: 18,
|
||||||
|
maxWidth: 28,
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center',
|
||||||
|
borderWidth: 1,
|
||||||
|
borderColor: 'transparent',
|
||||||
|
|
||||||
|
variants: {
|
||||||
|
type: {
|
||||||
|
neutral: {
|
||||||
|
backgroundColor: '$transparent',
|
||||||
|
borderColor: '$neutral-20',
|
||||||
|
},
|
||||||
|
complete: {
|
||||||
|
backgroundColor: '$blue-50',
|
||||||
|
},
|
||||||
|
active: {
|
||||||
|
backgroundColor: '$blue-50-opa-10',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const textColors: Record<NonNullable<Props['type']>, ColorTokens> = {
|
||||||
|
neutral: '$neutral-100',
|
||||||
|
complete: '$white-100',
|
||||||
|
active: '$neutral-100',
|
||||||
|
}
|
|
@ -3,8 +3,8 @@ import { PlaceholderIcon } from '@status-im/icons'
|
||||||
import { Text } from '../text'
|
import { Text } from '../text'
|
||||||
import { Tabs } from './tabs'
|
import { Tabs } from './tabs'
|
||||||
|
|
||||||
|
import type { TabsProps } from './tabs'
|
||||||
import type { Meta, StoryObj } from '@storybook/react'
|
import type { Meta, StoryObj } from '@storybook/react'
|
||||||
import type { ComponentProps } from 'react'
|
|
||||||
|
|
||||||
const meta: Meta<typeof Tabs> = {
|
const meta: Meta<typeof Tabs> = {
|
||||||
component: Tabs,
|
component: Tabs,
|
||||||
|
@ -18,40 +18,129 @@ const meta: Meta<typeof Tabs> = {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
type Story = StoryObj<{ size: 24 | 32; icon: boolean; count: boolean }>
|
export const Default: StoryObj<TabsProps> = {
|
||||||
|
|
||||||
export const Default: Story = {
|
|
||||||
name: 'Default',
|
|
||||||
args: {
|
args: {
|
||||||
size: 24,
|
defaultValue: '1',
|
||||||
icon: false,
|
|
||||||
},
|
|
||||||
argTypes: {
|
|
||||||
size: {
|
|
||||||
control: 'select',
|
|
||||||
options: [24, 32] satisfies ComponentProps<typeof Tabs.List>['size'][],
|
|
||||||
},
|
|
||||||
icon: {
|
|
||||||
control: 'boolean',
|
|
||||||
},
|
|
||||||
count: {
|
|
||||||
control: 'boolean',
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
render(args) {
|
render(args) {
|
||||||
const icon = args.icon ? <PlaceholderIcon size={20} /> : undefined
|
|
||||||
const count = args.count ? 8 : undefined
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Tabs defaultValue="1">
|
<Tabs {...args}>
|
||||||
<Tabs.List size={args.size}>
|
<Tabs.List size={32}>
|
||||||
<Tabs.Trigger value="1" icon={icon} count={count}>
|
<Tabs.Trigger type="default" value="1">
|
||||||
Tab 1
|
Tab 1
|
||||||
</Tabs.Trigger>
|
</Tabs.Trigger>
|
||||||
<Tabs.Trigger value="2" icon={icon}>
|
<Tabs.Trigger type="default" value="2">
|
||||||
Tab 2
|
Tab 2
|
||||||
</Tabs.Trigger>
|
</Tabs.Trigger>
|
||||||
<Tabs.Trigger value="3" icon={icon}>
|
<Tabs.Trigger type="default" value="3">
|
||||||
|
Tab 3
|
||||||
|
</Tabs.Trigger>
|
||||||
|
</Tabs.List>
|
||||||
|
<Tabs.Content value="1">
|
||||||
|
<Text size={15}>Content 1</Text>
|
||||||
|
</Tabs.Content>
|
||||||
|
<Tabs.Content value="2">
|
||||||
|
<Text size={15}>Content 2</Text>
|
||||||
|
</Tabs.Content>
|
||||||
|
<Tabs.Content value="3">
|
||||||
|
<Text size={15}>Content 3</Text>
|
||||||
|
</Tabs.Content>
|
||||||
|
</Tabs>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export const Icon: StoryObj<TabsProps> = {
|
||||||
|
args: {
|
||||||
|
defaultValue: '1',
|
||||||
|
},
|
||||||
|
render(args) {
|
||||||
|
return (
|
||||||
|
<Tabs {...args}>
|
||||||
|
<Tabs.List size={32}>
|
||||||
|
<Tabs.Trigger
|
||||||
|
type="icon"
|
||||||
|
value="1"
|
||||||
|
icon={<PlaceholderIcon size={16} />}
|
||||||
|
>
|
||||||
|
Tab 1
|
||||||
|
</Tabs.Trigger>
|
||||||
|
<Tabs.Trigger
|
||||||
|
type="icon"
|
||||||
|
value="2"
|
||||||
|
icon={<PlaceholderIcon size={16} />}
|
||||||
|
>
|
||||||
|
Tab 2
|
||||||
|
</Tabs.Trigger>
|
||||||
|
<Tabs.Trigger
|
||||||
|
type="icon"
|
||||||
|
value="3"
|
||||||
|
icon={<PlaceholderIcon size={16} />}
|
||||||
|
>
|
||||||
|
Tab 3
|
||||||
|
</Tabs.Trigger>
|
||||||
|
</Tabs.List>
|
||||||
|
<Tabs.Content value="1">
|
||||||
|
<Text size={15}>Content 1</Text>
|
||||||
|
</Tabs.Content>
|
||||||
|
<Tabs.Content value="2">
|
||||||
|
<Text size={15}>Content 2</Text>
|
||||||
|
</Tabs.Content>
|
||||||
|
<Tabs.Content value="3">
|
||||||
|
<Text size={15}>Content 3</Text>
|
||||||
|
</Tabs.Content>
|
||||||
|
</Tabs>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export const Counter: StoryObj<TabsProps> = {
|
||||||
|
args: {
|
||||||
|
defaultValue: '1',
|
||||||
|
},
|
||||||
|
render(args) {
|
||||||
|
return (
|
||||||
|
<Tabs {...args}>
|
||||||
|
<Tabs.List size={32}>
|
||||||
|
<Tabs.Trigger type="counter" value="1" count={5}>
|
||||||
|
Tab 1
|
||||||
|
</Tabs.Trigger>
|
||||||
|
<Tabs.Trigger type="counter" value="2" count={10}>
|
||||||
|
Tab 2
|
||||||
|
</Tabs.Trigger>
|
||||||
|
<Tabs.Trigger type="counter" value="3" count={100}>
|
||||||
|
Tab 3
|
||||||
|
</Tabs.Trigger>
|
||||||
|
</Tabs.List>
|
||||||
|
<Tabs.Content value="1">
|
||||||
|
<Text size={15}>Content 1</Text>
|
||||||
|
</Tabs.Content>
|
||||||
|
<Tabs.Content value="2">
|
||||||
|
<Text size={15}>Content 2</Text>
|
||||||
|
</Tabs.Content>
|
||||||
|
<Tabs.Content value="3">
|
||||||
|
<Text size={15}>Content 3</Text>
|
||||||
|
</Tabs.Content>
|
||||||
|
</Tabs>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export const Step: StoryObj<TabsProps> = {
|
||||||
|
args: {
|
||||||
|
defaultValue: '1',
|
||||||
|
},
|
||||||
|
render(args) {
|
||||||
|
return (
|
||||||
|
<Tabs {...args}>
|
||||||
|
<Tabs.List size={32}>
|
||||||
|
<Tabs.Trigger type="step" value="1" step={1}>
|
||||||
|
Tab 1
|
||||||
|
</Tabs.Trigger>
|
||||||
|
<Tabs.Trigger type="step" value="2" step={10}>
|
||||||
|
Tab 2
|
||||||
|
</Tabs.Trigger>
|
||||||
|
<Tabs.Trigger type="step" value="3" step={999}>
|
||||||
Tab 3
|
Tab 3
|
||||||
</Tabs.Trigger>
|
</Tabs.Trigger>
|
||||||
</Tabs.List>
|
</Tabs.List>
|
||||||
|
|
|
@ -7,6 +7,7 @@ import { styled } from 'tamagui'
|
||||||
|
|
||||||
import { Counter } from '../counter'
|
import { Counter } from '../counter'
|
||||||
import { usePressableColors } from '../hooks/use-pressable-colors'
|
import { usePressableColors } from '../hooks/use-pressable-colors'
|
||||||
|
import { Step } from '../step'
|
||||||
import { Text } from '../text'
|
import { Text } from '../text'
|
||||||
|
|
||||||
import type { TextProps } from '../text'
|
import type { TextProps } from '../text'
|
||||||
|
@ -16,6 +17,7 @@ import type { Ref } from 'react'
|
||||||
type Variants = GetVariants<typeof TriggerBase>
|
type Variants = GetVariants<typeof TriggerBase>
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
|
// type: TriggerProps['type']
|
||||||
children: React.ReactNode[]
|
children: React.ReactNode[]
|
||||||
defaultValue: string
|
defaultValue: string
|
||||||
value?: string
|
value?: string
|
||||||
|
@ -57,16 +59,28 @@ const TabsList = (props: ListProps) => {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
type TriggerProps = {
|
type TriggerProps =
|
||||||
value: string
|
| {
|
||||||
children: string
|
type: 'default'
|
||||||
icon?: React.ReactElement
|
value: string
|
||||||
count?: number
|
children: string
|
||||||
}
|
}
|
||||||
|
| {
|
||||||
|
type: 'icon'
|
||||||
|
value: string
|
||||||
|
children: string
|
||||||
|
icon: React.ReactElement
|
||||||
|
}
|
||||||
|
| { type: 'counter'; value: string; children: string; count: number }
|
||||||
|
| {
|
||||||
|
type: 'step'
|
||||||
|
value: string
|
||||||
|
children: string
|
||||||
|
step: number
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: Add counter
|
|
||||||
const TabsTrigger = (props: TriggerProps, ref: Ref<View>) => {
|
const TabsTrigger = (props: TriggerProps, ref: Ref<View>) => {
|
||||||
const { icon = null, children, count, ...triggerProps } = props
|
const { children, ...triggerProps } = props
|
||||||
|
|
||||||
// props coming from parent List and Trigger, not passed by the user (line 52)
|
// props coming from parent List and Trigger, not passed by the user (line 52)
|
||||||
const providedProps = props as TriggerProps & {
|
const providedProps = props as TriggerProps & {
|
||||||
|
@ -96,13 +110,18 @@ const TabsTrigger = (props: TriggerProps, ref: Ref<View>) => {
|
||||||
size={size}
|
size={size}
|
||||||
active={selected}
|
active={selected}
|
||||||
>
|
>
|
||||||
{icon && cloneElement(icon, { size: iconSizes[size] })}
|
{props.type === 'icon' &&
|
||||||
|
cloneElement(props.icon, { size: iconSizes[size] })}
|
||||||
|
|
||||||
|
{props.type === 'step' && <Step type="complete" value={props.step} />}
|
||||||
|
|
||||||
<Text size={textSize} weight="medium" color={color}>
|
<Text size={textSize} weight="medium" color={color}>
|
||||||
{children}
|
{children}
|
||||||
</Text>
|
</Text>
|
||||||
{count && (
|
|
||||||
|
{props.type === 'counter' && (
|
||||||
<Stack marginRight={-4}>
|
<Stack marginRight={-4}>
|
||||||
<Counter type="secondary" value={count} />
|
<Counter type="secondary" value={props.count} />
|
||||||
</Stack>
|
</Stack>
|
||||||
)}
|
)}
|
||||||
</TriggerBase>
|
</TriggerBase>
|
||||||
|
|
Loading…
Reference in New Issue