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 './shortcut'
|
||||
export * from './skeleton'
|
||||
export * from './step'
|
||||
export * from './tabs'
|
||||
export * from './tag'
|
||||
export * from './text'
|
||||
|
|
|
@ -68,6 +68,7 @@ export const ReactionsDialog = (props: Props) => {
|
|||
const Icon = REACTIONS_ICONS[reaction as keyof ReactionsType]
|
||||
return (
|
||||
<Tabs.Trigger
|
||||
type="icon"
|
||||
key={reaction}
|
||||
value={reaction}
|
||||
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 { Tabs } from './tabs'
|
||||
|
||||
import type { TabsProps } from './tabs'
|
||||
import type { Meta, StoryObj } from '@storybook/react'
|
||||
import type { ComponentProps } from 'react'
|
||||
|
||||
const meta: Meta<typeof 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: Story = {
|
||||
name: 'Default',
|
||||
export const Default: StoryObj<TabsProps> = {
|
||||
args: {
|
||||
size: 24,
|
||||
icon: false,
|
||||
},
|
||||
argTypes: {
|
||||
size: {
|
||||
control: 'select',
|
||||
options: [24, 32] satisfies ComponentProps<typeof Tabs.List>['size'][],
|
||||
},
|
||||
icon: {
|
||||
control: 'boolean',
|
||||
},
|
||||
count: {
|
||||
control: 'boolean',
|
||||
},
|
||||
defaultValue: '1',
|
||||
},
|
||||
render(args) {
|
||||
const icon = args.icon ? <PlaceholderIcon size={20} /> : undefined
|
||||
const count = args.count ? 8 : undefined
|
||||
|
||||
return (
|
||||
<Tabs defaultValue="1">
|
||||
<Tabs.List size={args.size}>
|
||||
<Tabs.Trigger value="1" icon={icon} count={count}>
|
||||
<Tabs {...args}>
|
||||
<Tabs.List size={32}>
|
||||
<Tabs.Trigger type="default" value="1">
|
||||
Tab 1
|
||||
</Tabs.Trigger>
|
||||
<Tabs.Trigger value="2" icon={icon}>
|
||||
<Tabs.Trigger type="default" value="2">
|
||||
Tab 2
|
||||
</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
|
||||
</Tabs.Trigger>
|
||||
</Tabs.List>
|
||||
|
|
|
@ -7,6 +7,7 @@ import { styled } from 'tamagui'
|
|||
|
||||
import { Counter } from '../counter'
|
||||
import { usePressableColors } from '../hooks/use-pressable-colors'
|
||||
import { Step } from '../step'
|
||||
import { Text } from '../text'
|
||||
|
||||
import type { TextProps } from '../text'
|
||||
|
@ -16,6 +17,7 @@ import type { Ref } from 'react'
|
|||
type Variants = GetVariants<typeof TriggerBase>
|
||||
|
||||
type Props = {
|
||||
// type: TriggerProps['type']
|
||||
children: React.ReactNode[]
|
||||
defaultValue: string
|
||||
value?: string
|
||||
|
@ -57,16 +59,28 @@ const TabsList = (props: ListProps) => {
|
|||
)
|
||||
}
|
||||
|
||||
type TriggerProps = {
|
||||
type TriggerProps =
|
||||
| {
|
||||
type: 'default'
|
||||
value: string
|
||||
children: string
|
||||
icon?: React.ReactElement
|
||||
count?: number
|
||||
}
|
||||
| {
|
||||
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 { icon = null, children, count, ...triggerProps } = props
|
||||
const { children, ...triggerProps } = props
|
||||
|
||||
// props coming from parent List and Trigger, not passed by the user (line 52)
|
||||
const providedProps = props as TriggerProps & {
|
||||
|
@ -96,13 +110,18 @@ const TabsTrigger = (props: TriggerProps, ref: Ref<View>) => {
|
|||
size={size}
|
||||
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}>
|
||||
{children}
|
||||
</Text>
|
||||
{count && (
|
||||
|
||||
{props.type === 'counter' && (
|
||||
<Stack marginRight={-4}>
|
||||
<Counter type="secondary" value={count} />
|
||||
<Counter type="secondary" value={props.count} />
|
||||
</Stack>
|
||||
)}
|
||||
</TriggerBase>
|
||||
|
|
Loading…
Reference in New Issue