forge/examples/form.tsx
Chris Wanstrath 855112ac82 themes
2025-12-29 14:18:30 -08:00

252 lines
5.8 KiB
TypeScript

import { define } from '../src'
import { ExampleSection } from './ssr/helpers'
import { theme } from './ssr/themes'
const Input = define('Input', {
base: 'input',
padding: `${theme('spacing-sm')} ${theme('spacing-md')}`,
fontSize: 14,
border: `1px solid ${theme('colors-border')}`,
borderRadius: theme('radius-sm'),
background: theme('colors-bgElevated'),
color: theme('colors-fg'),
transition: 'all 0.2s ease',
width: '100%',
boxSizing: 'border-box',
states: {
':focus': {
outline: 'none',
borderColor: theme('colors-borderActive'),
},
':disabled': {
background: theme('colors-bg'),
color: theme('colors-fgDim'),
cursor: 'not-allowed'
}
},
variants: {
status: {
error: {
borderColor: '#ff0000',
states: {
':focus': {
borderColor: '#ff0000',
}
}
},
success: {
borderColor: theme('colors-accent'),
states: {
':focus': {
borderColor: theme('colors-accent'),
}
}
}
}
}
})
const Textarea = define('Textarea', {
base: 'textarea',
padding: `${theme('spacing-sm')} ${theme('spacing-md')}`,
fontSize: 14,
border: `1px solid ${theme('colors-border')}`,
borderRadius: theme('radius-sm'),
background: theme('colors-bgElevated'),
color: theme('colors-fg'),
transition: 'all 0.2s ease',
width: '100%',
minHeight: 120,
boxSizing: 'border-box',
fontFamily: 'inherit',
resize: 'vertical',
states: {
':focus': {
outline: 'none',
borderColor: theme('colors-borderActive'),
}
}
})
const FormGroup = define('FormGroup', {
marginBottom: theme('spacing-lg'),
parts: {
Label: {
base: 'label',
display: 'block',
fontSize: 14,
fontWeight: 400,
color: theme('colors-fg'),
marginBottom: theme('spacing-xs')
},
Helper: {
fontSize: 12,
color: theme('colors-fgMuted'),
marginTop: 6
},
Error: {
fontSize: 12,
color: '#ff0000',
marginTop: 6
}
},
render({ props, parts: { Root, Label, Helper, Error } }) {
return (
<Root>
{props.label && <Label>{props.label}</Label>}
{props.children}
{props.helper && <Helper>{props.helper}</Helper>}
{props.error && <Error>{props.error}</Error>}
</Root>
)
}
})
const Checkbox = define('Checkbox', {
parts: {
Input: {
base: 'input[type=checkbox]',
width: 18,
height: 18,
cursor: 'pointer'
},
Label: {
base: 'label',
display: 'flex',
alignItems: 'center',
gap: theme('spacing-sm'),
cursor: 'pointer',
fontSize: 14,
color: theme('colors-fgMuted'),
states: {
':hover': {
color: theme('colors-fg')
}
},
selectors: {
'@Input:disabled + &': {
cursor: 'not-allowed',
color: theme('colors-fgDim')
}
}
}
},
render({ props, parts: { Root, Input, Label } }) {
return (
<Root>
<Label>
<Input id={props.id} checked={props.checked} disabled={props.disabled} />
{props.label}
</Label>
</Root>
)
}
})
const FormExamples = define('FormExamples', {
maxWidth: 600,
margin: '0 auto'
})
const Button = define('FormButton', {
base: 'button',
padding: `${theme('spacing-sm')} ${theme('spacing-lg')}`,
fontSize: 14,
fontWeight: 400,
border: `1px solid ${theme('colors-accent')}`,
borderRadius: theme('radius-sm'),
cursor: 'pointer',
transition: 'all 0.2s ease',
background: theme('colors-accent'),
color: theme('colors-bg'),
states: {
':hover': {
background: theme('colors-accentDim'),
borderColor: theme('colors-accentDim'),
},
':active': {
transform: 'translateY(1px)'
}
},
variants: {
variant: {
secondary: {
background: theme('colors-bgElevated'),
color: theme('colors-fg'),
border: `1px solid ${theme('colors-border')}`,
states: {
':hover': {
borderColor: theme('colors-borderActive'),
}
}
}
}
}
})
const ButtonGroup = define('FormButtonGroup', {
display: 'flex',
gap: theme('spacing-sm'),
marginTop: theme('spacing-lg')
})
export const FormExamplesContent = () => (
<FormExamples>
<ExampleSection title="Text Inputs">
<FormGroup label="Email" helper="We'll never share your email">
<Input type="email" placeholder="you@example.com" />
</FormGroup>
<FormGroup label="Password">
<Input type="password" placeholder="Enter your password" />
</FormGroup>
<FormGroup label="Disabled Input">
<Input value="This field is disabled" disabled />
</FormGroup>
</ExampleSection>
<ExampleSection title="Validation States">
<FormGroup label="Valid Email" helper="Looks good!">
<Input status="success" type="email" value="user@example.com" />
</FormGroup>
<FormGroup label="Invalid Email" error="Please enter a valid email address">
<Input status="error" type="email" value="not-an-email" />
</FormGroup>
</ExampleSection>
<ExampleSection title="Textarea">
<FormGroup label="Bio" helper="Tell us about yourself">
<Textarea placeholder="Write something interesting..." />
</FormGroup>
</ExampleSection>
<ExampleSection title="Checkboxes">
<FormGroup>
<Checkbox id="cb1" label="I agree to the terms and conditions" checked />
<Checkbox id="cb2" label="Subscribe to newsletter" />
<Checkbox id="cb3" label="This option is disabled" disabled />
</FormGroup>
</ExampleSection>
<ButtonGroup>
<Button type="submit">Submit</Button>
<Button type="reset" variant="secondary">Reset</Button>
</ButtonGroup>
</FormExamples>
)