Skip to content

Commit

Permalink
port navigators to use cva
Browse files Browse the repository at this point in the history
  • Loading branch information
aswinshenoy committed Dec 21, 2023
1 parent 0926578 commit 0b21be1
Show file tree
Hide file tree
Showing 5 changed files with 141 additions and 102 deletions.
69 changes: 32 additions & 37 deletions src/components/HorizontalNavigator/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,12 @@ import React, { useEffect, useMemo, useRef, useState } from 'react';
import clsx from 'clsx';
import { nanoid } from 'nanoid';

import useColors, { ChayaColorType } from '../../hooks/useColors';
import { cva } from '../../utils/cva';
import {
colorVariantMapper, ChayaColorType, EMPTY_COLOR_MAP, BORDER_COLOR_MAP, SOLID_BG_COLOR_MAP,
} from '../../utils/classMaps/colors';

import HorizontalNavigatorItem, { HorizontalNavigatorItemType } from './item';
import HorizontalNavigatorItem, { HorizontalNavigatorItemType, HorizontalNavigatorVariantType } from './item';

export type HorizontalNavigatorProps = {
// id of the navigator
Expand All @@ -19,13 +22,31 @@ export type HorizontalNavigatorProps = {
// key of the active item. If null, no item will be active.
activeItem?: string | null,
// variant of the navigator. Can be 'pill' or 'line', defaults to 'pill'
variant?: 'pill' | 'line',
variant?: HorizontalNavigatorVariantType,
// color of the navigator.
color?: ChayaColorType,
// callback when an item is clicked. Passes the key and the item as arguments.
onClickItem?: (key: string, item: HorizontalNavigatorItemType) => void,
};

const activeMarkerClassName = cva({
base: [
'dsr-absolute dsr-left-0 dsr-rounded-lg',
'dsr-transition-all dsr-ease-in-out',
],
variants: {
variant: {
line: 'horizontal-navigator-underline dsr-border-2 dsr-w-full dsr-bottom-0',
pill: 'horizontal-navigator-pill dsr-shadow-lg dsr-z-[500] dsr-top-0',
},
color: EMPTY_COLOR_MAP,
},
compoundVariants: [
...colorVariantMapper<HorizontalNavigatorVariantType>([BORDER_COLOR_MAP], 'line'),
...colorVariantMapper<HorizontalNavigatorVariantType>([SOLID_BG_COLOR_MAP], 'pill'),
],
});

const HorizontalNavigator = ({
id, items, variant = 'pill', color = 'primary',
className, itemClassName, activeItem, onClickItem = () => {},
Expand All @@ -34,8 +55,6 @@ const HorizontalNavigator = ({
const navigatorID = useMemo(() => id || `horizontal-navigator-${nanoid()}`, [id]);
const tabRef = useRef<HTMLUListElement>(null);

const { backgroundColor } = useColors('solid', color);

const [indicatorStyle, setIndicatorStyle] = useState<{
width: number | null,
height: number | null,
Expand Down Expand Up @@ -64,37 +83,6 @@ const HorizontalNavigator = ({
updateIndicator();
}
}, [activeItem]);

const underlineRenderer = (
<div
className={clsx([
'horizontal-navigator-underline dsr-transition-all dsr-ease-in-out dsr-absolute',
'dsr-border-2 dsr-rounded-lg dsr-left-0',
'dsr-bottom-0 dsr-w-full',
])}
style={{
transform: `${indicatorStyle?.translateY ? `translateY(${indicatorStyle?.translateY}px)` : ''} ${indicatorStyle?.translateX ? `translateX(${indicatorStyle?.translateX}px)` : ''}`,
width: indicatorStyle?.width || 0,
height: indicatorStyle?.height || 0,
borderColor: backgroundColor,
}}
/>
);

const highlightRenderer = (
<div
className={clsx([
'horizontal-navigator-highlight dsr-transition-all dsr-ease-in-out dsr-shadow-lg dsr-rounded-lg',
'dsr-absolute dsr-top-0 dsr-left-0 dsr-z-[500]',
])}
style={{
transform: `translateY(${indicatorStyle?.translateY}px) translateX(${indicatorStyle?.translateX}px)`,
width: indicatorStyle?.width || 0,
height: indicatorStyle?.height || 0,
backgroundColor,
}}
/>
);

return (
<div
Expand Down Expand Up @@ -129,7 +117,14 @@ const HorizontalNavigator = ({
/>
))}
</ul>
{variant === 'line' ? underlineRenderer : highlightRenderer}
<div
className={activeMarkerClassName({ variant: variant, color: color })}
style={{
transform: `${indicatorStyle?.translateY ? `translateY(${indicatorStyle?.translateY}px)` : ''} ${indicatorStyle?.translateX ? `translateX(${indicatorStyle?.translateX}px)` : ''}`,
width: indicatorStyle?.width || 0,
height: indicatorStyle?.height || 0,
}}
/>
</div>
);

Expand Down
54 changes: 27 additions & 27 deletions src/components/HorizontalNavigator/item.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@ import { cva } from '../../utils/cva';
import { LinkWrapper } from '../../utils/misc';
import Icon, { IconInputType } from '../Icon';
import Badge, { BaseBadgeProps } from '../Badge';
import { colorVariantMapper, ChayaColorType, MINIMAL_BG_COLOR_MAP, TEXT_COLOR_MAP } from '../../utils/classMaps/colors';
import {
colorVariantMapper, ChayaColorType,
MINIMAL_BG_COLOR_MAP, TEXT_COLOR_MAP, EMPTY_COLOR_MAP,
} from '../../utils/classMaps/colors';

export type HorizontalNavigatorItemType = {
key: string,
Expand Down Expand Up @@ -35,35 +38,34 @@ export type HorizontalNavigatorItemProps = {
onClickItem?: (key: string, item: HorizontalNavigatorItemType) => void,
};

const buttonClassNames = cva({
variants: {
variant: {
pill: 'dsr-px-5 dsr-py-2',
line: 'dsr-py-1 dsr-px-3',
},
},
});

const HorizontalNavigatorItem = ({
item, activeItem, badgeProps, variant = 'pill', className, navigatorID, onClickItem = () => {}, color = 'primary',
}: HorizontalNavigatorItemProps) => {


const liClassNames = cva({
base: [
'dsr-outline-1 focus-visible:dsr-outline dsr-duration-200 dsr-transition',
'dsr-outline-1 focus-visible:dsr-outline dsr-duration-200 dsr-transition dsr-text-color',
'dsr-rounded-lg dsr-transition-background dsr-outline-2 dsr-no-underline',
item?.isDisabled && 'dsr-opacity-60 dsr-cursor-not-allowed',
activeItem === item.key && 'active dsr-font-semibold',
],
variants: {
color: {
primary: '',
secondary: '',
success: '',
warning: '',
danger: '',
shade: '',
contrast: '',
white: '',
black: '',
},
color: EMPTY_COLOR_MAP,
variant: {
pill: [
'border border-neutral-300/20 ',
activeItem === item.key && 'dsr-text-primaryTextColor',
activeItem !== item.key && !item?.isDisabled && 'hover:dsr-bg-neutral-50/80 dark:hover:dsr-bg-neutral-800/80',
activeItem !== item.key && !item?.isDisabled && 'hover:dsr-bg-neutral-50/80 dark:hover:dsr-bg-neutral-500/80',
],
line: [
'dsr-transition-all dsr-rounded-lg dsr-gap-2 dsr-border-0 dsr-mb-2',
Expand All @@ -74,20 +76,19 @@ const HorizontalNavigatorItem = ({
compoundVariants: [
...(activeItem === item.key ? colorVariantMapper<HorizontalNavigatorVariantType>([MINIMAL_BG_COLOR_MAP, TEXT_COLOR_MAP], 'line') : []),
{
variant: 'pill',
color: 'white',
class: activeItem === item.key ? 'dsr-text-neutral-900 dsr-bg-neutral-50/80 dark:dsr-bg-neutral-800/80' : '',
variant: 'pill', color: 'white',
className: [
'dark:dsr-text-neutral-100',
activeItem === item.key && 'dsr-text-neutral-900 dsr-bg-neutral-50/80 dark:dsr-bg-neutral-100/80 dark:dsr-text-neutral-900',
],
},
],
});

const buttonClassNames = cva({
variants: {
variant: {
pill: 'dsr-px-5 dsr-py-2',
line: 'dsr-py-1 dsr-px-3',
{
variant: 'pill', color: 'contrast',
className: [
activeItem === item.key && 'dsr-text-neutral-100 dark:dsr-text-neutral-900',
],
},
},
],
});

const renderOption = (item: HorizontalNavigatorItemType) => (
Expand Down Expand Up @@ -138,7 +139,6 @@ const HorizontalNavigatorItem = ({
key={item?.key ? `tab_selector_${item?.key}` : nanoid()}
role="presentation"
className={clsx([
color === 'white' && variant === 'pill' ? 'dsr-text-neutral-900' : 'dsr-text-color',
liClassNames({ color, variant }),
className, item.className,
])}
Expand Down
65 changes: 40 additions & 25 deletions src/components/VerticalNavigator/Item.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@ import { LinkWrapper } from '../../utils/misc';
import Icon, { IconInputType } from '../Icon';
import Badge, { BaseBadgeProps } from '../Badge';
import ChevronUp from '../../utils/icons/chevron-up';
import useColors, { ChayaColorType } from '../../hooks/useColors';
import { cva } from '../../utils/cva';
import {
ChayaColorType, colorMapper,
EMPTY_COLOR_MAP, MINIMAL_BG_COLOR_MAP, SOLID_TEXT_COLOR_MAP, TEXT_COLOR_MAP,
} from '../../utils/classMaps/colors';

export type VerticalNavigatorItemBaseType = {
key: string,
Expand All @@ -26,6 +30,8 @@ export type VerticalNavigatorItemType = VerticalNavigatorItemBaseType & {
items?: VerticalNavigatorItemBaseType[]
};

export type VerticalNavigatorVariantType = 'pill' | 'line';

export type VerticalNavigatorItemProps = {
item: VerticalNavigatorItemType,
className?: string,
Expand All @@ -46,9 +52,6 @@ const VerticalNavigatorItem = ({
const [height, setHeight] = useState<undefined | number>(undefined);
const dropdownContentRef = useRef<HTMLLIElement>(null);

const { backgroundColor, activeColor } = useColors('minimal', color);
const { textColor } = useColors('solid', color);

const [dropdownVisibility, setDropdownVisibility] = useState(defaultExpansion);

useEffect(() => setDropdownVisibility(!isCollapsed), [isCollapsed]);
Expand All @@ -66,18 +69,39 @@ const VerticalNavigatorItem = ({
'dsr-flex dsr-justify-between dsr-items-center dsr-transition dsr-w-full', className,
]);

const innerContent = (item: VerticalNavigatorItemBaseType, hasChildren: boolean = false, isChild: boolean = false) => (
const innerContentClassName = cva({
base: [
'dsr-flex dsr-w-full dsr-items-center dsr-gap-2 dsr-text-color dsr-py-1.5 dsr-px-1',
isCollapsed ? 'dsr-justify-center' : 'dsr-justify-between',
],
variants: {
variant: {
line: 'dsr-transition-all dsr-rounded-r-lg dsr-gap-2',
pill: '',
},
color: EMPTY_COLOR_MAP,
state: {
active: '',
inactive: '',
},
},
compoundVariants: [
...colorMapper<{ variant: VerticalNavigatorVariantType, state: 'active' | 'inactive' }>([SOLID_TEXT_COLOR_MAP], { variant: 'pill', state: 'active' }),
...colorMapper<{ variant: VerticalNavigatorVariantType, state: 'active' | 'inactive' }>([MINIMAL_BG_COLOR_MAP, TEXT_COLOR_MAP], { variant: 'line', state: 'active' }),
{
variant: 'line',
color: 'white',
className: activeItem === item.key ? 'dark:dsr-bg-neutral-100/80' : '',
},
],
});

const innerContent = (item: VerticalNavigatorItemBaseType, isChild: boolean = false) => (
<div
className={clsx([
'dsr-flex dsr-w-full dsr-items-center dsr-gap-2 dsr-py-1.5 dsr-px-1',
variant === 'line' && 'dsr-transition-all dsr-rounded-r-lg dsr-gap-2',
innerContentClassName({ variant, color, state: activeItem === item.key ? 'active' : 'inactive' }),
activeItem === item.key && (!isChild || dropdownVisibility) && 'active dsr-font-semibold',
isCollapsed ? 'dsr-justify-center' : 'dsr-justify-between',
])}
style={{
background: (variant === 'line' && activeItem === item.key && !hasChildren) ? backgroundColor : undefined,
color: (variant === 'line' && activeItem === item.key) ? color === 'white' ? textColor : activeColor : undefined,
}}
>
<div className="dsr-flex dsr-items-center dsr-gap-2 dsr-px-1 dst-text-lg dsr-text-left">
{item.icon && (
Expand Down Expand Up @@ -108,7 +132,7 @@ const VerticalNavigatorItem = ({
]);

const contentRenderer = (item: VerticalNavigatorItemBaseType, isChild: boolean = false) => item?.link ?
LinkWrapper(item.link, innerContent(item, false, isChild), {
LinkWrapper(item.link, innerContent(item, isChild), {
role: item.role ?? 'tab',
className: clsx([
commonClasses,
Expand All @@ -129,7 +153,7 @@ const VerticalNavigatorItem = ({
(isChild && variant === 'line') && 'dsr-my-0.5',
])}
>
{innerContent(item, false, isChild)}
{innerContent(item, isChild)}
</button>
);

Expand All @@ -151,11 +175,11 @@ const VerticalNavigatorItem = ({
])}
onClick={() => setDropdownVisibility(!dropdownVisibility)}
>
<span className="dsr-flex dsr-items-center dsr-gap-2.5">{innerContent(item, true, false)}</span>
<span className="dsr-flex dsr-items-center dsr-gap-2.5">{innerContent(item)}</span>
{!isCollapsed && (
<span
className={clsx([
'dsr-transform dsr-transition-transform dsr-mr-2 dsr-opacity-80',
'dsr-transform dsr-transition-transform dsr-mr-2 dsr-opacity-80 dsr-text-color',
!dropdownVisibility ? 'dsr-rotate-180' : '',
])}
>
Expand Down Expand Up @@ -188,13 +212,7 @@ const VerticalNavigatorItem = ({
<li
className={clsx([
liClass, 'dsr-rounded-l-none dsr-rounded-r-lg',
variant === 'line' && 'dsr-border-l-4 dsr-border-gray-500/20',
variant === 'pill' && activeItem === subItem.key ? 'dsr-text-primaryTextColor hover:dsr-bg-neutral-900/30' : 'hover:dsr-bg-neutral-300/20',
])}
style={{
borderColor: variant === 'line' && activeItem === subItem.key ? activeColor : undefined,
color: variant === 'pill' && activeItem === subItem.key ? textColor : undefined,
}}
key={item.key + subItem.key}
>
{contentRenderer(subItem, true)}
Expand All @@ -216,9 +234,6 @@ const VerticalNavigatorItem = ({
variant === 'pill' && 'hover:dsr-bg-neutral-900/30',
]) : 'hover:dsr-bg-neutral-300/20',
])}
style={{
color: (activeItem === item.key && variant === 'pill') ? textColor : undefined,
}}
key={item.key}
>
{contentRenderer(item)}
Expand Down
Loading

0 comments on commit 0b21be1

Please sign in to comment.