@swift-rust/ui 0.2.0 → 0.6.0
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.
- package/README.md +66 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +89 -41
- package/dist/cli.js.map +1 -1
- package/dist/cli.test.d.ts +2 -0
- package/dist/cli.test.d.ts.map +1 -0
- package/dist/cli.test.js +36 -0
- package/dist/cli.test.js.map +1 -0
- package/dist/components.d.ts.map +1 -1
- package/dist/components.js +61 -32
- package/dist/components.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/registry.test.d.ts +2 -0
- package/dist/registry.test.d.ts.map +1 -0
- package/dist/registry.test.js +82 -0
- package/dist/registry.test.js.map +1 -0
- package/dist/smoke.test.js +5 -3
- package/dist/smoke.test.js.map +1 -1
- package/package.json +7 -7
- package/registry/components/accordion.tsx +125 -16
- package/registry/components/alert-dialog.tsx +102 -0
- package/registry/components/alert.tsx +114 -14
- package/registry/components/aspect-ratio.tsx +18 -0
- package/registry/components/avatar.tsx +59 -7
- package/registry/components/badge.tsx +29 -14
- package/registry/components/breadcrumb.tsx +7 -13
- package/registry/components/button-group.tsx +28 -0
- package/registry/components/button.tsx +113 -28
- package/registry/components/calendar.tsx +92 -0
- package/registry/components/callout.tsx +14 -14
- package/registry/components/card.tsx +87 -12
- package/registry/components/carousel.tsx +41 -0
- package/registry/components/chart.tsx +50 -0
- package/registry/components/checkbox.tsx +5 -5
- package/registry/components/code-block.tsx +118 -0
- package/registry/components/code.tsx +2 -3
- package/registry/components/collapsible.tsx +60 -0
- package/registry/components/combobox.tsx +102 -0
- package/registry/components/command.tsx +5 -5
- package/registry/components/context-menu.tsx +81 -0
- package/registry/components/data-table.tsx +71 -0
- package/registry/components/date-picker.tsx +58 -0
- package/registry/components/dialog.tsx +2 -2
- package/registry/components/direction.tsx +17 -0
- package/registry/components/drawer.tsx +77 -0
- package/registry/components/dropdown-menu.tsx +5 -5
- package/registry/components/empty.tsx +34 -0
- package/registry/components/field.tsx +27 -0
- package/registry/components/file-upload.tsx +116 -0
- package/registry/components/form.tsx +3 -4
- package/registry/components/hover-card.tsx +59 -0
- package/registry/components/input-group.tsx +34 -0
- package/registry/components/input-otp.tsx +50 -0
- package/registry/components/input.tsx +71 -7
- package/registry/components/item.tsx +42 -0
- package/registry/components/kbd.tsx +3 -4
- package/registry/components/label.tsx +34 -4
- package/registry/components/menubar.tsx +60 -0
- package/registry/components/native-select.tsx +35 -0
- package/registry/components/navigation-menu.tsx +3 -3
- package/registry/components/pagination.tsx +4 -5
- package/registry/components/popover.tsx +1 -1
- package/registry/components/progress.tsx +10 -5
- package/registry/components/radio-group.tsx +9 -9
- package/registry/components/resizable.tsx +77 -0
- package/registry/components/scroll-area.tsx +20 -0
- package/registry/components/select.tsx +2 -3
- package/registry/components/separator.tsx +1 -2
- package/registry/components/sheet.tsx +1 -1
- package/registry/components/sidebar.tsx +72 -0
- package/registry/components/skeleton.tsx +1 -6
- package/registry/components/slider.tsx +6 -3
- package/registry/components/sonner.tsx +52 -0
- package/registry/components/spinner.tsx +19 -6
- package/registry/components/stepper.tsx +63 -0
- package/registry/components/switch.tsx +7 -6
- package/registry/components/table.tsx +2 -3
- package/registry/components/tabs.tsx +3 -3
- package/registry/components/textarea.tsx +42 -6
- package/registry/components/toast.tsx +2 -2
- package/registry/components/toggle-group.tsx +72 -0
- package/registry/components/toggle.tsx +45 -20
- package/registry/components/tooltip.tsx +4 -2
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import { cn } from "@/lib/utils";
|
|
4
|
+
|
|
5
|
+
export interface StepItem {
|
|
6
|
+
title: string;
|
|
7
|
+
description?: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function Stepper({
|
|
11
|
+
steps,
|
|
12
|
+
current = 0,
|
|
13
|
+
orientation = "horizontal",
|
|
14
|
+
className,
|
|
15
|
+
}: {
|
|
16
|
+
steps: StepItem[];
|
|
17
|
+
current?: number;
|
|
18
|
+
orientation?: "horizontal" | "vertical";
|
|
19
|
+
className?: string;
|
|
20
|
+
}) {
|
|
21
|
+
const vertical = orientation === "vertical";
|
|
22
|
+
return (
|
|
23
|
+
<ol className={cn("flex w-full", vertical ? "flex-col gap-0" : "items-start", className)}>
|
|
24
|
+
{steps.map((step, i) => {
|
|
25
|
+
const state = i < current ? "complete" : i === current ? "current" : "upcoming";
|
|
26
|
+
const last = i === steps.length - 1;
|
|
27
|
+
return (
|
|
28
|
+
<li key={step.title} className={cn("flex", vertical ? "gap-3" : "flex-1 flex-col items-center text-center")}>
|
|
29
|
+
<div className={cn("flex items-center", vertical ? "flex-col" : "w-full")}>
|
|
30
|
+
{!vertical && i > 0 && (
|
|
31
|
+
<span className={cn("h-0.5 flex-1", i <= current ? "bg-primary" : "bg-border")} />
|
|
32
|
+
)}
|
|
33
|
+
<span
|
|
34
|
+
className={cn(
|
|
35
|
+
"flex size-8 shrink-0 items-center justify-center rounded-full border text-sm font-medium transition-colors",
|
|
36
|
+
state === "complete" && "border-primary bg-primary text-primary-foreground",
|
|
37
|
+
state === "current" && "border-primary text-primary",
|
|
38
|
+
state === "upcoming" && "border-border text-muted-foreground",
|
|
39
|
+
)}
|
|
40
|
+
>
|
|
41
|
+
{state === "complete" ? (
|
|
42
|
+
<svg viewBox="0 0 24 24" className="size-4" fill="none" stroke="currentColor" strokeWidth="2.5" aria-hidden><path d="M20 6 9 17l-5-5" strokeLinecap="round" strokeLinejoin="round" /></svg>
|
|
43
|
+
) : (
|
|
44
|
+
i + 1
|
|
45
|
+
)}
|
|
46
|
+
</span>
|
|
47
|
+
{!vertical && !last && (
|
|
48
|
+
<span className={cn("h-0.5 flex-1", i < current ? "bg-primary" : "bg-border")} />
|
|
49
|
+
)}
|
|
50
|
+
{vertical && !last && <span className={cn("my-1 w-0.5 flex-1", i < current ? "bg-primary" : "bg-border")} />}
|
|
51
|
+
</div>
|
|
52
|
+
<div className={cn(vertical ? "pb-6 pt-1" : "mt-2")}>
|
|
53
|
+
<p className={cn("text-sm font-medium", state === "upcoming" ? "text-muted-foreground" : "text-foreground")}>
|
|
54
|
+
{step.title}
|
|
55
|
+
</p>
|
|
56
|
+
{step.description && <p className="mt-0.5 text-xs text-muted-foreground">{step.description}</p>}
|
|
57
|
+
</div>
|
|
58
|
+
</li>
|
|
59
|
+
);
|
|
60
|
+
})}
|
|
61
|
+
</ol>
|
|
62
|
+
);
|
|
63
|
+
}
|
|
@@ -1,18 +1,19 @@
|
|
|
1
|
-
"use client";
|
|
2
1
|
import * as React from "react";
|
|
3
2
|
import { cn } from "@/lib/utils";
|
|
4
3
|
|
|
5
|
-
export
|
|
4
|
+
export type SwitchProps = React.InputHTMLAttributes<HTMLInputElement>;
|
|
5
|
+
|
|
6
|
+
export const Switch = React.forwardRef<HTMLInputElement, SwitchProps>(
|
|
6
7
|
({ className, ...props }, ref) => (
|
|
7
8
|
<label className="inline-flex cursor-pointer items-center">
|
|
8
9
|
<input type="checkbox" ref={ref} className="peer sr-only" {...props} />
|
|
9
10
|
<span
|
|
10
11
|
className={cn(
|
|
11
|
-
"relative h-5 w-9 rounded-full bg-
|
|
12
|
-
"peer-checked:bg-
|
|
13
|
-
"peer-focus-visible:ring-2 peer-focus-visible:ring-
|
|
12
|
+
"relative h-5 w-9 rounded-full bg-input transition-colors",
|
|
13
|
+
"peer-checked:bg-primary",
|
|
14
|
+
"peer-focus-visible:ring-2 peer-focus-visible:ring-ring/50 peer-focus-visible:ring-offset-2 peer-focus-visible:ring-offset-background",
|
|
14
15
|
"peer-disabled:cursor-not-allowed peer-disabled:opacity-50",
|
|
15
|
-
"after:absolute after:left-0.5 after:top-0.5 after:
|
|
16
|
+
"after:absolute after:left-0.5 after:top-0.5 after:size-4 after:rounded-full after:bg-background after:shadow-sm after:transition-transform",
|
|
16
17
|
"peer-checked:after:translate-x-4",
|
|
17
18
|
className,
|
|
18
19
|
)}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
"use client";
|
|
2
1
|
import * as React from "react";
|
|
3
2
|
import { cn } from "@/lib/utils";
|
|
4
3
|
|
|
@@ -34,7 +33,7 @@ export const TableRow = React.forwardRef<HTMLTableRowElement, React.HTMLAttribut
|
|
|
34
33
|
<tr
|
|
35
34
|
ref={ref}
|
|
36
35
|
className={cn(
|
|
37
|
-
"border-b border-
|
|
36
|
+
"border-b border-border transition-colors hover:bg-muted data-[state=selected]:bg-muted",
|
|
38
37
|
className,
|
|
39
38
|
)}
|
|
40
39
|
{...props}
|
|
@@ -48,7 +47,7 @@ export const TableHead = React.forwardRef<HTMLTableCellElement, React.ThHTMLAttr
|
|
|
48
47
|
<th
|
|
49
48
|
ref={ref}
|
|
50
49
|
className={cn(
|
|
51
|
-
"h-10 px-3 text-left align-middle text-xs font-semibold uppercase tracking-wider text-
|
|
50
|
+
"h-10 px-3 text-left align-middle text-xs font-semibold uppercase tracking-wider text-muted-foreground",
|
|
52
51
|
className,
|
|
53
52
|
)}
|
|
54
53
|
{...props}
|
|
@@ -35,7 +35,7 @@ export function TabsList({ className, ...props }: React.HTMLAttributes<HTMLDivEl
|
|
|
35
35
|
<div
|
|
36
36
|
role="tablist"
|
|
37
37
|
className={cn(
|
|
38
|
-
"inline-flex h-9 items-center justify-center rounded-lg bg-
|
|
38
|
+
"inline-flex h-9 items-center justify-center rounded-lg bg-muted p-1 text-muted-foreground",
|
|
39
39
|
className,
|
|
40
40
|
)}
|
|
41
41
|
{...props}
|
|
@@ -59,8 +59,8 @@ export function TabsTrigger({
|
|
|
59
59
|
onClick={() => ctx.setValue(value)}
|
|
60
60
|
className={cn(
|
|
61
61
|
"inline-flex items-center justify-center whitespace-nowrap rounded-md px-3 py-1 text-sm font-medium transition-all",
|
|
62
|
-
"focus-visible:outline-
|
|
63
|
-
active ? "bg-
|
|
62
|
+
"focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring",
|
|
63
|
+
active ? "bg-popover text-foreground shadow-sm" : "hover:text-foreground",
|
|
64
64
|
className,
|
|
65
65
|
)}
|
|
66
66
|
{...props}
|
|
@@ -1,18 +1,54 @@
|
|
|
1
|
-
"use client";
|
|
2
1
|
import * as React from "react";
|
|
3
2
|
import { cn } from "@/lib/utils";
|
|
4
3
|
|
|
5
|
-
export type
|
|
4
|
+
export type TextareaVariant = "default" | "outline" | "secondary" | "ghost" | "destructive";
|
|
5
|
+
export type TextareaDesign = "flat" | "soft" | "3d" | "glass" | "neo" | "brutal" | "gradient";
|
|
6
|
+
|
|
7
|
+
const VARIANTS: Record<TextareaVariant, string> = {
|
|
8
|
+
default: "border border-input bg-background",
|
|
9
|
+
outline: "border-2 border-input bg-transparent",
|
|
10
|
+
secondary: "border border-transparent bg-secondary",
|
|
11
|
+
ghost: "border border-transparent bg-transparent hover:bg-secondary/50",
|
|
12
|
+
destructive:
|
|
13
|
+
"border border-destructive text-destructive placeholder:text-destructive/60 focus-visible:ring-destructive/40",
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
const DESIGNS: Record<TextareaDesign, string> = {
|
|
17
|
+
flat: "shadow-xs",
|
|
18
|
+
soft: "rounded-xl border-transparent bg-secondary shadow-none",
|
|
19
|
+
"3d": "border-t-2 border-t-black/15 bg-linear-to-b from-black/[0.06] to-transparent dark:border-t-black/40",
|
|
20
|
+
glass:
|
|
21
|
+
"border-white/40 bg-white/15 backdrop-blur-xl backdrop-saturate-200 placeholder:text-foreground/50 " +
|
|
22
|
+
"bg-linear-to-br from-white/30 to-white/5 dark:border-white/20 dark:bg-white/10 dark:from-white/15 dark:to-transparent",
|
|
23
|
+
neo:
|
|
24
|
+
"border-transparent bg-background " +
|
|
25
|
+
"shadow-[inset_3px_3px_6px_rgba(0,0,0,0.12),inset_-3px_-3px_6px_rgba(255,255,255,0.7)] " +
|
|
26
|
+
"dark:shadow-[inset_3px_3px_6px_rgba(0,0,0,0.6),inset_-3px_-3px_6px_rgba(255,255,255,0.05)]",
|
|
27
|
+
brutal:
|
|
28
|
+
"rounded-none border-2 border-foreground shadow-[3px_3px_0_0_var(--color-foreground)] " +
|
|
29
|
+
"focus-visible:shadow-[1px_1px_0_0_var(--color-foreground)] focus-visible:ring-0",
|
|
30
|
+
gradient:
|
|
31
|
+
"border-2 border-transparent " +
|
|
32
|
+
"[background:linear-gradient(var(--color-background),var(--color-background))_padding-box," +
|
|
33
|
+
"linear-gradient(135deg,#8b5cf6,#d946ef,#fb923c)_border-box]",
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export interface TextareaProps extends React.TextareaHTMLAttributes<HTMLTextAreaElement> {
|
|
37
|
+
variant?: TextareaVariant;
|
|
38
|
+
design?: TextareaDesign;
|
|
39
|
+
}
|
|
6
40
|
|
|
7
41
|
export const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(
|
|
8
|
-
({ className, ...props }, ref) => (
|
|
42
|
+
({ className, variant = "default", design = "flat", ...props }, ref) => (
|
|
9
43
|
<textarea
|
|
10
44
|
ref={ref}
|
|
11
45
|
className={cn(
|
|
12
|
-
"flex min-h-
|
|
13
|
-
"placeholder:text-
|
|
14
|
-
"focus-visible:outline-
|
|
46
|
+
"flex min-h-20 w-full rounded-lg px-3 py-2 text-sm text-foreground transition-[color,box-shadow,background-color]",
|
|
47
|
+
"placeholder:text-muted-foreground",
|
|
48
|
+
"focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring/50",
|
|
15
49
|
"disabled:cursor-not-allowed disabled:opacity-50",
|
|
50
|
+
VARIANTS[variant],
|
|
51
|
+
DESIGNS[design],
|
|
16
52
|
className,
|
|
17
53
|
)}
|
|
18
54
|
{...props}
|
|
@@ -25,9 +25,9 @@ export function ToastProvider({ children }: { children: React.ReactNode }) {
|
|
|
25
25
|
}, []);
|
|
26
26
|
|
|
27
27
|
const TONE: Record<ToastTone, string> = {
|
|
28
|
-
default: "bg-
|
|
28
|
+
default: "bg-primary text-primary-foreground",
|
|
29
29
|
success: "bg-[#16a34a] text-white",
|
|
30
|
-
error: "bg-
|
|
30
|
+
error: "bg-destructive text-white",
|
|
31
31
|
warning: "bg-[#f59e0b] text-white",
|
|
32
32
|
};
|
|
33
33
|
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import { cn } from "@/lib/utils";
|
|
4
|
+
|
|
5
|
+
const ToggleGroupContext = React.createContext<{
|
|
6
|
+
value: string[];
|
|
7
|
+
toggle: (v: string) => void;
|
|
8
|
+
} | null>(null);
|
|
9
|
+
|
|
10
|
+
export function ToggleGroup({
|
|
11
|
+
type = "single",
|
|
12
|
+
value: controlled,
|
|
13
|
+
defaultValue,
|
|
14
|
+
onValueChange,
|
|
15
|
+
className,
|
|
16
|
+
children,
|
|
17
|
+
}: {
|
|
18
|
+
type?: "single" | "multiple";
|
|
19
|
+
value?: string | string[];
|
|
20
|
+
defaultValue?: string | string[];
|
|
21
|
+
onValueChange?: (v: string | string[]) => void;
|
|
22
|
+
className?: string;
|
|
23
|
+
children: React.ReactNode;
|
|
24
|
+
}) {
|
|
25
|
+
const norm = (v: string | string[] | undefined) =>
|
|
26
|
+
v === undefined ? [] : Array.isArray(v) ? v : [v];
|
|
27
|
+
const [internal, setInternal] = React.useState<string[]>(norm(defaultValue));
|
|
28
|
+
const value = controlled !== undefined ? norm(controlled) : internal;
|
|
29
|
+
const toggle = (v: string) => {
|
|
30
|
+
let next: string[];
|
|
31
|
+
if (type === "single") next = value.includes(v) ? [] : [v];
|
|
32
|
+
else next = value.includes(v) ? value.filter((x) => x !== v) : [...value, v];
|
|
33
|
+
if (controlled === undefined) setInternal(next);
|
|
34
|
+
onValueChange?.(type === "single" ? (next[0] ?? "") : next);
|
|
35
|
+
};
|
|
36
|
+
return (
|
|
37
|
+
<ToggleGroupContext.Provider value={{ value, toggle }}>
|
|
38
|
+
<div role="group" className={cn("inline-flex gap-0.5 rounded-md border border-border p-0.5", className)}>
|
|
39
|
+
{children}
|
|
40
|
+
</div>
|
|
41
|
+
</ToggleGroupContext.Provider>
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function ToggleGroupItem({
|
|
46
|
+
value,
|
|
47
|
+
className,
|
|
48
|
+
children,
|
|
49
|
+
}: {
|
|
50
|
+
value: string;
|
|
51
|
+
className?: string;
|
|
52
|
+
children: React.ReactNode;
|
|
53
|
+
}) {
|
|
54
|
+
const ctx = React.useContext(ToggleGroupContext);
|
|
55
|
+
const active = ctx?.value.includes(value);
|
|
56
|
+
return (
|
|
57
|
+
<button
|
|
58
|
+
type="button"
|
|
59
|
+
aria-pressed={active}
|
|
60
|
+
data-state={active ? "on" : "off"}
|
|
61
|
+
onClick={() => ctx?.toggle(value)}
|
|
62
|
+
className={cn(
|
|
63
|
+
"inline-flex h-8 min-w-8 items-center justify-center gap-2 rounded px-2.5 text-sm font-medium transition-colors",
|
|
64
|
+
"hover:bg-muted focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring/50",
|
|
65
|
+
"data-[state=on]:bg-secondary data-[state=on]:text-secondary-foreground [&_svg]:size-4",
|
|
66
|
+
className,
|
|
67
|
+
)}
|
|
68
|
+
>
|
|
69
|
+
{children}
|
|
70
|
+
</button>
|
|
71
|
+
);
|
|
72
|
+
}
|
|
@@ -1,18 +1,42 @@
|
|
|
1
|
-
"use client";
|
|
2
1
|
import * as React from "react";
|
|
3
2
|
import { cn } from "@/lib/utils";
|
|
4
3
|
|
|
5
|
-
export
|
|
6
|
-
|
|
4
|
+
export type ToggleVariant = "default" | "outline";
|
|
5
|
+
export type ToggleSize = "sm" | "default" | "lg";
|
|
6
|
+
|
|
7
|
+
const VARIANTS: Record<ToggleVariant, string> = {
|
|
8
|
+
default: "bg-transparent",
|
|
9
|
+
outline: "border border-input bg-transparent shadow-xs",
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
const SIZES: Record<ToggleSize, string> = {
|
|
13
|
+
sm: "h-8 min-w-8 px-2 text-xs",
|
|
14
|
+
default: "h-9 min-w-9 px-2.5 text-sm",
|
|
15
|
+
lg: "h-10 min-w-10 px-3 text-sm",
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export interface ToggleProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
|
|
19
|
+
pressed?: boolean;
|
|
20
|
+
variant?: ToggleVariant;
|
|
21
|
+
size?: ToggleSize;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export const Toggle = React.forwardRef<HTMLButtonElement, ToggleProps>(
|
|
25
|
+
({ className, pressed, variant = "default", size = "default", ...props }, ref) => (
|
|
7
26
|
<button
|
|
8
27
|
ref={ref}
|
|
9
28
|
type="button"
|
|
10
29
|
aria-pressed={pressed}
|
|
11
30
|
data-state={pressed ? "on" : "off"}
|
|
12
31
|
className={cn(
|
|
13
|
-
"inline-flex
|
|
14
|
-
"
|
|
15
|
-
|
|
32
|
+
"inline-flex items-center justify-center gap-2 rounded-md font-medium transition-colors",
|
|
33
|
+
"hover:bg-muted hover:text-foreground",
|
|
34
|
+
"focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring/50",
|
|
35
|
+
"disabled:pointer-events-none disabled:opacity-50",
|
|
36
|
+
"data-[state=on]:bg-secondary data-[state=on]:text-secondary-foreground",
|
|
37
|
+
"[&_svg]:size-4 [&_svg]:shrink-0",
|
|
38
|
+
VARIANTS[variant],
|
|
39
|
+
SIZES[size],
|
|
16
40
|
className,
|
|
17
41
|
)}
|
|
18
42
|
{...props}
|
|
@@ -21,7 +45,7 @@ export const Toggle = React.forwardRef<HTMLButtonElement, React.ButtonHTMLAttrib
|
|
|
21
45
|
);
|
|
22
46
|
Toggle.displayName = "Toggle";
|
|
23
47
|
|
|
24
|
-
export
|
|
48
|
+
export function ToggleGroup({
|
|
25
49
|
value,
|
|
26
50
|
onValueChange,
|
|
27
51
|
children,
|
|
@@ -31,16 +55,17 @@ export const ToggleGroup = ({
|
|
|
31
55
|
onValueChange: (v: string) => void;
|
|
32
56
|
children: React.ReactNode;
|
|
33
57
|
className?: string;
|
|
34
|
-
})
|
|
35
|
-
|
|
36
|
-
{
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
);
|
|
58
|
+
}) {
|
|
59
|
+
return (
|
|
60
|
+
<div role="group" className={cn("inline-flex gap-0.5 rounded-md border border-border p-0.5", className)}>
|
|
61
|
+
{React.Children.map(children, (child) => {
|
|
62
|
+
if (!React.isValidElement(child)) return child;
|
|
63
|
+
const c = child as React.ReactElement<{ value: string; pressed?: boolean; onClick?: () => void }>;
|
|
64
|
+
return React.cloneElement(c, {
|
|
65
|
+
pressed: c.props.value === value,
|
|
66
|
+
onClick: () => onValueChange(c.props.value),
|
|
67
|
+
});
|
|
68
|
+
})}
|
|
69
|
+
</div>
|
|
70
|
+
);
|
|
71
|
+
}
|
|
@@ -14,7 +14,7 @@ export function TooltipProvider({ children }: { children: React.ReactNode }) {
|
|
|
14
14
|
{children}
|
|
15
15
|
{label ? (
|
|
16
16
|
<div
|
|
17
|
-
className="pointer-events-none fixed z-50 -translate-x-1/2 -translate-y-full rounded-md bg-
|
|
17
|
+
className="pointer-events-none fixed z-50 -translate-x-1/2 -translate-y-full rounded-md bg-primary px-2 py-1 text-xs text-primary-foreground shadow-md"
|
|
18
18
|
style={{ left: pos.x, top: pos.y - 6 }}
|
|
19
19
|
>
|
|
20
20
|
{label}
|
|
@@ -66,5 +66,7 @@ export function Tooltip({
|
|
|
66
66
|
children: React.ReactElement;
|
|
67
67
|
label: string;
|
|
68
68
|
}) {
|
|
69
|
-
return React.cloneElement(children
|
|
69
|
+
return React.cloneElement(children as React.ReactElement<Record<string, unknown>>, {
|
|
70
|
+
"data-tooltip": label,
|
|
71
|
+
});
|
|
70
72
|
}
|