Skip to content

Commit

Permalink
feat: menu keyboard control reset and throttle
Browse files Browse the repository at this point in the history
  • Loading branch information
zzxming committed Jan 9, 2025
1 parent af583dd commit ca2be19
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 10 deletions.
28 changes: 18 additions & 10 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import type { BlockEmbed as TypeBlockEmbed } from 'quill/blots/block';
import type TypeBlock from 'quill/blots/block';
import type { MenuItems, QuillQuickInsertOptions } from './utils';
import Quill from 'quill';
import { createBEM, createMenu, SearchIndex } from './utils';
import { createBEM, createMenu, SearchIndex, throttle } from './utils';

const Parchment = Quill.import('parchment');

Expand Down Expand Up @@ -103,10 +103,6 @@ export class QuillQuickInsert {
item.handler.call(this.quill, item.name);
this.destroyMenuList();
},
onHover: () => {
this.selectedItemIndex -= 1;
this.setMenuSelected();
},
};
}));

Expand All @@ -119,6 +115,7 @@ export class QuillQuickInsert {
this.menuContainer.classList.add(this.bem.be('container'));
this.quill.root.addEventListener('keydown', this.handleMenuControl, true);
this.quill.root.addEventListener('click', this.destroyMenuList);
this.menuContainer.addEventListener('mousemove', this.resetMenuSelected);
this.quill.container.appendChild(this.menuContainer);
}
const rootRect = this.quill.root.getBoundingClientRect();
Expand All @@ -141,7 +138,8 @@ export class QuillQuickInsert {
});
}

handleMenuControl = (e: KeyboardEvent) => {
// eslint-disable-next-line unicorn/consistent-function-scoping
handleMenuControl = throttle((e: KeyboardEvent) => {
const handleKey = new Set(['Escape', 'Enter', 'ArrowDown', 'ArrowUp', 'ArrowLeft', 'ArrowRight']);
if (handleKey.has(e.code) && this.menuContainer) {
e.stopImmediatePropagation();
Expand All @@ -160,10 +158,15 @@ export class QuillQuickInsert {

switch (e.code) {
case 'Enter': {
const selected = this.menuContainer.querySelector(`.${this.bem.is('selected')}`) as HTMLElement;
if (selected) {
selected.click();
return;
}
const items = Array.from(this.menuContainer.querySelectorAll(`.${this.bem.be('item')}`)) as HTMLElement[];
const el = this.selectedItemIndex === -1 ? items[0] : items[this.selectedItemIndex];
if (el) {
el.click();
const item = this.selectedItemIndex === -1 ? items[0] : items[this.selectedItemIndex];
if (item) {
item.click();
}
return;
}
Expand All @@ -187,14 +190,18 @@ export class QuillQuickInsert {

this.setMenuSelected();
}
}, 50);

resetMenuSelected = () => {
this.selectedItemIndex = -1;
};

setMenuSelected() {
if (this.menuContainer) {
for (const el of Array.from(this.menuContainer.querySelectorAll(`.${this.bem.is('selected')}`))) {
el.classList.remove(this.bem.is('selected'));
}
if (this.selectedItemIndex !== -1) {
if (this.selectedItemIndex >= 0) {
const el = this.menuContainer.querySelectorAll(`.${this.bem.be('item')}`)[this.selectedItemIndex] as HTMLElement;
if (el) {
el.classList.add(this.bem.is('selected'));
Expand Down Expand Up @@ -224,6 +231,7 @@ export class QuillQuickInsert {
this.quill.root.removeEventListener('keydown', this.handleMenuControl, true);
this.quill.root.removeEventListener('click', this.destroyMenuList);
if (!this.menuContainer) return;
this.menuContainer.removeEventListener('mousemove', this.resetMenuSelected);
this.menuContainer.remove();
this.menuContainer = undefined;
};
Expand Down
30 changes: 30 additions & 0 deletions src/utils/function.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
export function throttle(func: (...args: any[]) => any, wait: number) {
let timeout: ReturnType<typeof setTimeout> | null = null;
let lastArgs: any[] = [];
let lastThis: any = null;
let lastCallTime = 0;

return function (this: any, ...args: any[]) {
const now = Date.now();
const remainingTime = wait - (now - lastCallTime);

lastArgs = args;
lastThis = this;

if (remainingTime <= 0 || remainingTime > wait) {
if (timeout) {
clearTimeout(timeout);
timeout = null;
}
lastCallTime = now;
func.apply(lastThis, lastArgs);
}
else if (!timeout) {
timeout = setTimeout(() => {
lastCallTime = Date.now();
timeout = null;
func.apply(lastThis, lastArgs);
}, remainingTime);
}
};
}
1 change: 1 addition & 0 deletions src/utils/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export * from './bem';
export * from './components';
export * from './constants';
export * from './function';
export * from './searchIndex';
export * from './types';

0 comments on commit ca2be19

Please sign in to comment.