torch-glare 1.5.1 → 1.5.2

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,302 @@
1
+ "use client";
2
+
3
+ import React, {
4
+ forwardRef,
5
+ HTMLAttributes,
6
+ ReactNode,
7
+ createContext,
8
+ useContext,
9
+ } from "react";
10
+ import { cva } from "class-variance-authority";
11
+ import { cn } from "../utils/cn";
12
+ import { Themes } from "../utils/types";
13
+
14
+ // ─── Types ───────────────────────────────────────────────────────────────────
15
+
16
+ type FormStepperType = "default" | "success" | "negative";
17
+
18
+ // ─── Context ─────────────────────────────────────────────────────────────────
19
+
20
+ interface FormStepperContextValue {
21
+ activeStep: number;
22
+ }
23
+
24
+ const FormStepperContext = createContext<FormStepperContextValue>({
25
+ activeStep: 0,
26
+ });
27
+
28
+ const useFormStepperContext = () => useContext(FormStepperContext);
29
+
30
+ // ─── FormStepper Root ────────────────────────────────────────────────────────
31
+
32
+ interface FormStepperProps extends HTMLAttributes<HTMLDivElement> {
33
+ theme?: Themes;
34
+ activeStep?: number;
35
+ }
36
+
37
+ const FormStepper = forwardRef<HTMLDivElement, FormStepperProps>(
38
+ ({ className, theme, activeStep = 0, ...props }, ref) => (
39
+ <FormStepperContext.Provider value={{ activeStep }}>
40
+ <div
41
+ ref={ref}
42
+ data-theme={theme}
43
+ className={cn("flex items-center gap-3", className)}
44
+ {...props}
45
+ />
46
+ </FormStepperContext.Provider>
47
+ ),
48
+ );
49
+ FormStepper.displayName = "FormStepper";
50
+
51
+ // ─── FormStep (the pill wrapper) ─────────────────────────────────────────────
52
+
53
+ const formStepStyles = cva(
54
+ [
55
+ "group/form-step inline-flex items-center shrink-0",
56
+ "h-[28px] rounded-full p-[2px]",
57
+ "transition-all duration-200 ease-in-out",
58
+ "cursor-pointer select-none outline-none",
59
+ ],
60
+ {
61
+ variants: {
62
+ // Selection drives the pill background. Hover drives a white bg + soft
63
+ // shadow for non-selected pills, and a stronger shadow for selected pills.
64
+ selected: {
65
+ true: [
66
+ "bg-[#000000]",
67
+ "shadow-[0_0_32px_2px_rgba(0,0,0,0.05)]",
68
+ "hover:shadow-[0_0_32px_2px_rgba(0,0,0,0.2)]",
69
+ ],
70
+ false: [
71
+ "bg-transparent",
72
+ "hover:bg-[#FFFFFF]",
73
+ "hover:shadow-[0_0_32px_2px_rgba(0,0,0,0.05)]",
74
+ ],
75
+ },
76
+ },
77
+ defaultVariants: {
78
+ selected: false,
79
+ },
80
+ },
81
+ );
82
+
83
+ interface FormStepProps
84
+ extends Omit<HTMLAttributes<HTMLDivElement>, "type"> {
85
+ index?: number;
86
+ type?: FormStepperType;
87
+ selected?: boolean;
88
+ }
89
+
90
+ const FormStep = forwardRef<HTMLDivElement, FormStepProps>(
91
+ (
92
+ { className, index = 0, type = "default", selected, children, ...props },
93
+ ref,
94
+ ) => {
95
+ const { activeStep } = useFormStepperContext();
96
+ const isSelected = selected ?? index === activeStep;
97
+
98
+ return (
99
+ <div
100
+ ref={ref}
101
+ data-selected={isSelected || undefined}
102
+ data-type={type}
103
+ className={cn(formStepStyles({ selected: isSelected }), className)}
104
+ {...props}
105
+ >
106
+ {React.Children.map(children, (child) => {
107
+ if (!React.isValidElement(child)) return child;
108
+ return React.cloneElement(child as React.ReactElement<any>, {
109
+ _selected: isSelected,
110
+ _type: type,
111
+ _index: index,
112
+ });
113
+ })}
114
+ </div>
115
+ );
116
+ },
117
+ );
118
+ FormStep.displayName = "FormStep";
119
+
120
+ // ─── FormStepIndicator (circle badge) ───────────────────────────────────────
121
+
122
+ const formStepIndicatorStyles = cva(
123
+ [
124
+ "relative inline-flex items-center justify-center shrink-0",
125
+ "w-[24px] h-[24px] text-[14px]",
126
+ "rounded-full",
127
+ "transition-colors duration-200 ease-in-out",
128
+ "typography-body-medium-medium",
129
+ ],
130
+ {
131
+ variants: {
132
+ type: {
133
+ default: ["border-[3px]"],
134
+ success: ["bg-[#047854] text-[#FFFFFF]", "border border-transparent"],
135
+ negative: ["bg-[#E30C30] text-[#FFFFFF]", "border border-transparent"],
136
+ },
137
+ // Only meaningful for type=default. Selected = filled blue, otherwise
138
+ // ring color comes from the resting/hover compound variants below.
139
+ selected: {
140
+ true: "",
141
+ false: "",
142
+ },
143
+ },
144
+ defaultVariants: {
145
+ type: "default",
146
+ selected: false,
147
+ },
148
+ compoundVariants: [
149
+ // Default type, not selected: gray ring + gray number at rest;
150
+ // hover (driven by parent .group/form-step) flips ring blue, number black.
151
+ {
152
+ type: "default",
153
+ selected: false,
154
+ className: [
155
+ "bg-transparent border-[#A0A0A0] text-[#626467]",
156
+ "group-hover/form-step:border-[#004699]",
157
+ "group-hover/form-step:text-[#000000]",
158
+ ],
159
+ },
160
+ // Default type, selected: solid blue fill, white number, no ring color.
161
+ {
162
+ type: "default",
163
+ selected: true,
164
+ className: ["bg-[#005ECC] border-transparent text-[#FFFFFF]"],
165
+ },
166
+ ],
167
+ },
168
+ );
169
+
170
+ const formStepIndicatorBadgeStyles = cva(
171
+ [
172
+ "absolute -top-[7px]",
173
+ "w-[15px] h-[15px]",
174
+ "rounded-full",
175
+ "inline-flex items-center justify-center",
176
+ "border border-[#F0F0F0]",
177
+ "[&_i]:leading-none [&_i]:flex [&_i]:text-[11px]",
178
+ // LTR: badge top-right; RTL: badge top-left
179
+ "ltr:right-[-4px] rtl:left-[-4px]",
180
+ ],
181
+ {
182
+ variants: {
183
+ type: {
184
+ success: "bg-[#047854] text-[#FFFFFF]",
185
+ negative: "bg-[#E30C30] text-[#FFFFFF]",
186
+ },
187
+ },
188
+ },
189
+ );
190
+
191
+ interface FormStepIndicatorProps extends HTMLAttributes<HTMLDivElement> {
192
+ badgeIcon?: ReactNode;
193
+ _selected?: boolean;
194
+ _type?: FormStepperType;
195
+ _index?: number;
196
+ }
197
+
198
+ const FormStepIndicator = forwardRef<HTMLDivElement, FormStepIndicatorProps>(
199
+ (
200
+ {
201
+ className,
202
+ badgeIcon,
203
+ _selected,
204
+ _type = "default",
205
+ _index = 0,
206
+ children,
207
+ ...props
208
+ },
209
+ ref,
210
+ ) => {
211
+ const showBadge = _type === "success" || _type === "negative";
212
+ const defaultBadgeIcon =
213
+ _type === "success" ? (
214
+ <i className="ri-check-line" />
215
+ ) : (
216
+ <i className="ri-information-fill" />
217
+ );
218
+
219
+ return (
220
+ <div
221
+ ref={ref}
222
+ className={cn(
223
+ formStepIndicatorStyles({ type: _type, selected: !!_selected }),
224
+ className,
225
+ )}
226
+ {...props}
227
+ >
228
+ {children ?? _index + 1}
229
+ {showBadge && (
230
+ <span
231
+ className={cn(
232
+ formStepIndicatorBadgeStyles({
233
+ type: _type as "success" | "negative",
234
+ }),
235
+ )}
236
+ aria-hidden
237
+ >
238
+ {badgeIcon ?? defaultBadgeIcon}
239
+ </span>
240
+ )}
241
+ </div>
242
+ );
243
+ },
244
+ );
245
+ FormStepIndicator.displayName = "FormStepIndicator";
246
+
247
+ // ─── FormStepLabel ──────────────────────────────────────────────────────────
248
+
249
+ const formStepLabelStyles = cva(
250
+ [
251
+ "typography-body-small-medium whitespace-nowrap",
252
+ "transition-[padding,color] duration-200 ease-in-out",
253
+ // At rest the label sits 6px from the circle. On hover (parent pill
254
+ // hovered) the gap grows to 9px — matches figma onHover/onSelect-Hoverd.
255
+ // The outer edge keeps a constant 12px.
256
+ "ltr:pl-[6px] ltr:pr-[12px] rtl:pr-[6px] rtl:pl-[12px]",
257
+ "group-hover/form-step:ltr:pl-[9px] group-hover/form-step:rtl:pr-[9px]",
258
+ ],
259
+ {
260
+ variants: {
261
+ selected: {
262
+ true: "text-[#FFFFFF]",
263
+ false: "text-[#000000]",
264
+ },
265
+ },
266
+ defaultVariants: {
267
+ selected: false,
268
+ },
269
+ },
270
+ );
271
+
272
+ interface FormStepLabelProps extends HTMLAttributes<HTMLDivElement> {
273
+ _selected?: boolean;
274
+ _type?: FormStepperType;
275
+ _index?: number;
276
+ }
277
+
278
+ const FormStepLabel = forwardRef<HTMLDivElement, FormStepLabelProps>(
279
+ ({ className, _selected, _type: _t, _index: _i, ...props }, ref) => (
280
+ <div
281
+ ref={ref}
282
+ className={cn(
283
+ formStepLabelStyles({ selected: !!_selected }),
284
+ className,
285
+ )}
286
+ {...props}
287
+ />
288
+ ),
289
+ );
290
+ FormStepLabel.displayName = "FormStepLabel";
291
+
292
+ // ─── Exports ─────────────────────────────────────────────────────────────────
293
+
294
+ export {
295
+ FormStepper,
296
+ FormStep,
297
+ FormStepIndicator,
298
+ FormStepLabel,
299
+ formStepStyles,
300
+ formStepIndicatorStyles,
301
+ formStepLabelStyles,
302
+ };
@@ -1,4 +1,4 @@
1
- 'use client'
1
+ "use client";
2
2
  import * as React from "react";
