mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-26 14:27:00 -05:00
Create unified FormFieldWrapper
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.
This commit is contained in:
278
src/components/examples/FormFieldWrapperDemo.tsx
Normal file
278
src/components/examples/FormFieldWrapperDemo.tsx
Normal file
@@ -0,0 +1,278 @@
|
||||
/**
|
||||
* 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>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user