mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-26 00:31:12 -05:00
Introduce a new reusable form field component that automatically shows hints, validation messages, and terminology tooltips based on field type; refactor forms to demonstrate usage.
279 lines
12 KiB
TypeScript
279 lines
12 KiB
TypeScript
/**
|
|
* FormFieldWrapper Live Demo
|
|
*
|
|
* This component demonstrates the FormFieldWrapper in action
|
|
* You can view this by navigating to /examples/form-field-wrapper
|
|
*/
|
|
|
|
import { useForm } from 'react-hook-form';
|
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
|
|
import { Button } from '@/components/ui/button';
|
|
import { FormFieldWrapper, formFieldPresets } from '@/components/ui/form-field-wrapper';
|
|
import { TooltipProvider } from '@/components/ui/tooltip';
|
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
|
|
|
|
export function FormFieldWrapperDemo() {
|
|
const { register, formState: { errors }, watch, handleSubmit } = useForm();
|
|
|
|
const onSubmit = (data: any) => {
|
|
console.log('Form submitted:', data);
|
|
alert('Check console for form data');
|
|
};
|
|
|
|
return (
|
|
<TooltipProvider>
|
|
<div className="container mx-auto py-8 max-w-4xl">
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle>FormFieldWrapper Demo</CardTitle>
|
|
<CardDescription>
|
|
Interactive demonstration of the unified form field component
|
|
</CardDescription>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<Tabs defaultValue="basic">
|
|
<TabsList className="grid w-full grid-cols-4">
|
|
<TabsTrigger value="basic">Basic</TabsTrigger>
|
|
<TabsTrigger value="terminology">Terminology</TabsTrigger>
|
|
<TabsTrigger value="presets">Presets</TabsTrigger>
|
|
<TabsTrigger value="advanced">Advanced</TabsTrigger>
|
|
</TabsList>
|
|
|
|
<form onSubmit={handleSubmit(onSubmit)} className="space-y-6 mt-6">
|
|
{/* Basic Examples */}
|
|
<TabsContent value="basic" className="space-y-6">
|
|
<div className="space-y-4">
|
|
<h3 className="text-lg font-semibold">Basic Field Types</h3>
|
|
<p className="text-sm text-muted-foreground">
|
|
These fields automatically show appropriate hints and validation
|
|
</p>
|
|
|
|
<FormFieldWrapper
|
|
id="website_url"
|
|
label="Website URL"
|
|
fieldType="url"
|
|
error={errors.website_url?.message as string}
|
|
inputProps={{
|
|
...register('website_url'),
|
|
placeholder: "https://example.com"
|
|
}}
|
|
/>
|
|
|
|
<FormFieldWrapper
|
|
id="email"
|
|
label="Email Address"
|
|
fieldType="email"
|
|
required
|
|
error={errors.email?.message as string}
|
|
inputProps={{
|
|
...register('email', { required: 'Email is required' }),
|
|
placeholder: "contact@example.com"
|
|
}}
|
|
/>
|
|
|
|
<FormFieldWrapper
|
|
id="phone"
|
|
label="Phone Number"
|
|
fieldType="phone"
|
|
error={errors.phone?.message as string}
|
|
inputProps={{
|
|
...register('phone'),
|
|
placeholder: "+1 (555) 123-4567"
|
|
}}
|
|
/>
|
|
</div>
|
|
</TabsContent>
|
|
|
|
{/* Terminology Examples */}
|
|
<TabsContent value="terminology" className="space-y-6">
|
|
<div className="space-y-4">
|
|
<h3 className="text-lg font-semibold">Fields with Terminology</h3>
|
|
<p className="text-sm text-muted-foreground">
|
|
Hover over labels with icons to see terminology definitions
|
|
</p>
|
|
|
|
<FormFieldWrapper
|
|
id="inversions"
|
|
label="Inversions"
|
|
fieldType="inversions"
|
|
termKey="inversion"
|
|
error={errors.inversions?.message as string}
|
|
inputProps={{
|
|
...register('inversions'),
|
|
type: "number",
|
|
min: 0,
|
|
placeholder: "e.g. 7"
|
|
}}
|
|
/>
|
|
|
|
<FormFieldWrapper
|
|
id="max_speed"
|
|
label="Max Speed (km/h)"
|
|
fieldType="speed"
|
|
termKey="kilometers-per-hour"
|
|
error={errors.max_speed?.message as string}
|
|
inputProps={{
|
|
...register('max_speed'),
|
|
type: "number",
|
|
min: 0,
|
|
step: 0.1,
|
|
placeholder: "e.g. 193"
|
|
}}
|
|
/>
|
|
|
|
<FormFieldWrapper
|
|
id="max_height"
|
|
label="Max Height (meters)"
|
|
fieldType="height"
|
|
termKey="meters"
|
|
error={errors.max_height?.message as string}
|
|
inputProps={{
|
|
...register('max_height'),
|
|
type: "number",
|
|
min: 0,
|
|
step: 0.1,
|
|
placeholder: "e.g. 94"
|
|
}}
|
|
/>
|
|
</div>
|
|
</TabsContent>
|
|
|
|
{/* Preset Examples */}
|
|
<TabsContent value="presets" className="space-y-6">
|
|
<div className="space-y-4">
|
|
<h3 className="text-lg font-semibold">Using Presets</h3>
|
|
<p className="text-sm text-muted-foreground">
|
|
Common field configurations with one-line setup
|
|
</p>
|
|
|
|
<FormFieldWrapper
|
|
{...formFieldPresets.sourceUrl({})}
|
|
id="source_url"
|
|
error={errors.source_url?.message as string}
|
|
inputProps={{
|
|
...register('source_url'),
|
|
placeholder: "https://source.com/article"
|
|
}}
|
|
/>
|
|
|
|
<FormFieldWrapper
|
|
{...formFieldPresets.heightRequirement({})}
|
|
id="height_requirement"
|
|
error={errors.height_requirement?.message as string}
|
|
inputProps={{
|
|
...register('height_requirement'),
|
|
type: "number",
|
|
min: 0,
|
|
placeholder: "122"
|
|
}}
|
|
/>
|
|
|
|
<FormFieldWrapper
|
|
{...formFieldPresets.capacity({})}
|
|
id="capacity"
|
|
error={errors.capacity?.message as string}
|
|
inputProps={{
|
|
...register('capacity'),
|
|
type: "number",
|
|
min: 0,
|
|
placeholder: "1200"
|
|
}}
|
|
/>
|
|
</div>
|
|
</TabsContent>
|
|
|
|
{/* Advanced Examples */}
|
|
<TabsContent value="advanced" className="space-y-6">
|
|
<div className="space-y-4">
|
|
<h3 className="text-lg font-semibold">Advanced Features</h3>
|
|
<p className="text-sm text-muted-foreground">
|
|
Textareas, character counting, and custom hints
|
|
</p>
|
|
|
|
<FormFieldWrapper
|
|
{...formFieldPresets.submissionNotes({})}
|
|
id="submission_notes"
|
|
value={watch('submission_notes')}
|
|
error={errors.submission_notes?.message as string}
|
|
textareaProps={{
|
|
...register('submission_notes', {
|
|
maxLength: { value: 1000, message: 'Maximum 1000 characters' }
|
|
}),
|
|
placeholder: "Add context for moderators...",
|
|
rows: 4
|
|
}}
|
|
/>
|
|
|
|
<FormFieldWrapper
|
|
id="custom_field"
|
|
label="Custom Field with Override"
|
|
fieldType="text"
|
|
hint="This is a custom hint that overrides any automatic hint"
|
|
error={errors.custom_field?.message as string}
|
|
inputProps={{
|
|
...register('custom_field'),
|
|
placeholder: "Enter custom value"
|
|
}}
|
|
/>
|
|
|
|
<FormFieldWrapper
|
|
id="no_hint_field"
|
|
label="Field Without Hint"
|
|
fieldType="url"
|
|
hideHint
|
|
error={errors.no_hint_field?.message as string}
|
|
inputProps={{
|
|
...register('no_hint_field'),
|
|
placeholder: "https://"
|
|
}}
|
|
/>
|
|
</div>
|
|
</TabsContent>
|
|
|
|
<Button type="submit" className="w-full">
|
|
Submit Form (Check Console)
|
|
</Button>
|
|
</form>
|
|
</Tabs>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
{/* Benefits Card */}
|
|
<Card className="mt-6">
|
|
<CardHeader>
|
|
<CardTitle>Benefits</CardTitle>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<ul className="space-y-2 text-sm">
|
|
<li className="flex items-start gap-2">
|
|
<span className="text-green-500">✓</span>
|
|
<span><strong>Consistency:</strong> All fields follow the same structure and styling</span>
|
|
</li>
|
|
<li className="flex items-start gap-2">
|
|
<span className="text-green-500">✓</span>
|
|
<span><strong>Less Code:</strong> ~50% reduction in form field boilerplate</span>
|
|
</li>
|
|
<li className="flex items-start gap-2">
|
|
<span className="text-green-500">✓</span>
|
|
<span><strong>Smart Defaults:</strong> Automatic hints based on field type</span>
|
|
</li>
|
|
<li className="flex items-start gap-2">
|
|
<span className="text-green-500">✓</span>
|
|
<span><strong>Built-in Terminology:</strong> Hover tooltips for technical terms</span>
|
|
</li>
|
|
<li className="flex items-start gap-2">
|
|
<span className="text-green-500">✓</span>
|
|
<span><strong>Easy Updates:</strong> Change hints in one place, updates everywhere</span>
|
|
</li>
|
|
<li className="flex items-start gap-2">
|
|
<span className="text-green-500">✓</span>
|
|
<span><strong>Type Safety:</strong> TypeScript ensures correct usage</span>
|
|
</li>
|
|
</ul>
|
|
</CardContent>
|
|
</Card>
|
|
</div>
|
|
</TooltipProvider>
|
|
);
|
|
}
|