3
3
  import { cn } from "../utils/cn";
4
4
  import { cva, VariantProps } from "class-variance-authority";
@@ -7,8 +7,6 @@ import { Button } from "./Button";
7
7
  import { Checkbox } from "./Checkbox";
8
8
  import { useResize } from "../hooks/useResize";
9
9
 
10
-
11
-
12
10
  type TableHeadVariantsProps = VariantProps<typeof tableHeadVariants>;
13
11
 
14
12
  const Table = React.forwardRef<
@@ -20,9 +18,11 @@ const Table = React.forwardRef<
20
18
  <table
21
19
  data-theme={theme}
22
20
  ref={ref}
23
- className={cn("overflow-hidden w-auto [border-collapse:separate] border-spacing-0", className)}
21
+ className={cn(
22
+ "overflow-hidden w-auto [border-collapse:separate] border-spacing-0",
23
+ className,
24
+ )}
24
25
  {...props}
25
-
26
26
  >
27
27
  {props.children}
28
28
  </table>
@@ -35,10 +35,7 @@ const TableHeader = React.forwardRef<
35
35
  >(({ className, ...props }, ref) => (
36
36
  <thead
37
37
  ref={ref}
38
- className={cn(
39
- "shadow-[0px_4px_8px_0px_rgba(0,0,0,0.15)]",
40
- className
41
- )}
38
+ className={cn("shadow-[0px_4px_8px_0px_rgba(0,0,0,0.15)]", className)}
42
39
  {...props}
43
40
  />
44
41
  ));
