Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,042 changes: 764 additions & 278 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@
"yarn": "^1.22.10"
},
"dependencies": {
"@popperjs/core": "^2.9.3",
"@floating-ui/dom": "^1.7.0",
"flowbite-datepicker": "^1.3.1",
"mini-svg-data-uri": "^1.4.3",
"postcss": "^8.5.1"
Expand Down
58 changes: 18 additions & 40 deletions src/components/dropdown/index.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
/* eslint-disable @typescript-eslint/no-empty-function */
import { createPopper } from '@popperjs/core';
import type {
Options as PopperOptions,
Instance as PopperInstance,
} from '@popperjs/core';
import { computePosition, autoUpdate, offset } from '@floating-ui/dom';
import type { DropdownOptions } from './types';
import type { InstanceOptions } from '../../dom/types';
import { DropdownInterface } from './interface';
Expand Down Expand Up @@ -32,7 +28,7 @@ class Dropdown implements DropdownInterface {
_triggerEl: HTMLElement;
_options: DropdownOptions;
_visible: boolean;
_popperInstance: PopperInstance;
_cleanupAutoUpdate: Function;
_initialized: boolean;
_clickOutsideEventListener: EventListenerOrEventListenerObject;
_hoverShowTriggerElHandler: EventListenerOrEventListenerObject;
Expand All @@ -52,7 +48,7 @@ class Dropdown implements DropdownInterface {
this._targetEl = targetElement;
this._triggerEl = triggerElement;
this._options = { ...Default, ...options };
this._popperInstance = null;
this._cleanupAutoUpdate = null;
this._visible = false;
this._initialized = false;
this.init();
Expand All @@ -66,7 +62,6 @@ class Dropdown implements DropdownInterface {

init() {
if (this._triggerEl && this._targetEl && !this._initialized) {
this._popperInstance = this._createPopperInstance();
this._setupEventListeners();
this._initialized = true;
}
Expand Down Expand Up @@ -101,7 +96,9 @@ class Dropdown implements DropdownInterface {
});
}

this._popperInstance.destroy();
// stop FloatingUI auto updates
this?._cleanupAutoUpdate();

this._initialized = false;
}

Expand Down Expand Up @@ -169,21 +166,13 @@ class Dropdown implements DropdownInterface {
}
}

_createPopperInstance() {
return createPopper(this._triggerEl, this._targetEl, {
placement: this._options.placement,
modifiers: [
{
name: 'offset',
options: {
offset: [
this._options.offsetSkidding,
this._options.offsetDistance,
],
},
},
],
});
_initializeFloatingUI() {
computePosition(this._triggerEl, this._targetEl, {
placement: this._options.placement,
middleware: [offset({ mainAxis: this._options.offsetSkidding, crossAxis: this._options.offsetDistance})]
}).then(({ x, y }) => {
Object.assign(this._targetEl.style, { left: `${x}px`, top: `${y}px` });
});
}

_setupClickOutsideListener() {
Expand Down Expand Up @@ -279,19 +268,13 @@ class Dropdown implements DropdownInterface {
this._targetEl.classList.add('block');
this._targetEl.removeAttribute('aria-hidden');

// Update its position
this._initializeFloatingUI();
// Enable the event listeners
this._popperInstance.setOptions((options: PopperOptions) => ({
...options,
modifiers: [
...options.modifiers,
{ name: 'eventListeners', enabled: true },
],
}));
this._cleanupAutoUpdate = autoUpdate(this._triggerEl, this._targetEl, () => { this._initializeFloatingUI() });

this._setupClickOutsideListener();

// Update its position
this._popperInstance.update();
this._visible = true;

// callback function
Expand All @@ -304,13 +287,8 @@ class Dropdown implements DropdownInterface {
this._targetEl.setAttribute('aria-hidden', 'true');

// Disable the event listeners
this._popperInstance.setOptions((options: PopperOptions) => ({
...options,
modifiers: [
...options.modifiers,
{ name: 'eventListeners', enabled: false },
],
}));
this._cleanupAutoUpdate();
this._cleanupAutoUpdate = null;

this._visible = false;

Expand Down
4 changes: 1 addition & 3 deletions src/components/dropdown/interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,17 @@ import {
DropdownTriggerType,
DropdownTriggerEventTypes,
} from './types';
import type { Instance as PopperInstance } from '@popperjs/core';

export declare interface DropdownInterface {
_targetEl: HTMLElement;
_triggerEl: HTMLElement;
_options: DropdownOptions;
_cleanupAutoUpdate: Function;
_visible: boolean;
_popperInstance: PopperInstance;
_initialized: boolean;
_clickOutsideEventListener: EventListenerOrEventListenerObject;

init(): void;
_createPopperInstance(): PopperInstance;
_setupEventListeners(): void;
_setupClickOutsideListener(): void;
_removeClickOutsideListener(): void;
Expand Down
2 changes: 1 addition & 1 deletion src/components/dropdown/types.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { DropdownInterface } from './interface';
import type { Placement } from '@popperjs/core';
import type { Placement } from '@floating-ui/dom';

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

Expand Down
58 changes: 17 additions & 41 deletions src/components/popover/index.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
/* eslint-disable @typescript-eslint/no-empty-function */
import { createPopper } from '@popperjs/core';
import type {
Options as PopperOptions,
Instance as PopperInstance,
} from '@popperjs/core';
import { computePosition, autoUpdate, offset } from '@floating-ui/dom';
import type { PopoverOptions } from './types';
import type { InstanceOptions } from '../../dom/types';
import { PopoverInterface } from './interface';
Expand All @@ -28,7 +24,7 @@ class Popover implements PopoverInterface {
_targetEl: HTMLElement;
_triggerEl: HTMLElement;
_options: PopoverOptions;
_popperInstance: PopperInstance;
_cleanupAutoUpdate: Function;
_clickOutsideEventListener: EventListenerOrEventListenerObject;
_keydownEventListener: EventListenerOrEventListenerObject;
_visible: boolean;
Expand All @@ -48,7 +44,7 @@ class Popover implements PopoverInterface {
this._targetEl = targetEl;
this._triggerEl = triggerEl;
this._options = { ...Default, ...options };
this._popperInstance = null;
this._cleanupAutoUpdate = null;
this._visible = false;
this._initialized = false;
this.init();
Expand All @@ -63,7 +59,6 @@ class Popover implements PopoverInterface {
init() {
if (this._triggerEl && this._targetEl && !this._initialized) {
this._setupEventListeners();
this._popperInstance = this._createPopperInstance();
this._initialized = true;
}
}
Expand All @@ -89,10 +84,8 @@ class Popover implements PopoverInterface {
// remove event listeners for click outside
this._removeClickOutsideListener();

// destroy the Popper instance if you have one (assuming this._popperInstance is the Popper instance)
if (this._popperInstance) {
this._popperInstance.destroy();
}
// stop FloatingUI auto updates
this?._cleanupAutoUpdate();

this._initialized = false;
}
Expand Down Expand Up @@ -133,18 +126,13 @@ class Popover implements PopoverInterface {
});
}

_createPopperInstance() {
return createPopper(this._triggerEl, this._targetEl, {
placement: this._options.placement,
modifiers: [
{
name: 'offset',
options: {
offset: [0, this._options.offset],
},
},
],
});
_initializeFloatingUI() {
computePosition(this._triggerEl, this._targetEl, {
placement: this._options.placement,
middleware: [offset(this._options.offset)]
}).then(({ x, y }) => {
Object.assign(this._targetEl.style, { left: `${x}px`, top: `${y}px` });
});
}

_getTriggerEvents() {
Expand Down Expand Up @@ -241,24 +229,17 @@ class Popover implements PopoverInterface {
this._targetEl.classList.remove('opacity-0', 'invisible');
this._targetEl.classList.add('opacity-100', 'visible');

// Update its position
this._initializeFloatingUI();
// Enable the event listeners
this._popperInstance.setOptions((options: PopperOptions) => ({
...options,
modifiers: [
...options.modifiers,
{ name: 'eventListeners', enabled: true },
],
}));
this._cleanupAutoUpdate = autoUpdate(this._triggerEl, this._targetEl, () => { this._initializeFloatingUI() });

// handle click outside
this._setupClickOutsideListener();

// handle esc keydown
this._setupKeydownListener();

// Update its position
this._popperInstance.update();

// set visibility to true
this._visible = true;

Expand All @@ -271,13 +252,8 @@ class Popover implements PopoverInterface {
this._targetEl.classList.add('opacity-0', 'invisible');

// Disable the event listeners
this._popperInstance.setOptions((options: PopperOptions) => ({
...options,
modifiers: [
...options.modifiers,
{ name: 'eventListeners', enabled: false },
],
}));
this._cleanupAutoUpdate();
this._cleanupAutoUpdate = null;

// handle click outside
this._removeClickOutsideListener();
Expand Down
3 changes: 1 addition & 2 deletions src/components/popover/interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,12 @@ import {
PopoverTriggerType,
PopoverTriggerEventTypes,
} from './types';
import type { Instance as PopperInstance } from '@popperjs/core';

export declare interface PopoverInterface {
_targetEl: HTMLElement | null;
_triggerEl: HTMLElement | null;
_options: PopoverOptions;
_popperInstance: PopperInstance;
_cleanupAutoUpdate: Function;
_clickOutsideEventListener: EventListenerOrEventListenerObject;
_keydownEventListener: EventListenerOrEventListenerObject;

Expand Down
2 changes: 1 addition & 1 deletion src/components/popover/types.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { PopoverInterface } from './interface';
import type { Placement } from '@popperjs/core';
import type { Placement } from '@floating-ui/dom';

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

Expand Down
Loading