Files
maher 703f50a09d
Some checks failed
Build / run (push) Has been cancelled
first commit
2025-10-29 11:42:25 +01:00

112 lines
2.7 KiB
TypeScript
Executable File

import React, {JSXElementConstructor, ReactNode, useContext} from 'react';
import clsx from 'clsx';
import {useFocusManager} from '@react-aria/focus';
import {TabContext} from './tabs-context';
import {LinkProps} from 'react-router-dom';
export interface TabProps {
className?: string;
index?: number;
children: ReactNode;
isDisabled?: boolean;
padding?: string;
elementType?: 'button' | 'a' | JSXElementConstructor<any>;
to?: LinkProps['to'];
relative?: LinkProps['relative'];
replace?: LinkProps['replace'];
width?: string;
}
export function Tab({
index,
className,
isDisabled,
children,
padding: paddingProp,
elementType = 'button',
to,
relative,
width = 'min-w-min',
}: TabProps) {
const {
selectedTab,
setSelectedTab,
tabsRef,
size = 'md',
id,
} = useContext(TabContext);
const isSelected = index === selectedTab;
const focusManager = useFocusManager();
const padding = paddingProp || (size === 'sm' ? 'px-12' : 'px-18');
const mergedClassname = clsx(
'tracking-wide overflow-hidden capitalize text-sm flex items-center justify-center outline-none transition-colors',
'focus-visible:ring focus-visible:ring-2 ring-inset rounded whitespace-nowrap cursor-pointer',
width,
textColor({isDisabled, isSelected}),
className,
size === 'md' && `${padding} h-48`,
size === 'sm' && `${padding} h-32`,
isDisabled && 'pointer-events-none',
);
const onKeyDown = (e: React.KeyboardEvent<HTMLButtonElement>) => {
switch (e.key) {
case 'ArrowLeft':
focusManager?.focusPrevious();
break;
case 'ArrowRight':
focusManager?.focusNext();
break;
case 'Home':
focusManager?.focusFirst();
break;
case 'End':
focusManager?.focusLast();
break;
}
};
const tabIndex = isSelected ? 0 : -1;
const Element = elementType;
return (
<Element
disabled={isDisabled}
id={`${id}-${index}-tab`}
aria-controls={`${id}-${index}-tabpanel`}
type="button"
role="tab"
aria-selected={isSelected}
tabIndex={isDisabled ? undefined : tabIndex}
onKeyDown={onKeyDown}
onClick={() => {
setSelectedTab(index!);
}}
to={to}
relative={relative}
className={mergedClassname}
ref={(el: HTMLElement) => {
if (tabsRef.current && el) {
tabsRef.current[index!] = el;
}
}}
>
{children}
</Element>
);
}
interface TextColorProps {
isDisabled?: boolean;
isSelected: boolean;
}
function textColor({isDisabled, isSelected}: TextColorProps): string {
if (isDisabled) {
return 'text-disabled cursor-default';
}
if (isSelected) {
return 'text-primary';
}
return 'text-muted hover:text-main';
}