import type { Meta, StoryObj } from '@storybook/nextjs-vite'; import { Monitor, Smartphone, Tablet, Apple, Globe, Shield } from 'lucide-react'; import { useState } from 'react'; import { TabSelector, type TabSelectorItem } from '../components/ui/tab-selector'; const meta = { title: 'UI/TabSelector', component: TabSelector, parameters: { layout: 'centered', docs: { description: { component: 'A tab-style selector with primary (accent) and secondary (soft grey) variants. Supports icons, disabled states, and badges.', }, }, }, tags: ['autodocs'], argTypes: { variant: { control: 'select', options: ['primary', 'secondary'], description: 'Visual variant', }, label: { control: 'text', description: 'Optional label above the selector', }, }, decorators: [ (Story) => (
), ], } satisfies Meta; export default meta; type Story = StoryObj; const basicItems: TabSelectorItem[] = [ { id: 'tab1', label: 'Tab 1' }, { id: 'tab2', label: 'Tab 2' }, { id: 'tab3', label: 'Tab 3' }, ]; const fiveItems: TabSelectorItem[] = [ { id: 'tab1', label: 'Tab 1' }, { id: 'tab2', label: 'Tab 2' }, { id: 'tab3', label: 'Tab 3' }, { id: 'tab4', label: 'Tab 4' }, { id: 'tab5', label: 'Tab 5' }, ]; const itemsWithIcons: TabSelectorItem[] = [ { id: 'desktop', label: 'Desktop', icon: }, { id: 'tablet', label: 'Tablet', icon: }, { id: 'mobile', label: 'Mobile', icon: }, ]; /** * Primary variant with 3 tabs — active tab uses accent background. */ export const Primary: Story = { args: { value: 'tab1', items: basicItems, variant: 'primary', onValueChange: () => {}, }, render: function Render(args) { const [value, setValue] = useState(args.value); return ; }, }; /** * Secondary variant — active tab uses soft grey background. */ export const Secondary: Story = { args: { value: 'tab1', items: basicItems, variant: 'secondary', onValueChange: () => {}, }, render: function Render(args) { const [value, setValue] = useState(args.value); return ; }, }; /** * Five tabs matching the full Figma design spec. */ export const FiveTabs: Story = { args: { value: 'tab1', items: fiveItems, variant: 'primary', onValueChange: () => {}, }, render: function Render(args) { const [value, setValue] = useState(args.value); return ; }, }; /** * Tabs with icons. */ export const WithIcons: Story = { args: { value: 'desktop', items: itemsWithIcons, variant: 'primary', onValueChange: () => {}, }, render: function Render(args) { const [value, setValue] = useState(args.value); return ; }, }; /** * With a label above the selector. */ export const WithLabel: Story = { args: { value: 'desktop', items: itemsWithIcons, variant: 'primary', label: 'Select Device', onValueChange: () => {}, }, render: function Render(args) { const [value, setValue] = useState(args.value); return ; }, }; /** * Tab with a disabled item. */ export const WithDisabled: Story = { args: { value: 'tab1', items: [ { id: 'tab1', label: 'Tab 1' }, { id: 'tab2', label: 'Tab 2' }, { id: 'tab3', label: 'Tab 3', disabled: true }, ], variant: 'primary', onValueChange: () => {}, }, render: function Render(args) { const [value, setValue] = useState(args.value); return ; }, }; /** * Entire selector disabled via the top-level `disabled` prop. */ export const Disabled: Story = { args: { value: 'tab1', items: basicItems, variant: 'primary', disabled: true, onValueChange: () => {}, }, render: function Render(args) { const [value, setValue] = useState(args.value); return ; }, }; /** * Two tabs only. */ export const TwoTabs: Story = { args: { value: 'on', items: [ { id: 'on', label: 'Enabled' }, { id: 'off', label: 'Disabled' }, ], variant: 'primary', onValueChange: () => {}, }, render: function Render(args) { const [value, setValue] = useState(args.value); return ; }, }; /** * Real-world example: platform selector with icons. */ export const PlatformExample: Story = { args: { value: 'macos', items: [ { id: 'windows', label: 'Windows', icon: }, { id: 'macos', label: 'macOS', icon: }, { id: 'linux', label: 'Linux', icon: }, ], variant: 'primary', label: 'Select Platform', onValueChange: () => {}, }, render: function Render(args) { const [value, setValue] = useState(args.value); return ; }, }; /** * Side-by-side comparison of both variants. */ export const VariantComparison: Story = { args: { value: 'tab2', items: fiveItems, onValueChange: () => {}, }, render: function Render() { const [primaryValue, setPrimaryValue] = useState('tab2'); const [secondaryValue, setSecondaryValue] = useState('tab2'); return (
); }, }; /** * Real-world example with badges and disabled tabs. */ export const WithBadges: Story = { args: { value: 'basic', items: [], onValueChange: () => {}, }, render: function Render() { const [value, setValue] = useState('basic'); const items: TabSelectorItem[] = [ { id: 'basic', label: 'Basic', icon: }, { id: 'pro', label: 'Pro', icon: }, { id: 'enterprise', label: 'Enterprise', icon: , disabled: true, badge: ( Soon ), }, ]; return ; }, };