dropdown ok

This commit is contained in:
2026-04-02 21:40:07 +02:00
parent f0c710f8c2
commit b0629ef3d0
6 changed files with 301 additions and 323 deletions

View File

@@ -1,6 +1,6 @@
# Dropdown
Dropdown component for creating menus, selectors, and action panels that appear when triggered. Supports both array-based items and custom content.
Dropdown component for creating menus that appear when triggered. Uses DaisyUI's native details/summary pattern.
## Tag
@@ -12,11 +12,10 @@ Dropdown component for creating menus, selectors, and action panels that appear
| :--- | :--- | :--- | :--- |
| `label` | `string \| VNode \| Signal` | `-` | Button label or content |
| `icon` | `string \| VNode \| Signal` | `-` | Icon displayed next to label |
| `items` | `Array<MenuItem> \| Signal<Array>` | `-` | Array of menu items (alternative to children) |
| `items` | `Array<MenuItem> \| Signal<Array>` | Required | Array of menu items |
| `class` | `string` | `''` | Additional CSS classes (DaisyUI + Tailwind) |
| `children` | `VNode \| function` | `-` | Custom dropdown content (alternative to items) |
### MenuItem Structure (when using `items`)
### MenuItem Structure
| Property | Type | Description |
| :--- | :--- | :--- |
@@ -43,14 +42,16 @@ Dropdown supports all **daisyUI Dropdown classes**:
Dropdown({
label: "Menu",
class: "dropdown-end dropdown-hover",
items: menuItems
items: [
{ label: "Profile", onclick: () => console.log("Profile") },
{ label: "Settings", onclick: () => console.log("Settings") }
]
});
// Applies: right-aligned, opens on hover
```
## Live Examples
### Basic Dropdown (Items Array)
### Basic Dropdown
<div class="card bg-base-200 border border-base-300 shadow-sm my-6">
<div class="card-body">
@@ -73,7 +74,7 @@ const BasicDemo = () => {
$mount(BasicDemo, '#demo-basic');
```
### With Icons (Items Array)
### With Icons
<div class="card bg-base-200 border border-base-300 shadow-sm my-6">
<div class="card-body">
@@ -98,7 +99,7 @@ const IconsDemo = () => {
$mount(IconsDemo, '#demo-icons');
```
### Action Dropdown (Items Array)
### Action Dropdown
<div class="card bg-base-200 border border-base-300 shadow-sm my-6">
<div class="card-body">
@@ -126,7 +127,7 @@ const ActionsDemo = () => {
$mount(ActionsDemo, '#demo-actions');
```
### User Dropdown (Items Array)
### User Dropdown
<div class="card bg-base-200 border border-base-300 shadow-sm my-6">
<div class="card-body">
@@ -167,7 +168,7 @@ $mount(UserDropdown, '#demo-user');
```javascript
const ReactiveDropdown = () => {
const count = $(0);
$watch(()=>console.log(count()));
const items = () => [
{ label: `Count: ${count()}`, onclick: () => {} },
{ label: 'Increment', onclick: () => count(count() + 1) },
@@ -183,7 +184,7 @@ const ReactiveDropdown = () => {
$mount(ReactiveDropdown, '#demo-reactive');
```
### Notification Dropdown (Custom Children)
### Notification Dropdown
<div class="card bg-base-200 border border-base-300 shadow-sm my-6">
<div class="card-body">
@@ -200,81 +201,34 @@ const NotificationsDropdown = () => {
{ id: 3, title: 'Task completed', time: '2 hours ago', read: true }
]);
const unreadCount = () => notifications().filter(n => !n.read).length;
const markAsRead = (id) => {
notifications(notifications().map(n =>
n.id === id ? { ...n, read: true } : n
));
};
const unreadCount = () => notifications().filter(n => !n.read).length;
return Dropdown({
label: Span({ class: 'relative' }, [
'🔔',
() => unreadCount() > 0 ? Span({ class: 'badge badge-xs badge-error absolute -top-1 -right-2' }, unreadCount()) : null
]),
class: 'dropdown-end',
children: () => Div({ class: 'w-80' }, [
Div({ class: 'p-3 border-b border-base-300 font-bold' }, `Notifications (${unreadCount()} unread)`),
Div({ class: 'max-h-64 overflow-y-auto' }, notifications().map(notif =>
Div({
class: `p-3 border-b border-base-300 cursor-pointer hover:bg-base-200 ${!notif.read ? 'bg-primary/5' : ''}`,
onclick: () => markAsRead(notif.id)
}, [
Div({ class: 'font-medium' }, notif.title),
Div({ class: 'text-xs opacity-60' }, notif.time),
!notif.read && Span({ class: 'badge badge-xs badge-primary mt-1' }, 'New')
])
)),
Div({ class: 'p-2 text-center' }, [
Button({
class: 'btn btn-xs btn-ghost w-full',
onclick: () => notifications([])
}, 'Clear all')
])
])
items: () => notifications().map(notif => ({
label: Div({ class: 'flex flex-col' }, [
Span({ class: 'font-medium' }, notif.title),
Span({ class: 'text-xs opacity-60' }, notif.time)
]),
class: notif.read ? '' : 'bg-primary/5',
onclick: () => markAsRead(notif.id)
}))
});
};
$mount(NotificationsDropdown, '#demo-notifications');
```
### Custom Content Dropdown
<div class="card bg-base-200 border border-base-300 shadow-sm my-6">
<div class="card-body">
<h3 class="card-title text-sm uppercase opacity-50 mb-4">Live Demo</h3>
<div id="demo-custom" class="bg-base-100 p-6 rounded-xl border border-base-300 flex items-center justify-center"></div>
</div>
</div>
```javascript
const CustomDropdown = () => {
const selected = $('Option 1');
return Dropdown({
label: () => selected(),
children: () => Div({ class: 'p-4 min-w-48' }, [
Div({ class: 'text-sm font-bold mb-2' }, 'Select an option'),
Div({ class: 'flex flex-col gap-1' }, [
Button({
class: 'btn btn-ghost btn-sm justify-start',
onclick: () => selected('Option 1')
}, 'Option 1'),
Button({
class: 'btn btn-ghost btn-sm justify-start',
onclick: () => selected('Option 2')
}, 'Option 2'),
Button({
class: 'btn btn-ghost btn-sm justify-start',
onclick: () => selected('Option 3')
}, 'Option 3')
])
])
});
};
$mount(CustomDropdown, '#demo-custom');
```
### All Variants
<div class="card bg-base-200 border border-base-300 shadow-sm my-6">