1import { useId, type CSSProperties, type SVGProps } from "react";
2
3import type { ProviderIcon } from "@t3tools/provider-core/client";
4
5import { cn } from "~/lib/utils";
6
7/**
8 * Draws a provider package's plain-data glyph. Theme colors travel as CSS
9 * variables so the `.dark` class switches them without a re-render.
10 */
11export function ProviderPackageIcon({
12 icon,
13 className,
14 ...props
15}: { readonly icon: ProviderIcon } & SVGProps<SVGSVGElement>) {
16 const gradientId = useId();
17 return (
18 <svg
19 {...props}
20 viewBox={icon.viewBox}
21 fill="none"
22 // Lets monochrome renderings dim the whole glyph once instead of each path.
23 data-provider-package-icon
24 className={cn("fill-(--icon-light) dark:fill-(--icon-dark)", className)}
25 style={
26 {
27 "--icon-light": icon.fill.light,
28 "--icon-dark": icon.fill.dark,
29 } as CSSProperties
30 }
31 >
32 {icon.paths.some((path) => path.gradient) ? (
33 <defs>
34 {icon.paths.map((path, index) =>
35 path.gradient ? (
36 <linearGradient
37 key={path.d}
38 id={`${gradientId}-${index}`}
39 x1={path.gradient.x1}
40 y1={path.gradient.y1}
41 x2={path.gradient.x2}
42 y2={path.gradient.y2}
43 gradientUnits="userSpaceOnUse"
44 >
45 {path.gradient.stops.map((stop) => (
46 <stop key={stop.offset} offset={stop.offset} stopColor={stop.color} />
47 ))}
48 </linearGradient>
49 ) : null,
50 )}
51 </defs>
52 ) : null}
53 {icon.paths.map((path, index) => (
54 <path
55 key={path.d}
56 d={path.d}
57 fillRule={path.fillRule}
58 // An attribute, so monochrome renderings can still override it from CSS.
59 fill={path.gradient ? `url(#${gradientId}-${index})` : undefined}
60 // Monochrome renderings (the collapsed composer) clear these detail paths.
61 data-icon-detail={path.fill ? true : undefined}
62 className={path.fill ? "fill-(--path-light) dark:fill-(--path-dark)" : undefined}
63 style={
64 path.fill
65 ? ({
66 "--path-light": path.fill.light,
67 "--path-dark": path.fill.dark,
68 } as CSSProperties)
69 : undefined
70 }
71 />
72 ))}
73 </svg>
74 );
75}