torch-glare 2.1.0 → 2.1.1

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.
@@ -60,7 +60,7 @@ const solidCompoundVariants = [
60
60
  ];
61
61
 
62
62
  const SUBTLE_TEXT =
63
- "text-content-presentation-global-subtle [&_i]:text-content-presentation-global-subtle mix-blend-luminosity";
63
+ "text-content-presentation-global-subtle [&>div]:mix-blend-luminosity [&_i]:text-content-presentation-global-subtle [&_i]:mix-blend-luminosity [&>button]:mix-blend-luminosity";
64
64
 
65
65
  const subtleCompoundVariants = [
66
66
  {
@@ -163,8 +163,8 @@ interface BadgeProps
163
163
  label?: string;
164
164
  badgeIcon?: ReactNode;
165
165
  showIcon?: boolean;
166
- isSelected?: boolean;
167
- onUnselect?: () => void;
166
+ isClosable?: boolean;
167
+ onClose?: () => void;
168
168
  theme?: Themes;
169
169
  className?: string;
170
170
  }
@@ -173,8 +173,8 @@ export const Badge: React.FC<BadgeProps> = ({
173
173
  label,
174
174
  badgeIcon,
175
175
  showIcon = true,
176
- isSelected,
177
- onUnselect,
176
+ isClosable,
177
+ onClose,
178
178
  theme,
179
179
  badgeStyle,
180
180
  color,
@@ -188,7 +188,7 @@ export const Badge: React.FC<BadgeProps> = ({
188
188
  data-theme={theme}
189
189
  className={cn(
190
190
  badgeStyles({ badgeStyle, color, size }),
191
- { "cursor-default": isSelected },
191
+ { "cursor-default": isClosable },
192
192
  className,
193
193
  )}
194
194
  >
@@ -198,149 +198,46 @@ export const Badge: React.FC<BadgeProps> = ({
198
198
  </div>
199
199
  )}
200
200
 
201
- {label && (
202
- <div className={cn("px-[3px]", { "pt-[1px]": size === "M" })}>
203
- {label}
204
- </div>
205
- )}
201
+ {label && <div className="px-[3px]">{label}</div>}
206
202
 
207
- {isSelected && (
203
+ {isClosable && (
208
204
  <button
209
205
  type="button"
210
- onClick={onUnselect}
206
+ onClick={onClose}
211
207
  onKeyDown={(e) => {
212
208
  if (e.key === "Enter" || e.key === " ") {
213
209
  e.preventDefault();
214
- onUnselect?.();
210
+ onClose?.();
215
211
  }
216
212
  }}
217
- className="rounded-[2px] flex items-center justify-center cursor-pointer"
213
+ className={cn(
214
+ "rounded-[4px]",
215
+ "flex items-center justify-center cursor-pointer",
216
+ "hover:bg-background-presentation-action-secondary",
217
+ "transition-colors duration-150",
218
+ size === "M"
219
+ ? "w-[16px] h-[16px]"
220
+ : size === "S"
221
+ ? "w-[14px] h-[14px]"
222
+ : "w-[12px] h-[12px]",
223
+ )}
218
224
  aria-label="Remove badge"
219
225
  >
220
- <i className="ri-close-line" />
226
+ <svg
227
+ xmlns="http://www.w3.org/2000/svg"
228
+ width="100%"
229
+ height="100%"
230
+ viewBox="0 0 12 12"
231
+ fill="none"
232
+ aria-hidden="true"
233
+ >
234
+ <path
235
+ d="M6.00002 5.33336L8.33334 3L9 3.66667L6.66668 6.00002L9 8.33334L8.33334 9L6.00002 6.66668L3.66667 9L3 8.33334L5.33336 6.00002L3 3.66667L3.66667 3L6.00002 5.33336Z"
236
+ fill="currentColor"
237
+ />
238
+ </svg>
221
239
  </button>
222
240
  )}
223
241
  </span>
224
242
  );
225
243
  };
226
-
227
- /* ============================================================
228
- * REFERENCE — original Badge implementation (pre-NEWCOLORS2)
229
- * Kept as a commented snippet so the old token names and variant
230
- * surface remain consultable while migrating callers. Do not
231
- * uncomment — the referenced tokens no longer exist in the
232
- * regenerated mapping-color-system plugin.
233
- * ============================================================
234
- *
235
- * export const badgeBase = cva(
236
- * [
237
- * "px-[6px]",
238
- * "[&_div]:text-content-presentation-action-light-primary",
239
- * "[&_i]:!leading-none",
240
- * "flex",
241
- * "justify-center",
242
- * "items-center",
243
- * "border",
244
- * "rounded-[6px]",
245
- * "transition-all",
246
- * "duration-300",
247
- * "ease-in-out",
248
- * "w-fit",
249
- * "cursor-pointer",
250
- * "[&_i]:leading-0",
251
- * ],
252
- * {
253
- * variants: {
254
- * size: {
255
- * XS: "h-[18px] [&_i]:text-[12px] [&_div]:typography-body-small-medium",
256
- * S: "h-[22px] [&_i]:text-[12px] [&_div]:typography-body-small-medium",
257
- * M: "h-[26px] [&_i]:text-[16px] [&_div]:typography-body-medium-medium",
258
- * },
259
- * variant: {
260
- * highlight: ["h-[20px] [&_i]:text-[12px] [&_div]:typography-body-small-medium",
261
- * "bg-background-presentation-badge-gray border-transparent px-[3px]"
262
- * ],
263
- * green: "border-border-presentation-badge-green bg-background-presentation-badge-green [&_i]:text-content-presentation-badge-green",
264
- * greenLight: "border-border-presentation-badge-green-light bg-background-presentation-badge-green-light [&_i]:text-content-presentation-badge-green-light",
265
- * cocktailGreen: "border-border-presentation-badge-cocktail-green bg-background-presentation-badge-cocktail-green [&_i]:text-content-presentation-badge-cocktail-green",
266
- * yellow: "border-border-presentation-badge-yellow bg-background-presentation-badge-yellow [&_i]:text-content-presentation-badge-yellow",
267
- * redOrange: "border-border-presentation-badge-red-orange bg-background-presentation-badge-red-orange [&_i]:text-content-presentation-badge-red-orange",
268
- * redLight: "border-border-presentation-badge-red bg-background-presentation-badge-red [&_i]:text-content-presentation-badge-red",
269
- * rose: "border-border-presentation-badge-rose bg-background-presentation-badge-rose [&_i]:text-content-presentation-badge-rose",
270
- * purple: "border-border-presentation-badge-purple bg-background-presentation-badge-purple [&_i]:text-content-presentation-badge-purple",
271
- * bluePurple: "border-border-presentation-badge-blue-purple bg-background-presentation-badge-blue-purple [&_i]:text-content-presentation-badge-blue-purple",
272
- * blue: "border-border-presentation-badge-blue bg-background-presentation-badge-blue [&_i]:text-content-presentation-badge-blue",
273
- * navy: "border-border-presentation-badge-navy bg-background-presentation-badge-navy [&_i]:text-content-presentation-badge-navy",
274
- * gray: "border-border-presentation-badge-gray bg-background-presentation-badge-gray [&_i]:text-content-presentation-badge-gray",
275
- * },
276
- * },
277
- * defaultVariants: {
278
- * size: "S",
279
- * variant: "green",
280
- * },
281
- * }
282
- * );
283
- *
284
- * interface BadgeProps extends HTMLAttributes<HTMLButtonElement>,
285
- * VariantProps<typeof badgeBase> {
286
- * label?: string;
287
- * onUnselect?: () => void;
288
- * isSelected?: boolean;
289
- * badgeIcon?: ReactNode;
290
- * className?: string;
291
- * theme?: Themes
292
- * }
293
- *
294
- * export const Badge: React.FC<BadgeProps> = ({
295
- * label,
296
- * onUnselect,
297
- * isSelected,
298
- * badgeIcon,
299
- * theme,
300
- * size = "S",
301
- * variant = "green",
302
- * className,
303
- * ...props
304
- * }) => {
305
- * return (
306
- * <span
307
- * {...props}
308
- * data-theme={theme}
309
- * className={cn(
310
- * badgeBase({ size, variant }),
311
- * {
312
- * "cursor-default": isSelected,
313
- * },
314
- * className
315
- * )}
316
- * >
317
- * <div className={"flex justify-center items-center"}>
318
- * {!badgeIcon ? (
319
- * <i className={cn("ri-circle-fill !text-[8px]", { "hidden": variant === "highlight" })}></i>
320
- * ) : (
321
- * badgeIcon
322
- * )}
323
- * </div>
324
- *
325
- * <div className="px-[3px] whitespace-nowrap">{label}</div>
326
- * {isSelected && (
327
- * <button
328
- * onClick={onUnselect}
329
- * className="rounded-[2px] flex justify-center items-center cursor-pointer"
330
- * tabIndex={0}
331
- * role="button"
332
- * aria-label="Remove badge"
333
- * onKeyDown={(e) => {
334
- * if (e.key === 'Enter' || e.key === ' ') {
335
- * e.preventDefault();
336
- * onUnselect?.();
337
- * }
338
- * }}
339
- * >
340
- * <i className="ri-close-line !text-content-presentation-action-light-primary"></i>
341
- * </button>
342
- * )}
343
- * </span>
344
- * );
345
- * };
346
- */
@@ -126,8 +126,8 @@ export const BadgeField = forwardRef<HTMLInputElement, Props>(
126
126
  size={size}
127
127
  color={tag.variant as any}
128
128
  label={tag.name}
129
- isSelected={true}
130
- onUnselect={() => handleUnselectTag(tag.id)}
129
+ isClosable={true}
130
+ onClose={() => handleUnselectTag(tag.id)}
131
131
  className={
132
132
  focusedTagIndex === index ? "ring-2 ring-blue-500" : ""
133
133
  }
@@ -0,0 +1,365 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import * as RechartsPrimitive from "recharts"
5
+
6
+ import { cn } from "../utils/cn"
7
+
8
+ // Format: { THEME_NAME: CSS_SELECTOR }
9
+ const THEMES = { light: "", dark: ".dark" } as const
10
+
11
+ export type ChartConfig = {
12
+ [k in string]: {
13
+ label?: React.ReactNode
14
+ icon?: React.ComponentType
15
+ } & (
16
+ | { color?: string; theme?: never }
17
+ | { color?: never; theme: Record<keyof typeof THEMES, string> }
18
+ )
19
+ }
20
+
21
+ type ChartContextProps = {
22
+ config: ChartConfig
23
+ }
24
+
25
+ const ChartContext = React.createContext<ChartContextProps | null>(null)
26
+
27
+ function useChart() {
28
+ const context = React.useContext(ChartContext)
29
+
30
+ if (!context) {
31
+ throw new Error("useChart must be used within a <ChartContainer />")
32
+ }
33
+
34
+ return context
35
+ }
36
+
37
+ const ChartContainer = React.forwardRef<
38
+ HTMLDivElement,
39
+ React.ComponentProps<"div"> & {
40
+ config: ChartConfig
41
+ children: React.ComponentProps<
42
+ typeof RechartsPrimitive.ResponsiveContainer
43
+ >["children"]
44
+ }
45
+ >(({ id, className, children, config, ...props }, ref) => {
46
+ const uniqueId = React.useId()
47
+ const chartId = `chart-${id || uniqueId.replace(/:/g, "")}`
48
+
49
+ return (
50
+ <ChartContext.Provider value={{ config }}>
51
+ <div
52
+ data-chart={chartId}
53
+ ref={ref}
54
+ className={cn(
55
+ "flex aspect-video justify-center text-xs [&_.recharts-cartesian-axis-tick_text]:fill-muted-foreground [&_.recharts-cartesian-grid_line[stroke='#ccc']]:stroke-border/50 [&_.recharts-curve.recharts-tooltip-cursor]:stroke-border [&_.recharts-dot[stroke='#fff']]:stroke-transparent [&_.recharts-layer]:outline-none [&_.recharts-polar-grid_[stroke='#ccc']]:stroke-border [&_.recharts-radial-bar-background-sector]:fill-muted [&_.recharts-rectangle.recharts-tooltip-cursor]:fill-muted [&_.recharts-reference-line_[stroke='#ccc']]:stroke-border [&_.recharts-sector[stroke='#fff']]:stroke-transparent [&_.recharts-sector]:outline-none [&_.recharts-surface]:outline-none",
56
+ className
57
+ )}
58
+ {...props}
59
+ >
60
+ <ChartStyle id={chartId} config={config} />
61
+ <RechartsPrimitive.ResponsiveContainer>
62
+ {children}
63
+ </RechartsPrimitive.ResponsiveContainer>
64
+ </div>
65
+ </ChartContext.Provider>
66
+ )
67
+ })
68
+ ChartContainer.displayName = "Chart"
69
+
70
+ const ChartStyle = ({ id, config }: { id: string; config: ChartConfig }) => {
71
+ const colorConfig = Object.entries(config).filter(
72
+ ([, config]) => config.theme || config.color
73
+ )
74
+
75
+ if (!colorConfig.length) {
76
+ return null
77
+ }
78
+
79
+ return (
80
+ <style
81
+ dangerouslySetInnerHTML={{
82
+ __html: Object.entries(THEMES)
83
+ .map(
84
+ ([theme, prefix]) => `
85
+ ${prefix} [data-chart=${id}] {
86
+ ${colorConfig
87
+ .map(([key, itemConfig]) => {
88
+ const color =
89
+ itemConfig.theme?.[theme as keyof typeof itemConfig.theme] ||
90
+ itemConfig.color
91
+ return color ? ` --color-${key}: ${color};` : null
92
+ })
93
+ .join("\n")}
94
+ }
95
+ `
96
+ )
97
+ .join("\n"),
98
+ }}
99
+ />
100
+ )
101
+ }
102
+
103
+ const ChartTooltip = RechartsPrimitive.Tooltip
104
+
105
+ const ChartTooltipContent = React.forwardRef<
106
+ HTMLDivElement,
107
+ React.ComponentProps<typeof RechartsPrimitive.Tooltip> &
108
+ React.ComponentProps<"div"> & {
109
+ hideLabel?: boolean
110
+ hideIndicator?: boolean
111
+ indicator?: "line" | "dot" | "dashed"
112
+ nameKey?: string
113
+ labelKey?: string
114
+ }
115
+ >(
116
+ (
117
+ {
118
+ active,
119
+ payload,
120
+ className,
121
+ indicator = "dot",
122
+ hideLabel = false,
123
+ hideIndicator = false,
124
+ label,
125
+ labelFormatter,
126
+ labelClassName,
127
+ formatter,
128
+ color,
129
+ nameKey,
130
+ labelKey,
131
+ },
132
+ ref
133
+ ) => {
134
+ const { config } = useChart()
135
+
136
+ const tooltipLabel = React.useMemo(() => {
137
+ if (hideLabel || !payload?.length) {
138
+ return null
139
+ }
140
+
141
+ const [item] = payload
142
+ const key = `${labelKey || item?.dataKey || item?.name || "value"}`
143
+ const itemConfig = getPayloadConfigFromPayload(config, item, key)
144
+ const value =
145
+ !labelKey && typeof label === "string"
146
+ ? config[label as keyof typeof config]?.label || label
147
+ : itemConfig?.label
148
+
149
+ if (labelFormatter) {
150
+ return (
151
+ <div className={cn("font-medium", labelClassName)}>
152
+ {labelFormatter(value, payload)}
153
+ </div>
154
+ )
155
+ }
156
+
157
+ if (!value) {
158
+ return null
159
+ }
160
+
161
+ return <div className={cn("font-medium", labelClassName)}>{value}</div>
162
+ }, [
163
+ label,
164
+ labelFormatter,
165
+ payload,
166
+ hideLabel,
167
+ labelClassName,
168
+ config,
169
+ labelKey,
170
+ ])
171
+
172
+ if (!active || !payload?.length) {
173
+ return null
174
+ }
175
+
176
+ const nestLabel = payload.length === 1 && indicator !== "dot"
177
+
178
+ return (
179
+ <div
180
+ ref={ref}
181
+ className={cn(
182
+ "grid min-w-[8rem] items-start gap-1.5 rounded-lg border border-border/50 bg-background px-2.5 py-1.5 text-xs shadow-xl",
183
+ className
184
+ )}
185
+ >
186
+ {!nestLabel ? tooltipLabel : null}
187
+ <div className="grid gap-1.5">
188
+ {payload.map((item: any, index: number) => {
189
+ const key = `${nameKey || item.name || item.dataKey || "value"}`
190
+ const itemConfig = getPayloadConfigFromPayload(config, item, key)
191
+ const indicatorColor = color || item.payload.fill || item.color
192
+
193
+ return (
194
+ <div
195
+ key={item.dataKey}
196
+ className={cn(
197
+ "flex w-full flex-wrap items-stretch gap-2 [&>svg]:h-2.5 [&>svg]:w-2.5 [&>svg]:text-muted-foreground",
198
+ indicator === "dot" && "items-center"
199
+ )}
200
+ >
201
+ {formatter && item?.value !== undefined && item.name ? (
202
+ formatter(item.value, item.name, item, index, item.payload)
203
+ ) : (
204
+ <>
205
+ {itemConfig?.icon ? (
206
+ <itemConfig.icon />
207
+ ) : (
208
+ !hideIndicator && (
209
+ <div
210
+ className={cn(
211
+ "shrink-0 rounded-[2px] border-[--color-border] bg-[--color-bg]",
212
+ {
213
+ "h-2.5 w-2.5": indicator === "dot",
214
+ "w-1": indicator === "line",
215
+ "w-0 border-[1.5px] border-dashed bg-transparent":
216
+ indicator === "dashed",
217
+ "my-0.5": nestLabel && indicator === "dashed",
218
+ }
219
+ )}
220
+ style={
221
+ {
222
+ "--color-bg": indicatorColor,
223
+ "--color-border": indicatorColor,
224
+ } as React.CSSProperties
225
+ }
226
+ />
227
+ )
228
+ )}
229
+ <div
230
+ className={cn(
231
+ "flex flex-1 justify-between leading-none",
232
+ nestLabel ? "items-end" : "items-center"
233
+ )}
234
+ >
235
+ <div className="grid gap-1.5">
236
+ {nestLabel ? tooltipLabel : null}
237
+ <span className="text-muted-foreground">
238
+ {itemConfig?.label || item.name}
239
+ </span>
240
+ </div>
241
+ {item.value && (
242
+ <span className="font-mono font-medium tabular-nums text-foreground">
243
+ {item.value.toLocaleString()}
244
+ </span>
245
+ )}
246
+ </div>
247
+ </>
248
+ )}
249
+ </div>
250
+ )
251
+ })}
252
+ </div>
253
+ </div>
254
+ )
255
+ }
256
+ )
257
+ ChartTooltipContent.displayName = "ChartTooltip"
258
+
259
+ const ChartLegend = RechartsPrimitive.Legend
260
+
261
+ const ChartLegendContent = React.forwardRef<
262
+ HTMLDivElement,
263
+ React.ComponentProps<"div"> &
264
+ Pick<RechartsPrimitive.LegendProps, "payload" | "verticalAlign"> & {
265
+ hideIcon?: boolean
266
+ nameKey?: string
267
+ }
268
+ >(
269
+ (
270
+ { className, hideIcon = false, payload, verticalAlign = "bottom", nameKey },
271
+ ref
272
+ ) => {
273
+ const { config } = useChart()
274
+
275
+ if (!payload?.length) {
276
+ return null
277
+ }
278
+
279
+ return (
280
+ <div
281
+ ref={ref}
282
+ className={cn(
283
+ "flex items-center justify-center gap-4",
284
+ verticalAlign === "top" ? "pb-3" : "pt-3",
285
+ className
286
+ )}
287
+ >
288
+ {payload.map((item) => {
289
+ const key = `${nameKey || item.dataKey || "value"}`
290
+ const itemConfig = getPayloadConfigFromPayload(config, item, key)
291
+
292
+ return (
293
+ <div
294
+ key={item.value}
295
+ className={cn(
296
+ "flex items-center gap-1.5 [&>svg]:h-3 [&>svg]:w-3 [&>svg]:text-muted-foreground"
297
+ )}
298
+ >
299
+ {itemConfig?.icon && !hideIcon ? (
300
+ <itemConfig.icon />
301
+ ) : (
302
+ <div
303
+ className="h-2 w-2 shrink-0 rounded-[2px]"
304
+ style={{
305
+ backgroundColor: item.color,
306
+ }}
307
+ />
308
+ )}
309
+ {itemConfig?.label}
310
+ </div>
311
+ )
312
+ })}
313
+ </div>
314
+ )
315
+ }
316
+ )
317
+ ChartLegendContent.displayName = "ChartLegend"
318
+
319
+ // Helper to extract item config from a payload.
320
+ function getPayloadConfigFromPayload(
321
+ config: ChartConfig,
322
+ payload: unknown,
323
+ key: string
324
+ ) {
325
+ if (typeof payload !== "object" || payload === null) {
326
+ return undefined
327
+ }
328
+
329
+ const payloadPayload =
330
+ "payload" in payload &&
331
+ typeof payload.payload === "object" &&
332
+ payload.payload !== null
333
+ ? payload.payload
334
+ : undefined
335
+
336
+ let configLabelKey: string = key
337
+
338
+ if (
339
+ key in payload &&
340
+ typeof payload[key as keyof typeof payload] === "string"
341
+ ) {
342
+ configLabelKey = payload[key as keyof typeof payload] as string
343
+ } else if (
344
+ payloadPayload &&
345
+ key in payloadPayload &&
346
+ typeof payloadPayload[key as keyof typeof payloadPayload] === "string"
347
+ ) {
348
+ configLabelKey = payloadPayload[
349
+ key as keyof typeof payloadPayload
350
+ ] as string
351
+ }
352
+
353
+ return configLabelKey in config
354
+ ? config[configLabelKey]
355
+ : config[key as keyof typeof config]
356
+ }
357
+
358
+ export {
359
+ ChartContainer,
360
+ ChartTooltip,
361
+ ChartTooltipContent,
362
+ ChartLegend,
363
+ ChartLegendContent,
364
+ ChartStyle,
365
+ }