mirror of
https://github.com/tabler/tabler.git
synced 2026-10-12 05:06:55 +04:00
Add ESLint with typescript-eslint and fix its findings (#3256)
This commit is contained in:
1 parent
0e90f8fd16
commit
6394af0a59
40 files changed
+935
-339
No files matched your search
@@ -44,7 +44,7 @@ class Button extends BaseComponent {
|
||||
EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, (event: Event) => {
|
||||
event.preventDefault()
|
||||
|
||||
const target = (event.target as HTMLElement)?.closest(SELECTOR_DATA_TOGGLE) as HTMLElement | null
|
||||
const target = (event.target as HTMLElement)?.closest<HTMLElement>(SELECTOR_DATA_TOGGLE)
|
||||
if (!target) {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -297,7 +297,7 @@ class Carousel extends BaseComponent {
|
||||
|
||||
const activeElement = this._getActive()
|
||||
const isNext = order === ORDER_NEXT
|
||||
const nextElement = element || (getNextActiveElement(this._getItems(), activeElement!, isNext, this._config.wrap as boolean) as HTMLElement)
|
||||
const nextElement = element || getNextActiveElement<HTMLElement>(this._getItems(), activeElement!, isNext, this._config.wrap)
|
||||
|
||||
if (nextElement === activeElement) {
|
||||
return
|
||||
|
||||
@@ -16,7 +16,6 @@ const Data = {
|
||||
const instanceMap = elementMap.get(element)!
|
||||
|
||||
if (!instanceMap.has(key) && instanceMap.size !== 0) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error(`Bootstrap doesn't allow more than one instance per element. Bound instance: ${Array.from(instanceMap.keys())[0]}.`)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -106,7 +106,7 @@ function bootstrapHandler(element: EventTarget, fn: EventCallback): BootstrapHan
|
||||
}
|
||||
|
||||
return fn.apply(element as HTMLElement, [event])
|
||||
} as BootstrapHandler
|
||||
}
|
||||
}
|
||||
|
||||
function bootstrapDelegationHandler(element: EventTarget, selector: string, fn: EventCallback): BootstrapHandler {
|
||||
@@ -128,7 +128,7 @@ function bootstrapDelegationHandler(element: EventTarget, selector: string, fn:
|
||||
return fn.apply(target as HTMLElement, [event])
|
||||
}
|
||||
}
|
||||
} as BootstrapHandler
|
||||
}
|
||||
}
|
||||
|
||||
function findHandler(events: Record<string | number, BootstrapHandler>, callable: EventCallback, delegationSelector: string | null = null): BootstrapHandler | undefined {
|
||||
|
||||
@@ -29,7 +29,7 @@ function normalizeData(value: string): DataValue {
|
||||
}
|
||||
|
||||
try {
|
||||
return JSON.parse(decodeURIComponent(value))
|
||||
return JSON.parse(decodeURIComponent(value)) as DataValue
|
||||
} catch {
|
||||
return value
|
||||
}
|
||||
|
||||
@@ -123,7 +123,11 @@ class Dropdown extends BaseComponent {
|
||||
}
|
||||
|
||||
toggle(): void {
|
||||
this._isShown() ? this.hide() : this.show()
|
||||
if (this._isShown()) {
|
||||
this.hide()
|
||||
} else {
|
||||
this.show()
|
||||
}
|
||||
}
|
||||
|
||||
show(): void {
|
||||
@@ -180,7 +184,7 @@ class Dropdown extends BaseComponent {
|
||||
update(): void {
|
||||
this._inNavbar = this._detectNavbar()
|
||||
if (this._popper) {
|
||||
this._popper.update()
|
||||
void this._popper.update()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -210,7 +214,7 @@ class Dropdown extends BaseComponent {
|
||||
_getConfig(config?: ComponentConfigInput): ComponentConfig {
|
||||
const merged = super._getConfig(config) as ComponentConfig
|
||||
|
||||
if (typeof merged.reference === 'object' && !isElement(merged.reference) && typeof (merged.reference as Popper.VirtualElement).getBoundingClientRect !== 'function') {
|
||||
if (typeof merged.reference === 'object' && !isElement(merged.reference) && typeof merged.reference.getBoundingClientRect !== 'function') {
|
||||
throw new TypeError(`${NAME.toUpperCase()}: Option "reference" provided type "object" without a required "getBoundingClientRect" method.`)
|
||||
}
|
||||
|
||||
@@ -227,9 +231,9 @@ class Dropdown extends BaseComponent {
|
||||
if (this._config.reference === 'parent') {
|
||||
referenceElement = this._parent
|
||||
} else if (isElement(this._config.reference)) {
|
||||
referenceElement = getElement(this._config.reference as HTMLElement | string)!
|
||||
referenceElement = getElement(this._config.reference)!
|
||||
} else if (typeof this._config.reference === 'object') {
|
||||
referenceElement = this._config.reference as Popper.VirtualElement
|
||||
referenceElement = this._config.reference
|
||||
}
|
||||
|
||||
const popperConfig = this._getPopperConfig()
|
||||
@@ -383,7 +387,7 @@ class Dropdown extends BaseComponent {
|
||||
|
||||
const getToggleButton = this.matches(SELECTOR_DATA_TOGGLE) ? this : SelectorEngine.prev(this, SELECTOR_DATA_TOGGLE)[0] || SelectorEngine.next(this, SELECTOR_DATA_TOGGLE)[0] || SelectorEngine.findOne(SELECTOR_DATA_TOGGLE, (event as DelegatedEvent<KeyboardEvent>).delegateTarget.parentNode as Element)
|
||||
|
||||
const instance = Dropdown.getOrCreateInstance(getToggleButton!) as Dropdown
|
||||
const instance = Dropdown.getOrCreateInstance(getToggleButton) as Dropdown
|
||||
|
||||
if (isUpOrDownEvent) {
|
||||
event.stopPropagation()
|
||||
@@ -395,7 +399,7 @@ class Dropdown extends BaseComponent {
|
||||
if (instance._isShown()) {
|
||||
event.stopPropagation()
|
||||
instance.hide()
|
||||
getToggleButton!.focus()
|
||||
getToggleButton.focus()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -137,9 +137,9 @@ class ScrollSpy extends BaseComponent {
|
||||
return
|
||||
}
|
||||
|
||||
EventHandler.off(this._config.target as HTMLElement, EVENT_CLICK)
|
||||
EventHandler.off(this._config.target, EVENT_CLICK)
|
||||
|
||||
EventHandler.on(this._config.target as HTMLElement, EVENT_CLICK, SELECTOR_TARGET_LINKS, (event: Event) => {
|
||||
EventHandler.on(this._config.target, EVENT_CLICK, SELECTOR_TARGET_LINKS, (event: Event) => {
|
||||
const observableSection = this._observableSections.get((event.target as HTMLAnchorElement).hash)
|
||||
if (observableSection) {
|
||||
event.preventDefault()
|
||||
@@ -158,8 +158,8 @@ class ScrollSpy extends BaseComponent {
|
||||
_getNewObserver(): IntersectionObserver {
|
||||
const options: IntersectionObserverInit = {
|
||||
root: this._rootElement,
|
||||
threshold: this._config.threshold as number[],
|
||||
rootMargin: this._config.rootMargin as string,
|
||||
threshold: this._config.threshold,
|
||||
rootMargin: this._config.rootMargin,
|
||||
}
|
||||
|
||||
return new IntersectionObserver((entries) => this._observerCallback(entries), options)
|
||||
|
||||
@@ -153,7 +153,7 @@ class Tab extends BaseComponent {
|
||||
nextActiveElement = children[event.key === HOME_KEY ? 0 : children.length - 1]
|
||||
} else {
|
||||
const isNext = [ARROW_RIGHT_KEY, ARROW_DOWN_KEY].includes(event.key)
|
||||
nextActiveElement = getNextActiveElement(children, event.target as HTMLElement, isNext, true) as HTMLElement
|
||||
nextActiveElement = getNextActiveElement<HTMLElement>(children, event.target as HTMLElement, isNext, true)
|
||||
}
|
||||
|
||||
if (nextActiveElement) {
|
||||
|
||||
@@ -138,7 +138,7 @@ class Tooltip extends BaseComponent {
|
||||
declare _element: HTMLElement
|
||||
declare _config: ComponentConfig
|
||||
_isEnabled: boolean
|
||||
_timeout: ReturnType<typeof setTimeout> | number
|
||||
_timeout: ReturnType<typeof setTimeout>
|
||||
_isHovered: boolean | null
|
||||
_activeTrigger: Record<string, boolean>
|
||||
_popper: Popper.Instance | null
|
||||
@@ -259,7 +259,7 @@ class Tooltip extends BaseComponent {
|
||||
|
||||
this._popper = this._createPopper(tip)
|
||||
|
||||
tip!.classList.add(CLASS_NAME_SHOW)
|
||||
tip.classList.add(CLASS_NAME_SHOW)
|
||||
|
||||
if ('ontouchstart' in document.documentElement) {
|
||||
for (const element of Array.from(document.body.children)) {
|
||||
@@ -322,7 +322,7 @@ class Tooltip extends BaseComponent {
|
||||
|
||||
update(): void {
|
||||
if (this._popper) {
|
||||
this._popper.update()
|
||||
void this._popper.update()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -511,7 +511,7 @@ class Tooltip extends BaseComponent {
|
||||
return
|
||||
}
|
||||
|
||||
if (!this._element.getAttribute('aria-label') && !this._element.textContent!.trim()) {
|
||||
if (!this._element.getAttribute('aria-label') && !this._element.textContent.trim()) {
|
||||
this._element.setAttribute('aria-label', title)
|
||||
}
|
||||
|
||||
|
||||
@@ -34,13 +34,13 @@ class Config {
|
||||
}
|
||||
|
||||
_mergeConfigObj(config?: ComponentConfig, element?: HTMLElement): ComponentConfig {
|
||||
const jsonConfig = isElement(element) ? Manipulator.getDataAttribute(element!, 'config') : {}
|
||||
const jsonConfig = isElement(element) ? Manipulator.getDataAttribute(element, 'config') : {}
|
||||
const ctor = this.constructor as unknown as ConfigStatic
|
||||
|
||||
return {
|
||||
...ctor.Default,
|
||||
...(typeof jsonConfig === 'object' ? jsonConfig : {}),
|
||||
...(isElement(element) ? Manipulator.getDataAttributes(element!) : {}),
|
||||
...(isElement(element) ? Manipulator.getDataAttributes(element) : {}),
|
||||
...(typeof config === 'object' ? config : {}),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,7 +94,7 @@ class FocusTrap extends Config {
|
||||
const elements = SelectorEngine.focusableChildren(trapElement)
|
||||
|
||||
if (elements.length === 0) {
|
||||
trapElement!.focus()
|
||||
trapElement.focus()
|
||||
} else if (this._lastTabNavDirection === TAB_NAV_BACKWARD) {
|
||||
elements[elements.length - 1].focus()
|
||||
} else {
|
||||
|
||||
@@ -13,7 +13,7 @@ const TRANSITION_END = 'transitionend'
|
||||
|
||||
const parseSelector = (selector: string): string => {
|
||||
if (selector && typeof CSS !== 'undefined' && typeof CSS.escape === 'function') {
|
||||
selector = selector.replace(/#([^\s"#']+)/g, (match, id) => `#${CSS.escape(id)}`)
|
||||
selector = selector.replace(/#([^\s"#']+)/g, (_match: string, id: string) => `#${CSS.escape(id)}`)
|
||||
}
|
||||
|
||||
return selector
|
||||
@@ -166,7 +166,7 @@ const noop = (): void => {}
|
||||
* @see https://www.harrytheo.com/blog/2021/02/restart-a-css-animation-with-javascript/#restarting-a-css-animation
|
||||
*/
|
||||
const reflow = (element: HTMLElement): void => {
|
||||
element.offsetHeight // eslint-disable-line no-unused-expressions
|
||||
element.offsetHeight // eslint-disable-line @typescript-eslint/no-unused-expressions
|
||||
}
|
||||
|
||||
const isRTL = (): boolean => document.documentElement.dir === 'rtl'
|
||||
|
||||
@@ -62,7 +62,7 @@ const allowedAttribute = (attribute: Attr, allowedAttributeList: (string | RegEx
|
||||
return true
|
||||
}
|
||||
|
||||
return allowedAttributeList.filter((attributeRegex) => attributeRegex instanceof RegExp).some((regex) => (regex as RegExp).test(attributeName))
|
||||
return allowedAttributeList.filter((attributeRegex) => attributeRegex instanceof RegExp).some((regex) => regex.test(attributeName))
|
||||
}
|
||||
|
||||
export function sanitizeHtml(unsafeHtml: string, allowList: AllowList, sanitizeFunction?: SanitizeFn): string {
|
||||
|
||||
@@ -81,6 +81,8 @@ class ScrollBarHelper {
|
||||
}
|
||||
|
||||
Manipulator.removeDataAttribute(element, styleProperty)
|
||||
// The attribute holds the CSS value `_saveInitialAttribute()` stored
|
||||
// eslint-disable-next-line @typescript-eslint/no-base-to-string
|
||||
element.style.setProperty(styleProperty, String(value))
|
||||
}
|
||||
|
||||
|
||||
@@ -273,7 +273,7 @@ const stage = {
|
||||
}
|
||||
|
||||
for (let i = this.particles.length - 1; i >= 0; i--) {
|
||||
const p = this.particles[i]!
|
||||
const p = this.particles[i]
|
||||
const fadeFrom = height * (1 - p.emitter.config.fade)
|
||||
|
||||
p.sway += 0.05 * step
|
||||
@@ -317,7 +317,7 @@ const stage = {
|
||||
// is still in the air; `end` fires on its element and it leaves the stage.
|
||||
_settle(now: number): void {
|
||||
for (let i = this.emitters.length - 1; i >= 0; i--) {
|
||||
const emitter = this.emitters[i]!
|
||||
const emitter = this.emitters[i]
|
||||
const pouring = !emitter.stopped && now - emitter.startedAt < emitter.config.duration
|
||||
const airborne = this.particles.some((p) => p.emitter === emitter)
|
||||
|
||||
@@ -349,7 +349,7 @@ class Confetti extends BaseComponent {
|
||||
_emitter: Emitter | null = null
|
||||
|
||||
constructor(element: ElementSelector, config?: ComponentConfigInput) {
|
||||
super(element, config as BaseConfig | undefined)
|
||||
super(element, config)
|
||||
}
|
||||
|
||||
// Getters
|
||||
|
||||
@@ -70,6 +70,7 @@ type WeekDayID = 0 | 1 | 2 | 3 | 4 | 5 | 6
|
||||
*/
|
||||
interface CalendarInstance {
|
||||
// Loosely typed on purpose: the plugin's context is large and version-specific.
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
context: Record<string, any>
|
||||
init(): unknown
|
||||
update(resetOptions?: object): unknown
|
||||
@@ -258,6 +259,8 @@ class Datepicker extends BaseComponent {
|
||||
this._isShowing = false
|
||||
}
|
||||
|
||||
// `async` like `show()`, so a plugin error reaches the caller as a rejection
|
||||
// eslint-disable-next-line @typescript-eslint/require-await
|
||||
async hide(): Promise<void> {
|
||||
if (this._config.inline) {
|
||||
return // Inline calendars are always visible
|
||||
@@ -512,7 +515,7 @@ class Datepicker extends BaseComponent {
|
||||
return
|
||||
}
|
||||
|
||||
this.hide()
|
||||
void this.hide()
|
||||
}
|
||||
|
||||
EventHandler.on(document, EVENT_FOCUSIN, this._onFocusIn)
|
||||
@@ -665,7 +668,7 @@ class Datepicker extends BaseComponent {
|
||||
|
||||
if (shouldHide) {
|
||||
window.clearTimeout(this._hideTimeout)
|
||||
this._hideTimeout = window.setTimeout(() => this.hide(), HIDE_DELAY)
|
||||
this._hideTimeout = window.setTimeout(() => void this.hide(), HIDE_DELAY)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -699,7 +702,7 @@ class Datepicker extends BaseComponent {
|
||||
}
|
||||
|
||||
if (dates.length === 1) {
|
||||
return this._formatDate(dates[0]!)
|
||||
return this._formatDate(dates[0])
|
||||
}
|
||||
|
||||
// For date ranges, use en-dash; for multiple dates, use comma
|
||||
@@ -732,7 +735,7 @@ class Datepicker extends BaseComponent {
|
||||
this._calendar?.set({ selectedDates: this._selectedDates, ...this._monthOf(this._selectedDates[0]) })
|
||||
}
|
||||
|
||||
_toIsoDate(value: DateAny | string): string {
|
||||
_toIsoDate(value: Date | number | string): string {
|
||||
if (typeof value === 'string' && DATE_PATTERN.test(value)) {
|
||||
return value
|
||||
}
|
||||
@@ -772,7 +775,7 @@ EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (
|
||||
}
|
||||
|
||||
event.preventDefault()
|
||||
;(Datepicker.getOrCreateInstance(this) as Datepicker).toggle()
|
||||
void (Datepicker.getOrCreateInstance(this) as Datepicker).toggle()
|
||||
})
|
||||
|
||||
EventHandler.on(document, EVENT_FOCUSIN_DATA_API, SELECTOR_DATA_TOGGLE, function (this: HTMLElement) {
|
||||
@@ -780,7 +783,7 @@ EventHandler.on(document, EVENT_FOCUSIN_DATA_API, SELECTOR_DATA_TOGGLE, function
|
||||
return
|
||||
}
|
||||
|
||||
;(Datepicker.getOrCreateInstance(this) as Datepicker).show()
|
||||
void (Datepicker.getOrCreateInstance(this) as Datepicker).show()
|
||||
})
|
||||
|
||||
// Render on load what cannot wait for a focus or a click: inline calendars,
|
||||
|
||||
@@ -12,7 +12,7 @@ export const prefix: string = 'tblr-'
|
||||
export const hexToRgba = (hex: string, opacity: number): string | null => {
|
||||
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex)
|
||||
|
||||
return result ? `rgba(${parseInt(result[1]!, 16)}, ${parseInt(result[2]!, 16)}, ${parseInt(result[3]!, 16)}, ${opacity})` : null
|
||||
return result ? `rgba(${parseInt(result[1], 16)}, ${parseInt(result[2], 16)}, ${parseInt(result[3], 16)}, ${opacity})` : null
|
||||
}
|
||||
|
||||
export const getColor = (color: string, opacity: number = 1): string | null => {
|
||||
|
||||
@@ -114,14 +114,14 @@ const clampSpan = (min: number, max: number): number => {
|
||||
|
||||
// Accepts "3,4,2" as well as a JSON array literal "[3,4,2]".
|
||||
const parseNumberList = (input: unknown): number[] => {
|
||||
const raw = String(input ?? '').trim()
|
||||
const raw = typeof input === 'string' ? input.trim() : ''
|
||||
if (!raw) {
|
||||
return []
|
||||
}
|
||||
|
||||
if (raw.startsWith('[')) {
|
||||
try {
|
||||
const arr = JSON.parse(raw)
|
||||
const arr = JSON.parse(raw) as unknown
|
||||
return Array.isArray(arr) ? arr.map(Number).filter(Number.isFinite) : []
|
||||
} catch {
|
||||
return []
|
||||
|
||||
@@ -296,7 +296,7 @@ describe('Tab', () => {
|
||||
fixtureEl.innerHTML = ['<ul class="nav">', ' <li class="nav-link" data-bs-toggle="tab"></li>', '</ul>'].join('')
|
||||
|
||||
const tabEl = fixtureEl.querySelector('.nav-link')!
|
||||
const tab = new Tab(tabEl)
|
||||
new Tab(tabEl)
|
||||
|
||||
const spyStop = vi.spyOn(Event.prototype, 'stopPropagation')
|
||||
const spyPrevent = vi.spyOn(Event.prototype, 'preventDefault')
|
||||
@@ -326,6 +326,7 @@ describe('Tab', () => {
|
||||
tabEl1.dispatchEvent(keydown)
|
||||
|
||||
expect(spyFocus2).toHaveBeenCalled()
|
||||
expect(spyFocus3).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('should handle left/up arrow', () => {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { describe, it, expect, beforeAll, beforeEach, afterEach, vi } from 'vitest'
|
||||
import { describe, it, expect, beforeAll, afterEach, vi } from 'vitest'
|
||||
import { execute, executeAfterTransition, findShadowRoot, getElement, getNextActiveElement, getTransitionDurationFromElement, getUID, isDisabled, isElement, isRTL, isVisible, noop, parseSelector, reflow, toType, triggerTransitionEnd } from '../../../src/bootstrap/util/index'
|
||||
import { clearFixture, getFixture } from '../../helpers/fixture'
|
||||
|
||||
|
||||
+1
-1
@@ -286,7 +286,7 @@
|
||||
"star-rating.js": "^4.3.1",
|
||||
"tom-select": "^2.6.2",
|
||||
"typed.js": "^3.0.0",
|
||||
"typescript": "^7.0.2",
|
||||
"typescript": "^6.0.3",
|
||||
"vanilla-calendar-pro": "^3.4.0",
|
||||
"vitest": "4.1.11"
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user