Skip to content

Commit

Permalink
fix(c): dropdown fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
brianorwhatever committed Jan 30, 2025
1 parent 041f819 commit 5b6f640
Show file tree
Hide file tree
Showing 5 changed files with 115 additions and 63,372 deletions.
88 changes: 53 additions & 35 deletions src/components/dropdown/Dropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export const Dropdown: React.FC<DropdownProps> = ({
className,
}) => {
const [isOpen, setIsOpen] = React.useState(false);
const [position, setPosition] = React.useState<{ top?: number; bottom?: number; left: number; right: number }>({ left: 0, right: 0 });
const dropdownRef = React.useRef<HTMLDivElement>(null);
const triggerRef = React.useRef<HTMLDivElement>(null);

Expand Down Expand Up @@ -50,6 +51,34 @@ export const Dropdown: React.FC<DropdownProps> = ({
};
}, [variant]);

// Update position when scrolling or resizing
React.useEffect(() => {
if (!isOpen) return;

const updatePosition = () => {
if (!triggerRef.current) return;
const rect = triggerRef.current.getBoundingClientRect();

setPosition({
left: rect.left,
right: window.innerWidth - rect.right,
...(direction === 'down'
? { top: rect.bottom + 8 }
: { bottom: window.innerHeight - rect.top + 8 }
),
});
};

updatePosition();
window.addEventListener('scroll', updatePosition, true);
window.addEventListener('resize', updatePosition);

return () => {
window.removeEventListener('scroll', updatePosition, true);
window.removeEventListener('resize', updatePosition);
};
}, [isOpen, direction]);

const triggerClasses = cn({
"cursor-pointer": true,
"flex items-center gap-1 text-sm font-medium text-gray-600 hover:text-gray-900 dark:text-gray-400 dark:hover:text-gray-200 transition-colors":
Expand All @@ -76,22 +105,6 @@ export const Dropdown: React.FC<DropdownProps> = ({
className
);

// Get position for the dropdown menu
const getDropdownPosition = () => {
if (!triggerRef.current) return {};
const rect = triggerRef.current.getBoundingClientRect();

return {
position: 'fixed' as const,
left: rect.left,
right: window.innerWidth - rect.right,
...(direction === 'down'
? { top: rect.bottom + 8 }
: { bottom: window.innerHeight - rect.top + 8 }
),
};
};

return (
<div className="relative inline-block" ref={dropdownRef}>
<div
Expand All @@ -105,7 +118,8 @@ export const Dropdown: React.FC<DropdownProps> = ({
<div
className={menuClasses}
style={{
...getDropdownPosition(),
position: 'fixed',
...position,
zIndex: ZINDEX.dropdown,
}}
>
Expand All @@ -117,22 +131,26 @@ export const Dropdown: React.FC<DropdownProps> = ({
);
};

export const DropdownItem = React.forwardRef<
HTMLButtonElement,
React.ButtonHTMLAttributes<HTMLButtonElement>
>(({ className, children, ...props }, ref) => (
<button
ref={ref}
className={cn(
"flex w-full items-center px-3 py-2 text-sm",
"text-gray-700 dark:text-gray-200",
"hover:bg-gray-100 dark:hover:bg-gray-800",
"focus:outline-none focus:bg-gray-100 dark:focus:bg-gray-800",
className
)}
{...props}
>
{children}
</button>
));
export interface DropdownItemProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
icon?: React.ReactNode;
}

export const DropdownItem = React.forwardRef<HTMLButtonElement, DropdownItemProps>(
({ className, children, icon, ...props }, ref) => (
<button
ref={ref}
className={cn(
"flex w-full items-center px-3 py-2 text-sm gap-2",
"text-gray-700 dark:text-gray-200",
"hover:bg-gray-100 dark:hover:bg-gray-800",
"focus:outline-none focus:bg-gray-100 dark:focus:bg-gray-800",
className
)}
{...props}
>
{icon}
{children}
</button>
)
);
DropdownItem.displayName = "DropdownItem";
62 changes: 62 additions & 0 deletions src/docs/pages/components/DropdownPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,68 @@ const MyComponent = () => (
</ComponentDemo>
</div>
</section>

<ComponentDemo
title="With Images"
description="Dropdown items with images"
code={`<Dropdown trigger={<Button>User Menu</Button>}>
<DropdownItem>
<img
src="/avatars/user1.jpg"
alt="User 1 avatar"
className="h-5 w-5 rounded-full object-cover"
/>
John Doe
</DropdownItem>
<DropdownItem>
<img
src="/avatars/user2.jpg"
alt="User 2 avatar"
className="h-5 w-5 rounded-full object-cover"
/>
Jane Smith
</DropdownItem>
</Dropdown>`}
>
<Dropdown trigger={<Button>User Menu</Button>}>
<DropdownItem>
<img
src="https://github.com/github.png"
alt="GitHub avatar"
className="h-5 w-5 rounded-full object-cover"
/>
GitHub
</DropdownItem>
<DropdownItem>
<img
src="https://avatars.githubusercontent.com/u/6412038?s=200&v=4"
alt="React avatar"
className="h-5 w-5 rounded-full object-cover"
/>
React
</DropdownItem>
</Dropdown>
</ComponentDemo>

<section>
<Title level={3}>DropdownItem Properties</Title>
<div className="mt-4">
<PropsTable
props={[
{
name: "icon",
type: "ReactNode",
description: "Icon element to display",
},
{
name: "className",
type: "string",
description: "Additional CSS classes",
},
]}
/>
</div>
</section>
</div>
);
};
17 changes: 0 additions & 17 deletions tmp/index-7k4560vb.css

This file was deleted.

18 changes: 0 additions & 18 deletions tmp/index-xqc55zjs.css

This file was deleted.

Loading

0 comments on commit 5b6f640

Please sign in to comment.