forked from defunkt/howl
/ |/ \ / \ / \ / | $$$$$$$$//$$$$$$ |$$$$$$$ |/$$$$$$ |$$$$$$$$/ $$ |__ $$ | $$ |$$ |__$$ |$$ | _$$/ $$ |__ $$ | $$ | $$ |$$ $$< $$ |/ |$$ | $$$$$/ $$ | $$ |$$$$$$$ |$$ |$$$$ |$$$$$/ $$ | $$ \__$$ |$$ | $$ |$$ \__$$ |$$ |_____ $$ | $$ $$/ $$ | $$ |$$ $$/ $$ | $$/ $$$$$$/ $$/ $$/ $$$$$$/ $$$$$$$$/
193 lines
5.0 KiB
TypeScript
193 lines
5.0 KiB
TypeScript
import { define } from 'forge'
|
|
import { theme } from './theme'
|
|
import { Section } from './section'
|
|
import { H2 } from './text'
|
|
import { VStack, HStack } from './stack'
|
|
|
|
export const Input = define('Input', {
|
|
parts: {
|
|
Wrapper: {
|
|
display: 'flex',
|
|
flexDirection: 'column',
|
|
gap: theme('spacing-1'),
|
|
flex: 1,
|
|
minWidth: 0,
|
|
},
|
|
Label: {
|
|
base: 'label',
|
|
fontSize: theme('fontSize-sm'),
|
|
fontWeight: 500,
|
|
color: theme('colors-fg'),
|
|
},
|
|
Field: {
|
|
base: 'input',
|
|
height: 40,
|
|
padding: `${theme('spacing-2')} ${theme('spacing-3')}`,
|
|
borderRadius: theme('radius-md'),
|
|
border: `1px solid ${theme('colors-border')}`,
|
|
background: theme('colors-bg'),
|
|
fontSize: theme('fontSize-sm'),
|
|
outline: 'none',
|
|
flex: 1,
|
|
|
|
states: {
|
|
':focus': {
|
|
borderColor: theme('colors-borderActive'),
|
|
},
|
|
':disabled': {
|
|
opacity: 0.5,
|
|
cursor: 'not-allowed',
|
|
},
|
|
},
|
|
},
|
|
},
|
|
|
|
variants: {
|
|
labelPosition: {
|
|
above: {
|
|
parts: {
|
|
Wrapper: {
|
|
flexDirection: 'column',
|
|
gap: theme('spacing-1'),
|
|
},
|
|
},
|
|
},
|
|
left: {
|
|
parts: {
|
|
Wrapper: {
|
|
flexDirection: 'row',
|
|
alignItems: 'center',
|
|
gap: theme('spacing-1'),
|
|
},
|
|
},
|
|
},
|
|
right: {
|
|
parts: {
|
|
Wrapper: {
|
|
flexDirection: 'row-reverse',
|
|
alignItems: 'center',
|
|
gap: theme('spacing-1'),
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
|
|
render({ props, parts: { Root, Wrapper, Label, Field } }) {
|
|
const { children, labelPosition = 'above', ...inputProps } = props
|
|
|
|
if (!children) {
|
|
return <Field {...inputProps} />
|
|
}
|
|
|
|
return (
|
|
<Wrapper labelPosition={labelPosition}>
|
|
<Label for={props.id}>{children}</Label>
|
|
<Field {...inputProps} />
|
|
</Wrapper>
|
|
)
|
|
},
|
|
})
|
|
|
|
export type InputProps = Parameters<typeof Input>[0]
|
|
|
|
export const Test = () => {
|
|
return (
|
|
<Section style={{ maxWidth: '448px' }}>
|
|
{/* Basic inputs */}
|
|
<VStack gap={4}>
|
|
<H2>Basic Inputs</H2>
|
|
<VStack gap={4}>
|
|
<Input placeholder="Enter your name" />
|
|
<Input type="email" placeholder="Enter your email" />
|
|
<Input type="password" placeholder="Enter your password" />
|
|
</VStack>
|
|
</VStack>
|
|
|
|
{/* Custom styling */}
|
|
<VStack gap={4}>
|
|
<H2>Custom Styling</H2>
|
|
<VStack gap={4}>
|
|
<Input style={{ height: '32px', fontSize: '12px' }} placeholder="Small input" />
|
|
<Input placeholder="Default input" />
|
|
<Input style={{ height: '48px', fontSize: '16px' }} placeholder="Large input" />
|
|
</VStack>
|
|
</VStack>
|
|
|
|
{/* With values */}
|
|
<VStack gap={4}>
|
|
<H2>With Values</H2>
|
|
<VStack gap={4}>
|
|
<Input value="John Doe" placeholder="Name" />
|
|
<Input type="email" value="john@example.com" placeholder="Email" />
|
|
</VStack>
|
|
</VStack>
|
|
|
|
{/* Disabled state */}
|
|
<VStack gap={4}>
|
|
<H2>Disabled State</H2>
|
|
<VStack gap={4}>
|
|
<Input disabled placeholder="Disabled input" />
|
|
<Input disabled value="Disabled with value" />
|
|
</VStack>
|
|
</VStack>
|
|
|
|
{/* Label above */}
|
|
<VStack gap={4}>
|
|
<H2>Label Above</H2>
|
|
<VStack gap={4}>
|
|
<Input placeholder="Enter your name">Name</Input>
|
|
<Input type="email" placeholder="Enter your email">
|
|
Email
|
|
</Input>
|
|
<Input type="password" placeholder="Enter your password">
|
|
Password
|
|
</Input>
|
|
</VStack>
|
|
</VStack>
|
|
|
|
{/* Label to the left */}
|
|
<VStack gap={4}>
|
|
<H2>Label Left</H2>
|
|
<VStack gap={4}>
|
|
<Input labelPosition="left" placeholder="Enter your name">
|
|
Name
|
|
</Input>
|
|
<Input labelPosition="left" type="email" placeholder="Enter your email">
|
|
Email
|
|
</Input>
|
|
<Input labelPosition="left" type="password" placeholder="Enter your password">
|
|
Password
|
|
</Input>
|
|
</VStack>
|
|
</VStack>
|
|
|
|
{/* Label to the right */}
|
|
<VStack gap={4}>
|
|
<H2>Label Right</H2>
|
|
<VStack gap={4}>
|
|
<Input labelPosition="right" placeholder="Enter your name">
|
|
Name
|
|
</Input>
|
|
<Input labelPosition="right" type="email" placeholder="Enter your email">
|
|
Email
|
|
</Input>
|
|
<Input labelPosition="right" type="password" placeholder="Enter your password">
|
|
Password
|
|
</Input>
|
|
</VStack>
|
|
</VStack>
|
|
|
|
{/* Horizontal layout */}
|
|
<VStack gap={4}>
|
|
<H2>Horizontal Layout</H2>
|
|
<HStack gap={4}>
|
|
<Input placeholder="First name">First</Input>
|
|
<Input placeholder="Last name">Last</Input>
|
|
<Input placeholder="Age">Age</Input>
|
|
</HStack>
|
|
</VStack>
|
|
</Section>
|
|
)
|
|
}
|