Skip to content

Commit a108977

Browse files
committed
Add Stepper component and update documentation
- Introduced the Stepper component for multi-step forms, including usage examples and prop definitions in AGENTS.md. - Updated the component catalog to include the Stepper with a summary. - Added tests for the Stepper component to verify its rendering and state management. - Exported the Stepper and StepperItem components from the main index file for accessibility.
1 parent 50e6f62 commit a108977

9 files changed

Lines changed: 611 additions & 6 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@pplethai/components": minor
3+
---
4+
5+
Add `Stepper` + `StepperItem` for multi-step forms and wizards. Compound API with a `value` prop (0-indexed current step) on the root and per-step `title` / `description` on items. Supports `orientation="horizontal" | "vertical"`, marks the current step with `aria-current="step"`, and renders a checkmark for completed steps.

AGENTS.md

Lines changed: 118 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ A complete, self-contained reference for AI agents working with the People's Par
1515
5. [Icon, Logo, Navbar](#5-icon-logo-navbar)
1616
6. [Form inputs](#6-form-inputs) — Button, Input, Label, Textarea, Checkbox, RadioGroup, Switch, Select, MultiSelect, Autocomplete, Slider
1717
7. [Overlays](#7-overlays) — Dialog, Sheet, Popover, DropdownMenu
18-
8. [Navigation](#8-navigation) — Tabs, Accordion, Breadcrumb, NavigationMenu
19-
9. [Feedback](#9-feedback) — Alert, Badge, Progress, Skeleton, Toast (Sonner)
18+
8. [Navigation](#8-navigation) — Tabs, Accordion, Breadcrumb, NavigationMenu, Stepper
19+
9. [Feedback](#9-feedback) — Alert, Badge, Progress, Spinner, Skeleton, Toast (Sonner)
2020
10. [Data display](#10-data-display) — Card, Separator
2121
11. [Forms with react-hook-form + zod](#11-forms-with-react-hook-form--zod)
2222
12. [Design tokens](#12-design-tokens)
@@ -730,6 +730,89 @@ import {
730730

731731
For simple navbars use `Navbar` (§5.3). NavigationMenu is for desktop mega-menus.
732732

733+
### 8.5 Stepper
734+
735+
Step indicator for multi-step forms / wizards. Compound API — render one `<StepperItem>` per step. `value` is the **0-indexed current step**; earlier indices render as completed (checkmark + primary fill), the matching index is current, later indices are upcoming (muted).
736+
737+
```tsx
738+
import { Stepper, StepperItem } from "@pplethai/components";
739+
740+
// Horizontal (default)
741+
<Stepper value={1}>
742+
<StepperItem title="Account" description="Email & password" />
743+
<StepperItem title="Profile" description="Name & avatar" />
744+
<StepperItem title="Confirm" />
745+
</Stepper>
746+
747+
// Vertical
748+
<Stepper value={0} orientation="vertical">
749+
<StepperItem title="Step one" description="" />
750+
<StepperItem title="Step two" />
751+
</Stepper>
752+
753+
// All steps completed — set value to step count
754+
<Stepper value={3}>
755+
<StepperItem title="A" />
756+
<StepperItem title="B" />
757+
<StepperItem title="C" />
758+
</Stepper>
759+
```
760+
761+
| `Stepper` prop | Type | Default |
762+
|---|---|---|
763+
| `value` | `number` (0-indexed current step) | — (required) |
764+
| `orientation` | `"horizontal" \| "vertical"` | `"horizontal"` |
765+
766+
| `StepperItem` prop | Type |
767+
|---|---|
768+
| `title` | `ReactNode` |
769+
| `description?` | `ReactNode` |
770+
771+
The current step receives `aria-current="step"`. Stepper is **presentational** — wire next/back buttons and step state in your own component.
772+
773+
**Multi-step form pattern:**
774+
775+
```tsx
776+
import { useState } from "react";
777+
import {
778+
Button, Card, CardContent, Inline, Stack, Stepper, StepperItem,
779+
} from "@pplethai/components";
780+
781+
const STEPS = [
782+
{ title: "Account", description: "Email & password" },
783+
{ title: "Profile", description: "Name & avatar" },
784+
{ title: "Confirm" },
785+
];
786+
787+
function MultiStepForm() {
788+
const [step, setStep] = useState(0);
789+
const isLast = step === STEPS.length - 1;
790+
791+
return (
792+
<Stack gap="lg">
793+
<Stepper value={step}>
794+
{STEPS.map((s) => (
795+
<StepperItem key={s.title} title={s.title} description={s.description} />
796+
))}
797+
</Stepper>
798+
<Card><CardContent className="pt-6">{/* fields per step */}</CardContent></Card>
799+
<Inline justify="between">
800+
<Button
801+
variant="outline"
802+
onClick={() => setStep((s) => Math.max(0, s - 1))}
803+
disabled={step === 0}
804+
>
805+
Back
806+
</Button>
807+
<Button onClick={() => setStep((s) => s + 1)}>
808+
{isLast ? "Finish" : "Next"}
809+
</Button>
810+
</Inline>
811+
</Stack>
812+
);
813+
}
814+
```
815+
733816
---
734817

735818
## 9. Feedback
@@ -786,7 +869,36 @@ import { Progress } from "@pplethai/components";
786869

787870
When `value < max` or value omitted, the bar runs an animated shimmer (auto-disabled under `prefers-reduced-motion`).
788871

789-
### 9.4 Skeleton
872+
### 9.4 Spinner
873+
874+
Circular loader. Omit `value` for an infinite spin (indeterminate); pass `value` (0..`max`) for a determinate arc.
875+
876+
```tsx
877+
import { Spinner } from "@pplethai/components";
878+
879+
<Spinner /> {/* indeterminate, default size */}
880+
<Spinner size="lg" /> {/* indeterminate, large */}
881+
<Spinner value={66} /> {/* determinate (arc proportional to value) */}
882+
<Spinner className="text-secondary" /> {/* recolor via text-* (uses currentColor) */}
883+
884+
// In a button while submitting
885+
<Button disabled>
886+
<Spinner size="sm" className="text-primary-foreground" />
887+
Saving…
888+
</Button>
889+
```
890+
891+
| Prop | Type | Default | Notes |
892+
|---|---|---|---|
893+
| `value` | `number \| null` | `undefined` | Omit → indeterminate spin; `0..max` → determinate arc |
894+
| `max` | `number` | `100` | Maximum when determinate |
895+
| `size` | `"sm" \| "default" \| "lg" \| "xl"` | `"default"` | 16 / 24 / 32 / 48 px |
896+
| `strokeWidth` | `number` | `2.5` | Stroke thickness inside a 24×24 viewBox |
897+
| `label` | `string` | `"Loading"` | `aria-label` for screen readers |
898+
899+
Indeterminate uses Tailwind's `animate-spin` (respects `prefers-reduced-motion`). Determinate switches `role` to `progressbar` with `aria-valuemin/max/now`; indeterminate uses `role="status"` + `aria-live="polite"`. Color inherits `currentColor` — tint with `text-*` classes.
900+
901+
### 9.5 Skeleton
790902

791903
```tsx
792904
import { Skeleton } from "@pplethai/components";
@@ -798,7 +910,7 @@ import { Skeleton } from "@pplethai/components";
798910

799911
Style with Tailwind to match the real content's shape.
800912

801-
### 9.5 Toast (Sonner)
913+
### 9.6 Toast (Sonner)
802914

803915
**Step 1 — once, at app root:**
804916

@@ -1308,6 +1420,8 @@ Badge, badgeVariants, type BadgeProps
13081420
Toaster, showToast, toast, type ShowToastOptions, type ToastVariant
13091421
Skeleton
13101422
Progress
1423+
Spinner, spinnerVariants, type SpinnerProps
1424+
Stepper, StepperItem, type StepperProps, type StepperItemProps
13111425
Breadcrumb, BreadcrumbEllipsis, BreadcrumbItem, BreadcrumbLink,
13121426
BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator
13131427
NavigationMenu, NavigationMenuContent, NavigationMenuIndicator,

apps/docs/src/pages/components/catalog.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ export const componentCatalog: ComponentGroup[] = [
4343
{ slug: "breadcrumb", label: "Breadcrumb", summary: "เส้นทางตำแหน่งปัจจุบัน" },
4444
{ slug: "navigation-menu", label: "NavigationMenu", summary: "เมนูนำทางพร้อมแผงเนื้อหา" },
4545
{ slug: "navbar", label: "Navbar", summary: "แถบนำทางพร้อมเมนูมือถือ" },
46+
{ slug: "stepper", label: "Stepper", summary: "ตัวบอกขั้นตอนสำหรับฟอร์มหลายขั้น" },
4647
],
4748
},
4849
{

0 commit comments

Comments
 (0)