@@ -70,29 +67,32 @@ const TableRow = React.forwardRef<
70
67
  >(({ className, state = "", ...props }, ref) => (
71
68
  <tr
72
69
  ref={ref}
73
- className={cn([
74
- "[&_button]:hover:opacity-100 hover:bg-background-presentation-table-row-hover transition-colors",
75
- {
76
- "bg-background-presentation-table-row-negative border-border-presentation-badge-red":
77
- state === "delete",
78
- },
79
- {
80
- "bg-background-presentation-table-row-information border-border-presentation-badge-navy":
81
- state === "update",
82
- },
83
- {
84
- "bg-background-presentation-table-row-success border-border-presentation-badge-green":
85
- state === "add",
86
- },
87
- {
88
- "bg-background-presentation-table-row-selected border-t border-[2px] border-border-presentation-table-selected":
89
- state === "selected",
90
- },
91
- {
92
- "bg-background-presentation-table-row-hover border-t border-[2px] border-border-presentation-table-dropdown":
93
- state === "open",
94
- },
95
- ], className)}
70
+ className={cn(
71
+ [
72
+ "[&_button]:hover:opacity-100 hover:bg-background-presentation-table-row-hover transition-colors",
73
+ {
74
+ "bg-background-presentation-table-row-negative border-border-presentation-badge-red":
75
+ state === "delete",
76
+ },
77
+ {
78
+ "bg-background-presentation-table-row-information border-border-presentation-badge-navy":
79
+ state === "update",
80
+ },
81
+ {
82
+ "bg-background-presentation-table-row-success border-border-presentation-badge-green":
83
+ state === "add",
84
+ },
85
+ {
86
+ "bg-background-presentation-table-row-selected border-t border-[2px] border-border-presentation-table-selected":
87
+ state === "selected",
88
+ },
89
+ {
90
+ "bg-background-presentation-table-row-hover border-t border-[2px] border-border-presentation-table-dropdown":
91
+ state === "open",
92
+ },
93
+ ],
94
+ className,
95
+ )}
96
96
  {...props}
97
97
  >
98
98
  {props.children}
@@ -103,16 +103,16 @@ TableRow.displayName = "TableRow";
103
103
  const TableHead = React.forwardRef<
104
104
  HTMLTableCellElement,
105
105
  React.ThHTMLAttributes<HTMLTableCellElement> &
106
- TableHeadVariantsProps &
107
- React.ButtonHTMLAttributes<HTMLButtonElement> & {
108
- sortType?: "asc" | "desc" | undefined;
109
- onSort?: () => void;
110
- isDummy?: boolean;
111
- }
106
+ TableHeadVariantsProps &
107
+ React.ButtonHTMLAttributes<HTMLButtonElement> & {
108
+ sortType?: "asc" | "desc" | undefined;
109
+ onSort?: () => void;
110
+ isDummy?: boolean;
111
+ }
112
112
  >(
113
113
  (
114
114
  { className, size = "M", disabled, sortType, onSort, isDummy, ...props },
115
- forwardedRef
115
+ forwardedRef,
116
116
  ) => {
117
117
  const headRef = useRef<any>(null);
118
118
  const { width, handleStartResize } = useResize(headRef);
@@ -136,7 +136,7 @@ const TableHead = React.forwardRef<
136
136
  className={cn(
137
137
  tableHeadVariants({ size, disabled, isDummy }),
138
138
  { "min-w-[100px]": !isDummy },
139
- className
139
+ className,
140
140
  )}
141
141
  >
142
142
  <div
@@ -146,10 +146,15 @@ const TableHead = React.forwardRef<
146
146
  })}
147
147
  >
148
148
  {props.children}
149
- {isDummy || !onSort ? null : <SortButton onSort={onSort} sortType={sortType} />}
149
+ {isDummy || !onSort ? null : (
150
+ <SortButton onSort={onSort} sortType={sortType} />
151
+ )}
150
152
  </div>
151
153
  </div>
152
- <button disabled={isDummy} className="absolute top-[50%] translate-y-[-50%] right-[-1px] rtl:left-[-1px] rtl:right-[unset] h-[20px] w-[2px] rounded-full bg-border-presentation-action-primary">
154
+ <button
155
+ disabled={isDummy}
156
+ className="absolute top-[50%] translate-y-[-50%] right-[-1px] rtl:left-[-1px] rtl:right-[unset] h-[20px] w-[2px] rounded-full bg-border-presentation-action-primary"
157
+ >
153
158
  <ResizeIcon
154
159
  className={cn({ "!opacity-0 cursor-default": isDummy })}
155
160
  onMouseDown={handleStartResize}
@@ -158,7 +163,7 @@ const TableHead = React.forwardRef<
158
163
  </button>
159
164
  </th>
160
165
  );
