Skip to content

Commit

Permalink
feat(sidebaritem): add forwardRef to sidebar item (themesberg#420)
Browse files Browse the repository at this point in the history
Added forwardRef to sidebar item to support Next link

fix themesberg#397
  • Loading branch information
myabeaver authored Nov 1, 2022
1 parent 0afdab7 commit faca797
Showing 1 changed file with 67 additions and 70 deletions.
137 changes: 67 additions & 70 deletions src/lib/components/Sidebar/SidebarItem.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import classNames from 'classnames';
import type { ComponentProps, ElementType, FC, PropsWithChildren } from 'react';
import { useId } from 'react';
import { ComponentProps, ElementType, FC, forwardRef, PropsWithChildren, useId } from 'react';
import { Badge } from '../Badge';
import type { FlowbiteColors } from '../Flowbite/FlowbiteTheme';
import { useTheme } from '../Flowbite/ThemeContext';
import { Tooltip } from '../Tooltip';
import { useSidebarContext } from './SidebarContext';
import { useSidebarItemContext } from './SidebarItemContext';

export interface SidebarItemProps extends PropsWithChildren<ComponentProps<'div'> & Record<string, unknown>> {
export interface SidebarItemProps
extends PropsWithChildren<Omit<ComponentProps<'div'>, 'ref'> & Record<string, unknown>> {
active?: boolean;
as?: ElementType;
href?: string;
Expand All @@ -21,77 +21,74 @@ export interface SidebarItemLabelColors extends Pick<FlowbiteColors, 'gray'> {
[key: string]: string;
}

const SidebarItem: FC<SidebarItemProps> = ({
as: Component = 'a',
children,
icon: Icon,
active: isActive,
label,
labelColor = 'info',
className,
...props
}) => {
const id = useId();
const { isCollapsed } = useSidebarContext();
const { isInsideCollapse } = useSidebarItemContext();
const theme = useTheme().theme.sidebar.item;
const SidebarItem = forwardRef<Element, SidebarItemProps>(
(
{ as: Component = 'a', children, icon: Icon, active: isActive, label, labelColor = 'info', className, ...props },
ref,
) => {
const id = useId();
const { isCollapsed } = useSidebarContext();
const { isInsideCollapse } = useSidebarItemContext();
const theme = useTheme().theme.sidebar.item;

const ListItem: FC<PropsWithChildren> = ({ children: wrapperChildren }) => (
<li>
{isCollapsed ? (
<Tooltip content={<TooltipContent>{children}</TooltipContent>} placement="right">
{wrapperChildren}
</Tooltip>
) : (
wrapperChildren
)}
</li>
);

const TooltipContent: FC<PropsWithChildren> = ({ children }) => <Children>{children}</Children>;
const ListItem: FC<PropsWithChildren> = ({ children: wrapperChildren }) => (
<li>
{isCollapsed ? (
<Tooltip content={<TooltipContent>{children}</TooltipContent>} placement="right">
{wrapperChildren}
</Tooltip>
) : (
wrapperChildren
)}
</li>
);

const Children: FC<PropsWithChildren> = ({ children }) => (
<span
className={classNames(theme.content.base)}
data-testid="flowbite-sidebar-item-content"
id={`flowbite-sidebar-item-${id}`}
>
{children}
</span>
);
const TooltipContent: FC<PropsWithChildren> = ({ children }) => <Children>{children}</Children>;

return (
<ListItem>
<Component
aria-labelledby={`flowbite-sidebar-item-${id}`}
className={classNames(
theme.base,
isActive && theme.active,
!isCollapsed && isInsideCollapse && theme.collapsed.insideCollapse,
className,
)}
{...props}
const Children: FC<PropsWithChildren> = ({ children }) => (
<span
className={classNames(theme.content.base)}
data-testid="flowbite-sidebar-item-content"
id={`flowbite-sidebar-item-${id}`}
>
{Icon && (
<Icon
aria-hidden
className={classNames(theme.icon.base, isActive && theme.icon.active)}
data-testid="flowbite-sidebar-item-icon"
/>
)}
{isCollapsed && !Icon && (
<span className={theme.collapsed.noIcon}>{(children as string).charAt(0).toLocaleUpperCase() ?? '?'}</span>
)}
{!isCollapsed && <Children>{children}</Children>}
{!isCollapsed && label && (
<Badge color={labelColor} data-testid="flowbite-sidebar-label" hidden={isCollapsed}>
{label}
</Badge>
)}
</Component>
</ListItem>
);
};
{children}
</span>
);

return (
<ListItem>
<Component
aria-labelledby={`flowbite-sidebar-item-${id}`}
className={classNames(
theme.base,
isActive && theme.active,
!isCollapsed && isInsideCollapse && theme.collapsed.insideCollapse,
className,
)}
ref={ref}
{...props}
>
{Icon && (
<Icon
aria-hidden
className={classNames(theme.icon.base, isActive && theme.icon.active)}
data-testid="flowbite-sidebar-item-icon"
/>
)}
{isCollapsed && !Icon && (
<span className={theme.collapsed.noIcon}>{(children as string).charAt(0).toLocaleUpperCase() ?? '?'}</span>
)}
{!isCollapsed && <Children>{children}</Children>}
{!isCollapsed && label && (
<Badge color={labelColor} data-testid="flowbite-sidebar-label" hidden={isCollapsed}>
{label}
</Badge>
)}
</Component>
</ListItem>
);
},
);

SidebarItem.displayName = 'Sidebar.Item';
export default SidebarItem;

0 comments on commit faca797

Please sign in to comment.