Update Segmented.tsx

This commit is contained in:
Nate Kelley 2025-02-24 15:32:09 -07:00
parent 7422c25b74
commit c3952d5918
No known key found for this signature in database
GPG Key ID: FD90372AB8D98B4F
1 changed files with 10 additions and 19 deletions

View File

@ -18,7 +18,7 @@ export interface SegmentedItem {
interface SegmentedProps { interface SegmentedProps {
items: SegmentedItem[]; items: SegmentedItem[];
value?: string; value?: string;
onChange?: (value: string) => void; onChange?: (value: SegmentedItem) => void;
className?: string; className?: string;
size?: 'default' | 'large'; size?: 'default' | 'large';
block?: boolean; block?: boolean;
@ -61,10 +61,6 @@ const triggerVariants = cva(
selected: { selected: {
true: 'text-foreground', true: 'text-foreground',
false: 'text-gray-dark hover:text-foreground' false: 'text-gray-dark hover:text-foreground'
},
hovered: {
true: '',
false: ''
} }
} }
} }
@ -82,7 +78,6 @@ export const Segmented = React.forwardRef<HTMLDivElement, SegmentedProps>(
({ items, type = 'track', value, onChange, className, size = 'default', block = false }, ref) => { ({ items, type = 'track', value, onChange, className, size = 'default', block = false }, ref) => {
const tabRefs = React.useRef<Map<string, HTMLButtonElement>>(new Map()); const tabRefs = React.useRef<Map<string, HTMLButtonElement>>(new Map());
const [selectedValue, setSelectedValue] = useState(value || items[0]?.value); const [selectedValue, setSelectedValue] = useState(value || items[0]?.value);
const [hoveredValue, setHoveredValue] = useState<string | null>(null);
const [gliderStyle, setGliderStyle] = useState({ const [gliderStyle, setGliderStyle] = useState({
width: 0, width: 0,
transform: 'translateX(0)' transform: 'translateX(0)'
@ -107,16 +102,19 @@ export const Segmented = React.forwardRef<HTMLDivElement, SegmentedProps>(
} }
}, [selectedValue]); }, [selectedValue]);
const handleValueChange = useMemoizedFn((newValue: string) => { const handleTabClick = useMemoizedFn((value: string) => {
setSelectedValue(newValue); const item = items.find((item) => item.value === value);
onChange?.(newValue); if (item && !item.disabled) {
setSelectedValue(item.value);
onChange?.(item);
}
}); });
return ( return (
<Tabs.Root <Tabs.Root
ref={ref} ref={ref}
value={selectedValue} value={selectedValue}
onValueChange={handleValueChange} onValueChange={handleTabClick}
className={cn(segmentedVariants({ block, type }), height, className)}> className={cn(segmentedVariants({ block, type }), height, className)}>
<motion.div <motion.div
className={cn(gliderVariants({ type }), height)} className={cn(gliderVariants({ type }), height)}
@ -139,10 +137,8 @@ export const Segmented = React.forwardRef<HTMLDivElement, SegmentedProps>(
key={item.value} key={item.value}
item={item} item={item}
selectedValue={selectedValue} selectedValue={selectedValue}
hoveredValue={hoveredValue}
size={size} size={size}
block={block} block={block}
setHoveredValue={setHoveredValue}
tabRefs={tabRefs} tabRefs={tabRefs}
/> />
))} ))}
@ -157,12 +153,10 @@ Segmented.displayName = 'Segmented';
const SegmentedTrigger = React.memo<{ const SegmentedTrigger = React.memo<{
item: SegmentedItem; item: SegmentedItem;
selectedValue: string; selectedValue: string;
hoveredValue: string | null;
size: SegmentedProps['size']; size: SegmentedProps['size'];
block: SegmentedProps['block']; block: SegmentedProps['block'];
setHoveredValue: (value: string | null) => void;
tabRefs: React.MutableRefObject<Map<string, HTMLButtonElement>>; tabRefs: React.MutableRefObject<Map<string, HTMLButtonElement>>;
}>(({ item, selectedValue, hoveredValue, size, block, setHoveredValue, tabRefs }) => { }>(({ item, selectedValue, size, block, tabRefs }) => {
return ( return (
<Tabs.Trigger <Tabs.Trigger
key={item.value} key={item.value}
@ -171,16 +165,13 @@ const SegmentedTrigger = React.memo<{
ref={(el) => { ref={(el) => {
if (el) tabRefs.current.set(item.value, el); if (el) tabRefs.current.set(item.value, el);
}} }}
onMouseEnter={() => !item.disabled && setHoveredValue(item.value)}
onMouseLeave={() => setHoveredValue(null)}
className={cn( className={cn(
'focus-visible:ring-primary focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-2', 'focus-visible:ring-primary focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-2',
triggerVariants({ triggerVariants({
size, size,
block, block,
disabled: item.disabled, disabled: item.disabled,
selected: selectedValue === item.value, selected: selectedValue === item.value
hovered: hoveredValue === item.value
}) })
)}> )}>
{item.icon && <span className={cn('flex items-center text-sm')}>{item.icon}</span>} {item.icon && <span className={cn('flex items-center text-sm')}>{item.icon}</span>}