161
- }
166
+ },
162
167
  );
163
168
  TableHead.displayName = "TableHead";
164
169
 
@@ -179,7 +184,7 @@ const TableCell = React.forwardRef<
179
184
  "border-r border-b border-border-presentation-table-header px-1 rtl:border-l rtl:border-r-0",
180
185
  "break-all",
181
186
  ],
182
- className
187
+ className,
183
188
  )}
184
189
  {...props}
185
190
  >
@@ -189,7 +194,9 @@ const TableCell = React.forwardRef<
189
194
  "[mask-image:linear-gradient(to_right,black_0%,black_0%,black_75%,transparent_100%)]",
190
195
  "rtl:[mask-image:linear-gradient(to_left,black_0%,black_0%,black_75%,transparent_100%)]",
191
196
  "[&:has(input)]:[mask-image:none]",
192
- { "min-w-fit justify-center": isDummy }, childrenClassName)}
197
+ { "min-w-fit justify-center": isDummy },
198
+ childrenClassName,
199
+ )}
193
200
  >
194
201
  {props.children}
195
202
  </div>
@@ -230,15 +237,11 @@ const TableFooterButton = React.forwardRef<
230
237
  }>
231
238
  >(({ children, className, ...props }, ref) => {
232
239
  return (
233
- <TableRow
234
- className={cn(
235
- "h-[40px] overflow-hidden",
236
- className
237
- )}
238
- >
240
+ <TableRow className={cn("h-[40px] overflow-hidden", className)}>
239
241
  <TableCell
240
242
  className={
241
- "border-t-2 border-b-2 border-transparent hover:border-border-presentation-table-action-hover hover:bg-background-presentation-table-acton-hover"}
243
+ "border-t-2 border-b-2 border-transparent hover:border-border-presentation-table-action-hover hover:bg-background-presentation-table-acton-hover"
244
+ }
242
245
  colSpan={100}
243
246
  >
244
247
  <button
@@ -246,16 +249,17 @@ const TableFooterButton = React.forwardRef<
246
249
  {...props}
247
250
  className={cn(
248
251
  "overflow-hidden w-full flex items-center justify-start gap-2 typography-body-medium-semibold [&_i]:text-[20px]",
249
- className
252
+ className,
250
253
  )}
251
- >{children}</button>
254
+ >
255
+ {children}
256
+ </button>
252
257
  </TableCell>
253
258
  </TableRow>
254
259
  );
255
260
  });
