@turtleclub/ui 0.7.0-beta.3 → 0.7.0-beta.30

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.
Files changed (69) hide show
  1. package/.turbo/turbo-build.log +143 -132
  2. package/CHANGELOG.md +152 -0
  3. package/dist/index.cjs +76 -36
  4. package/dist/index.cjs.map +1 -1
  5. package/dist/index.js +36068 -17674
  6. package/dist/index.js.map +1 -1
  7. package/dist/styles.css +1 -1
  8. package/dist/types/components/charts/area-chart.d.ts +108 -0
  9. package/dist/types/components/charts/area-chart.d.ts.map +1 -0
  10. package/dist/types/components/charts/bar-chart.d.ts +110 -0
  11. package/dist/types/components/charts/bar-chart.d.ts.map +1 -0
  12. package/dist/types/components/charts/index.d.ts +5 -0
  13. package/dist/types/components/charts/index.d.ts.map +1 -0
  14. package/dist/types/components/charts/pie-chart.d.ts +94 -0
  15. package/dist/types/components/charts/pie-chart.d.ts.map +1 -0
  16. package/dist/types/components/charts/radial-chart.d.ts +151 -0
  17. package/dist/types/components/charts/radial-chart.d.ts.map +1 -0
  18. package/dist/types/components/features/data-table/data-table.d.ts +7 -4
  19. package/dist/types/components/features/data-table/data-table.d.ts.map +1 -1
  20. package/dist/types/components/features/data-table/sort-dropdown.d.ts.map +1 -1
  21. package/dist/types/components/features/search-bar.d.ts +1 -0
  22. package/dist/types/components/features/search-bar.d.ts.map +1 -1
  23. package/dist/types/components/molecules/swap-input.d.ts +3 -0
  24. package/dist/types/components/molecules/swap-input.d.ts.map +1 -1
  25. package/dist/types/components/molecules/token-selector.d.ts +2 -1
  26. package/dist/types/components/molecules/token-selector.d.ts.map +1 -1
  27. package/dist/types/components/ui/avatar.d.ts +2 -2
  28. package/dist/types/components/ui/avatar.d.ts.map +1 -1
  29. package/dist/types/components/ui/chart.d.ts +18 -4
  30. package/dist/types/components/ui/chart.d.ts.map +1 -1
  31. package/dist/types/components/ui/combobox.d.ts +21 -0
  32. package/dist/types/components/ui/combobox.d.ts.map +1 -1
  33. package/dist/types/components/ui/dialog.d.ts.map +1 -1
  34. package/dist/types/components/ui/dropdown.d.ts +2 -1
  35. package/dist/types/components/ui/dropdown.d.ts.map +1 -1
  36. package/dist/types/components/ui/index.d.ts +1 -0
  37. package/dist/types/components/ui/index.d.ts.map +1 -1
  38. package/dist/types/components/ui/multi-select.d.ts.map +1 -1
  39. package/dist/types/components/ui/segment-control.d.ts +1 -0
  40. package/dist/types/components/ui/segment-control.d.ts.map +1 -1
  41. package/dist/types/components/ui/slider.d.ts.map +1 -1
  42. package/dist/types/index.d.ts +1 -0
  43. package/dist/types/index.d.ts.map +1 -1
  44. package/package.json +3 -3
  45. package/src/components/charts/QUICK_REFERENCE.md +323 -0
  46. package/src/components/charts/README.md +658 -0
  47. package/src/components/charts/RECHARTS_FEATURES.md +458 -0
  48. package/src/components/charts/area-chart.tsx +248 -0
  49. package/src/components/charts/bar-chart.tsx +362 -0
  50. package/src/components/charts/index.ts +4 -0
  51. package/src/components/charts/pie-chart.tsx +277 -0
  52. package/src/components/charts/radial-chart.tsx +312 -0
  53. package/src/components/features/data-table/data-table.tsx +136 -125
  54. package/src/components/features/data-table/sort-dropdown.tsx +8 -11
  55. package/src/components/features/search-bar.tsx +6 -1
  56. package/src/components/molecules/swap-input.tsx +44 -30
  57. package/src/components/molecules/token-selector.tsx +10 -1
  58. package/src/components/ui/avatar.tsx +8 -15
  59. package/src/components/ui/chart.tsx +100 -109
  60. package/src/components/ui/combobox.tsx +150 -137
  61. package/src/components/ui/dialog.tsx +9 -23
  62. package/src/components/ui/dropdown.tsx +3 -1
  63. package/src/components/ui/index.ts +1 -0
  64. package/src/components/ui/multi-select.tsx +325 -307
  65. package/src/components/ui/segment-control.tsx +7 -2
  66. package/src/components/ui/slider.tsx +6 -11
  67. package/src/index.ts +1 -0
  68. package/src/styles/globals.css +4 -0
  69. package/src/styles/themes/semantic.css +26 -56
