Skip to content

Commit 3bf9683

Browse files
authored
Reactivate eslint rules & improve typings (#947)
* Reactivate unbound-method * Fix typing for dropdown * Fix no-unsafe-call & fix component typing
1 parent 939f901 commit 3bf9683

File tree

6 files changed

+92
-60
lines changed

6 files changed

+92
-60
lines changed

ember-basic-dropdown/eslint.config.mjs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -85,10 +85,6 @@ export default ts.config(
8585
parserOptions: parserOptions.esm.ts,
8686
},
8787
extends: [...ts.configs.recommendedTypeChecked, ember.configs.gts],
88-
rules: {
89-
'@typescript-eslint/no-unsafe-call': 'off',
90-
'@typescript-eslint/unbound-method': 'off',
91-
},
9288
},
9389
{
9490
files: ['src/**/*'],

ember-basic-dropdown/src/components/basic-dropdown-content.ts

Lines changed: 37 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -202,17 +202,24 @@ export default class BasicDropdownContent extends Component<BasicDropdownContent
202202
);
203203
}
204204

205-
window.addEventListener('resize', this.runloopAwareReposition);
206-
window.addEventListener('orientationchange', this.runloopAwareReposition);
205+
window.addEventListener('resize', this.runloopAwareRepositionBound);
206+
window.addEventListener(
207+
'orientationchange',
208+
this.runloopAwareRepositionBound,
209+
);
207210

