Skip to content

Commit

Permalink
Merge pull request #351 from philomena-dev/mouse-move-then-over
Browse files Browse the repository at this point in the history
Add mouseMoveThenOver, test
  • Loading branch information
liamwhite authored Aug 29, 2024
2 parents 11d8ca0 + a3152fc commit c83b9f1
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 23 deletions.
25 changes: 3 additions & 22 deletions assets/js/autocomplete.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { getTermContexts } from './match_query';
import store from './utils/store';
import { TermContext } from './query/lex.ts';
import { $, $$, makeEl, removeEl } from './utils/dom.ts';
import { mouseMoveThenOver } from './utils/events.ts';

type TermSuggestion = {
label: string;
Expand Down Expand Up @@ -125,38 +126,18 @@ function createItem(list: HTMLUListElement, suggestion: TermSuggestion) {
className: 'autocomplete__item',
});

let ignoreMouseOver = true;

item.textContent = suggestion.label;
item.dataset.value = suggestion.value;

function onItemMouseOver() {
// Prevent selection when mouse entered the element without actually moving.
if (ignoreMouseOver) {
return;
}

mouseMoveThenOver(item, () => {
removeSelected();
item.classList.add('autocomplete__item--selected');
}

item.addEventListener('mouseover', onItemMouseOver);
});

item.addEventListener('mouseout', () => {
removeSelected();
});

item.addEventListener(
'mousemove',
() => {
ignoreMouseOver = false;
onItemMouseOver();
},
{
once: true,
},
);

item.addEventListener('click', () => {
if (!inputField || !item.dataset.value) return;

Expand Down
51 changes: 50 additions & 1 deletion assets/js/utils/__tests__/events.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { delegate, fire, leftClick, on, PhilomenaAvailableEventsMap } from '../events';
import { delegate, fire, mouseMoveThenOver, leftClick, on, PhilomenaAvailableEventsMap } from '../events';
import { getRandomArrayItem } from '../../../test/randomness';
import { fireEvent } from '@testing-library/dom';

Expand Down Expand Up @@ -80,6 +80,55 @@ describe('Event utils', () => {
});
});

describe('mouseMoveThenOver', () => {
it('should NOT fire on first mouseover', () => {
const mockButton = document.createElement('button');
const mockHandler = vi.fn();

mouseMoveThenOver(mockButton, mockHandler);

fireEvent.mouseOver(mockButton);

expect(mockHandler).toHaveBeenCalledTimes(0);
});

it('should fire on the first mousemove', () => {
const mockButton = document.createElement('button');
const mockHandler = vi.fn();

mouseMoveThenOver(mockButton, mockHandler);

fireEvent.mouseMove(mockButton);

expect(mockHandler).toHaveBeenCalledTimes(1);
});

it('should fire on subsequent mouseover', () => {
const mockButton = document.createElement('button');
const mockHandler = vi.fn();

mouseMoveThenOver(mockButton, mockHandler);

fireEvent.mouseMove(mockButton);
fireEvent.mouseOver(mockButton);

expect(mockHandler).toHaveBeenCalledTimes(2);
});

it('should NOT fire on subsequent mousemove', () => {
const mockButton = document.createElement('button');
const mockHandler = vi.fn();

mouseMoveThenOver(mockButton, mockHandler);

fireEvent.mouseMove(mockButton);
fireEvent.mouseOver(mockButton);
fireEvent.mouseMove(mockButton);

expect(mockHandler).toHaveBeenCalledTimes(2);
});
});

describe('delegate', () => {
it('should call the native addEventListener method on the element', () => {
const mockElement = document.createElement('div');
Expand Down
11 changes: 11 additions & 0 deletions assets/js/utils/events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,17 @@ export function leftClick<E extends MouseEvent, Target extends EventTarget>(func
};
}

export function mouseMoveThenOver<El extends HTMLElement>(element: El, func: (e: MouseEvent) => void) {
element.addEventListener(
'mousemove',
(event: MouseEvent) => {
func(event);
element.addEventListener('mouseover', func);
},
{ once: true },
);
}

export function delegate<K extends keyof PhilomenaAvailableEventsMap, Target extends Element>(
node: PhilomenaEventElement,
event: K,
Expand Down

0 comments on commit c83b9f1

Please sign in to comment.