ui-arreya-components 0.0.15 → 0.0.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,199 @@
1
+ import type { Meta, StoryObj } from "@storybook/react"
2
+ import { Wizard, WizardStepContent, WizardCompletion } from "./wizard"
3
+ import { Button } from "@/components/ui/button"
4
+ import { Input } from "@/components/ui/input"
5
+ import { Label } from "@/components/ui/label"
6
+ import { Card, CardContent } from "@/components/ui/card"
7
+
8
+ const meta: Meta<typeof Wizard> = {
9
+ title: "Feature/Wizard",
10
+ component: Wizard,
11
+ parameters: {
12
+ layout: "centered",
13
+ },
14
+ tags: ["autodocs"],
15
+ }
16
+
17
+ export default meta
18
+ type Story = StoryObj<typeof Wizard>
19
+
20
+ export const Default: Story = {
21
+ render: () => (
22
+ <Card className="w-full max-w-2xl">
23
+ <CardContent className="p-6">
24
+ <Wizard
25
+ steps={[
26
+ { id: "step1", title: "Step 1", description: "Personal Info" },
27
+ { id: "step2", title: "Step 2", description: "Account Details" },
28
+ { id: "step3", title: "Step 3", description: "Confirmation" },
29
+ ]}
30
+ >
31
+ <WizardStepContent stepId="step1">
32
+ <div className="space-y-4 py-4">
33
+ <h3 className="text-lg font-medium">Personal Information</h3>
34
+ <p className="text-sm text-muted-foreground">Please provide your personal details.</p>
35
+ <div className="grid gap-4">
36
+ <div className="grid gap-2">
37
+ <Label htmlFor="name">Full Name</Label>
38
+ <Input id="name" placeholder="John Doe" />
39
+ </div>
40
+ <div className="grid gap-2">
41
+ <Label htmlFor="email">Email</Label>
42
+ <Input id="email" type="email" placeholder="john@example.com" />
43
+ </div>
44
+ </div>
45
+ </div>
46
+ </WizardStepContent>
47
+
48
+ <WizardStepContent stepId="step2">
49
+ <div className="space-y-4 py-4">
50
+ <h3 className="text-lg font-medium">Account Details</h3>
51
+ <p className="text-sm text-muted-foreground">Set up your account preferences.</p>
52
+ <div className="grid gap-4">
53
+ <div className="grid gap-2">
54
+ <Label htmlFor="username">Username</Label>
55
+ <Input id="username" placeholder="johndoe" />
56
+ </div>
57
+ <div className="grid gap-2">
58
+ <Label htmlFor="password">Password</Label>
59
+ <Input id="password" type="password" />
60
+ </div>
61
+ </div>
62
+ </div>
63
+ </WizardStepContent>
64
+
65
+ <WizardStepContent stepId="step3">
66
+ <div className="space-y-4 py-4">
67
+ <h3 className="text-lg font-medium">Confirmation</h3>
68
+ <p className="text-sm text-muted-foreground">Review your information before submitting.</p>
69
+ <div className="rounded-lg border p-4">
70
+ <div className="grid grid-cols-2 gap-4">
71
+ <div className="text-sm font-medium">Name</div>
72
+ <div className="text-sm">John Doe</div>
73
+ <div className="text-sm font-medium">Email</div>
74
+ <div className="text-sm">john@example.com</div>
75
+ <div className="text-sm font-medium">Username</div>
76
+ <div className="text-sm">johndoe</div>
77
+ </div>
78
+ </div>
79
+ </div>
80
+ </WizardStepContent>
81
+
82
+ <WizardCompletion>
83
+ <div className="flex flex-col items-center justify-center py-8 text-center">
84
+ <div className="rounded-full bg-primary/10 p-3 mb-4">
85
+ <svg
86
+ className="h-8 w-8 text-primary"
87
+ xmlns="http://www.w3.org/2000/svg"
88
+ width="24"
89
+ height="24"
90
+ viewBox="0 0 24 24"
91
+ fill="none"
92
+ stroke="currentColor"
93
+ strokeWidth="2"
94
+ strokeLinecap="round"
95
+ strokeLinejoin="round"
96
+ >
97
+ <path d="M20 6L9 17l-5-5" />
98
+ </svg>
99
+ </div>
100
+ <h3 className="text-2xl font-semibold mb-2">Setup Complete!</h3>
101
+ <p className="text-muted-foreground mb-6">Your account has been successfully created.</p>
102
+ <Button>Go to Dashboard</Button>
103
+ </div>
104
+ </WizardCompletion>
105
+ </Wizard>
106
+ </CardContent>
107
+ </Card>
108
+ ),
109
+ }
110
+
111
+ export const WithoutStepIndicator: Story = {
112
+ render: () => (
113
+ <Card className="w-full max-w-2xl">
114
+ <CardContent className="p-6">
115
+ <Wizard
116
+ steps={[
117
+ { id: "step1", title: "Step 1" },
118
+ { id: "step2", title: "Step 2" },
119
+ { id: "step3", title: "Step 3" },
120
+ ]}
121
+ showStepIndicator={false}
122
+ >
123
+ <WizardStepContent stepId="step1">
124
+ <div className="space-y-4 py-4">
125
+ <h3 className="text-lg font-medium">Step 1 Content</h3>
126
+ <p className="text-sm text-muted-foreground">This wizard doesn't show the step indicator.</p>
127
+ </div>
128
+ </WizardStepContent>
129
+
130
+ <WizardStepContent stepId="step2">
131
+ <div className="space-y-4 py-4">
132
+ <h3 className="text-lg font-medium">Step 2 Content</h3>
133
+ <p className="text-sm text-muted-foreground">Navigation is still available at the bottom.</p>
134
+ </div>
135
+ </WizardStepContent>
136
+
137
+ <WizardStepContent stepId="step3">
138
+ <div className="space-y-4 py-4">
139
+ <h3 className="text-lg font-medium">Step 3 Content</h3>
140
+ <p className="text-sm text-muted-foreground">This is the final step.</p>
141
+ </div>
142
+ </WizardStepContent>
143
+
144
+ <WizardCompletion>
145
+ <div className="py-4 text-center">
146
+ <h3 className="text-lg font-medium">All Done!</h3>
147
+ </div>
148
+ </WizardCompletion>
149
+ </Wizard>
150
+ </CardContent>
151
+ </Card>
152
+ ),
153
+ }
154
+
155
+ export const TopNavigation: Story = {
156
+ render: () => (
157
+ <Card className="w-full max-w-2xl">
158
+ <CardContent className="p-6">
159
+ <Wizard
160
+ steps={[
161
+ { id: "step1", title: "Step 1" },
162
+ { id: "step2", title: "Step 2" },
163
+ { id: "step3", title: "Step 3" },
164
+ ]}
165
+ navigationPosition="top"
166
+ >
167
+ <WizardStepContent stepId="step1">
168
+ <div className="space-y-4 py-4">
169
+ <h3 className="text-lg font-medium">Step 1 Content</h3>
170
+ <p className="text-sm text-muted-foreground">This wizard has navigation at the top.</p>
171
+ </div>
172
+ </WizardStepContent>
173
+
174
+ <WizardStepContent stepId="step2">
175
+ <div className="space-y-4 py-4">
176
+ <h3 className="text-lg font-medium">Step 2 Content</h3>
177
+ <p className="text-sm text-muted-foreground">Navigation buttons are above the content.</p>
178
+ </div>
179
+ </WizardStepContent>
180
+
181
+ <WizardStepContent stepId="step3">
182
+ <div className="space-y-4 py-4">
183
+ <h3 className="text-lg font-medium">Step 3 Content</h3>
184
+ <p className="text-sm text-muted-foreground">This is the final step.</p>
185
+ </div>
186
+ </WizardStepContent>
187
+
188
+ <WizardCompletion>
189
+ <div className="py-4 text-center">
190
+ <h3 className="text-lg font-medium">All Done!</h3>
191
+ </div>
192
+ </WizardCompletion>
193
+ </Wizard>
194
+ </CardContent>
195
+ </Card>
196
+ ),
197
+ }
198
+
199
+
@@ -0,0 +1,278 @@
1
+ "use client"
2
+
3
+ import React, { useState, createContext, useContext } from "react"
4
+ import { cn } from "@/lib/utils"
5
+ import { Check, ChevronRight } from 'lucide-react'
6
+ import { Button } from "@/components/ui/button"
7
+
8
+ // Types
9
+ export type WizardStepStatus = "upcoming" | "current" | "completed"
10
+
11
+ export interface WizardStep {
12
+ id: string
13
+ title: string
14
+ description?: string
15
+ optional?: boolean
16
+ }
17
+
18
+ interface WizardContextValue {
19
+ currentStepIndex: number
20
+ steps: WizardStep[]
21
+ goToStep: (index: number) => void
22
+ nextStep: () => void
23
+ prevStep: () => void
24
+ isFirstStep: boolean
25
+ isLastStep: boolean
26
+ getStepStatus: (index: number) => WizardStepStatus
27
+ completeWizard: () => void
28
+ isComplete: boolean
29
+ }
30
+
31
+ // Context
32
+ const WizardContext = createContext<WizardContextValue | undefined>(undefined)
33
+
34
+ export function useWizard() {
35
+ const context = useContext(WizardContext)
36
+ if (!context) {
37
+ throw new Error("useWizard must be used within a WizardProvider")
38
+ }
39
+ return context
40
+ }
41
+
42
+ // Provider Component
43
+ interface WizardProviderProps {
44
+ steps: WizardStep[]
45
+ children: React.ReactNode
46
+ onComplete?: () => void
47
+ initialStep?: number
48
+ }
49
+
50
+ export function WizardProvider({
51
+ steps,
52
+ children,
53
+ onComplete,
54
+ initialStep = 0,
55
+ }: WizardProviderProps) {
56
+ const [currentStepIndex, setCurrentStepIndex] = useState(initialStep)
57
+ const [isComplete, setIsComplete] = useState(false)
58
+
59
+ const goToStep = (index: number) => {
60
+ if (index >= 0 && index < steps.length) {
61
+ setCurrentStepIndex(index)
62
+ }
63
+ }
64
+
65
+ const nextStep = () => {
66
+ if (currentStepIndex < steps.length - 1) {
67
+ setCurrentStepIndex(currentStepIndex + 1)
68
+ } else {
69
+ completeWizard()
70
+ }
71
+ }
72
+
73
+ const prevStep = () => {
74
+ if (currentStepIndex > 0) {
75
+ setCurrentStepIndex(currentStepIndex - 1)
76
+ }
77
+ }
78
+
79
+ const completeWizard = () => {
80
+ setIsComplete(true)
81
+ onComplete?.()
82
+ }
83
+
84
+ const getStepStatus = (index: number): WizardStepStatus => {
85
+ if (isComplete) return "completed"
86
+ if (index < currentStepIndex) return "completed"
87
+ if (index === currentStepIndex) return "current"
88
+ return "upcoming"
89
+ }
90
+
91
+ const value = {
92
+ currentStepIndex,
93
+ steps,
94
+ goToStep,
95
+ nextStep,
96
+ prevStep,
97
+ isFirstStep: currentStepIndex === 0,
98
+ isLastStep: currentStepIndex === steps.length - 1,
99
+ getStepStatus,
100
+ completeWizard,
101
+ isComplete,
102
+ }
103
+
104
+ return <WizardContext.Provider value={value}>{children}</WizardContext.Provider>
105
+ }
106
+
107
+ // Wizard Component
108
+ interface WizardProps extends WizardProviderProps {
109
+ className?: string
110
+ showStepIndicator?: boolean
111
+ navigationPosition?: "top" | "bottom" | "both"
112
+ }
113
+
114
+ export function Wizard({
115
+ steps,
116
+ children,
117
+ onComplete,
118
+ initialStep = 0,
119
+ className,
120
+ showStepIndicator = true,
121
+ navigationPosition = "bottom",
122
+ }: WizardProps) {
123
+ return (
124
+ <WizardProvider steps={steps} onComplete={onComplete} initialStep={initialStep}>
125
+ <div className={cn("w-full", className)}>
126
+ {(navigationPosition === "top" || navigationPosition === "both") && (
127
+ <WizardNavigation className="mb-6" />
128
+ )}
129
+
130
+ {showStepIndicator && <WizardStepIndicator className="mb-8" />}
131
+
132
+ <div className="wizard-content">{children}</div>
133
+
134
+ {(navigationPosition === "bottom" || navigationPosition === "both") && (
135
+ <WizardNavigation className="mt-6" />
136
+ )}
137
+ </div>
138
+ </WizardProvider>
139
+ )
140
+ }
141
+
142
+ // Step Indicator Component
143
+ interface WizardStepIndicatorProps {
144
+ className?: string
145
+ }
146
+
147
+ export function WizardStepIndicator({ className }: WizardStepIndicatorProps) {
148
+ const { steps, currentStepIndex, getStepStatus, goToStep } = useWizard()
149
+
150
+ return (
151
+ <div className={cn("w-full", className)}>
152
+ <div className="relative flex w-full justify-between">
153
+ {/* Progress Bar */}
154
+ <div className="absolute top-1/2 h-0.5 w-full -translate-y-1/2 bg-muted">
155
+ <div
156
+ className="h-full bg-primary transition-all duration-300 ease-in-out"
157
+ style={{ width: `${(currentStepIndex / (steps.length - 1)) * 100}%` }}
158
+ />
159
+ </div>
160
+
161
+ {/* Step Indicators */}
162
+ {steps.map((step, index) => {
163
+ const status = getStepStatus(index)
164
+ return (
165
+ <div key={step.id} className="relative z-10 flex flex-col items-center">
166
+ <button
167
+ onClick={() => {
168
+ if (status === "completed") {
169
+ goToStep(index)
170
+ }
171
+ }}
172
+ disabled={status === "upcoming"}
173
+ className={cn(
174
+ "flex h-8 w-8 items-center justify-center rounded-full border-2 text-sm font-medium transition-colors",
175
+ status === "completed" && "border-primary bg-primary text-primary-foreground hover:bg-primary/90",
176
+ status === "current" && "border-primary bg-background text-primary",
177
+ status === "upcoming" && "border-muted bg-background text-muted-foreground"
178
+ )}
179
+ aria-current={status === "current" ? "step" : undefined}
180
+ >
181
+ {status === "completed" ? <Check className="h-4 w-4" /> : index + 1}
182
+ </button>
183
+ <div className="mt-2 text-center">
184
+ <div
185
+ className={cn(
186
+ "text-xs font-medium",
187
+ status === "completed" && "text-primary",
188
+ status === "current" && "text-primary",
189
+ status === "upcoming" && "text-muted-foreground"
190
+ )}
191
+ >
192
+ {step.title}
193
+ </div>
194
+ {step.description && (
195
+ <div className="mt-0.5 text-xs text-muted-foreground">
196
+ {step.description}
197
+ </div>
198
+ )}
199
+ </div>
200
+ </div>
201
+ )
202
+ })}
203
+ </div>
204
+ </div>
205
+ )
206
+ }
207
+
208
+ // Navigation Component
209
+ interface WizardNavigationProps {
210
+ className?: string
211
+ showCancel?: boolean
212
+ onCancel?: () => void
213
+ nextLabel?: string
214
+ backLabel?: string
215
+ completeLabel?: string
216
+ }
217
+
218
+ export function WizardNavigation({
219
+ className,
220
+ showCancel = false,
221
+ onCancel,
222
+ nextLabel = "Next",
223
+ backLabel = "Back",
224
+ completeLabel = "Complete",
225
+ }: WizardNavigationProps) {
226
+ const { nextStep, prevStep, isFirstStep, isLastStep, completeWizard } = useWizard()
227
+
228
+ return (
229
+ <div className={cn("flex items-center justify-between", className)}>
230
+ <div>
231
+ {!isFirstStep && (
232
+ <Button variant="outline" onClick={prevStep}>
233
+ {backLabel}
234
+ </Button>
235
+ )}
236
+ {showCancel && isFirstStep && (
237
+ <Button variant="outline" onClick={onCancel}>
238
+ Cancel
239
+ </Button>
240
+ )}
241
+ </div>
242
+ <Button onClick={isLastStep ? completeWizard : nextStep}>
243
+ {isLastStep ? completeLabel : nextLabel}
244
+ {!isLastStep && <ChevronRight className="ml-1 h-4 w-4" />}
245
+ </Button>
246
+ </div>
247
+ )
248
+ }
249
+
250
+ // Step Component
251
+ interface WizardStepContentProps {
252
+ stepId: string
253
+ children: React.ReactNode
254
+ }
255
+
256
+ export function WizardStepContent({ stepId, children }: WizardStepContentProps) {
257
+ const { steps, currentStepIndex, isComplete } = useWizard()
258
+ const currentStep = steps[currentStepIndex]
259
+
260
+ if (isComplete) return null
261
+ if (currentStep.id !== stepId) return null
262
+
263
+ return <>{children}</>
264
+ }
265
+
266
+ // Completion Component
267
+ interface WizardCompletionProps {
268
+ children: React.ReactNode
269
+ }
270
+
271
+ export function WizardCompletion({ children }: WizardCompletionProps) {
272
+ const { isComplete } = useWizard()
273
+
274
+ if (!isComplete) return null
275
+
276
+ return <>{children}</>
277
+ }
278
+
@@ -1,5 +1,3 @@
1
- "use client"
2
-
3
1
  import * as React from "react"
4
2
  import * as SheetPrimitive from "@radix-ui/react-dialog"
5
3
  import { cva, type VariantProps } from "class-variance-authority"
@@ -3,7 +3,7 @@ import { Toaster as Sonner } from "sonner"
3
3
 
4
4
  type ToasterProps = React.ComponentProps<typeof Sonner>
5
5
 
6
- const Toaster = ({ ...props }: ToasterProps) => {
6
+ const SonnerToaster = ({ ...props }: ToasterProps) => {
7
7
  const { theme = "system" } = useTheme()
8
8
 
9
9
  return (
@@ -26,4 +26,4 @@ const Toaster = ({ ...props }: ToasterProps) => {
26
26
  )
27
27
  }
28
28
 
29
- export { Toaster }
29
+ export { SonnerToaster }