mirror of
https://gitlab.com/mbugroup/lti-web-client.git
synced 2026-05-21 13:55:45 +00:00
hotfix(FE): fixing dropdown logout and floating button max size
This commit is contained in:
@@ -0,0 +1,116 @@
|
||||
'use client';
|
||||
|
||||
import { ReactNode, useRef, useEffect, useState } from 'react';
|
||||
import { cn } from '@/lib/helper';
|
||||
|
||||
interface DropdownProps {
|
||||
trigger: ReactNode;
|
||||
children: ReactNode;
|
||||
position?:
|
||||
| 'top'
|
||||
| 'bottom'
|
||||
| 'left'
|
||||
| 'right'
|
||||
| 'top-start'
|
||||
| 'top-end'
|
||||
| 'bottom-start'
|
||||
| 'bottom-end'
|
||||
| 'left-start'
|
||||
| 'left-end'
|
||||
| 'right-start'
|
||||
| 'right-end';
|
||||
align?: 'start' | 'center' | 'end';
|
||||
hover?: boolean;
|
||||
className?: string;
|
||||
contentClassName?: string;
|
||||
}
|
||||
|
||||
const Dropdown = ({
|
||||
trigger,
|
||||
children,
|
||||
position = 'bottom',
|
||||
align = 'start',
|
||||
hover = false,
|
||||
className,
|
||||
contentClassName,
|
||||
}: DropdownProps) => {
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const dropdownRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
// Handle click outside to close dropdown
|
||||
useEffect(() => {
|
||||
const handleClickOutside = (event: MouseEvent) => {
|
||||
if (
|
||||
dropdownRef.current &&
|
||||
!dropdownRef.current.contains(event.target as Node)
|
||||
) {
|
||||
setIsOpen(false);
|
||||
}
|
||||
};
|
||||
|
||||
if (isOpen) {
|
||||
document.addEventListener('mousedown', handleClickOutside);
|
||||
}
|
||||
|
||||
return () => {
|
||||
document.removeEventListener('mousedown', handleClickOutside);
|
||||
};
|
||||
}, [isOpen]);
|
||||
|
||||
// Build position classes
|
||||
const getPositionClasses = () => {
|
||||
const classes: string[] = [];
|
||||
|
||||
// Handle combined positions like 'top-start'
|
||||
if (position.includes('-')) {
|
||||
const [pos, al] = position.split('-');
|
||||
classes.push(`dropdown-${pos}`);
|
||||
classes.push(`dropdown-${al}`);
|
||||
} else {
|
||||
classes.push(`dropdown-${position}`);
|
||||
if (align !== 'start') {
|
||||
classes.push(`dropdown-${align}`);
|
||||
}
|
||||
}
|
||||
|
||||
return classes.join(' ');
|
||||
};
|
||||
|
||||
const handleToggle = (e: React.MouseEvent) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
// alert('clicked');
|
||||
setIsOpen(!isOpen);
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={dropdownRef}
|
||||
className={cn(
|
||||
'dropdown',
|
||||
getPositionClasses(),
|
||||
hover && 'dropdown-hover',
|
||||
isOpen && 'dropdown-open',
|
||||
className
|
||||
)}
|
||||
>
|
||||
{/* Trigger Button */}
|
||||
<div onClick={handleToggle} className='cursor-pointer'>
|
||||
{trigger}
|
||||
</div>
|
||||
|
||||
{/* Dropdown Content - Only render when open */}
|
||||
{isOpen && (
|
||||
<div
|
||||
tabIndex={-1}
|
||||
className={cn('dropdown-content z-[10]', contentClassName)}
|
||||
onClick={() => setIsOpen(false)} // Close on item click
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Dropdown;
|
||||
@@ -0,0 +1,83 @@
|
||||
# Dropdown Component
|
||||
|
||||
Komponen Dropdown reusable berdasarkan DaisyUI yang mengatasi issue children component yang ter-render sebelum dropdown dibuka.
|
||||
|
||||
## Features
|
||||
|
||||
- ✅ **Conditional Rendering**: Children hanya di-render ketika dropdown aktif/terbuka
|
||||
- ✅ **Click Outside to Close**: Otomatis menutup dropdown ketika klik di luar area dropdown
|
||||
- ✅ **Multiple Positions**: Support berbagai posisi (top, bottom, left, right) dengan alignment (start, center, end)
|
||||
- ✅ **Hover Support**: Optional hover mode untuk membuka dropdown
|
||||
- ✅ **Customizable**: Mendukung custom className untuk container dan content
|
||||
|
||||
## Usage
|
||||
|
||||
### Basic Example
|
||||
|
||||
```tsx
|
||||
import Dropdown from '@/components/dropdown/Dropdown';
|
||||
import Menu from '@/components/menu/Menu';
|
||||
import MenuItem from '@/components/menu/MenuItem';
|
||||
|
||||
<Dropdown
|
||||
trigger={
|
||||
<button className="btn">Click Me</button>
|
||||
}
|
||||
>
|
||||
<Menu className="p-2 bg-base-100 shadow rounded-box menu-sm w-52">
|
||||
<MenuItem title="Item 1" onClick={() => console.log('Item 1')} />
|
||||
<MenuItem title="Item 2" onClick={() => console.log('Item 2')} />
|
||||
</Menu>
|
||||
</Dropdown>
|
||||
```
|
||||
|
||||
### With Position
|
||||
|
||||
```tsx
|
||||
<Dropdown
|
||||
position="bottom-end"
|
||||
trigger={<button className="btn">Dropdown</button>}
|
||||
contentClassName="w-52 mt-3"
|
||||
>
|
||||
{/* Your content */}
|
||||
</Dropdown>
|
||||
```
|
||||
|
||||
### Hover Mode
|
||||
|
||||
```tsx
|
||||
<Dropdown
|
||||
hover={true}
|
||||
trigger={<button className="btn">Hover Me</button>}
|
||||
>
|
||||
{/* Your content */}
|
||||
</Dropdown>
|
||||
```
|
||||
|
||||
## Props
|
||||
|
||||
| Prop | Type | Default | Description |
|
||||
|------|------|---------|-------------|
|
||||
| `trigger` | `ReactNode` | - | **Required**. Element yang akan men-trigger dropdown |
|
||||
| `children` | `ReactNode` | - | **Required**. Content dropdown yang akan ditampilkan |
|
||||
| `position` | `'top' \| 'bottom' \| 'left' \| 'right' \| 'top-start' \| 'top-end' \| 'bottom-start' \| 'bottom-end' \| 'left-start' \| 'left-end' \| 'right-start' \| 'right-end'` | `'bottom'` | Posisi dropdown relatif terhadap trigger |
|
||||
| `align` | `'start' \| 'center' \| 'end'` | `'start'` | Alignment dropdown (digunakan jika position tidak mengandung alignment) |
|
||||
| `hover` | `boolean` | `false` | Aktifkan mode hover untuk membuka dropdown |
|
||||
| `className` | `string` | - | Custom className untuk container dropdown |
|
||||
| `contentClassName` | `string` | - | Custom className untuk content dropdown |
|
||||
|
||||
## Position Examples
|
||||
|
||||
- `bottom` - Dropdown muncul di bawah, align ke start
|
||||
- `bottom-end` - Dropdown muncul di bawah, align ke end
|
||||
- `bottom-center` - Dropdown muncul di bawah, align ke center
|
||||
- `top-start` - Dropdown muncul di atas, align ke start
|
||||
- `left-end` - Dropdown muncul di kiri, align ke end
|
||||
- Dan seterusnya...
|
||||
|
||||
## Key Benefits
|
||||
|
||||
1. **Performance**: Children tidak di-render sampai dropdown dibuka, menghemat resources
|
||||
2. **Clean State**: Setiap kali dropdown dibuka, children di-render fresh
|
||||
3. **DaisyUI Compatible**: Menggunakan class DaisyUI yang sudah ada
|
||||
4. **Accessible**: Menggunakan proper ARIA attributes dan keyboard navigation
|
||||
Reference in New Issue
Block a user