Skip to content

Commit a43a40b

Browse files
fix: import react-use hooks and remove it as a dep
1 parent d721cc5 commit a43a40b

File tree

4 files changed

+226
-198
lines changed

4 files changed

+226
-198
lines changed

packages/react-notion-x/package.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,7 @@
6565
"react-image": "^4.0.3",
6666
"react-lazy-images": "^1.1.0",
6767
"react-modal": "^3.14.3",
68-
"react-pdf": "^9.1.1",
69-
"react-use": "^17.5.1"
68+
"react-pdf": "^9.1.1"
7069
},
7170
"devDependencies": {
7271
"@types/lodash.throttle": "^4.1.6",

packages/react-notion-x/src/third-party/collection.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import {
55
getTextContent
66
} from 'notion-utils'
77
import * as React from 'react'
8-
import { useLocalStorage, useWindowSize } from 'react-use'
98

109
import { PageIcon } from '../components/page-icon'
1110
import {
@@ -17,6 +16,7 @@ import { CollectionViewIcon } from '../icons/collection-view-icon'
1716
import { cs } from '../utils'
1817
import { CollectionRow } from './collection-row'
1918
import { CollectionView } from './collection-view'
19+
import { useLocalStorage, useWindowSize } from './react-use'
2020

2121
const isServer = typeof window === 'undefined'
2222

Lines changed: 213 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,213 @@
1+
// Imported from https://github.com/streamich/react-use
2+
import {
3+
type Dispatch,
4+
type EffectCallback,
5+
type SetStateAction,
6+
useCallback,
7+
useEffect,
8+
useLayoutEffect,
9+
useRef,
10+
useState
11+
} from 'react'
12+
13+
const noop = () => {}
14+
15+
function on<T extends Window | Document | HTMLElement | EventTarget>(
16+
obj: T | null,
17+
...args:
18+
| Parameters<T['addEventListener']>
19+
| [string, ((...args: any[]) => any) | null, ...any]
20+
): void {
21+
if (obj && obj.addEventListener) {
22+
obj.addEventListener(
23+
...(args as Parameters<HTMLElement['addEventListener']>)
24+
)
25+
}
26+
}
27+
28+
function off<T extends Window | Document | HTMLElement | EventTarget>(
29+
obj: T | null,
30+
...args:
31+
| Parameters<T['removeEventListener']>
32+
| [string, ((...args: any[]) => any) | null, ...any]
33+
): void {
34+
if (obj && obj.removeEventListener) {
35+
obj.removeEventListener(
36+
...(args as Parameters<HTMLElement['removeEventListener']>)
37+
)
38+
}
39+
}
40+
41+
const isBrowser = typeof window !== 'undefined'
42+
43+
export const useWindowSize = (
44+
initialWidth = Infinity,
45+
initialHeight = Infinity
46+
) => {
47+
const [state, setState] = useRafState<{ width: number; height: number }>({
48+
width: isBrowser ? window.innerWidth : initialWidth,
49+
height: isBrowser ? window.innerHeight : initialHeight
50+
})
51+
52+
useEffect((): (() => void) | void => {
53+
if (isBrowser) {
54+
const handler = () => {
55+
setState({
56+
width: window.innerWidth,
57+
height: window.innerHeight
58+
})
59+
}
60+
61+
on(window, 'resize', handler)
62+
63+
return () => {
64+
off(window, 'resize', handler)
65+
}
66+
}
67+
// eslint-disable-next-line react-hooks/exhaustive-deps
68+
}, [])
69+
70+
return state
71+
}
72+
73+
export const useEffectOnce = (effect: EffectCallback) => {
74+
// eslint-disable-next-line react-hooks/exhaustive-deps
75+
useEffect(effect, [])
76+
}
77+
78+
export const useUnmount = (fn: () => any): void => {
79+
const fnRef = useRef(fn)
80+
81+
// update the ref each render so if it change the newest callback will be invoked
82+
fnRef.current = fn
83+
84+
// eslint-disable-next-line unicorn/consistent-function-scoping
85+
useEffectOnce(() => () => fnRef.current())
86+
}
87+
88+
export const useRafState = <S>(
89+
initialState: S | (() => S)
90+
): [S, Dispatch<SetStateAction<S>>] => {
91+
const frame = useRef(0)
92+
const [state, setState] = useState(initialState)
93+
94+
const setRafState = useCallback((value: S | ((prevState: S) => S)) => {
95+
cancelAnimationFrame(frame.current)
96+
97+
frame.current = requestAnimationFrame(() => {
98+
setState(value)
99+
})
100+
}, [])
101+
102+
useUnmount(() => {
103+
cancelAnimationFrame(frame.current)
104+
})
105+
106+
return [state, setRafState]
107+
}
108+
109+
type parserOptions<T> =
110+
| {
111+
raw: true
112+
}
113+
| {
114+
raw: false
115+
serializer: (value: T) => string
116+
deserializer: (value: string) => T
117+
}
118+
119+
export const useLocalStorage = <T>(
120+
key: string,
121+
initialValue?: T,
122+
options?: parserOptions<T>
123+
): [T | undefined, Dispatch<SetStateAction<T | undefined>>, () => void] => {
124+
if (!isBrowser) {
125+
return [initialValue as T, noop, noop]
126+
}
127+
if (!key) {
128+
throw new Error('useLocalStorage key may not be falsy')
129+
}
130+
131+
const deserializer = options
132+
? options.raw
133+
? (value: any) => value
134+
: options.deserializer
135+
: JSON.parse
136+
137+
// eslint-disable-next-line react-hooks/rules-of-hooks
138+
const initializer = useRef((key: string) => {
139+
try {
140+
const serializer = options
141+
? options.raw
142+
? String
143+
: options.serializer
144+
: JSON.stringify
145+
146+
const localStorageValue = localStorage.getItem(key)
147+
if (localStorageValue !== null) {
148+
return deserializer(localStorageValue)
149+
} else {
150+
if (initialValue) {
151+
localStorage.setItem(key, serializer(initialValue))
152+
}
153+
return initialValue
154+
}
155+
} catch {
156+
// If user is in private mode or has storage restriction
157+
// localStorage can throw. JSON.parse and JSON.stringify
158+
// can throw, too.
159+
return initialValue
160+
}
161+
})
162+
163+
// eslint-disable-next-line react-hooks/rules-of-hooks
164+
const [state, setState] = useState<T | undefined>(() =>
165+
initializer.current(key)
166+
)
167+
168+
// eslint-disable-next-line react-hooks/rules-of-hooks
169+
useLayoutEffect(() => setState(initializer.current(key)), [key])
170+
171+
// eslint-disable-next-line react-hooks/rules-of-hooks
172+
const set: Dispatch<SetStateAction<T | undefined>> = useCallback(
173+
(valOrFunc) => {
174+
try {
175+
const newState =
176+
typeof valOrFunc === 'function'
177+
? (valOrFunc as any)(state)
178+
: valOrFunc
179+
if (newState === undefined) return
180+
let value: string
181+
182+
if (options)
183+
if (options.raw)
184+
if (typeof newState === 'string') value = newState
185+
else value = JSON.stringify(newState)
186+
else if (options.serializer) value = options.serializer(newState)
187+
else value = JSON.stringify(newState)
188+
else value = JSON.stringify(newState)
189+
190+
localStorage.setItem(key, value)
191+
setState(deserializer(value))
192+
} catch {
193+
// If user is in private mode or has storage restriction
194+
// localStorage can throw. Also JSON.stringify can throw.
195+
}
196+
},
197+
// eslint-disable-next-line react-hooks/exhaustive-deps
198+
[key, setState]
199+
)
200+
201+
// eslint-disable-next-line react-hooks/rules-of-hooks
202+
const remove = useCallback(() => {
203+
try {
204+
localStorage.removeItem(key)
205+
setState(undefined)
206+
} catch {
207+
// If user is in private mode or has storage restriction
208+
// localStorage can throw.
209+
}
210+
}, [key, setState])
211+
212+
return [state, set, remove]
213+
}

0 commit comments

Comments
 (0)