import type { Meta, StoryObj } from '@storybook/react'; import { useState } from 'react'; import { PixelInput } from './forms/PixelInput'; import { PixelPasswordInput } from './forms/PixelPasswordInput'; import { PixelTextarea } from './forms/PixelTextarea'; import { PixelSelect } from './forms/PixelSelect'; import { PixelCheckbox } from './forms/PixelCheckbox'; import { PixelRadioGroup } from './forms/PixelRadioGroup'; import { PixelSwitch } from './forms/PixelSwitch'; import { PixelSlider } from './forms/PixelSlider'; import { PixelSegmented } from './forms/PixelSegmented'; import { PxlKitIcon } from '@pxlkit/core'; import { Search, Gear } from '@pxlkit/ui'; import { Mail } from '@pxlkit/feedback'; const TONES = ['green', 'cyan', 'gold', 'red', 'purple', 'pink', 'neutral'] as const; const SIZES = ['sm', 'md', 'lg'] as const; const SURFACES = ['pixel', 'linear'] as const; const PLANETS = [ { value: 'earth', label: 'Earth' }, { value: 'mars', label: 'Mars' }, { value: 'venus', label: 'Venus' }, ]; const meta: Meta = { title: 'UI Kit / Inputs', parameters: { layout: 'padded' }, }; export default meta; type Story = StoryObj; /* ────────────────────────────────────────────────────────────────────────── AllInputs — playground showing every input under one surface. ────────────────────────────────────────────────────────────────────────── */ function InputPlayground({ surface }: { surface: 'pixel' | 'linear' }) { const [name, setName] = useState('Pixel Hero'); const [planet, setPlanet] = useState('mars'); const [agreed, setAgreed] = useState(false); const [tier, setTier] = useState('community'); const [notify, setNotify] = useState(true); const [vol, setVol] = useState(60); const [view, setView] = useState('grid'); return (
setName(e.target.value)} hint="Your retro alias" icon={} surface={surface} /> } surface={surface} />
); } export const AllInputs: Story = { render: (args: any) => , argTypes: { surface: { control: 'inline-radio', options: SURFACES }, }, args: { surface: 'pixel' as const }, }; /* ────────────────────────────────────────────────────────────────────────── PixelInput ────────────────────────────────────────────────────────────────────────── */ export const PixelInputStory: Story = { name: 'PixelInput', render: (args: any) => { const [v, setV] = useState(args.defaultValue as string || ''); return setV(e.target.value)} />; }, argTypes: { label: { control: 'text' }, placeholder: { control: 'text' }, hint: { control: 'text' }, error: { control: 'text' }, tone: { control: 'select', options: TONES }, size: { control: 'inline-radio', options: SIZES }, surface: { control: 'inline-radio', options: SURFACES }, disabled: { control: 'boolean' }, }, args: { label: 'Search icons', placeholder: 'Find a pixel icon…', hint: 'Try "trophy" or "flame"', tone: 'cyan', size: 'md', surface: 'pixel', disabled: false, defaultValue: '', icon: , }, }; /* ────────────────────────────────────────────────────────────────────────── PixelPasswordInput ────────────────────────────────────────────────────────────────────────── */ export const PixelPasswordInputStory: Story = { name: 'PixelPasswordInput', render: (args: any) => , argTypes: { label: { control: 'text' }, placeholder: { control: 'text' }, hint: { control: 'text' }, error: { control: 'text' }, tone: { control: 'select', options: TONES }, size: { control: 'inline-radio', options: SIZES }, surface: { control: 'inline-radio', options: SURFACES }, disabled: { control: 'boolean' }, }, args: { label: 'Master key', placeholder: 'Enter your sigil…', hint: 'Keep it secret. Keep it safe.', tone: 'purple', size: 'md', surface: 'pixel', disabled: false, }, }; /* ────────────────────────────────────────────────────────────────────────── PixelTextarea ────────────────────────────────────────────────────────────────────────── */ export const PixelTextareaStory: Story = { name: 'PixelTextarea', render: (args: any) => , argTypes: { label: { control: 'text' }, placeholder: { control: 'text' }, hint: { control: 'text' }, error: { control: 'text' }, tone: { control: 'select', options: TONES }, surface: { control: 'inline-radio', options: SURFACES }, disabled: { control: 'boolean' }, }, args: { label: 'Quest log', placeholder: 'Describe your latest adventure…', hint: 'Markdown supported', tone: 'green', surface: 'pixel', disabled: false, rows: 4, }, }; /* ────────────────────────────────────────────────────────────────────────── PixelSelect ────────────────────────────────────────────────────────────────────────── */ export const PixelSelectStory: Story = { name: 'PixelSelect', render: (args: any) => { const [v, setV] = useState((args.value as string) || 'mars'); return ; }, argTypes: { label: { control: 'text' }, placeholder: { control: 'text' }, hint: { control: 'text' }, error: { control: 'text' }, tone: { control: 'select', options: TONES }, size: { control: 'inline-radio', options: SIZES }, surface: { control: 'inline-radio', options: SURFACES }, disabled: { control: 'boolean' }, }, args: { label: 'Home planet', placeholder: 'Choose your planet…', tone: 'purple', size: 'md', surface: 'pixel', disabled: false, options: PLANETS, value: 'mars', }, }; /* ────────────────────────────────────────────────────────────────────────── PixelCheckbox ────────────────────────────────────────────────────────────────────────── */ export const PixelCheckboxStory: Story = { name: 'PixelCheckbox', render: (args: any) => { const [v, setV] = useState(args.checked as boolean ?? false); return ; }, argTypes: { label: { control: 'text' }, tone: { control: 'select', options: TONES }, surface: { control: 'inline-radio', options: SURFACES }, disabled: { control: 'boolean' }, checked: { control: 'boolean' }, }, args: { label: 'Enable animated icons', tone: 'green', surface: 'pixel', disabled: false, checked: false, }, }; /* ────────────────────────────────────────────────────────────────────────── PixelRadioGroup ────────────────────────────────────────────────────────────────────────── */ export const PixelRadioGroupStory: Story = { name: 'PixelRadioGroup', render: (args: any) => { const [v, setV] = useState(args.value as string || 'indie'); return ; }, argTypes: { label: { control: 'text' }, tone: { control: 'select', options: TONES }, surface: { control: 'inline-radio', options: SURFACES }, disabled: { control: 'boolean' }, }, args: { label: 'License tier', tone: 'cyan', surface: 'pixel', disabled: false, value: 'indie', options: [ { value: 'community', label: 'Community' }, { value: 'indie', label: 'Indie' }, { value: 'team', label: 'Team' }, ], }, }; /* ────────────────────────────────────────────────────────────────────────── PixelSwitch ────────────────────────────────────────────────────────────────────────── */ export const PixelSwitchStory: Story = { name: 'PixelSwitch', render: (args: any) => { const [v, setV] = useState(args.checked as boolean ?? false); return ; }, argTypes: { label: { control: 'text' }, tone: { control: 'select', options: TONES }, surface: { control: 'inline-radio', options: SURFACES }, disabled: { control: 'boolean' }, checked: { control: 'boolean' }, }, args: { label: 'Email notifications', tone: 'cyan', surface: 'pixel', disabled: false, checked: true, }, }; /* ────────────────────────────────────────────────────────────────────────── PixelSlider ────────────────────────────────────────────────────────────────────────── */ export const PixelSliderStory: Story = { name: 'PixelSlider', render: (args: any) => { const [v, setV] = useState(args.value as number ?? 60); return
; }, argTypes: { label: { control: 'text' }, min: { control: { type: 'number' } }, max: { control: { type: 'number' } }, step: { control: { type: 'number' } }, showMinMax: { control: 'boolean' }, tone: { control: 'select', options: TONES }, surface: { control: 'inline-radio', options: SURFACES }, disabled: { control: 'boolean' }, }, args: { label: 'Volume', min: 0, max: 100, step: 1, showMinMax: true, tone: 'gold', surface: 'pixel', disabled: false, value: 60, }, }; /* ────────────────────────────────────────────────────────────────────────── PixelSegmented ────────────────────────────────────────────────────────────────────────── */ export const PixelSegmentedStory: Story = { name: 'PixelSegmented', render: (args: any) => { const [v, setV] = useState(args.value as string || 'grid'); return ; }, argTypes: { label: { control: 'text' }, tone: { control: 'select', options: TONES }, surface: { control: 'inline-radio', options: SURFACES }, disabled: { control: 'boolean' }, }, args: { label: 'Layout density', tone: 'green', surface: 'pixel', disabled: false, value: 'grid', options: [ { value: 'grid', label: 'Grid' }, { value: 'list', label: 'List' }, { value: 'kanban', label: 'Kanban' }, ], }, };