@@ -28,6 +28,7 @@ interface TokenSelectorProps {
28
28
  variant?: "default" | "bordered";
29
29
  size?: "xs" | "sm" | "default";
30
30
  showBalance?: boolean;
31
+ triggerWidth?: number;
31
32
  }
32
33
 
33
34
  const TokenSelector = ({
@@ -40,6 +41,7 @@ const TokenSelector = ({
40
41
  variant = "bordered",
41
42
  size = "default",
42
43
  showBalance = true,
44
+ triggerWidth,
43
45
  }: TokenSelectorProps) => {
44
46
  // Auto-select first token if no value is provided and tokens exist
45
47
  const effectiveValue =
@@ -54,7 +56,13 @@ const TokenSelector = ({
54
56
  const getTokenIcon = (token: Token) => {
55
57
  if (token.icon) return token.icon;
56
58
  if (token.logoUrl) {
57
- return <img src={token.logoUrl} alt={token.symbol} className="size-full rounded-full" />;
59
+ return (
60
+ <img
61
+ src={token.logoUrl}
62
+ alt={token.symbol}
63
+ className="size-full rounded-full"
64
+ />
65
+ );
58
66
  }
59
67
  return null;
60
68
  };
@@ -75,6 +83,7 @@ const TokenSelector = ({
75
83
  <SelectTrigger
76
84
  // variant={variant}
77
85
  // size={size}
86
+ style={triggerWidth ? { width: `${triggerWidth}px` } : undefined}
78
87
  className={cn(
79
88
  "bg-muted hover:bg-muted/80 w-auto min-w-[80px] rounded-md font-medium",
80
89
  "focus:ring-primary/20 focus:ring-2 focus:outline-none",
@@ -21,19 +21,13 @@ function Avatar({
21
21
  return (
22
22
  <AvatarPrimitive.Root
23
23
  data-slot="avatar"
24
- className={cn(
25
- "relative flex size-8 shrink-0 overflow-hidden rounded-full",
26
- className,
27
- )}
24
+ className={cn("relative flex size-8 shrink-0 overflow-hidden rounded-full", className)}
28
25
  {...props}
29
26
  />
30
27
  );
31
28
  }
32
29
 
33
- function AvatarImage({
34
- className,
35
- ...props
36
- }: React.ComponentProps<typeof AvatarPrimitive.Image>) {
30
+ function AvatarImage({ className, ...props }: React.ComponentProps<typeof AvatarPrimitive.Image>) {
37
31
  return (
38
32
  <AvatarPrimitive.Image
39
33
  data-slot="avatar-image"
@@ -50,10 +44,7 @@ function AvatarFallback({
50
44
  return (
51
45
  <AvatarPrimitive.Fallback
52
46
  data-slot="avatar-fallback"
53
- className={cn(
54
- "bg-muted flex size-full items-center justify-center rounded-full",
55
- className,
56
- )}
47
+ className={cn("bg-muted flex size-full items-center justify-center rounded-full", className)}
57
48
  {...props}
58
49
  />
59
50
  );
@@ -65,14 +56,16 @@ function TurtleAvatar({
65
56
  fallback,
66
57
  ...rest
67
58
  }: AvatarPrimitive.AvatarProps & {
68
- src: string;
69
- alt: string;
59
+ src?: string;
60
+ alt?: string;
70
61
  fallback?: React.ReactNode;
71
62
  }) {
72
63
  return (
73
64
  <Avatar {...rest}>
74
65
  <AvatarImage src={src} alt={alt} />
75
- <AvatarFallback>{fallback}</AvatarFallback>
66
+ <AvatarFallback className="border-gradient-primary bg-primary/10 opacity-50">
67
+ {fallback}
68
+ </AvatarFallback>
76
69
  </Avatar>
77
70
  );
78
71
  }
@@ -1,35 +1,38 @@
1
- import * as React from "react"
2
- import * as RechartsPrimitive from "recharts"
1
+ "use client";
3
2
 
4
- import { cn } from "@/lib/utils"
3
+ import * as React from "react";
4
+ import * as RechartsPrimitive from "recharts";
5
+ import type { Payload, NameType, ValueType } from "recharts/types/component/DefaultTooltipContent";
6
+
7
+ import { cn } from "@/lib/utils";
5
8
 
6
9
  // Format: { THEME_NAME: CSS_SELECTOR }
7
- const THEMES = { light: "", dark: ".dark" } as const
10
+ const THEMES = { light: "", dark: ".dark" } as const;
8
11
 
9
12
  export type ChartConfig = {
10
13
  [k in string]: {
11
- label?: React.ReactNode
12
- icon?: React.ComponentType
14
+ label?: React.ReactNode;
15
+ icon?: React.ComponentType;
13
16
  } & (
14
17
  | { color?: string; theme?: never }
15
18
  | { color?: never; theme: Record<keyof typeof THEMES, string> }
16
- )
17
- }
19
+ );
20
+ };
18
21
 
19
22
  type ChartContextProps = {
20
- config: ChartConfig
21
- }
23
+ config: ChartConfig;
24
+ };
22
25
 
23
- const ChartContext = React.createContext<ChartContextProps | null>(null)
26
+ const ChartContext = React.createContext<ChartContextProps | null>(null);
24
27
 
25
28
  function useChart() {
26
- const context = React.useContext(ChartContext)
29
+ const context = React.useContext(ChartContext);
27
30
 
28
31
  if (!context) {
29
- throw new Error("useChart must be used within a <ChartContainer />")
32
+ throw new Error("useChart must be used within a <ChartContainer />");
30
33
  }
31
34
 
32
- return context
35
+ return context;
33
36
  }
34
37
 
35
38
  function ChartContainer({
@@ -37,15 +40,15 @@ function ChartContainer({
37
40
  className,
38
41
  children,
39
42
  config,
43
+ initialDimension = { width: 100, height: 50 },
40
44
  ...props
41
45
  }: React.ComponentProps<"div"> & {
42
- config: ChartConfig
43
- children: React.ComponentProps<
44
- typeof RechartsPrimitive.ResponsiveContainer
45
- >["children"]
46
+ config: ChartConfig;
47
+ children: React.ComponentProps<typeof RechartsPrimitive.ResponsiveContainer>["children"];
48
+ initialDimension?: { width: number; height: number };
46
49
  }) {
47
- const uniqueId = React.useId()
48
- const chartId = `chart-${id || uniqueId.replace(/:/g, "")}`
50
+ const uniqueId = React.useId();
51
+ const chartId = `chart-${id || uniqueId.replace(/:/g, "")}`;
49
52
 
50
53
  return (
51
54
  <ChartContext.Provider value={{ config }}>
@@ -59,21 +62,19 @@ function ChartContainer({
59
62
  {...props}
60
63
  >
61
64
  <ChartStyle id={chartId} config={config} />
62
- <RechartsPrimitive.ResponsiveContainer>
65
+ <RechartsPrimitive.ResponsiveContainer initialDimension={initialDimension}>
63
66
  {children}
64
67
  </RechartsPrimitive.ResponsiveContainer>
65
68
  </div>
66
69
  </ChartContext.Provider>
67
- )
70
+ );
68
71
  }
69
72
 
70
73
  const ChartStyle = ({ id, config }: { id: string; config: ChartConfig }) => {
71
- const colorConfig = Object.entries(config).filter(
72
- ([, config]) => config.theme || config.color
73
- )
74
+ const colorConfig = Object.entries(config).filter(([, config]) => config.theme || config.color);
74
75
 
75
76
  if (!colorConfig.length) {
76
- return null
77
+ return null;
77
78
  }
78
79
 
79
80
  return (
@@ -85,10 +86,8 @@ const ChartStyle = ({ id, config }: { id: string; config: ChartConfig }) => {
85
86
  ${prefix} [data-chart=${id}] {
86
87
  ${colorConfig
87
88
  .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
89
+ const color = itemConfig.theme?.[theme as keyof typeof itemConfig.theme] || itemConfig.color;
90
+ return color ? ` --color-${key}: ${color};` : null;
92
91
  })
93
92
  .join("\n")}
94
93
  }
@@ -97,12 +96,15 @@ ${colorConfig
97
96
  .join("\n"),
98
97
  }}
99
98
  />
100
- )
101
- }
99
+ );
100
+ };
102
101
 
103
- const ChartTooltip = RechartsPrimitive.Tooltip
102
+ const ChartTooltip = RechartsPrimitive.Tooltip;
104
103
 
105
- function ChartTooltipContent({
104
+ function ChartTooltipContent<
105
+ TValue extends ValueType = ValueType,
106
+ TName extends NameType = NameType,
107
+ >({
106
108
  active,
107
109
  payload,
108
110
  className,
@@ -116,57 +118,59 @@ function ChartTooltipContent({
116
118
  color,
117
119
  nameKey,
118
120
  labelKey,
119
- }: React.ComponentProps<typeof RechartsPrimitive.Tooltip> &
120
- React.ComponentProps<"div"> & {
121
- hideLabel?: boolean
122
- hideIndicator?: boolean
123
- indicator?: "line" | "dot" | "dashed"
124
- nameKey?: string
125
- labelKey?: string
126
- }) {
127
- const { config } = useChart()
121
+ }: {
122
+ active?: boolean;
123
+ payload?: ReadonlyArray<Payload<TValue, TName>>;
124
+ label?: TValue;
125
+ labelFormatter?: (label: any, payload: ReadonlyArray<Payload<TValue, TName>>) => React.ReactNode;
126
+ formatter?: (
127
+ value: TValue,
128
+ name: TName,
129
+ item: Payload<TValue, TName>,
130
+ index: number,
131
+ payload: ReadonlyArray<Payload<TValue, TName>>
132
+ ) => React.ReactNode;
133
+ color?: string;
134
+ labelClassName?: string;
135
+ hideLabel?: boolean;
136
+ hideIndicator?: boolean;
137
+ indicator?: "line" | "dot" | "dashed";
138
+ nameKey?: string;
139
+ labelKey?: string;
140
+ } & React.ComponentProps<"div">) {
141
+ const { config } = useChart();
128
142
 
129
143
  const tooltipLabel = React.useMemo(() => {
130
144
  if (hideLabel || !payload?.length) {
131
- return null
145
+ return null;
132
146
  }
133
147
 
134
- const [item] = payload
135
- const key = `${labelKey || item?.dataKey || item?.name || "value"}`
136
- const itemConfig = getPayloadConfigFromPayload(config, item, key)
148
+ const [item] = payload;
149
+ const key = `${labelKey || item?.dataKey || item?.name || "value"}`;
150
+ const itemConfig = getPayloadConfigFromPayload(config, item, key);
137
151
  const value =
138
152
  !labelKey && typeof label === "string"
139
153
  ? config[label as keyof typeof config]?.label || label
140
- : itemConfig?.label
154
+ : itemConfig?.label;
141
155
 
142
156
  if (labelFormatter) {
143
157
  return (
144
- <div className={cn("font-medium", labelClassName)}>
145
- {labelFormatter(value, payload)}
146
- </div>
147
- )
158
+ <div className={cn("font-medium", labelClassName)}>{labelFormatter(value, payload)}</div>
159
+ );
148
160
  }
149
161
 
150
162
  if (!value) {
151
- return null
163
+ return null;
152
164
  }
153
165
 
154
- return <div className={cn("font-medium", labelClassName)}>{value}</div>
155
- }, [
156
- label,
157
- labelFormatter,
158
- payload,
159
- hideLabel,
160
- labelClassName,
161
- config,
162
- labelKey,
163
- ])
166
+ return <div className={cn("font-medium", labelClassName)}>{value}</div>;
167
+ }, [label, labelFormatter, payload, hideLabel, labelClassName, config, labelKey]);
164
168
 
165
169
  if (!active || !payload?.length) {
166
- return null
170
+ return null;
167
171
  }
168
172
 
169
- const nestLabel = payload.length === 1 && indicator !== "dot"
173
+ const nestLabel = payload.length === 1 && indicator !== "dot";
170
174
 
171
175
  return (
172
176
  <div
@@ -180,13 +184,13 @@ function ChartTooltipContent({
180
184
  {payload
181
185
  .filter((item) => item.type !== "none")
182
186
  .map((item, index) => {
183
- const key = `${nameKey || item.name || item.dataKey || "value"}`
184
- const itemConfig = getPayloadConfigFromPayload(config, item, key)
185
- const indicatorColor = color || item.payload.fill || item.color
187
+ const key = `${nameKey || item.name || item.dataKey || "value"}`;
188
+ const itemConfig = getPayloadConfigFromPayload(config, item, key);
189
+ const indicatorColor = color || item.payload.fill || item.color;
186
190
 
187
191
  return (
188
192
  <div
189
- key={item.dataKey}
193
+ key={String(item.dataKey) || index}
190
194
  className={cn(
191
195
  "[&>svg]:text-muted-foreground flex w-full flex-wrap items-stretch gap-2 [&>svg]:h-2.5 [&>svg]:w-2.5",
192
196
  indicator === "dot" && "items-center"
@@ -241,14 +245,14 @@ function ChartTooltipContent({
241
245
  </>
242
246
  )}
243
247
  </div>
244
- )
248
+ );
245
249
  })}
246
250
  </div>
247
251
  </div>
248
- )
252
+ );
249
253
  }
250
254
 
251
- const ChartLegend = RechartsPrimitive.Legend
255
+ const ChartLegend = RechartsPrimitive.Legend;
252
256
 
253
257
  function ChartLegendContent({
254
258
  className,
@@ -256,15 +260,16 @@ function ChartLegendContent({
256
260
  payload,
257
261
  verticalAlign = "bottom",
258
262
  nameKey,
259
- }: React.ComponentProps<"div"> &
260
- Pick<RechartsPrimitive.LegendProps, "payload" | "verticalAlign"> & {
261
- hideIcon?: boolean
262
- nameKey?: string
263
- }) {
264
- const { config } = useChart()
263
+ }: React.ComponentProps<"div"> & {
264
+ payload?: ReadonlyArray<Payload<ValueType, NameType>>;
265
+ verticalAlign?: "top" | "bottom";
266
+ hideIcon?: boolean;
267
+ nameKey?: string;
268
+ }) {
269
+ const { config } = useChart();
265
270
 
266
271
  if (!payload?.length) {
267
- return null
272
+ return null;
268
273
  }
269
274
 
270
275
  return (
@@ -277,13 +282,13 @@ function ChartLegendContent({
277
282
  >
278
283
  {payload
279
284
  .filter((item) => item.type !== "none")
280
- .map((item) => {
281
- const key = `${nameKey || item.dataKey || "value"}`
282
- const itemConfig = getPayloadConfigFromPayload(config, item, key)
285
+ .map((item, index) => {
286
+ const key = `${nameKey || item.dataKey || "value"}`;
287
+ const itemConfig = getPayloadConfigFromPayload(config, item, key);
283
288
 
284
289
  return (
285
290
  <div
286
- key={item.value}
291
+ key={String(item.value) || index}
287
292
  className={cn(
288
293
  "[&>svg]:text-muted-foreground flex items-center gap-1.5 [&>svg]:h-3 [&>svg]:w-3"
289
294
  )}
@@ -300,49 +305,35 @@ function ChartLegendContent({
300
305
  )}
301
306
  {itemConfig?.label}
302
307
  </div>
303
- )
308
+ );
304
309
  })}
305
310
  </div>
306
- )
311
+ );
307
312
  }
308
313
 
309
- // Helper to extract item config from a payload.
310
- function getPayloadConfigFromPayload(
311
- config: ChartConfig,
312
- payload: unknown,
313
- key: string
314
- ) {
314
+ function getPayloadConfigFromPayload(config: ChartConfig, payload: unknown, key: string) {
315
315
  if (typeof payload !== "object" || payload === null) {
316
- return undefined
316
+ return undefined;
317
317
  }
318
318
 
319
319
  const payloadPayload =
320
- "payload" in payload &&
321
- typeof payload.payload === "object" &&
322
- payload.payload !== null
320
+ "payload" in payload && typeof payload.payload === "object" && payload.payload !== null
323
321
  ? payload.payload
324
- : undefined
322
+ : undefined;
325
323
 
326
- let configLabelKey: string = key
324
+ let configLabelKey: string = key;
327
325
 
328
- if (
329
- key in payload &&
330
- typeof payload[key as keyof typeof payload] === "string"
331
- ) {
332
- configLabelKey = payload[key as keyof typeof payload] as string
326
+ if (key in payload && typeof payload[key as keyof typeof payload] === "string") {
327
+ configLabelKey = payload[key as keyof typeof payload] as string;
333
328
  } else if (
334
329
  payloadPayload &&
335
330
  key in payloadPayload &&
336
331
  typeof payloadPayload[key as keyof typeof payloadPayload] === "string"
337
332
  ) {
338
- configLabelKey = payloadPayload[
339
- key as keyof typeof payloadPayload
340
- ] as string
333
+ configLabelKey = payloadPayload[key as keyof typeof payloadPayload] as string;
341
334
  }
342
335
 
343
- return configLabelKey in config
344
- ? config[configLabelKey]
345
- : config[key as keyof typeof config]
336
+ return configLabelKey in config ? config[configLabelKey] : config[key as keyof typeof config];
346
337
  }
347
338
 
348
339
  export {
@@ -352,4 +343,4 @@ export {
352
343
  ChartLegend,
353
344
  ChartLegendContent,
354
345
  ChartStyle,
355
- }
346
+ };