diff --git a/.changeset/shy-parents-sparkle.md b/.changeset/shy-parents-sparkle.md
new file mode 100644
index 00000000..3a7de3e5
--- /dev/null
+++ b/.changeset/shy-parents-sparkle.md
@@ -0,0 +1,5 @@
+---
+'@status-im/components': minor
+---
+
+add Step and Tabs with Step
diff --git a/packages/components/src/index.tsx b/packages/components/src/index.tsx
index 701ab3ff..27a89501 100644
--- a/packages/components/src/index.tsx
+++ b/packages/components/src/index.tsx
@@ -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'
diff --git a/packages/components/src/messages/components/reactions-dialog.tsx b/packages/components/src/messages/components/reactions-dialog.tsx
index 80678ae5..dfc76805 100644
--- a/packages/components/src/messages/components/reactions-dialog.tsx
+++ b/packages/components/src/messages/components/reactions-dialog.tsx
@@ -68,6 +68,7 @@ export const ReactionsDialog = (props: Props) => {
const Icon = REACTIONS_ICONS[reaction as keyof ReactionsType]
return (
}
diff --git a/packages/components/src/step/index.tsx b/packages/components/src/step/index.tsx
new file mode 100644
index 00000000..fdbeb14f
--- /dev/null
+++ b/packages/components/src/step/index.tsx
@@ -0,0 +1 @@
+export { Step, type StepProps } from './step'
diff --git a/packages/components/src/step/step.stories.tsx b/packages/components/src/step/step.stories.tsx
new file mode 100644
index 00000000..63c8e429
--- /dev/null
+++ b/packages/components/src/step/step.stories.tsx
@@ -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 = {
+ 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
+
+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: () => (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ),
+}
+
+export default meta
diff --git a/packages/components/src/step/step.tsx b/packages/components/src/step/step.tsx
new file mode 100644
index 00000000..c777a26c
--- /dev/null
+++ b/packages/components/src/step/step.tsx
@@ -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 (
+
+
+
+ {value}
+
+
+
+ )
+}
+
+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, ColorTokens> = {
+ neutral: '$neutral-100',
+ complete: '$white-100',
+ active: '$neutral-100',
+}
diff --git a/packages/components/src/tabs/tabs.stories.tsx b/packages/components/src/tabs/tabs.stories.tsx
index 8c7e274b..de12a3ff 100644
--- a/packages/components/src/tabs/tabs.stories.tsx
+++ b/packages/components/src/tabs/tabs.stories.tsx
@@ -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 = {
component: Tabs,
@@ -18,40 +18,129 @@ const meta: Meta = {
},
}
-type Story = StoryObj<{ size: 24 | 32; icon: boolean; count: boolean }>
-
-export const Default: Story = {
- name: 'Default',
+export const Default: StoryObj = {
args: {
- size: 24,
- icon: false,
- },
- argTypes: {
- size: {
- control: 'select',
- options: [24, 32] satisfies ComponentProps['size'][],
- },
- icon: {
- control: 'boolean',
- },
- count: {
- control: 'boolean',
- },
+ defaultValue: '1',
},
render(args) {
- const icon = args.icon ? : undefined
- const count = args.count ? 8 : undefined
-
return (
-
-
-
+
+
+
Tab 1
-
+
Tab 2
-
+
+ Tab 3
+
+
+
+ Content 1
+
+
+ Content 2
+
+
+ Content 3
+
+
+ )
+ },
+}
+
+export const Icon: StoryObj = {
+ args: {
+ defaultValue: '1',
+ },
+ render(args) {
+ return (
+
+
+ }
+ >
+ Tab 1
+
+ }
+ >
+ Tab 2
+
+ }
+ >
+ Tab 3
+
+
+
+ Content 1
+
+
+ Content 2
+
+
+ Content 3
+
+
+ )
+ },
+}
+
+export const Counter: StoryObj = {
+ args: {
+ defaultValue: '1',
+ },
+ render(args) {
+ return (
+
+
+
+ Tab 1
+
+
+ Tab 2
+
+
+ Tab 3
+
+
+
+ Content 1
+
+
+ Content 2
+
+
+ Content 3
+
+
+ )
+ },
+}
+
+export const Step: StoryObj = {
+ args: {
+ defaultValue: '1',
+ },
+ render(args) {
+ return (
+
+
+
+ Tab 1
+
+
+ Tab 2
+
+
Tab 3
diff --git a/packages/components/src/tabs/tabs.tsx b/packages/components/src/tabs/tabs.tsx
index a470c5bf..b4c817a6 100644
--- a/packages/components/src/tabs/tabs.tsx
+++ b/packages/components/src/tabs/tabs.tsx
@@ -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
type Props = {
+ // type: TriggerProps['type']
children: React.ReactNode[]
defaultValue: string
value?: string
@@ -57,16 +59,28 @@ const TabsList = (props: ListProps) => {
)
}
-type TriggerProps = {
- value: string
- children: string
- icon?: React.ReactElement
- count?: number
-}
+type TriggerProps =
+ | {
+ type: 'default'
+ value: string
+ 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) => {
- 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) => {
size={size}
active={selected}
>
- {icon && cloneElement(icon, { size: iconSizes[size] })}
+ {props.type === 'icon' &&
+ cloneElement(props.icon, { size: iconSizes[size] })}
+
+ {props.type === 'step' && }
+
{children}
- {count && (
+
+ {props.type === 'counter' && (
-
+
)}