aura-glass
Version:
A comprehensive glassmorphism design system for React applications with 142+ production-ready components
239 lines (236 loc) • 9.87 kB
JavaScript
'use client';
import { jsxs, jsx } from 'react/jsx-runtime';
import React from 'react';
import * as SelectPrimitive from '@radix-ui/react-select';
import { ChevronDown, Check, ChevronUp } from 'lucide-react';
import '../../primitives/GlassCore.js';
import '../../primitives/glass/GlassAdvanced.js';
import '../../primitives/OptimizedGlassCore.js';
import '../../primitives/glass/OptimizedGlassAdvanced.js';
import '../../primitives/MotionNative.js';
import { MotionFramer } from '../../primitives/motion/MotionFramer.js';
import { cn } from '../../lib/utilsComprehensive.js';
// Main Select Root
const GlassSelect = SelectPrimitive.Root;
// Select Value
const GlassSelectValue = SelectPrimitive.Value;
const GlassSelectTrigger = /*#__PURE__*/React.forwardRef(({
className,
children,
size = "md",
variant = "default",
error = false,
...props
}, ref) => {
const sizeConfig = {
sm: "h-8 glass-px-2 glass-py-1 glass-text-xs",
md: "h-10 glass-px-3 glass-py-2 glass-text-sm",
lg: "h-12 glass-px-4 glass-py-3 glass-text-base"
};
const variantConfig = {
default: cn("bg-background/50 border border-border/20", "focus:border-primary focus:ring-1 focus:ring-primary"),
filled: cn("bg-muted/50 border border-transparent", "focus:bg-background/50 focus:border-primary"),
outlined: cn("bg-transparent border-2 border-border/20", "focus:border-primary"),
minimal: cn("bg-transparent border-0 border-b border-border/20 rounded-none", "focus:border-primary")
};
return jsxs(SelectPrimitive.Trigger, {
"data-glass-component": true,
ref: ref,
className: cn(
// Base styles
"glass-select-trigger group flex w-full items-center justify-between", "glass-radius-lg glass-backdrop-blur-md transition-all duration-200", "text-foreground placeholder:glass-text-secondary", "focus:outline-none focus:ring-offset-2 focus:ring-offset-background", "disabled:cursor-not-allowed disabled:opacity-50", "[&>span]:line-clamp-1",
// Size
sizeConfig[size],
// Variant
variantConfig[variant],
// Error state
error && "border-red-400 focus:border-red-400 focus:ring-red-400", className),
...props,
children: [children, jsx(SelectPrimitive.Icon, {
asChild: true,
children: jsx(ChevronDown, {
className: 'h-4 w-4 opacity-50 transition-transform group-data-[state=open]:rotate-180'
})
})]
});
});
GlassSelectTrigger.displayName = SelectPrimitive.Trigger.displayName;
const GlassSelectContent = /*#__PURE__*/React.forwardRef(({
className,
children,
position = "popper",
variant = "default",
...props
}, ref) => jsx(SelectPrimitive.Portal, {
children: jsx(MotionFramer, {
preset: "scaleIn",
children: jsxs(SelectPrimitive.Content, {
ref: ref,
className: cn(
// Base styles
"glass-select-content relative z-50 max-h-96 min-w-[8rem] overflow-hidden",
// Darker, more legible surface for options
"glass-backdrop-blur-md bg-black/70 ring-1 ring-white/12", "glass-radius-xl shadow-2xl shadow-black/40", "text-foreground",
// Animations
"data-[state=open]:animate-in data-[state=closed]:animate-out", "data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0", "data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95", "data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2", "data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
// Position adjustments
position === "popper" && ["data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1", "data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1"], className),
position: position,
...props,
children: [jsx(GlassSelectScrollUpButton, {}), jsx(SelectPrimitive.Viewport, {
className: cn("glass-p-1", position === "popper" && ["h-[var(--radix-select-trigger-height)] w-full", "min-w-[var(--radix-select-trigger-width)]"]),
children: children
}), jsx(GlassSelectScrollDownButton, {})]
})
})
}));
GlassSelectContent.displayName = SelectPrimitive.Content.displayName;
const GlassSelectItem = /*#__PURE__*/React.forwardRef(({
className,
children,
variant = "default",
...props
}, ref) => {
const variantStyles = {
default: cn("focus:bg-muted/50 focus:text-foreground", "data-[highlighted]:bg-muted/50 data-[highlighted]:text-foreground"),
ghost: cn("focus:bg-primary/10 focus:text-primary", "data-[highlighted]:bg-primary/10 data-[highlighted]:text-primary")
};
return jsxs(SelectPrimitive.Item, {
ref: ref,
className: cn(
// Base styles
"glass-select-item relative flex w-full cursor-pointer select-none items-center", "glass-radius-lg glass-py-2 pl-8 pr-2 glass-text-sm outline-none transition-all duration-150", "data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
// Variant styles
variantStyles[variant], className),
...props,
children: [jsx("span", {
className: 'absolute left-2 glass-flex h-3.5 w-3.5 glass-items-center glass-justify-center',
children: jsx(SelectPrimitive.ItemIndicator, {
children: jsx(Check, {
className: 'h-4 w-4'
})
})
}), jsx(SelectPrimitive.ItemText, {
children: children
})]
});
});
GlassSelectItem.displayName = SelectPrimitive.Item.displayName;
// Glass Select Label
const GlassSelectLabel = /*#__PURE__*/React.forwardRef(({
className,
...props
}, ref) => jsx(SelectPrimitive.Label, {
ref: ref,
className: cn("glass-select-label glass-py-1.5 pl-8 pr-2 glass-text-sm font-semibold glass-text-secondary", className),
...props
}));
GlassSelectLabel.displayName = SelectPrimitive.Label.displayName;
// Glass Select Separator
const GlassSelectSeparator = /*#__PURE__*/React.forwardRef(({
className,
...props
}, ref) => jsx(SelectPrimitive.Separator, {
ref: ref,
className: cn("glass-select-separator -glass-mx-1 glass-my-1 h-px bg-border/20", className),
...props
}));
GlassSelectSeparator.displayName = SelectPrimitive.Separator.displayName;
// Glass Select Scroll Buttons
const GlassSelectScrollUpButton = /*#__PURE__*/React.forwardRef(({
className,
...props
}, ref) => jsx(SelectPrimitive.ScrollUpButton, {
ref: ref,
className: cn("glass-select-scroll-up flex cursor-default items-center justify-center glass-py-1", "glass-text-secondary hover:text-foreground transition-colors", className),
...props,
children: jsx(ChevronUp, {
className: 'h-4 w-4'
})
}));
GlassSelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName;
const GlassSelectScrollDownButton = /*#__PURE__*/React.forwardRef(({
className,
...props
}, ref) => jsx(SelectPrimitive.ScrollDownButton, {
ref: ref,
className: cn("glass-select-scroll-down flex cursor-default items-center justify-center glass-py-1", "glass-text-secondary hover:text-foreground transition-colors", className),
...props,
children: jsx(ChevronDown, {
className: 'h-4 w-4'
})
}));
GlassSelectScrollDownButton.displayName = SelectPrimitive.ScrollDownButton.displayName;
const DEFAULT_SELECT_OPTIONS = [{
value: "option-1",
label: "Option 1"
}, {
value: "option-2",
label: "Option 2"
}, {
value: "option-3",
label: "Option 3"
}];
const GlassSelectCompound = /*#__PURE__*/React.forwardRef(({
options = DEFAULT_SELECT_OPTIONS,
placeholder = "Select an option",
label,
helperText,
className,
triggerClassName,
contentClassName,
size = "md",
variant = "default",
error = false,
...rest
}, ref) => {
const resolvedOptions = React.useMemo(() => {
if (!Array.isArray(options) || options.length === 0) {
return DEFAULT_SELECT_OPTIONS;
}
return options;
}, [options]);
const [value, setValue] = React.useState(resolvedOptions[0]?.value ?? "");
React.useEffect(() => {
if (!resolvedOptions.some(option => option.value === value)) {
setValue(resolvedOptions[0]?.value ?? "");
}
}, [resolvedOptions, value]);
const triggerAriaLabel = typeof label === "string" && label.trim().length > 0 ? label : placeholder;
return jsxs("div", {
ref: ref,
"data-glass-component": true,
className: cn("glass-select-compound flex flex-col glass-gap-2", className),
...rest,
children: [label && jsx("span", {
className: 'glass-text-sm font-medium glass-text-primary',
children: label
}), jsxs(GlassSelect, {
value: value,
onValueChange: setValue,
children: [jsx(GlassSelectTrigger, {
size: size,
variant: variant,
error: error,
className: triggerClassName,
"aria-label": triggerAriaLabel,
children: jsx(GlassSelectValue, {
placeholder: placeholder
})
}), jsx(GlassSelectContent, {
className: contentClassName,
children: resolvedOptions.map(option => jsx(GlassSelectItem, {
value: option.value,
disabled: option.disabled,
children: option.label
}, option.value))
})]
}), helperText && jsx("p", {
className: 'glass-text-xs glass-text-secondary',
children: helperText
})]
});
});
GlassSelectCompound.displayName = "GlassSelectCompound";
export { GlassSelect, GlassSelectCompound, GlassSelectContent, GlassSelectItem, GlassSelectLabel, GlassSelectScrollDownButton, GlassSelectScrollUpButton, GlassSelectSeparator, GlassSelectTrigger, GlassSelectValue, GlassSelect as Select, GlassSelectCompound as SelectCompound, GlassSelectContent as SelectContent, GlassSelectItem as SelectItem, GlassSelectLabel as SelectLabel, GlassSelectScrollDownButton as SelectScrollDownButton, GlassSelectScrollUpButton as SelectScrollUpButton, GlassSelectSeparator as SelectSeparator, GlassSelectTrigger as SelectTrigger, GlassSelectValue as SelectValue, GlassSelectCompound as default };
//# sourceMappingURL=GlassSelectCompound.js.map