组件
进度条 Progress
细腻、克制并支持确定与不确定状态的进度指示器。
基础示例
Loading…
pnpm dlx wui@latest add @wui/progress"use client"
import * as React from "react"
import { Progress as ProgressPrimitive } from "radix-ui"
import { cva } from "class-variance-authority"
import { cn } from "@/lib/utils"
const progressVariants = cva("relative", {
variants: {
variant: {
linear: "w-full overflow-hidden rounded-full bg-muted/80",
circular: "inline-flex shrink-0 items-center justify-center",
},
size: {
sm: "h-1",
default: "h-1.5",
lg: "h-2",
},
},
compoundVariants: [
{ variant: "circular", size: "sm", className: "size-8" },
{ variant: "circular", size: "default", className: "size-11" },
{ variant: "circular", size: "lg", className: "size-14" },
],
defaultVariants: { variant: "linear", size: "default" },
})
const progressColor = {
primary: "text-primary",
blue: "text-info",
success: "text-success",
warning: "text-warning",
destructive: "text-destructive",
} as const
export interface ProgressProps
extends Omit<React.ComponentProps<typeof ProgressPrimitive.Root>, "color"> {
/** Layout of the progress indicator. @default "linear" */
variant?: "linear" | "circular"
/** Thickness preset for linear progress and diameter preset for circular progress. @default "default" */
size?: "sm" | "default" | "lg"
/** Semantic accent used by the completed portion. @default "primary" */
color?: keyof typeof progressColor
/** Shows the current percentage inside a circular indicator. @default false */
showValue?: boolean
/** Extra classes applied to the completed portion. */
indicatorClassName?: string
}
/** A linear or circular progress indicator with determinate and indeterminate states. */
function Progress({
className,
indicatorClassName,
value,
max = 100,
variant = "linear",
size = "default",
color = "primary",
showValue = false,
...props
}: ProgressProps) {
const percentage = value == null ? 28 : Math.min(100, Math.max(0, (value / max) * 100))
const strokeWidth = size === "sm" ? 7 : size === "lg" ? 5 : 6
const radius = 50 - strokeWidth / 2
const circumference = 2 * Math.PI * radius
return (
<ProgressPrimitive.Root
data-slot="progress"
data-size={size}
data-variant={variant}
data-color={color}
className={cn(progressVariants({ variant, size }), progressColor[color], className)}
value={value}
max={max}
{...props}
>
{variant === "circular" ? (
<>
<svg
data-slot="progress-ring"
className={cn("size-full -rotate-90", value == null && "animate-spin motion-reduce:animate-none")}
viewBox="0 0 100 100"
aria-hidden="true"
>
<circle
cx="50"
cy="50"
r={radius}
fill="none"
stroke="currentColor"
strokeOpacity="0.14"
strokeWidth={strokeWidth}
/>
<ProgressPrimitive.Indicator asChild>
<circle
data-slot="progress-indicator"
className={cn("transition-[stroke-dashoffset] duration-500 ease-out motion-reduce:transition-none", indicatorClassName)}
cx="50"
cy="50"
r={radius}
fill="none"
stroke="currentColor"
strokeWidth={strokeWidth}
strokeLinecap="round"
strokeDasharray={circumference}
strokeDashoffset={circumference * (1 - percentage / 100)}
/>
</ProgressPrimitive.Indicator>
</svg>
{showValue && value != null ? (
<span
data-slot="progress-value"
className="absolute text-[10px] font-semibold tabular-nums text-foreground"
>
{Math.round(percentage)}
</span>
) : null}
</>
) : (
<ProgressPrimitive.Indicator
data-slot="progress-indicator"
className={cn(
"h-full origin-left rounded-full bg-current transition-transform duration-500 ease-out motion-reduce:transition-none",
value == null && "animate-pulse",
indicatorClassName
)}
style={{ transform: `scaleX(${percentage / 100})` }}
/>
)}
</ProgressPrimitive.Root>
)
}
export { Progress, progressVariants }
组件作用
Progress 用于展示下载、上传、同步或处理任务的完成程度。它同时提供安静的线性轨道和紧凑环形布局;不传 value 时会显示不确定进度。
组件属性
| Prop | Type | Default | Description |
|---|---|---|---|
| variant | "linear" | "circular" | linear | Layout of the progress indicator. |
| size | "sm" | "default" | "lg" | default | Thickness preset for linear progress and diameter preset for circular progress. |
| color | "primary" | "blue" | "success" | "warning" | "destructive" | primary | Semantic accent used by the completed portion. |
| showValue | boolean | false | Shows the current percentage inside a circular indicator. |
| indicatorClassName | string | — | Extra classes applied to the completed portion. |
| asChild | boolean | — |
事件
进度条是只读状态组件,不提供交互事件。使用 value 更新完成度,并通过 aria-label 或 getValueLabel 提供可访问描述。
拓展使用
颜色与环形进度
Loading…
使用 color="primary | blue | success | warning | destructive" 表达不同语义。variant="circular" 切换为环形布局,配合 showValue 在环内显示百分比;size 会分别调整线性轨道厚度或环形直径。动画会在系统开启“减少动态效果”时自动停用。