feat(add): 新增 ButtonGroup 组件
This commit is contained in:
1 parent
3dc1fed1c1
commit
c915efe4e9
3 files changed
+72
-17
No files matched your search
@@ -33,3 +33,4 @@ lerna-debug.log*
|
||||
public*/
|
||||
bun.lock
|
||||
*.local.jsonc
|
||||
docs/
|
||||
@@ -0,0 +1,63 @@
|
||||
import * as React from "react";
|
||||
|
||||
import { Button, type ButtonProps } from "@/components/ui/button";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
type ButtonGroupValue = string | number;
|
||||
|
||||
export interface ButtonGroupOption<T extends ButtonGroupValue = ButtonGroupValue> {
|
||||
label: React.ReactNode;
|
||||
value: T;
|
||||
disabled?: boolean;
|
||||
}
|
||||
|
||||
export interface ButtonGroupProps<T extends ButtonGroupValue = ButtonGroupValue>
|
||||
extends Omit<React.HTMLAttributes<HTMLDivElement>, "onChange"> {
|
||||
value: T;
|
||||
options: readonly ButtonGroupOption<T>[];
|
||||
onValueChange: (value: T) => void;
|
||||
size?: ButtonProps["size"];
|
||||
activeVariant?: ButtonProps["variant"];
|
||||
inactiveVariant?: ButtonProps["variant"];
|
||||
buttonClassName?: string;
|
||||
}
|
||||
|
||||
export function ButtonGroup<T extends ButtonGroupValue = ButtonGroupValue>({
|
||||
value,
|
||||
options,
|
||||
onValueChange,
|
||||
size = "sm",
|
||||
activeVariant = "default",
|
||||
inactiveVariant = "outline",
|
||||
className,
|
||||
buttonClassName,
|
||||
...props
|
||||
}: ButtonGroupProps<T>) {
|
||||
return (
|
||||
<div
|
||||
{...props}
|
||||
role="radiogroup"
|
||||
className={cn("inline-flex flex-wrap rounded-md border border-border", className)}
|
||||
>
|
||||
{options.map((option) => {
|
||||
const isActive = Object.is(option.value, value);
|
||||
|
||||
return (
|
||||
<Button
|
||||
key={String(option.value)}
|
||||
type="button"
|
||||
role="radio"
|
||||
aria-checked={isActive}
|
||||
variant={isActive ? activeVariant : inactiveVariant}
|
||||
size={size}
|
||||
disabled={option.disabled}
|
||||
onClick={() => onValueChange(option.value)}
|
||||
className={cn("border-0", size === "sm" && "h-8", buttonClassName)}
|
||||
>
|
||||
{option.label}
|
||||
</Button>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import { Bot, Check, FileText, Globe, Shield, SlidersHorizontal } from "lucide-r
|
||||
|
||||
import { apiClient } from "@/api/client";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { ButtonGroup } from "@/components/ui/button-group";
|
||||
import { Card } from "@/components/ui/card";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Switch } from "@/components/ui/switch";
|
||||
@@ -366,27 +367,17 @@ export function SystemSettings() {
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex-1" />
|
||||
<div className="inline-flex flex-wrap rounded-md border">
|
||||
{PRECISION_OPTIONS.map((option) => {
|
||||
const isActive = normalizedSystemConfig.displayDecimals === option.value;
|
||||
return (
|
||||
<Button
|
||||
key={option.value}
|
||||
type="button"
|
||||
variant={isActive ? "default" : "outline"}
|
||||
onClick={() =>
|
||||
<ButtonGroup
|
||||
aria-label="显示金额精度"
|
||||
value={normalizedSystemConfig.displayDecimals}
|
||||
options={PRECISION_OPTIONS}
|
||||
onValueChange={(value) =>
|
||||
setSystemConfig((current) => ({
|
||||
...current,
|
||||
displayDecimals: option.value,
|
||||
displayDecimals: value,
|
||||
}))
|
||||
}
|
||||
className="h-8 border-0"
|
||||
>
|
||||
{option.label}
|
||||
</Button>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
/>
|
||||
</section>
|
||||
|
||||
<div className="h-px bg-border" />
|
||||
|
||||
Reference in new issue
Block a user