elements
lifecycle
browser
- useAudio
- useBattery
- useBluetooth
- useBreakpoints
- useBroadcastChannel
- useBrowserLocation
- useClipboard
- useCopy
- useCssVar
- useDisplayMedia
- useDocumentEvent
- useDocumentTitle
- useDocumentVisibility
- useEventListener
- useEventSource
- useEyeDropper
- useFavicon
- useFileSystemAccess
- useFps
- useFullscreen
- useGamepad
- useGeolocation
- useMeasure
- useMediaControls
- useMediaQuery
- useMemory
- useNetwork
- useObjectUrl
- useOnline
- useOtpCredential
- usePermission
- usePictureInPicture
- usePointerLock
- usePostMessage
- useRaf
- useShare
- useSpeechRecognition
- useSpeechSynthesis
- useSticky
- useVibrate
- useVirtualKeyboard
- useWakeLock
- useWebSocket
utilities
state
- useBoolean
- useControllableState
- useCookie
- useCookies
- useCounter
- useCycleList
- useDefault
- useDisclosure
- useField
- useHash
- useList
- useLocalStorage
- useMap
- useMask
- useMergedRef
- useObject
- useOffsetPagination
- useQueue
- useRafState
- useRefState
- useSessionStorage
- useSet
- useStateHistory
- useStep
- useStorage
- useToggle
- useUrlSearchParam
- useUrlSearchParams
- useValidatedState
- useWizard
user
sensors
- useDeviceMotion
- useDeviceOrientation
- useHotkeys
- useIdle
- useInfiniteScroll
- useIntersectionObserver
- useKeyboard
- useKeyPress
- useKeysPressed
- useMouse
- useMutationObserver
- useOrientation
- usePageLeave
- useParallax
- usePerformanceObserver
- useResizeObserver
- useScroll
- useScrollIntoView
- useScrollTo
- useSwipe
- useTextSelection
- useVisibility
- useWindowEvent
- useWindowFocus
- useWindowScroll
- useWindowSize
Draft
reactuse is a collection of essential React hooks. Start typing here and watch the stats update as the content changes.
20 words119 characters1 min read
import type { ClipboardEvent } from 'react';
import { useMutationObserver } from '@siberiacancode/reactuse';
import { FileTextIcon } from 'lucide-react';
import { useState } from 'react';
const INITIAL_TEXT =
'reactuse is a collection of essential React hooks. Start typing here and watch the stats update as the content changes.';
const getStats = (text: string) => {
const normalizedText = text.replace(/\s+/g, ' ').trim();
const words = normalizedText.match(/[\p{L}\p{N}]+(?:['’-][\p{L}\p{N}]+)*/gu)?.length ?? 0;
const characters = Array.from(text).length;
const minutes = Math.max(1, Math.ceil(words / 200));
return { words, characters, minutes };
};
const Demo = () => {
const [stats, setStats] = useState(() => getStats(INITIAL_TEXT));
const editor = useMutationObserver<HTMLDivElement>({
childList: true,
subtree: true,
characterData: true,
onChange: () => {
const text = editor.ref.current?.textContent ?? '';
setStats(getStats(text));
}
});
const onPaste = (event: ClipboardEvent) => {
event.preventDefault();
const text = event.clipboardData.getData('text/plain');
document.execCommand('insertText', false, text);
};
return (
<section className='flex w-full max-w-md flex-col gap-3 p-4'>
<div className='text-muted-foreground flex items-center gap-1.5 text-xs font-medium tracking-wide uppercase'>
<FileTextIcon className='size-3.5' />
Draft
</div>
<div
contentEditable
suppressContentEditableWarning
ref={editor.ref}
className='text-foreground min-h-36 rounded-lg text-base leading-relaxed outline-none'
onPaste={onPaste}
>
{INITIAL_TEXT}
</div>
<div className='border-border text-muted-foreground flex gap-5 border-t pt-3 text-xs'>
<span>
<span className='text-foreground font-semibold tabular-nums'>{stats.words}</span> words
</span>
<span>
<span className='text-foreground font-semibold tabular-nums'>{stats.characters}</span>{' '}
characters
</span>
<span>
<span className='text-foreground font-semibold tabular-nums'>{stats.minutes}</span> min
read
</span>
</div>
</section>
);
};
export default Demo;
This hook uses MutationObserver browser api to provide enhanced functionality. Make sure to check for compatibility with different browsers when using this api
Installation
pnpm add @siberiacancode/reactuseUsage
const { observer, stop } = useMutationObserver(ref, { childList: true });
// or
const { ref, observer, stop } = useMutationObserver({ childList: true });
// or
const { ref, observer, stop } = useMutationObserver((mutations) => console.log(mutations));
// or
const { observer, stop } = useMutationObserver((mutations) => console.log(mutations), ref);Type Declarations
import type { HookTarget } from '@/utils/helpers';
import type { StateRef } from '../useRefState/useRefState';
export type UseMutationObserverCallback = (
mutations: MutationRecord[],
observer: MutationObserver
) => void;
export interface UseMutationObserverOptions extends MutationObserverInit {
/** The enabled state of the mutation observer */
enabled?: boolean;
/** The callback to execute when mutation is detected */
onChange?: UseMutationObserverCallback;
}
export interface UseMutationObserverReturn {
/** The mutation observer instance */
observer?: MutationObserver;
}
export interface UseMutationObserver {
<Target extends Element>(
options?: UseMutationObserverOptions,
target?: never
): UseMutationObserverReturn & { ref: StateRef<Target> };
(target: HookTarget, options?: UseMutationObserverOptions): UseMutationObserverReturn;
<Target extends Element>(
callback: UseMutationObserverCallback,
target?: never
): UseMutationObserverReturn & { ref: StateRef<Target> };
(target: HookTarget, callback: UseMutationObserverCallback): UseMutationObserverReturn;
}API
Parameters
| Name | Type | Default | Note |
|---|---|---|---|
| target | HookTarget | - | The target element to observe |
| options.enabled | boolean | true | The enabled state of the mutation observer |
| options.onChange | UseMutationObserverCallback | - | The callback to execute when mutation is detected |
| options.attributes | boolean | - | Set to true if mutations to target's attributes are to be observed |
| options.characterData | boolean | - | Set to true if mutations to target's data are to be observed |
| options.childList | boolean | - | Set to true if mutations to target's children are to be observed |
| options.subtree | boolean | - | Set to true if mutations to not just target, but also target's descendants are to be observed |
Returns
UseMutationObserverReturnParameters
| Name | Type | Default | Note |
|---|---|---|---|
| options.enabled | boolean | true | The enabled state of the mutation observer |
| options.onChange | UseMutationObserverCallback | - | The callback to execute when mutation is detected |
| options.attributes | boolean | - | Set to true if mutations to target's attributes are to be observed |
| options.characterData | boolean | - | Set to true if mutations to target's data are to be observed |
| options.childList | boolean | - | Set to true if mutations to target's children are to be observed |
| options.subtree | boolean | - | Set to true if mutations to not just target, but also target's descendants are to be observed |
Returns
UseMutationObserverReturn & { ref: StateRef<Target> }Parameters
| Name | Type | Default | Note |
|---|---|---|---|
| callback | UseMutationObserverCallback | - | The callback to execute when mutation is detected |
Returns
UseMutationObserverReturn & { ref: StateRef<Target> }Parameters
| Name | Type | Default | Note |
|---|---|---|---|
| callback | UseMutationObserverCallback | - | The callback to execute when mutation is detected |
| target | HookTarget | - | The target element to observe |
Returns
UseMutationObserverReturnContributors
ddebabin
Last updated on