{ "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "progress", "type": "registry:block", "title": "Progress", "description": "Progress UI for uploads, onboarding, and capacity states.", "author": "Wensity ", "dependencies": [ "@base-ui/react", "clsx", "framer-motion", "tailwind-merge" ], "registryDependencies": [], "files": [ { "path": "registry/wensity/lib/utils.ts", "type": "registry:lib", "target": "@lib/utils.ts", "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n" }, { "path": "registry/wensity/progress.tsx", "type": "registry:component", "target": "@components/wensity/progress.tsx", "content": "\"use client\";\n\nimport * as React from \"react\";\nimport { Progress as BaseProgress } from \"@base-ui/react/progress\";\nimport {\n motion,\n useMotionValue,\n useMotionValueEvent,\n useReducedMotion,\n useSpring,\n useTransform,\n type MotionValue,\n} from \"framer-motion\";\nimport { cn } from \"@/lib/utils\";\n\nexport type ProgressSize = \"sm\" | \"md\" | \"lg\";\nexport type ProgressTone = \"neutral\" | \"brand\" | \"success\" | \"warning\" | \"danger\";\n\nexport interface ProgressProps extends React.HTMLAttributes {\n value?: number;\n max?: number;\n size?: ProgressSize;\n tone?: ProgressTone;\n /** Accessible label for the progress bar. */\n label?: string;\n showValue?: boolean;\n indeterminate?: boolean;\n}\n\nexport interface CircularProgressProps extends React.HTMLAttributes {\n value?: number;\n max?: number;\n size?: number;\n strokeWidth?: number;\n tone?: ProgressTone;\n label?: string;\n showValue?: boolean;\n indeterminate?: boolean;\n}\n\nexport interface SegmentedProgressProps extends React.HTMLAttributes {\n steps: number;\n current: number;\n size?: ProgressSize;\n tone?: ProgressTone;\n labels?: string[];\n}\n\nexport interface StackedProgressSegment {\n value: number;\n tone?: ProgressTone;\n label?: string;\n}\n\nexport interface StackedProgressProps extends React.HTMLAttributes {\n segments: StackedProgressSegment[];\n max?: number;\n size?: ProgressSize;\n showLegend?: boolean;\n}\n\nconst EASE_OUT: [number, number, number, number] = [0.16, 1, 0.3, 1];\n\nconst PROGRESS_SPRING = { stiffness: 110, damping: 26, mass: 0.52 };\nconst PROGRESS_SPRING_INSTANT = { stiffness: 10000, damping: 100, mass: 1 };\n\nconst trackSizes: Record = {\n sm: \"h-1.5 rounded-full\",\n md: \"h-2 rounded-full\",\n lg: \"h-2.5 rounded-full\",\n};\n\nconst fillTones: Record = {\n neutral:\n \"bg-[linear-gradient(90deg,color-mix(in_srgb,var(--foreground)_72%,var(--background)),color-mix(in_srgb,var(--foreground)_88%,var(--background)))]\",\n brand: \"bg-[var(--primitive-control-solid)]\",\n success: \"bg-[var(--primitive-success)]\",\n warning: \"bg-[var(--primitive-warning)]\",\n danger: \"bg-[var(--primitive-destructive)]\",\n};\n\nconst fillGlow: Record = {\n neutral: \"shadow-[0_0_14px_color-mix(in_srgb,var(--foreground)_22%,transparent)]\",\n brand: \"shadow-[0_0_16px_color-mix(in_srgb,var(--primitive-control-solid)_38%,transparent)]\",\n success: \"shadow-[0_0_16px_color-mix(in_srgb,var(--primitive-success)_32%,transparent)]\",\n warning: \"shadow-[0_0_16px_color-mix(in_srgb,var(--primitive-warning)_28%,transparent)]\",\n danger: \"shadow-[0_0_16px_color-mix(in_srgb,var(--primitive-destructive)_32%,transparent)]\",\n};\n\nconst completeDropShadow: Record = {\n neutral: \"drop-shadow-[0_0_6px_color-mix(in_srgb,var(--foreground)_22%,transparent)]\",\n brand: \"drop-shadow-[0_0_6px_color-mix(in_srgb,var(--primitive-control-solid)_35%,transparent)]\",\n success: \"drop-shadow-[0_0_6px_color-mix(in_srgb,var(--primitive-success)_35%,transparent)]\",\n warning: \"drop-shadow-[0_0_6px_color-mix(in_srgb,var(--primitive-warning)_35%,transparent)]\",\n danger: \"drop-shadow-[0_0_6px_color-mix(in_srgb,var(--primitive-destructive)_35%,transparent)]\",\n};\n\nconst strokeTones: Record = {\n neutral: \"stroke-[color-mix(in_srgb,var(--foreground)_75%,var(--background))]\",\n brand: \"stroke-[var(--primitive-control-solid)]\",\n success: \"stroke-[var(--primitive-success)]\",\n warning: \"stroke-[var(--primitive-warning)]\",\n danger: \"stroke-[var(--primitive-destructive)]\",\n};\n\nconst indeterminateGradients: Record = {\n neutral:\n \"bg-[linear-gradient(90deg,transparent,color-mix(in_srgb,var(--foreground)_70%,var(--background)),transparent)]\",\n brand:\n \"bg-[linear-gradient(90deg,transparent,var(--primitive-control-solid),transparent)]\",\n success:\n \"bg-[linear-gradient(90deg,transparent,var(--primitive-success),transparent)]\",\n warning:\n \"bg-[linear-gradient(90deg,transparent,var(--primitive-warning),transparent)]\",\n danger:\n \"bg-[linear-gradient(90deg,transparent,var(--primitive-destructive),transparent)]\",\n};\n\nconst legendDots: Record = {\n neutral: \"bg-[color-mix(in_srgb,var(--foreground)_70%,var(--background))]\",\n brand: \"bg-[var(--primitive-control-solid)]\",\n success: \"bg-[var(--primitive-success)]\",\n warning: \"bg-[var(--primitive-warning)]\",\n danger: \"bg-[var(--primitive-destructive)]\",\n};\n\nfunction clamp(value: number, min: number, max: number) {\n return Math.min(max, Math.max(min, value));\n}\n\nfunction percent(value: number, max: number) {\n if (max <= 0) return 0;\n return clamp((value / max) * 100, 0, 100);\n}\n\nfunction useSmoothPercent(target: number, reduceMotion: boolean) {\n const motionValue = useMotionValue(target);\n const smooth = useSpring(\n motionValue,\n reduceMotion ? PROGRESS_SPRING_INSTANT : PROGRESS_SPRING,\n );\n\n React.useEffect(() => {\n motionValue.set(target);\n }, [target, motionValue]);\n\n return smooth;\n}\n\nfunction ProgressPercentLabel({\n value,\n className,\n initial = 0,\n}: {\n value: MotionValue;\n className?: string;\n initial?: number;\n}) {\n const [display, setDisplay] = React.useState(initial);\n\n useMotionValueEvent(value, \"change\", (next) => {\n setDisplay(Math.round(next));\n });\n\n return {display}%;\n}\n\nexport const Progress = React.forwardRef(\n (\n {\n className,\n value = 0,\n max = 100,\n size = \"md\",\n tone = \"brand\",\n label = \"Progress\",\n showValue = false,\n indeterminate = false,\n ...props\n },\n ref,\n ) => {\n const reduceMotion = useReducedMotion() ?? false;\n\n React.useEffect(() => {\n ensureProgressStyles();\n }, []);\n\n const actual = percent(value, max);\n const smoothPercent = useSmoothPercent(actual, reduceMotion);\n const fillWidth = useTransform(smoothPercent, (v) => `${v}%`);\n const isComplete = actual >= 100;\n\n return (\n \n {showValue ? (\n
\n \n {label}\n \n {!indeterminate ? (\n \n ) : null}\n
\n ) : null}\n \n {indeterminate ? (\n \n ) : (\n \n )}\n \n
\n );\n },\n);\nProgress.displayName = \"Progress\";\n\nexport const CircularProgress = React.forwardRef(\n (\n {\n className,\n value = 0,\n max = 100,\n size = 56,\n strokeWidth = 7,\n tone = \"brand\",\n label = \"Progress\",\n showValue = true,\n indeterminate = false,\n ...props\n },\n ref,\n ) => {\n const reduceMotion = useReducedMotion() ?? false;\n\n React.useEffect(() => {\n ensureProgressStyles();\n }, []);\n\n const radius = (size - strokeWidth) / 2;\n const circumference = 2 * Math.PI * radius;\n const actual = percent(value, max);\n const smoothPercent = useSmoothPercent(actual, reduceMotion);\n const strokeOffset = useTransform(\n smoothPercent,\n (v) => circumference - (v / 100) * circumference,\n );\n const isComplete = actual >= 100;\n\n return (\n
\n \n \n {indeterminate ? (\n \n ) : (\n \n )}\n \n {showValue && !indeterminate ? (\n \n ) : null}\n
\n );\n },\n);\nCircularProgress.displayName = \"CircularProgress\";\n\nexport const SegmentedProgress = React.forwardRef(\n ({ className, steps, current, size = \"md\", tone = \"brand\", labels, ...props }, ref) => {\n const reduceMotion = useReducedMotion() ?? false;\n\n return (\n
\n \n {Array.from({ length: Math.max(1, steps) }, (_, index) => {\n const stepNumber = index + 1;\n const safeCurrent = clamp(current, 0, Math.max(1, steps));\n const isComplete = stepNumber < safeCurrent;\n const isActive = stepNumber === safeCurrent;\n\n return (\n
\n \n \n
\n {labels?.[index] ? (\n \n {labels[index]}\n \n ) : null}\n
\n );\n })}\n \n \n );\n },\n);\nSegmentedProgress.displayName = \"SegmentedProgress\";\n\nexport const StackedProgress = React.forwardRef(\n (\n {\n className,\n segments,\n max = 100,\n size = \"md\",\n showLegend = true,\n ...props\n },\n ref,\n ) => {\n const reduceMotion = useReducedMotion() ?? false;\n const total = segments.reduce((sum, segment) => sum + segment.value, 0);\n const scaleMax = Math.max(max, total);\n\n return (\n
\n \n {segments.map((segment, index) => {\n const width = percent(segment.value, scaleMax);\n const tone = segment.tone ?? \"neutral\";\n return (\n 0 && \"border-l border-[var(--background)]/80\",\n )}\n initial={false}\n animate={{ width: `${width}%` }}\n transition={\n reduceMotion\n ? { duration: 0 }\n : { duration: 0.55, ease: EASE_OUT }\n }\n />\n );\n })}\n
\n {showLegend ? (\n
\n {segments.map((segment, index) => {\n const tone = segment.tone ?? \"neutral\";\n return (\n \n \n {segment.label}\n {segment.value}\n
\n );\n })}\n \n ) : null}\n \n );\n },\n);\nStackedProgress.displayName = \"StackedProgress\";\n\nconst PROGRESS_STYLE_ID = \"wensity-progress-styles-v3\";\n\nfunction ensureProgressStyles() {\n if (typeof document === \"undefined\") return;\n if (document.getElementById(PROGRESS_STYLE_ID)) return;\n\n const style = document.createElement(\"style\");\n style.id = PROGRESS_STYLE_ID;\n style.textContent = `\n @keyframes wensity-progress-indeterminate-sweep {\n 0% { transform: translateX(-100%); }\n 100% { transform: translateX(200%); }\n }\n @keyframes wensity-progress-circular-spin {\n 100% { transform: rotate(270deg); }\n }\n @media (prefers-reduced-motion: reduce) {\n [data-slot=\"progress\"] [class*=\"wensity-progress-indeterminate-sweep\"],\n [data-slot=\"circular-progress\"] [class*=\"wensity-progress-circular-spin\"] {\n animation: none !important;\n }\n }\n `;\n document.head.appendChild(style);\n}\n\nexport function ProgressStyles() {\n React.useEffect(() => {\n ensureProgressStyles();\n }, []);\n return null;\n}\n" } ], "cssVars": { "theme": { "font-sans": "var(--font-satoshi, ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, Helvetica Neue, Arial, sans-serif)", "font-display": "var(--font-cabinet, ui-sans-serif, system-ui, sans-serif)", "color-background": "var(--background)", "color-foreground": "var(--foreground)", "color-surface": "var(--surface)", "color-surface-muted": "var(--surface-muted)", "color-border": "var(--border)", "color-border-strong": "var(--border-strong)", "color-muted": "var(--muted)", "color-muted-foreground": "var(--muted-foreground)", "color-ring": "var(--ring)", "color-chili-50": "#fff1ee", "color-chili-100": "#ffe2db", "color-chili-200": "#ffa896", "color-chili-300": "#ff8a73", "color-chili-400": "#f15a45", "color-chili-500": "#cd1c18", "color-chili-600": "#b31614", "color-chili-700": "#9b1313", "color-chili-800": "#6a0d0e", "color-chili-900": "#38000a", "color-chili-950": "#1f0006", "color-primitive-surface-elevated": "var(--primitive-surface-elevated)", "color-primitive-surface-overlay": "var(--primitive-surface-overlay)", "color-primitive-surface-hover": "var(--primitive-surface-hover)", "color-primitive-surface-active": "var(--primitive-surface-active)", "color-primitive-surface-selected": "var(--primitive-surface-selected)", "color-primitive-border-subtle": "var(--primitive-border-subtle)", "color-primitive-ring": "var(--primitive-ring)", "color-primitive-text-secondary": "var(--primitive-text-secondary)", "color-primitive-text-placeholder": "var(--primitive-text-placeholder)", "color-primitive-text-inverse": "var(--primitive-text-inverse)", "color-primitive-destructive": "var(--primitive-destructive)", "color-primitive-destructive-hover": "var(--primitive-destructive-hover)", "color-primitive-destructive-active": "var(--primitive-destructive-active)", "color-primitive-destructive-foreground": "var(--primitive-destructive-foreground)", "color-primitive-destructive-surface": "var(--primitive-destructive-surface)", "color-primitive-destructive-border": "var(--primitive-destructive-border)", "color-primitive-success": "var(--primitive-success)", "color-primitive-warning": "var(--primitive-warning)", "color-primitive-info": "var(--primitive-info)", "color-primitive-control-solid": "var(--primitive-control-solid)", "color-primitive-control-solid-hover": "var(--primitive-control-solid-hover)", "color-primitive-control-solid-active": "var(--primitive-control-solid-active)", "color-primitive-control-solid-foreground": "var(--primitive-control-solid-foreground)", "color-primitive-chart-1": "var(--primitive-chart-1)", "color-primitive-chart-2": "var(--primitive-chart-2)", "color-primitive-chart-3": "var(--primitive-chart-3)", "color-primitive-chart-4": "var(--primitive-chart-4)", "color-primitive-chart-5": "var(--primitive-chart-5)", "color-primitive-chart-6": "var(--primitive-chart-6)", "radius-primitive": "var(--primitive-radius)", "radius-primitive-control": "var(--primitive-radius-control)", "radius-primitive-control-sm": "var(--primitive-radius-control-sm)", "radius-primitive-surface": "var(--primitive-radius-surface)", "radius-primitive-item": "var(--primitive-radius-item)", "font-primitive-sans": "var(--primitive-font-sans)", "font-primitive-display": "var(--primitive-font-display)", "font-primitive-mono": "var(--primitive-font-mono)", "spacing-primitive-control-height-sm": "var(--primitive-control-height-sm)", "spacing-primitive-control-height-md": "var(--primitive-control-height-md)", "spacing-primitive-control-height-lg": "var(--primitive-control-height-lg)" }, "light": { "background": "#fafafa", "foreground": "#0a0a0a", "surface": "#ffffff", "surface-muted": "#f4f4f5", "border": "rgba(10, 10, 10, 0.08)", "border-strong": "rgba(10, 10, 10, 0.16)", "muted": "#f4f4f5", "muted-foreground": "#52525b", "ring": "#cd1c18", "pattern-fg": "rgba(10, 10, 10, 0.07)", "llb-primary": "#18181b", "llb-primary-fg": "#ffffff", "llb-success": "#1f883d", "llb-error": "#cf222e", "primitive-surface-elevated": "#ffffff", "primitive-surface-overlay": "#ffffff", "primitive-surface-hover": "color-mix(in srgb, var(--foreground) 4%, transparent)", "primitive-surface-active": "color-mix(in srgb, var(--foreground) 7%, transparent)", "primitive-surface-selected": "color-mix(in srgb, var(--foreground) 6%, transparent)", "primitive-border-subtle": "color-mix(in srgb, var(--border) 60%, transparent)", "primitive-ring": "color-mix(in srgb, var(--foreground) 45%, transparent)", "primitive-text-secondary": "color-mix(in srgb, var(--foreground) 72%, transparent)", "primitive-text-placeholder": "color-mix(in srgb, var(--muted-foreground) 85%, transparent)", "primitive-radius": "0.875rem", "primitive-font-sans": "var(--font-sans)", "primitive-font-display": "var(--font-display)", "primitive-font-mono": "ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace", "primitive-control-solid": "#24292d", "primitive-control-solid-hover": "#2c3237", "primitive-control-solid-active": "#1e2326", "primitive-control-solid-foreground": "#ffffff", "primitive-chart-1": "#2a78d6", "primitive-chart-2": "#1baf7a", "primitive-chart-3": "#eda100", "primitive-chart-4": "#008300", "primitive-chart-5": "#4a3aa7", "primitive-chart-6": "#e34948", "primitive-text-inverse": "#ffffff", "primitive-text-hint": "0.6875rem", "primitive-destructive": "#dc2626", "primitive-destructive-hover": "#b91c1c", "primitive-destructive-active": "#991b1b", "primitive-destructive-foreground": "#ffffff", "primitive-destructive-surface": "rgba(220, 38, 38, 0.10)", "primitive-destructive-border": "rgba(220, 38, 38, 0.45)", "primitive-success": "#047857", "primitive-success-surface": "rgba(4, 120, 87, 0.10)", "primitive-success-border": "rgba(4, 120, 87, 0.45)", "primitive-warning": "#b45309", "primitive-warning-surface": "rgba(180, 83, 9, 0.10)", "primitive-warning-border": "rgba(180, 83, 9, 0.45)", "primitive-info": "#0369a1", "primitive-info-surface": "rgba(3, 105, 161, 0.10)", "primitive-info-border": "rgba(3, 105, 161, 0.45)", "primitive-radius-control": "var(--primitive-radius)", "primitive-radius-control-sm": "max(0px, calc(var(--primitive-radius) - 4px))", "primitive-radius-surface": "calc(var(--primitive-radius) + min(2px, var(--primitive-radius)))", "primitive-radius-item": "max(0px, calc(var(--primitive-radius-surface) - 6px))", "primitive-control-height-sm": "2rem", "primitive-control-height-md": "2.25rem", "primitive-control-height-lg": "2.5rem", "primitive-shadow-raised": "0 1px 2px rgba(0, 0, 0, 0.06), 0 8px 24px -12px rgba(0, 0, 0, 0.08)", "primitive-shadow-overlay": "0 1px 2px rgba(0, 0, 0, 0.06), 0 18px 48px -24px rgba(0, 0, 0, 0.35)", "primitive-shadow-modal": "0 1px 2px rgba(0, 0, 0, 0.08), 0 24px 64px -28px rgba(0, 0, 0, 0.42)", "primitive-z-overlay": "100", "primitive-z-popover": "130", "primitive-z-toast": "140", "primitive-backdrop": "rgba(0, 0, 0, 0.6)", "primitive-ease": "cubic-bezier(0.23, 1, 0.32, 1)" }, "dark": { "background": "#0a0a0b", "foreground": "#f5f5f6", "surface": "#111113", "surface-muted": "#18181b", "border": "rgba(255, 255, 255, 0.08)", "border-strong": "rgba(255, 255, 255, 0.14)", "muted": "#1c1c1f", "muted-foreground": "#a1a1aa", "ring": "#cd1c18", "pattern-fg": "rgba(255, 255, 255, 0.06)", "llb-primary": "#f5f5f6", "llb-primary-fg": "#0a0a0b", "llb-success": "#2da44e", "llb-error": "#f85149", "primitive-surface-elevated": "#0f0f10", "primitive-surface-overlay": "#141415", "primitive-surface-hover": "color-mix(in srgb, var(--foreground) 5%, transparent)", "primitive-surface-active": "color-mix(in srgb, var(--foreground) 10%, transparent)", "primitive-surface-selected": "color-mix(in srgb, var(--foreground) 8%, transparent)", "primitive-border-subtle": "color-mix(in srgb, var(--border) 60%, transparent)", "primitive-ring": "color-mix(in srgb, var(--foreground) 45%, transparent)", "primitive-text-secondary": "color-mix(in srgb, var(--foreground) 72%, transparent)", "primitive-text-placeholder": "color-mix(in srgb, var(--muted-foreground) 85%, transparent)", "primitive-radius": "0.875rem", "primitive-font-sans": "var(--font-sans)", "primitive-font-display": "var(--font-display)", "primitive-font-mono": "ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace", "primitive-control-solid": "#f5f3ee", "primitive-control-solid-hover": "#ffffff", "primitive-control-solid-active": "#e8e4da", "primitive-control-solid-foreground": "#151719", "primitive-chart-1": "#3987e5", "primitive-chart-2": "#199e70", "primitive-chart-3": "#c98500", "primitive-chart-4": "#008300", "primitive-chart-5": "#9085e9", "primitive-chart-6": "#e66767", "primitive-text-inverse": "#151719", "primitive-text-hint": "0.6875rem", "primitive-destructive": "#e11d2e", "primitive-destructive-hover": "#c1121f", "primitive-destructive-active": "#a4161a", "primitive-destructive-foreground": "#ffffff", "primitive-destructive-surface": "rgba(225, 29, 46, 0.12)", "primitive-destructive-border": "rgba(225, 29, 46, 0.52)", "primitive-success": "#34d399", "primitive-success-surface": "rgba(52, 211, 153, 0.12)", "primitive-success-border": "rgba(52, 211, 153, 0.45)", "primitive-warning": "#fbbf24", "primitive-warning-surface": "rgba(251, 191, 36, 0.12)", "primitive-warning-border": "rgba(251, 191, 36, 0.45)", "primitive-info": "#38bdf8", "primitive-info-surface": "rgba(56, 189, 248, 0.12)", "primitive-info-border": "rgba(56, 189, 248, 0.45)", "primitive-radius-control": "var(--primitive-radius)", "primitive-radius-control-sm": "max(0px, calc(var(--primitive-radius) - 4px))", "primitive-radius-surface": "calc(var(--primitive-radius) + min(2px, var(--primitive-radius)))", "primitive-radius-item": "max(0px, calc(var(--primitive-radius-surface) - 6px))", "primitive-control-height-sm": "2rem", "primitive-control-height-md": "2.25rem", "primitive-control-height-lg": "2.5rem", "primitive-shadow-raised": "0 1px 2px rgba(0, 0, 0, 0.4), 0 8px 24px -12px rgba(0, 0, 0, 0.6)", "primitive-shadow-overlay": "0 1px 2px rgba(0, 0, 0, 0.4), 0 20px 56px -28px rgba(0, 0, 0, 0.72)", "primitive-shadow-modal": "0 1px 2px rgba(0, 0, 0, 0.45), 0 28px 72px -32px rgba(0, 0, 0, 0.8)", "primitive-z-overlay": "100", "primitive-z-popover": "130", "primitive-z-toast": "140", "primitive-backdrop": "rgba(0, 0, 0, 0.6)", "primitive-ease": "cubic-bezier(0.23, 1, 0.32, 1)" } }, "css": { "@layer base": { ":where([data-wensity-primitive])": { "font-family": "var(--primitive-font-sans)" } }, "@utility scrollbar-hidden": { "scrollbar-width": "none", "-ms-overflow-style": "none", "&::-webkit-scrollbar": { "display": "none" } }, "@keyframes wensity-marquee-x": { "from": { "transform": "translate3d(0, 0, 0)" }, "to": { "transform": "translate3d(-50%, 0, 0)" } }, "@keyframes wensity-marquee-x-reverse": { "from": { "transform": "translate3d(-50%, 0, 0)" }, "to": { "transform": "translate3d(0, 0, 0)" } }, "@keyframes wensity-morph-rot-cw": { "from": { "transform": "rotate(0deg)" }, "to": { "transform": "rotate(360deg)" } }, "@keyframes wensity-morph-rot-ccw": { "from": { "transform": "rotate(0deg)" }, "to": { "transform": "rotate(-360deg)" } } }, "docs": "Free Wensity component. Installs to @components/wensity/progress.tsx. For Pro components and updates, use pnpm dlx wensity@latest add progress.", "categories": [ "UI Primitives", "wensity", "free" ], "meta": { "wensity": { "slug": "progress", "access": "free", "category": "UI Primitives", "kind": "component", "componentUrl": "https://ui.wensity.com/primitives/progress", "shadcnUrl": "https://ui.wensity.com/r/progress", "cliInstall": "pnpm dlx wensity@latest add progress" } } }