torch-glare 1.2.9 → 1.4.0

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,374 @@
1
+ "use client";
2
+
3
+ import React, {
4
+ forwardRef,
5
+ HTMLAttributes,
6
+ ReactNode,
7
+ createContext,
8
+ useContext,
9
+ } from "react";
10
+ import { cva, type VariantProps } from "class-variance-authority";
11
+ import { cn } from "../utils/cn";
12
+ import { Themes } from "../utils/types";
13
+
14
+ // ─── Context ─────────────────────────────────────────────────────────────────
15
+
16
+ interface StepperContextValue {
17
+ activeStep: number;
18
+ orientation: "horizontal" | "vertical";
19
+ size: "S" | "M" | "L";
20
+ }
21
+
22
+ const StepperContext = createContext<StepperContextValue>({
23
+ activeStep: 0,
24
+ orientation: "horizontal",
25
+ size: "M",
26
+ });
27
+
28
+ const useStepperContext = () => useContext(StepperContext);
29
+
30
+ // ─── Stepper Root ────────────────────────────────────────────────────────────
31
+
32
+ const stepperStyles = cva(["flex gap-0"], {
33
+ variants: {
34
+ orientation: {
35
+ horizontal: "flex-row items-start",
36
+ vertical: "flex-col",
37
+ },
38
+ },
39
+ defaultVariants: {
40
+ orientation: "horizontal",
41
+ },
42
+ });
43
+
44
+ interface StepperProps
45
+ extends HTMLAttributes<HTMLDivElement>, VariantProps<typeof stepperStyles> {
46
+ theme?: Themes;
47
+ activeStep?: number;
48
+ size?: "S" | "M" | "L";
49
+ }
50
+
51
+ const Stepper = forwardRef<HTMLDivElement, StepperProps>(
52
+ (
53
+ {
54
+ className,
55
+ orientation = "horizontal",
56
+ theme,
57
+ activeStep = 0,
58
+ size = "M",
59
+ ...props
60
+ },
61
+ ref,
62
+ ) => (
63
+ <StepperContext.Provider
64
+ value={{
65
+ activeStep,
66
+ orientation: orientation ?? "horizontal",
67
+ size: size ?? "M",
68
+ }}
69
+ >
70
+ <div
71
+ ref={ref}
72
+ data-theme={theme}
73
+ data-orientation={orientation}
74
+ className={cn(stepperStyles({ orientation }), className)}
75
+ {...props}
76
+ />
77
+ </StepperContext.Provider>
78
+ ),
79
+ );
80
+ Stepper.displayName = "Stepper";
81
+
82
+ // ─── Step ────────────────────────────────────────────────────────────────────
83
+
84
+ interface StepProps extends HTMLAttributes<HTMLDivElement> {
85
+ index?: number;
86
+ isCompleted?: boolean;
87
+ isActive?: boolean;
88
+ isError?: boolean;
89
+ }
90
+
91
+ const Step = forwardRef<HTMLDivElement, StepProps>(
92
+ (
93
+ {
94
+ className,
95
+ index = 0,
96
+ isCompleted,
97
+ isActive,
98
+ isError,
99
+ children,
100
+ ...props
101
+ },
102
+ ref,
103
+ ) => {
104
+ const { activeStep, orientation } = useStepperContext();
105
+
106
+ const computedActive = isActive ?? index === activeStep;
107
+ const computedCompleted = isCompleted ?? index < activeStep;
108
+ const computedError = isError ?? false;
109
+
110
+ return (
111
+ <div
112
+ ref={ref}
113
+ data-active={computedActive || undefined}
114
+ data-completed={computedCompleted || undefined}
115
+ data-error={computedError || undefined}
116
+ data-orientation={orientation}
117
+ className={cn(
118
+ "flex group/step",
119
+ orientation === "horizontal"
120
+ ? "shrink-0 flex-col items-center gap-2"
121
+ : "flex-row gap-3",
122
+ className,
123
+ )}
124
+ {...props}
125
+ >
126
+ {React.Children.map(children, (child) => {
127
+ if (!React.isValidElement(child)) return child;
128
+ return React.cloneElement(child as React.ReactElement<any>, {
129
+ _active: computedActive,
130
+ _completed: computedCompleted,
131
+ _error: computedError,
132
+ _index: index,
133
+ });
134
+ })}
135
+ </div>
136
+ );
137
+ },
138
+ );
139
+ Step.displayName = "Step";
140
+
141
+ // ─── Step Indicator ──────────────────────────────────────────────────────────
142
+
143
+ const stepIndicatorStyles = cva(
144
+ [
145
+ "flex items-center justify-center shrink-0 rounded-full",
146
+ "border",
147
+ "transition-all duration-200 ease-in-out",
148
+ "typography-body-small-medium",
149
+ "[&_i]:leading-none [&_i]:flex [&_i]:items-center [&_i]:justify-center",
150
+ ],
151
+ {
152
+ variants: {
153
+ state: {
154
+ pending: [
155
+ "bg-background-presentation-action-disabled",
156
+ "border-border-presentation-action-disabled",
157
+ "text-content-presentation-state-disabled",
158
+ ],
159
+ active: [
160
+ "bg-background-presentation-state-information-primary",
161
+ "border-border-presentation-state-focus",
162
+ "text-content-presentation-state-information",
163
+ ],
164
+ completed: [
165
+ "bg-background-presentation-state-success-primary",
166
+ "border-border-presentation-state-success",
167
+ "text-content-presentation-state-success",
168
+ ],
169
+ error: [
170
+ "bg-background-presentation-state-negative-primary",
171
+ "border-border-presentation-state-negative",
172
+ "text-content-presentation-state-negative",
173
+ ],
174
+ },
175
+ size: {
176
+ S: "w-[22px] h-[22px] text-[10px] [&_i]:text-[12px]",
177
+ M: "w-[28px] h-[28px] text-[12px] [&_i]:text-[14px]",
178
+ L: "w-[34px] h-[34px] text-[14px] [&_i]:text-[16px]",
179
+ },
180
+ },
181
+ defaultVariants: {
182
+ state: "pending",
183
+ size: "M",
184
+ },
185
+ },
186
+ );
187
+
188
+ interface StepIndicatorProps extends HTMLAttributes<HTMLDivElement> {
189
+ icon?: ReactNode;
190
+ completedIcon?: ReactNode;
191
+ errorIcon?: ReactNode;
192
+ _active?: boolean;
193
+ _completed?: boolean;
194
+ _error?: boolean;
195
+ _index?: number;
196
+ }
197
+
198
+ const StepIndicator = forwardRef<HTMLDivElement, StepIndicatorProps>(
199
+ (
200
+ {
201
+ className,
202
+ icon,
203
+ completedIcon,
204
+ errorIcon,
205
+ _active,
206
+ _completed,
207
+ _error,
208
+ _index = 0,
209
+ children,
210
+ ...props
211
+ },
212
+ ref,
213
+ ) => {
214
+ const { size } = useStepperContext();
215
+
216
+ const state = _error
217
+ ? "error"
218
+ : _completed
219
+ ? "completed"
220
+ : _active
221
+ ? "active"
222
+ : "pending";
223
+
224
+ const renderContent = () => {
225
+ if (_error && errorIcon) return errorIcon;
226
+ if (_error) return <i className="ri-close-line" />;
227
+ if (_completed && completedIcon) return completedIcon;
228
+ if (_completed) return <i className="ri-check-line" />;
229
+ if (icon) return icon;
230
+ if (children) return children;
231
+ return _index + 1;
232
+ };
233
+
234
+ return (
235
+ <div
236
+ ref={ref}
237
+ className={cn(stepIndicatorStyles({ state, size }), className)}
238
+ {...props}
239
+ >
240
+ {renderContent()}
241
+ </div>
242
+ );
243
+ },
244
+ );
245
+ StepIndicator.displayName = "StepIndicator";
246
+
247
+ // ─── Step Connector (the line between steps) ────────────────────────────────
248
+
249
+ const connectorStyles = cva(["transition-all duration-200 ease-in-out"], {
250
+ variants: {
251
+ orientation: {
252
+ horizontal: "h-[2px] flex-1 mx-2 mt-[13px]",
253
+ vertical: "w-[2px] flex-1 min-h-[24px] my-2",
254
+ },
255
+ state: {
256
+ pending: "bg-border-presentation-action-disabled",
257
+ completed: "bg-border-presentation-state-focus",
258
+ },
259
+ },
260
+ defaultVariants: {
261
+ orientation: "horizontal",
262
+ state: "pending",
263
+ },
264
+ compoundVariants: [
265
+ {
266
+ orientation: "horizontal",
267
+ className: "self-start",
268
+ },
269
+ ],
270
+ });
271
+
272
+ interface StepConnectorProps extends HTMLAttributes<HTMLDivElement> {
273
+ _completed?: boolean;
274
+ _active?: boolean;
275
+ _error?: boolean;
276
+ _index?: number;
277
+ }
278
+
279
+ const StepConnector = forwardRef<HTMLDivElement, StepConnectorProps>(
280
+ (
281
+ { className, _completed, _active: _a, _error: _e, _index: _i, ...props },
282
+ ref,
283
+ ) => {
284
+ const { orientation } = useStepperContext();
285
+
286
+ return (
287
+ <div
288
+ ref={ref}
289
+ className={cn(
290
+ connectorStyles({
291
+ orientation,
292
+ state: _completed ? "completed" : "pending",
293
+ }),
294
+ className,
295
+ )}
296
+ {...props}
297
+ />
298
+ );
299
+ },
300
+ );
301
+ StepConnector.displayName = "StepConnector";
302
+
303
+ // ─── Step Label ──────────────────────────────────────────────────────────────
304
+
305
+ interface StepLabelProps extends HTMLAttributes<HTMLDivElement> {
306
+ _active?: boolean;
307
+ _completed?: boolean;
308
+ _error?: boolean;
309
+ _index?: number;
310
+ }
311
+
312
+ const StepLabel = forwardRef<HTMLDivElement, StepLabelProps>(
313
+ ({ className, _active, _completed, _error, _index: _i, ...props }, ref) => (
314
+ <div
315
+ ref={ref}
316
+ className={cn(
317
+ "typography-body-small-medium transition-colors duration-200 ease-in-out",
318
+ _active
319
+ ? "text-content-presentation-state-information"
320
+ : _error
321
+ ? "text-content-presentation-state-negative"
322
+ : _completed
323
+ ? "text-content-presentation-global-primary"
324
+ : "text-content-presentation-state-disabled",
325
+ className,
326
+ )}
327
+ {...props}
328
+ />
329
+ ),
330
+ );
331
+ StepLabel.displayName = "StepLabel";
332
+
333
+ // ─── Step Description ────────────────────────────────────────────────────────
334
+
335
+ interface StepDescriptionProps extends HTMLAttributes<HTMLDivElement> {
336
+ _active?: boolean;
337
+ _completed?: boolean;
338
+ _error?: boolean;
339
+ _index?: number;
340
+ }
341
+
342
+ const StepDescription = forwardRef<HTMLDivElement, StepDescriptionProps>(
343
+ (
344
+ { className, _active, _completed: _c, _error: _e, _index: _i, ...props },
345
+ ref,
346
+ ) => (
347
+ <div
348
+ ref={ref}
349
+ className={cn(
350
+ "typography-body-small-regular",
351
+ _active
352
+ ? "text-content-presentation-global-secondary"
353
+ : "text-content-presentation-state-disabled",
354
+ className,
355
+ )}
356
+ {...props}
357
+ />
358
+ ),
359
+ );
360
+ StepDescription.displayName = "StepDescription";
361
+
362
+ // ─── Exports ─────────────────────────────────────────────────────────────────
363
+
364
+ export {
365
+ Stepper,
366
+ Step,
367
+ StepIndicator,
368
+ StepConnector,
369
+ StepLabel,
370
+ StepDescription,
371
+ stepperStyles,
372
+ stepIndicatorStyles,
373
+ connectorStyles,
374
+ };