@humain/ui 2.2.4 → 2.2.6
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/dist/index11.js +4 -4
- package/dist/index11.js.map +1 -1
- package/dist/index110.js +4 -4
- package/dist/index110.js.map +1 -1
- package/dist/index134.js +4 -4
- package/dist/index134.js.map +1 -1
- package/dist/index135.js +2 -2
- package/dist/index135.js.map +1 -1
- package/dist/index151.js +3 -3
- package/dist/index151.js.map +1 -1
- package/dist/index152.js +1 -1
- package/dist/index152.js.map +1 -1
- package/dist/index155.js +1 -1
- package/dist/index155.js.map +1 -1
- package/dist/index188.js +4 -4
- package/dist/index188.js.map +1 -1
- package/dist/index201.js +1 -1
- package/dist/index201.js.map +1 -1
- package/dist/index228.js +1 -1
- package/dist/index228.js.map +1 -1
- package/dist/index24.js +1 -1
- package/dist/index24.js.map +1 -1
- package/dist/index25.js +4 -4
- package/dist/index25.js.map +1 -1
- package/dist/index39.js +2 -2
- package/dist/index39.js.map +1 -1
- package/dist/index5.js +8 -8
- package/dist/index5.js.map +1 -1
- package/dist/styles.css +1 -1
- package/dist/wc/AIScrollButton.js +8 -8
- package/dist/wc/AIScrollButton.js.map +1 -1
- package/dist/wc/Badge.js +9 -9
- package/dist/wc/Badge.js.map +1 -1
- package/dist/wc/Checkbox.js +22 -22
- package/dist/wc/Checkbox.js.map +1 -1
- package/dist/wc/Pagination.js +4 -4
- package/dist/wc/Pagination.js.map +1 -1
- package/dist/wc/Switch.js +23 -23
- package/dist/wc/Switch.js.map +1 -1
- package/dist/wc/Tabs.js +110 -110
- package/dist/wc/Tabs.js.map +1 -1
- package/dist/wc/Tooltip.js +28 -28
- package/dist/wc/Tooltip.js.map +1 -1
- package/dist/wc/button.js +33 -33
- package/dist/wc/button.js.map +1 -1
- package/dist/wc/hf-alert.js +10 -10
- package/dist/wc/hf-alert.js.map +1 -1
- package/dist/wc/hf-nav-account-menu.js +8 -8
- package/dist/wc/hf-nav-account-menu.js.map +1 -1
- package/dist/wc/hf-steps.js +8 -8
- package/dist/wc/hf-steps.js.map +1 -1
- package/dist/wc/markdown-renderer.js +4 -4
- package/dist/wc/markdown-renderer.js.map +1 -1
- package/dist/wc/selection-group.js +6 -6
- package/dist/wc/selection-group.js.map +1 -1
- package/dist/wc-react/AIScrollButton.js +18 -18
- package/dist/wc-react/AIScrollButton.js.map +1 -1
- package/dist/wc-react/Badge.js +16 -16
- package/dist/wc-react/Badge.js.map +1 -1
- package/dist/wc-react/Checkbox.js +14 -14
- package/dist/wc-react/Checkbox.js.map +1 -1
- package/dist/wc-react/Pagination.js +130 -130
- package/dist/wc-react/Pagination.js.map +1 -1
- package/dist/wc-react/Switch.js +2 -2
- package/dist/wc-react/Switch.js.map +1 -1
- package/dist/wc-react/Tabs.js +38 -38
- package/dist/wc-react/Tabs.js.map +1 -1
- package/dist/wc-react/Tooltip.js +22 -22
- package/dist/wc-react/Tooltip.js.map +1 -1
- package/dist/wc-react/button.js +8 -8
- package/dist/wc-react/button.js.map +1 -1
- package/dist/wc-react/hf-alert.js +28 -28
- package/dist/wc-react/hf-alert.js.map +1 -1
- package/dist/wc-react/hf-nav-account-menu.js +7 -7
- package/dist/wc-react/hf-nav-account-menu.js.map +1 -1
- package/dist/wc-react/hf-steps.js +16 -16
- package/dist/wc-react/hf-steps.js.map +1 -1
- package/dist/wc-react/markdown-renderer.js +4 -4
- package/dist/wc-react/markdown-renderer.js.map +1 -1
- package/dist/wc-react/selection-group.js +1 -1
- package/dist/wc-react/selection-group.js.map +1 -1
- package/package.json +1 -1
- package/skills/humain-ui/SKILL.md +1 -1
- package/skills/humain-ui/references/foundations.md +1 -1
- package/skills/humain-ui-wc/SKILL.md +1 -1
- package/skills/humain-ui-wc.skill +0 -0
- package/skills/humain-ui.skill +0 -0
- package/src/tokens.css +14 -6
|
@@ -13,8 +13,8 @@ function E(a = {}) {
|
|
|
13
13
|
function F(a = {}) {
|
|
14
14
|
const { value: r, defaultValue: o = [], onValueChange: e } = a, [d, t] = u.useState(o), c = r !== void 0, n = c ? r : d;
|
|
15
15
|
return [n, u.useCallback((l, f) => {
|
|
16
|
-
const
|
|
17
|
-
c || t(
|
|
16
|
+
const g = f ? [...n, l] : n.filter((x) => x !== l);
|
|
17
|
+
c || t(g), e?.(g);
|
|
18
18
|
}, [
|
|
19
19
|
c,
|
|
20
20
|
n,
|
|
@@ -102,7 +102,7 @@ var k = {
|
|
|
102
102
|
sm: "text-sm",
|
|
103
103
|
md: "text-sm",
|
|
104
104
|
lg: "text-base"
|
|
105
|
-
},
|
|
105
|
+
}, m = {
|
|
106
106
|
sm: "size-3",
|
|
107
107
|
md: "size-3.5",
|
|
108
108
|
lg: "size-4"
|
|
@@ -129,9 +129,9 @@ var V = u.forwardRef(({ type: a, checked: r = !1, disabled: o = !1, size: e = "s
|
|
|
129
129
|
className: s(C({ size: e }), r ? s(l.indicatorChecked, l.border, l.text, "border", "delight-check-bounce") : "border-border bg-background", o && "opacity-50", t),
|
|
130
130
|
"aria-hidden": "true",
|
|
131
131
|
children: r && (c ? /* @__PURE__ */ (0, i.jsx)(y, {
|
|
132
|
-
className: s(
|
|
132
|
+
className: s(m[e], "animate-[scale-in_150ms_ease-out] motion-reduce:animate-none"),
|
|
133
133
|
strokeWidth: 3
|
|
134
|
-
}) : /* @__PURE__ */ (0, i.jsx)(j, { className:
|
|
134
|
+
}) : /* @__PURE__ */ (0, i.jsx)(j, { className: m[e] }))
|
|
135
135
|
}) : /* @__PURE__ */ (0, i.jsx)("span", {
|
|
136
136
|
ref: n,
|
|
137
137
|
"data-slot": "selection-indicator",
|
|
@@ -139,7 +139,7 @@ var V = u.forwardRef(({ type: a, checked: r = !1, disabled: o = !1, size: e = "s
|
|
|
139
139
|
"data-checked": r,
|
|
140
140
|
className: s(z({ size: e }), "transition-[background-color,border-color] duration-150 motion-reduce:transition-none", r ? s(l.indicatorChecked, "border-transparent") : "border-border bg-background", o && "opacity-50", t),
|
|
141
141
|
"aria-hidden": "true",
|
|
142
|
-
children: /* @__PURE__ */ (0, i.jsx)("span", { className: s("bg-
|
|
142
|
+
children: /* @__PURE__ */ (0, i.jsx)("span", { className: s("bg-background rounded-full transition-transform duration-150 ease-out motion-reduce:transition-none", w[e], r ? "scale-100" : "scale-0") })
|
|
143
143
|
});
|
|
144
144
|
});
|
|
145
145
|
V.displayName = "SelectionIndicator";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"selection-group.js","names":[],"sources":["../../src/components/ui/selection-group.tsx"],"sourcesContent":["'use client';\n\nimport { cva } from 'class-variance-authority';\nimport { Minus } from 'lucide-react';\nimport * as React from 'react';\nimport { cn } from '@/lib/utils';\n\n// =============================================================================\n// Types\n// =============================================================================\n\nexport type SelectionColor =\n | 'primary'\n | 'secondary'\n | 'success'\n | 'warning'\n | 'info'\n | 'destructive';\n\nexport type SelectionSize = 'sm' | 'md' | 'lg';\n\nexport type SelectionVariant =\n | 'default'\n | 'card'\n | 'pill'\n | 'stacked'\n | 'icon-simple'\n | 'icon-card'\n | 'avatar'\n | 'payment'\n | 'simple'\n | 'chip';\n\nexport interface SelectionItem {\n /** Unique value for the option */\n value: string;\n /** Display label */\n label: string;\n /** Whether this option is disabled */\n disabled?: boolean;\n /** Secondary text (e.g., \"$10/month\") */\n subtext?: string;\n /** Supporting description text */\n description?: string;\n /** Leading icon component */\n icon?: React.ReactNode;\n /** Avatar element */\n avatar?: React.ReactNode;\n /** Image URL */\n image?: string;\n /** Alt text for the image (defaults to \"\" if omitted) */\n imageAlt?: string;\n /** Position of the image */\n imagePosition?: 'top' | 'left' | 'trailing';\n /** Badge element */\n badge?: React.ReactNode;\n /** Dot color for chip variant (named color or hex) */\n dotColor?: string;\n /** Price display (e.g., \"$10\") */\n price?: string;\n /** Price period (e.g., \"per month\") */\n pricePeriod?: string;\n /** Payment icon element */\n paymentIcon?: React.ReactNode;\n /** Action buttons */\n actions?: React.ReactNode;\n}\n\n// =============================================================================\n// Hooks\n// =============================================================================\n\ninterface UseSelectionStateOptions {\n /** Controlled value */\n value?: string;\n /** Default value for uncontrolled mode */\n defaultValue?: string;\n /** Callback when value changes */\n onValueChange?: (value: string) => void;\n}\n\n/**\n * Hook for managing single selection state (radio behavior).\n * Supports both controlled and uncontrolled modes.\n */\nexport function useSelectionState(\n options: UseSelectionStateOptions = {},\n): [string | undefined, (value: string) => void] {\n const { value: controlledValue, defaultValue, onValueChange } = options;\n\n const [internalValue, setInternalValue] = React.useState<string | undefined>(\n defaultValue,\n );\n\n const isControlled = controlledValue !== undefined;\n const selectedValue = isControlled ? controlledValue : internalValue;\n\n const setValue = React.useCallback(\n (newValue: string) => {\n if (!isControlled) {\n setInternalValue(newValue);\n }\n onValueChange?.(newValue);\n },\n [isControlled, onValueChange],\n );\n\n return [selectedValue, setValue];\n}\n\ninterface UseMultiSelectionStateOptions {\n /** Controlled value */\n value?: string[];\n /** Default value for uncontrolled mode */\n defaultValue?: string[];\n /** Callback when value changes */\n onValueChange?: (value: string[]) => void;\n}\n\n/**\n * Hook for managing multi selection state (checkbox behavior).\n * Supports both controlled and uncontrolled modes.\n */\nexport function useMultiSelectionState(\n options: UseMultiSelectionStateOptions = {},\n): [string[], (value: string, checked: boolean) => void] {\n const { value: controlledValue, defaultValue = [], onValueChange } = options;\n\n const [internalValue, setInternalValue] =\n React.useState<string[]>(defaultValue);\n\n const isControlled = controlledValue !== undefined;\n const selectedValues = isControlled ? controlledValue : internalValue;\n\n const setValue = React.useCallback(\n (itemValue: string, checked: boolean) => {\n const newValue = checked\n ? [...selectedValues, itemValue]\n : selectedValues.filter((v) => v !== itemValue);\n\n if (!isControlled) {\n setInternalValue(newValue);\n }\n onValueChange?.(newValue);\n },\n [isControlled, selectedValues, onValueChange],\n );\n\n return [selectedValues, setValue];\n}\n\n// =============================================================================\n// Color Mappings\n// =============================================================================\n\nexport const selectionColorClasses: Record<\n SelectionColor,\n {\n indicator: string;\n indicatorChecked: string;\n border: string;\n bg: string;\n text: string;\n }\n> = {\n primary: {\n indicator: 'border-primary',\n indicatorChecked: 'bg-primary',\n border: 'border-primary',\n bg: 'bg-primary',\n text: 'text-primary-foreground',\n },\n secondary: {\n indicator: 'border-secondary',\n indicatorChecked: 'bg-secondary',\n border: 'border-secondary',\n bg: 'bg-secondary',\n text: 'text-secondary-foreground',\n },\n success: {\n indicator: 'border-success',\n indicatorChecked: 'bg-success',\n border: 'border-success',\n bg: 'bg-success',\n text: 'text-primary-foreground',\n },\n warning: {\n indicator: 'border-warning',\n indicatorChecked: 'bg-warning',\n border: 'border-warning',\n bg: 'bg-warning',\n text: 'text-primary-foreground',\n },\n info: {\n indicator: 'border-info',\n indicatorChecked: 'bg-info',\n border: 'border-info',\n bg: 'bg-info',\n text: 'text-primary-foreground',\n },\n destructive: {\n indicator: 'border-destructive',\n indicatorChecked: 'bg-destructive',\n border: 'border-destructive',\n bg: 'bg-destructive',\n text: 'text-primary-foreground',\n },\n};\n\n// =============================================================================\n// CVA Variants\n// =============================================================================\n\n/**\n * Selection group container variants.\n * Used for the outer wrapper of a group of selection items.\n */\nexport const selectionGroupVariants = cva('flex', {\n variants: {\n orientation: {\n horizontal: 'flex-row flex-wrap',\n vertical: 'flex-col',\n },\n gap: {\n sm: 'gap-2',\n md: 'gap-3',\n lg: 'gap-4',\n },\n },\n defaultVariants: {\n orientation: 'horizontal',\n gap: 'md',\n },\n});\n\n/**\n * Selection indicator variants (for both radio and checkbox).\n * Renders as a rounded indicator with border.\n */\nexport const selectionIndicatorVariants = cva(\n 'shrink-0 rounded-full border-2 transition-all flex items-center justify-center',\n {\n variants: {\n size: {\n sm: 'size-4',\n md: 'size-5',\n lg: 'size-6',\n },\n },\n defaultVariants: {\n size: 'sm',\n },\n },\n);\n\n/**\n * Checkbox indicator variants (square with rounded corners).\n */\nexport const checkboxIndicatorVariants = cva(\n 'shrink-0 border transition-[border-color,background-color,color,box-shadow] duration-200 ease-out motion-reduce:transition-none flex items-center justify-center',\n {\n variants: {\n size: {\n sm: 'size-4 rounded-[4px]',\n md: 'size-5 rounded-[5px]',\n lg: 'size-6 rounded-[6px]',\n },\n },\n defaultVariants: {\n size: 'sm',\n },\n },\n);\n\n/**\n * Inner dot sizes for radio indicators when checked.\n */\nexport const innerDotSizes: Record<SelectionSize, string> = {\n sm: 'size-1.5',\n md: 'size-2',\n lg: 'size-2.5',\n};\n\n/**\n * Text size classes for selection labels.\n */\nexport const textSizeClasses: Record<SelectionSize, string> = {\n sm: 'text-sm',\n md: 'text-sm',\n lg: 'text-base',\n};\n\n/**\n * Icon size classes for checkbox indicators.\n */\nexport const iconSizeClasses: Record<SelectionSize, string> = {\n sm: 'size-3',\n md: 'size-3.5',\n lg: 'size-4',\n};\n\n// =============================================================================\n// Draw-on checkmark SVG (shared delight animation)\n// =============================================================================\n\nexport const CHECKMARK_PATH = 'M4 12l5 5L20 6';\n\nexport function DrawCheck({ className }: { className?: string }) {\n return (\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={3}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className={cn(className, 'delight-check-draw')}\n >\n <path d={CHECKMARK_PATH} />\n </svg>\n );\n}\n\n// =============================================================================\n// SelectionIndicator Component\n// =============================================================================\n\nexport interface SelectionIndicatorProps {\n /** Type of indicator to render */\n type: 'checkbox' | 'radio';\n /** Whether the indicator is checked */\n checked?: boolean;\n /** Whether the indicator is disabled */\n disabled?: boolean;\n /** Size of the indicator */\n size?: SelectionSize;\n /** Color of the indicator */\n color?: SelectionColor;\n /** Additional CSS classes */\n className?: string;\n /** Whether the checkbox is in indeterminate state (checkbox only) */\n indeterminate?: boolean;\n}\n\n/**\n * SelectionIndicator renders either a checkbox or radio indicator based on type.\n * For checkbox: renders a check icon when checked.\n * For radio: renders an inner dot when checked.\n */\nconst SelectionIndicator = React.forwardRef<\n HTMLSpanElement,\n SelectionIndicatorProps\n>(\n (\n {\n type,\n checked = false,\n disabled = false,\n size = 'sm',\n color = 'primary',\n className,\n indeterminate = false,\n },\n ref,\n ) => {\n const colors = selectionColorClasses[color];\n\n if (type === 'checkbox') {\n return (\n <span\n ref={ref}\n data-slot=\"selection-indicator\"\n data-type=\"checkbox\"\n data-checked={checked}\n className={cn(\n checkboxIndicatorVariants({ size }),\n checked\n ? cn(\n colors.indicatorChecked,\n colors.border,\n colors.text,\n 'border',\n 'delight-check-bounce',\n )\n : 'border-border bg-background',\n disabled && 'opacity-50',\n className,\n )}\n aria-hidden=\"true\"\n >\n {checked &&\n (indeterminate ? (\n <Minus\n className={cn(\n iconSizeClasses[size],\n 'animate-[scale-in_150ms_ease-out] motion-reduce:animate-none',\n )}\n strokeWidth={3}\n />\n ) : (\n <DrawCheck className={iconSizeClasses[size]} />\n ))}\n </span>\n );\n }\n\n // Radio type\n return (\n <span\n ref={ref}\n data-slot=\"selection-indicator\"\n data-type=\"radio\"\n data-checked={checked}\n className={cn(\n selectionIndicatorVariants({ size }),\n 'transition-[background-color,border-color] duration-150 motion-reduce:transition-none',\n checked\n ? cn(colors.indicatorChecked, 'border-transparent')\n : 'border-border bg-background',\n disabled && 'opacity-50',\n className,\n )}\n aria-hidden=\"true\"\n >\n <span\n className={cn(\n 'bg-primary-foreground rounded-full transition-transform duration-150 ease-out motion-reduce:transition-none',\n innerDotSizes[size],\n checked ? 'scale-100' : 'scale-0',\n )}\n />\n </span>\n );\n },\n);\n\nSelectionIndicator.displayName = 'SelectionIndicator';\n\n// =============================================================================\n// FeaturedIcon Component\n// =============================================================================\n\nexport interface FeaturedIconProps {\n /** The icon content to display */\n children: React.ReactNode;\n /** Size of the featured icon container */\n size?: SelectionSize;\n /** Additional CSS classes */\n className?: string;\n}\n\n// Hoisted outside component to avoid recreation on every render\nconst featuredIconContainerSizes: Record<SelectionSize, string> = {\n sm: 'size-8',\n md: 'size-10',\n lg: 'size-12',\n};\n\nconst featuredIconInnerSizes: Record<SelectionSize, string> = {\n sm: 'size-4',\n md: 'size-5',\n lg: 'size-6',\n};\n\n/**\n * FeaturedIcon is a container for icons with border and shadow.\n * Used in icon-simple and icon-card variants.\n */\nconst FeaturedIcon = React.forwardRef<HTMLDivElement, FeaturedIconProps>(\n ({ children, size = 'sm', className }, ref) => {\n const containerSize = featuredIconContainerSizes[size];\n const innerSize = featuredIconInnerSizes[size];\n\n return (\n <div\n ref={ref}\n data-slot=\"featured-icon\"\n className={cn(\n 'shrink-0 rounded-md border border-border bg-card/60',\n 'flex items-center justify-center',\n 'dark:bg-foreground/60 dark:border-border',\n containerSize,\n className,\n )}\n style={{\n boxShadow: 'var(--shadow-inset-ring)',\n }}\n >\n <div\n className={cn(\n 'text-secondary-foreground dark:text-text-quaternary',\n innerSize,\n )}\n >\n {children}\n </div>\n </div>\n );\n },\n);\n\nFeaturedIcon.displayName = 'FeaturedIcon';\n\n// =============================================================================\n// ColorDot Component\n// =============================================================================\n\nexport type ColorDotColor =\n | 'gray'\n | 'orange'\n | 'red'\n | 'darkRed'\n | 'brand'\n | 'success'\n | 'warning'\n | 'error'\n | string; // Allow custom hex colors\n\nconst dotColorMap: Record<string, string> = {\n gray: 'bg-muted',\n orange: 'bg-warning',\n red: 'bg-destructive',\n darkRed: 'bg-destructive-hover',\n brand: 'bg-primary/10',\n success: 'bg-success/10',\n warning: 'bg-warning/10',\n error: 'bg-destructive/10',\n};\n\nconst dotSizeMap: Record<SelectionSize, string> = {\n sm: 'size-[10px]',\n md: 'size-3',\n lg: 'size-3.5',\n};\n\nexport interface ColorDotProps {\n /** Color of the dot (named color or hex) */\n color?: ColorDotColor;\n /** Size of the dot */\n size?: SelectionSize;\n /** Additional CSS classes */\n className?: string;\n}\n\n/**\n * ColorDot renders a colored dot for chip variant.\n * Supports named colors (gray, orange, red, etc.) and hex colors.\n */\nconst ColorDot = React.forwardRef<HTMLSpanElement, ColorDotProps>(\n ({ color, size = 'sm', className }, ref) => {\n if (!color) return null;\n\n const colorClass = dotColorMap[color];\n const isHexColor = color.startsWith('#');\n\n return (\n <span\n ref={ref}\n data-slot=\"color-dot\"\n className={cn(\n 'shrink-0 rounded-full',\n dotSizeMap[size],\n !isHexColor && colorClass,\n className,\n )}\n style={isHexColor ? { backgroundColor: color } : undefined}\n aria-hidden=\"true\"\n />\n );\n },\n);\n\nColorDot.displayName = 'ColorDot';\n\n// =============================================================================\n// Exports\n// =============================================================================\n\nexport { ColorDot, FeaturedIcon, SelectionIndicator };\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"selection-group.js","names":[],"sources":["../../src/components/ui/selection-group.tsx"],"sourcesContent":["'use client';\n\nimport { cva } from 'class-variance-authority';\nimport { Minus } from 'lucide-react';\nimport * as React from 'react';\nimport { cn } from '@/lib/utils';\n\n// =============================================================================\n// Types\n// =============================================================================\n\nexport type SelectionColor =\n | 'primary'\n | 'secondary'\n | 'success'\n | 'warning'\n | 'info'\n | 'destructive';\n\nexport type SelectionSize = 'sm' | 'md' | 'lg';\n\nexport type SelectionVariant =\n | 'default'\n | 'card'\n | 'pill'\n | 'stacked'\n | 'icon-simple'\n | 'icon-card'\n | 'avatar'\n | 'payment'\n | 'simple'\n | 'chip';\n\nexport interface SelectionItem {\n /** Unique value for the option */\n value: string;\n /** Display label */\n label: string;\n /** Whether this option is disabled */\n disabled?: boolean;\n /** Secondary text (e.g., \"$10/month\") */\n subtext?: string;\n /** Supporting description text */\n description?: string;\n /** Leading icon component */\n icon?: React.ReactNode;\n /** Avatar element */\n avatar?: React.ReactNode;\n /** Image URL */\n image?: string;\n /** Alt text for the image (defaults to \"\" if omitted) */\n imageAlt?: string;\n /** Position of the image */\n imagePosition?: 'top' | 'left' | 'trailing';\n /** Badge element */\n badge?: React.ReactNode;\n /** Dot color for chip variant (named color or hex) */\n dotColor?: string;\n /** Price display (e.g., \"$10\") */\n price?: string;\n /** Price period (e.g., \"per month\") */\n pricePeriod?: string;\n /** Payment icon element */\n paymentIcon?: React.ReactNode;\n /** Action buttons */\n actions?: React.ReactNode;\n}\n\n// =============================================================================\n// Hooks\n// =============================================================================\n\ninterface UseSelectionStateOptions {\n /** Controlled value */\n value?: string;\n /** Default value for uncontrolled mode */\n defaultValue?: string;\n /** Callback when value changes */\n onValueChange?: (value: string) => void;\n}\n\n/**\n * Hook for managing single selection state (radio behavior).\n * Supports both controlled and uncontrolled modes.\n */\nexport function useSelectionState(\n options: UseSelectionStateOptions = {},\n): [string | undefined, (value: string) => void] {\n const { value: controlledValue, defaultValue, onValueChange } = options;\n\n const [internalValue, setInternalValue] = React.useState<string | undefined>(\n defaultValue,\n );\n\n const isControlled = controlledValue !== undefined;\n const selectedValue = isControlled ? controlledValue : internalValue;\n\n const setValue = React.useCallback(\n (newValue: string) => {\n if (!isControlled) {\n setInternalValue(newValue);\n }\n onValueChange?.(newValue);\n },\n [isControlled, onValueChange],\n );\n\n return [selectedValue, setValue];\n}\n\ninterface UseMultiSelectionStateOptions {\n /** Controlled value */\n value?: string[];\n /** Default value for uncontrolled mode */\n defaultValue?: string[];\n /** Callback when value changes */\n onValueChange?: (value: string[]) => void;\n}\n\n/**\n * Hook for managing multi selection state (checkbox behavior).\n * Supports both controlled and uncontrolled modes.\n */\nexport function useMultiSelectionState(\n options: UseMultiSelectionStateOptions = {},\n): [string[], (value: string, checked: boolean) => void] {\n const { value: controlledValue, defaultValue = [], onValueChange } = options;\n\n const [internalValue, setInternalValue] =\n React.useState<string[]>(defaultValue);\n\n const isControlled = controlledValue !== undefined;\n const selectedValues = isControlled ? controlledValue : internalValue;\n\n const setValue = React.useCallback(\n (itemValue: string, checked: boolean) => {\n const newValue = checked\n ? [...selectedValues, itemValue]\n : selectedValues.filter((v) => v !== itemValue);\n\n if (!isControlled) {\n setInternalValue(newValue);\n }\n onValueChange?.(newValue);\n },\n [isControlled, selectedValues, onValueChange],\n );\n\n return [selectedValues, setValue];\n}\n\n// =============================================================================\n// Color Mappings\n// =============================================================================\n\nexport const selectionColorClasses: Record<\n SelectionColor,\n {\n indicator: string;\n indicatorChecked: string;\n border: string;\n bg: string;\n text: string;\n }\n> = {\n primary: {\n indicator: 'border-primary',\n indicatorChecked: 'bg-primary',\n border: 'border-primary',\n bg: 'bg-primary',\n text: 'text-primary-foreground',\n },\n secondary: {\n indicator: 'border-secondary',\n indicatorChecked: 'bg-secondary',\n border: 'border-secondary',\n bg: 'bg-secondary',\n text: 'text-secondary-foreground',\n },\n success: {\n indicator: 'border-success',\n indicatorChecked: 'bg-success',\n border: 'border-success',\n bg: 'bg-success',\n text: 'text-primary-foreground',\n },\n warning: {\n indicator: 'border-warning',\n indicatorChecked: 'bg-warning',\n border: 'border-warning',\n bg: 'bg-warning',\n text: 'text-primary-foreground',\n },\n info: {\n indicator: 'border-info',\n indicatorChecked: 'bg-info',\n border: 'border-info',\n bg: 'bg-info',\n text: 'text-primary-foreground',\n },\n destructive: {\n indicator: 'border-destructive',\n indicatorChecked: 'bg-destructive',\n border: 'border-destructive',\n bg: 'bg-destructive',\n text: 'text-primary-foreground',\n },\n};\n\n// =============================================================================\n// CVA Variants\n// =============================================================================\n\n/**\n * Selection group container variants.\n * Used for the outer wrapper of a group of selection items.\n */\nexport const selectionGroupVariants = cva('flex', {\n variants: {\n orientation: {\n horizontal: 'flex-row flex-wrap',\n vertical: 'flex-col',\n },\n gap: {\n sm: 'gap-2',\n md: 'gap-3',\n lg: 'gap-4',\n },\n },\n defaultVariants: {\n orientation: 'horizontal',\n gap: 'md',\n },\n});\n\n/**\n * Selection indicator variants (for both radio and checkbox).\n * Renders as a rounded indicator with border.\n */\nexport const selectionIndicatorVariants = cva(\n 'shrink-0 rounded-full border-2 transition-all flex items-center justify-center',\n {\n variants: {\n size: {\n sm: 'size-4',\n md: 'size-5',\n lg: 'size-6',\n },\n },\n defaultVariants: {\n size: 'sm',\n },\n },\n);\n\n/**\n * Checkbox indicator variants (square with rounded corners).\n */\nexport const checkboxIndicatorVariants = cva(\n 'shrink-0 border transition-[border-color,background-color,color,box-shadow] duration-200 ease-out motion-reduce:transition-none flex items-center justify-center',\n {\n variants: {\n size: {\n sm: 'size-4 rounded-[4px]',\n md: 'size-5 rounded-[5px]',\n lg: 'size-6 rounded-[6px]',\n },\n },\n defaultVariants: {\n size: 'sm',\n },\n },\n);\n\n/**\n * Inner dot sizes for radio indicators when checked.\n */\nexport const innerDotSizes: Record<SelectionSize, string> = {\n sm: 'size-1.5',\n md: 'size-2',\n lg: 'size-2.5',\n};\n\n/**\n * Text size classes for selection labels.\n */\nexport const textSizeClasses: Record<SelectionSize, string> = {\n sm: 'text-sm',\n md: 'text-sm',\n lg: 'text-base',\n};\n\n/**\n * Icon size classes for checkbox indicators.\n */\nexport const iconSizeClasses: Record<SelectionSize, string> = {\n sm: 'size-3',\n md: 'size-3.5',\n lg: 'size-4',\n};\n\n// =============================================================================\n// Draw-on checkmark SVG (shared delight animation)\n// =============================================================================\n\nexport const CHECKMARK_PATH = 'M4 12l5 5L20 6';\n\nexport function DrawCheck({ className }: { className?: string }) {\n return (\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={3}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className={cn(className, 'delight-check-draw')}\n >\n <path d={CHECKMARK_PATH} />\n </svg>\n );\n}\n\n// =============================================================================\n// SelectionIndicator Component\n// =============================================================================\n\nexport interface SelectionIndicatorProps {\n /** Type of indicator to render */\n type: 'checkbox' | 'radio';\n /** Whether the indicator is checked */\n checked?: boolean;\n /** Whether the indicator is disabled */\n disabled?: boolean;\n /** Size of the indicator */\n size?: SelectionSize;\n /** Color of the indicator */\n color?: SelectionColor;\n /** Additional CSS classes */\n className?: string;\n /** Whether the checkbox is in indeterminate state (checkbox only) */\n indeterminate?: boolean;\n}\n\n/**\n * SelectionIndicator renders either a checkbox or radio indicator based on type.\n * For checkbox: renders a check icon when checked.\n * For radio: renders an inner dot when checked.\n */\nconst SelectionIndicator = React.forwardRef<\n HTMLSpanElement,\n SelectionIndicatorProps\n>(\n (\n {\n type,\n checked = false,\n disabled = false,\n size = 'sm',\n color = 'primary',\n className,\n indeterminate = false,\n },\n ref,\n ) => {\n const colors = selectionColorClasses[color];\n\n if (type === 'checkbox') {\n return (\n <span\n ref={ref}\n data-slot=\"selection-indicator\"\n data-type=\"checkbox\"\n data-checked={checked}\n className={cn(\n checkboxIndicatorVariants({ size }),\n checked\n ? cn(\n colors.indicatorChecked,\n colors.border,\n colors.text,\n 'border',\n 'delight-check-bounce',\n )\n : 'border-border bg-background',\n disabled && 'opacity-50',\n className,\n )}\n aria-hidden=\"true\"\n >\n {checked &&\n (indeterminate ? (\n <Minus\n className={cn(\n iconSizeClasses[size],\n 'animate-[scale-in_150ms_ease-out] motion-reduce:animate-none',\n )}\n strokeWidth={3}\n />\n ) : (\n <DrawCheck className={iconSizeClasses[size]} />\n ))}\n </span>\n );\n }\n\n // Radio type\n return (\n <span\n ref={ref}\n data-slot=\"selection-indicator\"\n data-type=\"radio\"\n data-checked={checked}\n className={cn(\n selectionIndicatorVariants({ size }),\n 'transition-[background-color,border-color] duration-150 motion-reduce:transition-none',\n checked\n ? cn(colors.indicatorChecked, 'border-transparent')\n : 'border-border bg-background',\n disabled && 'opacity-50',\n className,\n )}\n aria-hidden=\"true\"\n >\n <span\n className={cn(\n 'bg-background rounded-full transition-transform duration-150 ease-out motion-reduce:transition-none',\n innerDotSizes[size],\n checked ? 'scale-100' : 'scale-0',\n )}\n />\n </span>\n );\n },\n);\n\nSelectionIndicator.displayName = 'SelectionIndicator';\n\n// =============================================================================\n// FeaturedIcon Component\n// =============================================================================\n\nexport interface FeaturedIconProps {\n /** The icon content to display */\n children: React.ReactNode;\n /** Size of the featured icon container */\n size?: SelectionSize;\n /** Additional CSS classes */\n className?: string;\n}\n\n// Hoisted outside component to avoid recreation on every render\nconst featuredIconContainerSizes: Record<SelectionSize, string> = {\n sm: 'size-8',\n md: 'size-10',\n lg: 'size-12',\n};\n\nconst featuredIconInnerSizes: Record<SelectionSize, string> = {\n sm: 'size-4',\n md: 'size-5',\n lg: 'size-6',\n};\n\n/**\n * FeaturedIcon is a container for icons with border and shadow.\n * Used in icon-simple and icon-card variants.\n */\nconst FeaturedIcon = React.forwardRef<HTMLDivElement, FeaturedIconProps>(\n ({ children, size = 'sm', className }, ref) => {\n const containerSize = featuredIconContainerSizes[size];\n const innerSize = featuredIconInnerSizes[size];\n\n return (\n <div\n ref={ref}\n data-slot=\"featured-icon\"\n className={cn(\n 'shrink-0 rounded-md border border-border bg-card/60',\n 'flex items-center justify-center',\n 'dark:bg-foreground/60 dark:border-border',\n containerSize,\n className,\n )}\n style={{\n boxShadow: 'var(--shadow-inset-ring)',\n }}\n >\n <div\n className={cn(\n 'text-secondary-foreground dark:text-text-quaternary',\n innerSize,\n )}\n >\n {children}\n </div>\n </div>\n );\n },\n);\n\nFeaturedIcon.displayName = 'FeaturedIcon';\n\n// =============================================================================\n// ColorDot Component\n// =============================================================================\n\nexport type ColorDotColor =\n | 'gray'\n | 'orange'\n | 'red'\n | 'darkRed'\n | 'brand'\n | 'success'\n | 'warning'\n | 'error'\n | string; // Allow custom hex colors\n\nconst dotColorMap: Record<string, string> = {\n gray: 'bg-muted',\n orange: 'bg-warning',\n red: 'bg-destructive',\n darkRed: 'bg-destructive-hover',\n brand: 'bg-primary/10',\n success: 'bg-success/10',\n warning: 'bg-warning/10',\n error: 'bg-destructive/10',\n};\n\nconst dotSizeMap: Record<SelectionSize, string> = {\n sm: 'size-[10px]',\n md: 'size-3',\n lg: 'size-3.5',\n};\n\nexport interface ColorDotProps {\n /** Color of the dot (named color or hex) */\n color?: ColorDotColor;\n /** Size of the dot */\n size?: SelectionSize;\n /** Additional CSS classes */\n className?: string;\n}\n\n/**\n * ColorDot renders a colored dot for chip variant.\n * Supports named colors (gray, orange, red, etc.) and hex colors.\n */\nconst ColorDot = React.forwardRef<HTMLSpanElement, ColorDotProps>(\n ({ color, size = 'sm', className }, ref) => {\n if (!color) return null;\n\n const colorClass = dotColorMap[color];\n const isHexColor = color.startsWith('#');\n\n return (\n <span\n ref={ref}\n data-slot=\"color-dot\"\n className={cn(\n 'shrink-0 rounded-full',\n dotSizeMap[size],\n !isHexColor && colorClass,\n className,\n )}\n style={isHexColor ? { backgroundColor: color } : undefined}\n aria-hidden=\"true\"\n />\n );\n },\n);\n\nColorDot.displayName = 'ColorDot';\n\n// =============================================================================\n// Exports\n// =============================================================================\n\nexport { ColorDot, FeaturedIcon, SelectionIndicator };\n"],"mappings":"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"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { f as
|
|
1
|
+
import { f as w } from "./_shared.js";
|
|
2
2
|
import { t as k } from "./arrow-down.js";
|
|
3
3
|
import { t as I } from "./dist.js";
|
|
4
4
|
import { t as V } from "./button.js";
|
|
5
|
-
import { t as
|
|
5
|
+
import { t as y } from "./react.js";
|
|
6
6
|
import { t as N } from "./AnimatePresence.js";
|
|
7
7
|
import * as e from "react";
|
|
8
8
|
import { jsx as p, jsxs as H } from "react/jsx-runtime";
|
|
@@ -31,7 +31,7 @@ var T = I("fixed flex items-center justify-center shadow-lg transition-all", {
|
|
|
31
31
|
}
|
|
32
32
|
});
|
|
33
33
|
function U({ threshold: l = 50, behavior: n = "smooth", autoScroll: m = !1 } = {}) {
|
|
34
|
-
const o = e.useRef(null), a = e.useRef(null), [b,
|
|
34
|
+
const o = e.useRef(null), a = e.useRef(null), [b, d] = e.useState(!0), [f, h] = e.useState(!0), i = e.useCallback((t) => {
|
|
35
35
|
const r = t ?? n;
|
|
36
36
|
a.current ? a.current.scrollIntoView({ behavior: r }) : o.current && (o.current.scrollTop = o.current.scrollHeight);
|
|
37
37
|
}, [n]), u = e.useCallback(() => {
|
|
@@ -45,7 +45,7 @@ function U({ threshold: l = 50, behavior: n = "smooth", autoScroll: m = !1 } = {
|
|
|
45
45
|
if (!t) return;
|
|
46
46
|
const r = () => {
|
|
47
47
|
const c = u();
|
|
48
|
-
|
|
48
|
+
d((s) => s === c ? s : c), m && c && h((s) => s || !0);
|
|
49
49
|
};
|
|
50
50
|
return r(), t.addEventListener("scroll", r, { passive: !0 }), () => t.removeEventListener("scroll", r);
|
|
51
51
|
}, [u, m]), e.useEffect(() => {
|
|
@@ -55,7 +55,7 @@ function U({ threshold: l = 50, behavior: n = "smooth", autoScroll: m = !1 } = {
|
|
|
55
55
|
if (!r) return;
|
|
56
56
|
const c = new r(() => {
|
|
57
57
|
const s = u();
|
|
58
|
-
|
|
58
|
+
d((g) => g === s ? g : s);
|
|
59
59
|
});
|
|
60
60
|
return c.observe(t), () => c.disconnect();
|
|
61
61
|
}, [u]), {
|
|
@@ -63,17 +63,17 @@ function U({ threshold: l = 50, behavior: n = "smooth", autoScroll: m = !1 } = {
|
|
|
63
63
|
scrollToBottom: i,
|
|
64
64
|
containerRef: o,
|
|
65
65
|
anchorRef: a,
|
|
66
|
-
shouldAutoScroll:
|
|
66
|
+
shouldAutoScroll: f,
|
|
67
67
|
handleUserScroll: e.useCallback(() => {
|
|
68
68
|
u() || h(!1);
|
|
69
69
|
}, [u]),
|
|
70
70
|
triggerAutoScroll: e.useCallback(() => {
|
|
71
|
-
m &&
|
|
71
|
+
m && f && (a.current?.ownerDocument.defaultView ?? o.current?.ownerDocument.defaultView)?.requestAnimationFrame(() => {
|
|
72
72
|
i("smooth");
|
|
73
73
|
});
|
|
74
74
|
}, [
|
|
75
75
|
m,
|
|
76
|
-
|
|
76
|
+
f,
|
|
77
77
|
i
|
|
78
78
|
])
|
|
79
79
|
};
|
|
@@ -88,7 +88,7 @@ function j(l) {
|
|
|
88
88
|
return "size-5";
|
|
89
89
|
}
|
|
90
90
|
}
|
|
91
|
-
function D({ scrollRef: l, containerRef: n, threshold: m = 50, onClick: o, visible: a, variant: b, size:
|
|
91
|
+
function D({ scrollRef: l, containerRef: n, threshold: m = 50, onClick: o, visible: a, variant: b, size: d, position: f, label: h = "Scroll to bottom", unreadCount: i, className: u }) {
|
|
92
92
|
const [t, r] = e.useState(!1);
|
|
93
93
|
e.useEffect(() => {
|
|
94
94
|
if (a !== void 0) return;
|
|
@@ -106,8 +106,8 @@ function D({ scrollRef: l, containerRef: n, threshold: m = 50, onClick: o, visib
|
|
|
106
106
|
]);
|
|
107
107
|
const c = a ?? t, s = () => {
|
|
108
108
|
o ? o() : l?.current ? l.current.scrollIntoView({ behavior: "smooth" }) : n?.current && (n.current.scrollTop = n.current.scrollHeight);
|
|
109
|
-
}, g = j(
|
|
110
|
-
return /* @__PURE__ */ p(N, { children: c && /* @__PURE__ */ H(
|
|
109
|
+
}, g = j(d);
|
|
110
|
+
return /* @__PURE__ */ p(N, { children: c && /* @__PURE__ */ H(y.div, {
|
|
111
111
|
"data-slot": "ai-scroll-button",
|
|
112
112
|
initial: {
|
|
113
113
|
opacity: 0,
|
|
@@ -133,10 +133,10 @@ function D({ scrollRef: l, containerRef: n, threshold: m = 50, onClick: o, visib
|
|
|
133
133
|
1
|
|
134
134
|
]
|
|
135
135
|
},
|
|
136
|
-
className:
|
|
136
|
+
className: w(T({
|
|
137
137
|
variant: b,
|
|
138
|
-
size:
|
|
139
|
-
position:
|
|
138
|
+
size: d,
|
|
139
|
+
position: f
|
|
140
140
|
}), "motion-reduce:transition-none", u),
|
|
141
141
|
children: [/* @__PURE__ */ p(V, {
|
|
142
142
|
appearance: "ghost",
|
|
@@ -145,8 +145,8 @@ function D({ scrollRef: l, containerRef: n, threshold: m = 50, onClick: o, visib
|
|
|
145
145
|
onClick: s,
|
|
146
146
|
className: "size-full rounded-full",
|
|
147
147
|
"aria-label": h,
|
|
148
|
-
children: /* @__PURE__ */ p(k, { className:
|
|
149
|
-
}), i !== void 0 && i > 0 && /* @__PURE__ */ p(
|
|
148
|
+
children: /* @__PURE__ */ p(k, { className: w(g, b === "primary" ? "text-primary-foreground" : "text-muted-foreground") })
|
|
149
|
+
}), i !== void 0 && i > 0 && /* @__PURE__ */ p(y.div, {
|
|
150
150
|
initial: { scale: 0 },
|
|
151
151
|
animate: { scale: 1 },
|
|
152
152
|
transition: {
|
|
@@ -154,7 +154,7 @@ function D({ scrollRef: l, containerRef: n, threshold: m = 50, onClick: o, visib
|
|
|
154
154
|
stiffness: 500,
|
|
155
155
|
damping: 30
|
|
156
156
|
},
|
|
157
|
-
className: "absolute -top-1 -end-1 flex items-center justify-center min-w-[18px] h-[18px] px-1 rounded-full bg-destructive text-
|
|
157
|
+
className: "absolute -top-1 -end-1 flex items-center justify-center min-w-[18px] h-[18px] px-1 rounded-full bg-destructive text-destructive-foreground text-xs font-medium motion-reduce:transition-none",
|
|
158
158
|
"aria-label": `${i > 99 ? "99+" : i} new messages`,
|
|
159
159
|
children: i > 99 ? "99+" : i
|
|
160
160
|
})]
|
|
@@ -163,7 +163,7 @@ function D({ scrollRef: l, containerRef: n, threshold: m = 50, onClick: o, visib
|
|
|
163
163
|
D.displayName = "AIScrollButton";
|
|
164
164
|
var E = e.forwardRef(({ className: l }, n) => /* @__PURE__ */ p("div", {
|
|
165
165
|
ref: n,
|
|
166
|
-
className:
|
|
166
|
+
className: w("h-px w-full", l),
|
|
167
167
|
"aria-hidden": !0
|
|
168
168
|
}));
|
|
169
169
|
E.displayName = "AIScrollAnchor";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AIScrollButton.js","names":[],"sources":["../../src/components/organisms/ai/AIScrollButton/AIScrollButton.tsx"],"sourcesContent":["import { cva, type VariantProps } from 'class-variance-authority';\nimport { ArrowDown } from 'lucide-react';\nimport { AnimatePresence, motion } from 'motion/react';\nimport * as React from 'react';\nimport { Button } from '@/components/atoms/buttons/Button';\nimport { cn } from '@/lib/utils';\n\n// =============================================================================\n// Variants\n// =============================================================================\n\nconst scrollButtonVariants = cva(\n 'fixed flex items-center justify-center shadow-lg transition-all',\n {\n variants: {\n variant: {\n default: 'bg-background hover:bg-muted border border-border',\n primary: 'bg-primary/10 hover:bg-primary/90 text-primary-foreground',\n ghost:\n 'bg-card/80 hover:bg-background supports-backdrop-filter:backdrop-blur-sm border border-border',\n },\n size: {\n sm: 'size-8 rounded-full',\n md: 'size-10 rounded-full',\n lg: 'size-12 rounded-xl',\n },\n position: {\n 'bottom-center':\n 'bottom-4 start-1/2 -translate-x-1/2 rtl:translate-x-1/2',\n 'bottom-right': 'bottom-4 end-4',\n 'bottom-left': 'bottom-4 start-4',\n },\n },\n defaultVariants: {\n variant: 'default',\n size: 'md',\n position: 'bottom-center',\n },\n },\n);\n\n// =============================================================================\n// useScrollToBottom Hook\n// =============================================================================\n\nexport interface UseScrollToBottomOptions {\n /** Threshold in pixels from bottom to consider \"at bottom\" */\n threshold?: number;\n /** Scroll behavior */\n behavior?: ScrollBehavior;\n /** Enable auto-scroll mode: tracks whether auto-scroll should fire on content changes */\n autoScroll?: boolean;\n}\n\nexport interface UseScrollToBottomReturn {\n /** Whether the user is at the bottom of the container */\n isAtBottom: boolean;\n /** Scroll to bottom function */\n scrollToBottom: (behavior?: ScrollBehavior) => void;\n /** Ref to attach to the scrollable container */\n containerRef: React.RefObject<HTMLDivElement | null>;\n /** Ref to attach to the scroll anchor element */\n anchorRef: React.RefObject<HTMLDivElement | null>;\n /** Whether auto-scroll should fire (only meaningful when autoScroll option is true) */\n shouldAutoScroll: boolean;\n /** Call when user scrolls manually to disable auto-scroll (re-enables when user scrolls back to bottom) */\n handleUserScroll: () => void;\n /** Trigger an auto-scroll if shouldAutoScroll is true (uses requestAnimationFrame) */\n triggerAutoScroll: () => void;\n}\n\nexport function useScrollToBottom({\n threshold = 50,\n behavior = 'smooth',\n autoScroll: autoScrollEnabled = false,\n}: UseScrollToBottomOptions = {}): UseScrollToBottomReturn {\n const containerRef = React.useRef<HTMLDivElement>(null);\n const anchorRef = React.useRef<HTMLDivElement>(null);\n const [isAtBottom, setIsAtBottom] = React.useState(true);\n const [shouldAutoScroll, setShouldAutoScroll] = React.useState(true);\n\n const scrollToBottom = React.useCallback(\n (overrideBehavior?: ScrollBehavior) => {\n const scrollBehavior = overrideBehavior ?? behavior;\n if (anchorRef.current) {\n anchorRef.current.scrollIntoView({ behavior: scrollBehavior });\n } else if (containerRef.current) {\n containerRef.current.scrollTop = containerRef.current.scrollHeight;\n }\n },\n [behavior],\n );\n\n const checkIsAtBottom = React.useCallback(() => {\n const container = containerRef.current;\n if (!container) return true;\n const { scrollTop, scrollHeight, clientHeight } = container;\n const distanceFromBottom = scrollHeight - scrollTop - clientHeight;\n return distanceFromBottom <= threshold;\n }, [threshold]);\n\n React.useEffect(() => {\n const container = containerRef.current;\n if (!container) return;\n\n const handleScroll = () => {\n const atBottom = checkIsAtBottom();\n setIsAtBottom((prev) => (prev === atBottom ? prev : atBottom));\n if (autoScrollEnabled && atBottom) {\n setShouldAutoScroll((prev) => prev || true);\n }\n };\n\n handleScroll();\n\n container.addEventListener('scroll', handleScroll, { passive: true });\n return () => container.removeEventListener('scroll', handleScroll);\n }, [checkIsAtBottom, autoScrollEnabled]);\n\n React.useEffect(() => {\n const container = containerRef.current;\n if (!container) return;\n const OwnerResizeObserver =\n container.ownerDocument.defaultView?.ResizeObserver;\n if (!OwnerResizeObserver) return;\n\n const resizeObserver = new OwnerResizeObserver(() => {\n const atBottom = checkIsAtBottom();\n setIsAtBottom((prev) => (prev === atBottom ? prev : atBottom));\n });\n\n resizeObserver.observe(container);\n return () => resizeObserver.disconnect();\n }, [checkIsAtBottom]);\n\n const handleUserScroll = React.useCallback(() => {\n if (!checkIsAtBottom()) {\n setShouldAutoScroll(false);\n }\n }, [checkIsAtBottom]);\n\n const triggerAutoScroll = React.useCallback(() => {\n if (autoScrollEnabled && shouldAutoScroll) {\n const ownerWindow =\n anchorRef.current?.ownerDocument.defaultView ??\n containerRef.current?.ownerDocument.defaultView;\n ownerWindow?.requestAnimationFrame(() => {\n scrollToBottom('smooth');\n });\n }\n }, [autoScrollEnabled, shouldAutoScroll, scrollToBottom]);\n\n return {\n isAtBottom,\n scrollToBottom,\n containerRef,\n anchorRef,\n shouldAutoScroll,\n handleUserScroll,\n triggerAutoScroll,\n };\n}\n\n// =============================================================================\n// Main AIScrollButton Component\n// =============================================================================\n\nexport interface AIScrollButtonProps\n extends VariantProps<typeof scrollButtonVariants> {\n /** Target scroll element ref */\n scrollRef?: React.RefObject<HTMLElement | null>;\n /** Scrollable container ref */\n containerRef?: React.RefObject<HTMLElement | null>;\n /** Threshold in pixels from bottom to show button */\n threshold?: number;\n /** Click handler (defaults to scrolling to bottom) */\n onClick?: () => void;\n /** Whether to show the button (controlled) */\n visible?: boolean;\n /** Label for accessibility */\n label?: string;\n /** Show unread count badge */\n unreadCount?: number;\n /** Additional class name */\n className?: string;\n}\n\nfunction getIconSize(size: AIScrollButtonProps['size']): string {\n switch (size) {\n case 'sm':\n return 'size-4';\n case 'lg':\n return 'size-6';\n default:\n return 'size-5';\n }\n}\n\nfunction AIScrollButton({\n scrollRef,\n containerRef,\n threshold = 50,\n onClick,\n visible: controlledVisible,\n variant,\n size,\n position,\n label = 'Scroll to bottom',\n unreadCount,\n className,\n}: AIScrollButtonProps) {\n const [internalVisible, setInternalVisible] = React.useState(false);\n\n // Track scroll position if containerRef is provided and no controlled visibility\n React.useEffect(() => {\n if (controlledVisible !== undefined) return;\n\n const container = containerRef?.current;\n if (!container) return;\n\n const handleScroll = () => {\n const { scrollTop, scrollHeight, clientHeight } = container;\n const distanceFromBottom = scrollHeight - scrollTop - clientHeight;\n setInternalVisible(distanceFromBottom > threshold);\n };\n\n handleScroll();\n container.addEventListener('scroll', handleScroll, { passive: true });\n return () => container.removeEventListener('scroll', handleScroll);\n }, [containerRef, threshold, controlledVisible]);\n\n const isVisible = controlledVisible ?? internalVisible;\n\n const handleClick = () => {\n if (onClick) {\n onClick();\n } else if (scrollRef?.current) {\n scrollRef.current.scrollIntoView({ behavior: 'smooth' });\n } else if (containerRef?.current) {\n containerRef.current.scrollTop = containerRef.current.scrollHeight;\n }\n };\n\n const iconSize = getIconSize(size);\n\n return (\n <AnimatePresence>\n {isVisible && (\n <motion.div\n data-slot=\"ai-scroll-button\"\n initial={{ opacity: 0, y: 20, scale: 0.9 }}\n animate={{ opacity: 1, y: 0, scale: 1 }}\n exit={{ opacity: 0, y: 20, scale: 0.9 }}\n transition={{ duration: 0.2, ease: [0.4, 0, 0.2, 1] }}\n className={cn(\n scrollButtonVariants({ variant, size, position }),\n 'motion-reduce:transition-none',\n className,\n )}\n >\n <Button\n appearance=\"ghost\"\n variant=\"secondary\"\n size=\"icon\"\n onClick={handleClick}\n className=\"size-full rounded-full\"\n aria-label={label}\n >\n <ArrowDown\n className={cn(\n iconSize,\n variant === 'primary'\n ? 'text-primary-foreground'\n : 'text-muted-foreground',\n )}\n />\n </Button>\n\n {/* Unread count badge */}\n {unreadCount !== undefined && unreadCount > 0 && (\n <motion.div\n initial={{ scale: 0 }}\n animate={{ scale: 1 }}\n transition={{ type: 'spring', stiffness: 500, damping: 30 }}\n className=\"absolute -top-1 -end-1 flex items-center justify-center min-w-[18px] h-[18px] px-1 rounded-full bg-destructive text-primary-foreground text-xs font-medium motion-reduce:transition-none\"\n aria-label={`${unreadCount > 99 ? '99+' : unreadCount} new messages`}\n >\n {unreadCount > 99 ? '99+' : unreadCount}\n </motion.div>\n )}\n </motion.div>\n )}\n </AnimatePresence>\n );\n}\n\nAIScrollButton.displayName = 'AIScrollButton';\n\n// =============================================================================\n// Scroll Anchor Component\n// =============================================================================\n\nexport interface AIScrollAnchorProps {\n /** Ref to expose for scrolling */\n ref?: React.Ref<HTMLDivElement>;\n /** Additional class name */\n className?: string;\n}\n\nconst AIScrollAnchor = React.forwardRef<HTMLDivElement, AIScrollAnchorProps>(\n ({ className }, ref) => {\n return (\n <div ref={ref} className={cn('h-px w-full', className)} aria-hidden />\n );\n },\n);\n\nAIScrollAnchor.displayName = 'AIScrollAnchor';\n\nexport { AIScrollAnchor, AIScrollButton, scrollButtonVariants };\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"AIScrollButton.js","names":[],"sources":["../../src/components/organisms/ai/AIScrollButton/AIScrollButton.tsx"],"sourcesContent":["import { cva, type VariantProps } from 'class-variance-authority';\nimport { ArrowDown } from 'lucide-react';\nimport { AnimatePresence, motion } from 'motion/react';\nimport * as React from 'react';\nimport { Button } from '@/components/atoms/buttons/Button';\nimport { cn } from '@/lib/utils';\n\n// =============================================================================\n// Variants\n// =============================================================================\n\nconst scrollButtonVariants = cva(\n 'fixed flex items-center justify-center shadow-lg transition-all',\n {\n variants: {\n variant: {\n default: 'bg-background hover:bg-muted border border-border',\n primary: 'bg-primary/10 hover:bg-primary/90 text-primary-foreground',\n ghost:\n 'bg-card/80 hover:bg-background supports-backdrop-filter:backdrop-blur-sm border border-border',\n },\n size: {\n sm: 'size-8 rounded-full',\n md: 'size-10 rounded-full',\n lg: 'size-12 rounded-xl',\n },\n position: {\n 'bottom-center':\n 'bottom-4 start-1/2 -translate-x-1/2 rtl:translate-x-1/2',\n 'bottom-right': 'bottom-4 end-4',\n 'bottom-left': 'bottom-4 start-4',\n },\n },\n defaultVariants: {\n variant: 'default',\n size: 'md',\n position: 'bottom-center',\n },\n },\n);\n\n// =============================================================================\n// useScrollToBottom Hook\n// =============================================================================\n\nexport interface UseScrollToBottomOptions {\n /** Threshold in pixels from bottom to consider \"at bottom\" */\n threshold?: number;\n /** Scroll behavior */\n behavior?: ScrollBehavior;\n /** Enable auto-scroll mode: tracks whether auto-scroll should fire on content changes */\n autoScroll?: boolean;\n}\n\nexport interface UseScrollToBottomReturn {\n /** Whether the user is at the bottom of the container */\n isAtBottom: boolean;\n /** Scroll to bottom function */\n scrollToBottom: (behavior?: ScrollBehavior) => void;\n /** Ref to attach to the scrollable container */\n containerRef: React.RefObject<HTMLDivElement | null>;\n /** Ref to attach to the scroll anchor element */\n anchorRef: React.RefObject<HTMLDivElement | null>;\n /** Whether auto-scroll should fire (only meaningful when autoScroll option is true) */\n shouldAutoScroll: boolean;\n /** Call when user scrolls manually to disable auto-scroll (re-enables when user scrolls back to bottom) */\n handleUserScroll: () => void;\n /** Trigger an auto-scroll if shouldAutoScroll is true (uses requestAnimationFrame) */\n triggerAutoScroll: () => void;\n}\n\nexport function useScrollToBottom({\n threshold = 50,\n behavior = 'smooth',\n autoScroll: autoScrollEnabled = false,\n}: UseScrollToBottomOptions = {}): UseScrollToBottomReturn {\n const containerRef = React.useRef<HTMLDivElement>(null);\n const anchorRef = React.useRef<HTMLDivElement>(null);\n const [isAtBottom, setIsAtBottom] = React.useState(true);\n const [shouldAutoScroll, setShouldAutoScroll] = React.useState(true);\n\n const scrollToBottom = React.useCallback(\n (overrideBehavior?: ScrollBehavior) => {\n const scrollBehavior = overrideBehavior ?? behavior;\n if (anchorRef.current) {\n anchorRef.current.scrollIntoView({ behavior: scrollBehavior });\n } else if (containerRef.current) {\n containerRef.current.scrollTop = containerRef.current.scrollHeight;\n }\n },\n [behavior],\n );\n\n const checkIsAtBottom = React.useCallback(() => {\n const container = containerRef.current;\n if (!container) return true;\n const { scrollTop, scrollHeight, clientHeight } = container;\n const distanceFromBottom = scrollHeight - scrollTop - clientHeight;\n return distanceFromBottom <= threshold;\n }, [threshold]);\n\n React.useEffect(() => {\n const container = containerRef.current;\n if (!container) return;\n\n const handleScroll = () => {\n const atBottom = checkIsAtBottom();\n setIsAtBottom((prev) => (prev === atBottom ? prev : atBottom));\n if (autoScrollEnabled && atBottom) {\n setShouldAutoScroll((prev) => prev || true);\n }\n };\n\n handleScroll();\n\n container.addEventListener('scroll', handleScroll, { passive: true });\n return () => container.removeEventListener('scroll', handleScroll);\n }, [checkIsAtBottom, autoScrollEnabled]);\n\n React.useEffect(() => {\n const container = containerRef.current;\n if (!container) return;\n const OwnerResizeObserver =\n container.ownerDocument.defaultView?.ResizeObserver;\n if (!OwnerResizeObserver) return;\n\n const resizeObserver = new OwnerResizeObserver(() => {\n const atBottom = checkIsAtBottom();\n setIsAtBottom((prev) => (prev === atBottom ? prev : atBottom));\n });\n\n resizeObserver.observe(container);\n return () => resizeObserver.disconnect();\n }, [checkIsAtBottom]);\n\n const handleUserScroll = React.useCallback(() => {\n if (!checkIsAtBottom()) {\n setShouldAutoScroll(false);\n }\n }, [checkIsAtBottom]);\n\n const triggerAutoScroll = React.useCallback(() => {\n if (autoScrollEnabled && shouldAutoScroll) {\n const ownerWindow =\n anchorRef.current?.ownerDocument.defaultView ??\n containerRef.current?.ownerDocument.defaultView;\n ownerWindow?.requestAnimationFrame(() => {\n scrollToBottom('smooth');\n });\n }\n }, [autoScrollEnabled, shouldAutoScroll, scrollToBottom]);\n\n return {\n isAtBottom,\n scrollToBottom,\n containerRef,\n anchorRef,\n shouldAutoScroll,\n handleUserScroll,\n triggerAutoScroll,\n };\n}\n\n// =============================================================================\n// Main AIScrollButton Component\n// =============================================================================\n\nexport interface AIScrollButtonProps\n extends VariantProps<typeof scrollButtonVariants> {\n /** Target scroll element ref */\n scrollRef?: React.RefObject<HTMLElement | null>;\n /** Scrollable container ref */\n containerRef?: React.RefObject<HTMLElement | null>;\n /** Threshold in pixels from bottom to show button */\n threshold?: number;\n /** Click handler (defaults to scrolling to bottom) */\n onClick?: () => void;\n /** Whether to show the button (controlled) */\n visible?: boolean;\n /** Label for accessibility */\n label?: string;\n /** Show unread count badge */\n unreadCount?: number;\n /** Additional class name */\n className?: string;\n}\n\nfunction getIconSize(size: AIScrollButtonProps['size']): string {\n switch (size) {\n case 'sm':\n return 'size-4';\n case 'lg':\n return 'size-6';\n default:\n return 'size-5';\n }\n}\n\nfunction AIScrollButton({\n scrollRef,\n containerRef,\n threshold = 50,\n onClick,\n visible: controlledVisible,\n variant,\n size,\n position,\n label = 'Scroll to bottom',\n unreadCount,\n className,\n}: AIScrollButtonProps) {\n const [internalVisible, setInternalVisible] = React.useState(false);\n\n // Track scroll position if containerRef is provided and no controlled visibility\n React.useEffect(() => {\n if (controlledVisible !== undefined) return;\n\n const container = containerRef?.current;\n if (!container) return;\n\n const handleScroll = () => {\n const { scrollTop, scrollHeight, clientHeight } = container;\n const distanceFromBottom = scrollHeight - scrollTop - clientHeight;\n setInternalVisible(distanceFromBottom > threshold);\n };\n\n handleScroll();\n container.addEventListener('scroll', handleScroll, { passive: true });\n return () => container.removeEventListener('scroll', handleScroll);\n }, [containerRef, threshold, controlledVisible]);\n\n const isVisible = controlledVisible ?? internalVisible;\n\n const handleClick = () => {\n if (onClick) {\n onClick();\n } else if (scrollRef?.current) {\n scrollRef.current.scrollIntoView({ behavior: 'smooth' });\n } else if (containerRef?.current) {\n containerRef.current.scrollTop = containerRef.current.scrollHeight;\n }\n };\n\n const iconSize = getIconSize(size);\n\n return (\n <AnimatePresence>\n {isVisible && (\n <motion.div\n data-slot=\"ai-scroll-button\"\n initial={{ opacity: 0, y: 20, scale: 0.9 }}\n animate={{ opacity: 1, y: 0, scale: 1 }}\n exit={{ opacity: 0, y: 20, scale: 0.9 }}\n transition={{ duration: 0.2, ease: [0.4, 0, 0.2, 1] }}\n className={cn(\n scrollButtonVariants({ variant, size, position }),\n 'motion-reduce:transition-none',\n className,\n )}\n >\n <Button\n appearance=\"ghost\"\n variant=\"secondary\"\n size=\"icon\"\n onClick={handleClick}\n className=\"size-full rounded-full\"\n aria-label={label}\n >\n <ArrowDown\n className={cn(\n iconSize,\n variant === 'primary'\n ? 'text-primary-foreground'\n : 'text-muted-foreground',\n )}\n />\n </Button>\n\n {/* Unread count badge */}\n {unreadCount !== undefined && unreadCount > 0 && (\n <motion.div\n initial={{ scale: 0 }}\n animate={{ scale: 1 }}\n transition={{ type: 'spring', stiffness: 500, damping: 30 }}\n className=\"absolute -top-1 -end-1 flex items-center justify-center min-w-[18px] h-[18px] px-1 rounded-full bg-destructive text-destructive-foreground text-xs font-medium motion-reduce:transition-none\"\n aria-label={`${unreadCount > 99 ? '99+' : unreadCount} new messages`}\n >\n {unreadCount > 99 ? '99+' : unreadCount}\n </motion.div>\n )}\n </motion.div>\n )}\n </AnimatePresence>\n );\n}\n\nAIScrollButton.displayName = 'AIScrollButton';\n\n// =============================================================================\n// Scroll Anchor Component\n// =============================================================================\n\nexport interface AIScrollAnchorProps {\n /** Ref to expose for scrolling */\n ref?: React.Ref<HTMLDivElement>;\n /** Additional class name */\n className?: string;\n}\n\nconst AIScrollAnchor = React.forwardRef<HTMLDivElement, AIScrollAnchorProps>(\n ({ className }, ref) => {\n return (\n <div ref={ref} className={cn('h-px w-full', className)} aria-hidden />\n );\n },\n);\n\nAIScrollAnchor.displayName = 'AIScrollAnchor';\n\nexport { AIScrollAnchor, AIScrollButton, scrollButtonVariants };\n"],"mappings":"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"}
|
package/dist/wc-react/Badge.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { f as
|
|
1
|
+
import { f as a } from "./_shared.js";
|
|
2
2
|
import { t as N } from "./x.js";
|
|
3
3
|
import { t as w } from "./dist.js";
|
|
4
4
|
import { forwardRef as k } from "react";
|
|
5
|
-
import { jsx as
|
|
5
|
+
import { jsx as o, jsxs as d } from "react/jsx-runtime";
|
|
6
6
|
var z = w("inline-flex items-center justify-center gap-1.5 font-medium transition-colors whitespace-nowrap shrink-0 [&>svg]:pointer-events-none [&>svg]:shrink-0", {
|
|
7
7
|
variants: {
|
|
8
8
|
variant: {
|
|
@@ -55,22 +55,22 @@ var z = w("inline-flex items-center justify-center gap-1.5 font-medium transitio
|
|
|
55
55
|
{
|
|
56
56
|
variant: "solid",
|
|
57
57
|
color: "info",
|
|
58
|
-
className: "bg-info text-
|
|
58
|
+
className: "bg-info text-info-foreground hover:bg-info/90"
|
|
59
59
|
},
|
|
60
60
|
{
|
|
61
61
|
variant: "solid",
|
|
62
62
|
color: "success",
|
|
63
|
-
className: "bg-success text-
|
|
63
|
+
className: "bg-success text-success-foreground hover:bg-success/90"
|
|
64
64
|
},
|
|
65
65
|
{
|
|
66
66
|
variant: "solid",
|
|
67
67
|
color: "warning",
|
|
68
|
-
className: "bg-warning text-
|
|
68
|
+
className: "bg-warning text-warning-foreground hover:bg-warning/90"
|
|
69
69
|
},
|
|
70
70
|
{
|
|
71
71
|
variant: "solid",
|
|
72
72
|
color: "destructive",
|
|
73
|
-
className: "bg-destructive text-
|
|
73
|
+
className: "bg-destructive text-destructive-foreground hover:bg-destructive/90"
|
|
74
74
|
},
|
|
75
75
|
{
|
|
76
76
|
variant: "soft",
|
|
@@ -269,7 +269,7 @@ var z = w("inline-flex items-center justify-center gap-1.5 font-medium transitio
|
|
|
269
269
|
size: "sm",
|
|
270
270
|
shape: "round"
|
|
271
271
|
}
|
|
272
|
-
}),
|
|
272
|
+
}), s = {
|
|
273
273
|
primary: "bg-primary",
|
|
274
274
|
secondary: "bg-muted-foreground",
|
|
275
275
|
info: "bg-info",
|
|
@@ -280,14 +280,14 @@ var z = w("inline-flex items-center justify-center gap-1.5 font-medium transitio
|
|
|
280
280
|
}, C = ({ color: e = "secondary" }) => /* @__PURE__ */ d("span", {
|
|
281
281
|
className: "relative flex size-2 shrink-0",
|
|
282
282
|
"aria-hidden": "true",
|
|
283
|
-
children: [/* @__PURE__ */
|
|
283
|
+
children: [/* @__PURE__ */ o("span", { className: a("absolute inline-flex size-full animate-ping rounded-full opacity-40 motion-reduce:animate-none", s[e] ?? s.secondary) }), /* @__PURE__ */ o("span", { className: a("relative inline-flex size-2 rounded-full", s[e] ?? s.secondary) })]
|
|
284
284
|
}), j = k(({ children: e, leadingIcon: n, trailingIcon: i, avatar: t, iconOnly: l = !1, closable: c = !1, closeLabel: u = "Remove", onClose: v, className: p, variant: f = "soft", color: g = "secondary", size: m = "sm", shape: b = "round", ...y }, x) => {
|
|
285
|
-
const
|
|
285
|
+
const r = f === "dot", h = a((t || n || r) && "ps-1.5", (i || c) && "pe-1", l && "px-1.5");
|
|
286
286
|
return /* @__PURE__ */ d("span", {
|
|
287
287
|
ref: x,
|
|
288
288
|
"data-slot": "badge",
|
|
289
|
-
...
|
|
290
|
-
className:
|
|
289
|
+
...r && { role: "status" },
|
|
290
|
+
className: a(z({
|
|
291
291
|
variant: f,
|
|
292
292
|
color: g,
|
|
293
293
|
size: m,
|
|
@@ -295,20 +295,20 @@ var z = w("inline-flex items-center justify-center gap-1.5 font-medium transitio
|
|
|
295
295
|
}), h, p),
|
|
296
296
|
...y,
|
|
297
297
|
children: [
|
|
298
|
-
|
|
299
|
-
t && !
|
|
298
|
+
r && /* @__PURE__ */ o(C, { color: g ?? "secondary" }),
|
|
299
|
+
t && !r && /* @__PURE__ */ o("span", {
|
|
300
300
|
className: "shrink-0 -ms-0.5 [&>*]:size-4 [&>*]:rounded-full",
|
|
301
301
|
children: t
|
|
302
302
|
}),
|
|
303
|
-
n && !t && !
|
|
303
|
+
n && !t && !r && n,
|
|
304
304
|
e,
|
|
305
305
|
i && !c && i,
|
|
306
|
-
c && /* @__PURE__ */
|
|
306
|
+
c && /* @__PURE__ */ o("button", {
|
|
307
307
|
type: "button",
|
|
308
308
|
onClick: v,
|
|
309
309
|
className: "group/close relative shrink-0 rounded-full hover:bg-current/10 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 -me-0.5 p-0.5 before:absolute before:-inset-3.5 before:content-['']",
|
|
310
310
|
"aria-label": u,
|
|
311
|
-
children: /* @__PURE__ */
|
|
311
|
+
children: /* @__PURE__ */ o(N, { className: "size-3 transition-transform duration-150 ease-out group-hover/close:rotate-90 motion-reduce:transition-none" })
|
|
312
312
|
})
|
|
313
313
|
]
|
|
314
314
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Badge.js","names":[],"sources":["../../src/components/atoms/display/Badge/Badge.tsx"],"sourcesContent":["import { cva, type VariantProps } from 'class-variance-authority';\nimport { X } from 'lucide-react';\nimport { forwardRef } from 'react';\nimport { cn } from '@/lib/utils';\n\nconst badgeVariants = cva(\n 'inline-flex items-center justify-center gap-1.5 font-medium transition-colors whitespace-nowrap shrink-0 [&>svg]:pointer-events-none [&>svg]:shrink-0',\n {\n variants: {\n variant: {\n solid: '',\n soft: '',\n outline: 'border',\n white:\n 'bg-opacity-white-80 transition-opacity hover:opacity-80 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-current/50',\n dot: 'bg-transparent text-muted-foreground',\n },\n color: {\n primary: '',\n secondary: '',\n info: '',\n success: '',\n warning: '',\n destructive: '',\n gray: '',\n cyan: '',\n teal: '',\n green: '',\n blue: '',\n indigo: '',\n purple: '',\n pink: '',\n orange: '',\n yellow: '',\n },\n size: {\n xs: 'h-[18px] px-1.5 py-0.5 text-[10px] [&>svg]:size-2.5',\n sm: 'h-5 px-2 py-0.5 text-xs [&>svg]:size-3',\n md: 'h-[22px] px-2.5 py-1 text-xs [&>svg]:size-3.5',\n lg: 'h-[26px] px-3 py-1.5 text-sm [&>svg]:size-4',\n },\n shape: {\n round: 'rounded-full',\n rounded: 'rounded-sm',\n },\n },\n compoundVariants: [\n // Solid variants\n {\n variant: 'solid',\n color: 'primary',\n className: 'bg-primary text-primary-foreground hover:bg-primary/90',\n },\n {\n variant: 'solid',\n color: 'secondary',\n className:\n 'bg-secondary text-secondary-foreground hover:bg-secondary/90',\n },\n {\n variant: 'solid',\n color: 'info',\n className: 'bg-info text-primary-foreground hover:bg-info/90',\n },\n {\n variant: 'solid',\n color: 'success',\n className: 'bg-success text-primary-foreground hover:bg-success/90',\n },\n {\n variant: 'solid',\n color: 'warning',\n className: 'bg-warning text-primary-foreground hover:bg-warning/90',\n },\n {\n variant: 'solid',\n color: 'destructive',\n className:\n 'bg-destructive text-primary-foreground hover:bg-destructive/90',\n },\n\n // Soft variants\n {\n variant: 'soft',\n color: 'primary',\n className:\n 'bg-soft-primary text-soft-primary-foreground hover:bg-opacity-primary-20 dark:bg-soft-primary dark:text-soft-primary-foreground',\n },\n {\n variant: 'soft',\n color: 'secondary',\n className:\n 'bg-soft-secondary text-soft-secondary-foreground hover:bg-opacity-secondary-20 dark:bg-soft-secondary dark:text-soft-secondary-foreground',\n },\n {\n variant: 'soft',\n color: 'info',\n className:\n 'bg-soft-info text-soft-info-foreground hover:bg-opacity-info-20 dark:bg-soft-info dark:text-soft-info-foreground',\n },\n {\n variant: 'soft',\n color: 'success',\n className:\n 'bg-soft-success text-soft-success-foreground hover:bg-opacity-success-20 dark:bg-soft-success dark:text-soft-success-foreground',\n },\n {\n variant: 'soft',\n color: 'warning',\n className:\n 'bg-soft-warning text-soft-warning-foreground hover:bg-opacity-warning-20 dark:bg-soft-warning dark:text-soft-warning-foreground',\n },\n {\n variant: 'soft',\n color: 'destructive',\n className:\n 'bg-soft-destructive text-soft-destructive-foreground hover:bg-opacity-destructive-20 dark:bg-soft-destructive dark:text-soft-destructive-foreground',\n },\n {\n variant: 'soft',\n color: 'gray',\n className:\n 'bg-soft-gray text-soft-gray-foreground hover:bg-opacity-neutral-20 dark:bg-soft-gray dark:text-soft-gray-foreground',\n },\n {\n variant: 'soft',\n color: 'cyan',\n className:\n 'bg-soft-cyan text-soft-cyan-foreground hover:bg-opacity-info-20 dark:bg-soft-cyan dark:text-soft-cyan-foreground',\n },\n {\n variant: 'soft',\n color: 'teal',\n className:\n 'bg-soft-primary text-soft-primary-foreground hover:bg-opacity-primary-20 dark:bg-soft-primary dark:text-soft-primary-foreground',\n },\n {\n variant: 'soft',\n color: 'green',\n className:\n 'bg-soft-green text-soft-green-foreground hover:bg-opacity-success-20 dark:bg-soft-green dark:text-soft-green-foreground',\n },\n {\n variant: 'soft',\n color: 'blue',\n className:\n 'bg-soft-blue text-soft-blue-foreground hover:bg-opacity-info-20 dark:bg-soft-blue dark:text-soft-blue-foreground',\n },\n {\n variant: 'soft',\n color: 'indigo',\n className:\n 'bg-soft-indigo text-soft-indigo-foreground hover:bg-opacity-info-20 dark:bg-soft-indigo dark:text-soft-indigo-foreground',\n },\n {\n variant: 'soft',\n color: 'purple',\n className:\n 'bg-soft-purple text-soft-purple-foreground hover:bg-opacity-primary-20 dark:bg-soft-purple dark:text-soft-purple-foreground',\n },\n {\n variant: 'soft',\n color: 'pink',\n className:\n 'bg-soft-pink text-soft-pink-foreground hover:bg-opacity-destructive-20 dark:bg-soft-pink dark:text-soft-pink-foreground',\n },\n {\n variant: 'soft',\n color: 'orange',\n className:\n 'bg-soft-orange text-soft-orange-foreground hover:bg-opacity-warning-20 dark:bg-soft-orange dark:text-soft-orange-foreground',\n },\n {\n variant: 'soft',\n color: 'yellow',\n className:\n 'bg-soft-yellow text-soft-yellow-foreground hover:bg-opacity-warning-20 dark:bg-soft-yellow dark:text-soft-yellow-foreground',\n },\n\n // Outline variants\n {\n variant: 'outline',\n color: 'primary',\n className: 'border-primary text-primary hover:bg-primary/10',\n },\n {\n variant: 'outline',\n color: 'secondary',\n className:\n 'border-border text-secondary-foreground hover:bg-secondary/50',\n },\n {\n variant: 'outline',\n color: 'info',\n className: 'border-info text-info hover:bg-info/10',\n },\n {\n variant: 'outline',\n color: 'success',\n className: 'border-success text-success hover:bg-success/10',\n },\n {\n variant: 'outline',\n color: 'warning',\n className: 'border-warning text-warning hover:bg-warning/10',\n },\n {\n variant: 'outline',\n color: 'destructive',\n className:\n 'border-destructive text-destructive hover:bg-destructive/10',\n },\n\n // White variants\n {\n variant: 'white',\n color: 'primary',\n className: 'text-primary',\n },\n {\n variant: 'white',\n color: 'secondary',\n className: 'text-secondary-foreground',\n },\n {\n variant: 'white',\n color: 'info',\n className: 'text-info',\n },\n {\n variant: 'white',\n color: 'success',\n className: 'text-success',\n },\n {\n variant: 'white',\n color: 'warning',\n className: 'text-warning',\n },\n {\n variant: 'white',\n color: 'destructive',\n className: 'text-destructive',\n },\n {\n variant: 'white',\n color: 'gray',\n className: 'text-soft-gray-foreground',\n },\n {\n variant: 'white',\n color: 'cyan',\n className: 'text-soft-cyan-foreground',\n },\n {\n variant: 'white',\n color: 'teal',\n className: 'text-primary',\n },\n {\n variant: 'white',\n color: 'green',\n className: 'text-soft-green-foreground',\n },\n {\n variant: 'white',\n color: 'blue',\n className: 'text-soft-blue-foreground',\n },\n {\n variant: 'white',\n color: 'indigo',\n className: 'text-soft-indigo-foreground',\n },\n {\n variant: 'white',\n color: 'purple',\n className: 'text-soft-purple-foreground',\n },\n {\n variant: 'white',\n color: 'pink',\n className: 'text-soft-pink-foreground',\n },\n {\n variant: 'white',\n color: 'orange',\n className: 'text-soft-orange-foreground',\n },\n {\n variant: 'white',\n color: 'yellow',\n className: 'text-soft-yellow-foreground',\n },\n ],\n defaultVariants: {\n variant: 'soft',\n color: 'secondary',\n size: 'sm',\n shape: 'round',\n },\n },\n);\n\ntype BadgeColor = NonNullable<VariantProps<typeof badgeVariants>['color']>;\n\n// Dot color mapping for the dot variant\nconst dotColorClasses: Partial<Record<BadgeColor, string>> = {\n primary: 'bg-primary',\n secondary: 'bg-muted-foreground',\n info: 'bg-info',\n success: 'bg-success',\n warning: 'bg-warning',\n destructive: 'bg-destructive',\n cyan: 'bg-soft-cyan-foreground',\n};\n\nexport interface BadgeProps\n extends Omit<React.ComponentProps<'span'>, 'color'>,\n VariantProps<typeof badgeVariants> {\n /** Leading icon displayed before the text */\n leadingIcon?: React.ReactNode;\n /** Trailing icon displayed after the text */\n trailingIcon?: React.ReactNode;\n /** Avatar element to display before the text */\n avatar?: React.ReactNode;\n /** For icon-only badges - no text, just an icon */\n iconOnly?: boolean;\n /** Shows a close button and enables onClose callback */\n closable?: boolean;\n /** Accessible label for the close button */\n closeLabel?: string;\n /** Callback when close button is clicked */\n onClose?: () => void;\n}\n\n/**\n * Dot indicator for the dot variant\n */\nconst BadgeDot = ({ color = 'secondary' }: { color?: BadgeColor }) => (\n <span className=\"relative flex size-2 shrink-0\" aria-hidden=\"true\">\n <span\n className={cn(\n 'absolute inline-flex size-full animate-ping rounded-full opacity-40 motion-reduce:animate-none',\n dotColorClasses[color] ?? dotColorClasses.secondary,\n )}\n />\n <span\n className={cn(\n 'relative inline-flex size-2 rounded-full',\n dotColorClasses[color] ?? dotColorClasses.secondary,\n )}\n />\n </span>\n);\n\nconst Badge = forwardRef<HTMLSpanElement, BadgeProps>(\n (\n {\n children,\n leadingIcon,\n trailingIcon,\n avatar,\n iconOnly = false,\n closable = false,\n closeLabel = 'Remove',\n onClose,\n className,\n variant = 'soft',\n color = 'secondary',\n size = 'sm',\n shape = 'round',\n ...props\n },\n ref,\n ) => {\n const isDot = variant === 'dot';\n\n // Adjust padding for different configurations\n const paddingClasses = cn(\n // Leading content - reduce left padding\n (avatar || leadingIcon || isDot) && 'ps-1.5',\n // Trailing content - reduce right padding\n (trailingIcon || closable) && 'pe-1',\n // Icon only - equal padding\n iconOnly && 'px-1.5',\n );\n\n return (\n <span\n ref={ref}\n data-slot=\"badge\"\n {...(isDot && { role: 'status' })}\n className={cn(\n badgeVariants({ variant, color, size, shape }),\n paddingClasses,\n className,\n )}\n {...props}\n >\n {isDot && <BadgeDot color={color ?? 'secondary'} />}\n\n {avatar && !isDot && (\n <span className=\"shrink-0 -ms-0.5 [&>*]:size-4 [&>*]:rounded-full\">\n {avatar}\n </span>\n )}\n\n {leadingIcon && !avatar && !isDot && leadingIcon}\n\n {children}\n\n {trailingIcon && !closable && trailingIcon}\n\n {closable && (\n <button\n type=\"button\"\n onClick={onClose}\n className=\"group/close relative shrink-0 rounded-full hover:bg-current/10 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 -me-0.5 p-0.5 before:absolute before:-inset-3.5 before:content-['']\"\n aria-label={closeLabel}\n >\n <X className=\"size-3 transition-transform duration-150 ease-out group-hover/close:rotate-90 motion-reduce:transition-none\" />\n </button>\n )}\n </span>\n );\n },\n);\n\nBadge.displayName = 'Badge';\n\nexport { Badge, BadgeDot, badgeVariants };\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Badge.js","names":[],"sources":["../../src/components/atoms/display/Badge/Badge.tsx"],"sourcesContent":["import { cva, type VariantProps } from 'class-variance-authority';\nimport { X } from 'lucide-react';\nimport { forwardRef } from 'react';\nimport { cn } from '@/lib/utils';\n\nconst badgeVariants = cva(\n 'inline-flex items-center justify-center gap-1.5 font-medium transition-colors whitespace-nowrap shrink-0 [&>svg]:pointer-events-none [&>svg]:shrink-0',\n {\n variants: {\n variant: {\n solid: '',\n soft: '',\n outline: 'border',\n white:\n 'bg-opacity-white-80 transition-opacity hover:opacity-80 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-current/50',\n dot: 'bg-transparent text-muted-foreground',\n },\n color: {\n primary: '',\n secondary: '',\n info: '',\n success: '',\n warning: '',\n destructive: '',\n gray: '',\n cyan: '',\n teal: '',\n green: '',\n blue: '',\n indigo: '',\n purple: '',\n pink: '',\n orange: '',\n yellow: '',\n },\n size: {\n xs: 'h-[18px] px-1.5 py-0.5 text-[10px] [&>svg]:size-2.5',\n sm: 'h-5 px-2 py-0.5 text-xs [&>svg]:size-3',\n md: 'h-[22px] px-2.5 py-1 text-xs [&>svg]:size-3.5',\n lg: 'h-[26px] px-3 py-1.5 text-sm [&>svg]:size-4',\n },\n shape: {\n round: 'rounded-full',\n rounded: 'rounded-sm',\n },\n },\n compoundVariants: [\n // Solid variants\n {\n variant: 'solid',\n color: 'primary',\n className: 'bg-primary text-primary-foreground hover:bg-primary/90',\n },\n {\n variant: 'solid',\n color: 'secondary',\n className:\n 'bg-secondary text-secondary-foreground hover:bg-secondary/90',\n },\n {\n variant: 'solid',\n color: 'info',\n className: 'bg-info text-info-foreground hover:bg-info/90',\n },\n {\n variant: 'solid',\n color: 'success',\n className: 'bg-success text-success-foreground hover:bg-success/90',\n },\n {\n variant: 'solid',\n color: 'warning',\n className: 'bg-warning text-warning-foreground hover:bg-warning/90',\n },\n {\n variant: 'solid',\n color: 'destructive',\n className:\n 'bg-destructive text-destructive-foreground hover:bg-destructive/90',\n },\n\n // Soft variants\n {\n variant: 'soft',\n color: 'primary',\n className:\n 'bg-soft-primary text-soft-primary-foreground hover:bg-opacity-primary-20 dark:bg-soft-primary dark:text-soft-primary-foreground',\n },\n {\n variant: 'soft',\n color: 'secondary',\n className:\n 'bg-soft-secondary text-soft-secondary-foreground hover:bg-opacity-secondary-20 dark:bg-soft-secondary dark:text-soft-secondary-foreground',\n },\n {\n variant: 'soft',\n color: 'info',\n className:\n 'bg-soft-info text-soft-info-foreground hover:bg-opacity-info-20 dark:bg-soft-info dark:text-soft-info-foreground',\n },\n {\n variant: 'soft',\n color: 'success',\n className:\n 'bg-soft-success text-soft-success-foreground hover:bg-opacity-success-20 dark:bg-soft-success dark:text-soft-success-foreground',\n },\n {\n variant: 'soft',\n color: 'warning',\n className:\n 'bg-soft-warning text-soft-warning-foreground hover:bg-opacity-warning-20 dark:bg-soft-warning dark:text-soft-warning-foreground',\n },\n {\n variant: 'soft',\n color: 'destructive',\n className:\n 'bg-soft-destructive text-soft-destructive-foreground hover:bg-opacity-destructive-20 dark:bg-soft-destructive dark:text-soft-destructive-foreground',\n },\n {\n variant: 'soft',\n color: 'gray',\n className:\n 'bg-soft-gray text-soft-gray-foreground hover:bg-opacity-neutral-20 dark:bg-soft-gray dark:text-soft-gray-foreground',\n },\n {\n variant: 'soft',\n color: 'cyan',\n className:\n 'bg-soft-cyan text-soft-cyan-foreground hover:bg-opacity-info-20 dark:bg-soft-cyan dark:text-soft-cyan-foreground',\n },\n {\n variant: 'soft',\n color: 'teal',\n className:\n 'bg-soft-primary text-soft-primary-foreground hover:bg-opacity-primary-20 dark:bg-soft-primary dark:text-soft-primary-foreground',\n },\n {\n variant: 'soft',\n color: 'green',\n className:\n 'bg-soft-green text-soft-green-foreground hover:bg-opacity-success-20 dark:bg-soft-green dark:text-soft-green-foreground',\n },\n {\n variant: 'soft',\n color: 'blue',\n className:\n 'bg-soft-blue text-soft-blue-foreground hover:bg-opacity-info-20 dark:bg-soft-blue dark:text-soft-blue-foreground',\n },\n {\n variant: 'soft',\n color: 'indigo',\n className:\n 'bg-soft-indigo text-soft-indigo-foreground hover:bg-opacity-info-20 dark:bg-soft-indigo dark:text-soft-indigo-foreground',\n },\n {\n variant: 'soft',\n color: 'purple',\n className:\n 'bg-soft-purple text-soft-purple-foreground hover:bg-opacity-primary-20 dark:bg-soft-purple dark:text-soft-purple-foreground',\n },\n {\n variant: 'soft',\n color: 'pink',\n className:\n 'bg-soft-pink text-soft-pink-foreground hover:bg-opacity-destructive-20 dark:bg-soft-pink dark:text-soft-pink-foreground',\n },\n {\n variant: 'soft',\n color: 'orange',\n className:\n 'bg-soft-orange text-soft-orange-foreground hover:bg-opacity-warning-20 dark:bg-soft-orange dark:text-soft-orange-foreground',\n },\n {\n variant: 'soft',\n color: 'yellow',\n className:\n 'bg-soft-yellow text-soft-yellow-foreground hover:bg-opacity-warning-20 dark:bg-soft-yellow dark:text-soft-yellow-foreground',\n },\n\n // Outline variants\n {\n variant: 'outline',\n color: 'primary',\n className: 'border-primary text-primary hover:bg-primary/10',\n },\n {\n variant: 'outline',\n color: 'secondary',\n className:\n 'border-border text-secondary-foreground hover:bg-secondary/50',\n },\n {\n variant: 'outline',\n color: 'info',\n className: 'border-info text-info hover:bg-info/10',\n },\n {\n variant: 'outline',\n color: 'success',\n className: 'border-success text-success hover:bg-success/10',\n },\n {\n variant: 'outline',\n color: 'warning',\n className: 'border-warning text-warning hover:bg-warning/10',\n },\n {\n variant: 'outline',\n color: 'destructive',\n className:\n 'border-destructive text-destructive hover:bg-destructive/10',\n },\n\n // White variants\n {\n variant: 'white',\n color: 'primary',\n className: 'text-primary',\n },\n {\n variant: 'white',\n color: 'secondary',\n className: 'text-secondary-foreground',\n },\n {\n variant: 'white',\n color: 'info',\n className: 'text-info',\n },\n {\n variant: 'white',\n color: 'success',\n className: 'text-success',\n },\n {\n variant: 'white',\n color: 'warning',\n className: 'text-warning',\n },\n {\n variant: 'white',\n color: 'destructive',\n className: 'text-destructive',\n },\n {\n variant: 'white',\n color: 'gray',\n className: 'text-soft-gray-foreground',\n },\n {\n variant: 'white',\n color: 'cyan',\n className: 'text-soft-cyan-foreground',\n },\n {\n variant: 'white',\n color: 'teal',\n className: 'text-primary',\n },\n {\n variant: 'white',\n color: 'green',\n className: 'text-soft-green-foreground',\n },\n {\n variant: 'white',\n color: 'blue',\n className: 'text-soft-blue-foreground',\n },\n {\n variant: 'white',\n color: 'indigo',\n className: 'text-soft-indigo-foreground',\n },\n {\n variant: 'white',\n color: 'purple',\n className: 'text-soft-purple-foreground',\n },\n {\n variant: 'white',\n color: 'pink',\n className: 'text-soft-pink-foreground',\n },\n {\n variant: 'white',\n color: 'orange',\n className: 'text-soft-orange-foreground',\n },\n {\n variant: 'white',\n color: 'yellow',\n className: 'text-soft-yellow-foreground',\n },\n ],\n defaultVariants: {\n variant: 'soft',\n color: 'secondary',\n size: 'sm',\n shape: 'round',\n },\n },\n);\n\ntype BadgeColor = NonNullable<VariantProps<typeof badgeVariants>['color']>;\n\n// Dot color mapping for the dot variant\nconst dotColorClasses: Partial<Record<BadgeColor, string>> = {\n primary: 'bg-primary',\n secondary: 'bg-muted-foreground',\n info: 'bg-info',\n success: 'bg-success',\n warning: 'bg-warning',\n destructive: 'bg-destructive',\n cyan: 'bg-soft-cyan-foreground',\n};\n\nexport interface BadgeProps\n extends Omit<React.ComponentProps<'span'>, 'color'>,\n VariantProps<typeof badgeVariants> {\n /** Leading icon displayed before the text */\n leadingIcon?: React.ReactNode;\n /** Trailing icon displayed after the text */\n trailingIcon?: React.ReactNode;\n /** Avatar element to display before the text */\n avatar?: React.ReactNode;\n /** For icon-only badges - no text, just an icon */\n iconOnly?: boolean;\n /** Shows a close button and enables onClose callback */\n closable?: boolean;\n /** Accessible label for the close button */\n closeLabel?: string;\n /** Callback when close button is clicked */\n onClose?: () => void;\n}\n\n/**\n * Dot indicator for the dot variant\n */\nconst BadgeDot = ({ color = 'secondary' }: { color?: BadgeColor }) => (\n <span className=\"relative flex size-2 shrink-0\" aria-hidden=\"true\">\n <span\n className={cn(\n 'absolute inline-flex size-full animate-ping rounded-full opacity-40 motion-reduce:animate-none',\n dotColorClasses[color] ?? dotColorClasses.secondary,\n )}\n />\n <span\n className={cn(\n 'relative inline-flex size-2 rounded-full',\n dotColorClasses[color] ?? dotColorClasses.secondary,\n )}\n />\n </span>\n);\n\nconst Badge = forwardRef<HTMLSpanElement, BadgeProps>(\n (\n {\n children,\n leadingIcon,\n trailingIcon,\n avatar,\n iconOnly = false,\n closable = false,\n closeLabel = 'Remove',\n onClose,\n className,\n variant = 'soft',\n color = 'secondary',\n size = 'sm',\n shape = 'round',\n ...props\n },\n ref,\n ) => {\n const isDot = variant === 'dot';\n\n // Adjust padding for different configurations\n const paddingClasses = cn(\n // Leading content - reduce left padding\n (avatar || leadingIcon || isDot) && 'ps-1.5',\n // Trailing content - reduce right padding\n (trailingIcon || closable) && 'pe-1',\n // Icon only - equal padding\n iconOnly && 'px-1.5',\n );\n\n return (\n <span\n ref={ref}\n data-slot=\"badge\"\n {...(isDot && { role: 'status' })}\n className={cn(\n badgeVariants({ variant, color, size, shape }),\n paddingClasses,\n className,\n )}\n {...props}\n >\n {isDot && <BadgeDot color={color ?? 'secondary'} />}\n\n {avatar && !isDot && (\n <span className=\"shrink-0 -ms-0.5 [&>*]:size-4 [&>*]:rounded-full\">\n {avatar}\n </span>\n )}\n\n {leadingIcon && !avatar && !isDot && leadingIcon}\n\n {children}\n\n {trailingIcon && !closable && trailingIcon}\n\n {closable && (\n <button\n type=\"button\"\n onClick={onClose}\n className=\"group/close relative shrink-0 rounded-full hover:bg-current/10 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 -me-0.5 p-0.5 before:absolute before:-inset-3.5 before:content-['']\"\n aria-label={closeLabel}\n >\n <X className=\"size-3 transition-transform duration-150 ease-out group-hover/close:rotate-90 motion-reduce:transition-none\" />\n </button>\n )}\n </span>\n );\n },\n);\n\nBadge.displayName = 'Badge';\n\nexport { Badge, BadgeDot, badgeVariants };\n"],"mappings":"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"}
|