diff --git a/src/hooks/index.js b/src/hooks/index.ts similarity index 93% rename from src/hooks/index.js rename to src/hooks/index.ts index 000f7b951..1c0b6637c 100755 --- a/src/hooks/index.js +++ b/src/hooks/index.ts @@ -8,7 +8,6 @@ export { default as useOutsideClick } from './useOutsideClick' export { default as useLangPress } from './useLangPress' export { default as useTrans } from './useTrans' export { default as useDevice } from './useDevice' -export { default as useHover } from './useHover' export { default as useNetwork } from 'react-use/lib/useNetwork' export { default as useCopyToClipboard } from 'react-use/lib/useCopyToClipboard' diff --git a/src/hooks/useCustomScroll.js b/src/hooks/useCustomScroll.ts similarity index 67% rename from src/hooks/useCustomScroll.js rename to src/hooks/useCustomScroll.ts index 736913843..9e4b33275 100755 --- a/src/hooks/useCustomScroll.js +++ b/src/hooks/useCustomScroll.ts @@ -1,13 +1,30 @@ -import { useEffect, useState } from 'react' +import { useEffect, useState, RefObject } from 'react' import OverlayScrollbars from 'overlayscrollbars' +type TOption = { + className?: string + themeCategory?: string + scrollbars?: { + autoHide?: 'scroll' | 'never' // string + } + callbacks?: { + onScroll?: () => void + onScrollStart?: () => void + onScrollStop?: () => void + } + // more callbacks see overlayscrollbars docs +} + /** * options detail see: * https://kingsora.github.io/OverlayScrollbars/#!documentation/options * * @returns */ -const useCustomScroll = (ref, option = {}) => { +const useCustomScroll = ( + ref: RefObject, + option: TOption = {}, +): any => { const [scrollInstance, setScrollInstance] = useState(null) useEffect(() => { diff --git a/src/hooks/useDevice.js b/src/hooks/useDevice.ts similarity index 81% rename from src/hooks/useDevice.js rename to src/hooks/useDevice.ts index 2b13b21bd..4bf26a388 100644 --- a/src/hooks/useDevice.js +++ b/src/hooks/useDevice.ts @@ -1,7 +1,11 @@ import { useEffect, useState } from 'react' import { isMobile as detectMobile } from '@/utils' -const useDevice = () => { +type TDevice = { + isMobile: boolean +} + +const useDevice = (): TDevice => { const [isMobile, setIsMobile] = useState(false) useEffect(() => { diff --git a/src/hooks/useHover.js b/src/hooks/useHover.js deleted file mode 100644 index 20824149f..000000000 --- a/src/hooks/useHover.js +++ /dev/null @@ -1,45 +0,0 @@ -import React, { useRef, useState } from 'react' - -const canHover = () => - typeof window !== 'undefined' - ? !window.matchMedia('(hover: none)').matches - : false - -const useHover = (ref, options) => { - const { enterDelay, leaveDelay } = options - const timeout = useRef() - const [hovering, setHovering] = useState(false) - - const toggle = (which) => { - if (!canHover()) return - const delay = which ? enterDelay : leaveDelay - window.clearTimeout(timeout.current) - - if (delay) { - timeout.current = window.setTimeout(() => setHovering(which), delay) - } else { - setHovering(which) - } - } - - const el = ref?.current - - if (el) { - console.log('binding') - el.addEventListener('mouseenter', () => toggle(true)) - el.addEventListener('mouseleave', () => toggle(false)) - } - - // Cleans up timeout on unmount - React.useEffect( - () => () => { - window.clearTimeout(timeout.current) - }, - // eslint-disable-next-line react-hooks/exhaustive-deps - [], - ) - - return hovering -} - -export default useHover diff --git a/src/hooks/useLangPress.js b/src/hooks/useLangPress.ts similarity index 95% rename from src/hooks/useLangPress.js rename to src/hooks/useLangPress.ts index 4cf642d62..47ff15edb 100644 --- a/src/hooks/useLangPress.js +++ b/src/hooks/useLangPress.ts @@ -21,7 +21,7 @@ import { useState, useEffect, useCallback } from 'react' * @param {number} [ms=500] hold m-sec * @returns */ -const useLongPress = (callback = () => {}, ms = 500) => { +const useLongPress = (callback: () => void, ms = 500) => { const [startLongPress, setStartLongPress] = useState(false) useEffect(() => { diff --git a/src/hooks/useOutsideClick.js b/src/hooks/useOutsideClick.ts similarity index 57% rename from src/hooks/useOutsideClick.js rename to src/hooks/useOutsideClick.ts index 439e4733e..0da1bdd40 100644 --- a/src/hooks/useOutsideClick.js +++ b/src/hooks/useOutsideClick.ts @@ -1,9 +1,12 @@ -import { useEffect } from 'react' +import { useEffect, RefObject } from 'react' -const useOutsideClick = (ref, callback) => { - const handleClick = (e) => { +const useOutsideClick = ( + ref: RefObject, + callback?: (e) => void, +): void => { + const handleClick = (e): void => { if (ref.current && !ref.current.contains(e.target)) { - callback(e) + callback?.(e) } } diff --git a/src/hooks/usePlatform.js b/src/hooks/usePlatform.ts similarity index 90% rename from src/hooks/usePlatform.js rename to src/hooks/usePlatform.ts index d921162d7..d6772e815 100755 --- a/src/hooks/usePlatform.js +++ b/src/hooks/usePlatform.ts @@ -1,6 +1,7 @@ import { useState, useEffect } from 'react' import { merge } from 'ramda' +import type { TPlatform } from '@/spec' import { Global } from '@/utils' const initPlatform = { @@ -14,12 +15,13 @@ const initPlatform = { } // see https://stackoverflow.com/questions/49328382/browser-detection-in-reactjs/49328524 -const usePlatform = (/* { breakpoint } */) => { +const usePlatform = (/* { breakpoint } */): TPlatform => { const [platform, setPlatform] = useState(initPlatform) /* eslint-disable */ useEffect(() => { // Firefox 1.0+ + // @ts-ignore const isFirefox = typeof InstallTrigger !== 'undefined' // Safari 3.0+ "[object HTMLElementConstructor]" @@ -29,10 +31,12 @@ const usePlatform = (/* { breakpoint } */) => { return p.toString() === '[object SafariRemoteNotification]' })( !Global.safari || + // @ts-ignore (typeof safari !== 'undefined' && safari.pushNotification), ) // Internet Explorer 6-11 + // @ts-ignore const isIE = /*@cc_on!@*/ false || !!document.documentMode // Edge 20+ @@ -58,8 +62,6 @@ const usePlatform = (/* { breakpoint } */) => { isMobile, }), ) - - return () => {} }, []) return platform diff --git a/src/hooks/useResize.js b/src/hooks/useResize.ts similarity index 85% rename from src/hooks/useResize.js rename to src/hooks/useResize.ts index 093c68cb4..43500bd8e 100755 --- a/src/hooks/useResize.js +++ b/src/hooks/useResize.ts @@ -1,12 +1,17 @@ import { useState, useEffect, useCallback } from 'react' +type TSize = { + width?: number + height?: number +} + /** * hooks for detect window size * see: https://usehooks.com/useWindowSize/ for details * * @returns */ -const useWindowSize = (cb) => { +const useWindowSize = (cb: (size: TSize) => void): TSize => { const isClient = typeof window === 'object' const getSize = useCallback(() => { @@ -20,12 +25,12 @@ const useWindowSize = (cb) => { useEffect(() => { if (!isClient) { - return false + return } const handleResize = () => { setWindowSize(getSize()) - if (cb) cb(getSize()) + cb?.(getSize()) } window.addEventListener('resize', handleResize) diff --git a/src/hooks/useScript.js b/src/hooks/useScript.ts similarity index 95% rename from src/hooks/useScript.js rename to src/hooks/useScript.ts index 6d5e6c84a..14c8945a9 100755 --- a/src/hooks/useScript.js +++ b/src/hooks/useScript.ts @@ -2,7 +2,9 @@ import { useState, useEffect } from 'react' const cachedScripts = [] -const useScript = (src) => { +type TLoadState = boolean + +const useScript = (src: string): TLoadState[] => { // Keeping track of script loaded and error state const [state, setState] = useState({ loaded: false, diff --git a/src/hooks/useScroll.js b/src/hooks/useScroll.ts similarity index 50% rename from src/hooks/useScroll.js rename to src/hooks/useScroll.ts index bfdac7ddb..8b95362bf 100755 --- a/src/hooks/useScroll.js +++ b/src/hooks/useScroll.ts @@ -3,6 +3,11 @@ import { merge } from 'ramda' import { debounce } from '@/utils' +type TScrollState = { + direction: string + scrollPos: number +} + const initState = { direction: 'up', // 'down' scrollPos: 0, @@ -10,30 +15,34 @@ const initState = { // detect the scroll direction // see https://codepen.io/lehollandaisvolant/pen/ryrrGx?editors=1010 -const useScroll = (cb) => { +const useScroll = (cb: () => void): TScrollState => { const [scroll, setScroll] = useState(initState) /* eslint-disable */ useEffect(() => { // adding scroll event let scrollPos = scroll.scrollPos - const handleScroll = debounce(function () { - // detects new state and compares it with the new one - let direction = - document.body.getBoundingClientRect().top > scrollPos ? 'up' : 'down' - - // saves the new position for iteration. - scrollPos = document.body.getBoundingClientRect().top - - if (cb) cb() - - setScroll( - merge(initState, { - direction, - scrollPos, - }), - ) - }, 50) + const handleScroll = debounce( + () => { + // detects new state and compares it with the new one + let direction = + document.body.getBoundingClientRect().top > scrollPos ? 'up' : 'down' + + // saves the new position for iteration. + scrollPos = document.body.getBoundingClientRect().top + + cb?.() + + setScroll( + merge(initState, { + direction, + scrollPos, + }), + ) + }, + 50, + true, + ) window.addEventListener('scroll', handleScroll) diff --git a/src/hooks/useShortcut.js b/src/hooks/useShortcut.ts similarity index 80% rename from src/hooks/useShortcut.js rename to src/hooks/useShortcut.ts index 40441026b..5541b82bf 100644 --- a/src/hooks/useShortcut.js +++ b/src/hooks/useShortcut.ts @@ -1,20 +1,20 @@ import { useEffect } from 'react' import tinykeys from 'tinykeys' -const useShortcut = (combination, cb) => { +const useShortcut = (combination: string | string[], cb: () => void): void => { useEffect(() => { const handlers = {} if (Array.isArray(combination)) { for (let i = 0; i < combination.length; i += 1) { handlers[combination[i]] = (event) => { event.preventDefault() - return cb() + return cb?.() } } } else { handlers[combination] = (event) => { event.preventDefault() - return cb() + return cb?.() } } diff --git a/src/hooks/useTrans.js b/src/hooks/useTrans.ts similarity index 100% rename from src/hooks/useTrans.js rename to src/hooks/useTrans.ts diff --git a/src/spec/index.ts b/src/spec/index.ts index ab005320c..f6393a68d 100644 --- a/src/spec/index.ts +++ b/src/spec/index.ts @@ -15,7 +15,15 @@ export type { TButton } from './comp' export type { TTheme, TThemeMap, TThemeName } from './theme' export type { TAccount, TUser, TMembership } from './account' -export type { TTestable, TActive, TSpace, TGAEvent, TSEO, TLink } from './utils' +export type { + TTestable, + TActive, + TSpace, + TGAEvent, + TSEO, + TLink, + TPlatform, +} from './utils' export type TRoute = { communityPath?: string diff --git a/src/spec/utils.ts b/src/spec/utils.ts index 8542b272d..3bab10c8c 100644 --- a/src/spec/utils.ts +++ b/src/spec/utils.ts @@ -32,3 +32,13 @@ export type TSEO = { export type TLink = { href: string } + +export type TPlatform = { + isChrome: boolean + isFirefox: boolean + isSafari: boolean + isIE: boolean + isEdge: boolean + isMacOS: boolean + isMobile: boolean +}