256
261
  TableFooterButton.displayName = "TableFooterButton";
257
262
 
258
-
259
263
  const SubTableButton = ({
260
264
  isActive,
261
265
  className,
@@ -273,7 +277,7 @@ const SubTableButton = ({
273
277
  "hover:bg-transparent hover:text-black focus:bg-transparent focus:text-black active:bg-transparent active:text-black":
274
278
  dummy,
275
279
  },
276
- className
280
+ className,
277
281
  )}
278
282
  variant={"PrimeStyle"}
279
283
  buttonType={"icon"}
@@ -283,7 +287,7 @@ const SubTableButton = ({
283
287
  "ri-arrow-right-s-line",
284
288
  "rtl:rotate-180",
285
289
  "transition-transform duration-200",
286
- { "rotate-90": isActive }
290
+ { "rotate-90": isActive },
287
291
  )}
288
292
  ></i>
289
293
  </Button>
@@ -308,7 +312,10 @@ const ResizeIcon = (props: any) => {
308
312
  return (
309
313
  <svg
310
314
  {...props}
311
- className={cn("z-50 cursor-col-resize absolute top-[50%] right-[50%] translate-x-[50%] translate-y-[-50%] opacity-0 hover:opacity-100 transition-opacity duration-200", props.className)}
315
+ className={cn(
316
+ "z-50 cursor-col-resize absolute top-[50%] right-[50%] translate-x-[50%] translate-y-[-50%] opacity-0 hover:opacity-100 transition-opacity duration-200",
317
+ props.className,
318
+ )}
312
319
  width="8"
313
320
  height="32"
314
321
  viewBox="0 0 8 40"
@@ -351,9 +358,6 @@ const SortButton = ({
351
358
  );
352
359
  };
353
360
 
354
-
355
-
356
-
357
361
  const tableHeadVariants = cva(
358
362
  [
359
363
  "text-content-presentation-global-primary",
@@ -365,7 +369,7 @@ const tableHeadVariants = cva(
365
369
  "text-start",
366
370
  "bg-transparent",
367
371
  "hover:bg-background-presentation-action-hover",
368
- "hover:text-content-presentation-action-hover",
372
+ "hover:text-content-presentation-global-hover",
369
373
  "transition-[background-color,color]",
370
374
  "duration-200",
371
375
  "rounded-[3px]",
@@ -394,5 +398,5 @@ const tableHeadVariants = cva(
394
398
  size: "M",
395
399
  },
396
400
  },
397
- }
398
- );
401
+ },
402
+ );
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "torch-glare",
3
- "version": "1.5.1",
3
+ "version": "1.5.2",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "files": [