From 6ccc34d0b799b797e9e90b6a4777f1ae66ed7d12 Mon Sep 17 00:00:00 2001 From: Markus Sanin Date: Mon, 27 Nov 2023 11:42:56 +0100 Subject: [PATCH] Fix lints / disable some for the moment --- .../src/components/basic-dropdown-content.ts | 284 ++++++++++-------- .../src/components/basic-dropdown-trigger.ts | 2 +- .../src/components/basic-dropdown.ts | 71 +++-- .../src/modifiers/basic-dropdown-trigger.ts | 91 ++++-- .../src/utils/calculate-position.ts | 74 +++-- ember-basic-dropdown/src/utils/has-moved.ts | 11 +- .../src/utils/scroll-helpers.ts | 11 +- 7 files changed, 309 insertions(+), 235 deletions(-) diff --git a/ember-basic-dropdown/src/components/basic-dropdown-content.ts b/ember-basic-dropdown/src/components/basic-dropdown-content.ts index ffbb8072..c9af2cd1 100644 --- a/ember-basic-dropdown/src/components/basic-dropdown-content.ts +++ b/ember-basic-dropdown/src/components/basic-dropdown-content.ts @@ -111,134 +111,155 @@ export default class BasicDropdownContent extends Component void => { - let triggerElement = document.querySelector( - `[data-ebd-id=${this.args.dropdown.uniqueId}-trigger]` - ); - this.handleRootMouseDown = (e: MouseEvent | TouchEvent): any => { - if (e.target === null) return; - let target = e.target as Element; - if ( - hasMoved(e as TouchEvent, this.touchMoveEvent) || - dropdownElement.contains(target) || - (triggerElement && triggerElement.contains(target)) - ) { - this.touchMoveEvent = undefined; - return; - } - - if (dropdownIsValidParent(target, this.dropdownId)) { - this.touchMoveEvent = undefined; - return; - } - - this.args.dropdown.actions.close(e, true); - }; - document.addEventListener( - this.args.rootEventType, - this.handleRootMouseDown, - true - ); - window.addEventListener('resize', this.runloopAwareReposition); - window.addEventListener('orientationchange', this.runloopAwareReposition); + respondToEvents = modifier( + (dropdownElement: Element): (() => void) => { + const triggerElement = document.querySelector( + `[data-ebd-id=${this.args.dropdown.uniqueId}-trigger]`, + ); + // eslint-disable-next-line @typescript-eslint/no-explicit-any + this.handleRootMouseDown = (e: MouseEvent | TouchEvent): any => { + if (e.target === null) return; + const target = e.target as Element; + if ( + hasMoved(e as TouchEvent, this.touchMoveEvent) || + dropdownElement.contains(target) || + (triggerElement && triggerElement.contains(target)) + ) { + this.touchMoveEvent = undefined; + return; + } - if (this.isTouchDevice) { - document.addEventListener('touchstart', this.touchStartHandler, true); - document.addEventListener('touchend', this.handleRootMouseDown, true); - } - if (triggerElement !== null) { - this.scrollableAncestors = getScrollableAncestors(triggerElement); - } - this.addScrollHandling(dropdownElement); - return () => { - this.removeGlobalEvents(); - this.removeScrollHandling(); - this.scrollableAncestors = []; + if (dropdownIsValidParent(target, this.dropdownId)) { + this.touchMoveEvent = undefined; + return; + } - document.removeEventListener( + this.args.dropdown.actions.close(e, true); + }; + document.addEventListener( this.args.rootEventType, - this.handleRootMouseDown as RootMouseDownHandler, - true + this.handleRootMouseDown, + true, ); + window.addEventListener('resize', this.runloopAwareReposition); + window.addEventListener('orientationchange', this.runloopAwareReposition); if (this.isTouchDevice) { - document.removeEventListener('touchstart', this.touchStartHandler, true); + document.addEventListener('touchstart', this.touchStartHandler, true); + document.addEventListener('touchend', this.handleRootMouseDown, true); + } + if (triggerElement !== null) { + this.scrollableAncestors = getScrollableAncestors(triggerElement); + } + this.addScrollHandling(dropdownElement); + return () => { + this.removeGlobalEvents(); + this.removeScrollHandling(); + this.scrollableAncestors = []; + document.removeEventListener( - 'touchend', + this.args.rootEventType, this.handleRootMouseDown as RootMouseDownHandler, - true + true, ); - } - } - // @ts-ignore - }, { eager: false }); - - initiallyReposition = modifier(() => { - // Escape autotracking frame and avoid backtracking re-render - Promise.resolve().then(() => { - this.args.dropdown.actions.reposition() - }); - // @ts-ignore - }, { eager: false }); - animateInAndOut = modifier((dropdownElement: Element): () => void => { - if (!this.animationEnabled) return () => {}; - waitForAnimations(dropdownElement, () => { - this.animationClass = this.transitionedInClass; - }); - return () => { - if (!this.animationEnabled) return; - let parentElement = - dropdownElement.parentElement ?? this.destinationElement; - if (parentElement === null) return; - if (this.args.renderInPlace) { - parentElement = parentElement.parentElement; - } - if (parentElement === null) return; - let clone = dropdownElement.cloneNode(true) as Element; - clone.id = `${clone.id}--clone`; - clone.classList.remove(...this.transitioningInClass.split(' ')); - clone.classList.add(...this.transitioningOutClass.split(' ')); - parentElement.appendChild(clone); - this.animationClass = this.transitioningInClass; - waitForAnimations(clone, function () { - (parentElement as HTMLElement).removeChild(clone); + if (this.isTouchDevice) { + document.removeEventListener( + 'touchstart', + this.touchStartHandler, + true, + ); + document.removeEventListener( + 'touchend', + this.handleRootMouseDown as RootMouseDownHandler, + true, + ); + } + }; + }, + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + { eager: false }, + ); + + initiallyReposition = modifier( + () => { + // Escape autotracking frame and avoid backtracking re-render + Promise.resolve().then(() => { + this.args.dropdown.actions.reposition(); }); - }; - // @ts-ignore - }, { eager: false }); - - observeMutations = modifier((dropdownElement: Element): () => void => { - this.mutationObserver = new MutationObserver((mutations) => { - let shouldReposition = mutations.some( - (record: MutationRecord) => - containsRelevantMutation(record.addedNodes) || - containsRelevantMutation(record.removedNodes) - ); - - if (shouldReposition && this.args.shouldReposition) { - shouldReposition = this.args.shouldReposition( - mutations, - this.args.dropdown + }, + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + { eager: false }, + ); + + animateInAndOut = modifier( + (dropdownElement: Element): (() => void) => { + if (!this.animationEnabled) return () => {}; + waitForAnimations(dropdownElement, () => { + this.animationClass = this.transitionedInClass; + }); + return () => { + if (!this.animationEnabled) return; + let parentElement = + dropdownElement.parentElement ?? this.destinationElement; + if (parentElement === null) return; + if (this.args.renderInPlace) { + parentElement = parentElement.parentElement; + } + if (parentElement === null) return; + const clone = dropdownElement.cloneNode(true) as Element; + clone.id = `${clone.id}--clone`; + clone.classList.remove(...this.transitioningInClass.split(' ')); + clone.classList.add(...this.transitioningOutClass.split(' ')); + parentElement.appendChild(clone); + this.animationClass = this.transitioningInClass; + waitForAnimations(clone, function () { + (parentElement as HTMLElement).removeChild(clone); + }); + }; + }, + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + { eager: false }, + ); + + observeMutations = modifier( + (dropdownElement: Element): (() => void) => { + this.mutationObserver = new MutationObserver((mutations) => { + let shouldReposition = mutations.some( + (record: MutationRecord) => + containsRelevantMutation(record.addedNodes) || + containsRelevantMutation(record.removedNodes), ); - } - if (shouldReposition) { - this.runloopAwareReposition(); - } - }); - this.mutationObserver.observe(dropdownElement, { - childList: true, - subtree: true, - }); - return () => { - if (this.mutationObserver !== undefined) { - this.mutationObserver.disconnect(); - this.mutationObserver = undefined; - } - } - // @ts-ignore - }, { eager: false }); + if (shouldReposition && this.args.shouldReposition) { + shouldReposition = this.args.shouldReposition( + mutations, + this.args.dropdown, + ); + } + + if (shouldReposition) { + this.runloopAwareReposition(); + } + }); + this.mutationObserver.observe(dropdownElement, { + childList: true, + subtree: true, + }); + return () => { + if (this.mutationObserver !== undefined) { + this.mutationObserver.disconnect(); + this.mutationObserver = undefined; + } + }; + }, + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + { eager: false }, + ); @action touchStartHandler(): void { @@ -261,16 +282,16 @@ export default class BasicDropdownContent extends Component { + const wheelHandler = (event: WheelEvent) => { if (event.target === null) return; - let target = event.target as Element; + const target = event.target as Element; if ( dropdownElement.contains(target) || dropdownElement === event.target @@ -361,12 +382,12 @@ function containsRelevantMutation(nodeList: NodeList): boolean { // All ancestors with scroll (except the BODY, which is treated differently) function getScrollableAncestors(triggerElement: Element): Element[] { - let scrollableAncestors = []; + const scrollableAncestors = []; if (triggerElement) { - let parent = triggerElement.parentNode; + const parent = triggerElement.parentNode; if (parent !== null) { let nextScrollable: Element | undefined = getScrollParent( - parent as Element + parent as Element, ); while ( nextScrollable && @@ -374,7 +395,7 @@ function getScrollableAncestors(triggerElement: Element): Element[] { nextScrollable.tagName.toUpperCase() !== 'HTML' ) { scrollableAncestors.push(nextScrollable); - let nextParent = nextScrollable.parentNode; + const nextParent = nextScrollable.parentNode; if (nextParent === null) { nextScrollable = undefined; } else { @@ -397,14 +418,15 @@ function closestContent(el: Element): Element | null { return el; } +// eslint-disable-next-line @typescript-eslint/ban-types function waitForAnimations(element: Element, callback: Function): void { window.requestAnimationFrame(function () { - let computedStyle = window.getComputedStyle(element); + const computedStyle = window.getComputedStyle(element); if ( computedStyle.animationName !== 'none' && computedStyle.animationPlayState === 'running' ) { - let eventCallback = function () { + const eventCallback = function () { element.removeEventListener('animationend', eventCallback); callback(); }; @@ -422,18 +444,20 @@ function waitForAnimations(element: Element, callback: Function): void { * @param {String} dropdownId */ function dropdownIsValidParent(el: Element, dropdownId: string): boolean { - let closestDropdown = closestContent(el); + const closestDropdown = closestContent(el); if (closestDropdown === null) { return false; } else { - let closestAttrs = closestDropdown.attributes as unknown as any; - let trigger = document.querySelector( - `[aria-controls=${closestAttrs.id.value}]` + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const closestAttrs = closestDropdown.attributes as unknown as any; + const trigger = document.querySelector( + `[aria-controls=${closestAttrs.id.value}]`, ); if (trigger === null) return false; - let parentDropdown = closestContent(trigger); + const parentDropdown = closestContent(trigger); if (parentDropdown === null) return false; - let parentAttrs = parentDropdown.attributes as unknown as any; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const parentAttrs = parentDropdown.attributes as unknown as any; return ( (parentDropdown && parentAttrs.id.value === dropdownId) || dropdownIsValidParent(parentDropdown, dropdownId) diff --git a/ember-basic-dropdown/src/components/basic-dropdown-trigger.ts b/ember-basic-dropdown/src/components/basic-dropdown-trigger.ts index 07c85373..009969ce 100644 --- a/ember-basic-dropdown/src/components/basic-dropdown-trigger.ts +++ b/ember-basic-dropdown/src/components/basic-dropdown-trigger.ts @@ -47,7 +47,7 @@ export default class BasicDropdownTrigger extends Component void; close: (e?: Event, skipFocus?: boolean) => void; open: (e?: Event) => void; + // eslint-disable-next-line @typescript-eslint/no-explicit-any reposition: (...args: any[]) => undefined | RepositionChanges; } export interface Dropdown { @@ -45,11 +43,17 @@ interface Args { rootEventType?: string; preventScroll?: boolean; matchTriggerWidth?: boolean; + // eslint-disable-next-line @typescript-eslint/ban-types onInit?: Function; + // eslint-disable-next-line @typescript-eslint/ban-types registerAPI?: Function; + // eslint-disable-next-line @typescript-eslint/ban-types onOpen?: Function; + // eslint-disable-next-line @typescript-eslint/ban-types onClose?: Function; + // eslint-disable-next-line @typescript-eslint/no-explicit-any triggerComponent: string | ComponentLike; + // eslint-disable-next-line @typescript-eslint/no-explicit-any contentComponent: string | ComponentLike; calculatePosition?: CalculatePosition; Blocks: { @@ -108,18 +112,20 @@ export default class BasicDropdown extends Component { } get disabled(): boolean { - let newVal = this.args.disabled || false; + const newVal = this.args.disabled || false; if ( this._previousDisabled !== UNINITIALIZED && this._previousDisabled !== newVal ) { schedule('actions', () => { if (newVal && this.publicAPI.isOpen) { + // eslint-disable-next-line ember/no-side-effects this.isOpen = false; } this.args.registerAPI && this.args.registerAPI(this.publicAPI); }); } + // eslint-disable-next-line ember/no-side-effects this._previousDisabled = newVal; return newVal; } @@ -163,12 +169,14 @@ export default class BasicDropdown extends Component { } this.isOpen = true; this.args.registerAPI && this.args.registerAPI(this.publicAPI); - let trigger = document.querySelector( - `[data-ebd-id=${this.publicAPI.uniqueId}-trigger]` + const trigger = document.querySelector( + `[data-ebd-id=${this.publicAPI.uniqueId}-trigger]`, ) as HTMLElement; if (trigger) { - let parent = trigger.parentElement; - if (parent) { parent.setAttribute("aria-owns", this._dropdownId); } + const parent = trigger.parentElement; + if (parent) { + parent.setAttribute('aria-owns', this._dropdownId); + } } } @@ -191,14 +199,16 @@ export default class BasicDropdown extends Component { this.previousVerticalPosition = this.previousHorizontalPosition = undefined; this.isOpen = false; this.args.registerAPI && this.args.registerAPI(this.publicAPI); - let trigger = document.querySelector( - `[data-ebd-id=${this.publicAPI.uniqueId}-trigger]` + const trigger = document.querySelector( + `[data-ebd-id=${this.publicAPI.uniqueId}-trigger]`, ) as HTMLElement; if (!trigger) { return; } - let parent = trigger.parentElement; - if (parent) { parent.removeAttribute("aria-owns"); } + const parent = trigger.parentElement; + if (parent) { + parent.removeAttribute('aria-owns'); + } if (skipFocus) { return; } @@ -221,9 +231,9 @@ export default class BasicDropdown extends Component { if (!this.publicAPI.isOpen) { return; } - let dropdownElement = document.getElementById(this._dropdownId); - let triggerElement = document.querySelector( - `[data-ebd-id=${this.publicAPI.uniqueId}-trigger]` + const dropdownElement = document.getElementById(this._dropdownId); + const triggerElement = document.querySelector( + `[data-ebd-id=${this.publicAPI.uniqueId}-trigger]`, ) as HTMLElement; if (!dropdownElement || !triggerElement) { return; @@ -232,15 +242,16 @@ export default class BasicDropdown extends Component { this.destinationElement = this.destinationElement || (document.getElementById(this.destination) as HTMLElement); - let { + const { horizontalPosition, verticalPosition, previousHorizontalPosition, previousVerticalPosition, } = this; - let { renderInPlace = false, matchTriggerWidth = false } = this.args; - let calculatePositionFn = this.args.calculatePosition || calculatePosition; - let positionData = calculatePositionFn( + const { renderInPlace = false, matchTriggerWidth = false } = this.args; + const calculatePositionFn = + this.args.calculatePosition || calculatePosition; + const positionData = calculatePositionFn( triggerElement, dropdownElement, this.destinationElement, @@ -252,7 +263,7 @@ export default class BasicDropdown extends Component { renderInPlace, matchTriggerWidth, dropdown: this, - } + }, ); return this.applyReposition(triggerElement, dropdownElement, positionData); } @@ -260,9 +271,9 @@ export default class BasicDropdown extends Component { applyReposition( _trigger: Element, dropdown: HTMLElement, - positions: CalculatePositionResult + positions: CalculatePositionResult, ): RepositionChanges { - let changes: RepositionChanges = { + const changes: RepositionChanges = { hPosition: positions.horizontalPosition, vPosition: positions.verticalPosition, otherStyles: Object.assign({}, this.otherStyles), @@ -292,7 +303,7 @@ export default class BasicDropdown extends Component { } if (this.top === undefined) { // Bypass Ember on the first reposition only to avoid flickering. - for (let prop in positions.style) { + for (const prop in positions.style) { if (positions.style[prop] !== undefined) { if (typeof positions.style[prop] === 'number') { dropdown.style.setProperty(prop, `${positions.style[prop]}px`); @@ -303,7 +314,7 @@ export default class BasicDropdown extends Component { } } } - for (let prop in positions.style) { + for (const prop in positions.style) { if (!IGNORED_STYLES.includes(prop)) { changes.otherStyles; changes.otherStyles[prop] = positions.style[prop]; @@ -328,7 +339,8 @@ export default class BasicDropdown extends Component { if (macroCondition(isTesting())) { if (typeof FastBoot === 'undefined') { try { - let { getRootElement } = importSync('@ember/test-helpers') as any; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const { getRootElement } = importSync('@ember/test-helpers') as any; return getRootElement().id; } catch (error) { @@ -336,7 +348,7 @@ export default class BasicDropdown extends Component { } } - let rootView = document.querySelector('#ember-testing > .ember-view'); + const rootView = document.querySelector('#ember-testing > .ember-view'); if (rootView) { return rootView.id; } @@ -344,10 +356,11 @@ export default class BasicDropdown extends Component { return ''; } + // eslint-disable-next-line @typescript-eslint/no-explicit-any const _config = config as unknown as any; return ((_config['ember-basic-dropdown'] && - _config['ember-basic-dropdown'].destination) || + _config['ember-basic-dropdown'].destination) || 'ember-basic-dropdown-wormhole') as string; } } diff --git a/ember-basic-dropdown/src/modifiers/basic-dropdown-trigger.ts b/ember-basic-dropdown/src/modifiers/basic-dropdown-trigger.ts index 90f976c8..afc50e84 100644 --- a/ember-basic-dropdown/src/modifiers/basic-dropdown-trigger.ts +++ b/ember-basic-dropdown/src/modifiers/basic-dropdown-trigger.ts @@ -1,5 +1,5 @@ import Modifier, { ArgsFor, PositionalArgs, NamedArgs } from 'ember-modifier'; -import { assert } from '@ember/debug' +import { assert } from '@ember/debug'; import { action } from '@ember/object'; import { isDestroyed, registerDestructor } from '@ember/destroyable'; import hasMoved from '../utils/has-moved.ts'; @@ -27,31 +27,35 @@ export default class DropdownTriggerModifier extends Modifier { toggleIsBeingHandledByTouchEvents: boolean = false; touchMoveEvent: TouchEvent | undefined; - dropdown!: Dropdown - desiredEventType!: string - stopPropagation: boolean | undefined + dropdown!: Dropdown; + desiredEventType!: string; + stopPropagation: boolean | undefined; constructor(owner: Owner, args: ArgsFor) { - super(owner, args) - registerDestructor(this, cleanup) + super(owner, args); + registerDestructor(this, cleanup); } - override modify(element: HTMLElement, positional: PositionalArgs, named: NamedArgs): void { - assert('must be provided dropdown object', named.dropdown) - this.dropdown = named.dropdown - this.desiredEventType = named.eventType ?? 'click' - this.stopPropagation = named.stopPropagation + override modify( + element: HTMLElement, + positional: PositionalArgs, + named: NamedArgs, + ): void { + assert('must be provided dropdown object', named.dropdown); + this.dropdown = named.dropdown; + this.desiredEventType = named.eventType ?? 'click'; + this.stopPropagation = named.stopPropagation; if (!this.didSetup) { - this.setup(element) - this.didSetup = true + this.setup(element); + this.didSetup = true; } - this.update(element, positional, named) + this.update(element, positional, named); } setup(element: HTMLElement) { // Keep a reference to the element for cleanup - this.triggerElement = element + this.triggerElement = element; if (!element.getAttribute('role')) element.setAttribute('role', 'button'); @@ -62,12 +66,22 @@ export default class DropdownTriggerModifier extends Modifier { element.addEventListener('touchend', this.handleTouchEnd); } - update(element: HTMLElement, _positional: PositionalArgs, named: NamedArgs) { - const { dropdown } = named + update( + element: HTMLElement, + _positional: PositionalArgs, + named: NamedArgs, + ) { + const { dropdown } = named; element.setAttribute('data-ebd-id', `${dropdown.uniqueId}-trigger`); - element.setAttribute('aria-owns', `ember-basic-dropdown-content-${dropdown.uniqueId}`); - element.setAttribute('aria-controls', `ember-basic-dropdown-content-${dropdown.uniqueId}`); + element.setAttribute( + 'aria-owns', + `ember-basic-dropdown-content-${dropdown.uniqueId}`, + ); + element.setAttribute( + 'aria-controls', + `ember-basic-dropdown-content-${dropdown.uniqueId}`, + ); element.setAttribute('aria-expanded', dropdown.isOpen ? 'true' : 'false'); element.setAttribute('aria-disabled', dropdown.disabled ? 'true' : 'false'); } @@ -82,7 +96,7 @@ export default class DropdownTriggerModifier extends Modifier { const eventType = e.type; const notLeftClick = e.button !== 0; if (eventType !== desiredEventType || notLeftClick) return; - + if (stopPropagation) e.stopPropagation(); if (this.toggleIsBeingHandledByTouchEvents) { @@ -100,9 +114,11 @@ export default class DropdownTriggerModifier extends Modifier { const { disabled, actions } = this.dropdown; if (disabled) return; - if (e.keyCode === 13) { // Enter + if (e.keyCode === 13) { + // Enter actions.toggle(e); - } else if (e.keyCode === 32) { // Space + } else if (e.keyCode === 32) { + // Space e.preventDefault(); // prevents the space to trigger a scroll page-next actions.toggle(e); } else if (e.keyCode === 27) { @@ -134,11 +150,29 @@ export default class DropdownTriggerModifier extends Modifier { if (target !== null) { target.focus(); } - setTimeout(function() { - if (!e.target) { return; } + setTimeout(function () { + if (!e.target) { + return; + } try { const event = document.createEvent('MouseEvents'); - event.initMouseEvent('click', true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null); + event.initMouseEvent( + 'click', + true, + true, + window, + 0, + 0, + 0, + 0, + 0, + false, + false, + false, + false, + 0, + null, + ); e.target.dispatchEvent(event); } catch { const event = new Event('click'); @@ -156,9 +190,10 @@ export default class DropdownTriggerModifier extends Modifier { } function cleanup(instance: DropdownTriggerModifier) { - const { triggerElement } = instance + const { triggerElement } = instance; if (triggerElement) { - if (typeof document !== 'undefined') document.removeEventListener('touchmove', instance._touchMoveHandler); + if (typeof document !== 'undefined') + document.removeEventListener('touchmove', instance._touchMoveHandler); triggerElement.removeEventListener('click', instance.handleMouseEvent); triggerElement.removeEventListener('mousedown', instance.handleMouseEvent); @@ -166,4 +201,4 @@ function cleanup(instance: DropdownTriggerModifier) { triggerElement.removeEventListener('touchstart', instance.handleTouchStart); triggerElement.removeEventListener('touchend', instance.handleTouchEnd); } -} \ No newline at end of file +} diff --git a/ember-basic-dropdown/src/utils/calculate-position.ts b/ember-basic-dropdown/src/utils/calculate-position.ts index 83189677..1b4d6cd6 100644 --- a/ember-basic-dropdown/src/utils/calculate-position.ts +++ b/ember-basic-dropdown/src/utils/calculate-position.ts @@ -5,6 +5,7 @@ interface CalculatePositionOptions { previousHorizontalPosition?: string | undefined; previousVerticalPosition?: string | undefined; renderInPlace: boolean; + // eslint-disable-next-line @typescript-eslint/no-explicit-any dropdown: any; } export type CalculatePositionResultStyle = { @@ -24,10 +25,10 @@ export type CalculatePosition = ( trigger: Element, content: HTMLElement, destination: HTMLElement, - options: CalculatePositionOptions + options: CalculatePositionOptions, ) => CalculatePositionResult; -export let calculateWormholedPosition: CalculatePosition = ( +export const calculateWormholedPosition: CalculatePosition = ( trigger, content, destination, @@ -37,20 +38,17 @@ export let calculateWormholedPosition: CalculatePosition = ( matchTriggerWidth, previousHorizontalPosition, previousVerticalPosition, - } + }, ) => { // Collect information about all the involved DOM elements - let scroll = { left: window.pageXOffset, top: window.pageYOffset }; - let { - left: triggerLeft, - top: triggerTop, - width: triggerWidth, - height: triggerHeight, - } = trigger.getBoundingClientRect(); - let { height: dropdownHeight, width: dropdownWidth } = - content.getBoundingClientRect(); - let viewportWidth = document.body.clientWidth || window.innerWidth; - let style: CalculatePositionResultStyle = {}; + const scroll = { left: window.pageXOffset, top: window.pageYOffset }; + let { left: triggerLeft, top: triggerTop } = trigger.getBoundingClientRect(); + const { width: triggerWidth, height: triggerHeight } = + trigger.getBoundingClientRect(); + const { height: dropdownHeight } = content.getBoundingClientRect(); + let { width: dropdownWidth } = content.getBoundingClientRect(); + const viewportWidth = document.body.clientWidth || window.innerWidth; + const style: CalculatePositionResultStyle = {}; // Apply containers' offset let anchorElement = destination.parentNode as HTMLElement; @@ -64,10 +62,10 @@ export let calculateWormholedPosition: CalculatePosition = ( anchorPosition = window.getComputedStyle(anchorElement).position; } if (anchorPosition === 'relative' || anchorPosition === 'absolute') { - let rect = anchorElement.getBoundingClientRect(); + const rect = anchorElement.getBoundingClientRect(); triggerLeft = triggerLeft - rect.left; triggerTop = triggerTop - rect.top; - let { offsetParent } = anchorElement; + const { offsetParent } = anchorElement; if (offsetParent) { triggerLeft -= offsetParent.scrollLeft; triggerTop -= offsetParent.scrollTop; @@ -81,14 +79,14 @@ export let calculateWormholedPosition: CalculatePosition = ( } // Calculate horizontal position - let triggerLeftWithScroll = triggerLeft + scroll.left; + const triggerLeftWithScroll = triggerLeft + scroll.left; if (horizontalPosition === 'auto' || horizontalPosition === 'auto-left') { // Calculate the number of visible horizontal pixels if we were to place the // dropdown on the left and right - let leftVisible = + const leftVisible = Math.min(viewportWidth, triggerLeft + dropdownWidth) - Math.max(0, triggerLeft); - let rightVisible = + const rightVisible = Math.min(viewportWidth, triggerLeft + triggerWidth) - Math.max(0, triggerLeft + triggerWidth - dropdownWidth); @@ -107,10 +105,10 @@ export let calculateWormholedPosition: CalculatePosition = ( } else if (horizontalPosition === 'auto-right') { // Calculate the number of visible horizontal pixels if we were to place the // dropdown on the left and right - let leftVisible = + const leftVisible = Math.min(viewportWidth, triggerLeft + dropdownWidth) - Math.max(0, triggerLeft); - let rightVisible = + const rightVisible = Math.min(viewportWidth, triggerLeft + triggerWidth) - Math.max(0, triggerLeft + triggerWidth - dropdownWidth); @@ -142,7 +140,7 @@ export let calculateWormholedPosition: CalculatePosition = ( * Fixes bug where the dropdown always stays on the same position on the screen when * the is relatively positioned */ - let isBodyPositionRelative = + const isBodyPositionRelative = window.getComputedStyle(document.body).getPropertyValue('position') === 'relative'; if (!isBodyPositionRelative) { @@ -154,10 +152,10 @@ export let calculateWormholedPosition: CalculatePosition = ( } else if (verticalPosition === 'below') { style.top = triggerTopWithScroll + triggerHeight; } else { - let viewportBottom = scroll.top + window.innerHeight; - let enoughRoomBelow = + const viewportBottom = scroll.top + window.innerHeight; + const enoughRoomBelow = triggerTopWithScroll + triggerHeight + dropdownHeight < viewportBottom; - let enoughRoomAbove = triggerTop > dropdownHeight; + const enoughRoomAbove = triggerTop > dropdownHeight; if (!enoughRoomBelow && !enoughRoomAbove) { verticalPosition = 'below'; @@ -186,31 +184,31 @@ export let calculateWormholedPosition: CalculatePosition = ( return { horizontalPosition, verticalPosition, style }; }; -export let calculateInPlacePosition: CalculatePosition = ( +export const calculateInPlacePosition: CalculatePosition = ( trigger, content, _destination, - { horizontalPosition, verticalPosition } + { horizontalPosition, verticalPosition }, ) => { let dropdownRect; - let positionData: CalculatePositionResult = { + const positionData: CalculatePositionResult = { horizontalPosition: 'left', verticalPosition: 'below', style: {}, }; if (horizontalPosition === 'auto') { - let triggerRect = trigger.getBoundingClientRect(); + const triggerRect = trigger.getBoundingClientRect(); dropdownRect = content.getBoundingClientRect(); - let viewportRight = window.pageXOffset + window.innerWidth; + const viewportRight = window.pageXOffset + window.innerWidth; positionData.horizontalPosition = triggerRect.left + dropdownRect.width > viewportRight ? 'right' : 'left'; } else if (horizontalPosition === 'center') { - let { width: triggerWidth } = trigger.getBoundingClientRect(); - let { width: dropdownWidth } = content.getBoundingClientRect(); + const { width: triggerWidth } = trigger.getBoundingClientRect(); + const { width: dropdownWidth } = content.getBoundingClientRect(); positionData.style = { left: (triggerWidth - dropdownWidth) / 2 }; } else if (horizontalPosition === 'auto-right') { - let triggerRect = trigger.getBoundingClientRect(); - let dropdownRect = content.getBoundingClientRect(); + const triggerRect = trigger.getBoundingClientRect(); + const dropdownRect = content.getBoundingClientRect(); positionData.horizontalPosition = triggerRect.right > dropdownRect.width ? 'right' : 'left'; } else if (horizontalPosition === 'right') { @@ -229,8 +227,8 @@ export let calculateInPlacePosition: CalculatePosition = ( export function getScrollParent(element: Element) { let style = window.getComputedStyle(element); - let excludeStaticParent = style.position === 'absolute'; - let overflowRegex = /(auto|scroll)/; + const excludeStaticParent = style.position === 'absolute'; + const overflowRegex = /(auto|scroll)/; if (style.position === 'fixed') return document.body; for ( @@ -251,11 +249,11 @@ export function getScrollParent(element: Element) { return document.body; } -let calculatePosition: CalculatePosition = ( +const calculatePosition: CalculatePosition = ( trigger, content, destination, - options + options, ) => { if (options.renderInPlace) { return calculateInPlacePosition(trigger, content, destination, options); diff --git a/ember-basic-dropdown/src/utils/has-moved.ts b/ember-basic-dropdown/src/utils/has-moved.ts index 5aa87759..91f615a7 100644 --- a/ember-basic-dropdown/src/utils/has-moved.ts +++ b/ember-basic-dropdown/src/utils/has-moved.ts @@ -8,17 +8,20 @@ export default function hasMoved( if ( !endEvent.changedTouches?.[0] || + // eslint-disable-next-line @typescript-eslint/no-explicit-any (moveEvent.changedTouches[0] as any).touchType !== 'stylus' ) { return true; } // Distinguish stylus scroll and tap: if touch "distance" < 5px, we consider it a tap - let horizontalDistance = Math.abs( - (moveEvent.changedTouches[0]?.pageX ?? 0) - endEvent.changedTouches[0].pageX + const horizontalDistance = Math.abs( + (moveEvent.changedTouches[0]?.pageX ?? 0) - + endEvent.changedTouches[0].pageX, ); - let verticalDistance = Math.abs( - (moveEvent.changedTouches[0]?.pageY ?? 0) - endEvent.changedTouches[0].pageY + const verticalDistance = Math.abs( + (moveEvent.changedTouches[0]?.pageY ?? 0) - + endEvent.changedTouches[0].pageY, ); return horizontalDistance >= 5 || verticalDistance >= 5; } diff --git a/ember-basic-dropdown/src/utils/scroll-helpers.ts b/ember-basic-dropdown/src/utils/scroll-helpers.ts index f929c7f1..85afedc9 100644 --- a/ember-basic-dropdown/src/utils/scroll-helpers.ts +++ b/ember-basic-dropdown/src/utils/scroll-helpers.ts @@ -72,10 +72,11 @@ export function getScrollLineHeight(): number | undefined { const iframeDocument = (iframe.contentWindow as Window).document; iframeDocument.open(); iframeDocument.write( - 'X' + 'X', ); iframeDocument.close(); - let body = iframeDocument.body as unknown as any; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const body = iframeDocument.body as unknown as any; scrollLineHeight = (body.firstElementChild as HTMLElement).offsetHeight; document.body.removeChild(iframe); } @@ -99,7 +100,7 @@ export function getAvailableScroll(element: Element, container: Element) { availableScroll.deltaXPositive += scrollLeftMax - element.scrollLeft; availableScroll.deltaYNegative += -element.scrollTop; availableScroll.deltaYPositive += scrollTopMax - element.scrollTop; - let parent = element.parentNode; + const parent = element.parentNode; if (parent === null) break; element = parent as Element; } @@ -115,7 +116,7 @@ function calculateScrollDistribution( deltaY: number, element: Element, container: Element, - accumulator: ScrollInformation[] = [] + accumulator: ScrollInformation[] = [], ): ScrollInformation[] { const scrollInformation: ScrollInformation = { element, @@ -166,7 +167,7 @@ function calculateScrollDistribution( deltaY, element.parentNode as Element, container, - accumulator.concat([scrollInformation]) + accumulator.concat([scrollInformation]), ); }