Skip to content

Commit

Permalink
fix: calling open() method multiple times should keep drop (re)open (#33
Browse files Browse the repository at this point in the history
)

* fix: calling open() method multiple times should keep drop (re)open
- in the original ms-select, the body click was being triggered prior to the open() method but that is inversed in our new lib with vanilla JS, so in order to have the same lifecycle as the original, we can simply add a single CPU cycle delay. This delay arg could also be used by the users for other reasons
  • Loading branch information
ghiscoding authored Mar 22, 2023
1 parent ee8127d commit c36cf45
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 7 deletions.
28 changes: 21 additions & 7 deletions lib/src/MultipleSelectInstance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -347,11 +347,11 @@ export class MultipleSelectInstance {
this.update(true);

if (this.options.isOpen) {
setTimeout(() => this.open(), 10);
this.open(10);
}

if (this.options.openOnHover && this.parentElm) {
this._bindEventService.bind(this.parentElm, 'mouseover', () => this.open());
this._bindEventService.bind(this.parentElm, 'mouseover', () => this.open(null));
this._bindEventService.bind(this.parentElm, 'mouseout', () => this.close());
}
}
Expand Down Expand Up @@ -792,12 +792,26 @@ export class MultipleSelectInstance {
}) as EventListener);
}

open() {
/**
* Open the drop method, user could optionally provide a delay in ms to open the drop.
* The default delay is 0ms (which is 1 CPU cycle) when nothing is provided, to avoid a delay we can pass `-1` or `null`
* @param {number} [openDelay=0] - provide an optional delay, defaults to 0
*/
open(openDelay: number | null = 0) {
if (openDelay !== null && openDelay >= 0) {
let timer: NodeJS.Timeout | undefined;
clearTimeout(timer);
timer = setTimeout(() => this.openDrop(), openDelay);
} else {
this.openDrop();
}
}

protected openDrop() {
if (this.choiceElm?.classList.contains('disabled')) {
return;
}
// this.options.isOpen = true;
setTimeout(() => (this.options.isOpen = true)); // TODO: original code doesn't require this delay
this.options.isOpen = true;
this.parentElm.classList.add('ms-parent-open');
this.choiceElm?.querySelector('div')?.classList.add('open');
this.dropElm.style.display = 'block';
Expand Down Expand Up @@ -827,8 +841,8 @@ export class MultipleSelectInstance {
} else if (typeof this.options.container === 'string') {
// prettier-ignore
container = this.options.container === 'body'
? document.body
: document.querySelector(this.options.container) as HTMLElement;
? document.body
: document.querySelector(this.options.container) as HTMLElement;
}
container!.appendChild(this.dropElm);
this.dropElm.style.top = `${offset?.top ?? 0}px`;
Expand Down
23 changes: 23 additions & 0 deletions playwright/e2e/methods05.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { test, expect } from '@playwright/test';

test.describe('Methods 05 - open/close', () => {
test('open & close drop dynamically', async ({ page }) => {
await page.goto('#/methods05');
await page.locator('.ms-parent').click();
await expect(await page.locator('.ms-drop')).toBeVisible();

await page.getByRole('button', { name: 'Close' }).click();
await expect(await page.locator('.ms-drop')).not.toBeVisible();

// clicking on Close multiple times should keep the drop closed regardless
await page.getByRole('button', { name: 'Close' }).click();
await expect(await page.locator('.ms-drop')).not.toBeVisible();

await page.getByRole('button', { name: 'Open' }).click();
await expect(await page.locator('.ms-drop')).toBeVisible();

// clicking on Open multiple times should keep the drop open regardless
await page.getByRole('button', { name: 'Open' }).click();
await expect(await page.locator('.ms-drop')).toBeVisible();
});
});

0 comments on commit c36cf45

Please sign in to comment.