* feat(docs): add interactive examples and API references for Button, Card, and LoadingFallback components - Updated dependencies - Set `retries` to a fixed value of 3 for consistent test retries across environments. - Increased `timeout` from 60 seconds to 120 seconds to allow more time for tests to complete. - Reduced `expect` timeout from 10 seconds to 5 seconds for quicker feedback on assertions.
440 lines
14 KiB
TypeScript
440 lines
14 KiB
TypeScript
'use client';
|
|
|
|
import { useState } from 'react';
|
|
|
|
import { Button } from '@kit/ui/button';
|
|
import {
|
|
Card,
|
|
CardContent,
|
|
CardDescription,
|
|
CardHeader,
|
|
CardTitle,
|
|
} from '@kit/ui/card';
|
|
import { Label } from '@kit/ui/label';
|
|
import { Separator } from '@kit/ui/separator';
|
|
import { Stepper } from '@kit/ui/stepper';
|
|
|
|
import { generatePropsString, useStoryControls } from '../lib/story-utils';
|
|
import { ComponentStoryLayout } from './story-layout';
|
|
import { SimpleStorySelect } from './story-select';
|
|
|
|
interface StepperControls {
|
|
variant: 'default' | 'numbers' | 'dots';
|
|
currentStep: number;
|
|
stepCount: number;
|
|
}
|
|
|
|
const variantOptions = [
|
|
{ value: 'default', label: 'Default', description: 'Progress bar style' },
|
|
{ value: 'numbers', label: 'Numbers', description: 'Numbered circles' },
|
|
{ value: 'dots', label: 'Dots', description: 'Simple dot indicators' },
|
|
];
|
|
|
|
const stepCountOptions = [
|
|
{ value: '3', label: '3 steps', description: 'Simple flow' },
|
|
{ value: '4', label: '4 steps', description: 'Standard flow' },
|
|
{ value: '5', label: '5 steps', description: 'Complex flow' },
|
|
{ value: '6', label: '6 steps', description: 'Multi-step process' },
|
|
];
|
|
|
|
export function StepperStory() {
|
|
const { controls, updateControl } = useStoryControls<StepperControls>({
|
|
variant: 'default',
|
|
currentStep: 1,
|
|
stepCount: 4,
|
|
});
|
|
|
|
const [interactiveStep, setInteractiveStep] = useState(0);
|
|
|
|
// Generate step labels based on step count
|
|
const generateSteps = (count: number) => {
|
|
const baseSteps = [
|
|
'Account Setup',
|
|
'Personal Info',
|
|
'Preferences',
|
|
'Review',
|
|
'Payment',
|
|
'Confirmation',
|
|
];
|
|
return baseSteps.slice(0, count);
|
|
};
|
|
|
|
const steps = generateSteps(controls.stepCount);
|
|
|
|
const generateCode = () => {
|
|
const propsString = generatePropsString(
|
|
{
|
|
steps: JSON.stringify(steps),
|
|
currentStep: controls.currentStep,
|
|
variant: controls.variant,
|
|
},
|
|
{
|
|
steps: undefined,
|
|
currentStep: 0,
|
|
variant: 'default',
|
|
},
|
|
);
|
|
|
|
return `<Stepper${propsString} />`;
|
|
};
|
|
|
|
const renderPreview = () => (
|
|
<div className="w-full space-y-4">
|
|
<Stepper
|
|
steps={steps}
|
|
currentStep={controls.currentStep}
|
|
variant={controls.variant}
|
|
/>
|
|
|
|
{controls.variant === 'numbers' && (
|
|
<div className="text-muted-foreground text-center text-sm">
|
|
Step {controls.currentStep + 1} of {steps.length}:{' '}
|
|
{steps[controls.currentStep]}
|
|
</div>
|
|
)}
|
|
</div>
|
|
);
|
|
|
|
const renderControls = () => (
|
|
<>
|
|
<div className="space-y-2">
|
|
<Label htmlFor="variant">Variant</Label>
|
|
<SimpleStorySelect
|
|
value={controls.variant}
|
|
onValueChange={(value) => updateControl('variant', value as any)}
|
|
options={variantOptions}
|
|
/>
|
|
</div>
|
|
|
|
<div className="space-y-2">
|
|
<Label htmlFor="stepCount">Step Count</Label>
|
|
<SimpleStorySelect
|
|
value={controls.stepCount.toString()}
|
|
onValueChange={(value) => {
|
|
const count = parseInt(value);
|
|
updateControl('stepCount', count);
|
|
// Reset current step if it's beyond the new count
|
|
if (controls.currentStep >= count) {
|
|
updateControl('currentStep', count - 1);
|
|
}
|
|
}}
|
|
options={stepCountOptions}
|
|
/>
|
|
</div>
|
|
|
|
<div className="space-y-2">
|
|
<Label htmlFor="currentStep">Current Step</Label>
|
|
<div className="flex flex-wrap gap-1">
|
|
{Array.from({ length: controls.stepCount }, (_, i) => (
|
|
<Button
|
|
key={i}
|
|
size="sm"
|
|
variant={controls.currentStep === i ? 'default' : 'outline'}
|
|
onClick={() => updateControl('currentStep', i)}
|
|
className="h-8 w-8 p-0"
|
|
>
|
|
{i + 1}
|
|
</Button>
|
|
))}
|
|
</div>
|
|
</div>
|
|
</>
|
|
);
|
|
|
|
const renderExamples = () => (
|
|
<div className="space-y-6">
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle>Stepper Variants</CardTitle>
|
|
<CardDescription>
|
|
Different visual styles for step indicators
|
|
</CardDescription>
|
|
</CardHeader>
|
|
<CardContent className="space-y-6">
|
|
<div className="space-y-2">
|
|
<h4 className="text-sm font-semibold">Default Progress Bar</h4>
|
|
<Stepper
|
|
steps={['Setup', 'Configuration', 'Review', 'Complete']}
|
|
currentStep={1}
|
|
variant="default"
|
|
/>
|
|
</div>
|
|
|
|
<div className="space-y-2">
|
|
<h4 className="text-sm font-semibold">Numbered Steps</h4>
|
|
<Stepper
|
|
steps={['Setup', 'Configuration', 'Review', 'Complete']}
|
|
currentStep={1}
|
|
variant="numbers"
|
|
/>
|
|
</div>
|
|
|
|
<div className="space-y-2">
|
|
<h4 className="text-sm font-semibold">Dot Indicators</h4>
|
|
<Stepper
|
|
steps={['Setup', 'Configuration', 'Review', 'Complete']}
|
|
currentStep={1}
|
|
variant="dots"
|
|
/>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle>Interactive Stepper</CardTitle>
|
|
<CardDescription>
|
|
Navigate through steps with controls
|
|
</CardDescription>
|
|
</CardHeader>
|
|
<CardContent className="space-y-4">
|
|
<Stepper
|
|
steps={['Account', 'Profile', 'Settings', 'Review', 'Done']}
|
|
currentStep={interactiveStep}
|
|
variant="numbers"
|
|
/>
|
|
|
|
<div className="space-y-2 text-center">
|
|
<div className="text-muted-foreground text-sm">
|
|
Step {interactiveStep + 1} of 5:{' '}
|
|
{
|
|
['Account', 'Profile', 'Settings', 'Review', 'Done'][
|
|
interactiveStep
|
|
]
|
|
}
|
|
</div>
|
|
<div className="flex justify-center gap-2">
|
|
<Button
|
|
size="sm"
|
|
variant="outline"
|
|
onClick={() =>
|
|
setInteractiveStep(Math.max(0, interactiveStep - 1))
|
|
}
|
|
disabled={interactiveStep === 0}
|
|
>
|
|
Previous
|
|
</Button>
|
|
<Button
|
|
size="sm"
|
|
onClick={() =>
|
|
setInteractiveStep(Math.min(4, interactiveStep + 1))
|
|
}
|
|
disabled={interactiveStep === 4}
|
|
>
|
|
Next
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle>Different Step Counts</CardTitle>
|
|
<CardDescription>
|
|
Steppers with various numbers of steps
|
|
</CardDescription>
|
|
</CardHeader>
|
|
<CardContent className="space-y-6">
|
|
<div className="space-y-2">
|
|
<h4 className="text-sm font-semibold">3-Step Process</h4>
|
|
<Stepper
|
|
steps={['Start', 'Configure', 'Finish']}
|
|
currentStep={2}
|
|
variant="numbers"
|
|
/>
|
|
</div>
|
|
|
|
<div className="space-y-2">
|
|
<h4 className="text-sm font-semibold">6-Step Process</h4>
|
|
<Stepper
|
|
steps={[
|
|
'Account',
|
|
'Profile',
|
|
'Preferences',
|
|
'Payment',
|
|
'Review',
|
|
'Complete',
|
|
]}
|
|
currentStep={3}
|
|
variant="dots"
|
|
/>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
</div>
|
|
);
|
|
|
|
const renderApiReference = () => (
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle>Stepper Component</CardTitle>
|
|
<CardDescription>
|
|
Complete API reference for Stepper component
|
|
</CardDescription>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="space-y-6">
|
|
<div>
|
|
<h4 className="mb-3 text-lg font-semibold">Stepper</h4>
|
|
<p className="text-muted-foreground mb-3 text-sm">
|
|
A step indicator component for multi-step processes with various
|
|
visual styles.
|
|
</p>
|
|
<div className="overflow-x-auto">
|
|
<table className="border-border w-full border-collapse border">
|
|
<thead>
|
|
<tr className="border-b">
|
|
<th className="p-3 text-left font-medium">Prop</th>
|
|
<th className="p-3 text-left font-medium">Type</th>
|
|
<th className="p-3 text-left font-medium">Default</th>
|
|
<th className="p-3 text-left font-medium">Description</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr className="border-b">
|
|
<td className="p-3 font-mono text-sm">steps</td>
|
|
<td className="p-3 font-mono text-sm">string[]</td>
|
|
<td className="p-3 font-mono text-sm">-</td>
|
|
<td className="p-3">Array of step labels</td>
|
|
</tr>
|
|
<tr className="border-b">
|
|
<td className="p-3 font-mono text-sm">currentStep</td>
|
|
<td className="p-3 font-mono text-sm">number</td>
|
|
<td className="p-3 font-mono text-sm">0</td>
|
|
<td className="p-3">Index of currently active step</td>
|
|
</tr>
|
|
<tr>
|
|
<td className="p-3 font-mono text-sm">variant</td>
|
|
<td className="p-3 font-mono text-sm">
|
|
'default' | 'numbers' | 'dots'
|
|
</td>
|
|
<td className="p-3 font-mono text-sm">'default'</td>
|
|
<td className="p-3">Visual style variant</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
);
|
|
|
|
const renderUsageGuidelines = () => (
|
|
<div className="grid gap-6">
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle>When to Use Stepper</CardTitle>
|
|
<CardDescription>Best practices for step indicators</CardDescription>
|
|
</CardHeader>
|
|
<CardContent className="space-y-4">
|
|
<div className="space-y-2">
|
|
<h4 className="text-sm font-semibold text-green-700">
|
|
✅ Use Stepper For
|
|
</h4>
|
|
<ul className="ml-4 space-y-1 text-sm">
|
|
<li>• Multi-step forms and wizards</li>
|
|
<li>• Onboarding processes</li>
|
|
<li>• Setup and configuration flows</li>
|
|
<li>• Checkout and registration processes</li>
|
|
<li>• Sequential task completion</li>
|
|
</ul>
|
|
</div>
|
|
<div className="space-y-2">
|
|
<h4 className="text-sm font-semibold text-red-700">
|
|
❌ Don't Use Stepper For
|
|
</h4>
|
|
<ul className="ml-4 space-y-1 text-sm">
|
|
<li>• Single-page forms</li>
|
|
<li>• Non-sequential processes</li>
|
|
<li>• Navigation between unrelated sections</li>
|
|
<li>• File upload progress (use progress bar)</li>
|
|
</ul>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle>Choosing the Right Variant</CardTitle>
|
|
<CardDescription>Guidelines for stepper variants</CardDescription>
|
|
</CardHeader>
|
|
<CardContent className="space-y-4">
|
|
<div className="space-y-2">
|
|
<h4 className="text-sm font-semibold">Default (Progress Bar)</h4>
|
|
<p className="text-muted-foreground text-sm">
|
|
Best for linear progress indication with clear visual completion.
|
|
Good for forms and simple workflows.
|
|
</p>
|
|
</div>
|
|
<div className="space-y-2">
|
|
<h4 className="text-sm font-semibold">Numbers</h4>
|
|
<p className="text-muted-foreground text-sm">
|
|
Ideal for complex multi-step processes where step labels are
|
|
important. Shows clear progression and allows easy reference to
|
|
specific steps.
|
|
</p>
|
|
</div>
|
|
<div className="space-y-2">
|
|
<h4 className="text-sm font-semibold">Dots</h4>
|
|
<p className="text-muted-foreground text-sm">
|
|
Perfect for compact spaces and when step sequence is more
|
|
important than labels. Great for onboarding screens and quick
|
|
setup flows.
|
|
</p>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle>UX Best Practices</CardTitle>
|
|
<CardDescription>Creating effective step experiences</CardDescription>
|
|
</CardHeader>
|
|
<CardContent className="space-y-4">
|
|
<div className="space-y-2">
|
|
<h4 className="text-sm font-semibold">Clear Labels</h4>
|
|
<p className="text-muted-foreground text-sm">
|
|
Use concise, descriptive labels that clearly indicate what each
|
|
step contains.
|
|
</p>
|
|
</div>
|
|
<div className="space-y-2">
|
|
<h4 className="text-sm font-semibold">Optimal Step Count</h4>
|
|
<p className="text-muted-foreground text-sm">
|
|
Keep steps between 3-7 for optimal user comprehension. Break down
|
|
complex flows.
|
|
</p>
|
|
</div>
|
|
<div className="space-y-2">
|
|
<h4 className="text-sm font-semibold">Progress Indication</h4>
|
|
<p className="text-muted-foreground text-sm">
|
|
Show completion status and allow users to understand their
|
|
position in the flow.
|
|
</p>
|
|
</div>
|
|
<div className="space-y-2">
|
|
<h4 className="text-sm font-semibold">Navigation Support</h4>
|
|
<p className="text-muted-foreground text-sm">
|
|
Consider allowing backward navigation to previously completed
|
|
steps.
|
|
</p>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
</div>
|
|
);
|
|
|
|
return (
|
|
<ComponentStoryLayout
|
|
preview={renderPreview()}
|
|
controls={renderControls()}
|
|
generatedCode={generateCode()}
|
|
examples={renderExamples()}
|
|
apiReference={renderApiReference()}
|
|
usageGuidelines={renderUsageGuidelines()}
|
|
/>
|
|
);
|
|
}
|