Skip to content

Commit

Permalink
main 🧊 fix internal ref
Browse files Browse the repository at this point in the history
  • Loading branch information
debabin committed Jul 30, 2024
1 parent b151a79 commit 5ba6dd3
Show file tree
Hide file tree
Showing 14 changed files with 154 additions and 177 deletions.
4 changes: 2 additions & 2 deletions src/hooks/useClickOutside/useClickOutside.demo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@ import { useClickOutside } from './useClickOutside';
const Demo = () => {
const counter = useCounter();

const ref = useClickOutside<HTMLDivElement>(() => {
const clickOutsideRef = useClickOutside<HTMLDivElement>(() => {
console.log('click outside');
counter.inc();
});

return (
<div
ref={ref}
ref={clickOutsideRef}
style={{
width: 200,
height: 200,
Expand Down
20 changes: 6 additions & 14 deletions src/hooks/useClickOutside/useClickOutside.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import type { RefObject } from 'react';
import { useEffect, useRef } from 'react';

import { useRerender } from '../useRerender/useRerender';
import { useEffect, useRef, useState } from 'react';

/** The use click outside target element type */
type UseClickOutsideTarget = RefObject<Element | null | undefined> | (() => Element) | Element;
Expand Down Expand Up @@ -53,19 +51,18 @@ export type UseClickOutside = {
* const ref = useClickOutside<HMLDiTvElement>(() => console.log('click outside'));
*/
export const useClickOutside = ((...params: any[]) => {
const rerender = useRerender();
const target = (typeof params[1] === 'undefined' ? undefined : params[0]) as
| UseClickOutsideTarget
| UseClickOutsideTarget[]
| undefined;
const callback = (params[1] ? params[1] : params[0]) as (event: Event) => void;

const internalRef = useRef<Element>();
const [internalRef, setInternalRef] = useState<Element>();
const internalCallbackRef = useRef(callback);
internalCallbackRef.current = callback;

useEffect(() => {
if (!target && !internalRef.current) return;
if (!target && !internalRef) return;
const handler = (event: Event) => {
if (Array.isArray(target)) {
if (!target.length) return;
Expand All @@ -80,7 +77,7 @@ export const useClickOutside = ((...params: any[]) => {
return;
}

const element = target ? getElement(target) : internalRef.current;
const element = target ? getElement(target) : internalRef;

if (element && !element.contains(event.target as Node)) {
internalCallbackRef.current(event);
Expand All @@ -94,13 +91,8 @@ export const useClickOutside = ((...params: any[]) => {
document.removeEventListener('mousedown', handler);
document.removeEventListener('touchstart', handler);
};
}, [internalRef.current, target]);
}, [internalRef, target]);

if (target) return;
return (node: Element) => {
if (!internalRef.current) {
internalRef.current = node;
rerender.update();
}
};
return setInternalRef;
}) as UseClickOutside;
13 changes: 13 additions & 0 deletions src/hooks/useCssVar/useCssVar.demo.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { useCssVar } from './useCssVar';

const Demo = () => {
const counter = useCssVar('--count');

return (
<p>
Count: <code>{counter}</code>
</p>
);
};

export default Demo;
34 changes: 34 additions & 0 deletions src/hooks/useCssVar/useCssVar.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { useState } from 'react';

import { useMutationObserver } from '../useMutationObserver';

/**
* @name useCssVar
* @description - Hook that returns the value of a CSS variable
* @category Utilities
*
* @param {string} key The CSS variable key
* @param {string} initialValue The initial value of the CSS variable
* @returns {string} The value of the CSS variable
*
* @example
* const value = useCssVar('color', 'red');
*/
export const useCssVar = (key: string, initialValue: string) => {
const [value, setValue] = useState(initialValue);

const updateCssVar = () => {
const value = window
.getComputedStyle(window?.document?.documentElement)
.getPropertyValue(key)
?.trim();

setValue(value ?? initialValue);
};

useMutationObserver(updateCssVar, {
attributeFilter: ['style', 'class']
});

return value;
};
4 changes: 0 additions & 4 deletions src/hooks/useEventListener/useEventListener.demo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,6 @@ const Demo = () => {
}
);

useEventListener(window, 'click', (event) => console.log('@click 2', event.target), {
passive: true
});

return (
<div
id='content'
Expand Down
25 changes: 8 additions & 17 deletions src/hooks/useEventListener/useEventListener.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import type { RefObject } from 'react';
import { useEffect, useRef } from 'react';
import { useEffect, useState } from 'react';

import { getElement } from '@/utils/helpers';

import { useEvent } from '../useEvent/useEvent';

Expand All @@ -10,18 +12,6 @@ export type UseEventListenerTarget =
| Window
| Document;

const getElement = (target: UseEventListenerTarget) => {
if (typeof target === 'function') {
return target();
}

if (target instanceof Element || target instanceof Window || target instanceof Document) {
return target;
}

return target.current;
};

export type UseEventListenerOptions = boolean | AddEventListenerOptions;

export type UseEventListenerReturn<Target extends UseEventListenerTarget> = RefObject<Target>;
Expand Down Expand Up @@ -78,20 +68,21 @@ export const useEventListener = ((...params: any[]) => {
const listener = (target ? params[2] : params[1]) as (...arg: any[]) => void | undefined;
const options: UseEventListenerOptions | undefined = target ? params[3] : params[2];

const internalRef = useRef<Element | Document | Window>(null);
const [internalRef, setInternalRef] = useState<Element>();
const internalListener = useEvent(listener);

useEffect(() => {
if (!target && !internalRef) return;
const callback = (event: Event) => internalListener(event);
const element = target ? getElement(target) : internalRef.current;
const element = target ? getElement(target) : internalRef;
if (element) {
events.forEach((event) => element.addEventListener(event, callback, options));
return () => {
events.forEach((event) => element.removeEventListener(event, callback, options));
};
}
}, [target, event, options]);
}, [target, internalRef, event, options]);

if (target) return;
return internalRef;
return setInternalRef;
}) as UseEventListener;
16 changes: 5 additions & 11 deletions src/hooks/useInfiniteScroll/useInfiniteScroll.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import type { RefObject } from 'react';
import { useEffect, useRef, useState } from 'react';

import { useEvent } from '../useEvent/useEvent';
import { useRerender } from '../useRerender/useRerender';

/** The use infinite scroll target element type */
export type UseInfiniteScrollTarget = RefObject<Element | null> | (() => Element) | Element;
Expand Down Expand Up @@ -71,7 +70,6 @@ export type UseInfiniteScroll = {
* const isLoading = useInfiniteScroll(ref, () => console.log('infinite scroll'));
*/
export const useInfiniteScroll = ((...params) => {
const rerender = useRerender();
const target = params[1] instanceof Function ? (params[0] as UseInfiniteScrollTarget) : undefined;
const callback = params[1] instanceof Function ? params[1] : (params[0] as () => void);
const options = (
Expand All @@ -82,7 +80,7 @@ export const useInfiniteScroll = ((...params) => {
const distance = options?.distance ?? 10;

const [isLoading, setIsLoading] = useState(false);
const internalRef = useRef<Element>();
const [internalRef, setInternalRef] = useState<Element>();
const internalCallbackRef = useRef(callback);
internalCallbackRef.current = callback;

Expand All @@ -108,24 +106,20 @@ export const useInfiniteScroll = ((...params) => {
});

useEffect(() => {
const element = target ? getElement(target) : internalRef.current;
if (!target && !internalRef) return;
const element = target ? getElement(target) : internalRef;
if (!element) return;

element.addEventListener('scroll', onLoadMore);

return () => {
element.removeEventListener('scroll', onLoadMore);
};
}, [internalRef.current, target, direction, distance]);
}, [internalRef, target, direction, distance]);

if (target) return isLoading;
return {
ref: (node: Element) => {
if (!internalRef.current) {
internalRef.current = node;
rerender.update();
}
},
ref: setInternalRef,
isLoading
};
}) as UseInfiniteScroll;
55 changes: 8 additions & 47 deletions src/hooks/useIntersectionObserver/useIntersectionObserver.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { RefObject } from 'react';
import { useEffect, useRef, useState } from 'react';

import { useRerender } from '../useRerender/useRerender';
import { getElement } from '@/utils/helpers';

/** The intersection observer target element type */
export type UseIntersectionObserverTarget =
Expand All @@ -16,32 +16,6 @@ export interface UseIntersectionObserverOptions extends Omit<IntersectionObserve
root?: IntersectionObserverInit['root'] | RefObject<Element | null | undefined>;
}

const getTargetElement = (target: UseIntersectionObserverTarget) => {
if (typeof target === 'function') {
return target();
}

if (target instanceof Element) {
return target;
}

return target.current;
};

const getRootElement = (root: UseIntersectionObserverOptions['root']) => {
if (!root) return document;

if (root instanceof Element) {
return root;
}

if (root instanceof Document) {
return root;
}

return root.current;
};

/** The intersection observer return type */
export interface UseIntersectionObserverReturn {
inView: boolean;
Expand Down Expand Up @@ -87,7 +61,6 @@ export type UseIntersectionObserver = {
* const { entry, inView } = useIntersectionObserver(ref);
*/
export const useIntersectionObserver = ((...params: any[]) => {
const rerender = useRerender();
const target = (
typeof params[0] === 'object' && !('current' in params[0]) ? undefined : params[0]
) as UseIntersectionObserverTarget | undefined;
Expand All @@ -96,13 +69,13 @@ export const useIntersectionObserver = ((...params: any[]) => {

const [entry, setEntry] = useState<IntersectionObserverEntry>();

const internalRef = useRef<Element>();
const [internalRef, setInternalRef] = useState<Element>();
const internalOnChangeRef = useRef<UseIntersectionObserverOptions['onChange']>();
internalOnChangeRef.current = options?.onChange;

useEffect(() => {
if (!enabled || !internalRef.current) return;
const element = target ? getTargetElement(target) : internalRef.current;
if (!enabled || !internalRef) return;
const element = target ? getElement(target) : internalRef;
if (!element) return;

const observer = new IntersectionObserver(
Expand All @@ -112,32 +85,20 @@ export const useIntersectionObserver = ((...params: any[]) => {
},
{
...options,
root: getRootElement(options?.root)
root: options?.root ? (getElement(options?.root) as Element | Document) : document
}
);

observer.observe(element);
observer.observe(element as Element);

return () => {
observer.disconnect();
};
}, [
internalRef.current,
target,
options?.rootMargin,
options?.threshold,
options?.root,
enabled
]);
}, [target, internalRef, options?.rootMargin, options?.threshold, options?.root, enabled]);

if (target) return { entry, inView: !!entry?.isIntersecting };
return {
ref: (node: Element) => {
if (!internalRef.current) {
internalRef.current = node;
rerender.update();
}
},
ref: setInternalRef,
entry,
inView: !!entry?.isIntersecting
};
Expand Down
4 changes: 2 additions & 2 deletions src/hooks/useLongPress/useLongPress.demo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { useLongPress } from './useLongPress';

const Demo = () => {
const counter = useCounter();
const [longPressedRef, longPressing] = useLongPress<HTMLButtonElement>(() => counter.inc());
const [bind, longPressing] = useLongPress(() => counter.inc());

return (
<>
Expand All @@ -14,7 +14,7 @@ const Demo = () => {
<p>
Clicked: <code>{counter.value}</code>
</p>
<button type='button' ref={longPressedRef}>
<button type='button' {...bind}>
Long press
</button>
</>
Expand Down
Loading

0 comments on commit 5ba6dd3

Please sign in to comment.