diff --git a/package.json b/package.json index fe129c45..dd82bf52 100644 --- a/package.json +++ b/package.json @@ -151,7 +151,7 @@ "lint-staged": { "src/**/**/*.{ts,tsx}": [ "eslint --fix", - "prettier --write", + "yarn prettier --write", "git add" ] }, diff --git a/src/useDropArea.ts b/src/useDropArea.ts index 6586002b..ad4cc6ad 100644 --- a/src/useDropArea.ts +++ b/src/useDropArea.ts @@ -1,4 +1,3 @@ -/* eslint-disable */ import { useMemo, useState } from 'react'; import useMountedState from './useMountedState'; diff --git a/src/useEvent.ts b/src/useEvent.ts index ad86eb30..b9c1ec4c 100644 --- a/src/useEvent.ts +++ b/src/useEvent.ts @@ -1,4 +1,3 @@ -/* eslint-disable */ import { useEffect } from 'react'; import { isClient } from './util'; diff --git a/src/useFullscreen.ts b/src/useFullscreen.ts index cd380fbd..ec6e639c 100644 --- a/src/useFullscreen.ts +++ b/src/useFullscreen.ts @@ -1,4 +1,3 @@ -/* eslint-disable */ import { RefObject, useState } from 'react'; import screenfull from 'screenfull'; import useIsomorphicLayoutEffect from './useIsomorphicLayoutEffect'; diff --git a/src/useGeolocation.ts b/src/useGeolocation.ts index 70790849..27ee3876 100644 --- a/src/useGeolocation.ts +++ b/src/useGeolocation.ts @@ -1,4 +1,3 @@ -/* eslint-disable */ import { useEffect, useState } from 'react'; export interface GeoLocationSensorState { diff --git a/src/useGetSet.ts b/src/useGetSet.ts index e4cf860a..9cb4e021 100644 --- a/src/useGetSet.ts +++ b/src/useGetSet.ts @@ -1,4 +1,3 @@ -/* eslint-disable */ import { Dispatch, useMemo, useRef } from 'react'; import useUpdate from './useUpdate'; import { HookState, InitialHookState, resolveHookState } from './util/resolveHookState'; diff --git a/src/useGetSetState.ts b/src/useGetSetState.ts index 27b10016..90e70af3 100644 --- a/src/useGetSetState.ts +++ b/src/useGetSetState.ts @@ -1,4 +1,3 @@ -/* eslint-disable */ import { useCallback, useRef } from 'react'; import useUpdate from './useUpdate'; diff --git a/src/useIdle.ts b/src/useIdle.ts index a782c481..d03dd48f 100644 --- a/src/useIdle.ts +++ b/src/useIdle.ts @@ -1,4 +1,3 @@ -/* eslint-disable */ import { useEffect, useState } from 'react'; import { throttle } from 'throttle-debounce'; import { off, on } from './util'; diff --git a/src/useIntersection.ts b/src/useIntersection.ts index 01dc0292..7cf9941d 100644 --- a/src/useIntersection.ts +++ b/src/useIntersection.ts @@ -1,4 +1,3 @@ -/* eslint-disable */ import { RefObject, useEffect, useState } from 'react'; const useIntersection = ( diff --git a/src/useKey.ts b/src/useKey.ts index 650888ea..dd65b074 100644 --- a/src/useKey.ts +++ b/src/useKey.ts @@ -1,4 +1,3 @@ -/* eslint-disable */ import { DependencyList, useMemo } from 'react'; import useEvent, { UseEventTarget } from './useEvent'; diff --git a/src/useLifecycles.ts b/src/useLifecycles.ts index 77c16622..45a99429 100644 --- a/src/useLifecycles.ts +++ b/src/useLifecycles.ts @@ -1,4 +1,3 @@ -/* eslint-disable */ import { useEffect } from 'react'; const useLifecycles = (mount, unmount?) => { diff --git a/src/useList.ts b/src/useList.ts index 818020d6..4ed178c1 100644 --- a/src/useList.ts +++ b/src/useList.ts @@ -1,4 +1,3 @@ -/* eslint-disable */ import { useMemo, useRef } from 'react'; import useUpdate from './useUpdate'; import { InitialHookState, ResolvableHookState, resolveHookState } from './util/resolveHookState'; diff --git a/src/useLocalStorage.ts b/src/useLocalStorage.ts index 062ad36a..272069eb 100644 --- a/src/useLocalStorage.ts +++ b/src/useLocalStorage.ts @@ -1,4 +1,3 @@ -/* eslint-disable */ import { useState, useCallback, Dispatch, SetStateAction } from 'react'; import { isClient } from './util'; @@ -28,6 +27,7 @@ const useLocalStorage = ( const deserializer = options ? (options.raw ? (value) => value : options.deserializer) : JSON.parse; + // eslint-disable-next-line react-hooks/rules-of-hooks const [state, setState] = useState(() => { try { const serializer = options ? (options.raw ? String : options.serializer) : JSON.stringify; @@ -47,6 +47,7 @@ const useLocalStorage = ( } }); + // eslint-disable-next-line react-hooks/rules-of-hooks const set: Dispatch> = useCallback( (valOrFunc) => { try { @@ -72,6 +73,7 @@ const useLocalStorage = ( [key, setState] ); + // eslint-disable-next-line react-hooks/rules-of-hooks const remove = useCallback(() => { try { localStorage.removeItem(key); diff --git a/src/useLocation.ts b/src/useLocation.ts index 2a62692f..991b19d8 100644 --- a/src/useLocation.ts +++ b/src/useLocation.ts @@ -1,7 +1,9 @@ -/* eslint-disable */ import { useEffect, useState } from 'react'; import { isClient, off, on } from './util'; +const history = window.history; +const location = window.location; + const patchHistoryMethod = (method) => { const original = history[method]; diff --git a/src/useLockBodyScroll.ts b/src/useLockBodyScroll.ts index f8fe9049..6741e807 100644 --- a/src/useLockBodyScroll.ts +++ b/src/useLockBodyScroll.ts @@ -1,4 +1,3 @@ -/* eslint-disable */ import { RefObject, useEffect, useRef } from 'react'; export function getClosestBody(el: Element | HTMLElement | HTMLIFrameElement | null): HTMLElement | null { @@ -46,7 +45,8 @@ let documentListenerAdded = false; export default !doc ? function useLockBodyMock(_locked: boolean = true, _elementRef?: RefObject) {} : function useLockBody(locked: boolean = true, elementRef?: RefObject) { - elementRef = elementRef || useRef(doc!.body); + const bodyRef = useRef(doc!.body); + elementRef = elementRef || bodyRef; const lock = (body) => { const bodyInfo = bodies.get(body); diff --git a/src/useLongPress.ts b/src/useLongPress.ts index 762b3c94..a1635b71 100644 --- a/src/useLongPress.ts +++ b/src/useLongPress.ts @@ -1,4 +1,3 @@ -/* eslint-disable */ import { useCallback, useRef } from 'react'; interface Options { diff --git a/src/useMap.ts b/src/useMap.ts index f6021e40..0ebcae1e 100644 --- a/src/useMap.ts +++ b/src/useMap.ts @@ -1,4 +1,3 @@ -/* eslint-disable */ import { useState, useMemo, useCallback } from 'react'; export interface StableActions { diff --git a/src/useMeasureDirty.ts b/src/useMeasureDirty.ts index b884220b..d903a59f 100644 --- a/src/useMeasureDirty.ts +++ b/src/useMeasureDirty.ts @@ -1,4 +1,3 @@ -/* eslint-disable */ import { useState, useEffect, useRef, RefObject } from 'react'; import ResizeObserver from 'resize-observer-polyfill'; diff --git a/src/useMediatedState.ts b/src/useMediatedState.ts index cae8085f..708b2ecf 100644 --- a/src/useMediatedState.ts +++ b/src/useMediatedState.ts @@ -1,4 +1,3 @@ -/* eslint-disable */ import { Dispatch, SetStateAction, useCallback, useRef, useState } from 'react'; export interface StateMediator { diff --git a/src/useMouse.ts b/src/useMouse.ts index e0926d21..3acb6ccc 100644 --- a/src/useMouse.ts +++ b/src/useMouse.ts @@ -1,4 +1,3 @@ -/* eslint-disable */ import { RefObject, useEffect } from 'react'; import useRafState from './useRafState'; diff --git a/src/useMultiStateValidator.ts b/src/useMultiStateValidator.ts index 24cf106d..1486c524 100644 --- a/src/useMultiStateValidator.ts +++ b/src/useMultiStateValidator.ts @@ -1,4 +1,3 @@ -/* eslint-disable */ import { useCallback, useEffect, useRef, useState } from 'react'; import { StateValidator, UseStateValidatorReturn, ValidityState } from './useStateValidator'; diff --git a/src/useNetwork.ts b/src/useNetwork.ts index 5693f1e8..0d22a69d 100644 --- a/src/useNetwork.ts +++ b/src/useNetwork.ts @@ -1,4 +1,3 @@ -/* eslint-disable */ import { useEffect, useState } from 'react'; import { off, on } from './util'; diff --git a/src/useOrientation.ts b/src/useOrientation.ts index 63df2ecf..b6c17d15 100644 --- a/src/useOrientation.ts +++ b/src/useOrientation.ts @@ -1,4 +1,3 @@ -/* eslint-disable */ import { useEffect, useState } from 'react'; import { off, on } from './util'; @@ -12,6 +11,8 @@ const defaultState: OrientationState = { type: 'landscape-primary', }; +const screen = window.screen; + const useOrientation = (initialState: OrientationState = defaultState) => { const [state, setState] = useState(initialState); diff --git a/src/usePageLeave.ts b/src/usePageLeave.ts index c2f921d1..fc3b7387 100644 --- a/src/usePageLeave.ts +++ b/src/usePageLeave.ts @@ -1,4 +1,3 @@ -/* eslint-disable */ import { useEffect } from 'react'; const usePageLeave = (onPageLeave, args = []) => { diff --git a/src/usePermission.ts b/src/usePermission.ts index 7ddd3110..4d074acb 100644 --- a/src/usePermission.ts +++ b/src/usePermission.ts @@ -1,4 +1,3 @@ -/* eslint-disable */ import { useEffect, useState } from 'react'; import { off, on } from './util'; diff --git a/src/usePromise.ts b/src/usePromise.ts index 1a3ebdc2..ede5732c 100644 --- a/src/usePromise.ts +++ b/src/usePromise.ts @@ -1,4 +1,3 @@ -/* eslint-disable */ import { useCallback } from 'react'; import useMountedState from './useMountedState'; diff --git a/src/useScroll.ts b/src/useScroll.ts index 7d0d6eb5..f1805783 100644 --- a/src/useScroll.ts +++ b/src/useScroll.ts @@ -1,4 +1,3 @@ -/* eslint-disable */ import { RefObject, useEffect } from 'react'; import useRafState from './useRafState'; diff --git a/src/useScrollbarWidth.ts b/src/useScrollbarWidth.ts index 7c337461..ff637ce4 100644 --- a/src/useScrollbarWidth.ts +++ b/src/useScrollbarWidth.ts @@ -1,4 +1,3 @@ -/* eslint-disable */ import { scrollbarWidth } from '@xobotyi/scrollbar-width'; import { useEffect, useState } from 'react'; diff --git a/src/useScrolling.ts b/src/useScrolling.ts index 54e8bbfa..c95ae6c2 100644 --- a/src/useScrolling.ts +++ b/src/useScrolling.ts @@ -1,4 +1,3 @@ -/* eslint-disable */ import { RefObject, useEffect, useState } from 'react'; const useScrolling = (ref: RefObject): boolean => { diff --git a/src/useSearchParam.ts b/src/useSearchParam.ts index 4f893c37..085ddd7e 100644 --- a/src/useSearchParam.ts +++ b/src/useSearchParam.ts @@ -1,10 +1,11 @@ -/* eslint-disable */ import { useState, useEffect } from 'react'; const getValue = (search: string, param: string) => new URLSearchParams(search).get(param); export type UseQueryParam = (param: string) => string | null; +const location = window.location; + const useSearchParam: UseQueryParam = (param) => { const [value, setValue] = useState(() => getValue(location.search, param)); diff --git a/src/useSessionStorage.ts b/src/useSessionStorage.ts index cb3f80f3..c8c9b0f1 100644 --- a/src/useSessionStorage.ts +++ b/src/useSessionStorage.ts @@ -1,4 +1,3 @@ -/* eslint-disable */ import { useEffect, useState } from 'react'; import { isClient } from './util'; @@ -7,6 +6,7 @@ const useSessionStorage = (key: string, initialValue?: T, raw?: boolean): [T, return [initialValue as T, () => {}]; } + // eslint-disable-next-line react-hooks/rules-of-hooks const [state, setState] = useState(() => { try { const sessionStorageValue = sessionStorage.getItem(key); @@ -24,6 +24,7 @@ const useSessionStorage = (key: string, initialValue?: T, raw?: boolean): [T, } }); + // eslint-disable-next-line react-hooks/rules-of-hooks useEffect(() => { try { const serializedState = raw ? String(state) : JSON.stringify(state); diff --git a/src/useSet.ts b/src/useSet.ts index 1cd87cad..671b7953 100644 --- a/src/useSet.ts +++ b/src/useSet.ts @@ -1,4 +1,3 @@ -/* eslint-disable */ import { useState, useMemo, useCallback } from 'react'; export interface StableActions { diff --git a/src/useSize.tsx b/src/useSize.tsx index 119558a4..aad93c0c 100644 --- a/src/useSize.tsx +++ b/src/useSize.tsx @@ -1,4 +1,3 @@ -/* eslint-disable */ import * as React from 'react'; import { isClient } from './util'; @@ -21,6 +20,7 @@ const useSize = ( return [typeof element === 'function' ? element({ width, height }) : element, { width, height }]; } + // eslint-disable-next-line react-hooks/rules-of-hooks const [state, setState] = useState({ width, height }); if (typeof element === 'function') { @@ -28,6 +28,7 @@ const useSize = ( } const style = element.props.style || {}; + // eslint-disable-next-line react-hooks/rules-of-hooks const ref = useRef(null); let window: Window | null = null; const setSize = () => { @@ -46,6 +47,7 @@ const useSize = ( DRAF(setSize); }; + // eslint-disable-next-line react-hooks/rules-of-hooks useEffect(() => { const iframe: HTMLIFrameElement | null = ref.current; diff --git a/src/useSlider.ts b/src/useSlider.ts index 6e3a382b..8156d988 100644 --- a/src/useSlider.ts +++ b/src/useSlider.ts @@ -1,4 +1,3 @@ -/* eslint-disable */ import { useEffect, useRef, RefObject, CSSProperties } from 'react'; import { isClient, off, on } from './util'; diff --git a/src/useSpring.ts b/src/useSpring.ts index d08e727e..beff7702 100644 --- a/src/useSpring.ts +++ b/src/useSpring.ts @@ -1,4 +1,3 @@ -/* eslint-disable */ import { useEffect, useMemo, useState } from 'react'; import { Spring, SpringSystem } from 'rebound'; diff --git a/src/useStartTyping.ts b/src/useStartTyping.ts index c77834be..6764610f 100644 --- a/src/useStartTyping.ts +++ b/src/useStartTyping.ts @@ -1,4 +1,3 @@ -/* eslint-disable */ import useIsomorphicLayoutEffect from './useIsomorphicLayoutEffect'; const isFocusedElementEditable = () => { diff --git a/src/useStateList.ts b/src/useStateList.ts index d9828576..a0fc355a 100644 --- a/src/useStateList.ts +++ b/src/useStateList.ts @@ -1,4 +1,3 @@ -/* eslint-disable */ import { useMemo, useRef } from 'react'; import useMountedState from './useMountedState'; import useUpdate from './useUpdate'; diff --git a/src/useStateValidator.ts b/src/useStateValidator.ts index e52b69e0..f7b897ff 100644 --- a/src/useStateValidator.ts +++ b/src/useStateValidator.ts @@ -1,4 +1,3 @@ -/* eslint-disable */ import { Dispatch, SetStateAction, useCallback, useEffect, useRef, useState } from 'react'; export type ValidityState = [boolean | undefined, ...any[]]; diff --git a/src/useStateWithHistory.ts b/src/useStateWithHistory.ts index fd25ace0..caaed66e 100644 --- a/src/useStateWithHistory.ts +++ b/src/useStateWithHistory.ts @@ -1,4 +1,3 @@ -/* eslint-disable */ import { Dispatch, useCallback, useMemo, useRef, useState } from 'react'; import { useFirstMountState } from './useFirstMountState'; import { InitialHookState, ResolvableHookState, resolveHookState } from './util/resolveHookState'; diff --git a/src/useThrottle.ts b/src/useThrottle.ts index a58b5344..b231ba62 100644 --- a/src/useThrottle.ts +++ b/src/useThrottle.ts @@ -1,4 +1,3 @@ -/* eslint-disable */ import { useEffect, useRef, useState } from 'react'; import useUnmount from './useUnmount'; diff --git a/src/useThrottleFn.ts b/src/useThrottleFn.ts index 65398e64..7b197a1f 100644 --- a/src/useThrottleFn.ts +++ b/src/useThrottleFn.ts @@ -1,4 +1,3 @@ -/* eslint-disable */ import { useEffect, useRef, useState } from 'react'; import useUnmount from './useUnmount'; diff --git a/src/useTimeoutFn.ts b/src/useTimeoutFn.ts index a10d9956..4f9e8c50 100644 --- a/src/useTimeoutFn.ts +++ b/src/useTimeoutFn.ts @@ -1,4 +1,3 @@ -/* eslint-disable */ import { useCallback, useEffect, useRef } from 'react'; export type UseTimeoutFnReturn = [() => boolean | null, () => void, () => void]; diff --git a/src/useTitle.ts b/src/useTitle.ts index 171234fe..9e421b2d 100644 --- a/src/useTitle.ts +++ b/src/useTitle.ts @@ -1,4 +1,3 @@ -/* eslint-disable */ import { useRef, useEffect } from 'react'; export interface UseTitleOptions { restoreOnUnmount?: boolean; diff --git a/src/useUpdateEffect.ts b/src/useUpdateEffect.ts index 8aa3d844..736abf8c 100644 --- a/src/useUpdateEffect.ts +++ b/src/useUpdateEffect.ts @@ -1,4 +1,3 @@ -/* eslint-disable */ import { useEffect } from 'react'; import { useFirstMountState } from './useFirstMountState'; diff --git a/src/useVibrate.ts b/src/useVibrate.ts index c6ae491f..23f7c619 100644 --- a/src/useVibrate.ts +++ b/src/useVibrate.ts @@ -1,4 +1,3 @@ -/* eslint-disable */ import { useEffect } from 'react'; export type VibrationPattern = number | number[]; diff --git a/src/useWindowScroll.ts b/src/useWindowScroll.ts index aa452e87..82d6be15 100644 --- a/src/useWindowScroll.ts +++ b/src/useWindowScroll.ts @@ -1,4 +1,3 @@ -/* eslint-disable */ import { useEffect } from 'react'; import { isClient } from './util'; diff --git a/src/useWindowSize.ts b/src/useWindowSize.ts index 7ad39986..29957969 100644 --- a/src/useWindowSize.ts +++ b/src/useWindowSize.ts @@ -1,4 +1,3 @@ -/* eslint-disable */ import { useEffect } from 'react'; import useRafState from './useRafState'; diff --git a/src/util/createHTMLMediaHook.ts b/src/util/createHTMLMediaHook.ts index 43ef3e70..59a0be5c 100644 --- a/src/util/createHTMLMediaHook.ts +++ b/src/util/createHTMLMediaHook.ts @@ -1,4 +1,3 @@ -/* eslint-disable */ import * as React from 'react'; import { useEffect, useRef } from 'react'; import useSetState from '../useSetState'; @@ -26,210 +25,213 @@ export interface HTMLMediaControls { seek: (time: number) => void; } -const createHTMLMediaHook = (tag: 'audio' | 'video') => { - const hook = ( - elOrProps: HTMLMediaProps | React.ReactElement - ): [React.ReactElement, HTMLMediaState, HTMLMediaControls, { current: HTMLAudioElement | null }] => { - let element: React.ReactElement | undefined; - let props: HTMLMediaProps; +type createHTMLMediaHookReturn = [ + React.ReactElement, + HTMLMediaState, + HTMLMediaControls, + { current: HTMLAudioElement | null } +]; - if (React.isValidElement(elOrProps)) { - element = elOrProps; - props = element.props; - } else { - props = elOrProps as HTMLMediaProps; - } +const createHTMLMediaHook = (tag: 'audio' | 'video') => ( + elOrProps: HTMLMediaProps | React.ReactElement +): createHTMLMediaHookReturn => { + let element: React.ReactElement | undefined; + let props: HTMLMediaProps; - const [state, setState] = useSetState({ - buffered: [], - time: 0, - duration: 0, - paused: true, - muted: false, - volume: 1, - }); - const ref = useRef(null); + if (React.isValidElement(elOrProps)) { + element = elOrProps; + props = element.props; + } else { + props = elOrProps as HTMLMediaProps; + } - const wrapEvent = (userEvent, proxyEvent?) => { - return (event) => { - try { - proxyEvent && proxyEvent(event); - } finally { - userEvent && userEvent(event); - } - }; - }; + const [state, setState] = useSetState({ + buffered: [], + time: 0, + duration: 0, + paused: true, + muted: false, + volume: 1, + }); + const ref = useRef(null); - const onPlay = () => setState({ paused: false }); - const onPause = () => setState({ paused: true }); - const onVolumeChange = () => { - const el = ref.current; - if (!el) { - return; + const wrapEvent = (userEvent, proxyEvent?) => { + return (event) => { + try { + proxyEvent && proxyEvent(event); + } finally { + userEvent && userEvent(event); } - setState({ - muted: el.muted, - volume: el.volume, - }); }; - const onDurationChange = () => { - const el = ref.current; - if (!el) { - return; - } - const { duration, buffered } = el; - setState({ - duration, - buffered: parseTimeRanges(buffered), - }); - }; - const onTimeUpdate = () => { - const el = ref.current; - if (!el) { - return; - } - setState({ time: el.currentTime }); - }; - const onProgress = () => { - const el = ref.current; - if (!el) { - return; - } - setState({ buffered: parseTimeRanges(el.buffered) }); - }; - - if (element) { - element = React.cloneElement(element, { - controls: false, - ...props, - ref, - onPlay: wrapEvent(props.onPlay, onPlay), - onPause: wrapEvent(props.onPause, onPause), - onVolumeChange: wrapEvent(props.onVolumeChange, onVolumeChange), - onDurationChange: wrapEvent(props.onDurationChange, onDurationChange), - onTimeUpdate: wrapEvent(props.onTimeUpdate, onTimeUpdate), - onProgress: wrapEvent(props.onProgress, onProgress), - }); - } else { - element = React.createElement(tag, { - controls: false, - ...props, - ref, - onPlay: wrapEvent(props.onPlay, onPlay), - onPause: wrapEvent(props.onPause, onPause), - onVolumeChange: wrapEvent(props.onVolumeChange, onVolumeChange), - onDurationChange: wrapEvent(props.onDurationChange, onDurationChange), - onTimeUpdate: wrapEvent(props.onTimeUpdate, onTimeUpdate), - onProgress: wrapEvent(props.onProgress, onProgress), - } as any); // TODO: fix this typing. - } - - // Some browsers return `Promise` on `.play()` and may throw errors - // if one tries to execute another `.play()` or `.pause()` while that - // promise is resolving. So we prevent that with this lock. - // See: https://bugs.chromium.org/p/chromium/issues/detail?id=593273 - let lockPlay: boolean = false; - - const controls = { - play: () => { - const el = ref.current; - if (!el) { - return undefined; - } - - if (!lockPlay) { - const promise = el.play(); - const isPromise = typeof promise === 'object'; - - if (isPromise) { - lockPlay = true; - const resetLock = () => { - lockPlay = false; - }; - promise.then(resetLock, resetLock); - } - - return promise; - } - return undefined; - }, - pause: () => { - const el = ref.current; - if (el && !lockPlay) { - return el.pause(); - } - }, - seek: (time: number) => { - const el = ref.current; - if (!el || state.duration === undefined) { - return; - } - time = Math.min(state.duration, Math.max(0, time)); - el.currentTime = time; - }, - volume: (volume: number) => { - const el = ref.current; - if (!el) { - return; - } - volume = Math.min(1, Math.max(0, volume)); - el.volume = volume; - setState({ volume }); - }, - mute: () => { - const el = ref.current; - if (!el) { - return; - } - el.muted = true; - }, - unmute: () => { - const el = ref.current; - if (!el) { - return; - } - el.muted = false; - }, - }; - - useEffect(() => { - const el = ref.current!; - - if (!el) { - if (process.env.NODE_ENV !== 'production') { - if (tag === 'audio') { - console.error( - 'useAudio() ref to