Skip to content

Commit

Permalink
Add delay option and docs for #208.
Browse files Browse the repository at this point in the history
  • Loading branch information
zoltanszogyenyi committed Jan 20, 2023
1 parent 75bc645 commit 75faf96
Show file tree
Hide file tree
Showing 3 changed files with 107 additions and 41 deletions.
57 changes: 54 additions & 3 deletions content/components/dropdowns.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,9 @@ The `dropdownId` is the id of the dropdown menu element.

## Dropdown hover

Use the `data-dropdown-trigger="{hover|click}"` data attribute options to set whether the dropdown should be shown when hovering or clicking on the trigger element (ie. button).
Use the `data-dropdown-trigger="{hover|click}"` data attribute options to set whether the dropdown should be shown when hovering or clicking on the trigger element (ie. button).

There's a 300ms default delay when showing or hiding the dropdown due to UI/UX reasons and how it may affect the interaction with other components on the page. Generally, we recommend using the `click` method.

{{< example id="dropdown-hover-example" class="flex justify-center" github="components/dropdowns.md" show_dark=true iframeHeight="240" >}}
<button id="dropdownHoverButton" data-dropdown-toggle="dropdownHover" data-dropdown-trigger="hover" class="text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm px-4 py-2.5 text-center inline-flex items-center dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800" type="button">Dropdown hover <svg class="w-4 h-4 ml-2" aria-hidden="true" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"></path></svg></button>
Expand All @@ -68,6 +70,31 @@ Use the `data-dropdown-trigger="{hover|click}"` data attribute options to set wh
</div>
{{< /example >}}

### Delay duration

You can use the `data-dropdown-delay={miliseconds}` data attribute to set they delay on when to show or hide the dropdown menu when using hover. You may want to use this depending on how the users interact with your interface. In this example we add 500 miliseconds instead of the default 300.

{{< example id="dropdown-delay-example" class="flex justify-center" github="components/dropdowns.md" show_dark=true iframeHeight="240" >}}
<button id="dropdownDelayButton" data-dropdown-toggle="dropdownDelay" data-dropdown-delay="500" data-dropdown-trigger="hover" class="text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm px-4 py-2.5 text-center inline-flex items-center dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800" type="button">Dropdown hover <svg class="w-4 h-4 ml-2" aria-hidden="true" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"></path></svg></button>
<!-- Dropdown menu -->
<div id="dropdownDelay" class="z-10 hidden bg-white divide-y divide-gray-100 rounded shadow w-44 dark:bg-gray-700">
<ul class="py-1 text-sm text-gray-700 dark:text-gray-200" aria-labelledby="dropdownDelayButton">
<li>
<a href="#" class="block px-4 py-2 hover:bg-gray-100 dark:hover:bg-gray-600 dark:hover:text-white">Dashboard</a>
</li>
<li>
<a href="#" class="block px-4 py-2 hover:bg-gray-100 dark:hover:bg-gray-600 dark:hover:text-white">Settings</a>
</li>
<li>
<a href="#" class="block px-4 py-2 hover:bg-gray-100 dark:hover:bg-gray-600 dark:hover:text-white">Earnings</a>
</li>
<li>
<a href="#" class="block px-4 py-2 hover:bg-gray-100 dark:hover:bg-gray-600 dark:hover:text-white">Sign out</a>
</li>
</ul>
</div>
{{< /example >}}

## Dropdown divider

