No description
|
Some checks failed
Publish / publish (push) Failing after 0s
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com> |
||
|---|---|---|
| .forgejo/workflows | ||
| src | ||
| .gitignore | ||
| eslint.config.js | ||
| package.json | ||
| README.md | ||
| tsconfig.json | ||
| vitest-setup.ts | ||
| vitest.config.ts | ||
@lilith/ui-forms
Complex form components for multi-step forms, date pickers, color pickers, phone inputs, and other advanced form elements.
Features
- Multi-step forms with progress indicators and validation
- Date and DateTime pickers with min/max constraints
- Range sliders with customizable tracks
- Color picker with preset colors and custom input
- Phone input with country code selection
- Address input with structured fields
- Tag input for managing lists of tags
- Searchable multi-select dropdowns
- Dynamic field arrays for repeatable form sections
- Conditional fields that show/hide based on form state
- Theme-aware styling using styled-components
Installation
pnpm add @lilith/ui-forms
Peer Dependencies
{
"react": "^18.0.0",
"react-dom": "^18.0.0",
"styled-components": "^6.0.0"
}
Usage
MultiStepForm
Create wizard-style forms with validation per step:
import { MultiStepForm, type FormStep } from '@lilith/ui-forms';
const steps: FormStep[] = [
{
id: 'personal',
label: 'Personal Info',
component: <PersonalInfoStep />,
validate: () => validatePersonalInfo(),
},
{
id: 'address',
label: 'Address',
component: <AddressStep />,
validate: () => validateAddress(),
},
{
id: 'confirmation',
label: 'Confirm',
component: <ConfirmationStep />,
},
];
function RegistrationForm() {
return (
<MultiStepForm
steps={steps}
onComplete={() => handleSubmit()}
onCancel={() => handleCancel()}
showProgress={true}
/>
);
}
DatePicker
import { DatePicker } from '@lilith/ui-forms';
function DateForm() {
const [date, setDate] = useState<Date | null>(null);
return (
<DatePicker
value={date}
onChange={setDate}
min={new Date('2024-01-01')}
max={new Date('2024-12-31')}
placeholder="Select date"
/>
);
}
DateTimePicker
import { DateTimePicker } from '@lilith/ui-forms';
function EventForm() {
const [dateTime, setDateTime] = useState<Date | null>(null);
return (
<DateTimePicker
value={dateTime}
onChange={setDateTime}
placeholder="Select date and time"
/>
);
}
RangeSlider
import { RangeSlider } from '@lilith/ui-forms';
function PriceFilter() {
const [range, setRange] = useState({ min: 0, max: 100 });
return (
<RangeSlider
min={0}
max={500}
value={range}
onChange={setRange}
step={10}
/>
);
}
ColorPicker
import { ColorPicker } from '@lilith/ui-forms';
function ThemeEditor() {
const [color, setColor] = useState('#3b82f6');
return (
<ColorPicker
value={color}
onChange={setColor}
/>
);
}
PhoneInput
import { PhoneInput } from '@lilith/ui-forms';
function ContactForm() {
const [phone, setPhone] = useState('');
return (
<PhoneInput
value={phone}
onChange={setPhone}
defaultCountry="US"
/>
);
}
AddressInput
import { AddressInput, type Address } from '@lilith/ui-forms';
function ShippingForm() {
const [address, setAddress] = useState<Address>({
street: '',
city: '',
state: '',
zipCode: '',
country: '',
});
return (
<AddressInput
value={address}
onChange={setAddress}
/>
);
}
TagInput
import { TagInput } from '@lilith/ui-forms';
function SkillsForm() {
const [tags, setTags] = useState<string[]>(['react', 'typescript']);
return (
<TagInput
value={tags}
onChange={setTags}
placeholder="Add a skill..."
/>
);
}
SearchableMultiSelect
import { SearchableMultiSelect, type SearchableSelectOption } from '@lilith/ui-forms';
const options: SearchableSelectOption[] = [
{ value: 'react', label: 'React' },
{ value: 'vue', label: 'Vue' },
{ value: 'angular', label: 'Angular' },
];
function TechStackForm() {
const [selected, setSelected] = useState<string[]>([]);
return (
<SearchableMultiSelect
options={options}
value={selected}
onChange={setSelected}
placeholder="Search frameworks..."
/>
);
}
DynamicFieldArray
import { DynamicFieldArray } from '@lilith/ui-forms';
function TeamForm() {
const [members, setMembers] = useState([{ name: '', role: '' }]);
return (
<DynamicFieldArray
value={members}
onChange={setMembers}
renderField={(item, index, onChange) => (
<div>
<input
value={item.name}
onChange={(e) => onChange({ ...item, name: e.target.value })}
/>
</div>
)}
addButtonLabel="Add Member"
/>
);
}
ConditionalFields
import { ConditionalFields } from '@lilith/ui-forms';
function SurveyForm() {
const [hasOther, setHasOther] = useState(false);
return (
<>
<Checkbox checked={hasOther} onChange={setHasOther} label="Other" />
<ConditionalFields show={hasOther}>
<Input placeholder="Please specify..." />
</ConditionalFields>
</>
);
}
FormField
Generic form field component with icon support:
import { FormField, getFieldIcon } from '@lilith/ui-forms';
function DynamicForm() {
return (
<FormField
type="email"
label="Email Address"
name="email"
required
/>
);
}
LabeledSlider & WeightSlider
import { LabeledSlider, WeightSlider } from '@lilith/ui-forms';
function PreferencesForm() {
const [volume, setVolume] = useState(50);
const [weight, setWeight] = useState(1.0);
return (
<>
<LabeledSlider
label="Volume"
value={volume}
onChange={setVolume}
min={0}
max={100}
/>
<WeightSlider
label="Priority Weight"
value={weight}
onChange={setWeight}
min={0}
max={2}
step={0.1}
/>
</>
);
}
API Reference
MultiStepFormProps
| Prop | Type | Default | Description |
|---|---|---|---|
steps |
FormStep[] |
required | Array of form steps |
onComplete |
() => void | Promise<void> |
required | Called when form is completed |
onCancel |
() => void |
- | Called when cancel button is clicked |
showProgress |
boolean |
true |
Show progress bar |
FormStep
| Prop | Type | Description |
|---|---|---|
id |
string |
Unique step identifier |
label |
string |
Step label shown in progress bar |
component |
ReactNode |
Step content |
validate |
() => boolean | Promise<boolean> |
Optional validation function |
DatePickerProps
| Prop | Type | Default | Description |
|---|---|---|---|
value |
Date | null |
required | Selected date |
onChange |
(date: Date | null) => void |
required | Change handler |
min |
Date |
- | Minimum selectable date |
max |
Date |
- | Maximum selectable date |
disabled |
boolean |
false |
Disable input |
placeholder |
string |
'Select date' |
Placeholder text |
AddressInputProps
| Prop | Type | Description |
|---|---|---|
value |
Address |
Current address value |
onChange |
(address: Address) => void |
Change handler |
Address
interface Address {
street: string;
city: string;
state: string;
zipCode: string;
country: string;
}
Types
All component props and types are exported:
import type {
FormStep,
MultiStepFormProps,
DatePickerProps,
DateTimePickerProps,
RangeSliderProps,
ColorPickerProps,
PhoneInputProps,
AddressInputProps,
Address,
TagInputProps,
SearchableMultiSelectProps,
SearchableSelectOption,
DynamicFieldArrayProps,
ConditionalFieldsProps,
FormFieldProps,
FormFieldConfig,
FormFieldOption,
LabeledSliderProps,
WeightSliderProps,
StepIndicatorProps,
} from '@lilith/ui-forms';
License
MIT