208211
if (this.isTouchDevice) {
209-
document.addEventListener('touchstart', this.touchStartHandler, true);
212+
document.addEventListener(
213+
'touchstart',
214+
this.touchStartHandlerBound,
215+
true,
216+
);
210217
document.addEventListener('touchend', this.handleRootMouseDown, true);
211218

212219
if (rootElement) {
213220
rootElement.addEventListener(
214221
'touchstart',
215-
this.touchStartHandler,
222+
this.touchStartHandlerBound,
216223
true,
217224
);
218225
rootElement.addEventListener(
@@ -259,7 +266,7 @@ export default class BasicDropdownContent extends Component<BasicDropdownContent
259266
if (this.isTouchDevice) {
260267
document.removeEventListener(
261268
'touchstart',
262-
this.touchStartHandler,
269+
this.touchStartHandlerBound,
263270
true,
264271
);
265272
document.removeEventListener(
@@ -271,7 +278,7 @@ export default class BasicDropdownContent extends Component<BasicDropdownContent
271278
if (rootElement) {
272279
rootElement.removeEventListener(
273280
'touchstart',
274-
this.touchStartHandler,
281+
this.touchStartHandlerBound,
275282
true,
276283
);
277284
rootElement.removeEventListener(
@@ -369,28 +376,36 @@ export default class BasicDropdownContent extends Component<BasicDropdownContent
369376

370377
@action
371378
touchStartHandler(): void {
372-
document.addEventListener('touchmove', this.touchMoveHandler, true);
379+
document.addEventListener('touchmove', this.touchMoveHandlerBound, true);
373380

374381
if (
375382
this._contentWormhole &&
376383
this._contentWormhole.getRootNode() instanceof ShadowRoot
377384
) {
378385
const rootElement = this._contentWormhole.getRootNode() as HTMLElement;
379-
rootElement.addEventListener('touchmove', this.touchMoveHandler, true);
386+
rootElement.addEventListener(
387+
'touchmove',
388+
this.touchMoveHandlerBound,
389+
true,
390+
);
380391
}
381392
}
382393

383394
@action
384395
touchMoveHandler(e: TouchEvent): void {
385396
this.touchMoveEvent = e;
386-
document.removeEventListener('touchmove', this.touchMoveHandler, true);
397+
document.removeEventListener('touchmove', this.touchMoveHandlerBound, true);
387398

388399
if (
389400
this._contentWormhole &&
390401
this._contentWormhole.getRootNode() instanceof ShadowRoot
391402
) {
392403
const rootElement = this._contentWormhole.getRootNode() as HTMLElement;
393-
rootElement.removeEventListener('touchmove', this.touchMoveHandler, true);
404+
rootElement.removeEventListener(
405+
'touchmove',
406+
this.touchMoveHandlerBound,
407+
true,
408+
);
394409
}
395410
}
396411

@@ -411,13 +426,17 @@ export default class BasicDropdownContent extends Component<BasicDropdownContent
411426

412427
@action
413428
removeGlobalEvents(): void {
414-
window.removeEventListener('resize', this.runloopAwareReposition);
429+
window.removeEventListener('resize', this.runloopAwareRepositionBound);
415430
window.removeEventListener(
416431
'orientationchange',
417-
this.runloopAwareReposition,
432+
this.runloopAwareRepositionBound,
418433
);
419434
}
420435

436+
touchMoveHandlerBound = (e: TouchEvent) => this.touchMoveHandler(e);
437+
runloopAwareRepositionBound = () => this.runloopAwareReposition();
438+
touchStartHandlerBound = () => this.touchStartHandler();
439+
421440
// Methods
422441
addScrollHandling(dropdownElement: Element): void {
423442
if (this.args.preventScroll === true) {
@@ -497,7 +516,7 @@ export default class BasicDropdownContent extends Component<BasicDropdownContent
497516
};
498517
} else {
499518
this.addScrollEvents();
500-
this.removeScrollHandling = this.removeScrollEvents;
519+
this.removeScrollHandling = this.removeScrollEvents.bind(this);
501520
}
502521
}
503522

@@ -508,15 +527,15 @@ export default class BasicDropdownContent extends Component<BasicDropdownContent
508527
// These two functions wire up scroll handling if `preventScroll` is false.
509528
// These trigger reposition of the dropdown.
510529
addScrollEvents(): void {
511-
window.addEventListener('scroll', this.runloopAwareReposition);
530+
window.addEventListener('scroll', this.runloopAwareRepositionBound);
512531
this.scrollableAncestors.forEach((el) => {
513-
el.addEventListener('scroll', this.runloopAwareReposition);
532+
el.addEventListener('scroll', this.runloopAwareRepositionBound);
514533
});
515534
}
516535
removeScrollEvents(): void {
517-
window.removeEventListener('scroll', this.runloopAwareReposition);
536+
window.removeEventListener('scroll', this.runloopAwareRepositionBound);
518537
this.scrollableAncestors.forEach((el) => {
519-
el.removeEventListener('scroll', this.runloopAwareReposition);
538+
el.removeEventListener('scroll', this.runloopAwareRepositionBound);
520539
});
521540
}
522541
}
@@ -573,8 +592,7 @@ function closestContent(el: Element): Element | null {
573592
return el;
574593
}
575594

576-
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
577-
function waitForAnimations(element: Element, callback: Function): void {
595+
function waitForAnimations(element: Element, callback: () => void): void {
578596
window.requestAnimationFrame(function () {
579597
const computedStyle = window.getComputedStyle(element);
580598
if (

ember-basic-dropdown/src/components/basic-dropdown-wormhole.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ export default class BasicDropdownWormholeComponent extends Component<BasicDropd
99
get getDestinationId(): string {
1010
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
1111
// @ts-ignore
12+
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
1213
const config = getOwner(this).resolveRegistration('config:environment') as {
1314
'ember-basic-dropdown'?: {
1415
destination?: string;

ember-basic-dropdown/src/components/basic-dropdown.ts

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -68,18 +68,18 @@ export interface BasicDropdownArgs {
6868
rootEventType?: TRootEventType;
6969
preventScroll?: boolean;
7070
matchTriggerWidth?: boolean;
71-
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
72-
onInit?: Function;
73-
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
74-
registerAPI?: Function;
75-
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
76-
onOpen?: Function;
77-
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
78-
onClose?: Function;
79-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
80-
triggerComponent?: string | ComponentLike<any> | undefined;
81-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
82-
contentComponent?: string | ComponentLike<any> | undefined;
71+
onInit?: (dropdown: Dropdown) => void;
72+
registerAPI?: (dropdown: Dropdown | null) => void;
73+
onOpen?: (dropdown: Dropdown, e?: Event) => boolean | void;
74+
onClose?: (dropdown: Dropdown, e?: Event) => boolean | void;
75+
triggerComponent?:
76+
| string
77+
| ComponentLike<BasicDropdownTriggerSignature>
78+
| undefined;
79+
contentComponent?:
80+
| string
81+
| ComponentLike<BasicDropdownContentSignature>
82+
| undefined;
8383
calculatePosition?: CalculatePosition;
8484
}
8585

@@ -116,12 +116,12 @@ export default class BasicDropdown extends Component<BasicDropdownSignature> {
116116
this.args.dropdownId || `ember-basic-dropdown-content-${this._uid}`;
117117
private _previousDisabled = UNINITIALIZED;
118118
private _actions: DropdownActions = {
119-
open: this.open,
120-
close: this.close,
121-
toggle: this.toggle,
122-
reposition: this.reposition,
123-
registerTriggerElement: this.registerTriggerElement,
124-
registerDropdownElement: this.registerDropdownElement,
119+
open: this.open.bind(this),
120+
close: this.close.bind(this),
121+
toggle: this.toggle.bind(this),
122+
reposition: this.reposition.bind(this),
123+
registerTriggerElement: this.registerTriggerElement.bind(this),
124+
registerDropdownElement: this.registerDropdownElement.bind(this),
125125
getTriggerElement: () => this.triggerElement,
126126
};
127127

@@ -394,6 +394,7 @@ export default class BasicDropdown extends Component<BasicDropdownSignature> {
394394
_getDestinationId(): string {
395395
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
396396
// @ts-ignore
397+
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
397398
const config = getOwner(this).resolveRegistration('config:environment') as {
398399
environment: string;
399400
APP: {

ember-basic-dropdown/src/modifiers/basic-dropdown-trigger.ts

Lines changed: 32 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -63,13 +63,13 @@ export default class DropdownTriggerModifier extends Modifier<Signature> {
6363

6464
if (!element.getAttribute('role')) element.setAttribute('role', 'button');
6565

66-
element.addEventListener('click', this.handleMouseEvent);
67-
element.addEventListener('mousedown', this.handleMouseEvent);
68-
element.addEventListener('keydown', this.handleKeyDown);
69-
element.addEventListener('touchstart', this.handleTouchStart, {
66+
element.addEventListener('click', this.handleMouseEventBound);
67+
element.addEventListener('mousedown', this.handleMouseEventBound);
68+
element.addEventListener('keydown', this.handleKeyDownBound);
69+
element.addEventListener('touchstart', this.handleTouchStartBound, {
7070
passive: false,
7171
});
72-
element.addEventListener('touchend', this.handleTouchEnd);
72+
element.addEventListener('touchend', this.handleTouchEndBound);
7373
}
7474

7575
update(
@@ -142,11 +142,11 @@ export default class DropdownTriggerModifier extends Modifier<Signature> {
142142

143143
@action
144144
handleTouchStart(): void {
145-
document.addEventListener('touchmove', this._touchMoveHandler);
145+
document.addEventListener('touchmove', this.touchMoveHandlerBound);
146146
if (this.triggerElement?.getRootNode() instanceof ShadowRoot) {
147147
(this.triggerElement?.getRootNode() as HTMLElement).addEventListener(
148148
'touchmove',
149-
this._touchMoveHandler,
149+
this.touchMoveHandlerBound,
150150
);
151151
}
152152
}
@@ -164,7 +164,7 @@ export default class DropdownTriggerModifier extends Modifier<Signature> {
164164
actions.toggle(e);
165165
}
166166
this.touchMoveEvent = undefined;
167-
document.removeEventListener('touchmove', this._touchMoveHandler);
167+
document.removeEventListener('touchmove', this.touchMoveHandlerBound);
168168
// This next three lines are stolen from hammertime. This prevents the default
169169
// behaviour of the touchend, but synthetically trigger a focus and a (delayed) click
170170
// to simulate natural behaviour.
@@ -207,34 +207,49 @@ export default class DropdownTriggerModifier extends Modifier<Signature> {
207207
@action
208208
_touchMoveHandler(e: TouchEvent): void {
209209
this.touchMoveEvent = e;
210-
document.removeEventListener('touchmove', this._touchMoveHandler);
210+
document.removeEventListener('touchmove', this.touchMoveHandlerBound);
211211

212212
if (this.triggerElement?.getRootNode() instanceof ShadowRoot) {
213213
(this.triggerElement?.getRootNode() as HTMLElement).removeEventListener(
214214
'touchmove',
215-
this._touchMoveHandler,
215+
this.touchMoveHandlerBound,
216216
);
217217
}
218218
}
219+
220+
handleMouseEventBound = (e: MouseEvent) => this.handleMouseEvent(e);
221+
handleKeyDownBound = (e: KeyboardEvent) => this.handleKeyDown(e);
222+
handleTouchStartBound = () => this.handleTouchStart();
223+
handleTouchEndBound = (e: TouchEvent) => this.handleTouchEnd(e);
224+
touchMoveHandlerBound = (e: TouchEvent) => this._touchMoveHandler(e);
219225
}
220226

221227
function cleanup(instance: DropdownTriggerModifier) {
222228
const { triggerElement } = instance;
223229
if (triggerElement) {
224230
if (typeof document !== 'undefined')
225-
document.removeEventListener('touchmove', instance._touchMoveHandler);
231+
document.removeEventListener('touchmove', instance.touchMoveHandlerBound);
226232

227233
if (triggerElement?.getRootNode() instanceof ShadowRoot) {
228234
(triggerElement?.getRootNode() as HTMLElement).removeEventListener(
229235
'touchmove',
230-
instance._touchMoveHandler,
236+
instance.touchMoveHandlerBound,
231237
);
232238
}
233239

234-
triggerElement.removeEventListener('click', instance.handleMouseEvent);
235-
triggerElement.removeEventListener('mousedown', instance.handleMouseEvent);
236-
triggerElement.removeEventListener('keydown', instance.handleKeyDown);
237-
triggerElement.removeEventListener('touchstart', instance.handleTouchStart);
238-
triggerElement.removeEventListener('touchend', instance.handleTouchEnd);
240+
triggerElement.removeEventListener('click', instance.handleMouseEventBound);
241+
triggerElement.removeEventListener(
242+
'mousedown',
243+
instance.handleMouseEventBound,
244+
);
245+
triggerElement.removeEventListener('keydown', instance.handleKeyDownBound);
246+
triggerElement.removeEventListener(
247+
'touchstart',
248+
instance.handleTouchStartBound,
249+
);
250+
triggerElement.removeEventListener(
251+
'touchend',
252+
instance.handleTouchEndBound,
253+
);
239254
}
240255
}

ember-basic-dropdown/src/utils/calculate-position.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import type BasicDropdown from '../components/basic-dropdown';
2+
13
export type VerticalPosition = 'auto' | 'above' | 'below';
24
export type HorizontalPosition =
35
| 'auto'
@@ -14,8 +16,7 @@ export interface CalculatePositionOptions {
1416
previousHorizontalPosition?: HorizontalPosition | undefined;
1517
previousVerticalPosition?: VerticalPosition | undefined;
1618
renderInPlace: boolean;
17-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
18-
dropdown: any;
19+
dropdown: BasicDropdown;
1920
}
2021
export type CalculatePositionResultStyle = {
2122
top?: number | undefined;

0 commit comments

Comments
 (0)