You can use the `divide-y divide-gray-100` classes to add separate elements inside the dropdown menu.
Expand Down Expand Up @@ -1179,6 +1206,17 @@ Use the following options as the third parameter for the Dropdown class to set t
Set the position of the dropdown menu relative to the trigger element choosing from <code class="text-purple-600 dark:text-purple-400">top|right|bottom|left</code>.
</td>
</tr>
<tr class="border-b dark:bg-gray-800 dark:border-gray-700">
<td class="px-6 py-4 font-medium">
<code class="text-blue-600 dark:text-blue-400">triggerType</code>
</td>
<td class="px-6 py-4 font-medium">
String
</td>
<td class="px-6 py-4">
The possible options are click, hover, or none and these will set based on which event the dropdown will be shown.
</td>
</tr>
<tr class="border-b dark:bg-gray-800 dark:border-gray-700">
<td class="px-6 py-4 font-medium">
<code class="text-blue-600 dark:text-blue-400">offsetDistance</code>
Expand All @@ -1201,6 +1239,17 @@ Use the following options as the third parameter for the Dropdown class to set t
Set the number of pixels the dropdown menu should be offset relative to the trigger element on the Y horizontal axis.
</td>
</tr>
<tr class="border-b dark:bg-gray-800 dark:border-gray-700">
<td class="px-6 py-4 font-medium">
<code class="text-blue-600 dark:text-blue-400">delay</code>
</td>
<td class="px-6 py-4 font-medium">
Number
</td>
<td class="px-6 py-4">
Set the miliseconds for which the showing or hiding of the dropdown will be delayed for when using the hover trigger type.
</td>
</tr>
<tr class="border-b dark:bg-gray-800 dark:border-gray-700">
<td class="px-6 py-4 font-medium">
<code class="text-blue-600 dark:text-blue-400">onHide</code>
Expand Down Expand Up @@ -1282,8 +1331,10 @@ const $triggerEl = document.getElementById('dropdownButton');
// options with default values
const options = {
placement: 'bottom',
triggerType: 'click',
offsetSkidding: 0,
offsetDistance: 10,
delay: 300,
onHide: () => {
console.log('dropdown has been hidden');
},
Expand Down Expand Up @@ -1318,7 +1369,7 @@ dropdown.hide();

Use the following HTML code for the JavaScript example above.

```html
<!-- ```html -->
<button id="dropdownButton" class="text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm px-4 py-2.5 text-center inline-flex items-center dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800" type="button">Dropdown button <svg aria-hidden="true" class="w-4 h-4 ml-2" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"></path></svg></button>
<!-- Dropdown menu -->
<div id="dropdownMenu" class="z-10 hidden bg-white divide-y divide-gray-100 rounded shadow w-44 dark:bg-gray-700">
Expand All @@ -1337,7 +1388,7 @@ Use the following HTML code for the JavaScript example above.
</li>
</ul>
</div>
```
<!-- ``` -->

### TypeScript

Expand Down
84 changes: 49 additions & 35 deletions src/components/dropdown/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ const Default: DropdownOptions = {
triggerType: 'click',
offsetSkidding: 0,
offsetDistance: 10,
delay: 300,
onShow: () => {},
onHide: () => {},
};
Expand Down Expand Up @@ -39,48 +40,54 @@ class Dropdown implements DropdownInterface {

_init() {
if (this._triggerEl) {
const triggerEvents = this._getTriggerEvents();
this._setupEventListeners();
}
}

// click event handling for trigger element
if (this._options.triggerType === 'click') {
triggerEvents.showEvents.forEach((ev) => {
this._triggerEl.addEventListener(ev, () => {
this.toggle();
});
_setupEventListeners() {
const triggerEvents = this._getTriggerEvents();

// click event handling for trigger element
if (this._options.triggerType === 'click') {
triggerEvents.showEvents.forEach((ev) => {
this._triggerEl.addEventListener(ev, () => {
this.toggle();
});
}
});
}

// hover event handling for trigger element
if (this._options.triggerType === 'hover') {
triggerEvents.showEvents.forEach((ev) => {
this._triggerEl.addEventListener(ev, () => {
if (ev === 'click') {
this.toggle();
} else {
// hover event handling for trigger element
if (this._options.triggerType === 'hover') {
triggerEvents.showEvents.forEach((ev) => {
this._triggerEl.addEventListener(ev, () => {
if (ev === 'click') {
this.toggle();
} else {
setTimeout(() => {
this.show();
}, this._options.delay);
}
});
this._targetEl.addEventListener(ev, () => {
this.show();
});
});
triggerEvents.hideEvents.forEach((ev) => {
this._triggerEl.addEventListener(ev, () => {
setTimeout(() => {
if (!this._targetEl.matches(':hover')) {
this.hide();
}
});
this._targetEl.addEventListener(ev, () => {
this.show();
});
}, this._options.delay);
});
triggerEvents.hideEvents.forEach((ev) => {
this._triggerEl.addEventListener(ev, () => {
setTimeout(() => {
if (!this._targetEl.matches(':hover')) {
this.hide();
}
}, 100);
});
this._targetEl.addEventListener(ev, () => {
setTimeout(() => {
if (!this._triggerEl.matches(':hover')) {
this.hide();
}
}, 100);
});
this._targetEl.addEventListener(ev, () => {
setTimeout(() => {
if (!this._triggerEl.matches(':hover')) {
this.hide();
}
}, this._options.delay);
});
}
});
}
}

Expand Down Expand Up @@ -144,6 +151,11 @@ class Dropdown implements DropdownInterface {
showEvents: ['click'],
hideEvents: [],
};
case 'none':
return {
showEvents: [],
hideEvents: [],
};
default:
return {
showEvents: ['click'],
Expand Down Expand Up @@ -229,6 +241,7 @@ export function initDropdowns() {
const triggerType = $triggerEl.getAttribute(
'data-dropdown-trigger'
);
const delay = $triggerEl.getAttribute('data-dropdown-delay');

new Dropdown(
$dropdownEl as HTMLElement,
Expand All @@ -244,6 +257,7 @@ export function initDropdowns() {
offsetDistance: offsetDistance
? parseInt(offsetDistance)
: Default.offsetDistance,
delay: delay ? parseInt(delay) : Default.delay,
} as DropdownOptions
);
} else {
Expand Down
7 changes: 4 additions & 3 deletions src/components/dropdown/types.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
import { DropdownInterface } from './interface';
import type { Placement } from '@popperjs/core';

export declare type TriggerType = 'click' | 'hover';
export declare type TriggerType = 'click' | 'hover' | 'none';

export declare type TriggerEventTypes = {
show: string[];
hide: string[];
showEvents: string[];
hideEvents: string[];
};

export declare type DropdownOptions = {
placement?: Placement;
triggerType?: TriggerType;
offsetSkidding?: number;
offsetDistance?: number;
delay?: number;
onShow?: (tooltip: DropdownInterface) => void;
onHide?: (tooltip: DropdownInterface) => void;
};

0 comments on commit 75faf96

Please sign in to comment.