@karakuri-ui/react 0.3.2 → 0.3.4
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 +27 -4
- package/dist/components/ui/accordion.js +27 -24
- package/dist/components/ui/accordion.js.map +1 -1
- package/dist/components/ui/accordion.mjs +27 -24
- package/dist/components/ui/accordion.mjs.map +1 -1
- package/dist/components/ui/alert.js +45 -27
- package/dist/components/ui/alert.js.map +1 -1
- package/dist/components/ui/alert.mjs +45 -27
- package/dist/components/ui/alert.mjs.map +1 -1
- package/dist/components/ui/avatar.js +41 -32
- package/dist/components/ui/avatar.js.map +1 -1
- package/dist/components/ui/avatar.mjs +41 -32
- package/dist/components/ui/avatar.mjs.map +1 -1
- package/dist/components/ui/badge.js +46 -43
- package/dist/components/ui/badge.js.map +1 -1
- package/dist/components/ui/badge.mjs +46 -43
- package/dist/components/ui/badge.mjs.map +1 -1
- package/dist/components/ui/breadcrumb.js +30 -25
- package/dist/components/ui/breadcrumb.js.map +1 -1
- package/dist/components/ui/breadcrumb.mjs +30 -25
- package/dist/components/ui/breadcrumb.mjs.map +1 -1
- package/dist/components/ui/button-group.js +6 -5
- package/dist/components/ui/button-group.js.map +1 -1
- package/dist/components/ui/button-group.mjs +6 -5
- package/dist/components/ui/button-group.mjs.map +1 -1
- package/dist/components/ui/button.js +24 -14
- package/dist/components/ui/button.js.map +1 -1
- package/dist/components/ui/button.mjs +24 -14
- package/dist/components/ui/button.mjs.map +1 -1
- package/dist/components/ui/card.js +53 -39
- package/dist/components/ui/card.js.map +1 -1
- package/dist/components/ui/card.mjs +53 -39
- package/dist/components/ui/card.mjs.map +1 -1
- package/dist/components/ui/chart.d.mts +1 -1
- package/dist/components/ui/chart.d.ts +1 -1
- package/dist/components/ui/chart.js +154 -130
- package/dist/components/ui/chart.js.map +1 -1
- package/dist/components/ui/chart.mjs +154 -130
- package/dist/components/ui/chart.mjs.map +1 -1
- package/dist/components/ui/checkbox.js +47 -40
- package/dist/components/ui/checkbox.js.map +1 -1
- package/dist/components/ui/checkbox.mjs +47 -40
- package/dist/components/ui/checkbox.mjs.map +1 -1
- package/dist/components/ui/divider.js +16 -13
- package/dist/components/ui/divider.js.map +1 -1
- package/dist/components/ui/divider.mjs +16 -13
- package/dist/components/ui/divider.mjs.map +1 -1
- package/dist/components/ui/drawer.js +44 -35
- package/dist/components/ui/drawer.js.map +1 -1
- package/dist/components/ui/drawer.mjs +44 -35
- package/dist/components/ui/drawer.mjs.map +1 -1
- package/dist/components/ui/dropdown.js +31 -24
- package/dist/components/ui/dropdown.js.map +1 -1
- package/dist/components/ui/dropdown.mjs +31 -24
- package/dist/components/ui/dropdown.mjs.map +1 -1
- package/dist/components/ui/field.js +18 -15
- package/dist/components/ui/field.js.map +1 -1
- package/dist/components/ui/field.mjs +18 -15
- package/dist/components/ui/field.mjs.map +1 -1
- package/dist/components/ui/icon-button.js +17 -14
- package/dist/components/ui/icon-button.js.map +1 -1
- package/dist/components/ui/icon-button.mjs +17 -14
- package/dist/components/ui/icon-button.mjs.map +1 -1
- package/dist/components/ui/input.js +34 -29
- package/dist/components/ui/input.js.map +1 -1
- package/dist/components/ui/input.mjs +34 -29
- package/dist/components/ui/input.mjs.map +1 -1
- package/dist/components/ui/metric-card.js +24 -21
- package/dist/components/ui/metric-card.js.map +1 -1
- package/dist/components/ui/metric-card.mjs +24 -21
- package/dist/components/ui/metric-card.mjs.map +1 -1
- package/dist/components/ui/modal.js +91 -74
- package/dist/components/ui/modal.js.map +1 -1
- package/dist/components/ui/modal.mjs +91 -74
- package/dist/components/ui/modal.mjs.map +1 -1
- package/dist/components/ui/navigation-menu.js +114 -93
- package/dist/components/ui/navigation-menu.js.map +1 -1
- package/dist/components/ui/navigation-menu.mjs +114 -93
- package/dist/components/ui/navigation-menu.mjs.map +1 -1
- package/dist/components/ui/pagination.js +66 -55
- package/dist/components/ui/pagination.js.map +1 -1
- package/dist/components/ui/pagination.mjs +66 -55
- package/dist/components/ui/pagination.mjs.map +1 -1
- package/dist/components/ui/popover.js +39 -36
- package/dist/components/ui/popover.js.map +1 -1
- package/dist/components/ui/popover.mjs +39 -36
- package/dist/components/ui/popover.mjs.map +1 -1
- package/dist/components/ui/progress.js +73 -64
- package/dist/components/ui/progress.js.map +1 -1
- package/dist/components/ui/progress.mjs +73 -64
- package/dist/components/ui/progress.mjs.map +1 -1
- package/dist/components/ui/radio-group.js +23 -19
- package/dist/components/ui/radio-group.js.map +1 -1
- package/dist/components/ui/radio-group.mjs +23 -19
- package/dist/components/ui/radio-group.mjs.map +1 -1
- package/dist/components/ui/segmented.js +7 -6
- package/dist/components/ui/segmented.js.map +1 -1
- package/dist/components/ui/segmented.mjs +7 -6
- package/dist/components/ui/segmented.mjs.map +1 -1
- package/dist/components/ui/select.js +55 -48
- package/dist/components/ui/select.js.map +1 -1
- package/dist/components/ui/select.mjs +55 -48
- package/dist/components/ui/select.mjs.map +1 -1
- package/dist/components/ui/skeleton.js +20 -19
- package/dist/components/ui/skeleton.js.map +1 -1
- package/dist/components/ui/skeleton.mjs +20 -19
- package/dist/components/ui/skeleton.mjs.map +1 -1
- package/dist/components/ui/slider.js +68 -58
- package/dist/components/ui/slider.js.map +1 -1
- package/dist/components/ui/slider.mjs +68 -58
- package/dist/components/ui/slider.mjs.map +1 -1
- package/dist/components/ui/spinner.js +185 -176
- package/dist/components/ui/spinner.js.map +1 -1
- package/dist/components/ui/spinner.mjs +185 -176
- package/dist/components/ui/spinner.mjs.map +1 -1
- package/dist/components/ui/switch.js +39 -28
- package/dist/components/ui/switch.js.map +1 -1
- package/dist/components/ui/switch.mjs +39 -28
- package/dist/components/ui/switch.mjs.map +1 -1
- package/dist/components/ui/table.js +26 -23
- package/dist/components/ui/table.js.map +1 -1
- package/dist/components/ui/table.mjs +26 -23
- package/dist/components/ui/table.mjs.map +1 -1
- package/dist/components/ui/tabs.js +25 -9
- package/dist/components/ui/tabs.js.map +1 -1
- package/dist/components/ui/tabs.mjs +25 -9
- package/dist/components/ui/tabs.mjs.map +1 -1
- package/dist/components/ui/textarea.js +2 -1
- package/dist/components/ui/textarea.js.map +1 -1
- package/dist/components/ui/textarea.mjs +2 -1
- package/dist/components/ui/textarea.mjs.map +1 -1
- package/dist/components/ui/toast.js +104 -80
- package/dist/components/ui/toast.js.map +1 -1
- package/dist/components/ui/toast.mjs +104 -80
- package/dist/components/ui/toast.mjs.map +1 -1
- package/dist/components/ui/toggle-group.js +9 -8
- package/dist/components/ui/toggle-group.js.map +1 -1
- package/dist/components/ui/toggle-group.mjs +9 -8
- package/dist/components/ui/toggle-group.mjs.map +1 -1
- package/dist/components/ui/toggle.js +3 -2
- package/dist/components/ui/toggle.js.map +1 -1
- package/dist/components/ui/toggle.mjs +3 -2
- package/dist/components/ui/toggle.mjs.map +1 -1
- package/dist/components/ui/tooltip.js +18 -15
- package/dist/components/ui/tooltip.js.map +1 -1
- package/dist/components/ui/tooltip.mjs +18 -15
- package/dist/components/ui/tooltip.mjs.map +1 -1
- package/package.json +27 -19
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
"use client";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
3
|
import * as React from "react";
|
|
3
4
|
import * as PopoverPrimitive from "@radix-ui/react-popover";
|
|
4
5
|
import { cva } from "class-variance-authority";
|
|
5
6
|
import { cn } from "../../lib/utils";
|
|
6
|
-
const DefaultCloseIcon = ({ className }) => /* @__PURE__ */
|
|
7
|
+
const DefaultCloseIcon = ({ className }) => /* @__PURE__ */ jsx(
|
|
7
8
|
"svg",
|
|
8
9
|
{
|
|
9
10
|
className,
|
|
@@ -11,9 +12,9 @@ const DefaultCloseIcon = ({ className }) => /* @__PURE__ */ React.createElement(
|
|
|
11
12
|
viewBox: "0 0 24 24",
|
|
12
13
|
stroke: "currentColor",
|
|
13
14
|
strokeWidth: 2,
|
|
14
|
-
"aria-hidden": "true"
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
"aria-hidden": "true",
|
|
16
|
+
children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M6 18L18 6M6 6l12 12" })
|
|
17
|
+
}
|
|
17
18
|
);
|
|
18
19
|
const ANIMATION_CLASSES = {
|
|
19
20
|
top: "data-[state=open]:animate-popover-top-enter data-[state=closed]:animate-popover-top-exit",
|
|
@@ -22,7 +23,7 @@ const ANIMATION_CLASSES = {
|
|
|
22
23
|
right: "data-[state=open]:animate-popover-right-enter data-[state=closed]:animate-popover-right-exit"
|
|
23
24
|
};
|
|
24
25
|
const popoverContentVariants = cva(
|
|
25
|
-
"relative z-popover font-normal select-none w-auto max-w-[calc(100vw-16px)] outline-none",
|
|
26
|
+
"relative z-popover flex flex-col font-normal select-none w-auto max-w-[calc(100vw-16px)] max-h-[var(--radix-popover-content-available-height)] outline-none",
|
|
26
27
|
{
|
|
27
28
|
variants: {
|
|
28
29
|
variant: {
|
|
@@ -49,7 +50,7 @@ const CSS_ARROW_CLASSES = {
|
|
|
49
50
|
};
|
|
50
51
|
const ARROW_ELEVATED = "fill-background-paper drop-shadow-sm";
|
|
51
52
|
function Popover(props) {
|
|
52
|
-
return /* @__PURE__ */
|
|
53
|
+
return /* @__PURE__ */ jsx(PopoverPrimitive.Root, { ...props });
|
|
53
54
|
}
|
|
54
55
|
const PopoverTrigger = PopoverPrimitive.Trigger;
|
|
55
56
|
const PopoverPortal = PopoverPrimitive.Portal;
|
|
@@ -58,7 +59,7 @@ const PopoverClose = PopoverPrimitive.Close;
|
|
|
58
59
|
const PopoverContent = React.forwardRef(({ className, variant = "default", size, side = "bottom", sideOffset, showArrow = true, showClose = false, closeIcon, children, ...props }, ref) => {
|
|
59
60
|
const resolvedSide = side;
|
|
60
61
|
const resolvedOffset = sideOffset ?? (variant === "default" && showArrow ? 12 : 6);
|
|
61
|
-
return /* @__PURE__ */
|
|
62
|
+
return /* @__PURE__ */ jsx(PopoverPrimitive.Portal, { children: /* @__PURE__ */ jsxs(
|
|
62
63
|
PopoverPrimitive.Content,
|
|
63
64
|
{
|
|
64
65
|
ref,
|
|
@@ -69,38 +70,40 @@ const PopoverContent = React.forwardRef(({ className, variant = "default", size,
|
|
|
69
70
|
ANIMATION_CLASSES[resolvedSide],
|
|
70
71
|
className
|
|
71
72
|
),
|
|
72
|
-
...props
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
73
|
+
...props,
|
|
74
|
+
children: [
|
|
75
|
+
showClose && /* @__PURE__ */ jsx(
|
|
76
|
+
PopoverPrimitive.Close,
|
|
77
|
+
{
|
|
78
|
+
className: "absolute top-3 right-3 rounded-md p-1 text-text-muted hover:text-foreground hover:bg-background-muted transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-focus-ring",
|
|
79
|
+
"aria-label": "Close",
|
|
80
|
+
children: closeIcon || /* @__PURE__ */ jsx(DefaultCloseIcon, { className: "icon-sm" })
|
|
81
|
+
}
|
|
82
|
+
),
|
|
83
|
+
/* @__PURE__ */ jsx("div", { className: "min-h-0 overflow-y-auto -m-1 p-1", children }),
|
|
84
|
+
showArrow && variant === "default" && /* @__PURE__ */ jsx(
|
|
85
|
+
"div",
|
|
86
|
+
{
|
|
87
|
+
className: cn(
|
|
88
|
+
"absolute w-2.5 h-2.5 rotate-45 bg-background-paper",
|
|
89
|
+
CSS_ARROW_CLASSES[resolvedSide]
|
|
90
|
+
)
|
|
91
|
+
}
|
|
92
|
+
),
|
|
93
|
+
showArrow && variant === "elevated" && /* @__PURE__ */ jsx(
|
|
94
|
+
PopoverPrimitive.Arrow,
|
|
95
|
+
{
|
|
96
|
+
className: ARROW_ELEVATED,
|
|
97
|
+
width: 12,
|
|
98
|
+
height: 6
|
|
99
|
+
}
|
|
89
100
|
)
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
PopoverPrimitive.Arrow,
|
|
94
|
-
{
|
|
95
|
-
className: ARROW_ELEVATED,
|
|
96
|
-
width: 12,
|
|
97
|
-
height: 6
|
|
98
|
-
}
|
|
99
|
-
)
|
|
100
|
-
));
|
|
101
|
+
]
|
|
102
|
+
}
|
|
103
|
+
) });
|
|
101
104
|
});
|
|
102
105
|
PopoverContent.displayName = "PopoverContent";
|
|
103
|
-
const PopoverArrow = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */
|
|
106
|
+
const PopoverArrow = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
104
107
|
PopoverPrimitive.Arrow,
|
|
105
108
|
{
|
|
106
109
|
ref,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/ui/popover.tsx"],"sourcesContent":["'use client'\n\nimport * as React from 'react'\nimport * as PopoverPrimitive from '@radix-ui/react-popover'\nimport { cva, type VariantProps } from 'class-variance-authority'\nimport { cn } from '../../lib/utils'\n\n// ─── Default Close Icon (built-in, no external dependency) ──\nconst DefaultCloseIcon = ({ className }: { className?: string }) => (\n <svg\n className={className}\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n strokeWidth={2}\n aria-hidden=\"true\"\n >\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n)\n\n// ─── Types ──────────────────────────────────────────────────\nexport type PopoverSide = 'top' | 'right' | 'bottom' | 'left'\n\n// ─── Animation class mapping (static strings for Tailwind scanner) ──\nconst ANIMATION_CLASSES: Record<PopoverSide, string> = {\n top: 'data-[state=open]:animate-popover-top-enter data-[state=closed]:animate-popover-top-exit',\n bottom: 'data-[state=open]:animate-popover-bottom-enter data-[state=closed]:animate-popover-bottom-exit',\n left: 'data-[state=open]:animate-popover-left-enter data-[state=closed]:animate-popover-left-exit',\n right: 'data-[state=open]:animate-popover-right-enter data-[state=closed]:animate-popover-right-exit',\n}\n\n// ─── Content variants ────────────────────────────────────────\nconst popoverContentVariants = cva(\n 'relative z-popover font-normal select-none w-auto max-w-[calc(100vw-16px)] outline-none',\n {\n variants: {\n variant: {\n default: 'bg-background-paper text-foreground border border-border shadow-lg',\n elevated: 'bg-background-paper/95 text-foreground border border-border-subtle shadow-xl backdrop-blur-sm',\n },\n size: {\n sm: 'text-sm p-3 rounded-lg',\n default: 'text-sm p-4 rounded-xl',\n lg: 'text-md p-5 rounded-xl',\n },\n },\n defaultVariants: {\n variant: 'default',\n size: 'default',\n },\n }\n)\n\n// ─── Arrow styles ──────────────────────────────────────────────\n// default: CSS rotated square with 2-side border (seamless connection)\n// elevated: Radix SVG arrow with drop-shadow (glassmorphism, subtle border)\nconst CSS_ARROW_CLASSES: Record<PopoverSide, string> = {\n bottom: '-top-[5px] left-1/2 -translate-x-1/2 border-t border-l border-border',\n top: '-bottom-[5px] left-1/2 -translate-x-1/2 border-b border-r border-border',\n right: '-left-[5px] top-1/2 -translate-y-1/2 border-b border-l border-border',\n left: '-right-[5px] top-1/2 -translate-y-1/2 border-t border-r border-border',\n}\n\nconst ARROW_ELEVATED = 'fill-background-paper drop-shadow-sm'\n\n// ═══════════════════════════════════════════════════════════════\n// Popover\n// ═══════════════════════════════════════════════════════════════\n\n// ─── Popover (Root) — wrapper to keep our own component identity separate from Radix primitive ──\nexport interface PopoverProps extends React.ComponentPropsWithoutRef<typeof PopoverPrimitive.Root> {}\n\nfunction Popover(props: PopoverProps) {\n return <PopoverPrimitive.Root {...props} />\n}\n\n// ─── PopoverTrigger ──────────────────────────────────────────\nconst PopoverTrigger = PopoverPrimitive.Trigger\n\n// ─── PopoverPortal ───────────────────────────────────────────\nconst PopoverPortal = PopoverPrimitive.Portal\n\n// ─── PopoverAnchor ───────────────────────────────────────────\nconst PopoverAnchor = PopoverPrimitive.Anchor\n\n// ─── PopoverClose ────────────────────────────────────────────\nconst PopoverClose = PopoverPrimitive.Close\n\n// ─── PopoverContent ──────────────────────────────────────────\nexport interface PopoverContentProps\n extends React.ComponentPropsWithoutRef<typeof PopoverPrimitive.Content>,\n VariantProps<typeof popoverContentVariants> {\n /** Show arrow pointing to trigger */\n showArrow?: boolean\n /** Show built-in close button */\n showClose?: boolean\n /** Custom close icon (replaces default X icon) */\n closeIcon?: React.ReactNode\n}\n\nconst PopoverContent = React.forwardRef<\n React.ElementRef<typeof PopoverPrimitive.Content>,\n PopoverContentProps\n>(({ className, variant = 'default', size, side = 'bottom', sideOffset, showArrow = true, showClose = false, closeIcon, children, ...props }, ref) => {\n const resolvedSide = side as PopoverSide\n // CSS arrow (default) needs more gap since it doesn't occupy layout space\n const resolvedOffset = sideOffset ?? (variant === 'default' && showArrow ? 12 : 6)\n\n return (\n <PopoverPrimitive.Portal>\n <PopoverPrimitive.Content\n ref={ref}\n side={side}\n sideOffset={resolvedOffset}\n className={cn(\n popoverContentVariants({ variant, size }),\n ANIMATION_CLASSES[resolvedSide],\n className,\n )}\n {...props}\n >\n {showClose && (\n <PopoverPrimitive.Close\n className=\"absolute top-3 right-3 rounded-md p-1 text-text-muted hover:text-foreground hover:bg-background-muted transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-focus-ring\"\n aria-label=\"Close\"\n >\n {closeIcon || <DefaultCloseIcon className=\"icon-sm\" />}\n </PopoverPrimitive.Close>\n )}\n {children}\n {showArrow && variant === 'default' && (\n <div\n className={cn(\n 'absolute w-2.5 h-2.5 rotate-45 bg-background-paper',\n CSS_ARROW_CLASSES[resolvedSide],\n )}\n />\n )}\n {showArrow && variant === 'elevated' && (\n <PopoverPrimitive.Arrow\n className={ARROW_ELEVATED}\n width={12}\n height={6}\n />\n )}\n </PopoverPrimitive.Content>\n </PopoverPrimitive.Portal>\n )\n})\nPopoverContent.displayName = 'PopoverContent'\n\n// ─── PopoverArrow (standalone, for manual placement outside Content) ──\nconst PopoverArrow = React.forwardRef<\n React.ElementRef<typeof PopoverPrimitive.Arrow>,\n React.ComponentPropsWithoutRef<typeof PopoverPrimitive.Arrow>\n>(({ className, ...props }, ref) => (\n <PopoverPrimitive.Arrow\n ref={ref}\n className={cn('fill-background-paper', className)}\n width={10}\n height={5}\n {...props}\n />\n))\nPopoverArrow.displayName = 'PopoverArrow'\n\n// ─── Exports ────────────────────────────────────────────────\nexport {\n Popover,\n PopoverTrigger,\n PopoverContent,\n PopoverArrow,\n PopoverClose,\n PopoverAnchor,\n PopoverPortal,\n popoverContentVariants,\n}\n"],"mappings":";
|
|
1
|
+
{"version":3,"sources":["../../../src/components/ui/popover.tsx"],"sourcesContent":["'use client'\n\nimport * as React from 'react'\nimport * as PopoverPrimitive from '@radix-ui/react-popover'\nimport { cva, type VariantProps } from 'class-variance-authority'\nimport { cn } from '../../lib/utils'\n\n// ─── Default Close Icon (built-in, no external dependency) ──\nconst DefaultCloseIcon = ({ className }: { className?: string }) => (\n <svg\n className={className}\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n strokeWidth={2}\n aria-hidden=\"true\"\n >\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n)\n\n// ─── Types ──────────────────────────────────────────────────\nexport type PopoverSide = 'top' | 'right' | 'bottom' | 'left'\n\n// ─── Animation class mapping (static strings for Tailwind scanner) ──\nconst ANIMATION_CLASSES: Record<PopoverSide, string> = {\n top: 'data-[state=open]:animate-popover-top-enter data-[state=closed]:animate-popover-top-exit',\n bottom: 'data-[state=open]:animate-popover-bottom-enter data-[state=closed]:animate-popover-bottom-exit',\n left: 'data-[state=open]:animate-popover-left-enter data-[state=closed]:animate-popover-left-exit',\n right: 'data-[state=open]:animate-popover-right-enter data-[state=closed]:animate-popover-right-exit',\n}\n\n// ─── Content variants ────────────────────────────────────────\nconst popoverContentVariants = cva(\n 'relative z-popover flex flex-col font-normal select-none w-auto max-w-[calc(100vw-16px)] max-h-[var(--radix-popover-content-available-height)] outline-none',\n {\n variants: {\n variant: {\n default: 'bg-background-paper text-foreground border border-border shadow-lg',\n elevated: 'bg-background-paper/95 text-foreground border border-border-subtle shadow-xl backdrop-blur-sm',\n },\n size: {\n sm: 'text-sm p-3 rounded-lg',\n default: 'text-sm p-4 rounded-xl',\n lg: 'text-md p-5 rounded-xl',\n },\n },\n defaultVariants: {\n variant: 'default',\n size: 'default',\n },\n }\n)\n\n// ─── Arrow styles ──────────────────────────────────────────────\n// default: CSS rotated square with 2-side border (seamless connection)\n// elevated: Radix SVG arrow with drop-shadow (glassmorphism, subtle border)\nconst CSS_ARROW_CLASSES: Record<PopoverSide, string> = {\n bottom: '-top-[5px] left-1/2 -translate-x-1/2 border-t border-l border-border',\n top: '-bottom-[5px] left-1/2 -translate-x-1/2 border-b border-r border-border',\n right: '-left-[5px] top-1/2 -translate-y-1/2 border-b border-l border-border',\n left: '-right-[5px] top-1/2 -translate-y-1/2 border-t border-r border-border',\n}\n\nconst ARROW_ELEVATED = 'fill-background-paper drop-shadow-sm'\n\n// ═══════════════════════════════════════════════════════════════\n// Popover\n// ═══════════════════════════════════════════════════════════════\n\n// ─── Popover (Root) — wrapper to keep our own component identity separate from Radix primitive ──\nexport interface PopoverProps extends React.ComponentPropsWithoutRef<typeof PopoverPrimitive.Root> {}\n\nfunction Popover(props: PopoverProps) {\n return <PopoverPrimitive.Root {...props} />\n}\n\n// ─── PopoverTrigger ──────────────────────────────────────────\nconst PopoverTrigger = PopoverPrimitive.Trigger\n\n// ─── PopoverPortal ───────────────────────────────────────────\nconst PopoverPortal = PopoverPrimitive.Portal\n\n// ─── PopoverAnchor ───────────────────────────────────────────\nconst PopoverAnchor = PopoverPrimitive.Anchor\n\n// ─── PopoverClose ────────────────────────────────────────────\nconst PopoverClose = PopoverPrimitive.Close\n\n// ─── PopoverContent ──────────────────────────────────────────\nexport interface PopoverContentProps\n extends React.ComponentPropsWithoutRef<typeof PopoverPrimitive.Content>,\n VariantProps<typeof popoverContentVariants> {\n /** Show arrow pointing to trigger */\n showArrow?: boolean\n /** Show built-in close button */\n showClose?: boolean\n /** Custom close icon (replaces default X icon) */\n closeIcon?: React.ReactNode\n}\n\nconst PopoverContent = React.forwardRef<\n React.ElementRef<typeof PopoverPrimitive.Content>,\n PopoverContentProps\n>(({ className, variant = 'default', size, side = 'bottom', sideOffset, showArrow = true, showClose = false, closeIcon, children, ...props }, ref) => {\n const resolvedSide = side as PopoverSide\n // CSS arrow (default) needs more gap since it doesn't occupy layout space\n const resolvedOffset = sideOffset ?? (variant === 'default' && showArrow ? 12 : 6)\n\n return (\n <PopoverPrimitive.Portal>\n <PopoverPrimitive.Content\n ref={ref}\n side={side}\n sideOffset={resolvedOffset}\n className={cn(\n popoverContentVariants({ variant, size }),\n ANIMATION_CLASSES[resolvedSide],\n className,\n )}\n {...props}\n >\n {showClose && (\n <PopoverPrimitive.Close\n className=\"absolute top-3 right-3 rounded-md p-1 text-text-muted hover:text-foreground hover:bg-background-muted transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-focus-ring\"\n aria-label=\"Close\"\n >\n {closeIcon || <DefaultCloseIcon className=\"icon-sm\" />}\n </PopoverPrimitive.Close>\n )}\n {/* Scrolls when taller than the viewport space; lives inside Content so the arrow is not clipped.\n -m-1 p-1 keeps children's focus rings inside the scroll area */}\n <div className=\"min-h-0 overflow-y-auto -m-1 p-1\">\n {children}\n </div>\n {showArrow && variant === 'default' && (\n <div\n className={cn(\n 'absolute w-2.5 h-2.5 rotate-45 bg-background-paper',\n CSS_ARROW_CLASSES[resolvedSide],\n )}\n />\n )}\n {showArrow && variant === 'elevated' && (\n <PopoverPrimitive.Arrow\n className={ARROW_ELEVATED}\n width={12}\n height={6}\n />\n )}\n </PopoverPrimitive.Content>\n </PopoverPrimitive.Portal>\n )\n})\nPopoverContent.displayName = 'PopoverContent'\n\n// ─── PopoverArrow (standalone, for manual placement outside Content) ──\nconst PopoverArrow = React.forwardRef<\n React.ElementRef<typeof PopoverPrimitive.Arrow>,\n React.ComponentPropsWithoutRef<typeof PopoverPrimitive.Arrow>\n>(({ className, ...props }, ref) => (\n <PopoverPrimitive.Arrow\n ref={ref}\n className={cn('fill-background-paper', className)}\n width={10}\n height={5}\n {...props}\n />\n))\nPopoverArrow.displayName = 'PopoverArrow'\n\n// ─── Exports ────────────────────────────────────────────────\nexport {\n Popover,\n PopoverTrigger,\n PopoverContent,\n PopoverArrow,\n PopoverClose,\n PopoverAnchor,\n PopoverPortal,\n popoverContentVariants,\n}\n"],"mappings":";AAiBI,cA8FE,YA9FF;AAfJ,YAAY,WAAW;AACvB,YAAY,sBAAsB;AAClC,SAAS,WAA8B;AACvC,SAAS,UAAU;AAGnB,MAAM,mBAAmB,CAAC,EAAE,UAAU,MACpC;AAAA,EAAC;AAAA;AAAA,IACC;AAAA,IACA,MAAK;AAAA,IACL,SAAQ;AAAA,IACR,QAAO;AAAA,IACP,aAAa;AAAA,IACb,eAAY;AAAA,IAEZ,8BAAC,UAAK,eAAc,SAAQ,gBAAe,SAAQ,GAAE,wBAAuB;AAAA;AAC9E;AAOF,MAAM,oBAAiD;AAAA,EACrD,KAAQ;AAAA,EACR,QAAQ;AAAA,EACR,MAAQ;AAAA,EACR,OAAQ;AACV;AAGA,MAAM,yBAAyB;AAAA,EAC7B;AAAA,EACA;AAAA,IACE,UAAU;AAAA,MACR,SAAS;AAAA,QACP,SAAS;AAAA,QACT,UAAU;AAAA,MACZ;AAAA,MACA,MAAM;AAAA,QACJ,IAAI;AAAA,QACJ,SAAS;AAAA,QACT,IAAI;AAAA,MACN;AAAA,IACF;AAAA,IACA,iBAAiB;AAAA,MACf,SAAS;AAAA,MACT,MAAM;AAAA,IACR;AAAA,EACF;AACF;AAKA,MAAM,oBAAiD;AAAA,EACrD,QAAQ;AAAA,EACR,KAAK;AAAA,EACL,OAAO;AAAA,EACP,MAAM;AACR;AAEA,MAAM,iBAAiB;AASvB,SAAS,QAAQ,OAAqB;AACpC,SAAO,oBAAC,iBAAiB,MAAjB,EAAuB,GAAG,OAAO;AAC3C;AAGA,MAAM,iBAAiB,iBAAiB;AAGxC,MAAM,gBAAgB,iBAAiB;AAGvC,MAAM,gBAAgB,iBAAiB;AAGvC,MAAM,eAAe,iBAAiB;AActC,MAAM,iBAAiB,MAAM,WAG3B,CAAC,EAAE,WAAW,UAAU,WAAW,MAAM,OAAO,UAAU,YAAY,YAAY,MAAM,YAAY,OAAO,WAAW,UAAU,GAAG,MAAM,GAAG,QAAQ;AACpJ,QAAM,eAAe;AAErB,QAAM,iBAAiB,eAAe,YAAY,aAAa,YAAY,KAAK;AAEhF,SACE,oBAAC,iBAAiB,QAAjB,EACC;AAAA,IAAC,iBAAiB;AAAA,IAAjB;AAAA,MACC;AAAA,MACA;AAAA,MACA,YAAY;AAAA,MACZ,WAAW;AAAA,QACT,uBAAuB,EAAE,SAAS,KAAK,CAAC;AAAA,QACxC,kBAAkB,YAAY;AAAA,QAC9B;AAAA,MACF;AAAA,MACC,GAAG;AAAA,MAEH;AAAA,qBACC;AAAA,UAAC,iBAAiB;AAAA,UAAjB;AAAA,YACC,WAAU;AAAA,YACV,cAAW;AAAA,YAEV,uBAAa,oBAAC,oBAAiB,WAAU,WAAU;AAAA;AAAA,QACtD;AAAA,QAIF,oBAAC,SAAI,WAAU,oCACZ,UACH;AAAA,QACC,aAAa,YAAY,aACxB;AAAA,UAAC;AAAA;AAAA,YACC,WAAW;AAAA,cACT;AAAA,cACA,kBAAkB,YAAY;AAAA,YAChC;AAAA;AAAA,QACF;AAAA,QAED,aAAa,YAAY,cACxB;AAAA,UAAC,iBAAiB;AAAA,UAAjB;AAAA,YACC,WAAW;AAAA,YACX,OAAO;AAAA,YACP,QAAQ;AAAA;AAAA,QACV;AAAA;AAAA;AAAA,EAEJ,GACF;AAEJ,CAAC;AACD,eAAe,cAAc;AAG7B,MAAM,eAAe,MAAM,WAGzB,CAAC,EAAE,WAAW,GAAG,MAAM,GAAG,QAC1B;AAAA,EAAC,iBAAiB;AAAA,EAAjB;AAAA,IACC;AAAA,IACA,WAAW,GAAG,yBAAyB,SAAS;AAAA,IAChD,OAAO;AAAA,IACP,QAAQ;AAAA,IACP,GAAG;AAAA;AACN,CACD;AACD,aAAa,cAAc;","names":[]}
|
|
@@ -33,6 +33,7 @@ __export(progress_exports, {
|
|
|
33
33
|
linearTrackVariants: () => linearTrackVariants
|
|
34
34
|
});
|
|
35
35
|
module.exports = __toCommonJS(progress_exports);
|
|
36
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
36
37
|
var React = __toESM(require("react"));
|
|
37
38
|
var ProgressPrimitive = __toESM(require("@radix-ui/react-progress"));
|
|
38
39
|
var import_class_variance_authority = require("class-variance-authority");
|
|
@@ -108,7 +109,7 @@ const Progress = React.forwardRef(({
|
|
|
108
109
|
const r = (CIRCULAR_VIEWBOX - strokeWidth) / 2;
|
|
109
110
|
const circumference = 2 * Math.PI * r;
|
|
110
111
|
const offset = circumference * (1 - percentage / 100);
|
|
111
|
-
return /* @__PURE__ */
|
|
112
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
112
113
|
"div",
|
|
113
114
|
{
|
|
114
115
|
className: (0, import_utils.cn)("inline-flex items-center gap-2", className),
|
|
@@ -116,74 +117,82 @@ const Progress = React.forwardRef(({
|
|
|
116
117
|
"aria-valuenow": clampedValue,
|
|
117
118
|
"aria-valuemin": 0,
|
|
118
119
|
"aria-valuemax": max,
|
|
119
|
-
"aria-label": label
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
120
|
+
"aria-label": label,
|
|
121
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "relative", style: { width: diameter, height: diameter }, children: [
|
|
122
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
123
|
+
"svg",
|
|
124
|
+
{
|
|
125
|
+
viewBox: `0 0 ${CIRCULAR_VIEWBOX} ${CIRCULAR_VIEWBOX}`,
|
|
126
|
+
className: "transform -rotate-90",
|
|
127
|
+
width: diameter,
|
|
128
|
+
height: diameter,
|
|
129
|
+
children: [
|
|
130
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
131
|
+
"circle",
|
|
132
|
+
{
|
|
133
|
+
cx: CIRCULAR_CENTER,
|
|
134
|
+
cy: CIRCULAR_CENTER,
|
|
135
|
+
r,
|
|
136
|
+
fill: "none",
|
|
137
|
+
className: "stroke-border",
|
|
138
|
+
strokeWidth
|
|
139
|
+
}
|
|
140
|
+
),
|
|
141
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
142
|
+
"circle",
|
|
143
|
+
{
|
|
144
|
+
cx: CIRCULAR_CENTER,
|
|
145
|
+
cy: CIRCULAR_CENTER,
|
|
146
|
+
r,
|
|
147
|
+
fill: "none",
|
|
148
|
+
className: (0, import_utils.cn)(indicatorClassName || circularColorMap[color], "transition-[stroke-dashoffset] duration-normal ease-out"),
|
|
149
|
+
strokeWidth,
|
|
150
|
+
strokeDasharray: circumference,
|
|
151
|
+
strokeDashoffset: offset,
|
|
152
|
+
strokeLinecap: "round"
|
|
153
|
+
}
|
|
154
|
+
)
|
|
155
|
+
]
|
|
156
|
+
}
|
|
157
|
+
),
|
|
158
|
+
showValue && resolvedSize !== "sm" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: (0, import_utils.cn)(
|
|
159
|
+
"absolute inset-0 flex items-center justify-center font-semibold font-mono tabular-nums text-foreground",
|
|
160
|
+
CIRCULAR_FONT_SIZES[resolvedSize]
|
|
161
|
+
), children: valueLabel })
|
|
162
|
+
] })
|
|
163
|
+
}
|
|
158
164
|
);
|
|
159
165
|
}
|
|
160
166
|
const stripedBg = variant === "striped" ? "bg-[length:1rem_1rem] bg-[linear-gradient(45deg,rgba(255,255,255,0.15)_25%,transparent_25%,transparent_50%,rgba(255,255,255,0.15)_50%,rgba(255,255,255,0.15)_75%,transparent_75%,transparent)]" : "";
|
|
161
|
-
return /* @__PURE__ */
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
ref,
|
|
165
|
-
className: (0, import_utils.cn)(linearTrackVariants({ size })),
|
|
166
|
-
value: clampedValue,
|
|
167
|
-
max,
|
|
168
|
-
"aria-label": label,
|
|
169
|
-
...props
|
|
170
|
-
},
|
|
171
|
-
/* @__PURE__ */ React.createElement(
|
|
172
|
-
ProgressPrimitive.Indicator,
|
|
167
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: (0, import_utils.cn)("flex items-center gap-3", showValue && "w-full", className), children: [
|
|
168
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
169
|
+
ProgressPrimitive.Root,
|
|
173
170
|
{
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
171
|
+
ref,
|
|
172
|
+
className: (0, import_utils.cn)(linearTrackVariants({ size })),
|
|
173
|
+
value: clampedValue,
|
|
174
|
+
max,
|
|
175
|
+
"aria-label": label,
|
|
176
|
+
...props,
|
|
177
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
178
|
+
ProgressPrimitive.Indicator,
|
|
179
|
+
{
|
|
180
|
+
className: (0, import_utils.cn)(
|
|
181
|
+
"h-full transition-[width] duration-normal ease-out rounded-full",
|
|
182
|
+
indicatorClassName || colorMap[color],
|
|
183
|
+
stripedBg,
|
|
184
|
+
animated && variant === "striped" && "animate-progress-stripe"
|
|
185
|
+
),
|
|
186
|
+
style: { width: `${percentage}%` }
|
|
187
|
+
}
|
|
188
|
+
)
|
|
181
189
|
}
|
|
182
|
-
)
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
190
|
+
),
|
|
191
|
+
showValue && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: (0, import_utils.cn)(
|
|
192
|
+
"shrink-0 font-semibold font-mono tabular-nums text-foreground",
|
|
193
|
+
valueFontSizes[resolvedSize]
|
|
194
|
+
), children: valueLabel })
|
|
195
|
+
] });
|
|
187
196
|
});
|
|
188
197
|
Progress.displayName = "Progress";
|
|
189
198
|
// Annotate the CommonJS export names for ESM import in node:
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/ui/progress.tsx"],"sourcesContent":["'use client'\n\nimport * as React from 'react'\nimport * as ProgressPrimitive from '@radix-ui/react-progress'\nimport { cva, type VariantProps } from 'class-variance-authority'\nimport { cn } from '../../lib/utils'\n\n// ============================================================================\n// Constants\n// ============================================================================\n\n/** Circular SVG viewBox size */\nconst CIRCULAR_VIEWBOX = 100\n/** Circular center point */\nconst CIRCULAR_CENTER = 50\n\n/** Circular sizes (diameter in px) */\nconst CIRCULAR_SIZES = {\n sm: 32,\n default: 48,\n lg: 64,\n} as const\n\n/** Circular stroke thickness per size */\nconst CIRCULAR_THICKNESS = {\n sm: 4,\n default: 5,\n lg: 6,\n} as const\n\n/** Circular value font sizes */\nconst CIRCULAR_FONT_SIZES = {\n sm: 'text-2xs',\n default: 'text-xs',\n lg: 'text-sm',\n} as const\n\n// ============================================================================\n// Linear Progress\n// ============================================================================\n\nconst linearTrackVariants = cva(\n 'relative w-full overflow-hidden bg-border rounded-full',\n {\n variants: {\n size: {\n sm: 'h-1',\n default: 'h-2',\n lg: 'h-3',\n },\n },\n defaultVariants: {\n size: 'default',\n },\n }\n)\n\nconst colorMap = {\n default: 'bg-foreground',\n primary: 'bg-primary',\n} as const\n\nconst circularColorMap = {\n default: 'stroke-foreground',\n primary: 'stroke-primary',\n} as const\n\nconst valueFontSizes = {\n sm: 'text-xs',\n default: 'text-sm',\n lg: 'text-base',\n} as const\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface ProgressProps\n extends Omit<React.ComponentPropsWithoutRef<typeof ProgressPrimitive.Root>, 'children'>,\n VariantProps<typeof linearTrackVariants> {\n /** Progress type */\n type?: 'linear' | 'circular'\n /** Current value (0 to max) */\n value?: number\n /** Maximum value */\n max?: number\n /** Visual variant (linear only) */\n variant?: 'default' | 'striped'\n /** Indicator color */\n color?: 'default' | 'primary'\n /** Custom indicator class (overrides color) */\n indicatorClassName?: string\n /** Show percentage value */\n showValue?: boolean\n /** Custom label formatter */\n formatLabel?: (value: number, max: number) => string\n /** Animate striped variant */\n animated?: boolean\n /** Circular stroke thickness override */\n thickness?: number\n /** Accessibility label */\n label?: string\n}\n\nconst Progress = React.forwardRef<\n React.ElementRef<typeof ProgressPrimitive.Root>,\n ProgressProps\n>(({\n className,\n type = 'linear',\n value = 0,\n max = 100,\n size,\n variant = 'default',\n color = 'default',\n indicatorClassName,\n showValue = false,\n formatLabel,\n animated = false,\n thickness,\n label,\n ...props\n}, ref) => {\n const resolvedSize = size || 'default'\n const clampedValue = Math.min(Math.max(value, 0), max)\n const percentage = (clampedValue / max) * 100\n\n const valueLabel = formatLabel\n ? formatLabel(clampedValue, max)\n : `${Math.round(percentage)}%`\n\n // ── Circular ──\n if (type === 'circular') {\n const diameter = CIRCULAR_SIZES[resolvedSize]\n const strokeWidth = thickness ?? CIRCULAR_THICKNESS[resolvedSize]\n const r = (CIRCULAR_VIEWBOX - strokeWidth) / 2\n const circumference = 2 * Math.PI * r\n const offset = circumference * (1 - percentage / 100)\n\n return (\n <div\n className={cn('inline-flex items-center gap-2', className)}\n role=\"progressbar\"\n aria-valuenow={clampedValue}\n aria-valuemin={0}\n aria-valuemax={max}\n aria-label={label}\n >\n <div className=\"relative\" style={{ width: diameter, height: diameter }}>\n <svg\n viewBox={`0 0 ${CIRCULAR_VIEWBOX} ${CIRCULAR_VIEWBOX}`}\n className=\"transform -rotate-90\"\n width={diameter}\n height={diameter}\n >\n {/* Track */}\n <circle\n cx={CIRCULAR_CENTER}\n cy={CIRCULAR_CENTER}\n r={r}\n fill=\"none\"\n className=\"stroke-border\"\n strokeWidth={strokeWidth}\n />\n {/* Indicator */}\n <circle\n cx={CIRCULAR_CENTER}\n cy={CIRCULAR_CENTER}\n r={r}\n fill=\"none\"\n className={cn(indicatorClassName || circularColorMap[color], 'transition-[stroke-dashoffset] duration-normal ease-out')}\n strokeWidth={strokeWidth}\n strokeDasharray={circumference}\n strokeDashoffset={offset}\n strokeLinecap=\"round\"\n />\n </svg>\n {/* Center value */}\n {showValue && resolvedSize !== 'sm' && (\n <div className={cn(\n 'absolute inset-0 flex items-center justify-center font-semibold font-mono tabular-nums text-foreground',\n CIRCULAR_FONT_SIZES[resolvedSize]\n )}>\n {valueLabel}\n </div>\n )}\n </div>\n </div>\n )\n }\n\n // ── Linear ──\n const stripedBg = variant === 'striped'\n ? 'bg-[length:1rem_1rem] bg-[linear-gradient(45deg,rgba(255,255,255,0.15)_25%,transparent_25%,transparent_50%,rgba(255,255,255,0.15)_50%,rgba(255,255,255,0.15)_75%,transparent_75%,transparent)]'\n : ''\n\n return (\n <div className={cn('flex items-center gap-3', showValue && 'w-full', className)}>\n <ProgressPrimitive.Root\n ref={ref}\n className={cn(linearTrackVariants({ size }))}\n value={clampedValue}\n max={max}\n aria-label={label}\n {...props}\n >\n <ProgressPrimitive.Indicator\n className={cn(\n 'h-full transition-[width] duration-normal ease-out rounded-full',\n indicatorClassName || colorMap[color],\n stripedBg,\n animated && variant === 'striped' && 'animate-progress-stripe',\n )}\n style={{ width: `${percentage}%` }}\n />\n </ProgressPrimitive.Root>\n {showValue && (\n <span className={cn(\n 'shrink-0 font-semibold font-mono tabular-nums text-foreground',\n valueFontSizes[resolvedSize]\n )}>\n {valueLabel}\n </span>\n )}\n </div>\n )\n})\nProgress.displayName = 'Progress'\n\nexport { Progress, linearTrackVariants }\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;
|
|
1
|
+
{"version":3,"sources":["../../../src/components/ui/progress.tsx"],"sourcesContent":["'use client'\n\nimport * as React from 'react'\nimport * as ProgressPrimitive from '@radix-ui/react-progress'\nimport { cva, type VariantProps } from 'class-variance-authority'\nimport { cn } from '../../lib/utils'\n\n// ============================================================================\n// Constants\n// ============================================================================\n\n/** Circular SVG viewBox size */\nconst CIRCULAR_VIEWBOX = 100\n/** Circular center point */\nconst CIRCULAR_CENTER = 50\n\n/** Circular sizes (diameter in px) */\nconst CIRCULAR_SIZES = {\n sm: 32,\n default: 48,\n lg: 64,\n} as const\n\n/** Circular stroke thickness per size */\nconst CIRCULAR_THICKNESS = {\n sm: 4,\n default: 5,\n lg: 6,\n} as const\n\n/** Circular value font sizes */\nconst CIRCULAR_FONT_SIZES = {\n sm: 'text-2xs',\n default: 'text-xs',\n lg: 'text-sm',\n} as const\n\n// ============================================================================\n// Linear Progress\n// ============================================================================\n\nconst linearTrackVariants = cva(\n 'relative w-full overflow-hidden bg-border rounded-full',\n {\n variants: {\n size: {\n sm: 'h-1',\n default: 'h-2',\n lg: 'h-3',\n },\n },\n defaultVariants: {\n size: 'default',\n },\n }\n)\n\nconst colorMap = {\n default: 'bg-foreground',\n primary: 'bg-primary',\n} as const\n\nconst circularColorMap = {\n default: 'stroke-foreground',\n primary: 'stroke-primary',\n} as const\n\nconst valueFontSizes = {\n sm: 'text-xs',\n default: 'text-sm',\n lg: 'text-base',\n} as const\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface ProgressProps\n extends Omit<React.ComponentPropsWithoutRef<typeof ProgressPrimitive.Root>, 'children'>,\n VariantProps<typeof linearTrackVariants> {\n /** Progress type */\n type?: 'linear' | 'circular'\n /** Current value (0 to max) */\n value?: number\n /** Maximum value */\n max?: number\n /** Visual variant (linear only) */\n variant?: 'default' | 'striped'\n /** Indicator color */\n color?: 'default' | 'primary'\n /** Custom indicator class (overrides color) */\n indicatorClassName?: string\n /** Show percentage value */\n showValue?: boolean\n /** Custom label formatter */\n formatLabel?: (value: number, max: number) => string\n /** Animate striped variant */\n animated?: boolean\n /** Circular stroke thickness override */\n thickness?: number\n /** Accessibility label */\n label?: string\n}\n\nconst Progress = React.forwardRef<\n React.ElementRef<typeof ProgressPrimitive.Root>,\n ProgressProps\n>(({\n className,\n type = 'linear',\n value = 0,\n max = 100,\n size,\n variant = 'default',\n color = 'default',\n indicatorClassName,\n showValue = false,\n formatLabel,\n animated = false,\n thickness,\n label,\n ...props\n}, ref) => {\n const resolvedSize = size || 'default'\n const clampedValue = Math.min(Math.max(value, 0), max)\n const percentage = (clampedValue / max) * 100\n\n const valueLabel = formatLabel\n ? formatLabel(clampedValue, max)\n : `${Math.round(percentage)}%`\n\n // ── Circular ──\n if (type === 'circular') {\n const diameter = CIRCULAR_SIZES[resolvedSize]\n const strokeWidth = thickness ?? CIRCULAR_THICKNESS[resolvedSize]\n const r = (CIRCULAR_VIEWBOX - strokeWidth) / 2\n const circumference = 2 * Math.PI * r\n const offset = circumference * (1 - percentage / 100)\n\n return (\n <div\n className={cn('inline-flex items-center gap-2', className)}\n role=\"progressbar\"\n aria-valuenow={clampedValue}\n aria-valuemin={0}\n aria-valuemax={max}\n aria-label={label}\n >\n <div className=\"relative\" style={{ width: diameter, height: diameter }}>\n <svg\n viewBox={`0 0 ${CIRCULAR_VIEWBOX} ${CIRCULAR_VIEWBOX}`}\n className=\"transform -rotate-90\"\n width={diameter}\n height={diameter}\n >\n {/* Track */}\n <circle\n cx={CIRCULAR_CENTER}\n cy={CIRCULAR_CENTER}\n r={r}\n fill=\"none\"\n className=\"stroke-border\"\n strokeWidth={strokeWidth}\n />\n {/* Indicator */}\n <circle\n cx={CIRCULAR_CENTER}\n cy={CIRCULAR_CENTER}\n r={r}\n fill=\"none\"\n className={cn(indicatorClassName || circularColorMap[color], 'transition-[stroke-dashoffset] duration-normal ease-out')}\n strokeWidth={strokeWidth}\n strokeDasharray={circumference}\n strokeDashoffset={offset}\n strokeLinecap=\"round\"\n />\n </svg>\n {/* Center value */}\n {showValue && resolvedSize !== 'sm' && (\n <div className={cn(\n 'absolute inset-0 flex items-center justify-center font-semibold font-mono tabular-nums text-foreground',\n CIRCULAR_FONT_SIZES[resolvedSize]\n )}>\n {valueLabel}\n </div>\n )}\n </div>\n </div>\n )\n }\n\n // ── Linear ──\n const stripedBg = variant === 'striped'\n ? 'bg-[length:1rem_1rem] bg-[linear-gradient(45deg,rgba(255,255,255,0.15)_25%,transparent_25%,transparent_50%,rgba(255,255,255,0.15)_50%,rgba(255,255,255,0.15)_75%,transparent_75%,transparent)]'\n : ''\n\n return (\n <div className={cn('flex items-center gap-3', showValue && 'w-full', className)}>\n <ProgressPrimitive.Root\n ref={ref}\n className={cn(linearTrackVariants({ size }))}\n value={clampedValue}\n max={max}\n aria-label={label}\n {...props}\n >\n <ProgressPrimitive.Indicator\n className={cn(\n 'h-full transition-[width] duration-normal ease-out rounded-full',\n indicatorClassName || colorMap[color],\n stripedBg,\n animated && variant === 'striped' && 'animate-progress-stripe',\n )}\n style={{ width: `${percentage}%` }}\n />\n </ProgressPrimitive.Root>\n {showValue && (\n <span className={cn(\n 'shrink-0 font-semibold font-mono tabular-nums text-foreground',\n valueFontSizes[resolvedSize]\n )}>\n {valueLabel}\n </span>\n )}\n </div>\n )\n})\nProgress.displayName = 'Progress'\n\nexport { Progress, linearTrackVariants }\n"],"mappings":"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","names":[]}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
3
|
import * as React from "react";
|
|
3
4
|
import * as ProgressPrimitive from "@radix-ui/react-progress";
|
|
4
5
|
import { cva } from "class-variance-authority";
|
|
@@ -74,7 +75,7 @@ const Progress = React.forwardRef(({
|
|
|
74
75
|
const r = (CIRCULAR_VIEWBOX - strokeWidth) / 2;
|
|
75
76
|
const circumference = 2 * Math.PI * r;
|
|
76
77
|
const offset = circumference * (1 - percentage / 100);
|
|
77
|
-
return /* @__PURE__ */
|
|
78
|
+
return /* @__PURE__ */ jsx(
|
|
78
79
|
"div",
|
|
79
80
|
{
|
|
80
81
|
className: cn("inline-flex items-center gap-2", className),
|
|
@@ -82,74 +83,82 @@ const Progress = React.forwardRef(({
|
|
|
82
83
|
"aria-valuenow": clampedValue,
|
|
83
84
|
"aria-valuemin": 0,
|
|
84
85
|
"aria-valuemax": max,
|
|
85
|
-
"aria-label": label
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
86
|
+
"aria-label": label,
|
|
87
|
+
children: /* @__PURE__ */ jsxs("div", { className: "relative", style: { width: diameter, height: diameter }, children: [
|
|
88
|
+
/* @__PURE__ */ jsxs(
|
|
89
|
+
"svg",
|
|
90
|
+
{
|
|
91
|
+
viewBox: `0 0 ${CIRCULAR_VIEWBOX} ${CIRCULAR_VIEWBOX}`,
|
|
92
|
+
className: "transform -rotate-90",
|
|
93
|
+
width: diameter,
|
|
94
|
+
height: diameter,
|
|
95
|
+
children: [
|
|
96
|
+
/* @__PURE__ */ jsx(
|
|
97
|
+
"circle",
|
|
98
|
+
{
|
|
99
|
+
cx: CIRCULAR_CENTER,
|
|
100
|
+
cy: CIRCULAR_CENTER,
|
|
101
|
+
r,
|
|
102
|
+
fill: "none",
|
|
103
|
+
className: "stroke-border",
|
|
104
|
+
strokeWidth
|
|
105
|
+
}
|
|
106
|
+
),
|
|
107
|
+
/* @__PURE__ */ jsx(
|
|
108
|
+
"circle",
|
|
109
|
+
{
|
|
110
|
+
cx: CIRCULAR_CENTER,
|
|
111
|
+
cy: CIRCULAR_CENTER,
|
|
112
|
+
r,
|
|
113
|
+
fill: "none",
|
|
114
|
+
className: cn(indicatorClassName || circularColorMap[color], "transition-[stroke-dashoffset] duration-normal ease-out"),
|
|
115
|
+
strokeWidth,
|
|
116
|
+
strokeDasharray: circumference,
|
|
117
|
+
strokeDashoffset: offset,
|
|
118
|
+
strokeLinecap: "round"
|
|
119
|
+
}
|
|
120
|
+
)
|
|
121
|
+
]
|
|
122
|
+
}
|
|
123
|
+
),
|
|
124
|
+
showValue && resolvedSize !== "sm" && /* @__PURE__ */ jsx("div", { className: cn(
|
|
125
|
+
"absolute inset-0 flex items-center justify-center font-semibold font-mono tabular-nums text-foreground",
|
|
126
|
+
CIRCULAR_FONT_SIZES[resolvedSize]
|
|
127
|
+
), children: valueLabel })
|
|
128
|
+
] })
|
|
129
|
+
}
|
|
124
130
|
);
|
|
125
131
|
}
|
|
126
132
|
const stripedBg = variant === "striped" ? "bg-[length:1rem_1rem] bg-[linear-gradient(45deg,rgba(255,255,255,0.15)_25%,transparent_25%,transparent_50%,rgba(255,255,255,0.15)_50%,rgba(255,255,255,0.15)_75%,transparent_75%,transparent)]" : "";
|
|
127
|
-
return /* @__PURE__ */
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
ref,
|
|
131
|
-
className: cn(linearTrackVariants({ size })),
|
|
132
|
-
value: clampedValue,
|
|
133
|
-
max,
|
|
134
|
-
"aria-label": label,
|
|
135
|
-
...props
|
|
136
|
-
},
|
|
137
|
-
/* @__PURE__ */ React.createElement(
|
|
138
|
-
ProgressPrimitive.Indicator,
|
|
133
|
+
return /* @__PURE__ */ jsxs("div", { className: cn("flex items-center gap-3", showValue && "w-full", className), children: [
|
|
134
|
+
/* @__PURE__ */ jsx(
|
|
135
|
+
ProgressPrimitive.Root,
|
|
139
136
|
{
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
137
|
+
ref,
|
|
138
|
+
className: cn(linearTrackVariants({ size })),
|
|
139
|
+
value: clampedValue,
|
|
140
|
+
max,
|
|
141
|
+
"aria-label": label,
|
|
142
|
+
...props,
|
|
143
|
+
children: /* @__PURE__ */ jsx(
|
|
144
|
+
ProgressPrimitive.Indicator,
|
|
145
|
+
{
|
|
146
|
+
className: cn(
|
|
147
|
+
"h-full transition-[width] duration-normal ease-out rounded-full",
|
|
148
|
+
indicatorClassName || colorMap[color],
|
|
149
|
+
stripedBg,
|
|
150
|
+
animated && variant === "striped" && "animate-progress-stripe"
|
|
151
|
+
),
|
|
152
|
+
style: { width: `${percentage}%` }
|
|
153
|
+
}
|
|
154
|
+
)
|
|
147
155
|
}
|
|
148
|
-
)
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
156
|
+
),
|
|
157
|
+
showValue && /* @__PURE__ */ jsx("span", { className: cn(
|
|
158
|
+
"shrink-0 font-semibold font-mono tabular-nums text-foreground",
|
|
159
|
+
valueFontSizes[resolvedSize]
|
|
160
|
+
), children: valueLabel })
|
|
161
|
+
] });
|
|
153
162
|
});
|
|
154
163
|
Progress.displayName = "Progress";
|
|
155
164
|
export {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/ui/progress.tsx"],"sourcesContent":["'use client'\n\nimport * as React from 'react'\nimport * as ProgressPrimitive from '@radix-ui/react-progress'\nimport { cva, type VariantProps } from 'class-variance-authority'\nimport { cn } from '../../lib/utils'\n\n// ============================================================================\n// Constants\n// ============================================================================\n\n/** Circular SVG viewBox size */\nconst CIRCULAR_VIEWBOX = 100\n/** Circular center point */\nconst CIRCULAR_CENTER = 50\n\n/** Circular sizes (diameter in px) */\nconst CIRCULAR_SIZES = {\n sm: 32,\n default: 48,\n lg: 64,\n} as const\n\n/** Circular stroke thickness per size */\nconst CIRCULAR_THICKNESS = {\n sm: 4,\n default: 5,\n lg: 6,\n} as const\n\n/** Circular value font sizes */\nconst CIRCULAR_FONT_SIZES = {\n sm: 'text-2xs',\n default: 'text-xs',\n lg: 'text-sm',\n} as const\n\n// ============================================================================\n// Linear Progress\n// ============================================================================\n\nconst linearTrackVariants = cva(\n 'relative w-full overflow-hidden bg-border rounded-full',\n {\n variants: {\n size: {\n sm: 'h-1',\n default: 'h-2',\n lg: 'h-3',\n },\n },\n defaultVariants: {\n size: 'default',\n },\n }\n)\n\nconst colorMap = {\n default: 'bg-foreground',\n primary: 'bg-primary',\n} as const\n\nconst circularColorMap = {\n default: 'stroke-foreground',\n primary: 'stroke-primary',\n} as const\n\nconst valueFontSizes = {\n sm: 'text-xs',\n default: 'text-sm',\n lg: 'text-base',\n} as const\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface ProgressProps\n extends Omit<React.ComponentPropsWithoutRef<typeof ProgressPrimitive.Root>, 'children'>,\n VariantProps<typeof linearTrackVariants> {\n /** Progress type */\n type?: 'linear' | 'circular'\n /** Current value (0 to max) */\n value?: number\n /** Maximum value */\n max?: number\n /** Visual variant (linear only) */\n variant?: 'default' | 'striped'\n /** Indicator color */\n color?: 'default' | 'primary'\n /** Custom indicator class (overrides color) */\n indicatorClassName?: string\n /** Show percentage value */\n showValue?: boolean\n /** Custom label formatter */\n formatLabel?: (value: number, max: number) => string\n /** Animate striped variant */\n animated?: boolean\n /** Circular stroke thickness override */\n thickness?: number\n /** Accessibility label */\n label?: string\n}\n\nconst Progress = React.forwardRef<\n React.ElementRef<typeof ProgressPrimitive.Root>,\n ProgressProps\n>(({\n className,\n type = 'linear',\n value = 0,\n max = 100,\n size,\n variant = 'default',\n color = 'default',\n indicatorClassName,\n showValue = false,\n formatLabel,\n animated = false,\n thickness,\n label,\n ...props\n}, ref) => {\n const resolvedSize = size || 'default'\n const clampedValue = Math.min(Math.max(value, 0), max)\n const percentage = (clampedValue / max) * 100\n\n const valueLabel = formatLabel\n ? formatLabel(clampedValue, max)\n : `${Math.round(percentage)}%`\n\n // ── Circular ──\n if (type === 'circular') {\n const diameter = CIRCULAR_SIZES[resolvedSize]\n const strokeWidth = thickness ?? CIRCULAR_THICKNESS[resolvedSize]\n const r = (CIRCULAR_VIEWBOX - strokeWidth) / 2\n const circumference = 2 * Math.PI * r\n const offset = circumference * (1 - percentage / 100)\n\n return (\n <div\n className={cn('inline-flex items-center gap-2', className)}\n role=\"progressbar\"\n aria-valuenow={clampedValue}\n aria-valuemin={0}\n aria-valuemax={max}\n aria-label={label}\n >\n <div className=\"relative\" style={{ width: diameter, height: diameter }}>\n <svg\n viewBox={`0 0 ${CIRCULAR_VIEWBOX} ${CIRCULAR_VIEWBOX}`}\n className=\"transform -rotate-90\"\n width={diameter}\n height={diameter}\n >\n {/* Track */}\n <circle\n cx={CIRCULAR_CENTER}\n cy={CIRCULAR_CENTER}\n r={r}\n fill=\"none\"\n className=\"stroke-border\"\n strokeWidth={strokeWidth}\n />\n {/* Indicator */}\n <circle\n cx={CIRCULAR_CENTER}\n cy={CIRCULAR_CENTER}\n r={r}\n fill=\"none\"\n className={cn(indicatorClassName || circularColorMap[color], 'transition-[stroke-dashoffset] duration-normal ease-out')}\n strokeWidth={strokeWidth}\n strokeDasharray={circumference}\n strokeDashoffset={offset}\n strokeLinecap=\"round\"\n />\n </svg>\n {/* Center value */}\n {showValue && resolvedSize !== 'sm' && (\n <div className={cn(\n 'absolute inset-0 flex items-center justify-center font-semibold font-mono tabular-nums text-foreground',\n CIRCULAR_FONT_SIZES[resolvedSize]\n )}>\n {valueLabel}\n </div>\n )}\n </div>\n </div>\n )\n }\n\n // ── Linear ──\n const stripedBg = variant === 'striped'\n ? 'bg-[length:1rem_1rem] bg-[linear-gradient(45deg,rgba(255,255,255,0.15)_25%,transparent_25%,transparent_50%,rgba(255,255,255,0.15)_50%,rgba(255,255,255,0.15)_75%,transparent_75%,transparent)]'\n : ''\n\n return (\n <div className={cn('flex items-center gap-3', showValue && 'w-full', className)}>\n <ProgressPrimitive.Root\n ref={ref}\n className={cn(linearTrackVariants({ size }))}\n value={clampedValue}\n max={max}\n aria-label={label}\n {...props}\n >\n <ProgressPrimitive.Indicator\n className={cn(\n 'h-full transition-[width] duration-normal ease-out rounded-full',\n indicatorClassName || colorMap[color],\n stripedBg,\n animated && variant === 'striped' && 'animate-progress-stripe',\n )}\n style={{ width: `${percentage}%` }}\n />\n </ProgressPrimitive.Root>\n {showValue && (\n <span className={cn(\n 'shrink-0 font-semibold font-mono tabular-nums text-foreground',\n valueFontSizes[resolvedSize]\n )}>\n {valueLabel}\n </span>\n )}\n </div>\n )\n})\nProgress.displayName = 'Progress'\n\nexport { Progress, linearTrackVariants }\n"],"mappings":";
|
|
1
|
+
{"version":3,"sources":["../../../src/components/ui/progress.tsx"],"sourcesContent":["'use client'\n\nimport * as React from 'react'\nimport * as ProgressPrimitive from '@radix-ui/react-progress'\nimport { cva, type VariantProps } from 'class-variance-authority'\nimport { cn } from '../../lib/utils'\n\n// ============================================================================\n// Constants\n// ============================================================================\n\n/** Circular SVG viewBox size */\nconst CIRCULAR_VIEWBOX = 100\n/** Circular center point */\nconst CIRCULAR_CENTER = 50\n\n/** Circular sizes (diameter in px) */\nconst CIRCULAR_SIZES = {\n sm: 32,\n default: 48,\n lg: 64,\n} as const\n\n/** Circular stroke thickness per size */\nconst CIRCULAR_THICKNESS = {\n sm: 4,\n default: 5,\n lg: 6,\n} as const\n\n/** Circular value font sizes */\nconst CIRCULAR_FONT_SIZES = {\n sm: 'text-2xs',\n default: 'text-xs',\n lg: 'text-sm',\n} as const\n\n// ============================================================================\n// Linear Progress\n// ============================================================================\n\nconst linearTrackVariants = cva(\n 'relative w-full overflow-hidden bg-border rounded-full',\n {\n variants: {\n size: {\n sm: 'h-1',\n default: 'h-2',\n lg: 'h-3',\n },\n },\n defaultVariants: {\n size: 'default',\n },\n }\n)\n\nconst colorMap = {\n default: 'bg-foreground',\n primary: 'bg-primary',\n} as const\n\nconst circularColorMap = {\n default: 'stroke-foreground',\n primary: 'stroke-primary',\n} as const\n\nconst valueFontSizes = {\n sm: 'text-xs',\n default: 'text-sm',\n lg: 'text-base',\n} as const\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface ProgressProps\n extends Omit<React.ComponentPropsWithoutRef<typeof ProgressPrimitive.Root>, 'children'>,\n VariantProps<typeof linearTrackVariants> {\n /** Progress type */\n type?: 'linear' | 'circular'\n /** Current value (0 to max) */\n value?: number\n /** Maximum value */\n max?: number\n /** Visual variant (linear only) */\n variant?: 'default' | 'striped'\n /** Indicator color */\n color?: 'default' | 'primary'\n /** Custom indicator class (overrides color) */\n indicatorClassName?: string\n /** Show percentage value */\n showValue?: boolean\n /** Custom label formatter */\n formatLabel?: (value: number, max: number) => string\n /** Animate striped variant */\n animated?: boolean\n /** Circular stroke thickness override */\n thickness?: number\n /** Accessibility label */\n label?: string\n}\n\nconst Progress = React.forwardRef<\n React.ElementRef<typeof ProgressPrimitive.Root>,\n ProgressProps\n>(({\n className,\n type = 'linear',\n value = 0,\n max = 100,\n size,\n variant = 'default',\n color = 'default',\n indicatorClassName,\n showValue = false,\n formatLabel,\n animated = false,\n thickness,\n label,\n ...props\n}, ref) => {\n const resolvedSize = size || 'default'\n const clampedValue = Math.min(Math.max(value, 0), max)\n const percentage = (clampedValue / max) * 100\n\n const valueLabel = formatLabel\n ? formatLabel(clampedValue, max)\n : `${Math.round(percentage)}%`\n\n // ── Circular ──\n if (type === 'circular') {\n const diameter = CIRCULAR_SIZES[resolvedSize]\n const strokeWidth = thickness ?? CIRCULAR_THICKNESS[resolvedSize]\n const r = (CIRCULAR_VIEWBOX - strokeWidth) / 2\n const circumference = 2 * Math.PI * r\n const offset = circumference * (1 - percentage / 100)\n\n return (\n <div\n className={cn('inline-flex items-center gap-2', className)}\n role=\"progressbar\"\n aria-valuenow={clampedValue}\n aria-valuemin={0}\n aria-valuemax={max}\n aria-label={label}\n >\n <div className=\"relative\" style={{ width: diameter, height: diameter }}>\n <svg\n viewBox={`0 0 ${CIRCULAR_VIEWBOX} ${CIRCULAR_VIEWBOX}`}\n className=\"transform -rotate-90\"\n width={diameter}\n height={diameter}\n >\n {/* Track */}\n <circle\n cx={CIRCULAR_CENTER}\n cy={CIRCULAR_CENTER}\n r={r}\n fill=\"none\"\n className=\"stroke-border\"\n strokeWidth={strokeWidth}\n />\n {/* Indicator */}\n <circle\n cx={CIRCULAR_CENTER}\n cy={CIRCULAR_CENTER}\n r={r}\n fill=\"none\"\n className={cn(indicatorClassName || circularColorMap[color], 'transition-[stroke-dashoffset] duration-normal ease-out')}\n strokeWidth={strokeWidth}\n strokeDasharray={circumference}\n strokeDashoffset={offset}\n strokeLinecap=\"round\"\n />\n </svg>\n {/* Center value */}\n {showValue && resolvedSize !== 'sm' && (\n <div className={cn(\n 'absolute inset-0 flex items-center justify-center font-semibold font-mono tabular-nums text-foreground',\n CIRCULAR_FONT_SIZES[resolvedSize]\n )}>\n {valueLabel}\n </div>\n )}\n </div>\n </div>\n )\n }\n\n // ── Linear ──\n const stripedBg = variant === 'striped'\n ? 'bg-[length:1rem_1rem] bg-[linear-gradient(45deg,rgba(255,255,255,0.15)_25%,transparent_25%,transparent_50%,rgba(255,255,255,0.15)_50%,rgba(255,255,255,0.15)_75%,transparent_75%,transparent)]'\n : ''\n\n return (\n <div className={cn('flex items-center gap-3', showValue && 'w-full', className)}>\n <ProgressPrimitive.Root\n ref={ref}\n className={cn(linearTrackVariants({ size }))}\n value={clampedValue}\n max={max}\n aria-label={label}\n {...props}\n >\n <ProgressPrimitive.Indicator\n className={cn(\n 'h-full transition-[width] duration-normal ease-out rounded-full',\n indicatorClassName || colorMap[color],\n stripedBg,\n animated && variant === 'striped' && 'animate-progress-stripe',\n )}\n style={{ width: `${percentage}%` }}\n />\n </ProgressPrimitive.Root>\n {showValue && (\n <span className={cn(\n 'shrink-0 font-semibold font-mono tabular-nums text-foreground',\n valueFontSizes[resolvedSize]\n )}>\n {valueLabel}\n </span>\n )}\n </div>\n )\n})\nProgress.displayName = 'Progress'\n\nexport { Progress, linearTrackVariants }\n"],"mappings":"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","names":[]}
|