@the21og/a16z 0.0.1 → 0.0.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,219 @@
1
+ /**
2
+ * UI Lib - Chart System
3
+ *
4
+ * @module Chart
5
+ * @description A flexible wrapper around Recharts designed for the Red/Neutral theme context.
6
+ * Focuses on accessible color mapping and responsive container handling.
7
+ * @version 1.0.0 - Generated for user request: "create a chart component"
8
+ */
9
+
10
+ import * as React from "react";
11
+ import { ResponsiveContainer, Tooltip as RechartsTooltip, Legend as RechartsLegend } from "recharts";
12
+
13
+ // -----------------------------------------------------------------------------
14
+ // Types & Context
15
+ // -----------------------------------------------------------------------------
16
+
17
+ export type ChartConfig = Record<
18
+ string,
19
+ {
20
+ label?: React.ReactNode;
21
+ icon?: React.ComponentType;
22
+ color?: string;
23
+ theme?: Record<"light" | "dark", string>;
24
+ }
25
+ >;
26
+
27
+ type ChartContextProps = {
28
+ config: ChartConfig;
29
+ };
30
+
31
+ const ChartContext = React.createContext<ChartContextProps | null>(null);
32
+
33
+ const useChart = () => {
34
+ const context = React.useContext(ChartContext);
35
+ if (!context) {
36
+ throw new Error("useChart must be used within a ChartContainer");
37
+ }
38
+ return context;
39
+ };
40
+
41
+ // -----------------------------------------------------------------------------
42
+ // Components
43
+ // -----------------------------------------------------------------------------
44
+
45
+ /**
46
+ * Wrapper that injects CSS variables for chart colors based on the current theme configuration.
47
+ */
48
+ export const ChartContainer = React.forwardRef<
49
+ HTMLDivElement,
50
+ React.ComponentProps<"div"> & {
51
+ config: ChartConfig;
52
+ children: React.ReactComponentElement<any, any>;
53
+ }
54
+ >(({ id, className, children, config, ...props }, ref) => {
55
+ const uniqueId = React.useId();
56
+ const chartId = `chart-${id || uniqueId.replace(/:/g, "")}`;
57
+
58
+ return (
59
+ <ChartContext.Provider value={{ config }}>
60
+ <div
61
+ ref={ref}
62
+ data-chart={chartId}
63
+ id={chartId}
64
+ className={`flex aspect-video justify-center text-xs ${className || ""}`}
65
+ {...props}
66
+ >
67
+ <ChartStyle id={chartId} config={config} />
68
+ <ResponsiveContainer>
69
+ {children}
70
+ </ResponsiveContainer>
71
+ </div>
72
+ </ChartContext.Provider>
73
+ );
74
+ });
75
+ ChartContainer.displayName = "ChartContainer";
76
+
77
+ /**
78
+ * Generates a style tag to map internal chart colors to CSS variables.
79
+ */
80
+ const ChartStyle = ({ id, config }: { id: string; config: ChartConfig }) => {
81
+ const colorConfig = Object.entries(config).filter(([_, config]) => config.theme || config.color);
82
+ if (!colorConfig.length) return null;
83
+
84
+ return (
85
+ <style dangerouslySetInnerHTML={{ __html:
86
+ `[data-chart=${id}] {
87
+ ${colorConfig.map(([key, item]) => {
88
+ const color = item.theme?.light || item.color;
89
+ return color ? `--color-${key}: ${color};` : "";
90
+ }).join("\n")}
91
+ }
92
+ .dark [data-chart=${id}] {
93
+ ${colorConfig.map(([key, item]) => {
94
+ const color = item.theme?.dark || item.color;
95
+ return color ? `--color-${key}: ${color};` : "";
96
+ }).join("\n")}
97
+ }`
98
+ }} />
99
+ );
100
+ };
101
+
102
+ /**
103
+ * Custom Tooltip implementation ensuring consistent Red/Neutral styling.
104
+ */
105
+ export const ChartTooltip = RechartsTooltip;
106
+
107
+ export const ChartTooltipContent = React.forwardRef<
108
+ HTMLDivElement,
109
+ React.ComponentProps<"div"> & {
110
+ active?: boolean;
111
+ payload?: any[];
112
+ indicator?: "line" | "dot" | "dashed";
113
+ hideLabel?: boolean;
114
+ label?: string;
115
+ labelFormatter?: (value: any, payload: any[]) => React.ReactNode;
116
+ formatter?: (value: any, name: string, item: any, index: number, payload: any) => React.ReactNode;
117
+ color?: string;
118
+ nameKey?: string;
119
+ labelKey?: string;
120
+ }
121
+ >(({
122
+ active,
123
+ payload,
124
+ indicator = "dot",
125
+ hideLabel = false,
126
+ label,
127
+ labelFormatter,
128
+ className,
129
+ formatter,
130
+ color,
131
+ nameKey,
132
+ labelKey,
133
+ }, ref) => {
134
+ const { config } = useChart();
135
+
136
+ if (!active || !payload?.length) {
137
+ return null;
138
+ }
139
+
140
+ return (
141
+ <div
142
+ ref={ref}
143
+ className={`grid min-w-[8rem] items-start gap-1.5 rounded-xl border border-neutral-200 bg-white px-2.5 py-1.5 text-xs shadow-sm dark:border-neutral-800 dark:bg-neutral-950 ${className || ""}`}
144
+ >
145
+ {!hideLabel && (
146
+ <div className="mb-1 font-medium text-neutral-500 dark:text-neutral-400">
147
+ {labelFormatter ? labelFormatter(label, payload) : label}
148
+ </div>
149
+ )}
150
+ <div className="grid gap-1.5">
151
+ {payload.map((item, index) => {
152
+ const key = `${nameKey || item.name || item.dataKey || "value"}`;
153
+ const itemConfig = config[key] || config[item.name] || {};
154
+
155
+ const indicatorColor = color || item.payload.fill || item.color;
156
+
157
+ return (
158
+ <div
159
+ key={item.dataKey + index}
160
+ className="flex w-full flex-wrap items-stretch gap-2 [&>svg]:h-2.5 [&>svg]:w-2.5 [&>svg]:text-neutral-500 dark:[&>svg]:text-neutral-400"
161
+ >
162
+ {indicator === "dot" && (
163
+ <span
164
+ className="h-2.5 w-2.5 shrink-0 rounded-[2px] bg-[--color-bg]"
165
+ style={{ "--color-bg": indicatorColor } as React.CSSProperties}
166
+ />
167
+ )}
168
+ <div className="flex flex-1 justify-between leading-none gap-4">
169
+ <span className="text-neutral-500 dark:text-neutral-400">
170
+ {itemConfig?.label || item.name}
171
+ </span>
172
+ <span className="font-mono font-medium tabular-nums text-neutral-900 dark:text-neutral-50">
173
+ {item.value?.toLocaleString()}
174
+ </span>
175
+ </div>
176
+ </div>
177
+ );
178
+ })}
179
+ </div>
180
+ </div>
181
+ );
182
+ });
183
+ ChartTooltipContent.displayName = "ChartTooltipContent";
184
+
185
+ export const ChartLegend = RechartsLegend;
186
+
187
+ export const ChartLegendContent = React.forwardRef<
188
+ HTMLDivElement,
189
+ React.ComponentProps<"div"> & {
190
+ payload?: any[];
191
+ verticalAlign?: "top" | "bottom";
192
+ }
193
+ >(({ payload, verticalAlign = "bottom", className }, ref) => {
194
+ const { config } = useChart();
195
+
196
+ if (!payload?.length) return null;
197
+
198
+ return (
199
+ <div
200
+ ref={ref}
201
+ className={`flex flex-wrap items-center justify-center gap-4 pt-2 ${verticalAlign === "top" ? "pb-2" : "pt-2"} ${className || ""}`}
202
+ >
203
+ {payload.map((item) => {
204
+ const key = `${item.dataKey || "value"}`;
205
+ const itemConfig = config[key] || {};
206
+ return (
207
+ <div key={item.value} className="flex items-center gap-1.5 text-xs text-neutral-600 dark:text-neutral-400">
208
+ <div
209
+ className="h-2 w-2 rounded-full"
210
+ style={{ backgroundColor: item.color }}
211
+ />
212
+ <span>{itemConfig?.label || item.value}</span>
213
+ </div>
214
+ );
215
+ })}
216
+ </div>
217
+ );
218
+ });
219
+ ChartLegendContent.displayName = "ChartLegendContent";
package/index.css CHANGED
@@ -4,6 +4,8 @@
4
4
 
5
5
  @layer base {
6
6
  :root {
7
+ dark: [object Object];
8
+ light: [object Object];
7
9
  --card: 0 0% 100%;
8
10
  --ring: 0 72.2% 50.6%;
9
11
  --input: 0 0% 89.8%;
package/index.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import "./index.css";
2
2
  export * from "./components/ui/card";
3
+ export * from "./components/ui/chart";
3
4
  export * from "./components/ui/input";
4
5
  export * from "./components/ui/button";
5
6
  export * from "./lib/utils";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@the21og/a16z",
3
- "version": "0.0.1",
3
+ "version": "0.0.2",
4
4
  "description": "a16z is a startup accelerator and venture capital firm",
5
5
  "main": "index.js",
6
6
  "style": "index.css",