refactor(useResizable): refactor and fix useCallback dependency warning
This commit is contained in:
parent
fd0ecf579d
commit
387576c16c
7 changed files with 548 additions and 144 deletions
|
@ -44,6 +44,7 @@
|
||||||
"@typescript-eslint/no-misused-promises": "off",
|
"@typescript-eslint/no-misused-promises": "off",
|
||||||
"@typescript-eslint/consistent-type-assertions": "off",
|
"@typescript-eslint/consistent-type-assertions": "off",
|
||||||
"import/no-absolute-path": "off",
|
"import/no-absolute-path": "off",
|
||||||
|
"@typescript-eslint/no-base-to-string": "off",
|
||||||
"@typescript-eslint/no-unused-vars": "warn"
|
"@typescript-eslint/no-unused-vars": "warn"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,7 +61,7 @@
|
||||||
"peerjs": "^1.5.1",
|
"peerjs": "^1.5.1",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
"react-markdown": "^9.0.0",
|
"react-markdown": "^9.0.1",
|
||||||
"react-nice-avatar": "^1.4.1",
|
"react-nice-avatar": "^1.4.1",
|
||||||
"react-use": "^17.4.0",
|
"react-use": "^17.4.0",
|
||||||
"remark-breaks": "^4.0.0",
|
"remark-breaks": "^4.0.0",
|
||||||
|
@ -74,7 +74,7 @@
|
||||||
"type-fest": "^4.7.1"
|
"type-fest": "^4.7.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@commitlint/cli": "^18.4.0",
|
"@commitlint/cli": "^18.4.1",
|
||||||
"@commitlint/config-conventional": "^18.4.0",
|
"@commitlint/config-conventional": "^18.4.0",
|
||||||
"@types/node": "^20.9.0",
|
"@types/node": "^20.9.0",
|
||||||
"@types/react": "^18.2.37",
|
"@types/react": "^18.2.37",
|
||||||
|
@ -96,13 +96,13 @@
|
||||||
"lint-staged": "^15.1.0",
|
"lint-staged": "^15.1.0",
|
||||||
"npm-run-all": "^4.1.5",
|
"npm-run-all": "^4.1.5",
|
||||||
"postcss": "^8.4.31",
|
"postcss": "^8.4.31",
|
||||||
"prettier": "^3.0.3",
|
"prettier": "^3.1.0",
|
||||||
"rimraf": "^5.0.5",
|
"rimraf": "^5.0.5",
|
||||||
"tailwindcss": "^3.3.5",
|
"tailwindcss": "^3.3.5",
|
||||||
"tailwindcss-animate": "^1.0.7",
|
"tailwindcss-animate": "^1.0.7",
|
||||||
"typescript": "^5.2.2",
|
"typescript": "^5.2.2",
|
||||||
"webext-bridge": "^6.0.1",
|
"webext-bridge": "^6.0.1",
|
||||||
"wxt": "^0.9.0"
|
"wxt": "^0.10.0"
|
||||||
},
|
},
|
||||||
"lint-staged": {
|
"lint-staged": {
|
||||||
"*.{js,jsx,ts,tsx}": "eslint --fix"
|
"*.{js,jsx,ts,tsx}": "eslint --fix"
|
||||||
|
|
573
pnpm-lock.yaml
573
pnpm-lock.yaml
File diff suppressed because it is too large
Load diff
|
@ -12,8 +12,8 @@ export default defineContentScript({
|
||||||
matches: ['*://*.example.com/*', '*://*.google.com/*', '*://*.v2ex.com/*'],
|
matches: ['*://*.example.com/*', '*://*.google.com/*', '*://*.v2ex.com/*'],
|
||||||
async main(ctx) {
|
async main(ctx) {
|
||||||
const store = Remesh.store({
|
const store = Remesh.store({
|
||||||
externs: [StorageImpl],
|
externs: [StorageImpl]
|
||||||
inspectors: [RemeshLogger()]
|
// inspectors: [RemeshLogger()]
|
||||||
})
|
})
|
||||||
|
|
||||||
const ui = await createContentScriptUi(ctx, {
|
const ui = await createContentScriptUi(ctx, {
|
||||||
|
|
|
@ -7,7 +7,7 @@ export interface AppContainerProps {
|
||||||
const AppContainer: FC<AppContainerProps> = ({ children }) => {
|
const AppContainer: FC<AppContainerProps> = ({ children }) => {
|
||||||
const { size, ref } = useResizable({
|
const { size, ref } = useResizable({
|
||||||
initSize: 375,
|
initSize: 375,
|
||||||
maxSize: 1000,
|
maxSize: 750,
|
||||||
minSize: 375,
|
minSize: 375,
|
||||||
direction: 'left'
|
direction: 'left'
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import { useCallback, useEffect, useRef, useState } from 'react'
|
import { useCallback, useRef, useState } from 'react'
|
||||||
|
import { isInRange } from '@/utils'
|
||||||
|
|
||||||
export interface ResizableOptions {
|
export interface ResizableOptions {
|
||||||
minSize: number
|
minSize: number
|
||||||
|
@ -12,73 +13,79 @@ const useResizable = (options: ResizableOptions) => {
|
||||||
|
|
||||||
const [size, setSize] = useState(initSize)
|
const [size, setSize] = useState(initSize)
|
||||||
|
|
||||||
const [position, setPosition] = useState(0)
|
const position = useRef(0)
|
||||||
|
|
||||||
const [isMove, setIsMove] = useState(false)
|
const isMove = useRef(false)
|
||||||
|
|
||||||
const directionXY = direction === 'left' || direction === 'right' ? 'X' : 'Y'
|
const isHorizontal = direction === 'left' || direction === 'right'
|
||||||
|
|
||||||
const handleStart = (e: MouseEvent) => {
|
const handleMove = useCallback(
|
||||||
const { screenY, screenX } = e
|
(e: MouseEvent) => {
|
||||||
setIsMove(true)
|
if (isMove.current) {
|
||||||
setPosition(directionXY === 'Y' ? screenY : screenX)
|
|
||||||
document.documentElement.style.userSelect = 'none'
|
|
||||||
document.documentElement.style.cursor = directionXY === 'Y' ? 'ns-resize' : 'ew-resize'
|
|
||||||
}
|
|
||||||
const handleEnd = () => {
|
|
||||||
setIsMove(false)
|
|
||||||
document.documentElement.style.cursor = ''
|
|
||||||
document.documentElement.style.userSelect = ''
|
|
||||||
}
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const handleMove = (e: MouseEvent) => {
|
|
||||||
if (isMove) {
|
|
||||||
console.log('move')
|
|
||||||
const { screenY, screenX } = e
|
const { screenY, screenX } = e
|
||||||
let delta = 0
|
let delta = 0
|
||||||
switch (direction) {
|
switch (direction) {
|
||||||
case 'left':
|
case 'left':
|
||||||
delta = position - screenX
|
delta = position.current - screenX
|
||||||
break
|
break
|
||||||
case 'right':
|
case 'right':
|
||||||
delta = screenX - position
|
delta = screenX - position.current
|
||||||
break
|
break
|
||||||
case 'top':
|
case 'top':
|
||||||
delta = position - screenY
|
delta = position.current - screenY
|
||||||
break
|
break
|
||||||
case 'bottom':
|
case 'bottom':
|
||||||
delta = screenY - position
|
delta = screenY - position.current
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
const newSize = size + delta
|
const newSize = size + delta
|
||||||
if (size !== newSize && newSize >= minSize && newSize <= maxSize) {
|
if (isInRange(newSize, minSize, maxSize)) {
|
||||||
setSize(newSize)
|
position.current = isHorizontal ? screenX : screenY
|
||||||
|
}
|
||||||
|
if (newSize !== size) {
|
||||||
|
setSize(clamp(newSize, minSize, maxSize))
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
document.removeEventListener('mousemove', handleMove)
|
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
[direction, isHorizontal, maxSize, minSize, size]
|
||||||
|
)
|
||||||
|
|
||||||
document.addEventListener('mousemove', handleMove)
|
const handleEnd = useCallback(() => {
|
||||||
return () => {
|
isMove.current = false
|
||||||
document.removeEventListener('mousemove', handleMove)
|
document.documentElement.style.cursor = ''
|
||||||
}
|
document.documentElement.style.userSelect = ''
|
||||||
}, [isMove])
|
}, [])
|
||||||
|
|
||||||
|
const handleStart = useCallback(
|
||||||
|
(e: MouseEvent) => {
|
||||||
|
const { screenY, screenX } = e
|
||||||
|
isMove.current = true
|
||||||
|
position.current = isHorizontal ? screenX : screenY
|
||||||
|
document.documentElement.style.userSelect = 'none'
|
||||||
|
document.documentElement.style.cursor = isHorizontal ? 'ew-resize' : 'ns-resize'
|
||||||
|
},
|
||||||
|
[isHorizontal]
|
||||||
|
)
|
||||||
|
|
||||||
const ref = useRef<HTMLElement | null>(null)
|
const ref = useRef<HTMLElement | null>(null)
|
||||||
const setRef = useCallback((node: HTMLElement | null) => {
|
|
||||||
if (ref.current) {
|
// Watch ref: https://medium.com/@teh_builder/ref-objects-inside-useeffect-hooks-eb7c15198780
|
||||||
ref.current.removeEventListener('mousedown', handleStart)
|
const setRef = useCallback(
|
||||||
document.removeEventListener('mouseup', handleEnd)
|
(node: HTMLElement | null) => {
|
||||||
}
|
if (ref.current) {
|
||||||
if (node) {
|
ref.current.removeEventListener('mousedown', handleStart)
|
||||||
node.addEventListener('mousedown', handleStart)
|
document.removeEventListener('mouseup', handleEnd)
|
||||||
document.addEventListener('mouseup', handleEnd)
|
document.removeEventListener('mousemove', handleMove)
|
||||||
}
|
}
|
||||||
ref.current = node
|
if (node) {
|
||||||
}, [])
|
node.addEventListener('mousedown', handleStart)
|
||||||
|
document.addEventListener('mouseup', handleEnd)
|
||||||
|
document.addEventListener('mousemove', handleMove)
|
||||||
|
}
|
||||||
|
ref.current = node
|
||||||
|
},
|
||||||
|
[handleEnd, handleMove, handleStart]
|
||||||
|
)
|
||||||
|
|
||||||
return { size, ref: setRef }
|
return { size, ref: setRef }
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,9 @@ export const createElement = <T extends Element>(template: string) => {
|
||||||
export const chunk = <T = any>(array: T[], size: number) =>
|
export const chunk = <T = any>(array: T[], size: number) =>
|
||||||
Array.from({ length: Math.ceil(array.length / size) }, (_v, i) => array.slice(i * size, i * size + size))
|
Array.from({ length: Math.ceil(array.length / size) }, (_v, i) => array.slice(i * size, i * size + size))
|
||||||
|
|
||||||
|
export const clamp = (number: number, min: number, max: number) => Math.min(Math.max(number, min), max)
|
||||||
|
export const isInRange = (number: number, min: number, max: number) => number >= min && number <= max
|
||||||
|
|
||||||
export const getWebSiteInfo = (): WebSiteInfo => {
|
export const getWebSiteInfo = (): WebSiteInfo => {
|
||||||
return {
|
return {
|
||||||
host: document.location.host,
|
host: document.location.host,
|
||||||
|
|
Loading…
Reference in a new issue