Skip to content

Commit 918452d

Browse files
committed
main 🧊 use scroll rework
1 parent 53c6251 commit 918452d

File tree

8 files changed

+247
-184
lines changed

8 files changed

+247
-184
lines changed

‎src/hooks/useEventListener/useEventListener.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ export const useEventListener = ((...params: any[]) => {
6767
const event = (target ? params[1] : params[0]) as string | string[];
6868
const events = Array.isArray(event) ? event : [event];
6969
const listener = (target ? params[2] : params[1]) as (...arg: any[]) => undefined | void;
70-
const options: UseEventListenerOptions | undefined = target ? params[3] : params[2];
70+
const options = (target ? params[3] : params[2]) as UseEventListenerOptions | undefined;
7171

7272
const [internalRef, setInternalRef] = useState<Element>();
7373
const internalListener = useEvent(listener);

‎src/hooks/useField/useField.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,8 +102,8 @@ export interface UseFieldReturn<Value> {
102102
* const { register, getValue, setValue, reset, dirty, error, setError, clearError, touched, focus, watch } = useField();
103103
*/
104104
export const useField = <
105-
Value extends boolean | string = string,
106-
Type = Value extends string ? string : boolean
105+
Value extends boolean | number | string = string,
106+
Type = Value extends string ? string : Value extends boolean ? boolean : number
107107
>(
108108
params?: UseFieldParams<Value>
109109
): UseFieldReturn<Type> => {

‎src/hooks/useFocus/useFocus.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,14 @@ import type { RefObject } from 'react';
22

33
import { useEffect, useRef, useState } from 'react';
44

5-
import { getElement } from '@/utils/helpers';
5+
import { getElement, isTarget } from '@/utils/helpers';
66

77
/** The use focus target type */
8-
export type UseFocusTarget = (() => Element) | Element | RefObject<Element | null | undefined>;
8+
export type UseFocusTarget =
9+
| (() => Element)
10+
| string
11+
| Element
12+
| RefObject<Element | null | undefined>;
913

1014
/** The use focus options type */
1115
export interface UseFocusOptions {
@@ -53,8 +57,7 @@ export interface UseFocus {
5357
* const { ref, focus, blur, focused } = useFocus();
5458
*/
5559
export const useFocus = ((...params: any[]) => {
56-
const target =
57-
(params[0] && 'current' in params[0]) || params[0] instanceof Element ? params[0] : undefined;
60+
const target = isTarget(params[0]) ? params[0] : undefined;
5861
const options = ((target ? params[1] : params[0]) as UseFocusOptions) ?? {};
5962
const initialValue = options.initialValue ?? false;
6063

‎src/hooks/useMutationObserver/useMutationObserver.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,8 @@ export const useMutationObserver = ((...params: any[]) => {
9191
const [internalRef, setInternalRef] = useState<Element>();
9292
const internalCallbackRef = useRef<MutationCallback>(callback);
9393
internalCallbackRef.current = callback;
94+
const internalOptionsRef = useRef(options);
95+
internalOptionsRef.current = options;
9496

9597
useEffect(() => {
9698
if (!enabled && !target && !internalRef) return;
@@ -102,7 +104,7 @@ export const useMutationObserver = ((...params: any[]) => {
102104
target.forEach((target) => {
103105
const element = getElement(target);
104106
if (!element) return;
105-
observer.observe(element as Element, options);
107+
observer.observe(element as Element, internalOptionsRef.current);
106108
});
107109

108110
return () => {
@@ -115,12 +117,12 @@ export const useMutationObserver = ((...params: any[]) => {
115117

116118
const observer = new MutationObserver(internalCallbackRef.current);
117119
setObserver(observer);
118-
observer.observe(element as Element, options);
120+
observer.observe(element as Element, internalOptionsRef.current);
119121

120122
return () => {
121123
observer.disconnect();
122124
};
123-
}, [internalRef, target, ...Object.values(options ?? {})]);
125+
}, [internalRef, target]);
124126

125127
const stop = () => observer?.disconnect();
126128

‎src/hooks/useScroll/useScroll.demo.tsx

Lines changed: 68 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
import type { CSSProperties } from 'react';
22

3-
import { useMemo, useRef, useState } from 'react';
3+
import { register } from 'node:module';
44

5+
import { useField } from '../useField/useField';
6+
import { useToggle } from '../useToggle/useToggle';
57
import { useScroll } from './useScroll';
68

79
const styles: Record<string, CSSProperties> = {
810
container: {
911
width: '300px',
1012
height: '300px',
11-
margin: 'auto',
1213
overflow: 'scroll',
1314
backgroundColor: 'rgba(128, 128, 128, 0.05)',
1415
borderRadius: '8px'
@@ -64,65 +65,82 @@ const styles: Record<string, CSSProperties> = {
6465
};
6566

6667
const Demo = () => {
67-
const elementRef = useRef<HTMLDivElement>(null);
68+
const xInput = useField({ initialValue: 0 });
69+
const yInput = useField({ initialValue: 0 });
70+
const [behavior, setBehavior] = useToggle<ScrollBehavior>(['auto', 'smooth']);
6871

69-
const [scrollX, setScrollX] = useState(0);
70-
const [scrollY, setScrollY] = useState(0);
71-
const [behavior, setBehavior] = useState<ScrollBehavior>('auto');
72+
const scrollX = xInput.watch();
73+
const scrollY = yInput.watch();
7274

73-
const { x, y, isScrolling, arrivedState, directions } = useScroll(elementRef, {
75+
const scroll = useScroll<HTMLDivElement>({
7476
x: scrollX,
7577
y: scrollY,
76-
behavior
78+
behavior,
79+
onScroll: (event) => {
80+
console.log('onScroll', event);
81+
}
7782
});
7883

79-
const { left, right, top, bottom } = useMemo(() => arrivedState, [arrivedState]);
80-
81-
const {
82-
left: toLeft,
83-
right: toRight,
84-
top: toTop,
85-
bottom: toBottom
86-
} = useMemo(() => directions, [directions]);
87-
8884
return (
89-
<div style={{ display: 'flex' }}>
90-
<div ref={elementRef} style={styles.container}>
91-
<div style={styles.inner}>
92-
<div style={styles.topLeft}>TopLeft</div>
93-
<div style={styles.bottomLeft}>BottomLeft</div>
94-
<div style={styles.topRight}>TopRight</div>
95-
<div style={styles.bottomRight}>BottomRight</div>
96-
<div style={styles.center}>Scroll Me</div>
85+
<div>
86+
<div style={{ display: 'flex', gap: 10, flexDirection: 'column', marginBottom: 10 }}>
87+
<div style={{ display: 'flex', gap: 10 }}>
88+
<div style={{ display: 'flex', gap: 10, alignItems: 'center' }}>
89+
<span>x:</span>
90+
<input type='number'{...xInput.register()} />
91+
</div>
92+
<div style={{ display: 'flex', gap: 10, alignItems: 'center' }}>
93+
<span>y:</span>
94+
<input type='number' {...yInput.register()} />
95+
</div>
9796
</div>
98-
</div>
99-
<div style={styles.containerInfo}>
100-
<div>
101-
X Position:
102-
<input value={x} onChange={(event) => setScrollX(+event.target.value)} />
97+
<div style={{ display: 'flex', gap: 10, flexDirection: 'column' }}>
98+
<div style={{ display: 'flex', gap: 10, alignItems: 'center' }}>
99+
Smooth scrolling:{' '}
100+
<input
101+
type='checkbox'
102+
value={behavior}
103+
onChange={(event) => setBehavior(event.target.checked ? 'smooth' : 'auto')}
104+
/>
105+
</div>
106+
<div>scrolling: <code>{String(scroll.scrolling)}</code></div>
103107
</div>
104-
<div>
105-
Y Position:
106-
<input value={y} onChange={(event) => setScrollY(+event.target.value)} />
108+
</div>
109+
110+
111+
<div style={{ display: 'flex', gap: 10, justifyContent: 'space-between' }}>
112+
<div ref={scroll.ref} style={styles.container}>
113+
<div style={styles.inner}>
114+
<div style={styles.topLeft}>TopLeft</div>
115+
<div style={styles.bottomLeft}>BottomLeft</div>
116+
<div style={styles.topRight}>TopRight</div>
117+
<div style={styles.bottomRight}>BottomRight</div>
118+
<div style={styles.center}>Scroll Me</div>
119+
</div>
107120
</div>
108-
<div style={{ display: 'flex', gap: 10, alignItems: 'center' }}>
109-
Smooth scrolling:{' '}
110-
<input
111-
type='checkbox'
112-
value={behavior}
113-
onChange={(event) => setBehavior(event.target.checked ? 'smooth' : 'auto')}
114-
/>
121+
122+
<div style={{ display: 'flex', gap: 10, alignItems: 'center', padding: 15 }}>
123+
<div style={{ display: 'flex', gap: 10, flexDirection: 'column', minWidth: 150 }}>
124+
<h4>Arrived</h4>
125+
<div style={{ display: 'flex', gap: 15, flexDirection: 'column' }}>
126+
<div>top: <code>{String(scroll.arrived.top)}</code></div>
127+
<div>right: <code>{String(scroll.arrived.right)}</code></div>
128+
<div>bottom: <code>{String(scroll.arrived.bottom)}</code></div>
129+
<div>left: <code>{String(scroll.arrived.left)}</code></div>
130+
</div>
131+
</div>
132+
133+
<div style={{ display: 'flex', gap: 10, flexDirection: 'column' }}>
134+
<h4>Directions</h4>
135+
<div style={{ display: 'flex', gap: 15, flexDirection: 'column', minWidth: 150 }}>
136+
<div>top: <code>{String(scroll.directions.top)}</code></div>
137+
<div>right: <code>{String(scroll.directions.right)}</code></div>
138+
<div>bottom: <code>{String(scroll.directions.bottom)}</code></div>
139+
<div>left: <code>{String(scroll.directions.left)}</code></div>
140+
</div>
141+
</div>
115142
</div>
116-
<div>isScrolling: {JSON.stringify(isScrolling)}</div>
117-
<div>Top Arrived: {JSON.stringify(top)}</div>
118-
<div>Right Arrived: {JSON.stringify(right)}</div>
119-
<div>Bottom Arrived: {JSON.stringify(bottom)}</div>
120-
<div>Left Arrived: {JSON.stringify(left)}</div>
121-
<div>Scrolling Up: {JSON.stringify(toTop)}</div>
122-
<div>Scrolling Right: {JSON.stringify(toRight)}</div>
123-
<div>Scrolling Down: {JSON.stringify(toBottom)}</div>
124-
<div>Scrolling Left: {JSON.stringify(toLeft)}</div>
125-
</div>
143+
</div >
126144
</div>
127145
);
128146
};

0 commit comments

Comments
 (0)