Components
Loading preview...
Here is Button component
npx shadcn@latest add https://21st.dev/r/intentui/button7"use client"
import { useState } from "react"
import { IconPlus } from "@intentui/icons"
import { Button } from "@/components/ui/button"
import { ProgressBar, type ProgressBarProps } from "react-aria-components"
import { twMerge } from "tailwind-merge"
/* ====== ProgressCircle (stable spin) ====== */
interface ProgressCircleProps extends Omit<ProgressBarProps, "className"> {
className?: string
}
function ProgressCircle({ className, ...props }: ProgressCircleProps) {
return (
<ProgressBar {...props}>
{({ percentage, isIndeterminate }) => (
<svg
className={twMerge("size-4 shrink-0", className)}
viewBox="0 0 24 24"
fill="none"
aria-hidden="true"
>
{/* track */}
<circle
cx="12"
cy="12"
r="10"
strokeWidth={3}
stroke="currentColor"
strokeOpacity={0.25}
fill="none"
/>
{isIndeterminate ? (
// Spin only the dash group, not the whole SVG
<g
className="origin-center [transform-box:fill-box] animate-spin will-change-transform"
>
<circle
cx="12"
cy="12"
r="10"
strokeWidth={3}
stroke="currentColor"
fill="none"
pathLength={100}
strokeDasharray="28 72" // ~28% arc, 72% gap
strokeLinecap="round"
transform="rotate(-90 12 12)" // start at top
/>
</g>
) : (
// Determinate: fill from top
<circle
cx="12"
cy="12"
r="10"
strokeWidth={3}
stroke="currentColor"
fill="none"
pathLength={100}
strokeDasharray="100 200"
strokeDashoffset={100 - (percentage ?? 0)}
strokeLinecap="round"
transform="rotate(-90 12 12)"
/>
)}
</svg>
)}
</ProgressBar>
)
}
/* ============ Demo Button ============ */
export default function Component() {
const [isLoading, setLoading] = useState(false)
const handleClick = () => {
setLoading(true)
setTimeout(() => setLoading(false), 4500)
}
return (
<Button
onClick={handleClick}
isPending={isLoading}
className="flex items-center gap-2 px-4 py-2"
>
{isLoading ? (
<>
<ProgressCircle isIndeterminate aria-label="Creating..." />
<span>Creating...</span>
</>
) : (
<>
<IconPlus className="size-4" />
<span>Create</span>
</>
)}
</Button>
)
}
export { ProgressCircle }
export type { ProgressCircleProps }